@wordpress/block-editor 15.12.1-next.v.0 → 15.12.2-next.v.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.
Files changed (124) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/build/components/block-allowed-blocks/modal.cjs +1 -1
  3. package/build/components/block-allowed-blocks/modal.cjs.map +2 -2
  4. package/build/components/block-removal-warning-modal/index.cjs +30 -5
  5. package/build/components/block-removal-warning-modal/index.cjs.map +3 -3
  6. package/build/components/block-visibility/use-block-visibility.cjs +14 -29
  7. package/build/components/block-visibility/use-block-visibility.cjs.map +2 -2
  8. package/build/components/global-styles/hooks.cjs +7 -0
  9. package/build/components/global-styles/hooks.cjs.map +2 -2
  10. package/build/components/global-styles/typography-panel.cjs +71 -3
  11. package/build/components/global-styles/typography-panel.cjs.map +3 -3
  12. package/build/components/grid/grid-visualizer.cjs +49 -13
  13. package/build/components/grid/grid-visualizer.cjs.map +2 -2
  14. package/build/components/iframe/index.cjs +3 -1
  15. package/build/components/iframe/index.cjs.map +2 -2
  16. package/build/components/iframe/use-scale-canvas.cjs +1 -0
  17. package/build/components/iframe/use-scale-canvas.cjs.map +2 -2
  18. package/build/components/link-control/index.cjs +73 -2
  19. package/build/components/link-control/index.cjs.map +3 -3
  20. package/build/components/link-control/is-url-like.cjs +15 -3
  21. package/build/components/link-control/is-url-like.cjs.map +2 -2
  22. package/build/components/link-control/search-input.cjs +4 -1
  23. package/build/components/link-control/search-input.cjs.map +2 -2
  24. package/build/components/link-control/use-search-handler.cjs +1 -1
  25. package/build/components/link-control/use-search-handler.cjs.map +2 -2
  26. package/build/components/provider/use-block-sync.cjs +60 -8
  27. package/build/components/provider/use-block-sync.cjs.map +2 -2
  28. package/build/components/text-indent-control/index.cjs +121 -0
  29. package/build/components/text-indent-control/index.cjs.map +7 -0
  30. package/build/components/url-input/index.cjs +22 -2
  31. package/build/components/url-input/index.cjs.map +3 -3
  32. package/build/components/url-popover/image-url-input-ui.cjs +1 -1
  33. package/build/components/url-popover/image-url-input-ui.cjs.map +2 -2
  34. package/build/components/writing-flow/use-arrow-nav.cjs +0 -3
  35. package/build/components/writing-flow/use-arrow-nav.cjs.map +2 -2
  36. package/build/hooks/aria-label.cjs +2 -1
  37. package/build/hooks/aria-label.cjs.map +2 -2
  38. package/build/hooks/grid-visualizer.cjs +20 -4
  39. package/build/hooks/grid-visualizer.cjs.map +2 -2
  40. package/build/hooks/layout-child.cjs +8 -3
  41. package/build/hooks/layout-child.cjs.map +2 -2
  42. package/build/hooks/typography.cjs +2 -0
  43. package/build/hooks/typography.cjs.map +2 -2
  44. package/build/hooks/utils.cjs +4 -0
  45. package/build/hooks/utils.cjs.map +2 -2
  46. package/build/store/actions.cjs +2 -2
  47. package/build/store/actions.cjs.map +2 -2
  48. package/build-module/components/block-allowed-blocks/modal.mjs +2 -2
  49. package/build-module/components/block-allowed-blocks/modal.mjs.map +2 -2
  50. package/build-module/components/block-removal-warning-modal/index.mjs +34 -7
  51. package/build-module/components/block-removal-warning-modal/index.mjs.map +2 -2
  52. package/build-module/components/block-visibility/use-block-visibility.mjs +14 -29
  53. package/build-module/components/block-visibility/use-block-visibility.mjs.map +2 -2
  54. package/build-module/components/global-styles/hooks.mjs +7 -0
  55. package/build-module/components/global-styles/hooks.mjs.map +2 -2
  56. package/build-module/components/global-styles/typography-panel.mjs +73 -4
  57. package/build-module/components/global-styles/typography-panel.mjs.map +2 -2
  58. package/build-module/components/grid/grid-visualizer.mjs +50 -14
  59. package/build-module/components/grid/grid-visualizer.mjs.map +2 -2
  60. package/build-module/components/iframe/index.mjs +9 -2
  61. package/build-module/components/iframe/index.mjs.map +2 -2
  62. package/build-module/components/iframe/use-scale-canvas.mjs +1 -0
  63. package/build-module/components/iframe/use-scale-canvas.mjs.map +2 -2
  64. package/build-module/components/link-control/index.mjs +74 -3
  65. package/build-module/components/link-control/index.mjs.map +2 -2
  66. package/build-module/components/link-control/is-url-like.mjs +10 -3
  67. package/build-module/components/link-control/is-url-like.mjs.map +2 -2
  68. package/build-module/components/link-control/search-input.mjs +4 -1
  69. package/build-module/components/link-control/search-input.mjs.map +2 -2
  70. package/build-module/components/link-control/use-search-handler.mjs +2 -2
  71. package/build-module/components/link-control/use-search-handler.mjs.map +2 -2
  72. package/build-module/components/provider/use-block-sync.mjs +60 -8
  73. package/build-module/components/provider/use-block-sync.mjs.map +2 -2
  74. package/build-module/components/text-indent-control/index.mjs +110 -0
  75. package/build-module/components/text-indent-control/index.mjs.map +7 -0
  76. package/build-module/components/url-input/index.mjs +24 -4
  77. package/build-module/components/url-input/index.mjs.map +2 -2
  78. package/build-module/components/url-popover/image-url-input-ui.mjs +2 -2
  79. package/build-module/components/url-popover/image-url-input-ui.mjs.map +2 -2
  80. package/build-module/components/writing-flow/use-arrow-nav.mjs +0 -3
  81. package/build-module/components/writing-flow/use-arrow-nav.mjs.map +2 -2
  82. package/build-module/hooks/aria-label.mjs +2 -1
  83. package/build-module/hooks/aria-label.mjs.map +2 -2
  84. package/build-module/hooks/grid-visualizer.mjs +20 -4
  85. package/build-module/hooks/grid-visualizer.mjs.map +2 -2
  86. package/build-module/hooks/layout-child.mjs +8 -3
  87. package/build-module/hooks/layout-child.mjs.map +2 -2
  88. package/build-module/hooks/typography.mjs +2 -0
  89. package/build-module/hooks/typography.mjs.map +2 -2
  90. package/build-module/hooks/utils.mjs +4 -0
  91. package/build-module/hooks/utils.mjs.map +2 -2
  92. package/build-module/store/actions.mjs +2 -2
  93. package/build-module/store/actions.mjs.map +2 -2
  94. package/package.json +39 -39
  95. package/src/components/block-allowed-blocks/modal.js +2 -2
  96. package/src/components/block-removal-warning-modal/index.js +55 -19
  97. package/src/components/block-switcher/block-transformations-menu.native.js +1 -0
  98. package/src/components/block-toolbar/test/__snapshots__/block-toolbar-menu.native.js.snap +4 -6
  99. package/src/components/block-toolbar/test/block-toolbar-menu.native.js +2 -2
  100. package/src/components/block-visibility/use-block-visibility.js +17 -32
  101. package/src/components/global-styles/hooks.js +10 -0
  102. package/src/components/global-styles/typography-panel.js +78 -1
  103. package/src/components/grid/grid-visualizer.js +58 -12
  104. package/src/components/iframe/index.js +12 -2
  105. package/src/components/iframe/use-scale-canvas.js +1 -0
  106. package/src/components/inserter/menu.native.js +1 -0
  107. package/src/components/link-control/index.js +160 -3
  108. package/src/components/link-control/is-url-like.js +43 -8
  109. package/src/components/link-control/search-input.js +7 -0
  110. package/src/components/link-control/test/index.js +260 -0
  111. package/src/components/link-control/test/is-url-like.js +49 -1
  112. package/src/components/link-control/use-search-handler.js +2 -2
  113. package/src/components/provider/test/use-block-sync.js +105 -0
  114. package/src/components/provider/use-block-sync.js +118 -9
  115. package/src/components/text-indent-control/index.js +138 -0
  116. package/src/components/url-input/index.js +21 -2
  117. package/src/components/url-popover/image-url-input-ui.js +2 -2
  118. package/src/components/writing-flow/use-arrow-nav.js +0 -4
  119. package/src/hooks/aria-label.js +9 -1
  120. package/src/hooks/grid-visualizer.js +53 -33
  121. package/src/hooks/layout-child.js +6 -0
  122. package/src/hooks/typography.js +2 -0
  123. package/src/hooks/utils.js +4 -0
  124. package/src/store/actions.js +8 -6
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/link-control/index.js"],
4
- "sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport {\n\tButton,\n\tSpinner,\n\tNotice,\n\tTextControl,\n\t__experimentalHStack as HStack,\n\t__experimentalInputControlSuffixWrapper as InputControlSuffixWrapper,\n} from '@wordpress/components';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { useRef, useState, useEffect, useMemo } from '@wordpress/element';\nimport { useInstanceId } from '@wordpress/compose';\nimport { focus } from '@wordpress/dom';\nimport { ENTER } from '@wordpress/keycodes';\nimport { isShallowEqualObjects } from '@wordpress/is-shallow-equal';\nimport { useSelect, useDispatch } from '@wordpress/data';\nimport { store as preferencesStore } from '@wordpress/preferences';\nimport { keyboardReturn, linkOff } from '@wordpress/icons';\nimport deprecated from '@wordpress/deprecated';\n\n/**\n * Internal dependencies\n */\nimport LinkControlSettingsDrawer from './settings-drawer';\nimport LinkControlSearchInput from './search-input';\nimport LinkPreview from './link-preview';\nimport LinkSettings from './settings';\nimport useCreatePage from './use-create-page';\nimport useInternalValue from './use-internal-value';\nimport { ViewerFill } from './viewer-slot';\nimport { DEFAULT_LINK_SETTINGS } from './constants';\n\n/**\n * Default properties associated with a link control value.\n *\n * @typedef WPLinkControlDefaultValue\n *\n * @property {string} url Link URL.\n * @property {string=} title Link title.\n * @property {boolean=} opensInNewTab Whether link should open in a new browser\n * tab. This value is only assigned if not\n * providing a custom `settings` prop.\n */\n\n/**\n * Custom settings values associated with a link.\n *\n * @typedef {{[setting:string]:any}} WPLinkControlSettingsValue\n */\n\n/**\n * Custom settings values associated with a link.\n *\n * @typedef WPLinkControlSetting\n *\n * @property {string} id Identifier to use as property for setting value.\n * @property {string} title Human-readable label to show in user interface.\n */\n\n/**\n * Properties associated with a link control value, composed as a union of the\n * default properties and any custom settings values.\n *\n * @typedef {WPLinkControlDefaultValue&WPLinkControlSettingsValue} WPLinkControlValue\n */\n\n/** @typedef {(nextValue:WPLinkControlValue)=>void} WPLinkControlOnChangeProp */\n\n/**\n * Properties associated with a search suggestion used within the LinkControl.\n *\n * @typedef WPLinkControlSuggestion\n *\n * @property {string} id Identifier to use to uniquely identify the suggestion.\n * @property {string} type Identifies the type of the suggestion (eg: `post`,\n * `page`, `url`...etc)\n * @property {string} title Human-readable label to show in user interface.\n * @property {string} url A URL for the suggestion.\n */\n\n/** @typedef {(title:string)=>WPLinkControlSuggestion} WPLinkControlCreateSuggestionProp */\n\n/**\n * @typedef WPLinkControlProps\n *\n * @property {(WPLinkControlSetting[])=} settings An array of settings objects. Each object will used to\n * render a `ToggleControl` for that setting.\n * @property {boolean=} forceIsEditingLink If passed as either `true` or `false`, controls the\n * internal editing state of the component to respective\n * show or not show the URL input field.\n * @property {WPLinkControlValue=} value Current link value.\n * @property {WPLinkControlOnChangeProp=} onChange Value change handler, called with the updated value if\n * the user selects a new link or updates settings.\n * @property {boolean=} noDirectEntry Whether to allow turning a URL-like search query directly into a link.\n * @property {boolean=} showSuggestions Whether to present suggestions when typing the URL.\n * @property {boolean=} showInitialSuggestions Whether to present initial suggestions immediately.\n * @property {boolean=} withCreateSuggestion Whether to allow creation of link value from suggestion.\n * @property {Object=} suggestionsQuery Query parameters to pass along to wp.blockEditor.__experimentalFetchLinkSuggestions.\n * @property {boolean=} noURLSuggestion Whether to add a fallback suggestion which treats the search query as a URL.\n * @property {boolean=} hasTextControl Whether to add a text field to the UI to update the value.title.\n * @property {string|Function|undefined} createSuggestionButtonText The text to use in the button that calls createSuggestion.\n * @property {Function} renderControlBottom Optional controls to be rendered at the bottom of the component.\n * @property {boolean=} handleEntities Whether to handle entity links (links with ID). When true and a link has an ID, the input will be disabled and show an unlink button.\n */\n\nconst noop = () => {};\n\nconst PREFERENCE_SCOPE = 'core/block-editor';\nconst PREFERENCE_KEY = 'linkControlSettingsDrawer';\n\n/**\n * Renders a link control. A link control is a controlled input which maintains\n * a value associated with a link (HTML anchor element) and relevant settings\n * for how that link is expected to behave.\n *\n * @param {WPLinkControlProps} props Component props.\n */\nfunction LinkControl( {\n\tsearchInputPlaceholder,\n\tvalue,\n\tsettings = DEFAULT_LINK_SETTINGS,\n\tonChange = noop,\n\tonRemove,\n\tonCancel,\n\tnoDirectEntry = false,\n\tshowSuggestions = true,\n\tshowInitialSuggestions,\n\tforceIsEditingLink,\n\tcreateSuggestion,\n\twithCreateSuggestion,\n\tinputValue: propInputValue = '',\n\tsuggestionsQuery = {},\n\tnoURLSuggestion = false,\n\tcreateSuggestionButtonText,\n\thasRichPreviews = false,\n\thasTextControl = false,\n\trenderControlBottom = null,\n\thandleEntities = false,\n} ) {\n\tif ( withCreateSuggestion === undefined && createSuggestion ) {\n\t\twithCreateSuggestion = true;\n\t}\n\n\tconst [ settingsOpen, setSettingsOpen ] = useState( false );\n\n\tconst { advancedSettingsPreference } = useSelect( ( select ) => {\n\t\tconst prefsStore = select( preferencesStore );\n\n\t\treturn {\n\t\t\tadvancedSettingsPreference:\n\t\t\t\tprefsStore.get( PREFERENCE_SCOPE, PREFERENCE_KEY ) ?? false,\n\t\t};\n\t}, [] );\n\n\tconst { set: setPreference } = useDispatch( preferencesStore );\n\n\t/**\n\t * Sets the open/closed state of the Advanced Settings Drawer,\n\t * optionlly persisting the state to the user's preferences.\n\t *\n\t * Note that Block Editor components can be consumed by non-WordPress\n\t * environments which may not have preferences setup.\n\t * Therefore a local state is also used as a fallback.\n\t *\n\t * @param {boolean} prefVal the open/closed state of the Advanced Settings Drawer.\n\t */\n\tconst setSettingsOpenWithPreference = ( prefVal ) => {\n\t\tif ( setPreference ) {\n\t\t\tsetPreference( PREFERENCE_SCOPE, PREFERENCE_KEY, prefVal );\n\t\t}\n\t\tsetSettingsOpen( prefVal );\n\t};\n\n\t// Block Editor components can be consumed by non-WordPress environments\n\t// which may not have these preferences setup.\n\t// Therefore a local state is used as a fallback.\n\tconst isSettingsOpen = advancedSettingsPreference || settingsOpen;\n\n\tconst isMountingRef = useRef( true );\n\tconst wrapperNode = useRef();\n\tconst textInputRef = useRef();\n\tconst searchInputRef = useRef();\n\t// TODO: Remove entityUrlFallbackRef and previewValue in favor of value prop after taxonomy entity binding\n\t// is stable and returns the correct URL instead of null while resolving when creating the entity.\n\t//\n\t// Preserve the URL from entity suggestions before binding overrides it\n\t// This is due to entity binding not being available immediately after the suggestion is selected.\n\t// The URL can return null, especially for taxonomy entities, while entity binding is being resolved.\n\t// To avoid unnecessary rerenders and focus loss, we preserve the URL from the suggestion and use it\n\t// as a fallback until the entity binding is available.\n\tconst entityUrlFallbackRef = useRef();\n\n\tconst settingsKeys = settings.map( ( { id } ) => id );\n\n\tconst [\n\t\tinternalControlValue,\n\t\tsetInternalControlValue,\n\t\tsetInternalURLInputValue,\n\t\tsetInternalTextInputValue,\n\t\tcreateSetInternalSettingValueHandler,\n\t] = useInternalValue( value );\n\n\t// Compute isEntity internally based on handleEntities prop and presence of ID\n\tconst isEntity = handleEntities && !! internalControlValue?.id;\n\n\t// Generate help text ID for accessibility association\n\tconst baseId = useInstanceId( LinkControl, 'link-control' );\n\tconst helpTextId = isEntity ? `${ baseId }__help` : null;\n\n\tconst valueHasChanges =\n\t\tvalue && ! isShallowEqualObjects( internalControlValue, value );\n\n\tconst [ isEditingLink, setIsEditingLink ] = useState(\n\t\tforceIsEditingLink !== undefined\n\t\t\t? forceIsEditingLink\n\t\t\t: ! value || ! value.url\n\t);\n\n\tconst { createPage, isCreatingPage, errorMessage } =\n\t\tuseCreatePage( createSuggestion );\n\n\tuseEffect( () => {\n\t\tif ( forceIsEditingLink === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tsetIsEditingLink( forceIsEditingLink );\n\t}, [ forceIsEditingLink ] );\n\n\tuseEffect( () => {\n\t\t// We don't auto focus into the Link UI on mount\n\t\t// because otherwise using the keyboard to select text\n\t\t// *within* the link format is not possible.\n\t\tif ( isMountingRef.current ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Scenario - when:\n\t\t// - switching between editable and non editable LinkControl\n\t\t// - clicking on a link\n\t\t// ...then move focus to the *first* element to avoid focus loss\n\t\t// and to ensure focus is *within* the Link UI.\n\t\tconst nextFocusTarget =\n\t\t\tfocus.focusable.find( wrapperNode.current )[ 0 ] ||\n\t\t\twrapperNode.current;\n\n\t\tnextFocusTarget.focus();\n\t}, [ isEditingLink, isCreatingPage ] );\n\n\t// The component mounting reference is maintained separately\n\t// to correctly reset values in `StrictMode`.\n\tuseEffect( () => {\n\t\tisMountingRef.current = false;\n\n\t\treturn () => {\n\t\t\tisMountingRef.current = true;\n\t\t};\n\t}, [] );\n\n\tconst hasLinkValue = value?.url?.trim()?.length > 0;\n\n\t/**\n\t * Cancels editing state.\n\t */\n\tconst stopEditing = () => {\n\t\tsetIsEditingLink( false );\n\t};\n\n\tconst handleSelectSuggestion = ( updatedValue ) => {\n\t\t// Preserve the URL for taxonomy entities before binding overrides it\n\t\tif ( updatedValue?.kind === 'taxonomy' && updatedValue?.url ) {\n\t\t\tentityUrlFallbackRef.current = updatedValue.url;\n\t\t}\n\n\t\t// Suggestions may contains \"settings\" values (e.g. `opensInNewTab`)\n\t\t// which should not override any existing settings values set by the\n\t\t// user. This filters out any settings values from the suggestion.\n\t\tconst nonSettingsChanges = Object.keys( updatedValue ).reduce(\n\t\t\t( acc, key ) => {\n\t\t\t\tif ( ! settingsKeys.includes( key ) ) {\n\t\t\t\t\tacc[ key ] = updatedValue[ key ];\n\t\t\t\t}\n\t\t\t\treturn acc;\n\t\t\t},\n\t\t\t{}\n\t\t);\n\n\t\tonChange( {\n\t\t\t...internalControlValue,\n\t\t\t...nonSettingsChanges,\n\t\t\t// As title is not a setting, it must be manually applied\n\t\t\t// in such a way as to preserve the users changes over\n\t\t\t// any \"title\" value provided by the \"suggestion\".\n\t\t\ttitle: internalControlValue?.title || updatedValue?.title,\n\t\t} );\n\n\t\tstopEditing();\n\t};\n\n\tconst handleSubmit = () => {\n\t\tif ( valueHasChanges ) {\n\t\t\t// Submit the original value with new stored values applied\n\t\t\t// on top. URL is a special case as it may also be a prop.\n\t\t\tonChange( {\n\t\t\t\t...value,\n\t\t\t\t...internalControlValue,\n\t\t\t\turl: currentUrlInputValue,\n\t\t\t} );\n\t\t}\n\t\tstopEditing();\n\t};\n\n\tconst handleSubmitWithEnter = ( event ) => {\n\t\tconst { keyCode } = event;\n\n\t\tif (\n\t\t\tkeyCode === ENTER &&\n\t\t\t! currentInputIsEmpty // Disallow submitting empty values.\n\t\t) {\n\t\t\tevent.preventDefault();\n\t\t\thandleSubmit();\n\t\t}\n\t};\n\n\tconst resetInternalValues = () => {\n\t\tsetInternalControlValue( value );\n\t};\n\n\tconst handleCancel = ( event ) => {\n\t\tevent.preventDefault();\n\t\tevent.stopPropagation();\n\n\t\t// Ensure that any unsubmitted input changes are reset.\n\t\tresetInternalValues();\n\n\t\tif ( hasLinkValue ) {\n\t\t\t// If there is a link then exist editing mode and show preview.\n\t\t\tstopEditing();\n\t\t} else {\n\t\t\t// If there is no link value, then remove the link entirely.\n\t\t\tonRemove?.();\n\t\t}\n\n\t\tonCancel?.();\n\t};\n\n\tconst [ shouldFocusSearchInput, setShouldFocusSearchInput ] =\n\t\tuseState( false );\n\n\tconst handleUnlink = () => {\n\t\t// Clear the internal state to remove the ID and re-enable the field\n\t\t// Explicitly set id, kind, and type to undefined so they override\n\t\t// the original values when spread in handleSubmit. This ensures that\n\t\t// when the user types a custom URL and submits, the entity link is\n\t\t// properly severed (not just when selecting a different entity from suggestions).\n\t\tconst { id, kind, type, ...restValue } = internalControlValue;\n\t\tsetInternalControlValue( {\n\t\t\t...restValue,\n\t\t\tid: undefined,\n\t\t\tkind: undefined,\n\t\t\ttype: undefined,\n\t\t\turl: undefined,\n\t\t} );\n\n\t\t// Request focus after the component re-renders with the cleared state\n\t\t// We can't focus immediately because the input might still be disabled\n\t\tsetShouldFocusSearchInput( true );\n\t};\n\n\t// Focus the search input when requested, once the component has re-rendered\n\t// This ensures the input is enabled and ready to receive focus\n\tuseEffect( () => {\n\t\tif ( shouldFocusSearchInput ) {\n\t\t\tsearchInputRef.current?.focus();\n\t\t\tsetShouldFocusSearchInput( false );\n\t\t}\n\t}, [ shouldFocusSearchInput ] );\n\n\tconst currentUrlInputValue =\n\t\tpropInputValue || internalControlValue?.url || '';\n\n\tconst currentInputIsEmpty = ! currentUrlInputValue?.trim()?.length;\n\n\tconst shownUnlinkControl =\n\t\tonRemove && value && ! isEditingLink && ! isCreatingPage;\n\n\tconst showActions = isEditingLink && hasLinkValue;\n\n\t// Only show text control once a URL value has been committed\n\t// and it isn't just empty whitespace.\n\t// See https://github.com/WordPress/gutenberg/pull/33849/#issuecomment-932194927.\n\tconst showTextControl = hasLinkValue && hasTextControl;\n\n\tconst isEditing = ( isEditingLink || ! value ) && ! isCreatingPage;\n\tconst isDisabled = ! valueHasChanges || currentInputIsEmpty;\n\tconst showSettings = !! settings?.length && isEditingLink && hasLinkValue;\n\n\tconst previewValue = useMemo( () => {\n\t\t// There is a chance that the value is not yet set from the entity binding, so we use the preserved URL.\n\t\tif (\n\t\t\tvalue?.kind === 'taxonomy' &&\n\t\t\t! value?.url &&\n\t\t\tentityUrlFallbackRef.current\n\t\t) {\n\t\t\t// combine the value prop with the preserved URL from the suggestion\n\t\t\treturn {\n\t\t\t\t...value,\n\t\t\t\turl: entityUrlFallbackRef.current,\n\t\t\t};\n\t\t}\n\n\t\t// If we don't have a fallback URL, use the value prop.\n\t\treturn value;\n\t}, [ value ] );\n\n\treturn (\n\t\t<div\n\t\t\ttabIndex={ -1 }\n\t\t\tref={ wrapperNode }\n\t\t\tclassName=\"block-editor-link-control\"\n\t\t>\n\t\t\t{ isCreatingPage && (\n\t\t\t\t<div className=\"block-editor-link-control__loading\">\n\t\t\t\t\t<Spinner /> { __( 'Creating' ) }\u2026\n\t\t\t\t</div>\n\t\t\t) }\n\n\t\t\t{ isEditing && (\n\t\t\t\t<>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={ clsx( {\n\t\t\t\t\t\t\t'block-editor-link-control__search-input-wrapper': true,\n\t\t\t\t\t\t\t'has-text-control': showTextControl,\n\t\t\t\t\t\t\t'has-actions': showActions,\n\t\t\t\t\t\t} ) }\n\t\t\t\t\t>\n\t\t\t\t\t\t{ showTextControl && (\n\t\t\t\t\t\t\t<TextControl\n\t\t\t\t\t\t\t\tref={ textInputRef }\n\t\t\t\t\t\t\t\tclassName=\"block-editor-link-control__field block-editor-link-control__text-content\"\n\t\t\t\t\t\t\t\tlabel={ __( 'Text' ) }\n\t\t\t\t\t\t\t\tvalue={ internalControlValue?.title }\n\t\t\t\t\t\t\t\tonChange={ setInternalTextInputValue }\n\t\t\t\t\t\t\t\tonKeyDown={ handleSubmitWithEnter }\n\t\t\t\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) }\n\t\t\t\t\t\t<LinkControlSearchInput\n\t\t\t\t\t\t\tref={ searchInputRef }\n\t\t\t\t\t\t\tcurrentLink={ value }\n\t\t\t\t\t\t\tclassName=\"block-editor-link-control__field block-editor-link-control__search-input\"\n\t\t\t\t\t\t\tplaceholder={ searchInputPlaceholder }\n\t\t\t\t\t\t\tvalue={ currentUrlInputValue }\n\t\t\t\t\t\t\twithCreateSuggestion={ withCreateSuggestion }\n\t\t\t\t\t\t\tonCreateSuggestion={ createPage }\n\t\t\t\t\t\t\tonChange={ setInternalURLInputValue }\n\t\t\t\t\t\t\tonSelect={ handleSelectSuggestion }\n\t\t\t\t\t\t\tshowInitialSuggestions={ showInitialSuggestions }\n\t\t\t\t\t\t\tallowDirectEntry={ ! noDirectEntry }\n\t\t\t\t\t\t\tshowSuggestions={ showSuggestions }\n\t\t\t\t\t\t\tsuggestionsQuery={ suggestionsQuery }\n\t\t\t\t\t\t\twithURLSuggestion={ ! noURLSuggestion }\n\t\t\t\t\t\t\tcreateSuggestionButtonText={\n\t\t\t\t\t\t\t\tcreateSuggestionButtonText\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\thideLabelFromVision={ ! showTextControl }\n\t\t\t\t\t\t\tisEntity={ isEntity }\n\t\t\t\t\t\t\tsuffix={\n\t\t\t\t\t\t\t\t<SearchSuffixControl\n\t\t\t\t\t\t\t\t\tisEntity={ isEntity }\n\t\t\t\t\t\t\t\t\tshowActions={ showActions }\n\t\t\t\t\t\t\t\t\tisDisabled={ isDisabled }\n\t\t\t\t\t\t\t\t\tonUnlink={ handleUnlink }\n\t\t\t\t\t\t\t\t\tonSubmit={ handleSubmit }\n\t\t\t\t\t\t\t\t\thelpTextId={ helpTextId }\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{ isEntity && helpTextId && (\n\t\t\t\t\t\t\t<p\n\t\t\t\t\t\t\t\tid={ helpTextId }\n\t\t\t\t\t\t\t\tclassName=\"block-editor-link-control__help\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{ sprintf(\n\t\t\t\t\t\t\t\t\t/* translators: %s: entity type (e.g., page, post) */\n\t\t\t\t\t\t\t\t\t__( 'Synced with the selected %s.' ),\n\t\t\t\t\t\t\t\t\tinternalControlValue?.type || 'item'\n\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t) }\n\t\t\t\t\t</div>\n\t\t\t\t\t{ errorMessage && (\n\t\t\t\t\t\t<Notice\n\t\t\t\t\t\t\tclassName=\"block-editor-link-control__search-error\"\n\t\t\t\t\t\t\tstatus=\"error\"\n\t\t\t\t\t\t\tisDismissible={ false }\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{ errorMessage }\n\t\t\t\t\t\t</Notice>\n\t\t\t\t\t) }\n\t\t\t\t</>\n\t\t\t) }\n\n\t\t\t{ value && ! isEditingLink && ! isCreatingPage && (\n\t\t\t\t<LinkPreview\n\t\t\t\t\tkey={ previewValue?.url } // force remount when URL changes to avoid race conditions for rich previews\n\t\t\t\t\tvalue={ previewValue }\n\t\t\t\t\tonEditClick={ () => setIsEditingLink( true ) }\n\t\t\t\t\thasRichPreviews={ hasRichPreviews }\n\t\t\t\t\thasUnlinkControl={ shownUnlinkControl }\n\t\t\t\t\tonRemove={ () => {\n\t\t\t\t\t\tonRemove();\n\t\t\t\t\t\tsetIsEditingLink( true );\n\t\t\t\t\t} }\n\t\t\t\t/>\n\t\t\t) }\n\n\t\t\t{ showSettings && (\n\t\t\t\t<div className=\"block-editor-link-control__tools\">\n\t\t\t\t\t{ ! currentInputIsEmpty && (\n\t\t\t\t\t\t<LinkControlSettingsDrawer\n\t\t\t\t\t\t\tsettingsOpen={ isSettingsOpen }\n\t\t\t\t\t\t\tsetSettingsOpen={ setSettingsOpenWithPreference }\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<LinkSettings\n\t\t\t\t\t\t\t\tvalue={ internalControlValue }\n\t\t\t\t\t\t\t\tsettings={ settings }\n\t\t\t\t\t\t\t\tonChange={ createSetInternalSettingValueHandler(\n\t\t\t\t\t\t\t\t\tsettingsKeys\n\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</LinkControlSettingsDrawer>\n\t\t\t\t\t) }\n\t\t\t\t</div>\n\t\t\t) }\n\n\t\t\t{ showActions && (\n\t\t\t\t<HStack\n\t\t\t\t\tjustify=\"right\"\n\t\t\t\t\tclassName=\"block-editor-link-control__search-actions\"\n\t\t\t\t>\n\t\t\t\t\t<Button\n\t\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\tonClick={ handleCancel }\n\t\t\t\t\t>\n\t\t\t\t\t\t{ __( 'Cancel' ) }\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button\n\t\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\tonClick={ isDisabled ? noop : handleSubmit }\n\t\t\t\t\t\tclassName=\"block-editor-link-control__search-submit\"\n\t\t\t\t\t\taria-disabled={ isDisabled }\n\t\t\t\t\t>\n\t\t\t\t\t\t{ __( 'Apply' ) }\n\t\t\t\t\t</Button>\n\t\t\t\t</HStack>\n\t\t\t) }\n\n\t\t\t{ ! isCreatingPage && renderControlBottom && renderControlBottom() }\n\t\t</div>\n\t);\n}\n\n/**\n * Suffix control component for LinkControl search input.\n * Handles the display of unlink button for entities and submit button for regular links.\n *\n * @param {Object} props - Component props\n * @param {boolean} props.isEntity - Whether the link is bound to an entity\n * @param {boolean} props.showActions - Whether to show action buttons\n * @param {boolean} props.isDisabled - Whether the submit button should be disabled\n * @param {Function} props.onUnlink - Callback when unlink button is clicked\n * @param {Function} props.onSubmit - Callback when submit button is clicked\n * @param {string} props.helpTextId - ID of the help text element for accessibility\n */\nfunction SearchSuffixControl( {\n\tisEntity,\n\tshowActions,\n\tisDisabled,\n\tonUnlink,\n\tonSubmit,\n\thelpTextId,\n} ) {\n\tif ( isEntity ) {\n\t\treturn (\n\t\t\t<Button\n\t\t\t\ticon={ linkOff }\n\t\t\t\tonClick={ onUnlink }\n\t\t\t\taria-describedby={ helpTextId }\n\t\t\t\tshowTooltip\n\t\t\t\tlabel={ __( 'Unsync and edit' ) }\n\t\t\t\t__next40pxDefaultSize\n\t\t\t/>\n\t\t);\n\t}\n\n\tif ( showActions ) {\n\t\treturn undefined;\n\t}\n\n\treturn (\n\t\t<InputControlSuffixWrapper variant=\"control\">\n\t\t\t<Button\n\t\t\t\tonClick={ isDisabled ? noop : onSubmit }\n\t\t\t\tlabel={ __( 'Submit' ) }\n\t\t\t\ticon={ keyboardReturn }\n\t\t\t\tclassName=\"block-editor-link-control__search-submit\"\n\t\t\t\taria-disabled={ isDisabled }\n\t\t\t\tsize=\"small\"\n\t\t\t/>\n\t\t</InputControlSuffixWrapper>\n\t);\n}\n\nLinkControl.ViewerFill = ViewerFill;\nLinkControl.DEFAULT_LINK_SETTINGS = DEFAULT_LINK_SETTINGS;\n\nconst DeprecatedExperimentalLinkControl = ( props ) => {\n\tdeprecated( 'wp.blockEditor.__experimentalLinkControl', {\n\t\tsince: '6.8',\n\t\talternative: 'wp.blockEditor.LinkControl',\n\t} );\n\n\treturn <LinkControl { ...props } />;\n};\n\nDeprecatedExperimentalLinkControl.ViewerFill = LinkControl.ViewerFill;\nDeprecatedExperimentalLinkControl.DEFAULT_LINK_SETTINGS =\n\tLinkControl.DEFAULT_LINK_SETTINGS;\n\nexport { DeprecatedExperimentalLinkControl };\nexport default LinkControl;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport {\n\tButton,\n\tSpinner,\n\tNotice,\n\tTextControl,\n\t__experimentalHStack as HStack,\n\t__experimentalInputControlSuffixWrapper as InputControlSuffixWrapper,\n} from '@wordpress/components';\nimport { __, sprintf } from '@wordpress/i18n';\nimport { useRef, useState, useEffect, useMemo } from '@wordpress/element';\nimport { useInstanceId } from '@wordpress/compose';\nimport { focus } from '@wordpress/dom';\nimport { ENTER } from '@wordpress/keycodes';\nimport { isShallowEqualObjects } from '@wordpress/is-shallow-equal';\nimport { useSelect, useDispatch } from '@wordpress/data';\nimport { store as preferencesStore } from '@wordpress/preferences';\nimport { keyboardReturn, linkOff } from '@wordpress/icons';\nimport deprecated from '@wordpress/deprecated';\nimport { isURL, prependHTTPS } from '@wordpress/url';\n\n/**\n * Internal dependencies\n */\nimport LinkControlSettingsDrawer from './settings-drawer';\nimport LinkControlSearchInput from './search-input';\nimport LinkPreview from './link-preview';\nimport LinkSettings from './settings';\nimport useCreatePage from './use-create-page';\nimport useInternalValue from './use-internal-value';\nimport { ViewerFill } from './viewer-slot';\nimport { DEFAULT_LINK_SETTINGS, LINK_ENTRY_TYPES } from './constants';\nimport isURLLike, { isHashLink, isRelativePath } from './is-url-like';\n\n/**\n * Default properties associated with a link control value.\n *\n * @typedef WPLinkControlDefaultValue\n *\n * @property {string} url Link URL.\n * @property {string=} title Link title.\n * @property {boolean=} opensInNewTab Whether link should open in a new browser\n * tab. This value is only assigned if not\n * providing a custom `settings` prop.\n */\n\n/**\n * Custom settings values associated with a link.\n *\n * @typedef {{[setting:string]:any}} WPLinkControlSettingsValue\n */\n\n/**\n * Custom settings values associated with a link.\n *\n * @typedef WPLinkControlSetting\n *\n * @property {string} id Identifier to use as property for setting value.\n * @property {string} title Human-readable label to show in user interface.\n */\n\n/**\n * Properties associated with a link control value, composed as a union of the\n * default properties and any custom settings values.\n *\n * @typedef {WPLinkControlDefaultValue&WPLinkControlSettingsValue} WPLinkControlValue\n */\n\n/** @typedef {(nextValue:WPLinkControlValue)=>void} WPLinkControlOnChangeProp */\n\n/**\n * Properties associated with a search suggestion used within the LinkControl.\n *\n * @typedef WPLinkControlSuggestion\n *\n * @property {string} id Identifier to use to uniquely identify the suggestion.\n * @property {string} type Identifies the type of the suggestion (eg: `post`,\n * `page`, `url`...etc)\n * @property {string} title Human-readable label to show in user interface.\n * @property {string} url A URL for the suggestion.\n */\n\n/** @typedef {(title:string)=>WPLinkControlSuggestion} WPLinkControlCreateSuggestionProp */\n\n/**\n * @typedef WPLinkControlProps\n *\n * @property {(WPLinkControlSetting[])=} settings An array of settings objects. Each object will used to\n * render a `ToggleControl` for that setting.\n * @property {boolean=} forceIsEditingLink If passed as either `true` or `false`, controls the\n * internal editing state of the component to respective\n * show or not show the URL input field.\n * @property {WPLinkControlValue=} value Current link value.\n * @property {WPLinkControlOnChangeProp=} onChange Value change handler, called with the updated value if\n * the user selects a new link or updates settings.\n * @property {boolean=} noDirectEntry Whether to allow turning a URL-like search query directly into a link.\n * @property {boolean=} showSuggestions Whether to present suggestions when typing the URL.\n * @property {boolean=} showInitialSuggestions Whether to present initial suggestions immediately.\n * @property {boolean=} withCreateSuggestion Whether to allow creation of link value from suggestion.\n * @property {Object=} suggestionsQuery Query parameters to pass along to wp.blockEditor.__experimentalFetchLinkSuggestions.\n * @property {boolean=} noURLSuggestion Whether to add a fallback suggestion which treats the search query as a URL.\n * @property {boolean=} hasTextControl Whether to add a text field to the UI to update the value.title.\n * @property {string|Function|undefined} createSuggestionButtonText The text to use in the button that calls createSuggestion.\n * @property {Function} renderControlBottom Optional controls to be rendered at the bottom of the component.\n * @property {boolean=} handleEntities Whether to handle entity links (links with ID). When true and a link has an ID, the input will be disabled and show an unlink button.\n */\n\nconst noop = () => {};\n\nconst PREFERENCE_SCOPE = 'core/block-editor';\nconst PREFERENCE_KEY = 'linkControlSettingsDrawer';\n\n/**\n * Renders a link control. A link control is a controlled input which maintains\n * a value associated with a link (HTML anchor element) and relevant settings\n * for how that link is expected to behave.\n *\n * @param {WPLinkControlProps} props Component props.\n */\nfunction LinkControl( {\n\tsearchInputPlaceholder,\n\tvalue,\n\tsettings = DEFAULT_LINK_SETTINGS,\n\tonChange = noop,\n\tonRemove,\n\tonCancel,\n\tnoDirectEntry = false,\n\tshowSuggestions = true,\n\tshowInitialSuggestions,\n\tforceIsEditingLink,\n\tcreateSuggestion,\n\twithCreateSuggestion,\n\tinputValue: propInputValue = '',\n\tsuggestionsQuery = {},\n\tnoURLSuggestion = false,\n\tcreateSuggestionButtonText,\n\thasRichPreviews = false,\n\thasTextControl = false,\n\trenderControlBottom = null,\n\thandleEntities = false,\n} ) {\n\tif ( withCreateSuggestion === undefined && createSuggestion ) {\n\t\twithCreateSuggestion = true;\n\t}\n\n\tconst [ settingsOpen, setSettingsOpen ] = useState( false );\n\t// Sets if the URL value is valid when submitted. The value could be set to\n\t// { type: 'invalid', message: 'Please enter a valid URL.' } or { type: 'valid' }.\n\t// When it is undefined, the URL value has not been validated.\n\tconst [ customValidity, setCustomValidity ] = useState( undefined );\n\n\tconst { advancedSettingsPreference } = useSelect( ( select ) => {\n\t\tconst prefsStore = select( preferencesStore );\n\n\t\treturn {\n\t\t\tadvancedSettingsPreference:\n\t\t\t\tprefsStore.get( PREFERENCE_SCOPE, PREFERENCE_KEY ) ?? false,\n\t\t};\n\t}, [] );\n\n\tconst { set: setPreference } = useDispatch( preferencesStore );\n\n\t/**\n\t * Sets the open/closed state of the Advanced Settings Drawer,\n\t * optionlly persisting the state to the user's preferences.\n\t *\n\t * Note that Block Editor components can be consumed by non-WordPress\n\t * environments which may not have preferences setup.\n\t * Therefore a local state is also used as a fallback.\n\t *\n\t * @param {boolean} prefVal the open/closed state of the Advanced Settings Drawer.\n\t */\n\tconst setSettingsOpenWithPreference = ( prefVal ) => {\n\t\tif ( setPreference ) {\n\t\t\tsetPreference( PREFERENCE_SCOPE, PREFERENCE_KEY, prefVal );\n\t\t}\n\t\tsetSettingsOpen( prefVal );\n\t};\n\n\t// Block Editor components can be consumed by non-WordPress environments\n\t// which may not have these preferences setup.\n\t// Therefore a local state is used as a fallback.\n\tconst isSettingsOpen = advancedSettingsPreference || settingsOpen;\n\n\tconst isMountingRef = useRef( true );\n\tconst wrapperNode = useRef();\n\tconst textInputRef = useRef();\n\tconst searchInputRef = useRef();\n\t// TODO: Remove entityUrlFallbackRef and previewValue in favor of value prop after taxonomy entity binding\n\t// is stable and returns the correct URL instead of null while resolving when creating the entity.\n\t//\n\t// Preserve the URL from entity suggestions before binding overrides it\n\t// This is due to entity binding not being available immediately after the suggestion is selected.\n\t// The URL can return null, especially for taxonomy entities, while entity binding is being resolved.\n\t// To avoid unnecessary rerenders and focus loss, we preserve the URL from the suggestion and use it\n\t// as a fallback until the entity binding is available.\n\tconst entityUrlFallbackRef = useRef();\n\n\tconst settingsKeys = settings.map( ( { id } ) => id );\n\n\tconst [\n\t\tinternalControlValue,\n\t\tsetInternalControlValue,\n\t\tsetInternalURLInputValue,\n\t\tsetInternalTextInputValue,\n\t\tcreateSetInternalSettingValueHandler,\n\t] = useInternalValue( value );\n\n\t// Compute isEntity internally based on handleEntities prop and presence of ID\n\tconst isEntity = handleEntities && !! internalControlValue?.id;\n\n\t// Generate help text ID for accessibility association\n\tconst baseId = useInstanceId( LinkControl, 'link-control' );\n\tconst helpTextId = isEntity ? `${ baseId }__help` : null;\n\n\tconst valueHasChanges =\n\t\tvalue && ! isShallowEqualObjects( internalControlValue, value );\n\n\tconst [ isEditingLink, setIsEditingLink ] = useState(\n\t\tforceIsEditingLink !== undefined\n\t\t\t? forceIsEditingLink\n\t\t\t: ! value || ! value.url\n\t);\n\n\tconst { createPage, isCreatingPage, errorMessage } =\n\t\tuseCreatePage( createSuggestion );\n\n\tuseEffect( () => {\n\t\tif ( forceIsEditingLink === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tsetIsEditingLink( forceIsEditingLink );\n\t}, [ forceIsEditingLink ] );\n\n\tuseEffect( () => {\n\t\t// We don't auto focus into the Link UI on mount\n\t\t// because otherwise using the keyboard to select text\n\t\t// *within* the link format is not possible.\n\t\tif ( isMountingRef.current ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Scenario - when:\n\t\t// - switching between editable and non editable LinkControl\n\t\t// - clicking on a link\n\t\t// ...then move focus to the *first* element to avoid focus loss\n\t\t// and to ensure focus is *within* the Link UI.\n\t\tconst nextFocusTarget =\n\t\t\tfocus.focusable.find( wrapperNode.current )[ 0 ] ||\n\t\t\twrapperNode.current;\n\n\t\tnextFocusTarget.focus();\n\t}, [ isEditingLink, isCreatingPage ] );\n\n\t// The component mounting reference is maintained separately\n\t// to correctly reset values in `StrictMode`.\n\tuseEffect( () => {\n\t\tisMountingRef.current = false;\n\n\t\treturn () => {\n\t\t\tisMountingRef.current = true;\n\t\t};\n\t}, [] );\n\n\t// Trigger validation display when customValidity becomes invalid.\n\t// This effect runs after React has applied the customValidity state update\n\t// and ControlWithError's useEffect has set the native validity on the input.\n\tuseEffect( () => {\n\t\tif ( customValidity?.type === 'invalid' ) {\n\t\t\tconst inputElement = searchInputRef.current;\n\t\t\tif (\n\t\t\t\tinputElement &&\n\t\t\t\ttypeof inputElement.reportValidity === 'function'\n\t\t\t) {\n\t\t\t\tinputElement.reportValidity();\n\t\t\t}\n\t\t}\n\t}, [ customValidity ] );\n\n\tconst hasLinkValue = value?.url?.trim()?.length > 0;\n\n\t/**\n\t * Cancels editing state.\n\t */\n\tconst stopEditing = () => {\n\t\tsetIsEditingLink( false );\n\t};\n\n\t/**\n\t * Validates a URL string using a multi-stage validation process.\n\t * This helper consolidates URL validation logic used throughout the component.\n\t *\n\t * @param {string} urlToValidate - The URL string to validate\n\t * @return {Object} Validation result with isValid boolean and optional errorMessage\n\t */\n\tconst validateUrl = ( urlToValidate ) => {\n\t\tconst invalidResult = {\n\t\t\ttype: 'invalid',\n\t\t\tmessage: __( 'Please enter a valid URL.' ),\n\t\t};\n\n\t\tconst validResult = {\n\t\t\ttype: 'valid',\n\t\t};\n\n\t\tconst trimmedValue = urlToValidate?.trim();\n\n\t\t// If empty or not URL-like, return invalid\n\t\tif ( ! trimmedValue?.length || ! isURLLike( trimmedValue ) ) {\n\t\t\treturn invalidResult;\n\t\t}\n\n\t\t// Hash links (internal anchor links) and relative paths (/, ./, ../) are\n\t\t// valid href values but cannot be validated by the native URL constructor\n\t\t// (which requires absolute URLs). These are already validated by isURLLike.\n\t\t// Skip URL constructor validation for these cases.\n\t\tif ( isHashLink( trimmedValue ) || isRelativePath( trimmedValue ) ) {\n\t\t\treturn validResult;\n\t\t}\n\n\t\t// Perform URL validation using the native URL constructor as the authoritative source.\n\t\t// The native URL constructor is the standard for URL validity - if it accepts a URL,\n\t\t// we should allow it. For URLs without a protocol (e.g., \"www.wordpress.org\"),\n\t\t// prepend \"http://\" before validating, as the URL constructor requires a protocol.\n\t\t//\n\t\t// Note: Protocol URLs (mailto:, tel:, etc.) are also validated by the native\n\t\t// URL constructor, so we don't need special handling for them.\n\t\t//\n\t\t// Note: We rely on the native URL constructor rather than implementing custom TLD\n\t\t// validation to avoid blocking valid URLs. If a URL passes the native constructor,\n\t\t// it's technically valid according to web standards.\n\t\tconst urlToCheck = prependHTTPS( trimmedValue );\n\t\treturn isURL( urlToCheck ) ? validResult : invalidResult;\n\t};\n\n\tconst handleSelectSuggestion = ( updatedValue ) => {\n\t\t// Validate URL suggestions (link, mailto, tel, internal) or manually entered URLs.\n\t\t// Entity suggestions (post, page, category, etc.) don't need validation as they come from the database.\n\t\t// However, URL suggestions (created from user input with types like 'link', 'mailto', etc.)\n\t\t// still need validation as they may contain invalid URLs like \"www.wordp\".\n\t\tconst isEntitySuggestion =\n\t\t\tupdatedValue &&\n\t\t\tupdatedValue.id &&\n\t\t\tupdatedValue.type &&\n\t\t\t! LINK_ENTRY_TYPES.includes( updatedValue.type );\n\n\t\tif ( ! isEntitySuggestion ) {\n\t\t\t// URL suggestion (link, mailto, tel, internal) or manually entered URL - validate before submitting\n\t\t\t// Use the URL from the suggestion, or fall back to currentUrlInputValue\n\t\t\tconst urlToValidate = updatedValue?.url || currentUrlInputValue;\n\n\t\t\t// Validate the URL using the shared validation helper\n\t\t\tconst validation = validateUrl( urlToValidate );\n\t\t\tif ( validation.type === 'invalid' ) {\n\t\t\t\tsetCustomValidity( validation );\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Preserve the URL for taxonomy entities before binding overrides it\n\t\tif ( updatedValue?.kind === 'taxonomy' && updatedValue?.url ) {\n\t\t\tentityUrlFallbackRef.current = updatedValue.url;\n\t\t}\n\n\t\t// Suggestions may contains \"settings\" values (e.g. `opensInNewTab`)\n\t\t// which should not override any existing settings values set by the\n\t\t// user. This filters out any settings values from the suggestion.\n\t\tconst nonSettingsChanges = Object.keys( updatedValue ).reduce(\n\t\t\t( acc, key ) => {\n\t\t\t\tif ( ! settingsKeys.includes( key ) ) {\n\t\t\t\t\tacc[ key ] = updatedValue[ key ];\n\t\t\t\t}\n\t\t\t\treturn acc;\n\t\t\t},\n\t\t\t{}\n\t\t);\n\n\t\tonChange( {\n\t\t\t...internalControlValue,\n\t\t\t...nonSettingsChanges,\n\t\t\t// As title is not a setting, it must be manually applied\n\t\t\t// in such a way as to preserve the users changes over\n\t\t\t// any \"title\" value provided by the \"suggestion\".\n\t\t\ttitle: internalControlValue?.title || updatedValue?.title,\n\t\t} );\n\n\t\t// Reset validation state when a suggestion is selected\n\t\tsetCustomValidity( undefined );\n\n\t\tstopEditing();\n\t};\n\n\t// Centralized validation function\n\tconst validateAndSetValidity = () => {\n\t\tif ( currentInputIsEmpty ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst trimmedValue = currentUrlInputValue.trim();\n\n\t\t// If the current value is an entity link (has id and type not in LINK_ENTRY_TYPES)\n\t\t// and the URL hasn't changed from the original value, skip validation.\n\t\t// This allows entity links with permalink formats like \"?p=2\" to work without\n\t\t// requiring URL validation when only settings are being changed.\n\t\tconst isEntityLink =\n\t\t\tinternalControlValue &&\n\t\t\tinternalControlValue.id &&\n\t\t\tinternalControlValue.type &&\n\t\t\t! LINK_ENTRY_TYPES.includes( internalControlValue.type );\n\t\tconst urlUnchanged = value?.url === trimmedValue;\n\n\t\tif ( isEntityLink && urlUnchanged ) {\n\t\t\t// Entity link with unchanged URL - skip validation\n\t\t\tsetCustomValidity( undefined );\n\t\t\treturn true;\n\t\t}\n\n\t\t// Validate the URL using the shared validation helper\n\t\tconst validation = validateUrl( currentUrlInputValue );\n\n\t\tif ( validation.type === 'invalid' ) {\n\t\t\tsetCustomValidity( validation );\n\t\t\treturn false;\n\t\t}\n\n\t\t// Valid URL\n\t\tsetCustomValidity( undefined );\n\t\treturn true;\n\t};\n\n\t// Centralized submission function\n\tconst submitUrlValue = () => {\n\t\tif ( valueHasChanges ) {\n\t\t\t// Submit the original value with new stored values applied\n\t\t\t// on top. URL is a special case as it may also be a prop.\n\t\t\tonChange( {\n\t\t\t\t...value,\n\t\t\t\t...internalControlValue,\n\t\t\t\turl: currentUrlInputValue,\n\t\t\t} );\n\t\t}\n\t\tstopEditing();\n\t\tsetCustomValidity( undefined );\n\t};\n\n\tconst handleSubmit = () => {\n\t\t// Validate URL before submitting\n\t\tif ( ! validateAndSetValidity() ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Validation passed - proceed with submission\n\t\tsubmitUrlValue();\n\t};\n\n\tconst handleSubmitWithEnter = ( event ) => {\n\t\tconst { keyCode } = event;\n\n\t\tif (\n\t\t\tkeyCode === ENTER &&\n\t\t\t! currentInputIsEmpty // Disallow submitting empty values.\n\t\t) {\n\t\t\tevent.preventDefault();\n\t\t\thandleSubmit();\n\t\t}\n\t};\n\n\tconst resetInternalValues = () => {\n\t\tsetInternalControlValue( value );\n\t};\n\n\tconst handleCancel = ( event ) => {\n\t\tevent.preventDefault();\n\t\tevent.stopPropagation();\n\n\t\t// Ensure that any unsubmitted input changes are reset.\n\t\tresetInternalValues();\n\n\t\t// Reset validation state\n\t\tsetCustomValidity( undefined );\n\n\t\tif ( hasLinkValue ) {\n\t\t\t// If there is a link then exist editing mode and show preview.\n\t\t\tstopEditing();\n\t\t} else {\n\t\t\t// If there is no link value, then remove the link entirely.\n\t\t\tonRemove?.();\n\t\t}\n\n\t\tonCancel?.();\n\t};\n\n\tconst [ shouldFocusSearchInput, setShouldFocusSearchInput ] =\n\t\tuseState( false );\n\n\tconst handleUnlink = () => {\n\t\t// Clear the internal state to remove the ID and re-enable the field\n\t\t// Explicitly set id, kind, and type to undefined so they override\n\t\t// the original values when spread in handleSubmit. This ensures that\n\t\t// when the user types a custom URL and submits, the entity link is\n\t\t// properly severed (not just when selecting a different entity from suggestions).\n\t\tconst { id, kind, type, ...restValue } = internalControlValue;\n\t\tsetInternalControlValue( {\n\t\t\t...restValue,\n\t\t\tid: undefined,\n\t\t\tkind: undefined,\n\t\t\ttype: undefined,\n\t\t\turl: undefined,\n\t\t} );\n\n\t\t// Request focus after the component re-renders with the cleared state\n\t\t// We can't focus immediately because the input might still be disabled\n\t\tsetShouldFocusSearchInput( true );\n\t};\n\n\t// Focus the search input when requested, once the component has re-rendered\n\t// This ensures the input is enabled and ready to receive focus\n\tuseEffect( () => {\n\t\tif ( shouldFocusSearchInput ) {\n\t\t\tsearchInputRef.current?.focus();\n\t\t\tsetShouldFocusSearchInput( false );\n\t\t}\n\t}, [ shouldFocusSearchInput ] );\n\n\tconst currentUrlInputValue =\n\t\tpropInputValue || internalControlValue?.url || '';\n\n\tconst currentInputIsEmpty = ! currentUrlInputValue?.trim()?.length;\n\n\t// Reset validation state when the URL value changes\n\tuseEffect( () => {\n\t\tsetCustomValidity( undefined );\n\t}, [ currentUrlInputValue ] );\n\n\tconst isUrlValid = ! customValidity;\n\tconst shownUnlinkControl =\n\t\tonRemove && value && ! isEditingLink && ! isCreatingPage;\n\n\tconst showActions = isEditingLink && hasLinkValue;\n\n\t// Only show text control once a URL value has been committed\n\t// and it isn't just empty whitespace.\n\t// See https://github.com/WordPress/gutenberg/pull/33849/#issuecomment-932194927.\n\tconst showTextControl = hasLinkValue && hasTextControl;\n\n\tconst isEditing = ( isEditingLink || ! value ) && ! isCreatingPage;\n\t// When creating a new link (no existing value), allow submission if input is not empty and URL is valid\n\t// When editing an existing link, also require that the value has changed\n\tconst isDisabled =\n\t\tcurrentInputIsEmpty || ! isUrlValid || ( value && ! valueHasChanges );\n\tconst showSettings = !! settings?.length && isEditingLink && hasLinkValue;\n\n\tconst previewValue = useMemo( () => {\n\t\t// There is a chance that the value is not yet set from the entity binding, so we use the preserved URL.\n\t\tif (\n\t\t\tvalue?.kind === 'taxonomy' &&\n\t\t\t! value?.url &&\n\t\t\tentityUrlFallbackRef.current\n\t\t) {\n\t\t\t// combine the value prop with the preserved URL from the suggestion\n\t\t\treturn {\n\t\t\t\t...value,\n\t\t\t\turl: entityUrlFallbackRef.current,\n\t\t\t};\n\t\t}\n\n\t\t// If we don't have a fallback URL, use the value prop.\n\t\treturn value;\n\t}, [ value ] );\n\n\treturn (\n\t\t<div\n\t\t\ttabIndex={ -1 }\n\t\t\tref={ wrapperNode }\n\t\t\tclassName=\"block-editor-link-control\"\n\t\t>\n\t\t\t{ isCreatingPage && (\n\t\t\t\t<div className=\"block-editor-link-control__loading\">\n\t\t\t\t\t<Spinner /> { __( 'Creating' ) }\u2026\n\t\t\t\t</div>\n\t\t\t) }\n\n\t\t\t{ isEditing && (\n\t\t\t\t<>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={ clsx( {\n\t\t\t\t\t\t\t'block-editor-link-control__search-input-wrapper': true,\n\t\t\t\t\t\t\t'has-text-control': showTextControl,\n\t\t\t\t\t\t\t'has-actions': showActions,\n\t\t\t\t\t\t} ) }\n\t\t\t\t\t>\n\t\t\t\t\t\t{ showTextControl && (\n\t\t\t\t\t\t\t<TextControl\n\t\t\t\t\t\t\t\tref={ textInputRef }\n\t\t\t\t\t\t\t\tclassName=\"block-editor-link-control__field block-editor-link-control__text-content\"\n\t\t\t\t\t\t\t\tlabel={ __( 'Text' ) }\n\t\t\t\t\t\t\t\tvalue={ internalControlValue?.title }\n\t\t\t\t\t\t\t\tonChange={ setInternalTextInputValue }\n\t\t\t\t\t\t\t\tonKeyDown={ handleSubmitWithEnter }\n\t\t\t\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) }\n\t\t\t\t\t\t<LinkControlSearchInput\n\t\t\t\t\t\t\tref={ searchInputRef }\n\t\t\t\t\t\t\tcurrentLink={ value }\n\t\t\t\t\t\t\tclassName=\"block-editor-link-control__field block-editor-link-control__search-input\"\n\t\t\t\t\t\t\tplaceholder={ searchInputPlaceholder }\n\t\t\t\t\t\t\tvalue={ currentUrlInputValue }\n\t\t\t\t\t\t\twithCreateSuggestion={ withCreateSuggestion }\n\t\t\t\t\t\t\tonCreateSuggestion={ createPage }\n\t\t\t\t\t\t\tonChange={ setInternalURLInputValue }\n\t\t\t\t\t\t\tonSelect={ handleSelectSuggestion }\n\t\t\t\t\t\t\tshowInitialSuggestions={ showInitialSuggestions }\n\t\t\t\t\t\t\tallowDirectEntry={ ! noDirectEntry }\n\t\t\t\t\t\t\tshowSuggestions={ showSuggestions }\n\t\t\t\t\t\t\tsuggestionsQuery={ suggestionsQuery }\n\t\t\t\t\t\t\twithURLSuggestion={ ! noURLSuggestion }\n\t\t\t\t\t\t\tcreateSuggestionButtonText={\n\t\t\t\t\t\t\t\tcreateSuggestionButtonText\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\thideLabelFromVision={ ! showTextControl }\n\t\t\t\t\t\t\tisEntity={ isEntity }\n\t\t\t\t\t\t\tcustomValidity={ customValidity }\n\t\t\t\t\t\t\tsuffix={\n\t\t\t\t\t\t\t\t<SearchSuffixControl\n\t\t\t\t\t\t\t\t\tisEntity={ isEntity }\n\t\t\t\t\t\t\t\t\tshowActions={ showActions }\n\t\t\t\t\t\t\t\t\tisDisabled={ isDisabled }\n\t\t\t\t\t\t\t\t\tonUnlink={ handleUnlink }\n\t\t\t\t\t\t\t\t\tonSubmit={ handleSubmit }\n\t\t\t\t\t\t\t\t\thelpTextId={ helpTextId }\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{ isEntity && helpTextId && (\n\t\t\t\t\t\t\t<p\n\t\t\t\t\t\t\t\tid={ helpTextId }\n\t\t\t\t\t\t\t\tclassName=\"block-editor-link-control__help\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{ sprintf(\n\t\t\t\t\t\t\t\t\t/* translators: %s: entity type (e.g., page, post) */\n\t\t\t\t\t\t\t\t\t__( 'Synced with the selected %s.' ),\n\t\t\t\t\t\t\t\t\tinternalControlValue?.type || 'item'\n\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t) }\n\t\t\t\t\t</div>\n\t\t\t\t\t{ errorMessage && (\n\t\t\t\t\t\t<Notice\n\t\t\t\t\t\t\tclassName=\"block-editor-link-control__search-error\"\n\t\t\t\t\t\t\tstatus=\"error\"\n\t\t\t\t\t\t\tisDismissible={ false }\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{ errorMessage }\n\t\t\t\t\t\t</Notice>\n\t\t\t\t\t) }\n\t\t\t\t</>\n\t\t\t) }\n\n\t\t\t{ value && ! isEditingLink && ! isCreatingPage && (\n\t\t\t\t<LinkPreview\n\t\t\t\t\tkey={ previewValue?.url } // force remount when URL changes to avoid race conditions for rich previews\n\t\t\t\t\tvalue={ previewValue }\n\t\t\t\t\tonEditClick={ () => setIsEditingLink( true ) }\n\t\t\t\t\thasRichPreviews={ hasRichPreviews }\n\t\t\t\t\thasUnlinkControl={ shownUnlinkControl }\n\t\t\t\t\tonRemove={ () => {\n\t\t\t\t\t\tonRemove();\n\t\t\t\t\t\tsetIsEditingLink( true );\n\t\t\t\t\t} }\n\t\t\t\t/>\n\t\t\t) }\n\n\t\t\t{ showSettings && (\n\t\t\t\t<div className=\"block-editor-link-control__tools\">\n\t\t\t\t\t{ ! currentInputIsEmpty && (\n\t\t\t\t\t\t<LinkControlSettingsDrawer\n\t\t\t\t\t\t\tsettingsOpen={ isSettingsOpen }\n\t\t\t\t\t\t\tsetSettingsOpen={ setSettingsOpenWithPreference }\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<LinkSettings\n\t\t\t\t\t\t\t\tvalue={ internalControlValue }\n\t\t\t\t\t\t\t\tsettings={ settings }\n\t\t\t\t\t\t\t\tonChange={ createSetInternalSettingValueHandler(\n\t\t\t\t\t\t\t\t\tsettingsKeys\n\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</LinkControlSettingsDrawer>\n\t\t\t\t\t) }\n\t\t\t\t</div>\n\t\t\t) }\n\n\t\t\t{ showActions && (\n\t\t\t\t<HStack\n\t\t\t\t\tjustify=\"right\"\n\t\t\t\t\tclassName=\"block-editor-link-control__search-actions\"\n\t\t\t\t>\n\t\t\t\t\t<Button\n\t\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\tonClick={ handleCancel }\n\t\t\t\t\t>\n\t\t\t\t\t\t{ __( 'Cancel' ) }\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Button\n\t\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\tonClick={ isDisabled ? noop : handleSubmit }\n\t\t\t\t\t\tclassName=\"block-editor-link-control__search-submit\"\n\t\t\t\t\t\taria-disabled={ isDisabled }\n\t\t\t\t\t>\n\t\t\t\t\t\t{ __( 'Apply' ) }\n\t\t\t\t\t</Button>\n\t\t\t\t</HStack>\n\t\t\t) }\n\n\t\t\t{ ! isCreatingPage && renderControlBottom && renderControlBottom() }\n\t\t</div>\n\t);\n}\n\n/**\n * Suffix control component for LinkControl search input.\n * Handles the display of unlink button for entities and submit button for regular links.\n *\n * @param {Object} props - Component props\n * @param {boolean} props.isEntity - Whether the link is bound to an entity\n * @param {boolean} props.showActions - Whether to show action buttons\n * @param {boolean} props.isDisabled - Whether the submit button should be disabled\n * @param {Function} props.onUnlink - Callback when unlink button is clicked\n * @param {Function} props.onSubmit - Callback when submit button is clicked\n * @param {string} props.helpTextId - ID of the help text element for accessibility\n */\nfunction SearchSuffixControl( {\n\tisEntity,\n\tshowActions,\n\tisDisabled,\n\tonUnlink,\n\tonSubmit,\n\thelpTextId,\n} ) {\n\tif ( isEntity ) {\n\t\treturn (\n\t\t\t<Button\n\t\t\t\ticon={ linkOff }\n\t\t\t\tonClick={ onUnlink }\n\t\t\t\taria-describedby={ helpTextId }\n\t\t\t\tshowTooltip\n\t\t\t\tlabel={ __( 'Unsync and edit' ) }\n\t\t\t\t__next40pxDefaultSize\n\t\t\t/>\n\t\t);\n\t}\n\n\tif ( showActions ) {\n\t\treturn undefined;\n\t}\n\n\treturn (\n\t\t<InputControlSuffixWrapper variant=\"control\">\n\t\t\t<Button\n\t\t\t\tonClick={ isDisabled ? noop : onSubmit }\n\t\t\t\tlabel={ __( 'Submit' ) }\n\t\t\t\ticon={ keyboardReturn }\n\t\t\t\tclassName=\"block-editor-link-control__search-submit\"\n\t\t\t\taria-disabled={ isDisabled }\n\t\t\t\tsize=\"small\"\n\t\t\t/>\n\t\t</InputControlSuffixWrapper>\n\t);\n}\n\nLinkControl.ViewerFill = ViewerFill;\nLinkControl.DEFAULT_LINK_SETTINGS = DEFAULT_LINK_SETTINGS;\n\nconst DeprecatedExperimentalLinkControl = ( props ) => {\n\tdeprecated( 'wp.blockEditor.__experimentalLinkControl', {\n\t\tsince: '6.8',\n\t\talternative: 'wp.blockEditor.LinkControl',\n\t} );\n\n\treturn <LinkControl { ...props } />;\n};\n\nDeprecatedExperimentalLinkControl.ViewerFill = LinkControl.ViewerFill;\nDeprecatedExperimentalLinkControl.DEFAULT_LINK_SETTINGS =\n\tLinkControl.DEFAULT_LINK_SETTINGS;\n\nexport { DeprecatedExperimentalLinkControl };\nexport default LinkControl;\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,5 +1,11 @@
1
1
  // packages/block-editor/src/components/link-control/is-url-like.js
