@elementor/editor-editing-panel 0.1.0 → 0.2.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 CHANGED
@@ -3,6 +3,17 @@
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.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)
7
+
8
+
9
+ ### Features
10
+
11
+ * **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))
12
+
13
+
14
+
15
+
16
+
6
17
  # 0.1.0 (2024-07-08)
7
18
 
8
19
 
package/dist/index.js CHANGED
@@ -29,8 +29,78 @@ var import_editor_panels2 = require("@elementor/editor-panels");
29
29
  var React = __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/components/editing-panel.tsx
32
96
  var EditingPanel = () => {
33
- return /* @__PURE__ */ React.createElement(import_editor_panels.Panel, null, /* @__PURE__ */ React.createElement(import_editor_panels.PanelHeader, null, /* @__PURE__ */ React.createElement(import_editor_panels.PanelHeaderTitle, null, (0, import_i18n.__)("Editing Panel", "elementor"))), /* @__PURE__ */ React.createElement(import_editor_panels.PanelBody, null));
97
+ const elements = useSelectedElements();
98
+ const elementType = useElementType(elements[0]?.type);
99
+ if (elements.length !== 1 || !elementType) {
100
+ return null;
101
+ }
102
+ const panelTitle = (0, import_i18n.__)("Edit %s", "elementor").replace("%s", elementType.title);
103
+ return /* @__PURE__ */ React.createElement(import_editor_panels.Panel, null, /* @__PURE__ */ React.createElement(import_editor_panels.PanelHeader, null, /* @__PURE__ */ React.createElement(import_editor_panels.PanelHeaderTitle, null, panelTitle)), /* @__PURE__ */ React.createElement(import_editor_panels.PanelBody, null));
34
104
  };
35
105
 
36
106
  // src/panel.ts
@@ -48,33 +118,22 @@ var import_editor = require("@elementor/editor");
48
118
 
49
119
  // src/sync/should-use-v2-panel.ts
50
120
  var shouldUseV2Panel = () => {
51
- const selectedElements = getSelectedElements() ?? [];
121
+ const selectedElements = getSelectedElements();
122
+ const widgetCache = getWidgetsCache();
52
123
  if (selectedElements.length !== 1) {
53
124
  return false;
54
125
  }
55
- return !!selectedElements[0].atomicControls;
126
+ return !!widgetCache?.[selectedElements[0].type]?.atomic_controls;
56
127
  };
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
128
 
70
129
  // src/hooks/use-open-editor-panel.ts
71
130
  var import_react = require("react");
