@wordpress/components 27.1.0 → 27.3.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 (223) hide show
  1. package/CHANGELOG.md +53 -3
  2. package/README.md +13 -0
  3. package/build/button/index.js +3 -4
  4. package/build/button/index.js.map +1 -1
  5. package/build/button/types.js.map +1 -1
  6. package/build/color-picker/component.js +2 -12
  7. package/build/color-picker/component.js.map +1 -1
  8. package/build/color-picker/picker.js +18 -77
  9. package/build/color-picker/picker.js.map +1 -1
  10. package/build/color-picker/types.js.map +1 -1
  11. package/build/custom-select-control-v2/default-component/index.js +4 -2
  12. package/build/custom-select-control-v2/default-component/index.js.map +1 -1
  13. package/build/custom-select-control-v2/index.js +1 -8
  14. package/build/custom-select-control-v2/index.js.map +1 -1
  15. package/build/custom-select-control-v2/{custom-select-item.js → item.js} +2 -1
  16. package/build/custom-select-control-v2/{custom-select-item.js.map → item.js.map} +1 -1
  17. package/build/custom-select-control-v2/legacy-component/index.js +5 -5
  18. package/build/custom-select-control-v2/legacy-component/index.js.map +1 -1
  19. package/build/date-time/date/styles.js +7 -7
  20. package/build/date-time/date/styles.js.map +1 -1
  21. package/build/form-token-field/index.js +1 -1
  22. package/build/form-token-field/index.js.map +1 -1
  23. package/build/input-control/index.js +1 -1
  24. package/build/input-control/index.js.map +1 -1
  25. package/build/input-control/input-field.js +2 -1
  26. package/build/input-control/input-field.js.map +1 -1
  27. package/build/mobile/color-settings/palette.screen.native.js +1 -0
  28. package/build/mobile/color-settings/palette.screen.native.js.map +1 -1
  29. package/build/navigable-container/container.js.map +1 -1
  30. package/build/navigator/navigator-provider/component.js +162 -120
  31. package/build/navigator/navigator-provider/component.js.map +1 -1
  32. package/build/navigator/navigator-screen/component.js +2 -2
  33. package/build/navigator/navigator-screen/component.js.map +1 -1
  34. package/build/palette-edit/index.js +18 -12
  35. package/build/palette-edit/index.js.map +1 -1
  36. package/build/popover/index.js +7 -34
  37. package/build/popover/index.js.map +1 -1
  38. package/build/range-control/styles/range-control-styles.js +29 -29
  39. package/build/range-control/styles/range-control-styles.js.map +1 -1
  40. package/build/text-control/types.js.map +1 -1
  41. package/build/toggle-group-control/toggle-group-control-option-base/component.js +5 -2
  42. package/build/toggle-group-control/toggle-group-control-option-base/component.js.map +1 -1
  43. package/build/tools-panel/tools-panel-header/component.js +1 -1
  44. package/build/tools-panel/tools-panel-header/component.js.map +1 -1
  45. package/build/utils/config-values.js +1 -1
  46. package/build/utils/config-values.js.map +1 -1
  47. package/build/utils/input/base.js +2 -2
  48. package/build/utils/input/base.js.map +1 -1
  49. package/build-module/button/index.js +3 -4
  50. package/build-module/button/index.js.map +1 -1
  51. package/build-module/button/types.js.map +1 -1
  52. package/build-module/color-picker/component.js +3 -13
  53. package/build-module/color-picker/component.js.map +1 -1
  54. package/build-module/color-picker/picker.js +19 -78
  55. package/build-module/color-picker/picker.js.map +1 -1
  56. package/build-module/color-picker/types.js.map +1 -1
  57. package/build-module/custom-select-control-v2/default-component/index.js +4 -2
  58. package/build-module/custom-select-control-v2/default-component/index.js.map +1 -1
  59. package/build-module/custom-select-control-v2/index.js +1 -2
  60. package/build-module/custom-select-control-v2/index.js.map +1 -1
  61. package/build-module/custom-select-control-v2/{custom-select-item.js → item.js} +2 -1
  62. package/build-module/custom-select-control-v2/{custom-select-item.js.map → item.js.map} +1 -1
  63. package/build-module/custom-select-control-v2/legacy-component/index.js +4 -4
  64. package/build-module/custom-select-control-v2/legacy-component/index.js.map +1 -1
  65. package/build-module/date-time/date/styles.js +7 -7
  66. package/build-module/date-time/date/styles.js.map +1 -1
  67. package/build-module/form-token-field/index.js +1 -1
  68. package/build-module/form-token-field/index.js.map +1 -1
  69. package/build-module/input-control/index.js +1 -1
  70. package/build-module/input-control/index.js.map +1 -1
  71. package/build-module/input-control/input-field.js +2 -1
  72. package/build-module/input-control/input-field.js.map +1 -1
  73. package/build-module/mobile/color-settings/palette.screen.native.js +1 -0
  74. package/build-module/mobile/color-settings/palette.screen.native.js.map +1 -1
  75. package/build-module/navigable-container/container.js.map +1 -1
  76. package/build-module/navigator/navigator-provider/component.js +163 -121
  77. package/build-module/navigator/navigator-provider/component.js.map +1 -1
  78. package/build-module/navigator/navigator-screen/component.js +2 -2
  79. package/build-module/navigator/navigator-screen/component.js.map +1 -1
  80. package/build-module/palette-edit/index.js +17 -11
  81. package/build-module/palette-edit/index.js.map +1 -1
  82. package/build-module/popover/index.js +9 -36
  83. package/build-module/popover/index.js.map +1 -1
  84. package/build-module/range-control/styles/range-control-styles.js +29 -29
  85. package/build-module/range-control/styles/range-control-styles.js.map +1 -1
  86. package/build-module/text-control/types.js.map +1 -1
  87. package/build-module/toggle-group-control/toggle-group-control-option-base/component.js +6 -3
  88. package/build-module/toggle-group-control/toggle-group-control-option-base/component.js.map +1 -1
  89. package/build-module/tools-panel/tools-panel-header/component.js +1 -1
  90. package/build-module/tools-panel/tools-panel-header/component.js.map +1 -1
  91. package/build-module/utils/config-values.js +1 -1
  92. package/build-module/utils/config-values.js.map +1 -1
  93. package/build-module/utils/input/base.js +2 -2
  94. package/build-module/utils/input/base.js.map +1 -1
  95. package/build-style/style-rtl.css +26 -29
  96. package/build-style/style.css +26 -29
  97. package/build-types/box-control/styles/box-control-styles.d.ts +1 -1
  98. package/build-types/button/deprecated.d.ts +4 -10
  99. package/build-types/button/deprecated.d.ts.map +1 -1
  100. package/build-types/button/index.d.ts +3 -3
  101. package/build-types/button/index.d.ts.map +1 -1
  102. package/build-types/button/stories/e2e/index.story.d.ts +1 -1
  103. package/build-types/button/stories/e2e/index.story.d.ts.map +1 -1
  104. package/build-types/button/stories/index.story.d.ts +7 -7
  105. package/build-types/button/stories/index.story.d.ts.map +1 -1
  106. package/build-types/button/types.d.ts +37 -8
  107. package/build-types/button/types.d.ts.map +1 -1
  108. package/build-types/color-picker/component.d.ts.map +1 -1
  109. package/build-types/color-picker/picker.d.ts +1 -1
  110. package/build-types/color-picker/picker.d.ts.map +1 -1
  111. package/build-types/color-picker/styles.d.ts +1 -1
  112. package/build-types/color-picker/types.d.ts +0 -3
  113. package/build-types/color-picker/types.d.ts.map +1 -1
  114. package/build-types/custom-select-control/stories/index.story.d.ts +35 -0
  115. package/build-types/custom-select-control/stories/index.story.d.ts.map +1 -0
  116. package/build-types/custom-select-control-v2/default-component/index.d.ts +5 -2
  117. package/build-types/custom-select-control-v2/default-component/index.d.ts.map +1 -1
  118. package/build-types/custom-select-control-v2/index.d.ts +1 -2
  119. package/build-types/custom-select-control-v2/index.d.ts.map +1 -1
  120. package/build-types/custom-select-control-v2/{custom-select-item.d.ts → item.d.ts} +4 -1
  121. package/build-types/custom-select-control-v2/item.d.ts.map +1 -0
  122. package/build-types/custom-select-control-v2/legacy-component/index.d.ts +2 -2
  123. package/build-types/custom-select-control-v2/legacy-component/index.d.ts.map +1 -1
  124. package/build-types/custom-select-control-v2/stories/default.story.d.ts +2 -2
  125. package/build-types/custom-select-control-v2/stories/default.story.d.ts.map +1 -1
  126. package/build-types/custom-select-control-v2/stories/legacy.story.d.ts +4 -2
  127. package/build-types/custom-select-control-v2/stories/legacy.story.d.ts.map +1 -1
  128. package/build-types/date-time/date/styles.d.ts +1 -1
  129. package/build-types/dropdown/stories/index.story.d.ts +1 -0
  130. package/build-types/dropdown/stories/index.story.d.ts.map +1 -1
  131. package/build-types/font-size-picker/styles.d.ts +1 -1
  132. package/build-types/form-token-field/index.d.ts +1 -1
  133. package/build-types/input-control/index.d.ts +1 -1
  134. package/build-types/input-control/input-field.d.ts.map +1 -1
  135. package/build-types/input-control/stories/index.story.d.ts.map +1 -1
  136. package/build-types/navigation/styles/navigation-styles.d.ts +1 -1
  137. package/build-types/navigator/navigator-back-button/component.d.ts +0 -1
  138. package/build-types/navigator/navigator-back-button/component.d.ts.map +1 -1
  139. package/build-types/navigator/navigator-back-button/hook.d.ts +1 -2
  140. package/build-types/navigator/navigator-back-button/hook.d.ts.map +1 -1
  141. package/build-types/navigator/navigator-button/component.d.ts +0 -1
  142. package/build-types/navigator/navigator-button/component.d.ts.map +1 -1
  143. package/build-types/navigator/navigator-button/hook.d.ts +1 -2
  144. package/build-types/navigator/navigator-button/hook.d.ts.map +1 -1
  145. package/build-types/navigator/navigator-provider/component.d.ts.map +1 -1
  146. package/build-types/navigator/navigator-screen/component.d.ts.map +1 -1
  147. package/build-types/navigator/navigator-to-parent-button/component.d.ts +0 -1
  148. package/build-types/navigator/navigator-to-parent-button/component.d.ts.map +1 -1
  149. package/build-types/number-control/styles/number-control-styles.d.ts +1 -1
  150. package/build-types/palette-edit/index.d.ts +6 -3
  151. package/build-types/palette-edit/index.d.ts.map +1 -1
  152. package/build-types/palette-edit/styles.d.ts +2 -2
  153. package/build-types/popover/index.d.ts.map +1 -1
  154. package/build-types/text-control/index.d.ts +1 -1
  155. package/build-types/text-control/types.d.ts +1 -1
  156. package/build-types/text-control/types.d.ts.map +1 -1
  157. package/build-types/toggle-group-control/toggle-group-control-option-base/component.d.ts.map +1 -1
  158. package/build-types/toolbar/toolbar-button/index.d.ts +4 -10
  159. package/build-types/toolbar/toolbar-button/index.d.ts.map +1 -1
  160. package/package.json +21 -21
  161. package/src/button/index.tsx +3 -4
  162. package/src/button/test/index.tsx +6 -6
  163. package/src/button/types.ts +37 -9
  164. package/src/color-picker/component.tsx +3 -25
  165. package/src/color-picker/picker.tsx +12 -96
  166. package/src/color-picker/types.ts +0 -3
  167. package/src/confirm-dialog/README.md +7 -0
  168. package/src/custom-select-control/stories/{index.story.js → index.story.tsx} +8 -3
  169. package/src/custom-select-control/test/index.js +24 -0
  170. package/src/custom-select-control-v2/README.md +27 -27
  171. package/src/custom-select-control-v2/default-component/index.tsx +5 -2
  172. package/src/custom-select-control-v2/index.tsx +1 -2
  173. package/src/custom-select-control-v2/{custom-select-item.tsx → item.tsx} +2 -0
  174. package/src/custom-select-control-v2/legacy-component/index.tsx +4 -6
  175. package/src/custom-select-control-v2/legacy-component/test/index.tsx +13 -10
  176. package/src/custom-select-control-v2/stories/default.story.tsx +16 -17
  177. package/src/custom-select-control-v2/stories/legacy.story.tsx +20 -35
  178. package/src/custom-select-control-v2/test/index.tsx +26 -16
  179. package/src/date-time/date/styles.ts +2 -2
  180. package/src/dimension-control/test/__snapshots__/index.test.js.snap +4 -4
  181. package/src/dropdown/stories/index.story.tsx +19 -0
  182. package/src/dropdown/style.scss +26 -0
  183. package/src/dropdown-menu/style.scss +0 -25
  184. package/src/flex/flex/README.md +2 -2
  185. package/src/form-token-field/README.md +1 -1
  186. package/src/form-token-field/index.tsx +1 -1
  187. package/src/grid/README.md +11 -11
  188. package/src/h-stack/README.md +6 -6
  189. package/src/heading/README.md +1 -1
  190. package/src/heading/test/__snapshots__/index.tsx.snap +3 -3
  191. package/src/input-control/README.md +1 -1
  192. package/src/input-control/index.tsx +1 -1
  193. package/src/input-control/input-field.tsx +2 -1
  194. package/src/input-control/stories/index.story.tsx +1 -0
  195. package/src/item-group/test/__snapshots__/index.js.snap +11 -11
  196. package/src/mobile/bottom-sheet-select-control/README.md +1 -1
  197. package/src/mobile/color-settings/palette.screen.native.js +5 -1
  198. package/src/navigable-container/container.tsx +1 -1
  199. package/src/navigator/navigator-provider/component.tsx +187 -188
  200. package/src/navigator/navigator-screen/component.tsx +2 -4
  201. package/src/palette-edit/index.tsx +21 -21
  202. package/src/palette-edit/test/index.tsx +21 -17
  203. package/src/placeholder/style.scss +5 -1
  204. package/src/popover/index.tsx +59 -99
  205. package/src/popover/style.scss +0 -9
  206. package/src/progress-bar/README.md +1 -1
  207. package/src/radio-control/README.md +3 -3
  208. package/src/range-control/styles/range-control-styles.ts +1 -1
  209. package/src/resizable-box/resize-tooltip/README.md +2 -2
  210. package/src/text/test/__snapshots__/index.tsx.snap +3 -3
  211. package/src/text-control/style.scss +2 -0
  212. package/src/text-control/types.ts +12 -1
  213. package/src/toggle-group-control/test/__snapshots__/index.tsx.snap +14 -10
  214. package/src/toggle-group-control/toggle-group-control-option-base/component.tsx +14 -12
  215. package/src/toolbar/toolbar/style.scss +1 -1
  216. package/src/tools-panel/tools-panel-header/component.tsx +1 -1
  217. package/src/truncate/README.md +5 -5
  218. package/src/utils/config-values.js +1 -1
  219. package/src/utils/input/base.js +1 -1
  220. package/src/v-stack/README.md +6 -6
  221. package/tsconfig.json +1 -0
  222. package/tsconfig.tsbuildinfo +1 -1
  223. package/build-types/custom-select-control-v2/custom-select-item.d.ts.map +0 -1
