@wordpress/components 23.8.0 → 23.9.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 (142) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/build/checkbox-control/index.js +2 -2
  3. package/build/checkbox-control/index.js.map +1 -1
  4. package/build/color-palette/index.native.js +12 -0
  5. package/build/color-palette/index.native.js.map +1 -1
  6. package/build/custom-gradient-picker/index.native.js +3 -1
  7. package/build/custom-gradient-picker/index.native.js.map +1 -1
  8. package/build/draggable/index.js +6 -1
  9. package/build/draggable/index.js.map +1 -1
  10. package/build/index.js.map +1 -1
  11. package/build/mobile/bottom-sheet/cell.native.js +6 -6
  12. package/build/mobile/bottom-sheet/cell.native.js.map +1 -1
  13. package/build/mobile/color-settings/palette.screen.native.js +0 -8
  14. package/build/mobile/color-settings/palette.screen.native.js.map +1 -1
  15. package/build/mobile/global-styles-context/utils.native.js +21 -4
  16. package/build/mobile/global-styles-context/utils.native.js.map +1 -1
  17. package/build/mobile/segmented-control/index.native.js +4 -2
  18. package/build/mobile/segmented-control/index.native.js.map +1 -1
  19. package/build/navigator/navigator-screen/component.js +1 -1
  20. package/build/navigator/navigator-screen/component.js.map +1 -1
  21. package/build/popover/index.js +1 -8
  22. package/build/popover/index.js.map +1 -1
  23. package/build/private-apis.js +4 -1
  24. package/build/private-apis.js.map +1 -1
  25. package/build/sandbox/index.native.js +5 -2
  26. package/build/sandbox/index.native.js.map +1 -1
  27. package/build/slot-fill/index.js +20 -7
  28. package/build/slot-fill/index.js.map +1 -1
  29. package/build/spinner/styles.js +4 -4
  30. package/build/spinner/styles.js.map +1 -1
  31. package/build/tree-grid/index.js +3 -3
  32. package/build/tree-grid/index.js.map +1 -1
  33. package/build/view/component.js +1 -2
  34. package/build/view/component.js.map +1 -1
  35. package/build-module/checkbox-control/index.js +2 -2
  36. package/build-module/checkbox-control/index.js.map +1 -1
  37. package/build-module/color-palette/index.native.js +13 -1
  38. package/build-module/color-palette/index.native.js.map +1 -1
  39. package/build-module/custom-gradient-picker/index.native.js +3 -1
  40. package/build-module/custom-gradient-picker/index.native.js.map +1 -1
  41. package/build-module/draggable/index.js +6 -1
  42. package/build-module/draggable/index.js.map +1 -1
  43. package/build-module/index.js.map +1 -1
  44. package/build-module/mobile/bottom-sheet/cell.native.js +6 -5
  45. package/build-module/mobile/bottom-sheet/cell.native.js.map +1 -1
  46. package/build-module/mobile/color-settings/palette.screen.native.js +0 -8
  47. package/build-module/mobile/color-settings/palette.screen.native.js.map +1 -1
  48. package/build-module/mobile/global-styles-context/utils.native.js +21 -3
  49. package/build-module/mobile/global-styles-context/utils.native.js.map +1 -1
  50. package/build-module/mobile/segmented-control/index.native.js +4 -2
  51. package/build-module/mobile/segmented-control/index.native.js.map +1 -1
  52. package/build-module/navigator/navigator-screen/component.js +1 -1
  53. package/build-module/navigator/navigator-screen/component.js.map +1 -1
  54. package/build-module/popover/index.js +1 -8
  55. package/build-module/popover/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/sandbox/index.native.js +5 -2
  59. package/build-module/sandbox/index.native.js.map +1 -1
  60. package/build-module/slot-fill/index.js +16 -6
  61. package/build-module/slot-fill/index.js.map +1 -1
  62. package/build-module/spinner/styles.js +4 -4
  63. package/build-module/spinner/styles.js.map +1 -1
  64. package/build-module/tree-grid/index.js +3 -3
  65. package/build-module/tree-grid/index.js.map +1 -1
  66. package/build-module/view/component.js +1 -2
  67. package/build-module/view/component.js.map +1 -1
  68. package/build-style/style-rtl.css +25 -15
  69. package/build-style/style.css +25 -15
  70. package/build-types/box-control/styles/box-control-styles.d.ts +1 -1
  71. package/build-types/button/deprecated.d.ts +6 -6
  72. package/build-types/checkbox-control/index.d.ts.map +1 -1
  73. package/build-types/color-palette/styles.d.ts +1 -1
  74. package/build-types/color-picker/styles.d.ts +3 -3
  75. package/build-types/date-time/date/styles.d.ts +1 -1
  76. package/build-types/date-time/time/styles.d.ts +4 -4
  77. package/build-types/draggable/index.d.ts +1 -1
  78. package/build-types/draggable/index.d.ts.map +1 -1
  79. package/build-types/draggable/stories/index.d.ts +8 -0
  80. package/build-types/draggable/stories/index.d.ts.map +1 -1
  81. package/build-types/draggable/types.d.ts +7 -0
  82. package/build-types/draggable/types.d.ts.map +1 -1
  83. package/build-types/focal-point-picker/styles/focal-point-picker-style.d.ts +1 -1
  84. package/build-types/index.d.ts +1 -0
  85. package/build-types/index.d.ts.map +1 -1
  86. package/build-types/navigation/styles/navigation-styles.d.ts +1 -1
  87. package/build-types/navigator/navigator-back-button/component.d.ts +1 -1
  88. package/build-types/navigator/navigator-back-button/hook.d.ts +1 -1
  89. package/build-types/navigator/navigator-button/component.d.ts +1 -1
  90. package/build-types/navigator/navigator-button/hook.d.ts +1 -1
  91. package/build-types/navigator/navigator-screen/component.d.ts +1 -1
  92. package/build-types/navigator/navigator-screen/component.d.ts.map +1 -1
  93. package/build-types/navigator/navigator-to-parent-button/component.d.ts +1 -1
  94. package/build-types/number-control/index.d.ts +1 -1
  95. package/build-types/number-control/stories/index.d.ts +1 -1
  96. package/build-types/palette-edit/styles.d.ts +16 -10
  97. package/build-types/palette-edit/styles.d.ts.map +1 -1
  98. package/build-types/popover/index.d.ts +1 -1
  99. package/build-types/popover/index.d.ts.map +1 -1
  100. package/build-types/popover/stories/e2e/index.d.ts +1 -1
  101. package/build-types/private-apis.d.ts.map +1 -1
  102. package/build-types/range-control/styles/range-control-styles.d.ts +1 -1
  103. package/build-types/slot-fill/index.d.ts +13 -1
  104. package/build-types/slot-fill/index.d.ts.map +1 -1
  105. package/build-types/spinner/styles.d.ts.map +1 -1
  106. package/build-types/toolbar/toolbar-button/index.d.ts +6 -6
  107. package/build-types/tree-grid/index.d.ts.map +1 -1
  108. package/build-types/ui/context/wordpress-component.d.ts +1 -1
  109. package/build-types/ui/context/wordpress-component.d.ts.map +1 -1
  110. package/build-types/unit-control/index.d.ts +1 -1
  111. package/build-types/unit-control/styles/unit-control-styles.d.ts +1 -1
  112. package/build-types/view/component.d.ts +1 -1
  113. package/build-types/view/component.d.ts.map +1 -1
  114. package/package.json +21 -22
  115. package/src/autocomplete/README.md +4 -2
  116. package/src/checkbox-control/index.tsx +6 -2
  117. package/src/color-palette/index.native.js +20 -1
  118. package/src/color-picker/test/index.tsx +99 -99
  119. package/src/custom-gradient-picker/index.native.js +1 -1
  120. package/src/dimension-control/README.md +1 -1
  121. package/src/draggable/README.md +8 -1
  122. package/src/draggable/index.tsx +6 -1
  123. package/src/draggable/stories/index.tsx +69 -33
  124. package/src/draggable/types.ts +7 -0
  125. package/src/index.ts +1 -0
  126. package/src/mobile/bottom-sheet/cell.native.js +4 -5
  127. package/src/mobile/color-settings/palette.screen.native.js +0 -7
  128. package/src/mobile/global-styles-context/utils.native.js +18 -3
  129. package/src/mobile/segmented-control/index.native.js +2 -2
  130. package/src/modal/style.scss +20 -12
  131. package/src/navigator/navigator-screen/component.tsx +1 -1
  132. package/src/popover/index.tsx +2 -15
  133. package/src/private-apis.ts +2 -0
  134. package/src/sandbox/index.native.js +8 -1
  135. package/src/slot-fill/index.js +14 -6
  136. package/src/snackbar/style.scss +2 -1
  137. package/src/spinner/styles.ts +2 -0
  138. package/src/tree-grid/index.tsx +7 -2
  139. package/src/ui/context/wordpress-component.ts +1 -1
  140. package/src/view/component.tsx +2 -2
  141. package/tsconfig.json +2 -2
  142. package/tsconfig.tsbuildinfo +1 -1
