@wordpress/components 32.5.0 → 32.6.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 (282) hide show
  1. package/AGENTS.md +2 -2
  2. package/CHANGELOG.md +40 -0
  3. package/README.md +18 -4
  4. package/build/alignment-matrix-control/cell.cjs +3 -3
  5. package/build/alignment-matrix-control/cell.cjs.map +2 -2
  6. package/build/alignment-matrix-control/index.cjs +3 -3
  7. package/build/alignment-matrix-control/index.cjs.map +2 -2
  8. package/build/autocomplete/autocompleter-ui.cjs +75 -79
  9. package/build/autocomplete/autocompleter-ui.cjs.map +2 -2
  10. package/build/autocomplete/get-autocomplete-match.cjs +91 -0
  11. package/build/autocomplete/get-autocomplete-match.cjs.map +7 -0
  12. package/build/autocomplete/index.cjs +104 -107
  13. package/build/autocomplete/index.cjs.map +3 -3
  14. package/build/box-control/index.cjs +0 -8
  15. package/build/box-control/index.cjs.map +2 -2
  16. package/build/box-control/utils.cjs +1 -10
  17. package/build/box-control/utils.cjs.map +2 -2
  18. package/build/calendar/utils/use-localization-props.cjs +3 -2
  19. package/build/calendar/utils/use-localization-props.cjs.map +2 -2
  20. package/build/custom-gradient-picker/index.cjs.map +2 -2
  21. package/build/custom-select-control/index.cjs.map +3 -3
  22. package/build/custom-select-control-v2/custom-select.cjs +2 -2
  23. package/build/custom-select-control-v2/custom-select.cjs.map +2 -2
  24. package/build/custom-select-control-v2/index.cjs.map +3 -3
  25. package/build/date-time/{date → date-picker}/index.cjs +6 -6
  26. package/build/date-time/{date → date-picker}/index.cjs.map +2 -2
  27. package/build/date-time/{date → date-picker}/styles.cjs +17 -17
  28. package/build/date-time/{date → date-picker}/styles.cjs.map +2 -2
  29. package/build/date-time/{date → date-picker}/use-lilius/index.cjs +1 -1
  30. package/build/date-time/{date → date-picker}/use-lilius/index.cjs.map +1 -1
  31. package/build/date-time/date-time/index.cjs +6 -6
  32. package/build/date-time/date-time/index.cjs.map +2 -2
  33. package/build/date-time/index.cjs +4 -4
  34. package/build/date-time/index.cjs.map +2 -2
  35. package/build/date-time/{time → time-picker}/index.cjs +6 -6
  36. package/build/date-time/time-picker/index.cjs.map +7 -0
  37. package/build/date-time/{time → time-picker}/styles.cjs +21 -21
  38. package/build/date-time/{time → time-picker}/styles.cjs.map +2 -2
  39. package/build/date-time/{time → time-picker}/time-input/index.cjs +1 -1
  40. package/build/date-time/{time → time-picker}/time-input/index.cjs.map +1 -1
  41. package/build/date-time/{time → time-picker}/timezone.cjs +1 -1
  42. package/build/date-time/{time → time-picker}/timezone.cjs.map +1 -1
  43. package/build/modal/index.cjs.map +2 -2
  44. package/build/palette-edit/index.cjs.map +2 -2
  45. package/build/radio-control/index.cjs +2 -0
  46. package/build/radio-control/index.cjs.map +2 -2
  47. package/build/sandbox/index.cjs +127 -3
  48. package/build/sandbox/index.cjs.map +2 -2
  49. package/build/textarea-control/styles/textarea-control-styles.cjs +3 -3
  50. package/build/textarea-control/styles/textarea-control-styles.cjs.map +2 -2
  51. package/build/validated-form-controls/control-with-error.cjs +12 -8
  52. package/build/validated-form-controls/control-with-error.cjs.map +2 -2
  53. package/build-module/alignment-matrix-control/cell.mjs +3 -3
  54. package/build-module/alignment-matrix-control/cell.mjs.map +2 -2
  55. package/build-module/alignment-matrix-control/index.mjs +3 -3
  56. package/build-module/alignment-matrix-control/index.mjs.map +2 -2
  57. package/build-module/autocomplete/autocompleter-ui.mjs +74 -78
  58. package/build-module/autocomplete/autocompleter-ui.mjs.map +2 -2
  59. package/build-module/autocomplete/get-autocomplete-match.mjs +56 -0
  60. package/build-module/autocomplete/get-autocomplete-match.mjs.map +7 -0
  61. package/build-module/autocomplete/index.mjs +103 -107
  62. package/build-module/autocomplete/index.mjs.map +3 -3
  63. package/build-module/box-control/index.mjs +1 -9
  64. package/build-module/box-control/index.mjs.map +2 -2
  65. package/build-module/box-control/utils.mjs +1 -9
  66. package/build-module/box-control/utils.mjs.map +2 -2
  67. package/build-module/calendar/utils/use-localization-props.mjs +3 -2
  68. package/build-module/calendar/utils/use-localization-props.mjs.map +2 -2
  69. package/build-module/custom-gradient-picker/index.mjs.map +2 -2
  70. package/build-module/custom-select-control/index.mjs +2 -2
  71. package/build-module/custom-select-control/index.mjs.map +2 -2
  72. package/build-module/custom-select-control-v2/custom-select.mjs +2 -2
  73. package/build-module/custom-select-control-v2/custom-select.mjs.map +2 -2
  74. package/build-module/custom-select-control-v2/index.mjs +2 -2
  75. package/build-module/custom-select-control-v2/index.mjs.map +2 -2
  76. package/build-module/date-time/{date → date-picker}/index.mjs +3 -3
  77. package/build-module/date-time/{date → date-picker}/index.mjs.map +2 -2
  78. package/build-module/date-time/{date → date-picker}/styles.mjs +17 -17
  79. package/build-module/date-time/{date → date-picker}/styles.mjs.map +2 -2
  80. package/build-module/date-time/{date → date-picker}/use-lilius/index.mjs +1 -1
  81. package/build-module/date-time/{date → date-picker}/use-lilius/index.mjs.map +1 -1
  82. package/build-module/date-time/date-time/index.mjs +2 -2
  83. package/build-module/date-time/date-time/index.mjs.map +1 -1
  84. package/build-module/date-time/index.mjs +2 -2
  85. package/build-module/date-time/index.mjs.map +1 -1
  86. package/build-module/date-time/{time → time-picker}/index.mjs +3 -3
  87. package/build-module/date-time/time-picker/index.mjs.map +7 -0
  88. package/build-module/date-time/{time → time-picker}/styles.mjs +21 -21
  89. package/build-module/date-time/{time → time-picker}/styles.mjs.map +2 -2
  90. package/build-module/date-time/{time → time-picker}/time-input/index.mjs +1 -1
  91. package/build-module/date-time/{time → time-picker}/time-input/index.mjs.map +1 -1
  92. package/build-module/date-time/{time → time-picker}/timezone.mjs +1 -1
  93. package/build-module/date-time/{time → time-picker}/timezone.mjs.map +1 -1
  94. package/build-module/modal/index.mjs.map +2 -2
  95. package/build-module/palette-edit/index.mjs.map +2 -2
  96. package/build-module/radio-control/index.mjs +2 -0
  97. package/build-module/radio-control/index.mjs.map +2 -2
  98. package/build-module/sandbox/index.mjs +128 -4
  99. package/build-module/sandbox/index.mjs.map +2 -2
  100. package/build-module/textarea-control/styles/textarea-control-styles.mjs +3 -3
  101. package/build-module/textarea-control/styles/textarea-control-styles.mjs.map +2 -2
  102. package/build-module/validated-form-controls/control-with-error.mjs +12 -8
  103. package/build-module/validated-form-controls/control-with-error.mjs.map +2 -2
  104. package/build-style/style-rtl.css +83 -26
  105. package/build-style/style.css +83 -26
  106. package/build-types/autocomplete/autocompleter-ui.d.ts +2 -2
  107. package/build-types/autocomplete/autocompleter-ui.d.ts.map +1 -1
  108. package/build-types/autocomplete/get-autocomplete-match.d.ts +11 -0
  109. package/build-types/autocomplete/get-autocomplete-match.d.ts.map +1 -0
  110. package/build-types/autocomplete/index.d.ts +8 -0
  111. package/build-types/autocomplete/index.d.ts.map +1 -1
  112. package/build-types/autocomplete/test/get-autocomplete-match.d.ts +2 -0
  113. package/build-types/autocomplete/test/get-autocomplete-match.d.ts.map +1 -0
  114. package/build-types/autocomplete/types.d.ts +23 -9
  115. package/build-types/autocomplete/types.d.ts.map +1 -1
  116. package/build-types/box-control/index.d.ts.map +1 -1
  117. package/build-types/box-control/utils.d.ts +7 -16
  118. package/build-types/box-control/utils.d.ts.map +1 -1
  119. package/build-types/button/stories/index.story.d.ts +0 -1
  120. package/build-types/button/stories/index.story.d.ts.map +1 -1
  121. package/build-types/calendar/utils/use-localization-props.d.ts +3 -3
  122. package/build-types/calendar/utils/use-localization-props.d.ts.map +1 -1
  123. package/build-types/checkbox-control/types.d.ts +4 -0
  124. package/build-types/checkbox-control/types.d.ts.map +1 -1
  125. package/build-types/custom-gradient-picker/constants.d.ts +2 -2
  126. package/build-types/custom-gradient-picker/index.d.ts.map +1 -1
  127. package/build-types/custom-select-control-v2/custom-select.d.ts +3 -3
  128. package/build-types/custom-select-control-v2/custom-select.d.ts.map +1 -1
  129. package/build-types/custom-select-control-v2/types.d.ts +1 -1
  130. package/build-types/custom-select-control-v2/types.d.ts.map +1 -1
  131. package/build-types/date-time/date-picker/index.d.ts.map +1 -0
  132. package/build-types/date-time/date-picker/styles.d.ts.map +1 -0
  133. package/build-types/date-time/date-picker/test/index.d.ts.map +1 -0
  134. package/build-types/date-time/date-picker/test/use-lilius.d.ts.map +1 -0
  135. package/build-types/date-time/date-picker/use-lilius/index.d.ts.map +1 -0
  136. package/build-types/date-time/date-time/index.d.ts +2 -2
  137. package/build-types/date-time/date-time/index.d.ts.map +1 -1
  138. package/build-types/date-time/index.d.ts +2 -2
  139. package/build-types/date-time/index.d.ts.map +1 -1
  140. package/build-types/date-time/stories/date.story.d.ts +1 -1
  141. package/build-types/date-time/stories/date.story.d.ts.map +1 -1
  142. package/build-types/date-time/stories/time.story.d.ts +1 -1
  143. package/build-types/date-time/stories/time.story.d.ts.map +1 -1
  144. package/build-types/date-time/{time → time-picker}/index.d.ts +1 -1
  145. package/build-types/date-time/time-picker/index.d.ts.map +1 -0
  146. package/build-types/date-time/time-picker/styles.d.ts.map +1 -0
  147. package/build-types/date-time/time-picker/test/index.d.ts.map +1 -0
  148. package/build-types/date-time/time-picker/time-input/index.d.ts.map +1 -0
  149. package/build-types/date-time/time-picker/time-input/test/index.d.ts.map +1 -0
  150. package/build-types/date-time/time-picker/timezone.d.ts.map +1 -0
  151. package/build-types/date-time/types.d.ts +1 -1
  152. package/build-types/date-time/types.d.ts.map +1 -1
  153. package/build-types/font-size-picker/constants.d.ts +2 -2
  154. package/build-types/font-size-picker/constants.d.ts.map +1 -1
  155. package/build-types/modal/index.d.ts.map +1 -1
  156. package/build-types/palette-edit/index.d.ts +1 -1
  157. package/build-types/palette-edit/index.d.ts.map +1 -1
  158. package/build-types/radio-control/index.d.ts.map +1 -1
  159. package/build-types/radio-control/types.d.ts +6 -0
  160. package/build-types/radio-control/types.d.ts.map +1 -1
  161. package/build-types/sandbox/index.d.ts +1 -1
  162. package/build-types/sandbox/index.d.ts.map +1 -1
  163. package/build-types/sandbox/types.d.ts +11 -0
  164. package/build-types/sandbox/types.d.ts.map +1 -1
  165. package/build-types/textarea-control/stories/index.story.d.ts.map +1 -1
  166. package/build-types/textarea-control/styles/textarea-control-styles.d.ts.map +1 -1
  167. package/build-types/validated-form-controls/components/checkbox-control.d.ts +2 -1
  168. package/build-types/validated-form-controls/components/checkbox-control.d.ts.map +1 -1
  169. package/build-types/validated-form-controls/components/radio-control.d.ts +2 -1
  170. package/build-types/validated-form-controls/components/radio-control.d.ts.map +1 -1
  171. package/build-types/validated-form-controls/control-with-error.d.ts.map +1 -1
  172. package/package.json +21 -21
  173. package/src/alignment-matrix-control/README.md +1 -1
  174. package/src/alignment-matrix-control/style.module.scss +1 -1
  175. package/src/angle-picker-control/style.module.scss +1 -0
  176. package/src/autocomplete/README.md +2 -2
  177. package/src/autocomplete/autocompleter-ui.native.js +166 -173
  178. package/src/autocomplete/autocompleter-ui.tsx +114 -116
  179. package/src/autocomplete/get-autocomplete-match.ts +115 -0
  180. package/src/autocomplete/index.tsx +129 -208
  181. package/src/autocomplete/test/get-autocomplete-match.ts +338 -0
  182. package/src/autocomplete/test/index.tsx +112 -4
  183. package/src/autocomplete/types.ts +17 -10
  184. package/src/box-control/index.tsx +1 -19
  185. package/src/box-control/utils.ts +1 -19
  186. package/src/button/README.md +1 -1
  187. package/src/button/stories/index.story.tsx +0 -1
  188. package/src/button/style.scss +1 -7
  189. package/src/calendar/style.scss +3 -3
  190. package/src/calendar/utils/use-localization-props.ts +3 -4
  191. package/src/checkbox-control/style.scss +17 -5
  192. package/src/checkbox-control/types.ts +4 -0
  193. package/src/circular-option-picker/style.scss +1 -1
  194. package/src/color-palette/style.scss +1 -1
  195. package/src/css.d.ts +1 -0
  196. package/src/custom-gradient-picker/index.tsx +1 -0
  197. package/src/custom-select-control/index.tsx +3 -3
  198. package/src/custom-select-control-v2/custom-select.tsx +4 -4
  199. package/src/custom-select-control-v2/index.tsx +2 -2
  200. package/src/custom-select-control-v2/types.ts +1 -1
  201. package/src/date-time/README.md +3 -3
  202. package/src/date-time/date-picker/README.md +65 -0
  203. package/src/date-time/date-time/index.tsx +2 -2
  204. package/src/date-time/index.ts +2 -2
  205. package/src/date-time/stories/date.story.tsx +1 -1
  206. package/src/date-time/stories/time.story.tsx +1 -1
  207. package/src/date-time/time-picker/README.md +119 -0
  208. package/src/date-time/{time → time-picker}/index.tsx +1 -1
  209. package/src/date-time/types.ts +1 -1
  210. package/src/divider/README.md +5 -6
  211. package/src/dropdown-menu/style.scss +1 -1
  212. package/src/flex/stories/index.story.tsx +1 -1
  213. package/src/form-file-upload/README.md +3 -3
  214. package/src/form-toggle/style.scss +35 -2
  215. package/src/form-token-field/style.scss +12 -3
  216. package/src/gradient-picker/README.md +2 -2
  217. package/src/h-stack/README.md +10 -15
  218. package/src/h-stack/stories/index.story.tsx +2 -2
  219. package/src/heading/stories/index.story.tsx +1 -1
  220. package/src/higher-order/with-focus-outside/index.native.js +21 -20
  221. package/src/icon/README.md +1 -1
  222. package/src/menu/README.md +2 -2
  223. package/src/mobile/utils/get-px-from-css-unit.native.js +1 -1
  224. package/src/modal/index.tsx +1 -0
  225. package/src/palette-edit/index.tsx +1 -0
  226. package/src/radio-control/index.tsx +2 -0
  227. package/src/radio-control/style.scss +21 -2
  228. package/src/radio-control/test/index.tsx +10 -0
  229. package/src/radio-control/types.ts +6 -0
  230. package/src/sandbox/index.native.js +2 -2
  231. package/src/sandbox/index.tsx +191 -11
  232. package/src/sandbox/test/index.tsx +65 -24
  233. package/src/sandbox/types.ts +11 -0
  234. package/src/snackbar/style.scss +2 -2
  235. package/src/tab-panel/style.scss +1 -1
  236. package/src/tabs/README.md +6 -6
  237. package/src/text/stories/index.story.tsx +1 -1
  238. package/src/textarea-control/stories/index.story.tsx +3 -0
  239. package/src/textarea-control/styles/textarea-control-styles.ts +6 -0
  240. package/src/toggle-control/style.scss +1 -1
  241. package/src/toggle-control/test/index.tsx +8 -2
  242. package/src/toolbar/toolbar-button/toolbar-button-container.native.js +3 -1
  243. package/src/tree-select/README.md +1 -1
  244. package/src/v-stack/README.md +10 -15
  245. package/src/v-stack/stories/index.story.tsx +2 -2
  246. package/src/validated-form-controls/control-with-error.tsx +17 -12
  247. package/src/validated-form-controls/test/control-with-error.tsx +28 -1
  248. package/src/view/README.md +2 -5
  249. package/build/date-time/time/index.cjs.map +0 -7
  250. package/build-module/date-time/time/index.mjs.map +0 -7
  251. package/build-types/date-time/date/index.d.ts.map +0 -1
  252. package/build-types/date-time/date/styles.d.ts.map +0 -1
  253. package/build-types/date-time/date/test/index.d.ts.map +0 -1
  254. package/build-types/date-time/date/test/use-lilius.d.ts.map +0 -1
  255. package/build-types/date-time/date/use-lilius/index.d.ts.map +0 -1
  256. package/build-types/date-time/time/index.d.ts.map +0 -1
  257. package/build-types/date-time/time/styles.d.ts.map +0 -1
  258. package/build-types/date-time/time/test/index.d.ts.map +0 -1
  259. package/build-types/date-time/time/time-input/index.d.ts.map +0 -1
  260. package/build-types/date-time/time/time-input/test/index.d.ts.map +0 -1
  261. package/build-types/date-time/time/timezone.d.ts.map +0 -1
  262. package/src/button/stories/style.css +0 -8
  263. /package/build-types/date-time/{date → date-picker}/index.d.ts +0 -0
  264. /package/build-types/date-time/{date → date-picker}/styles.d.ts +0 -0
  265. /package/build-types/date-time/{date → date-picker}/test/index.d.ts +0 -0
  266. /package/build-types/date-time/{date → date-picker}/test/use-lilius.d.ts +0 -0
  267. /package/build-types/date-time/{date → date-picker}/use-lilius/index.d.ts +0 -0
  268. /package/build-types/date-time/{time → time-picker}/styles.d.ts +0 -0
  269. /package/build-types/date-time/{time → time-picker}/test/index.d.ts +0 -0
  270. /package/build-types/date-time/{time → time-picker}/time-input/index.d.ts +0 -0
  271. /package/build-types/date-time/{time → time-picker}/time-input/test/index.d.ts +0 -0
  272. /package/build-types/date-time/{time → time-picker}/timezone.d.ts +0 -0
  273. /package/src/date-time/{date → date-picker}/index.tsx +0 -0
  274. /package/src/date-time/{date → date-picker}/styles.ts +0 -0
  275. /package/src/date-time/{date → date-picker}/test/index.tsx +0 -0
  276. /package/src/date-time/{date → date-picker}/test/use-lilius.ts +0 -0
  277. /package/src/date-time/{date → date-picker}/use-lilius/index.ts +0 -0
  278. /package/src/date-time/{time → time-picker}/styles.ts +0 -0
  279. /package/src/date-time/{time → time-picker}/test/index.tsx +0 -0
  280. /package/src/date-time/{time → time-picker}/time-input/index.tsx +0 -0
  281. /package/src/date-time/{time → time-picker}/time-input/test/index.tsx +0 -0
  282. /package/src/date-time/{time → time-picker}/timezone.tsx +0 -0