72
- var import_editor_v1_adapters = require("@elementor/editor-v1-adapters");
131
+ var import_editor_v1_adapters3 = require("@elementor/editor-v1-adapters");
73
132
  var useOpenEditorPanel = () => {
74
133
  const { open } = usePanelActions();
75
134
  (0, import_react.useEffect)(() => {
76
- return (0, import_editor_v1_adapters.__privateListenTo)(
77
- (0, import_editor_v1_adapters.commandStartEvent)("panel/editor/open"),
135
+ return (0, import_editor_v1_adapters3.__privateListenTo)(
136
+ (0, import_editor_v1_adapters3.commandStartEvent)("panel/editor/open"),
78
137
  () => {
79
138
  if (shouldUseV2Panel()) {
80
139
  open();
@@ -92,7 +151,7 @@ var EditingPanelHooks = () => {
92
151
 
93
152
  // src/init.ts
94
153
  var import_editor_panels3 = require("@elementor/editor-panels");
95
- var import_editor_v1_adapters2 = require("@elementor/editor-v1-adapters");
154
+ var import_editor_v1_adapters4 = require("@elementor/editor-v1-adapters");
96
155
  function init() {
97
156
  (0, import_editor_panels3.__registerPanel)(panel);
98
157
  blockV1Panel();
@@ -102,7 +161,7 @@ function init() {
102
161
  });
103
162
  }
104
163
  var blockV1Panel = () => {
105
- (0, import_editor_v1_adapters2.__privateBlockDataCommand)({
164
+ (0, import_editor_v1_adapters4.__privateBlockDataCommand)({
106
165
  command: "panel/editor/open",
107
166
  condition: shouldUseV2Panel
108
167
  });
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>{ __( 'Editing Panel', 'elementor' ) }</PanelHeaderTitle>\n\t\t\t</PanelHeader>\n\t\t\t<PanelBody></PanelBody>\n\t\t</Panel>\n\t);\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 { ExtendedWindow } from '../types';\n\nexport const shouldUseV2Panel = () => {\n\tconst selectedElements = getSelectedElements() ?? [ ];\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 !! selectedElements[ 0 ].atomicControls;\n};\n\nfunction getSelectedElements() {\n\tconst extendedWindow = window as unknown as ExtendedWindow;\n\n\tconst elements = extendedWindow.elementor?.selection?.getElements?.() ?? [ ];\n\n\treturn elements.map( ( element ) => {\n\t\tconst type = element.model.get( 'widgetType' ) || element.model.get( 'elType' ) || '';\n\t\tconst widgetSettings = extendedWindow.elementor?.widgetsCache[ type ];\n\n\t\treturn {\n\t\t\ttype,\n\t\t\tatomicControls: widgetSettings?.atomic_controls || null,\n\t\t};\n\t} );\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":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,wBAA6C;;;ACA7C,YAAuB;AACvB,2BAKO;AACP,kBAAmB;AAEZ,IAAM,eAAe,MAAM;AACjC,SACC,oCAAC,kCACA,oCAAC,wCACA,oCAAC,iDAAmB,gBAAI,iBAAiB,WAAY,CAAG,CACzD,GACA,oCAAC,oCAAU,CACZ;AAEF;;;ADfO,IAAM;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AACD,QAAI,sBAAAC,eAAa;AAAA,EAChB,IAAI;AAAA,EACJ,WAAW;AACZ,CAAE;;;AETF,oBAAgC;;;ACCzB,IAAM,mBAAmB,MAAM;AACrC,QAAM,mBAAmB,oBAAoB,KAAK,CAAE;AAEpD,MAAK,iBAAiB,WAAW,GAAI;AACpC,WAAO;AAAA,EACR;AAGA,SAAO,CAAC,CAAE,iBAAkB,CAAE,EAAE;AACjC;AAEA,SAAS,sBAAsB;AAC9B,QAAM,iBAAiB;AAEvB,QAAM,WAAW,eAAe,WAAW,WAAW,cAAc,KAAK,CAAE;AAE3E,SAAO,SAAS,IAAK,CAAE,YAAa;AACnC,UAAM,OAAO,QAAQ,MAAM,IAAK,YAAa,KAAK,QAAQ,MAAM,IAAK,QAAS,KAAK;AACnF,UAAM,iBAAiB,eAAe,WAAW,aAAc,IAAK;AAEpE,WAAO;AAAA,MACN;AAAA,MACA,gBAAgB,gBAAgB,mBAAmB;AAAA,IACpD;AAAA,EACD,CAAE;AACH;;;AC3BA,mBAA0B;AAC1B,gCAAiE;AAI1D,IAAM,qBAAqB,MAAM;AACvC,QAAM,EAAE,KAAK,IAAI,gBAAgB;AAEjC,8BAAW,MAAM;AAChB,eAAO,0BAAAC;AAAA,UACN,6CAAmB,mBAAoB;AAAA,MACvC,MAAM;AACL,YAAK,iBAAiB,GAAI;AACzB,eAAK;AAAA,QACN;AAAA,MACD;AAAA,IACD;AAAA,EACD,GAAG,CAAC,CAAE;AACP;;;AChBO,IAAM,oBAAoB,MAAM;AACtC,qBAAmB;AAEnB,SAAO;AACR;;;AHFA,IAAAC,wBAAiD;AACjD,IAAAC,6BAA8D;AAE/C,SAAR,OAAwB;AAC9B,4BAAAC,iBAAe,KAAM;AACrB,eAAa;AAEb,qCAAiB;AAAA,IAChB,IAAI;AAAA,IACJ,WAAW;AAAA,EACZ,CAAE;AACH;AAEA,IAAM,eAAe,MAAM;AAC1B,iCAAAC,2BAAkB;AAAA,IACjB,SAAS;AAAA,IACT,WAAW;AAAA,EACZ,CAAE;AACH;;;AIpBA,KAAK;","names":["import_editor_panels","createPanel","listenTo","import_editor_panels","import_editor_v1_adapters","registerPanel","blockDataCommand"]}
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/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';\n\nexport const EditingPanel = () => {\n\tconst elements = useSelectedElements();\n\tconst elementType = useElementType( elements[ 0 ]?.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></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 { 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","useListenTo","import_editor_v1_adapters","useListenTo","createPanel","import_editor_v1_adapters","listenTo","import_editor_panels","import_editor_v1_adapters","registerPanel","blockDataCommand"]}
package/dist/index.mjs CHANGED
@@ -10,8 +10,78 @@ 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/components/editing-panel.tsx
13
77
  var EditingPanel = () => {
14
- return /* @__PURE__ */ React.createElement(Panel, null, /* @__PURE__ */ React.createElement(PanelHeader, null, /* @__PURE__ */ React.createElement(PanelHeaderTitle, null, __("Editing Panel", "elementor"))), /* @__PURE__ */ React.createElement(PanelBody, null));
78
+ const elements = useSelectedElements();
79
+ const elementType = useElementType(elements[0]?.type);
80
+ if (elements.length !== 1 || !elementType) {
81
+ return null;
82
+ }
83
+ const panelTitle = __("Edit %s", "elementor").replace("%s", elementType.title);
84
+ return /* @__PURE__ */ React.createElement(Panel, null, /* @__PURE__ */ React.createElement(PanelHeader, null, /* @__PURE__ */ React.createElement(PanelHeaderTitle, null, panelTitle)), /* @__PURE__ */ React.createElement(PanelBody, null));
15
85
  };
16
86
 
17
87
  // src/panel.ts
@@ -29,24 +99,13 @@ import { injectIntoLogic } from "@elementor/editor";
29
99
 
30
100
  // src/sync/should-use-v2-panel.ts
31
101
  var shouldUseV2Panel = () => {
32
- const selectedElements = getSelectedElements() ?? [];
102
+ const selectedElements = getSelectedElements();
103
+ const widgetCache = getWidgetsCache();
33
104
  if (selectedElements.length !== 1) {
34
105
  return false;
35
106
  }
36
- return !!selectedElements[0].atomicControls;
107
+ return !!widgetCache?.[selectedElements[0].type]?.atomic_controls;
37
108
  };
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
109
 
51
110
  // src/hooks/use-open-editor-panel.ts
52
111
  import { useEffect } from "react";
@@ -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>{ __( 'Editing Panel', 'elementor' ) }</PanelHeaderTitle>\n\t\t\t</PanelHeader>\n\t\t\t<PanelBody></PanelBody>\n\t\t</Panel>\n\t);\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 { ExtendedWindow } from '../types';\n\nexport const shouldUseV2Panel = () => {\n\tconst selectedElements = getSelectedElements() ?? [ ];\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 !! selectedElements[ 0 ].atomicControls;\n};\n\nfunction getSelectedElements() {\n\tconst extendedWindow = window as unknown as ExtendedWindow;\n\n\tconst elements = extendedWindow.elementor?.selection?.getElements?.() ?? [ ];\n\n\treturn elements.map( ( element ) => {\n\t\tconst type = element.model.get( 'widgetType' ) || element.model.get( 'elType' ) || '';\n\t\tconst widgetSettings = extendedWindow.elementor?.widgetsCache[ type ];\n\n\t\treturn {\n\t\t\ttype,\n\t\t\tatomicControls: widgetSettings?.atomic_controls || null,\n\t\t};\n\t} );\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":";AAAA,SAAS,iBAAiB,mBAAmB;;;ACA7C,YAAY,WAAW;AACvB;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,UAAU;AAEZ,IAAM,eAAe,MAAM;AACjC,SACC,oCAAC,aACA,oCAAC,mBACA,oCAAC,wBAAmB,GAAI,iBAAiB,WAAY,CAAG,CACzD,GACA,oCAAC,eAAU,CACZ;AAEF;;;ADfO,IAAM;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AACD,IAAI,YAAa;AAAA,EAChB,IAAI;AAAA,EACJ,WAAW;AACZ,CAAE;;;AETF,SAAS,uBAAuB;;;ACCzB,IAAM,mBAAmB,MAAM;AACrC,QAAM,mBAAmB,oBAAoB,KAAK,CAAE;AAEpD,MAAK,iBAAiB,WAAW,GAAI;AACpC,WAAO;AAAA,EACR;AAGA,SAAO,CAAC,CAAE,iBAAkB,CAAE,EAAE;AACjC;AAEA,SAAS,sBAAsB;AAC9B,QAAM,iBAAiB;AAEvB,QAAM,WAAW,eAAe,WAAW,WAAW,cAAc,KAAK,CAAE;AAE3E,SAAO,SAAS,IAAK,CAAE,YAAa;AACnC,UAAM,OAAO,QAAQ,MAAM,IAAK,YAAa,KAAK,QAAQ,MAAM,IAAK,QAAS,KAAK;AACnF,UAAM,iBAAiB,eAAe,WAAW,aAAc,IAAK;AAEpE,WAAO;AAAA,MACN;AAAA,MACA,gBAAgB,gBAAgB,mBAAmB;AAAA,IACpD;AAAA,EACD,CAAE;AACH;;;AC3BA,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB,qBAAqB,gBAAgB;AAI1D,IAAM,qBAAqB,MAAM;AACvC,QAAM,EAAE,KAAK,IAAI,gBAAgB;AAEjC,YAAW,MAAM;AAChB,WAAO;AAAA,MACN,kBAAmB,mBAAoB;AAAA,MACvC,MAAM;AACL,YAAK,iBAAiB,GAAI;AACzB,eAAK;AAAA,QACN;AAAA,MACD;AAAA,IACD;AAAA,EACD,GAAG,CAAC,CAAE;AACP;;;AChBO,IAAM,oBAAoB,MAAM;AACtC,qBAAmB;AAEnB,SAAO;AACR;;;AHFA,SAAS,mBAAmB,qBAAqB;AACjD,SAAS,6BAA6B,wBAAwB;AAE/C,SAAR,OAAwB;AAC9B,gBAAe,KAAM;AACrB,eAAa;AAEb,kBAAiB;AAAA,IAChB,IAAI;AAAA,IACJ,WAAW;AAAA,EACZ,CAAE;AACH;AAEA,IAAM,eAAe,MAAM;AAC1B,mBAAkB;AAAA,IACjB,SAAS;AAAA,IACT,WAAW;AAAA,EACZ,CAAE;AACH;;;AIpBA,KAAK;","names":[]}
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/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';\n\nexport const EditingPanel = () => {\n\tconst elements = useSelectedElements();\n\tconst elementType = useElementType( elements[ 0 ]?.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></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 { 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":["useListenTo","commandEndEvent","useListenTo","commandEndEvent"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/editor-editing-panel",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -40,5 +40,5 @@
40
40
  "peerDependencies": {
41
41
  "react": "^18.3.1"
42
42
  },
43
- "gitHead": "33d28e27101a9bf272b11d19d7092830e8cb69d0"
43
+ "gitHead": "1c8d86d0aa369e98aa84631abea0df04c9fd8fc5"
44
44
  }
@@ -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,12 +6,24 @@ 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';
9
11
 
10
12
  export const EditingPanel = () => {
13
+ const elements = useSelectedElements();
14
+ const elementType = useElementType( elements[ 0 ]?.type );
15
+
16
+ if ( elements.length !== 1 || ! elementType ) {
17
+ return null;
18
+ }
19
+
20
+ /* translators: %s: Element type title. */
21
+ const panelTitle = __( 'Edit %s', 'elementor' ).replace( '%s', elementType.title );
22
+
11
23
  return (
12
24
  <Panel>
13
25
  <PanelHeader>
14
- <PanelHeaderTitle>{ __( 'Editing Panel', 'elementor' ) }</PanelHeaderTitle>
26
+ <PanelHeaderTitle>{ panelTitle }</PanelHeaderTitle>
15
27
  </PanelHeader>
16
28
  <PanelBody></PanelBody>
17
29
  </Panel>
@@ -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 '../../types';
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 widget', () => {
42
+ it( 'should return true for v2 element', () => {
39
43
  // Arrange.
40
- getElements.mockReturnValue( [ mockElement( { widgetType: 'v2-heading' } ) ] );
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( [ mockElement( { elType: 'v2-container' } ) ] );
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 widget', () => {
58
+ it( 'should return false for v1 element', () => {
55
59
  // Arrange.
56
- getElements.mockReturnValue( [ mockElement( { widgetType: 'v1-heading' } ) ] );
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 widget', () => {
66
+ it( 'should return false for non-existing element', () => {
63
67
  // Arrange.
64
- getElements.mockReturnValue( [ mockElement( { widgetType: 'non-existing' } ) ] );
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
- mockElement( { widgetType: 'v2-heading' } ),
74
- mockElement( { widgetType: 'v1-heading' } ),
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
- mockElement( { widgetType: 'v2-heading' } ),
85
- mockElement( { widgetType: 'v2-container' } ),
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
+ }
@@ -0,0 +1,7 @@
1
+ import { ExtendedWindow } from './types';
2
+
3
+ export default function getWidgetsCache() {
4
+ const extendedWindow = window as unknown as ExtendedWindow;
5
+
6
+ return extendedWindow?.elementor?.widgetsCache || null;
7
+ }
@@ -1,28 +1,14 @@
1
- import { ExtendedWindow } from '../types';
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 ].atomicControls;
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 ExtendedWindow = Window & {
2
- elementor: {
3
- selection?: {
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 ExtendedElement = {
11
- model: ElementModel<{ widgetType?: string, elType?: string }>
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
  }