@elementor/editor-editing-panel 3.33.0-139 → 3.33.0-140

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/editor-editing-panel",
3
- "version": "3.33.0-139",
3
+ "version": "3.33.0-140",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -39,26 +39,26 @@
39
39
  "dev": "tsup --config=../../tsup.dev.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@elementor/editor": "3.33.0-139",
43
- "@elementor/editor-canvas": "3.33.0-139",
44
- "@elementor/editor-controls": "3.33.0-139",
45
- "@elementor/editor-documents": "3.33.0-139",
46
- "@elementor/editor-elements": "3.33.0-139",
47
- "@elementor/editor-panels": "3.33.0-139",
48
- "@elementor/editor-props": "3.33.0-139",
49
- "@elementor/editor-responsive": "3.33.0-139",
50
- "@elementor/editor-styles": "3.33.0-139",
51
- "@elementor/editor-styles-repository": "3.33.0-139",
52
- "@elementor/editor-ui": "3.33.0-139",
53
- "@elementor/editor-v1-adapters": "3.33.0-139",
42
+ "@elementor/editor": "3.33.0-140",
43
+ "@elementor/editor-canvas": "3.33.0-140",
44
+ "@elementor/editor-controls": "3.33.0-140",
45
+ "@elementor/editor-documents": "3.33.0-140",
46
+ "@elementor/editor-elements": "3.33.0-140",
47
+ "@elementor/editor-panels": "3.33.0-140",
48
+ "@elementor/editor-props": "3.33.0-140",
49
+ "@elementor/editor-responsive": "3.33.0-140",
50
+ "@elementor/editor-styles": "3.33.0-140",
51
+ "@elementor/editor-styles-repository": "3.33.0-140",
52
+ "@elementor/editor-ui": "3.33.0-140",
53
+ "@elementor/editor-v1-adapters": "3.33.0-140",
54
54
  "@elementor/icons": "1.46.0",
55
- "@elementor/locations": "3.33.0-139",
56
- "@elementor/menus": "3.33.0-139",
57
- "@elementor/schema": "3.33.0-139",
58
- "@elementor/session": "3.33.0-139",
55
+ "@elementor/locations": "3.33.0-140",
56
+ "@elementor/menus": "3.33.0-140",
57
+ "@elementor/schema": "3.33.0-140",
58
+ "@elementor/session": "3.33.0-140",
59
59
  "@elementor/ui": "1.36.12",
60
- "@elementor/utils": "3.33.0-139",
61
- "@elementor/wp-media": "3.33.0-139",
60
+ "@elementor/utils": "3.33.0-140",
61
+ "@elementor/wp-media": "3.33.0-140",
62
62
  "@wordpress/i18n": "^5.13.0"
63
63
  },
