Skip to content

feat: the problem of starting to input the placeholder without disappearing in the context of Chinese input method#457

Open
wuyiping0628 wants to merge 1 commit intodevfrom
wyp/placeholder-0313
Open

feat: the problem of starting to input the placeholder without disappearing in the context of Chinese input method#457
wuyiping0628 wants to merge 1 commit intodevfrom
wyp/placeholder-0313

Conversation

@wuyiping0628
Copy link
Collaborator

@wuyiping0628 wuyiping0628 commented Mar 13, 2026

…earing in the context of Chinese input method

PR

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

  • Bug Fixes
    • Fixed placeholder visibility issue when using Chinese input methods in the editor.

…earing in the context of Chinese input method
@github-actions github-actions bot added the enhancement New feature or request label Mar 13, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

Walkthrough

A constructor is added to the CustomClipboard class that initializes with a FluentEditor instance and sets up an input event listener on the editor root. This listener manages placeholder visibility for Chinese input method compatibility by toggling the ql-blank class and updating placeholder text.

Changes

Cohort / File(s) Summary
Constructor Addition
packages/fluent-editor/src/modules/custom-clipboard.ts
Added a public constructor that accepts a FluentEditor instance, calls super(quill), and injects an input event listener to fix placeholder visibility when using Chinese input methods by toggling the ql-blank class and updating placeholder text.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 A constructor so fine, with input in view,
Chinese characters flowing, placeholder shines through,
The ql-blank dance, toggling with care,
Placeholder text magic floating in air!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main change: adding a constructor with placeholder fix logic for Chinese input methods in CustomClipboard.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch wyp/placeholder-0313
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can disable the changed files summary in the walkthrough.

Disable the reviews.changed_files_summary setting to disable the changed files summary in the walkthrough.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/fluent-editor/src/modules/custom-clipboard.ts (1)

28-35: Reconsider the else branch logic and add cleanup for the event listener.

Two concerns with this implementation:

  1. Else branch redundancy: The else branch executes when innerText === '\n' (empty) OR when ql-blank is already absent. Setting this.quill.options.placeholder on every input event in these cases seems unnecessary - the placeholder text doesn't need to be reassigned repeatedly.

  2. Memory leak risk: The event listener is never removed. If the editor instance is destroyed, the listener remains attached to the DOM element.

♻️ Suggested improvement
   constructor(public quill: FluentEditor) {
     super(quill)
     // 解决 quill 组件在中文输入法的情景下开始输入placeholder不消失的问题
-    this.quill.root.addEventListener('input', () => {
+    const handleInput = () => {
       if (this.quill.root.innerText !== '\n' && this.quill.root.classList.contains('ql-blank')) {
         this.quill.root.classList.toggle('ql-blank', false)
       }
-      else {
-        this.quill.options.placeholder = this.quill.getLangText('editor-placeholder')
-      }
-    })
+    }
+    this.quill.root.addEventListener('input', handleInput)
+    
+    // Cleanup on editor destruction
+    this.quill.on('editor-cleanup' as any, () => {
+      this.quill.root.removeEventListener('input', handleInput)
+    })
   }

Could you clarify the purpose of the else branch? If it's intended to reset the placeholder text after the editor becomes empty again, this may conflict with Quill's built-in placeholder handling.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/fluent-editor/src/modules/custom-clipboard.ts` around lines 28 - 35,
The input handler attached via this.quill.root.addEventListener redundantly
reassigns this.quill.options.placeholder on every input and is never removed;
change the listener to a named function that tracks state transitions (only set
this.quill.options.placeholder when the editor transitions from non-empty to
empty, i.e., when this.quill.root.innerText becomes '\n' and ql-blank is absent)
instead of on every event, and store that handler so you can call
this.quill.root.removeEventListener(...) in the editor cleanup path (e.g., a
dispose/destroy method on the CustomClipboard or where the Quill instance is
torn down) to avoid the memory leak; reference the existing symbols
this.quill.root, this.quill.options.placeholder, this.quill.getLangText,
classList.contains/classList.toggle and implement the removal in the
corresponding teardown method.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/fluent-editor/src/modules/custom-clipboard.ts`:
- Around line 23-26: The constructor for your custom Clipboard module is
incorrect: remove the redundant "declare quill: FluentEditor" and change the
constructor signature to accept both (quill: FluentEditor, options?:
Partial<ClipboardOptions>) and forward options to the parent by calling
super(quill, options) so Quill-provided matchers and options aren't dropped;
also capture the event listener handler you add (store the reference) and remove
it during cleanup/destroy (e.g., on module teardown or override a destroy
method) to avoid the memory leak.

