@elementor/editor-components 4.0.0-666 → 4.0.0-668

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.
Files changed (72) hide show
  1. package/dist/index.js +191 -3870
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.mjs +184 -3904
  4. package/dist/index.mjs.map +1 -1
  5. package/package.json +23 -23
  6. package/src/init.ts +0 -13
  7. package/src/extended/components/component-introduction.tsx +0 -77
  8. package/src/extended/components/component-panel-header/component-badge.tsx +0 -73
  9. package/src/extended/components/component-panel-header/component-panel-header.tsx +0 -98
  10. package/src/extended/components/component-properties-panel/component-properties-panel-content.tsx +0 -176
  11. package/src/extended/components/component-properties-panel/component-properties-panel.tsx +0 -43
  12. package/src/extended/components/component-properties-panel/properties-empty-state.tsx +0 -51
  13. package/src/extended/components/component-properties-panel/properties-group.tsx +0 -196
  14. package/src/extended/components/component-properties-panel/property-item.tsx +0 -124
  15. package/src/extended/components/component-properties-panel/sortable.tsx +0 -92
  16. package/src/extended/components/component-properties-panel/use-current-editable-item.ts +0 -73
  17. package/src/extended/components/component-properties-panel/utils/generate-unique-label.ts +0 -21
  18. package/src/extended/components/component-properties-panel/utils/validate-group-label.ts +0 -24
  19. package/src/extended/components/components-tab/component-item.tsx +0 -180
  20. package/src/extended/components/components-tab/components.tsx +0 -58
  21. package/src/extended/components/components-tab/delete-confirmation-dialog.tsx +0 -26
  22. package/src/extended/components/create-component-form/create-component-form.tsx +0 -281
  23. package/src/extended/components/create-component-form/hooks/use-form.ts +0 -72
  24. package/src/extended/components/create-component-form/utils/get-component-event-data.ts +0 -54
  25. package/src/extended/components/edit-component/component-modal.tsx +0 -133
  26. package/src/extended/components/edit-component/edit-component.tsx +0 -166
  27. package/src/extended/components/edit-component/use-canvas-document.ts +0 -9
  28. package/src/extended/components/edit-component/use-element-rect.ts +0 -81
  29. package/src/extended/components/instance-editing-panel/instance-editing-panel.tsx +0 -60
  30. package/src/extended/components/overridable-props/indicator.tsx +0 -83
  31. package/src/extended/components/overridable-props/overridable-prop-control.tsx +0 -127
  32. package/src/extended/components/overridable-props/overridable-prop-form.tsx +0 -135
  33. package/src/extended/components/overridable-props/overridable-prop-indicator.tsx +0 -138
  34. package/src/extended/components/overridable-props/utils/validate-prop-label.ts +0 -38
  35. package/src/extended/consts.ts +0 -3
  36. package/src/extended/hooks/use-navigate-back.ts +0 -24
  37. package/src/extended/init.ts +0 -108
  38. package/src/extended/mcp/index.ts +0 -14
  39. package/src/extended/mcp/save-as-component-tool.ts +0 -436
  40. package/src/extended/shortcuts/create-component-shortcut.ts +0 -121
  41. package/src/extended/store/actions/add-overridable-group.ts +0 -53
  42. package/src/extended/store/actions/archive-component.ts +0 -18
  43. package/src/extended/store/actions/create-unpublished-component.ts +0 -99
  44. package/src/extended/store/actions/delete-overridable-group.ts +0 -32
  45. package/src/extended/store/actions/delete-overridable-prop.ts +0 -64
  46. package/src/extended/store/actions/rename-component.ts +0 -48
  47. package/src/extended/store/actions/rename-overridable-group.ts +0 -33
  48. package/src/extended/store/actions/reorder-group-props.ts +0 -37
  49. package/src/extended/store/actions/reorder-overridable-groups.ts +0 -24
  50. package/src/extended/store/actions/reset-sanitized-components.ts +0 -5
  51. package/src/extended/store/actions/set-overridable-prop.ts +0 -109
  52. package/src/extended/store/actions/update-component-sanitized-attribute.ts +0 -7
  53. package/src/extended/store/actions/update-current-component.ts +0 -12
  54. package/src/extended/store/actions/update-overridable-prop-params.ts +0 -52
  55. package/src/extended/store/utils/groups-transformers.ts +0 -187
  56. package/src/extended/sync/before-save.ts +0 -52
  57. package/src/extended/sync/cleanup-overridable-props-on-delete.ts +0 -78
  58. package/src/extended/sync/create-components-before-save.ts +0 -111
  59. package/src/extended/sync/handle-component-edit-mode-container.ts +0 -114
  60. package/src/extended/sync/prevent-non-atomic-nesting.ts +0 -198
  61. package/src/extended/sync/revert-overridables-on-copy-or-duplicate.ts +0 -66
  62. package/src/extended/sync/sanitize-overridable-props.ts +0 -32
  63. package/src/extended/sync/set-component-overridable-props-settings-before-save.ts +0 -22
  64. package/src/extended/sync/update-archived-component-before-save.ts +0 -31
  65. package/src/extended/sync/update-component-title-before-save.ts +0 -18
  66. package/src/extended/utils/component-form-schema.ts +0 -32
  67. package/src/extended/utils/component-name-validation.ts +0 -25
  68. package/src/extended/utils/create-component-model.ts +0 -28
  69. package/src/extended/utils/get-container-for-new-element.ts +0 -49
  70. package/src/extended/utils/is-editing-component.ts +0 -5
  71. package/src/extended/utils/replace-element-with-component.ts +0 -11
  72. package/src/extended/utils/revert-overridable-settings.ts +0 -207
package/dist/index.mjs CHANGED
@@ -1,17 +1,16 @@
1
1
  // src/init.ts
2
- import { injectIntoLogic as injectIntoLogic2 } from "@elementor/editor";
2
+ import { injectIntoLogic } from "@elementor/editor";
3
3
  import {
4
4
  registerElementType,
5
5
  settingsTransformersRegistry as settingsTransformersRegistry2
6
6
  } from "@elementor/editor-canvas";
7
- import { getV1CurrentDocument as getV1CurrentDocument2 } from "@elementor/editor-documents";
8
- import { registerEditingPanelReplacement as registerEditingPanelReplacement2 } from "@elementor/editor-editing-panel";
7
+ import { getV1CurrentDocument } from "@elementor/editor-documents";
8
+ import { registerEditingPanelReplacement } from "@elementor/editor-editing-panel";
9
9
  import { injectTab } from "@elementor/editor-elements-panel";
10
10
  import { stylesRepository } from "@elementor/editor-styles-repository";
11
- import { registerDataHook as registerDataHook6 } from "@elementor/editor-v1-adapters";
11
+ import { registerDataHook as registerDataHook2 } from "@elementor/editor-v1-adapters";
12
12
  import { __registerSlice as registerSlice } from "@elementor/store";
13
- import { isProAtLeast } from "@elementor/utils";
14
- import { __ as __36 } from "@wordpress/i18n";
13
+ import { __ as __12 } from "@wordpress/i18n";
15
14
 
16
15
  // src/component-instance-transformer.ts
17
16
  import { createTransformer } from "@elementor/editor-canvas";
@@ -31,10 +30,10 @@ import { __createAsyncThunk as createAsyncThunk } from "@elementor/store";
31
30
  import { ajax } from "@elementor/editor-v1-adapters";
32
31
  import { httpService } from "@elementor/http-client";
33
32
  var BASE_URL = "elementor/v1/components";
