@wordpress/components 32.6.0 → 33.0.1-next.v.202604201441.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/build/autocomplete/get-autocomplete-match.cjs +11 -2
  3. package/build/autocomplete/get-autocomplete-match.cjs.map +2 -2
  4. package/build/autocomplete/index.cjs +42 -11
  5. package/build/autocomplete/index.cjs.map +2 -2
  6. package/build/external-link/index.cjs +1 -1
  7. package/build/external-link/index.cjs.map +2 -2
  8. package/build/menu/styles.cjs +15 -15
  9. package/build/menu/styles.cjs.map +2 -2
  10. package/build/navigable-container/container.cjs +72 -110
  11. package/build/navigable-container/container.cjs.map +2 -2
  12. package/build-module/autocomplete/get-autocomplete-match.mjs +11 -2
  13. package/build-module/autocomplete/get-autocomplete-match.mjs.map +2 -2
  14. package/build-module/autocomplete/index.mjs +42 -11
  15. package/build-module/autocomplete/index.mjs.map +2 -2
  16. package/build-module/external-link/index.mjs +1 -1
  17. package/build-module/external-link/index.mjs.map +2 -2
  18. package/build-module/menu/styles.mjs +15 -15
  19. package/build-module/menu/styles.mjs.map +2 -2
  20. package/build-module/navigable-container/container.mjs +73 -111
  21. package/build-module/navigable-container/container.mjs.map +2 -2
  22. package/build-types/autocomplete/get-autocomplete-match.d.ts +10 -1
  23. package/build-types/autocomplete/get-autocomplete-match.d.ts.map +1 -1
  24. package/build-types/autocomplete/index.d.ts.map +1 -1
  25. package/build-types/base-control/stories/index.story.d.ts.map +1 -1
  26. package/build-types/button/stories/index.story.d.ts.map +1 -1
  27. package/build-types/checkbox-control/stories/index.story.d.ts.map +1 -1
  28. package/build-types/color-indicator/stories/index.story.d.ts.map +1 -1
  29. package/build-types/color-palette/stories/index.story.d.ts.map +1 -1
  30. package/build-types/color-picker/stories/index.story.d.ts.map +1 -1
  31. package/build-types/combobox-control/stories/index.story.d.ts.map +1 -1
  32. package/build-types/composite/stories/index.story.d.ts.map +1 -1
  33. package/build-types/custom-select-control/stories/index.story.d.ts.map +1 -1
  34. package/build-types/disabled/stories/index.story.d.ts.map +1 -1
  35. package/build-types/drop-zone/stories/index.story.d.ts.map +1 -1
  36. package/build-types/dropdown/stories/index.story.d.ts.map +1 -1
  37. package/build-types/external-link/index.d.ts.map +1 -1
  38. package/build-types/external-link/stories/index.story.d.ts.map +1 -1
  39. package/build-types/form-file-upload/stories/index.story.d.ts.map +1 -1
  40. package/build-types/form-toggle/stories/index.story.d.ts.map +1 -1
  41. package/build-types/form-token-field/stories/index.story.d.ts.map +1 -1
  42. package/build-types/gradient-picker/stories/index.story.d.ts.map +1 -1
  43. package/build-types/icon/stories/index.story.d.ts.map +1 -1
  44. package/build-types/keyboard-shortcuts/stories/index.story.d.ts.map +1 -1
  45. package/build-types/menu-group/stories/index.story.d.ts.map +1 -1
  46. package/build-types/menu-item/stories/index.story.d.ts.map +1 -1
  47. package/build-types/menu-items-choice/stories/index.story.d.ts.map +1 -1
  48. package/build-types/modal/stories/index.story.d.ts.map +1 -1
  49. package/build-types/navigable-container/container.d.ts +3 -8
  50. package/build-types/navigable-container/container.d.ts.map +1 -1
  51. package/build-types/navigable-container/types.d.ts +1 -5
  52. package/build-types/navigable-container/types.d.ts.map +1 -1
  53. package/build-types/navigation/stories/utils/more-examples.d.ts.map +1 -1
  54. package/build-types/navigator/stories/index.story.d.ts.map +1 -1
  55. package/build-types/notice/stories/index.story.d.ts.map +1 -1
  56. package/build-types/panel/stories/index.story.d.ts.map +1 -1
  57. package/build-types/popover/stories/index.story.d.ts.map +1 -1
  58. package/build-types/progress-bar/stories/index.story.d.ts.map +1 -1
  59. package/build-types/radio-control/stories/index.story.d.ts.map +1 -1
  60. package/build-types/range-control/stories/index.story.d.ts.map +1 -1
  61. package/build-types/resizable-box/stories/index.story.d.ts.map +1 -1
  62. package/build-types/sandbox/stories/index.story.d.ts.map +1 -1
  63. package/build-types/scroll-lock/stories/index.story.d.ts.map +1 -1
  64. package/build-types/search-control/stories/index.story.d.ts.map +1 -1
  65. package/build-types/select-control/stories/index.story.d.ts.map +1 -1
  66. package/build-types/shortcut/stories/index.story.d.ts.map +1 -1
  67. package/build-types/slot-fill/stories/index.story.d.ts.map +1 -1
  68. package/build-types/snackbar/stories/index.story.d.ts.map +1 -1
  69. package/build-types/spinner/stories/index.story.d.ts.map +1 -1
  70. package/build-types/text-control/stories/index.story.d.ts.map +1 -1
  71. package/build-types/text-highlight/stories/index.story.d.ts.map +1 -1
  72. package/build-types/textarea-control/stories/index.story.d.ts.map +1 -1
  73. package/build-types/toggle-control/stories/index.story.d.ts.map +1 -1
  74. package/build-types/tooltip/stories/index.story.d.ts.map +1 -1
  75. package/build-types/tree-select/stories/index.story.d.ts.map +1 -1
  76. package/build-types/visually-hidden/stories/index.story.d.ts.map +1 -1
  77. package/package.json +21 -21
  78. package/src/autocomplete/get-autocomplete-match.ts +25 -4
  79. package/src/autocomplete/index.tsx +69 -21
  80. package/src/autocomplete/test/get-autocomplete-match.ts +97 -75
  81. package/src/base-control/stories/index.story.tsx +1 -0
  82. package/src/button/stories/index.story.tsx +1 -0
  83. package/src/checkbox-control/stories/index.story.tsx +1 -0
  84. package/src/color-indicator/stories/index.story.tsx +1 -0
  85. package/src/color-palette/stories/index.story.tsx +1 -0
  86. package/src/color-picker/stories/index.story.tsx +1 -0
  87. package/src/combobox-control/stories/index.story.tsx +1 -0
  88. package/src/composite/stories/index.story.tsx +1 -0
  89. package/src/confirm-dialog/stories/index.story.tsx +1 -1
  90. package/src/custom-select-control/stories/index.story.tsx +1 -0
  91. package/src/disabled/stories/index.story.tsx +1 -0
  92. package/src/drop-zone/stories/index.story.tsx +1 -0
  93. package/src/dropdown/stories/index.story.tsx +1 -0
  94. package/src/external-link/index.tsx +1 -6
  95. package/src/external-link/stories/index.story.tsx +1 -0
  96. package/src/form-file-upload/stories/index.story.tsx +1 -0
  97. package/src/form-toggle/stories/index.story.tsx +1 -0
  98. package/src/form-token-field/stories/index.story.tsx +1 -0
  99. package/src/gradient-picker/stories/index.story.tsx +1 -0
  100. package/src/icon/stories/index.story.tsx +1 -0
  101. package/src/input-control/stories/index.story.tsx +1 -1
  102. package/src/item-group/stories/index.story.tsx +1 -1
  103. package/src/keyboard-shortcuts/stories/index.story.tsx +1 -0
  104. package/src/menu/styles.ts +1 -1
  105. package/src/menu-group/stories/index.story.tsx +1 -0
  106. package/src/menu-item/stories/index.story.tsx +1 -0
  107. package/src/menu-items-choice/stories/index.story.tsx +1 -0
  108. package/src/mobile/link-settings/index.native.js +1 -1
  109. package/src/modal/stories/index.story.tsx +1 -0
  110. package/src/navigable-container/container.tsx +120 -141
  111. package/src/navigable-container/test/navigable-menu.tsx +24 -0
  112. package/src/navigable-container/types.ts +1 -5
  113. package/src/navigation/stories/utils/more-examples.tsx +2 -1
  114. package/src/navigator/stories/index.story.tsx +1 -0
  115. package/src/notice/stories/index.story.tsx +1 -0
  116. package/src/number-control/stories/index.story.tsx +1 -1
  117. package/src/panel/stories/index.story.tsx +1 -0
  118. package/src/popover/stories/index.story.tsx +1 -0
  119. package/src/progress-bar/stories/index.story.tsx +1 -0
  120. package/src/radio-control/stories/index.story.tsx +1 -0
  121. package/src/range-control/stories/index.story.tsx +1 -0
  122. package/src/resizable-box/stories/index.story.tsx +1 -0
  123. package/src/sandbox/stories/index.story.tsx +1 -0
  124. package/src/scroll-lock/stories/index.story.tsx +1 -0
  125. package/src/search-control/stories/index.story.tsx +1 -0
  126. package/src/select-control/stories/index.story.tsx +1 -0
  127. package/src/shortcut/stories/index.story.tsx +1 -0
  128. package/src/slot-fill/stories/index.story.tsx +1 -0
  129. package/src/snackbar/stories/index.story.tsx +1 -0
  130. package/src/spinner/stories/index.story.tsx +1 -0
  131. package/src/text-control/stories/index.story.tsx +1 -0
  132. package/src/text-highlight/stories/index.story.tsx +1 -0
  133. package/src/textarea-control/stories/index.story.tsx +1 -0
  134. package/src/toggle-control/stories/index.story.tsx +1 -0
  135. package/src/toggle-group-control/stories/index.story.tsx +1 -1
  136. package/src/tooltip/stories/index.story.tsx +1 -0
  137. package/src/tree-grid/stories/index.story.tsx +1 -1
  138. package/src/tree-select/stories/index.story.tsx +1 -0
  139. package/src/truncate/stories/index.story.tsx +1 -1
  140. package/src/unit-control/stories/index.story.tsx +1 -1
  141. package/src/visually-hidden/stories/index.story.tsx +1 -0
  142. package/build/card/context.cjs +0 -36
  143. package/build/card/context.cjs.map +0 -7
  144. package/build-module/card/context.mjs +0 -10
  145. package/build-module/card/context.mjs.map +0 -7
  146. package/build-types/card/context.d.ts +0 -3
  147. package/build-types/card/context.d.ts.map +0 -1
  148. package/src/card/context.ts +0 -9