64
64
  "peerDependencies": {
@@ -0,0 +1,21 @@
1
+ import { getContainer } from '@elementor/editor-elements';
2
+
3
+ export const getElementByType = ( elementId: string, type: string ) => {
4
+ const currentElement = getContainer( elementId );
5
+
6
+ if ( ! currentElement ) {
7
+ throw new Error( `Current element not found, elementId: ${ elementId }` );
8
+ }
9
+
10
+ if ( currentElement.model.get( 'elType' ) === type ) {
11
+ return currentElement;
12
+ }
13
+
14
+ const element = currentElement.children?.findRecursive?.( ( child ) => child.model.get( 'elType' ) === type );
15
+
16
+ if ( ! element ) {
17
+ throw new Error( `Child element ${ type } not found` );
18
+ }
19
+
20
+ return element;
21
+ };
@@ -0,0 +1,151 @@
1
+ import { type ItemActionPayload } from '@elementor/editor-controls';
2
+ import {
3
+ createElements,
4
+ duplicateElements,
5
+ generateElementId,
6
+ getElementSetting,
7
+ moveElements,
8
+ removeElements,
9
+ updateElementSettings,
10
+ } from '@elementor/editor-elements';
11
+ import { stringPropTypeUtil, type StringPropValue } from '@elementor/editor-props';
12
+ import { __ } from '@wordpress/i18n';
13
+
14
+ export type TabItem = {
15
+ id?: string;
16
+ title?: string;
17
+ };
18
+
19
+ export const TAB_ELEMENT_TYPE = 'e-tab';
20
+ export const TAB_PANEL_ELEMENT_TYPE = 'e-tab-panel';
21
+
22
+ export const duplicateItem = ( { items }: { items: ItemActionPayload< TabItem > } ) => {
23
+ items.forEach( ( { item } ) => {
24
+ const tabId = item.id as string;
25
+
26
+ const { value: tabPanelId } = getElementSetting< StringPropValue >( tabId, 'tab-panel-id' ) ?? {};
27
+
28
+ if ( ! tabPanelId ) {
29
+ throw new Error( 'Original panel ID is required for duplication' );
30
+ }
31
+
32
+ duplicateElements( {
33
+ elementIds: [ tabId, tabPanelId ],
34
+ title: __( 'Duplicate Tab', 'elementor' ),
35
+ onCreate: ( duplicatedElements ) => {
36
+ const tab = duplicatedElements.find( ( element ) => element.originalElementId === tabId );
37
+ const tabPanel = duplicatedElements.find( ( element ) => element.originalElementId === tabPanelId );
38
+
39
+ if ( tabPanel && tab ) {
40
+ updateElementSettings( {
41
+ withHistory: false,
42
+ id: tab.id,
43
+ props: {
44
+ 'tab-panel-id': stringPropTypeUtil.create( tabPanel.id ),
45
+ },
46
+ } );
47
+ updateElementSettings( {
48
+ withHistory: false,
49
+ id: tabPanel.id,
50
+ props: {
51
+ 'tab-id': stringPropTypeUtil.create( tab.id ),
52
+ },
53
+ } );
54
+ }
55
+ },
56
+ } );
57
+ } );
58
+ };
59
+
60
+ export const moveItem = ( {
61
+ toIndex,
62
+ tabListId,
63
+ tabContentId,
64
+ movedElementId,
65
+ }: {
66
+ toIndex: number;
67
+ tabListId: string;
68
+ tabContentId: string;
69
+ movedElementId: string;
70
+ } ) => {
71
+ const { value: tabPanelId } = getElementSetting< StringPropValue >( movedElementId, 'tab-panel-id' ) ?? {};
72
+
73
+ if ( ! tabPanelId ) {
74
+ throw new Error( 'Required tab elements not found for reordering' );
75
+ }
76
+
77
+ moveElements( {
78
+ title: __( 'Reorder Tabs', 'elementor' ),
79
+ moves: [
80
+ {
81
+ elementId: movedElementId,
82
+ targetContainerId: tabListId,
83
+ options: { at: toIndex },
84
+ },
85
+ {
86
+ elementId: tabPanelId,
87
+ targetContainerId: tabContentId,
88
+ options: { at: toIndex },
89
+ },
90
+ ],
91
+ } );
92
+ };
93
+
94
+ export const removeItem = ( { items }: { items: ItemActionPayload< TabItem > } ) => {
95
+ removeElements( {
96
+ title: __( 'Tabs', 'elementor' ),
97
+ elementIds: items.flatMap( ( { item } ) => {
98
+ const tabId = item.id as string;
99
+ const { value: panelId } = getElementSetting< StringPropValue >( tabId, 'tab-panel-id' ) ?? {};
100
+
101
+ if ( ! panelId ) {
102
+ throw new Error( 'Pane ID is required' );
103
+ }
104
+
105
+ return [ tabId, panelId ];
106
+ } ),
107
+ } );
108
+ };
109
+
110
+ export const addItem = ( {
111
+ tabContentId,
112
+ tabListId,
113
+ items,
114
+ }: {
115
+ tabContentId: string;
116
+ tabListId: string;
117
+ items: ItemActionPayload< TabItem >;
118
+ } ) => {
119
+ items.forEach( ( { item, index } ) => {
120
+ const newTabPanelId = generateElementId();
121
+ const newTabId = generateElementId();
122
+
123
+ createElements( {
124
+ title: __( 'Tabs', 'elementor' ),
125
+ elements: [
126
+ {
127
+ containerId: tabContentId,
128
+ model: {
129
+ id: newTabPanelId,
130
+ elType: TAB_PANEL_ELEMENT_TYPE,
131
+ settings: {
132
+ 'tab-id': stringPropTypeUtil.create( newTabId ),
133
+ },
134
+ },
135
+ },
136
+ {
137
+ containerId: tabListId,
138
+ model: {
139
+ id: newTabId,
140
+ elType: TAB_ELEMENT_TYPE,
141
+ settings: {
142
+ ...item,
143
+ 'tab-panel-id': stringPropTypeUtil.create( newTabPanelId ),
144
+ },
145
+ editor_settings: { title: `Tab #${ index + 1 }` },
146
+ },
147
+ },
148
+ ],
149
+ } );
150
+ } );
151
+ };
@@ -0,0 +1,163 @@
1
+ import * as React from 'react';
2
+ import { ControlFormLabel, Repeater, type RepeaterItem, type SetRepeaterValuesMeta } from '@elementor/editor-controls';
3
+ import {
4
+ type Element,
5
+ getElementEditorSettings,
6
+ updateElementEditorSettings,
7
+ useElementChildren,
8
+ useElementEditorSettings,
9
+ useElementType,
10
+ } from '@elementor/editor-elements';
11
+ import { type CreateOptions } from '@elementor/editor-props';
12
+ import { Stack, TextField } from '@elementor/ui';
13
+ import { __ } from '@wordpress/i18n';
14
+
15
+ import { ElementProvider, useElement } from '../../../contexts/element-context';
16
+ import { getElementByType } from '../get-element-by-type';
17
+ import { addItem, duplicateItem, moveItem, removeItem, TAB_ELEMENT_TYPE, type TabItem } from './actions';
18
+
19
+ const TAB_LIST_ELEMENT_TYPE = 'e-tabs-list';
20
+ const TAB_CONTENT_ELEMENT_TYPE = 'e-tabs-content';
21
+
22
+ type ChildElement = {
23
+ type: string;
24
+ target_container_selector: string;
25
+ };
26
+
27
+ export const TabsControl = ( { childElements }: { childElements: ChildElement[] } ) => {
28
+ const { element } = useElement();
29
+
30
+ const { [ TAB_ELEMENT_TYPE ]: tabLinks } = useElementChildren(
31
+ element.id,
32
+ childElements.map( ( child ) => child.type )
33
+ );
34
+
35
+ const tabList = getElementByType( element.id, TAB_LIST_ELEMENT_TYPE );
36
+ const tabContent = getElementByType( element.id, TAB_CONTENT_ELEMENT_TYPE );
37
+
38
+ const repeaterValues: RepeaterItem< TabItem >[] = tabLinks.map( ( tabLink ) => {
39
+ const { title: titleSetting } = getElementEditorSettings( tabLink.id ) ?? {};
40
+
41
+ return {
42
+ id: tabLink.id,
43
+ title: titleSetting,
44
+ };
45
+ } );
46
+
47
+ const setValue = (
48
+ _newValues: RepeaterItem< TabItem >[],
49
+ _options: CreateOptions,
50
+ meta?: SetRepeaterValuesMeta< RepeaterItem< TabItem > >
51
+ ) => {
52
+ if ( meta?.action?.type === 'add' ) {
53
+ const items = meta.action.payload;
54
+
55
+ return addItem( { tabContentId: tabContent.id, items, tabListId: tabList.id } );
56
+ }
57
+
58
+ if ( meta?.action?.type === 'remove' ) {
59
+ const items = meta.action.payload;
60
+
61
+ return removeItem( { items } );
62
+ }
63
+
64
+ if ( meta?.action?.type === 'duplicate' ) {
65
+ const items = meta.action.payload;
66
+
67
+ return duplicateItem( { items } );
68
+ }
69
+
70
+ if ( meta?.action?.type === 'reorder' ) {
71
+ const { from, to } = meta.action.payload;
72
+
73
+ return moveItem( {
74
+ toIndex: to,
75
+ tabListId: tabList.id,
76
+ tabContentId: tabContent.id,
77
+ movedElementId: tabLinks[ from ].id,
78
+ } );
79
+ }
80
+ };
81
+
82
+ return (
83
+ <Repeater
84
+ addToBottom
85
+ showToggle={ false }
86
+ openOnAdd={ false }
87
+ values={ repeaterValues }
88
+ setValues={ setValue }
89
+ label={ __( 'Tabs', 'elementor' ) }
90
+ itemSettings={ {
91
+ initialValues: { title: 'Tab' },
92
+ Label: ( props ) => (
93
+ <ElementItem { ...props }>
94
+ <ItemLabel value={ props.value } />
95
+ </ElementItem>
96
+ ),
97
+ Content: ( props ) => (
98
+ <ElementItem { ...props }>
99
+ <ItemContent />
100
+ </ElementItem>
101
+ ),
102
+ Icon: () => null,
103
+ } }
104
+ />
105
+ );
106
+ };
107
+
108
+ const ItemLabel = ( { value }: { value: TabItem } ) => {
109
+ const id = value.id ?? '';
110
+
111
+ const editorSettings = useElementEditorSettings( id );
112
+
113
+ const elementTitle = editorSettings?.title;
114
+
115
+ return (
116
+ <Stack sx={ { minHeight: 20 } } direction="row" alignItems="center">
117
+ <span>{ elementTitle }</span>
118
+ </Stack>
119
+ );
120
+ };
121
+
122
+ const ItemContent = () => {
123
+ const { element } = useElement();
124
+
125
+ const editorSettings = useElementEditorSettings( element.id );
126
+
127
+ const label = editorSettings?.title ?? '';
128
+
129
+ return (
130
+ <Stack p={ 2 }>
131
+ <ControlFormLabel sx={ { mb: 1 } }>{ __( 'Tab name', 'elementor' ) }</ControlFormLabel>
132
+ <TextField
133
+ value={ label }
134
+ size="tiny"
135
+ onChange={ ( { target }: React.ChangeEvent< HTMLInputElement > ) => {
136
+ updateElementEditorSettings( {
137
+ elementId: element.id,
138
+ settings: { title: target.value },
139
+ } );
140
+ } }
141
+ />
142
+ </Stack>
143
+ );
144
+ };
145
+
146
+ const ElementItem = ( { children, value }: { children: React.ReactNode; value: TabItem } ) => {
147
+ const elementType = useElementType( TAB_ELEMENT_TYPE );
148
+
149
+ if ( ! elementType ) {
150
+ return null;
151
+ }
152
+
153
+ const element: Element = {
154
+ id: value.id ?? '',
155
+ type: elementType.key,
156
+ };
157
+
158
+ return (
159
+ <ElementProvider element={ element } elementType={ elementType }>
160
+ { children }
161
+ </ElementProvider>
162
+ );
163
+ };