Skip to content

Fix allow mouse users to edit link text when Link UI is active#59635

Merged
draganescu merged 18 commits into
trunkfrom
fix/alt-rich-link-ui-text-update-under-link-ui
Mar 11, 2024
Merged

Fix allow mouse users to edit link text when Link UI is active#59635
draganescu merged 18 commits into
trunkfrom
fix/alt-rich-link-ui-text-update-under-link-ui

Conversation

@getdave

@getdave getdave commented Mar 6, 2024

Copy link
Copy Markdown
Contributor

What?

Allows for editing a link underneath popover UI when clicking on it in Rich Text. Restores this portion of the original behaviour in WP 6.4 prior (see below) to updating the UX on the Link UI.

📹 Screencast of behaviour in WP 6.4
Screen.Capture.on.2024-03-07.at.15-43-17.mp4

Alternative to #59599 and #59626.

Fixes #59525

Why?

Currently on trunk if you click a link you cannot edit the text of the link except by:

  • hitting escape
  • using the Text input within the Link UI

This is a regression on WP 6.4 and so this PR tries to solve that.

This is an alternative approach to #59599 and tries to better restore the previous functionality from WP 6.4 in terms of retaining the ability to edit the link text underneath the UI when it has been clicked.

How?

In this PR I have disabled auto focus when a user clicks on a link. This means the focus is not automatically transferred to the popover and remains on the rich text until the mouse user chooses to select the Link UI.

This means mouse users can edit the text underneath the link popover in the same way as keyboard users.

Note that users of mice should be able to perceive that a popover has appeared and thus can use the mouse pointer to choose to edit the link via the control in popover.

The behaviour should remain the same for keyboard users.

I also fixed a hidden bug with useAnchor whereby it cannot distinguish between multiple core/link formats within in a content editable.

Accessibility Checks

Note that the a11y of this PR's approach was discussed during Accessibility team office hours on WP Slack. As part of this we received the following guidance:

For now, I’d opt for:
Not move focus into the link UI when it opens via a mouse click
This would have to advantages:
Mouse users can always click again inside the popover, if their intent is to edit
or simply continue editing the text.

This suggests that this PR does meet a11y standards because the keyboard interactions are maintained as per trunk but mouse users get a more intuitive experience.

Testing Instructions

For this PR please be sure to test against trunk (or WP 6.5 RC) to validate any "issue" isn't something already present as intended behaviour. Link UI UX has changed a lot in WP 6.5 so it's important to validate 🙏

  • New Post
  • Add a paragraph block
  • Add several links to the paragraph block
  • Click on each link in turn and validate that the popover moves correctly between the links, shows the correct contents and anchors correctly.
  • Check that when activating a link via mouse focus is not transferred to the popover and remains on rich text. Check that you can make edits to the text underneath the popover (note this is as per WP 6.4).
  • Check that using a keyboard to interact with links remains as per trunk.
  • Check that adding other formats within a link (e.g. bold, italic .etc) does not prevent accessing the link popover by mouse or keyboard.

Testing Instructions for Keyboard

Screenshots or screencast

Screen.Capture.on.2024-03-06.at.11-14-55.mp4

Co-authored-by: getdave get_dave@git.wordpress.org
Co-authored-by: jeryj jeryj@git.wordpress.org
Co-authored-by: draganescu andraganescu@git.wordpress.org
Co-authored-by: scruffian scruffian@git.wordpress.org
Co-authored-by: bacoords bacoords@git.wordpress.org
Co-authored-by: annezazu annezazu@git.wordpress.org
Co-authored-by: youknowriad youknowriad@git.wordpress.org
Co-authored-by: richtabor richtabor@git.wordpress.org
Co-authored-by: fabiankaegy fabiankaegy@git.wordpress.org

@getdave getdave added [Type] Bug An existing feature does not function as intended [Feature] Link Editing Link components (LinkControl, URLInput) and integrations (RichText link formatting) labels Mar 6, 2024
@github-actions

github-actions Bot commented Mar 6, 2024

Copy link
Copy Markdown

Size Change: +676 B (0%)

Total Size: 1.71 MB

