@wordpress/components 25.4.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 (119) hide show
  1. package/CHANGELOG.md +16 -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/color-palette/index.js +2 -2
  5. package/build/color-palette/index.js.map +1 -1
  6. package/build/focal-point-picker/index.native.js +6 -4
  7. package/build/focal-point-picker/index.native.js.map +1 -1
  8. package/build/menu-items-choice/index.js +1 -0
  9. package/build/menu-items-choice/index.js.map +1 -1
  10. package/build/mobile/bottom-sheet/bottom-sheet-navigation/bottom-sheet-navigation-context.native.js +3 -1
  11. package/build/mobile/bottom-sheet/bottom-sheet-navigation/bottom-sheet-navigation-context.native.js.map +1 -1
  12. package/build/mobile/bottom-sheet/bottom-sheet-navigation/navigation-container.native.js +50 -44
  13. package/build/mobile/bottom-sheet/bottom-sheet-navigation/navigation-container.native.js.map +1 -1
  14. package/build/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js +13 -20
  15. package/build/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js.map +1 -1
  16. package/build/mobile/bottom-sheet/index.native.js +3 -1
  17. package/build/mobile/bottom-sheet/index.native.js.map +1 -1
  18. package/build/mobile/link-picker/link-picker-results.native.js +2 -1
  19. package/build/mobile/link-picker/link-picker-results.native.js.map +1 -1
  20. package/build/mobile/segmented-control/index.native.js +7 -7
  21. package/build/mobile/segmented-control/index.native.js.map +1 -1
  22. package/build/modal/index.js +14 -1
  23. package/build/modal/index.js.map +1 -1
  24. package/build/private-apis.js +4 -1
  25. package/build/private-apis.js.map +1 -1
  26. package/build/progress-bar/index.js +54 -0
  27. package/build/progress-bar/index.js.map +1 -0
  28. package/build/progress-bar/styles.js +69 -0
  29. package/build/progress-bar/styles.js.map +1 -0
  30. package/build/progress-bar/types.js +6 -0
  31. package/build/progress-bar/types.js.map +1 -0
  32. package/build/tab-panel/index.js +91 -58
  33. package/build/tab-panel/index.js.map +1 -1
  34. package/build-module/border-control/border-control-dropdown/component.js +8 -10
  35. package/build-module/border-control/border-control-dropdown/component.js.map +1 -1
  36. package/build-module/color-palette/index.js +2 -2
  37. package/build-module/color-palette/index.js.map +1 -1
  38. package/build-module/focal-point-picker/index.native.js +6 -5
  39. package/build-module/focal-point-picker/index.native.js.map +1 -1
  40. package/build-module/menu-items-choice/index.js +1 -0
  41. package/build-module/menu-items-choice/index.js.map +1 -1
  42. package/build-module/mobile/bottom-sheet/bottom-sheet-navigation/bottom-sheet-navigation-context.native.js +3 -1
  43. package/build-module/mobile/bottom-sheet/bottom-sheet-navigation/bottom-sheet-navigation-context.native.js.map +1 -1
  44. package/build-module/mobile/bottom-sheet/bottom-sheet-navigation/navigation-container.native.js +43 -41
  45. package/build-module/mobile/bottom-sheet/bottom-sheet-navigation/navigation-container.native.js.map +1 -1
  46. package/build-module/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js +14 -20
  47. package/build-module/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js.map +1 -1
  48. package/build-module/mobile/bottom-sheet/index.native.js +3 -1
  49. package/build-module/mobile/bottom-sheet/index.native.js.map +1 -1
  50. package/build-module/mobile/link-picker/link-picker-results.native.js +2 -1
  51. package/build-module/mobile/link-picker/link-picker-results.native.js.map +1 -1
  52. package/build-module/mobile/segmented-control/index.native.js +7 -7
  53. package/build-module/mobile/segmented-control/index.native.js.map +1 -1
  54. package/build-module/modal/index.js +14 -1
  55. package/build-module/modal/index.js.map +1 -1
  56. package/build-module/private-apis.js +3 -1
  57. package/build-module/private-apis.js.map +1 -1
  58. package/build-module/progress-bar/index.js +41 -0
  59. package/build-module/progress-bar/index.js.map +1 -0
  60. package/build-module/progress-bar/styles.js +61 -0
  61. package/build-module/progress-bar/styles.js.map +1 -0
  62. package/build-module/progress-bar/types.js +2 -0
  63. package/build-module/progress-bar/types.js.map +1 -0
  64. package/build-module/tab-panel/index.js +88 -59
  65. package/build-module/tab-panel/index.js.map +1 -1
  66. package/build-types/border-control/border-control-dropdown/component.d.ts.map +1 -1
  67. package/build-types/menu-items-choice/index.d.ts.map +1 -1
  68. package/build-types/menu-items-choice/types.d.ts +5 -0
  69. package/build-types/menu-items-choice/types.d.ts.map +1 -1
  70. package/build-types/modal/index.d.ts.map +1 -1
  71. package/build-types/private-apis.d.ts.map +1 -1
  72. package/build-types/progress-bar/index.d.ts +5 -0
  73. package/build-types/progress-bar/index.d.ts.map +1 -0
  74. package/build-types/progress-bar/stories/index.d.ts +12 -0
  75. package/build-types/progress-bar/stories/index.d.ts.map +1 -0
  76. package/build-types/progress-bar/styles.d.ts +18 -0
  77. package/build-types/progress-bar/styles.d.ts.map +1 -0
  78. package/build-types/progress-bar/test/index.d.ts +2 -0
  79. package/build-types/progress-bar/test/index.d.ts.map +1 -0
  80. package/build-types/progress-bar/types.d.ts +11 -0
  81. package/build-types/progress-bar/types.d.ts.map +1 -0
  82. package/build-types/tab-panel/index.d.ts.map +1 -1
  83. package/build-types/tab-panel/stories/index.d.ts +1 -0
  84. package/build-types/tab-panel/stories/index.d.ts.map +1 -1
  85. package/build-types/tab-panel/types.d.ts +1 -9
  86. package/build-types/tab-panel/types.d.ts.map +1 -1
  87. package/package.json +20 -20
  88. package/src/border-control/border-control-dropdown/component.tsx +7 -11
  89. package/src/border-control/test/index.js +6 -6
  90. package/src/color-palette/index.tsx +2 -2
  91. package/src/color-palette/test/__snapshots__/index.tsx.snap +1 -1
  92. package/src/color-palette/test/index.tsx +1 -5
  93. package/src/draggable/test/index.native.js +4 -0
  94. package/src/focal-point-picker/index.native.js +6 -5
  95. package/src/menu-item/README.md +7 -0
  96. package/src/menu-items-choice/index.tsx +1 -0
  97. package/src/menu-items-choice/types.ts +5 -0
  98. package/src/mobile/bottom-sheet/bottom-sheet-navigation/bottom-sheet-navigation-context.native.js +1 -1
  99. package/src/mobile/bottom-sheet/bottom-sheet-navigation/navigation-container.native.js +72 -53
  100. package/src/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js +15 -21
  101. package/src/mobile/bottom-sheet/bottom-sheet-navigation/test/navigation-container.native.js +165 -119
  102. package/src/mobile/bottom-sheet/index.native.js +2 -0
  103. package/src/mobile/link-picker/link-picker-results.native.js +1 -1
  104. package/src/mobile/link-settings/test/edit.native.js +37 -23
  105. package/src/mobile/segmented-control/index.native.js +11 -11
  106. package/src/modal/index.tsx +16 -0
  107. package/src/modal/test/index.tsx +33 -0
  108. package/src/private-apis.ts +2 -0
  109. package/src/progress-bar/README.md +30 -0
  110. package/src/progress-bar/index.tsx +45 -0
  111. package/src/progress-bar/stories/index.tsx +33 -0
  112. package/src/progress-bar/styles.ts +67 -0
  113. package/src/progress-bar/test/index.tsx +79 -0
  114. package/src/progress-bar/types.ts +11 -0
  115. package/src/tab-panel/index.tsx +121 -84
  116. package/src/tab-panel/stories/index.tsx +6 -0
  117. package/src/tab-panel/test/index.tsx +128 -109
  118. package/src/tab-panel/types.ts +1 -10
  119. package/tsconfig.tsbuildinfo +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/components",