34
- var getParams = (id2) => ({
33
+ var getParams = (id) => ({
35
34
  action: "get_document_config",
36
- unique_id: `document-config-${id2}`,
37
- data: { id: id2 }
35
+ unique_id: `document-config-${id}`,
36
+ data: { id }
38
37
  });
39
38
  var apiClient = {
40
39
  get: () => httpService().get(`${BASE_URL}`).then((res) => res.data.data),
@@ -43,8 +42,8 @@ var apiClient = {
43
42
  ids,
44
43
  status
45
44
  }),
46
- getComponentConfig: (id2) => ajax.load(getParams(id2)),
47
- invalidateComponentConfigCache: (id2) => ajax.invalidateCache(getParams(id2)),
45
+ getComponentConfig: (id) => ajax.load(getParams(id)),
46
+ invalidateComponentConfigCache: (id) => ajax.invalidateCache(getParams(id)),
48
47
  getComponentLockStatus: async (componentId) => await httpService().get(`${BASE_URL}/lock-status`, {
49
48
  params: {
50
49
  componentId
@@ -298,10 +297,10 @@ var useIsSanitizedComponent = (componentId, key) => {
298
297
 
299
298
  // src/utils/component-document-data.ts
300
299
  import { getV1DocumentsManager } from "@elementor/editor-documents";
301
- var getComponentDocumentData = async (id2) => {
300
+ var getComponentDocumentData = async (id) => {
302
301
  const documentManager = getV1DocumentsManager();
303
302
  try {
304
- return await documentManager.request(id2);
303
+ return await documentManager.request(id);
305
304
  } catch {
306
305
  return null;
307
306
  }
@@ -310,11 +309,11 @@ var getComponentDocumentData = async (id2) => {
310
309
  // src/component-instance-transformer.ts
311
310
  var componentInstanceTransformer = createTransformer(
312
311
  async ({
313
- component_id: id2,
312
+ component_id: id,
314
313
  overrides: overridesValue
315
314
  }) => {
316
315
  const unpublishedComponents = selectUnpublishedComponents(getState());
317
- const unpublishedComponent = unpublishedComponents.find(({ uid }) => uid === id2);
316
+ const unpublishedComponent = unpublishedComponents.find(({ uid }) => uid === id);
318
317
  const overrides = overridesValue?.reduce((acc, override) => ({ ...acc, ...override }), {});
319
318
  if (unpublishedComponent) {
320
319
  return {
@@ -322,10 +321,10 @@ var componentInstanceTransformer = createTransformer(
322
321
  overrides
323
322
  };
324
323
  }
325
- if (typeof id2 !== "number") {
326
- throw new Error(`Component ID "${id2}" not valid.`);
324
+ if (typeof id !== "number") {
325
+ throw new Error(`Component ID "${id}" not valid.`);
327
326
  }
328
- const data = await getComponentDocumentData(id2);
327
+ const data = await getComponentDocumentData(id);
329
328
  return {
330
329
  elements: data?.elements ?? [],
331
330
  overrides
@@ -1378,8 +1377,8 @@ var componentsActions = {
1378
1377
  resetUnpublished() {
1379
1378
  dispatch2(slice.actions.resetUnpublished());
1380
1379
  },
1381
- removeStyles(id2) {
1382
- dispatch2(slice.actions.removeStyles({ id: id2 }));
1380
+ removeStyles(id) {
1381
+ dispatch2(slice.actions.removeStyles({ id }));
1383
1382
  },
1384
1383
  addStyles(styles) {
1385
1384
  dispatch2(slice.actions.addStyles(styles));
@@ -1393,8 +1392,8 @@ var componentsActions = {
1393
1392
  archive(componentId) {
1394
1393
  dispatch2(slice.actions.archive(componentId));
1395
1394
  },
1396
- setCurrentComponentId(id2) {
1397
- safeDispatch()?.(slice.actions.setCurrentComponentId(id2));
1395
+ setCurrentComponentId(id) {
1396
+ safeDispatch()?.(slice.actions.setCurrentComponentId(id));
1398
1397
  },
1399
1398
  setPath(path) {
1400
1399
  safeDispatch()?.(slice.actions.setPath(path));
@@ -1863,9 +1862,9 @@ function OverridePropsGroup({ group }) {
1863
1862
  const handleClick = () => {
1864
1863
  setIsOpen(!isOpen);
1865
1864
  };
1866
- const id2 = useId();
1867
- const labelId = `label-${id2}`;
1868
- const contentId = `content-${id2}`;
1865
+ const id = useId();
1866
+ const labelId = `label-${id}`;
1867
+ const contentId = `content-${id}`;
1869
1868
  const title = group.label;
1870
1869
  return /* @__PURE__ */ React17.createElement(Box7, { "aria-label": `${title} section` }, /* @__PURE__ */ React17.createElement(
1871
1870
  ListItemButton3,
@@ -2059,12 +2058,12 @@ async function getComponentIds(elements, cache) {
2059
2058
  }
2060
2059
  async function getDocumentsMap(ids, cache) {
2061
2060
  const documents = await Promise.all(
2062
- ids.map(async (id2) => {
2063
- const document = await cache.get(id2);
2061
+ ids.map(async (id) => {
2062
+ const document = await cache.get(id);
2064
2063
  if (!document) {
2065
2064
  return null;
2066
2065
  }
2067
- return [id2, document];
2066
+ return [id, document];
2068
2067
  })
2069
2068
  );
2070
2069
  return new Map(documents.filter((document) => document !== null));
@@ -2102,7 +2101,7 @@ function loadComponentsStyles(documents) {
2102
2101
  return;
2103
2102
  }
2104
2103
  const knownComponents = selectStyles(getState7());
2105
- const unknownDocuments = new Map([...documents.entries()].filter(([id2]) => !knownComponents[id2]));
2104
+ const unknownDocuments = new Map([...documents.entries()].filter(([id]) => !knownComponents[id]));
2106
2105
  if (!unknownDocuments.size) {
2107
2106
  return;
2108
2107
  }
@@ -2110,7 +2109,7 @@ function loadComponentsStyles(documents) {
2110
2109
  }
2111
2110
  function addStyles(documents) {
2112
2111
  const styles = Object.fromEntries(
2113
- [...documents.entries()].map(([id2, document]) => [id2, extractStylesFromDocument(document)])
2112
+ [...documents.entries()].map(([id, document]) => [id, extractStylesFromDocument(document)])
2114
2113
  );
2115
2114
  dispatch4(slice.actions.addStyles(styles));
2116
2115
  }
@@ -2166,10 +2165,10 @@ var ELEMENT_ID_LENGTH = 7;
2166
2165
  function formatComponentElementsId(elements, path) {
2167
2166
  return elements.map((element) => {
2168
2167
  const nestingPath = [...path, element.id];
2169
- const id2 = hashString(nestingPath.join("_"), ELEMENT_ID_LENGTH);
2168
+ const id = hashString(nestingPath.join("_"), ELEMENT_ID_LENGTH);
2170
2169
  return {
2171
2170
  ...element,
2172
- id: id2,
2171
+ id,
2173
2172
  originId: element.id,
2174
2173
  elements: element.elements ? formatComponentElementsId(element.elements, nestingPath) : void 0
2175
2174
  };
@@ -2529,3912 +2528,200 @@ function createComponentModel() {
2529
2528
  });
2530
2529
  }
2531
2530
 
2532
- // src/extended/init.ts
2533
- import { injectIntoLogic, injectIntoTop } from "@elementor/editor";
2534
- import { registerControlReplacement } from "@elementor/editor-controls";
2535
- import { getV1CurrentDocument } from "@elementor/editor-documents";
2536
- import {
2537
- FIELD_TYPE,
2538
- injectIntoPanelHeaderTop,
2539
- registerEditingPanelReplacement,
2540
- registerFieldIndicator
2541
- } from "@elementor/editor-editing-panel";
2542
- import { registerTab } from "@elementor/editor-elements-panel";
2543
- import { __registerPanel as registerPanel } from "@elementor/editor-panels";
2544
- import { registerDataHook as registerDataHook4 } from "@elementor/editor-v1-adapters";
2545
- import { __ as __34 } from "@wordpress/i18n";
2546
-
2547
- // src/extended/components/component-panel-header/component-panel-header.tsx
2548
- import * as React29 from "react";
2549
- import { useSuppressedMessage } from "@elementor/editor-current-user";
2550
- import { getV1DocumentsManager as getV1DocumentsManager3 } from "@elementor/editor-documents";
2551
- import { PanelHeader as PanelHeader3 } from "@elementor/editor-panels";
2552
- import { EllipsisWithTooltip as EllipsisWithTooltip4 } from "@elementor/editor-ui";
2553
- import { ArrowLeftIcon, ComponentsFilledIcon } from "@elementor/icons";
2554
- import { __getState as getState9 } from "@elementor/store";
2555
- import { Box as Box15, Divider as Divider4, IconButton as IconButton5, Tooltip as Tooltip5, Typography as Typography11 } from "@elementor/ui";
2556
- import { __ as __22 } from "@wordpress/i18n";
2557
-
2558
- // src/extended/hooks/use-navigate-back.ts
2559
- import { useCallback } from "react";
2560
- import { getV1DocumentsManager as getV1DocumentsManager2 } from "@elementor/editor-documents";
2561
- import { __useSelector as useSelector4 } from "@elementor/store";
2562
- function useNavigateBack() {
2563
- const path = useSelector4(selectPath);
2564
- const documentsManager = getV1DocumentsManager2();
2565
- return useCallback(() => {
2566
- const { componentId: prevComponentId, instanceId: prevComponentInstanceId } = path.at(-2) ?? {};
2567
- if (prevComponentId && prevComponentInstanceId) {
2568
- switchToComponent(prevComponentId, prevComponentInstanceId);
2569
- return;
2570
- }
2571
- switchToComponent(documentsManager.getInitialId());
2572
- }, [path, documentsManager]);
2531
+ // src/populate-store.ts
2532
+ import { useEffect as useEffect2 } from "react";
2533
+ import { __dispatch as dispatch5 } from "@elementor/store";
2534
+ function PopulateStore() {
2535
+ useEffect2(() => {
2536
+ dispatch5(loadComponents());
2537
+ }, []);
2538
+ return null;
2573
2539
  }
2574
2540
 
2575
- // src/extended/components/component-introduction.tsx
2576
- import * as React20 from "react";
2577
- import { PopoverContent } from "@elementor/editor-controls";
2578
- import { PopoverHeader } from "@elementor/editor-ui";
2579
- import { Box as Box9, Button as Button3, Image, Link as Link2, Popover, Stack as Stack12, Typography as Typography6 } from "@elementor/ui";
2541
+ // src/prevent-circular-nesting.ts
2542
+ import { getAllDescendants } from "@elementor/editor-elements";
2543
+ import { notify as notify3 } from "@elementor/editor-notifications";
2544
+ import { blockCommand } from "@elementor/editor-v1-adapters";
2545
+ import { __getState as getState9 } from "@elementor/store";
2580
2546
  import { __ as __11 } from "@wordpress/i18n";
2581
- var ComponentIntroduction = ({
2582
- anchorRef,
2583
- shouldShowIntroduction,
2584
- onClose
2585
- }) => {
2586
- if (!anchorRef.current || !shouldShowIntroduction) {
2587
- return null;
2588
- }
2589
- return /* @__PURE__ */ React20.createElement(
2590
- Popover,
2591
- {
2592
- anchorEl: anchorRef.current,
2593
- open: shouldShowIntroduction,
2594
- anchorOrigin: {
2595
- vertical: "top",
2596
- horizontal: "right"
2597
- },
2598
- transformOrigin: {
2599
- vertical: "top",
2600
- horizontal: -30
2601
- },
2602
- onClose
2603
- },
2604
- /* @__PURE__ */ React20.createElement(Box9, { sx: { width: "296px" } }, /* @__PURE__ */ React20.createElement(PopoverHeader, { title: __11("Add your first property", "elementor"), onClose }), /* @__PURE__ */ React20.createElement(
2605
- Image,
2606
- {
2607
- sx: { width: "296px", height: "160px" },
2608
- src: "https://assets.elementor.com/packages/v1/images/components-properties-intro.png",
2609
- alt: ""
2610
- }
2611
- ), /* @__PURE__ */ React20.createElement(PopoverContent, null, /* @__PURE__ */ React20.createElement(Stack12, { sx: { p: 2 } }, /* @__PURE__ */ React20.createElement(Typography6, { variant: "body2" }, __11("Properties make instances flexible.", "elementor")), /* @__PURE__ */ React20.createElement(Typography6, { variant: "body2" }, __11(
2612
- "Select any Element, then in the General tab, click next to any setting you want users to customize - like text, images, or links.",
2613
- "elementor"
2614
- )), /* @__PURE__ */ React20.createElement(Typography6, { variant: "body2", sx: { mt: 2 } }, __11(
2615
- "Your properties will appear in the Properties panel, where you can organize and manage them anytime.",
2616
- "elementor"
2617
- )), /* @__PURE__ */ React20.createElement(
2618
- Link2,
2619
- {
2620
- href: "http://go.elementor.com/components-guide",
2621
- target: "_blank",
2622
- sx: { mt: 2 },
2623
- color: "info.main",
2624
- variant: "body2"
2625
- },
2626
- __11("Learn more", "elementor")
2627
- ), /* @__PURE__ */ React20.createElement(Stack12, { direction: "row", alignItems: "center", justifyContent: "flex-end", sx: { pt: 1 } }, /* @__PURE__ */ React20.createElement(Button3, { size: "medium", variant: "contained", onClick: onClose }, __11("Got it", "elementor"))))))
2628
- );
2547
+ var COMPONENT_TYPE = "e-component";
2548
+ var COMPONENT_CIRCULAR_NESTING_ALERT = {
2549
+ type: "default",
2550
+ message: __11("Can't add this component - components that contain each other can't be nested.", "elementor"),
2551
+ id: "circular-component-nesting-blocked"
2629
2552
  };
2630
-
2631
- // src/extended/components/component-properties-panel/component-properties-panel.tsx
2632
- import * as React27 from "react";
2633
- import { usePanelActions as useEditingPanelActions } from "@elementor/editor-editing-panel";
2634
- import { __createPanel as createPanel, Panel } from "@elementor/editor-panels";
2635
- import { ThemeProvider as ThemeProvider2 } from "@elementor/editor-ui";
2636
- import { Alert, Box as Box13, ErrorBoundary } from "@elementor/ui";
2637
- import { __ as __20 } from "@wordpress/i18n";
2638
-
2639
- // src/extended/components/component-properties-panel/component-properties-panel-content.tsx
2640
- import * as React26 from "react";
2641
- import { useMemo, useRef, useState as useState5 } from "react";
2642
- import { setDocumentModifiedStatus as setDocumentModifiedStatus3 } from "@elementor/editor-documents";
2643
- import { PanelBody as PanelBody2, PanelHeader as PanelHeader2, PanelHeaderTitle as PanelHeaderTitle2 } from "@elementor/editor-panels";
2644
- import { ComponentPropListIcon as ComponentPropListIcon3, FolderPlusIcon, XIcon as XIcon2 } from "@elementor/icons";
2645
- import { Divider as Divider3, IconButton as IconButton4, List as List3, Stack as Stack16, Tooltip as Tooltip3 } from "@elementor/ui";
2646
- import { generateUniqueId as generateUniqueId2 } from "@elementor/utils";
2647
- import { __ as __19 } from "@wordpress/i18n";
2648
-
2649
- // src/extended/store/actions/add-overridable-group.ts
2650
- function addOverridableGroup({
2651
- componentId,
2652
- groupId,
2653
- label,
2654
- source
2655
- }) {
2656
- const currentComponent = componentsSelectors.getCurrentComponent();
2657
- const overridableProps = componentsSelectors.getOverridableProps(componentId);
2658
- if (!overridableProps) {
2659
- return;
2660
- }
2661
- const newGroup = {
2662
- id: groupId,
2663
- label,
2664
- props: []
2665
- };
2666
- componentsActions.setOverridableProps(componentId, {
2667
- ...overridableProps,
2668
- groups: {
2669
- ...overridableProps.groups,
2670
- items: {
2671
- ...overridableProps.groups.items,
2672
- [groupId]: newGroup
2673
- },
2674
- order: [groupId, ...overridableProps.groups.order]
2675
- }
2553
+ function initCircularNestingPrevention() {
2554
+ blockCommand({
2555
+ command: "document/elements/create",
2556
+ condition: blockCircularCreate
2676
2557
  });
2677
- trackComponentEvent({
2678
- action: "propertiesGroupCreated",
2679
- source,
2680
- component_uid: currentComponent?.uid,
2681
- group_name: label
2558
+ blockCommand({
2559
+ command: "document/elements/move",
2560
+ condition: blockCircularMove
2561
+ });
2562
+ blockCommand({
2563
+ command: "document/elements/paste",
2564
+ condition: blockCircularPaste
2682
2565
  });
2683
- return newGroup;
2684
- }
2685
-
2686
- // src/extended/store/utils/groups-transformers.ts
2687
- import { generateUniqueId } from "@elementor/utils";
2688
- import { __ as __12 } from "@wordpress/i18n";
2689
- function removePropFromAllGroups(groups, propKey) {
2690
- const propKeys = Array.isArray(propKey) ? propKey : [propKey];
2691
- return {
2692
- ...groups,
2693
- items: Object.fromEntries(
2694
- Object.entries(groups.items).map(([groupId, group]) => [
2695
- groupId,
2696
- {
2697
- ...group,
2698
- props: group.props.filter((p) => !propKeys.includes(p))
2699
- }
2700
- ])
2701
- )
2702
- };
2703
2566
  }
2704
- function addPropToGroup(groups, groupId, propKey) {
2705
- const group = groups.items[groupId];
2706
- if (!group) {
2707
- return groups;
2708
- }
2709
- if (group.props.includes(propKey)) {
2710
- return groups;
2567
+ function wouldCreateCircularNesting(componentIdToAdd) {
2568
+ if (componentIdToAdd === void 0) {
2569
+ return false;
2711
2570
  }
2712
- return {
2713
- ...groups,
2714
- items: {
2715
- ...groups.items,
2716
- [groupId]: {
2717
- ...group,
2718
- props: [...group.props, propKey]
2719
- }
2720
- }
2721
- };
2722
- }
2723
- function movePropBetweenGroups(groups, propKey, fromGroupId, toGroupId) {
2724
- if (fromGroupId === toGroupId) {
2725
- return groups;
2571
+ const state = getState9();
2572
+ const currentComponentId = selectCurrentComponentId(state);
2573
+ const path = selectPath(state);
2574
+ if (currentComponentId === null) {
2575
+ return false;
2726
2576
  }
2727
- const withoutProp = removePropFromGroup(groups, fromGroupId, propKey);
2728
- return addPropToGroup(withoutProp, toGroupId, propKey);
2729
- }
2730
- function removePropFromGroup(groups, groupId, propKey) {
2731
- const group = groups.items[groupId];
2732
- if (!group) {
2733
- return groups;
2577
+ if (componentIdToAdd === currentComponentId) {
2578
+ return true;
2734
2579
  }
2735
- return {
2736
- ...groups,
2737
- items: {
2738
- ...groups.items,
2739
- [groupId]: {
2740
- ...group,
2741
- props: group.props.filter((p) => p !== propKey)
2742
- }
2743
- }
2744
- };
2580
+ return path.some((item) => item.componentId === componentIdToAdd);
2745
2581
  }
2746
- function resolveOrCreateGroup(groups, requestedGroupId) {
2747
- if (requestedGroupId && groups.items[requestedGroupId]) {
2748
- return { groups, groupId: requestedGroupId };
2582
+ function extractComponentIdFromModel(model) {
2583
+ if (!model) {
2584
+ return null;
2749
2585
  }
2750
- if (!requestedGroupId && groups.order.length > 0) {
2751
- return { groups, groupId: groups.order[0] };
2586
+ const isComponent = model.widgetType === COMPONENT_TYPE;
2587
+ if (!isComponent) {
2588
+ return null;
2752
2589
  }
2753
- return createGroup(groups, requestedGroupId);
2590
+ return model.settings?.component_instance?.value?.component_id?.value ?? null;
2754
2591
  }
2755
- function createGroup(groups, groupId, label) {
2756
- const newGroupId = groupId || generateUniqueId("group");
2757
- const newLabel = label || __12("Default", "elementor");
2758
- return {
2759
- groups: {
2760
- ...groups,
2761
- items: {
2762
- ...groups.items,
2763
- [newGroupId]: {
2764
- id: newGroupId,
2765
- label: newLabel,
2766
- props: []
2767
- }
2768
- },
2769
- order: [...groups.order, newGroupId]
2770
- },
2771
- groupId: newGroupId
2772
- };
2592
+ function extractComponentIdFromElement(element) {
2593
+ if (element.widgetType !== COMPONENT_TYPE) {
2594
+ return null;
2595
+ }
2596
+ return element.settings?.component_instance?.value?.component_id?.value ?? null;
2773
2597
  }
2774
- function removePropsFromState(overridableProps, propsToRemove) {
2775
- const overrideKeysToRemove = propsToRemove.map((prop) => prop.overrideKey);
2776
- const remainingProps = Object.fromEntries(
2777
- Object.entries(overridableProps.props).filter(([, prop]) => !propsToRemove.includes(prop))
2778
- );
2779
- const updatedGroupItems = Object.fromEntries(
2780
- Object.entries(overridableProps.groups.items).map(
2781
- ([groupId, group]) => [
2782
- groupId,
2783
- {
2784
- ...group,
2785
- props: group.props.filter((prop) => !overrideKeysToRemove.includes(prop))
2786
- }
2787
- ]
2788
- )
2789
- );
2790
- return {
2791
- props: remainingProps,
2792
- groups: {
2793
- items: updatedGroupItems,
2794
- order: overridableProps.groups.order.filter((groupId) => !overrideKeysToRemove.includes(groupId))
2598
+ function extractComponentIdsFromElements(elements) {
2599
+ const ids = [];
2600
+ for (const element of elements) {
2601
+ const componentId = extractComponentIdFromElement(element);
2602
+ if (componentId !== null) {
2603
+ ids.push(componentId);
2604
+ }
2605
+ if (element.elements?.length) {
2606
+ ids.push(...extractComponentIdsFromElements(element.elements));
2795
2607
  }
2796
- };
2797
- }
2798
- function ensureGroupInOrder(groups, groupId) {
2799
- if (groups.order.includes(groupId)) {
2800
- return groups;
2801
2608
  }
2802
- return {
2803
- ...groups,
2804
- order: [...groups.order, groupId]
2805
- };
2806
- }
2807
- function deleteGroup(groups, groupId) {
2808
- const { [groupId]: removed, ...remainingItems } = groups.items;
2809
- return {
2810
- items: remainingItems,
2811
- order: groups.order.filter((id2) => id2 !== groupId)
2812
- };
2609
+ return ids;
2813
2610
  }
2814
- function renameGroup(groups, groupId, newLabel) {
2815
- const group = groups.items[groupId];
2816
- if (!group) {
2817
- return groups;
2611
+ function extractComponentIdFromContainer(container) {
2612
+ const widgetType = container.model?.get?.("widgetType");
2613
+ if (widgetType !== COMPONENT_TYPE) {
2614
+ return null;
2818
2615
  }
2819
- return {
2820
- ...groups,
2821
- items: {
2822
- ...groups.items,
2823
- [groupId]: {
2824
- ...group,
2825
- label: newLabel
2826
- }
2827
- }
2828
- };
2616
+ const settings = container.model?.get?.("settings");
2617
+ const componentInstance = settings?.get?.("component_instance");
2618
+ return componentInstance?.value?.component_id?.value ?? null;
2829
2619
  }
2830
-
2831
- // src/extended/store/actions/delete-overridable-group.ts
2832
- function deleteOverridableGroup({ componentId, groupId }) {
2833
- const overridableProps = componentsSelectors.getOverridableProps(componentId);
2834
- if (!overridableProps) {
2620
+ function blockCircularCreate(args) {
2621
+ const componentId = extractComponentIdFromModel(args.model);
2622
+ if (componentId === null) {
2835
2623
  return false;
2836
2624
  }
2837
- const group = overridableProps.groups.items[groupId];
2838
- if (!group || group.props.length > 0) {
2839
- return false;
2625
+ const isBlocked = wouldCreateCircularNesting(componentId);
2626
+ if (isBlocked) {
2627
+ notify3(COMPONENT_CIRCULAR_NESTING_ALERT);
2840
2628
  }
2841
- const updatedGroups = deleteGroup(overridableProps.groups, groupId);
2842
- componentsActions.setOverridableProps(componentId, {
2843
- ...overridableProps,
2844
- groups: updatedGroups
2845
- });
2846
- return true;
2629
+ return isBlocked;
2847
2630
  }
2848
-
2849
- // src/extended/utils/revert-overridable-settings.ts
2850
- import {
2851
- getAllDescendants,
2852
- getContainer as getContainer3,
2853
- getElementSetting,
2854
- updateElementSettings
2855
- } from "@elementor/editor-elements";
2856
- function revertElementOverridableSetting(elementId, settingKey, originValue, overrideKey) {
2857
- const container = getContainer3(elementId);
2858
- if (!container) {
2859
- return;
2860
- }
2861
- if (isComponentInstance(container.model.toJSON())) {
2862
- revertComponentInstanceOverridableSetting(elementId, overrideKey);
2863
- return;
2864
- }
2865
- updateElementSettings({
2866
- id: elementId,
2867
- props: { [settingKey]: originValue ?? null },
2868
- withHistory: false
2631
+ function blockCircularMove(args) {
2632
+ const { containers = [args.container] } = args;
2633
+ const hasCircularComponent = containers.some((container) => {
2634
+ if (!container) {
2635
+ return false;
2636
+ }
2637
+ const allElements = getAllDescendants(container);
2638
+ return allElements.some((element) => {
2639
+ const componentId = extractComponentIdFromContainer(element);
2640
+ if (componentId === null) {
2641
+ return false;
2642
+ }
2643
+ return wouldCreateCircularNesting(componentId);
2644
+ });
2869
2645
  });
2870
- }
2871
- function revertComponentInstanceOverridableSetting(elementId, overrideKey) {
2872
- const setting = getElementSetting(elementId, "component_instance");
2873
- const componentInstance = componentInstancePropTypeUtil.extract(setting);
2874
- const overrides = componentInstanceOverridesPropTypeUtil.extract(componentInstance?.overrides);
2875
- if (!overrides?.length) {
2876
- return;
2646
+ if (hasCircularComponent) {
2647
+ notify3(COMPONENT_CIRCULAR_NESTING_ALERT);
2877
2648
  }
2878
- const revertedOverrides = revertComponentInstanceOverrides(overrides, overrideKey);
2879
- const updatedSetting = componentInstancePropTypeUtil.create({
2880
- ...componentInstance,
2881
- overrides: componentInstanceOverridesPropTypeUtil.create(revertedOverrides)
2882
- });
2883
- updateElementSettings({
2884
- id: elementId,
2885
- props: { component_instance: updatedSetting },
2886
- withHistory: false
2887
- });
2888
- }
2889
- function revertComponentInstanceOverrides(overrides, filterByKey) {
2890
- return overrides.map((item) => {
2891
- if (!componentOverridablePropTypeUtil.isValid(item)) {
2892
- return item;
2893
- }
2894
- if (!componentInstanceOverridePropTypeUtil.isValid(item.value.origin_value)) {
2895
- return null;
2896
- }
2897
- if (filterByKey && item.value.override_key !== filterByKey) {
2898
- return item;
2899
- }
2900
- return item.value.origin_value;
2901
- }).filter((item) => item !== null);
2649
+ return hasCircularComponent;
2902
2650
  }
2903
- function revertOverridablePropsFromSettings(settings) {
2904
- let hasChanges = false;
2905
- const revertedSettings = {};
2906
- for (const [key, value] of Object.entries(settings)) {
2907
- if (componentOverridablePropTypeUtil.isValid(value)) {
2908
- revertedSettings[key] = value.value.origin_value;
2909
- hasChanges = true;
2910
- } else {
2911
- revertedSettings[key] = value;
2912
- }
2651
+ function blockCircularPaste(args) {
2652
+ const { storageType } = args;
2653
+ if (storageType !== "localstorage") {
2654
+ return false;
2913
2655
  }
2914
- return { hasChanges, settings: revertedSettings };
2915
- }
2916
- function revertAllOverridablesInElementData(elementData) {
2917
- const revertedElement = { ...elementData };
2918
- if (isComponentInstance({ widgetType: elementData.widgetType, elType: elementData.elType })) {
2919
- revertedElement.settings = revertComponentInstanceSettings(elementData.settings);
2920
- } else if (revertedElement.settings) {
2921
- const { settings } = revertOverridablePropsFromSettings(revertedElement.settings);
2922
- revertedElement.settings = settings;
2656
+ const data = window?.elementorCommon?.storage?.get();
2657
+ if (!data?.clipboard?.elements) {
2658
+ return false;
2923
2659
  }
2924
- if (revertedElement.elements) {
2925
- revertedElement.elements = revertedElement.elements.map(revertAllOverridablesInElementData);
2660
+ const allComponentIds = extractComponentIdsFromElements(data.clipboard.elements);
2661
+ const hasCircularComponent = allComponentIds.some(wouldCreateCircularNesting);
2662
+ if (hasCircularComponent) {
2663
+ notify3(COMPONENT_CIRCULAR_NESTING_ALERT);
2926
2664
  }
2927
- return revertedElement;
2665
+ return hasCircularComponent;
2928
2666
  }
2929
- function revertComponentInstanceSettings(settings) {
2930
- if (!settings?.component_instance) {
2931
- return settings;
2932
- }
2933
- const componentInstance = componentInstancePropTypeUtil.extract(settings.component_instance);
2934
- const overrides = componentInstanceOverridesPropTypeUtil.extract(componentInstance?.overrides);
2935
- if (!overrides?.length) {
2936
- return settings;
2937
- }
2938
- const revertedOverrides = revertComponentInstanceOverrides(overrides);
2939
- return {
2940
- ...settings,
2941
- component_instance: componentInstancePropTypeUtil.create({
2942
- ...componentInstance,
2943
- overrides: componentInstanceOverridesPropTypeUtil.create(revertedOverrides)
2944
- })
2945
- };
2667
+
2668
+ // src/store/actions/remove-component-styles.ts
2669
+ import { __dispatch as dispatch6 } from "@elementor/store";
2670
+ function removeComponentStyles(id) {
2671
+ apiClient.invalidateComponentConfigCache(id);
2672
+ dispatch6(slice.actions.removeStyles({ id }));
2946
2673
  }
2947
- function revertAllOverridablesInContainer(container) {
2948
- getAllDescendants(container).forEach((element) => {
2949
- if (element.model.get("widgetType") === COMPONENT_WIDGET_TYPE2) {
2950
- revertComponentInstanceOverridesInElement(element);
2951
- } else {
2952
- revertElementSettings(element);
2674
+
2675
+ // src/store/components-styles-provider.ts
2676
+ import { createStylesProvider } from "@elementor/editor-styles-repository";
2677
+ import { __getState as getState10, __subscribeWithSelector as subscribeWithSelector } from "@elementor/store";
2678
+ var componentsStylesProvider = createStylesProvider({
2679
+ key: "components-styles",
2680
+ priority: 100,
2681
+ subscribe: (cb) => subscribeWithSelector(
2682
+ (state) => state[SLICE_NAME],
2683
+ () => {
2684
+ cb();
2685
+ }
2686
+ ),
2687
+ actions: {
2688
+ all: () => {
2689
+ return selectFlatStyles(getState10());
2690
+ },
2691
+ get: (id) => {
2692
+ return selectFlatStyles(getState10()).find((style) => style.id === id) ?? null;
2953
2693
  }
2954
- });
2955
- }
2956
- function revertComponentInstanceOverridesInElement(element) {
2957
- const settings = element.settings?.toJSON() ?? {};
2958
- const componentInstance = componentInstancePropTypeUtil.extract(settings.component_instance);
2959
- const overrides = componentInstanceOverridesPropTypeUtil.extract(componentInstance?.overrides);
2960
- if (!overrides?.length) {
2961
- return;
2962
- }
2963
- const revertedOverrides = revertComponentInstanceOverrides(overrides);
2964
- const updatedSetting = componentInstancePropTypeUtil.create({
2965
- ...componentInstance,
2966
- overrides: componentInstanceOverridesPropTypeUtil.create(revertedOverrides)
2967
- });
2968
- updateElementSettings({
2969
- id: element.id,
2970
- props: { component_instance: updatedSetting },
2971
- withHistory: false
2972
- });
2973
- }
2974
- function revertElementSettings(element) {
2975
- const settings = element.settings?.toJSON() ?? {};
2976
- const { hasChanges, settings: revertedSettings } = revertOverridablePropsFromSettings(settings);
2977
- if (!hasChanges) {
2978
- return;
2979
2694
  }
2980
- updateElementSettings({
2981
- id: element.id,
2982
- props: revertedSettings,
2983
- withHistory: false
2984
- });
2985
- }
2695
+ });
2986
2696
 
2987
- // src/extended/store/actions/delete-overridable-prop.ts
2988
- function deleteOverridableProp({ componentId, propKey, source }) {
2989
- const overridableProps = componentsSelectors.getOverridableProps(componentId);
2990
- if (!overridableProps || Object.keys(overridableProps.props).length === 0) {
2697
+ // src/sync/publish-draft-components-in-page-before-save.ts
2698
+ import { invalidateDocumentData as invalidateDocumentData2, isDocumentDirty as isDocumentDirty2 } from "@elementor/editor-documents";
2699
+ async function publishDraftComponentsInPageBeforeSave({ status, elements }) {
2700
+ if (status !== "publish") {
2991
2701
  return;
2992
2702
  }
2993
- const propKeysToDelete = Array.isArray(propKey) ? propKey : [propKey];
2994
- const deletedProps = [];
2995
- for (const key of propKeysToDelete) {
2996
- const prop = overridableProps.props[key];
2997
- if (!prop) {
2998
- continue;
2999
- }
3000
- deletedProps.push(prop);
3001
- revertElementOverridableSetting(prop.elementId, prop.propKey, prop.originValue, key);
3002
- }
3003
- if (deletedProps.length === 0) {
2703
+ const documents = await getComponentDocuments(elements);
2704
+ const draftIds = [...documents.values()].filter(isDocumentDirty2).map((document) => document.id);
2705
+ if (draftIds.length === 0) {
3004
2706
  return;
3005
2707
  }
3006
- const remainingProps = Object.fromEntries(
3007
- Object.entries(overridableProps.props).filter(([key]) => !propKeysToDelete.includes(key))
3008
- );
3009
- const updatedGroups = removePropFromAllGroups(overridableProps.groups, propKey);
3010
- componentsActions.setOverridableProps(componentId, {
3011
- ...overridableProps,
3012
- props: remainingProps,
3013
- groups: updatedGroups
3014
- });
3015
- const currentComponent = componentsSelectors.getCurrentComponent();
3016
- for (const prop of deletedProps) {
3017
- trackComponentEvent({
3018
- action: "propertyRemoved",
3019
- source,
3020
- component_uid: currentComponent?.uid,
3021
- property_id: prop.overrideKey,
3022
- property_path: prop.propKey,
3023
- property_name: prop.label,
3024
- element_type: prop.widgetType ?? prop.elType
3025
- });
3026
- }
3027
- }
3028
-
3029
- // src/extended/store/actions/reorder-group-props.ts
3030
- function reorderGroupProps({ componentId, groupId, newPropsOrder }) {
3031
- const overridableProps = componentsSelectors.getOverridableProps(componentId);
3032
- if (!overridableProps) {
3033
- return;
3034
- }
3035
- const group = overridableProps.groups.items[groupId];
3036
- if (!group) {
3037
- return;
3038
- }
3039
- componentsActions.setOverridableProps(componentId, {
3040
- ...overridableProps,
3041
- groups: {
3042
- ...overridableProps.groups,
3043
- items: {
3044
- ...overridableProps.groups.items,
3045
- [groupId]: {
3046
- ...group,
3047
- props: newPropsOrder
3048
- }
3049
- }
3050
- }
3051
- });
3052
- }
3053
-
3054
- // src/extended/store/actions/reorder-overridable-groups.ts
3055
- function reorderOverridableGroups({ componentId, newOrder }) {
3056
- const overridableProps = componentsSelectors.getOverridableProps(componentId);
3057
- if (!overridableProps) {
3058
- return;
3059
- }
3060
- componentsActions.setOverridableProps(componentId, {
3061
- ...overridableProps,
3062
- groups: {
3063
- ...overridableProps.groups,
3064
- order: newOrder
3065
- }
3066
- });
3067
- }
3068
-
3069
- // src/extended/store/actions/update-overridable-prop-params.ts
3070
- function updateOverridablePropParams({
3071
- componentId,
3072
- overrideKey,
3073
- label,
3074
- groupId
3075
- }) {
3076
- const overridableProps = componentsSelectors.getOverridableProps(componentId);
3077
- if (!overridableProps) {
3078
- return;
3079
- }
3080
- const prop = overridableProps.props[overrideKey];
3081
- if (!prop) {
3082
- return;
3083
- }
3084
- const oldGroupId = prop.groupId;
3085
- const newGroupId = groupId ?? oldGroupId;
3086
- const updatedProp = {
3087
- ...prop,
3088
- label,
3089
- groupId: newGroupId
3090
- };
3091
- const updatedGroups = movePropBetweenGroups(overridableProps.groups, overrideKey, oldGroupId, newGroupId);
3092
- componentsActions.setOverridableProps(componentId, {
3093
- ...overridableProps,
3094
- props: {
3095
- ...overridableProps.props,
3096
- [overrideKey]: updatedProp
3097
- },
3098
- groups: updatedGroups
3099
- });
3100
- return updatedProp;
3101
- }
3102
-
3103
- // src/extended/components/component-properties-panel/properties-empty-state.tsx
3104
- import * as React21 from "react";
3105
- import { useState as useState2 } from "react";
3106
- import { ComponentPropListIcon as ComponentPropListIcon2 } from "@elementor/icons";
3107
- import { Link as Link3, Stack as Stack13, Typography as Typography7 } from "@elementor/ui";
3108
- import { __ as __13 } from "@wordpress/i18n";
3109
- function PropertiesEmptyState({ introductionRef }) {
3110
- const [isOpen, setIsOpen] = useState2(false);
3111
- return /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement(
3112
- Stack13,
3113
- {
3114
- alignItems: "center",
3115
- justifyContent: "flex-start",
3116
- height: "100%",
3117
- color: "text.secondary",
3118
- sx: { px: 2.5, pt: 10, pb: 5.5 },
3119
- gap: 1
3120
- },
3121
- /* @__PURE__ */ React21.createElement(ComponentPropListIcon2, { fontSize: "large" }),
3122
- /* @__PURE__ */ React21.createElement(Typography7, { align: "center", variant: "subtitle2" }, __13("Add your first property", "elementor")),
3123
- /* @__PURE__ */ React21.createElement(Typography7, { align: "center", variant: "caption" }, __13("Make instances flexible while keeping design synced.", "elementor")),
3124
- /* @__PURE__ */ React21.createElement(Typography7, { align: "center", variant: "caption" }, __13("Select any element, then click + next to a setting to expose it.", "elementor")),
3125
- /* @__PURE__ */ React21.createElement(
3126
- Link3,
3127
- {
3128
- variant: "caption",
3129
- color: "secondary",
3130
- sx: { textDecorationLine: "underline" },
3131
- onClick: () => setIsOpen(true)
3132
- },
3133
- __13("Learn more", "elementor")
3134
- )
3135
- ), /* @__PURE__ */ React21.createElement(
3136
- ComponentIntroduction,
3137
- {
3138
- anchorRef: introductionRef,
3139
- shouldShowIntroduction: isOpen,
3140
- onClose: () => setIsOpen(false)
3141
- }
3142
- ));
3143
- }
3144
-
3145
- // src/extended/components/component-properties-panel/properties-group.tsx
3146
- import * as React25 from "react";
3147
- import { EditableField as EditableField2, EllipsisWithTooltip as EllipsisWithTooltip3, MenuListItem as MenuListItem2 } from "@elementor/editor-ui";
3148
- import { DotsVerticalIcon } from "@elementor/icons";
3149
- import {
3150
- bindMenu,
3151
- bindTrigger as bindTrigger2,
3152
- Box as Box12,
3153
- IconButton as IconButton3,
3154
- List as List2,
3155
- Menu,
3156
- Stack as Stack15,
3157
- Tooltip as Tooltip2,
3158
- Typography as Typography10,
3159
- usePopupState as usePopupState2
3160
- } from "@elementor/ui";
3161
- import { __ as __16 } from "@wordpress/i18n";
3162
-
3163
- // src/extended/components/component-properties-panel/property-item.tsx
3164
- import * as React24 from "react";
3165
- import { getWidgetsCache as getWidgetsCache2 } from "@elementor/editor-elements";
3166
- import { XIcon } from "@elementor/icons";
3167
- import { bindPopover, bindTrigger, Box as Box11, IconButton as IconButton2, Popover as Popover2, Typography as Typography9, usePopupState } from "@elementor/ui";
3168
-
3169
- // src/extended/components/overridable-props/overridable-prop-form.tsx
3170
- import * as React22 from "react";
3171
- import { useState as useState3 } from "react";
3172
- import { Form, MenuListItem } from "@elementor/editor-ui";
3173
- import { Button as Button4, FormLabel, Grid, Select, Stack as Stack14, TextField as TextField2, Typography as Typography8 } from "@elementor/ui";
3174
- import { __ as __15 } from "@wordpress/i18n";
3175
-
3176
- // src/extended/components/overridable-props/utils/validate-prop-label.ts
3177
- import { __ as __14 } from "@wordpress/i18n";
3178
- var ERROR_MESSAGES = {
3179
- EMPTY_NAME: __14("Property name is required", "elementor"),
3180
- DUPLICATE_NAME: __14("Property name already exists", "elementor")
3181
- };
3182
- function validatePropLabel(label, existingLabels, currentLabel) {
3183
- const trimmedLabel = label.trim();
3184
- if (!trimmedLabel) {
3185
- return { isValid: false, errorMessage: ERROR_MESSAGES.EMPTY_NAME };
3186
- }
3187
- const normalizedLabel = trimmedLabel.toLowerCase();
3188
- const normalizedCurrentLabel = currentLabel?.trim().toLowerCase();
3189
- const isDuplicate = existingLabels.some((existingLabel) => {
3190
- const normalizedExisting = existingLabel.trim().toLowerCase();
3191
- if (normalizedCurrentLabel && normalizedExisting === normalizedCurrentLabel) {
3192
- return false;
3193
- }
3194
- return normalizedExisting === normalizedLabel;
3195
- });
3196
- if (isDuplicate) {
3197
- return { isValid: false, errorMessage: ERROR_MESSAGES.DUPLICATE_NAME };
3198
- }
3199
- return { isValid: true, errorMessage: null };
3200
- }
3201
-
3202
- // src/extended/components/overridable-props/overridable-prop-form.tsx
3203
- var SIZE = "tiny";
3204
- var DEFAULT_GROUP = { value: null, label: __15("Default", "elementor") };
3205
- function OverridablePropForm({ onSubmit, groups, currentValue, existingLabels = [], sx }) {
3206
- const selectGroups = groups?.length ? groups : [DEFAULT_GROUP];
3207
- const [propLabel, setPropLabel] = useState3(currentValue?.label ?? null);
3208
- const [group, setGroup] = useState3(currentValue?.groupId ?? selectGroups[0]?.value ?? null);
3209
- const [error, setError] = useState3(null);
3210
- const name = __15("Name", "elementor");
3211
- const groupName = __15("Group Name", "elementor");
3212
- const isCreate = currentValue === void 0;
3213
- const title = isCreate ? __15("Create new property", "elementor") : __15("Update property", "elementor");
3214
- const ctaLabel = isCreate ? __15("Create", "elementor") : __15("Update", "elementor");
3215
- const handleSubmit = () => {
3216
- const validationResult = validatePropLabel(propLabel ?? "", existingLabels, currentValue?.label);
3217
- if (!validationResult.isValid) {
3218
- setError(validationResult.errorMessage);
3219
- return;
3220
- }
3221
- onSubmit({ label: propLabel ?? "", group });
3222
- };
3223
- return /* @__PURE__ */ React22.createElement(Form, { onSubmit: handleSubmit, "data-testid": "overridable-prop-form" }, /* @__PURE__ */ React22.createElement(Stack14, { alignItems: "start", sx: { width: "268px", ...sx } }, /* @__PURE__ */ React22.createElement(
3224
- Stack14,
3225
- {
3226
- direction: "row",
3227
- alignItems: "center",
3228
- py: 1,
3229
- px: 1.5,
3230
- sx: { columnGap: 0.5, borderBottom: "1px solid", borderColor: "divider", width: "100%", mb: 1.5 }
3231
- },
3232
- /* @__PURE__ */ React22.createElement(Typography8, { variant: "caption", sx: { color: "text.primary", fontWeight: "500", lineHeight: 1 } }, title)
3233
- ), /* @__PURE__ */ React22.createElement(Grid, { container: true, gap: 0.75, alignItems: "start", px: 1.5, mb: 1.5 }, /* @__PURE__ */ React22.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React22.createElement(FormLabel, { size: "tiny" }, name)), /* @__PURE__ */ React22.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React22.createElement(
3234
- TextField2,
3235
- {
3236
- name,
3237
- size: SIZE,
3238
- fullWidth: true,
3239
- placeholder: __15("Enter value", "elementor"),
3240
- value: propLabel ?? "",
3241
- onChange: (e) => {
3242
- const newValue = e.target.value;
3243
- setPropLabel(newValue);
3244
- const validationResult = validatePropLabel(
3245
- newValue,
3246
- existingLabels,
3247
- currentValue?.label
3248
- );
3249
- setError(validationResult.errorMessage);
3250
- },
3251
- error: Boolean(error),
3252
- helperText: error
3253
- }
3254
- ))), /* @__PURE__ */ React22.createElement(Grid, { container: true, gap: 0.75, alignItems: "start", px: 1.5, mb: 1.5 }, /* @__PURE__ */ React22.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React22.createElement(FormLabel, { size: "tiny" }, groupName)), /* @__PURE__ */ React22.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React22.createElement(
3255
- Select,
3256
- {
3257
- name: groupName,
3258
- size: SIZE,
3259
- fullWidth: true,
3260
- value: group ?? null,
3261
- onChange: (e) => setGroup(e.target.value),
3262
- displayEmpty: true,
3263
- renderValue: (selectedValue) => {
3264
- if (!selectedValue) {
3265
- return selectGroups[0].label;
3266
- }
3267
- return selectGroups.find(({ value }) => value === selectedValue)?.label ?? selectedValue;
3268
- }
3269
- },
3270
- selectGroups.map(({ label: groupLabel, ...props }) => /* @__PURE__ */ React22.createElement(MenuListItem, { key: props.value, ...props, value: props.value ?? "" }, groupLabel))
3271
- ))), /* @__PURE__ */ React22.createElement(Stack14, { direction: "row", justifyContent: "flex-end", alignSelf: "end", mt: 1.5, py: 1, px: 1.5 }, /* @__PURE__ */ React22.createElement(
3272
- Button4,
3273
- {
3274
- type: "submit",
3275
- disabled: !propLabel || Boolean(error),
3276
- variant: "contained",
3277
- color: "primary",
3278
- size: "small"
3279
- },
3280
- ctaLabel
3281
- ))));
3282
- }
3283
-
3284
- // src/extended/components/component-properties-panel/sortable.tsx
3285
- import * as React23 from "react";
3286
- import { GripVerticalIcon } from "@elementor/icons";
3287
- import {
3288
- Box as Box10,
3289
- styled as styled2,
3290
- UnstableSortableItem,
3291
- UnstableSortableProvider
3292
- } from "@elementor/ui";
3293
- var SortableProvider = (props) => /* @__PURE__ */ React23.createElement(UnstableSortableProvider, { restrictAxis: true, variant: "static", dragPlaceholderStyle: { opacity: "1" }, ...props });
3294
- var SortableTrigger = ({ triggerClassName, ...props }) => /* @__PURE__ */ React23.createElement(
3295
- StyledSortableTrigger,
3296
- {
3297
- ...props,
3298
- role: "button",
3299
- className: `sortable-trigger ${triggerClassName ?? ""}`.trim(),
3300
- "aria-label": "sort"
3301
- },
3302
- /* @__PURE__ */ React23.createElement(GripVerticalIcon, { fontSize: "tiny" })
3303
- );
3304
- var SortableItem = ({ children, id: id2 }) => /* @__PURE__ */ React23.createElement(
3305
- UnstableSortableItem,
3306
- {
3307
- id: id2,
3308
- render: ({
3309
- itemProps,
3310
- isDragged,
3311
- triggerProps,
3312
- itemStyle,
3313
- triggerStyle,
3314
- dropIndicationStyle,
3315
- showDropIndication,
3316
- isDragOverlay,
3317
- isDragPlaceholder
3318
- }) => /* @__PURE__ */ React23.createElement(
3319
- Box10,
3320
- {
3321
- ...itemProps,
3322
- style: itemStyle,
3323
- component: "div",
3324
- role: "listitem",
3325
- sx: {
3326
- backgroundColor: isDragOverlay ? "background.paper" : void 0
3327
- }
3328
- },
3329
- children({
3330
- isDragged,
3331
- isDragPlaceholder,
3332
- triggerProps,
3333
- triggerStyle
3334
- }),
3335
- showDropIndication && /* @__PURE__ */ React23.createElement(SortableItemIndicator, { style: dropIndicationStyle })
3336
- )
3337
- }
3338
- );
3339
- var StyledSortableTrigger = styled2("div")(({ theme }) => ({
3340
- position: "absolute",
3341
- left: "-2px",
3342
- top: "50%",
3343
- transform: `translate( -${theme.spacing(1.5)}, -50% )`,
3344
- color: theme.palette.action.active,
3345
- cursor: "grab"
3346
- }));
3347
- var SortableItemIndicator = styled2(Box10)`
3348
- width: 100%;
3349
- height: 1px;
3350
- background-color: ${({ theme }) => theme.palette.text.primary};
3351
- `;
3352
-
3353
- // src/extended/components/component-properties-panel/property-item.tsx
3354
- function PropertyItem({
3355
- prop,
3356
- sortableTriggerProps,
3357
- isDragPlaceholder,
3358
- groups,
3359
- existingLabels,
3360
- onDelete,
3361
- onUpdate
3362
- }) {
3363
- const popoverState = usePopupState({
3364
- variant: "popover"
3365
- });
3366
- const icon = getElementIcon(prop);
3367
- const popoverProps = bindPopover(popoverState);
3368
- const handleSubmit = (data) => {
3369
- onUpdate(data);
3370
- popoverState.close();
3371
- };
3372
- const handleDelete = (event) => {
3373
- event.stopPropagation();
3374
- onDelete(prop.overrideKey);
3375
- };
3376
- return /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(
3377
- Box11,
3378
- {
3379
- ...bindTrigger(popoverState),
3380
- sx: {
3381
- position: "relative",
3382
- pl: 0.5,
3383
- pr: 1,
3384
- py: 0.25,
3385
- minHeight: 28,
3386
- borderRadius: 1,
3387
- border: "1px solid",
3388
- borderColor: "divider",
3389
- display: "flex",
3390
- alignItems: "center",
3391
- gap: 0.5,
3392
- opacity: isDragPlaceholder ? 0.5 : 1,
3393
- cursor: "pointer",
3394
- "&:hover": {
3395
- backgroundColor: "action.hover"
3396
- },
3397
- "&:hover .sortable-trigger": {
3398
- visibility: "visible"
3399
- },
3400
- "& .sortable-trigger": {
3401
- visibility: "hidden"
3402
- },
3403
- "&:hover .delete-button": {
3404
- visibility: "visible"
3405
- },
3406
- "& .delete-button": {
3407
- visibility: "hidden"
3408
- }
3409
- }
3410
- },
3411
- /* @__PURE__ */ React24.createElement(SortableTrigger, { ...sortableTriggerProps }),
3412
- /* @__PURE__ */ React24.createElement(
3413
- Box11,
3414
- {
3415
- sx: { display: "flex", alignItems: "center", color: "text.primary", fontSize: 12, padding: 0.25 }
3416
- },
3417
- /* @__PURE__ */ React24.createElement("i", { className: icon })
3418
- ),
3419
- /* @__PURE__ */ React24.createElement(Typography9, { variant: "caption", sx: { color: "text.primary", flexGrow: 1, fontSize: 10 } }, prop.label),
3420
- /* @__PURE__ */ React24.createElement(IconButton2, { size: "tiny", onClick: handleDelete, "aria-label": "Delete property", sx: { p: 0.25 } }, /* @__PURE__ */ React24.createElement(XIcon, { fontSize: "tiny" }))
3421
- ), /* @__PURE__ */ React24.createElement(
3422
- Popover2,
3423
- {
3424
- ...popoverProps,
3425
- anchorOrigin: { vertical: "bottom", horizontal: "left" },
3426
- transformOrigin: { vertical: "top", horizontal: "left" },
3427
- PaperProps: { sx: { width: popoverState.anchorEl?.getBoundingClientRect().width } }
3428
- },
3429
- /* @__PURE__ */ React24.createElement(
3430
- OverridablePropForm,
3431
- {
3432
- onSubmit: handleSubmit,
3433
- currentValue: prop,
3434
- groups,
3435
- existingLabels,
3436
- sx: { width: "100%" }
3437
- }
3438
- )
3439
- ));
3440
- }
3441
- function getElementIcon(prop) {
3442
- const elType = prop.elType === "widget" ? prop.widgetType : prop.elType;
3443
- const widgetsCache = getWidgetsCache2();
3444
- if (!widgetsCache) {
3445
- return "eicon-apps";
3446
- }
3447
- const widgetConfig = widgetsCache[elType];
3448
- return widgetConfig?.icon || "eicon-apps";
3449
- }
3450
-
3451
- // src/extended/components/component-properties-panel/properties-group.tsx
3452
- function PropertiesGroup({
3453
- group,
3454
- props,
3455
- allGroups,
3456
- sortableTriggerProps,
3457
- isDragPlaceholder,
3458
- onPropsReorder,
3459
- onPropertyDelete,
3460
- onPropertyUpdate,
3461
- onGroupDelete,
3462
- editableLabelProps
3463
- }) {
3464
- const groupProps = group.props.map((propId) => props[propId]).filter((prop) => Boolean(prop));
3465
- const popupState = usePopupState2({
3466
- variant: "popover",
3467
- disableAutoFocus: true
3468
- });
3469
- const { editableRef, isEditing, error, getEditableProps, setEditingGroupId, editingGroupId } = editableLabelProps;
3470
- const hasProperties = group.props.length > 0;
3471
- const isThisGroupEditing = isEditing && editingGroupId === group.id;
3472
- const handleRenameClick = () => {
3473
- popupState.close();
3474
- setEditingGroupId(group.id);
3475
- };
3476
- const handleDeleteClick = () => {
3477
- popupState.close();
3478
- onGroupDelete(group.id);
3479
- };
3480
- return /* @__PURE__ */ React25.createElement(
3481
- Box12,
3482
- {
3483
- sx: {
3484
- opacity: isDragPlaceholder ? 0.5 : 1
3485
- }
3486
- },
3487
- /* @__PURE__ */ React25.createElement(Stack15, { gap: 1 }, /* @__PURE__ */ React25.createElement(
3488
- Box12,
3489
- {
3490
- className: "group-header",
3491
- sx: {
3492
- position: "relative",
3493
- "&:hover .group-sortable-trigger": {
3494
- visibility: "visible"
3495
- },
3496
- "& .group-sortable-trigger": {
3497
- visibility: "hidden"
3498
- },
3499
- "&:hover .group-menu": {
3500
- visibility: "visible"
3501
- },
3502
- "& .group-menu": {
3503
- visibility: "hidden"
3504
- }
3505
- }
3506
- },
3507
- /* @__PURE__ */ React25.createElement(SortableTrigger, { triggerClassName: "group-sortable-trigger", ...sortableTriggerProps }),
3508
- /* @__PURE__ */ React25.createElement(Stack15, { direction: "row", alignItems: "center", justifyContent: "space-between", gap: 2 }, isThisGroupEditing ? /* @__PURE__ */ React25.createElement(
3509
- Box12,
3510
- {
3511
- sx: {
3512
- height: 28,
3513
- display: "flex",
3514
- alignItems: "center",
3515
- border: 2,
3516
- borderColor: "text.secondary",
3517
- borderRadius: 1,
3518
- pl: 0.5,
3519
- flexGrow: 1,
3520
- overflow: "hidden",
3521
- textOverflow: "ellipsis",
3522
- whiteSpace: "nowrap",
3523
- width: "100%"
3524
- }
3525
- },
3526
- /* @__PURE__ */ React25.createElement(
3527
- EditableField2,
3528
- {
3529
- ref: editableRef,
3530
- as: Typography10,
3531
- variant: "caption",
3532
- error: error ?? void 0,
3533
- sx: { color: "text.primary", fontWeight: 400, lineHeight: 1.66 },
3534
- ...getEditableProps()
3535
- }
3536
- )
3537
- ) : /* @__PURE__ */ React25.createElement(
3538
- EllipsisWithTooltip3,
3539
- {
3540
- title: group.label,
3541
- as: Typography10,
3542
- variant: "caption",
3543
- sx: { color: "text.primary", fontWeight: 400, lineHeight: 1.66 }
3544
- }
3545
- ), /* @__PURE__ */ React25.createElement(
3546
- IconButton3,
3547
- {
3548
- className: "group-menu",
3549
- size: "tiny",
3550
- sx: { p: 0.25, visibility: isThisGroupEditing ? "visible" : void 0 },
3551
- "aria-label": __16("Group actions", "elementor"),
3552
- ...bindTrigger2(popupState)
3553
- },
3554
- /* @__PURE__ */ React25.createElement(DotsVerticalIcon, { fontSize: "tiny" })
3555
- ))
3556
- ), /* @__PURE__ */ React25.createElement(List2, { sx: { p: 0, display: "flex", flexDirection: "column", gap: 1 } }, /* @__PURE__ */ React25.createElement(SortableProvider, { value: group.props, onChange: onPropsReorder }, groupProps.map((prop) => /* @__PURE__ */ React25.createElement(SortableItem, { key: prop.overrideKey, id: prop.overrideKey }, ({ triggerProps, triggerStyle, isDragPlaceholder: isItemDragPlaceholder }) => /* @__PURE__ */ React25.createElement(
3557
- PropertyItem,
3558
- {
3559
- prop,
3560
- sortableTriggerProps: { ...triggerProps, style: triggerStyle },
3561
- isDragPlaceholder: isItemDragPlaceholder,
3562
- groups: allGroups,
3563
- existingLabels: Object.values(props).map((p) => p.label),
3564
- onDelete: onPropertyDelete,
3565
- onUpdate: (data) => onPropertyUpdate(prop.overrideKey, data)
3566
- }
3567
- )))))),
3568
- /* @__PURE__ */ React25.createElement(
3569
- Menu,
3570
- {
3571
- ...bindMenu(popupState),
3572
- anchorOrigin: { vertical: "bottom", horizontal: "right" },
3573
- transformOrigin: { vertical: "top", horizontal: "right" }
3574
- },
3575
- /* @__PURE__ */ React25.createElement(MenuListItem2, { sx: { minWidth: "160px" }, onClick: handleRenameClick }, /* @__PURE__ */ React25.createElement(Typography10, { variant: "caption", sx: { color: "text.primary" } }, __16("Rename", "elementor"))),
3576
- /* @__PURE__ */ React25.createElement(
3577
- Tooltip2,
3578
- {
3579
- title: hasProperties ? __16("To delete the group, first remove all the properties", "elementor") : "",
3580
- placement: "right"
3581
- },
3582
- /* @__PURE__ */ React25.createElement("span", null, /* @__PURE__ */ React25.createElement(MenuListItem2, { onClick: handleDeleteClick, disabled: hasProperties }, /* @__PURE__ */ React25.createElement(
3583
- Typography10,
3584
- {
3585
- variant: "caption",
3586
- sx: { color: hasProperties ? "text.disabled" : "error.light" }
3587
- },
3588
- __16("Delete", "elementor")
3589
- )))
3590
- )
3591
- )
3592
- );
3593
- }
3594
-
3595
- // src/extended/components/component-properties-panel/use-current-editable-item.ts
3596
- import { useState as useState4 } from "react";
3597
- import { setDocumentModifiedStatus as setDocumentModifiedStatus2 } from "@elementor/editor-documents";
3598
- import { useEditable } from "@elementor/editor-ui";
3599
- import { __ as __18 } from "@wordpress/i18n";
3600
-
3601
- // src/extended/store/actions/rename-overridable-group.ts
3602
- function renameOverridableGroup({ componentId, groupId, label }) {
3603
- const overridableProps = componentsSelectors.getOverridableProps(componentId);
3604
- if (!overridableProps) {
3605
- return false;
3606
- }
3607
- const group = overridableProps.groups.items[groupId];
3608
- if (!group) {
3609
- return false;
3610
- }
3611
- const updatedGroups = renameGroup(overridableProps.groups, groupId, label);
3612
- componentsActions.setOverridableProps(componentId, {
3613
- ...overridableProps,
3614
- groups: updatedGroups
3615
- });
3616
- return true;
3617
- }
3618
-
3619
- // src/extended/components/component-properties-panel/utils/validate-group-label.ts
3620
- import { __ as __17 } from "@wordpress/i18n";
3621
- var ERROR_MESSAGES2 = {
3622
- EMPTY_NAME: __17("Group name is required", "elementor"),
3623
- DUPLICATE_NAME: __17("Group name already exists", "elementor")
3624
- };
3625
- function validateGroupLabel(label, existingGroups) {
3626
- const trimmedLabel = label.trim();
3627
- if (!trimmedLabel) {
3628
- return ERROR_MESSAGES2.EMPTY_NAME;
3629
- }
3630
- const isDuplicate = Object.values(existingGroups).some((group) => group.label === trimmedLabel);
3631
- if (isDuplicate) {
3632
- return ERROR_MESSAGES2.DUPLICATE_NAME;
3633
- }
3634
- return "";
3635
- }
3636
-
3637
- // src/extended/components/component-properties-panel/use-current-editable-item.ts
3638
- function useCurrentEditableItem() {
3639
- const [editingGroupId, setEditingGroupId] = useState4(null);
3640
- const currentComponentId = useCurrentComponentId();
3641
- const overridableProps = useOverridableProps(currentComponentId);
3642
- const allGroupsRecord = overridableProps?.groups?.items ?? {};
3643
- const currentGroup = editingGroupId ? allGroupsRecord[editingGroupId] : null;
3644
- const validateLabel = (newLabel) => {
3645
- const otherGroups = Object.fromEntries(
3646
- Object.entries(allGroupsRecord).filter(([id2]) => id2 !== editingGroupId)
3647
- );
3648
- return validateGroupLabel(newLabel, otherGroups) || null;
3649
- };
3650
- const handleSubmit = (newLabel) => {
3651
- if (!editingGroupId || !currentComponentId) {
3652
- throw new Error(__18("Group ID or component ID is missing", "elementor"));
3653
- }
3654
- renameOverridableGroup({
3655
- componentId: currentComponentId,
3656
- groupId: editingGroupId,
3657
- label: newLabel
3658
- });
3659
- setDocumentModifiedStatus2(true);
3660
- };
3661
- const {
3662
- ref: editableRef,
3663
- openEditMode,
3664
- isEditing,
3665
- error,
3666
- getProps: getEditableProps
3667
- } = useEditable({
3668
- value: currentGroup?.label ?? "",
3669
- onSubmit: handleSubmit,
3670
- validation: validateLabel
3671
- });
3672
- return {
3673
- editableRef,
3674
- isEditing,
3675
- error,
3676
- getEditableProps,
3677
- setEditingGroupId: (groupId) => {
3678
- setEditingGroupId(groupId);
3679
- openEditMode();
3680
- },
3681
- editingGroupId
3682
- };
3683
- }
3684
-
3685
- // src/extended/components/component-properties-panel/utils/generate-unique-label.ts
3686
- var DEFAULT_NEW_GROUP_LABEL = "New group";
3687
- function generateUniqueLabel(groups) {
3688
- const existingLabels = new Set(groups.map((group) => group.label));
3689
- if (!existingLabels.has(DEFAULT_NEW_GROUP_LABEL)) {
3690
- return DEFAULT_NEW_GROUP_LABEL;
3691
- }
3692
- let index = 1;
3693
- let newLabel = `${DEFAULT_NEW_GROUP_LABEL}-${index}`;
3694
- while (existingLabels.has(newLabel)) {
3695
- index++;
3696
- newLabel = `${DEFAULT_NEW_GROUP_LABEL}-${index}`;
3697
- }
3698
- return newLabel;
3699
- }
3700
-
3701
- // src/extended/components/component-properties-panel/component-properties-panel-content.tsx
3702
- function ComponentPropertiesPanelContent({ onClose }) {
3703
- const currentComponentId = useCurrentComponentId();
3704
- const overridableProps = useSanitizeOverridableProps(currentComponentId);
3705
- const [isAddingGroup, setIsAddingGroup] = useState5(false);
3706
- const introductionRef = useRef(null);
3707
- const groupLabelEditable = useCurrentEditableItem();
3708
- const groups = useMemo(() => {
3709
- if (!overridableProps) {
3710
- return [];
3711
- }
3712
- return overridableProps.groups.order.map((groupId) => overridableProps.groups.items[groupId] ?? null).filter(Boolean);
3713
- }, [overridableProps]);
3714
- const allGroupsForSelect = useMemo(
3715
- () => groups.map((group) => ({ value: group.id, label: group.label })),
3716
- [groups]
3717
- );
3718
- if (!currentComponentId || !overridableProps) {
3719
- return null;
3720
- }
3721
- const hasGroups = groups.length > 0;
3722
- const showEmptyState = !hasGroups && !isAddingGroup;
3723
- const groupIds = overridableProps.groups.order;
3724
- const handleAddGroupClick = () => {
3725
- if (isAddingGroup) {
3726
- return;
3727
- }
3728
- const newGroupId = generateUniqueId2("group");
3729
- const newLabel = generateUniqueLabel(groups);
3730
- addOverridableGroup({
3731
- componentId: currentComponentId,
3732
- groupId: newGroupId,
3733
- label: newLabel,
3734
- source: "user"
3735
- });
3736
- setDocumentModifiedStatus3(true);
3737
- setIsAddingGroup(false);
3738
- groupLabelEditable.setEditingGroupId(newGroupId);
3739
- };
3740
- const handleGroupsReorder = (newOrder) => {
3741
- reorderOverridableGroups({ componentId: currentComponentId, newOrder });
3742
- setDocumentModifiedStatus3(true);
3743
- };
3744
- const handlePropsReorder = (groupId, newPropsOrder) => {
3745
- reorderGroupProps({ componentId: currentComponentId, groupId, newPropsOrder });
3746
- setDocumentModifiedStatus3(true);
3747
- };
3748
- const handlePropertyDelete = (propKey) => {
3749
- deleteOverridableProp({ componentId: currentComponentId, propKey, source: "user" });
3750
- setDocumentModifiedStatus3(true);
3751
- };
3752
- const handlePropertyUpdate = (overrideKey, data) => {
3753
- updateOverridablePropParams({
3754
- componentId: currentComponentId,
3755
- overrideKey,
3756
- label: data.label,
3757
- groupId: data.group
3758
- });
3759
- setDocumentModifiedStatus3(true);
3760
- };
3761
- const handleGroupDelete = (groupId) => {
3762
- deleteOverridableGroup({ componentId: currentComponentId, groupId });
3763
- setDocumentModifiedStatus3(true);
3764
- };
3765
- return /* @__PURE__ */ React26.createElement(React26.Fragment, null, /* @__PURE__ */ React26.createElement(PanelHeader2, { sx: { justifyContent: "start", pl: 1.5, pr: 1, py: 1 } }, /* @__PURE__ */ React26.createElement(Stack16, { direction: "row", alignItems: "center", gap: 0.5, flexGrow: 1 }, /* @__PURE__ */ React26.createElement(ComponentPropListIcon3, { fontSize: "tiny" }), /* @__PURE__ */ React26.createElement(PanelHeaderTitle2, { variant: "subtitle2" }, __19("Component properties", "elementor"))), !showEmptyState && /* @__PURE__ */ React26.createElement(Tooltip3, { title: __19("Add new group", "elementor") }, /* @__PURE__ */ React26.createElement(
3766
- IconButton4,
3767
- {
3768
- size: "tiny",
3769
- "aria-label": __19("Add new group", "elementor"),
3770
- onClick: handleAddGroupClick
3771
- },
3772
- /* @__PURE__ */ React26.createElement(FolderPlusIcon, { fontSize: "tiny" })
3773
- )), /* @__PURE__ */ React26.createElement(Tooltip3, { title: __19("Close panel", "elementor") }, /* @__PURE__ */ React26.createElement(
3774
- IconButton4,
3775
- {
3776
- ref: introductionRef,
3777
- size: "tiny",
3778
- "aria-label": __19("Close panel", "elementor"),
3779
- onClick: onClose
3780
- },
3781
- /* @__PURE__ */ React26.createElement(XIcon2, { fontSize: "tiny" })
3782
- ))), /* @__PURE__ */ React26.createElement(Divider3, null), /* @__PURE__ */ React26.createElement(PanelBody2, null, showEmptyState ? /* @__PURE__ */ React26.createElement(PropertiesEmptyState, { introductionRef }) : /* @__PURE__ */ React26.createElement(List3, { sx: { p: 2, display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ React26.createElement(SortableProvider, { value: groupIds, onChange: handleGroupsReorder }, groups.map((group) => /* @__PURE__ */ React26.createElement(SortableItem, { key: group.id, id: group.id }, ({ triggerProps, triggerStyle, isDragPlaceholder }) => /* @__PURE__ */ React26.createElement(
3783
- PropertiesGroup,
3784
- {
3785
- group,
3786
- props: overridableProps.props,
3787
- allGroups: allGroupsForSelect,
3788
- allGroupsRecord: overridableProps.groups.items,
3789
- sortableTriggerProps: { ...triggerProps, style: triggerStyle },
3790
- isDragPlaceholder,
3791
- setIsAddingGroup,
3792
- onPropsReorder: (newOrder) => handlePropsReorder(group.id, newOrder),
3793
- onPropertyDelete: handlePropertyDelete,
3794
- onPropertyUpdate: handlePropertyUpdate,
3795
- editableLabelProps: groupLabelEditable,
3796
- onGroupDelete: handleGroupDelete
3797
- }
3798
- )))))));
3799
- }
3800
-
3801
- // src/extended/components/component-properties-panel/component-properties-panel.tsx
3802
- var id = "component-properties-panel";
3803
- var { panel, usePanelActions } = createPanel({
3804
- id,
3805
- component: ComponentPropertiesPanel
3806
- });
3807
- function ComponentPropertiesPanel() {
3808
- const { close: closePanel } = usePanelActions();
3809
- const { open: openEditingPanel } = useEditingPanelActions();
3810
- return /* @__PURE__ */ React27.createElement(ThemeProvider2, null, /* @__PURE__ */ React27.createElement(ErrorBoundary, { fallback: /* @__PURE__ */ React27.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React27.createElement(Panel, null, /* @__PURE__ */ React27.createElement(
3811
- ComponentPropertiesPanelContent,
3812
- {
3813
- onClose: () => {
3814
- closePanel();
3815
- openEditingPanel();
3816
- }
3817
- }
3818
- ))));
3819
- }
3820
- var ErrorBoundaryFallback = () => /* @__PURE__ */ React27.createElement(Box13, { role: "alert", sx: { minHeight: "100%", p: 2 } }, /* @__PURE__ */ React27.createElement(Alert, { severity: "error", sx: { mb: 2, maxWidth: 400, textAlign: "center" } }, /* @__PURE__ */ React27.createElement("strong", null, __20("Something went wrong", "elementor"))));
3821
-
3822
- // src/extended/components/component-panel-header/component-badge.tsx
3823
- import * as React28 from "react";
3824
- import { useEffect as useEffect2, useRef as useRef2 } from "react";
3825
- import { ComponentPropListIcon as ComponentPropListIcon4 } from "@elementor/icons";
3826
- import { Badge, Box as Box14, keyframes, styled as styled3, ToggleButton, Tooltip as Tooltip4 } from "@elementor/ui";
3827
- import { __ as __21 } from "@wordpress/i18n";
3828
- var ComponentsBadge = React28.forwardRef(({ overridablePropsCount, onClick }, ref) => {
3829
- const prevCount = usePrevious(overridablePropsCount);
3830
- const isFirstExposedProperty = prevCount === 0 && overridablePropsCount === 1;
3831
- return /* @__PURE__ */ React28.createElement(
3832
- StyledBadge,
3833
- {
3834
- ref,
3835
- color: "primary",
3836
- key: overridablePropsCount,
3837
- invisible: overridablePropsCount === 0,
3838
- animate: isFirstExposedProperty,
3839
- anchorOrigin: { vertical: "top", horizontal: "right" },
3840
- badgeContent: /* @__PURE__ */ React28.createElement(Box14, { sx: { animation: !isFirstExposedProperty ? `${slideUp} 300ms ease-out` : "none" } }, overridablePropsCount)
3841
- },
3842
- /* @__PURE__ */ React28.createElement(Tooltip4, { title: __21("Component properties", "elementor") }, /* @__PURE__ */ React28.createElement(
3843
- ToggleButton,
3844
- {
3845
- value: "exposed properties",
3846
- size: "tiny",
3847
- onClick,
3848
- "aria-label": __21("Component properties", "elementor")
3849
- },
3850
- /* @__PURE__ */ React28.createElement(ComponentPropListIcon4, { fontSize: "tiny" })
3851
- ))
3852
- );
3853
- });
3854
- var StyledBadge = styled3(Badge, { shouldForwardProp: (prop) => prop !== "animate" })(
3855
- ({ theme, animate }) => ({
3856
- "& .MuiBadge-badge": {
3857
- minWidth: theme.spacing(2),
3858
- height: theme.spacing(2),
3859
- minHeight: theme.spacing(2),
3860
- maxWidth: theme.spacing(2),
3861
- fontSize: theme.typography.caption.fontSize,
3862
- animation: animate ? `${bounceIn} 300ms ease-out` : "none"
3863
- }
3864
- })
3865
- );
3866
- function usePrevious(value) {
3867
- const ref = useRef2(value);
3868
- useEffect2(() => {
3869
- ref.current = value;
3870
- }, [value]);
3871
- return ref.current;
3872
- }
3873
- var bounceIn = keyframes`
3874
- 0% { transform: scale(0) translate(50%, 50%); opacity: 0; }
3875
- 70% { transform: scale(1.1) translate(50%, -50%); opacity: 1; }
3876
- 100% { transform: scale(1) translate(50%, -50%); opacity: 1; }
3877
- `;
3878
- var slideUp = keyframes`
3879
- from { transform: translateY(100%); opacity: 0; }
3880
- to { transform: translateY(0); opacity: 1; }
3881
- `;
3882
-
3883
- // src/extended/components/component-panel-header/component-panel-header.tsx
3884
- var MESSAGE_KEY = "components-properties-introduction";
3885
- var ComponentPanelHeader = () => {
3886
- const { id: currentComponentId, uid: componentUid } = useCurrentComponent() ?? { id: null, uid: null };
3887
- const overridableProps = useSanitizeOverridableProps(currentComponentId);
3888
- const onBack = useNavigateBack();
3889
- const componentName = getComponentName();
3890
- const [isMessageSuppressed, suppressMessage] = useSuppressedMessage(MESSAGE_KEY);
3891
- const [shouldShowIntroduction, setShouldShowIntroduction] = React29.useState(!isMessageSuppressed);
3892
- const { open: openPropertiesPanel } = usePanelActions();
3893
- const overridablePropsCount = overridableProps ? Object.keys(overridableProps.props).length : 0;
3894
- const anchorRef = React29.useRef(null);
3895
- if (!currentComponentId) {
3896
- return null;
3897
- }
3898
- const handleCloseIntroduction = () => {
3899
- suppressMessage();
3900
- setShouldShowIntroduction(false);
3901
- };
3902
- const handleOpenPropertiesPanel = () => {
3903
- openPropertiesPanel();
3904
- trackComponentEvent({
3905
- action: "propertiesPanelOpened",
3906
- source: "user",
3907
- component_uid: componentUid,
3908
- properties_count: overridablePropsCount
3909
- });
3910
- };
3911
- return /* @__PURE__ */ React29.createElement(Box15, { "data-testid": "component-panel-header" }, /* @__PURE__ */ React29.createElement(PanelHeader3, { sx: { justifyContent: "start", px: 2 } }, /* @__PURE__ */ React29.createElement(Tooltip5, { title: __22("Back", "elementor") }, /* @__PURE__ */ React29.createElement(IconButton5, { size: "tiny", onClick: onBack, "aria-label": __22("Back", "elementor") }, /* @__PURE__ */ React29.createElement(ArrowLeftIcon, { fontSize: "tiny" }))), /* @__PURE__ */ React29.createElement(ComponentsFilledIcon, { fontSize: "tiny", stroke: "currentColor" }), /* @__PURE__ */ React29.createElement(
3912
- EllipsisWithTooltip4,
3913
- {
3914
- title: componentName,
3915
- as: Typography11,
3916
- variant: "caption",
3917
- sx: { fontWeight: 500, flexGrow: 1 }
3918
- }
3919
- ), /* @__PURE__ */ React29.createElement(
3920
- ComponentsBadge,
3921
- {
3922
- overridablePropsCount,
3923
- ref: anchorRef,
3924
- onClick: handleOpenPropertiesPanel
3925
- }
3926
- )), /* @__PURE__ */ React29.createElement(Divider4, null), /* @__PURE__ */ React29.createElement(
3927
- ComponentIntroduction,
3928
- {
3929
- anchorRef,
3930
- shouldShowIntroduction,
3931
- onClose: handleCloseIntroduction
3932
- }
3933
- ));
3934
- };
3935
- function getComponentName() {
3936
- const state = getState9();
3937
- const path = state[SLICE_NAME].path;
3938
- const { instanceTitle } = path.at(-1) ?? {};
3939
- if (instanceTitle) {
3940
- return instanceTitle;
3941
- }
3942
- const documentsManager = getV1DocumentsManager3();
3943
- const currentDocument = documentsManager.getCurrent();
3944
- return currentDocument?.container?.settings?.get("post_title") ?? "";
3945
- }
3946
-
3947
- // src/extended/components/components-tab/components.tsx
3948
- import * as React32 from "react";
3949
- import { ThemeProvider as ThemeProvider3 } from "@elementor/editor-ui";
3950
- import { List as List4 } from "@elementor/ui";
3951
-
3952
- // src/extended/components/components-tab/component-item.tsx
3953
- import * as React31 from "react";
3954
- import { useRef as useRef4, useState as useState7 } from "react";
3955
- import { endDragElementFromPanel, startDragElementFromPanel } from "@elementor/editor-canvas";
3956
- import { dropElement } from "@elementor/editor-elements";
3957
- import { MenuListItem as MenuListItem3, useEditable as useEditable2, WarningInfotip } from "@elementor/editor-ui";
3958
- import { DotsVerticalIcon as DotsVerticalIcon2 } from "@elementor/icons";
3959
- import { bindMenu as bindMenu2, bindTrigger as bindTrigger3, IconButton as IconButton6, Menu as Menu2, Stack as Stack17, usePopupState as usePopupState3 } from "@elementor/ui";
3960
- import { __ as __26 } from "@wordpress/i18n";
3961
-
3962
- // src/extended/store/actions/archive-component.ts
3963
- import { setDocumentModifiedStatus as setDocumentModifiedStatus4 } from "@elementor/editor-documents";
3964
- import { notify as notify3 } from "@elementor/editor-notifications";
3965
- import { __ as __23 } from "@wordpress/i18n";
3966
- var successNotification = (componentId, componentName) => ({
3967
- type: "success",
3968
- /* translators: %s: component name */
3969
- message: __23("Successfully deleted component %s", "elementor").replace("%s", componentName),
3970
- id: `success-archived-components-notification-${componentId}`
3971
- });
3972
- var archiveComponent = (componentId, componentName) => {
3973
- componentsActions.archive(componentId);
3974
- setDocumentModifiedStatus4(true);
3975
- notify3(successNotification(componentId, componentName));
3976
- };
3977
-
3978
- // src/extended/store/actions/rename-component.ts
3979
- import { getV1DocumentsManager as getV1DocumentsManager4, setDocumentModifiedStatus as setDocumentModifiedStatus5 } from "@elementor/editor-documents";
3980
- import { getAllDescendants as getAllDescendants2 } from "@elementor/editor-elements";
3981
- var TITLE_EXTERNAL_CHANGE_COMMAND = "title_external_change";
3982
- var renameComponent = (componentUid, newName) => {
3983
- componentsActions.rename(componentUid, newName);
3984
- setDocumentModifiedStatus5(true);
3985
- refreshComponentInstanceTitles(componentUid);
3986
- };
3987
- function refreshComponentInstanceTitles(componentUid) {
3988
- const documentContainer = getDocumentContainer();
3989
- if (!documentContainer) {
3990
- return;
3991
- }
3992
- const componentInstances = findComponentInstancesByUid(documentContainer, componentUid);
3993
- componentInstances.forEach((element) => {
3994
- element.model.trigger?.(TITLE_EXTERNAL_CHANGE_COMMAND);
3995
- });
3996
- }
3997
- function getDocumentContainer() {
3998
- const documentsManager = getV1DocumentsManager4();
3999
- return documentsManager?.getCurrent()?.container;
4000
- }
4001
- function findComponentInstancesByUid(documentContainer, componentUid) {
4002
- const allDescendants = getAllDescendants2(documentContainer);
4003
- return allDescendants.filter((element) => {
4004
- const widgetType = element.model.get("widgetType");
4005
- const editorSettings = element.model.get("editor_settings");
4006
- const isMatch = widgetType === COMPONENT_WIDGET_TYPE2 && editorSettings?.component_uid === componentUid;
4007
- return isMatch;
4008
- });
4009
- }
4010
-
4011
- // src/extended/utils/component-form-schema.ts
4012
- import { z as z5 } from "@elementor/schema";
4013
- import { __ as __24 } from "@wordpress/i18n";
4014
- var MIN_NAME_LENGTH = 2;
4015
- var MAX_NAME_LENGTH = 50;
4016
- var baseComponentSchema = z5.string().trim().max(MAX_NAME_LENGTH, __24("Component name is too long. Please keep it under 50 characters.", "elementor"));
4017
- var createBaseComponentSchema = (existingNames) => {
4018
- return z5.object({
4019
- componentName: baseComponentSchema.refine((value) => !existingNames.includes(value), {
4020
- message: __24("Component name already exists", "elementor")
4021
- })
4022
- });
4023
- };
4024
- var createSubmitComponentSchema = (existingNames) => {
4025
- const baseSchema = createBaseComponentSchema(existingNames);
4026
- return baseSchema.extend({
4027
- componentName: baseSchema.shape.componentName.refine((value) => value.length > 0, {
4028
- message: __24("Component name is required.", "elementor")
4029
- }).refine((value) => value.length >= MIN_NAME_LENGTH, {
4030
- message: __24("Component name is too short. Please enter at least 2 characters.", "elementor")
4031
- })
4032
- });
4033
- };
4034
-
4035
- // src/extended/utils/component-name-validation.ts
4036
- function validateComponentName(label) {
4037
- const existingComponentTitles = componentsSelectors.getComponents()?.map(({ name }) => name) ?? [];
4038
- const schema = createSubmitComponentSchema(existingComponentTitles);
4039
- const result = schema.safeParse({ componentName: label.toLowerCase() });
4040
- if (result.success) {
4041
- return {
4042
- isValid: true,
4043
- errorMessage: null
4044
- };
4045
- }
4046
- const formattedErrors = result.error.format();
4047
- const errorMessage = formattedErrors.componentName?._errors[0] ?? formattedErrors._errors[0];
4048
- return {
4049
- isValid: false,
4050
- errorMessage
4051
- };
4052
- }
4053
-
4054
- // src/extended/utils/create-component-model.ts
4055
- var createComponentModel2 = (component) => {
4056
- return {
4057
- elType: "widget",
4058
- widgetType: "e-component",
4059
- settings: {
4060
- component_instance: {
4061
- $$type: "component-instance",
4062
- value: {
4063
- component_id: {
4064
- $$type: "number",
4065
- value: component.id ?? component.uid
4066
- }
4067
- }
4068
- }
4069
- },
4070
- editor_settings: {
4071
- component_uid: component.uid
4072
- }
4073
- };
4074
- };
4075
-
4076
- // src/extended/utils/get-container-for-new-element.ts
4077
- import {
4078
- getContainer as getContainer4,
4079
- getCurrentDocumentContainer as getCurrentDocumentContainer2,
4080
- getSelectedElements
4081
- } from "@elementor/editor-elements";
4082
- var getContainerForNewElement = () => {
4083
- const currentDocumentContainer = getCurrentDocumentContainer2();
4084
- const selectedElement = getSelectedElementContainer();
4085
- let container, options;
4086
- if (selectedElement) {
4087
- switch (selectedElement.model.get("elType")) {
4088
- case "widget": {
4089
- container = selectedElement?.parent;
4090
- const selectedElIndex = selectedElement.view?._index ?? -1;
4091
- if (selectedElIndex > -1) {
4092
- options = { at: selectedElIndex + 1 };
4093
- }
4094
- break;
4095
- }
4096
- case "section": {
4097
- container = selectedElement?.children?.[0];
4098
- break;
4099
- }
4100
- default: {
4101
- container = selectedElement;
4102
- break;
4103
- }
4104
- }
4105
- }
4106
- return { container: container ?? currentDocumentContainer, options };
4107
- };
4108
- function getSelectedElementContainer() {
4109
- const selectedElements = getSelectedElements();
4110
- if (selectedElements.length !== 1) {
4111
- return void 0;
4112
- }
4113
- return getContainer4(selectedElements[0].id);
4114
- }
4115
-
4116
- // src/extended/components/components-tab/delete-confirmation-dialog.tsx
4117
- import * as React30 from "react";
4118
- import { ConfirmationDialog as ConfirmationDialog2 } from "@elementor/editor-ui";
4119
- import { __ as __25 } from "@wordpress/i18n";
4120
- function DeleteConfirmationDialog({ open, onClose, onConfirm }) {
4121
- return /* @__PURE__ */ React30.createElement(ConfirmationDialog2, { open, onClose }, /* @__PURE__ */ React30.createElement(ConfirmationDialog2.Title, null, __25("Delete this component?", "elementor")), /* @__PURE__ */ React30.createElement(ConfirmationDialog2.Content, null, /* @__PURE__ */ React30.createElement(ConfirmationDialog2.ContentText, null, __25(
4122
- "Existing instances on your pages will remain functional. You will no longer find this component in your list.",
4123
- "elementor"
4124
- ))), /* @__PURE__ */ React30.createElement(ConfirmationDialog2.Actions, { onClose, onConfirm }));
4125
- }
4126
-
4127
- // src/extended/components/components-tab/component-item.tsx
4128
- function ComponentItem2({ component }) {
4129
- const itemRef = useRef4(null);
4130
- const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState7(false);
4131
- const { canRename, canDelete } = useComponentsPermissions();
4132
- const shouldShowActions = canRename || canDelete;
4133
- const {
4134
- ref: editableRef,
4135
- isEditing,
4136
- openEditMode,
4137
- error,
4138
- getProps: getEditableProps
4139
- } = useEditable2({
4140
- value: component.name,
4141
- onSubmit: (newName) => renameComponent(component.uid, newName),
4142
- validation: validateComponentTitle
4143
- });
4144
- const componentModel = createComponentModel2(component);
4145
- const popupState = usePopupState3({
4146
- variant: "popover",
4147
- disableAutoFocus: true
4148
- });
4149
- const handleClick = () => {
4150
- addComponentToPage(componentModel);
4151
- };
4152
- const handleDragEnd = () => {
4153
- loadComponentsAssets([componentModel]);
4154
- endDragElementFromPanel();
4155
- };
4156
- const handleDeleteClick = () => {
4157
- setIsDeleteDialogOpen(true);
4158
- popupState.close();
4159
- };
4160
- const handleDeleteConfirm = () => {
4161
- if (!component.id) {
4162
- throw new Error("Component ID is required");
4163
- }
4164
- setIsDeleteDialogOpen(false);
4165
- archiveComponent(component.id, component.name);
4166
- };
4167
- const handleDeleteDialogClose = () => {
4168
- setIsDeleteDialogOpen(false);
4169
- };
4170
- return /* @__PURE__ */ React31.createElement(Stack17, null, /* @__PURE__ */ React31.createElement(
4171
- WarningInfotip,
4172
- {
4173
- open: Boolean(error),
4174
- text: error ?? "",
4175
- placement: "bottom",
4176
- width: itemRef.current?.getBoundingClientRect().width,
4177
- offset: [0, -15]
4178
- },
4179
- /* @__PURE__ */ React31.createElement(
4180
- ComponentItem,
4181
- {
4182
- ref: itemRef,
4183
- component,
4184
- disabled: false,
4185
- draggable: true,
4186
- onDragStart: (event) => startDragElementFromPanel(componentModel, event),
4187
- onDragEnd: handleDragEnd,
4188
- onClick: handleClick,
4189
- isEditing,
4190
- error,
4191
- nameSlot: /* @__PURE__ */ React31.createElement(
4192
- ComponentName,
4193
- {
4194
- name: component.name,
4195
- editable: { ref: editableRef, isEditing, getProps: getEditableProps }
4196
- }
4197
- ),
4198
- endSlot: shouldShowActions ? /* @__PURE__ */ React31.createElement(IconButton6, { size: "tiny", ...bindTrigger3(popupState), "aria-label": "More actions" }, /* @__PURE__ */ React31.createElement(DotsVerticalIcon2, { fontSize: "tiny" })) : void 0
4199
- }
4200
- )
4201
- ), shouldShowActions && /* @__PURE__ */ React31.createElement(
4202
- Menu2,
4203
- {
4204
- ...bindMenu2(popupState),
4205
- anchorOrigin: {
4206
- vertical: "bottom",
4207
- horizontal: "right"
4208
- },
4209
- transformOrigin: {
4210
- vertical: "top",
4211
- horizontal: "right"
4212
- }
4213
- },
4214
- canRename && /* @__PURE__ */ React31.createElement(
4215
- MenuListItem3,
4216
- {
4217
- sx: { minWidth: "160px" },
4218
- primaryTypographyProps: { variant: "caption", color: "text.primary" },
4219
- onClick: () => {
4220
- popupState.close();
4221
- openEditMode();
4222
- }
4223
- },
4224
- __26("Rename", "elementor")
4225
- ),
4226
- canDelete && /* @__PURE__ */ React31.createElement(
4227
- MenuListItem3,
4228
- {
4229
- sx: { minWidth: "160px" },
4230
- primaryTypographyProps: { variant: "caption", color: "error.light" },
4231
- onClick: handleDeleteClick
4232
- },
4233
- __26("Delete", "elementor")
4234
- )
4235
- ), /* @__PURE__ */ React31.createElement(
4236
- DeleteConfirmationDialog,
4237
- {
4238
- open: isDeleteDialogOpen,
4239
- onClose: handleDeleteDialogClose,
4240
- onConfirm: handleDeleteConfirm
4241
- }
4242
- ));
4243
- }
4244
- var addComponentToPage = (model) => {
4245
- const { container, options } = getContainerForNewElement();
4246
- if (!container) {
4247
- throw new Error(`Can't find container to drop new component instance at`);
4248
- }
4249
- loadComponentsAssets([model]);
4250
- dropElement({
4251
- containerId: container.id,
4252
- model,
4253
- options: { ...options, useHistory: false, scrollIntoView: true }
4254
- });
4255
- };
4256
- var validateComponentTitle = (newTitle) => {
4257
- const result = validateComponentName(newTitle);
4258
- if (!result.errorMessage) {
4259
- return null;
4260
- }
4261
- return result.errorMessage;
4262
- };
4263
-
4264
- // src/extended/components/components-tab/components.tsx
4265
- var ExtendedComponentsList = () => {
4266
- const { components, isLoading, searchValue } = useFilteredComponents();
4267
- if (isLoading) {
4268
- return /* @__PURE__ */ React32.createElement(LoadingComponents, null);
4269
- }
4270
- const isEmpty = !components?.length;
4271
- if (isEmpty) {
4272
- return searchValue.length ? /* @__PURE__ */ React32.createElement(EmptySearchResult, null) : /* @__PURE__ */ React32.createElement(EmptyState, null);
4273
- }
4274
- return /* @__PURE__ */ React32.createElement(List4, { sx: { display: "flex", flexDirection: "column", gap: 1, px: 2 } }, components.map((component) => /* @__PURE__ */ React32.createElement(ComponentItem2, { key: component.uid, component })));
4275
- };
4276
- var ExtendedComponentsContent = () => {
4277
- const { components, isLoading } = useComponents();
4278
- const hasComponents = !isLoading && components.length > 0;
4279
- return /* @__PURE__ */ React32.createElement(React32.Fragment, null, hasComponents && /* @__PURE__ */ React32.createElement(ComponentSearch, null), /* @__PURE__ */ React32.createElement(ExtendedComponentsList, null));
4280
- };
4281
- var ExtendedComponents = () => {
4282
- return /* @__PURE__ */ React32.createElement(ThemeProvider3, null, /* @__PURE__ */ React32.createElement(SearchProvider, { localStorageKey: "elementor-components-search" }, /* @__PURE__ */ React32.createElement(ExtendedComponentsContent, null)));
4283
- };
4284
-
4285
- // src/extended/components/create-component-form/create-component-form.tsx
4286
- import * as React33 from "react";
4287
- import { useEffect as useEffect3, useMemo as useMemo3, useRef as useRef5, useState as useState9 } from "react";
4288
- import { getElementLabel } from "@elementor/editor-elements";
4289
- import { notify as notify5 } from "@elementor/editor-notifications";
4290
- import { Form as FormElement, ThemeProvider as ThemeProvider4, useTextFieldAutoSelect } from "@elementor/editor-ui";
4291
- import { ComponentsIcon as ComponentsIcon4 } from "@elementor/icons";
4292
- import { Button as Button5, FormLabel as FormLabel2, Grid as Grid2, Popover as Popover3, Stack as Stack18, TextField as TextField3, Typography as Typography12 } from "@elementor/ui";
4293
- import { __ as __29 } from "@wordpress/i18n";
4294
-
4295
- // src/extended/store/actions/create-unpublished-component.ts
4296
- import { createElements, deleteElement, getContainer as getContainer5 } from "@elementor/editor-elements";
4297
- import { __privateRunCommand as runCommand2 } from "@elementor/editor-v1-adapters";
4298
- import { generateUniqueId as generateUniqueId3 } from "@elementor/utils";
4299
- import { __ as __27 } from "@wordpress/i18n";
4300
-
4301
- // src/extended/utils/replace-element-with-component.ts
4302
- import { replaceElement as replaceElement2 } from "@elementor/editor-elements";
4303
- var replaceElementWithComponent = (element, component) => {
4304
- return replaceElement2({
4305
- currentElementId: element.id,
4306
- newElement: createComponentModel2(component),
4307
- withHistory: false
4308
- });
4309
- };
4310
-
4311
- // src/extended/store/actions/create-unpublished-component.ts
4312
- async function createUnpublishedComponent({
4313
- name,
4314
- element,
4315
- eventData,
4316
- uid,
4317
- overridableProps,
4318
- source
4319
- }) {
4320
- const generatedUid = uid ?? generateUniqueId3("component");
4321
- const componentBase = { uid: generatedUid, name };
4322
- const elementDataWithOverridablesReverted = revertAllOverridablesInElementData(element);
4323
- const container = getContainer5(element.id);
4324
- const modelFromContainer = container?.model?.toJSON?.();
4325
- const originalElement = {
4326
- model: modelFromContainer ?? element,
4327
- parentId: container?.parent?.id ?? "",
4328
- index: container?.view?._index ?? 0
4329
- };
4330
- componentsActions.addUnpublished({
4331
- ...componentBase,
4332
- elements: [elementDataWithOverridablesReverted],
4333
- overridableProps
4334
- });
4335
- componentsActions.addCreatedThisSession(generatedUid);
4336
- const componentInstance = replaceElementWithComponent(element, componentBase);
4337
- trackComponentEvent({
4338
- action: "created",
4339
- source,
4340
- component_uid: generatedUid,
4341
- component_name: name,
4342
- ...eventData
4343
- });
4344
- try {
4345
- await runCommand2("document/save/auto");
4346
- } catch (error) {
4347
- restoreOriginalElement(originalElement, componentInstance.id);
4348
- componentsActions.removeUnpublished(generatedUid);
4349
- componentsActions.removeCreatedThisSession(generatedUid);
4350
- throw error;
4351
- }
4352
- return { uid: generatedUid, instanceId: componentInstance.id };
4353
- }
4354
- function restoreOriginalElement(originalElement, componentInstanceId) {
4355
- const componentContainer = getContainer5(componentInstanceId);
4356
- if (componentContainer) {
4357
- deleteElement({ container: componentContainer, options: { useHistory: false } });
4358
- }
4359
- const parentContainer = getContainer5(originalElement.parentId);
4360
- if (!parentContainer) {
4361
- return;
4362
- }
4363
- const clonedModel = structuredClone(originalElement.model);
4364
- createElements({
4365
- title: __27("Restore Element", "elementor"),
4366
- elements: [
4367
- {
4368
- container: parentContainer,
4369
- model: clonedModel,
4370
- options: { at: originalElement.index }
4371
- }
4372
- ]
4373
- });
4374
- }
4375
-
4376
- // src/extended/sync/prevent-non-atomic-nesting.ts
4377
- import { isAtomicWidget } from "@elementor/editor-canvas";
4378
- import { getAllDescendants as getAllDescendants3, getElementType as getElementType3 } from "@elementor/editor-elements";
4379
- import { notify as notify4 } from "@elementor/editor-notifications";
4380
- import { blockCommand } from "@elementor/editor-v1-adapters";
4381
- import { __ as __28 } from "@wordpress/i18n";
4382
-
4383
- // src/extended/utils/is-editing-component.ts
4384
- function isEditingComponent() {
4385
- return componentsSelectors.getCurrentComponentId() !== null;
4386
- }
4387
-
4388
- // src/extended/sync/prevent-non-atomic-nesting.ts
4389
- var NON_ATOMIC_ELEMENT_ALERT = {
4390
- type: "default",
4391
- message: __28("This widget isn't compatible with components. Use atomic elements instead.", "elementor"),
4392
- id: "non-atomic-element-blocked"
4393
- };
4394
- function initNonAtomicNestingPrevention() {
4395
- blockCommand({
4396
- command: "document/elements/create",
4397
- condition: blockNonAtomicCreate
4398
- });
4399
- blockCommand({
4400
- command: "document/elements/move",
4401
- condition: blockNonAtomicMove
4402
- });
4403
- blockCommand({
4404
- command: "document/elements/paste",
4405
- condition: blockNonAtomicPaste
4406
- });
4407
- }
4408
- function isElementAtomic(elementType) {
4409
- return getElementType3(elementType) !== null;
4410
- }
4411
- function blockNonAtomicCreate(args) {
4412
- if (!isEditingComponent()) {
4413
- return false;
4414
- }
4415
- const { model } = args;
4416
- const elementType = model?.widgetType || model?.elType;
4417
- if (!elementType) {
4418
- return false;
4419
- }
4420
- if (isElementAtomic(elementType)) {
4421
- return false;
4422
- }
4423
- notify4(NON_ATOMIC_ELEMENT_ALERT);
4424
- return true;
4425
- }
4426
- function blockNonAtomicMove(args) {
4427
- if (!isEditingComponent()) {
4428
- return false;
4429
- }
4430
- const { containers = [args.container] } = args;
4431
- const hasNonAtomicElement = containers.some((container) => {
4432
- if (!container) {
4433
- return false;
4434
- }
4435
- const allElements = getAllDescendants3(container);
4436
- return allElements.some((element) => !isAtomicWidget(element));
4437
- });
4438
- if (hasNonAtomicElement) {
4439
- notify4(NON_ATOMIC_ELEMENT_ALERT);
4440
- }
4441
- return hasNonAtomicElement;
4442
- }
4443
- function blockNonAtomicPaste(args) {
4444
- if (!isEditingComponent()) {
4445
- return false;
4446
- }
4447
- const { storageType } = args;
4448
- if (storageType !== "localstorage") {
4449
- return false;
4450
- }
4451
- const data = window?.elementorCommon?.storage?.get();
4452
- if (!data?.clipboard?.elements) {
4453
- return false;
4454
- }
4455
- const hasNonAtomicElement = hasNonAtomicElementsInTree(data.clipboard.elements);
4456
- if (hasNonAtomicElement) {
4457
- notify4(NON_ATOMIC_ELEMENT_ALERT);
4458
- }
4459
- return hasNonAtomicElement;
4460
- }
4461
- function hasNonAtomicElementsInTree(elements) {
4462
- for (const element of elements) {
4463
- const elementType = element.widgetType || element.elType;
4464
- if (elementType && !isElementAtomic(elementType)) {
4465
- return true;
4466
- }
4467
- if (element.elements?.length) {
4468
- if (hasNonAtomicElementsInTree(element.elements)) {
4469
- return true;
4470
- }
4471
- }
4472
- }
4473
- return false;
4474
- }
4475
- function findNonAtomicElementsInElement(element) {
4476
- const nonAtomicElements = [];
4477
- const elementType = element.widgetType || element.elType;
4478
- if (elementType && !isElementAtomic(elementType)) {
4479
- nonAtomicElements.push(elementType);
4480
- }
4481
- if (element.elements?.length) {
4482
- for (const child of element.elements) {
4483
- nonAtomicElements.push(...findNonAtomicElementsInElement(child));
4484
- }
4485
- }
4486
- return [...new Set(nonAtomicElements)];
4487
- }
4488
-
4489
- // src/extended/components/create-component-form/hooks/use-form.ts
4490
- import { useMemo as useMemo2, useState as useState8 } from "react";
4491
- var useForm = (initialValues) => {
4492
- const [values, setValues] = useState8(initialValues);
4493
- const [errors, setErrors] = useState8({});
4494
- const isValid = useMemo2(() => {
4495
- return !Object.values(errors).some((error) => error);
4496
- }, [errors]);
4497
- const handleChange = (e, field, validationSchema) => {
4498
- const updated = { ...values, [field]: e.target.value };
4499
- setValues(updated);
4500
- const { success, errors: validationErrors } = validateForm(updated, validationSchema);
4501
- if (!success) {
4502
- setErrors(validationErrors);
4503
- } else {
4504
- setErrors({});
4505
- }
4506
- };
4507
- const validate = (validationSchema) => {
4508
- const { success, errors: validationErrors, parsedValues } = validateForm(values, validationSchema);
4509
- if (!success) {
4510
- setErrors(validationErrors);
4511
- return { success };
4512
- }
4513
- setErrors({});
4514
- return { success, parsedValues };
4515
- };
4516
- return {
4517
- values,
4518
- errors,
4519
- isValid,
4520
- handleChange,
4521
- validateForm: validate
4522
- };
4523
- };
4524
- var validateForm = (values, schema) => {
4525
- const result = schema.safeParse(values);
4526
- if (result.success) {
4527
- return { success: true, parsedValues: result.data };
4528
- }
4529
- const errors = {};
4530
- Object.entries(result.error.formErrors.fieldErrors).forEach(
4531
- ([field, error]) => {
4532
- errors[field] = error[0];
4533
- }
4534
- );
4535
- return { success: false, errors };
4536
- };
4537
-
4538
- // src/extended/components/create-component-form/utils/get-component-event-data.ts
4539
- var getComponentEventData = (containerElement, options) => {
4540
- const { elementsCount, componentsCount } = countNestedElements(containerElement);
4541
- return {
4542
- nested_elements_count: elementsCount,
4543
- nested_components_count: componentsCount,
4544
- top_element_type: containerElement.elType,
4545
- location: options?.location,
4546
- secondary_location: options?.secondaryLocation,
4547
- trigger: options?.trigger
4548
- };
4549
- };
4550
- function countNestedElements(container) {
4551
- if (!container.elements || container.elements.length === 0) {
4552
- return { elementsCount: 0, componentsCount: 0 };
4553
- }
4554
- let elementsCount = container.elements.length;
4555
- let componentsCount = 0;
4556
- for (const element of container.elements) {
4557
- if (element.widgetType === "e-component") {
4558
- componentsCount++;
4559
- }
4560
- const { elementsCount: nestedElementsCount, componentsCount: nestedComponentsCount } = countNestedElements(element);
4561
- elementsCount += nestedElementsCount;
4562
- componentsCount += nestedComponentsCount;
4563
- }
4564
- return { elementsCount, componentsCount };
4565
- }
4566
-
4567
- // src/extended/components/create-component-form/create-component-form.tsx
4568
- var MAX_COMPONENTS = 100;
4569
- function CreateComponentForm() {
4570
- const [element, setElement] = useState9(null);
4571
- const [anchorPosition, setAnchorPosition] = useState9();
4572
- const { components } = useComponents();
4573
- const eventData = useRef5(null);
4574
- useEffect3(() => {
4575
- const OPEN_SAVE_AS_COMPONENT_FORM_EVENT2 = "elementor/editor/open-save-as-component-form";
4576
- const openPopup = (event) => {
4577
- const { shouldOpen, notification } = shouldOpenForm(event.detail.element, components?.length ?? 0);
4578
- if (!shouldOpen) {
4579
- notify5(notification);
4580
- return;
4581
- }
4582
- setElement({ element: event.detail.element, elementLabel: getElementLabel(event.detail.element.id) });
4583
- setAnchorPosition(event.detail.anchorPosition);
4584
- eventData.current = getComponentEventData(event.detail.element, event.detail.options);
4585
- trackComponentEvent({
4586
- action: "createClicked",
4587
- source: "user",
4588
- ...eventData.current
4589
- });
4590
- };
4591
- window.addEventListener(OPEN_SAVE_AS_COMPONENT_FORM_EVENT2, openPopup);
4592
- return () => {
4593
- window.removeEventListener(OPEN_SAVE_AS_COMPONENT_FORM_EVENT2, openPopup);
4594
- };
4595
- }, [components?.length]);
4596
- const handleSave = async (values) => {
4597
- try {
4598
- if (!element) {
4599
- throw new Error(`Can't save element as component: element not found`);
4600
- }
4601
- const { uid, instanceId } = await createUnpublishedComponent({
4602
- name: values.componentName,
4603
- element: element.element,
4604
- eventData: eventData.current,
4605
- source: "user"
4606
- });
4607
- const publishedComponentId = componentsSelectors.getComponentByUid(uid)?.id;
4608
- if (publishedComponentId) {
4609
- switchToComponent(publishedComponentId, instanceId);
4610
- } else {
4611
- throw new Error("Failed to find published component");
4612
- }
4613
- notify5({
4614
- type: "success",
4615
- message: __29("Component created successfully.", "elementor"),
4616
- id: `component-saved-successfully-${uid}`
4617
- });
4618
- resetAndClosePopup();
4619
- } catch {
4620
- const errorMessage = __29("Failed to create component. Please try again.", "elementor");
4621
- notify5({
4622
- type: "error",
4623
- message: errorMessage,
4624
- id: "component-save-failed"
4625
- });
4626
- resetAndClosePopup();
4627
- }
4628
- };
4629
- const resetAndClosePopup = () => {
4630
- setElement(null);
4631
- setAnchorPosition(void 0);
4632
- };
4633
- const cancelSave = () => {
4634
- resetAndClosePopup();
4635
- trackComponentEvent({
4636
- action: "createCancelled",
4637
- source: "user",
4638
- ...eventData.current
4639
- });
4640
- };
4641
- return /* @__PURE__ */ React33.createElement(ThemeProvider4, null, /* @__PURE__ */ React33.createElement(
4642
- Popover3,
4643
- {
4644
- open: element !== null,
4645
- onClose: cancelSave,
4646
- anchorReference: "anchorPosition",
4647
- anchorPosition,
4648
- "data-testid": "create-component-form"
4649
- },
4650
- element !== null && /* @__PURE__ */ React33.createElement(
4651
- Form2,
4652
- {
4653
- initialValues: { componentName: element.elementLabel },
4654
- handleSave,
4655
- closePopup: cancelSave
4656
- }
4657
- )
4658
- ));
4659
- }
4660
- function shouldOpenForm(element, componentsCount) {
4661
- const nonAtomicElements = findNonAtomicElementsInElement(element);
4662
- if (nonAtomicElements.length > 0) {
4663
- return {
4664
- shouldOpen: false,
4665
- notification: {
4666
- type: "default",
4667
- message: __29(
4668
- "Components require atomic elements only. Remove widgets to create this component.",
4669
- "elementor"
4670
- ),
4671
- id: "non-atomic-element-save-blocked"
4672
- }
4673
- };
4674
- }
4675
- if (componentsCount >= MAX_COMPONENTS) {
4676
- return {
4677
- shouldOpen: false,
4678
- notification: {
4679
- type: "default",
4680
- /* translators: %s is the maximum number of components */
4681
- message: __29(
4682
- `You've reached the limit of %s components. Please remove an existing one to create a new component.`,
4683
- "elementor"
4684
- ).replace("%s", MAX_COMPONENTS.toString()),
4685
- id: "maximum-number-of-components-exceeded"
4686
- }
4687
- };
4688
- }
4689
- return { shouldOpen: true, notification: null };
4690
- }
4691
- var FONT_SIZE = "tiny";
4692
- var Form2 = ({
4693
- initialValues,
4694
- handleSave,
4695
- closePopup
4696
- }) => {
4697
- const { values, errors, isValid, handleChange, validateForm: validateForm2 } = useForm(initialValues);
4698
- const nameInputRef = useTextFieldAutoSelect();
4699
- const { components } = useComponents();
4700
- const existingComponentNames = useMemo3(() => {
4701
- return components?.map((component) => component.name) ?? [];
4702
- }, [components]);
4703
- const changeValidationSchema = useMemo3(
4704
- () => createBaseComponentSchema(existingComponentNames),
4705
- [existingComponentNames]
4706
- );
4707
- const submitValidationSchema = useMemo3(
4708
- () => createSubmitComponentSchema(existingComponentNames),
4709
- [existingComponentNames]
4710
- );
4711
- const handleSubmit = () => {
4712
- const { success, parsedValues } = validateForm2(submitValidationSchema);
4713
- if (success) {
4714
- handleSave(parsedValues);
4715
- }
4716
- };
4717
- const texts = {
4718
- heading: __29("Create component", "elementor"),
4719
- name: __29("Name", "elementor"),
4720
- cancel: __29("Cancel", "elementor"),
4721
- create: __29("Create", "elementor")
4722
- };
4723
- const nameInputId = "component-name";
4724
- return /* @__PURE__ */ React33.createElement(FormElement, { onSubmit: handleSubmit }, /* @__PURE__ */ React33.createElement(Stack18, { alignItems: "start", width: "268px" }, /* @__PURE__ */ React33.createElement(
4725
- Stack18,
4726
- {
4727
- direction: "row",
4728
- alignItems: "center",
4729
- py: 1,
4730
- px: 1.5,
4731
- sx: { columnGap: 0.5, borderBottom: "1px solid", borderColor: "divider", width: "100%" }
4732
- },
4733
- /* @__PURE__ */ React33.createElement(ComponentsIcon4, { fontSize: FONT_SIZE }),
4734
- /* @__PURE__ */ React33.createElement(Typography12, { variant: "caption", sx: { color: "text.primary", fontWeight: "500", lineHeight: 1 } }, texts.heading)
4735
- ), /* @__PURE__ */ React33.createElement(Grid2, { container: true, gap: 0.75, alignItems: "start", p: 1.5 }, /* @__PURE__ */ React33.createElement(Grid2, { item: true, xs: 12 }, /* @__PURE__ */ React33.createElement(FormLabel2, { htmlFor: nameInputId, size: "tiny" }, texts.name)), /* @__PURE__ */ React33.createElement(Grid2, { item: true, xs: 12 }, /* @__PURE__ */ React33.createElement(
4736
- TextField3,
4737
- {
4738
- id: nameInputId,
4739
- size: FONT_SIZE,
4740
- fullWidth: true,
4741
- value: values.componentName,
4742
- onChange: (e) => handleChange(e, "componentName", changeValidationSchema),
4743
- inputProps: { style: { color: "text.primary", fontWeight: "600" } },
4744
- error: Boolean(errors.componentName),
4745
- helperText: errors.componentName,
4746
- inputRef: nameInputRef
4747
- }
4748
- ))), /* @__PURE__ */ React33.createElement(Stack18, { direction: "row", justifyContent: "flex-end", alignSelf: "end", py: 1, px: 1.5 }, /* @__PURE__ */ React33.createElement(Button5, { onClick: closePopup, color: "secondary", variant: "text", size: "small" }, texts.cancel), /* @__PURE__ */ React33.createElement(Button5, { type: "submit", disabled: !isValid, variant: "contained", color: "primary", size: "small" }, texts.create))));
4749
- };
4750
-
4751
- // src/extended/components/edit-component/edit-component.tsx
4752
- import * as React35 from "react";
4753
- import { useEffect as useEffect6, useState as useState11 } from "react";
4754
- import { getV1DocumentsManager as getV1DocumentsManager5 } from "@elementor/editor-documents";
4755
- import { __privateListenTo as listenTo, commandEndEvent as commandEndEvent2 } from "@elementor/editor-v1-adapters";
4756
- import { __useSelector as useSelector5 } from "@elementor/store";
4757
- import { throttle as throttle2 } from "@elementor/utils";
4758
-
4759
- // src/extended/consts.ts
4760
- var OVERRIDABLE_PROP_REPLACEMENT_ID = "overridable-prop";
4761
- var COMPONENT_DOCUMENT_TYPE = "elementor_component";
4762
-
4763
- // src/extended/store/actions/reset-sanitized-components.ts
4764
- function resetSanitizedComponents() {
4765
- componentsActions.resetSanitizedComponents();
4766
- }
4767
-
4768
- // src/extended/store/actions/update-current-component.ts
4769
- function updateCurrentComponent(params) {
4770
- componentsActions.setPath(params.path);
4771
- componentsActions.setCurrentComponentId(params.currentComponentId);
4772
- }
4773
-
4774
- // src/extended/components/edit-component/component-modal.tsx
4775
- import * as React34 from "react";
4776
- import { useEffect as useEffect5 } from "react";
4777
- import { createPortal } from "react-dom";
4778
- import { __ as __30 } from "@wordpress/i18n";
4779
-
4780
- // src/extended/components/edit-component/use-canvas-document.ts
4781
- import {
4782
- __privateUseListenTo as useListenTo,
4783
- commandEndEvent,
4784
- getCanvasIframeDocument
4785
- } from "@elementor/editor-v1-adapters";
4786
- function useCanvasDocument() {
4787
- return useListenTo(commandEndEvent("editor/documents/attach-preview"), () => getCanvasIframeDocument());
4788
- }
4789
-
4790
- // src/extended/components/edit-component/use-element-rect.ts
4791
- import { useEffect as useEffect4, useState as useState10 } from "react";
4792
- import { throttle } from "@elementor/utils";
4793
- function useElementRect(element) {
4794
- const [rect, setRect] = useState10(new DOMRect(0, 0, 0, 0));
4795
- const onChange = throttle(
4796
- () => {
4797
- setRect(element?.getBoundingClientRect() ?? new DOMRect(0, 0, 0, 0));
4798
- },
4799
- 20,
4800
- true
4801
- );
4802
- useScrollListener({ element, onChange });
4803
- useResizeListener({ element, onChange });
4804
- useMutationsListener({ element, onChange });
4805
- useEffect4(
4806
- () => () => {
4807
- onChange.cancel();
4808
- },
4809
- [onChange]
4810
- );
4811
- return rect;
4812
- }
4813
- function useScrollListener({ element, onChange }) {
4814
- useEffect4(() => {
4815
- if (!element) {
4816
- return;
4817
- }
4818
- const win = element.ownerDocument?.defaultView;
4819
- win?.addEventListener("scroll", onChange, { passive: true });
4820
- return () => {
4821
- win?.removeEventListener("scroll", onChange);
4822
- };
4823
- }, [element, onChange]);
4824
- }
4825
- function useResizeListener({ element, onChange }) {
4826
- useEffect4(() => {
4827
- if (!element) {
4828
- return;
4829
- }
4830
- const resizeObserver = new ResizeObserver(onChange);
4831
- resizeObserver.observe(element);
4832
- const win = element.ownerDocument?.defaultView;
4833
- win?.addEventListener("resize", onChange, { passive: true });
4834
- return () => {
4835
- resizeObserver.disconnect();
4836
- win?.removeEventListener("resize", onChange);
4837
- };
4838
- }, [element, onChange]);
4839
- }
4840
- function useMutationsListener({ element, onChange }) {
4841
- useEffect4(() => {
4842
- if (!element) {
4843
- return;
4844
- }
4845
- const mutationObserver = new MutationObserver(onChange);
4846
- mutationObserver.observe(element, { childList: true, subtree: true });
4847
- return () => {
4848
- mutationObserver.disconnect();
4849
- };
4850
- }, [element, onChange]);
4851
- }
4852
-
4853
- // src/extended/components/edit-component/component-modal.tsx
4854
- function ComponentModal({ topLevelElementDom, onClose }) {
4855
- const canvasDocument = useCanvasDocument();
4856
- useEffect5(() => {
4857
- const handleEsc = (event) => {
4858
- if (event.key === "Escape") {
4859
- onClose();
4860
- }
4861
- };
4862
- canvasDocument?.body.addEventListener("keydown", handleEsc);
4863
- return () => {
4864
- canvasDocument?.body.removeEventListener("keydown", handleEsc);
4865
- };
4866
- }, [canvasDocument, onClose]);
4867
- if (!canvasDocument?.body) {
4868
- return null;
4869
- }
4870
- return createPortal(
4871
- /* @__PURE__ */ React34.createElement(React34.Fragment, null, /* @__PURE__ */ React34.createElement(BlockEditPage, null), /* @__PURE__ */ React34.createElement(Backdrop, { canvas: canvasDocument, element: topLevelElementDom, onClose })),
4872
- canvasDocument.body
4873
- );
4874
- }
4875
- function Backdrop({
4876
- canvas,
4877
- element,
4878
- onClose
4879
- }) {
4880
- const rect = useElementRect(element);
4881
- const clipPath = element ? getRectPath(rect, canvas.defaultView) : void 0;
4882
- const backdropStyle = {
4883
- position: "fixed",
4884
- top: 0,
4885
- left: 0,
4886
- width: "100vw",
4887
- height: "100vh",
4888
- backgroundColor: "rgba(0, 0, 0, 0.5)",
4889
- zIndex: 999,
4890
- pointerEvents: "painted",
4891
- cursor: "pointer",
4892
- clipPath
4893
- };
4894
- const handleKeyDown = (event) => {
4895
- if (event.key === "Enter" || event.key === " ") {
4896
- event.preventDefault();
4897
- onClose();
4898
- }
4899
- };
4900
- return /* @__PURE__ */ React34.createElement(
4901
- "div",
4902
- {
4903
- style: backdropStyle,
4904
- onClick: onClose,
4905
- onKeyDown: handleKeyDown,
4906
- role: "button",
4907
- tabIndex: 0,
4908
- "aria-label": __30("Exit component editing mode", "elementor")
4909
- }
4910
- );
4911
- }
4912
- function getRectPath(rect, viewport) {
4913
- const { x, y, width, height } = rect;
4914
- const { innerWidth: vw, innerHeight: vh } = viewport;
4915
- const path = `path(evenodd, 'M 0 0
4916
- L ${vw} 0
4917
- L ${vw} ${vh}
4918
- L 0 ${vh}
4919
- Z
4920
- M ${x} ${y}
4921
- L ${x + width} ${y}
4922
- L ${x + width} ${y + height}
4923
- L ${x} ${y + height}
4924
- L ${x} ${y}
4925
- Z'
4926
- )`;
4927
- return path.replace(/\s{2,}/g, " ");
4928
- }
4929
- function BlockEditPage() {
4930
- const blockV3DocumentHandlesStyles = `
4931
- .elementor-editor-active {
4932
- & .elementor-section-wrap.ui-sortable {
4933
- display: contents;
4934
- }
4935
-
4936
- & *[data-editable-elementor-document]:not(.elementor-edit-mode):hover {
4937
- & .elementor-document-handle:not(.elementor-document-save-back-handle) {
4938
- display: none;
4939
-
4940
- &::before,
4941
- & .elementor-document-handle__inner {
4942
- display: none;
4943
- }
4944
- }
4945
- }
4946
- }
4947
- `;
4948
- return /* @__PURE__ */ React34.createElement("style", { "data-e-style-id": "e-block-v3-document-handles-styles" }, blockV3DocumentHandlesStyles);
4949
- }
4950
-
4951
- // src/extended/components/edit-component/edit-component.tsx
4952
- function EditComponent() {
4953
- const currentComponentId = useCurrentComponentId();
4954
- useHandleDocumentSwitches();
4955
- const navigateBack = useNavigateBack();
4956
- const onClose = throttle2(navigateBack, 100);
4957
- const topLevelElementDom = useComponentDOMElement(currentComponentId ?? void 0);
4958
- if (!currentComponentId) {
4959
- return null;
4960
- }
4961
- return /* @__PURE__ */ React35.createElement(ComponentModal, { topLevelElementDom, onClose });
4962
- }
4963
- function useHandleDocumentSwitches() {
4964
- const documentsManager = getV1DocumentsManager5();
4965
- const currentComponentId = useCurrentComponentId();
4966
- const path = useSelector5(selectPath);
4967
- useEffect6(() => {
4968
- return listenTo(commandEndEvent2("editor/documents/open"), () => {
4969
- const nextDocument = documentsManager.getCurrent();
4970
- if (nextDocument.id === currentComponentId) {
4971
- return;
4972
- }
4973
- if (currentComponentId) {
4974
- apiClient.unlockComponent(currentComponentId);
4975
- }
4976
- resetSanitizedComponents();
4977
- const isComponent2 = nextDocument.config.type === COMPONENT_DOCUMENT_TYPE;
4978
- if (!isComponent2) {
4979
- updateCurrentComponent({ path: [], currentComponentId: null });
4980
- return;
4981
- }
4982
- updateCurrentComponent({
4983
- path: getUpdatedComponentPath(path, nextDocument),
4984
- currentComponentId: nextDocument.id
4985
- });
4986
- });
4987
- }, [path, documentsManager, currentComponentId]);
4988
- }
4989
- function getUpdatedComponentPath(path, nextDocument) {
4990
- const componentIndex = path.findIndex(({ componentId }) => componentId === nextDocument.id);
4991
- if (componentIndex >= 0) {
4992
- return path.slice(0, componentIndex + 1);
4993
- }
4994
- const instanceId = nextDocument?.container.view?.el?.dataset.id;
4995
- const instanceTitle = getInstanceTitle(instanceId, path);
4996
- return [
4997
- ...path,
4998
- {
4999
- instanceId,
5000
- instanceTitle,
5001
- componentId: nextDocument.id
5002
- }
5003
- ];
5004
- }
5005
- function getInstanceTitle(instanceId, path) {
5006
- if (!instanceId) {
5007
- return void 0;
5008
- }
5009
- const documentsManager = getV1DocumentsManager5();
5010
- const parentDocId = path.at(-1)?.componentId ?? documentsManager.getInitialId();
5011
- const parentDoc = documentsManager.get(parentDocId);
5012
- const parentContainer = parentDoc?.container;
5013
- const widget = parentContainer?.children?.findRecursive?.(
5014
- (container) => container.id === instanceId
5015
- );
5016
- const editorSettings = widget?.model?.get?.("editor_settings");
5017
- return editorSettings?.title;
5018
- }
5019
- function useComponentDOMElement(id2) {
5020
- const { componentContainerDomElement, topLevelElementDom } = getComponentDOMElements(id2);
5021
- const [currentElementDom, setCurrentElementDom] = useState11(topLevelElementDom);
5022
- useEffect6(() => {
5023
- setCurrentElementDom(topLevelElementDom);
5024
- }, [topLevelElementDom]);
5025
- useEffect6(() => {
5026
- if (!componentContainerDomElement) {
5027
- return;
5028
- }
5029
- const mutationObserver = new MutationObserver(() => {
5030
- const newElementDom = componentContainerDomElement.children[0];
5031
- setCurrentElementDom(newElementDom);
5032
- });
5033
- mutationObserver.observe(componentContainerDomElement, { childList: true });
5034
- return () => {
5035
- mutationObserver.disconnect();
5036
- };
5037
- }, [componentContainerDomElement]);
5038
- return currentElementDom;
5039
- }
5040
- function getComponentDOMElements(id2) {
5041
- if (!id2) {
5042
- return { componentContainerDomElement: null, topLevelElementDom: null };
5043
- }
5044
- const documentsManager = getV1DocumentsManager5();
5045
- const currentComponent = documentsManager.get(id2);
5046
- const componentContainer = currentComponent?.container;
5047
- const componentContainerDomElement = componentContainer?.view?.el?.children?.[0] ?? null;
5048
- const topLevelElementDom = componentContainerDomElement?.children[0] ?? null;
5049
- return { componentContainerDomElement, topLevelElementDom };
5050
- }
5051
-
5052
- // src/extended/components/instance-editing-panel/instance-editing-panel.tsx
5053
- import * as React36 from "react";
5054
- import { PencilIcon as PencilIcon3 } from "@elementor/icons";
5055
- import { Box as Box16 } from "@elementor/ui";
5056
- import { __ as __31 } from "@wordpress/i18n";
5057
- function ExtendedInstanceEditingPanel() {
5058
- const { canEdit } = useComponentsPermissions();
5059
- const data = useInstancePanelData();
5060
- if (!data) {
5061
- return null;
5062
- }
5063
- const { componentId, component, overrides, overridableProps, groups, isEmpty, componentInstanceId } = data;
5064
- const panelTitle = __31("Edit %s", "elementor").replace("%s", component.name);
5065
- const handleEditComponent = () => switchToComponent(componentId, componentInstanceId);
5066
- return /* @__PURE__ */ React36.createElement(Box16, { "data-testid": "instance-editing-panel" }, /* @__PURE__ */ React36.createElement(
5067
- ComponentInstanceProvider,
5068
- {
5069
- componentId,
5070
- overrides,
5071
- overridableProps
5072
- },
5073
- /* @__PURE__ */ React36.createElement(
5074
- InstancePanelHeader,
5075
- {
5076
- componentName: component.name,
5077
- actions: canEdit ? /* @__PURE__ */ React36.createElement(
5078
- EditComponentAction,
5079
- {
5080
- label: panelTitle,
5081
- onClick: handleEditComponent,
5082
- icon: PencilIcon3
5083
- }
5084
- ) : void 0
5085
- }
5086
- ),
5087
- /* @__PURE__ */ React36.createElement(
5088
- InstancePanelBody,
5089
- {
5090
- groups,
5091
- isEmpty,
5092
- emptyState: /* @__PURE__ */ React36.createElement(EmptyState2, { onEditComponent: canEdit ? handleEditComponent : void 0 }),
5093
- componentInstanceId
5094
- }
5095
- )
5096
- ));
5097
- }
5098
-
5099
- // src/extended/components/overridable-props/overridable-prop-control.tsx
5100
- import * as React37 from "react";
5101
- import {
5102
- ControlReplacementsProvider as ControlReplacementsProvider2,
5103
- getControlReplacements as getControlReplacements2,
5104
- PropKeyProvider as PropKeyProvider2,
5105
- PropProvider as PropProvider2,
5106
- useBoundProp as useBoundProp2,
5107
- useControlReplacement
5108
- } from "@elementor/editor-controls";
5109
- import { createTopLevelObjectType as createTopLevelObjectType2, useElement as useElement3 } from "@elementor/editor-editing-panel";
5110
- function OverridablePropControl({
5111
- OriginalControl: OriginalControl2,
5112
- ...props
5113
- }) {
5114
- const { elementType } = useElement3();
5115
- const { value, bind, setValue, placeholder, ...propContext } = useBoundProp2(componentOverridablePropTypeUtil);
5116
- const componentId = useCurrentComponentId();
5117
- const overridableProps = useOverridableProps(componentId);
5118
- const filteredReplacements = getControlReplacements2().filter(
5119
- (r) => !r.id || r.id !== OVERRIDABLE_PROP_REPLACEMENT_ID
5120
- );
5121
- if (!componentId) {
5122
- return null;
5123
- }
5124
- if (!value?.override_key) {
5125
- throw new Error("Override key is required");
5126
- }
5127
- const isComponentInstance2 = elementType.key === "e-component";
5128
- const overridablePropData = overridableProps?.props?.[value.override_key];
5129
- const setOverridableValue = (newValue) => {
5130
- const propValue2 = {
5131
- ...value,
5132
- origin_value: newValue[bind]
5133
- };
5134
- setValue(propValue2);
5135
- if (!isComponentInstance2) {
5136
- updateOverridableProp(componentId, propValue2, overridablePropData?.originPropFields);
5137
- }
5138
- };
5139
- const defaultPropType = elementType.propsSchema[bind];
5140
- const overridePropType = overridablePropData ? getPropTypeForComponentOverride(overridablePropData) : void 0;
5141
- const resolvedPropType = overridePropType ?? defaultPropType;
5142
- if (!resolvedPropType) {
5143
- return null;
5144
- }
5145
- const propType = createTopLevelObjectType2({
5146
- schema: {
5147
- [bind]: resolvedPropType
5148
- }
5149
- });
5150
- const propValue = isComponentInstance2 ? (value.origin_value?.value).override_value : value.origin_value;
5151
- const objectPlaceholder = placeholder ? { [bind]: placeholder } : void 0;
5152
- return /* @__PURE__ */ React37.createElement(OverridablePropProvider, { value }, /* @__PURE__ */ React37.createElement(
5153
- PropProvider2,
5154
- {
5155
- ...propContext,
5156
- propType,
5157
- setValue: setOverridableValue,
5158
- value: {
5159
- [bind]: propValue
5160
- },
5161
- placeholder: objectPlaceholder
5162
- },
5163
- /* @__PURE__ */ React37.createElement(PropKeyProvider2, { bind }, /* @__PURE__ */ React37.createElement(ControlReplacementsProvider2, { replacements: filteredReplacements }, /* @__PURE__ */ React37.createElement(ControlWithReplacements, { OriginalControl: OriginalControl2, props })))
5164
- ));
5165
- }
5166
- function ControlWithReplacements({
5167
- OriginalControl: OriginalControl2,
5168
- props
5169
- }) {
5170
- const { ControlToRender, isReplaced } = useControlReplacement(OriginalControl2);
5171
- if (isReplaced) {
5172
- const ReplacementControl = ControlToRender;
5173
- return /* @__PURE__ */ React37.createElement(ReplacementControl, { ...props, OriginalControl: OriginalControl2 });
5174
- }
5175
- return /* @__PURE__ */ React37.createElement(OriginalControl2, { ...props });
5176
- }
5177
-
5178
- // src/extended/components/overridable-props/overridable-prop-indicator.tsx
5179
- import * as React39 from "react";
5180
- import { useBoundProp as useBoundProp3 } from "@elementor/editor-controls";
5181
- import { useElement as useElement4 } from "@elementor/editor-editing-panel";
5182
- import { getWidgetsCache as getWidgetsCache3 } from "@elementor/editor-elements";
5183
- import { bindPopover as bindPopover2, bindTrigger as bindTrigger4, Popover as Popover4, Tooltip as Tooltip6, usePopupState as usePopupState4 } from "@elementor/ui";
5184
- import { __ as __33 } from "@wordpress/i18n";
5185
-
5186
- // src/extended/store/actions/set-overridable-prop.ts
5187
- import { generateUniqueId as generateUniqueId4 } from "@elementor/utils";
5188
- function setOverridableProp({
5189
- componentId,
5190
- overrideKey,
5191
- elementId,
5192
- label,
5193
- groupId,
5194
- propKey,
5195
- elType,
5196
- widgetType,
5197
- originValue,
5198
- originPropFields,
5199
- source
5200
- }) {
5201
- const overridableProps = componentsSelectors.getOverridableProps(componentId);
5202
- if (!overridableProps) {
5203
- return;
5204
- }
5205
- const existingOverridableProp = overrideKey ? overridableProps.props[overrideKey] : null;
5206
- const duplicatedTargetProps = Object.values(overridableProps.props).filter(
5207
- (prop) => prop.elementId === elementId && prop.propKey === propKey && prop !== existingOverridableProp
5208
- );
5209
- const { groups: groupsAfterResolve, groupId: currentGroupId } = resolveOrCreateGroup(
5210
- overridableProps.groups,
5211
- groupId || existingOverridableProp?.groupId || void 0
5212
- );
5213
- const overridableProp = {
5214
- overrideKey: existingOverridableProp?.overrideKey || generateUniqueId4("prop"),
5215
- label,
5216
- elementId,
5217
- propKey,
5218
- widgetType,
5219
- elType,
5220
- originValue,
5221
- groupId: currentGroupId,
5222
- originPropFields
5223
- };
5224
- const stateAfterRemovingDuplicates = removePropsFromState(
5225
- { ...overridableProps, groups: groupsAfterResolve },
5226
- duplicatedTargetProps
5227
- );
5228
- const props = {
5229
- ...stateAfterRemovingDuplicates.props,
5230
- [overridableProp.overrideKey]: overridableProp
5231
- };
5232
- let groups = addPropToGroup(stateAfterRemovingDuplicates.groups, currentGroupId, overridableProp.overrideKey);
5233
- groups = ensureGroupInOrder(groups, currentGroupId);
5234
- const isChangingGroups = existingOverridableProp && existingOverridableProp.groupId !== currentGroupId;
5235
- if (isChangingGroups) {
5236
- groups = removePropFromGroup(groups, existingOverridableProp.groupId, overridableProp.overrideKey);
5237
- }
5238
- componentsActions.setOverridableProps(componentId, { props, groups });
5239
- const isNewProperty = !existingOverridableProp;
5240
- if (isNewProperty) {
5241
- const currentComponent = componentsSelectors.getCurrentComponent();
5242
- trackComponentEvent({
5243
- action: "propertyExposed",
5244
- source,
5245
- component_uid: currentComponent?.uid,
5246
- property_id: overridableProp.overrideKey,
5247
- property_path: propKey,
5248
- property_name: label,
5249
- element_type: widgetType ?? elType
5250
- });
5251
- }
5252
- return overridableProp;
5253
- }
5254
-
5255
- // src/extended/components/overridable-props/indicator.tsx
5256
- import * as React38 from "react";
5257
- import { forwardRef as forwardRef3 } from "react";
5258
- import { CheckIcon, PlusIcon } from "@elementor/icons";
5259
- import { Box as Box17, styled as styled4 } from "@elementor/ui";
5260
- import { __ as __32 } from "@wordpress/i18n";
5261
- var SIZE2 = "tiny";
5262
- var IconContainer = styled4(Box17)`
5263
- pointer-events: none;
5264
- opacity: 0;
5265
- transition: opacity 0.2s ease-in-out;
5266
-
5267
- & > svg {
5268
- position: absolute;
5269
- top: 50%;
5270
- left: 50%;
5271
- transform: translate( -50%, -50% );
5272
- width: 10px;
5273
- height: 10px;
5274
- fill: ${({ theme }) => theme.palette.primary.contrastText};
5275
- stroke: ${({ theme }) => theme.palette.primary.contrastText};
5276
- stroke-width: 2px;
5277
- }
5278
- `;
5279
- var Content = styled4(Box17)`
5280
- position: relative;
5281
- display: flex;
5282
- align-items: center;
5283
- justify-content: center;
5284
- cursor: pointer;
5285
- width: 16px;
5286
- height: 16px;
5287
- margin-inline: ${({ theme }) => theme.spacing(0.5)};
5288
-
5289
- &:before {
5290
- content: '';
5291
- display: block;
5292
- position: absolute;
5293
- top: 50%;
5294
- left: 50%;
5295
- transform: translate( -50%, -50% ) rotate( 45deg );
5296
- width: 5px;
5297
- height: 5px;
5298
- border-radius: 1px;
5299
- background-color: ${({ theme }) => theme.palette.primary.main};
5300
- transition: all 0.1s ease-in-out;
5301
- }
5302
-
5303
- &:hover,
5304
- &.enlarged {
5305
- &:before {
5306
- width: 12px;
5307
- height: 12px;
5308
- border-radius: 2px;
5309
- }
5310
-
5311
- .icon {
5312
- opacity: 1;
5313
- }
5314
- }
5315
- `;
5316
- var Indicator2 = forwardRef3(({ isOpen, isOverridable, ...props }, ref) => /* @__PURE__ */ React38.createElement(
5317
- Content,
5318
- {
5319
- role: "button",
5320
- ref,
5321
- ...props,
5322
- className: isOpen || isOverridable ? "enlarged" : "",
5323
- "aria-label": isOverridable ? __32("Overridable property", "elementor") : __32("Make prop overridable", "elementor")
5324
- },
5325
- /* @__PURE__ */ React38.createElement(IconContainer, { className: "icon" }, isOverridable ? /* @__PURE__ */ React38.createElement(CheckIcon, { fontSize: SIZE2 }) : /* @__PURE__ */ React38.createElement(PlusIcon, { fontSize: SIZE2 }))
5326
- ));
5327
-
5328
- // src/extended/components/overridable-props/overridable-prop-indicator.tsx
5329
- function OverridablePropIndicator() {
5330
- const { propType } = useBoundProp3();
5331
- const componentId = useCurrentComponentId();
5332
- const overridableProps = useSanitizeOverridableProps(componentId);
5333
- if (!isPropAllowed(propType) || !componentId || !overridableProps) {
5334
- return null;
5335
- }
5336
- return /* @__PURE__ */ React39.createElement(Content2, { componentId, overridableProps });
5337
- }
5338
- function Content2({ componentId, overridableProps }) {
5339
- const {
5340
- element: { id: elementId },
5341
- elementType
5342
- } = useElement4();
5343
- const { value, bind, propType } = useBoundProp3();
5344
- const contextOverridableValue = useOverridablePropValue();
5345
- const componentInstanceElement = useComponentInstanceElement();
5346
- const { value: boundPropOverridableValue, setValue: setOverridableValue } = useBoundProp3(
5347
- componentOverridablePropTypeUtil
5348
- );
5349
- const overridableValue = boundPropOverridableValue ?? contextOverridableValue;
5350
- const popupState = usePopupState4({
5351
- variant: "popover"
5352
- });
5353
- const triggerProps = bindTrigger4(popupState);
5354
- const popoverProps = bindPopover2(popupState);
5355
- const { elType } = getWidgetsCache3()?.[elementType.key] ?? { elType: "widget" };
5356
- const handleSubmit = ({ label, group }) => {
5357
- const propTypeDefault = propType.default ?? {};
5358
- const originValue = resolveOverridePropValue(overridableValue?.origin_value) ?? value ?? propTypeDefault;
5359
- const matchingOverridableProp = overridableValue ? overridableProps?.props?.[overridableValue.override_key] : void 0;
5360
- const overridablePropConfig = setOverridableProp({
5361
- componentId,
5362
- overrideKey: overridableValue?.override_key ?? null,
5363
- elementId: componentInstanceElement?.element.id ?? elementId,
5364
- label,
5365
- groupId: group,
5366
- propKey: bind,
5367
- elType: elType ?? "widget",
5368
- widgetType: componentInstanceElement?.elementType.key ?? elementType.key,
5369
- originValue,
5370
- originPropFields: matchingOverridableProp?.originPropFields,
5371
- source: "user"
5372
- });
5373
- if (!overridableValue && overridablePropConfig) {
5374
- setOverridableValue({
5375
- override_key: overridablePropConfig.overrideKey,
5376
- origin_value: originValue
5377
- });
5378
- }
5379
- popupState.close();
5380
- };
5381
- const overridableConfig = overridableValue ? getOverridableProp({ componentId, overrideKey: overridableValue.override_key }) : void 0;
5382
- return /* @__PURE__ */ React39.createElement(React39.Fragment, null, /* @__PURE__ */ React39.createElement(Tooltip6, { placement: "top", title: __33("Override Property", "elementor") }, /* @__PURE__ */ React39.createElement(Indicator2, { ...triggerProps, isOpen: !!popoverProps.open, isOverridable: !!overridableValue })), /* @__PURE__ */ React39.createElement(
5383
- Popover4,
5384
- {
5385
- disableScrollLock: true,
5386
- anchorOrigin: {
5387
- vertical: "bottom",
5388
- horizontal: "right"
5389
- },
5390
- transformOrigin: {
5391
- vertical: "top",
5392
- horizontal: "right"
5393
- },
5394
- PaperProps: {
5395
- sx: { my: 2.5 }
5396
- },
5397
- ...popoverProps
5398
- },
5399
- /* @__PURE__ */ React39.createElement(
5400
- OverridablePropForm,
5401
- {
5402
- onSubmit: handleSubmit,
5403
- groups: overridableProps?.groups.order.map((groupId) => ({
5404
- value: groupId,
5405
- label: overridableProps.groups.items[groupId].label
5406
- })),
5407
- existingLabels: Object.values(overridableProps?.props ?? {}).map((prop) => prop.label),
5408
- currentValue: overridableConfig
5409
- }
5410
- )
5411
- ));
5412
- }
5413
- function isPropAllowed(propType) {
5414
- return propType.meta.overridable !== false;
5415
- }
5416
-
5417
- // src/extended/mcp/index.ts
5418
- import { getMCPByDomain as getMCPByDomain2 } from "@elementor/editor-mcp";
5419
-
5420
- // src/extended/mcp/save-as-component-tool.ts
5421
- import { DOCUMENT_STRUCTURE_URI, WIDGET_SCHEMA_URI } from "@elementor/editor-canvas";
5422
- import { getContainer as getContainer6, getElementType as getElementType4, getWidgetsCache as getWidgetsCache4 } from "@elementor/editor-elements";
5423
- import { getMCPByDomain, toolPrompts } from "@elementor/editor-mcp";
5424
- import { AxiosError } from "@elementor/http-client";
5425
- import { z as z6 } from "@elementor/schema";
5426
- import { generateUniqueId as generateUniqueId5 } from "@elementor/utils";
5427
- var InputSchema = {
5428
- element_id: z6.string().describe(
5429
- 'The unique identifier of the element to save as a component. Use the "list-elements" tool to find available element IDs in the current document.'
5430
- ),
5431
- component_name: z6.string().describe("The name for the new component. Should be descriptive and unique among existing components."),
5432
- overridable_props: z6.object({
5433
- props: z6.record(
5434
- z6.object({
5435
- elementId: z6.string().describe("The id of the child element that you want to override its settings"),
5436
- propKey: z6.string().describe(
5437
- 'The property key of the child element that you want to override its settings (e.g., "text", "url", "tag"). To get the available propKeys for an element, use the "get-element-type-config" tool.'
5438
- ),
5439
- label: z6.string().describe(
5440
- 'A unique, user-friendly display name for this property (e.g., "Hero Headline", "CTA Button Text"). Must be unique within the same component.'
5441
- ),
5442
- group: z6.string().optional().describe("Non unique, optional property grouping")
5443
- })
5444
- )
5445
- }).optional().describe(
5446
- 'Overridable properties configuration. Specify which CHILD element properties can be customized. Only elementId and propKey are required; To get the available propKeys for a child element you must use the "get-element-type-config" tool.'
5447
- ),
5448
- groups: z6.array(z6.string()).describe("Property Groups, by order, unique values").optional()
5449
- };
5450
- var OutputSchema = {
5451
- message: z6.string().optional().describe("Additional information about the operation result"),
5452
- component_uid: z6.string().optional().describe("The unique identifier of the newly created component (only present on success)")
5453
- };
5454
- var ERROR_MESSAGES3 = {
5455
- ELEMENT_NOT_FOUND: "Element not found. Use 'list-elements' to get valid element IDs.",
5456
- ELEMENT_NOT_ONE_OF_TYPES: (validTypes) => `Element is not one of the following types: ${validTypes.join(", ")}`,
5457
- ELEMENT_IS_LOCKED: "Cannot save a locked element as a component."
5458
- };
5459
- var handleSaveAsComponent = async (params) => {
5460
- const {
5461
- groups = [],
5462
- element_id: elementId,
5463
- component_name: componentName,
5464
- overridable_props: overridablePropsInput
5465
- } = params;
5466
- const validElementTypes = getValidElementTypes();
5467
- const container = getContainer6(elementId);
5468
- if (!container) {
5469
- throw new Error(ERROR_MESSAGES3.ELEMENT_NOT_FOUND);
5470
- }
5471
- const elType = container.model.get("elType");
5472
- if (!validElementTypes.includes(elType)) {
5473
- throw new Error(ERROR_MESSAGES3.ELEMENT_NOT_ONE_OF_TYPES(validElementTypes));
5474
- }
5475
- const element = container.model.toJSON({ remove: ["default"] });
5476
- if (element?.isLocked) {
5477
- throw new Error(ERROR_MESSAGES3.ELEMENT_IS_LOCKED);
5478
- }
5479
- const groupsWithDefaultGroup = groups.indexOf("Default") >= 0 ? [...groups] : ["Default", ...groups];
5480
- const propertyGroups = groupsWithDefaultGroup.map((groupName) => ({
5481
- id: generateUniqueId5("group"),
5482
- label: groupName,
5483
- props: []
5484
- }));
5485
- const overridableProps = overridablePropsInput ? enrichOverridableProps(overridablePropsInput, element, propertyGroups) : void 0;
5486
- if (overridableProps) {
5487
- updateElementDataWithOverridableProps(element, overridableProps);
5488
- }
5489
- const uid = generateUniqueId5("component");
5490
- try {
5491
- await apiClient.validate({
5492
- items: [
5493
- { uid, title: componentName, elements: [element], settings: { overridable_props: overridableProps } }
5494
- ]
5495
- });
5496
- } catch (error) {
5497
- if (error instanceof AxiosError) {
5498
- throw new Error(error.response?.data.messge);
5499
- }
5500
- throw new Error("Unknown error");
5501
- }
5502
- await createUnpublishedComponent({
5503
- name: componentName,
5504
- element,
5505
- eventData: null,
5506
- uid,
5507
- overridableProps,
5508
- source: "mcp_tool"
5509
- });
5510
- return {
5511
- status: "ok",
5512
- message: `Component "${componentName}" created successfully.`,
5513
- component_uid: uid
5514
- };
5515
- };
5516
- function enrichOverridableProps(input, rootElement, propertGroups) {
5517
- const enrichedProps = {};
5518
- const enrichedGroups = {};
5519
- const defaultGroup = propertGroups.find((g) => g.label === "Default");
5520
- if (!defaultGroup) {
5521
- throw new Error("Internal mcp error: could not generate default group");
5522
- }
5523
- Object.entries(input.props).forEach(([, prop]) => {
5524
- const { elementId, propKey, label, group = "Default" } = prop;
5525
- const targetGroup = propertGroups.find((g) => g.label === group) || defaultGroup;
5526
- const targetGroupId = targetGroup.id;
5527
- const element = findElementById(rootElement, elementId);
5528
- if (!element) {
5529
- throw new Error(`Element with ID "${elementId}" not found in component`);
5530
- }
5531
- const elType = element.elType;
5532
- const widgetType = element.widgetType || element.elType;
5533
- const elementType = getElementType4(widgetType);
5534
- if (!elementType) {
5535
- throw new Error(
5536
- `Element type "${widgetType}" is not atomic or does not have a settings schema. Cannot expose property "${propKey}" for element "${elementId}".`
5537
- );
5538
- }
5539
- if (!elementType.propsSchema[propKey]) {
5540
- const availableProps = Object.keys(elementType.propsSchema).join(", ");
5541
- throw new Error(
5542
- `Property "${propKey}" does not exist in element "${elementId}" (type: ${widgetType}). Available properties: ${availableProps}`
5543
- );
5544
- }
5545
- const overrideKey = generateUniqueId5("prop");
5546
- const originValue = element.settings?.[propKey] ? element.settings[propKey] : elementType.propsSchema[propKey].default ?? null;
5547
- if (!enrichedGroups[targetGroupId]) {
5548
- enrichedGroups[targetGroupId] = {
5549
- id: targetGroupId,
5550
- label: targetGroup.label,
5551
- props: []
5552
- };
5553
- }
5554
- enrichedGroups[targetGroupId].props.push(overrideKey);
5555
- enrichedProps[overrideKey] = {
5556
- overrideKey,
5557
- label,
5558
- elementId,
5559
- propKey,
5560
- elType,
5561
- widgetType,
5562
- originValue,
5563
- groupId: targetGroupId
5564
- };
5565
- });
5566
- return {
5567
- props: enrichedProps,
5568
- groups: {
5569
- items: enrichedGroups,
5570
- order: [defaultGroup.id]
5571
- }
5572
- };
5573
- }
5574
- function updateElementDataWithOverridableProps(rootElement, overridableProps) {
5575
- Object.values(overridableProps.props).forEach((prop) => {
5576
- const element = findElementById(rootElement, prop.elementId);
5577
- if (!element || !element.settings) {
5578
- return;
5579
- }
5580
- element.settings[prop.propKey] = {
5581
- $$type: "overridable",
5582
- value: {
5583
- override_key: prop.overrideKey,
5584
- origin_value: prop.originValue
5585
- }
5586
- };
5587
- });
5588
- }
5589
- function findElementById(root, targetId) {
5590
- if (root.id === targetId) {
5591
- return root;
5592
- }
5593
- if (root.elements) {
5594
- for (const child of root.elements) {
5595
- const found = findElementById(child, targetId);
5596
- if (found) {
5597
- return found;
5598
- }
5599
- }
5600
- }
5601
- return null;
5602
- }
5603
- function getValidElementTypes() {
5604
- const types = getWidgetsCache4();
5605
- if (!types) {
5606
- return [];
5607
- }
5608
- return Object.entries(types).reduce((acc, [type, value]) => {
5609
- if (!value.atomic_props_schema || !value.show_in_panel || value.elType === "widget") {
5610
- return acc;
5611
- }
5612
- acc.push(type);
5613
- return acc;
5614
- }, []);
5615
- }
5616
- var generatePrompt = () => {
5617
- const saveAsComponentPrompt = toolPrompts("save-as-component");
5618
- saveAsComponentPrompt.description(`
5619
- Save an existing element as a reusable component in the Elementor editor.
5620
-
5621
- # When to use this tool
5622
- Use this tool when the user wants to:
5623
- - Create a reusable component from an existing element structure
5624
- - Make specific child element properties customizable in component instances
5625
- - Build a library of reusable design patterns
5626
-
5627
- # When NOT to use this tool
5628
- - Element is already a component (widgetType: 'e-component')
5629
- - Element is locked
5630
- - Element is not an atomic element (atomic_props_schema is not defined)
5631
- - Element elType is a 'widget'
5632
-
5633
- # **CRITICAL - REQUIRED RESOURCES (Must read before using this tool)**
5634
- 1. [${DOCUMENT_STRUCTURE_URI}]
5635
- **MANDATORY** - Required to understand the document structure and identify child elements for overridable properties.
5636
- Use this resource to find element IDs and understand the element hierarchy.
5637
-
5638
- 2. [${WIDGET_SCHEMA_URI}]
5639
- **MANDATORY** - Required to understand which properties are available for each widget type.
5640
- Use this to identify available propKeys in the atomic_props_schema for child elements.
5641
-
5642
- # Instructions - MUST FOLLOW IN ORDER
5643
- ## Step 1: Identify the Target Element
5644
- 1. Read the [${DOCUMENT_STRUCTURE_URI}] resource to understand the document structure
5645
- 2. Locate the element you want to save as a component by its element_id
5646
- 3. Verify the element type is a valid element type
5647
- 4. Ensure the element is not locked and is not already a component
5648
-
5649
- ## Step 2: Define Overridable Properties
5650
- Do this step to make child element properties customizable.
5651
- Skip that step ONLY if the user explicitly requests to not make any properties customizable.
5652
-
5653
- 1. **Identify Child Elements**
5654
- - Use the [${DOCUMENT_STRUCTURE_URI}] resource to find all child elements
5655
- - Note the elementId and widgetType/elType of each child element you want to customize
5656
-
5657
- 2. **Find Available Properties**
5658
- - Use the [${WIDGET_SCHEMA_URI}] resource to find the child element's widget type schema
5659
- - Review the atomic_props_schema to find available propKeys (ONLY use top-level props)
5660
- - Common propKeys include: "text", "url", "tag", "size", etc.
5661
- - Use only the top level properties, do not use nested properties.
5662
-
5663
- 3. **Build the overridable_props Object**
5664
- - For each property you want to make overridable, add an entry:
5665
- \`{ "elementId": "<child-element-id>", "propKey": "<property-key>", "label": "<user-friendly-name>" }\`
5666
- - The label must be unique within the component and should be meaningful to the user (e.g., "Hero Headline", "CTA Button Text")
5667
- - Group all entries under the "props" object
5668
-
5669
- ## Step 3: Execute the Tool
5670
- Call the tool with:
5671
- - element_id: The ID of the parent element to save as component
5672
- - component_name: A descriptive name for the component
5673
- - overridable_props: (Optional) The properties configuration from Step 2
5674
-
5675
- # CONSTRAINTS
5676
- - NEVER try to override properties of the parent element itself - ONLY child elements
5677
- - NEVER use invalid propKeys - always verify against the widget's atomic_props_schema in [${WIDGET_SCHEMA_URI}]
5678
- - Property keys must exist in the child element's atomic_props_schema
5679
- - Element IDs must exist within the target element's children
5680
- - When tool execution fails, read the error message and adjust accordingly
5681
- - The element being saved must not be inside another component
5682
- `);
5683
- saveAsComponentPrompt.parameter(
5684
- "element_id",
5685
- `**MANDATORY** The unique identifier of the element to save as a component.
5686
- Use the [${DOCUMENT_STRUCTURE_URI}] resource to find available element IDs.`
5687
- );
5688
- saveAsComponentPrompt.parameter(
5689
- "component_name",
5690
- `**MANDATORY** A descriptive name for the new component.
5691
- Should be unique and clearly describe the component's purpose (e.g., "Hero Section", "Feature Card").`
5692
- );
5693
- saveAsComponentPrompt.parameter(
5694
- "overridable_props",
5695
- `**OPTIONAL** Configuration for which child element properties can be customized in component instances.
5696
-
5697
- Structure:
5698
- \`\`\`json
5699
- {
5700
- "props": {
5701
- "<unique-key>": {
5702
- "elementId": "<child-element-id>",
5703
- "propKey": "<property-key>",
5704
- "label": "<user-friendly-name>"
5705
- }
5706
- }
5707
- }
5708
- \`\`\`
5709
-
5710
- To populate this correctly:
5711
- 1. Use [${DOCUMENT_STRUCTURE_URI}] to find child element IDs and their widgetType
5712
- 2. Use [${WIDGET_SCHEMA_URI}] to find the atomic_props_schema for each child element's widgetType
5713
- 3. Only include properties you want to be customizable in component instances
5714
- 4. Provide a unique, user-friendly label for each property (e.g., "Hero Headline", "CTA Button Text")`
5715
- );
5716
- saveAsComponentPrompt.example(`
5717
- Basic component without overridable properties:
5718
- \`\`\`json
5719
- {
5720
- "element_id": "abc123",
5721
- "component_name": "Hero Section"
5722
- }
5723
- \`\`\`
5724
-
5725
- Component with overridable properties:
5726
- \`\`\`json
5727
- {
5728
- "element_id": "abc123",
5729
- "component_name": "Feature Card",
5730
- "overridable_props": {
5731
- "props": {
5732
- "heading-text": {
5733
- "elementId": "heading-123",
5734
- "propKey": "text",
5735
- "label": "Card Title",
5736
- "group": "Content"
5737
- },
5738
- "button-text": {
5739
- "elementId": "button-456",
5740
- "propKey": "text",
5741
- "label": "Button Text",
5742
- "group": "Content"
5743
- },
5744
- "button-link": {
5745
- "elementId": "button-456",
5746
- "propKey": "url",
5747
- "label": "Button Link",
5748
- "group": "Settings"
5749
- }
5750
- }
5751
- }
5752
- }
5753
- \`\`\`
5754
- `);
5755
- saveAsComponentPrompt.instruction(
5756
- `After successful creation, the component will be available in the components library and can be inserted into any page or template.`
5757
- );
5758
- saveAsComponentPrompt.instruction(
5759
- `When overridable properties are defined, component instances will show customization controls for those specific properties in the editing panel.`
5760
- );
5761
- return saveAsComponentPrompt.prompt();
5762
- };
5763
- var initSaveAsComponentTool = () => {
5764
- return getMCPByDomain("components").addTool({
5765
- name: "save-as-component",
5766
- schema: InputSchema,
5767
- outputSchema: OutputSchema,
5768
- description: generatePrompt(),
5769
- handler: handleSaveAsComponent
5770
- });
5771
- };
5772
-
5773
- // src/extended/mcp/index.ts
5774
- function initMcp() {
5775
- const { setMCPDescription } = getMCPByDomain2("components");
5776
- setMCPDescription(
5777
- `Elementor Editor Components MCP - Tools for creating and managing reusable components.
5778
- Components are reusable blocks of content that can be used multiple times across the pages, its a widget which contains a set of elements and styles.`
5779
- );
5780
- initSaveAsComponentTool();
5781
- }
5782
-
5783
- // src/sync/publish-draft-components-in-page-before-save.ts
5784
- import { invalidateDocumentData as invalidateDocumentData2, isDocumentDirty as isDocumentDirty2 } from "@elementor/editor-documents";
5785
- async function publishDraftComponentsInPageBeforeSave({ status, elements }) {
5786
- if (status !== "publish") {
5787
- return;
5788
- }
5789
- const documents = await getComponentDocuments(elements);
5790
- const draftIds = [...documents.values()].filter(isDocumentDirty2).map((document) => document.id);
5791
- if (draftIds.length === 0) {
5792
- return;
5793
- }
5794
- await apiClient.updateStatuses(draftIds, "publish");
5795
- draftIds.forEach((id2) => invalidateDocumentData2(id2));
5796
- }
5797
-
5798
- // src/extended/sync/set-component-overridable-props-settings-before-save.ts
5799
- var setComponentOverridablePropsSettingsBeforeSave = ({
5800
- container
5801
- }) => {
5802
- const currentDocument = container.document;
5803
- if (!currentDocument || currentDocument.config.type !== COMPONENT_DOCUMENT_TYPE) {
5804
- return;
5805
- }
5806
- const overridableProps = componentsSelectors.getOverridableProps(currentDocument.id);
5807
- if (overridableProps) {
5808
- container.settings.set("overridable_props", overridableProps);
5809
- }
5810
- };
5811
-
5812
- // src/extended/sync/update-archived-component-before-save.ts
5813
- import { notify as notify6 } from "@elementor/editor-notifications";
5814
- var failedNotification = (message) => ({
5815
- type: "error",
5816
- message: `Failed to archive components: ${message}`,
5817
- id: "failed-archived-components-notification"
5818
- });
5819
- var updateArchivedComponentBeforeSave = async (status) => {
5820
- try {
5821
- const archivedComponents = componentsSelectors.getArchivedThisSession();
5822
- if (!archivedComponents.length) {
5823
- return;
5824
- }
5825
- const result = await apiClient.updateArchivedComponents(archivedComponents, status);
5826
- const failedIds = result.failedIds.join(", ");
5827
- if (failedIds) {
5828
- notify6(failedNotification(failedIds));
5829
- }
5830
- } catch (error) {
5831
- throw new Error(`Failed to update archived components: ${error}`);
5832
- }
5833
- };
5834
-
5835
- // src/extended/sync/update-component-title-before-save.ts
5836
- var updateComponentTitleBeforeSave = async (status) => {
5837
- const updatedComponentNames = componentsSelectors.getUpdatedComponentNames();
5838
- if (!updatedComponentNames.length) {
5839
- return;
5840
- }
5841
- const result = await apiClient.updateComponentTitle(updatedComponentNames, status);
5842
- if (result.failedIds.length === 0) {
5843
- componentsActions.cleanUpdatedComponentNames();
5844
- }
5845
- };
5846
-
5847
- // src/extended/sync/create-components-before-save.ts
5848
- import { updateElementSettings as updateElementSettings2 } from "@elementor/editor-elements";
5849
- async function createComponentsBeforeSave({
5850
- elements,
5851
- status
5852
- }) {
5853
- const unpublishedComponents = componentsSelectors.getUnpublishedComponents();
5854
- if (!unpublishedComponents.length) {
5855
- return;
5856
- }
5857
- try {
5858
- const uidToComponentId = await createComponents(unpublishedComponents, status);
5859
- updateComponentInstances(elements, uidToComponentId);
5860
- componentsActions.add(
5861
- unpublishedComponents.map((component) => ({
5862
- id: uidToComponentId.get(component.uid),
5863
- name: component.name,
5864
- uid: component.uid,
5865
- overridableProps: component.overridableProps ? component.overridableProps : void 0
5866
- }))
5867
- );
5868
- componentsActions.resetUnpublished();
5869
- } catch (error) {
5870
- const failedUids = unpublishedComponents.map((component) => component.uid);
5871
- componentsActions.removeUnpublished(failedUids);
5872
- throw new Error(`Failed to publish components: ${error}`);
5873
- }
5874
- }
5875
- async function createComponents(components, status) {
5876
- const response = await apiClient.create({
5877
- status,
5878
- items: components.map((component) => ({
5879
- uid: component.uid,
5880
- title: component.name,
5881
- elements: component.elements,
5882
- settings: component.overridableProps ? { overridable_props: component.overridableProps } : void 0
5883
- }))
5884
- });
5885
- const map = /* @__PURE__ */ new Map();
5886
- Object.entries(response).forEach(([key, value]) => {
5887
- map.set(key, value);
5888
- });
5889
- return map;
5890
- }
5891
- function updateComponentInstances(elements, uidToComponentId) {
5892
- elements.forEach((element) => {
5893
- const { shouldUpdate, newComponentId } = shouldUpdateElement(element, uidToComponentId);
5894
- if (shouldUpdate) {
5895
- updateElementComponentId(element.id, newComponentId);
5896
- }
5897
- if (element.elements) {
5898
- updateComponentInstances(element.elements, uidToComponentId);
5899
- }
5900
- });
5901
- }
5902
- function shouldUpdateElement(element, uidToComponentId) {
5903
- if (element.widgetType === "e-component") {
5904
- const currentComponentId = element.settings?.component_instance?.value?.component_id.value;
5905
- if (currentComponentId && uidToComponentId.has(currentComponentId.toString())) {
5906
- return {
5907
- shouldUpdate: true,
5908
- newComponentId: uidToComponentId.get(currentComponentId.toString())
5909
- };
5910
- }
5911
- }
5912
- return { shouldUpdate: false, newComponentId: null };
5913
- }
5914
- function updateElementComponentId(elementId, componentId) {
5915
- updateElementSettings2({
5916
- id: elementId,
5917
- props: {
5918
- component_instance: {
5919
- $$type: "component-instance",
5920
- value: {
5921
- component_id: { $$type: "number", value: componentId }
5922
- }
5923
- }
5924
- },
5925
- withHistory: false
5926
- });
5927
- }
5928
-
5929
- // src/extended/sync/before-save.ts
5930
- var beforeSave = ({ container, status }) => {
5931
- const elements = container?.model.get("elements").toJSON?.() ?? [];
5932
- return Promise.all([
5933
- syncComponents({ elements, status }),
5934
- setComponentOverridablePropsSettingsBeforeSave({ container })
5935
- ]);
5936
- };
5937
- var syncComponents = async ({ elements, status }) => {
5938
- await updateExistingComponentsBeforeSave({ elements, status });
5939
- await createComponentsBeforeSave({ elements, status });
5940
- };
5941
- var updateExistingComponentsBeforeSave = async ({
5942
- elements,
5943
- status
5944
- }) => {
5945
- await updateComponentTitleBeforeSave(status);
5946
- await updateArchivedComponentBeforeSave(status);
5947
- await publishDraftComponentsInPageBeforeSave({ elements, status });
5948
- };
5949
-
5950
- // src/extended/sync/cleanup-overridable-props-on-delete.ts
5951
- import { getAllDescendants as getAllDescendants4 } from "@elementor/editor-elements";
5952
- import { registerDataHook } from "@elementor/editor-v1-adapters";
5953
- function initCleanupOverridablePropsOnDelete() {
5954
- registerDataHook("dependency", "document/elements/delete", (args, options) => {
5955
- if (isPartOfMoveCommand(options)) {
5956
- return true;
5957
- }
5958
- const currentComponentId = componentsSelectors.getCurrentComponentId();
5959
- if (!currentComponentId) {
5960
- return true;
5961
- }
5962
- const overridableProps = componentsSelectors.getOverridableProps(currentComponentId);
5963
- if (!overridableProps || Object.keys(overridableProps.props).length === 0) {
5964
- return true;
5965
- }
5966
- const containers = args.containers ?? (args.container ? [args.container] : []);
5967
- if (containers.length === 0) {
5968
- return true;
5969
- }
5970
- const deletedElementIds = collectDeletedElementIds(containers);
5971
- if (deletedElementIds.length === 0) {
5972
- return true;
5973
- }
5974
- const propKeysToDelete = Object.entries(overridableProps.props).filter(([, prop]) => deletedElementIds.includes(prop.elementId)).map(([propKey]) => propKey);
5975
- if (propKeysToDelete.length === 0) {
5976
- return true;
5977
- }
5978
- deleteOverridableProp({ componentId: currentComponentId, propKey: propKeysToDelete, source: "system" });
5979
- return true;
5980
- });
5981
- }
5982
- function collectDeletedElementIds(containers) {
5983
- const elementIds = containers.filter(Boolean).flatMap((container) => [container, ...getAllDescendants4(container)]).map((element) => element.model?.get?.("id") ?? element.id).filter((id2) => Boolean(id2));
5984
- return elementIds;
5985
- }
5986
- function isPartOfMoveCommand(options) {
5987
- const isMoveCommandInTrace = options?.commandsCurrentTrace?.includes("document/elements/move") || options?.commandsCurrentTrace?.includes("document/repeater/move");
5988
- return Boolean(isMoveCommandInTrace);
5989
- }
5990
-
5991
- // src/extended/sync/handle-component-edit-mode-container.ts
5992
- import { createElement as createElement40, selectElement as selectElement2 } from "@elementor/editor-elements";
5993
- import { registerDataHook as registerDataHook2 } from "@elementor/editor-v1-adapters";
5994
- var V4_DEFAULT_CONTAINER_TYPE = "e-flexbox";
5995
- function initHandleComponentEditModeContainer() {
5996
- initRedirectDropIntoComponent();
5997
- initHandleTopLevelElementDelete();
5998
- }
5999
- function initHandleTopLevelElementDelete() {
6000
- registerDataHook2("after", "document/elements/delete", (args) => {
6001
- if (!isEditingComponent()) {
6002
- return;
6003
- }
6004
- const containers = args.containers ?? (args.container ? [args.container] : []);
6005
- for (const container of containers) {
6006
- if (!container.parent || !isComponent(container.parent)) {
6007
- continue;
6008
- }
6009
- const component = container.parent;
6010
- const isComponentEmpty = component.children?.length === 0;
6011
- if (isComponentEmpty) {
6012
- createEmptyTopLevelContainer(container.parent);
6013
- }
6014
- }
6015
- });
6016
- }
6017
- function initRedirectDropIntoComponent() {
6018
- registerDataHook2("dependency", "preview/drop", (args) => {
6019
- if (!isEditingComponent()) {
6020
- return true;
6021
- }
6022
- const containers = args.containers ?? (args.container ? [args.container] : []);
6023
- for (const container of containers) {
6024
- if (!isComponent(container)) {
6025
- continue;
6026
- }
6027
- const { shouldRedirect, container: redirectedContainer } = getComponentContainer(container);
6028
- if (!shouldRedirect) {
6029
- continue;
6030
- }
6031
- if (args.containers) {
6032
- const index = args.containers.indexOf(container);
6033
- args.containers[index] = redirectedContainer;
6034
- } else {
6035
- args.container = redirectedContainer;
6036
- }
6037
- }
6038
- return true;
6039
- });
6040
- }
6041
- function createEmptyTopLevelContainer(container) {
6042
- const newContainer = createElement40({
6043
- container,
6044
- model: { elType: V4_DEFAULT_CONTAINER_TYPE }
6045
- });
6046
- selectElement2(newContainer.id);
6047
- }
6048
- function getComponentContainer(container) {
6049
- const topLevelElement = container.children?.[0];
6050
- if (topLevelElement) {
6051
- return { shouldRedirect: true, container: topLevelElement };
6052
- }
6053
- return { shouldRedirect: false, container };
6054
- }
6055
- function isComponent(container) {
6056
- const isDocument = container.id === "document";
6057
- if (!isDocument) {
6058
- return false;
6059
- }
6060
- return container.document?.config.type === COMPONENT_DOCUMENT_TYPE;
6061
- }
6062
-
6063
- // src/extended/sync/revert-overridables-on-copy-or-duplicate.ts
6064
- import { registerDataHook as registerDataHook3 } from "@elementor/editor-v1-adapters";
6065
- function initRevertOverridablesOnCopyOrDuplicate() {
6066
- registerDataHook3("after", "document/elements/duplicate", (_args, result) => {
6067
- if (!isEditingComponent()) {
6068
- return;
6069
- }
6070
- revertOverridablesForDuplicatedElements(result);
6071
- });
6072
- registerDataHook3("after", "document/elements/copy", (args) => {
6073
- if (!isEditingComponent()) {
6074
- return;
6075
- }
6076
- revertOverridablesInStorage(args.storageKey ?? "clipboard");
6077
- });
6078
- }
6079
- function revertOverridablesForDuplicatedElements(duplicatedElements) {
6080
- const containers = Array.isArray(duplicatedElements) ? duplicatedElements : [duplicatedElements];
6081
- containers.forEach((container) => {
6082
- revertAllOverridablesInContainer(container);
6083
- });
6084
- }
6085
- function revertOverridablesInStorage(storageKey) {
6086
- const storage = window.elementorCommon?.storage;
6087
- if (!storage) {
6088
- return;
6089
- }
6090
- const storageData = storage.get(storageKey);
6091
- if (!storageData?.elements?.length) {
6092
- return;
6093
- }
6094
- const elementsDataWithOverridablesReverted = storageData.elements.map(revertAllOverridablesInElementData);
6095
- storage.set(storageKey, {
6096
- ...storageData,
6097
- elements: elementsDataWithOverridablesReverted
6098
- });
6099
- }
6100
-
6101
- // src/extended/sync/sanitize-overridable-props.ts
6102
- import { useEffect as useEffect7 } from "react";
6103
-
6104
- // src/extended/store/actions/update-component-sanitized-attribute.ts
6105
- function updateComponentSanitizedAttribute(componentId, attribute) {
6106
- componentsActions.updateComponentSanitizedAttribute(componentId, attribute);
6107
- }
6108
-
6109
- // src/extended/sync/sanitize-overridable-props.ts
6110
- function SanitizeOverridableProps() {
6111
- const currentComponentId = useCurrentComponentId();
6112
- const overridableProps = useOverridableProps(currentComponentId);
6113
- const isSanitized = useIsSanitizedComponent(currentComponentId, "overridableProps");
6114
- useEffect7(() => {
6115
- if (isSanitized || !overridableProps || !currentComponentId) {
6116
- return;
6117
- }
6118
- const filtered = filterValidOverridableProps(overridableProps);
6119
- const propsToDelete = Object.keys(overridableProps.props ?? {}).filter((key) => !filtered.props[key]);
6120
- if (propsToDelete.length > 0) {
6121
- propsToDelete.forEach((key) => {
6122
- deleteOverridableProp({ componentId: currentComponentId, propKey: key, source: "system" });
6123
- });
6124
- }
6125
- updateComponentSanitizedAttribute(currentComponentId, "overridableProps");
6126
- }, [currentComponentId, isSanitized, overridableProps]);
6127
- return null;
6128
- }
6129
-
6130
- // src/extended/init.ts
6131
- var PRIORITY = 1;
6132
- function initExtended() {
6133
- registerEditingPanelReplacement({
6134
- id: "extended-component-instance-edit-panel",
6135
- priority: PRIORITY,
6136
- condition: (_, elementType) => elementType.key === "e-component",
6137
- component: ExtendedInstanceEditingPanel
6138
- });
6139
- registerTab({
6140
- id: "components",
6141
- label: __34("Components", "elementor"),
6142
- component: ExtendedComponents,
6143
- priority: PRIORITY
6144
- });
6145
- registerPanel(panel);
6146
- registerDataHook4("dependency", "editor/documents/close", (args) => {
6147
- const document = getV1CurrentDocument();
6148
- if (document.config.type === COMPONENT_DOCUMENT_TYPE) {
6149
- args.mode = "autosave";
6150
- }
6151
- return true;
6152
- });
6153
- registerDataHook4("after", "preview/drop", onElementDrop);
6154
- window.elementorCommon.__beforeSave = beforeSave;
6155
- injectIntoTop({
6156
- id: "create-component-popup",
6157
- component: CreateComponentForm
6158
- });
6159
- injectIntoTop({
6160
- id: "edit-component",
6161
- component: EditComponent
6162
- });
6163
- injectIntoPanelHeaderTop({
6164
- id: "component-panel-header",
6165
- component: ComponentPanelHeader
6166
- });
6167
- registerFieldIndicator({
6168
- fieldType: FIELD_TYPE.SETTINGS,
6169
- id: "component-overridable-prop",
6170
- priority: 1,
6171
- indicator: OverridablePropIndicator
6172
- });
6173
- registerControlReplacement({
6174
- id: OVERRIDABLE_PROP_REPLACEMENT_ID,
6175
- component: OverridablePropControl,
6176
- condition: ({ value }) => componentOverridablePropTypeUtil.isValid(value)
6177
- });
6178
- initCleanupOverridablePropsOnDelete();
6179
- initMcp();
6180
- initNonAtomicNestingPrevention();
6181
- initHandleComponentEditModeContainer();
6182
- initRevertOverridablesOnCopyOrDuplicate();
6183
- injectIntoLogic({
6184
- id: "sanitize-overridable-props",
6185
- component: SanitizeOverridableProps
6186
- });
6187
- }
6188
-
6189
- // src/extended/shortcuts/create-component-shortcut.ts
6190
- import { getElementType as getElementType5, getSelectedElements as getSelectedElements2, getWidgetsCache as getWidgetsCache5 } from "@elementor/editor-elements";
6191
- import { isProActive } from "@elementor/utils";
6192
- var CREATE_COMPONENT_SHORTCUT_KEYS = "ctrl+shift+k";
6193
- var OPEN_SAVE_AS_COMPONENT_FORM_EVENT = "elementor/editor/open-save-as-component-form";
6194
- function isCreateComponentAllowed() {
6195
- const selectedElements = getSelectedElements2();
6196
- if (selectedElements.length !== 1) {
6197
- return { allowed: false };
6198
- }
6199
- const element = selectedElements[0];
6200
- const elementType = getElementType5(element.type);
6201
- if (!elementType) {
6202
- return { allowed: false };
6203
- }
6204
- if (!isProActive()) {
6205
- return { allowed: false };
6206
- }
6207
- const widgetsCache = getWidgetsCache5();
6208
- const elementConfig = widgetsCache?.[element.type];
6209
- if (!elementConfig?.atomic_props_schema || !elementConfig?.show_in_panel || elementConfig?.elType === "widget") {
6210
- return { allowed: false };
6211
- }
6212
- const legacyWindow = window;
6213
- const container = legacyWindow.elementor.getContainer(element.id);
6214
- if (!container || container.isLocked()) {
6215
- return { allowed: false };
6216
- }
6217
- return { allowed: true, container };
6218
- }
6219
- function triggerCreateComponentForm(container) {
6220
- const legacyWindow = window;
6221
- const elementRect = container.view.el.getBoundingClientRect();
6222
- const iframeRect = legacyWindow.elementor.$preview[0].getBoundingClientRect();
6223
- const anchorPosition = {
6224
- left: iframeRect.left + elementRect.left + elementRect.width / 2,
6225
- top: iframeRect.top + elementRect.top
6226
- };
6227
- window.dispatchEvent(
6228
- new CustomEvent(OPEN_SAVE_AS_COMPONENT_FORM_EVENT, {
6229
- detail: {
6230
- element: container.model.toJSON({ remove: ["default"] }),
6231
- anchorPosition,
6232
- options: {
6233
- trigger: "keyboard",
6234
- location: "canvas",
6235
- secondaryLocation: "canvasElement"
6236
- }
6237
- }
6238
- })
6239
- );
6240
- }
6241
- function initCreateComponentShortcut() {
6242
- const legacyWindow = window;
6243
- legacyWindow.$e.shortcuts.register(CREATE_COMPONENT_SHORTCUT_KEYS, {
6244
- callback: () => {
6245
- const result = isCreateComponentAllowed();
6246
- if (!result.allowed) {
6247
- return;
6248
- }
6249
- triggerCreateComponentForm(result.container);
6250
- },
6251
- dependency: () => {
6252
- const result = isCreateComponentAllowed();
6253
- return result.allowed;
6254
- },
6255
- exclude: ["input"]
6256
- });
6257
- }
6258
-
6259
- // src/populate-store.ts
6260
- import { useEffect as useEffect8 } from "react";
6261
- import { __dispatch as dispatch5 } from "@elementor/store";
6262
- function PopulateStore() {
6263
- useEffect8(() => {
6264
- dispatch5(loadComponents());
6265
- }, []);
6266
- return null;
6267
- }
6268
-
6269
- // src/prevent-circular-nesting.ts
6270
- import { getAllDescendants as getAllDescendants5 } from "@elementor/editor-elements";
6271
- import { notify as notify7 } from "@elementor/editor-notifications";
6272
- import { blockCommand as blockCommand2 } from "@elementor/editor-v1-adapters";
6273
- import { __getState as getState10 } from "@elementor/store";
6274
- import { __ as __35 } from "@wordpress/i18n";
6275
- var COMPONENT_TYPE = "e-component";
6276
- var COMPONENT_CIRCULAR_NESTING_ALERT = {
6277
- type: "default",
6278
- message: __35("Can't add this component - components that contain each other can't be nested.", "elementor"),
6279
- id: "circular-component-nesting-blocked"
6280
- };
6281
- function initCircularNestingPrevention() {
6282
- blockCommand2({
6283
- command: "document/elements/create",
6284
- condition: blockCircularCreate
6285
- });
6286
- blockCommand2({
6287
- command: "document/elements/move",
6288
- condition: blockCircularMove
6289
- });
6290
- blockCommand2({
6291
- command: "document/elements/paste",
6292
- condition: blockCircularPaste
6293
- });
6294
- }
6295
- function wouldCreateCircularNesting(componentIdToAdd) {
6296
- if (componentIdToAdd === void 0) {
6297
- return false;
6298
- }
6299
- const state = getState10();
6300
- const currentComponentId = selectCurrentComponentId(state);
6301
- const path = selectPath(state);
6302
- if (currentComponentId === null) {
6303
- return false;
6304
- }
6305
- if (componentIdToAdd === currentComponentId) {
6306
- return true;
6307
- }
6308
- return path.some((item) => item.componentId === componentIdToAdd);
6309
- }
6310
- function extractComponentIdFromModel(model) {
6311
- if (!model) {
6312
- return null;
6313
- }
6314
- const isComponent2 = model.widgetType === COMPONENT_TYPE;
6315
- if (!isComponent2) {
6316
- return null;
6317
- }
6318
- return model.settings?.component_instance?.value?.component_id?.value ?? null;
6319
- }
6320
- function extractComponentIdFromElement(element) {
6321
- if (element.widgetType !== COMPONENT_TYPE) {
6322
- return null;
6323
- }
6324
- return element.settings?.component_instance?.value?.component_id?.value ?? null;
6325
- }
6326
- function extractComponentIdsFromElements(elements) {
6327
- const ids = [];
6328
- for (const element of elements) {
6329
- const componentId = extractComponentIdFromElement(element);
6330
- if (componentId !== null) {
6331
- ids.push(componentId);
6332
- }
6333
- if (element.elements?.length) {
6334
- ids.push(...extractComponentIdsFromElements(element.elements));
6335
- }
6336
- }
6337
- return ids;
6338
- }
6339
- function extractComponentIdFromContainer(container) {
6340
- const widgetType = container.model?.get?.("widgetType");
6341
- if (widgetType !== COMPONENT_TYPE) {
6342
- return null;
6343
- }
6344
- const settings = container.model?.get?.("settings");
6345
- const componentInstance = settings?.get?.("component_instance");
6346
- return componentInstance?.value?.component_id?.value ?? null;
6347
- }
6348
- function blockCircularCreate(args) {
6349
- const componentId = extractComponentIdFromModel(args.model);
6350
- if (componentId === null) {
6351
- return false;
6352
- }
6353
- const isBlocked = wouldCreateCircularNesting(componentId);
6354
- if (isBlocked) {
6355
- notify7(COMPONENT_CIRCULAR_NESTING_ALERT);
6356
- }
6357
- return isBlocked;
6358
- }
6359
- function blockCircularMove(args) {
6360
- const { containers = [args.container] } = args;
6361
- const hasCircularComponent = containers.some((container) => {
6362
- if (!container) {
6363
- return false;
6364
- }
6365
- const allElements = getAllDescendants5(container);
6366
- return allElements.some((element) => {
6367
- const componentId = extractComponentIdFromContainer(element);
6368
- if (componentId === null) {
6369
- return false;
6370
- }
6371
- return wouldCreateCircularNesting(componentId);
6372
- });
6373
- });
6374
- if (hasCircularComponent) {
6375
- notify7(COMPONENT_CIRCULAR_NESTING_ALERT);
6376
- }
6377
- return hasCircularComponent;
6378
- }
6379
- function blockCircularPaste(args) {
6380
- const { storageType } = args;
6381
- if (storageType !== "localstorage") {
6382
- return false;
6383
- }
6384
- const data = window?.elementorCommon?.storage?.get();
6385
- if (!data?.clipboard?.elements) {
6386
- return false;
6387
- }
6388
- const allComponentIds = extractComponentIdsFromElements(data.clipboard.elements);
6389
- const hasCircularComponent = allComponentIds.some(wouldCreateCircularNesting);
6390
- if (hasCircularComponent) {
6391
- notify7(COMPONENT_CIRCULAR_NESTING_ALERT);
6392
- }
6393
- return hasCircularComponent;
6394
- }
6395
-
6396
- // src/store/actions/remove-component-styles.ts
6397
- import { __dispatch as dispatch6 } from "@elementor/store";
6398
- function removeComponentStyles(id2) {
6399
- apiClient.invalidateComponentConfigCache(id2);
6400
- dispatch6(slice.actions.removeStyles({ id: id2 }));
2708
+ await apiClient.updateStatuses(draftIds, "publish");
2709
+ draftIds.forEach((id) => invalidateDocumentData2(id));
6401
2710
  }
6402
2711
 
6403
- // src/store/components-styles-provider.ts
6404
- import { createStylesProvider } from "@elementor/editor-styles-repository";
6405
- import { __getState as getState11, __subscribeWithSelector as subscribeWithSelector } from "@elementor/store";
6406
- var componentsStylesProvider = createStylesProvider({
6407
- key: "components-styles",
6408
- priority: 100,
6409
- subscribe: (cb) => subscribeWithSelector(
6410
- (state) => state[SLICE_NAME],
6411
- () => {
6412
- cb();
6413
- }
6414
- ),
6415
- actions: {
6416
- all: () => {
6417
- return selectFlatStyles(getState11());
6418
- },
6419
- get: (id2) => {
6420
- return selectFlatStyles(getState11()).find((style) => style.id === id2) ?? null;
6421
- }
6422
- }
6423
- });
6424
-
6425
2712
  // src/sync/before-save.ts
6426
- var beforeSave2 = ({ container, status }) => {
2713
+ var beforeSave = ({ container, status }) => {
6427
2714
  const elements = container?.model.get("elements").toJSON?.() ?? [];
6428
2715
  return publishDraftComponentsInPageBeforeSave({ elements, status });
6429
2716
  };
6430
2717
 
6431
2718
  // src/sync/load-component-data-after-instance-added.ts
6432
- import { registerDataHook as registerDataHook5 } from "@elementor/editor-v1-adapters";
2719
+ import { registerDataHook } from "@elementor/editor-v1-adapters";
6433
2720
  function initLoadComponentDataAfterInstanceAdded() {
6434
- registerDataHook5("after", "document/elements/paste", (_args, result) => {
2721
+ registerDataHook("after", "document/elements/paste", (_args, result) => {
6435
2722
  load(result);
6436
2723
  });
6437
- registerDataHook5("after", "document/elements/import", (_args, result) => {
2724
+ registerDataHook("after", "document/elements/import", (_args, result) => {
6438
2725
  load(result);
6439
2726
  });
6440
2727
  }
@@ -6444,7 +2731,6 @@ function load(result) {
6444
2731
  }
6445
2732
 
6446
2733
  // src/init.ts
6447
- var PRO_EXTENDED_MIGRATION_VERSION = "4.0.0";
6448
2734
  function init() {
6449
2735
  stylesRepository.register(componentsStylesProvider);
6450
2736
  registerSlice(slice);
@@ -6456,29 +2742,29 @@ function init() {
6456
2742
  showDetachConfirmDialog: openDetachConfirmDialog
6457
2743
  })
6458
2744
  );
6459
- window.elementorCommon.__beforeSave = beforeSave2;
2745
+ window.elementorCommon.__beforeSave = beforeSave;
6460
2746
  injectTab({
6461
2747
  id: "components",
6462
- label: __36("Components", "elementor"),
2748
+ label: __12("Components", "elementor"),
6463
2749
  component: Components,
6464
2750
  position: 1
6465
2751
  });
6466
- injectIntoLogic2({
2752
+ injectIntoLogic({
6467
2753
  id: "components-populate-store",
6468
2754
  component: PopulateStore
6469
2755
  });
6470
- registerDataHook6("after", "editor/documents/attach-preview", async () => {
6471
- const { id: id2, config } = getV1CurrentDocument2();
6472
- if (id2) {
6473
- removeComponentStyles(id2);
2756
+ registerDataHook2("after", "editor/documents/attach-preview", async () => {
2757
+ const { id, config } = getV1CurrentDocument();
2758
+ if (id) {
2759
+ removeComponentStyles(id);
6474
2760
  }
6475
2761
  await loadComponentsAssets(config?.elements ?? []);
6476
2762
  });
6477
- injectIntoLogic2({
2763
+ injectIntoLogic({
6478
2764
  id: "templates",
6479
2765
  component: LoadTemplateComponents
6480
2766
  });
6481
- registerEditingPanelReplacement2({
2767
+ registerEditingPanelReplacement({
6482
2768
  id: "component-instance-edit-panel",
6483
2769
  condition: (_, elementType) => elementType.key === "e-component",
6484
2770
  component: InstanceEditingPanel
@@ -6488,12 +2774,6 @@ function init() {
6488
2774
  settingsTransformersRegistry2.register("override", componentOverrideTransformer);
6489
2775
  initCircularNestingPrevention();
6490
2776
  initLoadComponentDataAfterInstanceAdded();
6491
- if (!!window.elementorPro && !isProAtLeast(PRO_EXTENDED_MIGRATION_VERSION)) {
6492
- initExtended();
6493
- }
6494
- if (!!window.elementorPro) {
6495
- initCreateComponentShortcut();
6496
- }
6497
2777
  }
6498
2778
  export {
6499
2779
  COMPONENT_WIDGET_TYPE2 as COMPONENT_WIDGET_TYPE,