@@ -41,92 +41,88 @@ function ListBox({
41
41
  }, option.key))
42
42
  });
43
43
  }
44
- function getAutoCompleterUI(autocompleter) {
44
+ function AutocompleterUI({
45
+ autocompleter,
46
+ filterValue,
47
+ instanceId,
48
+ listBoxId,
49
+ className,
50
+ selectedIndex,
51
+ onChangeOptions,
52
+ onSelect,
53
+ reset,
54
+ contentRef
55
+ }) {
45
56
  const useItems = autocompleter.useItems ?? getDefaultUseItems(autocompleter);
46
- function AutocompleterUI({
47
- filterValue,
48
- instanceId,
49
- listBoxId,
50
- className,
51
- selectedIndex,
52
- onChangeOptions,
53
- onSelect,
54
- onReset,
55
- reset,
56
- contentRef
57
- }) {
58
- const [items] = useItems(filterValue);
59
- const popoverAnchor = useAnchor({
60
- editableContentElement: contentRef.current
61
- });
62
- const [needsA11yCompat, setNeedsA11yCompat] = useState(false);
63
- const popoverRef = useRef(null);
64
- const popoverRefs = useMergeRefs([popoverRef, useRefEffect((node) => {
65
- if (!contentRef.current) {
66
- return;
67
- }
68
- setNeedsA11yCompat(node.ownerDocument !== contentRef.current.ownerDocument);
69
- }, [contentRef])]);
70
- useOnClickOutside(popoverRef, reset);
71
- const debouncedSpeak = useDebounce(speak, 500);
72
- function announce(options) {
73
- if (!debouncedSpeak) {
74
- return;
75
- }
76
- if (!!options.length) {
77
- if (filterValue) {
78
- debouncedSpeak(sprintf(
79
- /* translators: %d: number of results. */
80
- _n("%d result found, use up and down arrow keys to navigate.", "%d results found, use up and down arrow keys to navigate.", options.length),
81
- options.length
82
- ), "assertive");
83
- } else {
84
- debouncedSpeak(sprintf(
85
- /* translators: %d: number of results. */
86
- _n("Initial %d result loaded. Type to filter all available results. Use up and down arrow keys to navigate.", "Initial %d results loaded. Type to filter all available results. Use up and down arrow keys to navigate.", options.length),
87
- options.length
88
- ), "assertive");
89
- }
57
+ const [items] = useItems(filterValue);
58
+ const popoverAnchor = useAnchor({
59
+ editableContentElement: contentRef.current
60
+ });
61
+ const [needsA11yCompat, setNeedsA11yCompat] = useState(false);
62
+ const popoverRef = useRef(null);
63
+ const popoverRefs = useMergeRefs([popoverRef, useRefEffect((node) => {
64
+ if (!contentRef.current) {
65
+ return;
66
+ }
67
+ setNeedsA11yCompat(node.ownerDocument !== contentRef.current.ownerDocument);
68
+ }, [contentRef])]);
69
+ useOnClickOutside(popoverRef, reset);
70
+ const debouncedSpeak = useDebounce(speak, 500);
71
+ function announce(options) {
72
+ if (!debouncedSpeak) {
73
+ return;
74
+ }
75
+ if (!!options.length) {
76
+ if (filterValue) {
77
+ debouncedSpeak(sprintf(
78
+ /* translators: %d: number of results. */
79
+ _n("%d result found, use up and down arrow keys to navigate.", "%d results found, use up and down arrow keys to navigate.", options.length),
80
+ options.length
81
+ ), "assertive");
90
82
  } else {
91
- debouncedSpeak(__("No results."), "assertive");
83
+ debouncedSpeak(sprintf(
84
+ /* translators: %d: number of results. */
85
+ _n("Initial %d result loaded. Type to filter all available results. Use up and down arrow keys to navigate.", "Initial %d results loaded. Type to filter all available results. Use up and down arrow keys to navigate.", options.length),
86
+ options.length
87
+ ), "assertive");
92
88
  }
89
+ } else {
90
+ debouncedSpeak(__("No results."), "assertive");
93
91
  }
94
- useLayoutEffect(() => {
95
- onChangeOptions(items);
96
- announce(items);
97
- }, [items]);
98
- if (items.length === 0) {
99
- return null;
100
- }
101
- return /* @__PURE__ */ _jsxs(_Fragment, {
102
- children: [/* @__PURE__ */ _jsx(Popover, {
103
- offset: 8,
104
- focusOnMount: false,
105
- onClose: onReset,
106
- placement: "top-start",
107
- className: "components-autocomplete__popover",
108
- anchor: popoverAnchor,
109
- ref: popoverRefs,
110
- children: /* @__PURE__ */ _jsx(ListBox, {
111
- items,
112
- onSelect,
113
- selectedIndex,
114
- instanceId,
115
- listBoxId,
116
- className
117
- })
118
- }), contentRef.current && needsA11yCompat && createPortal(/* @__PURE__ */ _jsx(ListBox, {
92
+ }
93
+ useLayoutEffect(() => {
94
+ onChangeOptions(items);
95
+ announce(items);
96
+ }, [items]);
97
+ if (items.length === 0) {
98
+ return null;
99
+ }
100
+ return /* @__PURE__ */ _jsxs(_Fragment, {
101
+ children: [/* @__PURE__ */ _jsx(Popover, {
102
+ offset: 8,
103
+ focusOnMount: false,
104
+ placement: "top-start",
105
+ className: "components-autocomplete__popover",
106
+ anchor: popoverAnchor,
107
+ ref: popoverRefs,
108
+ children: /* @__PURE__ */ _jsx(ListBox, {
119
109
  items,
120
110
  onSelect,
121
111
  selectedIndex,
122
112
  instanceId,
123
113
  listBoxId,
124
- className,
125
- Component: VisuallyHidden
126
- }), contentRef.current.ownerDocument.body)]
127
- });
128
- }
129
- return AutocompleterUI;
114
+ className
115
+ })
116
+ }), contentRef.current && needsA11yCompat && createPortal(/* @__PURE__ */ _jsx(ListBox, {
117
+ items,
118
+ onSelect,
119
+ selectedIndex,
120
+ instanceId,
121
+ listBoxId,
122
+ className,
123
+ Component: VisuallyHidden
124
+ }), contentRef.current.ownerDocument.body)]
125
+ });
130
126
  }
131
127
  function useOnClickOutside(ref, handler) {
132
128
  useEffect(() => {
@@ -145,6 +141,6 @@ function useOnClickOutside(ref, handler) {
145
141
  }, [handler, ref]);
146
142
  }
147
143
  export {
148
- getAutoCompleterUI
144
+ AutocompleterUI
149
145
  };
150
146
  //# sourceMappingURL=autocompleter-ui.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/autocomplete/autocompleter-ui.tsx"],
4
- "sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\nimport { createPortal } from 'react-dom';\n\n/**\n * WordPress dependencies\n */\nimport { useLayoutEffect, useRef, useEffect, useState } from '@wordpress/element';\nimport { useAnchor } from '@wordpress/rich-text';\nimport { useDebounce, useMergeRefs, useRefEffect } from '@wordpress/compose';\nimport { speak } from '@wordpress/a11y';\nimport { __, _n, sprintf } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport getDefaultUseItems from './get-default-use-items';\nimport Button from '../button';\nimport Popover from '../popover';\nimport { VisuallyHidden } from '../visually-hidden';\nimport { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from \"react/jsx-runtime\";\nfunction ListBox({\n items,\n onSelect,\n selectedIndex,\n instanceId,\n listBoxId,\n className,\n Component = 'div'\n}) {\n return /*#__PURE__*/_jsx(Component, {\n id: listBoxId,\n role: \"listbox\",\n className: \"components-autocomplete__results\",\n children: items.map((option, index) => /*#__PURE__*/_jsx(Button, {\n id: `components-autocomplete-item-${instanceId}-${option.key}`,\n role: \"option\",\n __next40pxDefaultSize: true,\n \"aria-selected\": index === selectedIndex,\n accessibleWhenDisabled: true,\n disabled: option.isDisabled,\n className: clsx('components-autocomplete__result', className, {\n // Unused, for backwards compatibility.\n 'is-selected': index === selectedIndex\n }),\n variant: index === selectedIndex ? 'primary' : undefined,\n onClick: () => onSelect(option),\n children: option.label\n }, option.key))\n });\n}\nexport function getAutoCompleterUI(autocompleter) {\n const useItems = autocompleter.useItems ?? getDefaultUseItems(autocompleter);\n function AutocompleterUI({\n filterValue,\n instanceId,\n listBoxId,\n className,\n selectedIndex,\n onChangeOptions,\n onSelect,\n onReset,\n reset,\n contentRef\n }) {\n const [items] = useItems(filterValue);\n const popoverAnchor = useAnchor({\n editableContentElement: contentRef.current\n });\n const [needsA11yCompat, setNeedsA11yCompat] = useState(false);\n const popoverRef = useRef(null);\n const popoverRefs = useMergeRefs([popoverRef, useRefEffect(node => {\n if (!contentRef.current) {\n return;\n }\n\n // If the popover is rendered in a different document than\n // the content, we need to duplicate the options list in the\n // content document so that it's available to the screen\n // readers, which check the DOM ID based aria-* attributes.\n setNeedsA11yCompat(node.ownerDocument !== contentRef.current.ownerDocument);\n }, [contentRef])]);\n useOnClickOutside(popoverRef, reset);\n const debouncedSpeak = useDebounce(speak, 500);\n function announce(options) {\n if (!debouncedSpeak) {\n return;\n }\n if (!!options.length) {\n if (filterValue) {\n debouncedSpeak(sprintf(/* translators: %d: number of results. */\n _n('%d result found, use up and down arrow keys to navigate.', '%d results found, use up and down arrow keys to navigate.', options.length), options.length), 'assertive');\n } else {\n debouncedSpeak(sprintf(/* translators: %d: number of results. */\n _n('Initial %d result loaded. Type to filter all available results. Use up and down arrow keys to navigate.', 'Initial %d results loaded. Type to filter all available results. Use up and down arrow keys to navigate.', options.length), options.length), 'assertive');\n }\n } else {\n debouncedSpeak(__('No results.'), 'assertive');\n }\n }\n useLayoutEffect(() => {\n onChangeOptions(items);\n announce(items);\n // We want to avoid introducing unexpected side effects.\n // See https://github.com/WordPress/gutenberg/pull/41820\n }, [items]);\n if (items.length === 0) {\n return null;\n }\n return /*#__PURE__*/_jsxs(_Fragment, {\n children: [/*#__PURE__*/_jsx(Popover, {\n offset: 8,\n focusOnMount: false,\n onClose: onReset,\n placement: \"top-start\",\n className: \"components-autocomplete__popover\",\n anchor: popoverAnchor,\n ref: popoverRefs,\n children: /*#__PURE__*/_jsx(ListBox, {\n items: items,\n onSelect: onSelect,\n selectedIndex: selectedIndex,\n instanceId: instanceId,\n listBoxId: listBoxId,\n className: className\n })\n }), contentRef.current && needsA11yCompat && createPortal(/*#__PURE__*/_jsx(ListBox, {\n items: items,\n onSelect: onSelect,\n selectedIndex: selectedIndex,\n instanceId: instanceId,\n listBoxId: listBoxId,\n className: className,\n Component: VisuallyHidden\n }), contentRef.current.ownerDocument.body)]\n });\n }\n return AutocompleterUI;\n}\nfunction useOnClickOutside(ref, handler) {\n useEffect(() => {\n const listener = event => {\n // Do nothing if clicking ref's element or descendent elements, or if the ref is not referencing an element\n if (!ref.current || ref.current.contains(event.target)) {\n return;\n }\n handler(event);\n };\n document.addEventListener('mousedown', listener);\n document.addEventListener('touchstart', listener);\n return () => {\n document.removeEventListener('mousedown', listener);\n document.removeEventListener('touchstart', listener);\n };\n }, [handler, ref]);\n}"],
5
- "mappings": ";AAGA,OAAO,UAAU;AACjB,SAAS,oBAAoB;AAK7B,SAAS,iBAAiB,QAAQ,WAAW,gBAAgB;AAC7D,SAAS,iBAAiB;AAC1B,SAAS,aAAa,cAAc,oBAAoB;AACxD,SAAS,aAAa;AACtB,SAAS,IAAI,IAAI,eAAe;AAKhC,OAAO,wBAAwB;AAC/B,OAAO,YAAY;AACnB,OAAO,aAAa;AACpB,SAAS,sBAAsB;AAC/B,SAAS,OAAO,MAAM,YAAY,WAAW,QAAQ,aAAa;AAClE,SAAS,QAAQ;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AACd,GAAG;AACD,SAAoB,qBAAK,WAAW;AAAA,IAClC,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU,MAAM,IAAI,CAAC,QAAQ,UAAuB,qBAAK,QAAQ;AAAA,MAC/D,IAAI,gCAAgC,UAAU,IAAI,OAAO,GAAG;AAAA,MAC5D,MAAM;AAAA,MACN,uBAAuB;AAAA,MACvB,iBAAiB,UAAU;AAAA,MAC3B,wBAAwB;AAAA,MACxB,UAAU,OAAO;AAAA,MACjB,WAAW,KAAK,mCAAmC,WAAW;AAAA;AAAA,QAE5D,eAAe,UAAU;AAAA,MAC3B,CAAC;AAAA,MACD,SAAS,UAAU,gBAAgB,YAAY;AAAA,MAC/C,SAAS,MAAM,SAAS,MAAM;AAAA,MAC9B,UAAU,OAAO;AAAA,IACnB,GAAG,OAAO,GAAG,CAAC;AAAA,EAChB,CAAC;AACH;AACO,SAAS,mBAAmB,eAAe;AAChD,QAAM,WAAW,cAAc,YAAY,mBAAmB,aAAa;AAC3E,WAAS,gBAAgB;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAAG;AACD,UAAM,CAAC,KAAK,IAAI,SAAS,WAAW;AACpC,UAAM,gBAAgB,UAAU;AAAA,MAC9B,wBAAwB,WAAW;AAAA,IACrC,CAAC;AACD,UAAM,CAAC,iBAAiB,kBAAkB,IAAI,SAAS,KAAK;AAC5D,UAAM,aAAa,OAAO,IAAI;AAC9B,UAAM,cAAc,aAAa,CAAC,YAAY,aAAa,UAAQ;AACjE,UAAI,CAAC,WAAW,SAAS;AACvB;AAAA,MACF;AAMA,yBAAmB,KAAK,kBAAkB,WAAW,QAAQ,aAAa;AAAA,IAC5E,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;AACjB,sBAAkB,YAAY,KAAK;AACnC,UAAM,iBAAiB,YAAY,OAAO,GAAG;AAC7C,aAAS,SAAS,SAAS;AACzB,UAAI,CAAC,gBAAgB;AACnB;AAAA,MACF;AACA,UAAI,CAAC,CAAC,QAAQ,QAAQ;AACpB,YAAI,aAAa;AACf,yBAAe;AAAA;AAAA,YACf,GAAG,4DAA4D,6DAA6D,QAAQ,MAAM;AAAA,YAAG,QAAQ;AAAA,UAAM,GAAG,WAAW;AAAA,QAC3K,OAAO;AACL,yBAAe;AAAA;AAAA,YACf,GAAG,2GAA2G,4GAA4G,QAAQ,MAAM;AAAA,YAAG,QAAQ;AAAA,UAAM,GAAG,WAAW;AAAA,QACzQ;AAAA,MACF,OAAO;AACL,uBAAe,GAAG,aAAa,GAAG,WAAW;AAAA,MAC/C;AAAA,IACF;AACA,oBAAgB,MAAM;AACpB,sBAAgB,KAAK;AACrB,eAAS,KAAK;AAAA,IAGhB,GAAG,CAAC,KAAK,CAAC;AACV,QAAI,MAAM,WAAW,GAAG;AACtB,aAAO;AAAA,IACT;AACA,WAAoB,sBAAM,WAAW;AAAA,MACnC,UAAU,CAAc,qBAAK,SAAS;AAAA,QACpC,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,SAAS;AAAA,QACT,WAAW;AAAA,QACX,WAAW;AAAA,QACX,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,UAAuB,qBAAK,SAAS;AAAA,UACnC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH,CAAC,GAAG,WAAW,WAAW,mBAAmB,aAA0B,qBAAK,SAAS;AAAA,QACnF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAW;AAAA,MACb,CAAC,GAAG,WAAW,QAAQ,cAAc,IAAI,CAAC;AAAA,IAC5C,CAAC;AAAA,EACH;AACA,SAAO;AACT;AACA,SAAS,kBAAkB,KAAK,SAAS;AACvC,YAAU,MAAM;AACd,UAAM,WAAW,WAAS;AAExB,UAAI,CAAC,IAAI,WAAW,IAAI,QAAQ,SAAS,MAAM,MAAM,GAAG;AACtD;AAAA,MACF;AACA,cAAQ,KAAK;AAAA,IACf;AACA,aAAS,iBAAiB,aAAa,QAAQ;AAC/C,aAAS,iBAAiB,cAAc,QAAQ;AAChD,WAAO,MAAM;AACX,eAAS,oBAAoB,aAAa,QAAQ;AAClD,eAAS,oBAAoB,cAAc,QAAQ;AAAA,IACrD;AAAA,EACF,GAAG,CAAC,SAAS,GAAG,CAAC;AACnB;",
4
+ "sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\nimport { createPortal } from 'react-dom';\n\n/**\n * WordPress dependencies\n */\nimport { useLayoutEffect, useRef, useEffect, useState } from '@wordpress/element';\nimport { useAnchor } from '@wordpress/rich-text';\nimport { useDebounce, useMergeRefs, useRefEffect } from '@wordpress/compose';\nimport { speak } from '@wordpress/a11y';\nimport { __, _n, sprintf } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport getDefaultUseItems from './get-default-use-items';\nimport Button from '../button';\nimport Popover from '../popover';\nimport { VisuallyHidden } from '../visually-hidden';\nimport { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from \"react/jsx-runtime\";\nfunction ListBox({\n items,\n onSelect,\n selectedIndex,\n instanceId,\n listBoxId,\n className,\n Component = 'div'\n}) {\n return /*#__PURE__*/_jsx(Component, {\n id: listBoxId,\n role: \"listbox\",\n className: \"components-autocomplete__results\",\n children: items.map((option, index) => /*#__PURE__*/_jsx(Button, {\n id: `components-autocomplete-item-${instanceId}-${option.key}`,\n role: \"option\",\n __next40pxDefaultSize: true,\n \"aria-selected\": index === selectedIndex,\n accessibleWhenDisabled: true,\n disabled: option.isDisabled,\n className: clsx('components-autocomplete__result', className, {\n // Unused, for backwards compatibility.\n 'is-selected': index === selectedIndex\n }),\n variant: index === selectedIndex ? 'primary' : undefined,\n onClick: () => onSelect(option),\n children: option.label\n }, option.key))\n });\n}\nexport function AutocompleterUI({\n autocompleter,\n filterValue,\n instanceId,\n listBoxId,\n className,\n selectedIndex,\n onChangeOptions,\n onSelect,\n reset,\n contentRef\n}) {\n // The useItems hook is derived from the autocompleter prop. This is safe\n // because the parent renders this component with key={autocompleter.name},\n // ensuring a fresh mount (and stable hook identity) when the completer changes.\n const useItems = autocompleter.useItems ?? getDefaultUseItems(autocompleter);\n // eslint-disable-next-line react-compiler/react-compiler\n const [items] = useItems(filterValue);\n const popoverAnchor = useAnchor({\n editableContentElement: contentRef.current\n });\n const [needsA11yCompat, setNeedsA11yCompat] = useState(false);\n const popoverRef = useRef(null);\n const popoverRefs = useMergeRefs([popoverRef, useRefEffect(node => {\n if (!contentRef.current) {\n return;\n }\n\n // If the popover is rendered in a different document than\n // the content, we need to duplicate the options list in the\n // content document so that it's available to the screen\n // readers, which check the DOM ID based aria-* attributes.\n setNeedsA11yCompat(node.ownerDocument !== contentRef.current.ownerDocument);\n }, [contentRef])]);\n useOnClickOutside(popoverRef, reset);\n const debouncedSpeak = useDebounce(speak, 500);\n function announce(options) {\n if (!debouncedSpeak) {\n return;\n }\n if (!!options.length) {\n if (filterValue) {\n debouncedSpeak(sprintf(/* translators: %d: number of results. */\n _n('%d result found, use up and down arrow keys to navigate.', '%d results found, use up and down arrow keys to navigate.', options.length), options.length), 'assertive');\n } else {\n debouncedSpeak(sprintf(/* translators: %d: number of results. */\n _n('Initial %d result loaded. Type to filter all available results. Use up and down arrow keys to navigate.', 'Initial %d results loaded. Type to filter all available results. Use up and down arrow keys to navigate.', options.length), options.length), 'assertive');\n }\n } else {\n debouncedSpeak(__('No results.'), 'assertive');\n }\n }\n useLayoutEffect(() => {\n onChangeOptions(items);\n announce(items);\n // We want to avoid introducing unexpected side effects.\n // See https://github.com/WordPress/gutenberg/pull/41820\n }, [items]);\n if (items.length === 0) {\n return null;\n }\n return /*#__PURE__*/_jsxs(_Fragment, {\n children: [/*#__PURE__*/_jsx(Popover, {\n offset: 8,\n focusOnMount: false,\n placement: \"top-start\",\n className: \"components-autocomplete__popover\",\n anchor: popoverAnchor,\n ref: popoverRefs,\n children: /*#__PURE__*/_jsx(ListBox, {\n items: items,\n onSelect: onSelect,\n selectedIndex: selectedIndex,\n instanceId: instanceId,\n listBoxId: listBoxId,\n className: className\n })\n }), contentRef.current && needsA11yCompat && createPortal(/*#__PURE__*/_jsx(ListBox, {\n items: items,\n onSelect: onSelect,\n selectedIndex: selectedIndex,\n instanceId: instanceId,\n listBoxId: listBoxId,\n className: className,\n Component: VisuallyHidden\n }), contentRef.current.ownerDocument.body)]\n });\n}\nfunction useOnClickOutside(ref, handler) {\n useEffect(() => {\n const listener = event => {\n // Do nothing if clicking ref's element or descendent elements, or if the ref is not referencing an element\n if (!ref.current || ref.current.contains(event.target)) {\n return;\n }\n handler(event);\n };\n document.addEventListener('mousedown', listener);\n document.addEventListener('touchstart', listener);\n return () => {\n document.removeEventListener('mousedown', listener);\n document.removeEventListener('touchstart', listener);\n };\n }, [handler, ref]);\n}"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,56 @@
1
+ // packages/components/src/autocomplete/get-autocomplete-match.ts
2
+ import removeAccents from "remove-accents";
3
+ function getAutocompleteMatch(textContent, completers, filteredOptionsLength, isBackspacing, getTextAfterSelection) {
4
+ if (!textContent) {
5
+ return null;
6
+ }
7
+ let completer = null;
8
+ let triggerIndex = -1;
9
+ let matchedEndIndex = -1;
10
+ let matchedPrefixLength = 0;
11
+ for (const currentCompleter of completers) {
12
+ const currentIndex = textContent.lastIndexOf(currentCompleter.triggerPrefix);
13
+ if (currentIndex < 0) {
14
+ continue;
15
+ }
16
+ const currentEndIndex = currentIndex + currentCompleter.triggerPrefix.length;
17
+ if (currentEndIndex > matchedEndIndex || currentEndIndex === matchedEndIndex && currentCompleter.triggerPrefix.length > matchedPrefixLength) {
18
+ completer = currentCompleter;
19
+ triggerIndex = currentIndex;
20
+ matchedEndIndex = currentEndIndex;
21
+ matchedPrefixLength = currentCompleter.triggerPrefix.length;
22
+ }
23
+ }
24
+ if (!completer) {
25
+ return null;
26
+ }
27
+ const {
28
+ allowContext,
29
+ triggerPrefix
30
+ } = completer;
31
+ const textWithoutTrigger = textContent.slice(triggerIndex + triggerPrefix.length);
32
+ if (textWithoutTrigger.length > 50) {
33
+ return null;
34
+ }
35
+ const mismatch = filteredOptionsLength === 0;
36
+ const wordsFromTrigger = textWithoutTrigger.split(/\s/);
37
+ const hasOneTriggerWord = wordsFromTrigger.length === 1;
38
+ const matchingWhileBackspacing = isBackspacing && wordsFromTrigger.length <= 3;
39
+ if (mismatch && !(matchingWhileBackspacing || hasOneTriggerWord)) {
40
+ return null;
41
+ }
42
+ if (allowContext && !allowContext(textContent.slice(0, triggerIndex), getTextAfterSelection())) {
43
+ return null;
44
+ }
45
+ if (/^\s/.test(textWithoutTrigger) || /\s\s+$/.test(textWithoutTrigger)) {
46
+ return null;
47
+ }
48
+ return {
49
+ completer,
50
+ filterValue: removeAccents(textWithoutTrigger)
51
+ };
52
+ }
53
+ export {
54
+ getAutocompleteMatch
55
+ };
56
+ //# sourceMappingURL=get-autocomplete-match.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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;",
6
+ "names": []
7
+ }
@@ -1,17 +1,54 @@
1
1
  // packages/components/src/autocomplete/index.tsx
2
- import removeAccents from "remove-accents";
3
- import { renderToString, useEffect, useState, useRef, useMemo } from "@wordpress/element";
2
+ import { renderToString, useEffect, useMemo, useReducer, useRef } from "@wordpress/element";
4
3
  import { useInstanceId, useMergeRefs, useRefEffect } from "@wordpress/compose";
5
4
  import { create, slice, insert, isCollapsed, getTextContent } from "@wordpress/rich-text";
6
5
  import { speak } from "@wordpress/a11y";
7
6
  import { isAppleOS } from "@wordpress/keycodes";
8
- import { getAutoCompleterUI } from "./autocompleter-ui.mjs";
9
- import { escapeRegExp } from "../utils/strings.mjs";
7
+ import { AutocompleterUI } from "./autocompleter-ui.mjs";
8
+ import { getAutocompleteMatch } from "./get-autocomplete-match.mjs";
10
9
  import { withIgnoreIMEEvents } from "../utils/with-ignore-ime-events.mjs";
11
10
  import getNodeText from "../utils/get-node-text.mjs";
12
11
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
13
12
  var EMPTY_FILTERED_OPTIONS = [];
14
13
  var AUTOCOMPLETE_HOOK_REFERENCE = {};
14
+ function getCompletionObject(completion) {
15
+ if (completion !== null && typeof completion === "object" && "action" in completion && completion.action !== void 0 && "value" in completion && completion.value !== void 0) {
16
+ return completion;
17
+ }
18
+ return {
19
+ action: "insert-at-caret",
20
+ value: completion
21
+ };
22
+ }
23
+ var initialState = {
24
+ selectedIndex: 0,
25
+ filteredOptions: EMPTY_FILTERED_OPTIONS,
26
+ filterValue: "",
27
+ autocompleter: null
28
+ };
29
+ function autocompleteReducer(state, action) {
30
+ switch (action.type) {
31
+ case "RESET":
32
+ return initialState;
33
+ case "SELECT":
34
+ return {
35
+ ...state,
36
+ selectedIndex: action.index
37
+ };
38
+ case "OPTIONS":
39
+ return {
40
+ ...state,
41
+ filteredOptions: action.options,
42
+ selectedIndex: action.options.length === state.filteredOptions.length ? state.selectedIndex : 0
43
+ };
44
+ case "MATCH":
45
+ return {
46
+ ...state,
47
+ autocompleter: action.completer,
48
+ filterValue: action.query
49
+ };
50
+ }
51
+ }
15
52
  function useAutocomplete({
16
53
  record,
17
54
  onChange,
@@ -20,11 +57,13 @@ function useAutocomplete({
20
57
  contentRef
21
58
  }) {
22
59
  const instanceId = useInstanceId(AUTOCOMPLETE_HOOK_REFERENCE);
23
- const [selectedIndex, setSelectedIndex] = useState(0);
24
- const [filteredOptions, setFilteredOptions] = useState(EMPTY_FILTERED_OPTIONS);
25
- const [filterValue, setFilterValue] = useState("");
26
- const [autocompleter, setAutocompleter] = useState(null);
27
- const [AutocompleterUI, setAutocompleterUI] = useState(null);
60
+ const [state, dispatch] = useReducer(autocompleteReducer, initialState);
61
+ const {
62
+ selectedIndex,
63
+ filteredOptions,
64
+ filterValue,
65
+ autocompleter
66
+ } = state;
28
67
  const backspacingRef = useRef(false);
29
68
  function insertCompletion(replacement) {
30
69
  if (autocompleter === null) {
@@ -45,14 +84,7 @@ function useAutocomplete({
45
84
  return;
46
85
  }
47
86
  if (getOptionCompletion) {
48
- const completion = getOptionCompletion(option.value, filterValue);
49
- const isCompletionObject = (obj) => {
50
- return obj !== null && typeof obj === "object" && "action" in obj && obj.action !== void 0 && "value" in obj && obj.value !== void 0;
51
- };
52
- const completionObject = isCompletionObject(completion) ? completion : {
53
- action: "insert-at-caret",
54
- value: completion
55
- };
87
+ const completionObject = getCompletionObject(getOptionCompletion(option.value, filterValue));
56
88
  if ("replace" === completionObject.action) {
57
89
  onReplace([completionObject.value]);
58
90
  return;
@@ -60,19 +92,16 @@ function useAutocomplete({
60
92
  insertCompletion(completionObject.value);
61
93
  }
62
94
  }
63
- reset();
95
+ dispatch({
96
+ type: "RESET"
97
+ });
64
98
  contentRef.current?.focus();
65
99
  }
66
- function reset() {
67
- setSelectedIndex(0);
68
- setFilteredOptions(EMPTY_FILTERED_OPTIONS);
69
- setFilterValue("");
70
- setAutocompleter(null);
71
- setAutocompleterUI(null);
72
- }
73
100
  function onChangeOptions(options) {
74
- setSelectedIndex(options.length === filteredOptions.length ? selectedIndex : 0);
75
- setFilteredOptions(options);
101
+ dispatch({
102
+ type: "OPTIONS",
103
+ options
104
+ });
76
105
  }
77
106
  function handleKeyDown(event) {
78
107
  backspacingRef.current = event.key === "Backspace";
@@ -86,25 +115,23 @@ function useAutocomplete({
86
115
  return;
87
116
  }
88
117
  switch (event.key) {
89
- case "ArrowUp": {
90
- const newIndex = (selectedIndex === 0 ? filteredOptions.length : selectedIndex) - 1;
91
- setSelectedIndex(newIndex);
92
- if (isAppleOS()) {
93
- speak(getNodeText(filteredOptions[newIndex].label), "assertive");
94
- }
95
- break;
96
- }
118
+ case "ArrowUp":
97
119
  case "ArrowDown": {
98
- const newIndex = (selectedIndex + 1) % filteredOptions.length;
99
- setSelectedIndex(newIndex);
120
+ const offset = event.key === "ArrowUp" ? -1 : 1;
121
+ const newIndex = (selectedIndex + offset + filteredOptions.length) % filteredOptions.length;
122
+ dispatch({
123
+ type: "SELECT",
124
+ index: newIndex
125
+ });
100
126
  if (isAppleOS()) {
101
127
  speak(getNodeText(filteredOptions[newIndex].label), "assertive");
102
128
  }
103
129
  break;
104
130
  }
105
131
  case "Escape":
106
- setAutocompleter(null);
107
- setAutocompleterUI(null);
132
+ dispatch({
133
+ type: "RESET"
134
+ });
108
135
  event.preventDefault();
109
136
  break;
110
137
  case "Enter":
@@ -112,7 +139,9 @@ function useAutocomplete({
112
139
  break;
113
140
  case "ArrowLeft":
114
141
  case "ArrowRight":
115
- reset();
142
+ dispatch({
143
+ type: "RESET"
144
+ });
116
145
  return;
117
146
  default:
118
147
  return;
@@ -126,69 +155,27 @@ function useAutocomplete({
126
155
  return "";
127
156
  }, [record]);
128
157
  useEffect(() => {
129
- if (!textContent) {
130
- if (autocompleter) {
131
- reset();
132
- }
133
- return;
158
+ function getTextAfterSelection() {
159
+ return textContent ? getTextContent(slice(record, void 0, getTextContent(record).length)) : "";
134
160
  }
135
- const completer = completers.reduce((lastTrigger, currentCompleter) => {
136
- const triggerIndex2 = textContent.lastIndexOf(currentCompleter.triggerPrefix);
137
- const lastTriggerIndex = lastTrigger !== null ? textContent.lastIndexOf(lastTrigger.triggerPrefix) : -1;
138
- return triggerIndex2 > lastTriggerIndex ? currentCompleter : lastTrigger;
139
- }, null);
140
- if (!completer) {
161
+ const match = getAutocompleteMatch(textContent, completers, filteredOptions.length, backspacingRef.current, getTextAfterSelection);
162
+ if (!match) {
141
163
  if (autocompleter) {
142
- reset();
164
+ dispatch({
165
+ type: "RESET"
166
+ });
143
167
  }
144
168
  return;
145
169
  }
146
170
  const {
147
- allowContext,
148
- triggerPrefix
149
- } = completer;
150
- const triggerIndex = textContent.lastIndexOf(triggerPrefix);
151
- const textWithoutTrigger = textContent.slice(triggerIndex + triggerPrefix.length);
152
- const tooDistantFromTrigger = textWithoutTrigger.length > 50;
153
- if (tooDistantFromTrigger) {
154
- return;
155
- }
156
- const mismatch = filteredOptions.length === 0;
157
- const wordsFromTrigger = textWithoutTrigger.split(/\s/);
158
- const hasOneTriggerWord = wordsFromTrigger.length === 1;
159
- const matchingWhileBackspacing = backspacingRef.current && wordsFromTrigger.length <= 3;
160
- if (mismatch && !(matchingWhileBackspacing || hasOneTriggerWord)) {
161
- if (autocompleter) {
162
- reset();
163
- }
164
- return;
165
- }
166
- const textAfterSelection = getTextContent(slice(record, void 0, getTextContent(record).length));
167
- if (allowContext && !allowContext(textContent.slice(0, triggerIndex), textAfterSelection)) {
168
- if (autocompleter) {
169
- reset();
170
- }
171
- return;
172
- }
173
- if (/^\s/.test(textWithoutTrigger) || /\s\s+$/.test(textWithoutTrigger)) {
174
- if (autocompleter) {
175
- reset();
176
- }
177
- return;
178
- }
179
- if (!/[\u0000-\uFFFF]*$/.test(textWithoutTrigger)) {
180
- if (autocompleter) {
181
- reset();
182
- }
183
- return;
184
- }
185
- const safeTrigger = escapeRegExp(completer.triggerPrefix);
186
- const text = removeAccents(textContent);
187
- const match = text.slice(text.lastIndexOf(completer.triggerPrefix)).match(new RegExp(`${safeTrigger}([\0-\uFFFF]*)$`));
188
- const query = match && match[1];
189
- setAutocompleter(completer);
190
- setAutocompleterUI(() => completer !== autocompleter ? getAutoCompleterUI(completer) : AutocompleterUI);
191
- setFilterValue(query === null ? "" : query);
171
+ completer,
172
+ filterValue: query
173
+ } = match;
174
+ dispatch({
175
+ type: "MATCH",
176
+ completer,
177
+ query
178
+ });
192
179
  }, [textContent]);
193
180
  const {
194
181
  key: selectedKey = ""
@@ -200,12 +187,13 @@ function useAutocomplete({
200
187
  const listBoxId = isExpanded ? `components-autocomplete-listbox-${instanceId}` : void 0;
201
188
  const activeId = isExpanded ? `components-autocomplete-item-${instanceId}-${selectedKey}` : null;
202
189
  const hasSelection = record.start !== void 0;
203
- const showPopover = !!textContent && hasSelection && !!AutocompleterUI;
190
+ const showPopover = !!textContent && hasSelection && !!autocompleter;
204
191
  return {
205
192
  listBoxId,
206
193
  activeId,
207
194
  onKeyDown: withIgnoreIMEEvents(handleKeyDown),
208
195
  popover: showPopover && /* @__PURE__ */ _jsx(AutocompleterUI, {
196
+ autocompleter,
209
197
  className,
210
198
  filterValue,
211
199
  instanceId,
@@ -213,19 +201,26 @@ function useAutocomplete({
213
201
  selectedIndex,
214
202
  onChangeOptions,
215
203
  onSelect: select,
216
- value: record,
217
204
  contentRef,
218
- reset
219
- })
205
+ reset: () => dispatch({
206
+ type: "RESET"
207
+ })
208
+ }, autocompleter.name + autocompleter.triggerPrefix)
220
209
  };
221
210
  }
211
+ function recordValuesMatch(a, b) {
212
+ return a.text === b.text && a.start === b.start && a.end === b.end;
213
+ }
222
214
  function useLastDifferentValue(value) {
223
- const history = useRef(/* @__PURE__ */ new Set());
224
- history.current.add(value);
225
- if (history.current.size > 2) {
226
- history.current.delete(Array.from(history.current)[0]);
215
+ const history = useRef([]);
216
+ const lastEntry = history.current[history.current.length - 1];
217
+ if (!lastEntry || !recordValuesMatch(value, lastEntry)) {
218
+ history.current.push(value);
219
+ }
220
+ if (history.current.length > 2) {
221
+ history.current.shift();
227
222
  }
228
- return Array.from(history.current)[0];
223
+ return history.current[0];
229
224
  }
230
225
  function useAutocompleteProps(options) {
231
226
  const ref = useRef(null);
@@ -283,6 +278,7 @@ function Autocomplete({
283
278
  export {
284
279
  Autocomplete as default,
285
280
  useAutocomplete,
286
- useAutocompleteProps
281
+ useAutocompleteProps,
282
+ useLastDifferentValue
287
283
  };
288
284
  //# sourceMappingURL=index.mjs.map