3
- "version": "25.4.0",
3
+ "version": "25.5.0",
4
4
  "description": "UI components for WordPress.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -41,23 +41,23 @@
41
41
  "@floating-ui/react-dom": "1.0.0",
42
42
  "@radix-ui/react-dropdown-menu": "2.0.4",
43
43
  "@use-gesture/react": "^10.2.24",
44
- "@wordpress/a11y": "^3.38.0",
45
- "@wordpress/compose": "^6.15.0",
46
- "@wordpress/date": "^4.38.0",
47
- "@wordpress/deprecated": "^3.38.0",
48
- "@wordpress/dom": "^3.38.0",
49
- "@wordpress/element": "^5.15.0",
50
- "@wordpress/escape-html": "^2.38.0",
51
- "@wordpress/hooks": "^3.38.0",
52
- "@wordpress/html-entities": "^3.38.0",
53
- "@wordpress/i18n": "^4.38.0",
54
- "@wordpress/icons": "^9.29.0",
55
- "@wordpress/is-shallow-equal": "^4.38.0",
56
- "@wordpress/keycodes": "^3.38.0",
57
- "@wordpress/primitives": "^3.36.0",
58
- "@wordpress/private-apis": "^0.20.0",
59
- "@wordpress/rich-text": "^6.15.0",
60
- "@wordpress/warning": "^2.38.0",
44
+ "@wordpress/a11y": "^3.39.0",
45
+ "@wordpress/compose": "^6.16.0",
46
+ "@wordpress/date": "^4.39.0",
47
+ "@wordpress/deprecated": "^3.39.0",
48
+ "@wordpress/dom": "^3.39.0",
49
+ "@wordpress/element": "^5.16.0",
50
+ "@wordpress/escape-html": "^2.39.0",
51
+ "@wordpress/hooks": "^3.39.0",
52
+ "@wordpress/html-entities": "^3.39.0",
53
+ "@wordpress/i18n": "^4.39.0",
54
+ "@wordpress/icons": "^9.30.0",
55
+ "@wordpress/is-shallow-equal": "^4.39.0",
56
+ "@wordpress/keycodes": "^3.39.0",
57
+ "@wordpress/primitives": "^3.37.0",
58
+ "@wordpress/private-apis": "^0.21.0",
59
+ "@wordpress/rich-text": "^6.16.0",
60
+ "@wordpress/warning": "^2.39.0",
61
61
  "change-case": "^4.1.2",
