@elementor/editor-ui 3.33.0-100 → 3.33.0-101
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/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +11 -5
- package/dist/index.mjs +12 -6
- package/package.json +2 -2
- package/src/components/popover/__tests__/menu-list.test.tsx +106 -0
- package/src/components/popover/menu-list.tsx +25 -15
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -429,6 +429,7 @@ var PopoverMenuList = ({
|
|
|
429
429
|
onChange
|
|
430
430
|
});
|
|
431
431
|
useScrollToSelected({ selectedValue, items, virtualizer });
|
|
432
|
+
const virtualItems = virtualizer.getVirtualItems();
|
|
432
433
|
return /* @__PURE__ */ React11.createElement(import_ui11.Box, { ref: containerRef, sx: { height: "100%", overflowY: "auto" } }, items.length === 0 && noResultsComponent ? noResultsComponent : /* @__PURE__ */ React11.createElement(
|
|
433
434
|
MenuListComponent,
|
|
434
435
|
{
|
|
@@ -436,7 +437,7 @@ var PopoverMenuList = ({
|
|
|
436
437
|
style: { height: `${virtualizer.getTotalSize()}px` },
|
|
437
438
|
"data-testid": dataTestId
|
|
438
439
|
},
|
|
439
|
-
|
|
440
|
+
virtualItems.map((virtualRow) => {
|
|
440
441
|
const item = items[virtualRow.index];
|
|
441
442
|
const isLast = virtualRow.index === items.length - 1;
|
|
442
443
|
const isFirst = items[0]?.type === "category" ? virtualRow.index === 1 : virtualRow.index === 0;
|
|
@@ -457,13 +458,15 @@ var PopoverMenuList = ({
|
|
|
457
458
|
item.label || item.value
|
|
458
459
|
);
|
|
459
460
|
}
|
|
461
|
+
const isDisabled = item.disabled;
|
|
460
462
|
return /* @__PURE__ */ React11.createElement(
|
|
461
|
-
|
|
463
|
+
import_ui11.ListItem,
|
|
462
464
|
{
|
|
463
465
|
key: virtualRow.key,
|
|
464
466
|
role: "option",
|
|
465
467
|
"aria-selected": isSelected,
|
|
466
|
-
|
|
468
|
+
"aria-disabled": isDisabled,
|
|
469
|
+
onClick: isDisabled ? void 0 : (e) => {
|
|
467
470
|
if (e.target.closest("button")) {
|
|
468
471
|
return;
|
|
469
472
|
}
|
|
@@ -471,7 +474,7 @@ var PopoverMenuList = ({
|
|
|
471
474
|
onClose();
|
|
472
475
|
},
|
|
473
476
|
onKeyDown: (event) => {
|
|
474
|
-
if (event.key === "Enter") {
|
|
477
|
+
if (event.key === "Enter" && !isDisabled) {
|
|
475
478
|
onSelect(item.value);
|
|
476
479
|
onClose();
|
|
477
480
|
}
|
|
@@ -485,7 +488,7 @@ var PopoverMenuList = ({
|
|
|
485
488
|
}
|
|
486
489
|
},
|
|
487
490
|
tabIndex: isSelected ? 0 : tabIndexFallback,
|
|
488
|
-
|
|
491
|
+
sx: {
|
|
489
492
|
transform: `translateY(${virtualRow.start + MENU_LIST_PADDING_TOP}px)`,
|
|
490
493
|
...itemStyle ? itemStyle(item) : {}
|
|
491
494
|
}
|
|
@@ -512,6 +515,9 @@ var StyledMenuList = (0, import_ui11.styled)(import_ui11.MenuList)(({ theme }) =
|
|
|
512
515
|
'&[aria-selected="true"]': {
|
|
513
516
|
backgroundColor: theme.palette.action.selected
|
|
514
517
|
},
|
|
518
|
+
'&[aria-disabled="true"]': {
|
|
519
|
+
color: theme.palette.text.disabled
|
|
520
|
+
},
|
|
515
521
|
cursor: "pointer",
|
|
516
522
|
textOverflow: "ellipsis",
|
|
517
523
|
position: "absolute",
|
package/dist/index.mjs
CHANGED
|
@@ -294,7 +294,7 @@ var PopoverHeader = ({ title, onClose, icon, actions }) => {
|
|
|
294
294
|
// src/components/popover/menu-list.tsx
|
|
295
295
|
import * as React11 from "react";
|
|
296
296
|
import { useMemo, useRef } from "react";
|
|
297
|
-
import { Box as Box5, MenuList, MenuSubheader, styled as styled2 } from "@elementor/ui";
|
|
297
|
+
import { Box as Box5, ListItem, MenuList, MenuSubheader, styled as styled2 } from "@elementor/ui";
|
|
298
298
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
299
299
|
|
|
300
300
|
// src/hooks/use-scroll-to-selected.ts
|
|
@@ -392,6 +392,7 @@ var PopoverMenuList = ({
|
|
|
392
392
|
onChange
|
|
393
393
|
});
|
|
394
394
|
useScrollToSelected({ selectedValue, items, virtualizer });
|
|
395
|
+
const virtualItems = virtualizer.getVirtualItems();
|
|
395
396
|
return /* @__PURE__ */ React11.createElement(Box5, { ref: containerRef, sx: { height: "100%", overflowY: "auto" } }, items.length === 0 && noResultsComponent ? noResultsComponent : /* @__PURE__ */ React11.createElement(
|
|
396
397
|
MenuListComponent,
|
|
397
398
|
{
|
|
@@ -399,7 +400,7 @@ var PopoverMenuList = ({
|
|
|
399
400
|
style: { height: `${virtualizer.getTotalSize()}px` },
|
|
400
401
|
"data-testid": dataTestId
|
|
401
402
|
},
|
|
402
|
-
|
|
403
|
+
virtualItems.map((virtualRow) => {
|
|
403
404
|
const item = items[virtualRow.index];
|
|
404
405
|
const isLast = virtualRow.index === items.length - 1;
|
|
405
406
|
const isFirst = items[0]?.type === "category" ? virtualRow.index === 1 : virtualRow.index === 0;
|
|
@@ -420,13 +421,15 @@ var PopoverMenuList = ({
|
|
|
420
421
|
item.label || item.value
|
|
421
422
|
);
|
|
422
423
|
}
|
|
424
|
+
const isDisabled = item.disabled;
|
|
423
425
|
return /* @__PURE__ */ React11.createElement(
|
|
424
|
-
|
|
426
|
+
ListItem,
|
|
425
427
|
{
|
|
426
428
|
key: virtualRow.key,
|
|
427
429
|
role: "option",
|
|
428
430
|
"aria-selected": isSelected,
|
|
429
|
-
|
|
431
|
+
"aria-disabled": isDisabled,
|
|
432
|
+
onClick: isDisabled ? void 0 : (e) => {
|
|
430
433
|
if (e.target.closest("button")) {
|
|
431
434
|
return;
|
|
432
435
|
}
|
|
@@ -434,7 +437,7 @@ var PopoverMenuList = ({
|
|
|
434
437
|
onClose();
|
|
435
438
|
},
|
|
436
439
|
onKeyDown: (event) => {
|
|
437
|
-
if (event.key === "Enter") {
|
|
440
|
+
if (event.key === "Enter" && !isDisabled) {
|
|
438
441
|
onSelect(item.value);
|
|
439
442
|
onClose();
|
|
440
443
|
}
|
|
@@ -448,7 +451,7 @@ var PopoverMenuList = ({
|
|
|
448
451
|
}
|
|
449
452
|
},
|
|
450
453
|
tabIndex: isSelected ? 0 : tabIndexFallback,
|
|
451
|
-
|
|
454
|
+
sx: {
|
|
452
455
|
transform: `translateY(${virtualRow.start + MENU_LIST_PADDING_TOP}px)`,
|
|
453
456
|
...itemStyle ? itemStyle(item) : {}
|
|
454
457
|
}
|
|
@@ -475,6 +478,9 @@ var StyledMenuList = styled2(MenuList)(({ theme }) => ({
|
|
|
475
478
|
'&[aria-selected="true"]': {
|
|
476
479
|
backgroundColor: theme.palette.action.selected
|
|
477
480
|
},
|
|
481
|
+
'&[aria-disabled="true"]': {
|
|
482
|
+
color: theme.palette.text.disabled
|
|
483
|
+
},
|
|
478
484
|
cursor: "pointer",
|
|
479
485
|
textOverflow: "ellipsis",
|
|
480
486
|
position: "absolute",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-ui",
|
|
3
3
|
"description": "Elementor Editor UI",
|
|
4
|
-
"version": "3.33.0-
|
|
4
|
+
"version": "3.33.0-101",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"react-dom": "^18.3.1"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@elementor/editor-v1-adapters": "3.33.0-
|
|
40
|
+
"@elementor/editor-v1-adapters": "3.33.0-101",
|
|
41
41
|
"@elementor/icons": "1.46.0",
|
|
42
42
|
"@elementor/ui": "1.36.12",
|
|
43
43
|
"@tanstack/react-virtual": "^3.13.3",
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
3
|
+
|
|
4
|
+
import { PopoverMenuList } from '../menu-list';
|
|
5
|
+
|
|
6
|
+
const mockItems = [
|
|
7
|
+
{ value: 'Item 1', type: 'item', disabled: false },
|
|
8
|
+
{ value: 'Item 2', type: 'item', disabled: true },
|
|
9
|
+
{ value: 'Item 3', type: 'item', disabled: false },
|
|
10
|
+
{ value: 'Item 4', type: 'item', disabled: false },
|
|
11
|
+
{ value: 'Item 5', type: 'item', disabled: true },
|
|
12
|
+
{ value: 'Item 6', type: 'item', disabled: false },
|
|
13
|
+
{ value: 'Item 7', type: 'item', disabled: false },
|
|
14
|
+
{ value: 'Item 8', type: 'item', disabled: false },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
jest.mock( '@tanstack/react-virtual', () => ( {
|
|
18
|
+
useVirtualizer: jest.fn().mockImplementation( () => ( {
|
|
19
|
+
getVirtualItems: jest
|
|
20
|
+
.fn()
|
|
21
|
+
.mockReturnValue( mockItems.map( ( item, index ) => ( { key: item.value, index, start: index * 10 } ) ) ),
|
|
22
|
+
getTotalSize: jest.fn().mockReturnValue( mockItems.length ),
|
|
23
|
+
scrollToIndex: jest.fn(),
|
|
24
|
+
} ) ),
|
|
25
|
+
} ) );
|
|
26
|
+
|
|
27
|
+
describe( 'PopoverMenuList', () => {
|
|
28
|
+
it( 'should render an empty list', async () => {
|
|
29
|
+
// Arrange.
|
|
30
|
+
render(
|
|
31
|
+
<PopoverMenuList
|
|
32
|
+
items={ [] }
|
|
33
|
+
onSelect={ jest.fn() }
|
|
34
|
+
onClose={ jest.fn() }
|
|
35
|
+
noResultsComponent={ <div>No results</div> }
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// Assert.
|
|
40
|
+
expect( screen.getByText( 'No results' ) ).toBeInTheDocument();
|
|
41
|
+
} );
|
|
42
|
+
|
|
43
|
+
it( 'should render a list with items', async () => {
|
|
44
|
+
const onSelect = jest.fn();
|
|
45
|
+
// Arrange.
|
|
46
|
+
const enabledMockItems = mockItems.filter( ( item ) => ! item.disabled );
|
|
47
|
+
render( <PopoverMenuList items={ mockItems } onSelect={ onSelect } onClose={ jest.fn() } /> );
|
|
48
|
+
|
|
49
|
+
// Assert.
|
|
50
|
+
enabledMockItems.forEach( ( item ) => {
|
|
51
|
+
const itemElement = screen.getByText( item.value );
|
|
52
|
+
expect( itemElement ).toBeInTheDocument();
|
|
53
|
+
fireEvent.click( itemElement );
|
|
54
|
+
expect( onSelect ).toHaveBeenCalledWith( item.value );
|
|
55
|
+
} );
|
|
56
|
+
|
|
57
|
+
expect( onSelect ).toHaveBeenCalledTimes( enabledMockItems.length );
|
|
58
|
+
} );
|
|
59
|
+
|
|
60
|
+
it( 'should render a list with items and a selected item', async () => {
|
|
61
|
+
// Arrange.
|
|
62
|
+
const selectedValue = 'Item 5';
|
|
63
|
+
render(
|
|
64
|
+
<PopoverMenuList
|
|
65
|
+
items={ mockItems }
|
|
66
|
+
onSelect={ jest.fn() }
|
|
67
|
+
onClose={ jest.fn() }
|
|
68
|
+
selectedValue={ selectedValue }
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// Assert.
|
|
73
|
+
mockItems.forEach( ( item ) => {
|
|
74
|
+
const itemElement = screen.getByText( item.value );
|
|
75
|
+
expect( itemElement ).toBeInTheDocument();
|
|
76
|
+
} );
|
|
77
|
+
|
|
78
|
+
const item5 = screen.getByText( selectedValue );
|
|
79
|
+
expect( item5 ).toHaveAttribute( 'aria-selected', 'true' );
|
|
80
|
+
} );
|
|
81
|
+
|
|
82
|
+
it( 'should render a list with items and disabled items', async () => {
|
|
83
|
+
// Arrange.
|
|
84
|
+
const onSelect = jest.fn();
|
|
85
|
+
render( <PopoverMenuList items={ mockItems } onSelect={ onSelect } onClose={ jest.fn() } /> );
|
|
86
|
+
|
|
87
|
+
// Assert.
|
|
88
|
+
mockItems.forEach( ( item ) => {
|
|
89
|
+
const itemElement = screen.getByText( item.value );
|
|
90
|
+
expect( itemElement ).toBeInTheDocument();
|
|
91
|
+
} );
|
|
92
|
+
|
|
93
|
+
let disabledItem = screen.getByText( mockItems[ 1 ].value );
|
|
94
|
+
expect( disabledItem ).toHaveAttribute( 'aria-disabled', 'true' );
|
|
95
|
+
fireEvent.click( disabledItem );
|
|
96
|
+
expect( onSelect ).not.toHaveBeenCalled();
|
|
97
|
+
disabledItem = screen.getByText( mockItems[ 4 ].value );
|
|
98
|
+
expect( disabledItem ).toHaveAttribute( 'aria-disabled', 'true' );
|
|
99
|
+
fireEvent.click( disabledItem );
|
|
100
|
+
expect( onSelect ).not.toHaveBeenCalled();
|
|
101
|
+
const item1 = screen.getByText( mockItems[ 0 ].value );
|
|
102
|
+
expect( item1 ).toHaveAttribute( 'aria-disabled', 'false' );
|
|
103
|
+
fireEvent.click( item1 );
|
|
104
|
+
expect( onSelect ).toHaveBeenCalledWith( mockItems[ 0 ].value );
|
|
105
|
+
} );
|
|
106
|
+
} );
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useMemo, useRef } from 'react';
|
|
3
|
-
import { Box, MenuList, MenuSubheader, styled } from '@elementor/ui';
|
|
3
|
+
import { Box, ListItem, MenuList, MenuSubheader, styled } from '@elementor/ui';
|
|
4
4
|
import { useVirtualizer } from '@tanstack/react-virtual';
|
|
5
5
|
|
|
6
6
|
import { useScrollTop, useScrollToSelected } from '../../hooks';
|
|
@@ -8,6 +8,7 @@ import { useScrollTop, useScrollToSelected } from '../../hooks';
|
|
|
8
8
|
export type VirtualizedItem< T, V extends string > = {
|
|
9
9
|
type: T;
|
|
10
10
|
value: V;
|
|
11
|
+
disabled?: boolean;
|
|
11
12
|
label?: string;
|
|
12
13
|
icon?: React.ReactNode;
|
|
13
14
|
secondaryText?: string;
|
|
@@ -105,6 +106,7 @@ export const PopoverMenuList = < T, V extends string >( {
|
|
|
105
106
|
} );
|
|
106
107
|
|
|
107
108
|
useScrollToSelected( { selectedValue, items, virtualizer } );
|
|
109
|
+
const virtualItems = virtualizer.getVirtualItems();
|
|
108
110
|
|
|
109
111
|
return (
|
|
110
112
|
<Box ref={ containerRef } sx={ { height: '100%', overflowY: 'auto' } }>
|
|
@@ -116,7 +118,7 @@ export const PopoverMenuList = < T, V extends string >( {
|
|
|
116
118
|
style={ { height: `${ virtualizer.getTotalSize() }px` } }
|
|
117
119
|
data-testid={ dataTestId }
|
|
118
120
|
>
|
|
119
|
-
{
|
|
121
|
+
{ virtualItems.map( ( virtualRow ) => {
|
|
120
122
|
const item = items[ virtualRow.index ];
|
|
121
123
|
const isLast = virtualRow.index === items.length - 1;
|
|
122
124
|
const isFirst =
|
|
@@ -141,21 +143,26 @@ export const PopoverMenuList = < T, V extends string >( {
|
|
|
141
143
|
</MenuSubheader>
|
|
142
144
|
);
|
|
143
145
|
}
|
|
144
|
-
|
|
146
|
+
const isDisabled = item.disabled;
|
|
145
147
|
return (
|
|
146
|
-
<
|
|
148
|
+
<ListItem
|
|
147
149
|
key={ virtualRow.key }
|
|
148
150
|
role="option"
|
|
149
151
|
aria-selected={ isSelected }
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
152
|
+
aria-disabled={ isDisabled }
|
|
153
|
+
onClick={
|
|
154
|
+
isDisabled
|
|
155
|
+
? undefined
|
|
156
|
+
: ( e: React.MouseEvent< HTMLLIElement > ) => {
|
|
157
|
+
if ( ( e.target as HTMLElement ).closest( 'button' ) ) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
onSelect( item.value );
|
|
161
|
+
onClose();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
onKeyDown={ ( event: React.KeyboardEvent< HTMLLIElement > ) => {
|
|
165
|
+
if ( event.key === 'Enter' && ! isDisabled ) {
|
|
159
166
|
onSelect( item.value );
|
|
160
167
|
onClose();
|
|
161
168
|
}
|
|
@@ -171,13 +178,13 @@ export const PopoverMenuList = < T, V extends string >( {
|
|
|
171
178
|
}
|
|
172
179
|
} }
|
|
173
180
|
tabIndex={ isSelected ? 0 : tabIndexFallback }
|
|
174
|
-
|
|
181
|
+
sx={ {
|
|
175
182
|
transform: `translateY(${ virtualRow.start + MENU_LIST_PADDING_TOP }px)`,
|
|
176
183
|
...( itemStyle ? itemStyle( item ) : {} ),
|
|
177
184
|
} }
|
|
178
185
|
>
|
|
179
186
|
{ menuItemContentTemplate ? menuItemContentTemplate( item ) : item.label || item.value }
|
|
180
|
-
</
|
|
187
|
+
</ListItem>
|
|
181
188
|
);
|
|
182
189
|
} ) }
|
|
183
190
|
</MenuListComponent>
|
|
@@ -203,6 +210,9 @@ export const StyledMenuList = styled( MenuList )( ( { theme } ) => ( {
|
|
|
203
210
|
'&[aria-selected="true"]': {
|
|
204
211
|
backgroundColor: theme.palette.action.selected,
|
|
205
212
|
},
|
|
213
|
+
'&[aria-disabled="true"]': {
|
|
214
|
+
color: theme.palette.text.disabled,
|
|
215
|
+
},
|
|
206
216
|
cursor: 'pointer',
|
|
207
217
|
textOverflow: 'ellipsis',
|
|
208
218
|
position: 'absolute',
|