@wordpress/components 25.3.0 → 25.5.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 (190) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/build/border-control/border-control-dropdown/component.js +8 -10
  3. package/build/border-control/border-control-dropdown/component.js.map +1 -1
  4. package/build/button/index.native.js +9 -6
  5. package/build/button/index.native.js.map +1 -1
  6. package/build/color-palette/index.js +2 -2
  7. package/build/color-palette/index.js.map +1 -1
  8. package/build/focal-point-picker/index.native.js +6 -4
  9. package/build/focal-point-picker/index.native.js.map +1 -1
  10. package/build/form-token-field/styles.js +4 -2
  11. package/build/form-token-field/styles.js.map +1 -1
  12. package/build/item-group/item/hook.js +1 -1
  13. package/build/item-group/item/hook.js.map +1 -1
  14. package/build/item-group/styles.js +13 -10
  15. package/build/item-group/styles.js.map +1 -1
  16. package/build/menu-items-choice/index.js +1 -0
  17. package/build/menu-items-choice/index.js.map +1 -1
  18. package/build/mobile/bottom-sheet/bottom-sheet-navigation/bottom-sheet-navigation-context.native.js +3 -1
  19. package/build/mobile/bottom-sheet/bottom-sheet-navigation/bottom-sheet-navigation-context.native.js.map +1 -1
  20. package/build/mobile/bottom-sheet/bottom-sheet-navigation/navigation-container.native.js +50 -44
  21. package/build/mobile/bottom-sheet/bottom-sheet-navigation/navigation-container.native.js.map +1 -1
  22. package/build/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js +13 -20
  23. package/build/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js.map +1 -1
  24. package/build/mobile/bottom-sheet/index.native.js +3 -1
  25. package/build/mobile/bottom-sheet/index.native.js.map +1 -1
  26. package/build/mobile/image/index.native.js +4 -3
  27. package/build/mobile/image/index.native.js.map +1 -1
  28. package/build/mobile/link-picker/link-picker-results.native.js +2 -1
  29. package/build/mobile/link-picker/link-picker-results.native.js.map +1 -1
  30. package/build/mobile/segmented-control/index.native.js +7 -7
  31. package/build/mobile/segmented-control/index.native.js.map +1 -1
  32. package/build/modal/index.js +14 -1
  33. package/build/modal/index.js.map +1 -1
  34. package/build/navigator/navigator-provider/component.js +18 -10
  35. package/build/navigator/navigator-provider/component.js.map +1 -1
  36. package/build/private-apis.js +4 -1
  37. package/build/private-apis.js.map +1 -1
  38. package/build/progress-bar/index.js +54 -0
  39. package/build/progress-bar/index.js.map +1 -0
  40. package/build/progress-bar/styles.js +69 -0
  41. package/build/progress-bar/styles.js.map +1 -0
  42. package/build/progress-bar/types.js +6 -0
  43. package/build/progress-bar/types.js.map +1 -0
  44. package/build/query-controls/index.js +1 -0
  45. package/build/query-controls/index.js.map +1 -1
  46. package/build/query-controls/index.native.js +1 -0
  47. package/build/query-controls/index.native.js.map +1 -1
  48. package/build/tab-panel/index.js +91 -58
  49. package/build/tab-panel/index.js.map +1 -1
  50. package/build/text-control/index.js +2 -2
  51. package/build/text-control/index.js.map +1 -1
  52. package/build/toolbar/toolbar-group/toolbar-group-container.native.js +10 -7
  53. package/build/toolbar/toolbar-group/toolbar-group-container.native.js.map +1 -1
  54. package/build-module/border-control/border-control-dropdown/component.js +8 -10
  55. package/build-module/border-control/border-control-dropdown/component.js.map +1 -1
  56. package/build-module/button/index.native.js +8 -6
  57. package/build-module/button/index.native.js.map +1 -1
  58. package/build-module/color-palette/index.js +2 -2
  59. package/build-module/color-palette/index.js.map +1 -1
  60. package/build-module/focal-point-picker/index.native.js +6 -5
  61. package/build-module/focal-point-picker/index.native.js.map +1 -1
  62. package/build-module/form-token-field/styles.js +3 -2
  63. package/build-module/form-token-field/styles.js.map +1 -1
  64. package/build-module/item-group/item/hook.js +1 -1
  65. package/build-module/item-group/item/hook.js.map +1 -1
  66. package/build-module/item-group/styles.js +13 -11
  67. package/build-module/item-group/styles.js.map +1 -1
  68. package/build-module/menu-items-choice/index.js +1 -0
  69. package/build-module/menu-items-choice/index.js.map +1 -1
  70. package/build-module/mobile/bottom-sheet/bottom-sheet-navigation/bottom-sheet-navigation-context.native.js +3 -1
  71. package/build-module/mobile/bottom-sheet/bottom-sheet-navigation/bottom-sheet-navigation-context.native.js.map +1 -1
  72. package/build-module/mobile/bottom-sheet/bottom-sheet-navigation/navigation-container.native.js +43 -41
  73. package/build-module/mobile/bottom-sheet/bottom-sheet-navigation/navigation-container.native.js.map +1 -1
  74. package/build-module/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js +14 -20
  75. package/build-module/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js.map +1 -1
  76. package/build-module/mobile/bottom-sheet/index.native.js +3 -1
  77. package/build-module/mobile/bottom-sheet/index.native.js.map +1 -1
  78. package/build-module/mobile/image/index.native.js +4 -3
  79. package/build-module/mobile/image/index.native.js.map +1 -1
  80. package/build-module/mobile/link-picker/link-picker-results.native.js +2 -1
  81. package/build-module/mobile/link-picker/link-picker-results.native.js.map +1 -1
  82. package/build-module/mobile/segmented-control/index.native.js +7 -7
  83. package/build-module/mobile/segmented-control/index.native.js.map +1 -1
  84. package/build-module/modal/index.js +14 -1
  85. package/build-module/modal/index.js.map +1 -1
  86. package/build-module/navigator/navigator-provider/component.js +18 -10
  87. package/build-module/navigator/navigator-provider/component.js.map +1 -1
  88. package/build-module/private-apis.js +3 -1
  89. package/build-module/private-apis.js.map +1 -1
  90. package/build-module/progress-bar/index.js +41 -0
  91. package/build-module/progress-bar/index.js.map +1 -0
  92. package/build-module/progress-bar/styles.js +61 -0
  93. package/build-module/progress-bar/styles.js.map +1 -0
  94. package/build-module/progress-bar/types.js +2 -0
  95. package/build-module/progress-bar/types.js.map +1 -0
  96. package/build-module/query-controls/index.js +1 -0
  97. package/build-module/query-controls/index.js.map +1 -1
  98. package/build-module/query-controls/index.native.js +1 -0
  99. package/build-module/query-controls/index.native.js.map +1 -1
  100. package/build-module/tab-panel/index.js +88 -59
  101. package/build-module/tab-panel/index.js.map +1 -1
  102. package/build-module/text-control/index.js +2 -2
  103. package/build-module/text-control/index.js.map +1 -1
  104. package/build-module/toolbar/toolbar-group/toolbar-group-container.native.js +11 -7
  105. package/build-module/toolbar/toolbar-group/toolbar-group-container.native.js.map +1 -1
  106. package/build-style/style-rtl.css +3 -0
  107. package/build-style/style.css +3 -0
  108. package/build-types/border-control/border-control-dropdown/component.d.ts.map +1 -1
  109. package/build-types/form-token-field/styles.d.ts.map +1 -1
  110. package/build-types/item-group/item/hook.d.ts.map +1 -1
  111. package/build-types/item-group/stories/index.d.ts.map +1 -1
  112. package/build-types/item-group/styles.d.ts +1 -1
  113. package/build-types/item-group/styles.d.ts.map +1 -1
  114. package/build-types/menu-items-choice/index.d.ts.map +1 -1
  115. package/build-types/menu-items-choice/types.d.ts +5 -0
  116. package/build-types/menu-items-choice/types.d.ts.map +1 -1
  117. package/build-types/modal/index.d.ts.map +1 -1
  118. package/build-types/navigator/navigator-provider/component.d.ts.map +1 -1
  119. package/build-types/navigator/types.d.ts +3 -1
  120. package/build-types/navigator/types.d.ts.map +1 -1
  121. package/build-types/private-apis.d.ts.map +1 -1
  122. package/build-types/progress-bar/index.d.ts +5 -0
  123. package/build-types/progress-bar/index.d.ts.map +1 -0
  124. package/build-types/progress-bar/stories/index.d.ts +12 -0
  125. package/build-types/progress-bar/stories/index.d.ts.map +1 -0
  126. package/build-types/progress-bar/styles.d.ts +18 -0
  127. package/build-types/progress-bar/styles.d.ts.map +1 -0
  128. package/build-types/progress-bar/test/index.d.ts +2 -0
  129. package/build-types/progress-bar/test/index.d.ts.map +1 -0
  130. package/build-types/progress-bar/types.d.ts +11 -0
  131. package/build-types/progress-bar/types.d.ts.map +1 -0
  132. package/build-types/query-controls/index.d.ts.map +1 -1
  133. package/build-types/tab-panel/index.d.ts.map +1 -1
  134. package/build-types/tab-panel/stories/index.d.ts +1 -0
  135. package/build-types/tab-panel/stories/index.d.ts.map +1 -1
  136. package/build-types/tab-panel/types.d.ts +1 -9
  137. package/build-types/tab-panel/types.d.ts.map +1 -1
  138. package/build-types/text-control/test/text-control.d.ts +2 -0
  139. package/build-types/text-control/test/text-control.d.ts.map +1 -0
  140. package/package.json +22 -22
  141. package/src/border-control/border-control-dropdown/component.tsx +7 -11
  142. package/src/border-control/test/index.js +6 -6
  143. package/src/button/index.native.js +9 -3
  144. package/src/button/style.native.scss +9 -0
  145. package/src/color-palette/index.tsx +2 -2
  146. package/src/color-palette/test/__snapshots__/index.tsx.snap +1 -1
  147. package/src/color-palette/test/index.tsx +1 -5
  148. package/src/draggable/test/index.native.js +4 -0
  149. package/src/focal-point-picker/index.native.js +6 -5
  150. package/src/form-token-field/styles.ts +2 -0
  151. package/src/item-group/item/hook.ts +2 -1
  152. package/src/item-group/stories/index.tsx +8 -3
  153. package/src/item-group/styles.ts +39 -28
  154. package/src/menu-item/README.md +7 -0
  155. package/src/menu-items-choice/index.tsx +1 -0
  156. package/src/menu-items-choice/types.ts +5 -0
  157. package/src/mobile/bottom-sheet/bottom-sheet-navigation/bottom-sheet-navigation-context.native.js +1 -1
  158. package/src/mobile/bottom-sheet/bottom-sheet-navigation/navigation-container.native.js +72 -53
  159. package/src/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js +15 -21
  160. package/src/mobile/bottom-sheet/bottom-sheet-navigation/test/navigation-container.native.js +165 -119
  161. package/src/mobile/bottom-sheet/index.native.js +2 -0
  162. package/src/mobile/image/index.native.js +8 -6
  163. package/src/mobile/image/style.native.scss +5 -1
  164. package/src/mobile/link-picker/link-picker-results.native.js +1 -1
  165. package/src/mobile/link-settings/test/edit.native.js +37 -23
  166. package/src/mobile/segmented-control/index.native.js +11 -11
  167. package/src/modal/index.tsx +16 -0
  168. package/src/modal/test/index.tsx +33 -0
  169. package/src/navigator/navigator-provider/component.tsx +30 -23
  170. package/src/navigator/types.ts +4 -1
  171. package/src/placeholder/style.scss +5 -0
  172. package/src/private-apis.ts +2 -0
  173. package/src/progress-bar/README.md +30 -0
  174. package/src/progress-bar/index.tsx +45 -0
  175. package/src/progress-bar/stories/index.tsx +33 -0
  176. package/src/progress-bar/styles.ts +67 -0
  177. package/src/progress-bar/test/index.tsx +79 -0
  178. package/src/progress-bar/types.ts +11 -0
  179. package/src/query-controls/index.native.js +1 -0
  180. package/src/query-controls/index.tsx +1 -0
  181. package/src/tab-panel/index.tsx +121 -84
  182. package/src/tab-panel/stories/index.tsx +6 -0
  183. package/src/tab-panel/test/index.tsx +128 -109
  184. package/src/tab-panel/types.ts +1 -10
  185. package/src/text-control/index.tsx +2 -2
  186. package/src/text-control/test/text-control.tsx +61 -0
  187. package/src/toolbar/toolbar-group/style.native.scss +2 -3
  188. package/src/toolbar/toolbar-group/toolbar-group-container.native.js +12 -17
  189. package/src/tooltip/README.md +1 -1
  190. package/tsconfig.tsbuildinfo +1 -1
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
+ import * as Ariakit from '@ariakit/react';
4
5
  import classnames from 'classnames';
5
6
  import type { ForwardedRef } from 'react';
6
7
 
@@ -9,38 +10,30 @@ import type { ForwardedRef } from 'react';
9
10
  */
10
11
  import {
11
12
  forwardRef,
12
- useState,
13
13
  useEffect,
14
14
  useLayoutEffect,
15
15
  useCallback,
16
16
  } from '@wordpress/element';
17
- import { useInstanceId } from '@wordpress/compose';
17
+ import { useInstanceId, usePrevious } from '@wordpress/compose';
18
18
 
19
19
  /**
20
20
  * Internal dependencies
21
21
  */
22
- import { NavigableMenu } from '../navigable-container';
22
+
23
23
  import Button from '../button';
24
- import type { TabButtonProps, TabPanelProps } from './types';
24
+ import type { TabPanelProps } from './types';
25
25
  import type { WordPressComponentProps } from '../ui/context';
26
26
 
27
- const TabButton = ( {
28
- tabId,
29
- children,
30
- selected,
31
- ...rest
32
- }: TabButtonProps ) => (
33
- <Button
34
- role="tab"
35
- tabIndex={ selected ? undefined : -1 }
36
- aria-selected={ selected }
37
- id={ tabId }
38
- __experimentalIsFocusable
39
- { ...rest }
40
- >
41
- { children }
42
- </Button>
43
- );
27
+ // Separate the actual tab name from the instance ID. This is
28
+ // necessary because Ariakit internally uses the element ID when
29
+ // a new tab is selected, but our implementation looks specifically
30
+ // for the tab name to be passed to the `onSelect` callback.
31
+ const extractTabName = ( id: string | undefined | null ) => {
32
+ if ( typeof id === 'undefined' || id === null ) {
33
+ return;
34
+ }
35
+ return id.match( /^tab-panel-[0-9]*-(.*)/ )?.[ 1 ];
36
+ };
44
37
 
