@wordpress/components 32.5.0 → 32.5.2-next.v.202604091042.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 (117) hide show
  1. package/AGENTS.md +2 -2
  2. package/CHANGELOG.md +20 -0
  3. package/README.md +18 -4
  4. package/build/autocomplete/autocompleter-ui.cjs +75 -79
  5. package/build/autocomplete/autocompleter-ui.cjs.map +2 -2
  6. package/build/autocomplete/get-autocomplete-match.cjs +91 -0
  7. package/build/autocomplete/get-autocomplete-match.cjs.map +7 -0
  8. package/build/autocomplete/index.cjs +104 -107
  9. package/build/autocomplete/index.cjs.map +3 -3
  10. package/build/box-control/index.cjs +0 -8
  11. package/build/box-control/index.cjs.map +2 -2
  12. package/build/box-control/utils.cjs +1 -10
  13. package/build/box-control/utils.cjs.map +2 -2
  14. package/build/calendar/utils/use-localization-props.cjs +3 -2
  15. package/build/calendar/utils/use-localization-props.cjs.map +2 -2
  16. package/build/custom-select-control/index.cjs.map +3 -3
  17. package/build/custom-select-control-v2/custom-select.cjs +2 -2
  18. package/build/custom-select-control-v2/custom-select.cjs.map +2 -2
  19. package/build/custom-select-control-v2/index.cjs.map +3 -3
  20. package/build/sandbox/index.cjs +2 -2
  21. package/build/sandbox/index.cjs.map +2 -2
  22. package/build/validated-form-controls/control-with-error.cjs +12 -8
  23. package/build/validated-form-controls/control-with-error.cjs.map +2 -2
  24. package/build-module/autocomplete/autocompleter-ui.mjs +74 -78
  25. package/build-module/autocomplete/autocompleter-ui.mjs.map +2 -2
  26. package/build-module/autocomplete/get-autocomplete-match.mjs +56 -0
  27. package/build-module/autocomplete/get-autocomplete-match.mjs.map +7 -0
  28. package/build-module/autocomplete/index.mjs +103 -107
  29. package/build-module/autocomplete/index.mjs.map +3 -3
  30. package/build-module/box-control/index.mjs +1 -9
  31. package/build-module/box-control/index.mjs.map +2 -2
  32. package/build-module/box-control/utils.mjs +1 -9
  33. package/build-module/box-control/utils.mjs.map +2 -2
  34. package/build-module/calendar/utils/use-localization-props.mjs +3 -2
  35. package/build-module/calendar/utils/use-localization-props.mjs.map +2 -2
  36. package/build-module/custom-select-control/index.mjs +2 -2
  37. package/build-module/custom-select-control/index.mjs.map +2 -2
  38. package/build-module/custom-select-control-v2/custom-select.mjs +2 -2
  39. package/build-module/custom-select-control-v2/custom-select.mjs.map +2 -2
  40. package/build-module/custom-select-control-v2/index.mjs +2 -2
  41. package/build-module/custom-select-control-v2/index.mjs.map +2 -2
  42. package/build-module/sandbox/index.mjs +2 -2
  43. package/build-module/sandbox/index.mjs.map +2 -2
  44. package/build-module/validated-form-controls/control-with-error.mjs +12 -8
  45. package/build-module/validated-form-controls/control-with-error.mjs.map +2 -2
  46. package/build-style/style-rtl.css +0 -3
  47. package/build-style/style.css +0 -3
  48. package/build-types/autocomplete/autocompleter-ui.d.ts +2 -2
  49. package/build-types/autocomplete/autocompleter-ui.d.ts.map +1 -1
  50. package/build-types/autocomplete/get-autocomplete-match.d.ts +11 -0
  51. package/build-types/autocomplete/get-autocomplete-match.d.ts.map +1 -0
  52. package/build-types/autocomplete/index.d.ts +8 -0
  53. package/build-types/autocomplete/index.d.ts.map +1 -1
  54. package/build-types/autocomplete/test/get-autocomplete-match.d.ts +2 -0
  55. package/build-types/autocomplete/test/get-autocomplete-match.d.ts.map +1 -0
  56. package/build-types/autocomplete/types.d.ts +23 -9
  57. package/build-types/autocomplete/types.d.ts.map +1 -1
  58. package/build-types/box-control/index.d.ts.map +1 -1
  59. package/build-types/box-control/utils.d.ts +7 -16
  60. package/build-types/box-control/utils.d.ts.map +1 -1
  61. package/build-types/button/stories/index.story.d.ts +0 -1
  62. package/build-types/button/stories/index.story.d.ts.map +1 -1
  63. package/build-types/calendar/utils/use-localization-props.d.ts +3 -3
  64. package/build-types/calendar/utils/use-localization-props.d.ts.map +1 -1
  65. package/build-types/custom-gradient-picker/constants.d.ts +2 -2
  66. package/build-types/custom-select-control-v2/custom-select.d.ts +3 -3
  67. package/build-types/custom-select-control-v2/custom-select.d.ts.map +1 -1
  68. package/build-types/custom-select-control-v2/types.d.ts +1 -1
  69. package/build-types/custom-select-control-v2/types.d.ts.map +1 -1
  70. package/build-types/font-size-picker/constants.d.ts +2 -2
  71. package/build-types/font-size-picker/constants.d.ts.map +1 -1
  72. package/build-types/palette-edit/index.d.ts +1 -1
  73. package/build-types/validated-form-controls/control-with-error.d.ts.map +1 -1
  74. package/package.json +21 -21
  75. package/src/alignment-matrix-control/README.md +1 -1
  76. package/src/angle-picker-control/style.module.scss +1 -0
  77. package/src/autocomplete/README.md +2 -2
  78. package/src/autocomplete/autocompleter-ui.native.js +166 -173
  79. package/src/autocomplete/autocompleter-ui.tsx +114 -116
  80. package/src/autocomplete/get-autocomplete-match.ts +115 -0
  81. package/src/autocomplete/index.tsx +129 -208
  82. package/src/autocomplete/test/get-autocomplete-match.ts +338 -0
  83. package/src/autocomplete/test/index.tsx +112 -4
  84. package/src/autocomplete/types.ts +17 -10
  85. package/src/box-control/index.tsx +1 -19
  86. package/src/box-control/utils.ts +1 -19
  87. package/src/button/README.md +1 -1
  88. package/src/button/stories/index.story.tsx +0 -1
  89. package/src/button/style.scss +0 -6
  90. package/src/calendar/utils/use-localization-props.ts +3 -4
  91. package/src/custom-select-control/index.tsx +3 -3
  92. package/src/custom-select-control-v2/custom-select.tsx +4 -4
  93. package/src/custom-select-control-v2/index.tsx +2 -2
  94. package/src/custom-select-control-v2/types.ts +1 -1
  95. package/src/divider/README.md +5 -6
  96. package/src/flex/stories/index.story.tsx +1 -1
  97. package/src/form-file-upload/README.md +3 -3
  98. package/src/gradient-picker/README.md +2 -2
  99. package/src/h-stack/README.md +10 -15
  100. package/src/h-stack/stories/index.story.tsx +2 -2
  101. package/src/heading/stories/index.story.tsx +1 -1
  102. package/src/higher-order/with-focus-outside/index.native.js +21 -20
  103. package/src/icon/README.md +1 -1
  104. package/src/menu/README.md +2 -2
  105. package/src/mobile/utils/get-px-from-css-unit.native.js +1 -1
  106. package/src/sandbox/index.native.js +2 -2
  107. package/src/sandbox/index.tsx +2 -2
  108. package/src/tabs/README.md +6 -6
  109. package/src/text/stories/index.story.tsx +1 -1
  110. package/src/toolbar/toolbar-button/toolbar-button-container.native.js +3 -1
  111. package/src/tree-select/README.md +1 -1
  112. package/src/v-stack/README.md +10 -15
  113. package/src/v-stack/stories/index.story.tsx +2 -2
  114. package/src/validated-form-controls/control-with-error.tsx +17 -12
  115. package/src/validated-form-controls/test/control-with-error.tsx +28 -1
  116. package/src/view/README.md +2 -5
  117. package/src/button/stories/style.css +0 -8
