@elementor/editor-editing-panel 0.1.0 → 0.3.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 +22 -0
- package/dist/index.js +92 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +85 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
- package/src/__tests__/utils.ts +17 -0
- package/src/components/__tests__/editing-panel.test.tsx +96 -0
- package/src/components/editing-panel.tsx +27 -2
- package/src/contexts/settings-controls.tsx +32 -0
- package/src/hooks/use-element-type.ts +28 -0
- package/src/hooks/use-selected-elements.ts +12 -0
- package/src/sync/__tests__/should-use-v2-panel.test.ts +19 -27
- package/src/sync/get-selected-elements.ts +21 -0
- package/src/sync/get-widgets-cache.ts +7 -0
- package/src/sync/should-use-v2-panel.ts +5 -19
- package/src/sync/types.ts +26 -0
- package/src/types.ts +7 -13
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [0.3.0](https://github.com/elementor/elementor-packages/compare/@elementor/editor-editing-panel@0.2.0...@elementor/editor-editing-panel@0.3.0) (2024-07-14)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **editor-editing-panel:** element context [EDS-255] ([#200](https://github.com/elementor/elementor-packages/issues/200)) ([cff677e](https://github.com/elementor/elementor-packages/commit/cff677eec3690fe8b9569d5fd27c2512a981334c))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [0.2.0](https://github.com/elementor/elementor-packages/compare/@elementor/editor-editing-panel@0.1.0...@elementor/editor-editing-panel@0.2.0) (2024-07-11)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* **editor-editing-panel:** api for selecting and widget type [EDS-244] ([#199](https://github.com/elementor/elementor-packages/issues/199)) ([3e3da8a](https://github.com/elementor/elementor-packages/commit/3e3da8ac1dc37e502991f0905cbe8054422b3b71))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
# 0.1.0 (2024-07-08)
|
|
7
29
|
|
|
8
30
|
|
package/dist/index.js
CHANGED
|
@@ -26,11 +26,91 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
var import_editor_panels2 = require("@elementor/editor-panels");
|
|
27
27
|
|
|
28
28
|
// src/components/editing-panel.tsx
|
|
29
|
-
var
|
|
29
|
+
var React2 = __toESM(require("react"));
|
|
30
30
|
var import_editor_panels = require("@elementor/editor-panels");
|
|
31
31
|
var import_i18n = require("@wordpress/i18n");
|
|
32
|
+
|
|
33
|
+
// src/hooks/use-selected-elements.ts
|
|
34
|
+
var import_editor_v1_adapters = require("@elementor/editor-v1-adapters");
|
|
35
|
+
|
|
36
|
+
// src/sync/get-selected-elements.ts
|
|
37
|
+
function getSelectedElements() {
|
|
38
|
+
const extendedWindow = window;
|
|
39
|
+
const selectedElements = extendedWindow.elementor?.selection?.getElements?.() ?? [];
|
|
40
|
+
return selectedElements.reduce((acc, el) => {
|
|
41
|
+
const type = el.model.get("widgetType") || el.model.get("elType");
|
|
42
|
+
if (type) {
|
|
43
|
+
acc.push({
|
|
44
|
+
id: el.model.get("id"),
|
|
45
|
+
type
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return acc;
|
|
49
|
+
}, []);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/hooks/use-selected-elements.ts
|
|
53
|
+
function useSelectedElements() {
|
|
54
|
+
return (0, import_editor_v1_adapters.__privateUseListenTo)(
|
|
55
|
+
[
|
|
56
|
+
(0, import_editor_v1_adapters.commandEndEvent)("document/elements/select"),
|
|
57
|
+
(0, import_editor_v1_adapters.commandEndEvent)("document/elements/deselect")
|
|
58
|
+
],
|
|
59
|
+
() => getSelectedElements()
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/hooks/use-element-type.ts
|
|
64
|
+
var import_editor_v1_adapters2 = require("@elementor/editor-v1-adapters");
|
|
65
|
+
|
|
66
|
+
// src/sync/get-widgets-cache.ts
|
|
67
|
+
function getWidgetsCache() {
|
|
68
|
+
const extendedWindow = window;
|
|
69
|
+
return extendedWindow?.elementor?.widgetsCache || null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/hooks/use-element-type.ts
|
|
73
|
+
function useElementType(type) {
|
|
74
|
+
return (0, import_editor_v1_adapters2.__privateUseListenTo)(
|
|
75
|
+
(0, import_editor_v1_adapters2.commandEndEvent)("editor/documents/load"),
|
|
76
|
+
() => {
|
|
77
|
+
if (!type) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const widgetsCache = getWidgetsCache();
|
|
81
|
+
const elementType = widgetsCache?.[type];
|
|
82
|
+
if (!elementType?.atomic_controls) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
key: type,
|
|
87
|
+
controls: elementType.atomic_controls,
|
|
88
|
+
title: elementType.title
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
[type]
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/contexts/settings-controls.tsx
|
|
96
|
+
var React = __toESM(require("react"));
|
|
97
|
+
var import_react = require("react");
|
|
98
|
+
var Context = (0, import_react.createContext)(null);
|
|
99
|
+
function ElementContext({ children, element }) {
|
|
100
|
+
return /* @__PURE__ */ React.createElement(Context.Provider, { value: { element } }, children);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/components/editing-panel.tsx
|
|
104
|
+
var import_ui = require("@elementor/ui");
|
|
32
105
|
var EditingPanel = () => {
|
|
33
|
-
|
|
106
|
+
const elements = useSelectedElements();
|
|
107
|
+
const selectedElement = elements[0];
|
|
108
|
+
const elementType = useElementType(selectedElement?.type);
|
|
109
|
+
if (elements.length !== 1 || !elementType) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
const panelTitle = (0, import_i18n.__)("Edit %s", "elementor").replace("%s", elementType.title);
|
|
113
|
+
return /* @__PURE__ */ React2.createElement(import_editor_panels.Panel, null, /* @__PURE__ */ React2.createElement(import_editor_panels.PanelHeader, null, /* @__PURE__ */ React2.createElement(import_editor_panels.PanelHeaderTitle, null, panelTitle)), /* @__PURE__ */ React2.createElement(import_editor_panels.PanelBody, null, /* @__PURE__ */ React2.createElement(ElementContext, { element: selectedElement }, /* @__PURE__ */ React2.createElement(import_ui.Box, { padding: 2 }, /* @__PURE__ */ React2.createElement(import_ui.Typography, null, "Here should be the controls.")))));
|
|
34
114
|
};
|
|
35
115
|
|
|
36
116
|
// src/panel.ts
|
|
@@ -48,33 +128,22 @@ var import_editor = require("@elementor/editor");
|
|
|
48
128
|
|
|
49
129
|
// src/sync/should-use-v2-panel.ts
|
|
50
130
|
var shouldUseV2Panel = () => {
|
|
51
|
-
const selectedElements = getSelectedElements()
|
|
131
|
+
const selectedElements = getSelectedElements();
|
|
132
|
+
const widgetCache = getWidgetsCache();
|
|
52
133
|
if (selectedElements.length !== 1) {
|
|
53
134
|
return false;
|
|
54
135
|
}
|
|
55
|
-
return !!selectedElements[0].
|
|
136
|
+
return !!widgetCache?.[selectedElements[0].type]?.atomic_controls;
|
|
56
137
|
};
|
|
57
|
-
function getSelectedElements() {
|
|
58
|
-
const extendedWindow = window;
|
|
59
|
-
const elements = extendedWindow.elementor?.selection?.getElements?.() ?? [];
|
|
60
|
-
return elements.map((element) => {
|
|
61
|
-
const type = element.model.get("widgetType") || element.model.get("elType") || "";
|
|
62
|
-
const widgetSettings = extendedWindow.elementor?.widgetsCache[type];
|
|
63
|
-
return {
|
|
64
|
-
type,
|
|
65
|
-
atomicControls: widgetSettings?.atomic_controls || null
|
|
66
|
-
};
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
138
|
|
|
70
139
|
// src/hooks/use-open-editor-panel.ts
|
|
71
|
-
var
|
|
72
|
-
var
|
|
140
|
+
var import_react2 = require("react");
|
|
141
|
+
var import_editor_v1_adapters3 = require("@elementor/editor-v1-adapters");
|
|
73
142
|
var useOpenEditorPanel = () => {
|
|
74
143
|
const { open } = usePanelActions();
|
|
75
|
-
(0,
|
|
76
|
-
return (0,
|
|
77
|
-
(0,
|
|
144
|
+
(0, import_react2.useEffect)(() => {
|
|
145
|
+
return (0, import_editor_v1_adapters3.__privateListenTo)(
|
|
146
|
+
(0, import_editor_v1_adapters3.commandStartEvent)("panel/editor/open"),
|
|
78
147
|
() => {
|
|
79
148
|
if (shouldUseV2Panel()) {
|
|
80
149
|
open();
|
|
@@ -92,7 +161,7 @@ var EditingPanelHooks = () => {
|
|
|
92
161
|
|
|
93
162
|
// src/init.ts
|
|
94
163
|
var import_editor_panels3 = require("@elementor/editor-panels");
|
|
95
|
-
var
|
|
164
|
+
var import_editor_v1_adapters4 = require("@elementor/editor-v1-adapters");
|
|
96
165
|
function init() {
|
|
97
166
|
(0, import_editor_panels3.__registerPanel)(panel);
|
|
98
167
|
blockV1Panel();
|
|
@@ -102,7 +171,7 @@ function init() {
|
|
|
102
171
|
});
|
|
103
172
|
}
|
|
104
173
|
var blockV1Panel = () => {
|
|
105
|
-
(0,
|
|
174
|
+
(0, import_editor_v1_adapters4.__privateBlockDataCommand)({
|
|
106
175
|
command: "panel/editor/open",
|
|
107
176
|
condition: shouldUseV2Panel
|
|
108
177
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/panel.ts","../src/components/editing-panel.tsx","../src/init.ts","../src/sync/should-use-v2-panel.ts","../src/hooks/use-open-editor-panel.ts","../src/components/editing-panel-hooks.tsx","../src/index.ts"],"sourcesContent":["import { __createPanel as createPanel } from '@elementor/editor-panels';\nimport { EditingPanel } from './components/editing-panel';\n\nexport const {\n\tpanel,\n\tusePanelActions,\n\tusePanelStatus,\n} = createPanel( {\n\tid: 'editing-panel',\n\tcomponent: EditingPanel,\n} );\n","import * as React from 'react';\nimport {\n\tPanel,\n\tPanelBody,\n\tPanelHeader,\n\tPanelHeaderTitle,\n} from '@elementor/editor-panels';\nimport { __ } from '@wordpress/i18n';\n\nexport const EditingPanel = () => {\n\treturn (\n\t\t<Panel>\n\t\t\t<PanelHeader>\n\t\t\t\t<PanelHeaderTitle>{
|
|
1
|
+
{"version":3,"sources":["../src/panel.ts","../src/components/editing-panel.tsx","../src/hooks/use-selected-elements.ts","../src/sync/get-selected-elements.ts","../src/hooks/use-element-type.ts","../src/sync/get-widgets-cache.ts","../src/contexts/settings-controls.tsx","../src/init.ts","../src/sync/should-use-v2-panel.ts","../src/hooks/use-open-editor-panel.ts","../src/components/editing-panel-hooks.tsx","../src/index.ts"],"sourcesContent":["import { __createPanel as createPanel } from '@elementor/editor-panels';\nimport { EditingPanel } from './components/editing-panel';\n\nexport const {\n\tpanel,\n\tusePanelActions,\n\tusePanelStatus,\n} = createPanel( {\n\tid: 'editing-panel',\n\tcomponent: EditingPanel,\n} );\n","import * as React from 'react';\nimport {\n\tPanel,\n\tPanelBody,\n\tPanelHeader,\n\tPanelHeaderTitle,\n} from '@elementor/editor-panels';\nimport { __ } from '@wordpress/i18n';\nimport useSelectedElements from '../hooks/use-selected-elements';\nimport useElementType from '../hooks/use-element-type';\nimport { ElementContext } from '../contexts/settings-controls';\nimport { Box, Typography } from '@elementor/ui';\n\nexport const EditingPanel = () => {\n\tconst elements = useSelectedElements();\n\n\tconst selectedElement = elements[ 0 ];\n\n\tconst elementType = useElementType( selectedElement?.type );\n\n\tif ( elements.length !== 1 || ! elementType ) {\n\t\treturn null;\n\t}\n\n\t/* translators: %s: Element type title. */\n\tconst panelTitle = __( 'Edit %s', 'elementor' ).replace( '%s', elementType.title );\n\n\treturn (\n\t\t<Panel>\n\t\t\t<PanelHeader>\n\t\t\t\t<PanelHeaderTitle>{ panelTitle }</PanelHeaderTitle>\n\t\t\t</PanelHeader>\n\t\t\t<PanelBody>\n\t\t\t\t<ElementContext element={ selectedElement }>\n\t\t\t\t\t<Box padding={ 2 }>\n\t\t\t\t\t\t<Typography>\n\t\t\t\t\t\t\tHere should be the controls.\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t</Box>\n\t\t\t\t</ElementContext>\n\t\t\t</PanelBody>\n\t\t</Panel>\n\t);\n};\n","import { __privateUseListenTo as useListenTo, commandEndEvent } from '@elementor/editor-v1-adapters';\nimport getSelectedElements from '../sync/get-selected-elements';\n\nexport default function useSelectedElements() {\n\treturn useListenTo(\n\t\t[\n\t\t\tcommandEndEvent( 'document/elements/select' ),\n\t\t\tcommandEndEvent( 'document/elements/deselect' ),\n\t\t],\n\t\t() => getSelectedElements()\n\t);\n}\n","import { ExtendedWindow } from './types';\nimport { Element } from '../types';\n\nexport default function getSelectedElements(): Element[] {\n\tconst extendedWindow = window as unknown as ExtendedWindow;\n\n\tconst selectedElements = extendedWindow.elementor?.selection?.getElements?.() ?? [];\n\n\treturn selectedElements.reduce<Element[]>( ( acc, el ) => {\n\t\tconst type = el.model.get( 'widgetType' ) || el.model.get( 'elType' );\n\n\t\tif ( type ) {\n\t\t\tacc.push( {\n\t\t\t\tid: el.model.get( 'id' ),\n\t\t\t\ttype,\n\t\t\t} );\n\t\t}\n\n\t\treturn acc;\n\t}, [] );\n}\n","import { __privateUseListenTo as useListenTo, commandEndEvent } from '@elementor/editor-v1-adapters';\nimport getWidgetsCache from '../sync/get-widgets-cache';\nimport { ElementType } from '../types';\n\nexport default function useElementType( type?: string ) {\n\treturn useListenTo(\n\t\tcommandEndEvent( 'editor/documents/load' ),\n\t\t(): ElementType | null => {\n\t\t\tif ( ! type ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst widgetsCache = getWidgetsCache();\n\t\t\tconst elementType = widgetsCache?.[ type ];\n\n\t\t\tif ( ! elementType?.atomic_controls ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tkey: type,\n\t\t\t\tcontrols: elementType.atomic_controls,\n\t\t\t\ttitle: elementType.title,\n\t\t\t};\n\t\t},\n\t\t[ type ]\n\t);\n}\n","import { ExtendedWindow } from './types';\n\nexport default function getWidgetsCache() {\n\tconst extendedWindow = window as unknown as ExtendedWindow;\n\n\treturn extendedWindow?.elementor?.widgetsCache || null;\n}\n","import * as React from 'react';\nimport { createContext, ReactNode, useContext } from 'react';\nimport { Element } from '../types';\n\ntype ContextValue = {\n\telement: Element;\n}\n\nconst Context = createContext<ContextValue | null>( null );\n\ntype Props = {\n\telement: Element;\n\tchildren?: ReactNode;\n}\n\nexport function ElementContext( { children, element }: Props ) {\n\treturn (\n\t\t<Context.Provider value={ { element } }>\n\t\t\t{ children }\n\t\t</Context.Provider>\n\t);\n}\n\nexport function useElementContext() {\n\tconst context = useContext( Context );\n\n\tif ( ! context ) {\n\t\tthrow new Error( 'useElementContext must be used within a ElementContextProvider' );\n\t}\n\n\treturn context;\n}\n","import { panel } from './panel';\nimport { injectIntoLogic } from '@elementor/editor';\nimport { shouldUseV2Panel } from './sync/should-use-v2-panel';\nimport { EditingPanelHooks } from './components/editing-panel-hooks';\nimport { __registerPanel as registerPanel } from '@elementor/editor-panels';\nimport { __privateBlockDataCommand as blockDataCommand } from '@elementor/editor-v1-adapters';\n\nexport default function init() {\n\tregisterPanel( panel );\n\tblockV1Panel();\n\n\tinjectIntoLogic( {\n\t\tid: 'editing-panel-hooks',\n\t\tcomponent: EditingPanelHooks,\n\t} );\n}\n\nconst blockV1Panel = () => {\n\tblockDataCommand( {\n\t\tcommand: 'panel/editor/open',\n\t\tcondition: shouldUseV2Panel,\n\t} );\n};\n","import getSelectedElements from './get-selected-elements';\nimport getWidgetsCache from './get-widgets-cache';\n\nexport const shouldUseV2Panel = () => {\n\tconst selectedElements = getSelectedElements();\n\tconst widgetCache = getWidgetsCache();\n\n\tif ( selectedElements.length !== 1 ) {\n\t\treturn false;\n\t}\n\n\t// Check if the selected element has atomic controls, meaning it's a V2 element.\n\treturn !! widgetCache?.[ selectedElements[ 0 ].type ]?.atomic_controls;\n};\n","import { useEffect } from 'react';\nimport { commandStartEvent, __privateListenTo as listenTo } from '@elementor/editor-v1-adapters';\nimport { usePanelActions } from '../panel';\nimport { shouldUseV2Panel } from '../sync/should-use-v2-panel';\n\nexport const useOpenEditorPanel = () => {\n\tconst { open } = usePanelActions();\n\n\tuseEffect( () => {\n\t\treturn listenTo(\n\t\t\tcommandStartEvent( 'panel/editor/open' ),\n\t\t\t() => {\n\t\t\t\tif ( shouldUseV2Panel() ) {\n\t\t\t\t\topen();\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}, [] ); // eslint-disable-line react-hooks/exhaustive-deps\n};\n","import { useOpenEditorPanel } from '../hooks/use-open-editor-panel';\n\nexport const EditingPanelHooks = () => {\n\tuseOpenEditorPanel();\n\n\treturn null;\n};\n","import init from './init';\n\ninit();\n"],"mappings":"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","names":["import_editor_panels","React","useListenTo","import_editor_v1_adapters","useListenTo","createPanel","import_react","import_editor_v1_adapters","listenTo","import_editor_panels","import_editor_v1_adapters","registerPanel","blockDataCommand"]}
|
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { __createPanel as createPanel } from "@elementor/editor-panels";
|
|
3
3
|
|
|
4
4
|
// src/components/editing-panel.tsx
|
|
5
|
-
import * as
|
|
5
|
+
import * as React2 from "react";
|
|
6
6
|
import {
|
|
7
7
|
Panel,
|
|
8
8
|
PanelBody,
|
|
@@ -10,8 +10,88 @@ import {
|
|
|
10
10
|
PanelHeaderTitle
|
|
11
11
|
} from "@elementor/editor-panels";
|
|
12
12
|
import { __ } from "@wordpress/i18n";
|
|
13
|
+
|
|
14
|
+
// src/hooks/use-selected-elements.ts
|
|
15
|
+
import { __privateUseListenTo as useListenTo, commandEndEvent } from "@elementor/editor-v1-adapters";
|
|
16
|
+
|
|
17
|
+
// src/sync/get-selected-elements.ts
|
|
18
|
+
function getSelectedElements() {
|
|
19
|
+
const extendedWindow = window;
|
|
20
|
+
const selectedElements = extendedWindow.elementor?.selection?.getElements?.() ?? [];
|
|
21
|
+
return selectedElements.reduce((acc, el) => {
|
|
22
|
+
const type = el.model.get("widgetType") || el.model.get("elType");
|
|
23
|
+
if (type) {
|
|
24
|
+
acc.push({
|
|
25
|
+
id: el.model.get("id"),
|
|
26
|
+
type
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return acc;
|
|
30
|
+
}, []);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/hooks/use-selected-elements.ts
|
|
34
|
+
function useSelectedElements() {
|
|
35
|
+
return useListenTo(
|
|
36
|
+
[
|
|
37
|
+
commandEndEvent("document/elements/select"),
|
|
38
|
+
commandEndEvent("document/elements/deselect")
|
|
39
|
+
],
|
|
40
|
+
() => getSelectedElements()
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/hooks/use-element-type.ts
|
|
45
|
+
import { __privateUseListenTo as useListenTo2, commandEndEvent as commandEndEvent2 } from "@elementor/editor-v1-adapters";
|
|
46
|
+
|
|
47
|
+
// src/sync/get-widgets-cache.ts
|
|
48
|
+
function getWidgetsCache() {
|
|
49
|
+
const extendedWindow = window;
|
|
50
|
+
return extendedWindow?.elementor?.widgetsCache || null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/hooks/use-element-type.ts
|
|
54
|
+
function useElementType(type) {
|
|
55
|
+
return useListenTo2(
|
|
56
|
+
commandEndEvent2("editor/documents/load"),
|
|
57
|
+
() => {
|
|
58
|
+
if (!type) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const widgetsCache = getWidgetsCache();
|
|
62
|
+
const elementType = widgetsCache?.[type];
|
|
63
|
+
if (!elementType?.atomic_controls) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
key: type,
|
|
68
|
+
controls: elementType.atomic_controls,
|
|
69
|
+
title: elementType.title
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
[type]
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/contexts/settings-controls.tsx
|
|
77
|
+
import * as React from "react";
|
|
78
|
+
import { createContext, useContext } from "react";
|
|
79
|
+
var Context = createContext(null);
|
|
80
|
+
function ElementContext({ children, element }) {
|
|
81
|
+
return /* @__PURE__ */ React.createElement(Context.Provider, { value: { element } }, children);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/components/editing-panel.tsx
|
|
85
|
+
import { Box, Typography } from "@elementor/ui";
|
|
13
86
|
var EditingPanel = () => {
|
|
14
|
-
|
|
87
|
+
const elements = useSelectedElements();
|
|
88
|
+
const selectedElement = elements[0];
|
|
89
|
+
const elementType = useElementType(selectedElement?.type);
|
|
90
|
+
if (elements.length !== 1 || !elementType) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
const panelTitle = __("Edit %s", "elementor").replace("%s", elementType.title);
|
|
94
|
+
return /* @__PURE__ */ React2.createElement(Panel, null, /* @__PURE__ */ React2.createElement(PanelHeader, null, /* @__PURE__ */ React2.createElement(PanelHeaderTitle, null, panelTitle)), /* @__PURE__ */ React2.createElement(PanelBody, null, /* @__PURE__ */ React2.createElement(ElementContext, { element: selectedElement }, /* @__PURE__ */ React2.createElement(Box, { padding: 2 }, /* @__PURE__ */ React2.createElement(Typography, null, "Here should be the controls.")))));
|
|
15
95
|
};
|
|
16
96
|
|
|
17
97
|
// src/panel.ts
|
|
@@ -29,24 +109,13 @@ import { injectIntoLogic } from "@elementor/editor";
|
|
|
29
109
|
|
|
30
110
|
// src/sync/should-use-v2-panel.ts
|
|
31
111
|
var shouldUseV2Panel = () => {
|
|
32
|
-
const selectedElements = getSelectedElements()
|
|
112
|
+
const selectedElements = getSelectedElements();
|
|
113
|
+
const widgetCache = getWidgetsCache();
|
|
33
114
|
if (selectedElements.length !== 1) {
|
|
34
115
|
return false;
|
|
35
116
|
}
|
|
36
|
-
return !!selectedElements[0].
|
|
117
|
+
return !!widgetCache?.[selectedElements[0].type]?.atomic_controls;
|
|
37
118
|
};
|
|
38
|
-
function getSelectedElements() {
|
|
39
|
-
const extendedWindow = window;
|
|
40
|
-
const elements = extendedWindow.elementor?.selection?.getElements?.() ?? [];
|
|
41
|
-
return elements.map((element) => {
|
|
42
|
-
const type = element.model.get("widgetType") || element.model.get("elType") || "";
|
|
43
|
-
const widgetSettings = extendedWindow.elementor?.widgetsCache[type];
|
|
44
|
-
return {
|
|
45
|
-
type,
|
|
46
|
-
atomicControls: widgetSettings?.atomic_controls || null
|
|
47
|
-
};
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
119
|
|
|
51
120
|
// src/hooks/use-open-editor-panel.ts
|
|
52
121
|
import { useEffect } from "react";
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/panel.ts","../src/components/editing-panel.tsx","../src/init.ts","../src/sync/should-use-v2-panel.ts","../src/hooks/use-open-editor-panel.ts","../src/components/editing-panel-hooks.tsx","../src/index.ts"],"sourcesContent":["import { __createPanel as createPanel } from '@elementor/editor-panels';\nimport { EditingPanel } from './components/editing-panel';\n\nexport const {\n\tpanel,\n\tusePanelActions,\n\tusePanelStatus,\n} = createPanel( {\n\tid: 'editing-panel',\n\tcomponent: EditingPanel,\n} );\n","import * as React from 'react';\nimport {\n\tPanel,\n\tPanelBody,\n\tPanelHeader,\n\tPanelHeaderTitle,\n} from '@elementor/editor-panels';\nimport { __ } from '@wordpress/i18n';\n\nexport const EditingPanel = () => {\n\treturn (\n\t\t<Panel>\n\t\t\t<PanelHeader>\n\t\t\t\t<PanelHeaderTitle>{
|
|
1
|
+
{"version":3,"sources":["../src/panel.ts","../src/components/editing-panel.tsx","../src/hooks/use-selected-elements.ts","../src/sync/get-selected-elements.ts","../src/hooks/use-element-type.ts","../src/sync/get-widgets-cache.ts","../src/contexts/settings-controls.tsx","../src/init.ts","../src/sync/should-use-v2-panel.ts","../src/hooks/use-open-editor-panel.ts","../src/components/editing-panel-hooks.tsx","../src/index.ts"],"sourcesContent":["import { __createPanel as createPanel } from '@elementor/editor-panels';\nimport { EditingPanel } from './components/editing-panel';\n\nexport const {\n\tpanel,\n\tusePanelActions,\n\tusePanelStatus,\n} = createPanel( {\n\tid: 'editing-panel',\n\tcomponent: EditingPanel,\n} );\n","import * as React from 'react';\nimport {\n\tPanel,\n\tPanelBody,\n\tPanelHeader,\n\tPanelHeaderTitle,\n} from '@elementor/editor-panels';\nimport { __ } from '@wordpress/i18n';\nimport useSelectedElements from '../hooks/use-selected-elements';\nimport useElementType from '../hooks/use-element-type';\nimport { ElementContext } from '../contexts/settings-controls';\nimport { Box, Typography } from '@elementor/ui';\n\nexport const EditingPanel = () => {\n\tconst elements = useSelectedElements();\n\n\tconst selectedElement = elements[ 0 ];\n\n\tconst elementType = useElementType( selectedElement?.type );\n\n\tif ( elements.length !== 1 || ! elementType ) {\n\t\treturn null;\n\t}\n\n\t/* translators: %s: Element type title. */\n\tconst panelTitle = __( 'Edit %s', 'elementor' ).replace( '%s', elementType.title );\n\n\treturn (\n\t\t<Panel>\n\t\t\t<PanelHeader>\n\t\t\t\t<PanelHeaderTitle>{ panelTitle }</PanelHeaderTitle>\n\t\t\t</PanelHeader>\n\t\t\t<PanelBody>\n\t\t\t\t<ElementContext element={ selectedElement }>\n\t\t\t\t\t<Box padding={ 2 }>\n\t\t\t\t\t\t<Typography>\n\t\t\t\t\t\t\tHere should be the controls.\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t</Box>\n\t\t\t\t</ElementContext>\n\t\t\t</PanelBody>\n\t\t</Panel>\n\t);\n};\n","import { __privateUseListenTo as useListenTo, commandEndEvent } from '@elementor/editor-v1-adapters';\nimport getSelectedElements from '../sync/get-selected-elements';\n\nexport default function useSelectedElements() {\n\treturn useListenTo(\n\t\t[\n\t\t\tcommandEndEvent( 'document/elements/select' ),\n\t\t\tcommandEndEvent( 'document/elements/deselect' ),\n\t\t],\n\t\t() => getSelectedElements()\n\t);\n}\n","import { ExtendedWindow } from './types';\nimport { Element } from '../types';\n\nexport default function getSelectedElements(): Element[] {\n\tconst extendedWindow = window as unknown as ExtendedWindow;\n\n\tconst selectedElements = extendedWindow.elementor?.selection?.getElements?.() ?? [];\n\n\treturn selectedElements.reduce<Element[]>( ( acc, el ) => {\n\t\tconst type = el.model.get( 'widgetType' ) || el.model.get( 'elType' );\n\n\t\tif ( type ) {\n\t\t\tacc.push( {\n\t\t\t\tid: el.model.get( 'id' ),\n\t\t\t\ttype,\n\t\t\t} );\n\t\t}\n\n\t\treturn acc;\n\t}, [] );\n}\n","import { __privateUseListenTo as useListenTo, commandEndEvent } from '@elementor/editor-v1-adapters';\nimport getWidgetsCache from '../sync/get-widgets-cache';\nimport { ElementType } from '../types';\n\nexport default function useElementType( type?: string ) {\n\treturn useListenTo(\n\t\tcommandEndEvent( 'editor/documents/load' ),\n\t\t(): ElementType | null => {\n\t\t\tif ( ! type ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst widgetsCache = getWidgetsCache();\n\t\t\tconst elementType = widgetsCache?.[ type ];\n\n\t\t\tif ( ! elementType?.atomic_controls ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tkey: type,\n\t\t\t\tcontrols: elementType.atomic_controls,\n\t\t\t\ttitle: elementType.title,\n\t\t\t};\n\t\t},\n\t\t[ type ]\n\t);\n}\n","import { ExtendedWindow } from './types';\n\nexport default function getWidgetsCache() {\n\tconst extendedWindow = window as unknown as ExtendedWindow;\n\n\treturn extendedWindow?.elementor?.widgetsCache || null;\n}\n","import * as React from 'react';\nimport { createContext, ReactNode, useContext } from 'react';\nimport { Element } from '../types';\n\ntype ContextValue = {\n\telement: Element;\n}\n\nconst Context = createContext<ContextValue | null>( null );\n\ntype Props = {\n\telement: Element;\n\tchildren?: ReactNode;\n}\n\nexport function ElementContext( { children, element }: Props ) {\n\treturn (\n\t\t<Context.Provider value={ { element } }>\n\t\t\t{ children }\n\t\t</Context.Provider>\n\t);\n}\n\nexport function useElementContext() {\n\tconst context = useContext( Context );\n\n\tif ( ! context ) {\n\t\tthrow new Error( 'useElementContext must be used within a ElementContextProvider' );\n\t}\n\n\treturn context;\n}\n","import { panel } from './panel';\nimport { injectIntoLogic } from '@elementor/editor';\nimport { shouldUseV2Panel } from './sync/should-use-v2-panel';\nimport { EditingPanelHooks } from './components/editing-panel-hooks';\nimport { __registerPanel as registerPanel } from '@elementor/editor-panels';\nimport { __privateBlockDataCommand as blockDataCommand } from '@elementor/editor-v1-adapters';\n\nexport default function init() {\n\tregisterPanel( panel );\n\tblockV1Panel();\n\n\tinjectIntoLogic( {\n\t\tid: 'editing-panel-hooks',\n\t\tcomponent: EditingPanelHooks,\n\t} );\n}\n\nconst blockV1Panel = () => {\n\tblockDataCommand( {\n\t\tcommand: 'panel/editor/open',\n\t\tcondition: shouldUseV2Panel,\n\t} );\n};\n","import getSelectedElements from './get-selected-elements';\nimport getWidgetsCache from './get-widgets-cache';\n\nexport const shouldUseV2Panel = () => {\n\tconst selectedElements = getSelectedElements();\n\tconst widgetCache = getWidgetsCache();\n\n\tif ( selectedElements.length !== 1 ) {\n\t\treturn false;\n\t}\n\n\t// Check if the selected element has atomic controls, meaning it's a V2 element.\n\treturn !! widgetCache?.[ selectedElements[ 0 ].type ]?.atomic_controls;\n};\n","import { useEffect } from 'react';\nimport { commandStartEvent, __privateListenTo as listenTo } from '@elementor/editor-v1-adapters';\nimport { usePanelActions } from '../panel';\nimport { shouldUseV2Panel } from '../sync/should-use-v2-panel';\n\nexport const useOpenEditorPanel = () => {\n\tconst { open } = usePanelActions();\n\n\tuseEffect( () => {\n\t\treturn listenTo(\n\t\t\tcommandStartEvent( 'panel/editor/open' ),\n\t\t\t() => {\n\t\t\t\tif ( shouldUseV2Panel() ) {\n\t\t\t\t\topen();\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}, [] ); // eslint-disable-line react-hooks/exhaustive-deps\n};\n","import { useOpenEditorPanel } from '../hooks/use-open-editor-panel';\n\nexport const EditingPanelHooks = () => {\n\tuseOpenEditorPanel();\n\n\treturn null;\n};\n","import init from './init';\n\ninit();\n"],"mappings":"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","names":["React","useListenTo","commandEndEvent","useListenTo","commandEndEvent"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-editing-panel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Elementor Team",
|
|
6
6
|
"homepage": "https://elementor.com/",
|
|
@@ -35,10 +35,11 @@
|
|
|
35
35
|
"@elementor/editor": "^0.11.0",
|
|
36
36
|
"@elementor/editor-panels": "^0.4.15",
|
|
37
37
|
"@elementor/editor-v1-adapters": "^0.7.0",
|
|
38
|
+
"@elementor/ui": "^1.4.61",
|
|
38
39
|
"@wordpress/i18n": "^4.45.0"
|
|
39
40
|
},
|
|
40
41
|
"peerDependencies": {
|
|
41
42
|
"react": "^18.3.1"
|
|
42
43
|
},
|
|
43
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "24e239cdbfb5a4ec3776a7694d6800a5a79c08e8"
|
|
44
45
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { V1Element, V1ElementModelProps } from '../sync/types';
|
|
2
|
+
|
|
3
|
+
export function mockV1Element( partialSettings: Partial<V1ElementModelProps> ): V1Element {
|
|
4
|
+
const settings = {
|
|
5
|
+
elType: 'widget',
|
|
6
|
+
id: '1',
|
|
7
|
+
...partialSettings,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
model: {
|
|
12
|
+
get: ( key ) => {
|
|
13
|
+
return settings[ key ];
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { act, render, screen } from '@testing-library/react';
|
|
3
|
+
import { EditingPanel } from '../editing-panel';
|
|
4
|
+
import { V1Element, ExtendedWindow } from '../../sync/types';
|
|
5
|
+
import { mockV1Element } from '../../__tests__/utils';
|
|
6
|
+
import { dispatchCommandAfter } from 'test-utils';
|
|
7
|
+
|
|
8
|
+
describe( '<EditingPanel />', () => {
|
|
9
|
+
const getElements = jest.fn();
|
|
10
|
+
|
|
11
|
+
function selectElements( elements: V1Element[] ) {
|
|
12
|
+
act( () => {
|
|
13
|
+
getElements.mockReturnValue( elements );
|
|
14
|
+
dispatchCommandAfter( 'document/elements/select' );
|
|
15
|
+
} );
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function deselectElements() {
|
|
19
|
+
act( () => {
|
|
20
|
+
getElements.mockReturnValue( [] );
|
|
21
|
+
dispatchCommandAfter( 'document/elements/deselect' );
|
|
22
|
+
} );
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
beforeEach( () => {
|
|
26
|
+
const extendedWindow = window as unknown as ExtendedWindow;
|
|
27
|
+
|
|
28
|
+
extendedWindow.elementor = {
|
|
29
|
+
selection: {
|
|
30
|
+
getElements,
|
|
31
|
+
},
|
|
32
|
+
widgetsCache: {
|
|
33
|
+
'atomic-heading': {
|
|
34
|
+
controls: {},
|
|
35
|
+
atomic_controls: [],
|
|
36
|
+
title: 'Atomic Heading',
|
|
37
|
+
},
|
|
38
|
+
heading: {
|
|
39
|
+
controls: {},
|
|
40
|
+
title: 'Heading',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
} );
|
|
45
|
+
|
|
46
|
+
it( 'should render the selected element editing panel', () => {
|
|
47
|
+
// Arrange + Act.
|
|
48
|
+
render( <EditingPanel /> );
|
|
49
|
+
|
|
50
|
+
// Assert.
|
|
51
|
+
expect( screen.queryByText( 'Edit Atomic Heading' ) ).not.toBeInTheDocument();
|
|
52
|
+
|
|
53
|
+
// Act.
|
|
54
|
+
selectElements( [ mockV1Element( { widgetType: 'atomic-heading' } ) ] );
|
|
55
|
+
|
|
56
|
+
// Assert.
|
|
57
|
+
expect( screen.getByText( 'Edit Atomic Heading' ) ).toBeInTheDocument();
|
|
58
|
+
|
|
59
|
+
// Act.
|
|
60
|
+
deselectElements();
|
|
61
|
+
|
|
62
|
+
// Assert.
|
|
63
|
+
expect( screen.queryByText( 'Edit Atomic Heading' ) ).not.toBeInTheDocument();
|
|
64
|
+
} );
|
|
65
|
+
|
|
66
|
+
it.each( [
|
|
67
|
+
{
|
|
68
|
+
title: 'multiple elements are selected',
|
|
69
|
+
selected: [
|
|
70
|
+
mockV1Element( { widgetType: 'atomic-heading' } ),
|
|
71
|
+
mockV1Element( { widgetType: 'atomic-heading' } ),
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
title: 'the element type does not exist',
|
|
76
|
+
selected: [
|
|
77
|
+
mockV1Element( { widgetType: 'atomic-button' } ),
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
title: 'the element does not have atomic controls',
|
|
82
|
+
selected: [
|
|
83
|
+
mockV1Element( { widgetType: 'heading' } ),
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
] )( 'should not render panel when $title', ( { selected } ) => {
|
|
87
|
+
// Arrange.
|
|
88
|
+
selectElements( selected );
|
|
89
|
+
|
|
90
|
+
// Act.
|
|
91
|
+
render( <EditingPanel /> );
|
|
92
|
+
|
|
93
|
+
// Assert.
|
|
94
|
+
expect( screen.queryByText( 'Edit Atomic Heading' ) ).not.toBeInTheDocument();
|
|
95
|
+
} );
|
|
96
|
+
} );
|
|
@@ -6,14 +6,39 @@ import {
|
|
|
6
6
|
PanelHeaderTitle,
|
|
7
7
|
} from '@elementor/editor-panels';
|
|
8
8
|
import { __ } from '@wordpress/i18n';
|
|
9
|
+
import useSelectedElements from '../hooks/use-selected-elements';
|
|
10
|
+
import useElementType from '../hooks/use-element-type';
|
|
11
|
+
import { ElementContext } from '../contexts/settings-controls';
|
|
12
|
+
import { Box, Typography } from '@elementor/ui';
|
|
9
13
|
|
|
10
14
|
export const EditingPanel = () => {
|
|
15
|
+
const elements = useSelectedElements();
|
|
16
|
+
|
|
17
|
+
const selectedElement = elements[ 0 ];
|
|
18
|
+
|
|
19
|
+
const elementType = useElementType( selectedElement?.type );
|
|
20
|
+
|
|
21
|
+
if ( elements.length !== 1 || ! elementType ) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* translators: %s: Element type title. */
|
|
26
|
+
const panelTitle = __( 'Edit %s', 'elementor' ).replace( '%s', elementType.title );
|
|
27
|
+
|
|
11
28
|
return (
|
|
12
29
|
<Panel>
|
|
13
30
|
<PanelHeader>
|
|
14
|
-
<PanelHeaderTitle>{
|
|
31
|
+
<PanelHeaderTitle>{ panelTitle }</PanelHeaderTitle>
|
|
15
32
|
</PanelHeader>
|
|
16
|
-
<PanelBody
|
|
33
|
+
<PanelBody>
|
|
34
|
+
<ElementContext element={ selectedElement }>
|
|
35
|
+
<Box padding={ 2 }>
|
|
36
|
+
<Typography>
|
|
37
|
+
Here should be the controls.
|
|
38
|
+
</Typography>
|
|
39
|
+
</Box>
|
|
40
|
+
</ElementContext>
|
|
41
|
+
</PanelBody>
|
|
17
42
|
</Panel>
|
|
18
43
|
);
|
|
19
44
|
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { createContext, ReactNode, useContext } from 'react';
|
|
3
|
+
import { Element } from '../types';
|
|
4
|
+
|
|
5
|
+
type ContextValue = {
|
|
6
|
+
element: Element;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const Context = createContext<ContextValue | null>( null );
|
|
10
|
+
|
|
11
|
+
type Props = {
|
|
12
|
+
element: Element;
|
|
13
|
+
children?: ReactNode;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function ElementContext( { children, element }: Props ) {
|
|
17
|
+
return (
|
|
18
|
+
<Context.Provider value={ { element } }>
|
|
19
|
+
{ children }
|
|
20
|
+
</Context.Provider>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function useElementContext() {
|
|
25
|
+
const context = useContext( Context );
|
|
26
|
+
|
|
27
|
+
if ( ! context ) {
|
|
28
|
+
throw new Error( 'useElementContext must be used within a ElementContextProvider' );
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return context;
|
|
32
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { __privateUseListenTo as useListenTo, commandEndEvent } from '@elementor/editor-v1-adapters';
|
|
2
|
+
import getWidgetsCache from '../sync/get-widgets-cache';
|
|
3
|
+
import { ElementType } from '../types';
|
|
4
|
+
|
|
5
|
+
export default function useElementType( type?: string ) {
|
|
6
|
+
return useListenTo(
|
|
7
|
+
commandEndEvent( 'editor/documents/load' ),
|
|
8
|
+
(): ElementType | null => {
|
|
9
|
+
if ( ! type ) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const widgetsCache = getWidgetsCache();
|
|
14
|
+
const elementType = widgetsCache?.[ type ];
|
|
15
|
+
|
|
16
|
+
if ( ! elementType?.atomic_controls ) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
key: type,
|
|
22
|
+
controls: elementType.atomic_controls,
|
|
23
|
+
title: elementType.title,
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
[ type ]
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { __privateUseListenTo as useListenTo, commandEndEvent } from '@elementor/editor-v1-adapters';
|
|
2
|
+
import getSelectedElements from '../sync/get-selected-elements';
|
|
3
|
+
|
|
4
|
+
export default function useSelectedElements() {
|
|
5
|
+
return useListenTo(
|
|
6
|
+
[
|
|
7
|
+
commandEndEvent( 'document/elements/select' ),
|
|
8
|
+
commandEndEvent( 'document/elements/deselect' ),
|
|
9
|
+
],
|
|
10
|
+
() => getSelectedElements()
|
|
11
|
+
);
|
|
12
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { ExtendedWindow } from '
|
|
1
|
+
import { ExtendedWindow } from '../types';
|
|
2
2
|
import { shouldUseV2Panel } from '../should-use-v2-panel';
|
|
3
|
+
import { mockV1Element } from '../../__tests__/utils';
|
|
3
4
|
|
|
4
5
|
describe( 'shouldUseV2Panel', () => {
|
|
5
6
|
const getElements = jest.fn();
|
|
@@ -13,15 +14,18 @@ describe( 'shouldUseV2Panel', () => {
|
|
|
13
14
|
},
|
|
14
15
|
widgetsCache: {
|
|
15
16
|
'v1-heading': {
|
|
16
|
-
controls:
|
|
17
|
+
controls: {},
|
|
18
|
+
title: 'V1 Heading',
|
|
17
19
|
},
|
|
18
20
|
'v2-heading': {
|
|
19
|
-
controls:
|
|
21
|
+
controls: {},
|
|
20
22
|
atomic_controls: [],
|
|
23
|
+
title: 'V2 Heading',
|
|
21
24
|
},
|
|
22
25
|
'v2-container': {
|
|
23
|
-
controls:
|
|
26
|
+
controls: {},
|
|
24
27
|
atomic_controls: [],
|
|
28
|
+
title: 'V2 Container',
|
|
25
29
|
},
|
|
26
30
|
},
|
|
27
31
|
};
|
|
@@ -35,9 +39,9 @@ describe( 'shouldUseV2Panel', () => {
|
|
|
35
39
|
expect( shouldUseV2Panel() ).toBe( false );
|
|
36
40
|
} );
|
|
37
41
|
|
|
38
|
-
it( 'should return true for v2
|
|
42
|
+
it( 'should return true for v2 element', () => {
|
|
39
43
|
// Arrange.
|
|
40
|
-
getElements.mockReturnValue( [
|
|
44
|
+
getElements.mockReturnValue( [ mockV1Element( { widgetType: 'v2-heading' } ) ] );
|
|
41
45
|
|
|
42
46
|
// Assert.
|
|
43
47
|
expect( shouldUseV2Panel() ).toBe( true );
|
|
@@ -45,23 +49,23 @@ describe( 'shouldUseV2Panel', () => {
|
|
|
45
49
|
|
|
46
50
|
it( 'should return true for v2 element', () => {
|
|
47
51
|
// Arrange.
|
|
48
|
-
getElements.mockReturnValue( [
|
|
52
|
+
getElements.mockReturnValue( [ mockV1Element( { elType: 'v2-container' } ) ] );
|
|
49
53
|
|
|
50
54
|
// Assert.
|
|
51
55
|
expect( shouldUseV2Panel() ).toBe( true );
|
|
52
56
|
} );
|
|
53
57
|
|
|
54
|
-
it( 'should return false for v1
|
|
58
|
+
it( 'should return false for v1 element', () => {
|
|
55
59
|
// Arrange.
|
|
56
|
-
getElements.mockReturnValue( [
|
|
60
|
+
getElements.mockReturnValue( [ mockV1Element( { widgetType: 'v1-heading' } ) ] );
|
|
57
61
|
|
|
58
62
|
// Assert.
|
|
59
63
|
expect( shouldUseV2Panel() ).toBe( false );
|
|
60
64
|
} );
|
|
61
65
|
|
|
62
|
-
it( 'should return false for non-existing
|
|
66
|
+
it( 'should return false for non-existing element', () => {
|
|
63
67
|
// Arrange.
|
|
64
|
-
getElements.mockReturnValue( [
|
|
68
|
+
getElements.mockReturnValue( [ mockV1Element( { widgetType: 'non-existing' } ) ] );
|
|
65
69
|
|
|
66
70
|
// Assert.
|
|
67
71
|
expect( shouldUseV2Panel() ).toBe( false );
|
|
@@ -70,8 +74,8 @@ describe( 'shouldUseV2Panel', () => {
|
|
|
70
74
|
it( 'should return false if there is more than 1 selected element with mixed versions', () => {
|
|
71
75
|
// Arrange.
|
|
72
76
|
getElements.mockReturnValue( [
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
mockV1Element( { widgetType: 'v2-heading' } ),
|
|
78
|
+
mockV1Element( { widgetType: 'v1-heading' } ),
|
|
75
79
|
] );
|
|
76
80
|
|
|
77
81
|
// Assert.
|
|
@@ -81,23 +85,11 @@ describe( 'shouldUseV2Panel', () => {
|
|
|
81
85
|
it( 'should return false if there is more than 1 selected element with same version', () => {
|
|
82
86
|
// Arrange.
|
|
83
87
|
getElements.mockReturnValue( [
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
mockV1Element( { widgetType: 'v2-heading' } ),
|
|
89
|
+
mockV1Element( { widgetType: 'v2-container' } ),
|
|
86
90
|
] );
|
|
87
91
|
|
|
88
92
|
// Assert.
|
|
89
93
|
expect( shouldUseV2Panel() ).toBe( false );
|
|
90
94
|
} );
|
|
91
95
|
} );
|
|
92
|
-
|
|
93
|
-
function mockElement<T extends Record<string, unknown>>( settings: T ) {
|
|
94
|
-
return { model: mockModel( settings ) };
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function mockModel<T extends Record<string, unknown>>( settings: T ) {
|
|
98
|
-
return {
|
|
99
|
-
get: <K extends keyof T>( key: K ): T[K] => {
|
|
100
|
-
return settings[ key ];
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ExtendedWindow } from './types';
|
|
2
|
+
import { Element } from '../types';
|
|
3
|
+
|
|
4
|
+
export default function getSelectedElements(): Element[] {
|
|
5
|
+
const extendedWindow = window as unknown as ExtendedWindow;
|
|
6
|
+
|
|
7
|
+
const selectedElements = extendedWindow.elementor?.selection?.getElements?.() ?? [];
|
|
8
|
+
|
|
9
|
+
return selectedElements.reduce<Element[]>( ( acc, el ) => {
|
|
10
|
+
const type = el.model.get( 'widgetType' ) || el.model.get( 'elType' );
|
|
11
|
+
|
|
12
|
+
if ( type ) {
|
|
13
|
+
acc.push( {
|
|
14
|
+
id: el.model.get( 'id' ),
|
|
15
|
+
type,
|
|
16
|
+
} );
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return acc;
|
|
20
|
+
}, [] );
|
|
21
|
+
}
|
|
@@ -1,28 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
import getSelectedElements from './get-selected-elements';
|
|
2
|
+
import getWidgetsCache from './get-widgets-cache';
|
|
2
3
|
|
|
3
4
|
export const shouldUseV2Panel = () => {
|
|
4
|
-
const selectedElements = getSelectedElements()
|
|
5
|
+
const selectedElements = getSelectedElements();
|
|
6
|
+
const widgetCache = getWidgetsCache();
|
|
5
7
|
|
|
6
8
|
if ( selectedElements.length !== 1 ) {
|
|
7
9
|
return false;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
// Check if the selected element has atomic controls, meaning it's a V2 element.
|
|
11
|
-
return !! selectedElements[ 0 ].
|
|
13
|
+
return !! widgetCache?.[ selectedElements[ 0 ].type ]?.atomic_controls;
|
|
12
14
|
};
|
|
13
|
-
|
|
14
|
-
function getSelectedElements() {
|
|
15
|
-
const extendedWindow = window as unknown as ExtendedWindow;
|
|
16
|
-
|
|
17
|
-
const elements = extendedWindow.elementor?.selection?.getElements?.() ?? [ ];
|
|
18
|
-
|
|
19
|
-
return elements.map( ( element ) => {
|
|
20
|
-
const type = element.model.get( 'widgetType' ) || element.model.get( 'elType' ) || '';
|
|
21
|
-
const widgetSettings = extendedWindow.elementor?.widgetsCache[ type ];
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
type,
|
|
25
|
-
atomicControls: widgetSettings?.atomic_controls || null,
|
|
26
|
-
};
|
|
27
|
-
} );
|
|
28
|
-
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type ExtendedWindow = Window & {
|
|
2
|
+
elementor?: {
|
|
3
|
+
selection?: {
|
|
4
|
+
getElements: () => V1Element[];
|
|
5
|
+
},
|
|
6
|
+
widgetsCache?: Record<string, {
|
|
7
|
+
atomic_controls?: unknown[],
|
|
8
|
+
controls: object,
|
|
9
|
+
title: string,
|
|
10
|
+
}>
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type V1Element = {
|
|
15
|
+
model: V1ElementModel<V1ElementModelProps>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type V1ElementModelProps = {
|
|
19
|
+
widgetType?: string;
|
|
20
|
+
elType: string;
|
|
21
|
+
id: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type V1ElementModel<T> = {
|
|
25
|
+
get: <K extends keyof T>( key: K ) => T[K],
|
|
26
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
export type
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
getElements: () => ExtendedElement[];
|
|
5
|
-
},
|
|
6
|
-
widgetsCache: Record<string, { atomic_controls?: unknown[], controls: unknown[] }>
|
|
7
|
-
}
|
|
1
|
+
export type Element = {
|
|
2
|
+
id: string;
|
|
3
|
+
type: string;
|
|
8
4
|
}
|
|
9
5
|
|
|
10
|
-
export type
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
type ElementModel<T> = {
|
|
15
|
-
get: <K extends keyof T>( key: K ) => T[K],
|
|
6
|
+
export type ElementType = {
|
|
7
|
+
key: string;
|
|
8
|
+
controls: unknown[];
|
|
9
|
+
title: string;
|
|
16
10
|
}
|