Filename Size Change
build/block-editor/index.min.js 252 kB -223 B (0%)
build/block-editor/style-rtl.css 15.6 kB -79 B (-1%)
build/block-editor/style.css 15.6 kB -85 B (-1%)
build/block-library/blocks/media-text/editor-rtl.css 306 B +40 B (+15%) ⚠️
build/block-library/blocks/media-text/editor.css 305 B +42 B (+16%) ⚠️
build/block-library/blocks/social-links/style-rtl.css 1.48 kB -5 B (0%)
build/block-library/blocks/social-links/style.css 1.48 kB -5 B (0%)
build/block-library/editor-rtl.css 12.4 kB +19 B (0%)
build/block-library/editor.css 12.4 kB +20 B (0%)
build/block-library/index.min.js 217 kB +278 B (0%)
build/block-library/style-rtl.css 14.8 kB -6 B (0%)
build/block-library/style.css 14.8 kB -6 B (0%)
build/blocks/index.min.js 51.8 kB +8 B (0%)
build/components/index.min.js 223 kB +7 B (0%)
build/edit-post/index.min.js 24.2 kB +471 B (+2%)
build/edit-site/index.min.js 216 kB +213 B (0%)
build/edit-site/style-rtl.css 15 kB +18 B (0%)
build/edit-site/style.css 15 kB +17 B (0%)
build/editor/index.min.js 63.7 kB -305 B (0%)
build/format-library/index.min.js 8.02 kB +131 B (+2%)
build/interactivity/index.min.js 13 kB +5 B (0%)
build/patterns/index.min.js 5.71 kB +40 B (+1%)
build/rich-text/index.min.js 10.5 kB +81 B (+1%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 955 B
build/annotations/index.min.js 2.69 kB
build/api-fetch/index.min.js 2.32 kB
build/autop/index.min.js 2.1 kB
build/blob/index.min.js 578 B
build/block-directory/index.min.js 7.22 kB
build/block-directory/style-rtl.css 1.03 kB
build/block-directory/style.css 1.03 kB
build/block-editor/content-rtl.css 4.4 kB
build/block-editor/content.css 4.4 kB
build/block-editor/default-editor-styles-rtl.css 394 B
build/block-editor/default-editor-styles.css 394 B
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 126 B
build/block-library/blocks/audio/theme.css 126 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 104 B
build/block-library/blocks/avatar/style.css 104 B
build/block-library/blocks/block/editor-rtl.css 305 B
build/block-library/blocks/block/editor.css 305 B
build/block-library/blocks/button/editor-rtl.css 415 B
build/block-library/blocks/button/editor.css 414 B
build/block-library/blocks/button/style-rtl.css 627 B
build/block-library/blocks/button/style.css 626 B
build/block-library/blocks/buttons/editor-rtl.css 337 B
build/block-library/blocks/buttons/editor.css 337 B
build/block-library/blocks/buttons/style-rtl.css 332 B
build/block-library/blocks/buttons/style.css 332 B
build/block-library/blocks/calendar/style-rtl.css 239 B
build/block-library/blocks/calendar/style.css 239 B
build/block-library/blocks/categories/editor-rtl.css 113 B
build/block-library/blocks/categories/editor.css 112 B
build/block-library/blocks/categories/style-rtl.css 124 B
build/block-library/blocks/categories/style.css 124 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 421 B
build/block-library/blocks/columns/style.css 421 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 199 B
build/block-library/blocks/comment-template/style.css 198 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 840 B
build/block-library/blocks/comments/editor.css 839 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 636 B
build/block-library/blocks/cover/editor-rtl.css 647 B
build/block-library/blocks/cover/editor.css 650 B
build/block-library/blocks/cover/style-rtl.css 1.69 kB
build/block-library/blocks/cover/style.css 1.68 kB
build/block-library/blocks/details/editor-rtl.css 65 B
build/block-library/blocks/details/editor.css 65 B
build/block-library/blocks/details/style-rtl.css 98 B
build/block-library/blocks/details/style.css 98 B
build/block-library/blocks/embed/editor-rtl.css 322 B
build/block-library/blocks/embed/editor.css 322 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 126 B
build/block-library/blocks/embed/theme.css 126 B
build/block-library/blocks/file/editor-rtl.css 316 B
build/block-library/blocks/file/editor.css 316 B
build/block-library/blocks/file/style-rtl.css 280 B
build/block-library/blocks/file/style.css 281 B
build/block-library/blocks/file/view.min.js 324 B
build/block-library/blocks/footnotes/style-rtl.css 201 B
build/block-library/blocks/footnotes/style.css 199 B
build/block-library/blocks/form-input/editor-rtl.css 227 B
build/block-library/blocks/form-input/editor.css 227 B
build/block-library/blocks/form-input/style-rtl.css 343 B
build/block-library/blocks/form-input/style.css 343 B
build/block-library/blocks/form-submission-notification/editor-rtl.css 340 B
build/block-library/blocks/form-submission-notification/editor.css 340 B
build/block-library/blocks/form-submit-button/style-rtl.css 69 B
build/block-library/blocks/form-submit-button/style.css 69 B
build/block-library/blocks/form/view.min.js 471 B
build/block-library/blocks/freeform/editor-rtl.css 2.61 kB
build/block-library/blocks/freeform/editor.css 2.61 kB
build/block-library/blocks/gallery/editor-rtl.css 947 B
build/block-library/blocks/gallery/editor.css 952 B
build/block-library/blocks/gallery/style-rtl.css 1.72 kB
build/block-library/blocks/gallery/style.css 1.72 kB
build/block-library/blocks/gallery/theme-rtl.css 108 B
build/block-library/blocks/gallery/theme.css 108 B
build/block-library/blocks/group/editor-rtl.css 647 B
build/block-library/blocks/group/editor.css 647 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 189 B
build/block-library/blocks/heading/style.css 189 B
build/block-library/blocks/html/editor-rtl.css 336 B
build/block-library/blocks/html/editor.css 337 B
build/block-library/blocks/image/editor-rtl.css 894 B
build/block-library/blocks/image/editor.css 893 B
build/block-library/blocks/image/style-rtl.css 1.6 kB
build/block-library/blocks/image/style.css 1.59 kB
build/block-library/blocks/image/theme-rtl.css 126 B
build/block-library/blocks/image/theme.css 126 B
build/block-library/blocks/image/view.min.js 1.54 kB
build/block-library/blocks/latest-comments/style-rtl.css 357 B
build/block-library/blocks/latest-comments/style.css 357 B
build/block-library/blocks/latest-posts/editor-rtl.css 213 B
build/block-library/blocks/latest-posts/editor.css 212 B
build/block-library/blocks/latest-posts/style-rtl.css 478 B
build/block-library/blocks/latest-posts/style.css 478 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 B
build/block-library/blocks/media-text/style-rtl.css 505 B
build/block-library/blocks/media-text/style.css 503 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 668 B
build/block-library/blocks/navigation-link/editor.css 669 B
build/block-library/blocks/navigation-link/style-rtl.css 259 B
build/block-library/blocks/navigation-link/style.css 257 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 296 B
build/block-library/blocks/navigation-submenu/editor.css 295 B
build/block-library/blocks/navigation/editor-rtl.css 2.26 kB
build/block-library/blocks/navigation/editor.css 2.26 kB
build/block-library/blocks/navigation/style-rtl.css 2.26 kB
build/block-library/blocks/navigation/style.css 2.25 kB
build/block-library/blocks/navigation/view.min.js 1.02 kB
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 377 B
build/block-library/blocks/page-list/editor.css 377 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 235 B
build/block-library/blocks/paragraph/editor.css 235 B
build/block-library/blocks/paragraph/style-rtl.css 335 B
build/block-library/blocks/paragraph/style.css 335 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 508 B
build/block-library/blocks/post-comments-form/style.css 508 B
build/block-library/blocks/post-content/editor-rtl.css 74 B
build/block-library/blocks/post-content/editor.css 74 B
build/block-library/blocks/post-date/style-rtl.css 61 B
build/block-library/blocks/post-date/style.css 61 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 141 B
build/block-library/blocks/post-excerpt/style.css 141 B
build/block-library/blocks/post-featured-image/editor-rtl.css 666 B
build/block-library/blocks/post-featured-image/editor.css 662 B
build/block-library/blocks/post-featured-image/style-rtl.css 342 B
build/block-library/blocks/post-featured-image/style.css 342 B
build/block-library/blocks/post-navigation-link/style-rtl.css 215 B
build/block-library/blocks/post-navigation-link/style.css 214 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 409 B
build/block-library/blocks/post-template/style.css 408 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-time-to-read/style-rtl.css 69 B
build/block-library/blocks/post-time-to-read/style.css 69 B
build/block-library/blocks/post-title/style-rtl.css 100 B
build/block-library/blocks/post-title/style.css 100 B
build/block-library/blocks/preformatted/style-rtl.css 125 B
build/block-library/blocks/preformatted/style.css 125 B
build/block-library/blocks/pullquote/editor-rtl.css 135 B
build/block-library/blocks/pullquote/editor.css 135 B
build/block-library/blocks/pullquote/style-rtl.css 354 B
build/block-library/blocks/pullquote/style.css 354 B
build/block-library/blocks/pullquote/theme-rtl.css 168 B
build/block-library/blocks/pullquote/theme.css 168 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 288 B
build/block-library/blocks/query-pagination/style.css 284 B
build/block-library/blocks/query-title/style-rtl.css 63 B
build/block-library/blocks/query-title/style.css 63 B
build/block-library/blocks/query/editor-rtl.css 486 B
build/block-library/blocks/query/editor.css 486 B
build/block-library/blocks/query/view.min.js 958 B
build/block-library/blocks/quote/style-rtl.css 237 B
build/block-library/blocks/quote/style.css 237 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 140 B
build/block-library/blocks/read-more/style.css 140 B
build/block-library/blocks/rss/editor-rtl.css 149 B
build/block-library/blocks/rss/editor.css 149 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 184 B
build/block-library/blocks/search/editor.css 184 B
build/block-library/blocks/search/style-rtl.css 629 B
build/block-library/blocks/search/style.css 628 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/search/view.min.js 478 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 229 B
build/block-library/blocks/separator/style.css 229 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 323 B
build/block-library/blocks/shortcode/editor.css 323 B
build/block-library/blocks/site-logo/editor-rtl.css 754 B
build/block-library/blocks/site-logo/editor.css 754 B
build/block-library/blocks/site-logo/style-rtl.css 204 B
build/block-library/blocks/site-logo/style.css 204 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 116 B
build/block-library/blocks/site-title/editor.css 116 B
build/block-library/blocks/site-title/style-rtl.css 57 B
build/block-library/blocks/site-title/style.css 57 B
build/block-library/blocks/social-link/editor-rtl.css 184 B
build/block-library/blocks/social-link/editor.css 184 B
build/block-library/blocks/social-links/editor-rtl.css 682 B
build/block-library/blocks/social-links/editor.css 681 B
build/block-library/blocks/spacer/editor-rtl.css 350 B
build/block-library/blocks/spacer/editor.css 350 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 395 B
build/block-library/blocks/table/editor.css 395 B
build/block-library/blocks/table/style-rtl.css 639 B
build/block-library/blocks/table/style.css 639 B
build/block-library/blocks/table/theme-rtl.css 146 B
build/block-library/blocks/table/theme.css 146 B
build/block-library/blocks/tag-cloud/style-rtl.css 251 B
build/block-library/blocks/tag-cloud/style.css 253 B
build/block-library/blocks/template-part/editor-rtl.css 403 B
build/block-library/blocks/template-part/editor.css 403 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/term-description/style-rtl.css 111 B
build/block-library/blocks/term-description/style.css 111 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 99 B
build/block-library/blocks/verse/style.css 99 B
build/block-library/blocks/video/editor-rtl.css 552 B
build/block-library/blocks/video/editor.css 555 B
build/block-library/blocks/video/style-rtl.css 185 B
build/block-library/blocks/video/style.css 185 B
build/block-library/blocks/video/theme-rtl.css 126 B
build/block-library/blocks/video/theme.css 126 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.11 kB
build/block-library/common.css 1.11 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/reset-rtl.css 472 B
build/block-library/reset.css 472 B
build/block-library/theme-rtl.css 688 B
build/block-library/theme.css 693 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/commands/index.min.js 15.6 kB
build/commands/style-rtl.css 935 B
build/commands/style.css 930 B
build/components/style-rtl.css 11.8 kB
build/components/style.css 11.8 kB
build/compose/index.min.js 12.6 kB
build/core-commands/index.min.js 2.77 kB
build/core-data/index.min.js 72.8 kB
build/customize-widgets/index.min.js 11.2 kB
build/customize-widgets/style-rtl.css 1.36 kB
build/customize-widgets/style.css 1.36 kB
build/data-controls/index.min.js 640 B
build/data/index.min.js 8.95 kB
build/date/index.min.js 17.9 kB
build/deprecated/index.min.js 451 B
build/dom-ready/index.min.js 324 B
build/dom/index.min.js 4.65 kB
build/edit-post/classic-rtl.css 558 B
build/edit-post/classic.css 558 B
build/edit-post/style-rtl.css 5.58 kB
build/edit-post/style.css 5.57 kB
build/edit-widgets/index.min.js 17.3 kB
build/edit-widgets/style-rtl.css 4.17 kB
build/edit-widgets/style.css 4.16 kB
build/editor/style-rtl.css 5.34 kB
build/editor/style.css 5.33 kB
build/element/index.min.js 4.83 kB
build/escape-html/index.min.js 537 B
build/format-library/style-rtl.css 492 B
build/format-library/style.css 490 B
build/hooks/index.min.js 1.55 kB
build/html-entities/index.min.js 448 B
build/i18n/index.min.js 3.58 kB
build/interactivity/file.min.js 447 B
build/interactivity/image.min.js 1.67 kB
build/interactivity/navigation.min.js 1.15 kB
build/interactivity/query.min.js 740 B
build/interactivity/router.min.js 1.36 kB
build/interactivity/search.min.js 618 B
build/is-shallow-equal/index.min.js 527 B
build/keyboard-shortcuts/index.min.js 1.74 kB
build/keycodes/index.min.js 1.46 kB
build/list-reusable-blocks/index.min.js 2.11 kB
build/list-reusable-blocks/style-rtl.css 851 B
build/list-reusable-blocks/style.css 849 B
build/media-utils/index.min.js 2.9 kB
build/modules/importmap-polyfill.min.js 12.2 kB
build/notices/index.min.js 948 B
build/nux/index.min.js 2 kB
build/nux/style-rtl.css 747 B
build/nux/style.css 742 B
build/patterns/style-rtl.css 553 B
build/patterns/style.css 552 B
build/plugins/index.min.js 1.8 kB
build/preferences-persistence/index.min.js 2.05 kB
build/preferences/index.min.js 2.82 kB
build/preferences/style-rtl.css 710 B
build/preferences/style.css 712 B
build/primitives/index.min.js 975 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 1 kB
build/react-i18n/index.min.js 623 B
build/react-refresh-entry/index.min.js 9.47 kB
build/react-refresh-runtime/index.min.js 6.78 kB
build/redux-routine/index.min.js 2.7 kB
build/reusable-blocks/index.min.js 2.72 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/router/index.min.js 1.79 kB
build/server-side-render/index.min.js 1.95 kB
build/shortcode/index.min.js 1.39 kB
build/style-engine/index.min.js 2.1 kB
build/token-list/index.min.js 582 B
build/url/index.min.js 3.72 kB
build/vendors/inert-polyfill.min.js 2.48 kB
build/vendors/react-dom.min.js 41.8 kB
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 957 B
build/warning/index.min.js 249 B
build/widgets/index.min.js 7.21 kB
build/widgets/style-rtl.css 1.17 kB
build/widgets/style.css 1.17 kB
build/wordcount/index.min.js 1.02 kB

compressed-size-action

Comment thread packages/format-library/src/link/inline.js Outdated
@getdave getdave marked this pull request as ready for review March 6, 2024 11:30
@github-actions

github-actions Bot commented Mar 6, 2024

Copy link
Copy Markdown

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 props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: getdave <get_dave@git.wordpress.org>
Co-authored-by: jeryj <jeryj@git.wordpress.org>
Co-authored-by: draganescu <andraganescu@git.wordpress.org>
Co-authored-by: scruffian <scruffian@git.wordpress.org>
Co-authored-by: youknowriad <youknowriad@git.wordpress.org>
Co-authored-by: bacoords <bacoords@git.wordpress.org>
Co-authored-by: joedolson <joedolson@git.wordpress.org>
Co-authored-by: annezazu <annezazu@git.wordpress.org>
Co-authored-by: richtabor <richtabor@git.wordpress.org>
Co-authored-by: fabiankaegy <fabiankaegy@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@draganescu

This comment was marked as resolved.

@scruffian

This comment was marked as resolved.

@getdave

This comment was marked as resolved.

@jeryj

This comment was marked as resolved.

@bacoords

This comment was marked as resolved.

@draganescu

Copy link
Copy Markdown
Contributor

@getdave in my video there are two issues (Safari):

  1. On first click the focus is not moved to the popover
  2. On clicking on another link the popover is still anchored to the 1st link

@getdave

getdave commented Mar 6, 2024

Copy link
Copy Markdown
Contributor Author
  1. On first click the focus is not moved to the popover

That's intentional in order to solve the Issue. By not forcing focus we can manipulate the text underneath. However the auto focus is retained for keyboard users when they initiate opening the Link UI.

On clicking on another link the popover is still anchored to the 1st link

That's a bug. I think because something changed and now the component doesn't unmount and so doesn't find it's new position.

@getdave

This comment was marked as resolved.

Comment thread packages/format-library/src/link/index.js Outdated
@jeryj

This comment was marked as resolved.

Comment thread packages/format-library/src/link/index.js Outdated
@getdave

getdave commented Mar 7, 2024

Copy link
Copy Markdown
Contributor Author
  1. If you click a link, then use the arrow keys to move the caret off the link and onto another link, the popover will open again

Fixed in d4e6861. Generally i'd consider this an anti-pattern, but here I think it's valid because the incoming state cannot be synced in any other way and is triggered by changes outside the React tree (i.e. contenteditable). Open to being told I'm wrong though.

  1. The Link UI position gets "stuck" on the second clicked link

I've fixed this in f1b33ee. I believe the current code in trunk has been masking an underlying issue with useAnchor which I've been suspicious of for some time and have tried to narrow down before.

Essentially, if you have multiple anchors within the same content editable then useAnchor has no means to distinguish between them. This is because the args provided to the useLayoutEffect hook within useAnchor do not change when you move between the anchors which means the effect doesn't re-run which means the getAnchor call is never triggered and thus the anchor remains on the last link.

If you're wondering why it's inconsistent then that's because of the usage of usePrevious within the hook to track the last isActive state. This will change between the first and second clicks and thus the effect will run. However, on subsequent clicks the usePrevious will return isActive as true forever more and thus the effect will stop re-running.

My solution is to provide more information to disambiguate the link. I've done this by passing activeAttributes as a dependency because that is used by all format types and not just core/link which means we could pull this out into a standalone fix. Moreover, by defaulting it to a stable object, it guarantees that any consumer of useAnchor that doesn't pass activeAttribute in the settings will behave "as was".

Testing overview
Screen.Capture.on.2024-03-07.at.13-03-30.mp4

Comment thread packages/format-library/src/link/index.js
Comment thread packages/format-library/src/link/index.js Outdated
Comment thread packages/rich-text/src/component/use-anchor.js Outdated
className,
isActive,
wasActive,
// Active attributes is defaulted to a stable object to avoid re-rendering,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It's unclear what the "stable object" idea should offer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I agree. See

The Link UI position gets "stuck" on the second clicked link

...from this comment.

I am loath to modify the API of useAnchor (even if it's "safe") but without this "fix" this PR will not working because the anchor will not be recomputed.

We've run into this issue before but somehow our UI masked the error but it keeps surfacing.

@getdave getdave Mar 8, 2024

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I am actually wondering if I made the function signature use a object is that object "stable" (by which I mean, it is not a new reference on each call of the hook).

Update: I confidence checked myself and no this would be incorrect. We need to provide a stable object as the default and so what I have in the PR now is correct.

// I'm now proposing we DON'T do this...
const {
	tagName,
	className,
	isActive,
	__unstableActiveAttributes: activeAttributes = {}, // new object reference each time :(
} = settings;

The reason why I want a stable object, is because it is one of the deps to the useLayoutEffect and thus if it changes on each render then the effect will run more often then is necessary. For the purposes of backwards compatibility I want to make sure there are no performance regressions introduced by providing this new setting option.

@@ -138,7 +140,12 @@ function getAnchor( editableContentElement, tagName, className ) {
* @return {Element|VirtualAnchorElement|undefined|null} The active element or selection range.
*/
export function useAnchor( { editableContentElement, settings = {} } ) {

@getdave getdave Mar 8, 2024

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@ellatrix I would very much appreciate your opinion on this change.

The crux of this is that when clicking between multiple links in the same contenteditable (i.e. paragraph), the Link UI popover was being incorrectly anchored.

This was because the useLayoutEffect was not being re-run because all the props were the same between renders. This is because all link formats have the same:

  • tagName - this is always a for core/link.
  • className - this is an empty string by default.
  • isActive status - this will vary based on state of link activation.

The last is is probably the one that will peek interest. Whilst it's obvious that the tagName and className will be stable, you'd think isActive would change when moving between links.

It does in fact do this, but when you click on a link the isActive status is set to true. If you then click directly on another link the isActive status remains as true. This state continues across all links so long as you don't click outside of a link format. As a result the useLayoutEffect deps don't change and thus the anchor is not recomputed.

Ultimately I decided what we needed is a way to distinguish between mutliple link formats in a single contenteditable. It is for this reason that I have introduced the activeAttributes as an optional setting prop because this will be unique to each individual format. This guarantees the useLayoutEffect will run and recompute the anchor position correctly.

As I'm not absolutely 100% confident in the API, I've elected to do two things

  1. Default to a stable reference so that any consumer of useAnchor will not cause re-renders if it doesn't pass activeAttributes as one of the settings.
  2. Mark as __unstable.

@getdave getdave Mar 8, 2024

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@youknowriad also pointed out that #58900 seemed to make some large changes to the implementation of useAnchor which may be related to the incorrect anchor situation.

I'm going to continue to dive in here as in essence I would much prefer to avoid any change to useAnchor (excepting reverting to a previous code state) at this juncture.

@getdave getdave Mar 8, 2024

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I reverted (locally only at this stage) useAnchor to the state of the code prior to #58900.

git checkout 7e51b4352cdb5ad22b874d969f8dbb972d233525 packages/rich-text/src/component/use-anchor.js
Patch diff
diff --git a/packages/rich-text/src/component/use-anchor.js b/packages/rich-text/src/component/use-anchor.js
index 3e950d4d3c..5f99509c1f 100644
--- a/packages/rich-text/src/component/use-anchor.js
+++ b/packages/rich-text/src/component/use-anchor.js
@@ -140,48 +140,44 @@ function getAnchor( editableContentElement, tagName, className ) {
  * @return {Element|VirtualAnchorElement|undefined|null} The active element or selection range.
  */
 export function useAnchor( { editableContentElement, settings = {} } ) {
-	const {
-		tagName,
-		className,
-		isActive,
-		__unstableActiveAttributes: activeAttributes = STABLE_OBJECT,
-	} = settings;
+	const { tagName, className } = settings;
 	const [ anchor, setAnchor ] = useState( () =>
 		getAnchor( editableContentElement, tagName, className )
 	);
-	const wasActive = usePrevious( isActive );
 
 	useLayoutEffect( () => {
 		if ( ! editableContentElement ) return;
 
 		const { ownerDocument } = editableContentElement;
 
-		if (
-			editableContentElement === ownerDocument.activeElement ||
-			// When a link is created, we need to attach the popover to the newly created anchor.
-			( ! wasActive && isActive ) ||
-			// Sometimes we're _removing_ an active anchor, such as the inline color popover.
-			// When we add the color, it switches from a virtual anchor to a `<mark>` element.
-			// When we _remove_ the color, it switches from a `<mark>` element to a virtual anchor.
-			( wasActive && ! isActive )
-		) {
+		function callback() {
 			setAnchor(
 				getAnchor( editableContentElement, tagName, className )
 			);
 		}
-	}, [
-		editableContentElement,
-		tagName,
-		className,
-		isActive,
-		wasActive,
-		// Active attributes is defaulted to a stable object to avoid re-rendering,
-		// but in specific circumstances it can be used to provide additional information
-		// about the currently active format to disambiguate the format from other instances of the same format
-		// within the same editable content element. This is useful for `core/link` when you
-		// want to disambiguate between different links when clicking between them.
-		activeAttributes,
-	] );
+
+		function attach() {
+			ownerDocument.addEventListener( 'selectionchange', callback );
+		}
+
+		function detach() {
+			ownerDocument.removeEventListener( 'selectionchange', callback );
+		}
+
+		if ( editableContentElement === ownerDocument.activeElement ) {
+			attach();
+		}
+
+		editableContentElement.addEventListener( 'focusin', attach );
+		editableContentElement.addEventListener( 'focusout', detach );
+
+		return () => {
+			detach();
+
+			editableContentElement.removeEventListener( 'focusin', attach );
+			editableContentElement.removeEventListener( 'focusout', detach );
+		};
+	}, [ editableContentElement, tagName, className ] );
 
 	return anchor;
 }

This appears to fix the anchor positioning issue without requiring any further changes to useAnchor.

Screen.Capture.on.2024-03-08.at.13-58-35.mp4

Therefore I wonder if @jeryj could confirm whether he notices any other regressions as a result of reverting #58900?

It not then I propose we revert the changes in #58900.

@jeryj jeryj Mar 8, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Try creating a link :) The isActive / wasActive checks allow for the popover to reposition when the selection changes the element underneath of it. Ie, going from no markup to an . This bug was attempted to be fixed by caching the position, but that just covered up the underlying issue and caused its own bug of being fixed position on the page when scrolling.

Screen.Recording.2024-03-08.at.9.20.36.AM.mov

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ah yes it was about creation of links. Right. Let's see if we can work this out then.

@getdave getdave Mar 11, 2024

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Circling back, here's what I've done to resolve this:

These changes were made in f923286.

Rationale:

  • changes to remove the listeners in Fix incorrect useAnchor positioning when switching from virtual to rich text elements #58900 were made on the basis of them not being required for the Link UI implementation. However, as useAnchor is exported, we cannot know what use cases it is currently supporting and changing such a key implementation detail has the potential for backwards compatibility issues. Therefore reverting to the state of the code in WP 6.4 should not be considered a "change" for 6.5.
  • changes to introduce the isActive prop were included in WP 6.5 prior to the Beta / RC period and thus are valid to be maintained. They are part of a legitimate bug fix.

From what I can see the functionality is now working as expected but I could do with careful checking.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we cannot know what use cases it is currently supporting and changing such a key implementation detail has the potential for backwards compatibility issues

It's not just about backward compatibility, having the listeners is the right fix to position the anchor properly when you switch between links using the mouse.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sounds like a reasonable way forwards to me. Thanks @getdave!

Comment thread packages/rich-text/src/component/use-anchor.js Outdated
@jeryj

jeryj commented Mar 8, 2024

Copy link
Copy Markdown
Contributor

@jeryj I noticed you forced constrained tabbing in 3f63012. Can I confirm that's an a11y change to enforce some consistency in how the modal behaves once focus is transferred into it? It seems fine to me but I wanted to make sure.

Yup. If you don't constrain tabbing, then it's very easy to accidentally tab outside of the popover, which closes it due to onFocusOutside on the popover closing itself. It is technically a focus trap, but it doesn't feel like one, as it's akin to focus being placed on the wrapper of the popover when clicking a link. Also, escape does work to move back to the caret selection. I think this is one of those murky areas where having a focus trap when you tab into it is actually a better experience for everyone.

@joedolson

Copy link
Copy Markdown
Contributor

Noting that a 'focus trap' is actually a case where there is no way to get out of a context. This is not a focus trap, it's a focus constraint; which limits focus movement, but offers methods to end the constraint - and there are several ways to exit the popover. It does seem like a close button would be beneficial, for clarity - it's a little confusing for a keyboard user to have to click 'edit' in order to cancel.

@getdave

getdave commented Mar 11, 2024

Copy link
Copy Markdown
Contributor Author

As a next step here I am going to explore reverting the changes to useAnchor and go back to having listeners

@getdave

getdave commented Mar 11, 2024

Copy link
Copy Markdown
Contributor Author

I'm proposing this for inclusion in WordPress 6.5 during the RC period. Why? Because

  • this PR fixes a bad bug with the Link UI where mouse users cannot edit the text of the link within the rich text when clicking on a link.
  • this PR reverts the useAnchor implementation to restore code already in use in WP 6.4

@jeryj

jeryj commented Mar 11, 2024

Copy link
Copy Markdown
Contributor

I'm proposing this for inclusion in WordPress 6.5 during the RC period.

👍🏻

// we have an active link format.
if ( event.target.tagName !== 'A' || ! isActive ) {
if (
! event.target.closest( '[contenteditable] a' ) || // other formats (e.g. bold) may be nested within the link.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is an enhancement compared to trunk 😄

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

...yes in terms of it fixes a regression introduced during the 6.5 cycle whereby links that had other formats inside them would not activate on click 👍

@draganescu draganescu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This PR seems to tick all the boxes:

  • fixes the bug
  • improves underlying issues
  • enhances the experience where the bug exists

@draganescu draganescu merged commit e9266d7 into trunk Mar 11, 2024
@draganescu draganescu deleted the fix/alt-rich-link-ui-text-update-under-link-ui branch March 11, 2024 17:43
@github-actions github-actions Bot added this to the Gutenberg 18.0 milestone Mar 11, 2024
getdave added a commit that referenced this pull request Mar 11, 2024
* PoC

* Fix cmd + K with click

* Adding mutually exclusive states

* Sync internal state with format active state

* Fix broken anchors for Links

* Improve variable naming

* Normalize more variable names

* Fix sub formats breaking click to edit

* Force constrainedTabbing for link ui

* Handle nested formats

* Revert change to hasLink var

* Locate const at top of file

* Improve comment

* Add test for editing text

* Improve var naming

* Correct comments

* Make new prop unstable

* Revert useAnchor API

---------

Co-authored-by: getdave <get_dave@git.wordpress.org>
Co-authored-by: jeryj <jeryj@git.wordpress.org>
Co-authored-by: draganescu <andraganescu@git.wordpress.org>
Co-authored-by: scruffian <scruffian@git.wordpress.org>
Co-authored-by: youknowriad <youknowriad@git.wordpress.org>
Co-authored-by: bacoords <bacoords@git.wordpress.org>
Co-authored-by: joedolson <joedolson@git.wordpress.org>
Co-authored-by: annezazu <annezazu@git.wordpress.org>
Co-authored-by: richtabor <richtabor@git.wordpress.org>
Co-authored-by: fabiankaegy <fabiankaegy@git.wordpress.org>
@getdave

getdave commented Mar 11, 2024

Copy link
Copy Markdown
Contributor Author

I just manually cherry-picked this PR to the pick/wp-65-rc-2 branch to get it included in the next release

#59756

@getdave getdave added Backported to WP Core Pull request that has been successfully merged into WP Core and removed Backport to WP Beta/RC labels Mar 11, 2024
@jeryj jeryj mentioned this pull request Mar 11, 2024
getdave added a commit that referenced this pull request Mar 12, 2024
* PoC

* Fix cmd + K with click

* Adding mutually exclusive states

* Sync internal state with format active state

* Fix broken anchors for Links

* Improve variable naming

* Normalize more variable names

* Fix sub formats breaking click to edit

* Force constrainedTabbing for link ui

* Handle nested formats

* Revert change to hasLink var

* Locate const at top of file

* Improve comment

* Add test for editing text

* Improve var naming

* Correct comments

* Make new prop unstable

* Revert useAnchor API

---------

Co-authored-by: getdave <get_dave@git.wordpress.org>
Co-authored-by: jeryj <jeryj@git.wordpress.org>
Co-authored-by: draganescu <andraganescu@git.wordpress.org>
Co-authored-by: scruffian <scruffian@git.wordpress.org>
Co-authored-by: youknowriad <youknowriad@git.wordpress.org>
Co-authored-by: bacoords <bacoords@git.wordpress.org>
Co-authored-by: joedolson <joedolson@git.wordpress.org>
Co-authored-by: annezazu <annezazu@git.wordpress.org>
Co-authored-by: richtabor <richtabor@git.wordpress.org>
Co-authored-by: fabiankaegy <fabiankaegy@git.wordpress.org>
carstingaxion pushed a commit to carstingaxion/gutenberg that referenced this pull request Mar 27, 2024
…ress#59635)

* PoC

* Fix cmd + K with click

* Adding mutually exclusive states

* Sync internal state with format active state

* Fix broken anchors for Links

* Improve variable naming

* Normalize more variable names

* Fix sub formats breaking click to edit

* Force constrainedTabbing for link ui

* Handle nested formats

* Revert change to hasLink var

* Locate const at top of file

* Improve comment

* Add test for editing text

* Improve var naming

* Correct comments

* Make new prop unstable

* Revert useAnchor API

---------

Co-authored-by: getdave <get_dave@git.wordpress.org>
Co-authored-by: jeryj <jeryj@git.wordpress.org>
Co-authored-by: draganescu <andraganescu@git.wordpress.org>
Co-authored-by: scruffian <scruffian@git.wordpress.org>
Co-authored-by: youknowriad <youknowriad@git.wordpress.org>
Co-authored-by: bacoords <bacoords@git.wordpress.org>
Co-authored-by: joedolson <joedolson@git.wordpress.org>
Co-authored-by: annezazu <annezazu@git.wordpress.org>
Co-authored-by: richtabor <richtabor@git.wordpress.org>
Co-authored-by: fabiankaegy <fabiankaegy@git.wordpress.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backported to WP Core Pull request that has been successfully merged into WP Core [Feature] Link Editing Link components (LinkControl, URLInput) and integrations (RichText link formatting) Needs Accessibility Feedback Need input from accessibility [Type] Bug An existing feature does not function as intended

Projects

No open projects
Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

Link Control: allow double clicking to edit text of link

7 participants