@@ -34,185 +34,178 @@ import { __unstableAutocompletionItemsFill as AutocompletionItemsFill } from '..
34
34
 
35
35
  const { compose: stylesCompose } = StyleSheet;
36
36
 
37
- export function getAutoCompleterUI( autocompleter ) {
37
+ export function AutocompleterUI( {
38
+ autocompleter,
39
+ filterValue,
40
+ selectedIndex,
41
+ onChangeOptions,
42
+ onSelect,
43
+ reset,
44
+ } ) {
45
+ // The useItems hook is derived from the autocompleter prop. This is safe
46
+ // because the parent renders this component with a key that triggers
47
+ // remount when the completer changes.
38
48
  const useItems = autocompleter.useItems
39
49
  ? autocompleter.useItems
40
50
  : getDefaultUseItems( autocompleter );
51
+ const [ items ] = useItems( filterValue );
52
+ const filteredItems = items.filter( ( item ) => ! item.isDisabled );
53
+ const scrollViewRef = useRef();
54
+ const animationValue = useRef( new Animated.Value( 0 ) ).current;
55
+ const [ isVisible, setIsVisible ] = useState( false );
56
+
57
+ useEffect( () => {
58
+ if ( ! isVisible && filterValue.length > 0 ) {
59
+ setIsVisible( true );
60
+ }
61
+ }, [ isVisible, filterValue ] );
41
62
 
42
- function AutocompleterUI( {
43
- filterValue,
44
- selectedIndex,
45
- onChangeOptions,
46
- onSelect,
47
- value,
48
- reset,
49
- } ) {
50
- const [ items ] = useItems( filterValue );
51
- const filteredItems = items.filter( ( item ) => ! item.isDisabled );
52
- const scrollViewRef = useRef();
53
- const animationValue = useRef( new Animated.Value( 0 ) ).current;
54
- const [ isVisible, setIsVisible ] = useState( false );
55
- const { text } = value;
56
-
57
- useEffect( () => {
58
- if ( ! isVisible && text.length > 0 ) {
59
- setIsVisible( true );
60
- }
61
- }, [ isVisible, text ] );
62
-
63
- useLayoutEffect( () => {
64
- onChangeOptions( items );
65
- scrollViewRef.current?.scrollTo( { x: 0, animated: false } );
66
-
67
- if ( isVisible && text.length > 0 ) {
68
- startAnimation( true );
69
- } else if ( isVisible && text.length === 0 ) {
70
- startAnimation( false );
71
- }
72
- // We want to avoid introducing unexpected side effects.
73
- // See https://github.com/WordPress/gutenberg/pull/41820
74
- }, [ items, isVisible, text ] );
75
-
76
- const activeItemStyles = usePreferredColorSchemeStyle(
77
- styles[ 'components-autocomplete__item-active' ],
78
- styles[ 'components-autocomplete__item-active-dark' ]
79
- );
80
-
81
- const iconStyles = usePreferredColorSchemeStyle(
82
- styles[ 'components-autocomplete__icon' ],
83
- styles[ 'components-autocomplete__icon-active-dark' ]
84
- );
85
-
86
- const activeIconStyles = usePreferredColorSchemeStyle(
87
- styles[ 'components-autocomplete__icon-active ' ],
88
- styles[ 'components-autocomplete__icon-active-dark' ]
89
- );
90
-
91
- const textStyles = usePreferredColorSchemeStyle(
92
- styles[ 'components-autocomplete__text' ],
93
- styles[ 'components-autocomplete__text-dark' ]
94
- );
95
-
96
- const activeTextStyles = usePreferredColorSchemeStyle(
97
- styles[ 'components-autocomplete__text-active' ],
98
- styles[ 'components-autocomplete__text-active-dark' ]
99
- );
100
-
101
- const startAnimation = useCallback(
102
- ( show ) => {
103
- Animated.timing( animationValue, {
104
- toValue: show ? 1 : 0,
105
- duration: show ? 200 : 100,
106
- useNativeDriver: true,
107
- } ).start( ( { finished } ) => {
108
- if ( finished && ! show && isVisible ) {
109
- setIsVisible( false );
110
- reset();
111
- }
112
- } );
113
- },
114
- // We want to avoid introducing unexpected side effects.
115
- // See https://github.com/WordPress/gutenberg/pull/41820
116
- [ isVisible ]
117
- );
118
-
119
- const contentStyles = {
120
- transform: [
121
- {
122
- translateY: animationValue.interpolate( {
123
- inputRange: [ 0, 1 ],
124
- outputRange: [
125
- styles[ 'components-autocomplete' ].height,
126
- 0,
127
- ],
128
- } ),
129
- },
130
- ],
131
- };
132
-
133
- if ( ! filteredItems.length > 0 || ! isVisible ) {
134
- return null;
63
+ useLayoutEffect( () => {
64
+ onChangeOptions( items );
65
+ scrollViewRef.current?.scrollTo( { x: 0, animated: false } );
66
+
67
+ if ( isVisible && filterValue.length > 0 ) {
68
+ startAnimation( true );
69
+ } else if ( isVisible && filterValue.length === 0 ) {
70
+ startAnimation( false );
135
71
  }
72
+ // We want to avoid introducing unexpected side effects.
73
+ // See https://github.com/WordPress/gutenberg/pull/41820
74
+ }, [ items, isVisible, filterValue ] );
75
+
76
+ const activeItemStyles = usePreferredColorSchemeStyle(
77
+ styles[ 'components-autocomplete__item-active' ],
78
+ styles[ 'components-autocomplete__item-active-dark' ]
79
+ );
80
+
81
+ const iconStyles = usePreferredColorSchemeStyle(
82
+ styles[ 'components-autocomplete__icon' ],
83
+ styles[ 'components-autocomplete__icon-active-dark' ]
84
+ );
85
+
86
+ const activeIconStyles = usePreferredColorSchemeStyle(
87
+ styles[ 'components-autocomplete__icon-active ' ],
88
+ styles[ 'components-autocomplete__icon-active-dark' ]
89
+ );
90
+
91
+ const textStyles = usePreferredColorSchemeStyle(
92
+ styles[ 'components-autocomplete__text' ],
93
+ styles[ 'components-autocomplete__text-dark' ]
94
+ );
95
+
96
+ const activeTextStyles = usePreferredColorSchemeStyle(
97
+ styles[ 'components-autocomplete__text-active' ],
98
+ styles[ 'components-autocomplete__text-active-dark' ]
99
+ );
100
+
101
+ const startAnimation = useCallback(
102
+ ( show ) => {
103
+ Animated.timing( animationValue, {
104
+ toValue: show ? 1 : 0,
105
+ duration: show ? 200 : 100,
106
+ useNativeDriver: true,
107
+ } ).start( ( { finished } ) => {
108
+ if ( finished && ! show && isVisible ) {
109
+ setIsVisible( false );
110
+ reset();
111
+ }
112
+ } );
113
+ },
114
+ // We want to avoid introducing unexpected side effects.
115
+ // See https://github.com/WordPress/gutenberg/pull/41820
116
+ [ isVisible ]
117
+ );
118
+
119
+ const contentStyles = {
120
+ transform: [
121
+ {
122
+ translateY: animationValue.interpolate( {
123
+ inputRange: [ 0, 1 ],
124
+ outputRange: [
125
+ styles[ 'components-autocomplete' ].height,
126
+ 0,
127
+ ],
128
+ } ),
129
+ },
130
+ ],
131
+ };
136
132
 
137
- return (
138
- <AutocompletionItemsFill>
139
- <View style={ styles[ 'components-autocomplete' ] }>
140
- <Animated.View style={ contentStyles }>
141
- <BackgroundView>
142
- <ScrollView
143
- testID="autocompleter"
144
- ref={ scrollViewRef }
145
- horizontal
146
- contentContainerStyle={
147
- styles[ 'components-autocomplete__content' ]
148
- }
149
- showsHorizontalScrollIndicator={ false }
150
- keyboardShouldPersistTaps="always"
151
- accessibilityLabel={
152
- // translators: Slash inserter autocomplete results
153
- __( 'Slash inserter results' )
154
- }
155
- >
156
- { filteredItems.map( ( option, index ) => {
157
- const isActive = index === selectedIndex;
158
- const itemStyle = stylesCompose(
159
- styles[
160
- 'components-autocomplete__item'
161
- ],
162
- isActive && activeItemStyles
163
- );
164
- const textStyle = stylesCompose(
165
- textStyles,
166
- isActive && activeTextStyles
167
- );
168
- const iconStyle = stylesCompose(
169
- iconStyles,
170
- isActive && activeIconStyles
171
- );
172
- const iconSource =
173
- option?.value?.icon?.src ||
174
- option?.value?.icon;
175
-
176
- return (
177
- <TouchableOpacity
178
- activeOpacity={ 0.5 }
179
- style={ itemStyle }
180
- key={ index }
181
- onPress={ () => onSelect( option ) }
182
- accessibilityLabel={ sprintf(
183
- // translators: %s: Block name e.g. "Image block"
184
- __( '%s block' ),
185
- option?.value?.title
186
- ) }
187
- >
188
- <View
189
- style={
190
- styles[
191
- 'components-autocomplete__icon'
192
- ]
193
- }
194
- >
195
- <Icon
196
- icon={ iconSource }
197
- size={ 24 }
198
- style={ iconStyle }
199
- />
200
- </View>
201
- <Text style={ textStyle }>
202
- { option?.value?.title }
203
- </Text>
204
- </TouchableOpacity>
205
- );
206
- } ) }
207
- </ScrollView>
208
- </BackgroundView>
209
- </Animated.View>
210
- </View>
211
- </AutocompletionItemsFill>
212
- );
133
+ if ( ! filteredItems.length > 0 || ! isVisible ) {
134
+ return null;
213
135
  }
214
136
 
215
- return AutocompleterUI;
137
+ return (
138
+ <AutocompletionItemsFill>
139
+ <View style={ styles[ 'components-autocomplete' ] }>
140
+ <Animated.View style={ contentStyles }>
141
+ <BackgroundView>
142
+ <ScrollView
143
+ testID="autocompleter"
144
+ ref={ scrollViewRef }
145
+ horizontal
146
+ contentContainerStyle={
147
+ styles[ 'components-autocomplete__content' ]
148
+ }
149
+ showsHorizontalScrollIndicator={ false }
150
+ keyboardShouldPersistTaps="always"
151
+ accessibilityLabel={
152
+ // translators: Slash inserter autocomplete results
153
+ __( 'Slash inserter results' )
154
+ }
155
+ >
156
+ { filteredItems.map( ( option, index ) => {
157
+ const isActive = index === selectedIndex;
158
+ const itemStyle = stylesCompose(
159
+ styles[ 'components-autocomplete__item' ],
160
+ isActive && activeItemStyles
161
+ );
162
+ const textStyle = stylesCompose(
163
+ textStyles,
164
+ isActive && activeTextStyles
165
+ );
166
+ const iconStyle = stylesCompose(
167
+ iconStyles,
168
+ isActive && activeIconStyles
169
+ );
170
+ const iconSource =
171
+ option?.value?.icon?.src ||
172
+ option?.value?.icon;
173
+
174
+ return (
175
+ <TouchableOpacity
176
+ activeOpacity={ 0.5 }
177
+ style={ itemStyle }
178
+ key={ index }
179
+ onPress={ () => onSelect( option ) }
180
+ accessibilityLabel={ sprintf(
181
+ // translators: %s: Block name e.g. "Image block"
182
+ __( '%s block' ),
183
+ option?.value?.title
184
+ ) }
185
+ >
186
+ <View
187
+ style={
188
+ styles[
189
+ 'components-autocomplete__icon'
190
+ ]
191
+ }
192
+ >
193
+ <Icon
194
+ icon={ iconSource }
195
+ size={ 24 }
196
+ style={ iconStyle }
197
+ />
198
+ </View>
199
+ <Text style={ textStyle }>
200
+ { option?.value?.title }
201
+ </Text>
202
+ </TouchableOpacity>
203
+ );
204
+ } ) }
205
+ </ScrollView>
206
+ </BackgroundView>
207
+ </Animated.View>
208
+ </View>
209
+ </AutocompletionItemsFill>
210
+ );
216
211
  }
217
-
218
- export default getAutoCompleterUI;
@@ -25,7 +25,7 @@ import getDefaultUseItems from './get-default-use-items';
25
25
  import Button from '../button';
26
26
  import Popover from '../popover';
27
27
  import { VisuallyHidden } from '../visually-hidden';
28
- import type { AutocompleterUIProps, KeyedOption, WPCompleter } from './types';
28
+ import type { AutocompleterUIProps, KeyedOption } from './types';
29
29
 
30
30
  type ListBoxProps = {
31
31
  items: KeyedOption[];
@@ -79,112 +79,125 @@ function ListBox( {
79
79
  );
80
80
  }
81
81
 
82
- export function getAutoCompleterUI( autocompleter: WPCompleter ) {
82
+ export function AutocompleterUI( {
83
+ autocompleter,
84
+ filterValue,
85
+ instanceId,
86
+ listBoxId,
87
+ className,
88
+ selectedIndex,
89
+ onChangeOptions,
90
+ onSelect,
91
+ reset,
92
+ contentRef,
93
+ }: AutocompleterUIProps ) {
94
+ // The useItems hook is derived from the autocompleter prop. This is safe
95
+ // because the parent renders this component with key={autocompleter.name},
96
+ // ensuring a fresh mount (and stable hook identity) when the completer changes.
83
97
  const useItems =
84
98
  autocompleter.useItems ?? getDefaultUseItems( autocompleter );
99
+ // eslint-disable-next-line react-compiler/react-compiler
100
+ const [ items ] = useItems( filterValue );
101
+ const popoverAnchor = useAnchor( {
102
+ editableContentElement: contentRef.current,
103
+ } );
104
+
105
+ const [ needsA11yCompat, setNeedsA11yCompat ] = useState( false );
106
+ const popoverRef = useRef< HTMLElement >( null );
107
+ const popoverRefs = useMergeRefs( [
108
+ popoverRef,
109
+ useRefEffect(
110
+ ( node ) => {
111
+ if ( ! contentRef.current ) {
112
+ return;
113
+ }
85
114
 
86
- function AutocompleterUI( {
87
- filterValue,
88
- instanceId,
89
- listBoxId,
90
- className,
91
- selectedIndex,
92
- onChangeOptions,
93
- onSelect,
94
- onReset,
95
- reset,
96
- contentRef,
97
- }: AutocompleterUIProps ) {
98
- const [ items ] = useItems( filterValue );
99
- const popoverAnchor = useAnchor( {
100
- editableContentElement: contentRef.current,
101
- } );
102
-
103
- const [ needsA11yCompat, setNeedsA11yCompat ] = useState( false );
104
- const popoverRef = useRef< HTMLElement >( null );
105
- const popoverRefs = useMergeRefs( [
106
- popoverRef,
107
- useRefEffect(
108
- ( node ) => {
109
- if ( ! contentRef.current ) {
110
- return;
111
- }
112
-
113
- // If the popover is rendered in a different document than
114
- // the content, we need to duplicate the options list in the
115
- // content document so that it's available to the screen
116
- // readers, which check the DOM ID based aria-* attributes.
117
- setNeedsA11yCompat(
118
- node.ownerDocument !== contentRef.current.ownerDocument
119
- );
120
- },
121
- [ contentRef ]
122
- ),
123
- ] );
124
-
125
- useOnClickOutside( popoverRef, reset );
126
-
127
- const debouncedSpeak = useDebounce( speak, 500 );
128
-
129
- function announce( options: Array< KeyedOption > ) {
130
- if ( ! debouncedSpeak ) {
131
- return;
132
- }
133
- if ( !! options.length ) {
134
- if ( filterValue ) {
135
- debouncedSpeak(
136
- sprintf(
137
- /* translators: %d: number of results. */
138
- _n(
139
- '%d result found, use up and down arrow keys to navigate.',
140
- '%d results found, use up and down arrow keys to navigate.',
141
- options.length
142
- ),
115
+ // If the popover is rendered in a different document than
116
+ // the content, we need to duplicate the options list in the
117
+ // content document so that it's available to the screen
118
+ // readers, which check the DOM ID based aria-* attributes.
119
+ setNeedsA11yCompat(
120
+ node.ownerDocument !== contentRef.current.ownerDocument
121
+ );
122
+ },
123
+ [ contentRef ]
124
+ ),
125
+ ] );
126
+
127
+ useOnClickOutside( popoverRef, reset );
128
+
129
+ const debouncedSpeak = useDebounce( speak, 500 );
130
+
131
+ function announce( options: Array< KeyedOption > ) {
132
+ if ( ! debouncedSpeak ) {
133
+ return;
134
+ }
135
+ if ( !! options.length ) {
136
+ if ( filterValue ) {
137
+ debouncedSpeak(
138
+ sprintf(
139
+ /* translators: %d: number of results. */
140
+ _n(
141
+ '%d result found, use up and down arrow keys to navigate.',
142
+ '%d results found, use up and down arrow keys to navigate.',
143
143
  options.length
144
144
  ),
145
- 'assertive'
146
- );
147
- } else {
148
- debouncedSpeak(
149
- sprintf(
150
- /* translators: %d: number of results. */
151
- _n(
152
- 'Initial %d result loaded. Type to filter all available results. Use up and down arrow keys to navigate.',
153
- 'Initial %d results loaded. Type to filter all available results. Use up and down arrow keys to navigate.',
154
- options.length
155
- ),
145
+ options.length
146
+ ),
147
+ 'assertive'
148
+ );
149
+ } else {
150
+ debouncedSpeak(
151
+ sprintf(
152
+ /* translators: %d: number of results. */
153
+ _n(
154
+ 'Initial %d result loaded. Type to filter all available results. Use up and down arrow keys to navigate.',
155
+ 'Initial %d results loaded. Type to filter all available results. Use up and down arrow keys to navigate.',
156
156
  options.length
157
157
  ),
158
- 'assertive'
159
- );
160
- }
161
- } else {
162
- debouncedSpeak( __( 'No results.' ), 'assertive' );
158
+ options.length
159
+ ),
160
+ 'assertive'
161
+ );
163
162
  }
163
+ } else {
164
+ debouncedSpeak( __( 'No results.' ), 'assertive' );
164
165
  }
166
+ }
165
167
 
166
- useLayoutEffect( () => {
167
- onChangeOptions( items );
168
- announce( items );
169
- // We want to avoid introducing unexpected side effects.
170
- // See https://github.com/WordPress/gutenberg/pull/41820
171
- }, [ items ] );
168
+ useLayoutEffect( () => {
169
+ onChangeOptions( items );
170
+ announce( items );
171
+ // We want to avoid introducing unexpected side effects.
172
+ // See https://github.com/WordPress/gutenberg/pull/41820
173
+ }, [ items ] );
172
174
 
173
- if ( items.length === 0 ) {
174
- return null;
175
- }
175
+ if ( items.length === 0 ) {
176
+ return null;
177
+ }
176
178
 
177
- return (
178
- <>
179
- <Popover
180
- offset={ 8 }
181
- focusOnMount={ false }
182
- onClose={ onReset }
183
- placement="top-start"
184
- className="components-autocomplete__popover"
185
- anchor={ popoverAnchor }
186
- ref={ popoverRefs }
187
- >
179
+ return (
180
+ <>
181
+ <Popover
182
+ offset={ 8 }
183
+ focusOnMount={ false }
184
+ placement="top-start"
185
+ className="components-autocomplete__popover"
186
+ anchor={ popoverAnchor }
187
+ ref={ popoverRefs }
188
+ >
189
+ <ListBox
190
+ items={ items }
191
+ onSelect={ onSelect }
192
+ selectedIndex={ selectedIndex }
193
+ instanceId={ instanceId }
194
+ listBoxId={ listBoxId }
195
+ className={ className }
196
+ />
197
+ </Popover>
198
+ { contentRef.current &&
199
+ needsA11yCompat &&
200
+ createPortal(
188
201
  <ListBox
189
202
  items={ items }
190
203
  onSelect={ onSelect }
@@ -192,27 +205,12 @@ export function getAutoCompleterUI( autocompleter: WPCompleter ) {
192
205
  instanceId={ instanceId }
193
206
  listBoxId={ listBoxId }
194
207
  className={ className }
195
- />
196
- </Popover>
197
- { contentRef.current &&
198
- needsA11yCompat &&
199
- createPortal(
200
- <ListBox
201
- items={ items }
202
- onSelect={ onSelect }
203
- selectedIndex={ selectedIndex }
204
- instanceId={ instanceId }
205
- listBoxId={ listBoxId }
206
- className={ className }
207
- Component={ VisuallyHidden }
208
- />,
209
- contentRef.current.ownerDocument.body
210
- ) }
211
- </>
212
- );
213
- }
214
-
215
- return AutocompleterUI;
208
+ Component={ VisuallyHidden }
209
+ />,
210
+ contentRef.current.ownerDocument.body
211
+ ) }
212
+ </>
213
+ );
216
214
  }
217
215
 
218
216
  function useOnClickOutside(