---

Nitpick comments:
In `@packages/fluent-editor/src/modules/custom-clipboard.ts`:
- Around line 28-35: The input handler attached via
this.quill.root.addEventListener redundantly reassigns
this.quill.options.placeholder on every input and is never removed; change the
listener to a named function that tracks state transitions (only set
this.quill.options.placeholder when the editor transitions from non-empty to
empty, i.e., when this.quill.root.innerText becomes '\n' and ql-blank is absent)
instead of on every event, and store that handler so you can call
this.quill.root.removeEventListener(...) in the editor cleanup path (e.g., a
dispose/destroy method on the CustomClipboard or where the Quill instance is
torn down) to avoid the memory leak; reference the existing symbols
this.quill.root, this.quill.options.placeholder, this.quill.getLangText,
classList.contains/classList.toggle and implement the removal in the
corresponding teardown method.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1c74abfa-1865-4833-ac1a-9a0da5f863db

📥 Commits

Reviewing files that changed from the base of the PR and between 270a8cd and 9049447.

📒 Files selected for processing (1)
  • packages/fluent-editor/src/modules/custom-clipboard.ts

Comment on lines 23 to +26
declare quill: FluentEditor

constructor(public quill: FluentEditor) {
super(quill)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Quill clipboard module constructor signature options parameter

💡 Result:

In Quill v2, the Clipboard module constructor is:

constructor(quill: Quill, options: Partial<ClipboardOptions>)

where:

interface ClipboardOptions {
  matchers: [Selector, Matcher][];
}

type Selector = string | Node['TEXT_NODE'] | Node['ELEMENT_NODE'];
type Matcher = (node: Node, delta: Delta, scroll: ScrollBlot) => Delta;

So the only documented/typed option is matchers, an array of [selectorOrNodeType, matcherFn] entries. These configured matchers are appended after Quill’s default clipboard matchers (e.g., via modules: { clipboard: { matchers: [...] } }). [1], [2]


🏁 Script executed:

cat -n packages/fluent-editor/src/modules/custom-clipboard.ts | head -50

Repository: opentiny/tiny-editor

Length of output: 1996


Constructor signature mismatch with Quill module system.

Quill v2's Clipboard module constructor expects (quill: Quill, options: Partial<ClipboardOptions>) where options.matchers allows users to configure custom clipboard matchers. This constructor only accepts quill, which means:

  1. Any options passed by Quill are silently dropped
  2. User-configured clipboard matchers will be lost
  3. The super(quill) call doesn't forward options to the parent Clipboard class

Additionally, the declare quill: FluentEditor on line 23 is redundant and should be removed since it's redeclared as public on line 25.

The event listener added on line 28 is never cleaned up, creating a potential memory leak if the editor instance is destroyed or recreated.

🔧 Proposed fix to accept and forward options
 export class CustomClipboard extends Clipboard {
-  declare quill: FluentEditor
 
-  constructor(public quill: FluentEditor) {
-    super(quill)
+  constructor(quill: FluentEditor, options?: Record<string, unknown>) {
+    super(quill, options)
+    this.quill = quill

Also consider storing the listener reference and removing it on cleanup to prevent memory leaks:

+  private inputListener = () => {
+    if (this.quill.root.innerText !== '\n' && this.quill.root.classList.contains('ql-blank')) {
+      this.quill.root.classList.toggle('ql-blank', false)
+    }
+    else {
+      this.quill.options.placeholder = this.quill.getLangText('editor-placeholder')
+    }
+  }
+
   constructor(quill: FluentEditor, options?: Record<string, unknown>) {
     super(quill, options)
     this.quill = quill
-    this.quill.root.addEventListener('input', () => { ... })
+    this.quill.root.addEventListener('input', this.inputListener)
+  }
+
+  destroy() {
+    this.quill.root.removeEventListener('input', this.inputListener)
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
declare quill: FluentEditor
constructor(public quill: FluentEditor) {
super(quill)
constructor(quill: FluentEditor, options?: Record<string, unknown>) {
super(quill, options)
this.quill = quill
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/fluent-editor/src/modules/custom-clipboard.ts` around lines 23 - 26,
The constructor for your custom Clipboard module is incorrect: remove the
redundant "declare quill: FluentEditor" and change the constructor signature to
accept both (quill: FluentEditor, options?: Partial<ClipboardOptions>) and
forward options to the parent by calling super(quill, options) so Quill-provided
matchers and options aren't dropped; also capture the event listener handler you
add (store the reference) and remove it during cleanup/destroy (e.g., on module
teardown or override a destroy method) to avoid the memory leak.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant