Replace broken el.hasAttribute("aria-") with a curated list of 27
aria attributes checked via hasAttribute. Each check is O(1).
WAI-ARIA 1.2 defines ~50 aria attributes total per MDN.
Of these ~27 appear on interactive elements such as buttons,
inputs, sliders, and dialogs. The remaining ~20 are structural
container attributes like aria-live, aria-colcount, and
aria-rowspan that only appear on non-interactive containers.
Checking them would not change results.
Replace inline style.display with CSS class toggling.
Changes:
- Add .visible class to CSS module
- Use classList.add/remove instead of style.display
(cherry picked from commit 33465bbf520b65908c18d8022f259803253a7621)
When typing into contenteditable elements (e.g. LinkedIn post editor),
the synthetic event approach (Plan A) may fail silently — the events
fire but the editor's internal state doesn't update, leaving the
element empty.
This adds an automatic fallback: after Plan A, we verify the text was
actually inserted by checking element.innerText. If it wasn't, we
fall back to execCommand('insertText') which integrates natively with
most rich-text editors including LinkedIn, Quill, and Slate.js.
The fallback uses proper Selection/Range API to select-all before
replacing, and preserves the undo stack since execCommand is handled
by the browser natively.
Fixes#168
Elements detected as interactive via heuristic methods (cursor:pointer
style, interactive class names, event listeners) had empty attributes
because `isInteractiveCandidate()` was used as the gate for attribute
extraction. This function only recognizes standard HTML tags and ARIA
attributes, missing heuristic detections.
After interactivity is confirmed by `isInteractiveElement()`, backfill
attributes for elements that were missed. This ensures
`includeAttributes` (e.g. `['class']`) works correctly for all
interactive elements, not just semantically standard ones.
Closes#124
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
## Changes
Based on @gaomeng1900's comprehensive testing feedback:
1. **Document known limitations**
- Slate.js and Draft.js do not work with synthetic events
- Draft.js: Cannot be supported via DOM manipulation (by design, unmaintained)
- Monaco/CodeMirror: Require direct JS instance access
2. **Clarify tested editors**
- Works: Quill, LinkedIn, simple contenteditable editors
- Does not work: Slate.js, Draft.js
3. **Preserve execCommand as fallback**
- execCommand works better for LinkedIn, Quill, and Draft.js
- Kept as commented fallback (deprecated API)
- Users can uncomment if synthetic events don't work
Co-authored-by: gaomeng1900 <gaomeng1900@users.noreply.github.com>
## Changes
1. **Fix keyboard event semantics** (per review feedback)
- Only dispatch keydown/keyup for single-character input
- Avoids inconsistent event payloads for multi-character strings
- Prevents confusion in editors that correlate key events with text changes
2. **Remove extra blank line**
- Formatting consistency
Reviewer noted that dispatching key events with only the last character
of multi-character text creates semantic inconsistency with the actual
DOM mutation (which inserts the full string at once).
This fix follows the suggested change from the review.