Procházet zdrojové kódy

Fix text editor placeholder and caret alignment in ThinCaretTextEditor.

Render placeholders inside the NSTextView so they share the same insets and baseline as typed text, and tune caret height and vertical position.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 před 1 měsícem
rodič
revize
00a48fb9f5

+ 77 - 0
gramora/Views/Components/ThinCaretTextEditor.swift

@@ -3,17 +3,75 @@ import SwiftUI
 
 
 private final class ThinCaretTextView: NSTextView {
 private final class ThinCaretTextView: NSTextView {
     private let caretWidth: CGFloat = 1
     private let caretWidth: CGFloat = 1
+    private let caretHeightBoost: CGFloat = 2
+    private let caretVerticalOffset: CGFloat = 1
+
+    var placeholder: String = "" {
+        didSet {
+            guard placeholder != oldValue else { return }
+            needsDisplay = true
+        }
+    }
+
+    var placeholderColor: NSColor = .placeholderTextColor
 
 
     override func drawInsertionPoint(in rect: NSRect, color: NSColor, turnedOn flag: Bool) {
     override func drawInsertionPoint(in rect: NSRect, color: NSColor, turnedOn flag: Bool) {
         var caretRect = rect
         var caretRect = rect
         caretRect.size.width = caretWidth
         caretRect.size.width = caretWidth
         caretRect.origin.x += (rect.width - caretWidth) / 2
         caretRect.origin.x += (rect.width - caretWidth) / 2
+
+        if let font {
+            let caretHeight = font.ascender + abs(font.descender) + caretHeightBoost
+            caretRect.size.height = caretHeight
+            caretRect.origin.y = rect.origin.y + (rect.height - caretHeight) / 2 + caretVerticalOffset
+        }
+
         super.drawInsertionPoint(in: caretRect, color: color, turnedOn: flag)
         super.drawInsertionPoint(in: caretRect, color: color, turnedOn: flag)
     }
     }
+
+    override func draw(_ dirtyRect: NSRect) {
+        super.draw(dirtyRect)
+        drawPlaceholderIfNeeded()
+    }
+
+    override func didChangeText() {
+        super.didChangeText()
+        needsDisplay = true
+    }
+
+    private func drawPlaceholderIfNeeded() {
+        guard string.isEmpty, !placeholder.isEmpty else { return }
+
+        let font = font ?? NSFont.systemFont(ofSize: 14)
+        let paragraphStyle = NSMutableParagraphStyle()
+        paragraphStyle.lineBreakMode = .byWordWrapping
+
+        let attributes: [NSAttributedString.Key: Any] = [
+            .font: font,
+            .foregroundColor: placeholderColor,
+            .paragraphStyle: paragraphStyle
+        ]
+
+        let horizontalInset = textContainerInset.width + (textContainer?.lineFragmentPadding ?? 0)
+        let verticalInset = textContainerInset.height
+        let drawRect = NSRect(
+            x: horizontalInset,
+            y: verticalInset,
+            width: bounds.width - horizontalInset - textContainerInset.width,
+            height: bounds.height - verticalInset - textContainerInset.height
+        )
+
+        placeholder.draw(
+            with: drawRect,
+            options: [.usesLineFragmentOrigin, .usesFontLeading],
+            attributes: attributes
+        )
+    }
 }
 }
 
 
 struct ThinCaretTextEditor: NSViewRepresentable {
 struct ThinCaretTextEditor: NSViewRepresentable {
     @Binding var text: String
     @Binding var text: String
+    var placeholder: String = ""
     var isEditable: Bool = true
     var isEditable: Bool = true
     var onSubmit: (() -> Void)?
     var onSubmit: (() -> Void)?
 
 
@@ -36,7 +94,15 @@ struct ThinCaretTextEditor: NSViewRepresentable {
         textView.allowsUndo = true
         textView.allowsUndo = true
         textView.drawsBackground = false
         textView.drawsBackground = false
         textView.backgroundColor = .clear
         textView.backgroundColor = .clear
+        textView.isVerticallyResizable = true
+        textView.isHorizontallyResizable = false
+        textView.autoresizingMask = [.width]
         textView.textContainer?.lineFragmentPadding = 0
         textView.textContainer?.lineFragmentPadding = 0
+        textView.textContainer?.widthTracksTextView = true
+        textView.textContainer?.containerSize = NSSize(
+            width: 0,
+            height: CGFloat.greatestFiniteMagnitude
+        )
         textView.textContainerInset = NSSize(
         textView.textContainerInset = NSSize(
             width: AppTheme.textEditorHorizontalInset,
             width: AppTheme.textEditorHorizontalInset,
             height: AppTheme.textEditorVerticalInset
             height: AppTheme.textEditorVerticalInset
@@ -46,6 +112,8 @@ struct ThinCaretTextEditor: NSViewRepresentable {
         textView.isAutomaticTextReplacementEnabled = false
         textView.isAutomaticTextReplacementEnabled = false
         textView.font = NSFont.systemFont(ofSize: 14)
         textView.font = NSFont.systemFont(ofSize: 14)
         textView.textColor = NSColor(AppTheme.textPrimary)
         textView.textColor = NSColor(AppTheme.textPrimary)
+        textView.placeholder = placeholder
+        textView.placeholderColor = NSColor(AppTheme.textMuted)
         textView.delegate = context.coordinator
         textView.delegate = context.coordinator
         textView.string = text
         textView.string = text
 
 
@@ -56,7 +124,15 @@ struct ThinCaretTextEditor: NSViewRepresentable {
 
 
     func updateNSView(_ scrollView: NSScrollView, context: Context) {
     func updateNSView(_ scrollView: NSScrollView, context: Context) {
         guard let textView = scrollView.documentView as? ThinCaretTextView else { return }
         guard let textView = scrollView.documentView as? ThinCaretTextView else { return }
+
         textView.isEditable = isEditable
         textView.isEditable = isEditable
+        textView.placeholder = placeholder
+        textView.placeholderColor = NSColor(AppTheme.textMuted)
+        textView.textContainerInset = NSSize(
+            width: AppTheme.textEditorHorizontalInset,
+            height: AppTheme.textEditorVerticalInset
+        )
+
         if textView.string != text {
         if textView.string != text {
             textView.string = text
             textView.string = text
         }
         }
@@ -73,6 +149,7 @@ struct ThinCaretTextEditor: NSViewRepresentable {
         func textDidChange(_ notification: Notification) {
         func textDidChange(_ notification: Notification) {
             guard let textView = notification.object as? NSTextView else { return }
             guard let textView = notification.object as? NSTextView else { return }
             parent.text = textView.string
             parent.text = textView.string
+            textView.needsDisplay = true
         }
         }
 
 
         func textView(_ textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
         func textView(_ textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {

+ 8 - 20
gramora/Views/EmailWriterView.swift

@@ -174,7 +174,11 @@ struct EmailWriterView: View {
             }
             }
 
 
             ZStack(alignment: .bottomTrailing) {
             ZStack(alignment: .bottomTrailing) {
-                ThinCaretTextEditor(text: $viewModel.prompt, onSubmit: viewModel.generateEmail)
+                ThinCaretTextEditor(
+                    text: $viewModel.prompt,
+                    placeholder: "Describe the email you need — key points, recipient context, or a rough draft...",
+                    onSubmit: viewModel.generateEmail
+                )
                     .font(.system(size: 14))
                     .font(.system(size: 14))
                     .foregroundStyle(AppTheme.textPrimary)
                     .foregroundStyle(AppTheme.textPrimary)
                     .frame(maxWidth: .infinity, maxHeight: .infinity)
                     .frame(maxWidth: .infinity, maxHeight: .infinity)
@@ -185,16 +189,6 @@ struct EmailWriterView: View {
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                     )
                     )
-                    .overlay(alignment: .topLeading) {
-                        if viewModel.prompt.isEmpty {
-                            Text("Describe the email you need — key points, recipient context, or a rough draft...")
-                                .font(.system(size: 14))
-                                .foregroundStyle(AppTheme.textMuted)
-                                .padding(.leading, AppTheme.textEditorHorizontalInset)
-                                .padding(.top, AppTheme.textEditorVerticalInset)
-                                .allowsHitTesting(false)
-                        }
-                    }
 
 
                 Text(viewModel.characterCountLabel)
                 Text(viewModel.characterCountLabel)
                     .font(.system(size: 11))
                     .font(.system(size: 11))
@@ -233,6 +227,9 @@ struct EmailWriterView: View {
             ZStack(alignment: .topLeading) {
             ZStack(alignment: .topLeading) {
                 ThinCaretTextEditor(
                 ThinCaretTextEditor(
                     text: $viewModel.generatedEmail,
                     text: $viewModel.generatedEmail,
+                    placeholder: viewModel.isGenerating
+                        ? "Writing your email..."
+                        : "Your generated email will appear here...",
                     isEditable: false
                     isEditable: false
                 )
                 )
                 .font(.system(size: 14))
                 .font(.system(size: 14))
@@ -245,15 +242,6 @@ struct EmailWriterView: View {
                     RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                     RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                         .stroke(AppTheme.inputBorder, lineWidth: 1)
                         .stroke(AppTheme.inputBorder, lineWidth: 1)
                 )
                 )
-
-                if viewModel.generatedEmail.isEmpty {
-                    Text(viewModel.isGenerating ? "Writing your email..." : "Your generated email will appear here...")
-                        .font(.system(size: 14))
-                        .foregroundStyle(AppTheme.textMuted)
-                        .padding(.leading, AppTheme.textEditorHorizontalInset)
-                        .padding(.top, AppTheme.textEditorVerticalInset)
-                        .allowsHitTesting(false)
-                }
             }
             }
             .frame(maxHeight: .infinity)
             .frame(maxHeight: .infinity)
         }
         }

+ 4 - 11
gramora/Views/GrammarCheckerView.swift

@@ -134,7 +134,10 @@ struct GrammarCheckerView: View {
                 .accessibilityLabel("Your Content")
                 .accessibilityLabel("Your Content")
 
 
             ZStack(alignment: .bottomTrailing) {
             ZStack(alignment: .bottomTrailing) {
-                ThinCaretTextEditor(text: $viewModel.text)
+                ThinCaretTextEditor(
+                    text: $viewModel.text,
+                    placeholder: "Type or paste your text here and press the check button..."
+                )
                     .font(.system(size: 14))
                     .font(.system(size: 14))
                     .foregroundStyle(AppTheme.textPrimary)
                     .foregroundStyle(AppTheme.textPrimary)
                     .frame(minHeight: editorHeight, idealHeight: editorHeight)
                     .frame(minHeight: editorHeight, idealHeight: editorHeight)
@@ -144,16 +147,6 @@ struct GrammarCheckerView: View {
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                     )
                     )
-                    .overlay(alignment: .topLeading) {
-                        if viewModel.text.isEmpty {
-                            Text("Type or paste your text here and press the check button...")
-                                .font(.system(size: 14))
-                                .foregroundStyle(AppTheme.textMuted)
-                                .padding(.leading, AppTheme.textEditorHorizontalInset)
-                                .padding(.top, AppTheme.textEditorVerticalInset)
-                                .allowsHitTesting(false)
-                        }
-                    }
 
 
                 Text(viewModel.characterCountLabel)
                 Text(viewModel.characterCountLabel)
                     .font(.system(size: 11))
                     .font(.system(size: 11))

+ 4 - 9
gramora/Views/JournalFinderView.swift

@@ -254,17 +254,12 @@ struct JournalFinderView: View {
             fieldLabel("Abstract or Summary", optional: false)
             fieldLabel("Abstract or Summary", optional: false)
 
 
             ZStack(alignment: .topLeading) {
             ZStack(alignment: .topLeading) {
-                ThinCaretTextEditor(text: $viewModel.abstractText)
+                ThinCaretTextEditor(
+                    text: $viewModel.abstractText,
+                    placeholder: "Paste your abstract, introduction, or manuscript summary here..."
+                )
                     .frame(height: height)
                     .frame(height: height)
 
 
-                if viewModel.abstractText.isEmpty {
-                    Text("Paste your abstract, introduction, or manuscript summary here...")
-                        .font(.system(size: 15))
-                        .foregroundStyle(AppTheme.textMuted)
-                        .padding(.horizontal, AppTheme.textEditorHorizontalInset + 2)
-                        .padding(.vertical, AppTheme.textEditorVerticalInset + 2)
-                        .allowsHitTesting(false)
-                }
             }
             }
             .background(Color.white)
             .background(Color.white)
             .clipShape(RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius))
             .clipShape(RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius))

+ 8 - 20
gramora/Views/LanguageTranslatorView.swift

@@ -150,7 +150,11 @@ struct LanguageTranslatorView: View {
             }
             }
 
 
             ZStack(alignment: .bottomTrailing) {
             ZStack(alignment: .bottomTrailing) {
-                ThinCaretTextEditor(text: $viewModel.sourceText, onSubmit: viewModel.translate)
+                ThinCaretTextEditor(
+                    text: $viewModel.sourceText,
+                    placeholder: "Start writing...",
+                    onSubmit: viewModel.translate
+                )
                     .font(.system(size: 14))
                     .font(.system(size: 14))
                     .foregroundStyle(AppTheme.textPrimary)
                     .foregroundStyle(AppTheme.textPrimary)
                     .frame(maxWidth: .infinity, maxHeight: .infinity)
                     .frame(maxWidth: .infinity, maxHeight: .infinity)
@@ -161,16 +165,6 @@ struct LanguageTranslatorView: View {
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                     )
                     )
-                    .overlay(alignment: .topLeading) {
-                        if viewModel.sourceText.isEmpty {
-                            Text("Start writing...")
-                                .font(.system(size: 14))
-                                .foregroundStyle(AppTheme.textMuted)
-                                .padding(.leading, AppTheme.textEditorHorizontalInset)
-                                .padding(.top, AppTheme.textEditorVerticalInset)
-                                .allowsHitTesting(false)
-                        }
-                    }
 
 
                 Text(viewModel.characterCountLabel)
                 Text(viewModel.characterCountLabel)
                     .font(.system(size: 11))
                     .font(.system(size: 11))
@@ -202,6 +196,9 @@ struct LanguageTranslatorView: View {
             ZStack(alignment: .topLeading) {
             ZStack(alignment: .topLeading) {
                 ThinCaretTextEditor(
                 ThinCaretTextEditor(
                     text: $viewModel.translatedText,
                     text: $viewModel.translatedText,
+                    placeholder: viewModel.isTranslating
+                        ? "Translating..."
+                        : "Translation will appear here...",
                     isEditable: false
                     isEditable: false
                 )
                 )
                 .font(.system(size: 14))
                 .font(.system(size: 14))
@@ -214,15 +211,6 @@ struct LanguageTranslatorView: View {
                     RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                     RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                         .stroke(AppTheme.inputBorder, lineWidth: 1)
                         .stroke(AppTheme.inputBorder, lineWidth: 1)
                 )
                 )
-
-                if viewModel.translatedText.isEmpty {
-                    Text(viewModel.isTranslating ? "Translating..." : "Translation will appear here...")
-                        .font(.system(size: 14))
-                        .foregroundStyle(AppTheme.textMuted)
-                        .padding(.leading, AppTheme.textEditorHorizontalInset)
-                        .padding(.top, AppTheme.textEditorVerticalInset)
-                        .allowsHitTesting(false)
-                }
             }
             }
             .frame(maxHeight: .infinity)
             .frame(maxHeight: .infinity)
         }
         }

+ 4 - 11
gramora/Views/ParaphrasingView.swift

@@ -93,7 +93,10 @@ struct ParaphrasingView: View {
                 .accessibilityLabel("Your Content")
                 .accessibilityLabel("Your Content")
 
 
             ZStack(alignment: .bottomTrailing) {
             ZStack(alignment: .bottomTrailing) {
-                ThinCaretTextEditor(text: $viewModel.text)
+                ThinCaretTextEditor(
+                    text: $viewModel.text,
+                    placeholder: "Type or paste your text here and press the paraphrase button..."
+                )
                     .font(.system(size: 14))
                     .font(.system(size: 14))
                     .foregroundStyle(AppTheme.textPrimary)
                     .foregroundStyle(AppTheme.textPrimary)
                     .frame(minHeight: editorHeight, idealHeight: editorHeight)
                     .frame(minHeight: editorHeight, idealHeight: editorHeight)
@@ -103,16 +106,6 @@ struct ParaphrasingView: View {
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                     )
                     )
-                    .overlay(alignment: .topLeading) {
-                        if viewModel.text.isEmpty {
-                            Text("Type or paste your text here and press the paraphrase button...")
-                                .font(.system(size: 14))
-                                .foregroundStyle(AppTheme.textMuted)
-                                .padding(.leading, AppTheme.textEditorHorizontalInset)
-                                .padding(.top, AppTheme.textEditorVerticalInset)
-                                .allowsHitTesting(false)
-                        }
-                    }
 
 
                 Text(viewModel.characterCountLabel)
                 Text(viewModel.characterCountLabel)
                     .font(.system(size: 11))
                     .font(.system(size: 11))

+ 4 - 11
gramora/Views/PunctuationCheckerView.swift

@@ -93,7 +93,10 @@ struct PunctuationCheckerView: View {
                 .accessibilityLabel("Your Content")
                 .accessibilityLabel("Your Content")
 
 
             ZStack(alignment: .bottomTrailing) {
             ZStack(alignment: .bottomTrailing) {
-                ThinCaretTextEditor(text: $viewModel.text)
+                ThinCaretTextEditor(
+                    text: $viewModel.text,
+                    placeholder: "Type or paste your text here and press the check button..."
+                )
                     .font(.system(size: 14))
                     .font(.system(size: 14))
                     .foregroundStyle(AppTheme.textPrimary)
                     .foregroundStyle(AppTheme.textPrimary)
                     .frame(minHeight: editorHeight, idealHeight: editorHeight)
                     .frame(minHeight: editorHeight, idealHeight: editorHeight)
@@ -103,16 +106,6 @@ struct PunctuationCheckerView: View {
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                     )
                     )
-                    .overlay(alignment: .topLeading) {
-                        if viewModel.text.isEmpty {
-                            Text("Type or paste your text here and press the check button...")
-                                .font(.system(size: 14))
-                                .foregroundStyle(AppTheme.textMuted)
-                                .padding(.leading, AppTheme.textEditorHorizontalInset)
-                                .padding(.top, AppTheme.textEditorVerticalInset)
-                                .allowsHitTesting(false)
-                        }
-                    }
 
 
                 Text(viewModel.characterCountLabel)
                 Text(viewModel.characterCountLabel)
                     .font(.system(size: 11))
                     .font(.system(size: 11))

+ 4 - 11
gramora/Views/SpellCheckerView.swift

@@ -134,7 +134,10 @@ struct SpellCheckerView: View {
                 .accessibilityLabel("Your Content")
                 .accessibilityLabel("Your Content")
 
 
             ZStack(alignment: .bottomTrailing) {
             ZStack(alignment: .bottomTrailing) {
-                ThinCaretTextEditor(text: $viewModel.text)
+                ThinCaretTextEditor(
+                    text: $viewModel.text,
+                    placeholder: "Type or paste your text here and press the check button..."
+                )
                     .font(.system(size: 14))
                     .font(.system(size: 14))
                     .foregroundStyle(AppTheme.textPrimary)
                     .foregroundStyle(AppTheme.textPrimary)
                     .frame(minHeight: editorHeight, idealHeight: editorHeight)
                     .frame(minHeight: editorHeight, idealHeight: editorHeight)
@@ -144,16 +147,6 @@ struct SpellCheckerView: View {
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                     )
                     )
-                    .overlay(alignment: .topLeading) {
-                        if viewModel.text.isEmpty {
-                            Text("Type or paste your text here and press the check button...")
-                                .font(.system(size: 14))
-                                .foregroundStyle(AppTheme.textMuted)
-                                .padding(.leading, AppTheme.textEditorHorizontalInset)
-                                .padding(.top, AppTheme.textEditorVerticalInset)
-                                .allowsHitTesting(false)
-                        }
-                    }
 
 
                 Text(viewModel.characterCountLabel)
                 Text(viewModel.characterCountLabel)
                     .font(.system(size: 11))
                     .font(.system(size: 11))

+ 4 - 11
gramora/Views/SummarizerView.swift

@@ -93,7 +93,10 @@ struct SummarizerView: View {
                 .accessibilityLabel("Your Content")
                 .accessibilityLabel("Your Content")
 
 
             ZStack(alignment: .bottomTrailing) {
             ZStack(alignment: .bottomTrailing) {
-                ThinCaretTextEditor(text: $viewModel.text)
+                ThinCaretTextEditor(
+                    text: $viewModel.text,
+                    placeholder: "Type or paste your text here and press the summarize button..."
+                )
                     .font(.system(size: 14))
                     .font(.system(size: 14))
                     .foregroundStyle(AppTheme.textPrimary)
                     .foregroundStyle(AppTheme.textPrimary)
                     .frame(minHeight: editorHeight, idealHeight: editorHeight)
                     .frame(minHeight: editorHeight, idealHeight: editorHeight)
@@ -103,16 +106,6 @@ struct SummarizerView: View {
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                     )
                     )
-                    .overlay(alignment: .topLeading) {
-                        if viewModel.text.isEmpty {
-                            Text("Type or paste your text here and press the summarize button...")
-                                .font(.system(size: 14))
-                                .foregroundStyle(AppTheme.textMuted)
-                                .padding(.leading, AppTheme.textEditorHorizontalInset)
-                                .padding(.top, AppTheme.textEditorVerticalInset)
-                                .allowsHitTesting(false)
-                        }
-                    }
 
 
                 Text(viewModel.characterCountLabel)
                 Text(viewModel.characterCountLabel)
                     .font(.system(size: 11))
                     .font(.system(size: 11))

+ 4 - 11
gramora/Views/WordsCountView.swift

@@ -79,7 +79,10 @@ struct WordsCountView: View {
             statsRow
             statsRow
 
 
             ZStack(alignment: .bottomTrailing) {
             ZStack(alignment: .bottomTrailing) {
-                ThinCaretTextEditor(text: $viewModel.text)
+                ThinCaretTextEditor(
+                    text: $viewModel.text,
+                    placeholder: "Type or paste your text here to count words..."
+                )
                     .font(.system(size: 14))
                     .font(.system(size: 14))
                     .foregroundStyle(AppTheme.textPrimary)
                     .foregroundStyle(AppTheme.textPrimary)
                     .frame(maxWidth: .infinity, maxHeight: .infinity)
                     .frame(maxWidth: .infinity, maxHeight: .infinity)
@@ -90,16 +93,6 @@ struct WordsCountView: View {
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                         RoundedRectangle(cornerRadius: AppTheme.inputCornerRadius)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                             .stroke(AppTheme.inputBorder, lineWidth: 1)
                     )
                     )
-                    .overlay(alignment: .topLeading) {
-                        if viewModel.text.isEmpty {
-                            Text("Type or paste your text here to count words...")
-                                .font(.system(size: 14))
-                                .foregroundStyle(AppTheme.textMuted)
-                                .padding(.leading, AppTheme.textEditorHorizontalInset)
-                                .padding(.top, AppTheme.textEditorVerticalInset)
-                                .allowsHitTesting(false)
-                        }
-                    }
 
 
                 Text(viewModel.characterCountLabel)
                 Text(viewModel.characterCountLabel)
                     .font(.system(size: 11))
                     .font(.system(size: 11))