@wordpress/block-editor 16.0.0 → 16.1.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 +18 -0
- package/README.md +8 -0
- package/build/components/alignment-control/ui.cjs +2 -4
- package/build/components/alignment-control/ui.cjs.map +2 -2
- package/build/components/background-image-control/index.cjs +40 -10
- package/build/components/background-image-control/index.cjs.map +2 -2
- package/build/components/block-alignment-control/ui.cjs +5 -3
- package/build/components/block-alignment-control/ui.cjs.map +2 -2
- package/build/components/block-inspector/index.cjs +73 -46
- package/build/components/block-inspector/index.cjs.map +2 -2
- package/build/components/block-list/block-html.cjs +4 -1
- package/build/components/block-list/block-html.cjs.map +2 -2
- package/build/components/block-list/use-block-props/index.cjs +5 -2
- package/build/components/block-list/use-block-props/index.cjs.map +2 -2
- package/build/components/block-list/use-block-props/use-focus-handler.cjs +2 -3
- package/build/components/block-list/use-block-props/use-focus-handler.cjs.map +2 -2
- package/build/components/block-list/use-block-props/use-register-block-event-handlers.cjs +48 -0
- package/build/components/block-list/use-block-props/use-register-block-event-handlers.cjs.map +7 -0
- package/build/components/block-parent-selector/index.cjs +2 -2
- package/build/components/block-parent-selector/index.cjs.map +2 -2
- package/build/components/block-toolbar/switch-section-style.cjs +4 -2
- package/build/components/block-toolbar/switch-section-style.cjs.map +3 -3
- package/build/components/block-tools/empty-block-inserter.cjs +2 -7
- package/build/components/block-tools/empty-block-inserter.cjs.map +2 -2
- package/build/components/block-vertical-alignment-control/ui.cjs +3 -5
- package/build/components/block-vertical-alignment-control/ui.cjs.map +2 -2
- package/build/components/border-radius-control/utils.cjs +8 -58
- package/build/components/border-radius-control/utils.cjs.map +2 -2
- package/build/components/colors-gradients/control.cjs +5 -3
- package/build/components/colors-gradients/control.cjs.map +2 -2
- package/build/components/dimension-control/index.cjs +30 -20
- package/build/components/dimension-control/index.cjs.map +3 -3
- package/build/components/dimensions-tool/aspect-ratio-tool.cjs +9 -2
- package/build/components/dimensions-tool/aspect-ratio-tool.cjs.map +3 -3
- package/build/components/editor-styles/index.cjs +9 -1
- package/build/components/editor-styles/index.cjs.map +2 -2
- package/build/components/global-styles/background-panel.cjs +66 -25
- package/build/components/global-styles/background-panel.cjs.map +3 -3
- package/build/components/global-styles/border-panel.cjs +153 -55
- package/build/components/global-styles/border-panel.cjs.map +3 -3
- package/build/components/global-styles/color-gradient-dropdown-item.cjs +46 -14
- package/build/components/global-styles/color-gradient-dropdown-item.cjs.map +3 -3
- package/build/components/global-styles/color-panel.cjs +63 -17
- package/build/components/global-styles/color-panel.cjs.map +2 -2
- package/build/components/global-styles/dimensions-panel.cjs +242 -64
- package/build/components/global-styles/dimensions-panel.cjs.map +3 -3
- package/build/components/global-styles/filters-panel.cjs +59 -20
- package/build/components/global-styles/filters-panel.cjs.map +3 -3
- package/build/components/global-styles/hooks.cjs +4 -1
- package/build/components/global-styles/hooks.cjs.map +2 -2
- package/build/components/global-styles/inheritance/index.cjs +142 -0
- package/build/components/global-styles/inheritance/index.cjs.map +7 -0
- package/build/components/global-styles/inherited-value-context.cjs +173 -0
- package/build/components/global-styles/inherited-value-context.cjs.map +7 -0
- package/build/components/global-styles/shadow-panel-components.cjs +38 -20
- package/build/components/global-styles/shadow-panel-components.cjs.map +2 -2
- package/build/components/global-styles/state-control.cjs +1 -1
- package/build/components/global-styles/state-control.cjs.map +2 -2
- package/build/components/global-styles/typography-panel.cjs +271 -78
- package/build/components/global-styles/typography-panel.cjs.map +3 -3
- package/build/components/inspector-controls-tabs/styles-tab.cjs +10 -1
- package/build/components/inspector-controls-tabs/styles-tab.cjs.map +2 -2
- package/build/components/line-height-control/index.cjs +1 -1
- package/build/components/line-height-control/index.cjs.map +2 -2
- package/build/components/link-control/index.cjs +3 -1
- package/build/components/link-control/index.cjs.map +2 -2
- package/build/components/preset-input-control/index.cjs +2 -1
- package/build/components/preset-input-control/index.cjs.map +2 -2
- package/build/components/provider/block-refs-provider.cjs +8 -2
- package/build/components/provider/block-refs-provider.cjs.map +2 -2
- package/build/components/provider/index.cjs +1 -1
- package/build/components/provider/index.cjs.map +2 -2
- package/build/components/provider/use-block-sync.cjs +18 -6
- package/build/components/provider/use-block-sync.cjs.map +2 -2
- package/build/components/provider/use-media-upload-settings.cjs +3 -1
- package/build/components/provider/use-media-upload-settings.cjs.map +2 -2
- package/build/components/rich-text/index.cjs +23 -13
- package/build/components/rich-text/index.cjs.map +2 -2
- package/build/components/spacing-sizes-control/utils.cjs +6 -19
- package/build/components/spacing-sizes-control/utils.cjs.map +2 -2
- package/build/components/text-indent-control/index.cjs +8 -2
- package/build/components/text-indent-control/index.cjs.map +2 -2
- package/build/components/url-input/index.cjs +303 -344
- package/build/components/url-input/index.cjs.map +3 -3
- package/build/components/writing-flow/index.cjs +2 -0
- package/build/components/writing-flow/index.cjs.map +3 -3
- package/build/components/writing-flow/use-arrow-nav.cjs +24 -1
- package/build/components/writing-flow/use-arrow-nav.cjs.map +2 -2
- package/build/components/writing-flow/use-click-selection.cjs +28 -2
- package/build/components/writing-flow/use-click-selection.cjs.map +2 -2
- package/build/components/writing-flow/use-editable-root-event-handlers.cjs +179 -0
- package/build/components/writing-flow/use-editable-root-event-handlers.cjs.map +7 -0
- package/build/components/writing-flow/use-editable-root.cjs +5 -42
- package/build/components/writing-flow/use-editable-root.cjs.map +2 -2
- package/build/components/writing-flow/use-home-end.cjs +1 -1
- package/build/components/writing-flow/use-home-end.cjs.map +2 -2
- package/build/components/writing-flow/use-selection-observer.cjs +17 -13
- package/build/components/writing-flow/use-selection-observer.cjs.map +2 -2
- package/build/components/writing-flow/utils.cjs +3 -14
- package/build/components/writing-flow/utils.cjs.map +2 -2
- package/build/hooks/background.cjs +13 -10
- package/build/hooks/background.cjs.map +2 -2
- package/build/hooks/block-style-variation.cjs +4 -45
- package/build/hooks/block-style-variation.cjs.map +3 -3
- package/build/hooks/border.cjs +19 -4
- package/build/hooks/border.cjs.map +2 -2
- package/build/hooks/custom-css.cjs +6 -2
- package/build/hooks/custom-css.cjs.map +2 -2
- package/build/hooks/dimensions.cjs +15 -4
- package/build/hooks/dimensions.cjs.map +2 -2
- package/build/hooks/duotone.cjs +26 -14
- package/build/hooks/duotone.cjs.map +3 -3
- package/build/hooks/elements.cjs +14 -4
- package/build/hooks/elements.cjs.map +2 -2
- package/build/hooks/line-height.cjs +1 -2
- package/build/hooks/line-height.cjs.map +2 -2
- package/build/hooks/typography.cjs +13 -4
- package/build/hooks/typography.cjs.map +2 -2
- package/build/private-apis.cjs +9 -5
- package/build/private-apis.cjs.map +3 -3
- package/build/store/actions.cjs +9 -4
- package/build/store/actions.cjs.map +2 -2
- package/build/store/private-selectors.cjs +28 -1
- package/build/store/private-selectors.cjs.map +2 -2
- package/build/store/reducer.cjs +6 -6
- package/build/store/reducer.cjs.map +2 -2
- package/build/store/selectors.cjs +23 -0
- package/build/store/selectors.cjs.map +2 -2
- package/build/utils/native-undo.cjs +55 -0
- package/build/utils/native-undo.cjs.map +7 -0
- package/build-module/components/alignment-control/ui.mjs +2 -4
- package/build-module/components/alignment-control/ui.mjs.map +2 -2
- package/build-module/components/background-image-control/index.mjs +43 -10
- package/build-module/components/background-image-control/index.mjs.map +2 -2
- package/build-module/components/block-alignment-control/ui.mjs +5 -3
- package/build-module/components/block-alignment-control/ui.mjs.map +2 -2
- package/build-module/components/block-inspector/index.mjs +74 -46
- package/build-module/components/block-inspector/index.mjs.map +2 -2
- package/build-module/components/block-list/block-html.mjs +4 -1
- package/build-module/components/block-list/block-html.mjs.map +2 -2
- package/build-module/components/block-list/use-block-props/index.mjs +5 -2
- package/build-module/components/block-list/use-block-props/index.mjs.map +2 -2
- package/build-module/components/block-list/use-block-props/use-focus-handler.mjs +2 -3
- package/build-module/components/block-list/use-block-props/use-focus-handler.mjs.map +2 -2
- package/build-module/components/block-list/use-block-props/use-register-block-event-handlers.mjs +28 -0
- package/build-module/components/block-list/use-block-props/use-register-block-event-handlers.mjs.map +7 -0
- package/build-module/components/block-parent-selector/index.mjs +2 -2
- package/build-module/components/block-parent-selector/index.mjs.map +2 -2
- package/build-module/components/block-toolbar/switch-section-style.mjs +4 -2
- package/build-module/components/block-toolbar/switch-section-style.mjs.map +2 -2
- package/build-module/components/block-tools/empty-block-inserter.mjs +2 -7
- package/build-module/components/block-tools/empty-block-inserter.mjs.map +2 -2
- package/build-module/components/block-vertical-alignment-control/ui.mjs +4 -6
- package/build-module/components/block-vertical-alignment-control/ui.mjs.map +2 -2
- package/build-module/components/border-radius-control/utils.mjs +11 -53
- package/build-module/components/border-radius-control/utils.mjs.map +2 -2
- package/build-module/components/colors-gradients/control.mjs +5 -3
- package/build-module/components/colors-gradients/control.mjs.map +2 -2
- package/build-module/components/dimension-control/index.mjs +30 -20
- package/build-module/components/dimension-control/index.mjs.map +2 -2
- package/build-module/components/dimensions-tool/aspect-ratio-tool.mjs +10 -6
- package/build-module/components/dimensions-tool/aspect-ratio-tool.mjs.map +2 -2
- package/build-module/components/editor-styles/index.mjs +9 -1
- package/build-module/components/editor-styles/index.mjs.map +2 -2
- package/build-module/components/global-styles/background-panel.mjs +71 -29
- package/build-module/components/global-styles/background-panel.mjs.map +2 -2
- package/build-module/components/global-styles/border-panel.mjs +157 -56
- package/build-module/components/global-styles/border-panel.mjs.map +2 -2
- package/build-module/components/global-styles/color-gradient-dropdown-item.mjs +51 -15
- package/build-module/components/global-styles/color-gradient-dropdown-item.mjs.map +2 -2
- package/build-module/components/global-styles/color-panel.mjs +63 -17
- package/build-module/components/global-styles/color-panel.mjs.map +2 -2
- package/build-module/components/global-styles/dimensions-panel.mjs +248 -66
- package/build-module/components/global-styles/dimensions-panel.mjs.map +2 -2
- package/build-module/components/global-styles/filters-panel.mjs +64 -21
- package/build-module/components/global-styles/filters-panel.mjs.map +2 -2
- package/build-module/components/global-styles/hooks.mjs +4 -1
- package/build-module/components/global-styles/hooks.mjs.map +2 -2
- package/build-module/components/global-styles/inheritance/index.mjs +108 -0
- package/build-module/components/global-styles/inheritance/index.mjs.map +7 -0
- package/build-module/components/global-styles/inherited-value-context.mjs +141 -0
- package/build-module/components/global-styles/inherited-value-context.mjs.map +7 -0
- package/build-module/components/global-styles/shadow-panel-components.mjs +38 -20
- package/build-module/components/global-styles/shadow-panel-components.mjs.map +2 -2
- package/build-module/components/global-styles/state-control.mjs +1 -1
- package/build-module/components/global-styles/state-control.mjs.map +2 -2
- package/build-module/components/global-styles/typography-panel.mjs +276 -79
- package/build-module/components/global-styles/typography-panel.mjs.map +2 -2
- package/build-module/components/inspector-controls-tabs/styles-tab.mjs +6 -1
- package/build-module/components/inspector-controls-tabs/styles-tab.mjs.map +2 -2
- package/build-module/components/line-height-control/index.mjs +1 -1
- package/build-module/components/line-height-control/index.mjs.map +2 -2
- package/build-module/components/link-control/index.mjs +4 -2
- package/build-module/components/link-control/index.mjs.map +2 -2
- package/build-module/components/preset-input-control/index.mjs +2 -1
- package/build-module/components/preset-input-control/index.mjs.map +2 -2
- package/build-module/components/provider/block-refs-provider.mjs +8 -2
- package/build-module/components/provider/block-refs-provider.mjs.map +2 -2
- package/build-module/components/provider/index.mjs +1 -1
- package/build-module/components/provider/index.mjs.map +2 -2
- package/build-module/components/provider/use-block-sync.mjs +18 -6
- package/build-module/components/provider/use-block-sync.mjs.map +2 -2
- package/build-module/components/provider/use-media-upload-settings.mjs +3 -1
- package/build-module/components/provider/use-media-upload-settings.mjs.map +2 -2
- package/build-module/components/rich-text/index.mjs +28 -14
- package/build-module/components/rich-text/index.mjs.map +2 -2
- package/build-module/components/spacing-sizes-control/utils.mjs +6 -18
- package/build-module/components/spacing-sizes-control/utils.mjs.map +2 -2
- package/build-module/components/text-indent-control/index.mjs +8 -2
- package/build-module/components/text-indent-control/index.mjs.map +2 -2
- package/build-module/components/url-input/index.mjs +306 -353
- package/build-module/components/url-input/index.mjs.map +2 -2
- package/build-module/components/writing-flow/index.mjs +2 -0
- package/build-module/components/writing-flow/index.mjs.map +2 -2
- package/build-module/components/writing-flow/use-arrow-nav.mjs +24 -1
- package/build-module/components/writing-flow/use-arrow-nav.mjs.map +2 -2
- package/build-module/components/writing-flow/use-click-selection.mjs +28 -2
- package/build-module/components/writing-flow/use-click-selection.mjs.map +2 -2
- package/build-module/components/writing-flow/use-editable-root-event-handlers.mjs +154 -0
- package/build-module/components/writing-flow/use-editable-root-event-handlers.mjs.map +7 -0
- package/build-module/components/writing-flow/use-editable-root.mjs +5 -37
- package/build-module/components/writing-flow/use-editable-root.mjs.map +2 -2
- package/build-module/components/writing-flow/use-home-end.mjs +1 -1
- package/build-module/components/writing-flow/use-home-end.mjs.map +2 -2
- package/build-module/components/writing-flow/use-selection-observer.mjs +18 -14
- package/build-module/components/writing-flow/use-selection-observer.mjs.map +2 -2
- package/build-module/components/writing-flow/utils.mjs +2 -11
- package/build-module/components/writing-flow/utils.mjs.map +2 -2
- package/build-module/hooks/background.mjs +13 -10
- package/build-module/hooks/background.mjs.map +2 -2
- package/build-module/hooks/block-style-variation.mjs +8 -44
- package/build-module/hooks/block-style-variation.mjs.map +2 -2
- package/build-module/hooks/border.mjs +19 -4
- package/build-module/hooks/border.mjs.map +2 -2
- package/build-module/hooks/custom-css.mjs +7 -3
- package/build-module/hooks/custom-css.mjs.map +2 -2
- package/build-module/hooks/dimensions.mjs +15 -4
- package/build-module/hooks/dimensions.mjs.map +2 -2
- package/build-module/hooks/duotone.mjs +20 -9
- package/build-module/hooks/duotone.mjs.map +2 -2
- package/build-module/hooks/elements.mjs +14 -4
- package/build-module/hooks/elements.mjs.map +2 -2
- package/build-module/hooks/line-height.mjs +1 -2
- package/build-module/hooks/line-height.mjs.map +2 -2
- package/build-module/hooks/typography.mjs +13 -4
- package/build-module/hooks/typography.mjs.map +2 -2
- package/build-module/private-apis.mjs +7 -3
- package/build-module/private-apis.mjs.map +2 -2
- package/build-module/store/actions.mjs +9 -4
- package/build-module/store/actions.mjs.map +2 -2
- package/build-module/store/private-selectors.mjs +29 -1
- package/build-module/store/private-selectors.mjs.map +2 -2
- package/build-module/store/reducer.mjs +6 -6
- package/build-module/store/reducer.mjs.map +2 -2
- package/build-module/store/selectors.mjs +23 -0
- package/build-module/store/selectors.mjs.map +2 -2
- package/build-module/utils/native-undo.mjs +29 -0
- package/build-module/utils/native-undo.mjs.map +7 -0
- package/build-style/content-rtl.css +10 -18
- package/build-style/content.css +10 -18
- package/build-style/style-rtl.css +150 -7
- package/build-style/style.css +150 -7
- package/package.json +40 -41
- package/src/components/alignment-control/test/__snapshots__/index.js.snap +1 -1
- package/src/components/alignment-control/ui.js +2 -4
- package/src/components/background-image-control/index.js +74 -37
- package/src/components/background-image-control/style.scss +13 -4
- package/src/components/block-alignment-control/test/__snapshots__/index.js.snap +3 -3
- package/src/components/block-alignment-control/test/index.js +1 -1
- package/src/components/block-alignment-control/ui.js +4 -2
- package/src/components/block-breadcrumb/test/__snapshots__/index.js.snap +1 -1
- package/src/components/block-compare/test/__snapshots__/block-view.js.snap +1 -1
- package/src/components/block-icon/test/__snapshots__/index.js.snap +1 -1
- package/src/components/block-inspector/index.js +60 -31
- package/src/components/block-list/block-html.js +5 -0
- package/src/components/block-list/content.scss +1 -11
- package/src/components/block-list/use-block-props/index.js +5 -1
- package/src/components/block-list/use-block-props/use-focus-handler.js +9 -8
- package/src/components/block-list/use-block-props/use-register-block-event-handlers.js +45 -0
- package/src/components/block-parent-selector/index.js +5 -2
- package/src/components/block-toolbar/switch-section-style.js +5 -2
- package/src/components/block-tools/empty-block-inserter.js +3 -7
- package/src/components/block-vertical-alignment-control/test/__snapshots__/index.js.snap +3 -3
- package/src/components/block-vertical-alignment-control/test/index.js +18 -2
- package/src/components/block-vertical-alignment-control/ui.js +3 -5
- package/src/components/border-radius-control/test/utils.js +0 -41
- package/src/components/border-radius-control/utils.js +16 -107
- package/src/components/button-block-appender/content.scss +6 -2
- package/src/components/color-palette/test/__snapshots__/control.js.snap +1 -1
- package/src/components/colors-gradients/control.js +6 -3
- package/src/components/default-block-appender/test/__snapshots__/index.js.snap +1 -1
- package/src/components/dimension-control/index.js +13 -1
- package/src/components/dimensions-tool/aspect-ratio-tool.js +13 -6
- package/src/components/editor-styles/index.js +16 -1
- package/src/components/global-styles/background-panel.js +107 -34
- package/src/components/global-styles/border-panel.js +219 -48
- package/src/components/global-styles/color-gradient-dropdown-item.js +93 -28
- package/src/components/global-styles/color-panel.js +92 -11
- package/src/components/global-styles/dimensions-panel.js +422 -71
- package/src/components/global-styles/filters-panel.js +88 -28
- package/src/components/global-styles/hooks.js +8 -1
- package/src/components/global-styles/inheritance/index.js +204 -0
- package/src/components/global-styles/inheritance/style.scss +184 -0
- package/src/components/global-styles/inheritance/test/index.js +281 -0
- package/src/components/global-styles/inherited-value-context.js +271 -0
- package/src/components/global-styles/shadow-panel-components.js +48 -26
- package/src/components/global-styles/state-control.js +2 -2
- package/src/components/global-styles/test/background-panel.js +338 -1
- package/src/components/global-styles/test/border-panel.js +441 -0
- package/src/components/global-styles/test/color-panel.js +182 -2
- package/src/components/global-styles/test/dimensions-panel.js +753 -0
- package/src/components/global-styles/test/filters-panel.js +194 -0
- package/src/components/global-styles/test/inherited-value-context-core.js +98 -0
- package/src/components/global-styles/test/inherited-value-context.js +454 -0
- package/src/components/global-styles/test/typography-panel-core.js +185 -0
- package/src/components/global-styles/test/typography-panel.js +849 -12
- package/src/components/global-styles/typography-panel.js +449 -100
- package/src/components/image-editor/style.scss +33 -0
- package/src/components/inner-blocks/test/__snapshots__/index.js.snap +1 -1
- package/src/components/inspector-controls-tabs/styles-tab.js +5 -1
- package/src/components/line-height-control/index.js +1 -1
- package/src/components/link-control/index.js +7 -2
- package/src/components/preset-input-control/index.js +4 -1
- package/src/components/provider/block-refs-provider.js +12 -2
- package/src/components/provider/index.js +2 -2
- package/src/components/provider/use-block-sync.js +18 -6
- package/src/components/provider/use-media-upload-settings.js +2 -0
- package/src/components/rich-text/index.js +37 -16
- package/src/components/spacing-sizes-control/test/utils.js +16 -5
- package/src/components/spacing-sizes-control/utils.js +11 -28
- package/src/components/text-indent-control/index.js +8 -0
- package/src/components/url-input/index.js +363 -431
- package/src/components/url-input/test/index.js +592 -0
- package/src/components/warning/test/__snapshots__/index.js.snap +1 -1
- package/src/components/writing-flow/index.js +2 -0
- package/src/components/writing-flow/use-arrow-nav.js +51 -1
- package/src/components/writing-flow/use-click-selection.js +54 -3
- package/src/components/writing-flow/use-editable-root-event-handlers.js +266 -0
- package/src/components/writing-flow/use-editable-root.js +7 -77
- package/src/components/writing-flow/use-home-end.js +17 -9
- package/src/components/writing-flow/use-selection-observer.js +32 -15
- package/src/components/writing-flow/utils.js +3 -24
- package/src/hooks/background.js +26 -21
- package/src/hooks/block-fields/rich-text/styles.scss +1 -1
- package/src/hooks/block-style-variation.js +8 -74
- package/src/hooks/border.js +19 -4
- package/src/hooks/custom-css.js +15 -6
- package/src/hooks/dimensions.js +17 -4
- package/src/hooks/duotone.js +26 -8
- package/src/hooks/elements.js +14 -3
- package/src/hooks/line-height.js +0 -1
- package/src/hooks/test/inherited-value-wiring.js +411 -0
- package/src/hooks/test/preset-round-trip.js +456 -0
- package/src/hooks/typography.js +35 -23
- package/src/private-apis.js +11 -2
- package/src/store/actions.js +10 -4
- package/src/store/private-selectors.js +57 -1
- package/src/store/reducer.js +9 -9
- package/src/store/selectors.js +56 -8
- package/src/store/test/private-selectors.js +160 -1
- package/src/style.scss +2 -0
- package/src/utils/native-undo.js +56 -0
- package/build/components/duotone/utils.cjs +0 -87
- package/build/components/duotone/utils.cjs.map +0 -7
- package/build-module/components/duotone/utils.mjs +0 -59
- package/build-module/components/duotone/utils.mjs.map +0 -7
- package/src/components/duotone/utils.js +0 -90
- package/src/hooks/test/get-variation-styles-with-ref-values.js +0 -91
|
@@ -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\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.hasRenderedValidation = { current: false };\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: this.props.required ?? 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\t// Use ValidatedInputControl if customValidity has ever had a non-undefined value.\n\t\tif ( customValidity !== undefined ) {\n\t\t\tthis.hasRenderedValidation.current = true;\n\t\t}\n\n\t\tconst MaybeValidatedInputControl = this.hasRenderedValidation.current\n\t\t\t? ValidatedInputControl\n\t\t\t: InputControl;\n\n\t\treturn (\n\t\t\t<BaseControl { ...controlProps }>\n\t\t\t\t<MaybeValidatedInputControl\n\t\t\t\t\t{ ...inputProps }\n\t\t\t\t\t{ ...( this.hasRenderedValidation.current\n\t\t\t\t\t\t? validationProps\n\t\t\t\t\t\t: {} ) }\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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAAiB;AAKjB,kBAAgC;AAChC,
|
|
6
|
-
"names": ["componentsPrivateApis", "
|
|
4
|
+
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport { speak } from '@wordpress/a11y';\nimport { __, sprintf, _n } from '@wordpress/i18n';\nimport { useEffect, useRef, useState } from '@wordpress/element';\nimport { UP, DOWN, ENTER, TAB } from '@wordpress/keycodes';\nimport {\n\tBaseControl,\n\tButton,\n\t__experimentalInputControl as InputControl,\n\tSpinner,\n\tPopover,\n\tprivateApis as componentsPrivateApis,\n} from '@wordpress/components';\nimport { useDebounce, useEvent, useInstanceId } from '@wordpress/compose';\nimport { useSelect } 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\nconst noop = () => {};\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\n/**\n * Text field for entering a URL, with an autocomplete list of matching posts,\n * pages and other link suggestions.\n *\n * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/url-input/README.md\n *\n * @param {Object} props Component props.\n */\nexport default function URLInput( props ) {\n\tconst {\n\t\t__experimentalFetchLinkSuggestions: fetchLinkSuggestionsProp,\n\t\t__experimentalHandleURLSuggestions: handleURLSuggestions,\n\t\t__experimentalRenderControl: renderControl,\n\t\t__experimentalRenderSuggestions: renderSuggestions,\n\t\t__experimentalShowInitialSuggestions: showInitialSuggestions = false,\n\t\tautocompleteRef,\n\t\tclassName,\n\t\tcustomValidity,\n\t\tdisableSuggestions,\n\t\tdisabled = false,\n\t\thelp = null,\n\t\thideLabelFromVision = false,\n\t\tinputRef,\n\t\tisFullWidth,\n\t\tlabel = null,\n\t\tmarkWhenOptional,\n\t\tonChange,\n\t\tonKeyDown,\n\t\tonSubmit,\n\t\tplaceholder = __( 'Paste URL or type to search' ),\n\t\trequired = true,\n\t\tsuffix,\n\t\tvalue = '',\n\t} = props;\n\n\tconst instanceId = useInstanceId( URLInput );\n\tconst { getSettings } = useSelect( blockEditorStore );\n\tconst debouncedSpeak = useDebounce( speak, 500 );\n\n\tconst [ suggestions, setSuggestions ] = useState( [] );\n\tconst [ suggestionsValue, setSuggestionsValue ] = useState( null );\n\tconst [ selectedSuggestion, setSelectedSuggestion ] = useState( null );\n\tconst [ isSuggestionsListOpen, setIsSuggestionsListOpen ] =\n\t\tuseState( false );\n\tconst [ isLoading, setIsLoading ] = useState( false );\n\n\tconst fallbackInputRef = useRef();\n\tconst suggestionNodesRef = useRef( [] );\n\t// A fetch Promise can't be aborted. It's mimicked by holding on to the\n\t// pending request so that responses of superseded requests can be ignored.\n\tconst suggestionsRequestRef = useRef( null );\n\n\tconst controlInputRef = inputRef ?? fallbackInputRef;\n\n\tconst inputId = `url-input-control-${ instanceId }`;\n\tconst suggestionsListboxId = `block-editor-url-input-suggestions-${ instanceId }`;\n\tconst suggestionOptionIdPrefix = `block-editor-url-input-suggestion-${ instanceId }`;\n\n\t// The suggestions are hidden rather than discarded, so that returning focus\n\t// to a field that already has results doesn't trigger a new search.\n\tconst showSuggestions =\n\t\tisSuggestionsListOpen &&\n\t\tdisableSuggestions !== true &&\n\t\t( showInitialSuggestions || !! value.length );\n\n\tconst updateSuggestions = useEvent( ( searchValue = '' ) => {\n\t\tconst fetchLinkSuggestions = isFunction( fetchLinkSuggestionsProp )\n\t\t\t? fetchLinkSuggestionsProp\n\t\t\t: getSettings().__experimentalFetchLinkSuggestions;\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 = ! searchValue?.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\tconst search = searchValue.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( search.length < 2 ||\n\t\t\t\t( ! handleURLSuggestions && isURL( search ) ) )\n\t\t) {\n\t\t\tsuggestionsRequestRef.current?.cancel?.();\n\t\t\tsuggestionsRequestRef.current = null;\n\n\t\t\tsetSuggestions( [] );\n\t\t\tsetIsSuggestionsListOpen( false );\n\t\t\tsetSuggestionsValue( search );\n\t\t\tsetSelectedSuggestion( null );\n\t\t\tsetIsLoading( false );\n\n\t\t\treturn;\n\t\t}\n\n\t\tsetSelectedSuggestion( null );\n\t\tsetIsLoading( true );\n\n\t\tconst request = fetchLinkSuggestions( search, {\n\t\t\tisInitialSuggestions,\n\t\t} );\n\t\tsuggestionsRequestRef.current = request;\n\n\t\trequest\n\t\t\t.then( ( nextSuggestions ) => {\n\t\t\t\tif ( suggestionsRequestRef.current !== request ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tsetSuggestions( nextSuggestions );\n\t\t\t\tsetSuggestionsValue( search );\n\t\t\t\tsetIsLoading( false );\n\t\t\t\tsetIsSuggestionsListOpen( !! nextSuggestions.length );\n\n\t\t\t\tif ( nextSuggestions.length ) {\n\t\t\t\t\tdebouncedSpeak(\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\tnextSuggestions.length\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tnextSuggestions.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\tdebouncedSpeak( __( 'No results.' ), 'assertive' );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.catch( () => {\n\t\t\t\tif ( suggestionsRequestRef.current !== request ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tsetIsLoading( false );\n\t\t\t} )\n\t\t\t.finally( () => {\n\t\t\t\tif ( suggestionsRequestRef.current === request ) {\n\t\t\t\t\tsuggestionsRequestRef.current = null;\n\t\t\t\t}\n\t\t\t} );\n\t} );\n\n\tconst debouncedUpdateSuggestions = useDebounce( updateSuggestions, 200 );\n\n\t// Keep the suggestions in sync with the value being searched for. An empty\n\t// value requests the initial suggestions, when those are enabled.\n\tuseEffect( () => {\n\t\tif (\n\t\t\t! disableSuggestions &&\n\t\t\t( value.length || showInitialSuggestions )\n\t\t) {\n\t\t\tdebouncedUpdateSuggestions( value );\n\t\t}\n\t}, [\n\t\tvalue,\n\t\tdisableSuggestions,\n\t\tshowInitialSuggestions,\n\t\tdebouncedUpdateSuggestions,\n\t] );\n\n\t// Persist the hidden state, so that the list can't reappear with stale\n\t// results once the value or the props allow suggestions again.\n\tuseEffect( () => {\n\t\tif ( ! showSuggestions ) {\n\t\t\tsetIsSuggestionsListOpen( false );\n\t\t}\n\t}, [ showSuggestions ] );\n\n\tuseEffect( () => {\n\t\tif ( showSuggestions && selectedSuggestion !== null ) {\n\t\t\tsuggestionNodesRef.current[ 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\t}, [ showSuggestions, selectedSuggestion ] );\n\n\tuseEffect( () => {\n\t\treturn () => {\n\t\t\tsuggestionsRequestRef.current?.cancel?.();\n\t\t\tsuggestionsRequestRef.current = null;\n\t\t};\n\t}, [] );\n\n\tfunction selectLink( suggestion ) {\n\t\tonChange( suggestion.url, suggestion );\n\t\tsetSelectedSuggestion( null );\n\t\tsetIsSuggestionsListOpen( false );\n\t}\n\n\tfunction handleSuggestionClick( suggestion ) {\n\t\tselectLink( suggestion );\n\t\t// Move focus to the input field when a link suggestion is clicked.\n\t\tcontrolInputRef.current.focus();\n\t}\n\n\tfunction handleChange( newValue ) {\n\t\t// `InputControl` passes an `{ event }` object as its second argument,\n\t\t// which callers would mistake for a selected suggestion.\n\t\tonChange( newValue );\n\t}\n\n\tfunction handleFocus() {\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.length &&\n\t\t\tsuggestionsRequestRef.current === null\n\t\t) {\n\t\t\tdebouncedUpdateSuggestions( value );\n\t\t}\n\t}\n\n\tfunction handleKeyDown( event ) {\n\t\tonKeyDown?.( event );\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 || isLoading ) {\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 ( value.length !== event.target.selectionStart ) {\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\tvalue.length,\n\t\t\t\t\t\t\tvalue.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 ( onSubmit ) {\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\tonSubmit( 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 = suggestions[ selectedSuggestion ];\n\n\t\tswitch ( event.keyCode ) {\n\t\t\tcase UP: {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tsetSelectedSuggestion(\n\t\t\t\t\t! selectedSuggestion\n\t\t\t\t\t\t? suggestions.length - 1\n\t\t\t\t\t\t: selectedSuggestion - 1\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\tsetSelectedSuggestion(\n\t\t\t\t\tselectedSuggestion === null ||\n\t\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\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase TAB: {\n\t\t\t\tif ( selectedSuggestion !== null ) {\n\t\t\t\t\tselectLink( 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\tspeak( __( '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 ( selectedSuggestion !== null ) {\n\t\t\t\t\tselectLink( suggestion );\n\n\t\t\t\t\tif ( onSubmit ) {\n\t\t\t\t\t\tonSubmit( suggestion, event );\n\t\t\t\t\t}\n\t\t\t\t} else if ( onSubmit ) {\n\t\t\t\t\tonSubmit( null, event );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst controlProps = {\n\t\tid: inputId, // Passes attribute to label for the for attribute\n\t\tlabel,\n\t\tclassName: clsx( 'block-editor-url-input', className, {\n\t\t\t'is-full-width': isFullWidth,\n\t\t} ),\n\t\thideLabelFromVision,\n\t};\n\n\tconst inputProps = {\n\t\tid: inputId,\n\t\tvalue,\n\t\trequired,\n\t\ttype: 'text',\n\t\tname: inputId,\n\t\tautoComplete: 'off',\n\t\tonChange: disabled ? noop : handleChange,\n\t\tonFocus: disabled ? noop : handleFocus,\n\t\tonKeyDown: disabled ? noop : handleKeyDown,\n\t\tplaceholder,\n\t\trole: 'combobox',\n\t\t'aria-label': label ? undefined : __( 'URL' ), // Ensure input always has an accessible label\n\t\t'aria-expanded': showSuggestions,\n\t\t'aria-autocomplete': 'list',\n\t\t'aria-owns': suggestionsListboxId,\n\t\t'aria-activedescendant':\n\t\t\tselectedSuggestion !== null\n\t\t\t\t? `${ suggestionOptionIdPrefix }-${ selectedSuggestion }`\n\t\t\t\t: undefined,\n\t\tref: controlInputRef,\n\t\tdisabled,\n\t\tsuffix,\n\t\thelp,\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<Control\n\t\t\t\tcontrolProps={ controlProps }\n\t\t\t\tinputProps={ inputProps }\n\t\t\t\tisLoading={ isLoading }\n\t\t\t\tcustomValidity={ customValidity }\n\t\t\t\tmarkWhenOptional={ markWhenOptional }\n\t\t\t\trenderControl={ renderControl }\n\t\t\t/>\n\t\t\t{ showSuggestions && suggestions.length > 0 && (\n\t\t\t\t<Suggestions\n\t\t\t\t\tautocompleteRef={ autocompleteRef }\n\t\t\t\t\tclassName={ className }\n\t\t\t\t\thandleSuggestionClick={ handleSuggestionClick }\n\t\t\t\t\tisLoading={ isLoading }\n\t\t\t\t\trenderSuggestions={ renderSuggestions }\n\t\t\t\t\tselectedSuggestion={ selectedSuggestion }\n\t\t\t\t\tsuggestionNodesRef={ suggestionNodesRef }\n\t\t\t\t\tsuggestionOptionIdPrefix={ suggestionOptionIdPrefix }\n\t\t\t\t\tsuggestions={ suggestions }\n\t\t\t\t\tsuggestionsListboxId={ suggestionsListboxId }\n\t\t\t\t\tsuggestionsValue={ suggestionsValue }\n\t\t\t\t/>\n\t\t\t) }\n\t\t</>\n\t);\n}\n\nfunction Control( {\n\tcontrolProps,\n\tinputProps,\n\tisLoading,\n\tcustomValidity,\n\tmarkWhenOptional,\n\trenderControl,\n} ) {\n\t// Once a validity has been reported, keep using the validated control, so\n\t// that clearing the validity doesn't remount (and blur) the input.\n\tconst [ isValidated, setIsValidated ] = useState(\n\t\tcustomValidity !== undefined\n\t);\n\n\tif ( customValidity !== undefined && ! isValidated ) {\n\t\tsetIsValidated( true );\n\t}\n\n\tif ( renderControl ) {\n\t\treturn renderControl( controlProps, inputProps, isLoading );\n\t}\n\n\tconst MaybeValidatedInputControl = isValidated\n\t\t? ValidatedInputControl\n\t\t: InputControl;\n\n\treturn (\n\t\t<BaseControl { ...controlProps }>\n\t\t\t<MaybeValidatedInputControl\n\t\t\t\t{ ...inputProps }\n\t\t\t\t{ ...( isValidated && {\n\t\t\t\t\tcustomValidity,\n\t\t\t\t\t// Suppress the \"(Required)\" indicator in the label.\n\t\t\t\t\t// The field is still required for validation, but the indicator\n\t\t\t\t\t// can be hidden when markWhenOptional is set to true.\n\t\t\t\t\t...( markWhenOptional !== undefined && {\n\t\t\t\t\t\tmarkWhenOptional,\n\t\t\t\t\t} ),\n\t\t\t\t} ) }\n\t\t\t/>\n\t\t\t{ isLoading && <Spinner /> }\n\t\t</BaseControl>\n\t);\n}\n\nfunction Suggestions( {\n\tautocompleteRef,\n\tclassName,\n\thandleSuggestionClick,\n\tisLoading,\n\trenderSuggestions,\n\tselectedSuggestion,\n\tsuggestionNodesRef,\n\tsuggestionOptionIdPrefix,\n\tsuggestions,\n\tsuggestionsListboxId,\n\tsuggestionsValue,\n} ) {\n\tconst suggestionsListProps = {\n\t\tid: suggestionsListboxId,\n\t\tref: autocompleteRef,\n\t\trole: 'listbox',\n\t};\n\n\tconst buildSuggestionItemProps = ( suggestion, index ) => {\n\t\treturn {\n\t\t\trole: 'option',\n\t\t\ttabIndex: '-1',\n\t\t\tid: `${ suggestionOptionIdPrefix }-${ index }`,\n\t\t\tref: ( node ) => {\n\t\t\t\tsuggestionNodesRef.current[ index ] = node;\n\t\t\t},\n\t\t\t'aria-selected': index === selectedSuggestion ? true : undefined,\n\t\t};\n\t};\n\n\tif ( isFunction( renderSuggestions ) ) {\n\t\treturn renderSuggestions( {\n\t\t\tsuggestions,\n\t\t\tselectedSuggestion,\n\t\t\tsuggestionsListProps,\n\t\t\tbuildSuggestionItemProps,\n\t\t\tisLoading,\n\t\t\thandleSuggestionClick,\n\t\t\tisInitialSuggestions: ! suggestionsValue?.length,\n\t\t\tcurrentInputValue: suggestionsValue,\n\t\t} );\n\t}\n\n\treturn (\n\t\t<Popover placement=\"bottom\" focusOnMount={ false }>\n\t\t\t<div\n\t\t\t\t{ ...suggestionsListProps }\n\t\t\t\tclassName={ clsx( 'block-editor-url-input__suggestions', {\n\t\t\t\t\t[ `${ className }__suggestions` ]: className,\n\t\t\t\t} ) }\n\t\t\t>\n\t\t\t\t{ suggestions.map( ( suggestion, index ) => (\n\t\t\t\t\t<Button\n\t\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\t\t{ ...buildSuggestionItemProps( suggestion, index ) }\n\t\t\t\t\t\tkey={ suggestion.id }\n\t\t\t\t\t\tclassName={ clsx(\n\t\t\t\t\t\t\t'block-editor-url-input__suggestion',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t'is-selected': index === selectedSuggestion,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t) }\n\t\t\t\t\t\tonClick={ () => handleSuggestionClick( suggestion ) }\n\t\t\t\t\t>\n\t\t\t\t\t\t{ suggestion.title }\n\t\t\t\t\t</Button>\n\t\t\t\t) ) }\n\t\t\t</div>\n\t\t</Popover>\n\t);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["componentsPrivateApis", "blockEditorStore", "clsx", "InputControl"]
|
|
7
7
|
}
|
|
@@ -48,6 +48,7 @@ var import_use_preview_mode_nav = require("./use-preview-mode-nav.cjs");
|
|
|
48
48
|
var import_use_select_all = __toESM(require("./use-select-all.cjs"));
|
|
49
49
|
var import_use_drag_selection = __toESM(require("./use-drag-selection.cjs"));
|
|
50
50
|
var import_use_selection_observer = __toESM(require("./use-selection-observer.cjs"));
|
|
51
|
+
var import_use_editable_root_event_handlers = __toESM(require("./use-editable-root-event-handlers.cjs"));
|
|
51
52
|
var import_use_click_selection = __toESM(require("./use-click-selection.cjs"));
|
|
52
53
|
var import_use_input = __toESM(require("./use-input.cjs"));
|
|
53
54
|
var import_use_clipboard_handler = __toESM(require("./use-clipboard-handler.cjs"));
|
|
@@ -63,6 +64,7 @@ function useWritingFlow() {
|
|
|
63
64
|
before,
|
|
64
65
|
(0, import_compose.useMergeRefs)([
|
|
65
66
|
ref,
|
|
67
|
+
(0, import_use_editable_root_event_handlers.default)(),
|
|
66
68
|
(0, import_use_clipboard_handler.default)(),
|
|
67
69
|
(0, import_use_input.default)(),
|
|
68
70
|
(0, import_use_editable_root.default)(),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/writing-flow/index.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport { useSelect } from '@wordpress/data';\nimport { __ } from '@wordpress/i18n';\nimport { useMergeRefs, useRefEffect } from '@wordpress/compose';\nimport { forwardRef } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport useEditableRoot from './use-editable-root';\nimport useHomeEnd from './use-home-end';\nimport useMultiSelection from './use-multi-selection';\nimport useTabNav from './use-tab-nav';\nimport useArrowNav from './use-arrow-nav';\nimport { usePreviewModeNav } from './use-preview-mode-nav';\nimport useSelectAll from './use-select-all';\nimport useDragSelection from './use-drag-selection';\nimport useSelectionObserver from './use-selection-observer';\nimport useClickSelection from './use-click-selection';\nimport useInput from './use-input';\nimport useClipboardHandler from './use-clipboard-handler';\nimport { store as blockEditorStore } from '../../store';\n\nexport function useWritingFlow() {\n\tconst [ before, ref, after ] = useTabNav();\n\tconst hasMultiSelection = useSelect(\n\t\t( select ) => select( blockEditorStore ).hasMultiSelection(),\n\t\t[]\n\t);\n\n\treturn [\n\t\tbefore,\n\t\tuseMergeRefs( [\n\t\t\tref,\n\t\t\tuseClipboardHandler(),\n\t\t\tuseInput(),\n\t\t\tuseEditableRoot(),\n\t\t\tuseHomeEnd(),\n\t\t\tuseDragSelection(),\n\t\t\tuseSelectionObserver(),\n\t\t\tuseClickSelection(),\n\t\t\tuseMultiSelection(),\n\t\t\tuseSelectAll(),\n\t\t\tuseArrowNav(),\n\t\t\tusePreviewModeNav(),\n\t\t\tuseRefEffect(\n\t\t\t\t( node ) => {\n\t\t\t\t\tnode.tabIndex = 0;\n\t\t\t\t\tnode.dataset.hasMultiSelection = hasMultiSelection;\n\n\t\t\t\t\tif ( ! hasMultiSelection ) {\n\t\t\t\t\t\treturn () => {\n\t\t\t\t\t\t\tdelete node.dataset.hasMultiSelection;\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tnode.setAttribute(\n\t\t\t\t\t\t'aria-label',\n\t\t\t\t\t\t__( 'Multiple selected blocks' )\n\t\t\t\t\t);\n\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tdelete node.dataset.hasMultiSelection;\n\t\t\t\t\t\t// The wrapper may remain the editing host (the\n\t\t\t\t\t\t// collapsed block supports `editableRoot`): keep it\n\t\t\t\t\t\t// named, as the textbox role requires.\n\t\t\t\t\t\tif ( node.contentEditable === 'true' ) {\n\t\t\t\t\t\t\tnode.setAttribute(\n\t\t\t\t\t\t\t\t'aria-label',\n\t\t\t\t\t\t\t\t__( 'Editor canvas' )\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tnode.removeAttribute( 'aria-label' );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\t[ hasMultiSelection ]\n\t\t\t),\n\t\t] ),\n\t\tafter,\n\t];\n}\n\nfunction WritingFlow( { children, ...props }, forwardedRef ) {\n\tconst [ before, ref, after ] = useWritingFlow();\n\treturn (\n\t\t<>\n\t\t\t{ before }\n\t\t\t<div\n\t\t\t\t{ ...props }\n\t\t\t\tref={ useMergeRefs( [ ref, forwardedRef ] ) }\n\t\t\t\tclassName={ clsx(\n\t\t\t\t\tprops.className,\n\t\t\t\t\t'block-editor-writing-flow'\n\t\t\t\t) }\n\t\t\t>\n\t\t\t\t{ children }\n\t\t\t</div>\n\t\t\t{ after }\n\t\t</>\n\t);\n}\n\n/**\n * Handles selection and navigation across blocks. This component should be\n * wrapped around BlockList.\n *\n * @param {Object} props Component properties.\n * @param {Element} props.children Children to be rendered.\n */\nexport default forwardRef( WritingFlow );\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAAiB;AAKjB,kBAA0B;AAC1B,kBAAmB;AACnB,qBAA2C;AAC3C,qBAA2B;AAK3B,+BAA4B;AAC5B,0BAAuB;AACvB,iCAA8B;AAC9B,yBAAsB;AACtB,2BAAwB;AACxB,kCAAkC;AAClC,4BAAyB;AACzB,gCAA6B;AAC7B,oCAAiC;AACjC,iCAA8B;AAC9B,uBAAqB;AACrB,mCAAgC;AAChC,mBAA0C;
|
|
6
|
-
"names": ["useTabNav", "blockEditorStore", "useClipboardHandler", "useInput", "useEditableRoot", "useHomeEnd", "useDragSelection", "useSelectionObserver", "useClickSelection", "useMultiSelection", "useSelectAll", "useArrowNav", "clsx"]
|
|
4
|
+
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport { useSelect } from '@wordpress/data';\nimport { __ } from '@wordpress/i18n';\nimport { useMergeRefs, useRefEffect } from '@wordpress/compose';\nimport { forwardRef } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport useEditableRoot from './use-editable-root';\nimport useHomeEnd from './use-home-end';\nimport useMultiSelection from './use-multi-selection';\nimport useTabNav from './use-tab-nav';\nimport useArrowNav from './use-arrow-nav';\nimport { usePreviewModeNav } from './use-preview-mode-nav';\nimport useSelectAll from './use-select-all';\nimport useDragSelection from './use-drag-selection';\nimport useSelectionObserver from './use-selection-observer';\nimport useEditableRootEventHandlers from './use-editable-root-event-handlers';\nimport useClickSelection from './use-click-selection';\nimport useInput from './use-input';\nimport useClipboardHandler from './use-clipboard-handler';\nimport { store as blockEditorStore } from '../../store';\n\nexport function useWritingFlow() {\n\tconst [ before, ref, after ] = useTabNav();\n\tconst hasMultiSelection = useSelect(\n\t\t( select ) => select( blockEditorStore ).hasMultiSelection(),\n\t\t[]\n\t);\n\n\treturn [\n\t\tbefore,\n\t\tuseMergeRefs( [\n\t\t\tref,\n\t\t\tuseEditableRootEventHandlers(),\n\t\t\tuseClipboardHandler(),\n\t\t\tuseInput(),\n\t\t\tuseEditableRoot(),\n\t\t\tuseHomeEnd(),\n\t\t\tuseDragSelection(),\n\t\t\tuseSelectionObserver(),\n\t\t\tuseClickSelection(),\n\t\t\tuseMultiSelection(),\n\t\t\tuseSelectAll(),\n\t\t\tuseArrowNav(),\n\t\t\tusePreviewModeNav(),\n\t\t\tuseRefEffect(\n\t\t\t\t( node ) => {\n\t\t\t\t\tnode.tabIndex = 0;\n\t\t\t\t\tnode.dataset.hasMultiSelection = hasMultiSelection;\n\n\t\t\t\t\tif ( ! hasMultiSelection ) {\n\t\t\t\t\t\treturn () => {\n\t\t\t\t\t\t\tdelete node.dataset.hasMultiSelection;\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tnode.setAttribute(\n\t\t\t\t\t\t'aria-label',\n\t\t\t\t\t\t__( 'Multiple selected blocks' )\n\t\t\t\t\t);\n\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tdelete node.dataset.hasMultiSelection;\n\t\t\t\t\t\t// The wrapper may remain the editing host (the\n\t\t\t\t\t\t// collapsed block supports `editableRoot`): keep it\n\t\t\t\t\t\t// named, as the textbox role requires.\n\t\t\t\t\t\tif ( node.contentEditable === 'true' ) {\n\t\t\t\t\t\t\tnode.setAttribute(\n\t\t\t\t\t\t\t\t'aria-label',\n\t\t\t\t\t\t\t\t__( 'Editor canvas' )\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tnode.removeAttribute( 'aria-label' );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\t[ hasMultiSelection ]\n\t\t\t),\n\t\t] ),\n\t\tafter,\n\t];\n}\n\nfunction WritingFlow( { children, ...props }, forwardedRef ) {\n\tconst [ before, ref, after ] = useWritingFlow();\n\treturn (\n\t\t<>\n\t\t\t{ before }\n\t\t\t<div\n\t\t\t\t{ ...props }\n\t\t\t\tref={ useMergeRefs( [ ref, forwardedRef ] ) }\n\t\t\t\tclassName={ clsx(\n\t\t\t\t\tprops.className,\n\t\t\t\t\t'block-editor-writing-flow'\n\t\t\t\t) }\n\t\t\t>\n\t\t\t\t{ children }\n\t\t\t</div>\n\t\t\t{ after }\n\t\t</>\n\t);\n}\n\n/**\n * Handles selection and navigation across blocks. This component should be\n * wrapped around BlockList.\n *\n * @param {Object} props Component properties.\n * @param {Element} props.children Children to be rendered.\n */\nexport default forwardRef( WritingFlow );\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAAiB;AAKjB,kBAA0B;AAC1B,kBAAmB;AACnB,qBAA2C;AAC3C,qBAA2B;AAK3B,+BAA4B;AAC5B,0BAAuB;AACvB,iCAA8B;AAC9B,yBAAsB;AACtB,2BAAwB;AACxB,kCAAkC;AAClC,4BAAyB;AACzB,gCAA6B;AAC7B,oCAAiC;AACjC,8CAAyC;AACzC,iCAA8B;AAC9B,uBAAqB;AACrB,mCAAgC;AAChC,mBAA0C;AAkExC;AAhEK,SAAS,iBAAiB;AAChC,QAAM,CAAE,QAAQ,KAAK,KAAM,QAAI,mBAAAA,SAAU;AACzC,QAAM,wBAAoB;AAAA,IACzB,CAAE,WAAY,OAAQ,aAAAC,KAAiB,EAAE,kBAAkB;AAAA,IAC3D,CAAC;AAAA,EACF;AAEA,SAAO;AAAA,IACN;AAAA,QACA,6BAAc;AAAA,MACb;AAAA,UACA,wCAAAC,SAA6B;AAAA,UAC7B,6BAAAC,SAAoB;AAAA,UACpB,iBAAAC,SAAS;AAAA,UACT,yBAAAC,SAAgB;AAAA,UAChB,oBAAAC,SAAW;AAAA,UACX,0BAAAC,SAAiB;AAAA,UACjB,8BAAAC,SAAqB;AAAA,UACrB,2BAAAC,SAAkB;AAAA,UAClB,2BAAAC,SAAkB;AAAA,UAClB,sBAAAC,SAAa;AAAA,UACb,qBAAAC,SAAY;AAAA,UACZ,+CAAkB;AAAA,UAClB;AAAA,QACC,CAAE,SAAU;AACX,eAAK,WAAW;AAChB,eAAK,QAAQ,oBAAoB;AAEjC,cAAK,CAAE,mBAAoB;AAC1B,mBAAO,MAAM;AACZ,qBAAO,KAAK,QAAQ;AAAA,YACrB;AAAA,UACD;AAEA,eAAK;AAAA,YACJ;AAAA,gBACA,gBAAI,0BAA2B;AAAA,UAChC;AAEA,iBAAO,MAAM;AACZ,mBAAO,KAAK,QAAQ;AAIpB,gBAAK,KAAK,oBAAoB,QAAS;AACtC,mBAAK;AAAA,gBACJ;AAAA,oBACA,gBAAI,eAAgB;AAAA,cACrB;AAAA,YACD,OAAO;AACN,mBAAK,gBAAiB,YAAa;AAAA,YACpC;AAAA,UACD;AAAA,QACD;AAAA,QACA,CAAE,iBAAkB;AAAA,MACrB;AAAA,IACD,CAAE;AAAA,IACF;AAAA,EACD;AACD;AAEA,SAAS,YAAa,EAAE,UAAU,GAAG,MAAM,GAAG,cAAe;AAC5D,QAAM,CAAE,QAAQ,KAAK,KAAM,IAAI,eAAe;AAC9C,SACC,4EACG;AAAA;AAAA,IACF;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACL,SAAM,6BAAc,CAAE,KAAK,YAAa,CAAE;AAAA,QAC1C,eAAY,YAAAC;AAAA,UACX,MAAM;AAAA,UACN;AAAA,QACD;AAAA,QAEE;AAAA;AAAA,IACH;AAAA,IACE;AAAA,KACH;AAEF;AASA,IAAO,2BAAQ,2BAAY,WAAY;",
|
|
6
|
+
"names": ["useTabNav", "blockEditorStore", "useEditableRootEventHandlers", "useClipboardHandler", "useInput", "useEditableRoot", "useHomeEnd", "useDragSelection", "useSelectionObserver", "useClickSelection", "useMultiSelection", "useSelectAll", "useArrowNav", "clsx"]
|
|
7
7
|
}
|
|
@@ -103,11 +103,15 @@ function useArrowNav() {
|
|
|
103
103
|
const {
|
|
104
104
|
getMultiSelectedBlocksStartClientId,
|
|
105
105
|
getMultiSelectedBlocksEndClientId,
|
|
106
|
+
getNextBlockClientId,
|
|
107
|
+
getPreviousBlockClientId,
|
|
108
|
+
getSelectedBlockClientId,
|
|
109
|
+
getSelectionStart,
|
|
106
110
|
getSettings,
|
|
107
111
|
hasMultiSelection,
|
|
108
112
|
__unstableIsFullySelected
|
|
109
113
|
} = (0, import_data.useSelect)(import_store.store);
|
|
110
|
-
const { selectBlock } = (0, import_data.useDispatch)(import_store.store);
|
|
114
|
+
const { selectBlock, multiSelect } = (0, import_data.useDispatch)(import_store.store);
|
|
111
115
|
return (0, import_compose.useRefEffect)((node) => {
|
|
112
116
|
let verticalRect;
|
|
113
117
|
function onMouseDown() {
|
|
@@ -150,6 +154,16 @@ function useArrowNav() {
|
|
|
150
154
|
}
|
|
151
155
|
if (hasMultiSelection()) {
|
|
152
156
|
if (shiftKey) {
|
|
157
|
+
const selection = defaultView.getSelection();
|
|
158
|
+
if (__unstableIsFullySelected() && (!selection.rangeCount || selection.isCollapsed)) {
|
|
159
|
+
const anchorClientId = getMultiSelectedBlocksStartClientId();
|
|
160
|
+
const focusClientId = getMultiSelectedBlocksEndClientId();
|
|
161
|
+
const nextClientId = isReverse ? getPreviousBlockClientId(focusClientId) : getNextBlockClientId(focusClientId);
|
|
162
|
+
if (nextClientId) {
|
|
163
|
+
multiSelect(anchorClientId, nextClientId);
|
|
164
|
+
event.preventDefault();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
153
167
|
return;
|
|
154
168
|
}
|
|
155
169
|
if (!__unstableIsFullySelected()) {
|
|
@@ -163,6 +177,15 @@ function useArrowNav() {
|
|
|
163
177
|
}
|
|
164
178
|
return;
|
|
165
179
|
}
|
|
180
|
+
if (shiftKey && getSelectedBlockClientId() && !getSelectionStart().attributeKey) {
|
|
181
|
+
const selectedClientId = getSelectedBlockClientId();
|
|
182
|
+
const nextClientId = isReverse ? getPreviousBlockClientId(selectedClientId) : getNextBlockClientId(selectedClientId);
|
|
183
|
+
if (nextClientId) {
|
|
184
|
+
multiSelect(selectedClientId, nextClientId);
|
|
185
|
+
event.preventDefault();
|
|
186
|
+
}
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
166
189
|
if (!isNavigationCandidate(target, keyCode, hasModifier)) {
|
|
167
190
|
return;
|
|
168
191
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/writing-flow/use-arrow-nav.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {\n\tcomputeCaretRect,\n\tfocus,\n\tisHorizontalEdge,\n\tisVerticalEdge,\n\tplaceCaretAtHorizontalEdge,\n\tplaceCaretAtVerticalEdge,\n\tisRTL,\n\tisFormElement,\n} from '@wordpress/dom';\nimport { UP, DOWN, LEFT, RIGHT } from '@wordpress/keycodes';\nimport { useDispatch, useSelect } from '@wordpress/data';\nimport { useRefEffect } from '@wordpress/compose';\n\n/**\n * Internal dependencies\n */\nimport { getBlockClientId, getSelectionEditableElement } from '../../utils/dom';\nimport { store as blockEditorStore } from '../../store';\nimport { setContentEditableWrapper } from './utils';\n\n/**\n * Returns true if the element should consider edge navigation upon a keyboard\n * event of the given directional key code, or false otherwise.\n *\n * @param {Element} element HTML element to test.\n * @param {number} keyCode KeyboardEvent keyCode to test.\n * @param {boolean} hasModifier Whether a modifier is pressed.\n *\n * @return {boolean} Whether element should consider edge navigation.\n */\nexport function isNavigationCandidate( element, keyCode, hasModifier ) {\n\tconst isVertical = keyCode === UP || keyCode === DOWN;\n\tconst { tagName } = element;\n\tconst elementType = element.getAttribute( 'type' );\n\n\t// Native inputs should not navigate vertically, unless they are simple types that don't need up/down arrow keys.\n\tif ( isVertical && ! hasModifier ) {\n\t\tif ( tagName === 'INPUT' ) {\n\t\t\tconst verticalInputTypes = [\n\t\t\t\t'date',\n\t\t\t\t'datetime-local',\n\t\t\t\t'month',\n\t\t\t\t'number',\n\t\t\t\t'range',\n\t\t\t\t'time',\n\t\t\t\t'week',\n\t\t\t];\n\t\t\treturn ! verticalInputTypes.includes( elementType );\n\t\t}\n\t\treturn true;\n\t}\n\n\t// Native inputs should not navigate horizontally, unless they are simple types that don't need left/right arrow keys.\n\tif ( tagName === 'INPUT' ) {\n\t\tconst simpleInputTypes = [\n\t\t\t'button',\n\t\t\t'checkbox',\n\t\t\t'number',\n\t\t\t'color',\n\t\t\t'file',\n\t\t\t'image',\n\t\t\t'radio',\n\t\t\t'reset',\n\t\t\t'submit',\n\t\t];\n\t\treturn simpleInputTypes.includes( elementType );\n\t}\n\n\t// Native textareas should not navigate horizontally.\n\treturn tagName !== 'TEXTAREA';\n}\n\n/**\n * Returns the optimal tab target from the given focused element in the desired\n * direction. A preference is made toward text fields, falling back to the block\n * focus stop if no other candidates exist for the block.\n *\n * @param {Element} target Currently focused text field.\n * @param {boolean} isReverse True if considering as the first field.\n * @param {Element} containerElement Element containing all blocks.\n * @param {boolean} onlyVertical Whether to only consider tabbable elements\n * that are visually above or under the\n * target.\n *\n * @return {?Element} Optimal tab target, if one exists.\n */\nexport function getClosestTabbable(\n\ttarget,\n\tisReverse,\n\tcontainerElement,\n\tonlyVertical\n) {\n\t// Since the current focus target is not guaranteed to be a text field, find\n\t// all focusables. Tabbability is considered later.\n\tlet focusableNodes = focus.focusable.find( containerElement );\n\n\tif ( isReverse ) {\n\t\tfocusableNodes.reverse();\n\t}\n\n\t// Consider as candidates those focusables after the current target. It's\n\t// assumed this can only be reached if the target is focusable (on its\n\t// keydown event), so no need to verify it exists in the set.\n\tfocusableNodes = focusableNodes.slice(\n\t\tfocusableNodes.indexOf( target ) + 1\n\t);\n\n\tlet targetRect;\n\n\tif ( onlyVertical ) {\n\t\ttargetRect = target.getBoundingClientRect();\n\t}\n\n\tfunction isTabCandidate( node ) {\n\t\t// If it's a block wrapper (not itself a contenteditable editing surface)\n\t\t// and there are nested focusable nodes, skip because there are better\n\t\t// candidates. We must not skip contenteditable nodes that happen to\n\t\t// contain links or other focusable inline elements, since those are the\n\t\t// correct navigation targets.\n\t\t//\n\t\t// See https://github.com/WordPress/gutenberg/pull/77474\n\t\t// TODO: Consider fixing focus.tabbable\n\t\tif (\n\t\t\tnode.contentEditable !== 'true' &&\n\t\t\tgetBlockClientId( node ) &&\n\t\t\tfocus.focusable\n\t\t\t\t.find( node )\n\t\t\t\t// Exclude form elements for now because primary+a cannot be\n\t\t\t\t// used to select the parent element.\n\t\t\t\t.filter( ( element ) => ! isFormElement( element ) ).length !==\n\t\t\t\t0\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Not a candidate if the node is not tabbable.\n\t\tif ( ! focus.tabbable.isTabbableIndex( node ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Skip focusable elements such as links within content editable\n\t\t// nodes: nodes whose closest editable host is an editable element\n\t\t// within a block. When an editable root (e.g. the canvas wrapper)\n\t\t// is the editing host, everything within it is content editable,\n\t\t// but focusables like block wrappers are not text content.\n\t\tif (\n\t\t\tnode.isContentEditable &&\n\t\t\tnode.contentEditable !== 'true' &&\n\t\t\tgetBlockClientId( node.closest( '[contenteditable=\"true\"]' ) )\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( onlyVertical ) {\n\t\t\tconst nodeRect = node.getBoundingClientRect();\n\n\t\t\tif (\n\t\t\t\tnodeRect.left >= targetRect.right ||\n\t\t\t\tnodeRect.right <= targetRect.left\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\treturn focusableNodes.find( isTabCandidate );\n}\n\nexport default function useArrowNav() {\n\tconst {\n\t\tgetMultiSelectedBlocksStartClientId,\n\t\tgetMultiSelectedBlocksEndClientId,\n\t\tgetSettings,\n\t\thasMultiSelection,\n\t\t__unstableIsFullySelected,\n\t} = useSelect( blockEditorStore );\n\tconst { selectBlock } = useDispatch( blockEditorStore );\n\treturn useRefEffect( ( node ) => {\n\t\t// Here a DOMRect is stored while moving the caret vertically so\n\t\t// vertical position of the start position can be restored. This is to\n\t\t// recreate browser behaviour across blocks.\n\t\tlet verticalRect;\n\n\t\tfunction onMouseDown() {\n\t\t\tverticalRect = null;\n\t\t}\n\n\t\tfunction isClosestTabbableABlock( target, isReverse ) {\n\t\t\tconst closestTabbable = getClosestTabbable(\n\t\t\t\ttarget,\n\t\t\t\tisReverse,\n\t\t\t\tnode\n\t\t\t);\n\t\t\treturn closestTabbable && getBlockClientId( closestTabbable );\n\t\t}\n\n\t\tfunction onKeyDown( event ) {\n\t\t\t// Abort if navigation has already been handled (e.g. RichText\n\t\t\t// inline boundaries).\n\t\t\tif ( event.defaultPrevented ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { keyCode, shiftKey, ctrlKey, altKey, metaKey } = event;\n\t\t\t// When the wrapper is contentEditable and holds focus (the\n\t\t\t// selected block supports `editableRoot`), the event targets the\n\t\t\t// wrapper; resolve the editable element containing the selection.\n\t\t\tconst target =\n\t\t\t\t( event.target === node &&\n\t\t\t\t\tgetSelectionEditableElement(\n\t\t\t\t\t\tnode.ownerDocument.defaultView.getSelection(),\n\t\t\t\t\t\tnode\n\t\t\t\t\t) ) ||\n\t\t\t\tevent.target;\n\t\t\tconst isUp = keyCode === UP;\n\t\t\tconst isDown = keyCode === DOWN;\n\t\t\tconst isLeft = keyCode === LEFT;\n\t\t\tconst isRight = keyCode === RIGHT;\n\t\t\tconst isReverse = isUp || isLeft;\n\t\t\tconst isHorizontal = isLeft || isRight;\n\t\t\tconst isVertical = isUp || isDown;\n\t\t\tconst isNav = isHorizontal || isVertical;\n\t\t\tconst hasModifier = shiftKey || ctrlKey || altKey || metaKey;\n\t\t\tconst isNavEdge = isVertical ? isVerticalEdge : isHorizontalEdge;\n\t\t\tconst { ownerDocument } = node;\n\t\t\tconst { defaultView } = ownerDocument;\n\n\t\t\tif ( ! isNav ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// In preview mode, navigation is handled by useSelectableBlocksNav.\n\t\t\tif ( getSettings().isPreviewMode ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If there is a multi-selection, the arrow keys should collapse the\n\t\t\t// selection to the start or end of the selection.\n\t\t\tif ( hasMultiSelection() ) {\n\t\t\t\tif ( shiftKey ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Only handle if we have a full selection (not a native partial\n\t\t\t\t// selection).\n\t\t\t\tif ( ! __unstableIsFullySelected() ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tevent.preventDefault();\n\n\t\t\t\tif ( isReverse ) {\n\t\t\t\t\tselectBlock( getMultiSelectedBlocksStartClientId() );\n\t\t\t\t} else {\n\t\t\t\t\tselectBlock( getMultiSelectedBlocksEndClientId(), -1 );\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Abort if our current target is not a candidate for navigation\n\t\t\t// (e.g. preserve native input behaviors).\n\t\t\tif ( ! isNavigationCandidate( target, keyCode, hasModifier ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// When presing any key other than up or down, the initial vertical\n\t\t\t// position must ALWAYS be reset. The vertical position is saved so\n\t\t\t// it can be restored as well as possible on sebsequent vertical\n\t\t\t// arrow key presses. It may not always be possible to restore the\n\t\t\t// exact same position (such as at an empty line), so it wouldn't be\n\t\t\t// good to compute the position right before any vertical arrow key\n\t\t\t// press.\n\t\t\tif ( ! isVertical ) {\n\t\t\t\tverticalRect = null;\n\t\t\t} else if ( ! verticalRect ) {\n\t\t\t\tverticalRect = computeCaretRect( defaultView );\n\t\t\t}\n\n\t\t\t// In the case of RTL scripts, right means previous and left means\n\t\t\t// next, which is the exact reverse of LTR.\n\t\t\tconst isReverseDir = isRTL( target ) ? ! isReverse : isReverse;\n\t\t\tconst { keepCaretInsideBlock } = getSettings();\n\n\t\t\tif ( shiftKey ) {\n\t\t\t\tif ( isNavEdge( target, isReverse ) ) {\n\t\t\t\t\tif ( isClosestTabbableABlock( target, isReverse ) ) {\n\t\t\t\t\t\tsetContentEditableWrapper( node, true );\n\t\t\t\t\t} else if ( node.contentEditable === 'true' ) {\n\t\t\t\t\t\t// There is no block to extend the selection into.\n\t\t\t\t\t\t// Within an editable wrapper the selection could\n\t\t\t\t\t\t// natively escape into surrounding editable elements\n\t\t\t\t\t\t// (e.g. the post title), so keep it inside the block\n\t\t\t\t\t\t// by extending it to the block's edge.\n\t\t\t\t\t\tconst selection = defaultView.getSelection();\n\t\t\t\t\t\tselection.extend(\n\t\t\t\t\t\t\ttarget,\n\t\t\t\t\t\t\tisReverse ? 0 : target.childNodes.length\n\t\t\t\t\t\t);\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (\n\t\t\t\tisVertical &&\n\t\t\t\tisVerticalEdge( target, isReverse ) &&\n\t\t\t\t// When Alt is pressed, only intercept if the caret is also at\n\t\t\t\t// the horizontal edge.\n\t\t\t\t( altKey ? isHorizontalEdge( target, isReverseDir ) : true ) &&\n\t\t\t\t! keepCaretInsideBlock\n\t\t\t) {\n\t\t\t\tconst closestTabbable = getClosestTabbable(\n\t\t\t\t\ttarget,\n\t\t\t\t\tisReverse,\n\t\t\t\t\tnode,\n\t\t\t\t\ttrue\n\t\t\t\t);\n\n\t\t\t\tif ( closestTabbable ) {\n\t\t\t\t\tplaceCaretAtVerticalEdge(\n\t\t\t\t\t\tclosestTabbable,\n\t\t\t\t\t\t// When Alt is pressed, place the caret at the furthest\n\t\t\t\t\t\t// horizontal edge and the furthest vertical edge.\n\t\t\t\t\t\taltKey ? ! isReverse : isReverse,\n\t\t\t\t\t\taltKey ? undefined : verticalRect\n\t\t\t\t\t);\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t} else if (\n\t\t\t\tisHorizontal &&\n\t\t\t\tdefaultView.getSelection().isCollapsed &&\n\t\t\t\tisHorizontalEdge( target, isReverseDir ) &&\n\t\t\t\t! keepCaretInsideBlock\n\t\t\t) {\n\t\t\t\tconst closestTabbable = getClosestTabbable(\n\t\t\t\t\ttarget,\n\t\t\t\t\tisReverseDir,\n\t\t\t\t\tnode\n\t\t\t\t);\n\t\t\t\tplaceCaretAtHorizontalEdge( closestTabbable, isReverse );\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\t\t}\n\n\t\tnode.addEventListener( 'mousedown', onMouseDown );\n\t\tnode.addEventListener( 'keydown', onKeyDown );\n\t\treturn () => {\n\t\t\tnode.removeEventListener( 'mousedown', onMouseDown );\n\t\t\tnode.removeEventListener( 'keydown', onKeyDown );\n\t\t};\n\t}, [] );\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,iBASO;AACP,sBAAsC;AACtC,kBAAuC;AACvC,qBAA6B;AAK7B,IAAAA,cAA8D;AAC9D,mBAA0C;AAC1C,mBAA0C;AAYnC,SAAS,sBAAuB,SAAS,SAAS,aAAc;AACtE,QAAM,aAAa,YAAY,sBAAM,YAAY;AACjD,QAAM,EAAE,QAAQ,IAAI;AACpB,QAAM,cAAc,QAAQ,aAAc,MAAO;AAGjD,MAAK,cAAc,CAAE,aAAc;AAClC,QAAK,YAAY,SAAU;AAC1B,YAAM,qBAAqB;AAAA,QAC1B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD;AACA,aAAO,CAAE,mBAAmB,SAAU,WAAY;AAAA,IACnD;AACA,WAAO;AAAA,EACR;AAGA,MAAK,YAAY,SAAU;AAC1B,UAAM,mBAAmB;AAAA,MACxB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AACA,WAAO,iBAAiB,SAAU,WAAY;AAAA,EAC/C;AAGA,SAAO,YAAY;AACpB;AAgBO,SAAS,mBACf,QACA,WACA,kBACA,cACC;AAGD,MAAI,iBAAiB,iBAAM,UAAU,KAAM,gBAAiB;AAE5D,MAAK,WAAY;AAChB,mBAAe,QAAQ;AAAA,EACxB;AAKA,mBAAiB,eAAe;AAAA,IAC/B,eAAe,QAAS,MAAO,IAAI;AAAA,EACpC;AAEA,MAAI;AAEJ,MAAK,cAAe;AACnB,iBAAa,OAAO,sBAAsB;AAAA,EAC3C;AAEA,WAAS,eAAgB,MAAO;AAS/B,QACC,KAAK,oBAAoB,cACzB,8BAAkB,IAAK,KACvB,iBAAM,UACJ,KAAM,IAAK,EAGX,OAAQ,CAAE,YAAa,KAAE,0BAAe,OAAQ,CAAE,EAAE,WACrD,GACA;AACD,aAAO;AAAA,IACR;AAGA,QAAK,CAAE,iBAAM,SAAS,gBAAiB,IAAK,GAAI;AAC/C,aAAO;AAAA,IACR;AAOA,QACC,KAAK,qBACL,KAAK,oBAAoB,cACzB,8BAAkB,KAAK,QAAS,0BAA2B,CAAE,GAC5D;AACD,aAAO;AAAA,IACR;AAEA,QAAK,cAAe;AACnB,YAAM,WAAW,KAAK,sBAAsB;AAE5C,UACC,SAAS,QAAQ,WAAW,SAC5B,SAAS,SAAS,WAAW,MAC5B;AACD,eAAO;AAAA,MACR;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAEA,SAAO,eAAe,KAAM,cAAe;AAC5C;AAEe,SAAR,cAA+B;AACrC,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,QAAI,uBAAW,aAAAC,KAAiB;AAChC,QAAM,EAAE,YAAY,QAAI,yBAAa,aAAAA,KAAiB;
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport {\n\tcomputeCaretRect,\n\tfocus,\n\tisHorizontalEdge,\n\tisVerticalEdge,\n\tplaceCaretAtHorizontalEdge,\n\tplaceCaretAtVerticalEdge,\n\tisRTL,\n\tisFormElement,\n} from '@wordpress/dom';\nimport { UP, DOWN, LEFT, RIGHT } from '@wordpress/keycodes';\nimport { useDispatch, useSelect } from '@wordpress/data';\nimport { useRefEffect } from '@wordpress/compose';\n\n/**\n * Internal dependencies\n */\nimport { getBlockClientId, getSelectionEditableElement } from '../../utils/dom';\nimport { store as blockEditorStore } from '../../store';\nimport { setContentEditableWrapper } from './utils';\n\n/**\n * Returns true if the element should consider edge navigation upon a keyboard\n * event of the given directional key code, or false otherwise.\n *\n * @param {Element} element HTML element to test.\n * @param {number} keyCode KeyboardEvent keyCode to test.\n * @param {boolean} hasModifier Whether a modifier is pressed.\n *\n * @return {boolean} Whether element should consider edge navigation.\n */\nexport function isNavigationCandidate( element, keyCode, hasModifier ) {\n\tconst isVertical = keyCode === UP || keyCode === DOWN;\n\tconst { tagName } = element;\n\tconst elementType = element.getAttribute( 'type' );\n\n\t// Native inputs should not navigate vertically, unless they are simple types that don't need up/down arrow keys.\n\tif ( isVertical && ! hasModifier ) {\n\t\tif ( tagName === 'INPUT' ) {\n\t\t\tconst verticalInputTypes = [\n\t\t\t\t'date',\n\t\t\t\t'datetime-local',\n\t\t\t\t'month',\n\t\t\t\t'number',\n\t\t\t\t'range',\n\t\t\t\t'time',\n\t\t\t\t'week',\n\t\t\t];\n\t\t\treturn ! verticalInputTypes.includes( elementType );\n\t\t}\n\t\treturn true;\n\t}\n\n\t// Native inputs should not navigate horizontally, unless they are simple types that don't need left/right arrow keys.\n\tif ( tagName === 'INPUT' ) {\n\t\tconst simpleInputTypes = [\n\t\t\t'button',\n\t\t\t'checkbox',\n\t\t\t'number',\n\t\t\t'color',\n\t\t\t'file',\n\t\t\t'image',\n\t\t\t'radio',\n\t\t\t'reset',\n\t\t\t'submit',\n\t\t];\n\t\treturn simpleInputTypes.includes( elementType );\n\t}\n\n\t// Native textareas should not navigate horizontally.\n\treturn tagName !== 'TEXTAREA';\n}\n\n/**\n * Returns the optimal tab target from the given focused element in the desired\n * direction. A preference is made toward text fields, falling back to the block\n * focus stop if no other candidates exist for the block.\n *\n * @param {Element} target Currently focused text field.\n * @param {boolean} isReverse True if considering as the first field.\n * @param {Element} containerElement Element containing all blocks.\n * @param {boolean} onlyVertical Whether to only consider tabbable elements\n * that are visually above or under the\n * target.\n *\n * @return {?Element} Optimal tab target, if one exists.\n */\nexport function getClosestTabbable(\n\ttarget,\n\tisReverse,\n\tcontainerElement,\n\tonlyVertical\n) {\n\t// Since the current focus target is not guaranteed to be a text field, find\n\t// all focusables. Tabbability is considered later.\n\tlet focusableNodes = focus.focusable.find( containerElement );\n\n\tif ( isReverse ) {\n\t\tfocusableNodes.reverse();\n\t}\n\n\t// Consider as candidates those focusables after the current target. It's\n\t// assumed this can only be reached if the target is focusable (on its\n\t// keydown event), so no need to verify it exists in the set.\n\tfocusableNodes = focusableNodes.slice(\n\t\tfocusableNodes.indexOf( target ) + 1\n\t);\n\n\tlet targetRect;\n\n\tif ( onlyVertical ) {\n\t\ttargetRect = target.getBoundingClientRect();\n\t}\n\n\tfunction isTabCandidate( node ) {\n\t\t// If it's a block wrapper (not itself a contenteditable editing surface)\n\t\t// and there are nested focusable nodes, skip because there are better\n\t\t// candidates. We must not skip contenteditable nodes that happen to\n\t\t// contain links or other focusable inline elements, since those are the\n\t\t// correct navigation targets.\n\t\t//\n\t\t// See https://github.com/WordPress/gutenberg/pull/77474\n\t\t// TODO: Consider fixing focus.tabbable\n\t\tif (\n\t\t\tnode.contentEditable !== 'true' &&\n\t\t\tgetBlockClientId( node ) &&\n\t\t\tfocus.focusable\n\t\t\t\t.find( node )\n\t\t\t\t// Exclude form elements for now because primary+a cannot be\n\t\t\t\t// used to select the parent element.\n\t\t\t\t.filter( ( element ) => ! isFormElement( element ) ).length !==\n\t\t\t\t0\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Not a candidate if the node is not tabbable.\n\t\tif ( ! focus.tabbable.isTabbableIndex( node ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Skip focusable elements such as links within content editable\n\t\t// nodes: nodes whose closest editable host is an editable element\n\t\t// within a block. When an editable root (e.g. the canvas wrapper)\n\t\t// is the editing host, everything within it is content editable,\n\t\t// but focusables like block wrappers are not text content.\n\t\tif (\n\t\t\tnode.isContentEditable &&\n\t\t\tnode.contentEditable !== 'true' &&\n\t\t\tgetBlockClientId( node.closest( '[contenteditable=\"true\"]' ) )\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( onlyVertical ) {\n\t\t\tconst nodeRect = node.getBoundingClientRect();\n\n\t\t\tif (\n\t\t\t\tnodeRect.left >= targetRect.right ||\n\t\t\t\tnodeRect.right <= targetRect.left\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\treturn focusableNodes.find( isTabCandidate );\n}\n\nexport default function useArrowNav() {\n\tconst {\n\t\tgetMultiSelectedBlocksStartClientId,\n\t\tgetMultiSelectedBlocksEndClientId,\n\t\tgetNextBlockClientId,\n\t\tgetPreviousBlockClientId,\n\t\tgetSelectedBlockClientId,\n\t\tgetSelectionStart,\n\t\tgetSettings,\n\t\thasMultiSelection,\n\t\t__unstableIsFullySelected,\n\t} = useSelect( blockEditorStore );\n\tconst { selectBlock, multiSelect } = useDispatch( blockEditorStore );\n\treturn useRefEffect( ( node ) => {\n\t\t// Here a DOMRect is stored while moving the caret vertically so\n\t\t// vertical position of the start position can be restored. This is to\n\t\t// recreate browser behaviour across blocks.\n\t\tlet verticalRect;\n\n\t\tfunction onMouseDown() {\n\t\t\tverticalRect = null;\n\t\t}\n\n\t\tfunction isClosestTabbableABlock( target, isReverse ) {\n\t\t\tconst closestTabbable = getClosestTabbable(\n\t\t\t\ttarget,\n\t\t\t\tisReverse,\n\t\t\t\tnode\n\t\t\t);\n\t\t\treturn closestTabbable && getBlockClientId( closestTabbable );\n\t\t}\n\n\t\tfunction onKeyDown( event ) {\n\t\t\t// Abort if navigation has already been handled (e.g. RichText\n\t\t\t// inline boundaries).\n\t\t\tif ( event.defaultPrevented ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { keyCode, shiftKey, ctrlKey, altKey, metaKey } = event;\n\t\t\t// When the wrapper is contentEditable and holds focus (the\n\t\t\t// selected block supports `editableRoot`), the event targets the\n\t\t\t// wrapper; resolve the editable element containing the selection.\n\t\t\tconst target =\n\t\t\t\t( event.target === node &&\n\t\t\t\t\tgetSelectionEditableElement(\n\t\t\t\t\t\tnode.ownerDocument.defaultView.getSelection(),\n\t\t\t\t\t\tnode\n\t\t\t\t\t) ) ||\n\t\t\t\tevent.target;\n\t\t\tconst isUp = keyCode === UP;\n\t\t\tconst isDown = keyCode === DOWN;\n\t\t\tconst isLeft = keyCode === LEFT;\n\t\t\tconst isRight = keyCode === RIGHT;\n\t\t\tconst isReverse = isUp || isLeft;\n\t\t\tconst isHorizontal = isLeft || isRight;\n\t\t\tconst isVertical = isUp || isDown;\n\t\t\tconst isNav = isHorizontal || isVertical;\n\t\t\tconst hasModifier = shiftKey || ctrlKey || altKey || metaKey;\n\t\t\tconst isNavEdge = isVertical ? isVerticalEdge : isHorizontalEdge;\n\t\t\tconst { ownerDocument } = node;\n\t\t\tconst { defaultView } = ownerDocument;\n\n\t\t\tif ( ! isNav ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// In preview mode, navigation is handled by useSelectableBlocksNav.\n\t\t\tif ( getSettings().isPreviewMode ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If there is a multi-selection, the arrow keys should collapse the\n\t\t\t// selection to the start or end of the selection.\n\t\t\tif ( hasMultiSelection() ) {\n\t\t\t\tif ( shiftKey ) {\n\t\t\t\t\t// A fully selected multi-selection has no native\n\t\t\t\t\t// selection to extend (use-multi-selection cleared it),\n\t\t\t\t\t// so grow or shrink it by one block at the focus end.\n\t\t\t\t\t// Only without a usable native selection: a selection\n\t\t\t\t\t// that is fully selected because it resolves to a\n\t\t\t\t\t// nesting ancestor keeps its native selection, which\n\t\t\t\t\t// the browser extends natively (and the observer\n\t\t\t\t\t// promotes to the common level).\n\t\t\t\t\tconst selection = defaultView.getSelection();\n\t\t\t\t\tif (\n\t\t\t\t\t\t__unstableIsFullySelected() &&\n\t\t\t\t\t\t( ! selection.rangeCount || selection.isCollapsed )\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst anchorClientId =\n\t\t\t\t\t\t\tgetMultiSelectedBlocksStartClientId();\n\t\t\t\t\t\tconst focusClientId =\n\t\t\t\t\t\t\tgetMultiSelectedBlocksEndClientId();\n\t\t\t\t\t\tconst nextClientId = isReverse\n\t\t\t\t\t\t\t? getPreviousBlockClientId( focusClientId )\n\t\t\t\t\t\t\t: getNextBlockClientId( focusClientId );\n\n\t\t\t\t\t\tif ( nextClientId ) {\n\t\t\t\t\t\t\tmultiSelect( anchorClientId, nextClientId );\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Only handle if we have a full selection (not a native partial\n\t\t\t\t// selection).\n\t\t\t\tif ( ! __unstableIsFullySelected() ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tevent.preventDefault();\n\n\t\t\t\tif ( isReverse ) {\n\t\t\t\t\tselectBlock( getMultiSelectedBlocksStartClientId() );\n\t\t\t\t} else {\n\t\t\t\t\tselectBlock( getMultiSelectedBlocksEndClientId(), -1 );\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// A block selected without a text selection within it (e.g. an\n\t\t\t// image or spacer) has no native selection to extend: start a\n\t\t\t// block multi-selection with the adjacent block.\n\t\t\tif (\n\t\t\t\tshiftKey &&\n\t\t\t\tgetSelectedBlockClientId() &&\n\t\t\t\t! getSelectionStart().attributeKey\n\t\t\t) {\n\t\t\t\tconst selectedClientId = getSelectedBlockClientId();\n\t\t\t\tconst nextClientId = isReverse\n\t\t\t\t\t? getPreviousBlockClientId( selectedClientId )\n\t\t\t\t\t: getNextBlockClientId( selectedClientId );\n\n\t\t\t\tif ( nextClientId ) {\n\t\t\t\t\tmultiSelect( selectedClientId, nextClientId );\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Abort if our current target is not a candidate for navigation\n\t\t\t// (e.g. preserve native input behaviors).\n\t\t\tif ( ! isNavigationCandidate( target, keyCode, hasModifier ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// When presing any key other than up or down, the initial vertical\n\t\t\t// position must ALWAYS be reset. The vertical position is saved so\n\t\t\t// it can be restored as well as possible on sebsequent vertical\n\t\t\t// arrow key presses. It may not always be possible to restore the\n\t\t\t// exact same position (such as at an empty line), so it wouldn't be\n\t\t\t// good to compute the position right before any vertical arrow key\n\t\t\t// press.\n\t\t\tif ( ! isVertical ) {\n\t\t\t\tverticalRect = null;\n\t\t\t} else if ( ! verticalRect ) {\n\t\t\t\tverticalRect = computeCaretRect( defaultView );\n\t\t\t}\n\n\t\t\t// In the case of RTL scripts, right means previous and left means\n\t\t\t// next, which is the exact reverse of LTR.\n\t\t\tconst isReverseDir = isRTL( target ) ? ! isReverse : isReverse;\n\t\t\tconst { keepCaretInsideBlock } = getSettings();\n\n\t\t\tif ( shiftKey ) {\n\t\t\t\tif ( isNavEdge( target, isReverse ) ) {\n\t\t\t\t\tif ( isClosestTabbableABlock( target, isReverse ) ) {\n\t\t\t\t\t\tsetContentEditableWrapper( node, true );\n\t\t\t\t\t} else if ( node.contentEditable === 'true' ) {\n\t\t\t\t\t\t// There is no block to extend the selection into.\n\t\t\t\t\t\t// Within an editable wrapper the selection could\n\t\t\t\t\t\t// natively escape into surrounding editable elements\n\t\t\t\t\t\t// (e.g. the post title), so keep it inside the block\n\t\t\t\t\t\t// by extending it to the block's edge.\n\t\t\t\t\t\tconst selection = defaultView.getSelection();\n\t\t\t\t\t\tselection.extend(\n\t\t\t\t\t\t\ttarget,\n\t\t\t\t\t\t\tisReverse ? 0 : target.childNodes.length\n\t\t\t\t\t\t);\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (\n\t\t\t\tisVertical &&\n\t\t\t\tisVerticalEdge( target, isReverse ) &&\n\t\t\t\t// When Alt is pressed, only intercept if the caret is also at\n\t\t\t\t// the horizontal edge.\n\t\t\t\t( altKey ? isHorizontalEdge( target, isReverseDir ) : true ) &&\n\t\t\t\t! keepCaretInsideBlock\n\t\t\t) {\n\t\t\t\tconst closestTabbable = getClosestTabbable(\n\t\t\t\t\ttarget,\n\t\t\t\t\tisReverse,\n\t\t\t\t\tnode,\n\t\t\t\t\ttrue\n\t\t\t\t);\n\n\t\t\t\tif ( closestTabbable ) {\n\t\t\t\t\tplaceCaretAtVerticalEdge(\n\t\t\t\t\t\tclosestTabbable,\n\t\t\t\t\t\t// When Alt is pressed, place the caret at the furthest\n\t\t\t\t\t\t// horizontal edge and the furthest vertical edge.\n\t\t\t\t\t\taltKey ? ! isReverse : isReverse,\n\t\t\t\t\t\taltKey ? undefined : verticalRect\n\t\t\t\t\t);\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t} else if (\n\t\t\t\tisHorizontal &&\n\t\t\t\tdefaultView.getSelection().isCollapsed &&\n\t\t\t\tisHorizontalEdge( target, isReverseDir ) &&\n\t\t\t\t! keepCaretInsideBlock\n\t\t\t) {\n\t\t\t\tconst closestTabbable = getClosestTabbable(\n\t\t\t\t\ttarget,\n\t\t\t\t\tisReverseDir,\n\t\t\t\t\tnode\n\t\t\t\t);\n\t\t\t\tplaceCaretAtHorizontalEdge( closestTabbable, isReverse );\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\t\t}\n\n\t\tnode.addEventListener( 'mousedown', onMouseDown );\n\t\tnode.addEventListener( 'keydown', onKeyDown );\n\t\treturn () => {\n\t\t\tnode.removeEventListener( 'mousedown', onMouseDown );\n\t\t\tnode.removeEventListener( 'keydown', onKeyDown );\n\t\t};\n\t}, [] );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["import_dom", "blockEditorStore"]
|
|
7
7
|
}
|
|
@@ -30,7 +30,12 @@ var import_utils = require("./utils.cjs");
|
|
|
30
30
|
var import_dom = require("../../utils/dom.cjs");
|
|
31
31
|
function useClickSelection() {
|
|
32
32
|
const { selectBlock } = (0, import_data.useDispatch)(import_store.store);
|
|
33
|
-
const {
|
|
33
|
+
const {
|
|
34
|
+
isSelectionEnabled,
|
|
35
|
+
getBlockSelectionStart,
|
|
36
|
+
getSelectionStart,
|
|
37
|
+
hasMultiSelection
|
|
38
|
+
} = (0, import_data.useSelect)(import_store.store);
|
|
34
39
|
return (0, import_compose.useRefEffect)(
|
|
35
40
|
(node) => {
|
|
36
41
|
function onMouseDown(event) {
|
|
@@ -41,7 +46,27 @@ function useClickSelection() {
|
|
|
41
46
|
const clickedClientId = (0, import_dom.getBlockClientId)(event.target);
|
|
42
47
|
if (event.shiftKey) {
|
|
43
48
|
if (startClientId && startClientId !== clickedClientId) {
|
|
44
|
-
|
|
49
|
+
const { clientId, attributeKey } = getSelectionStart();
|
|
50
|
+
(0, import_utils.setContentEditableWrapper)(node, true, {
|
|
51
|
+
focus: !!attributeKey
|
|
52
|
+
});
|
|
53
|
+
const { ownerDocument } = node;
|
|
54
|
+
const selection = ownerDocument.defaultView.getSelection();
|
|
55
|
+
const blockElement = !attributeKey && ownerDocument.getElementById(
|
|
56
|
+
`block-${clientId}`
|
|
57
|
+
);
|
|
58
|
+
if (blockElement && !(selection.anchorNode && blockElement.contains(selection.anchorNode))) {
|
|
59
|
+
const isForward = (
|
|
60
|
+
// eslint-disable-next-line no-bitwise
|
|
61
|
+
blockElement.compareDocumentPosition(
|
|
62
|
+
event.target
|
|
63
|
+
) & node.DOCUMENT_POSITION_FOLLOWING
|
|
64
|
+
);
|
|
65
|
+
selection.setPosition(
|
|
66
|
+
blockElement,
|
|
67
|
+
isForward ? 0 : blockElement.childNodes.length
|
|
68
|
+
);
|
|
69
|
+
}
|
|
45
70
|
}
|
|
46
71
|
} else if (hasMultiSelection()) {
|
|
47
72
|
selectBlock(clickedClientId);
|
|
@@ -56,6 +81,7 @@ function useClickSelection() {
|
|
|
56
81
|
selectBlock,
|
|
57
82
|
isSelectionEnabled,
|
|
58
83
|
getBlockSelectionStart,
|
|
84
|
+
getSelectionStart,
|
|
59
85
|
hasMultiSelection
|
|
60
86
|
]
|
|
61
87
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/writing-flow/use-click-selection.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useSelect, useDispatch } from '@wordpress/data';\nimport { useRefEffect } from '@wordpress/compose';\n\n/**\n * Internal dependencies\n */\nimport { store as blockEditorStore } from '../../store';\nimport { setContentEditableWrapper } from './utils';\nimport { getBlockClientId } from '../../utils/dom';\n\nexport default function useClickSelection() {\n\tconst { selectBlock } = useDispatch( blockEditorStore );\n\tconst {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAAuC;AACvC,qBAA6B;AAK7B,mBAA0C;AAC1C,mBAA0C;AAC1C,iBAAiC;AAElB,SAAR,oBAAqC;AAC3C,QAAM,EAAE,YAAY,QAAI,yBAAa,aAAAA,KAAiB;AACtD,QAAM,
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useSelect, useDispatch } from '@wordpress/data';\nimport { useRefEffect } from '@wordpress/compose';\n\n/**\n * Internal dependencies\n */\nimport { store as blockEditorStore } from '../../store';\nimport { setContentEditableWrapper } from './utils';\nimport { getBlockClientId } from '../../utils/dom';\n\nexport default function useClickSelection() {\n\tconst { selectBlock } = useDispatch( blockEditorStore );\n\tconst {\n\t\tisSelectionEnabled,\n\t\tgetBlockSelectionStart,\n\t\tgetSelectionStart,\n\t\thasMultiSelection,\n\t} = useSelect( blockEditorStore );\n\treturn useRefEffect(\n\t\t( node ) => {\n\t\t\tfunction onMouseDown( event ) {\n\t\t\t\t// The main button.\n\t\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button\n\t\t\t\tif ( ! isSelectionEnabled() || event.button !== 0 ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst startClientId = getBlockSelectionStart();\n\t\t\t\tconst clickedClientId = getBlockClientId( event.target );\n\n\t\t\t\tif ( event.shiftKey ) {\n\t\t\t\t\t// When selecting a single block in a document by holding the shift key,\n\t\t\t\t\t// don't mark this action as multiselection.\n\t\t\t\t\tif ( startClientId && startClientId !== clickedClientId ) {\n\t\t\t\t\t\t// When the selected block has no text selection\n\t\t\t\t\t\t// within it (e.g. an image or spacer), there is no\n\t\t\t\t\t\t// native selection for the wrapper to adopt when it\n\t\t\t\t\t\t// is focused, so Safari inserts a caret at the start\n\t\t\t\t\t\t// of the wrapper and asynchronously reveals it,\n\t\t\t\t\t\t// scrolling a scrolled-down viewport back up, which\n\t\t\t\t\t\t// `preventScroll` does not cover. Leave focus alone\n\t\t\t\t\t\t// in that case: the click moves it.\n\t\t\t\t\t\tconst { clientId, attributeKey } = getSelectionStart();\n\t\t\t\t\t\tsetContentEditableWrapper( node, true, {\n\t\t\t\t\t\t\tfocus: !! attributeKey,\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t\t// The browser extends the selection from the native\n\t\t\t\t\t\t// anchor. When a block is selected without a text\n\t\t\t\t\t\t// selection within it, there is no native anchor,\n\t\t\t\t\t\t// and browsers synthesize one at the nearest text\n\t\t\t\t\t\t// instead, excluding the block itself. Give the\n\t\t\t\t\t\t// browser the right anchor before it acts on the\n\t\t\t\t\t\t// click: the near edge of the selected block, so the\n\t\t\t\t\t\t// whole block ends up within the extended selection.\n\t\t\t\t\t\tconst { ownerDocument } = node;\n\t\t\t\t\t\tconst selection =\n\t\t\t\t\t\t\townerDocument.defaultView.getSelection();\n\t\t\t\t\t\tconst blockElement =\n\t\t\t\t\t\t\t! attributeKey &&\n\t\t\t\t\t\t\townerDocument.getElementById(\n\t\t\t\t\t\t\t\t`block-${ clientId }`\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tblockElement &&\n\t\t\t\t\t\t\t! (\n\t\t\t\t\t\t\t\tselection.anchorNode &&\n\t\t\t\t\t\t\t\tblockElement.contains( selection.anchorNode )\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tconst isForward =\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-bitwise\n\t\t\t\t\t\t\t\tblockElement.compareDocumentPosition(\n\t\t\t\t\t\t\t\t\tevent.target\n\t\t\t\t\t\t\t\t) & node.DOCUMENT_POSITION_FOLLOWING;\n\t\t\t\t\t\t\tselection.setPosition(\n\t\t\t\t\t\t\t\tblockElement,\n\t\t\t\t\t\t\t\tisForward ? 0 : blockElement.childNodes.length\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} else if ( hasMultiSelection() ) {\n\t\t\t\t\t// Allow user to escape out of a multi-selection to a\n\t\t\t\t\t// singular selection of a block via click. This is handled\n\t\t\t\t\t// here since focus handling excludes blocks when there is\n\t\t\t\t\t// multiselection, as focus can be incurred by starting a\n\t\t\t\t\t// multiselection (focus moved to first block's multi-\n\t\t\t\t\t// controls).\n\t\t\t\t\tselectBlock( clickedClientId );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tnode.addEventListener( 'mousedown', onMouseDown );\n\n\t\t\treturn () => {\n\t\t\t\tnode.removeEventListener( 'mousedown', onMouseDown );\n\t\t\t};\n\t\t},\n\t\t[\n\t\t\tselectBlock,\n\t\t\tisSelectionEnabled,\n\t\t\tgetBlockSelectionStart,\n\t\t\tgetSelectionStart,\n\t\t\thasMultiSelection,\n\t\t]\n\t);\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAAuC;AACvC,qBAA6B;AAK7B,mBAA0C;AAC1C,mBAA0C;AAC1C,iBAAiC;AAElB,SAAR,oBAAqC;AAC3C,QAAM,EAAE,YAAY,QAAI,yBAAa,aAAAA,KAAiB;AACtD,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,QAAI,uBAAW,aAAAA,KAAiB;AAChC,aAAO;AAAA,IACN,CAAE,SAAU;AACX,eAAS,YAAa,OAAQ;AAG7B,YAAK,CAAE,mBAAmB,KAAK,MAAM,WAAW,GAAI;AACnD;AAAA,QACD;AAEA,cAAM,gBAAgB,uBAAuB;AAC7C,cAAM,sBAAkB,6BAAkB,MAAM,MAAO;AAEvD,YAAK,MAAM,UAAW;AAGrB,cAAK,iBAAiB,kBAAkB,iBAAkB;AASzD,kBAAM,EAAE,UAAU,aAAa,IAAI,kBAAkB;AACrD,wDAA2B,MAAM,MAAM;AAAA,cACtC,OAAO,CAAC,CAAE;AAAA,YACX,CAAE;AAUF,kBAAM,EAAE,cAAc,IAAI;AAC1B,kBAAM,YACL,cAAc,YAAY,aAAa;AACxC,kBAAM,eACL,CAAE,gBACF,cAAc;AAAA,cACb,SAAU,QAAS;AAAA,YACpB;AAED,gBACC,gBACA,EACC,UAAU,cACV,aAAa,SAAU,UAAU,UAAW,IAE5C;AACD,oBAAM;AAAA;AAAA,gBAEL,aAAa;AAAA,kBACZ,MAAM;AAAA,gBACP,IAAI,KAAK;AAAA;AACV,wBAAU;AAAA,gBACT;AAAA,gBACA,YAAY,IAAI,aAAa,WAAW;AAAA,cACzC;AAAA,YACD;AAAA,UACD;AAAA,QACD,WAAY,kBAAkB,GAAI;AAOjC,sBAAa,eAAgB;AAAA,QAC9B;AAAA,MACD;AAEA,WAAK,iBAAkB,aAAa,WAAY;AAEhD,aAAO,MAAM;AACZ,aAAK,oBAAqB,aAAa,WAAY;AAAA,MACpD;AAAA,IACD;AAAA,IACA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AACD;",
|
|
6
6
|
"names": ["blockEditorStore"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// packages/block-editor/src/components/writing-flow/use-editable-root-event-handlers.js
|
|
21
|
+
var use_editable_root_event_handlers_exports = {};
|
|
22
|
+
__export(use_editable_root_event_handlers_exports, {
|
|
23
|
+
default: () => useEditableRootEventHandlers,
|
|
24
|
+
getEventHandlers: () => getEventHandlers
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(use_editable_root_event_handlers_exports);
|
|
27
|
+
var import_data = require("@wordpress/data");
|
|
28
|
+
var import_compose = require("@wordpress/compose");
|
|
29
|
+
var import_element = require("@wordpress/element");
|
|
30
|
+
var import_store = require("../../store/index.cjs");
|
|
31
|
+
var import_dom = require("../../utils/dom.cjs");
|
|
32
|
+
var import_block_refs_provider = require("../provider/block-refs-provider.cjs");
|
|
33
|
+
var SUPPORTED_EVENTS = {
|
|
34
|
+
onKeyDown: "keydown",
|
|
35
|
+
onKeyUp: "keyup",
|
|
36
|
+
onBeforeInput: "beforeinput",
|
|
37
|
+
onInput: "input",
|
|
38
|
+
onCompositionStart: "compositionstart",
|
|
39
|
+
onCompositionUpdate: "compositionupdate",
|
|
40
|
+
onCompositionEnd: "compositionend"
|
|
41
|
+
};
|
|
42
|
+
var EVENT_TYPES = Object.values(SUPPORTED_EVENTS);
|
|
43
|
+
function getEventHandlers(props) {
|
|
44
|
+
let handlers;
|
|
45
|
+
for (const name in SUPPORTED_EVENTS) {
|
|
46
|
+
if (typeof props[name] === "function") {
|
|
47
|
+
handlers = handlers || {};
|
|
48
|
+
handlers[SUPPORTED_EVENTS[name]] = props[name];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return handlers;
|
|
52
|
+
}
|
|
53
|
+
var EVENT_INTERFACE = [
|
|
54
|
+
"eventPhase",
|
|
55
|
+
"bubbles",
|
|
56
|
+
"cancelable",
|
|
57
|
+
"timeStamp",
|
|
58
|
+
"defaultPrevented",
|
|
59
|
+
"isTrusted"
|
|
60
|
+
];
|
|
61
|
+
var KEYBOARD_EVENT_INTERFACE = [
|
|
62
|
+
...EVENT_INTERFACE,
|
|
63
|
+
"view",
|
|
64
|
+
"detail",
|
|
65
|
+
"key",
|
|
66
|
+
"code",
|
|
67
|
+
"location",
|
|
68
|
+
"ctrlKey",
|
|
69
|
+
"shiftKey",
|
|
70
|
+
"altKey",
|
|
71
|
+
"metaKey",
|
|
72
|
+
"repeat",
|
|
73
|
+
"locale",
|
|
74
|
+
"getModifierState",
|
|
75
|
+
"charCode",
|
|
76
|
+
"keyCode",
|
|
77
|
+
"which"
|
|
78
|
+
];
|
|
79
|
+
var INPUT_EVENT_INTERFACE = [...EVENT_INTERFACE, "data"];
|
|
80
|
+
var EVENT_INTERFACES = {
|
|
81
|
+
keydown: KEYBOARD_EVENT_INTERFACE,
|
|
82
|
+
keyup: KEYBOARD_EVENT_INTERFACE,
|
|
83
|
+
beforeinput: INPUT_EVENT_INTERFACE,
|
|
84
|
+
input: INPUT_EVENT_INTERFACE,
|
|
85
|
+
compositionstart: INPUT_EVENT_INTERFACE,
|
|
86
|
+
compositionupdate: INPUT_EVENT_INTERFACE,
|
|
87
|
+
compositionend: INPUT_EVENT_INTERFACE
|
|
88
|
+
};
|
|
89
|
+
function createBlockSyntheticEvent(nativeEvent, target) {
|
|
90
|
+
let propagationStopped = false;
|
|
91
|
+
const syntheticEvent = {
|
|
92
|
+
nativeEvent,
|
|
93
|
+
type: nativeEvent.type,
|
|
94
|
+
target,
|
|
95
|
+
currentTarget: null,
|
|
96
|
+
preventDefault() {
|
|
97
|
+
nativeEvent.preventDefault();
|
|
98
|
+
syntheticEvent.defaultPrevented = true;
|
|
99
|
+
},
|
|
100
|
+
isDefaultPrevented() {
|
|
101
|
+
return syntheticEvent.defaultPrevented;
|
|
102
|
+
},
|
|
103
|
+
stopPropagation() {
|
|
104
|
+
nativeEvent.stopPropagation();
|
|
105
|
+
propagationStopped = true;
|
|
106
|
+
},
|
|
107
|
+
isPropagationStopped() {
|
|
108
|
+
return propagationStopped;
|
|
109
|
+
},
|
|
110
|
+
// The modern event system doesn't pool, so persistence is a no-op.
|
|
111
|
+
persist() {
|
|
112
|
+
},
|
|
113
|
+
isPersistent() {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
for (const property of EVENT_INTERFACES[nativeEvent.type]) {
|
|
118
|
+
const value = nativeEvent[property];
|
|
119
|
+
syntheticEvent[property] = typeof value === "function" ? value.bind(nativeEvent) : value;
|
|
120
|
+
}
|
|
121
|
+
return syntheticEvent;
|
|
122
|
+
}
|
|
123
|
+
function useEditableRootEventHandlers() {
|
|
124
|
+
const { hasMultiSelection, getBlockParents } = (0, import_data.useSelect)(import_store.store);
|
|
125
|
+
const { refsMap, eventHandlers } = (0, import_element.useContext)(import_block_refs_provider.BlockRefs);
|
|
126
|
+
return (0, import_compose.useRefEffect)(
|
|
127
|
+
(node) => {
|
|
128
|
+
function onEvent(event) {
|
|
129
|
+
if (!eventHandlers.size || event.target !== node || !event.isTrusted || node.contentEditable !== "true" || hasMultiSelection()) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const selection = node.ownerDocument.defaultView.getSelection();
|
|
133
|
+
if (!selection.rangeCount) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const editable = (0, import_dom.getSelectionEditableElement)(selection, node);
|
|
137
|
+
const clientId = (0, import_dom.getBlockClientId)(editable);
|
|
138
|
+
if (!clientId) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const clientIds = [
|
|
142
|
+
clientId,
|
|
143
|
+
...getBlockParents(clientId, true)
|
|
144
|
+
];
|
|
145
|
+
let syntheticEvent;
|
|
146
|
+
for (const ancestorClientId of clientIds) {
|
|
147
|
+
const handler = eventHandlers.get(ancestorClientId)?.current?.[event.type];
|
|
148
|
+
const element = handler && refsMap.get(ancestorClientId);
|
|
149
|
+
if (!element) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (!syntheticEvent) {
|
|
153
|
+
syntheticEvent = createBlockSyntheticEvent(
|
|
154
|
+
event,
|
|
155
|
+
editable
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
syntheticEvent.currentTarget = element;
|
|
159
|
+
handler(syntheticEvent);
|
|
160
|
+
if (syntheticEvent.isPropagationStopped()) {
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const root = node.ownerDocument.documentElement;
|
|
166
|
+
const unsubscribers = EVENT_TYPES.map((type) => {
|
|
167
|
+
root.addEventListener(type, onEvent);
|
|
168
|
+
return () => root.removeEventListener(type, onEvent);
|
|
169
|
+
});
|
|
170
|
+
return () => unsubscribers.forEach((unsubscribe) => unsubscribe());
|
|
171
|
+
},
|
|
172
|
+
[hasMultiSelection, getBlockParents, refsMap, eventHandlers]
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
176
|
+
0 && (module.exports = {
|
|
177
|
+
getEventHandlers
|
|
178
|
+
});
|
|
179
|
+
//# sourceMappingURL=use-editable-root-event-handlers.cjs.map
|