@elementor/editor-controls 3.32.0-28 → 3.32.0-30
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 -3
- package/dist/index.d.ts +1 -3
- package/dist/index.js +274 -282
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +235 -242
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -14
- package/src/components/unstable-repeater/actions/disable-item-action.tsx +2 -2
- package/src/components/unstable-repeater/actions/duplicate-item-action.tsx +3 -3
- package/src/components/unstable-repeater/actions/tooltip-add-item-action.tsx +66 -0
- package/src/components/unstable-repeater/context/repeater-context.tsx +52 -67
- package/src/components/unstable-repeater/header/header.tsx +2 -2
- package/src/components/unstable-repeater/index.ts +1 -1
- package/src/components/unstable-repeater/items/edit-item-popover.tsx +28 -12
- package/src/components/unstable-repeater/items/item.tsx +15 -19
- package/src/components/unstable-repeater/items/items-container.tsx +17 -15
- package/src/components/unstable-repeater/types.ts +2 -12
- package/src/components/unstable-repeater/unstable-repeater.tsx +5 -3
- package/src/controls/background-control/background-overlay/background-overlay-repeater-control.tsx +25 -23
- package/src/controls/transform-control/functions/move.tsx +1 -1
- package/src/controls/transform-control/functions/rotate.tsx +1 -1
- package/src/controls/transform-control/functions/scale.tsx +1 -1
- package/src/controls/transform-control/functions/skew.tsx +1 -1
- package/src/controls/transform-control/transform-content.tsx +2 -12
- package/src/controls/transform-control/transform-icon.tsx +1 -1
- package/src/controls/transform-control/transform-label.tsx +1 -1
- package/src/controls/transform-control/transform-repeater-control.tsx +49 -17
- package/src/controls/transform-control/use-transform-tabs-history.tsx +12 -2
- package/src/index.ts +0 -1
- package/src/components/unstable-repeater/actions/add-item-action.tsx +0 -50
- package/src/components/unstable-repeater/items/use-popover.tsx +0 -26
- package/src/controls/unstable-transform-control/unstable-transform-repeater-control.tsx +0 -35
- /package/src/controls/transform-control/{types.ts → initial-values.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-controls",
|
|
3
3
|
"description": "This package contains the controls model and utils for the Elementor editor",
|
|
4
|
-
"version": "3.32.0-
|
|
4
|
+
"version": "3.32.0-30",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -40,21 +40,21 @@
|
|
|
40
40
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@elementor/editor-current-user": "3.32.0-
|
|
44
|
-
"@elementor/editor-elements": "3.32.0-
|
|
45
|
-
"@elementor/editor-props": "3.32.0-
|
|
46
|
-
"@elementor/editor-responsive": "3.32.0-
|
|
47
|
-
"@elementor/editor-ui": "3.32.0-
|
|
48
|
-
"@elementor/editor-v1-adapters": "3.32.0-
|
|
49
|
-
"@elementor/env": "3.32.0-
|
|
50
|
-
"@elementor/http-client": "3.32.0-
|
|
43
|
+
"@elementor/editor-current-user": "3.32.0-30",
|
|
44
|
+
"@elementor/editor-elements": "3.32.0-30",
|
|
45
|
+
"@elementor/editor-props": "3.32.0-30",
|
|
46
|
+
"@elementor/editor-responsive": "3.32.0-30",
|
|
47
|
+
"@elementor/editor-ui": "3.32.0-30",
|
|
48
|
+
"@elementor/editor-v1-adapters": "3.32.0-30",
|
|
49
|
+
"@elementor/env": "3.32.0-30",
|
|
50
|
+
"@elementor/http-client": "3.32.0-30",
|
|
51
51
|
"@elementor/icons": "^1.51.1",
|
|
52
|
-
"@elementor/locations": "3.32.0-
|
|
53
|
-
"@elementor/query": "3.32.0-
|
|
54
|
-
"@elementor/session": "3.32.0-
|
|
52
|
+
"@elementor/locations": "3.32.0-30",
|
|
53
|
+
"@elementor/query": "3.32.0-30",
|
|
54
|
+
"@elementor/session": "3.32.0-30",
|
|
55
55
|
"@elementor/ui": "1.36.2",
|
|
56
|
-
"@elementor/utils": "3.32.0-
|
|
57
|
-
"@elementor/wp-media": "3.32.0-
|
|
56
|
+
"@elementor/utils": "3.32.0-30",
|
|
57
|
+
"@elementor/wp-media": "3.32.0-30",
|
|
58
58
|
"@wordpress/i18n": "^5.13.0",
|
|
59
59
|
"@monaco-editor/react": "^4.7.0"
|
|
60
60
|
},
|
|
@@ -13,12 +13,12 @@ export const DisableItemAction = ( { index = -1 }: { index?: number } ) => {
|
|
|
13
13
|
return null;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
const propDisabled = items[ index ]
|
|
16
|
+
const propDisabled = items[ index ].item.disabled ?? false;
|
|
17
17
|
|
|
18
18
|
const toggleLabel = propDisabled ? __( 'Show', 'elementor' ) : __( 'Hide', 'elementor' );
|
|
19
19
|
|
|
20
20
|
const onClick = () => {
|
|
21
|
-
const self = structuredClone( items[ index ] );
|
|
21
|
+
const self = structuredClone( items[ index ].item );
|
|
22
22
|
|
|
23
23
|
self.disabled = ! self.disabled;
|
|
24
24
|
|
|
@@ -16,10 +16,10 @@ export const DuplicateItemAction = ( { index = -1 }: { index?: number } ) => {
|
|
|
16
16
|
|
|
17
17
|
const duplicateLabel = __( 'Duplicate', 'elementor' );
|
|
18
18
|
|
|
19
|
-
const onClick = () => {
|
|
20
|
-
const newItem = structuredClone( items[ index ] );
|
|
19
|
+
const onClick = ( ev: React.MouseEvent ) => {
|
|
20
|
+
const newItem = structuredClone( items[ index ]?.item );
|
|
21
21
|
|
|
22
|
-
addItem( { item: newItem, index: index + 1 } );
|
|
22
|
+
addItem( ev, { item: newItem, index: index + 1 } );
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
return (
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { PlusIcon } from '@elementor/icons';
|
|
3
|
+
import { Box, IconButton, Infotip } from '@elementor/ui';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
|
|
6
|
+
import { useRepeaterContext } from '../context/repeater-context';
|
|
7
|
+
|
|
8
|
+
const SIZE = 'tiny';
|
|
9
|
+
|
|
10
|
+
export const TooltipAddItemAction = ( {
|
|
11
|
+
disabled = false,
|
|
12
|
+
enableTooltip = false,
|
|
13
|
+
tooltipContent = null,
|
|
14
|
+
newItemIndex,
|
|
15
|
+
}: {
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
enableTooltip?: boolean;
|
|
18
|
+
tooltipContent?: React.ReactNode;
|
|
19
|
+
newItemIndex?: number;
|
|
20
|
+
} ) => {
|
|
21
|
+
const { addItem } = useRepeaterContext();
|
|
22
|
+
|
|
23
|
+
const onClick = ( ev: React.MouseEvent ) => addItem( ev, { index: newItemIndex } );
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<ConditionalToolTip content={ tooltipContent } enable={ enableTooltip }>
|
|
27
|
+
<Box sx={ { ml: 'auto' } }>
|
|
28
|
+
<IconButton
|
|
29
|
+
size={ SIZE }
|
|
30
|
+
disabled={ disabled }
|
|
31
|
+
onClick={ onClick }
|
|
32
|
+
aria-label={ __( 'Add item', 'elementor' ) }
|
|
33
|
+
>
|
|
34
|
+
<PlusIcon fontSize={ SIZE } />
|
|
35
|
+
</IconButton>
|
|
36
|
+
</Box>
|
|
37
|
+
</ConditionalToolTip>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const ConditionalToolTip = ( {
|
|
42
|
+
children,
|
|
43
|
+
enable,
|
|
44
|
+
content,
|
|
45
|
+
}: React.PropsWithChildren< {
|
|
46
|
+
content?: React.ReactNode;
|
|
47
|
+
enable: boolean;
|
|
48
|
+
} > ) =>
|
|
49
|
+
enable && content ? (
|
|
50
|
+
<Infotip
|
|
51
|
+
placement="right"
|
|
52
|
+
content={
|
|
53
|
+
<Box
|
|
54
|
+
component="span"
|
|
55
|
+
aria-label={ undefined }
|
|
56
|
+
sx={ { display: 'flex', gap: 0.5, p: 2, width: 320, borderRadius: 1 } }
|
|
57
|
+
>
|
|
58
|
+
{ content }
|
|
59
|
+
</Box>
|
|
60
|
+
}
|
|
61
|
+
>
|
|
62
|
+
{ children }
|
|
63
|
+
</Infotip>
|
|
64
|
+
) : (
|
|
65
|
+
children
|
|
66
|
+
);
|
|
@@ -1,35 +1,36 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { createContext, useState } from 'react';
|
|
3
|
-
import { type PropTypeUtil
|
|
3
|
+
import { type PropTypeUtil } from '@elementor/editor-props';
|
|
4
|
+
import { type PopupState, usePopupState } from '@elementor/ui';
|
|
4
5
|
|
|
5
6
|
import { useBoundProp } from '../../../bound-prop-context/use-bound-prop';
|
|
6
7
|
import { useSyncExternalState } from '../../../hooks/use-sync-external-state';
|
|
7
|
-
import { type Item } from '../types';
|
|
8
|
+
import { type Item, type RepeatablePropValue } from '../types';
|
|
8
9
|
|
|
9
|
-
type SetterFn< T
|
|
10
|
+
type SetterFn< T > = ( prevItems: T ) => T;
|
|
10
11
|
|
|
11
12
|
type AddItem< T > = { item?: T; index?: number };
|
|
12
13
|
|
|
13
|
-
type
|
|
14
|
+
type ItemWithKey< T > = { key: number; item: T };
|
|
15
|
+
|
|
16
|
+
type RepeaterContextType< T extends RepeatablePropValue > = {
|
|
14
17
|
isOpen: boolean;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
items: Item< T >[];
|
|
18
|
-
setItems: ( items:
|
|
18
|
+
openItemIndex: number;
|
|
19
|
+
setOpenItemIndex: ( key: number ) => void;
|
|
20
|
+
items: ItemWithKey< Item< T > >[];
|
|
21
|
+
setItems: ( items: ItemWithKey< T >[] ) => void;
|
|
22
|
+
popoverState: PopupState;
|
|
19
23
|
initial: T;
|
|
20
|
-
|
|
21
|
-
setUniqueKeys: ( keys: number[] ) => void;
|
|
22
|
-
isSortable: boolean;
|
|
23
|
-
generateNextKey: ( source: number[] ) => number;
|
|
24
|
-
addItem: ( config?: AddItem< T > ) => void;
|
|
24
|
+
addItem: ( ev: React.MouseEvent, config?: AddItem< T > ) => void;
|
|
25
25
|
updateItem: ( item: T, index: number ) => void;
|
|
26
26
|
removeItem: ( index: number ) => void;
|
|
27
|
-
|
|
27
|
+
rowRef: HTMLElement | null;
|
|
28
|
+
setRowRef: ( ref: HTMLElement | null | SetterFn< HTMLElement | null > ) => void;
|
|
28
29
|
};
|
|
29
30
|
|
|
30
|
-
const RepeaterContext = createContext< RepeaterContextType<
|
|
31
|
+
const RepeaterContext = createContext< RepeaterContextType< RepeatablePropValue > | null >( null );
|
|
31
32
|
|
|
32
|
-
const EMPTY_OPEN_ITEM = -1;
|
|
33
|
+
export const EMPTY_OPEN_ITEM = -1;
|
|
33
34
|
|
|
34
35
|
export const useRepeaterContext = () => {
|
|
35
36
|
const context = React.useContext( RepeaterContext );
|
|
@@ -38,29 +39,13 @@ export const useRepeaterContext = () => {
|
|
|
38
39
|
throw new Error( 'useRepeaterContext must be used within a RepeaterContextProvider' );
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
return
|
|
42
|
-
isOpen: context.isOpen,
|
|
43
|
-
openItem: context.openItem,
|
|
44
|
-
setOpenItem: context.setOpenItem,
|
|
45
|
-
items: context.items,
|
|
46
|
-
setItems: context.setItems,
|
|
47
|
-
uniqueKeys: context.uniqueKeys,
|
|
48
|
-
setUniqueKeys: context.setUniqueKeys,
|
|
49
|
-
initial: context.initial,
|
|
50
|
-
isSortable: context.isSortable,
|
|
51
|
-
generateNextKey: context.generateNextKey,
|
|
52
|
-
sortItemsByKeys: context.sortItemsByKeys,
|
|
53
|
-
addItem: context.addItem,
|
|
54
|
-
updateItem: context.updateItem,
|
|
55
|
-
removeItem: context.removeItem,
|
|
56
|
-
};
|
|
42
|
+
return context;
|
|
57
43
|
};
|
|
58
44
|
|
|
59
|
-
export const RepeaterContextProvider = < T extends
|
|
45
|
+
export const RepeaterContextProvider = < T extends RepeatablePropValue = RepeatablePropValue >( {
|
|
60
46
|
children,
|
|
61
47
|
initial,
|
|
62
48
|
propTypeUtil,
|
|
63
|
-
isSortable = true,
|
|
64
49
|
}: React.PropsWithChildren< { initial: T; propTypeUtil: PropTypeUtil< string, T[] >; isSortable?: boolean } > ) => {
|
|
65
50
|
const { value: repeaterValues, setValue: setRepeaterValues } = useBoundProp( propTypeUtil );
|
|
66
51
|
|
|
@@ -71,60 +56,60 @@ export const RepeaterContextProvider = < T extends PropValue = PropValue >( {
|
|
|
71
56
|
persistWhen: () => true,
|
|
72
57
|
} );
|
|
73
58
|
|
|
74
|
-
const
|
|
75
|
-
|
|
59
|
+
const itemWithKeysState = useState< ItemWithKey< T >[] >(
|
|
60
|
+
items?.map( ( item, index ) => ( { key: index, item } ) ) ?? []
|
|
61
|
+
);
|
|
76
62
|
|
|
77
|
-
const
|
|
63
|
+
const itemsWithKeys = itemWithKeysState[ 0 ];
|
|
64
|
+
const setItemsWithKeys = ( newItems: ItemWithKey< T >[] ) => {
|
|
65
|
+
itemWithKeysState[ 1 ]( newItems as ItemWithKey< T >[] );
|
|
66
|
+
setItems( newItems.map( ( { item } ) => item as T ) );
|
|
67
|
+
};
|
|
78
68
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
setItems( ( prevItems ) =>
|
|
82
|
-
keysOrder.map( ( key ) => {
|
|
83
|
-
const index = uniqueKeys.indexOf( key );
|
|
69
|
+
const [ openItemIndex, setOpenItemIndex ] = useState( EMPTY_OPEN_ITEM );
|
|
70
|
+
const [ rowRef, setRowRef ] = useState< HTMLElement | null >( null );
|
|
84
71
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
);
|
|
88
|
-
};
|
|
72
|
+
const isOpen = openItemIndex !== EMPTY_OPEN_ITEM;
|
|
73
|
+
const popoverState = usePopupState( { variant: 'popover' } );
|
|
89
74
|
|
|
90
|
-
const addItem = ( config?: AddItem< T > ) => {
|
|
75
|
+
const addItem = ( ev: React.MouseEvent, config?: AddItem< T > ) => {
|
|
91
76
|
const item = config?.item ?? initial;
|
|
92
|
-
const
|
|
93
|
-
const
|
|
77
|
+
const newIndex = config?.index ?? items.length;
|
|
78
|
+
const newKey = generateNextKey( itemsWithKeys.map( ( { key } ) => key ) );
|
|
79
|
+
const newItemsWithKeys = [ ...itemsWithKeys ];
|
|
94
80
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
setUniqueKeys( newItems.map( ( _, i ) => i ) );
|
|
81
|
+
newItemsWithKeys.splice( newIndex, 0, { item, key: newKey } );
|
|
82
|
+
setItemsWithKeys( newItemsWithKeys );
|
|
98
83
|
|
|
99
|
-
|
|
84
|
+
setOpenItemIndex( newIndex );
|
|
85
|
+
popoverState.open( rowRef ?? ev );
|
|
100
86
|
};
|
|
101
87
|
|
|
102
88
|
const removeItem = ( index: number ) => {
|
|
103
|
-
|
|
104
|
-
setUniqueKeys( ( prevKeys ) => prevKeys.slice( 0, -1 ) );
|
|
89
|
+
setItemsWithKeys( itemsWithKeys.filter( ( _, pos ) => pos !== index ) );
|
|
105
90
|
};
|
|
106
91
|
|
|
107
92
|
const updateItem = ( updatedItem: T, index: number ) => {
|
|
108
|
-
|
|
93
|
+
const item = itemsWithKeys[ index ];
|
|
94
|
+
|
|
95
|
+
setItemsWithKeys( itemsWithKeys.toSpliced( index, 1, { ...item, item: updatedItem } ) );
|
|
109
96
|
};
|
|
110
97
|
|
|
111
98
|
return (
|
|
112
99
|
<RepeaterContext.Provider
|
|
113
100
|
value={ {
|
|
114
101
|
isOpen,
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
items: (
|
|
118
|
-
setItems:
|
|
102
|
+
openItemIndex,
|
|
103
|
+
setOpenItemIndex,
|
|
104
|
+
items: ( itemsWithKeys ?? [] ) as RepeaterContextType< T >[ 'items' ],
|
|
105
|
+
setItems: setItemsWithKeys as RepeaterContextType< RepeatablePropValue >[ 'setItems' ],
|
|
106
|
+
popoverState,
|
|
119
107
|
initial,
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
isSortable,
|
|
123
|
-
generateNextKey,
|
|
124
|
-
sortItemsByKeys,
|
|
125
|
-
addItem: addItem as ( config?: AddItem< PropValue > ) => void,
|
|
126
|
-
updateItem: updateItem as ( item: PropValue, index: number ) => void,
|
|
108
|
+
updateItem: updateItem as RepeaterContextType< RepeatablePropValue >[ 'updateItem' ],
|
|
109
|
+
addItem: addItem as RepeaterContextType< RepeatablePropValue >[ 'addItem' ],
|
|
127
110
|
removeItem,
|
|
111
|
+
rowRef,
|
|
112
|
+
setRowRef,
|
|
128
113
|
} }
|
|
129
114
|
>
|
|
130
115
|
{ children }
|
|
@@ -4,7 +4,7 @@ import { Stack, Typography } from '@elementor/ui';
|
|
|
4
4
|
import { useBoundProp } from '../../../bound-prop-context/use-bound-prop';
|
|
5
5
|
import { ControlAdornments } from '../../../control-adornments/control-adornments';
|
|
6
6
|
import { SlotChildren } from '../../../control-replacements';
|
|
7
|
-
import {
|
|
7
|
+
import { TooltipAddItemAction } from '../actions/tooltip-add-item-action';
|
|
8
8
|
import { RepeaterHeaderActionsSlot } from '../locations';
|
|
9
9
|
|
|
10
10
|
export const Header = ( { label, children }: React.PropsWithChildren< { label: string } > ) => {
|
|
@@ -16,7 +16,7 @@ export const Header = ( { label, children }: React.PropsWithChildren< { label: s
|
|
|
16
16
|
{ label }
|
|
17
17
|
</Typography>
|
|
18
18
|
<RepeaterHeaderActionsSlot value={ value } />
|
|
19
|
-
<SlotChildren whitelist={ [
|
|
19
|
+
<SlotChildren whitelist={ [ TooltipAddItemAction ] as React.FC[] }>{ children }</SlotChildren>
|
|
20
20
|
<ControlAdornments />
|
|
21
21
|
</Stack>
|
|
22
22
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { TooltipAddItemAction } from './actions/tooltip-add-item-action';
|
|
2
2
|
export { Header } from './header/header';
|
|
3
3
|
export { ItemsContainer } from './items/items-container';
|
|
4
4
|
export { Item } from './items/item';
|
|
@@ -1,28 +1,44 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { Box, Popover
|
|
2
|
+
import { bindPopover, Box, Popover } from '@elementor/ui';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
import { PropKeyProvider } from '../../../bound-prop-context';
|
|
5
|
+
import { EMPTY_OPEN_ITEM, useRepeaterContext } from '../context/repeater-context';
|
|
6
|
+
|
|
7
|
+
export const EditItemPopover = ( { children }: { children: React.ReactNode } ) => {
|
|
8
|
+
const { popoverState, openItemIndex, isOpen, rowRef, setOpenItemIndex, setRowRef, items } = useRepeaterContext();
|
|
9
|
+
const popoverProps = bindPopover( popoverState );
|
|
10
|
+
|
|
11
|
+
if ( ! isOpen || ! rowRef ) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const bind = items[ openItemIndex ].item.$$type;
|
|
16
|
+
|
|
17
|
+
const onClose = () => {
|
|
18
|
+
popoverProps.onClose?.();
|
|
19
|
+
setRowRef( null );
|
|
20
|
+
setOpenItemIndex( EMPTY_OPEN_ITEM );
|
|
21
|
+
};
|
|
10
22
|
|
|
11
|
-
export const EditItemPopover = ( { children, anchorRef, setAnchorEl, popoverProps }: AddItemPopoverProps ) => {
|
|
12
23
|
return (
|
|
13
24
|
<Popover
|
|
14
25
|
disablePortal
|
|
15
26
|
slotProps={ {
|
|
16
27
|
paper: {
|
|
17
|
-
|
|
18
|
-
sx: { mt: 0.5, width: anchorRef?.offsetWidth },
|
|
28
|
+
sx: { mt: 0.5, width: rowRef.offsetWidth },
|
|
19
29
|
},
|
|
20
30
|
} }
|
|
21
31
|
anchorOrigin={ { vertical: 'bottom', horizontal: 'left' } }
|
|
22
|
-
anchorEl={ anchorRef }
|
|
23
32
|
{ ...popoverProps }
|
|
33
|
+
anchorEl={ rowRef }
|
|
34
|
+
onClose={ onClose }
|
|
24
35
|
>
|
|
25
|
-
<
|
|
36
|
+
<PropKeyProvider bind={ String( openItemIndex ) }>
|
|
37
|
+
<Box>
|
|
38
|
+
{ React.isValidElement< { bind: string; index: number } >( children ) &&
|
|
39
|
+
React.cloneElement( children, { bind, index: openItemIndex } ) }
|
|
40
|
+
</Box>
|
|
41
|
+
</PropKeyProvider>
|
|
26
42
|
</Popover>
|
|
27
43
|
);
|
|
28
44
|
};
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import { type PropValue } from '@elementor/editor-props';
|
|
4
2
|
import { bindTrigger, UnstableTag } from '@elementor/ui';
|
|
5
3
|
import { __ } from '@wordpress/i18n';
|
|
6
4
|
|
|
@@ -8,25 +6,25 @@ import { SlotChildren } from '../../../control-replacements';
|
|
|
8
6
|
import { DisableItemAction } from '../actions/disable-item-action';
|
|
9
7
|
import { DuplicateItemAction } from '../actions/duplicate-item-action';
|
|
10
8
|
import { RemoveItemAction } from '../actions/remove-item-action';
|
|
9
|
+
import { useRepeaterContext } from '../context/repeater-context';
|
|
11
10
|
import { RepeaterItemActionsSlot, RepeaterItemIconSlot, RepeaterItemLabelSlot } from '../locations';
|
|
12
|
-
import { type ItemProps } from '../types';
|
|
13
|
-
import { EditItemPopover } from './edit-item-popover';
|
|
14
|
-
import { usePopover } from './use-popover';
|
|
11
|
+
import { type ItemProps, type RepeatablePropValue } from '../types';
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export const Item = < T extends PropValue >( {
|
|
13
|
+
export const Item = < T extends RepeatablePropValue >( {
|
|
19
14
|
Label,
|
|
20
15
|
Icon,
|
|
21
|
-
Content,
|
|
22
|
-
key,
|
|
23
16
|
value,
|
|
24
|
-
index,
|
|
25
|
-
openOnMount,
|
|
17
|
+
index = -1,
|
|
26
18
|
children,
|
|
27
19
|
}: React.PropsWithChildren< ItemProps< T > > ) => {
|
|
28
|
-
const
|
|
29
|
-
const
|
|
20
|
+
const { items, popoverState, setRowRef, openItemIndex, setOpenItemIndex } = useRepeaterContext();
|
|
21
|
+
const triggerProps = bindTrigger( popoverState );
|
|
22
|
+
const key = items[ index ].key ?? -1;
|
|
23
|
+
|
|
24
|
+
const onClick = ( ev: React.MouseEvent ) => {
|
|
25
|
+
triggerProps.onClick( ev );
|
|
26
|
+
setOpenItemIndex( index );
|
|
27
|
+
};
|
|
30
28
|
|
|
31
29
|
return (
|
|
32
30
|
<>
|
|
@@ -40,10 +38,11 @@ export const Item = < T extends PropValue >( {
|
|
|
40
38
|
}
|
|
41
39
|
showActionsOnHover
|
|
42
40
|
fullWidth
|
|
43
|
-
ref={
|
|
41
|
+
ref={ ( ref ) => ref && openItemIndex === index && setRowRef( ref ) }
|
|
44
42
|
variant="outlined"
|
|
45
43
|
aria-label={ __( 'Open item', 'elementor' ) }
|
|
46
|
-
{ ...
|
|
44
|
+
{ ...triggerProps }
|
|
45
|
+
onClick={ onClick }
|
|
47
46
|
startIcon={
|
|
48
47
|
<RepeaterItemIconSlot value={ value }>
|
|
49
48
|
<Icon value={ value as T } />
|
|
@@ -63,9 +62,6 @@ export const Item = < T extends PropValue >( {
|
|
|
63
62
|
</>
|
|
64
63
|
}
|
|
65
64
|
/>
|
|
66
|
-
<EditItemPopover anchorRef={ ref } setAnchorEl={ setAnchorEl } popoverProps={ popoverProps }>
|
|
67
|
-
<Content anchorEl={ anchorEl } bind={ String( index ) } value={ value as T } />
|
|
68
|
-
</EditItemPopover>
|
|
69
65
|
</>
|
|
70
66
|
);
|
|
71
67
|
};
|
|
@@ -1,33 +1,36 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { type PropValue } from '@elementor/editor-props';
|
|
3
2
|
|
|
4
3
|
import { SortableItem, SortableProvider } from '../../sortable';
|
|
5
4
|
import { useRepeaterContext } from '../context/repeater-context';
|
|
6
|
-
import { type ItemProps } from '../types';
|
|
5
|
+
import { type Item, type ItemProps, type RepeatablePropValue } from '../types';
|
|
7
6
|
|
|
8
|
-
export const ItemsContainer = < T extends
|
|
7
|
+
export const ItemsContainer = < T extends RepeatablePropValue >( {
|
|
9
8
|
itemTemplate,
|
|
9
|
+
isSortable = true,
|
|
10
10
|
children,
|
|
11
|
-
}: React.PropsWithChildren< { itemTemplate: React.ReactNode } > ) => {
|
|
12
|
-
const { items,
|
|
11
|
+
}: React.PropsWithChildren< { itemTemplate: React.ReactNode; isSortable?: boolean } > ) => {
|
|
12
|
+
const { items, setItems } = useRepeaterContext();
|
|
13
|
+
const keys = items.map( ( { key } ) => key );
|
|
13
14
|
|
|
14
15
|
if ( ! itemTemplate ) {
|
|
15
16
|
return null;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
const onChangeOrder = (
|
|
19
|
-
|
|
19
|
+
const onChangeOrder = ( newKeys: number[] ) => {
|
|
20
|
+
setItems(
|
|
21
|
+
newKeys.map( ( key ) => {
|
|
22
|
+
const index = items.findIndex( ( item ) => item.key === key );
|
|
23
|
+
|
|
24
|
+
return items[ index ];
|
|
25
|
+
} )
|
|
26
|
+
);
|
|
20
27
|
};
|
|
21
28
|
|
|
22
29
|
return (
|
|
23
30
|
<>
|
|
24
|
-
<SortableProvider value={
|
|
25
|
-
{
|
|
26
|
-
const value = items
|
|
27
|
-
|
|
28
|
-
if ( ! value ) {
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
+
<SortableProvider value={ keys } onChange={ onChangeOrder }>
|
|
32
|
+
{ keys.map( ( key: number, index: number ) => {
|
|
33
|
+
const value = items[ index ].item as Item< T >;
|
|
31
34
|
|
|
32
35
|
return (
|
|
33
36
|
<SortableItem id={ key } key={ `sortable-${ key }` } disabled={ ! isSortable }>
|
|
@@ -36,7 +39,6 @@ export const ItemsContainer = < T extends PropValue >( {
|
|
|
36
39
|
key,
|
|
37
40
|
value,
|
|
38
41
|
index,
|
|
39
|
-
openOnMount: key === openItem,
|
|
40
42
|
children,
|
|
41
43
|
} )
|
|
42
44
|
: null }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type PropKey, type PropTypeUtil } from '@elementor/editor-props';
|
|
1
|
+
import { type PropKey, type PropTypeUtil, type PropValue, type TransformablePropValue } from '@elementor/editor-props';
|
|
2
2
|
|
|
3
3
|
export type CollectionPropUtil< T > = PropTypeUtil< PropKey, T[] >;
|
|
4
4
|
|
|
@@ -6,21 +6,11 @@ export type Item< T > = {
|
|
|
6
6
|
disabled?: boolean;
|
|
7
7
|
} & T;
|
|
8
8
|
|
|
9
|
-
type
|
|
10
|
-
anchorEl: HTMLElement | null;
|
|
11
|
-
bind: PropKey;
|
|
12
|
-
value: T;
|
|
13
|
-
collectionPropUtil?: CollectionPropUtil< T >;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
type RepeaterItemContent< T > = React.ComponentType< RepeaterItemContentProps< T > >;
|
|
9
|
+
export type RepeatablePropValue = TransformablePropValue< PropKey, PropValue >;
|
|
17
10
|
|
|
18
11
|
export type ItemProps< T > = {
|
|
19
12
|
Label: React.ComponentType< { value: T } >;
|
|
20
13
|
Icon: React.ComponentType< { value: T } >;
|
|
21
|
-
Content: RepeaterItemContent< T >;
|
|
22
14
|
value?: Item< T >;
|
|
23
|
-
key?: string | number;
|
|
24
15
|
index?: number;
|
|
25
|
-
openOnMount?: boolean;
|
|
26
16
|
};
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { type PropTypeUtil
|
|
2
|
+
import { type PropTypeUtil } from '@elementor/editor-props';
|
|
3
3
|
|
|
4
4
|
import { SlotChildren } from '../../control-replacements';
|
|
5
5
|
import { SectionContent } from '../section-content';
|
|
6
6
|
import { RepeaterContextProvider } from './context/repeater-context';
|
|
7
7
|
import { Header } from './header/header';
|
|
8
|
+
import { EditItemPopover } from './items/edit-item-popover';
|
|
8
9
|
import { ItemsContainer } from './items/items-container';
|
|
10
|
+
import { type RepeatablePropValue } from './types';
|
|
9
11
|
|
|
10
|
-
export const UnstableRepeater = < T extends
|
|
12
|
+
export const UnstableRepeater = < T extends RepeatablePropValue >( {
|
|
11
13
|
children,
|
|
12
14
|
initial,
|
|
13
15
|
propTypeUtil,
|
|
@@ -15,7 +17,7 @@ export const UnstableRepeater = < T extends PropValue >( {
|
|
|
15
17
|
return (
|
|
16
18
|
<SectionContent>
|
|
17
19
|
<RepeaterContextProvider initial={ initial } propTypeUtil={ propTypeUtil }>
|
|
18
|
-
<SlotChildren whitelist={ [ Header, ItemsContainer ] as React.FC[] } sorted>
|
|
20
|
+
<SlotChildren whitelist={ [ Header, ItemsContainer, EditItemPopover ] as React.FC[] } sorted>
|
|
19
21
|
{ children }
|
|
20
22
|
</SlotChildren>
|
|
21
23
|
</RepeaterContextProvider>
|