62
62
  "classnames": "^2.3.1",
63
63
  "colord": "^2.7.0",
@@ -66,7 +66,7 @@
66
66
  "dom-scroll-into-view": "^1.2.1",
67
67
  "downshift": "^6.0.15",
68
68
  "fast-deep-equal": "^3.1.3",
69
- "framer-motion": "~10.11.6",
69
+ "framer-motion": "^10.13.0",
70
70
  "gradient-parser": "^0.1.5",
71
71
  "highlight-words-core": "^1.2.2",
72
72
  "is-plain-object": "^5.0.0",
@@ -87,5 +87,5 @@
87
87
  "publishConfig": {
88
88
  "access": "public"
89
89
  },
90
- "gitHead": "6f14d11ed4cb59df110a28ebaa23ecba95eb673a"
90
+ "gitHead": "b898cf1dc8e70841d1647ea0994ac6278acc18a7"
91
91
  }
@@ -30,12 +30,8 @@ import type { DropdownProps as DropdownComponentProps } from '../../dropdown/typ
30
30
  import type { ColorProps, DropdownProps } from '../types';
31
31
 
32
32
  const getAriaLabelColorValue = ( colorValue: string ) => {
33
- const isHex = colorValue.startsWith( '#' );
34
-
35
33
  // Leave hex values as-is. Remove the `var()` wrapper from CSS vars.
36
- const displayValue = colorValue.replace( /^var\((.+)\)$/, '$1' );
37
-
38
- return isHex ? displayValue.split( '' ).join( '-' ) : displayValue;
34
+ return colorValue.replace( /^var\((.+)\)$/, '$1' );
39
35
  };
40
36
 
