@wordpress/format-library 4.25.1-next.79a6196f.0 → 4.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 4.27.0 (2024-01-24)
6
+
7
+ ## 4.26.0 (2024-01-10)
8
+
5
9
  ## 4.25.0 (2023-12-13)
6
10
 
7
11
  ## 4.24.0 (2023-11-29)
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
 
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
3
  Object.defineProperty(exports, "__esModule", {
5
4
  value: true
6
5
  });
@@ -16,7 +15,6 @@ var _blockEditor = require("@wordpress/block-editor");
16
15
  var _data = require("@wordpress/data");
17
16
  var _utils = require("./utils");
18
17
  var _index = require("./index");
19
- var _useLinkInstanceKey = _interopRequireDefault(require("./use-link-instance-key"));
20
18
  /**
21
19
  * WordPress dependencies
22
20
  */
@@ -70,10 +68,9 @@ function InlineLinkUI({
70
68
  (0, _a11y.speak)((0, _i18n.__)('Link removed.'), 'assertive');
71
69
  }
72
70
  function onChangeLink(nextValue) {
73
- // LinkControl calls `onChange` immediately upon the toggling a setting.
74
- // Before merging the next value with the current link value, check if
75
- // the setting was toggled.
76
- const didToggleSetting = linkValue.opensInNewTab !== nextValue.opensInNewTab && nextValue.url === undefined;
71
+ const hasLink = linkValue?.url;
72
+ const isNewLink = !hasLink;
73
+
77
74
  // Merge the next value with the current link value.
78
75
  nextValue = {
79
76
  ...linkValue,
@@ -137,17 +134,16 @@ function InlineLinkUI({
137
134
  const newValAfter = (0, _richText.replace)(valAfter, richTextText, newValue);
138
135
  newValue = (0, _richText.concat)(valBefore, newValAfter);
139
136
  }
140
- newValue.start = newValue.end;
141
-
142
- // Hides the Link UI.
143
- newValue.activeFormats = [];
144
137
  onChange(newValue);
145
138
  }
146
139
 
147
- // Focus should only be shifted back to the formatted segment when the
148
- // URL is submitted.
149
- if (!didToggleSetting) {
150
- stopAddingLink();
140
+ // Focus should only be returned to the rich text on submit if this link is not
141
+ // being created for the first time. If it is then focus should remain within the
142
+ // Link UI because it should remain open for the user to modify the link they have
143
+ // just created.
144
+ if (!isNewLink) {
145
+ const returnFocusToRichText = true;
146
+ stopAddingLink(returnFocusToRichText);
151
147
  }
152
148
  if (!(0, _utils.isValidHref)(newUrl)) {
153
149
  (0, _a11y.speak)((0, _i18n.__)('Warning: the link has been inserted but may have errors. Please test it.'), 'assertive');
@@ -162,11 +158,14 @@ function InlineLinkUI({
162
158
  settings: _index.link
163
159
  });
164
160
 
165
- // Generate a string based key that is unique to this anchor reference.
166
- // This is used to force re-mount the LinkControl component to avoid
167
- // potential stale state bugs caused by the component not being remounted
168
- // See https://github.com/WordPress/gutenberg/pull/34742.
169
- const forceRemountKey = (0, _useLinkInstanceKey.default)(popoverAnchor);
161
+ // As you change the link by interacting with the Link UI
162
+ // the return value of document.getSelection jumps to the field you're editing,
163
+ // not the highlighted text. Given that useAnchor uses document.getSelection,
164
+ // it will return null, since it can't find the <mark> element within the Link UI.
165
+ // This caches the last truthy value of the selection anchor reference.
166
+ // This ensures the Popover is positioned correctly on initial submission of the link.
167
+ const cachedRect = (0, _blockEditor.useCachedTruthy)(popoverAnchor.getBoundingClientRect());
168
+ popoverAnchor.getBoundingClientRect = () => cachedRect;
170
169
 
171
170
  // Focus should only be moved into the Popover when the Link is being created or edited.
172
171
  // When the Link is in "preview" mode focus should remain on the rich text because at
@@ -200,9 +199,9 @@ function InlineLinkUI({
200
199
  onClose: stopAddingLink,
201
200
  onFocusOutside: () => stopAddingLink(false),
202
201
  placement: "bottom",
202
+ offset: 10,
203
203
  shift: true
204
204
  }, (0, _react.createElement)(_blockEditor.__experimentalLinkControl, {
205
- key: forceRemountKey,
206
205
  value: linkValue,
207
206
  onChange: onChangeLink,
208
207
  onRemove: removeLink,
@@ -212,7 +211,16 @@ function InlineLinkUI({
212
211
  withCreateSuggestion: userCanCreatePages,
213
212
  createSuggestionButtonText: createButtonText,
214
213
  hasTextControl: true,
215
- settings: LINK_SETTINGS
214
+ settings: LINK_SETTINGS,
215
+ showInitialSuggestions: true,
216
+ suggestionsQuery: {
217
+ // always show Pages as initial suggestions
218
+ initialSuggestionsSearchOptions: {
219
+ type: 'post',
220
+ subtype: 'page',
221
+ perPage: 20
222
+ }
223
+ }
216
224
  }));
217
225
  }
218
226
  function getRichTextValueFromSelection(value, isActive) {
@@ -1 +1 @@
1
- {"version":3,"names":["_element","require","_i18n","_a11y","_components","_url","_richText","_blockEditor","_data","_utils","_index","_useLinkInstanceKey","_interopRequireDefault","LINK_SETTINGS","LinkControl","DEFAULT_LINK_SETTINGS","id","title","__","InlineLinkUI","isActive","activeAttributes","addingLink","value","onChange","stopAddingLink","contentRef","richLinkTextValue","getRichTextValueFromSelection","richTextText","text","createPageEntity","userCanCreatePages","useSelect","select","getSettings","blockEditorStore","_settings","__experimentalCreatePageEntity","__experimentalUserCanCreatePages","linkValue","useMemo","url","type","opensInNewTab","target","nofollow","rel","includes","removeLink","newValue","removeFormat","speak","onChangeLink","nextValue","didToggleSetting","undefined","newUrl","prependHTTP","linkFormat","createLinkFormat","String","opensInNewWindow","newText","isCollapsed","toInsert","applyFormat","create","length","insert","boundary","getFormatBoundary","valBefore","valAfter","split","start","newValAfter","replace","concat","end","activeFormats","isValidHref","popoverAnchor","useAnchor","editableContentElement","current","settings","forceRemountKey","useLinkInstanceKey","focusOnMount","useRef","handleCreate","pageTitle","page","status","rendered","link","kind","createButtonText","searchTerm","createInterpolateElement","sprintf","mark","_react","createElement","Popover","anchor","onClose","onFocusOutside","placement","shift","__experimentalLinkControl","key","onRemove","forceIsEditingLink","hasRichPreviews","createSuggestion","withCreateSuggestion","createSuggestionButtonText","hasTextControl","textStart","textEnd","slice","_default","exports","default"],"sources":["@wordpress/format-library/src/link/inline.js"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useMemo, useRef, createInterpolateElement } from '@wordpress/element';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { speak } from '@wordpress/a11y';\nimport { Popover } from '@wordpress/components';\nimport { prependHTTP } from '@wordpress/url';\nimport {\n\tcreate,\n\tinsert,\n\tisCollapsed,\n\tapplyFormat,\n\tuseAnchor,\n\tremoveFormat,\n\tslice,\n\treplace,\n\tsplit,\n\tconcat,\n} from '@wordpress/rich-text';\nimport {\n\t__experimentalLinkControl as LinkControl,\n\tstore as blockEditorStore,\n} from '@wordpress/block-editor';\nimport { useSelect } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport { createLinkFormat, isValidHref, getFormatBoundary } from './utils';\nimport { link as settings } from './index';\nimport useLinkInstanceKey from './use-link-instance-key';\n\nconst LINK_SETTINGS = [\n\t...LinkControl.DEFAULT_LINK_SETTINGS,\n\t{\n\t\tid: 'nofollow',\n\t\ttitle: __( 'Mark as nofollow' ),\n\t},\n];\n\nfunction InlineLinkUI( {\n\tisActive,\n\tactiveAttributes,\n\taddingLink,\n\tvalue,\n\tonChange,\n\tstopAddingLink,\n\tcontentRef,\n} ) {\n\tconst richLinkTextValue = getRichTextValueFromSelection( value, isActive );\n\n\t// Get the text content minus any HTML tags.\n\tconst richTextText = richLinkTextValue.text;\n\n\tconst { createPageEntity, userCanCreatePages } = useSelect( ( select ) => {\n\t\tconst { getSettings } = select( blockEditorStore );\n\t\tconst _settings = getSettings();\n\n\t\treturn {\n\t\t\tcreatePageEntity: _settings.__experimentalCreatePageEntity,\n\t\t\tuserCanCreatePages: _settings.__experimentalUserCanCreatePages,\n\t\t};\n\t}, [] );\n\n\tconst linkValue = useMemo(\n\t\t() => ( {\n\t\t\turl: activeAttributes.url,\n\t\t\ttype: activeAttributes.type,\n\t\t\tid: activeAttributes.id,\n\t\t\topensInNewTab: activeAttributes.target === '_blank',\n\t\t\tnofollow: activeAttributes.rel?.includes( 'nofollow' ),\n\t\t\ttitle: richTextText,\n\t\t} ),\n\t\t[\n\t\t\tactiveAttributes.id,\n\t\t\tactiveAttributes.rel,\n\t\t\tactiveAttributes.target,\n\t\t\tactiveAttributes.type,\n\t\t\tactiveAttributes.url,\n\t\t\trichTextText,\n\t\t]\n\t);\n\n\tfunction removeLink() {\n\t\tconst newValue = removeFormat( value, 'core/link' );\n\t\tonChange( newValue );\n\t\tstopAddingLink();\n\t\tspeak( __( 'Link removed.' ), 'assertive' );\n\t}\n\n\tfunction onChangeLink( nextValue ) {\n\t\t// LinkControl calls `onChange` immediately upon the toggling a setting.\n\t\t// Before merging the next value with the current link value, check if\n\t\t// the setting was toggled.\n\t\tconst didToggleSetting =\n\t\t\tlinkValue.opensInNewTab !== nextValue.opensInNewTab &&\n\t\t\tnextValue.url === undefined;\n\t\t// Merge the next value with the current link value.\n\t\tnextValue = {\n\t\t\t...linkValue,\n\t\t\t...nextValue,\n\t\t};\n\n\t\tconst newUrl = prependHTTP( nextValue.url );\n\t\tconst linkFormat = createLinkFormat( {\n\t\t\turl: newUrl,\n\t\t\ttype: nextValue.type,\n\t\t\tid:\n\t\t\t\tnextValue.id !== undefined && nextValue.id !== null\n\t\t\t\t\t? String( nextValue.id )\n\t\t\t\t\t: undefined,\n\t\t\topensInNewWindow: nextValue.opensInNewTab,\n\t\t\tnofollow: nextValue.nofollow,\n\t\t} );\n\n\t\tconst newText = nextValue.title || newUrl;\n\n\t\tif ( isCollapsed( value ) && ! isActive ) {\n\t\t\t// Scenario: we don't have any actively selected text or formats.\n\t\t\tconst toInsert = applyFormat(\n\t\t\t\tcreate( { text: newText } ),\n\t\t\t\tlinkFormat,\n\t\t\t\t0,\n\t\t\t\tnewText.length\n\t\t\t);\n\t\t\tonChange( insert( value, toInsert ) );\n\t\t} else {\n\t\t\t// Scenario: we have any active text selection or an active format.\n\t\t\tlet newValue;\n\n\t\t\tif ( newText === richTextText ) {\n\t\t\t\t// If we're not updating the text then ignore.\n\t\t\t\tnewValue = applyFormat( value, linkFormat );\n\t\t\t} else {\n\t\t\t\t// Create new RichText value for the new text in order that we\n\t\t\t\t// can apply formats to it.\n\t\t\t\tnewValue = create( { text: newText } );\n\n\t\t\t\t// Apply the new Link format to this new text value.\n\t\t\t\tnewValue = applyFormat(\n\t\t\t\t\tnewValue,\n\t\t\t\t\tlinkFormat,\n\t\t\t\t\t0,\n\t\t\t\t\tnewText.length\n\t\t\t\t);\n\n\t\t\t\t// Get the boundaries of the active link format.\n\t\t\t\tconst boundary = getFormatBoundary( value, {\n\t\t\t\t\ttype: 'core/link',\n\t\t\t\t} );\n\n\t\t\t\t// Split the value at the start of the active link format.\n\t\t\t\t// Passing \"start\" as the 3rd parameter is required to ensure\n\t\t\t\t// the second half of the split value is split at the format's\n\t\t\t\t// start boundary and avoids relying on the value's \"end\" property\n\t\t\t\t// which may not correspond correctly.\n\t\t\t\tconst [ valBefore, valAfter ] = split(\n\t\t\t\t\tvalue,\n\t\t\t\t\tboundary.start,\n\t\t\t\t\tboundary.start\n\t\t\t\t);\n\n\t\t\t\t// Update the original (full) RichTextValue replacing the\n\t\t\t\t// target text with the *new* RichTextValue containing:\n\t\t\t\t// 1. The new text content.\n\t\t\t\t// 2. The new link format.\n\t\t\t\t// As \"replace\" will operate on the first match only, it is\n\t\t\t\t// run only against the second half of the value which was\n\t\t\t\t// split at the active format's boundary. This avoids a bug\n\t\t\t\t// with incorrectly targetted replacements.\n\t\t\t\t// See: https://github.com/WordPress/gutenberg/issues/41771.\n\t\t\t\t// Note original formats will be lost when applying this change.\n\t\t\t\t// That is expected behaviour.\n\t\t\t\t// See: https://github.com/WordPress/gutenberg/pull/33849#issuecomment-936134179.\n\t\t\t\tconst newValAfter = replace( valAfter, richTextText, newValue );\n\n\t\t\t\tnewValue = concat( valBefore, newValAfter );\n\t\t\t}\n\n\t\t\tnewValue.start = newValue.end;\n\n\t\t\t// Hides the Link UI.\n\t\t\tnewValue.activeFormats = [];\n\t\t\tonChange( newValue );\n\t\t}\n\n\t\t// Focus should only be shifted back to the formatted segment when the\n\t\t// URL is submitted.\n\t\tif ( ! didToggleSetting ) {\n\t\t\tstopAddingLink();\n\t\t}\n\n\t\tif ( ! isValidHref( newUrl ) ) {\n\t\t\tspeak(\n\t\t\t\t__(\n\t\t\t\t\t'Warning: the link has been inserted but may have errors. Please test it.'\n\t\t\t\t),\n\t\t\t\t'assertive'\n\t\t\t);\n\t\t} else if ( isActive ) {\n\t\t\tspeak( __( 'Link edited.' ), 'assertive' );\n\t\t} else {\n\t\t\tspeak( __( 'Link inserted.' ), 'assertive' );\n\t\t}\n\t}\n\n\tconst popoverAnchor = useAnchor( {\n\t\teditableContentElement: contentRef.current,\n\t\tsettings,\n\t} );\n\n\t// Generate a string based key that is unique to this anchor reference.\n\t// This is used to force re-mount the LinkControl component to avoid\n\t// potential stale state bugs caused by the component not being remounted\n\t// See https://github.com/WordPress/gutenberg/pull/34742.\n\tconst forceRemountKey = useLinkInstanceKey( popoverAnchor );\n\n\t// Focus should only be moved into the Popover when the Link is being created or edited.\n\t// When the Link is in \"preview\" mode focus should remain on the rich text because at\n\t// this point the Link dialog is informational only and thus the user should be able to\n\t// continue editing the rich text.\n\t// Ref used because the focusOnMount prop shouldn't evolve during render of a Popover\n\t// otherwise it causes a render of the content.\n\tconst focusOnMount = useRef( addingLink ? 'firstElement' : false );\n\n\tasync function handleCreate( pageTitle ) {\n\t\tconst page = await createPageEntity( {\n\t\t\ttitle: pageTitle,\n\t\t\tstatus: 'draft',\n\t\t} );\n\n\t\treturn {\n\t\t\tid: page.id,\n\t\t\ttype: page.type,\n\t\t\ttitle: page.title.rendered,\n\t\t\turl: page.link,\n\t\t\tkind: 'post-type',\n\t\t};\n\t}\n\n\tfunction createButtonText( searchTerm ) {\n\t\treturn createInterpolateElement(\n\t\t\tsprintf(\n\t\t\t\t/* translators: %s: search term. */\n\t\t\t\t__( 'Create page: <mark>%s</mark>' ),\n\t\t\t\tsearchTerm\n\t\t\t),\n\t\t\t{ mark: <mark /> }\n\t\t);\n\t}\n\n\treturn (\n\t\t<Popover\n\t\t\tanchor={ popoverAnchor }\n\t\t\tfocusOnMount={ focusOnMount.current }\n\t\t\tonClose={ stopAddingLink }\n\t\t\tonFocusOutside={ () => stopAddingLink( false ) }\n\t\t\tplacement=\"bottom\"\n\t\t\tshift\n\t\t>\n\t\t\t<LinkControl\n\t\t\t\tkey={ forceRemountKey }\n\t\t\t\tvalue={ linkValue }\n\t\t\t\tonChange={ onChangeLink }\n\t\t\t\tonRemove={ removeLink }\n\t\t\t\tforceIsEditingLink={ addingLink }\n\t\t\t\thasRichPreviews\n\t\t\t\tcreateSuggestion={ createPageEntity && handleCreate }\n\t\t\t\twithCreateSuggestion={ userCanCreatePages }\n\t\t\t\tcreateSuggestionButtonText={ createButtonText }\n\t\t\t\thasTextControl\n\t\t\t\tsettings={ LINK_SETTINGS }\n\t\t\t/>\n\t\t</Popover>\n\t);\n}\n\nfunction getRichTextValueFromSelection( value, isActive ) {\n\t// Default to the selection ranges on the RichTextValue object.\n\tlet textStart = value.start;\n\tlet textEnd = value.end;\n\n\t// If the format is currently active then the rich text value\n\t// should always be taken from the bounds of the active format\n\t// and not the selected text.\n\tif ( isActive ) {\n\t\tconst boundary = getFormatBoundary( value, {\n\t\t\ttype: 'core/link',\n\t\t} );\n\n\t\ttextStart = boundary.start;\n\n\t\t// Text *selection* always extends +1 beyond the edge of the format.\n\t\t// We account for that here.\n\t\ttextEnd = boundary.end + 1;\n\t}\n\n\t// Get a RichTextValue containing the selected text content.\n\treturn slice( value, textStart, textEnd );\n}\n\nexport default InlineLinkUI;\n"],"mappings":"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"}
1
+ {"version":3,"names":["_element","require","_i18n","_a11y","_components","_url","_richText","_blockEditor","_data","_utils","_index","LINK_SETTINGS","LinkControl","DEFAULT_LINK_SETTINGS","id","title","__","InlineLinkUI","isActive","activeAttributes","addingLink","value","onChange","stopAddingLink","contentRef","richLinkTextValue","getRichTextValueFromSelection","richTextText","text","createPageEntity","userCanCreatePages","useSelect","select","getSettings","blockEditorStore","_settings","__experimentalCreatePageEntity","__experimentalUserCanCreatePages","linkValue","useMemo","url","type","opensInNewTab","target","nofollow","rel","includes","removeLink","newValue","removeFormat","speak","onChangeLink","nextValue","hasLink","isNewLink","newUrl","prependHTTP","linkFormat","createLinkFormat","undefined","String","opensInNewWindow","newText","isCollapsed","toInsert","applyFormat","create","length","insert","boundary","getFormatBoundary","valBefore","valAfter","split","start","newValAfter","replace","concat","returnFocusToRichText","isValidHref","popoverAnchor","useAnchor","editableContentElement","current","settings","cachedRect","useCachedTruthy","getBoundingClientRect","focusOnMount","useRef","handleCreate","pageTitle","page","status","rendered","link","kind","createButtonText","searchTerm","createInterpolateElement","sprintf","mark","_react","createElement","Popover","anchor","onClose","onFocusOutside","placement","offset","shift","__experimentalLinkControl","onRemove","forceIsEditingLink","hasRichPreviews","createSuggestion","withCreateSuggestion","createSuggestionButtonText","hasTextControl","showInitialSuggestions","suggestionsQuery","initialSuggestionsSearchOptions","subtype","perPage","textStart","textEnd","end","slice","_default","exports","default"],"sources":["@wordpress/format-library/src/link/inline.js"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useMemo, useRef, createInterpolateElement } from '@wordpress/element';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { speak } from '@wordpress/a11y';\nimport { Popover } from '@wordpress/components';\nimport { prependHTTP } from '@wordpress/url';\nimport {\n\tcreate,\n\tinsert,\n\tisCollapsed,\n\tapplyFormat,\n\tremoveFormat,\n\tslice,\n\treplace,\n\tsplit,\n\tconcat,\n\tuseAnchor,\n} from '@wordpress/rich-text';\nimport {\n\t__experimentalLinkControl as LinkControl,\n\tstore as blockEditorStore,\n\tuseCachedTruthy,\n} from '@wordpress/block-editor';\nimport { useSelect } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport { createLinkFormat, isValidHref, getFormatBoundary } from './utils';\nimport { link as settings } from './index';\n\nconst LINK_SETTINGS = [\n\t...LinkControl.DEFAULT_LINK_SETTINGS,\n\t{\n\t\tid: 'nofollow',\n\t\ttitle: __( 'Mark as nofollow' ),\n\t},\n];\n\nfunction InlineLinkUI( {\n\tisActive,\n\tactiveAttributes,\n\taddingLink,\n\tvalue,\n\tonChange,\n\tstopAddingLink,\n\tcontentRef,\n} ) {\n\tconst richLinkTextValue = getRichTextValueFromSelection( value, isActive );\n\n\t// Get the text content minus any HTML tags.\n\tconst richTextText = richLinkTextValue.text;\n\n\tconst { createPageEntity, userCanCreatePages } = useSelect( ( select ) => {\n\t\tconst { getSettings } = select( blockEditorStore );\n\t\tconst _settings = getSettings();\n\n\t\treturn {\n\t\t\tcreatePageEntity: _settings.__experimentalCreatePageEntity,\n\t\t\tuserCanCreatePages: _settings.__experimentalUserCanCreatePages,\n\t\t};\n\t}, [] );\n\n\tconst linkValue = useMemo(\n\t\t() => ( {\n\t\t\turl: activeAttributes.url,\n\t\t\ttype: activeAttributes.type,\n\t\t\tid: activeAttributes.id,\n\t\t\topensInNewTab: activeAttributes.target === '_blank',\n\t\t\tnofollow: activeAttributes.rel?.includes( 'nofollow' ),\n\t\t\ttitle: richTextText,\n\t\t} ),\n\t\t[\n\t\t\tactiveAttributes.id,\n\t\t\tactiveAttributes.rel,\n\t\t\tactiveAttributes.target,\n\t\t\tactiveAttributes.type,\n\t\t\tactiveAttributes.url,\n\t\t\trichTextText,\n\t\t]\n\t);\n\n\tfunction removeLink() {\n\t\tconst newValue = removeFormat( value, 'core/link' );\n\t\tonChange( newValue );\n\t\tstopAddingLink();\n\t\tspeak( __( 'Link removed.' ), 'assertive' );\n\t}\n\n\tfunction onChangeLink( nextValue ) {\n\t\tconst hasLink = linkValue?.url;\n\t\tconst isNewLink = ! hasLink;\n\n\t\t// Merge the next value with the current link value.\n\t\tnextValue = {\n\t\t\t...linkValue,\n\t\t\t...nextValue,\n\t\t};\n\n\t\tconst newUrl = prependHTTP( nextValue.url );\n\t\tconst linkFormat = createLinkFormat( {\n\t\t\turl: newUrl,\n\t\t\ttype: nextValue.type,\n\t\t\tid:\n\t\t\t\tnextValue.id !== undefined && nextValue.id !== null\n\t\t\t\t\t? String( nextValue.id )\n\t\t\t\t\t: undefined,\n\t\t\topensInNewWindow: nextValue.opensInNewTab,\n\t\t\tnofollow: nextValue.nofollow,\n\t\t} );\n\n\t\tconst newText = nextValue.title || newUrl;\n\n\t\tif ( isCollapsed( value ) && ! isActive ) {\n\t\t\t// Scenario: we don't have any actively selected text or formats.\n\t\t\tconst toInsert = applyFormat(\n\t\t\t\tcreate( { text: newText } ),\n\t\t\t\tlinkFormat,\n\t\t\t\t0,\n\t\t\t\tnewText.length\n\t\t\t);\n\t\t\tonChange( insert( value, toInsert ) );\n\t\t} else {\n\t\t\t// Scenario: we have any active text selection or an active format.\n\t\t\tlet newValue;\n\n\t\t\tif ( newText === richTextText ) {\n\t\t\t\t// If we're not updating the text then ignore.\n\t\t\t\tnewValue = applyFormat( value, linkFormat );\n\t\t\t} else {\n\t\t\t\t// Create new RichText value for the new text in order that we\n\t\t\t\t// can apply formats to it.\n\t\t\t\tnewValue = create( { text: newText } );\n\n\t\t\t\t// Apply the new Link format to this new text value.\n\t\t\t\tnewValue = applyFormat(\n\t\t\t\t\tnewValue,\n\t\t\t\t\tlinkFormat,\n\t\t\t\t\t0,\n\t\t\t\t\tnewText.length\n\t\t\t\t);\n\n\t\t\t\t// Get the boundaries of the active link format.\n\t\t\t\tconst boundary = getFormatBoundary( value, {\n\t\t\t\t\ttype: 'core/link',\n\t\t\t\t} );\n\n\t\t\t\t// Split the value at the start of the active link format.\n\t\t\t\t// Passing \"start\" as the 3rd parameter is required to ensure\n\t\t\t\t// the second half of the split value is split at the format's\n\t\t\t\t// start boundary and avoids relying on the value's \"end\" property\n\t\t\t\t// which may not correspond correctly.\n\t\t\t\tconst [ valBefore, valAfter ] = split(\n\t\t\t\t\tvalue,\n\t\t\t\t\tboundary.start,\n\t\t\t\t\tboundary.start\n\t\t\t\t);\n\n\t\t\t\t// Update the original (full) RichTextValue replacing the\n\t\t\t\t// target text with the *new* RichTextValue containing:\n\t\t\t\t// 1. The new text content.\n\t\t\t\t// 2. The new link format.\n\t\t\t\t// As \"replace\" will operate on the first match only, it is\n\t\t\t\t// run only against the second half of the value which was\n\t\t\t\t// split at the active format's boundary. This avoids a bug\n\t\t\t\t// with incorrectly targetted replacements.\n\t\t\t\t// See: https://github.com/WordPress/gutenberg/issues/41771.\n\t\t\t\t// Note original formats will be lost when applying this change.\n\t\t\t\t// That is expected behaviour.\n\t\t\t\t// See: https://github.com/WordPress/gutenberg/pull/33849#issuecomment-936134179.\n\t\t\t\tconst newValAfter = replace( valAfter, richTextText, newValue );\n\n\t\t\t\tnewValue = concat( valBefore, newValAfter );\n\t\t\t}\n\n\t\t\tonChange( newValue );\n\t\t}\n\n\t\t// Focus should only be returned to the rich text on submit if this link is not\n\t\t// being created for the first time. If it is then focus should remain within the\n\t\t// Link UI because it should remain open for the user to modify the link they have\n\t\t// just created.\n\t\tif ( ! isNewLink ) {\n\t\t\tconst returnFocusToRichText = true;\n\t\t\tstopAddingLink( returnFocusToRichText );\n\t\t}\n\n\t\tif ( ! isValidHref( newUrl ) ) {\n\t\t\tspeak(\n\t\t\t\t__(\n\t\t\t\t\t'Warning: the link has been inserted but may have errors. Please test it.'\n\t\t\t\t),\n\t\t\t\t'assertive'\n\t\t\t);\n\t\t} else if ( isActive ) {\n\t\t\tspeak( __( 'Link edited.' ), 'assertive' );\n\t\t} else {\n\t\t\tspeak( __( 'Link inserted.' ), 'assertive' );\n\t\t}\n\t}\n\n\tconst popoverAnchor = useAnchor( {\n\t\teditableContentElement: contentRef.current,\n\t\tsettings,\n\t} );\n\n\t// As you change the link by interacting with the Link UI\n\t// the return value of document.getSelection jumps to the field you're editing,\n\t// not the highlighted text. Given that useAnchor uses document.getSelection,\n\t// it will return null, since it can't find the <mark> element within the Link UI.\n\t// This caches the last truthy value of the selection anchor reference.\n\t// This ensures the Popover is positioned correctly on initial submission of the link.\n\tconst cachedRect = useCachedTruthy( popoverAnchor.getBoundingClientRect() );\n\tpopoverAnchor.getBoundingClientRect = () => cachedRect;\n\n\t// Focus should only be moved into the Popover when the Link is being created or edited.\n\t// When the Link is in \"preview\" mode focus should remain on the rich text because at\n\t// this point the Link dialog is informational only and thus the user should be able to\n\t// continue editing the rich text.\n\t// Ref used because the focusOnMount prop shouldn't evolve during render of a Popover\n\t// otherwise it causes a render of the content.\n\tconst focusOnMount = useRef( addingLink ? 'firstElement' : false );\n\n\tasync function handleCreate( pageTitle ) {\n\t\tconst page = await createPageEntity( {\n\t\t\ttitle: pageTitle,\n\t\t\tstatus: 'draft',\n\t\t} );\n\n\t\treturn {\n\t\t\tid: page.id,\n\t\t\ttype: page.type,\n\t\t\ttitle: page.title.rendered,\n\t\t\turl: page.link,\n\t\t\tkind: 'post-type',\n\t\t};\n\t}\n\n\tfunction createButtonText( searchTerm ) {\n\t\treturn createInterpolateElement(\n\t\t\tsprintf(\n\t\t\t\t/* translators: %s: search term. */\n\t\t\t\t__( 'Create page: <mark>%s</mark>' ),\n\t\t\t\tsearchTerm\n\t\t\t),\n\t\t\t{ mark: <mark /> }\n\t\t);\n\t}\n\n\treturn (\n\t\t<Popover\n\t\t\tanchor={ popoverAnchor }\n\t\t\tfocusOnMount={ focusOnMount.current }\n\t\t\tonClose={ stopAddingLink }\n\t\t\tonFocusOutside={ () => stopAddingLink( false ) }\n\t\t\tplacement=\"bottom\"\n\t\t\toffset={ 10 }\n\t\t\tshift\n\t\t>\n\t\t\t<LinkControl\n\t\t\t\tvalue={ linkValue }\n\t\t\t\tonChange={ onChangeLink }\n\t\t\t\tonRemove={ removeLink }\n\t\t\t\tforceIsEditingLink={ addingLink }\n\t\t\t\thasRichPreviews\n\t\t\t\tcreateSuggestion={ createPageEntity && handleCreate }\n\t\t\t\twithCreateSuggestion={ userCanCreatePages }\n\t\t\t\tcreateSuggestionButtonText={ createButtonText }\n\t\t\t\thasTextControl\n\t\t\t\tsettings={ LINK_SETTINGS }\n\t\t\t\tshowInitialSuggestions={ true }\n\t\t\t\tsuggestionsQuery={ {\n\t\t\t\t\t// always show Pages as initial suggestions\n\t\t\t\t\tinitialSuggestionsSearchOptions: {\n\t\t\t\t\t\ttype: 'post',\n\t\t\t\t\t\tsubtype: 'page',\n\t\t\t\t\t\tperPage: 20,\n\t\t\t\t\t},\n\t\t\t\t} }\n\t\t\t/>\n\t\t</Popover>\n\t);\n}\n\nfunction getRichTextValueFromSelection( value, isActive ) {\n\t// Default to the selection ranges on the RichTextValue object.\n\tlet textStart = value.start;\n\tlet textEnd = value.end;\n\n\t// If the format is currently active then the rich text value\n\t// should always be taken from the bounds of the active format\n\t// and not the selected text.\n\tif ( isActive ) {\n\t\tconst boundary = getFormatBoundary( value, {\n\t\t\ttype: 'core/link',\n\t\t} );\n\n\t\ttextStart = boundary.start;\n\n\t\t// Text *selection* always extends +1 beyond the edge of the format.\n\t\t// We account for that here.\n\t\ttextEnd = boundary.end + 1;\n\t}\n\n\t// Get a RichTextValue containing the selected text content.\n\treturn slice( value, textStart, textEnd );\n}\n\nexport default InlineLinkUI;\n"],"mappings":"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"}
@@ -7,8 +7,8 @@ import { __, sprintf } from '@wordpress/i18n';
7
7
  import { speak } from '@wordpress/a11y';
8
8
  import { Popover } from '@wordpress/components';
9
9
  import { prependHTTP } from '@wordpress/url';
10
- import { create, insert, isCollapsed, applyFormat, useAnchor, removeFormat, slice, replace, split, concat } from '@wordpress/rich-text';
11
- import { __experimentalLinkControl as LinkControl, store as blockEditorStore } from '@wordpress/block-editor';
10
+ import { create, insert, isCollapsed, applyFormat, removeFormat, slice, replace, split, concat, useAnchor } from '@wordpress/rich-text';
11
+ import { __experimentalLinkControl as LinkControl, store as blockEditorStore, useCachedTruthy } from '@wordpress/block-editor';
12
12
  import { useSelect } from '@wordpress/data';
13
13
 
14
14
  /**
@@ -16,7 +16,6 @@ import { useSelect } from '@wordpress/data';
16
16
  */
17
17
  import { createLinkFormat, isValidHref, getFormatBoundary } from './utils';
18
18
  import { link as settings } from './index';
19
- import useLinkInstanceKey from './use-link-instance-key';
20
19
  const LINK_SETTINGS = [...LinkControl.DEFAULT_LINK_SETTINGS, {
21
20
  id: 'nofollow',
22
21
  title: __('Mark as nofollow')
@@ -62,10 +61,9 @@ function InlineLinkUI({
62
61
  speak(__('Link removed.'), 'assertive');
63
62
  }
64
63
  function onChangeLink(nextValue) {
65
- // LinkControl calls `onChange` immediately upon the toggling a setting.
66
- // Before merging the next value with the current link value, check if
67
- // the setting was toggled.
68
- const didToggleSetting = linkValue.opensInNewTab !== nextValue.opensInNewTab && nextValue.url === undefined;
64
+ const hasLink = linkValue?.url;
65
+ const isNewLink = !hasLink;
66
+
69
67
  // Merge the next value with the current link value.
70
68
  nextValue = {
71
69
  ...linkValue,
@@ -129,17 +127,16 @@ function InlineLinkUI({
129
127
  const newValAfter = replace(valAfter, richTextText, newValue);
130
128
  newValue = concat(valBefore, newValAfter);
131
129
  }
132
- newValue.start = newValue.end;
133
-
134
- // Hides the Link UI.
135
- newValue.activeFormats = [];
136
130
  onChange(newValue);
137
131
  }
138
132
 
139
- // Focus should only be shifted back to the formatted segment when the
140
- // URL is submitted.
141
- if (!didToggleSetting) {
142
- stopAddingLink();
133
+ // Focus should only be returned to the rich text on submit if this link is not
134
+ // being created for the first time. If it is then focus should remain within the
135
+ // Link UI because it should remain open for the user to modify the link they have
136
+ // just created.
137
+ if (!isNewLink) {
138
+ const returnFocusToRichText = true;
139
+ stopAddingLink(returnFocusToRichText);
143
140
  }
144
141
  if (!isValidHref(newUrl)) {
145
142
  speak(__('Warning: the link has been inserted but may have errors. Please test it.'), 'assertive');
@@ -154,11 +151,14 @@ function InlineLinkUI({
154
151
  settings
155
152
  });
156
153
 
157
- // Generate a string based key that is unique to this anchor reference.
158
- // This is used to force re-mount the LinkControl component to avoid
159
- // potential stale state bugs caused by the component not being remounted
160
- // See https://github.com/WordPress/gutenberg/pull/34742.
161
- const forceRemountKey = useLinkInstanceKey(popoverAnchor);
154
+ // As you change the link by interacting with the Link UI
155
+ // the return value of document.getSelection jumps to the field you're editing,
156
+ // not the highlighted text. Given that useAnchor uses document.getSelection,
157
+ // it will return null, since it can't find the <mark> element within the Link UI.
158
+ // This caches the last truthy value of the selection anchor reference.
159
+ // This ensures the Popover is positioned correctly on initial submission of the link.
160
+ const cachedRect = useCachedTruthy(popoverAnchor.getBoundingClientRect());
161
+ popoverAnchor.getBoundingClientRect = () => cachedRect;
162
162
 
163
163
  // Focus should only be moved into the Popover when the Link is being created or edited.
164
164
  // When the Link is in "preview" mode focus should remain on the rich text because at
@@ -192,9 +192,9 @@ function InlineLinkUI({
192
192
  onClose: stopAddingLink,
193
193
  onFocusOutside: () => stopAddingLink(false),
194
194
  placement: "bottom",
195
+ offset: 10,
195
196
  shift: true
196
197
  }, createElement(LinkControl, {
197
- key: forceRemountKey,
198
198
  value: linkValue,
199
199
  onChange: onChangeLink,
200
200
  onRemove: removeLink,
@@ -204,7 +204,16 @@ function InlineLinkUI({
204
204
  withCreateSuggestion: userCanCreatePages,
205
205
  createSuggestionButtonText: createButtonText,
206
206
  hasTextControl: true,
207
- settings: LINK_SETTINGS
207
+ settings: LINK_SETTINGS,
208
+ showInitialSuggestions: true,
209
+ suggestionsQuery: {
210
+ // always show Pages as initial suggestions
211
+ initialSuggestionsSearchOptions: {
212
+ type: 'post',
213
+ subtype: 'page',
214
+ perPage: 20
215
+ }
216
+ }
208
217
  }));
209
218
  }
210
219
  function getRichTextValueFromSelection(value, isActive) {
@@ -1 +1 @@
1
- {"version":3,"names":["useMemo","useRef","createInterpolateElement","__","sprintf","speak","Popover","prependHTTP","create","insert","isCollapsed","applyFormat","useAnchor","removeFormat","slice","replace","split","concat","__experimentalLinkControl","LinkControl","store","blockEditorStore","useSelect","createLinkFormat","isValidHref","getFormatBoundary","link","settings","useLinkInstanceKey","LINK_SETTINGS","DEFAULT_LINK_SETTINGS","id","title","InlineLinkUI","isActive","activeAttributes","addingLink","value","onChange","stopAddingLink","contentRef","richLinkTextValue","getRichTextValueFromSelection","richTextText","text","createPageEntity","userCanCreatePages","select","getSettings","_settings","__experimentalCreatePageEntity","__experimentalUserCanCreatePages","linkValue","url","type","opensInNewTab","target","nofollow","rel","includes","removeLink","newValue","onChangeLink","nextValue","didToggleSetting","undefined","newUrl","linkFormat","String","opensInNewWindow","newText","toInsert","length","boundary","valBefore","valAfter","start","newValAfter","end","activeFormats","popoverAnchor","editableContentElement","current","forceRemountKey","focusOnMount","handleCreate","pageTitle","page","status","rendered","kind","createButtonText","searchTerm","mark","createElement","anchor","onClose","onFocusOutside","placement","shift","key","onRemove","forceIsEditingLink","hasRichPreviews","createSuggestion","withCreateSuggestion","createSuggestionButtonText","hasTextControl","textStart","textEnd"],"sources":["@wordpress/format-library/src/link/inline.js"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useMemo, useRef, createInterpolateElement } from '@wordpress/element';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { speak } from '@wordpress/a11y';\nimport { Popover } from '@wordpress/components';\nimport { prependHTTP } from '@wordpress/url';\nimport {\n\tcreate,\n\tinsert,\n\tisCollapsed,\n\tapplyFormat,\n\tuseAnchor,\n\tremoveFormat,\n\tslice,\n\treplace,\n\tsplit,\n\tconcat,\n} from '@wordpress/rich-text';\nimport {\n\t__experimentalLinkControl as LinkControl,\n\tstore as blockEditorStore,\n} from '@wordpress/block-editor';\nimport { useSelect } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport { createLinkFormat, isValidHref, getFormatBoundary } from './utils';\nimport { link as settings } from './index';\nimport useLinkInstanceKey from './use-link-instance-key';\n\nconst LINK_SETTINGS = [\n\t...LinkControl.DEFAULT_LINK_SETTINGS,\n\t{\n\t\tid: 'nofollow',\n\t\ttitle: __( 'Mark as nofollow' ),\n\t},\n];\n\nfunction InlineLinkUI( {\n\tisActive,\n\tactiveAttributes,\n\taddingLink,\n\tvalue,\n\tonChange,\n\tstopAddingLink,\n\tcontentRef,\n} ) {\n\tconst richLinkTextValue = getRichTextValueFromSelection( value, isActive );\n\n\t// Get the text content minus any HTML tags.\n\tconst richTextText = richLinkTextValue.text;\n\n\tconst { createPageEntity, userCanCreatePages } = useSelect( ( select ) => {\n\t\tconst { getSettings } = select( blockEditorStore );\n\t\tconst _settings = getSettings();\n\n\t\treturn {\n\t\t\tcreatePageEntity: _settings.__experimentalCreatePageEntity,\n\t\t\tuserCanCreatePages: _settings.__experimentalUserCanCreatePages,\n\t\t};\n\t}, [] );\n\n\tconst linkValue = useMemo(\n\t\t() => ( {\n\t\t\turl: activeAttributes.url,\n\t\t\ttype: activeAttributes.type,\n\t\t\tid: activeAttributes.id,\n\t\t\topensInNewTab: activeAttributes.target === '_blank',\n\t\t\tnofollow: activeAttributes.rel?.includes( 'nofollow' ),\n\t\t\ttitle: richTextText,\n\t\t} ),\n\t\t[\n\t\t\tactiveAttributes.id,\n\t\t\tactiveAttributes.rel,\n\t\t\tactiveAttributes.target,\n\t\t\tactiveAttributes.type,\n\t\t\tactiveAttributes.url,\n\t\t\trichTextText,\n\t\t]\n\t);\n\n\tfunction removeLink() {\n\t\tconst newValue = removeFormat( value, 'core/link' );\n\t\tonChange( newValue );\n\t\tstopAddingLink();\n\t\tspeak( __( 'Link removed.' ), 'assertive' );\n\t}\n\n\tfunction onChangeLink( nextValue ) {\n\t\t// LinkControl calls `onChange` immediately upon the toggling a setting.\n\t\t// Before merging the next value with the current link value, check if\n\t\t// the setting was toggled.\n\t\tconst didToggleSetting =\n\t\t\tlinkValue.opensInNewTab !== nextValue.opensInNewTab &&\n\t\t\tnextValue.url === undefined;\n\t\t// Merge the next value with the current link value.\n\t\tnextValue = {\n\t\t\t...linkValue,\n\t\t\t...nextValue,\n\t\t};\n\n\t\tconst newUrl = prependHTTP( nextValue.url );\n\t\tconst linkFormat = createLinkFormat( {\n\t\t\turl: newUrl,\n\t\t\ttype: nextValue.type,\n\t\t\tid:\n\t\t\t\tnextValue.id !== undefined && nextValue.id !== null\n\t\t\t\t\t? String( nextValue.id )\n\t\t\t\t\t: undefined,\n\t\t\topensInNewWindow: nextValue.opensInNewTab,\n\t\t\tnofollow: nextValue.nofollow,\n\t\t} );\n\n\t\tconst newText = nextValue.title || newUrl;\n\n\t\tif ( isCollapsed( value ) && ! isActive ) {\n\t\t\t// Scenario: we don't have any actively selected text or formats.\n\t\t\tconst toInsert = applyFormat(\n\t\t\t\tcreate( { text: newText } ),\n\t\t\t\tlinkFormat,\n\t\t\t\t0,\n\t\t\t\tnewText.length\n\t\t\t);\n\t\t\tonChange( insert( value, toInsert ) );\n\t\t} else {\n\t\t\t// Scenario: we have any active text selection or an active format.\n\t\t\tlet newValue;\n\n\t\t\tif ( newText === richTextText ) {\n\t\t\t\t// If we're not updating the text then ignore.\n\t\t\t\tnewValue = applyFormat( value, linkFormat );\n\t\t\t} else {\n\t\t\t\t// Create new RichText value for the new text in order that we\n\t\t\t\t// can apply formats to it.\n\t\t\t\tnewValue = create( { text: newText } );\n\n\t\t\t\t// Apply the new Link format to this new text value.\n\t\t\t\tnewValue = applyFormat(\n\t\t\t\t\tnewValue,\n\t\t\t\t\tlinkFormat,\n\t\t\t\t\t0,\n\t\t\t\t\tnewText.length\n\t\t\t\t);\n\n\t\t\t\t// Get the boundaries of the active link format.\n\t\t\t\tconst boundary = getFormatBoundary( value, {\n\t\t\t\t\ttype: 'core/link',\n\t\t\t\t} );\n\n\t\t\t\t// Split the value at the start of the active link format.\n\t\t\t\t// Passing \"start\" as the 3rd parameter is required to ensure\n\t\t\t\t// the second half of the split value is split at the format's\n\t\t\t\t// start boundary and avoids relying on the value's \"end\" property\n\t\t\t\t// which may not correspond correctly.\n\t\t\t\tconst [ valBefore, valAfter ] = split(\n\t\t\t\t\tvalue,\n\t\t\t\t\tboundary.start,\n\t\t\t\t\tboundary.start\n\t\t\t\t);\n\n\t\t\t\t// Update the original (full) RichTextValue replacing the\n\t\t\t\t// target text with the *new* RichTextValue containing:\n\t\t\t\t// 1. The new text content.\n\t\t\t\t// 2. The new link format.\n\t\t\t\t// As \"replace\" will operate on the first match only, it is\n\t\t\t\t// run only against the second half of the value which was\n\t\t\t\t// split at the active format's boundary. This avoids a bug\n\t\t\t\t// with incorrectly targetted replacements.\n\t\t\t\t// See: https://github.com/WordPress/gutenberg/issues/41771.\n\t\t\t\t// Note original formats will be lost when applying this change.\n\t\t\t\t// That is expected behaviour.\n\t\t\t\t// See: https://github.com/WordPress/gutenberg/pull/33849#issuecomment-936134179.\n\t\t\t\tconst newValAfter = replace( valAfter, richTextText, newValue );\n\n\t\t\t\tnewValue = concat( valBefore, newValAfter );\n\t\t\t}\n\n\t\t\tnewValue.start = newValue.end;\n\n\t\t\t// Hides the Link UI.\n\t\t\tnewValue.activeFormats = [];\n\t\t\tonChange( newValue );\n\t\t}\n\n\t\t// Focus should only be shifted back to the formatted segment when the\n\t\t// URL is submitted.\n\t\tif ( ! didToggleSetting ) {\n\t\t\tstopAddingLink();\n\t\t}\n\n\t\tif ( ! isValidHref( newUrl ) ) {\n\t\t\tspeak(\n\t\t\t\t__(\n\t\t\t\t\t'Warning: the link has been inserted but may have errors. Please test it.'\n\t\t\t\t),\n\t\t\t\t'assertive'\n\t\t\t);\n\t\t} else if ( isActive ) {\n\t\t\tspeak( __( 'Link edited.' ), 'assertive' );\n\t\t} else {\n\t\t\tspeak( __( 'Link inserted.' ), 'assertive' );\n\t\t}\n\t}\n\n\tconst popoverAnchor = useAnchor( {\n\t\teditableContentElement: contentRef.current,\n\t\tsettings,\n\t} );\n\n\t// Generate a string based key that is unique to this anchor reference.\n\t// This is used to force re-mount the LinkControl component to avoid\n\t// potential stale state bugs caused by the component not being remounted\n\t// See https://github.com/WordPress/gutenberg/pull/34742.\n\tconst forceRemountKey = useLinkInstanceKey( popoverAnchor );\n\n\t// Focus should only be moved into the Popover when the Link is being created or edited.\n\t// When the Link is in \"preview\" mode focus should remain on the rich text because at\n\t// this point the Link dialog is informational only and thus the user should be able to\n\t// continue editing the rich text.\n\t// Ref used because the focusOnMount prop shouldn't evolve during render of a Popover\n\t// otherwise it causes a render of the content.\n\tconst focusOnMount = useRef( addingLink ? 'firstElement' : false );\n\n\tasync function handleCreate( pageTitle ) {\n\t\tconst page = await createPageEntity( {\n\t\t\ttitle: pageTitle,\n\t\t\tstatus: 'draft',\n\t\t} );\n\n\t\treturn {\n\t\t\tid: page.id,\n\t\t\ttype: page.type,\n\t\t\ttitle: page.title.rendered,\n\t\t\turl: page.link,\n\t\t\tkind: 'post-type',\n\t\t};\n\t}\n\n\tfunction createButtonText( searchTerm ) {\n\t\treturn createInterpolateElement(\n\t\t\tsprintf(\n\t\t\t\t/* translators: %s: search term. */\n\t\t\t\t__( 'Create page: <mark>%s</mark>' ),\n\t\t\t\tsearchTerm\n\t\t\t),\n\t\t\t{ mark: <mark /> }\n\t\t);\n\t}\n\n\treturn (\n\t\t<Popover\n\t\t\tanchor={ popoverAnchor }\n\t\t\tfocusOnMount={ focusOnMount.current }\n\t\t\tonClose={ stopAddingLink }\n\t\t\tonFocusOutside={ () => stopAddingLink( false ) }\n\t\t\tplacement=\"bottom\"\n\t\t\tshift\n\t\t>\n\t\t\t<LinkControl\n\t\t\t\tkey={ forceRemountKey }\n\t\t\t\tvalue={ linkValue }\n\t\t\t\tonChange={ onChangeLink }\n\t\t\t\tonRemove={ removeLink }\n\t\t\t\tforceIsEditingLink={ addingLink }\n\t\t\t\thasRichPreviews\n\t\t\t\tcreateSuggestion={ createPageEntity && handleCreate }\n\t\t\t\twithCreateSuggestion={ userCanCreatePages }\n\t\t\t\tcreateSuggestionButtonText={ createButtonText }\n\t\t\t\thasTextControl\n\t\t\t\tsettings={ LINK_SETTINGS }\n\t\t\t/>\n\t\t</Popover>\n\t);\n}\n\nfunction getRichTextValueFromSelection( value, isActive ) {\n\t// Default to the selection ranges on the RichTextValue object.\n\tlet textStart = value.start;\n\tlet textEnd = value.end;\n\n\t// If the format is currently active then the rich text value\n\t// should always be taken from the bounds of the active format\n\t// and not the selected text.\n\tif ( isActive ) {\n\t\tconst boundary = getFormatBoundary( value, {\n\t\t\ttype: 'core/link',\n\t\t} );\n\n\t\ttextStart = boundary.start;\n\n\t\t// Text *selection* always extends +1 beyond the edge of the format.\n\t\t// We account for that here.\n\t\ttextEnd = boundary.end + 1;\n\t}\n\n\t// Get a RichTextValue containing the selected text content.\n\treturn slice( value, textStart, textEnd );\n}\n\nexport default InlineLinkUI;\n"],"mappings":"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"}
1
+ {"version":3,"names":["useMemo","useRef","createInterpolateElement","__","sprintf","speak","Popover","prependHTTP","create","insert","isCollapsed","applyFormat","removeFormat","slice","replace","split","concat","useAnchor","__experimentalLinkControl","LinkControl","store","blockEditorStore","useCachedTruthy","useSelect","createLinkFormat","isValidHref","getFormatBoundary","link","settings","LINK_SETTINGS","DEFAULT_LINK_SETTINGS","id","title","InlineLinkUI","isActive","activeAttributes","addingLink","value","onChange","stopAddingLink","contentRef","richLinkTextValue","getRichTextValueFromSelection","richTextText","text","createPageEntity","userCanCreatePages","select","getSettings","_settings","__experimentalCreatePageEntity","__experimentalUserCanCreatePages","linkValue","url","type","opensInNewTab","target","nofollow","rel","includes","removeLink","newValue","onChangeLink","nextValue","hasLink","isNewLink","newUrl","linkFormat","undefined","String","opensInNewWindow","newText","toInsert","length","boundary","valBefore","valAfter","start","newValAfter","returnFocusToRichText","popoverAnchor","editableContentElement","current","cachedRect","getBoundingClientRect","focusOnMount","handleCreate","pageTitle","page","status","rendered","kind","createButtonText","searchTerm","mark","createElement","anchor","onClose","onFocusOutside","placement","offset","shift","onRemove","forceIsEditingLink","hasRichPreviews","createSuggestion","withCreateSuggestion","createSuggestionButtonText","hasTextControl","showInitialSuggestions","suggestionsQuery","initialSuggestionsSearchOptions","subtype","perPage","textStart","textEnd","end"],"sources":["@wordpress/format-library/src/link/inline.js"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useMemo, useRef, createInterpolateElement } from '@wordpress/element';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { speak } from '@wordpress/a11y';\nimport { Popover } from '@wordpress/components';\nimport { prependHTTP } from '@wordpress/url';\nimport {\n\tcreate,\n\tinsert,\n\tisCollapsed,\n\tapplyFormat,\n\tremoveFormat,\n\tslice,\n\treplace,\n\tsplit,\n\tconcat,\n\tuseAnchor,\n} from '@wordpress/rich-text';\nimport {\n\t__experimentalLinkControl as LinkControl,\n\tstore as blockEditorStore,\n\tuseCachedTruthy,\n} from '@wordpress/block-editor';\nimport { useSelect } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport { createLinkFormat, isValidHref, getFormatBoundary } from './utils';\nimport { link as settings } from './index';\n\nconst LINK_SETTINGS = [\n\t...LinkControl.DEFAULT_LINK_SETTINGS,\n\t{\n\t\tid: 'nofollow',\n\t\ttitle: __( 'Mark as nofollow' ),\n\t},\n];\n\nfunction InlineLinkUI( {\n\tisActive,\n\tactiveAttributes,\n\taddingLink,\n\tvalue,\n\tonChange,\n\tstopAddingLink,\n\tcontentRef,\n} ) {\n\tconst richLinkTextValue = getRichTextValueFromSelection( value, isActive );\n\n\t// Get the text content minus any HTML tags.\n\tconst richTextText = richLinkTextValue.text;\n\n\tconst { createPageEntity, userCanCreatePages } = useSelect( ( select ) => {\n\t\tconst { getSettings } = select( blockEditorStore );\n\t\tconst _settings = getSettings();\n\n\t\treturn {\n\t\t\tcreatePageEntity: _settings.__experimentalCreatePageEntity,\n\t\t\tuserCanCreatePages: _settings.__experimentalUserCanCreatePages,\n\t\t};\n\t}, [] );\n\n\tconst linkValue = useMemo(\n\t\t() => ( {\n\t\t\turl: activeAttributes.url,\n\t\t\ttype: activeAttributes.type,\n\t\t\tid: activeAttributes.id,\n\t\t\topensInNewTab: activeAttributes.target === '_blank',\n\t\t\tnofollow: activeAttributes.rel?.includes( 'nofollow' ),\n\t\t\ttitle: richTextText,\n\t\t} ),\n\t\t[\n\t\t\tactiveAttributes.id,\n\t\t\tactiveAttributes.rel,\n\t\t\tactiveAttributes.target,\n\t\t\tactiveAttributes.type,\n\t\t\tactiveAttributes.url,\n\t\t\trichTextText,\n\t\t]\n\t);\n\n\tfunction removeLink() {\n\t\tconst newValue = removeFormat( value, 'core/link' );\n\t\tonChange( newValue );\n\t\tstopAddingLink();\n\t\tspeak( __( 'Link removed.' ), 'assertive' );\n\t}\n\n\tfunction onChangeLink( nextValue ) {\n\t\tconst hasLink = linkValue?.url;\n\t\tconst isNewLink = ! hasLink;\n\n\t\t// Merge the next value with the current link value.\n\t\tnextValue = {\n\t\t\t...linkValue,\n\t\t\t...nextValue,\n\t\t};\n\n\t\tconst newUrl = prependHTTP( nextValue.url );\n\t\tconst linkFormat = createLinkFormat( {\n\t\t\turl: newUrl,\n\t\t\ttype: nextValue.type,\n\t\t\tid:\n\t\t\t\tnextValue.id !== undefined && nextValue.id !== null\n\t\t\t\t\t? String( nextValue.id )\n\t\t\t\t\t: undefined,\n\t\t\topensInNewWindow: nextValue.opensInNewTab,\n\t\t\tnofollow: nextValue.nofollow,\n\t\t} );\n\n\t\tconst newText = nextValue.title || newUrl;\n\n\t\tif ( isCollapsed( value ) && ! isActive ) {\n\t\t\t// Scenario: we don't have any actively selected text or formats.\n\t\t\tconst toInsert = applyFormat(\n\t\t\t\tcreate( { text: newText } ),\n\t\t\t\tlinkFormat,\n\t\t\t\t0,\n\t\t\t\tnewText.length\n\t\t\t);\n\t\t\tonChange( insert( value, toInsert ) );\n\t\t} else {\n\t\t\t// Scenario: we have any active text selection or an active format.\n\t\t\tlet newValue;\n\n\t\t\tif ( newText === richTextText ) {\n\t\t\t\t// If we're not updating the text then ignore.\n\t\t\t\tnewValue = applyFormat( value, linkFormat );\n\t\t\t} else {\n\t\t\t\t// Create new RichText value for the new text in order that we\n\t\t\t\t// can apply formats to it.\n\t\t\t\tnewValue = create( { text: newText } );\n\n\t\t\t\t// Apply the new Link format to this new text value.\n\t\t\t\tnewValue = applyFormat(\n\t\t\t\t\tnewValue,\n\t\t\t\t\tlinkFormat,\n\t\t\t\t\t0,\n\t\t\t\t\tnewText.length\n\t\t\t\t);\n\n\t\t\t\t// Get the boundaries of the active link format.\n\t\t\t\tconst boundary = getFormatBoundary( value, {\n\t\t\t\t\ttype: 'core/link',\n\t\t\t\t} );\n\n\t\t\t\t// Split the value at the start of the active link format.\n\t\t\t\t// Passing \"start\" as the 3rd parameter is required to ensure\n\t\t\t\t// the second half of the split value is split at the format's\n\t\t\t\t// start boundary and avoids relying on the value's \"end\" property\n\t\t\t\t// which may not correspond correctly.\n\t\t\t\tconst [ valBefore, valAfter ] = split(\n\t\t\t\t\tvalue,\n\t\t\t\t\tboundary.start,\n\t\t\t\t\tboundary.start\n\t\t\t\t);\n\n\t\t\t\t// Update the original (full) RichTextValue replacing the\n\t\t\t\t// target text with the *new* RichTextValue containing:\n\t\t\t\t// 1. The new text content.\n\t\t\t\t// 2. The new link format.\n\t\t\t\t// As \"replace\" will operate on the first match only, it is\n\t\t\t\t// run only against the second half of the value which was\n\t\t\t\t// split at the active format's boundary. This avoids a bug\n\t\t\t\t// with incorrectly targetted replacements.\n\t\t\t\t// See: https://github.com/WordPress/gutenberg/issues/41771.\n\t\t\t\t// Note original formats will be lost when applying this change.\n\t\t\t\t// That is expected behaviour.\n\t\t\t\t// See: https://github.com/WordPress/gutenberg/pull/33849#issuecomment-936134179.\n\t\t\t\tconst newValAfter = replace( valAfter, richTextText, newValue );\n\n\t\t\t\tnewValue = concat( valBefore, newValAfter );\n\t\t\t}\n\n\t\t\tonChange( newValue );\n\t\t}\n\n\t\t// Focus should only be returned to the rich text on submit if this link is not\n\t\t// being created for the first time. If it is then focus should remain within the\n\t\t// Link UI because it should remain open for the user to modify the link they have\n\t\t// just created.\n\t\tif ( ! isNewLink ) {\n\t\t\tconst returnFocusToRichText = true;\n\t\t\tstopAddingLink( returnFocusToRichText );\n\t\t}\n\n\t\tif ( ! isValidHref( newUrl ) ) {\n\t\t\tspeak(\n\t\t\t\t__(\n\t\t\t\t\t'Warning: the link has been inserted but may have errors. Please test it.'\n\t\t\t\t),\n\t\t\t\t'assertive'\n\t\t\t);\n\t\t} else if ( isActive ) {\n\t\t\tspeak( __( 'Link edited.' ), 'assertive' );\n\t\t} else {\n\t\t\tspeak( __( 'Link inserted.' ), 'assertive' );\n\t\t}\n\t}\n\n\tconst popoverAnchor = useAnchor( {\n\t\teditableContentElement: contentRef.current,\n\t\tsettings,\n\t} );\n\n\t// As you change the link by interacting with the Link UI\n\t// the return value of document.getSelection jumps to the field you're editing,\n\t// not the highlighted text. Given that useAnchor uses document.getSelection,\n\t// it will return null, since it can't find the <mark> element within the Link UI.\n\t// This caches the last truthy value of the selection anchor reference.\n\t// This ensures the Popover is positioned correctly on initial submission of the link.\n\tconst cachedRect = useCachedTruthy( popoverAnchor.getBoundingClientRect() );\n\tpopoverAnchor.getBoundingClientRect = () => cachedRect;\n\n\t// Focus should only be moved into the Popover when the Link is being created or edited.\n\t// When the Link is in \"preview\" mode focus should remain on the rich text because at\n\t// this point the Link dialog is informational only and thus the user should be able to\n\t// continue editing the rich text.\n\t// Ref used because the focusOnMount prop shouldn't evolve during render of a Popover\n\t// otherwise it causes a render of the content.\n\tconst focusOnMount = useRef( addingLink ? 'firstElement' : false );\n\n\tasync function handleCreate( pageTitle ) {\n\t\tconst page = await createPageEntity( {\n\t\t\ttitle: pageTitle,\n\t\t\tstatus: 'draft',\n\t\t} );\n\n\t\treturn {\n\t\t\tid: page.id,\n\t\t\ttype: page.type,\n\t\t\ttitle: page.title.rendered,\n\t\t\turl: page.link,\n\t\t\tkind: 'post-type',\n\t\t};\n\t}\n\n\tfunction createButtonText( searchTerm ) {\n\t\treturn createInterpolateElement(\n\t\t\tsprintf(\n\t\t\t\t/* translators: %s: search term. */\n\t\t\t\t__( 'Create page: <mark>%s</mark>' ),\n\t\t\t\tsearchTerm\n\t\t\t),\n\t\t\t{ mark: <mark /> }\n\t\t);\n\t}\n\n\treturn (\n\t\t<Popover\n\t\t\tanchor={ popoverAnchor }\n\t\t\tfocusOnMount={ focusOnMount.current }\n\t\t\tonClose={ stopAddingLink }\n\t\t\tonFocusOutside={ () => stopAddingLink( false ) }\n\t\t\tplacement=\"bottom\"\n\t\t\toffset={ 10 }\n\t\t\tshift\n\t\t>\n\t\t\t<LinkControl\n\t\t\t\tvalue={ linkValue }\n\t\t\t\tonChange={ onChangeLink }\n\t\t\t\tonRemove={ removeLink }\n\t\t\t\tforceIsEditingLink={ addingLink }\n\t\t\t\thasRichPreviews\n\t\t\t\tcreateSuggestion={ createPageEntity && handleCreate }\n\t\t\t\twithCreateSuggestion={ userCanCreatePages }\n\t\t\t\tcreateSuggestionButtonText={ createButtonText }\n\t\t\t\thasTextControl\n\t\t\t\tsettings={ LINK_SETTINGS }\n\t\t\t\tshowInitialSuggestions={ true }\n\t\t\t\tsuggestionsQuery={ {\n\t\t\t\t\t// always show Pages as initial suggestions\n\t\t\t\t\tinitialSuggestionsSearchOptions: {\n\t\t\t\t\t\ttype: 'post',\n\t\t\t\t\t\tsubtype: 'page',\n\t\t\t\t\t\tperPage: 20,\n\t\t\t\t\t},\n\t\t\t\t} }\n\t\t\t/>\n\t\t</Popover>\n\t);\n}\n\nfunction getRichTextValueFromSelection( value, isActive ) {\n\t// Default to the selection ranges on the RichTextValue object.\n\tlet textStart = value.start;\n\tlet textEnd = value.end;\n\n\t// If the format is currently active then the rich text value\n\t// should always be taken from the bounds of the active format\n\t// and not the selected text.\n\tif ( isActive ) {\n\t\tconst boundary = getFormatBoundary( value, {\n\t\t\ttype: 'core/link',\n\t\t} );\n\n\t\ttextStart = boundary.start;\n\n\t\t// Text *selection* always extends +1 beyond the edge of the format.\n\t\t// We account for that here.\n\t\ttextEnd = boundary.end + 1;\n\t}\n\n\t// Get a RichTextValue containing the selected text content.\n\treturn slice( value, textStart, textEnd );\n}\n\nexport default InlineLinkUI;\n"],"mappings":"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"}
@@ -97,7 +97,7 @@
97
97
  --wp-block-synced-color: #7a00df;
98
98
  --wp-block-synced-color--rgb: 122, 0, 223;
99
99
  }
100
- @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
100
+ @media (min-resolution: 192dpi) {
101
101
  :root {
102
102
  --wp-admin-border-width-focus: 1.5px;
103
103
  }
@@ -97,7 +97,7 @@
97
97
  --wp-block-synced-color: #7a00df;
98
98
  --wp-block-synced-color--rgb: 122, 0, 223;
99
99
  }
100
- @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
100
+ @media (min-resolution: 192dpi) {
101
101
  :root {
102
102
  --wp-admin-border-width-focus: 1.5px;
103
103
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/format-library",
3
- "version": "4.25.1-next.79a6196f.0",
3
+ "version": "4.27.0",
4
4
  "description": "Format library for the WordPress editor.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -26,18 +26,18 @@
26
26
  "react-native": "src/index",
27
27
  "dependencies": {
28
28
  "@babel/runtime": "^7.16.0",
29
- "@wordpress/a11y": "^3.48.1-next.79a6196f.0",
30
- "@wordpress/block-editor": "^12.16.1-next.79a6196f.0",
31
- "@wordpress/components": "^25.15.1-next.79a6196f.0",
32
- "@wordpress/compose": "^6.25.1-next.79a6196f.0",
33
- "@wordpress/data": "^9.18.1-next.79a6196f.0",
34
- "@wordpress/element": "^5.25.1-next.79a6196f.0",
35
- "@wordpress/html-entities": "^3.48.1-next.79a6196f.0",
36
- "@wordpress/i18n": "^4.48.1-next.79a6196f.0",
37
- "@wordpress/icons": "^9.39.1-next.79a6196f.0",
38
- "@wordpress/private-apis": "^0.30.1-next.79a6196f.0",
39
- "@wordpress/rich-text": "^6.25.1-next.79a6196f.0",
40
- "@wordpress/url": "^3.49.1-next.79a6196f.0"
29
+ "@wordpress/a11y": "^3.50.0",
30
+ "@wordpress/block-editor": "^12.18.0",
31
+ "@wordpress/components": "^25.16.0",
32
+ "@wordpress/compose": "^6.27.0",
33
+ "@wordpress/data": "^9.20.0",
34
+ "@wordpress/element": "^5.27.0",
35
+ "@wordpress/html-entities": "^3.50.0",
36
+ "@wordpress/i18n": "^4.50.0",
37
+ "@wordpress/icons": "^9.41.0",
38
+ "@wordpress/private-apis": "^0.32.0",
39
+ "@wordpress/rich-text": "^6.27.0",
40
+ "@wordpress/url": "^3.51.0"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "react": "^18.0.0",
@@ -46,5 +46,5 @@
46
46
  "publishConfig": {
47
47
  "access": "public"
48
48
  },
49
- "gitHead": "1e74b942ac0119a22ceaaf5c9594263f3ec516ab"
49
+ "gitHead": "45de2cb4212fed7f2763e95f10300d1ff9d0ec08"
50
50
  }
@@ -11,16 +11,17 @@ import {
11
11
  insert,
12
12
  isCollapsed,
13
13
  applyFormat,
14
- useAnchor,
15
14
  removeFormat,
16
15
  slice,
17
16
  replace,
18
17
  split,
19
18
  concat,
19
+ useAnchor,
20
20
  } from '@wordpress/rich-text';
21
21
  import {
22
22
  __experimentalLinkControl as LinkControl,
23
23
  store as blockEditorStore,
24
+ useCachedTruthy,
24
25
  } from '@wordpress/block-editor';
25
26
  import { useSelect } from '@wordpress/data';
26
27
 
@@ -29,7 +30,6 @@ import { useSelect } from '@wordpress/data';
29
30
  */
30
31
  import { createLinkFormat, isValidHref, getFormatBoundary } from './utils';
31
32
  import { link as settings } from './index';
32
- import useLinkInstanceKey from './use-link-instance-key';
33
33
 
34
34
  const LINK_SETTINGS = [
35
35
  ...LinkControl.DEFAULT_LINK_SETTINGS,
@@ -90,12 +90,9 @@ function InlineLinkUI( {
90
90
  }
91
91
 
92
92
  function onChangeLink( nextValue ) {
93
- // LinkControl calls `onChange` immediately upon the toggling a setting.
94
- // Before merging the next value with the current link value, check if
95
- // the setting was toggled.
96
- const didToggleSetting =
97
- linkValue.opensInNewTab !== nextValue.opensInNewTab &&
98
- nextValue.url === undefined;
93
+ const hasLink = linkValue?.url;
94
+ const isNewLink = ! hasLink;
95
+
99
96
  // Merge the next value with the current link value.
100
97
  nextValue = {
101
98
  ...linkValue,
@@ -178,17 +175,16 @@ function InlineLinkUI( {
178
175
  newValue = concat( valBefore, newValAfter );
179
176
  }
180
177
 
181
- newValue.start = newValue.end;
182
-
183
- // Hides the Link UI.
184
- newValue.activeFormats = [];
185
178
  onChange( newValue );
186
179
  }
187
180
 
188
- // Focus should only be shifted back to the formatted segment when the
189
- // URL is submitted.
190
- if ( ! didToggleSetting ) {
191
- stopAddingLink();
181
+ // Focus should only be returned to the rich text on submit if this link is not
182
+ // being created for the first time. If it is then focus should remain within the
183
+ // Link UI because it should remain open for the user to modify the link they have
184
+ // just created.
185
+ if ( ! isNewLink ) {
186
+ const returnFocusToRichText = true;
187
+ stopAddingLink( returnFocusToRichText );
192
188
  }
193
189
 
194
190
  if ( ! isValidHref( newUrl ) ) {
@@ -210,11 +206,14 @@ function InlineLinkUI( {
210
206
  settings,
211
207
  } );
212
208
 
213
- // Generate a string based key that is unique to this anchor reference.
214
- // This is used to force re-mount the LinkControl component to avoid
215
- // potential stale state bugs caused by the component not being remounted
216
- // See https://github.com/WordPress/gutenberg/pull/34742.
217
- const forceRemountKey = useLinkInstanceKey( popoverAnchor );
209
+ // As you change the link by interacting with the Link UI
210
+ // the return value of document.getSelection jumps to the field you're editing,
211
+ // not the highlighted text. Given that useAnchor uses document.getSelection,
212
+ // it will return null, since it can't find the <mark> element within the Link UI.
213
+ // This caches the last truthy value of the selection anchor reference.
214
+ // This ensures the Popover is positioned correctly on initial submission of the link.
215
+ const cachedRect = useCachedTruthy( popoverAnchor.getBoundingClientRect() );
216
+ popoverAnchor.getBoundingClientRect = () => cachedRect;
218
217
 
219
218
  // Focus should only be moved into the Popover when the Link is being created or edited.
220
219
  // When the Link is in "preview" mode focus should remain on the rich text because at
@@ -257,10 +256,10 @@ function InlineLinkUI( {
257
256
  onClose={ stopAddingLink }
258
257
  onFocusOutside={ () => stopAddingLink( false ) }
259
258
  placement="bottom"
259
+ offset={ 10 }
260
260
  shift
261
261
  >
262
262
  <LinkControl
263
- key={ forceRemountKey }
264
263
  value={ linkValue }
265
264
  onChange={ onChangeLink }
266
265
  onRemove={ removeLink }
@@ -271,6 +270,15 @@ function InlineLinkUI( {
271
270
  createSuggestionButtonText={ createButtonText }
272
271
  hasTextControl
273
272
  settings={ LINK_SETTINGS }
273
+ showInitialSuggestions={ true }
274
+ suggestionsQuery={ {
275
+ // always show Pages as initial suggestions
276
+ initialSuggestionsSearchOptions: {
277
+ type: 'post',
278
+ subtype: 'page',
279
+ perPage: 20,
280
+ },
281
+ } }
274
282
  />
275
283
  </Popover>
276
284
  );