@@ -24,6 +24,7 @@ __export(container_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(container_exports);
26
26
  var import_element = require("@wordpress/element");
27
+ var import_compose = require("@wordpress/compose");
27
28
  var import_dom = require("@wordpress/dom");
28
29
  var import_jsx_runtime = require("react/jsx-runtime");
29
30
  var noop = () => {
@@ -38,47 +39,27 @@ function cycleValue(value, total, offset) {
38
39
  }
39
40
  return nextValue;
40
41
  }
41
- var NavigableContainer = class extends import_element.Component {
42
- constructor(args) {
43
- super(args);
44
- this.onKeyDown = this.onKeyDown.bind(this);
45
- this.bindContainer = this.bindContainer.bind(this);
46
- this.getFocusableContext = this.getFocusableContext.bind(this);
47
- this.getFocusableIndex = this.getFocusableIndex.bind(this);
48
- }
49
- componentDidMount() {
50
- if (!this.container) {
51
- return;
52
- }
53
- this.container.addEventListener("keydown", this.onKeyDown);
54
- }
55
- componentWillUnmount() {
56
- if (!this.container) {
57
- return;
58
- }
59
- this.container.removeEventListener("keydown", this.onKeyDown);
60
- }
61
- bindContainer(ref) {
62
- const {
63
- forwardedRef
64
- } = this.props;
65
- this.container = ref;
66
- if (typeof forwardedRef === "function") {
67
- forwardedRef(ref);
68
- } else if (forwardedRef && "current" in forwardedRef) {
69
- forwardedRef.current = ref;
70
- }
71
- }
72
- getFocusableContext(target) {
73
- if (!this.container) {
42
+ function UnforwardedNavigableContainer({
43
+ children,
44
+ stopNavigationEvents,
45
+ eventToOffset,
46
+ onNavigate = noop,
47
+ onKeyDown,
48
+ cycle = true,
49
+ onlyBrowserTabstops,
50
+ ...restProps
51
+ }, ref) {
52
+ const containerRef = (0, import_element.useRef)(null);
53
+ const getFocusableIndex = (0, import_element.useCallback)((focusables, target) => {
54
+ return focusables.indexOf(target);
55
+ }, []);
56
+ const getFocusableContext = (0, import_element.useCallback)((target) => {
57
+ if (!containerRef.current) {
74
58
  return null;
75
59
  }
76
- const {
77
- onlyBrowserTabstops
78
- } = this.props;
79
60
  const finder = onlyBrowserTabstops ? import_dom.focus.tabbable : import_dom.focus.focusable;
80
- const focusables = finder.find(this.container);
81
- const index = this.getFocusableIndex(focusables, target);
61
+ const focusables = finder.find(containerRef.current);
62
+ const index = getFocusableIndex(focusables, target);
82
63
  if (index > -1 && target) {
83
64
  return {
84
65
  index,
@@ -87,81 +68,62 @@ var NavigableContainer = class extends import_element.Component {
87
68
  };
88
69
  }
89
70
  return null;
90
- }
91
- getFocusableIndex(focusables, target) {
92
- return focusables.indexOf(target);
93
- }
94
- onKeyDown(event) {
95
- if (this.props.onKeyDown) {
96
- this.props.onKeyDown(event);
97
- }
98
- const {
99
- getFocusableContext
100
- } = this;
101
- const {
102
- cycle = true,
103
- eventToOffset,
104
- onNavigate = noop,
105
- stopNavigationEvents
106
- } = this.props;
107
- const offset = eventToOffset(event);
108
- if (offset !== void 0 && stopNavigationEvents) {
109
- event.stopImmediatePropagation();
110
- const targetRole = event.target?.getAttribute("role");
111
- const targetHasMenuItemRole = !!targetRole && MENU_ITEM_ROLES.includes(targetRole);
112
- if (targetHasMenuItemRole) {
113
- event.preventDefault();
114
- }
115
- }
116
- if (!offset) {
71
+ }, [onlyBrowserTabstops, getFocusableIndex]);
72
+ (0, import_element.useEffect)(() => {
73
+ const container = containerRef.current;
74
+ if (!container) {
117
75
  return;
118
76
  }
119
- const activeElement = event.target?.ownerDocument?.activeElement;
120
- if (!activeElement) {
121
- return;
122
- }
123
- const context = getFocusableContext(activeElement);
124
- if (!context) {
125
- return;
126
- }
127
- const {
128
- index,
129
- focusables
130
- } = context;
131
- const nextIndex = cycle ? cycleValue(index, focusables.length, offset) : index + offset;
132
- if (nextIndex >= 0 && nextIndex < focusables.length) {
133
- focusables[nextIndex].focus();
134
- onNavigate(nextIndex, focusables[nextIndex]);
135
- if (event.code === "Tab") {
136
- event.preventDefault();
77
+ function handleKeyDown(event) {
78
+ if (onKeyDown) {
79
+ onKeyDown(event);
80
+ }
81
+ const offset = eventToOffset(event);
82
+ if (offset !== void 0 && stopNavigationEvents) {
83
+ event.stopImmediatePropagation();
84
+ const targetRole = event.target?.getAttribute("role");
85
+ const targetHasMenuItemRole = !!targetRole && MENU_ITEM_ROLES.includes(targetRole);
86
+ if (targetHasMenuItemRole) {
87
+ event.preventDefault();
88
+ }
89
+ }
90
+ if (!offset) {
91
+ return;
92
+ }
93
+ const activeElement = event.target?.ownerDocument?.activeElement;
94
+ if (!activeElement) {
95
+ return;
96
+ }
97
+ const context = getFocusableContext(activeElement);
98
+ if (!context) {
99
+ return;
100
+ }
101
+ const {
102
+ index,
103
+ focusables
104
+ } = context;
105
+ const nextIndex = cycle ? cycleValue(index, focusables.length, offset) : index + offset;
106
+ if (nextIndex >= 0 && nextIndex < focusables.length) {
107
+ focusables[nextIndex].focus();
108
+ onNavigate(nextIndex, focusables[nextIndex]);
109
+ if (event.code === "Tab") {
110
+ event.preventDefault();
111
+ }
137
112
  }
138
113
  }
139
- }
140
- render() {
141
- const {
142
- children,
143
- stopNavigationEvents,
144
- eventToOffset,
145
- onNavigate,
146
- onKeyDown,
147
- cycle,
148
- onlyBrowserTabstops,
149
- forwardedRef,
150
- ...restProps
151
- } = this.props;
152
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
153
- ref: this.bindContainer,
154
- ...restProps,
155
- children
156
- });
157
- }
158
- };
159
- var forwardedNavigableContainer = (props, ref) => {
160
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NavigableContainer, {
161
- ...props,
162
- forwardedRef: ref
114
+ container.addEventListener("keydown", handleKeyDown);
115
+ return () => {
116
+ container.removeEventListener("keydown", handleKeyDown);
117
+ };
118
+ }, [onKeyDown, eventToOffset, stopNavigationEvents, cycle, onNavigate, getFocusableContext]);
119
+ const mergedRef = (0, import_compose.useMergeRefs)([containerRef, ref]);
120
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
121
+ ref: mergedRef,
122
+ ...restProps,
123
+ children
163
124
  });
164
- };
165
- forwardedNavigableContainer.displayName = "NavigableContainer";
166
- var container_default = (0, import_element.forwardRef)(forwardedNavigableContainer);
125
+ }
126
+ var NavigableContainer = (0, import_element.forwardRef)(UnforwardedNavigableContainer);
127
+ NavigableContainer.displayName = "NavigableContainer";
128
+ var container_default = NavigableContainer;
167
129
  //# sourceMappingURL=container.cjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/navigable-container/container.tsx"],
4
- "sourcesContent": ["/**\n * External dependencies\n */\n\n/**\n * WordPress dependencies\n */\nimport { Component, forwardRef } from '@wordpress/element';\nimport { focus } from '@wordpress/dom';\n\n/**\n * Internal dependencies\n */\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nconst noop = () => {};\nconst MENU_ITEM_ROLES = ['menuitem', 'menuitemradio', 'menuitemcheckbox'];\nfunction cycleValue(value, total, offset) {\n const nextValue = value + offset;\n if (nextValue < 0) {\n return total + nextValue;\n } else if (nextValue >= total) {\n return nextValue - total;\n }\n return nextValue;\n}\nclass NavigableContainer extends Component {\n constructor(args) {\n super(args);\n this.onKeyDown = this.onKeyDown.bind(this);\n this.bindContainer = this.bindContainer.bind(this);\n this.getFocusableContext = this.getFocusableContext.bind(this);\n this.getFocusableIndex = this.getFocusableIndex.bind(this);\n }\n componentDidMount() {\n if (!this.container) {\n return;\n }\n\n // We use DOM event listeners instead of React event listeners\n // because we want to catch events from the underlying DOM tree\n // The React Tree can be different from the DOM tree when using\n // portals. Block Toolbars for instance are rendered in a separate\n // React Trees.\n this.container.addEventListener('keydown', this.onKeyDown);\n }\n componentWillUnmount() {\n if (!this.container) {\n return;\n }\n this.container.removeEventListener('keydown', this.onKeyDown);\n }\n bindContainer(ref) {\n const {\n forwardedRef\n } = this.props;\n this.container = ref;\n if (typeof forwardedRef === 'function') {\n forwardedRef(ref);\n } else if (forwardedRef && 'current' in forwardedRef) {\n forwardedRef.current = ref;\n }\n }\n getFocusableContext(target) {\n if (!this.container) {\n return null;\n }\n const {\n onlyBrowserTabstops\n } = this.props;\n const finder = onlyBrowserTabstops ? focus.tabbable : focus.focusable;\n const focusables = finder.find(this.container);\n const index = this.getFocusableIndex(focusables, target);\n if (index > -1 && target) {\n return {\n index,\n target,\n focusables\n };\n }\n return null;\n }\n getFocusableIndex(focusables, target) {\n return focusables.indexOf(target);\n }\n onKeyDown(event) {\n if (this.props.onKeyDown) {\n this.props.onKeyDown(event);\n }\n const {\n getFocusableContext\n } = this;\n const {\n cycle = true,\n eventToOffset,\n onNavigate = noop,\n stopNavigationEvents\n } = this.props;\n const offset = eventToOffset(event);\n\n // eventToOffset returns undefined if the event is not handled by the component.\n if (offset !== undefined && stopNavigationEvents) {\n // Prevents arrow key handlers bound to the document directly interfering.\n event.stopImmediatePropagation();\n\n // When navigating a collection of items, prevent scroll containers\n // from scrolling. The preventDefault also prevents Voiceover from\n // 'handling' the event, as voiceover will try to use arrow keys\n // for highlighting text.\n const targetRole = event.target?.getAttribute('role');\n const targetHasMenuItemRole = !!targetRole && MENU_ITEM_ROLES.includes(targetRole);\n if (targetHasMenuItemRole) {\n event.preventDefault();\n }\n }\n if (!offset) {\n return;\n }\n const activeElement = event.target?.ownerDocument?.activeElement;\n if (!activeElement) {\n return;\n }\n const context = getFocusableContext(activeElement);\n if (!context) {\n return;\n }\n const {\n index,\n focusables\n } = context;\n const nextIndex = cycle ? cycleValue(index, focusables.length, offset) : index + offset;\n if (nextIndex >= 0 && nextIndex < focusables.length) {\n focusables[nextIndex].focus();\n onNavigate(nextIndex, focusables[nextIndex]);\n\n // `preventDefault()` on tab to avoid having the browser move the focus\n // after this component has already moved it.\n if (event.code === 'Tab') {\n event.preventDefault();\n }\n }\n }\n render() {\n const {\n children,\n stopNavigationEvents,\n eventToOffset,\n onNavigate,\n onKeyDown,\n cycle,\n onlyBrowserTabstops,\n forwardedRef,\n ...restProps\n } = this.props;\n return /*#__PURE__*/_jsx(\"div\", {\n ref: this.bindContainer,\n ...restProps,\n children: children\n });\n }\n}\nconst forwardedNavigableContainer = (props, ref) => {\n return /*#__PURE__*/_jsx(NavigableContainer, {\n ...props,\n forwardedRef: ref\n });\n};\nforwardedNavigableContainer.displayName = 'NavigableContainer';\nexport default forwardRef(forwardedNavigableContainer);"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * External dependencies\n */\n\n/**\n * WordPress dependencies\n */\nimport { forwardRef, useRef, useEffect, useCallback } from '@wordpress/element';\nimport { useMergeRefs } from '@wordpress/compose';\nimport { focus } from '@wordpress/dom';\n\n/**\n * Internal dependencies\n */\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nconst noop = () => {};\nconst MENU_ITEM_ROLES = ['menuitem', 'menuitemradio', 'menuitemcheckbox'];\nfunction cycleValue(value, total, offset) {\n const nextValue = value + offset;\n if (nextValue < 0) {\n return total + nextValue;\n } else if (nextValue >= total) {\n return nextValue - total;\n }\n return nextValue;\n}\nfunction UnforwardedNavigableContainer({\n children,\n stopNavigationEvents,\n eventToOffset,\n onNavigate = noop,\n onKeyDown,\n cycle = true,\n onlyBrowserTabstops,\n ...restProps\n}, ref) {\n const containerRef = useRef(null);\n const getFocusableIndex = useCallback((focusables, target) => {\n return focusables.indexOf(target);\n }, []);\n const getFocusableContext = useCallback(target => {\n if (!containerRef.current) {\n return null;\n }\n const finder = onlyBrowserTabstops ? focus.tabbable : focus.focusable;\n const focusables = finder.find(containerRef.current);\n const index = getFocusableIndex(focusables, target);\n if (index > -1 && target) {\n return {\n index,\n target,\n focusables\n };\n }\n return null;\n }, [onlyBrowserTabstops, getFocusableIndex]);\n useEffect(() => {\n const container = containerRef.current;\n if (!container) {\n return;\n }\n function handleKeyDown(event) {\n if (onKeyDown) {\n onKeyDown(event);\n }\n const offset = eventToOffset(event);\n\n // eventToOffset returns undefined if the event is not handled by the component.\n if (offset !== undefined && stopNavigationEvents) {\n // Prevents arrow key handlers bound to the document directly interfering.\n event.stopImmediatePropagation();\n\n // When navigating a collection of items, prevent scroll containers\n // from scrolling. The preventDefault also prevents Voiceover from\n // 'handling' the event, as voiceover will try to use arrow keys\n // for highlighting text.\n const targetRole = event.target?.getAttribute('role');\n const targetHasMenuItemRole = !!targetRole && MENU_ITEM_ROLES.includes(targetRole);\n if (targetHasMenuItemRole) {\n event.preventDefault();\n }\n }\n if (!offset) {\n return;\n }\n const activeElement = event.target?.ownerDocument?.activeElement;\n if (!activeElement) {\n return;\n }\n const context = getFocusableContext(activeElement);\n if (!context) {\n return;\n }\n const {\n index,\n focusables\n } = context;\n const nextIndex = cycle ? cycleValue(index, focusables.length, offset) : index + offset;\n if (nextIndex >= 0 && nextIndex < focusables.length) {\n focusables[nextIndex].focus();\n onNavigate(nextIndex, focusables[nextIndex]);\n\n // `preventDefault()` on tab to avoid having the browser move the focus\n // after this component has already moved it.\n if (event.code === 'Tab') {\n event.preventDefault();\n }\n }\n }\n\n // We use DOM event listeners instead of React event listeners\n // because we want to catch events from the underlying DOM tree.\n // The React Tree can be different from the DOM tree when using\n // portals. Block Toolbars for instance are rendered in a separate\n // React Trees.\n container.addEventListener('keydown', handleKeyDown);\n return () => {\n container.removeEventListener('keydown', handleKeyDown);\n };\n }, [onKeyDown, eventToOffset, stopNavigationEvents, cycle, onNavigate, getFocusableContext]);\n const mergedRef = useMergeRefs([containerRef, ref]);\n return /*#__PURE__*/_jsx(\"div\", {\n ref: mergedRef,\n ...restProps,\n children: children\n });\n}\nconst NavigableContainer = forwardRef(UnforwardedNavigableContainer);\nNavigableContainer.displayName = 'NavigableContainer';\nexport default NavigableContainer;"],
5
+ "mappings": "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",
6
6
  "names": ["_jsx"]
7
7
  }
@@ -1,6 +1,12 @@
1
1
  // packages/components/src/autocomplete/get-autocomplete-match.ts
2
2
  import removeAccents from "remove-accents";
3
- function getAutocompleteMatch(textContent, completers, filteredOptionsLength, isBackspacing, getTextAfterSelection) {
3
+ function getAutocompleteMatch(textContent, completers, options) {
4
+ const {
5
+ matchCount,
6
+ isBackspacing,
7
+ getTextAfterSelection,
8
+ lastCompletion
9
+ } = options;
4
10
  if (!textContent) {
5
11
  return null;
6
12
  }
@@ -32,7 +38,7 @@ function getAutocompleteMatch(textContent, completers, filteredOptionsLength, is
32
38
  if (textWithoutTrigger.length > 50) {
33
39
  return null;
34
40
  }
35
- const mismatch = filteredOptionsLength === 0;
41
+ const mismatch = matchCount === 0;
36
42
  const wordsFromTrigger = textWithoutTrigger.split(/\s/);
37
43
  const hasOneTriggerWord = wordsFromTrigger.length === 1;
38
44
  const matchingWhileBackspacing = isBackspacing && wordsFromTrigger.length <= 3;
@@ -45,6 +51,9 @@ function getAutocompleteMatch(textContent, completers, filteredOptionsLength, is
45
51
  if (/^\s/.test(textWithoutTrigger) || /\s\s+$/.test(textWithoutTrigger)) {
46
52
  return null;
47
53
  }
54
+ if (lastCompletion && lastCompletion.name === completer.name && textWithoutTrigger.trimEnd() === lastCompletion.value) {
55
+ return null;
56
+ }
48
57
  return {
49
58
  completer,
50
59
  filterValue: removeAccents(textWithoutTrigger)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/autocomplete/get-autocomplete-match.ts"],
4
- "sourcesContent": ["/**\n * External dependencies\n */\nimport removeAccents from 'remove-accents';\n\n/**\n * Internal dependencies\n */\n\nexport function getAutocompleteMatch(textContent, completers, filteredOptionsLength, isBackspacing, getTextAfterSelection) {\n if (!textContent) {\n return null;\n }\n\n // Find the completer whose trigger prefix ends closest to the cursor\n // (rightmost end position). Comparing end positions instead of start\n // positions correctly resolves overlapping prefixes like \"@\" and \"@@\".\n let completer = null;\n let triggerIndex = -1;\n let matchedEndIndex = -1;\n let matchedPrefixLength = 0;\n for (const currentCompleter of completers) {\n const currentIndex = textContent.lastIndexOf(currentCompleter.triggerPrefix);\n if (currentIndex < 0) {\n continue;\n }\n const currentEndIndex = currentIndex + currentCompleter.triggerPrefix.length;\n if (currentEndIndex > matchedEndIndex || currentEndIndex === matchedEndIndex && currentCompleter.triggerPrefix.length > matchedPrefixLength) {\n completer = currentCompleter;\n triggerIndex = currentIndex;\n matchedEndIndex = currentEndIndex;\n matchedPrefixLength = currentCompleter.triggerPrefix.length;\n }\n }\n if (!completer) {\n return null;\n }\n const {\n allowContext,\n triggerPrefix\n } = completer;\n const textWithoutTrigger = textContent.slice(triggerIndex + triggerPrefix.length);\n\n // Prevent matching with an extremely long string, which causes\n // the editor to slow-down significantly. This could happen, for\n // example, if `matchingWhileBackspacing` is true and one of the\n // \"words\" ends up being too long. Returning null here intentionally\n // resets the autocompleter state in the caller.\n if (textWithoutTrigger.length > 50) {\n return null;\n }\n const mismatch = filteredOptionsLength === 0;\n const wordsFromTrigger = textWithoutTrigger.split(/\\s/);\n\n // Allow matching when typing a trigger + the match string or when\n // clicking in an existing trigger word on the page.\n // E.g. \"Some text @a\" \u2014 \"@a\" is detected as a trigger word.\n const hasOneTriggerWord = wordsFromTrigger.length === 1;\n\n // Allow matching when backspacing near a trigger word (up to 3\n // words from the trigger character). This lets us recover from a\n // mismatch when backspacing while still imposing sane limits.\n // E.g. \"Some text @marcelo sekkkk\" \u2014 backspacing \"kkkk\" re-shows\n // the popup once the text matches again.\n const matchingWhileBackspacing = isBackspacing && wordsFromTrigger.length <= 3;\n if (mismatch && !(matchingWhileBackspacing || hasOneTriggerWord)) {\n return null;\n }\n if (allowContext && !allowContext(textContent.slice(0, triggerIndex), getTextAfterSelection())) {\n return null;\n }\n if (/^\\s/.test(textWithoutTrigger) || /\\s\\s+$/.test(textWithoutTrigger)) {\n return null;\n }\n return {\n completer,\n filterValue: removeAccents(textWithoutTrigger)\n };\n}"],
5
- "mappings": ";AAGA,OAAO,mBAAmB;AAMnB,SAAS,qBAAqB,aAAa,YAAY,uBAAuB,eAAe,uBAAuB;AACzH,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAKA,MAAI,YAAY;AAChB,MAAI,eAAe;AACnB,MAAI,kBAAkB;AACtB,MAAI,sBAAsB;AAC1B,aAAW,oBAAoB,YAAY;AACzC,UAAM,eAAe,YAAY,YAAY,iBAAiB,aAAa;AAC3E,QAAI,eAAe,GAAG;AACpB;AAAA,IACF;AACA,UAAM,kBAAkB,eAAe,iBAAiB,cAAc;AACtE,QAAI,kBAAkB,mBAAmB,oBAAoB,mBAAmB,iBAAiB,cAAc,SAAS,qBAAqB;AAC3I,kBAAY;AACZ,qBAAe;AACf,wBAAkB;AAClB,4BAAsB,iBAAiB,cAAc;AAAA,IACvD;AAAA,EACF;AACA,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AACA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,EACF,IAAI;AACJ,QAAM,qBAAqB,YAAY,MAAM,eAAe,cAAc,MAAM;AAOhF,MAAI,mBAAmB,SAAS,IAAI;AAClC,WAAO;AAAA,EACT;AACA,QAAM,WAAW,0BAA0B;AAC3C,QAAM,mBAAmB,mBAAmB,MAAM,IAAI;AAKtD,QAAM,oBAAoB,iBAAiB,WAAW;AAOtD,QAAM,2BAA2B,iBAAiB,iBAAiB,UAAU;AAC7E,MAAI,YAAY,EAAE,4BAA4B,oBAAoB;AAChE,WAAO;AAAA,EACT;AACA,MAAI,gBAAgB,CAAC,aAAa,YAAY,MAAM,GAAG,YAAY,GAAG,sBAAsB,CAAC,GAAG;AAC9F,WAAO;AAAA,EACT;AACA,MAAI,MAAM,KAAK,kBAAkB,KAAK,SAAS,KAAK,kBAAkB,GAAG;AACvE,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL;AAAA,IACA,aAAa,cAAc,kBAAkB;AAAA,EAC/C;AACF;",
4
+ "sourcesContent": ["/**\n * External dependencies\n */\nimport removeAccents from 'remove-accents';\n\n/**\n * Internal dependencies\n */\n\nexport function getAutocompleteMatch(textContent, completers, options) {\n const {\n matchCount,\n isBackspacing,\n getTextAfterSelection,\n lastCompletion\n } = options;\n if (!textContent) {\n return null;\n }\n\n // Find the completer whose trigger prefix ends closest to the cursor\n // (rightmost end position). Comparing end positions instead of start\n // positions correctly resolves overlapping prefixes like \"@\" and \"@@\".\n let completer = null;\n let triggerIndex = -1;\n let matchedEndIndex = -1;\n let matchedPrefixLength = 0;\n for (const currentCompleter of completers) {\n const currentIndex = textContent.lastIndexOf(currentCompleter.triggerPrefix);\n if (currentIndex < 0) {\n continue;\n }\n const currentEndIndex = currentIndex + currentCompleter.triggerPrefix.length;\n if (currentEndIndex > matchedEndIndex || currentEndIndex === matchedEndIndex && currentCompleter.triggerPrefix.length > matchedPrefixLength) {\n completer = currentCompleter;\n triggerIndex = currentIndex;\n matchedEndIndex = currentEndIndex;\n matchedPrefixLength = currentCompleter.triggerPrefix.length;\n }\n }\n if (!completer) {\n return null;\n }\n const {\n allowContext,\n triggerPrefix\n } = completer;\n const textWithoutTrigger = textContent.slice(triggerIndex + triggerPrefix.length);\n\n // Prevent matching with an extremely long string, which causes\n // the editor to slow-down significantly. This could happen, for\n // example, if `matchingWhileBackspacing` is true and one of the\n // \"words\" ends up being too long. Returning null here intentionally\n // resets the autocompleter state in the caller.\n if (textWithoutTrigger.length > 50) {\n return null;\n }\n const mismatch = matchCount === 0;\n const wordsFromTrigger = textWithoutTrigger.split(/\\s/);\n\n // Allow matching when typing a trigger + the match string or when\n // clicking in an existing trigger word on the page.\n // E.g. \"Some text @a\" \u2014 \"@a\" is detected as a trigger word.\n const hasOneTriggerWord = wordsFromTrigger.length === 1;\n\n // Allow matching when backspacing near a trigger word (up to 3\n // words from the trigger character). This lets us recover from a\n // mismatch when backspacing while still imposing sane limits.\n // E.g. \"Some text @marcelo sekkkk\" \u2014 backspacing \"kkkk\" re-shows\n // the popup once the text matches again.\n const matchingWhileBackspacing = isBackspacing && wordsFromTrigger.length <= 3;\n if (mismatch && !(matchingWhileBackspacing || hasOneTriggerWord)) {\n return null;\n }\n if (allowContext && !allowContext(textContent.slice(0, triggerIndex), getTextAfterSelection())) {\n return null;\n }\n if (/^\\s/.test(textWithoutTrigger) || /\\s\\s+$/.test(textWithoutTrigger)) {\n return null;\n }\n\n // After a completion whose value starts with the trigger prefix\n // (e.g. @username), the trigger remains in the text and would\n // re-activate the autocompleter. Suppress the match when the\n // filter value still corresponds to the recently completed text.\n if (lastCompletion && lastCompletion.name === completer.name && textWithoutTrigger.trimEnd() === lastCompletion.value) {\n return null;\n }\n return {\n completer,\n filterValue: removeAccents(textWithoutTrigger)\n };\n}"],
5
+ "mappings": ";AAGA,OAAO,mBAAmB;AAMnB,SAAS,qBAAqB,aAAa,YAAY,SAAS;AACrE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAKA,MAAI,YAAY;AAChB,MAAI,eAAe;AACnB,MAAI,kBAAkB;AACtB,MAAI,sBAAsB;AAC1B,aAAW,oBAAoB,YAAY;AACzC,UAAM,eAAe,YAAY,YAAY,iBAAiB,aAAa;AAC3E,QAAI,eAAe,GAAG;AACpB;AAAA,IACF;AACA,UAAM,kBAAkB,eAAe,iBAAiB,cAAc;AACtE,QAAI,kBAAkB,mBAAmB,oBAAoB,mBAAmB,iBAAiB,cAAc,SAAS,qBAAqB;AAC3I,kBAAY;AACZ,qBAAe;AACf,wBAAkB;AAClB,4BAAsB,iBAAiB,cAAc;AAAA,IACvD;AAAA,EACF;AACA,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AACA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,EACF,IAAI;AACJ,QAAM,qBAAqB,YAAY,MAAM,eAAe,cAAc,MAAM;AAOhF,MAAI,mBAAmB,SAAS,IAAI;AAClC,WAAO;AAAA,EACT;AACA,QAAM,WAAW,eAAe;AAChC,QAAM,mBAAmB,mBAAmB,MAAM,IAAI;AAKtD,QAAM,oBAAoB,iBAAiB,WAAW;AAOtD,QAAM,2BAA2B,iBAAiB,iBAAiB,UAAU;AAC7E,MAAI,YAAY,EAAE,4BAA4B,oBAAoB;AAChE,WAAO;AAAA,EACT;AACA,MAAI,gBAAgB,CAAC,aAAa,YAAY,MAAM,GAAG,YAAY,GAAG,sBAAsB,CAAC,GAAG;AAC9F,WAAO;AAAA,EACT;AACA,MAAI,MAAM,KAAK,kBAAkB,KAAK,SAAS,KAAK,kBAAkB,GAAG;AACvE,WAAO;AAAA,EACT;AAMA,MAAI,kBAAkB,eAAe,SAAS,UAAU,QAAQ,mBAAmB,QAAQ,MAAM,eAAe,OAAO;AACrH,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL;AAAA,IACA,aAAa,cAAc,kBAAkB;AAAA,EAC/C;AACF;",
6
6
  "names": []
7
7
  }
@@ -65,9 +65,11 @@ function useAutocomplete({
65
65
  autocompleter
66
66
  } = state;
67
67
  const backspacingRef = useRef(false);
68
+ const prevRecordTextRef = useRef("");
69
+ const lastCompletionRef = useRef(null);
68
70
  function insertCompletion(replacement) {
69
71
  if (autocompleter === null) {
70
- return;
72
+ return "";
71
73
  }
72
74
  const end = record.start;
73
75
  const start = end - autocompleter.triggerPrefix.length - filterValue.length;
@@ -75,21 +77,37 @@ function useAutocomplete({
75
77
  html: renderToString(replacement)
76
78
  });
77
79
  onChange(insert(record, toInsert, start, end));
80
+ return getTextContent(toInsert);
78
81
  }
79
82
  function select(option) {
83
+ if (option.isDisabled || !autocompleter) {
84
+ return;
85
+ }
80
86
  const {
81
87
  getOptionCompletion
82
- } = autocompleter || {};
83
- if (option.isDisabled) {
88
+ } = autocompleter;
89
+ if (!getOptionCompletion) {
90
+ dispatch({
91
+ type: "RESET"
92
+ });
93
+ contentRef.current?.focus();
84
94
  return;
85
95
  }
86
- if (getOptionCompletion) {
87
- const completionObject = getCompletionObject(getOptionCompletion(option.value, filterValue));
88
- if ("replace" === completionObject.action) {
89
- onReplace([completionObject.value]);
90
- return;
91
- } else if ("insert-at-caret" === completionObject.action) {
92
- insertCompletion(completionObject.value);
96
+ const completionObject = getCompletionObject(getOptionCompletion(option.value, filterValue));
97
+ if ("replace" === completionObject.action) {
98
+ onReplace([completionObject.value]);
99
+ return;
100
+ }
101
+ if ("insert-at-caret" === completionObject.action) {
102
+ const completionText = insertCompletion(completionObject.value);
103
+ if (completionText.startsWith(autocompleter.triggerPrefix)) {
104
+ const afterPrefix = completionText.slice(autocompleter.triggerPrefix.length);
105
+ if (afterPrefix) {
106
+ lastCompletionRef.current = {
107
+ name: autocompleter.name,
108
+ value: afterPrefix
109
+ };
110
+ }
93
111
  }
94
112
  }
95
113
  dispatch({
@@ -155,10 +173,17 @@ function useAutocomplete({
155
173
  return "";
156
174
  }, [record]);
157
175
  useEffect(() => {
176
+ const isTextChange = record.text !== prevRecordTextRef.current;
177
+ prevRecordTextRef.current = record.text;
158
178
  function getTextAfterSelection() {
159
179
  return textContent ? getTextContent(slice(record, void 0, getTextContent(record).length)) : "";
160
180
  }
161
- const match = getAutocompleteMatch(textContent, completers, filteredOptions.length, backspacingRef.current, getTextAfterSelection);
181
+ const match = getAutocompleteMatch(textContent, completers, {
182
+ matchCount: filteredOptions.length,
183
+ isBackspacing: backspacingRef.current,
184
+ getTextAfterSelection,
185
+ lastCompletion: lastCompletionRef.current
186
+ });
162
187
  if (!match) {
163
188
  if (autocompleter) {
164
189
  dispatch({
@@ -171,6 +196,12 @@ function useAutocomplete({
171
196
  completer,
172
197
  filterValue: query
173
198
  } = match;
199
+ if (!autocompleter && !isTextChange) {
200
+ return;
201
+ }
202
+ if (lastCompletionRef.current && lastCompletionRef.current.name === completer.name) {
203
+ lastCompletionRef.current = null;
204
+ }
174
205
  dispatch({
175
206
  type: "MATCH",
176
207
  completer,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/autocomplete/index.tsx"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { renderToString, useEffect, useMemo, useReducer, useRef } from '@wordpress/element';\nimport { useInstanceId, useMergeRefs, useRefEffect } from '@wordpress/compose';\nimport { create, slice, insert, isCollapsed, getTextContent } from '@wordpress/rich-text';\nimport { speak } from '@wordpress/a11y';\nimport { isAppleOS } from '@wordpress/keycodes';\n\n/**\n * Internal dependencies\n */\nimport { AutocompleterUI } from './autocompleter-ui';\nimport { getAutocompleteMatch } from './get-autocomplete-match';\nimport { withIgnoreIMEEvents } from '../utils/with-ignore-ime-events';\nimport getNodeText from '../utils/get-node-text';\nimport { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from \"react/jsx-runtime\";\nconst EMPTY_FILTERED_OPTIONS = [];\n\n// Used for generating the instance ID\nconst AUTOCOMPLETE_HOOK_REFERENCE = {};\nfunction getCompletionObject(completion) {\n if (completion !== null && typeof completion === 'object' && 'action' in completion && completion.action !== undefined && 'value' in completion && completion.value !== undefined) {\n return completion;\n }\n return {\n action: 'insert-at-caret',\n value: completion\n };\n}\nconst initialState = {\n selectedIndex: 0,\n filteredOptions: EMPTY_FILTERED_OPTIONS,\n filterValue: '',\n autocompleter: null\n};\nfunction autocompleteReducer(state, action) {\n switch (action.type) {\n case 'RESET':\n return initialState;\n case 'SELECT':\n return {\n ...state,\n selectedIndex: action.index\n };\n case 'OPTIONS':\n return {\n ...state,\n filteredOptions: action.options,\n selectedIndex: action.options.length === state.filteredOptions.length ? state.selectedIndex : 0\n };\n case 'MATCH':\n return {\n ...state,\n autocompleter: action.completer,\n filterValue: action.query\n };\n }\n}\nexport function useAutocomplete({\n record,\n onChange,\n onReplace,\n completers,\n contentRef\n}) {\n const instanceId = useInstanceId(AUTOCOMPLETE_HOOK_REFERENCE);\n const [state, dispatch] = useReducer(autocompleteReducer, initialState);\n const {\n selectedIndex,\n filteredOptions,\n filterValue,\n autocompleter\n } = state;\n const backspacingRef = useRef(false);\n function insertCompletion(replacement) {\n if (autocompleter === null) {\n return;\n }\n const end = record.start;\n const start = end - autocompleter.triggerPrefix.length - filterValue.length;\n const toInsert = create({\n html: renderToString(replacement)\n });\n onChange(insert(record, toInsert, start, end));\n }\n function select(option) {\n const {\n getOptionCompletion\n } = autocompleter || {};\n if (option.isDisabled) {\n return;\n }\n if (getOptionCompletion) {\n const completionObject = getCompletionObject(getOptionCompletion(option.value, filterValue));\n if ('replace' === completionObject.action) {\n onReplace([completionObject.value]);\n // When replacing, the component will unmount, so don't reset\n // state (below) on an unmounted component.\n return;\n } else if ('insert-at-caret' === completionObject.action) {\n insertCompletion(completionObject.value);\n }\n }\n\n // Reset autocomplete state after insertion rather than before\n // so insertion events don't cause the completion menu to redisplay.\n dispatch({\n type: 'RESET'\n });\n\n // Make sure that the content remains focused after making a selection\n // and that the text cursor position is not lost.\n contentRef.current?.focus();\n }\n function onChangeOptions(options) {\n dispatch({\n type: 'OPTIONS',\n options\n });\n }\n function handleKeyDown(event) {\n backspacingRef.current = event.key === 'Backspace';\n if (!autocompleter) {\n return;\n }\n if (filteredOptions.length === 0) {\n return;\n }\n if (event.defaultPrevented) {\n return;\n }\n switch (event.key) {\n case 'ArrowUp':\n case 'ArrowDown':\n {\n const offset = event.key === 'ArrowUp' ? -1 : 1;\n const newIndex = (selectedIndex + offset + filteredOptions.length) % filteredOptions.length;\n dispatch({\n type: 'SELECT',\n index: newIndex\n });\n // See the related PR as to why this is necessary: https://github.com/WordPress/gutenberg/pull/54902.\n if (isAppleOS()) {\n speak(getNodeText(filteredOptions[newIndex].label), 'assertive');\n }\n break;\n }\n case 'Escape':\n dispatch({\n type: 'RESET'\n });\n event.preventDefault();\n break;\n case 'Enter':\n select(filteredOptions[selectedIndex]);\n break;\n case 'ArrowLeft':\n case 'ArrowRight':\n dispatch({\n type: 'RESET'\n });\n return;\n default:\n return;\n }\n\n // Any handled key should prevent original behavior. This relies on\n // the early return in the default case.\n event.preventDefault();\n }\n\n // textContent is a primitive (string), memoizing is not strictly necessary\n // but this is a preemptive performance improvement, since the autocompleter\n // is a potential bottleneck for the editor type metric.\n const textContent = useMemo(() => {\n if (isCollapsed(record)) {\n return getTextContent(slice(record, 0));\n }\n return '';\n }, [record]);\n useEffect(() => {\n function getTextAfterSelection() {\n return textContent ? getTextContent(slice(record, undefined, getTextContent(record).length)) : '';\n }\n const match = getAutocompleteMatch(textContent, completers, filteredOptions.length, backspacingRef.current, getTextAfterSelection);\n if (!match) {\n if (autocompleter) {\n dispatch({\n type: 'RESET'\n });\n }\n return;\n }\n const {\n completer,\n filterValue: query\n } = match;\n dispatch({\n type: 'MATCH',\n completer,\n query\n });\n // We want to avoid introducing unexpected side effects.\n // See https://github.com/WordPress/gutenberg/pull/41820\n }, [textContent]);\n const {\n key: selectedKey = ''\n } = filteredOptions[selectedIndex] || {};\n const {\n className\n } = autocompleter || {};\n const isExpanded = !!autocompleter && filteredOptions.length > 0;\n const listBoxId = isExpanded ? `components-autocomplete-listbox-${instanceId}` : undefined;\n const activeId = isExpanded ? `components-autocomplete-item-${instanceId}-${selectedKey}` : null;\n const hasSelection = record.start !== undefined;\n const showPopover = !!textContent && hasSelection && !!autocompleter;\n return {\n listBoxId,\n activeId,\n onKeyDown: withIgnoreIMEEvents(handleKeyDown),\n popover: showPopover && /*#__PURE__*/_jsx(AutocompleterUI, {\n autocompleter: autocompleter,\n className: className,\n filterValue: filterValue,\n instanceId: instanceId,\n listBoxId: listBoxId,\n selectedIndex: selectedIndex,\n onChangeOptions: onChangeOptions,\n onSelect: select,\n contentRef: contentRef,\n reset: () => dispatch({\n type: 'RESET'\n })\n }, autocompleter.name + autocompleter.triggerPrefix)\n };\n}\n\n/**\n * Checks whether two records represent the same user-visible state\n * (same text content and cursor position).\n */\nfunction recordValuesMatch(a, b) {\n return a.text === b.text && a.start === b.start && a.end === b.end;\n}\n\n/**\n * Tracks the last record whose value differed from the current one.\n * Used to determine whether the user has actually typed something\n */\nexport function useLastDifferentValue(value) {\n const history = useRef([]);\n const lastEntry = history.current[history.current.length - 1];\n\n // Only add to history if the value is meaningfully different from\n // the most recent entry (analogous to Set.add being a no-op for\n // duplicate references in the original implementation).\n if (!lastEntry || !recordValuesMatch(value, lastEntry)) {\n history.current.push(value);\n }\n\n // Keep the history size to 2.\n if (history.current.length > 2) {\n history.current.shift();\n }\n return history.current[0];\n}\nexport function useAutocompleteProps(options) {\n const ref = useRef(null);\n const onKeyDownRef = useRef(undefined);\n const {\n record\n } = options;\n const previousRecord = useLastDifferentValue(record);\n const {\n popover,\n listBoxId,\n activeId,\n onKeyDown\n } = useAutocomplete({\n ...options,\n contentRef: ref\n });\n onKeyDownRef.current = onKeyDown;\n const mergedRefs = useMergeRefs([ref, useRefEffect(element => {\n function _onKeyDown(event) {\n onKeyDownRef.current?.(event);\n }\n element.addEventListener('keydown', _onKeyDown);\n return () => {\n element.removeEventListener('keydown', _onKeyDown);\n };\n }, [])]);\n\n // We only want to show the popover if the user has typed something.\n const didUserInput = record.text !== previousRecord?.text;\n if (!didUserInput) {\n return {\n ref: mergedRefs\n };\n }\n return {\n ref: mergedRefs,\n children: popover,\n 'aria-autocomplete': listBoxId ? 'list' : undefined,\n 'aria-owns': listBoxId,\n 'aria-activedescendant': activeId\n };\n}\nexport default function Autocomplete({\n children,\n isSelected,\n ...options\n}) {\n const {\n popover,\n ...props\n } = useAutocomplete(options);\n return /*#__PURE__*/_jsxs(_Fragment, {\n children: [children(props), isSelected && popover]\n });\n}"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { renderToString, useEffect, useMemo, useReducer, useRef } from '@wordpress/element';\nimport { useInstanceId, useMergeRefs, useRefEffect } from '@wordpress/compose';\nimport { create, slice, insert, isCollapsed, getTextContent } from '@wordpress/rich-text';\nimport { speak } from '@wordpress/a11y';\nimport { isAppleOS } from '@wordpress/keycodes';\n\n/**\n * Internal dependencies\n */\nimport { AutocompleterUI } from './autocompleter-ui';\nimport { getAutocompleteMatch } from './get-autocomplete-match';\nimport { withIgnoreIMEEvents } from '../utils/with-ignore-ime-events';\nimport getNodeText from '../utils/get-node-text';\nimport { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from \"react/jsx-runtime\";\nconst EMPTY_FILTERED_OPTIONS = [];\n\n// Used for generating the instance ID\nconst AUTOCOMPLETE_HOOK_REFERENCE = {};\nfunction getCompletionObject(completion) {\n if (completion !== null && typeof completion === 'object' && 'action' in completion && completion.action !== undefined && 'value' in completion && completion.value !== undefined) {\n return completion;\n }\n return {\n action: 'insert-at-caret',\n value: completion\n };\n}\nconst initialState = {\n selectedIndex: 0,\n filteredOptions: EMPTY_FILTERED_OPTIONS,\n filterValue: '',\n autocompleter: null\n};\nfunction autocompleteReducer(state, action) {\n switch (action.type) {\n case 'RESET':\n return initialState;\n case 'SELECT':\n return {\n ...state,\n selectedIndex: action.index\n };\n case 'OPTIONS':\n return {\n ...state,\n filteredOptions: action.options,\n selectedIndex: action.options.length === state.filteredOptions.length ? state.selectedIndex : 0\n };\n case 'MATCH':\n return {\n ...state,\n autocompleter: action.completer,\n filterValue: action.query\n };\n }\n}\nexport function useAutocomplete({\n record,\n onChange,\n onReplace,\n completers,\n contentRef\n}) {\n const instanceId = useInstanceId(AUTOCOMPLETE_HOOK_REFERENCE);\n const [state, dispatch] = useReducer(autocompleteReducer, initialState);\n const {\n selectedIndex,\n filteredOptions,\n filterValue,\n autocompleter\n } = state;\n const backspacingRef = useRef(false);\n const prevRecordTextRef = useRef('');\n const lastCompletionRef = useRef(null);\n function insertCompletion(replacement) {\n if (autocompleter === null) {\n return '';\n }\n const end = record.start;\n const start = end - autocompleter.triggerPrefix.length - filterValue.length;\n const toInsert = create({\n html: renderToString(replacement)\n });\n onChange(insert(record, toInsert, start, end));\n return getTextContent(toInsert);\n }\n function select(option) {\n if (option.isDisabled || !autocompleter) {\n return;\n }\n const {\n getOptionCompletion\n } = autocompleter;\n if (!getOptionCompletion) {\n dispatch({\n type: 'RESET'\n });\n contentRef.current?.focus();\n return;\n }\n const completionObject = getCompletionObject(getOptionCompletion(option.value, filterValue));\n if ('replace' === completionObject.action) {\n onReplace([completionObject.value]);\n // When replacing, the component will unmount, so don't reset\n // state (below) on an unmounted component.\n return;\n }\n if ('insert-at-caret' === completionObject.action) {\n const completionText = insertCompletion(completionObject.value);\n // When the completion value starts with the trigger prefix\n // (e.g. @username), the trigger stays in the text and would\n // re-activate the autocompleter. Store the completed text so\n // the effect can suppress the stale re-match.\n if (completionText.startsWith(autocompleter.triggerPrefix)) {\n const afterPrefix = completionText.slice(autocompleter.triggerPrefix.length);\n if (afterPrefix) {\n lastCompletionRef.current = {\n name: autocompleter.name,\n value: afterPrefix\n };\n }\n }\n }\n\n // Reset autocomplete state after insertion rather than before\n // so insertion events don't cause the completion menu to redisplay.\n dispatch({\n type: 'RESET'\n });\n\n // Make sure that the content remains focused after making a selection\n // and that the text cursor position is not lost.\n contentRef.current?.focus();\n }\n function onChangeOptions(options) {\n dispatch({\n type: 'OPTIONS',\n options\n });\n }\n function handleKeyDown(event) {\n backspacingRef.current = event.key === 'Backspace';\n if (!autocompleter) {\n return;\n }\n if (filteredOptions.length === 0) {\n return;\n }\n if (event.defaultPrevented) {\n return;\n }\n switch (event.key) {\n case 'ArrowUp':\n case 'ArrowDown':\n {\n const offset = event.key === 'ArrowUp' ? -1 : 1;\n const newIndex = (selectedIndex + offset + filteredOptions.length) % filteredOptions.length;\n dispatch({\n type: 'SELECT',\n index: newIndex\n });\n // See the related PR as to why this is necessary: https://github.com/WordPress/gutenberg/pull/54902.\n if (isAppleOS()) {\n speak(getNodeText(filteredOptions[newIndex].label), 'assertive');\n }\n break;\n }\n case 'Escape':\n dispatch({\n type: 'RESET'\n });\n event.preventDefault();\n break;\n case 'Enter':\n select(filteredOptions[selectedIndex]);\n break;\n case 'ArrowLeft':\n case 'ArrowRight':\n dispatch({\n type: 'RESET'\n });\n return;\n default:\n return;\n }\n\n // Any handled key should prevent original behavior. This relies on\n // the early return in the default case.\n event.preventDefault();\n }\n\n // textContent is a primitive (string), memoizing is not strictly necessary\n // but this is a preemptive performance improvement, since the autocompleter\n // is a potential bottleneck for the editor type metric.\n const textContent = useMemo(() => {\n if (isCollapsed(record)) {\n return getTextContent(slice(record, 0));\n }\n return '';\n }, [record]);\n useEffect(() => {\n const isTextChange = record.text !== prevRecordTextRef.current;\n prevRecordTextRef.current = record.text;\n function getTextAfterSelection() {\n return textContent ? getTextContent(slice(record, undefined, getTextContent(record).length)) : '';\n }\n const match = getAutocompleteMatch(textContent, completers, {\n matchCount: filteredOptions.length,\n isBackspacing: backspacingRef.current,\n getTextAfterSelection,\n lastCompletion: lastCompletionRef.current\n });\n if (!match) {\n if (autocompleter) {\n dispatch({\n type: 'RESET'\n });\n }\n return;\n }\n const {\n completer,\n filterValue: query\n } = match;\n\n // Don't re-activate a dismissed autocompleter on cursor-only\n // movement. `textContent` (text before cursor) changes with the\n // caret, so the effect re-runs, but `record.text` does not.\n // Complements the render-time `didUserInput` gate in\n // `useAutocompleteProps` for callers using this hook directly.\n if (!autocompleter && !isTextChange) {\n return;\n }\n\n // Clear stale completion ref when the user types a new trigger\n // for the same completer (the previous completion is no longer\n // relevant). Must be after the cursor-only check so that mere\n // cursor movement doesn't discard the suppression state.\n if (lastCompletionRef.current && lastCompletionRef.current.name === completer.name) {\n lastCompletionRef.current = null;\n }\n dispatch({\n type: 'MATCH',\n completer,\n query\n });\n // We want to avoid introducing unexpected side effects.\n // See https://github.com/WordPress/gutenberg/pull/41820\n }, [textContent]);\n const {\n key: selectedKey = ''\n } = filteredOptions[selectedIndex] || {};\n const {\n className\n } = autocompleter || {};\n const isExpanded = !!autocompleter && filteredOptions.length > 0;\n const listBoxId = isExpanded ? `components-autocomplete-listbox-${instanceId}` : undefined;\n const activeId = isExpanded ? `components-autocomplete-item-${instanceId}-${selectedKey}` : null;\n const hasSelection = record.start !== undefined;\n const showPopover = !!textContent && hasSelection && !!autocompleter;\n return {\n listBoxId,\n activeId,\n onKeyDown: withIgnoreIMEEvents(handleKeyDown),\n popover: showPopover && /*#__PURE__*/_jsx(AutocompleterUI, {\n autocompleter: autocompleter,\n className: className,\n filterValue: filterValue,\n instanceId: instanceId,\n listBoxId: listBoxId,\n selectedIndex: selectedIndex,\n onChangeOptions: onChangeOptions,\n onSelect: select,\n contentRef: contentRef,\n reset: () => dispatch({\n type: 'RESET'\n })\n }, autocompleter.name + autocompleter.triggerPrefix)\n };\n}\n\n/**\n * Checks whether two records represent the same user-visible state\n * (same text content and cursor position).\n */\nfunction recordValuesMatch(a, b) {\n return a.text === b.text && a.start === b.start && a.end === b.end;\n}\n\n/**\n * Tracks the last record whose value differed from the current one.\n * Used to determine whether the user has actually typed something\n */\nexport function useLastDifferentValue(value) {\n const history = useRef([]);\n const lastEntry = history.current[history.current.length - 1];\n\n // Only add to history if the value is meaningfully different from\n // the most recent entry (analogous to Set.add being a no-op for\n // duplicate references in the original implementation).\n if (!lastEntry || !recordValuesMatch(value, lastEntry)) {\n history.current.push(value);\n }\n\n // Keep the history size to 2.\n if (history.current.length > 2) {\n history.current.shift();\n }\n return history.current[0];\n}\nexport function useAutocompleteProps(options) {\n const ref = useRef(null);\n const onKeyDownRef = useRef(undefined);\n const {\n record\n } = options;\n const previousRecord = useLastDifferentValue(record);\n const {\n popover,\n listBoxId,\n activeId,\n onKeyDown\n } = useAutocomplete({\n ...options,\n contentRef: ref\n });\n onKeyDownRef.current = onKeyDown;\n const mergedRefs = useMergeRefs([ref, useRefEffect(element => {\n function _onKeyDown(event) {\n onKeyDownRef.current?.(event);\n }\n element.addEventListener('keydown', _onKeyDown);\n return () => {\n element.removeEventListener('keydown', _onKeyDown);\n };\n }, [])]);\n\n // We only want to show the popover if the user has typed something.\n const didUserInput = record.text !== previousRecord?.text;\n if (!didUserInput) {\n return {\n ref: mergedRefs\n };\n }\n return {\n ref: mergedRefs,\n children: popover,\n 'aria-autocomplete': listBoxId ? 'list' : undefined,\n 'aria-owns': listBoxId,\n 'aria-activedescendant': activeId\n };\n}\nexport default function Autocomplete({\n children,\n isSelected,\n ...options\n}) {\n const {\n popover,\n ...props\n } = useAutocomplete(options);\n return /*#__PURE__*/_jsxs(_Fragment, {\n children: [children(props), isSelected && popover]\n });\n}"],
5
+ "mappings": ";AAGA,SAAS,gBAAgB,WAAW,SAAS,YAAY,cAAc;AACvE,SAAS,eAAe,cAAc,oBAAoB;AAC1D,SAAS,QAAQ,OAAO,QAAQ,aAAa,sBAAsB;AACnE,SAAS,aAAa;AACtB,SAAS,iBAAiB;AAK1B,SAAS,uBAAuB;AAChC,SAAS,4BAA4B;AACrC,SAAS,2BAA2B;AACpC,OAAO,iBAAiB;AACxB,SAAS,OAAO,MAAM,YAAY,WAAW,QAAQ,aAAa;AAClE,IAAM,yBAAyB,CAAC;AAGhC,IAAM,8BAA8B,CAAC;AACrC,SAAS,oBAAoB,YAAY;AACvC,MAAI,eAAe,QAAQ,OAAO,eAAe,YAAY,YAAY,cAAc,WAAW,WAAW,UAAa,WAAW,cAAc,WAAW,UAAU,QAAW;AACjL,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,OAAO;AAAA,EACT;AACF;AACA,IAAM,eAAe;AAAA,EACnB,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,eAAe;AACjB;AACA,SAAS,oBAAoB,OAAO,QAAQ;AAC1C,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,eAAe,OAAO;AAAA,MACxB;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,iBAAiB,OAAO;AAAA,QACxB,eAAe,OAAO,QAAQ,WAAW,MAAM,gBAAgB,SAAS,MAAM,gBAAgB;AAAA,MAChG;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,eAAe,OAAO;AAAA,QACtB,aAAa,OAAO;AAAA,MACtB;AAAA,EACJ;AACF;AACO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAG;AACD,QAAM,aAAa,cAAc,2BAA2B;AAC5D,QAAM,CAAC,OAAO,QAAQ,IAAI,WAAW,qBAAqB,YAAY;AACtE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,QAAM,iBAAiB,OAAO,KAAK;AACnC,QAAM,oBAAoB,OAAO,EAAE;AACnC,QAAM,oBAAoB,OAAO,IAAI;AACrC,WAAS,iBAAiB,aAAa;AACrC,QAAI,kBAAkB,MAAM;AAC1B,aAAO;AAAA,IACT;AACA,UAAM,MAAM,OAAO;AACnB,UAAM,QAAQ,MAAM,cAAc,cAAc,SAAS,YAAY;AACrE,UAAM,WAAW,OAAO;AAAA,MACtB,MAAM,eAAe,WAAW;AAAA,IAClC,CAAC;AACD,aAAS,OAAO,QAAQ,UAAU,OAAO,GAAG,CAAC;AAC7C,WAAO,eAAe,QAAQ;AAAA,EAChC;AACA,WAAS,OAAO,QAAQ;AACtB,QAAI,OAAO,cAAc,CAAC,eAAe;AACvC;AAAA,IACF;AACA,UAAM;AAAA,MACJ;AAAA,IACF,IAAI;AACJ,QAAI,CAAC,qBAAqB;AACxB,eAAS;AAAA,QACP,MAAM;AAAA,MACR,CAAC;AACD,iBAAW,SAAS,MAAM;AAC1B;AAAA,IACF;AACA,UAAM,mBAAmB,oBAAoB,oBAAoB,OAAO,OAAO,WAAW,CAAC;AAC3F,QAAI,cAAc,iBAAiB,QAAQ;AACzC,gBAAU,CAAC,iBAAiB,KAAK,CAAC;AAGlC;AAAA,IACF;AACA,QAAI,sBAAsB,iBAAiB,QAAQ;AACjD,YAAM,iBAAiB,iBAAiB,iBAAiB,KAAK;AAK9D,UAAI,eAAe,WAAW,cAAc,aAAa,GAAG;AAC1D,cAAM,cAAc,eAAe,MAAM,cAAc,cAAc,MAAM;AAC3E,YAAI,aAAa;AACf,4BAAkB,UAAU;AAAA,YAC1B,MAAM,cAAc;AAAA,YACpB,OAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAIA,aAAS;AAAA,MACP,MAAM;AAAA,IACR,CAAC;AAID,eAAW,SAAS,MAAM;AAAA,EAC5B;AACA,WAAS,gBAAgB,SAAS;AAChC,aAAS;AAAA,MACP,MAAM;AAAA,MACN;AAAA,IACF,CAAC;AAAA,EACH;AACA,WAAS,cAAc,OAAO;AAC5B,mBAAe,UAAU,MAAM,QAAQ;AACvC,QAAI,CAAC,eAAe;AAClB;AAAA,IACF;AACA,QAAI,gBAAgB,WAAW,GAAG;AAChC;AAAA,IACF;AACA,QAAI,MAAM,kBAAkB;AAC1B;AAAA,IACF;AACA,YAAQ,MAAM,KAAK;AAAA,MACjB,KAAK;AAAA,MACL,KAAK,aACH;AACE,cAAM,SAAS,MAAM,QAAQ,YAAY,KAAK;AAC9C,cAAM,YAAY,gBAAgB,SAAS,gBAAgB,UAAU,gBAAgB;AACrF,iBAAS;AAAA,UACP,MAAM;AAAA,UACN,OAAO;AAAA,QACT,CAAC;AAED,YAAI,UAAU,GAAG;AACf,gBAAM,YAAY,gBAAgB,QAAQ,EAAE,KAAK,GAAG,WAAW;AAAA,QACjE;AACA;AAAA,MACF;AAAA,MACF,KAAK;AACH,iBAAS;AAAA,UACP,MAAM;AAAA,QACR,CAAC;AACD,cAAM,eAAe;AACrB;AAAA,MACF,KAAK;AACH,eAAO,gBAAgB,aAAa,CAAC;AACrC;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AACH,iBAAS;AAAA,UACP,MAAM;AAAA,QACR,CAAC;AACD;AAAA,MACF;AACE;AAAA,IACJ;AAIA,UAAM,eAAe;AAAA,EACvB;AAKA,QAAM,cAAc,QAAQ,MAAM;AAChC,QAAI,YAAY,MAAM,GAAG;AACvB,aAAO,eAAe,MAAM,QAAQ,CAAC,CAAC;AAAA,IACxC;AACA,WAAO;AAAA,EACT,GAAG,CAAC,MAAM,CAAC;AACX,YAAU,MAAM;AACd,UAAM,eAAe,OAAO,SAAS,kBAAkB;AACvD,sBAAkB,UAAU,OAAO;AACnC,aAAS,wBAAwB;AAC/B,aAAO,cAAc,eAAe,MAAM,QAAQ,QAAW,eAAe,MAAM,EAAE,MAAM,CAAC,IAAI;AAAA,IACjG;AACA,UAAM,QAAQ,qBAAqB,aAAa,YAAY;AAAA,MAC1D,YAAY,gBAAgB;AAAA,MAC5B,eAAe,eAAe;AAAA,MAC9B;AAAA,MACA,gBAAgB,kBAAkB;AAAA,IACpC,CAAC;AACD,QAAI,CAAC,OAAO;AACV,UAAI,eAAe;AACjB,iBAAS;AAAA,UACP,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AACA;AAAA,IACF;AACA,UAAM;AAAA,MACJ;AAAA,MACA,aAAa;AAAA,IACf,IAAI;AAOJ,QAAI,CAAC,iBAAiB,CAAC,cAAc;AACnC;AAAA,IACF;AAMA,QAAI,kBAAkB,WAAW,kBAAkB,QAAQ,SAAS,UAAU,MAAM;AAClF,wBAAkB,UAAU;AAAA,IAC9B;AACA,aAAS;AAAA,MACP,MAAM;AAAA,MACN;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EAGH,GAAG,CAAC,WAAW,CAAC;AAChB,QAAM;AAAA,IACJ,KAAK,cAAc;AAAA,EACrB,IAAI,gBAAgB,aAAa,KAAK,CAAC;AACvC,QAAM;AAAA,IACJ;AAAA,EACF,IAAI,iBAAiB,CAAC;AACtB,QAAM,aAAa,CAAC,CAAC,iBAAiB,gBAAgB,SAAS;AAC/D,QAAM,YAAY,aAAa,mCAAmC,UAAU,KAAK;AACjF,QAAM,WAAW,aAAa,gCAAgC,UAAU,IAAI,WAAW,KAAK;AAC5F,QAAM,eAAe,OAAO,UAAU;AACtC,QAAM,cAAc,CAAC,CAAC,eAAe,gBAAgB,CAAC,CAAC;AACvD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,WAAW,oBAAoB,aAAa;AAAA,IAC5C,SAAS,eAA4B,qBAAK,iBAAiB;AAAA,MACzD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU;AAAA,MACV;AAAA,MACA,OAAO,MAAM,SAAS;AAAA,QACpB,MAAM;AAAA,MACR,CAAC;AAAA,IACH,GAAG,cAAc,OAAO,cAAc,aAAa;AAAA,EACrD;AACF;AAMA,SAAS,kBAAkB,GAAG,GAAG;AAC/B,SAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE;AACjE;AAMO,SAAS,sBAAsB,OAAO;AAC3C,QAAM,UAAU,OAAO,CAAC,CAAC;AACzB,QAAM,YAAY,QAAQ,QAAQ,QAAQ,QAAQ,SAAS,CAAC;AAK5D,MAAI,CAAC,aAAa,CAAC,kBAAkB,OAAO,SAAS,GAAG;AACtD,YAAQ,QAAQ,KAAK,KAAK;AAAA,EAC5B;AAGA,MAAI,QAAQ,QAAQ,SAAS,GAAG;AAC9B,YAAQ,QAAQ,MAAM;AAAA,EACxB;AACA,SAAO,QAAQ,QAAQ,CAAC;AAC1B;AACO,SAAS,qBAAqB,SAAS;AAC5C,QAAM,MAAM,OAAO,IAAI;AACvB,QAAM,eAAe,OAAO,MAAS;AACrC,QAAM;AAAA,IACJ;AAAA,EACF,IAAI;AACJ,QAAM,iBAAiB,sBAAsB,MAAM;AACnD,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,gBAAgB;AAAA,IAClB,GAAG;AAAA,IACH,YAAY;AAAA,EACd,CAAC;AACD,eAAa,UAAU;AACvB,QAAM,aAAa,aAAa,CAAC,KAAK,aAAa,aAAW;AAC5D,aAAS,WAAW,OAAO;AACzB,mBAAa,UAAU,KAAK;AAAA,IAC9B;AACA,YAAQ,iBAAiB,WAAW,UAAU;AAC9C,WAAO,MAAM;AACX,cAAQ,oBAAoB,WAAW,UAAU;AAAA,IACnD;AAAA,EACF,GAAG,CAAC,CAAC,CAAC,CAAC;AAGP,QAAM,eAAe,OAAO,SAAS,gBAAgB;AACrD,MAAI,CAAC,cAAc;AACjB,WAAO;AAAA,MACL,KAAK;AAAA,IACP;AAAA,EACF;AACA,SAAO;AAAA,IACL,KAAK;AAAA,IACL,UAAU;AAAA,IACV,qBAAqB,YAAY,SAAS;AAAA,IAC1C,aAAa;AAAA,IACb,yBAAyB;AAAA,EAC3B;AACF;AACe,SAAR,aAA8B;AAAA,EACnC;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAG;AACD,QAAM;AAAA,IACJ;AAAA,IACA,GAAG;AAAA,EACL,IAAI,gBAAgB,OAAO;AAC3B,SAAoB,sBAAM,WAAW;AAAA,IACnC,UAAU,CAAC,SAAS,KAAK,GAAG,cAAc,OAAO;AAAA,EACnD,CAAC;AACH;",
6
6
  "names": []
7
7
  }
@@ -11,7 +11,7 @@ function UnforwardedExternalLink(props, ref) {
11
11
  rel = "",
12
12
  ...additionalProps
13
13
  } = props;
14
- const optimizedRel = [...new Set([...rel.split(" "), "external", "noreferrer", "noopener"].filter(Boolean))].join(" ");
14
+ const optimizedRel = [...new Set([...rel.split(" "), "external", "noopener"].filter(Boolean))].join(" ");
15
15
  const classes = clsx("components-external-link", className);
16
16
  const isInternalAnchor = !!href?.startsWith("#");
17
17
  const onClickHandler = (event) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/external-link/index.tsx"],
4
- "sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n/**\n * WordPress dependencies\n */\nimport { __, isRTL } from '@wordpress/i18n';\nimport { forwardRef } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport { jsx as _jsx, jsxs as _jsxs } from \"react/jsx-runtime\";\nfunction UnforwardedExternalLink(props, ref) {\n const {\n href,\n children,\n className,\n rel = '',\n ...additionalProps\n } = props;\n const optimizedRel = [...new Set([...rel.split(' '), 'external', 'noreferrer', 'noopener'].filter(Boolean))].join(' ');\n const classes = clsx('components-external-link', className);\n /* Anchor links are perceived as external links.\n This constant helps check for on page anchor links,\n to prevent them from being opened in the editor. */\n const isInternalAnchor = !!href?.startsWith('#');\n const onClickHandler = event => {\n if (isInternalAnchor) {\n event.preventDefault();\n }\n if (props.onClick) {\n props.onClick(event);\n }\n };\n return /*#__PURE__*/ /* eslint-disable react/jsx-no-target-blank */_jsxs(\"a\", {\n ...additionalProps,\n className: classes,\n href: href,\n onClick: onClickHandler,\n target: \"_blank\",\n rel: optimizedRel,\n ref: ref,\n children: [/*#__PURE__*/_jsx(\"span\", {\n className: \"components-external-link__contents\",\n children: children\n }), /*#__PURE__*/_jsx(\"span\", {\n className: clsx('components-external-link__icon',\n // This class prevents the arrow from being replaced by a Twemoji image.\n 'wp-exclude-emoji'),\n \"aria-label\": /* translators: accessibility text */\n __('(opens in a new tab)'),\n children: isRTL() ? '\\u2196' : '\\u2197'\n })]\n })\n /* eslint-enable react/jsx-no-target-blank */;\n}\n\n/**\n * Link to an external resource.\n *\n * ```jsx\n * import { ExternalLink } from '@wordpress/components';\n *\n * const MyExternalLink = () => (\n * <ExternalLink href=\"https://wordpress.org\">WordPress.org</ExternalLink>\n * );\n * ```\n */\nexport const ExternalLink = forwardRef(UnforwardedExternalLink);\nExternalLink.displayName = 'ExternalLink';\nexport default ExternalLink;"],
5
- "mappings": ";AAGA,OAAO,UAAU;AAIjB,SAAS,IAAI,aAAa;AAC1B,SAAS,kBAAkB;AAK3B,SAAS,OAAO,MAAM,QAAQ,aAAa;AAC3C,SAAS,wBAAwB,OAAO,KAAK;AAC3C,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL,IAAI;AACJ,QAAM,eAAe,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,MAAM,GAAG,GAAG,YAAY,cAAc,UAAU,EAAE,OAAO,OAAO,CAAC,CAAC,EAAE,KAAK,GAAG;AACrH,QAAM,UAAU,KAAK,4BAA4B,SAAS;AAI1D,QAAM,mBAAmB,CAAC,CAAC,MAAM,WAAW,GAAG;AAC/C,QAAM,iBAAiB,WAAS;AAC9B,QAAI,kBAAkB;AACpB,YAAM,eAAe;AAAA,IACvB;AACA,QAAI,MAAM,SAAS;AACjB,YAAM,QAAQ,KAAK;AAAA,IACrB;AAAA,EACF;AACA;AAAA;AAAA,IAAmE,sBAAM,KAAK;AAAA,MAC5E,GAAG;AAAA,MACH,WAAW;AAAA,MACX;AAAA,MACA,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,KAAK;AAAA,MACL;AAAA,MACA,UAAU,CAAc,qBAAK,QAAQ;AAAA,QACnC,WAAW;AAAA,QACX;AAAA,MACF,CAAC,GAAgB,qBAAK,QAAQ;AAAA,QAC5B,WAAW;AAAA,UAAK;AAAA;AAAA,UAEhB;AAAA,QAAkB;AAAA,QAClB;AAAA;AAAA,UACA,GAAG,sBAAsB;AAAA;AAAA,QACzB,UAAU,MAAM,IAAI,WAAW;AAAA,MACjC,CAAC,CAAC;AAAA,IACJ,CAAC;AAAA;AAEH;AAaO,IAAM,eAAe,WAAW,uBAAuB;AAC9D,aAAa,cAAc;AAC3B,IAAO,wBAAQ;",
4
+ "sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n/**\n * WordPress dependencies\n */\nimport { __, isRTL } from '@wordpress/i18n';\nimport { forwardRef } from '@wordpress/element';\n\n/**\n * Internal dependencies\n */\nimport { jsx as _jsx, jsxs as _jsxs } from \"react/jsx-runtime\";\nfunction UnforwardedExternalLink(props, ref) {\n const {\n href,\n children,\n className,\n rel = '',\n ...additionalProps\n } = props;\n const optimizedRel = [...new Set([...rel.split(' '), 'external', 'noopener'].filter(Boolean))].join(' ');\n const classes = clsx('components-external-link', className);\n /* Anchor links are perceived as external links.\n This constant helps check for on page anchor links,\n to prevent them from being opened in the editor. */\n const isInternalAnchor = !!href?.startsWith('#');\n const onClickHandler = event => {\n if (isInternalAnchor) {\n event.preventDefault();\n }\n if (props.onClick) {\n props.onClick(event);\n }\n };\n return /*#__PURE__*/ /* eslint-disable react/jsx-no-target-blank */_jsxs(\"a\", {\n ...additionalProps,\n className: classes,\n href: href,\n onClick: onClickHandler,\n target: \"_blank\",\n rel: optimizedRel,\n ref: ref,\n children: [/*#__PURE__*/_jsx(\"span\", {\n className: \"components-external-link__contents\",\n children: children\n }), /*#__PURE__*/_jsx(\"span\", {\n className: clsx('components-external-link__icon',\n // This class prevents the arrow from being replaced by a Twemoji image.\n 'wp-exclude-emoji'),\n \"aria-label\": /* translators: accessibility text */\n __('(opens in a new tab)'),\n children: isRTL() ? '\\u2196' : '\\u2197'\n })]\n })\n /* eslint-enable react/jsx-no-target-blank */;\n}\n\n/**\n * Link to an external resource.\n *\n * ```jsx\n * import { ExternalLink } from '@wordpress/components';\n *\n * const MyExternalLink = () => (\n * <ExternalLink href=\"https://wordpress.org\">WordPress.org</ExternalLink>\n * );\n * ```\n */\nexport const ExternalLink = forwardRef(UnforwardedExternalLink);\nExternalLink.displayName = 'ExternalLink';\nexport default ExternalLink;"],
5
+ "mappings": ";AAGA,OAAO,UAAU;AAIjB,SAAS,IAAI,aAAa;AAC1B,SAAS,kBAAkB;AAK3B,SAAS,OAAO,MAAM,QAAQ,aAAa;AAC3C,SAAS,wBAAwB,OAAO,KAAK;AAC3C,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,GAAG;AAAA,EACL,IAAI;AACJ,QAAM,eAAe,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,MAAM,GAAG,GAAG,YAAY,UAAU,EAAE,OAAO,OAAO,CAAC,CAAC,EAAE,KAAK,GAAG;AACvG,QAAM,UAAU,KAAK,4BAA4B,SAAS;AAI1D,QAAM,mBAAmB,CAAC,CAAC,MAAM,WAAW,GAAG;AAC/C,QAAM,iBAAiB,WAAS;AAC9B,QAAI,kBAAkB;AACpB,YAAM,eAAe;AAAA,IACvB;AACA,QAAI,MAAM,SAAS;AACjB,YAAM,QAAQ,KAAK;AAAA,IACrB;AAAA,EACF;AACA;AAAA;AAAA,IAAmE,sBAAM,KAAK;AAAA,MAC5E,GAAG;AAAA,MACH,WAAW;AAAA,MACX;AAAA,MACA,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,KAAK;AAAA,MACL;AAAA,MACA,UAAU,CAAc,qBAAK,QAAQ;AAAA,QACnC,WAAW;AAAA,QACX;AAAA,MACF,CAAC,GAAgB,qBAAK,QAAQ;AAAA,QAC5B,WAAW;AAAA,UAAK;AAAA;AAAA,UAEhB;AAAA,QAAkB;AAAA,QAClB;AAAA;AAAA,UACA,GAAG,sBAAsB;AAAA;AAAA,QACzB,UAAU,MAAM,IAAI,WAAW;AAAA,MACjC,CAAC,CAAC;AAAA,IACJ,CAAC;AAAA;AAEH;AAaO,IAAM,eAAe,WAAW,uBAAuB;AAC9D,aAAa,cAAc;AAC3B,IAAO,wBAAQ;",
6
6
  "names": []
7
7
  }