Skip to content

Migrate web editor to react-native-enriched (web demo + UX fixes)#13

Merged
winrid merged 6 commits into
mainfrom
migrate-web-editor-to-enriched
Jun 10, 2026
Merged

Migrate web editor to react-native-enriched (web demo + UX fixes)#13
winrid merged 6 commits into
mainfrom
migrate-web-editor-to-enriched

Conversation

@winrid

@winrid winrid commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Unifies the comment composer on react-native-enriched across native and web, and fixes the issues found while testing the enriched editor in the browser demo.

Migration

  • Web editor moved from Quill to react-native-enriched 0.7.0 (single comment-text-area.tsx for both platforms).

Web demo (example-web)

  • Runs on React 19 + react-native-web 0.21 (the enriched component reads ref as a prop, the React 19 convention; rnw 0.19 calls the removed ReactDOM.findDOMNode).
  • Vite: alias inline-style-prefixer CJS to its ESM build, pre-bundle CJS sub-entries (styleq/transform-localize-style, fbjs/lib/*, react-dom/client), and dedupe react/react-dom.

Fixes

  • Editor height - the contenteditable now fills its bordered box (was only the first line clickable).
  • Guest auth form - mirror the web widget: show the name/email form when there is no authorized user (was tied to replies only); reset the spinner on validation early-return.
  • Persist authenticated user after submit - merge response.user into the session (and read fresh state for the sessionId) so the form hides and the top bar updates instead of reverting to the anon user.
  • Loading indicator - fill via normal flow instead of an absolute overlay that collapsed and clipped the spinner.
  • @mentions - detect triggers in block-wrapped HTML; insert inline (no stray newline); overlay via a portal to body so it is not clipped/stacked by the comment list; keyboard nav (arrows / Enter / Tab / Esc); single-token queries + non-breaking-space commit so typing past a mention does not re-trigger.

Tests

  • New dependency-free mention-detection module with unit tests for the real block-wrapped editor output.
  • jest: 110 passed; tests-ui: 7 passed. Verified end-to-end in headless Chrome.

winrid added 6 commits June 2, 2026 00:44
Unify the comment composer on react-native-enriched across all platforms.
Previously native used react-native-enriched (0.5.2) while web used Quill
(react-quill-new); now that react-native-enriched 0.7.0 ships experimental
web support via package `exports` conditions, both platforms share a single
implementation.

- Bump react-native-enriched 0.5.2 -> 0.7.0 (web support); make it a
  required (non-optional) peer at >=0.7.0.
- Drop quill / react-quill-new from dev and peer dependencies.
- Collapse comment-text-area.native.tsx + comment-text-area.web.tsx into a
  single comment-text-area.tsx. The same EnrichedTextInput API resolves to
  the native build on Metro and the web build on web bundlers, so web now
  gets the @mention popup that the Quill path was missing, plus inline-code
  formatting (toggleInlineCode) on both platforms.
- example-web: pre-bundle react-native-enriched instead of quill, and add an
  exact-match react-native -> react-native-web alias so the enriched web
  build's bare `react-native` import (processColor) resolves during the
  production build.
- Update the stale README (it still referenced the long-removed 10tap editor
  and react-native-webview) and the tests-ui enriched mock.
react-native-enriched 0.7.0's component reads `ref` as a prop (React 19
convention), so the web editor's imperative API never attached under the
demo's React 18 - the toolbar, focus, setValue and image insert all
no-op'd. Bump react/react-dom to 19 and react-native-web to 0.21 (0.19
calls the removed ReactDOM.findDOMNode under React 19; 0.20+ supports both).

Also fix the Vite dev setup the bump and the enriched web build surfaced:
- alias inline-style-prefixer's CJS `lib/*` deep paths to its ESM `es/*`
  build, and pre-bundle the CJS sub-entries react-native-web imports
  (styleq/transform-localize-style, fbjs/lib/invariant|warning,
  react-dom/client) so the browser doesn't choke on missing ESM exports.
- dedupe react/react-dom so the SDK source (imported from ../src) shares
  the single React 19 instance instead of pulling its own copy.
Three issues surfaced testing the enriched web editor:

- Editor only accepted clicks on the first line. tiptap's contenteditable
  (.ProseMirror) auto-sizes to its content inside the .eti-editor wrapper
  that gets our minHeight/flex, so the rest of the box was a dead div.
  Inject a tiny web-only rule to make the editor fill its wrapper.

- Submitting a comment spun forever and made no request. submit()'s
  validation early-return never reset isReplySaving, and the guest
  name/email form never showed: needsAuth was `!currentUser &&
  !!parentComment`, which only prompted on replies and treated the anon
  session (present from connect, no username/email) as logged in. Mirror
  the web widget: show the form when there's no authorized user or an anon
  session still owes an email; reset the spinner on early return; default
  the inputs to '' to avoid a controlled/uncontrolled warning.

- @mention popup never appeared. detectMentionQuery bailed on the trailing
  newline that </p> produces in plain text, and the editor always wraps
  content in <p>...</p>. Strip trailing newlines before detecting. Extract
  detectMentionQuery/htmlToPlainText into a dependency-free module and add
  unit tests covering the real block-wrapped editor output.
The loading state early-returns only an absolutely-positioned overlay
(inset:0). With nothing in flow its container collapses to 0 height, and on
web (where the host #root is not always a flex container) a 0-height inset:0
box centers the large spinner on y=0 - i.e. half off the top of the screen.
Fill via normal flow (flex + a minHeight floor) so it cannot collapse, and
make the demo #root a flex container so the widget fills the viewport.
- Overlay the popup via a portal to document.body so it is not clipped by
  the scrollable comment list or painted under later comment rows. The
  composer lives inside react-native-web's virtualized list, whose
  transformed ancestor traps even position:fixed, so a web-only portal
  (mention-portal.web.tsx) is the reliable escape; native renders inline.
- Keyboard nav: arrow keys move the highlight, Enter/Tab select, Esc
  dismisses. Intercepted on the editor wrapper in the capture phase because
  the enriched web build forwards keydown but always returns false to
  ProseMirror, so there is no supported way to cancel its handling.
- Insert mentions inline with replaceActiveMention (splice at the located
  @query) rather than an end-anchored regex that missed block-wrapped HTML
  and appended onto a new line ("@A\n@name").
- The query is a single token (any whitespace ends it) and mentions commit
  with a non-breaking space, so typing past a completed mention no longer
  reopens the popup with "no matches".

Detection/insertion live in a dependency-free mention-detection module with
unit tests covering the real block-wrapped editor output.
On a successful post the API returns an authorized user carrying the
email/username the guest entered. A second update block then re-applied a
stale pre-merge snapshot, reverting currentUser to the anonymous session -
so the name/email form stayed visible and the top bar never updated. Merge
response.user into the session (matching the web widget) and read fresh
store state when applying the sessionId so it no longer clobbers the merge.
@winrid winrid changed the title Migrate web editor from Quill to react-native-enriched Migrate web editor to react-native-enriched (web demo + UX fixes) Jun 10, 2026
@winrid winrid merged commit 1f238da into main Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant