Repository navigation
Notes: Support inline rich text (bold, italic, link, code) - #78242
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
Size Change: -79 B (0%) Total Size: 7.71 MB 📦 View Changed
|
|
Sorry, don't have time to do a proper review now. A technical note: we shouldn't use |
Hmmm, that sounds like a bug. Checking.
Ok, thanks for the tip @Mamaduka and reference. I guess that means this ticket is blocked by #75275, unless you think there is a different approach we should use in the meantime? |
9eabe70 to
36b8be3
Compare
Per review feedback on #78242, replace the block-editor RichText component with RichTextControl introduced in #75275. RichText is intended for use inside blocks and pulls in editor state (selection store, format toolbar wiring, etc.) that the note form does not need. RichTextControl wraps useRichText directly and exposes the smaller surface the note form actually uses, which mirrors the approach DataForms takes for its rich-text field. The form keeps the same allowed-formats list (bold, italic, link, code), the same keyboard shortcuts (Cmd+B / Cmd+I / Cmd+K), and the same empty-state submit guard. The Cmd+Enter / Escape handling moves up to the form element because RichTextControl does not expose an onKeyDown prop; the events still reach it via bubbling from the contenteditable. Note styles are rescoped to the form-level container (the input now carries the .block-editor-rich-text-control class) and the explicit VisuallyHidden label is replaced by RichTextControl's built-in hideLabelFromVision option. Refs #75275 Refs #73413
NoteForm reused its visually hidden accessibility label as the visible placeholder, so the reply field showed the full 'Reply to note N by author' description. Trunk renders these fields with a hidden label and no placeholder; restore that behavior and drop the now-unused placeholder color override.
The richtext control now portals its format popovers (e.g. the Cmd+K link UI) to the body so overflow ancestors cannot clip them. Focus moving into one therefore leaves the thread's DOM, and the thread's blur handler deselected the note, unmounting the reply form and the popover with it. Carve out focus landing in a popover, mirroring the new-note form in add-note.js. Add e2e coverage for the link popover in the reply form (opens, stays mounted, lies fully within the viewport) and for the note fields not rendering their hidden labels as placeholders.
|
Both confirmed and fixed, @Mamaduka — one was specific to this PR, one general to #78471:
Both flows are now covered by e2e tests in
|
…ol-package # Conflicts: # packages/rich-text/CHANGELOG.md
Co-authored-by: Lena Morita <lena@jaguchi.com>
The @wordpress/ui direction is no stable public class names on components, so styling hooks must not leak from the component itself. The validated wrapper now applies its own class and targets the inner editable via [role="textbox"] for the error treatment, per review suggestion on #78471.
The description/aria-live changes to ControlWithError affect every delegate-based validated control, so they need broader consideration and testing (see #76741). Revert ControlWithError to trunk and skip the description-association test, matching how the other delegate-based controls document the same pre-existing limitation.
…into restack/notes-rich-text-on-rtc
The base PR removed the stable class per review — components expose no public styling hooks. Scope the note form's editable tweaks by role instead.
The placeholder-leak fix shipped without asserting the aria-placeholder or the accessible names, so the hidden label could silently reappear as a visible placeholder on divergent branches. Assert both fields expose no placeholder and keep their visually hidden labels as the accessible name.
The @example tag removal was applied through the GitHub UI, which skips the local docs regeneration hook; the code snippet now flows into the generated readme as intended.
…into restack/notes-rich-text-on-rtc
…into restack/notes-rich-text-on-rtc
|
Tested and the expected keyboard shortcuts and backticks work as expected, though I hadn't read the PR description at first and was surprised to see now simple richtext editing options in the notes textarea so we'll want to ensure we include in user education / marketing that we note its keyboard shortcuts that allow these. |
I fixed this bug and restored the current core behavior of no placeholders. |
|
oh that's a nice UI improvement from Google, perhaps something to consider in the @mentions PR though could also be a follow-up improvement after landing the @mention work for this release as more imperative? |
We can add it in #79604 |
Mamaduka
left a comment
There was a problem hiding this comment.
Thanks for bringing this over the line, @adamsilverstein! The feature tests well for me ✅
Pushed two minor cleanup commits:
- Remove 'focusOnMount'; the 'focusNote' handles this explicitly
- Combine dialog/popover focus checks in note thread
I think this is good to merge. Anything we missed can be fixed during the beta/RC cycle.





What?
Adds a minimal, safe rich text input to Notes, replacing the plain textarea with the
RichTextControlassembly from@wordpress/dataviews(introduced in #78471, now merged) - restricted to bold, italic, link, andcodeformatting. Keyboard shortcuts (⌘B / ⌘I / ⌘K) work; no visible toolbar. Surrounding text with backticks (`) adds code formatting.Closes #73413.
Preps code for @ mentions - #79604
Test in Playground: https://playground.wordpress.net/?gutenberg-pr=78242
Built on #78471 (merged)
This PR builds on #78471, which landed a standalone rich text form field in two layers: a presentational
ContentEditableControlshell in@wordpress/components(private API), and aRichTextControlassembly in@wordpress/dataviewsthat wires@wordpress/rich-text(useRichText,FormatEdit, keyboard-shortcut / input-event listeners) into that shell as the DataFormrichtextcontrol. This PR exposes the assembly through@wordpress/dataviewsprivate APIs and makes the notes sidebar its second consumer.Why a standalone control?
This input was originally prototyped against
RichTextfrom@wordpress/block-editor, then against an earlierRichTextControlexposed through the block-editor private API (#75275). Both coupled a tiny inline field to block-editor machinery it doesn't need - the selection store, the format-toolbar slot fill, block-attribute persistence - which leaked focus/selection bugs into the note form (see the workaround history on this branch).The control that landed in #78471 wraps
useRichTextdirectly and exposes the smallvalue/onChangesurface a standalone field actually needs. Because it skips block-editor selection coupling, focusing the note input no longer shifts the canvas block selection, which let this PR delete the clientId-snapshot workaround the earlier stacking required.Why?
Per discussion in #73413 with @jasmussen and @Mamaduka, Notes needed a lightweight inline rich-text input - useful for emphasizing labels, linking to references, and quoting identifiers - but without taking up sidebar space with a toolbar. This PR ships the smallest viable formatting set (bold/italic/link/code) so reviewers can express feedback more clearly without bloating the UI.
How?
@wordpress/dataviews-packages/dataviews/src/private-apis.ts(new)richtextcontrol'sRichTextControlassembly as a private API (vialock/unlock) so other core packages can render a standalone rich text form field without a DataForm.Client -
packages/editor/src/components/collab-sidebar/note-form.jsRichTextControl(unlocked from@wordpress/dataviews) withallowedFormats = ['core/bold','core/italic','core/link','core/code']andhideLabelFromVisionfor the accessible label.undefinedon failure (they surface their own error notice), so the draft is only cleared once the save actually succeeded - and only if the user hasn't typed more in the meantime.focusOnMountprop: the new-note form passes it so the caret lands in the field immediately; the reply form omits it so selecting a thread doesn't pull focus away from thread keyboard navigation.Add-note form -
packages/editor/src/components/collab-sidebar/add-note.jsrelatedTarget = nullblurs on the next frame (rich-text re-renders briefly drop focus to the body while typing), and keep the form open while a format popover (e.g. the ⌘K link UI, which portals out of the form) holds focus.AddNotereads the selected block directly like before.Thread -
packages/editor/src/components/collab-sidebar/note-thread.js[role="textbox"]now that it's no longer a textarea.Server - no changes needed. The default comment kses allowlist already permits the note formats (
strong,em,a,code) for users withoutunfiltered_html, and users withunfiltered_htmlare trusted with comment HTML everywhere else in core, so note content goes through the standard comment filter chain unchanged.Output - already renders HTML via
RawHTMLand the excerpt path already callsstripHTML, so no display-side changes were needed.Testing instructions
Test in Playground: https://playground.wordpress.net/?gutenberg-pr=78242
npm run wp-env start && npm start.Automated tests
npm run test:unit -- packages/editor/src/components/collab-sidebarandnpm run test:unit -- packages/dataviews/src/components/dataform-controls(the control's own tests landed with DataViews: Add a richtext control backed by a private RichTextControl shell in @wordpress/components #78471 and cover the format/shortcut/input-rule behavior this PR relies on).npm run test:e2e -- test/e2e/specs/editor/various/block-notes.spec.jsandtest/e2e/specs/editor/collaboration/collaboration-notes.spec.ts. Now that the standalone control holds focus and applies formats correctly, the rich-text flows (bold/code keyboard shortcuts, the Cmd+K link UI) and the focus-on-open of a new note are re-enabled and pass locally (29 passed). Six reply/thread focus flows stay deferred behindtest.fixme: the reply form deliberately does not focus on mount so selecting a thread doesn't pull focus away from thread keyboard navigation, and wiring focus into the reply/skip-link paths is follow-up work rather than part of this restack.Out of scope (deferred per issue discussion)
**bold**, etc.) - only the backtick-wrapping input rule for code ships today; keyboard shortcuts cover the rest of the primary UX.Screenshots/ Screencast
rich.text.notes.mp4
Types of changes
New feature.
Checklist