@@ -6,14 +6,7 @@ import type { ForwardedRef } from 'react';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
- import {
10
- useMemo,
11
- useState,
12
- useCallback,
13
- useReducer,
14
- useRef,
15
- useEffect,
16
- } from '@wordpress/element';
9
+ import { useMemo, useReducer } from '@wordpress/element';
17
10
  import isShallowEqual from '@wordpress/is-shallow-equal';
18
11
 
19
12
  /**
@@ -30,26 +23,178 @@ import type {
30
23
  NavigatorProviderProps,
31
24
  NavigatorLocation,
32
25
  NavigatorContext as NavigatorContextType,
26
+ NavigateOptions,
33
27
  Screen,
28
+ NavigateToParentOptions,
34
29
  } from '../types';
35
30
 
36
31
  type MatchedPath = ReturnType< typeof patternMatch >;
37
- type ScreenAction = { type: string; screen: Screen };
32
+
33
+ type RouterAction =
34
+ | { type: 'add' | 'remove'; screen: Screen }
35
+ | { type: 'goback' }
36
+ | { type: 'goto'; path: string; options?: NavigateOptions }
37
+ | { type: 'gotoparent'; options?: NavigateToParentOptions };
38
+
39
+ type RouterState = {
40
+ screens: Screen[];
41
+ locationHistory: NavigatorLocation[];
42
+ matchedPath: MatchedPath;
43
+ };
38
44
 
39
45
  const MAX_HISTORY_LENGTH = 50;
40
46
 
41
- function screensReducer(
42
- state: Screen[] = [],
43
- action: ScreenAction
44
- ): Screen[] {
47
+ function addScreen( { screens }: RouterState, screen: Screen ) {
48
+ return [ ...screens, screen ];
49
+ }
50
+
51
+ function removeScreen( { screens }: RouterState, screen: Screen ) {
52
+ return screens.filter( ( s ) => s.id !== screen.id );
53
+ }
54
+
55
+ function goBack( { locationHistory }: RouterState ) {
56
+ if ( locationHistory.length <= 1 ) {
57
+ return locationHistory;
58
+ }
59
+ return [
60
+ ...locationHistory.slice( 0, -2 ),
61
+ {
62
+ ...locationHistory[ locationHistory.length - 2 ],
63
+ isBack: true,
64
+ hasRestoredFocus: false,
65
+ },
66
+ ];
67
+ }
68
+
69
+ function goTo(
70
+ state: RouterState,
71
+ path: string,
72
+ options: NavigateOptions = {}
73
+ ) {
74
+ const { locationHistory } = state;
75
+ const {
76
+ focusTargetSelector,
77
+ isBack = false,
78
+ skipFocus = false,
79
+ replace = false,
80
+ ...restOptions
81
+ } = options;
82
+
83
+ const isNavigatingToPreviousPath =
84
+ isBack &&
85
+ locationHistory.length > 1 &&
86
+ locationHistory[ locationHistory.length - 2 ].path === path;
87
+
88
+ if ( isNavigatingToPreviousPath ) {
89
+ return goBack( state );
90
+ }
91
+
92
+ const newLocation = {
93
+ ...restOptions,
94
+ path,
95
+ isBack,
96
+ hasRestoredFocus: false,
97
+ skipFocus,
98
+ };
99
+
100
+ if ( locationHistory.length === 0 ) {
101
+ return replace ? [] : [ newLocation ];
102
+ }
103
+
104
+ const newLocationHistory = locationHistory.slice(
105
+ locationHistory.length > MAX_HISTORY_LENGTH - 1 ? 1 : 0,
106
+ -1
107
+ );
108
+
109
+ if ( ! replace ) {
110
+ newLocationHistory.push(
111
+ // Assign `focusTargetSelector` to the previous location in history
112
+ // (the one we just navigated from).
113
+ {
114
+ ...locationHistory[ locationHistory.length - 1 ],
115
+ focusTargetSelector,
116
+ }
117
+ );
118
+ }
119
+
120
+ newLocationHistory.push( newLocation );
121
+
122
+ return newLocationHistory;
123
+ }
124
+
125
+ function goToParent(
126
+ state: RouterState,
127
+ options: NavigateToParentOptions = {}
128
+ ) {
129
+ const { locationHistory, screens } = state;
130
+ const currentPath = locationHistory[ locationHistory.length - 1 ].path;
131
+ if ( currentPath === undefined ) {
132
+ return locationHistory;
133
+ }
134
+ const parentPath = findParent( currentPath, screens );
135
+ if ( parentPath === undefined ) {
136
+ return locationHistory;
137
+ }
138
+ return goTo( state, parentPath, {
139
+ ...options,
140
+ isBack: true,
141
+ } );
142
+ }
143
+
144
+ function routerReducer(
145
+ state: RouterState,
146
+ action: RouterAction
147
+ ): RouterState {
148
+ let { screens, locationHistory, matchedPath } = state;
149
+
45
150
  switch ( action.type ) {
46
151
  case 'add':
47
- return [ ...state, action.screen ];
152
+ screens = addScreen( state, action.screen );
153
+ break;
48
154
  case 'remove':
49
- return state.filter( ( s: Screen ) => s.id !== action.screen.id );
155
+ screens = removeScreen( state, action.screen );
156
+ break;
157
+ case 'goback':
158
+ locationHistory = goBack( state );
159
+ break;
160
+ case 'goto':
161
+ locationHistory = goTo( state, action.path, action.options );
162
+ break;
163
+ case 'gotoparent':
164
+ locationHistory = goToParent( state, action.options );
165
+ break;
166
+ }
167
+
168
+ // Return early in case there is no change
169
+ if (
170
+ screens === state.screens &&
171
+ locationHistory === state.locationHistory
172
+ ) {
173
+ return state;
50
174
  }
51
175
 
52
- return state;
176
+ // Compute the matchedPath
177
+ const currentPath =
178
+ locationHistory.length > 0
179
+ ? locationHistory[ locationHistory.length - 1 ].path
180
+ : undefined;
181
+ matchedPath =
182
+ currentPath !== undefined
183
+ ? patternMatch( currentPath, screens )
184
+ : undefined;
185
+
186
+ // If the new match is the same as the previous match,
187
+ // return the previous one to keep immutability.
188
+ if (
189
+ matchedPath &&
190
+ state.matchedPath &&
191
+ matchedPath.id === state.matchedPath.id &&
192
+ isShallowEqual( matchedPath.params, state.matchedPath.params )
193
+ ) {
194
+ matchedPath = state.matchedPath;
195
+ }
196
+
197
+ return { screens, locationHistory, matchedPath };
53
198
  }
54
199
 
55
200
  function UnconnectedNavigatorProvider(
@@ -59,167 +204,33 @@ function UnconnectedNavigatorProvider(
59
204
  const { initialPath, children, className, ...otherProps } =
60
205
  useContextSystem( props, 'NavigatorProvider' );
61
206
 
62
- const [ locationHistory, setLocationHistory ] = useState<
63
- NavigatorLocation[]
64
- >( [
65
- {
66
- path: initialPath,
67
- },
68
- ] );
69
- const currentLocationHistory = useRef< NavigatorLocation[] >( [] );
70
- const [ screens, dispatch ] = useReducer( screensReducer, [] );
71
- const currentScreens = useRef< Screen[] >( [] );
72
- useEffect( () => {
73
- currentScreens.current = screens;
74
- }, [ screens ] );
75
- useEffect( () => {
76
- currentLocationHistory.current = locationHistory;
77
- }, [ locationHistory ] );
78
- const currentMatch = useRef< MatchedPath >();
79
- const matchedPath = useMemo( () => {
80
- let currentPath: string | undefined;
81
- if (
82
- locationHistory.length === 0 ||
83
- ( currentPath =
84
- locationHistory[ locationHistory.length - 1 ].path ) ===
85
- undefined
86
- ) {
87
- currentMatch.current = undefined;
88
- return undefined;
89
- }
90
-
91
- const resolvePath = ( path: string ) => {
92
- const newMatch = patternMatch( path, screens );
93
-
94
- // If the new match is the same as the current match,
95
- // return the previous one for performance reasons.
96
- if (
97
- currentMatch.current &&
98
- newMatch &&
99
- isShallowEqual(
100
- newMatch.params,
101
- currentMatch.current.params
102
- ) &&
103
- newMatch.id === currentMatch.current.id
104
- ) {
105
- return currentMatch.current;
106
- }
107
-
108
- return newMatch;
109
- };
110
-
111
- const newMatch = resolvePath( currentPath );
112
- currentMatch.current = newMatch;
113
- return newMatch;
114
- }, [ screens, locationHistory ] );
115
-
116
- const addScreen = useCallback(
117
- ( screen: Screen ) => dispatch( { type: 'add', screen } ),
118
- []
207
+ const [ routerState, dispatch ] = useReducer(
208
+ routerReducer,
209
+ initialPath,
210
+ ( path ) => ( {
211
+ screens: [],
212
+ locationHistory: [ { path } ],
213
+ matchedPath: undefined,
214
+ } )
119
215
  );
120
216
 
121
- const removeScreen = useCallback(
122
- ( screen: Screen ) => dispatch( { type: 'remove', screen } ),
217
+ // The methods are constant forever, create stable references to them.
218
+ const methods = useMemo(
219
+ () => ( {
220
+ goBack: () => dispatch( { type: 'goback' } ),
221
+ goTo: ( path: string, options?: NavigateOptions ) =>
222
+ dispatch( { type: 'goto', path, options } ),
223
+ goToParent: ( options: NavigateToParentOptions | undefined ) =>
224
+ dispatch( { type: 'gotoparent', options } ),
225
+ addScreen: ( screen: Screen ) =>
226
+ dispatch( { type: 'add', screen } ),
227
+ removeScreen: ( screen: Screen ) =>
228
+ dispatch( { type: 'remove', screen } ),
229
+ } ),
123
230
  []
124
231
  );
125
232
 
126
- const goBack: NavigatorContextType[ 'goBack' ] = useCallback( () => {
127
- setLocationHistory( ( prevLocationHistory ) => {
128
- if ( prevLocationHistory.length <= 1 ) {
129
- return prevLocationHistory;
130
- }
131
- return [
132
- ...prevLocationHistory.slice( 0, -2 ),
133
- {
134
- ...prevLocationHistory[ prevLocationHistory.length - 2 ],
135
- isBack: true,
136
- hasRestoredFocus: false,
137
- },
138
- ];
139
- } );
140
- }, [] );
141
-
142
- const goTo: NavigatorContextType[ 'goTo' ] = useCallback(
143
- ( path, options = {} ) => {
144
- const {
145
- focusTargetSelector,
146
- isBack = false,
147
- skipFocus = false,
148
- replace = false,
149
- ...restOptions
150
- } = options;
151
-
152
- const isNavigatingToPreviousPath =
153
- isBack &&
154
- currentLocationHistory.current.length > 1 &&
155
- currentLocationHistory.current[
156
- currentLocationHistory.current.length - 2
157
- ].path === path;
158
-
159
- if ( isNavigatingToPreviousPath ) {
160
- goBack();
161
- return;
162
- }
163
-
164
- setLocationHistory( ( prevLocationHistory ) => {
165
- const newLocation = {
166
- ...restOptions,
167
- path,
168
- isBack,
169
- hasRestoredFocus: false,
170
- skipFocus,
171
- };
172
-
173
- if ( prevLocationHistory.length === 0 ) {
174
- return replace ? [] : [ newLocation ];
175
- }
176
-
177
- const newLocationHistory = prevLocationHistory.slice(
178
- prevLocationHistory.length > MAX_HISTORY_LENGTH - 1 ? 1 : 0,
179
- -1
180
- );
181
-
182
- if ( ! replace ) {
183
- newLocationHistory.push(
184
- // Assign `focusTargetSelector` to the previous location in history
185
- // (the one we just navigated from).
186
- {
187
- ...prevLocationHistory[
188
- prevLocationHistory.length - 1
189
- ],
190
- focusTargetSelector,
191
- }
192
- );
193
- }
194
-
195
- newLocationHistory.push( newLocation );
196
-
197
- return newLocationHistory;
198
- } );
199
- },
200
- [ goBack ]
201
- );
202
-
203
- const goToParent: NavigatorContextType[ 'goToParent' ] = useCallback(
204
- ( options = {} ) => {
205
- const currentPath =
206
- currentLocationHistory.current[
207
- currentLocationHistory.current.length - 1
208
- ].path;
209
- if ( currentPath === undefined ) {
210
- return;
211
- }
212
- const parentPath = findParent(
213
- currentPath,
214
- currentScreens.current
215
- );
216
- if ( parentPath === undefined ) {
217
- return;
218
- }
219
- goTo( parentPath, { ...options, isBack: true } );
220
- },
221
- [ goTo ]
222
- );
233
+ const { locationHistory, matchedPath } = routerState;
223
234
 
224
235
  const navigatorContextValue: NavigatorContextType = useMemo(
225
236
  () => ( {
@@ -227,23 +238,11 @@ function UnconnectedNavigatorProvider(
227
238
  ...locationHistory[ locationHistory.length - 1 ],
228
239
  isInitial: locationHistory.length === 1,
229
240
  },
230
- params: matchedPath ? matchedPath.params : {},
231
- match: matchedPath ? matchedPath.id : undefined,
232
- goTo,
233
- goBack,
234
- goToParent,
235
- addScreen,
236
- removeScreen,
241
+ params: matchedPath?.params ?? {},
242
+ match: matchedPath?.id,
243
+ ...methods,
237
244
  } ),
238
- [
239
- locationHistory,
240
- matchedPath,
241
- goTo,
242
- goBack,
243
- goToParent,
244
- addScreen,
245
- removeScreen,
246
- ]
245
+ [ locationHistory, matchedPath, methods ]
247
246
  );
248
247
 
249
248
  const cx = useCx();
@@ -106,7 +106,7 @@ function UnconnectedNavigatorScreen(
106
106
 
107
107
  // When navigating back, if a selector is provided, use it to look for the
108
108
  // target element (assumed to be a node inside the current NavigatorScreen)
109
- if ( location.isBack && location?.focusTargetSelector ) {
109
+ if ( location.isBack && location.focusTargetSelector ) {
110
110
  elementToFocus = wrapperRef.current.querySelector(
111
111
  location.focusTargetSelector
112
112
  );
@@ -115,9 +115,7 @@ function UnconnectedNavigatorScreen(
115
115
  // If the previous query didn't run or find any element to focus, fallback
116
116
  // to the first tabbable element in the screen (or the screen itself).
117
117
  if ( ! elementToFocus ) {
118
- const firstTabbable = (
119
- focus.tabbable.find( wrapperRef.current ) as HTMLElement[]
120
- )[ 0 ];
118
+ const [ firstTabbable ] = focus.tabbable.find( wrapperRef.current );
121
119
  elementToFocus = firstTabbable ?? wrapperRef.current;
122
120
  }
123
121
 
@@ -74,7 +74,7 @@ function NameInput( { value, onChange, label }: NameInputProps ) {
74
74
  }
75
75
 
76
76
  /**
77
- * Returns a name for a palette item in the format "Color + id".
77
+ * Returns a name and slug for a palette item. The name takes the format "Color + id".
78
78
  * To ensure there are no duplicate ids, this function checks all slugs.
79
79
  * It expects slugs to be in the format: slugPrefix + color- + number.
80
80
  * It then sets the id component of the new name based on the incremented id of the highest existing slug id.
@@ -82,9 +82,9 @@ function NameInput( { value, onChange, label }: NameInputProps ) {
82
82
  * @param elements An array of color palette items.
83
83
  * @param slugPrefix The slug prefix used to match the element slug.
84
84
  *
85
- * @return A unique name for a palette item.
85
+ * @return A name and slug for the new palette item.
86
86
  */
