@wordpress/block-editor 15.12.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.
- package/CHANGELOG.md +6 -0
- package/build/components/block-allowed-blocks/modal.cjs +1 -1
- package/build/components/block-allowed-blocks/modal.cjs.map +2 -2
- package/build/components/block-inspector/index.cjs +9 -9
- package/build/components/block-inspector/index.cjs.map +3 -3
- package/build/components/block-removal-warning-modal/index.cjs +30 -5
- package/build/components/block-removal-warning-modal/index.cjs.map +3 -3
- package/build/components/block-visibility/use-block-visibility.cjs +14 -29
- package/build/components/block-visibility/use-block-visibility.cjs.map +2 -2
- package/build/components/global-styles/hooks.cjs +7 -0
- package/build/components/global-styles/hooks.cjs.map +2 -2
- package/build/components/global-styles/typography-panel.cjs +71 -3
- package/build/components/global-styles/typography-panel.cjs.map +3 -3
- package/build/components/grid/grid-visualizer.cjs +49 -13
- package/build/components/grid/grid-visualizer.cjs.map +2 -2
- package/build/components/iframe/index.cjs +3 -1
- package/build/components/iframe/index.cjs.map +2 -2
- package/build/components/iframe/use-scale-canvas.cjs +1 -0
- package/build/components/iframe/use-scale-canvas.cjs.map +2 -2
- package/build/components/inspector-controls/last-item.cjs +41 -0
- package/build/components/inspector-controls/last-item.cjs.map +7 -0
- package/build/components/inspector-controls-tabs/styles-tab.cjs +3 -3
- package/build/components/inspector-controls-tabs/styles-tab.cjs.map +2 -2
- package/build/components/link-control/index.cjs +73 -2
- package/build/components/link-control/index.cjs.map +3 -3
- package/build/components/link-control/is-url-like.cjs +15 -3
- package/build/components/link-control/is-url-like.cjs.map +2 -2
- package/build/components/link-control/search-input.cjs +4 -1
- package/build/components/link-control/search-input.cjs.map +2 -2
- package/build/components/link-control/use-search-handler.cjs +1 -1
- package/build/components/link-control/use-search-handler.cjs.map +2 -2
- package/build/components/provider/use-block-sync.cjs +60 -8
- package/build/components/provider/use-block-sync.cjs.map +2 -2
- package/build/components/text-indent-control/index.cjs +121 -0
- package/build/components/text-indent-control/index.cjs.map +7 -0
- package/build/components/url-input/index.cjs +22 -2
- package/build/components/url-input/index.cjs.map +3 -3
- package/build/components/url-popover/image-url-input-ui.cjs +1 -1
- package/build/components/url-popover/image-url-input-ui.cjs.map +2 -2
- package/build/components/writing-flow/use-arrow-nav.cjs +0 -3
- package/build/components/writing-flow/use-arrow-nav.cjs.map +2 -2
- package/build/hooks/anchor.cjs +1 -1
- package/build/hooks/anchor.cjs.map +1 -1
- package/build/hooks/aria-label.cjs +2 -1
- package/build/hooks/aria-label.cjs.map +2 -2
- package/build/hooks/grid-visualizer.cjs +59 -6
- package/build/hooks/grid-visualizer.cjs.map +3 -3
- package/build/hooks/layout-child.cjs +47 -6
- package/build/hooks/layout-child.cjs.map +3 -3
- package/build/hooks/typography.cjs +2 -0
- package/build/hooks/typography.cjs.map +2 -2
- package/build/hooks/utils.cjs +4 -0
- package/build/hooks/utils.cjs.map +2 -2
- package/build/private-apis.cjs +2 -0
- package/build/private-apis.cjs.map +3 -3
- package/build/store/actions.cjs +2 -2
- package/build/store/actions.cjs.map +2 -2
- package/build-module/components/block-allowed-blocks/modal.mjs +2 -2
- package/build-module/components/block-allowed-blocks/modal.mjs.map +2 -2
- package/build-module/components/block-inspector/index.mjs +10 -9
- package/build-module/components/block-inspector/index.mjs.map +2 -2
- package/build-module/components/block-removal-warning-modal/index.mjs +34 -7
- package/build-module/components/block-removal-warning-modal/index.mjs.map +2 -2
- package/build-module/components/block-visibility/use-block-visibility.mjs +14 -29
- package/build-module/components/block-visibility/use-block-visibility.mjs.map +2 -2
- package/build-module/components/global-styles/hooks.mjs +7 -0
- package/build-module/components/global-styles/hooks.mjs.map +2 -2
- package/build-module/components/global-styles/typography-panel.mjs +73 -4
- package/build-module/components/global-styles/typography-panel.mjs.map +2 -2
- package/build-module/components/grid/grid-visualizer.mjs +50 -14
- package/build-module/components/grid/grid-visualizer.mjs.map +2 -2
- package/build-module/components/iframe/index.mjs +9 -2
- package/build-module/components/iframe/index.mjs.map +2 -2
- package/build-module/components/iframe/use-scale-canvas.mjs +1 -0
- package/build-module/components/iframe/use-scale-canvas.mjs.map +2 -2
- package/build-module/components/inspector-controls/last-item.mjs +23 -0
- package/build-module/components/inspector-controls/last-item.mjs.map +7 -0
- package/build-module/components/inspector-controls-tabs/styles-tab.mjs +3 -3
- package/build-module/components/inspector-controls-tabs/styles-tab.mjs.map +2 -2
- package/build-module/components/link-control/index.mjs +74 -3
- package/build-module/components/link-control/index.mjs.map +2 -2
- package/build-module/components/link-control/is-url-like.mjs +10 -3
- package/build-module/components/link-control/is-url-like.mjs.map +2 -2
- package/build-module/components/link-control/search-input.mjs +4 -1
- package/build-module/components/link-control/search-input.mjs.map +2 -2
- package/build-module/components/link-control/use-search-handler.mjs +2 -2
- package/build-module/components/link-control/use-search-handler.mjs.map +2 -2
- package/build-module/components/provider/use-block-sync.mjs +60 -8
- package/build-module/components/provider/use-block-sync.mjs.map +2 -2
- package/build-module/components/text-indent-control/index.mjs +110 -0
- package/build-module/components/text-indent-control/index.mjs.map +7 -0
- package/build-module/components/url-input/index.mjs +24 -4
- package/build-module/components/url-input/index.mjs.map +2 -2
- package/build-module/components/url-popover/image-url-input-ui.mjs +2 -2
- package/build-module/components/url-popover/image-url-input-ui.mjs.map +2 -2
- package/build-module/components/writing-flow/use-arrow-nav.mjs +0 -3
- package/build-module/components/writing-flow/use-arrow-nav.mjs.map +2 -2
- package/build-module/hooks/anchor.mjs +1 -1
- package/build-module/hooks/anchor.mjs.map +1 -1
- package/build-module/hooks/aria-label.mjs +2 -1
- package/build-module/hooks/aria-label.mjs.map +2 -2
- package/build-module/hooks/grid-visualizer.mjs +37 -6
- package/build-module/hooks/grid-visualizer.mjs.map +2 -2
- package/build-module/hooks/layout-child.mjs +37 -6
- package/build-module/hooks/layout-child.mjs.map +2 -2
- package/build-module/hooks/typography.mjs +2 -0
- package/build-module/hooks/typography.mjs.map +2 -2
- package/build-module/hooks/utils.mjs +4 -0
- package/build-module/hooks/utils.mjs.map +2 -2
- package/build-module/private-apis.mjs +2 -0
- package/build-module/private-apis.mjs.map +2 -2
- package/build-module/store/actions.mjs +2 -2
- package/build-module/store/actions.mjs.map +2 -2
- package/package.json +39 -39
- package/src/components/block-allowed-blocks/modal.js +2 -2
- package/src/components/block-inspector/index.js +19 -17
- package/src/components/block-removal-warning-modal/index.js +55 -19
- package/src/components/block-switcher/block-transformations-menu.native.js +1 -0
- package/src/components/block-toolbar/test/__snapshots__/block-toolbar-menu.native.js.snap +4 -6
- package/src/components/block-toolbar/test/block-toolbar-menu.native.js +2 -2
- package/src/components/block-visibility/use-block-visibility.js +17 -32
- package/src/components/global-styles/hooks.js +10 -0
- package/src/components/global-styles/typography-panel.js +78 -1
- package/src/components/grid/grid-visualizer.js +58 -12
- package/src/components/iframe/index.js +12 -2
- package/src/components/iframe/use-scale-canvas.js +1 -0
- package/src/components/inserter/menu.native.js +1 -0
- package/src/components/inspector-controls/last-item.js +29 -0
- package/src/components/inspector-controls-tabs/styles-tab.js +3 -3
- package/src/components/link-control/index.js +160 -3
- package/src/components/link-control/is-url-like.js +43 -8
- package/src/components/link-control/search-input.js +7 -0
- package/src/components/link-control/test/index.js +260 -0
- package/src/components/link-control/test/is-url-like.js +49 -1
- package/src/components/link-control/use-search-handler.js +2 -2
- package/src/components/provider/test/use-block-sync.js +105 -0
- package/src/components/provider/use-block-sync.js +118 -9
- package/src/components/text-indent-control/index.js +138 -0
- package/src/components/url-input/index.js +21 -2
- package/src/components/url-popover/image-url-input-ui.js +2 -2
- package/src/components/writing-flow/use-arrow-nav.js +0 -4
- package/src/hooks/anchor.js +1 -1
- package/src/hooks/aria-label.js +9 -1
- package/src/hooks/grid-visualizer.js +63 -24
- package/src/hooks/layout-child.js +45 -3
- package/src/hooks/typography.js +2 -0
- package/src/hooks/utils.js +4 -0
- package/src/private-apis.js +2 -0
- package/src/store/actions.js +8 -6
|
@@ -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": ";AAGA,SAAS,YAAY,gBAAgB;AACrC,SAAS,UAAU;AACnB,OAAO,gBAAgB;AAKvB,SAAS,gBAAgB;AACzB,OAAO,8BAA8B;AACrC,SAAS,mBAAmB;AAC5B,OAAO,sBAAsB;AAuBzB,
|
|
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,
|
|
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" ?
|
|
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,
|
|
5
|
-
"mappings": ";AAGA,SAAS,aAAa,
|
|
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) =>
|
|
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
|
-
|
|
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(
|
|
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": ";AAGA,SAAS,WAAW,cAAc;AAClC,SAAS,aAAa,iBAAiB;AACvC,SAAS,kBAAkB;AAK3B,SAAS,SAAS,wBAAwB;AAE1C,IAAM,OAAO,MAAM;AAAC;
|
|
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
|
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// packages/block-editor/src/components/text-indent-control/index.js
|
|
2
|
+
import {
|
|
3
|
+
__experimentalUnitControl as UnitControl,
|
|
4
|
+
__experimentalUseCustomUnits as useCustomUnits,
|
|
5
|
+
__experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue,
|
|
6
|
+
__experimentalView as View,
|
|
7
|
+
RangeControl,
|
|
8
|
+
__experimentalSpacer as Spacer,
|
|
9
|
+
Flex,
|
|
10
|
+
FlexItem,
|
|
11
|
+
BaseControl
|
|
12
|
+
} from "@wordpress/components";
|
|
13
|
+
import { __ } from "@wordpress/i18n";
|
|
14
|
+
import { useSettings } from "../use-settings/index.mjs";
|
|
15
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
function TextIndentControl({
|
|
17
|
+
__next40pxDefaultSize = false,
|
|
18
|
+
value,
|
|
19
|
+
onChange,
|
|
20
|
+
__unstableInputWidth = "60px",
|
|
21
|
+
withSlider = false,
|
|
22
|
+
hasBottomMargin = false,
|
|
23
|
+
help,
|
|
24
|
+
...otherProps
|
|
25
|
+
}) {
|
|
26
|
+
const [availableUnits] = useSettings("spacing.units");
|
|
27
|
+
const units = useCustomUnits({
|
|
28
|
+
availableUnits: availableUnits || [
|
|
29
|
+
"px",
|
|
30
|
+
"em",
|
|
31
|
+
"rem",
|
|
32
|
+
"ch",
|
|
33
|
+
"%",
|
|
34
|
+
"vw",
|
|
35
|
+
"vh"
|
|
36
|
+
],
|
|
37
|
+
defaultValues: { px: 16, em: 2, rem: 2, ch: 2 }
|
|
38
|
+
});
|
|
39
|
+
const [valueQuantity, valueUnit] = parseQuantityAndUnitFromRawValue(
|
|
40
|
+
value,
|
|
41
|
+
units
|
|
42
|
+
);
|
|
43
|
+
const isValueUnitRelative = !!valueUnit && ["em", "rem", "%", "ch", "vw", "vh"].includes(valueUnit);
|
|
44
|
+
if (!withSlider) {
|
|
45
|
+
return /* @__PURE__ */ jsx(
|
|
46
|
+
UnitControl,
|
|
47
|
+
{
|
|
48
|
+
__next40pxDefaultSize,
|
|
49
|
+
__shouldNotWarnDeprecated36pxSize: true,
|
|
50
|
+
...otherProps,
|
|
51
|
+
label: __("Line indent"),
|
|
52
|
+
value,
|
|
53
|
+
__unstableInputWidth,
|
|
54
|
+
units,
|
|
55
|
+
onChange,
|
|
56
|
+
help
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
return /* @__PURE__ */ jsxs(View, { style: hasBottomMargin ? { marginBottom: 12 } : void 0, children: [
|
|
61
|
+
/* @__PURE__ */ jsx(BaseControl.VisualLabel, { children: __("Line indent") }),
|
|
62
|
+
/* @__PURE__ */ jsxs(Flex, { children: [
|
|
63
|
+
/* @__PURE__ */ jsx(FlexItem, { isBlock: true, children: /* @__PURE__ */ jsx(
|
|
64
|
+
UnitControl,
|
|
65
|
+
{
|
|
66
|
+
__next40pxDefaultSize,
|
|
67
|
+
__shouldNotWarnDeprecated36pxSize: true,
|
|
68
|
+
label: __("Line indent"),
|
|
69
|
+
labelPosition: "top",
|
|
70
|
+
hideLabelFromVision: true,
|
|
71
|
+
value,
|
|
72
|
+
onChange,
|
|
73
|
+
size: otherProps.size,
|
|
74
|
+
units,
|
|
75
|
+
__unstableInputWidth,
|
|
76
|
+
min: 0
|
|
77
|
+
}
|
|
78
|
+
) }),
|
|
79
|
+
withSlider && /* @__PURE__ */ jsx(FlexItem, { isBlock: true, children: /* @__PURE__ */ jsx(Spacer, { marginX: 2, marginBottom: 0, children: /* @__PURE__ */ jsx(
|
|
80
|
+
RangeControl,
|
|
81
|
+
{
|
|
82
|
+
__next40pxDefaultSize,
|
|
83
|
+
__shouldNotWarnDeprecated36pxSize: true,
|
|
84
|
+
label: __("Line indent"),
|
|
85
|
+
hideLabelFromVision: true,
|
|
86
|
+
value: valueQuantity,
|
|
87
|
+
withInputField: false,
|
|
88
|
+
onChange: (newValue) => {
|
|
89
|
+
if (newValue === void 0) {
|
|
90
|
+
onChange?.(void 0);
|
|
91
|
+
} else {
|
|
92
|
+
onChange?.(
|
|
93
|
+
newValue + (valueUnit ?? "px")
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
min: 0,
|
|
98
|
+
max: isValueUnitRelative ? 10 : 100,
|
|
99
|
+
step: isValueUnitRelative ? 0.1 : 1,
|
|
100
|
+
initialPosition: 0
|
|
101
|
+
}
|
|
102
|
+
) }) })
|
|
103
|
+
] }),
|
|
104
|
+
help && /* @__PURE__ */ jsx("p", { className: "components-base-control__help", children: help })
|
|
105
|
+
] });
|
|
106
|
+
}
|
|
107
|
+
export {
|
|
108
|
+
TextIndentControl as default
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/components/text-indent-control/index.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {\n\t__experimentalUnitControl as UnitControl,\n\t__experimentalUseCustomUnits as useCustomUnits,\n\t__experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue,\n\t__experimentalView as View,\n\tRangeControl,\n\t__experimentalSpacer as Spacer,\n\tFlex,\n\tFlexItem,\n\tBaseControl,\n} from '@wordpress/components';\nimport { __ } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport { useSettings } from '../../components/use-settings';\n\n/**\n * Control for line text indent.\n *\n * @param {Object} props Component props.\n * @param {boolean} props.__next40pxDefaultSize Start opting into the larger default height that will become the default size in a future version.\n * @param {string} props.value Currently selected text indent.\n * @param {Function} props.onChange Handles change in text indent selection.\n * @param {string|number|undefined} props.__unstableInputWidth Input width to pass through to inner UnitControl. Should be a valid CSS value.\n * @param {boolean} props.withSlider Whether to show the slider control.\n * @param {boolean} props.hasBottomMargin Whether to add bottom margin below the control.\n * @param {string} props.help Help text to display below the control.\n *\n * @return {Element} Text indent control.\n */\nexport default function TextIndentControl( {\n\t__next40pxDefaultSize = false,\n\tvalue,\n\tonChange,\n\t__unstableInputWidth = '60px',\n\twithSlider = false,\n\thasBottomMargin = false,\n\thelp,\n\t...otherProps\n} ) {\n\tconst [ availableUnits ] = useSettings( 'spacing.units' );\n\tconst units = useCustomUnits( {\n\t\tavailableUnits: availableUnits || [\n\t\t\t'px',\n\t\t\t'em',\n\t\t\t'rem',\n\t\t\t'ch',\n\t\t\t'%',\n\t\t\t'vw',\n\t\t\t'vh',\n\t\t],\n\t\tdefaultValues: { px: 16, em: 2, rem: 2, ch: 2 },\n\t} );\n\n\tconst [ valueQuantity, valueUnit ] = parseQuantityAndUnitFromRawValue(\n\t\tvalue,\n\t\tunits\n\t);\n\tconst isValueUnitRelative =\n\t\t!! valueUnit &&\n\t\t[ 'em', 'rem', '%', 'ch', 'vw', 'vh' ].includes( valueUnit );\n\n\tif ( ! withSlider ) {\n\t\treturn (\n\t\t\t<UnitControl\n\t\t\t\t__next40pxDefaultSize={ __next40pxDefaultSize }\n\t\t\t\t__shouldNotWarnDeprecated36pxSize\n\t\t\t\t{ ...otherProps }\n\t\t\t\tlabel={ __( 'Line indent' ) }\n\t\t\t\tvalue={ value }\n\t\t\t\t__unstableInputWidth={ __unstableInputWidth }\n\t\t\t\tunits={ units }\n\t\t\t\tonChange={ onChange }\n\t\t\t\thelp={ help }\n\t\t\t/>\n\t\t);\n\t}\n\n\treturn (\n\t\t<View style={ hasBottomMargin ? { marginBottom: 12 } : undefined }>\n\t\t\t<BaseControl.VisualLabel>\n\t\t\t\t{ __( 'Line indent' ) }\n\t\t\t</BaseControl.VisualLabel>\n\t\t\t<Flex>\n\t\t\t\t<FlexItem isBlock>\n\t\t\t\t\t<UnitControl\n\t\t\t\t\t\t__next40pxDefaultSize={ __next40pxDefaultSize }\n\t\t\t\t\t\t__shouldNotWarnDeprecated36pxSize\n\t\t\t\t\t\tlabel={ __( 'Line indent' ) }\n\t\t\t\t\t\tlabelPosition=\"top\"\n\t\t\t\t\t\thideLabelFromVision\n\t\t\t\t\t\tvalue={ value }\n\t\t\t\t\t\tonChange={ onChange }\n\t\t\t\t\t\tsize={ otherProps.size }\n\t\t\t\t\t\tunits={ units }\n\t\t\t\t\t\t__unstableInputWidth={ __unstableInputWidth }\n\t\t\t\t\t\tmin={ 0 }\n\t\t\t\t\t/>\n\t\t\t\t</FlexItem>\n\t\t\t\t{ withSlider && (\n\t\t\t\t\t<FlexItem isBlock>\n\t\t\t\t\t\t<Spacer marginX={ 2 } marginBottom={ 0 }>\n\t\t\t\t\t\t\t<RangeControl\n\t\t\t\t\t\t\t\t__next40pxDefaultSize={ __next40pxDefaultSize }\n\t\t\t\t\t\t\t\t__shouldNotWarnDeprecated36pxSize\n\t\t\t\t\t\t\t\tlabel={ __( 'Line indent' ) }\n\t\t\t\t\t\t\t\thideLabelFromVision\n\t\t\t\t\t\t\t\tvalue={ valueQuantity }\n\t\t\t\t\t\t\t\twithInputField={ false }\n\t\t\t\t\t\t\t\tonChange={ ( newValue ) => {\n\t\t\t\t\t\t\t\t\tif ( newValue === undefined ) {\n\t\t\t\t\t\t\t\t\t\tonChange?.( undefined );\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tonChange?.(\n\t\t\t\t\t\t\t\t\t\t\tnewValue + ( valueUnit ?? 'px' )\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} }\n\t\t\t\t\t\t\t\tmin={ 0 }\n\t\t\t\t\t\t\t\tmax={ isValueUnitRelative ? 10 : 100 }\n\t\t\t\t\t\t\t\tstep={ isValueUnitRelative ? 0.1 : 1 }\n\t\t\t\t\t\t\t\tinitialPosition={ 0 }\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</Spacer>\n\t\t\t\t\t</FlexItem>\n\t\t\t\t) }\n\t\t\t</Flex>\n\t\t\t{ help && (\n\t\t\t\t<p className=\"components-base-control__help\">{ help }</p>\n\t\t\t) }\n\t\t</View>\n\t);\n}\n"],
|
|
5
|
+
"mappings": ";AAGA;AAAA,EACC,6BAA6B;AAAA,EAC7B,gCAAgC;AAAA,EAChC,kDAAkD;AAAA,EAClD,sBAAsB;AAAA,EACtB;AAAA,EACA,wBAAwB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,UAAU;AAKnB,SAAS,mBAAmB;AAkDzB,cAmBA,YAnBA;AAlCY,SAAR,kBAAoC;AAAA,EAC1C,wBAAwB;AAAA,EACxB;AAAA,EACA;AAAA,EACA,uBAAuB;AAAA,EACvB,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB;AAAA,EACA,GAAG;AACJ,GAAI;AACH,QAAM,CAAE,cAAe,IAAI,YAAa,eAAgB;AACxD,QAAM,QAAQ,eAAgB;AAAA,IAC7B,gBAAgB,kBAAkB;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,IACA,eAAe,EAAE,IAAI,IAAI,IAAI,GAAG,KAAK,GAAG,IAAI,EAAE;AAAA,EAC/C,CAAE;AAEF,QAAM,CAAE,eAAe,SAAU,IAAI;AAAA,IACpC;AAAA,IACA;AAAA,EACD;AACA,QAAM,sBACL,CAAC,CAAE,aACH,CAAE,MAAM,OAAO,KAAK,MAAM,MAAM,IAAK,EAAE,SAAU,SAAU;AAE5D,MAAK,CAAE,YAAa;AACnB,WACC;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA,mCAAiC;AAAA,QAC/B,GAAG;AAAA,QACL,OAAQ,GAAI,aAAc;AAAA,QAC1B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACD;AAAA,EAEF;AAEA,SACC,qBAAC,QAAK,OAAQ,kBAAkB,EAAE,cAAc,GAAG,IAAI,QACtD;AAAA,wBAAC,YAAY,aAAZ,EACE,aAAI,aAAc,GACrB;AAAA,IACA,qBAAC,QACA;AAAA,0BAAC,YAAS,SAAO,MAChB;AAAA,QAAC;AAAA;AAAA,UACA;AAAA,UACA,mCAAiC;AAAA,UACjC,OAAQ,GAAI,aAAc;AAAA,UAC1B,eAAc;AAAA,UACd,qBAAmB;AAAA,UACnB;AAAA,UACA;AAAA,UACA,MAAO,WAAW;AAAA,UAClB;AAAA,UACA;AAAA,UACA,KAAM;AAAA;AAAA,MACP,GACD;AAAA,MACE,cACD,oBAAC,YAAS,SAAO,MAChB,8BAAC,UAAO,SAAU,GAAI,cAAe,GACpC;AAAA,QAAC;AAAA;AAAA,UACA;AAAA,UACA,mCAAiC;AAAA,UACjC,OAAQ,GAAI,aAAc;AAAA,UAC1B,qBAAmB;AAAA,UACnB,OAAQ;AAAA,UACR,gBAAiB;AAAA,UACjB,UAAW,CAAE,aAAc;AAC1B,gBAAK,aAAa,QAAY;AAC7B,yBAAY,MAAU;AAAA,YACvB,OAAO;AACN;AAAA,gBACC,YAAa,aAAa;AAAA,cAC3B;AAAA,YACD;AAAA,UACD;AAAA,UACA,KAAM;AAAA,UACN,KAAM,sBAAsB,KAAK;AAAA,UACjC,MAAO,sBAAsB,MAAM;AAAA,UACnC,iBAAkB;AAAA;AAAA,MACnB,GACD,GACD;AAAA,OAEF;AAAA,IACE,QACD,oBAAC,OAAE,WAAU,iCAAkC,gBAAM;AAAA,KAEvD;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -6,10 +6,10 @@ import { UP, DOWN, ENTER, TAB } from "@wordpress/keycodes";
|
|
|
6
6
|
import {
|
|
7
7
|
BaseControl,
|
|
8
8
|
Button,
|
|
9
|
-
__experimentalInputControl as InputControl,
|
|
10
9
|
Spinner,
|
|
11
10
|
withSpokenMessages,
|
|
12
|
-
Popover
|
|
11
|
+
Popover,
|
|
12
|
+
privateApis as componentsPrivateApis
|
|
13
13
|
} from "@wordpress/components";
|
|
14
14
|
import {
|
|
15
15
|
compose,
|
|
@@ -20,8 +20,10 @@ import {
|
|
|
20
20
|
import { withSelect } from "@wordpress/data";
|
|
21
21
|
import { isURL } from "@wordpress/url";
|
|
22
22
|
import { store as blockEditorStore } from "../../store/index.mjs";
|
|
23
|
+
import { unlock } from "../../lock-unlock.mjs";
|
|
23
24
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
24
25
|
import { createElement } from "react";
|
|
26
|
+
var { ValidatedInputControl } = unlock(componentsPrivateApis);
|
|
25
27
|
function isFunction(maybeFunc) {
|
|
26
28
|
return typeof maybeFunc === "function";
|
|
27
29
|
}
|
|
@@ -293,7 +295,9 @@ var URLInput = class extends Component {
|
|
|
293
295
|
value = "",
|
|
294
296
|
hideLabelFromVision = false,
|
|
295
297
|
help = null,
|
|
296
|
-
disabled = false
|
|
298
|
+
disabled = false,
|
|
299
|
+
customValidity,
|
|
300
|
+
markWhenOptional
|
|
297
301
|
} = this.props;
|
|
298
302
|
const {
|
|
299
303
|
loading,
|
|
@@ -341,11 +345,27 @@ var URLInput = class extends Component {
|
|
|
341
345
|
suffix: this.props.suffix,
|
|
342
346
|
help
|
|
343
347
|
};
|
|
348
|
+
const validationProps = {
|
|
349
|
+
customValidity,
|
|
350
|
+
// Suppress the "(Required)" indicator in the label.
|
|
351
|
+
// The field is still required for validation, but the indicator
|
|
352
|
+
// can be hidden when markWhenOptional is set to true.
|
|
353
|
+
...markWhenOptional !== void 0 && {
|
|
354
|
+
markWhenOptional
|
|
355
|
+
}
|
|
356
|
+
};
|
|
344
357
|
if (renderControl) {
|
|
345
358
|
return renderControl(controlProps, inputProps, loading);
|
|
346
359
|
}
|
|
347
360
|
return /* @__PURE__ */ jsxs(BaseControl, { ...controlProps, children: [
|
|
348
|
-
/* @__PURE__ */ jsx(
|
|
361
|
+
/* @__PURE__ */ jsx(
|
|
362
|
+
ValidatedInputControl,
|
|
363
|
+
{
|
|
364
|
+
...inputProps,
|
|
365
|
+
...validationProps,
|
|
366
|
+
__next40pxDefaultSize: true
|
|
367
|
+
}
|
|
368
|
+
),
|
|
349
369
|
loading && /* @__PURE__ */ jsx(Spinner, {})
|
|
350
370
|
] });
|
|
351
371
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/url-input/index.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport { __, sprintf, _n } from '@wordpress/i18n';\nimport { Component, createRef } from '@wordpress/element';\nimport { UP, DOWN, ENTER, TAB } from '@wordpress/keycodes';\nimport {\n\tBaseControl,\n\tButton,\n\t__experimentalInputControl as InputControl,\n\tSpinner,\n\twithSpokenMessages,\n\tPopover,\n} from '@wordpress/components';\nimport {\n\tcompose,\n\tdebounce,\n\twithInstanceId,\n\twithSafeTimeout,\n} from '@wordpress/compose';\nimport { withSelect } from '@wordpress/data';\nimport { isURL } from '@wordpress/url';\n\n/**\n * Internal dependencies\n */\nimport { store as blockEditorStore } from '../../store';\n\n/**\n * Whether the argument is a function.\n *\n * @param {*} maybeFunc The argument to check.\n * @return {boolean} True if the argument is a function, false otherwise.\n */\nfunction isFunction( maybeFunc ) {\n\treturn typeof maybeFunc === 'function';\n}\n\nclass URLInput extends Component {\n\tconstructor( props ) {\n\t\tsuper( props );\n\n\t\tthis.onChange = this.onChange.bind( this );\n\t\tthis.onFocus = this.onFocus.bind( this );\n\t\tthis.onKeyDown = this.onKeyDown.bind( this );\n\t\tthis.selectLink = this.selectLink.bind( this );\n\t\tthis.handleOnClick = this.handleOnClick.bind( this );\n\t\tthis.bindSuggestionNode = this.bindSuggestionNode.bind( this );\n\t\tthis.autocompleteRef = props.autocompleteRef || createRef();\n\t\tthis.inputRef = props.inputRef || createRef();\n\t\tthis.updateSuggestions = debounce(\n\t\t\tthis.updateSuggestions.bind( this ),\n\t\t\t200\n\t\t);\n\n\t\tthis.suggestionNodes = [];\n\n\t\tthis.suggestionsRequest = null;\n\n\t\tthis.state = {\n\t\t\tsuggestions: [],\n\t\t\tshowSuggestions: false,\n\t\t\tsuggestionsValue: null,\n\t\t\tselectedSuggestion: null,\n\t\t\tsuggestionsListboxId: '',\n\t\t\tsuggestionOptionIdPrefix: '',\n\t\t};\n\t}\n\n\tcomponentDidUpdate( prevProps ) {\n\t\tconst { showSuggestions, selectedSuggestion } = this.state;\n\t\tconst { value, __experimentalShowInitialSuggestions = false } =\n\t\t\tthis.props;\n\n\t\t// Only have to worry about scrolling selected suggestion into view\n\t\t// when already expanded.\n\t\tif (\n\t\t\tshowSuggestions &&\n\t\t\tselectedSuggestion !== null &&\n\t\t\tthis.suggestionNodes[ selectedSuggestion ]\n\t\t) {\n\t\t\tthis.suggestionNodes[ selectedSuggestion ].scrollIntoView( {\n\t\t\t\tbehavior: 'instant',\n\t\t\t\tblock: 'nearest',\n\t\t\t\tinline: 'nearest',\n\t\t\t} );\n\t\t}\n\n\t\t// Update suggestions when the value changes.\n\t\tif ( prevProps.value !== value && ! this.props.disableSuggestions ) {\n\t\t\tif ( value?.length ) {\n\t\t\t\t// If the new value is not empty we need to update with suggestions for it.\n\t\t\t\tthis.updateSuggestions( value );\n\t\t\t} else if ( __experimentalShowInitialSuggestions ) {\n\t\t\t\t// If the new value is empty and we can show initial suggestions, then show initial suggestions.\n\t\t\t\tthis.updateSuggestions();\n\t\t\t}\n\t\t}\n\t}\n\n\tcomponentDidMount() {\n\t\tif ( this.shouldShowInitialSuggestions() ) {\n\t\t\tthis.updateSuggestions();\n\t\t}\n\t}\n\n\tcomponentWillUnmount() {\n\t\tthis.suggestionsRequest?.cancel?.();\n\t\tthis.suggestionsRequest = null;\n\t}\n\n\tbindSuggestionNode( index ) {\n\t\treturn ( ref ) => {\n\t\t\tthis.suggestionNodes[ index ] = ref;\n\t\t};\n\t}\n\n\tshouldShowInitialSuggestions() {\n\t\tconst { __experimentalShowInitialSuggestions = false, value } =\n\t\t\tthis.props;\n\t\treturn (\n\t\t\t__experimentalShowInitialSuggestions && ! ( value && value.length )\n\t\t);\n\t}\n\n\tupdateSuggestions( value = '' ) {\n\t\tconst {\n\t\t\t__experimentalFetchLinkSuggestions: fetchLinkSuggestions,\n\t\t\t__experimentalHandleURLSuggestions: handleURLSuggestions,\n\t\t} = this.props;\n\n\t\tif ( ! fetchLinkSuggestions ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Initial suggestions may only show if there is no value\n\t\t// (note: this includes whitespace).\n\t\tconst isInitialSuggestions = ! value?.length;\n\n\t\t// Trim only now we've determined whether or not it originally had a \"length\"\n\t\t// (even if that value was all whitespace).\n\t\tvalue = value.trim();\n\n\t\t// Allow a suggestions request if:\n\t\t// - there are at least 2 characters in the search input (except manual searches where\n\t\t// search input length is not required to trigger a fetch)\n\t\t// - this is a direct entry (eg: a URL)\n\t\tif (\n\t\t\t! isInitialSuggestions &&\n\t\t\t( value.length < 2 || ( ! handleURLSuggestions && isURL( value ) ) )\n\t\t) {\n\t\t\tthis.suggestionsRequest?.cancel?.();\n\t\t\tthis.suggestionsRequest = null;\n\n\t\t\tthis.setState( {\n\t\t\t\tsuggestions: [],\n\t\t\t\tshowSuggestions: false,\n\t\t\t\tsuggestionsValue: value,\n\t\t\t\tselectedSuggestion: null,\n\t\t\t\tloading: false,\n\t\t\t} );\n\n\t\t\treturn;\n\t\t}\n\n\t\tthis.setState( {\n\t\t\tselectedSuggestion: null,\n\t\t\tloading: true,\n\t\t} );\n\n\t\tconst request = fetchLinkSuggestions( value, {\n\t\t\tisInitialSuggestions,\n\t\t} );\n\n\t\trequest\n\t\t\t.then( ( suggestions ) => {\n\t\t\t\t// A fetch Promise doesn't have an abort option. It's mimicked by\n\t\t\t\t// comparing the request reference in on the instance, which is\n\t\t\t\t// reset or deleted on subsequent requests or unmounting.\n\t\t\t\tif ( this.suggestionsRequest !== request ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.setState( {\n\t\t\t\t\tsuggestions,\n\t\t\t\t\tsuggestionsValue: value,\n\t\t\t\t\tloading: false,\n\t\t\t\t\tshowSuggestions: !! suggestions.length,\n\t\t\t\t} );\n\n\t\t\t\tif ( !! suggestions.length ) {\n\t\t\t\t\tthis.props.debouncedSpeak(\n\t\t\t\t\t\tsprintf(\n\t\t\t\t\t\t\t/* translators: %d: number of results. */\n\t\t\t\t\t\t\t_n(\n\t\t\t\t\t\t\t\t'%d result found, use up and down arrow keys to navigate.',\n\t\t\t\t\t\t\t\t'%d results found, use up and down arrow keys to navigate.',\n\t\t\t\t\t\t\t\tsuggestions.length\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tsuggestions.length\n\t\t\t\t\t\t),\n\t\t\t\t\t\t'assertive'\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tthis.props.debouncedSpeak(\n\t\t\t\t\t\t__( 'No results.' ),\n\t\t\t\t\t\t'assertive'\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.catch( () => {\n\t\t\t\tif ( this.suggestionsRequest !== request ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.setState( {\n\t\t\t\t\tloading: false,\n\t\t\t\t} );\n\t\t\t} )\n\t\t\t.finally( () => {\n\t\t\t\t// If this is the current promise then reset the reference\n\t\t\t\t// to allow for checking if a new request is made.\n\t\t\t\tif ( this.suggestionsRequest === request ) {\n\t\t\t\t\tthis.suggestionsRequest = null;\n\t\t\t\t}\n\t\t\t} );\n\n\t\t// Note that this assignment is handled *before* the async search request\n\t\t// as a Promise always resolves on the next tick of the event loop.\n\t\tthis.suggestionsRequest = request;\n\t}\n\n\tonChange( newValue ) {\n\t\tthis.props.onChange( newValue );\n\t}\n\n\tonFocus() {\n\t\tconst { suggestions } = this.state;\n\t\tconst { disableSuggestions, value } = this.props;\n\n\t\t// When opening the link editor, if there's a value present, we want to load the suggestions pane with the results for this input search value\n\t\t// Don't re-run the suggestions on focus if there are already suggestions present (prevents searching again when tabbing between the input and buttons)\n\t\t// or there is already a request in progress.\n\t\tif (\n\t\t\tvalue &&\n\t\t\t! disableSuggestions &&\n\t\t\t! ( suggestions && suggestions.length ) &&\n\t\t\tthis.suggestionsRequest === null\n\t\t) {\n\t\t\t// Ensure the suggestions are updated with the current input value.\n\t\t\tthis.updateSuggestions( value );\n\t\t}\n\t}\n\n\tonKeyDown( event ) {\n\t\tthis.props.onKeyDown?.( event );\n\t\tconst { showSuggestions, selectedSuggestion, suggestions, loading } =\n\t\t\tthis.state;\n\n\t\t// If the suggestions are not shown or loading, we shouldn't handle the arrow keys\n\t\t// We shouldn't preventDefault to allow block arrow keys navigation.\n\t\tif ( ! showSuggestions || ! suggestions.length || loading ) {\n\t\t\t// In the Windows version of Firefox the up and down arrows don't move the caret\n\t\t\t// within an input field like they do for Mac Firefox/Chrome/Safari. This causes\n\t\t\t// a form of focus trapping that is disruptive to the user experience. This disruption\n\t\t\t// only happens if the caret is not in the first or last position in the text input.\n\t\t\t// See: https://github.com/WordPress/gutenberg/issues/5693#issuecomment-436684747\n\t\t\tswitch ( event.keyCode ) {\n\t\t\t\t// When UP is pressed, if the caret is at the start of the text, move it to the 0\n\t\t\t\t// position.\n\t\t\t\tcase UP: {\n\t\t\t\t\tif ( 0 !== event.target.selectionStart ) {\n\t\t\t\t\t\tevent.preventDefault();\n\n\t\t\t\t\t\t// Set the input caret to position 0.\n\t\t\t\t\t\tevent.target.setSelectionRange( 0, 0 );\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t// When DOWN is pressed, if the caret is not at the end of the text, move it to the\n\t\t\t\t// last position.\n\t\t\t\tcase DOWN: {\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis.props.value.length !== event.target.selectionStart\n\t\t\t\t\t) {\n\t\t\t\t\t\tevent.preventDefault();\n\n\t\t\t\t\t\t// Set the input caret to the last position.\n\t\t\t\t\t\tevent.target.setSelectionRange(\n\t\t\t\t\t\t\tthis.props.value.length,\n\t\t\t\t\t\t\tthis.props.value.length\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// Submitting while loading should trigger onSubmit.\n\t\t\t\tcase ENTER: {\n\t\t\t\t\tif ( this.props.onSubmit ) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tthis.props.onSubmit( null, event );\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst suggestion =\n\t\t\tthis.state.suggestions[ this.state.selectedSuggestion ];\n\n\t\tswitch ( event.keyCode ) {\n\t\t\tcase UP: {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tconst previousIndex = ! selectedSuggestion\n\t\t\t\t\t? suggestions.length - 1\n\t\t\t\t\t: selectedSuggestion - 1;\n\t\t\t\tthis.setState( {\n\t\t\t\t\tselectedSuggestion: previousIndex,\n\t\t\t\t} );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase DOWN: {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tconst nextIndex =\n\t\t\t\t\tselectedSuggestion === null ||\n\t\t\t\t\tselectedSuggestion === suggestions.length - 1\n\t\t\t\t\t\t? 0\n\t\t\t\t\t\t: selectedSuggestion + 1;\n\t\t\t\tthis.setState( {\n\t\t\t\t\tselectedSuggestion: nextIndex,\n\t\t\t\t} );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase TAB: {\n\t\t\t\tif ( this.state.selectedSuggestion !== null ) {\n\t\t\t\t\tthis.selectLink( suggestion );\n\t\t\t\t\t// Announce a link has been selected when tabbing away from the input field.\n\t\t\t\t\tthis.props.speak( __( 'Link selected.' ) );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ENTER: {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tif ( this.state.selectedSuggestion !== null ) {\n\t\t\t\t\tthis.selectLink( suggestion );\n\n\t\t\t\t\tif ( this.props.onSubmit ) {\n\t\t\t\t\t\tthis.props.onSubmit( suggestion, event );\n\t\t\t\t\t}\n\t\t\t\t} else if ( this.props.onSubmit ) {\n\t\t\t\t\tthis.props.onSubmit( null, event );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tselectLink( suggestion ) {\n\t\tthis.props.onChange( suggestion.url, suggestion );\n\t\tthis.setState( {\n\t\t\tselectedSuggestion: null,\n\t\t\tshowSuggestions: false,\n\t\t} );\n\t}\n\n\thandleOnClick( suggestion ) {\n\t\tthis.selectLink( suggestion );\n\t\t// Move focus to the input field when a link suggestion is clicked.\n\t\tthis.inputRef.current.focus();\n\t}\n\n\tstatic getDerivedStateFromProps(\n\t\t{\n\t\t\tvalue,\n\t\t\tinstanceId,\n\t\t\tdisableSuggestions,\n\t\t\t__experimentalShowInitialSuggestions = false,\n\t\t},\n\t\t{ showSuggestions }\n\t) {\n\t\tlet shouldShowSuggestions = showSuggestions;\n\n\t\tconst hasValue = value && value.length;\n\n\t\tif ( ! __experimentalShowInitialSuggestions && ! hasValue ) {\n\t\t\tshouldShowSuggestions = false;\n\t\t}\n\n\t\tif ( disableSuggestions === true ) {\n\t\t\tshouldShowSuggestions = false;\n\t\t}\n\n\t\treturn {\n\t\t\tshowSuggestions: shouldShowSuggestions,\n\t\t\tsuggestionsListboxId: `block-editor-url-input-suggestions-${ instanceId }`,\n\t\t\tsuggestionOptionIdPrefix: `block-editor-url-input-suggestion-${ instanceId }`,\n\t\t};\n\t}\n\n\trender() {\n\t\treturn (\n\t\t\t<>\n\t\t\t\t{ this.renderControl() }\n\t\t\t\t{ this.renderSuggestions() }\n\t\t\t</>\n\t\t);\n\t}\n\n\trenderControl() {\n\t\tconst {\n\t\t\tlabel = null,\n\t\t\tclassName,\n\t\t\tisFullWidth,\n\t\t\tinstanceId,\n\t\t\tplaceholder = __( 'Paste URL or type to search' ),\n\t\t\t__experimentalRenderControl: renderControl,\n\t\t\tvalue = '',\n\t\t\thideLabelFromVision = false,\n\t\t\thelp = null,\n\t\t\tdisabled = false,\n\t\t} = this.props;\n\n\t\tconst {\n\t\t\tloading,\n\t\t\tshowSuggestions,\n\t\t\tselectedSuggestion,\n\t\t\tsuggestionsListboxId,\n\t\t\tsuggestionOptionIdPrefix,\n\t\t} = this.state;\n\n\t\tconst inputId = `url-input-control-${ instanceId }`;\n\n\t\tconst controlProps = {\n\t\t\tid: inputId, // Passes attribute to label for the for attribute\n\t\t\tlabel,\n\t\t\tclassName: clsx( 'block-editor-url-input', className, {\n\t\t\t\t'is-full-width': isFullWidth,\n\t\t\t} ),\n\t\t\thideLabelFromVision,\n\t\t};\n\n\t\tconst inputProps = {\n\t\t\tid: inputId,\n\t\t\tvalue,\n\t\t\trequired: true,\n\t\t\ttype: 'text',\n\t\t\tname: inputId,\n\t\t\tautoComplete: 'off',\n\t\t\tonChange: disabled ? () => {} : this.onChange, // Disable onChange when disabled\n\t\t\tonFocus: disabled ? () => {} : this.onFocus, // Disable onFocus when disabled\n\t\t\tplaceholder,\n\t\t\tonKeyDown: disabled ? () => {} : this.onKeyDown, // Disable onKeyDown when disabled\n\t\t\trole: 'combobox',\n\t\t\t'aria-label': label ? undefined : __( 'URL' ), // Ensure input always has an accessible label\n\t\t\t'aria-expanded': showSuggestions,\n\t\t\t'aria-autocomplete': 'list',\n\t\t\t'aria-owns': suggestionsListboxId,\n\t\t\t'aria-activedescendant':\n\t\t\t\tselectedSuggestion !== null\n\t\t\t\t\t? `${ suggestionOptionIdPrefix }-${ selectedSuggestion }`\n\t\t\t\t\t: undefined,\n\t\t\tref: this.inputRef,\n\t\t\tdisabled,\n\t\t\tsuffix: this.props.suffix,\n\t\t\thelp,\n\t\t};\n\n\t\tif ( renderControl ) {\n\t\t\treturn renderControl( controlProps, inputProps, loading );\n\t\t}\n\n\t\treturn (\n\t\t\t<BaseControl { ...controlProps }>\n\t\t\t\t<InputControl { ...inputProps } __next40pxDefaultSize />\n\t\t\t\t{ loading && <Spinner /> }\n\t\t\t</BaseControl>\n\t\t);\n\t}\n\n\trenderSuggestions() {\n\t\tconst {\n\t\t\tclassName,\n\t\t\t__experimentalRenderSuggestions: renderSuggestions,\n\t\t} = this.props;\n\n\t\tconst {\n\t\t\tshowSuggestions,\n\t\t\tsuggestions,\n\t\t\tsuggestionsValue,\n\t\t\tselectedSuggestion,\n\t\t\tsuggestionsListboxId,\n\t\t\tsuggestionOptionIdPrefix,\n\t\t\tloading,\n\t\t} = this.state;\n\n\t\tif ( ! showSuggestions || suggestions.length === 0 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst suggestionsListProps = {\n\t\t\tid: suggestionsListboxId,\n\t\t\tref: this.autocompleteRef,\n\t\t\trole: 'listbox',\n\t\t};\n\n\t\tconst buildSuggestionItemProps = ( suggestion, index ) => {\n\t\t\treturn {\n\t\t\t\trole: 'option',\n\t\t\t\ttabIndex: '-1',\n\t\t\t\tid: `${ suggestionOptionIdPrefix }-${ index }`,\n\t\t\t\tref: this.bindSuggestionNode( index ),\n\t\t\t\t'aria-selected':\n\t\t\t\t\tindex === selectedSuggestion ? true : undefined,\n\t\t\t};\n\t\t};\n\n\t\tif ( isFunction( renderSuggestions ) ) {\n\t\t\treturn renderSuggestions( {\n\t\t\t\tsuggestions,\n\t\t\t\tselectedSuggestion,\n\t\t\t\tsuggestionsListProps,\n\t\t\t\tbuildSuggestionItemProps,\n\t\t\t\tisLoading: loading,\n\t\t\t\thandleSuggestionClick: this.handleOnClick,\n\t\t\t\tisInitialSuggestions: ! suggestionsValue?.length,\n\t\t\t\tcurrentInputValue: suggestionsValue,\n\t\t\t} );\n\t\t}\n\n\t\treturn (\n\t\t\t<Popover placement=\"bottom\" focusOnMount={ false }>\n\t\t\t\t<div\n\t\t\t\t\t{ ...suggestionsListProps }\n\t\t\t\t\tclassName={ clsx( 'block-editor-url-input__suggestions', {\n\t\t\t\t\t\t[ `${ className }__suggestions` ]: className,\n\t\t\t\t\t} ) }\n\t\t\t\t>\n\t\t\t\t\t{ suggestions.map( ( suggestion, index ) => (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\t\t\t{ ...buildSuggestionItemProps( suggestion, index ) }\n\t\t\t\t\t\t\tkey={ suggestion.id }\n\t\t\t\t\t\t\tclassName={ clsx(\n\t\t\t\t\t\t\t\t'block-editor-url-input__suggestion',\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t'is-selected': index === selectedSuggestion,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\tonClick={ () => this.handleOnClick( suggestion ) }\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{ suggestion.title }\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t) ) }\n\t\t\t\t</div>\n\t\t\t</Popover>\n\t\t);\n\t}\n}\n\n/**\n * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/url-input/README.md\n */\nexport default compose(\n\twithSafeTimeout,\n\twithSpokenMessages,\n\twithInstanceId,\n\twithSelect( ( select, props ) => {\n\t\t// If a link suggestions handler is already provided then\n\t\t// bail.\n\t\tif ( isFunction( props.__experimentalFetchLinkSuggestions ) ) {\n\t\t\treturn;\n\t\t}\n\t\tconst { getSettings } = select( blockEditorStore );\n\t\treturn {\n\t\t\t__experimentalFetchLinkSuggestions:\n\t\t\t\tgetSettings().__experimentalFetchLinkSuggestions,\n\t\t};\n\t} )\n)( URLInput );\n"],
|
|
5
|
-
"mappings": ";AAGA,OAAO,UAAU;AAKjB,SAAS,IAAI,SAAS,UAAU;AAChC,SAAS,WAAW,iBAAiB;AACrC,SAAS,IAAI,MAAM,OAAO,WAAW;AACrC;AAAA,EACC;AAAA,EACA;AAAA,EACA
|
|
4
|
+
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport { __, sprintf, _n } from '@wordpress/i18n';\nimport { Component, createRef } from '@wordpress/element';\nimport { UP, DOWN, ENTER, TAB } from '@wordpress/keycodes';\nimport {\n\tBaseControl,\n\tButton,\n\tSpinner,\n\twithSpokenMessages,\n\tPopover,\n\tprivateApis as componentsPrivateApis,\n} from '@wordpress/components';\nimport {\n\tcompose,\n\tdebounce,\n\twithInstanceId,\n\twithSafeTimeout,\n} from '@wordpress/compose';\nimport { withSelect } from '@wordpress/data';\nimport { isURL } from '@wordpress/url';\n\n/**\n * Internal dependencies\n */\nimport { store as blockEditorStore } from '../../store';\nimport { unlock } from '../../lock-unlock';\n\nconst { ValidatedInputControl } = unlock( componentsPrivateApis );\n\n/**\n * Whether the argument is a function.\n *\n * @param {*} maybeFunc The argument to check.\n * @return {boolean} True if the argument is a function, false otherwise.\n */\nfunction isFunction( maybeFunc ) {\n\treturn typeof maybeFunc === 'function';\n}\n\nclass URLInput extends Component {\n\tconstructor( props ) {\n\t\tsuper( props );\n\n\t\tthis.onChange = this.onChange.bind( this );\n\t\tthis.onFocus = this.onFocus.bind( this );\n\t\tthis.onKeyDown = this.onKeyDown.bind( this );\n\t\tthis.selectLink = this.selectLink.bind( this );\n\t\tthis.handleOnClick = this.handleOnClick.bind( this );\n\t\tthis.bindSuggestionNode = this.bindSuggestionNode.bind( this );\n\t\tthis.autocompleteRef = props.autocompleteRef || createRef();\n\t\tthis.inputRef = props.inputRef || createRef();\n\t\tthis.updateSuggestions = debounce(\n\t\t\tthis.updateSuggestions.bind( this ),\n\t\t\t200\n\t\t);\n\n\t\tthis.suggestionNodes = [];\n\n\t\tthis.suggestionsRequest = null;\n\n\t\tthis.state = {\n\t\t\tsuggestions: [],\n\t\t\tshowSuggestions: false,\n\t\t\tsuggestionsValue: null,\n\t\t\tselectedSuggestion: null,\n\t\t\tsuggestionsListboxId: '',\n\t\t\tsuggestionOptionIdPrefix: '',\n\t\t};\n\t}\n\n\tcomponentDidUpdate( prevProps ) {\n\t\tconst { showSuggestions, selectedSuggestion } = this.state;\n\t\tconst { value, __experimentalShowInitialSuggestions = false } =\n\t\t\tthis.props;\n\n\t\t// Only have to worry about scrolling selected suggestion into view\n\t\t// when already expanded.\n\t\tif (\n\t\t\tshowSuggestions &&\n\t\t\tselectedSuggestion !== null &&\n\t\t\tthis.suggestionNodes[ selectedSuggestion ]\n\t\t) {\n\t\t\tthis.suggestionNodes[ selectedSuggestion ].scrollIntoView( {\n\t\t\t\tbehavior: 'instant',\n\t\t\t\tblock: 'nearest',\n\t\t\t\tinline: 'nearest',\n\t\t\t} );\n\t\t}\n\n\t\t// Update suggestions when the value changes.\n\t\tif ( prevProps.value !== value && ! this.props.disableSuggestions ) {\n\t\t\tif ( value?.length ) {\n\t\t\t\t// If the new value is not empty we need to update with suggestions for it.\n\t\t\t\tthis.updateSuggestions( value );\n\t\t\t} else if ( __experimentalShowInitialSuggestions ) {\n\t\t\t\t// If the new value is empty and we can show initial suggestions, then show initial suggestions.\n\t\t\t\tthis.updateSuggestions();\n\t\t\t}\n\t\t}\n\t}\n\n\tcomponentDidMount() {\n\t\tif ( this.shouldShowInitialSuggestions() ) {\n\t\t\tthis.updateSuggestions();\n\t\t}\n\t}\n\n\tcomponentWillUnmount() {\n\t\tthis.suggestionsRequest?.cancel?.();\n\t\tthis.suggestionsRequest = null;\n\t}\n\n\tbindSuggestionNode( index ) {\n\t\treturn ( ref ) => {\n\t\t\tthis.suggestionNodes[ index ] = ref;\n\t\t};\n\t}\n\n\tshouldShowInitialSuggestions() {\n\t\tconst { __experimentalShowInitialSuggestions = false, value } =\n\t\t\tthis.props;\n\t\treturn (\n\t\t\t__experimentalShowInitialSuggestions && ! ( value && value.length )\n\t\t);\n\t}\n\n\tupdateSuggestions( value = '' ) {\n\t\tconst {\n\t\t\t__experimentalFetchLinkSuggestions: fetchLinkSuggestions,\n\t\t\t__experimentalHandleURLSuggestions: handleURLSuggestions,\n\t\t} = this.props;\n\n\t\tif ( ! fetchLinkSuggestions ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Initial suggestions may only show if there is no value\n\t\t// (note: this includes whitespace).\n\t\tconst isInitialSuggestions = ! value?.length;\n\n\t\t// Trim only now we've determined whether or not it originally had a \"length\"\n\t\t// (even if that value was all whitespace).\n\t\tvalue = value.trim();\n\n\t\t// Allow a suggestions request if:\n\t\t// - there are at least 2 characters in the search input (except manual searches where\n\t\t// search input length is not required to trigger a fetch)\n\t\t// - this is a direct entry (eg: a URL)\n\t\tif (\n\t\t\t! isInitialSuggestions &&\n\t\t\t( value.length < 2 || ( ! handleURLSuggestions && isURL( value ) ) )\n\t\t) {\n\t\t\tthis.suggestionsRequest?.cancel?.();\n\t\t\tthis.suggestionsRequest = null;\n\n\t\t\tthis.setState( {\n\t\t\t\tsuggestions: [],\n\t\t\t\tshowSuggestions: false,\n\t\t\t\tsuggestionsValue: value,\n\t\t\t\tselectedSuggestion: null,\n\t\t\t\tloading: false,\n\t\t\t} );\n\n\t\t\treturn;\n\t\t}\n\n\t\tthis.setState( {\n\t\t\tselectedSuggestion: null,\n\t\t\tloading: true,\n\t\t} );\n\n\t\tconst request = fetchLinkSuggestions( value, {\n\t\t\tisInitialSuggestions,\n\t\t} );\n\n\t\trequest\n\t\t\t.then( ( suggestions ) => {\n\t\t\t\t// A fetch Promise doesn't have an abort option. It's mimicked by\n\t\t\t\t// comparing the request reference in on the instance, which is\n\t\t\t\t// reset or deleted on subsequent requests or unmounting.\n\t\t\t\tif ( this.suggestionsRequest !== request ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.setState( {\n\t\t\t\t\tsuggestions,\n\t\t\t\t\tsuggestionsValue: value,\n\t\t\t\t\tloading: false,\n\t\t\t\t\tshowSuggestions: !! suggestions.length,\n\t\t\t\t} );\n\n\t\t\t\tif ( !! suggestions.length ) {\n\t\t\t\t\tthis.props.debouncedSpeak(\n\t\t\t\t\t\tsprintf(\n\t\t\t\t\t\t\t/* translators: %d: number of results. */\n\t\t\t\t\t\t\t_n(\n\t\t\t\t\t\t\t\t'%d result found, use up and down arrow keys to navigate.',\n\t\t\t\t\t\t\t\t'%d results found, use up and down arrow keys to navigate.',\n\t\t\t\t\t\t\t\tsuggestions.length\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tsuggestions.length\n\t\t\t\t\t\t),\n\t\t\t\t\t\t'assertive'\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tthis.props.debouncedSpeak(\n\t\t\t\t\t\t__( 'No results.' ),\n\t\t\t\t\t\t'assertive'\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.catch( () => {\n\t\t\t\tif ( this.suggestionsRequest !== request ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.setState( {\n\t\t\t\t\tloading: false,\n\t\t\t\t} );\n\t\t\t} )\n\t\t\t.finally( () => {\n\t\t\t\t// If this is the current promise then reset the reference\n\t\t\t\t// to allow for checking if a new request is made.\n\t\t\t\tif ( this.suggestionsRequest === request ) {\n\t\t\t\t\tthis.suggestionsRequest = null;\n\t\t\t\t}\n\t\t\t} );\n\n\t\t// Note that this assignment is handled *before* the async search request\n\t\t// as a Promise always resolves on the next tick of the event loop.\n\t\tthis.suggestionsRequest = request;\n\t}\n\n\tonChange( newValue ) {\n\t\tthis.props.onChange( newValue );\n\t}\n\n\tonFocus() {\n\t\tconst { suggestions } = this.state;\n\t\tconst { disableSuggestions, value } = this.props;\n\n\t\t// When opening the link editor, if there's a value present, we want to load the suggestions pane with the results for this input search value\n\t\t// Don't re-run the suggestions on focus if there are already suggestions present (prevents searching again when tabbing between the input and buttons)\n\t\t// or there is already a request in progress.\n\t\tif (\n\t\t\tvalue &&\n\t\t\t! disableSuggestions &&\n\t\t\t! ( suggestions && suggestions.length ) &&\n\t\t\tthis.suggestionsRequest === null\n\t\t) {\n\t\t\t// Ensure the suggestions are updated with the current input value.\n\t\t\tthis.updateSuggestions( value );\n\t\t}\n\t}\n\n\tonKeyDown( event ) {\n\t\tthis.props.onKeyDown?.( event );\n\t\tconst { showSuggestions, selectedSuggestion, suggestions, loading } =\n\t\t\tthis.state;\n\n\t\t// If the suggestions are not shown or loading, we shouldn't handle the arrow keys\n\t\t// We shouldn't preventDefault to allow block arrow keys navigation.\n\t\tif ( ! showSuggestions || ! suggestions.length || loading ) {\n\t\t\t// In the Windows version of Firefox the up and down arrows don't move the caret\n\t\t\t// within an input field like they do for Mac Firefox/Chrome/Safari. This causes\n\t\t\t// a form of focus trapping that is disruptive to the user experience. This disruption\n\t\t\t// only happens if the caret is not in the first or last position in the text input.\n\t\t\t// See: https://github.com/WordPress/gutenberg/issues/5693#issuecomment-436684747\n\t\t\tswitch ( event.keyCode ) {\n\t\t\t\t// When UP is pressed, if the caret is at the start of the text, move it to the 0\n\t\t\t\t// position.\n\t\t\t\tcase UP: {\n\t\t\t\t\tif ( 0 !== event.target.selectionStart ) {\n\t\t\t\t\t\tevent.preventDefault();\n\n\t\t\t\t\t\t// Set the input caret to position 0.\n\t\t\t\t\t\tevent.target.setSelectionRange( 0, 0 );\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t// When DOWN is pressed, if the caret is not at the end of the text, move it to the\n\t\t\t\t// last position.\n\t\t\t\tcase DOWN: {\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis.props.value.length !== event.target.selectionStart\n\t\t\t\t\t) {\n\t\t\t\t\t\tevent.preventDefault();\n\n\t\t\t\t\t\t// Set the input caret to the last position.\n\t\t\t\t\t\tevent.target.setSelectionRange(\n\t\t\t\t\t\t\tthis.props.value.length,\n\t\t\t\t\t\t\tthis.props.value.length\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// Submitting while loading should trigger onSubmit.\n\t\t\t\tcase ENTER: {\n\t\t\t\t\tif ( this.props.onSubmit ) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tthis.props.onSubmit( null, event );\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst suggestion =\n\t\t\tthis.state.suggestions[ this.state.selectedSuggestion ];\n\n\t\tswitch ( event.keyCode ) {\n\t\t\tcase UP: {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tconst previousIndex = ! selectedSuggestion\n\t\t\t\t\t? suggestions.length - 1\n\t\t\t\t\t: selectedSuggestion - 1;\n\t\t\t\tthis.setState( {\n\t\t\t\t\tselectedSuggestion: previousIndex,\n\t\t\t\t} );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase DOWN: {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tconst nextIndex =\n\t\t\t\t\tselectedSuggestion === null ||\n\t\t\t\t\tselectedSuggestion === suggestions.length - 1\n\t\t\t\t\t\t? 0\n\t\t\t\t\t\t: selectedSuggestion + 1;\n\t\t\t\tthis.setState( {\n\t\t\t\t\tselectedSuggestion: nextIndex,\n\t\t\t\t} );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase TAB: {\n\t\t\t\tif ( this.state.selectedSuggestion !== null ) {\n\t\t\t\t\tthis.selectLink( suggestion );\n\t\t\t\t\t// Announce a link has been selected when tabbing away from the input field.\n\t\t\t\t\tthis.props.speak( __( 'Link selected.' ) );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ENTER: {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tif ( this.state.selectedSuggestion !== null ) {\n\t\t\t\t\tthis.selectLink( suggestion );\n\n\t\t\t\t\tif ( this.props.onSubmit ) {\n\t\t\t\t\t\tthis.props.onSubmit( suggestion, event );\n\t\t\t\t\t}\n\t\t\t\t} else if ( this.props.onSubmit ) {\n\t\t\t\t\tthis.props.onSubmit( null, event );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tselectLink( suggestion ) {\n\t\tthis.props.onChange( suggestion.url, suggestion );\n\t\tthis.setState( {\n\t\t\tselectedSuggestion: null,\n\t\t\tshowSuggestions: false,\n\t\t} );\n\t}\n\n\thandleOnClick( suggestion ) {\n\t\tthis.selectLink( suggestion );\n\t\t// Move focus to the input field when a link suggestion is clicked.\n\t\tthis.inputRef.current.focus();\n\t}\n\n\tstatic getDerivedStateFromProps(\n\t\t{\n\t\t\tvalue,\n\t\t\tinstanceId,\n\t\t\tdisableSuggestions,\n\t\t\t__experimentalShowInitialSuggestions = false,\n\t\t},\n\t\t{ showSuggestions }\n\t) {\n\t\tlet shouldShowSuggestions = showSuggestions;\n\n\t\tconst hasValue = value && value.length;\n\n\t\tif ( ! __experimentalShowInitialSuggestions && ! hasValue ) {\n\t\t\tshouldShowSuggestions = false;\n\t\t}\n\n\t\tif ( disableSuggestions === true ) {\n\t\t\tshouldShowSuggestions = false;\n\t\t}\n\n\t\treturn {\n\t\t\tshowSuggestions: shouldShowSuggestions,\n\t\t\tsuggestionsListboxId: `block-editor-url-input-suggestions-${ instanceId }`,\n\t\t\tsuggestionOptionIdPrefix: `block-editor-url-input-suggestion-${ instanceId }`,\n\t\t};\n\t}\n\n\trender() {\n\t\treturn (\n\t\t\t<>\n\t\t\t\t{ this.renderControl() }\n\t\t\t\t{ this.renderSuggestions() }\n\t\t\t</>\n\t\t);\n\t}\n\n\trenderControl() {\n\t\tconst {\n\t\t\tlabel = null,\n\t\t\tclassName,\n\t\t\tisFullWidth,\n\t\t\tinstanceId,\n\t\t\tplaceholder = __( 'Paste URL or type to search' ),\n\t\t\t__experimentalRenderControl: renderControl,\n\t\t\tvalue = '',\n\t\t\thideLabelFromVision = false,\n\t\t\thelp = null,\n\t\t\tdisabled = false,\n\t\t\tcustomValidity,\n\t\t\tmarkWhenOptional,\n\t\t} = this.props;\n\n\t\tconst {\n\t\t\tloading,\n\t\t\tshowSuggestions,\n\t\t\tselectedSuggestion,\n\t\t\tsuggestionsListboxId,\n\t\t\tsuggestionOptionIdPrefix,\n\t\t} = this.state;\n\n\t\tconst inputId = `url-input-control-${ instanceId }`;\n\n\t\tconst controlProps = {\n\t\t\tid: inputId, // Passes attribute to label for the for attribute\n\t\t\tlabel,\n\t\t\tclassName: clsx( 'block-editor-url-input', className, {\n\t\t\t\t'is-full-width': isFullWidth,\n\t\t\t} ),\n\t\t\thideLabelFromVision,\n\t\t};\n\n\t\tconst inputProps = {\n\t\t\tid: inputId,\n\t\t\tvalue,\n\t\t\trequired: true,\n\t\t\ttype: 'text',\n\t\t\tname: inputId,\n\t\t\tautoComplete: 'off',\n\t\t\tonChange: disabled ? () => {} : this.onChange, // Disable onChange when disabled\n\t\t\tonFocus: disabled ? () => {} : this.onFocus, // Disable onFocus when disabled\n\t\t\tplaceholder,\n\t\t\tonKeyDown: disabled ? () => {} : this.onKeyDown, // Disable onKeyDown when disabled\n\t\t\trole: 'combobox',\n\t\t\t'aria-label': label ? undefined : __( 'URL' ), // Ensure input always has an accessible label\n\t\t\t'aria-expanded': showSuggestions,\n\t\t\t'aria-autocomplete': 'list',\n\t\t\t'aria-owns': suggestionsListboxId,\n\t\t\t'aria-activedescendant':\n\t\t\t\tselectedSuggestion !== null\n\t\t\t\t\t? `${ suggestionOptionIdPrefix }-${ selectedSuggestion }`\n\t\t\t\t\t: undefined,\n\t\t\tref: this.inputRef,\n\t\t\tdisabled,\n\t\t\tsuffix: this.props.suffix,\n\t\t\thelp,\n\t\t};\n\n\t\tconst validationProps = {\n\t\t\tcustomValidity,\n\t\t\t// Suppress the \"(Required)\" indicator in the label.\n\t\t\t// The field is still required for validation, but the indicator\n\t\t\t// can be hidden when markWhenOptional is set to true.\n\t\t\t...( markWhenOptional !== undefined && {\n\t\t\t\tmarkWhenOptional,\n\t\t\t} ),\n\t\t};\n\n\t\tif ( renderControl ) {\n\t\t\treturn renderControl( controlProps, inputProps, loading );\n\t\t}\n\n\t\treturn (\n\t\t\t<BaseControl { ...controlProps }>\n\t\t\t\t<ValidatedInputControl\n\t\t\t\t\t{ ...inputProps }\n\t\t\t\t\t{ ...validationProps }\n\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t/>\n\t\t\t\t{ loading && <Spinner /> }\n\t\t\t</BaseControl>\n\t\t);\n\t}\n\n\trenderSuggestions() {\n\t\tconst {\n\t\t\tclassName,\n\t\t\t__experimentalRenderSuggestions: renderSuggestions,\n\t\t} = this.props;\n\n\t\tconst {\n\t\t\tshowSuggestions,\n\t\t\tsuggestions,\n\t\t\tsuggestionsValue,\n\t\t\tselectedSuggestion,\n\t\t\tsuggestionsListboxId,\n\t\t\tsuggestionOptionIdPrefix,\n\t\t\tloading,\n\t\t} = this.state;\n\n\t\tif ( ! showSuggestions || suggestions.length === 0 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst suggestionsListProps = {\n\t\t\tid: suggestionsListboxId,\n\t\t\tref: this.autocompleteRef,\n\t\t\trole: 'listbox',\n\t\t};\n\n\t\tconst buildSuggestionItemProps = ( suggestion, index ) => {\n\t\t\treturn {\n\t\t\t\trole: 'option',\n\t\t\t\ttabIndex: '-1',\n\t\t\t\tid: `${ suggestionOptionIdPrefix }-${ index }`,\n\t\t\t\tref: this.bindSuggestionNode( index ),\n\t\t\t\t'aria-selected':\n\t\t\t\t\tindex === selectedSuggestion ? true : undefined,\n\t\t\t};\n\t\t};\n\n\t\tif ( isFunction( renderSuggestions ) ) {\n\t\t\treturn renderSuggestions( {\n\t\t\t\tsuggestions,\n\t\t\t\tselectedSuggestion,\n\t\t\t\tsuggestionsListProps,\n\t\t\t\tbuildSuggestionItemProps,\n\t\t\t\tisLoading: loading,\n\t\t\t\thandleSuggestionClick: this.handleOnClick,\n\t\t\t\tisInitialSuggestions: ! suggestionsValue?.length,\n\t\t\t\tcurrentInputValue: suggestionsValue,\n\t\t\t} );\n\t\t}\n\n\t\treturn (\n\t\t\t<Popover placement=\"bottom\" focusOnMount={ false }>\n\t\t\t\t<div\n\t\t\t\t\t{ ...suggestionsListProps }\n\t\t\t\t\tclassName={ clsx( 'block-editor-url-input__suggestions', {\n\t\t\t\t\t\t[ `${ className }__suggestions` ]: className,\n\t\t\t\t\t} ) }\n\t\t\t\t>\n\t\t\t\t\t{ suggestions.map( ( suggestion, index ) => (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\t\t\t{ ...buildSuggestionItemProps( suggestion, index ) }\n\t\t\t\t\t\t\tkey={ suggestion.id }\n\t\t\t\t\t\t\tclassName={ clsx(\n\t\t\t\t\t\t\t\t'block-editor-url-input__suggestion',\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t'is-selected': index === selectedSuggestion,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\tonClick={ () => this.handleOnClick( suggestion ) }\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{ suggestion.title }\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t) ) }\n\t\t\t\t</div>\n\t\t\t</Popover>\n\t\t);\n\t}\n}\n\n/**\n * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/url-input/README.md\n */\nexport default compose(\n\twithSafeTimeout,\n\twithSpokenMessages,\n\twithInstanceId,\n\twithSelect( ( select, props ) => {\n\t\t// If a link suggestions handler is already provided then\n\t\t// bail.\n\t\tif ( isFunction( props.__experimentalFetchLinkSuggestions ) ) {\n\t\t\treturn;\n\t\t}\n\t\tconst { getSettings } = select( blockEditorStore );\n\t\treturn {\n\t\t\t__experimentalFetchLinkSuggestions:\n\t\t\t\tgetSettings().__experimentalFetchLinkSuggestions,\n\t\t};\n\t} )\n)( URLInput );\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|