@elementor/editor-editing-panel 4.3.0-1060 → 4.3.0-1062
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.js +575 -311
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +492 -222
- package/dist/index.mjs.map +1 -1
- package/package.json +24 -24
- package/src/controls-registry/element-controls/list-items-control/list-actions.ts +129 -0
- package/src/controls-registry/element-controls/list-items-control/list-items-control.tsx +152 -0
- package/src/controls-registry/element-controls/list-items-control/use-show-markers-write-through.ts +89 -0
- package/src/controls-registry/element-controls/registry.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-editing-panel",
|
|
3
|
-
"version": "4.3.0-
|
|
3
|
+
"version": "4.3.0-1062",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Elementor Team",
|
|
6
6
|
"homepage": "https://elementor.com/",
|
|
@@ -39,31 +39,31 @@
|
|
|
39
39
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@elementor/editor": "4.3.0-
|
|
43
|
-
"@elementor/editor-canvas": "4.3.0-
|
|
44
|
-
"@elementor/editor-controls": "4.3.0-
|
|
45
|
-
"@elementor/editor-documents": "4.3.0-
|
|
46
|
-
"@elementor/editor-elements": "4.3.0-
|
|
47
|
-
"@elementor/editor-interactions": "4.3.0-
|
|
48
|
-
"@elementor/editor-notifications": "4.3.0-
|
|
49
|
-
"@elementor/editor-panels": "4.3.0-
|
|
50
|
-
"@elementor/editor-props": "4.3.0-
|
|
51
|
-
"@elementor/editor-responsive": "4.3.0-
|
|
52
|
-
"@elementor/editor-styles": "4.3.0-
|
|
53
|
-
"@elementor/editor-styles-repository": "4.3.0-
|
|
54
|
-
"@elementor/editor-ui": "4.3.0-
|
|
55
|
-
"@elementor/editor-v1-adapters": "4.3.0-
|
|
56
|
-
"@elementor/http-client": "4.3.0-
|
|
42
|
+
"@elementor/editor": "4.3.0-1062",
|
|
43
|
+
"@elementor/editor-canvas": "4.3.0-1062",
|
|
44
|
+
"@elementor/editor-controls": "4.3.0-1062",
|
|
45
|
+
"@elementor/editor-documents": "4.3.0-1062",
|
|
46
|
+
"@elementor/editor-elements": "4.3.0-1062",
|
|
47
|
+
"@elementor/editor-interactions": "4.3.0-1062",
|
|
48
|
+
"@elementor/editor-notifications": "4.3.0-1062",
|
|
49
|
+
"@elementor/editor-panels": "4.3.0-1062",
|
|
50
|
+
"@elementor/editor-props": "4.3.0-1062",
|
|
51
|
+
"@elementor/editor-responsive": "4.3.0-1062",
|
|
52
|
+
"@elementor/editor-styles": "4.3.0-1062",
|
|
53
|
+
"@elementor/editor-styles-repository": "4.3.0-1062",
|
|
54
|
+
"@elementor/editor-ui": "4.3.0-1062",
|
|
55
|
+
"@elementor/editor-v1-adapters": "4.3.0-1062",
|
|
56
|
+
"@elementor/http-client": "4.3.0-1062",
|
|
57
57
|
"@elementor/icons": "~1.75.1",
|
|
58
|
-
"@elementor/editor-variables": "4.3.0-
|
|
59
|
-
"@elementor/locations": "4.3.0-
|
|
60
|
-
"@elementor/menus": "4.3.0-
|
|
61
|
-
"@elementor/query": "4.3.0-
|
|
62
|
-
"@elementor/schema": "4.3.0-
|
|
63
|
-
"@elementor/session": "4.3.0-
|
|
58
|
+
"@elementor/editor-variables": "4.3.0-1062",
|
|
59
|
+
"@elementor/locations": "4.3.0-1062",
|
|
60
|
+
"@elementor/menus": "4.3.0-1062",
|
|
61
|
+
"@elementor/query": "4.3.0-1062",
|
|
62
|
+
"@elementor/schema": "4.3.0-1062",
|
|
63
|
+
"@elementor/session": "4.3.0-1062",
|
|
64
64
|
"@elementor/ui": "1.37.5",
|
|
65
|
-
"@elementor/utils": "4.3.0-
|
|
66
|
-
"@elementor/wp-media": "4.3.0-
|
|
65
|
+
"@elementor/utils": "4.3.0-1062",
|
|
66
|
+
"@elementor/wp-media": "4.3.0-1062",
|
|
67
67
|
"@wordpress/i18n": "^5.13.0"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { type ItemsActionPayload } from '@elementor/editor-controls';
|
|
2
|
+
import {
|
|
3
|
+
createElements,
|
|
4
|
+
duplicateElements,
|
|
5
|
+
getContainer,
|
|
6
|
+
moveElements,
|
|
7
|
+
removeElements,
|
|
8
|
+
} from '@elementor/editor-elements';
|
|
9
|
+
import { booleanPropTypeUtil } from '@elementor/editor-props';
|
|
10
|
+
import { __ } from '@wordpress/i18n';
|
|
11
|
+
|
|
12
|
+
export type ListItem = {
|
|
13
|
+
id: string;
|
|
14
|
+
title?: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const LIST_ITEM_ELEMENT_TYPE = 'e-list-item';
|
|
18
|
+
|
|
19
|
+
const TRAILING_NUMBER = /(\d+)\s*$/;
|
|
20
|
+
|
|
21
|
+
const getItemTitle = ( position: number ) => `Item ${ position }`;
|
|
22
|
+
|
|
23
|
+
const getNextItemNumber = ( existingTitles: ( string | undefined )[] ) => {
|
|
24
|
+
const taken = new Set( existingTitles.filter( ( title ): title is string => Boolean( title ) ) );
|
|
25
|
+
|
|
26
|
+
const highest = existingTitles.reduce( ( max: number, title ) => {
|
|
27
|
+
const [ , trailingNumber ] = title?.match( TRAILING_NUMBER ) ?? [];
|
|
28
|
+
const parsed = trailingNumber ? Number( trailingNumber ) : 0;
|
|
29
|
+
|
|
30
|
+
return Number.isFinite( parsed ) && parsed > max ? parsed : max;
|
|
31
|
+
}, 0 );
|
|
32
|
+
|
|
33
|
+
let next = highest + 1;
|
|
34
|
+
|
|
35
|
+
while ( taken.has( getItemTitle( next ) ) ) {
|
|
36
|
+
next += 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return next;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const duplicateItem = ( { items }: { items: ItemsActionPayload< ListItem > } ) => {
|
|
43
|
+
duplicateElements( {
|
|
44
|
+
elementIds: items.map( ( { item } ) => item.id ),
|
|
45
|
+
title: __( 'Duplicate List Item', 'elementor' ),
|
|
46
|
+
} );
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const moveItem = ( {
|
|
50
|
+
toIndex,
|
|
51
|
+
listContainerId,
|
|
52
|
+
movedElementId,
|
|
53
|
+
}: {
|
|
54
|
+
toIndex: number;
|
|
55
|
+
listContainerId: string;
|
|
56
|
+
movedElementId: string;
|
|
57
|
+
} ) => {
|
|
58
|
+
const movedElement = getContainer( movedElementId );
|
|
59
|
+
const listContainer = getContainer( listContainerId );
|
|
60
|
+
|
|
61
|
+
if ( ! movedElement || ! listContainer ) {
|
|
62
|
+
throw new Error( 'List item or list container not found' );
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
moveElements( {
|
|
66
|
+
title: __( 'Reorder List Items', 'elementor' ),
|
|
67
|
+
moves: [
|
|
68
|
+
{
|
|
69
|
+
element: movedElement,
|
|
70
|
+
targetContainer: listContainer,
|
|
71
|
+
options: { at: toIndex },
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
} );
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const removeItem = ( { items }: { items: ItemsActionPayload< ListItem > } ) => {
|
|
78
|
+
removeElements( {
|
|
79
|
+
title: __( 'List Items', 'elementor' ),
|
|
80
|
+
elementIds: items.map( ( { item } ) => item.id ),
|
|
81
|
+
} );
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const addItem = ( {
|
|
85
|
+
existingTitles,
|
|
86
|
+
listContainerId,
|
|
87
|
+
items,
|
|
88
|
+
showMarkers,
|
|
89
|
+
}: {
|
|
90
|
+
existingTitles: ( string | undefined )[];
|
|
91
|
+
listContainerId: string;
|
|
92
|
+
items: ItemsActionPayload< ListItem >;
|
|
93
|
+
showMarkers: boolean;
|
|
94
|
+
} ) => {
|
|
95
|
+
const listContainer = getContainer( listContainerId );
|
|
96
|
+
|
|
97
|
+
if ( ! listContainer ) {
|
|
98
|
+
throw new Error( 'List container not found' );
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const titles = [ ...existingTitles ];
|
|
102
|
+
|
|
103
|
+
items.forEach( ( { index } ) => {
|
|
104
|
+
const position = getNextItemNumber( titles );
|
|
105
|
+
|
|
106
|
+
createElements( {
|
|
107
|
+
title: __( 'List Items', 'elementor' ),
|
|
108
|
+
elements: [
|
|
109
|
+
{
|
|
110
|
+
container: listContainer,
|
|
111
|
+
model: {
|
|
112
|
+
elType: LIST_ITEM_ELEMENT_TYPE,
|
|
113
|
+
settings: {
|
|
114
|
+
show_markers: booleanPropTypeUtil.create( showMarkers ),
|
|
115
|
+
},
|
|
116
|
+
hydrateDefaultChildren: true,
|
|
117
|
+
editor_settings: {
|
|
118
|
+
title: getItemTitle( position ),
|
|
119
|
+
initial_position: position,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
options: { at: index },
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
} );
|
|
126
|
+
|
|
127
|
+
titles.push( getItemTitle( position ) );
|
|
128
|
+
} );
|
|
129
|
+
};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ControlFormLabel, Repeater, type RepeaterItem, type SetRepeaterValuesMeta } from '@elementor/editor-controls';
|
|
3
|
+
import { updateElementEditorSettings, useElementChildren, useElementEditorSettings } from '@elementor/editor-elements';
|
|
4
|
+
import { booleanPropTypeUtil, type CreateOptions } from '@elementor/editor-props';
|
|
5
|
+
import { Stack, TextField } from '@elementor/ui';
|
|
6
|
+
import { __ } from '@wordpress/i18n';
|
|
7
|
+
|
|
8
|
+
import { useElement } from '../../../contexts/element-context';
|
|
9
|
+
import { addItem, duplicateItem, LIST_ITEM_ELEMENT_TYPE, type ListItem, moveItem, removeItem } from './list-actions';
|
|
10
|
+
import { useShowMarkersWriteThrough } from './use-show-markers-write-through';
|
|
11
|
+
|
|
12
|
+
const LIST_ELEMENT_TYPE = 'e-list';
|
|
13
|
+
|
|
14
|
+
const getEffectiveListItemLabel = ( label: string | undefined, fallbackLabel: string ) => {
|
|
15
|
+
return label?.trim() ? label : fallbackLabel;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const getDefaultListItemLabel = ( index: number ) => {
|
|
19
|
+
return `Item ${ index + 1 }`;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const ListItemsControl = ( { label }: { label: string } ) => {
|
|
23
|
+
return <ListItemsControlContent label={ label } />;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const ListItemsControlContent = ( { label }: { label: string } ) => {
|
|
27
|
+
const { element, settings } = useElement();
|
|
28
|
+
const { [ LIST_ITEM_ELEMENT_TYPE ]: listItems } = useElementChildren(
|
|
29
|
+
element.id,
|
|
30
|
+
{ [ LIST_ELEMENT_TYPE ]: LIST_ITEM_ELEMENT_TYPE },
|
|
31
|
+
{ includeSelfAsParent: true }
|
|
32
|
+
);
|
|
33
|
+
// The root owns `show_markers`, but each child item needs a mirrored copy for its own
|
|
34
|
+
// `Child_Dependency`, so the repeater hosts the write-through that keeps those values undoable.
|
|
35
|
+
const showMarkers = booleanPropTypeUtil.extract( settings.show_markers ) ?? true;
|
|
36
|
+
|
|
37
|
+
useShowMarkersWriteThrough( element.id, showMarkers );
|
|
38
|
+
|
|
39
|
+
const repeaterValues: RepeaterItem< ListItem >[] = listItems.map( ( item, index ) => ( {
|
|
40
|
+
id: item.id,
|
|
41
|
+
title: item.editorSettings?.title ?? getDefaultListItemLabel( index ),
|
|
42
|
+
index,
|
|
43
|
+
} ) );
|
|
44
|
+
|
|
45
|
+
const setValue = (
|
|
46
|
+
_newValues: RepeaterItem< ListItem >[],
|
|
47
|
+
_options: CreateOptions,
|
|
48
|
+
meta?: SetRepeaterValuesMeta< RepeaterItem< ListItem > >
|
|
49
|
+
) => {
|
|
50
|
+
if ( meta?.action?.type === 'add' ) {
|
|
51
|
+
return addItem( {
|
|
52
|
+
existingTitles: repeaterValues.map( ( { title } ) => title ),
|
|
53
|
+
listContainerId: element.id,
|
|
54
|
+
items: meta.action.payload,
|
|
55
|
+
showMarkers,
|
|
56
|
+
} );
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if ( meta?.action?.type === 'remove' ) {
|
|
60
|
+
return removeItem( { items: meta.action.payload } );
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if ( meta?.action?.type === 'duplicate' ) {
|
|
64
|
+
return duplicateItem( { items: meta.action.payload } );
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if ( meta?.action?.type === 'reorder' ) {
|
|
68
|
+
const { from, to } = meta.action.payload;
|
|
69
|
+
|
|
70
|
+
return moveItem( {
|
|
71
|
+
toIndex: to,
|
|
72
|
+
listContainerId: element.id,
|
|
73
|
+
movedElementId: listItems[ from ].id,
|
|
74
|
+
} );
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<Repeater
|
|
80
|
+
showToggle={ false }
|
|
81
|
+
values={ repeaterValues }
|
|
82
|
+
setValues={ setValue }
|
|
83
|
+
showRemove={ repeaterValues.length > 1 }
|
|
84
|
+
label={ label }
|
|
85
|
+
// List items are child elements, not a prop on the root, so there is nothing meaningful
|
|
86
|
+
// to expose or bind here. Using an unrelated prop key just to satisfy adornment context
|
|
87
|
+
// makes the panel act as if that real prop belongs to this repeater.
|
|
88
|
+
adornment={ () => null }
|
|
89
|
+
itemSettings={ {
|
|
90
|
+
getId: ( { item } ) => item.id,
|
|
91
|
+
initialValues: { id: '', title: 'Item' },
|
|
92
|
+
Label: ItemLabel,
|
|
93
|
+
Content: ItemContent,
|
|
94
|
+
Icon: () => null,
|
|
95
|
+
} }
|
|
96
|
+
/>
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const ItemLabel = ( { value, index }: { value: ListItem; index: number } ) => {
|
|
101
|
+
const fallbackLabel = value.title ?? getDefaultListItemLabel( index );
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<Stack sx={ { minHeight: 20 } } direction="row" alignItems="center" gap={ 1.5 }>
|
|
105
|
+
{ value.id ? (
|
|
106
|
+
<ListItemRepeaterLabel elementId={ value.id } fallbackLabel={ fallbackLabel } />
|
|
107
|
+
) : (
|
|
108
|
+
<span>{ fallbackLabel }</span>
|
|
109
|
+
) }
|
|
110
|
+
</Stack>
|
|
111
|
+
);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const ItemContent = ( { value }: { value: ListItem } ) => {
|
|
115
|
+
if ( ! value.id ) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<Stack p={ 2 } gap={ 1.5 }>
|
|
121
|
+
<ListItemLabelControl elementId={ value.id } fallbackLabel={ value.title ?? '' } />
|
|
122
|
+
</Stack>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const ListItemRepeaterLabel = ( { elementId, fallbackLabel }: { elementId: string; fallbackLabel: string } ) => {
|
|
127
|
+
const editorSettings = useElementEditorSettings( elementId );
|
|
128
|
+
const label = getEffectiveListItemLabel( editorSettings?.title, fallbackLabel );
|
|
129
|
+
|
|
130
|
+
return <span>{ label }</span>;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const ListItemLabelControl = ( { elementId, fallbackLabel }: { elementId: string; fallbackLabel: string } ) => {
|
|
134
|
+
const editorSettings = useElementEditorSettings( elementId );
|
|
135
|
+
const label = getEffectiveListItemLabel( editorSettings?.title, fallbackLabel );
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<Stack gap={ 1 }>
|
|
139
|
+
<ControlFormLabel>{ __( 'Item name', 'elementor' ) }</ControlFormLabel>
|
|
140
|
+
<TextField
|
|
141
|
+
size="tiny"
|
|
142
|
+
value={ label }
|
|
143
|
+
onChange={ ( { target }: React.ChangeEvent< HTMLInputElement > ) => {
|
|
144
|
+
updateElementEditorSettings( {
|
|
145
|
+
elementId,
|
|
146
|
+
settings: { title: target.value },
|
|
147
|
+
} );
|
|
148
|
+
} }
|
|
149
|
+
/>
|
|
150
|
+
</Stack>
|
|
151
|
+
);
|
|
152
|
+
};
|
package/src/controls-registry/element-controls/list-items-control/use-show-markers-write-through.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { getContainer, getElementSettings, updateElementSettings } from '@elementor/editor-elements';
|
|
3
|
+
import { booleanPropTypeUtil } from '@elementor/editor-props';
|
|
4
|
+
import { undoable } from '@elementor/editor-v1-adapters';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
|
|
7
|
+
import { HISTORY_DEBOUNCE_WAIT } from '../../../hooks/use-styles-fields';
|
|
8
|
+
import { LIST_ITEM_ELEMENT_TYPE } from './list-actions';
|
|
9
|
+
|
|
10
|
+
type CascadeShowMarkersPayload = {
|
|
11
|
+
listId: string;
|
|
12
|
+
showMarkers: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type CascadeShowMarkersResult = {
|
|
16
|
+
previous: Record< string, ReturnType< typeof booleanPropTypeUtil.create > | null | undefined >;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// `show_markers` lives on the root list, but each `e-list-item` also carries a mirrored copy so its
|
|
20
|
+
// own `Child_Dependency` can attach/detach the marker child. This write-through keeps those mirrored
|
|
21
|
+
// props in sync through a debounced undoable history entry so Undo restores the switch and all items.
|
|
22
|
+
export const cascadeShowMarkersToItems = undoable< CascadeShowMarkersPayload, CascadeShowMarkersResult, undefined >(
|
|
23
|
+
{
|
|
24
|
+
do: ( { listId, showMarkers } ) => {
|
|
25
|
+
const itemIds = getListItemIds( listId );
|
|
26
|
+
|
|
27
|
+
const previous = Object.fromEntries(
|
|
28
|
+
itemIds.map(
|
|
29
|
+
( itemId ) =>
|
|
30
|
+
[
|
|
31
|
+
itemId,
|
|
32
|
+
getElementSettings< ReturnType< typeof booleanPropTypeUtil.create > >( itemId, [
|
|
33
|
+
'show_markers',
|
|
34
|
+
] ).show_markers,
|
|
35
|
+
] as const
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
itemIds.forEach( ( itemId ) => {
|
|
40
|
+
updateElementSettings( {
|
|
41
|
+
id: itemId,
|
|
42
|
+
props: { show_markers: booleanPropTypeUtil.create( showMarkers ) },
|
|
43
|
+
withHistory: false,
|
|
44
|
+
} );
|
|
45
|
+
} );
|
|
46
|
+
|
|
47
|
+
return { previous };
|
|
48
|
+
},
|
|
49
|
+
undo: ( _payload, { previous } ) => {
|
|
50
|
+
Object.entries( previous ).forEach( ( [ itemId, previousValue ] ) => {
|
|
51
|
+
updateElementSettings( {
|
|
52
|
+
id: itemId,
|
|
53
|
+
props: { show_markers: previousValue ?? null },
|
|
54
|
+
withHistory: false,
|
|
55
|
+
} );
|
|
56
|
+
} );
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
title: __( 'List', 'elementor' ),
|
|
61
|
+
subtitle: __( 'Show Markers', 'elementor' ),
|
|
62
|
+
debounce: { wait: HISTORY_DEBOUNCE_WAIT },
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
function getListItemIds( listId: string ): string[] {
|
|
67
|
+
const list = getContainer( listId );
|
|
68
|
+
|
|
69
|
+
const itemContainers = ( list?.children ?? [] ).filter(
|
|
70
|
+
( child ) => child.model.get( 'elType' ) === LIST_ITEM_ELEMENT_TYPE
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
return itemContainers.map( ( item ): string => item.id );
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function useShowMarkersWriteThrough( listId: string, showMarkers: boolean ): void {
|
|
77
|
+
const previousRef = useRef< { listId: string; showMarkers: boolean } | null >( null );
|
|
78
|
+
|
|
79
|
+
useEffect( () => {
|
|
80
|
+
const previous = previousRef.current;
|
|
81
|
+
previousRef.current = { listId, showMarkers };
|
|
82
|
+
|
|
83
|
+
if ( ! previous || previous.listId !== listId || previous.showMarkers === showMarkers ) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
cascadeShowMarkersToItems( { listId, showMarkers } );
|
|
88
|
+
}, [ listId, showMarkers ] );
|
|
89
|
+
}
|
|
@@ -2,9 +2,11 @@ import { type ControlComponent } from '@elementor/editor-controls';
|
|
|
2
2
|
|
|
3
3
|
import { type ControlRegistry, controlsRegistry } from '../controls-registry';
|
|
4
4
|
import { AccordionItemsControl } from './accordion-items-control/accordion-items-control';
|
|
5
|
+
import { ListItemsControl } from './list-items-control/list-items-control';
|
|
5
6
|
import { TabsControl } from './tabs-control/tabs-control';
|
|
6
7
|
|
|
7
8
|
const controlTypes = {
|
|
9
|
+
'list-items': { component: ListItemsControl as ControlComponent, layout: 'full' },
|
|
8
10
|
tabs: { component: TabsControl as ControlComponent, layout: 'full' },
|
|
9
11
|
'accordion-items': { component: AccordionItemsControl as ControlComponent, layout: 'full' },
|
|
10
12
|
} as const satisfies ControlRegistry;
|