45
38
  /**
46
39
  * TabPanel is an ARIA-compliant tabpanel.
@@ -92,26 +85,65 @@ const UnforwardedTabPanel = (
92
85
  ref: ForwardedRef< any >
93
86
  ) => {
94
87
  const instanceId = useInstanceId( TabPanel, 'tab-panel' );
95
- const [ selected, setSelected ] = useState< string >();
96
88
 
97
- const handleTabSelection = useCallback(
98
- ( tabKey: string ) => {
99
- setSelected( tabKey );
100
- onSelect?.( tabKey );
89
+ const prependInstanceId = useCallback(
90
+ ( tabName: string | undefined ) => {
91
+ if ( typeof tabName === 'undefined' ) {
92
+ return;
93
+ }
94
+ return `${ instanceId }-${ tabName }`;
95
+ },
96
+ [ instanceId ]
97
+ );
98
+
99
+ const tabStore = Ariakit.useTabStore( {
100
+ setSelectedId: ( newTabValue ) => {
101
+ if ( typeof newTabValue === 'undefined' || newTabValue === null ) {
102
+ return;
103
+ }
104
+
105
+ const newTab = tabs.find(
106
+ ( t ) => prependInstanceId( t.name ) === newTabValue
107
+ );
108
+ if ( newTab?.disabled || newTab === selectedTab ) {
109
+ return;
110
+ }
111
+
112
+ const simplifiedTabName = extractTabName( newTabValue );
113
+ if ( typeof simplifiedTabName === 'undefined' ) {
114
+ return;
115
+ }
116
+
117
+ onSelect?.( simplifiedTabName );
118
+ },
119
+ orientation,
120
+ selectOnMove,
121
+ defaultSelectedId: prependInstanceId( initialTabName ),
122
+ } );
123
+
124
+ const selectedTabName = extractTabName( tabStore.useState( 'selectedId' ) );
125
+
126
+ const setTabStoreSelectedId = useCallback(
127
+ ( tabName: string ) => {
128
+ tabStore.setState( 'selectedId', prependInstanceId( tabName ) );
101
129
  },
102
- [ onSelect ]
130
+ [ prependInstanceId, tabStore ]
103
131
  );
104
132
 
105
- // Simulate a click on the newly focused tab, which causes the component
106
- // to show the `tab-panel` associated with the clicked tab.
107
- const activateTabAutomatically = (
108
- _childIndex: number,
109
- child: HTMLElement
110
- ) => {
111
- child.click();
112
- };
113
- const selectedTab = tabs.find( ( { name } ) => name === selected );
114
- const selectedId = `${ instanceId }-${ selectedTab?.name ?? 'none' }`;
133
+ const selectedTab = tabs.find( ( { name } ) => name === selectedTabName );
134
+
135
+ const previousSelectedTabName = usePrevious( selectedTabName );
136
+
137
+ // Ensure `onSelect` is called when the initial tab is selected.
138
+ useEffect( () => {
139
+ if (
140
+ previousSelectedTabName !== selectedTabName &&
141
+ selectedTabName === initialTabName &&
142
+ !! selectedTabName
143
+ ) {
144
+ onSelect?.( selectedTabName );
145
+ }
146
+ }, [ selectedTabName, initialTabName, onSelect, previousSelectedTabName ] );
115
147
 
116
148
  // Handle selecting the initial tab.
117
149
  useLayoutEffect( () => {
@@ -119,25 +151,31 @@ const UnforwardedTabPanel = (
119
151
  if ( selectedTab ) {
120
152
  return;
121
153
  }
122
-
123
154
  const initialTab = tabs.find( ( tab ) => tab.name === initialTabName );
124
-
125
155
  // Wait for the denoted initial tab to be declared before making a
126
156
  // selection. This ensures that if a tab is declared lazily it can
127
157
  // still receive initial selection.
128
158
  if ( initialTabName && ! initialTab ) {
129
159
  return;
130
160
  }
131
-
132
161
  if ( initialTab && ! initialTab.disabled ) {
133
162
  // Select the initial tab if it's not disabled.
134
- handleTabSelection( initialTab.name );
163
+ setTabStoreSelectedId( initialTab.name );
135
164
  } else {
136
- // Fallback to the first enabled tab when the initial is disabled.
165
+ // Fallback to the first enabled tab when the initial tab is
166
+ // disabled or it can't be found.
137
167
  const firstEnabledTab = tabs.find( ( tab ) => ! tab.disabled );
138
- if ( firstEnabledTab ) handleTabSelection( firstEnabledTab.name );
168
+ if ( firstEnabledTab ) {
169
+ setTabStoreSelectedId( firstEnabledTab.name );
170
+ }
139
171
  }
140
- }, [ tabs, selectedTab, initialTabName, handleTabSelection ] );
172
+ }, [
173
+ tabs,
174
+ selectedTab,
175
+ initialTabName,
176
+ instanceId,
177
+ setTabStoreSelectedId,
178
+ ] );
141
179
 
142
180
  // Handle the currently selected tab becoming disabled.
143
181
  useEffect( () => {
@@ -145,59 +183,58 @@ const UnforwardedTabPanel = (
145
183
  if ( ! selectedTab?.disabled ) {
146
184
  return;
147
185
  }
148
-
149
186
  const firstEnabledTab = tabs.find( ( tab ) => ! tab.disabled );
150
-
151
187
  // If the currently selected tab becomes disabled, select the first enabled tab.
152
188
  // (if there is one).
153
189
  if ( firstEnabledTab ) {
154
- handleTabSelection( firstEnabledTab.name );
190
+ setTabStoreSelectedId( firstEnabledTab.name );
155
191
  }
156
- }, [ tabs, selectedTab?.disabled, handleTabSelection ] );
157
-
192
+ }, [ tabs, selectedTab?.disabled, setTabStoreSelectedId, instanceId ] );
158
193
  return (
159
194
  <div className={ className } ref={ ref }>
160
- <NavigableMenu
161
- role="tablist"
162
- orientation={ orientation }
163
- onNavigate={
164
- selectOnMove ? activateTabAutomatically : undefined
165
- }
195
+ <Ariakit.TabList
196
+ store={ tabStore }
166
197
  className="components-tab-panel__tabs"
167
198
  >
168
- { tabs.map( ( tab ) => (
169
- <TabButton
170
- className={ classnames(
171
- 'components-tab-panel__tabs-item',
172
- tab.className,
173
- {
174
- [ activeClass ]: tab.name === selected,
199
+ { tabs.map( ( tab ) => {
200
+ return (
201
+ <Ariakit.Tab
202
+ key={ tab.name }
203
+ id={ prependInstanceId( tab.name ) }
204
+ className={ classnames(
205
+ 'components-tab-panel__tabs-item',
206
+ tab.className,
207
+ {
208
+ [ activeClass ]:
209
+ tab.name === selectedTabName,
210
+ }
211
+ ) }
212
+ disabled={ tab.disabled }
213
+ aria-controls={ `${ prependInstanceId(
214
+ tab.name
215
+ ) }-view` }
216
+ render={
217
+ <Button
218
+ icon={ tab.icon }
219
+ label={ tab.icon && tab.title }
220
+ showTooltip={ !! tab.icon }
221
+ />
175
222
  }
176
- ) }
177
- tabId={ `${ instanceId }-${ tab.name }` }
178
- aria-controls={ `${ instanceId }-${ tab.name }-view` }
179
- selected={ tab.name === selected }
180
- key={ tab.name }
181
- onClick={ () => handleTabSelection( tab.name ) }
182
- disabled={ tab.disabled }
183
- label={ tab.icon && tab.title }
184
- icon={ tab.icon }
185
- showTooltip={ !! tab.icon }
186
- >
187
- { ! tab.icon && tab.title }
188
- </TabButton>
189
- ) ) }
190
- </NavigableMenu>
223
+ >
224
+ { ! tab.icon && tab.title }
225
+ </Ariakit.Tab>
226
+ );
227
+ } ) }
228
+ </Ariakit.TabList>
191
229
  { selectedTab && (
192
- <div
193
- key={ selectedId }
194
- aria-labelledby={ selectedId }
195
- role="tabpanel"
196
- id={ `${ selectedId }-view` }
197
- className="components-tab-panel__tab-content"
230
+ <Ariakit.TabPanel
231
+ id={ `${ prependInstanceId( selectedTab.name ) }-view` }
232
+ store={ tabStore }
233
+ tabId={ prependInstanceId( selectedTab.name ) }
234
+ className={ 'components-tab-panel__tab-content' }
198
235
  >
199
236
  { children( selectedTab ) }
200
- </div>
237
+ </Ariakit.TabPanel>
201
238
  ) }
202
239
  </div>
203
240
  );
@@ -96,3 +96,9 @@ WithTabIconsAndTooltips.args = {
96
96
  },
97
97
  ],
98
98
  };
99
+
100
+ export const ManualActivation = Template.bind( {} );
101
+ ManualActivation.args = {
102
+ ...Default.args,
103
+ selectOnMove: false,
104
+ };