fix(admin): improve portable text editor controls#2064
fix(admin): improve portable text editor controls#2064khoinguyenpham04 wants to merge 11 commits into
Conversation
🦋 Changeset detectedLatest commit: 203c39b The changes in this PR will be included in the next version bump. This PR includes changesets to release 16 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-cache | 203c39b | Jul 16 2026, 02:45 PM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-do | 203c39b | Jul 16 2026, 02:46 PM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-playground | 203c39b | Jul 16 2026, 02:44 PM |
Scope checkThis PR changes 2,226 lines across 13 files. Large PRs are harder to review and more likely to be closed without review. If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs. See CONTRIBUTING.md for contribution guidelines. |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/registry-verification
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
There was a problem hiding this comment.
This PR is a well-scoped UI refinement of the TipTap portable-text editor: it centers the writing column, collapses headings into a dropdown, adds a coarse-pointer block inserter, fixes floating-menu collision logic, and hardens the gutter slash-menu keyboard/mouse flow. The change stays inside the admin package, doesn’t touch backend routes or storage, and includes extensive tests, so it fits EmDash’s architecture.
I read the full diff, the changed source files, and the related editor tests. The implementation is solid and the test coverage is good. I’m flagging a small but real AGENTS/localization violation (two unlocalized placeholder="https://..." examples in the DOM), plus two lower-severity suggestions for using Kumo consistently and exposing the slash-menu selection to screen readers.
Findings
-
[needs fixing]
packages/admin/src/components/PortableTextEditor.tsx:3003The bubble-menu link input hard-codes
"https://..."as a placeholder. This is user-facing English that bypasses Lingui extraction, violating the AGENTS.md rule that every admin UI string goes through Lingui.placeholder={t`https://...`} -
[needs fixing]
packages/admin/src/components/PortableTextEditor.tsx:3564The toolbar link popover repeats the same unlocalized
"https://..."placeholder. Wrap it with Lingui so it can be extracted with the rest of the admin catalog.placeholder={t`https://...`} -
[suggestion]
packages/admin/src/components/editor/DragHandleWrapper.tsx:170The drag-handle control uses a hand-rolled
<button>with Kumo-style tokens instead of the KumoButtonprimitive. The sibling plus-button already uses KumoButton, so this is inconsistent and duplicates styling logic. Prefer Kumo’sButton(orbuttonVariantsif the element absolutely must stay native). For example:<Button ref={handleRef} type="button" variant="ghost" shape="square" className={cn( "h-6 w-6 flex-none rounded select-none", "text-kumo-subtle/50 hover:text-kumo-subtle", "hover:bg-kumo-tint/80 cursor-grab active:cursor-grabbing", "transition-colors duration-100", menuOpen && "text-kumo-subtle bg-kumo-tint", )} onClick={handleClick} data-block-handle aria-label={t`Block actions - drag to reorder, click for menu`} > <DotsSixVertical className="h-4 w-4" /> </Button> -
[suggestion]
packages/admin/src/components/PortableTextEditor.tsx:1352The slash command menu communicates the selected item only through the
bg-kumo-tintcolor class. Since the PR explicitly mentions improving screen-reader state, expose the selected state witharia-current(or wrap the list inrole="listbox"and userole="option"+aria-selected).<button key={item.id} type="button" data-index={index} aria-current={index === state.selectedIndex ? "true" : undefined} className={cn(
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
There was a problem hiding this comment.
This PR remains a well-scoped UI refinement of the admin TipTap editor: it centers the writing column, collapses headings into a compact dropdown, adds a coarse-pointer block inserter, separates inline and table bubble menus, and hardens gutter slash-menu keyboard/mouse behavior. The change stays inside @emdash-cms/admin, touches no backend or storage code, and ships an extensive test suite plus a correct changeset.
I verified that the four findings from the prior review are all addressed in this revision:
- Both
"https://..."placeholders are now wrapped with Lingui (t\https://...``). - The drag-handle controls now render as Kumo
Buttonprimitives, with tests assertingdata-kumo-component="Button". - The slash command menu exposes the selected item with
aria-current="true"and also announces it to screen readers via arole="status"region.
The implementation is solid overall. I’m leaving one new low-severity comment: the table bubble menu introduces a Kumo Tooltip usage that doesn’t match the render-prop trigger pattern used everywhere else in the repo, so the hover tooltip likely fails to attach to the actual button.
Tests were not run per the static-review policy; the author reports the full admin suite (1,131 tests) and focused editor suites (111 tests) pass.
|
@khoinguyenpham04 Love it! Overall solid improvement 🙌 One interaction feels a bit off:
|
|
Ah, good spot @masonjames |
|
@masonjames thank you for reviewing it! I'm on to fixing it. |



What does this PR do?
Makes the portable text editor easier and more reliable to use:
This also improves keyboard navigation, screen-reader state, narrow-screen behavior, and RTL icon placement.
Related issue: N/A
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runmessages.pochanges except in translation PRs — a workflow extracts catalogs on merge tomain.AI-generated code disclosure
Screenshots / test output
No screenshots included.
pnpm typecheckpnpm lintpnpm --filter @emdash-cms/admin test --run— 1,131 tests passedTry this PR
Open a fresh playground →
A full working EmDash site, deployed from this branch. Each visit gets its own session-scoped sandbox: no login needed and no shared state. Try the admin, edit content, hit the public site.
Tracks
feat/tiptap-editor-refinements. Updated automatically when the playground redeploys.