@@ -1,49 +1,14 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { render, fireEvent, waitFor } from '@testing-library/react';
4
+ import { screen, render } from '@testing-library/react';
5
+ import userEvent from '@testing-library/user-event';
5
6
 
6
7
  /**
7
8
  * Internal dependencies
8
9
  */
9
10
  import { ColorPicker } from '..';
10
11
 
11
- /**
12
- * Ordinarily we'd try to select the component by role but the slider role appears
13
- * on several elements and we'd end up encoding assumptions about order when
14
- * trying to select the appropriate element. We might as well just use the class name
15
- * on the container which will be more durable if, for example, the order changes.
16
- */
17
- function getSaturation( container: HTMLElement ) {
18
- return container.querySelector(
19
- '.react-colorful__saturation .react-colorful__interactive'
20
- );
21
- }
22
-
23
- type PageXPageY = { pageX: number; pageY: number };
24
-
25
- // Fix to pass `pageX` and `pageY`
26
- // See https://github.com/testing-library/react-testing-library/issues/268
27
- class FakeMouseEvent extends MouseEvent {
28
- constructor( type: MouseEvent[ 'type' ], values?: PageXPageY ) {
29
- super( type, { buttons: 1, bubbles: true, ...values } );
30
-
31
- Object.assign( this, {
32
- pageX: values?.pageX ?? 0,
33
- pageY: values?.pageY ?? 0,
34
- } );
35
- }
36
- }
37
-
38
- function moveReactColorfulSlider(
39
- sliderElement: Element,
40
- from: PageXPageY,
41
- to: PageXPageY
42
- ) {
43
- fireEvent( sliderElement, new FakeMouseEvent( 'mousedown', from ) );
44
- fireEvent( sliderElement, new FakeMouseEvent( 'mousemove', to ) );
45
- }
46
-
47
12
  const hslaMatcher = expect.objectContaining( {
48
13
  h: expect.any( Number ),
49
14
  s: expect.any( Number ),
@@ -73,99 +38,134 @@ const legacyColorMatcher = {
73
38
  describe( 'ColorPicker', () => {
74
39
  describe( 'legacy props', () => {
75
40
  it( 'should fire onChangeComplete with the legacy color format', async () => {
41
+ const user = userEvent.setup();
76
42
  const onChangeComplete = jest.fn();
77
- const color = '#fff';
43
+ const color = '#000';
78
44
 
79
- const { container } = render(
45
+ render(
80
46
  <ColorPicker
81
47
  onChangeComplete={ onChangeComplete }
82
48
  color={ color }
49
+ enableAlpha={ false }
83
50
  />
84
51
  );
85
52
 
86
- const saturation = getSaturation( container );
87
-
88
- if ( saturation === null ) {
89
- throw new Error( 'The saturation slider could not be found' );
90
- }
53
+ const formatSelector = screen.getByRole( 'combobox' );
54
+ expect( formatSelector ).toBeVisible();
91
55
 
92
- expect( saturation ).toBeInTheDocument();
56
+ await user.selectOptions( formatSelector, 'hex' );
93
57
 
94
- moveReactColorfulSlider(
95
- saturation,
96
- { pageX: 0, pageY: 0 },
97
- { pageX: 10, pageY: 10 }
98
- );
58
+ const hexInput = screen.getByRole( 'textbox' );
59
+ expect( hexInput ).toBeVisible();
99
60
 
100
- await waitFor( () =>
101
- expect( onChangeComplete ).toHaveBeenCalled()
102
- );
61
+ await user.clear( hexInput );
62
+ await user.type( hexInput, '1ab' );
103
63
 
104
- expect( onChangeComplete ).toHaveBeenCalledWith(
64
+ expect( onChangeComplete ).toHaveBeenCalledTimes( 3 );
65
+ expect( onChangeComplete ).toHaveBeenLastCalledWith(
105
66
  legacyColorMatcher
106
67
  );
107
68
  } );
108
69
  } );
70
+ describe( 'Hex input', () => {
71
+ it( 'should fire onChange with the correct value from the hex input', async () => {
72
+ const user = userEvent.setup();
73
+ const onChange = jest.fn();
74
+ const color = '#000';
75
+
76
+ render(
77
+ <ColorPicker
78
+ onChange={ onChange }
79
+ color={ color }
80
+ enableAlpha={ false }
81
+ />
82
+ );
83
+
84
+ const formatSelector = screen.getByRole( 'combobox' );
85
+ expect( formatSelector ).toBeVisible();
86
+
87
+ await user.selectOptions( formatSelector, 'hex' );
109
88
 
110
- it( 'should fire onChange with the string value', async () => {
111
- const onChange = jest.fn();
112
- const color = 'rgba(1, 1, 1, 0.5)';
89
+ const hexInput = screen.getByRole( 'textbox' );
90
+ expect( hexInput ).toBeVisible();
113
91
 
114
- const { container } = render(
115
- <ColorPicker onChange={ onChange } color={ color } enableAlpha />
116
- );
92
+ await user.clear( hexInput );
93
+ await user.type( hexInput, '1ab' );
117
94
 
118
- const saturation = getSaturation( container );
95
+ expect( onChange ).toHaveBeenCalledTimes( 3 );
96
+ expect( onChange ).toHaveBeenLastCalledWith( '#11aabb' );
97
+ } );
98
+ } );
119
99
 
120
- if ( saturation === null ) {
121
- throw new Error( 'The saturation slider could not be found' );
122
- }
100
+ describe.each( [
101
+ [ 'red', 'Red', '#7dffff' ],
102
+ [ 'green', 'Green', '#ff7dff' ],
103
+ [ 'blue', 'Blue', '#ffff7d' ],
104
+ ] )( 'RGB inputs', ( colorInput, inputLabel, expected ) => {
105
+ it( `should fire onChange with the correct value when the ${ colorInput } value is updated`, async () => {
106
+ const user = userEvent.setup();
107
+ const onChange = jest.fn();
108
+ const color = '#fff';
123
109
 
124
- expect( saturation ).toBeInTheDocument();
110
+ render(
111
+ <ColorPicker
112
+ onChange={ onChange }
113
+ color={ color }
114
+ enableAlpha={ false }
115
+ />
116
+ );
125
117
 
126
- moveReactColorfulSlider(
127
- saturation,
128
- { pageX: 0, pageY: 0 },
129
- { pageX: 10, pageY: 10 }
130
- );
118
+ const formatSelector = screen.getByRole( 'combobox' );
119
+ expect( formatSelector ).toBeVisible();
131
120
 
132
- await waitFor( () => expect( onChange ).toHaveBeenCalled() );
121
+ await user.selectOptions( formatSelector, 'rgb' );
133
122
 
134
- expect( onChange ).toHaveBeenCalledWith(
135
- expect.stringMatching( /^#([a-fA-F0-9]{8})$/ )
136
- );
137
- } );
123
+ const inputElement = screen.getByRole( 'spinbutton', {
124
+ name: inputLabel,
125
+ } );
126
+ expect( inputElement ).toBeVisible();
138
127
 
139
- it( 'should fire onChange with the HSL value', async () => {
140
- const onChange = jest.fn();
141
- const color = 'hsla(125, 20%, 50%, 0.5)';
128
+ await user.clear( inputElement );
129
+ await user.type( inputElement, '125' );
142
130
 
143
- const { container } = render(
144
- <ColorPicker
145
- onChange={ onChange }
146
- color={ color }
147
- enableAlpha={ false }
148
- />
149
- );
131
+ expect( onChange ).toHaveBeenCalledTimes( 4 );
132
+ expect( onChange ).toHaveBeenLastCalledWith( expected );
133
+ } );
134
+ } );
150
135
 
151
- const saturation = getSaturation( container );
136
+ describe.each( [
137
+ [ 'hue', 'Hue', '#aad52a' ],
138
+ [ 'saturation', 'Saturation', '#20dfdf' ],
139
+ [ 'lightness', 'Lightness', '#95eaea' ],
140
+ ] )( 'HSL inputs', ( colorInput, inputLabel, expected ) => {
141
+ it( `should fire onChange with the correct value when the ${ colorInput } value is updated`, async () => {
142
+ const user = userEvent.setup();
143
+ const onChange = jest.fn();
144
+ const color = '#2ad5d5';
145
+
146
+ render(
147
+ <ColorPicker
148
+ onChange={ onChange }
149
+ color={ color }
150
+ enableAlpha={ false }
151
+ />
152
+ );
152
153
 
153
- if ( saturation === null ) {
154
- throw new Error( 'The saturation slider could not be found' );
155
- }
154
+ const formatSelector = screen.getByRole( 'combobox' );
155
+ expect( formatSelector ).toBeVisible();
156
156
 
157
- expect( saturation ).toBeInTheDocument();
157
+ await user.selectOptions( formatSelector, 'hsl' );
158
158
 
159
- moveReactColorfulSlider(
160
- saturation,
161
- { pageX: 0, pageY: 0 },
162
- { pageX: 10, pageY: 10 }
163
- );
159
+ const inputElement = screen.getByRole( 'spinbutton', {
160
+ name: inputLabel,
161
+ } );
162
+ expect( inputElement ).toBeVisible();
164
163
 
165
- await waitFor( () => expect( onChange ).toHaveBeenCalled() );
164
+ await user.clear( inputElement );
165
+ await user.type( inputElement, '75' );
166
166
 
167
- expect( onChange ).toHaveBeenCalledWith(
168
- expect.stringMatching( /^#([a-fA-F0-9]{6})$/ )
169
- );
167
+ expect( onChange ).toHaveBeenCalledTimes( 3 );
168
+ expect( onChange ).toHaveBeenLastCalledWith( expected );
169
+ } );
170
170
  } );
171
171
  } );
@@ -25,7 +25,7 @@ function CustomGradientPicker( { setColor, currentValue, isGradientColor } ) {
25
25
  const [ currentColor, setCurrentColor ] = useState( currentValue );
26
26
 
27
27
  const { getGradientType, gradients, gradientOptions } = colorsUtils;
28
- const gradientAST = getGradientAstWithDefault( currentColor );
28
+ const { gradientAST } = getGradientAstWithDefault( currentColor );
29
29
  const gradientType = getGradientType( currentColor );
30
30
 
31
31
  function isLinearGradient( type ) {
@@ -9,8 +9,8 @@ This feature is still experimental. “Experimental” means this is an early im
9
9
  ## Usage
10
10
 
11
11
  ```jsx
12
- import { useState } from 'react';
13
12
  import { __experimentalDimensionControl as DimensionControl } from '@wordpress/components';
13
+ import { useState } from '@wordpress/element';
14
14
 
15
15
  export default function MyCustomDimensionControl() {
16
16
  const [ paddingSize, setPaddingSize ] = useState( '' );
@@ -8,9 +8,16 @@ Note that the drag handle needs to declare the `draggable="true"` property and b
8
8
 
9
9
  The component accepts the following props:
10
10
 
11
+ ### `appendToOwnerDocument`: `boolean`
12
+
13
+ Whether to append the cloned element to the `ownerDocument` body. By default, elements sourced by id are appended to the element's wrapper.
14
+
15
+ - Required: No
16
+ - Default: `false`
17
+
11
18
  ### `elementId`: `string`
12
19
 
13
- The HTML id of the element to clone on drag
20
+ The HTML id of the element to clone on drag.
14
21
 
15
22
  - Required: Yes
16
23
 
@@ -63,6 +63,7 @@ export function Draggable( {
63
63
  onDragStart,
64
64
  onDragOver,
65
65
  onDragEnd,
66
+ appendToOwnerDocument = false,
66
67
  cloneClassname,
67
68
  elementId,
68
69
  transferData,
@@ -173,7 +174,11 @@ export function Draggable( {
173
174
  cloneWrapper.appendChild( clone );
174
175
 
175
176
  // Inject the cloneWrapper into the DOM.
176
- elementWrapper?.appendChild( cloneWrapper );
177
+ if ( appendToOwnerDocument ) {
178
+ ownerDocument.body.appendChild( cloneWrapper );
179
+ } else {
180
+ elementWrapper?.appendChild( cloneWrapper );
181
+ }
177
182
  }
178
183
 
179
184
  // Mark the current cursor coordinates.
@@ -7,6 +7,7 @@ import type { DragEvent } from 'react';
7
7
  /**
8
8
  * WordPress dependencies
9
9
  */
10
+ import { useInstanceId } from '@wordpress/compose';
10
11
  import { useState } from '@wordpress/element';
11
12
  import { Icon, more } from '@wordpress/icons';
12
13
 
@@ -32,46 +33,68 @@ export default meta;
32
33
 
33
34
  const DefaultTemplate: ComponentStory< typeof Draggable > = ( args ) => {
34
35
  const [ isDragging, setDragging ] = useState( false );
36
+ const instanceId = useInstanceId( DefaultTemplate );
35
37
 
36
38
  // Allow for the use of ID in the example.
37
39
  return (
38
40
  <div>
39
- <p>Is Dragging? { isDragging ? 'Yes' : 'No!' }</p>
41
+ <p
42
+ style={ {
43
+ padding: '1em',
44
+ position: 'relative',
45
+ zIndex: 1000,
46
+ backgroundColor: 'whitesmoke',
47
+ } }
48
+ >
49
+ Is Dragging? { isDragging ? 'Yes' : 'No!' }
50
+ </p>
40
51
  <div
41
- /* eslint-disable no-restricted-syntax, eslint-comments/disable-enable-pair */
42
- id="draggable-example-box"
43
- style={ { display: 'inline-flex' } }
52
+ style={ {
53
+ zIndex: 100,
54
+ position: 'relative',
55
+ } }
44
56
  >
45
- <Draggable { ...args } elementId="draggable-example-box">
46
- { ( { onDraggableStart, onDraggableEnd } ) => {
47
- const handleOnDragStart = ( event: DragEvent ) => {
48
- setDragging( true );
49
- onDraggableStart( event );
50
- };
51
- const handleOnDragEnd = ( event: DragEvent ) => {
52
- setDragging( false );
53
- onDraggableEnd( event );
54
- };
55
-
56
- return (
57
- <div
58
- onDragStart={ handleOnDragStart }
59
- onDragEnd={ handleOnDragEnd }
60
- draggable
61
- style={ {
62
- alignItems: 'center',
63
- display: 'flex',
64
- justifyContent: 'center',
65
- width: 100,
66
- height: 100,
67
- background: '#ddd',
68
- } }
69
- >
70
- <Icon icon={ more } />
71
- </div>
72
- );
57
+ <div
58
+ id={ `draggable-example-box-${ instanceId }` }
59
+ style={ {
60
+ display: 'inline-flex',
61
+ position: 'relative',
73
62
  } }
74
- </Draggable>
63
+ >
64
+ <Draggable
65
+ { ...args }
66
+ elementId={ `draggable-example-box-${ instanceId }` }
67
+ >
68
+ { ( { onDraggableStart, onDraggableEnd } ) => {
69
+ const handleOnDragStart = ( event: DragEvent ) => {
70
+ setDragging( true );
71
+ onDraggableStart( event );
72
+ };
73
+ const handleOnDragEnd = ( event: DragEvent ) => {
74
+ setDragging( false );
75
+ onDraggableEnd( event );
76
+ };
77
+
78
+ return (
79
+ <div
80
+ onDragStart={ handleOnDragStart }
81
+ onDragEnd={ handleOnDragEnd }
82
+ draggable
83
+ style={ {
84
+ alignItems: 'center',
85
+ display: 'flex',
86
+ justifyContent: 'center',
87
+ width: 100,
88
+ height: 100,
89
+ background: '#ddd',
90
+ } }
91
+ >
92
+ <Icon icon={ more } />
93
+ </div>
94
+ );
95
+ } }
96
+ </Draggable>
97
+ </div>
75
98
  </div>
76
99
  </div>
77
100
  );
@@ -81,3 +104,16 @@ export const Default: ComponentStory< typeof Draggable > = DefaultTemplate.bind(
81
104
  {}
82
105
  );
83
106
  Default.args = {};
107
+
108
+ /**
109
+ * `appendToOwnerDocument` is used to append the element being dragged to the body of the owner document.
110
+ *
111
+ * This is useful when the element being dragged should not receive styles from its parent.
112
+ * For example, when the element's parent sets a `z-index` value that would cause the dragged
113
+ * element to be rendered behind other elements.
114
+ */
115
+ export const AppendElementToOwnerDocument: ComponentStory< typeof Draggable > =
116
+ DefaultTemplate.bind( {} );
117
+ AppendElementToOwnerDocument.args = {
118
+ appendToOwnerDocument: true,
119
+ };
@@ -17,6 +17,13 @@ export type DraggableProps = {
17
17
  */
18
18
  onDraggableEnd: ( event: DragEvent ) => void;
19
19
  } ) => JSX.Element | null;
20
+ /**
21
+ * Whether to append the cloned element to the `ownerDocument` body.
22
+ * By default, elements sourced by id are appended to the element's wrapper.
23
+ *
24
+ * @default false
25
+ */
26
+ appendToOwnerDocument?: boolean;
20
27
  /**
21
28
  * Classname for the cloned element.
22
29
  */
package/src/index.ts CHANGED
@@ -90,6 +90,7 @@ export { default as GuidePage } from './guide/page';
90
90
  export { Heading as __experimentalHeading } from './heading';
91
91
  export { HStack as __experimentalHStack } from './h-stack';
92
92
  export { default as Icon } from './icon';
93
+ export type { IconType } from './icon';
93
94
  export { default as IconButton } from './button/deprecated';
94
95
  export {
95
96
  ItemGroup as __experimentalItemGroup,
@@ -10,7 +10,6 @@ import {
10
10
  AccessibilityInfo,
11
11
  Platform,
12
12
  } from 'react-native';
13
- import { isEmpty, get } from 'lodash';
14
13
 
15
14
  /**
16
15
  * WordPress dependencies
@@ -273,8 +272,8 @@ class BottomSheetCell extends Component {
273
272
  return accessibilityLabel || label;
274
273
  }
275
274
 
276
- if ( isEmpty( value ) ) {
277
- return isEmpty( help )
275
+ if ( ! value ) {
276
+ return ! help
278
277
  ? sprintf(
279
278
  /* translators: accessibility text. Empty state of a inline textinput cell. %s: The cell's title */
280
279
  _x( '%s. Empty', 'inline textinput cell' ),
@@ -288,7 +287,7 @@ class BottomSheetCell extends Component {
288
287
  help
289
288
  );
290
289
  }
291
- return isEmpty( help )
290
+ return ! help
292
291
  ? sprintf(
293
292
  /* translators: accessibility text. Inline textinput title and value.%1: Cell title, %2: cell value. */
294
293
  _x( '%1$s, %2$s', 'inline textinput cell' ),
@@ -323,7 +322,7 @@ class BottomSheetCell extends Component {
323
322
  const opacity =
324
323
  activeOpacity !== undefined
325
324
  ? activeOpacity
326
- : get( platformStyles, 'activeOpacity.opacity' );
325
+ : platformStyles.activeOpacity?.opacity;
327
326
 
328
327
  return (
329
328
  <TouchableRipple
@@ -78,22 +78,15 @@ const PaletteScreen = () => {
78
78
  setCurrentValue( color );
79
79
  if ( isSolidSegment && onColorChange && onGradientChange ) {
80
80
  onColorChange( color );
81
- onGradientChange( '' );
82
81
  } else if ( isSolidSegment && onColorChange ) {
83
82
  onColorChange( color );
84
83
  } else if ( ! isSolidSegment && onGradientChange ) {
85
84
  onGradientChange( color );
86
- onColorChange( '' );
87
85
  }
88
86
  };
89
87
 
90
88
  function onClear() {
91
89
  setCurrentValue( undefined );
92
- if ( isSolidSegment ) {
93
- onColorChange( '' );
94
- } else {
95
- onGradientChange( '' );
96
- }
97
90
 
98
91
  if ( onColorCleared ) {
99
92
  onColorCleared();
@@ -2,7 +2,6 @@
2
2
  * External dependencies
3
3
  */
4
4
  import { camelCase } from 'change-case';
5
- import { get } from 'lodash';
6
5
  import { Dimensions } from 'react-native';
7
6
 
8
7
  /**
@@ -191,6 +190,22 @@ export function getBlockTypography(
191
190
  return typographyStyles;
192
191
  }
193
192
 
193
+ /**
194
+ * Return a value from a certain path of the object.
195
+ * Path is specified as an array of properties, like: [ 'parent', 'child' ].
196
+ *
197
+ * @param {Object} object Input object.
198
+ * @param {Array} path Path to the object property.
199
+ * @return {*} Value of the object property at the specified path.
200
+ */
201
+ const getValueFromObjectPath = ( object, path ) => {
202
+ let value = object;
203
+ path.forEach( ( fieldName ) => {
204
+ value = value?.[ fieldName ];
205
+ } );
206
+ return value;
207
+ };
208
+
194
209
  export function parseStylesVariables( styles, mappedValues, customValues ) {
195
210
  let stylesBase = styles;
196
211
  const variables = [ 'preset', 'custom', 'var', 'fontSize' ];
@@ -231,11 +246,11 @@ export function parseStylesVariables( styles, mappedValues, customValues ) {
231
246
  customValuesData
232
247
  )
233
248
  ) {
234
- return get( customValuesData, path );
249
+ return getValueFromObjectPath( customValuesData, path );
235
250
  }
236
251
 
237
252
  // Check for camelcase properties.
238
- return get( customValuesData, [
253
+ return getValueFromObjectPath( customValuesData, [
239
254
  ...path.slice( 0, path.length - 1 ),
240
255
  camelCase( path[ path.length - 1 ] ),
241
256
  ] );
@@ -140,8 +140,8 @@ const SegmentedControls = ( {
140
140
  styles.selectedDark
141
141
  );
142
142
 
143
- const width = segmentsDimensions[ activeSegmentIndex ].width;
144
- const height = segmentsDimensions[ activeSegmentIndex ].height;
143
+ const width = segmentsDimensions[ activeSegmentIndex ]?.width;
144
+ const height = segmentsDimensions[ activeSegmentIndex ]?.height;
145
145
 
146
146
  const outlineStyle = [ styles.outline, isIOS && styles.outlineIOS ];
147
147
 
@@ -16,31 +16,39 @@
16
16
  // The modal window element.
17
17
  .components-modal__frame {
18
18
  // Use the entire viewport on smaller screens.
19
- margin: 0;
19
+ margin: $grid-unit-50 0 0 0;
20
20
  width: 100%;
21
21
  background: $white;
22
22
  box-shadow: $shadow-modal;
23
- border-radius: $radius-block-ui;
23
+ border-radius: $grid-unit-10 $grid-unit-10 0 0;
24
24
  overflow: hidden;
25
25
  // Have the content element fill the vertical space yet not overflow.
26
26
  display: flex;
27
+ // Animate the modal frame/contents appearing on the page.
28
+ animation: components-modal__appear-animation 0.1s ease-out;
29
+ animation-fill-mode: forwards;
30
+ @include reduce-motion("animation");
27
31
 
28
32
  // Show a centered modal on bigger screens.
29
33
  @include break-small() {
34
+ border-radius: $grid-unit-10;
30
35
  margin: auto;
31
36
  width: auto;
32
37
  min-width: $modal-min-width;
33
38
  max-width: calc(100% - #{$grid-unit-20 * 2});
34
39
  max-height: calc(100% - #{$header-height * 2});
35
40
 
36
- // Animate the modal frame/contents appearing on the page.
37
- animation: components-modal__appear-animation 0.1s ease-out;
38
- animation-fill-mode: forwards;
39
- @include reduce-motion("animation");
40
-
41
41
  &.is-full-screen {
42
- width: 90vw;
43
- min-height: 90vh;
42
+ @include break-small() {
43
+ width: calc(100% - #{ $grid-unit-20 * 2 });
44
+ height: calc(100% - #{ $grid-unit-20 * 2 });
45
+ max-height: none;
46
+ }
47
+ @include break-medium() {
48
+ width: calc(100% - #{ $grid-unit-50 * 2 });
49
+ height: calc(100% - #{ $grid-unit-50 * 2 });
50
+ max-width: none;
51
+ }
44
52
  }
45
53
  }
46
54
 
@@ -64,12 +72,12 @@
64
72
  .components-modal__header {
65
73
  box-sizing: border-box;
66
74
  border-bottom: $border-width solid transparent;
67
- padding: 0 $grid-unit-40;
75
+ padding: $grid-unit-30 $grid-unit-40 $grid-unit-15;
68
76
  display: flex;
69
77
  flex-direction: row;
70
78
  justify-content: space-between;
71
79
  align-items: center;
72
- height: $header-height + $grid-unit-20;
80
+ height: $header-height + $grid-unit-15;
73
81
  width: 100%;
74
82
  z-index: z-index(".components-modal__header");
75
83
  position: absolute;
@@ -121,7 +129,7 @@
121
129
  // Modal contents.
122
130
  .components-modal__content {
123
131
  flex: 1;
124
- margin-top: $header-height + $grid-unit-20;
132
+ margin-top: $header-height + $grid-unit-15;
125
133
  padding: 0 $grid-unit-40 $grid-unit-40;
126
134
  overflow: auto;
127
135
 
@@ -43,7 +43,7 @@ const animationExitDelay = 0;
43
43
  // as some of them would overlap with HTML props (e.g. `onAnimationStart`, ...)
44
44
  type Props = Omit<
45
45
  WordPressComponentProps< NavigatorScreenProps, 'div', false >,
46
- Exclude< keyof MotionProps, 'style' >
46
+ Exclude< keyof MotionProps, 'style' | 'children' >
47
47
  >;
48
48
 
49
49
  function UnconnectedNavigatorScreen(