87
- export function getNameForPosition(
87
+ export function getNameAndSlugForPosition(
88
88
  elements: PaletteElement[],
89
89
  slugPrefix: string
90
90
  ) {
@@ -102,11 +102,14 @@ export function getNameForPosition(
102
102
  return previousValue;
103
103
  }, 1 );
104
104
 
105
- return sprintf(
106
- /* translators: %s: is an id for a custom color */
107
- __( 'Color %s' ),
108
- position
109
- );
105
+ return {
106
+ name: sprintf(
107
+ /* translators: %s: is an id for a custom color */
108
+ __( 'Color %s' ),
109
+ position
110
+ ),
111
+ slug: `${ slugPrefix }color-${ position }`,
112
+ };
110
113
  }
111
114
 
112
115
  function ColorPickerPopover< T extends Color | Gradient >( {
@@ -434,20 +437,19 @@ export function PaletteEdit( {
434
437
  : __( 'Add color' )
435
438
  }
436
439
  onClick={ () => {
437
- const optionName = getNameForPosition(
438
- elements,
439
- slugPrefix
440
- );
440
+ const { name, slug } =
441
+ getNameAndSlugForPosition(
442
+ elements,
443
+ slugPrefix
444
+ );
441
445
 
442
446
  if ( !! gradients ) {
443
447
  onChange( [
444
448
  ...gradients,
445
449
  {
446
450
  gradient: DEFAULT_GRADIENT,
447
- name: optionName,
448
- slug:
449
- slugPrefix +
450
- kebabCase( optionName ),
451
+ name,
452
+ slug,
451
453
  },
452
454
  ] );
453
455
  } else {
@@ -455,10 +457,8 @@ export function PaletteEdit( {
455
457
  ...colors,
456
458
  {
457
459
  color: DEFAULT_COLOR,
458
- name: optionName,
459
- slug:
460
- slugPrefix +
461
- kebabCase( optionName ),
460
+ name,
461
+ slug,
462
462
  },
463
463
  ] );
464
464
  }
@@ -480,7 +480,7 @@ export function PaletteEdit( {
480
480
  : __( 'Color options' )
481
481
  }
482
482
  toggleProps={ {
483
- isSmall: true,
483
+ size: 'small',
484
484
  } }
485
485
  >
486
486
  { ( { onClose }: { onClose: () => void } ) => (
@@ -7,7 +7,7 @@ import { click, type, press } from '@ariakit/test';
7
7
  /**
8
8
  * Internal dependencies
9
9
  */
10
- import PaletteEdit, { getNameForPosition } from '..';
10
+ import PaletteEdit, { getNameAndSlugForPosition } from '..';
11
11
  import type { PaletteElement } from '../types';
12
12
 
13
13
  const noop = () => {};
@@ -21,17 +21,18 @@ async function clearInput( input: HTMLInputElement ) {
21
21
  }
22
22
  }
23
23
 
24
- describe( 'getNameForPosition', () => {
24
+ describe( 'getNameAndSlugForPosition', () => {
25
25
  test( 'should return 1 by default', () => {
26
26
  const slugPrefix = 'test-';
27
27
  const elements: PaletteElement[] = [];
28
28
 
29
- expect( getNameForPosition( elements, slugPrefix ) ).toEqual(
30
- 'Color 1'
31
- );
29
+ expect( getNameAndSlugForPosition( elements, slugPrefix ) ).toEqual( {
30
+ name: 'Color 1',
31
+ slug: 'test-color-1',
32
+ } );
32
33
  } );
33
34
 
34
- test( 'should return a new color name with an incremented slug id', () => {
35
+ test( 'should return a new color name and slug with an incremented slug id', () => {
35
36
  const slugPrefix = 'test-';
36
37
  const elements = [
37
38
  {
@@ -41,12 +42,13 @@ describe( 'getNameForPosition', () => {
41
42
  },
42
43
  ];
43
44
 
44
- expect( getNameForPosition( elements, slugPrefix ) ).toEqual(
45
- 'Color 2'
46
- );
45
+ expect( getNameAndSlugForPosition( elements, slugPrefix ) ).toEqual( {
46
+ name: 'Color 2',
47
+ slug: 'test-color-2',
48
+ } );
47
49
  } );
48
50
 
49
- test( 'should ignore user-defined color names', () => {
51
+ test( 'should ignore user-defined color name and slug', () => {
50
52
  const slugPrefix = 'test-';
51
53
  const elements = [
52
54
  {
@@ -56,12 +58,13 @@ describe( 'getNameForPosition', () => {
56
58
  },
57
59
  ];
58
60
 
59
- expect( getNameForPosition( elements, slugPrefix ) ).toEqual(
60
- 'Color 1'
61
- );
61
+ expect( getNameAndSlugForPosition( elements, slugPrefix ) ).toEqual( {
62
+ name: 'Color 1',
63
+ slug: 'test-color-1',
64
+ } );
62
65
  } );
63
66
 
64
- test( 'should return a new color name with an incremented slug id one higher than the current highest', () => {
67
+ test( 'should return a new color name and slug with an incremented slug id one higher than the current highest', () => {
65
68
  const slugPrefix = 'test-';
66
69
  const elements = [
67
70
  {
@@ -86,9 +89,10 @@ describe( 'getNameForPosition', () => {
86
89
  },
87
90
  ];
88
91
 
89
- expect( getNameForPosition( elements, slugPrefix ) ).toEqual(
90
- 'Color 151'
91
- );
92
+ expect( getNameAndSlugForPosition( elements, slugPrefix ) ).toEqual( {
93
+ name: 'Color 151',
94
+ slug: 'test-color-151',
95
+ } );
92
96
  } );
93
97
  } );
94
98
 
@@ -212,7 +212,11 @@
212
212
 
213
213
  // By painting the borders here, we enable them to be replaced by the Border control.
214
214
  @include placeholder-style();
215
- overflow: auto;
215
+
216
+ overflow: hidden;
217
+ .is-selected & {
218
+ overflow: auto;
219
+ }
216
220
  }
217
221
 
218
222
  // Position the spinner.