@wordpress/format-library 4.2.0 → 4.3.1

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,8 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 4.3.0 (2023-02-01)
6
+
5
7
  ## 4.2.0 (2023-01-11)
6
8
 
7
9
  ## 4.1.0 (2023-01-02)
@@ -139,15 +139,31 @@ function InlineLinkUI(_ref) {
139
139
  text: newText
140
140
  }); // Apply the new Link format to this new text value.
141
141
 
142
- newValue = (0, _richText.applyFormat)(newValue, linkFormat, 0, newText.length); // Update the original (full) RichTextValue replacing the
142
+ newValue = (0, _richText.applyFormat)(newValue, linkFormat, 0, newText.length); // Get the boundaries of the active link format.
143
+
144
+ const boundary = (0, _utils.getFormatBoundary)(value, {
145
+ type: 'core/link'
146
+ }); // Split the value at the start of the active link format.
147
+ // Passing "start" as the 3rd parameter is required to ensure
148
+ // the second half of the split value is split at the format's
149
+ // start boundary and avoids relying on the value's "end" property
150
+ // which may not correspond correctly.
151
+
152
+ const [valBefore, valAfter] = (0, _richText.split)(value, boundary.start, boundary.start); // Update the original (full) RichTextValue replacing the
143
153
  // target text with the *new* RichTextValue containing:
144
154
  // 1. The new text content.
145
155
  // 2. The new link format.
156
+ // As "replace" will operate on the first match only, it is
157
+ // run only against the second half of the value which was
158
+ // split at the active format's boundary. This avoids a bug
159
+ // with incorrectly targetted replacements.
160
+ // See: https://github.com/WordPress/gutenberg/issues/41771.
146
161
  // Note original formats will be lost when applying this change.
147
162
  // That is expected behaviour.
148
163
  // See: https://github.com/WordPress/gutenberg/pull/33849#issuecomment-936134179.
149
164
 
150
- newValue = (0, _richText.replace)(value, richTextText, newValue);
165
+ const newValAfter = (0, _richText.replace)(valAfter, richTextText, newValue);
166
+ newValue = (0, _richText.concat)(valBefore, newValAfter);
151
167
  }
152
168
 
153
169
  newValue.start = newValue.end;