2
2
  import { getProtocol, isValidProtocol, isValidFragment } from "@wordpress/url";
3
+ function isHashLink(val) {
4
+ return val?.startsWith("#") && isValidFragment(val);
5
+ }
6
+ function isRelativePath(val) {
7
+ return val?.startsWith("/") || val?.startsWith("./") || val?.startsWith("../");
8
+ }
3
9
  function isURLLike(val) {
4
10
  const hasSpaces = val.includes(" ");
5
11
  if (hasSpaces) {
@@ -9,8 +15,7 @@ function isURLLike(val) {
9
15
  const protocolIsValid = isValidProtocol(protocol);
10
16
  const mayBeTLD = hasPossibleTLD(val);
11
17
  const isWWW = val?.startsWith("www.");
12
- const isInternal = val?.startsWith("#") && isValidFragment(val);
13
- return protocolIsValid || isWWW || isInternal || mayBeTLD;
18
+ return protocolIsValid || isWWW || isHashLink(val) || mayBeTLD || isRelativePath(val);
14
19
  }
15
20
  function hasPossibleTLD(url, maxLength = 6) {
16
21
  const cleanedURL = url.split(/[?#]/)[0];
@@ -20,6 +25,8 @@ function hasPossibleTLD(url, maxLength = 6) {
20
25
  return regex.test(cleanedURL);
21
26
  }
22
27
  export {
23
- isURLLike as default
28
+ isURLLike as default,
29
+ isHashLink,
30
+ isRelativePath
24
31
  };
25
32
  //# sourceMappingURL=is-url-like.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/link-control/is-url-like.js"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { getProtocol, isValidProtocol, isValidFragment } from '@wordpress/url';\n\n/**\n * Determines whether a given value could be a URL. Note this does not\n * guarantee the value is a URL only that it looks like it might be one. For\n * example, just because a string has `www.` in it doesn't make it a URL,\n * but it does make it highly likely that it will be so in the context of\n * creating a link it makes sense to treat it like one.\n *\n * @param {string} val the candidate for being URL-like (or not).\n *\n * @return {boolean} whether or not the value is potentially a URL.\n */\nexport default function isURLLike( val ) {\n\tconst hasSpaces = val.includes( ' ' );\n\n\tif ( hasSpaces ) {\n\t\treturn false;\n\t}\n\n\tconst protocol = getProtocol( val );\n\tconst protocolIsValid = isValidProtocol( protocol );\n\n\tconst mayBeTLD = hasPossibleTLD( val );\n\n\tconst isWWW = val?.startsWith( 'www.' );\n\n\tconst isInternal = val?.startsWith( '#' ) && isValidFragment( val );\n\n\treturn protocolIsValid || isWWW || isInternal || mayBeTLD;\n}\n\n/**\n * Checks if a given URL has a valid Top-Level Domain (TLD).\n *\n * @param {string} url - The URL to check.\n * @param {number} maxLength - The maximum length of the TLD.\n * @return {boolean} Returns true if the URL has a valid TLD, false otherwise.\n */\nfunction hasPossibleTLD( url, maxLength = 6 ) {\n\t// Clean the URL by removing anything after the first occurrence of \"?\" or \"#\".\n\tconst cleanedURL = url.split( /[?#]/ )[ 0 ];\n\n\t// Regular expression explanation:\n\t// - (?<=\\S) : Positive lookbehind assertion to ensure there is at least one non-whitespace character before the TLD\n\t// - \\. : Matches a literal dot (.)\n\t// - [a-zA-Z_]{2,maxLength} : Matches 2 to maxLength letters or underscores, representing the TLD\n\t// - (?:\\/|$) : Non-capturing group that matches either a forward slash (/) or the end of the string\n\tconst regex = new RegExp(\n\t\t`(?<=\\\\S)\\\\.(?:[a-zA-Z_]{2,${ maxLength }})(?:\\\\/|$)`\n\t);\n\n\treturn regex.test( cleanedURL );\n}\n"],
5
- "mappings": ";AAGA,SAAS,aAAa,iBAAiB,uBAAuB;AAa/C,SAAR,UAA4B,KAAM;AACxC,QAAM,YAAY,IAAI,SAAU,GAAI;AAEpC,MAAK,WAAY;AAChB,WAAO;AAAA,EACR;AAEA,QAAM,WAAW,YAAa,GAAI;AAClC,QAAM,kBAAkB,gBAAiB,QAAS;AAElD,QAAM,WAAW,eAAgB,GAAI;AAErC,QAAM,QAAQ,KAAK,WAAY,MAAO;AAEtC,QAAM,aAAa,KAAK,WAAY,GAAI,KAAK,gBAAiB,GAAI;AAElE,SAAO,mBAAmB,SAAS,cAAc;AAClD;AASA,SAAS,eAAgB,KAAK,YAAY,GAAI;AAE7C,QAAM,aAAa,IAAI,MAAO,MAAO,EAAG,CAAE;AAO1C,QAAM,QAAQ,IAAI;AAAA,IACjB,6BAA8B,SAAU;AAAA,EACzC;AAEA,SAAO,MAAM,KAAM,UAAW;AAC/B;",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { getProtocol, isValidProtocol, isValidFragment } from '@wordpress/url';\n\n/**\n * Checks if a value is a hash/anchor link (e.g., #section).\n *\n * @param {string} val The value to check.\n * @return {boolean} True if the value is a valid hash link.\n */\nexport function isHashLink( val ) {\n\treturn val?.startsWith( '#' ) && isValidFragment( val );\n}\n\n/**\n * Checks if a value is a relative path (e.g., /page, ./page, ../page).\n *\n * @param {string} val The value to check.\n * @return {boolean} True if the value is a relative path.\n */\nexport function isRelativePath( val ) {\n\treturn (\n\t\tval?.startsWith( '/' ) ||\n\t\tval?.startsWith( './' ) ||\n\t\tval?.startsWith( '../' )\n\t);\n}\n\n/**\n * Determines whether a given value could be a URL or valid href value (like\n * relative paths or hash links). Note this does not guarantee the value is a\n * URL only that it looks like something that should be treated as direct entry\n * rather than a search term. For example, just because a string has `www.` in\n * it doesn't make it a URL, but it does make it highly likely that it will be\n * so in the context of creating a link it makes sense to treat it like one.\n *\n * Examples of \"URL-like\" values:\n * - URLs with protocols: `https://wordpress.org`, `mailto:test@example.com`\n * - Domain-like strings: `www.wordpress.org`, `wordpress.org`\n * - Relative paths: `/handbook`, `./page`, `../parent`\n * - Hash links: `#section`\n *\n * @param {string} val the candidate for being URL-like (or not).\n *\n * @return {boolean} whether or not the value is potentially a URL.\n */\nexport default function isURLLike( val ) {\n\tconst hasSpaces = val.includes( ' ' );\n\n\tif ( hasSpaces ) {\n\t\treturn false;\n\t}\n\n\tconst protocol = getProtocol( val );\n\tconst protocolIsValid = isValidProtocol( protocol );\n\n\tconst mayBeTLD = hasPossibleTLD( val );\n\n\tconst isWWW = val?.startsWith( 'www.' );\n\n\treturn (\n\t\tprotocolIsValid ||\n\t\tisWWW ||\n\t\tisHashLink( val ) ||\n\t\tmayBeTLD ||\n\t\tisRelativePath( val )\n\t);\n}\n\n/**\n * Checks if a given URL has a valid Top-Level Domain (TLD).\n *\n * @param {string} url - The URL to check.\n * @param {number} maxLength - The maximum length of the TLD.\n * @return {boolean} Returns true if the URL has a valid TLD, false otherwise.\n */\nfunction hasPossibleTLD( url, maxLength = 6 ) {\n\t// Clean the URL by removing anything after the first occurrence of \"?\" or \"#\".\n\tconst cleanedURL = url.split( /[?#]/ )[ 0 ];\n\n\t// Regular expression explanation:\n\t// - (?<=\\S) : Positive lookbehind assertion to ensure there is at least one non-whitespace character before the TLD\n\t// - \\. : Matches a literal dot (.)\n\t// - [a-zA-Z_]{2,maxLength} : Matches 2 to maxLength letters or underscores, representing the TLD\n\t// - (?:\\/|$) : Non-capturing group that matches either a forward slash (/) or the end of the string\n\tconst regex = new RegExp(\n\t\t`(?<=\\\\S)\\\\.(?:[a-zA-Z_]{2,${ maxLength }})(?:\\\\/|$)`\n\t);\n\n\treturn regex.test( cleanedURL );\n}\n"],
5
+ "mappings": ";AAGA,SAAS,aAAa,iBAAiB,uBAAuB;AAQvD,SAAS,WAAY,KAAM;AACjC,SAAO,KAAK,WAAY,GAAI,KAAK,gBAAiB,GAAI;AACvD;AAQO,SAAS,eAAgB,KAAM;AACrC,SACC,KAAK,WAAY,GAAI,KACrB,KAAK,WAAY,IAAK,KACtB,KAAK,WAAY,KAAM;AAEzB;AAoBe,SAAR,UAA4B,KAAM;AACxC,QAAM,YAAY,IAAI,SAAU,GAAI;AAEpC,MAAK,WAAY;AAChB,WAAO;AAAA,EACR;AAEA,QAAM,WAAW,YAAa,GAAI;AAClC,QAAM,kBAAkB,gBAAiB,QAAS;AAElD,QAAM,WAAW,eAAgB,GAAI;AAErC,QAAM,QAAQ,KAAK,WAAY,MAAO;AAEtC,SACC,mBACA,SACA,WAAY,GAAI,KAChB,YACA,eAAgB,GAAI;AAEtB;AASA,SAAS,eAAgB,KAAK,YAAY,GAAI;AAE7C,QAAM,aAAa,IAAI,MAAO,MAAO,EAAG,CAAE;AAO1C,QAAM,QAAQ,IAAI;AAAA,IACjB,6BAA8B,SAAU;AAAA,EACzC;AAEA,SAAO,MAAM,KAAM,UAAW;AAC/B;",
6
6
  "names": []
7
7
  }
@@ -31,7 +31,8 @@ var LinkControlSearchInput = forwardRef(
31
31
  createSuggestionButtonText,
32
32
  hideLabelFromVision = false,
33
33
  suffix,
34
- isEntity = false
34
+ isEntity = false,
35
+ customValidity: customValidityProp
35
36
  }, ref) => {
36
37
  const genericSearchHandler = useSearchHandler(
37
38
  suggestionsQuery,
@@ -97,6 +98,8 @@ var LinkControlSearchInput = forwardRef(
97
98
  __experimentalFetchLinkSuggestions: searchHandler,
98
99
  __experimentalHandleURLSuggestions: true,
99
100
  __experimentalShowInitialSuggestions: showInitialSuggestions,
101
+ customValidity: customValidityProp,
102
+ markWhenOptional: true,
100
103
  onSubmit: (suggestion, event) => {
101
104
  const hasSuggestion = suggestion || focusedSuggestion;
102
105
  if (!hasSuggestion && !value?.trim()?.length) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/link-control/search-input.js"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { forwardRef, useState } from '@wordpress/element';\nimport { __ } from '@wordpress/i18n';\nimport deprecated from '@wordpress/deprecated';\n\n/**\n * Internal dependencies\n */\nimport { URLInput } from '../';\nimport LinkControlSearchResults from './search-results';\nimport { CREATE_TYPE } from './constants';\nimport useSearchHandler from './use-search-handler';\n\n// Must be a function as otherwise URLInput will default\n// to the fetchLinkSuggestions passed in block editor settings\n// which will cause an unintended http request.\nconst noopSearchHandler = () => Promise.resolve( [] );\n\nconst noop = () => {};\n\nconst LinkControlSearchInput = forwardRef(\n\t(\n\t\t{\n\t\t\tvalue,\n\t\t\tchildren,\n\t\t\tcurrentLink = {},\n\t\t\tclassName = null,\n\t\t\tplaceholder = null,\n\t\t\twithCreateSuggestion = false,\n\t\t\tonCreateSuggestion = noop,\n\t\t\tonChange = noop,\n\t\t\tonSelect = noop,\n\t\t\tshowSuggestions = true,\n\t\t\trenderSuggestions = ( props ) => (\n\t\t\t\t<LinkControlSearchResults { ...props } />\n\t\t\t),\n\t\t\tfetchSuggestions = null,\n\t\t\tallowDirectEntry = true,\n\t\t\tshowInitialSuggestions = false,\n\t\t\tsuggestionsQuery = {},\n\t\t\twithURLSuggestion = true,\n\t\t\tcreateSuggestionButtonText,\n\t\t\thideLabelFromVision = false,\n\t\t\tsuffix,\n\t\t\tisEntity = false,\n\t\t},\n\t\tref\n\t) => {\n\t\tconst genericSearchHandler = useSearchHandler(\n\t\t\tsuggestionsQuery,\n\t\t\tallowDirectEntry,\n\t\t\twithCreateSuggestion,\n\t\t\twithURLSuggestion\n\t\t);\n\n\t\tconst searchHandler = showSuggestions\n\t\t\t? fetchSuggestions || genericSearchHandler\n\t\t\t: noopSearchHandler;\n\n\t\tconst [ focusedSuggestion, setFocusedSuggestion ] = useState();\n\n\t\t/**\n\t\t * Handles the user moving between different suggestions. Does not handle\n\t\t * choosing an individual item.\n\t\t *\n\t\t * @param {string} selection the url of the selected suggestion.\n\t\t * @param {Object} suggestion the suggestion object.\n\t\t */\n\t\tconst onInputChange = ( selection, suggestion ) => {\n\t\t\tonChange( selection );\n\t\t\tsetFocusedSuggestion( suggestion );\n\t\t};\n\n\t\tconst handleRenderSuggestions = ( props ) =>\n\t\t\trenderSuggestions( {\n\t\t\t\t...props,\n\t\t\t\twithCreateSuggestion,\n\t\t\t\tcreateSuggestionButtonText,\n\t\t\t\tsuggestionsQuery,\n\t\t\t\thandleSuggestionClick: ( suggestion ) => {\n\t\t\t\t\tif ( props.handleSuggestionClick ) {\n\t\t\t\t\t\tprops.handleSuggestionClick( suggestion );\n\t\t\t\t\t}\n\t\t\t\t\tonSuggestionSelected( suggestion );\n\t\t\t\t},\n\t\t\t} );\n\n\t\tconst onSuggestionSelected = async ( selectedSuggestion ) => {\n\t\t\tlet suggestion = selectedSuggestion;\n\t\t\tif ( CREATE_TYPE === selectedSuggestion.type ) {\n\t\t\t\t// Create a new page and call onSelect with the output from the onCreateSuggestion callback.\n\t\t\t\ttry {\n\t\t\t\t\tsuggestion = await onCreateSuggestion(\n\t\t\t\t\t\tselectedSuggestion.title\n\t\t\t\t\t);\n\t\t\t\t\tif ( suggestion?.url ) {\n\t\t\t\t\t\tonSelect( suggestion );\n\t\t\t\t\t}\n\t\t\t\t} catch ( e ) {}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tallowDirectEntry ||\n\t\t\t\t( suggestion && Object.keys( suggestion ).length >= 1 )\n\t\t\t) {\n\t\t\t\t// Strip out id, url, kind, and type from the current link to prevent\n\t\t\t\t// entity metadata from persisting when switching to a different link type.\n\t\t\t\t// For example, when changing from an entity link (kind: 'post-type', type: 'page')\n\t\t\t\t// to a custom URL (type: 'link', no kind), we need to ensure the old 'kind'\n\t\t\t\t// doesn't carry over. We do want to preserve other properites like title, though.\n\t\t\t\tconst { id, url, kind, type, ...restLinkProps } =\n\t\t\t\t\tcurrentLink ?? {};\n\t\t\t\tonSelect(\n\t\t\t\t\t// Some direct entries don't have types or IDs, and we still need to clear the previous ones.\n\t\t\t\t\t{ ...restLinkProps, ...suggestion },\n\t\t\t\t\tsuggestion\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\n\t\tconst _placeholder = placeholder ?? __( 'Search or type URL' );\n\n\t\tconst label =\n\t\t\thideLabelFromVision && placeholder !== ''\n\t\t\t\t? _placeholder\n\t\t\t\t: __( 'Link' );\n\n\t\treturn (\n\t\t\t<div className=\"block-editor-link-control__search-input-container\">\n\t\t\t\t<URLInput\n\t\t\t\t\tdisableSuggestions={ currentLink?.url === value }\n\t\t\t\t\tlabel={ label }\n\t\t\t\t\thideLabelFromVision={ hideLabelFromVision }\n\t\t\t\t\tclassName={ className }\n\t\t\t\t\tvalue={ value }\n\t\t\t\t\tonChange={ onInputChange }\n\t\t\t\t\tplaceholder={ _placeholder }\n\t\t\t\t\t__experimentalRenderSuggestions={\n\t\t\t\t\t\tshowSuggestions ? handleRenderSuggestions : null\n\t\t\t\t\t}\n\t\t\t\t\t__experimentalFetchLinkSuggestions={ searchHandler }\n\t\t\t\t\t__experimentalHandleURLSuggestions\n\t\t\t\t\t__experimentalShowInitialSuggestions={\n\t\t\t\t\t\tshowInitialSuggestions\n\t\t\t\t\t}\n\t\t\t\t\tonSubmit={ ( suggestion, event ) => {\n\t\t\t\t\t\tconst hasSuggestion = suggestion || focusedSuggestion;\n\n\t\t\t\t\t\t// If there is no suggestion and the value (ie: any manually entered URL) is empty\n\t\t\t\t\t\t// then don't allow submission otherwise we get empty links.\n\t\t\t\t\t\tif ( ! hasSuggestion && ! value?.trim()?.length ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tonSuggestionSelected(\n\t\t\t\t\t\t\t\thasSuggestion || { url: value }\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t} }\n\t\t\t\t\tinputRef={ ref }\n\t\t\t\t\tsuffix={ suffix }\n\t\t\t\t\tdisabled={ isEntity }\n\t\t\t\t/>\n\t\t\t\t{ children }\n\t\t\t</div>\n\t\t);\n\t}\n);\n\nexport default LinkControlSearchInput;\n\nexport const __experimentalLinkControlSearchInput = ( props ) => {\n\tdeprecated( 'wp.blockEditor.__experimentalLinkControlSearchInput', {\n\t\tsince: '6.8',\n\t} );\n\n\treturn <LinkControlSearchInput { ...props } />;\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { forwardRef, useState } from '@wordpress/element';\nimport { __ } from '@wordpress/i18n';\nimport deprecated from '@wordpress/deprecated';\n\n/**\n * Internal dependencies\n */\nimport { URLInput } from '../';\nimport LinkControlSearchResults from './search-results';\nimport { CREATE_TYPE } from './constants';\nimport useSearchHandler from './use-search-handler';\n\n// Must be a function as otherwise URLInput will default\n// to the fetchLinkSuggestions passed in block editor settings\n// which will cause an unintended http request.\nconst noopSearchHandler = () => Promise.resolve( [] );\n\nconst noop = () => {};\n\nconst LinkControlSearchInput = forwardRef(\n\t(\n\t\t{\n\t\t\tvalue,\n\t\t\tchildren,\n\t\t\tcurrentLink = {},\n\t\t\tclassName = null,\n\t\t\tplaceholder = null,\n\t\t\twithCreateSuggestion = false,\n\t\t\tonCreateSuggestion = noop,\n\t\t\tonChange = noop,\n\t\t\tonSelect = noop,\n\t\t\tshowSuggestions = true,\n\t\t\trenderSuggestions = ( props ) => (\n\t\t\t\t<LinkControlSearchResults { ...props } />\n\t\t\t),\n\t\t\tfetchSuggestions = null,\n\t\t\tallowDirectEntry = true,\n\t\t\tshowInitialSuggestions = false,\n\t\t\tsuggestionsQuery = {},\n\t\t\twithURLSuggestion = true,\n\t\t\tcreateSuggestionButtonText,\n\t\t\thideLabelFromVision = false,\n\t\t\tsuffix,\n\t\t\tisEntity = false,\n\t\t\tcustomValidity: customValidityProp,\n\t\t},\n\t\tref\n\t) => {\n\t\tconst genericSearchHandler = useSearchHandler(\n\t\t\tsuggestionsQuery,\n\t\t\tallowDirectEntry,\n\t\t\twithCreateSuggestion,\n\t\t\twithURLSuggestion\n\t\t);\n\n\t\tconst searchHandler = showSuggestions\n\t\t\t? fetchSuggestions || genericSearchHandler\n\t\t\t: noopSearchHandler;\n\n\t\tconst [ focusedSuggestion, setFocusedSuggestion ] = useState();\n\n\t\t/**\n\t\t * Handles the user moving between different suggestions. Does not handle\n\t\t * choosing an individual item.\n\t\t *\n\t\t * @param {string} selection the url of the selected suggestion.\n\t\t * @param {Object} suggestion the suggestion object.\n\t\t */\n\t\tconst onInputChange = ( selection, suggestion ) => {\n\t\t\tonChange( selection );\n\t\t\tsetFocusedSuggestion( suggestion );\n\t\t};\n\n\t\tconst handleRenderSuggestions = ( props ) =>\n\t\t\trenderSuggestions( {\n\t\t\t\t...props,\n\t\t\t\twithCreateSuggestion,\n\t\t\t\tcreateSuggestionButtonText,\n\t\t\t\tsuggestionsQuery,\n\t\t\t\thandleSuggestionClick: ( suggestion ) => {\n\t\t\t\t\tif ( props.handleSuggestionClick ) {\n\t\t\t\t\t\tprops.handleSuggestionClick( suggestion );\n\t\t\t\t\t}\n\t\t\t\t\tonSuggestionSelected( suggestion );\n\t\t\t\t},\n\t\t\t} );\n\n\t\tconst onSuggestionSelected = async ( selectedSuggestion ) => {\n\t\t\tlet suggestion = selectedSuggestion;\n\t\t\tif ( CREATE_TYPE === selectedSuggestion.type ) {\n\t\t\t\t// Create a new page and call onSelect with the output from the onCreateSuggestion callback.\n\t\t\t\ttry {\n\t\t\t\t\tsuggestion = await onCreateSuggestion(\n\t\t\t\t\t\tselectedSuggestion.title\n\t\t\t\t\t);\n\t\t\t\t\tif ( suggestion?.url ) {\n\t\t\t\t\t\tonSelect( suggestion );\n\t\t\t\t\t}\n\t\t\t\t} catch ( e ) {}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tallowDirectEntry ||\n\t\t\t\t( suggestion && Object.keys( suggestion ).length >= 1 )\n\t\t\t) {\n\t\t\t\t// Strip out id, url, kind, and type from the current link to prevent\n\t\t\t\t// entity metadata from persisting when switching to a different link type.\n\t\t\t\t// For example, when changing from an entity link (kind: 'post-type', type: 'page')\n\t\t\t\t// to a custom URL (type: 'link', no kind), we need to ensure the old 'kind'\n\t\t\t\t// doesn't carry over. We do want to preserve other properites like title, though.\n\t\t\t\tconst { id, url, kind, type, ...restLinkProps } =\n\t\t\t\t\tcurrentLink ?? {};\n\t\t\t\tonSelect(\n\t\t\t\t\t// Some direct entries don't have types or IDs, and we still need to clear the previous ones.\n\t\t\t\t\t{ ...restLinkProps, ...suggestion },\n\t\t\t\t\tsuggestion\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\n\t\tconst _placeholder = placeholder ?? __( 'Search or type URL' );\n\n\t\tconst label =\n\t\t\thideLabelFromVision && placeholder !== ''\n\t\t\t\t? _placeholder\n\t\t\t\t: __( 'Link' );\n\n\t\treturn (\n\t\t\t<div className=\"block-editor-link-control__search-input-container\">\n\t\t\t\t<URLInput\n\t\t\t\t\tdisableSuggestions={ currentLink?.url === value }\n\t\t\t\t\tlabel={ label }\n\t\t\t\t\thideLabelFromVision={ hideLabelFromVision }\n\t\t\t\t\tclassName={ className }\n\t\t\t\t\tvalue={ value }\n\t\t\t\t\tonChange={ onInputChange }\n\t\t\t\t\tplaceholder={ _placeholder }\n\t\t\t\t\t__experimentalRenderSuggestions={\n\t\t\t\t\t\tshowSuggestions ? handleRenderSuggestions : null\n\t\t\t\t\t}\n\t\t\t\t\t__experimentalFetchLinkSuggestions={ searchHandler }\n\t\t\t\t\t__experimentalHandleURLSuggestions\n\t\t\t\t\t__experimentalShowInitialSuggestions={\n\t\t\t\t\t\tshowInitialSuggestions\n\t\t\t\t\t}\n\t\t\t\t\tcustomValidity={ customValidityProp }\n\t\t\t\t\t// Suppress the \"(Required)\" indicator that appears when validation\n\t\t\t\t\t// is triggered. The field is still required for validation purposes,\n\t\t\t\t\t// but we don't want to show the indicator as it looks cluttered\n\t\t\t\t\t// in the link control UI.\n\t\t\t\t\tmarkWhenOptional\n\t\t\t\t\tonSubmit={ ( suggestion, event ) => {\n\t\t\t\t\t\tconst hasSuggestion = suggestion || focusedSuggestion;\n\n\t\t\t\t\t\t// If there is no suggestion and the value (ie: any manually entered URL) is empty\n\t\t\t\t\t\t// then don't allow submission otherwise we get empty links.\n\t\t\t\t\t\tif ( ! hasSuggestion && ! value?.trim()?.length ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tonSuggestionSelected(\n\t\t\t\t\t\t\t\thasSuggestion || { url: value }\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t} }\n\t\t\t\t\tinputRef={ ref }\n\t\t\t\t\tsuffix={ suffix }\n\t\t\t\t\tdisabled={ isEntity }\n\t\t\t\t/>\n\t\t\t\t{ children }\n\t\t\t</div>\n\t\t);\n\t}\n);\n\nexport default LinkControlSearchInput;\n\nexport const __experimentalLinkControlSearchInput = ( props ) => {\n\tdeprecated( 'wp.blockEditor.__experimentalLinkControlSearchInput', {\n\t\tsince: '6.8',\n\t} );\n\n\treturn <LinkControlSearchInput { ...props } />;\n};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,5 +1,5 @@
1
1
  // packages/block-editor/src/components/link-control/use-search-handler.js
2
- import { getProtocol, prependHTTP } from "@wordpress/url";
2
+ import { getProtocol, prependHTTPS } from "@wordpress/url";
3
3
  import { useCallback } from "@wordpress/element";
4
4
  import { useSelect } from "@wordpress/data";
5
5
  import isURLLike from "./is-url-like.mjs";
@@ -28,7 +28,7 @@ var handleDirectEntry = (val) => {
28
28
  {
29
29
  id: val,
30
30
  title: val,
31
- url: type === "URL" ? prependHTTP(val) : val,
31
+ url: type === "URL" ? prependHTTPS(val) : val,
32
32
  type
33
33
  }
34
34
  ]);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/link-control/use-search-handler.js"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { getProtocol, prependHTTP } from '@wordpress/url';\nimport { useCallback } from '@wordpress/element';\nimport { useSelect } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport isURLLike from './is-url-like';\nimport {\n\tCREATE_TYPE,\n\tTEL_TYPE,\n\tMAILTO_TYPE,\n\tINTERNAL_TYPE,\n\tURL_TYPE,\n} from './constants';\nimport { store as blockEditorStore } from '../../store';\n\nexport const handleNoop = () => Promise.resolve( [] );\n\nexport const handleDirectEntry = ( val ) => {\n\tlet type = URL_TYPE;\n\n\tconst protocol = getProtocol( val ) || '';\n\n\tif ( protocol.includes( 'mailto' ) ) {\n\t\ttype = MAILTO_TYPE;\n\t}\n\n\tif ( protocol.includes( 'tel' ) ) {\n\t\ttype = TEL_TYPE;\n\t}\n\n\tif ( val?.startsWith( '#' ) ) {\n\t\ttype = INTERNAL_TYPE;\n\t}\n\n\treturn Promise.resolve( [\n\t\t{\n\t\t\tid: val,\n\t\t\ttitle: val,\n\t\t\turl: type === 'URL' ? prependHTTP( val ) : val,\n\t\t\ttype,\n\t\t},\n\t] );\n};\n\nconst handleEntitySearch = async (\n\tval,\n\tsuggestionsQuery,\n\tfetchSearchSuggestions,\n\twithCreateSuggestion,\n\tpageOnFront,\n\tpageForPosts\n) => {\n\tconst { isInitialSuggestions } = suggestionsQuery;\n\n\tconst results = await fetchSearchSuggestions( val, suggestionsQuery );\n\n\t// Identify front page and update type to match.\n\tresults.map( ( result ) => {\n\t\tif ( Number( result.id ) === pageOnFront ) {\n\t\t\tresult.isFrontPage = true;\n\t\t\treturn result;\n\t\t} else if ( Number( result.id ) === pageForPosts ) {\n\t\t\tresult.isBlogHome = true;\n\t\t\treturn result;\n\t\t}\n\n\t\treturn result;\n\t} );\n\n\t// If displaying initial suggestions just return plain results.\n\tif ( isInitialSuggestions ) {\n\t\treturn results;\n\t}\n\n\t// Here we append a faux suggestion to represent a \"CREATE\" option. This\n\t// is detected in the rendering of the search results and handled as a\n\t// special case. This is currently necessary because the suggestions\n\t// dropdown will only appear if there are valid suggestions and\n\t// therefore unless the create option is a suggestion it will not\n\t// display in scenarios where there are no results returned from the\n\t// API. In addition promoting CREATE to a first class suggestion affords\n\t// the a11y benefits afforded by `URLInput` to all suggestions (eg:\n\t// keyboard handling, ARIA roles...etc).\n\t//\n\t// Note also that the value of the `title` and `url` properties must correspond\n\t// to the text value of the `<input>`. This is because `title` is used\n\t// when creating the suggestion. Similarly `url` is used when using keyboard to select\n\t// the suggestion (the <form> `onSubmit` handler falls-back to `url`).\n\treturn isURLLike( val ) || ! withCreateSuggestion\n\t\t? results\n\t\t: results.concat( {\n\t\t\t\t// the `id` prop is intentionally omitted here because it\n\t\t\t\t// is never exposed as part of the component's public API.\n\t\t\t\t// see: https://github.com/WordPress/gutenberg/pull/19775#discussion_r378931316.\n\t\t\t\ttitle: val, // Must match the existing `<input>`s text value.\n\t\t\t\turl: val, // Must match the existing `<input>`s text value.\n\t\t\t\ttype: CREATE_TYPE,\n\t\t } );\n};\n\nexport default function useSearchHandler(\n\tsuggestionsQuery,\n\tallowDirectEntry,\n\twithCreateSuggestion\n) {\n\tconst { fetchSearchSuggestions, pageOnFront, pageForPosts } = useSelect(\n\t\t( select ) => {\n\t\t\tconst { getSettings } = select( blockEditorStore );\n\n\t\t\treturn {\n\t\t\t\tpageOnFront: getSettings().pageOnFront,\n\t\t\t\tpageForPosts: getSettings().pageForPosts,\n\t\t\t\tfetchSearchSuggestions:\n\t\t\t\t\tgetSettings().__experimentalFetchLinkSuggestions,\n\t\t\t};\n\t\t},\n\t\t[]\n\t);\n\n\tconst directEntryHandler = allowDirectEntry\n\t\t? handleDirectEntry\n\t\t: handleNoop;\n\n\treturn useCallback(\n\t\t( val, { isInitialSuggestions } ) => {\n\t\t\treturn isURLLike( val )\n\t\t\t\t? directEntryHandler( val, { isInitialSuggestions } )\n\t\t\t\t: handleEntitySearch(\n\t\t\t\t\t\tval,\n\t\t\t\t\t\t{ ...suggestionsQuery, isInitialSuggestions },\n\t\t\t\t\t\tfetchSearchSuggestions,\n\t\t\t\t\t\twithCreateSuggestion,\n\t\t\t\t\t\tpageOnFront,\n\t\t\t\t\t\tpageForPosts\n\t\t\t\t );\n\t\t},\n\t\t[\n\t\t\tdirectEntryHandler,\n\t\t\tfetchSearchSuggestions,\n\t\t\tpageOnFront,\n\t\t\tpageForPosts,\n\t\t\tsuggestionsQuery,\n\t\t\twithCreateSuggestion,\n\t\t]\n\t);\n}\n"],
5
- "mappings": ";AAGA,SAAS,aAAa,mBAAmB;AACzC,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAK1B,OAAO,eAAe;AACtB;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,SAAS,wBAAwB;AAEnC,IAAM,aAAa,MAAM,QAAQ,QAAS,CAAC,CAAE;AAE7C,IAAM,oBAAoB,CAAE,QAAS;AAC3C,MAAI,OAAO;AAEX,QAAM,WAAW,YAAa,GAAI,KAAK;AAEvC,MAAK,SAAS,SAAU,QAAS,GAAI;AACpC,WAAO;AAAA,EACR;AAEA,MAAK,SAAS,SAAU,KAAM,GAAI;AACjC,WAAO;AAAA,EACR;AAEA,MAAK,KAAK,WAAY,GAAI,GAAI;AAC7B,WAAO;AAAA,EACR;AAEA,SAAO,QAAQ,QAAS;AAAA,IACvB;AAAA,MACC,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,KAAK,SAAS,QAAQ,YAAa,GAAI,IAAI;AAAA,MAC3C;AAAA,IACD;AAAA,EACD,CAAE;AACH;AAEA,IAAM,qBAAqB,OAC1B,KACA,kBACA,wBACA,sBACA,aACA,iBACI;AACJ,QAAM,EAAE,qBAAqB,IAAI;AAEjC,QAAM,UAAU,MAAM,uBAAwB,KAAK,gBAAiB;AAGpE,UAAQ,IAAK,CAAE,WAAY;AAC1B,QAAK,OAAQ,OAAO,EAAG,MAAM,aAAc;AAC1C,aAAO,cAAc;AACrB,aAAO;AAAA,IACR,WAAY,OAAQ,OAAO,EAAG,MAAM,cAAe;AAClD,aAAO,aAAa;AACpB,aAAO;AAAA,IACR;AAEA,WAAO;AAAA,EACR,CAAE;AAGF,MAAK,sBAAuB;AAC3B,WAAO;AAAA,EACR;AAgBA,SAAO,UAAW,GAAI,KAAK,CAAE,uBAC1B,UACA,QAAQ,OAAQ;AAAA;AAAA;AAAA;AAAA,IAIhB,OAAO;AAAA;AAAA,IACP,KAAK;AAAA;AAAA,IACL,MAAM;AAAA,EACN,CAAE;AACN;AAEe,SAAR,iBACN,kBACA,kBACA,sBACC;AACD,QAAM,EAAE,wBAAwB,aAAa,aAAa,IAAI;AAAA,IAC7D,CAAE,WAAY;AACb,YAAM,EAAE,YAAY,IAAI,OAAQ,gBAAiB;AAEjD,aAAO;AAAA,QACN,aAAa,YAAY,EAAE;AAAA,QAC3B,cAAc,YAAY,EAAE;AAAA,QAC5B,wBACC,YAAY,EAAE;AAAA,MAChB;AAAA,IACD;AAAA,IACA,CAAC;AAAA,EACF;AAEA,QAAM,qBAAqB,mBACxB,oBACA;AAEH,SAAO;AAAA,IACN,CAAE,KAAK,EAAE,qBAAqB,MAAO;AACpC,aAAO,UAAW,GAAI,IACnB,mBAAoB,KAAK,EAAE,qBAAqB,CAAE,IAClD;AAAA,QACA;AAAA,QACA,EAAE,GAAG,kBAAkB,qBAAqB;AAAA,QAC5C;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACA;AAAA,IACJ;AAAA,IACA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AACD;",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { getProtocol, prependHTTPS } from '@wordpress/url';\nimport { useCallback } from '@wordpress/element';\nimport { useSelect } from '@wordpress/data';\n\n/**\n * Internal dependencies\n */\nimport isURLLike from './is-url-like';\nimport {\n\tCREATE_TYPE,\n\tTEL_TYPE,\n\tMAILTO_TYPE,\n\tINTERNAL_TYPE,\n\tURL_TYPE,\n} from './constants';\nimport { store as blockEditorStore } from '../../store';\n\nexport const handleNoop = () => Promise.resolve( [] );\n\nexport const handleDirectEntry = ( val ) => {\n\tlet type = URL_TYPE;\n\n\tconst protocol = getProtocol( val ) || '';\n\n\tif ( protocol.includes( 'mailto' ) ) {\n\t\ttype = MAILTO_TYPE;\n\t}\n\n\tif ( protocol.includes( 'tel' ) ) {\n\t\ttype = TEL_TYPE;\n\t}\n\n\tif ( val?.startsWith( '#' ) ) {\n\t\ttype = INTERNAL_TYPE;\n\t}\n\n\treturn Promise.resolve( [\n\t\t{\n\t\t\tid: val,\n\t\t\ttitle: val,\n\t\t\turl: type === 'URL' ? prependHTTPS( val ) : val,\n\t\t\ttype,\n\t\t},\n\t] );\n};\n\nconst handleEntitySearch = async (\n\tval,\n\tsuggestionsQuery,\n\tfetchSearchSuggestions,\n\twithCreateSuggestion,\n\tpageOnFront,\n\tpageForPosts\n) => {\n\tconst { isInitialSuggestions } = suggestionsQuery;\n\n\tconst results = await fetchSearchSuggestions( val, suggestionsQuery );\n\n\t// Identify front page and update type to match.\n\tresults.map( ( result ) => {\n\t\tif ( Number( result.id ) === pageOnFront ) {\n\t\t\tresult.isFrontPage = true;\n\t\t\treturn result;\n\t\t} else if ( Number( result.id ) === pageForPosts ) {\n\t\t\tresult.isBlogHome = true;\n\t\t\treturn result;\n\t\t}\n\n\t\treturn result;\n\t} );\n\n\t// If displaying initial suggestions just return plain results.\n\tif ( isInitialSuggestions ) {\n\t\treturn results;\n\t}\n\n\t// Here we append a faux suggestion to represent a \"CREATE\" option. This\n\t// is detected in the rendering of the search results and handled as a\n\t// special case. This is currently necessary because the suggestions\n\t// dropdown will only appear if there are valid suggestions and\n\t// therefore unless the create option is a suggestion it will not\n\t// display in scenarios where there are no results returned from the\n\t// API. In addition promoting CREATE to a first class suggestion affords\n\t// the a11y benefits afforded by `URLInput` to all suggestions (eg:\n\t// keyboard handling, ARIA roles...etc).\n\t//\n\t// Note also that the value of the `title` and `url` properties must correspond\n\t// to the text value of the `<input>`. This is because `title` is used\n\t// when creating the suggestion. Similarly `url` is used when using keyboard to select\n\t// the suggestion (the <form> `onSubmit` handler falls-back to `url`).\n\treturn isURLLike( val ) || ! withCreateSuggestion\n\t\t? results\n\t\t: results.concat( {\n\t\t\t\t// the `id` prop is intentionally omitted here because it\n\t\t\t\t// is never exposed as part of the component's public API.\n\t\t\t\t// see: https://github.com/WordPress/gutenberg/pull/19775#discussion_r378931316.\n\t\t\t\ttitle: val, // Must match the existing `<input>`s text value.\n\t\t\t\turl: val, // Must match the existing `<input>`s text value.\n\t\t\t\ttype: CREATE_TYPE,\n\t\t } );\n};\n\nexport default function useSearchHandler(\n\tsuggestionsQuery,\n\tallowDirectEntry,\n\twithCreateSuggestion\n) {\n\tconst { fetchSearchSuggestions, pageOnFront, pageForPosts } = useSelect(\n\t\t( select ) => {\n\t\t\tconst { getSettings } = select( blockEditorStore );\n\n\t\t\treturn {\n\t\t\t\tpageOnFront: getSettings().pageOnFront,\n\t\t\t\tpageForPosts: getSettings().pageForPosts,\n\t\t\t\tfetchSearchSuggestions:\n\t\t\t\t\tgetSettings().__experimentalFetchLinkSuggestions,\n\t\t\t};\n\t\t},\n\t\t[]\n\t);\n\n\tconst directEntryHandler = allowDirectEntry\n\t\t? handleDirectEntry\n\t\t: handleNoop;\n\n\treturn useCallback(\n\t\t( val, { isInitialSuggestions } ) => {\n\t\t\treturn isURLLike( val )\n\t\t\t\t? directEntryHandler( val, { isInitialSuggestions } )\n\t\t\t\t: handleEntitySearch(\n\t\t\t\t\t\tval,\n\t\t\t\t\t\t{ ...suggestionsQuery, isInitialSuggestions },\n\t\t\t\t\t\tfetchSearchSuggestions,\n\t\t\t\t\t\twithCreateSuggestion,\n\t\t\t\t\t\tpageOnFront,\n\t\t\t\t\t\tpageForPosts\n\t\t\t\t );\n\t\t},\n\t\t[\n\t\t\tdirectEntryHandler,\n\t\t\tfetchSearchSuggestions,\n\t\t\tpageOnFront,\n\t\t\tpageForPosts,\n\t\t\tsuggestionsQuery,\n\t\t\twithCreateSuggestion,\n\t\t]\n\t);\n}\n"],
5
+ "mappings": ";AAGA,SAAS,aAAa,oBAAoB;AAC1C,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAK1B,OAAO,eAAe;AACtB;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,SAAS,wBAAwB;AAEnC,IAAM,aAAa,MAAM,QAAQ,QAAS,CAAC,CAAE;AAE7C,IAAM,oBAAoB,CAAE,QAAS;AAC3C,MAAI,OAAO;AAEX,QAAM,WAAW,YAAa,GAAI,KAAK;AAEvC,MAAK,SAAS,SAAU,QAAS,GAAI;AACpC,WAAO;AAAA,EACR;AAEA,MAAK,SAAS,SAAU,KAAM,GAAI;AACjC,WAAO;AAAA,EACR;AAEA,MAAK,KAAK,WAAY,GAAI,GAAI;AAC7B,WAAO;AAAA,EACR;AAEA,SAAO,QAAQ,QAAS;AAAA,IACvB;AAAA,MACC,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,KAAK,SAAS,QAAQ,aAAc,GAAI,IAAI;AAAA,MAC5C;AAAA,IACD;AAAA,EACD,CAAE;AACH;AAEA,IAAM,qBAAqB,OAC1B,KACA,kBACA,wBACA,sBACA,aACA,iBACI;AACJ,QAAM,EAAE,qBAAqB,IAAI;AAEjC,QAAM,UAAU,MAAM,uBAAwB,KAAK,gBAAiB;AAGpE,UAAQ,IAAK,CAAE,WAAY;AAC1B,QAAK,OAAQ,OAAO,EAAG,MAAM,aAAc;AAC1C,aAAO,cAAc;AACrB,aAAO;AAAA,IACR,WAAY,OAAQ,OAAO,EAAG,MAAM,cAAe;AAClD,aAAO,aAAa;AACpB,aAAO;AAAA,IACR;AAEA,WAAO;AAAA,EACR,CAAE;AAGF,MAAK,sBAAuB;AAC3B,WAAO;AAAA,EACR;AAgBA,SAAO,UAAW,GAAI,KAAK,CAAE,uBAC1B,UACA,QAAQ,OAAQ;AAAA;AAAA;AAAA;AAAA,IAIhB,OAAO;AAAA;AAAA,IACP,KAAK;AAAA;AAAA,IACL,MAAM;AAAA,EACN,CAAE;AACN;AAEe,SAAR,iBACN,kBACA,kBACA,sBACC;AACD,QAAM,EAAE,wBAAwB,aAAa,aAAa,IAAI;AAAA,IAC7D,CAAE,WAAY;AACb,YAAM,EAAE,YAAY,IAAI,OAAQ,gBAAiB;AAEjD,aAAO;AAAA,QACN,aAAa,YAAY,EAAE;AAAA,QAC3B,cAAc,YAAY,EAAE;AAAA,QAC5B,wBACC,YAAY,EAAE;AAAA,MAChB;AAAA,IACD;AAAA,IACA,CAAC;AAAA,EACF;AAEA,QAAM,qBAAqB,mBACxB,oBACA;AAEH,SAAO;AAAA,IACN,CAAE,KAAK,EAAE,qBAAqB,MAAO;AACpC,aAAO,UAAW,GAAI,IACnB,mBAAoB,KAAK,EAAE,qBAAqB,CAAE,IAClD;AAAA,QACA;AAAA,QACA,EAAE,GAAG,kBAAkB,qBAAqB;AAAA,QAC5C;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACA;AAAA,IACJ;AAAA,IACA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AACD;",
6
6
  "names": []
7
7
  }
@@ -5,6 +5,49 @@ import { cloneBlock } from "@wordpress/blocks";
5
5
  import { store as blockEditorStore } from "../../store/index.mjs";
6
6
  var noop = () => {
7
7
  };
8
+ function cloneBlockWithMapping(block, mapping) {
9
+ const clonedBlock = cloneBlock(block);
10
+ mapping.externalToInternal.set(block.clientId, clonedBlock.clientId);
11
+ mapping.internalToExternal.set(clonedBlock.clientId, block.clientId);
12
+ if (block.innerBlocks?.length) {
13
+ clonedBlock.innerBlocks = block.innerBlocks.map((innerBlock) => {
14
+ const clonedInner = cloneBlockWithMapping(innerBlock, mapping);
15
+ return clonedInner;
16
+ });
17
+ }
18
+ return clonedBlock;
19
+ }
20
+ function restoreExternalIds(blocks, mapping) {
21
+ return blocks.map((block) => {
22
+ const externalId = mapping.internalToExternal.get(block.clientId);
23
+ return {
24
+ ...block,
25
+ // Use external ID if available, otherwise keep internal ID (for new blocks)
26
+ clientId: externalId ?? block.clientId,
27
+ innerBlocks: restoreExternalIds(block.innerBlocks, mapping)
28
+ };
29
+ });
30
+ }
31
+ function restoreSelectionIds(selection, mapping) {
32
+ const { selectionStart, selectionEnd, initialPosition } = selection;
33
+ const restoreClientId = (selectionState) => {
34
+ if (!selectionState?.clientId) {
35
+ return selectionState;
36
+ }
37
+ const externalId = mapping.internalToExternal.get(
38
+ selectionState.clientId
39
+ );
40
+ return {
41
+ ...selectionState,
42
+ clientId: externalId ?? selectionState.clientId
43
+ };
44
+ };
45
+ return {
46
+ selectionStart: restoreClientId(selectionStart),
47
+ selectionEnd: restoreClientId(selectionEnd),
48
+ initialPosition
49
+ };
50
+ }
8
51
  function useBlockSync({
9
52
  clientId = null,
10
53
  value: controlledBlocks,
@@ -29,6 +72,10 @@ function useBlockSync({
29
72
  );
30
73
  const pendingChangesRef = useRef({ incoming: null, outgoing: [] });
31
74
  const subscribedRef = useRef(false);
75
+ const idMappingRef = useRef({
76
+ externalToInternal: /* @__PURE__ */ new Map(),
77
+ internalToExternal: /* @__PURE__ */ new Map()
78
+ });
32
79
  const setControlledBlocks = () => {
33
80
  if (!controlledBlocks) {
34
81
  return;
@@ -37,8 +84,10 @@ function useBlockSync({
37
84
  if (clientId) {
38
85
  registry.batch(() => {
39
86
  setHasControlledInnerBlocks(clientId, true);
87
+ idMappingRef.current.externalToInternal.clear();
88
+ idMappingRef.current.internalToExternal.clear();
40
89
  const storeBlocks = controlledBlocks.map(
41
- (block) => cloneBlock(block)
90
+ (block) => cloneBlockWithMapping(block, idMappingRef.current)
42
91
  );
43
92
  if (subscribedRef.current) {
44
93
  pendingChangesRef.current.incoming = storeBlocks;
@@ -128,14 +177,17 @@ function useBlockSync({
128
177
  const didPersistenceChange = previousAreBlocksDifferent && !areBlocksDifferent && newIsPersistent && !isPersistent;
129
178
  if (areBlocksDifferent || didPersistenceChange) {
130
179
  isPersistent = newIsPersistent;
131
- pendingChangesRef.current.outgoing.push(blocks);
180
+ const blocksForParent = clientId ? restoreExternalIds(blocks, idMappingRef.current) : blocks;
181
+ const selection = {
182
+ selectionStart: getSelectionStart(),
183
+ selectionEnd: getSelectionEnd(),
184
+ initialPosition: getSelectedBlocksInitialCaretPosition()
185
+ };
186
+ const selectionForParent = clientId ? restoreSelectionIds(selection, idMappingRef.current) : selection;
187
+ pendingChangesRef.current.outgoing.push(blocksForParent);
132
188
  const updateParent = isPersistent ? onChangeRef.current : onInputRef.current;
133
- updateParent(blocks, {
134
- selection: {
135
- selectionStart: getSelectionStart(),
136
- selectionEnd: getSelectionEnd(),
137
- initialPosition: getSelectedBlocksInitialCaretPosition()
138
- }
189
+ updateParent(blocksForParent, {
190
+ selection: selectionForParent
139
191
  });
140
192
  }
141
193
  previousAreBlocksDifferent = areBlocksDifferent;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/provider/use-block-sync.js"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useEffect, useRef } from '@wordpress/element';\nimport { useRegistry, useSelect } from '@wordpress/data';\nimport { cloneBlock } from '@wordpress/blocks';\n\n/**\n * Internal dependencies\n */\nimport { store as blockEditorStore } from '../../store';\n\nconst noop = () => {};\n\n/**\n * A function to call when the block value has been updated in the block-editor\n * store.\n *\n * @callback onBlockUpdate\n * @param {Object[]} blocks The updated blocks.\n * @param {Object} options The updated block options, such as selectionStart\n * and selectionEnd.\n */\n\n/**\n * useBlockSync is a side effect which handles bidirectional sync between the\n * block-editor store and a controlling data source which provides blocks. This\n * is most commonly used by the BlockEditorProvider to synchronize the contents\n * of the block-editor store with the root entity, like a post.\n *\n * Another example would be the template part block, which provides blocks from\n * a separate entity data source than a root entity. This hook syncs edits to\n * the template part in the block editor back to the entity and vice-versa.\n *\n * Here are some of its basic functions:\n * - Initializes the block-editor store for the given clientID to the blocks\n * given via props.\n * - Adds incoming changes (like undo) to the block-editor store.\n * - Adds outgoing changes (like editing content) to the controlling entity,\n * determining if a change should be considered persistent or not.\n * - Handles edge cases and race conditions which occur in those operations.\n * - Ignores changes which happen to other entities (like nested inner block\n * controllers.\n * - Passes selection state from the block-editor store to the controlling entity.\n *\n * @param {Object} props Props for the block sync hook\n * @param {string} props.clientId The client ID of the inner block controller.\n * If none is passed, then it is assumed to be a\n * root controller rather than an inner block\n * controller.\n * @param {Object[]} props.value The control value for the blocks. This value\n * is used to initialize the block-editor store\n * and for resetting the blocks to incoming\n * changes like undo.\n * @param {Object} props.selection The selection state responsible to restore the selection on undo/redo.\n * @param {onBlockUpdate} props.onChange Function to call when a persistent\n * change has been made in the block-editor blocks\n * for the given clientId. For example, after\n * this function is called, an entity is marked\n * dirty because it has changes to save.\n * @param {onBlockUpdate} props.onInput Function to call when a non-persistent\n * change has been made in the block-editor blocks\n * for the given clientId. When this is called,\n * controlling sources do not become dirty.\n */\nexport default function useBlockSync( {\n\tclientId = null,\n\tvalue: controlledBlocks,\n\tselection: controlledSelection,\n\tonChange = noop,\n\tonInput = noop,\n} ) {\n\tconst registry = useRegistry();\n\n\tconst {\n\t\tresetBlocks,\n\t\tresetSelection,\n\t\treplaceInnerBlocks,\n\t\tsetHasControlledInnerBlocks,\n\t\t__unstableMarkNextChangeAsNotPersistent,\n\t} = registry.dispatch( blockEditorStore );\n\tconst { getBlockName, getBlocks, getSelectionStart, getSelectionEnd } =\n\t\tregistry.select( blockEditorStore );\n\tconst isControlled = useSelect(\n\t\t( select ) => {\n\t\t\treturn (\n\t\t\t\t! clientId ||\n\t\t\t\tselect( blockEditorStore ).areInnerBlocksControlled( clientId )\n\t\t\t);\n\t\t},\n\t\t[ clientId ]\n\t);\n\n\tconst pendingChangesRef = useRef( { incoming: null, outgoing: [] } );\n\tconst subscribedRef = useRef( false );\n\n\tconst setControlledBlocks = () => {\n\t\tif ( ! controlledBlocks ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// We don't need to persist this change because we only replace\n\t\t// controlled inner blocks when the change was caused by an entity,\n\t\t// and so it would already be persisted.\n\t\t__unstableMarkNextChangeAsNotPersistent();\n\t\tif ( clientId ) {\n\t\t\t// It is important to batch here because otherwise,\n\t\t\t// as soon as `setHasControlledInnerBlocks` is called\n\t\t\t// the effect to restore might be triggered\n\t\t\t// before the actual blocks get set properly in state.\n\t\t\tregistry.batch( () => {\n\t\t\t\tsetHasControlledInnerBlocks( clientId, true );\n\t\t\t\tconst storeBlocks = controlledBlocks.map( ( block ) =>\n\t\t\t\t\tcloneBlock( block )\n\t\t\t\t);\n\t\t\t\tif ( subscribedRef.current ) {\n\t\t\t\t\tpendingChangesRef.current.incoming = storeBlocks;\n\t\t\t\t}\n\t\t\t\t__unstableMarkNextChangeAsNotPersistent();\n\t\t\t\treplaceInnerBlocks( clientId, storeBlocks );\n\t\t\t} );\n\t\t} else {\n\t\t\tif ( subscribedRef.current ) {\n\t\t\t\tpendingChangesRef.current.incoming = controlledBlocks;\n\t\t\t}\n\t\t\tresetBlocks( controlledBlocks );\n\t\t}\n\t};\n\n\t// Clean up the changes made by setControlledBlocks() when the component\n\t// containing useBlockSync() unmounts.\n\tconst unsetControlledBlocks = () => {\n\t\t__unstableMarkNextChangeAsNotPersistent();\n\t\tif ( clientId ) {\n\t\t\tsetHasControlledInnerBlocks( clientId, false );\n\t\t\t__unstableMarkNextChangeAsNotPersistent();\n\t\t\treplaceInnerBlocks( clientId, [] );\n\t\t} else {\n\t\t\tresetBlocks( [] );\n\t\t}\n\t};\n\n\t// Add a subscription to the block-editor registry to detect when changes\n\t// have been made. This lets us inform the data source of changes. This\n\t// is an effect so that the subscriber can run synchronously without\n\t// waiting for React renders for changes.\n\tconst onInputRef = useRef( onInput );\n\tconst onChangeRef = useRef( onChange );\n\tuseEffect( () => {\n\t\tonInputRef.current = onInput;\n\t\tonChangeRef.current = onChange;\n\t}, [ onInput, onChange ] );\n\n\t// Determine if blocks need to be reset when they change.\n\tuseEffect( () => {\n\t\tif ( pendingChangesRef.current.outgoing.includes( controlledBlocks ) ) {\n\t\t\t// Skip block reset if the value matches expected outbound sync\n\t\t\t// triggered by this component by a preceding change detection.\n\t\t\t// Only skip if the value matches expectation, since a reset should\n\t\t\t// still occur if the value is modified (not equal by reference),\n\t\t\t// to allow that the consumer may apply modifications to reflect\n\t\t\t// back on the editor.\n\t\t\tif (\n\t\t\t\tpendingChangesRef.current.outgoing[\n\t\t\t\t\tpendingChangesRef.current.outgoing.length - 1\n\t\t\t\t] === controlledBlocks\n\t\t\t) {\n\t\t\t\tpendingChangesRef.current.outgoing = [];\n\t\t\t}\n\t\t} else if ( getBlocks( clientId ) !== controlledBlocks ) {\n\t\t\t// Reset changing value in all other cases than the sync described\n\t\t\t// above. Since this can be reached in an update following an out-\n\t\t\t// bound sync, unset the outbound value to avoid considering it in\n\t\t\t// subsequent renders.\n\t\t\tpendingChangesRef.current.outgoing = [];\n\t\t\tsetControlledBlocks();\n\n\t\t\tif ( controlledSelection ) {\n\t\t\t\tresetSelection(\n\t\t\t\t\tcontrolledSelection.selectionStart,\n\t\t\t\t\tcontrolledSelection.selectionEnd,\n\t\t\t\t\tcontrolledSelection.initialPosition\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}, [ controlledBlocks, clientId ] );\n\n\tconst isMountedRef = useRef( false );\n\n\tuseEffect( () => {\n\t\t// On mount, controlled blocks are already set in the effect above.\n\t\tif ( ! isMountedRef.current ) {\n\t\t\tisMountedRef.current = true;\n\t\t\treturn;\n\t\t}\n\n\t\t// When the block becomes uncontrolled, it means its inner state has been reset\n\t\t// we need to take the blocks again from the external value property.\n\t\tif ( ! isControlled ) {\n\t\t\tpendingChangesRef.current.outgoing = [];\n\t\t\tsetControlledBlocks();\n\t\t}\n\t}, [ isControlled ] );\n\n\tuseEffect( () => {\n\t\tconst {\n\t\t\tgetSelectedBlocksInitialCaretPosition,\n\t\t\tisLastBlockChangePersistent,\n\t\t\t__unstableIsLastBlockChangeIgnored,\n\t\t\tareInnerBlocksControlled,\n\t\t} = registry.select( blockEditorStore );\n\n\t\tlet blocks = getBlocks( clientId );\n\t\tlet isPersistent = isLastBlockChangePersistent();\n\t\tlet previousAreBlocksDifferent = false;\n\n\t\tsubscribedRef.current = true;\n\t\tconst unsubscribe = registry.subscribe( () => {\n\t\t\t// Sometimes, when changing block lists, lingering subscriptions\n\t\t\t// might trigger before they are cleaned up. If the block for which\n\t\t\t// the subscription runs is no longer in the store, this would clear\n\t\t\t// its parent entity's block list. To avoid this, we bail out if\n\t\t\t// the subscription is triggering for a block (`clientId !== null`)\n\t\t\t// and its block name can't be found because it's not on the list.\n\t\t\t// (`getBlockName( clientId ) === null`).\n\t\t\tif ( clientId !== null && getBlockName( clientId ) === null ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// When RESET_BLOCKS on parent blocks get called, the controlled blocks\n\t\t\t// can reset to uncontrolled, in these situations, it means we need to populate\n\t\t\t// the blocks again from the external blocks (the value property here)\n\t\t\t// and we should stop triggering onChange\n\t\t\tconst isStillControlled =\n\t\t\t\t! clientId || areInnerBlocksControlled( clientId );\n\t\t\tif ( ! isStillControlled ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst newIsPersistent = isLastBlockChangePersistent();\n\t\t\tconst newBlocks = getBlocks( clientId );\n\t\t\tconst areBlocksDifferent = newBlocks !== blocks;\n\t\t\tblocks = newBlocks;\n\t\t\tif (\n\t\t\t\tareBlocksDifferent &&\n\t\t\t\t( pendingChangesRef.current.incoming ||\n\t\t\t\t\t__unstableIsLastBlockChangeIgnored() )\n\t\t\t) {\n\t\t\t\tpendingChangesRef.current.incoming = null;\n\t\t\t\tisPersistent = newIsPersistent;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Since we often dispatch an action to mark the previous action as\n\t\t\t// persistent, we need to make sure that the blocks changed on the\n\t\t\t// previous action before committing the change.\n\t\t\tconst didPersistenceChange =\n\t\t\t\tpreviousAreBlocksDifferent &&\n\t\t\t\t! areBlocksDifferent &&\n\t\t\t\tnewIsPersistent &&\n\t\t\t\t! isPersistent;\n\n\t\t\tif ( areBlocksDifferent || didPersistenceChange ) {\n\t\t\t\tisPersistent = newIsPersistent;\n\t\t\t\t// We know that onChange/onInput will update controlledBlocks.\n\t\t\t\t// We need to be aware that it was caused by an outgoing change\n\t\t\t\t// so that we do not treat it as an incoming change later on,\n\t\t\t\t// which would cause a block reset.\n\t\t\t\tpendingChangesRef.current.outgoing.push( blocks );\n\n\t\t\t\t// Inform the controlling entity that changes have been made to\n\t\t\t\t// the block-editor store they should be aware about.\n\t\t\t\tconst updateParent = isPersistent\n\t\t\t\t\t? onChangeRef.current\n\t\t\t\t\t: onInputRef.current;\n\t\t\t\tupdateParent( blocks, {\n\t\t\t\t\tselection: {\n\t\t\t\t\t\tselectionStart: getSelectionStart(),\n\t\t\t\t\t\tselectionEnd: getSelectionEnd(),\n\t\t\t\t\t\tinitialPosition:\n\t\t\t\t\t\t\tgetSelectedBlocksInitialCaretPosition(),\n\t\t\t\t\t},\n\t\t\t\t} );\n\t\t\t}\n\t\t\tpreviousAreBlocksDifferent = areBlocksDifferent;\n\t\t}, blockEditorStore );\n\n\t\treturn () => {\n\t\t\tsubscribedRef.current = false;\n\t\t\tunsubscribe();\n\t\t};\n\t}, [ registry, clientId ] );\n\n\tuseEffect( () => {\n\t\treturn () => {\n\t\t\tunsetControlledBlocks();\n\t\t};\n\t}, [] );\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useEffect, useRef } from '@wordpress/element';\nimport { useRegistry, useSelect } from '@wordpress/data';\nimport { cloneBlock } from '@wordpress/blocks';\n\n/**\n * Internal dependencies\n */\nimport { store as blockEditorStore } from '../../store';\n\nconst noop = () => {};\n\n/**\n * Clones a block and its inner blocks, building a bidirectional mapping\n * between external (original) and internal (cloned) client IDs.\n *\n * This allows the block editor to use unique internal IDs while preserving\n * stable external IDs for features like real-time collaboration.\n *\n * @param {Object} block The block to clone.\n * @param {Object} mapping The mapping object with externalToInternal and internalToExternal Maps.\n * @return {Object} The cloned block with a new clientId.\n */\nfunction cloneBlockWithMapping( block, mapping ) {\n\tconst clonedBlock = cloneBlock( block );\n\n\t// Build bidirectional mapping\n\tmapping.externalToInternal.set( block.clientId, clonedBlock.clientId );\n\tmapping.internalToExternal.set( clonedBlock.clientId, block.clientId );\n\n\t// Recursively map inner blocks\n\tif ( block.innerBlocks?.length ) {\n\t\tclonedBlock.innerBlocks = block.innerBlocks.map( ( innerBlock ) => {\n\t\t\tconst clonedInner = cloneBlockWithMapping( innerBlock, mapping );\n\t\t\t// The clonedBlock already has cloned inner blocks from cloneBlock(),\n\t\t\t// but we need to use our mapped versions to maintain the mapping.\n\t\t\treturn clonedInner;\n\t\t} );\n\t}\n\n\treturn clonedBlock;\n}\n\n/**\n * Restores external (original) client IDs on blocks before passing them\n * to onChange/onInput callbacks.\n *\n * @param {Object[]} blocks The blocks with internal client IDs.\n * @param {Object} mapping The mapping object with internalToExternal Map.\n * @return {Object[]} Blocks with external client IDs restored.\n */\nfunction restoreExternalIds( blocks, mapping ) {\n\treturn blocks.map( ( block ) => {\n\t\tconst externalId = mapping.internalToExternal.get( block.clientId );\n\t\treturn {\n\t\t\t...block,\n\t\t\t// Use external ID if available, otherwise keep internal ID (for new blocks)\n\t\t\tclientId: externalId ?? block.clientId,\n\t\t\tinnerBlocks: restoreExternalIds( block.innerBlocks, mapping ),\n\t\t};\n\t} );\n}\n\n/**\n * Restores external client IDs in selection state.\n *\n * @param {Object} selection The selection state with internal client IDs.\n * @param {Object} mapping The mapping object with internalToExternal Map.\n * @return {Object} Selection state with external client IDs.\n */\nfunction restoreSelectionIds( selection, mapping ) {\n\tconst { selectionStart, selectionEnd, initialPosition } = selection;\n\n\tconst restoreClientId = ( selectionState ) => {\n\t\tif ( ! selectionState?.clientId ) {\n\t\t\treturn selectionState;\n\t\t}\n\t\tconst externalId = mapping.internalToExternal.get(\n\t\t\tselectionState.clientId\n\t\t);\n\t\treturn {\n\t\t\t...selectionState,\n\t\t\tclientId: externalId ?? selectionState.clientId,\n\t\t};\n\t};\n\n\treturn {\n\t\tselectionStart: restoreClientId( selectionStart ),\n\t\tselectionEnd: restoreClientId( selectionEnd ),\n\t\tinitialPosition,\n\t};\n}\n\n/**\n * A function to call when the block value has been updated in the block-editor\n * store.\n *\n * @callback onBlockUpdate\n * @param {Object[]} blocks The updated blocks.\n * @param {Object} options The updated block options, such as selectionStart\n * and selectionEnd.\n */\n\n/**\n * useBlockSync is a side effect which handles bidirectional sync between the\n * block-editor store and a controlling data source which provides blocks. This\n * is most commonly used by the BlockEditorProvider to synchronize the contents\n * of the block-editor store with the root entity, like a post.\n *\n * Another example would be the template part block, which provides blocks from\n * a separate entity data source than a root entity. This hook syncs edits to\n * the template part in the block editor back to the entity and vice-versa.\n *\n * Here are some of its basic functions:\n * - Initializes the block-editor store for the given clientID to the blocks\n * given via props.\n * - Adds incoming changes (like undo) to the block-editor store.\n * - Adds outgoing changes (like editing content) to the controlling entity,\n * determining if a change should be considered persistent or not.\n * - Handles edge cases and race conditions which occur in those operations.\n * - Ignores changes which happen to other entities (like nested inner block\n * controllers.\n * - Passes selection state from the block-editor store to the controlling entity.\n *\n * @param {Object} props Props for the block sync hook\n * @param {string} props.clientId The client ID of the inner block controller.\n * If none is passed, then it is assumed to be a\n * root controller rather than an inner block\n * controller.\n * @param {Object[]} props.value The control value for the blocks. This value\n * is used to initialize the block-editor store\n * and for resetting the blocks to incoming\n * changes like undo.\n * @param {Object} props.selection The selection state responsible to restore the selection on undo/redo.\n * @param {onBlockUpdate} props.onChange Function to call when a persistent\n * change has been made in the block-editor blocks\n * for the given clientId. For example, after\n * this function is called, an entity is marked\n * dirty because it has changes to save.\n * @param {onBlockUpdate} props.onInput Function to call when a non-persistent\n * change has been made in the block-editor blocks\n * for the given clientId. When this is called,\n * controlling sources do not become dirty.\n */\nexport default function useBlockSync( {\n\tclientId = null,\n\tvalue: controlledBlocks,\n\tselection: controlledSelection,\n\tonChange = noop,\n\tonInput = noop,\n} ) {\n\tconst registry = useRegistry();\n\n\tconst {\n\t\tresetBlocks,\n\t\tresetSelection,\n\t\treplaceInnerBlocks,\n\t\tsetHasControlledInnerBlocks,\n\t\t__unstableMarkNextChangeAsNotPersistent,\n\t} = registry.dispatch( blockEditorStore );\n\tconst { getBlockName, getBlocks, getSelectionStart, getSelectionEnd } =\n\t\tregistry.select( blockEditorStore );\n\tconst isControlled = useSelect(\n\t\t( select ) => {\n\t\t\treturn (\n\t\t\t\t! clientId ||\n\t\t\t\tselect( blockEditorStore ).areInnerBlocksControlled( clientId )\n\t\t\t);\n\t\t},\n\t\t[ clientId ]\n\t);\n\n\tconst pendingChangesRef = useRef( { incoming: null, outgoing: [] } );\n\tconst subscribedRef = useRef( false );\n\n\t// Mapping between external (original) and internal (cloned) client IDs.\n\t// This allows stable external IDs while using unique internal IDs.\n\tconst idMappingRef = useRef( {\n\t\texternalToInternal: new Map(),\n\t\tinternalToExternal: new Map(),\n\t} );\n\n\tconst setControlledBlocks = () => {\n\t\tif ( ! controlledBlocks ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// We don't need to persist this change because we only replace\n\t\t// controlled inner blocks when the change was caused by an entity,\n\t\t// and so it would already be persisted.\n\t\t__unstableMarkNextChangeAsNotPersistent();\n\t\tif ( clientId ) {\n\t\t\t// It is important to batch here because otherwise,\n\t\t\t// as soon as `setHasControlledInnerBlocks` is called\n\t\t\t// the effect to restore might be triggered\n\t\t\t// before the actual blocks get set properly in state.\n\t\t\tregistry.batch( () => {\n\t\t\t\tsetHasControlledInnerBlocks( clientId, true );\n\n\t\t\t\t// Clear previous mappings and build new ones during cloning.\n\t\t\t\t// This ensures the mapping stays in sync with the current blocks.\n\t\t\t\tidMappingRef.current.externalToInternal.clear();\n\t\t\t\tidMappingRef.current.internalToExternal.clear();\n\n\t\t\t\tconst storeBlocks = controlledBlocks.map( ( block ) =>\n\t\t\t\t\tcloneBlockWithMapping( block, idMappingRef.current )\n\t\t\t\t);\n\t\t\t\tif ( subscribedRef.current ) {\n\t\t\t\t\tpendingChangesRef.current.incoming = storeBlocks;\n\t\t\t\t}\n\t\t\t\t__unstableMarkNextChangeAsNotPersistent();\n\t\t\t\treplaceInnerBlocks( clientId, storeBlocks );\n\t\t\t} );\n\t\t} else {\n\t\t\tif ( subscribedRef.current ) {\n\t\t\t\tpendingChangesRef.current.incoming = controlledBlocks;\n\t\t\t}\n\t\t\tresetBlocks( controlledBlocks );\n\t\t}\n\t};\n\n\t// Clean up the changes made by setControlledBlocks() when the component\n\t// containing useBlockSync() unmounts.\n\tconst unsetControlledBlocks = () => {\n\t\t__unstableMarkNextChangeAsNotPersistent();\n\t\tif ( clientId ) {\n\t\t\tsetHasControlledInnerBlocks( clientId, false );\n\t\t\t__unstableMarkNextChangeAsNotPersistent();\n\t\t\treplaceInnerBlocks( clientId, [] );\n\t\t} else {\n\t\t\tresetBlocks( [] );\n\t\t}\n\t};\n\n\t// Add a subscription to the block-editor registry to detect when changes\n\t// have been made. This lets us inform the data source of changes. This\n\t// is an effect so that the subscriber can run synchronously without\n\t// waiting for React renders for changes.\n\tconst onInputRef = useRef( onInput );\n\tconst onChangeRef = useRef( onChange );\n\tuseEffect( () => {\n\t\tonInputRef.current = onInput;\n\t\tonChangeRef.current = onChange;\n\t}, [ onInput, onChange ] );\n\n\t// Determine if blocks need to be reset when they change.\n\tuseEffect( () => {\n\t\tif ( pendingChangesRef.current.outgoing.includes( controlledBlocks ) ) {\n\t\t\t// Skip block reset if the value matches expected outbound sync\n\t\t\t// triggered by this component by a preceding change detection.\n\t\t\t// Only skip if the value matches expectation, since a reset should\n\t\t\t// still occur if the value is modified (not equal by reference),\n\t\t\t// to allow that the consumer may apply modifications to reflect\n\t\t\t// back on the editor.\n\t\t\tif (\n\t\t\t\tpendingChangesRef.current.outgoing[\n\t\t\t\t\tpendingChangesRef.current.outgoing.length - 1\n\t\t\t\t] === controlledBlocks\n\t\t\t) {\n\t\t\t\tpendingChangesRef.current.outgoing = [];\n\t\t\t}\n\t\t} else if ( getBlocks( clientId ) !== controlledBlocks ) {\n\t\t\t// Reset changing value in all other cases than the sync described\n\t\t\t// above. Since this can be reached in an update following an out-\n\t\t\t// bound sync, unset the outbound value to avoid considering it in\n\t\t\t// subsequent renders.\n\t\t\tpendingChangesRef.current.outgoing = [];\n\t\t\tsetControlledBlocks();\n\n\t\t\tif ( controlledSelection ) {\n\t\t\t\tresetSelection(\n\t\t\t\t\tcontrolledSelection.selectionStart,\n\t\t\t\t\tcontrolledSelection.selectionEnd,\n\t\t\t\t\tcontrolledSelection.initialPosition\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}, [ controlledBlocks, clientId ] );\n\n\tconst isMountedRef = useRef( false );\n\n\tuseEffect( () => {\n\t\t// On mount, controlled blocks are already set in the effect above.\n\t\tif ( ! isMountedRef.current ) {\n\t\t\tisMountedRef.current = true;\n\t\t\treturn;\n\t\t}\n\n\t\t// When the block becomes uncontrolled, it means its inner state has been reset\n\t\t// we need to take the blocks again from the external value property.\n\t\tif ( ! isControlled ) {\n\t\t\tpendingChangesRef.current.outgoing = [];\n\t\t\tsetControlledBlocks();\n\t\t}\n\t}, [ isControlled ] );\n\n\tuseEffect( () => {\n\t\tconst {\n\t\t\tgetSelectedBlocksInitialCaretPosition,\n\t\t\tisLastBlockChangePersistent,\n\t\t\t__unstableIsLastBlockChangeIgnored,\n\t\t\tareInnerBlocksControlled,\n\t\t} = registry.select( blockEditorStore );\n\n\t\tlet blocks = getBlocks( clientId );\n\t\tlet isPersistent = isLastBlockChangePersistent();\n\t\tlet previousAreBlocksDifferent = false;\n\n\t\tsubscribedRef.current = true;\n\t\tconst unsubscribe = registry.subscribe( () => {\n\t\t\t// Sometimes, when changing block lists, lingering subscriptions\n\t\t\t// might trigger before they are cleaned up. If the block for which\n\t\t\t// the subscription runs is no longer in the store, this would clear\n\t\t\t// its parent entity's block list. To avoid this, we bail out if\n\t\t\t// the subscription is triggering for a block (`clientId !== null`)\n\t\t\t// and its block name can't be found because it's not on the list.\n\t\t\t// (`getBlockName( clientId ) === null`).\n\t\t\tif ( clientId !== null && getBlockName( clientId ) === null ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// When RESET_BLOCKS on parent blocks get called, the controlled blocks\n\t\t\t// can reset to uncontrolled, in these situations, it means we need to populate\n\t\t\t// the blocks again from the external blocks (the value property here)\n\t\t\t// and we should stop triggering onChange\n\t\t\tconst isStillControlled =\n\t\t\t\t! clientId || areInnerBlocksControlled( clientId );\n\t\t\tif ( ! isStillControlled ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst newIsPersistent = isLastBlockChangePersistent();\n\t\t\tconst newBlocks = getBlocks( clientId );\n\t\t\tconst areBlocksDifferent = newBlocks !== blocks;\n\t\t\tblocks = newBlocks;\n\t\t\tif (\n\t\t\t\tareBlocksDifferent &&\n\t\t\t\t( pendingChangesRef.current.incoming ||\n\t\t\t\t\t__unstableIsLastBlockChangeIgnored() )\n\t\t\t) {\n\t\t\t\tpendingChangesRef.current.incoming = null;\n\t\t\t\tisPersistent = newIsPersistent;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Since we often dispatch an action to mark the previous action as\n\t\t\t// persistent, we need to make sure that the blocks changed on the\n\t\t\t// previous action before committing the change.\n\t\t\tconst didPersistenceChange =\n\t\t\t\tpreviousAreBlocksDifferent &&\n\t\t\t\t! areBlocksDifferent &&\n\t\t\t\tnewIsPersistent &&\n\t\t\t\t! isPersistent;\n\n\t\t\tif ( areBlocksDifferent || didPersistenceChange ) {\n\t\t\t\tisPersistent = newIsPersistent;\n\n\t\t\t\t// For inner block controllers (clientId is set), restore external IDs\n\t\t\t\t// before passing blocks to the parent. This maintains stable external\n\t\t\t\t// IDs for features like real-time collaboration while using unique\n\t\t\t\t// internal IDs in the block-editor store.\n\t\t\t\tconst blocksForParent = clientId\n\t\t\t\t\t? restoreExternalIds( blocks, idMappingRef.current )\n\t\t\t\t\t: blocks;\n\n\t\t\t\tconst selection = {\n\t\t\t\t\tselectionStart: getSelectionStart(),\n\t\t\t\t\tselectionEnd: getSelectionEnd(),\n\t\t\t\t\tinitialPosition: getSelectedBlocksInitialCaretPosition(),\n\t\t\t\t};\n\n\t\t\t\t// Also restore external IDs in selection state for inner block controllers.\n\t\t\t\tconst selectionForParent = clientId\n\t\t\t\t\t? restoreSelectionIds( selection, idMappingRef.current )\n\t\t\t\t\t: selection;\n\n\t\t\t\t// We know that onChange/onInput will update controlledBlocks.\n\t\t\t\t// We need to be aware that it was caused by an outgoing change\n\t\t\t\t// so that we do not treat it as an incoming change later on,\n\t\t\t\t// which would cause a block reset.\n\t\t\t\tpendingChangesRef.current.outgoing.push( blocksForParent );\n\n\t\t\t\t// Inform the controlling entity that changes have been made to\n\t\t\t\t// the block-editor store they should be aware about.\n\t\t\t\tconst updateParent = isPersistent\n\t\t\t\t\t? onChangeRef.current\n\t\t\t\t\t: onInputRef.current;\n\t\t\t\tupdateParent( blocksForParent, {\n\t\t\t\t\tselection: selectionForParent,\n\t\t\t\t} );\n\t\t\t}\n\t\t\tpreviousAreBlocksDifferent = areBlocksDifferent;\n\t\t}, blockEditorStore );\n\n\t\treturn () => {\n\t\t\tsubscribedRef.current = false;\n\t\t\tunsubscribe();\n\t\t};\n\t}, [ registry, clientId ] );\n\n\tuseEffect( () => {\n\t\treturn () => {\n\t\t\tunsetControlledBlocks();\n\t\t};\n\t}, [] );\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }