Skip to content

Phase 4b: inline editor insert dialogs (replace window.prompt link/image/file)#33

Merged
bnz183 merged 1 commit into
mainfrom
feat/editor-conventions
Jun 19, 2026
Merged

Phase 4b: inline editor insert dialogs (replace window.prompt link/image/file)#33
bnz183 merged 1 commit into
mainfrom
feat/editor-conventions

Conversation

@bnz183

@bnz183 bnz183 commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Phase 4b — editor link/image/file UX

Second PR of the Phase 4 UX pass. Stacked on #32 (Phase 4a) — base is feat/design-system-foundation, so this diff is 4b only. Merge #32 first.

Brings the editor up to Google-Docs/Notion conventions by removing the blocking native window.prompt flows.

What changed

  • New EditorInsertDialog — accessible in-Studio dialog (role="dialog", aria-modal, labelled fields, autofocus, Enter submits, Escape/backdrop cancels) for inserting links, images, and file links. Editing an existing link offers Remove link.
  • New editorInsert helpersnormalizeUrl (bare domains gain https://; relative paths, anchors, mailto:/tel: preserved), fileLabelFromPath, hasUrl. Unit-tested.
  • SourceDraftEditor owns the dialog state and performs editor mutations; EditorToolbar and the slash commands just request the dialog — no window.prompt anywhere in the editor path.
  • Removed the unused legacy MarkdownToolbar (the last window.prompt; dead code).
  • Dialog styled with 4a design-system tokens.

Tests

  • Unit: editorInsert.test.ts.
  • e2e (demo mode): link insert (asserts href), image insert (asserts src), Escape cancels without inserting.
  • Local: pnpm build ✅ · pnpm test ✅ (studio 133/133) · pnpm lint ✅ · pnpm test:e2e ✅ (22/22).

Notes

  • Toolbar targets (≥24px) and editor token usage were already handled in 4a, so this PR focuses on the prompt-replacement headline. A fuller SVG icon set for the toolbar can follow if desired.

Next

  • 4c — Onboarding/config: stage Settings one-thing-per-page, guided connect-your-blog first run.
  • Final — QA sweep.

🤖 Generated with Claude Code

Replace the blocking window.prompt link / image / file-link flows (both the
toolbar and slash commands) with an accessible in-Studio dialog:

- new EditorInsertDialog: labelled fields, Enter to submit, Escape to cancel,
  backdrop click to dismiss, autofocus; "Remove link" when editing a link
- new editorInsert helpers (normalizeUrl, fileLabelFromPath, hasUrl) — bare
  domains gain https://; relative paths/anchors/mailto preserved (unit-tested)
- SourceDraftEditor now owns the dialog state and performs the editor mutations;
  EditorToolbar just requests open via callbacks (no window.prompt anywhere)
- removed the unused legacy MarkdownToolbar (last window.prompt; dead code)
- dialog styled with design-system tokens

Adds unit tests (editorInsert) and e2e (link insert, image insert, Escape
cancels). Stacked on feat/design-system-foundation (Phase 4a).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 882b2be6b9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

return;
}
const defaultPath =
latestUpload?.kind === "pdf" ? latestUpload.publicPath : "/files/";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid inserting file links with an empty label

When there is no latest PDF upload, the file dialog is prefilled with /files/; because that non-empty value enables submission, clicking “Insert file link” immediately reaches fileLabelFromPath('/files/'), whose basename is '', and the editor then attempts to insert a link with empty text/no visible label. This regresses the old prompt flow, which fell back to the full path for trailing-slash input. Please either make this a placeholder until the user enters a file path or make the label helper fall back when the basename is empty.

Useful? React with 👍 / 👎.

// of React and Tiptap so they can be unit-tested directly.

const ABSOLUTE_OR_RELATIVE =
/^(https?:|mailto:|tel:|\/|#|\.\/|\.\.\/)/iu;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve extension-only relative paths

When a user enters a same-directory relative file such as guide.md or photo.jpg, this pattern treats it as a bare domain and rewrites it to https://guide.md/https://photo.jpg. The dialog labels accept paths and the helper claims relative paths are preserved, so Markdown links/images to local files without a leading ./ are now published as broken external URLs.

Useful? React with 👍 / 👎.

editor.chain().focus().setImage({ src, alt, title: alt }).run();
}
} else {
const path = values.url.trim();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Normalize file-link URLs before insertion

For the file-link dialog, entering a bare external URL like example.com/file.pdf passes validation because hasUrl normalizes it, but this branch inserts the raw trimmed value. The resulting Markdown link points to the relative path example.com/file.pdf instead of https://example.com/file.pdf, unlike the link and image dialog branches that normalize before writing.

Useful? React with 👍 / 👎.

Comment on lines +99 to +102
className="editor-dialog"
role="dialog"
aria-modal="true"
aria-labelledby={titleId}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Trap focus inside the modal dialog

Because this is a custom aria-modal dialog rather than a native modal, keyboard focus is not automatically contained; when users Tab or Shift+Tab past the URL/text/action controls, focus can move to toolbar/editor controls behind the overlay while the dialog is still open. Add focus trapping or make the background inert so keyboard users cannot operate the underlying editor from an active modal.

Useful? React with 👍 / 👎.

@bnz183 bnz183 changed the base branch from feat/design-system-foundation to main June 19, 2026 12:10
@bnz183 bnz183 merged commit d0f20b3 into main Jun 19, 2026
5 checks passed
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