@@ -1 +1 @@
1
- {"version":3,"sources":["@wordpress/format-library/src/link/inline.js"],"names":["InlineLinkUI","isActive","activeAttributes","addingLink","value","onChange","speak","stopAddingLink","contentRef","richLinkTextValue","getRichTextValueFromSelection","richTextText","text","nextLinkValue","setNextLinkValue","createPageEntity","userCanCreatePages","select","getSettings","blockEditorStore","_settings","__experimentalCreatePageEntity","__experimentalUserCanCreatePages","linkValue","url","type","id","opensInNewTab","target","title","removeLink","newValue","onChangeLink","nextValue","didToggleSetting","didToggleSettingForNewLink","undefined","newUrl","linkFormat","String","opensInNewWindow","newText","toInsert","length","start","end","activeFormats","popoverAnchor","editableContentElement","current","settings","forceRemountKey","focusOnMount","handleCreate","pageTitle","page","status","rendered","link","kind","createButtonText","searchTerm","mark","textStart","textEnd","boundary"],"mappings":"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","sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useState, useRef, createInterpolateElement } from '@wordpress/element';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { withSpokenMessages, 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} 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\nfunction InlineLinkUI( {\n\tisActive,\n\tactiveAttributes,\n\taddingLink,\n\tvalue,\n\tonChange,\n\tspeak,\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\t/**\n\t * Pending settings to be applied to the next link. When inserting a new\n\t * link, toggle values cannot be applied immediately, because there is not\n\t * yet a link for them to apply to. Thus, they are maintained in a state\n\t * value until the time that the link can be inserted or edited.\n\t *\n\t * @type {[Object|undefined,Function]}\n\t */\n\tconst [ nextLinkValue, setNextLinkValue ] = useState();\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 = {\n\t\turl: activeAttributes.url,\n\t\ttype: activeAttributes.type,\n\t\tid: activeAttributes.id,\n\t\topensInNewTab: activeAttributes.target === '_blank',\n\t\ttitle: richTextText,\n\t\t...nextLinkValue,\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// Merge with values from state, both for the purpose of assigning the\n\t\t// next state value, and for use in constructing the new link format if\n\t\t// the link is ready to be applied.\n\t\tnextValue = {\n\t\t\t...nextLinkValue,\n\t\t\t...nextValue,\n\t\t};\n\n\t\t// LinkControl calls `onChange` immediately upon the toggling a setting.\n\t\tconst didToggleSetting =\n\t\t\tlinkValue.opensInNewTab !== nextValue.opensInNewTab &&\n\t\t\tlinkValue.url === nextValue.url;\n\n\t\t// If change handler was called as a result of a settings change during\n\t\t// link insertion, it must be held in state until the link is ready to\n\t\t// be applied.\n\t\tconst didToggleSettingForNewLink =\n\t\t\tdidToggleSetting && nextValue.url === undefined;\n\n\t\t// If link will be assigned, the state value can be considered flushed.\n\t\t// Otherwise, persist the pending changes.\n\t\tsetNextLinkValue( didToggleSettingForNewLink ? nextValue : undefined );\n\n\t\tif ( didToggleSettingForNewLink ) {\n\t\t\treturn;\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} );\n\n\t\tconst newText = nextValue.title || newUrl;\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// 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// 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\tnewValue = replace( value, richTextText, newValue );\n\t\t\t}\n\n\t\t\tnewValue.start = newValue.end;\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\tvalue,\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// 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\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/>\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 withSpokenMessages( InlineLinkUI );\n"]}
1
+ {"version":3,"sources":["@wordpress/format-library/src/link/inline.js"],"names":["InlineLinkUI","isActive","activeAttributes","addingLink","value","onChange","speak","stopAddingLink","contentRef","richLinkTextValue","getRichTextValueFromSelection","richTextText","text","nextLinkValue","setNextLinkValue","createPageEntity","userCanCreatePages","select","getSettings","blockEditorStore","_settings","__experimentalCreatePageEntity","__experimentalUserCanCreatePages","linkValue","url","type","id","opensInNewTab","target","title","removeLink","newValue","onChangeLink","nextValue","didToggleSetting","didToggleSettingForNewLink","undefined","newUrl","linkFormat","String","opensInNewWindow","newText","toInsert","length","boundary","valBefore","valAfter","start","newValAfter","end","activeFormats","popoverAnchor","editableContentElement","current","settings","forceRemountKey","focusOnMount","handleCreate","pageTitle","page","status","rendered","link","kind","createButtonText","searchTerm","mark","textStart","textEnd"],"mappings":"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","sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useState, useRef, createInterpolateElement } from '@wordpress/element';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { withSpokenMessages, 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\nfunction InlineLinkUI( {\n\tisActive,\n\tactiveAttributes,\n\taddingLink,\n\tvalue,\n\tonChange,\n\tspeak,\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\t/**\n\t * Pending settings to be applied to the next link. When inserting a new\n\t * link, toggle values cannot be applied immediately, because there is not\n\t * yet a link for them to apply to. Thus, they are maintained in a state\n\t * value until the time that the link can be inserted or edited.\n\t *\n\t * @type {[Object|undefined,Function]}\n\t */\n\tconst [ nextLinkValue, setNextLinkValue ] = useState();\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 = {\n\t\turl: activeAttributes.url,\n\t\ttype: activeAttributes.type,\n\t\tid: activeAttributes.id,\n\t\topensInNewTab: activeAttributes.target === '_blank',\n\t\ttitle: richTextText,\n\t\t...nextLinkValue,\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// Merge with values from state, both for the purpose of assigning the\n\t\t// next state value, and for use in constructing the new link format if\n\t\t// the link is ready to be applied.\n\t\tnextValue = {\n\t\t\t...nextLinkValue,\n\t\t\t...nextValue,\n\t\t};\n\n\t\t// LinkControl calls `onChange` immediately upon the toggling a setting.\n\t\tconst didToggleSetting =\n\t\t\tlinkValue.opensInNewTab !== nextValue.opensInNewTab &&\n\t\t\tlinkValue.url === nextValue.url;\n\n\t\t// If change handler was called as a result of a settings change during\n\t\t// link insertion, it must be held in state until the link is ready to\n\t\t// be applied.\n\t\tconst didToggleSettingForNewLink =\n\t\t\tdidToggleSetting && nextValue.url === undefined;\n\n\t\t// If link will be assigned, the state value can be considered flushed.\n\t\t// Otherwise, persist the pending changes.\n\t\tsetNextLinkValue( didToggleSettingForNewLink ? nextValue : undefined );\n\n\t\tif ( didToggleSettingForNewLink ) {\n\t\t\treturn;\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} );\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\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\tvalue,\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// 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\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/>\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 withSpokenMessages( InlineLinkUI );\n"]}
@@ -17,7 +17,7 @@ function getKey(_id) {
17
17
  * Builds a unique link control key for the given object reference.
18
18
  *
19
19
  * @param {Object} instance an unique object reference specific to this link control instance.
20
- * @return {string} the unique key to use for this link control.
20
+ * @return {string | undefined} the unique key to use for this link control.
21
21
  */
22
22
 
23
23
 
@@ -1 +1 @@
1
- {"version":3,"sources":["@wordpress/format-library/src/link/use-link-instance-key.js"],"names":["weakMap","WeakMap","id","prefix","getKey","_id","useLinkInstanceKey","instance","has","get","set"],"mappings":";;;;;;AAAA;AACA,MAAMA,OAAO,GAAG,IAAIC,OAAJ,EAAhB,C,CAEA;;AACA,IAAIC,EAAE,GAAG,CAAC,CAAV;AAEA,MAAMC,MAAM,GAAG,uBAAf;;AAEA,SAASC,MAAT,CAAiBC,GAAjB,EAAuB;AACtB,SAAQ,GAAGF,MAAQ,IAAIE,GAAK,EAA5B;AACA;AAED;AACA;AACA;AACA;AACA;AACA;;;AACA,SAASC,kBAAT,CAA6BC,QAA7B,EAAwC;AACvC,MAAK,CAAEA,QAAP,EAAkB;AACjB;AACA;;AACD,MAAKP,OAAO,CAACQ,GAAR,CAAaD,QAAb,CAAL,EAA+B;AAC9B,WAAOH,MAAM,CAAEJ,OAAO,CAACS,GAAR,CAAaF,QAAb,CAAF,CAAb;AACA;;AAEDL,EAAAA,EAAE,IAAI,CAAN;AAEAF,EAAAA,OAAO,CAACU,GAAR,CAAaH,QAAb,EAAuBL,EAAvB;AAEA,SAAOE,MAAM,CAAEF,EAAF,CAAb;AACA;;eAEcI,kB","sourcesContent":["// Weakly referenced map allows unused ids to be garbage collected.\nconst weakMap = new WeakMap();\n\n// Incrementing zero-based ID value.\nlet id = -1;\n\nconst prefix = 'link-control-instance';\n\nfunction getKey( _id ) {\n\treturn `${ prefix }-${ _id }`;\n}\n\n/**\n * Builds a unique link control key for the given object reference.\n *\n * @param {Object} instance an unique object reference specific to this link control instance.\n * @return {string} the unique key to use for this link control.\n */\nfunction useLinkInstanceKey( instance ) {\n\tif ( ! instance ) {\n\t\treturn;\n\t}\n\tif ( weakMap.has( instance ) ) {\n\t\treturn getKey( weakMap.get( instance ) );\n\t}\n\n\tid += 1;\n\n\tweakMap.set( instance, id );\n\n\treturn getKey( id );\n}\n\nexport default useLinkInstanceKey;\n"]}
1
+ {"version":3,"sources":["@wordpress/format-library/src/link/use-link-instance-key.js"],"names":["weakMap","WeakMap","id","prefix","getKey","_id","useLinkInstanceKey","instance","has","get","set"],"mappings":";;;;;;AAAA;AACA,MAAMA,OAAO,GAAG,IAAIC,OAAJ,EAAhB,C,CAEA;;AACA,IAAIC,EAAE,GAAG,CAAC,CAAV;AAEA,MAAMC,MAAM,GAAG,uBAAf;;AAEA,SAASC,MAAT,CAAiBC,GAAjB,EAAuB;AACtB,SAAQ,GAAGF,MAAQ,IAAIE,GAAK,EAA5B;AACA;AAED;AACA;AACA;AACA;AACA;AACA;;;AACA,SAASC,kBAAT,CAA6BC,QAA7B,EAAwC;AACvC,MAAK,CAAEA,QAAP,EAAkB;AACjB;AACA;;AACD,MAAKP,OAAO,CAACQ,GAAR,CAAaD,QAAb,CAAL,EAA+B;AAC9B,WAAOH,MAAM,CAAEJ,OAAO,CAACS,GAAR,CAAaF,QAAb,CAAF,CAAb;AACA;;AAEDL,EAAAA,EAAE,IAAI,CAAN;AAEAF,EAAAA,OAAO,CAACU,GAAR,CAAaH,QAAb,EAAuBL,EAAvB;AAEA,SAAOE,MAAM,CAAEF,EAAF,CAAb;AACA;;eAEcI,kB","sourcesContent":["// Weakly referenced map allows unused ids to be garbage collected.\nconst weakMap = new WeakMap();\n\n// Incrementing zero-based ID value.\nlet id = -1;\n\nconst prefix = 'link-control-instance';\n\nfunction getKey( _id ) {\n\treturn `${ prefix }-${ _id }`;\n}\n\n/**\n * Builds a unique link control key for the given object reference.\n *\n * @param {Object} instance an unique object reference specific to this link control instance.\n * @return {string | undefined} the unique key to use for this link control.\n */\nfunction useLinkInstanceKey( instance ) {\n\tif ( ! instance ) {\n\t\treturn;\n\t}\n\tif ( weakMap.has( instance ) ) {\n\t\treturn getKey( weakMap.get( instance ) );\n\t}\n\n\tid += 1;\n\n\tweakMap.set( instance, id );\n\n\treturn getKey( id );\n}\n\nexport default useLinkInstanceKey;\n"]}
@@ -7,7 +7,7 @@ import { useState, useRef, createInterpolateElement } from '@wordpress/element';
7
7
  import { __, sprintf } from '@wordpress/i18n';
8
8
  import { withSpokenMessages, Popover } from '@wordpress/components';
9
9
  import { prependHTTP } from '@wordpress/url';
10
- import { create, insert, isCollapsed, applyFormat, useAnchor, removeFormat, slice, replace } from '@wordpress/rich-text';
10
+ import { create, insert, isCollapsed, applyFormat, useAnchor, removeFormat, slice, replace, split, concat } from '@wordpress/rich-text';
11
11
  import { __experimentalLinkControl as LinkControl, store as blockEditorStore } from '@wordpress/block-editor';
12
12
  import { useSelect } from '@wordpress/data';
13
13
  /**
@@ -123,15 +123,31 @@ function InlineLinkUI(_ref) {
123
123
  text: newText
124
124
  }); // Apply the new Link format to this new text value.
125
125
 
126
- newValue = applyFormat(newValue, linkFormat, 0, newText.length); // Update the original (full) RichTextValue replacing the
126
+ newValue = applyFormat(newValue, linkFormat, 0, newText.length); // Get the boundaries of the active link format.
127
+
128
+ const boundary = getFormatBoundary(value, {
129
+ type: 'core/link'
130
+ }); // Split the value at the start of the active link format.
131
+ // Passing "start" as the 3rd parameter is required to ensure
132
+ // the second half of the split value is split at the format's
133
+ // start boundary and avoids relying on the value's "end" property
134
+ // which may not correspond correctly.
135
+
136
+ const [valBefore, valAfter] = split(value, boundary.start, boundary.start); // Update the original (full) RichTextValue replacing the
127
137
  // target text with the *new* RichTextValue containing:
128
138
  // 1. The new text content.
129
139
  // 2. The new link format.
140
+ // As "replace" will operate on the first match only, it is
141
+ // run only against the second half of the value which was
142
+ // split at the active format's boundary. This avoids a bug
143
+ // with incorrectly targetted replacements.
144
+ // See: https://github.com/WordPress/gutenberg/issues/41771.
130
145
  // Note original formats will be lost when applying this change.
131
146
  // That is expected behaviour.
132
147
  // See: https://github.com/WordPress/gutenberg/pull/33849#issuecomment-936134179.
133
148
 
134
- newValue = replace(value, richTextText, newValue);
149
+ const newValAfter = replace(valAfter, richTextText, newValue);
150
+ newValue = concat(valBefore, newValAfter);
135
151
  }
136
152
 
137
153
  newValue.start = newValue.end;
@@ -1 +1 @@
1
- {"version":3,"sources":["@wordpress/format-library/src/link/inline.js"],"names":["useState","useRef","createInterpolateElement","__","sprintf","withSpokenMessages","Popover","prependHTTP","create","insert","isCollapsed","applyFormat","useAnchor","removeFormat","slice","replace","__experimentalLinkControl","LinkControl","store","blockEditorStore","useSelect","createLinkFormat","isValidHref","getFormatBoundary","link","settings","useLinkInstanceKey","InlineLinkUI","isActive","activeAttributes","addingLink","value","onChange","speak","stopAddingLink","contentRef","richLinkTextValue","getRichTextValueFromSelection","richTextText","text","nextLinkValue","setNextLinkValue","createPageEntity","userCanCreatePages","select","getSettings","_settings","__experimentalCreatePageEntity","__experimentalUserCanCreatePages","linkValue","url","type","id","opensInNewTab","target","title","removeLink","newValue","onChangeLink","nextValue","didToggleSetting","didToggleSettingForNewLink","undefined","newUrl","linkFormat","String","opensInNewWindow","newText","toInsert","length","start","end","activeFormats","popoverAnchor","editableContentElement","current","forceRemountKey","focusOnMount","handleCreate","pageTitle","page","status","rendered","kind","createButtonText","searchTerm","mark","textStart","textEnd","boundary"],"mappings":"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","sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useState, useRef, createInterpolateElement } from '@wordpress/element';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { withSpokenMessages, 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} 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\nfunction InlineLinkUI( {\n\tisActive,\n\tactiveAttributes,\n\taddingLink,\n\tvalue,\n\tonChange,\n\tspeak,\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\t/**\n\t * Pending settings to be applied to the next link. When inserting a new\n\t * link, toggle values cannot be applied immediately, because there is not\n\t * yet a link for them to apply to. Thus, they are maintained in a state\n\t * value until the time that the link can be inserted or edited.\n\t *\n\t * @type {[Object|undefined,Function]}\n\t */\n\tconst [ nextLinkValue, setNextLinkValue ] = useState();\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 = {\n\t\turl: activeAttributes.url,\n\t\ttype: activeAttributes.type,\n\t\tid: activeAttributes.id,\n\t\topensInNewTab: activeAttributes.target === '_blank',\n\t\ttitle: richTextText,\n\t\t...nextLinkValue,\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// Merge with values from state, both for the purpose of assigning the\n\t\t// next state value, and for use in constructing the new link format if\n\t\t// the link is ready to be applied.\n\t\tnextValue = {\n\t\t\t...nextLinkValue,\n\t\t\t...nextValue,\n\t\t};\n\n\t\t// LinkControl calls `onChange` immediately upon the toggling a setting.\n\t\tconst didToggleSetting =\n\t\t\tlinkValue.opensInNewTab !== nextValue.opensInNewTab &&\n\t\t\tlinkValue.url === nextValue.url;\n\n\t\t// If change handler was called as a result of a settings change during\n\t\t// link insertion, it must be held in state until the link is ready to\n\t\t// be applied.\n\t\tconst didToggleSettingForNewLink =\n\t\t\tdidToggleSetting && nextValue.url === undefined;\n\n\t\t// If link will be assigned, the state value can be considered flushed.\n\t\t// Otherwise, persist the pending changes.\n\t\tsetNextLinkValue( didToggleSettingForNewLink ? nextValue : undefined );\n\n\t\tif ( didToggleSettingForNewLink ) {\n\t\t\treturn;\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} );\n\n\t\tconst newText = nextValue.title || newUrl;\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// 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// 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\tnewValue = replace( value, richTextText, newValue );\n\t\t\t}\n\n\t\t\tnewValue.start = newValue.end;\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\tvalue,\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// 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\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/>\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 withSpokenMessages( InlineLinkUI );\n"]}
1
+ {"version":3,"sources":["@wordpress/format-library/src/link/inline.js"],"names":["useState","useRef","createInterpolateElement","__","sprintf","withSpokenMessages","Popover","prependHTTP","create","insert","isCollapsed","applyFormat","useAnchor","removeFormat","slice","replace","split","concat","__experimentalLinkControl","LinkControl","store","blockEditorStore","useSelect","createLinkFormat","isValidHref","getFormatBoundary","link","settings","useLinkInstanceKey","InlineLinkUI","isActive","activeAttributes","addingLink","value","onChange","speak","stopAddingLink","contentRef","richLinkTextValue","getRichTextValueFromSelection","richTextText","text","nextLinkValue","setNextLinkValue","createPageEntity","userCanCreatePages","select","getSettings","_settings","__experimentalCreatePageEntity","__experimentalUserCanCreatePages","linkValue","url","type","id","opensInNewTab","target","title","removeLink","newValue","onChangeLink","nextValue","didToggleSetting","didToggleSettingForNewLink","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","textStart","textEnd"],"mappings":"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","sourcesContent":["/**\n * WordPress dependencies\n */\nimport { useState, useRef, createInterpolateElement } from '@wordpress/element';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { withSpokenMessages, 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\nfunction InlineLinkUI( {\n\tisActive,\n\tactiveAttributes,\n\taddingLink,\n\tvalue,\n\tonChange,\n\tspeak,\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\t/**\n\t * Pending settings to be applied to the next link. When inserting a new\n\t * link, toggle values cannot be applied immediately, because there is not\n\t * yet a link for them to apply to. Thus, they are maintained in a state\n\t * value until the time that the link can be inserted or edited.\n\t *\n\t * @type {[Object|undefined,Function]}\n\t */\n\tconst [ nextLinkValue, setNextLinkValue ] = useState();\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 = {\n\t\turl: activeAttributes.url,\n\t\ttype: activeAttributes.type,\n\t\tid: activeAttributes.id,\n\t\topensInNewTab: activeAttributes.target === '_blank',\n\t\ttitle: richTextText,\n\t\t...nextLinkValue,\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// Merge with values from state, both for the purpose of assigning the\n\t\t// next state value, and for use in constructing the new link format if\n\t\t// the link is ready to be applied.\n\t\tnextValue = {\n\t\t\t...nextLinkValue,\n\t\t\t...nextValue,\n\t\t};\n\n\t\t// LinkControl calls `onChange` immediately upon the toggling a setting.\n\t\tconst didToggleSetting =\n\t\t\tlinkValue.opensInNewTab !== nextValue.opensInNewTab &&\n\t\t\tlinkValue.url === nextValue.url;\n\n\t\t// If change handler was called as a result of a settings change during\n\t\t// link insertion, it must be held in state until the link is ready to\n\t\t// be applied.\n\t\tconst didToggleSettingForNewLink =\n\t\t\tdidToggleSetting && nextValue.url === undefined;\n\n\t\t// If link will be assigned, the state value can be considered flushed.\n\t\t// Otherwise, persist the pending changes.\n\t\tsetNextLinkValue( didToggleSettingForNewLink ? nextValue : undefined );\n\n\t\tif ( didToggleSettingForNewLink ) {\n\t\t\treturn;\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} );\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\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\tvalue,\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// 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\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/>\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 withSpokenMessages( InlineLinkUI );\n"]}
@@ -11,7 +11,7 @@ function getKey(_id) {
11
11
  * Builds a unique link control key for the given object reference.
12
12
  *
13
13
  * @param {Object} instance an unique object reference specific to this link control instance.
14
- * @return {string} the unique key to use for this link control.
14
+ * @return {string | undefined} the unique key to use for this link control.
15
15
  */
16
16
 
17
17
 
@@ -1 +1 @@
1
- {"version":3,"sources":["@wordpress/format-library/src/link/use-link-instance-key.js"],"names":["weakMap","WeakMap","id","prefix","getKey","_id","useLinkInstanceKey","instance","has","get","set"],"mappings":"AAAA;AACA,MAAMA,OAAO,GAAG,IAAIC,OAAJ,EAAhB,C,CAEA;;AACA,IAAIC,EAAE,GAAG,CAAC,CAAV;AAEA,MAAMC,MAAM,GAAG,uBAAf;;AAEA,SAASC,MAAT,CAAiBC,GAAjB,EAAuB;AACtB,SAAQ,GAAGF,MAAQ,IAAIE,GAAK,EAA5B;AACA;AAED;AACA;AACA;AACA;AACA;AACA;;;AACA,SAASC,kBAAT,CAA6BC,QAA7B,EAAwC;AACvC,MAAK,CAAEA,QAAP,EAAkB;AACjB;AACA;;AACD,MAAKP,OAAO,CAACQ,GAAR,CAAaD,QAAb,CAAL,EAA+B;AAC9B,WAAOH,MAAM,CAAEJ,OAAO,CAACS,GAAR,CAAaF,QAAb,CAAF,CAAb;AACA;;AAEDL,EAAAA,EAAE,IAAI,CAAN;AAEAF,EAAAA,OAAO,CAACU,GAAR,CAAaH,QAAb,EAAuBL,EAAvB;AAEA,SAAOE,MAAM,CAAEF,EAAF,CAAb;AACA;;AAED,eAAeI,kBAAf","sourcesContent":["// Weakly referenced map allows unused ids to be garbage collected.\nconst weakMap = new WeakMap();\n\n// Incrementing zero-based ID value.\nlet id = -1;\n\nconst prefix = 'link-control-instance';\n\nfunction getKey( _id ) {\n\treturn `${ prefix }-${ _id }`;\n}\n\n/**\n * Builds a unique link control key for the given object reference.\n *\n * @param {Object} instance an unique object reference specific to this link control instance.\n * @return {string} the unique key to use for this link control.\n */\nfunction useLinkInstanceKey( instance ) {\n\tif ( ! instance ) {\n\t\treturn;\n\t}\n\tif ( weakMap.has( instance ) ) {\n\t\treturn getKey( weakMap.get( instance ) );\n\t}\n\n\tid += 1;\n\n\tweakMap.set( instance, id );\n\n\treturn getKey( id );\n}\n\nexport default useLinkInstanceKey;\n"]}
1
+ {"version":3,"sources":["@wordpress/format-library/src/link/use-link-instance-key.js"],"names":["weakMap","WeakMap","id","prefix","getKey","_id","useLinkInstanceKey","instance","has","get","set"],"mappings":"AAAA;AACA,MAAMA,OAAO,GAAG,IAAIC,OAAJ,EAAhB,C,CAEA;;AACA,IAAIC,EAAE,GAAG,CAAC,CAAV;AAEA,MAAMC,MAAM,GAAG,uBAAf;;AAEA,SAASC,MAAT,CAAiBC,GAAjB,EAAuB;AACtB,SAAQ,GAAGF,MAAQ,IAAIE,GAAK,EAA5B;AACA;AAED;AACA;AACA;AACA;AACA;AACA;;;AACA,SAASC,kBAAT,CAA6BC,QAA7B,EAAwC;AACvC,MAAK,CAAEA,QAAP,EAAkB;AACjB;AACA;;AACD,MAAKP,OAAO,CAACQ,GAAR,CAAaD,QAAb,CAAL,EAA+B;AAC9B,WAAOH,MAAM,CAAEJ,OAAO,CAACS,GAAR,CAAaF,QAAb,CAAF,CAAb;AACA;;AAEDL,EAAAA,EAAE,IAAI,CAAN;AAEAF,EAAAA,OAAO,CAACU,GAAR,CAAaH,QAAb,EAAuBL,EAAvB;AAEA,SAAOE,MAAM,CAAEF,EAAF,CAAb;AACA;;AAED,eAAeI,kBAAf","sourcesContent":["// Weakly referenced map allows unused ids to be garbage collected.\nconst weakMap = new WeakMap();\n\n// Incrementing zero-based ID value.\nlet id = -1;\n\nconst prefix = 'link-control-instance';\n\nfunction getKey( _id ) {\n\treturn `${ prefix }-${ _id }`;\n}\n\n/**\n * Builds a unique link control key for the given object reference.\n *\n * @param {Object} instance an unique object reference specific to this link control instance.\n * @return {string | undefined} the unique key to use for this link control.\n */\nfunction useLinkInstanceKey( instance ) {\n\tif ( ! instance ) {\n\t\treturn;\n\t}\n\tif ( weakMap.has( instance ) ) {\n\t\treturn getKey( weakMap.get( instance ) );\n\t}\n\n\tid += 1;\n\n\tweakMap.set( instance, id );\n\n\treturn getKey( id );\n}\n\nexport default useLinkInstanceKey;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/format-library",
3
- "version": "4.2.0",
3
+ "version": "4.3.1",
4
4
  "description": "Format library for the WordPress editor.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -26,17 +26,17 @@
26
26
  "react-native": "src/index",
27
27
  "dependencies": {
28
28
  "@babel/runtime": "^7.16.0",
29
- "@wordpress/a11y": "^3.25.0",
30
- "@wordpress/block-editor": "^11.2.0",
31
- "@wordpress/components": "^23.2.0",
32
- "@wordpress/compose": "^6.2.0",
33
- "@wordpress/data": "^8.2.0",
34
- "@wordpress/element": "^5.2.0",
35
- "@wordpress/html-entities": "^3.25.0",
36
- "@wordpress/i18n": "^4.25.0",
37
- "@wordpress/icons": "^9.16.0",
38
- "@wordpress/rich-text": "^6.2.0",
39
- "@wordpress/url": "^3.26.0"
29
+ "@wordpress/a11y": "^3.26.1",
30
+ "@wordpress/block-editor": "^11.3.1",
31
+ "@wordpress/components": "^23.3.1",
32
+ "@wordpress/compose": "^6.3.1",
33
+ "@wordpress/data": "^8.3.1",
34
+ "@wordpress/element": "^5.3.1",
35
+ "@wordpress/html-entities": "^3.26.1",
36
+ "@wordpress/i18n": "^4.26.1",
37
+ "@wordpress/icons": "^9.17.1",
38
+ "@wordpress/rich-text": "^6.3.1",
39
+ "@wordpress/url": "^3.27.1"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "react": "^18.0.0",
@@ -45,5 +45,5 @@
45
45
  "publishConfig": {
46
46
  "access": "public"
47
47
  },
48
- "gitHead": "204c880ff65295768e9695dfee6c7a9fee1fdd05"
48
+ "gitHead": "e9ff92d836928aba65dde94d9d193bc401a934d7"
49
49
  }
@@ -14,6 +14,8 @@ import {
14
14
  removeFormat,
15
15
  slice,
16
16
  replace,
17
+ split,
18
+ concat,
17
19
  } from '@wordpress/rich-text';
18
20
  import {
19
21
  __experimentalLinkControl as LinkControl,
@@ -119,6 +121,7 @@ function InlineLinkUI( {
119
121
  } );
120
122
 
121
123
  const newText = nextValue.title || newUrl;
124
+
122
125
  if ( isCollapsed( value ) && ! isActive ) {
123
126
  // Scenario: we don't have any actively selected text or formats.
124
127
  const toInsert = applyFormat(
@@ -148,14 +151,37 @@ function InlineLinkUI( {
148
151
  newText.length
149
152
  );
150
153
 
154
+ // Get the boundaries of the active link format.
155
+ const boundary = getFormatBoundary( value, {
156
+ type: 'core/link',
157
+ } );
158
+
159
+ // Split the value at the start of the active link format.
160
+ // Passing "start" as the 3rd parameter is required to ensure
161
+ // the second half of the split value is split at the format's
162
+ // start boundary and avoids relying on the value's "end" property
163
+ // which may not correspond correctly.
164
+ const [ valBefore, valAfter ] = split(
165
+ value,
166
+ boundary.start,
167
+ boundary.start
168
+ );
169
+
151
170
  // Update the original (full) RichTextValue replacing the
152
171
  // target text with the *new* RichTextValue containing:
153
172
  // 1. The new text content.
154
173
  // 2. The new link format.
174
+ // As "replace" will operate on the first match only, it is
175
+ // run only against the second half of the value which was
176
+ // split at the active format's boundary. This avoids a bug
177
+ // with incorrectly targetted replacements.
178
+ // See: https://github.com/WordPress/gutenberg/issues/41771.
155
179
  // Note original formats will be lost when applying this change.
156
180
  // That is expected behaviour.
157
181
  // See: https://github.com/WordPress/gutenberg/pull/33849#issuecomment-936134179.
158
- newValue = replace( value, richTextText, newValue );
182
+ const newValAfter = replace( valAfter, richTextText, newValue );
183
+
184
+ newValue = concat( valBefore, newValAfter );
159
185
  }
160
186
 
161
187
  newValue.start = newValue.end;
@@ -14,7 +14,7 @@ function getKey( _id ) {
14
14
  * Builds a unique link control key for the given object reference.
15
15
  *
16
16
  * @param {Object} instance an unique object reference specific to this link control instance.
17
- * @return {string} the unique key to use for this link control.
17
+ * @return {string | undefined} the unique key to use for this link control.
18
18
  */
19
19
  function useLinkInstanceKey( instance ) {
20
20
  if ( ! instance ) {