41
37
  const getColorObject = (
@@ -79,14 +75,14 @@ const getToggleAriaLabel = (
79
75
  const ariaLabelValue = getAriaLabelColorValue( colorObject.color );
80
76
  return style
81
77
  ? sprintf(
82
- // translators: %1$s: The name of the color e.g. "vivid red". %2$s: The color's hex code, with added hyphens e.g: "#-f-0-0". %3$s: The current border style selection e.g. "solid".
78
+ // translators: %1$s: The name of the color e.g. "vivid red". %2$s: The color's hex code e.g.: "#f00:". %3$s: The current border style selection e.g. "solid".
83
79
  'Border color and style picker. The currently selected color is called "%1$s" and has a value of "%2$s". The currently selected style is "%3$s".',
84
80
  colorObject.name,
85
81
  ariaLabelValue,
86
82
  style
87
83
  )
88
84
  : sprintf(
89
- // translators: %1$s: The name of the color e.g. "vivid red". %2$s: The color's hex code, with added hyphens e.g: "#-f-0-0".
85
+ // translators: %1$s: The name of the color e.g. "vivid red". %2$s: The color's hex code e.g.: "#f00:".
90
86
  'Border color and style picker. The currently selected color is called "%1$s" and has a value of "%2$s".',
91
87
  colorObject.name,
92
88
  ariaLabelValue
@@ -97,13 +93,13 @@ const getToggleAriaLabel = (
97
93
  const ariaLabelValue = getAriaLabelColorValue( colorValue );
98
94
  return style
99
95
  ? sprintf(
100
- // translators: %1$s: The color's hex code, with added hyphens e.g: "#-f-0-0". %2$s: The current border style selection e.g. "solid".
96
+ // translators: %1$s: The color's hex code e.g.: "#f00:". %2$s: The current border style selection e.g. "solid".
101
97
  'Border color and style picker. The currently selected color has a value of "%1$s". The currently selected style is "%2$s".',
102
98
  ariaLabelValue,
103
99
  style
104
100
  )
105
101
  : sprintf(
106
- // translators: %1$s: The color's hex code, with added hyphens e.g: "#-f-0-0".
102
+ // translators: %1$s: The color's hex code e.g: "#f00".
107
103
  'Border color and style picker. The currently selected color has a value of "%1$s".',
108
104
  ariaLabelValue
109
105
  );
@@ -114,7 +110,7 @@ const getToggleAriaLabel = (
114
110
 
115
111
  if ( colorObject ) {
116
112
  return sprintf(
117
- // translators: %1$s: The name of the color e.g. "vivid red". %2$s: The color's hex code, with added hyphens e.g: "#-f-0-0".
113
+ // translators: %1$s: The name of the color e.g. "vivid red". %2$s: The color's hex code e.g: "#f00".
118
114
  'Border color picker. The currently selected color is called "%1$s" and has a value of "%2$s".',
119
115
  colorObject.name,
120
116
  getAriaLabelColorValue( colorObject.color )
@@ -123,7 +119,7 @@ const getToggleAriaLabel = (
123
119
 
124
120
  if ( colorValue ) {
125
121
  return sprintf(
126
- // translators: %1$s: The color's hex code, with added hyphens e.g: "#-f-0-0".
122
+ // translators: %1$s: The color's hex code e.g: "#f00".
127
123
  'Border color picker. The currently selected color has a value of "%1$s".',
128
124
  getAriaLabelColorValue( colorValue )
129
125
  );
@@ -215,7 +215,7 @@ describe( 'BorderControl', () => {
215
215
 
216
216
  expect(
217
217
  screen.getByLabelText(
218
- 'Border color and style picker. The currently selected color is called "Blue" and has a value of "#-7-2-a-e-e-6".'
218
+ 'Border color and style picker. The currently selected color is called "Blue" and has a value of "#72aee6".'
219
219
  )
220
220
  ).toBeInTheDocument();
221
221
  } );
@@ -226,7 +226,7 @@ describe( 'BorderControl', () => {
226
226
 
227
227
  expect(
228
228
  screen.getByLabelText(
229
- 'Border color and style picker. The currently selected color has a value of "#-4-b-1-d-8-0".'
229
+ 'Border color and style picker. The currently selected color has a value of "#4b1d80".'
230
230
  )
231
231
  ).toBeInTheDocument();
232
232
  } );
@@ -239,7 +239,7 @@ describe( 'BorderControl', () => {
239
239
 
240
240
  expect(
241
241
  screen.getByLabelText(
242
- 'Border color and style picker. The currently selected color is called "Blue" and has a value of "#-7-2-a-e-e-6". The currently selected style is "dotted".'
242
+ 'Border color and style picker. The currently selected color is called "Blue" and has a value of "#72aee6". The currently selected style is "dotted".'
243
243
  )
244
244
  ).toBeInTheDocument();
245
245
  } );
@@ -252,7 +252,7 @@ describe( 'BorderControl', () => {
252
252
 
253
253
  expect(
254
254
  screen.getByLabelText(
255
- 'Border color and style picker. The currently selected color has a value of "#-4-b-1-d-8-0". The currently selected style is "dashed".'
255
+ 'Border color and style picker. The currently selected color has a value of "#4b1d80". The currently selected style is "dashed".'
256
256
  )
257
257
  ).toBeInTheDocument();
258
258
  } );
@@ -280,7 +280,7 @@ describe( 'BorderControl', () => {
280
280
 
281
281
  expect(
282
282
  screen.getByLabelText(
283
- 'Border color picker. The currently selected color is called "Blue" and has a value of "#-7-2-a-e-e-6".'
283
+ 'Border color picker. The currently selected color is called "Blue" and has a value of "#72aee6".'
284
284
  )
285
285
  ).toBeInTheDocument();
286
286
  } );
@@ -294,7 +294,7 @@ describe( 'BorderControl', () => {
294
294
 
295
295
  expect(
296
296
  screen.getByLabelText(
297
- 'Border color picker. The currently selected color has a value of "#-4-b-1-d-8-0".'
297
+ 'Border color picker. The currently selected color has a value of "#4b1d80".'
298
298
  )
299
299
  ).toBeInTheDocument();
300
300
  } );
@@ -224,12 +224,12 @@ function UnforwardedColorPalette(
224
224
  const displayValue = value?.replace( /^var\((.+)\)$/, '$1' );
225
225
  const customColorAccessibleLabel = !! displayValue
226
226
  ? sprintf(
227
- // translators: %1$s: The name of the color e.g: "vivid red". %2$s: The color's hex code, with added hyphens e.g: "#-f-0-0".
227
+ // translators: %1$s: The name of the color e.g: "vivid red". %2$s: The color's hex code e.g: "#f00".
228
228
  __(
229
229
  'Custom color picker. The currently selected color is called "%1$s" and has a value of "%2$s".'
230
230
  ),
231
231
  buttonLabelName,
232
- isHex ? displayValue.split( '' ).join( '-' ) : displayValue
232
+ displayValue
233
233
  )
234
234
  : __( 'Custom color picker.' );
235
235
 
@@ -193,7 +193,7 @@ exports[`ColorPalette should render a dynamic toolbar of colors 1`] = `
193
193
  <button
194
194
  aria-expanded="false"
195
195
  aria-haspopup="true"
196
- aria-label="Custom color picker. The currently selected color is called "red" and has a value of "#-f-0-0"."
196
+ aria-label="Custom color picker. The currently selected color is called "red" and has a value of "#f00"."
197
197
  class="components-color-palette__custom-color-button"
198
198
  style="background: rgb(255, 0, 0);"
199
199
  />
@@ -240,11 +240,7 @@ describe( 'ColorPalette', () => {
240
240
  expect( screen.getByText( EXAMPLE_COLORS[ 0 ].color ) ).toBeVisible();
241
241
  expect(
242
242
  screen.getByRole( 'button', {
243
- name: `Custom color picker. The currently selected color is called "${
244
- EXAMPLE_COLORS[ 0 ].name
245
- }" and has a value of "${ EXAMPLE_COLORS[ 0 ].color
246
- .split( '' )
247
- .join( '-' ) }".`,
243
+ name: `Custom color picker. The currently selected color is called "${ EXAMPLE_COLORS[ 0 ].name }" and has a value of "${ EXAMPLE_COLORS[ 0 ].color }".`,
248
244
  expanded: false,
249
245
  } )
250
246
  ).toBeInTheDocument();
@@ -110,6 +110,10 @@ describe( 'Draggable', () => {
110
110
  },
111
111
  { state: State.END },
112
112
  ] );
113
+ // TODO(jest-console): Fix the warning and remove the expect below.
114
+ expect( console ).toHaveWarnedWith(
115
+ '[Reanimated] You can not use setGestureState in non-worklet function.'
116
+ );
113
117
 
114
118
  expect( onDragStart ).toHaveBeenCalledTimes( 1 );
115
119
  expect( onDragStart ).toHaveBeenCalledWith( {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { Animated, PanResponder, View } from 'react-native';
4
+ import { Animated, PanResponder, StyleSheet, View } from 'react-native';
5
5
  import Video from 'react-native-video';
6
6
 
7
7
  /**
@@ -164,7 +164,7 @@ function FocalPointPicker( props ) {
164
164
  },
165
165
  ];
166
166
  const FOCAL_POINT_SIZE = 50;
167
- const focalPointStyles = [
167
+ const focalPointStyles = StyleSheet.flatten( [
168
168
  styles.focalPoint,
169
169
  {
170
170
  height: FOCAL_POINT_SIZE,
@@ -172,7 +172,7 @@ function FocalPointPicker( props ) {
172
172
  marginTop: -( FOCAL_POINT_SIZE / 2 ),
173
173
  width: FOCAL_POINT_SIZE,
174
174
  },
175
- ];
175
+ ] );
176
176
 
177
177
  const onTooltipPress = () => setTooltipVisible( false );
178
178
  const onMediaLayout = ( event ) => {
@@ -243,9 +243,10 @@ function FocalPointPicker( props ) {
243
243
  yOffset={ -( FOCAL_POINT_SIZE / 2 ) }
244
244
  />
245
245
  <FocalPoint
246
- height={ styles.focalPoint?.height }
246
+ height={ focalPointStyles.height }
247
247
  style={ focalPointStyles }
248
- width={ styles.focalPoint?.width }
248
+ testID="focal-point-picker-handle"
249
+ width={ focalPointStyles.width }
249
250
  />
250
251
  </Animated.View>
251
252
  ) }
@@ -34,6 +34,13 @@ MenuItem supports the following props. Any additional props are passed through t
34
34
 
35
35
  Element to render as child of button.
36
36
 
37
+ ### `disabled`
38
+
39
+ - Type: `boolean`
40
+ - Required: No
41
+
42
+ Refer to documentation for [Button's `disabled` prop](/packages/components/src/button/README.md#disabled-boolean).
43
+
37
44
  ### `info`
38
45
 
39
46
  - Type: `string`
@@ -58,6 +58,7 @@ function MenuItemsChoice( {
58
58
  <MenuItem
59
59
  key={ item.value }
60
60
  role="menuitemradio"
61
+ disabled={ item.disabled }
61
62
  icon={ isSelected && check }
62
63
  info={ item.info }
63
64
  isSelected={ isSelected }
@@ -2,6 +2,7 @@
2
2
  * Internal dependencies
3
3
  */
4
4
  import type { ShortcutProps } from '../shortcut/types';
5
+ import type { ButtonAsButtonProps } from '../button/types';
5
6
 
6
7
  export type MenuItemsChoiceProps = {
7
8
  /**
@@ -38,6 +39,10 @@ export type MenuItemChoice = {
38
39
  * Unique value for choice.
39
40
  */
40
41
  value: string;
42
+ /**
43
+ * Whether the menu item is disabled.
44
+ */
45
+ disabled?: ButtonAsButtonProps[ 'disabled' ];
41
46
  /**
42
47
  * Additional information which will be rendered below the given label.
43
48
  */
@@ -6,7 +6,7 @@ import { createContext } from '@wordpress/element';
6
6
  // Navigation context in BottomSheet is necessary for controlling the
7
7
  // height of navigation container.
8
8
  export const BottomSheetNavigationContext = createContext( {
9
- currentHeight: 1,
9
+ currentHeight: { value: 0 },
10
10
  setHeight: () => {},
11
11
  } );
12
12
 
@@ -1,15 +1,19 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { View, Easing } from 'react-native';
5
4
  import { NavigationContainer, DefaultTheme } from '@react-navigation/native';
6
5
  import { createStackNavigator } from '@react-navigation/stack';
6
+ import Animated, {
7
+ Easing,
8
+ useAnimatedStyle,
9
+ useSharedValue,
10
+ withTiming,
11
+ } from 'react-native-reanimated';
7
12
 
8
13
  /**
9
14
  * WordPress dependencies
10
15
  */
11
16
  import {
12
- useState,
13
17
  useContext,
14
18
  useMemo,
15
19
  useCallback,
@@ -23,11 +27,11 @@ import { usePreferredColorSchemeStyle } from '@wordpress/compose';
23
27
  /**
24
28
  * Internal dependencies
25
29
  */
26
- import { performLayoutAnimation } from '../../layout-animation';
27
30
  import {
28
31
  BottomSheetNavigationContext,
29
32
  BottomSheetNavigationProvider,
30
33
  } from './bottom-sheet-navigation-context';
34
+ import { BottomSheetContext } from '../bottom-sheet-context';
31
35
 
32
36
  import styles from './styles.scss';
33
37
 
@@ -57,7 +61,8 @@ const options = {
57
61
  cardStyleInterpolator: fadeConfig,
58
62
  };
59
63
 
60
- const ANIMATION_DURATION = 190;
64
+ const HEIGHT_ANIMATION_DURATION = 300;
65
+ const DEFAULT_HEIGHT = 1;
61
66
 
62
67
  function BottomSheetNavigationContainer( {
63
68
  children,
@@ -65,11 +70,14 @@ function BottomSheetNavigationContainer( {
65
70
  main,
66
71
  theme,
67
72
  style,
73
+ testID,
68
74
  } ) {
69
75
  const Stack = useRef( createStackNavigator() ).current;
70
- const context = useContext( BottomSheetNavigationContext );
71
- const [ currentHeight, setCurrentHeight ] = useState(
72
- context.currentHeight || 1
76
+ const navigationContext = useContext( BottomSheetNavigationContext );
77
+ const { maxHeight: sheetMaxHeight, isMaxHeightSet: isSheetMaxHeightSet } =
78
+ useContext( BottomSheetContext );
79
+ const currentHeight = useSharedValue(
80
+ navigationContext.currentHeight?.value || DEFAULT_HEIGHT
73
81
  );
74
82
 
75
83
  const backgroundStyle = usePreferredColorSchemeStyle(
@@ -77,47 +85,49 @@ function BottomSheetNavigationContainer( {
77
85
  styles.backgroundDark
78
86
  );
79
87
 
80
- const _theme = theme || {
81
- ...DefaultTheme,
82
- colors: {
83
- ...DefaultTheme.colors,
84
- background: backgroundStyle.backgroundColor,
85
- },
86
- };
88
+ const defaultTheme = useMemo(
89
+ () => ( {
90
+ ...DefaultTheme,
91
+ colors: {
92
+ ...DefaultTheme.colors,
93
+ background: backgroundStyle.backgroundColor,
94
+ },
95
+ } ),
96
+ [ backgroundStyle.backgroundColor ]
97
+ );
98
+ const _theme = theme || defaultTheme;
87
99
 
88
100
  const setHeight = useCallback(
89
101
  ( height ) => {
90
- // The screen is fullHeight.
91
102
  if (
92
- typeof height === 'string' &&
93
- typeof height !== typeof currentHeight
103
+ height > DEFAULT_HEIGHT &&
104
+ Math.round( height ) !== Math.round( currentHeight.value )
94
105
  ) {
95
- performLayoutAnimation( ANIMATION_DURATION );
96
- setCurrentHeight( height );
97
-
98
- return;
99
- }
100
-
101
- if (
102
- height > 1 &&
103
- Math.round( height ) !== Math.round( currentHeight )
104
- ) {
105
- if ( currentHeight === 1 ) {
106
- setCurrentHeight( height );
107
- } else if ( animate ) {
108
- performLayoutAnimation( ANIMATION_DURATION );
109
- setCurrentHeight( height );
106
+ // If max height is set in the bottom sheet, we clamp
107
+ // the new height using that value.
108
+ const newHeight = isSheetMaxHeightSet
109
+ ? Math.min( sheetMaxHeight, height )
110
+ : height;
111
+ const shouldAnimate =
112
+ animate && currentHeight.value !== DEFAULT_HEIGHT;
113
+
114
+ if ( shouldAnimate ) {
115
+ currentHeight.value = withTiming( newHeight, {
116
+ duration: HEIGHT_ANIMATION_DURATION,
117
+ easing: Easing.out( Easing.cubic ),
118
+ } );
110
119
  } else {
111
- setCurrentHeight( height );
120
+ currentHeight.value = newHeight;
112
121
  }
113
122
  }
114
123
  },
115
- // Disable reason: deferring this refactor to the native team.
116
- // see https://github.com/WordPress/gutenberg/pull/41166
117
- // eslint-disable-next-line react-hooks/exhaustive-deps
118
- [ currentHeight ]
124
+ [ animate, currentHeight, isSheetMaxHeightSet, sheetMaxHeight ]
119
125
  );
120
126
 
127
+ const animatedStyles = useAnimatedStyle( () => ( {
128
+ height: currentHeight.value,
129
+ } ) );
130
+
121
131
  const screens = useMemo( () => {
122
132
  return Children.map( children, ( child ) => {
123
133
  let screen = child;
@@ -136,38 +146,47 @@ function BottomSheetNavigationContainer( {
136
146
  />
137
147
  );
138
148
  } );
139
- // Disable reason: deferring this refactor to the native team.
140
- // see https://github.com/WordPress/gutenberg/pull/41166
141
- // eslint-disable-next-line react-hooks/exhaustive-deps
142
- }, [ children ] );
149
+ }, [ children, main ] );
143
150
 
144
151
  return useMemo( () => {
145
152
  return (
146
- <View style={ [ style, { height: currentHeight } ] }>
153
+ <Animated.View
154
+ style={ [ style, animatedStyles ] }
155
+ testID={ testID }
156
+ >
147
157
  <BottomSheetNavigationProvider
148
- value={ {
149
- setHeight,
150
- currentHeight,
151
- } }
158
+ value={ { setHeight, currentHeight } }
152
159
  >
153
160
  { main ? (
154
161
  <NavigationContainer theme={ _theme }>
155
- <Stack.Navigator screenOptions={ options }>
162
+ <Stack.Navigator
163
+ screenOptions={ options }
164
+ detachInactiveScreens={ false }
165
+ >
156
166
  { screens }
157
167
  </Stack.Navigator>
158
168
  </NavigationContainer>
159
169
  ) : (
160
- <Stack.Navigator screenOptions={ options }>
170
+ <Stack.Navigator
171
+ screenOptions={ options }
172
+ detachInactiveScreens={ false }
173
+ >
161
174
  { screens }
162
175
  </Stack.Navigator>
163
176
  ) }
164
177
  </BottomSheetNavigationProvider>
165
- </View>
178
+ </Animated.View>
166
179
  );
167
- // Disable reason: deferring this refactor to the native team.
168
- // see https://github.com/WordPress/gutenberg/pull/41166
169
- // eslint-disable-next-line react-hooks/exhaustive-deps
170
- }, [ currentHeight, _theme ] );
180
+ }, [
181
+ _theme,
182
+ animatedStyles,
183
+ currentHeight,
184
+ main,
185
+ screens,
186
+ setHeight,
187
+ style,
188
+ testID,
189
+ ] );
171
190
  }
172
191
 
173
192
  export default BottomSheetNavigationContainer;
@@ -6,13 +6,17 @@ import {
6
6
  useNavigation,
7
7
  useFocusEffect,
8
8
  } from '@react-navigation/native';
9
- import { View, ScrollView, TouchableHighlight } from 'react-native';
9
+ import {
10
+ ScrollView,
11
+ TouchableHighlight,
12
+ useWindowDimensions,
13
+ View,
14
+ } from 'react-native';
10
15
 
11
16
  /**
12
17
  * WordPress dependencies
13
18
  */
14
19
  import { BottomSheetContext } from '@wordpress/components';
15
- import { debounce } from '@wordpress/compose';
16
20
  import { useRef, useCallback, useContext, useMemo } from '@wordpress/element';
17
21
 
18
22
  /**
@@ -29,7 +33,7 @@ const BottomSheetNavigationScreen = ( {
29
33
  name,
30
34
  } ) => {
31
35
  const navigation = useNavigation();
32
- const heightRef = useRef( { maxHeight: 0 } );
36
+ const maxHeight = useRef( 0 );
33
37
  const isFocused = useIsFocused();
34
38
  const {
35
39
  onHandleHardwareButtonPress,
@@ -38,16 +42,10 @@ const BottomSheetNavigationScreen = ( {
38
42
  listProps,
39
43
  safeAreaBottomInset,
40
44
  } = useContext( BottomSheetContext );
45
+ const { height: windowHeight } = useWindowDimensions();
41
46
 
42
47
  const { setHeight } = useContext( BottomSheetNavigationContext );
43
48
 
44
- // Disable reason: deferring this refactor to the native team.
45
- // see https://github.com/WordPress/gutenberg/pull/41166
46
- // eslint-disable-next-line react-hooks/exhaustive-deps
47
- const setHeightDebounce = useCallback( debounce( setHeight, 10 ), [
48
- setHeight,
49
- ] );
50
-
51
49
  useFocusEffect(
52
50
  useCallback( () => {
53
51
  onHandleHardwareButtonPress( () => {
@@ -81,17 +79,14 @@ const BottomSheetNavigationScreen = ( {
81
79
  useFocusEffect(
82
80
  useCallback( () => {
83
81
  if ( fullScreen ) {
84
- setHeight( '100%' );
82
+ setHeight( windowHeight );
85
83
  setIsFullScreen( true );
86
- } else if ( heightRef.current.maxHeight !== 0 ) {
84
+ } else if ( maxHeight.current !== 0 ) {
87
85
  setIsFullScreen( false );
88
- setHeight( heightRef.current.maxHeight );
86
+ setHeight( maxHeight.current );
89
87
  }
90
88
  return () => {};
91
- // Disable reason: deferring this refactor to the native team.
92
- // see https://github.com/WordPress/gutenberg/pull/41166
93
- // eslint-disable-next-line react-hooks/exhaustive-deps
94
- }, [ setHeight ] )
89
+ }, [ fullScreen, setHeight, setIsFullScreen, windowHeight ] )
95
90
  );
96
91
 
97
92
  const onLayout = ( { nativeEvent } ) => {
@@ -99,10 +94,9 @@ const BottomSheetNavigationScreen = ( {
99
94
  return;
100
95
  }
101
96
  const { height } = nativeEvent.layout;
102
-
103
- if ( heightRef.current.maxHeight !== height && isFocused ) {
104
- heightRef.current.maxHeight = height;
105
- setHeightDebounce( height );
97
+ if ( maxHeight.current !== height && isFocused ) {
98
+ maxHeight.current = height;
99
+ setHeight( height );
106
100
  }
107
101
  };
108
102