@wordpress/components 23.4.0 → 23.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.
- package/CHANGELOG.md +15 -0
- package/build/autocomplete/autocompleter-ui.js +41 -17
- package/build/autocomplete/autocompleter-ui.js.map +1 -1
- package/build/autocomplete/index.js +31 -33
- package/build/autocomplete/index.js.map +1 -1
- package/build/circular-option-picker/index.js +63 -14
- package/build/circular-option-picker/index.js.map +1 -1
- package/build/circular-option-picker/types.js +6 -0
- package/build/circular-option-picker/types.js.map +1 -0
- package/build/dropdown-menu/index.js +6 -2
- package/build/dropdown-menu/index.js.map +1 -1
- package/build/higher-order/with-constrained-tabbing/index.js +9 -0
- package/build/higher-order/with-constrained-tabbing/index.js.map +1 -1
- package/build/mobile/global-styles-context/utils.native.js +2 -1
- package/build/mobile/global-styles-context/utils.native.js.map +1 -1
- package/build/range-control/index.js +1 -0
- package/build/range-control/index.js.map +1 -1
- package/build/tools-panel/context.js +2 -0
- package/build/tools-panel/context.js.map +1 -1
- package/build/tools-panel/tools-panel/hook.js +18 -12
- package/build/tools-panel/tools-panel/hook.js.map +1 -1
- package/build/tools-panel/tools-panel-item/hook.js +14 -2
- package/build/tools-panel/tools-panel-item/hook.js.map +1 -1
- package/build/ui/context/context-system-provider.js +8 -4
- package/build/ui/context/context-system-provider.js.map +1 -1
- package/build-module/autocomplete/autocompleter-ui.js +40 -19
- package/build-module/autocomplete/autocompleter-ui.js.map +1 -1
- package/build-module/autocomplete/index.js +30 -32
- package/build-module/autocomplete/index.js.map +1 -1
- package/build-module/circular-option-picker/index.js +59 -16
- package/build-module/circular-option-picker/index.js.map +1 -1
- package/build-module/circular-option-picker/types.js +2 -0
- package/build-module/circular-option-picker/types.js.map +1 -0
- package/build-module/dropdown-menu/index.js +6 -2
- package/build-module/dropdown-menu/index.js.map +1 -1
- package/build-module/higher-order/with-constrained-tabbing/index.js +9 -0
- package/build-module/higher-order/with-constrained-tabbing/index.js.map +1 -1
- package/build-module/mobile/global-styles-context/utils.native.js +2 -1
- package/build-module/mobile/global-styles-context/utils.native.js.map +1 -1
- package/build-module/range-control/index.js +1 -0
- package/build-module/range-control/index.js.map +1 -1
- package/build-module/tools-panel/context.js +2 -0
- package/build-module/tools-panel/context.js.map +1 -1
- package/build-module/tools-panel/tools-panel/hook.js +18 -12
- package/build-module/tools-panel/tools-panel/hook.js.map +1 -1
- package/build-module/tools-panel/tools-panel-item/hook.js +14 -2
- package/build-module/tools-panel/tools-panel-item/hook.js.map +1 -1
- package/build-module/ui/context/context-system-provider.js +7 -4
- package/build-module/ui/context/context-system-provider.js.map +1 -1
- package/build-style/style-rtl.css +1 -0
- package/build-style/style.css +1 -0
- package/build-types/circular-option-picker/index.d.ts +56 -7
- package/build-types/circular-option-picker/index.d.ts.map +1 -1
- package/build-types/circular-option-picker/stories/index.d.ts +14 -0
- package/build-types/circular-option-picker/stories/index.d.ts.map +1 -0
- package/build-types/circular-option-picker/types.d.ts +49 -0
- package/build-types/circular-option-picker/types.d.ts.map +1 -0
- package/build-types/dropdown-menu/index.d.ts.map +1 -1
- package/build-types/h-stack/stories/e2e/index.d.ts +9 -0
- package/build-types/h-stack/stories/e2e/index.d.ts.map +1 -0
- package/build-types/higher-order/with-constrained-tabbing/index.d.ts +10 -1
- package/build-types/higher-order/with-constrained-tabbing/index.d.ts.map +1 -1
- package/build-types/range-control/index.d.ts.map +1 -1
- package/build-types/tab-panel/stories/index.d.ts +1 -0
- package/build-types/tab-panel/stories/index.d.ts.map +1 -1
- package/build-types/tools-panel/context.d.ts.map +1 -1
- package/build-types/tools-panel/test/index.d.ts +2 -0
- package/build-types/tools-panel/test/index.d.ts.map +1 -0
- package/build-types/tools-panel/tools-panel/hook.d.ts +3 -1
- package/build-types/tools-panel/tools-panel/hook.d.ts.map +1 -1
- package/build-types/tools-panel/tools-panel-header/hook.d.ts +1 -1
- package/build-types/tools-panel/tools-panel-item/component.d.ts +1 -0
- package/build-types/tools-panel/tools-panel-item/component.d.ts.map +1 -1
- package/build-types/tools-panel/tools-panel-item/hook.d.ts.map +1 -1
- package/build-types/tools-panel/types.d.ts +11 -9
- package/build-types/tools-panel/types.d.ts.map +1 -1
- package/build-types/ui/context/context-system-provider.d.ts.map +1 -1
- package/build-types/v-stack/stories/e2e/index.d.ts +9 -0
- package/build-types/v-stack/stories/e2e/index.d.ts.map +1 -0
- package/package.json +23 -21
- package/src/autocomplete/autocompleter-ui.js +72 -34
- package/src/autocomplete/index.js +36 -36
- package/src/circular-option-picker/README.md +141 -0
- package/src/circular-option-picker/{index.js → index.tsx} +74 -14
- package/src/circular-option-picker/stories/index.tsx +134 -0
- package/src/circular-option-picker/types.ts +69 -0
- package/src/color-palette/test/__snapshots__/index.tsx.snap +1 -1
- package/src/dropdown-menu/index.js +6 -3
- package/src/h-stack/stories/e2e/index.tsx +36 -0
- package/src/higher-order/navigate-regions/style.scss +2 -1
- package/src/higher-order/with-constrained-tabbing/index.tsx +30 -0
- package/src/mobile/global-styles-context/utils.native.js +1 -0
- package/src/range-control/index.tsx +5 -1
- package/src/tab-panel/stories/index.tsx +41 -0
- package/src/tab-panel/test/index.tsx +794 -262
- package/src/tools-panel/context.ts +2 -0
- package/src/tools-panel/test/{index.js → index.tsx} +171 -61
- package/src/tools-panel/tools-panel/hook.ts +30 -11
- package/src/tools-panel/tools-panel-item/hook.ts +18 -2
- package/src/tools-panel/types.ts +12 -9
- package/src/tree-grid/test/__snapshots__/index.tsx.snap +1 -1
- package/src/ui/context/context-system-provider.js +7 -4
- package/src/v-stack/stories/e2e/index.tsx +36 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/src/higher-order/with-constrained-tabbing/index.js +0 -22
|
@@ -18,6 +18,8 @@ export const ToolsPanelContext = createContext< ToolsPanelContextType >( {
|
|
|
18
18
|
registerPanelItem: noop,
|
|
19
19
|
deregisterPanelItem: noop,
|
|
20
20
|
flagItemCustomization: noop,
|
|
21
|
+
registerResetAllFilter: noop,
|
|
22
|
+
deregisterResetAllFilter: noop,
|
|
21
23
|
areAllOptionalControlsHidden: true,
|
|
22
24
|
} );
|
|
23
25
|
|
|
@@ -9,11 +9,17 @@ import userEvent from '@testing-library/user-event';
|
|
|
9
9
|
*/
|
|
10
10
|
import { ToolsPanel, ToolsPanelContext, ToolsPanelItem } from '../';
|
|
11
11
|
import { createSlotFill, Provider as SlotFillProvider } from '../../slot-fill';
|
|
12
|
+
import type {
|
|
13
|
+
ToolsPanelContext as ToolsPanelContextType,
|
|
14
|
+
ResetAllFilter,
|
|
15
|
+
} from '../types';
|
|
12
16
|
|
|
13
17
|
const { Fill: ToolsPanelItems, Slot } = createSlotFill( 'ToolsPanelSlot' );
|
|
14
18
|
const resetAll = jest.fn();
|
|
15
19
|
const noop = () => undefined;
|
|
16
20
|
|
|
21
|
+
type ControlValue = boolean | undefined;
|
|
22
|
+
|
|
17
23
|
// Default props for the tools panel.
|
|
18
24
|
const defaultProps = {
|
|
19
25
|
label: 'Panel header',
|
|
@@ -21,24 +27,24 @@ const defaultProps = {
|
|
|
21
27
|
};
|
|
22
28
|
|
|
23
29
|
// Default props for an enabled control to be rendered within panel.
|
|
30
|
+
let controlValue: ControlValue = true;
|
|
24
31
|
const controlProps = {
|
|
25
|
-
attributes: { value: true },
|
|
26
32
|
hasValue: jest.fn().mockImplementation( () => {
|
|
27
|
-
return !!
|
|
33
|
+
return !! controlValue;
|
|
28
34
|
} ),
|
|
29
35
|
label: 'Example',
|
|
30
36
|
onDeselect: jest.fn().mockImplementation( () => {
|
|
31
|
-
|
|
37
|
+
controlValue = undefined;
|
|
32
38
|
} ),
|
|
33
39
|
onSelect: jest.fn(),
|
|
34
40
|
};
|
|
35
41
|
|
|
36
42
|
// Default props without a value for an alternate control to be rendered within
|
|
37
43
|
// the panel.
|
|
44
|
+
let altControlValue: ControlValue = false;
|
|
38
45
|
const altControlProps = {
|
|
39
|
-
attributes: { value: false },
|
|
40
46
|
hasValue: jest.fn().mockImplementation( () => {
|
|
41
|
-
return !!
|
|
47
|
+
return !! altControlValue;
|
|
42
48
|
} ),
|
|
43
49
|
label: 'Alt',
|
|
44
50
|
onDeselect: jest.fn(),
|
|
@@ -46,24 +52,24 @@ const altControlProps = {
|
|
|
46
52
|
};
|
|
47
53
|
|
|
48
54
|
// Default props for wrapped or grouped panel items.
|
|
55
|
+
let nestedControlValue: ControlValue = true;
|
|
49
56
|
const nestedControlProps = {
|
|
50
|
-
attributes: { value: true },
|
|
51
57
|
hasValue: jest.fn().mockImplementation( () => {
|
|
52
|
-
return !!
|
|
58
|
+
return !! nestedControlValue;
|
|
53
59
|
} ),
|
|
54
60
|
label: 'Nested Control 1',
|
|
55
61
|
onDeselect: jest.fn().mockImplementation( () => {
|
|
56
|
-
|
|
62
|
+
nestedControlValue = undefined;
|
|
57
63
|
} ),
|
|
58
64
|
onSelect: jest.fn(),
|
|
59
65
|
isShownByDefault: true,
|
|
60
66
|
};
|
|
61
67
|
|
|
62
68
|
// Alternative props for wrapped or grouped panel items.
|
|
69
|
+
const altNestedControlValue: ControlValue = false;
|
|
63
70
|
const altNestedControlProps = {
|
|
64
|
-
attributes: { value: false },
|
|
65
71
|
hasValue: jest.fn().mockImplementation( () => {
|
|
66
|
-
return !!
|
|
72
|
+
return !! altNestedControlValue;
|
|
67
73
|
} ),
|
|
68
74
|
label: 'Nested Control 2',
|
|
69
75
|
onDeselect: jest.fn(),
|
|
@@ -90,7 +96,7 @@ const GroupedItems = ( {
|
|
|
90
96
|
|
|
91
97
|
// This context object is used to help simulate different scenarios in which
|
|
92
98
|
// `ToolsPanelItem` registration or deregistration requires testing.
|
|
93
|
-
const panelContext = {
|
|
99
|
+
const panelContext: ToolsPanelContextType = {
|
|
94
100
|
panelId: '1234',
|
|
95
101
|
menuItems: {
|
|
96
102
|
default: {},
|
|
@@ -101,6 +107,8 @@ const panelContext = {
|
|
|
101
107
|
shouldRenderPlaceholderItems: false,
|
|
102
108
|
registerPanelItem: jest.fn(),
|
|
103
109
|
deregisterPanelItem: jest.fn(),
|
|
110
|
+
registerResetAllFilter: jest.fn(),
|
|
111
|
+
deregisterResetAllFilter: jest.fn(),
|
|
104
112
|
flagItemCustomization: noop,
|
|
105
113
|
areAllOptionalControlsHidden: true,
|
|
106
114
|
};
|
|
@@ -117,7 +125,10 @@ const renderGroupedItemsInPanel = () => {
|
|
|
117
125
|
|
|
118
126
|
// Custom component rendering a panel item within a wrapping element. Also used
|
|
119
127
|
// to test panel item registration and rendering.
|
|
120
|
-
const WrappedItem = ( {
|
|
128
|
+
const WrappedItem = ( {
|
|
129
|
+
text,
|
|
130
|
+
...props
|
|
131
|
+
}: React.ComponentProps< typeof ToolsPanelItem > & { text: string } ) => {
|
|
121
132
|
return (
|
|
122
133
|
<div>
|
|
123
134
|
<span>Wrapper</span>
|
|
@@ -178,7 +189,7 @@ const openDropdownMenu = async () => {
|
|
|
178
189
|
};
|
|
179
190
|
|
|
180
191
|
// Opens dropdown then selects the menu item by label before simulating a click.
|
|
181
|
-
const selectMenuItem = async ( label ) => {
|
|
192
|
+
const selectMenuItem = async ( label: string ) => {
|
|
182
193
|
const user = userEvent.setup();
|
|
183
194
|
const menuItem = await screen.findByText( label );
|
|
184
195
|
await user.click( menuItem );
|
|
@@ -186,8 +197,8 @@ const selectMenuItem = async ( label ) => {
|
|
|
186
197
|
|
|
187
198
|
describe( 'ToolsPanel', () => {
|
|
188
199
|
afterEach( () => {
|
|
189
|
-
|
|
190
|
-
|
|
200
|
+
controlValue = true;
|
|
201
|
+
altControlValue = false;
|
|
191
202
|
} );
|
|
192
203
|
|
|
193
204
|
describe( 'basic rendering', () => {
|
|
@@ -229,10 +240,20 @@ describe( 'ToolsPanel', () => {
|
|
|
229
240
|
render(
|
|
230
241
|
<ToolsPanel { ...defaultProps }>
|
|
231
242
|
{ false && (
|
|
232
|
-
<ToolsPanelItem
|
|
243
|
+
<ToolsPanelItem
|
|
244
|
+
label="Not rendered 1"
|
|
245
|
+
hasValue={ () => false }
|
|
246
|
+
>
|
|
247
|
+
Should not show
|
|
248
|
+
</ToolsPanelItem>
|
|
233
249
|
) }
|
|
234
250
|
{ false && (
|
|
235
|
-
<ToolsPanelItem
|
|
251
|
+
<ToolsPanelItem
|
|
252
|
+
label="Not rendered 2"
|
|
253
|
+
hasValue={ () => false }
|
|
254
|
+
>
|
|
255
|
+
Not shown either
|
|
256
|
+
</ToolsPanelItem>
|
|
236
257
|
) }
|
|
237
258
|
<span>Visible but insignificant</span>
|
|
238
259
|
</ToolsPanel>
|
|
@@ -317,7 +338,11 @@ describe( 'ToolsPanel', () => {
|
|
|
317
338
|
} );
|
|
318
339
|
|
|
319
340
|
it( 'should render optional panel item when value is updated externally and panel has an ID', async () => {
|
|
320
|
-
const ToolsPanelOptional = ( {
|
|
341
|
+
const ToolsPanelOptional = ( {
|
|
342
|
+
toolsPanelItemValue,
|
|
343
|
+
}: {
|
|
344
|
+
toolsPanelItemValue?: number;
|
|
345
|
+
} ) => {
|
|
321
346
|
const itemProps = {
|
|
322
347
|
attributes: { value: toolsPanelItemValue },
|
|
323
348
|
hasValue: () => !! toolsPanelItemValue,
|
|
@@ -349,7 +374,11 @@ describe( 'ToolsPanel', () => {
|
|
|
349
374
|
|
|
350
375
|
it( 'should render optional item when value is updated externally and panelId is null', async () => {
|
|
351
376
|
// This test partially covers: https://github.com/WordPress/gutenberg/issues/47368
|
|
352
|
-
const ToolsPanelOptional = ( {
|
|
377
|
+
const ToolsPanelOptional = ( {
|
|
378
|
+
toolsPanelItemValue,
|
|
379
|
+
}: {
|
|
380
|
+
toolsPanelItemValue?: number;
|
|
381
|
+
} ) => {
|
|
353
382
|
const itemProps = {
|
|
354
383
|
attributes: { value: toolsPanelItemValue },
|
|
355
384
|
hasValue: () => !! toolsPanelItemValue,
|
|
@@ -452,10 +481,10 @@ describe( 'ToolsPanel', () => {
|
|
|
452
481
|
} );
|
|
453
482
|
|
|
454
483
|
it( 'should render default controls with conditional isShownByDefault', async () => {
|
|
484
|
+
const linkedControlValue = false;
|
|
455
485
|
const linkedControlProps = {
|
|
456
|
-
attributes: { value: false },
|
|
457
486
|
hasValue: jest.fn().mockImplementation( () => {
|
|
458
|
-
return !!
|
|
487
|
+
return !! linkedControlValue;
|
|
459
488
|
} ),
|
|
460
489
|
label: 'Linked',
|
|
461
490
|
onDeselect: jest.fn(),
|
|
@@ -472,7 +501,7 @@ describe( 'ToolsPanel', () => {
|
|
|
472
501
|
</ToolsPanelItem>
|
|
473
502
|
<ToolsPanelItem
|
|
474
503
|
{ ...linkedControlProps }
|
|
475
|
-
isShownByDefault={ !!
|
|
504
|
+
isShownByDefault={ !! altControlValue }
|
|
476
505
|
>
|
|
477
506
|
<div>Linked control</div>
|
|
478
507
|
</ToolsPanelItem>
|
|
@@ -495,13 +524,14 @@ describe( 'ToolsPanel', () => {
|
|
|
495
524
|
expect( menuGroups.length ).toEqual( 3 );
|
|
496
525
|
|
|
497
526
|
// The linked control should be in the second group, of optional controls.
|
|
498
|
-
|
|
499
|
-
|
|
527
|
+
expect(
|
|
528
|
+
within( menuGroups[ 1 ] ).getByText( 'Linked' )
|
|
529
|
+
).toBeInTheDocument();
|
|
500
530
|
|
|
501
531
|
// Simulate the main control having a value set which should
|
|
502
532
|
// trigger the linked control becoming a default control via the
|
|
503
533
|
// conditional `isShownByDefault` prop.
|
|
504
|
-
|
|
534
|
+
altControlValue = true;
|
|
505
535
|
|
|
506
536
|
rerender( <TestPanel /> );
|
|
507
537
|
|
|
@@ -526,17 +556,18 @@ describe( 'ToolsPanel', () => {
|
|
|
526
556
|
// Optional controls have an additional aria-label. This can be used
|
|
527
557
|
// to confirm the conditional default control has been removed from
|
|
528
558
|
// the optional menu item group.
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
559
|
+
expect(
|
|
560
|
+
screen.queryByRole( 'menuitemcheckbox', {
|
|
561
|
+
name: 'Show Linked',
|
|
562
|
+
} )
|
|
563
|
+
).not.toBeInTheDocument();
|
|
533
564
|
} );
|
|
534
565
|
|
|
535
566
|
it( 'should handle conditionally rendered default control', async () => {
|
|
567
|
+
const conditionalControlValue = false;
|
|
536
568
|
const conditionalControlProps = {
|
|
537
|
-
attributes: { value: false },
|
|
538
569
|
hasValue: jest.fn().mockImplementation( () => {
|
|
539
|
-
return !!
|
|
570
|
+
return !! conditionalControlValue;
|
|
540
571
|
} ),
|
|
541
572
|
label: 'Conditional',
|
|
542
573
|
onDeselect: jest.fn(),
|
|
@@ -551,7 +582,7 @@ describe( 'ToolsPanel', () => {
|
|
|
551
582
|
>
|
|
552
583
|
<div>Default control</div>
|
|
553
584
|
</ToolsPanelItem>
|
|
554
|
-
{ !!
|
|
585
|
+
{ !! altControlValue && (
|
|
555
586
|
<ToolsPanelItem
|
|
556
587
|
{ ...conditionalControlProps }
|
|
557
588
|
isShownByDefault={ true }
|
|
@@ -579,7 +610,7 @@ describe( 'ToolsPanel', () => {
|
|
|
579
610
|
|
|
580
611
|
// Simulate the main control having a value set which will now
|
|
581
612
|
// render the new default control into the ToolsPanel.
|
|
582
|
-
|
|
613
|
+
altControlValue = true;
|
|
583
614
|
|
|
584
615
|
rerender( <TestPanel /> );
|
|
585
616
|
|
|
@@ -614,7 +645,7 @@ describe( 'ToolsPanel', () => {
|
|
|
614
645
|
// themselves, while those for the old panelId deregister.
|
|
615
646
|
//
|
|
616
647
|
// See: https://github.com/WordPress/gutenberg/pull/36588
|
|
617
|
-
const context = { ...panelContext };
|
|
648
|
+
const context: ToolsPanelContextType = { ...panelContext };
|
|
618
649
|
const TestPanel = () => (
|
|
619
650
|
<ToolsPanelContext.Provider value={ context }>
|
|
620
651
|
<ToolsPanelItem { ...altControlProps } panelId="1234">
|
|
@@ -678,7 +709,10 @@ describe( 'ToolsPanel', () => {
|
|
|
678
709
|
// individual items should still render themselves in this case.
|
|
679
710
|
//
|
|
680
711
|
// See: https://github.com/WordPress/gutenberg/pull/37216
|
|
681
|
-
const context = {
|
|
712
|
+
const context: ToolsPanelContextType = {
|
|
713
|
+
...panelContext,
|
|
714
|
+
panelId: null,
|
|
715
|
+
};
|
|
682
716
|
const TestPanel = () => (
|
|
683
717
|
<ToolsPanelContext.Provider value={ context }>
|
|
684
718
|
<ToolsPanelItem { ...altControlProps } panelId="1234">
|
|
@@ -942,6 +976,8 @@ describe( 'ToolsPanel', () => {
|
|
|
942
976
|
shouldRenderPlaceholderItems: false,
|
|
943
977
|
registerPanelItem: noop,
|
|
944
978
|
deregisterPanelItem: noop,
|
|
979
|
+
registerResetAllFilter: noop,
|
|
980
|
+
deregisterResetAllFilter: noop,
|
|
945
981
|
flagItemCustomization: noop,
|
|
946
982
|
areAllOptionalControlsHidden: true,
|
|
947
983
|
};
|
|
@@ -981,7 +1017,12 @@ describe( 'ToolsPanel', () => {
|
|
|
981
1017
|
// test that no orphaned items appear registered in the panel menu.
|
|
982
1018
|
//
|
|
983
1019
|
// See: https://github.com/WordPress/gutenberg/pull/34085
|
|
984
|
-
const TestSlotFillPanel = ( {
|
|
1020
|
+
const TestSlotFillPanel = ( {
|
|
1021
|
+
panelId,
|
|
1022
|
+
}: Pick<
|
|
1023
|
+
React.ComponentProps< typeof ToolsPanelItem >,
|
|
1024
|
+
'panelId'
|
|
1025
|
+
> ) => (
|
|
985
1026
|
<SlotFillProvider>
|
|
986
1027
|
<ToolsPanelItems>
|
|
987
1028
|
<ToolsPanelItem { ...altControlProps } panelId="1234">
|
|
@@ -1004,37 +1045,38 @@ describe( 'ToolsPanel', () => {
|
|
|
1004
1045
|
|
|
1005
1046
|
// Only the item matching the panelId should have been registered
|
|
1006
1047
|
// and appear in the panel menu.
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1048
|
+
expect(
|
|
1049
|
+
screen.getByRole( 'menuitemcheckbox', {
|
|
1050
|
+
name: 'Show Alt',
|
|
1051
|
+
} )
|
|
1052
|
+
).toBeInTheDocument();
|
|
1053
|
+
expect(
|
|
1054
|
+
screen.queryByRole( 'menuitemcheckbox', {
|
|
1055
|
+
name: 'Hide and reset Example',
|
|
1056
|
+
} )
|
|
1057
|
+
).not.toBeInTheDocument();
|
|
1016
1058
|
|
|
1017
1059
|
// Re-render the panel with different panelID simulating a block
|
|
1018
1060
|
// selection change.
|
|
1019
1061
|
rerender( <TestSlotFillPanel panelId="9999" /> );
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1062
|
+
expect(
|
|
1063
|
+
screen.queryByRole( 'menuitemcheckbox', {
|
|
1064
|
+
name: 'Show Alt',
|
|
1065
|
+
} )
|
|
1066
|
+
).not.toBeInTheDocument();
|
|
1067
|
+
expect(
|
|
1068
|
+
screen.getByRole( 'menuitemcheckbox', {
|
|
1069
|
+
name: 'Hide and reset Example',
|
|
1070
|
+
} )
|
|
1071
|
+
).toBeInTheDocument();
|
|
1030
1072
|
} );
|
|
1031
1073
|
} );
|
|
1032
1074
|
|
|
1033
1075
|
describe( 'panel header icon toggle', () => {
|
|
1076
|
+
const defaultControlsValue = false;
|
|
1034
1077
|
const defaultControls = {
|
|
1035
|
-
attributes: { value: false },
|
|
1036
1078
|
hasValue: jest.fn().mockImplementation( () => {
|
|
1037
|
-
return !!
|
|
1079
|
+
return !! defaultControlsValue;
|
|
1038
1080
|
} ),
|
|
1039
1081
|
label: 'Default',
|
|
1040
1082
|
onDeselect: jest.fn(),
|
|
@@ -1042,10 +1084,10 @@ describe( 'ToolsPanel', () => {
|
|
|
1042
1084
|
isShownByDefault: true,
|
|
1043
1085
|
};
|
|
1044
1086
|
|
|
1087
|
+
const optionalControlsValue = false;
|
|
1045
1088
|
const optionalControls = {
|
|
1046
|
-
attributes: { value: false },
|
|
1047
1089
|
hasValue: jest.fn().mockImplementation( () => {
|
|
1048
|
-
return !!
|
|
1090
|
+
return !! optionalControlsValue;
|
|
1049
1091
|
} ),
|
|
1050
1092
|
label: 'Optional',
|
|
1051
1093
|
onDeselect: jest.fn(),
|
|
@@ -1107,6 +1149,69 @@ describe( 'ToolsPanel', () => {
|
|
|
1107
1149
|
// The dropdown toggle no longer has a description.
|
|
1108
1150
|
expect( optionsDisplayedIcon ).not.toHaveAccessibleDescription();
|
|
1109
1151
|
} );
|
|
1152
|
+
|
|
1153
|
+
it( 'should not call reset all for different panelIds', async () => {
|
|
1154
|
+
const resetItem = jest.fn();
|
|
1155
|
+
const resetItemB = jest.fn();
|
|
1156
|
+
|
|
1157
|
+
const children = (
|
|
1158
|
+
<>
|
|
1159
|
+
<ToolsPanelItem
|
|
1160
|
+
label="a"
|
|
1161
|
+
hasValue={ () => true }
|
|
1162
|
+
panelId="a"
|
|
1163
|
+
resetAllFilter={ resetItem }
|
|
1164
|
+
isShownByDefault
|
|
1165
|
+
>
|
|
1166
|
+
<div>Example control</div>
|
|
1167
|
+
</ToolsPanelItem>
|
|
1168
|
+
<ToolsPanelItem
|
|
1169
|
+
label="b"
|
|
1170
|
+
hasValue={ () => true }
|
|
1171
|
+
panelId="b"
|
|
1172
|
+
resetAllFilter={ resetItemB }
|
|
1173
|
+
isShownByDefault
|
|
1174
|
+
>
|
|
1175
|
+
<div>Alt control</div>
|
|
1176
|
+
</ToolsPanelItem>
|
|
1177
|
+
</>
|
|
1178
|
+
);
|
|
1179
|
+
|
|
1180
|
+
const resetAllCallback = (
|
|
1181
|
+
filters: ResetAllFilter[] | undefined
|
|
1182
|
+
) => filters?.forEach( ( f ) => f() );
|
|
1183
|
+
|
|
1184
|
+
const { rerender } = render(
|
|
1185
|
+
<ToolsPanel
|
|
1186
|
+
{ ...defaultProps }
|
|
1187
|
+
panelId="a"
|
|
1188
|
+
resetAll={ resetAllCallback }
|
|
1189
|
+
>
|
|
1190
|
+
{ children }
|
|
1191
|
+
</ToolsPanel>
|
|
1192
|
+
);
|
|
1193
|
+
|
|
1194
|
+
await openDropdownMenu();
|
|
1195
|
+
await selectMenuItem( 'Reset all' );
|
|
1196
|
+
expect( resetItem ).toHaveBeenCalled();
|
|
1197
|
+
expect( resetItemB ).not.toHaveBeenCalled();
|
|
1198
|
+
|
|
1199
|
+
resetItem.mockClear();
|
|
1200
|
+
|
|
1201
|
+
rerender(
|
|
1202
|
+
<ToolsPanel
|
|
1203
|
+
{ ...defaultProps }
|
|
1204
|
+
panelId="b"
|
|
1205
|
+
resetAll={ resetAllCallback }
|
|
1206
|
+
>
|
|
1207
|
+
{ children }
|
|
1208
|
+
</ToolsPanel>
|
|
1209
|
+
);
|
|
1210
|
+
|
|
1211
|
+
await selectMenuItem( 'Reset all' );
|
|
1212
|
+
expect( resetItem ).not.toHaveBeenCalled();
|
|
1213
|
+
expect( resetItemB ).toHaveBeenCalled();
|
|
1214
|
+
} );
|
|
1110
1215
|
} );
|
|
1111
1216
|
|
|
1112
1217
|
describe( 'reset all button', () => {
|
|
@@ -1115,9 +1220,10 @@ describe( 'ToolsPanel', () => {
|
|
|
1115
1220
|
await openDropdownMenu();
|
|
1116
1221
|
|
|
1117
1222
|
const resetAllItem = await screen.findByRole( 'menuitem', {
|
|
1118
|
-
|
|
1223
|
+
name: 'Reset all',
|
|
1119
1224
|
} );
|
|
1120
1225
|
expect( resetAllItem ).toBeInTheDocument();
|
|
1226
|
+
expect( resetAllItem ).toHaveAttribute( 'aria-disabled', 'false' );
|
|
1121
1227
|
|
|
1122
1228
|
await selectMenuItem( 'Reset all' );
|
|
1123
1229
|
|
|
@@ -1126,9 +1232,13 @@ describe( 'ToolsPanel', () => {
|
|
|
1126
1232
|
expect( announcement ).toHaveAttribute( 'aria-live', 'assertive' );
|
|
1127
1233
|
|
|
1128
1234
|
const disabledResetAllItem = await screen.findByRole( 'menuitem', {
|
|
1129
|
-
|
|
1235
|
+
name: 'Reset all',
|
|
1130
1236
|
} );
|
|
1131
1237
|
expect( disabledResetAllItem ).toBeInTheDocument();
|
|
1238
|
+
expect( disabledResetAllItem ).toHaveAttribute(
|
|
1239
|
+
'aria-disabled',
|
|
1240
|
+
'true'
|
|
1241
|
+
);
|
|
1132
1242
|
} );
|
|
1133
1243
|
} );
|
|
1134
1244
|
|
|
@@ -21,6 +21,7 @@ import type {
|
|
|
21
21
|
ToolsPanelMenuItems,
|
|
22
22
|
ToolsPanelMenuItemsConfig,
|
|
23
23
|
ToolsPanelProps,
|
|
24
|
+
ResetAllFilter,
|
|
24
25
|
} from '../types';
|
|
25
26
|
|
|
26
27
|
const DEFAULT_COLUMNS = 2;
|
|
@@ -81,6 +82,9 @@ export function useToolsPanel(
|
|
|
81
82
|
|
|
82
83
|
// Allow panel items to register themselves.
|
|
83
84
|
const [ panelItems, setPanelItems ] = useState< ToolsPanelItem[] >( [] );
|
|
85
|
+
const [ resetAllFilters, setResetAllFilters ] = useState<
|
|
86
|
+
ResetAllFilter[]
|
|
87
|
+
>( [] );
|
|
84
88
|
|
|
85
89
|
const registerPanelItem = useCallback(
|
|
86
90
|
( item: ToolsPanelItem ) => {
|
|
@@ -123,6 +127,26 @@ export function useToolsPanel(
|
|
|
123
127
|
[ setPanelItems ]
|
|
124
128
|
);
|
|
125
129
|
|
|
130
|
+
const registerResetAllFilter = useCallback(
|
|
131
|
+
( newFilter: ResetAllFilter ) => {
|
|
132
|
+
setResetAllFilters( ( filters ) => {
|
|
133
|
+
return [ ...filters, newFilter ];
|
|
134
|
+
} );
|
|
135
|
+
},
|
|
136
|
+
[ setResetAllFilters ]
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const deregisterResetAllFilter = useCallback(
|
|
140
|
+
( filterToRemove: ResetAllFilter ) => {
|
|
141
|
+
setResetAllFilters( ( filters ) => {
|
|
142
|
+
return filters.filter(
|
|
143
|
+
( filter ) => filter !== filterToRemove
|
|
144
|
+
);
|
|
145
|
+
} );
|
|
146
|
+
},
|
|
147
|
+
[ setResetAllFilters ]
|
|
148
|
+
);
|
|
149
|
+
|
|
126
150
|
// Manage and share display state of menu items representing child controls.
|
|
127
151
|
const [ menuItems, setMenuItems ] = useState< ToolsPanelMenuItems >( {
|
|
128
152
|
default: {},
|
|
@@ -237,16 +261,7 @@ export function useToolsPanel(
|
|
|
237
261
|
const resetAllItems = useCallback( () => {
|
|
238
262
|
if ( typeof resetAll === 'function' ) {
|
|
239
263
|
isResetting.current = true;
|
|
240
|
-
|
|
241
|
-
// Collect available reset filters from panel items.
|
|
242
|
-
const filters: Array< () => void > = [];
|
|
243
|
-
panelItems.forEach( ( item ) => {
|
|
244
|
-
if ( item.resetAllFilter ) {
|
|
245
|
-
filters.push( item.resetAllFilter );
|
|
246
|
-
}
|
|
247
|
-
} );
|
|
248
|
-
|
|
249
|
-
resetAll( filters );
|
|
264
|
+
resetAll( resetAllFilters );
|
|
250
265
|
}
|
|
251
266
|
|
|
252
267
|
// Turn off display of all non-default items.
|
|
@@ -255,7 +270,7 @@ export function useToolsPanel(
|
|
|
255
270
|
shouldReset: true,
|
|
256
271
|
} );
|
|
257
272
|
setMenuItems( resetMenuItems );
|
|
258
|
-
}, [ panelItems, resetAll, setMenuItems ] );
|
|
273
|
+
}, [ panelItems, resetAllFilters, resetAll, setMenuItems ] );
|
|
259
274
|
|
|
260
275
|
// Assist ItemGroup styling when there are potentially hidden placeholder
|
|
261
276
|
// items by identifying first & last items that are toggled on for display.
|
|
@@ -277,6 +292,7 @@ export function useToolsPanel(
|
|
|
277
292
|
() => ( {
|
|
278
293
|
areAllOptionalControlsHidden,
|
|
279
294
|
deregisterPanelItem,
|
|
295
|
+
deregisterResetAllFilter,
|
|
280
296
|
firstDisplayedItem,
|
|
281
297
|
flagItemCustomization,
|
|
282
298
|
hasMenuItems: !! panelItems.length,
|
|
@@ -285,6 +301,7 @@ export function useToolsPanel(
|
|
|
285
301
|
menuItems,
|
|
286
302
|
panelId,
|
|
287
303
|
registerPanelItem,
|
|
304
|
+
registerResetAllFilter,
|
|
288
305
|
shouldRenderPlaceholderItems,
|
|
289
306
|
__experimentalFirstVisibleItemClass,
|
|
290
307
|
__experimentalLastVisibleItemClass,
|
|
@@ -292,12 +309,14 @@ export function useToolsPanel(
|
|
|
292
309
|
[
|
|
293
310
|
areAllOptionalControlsHidden,
|
|
294
311
|
deregisterPanelItem,
|
|
312
|
+
deregisterResetAllFilter,
|
|
295
313
|
firstDisplayedItem,
|
|
296
314
|
flagItemCustomization,
|
|
297
315
|
lastDisplayedItem,
|
|
298
316
|
menuItems,
|
|
299
317
|
panelId,
|
|
300
318
|
panelItems,
|
|
319
|
+
registerResetAllFilter,
|
|
301
320
|
registerPanelItem,
|
|
302
321
|
shouldRenderPlaceholderItems,
|
|
303
322
|
__experimentalFirstVisibleItemClass,
|
|
@@ -33,6 +33,8 @@ export function useToolsPanelItem(
|
|
|
33
33
|
const {
|
|
34
34
|
panelId: currentPanelId,
|
|
35
35
|
menuItems,
|
|
36
|
+
registerResetAllFilter,
|
|
37
|
+
deregisterResetAllFilter,
|
|
36
38
|
registerPanelItem,
|
|
37
39
|
deregisterPanelItem,
|
|
38
40
|
flagItemCustomization,
|
|
@@ -62,7 +64,6 @@ export function useToolsPanelItem(
|
|
|
62
64
|
hasValue: hasValueCallback,
|
|
63
65
|
isShownByDefault,
|
|
64
66
|
label,
|
|
65
|
-
resetAllFilter: resetAllFilterCallback,
|
|
66
67
|
panelId,
|
|
67
68
|
} );
|
|
68
69
|
}
|
|
@@ -83,11 +84,26 @@ export function useToolsPanelItem(
|
|
|
83
84
|
hasValueCallback,
|
|
84
85
|
panelId,
|
|
85
86
|
previousPanelId,
|
|
86
|
-
resetAllFilterCallback,
|
|
87
87
|
registerPanelItem,
|
|
88
88
|
deregisterPanelItem,
|
|
89
89
|
] );
|
|
90
90
|
|
|
91
|
+
useEffect( () => {
|
|
92
|
+
if ( hasMatchingPanel ) {
|
|
93
|
+
registerResetAllFilter( resetAllFilterCallback );
|
|
94
|
+
}
|
|
95
|
+
return () => {
|
|
96
|
+
if ( hasMatchingPanel ) {
|
|
97
|
+
deregisterResetAllFilter( resetAllFilterCallback );
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}, [
|
|
101
|
+
registerResetAllFilter,
|
|
102
|
+
deregisterResetAllFilter,
|
|
103
|
+
resetAllFilterCallback,
|
|
104
|
+
hasMatchingPanel,
|
|
105
|
+
] );
|
|
106
|
+
|
|
91
107
|
// Note: `label` is used as a key when building menu item state in
|
|
92
108
|
// `ToolsPanel`.
|
|
93
109
|
const menuGroup = isShownByDefault ? 'default' : 'optional';
|
package/src/tools-panel/types.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { ReactNode } from 'react';
|
|
|
8
8
|
*/
|
|
9
9
|
import type { HeadingSize } from '../heading/types';
|
|
10
10
|
|
|
11
|
-
type ResetAllFilter = ( attributes?: any ) => any;
|
|
11
|
+
export type ResetAllFilter = ( attributes?: any ) => any;
|
|
12
12
|
type ResetAll = ( filters?: ResetAllFilter[] ) => void;
|
|
13
13
|
|
|
14
14
|
export type ToolsPanelProps = {
|
|
@@ -122,14 +122,6 @@ export type ToolsPanelItem = {
|
|
|
122
122
|
* from a shared source.
|
|
123
123
|
*/
|
|
124
124
|
panelId?: string | null;
|
|
125
|
-
/**
|
|
126
|
-
* A `ToolsPanel` will collect each item's `resetAllFilter` and pass an
|
|
127
|
-
* array of these functions through to the panel's `resetAll` callback. They
|
|
128
|
-
* can then be iterated over to perform additional tasks.
|
|
129
|
-
*
|
|
130
|
-
* @default noop
|
|
131
|
-
*/
|
|
132
|
-
resetAllFilter?: ResetAllFilter;
|
|
133
125
|
};
|
|
134
126
|
|
|
135
127
|
export type ToolsPanelItemProps = ToolsPanelItem & {
|
|
@@ -147,6 +139,15 @@ export type ToolsPanelItemProps = ToolsPanelItem & {
|
|
|
147
139
|
* menu.
|
|
148
140
|
*/
|
|
149
141
|
onSelect?: () => void;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* A `ToolsPanel` will collect each item's `resetAllFilter` and pass an
|
|
145
|
+
* array of these functions through to the panel's `resetAll` callback. They
|
|
146
|
+
* can then be iterated over to perform additional tasks.
|
|
147
|
+
*
|
|
148
|
+
* @default noop
|
|
149
|
+
*/
|
|
150
|
+
resetAllFilter?: ResetAllFilter;
|
|
150
151
|
};
|
|
151
152
|
|
|
152
153
|
export type ToolsPanelMenuItemKey = 'default' | 'optional';
|
|
@@ -161,6 +162,8 @@ export type ToolsPanelContext = {
|
|
|
161
162
|
hasMenuItems: boolean;
|
|
162
163
|
registerPanelItem: ( item: ToolsPanelItem ) => void;
|
|
163
164
|
deregisterPanelItem: ( label: string ) => void;
|
|
165
|
+
registerResetAllFilter: ( filter: ResetAllFilter ) => void;
|
|
166
|
+
deregisterResetAllFilter: ( filter: ResetAllFilter ) => void;
|
|
164
167
|
flagItemCustomization: (
|
|
165
168
|
label: string,
|
|
166
169
|
group?: ToolsPanelMenuItemKey
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
-
exports[`TreeGrid simple rendering renders a table, tbody and any child elements 1`] = `"<div role
|
|
3
|
+
exports[`TreeGrid simple rendering renders a table, tbody and any child elements 1`] = `"<div role="application"><table role="treegrid"><tbody><tr role="row" aria-level="1" aria-posinset="1" aria-setsize="1"><td role="gridcell">Test</td></tr></tbody></table></div>"`;
|