@elementor/editor-components 3.35.0-465 → 3.35.0-467

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -356,9 +356,9 @@ import * as React10 from "react";
356
356
  import { useSuppressedMessage } from "@elementor/editor-current-user";
357
357
  import { getV1DocumentsManager as getV1DocumentsManager3 } from "@elementor/editor-documents";
358
358
  import { ArrowLeftIcon, ComponentsFilledIcon } from "@elementor/icons";
359
- import { __getState as getState10 } from "@elementor/store";
360
- import { Box as Box7, Divider as Divider2, IconButton as IconButton4, Stack as Stack6, Tooltip as Tooltip3, Typography as Typography6 } from "@elementor/ui";
361
- import { __ as __12 } from "@wordpress/i18n";
359
+ import { __getState as getState11 } from "@elementor/store";
360
+ import { Box as Box7, Divider as Divider2, IconButton as IconButton4, Stack as Stack6, Tooltip as Tooltip4, Typography as Typography6 } from "@elementor/ui";
361
+ import { __ as __13 } from "@wordpress/i18n";
362
362
 
363
363
  // src/hooks/use-navigate-back.ts
364
364
  import { useCallback } from "react";
@@ -478,7 +478,7 @@ import { useSelectedElement } from "@elementor/editor-elements";
478
478
  import { __createPanel as createPanel, Panel } from "@elementor/editor-panels";
479
479
  import { ThemeProvider } from "@elementor/editor-ui";
480
480
  import { Alert, Box as Box5, ErrorBoundary } from "@elementor/ui";
481
- import { __ as __10 } from "@wordpress/i18n";
481
+ import { __ as __11 } from "@wordpress/i18n";
482
482
 
483
483
  // src/components/component-properties-panel/component-properties-panel-content.tsx
484
484
  import * as React7 from "react";
@@ -488,7 +488,7 @@ import { PanelBody, PanelHeader, PanelHeaderTitle } from "@elementor/editor-pane
488
488
  import { ComponentPropListIcon as ComponentPropListIcon2, FolderPlusIcon, XIcon as XIcon2 } from "@elementor/icons";
489
489
  import { Divider, IconButton as IconButton3, List as List2, Stack as Stack5, Tooltip as Tooltip2 } from "@elementor/ui";
490
490
  import { generateUniqueId as generateUniqueId2 } from "@elementor/utils";
491
- import { __ as __9 } from "@wordpress/i18n";
491
+ import { __ as __10 } from "@wordpress/i18n";
492
492
 
493
493
  // src/store/actions/add-overridable-group.ts
494
494
  import { __dispatch as dispatch, __getState as getState3 } from "@elementor/store";
@@ -704,1406 +704,1503 @@ function deleteOverridableGroup({ componentId, groupId }) {
704
704
  }
705
705
 
706
706
  // src/store/actions/delete-overridable-prop.ts
707
- import { getContainer, updateElementSettings } from "@elementor/editor-elements";
708
- import { __dispatch as dispatch3, __getState as getState5 } from "@elementor/store";
709
- function deleteOverridableProp({ componentId, propKey, source }) {
710
- const overridableProps = selectOverridableProps(getState5(), componentId);
711
- if (!overridableProps) {
712
- return;
713
- }
714
- const prop = overridableProps.props[propKey];
715
- if (!prop) {
716
- return;
717
- }
718
- revertElementSetting(prop.elementId, prop.propKey, prop.originValue);
719
- const { [propKey]: removedProp, ...remainingProps } = overridableProps.props;
720
- const updatedGroups = removePropFromAllGroups(overridableProps.groups, propKey);
721
- dispatch3(
722
- slice.actions.setOverridableProps({
723
- componentId,
724
- overridableProps: {
725
- ...overridableProps,
726
- props: remainingProps,
727
- groups: updatedGroups
728
- }
729
- })
730
- );
731
- const currentComponent = selectCurrentComponent(getState5());
732
- trackComponentEvent({
733
- action: "propertyRemoved",
734
- source,
735
- component_uid: currentComponent?.uid,
736
- property_id: removedProp.overrideKey,
737
- property_path: removedProp.propKey,
738
- property_name: removedProp.label,
739
- element_type: removedProp.widgetType ?? removedProp.elType
740
- });
741
- }
742
- function revertElementSetting(elementId, settingKey, originValue) {
743
- const container = getContainer(elementId);
744
- if (!container) {
745
- return;
746
- }
747
- updateElementSettings({
748
- id: elementId,
749
- props: { [settingKey]: originValue ?? null },
750
- withHistory: false
751
- });
752
- }
707
+ import { __dispatch as dispatch3, __getState as getState6 } from "@elementor/store";
753
708
 
754
- // src/store/actions/reorder-group-props.ts
755
- import { __dispatch as dispatch4, __getState as getState6 } from "@elementor/store";
756
- function reorderGroupProps({ componentId, groupId, newPropsOrder }) {
757
- const overridableProps = selectOverridableProps(getState6(), componentId);
758
- if (!overridableProps) {
759
- return;
760
- }
761
- const group = overridableProps.groups.items[groupId];
762
- if (!group) {
763
- return;
764
- }
765
- dispatch4(
766
- slice.actions.setOverridableProps({
767
- componentId,
768
- overridableProps: {
769
- ...overridableProps,
770
- groups: {
771
- ...overridableProps.groups,
772
- items: {
773
- ...overridableProps.groups.items,
774
- [groupId]: {
775
- ...group,
776
- props: newPropsOrder
777
- }
778
- }
779
- }
780
- }
781
- })
782
- );
783
- }
709
+ // src/utils/revert-element-overridable-setting.ts
710
+ import { getContainer, getElementSetting, updateElementSettings } from "@elementor/editor-elements";
784
711
 
785
- // src/store/actions/reorder-overridable-groups.ts
786
- import { __dispatch as dispatch5, __getState as getState7 } from "@elementor/store";
787
- function reorderOverridableGroups({ componentId, newOrder }) {
788
- const overridableProps = selectOverridableProps(getState7(), componentId);
789
- if (!overridableProps) {
790
- return;
791
- }
792
- dispatch5(
793
- slice.actions.setOverridableProps({
794
- componentId,
795
- overridableProps: {
796
- ...overridableProps,
797
- groups: {
798
- ...overridableProps.groups,
799
- order: newOrder
800
- }
801
- }
712
+ // src/prop-types/component-instance-override-prop-type.ts
713
+ import { createPropUtils } from "@elementor/editor-props";
714
+ import { z } from "@elementor/schema";
715
+ var componentInstanceOverridePropTypeUtil = createPropUtils(
716
+ "override",
717
+ z.object({
718
+ override_key: z.string(),
719
+ override_value: z.unknown(),
720
+ schema_source: z.object({
721
+ type: z.literal("component"),
722
+ id: z.number()
802
723
  })
803
- );
804
- }
724
+ })
725
+ );
805
726
 
806
- // src/store/actions/update-overridable-prop-params.ts
807
- import { __dispatch as dispatch6, __getState as getState8 } from "@elementor/store";
808
- function updateOverridablePropParams({
809
- componentId,
810
- overrideKey,
811
- label,
812
- groupId
813
- }) {
814
- const overridableProps = selectOverridableProps(getState8(), componentId);
815
- if (!overridableProps) {
816
- return;
817
- }
818
- const prop = overridableProps.props[overrideKey];
819
- if (!prop) {
820
- return;
821
- }
822
- const oldGroupId = prop.groupId;
823
- const newGroupId = groupId ?? oldGroupId;
824
- const updatedProp = {
825
- ...prop,
826
- label,
827
- groupId: newGroupId
828
- };
829
- const updatedGroups = movePropBetweenGroups(overridableProps.groups, overrideKey, oldGroupId, newGroupId);
830
- dispatch6(
831
- slice.actions.setOverridableProps({
832
- componentId,
833
- overridableProps: {
834
- ...overridableProps,
835
- props: {
836
- ...overridableProps.props,
837
- [overrideKey]: updatedProp
838
- },
839
- groups: updatedGroups
840
- }
841
- })
842
- );
843
- return updatedProp;
844
- }
727
+ // src/prop-types/component-instance-overrides-prop-type.ts
728
+ import { createPropUtils as createPropUtils3 } from "@elementor/editor-props";
729
+ import { z as z3 } from "@elementor/schema";
845
730
 
846
- // src/components/component-panel-header/use-overridable-props.ts
847
- import { __useSelector as useSelector3 } from "@elementor/store";
848
- function useOverridableProps2(componentId) {
849
- return useSelector3((state) => {
850
- if (!componentId) {
851
- return void 0;
852
- }
853
- return selectOverridableProps(state, componentId);
854
- });
855
- }
731
+ // src/prop-types/component-overridable-prop-type.ts
732
+ import { createPropUtils as createPropUtils2 } from "@elementor/editor-props";
733
+ import { z as z2 } from "@elementor/schema";
734
+ var componentOverridablePropTypeUtil = createPropUtils2(
735
+ "overridable",
736
+ z2.object({
737
+ override_key: z2.string(),
738
+ origin_value: z2.object({
739
+ $$type: z2.string(),
740
+ value: z2.unknown()
741
+ }).nullable()
742
+ })
743
+ );
856
744
 
857
- // src/components/component-properties-panel/properties-empty-state.tsx
858
- import * as React2 from "react";
859
- import { useState } from "react";
860
- import { ComponentPropListIcon } from "@elementor/icons";
861
- import { Link as Link2, Stack as Stack2, Typography as Typography2 } from "@elementor/ui";
862
- import { __ as __3 } from "@wordpress/i18n";
745
+ // src/prop-types/component-instance-overrides-prop-type.ts
746
+ var componentInstanceOverridesPropTypeUtil = createPropUtils3(
747
+ "overrides",
748
+ z3.array(z3.union([componentInstanceOverridePropTypeUtil.schema, componentOverridablePropTypeUtil.schema])).optional().default([])
749
+ );
863
750
 
864
- // src/components/components-tab/component-introduction.tsx
865
- import * as React from "react";
866
- import { PopoverContent } from "@elementor/editor-controls";
867
- import { PopoverHeader } from "@elementor/editor-ui";
868
- import { Box, Button, Image, Link, Popover, Stack, Typography } from "@elementor/ui";
751
+ // src/prop-types/component-instance-prop-type.ts
752
+ import { createPropUtils as createPropUtils4, numberPropTypeUtil } from "@elementor/editor-props";
753
+ import { z as z4 } from "@elementor/schema";
754
+ var componentInstancePropTypeUtil = createPropUtils4(
755
+ "component-instance",
756
+ z4.object({
757
+ component_id: numberPropTypeUtil.schema,
758
+ overrides: z4.optional(componentInstanceOverridesPropTypeUtil.schema)
759
+ })
760
+ );
761
+
762
+ // src/create-component-type.ts
763
+ import {
764
+ createTemplatedElementView
765
+ } from "@elementor/editor-canvas";
766
+ import { getCurrentDocument } from "@elementor/editor-documents";
767
+ import { __getState as getState5 } from "@elementor/store";
869
768
  import { __ as __2 } from "@wordpress/i18n";
870
- var ComponentIntroduction = ({
871
- anchorRef,
872
- shouldShowIntroduction,
873
- onClose
874
- }) => {
875
- if (!anchorRef.current || !shouldShowIntroduction) {
876
- return null;
877
- }
878
- return /* @__PURE__ */ React.createElement(
879
- Popover,
880
- {
881
- anchorEl: anchorRef.current,
882
- open: shouldShowIntroduction,
883
- anchorOrigin: {
884
- vertical: "top",
885
- horizontal: "right"
886
- },
887
- transformOrigin: {
888
- vertical: "top",
889
- horizontal: -30
890
- },
891
- onClose
892
- },
893
- /* @__PURE__ */ React.createElement(Box, { sx: { width: "296px" } }, /* @__PURE__ */ React.createElement(PopoverHeader, { title: __2("Add your first property", "elementor"), onClose }), /* @__PURE__ */ React.createElement(
894
- Image,
895
- {
896
- sx: { width: "296px", height: "160px" },
897
- src: "https://assets.elementor.com/packages/v1/images/components-properties-intro.png",
898
- alt: ""
899
- }
900
- ), /* @__PURE__ */ React.createElement(PopoverContent, null, /* @__PURE__ */ React.createElement(Stack, { sx: { p: 2 } }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, __2("Properties make instances flexible.", "elementor")), /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, __2(
901
- "Click next to any setting you want users to customize - like text, images, or links.",
902
- "elementor"
903
- )), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", sx: { mt: 2 } }, __2(
904
- "Your properties will appear in the Properties panel, where you can organize and manage them anytime.",
905
- "elementor"
906
- )), /* @__PURE__ */ React.createElement(
907
- Link,
908
- {
909
- href: "http://go.elementor.com/components-guide",
910
- target: "_blank",
911
- sx: { mt: 2 },
912
- color: "info.main",
913
- variant: "body2"
914
- },
915
- __2("Learn more", "elementor")
916
- ), /* @__PURE__ */ React.createElement(Stack, { direction: "row", alignItems: "center", justifyContent: "flex-end", sx: { pt: 1 } }, /* @__PURE__ */ React.createElement(Button, { size: "medium", variant: "contained", onClick: onClose }, __2("Got it", "elementor"))))))
917
- );
769
+ var COMPONENT_WIDGET_TYPE = "e-component";
770
+ var updateGroups = (groups, config) => {
771
+ const disableMap = new Map(Object.entries(config.disable ?? {}));
772
+ const addMap = new Map(Object.entries(config.add ?? {}));
773
+ return groups.map((group) => {
774
+ const disabledActions = disableMap.get(group.name) ?? [];
775
+ const addConfig = addMap.get(group.name);
776
+ const updatedActions = group.actions.map(
777
+ (action) => disabledActions.includes(action.name) ? { ...action, isEnabled: () => false } : action
778
+ );
779
+ if (addConfig) {
780
+ updatedActions.splice(addConfig.index, 0, addConfig.action);
781
+ }
782
+ return { ...group, actions: updatedActions };
783
+ });
918
784
  };
919
-
920
- // src/components/component-properties-panel/properties-empty-state.tsx
921
- function PropertiesEmptyState({ introductionRef }) {
922
- const [isOpen, setIsOpen] = useState(false);
923
- return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(
924
- Stack2,
925
- {
926
- alignItems: "center",
927
- justifyContent: "flex-start",
928
- height: "100%",
929
- color: "text.secondary",
930
- sx: { px: 2.5, pt: 10, pb: 5.5 },
931
- gap: 1
932
- },
933
- /* @__PURE__ */ React2.createElement(ComponentPropListIcon, { fontSize: "large" }),
934
- /* @__PURE__ */ React2.createElement(Typography2, { align: "center", variant: "subtitle2" }, __3("Add your first property", "elementor")),
935
- /* @__PURE__ */ React2.createElement(Typography2, { align: "center", variant: "caption" }, __3("Make instances flexible while keeping design synced.", "elementor")),
936
- /* @__PURE__ */ React2.createElement(Typography2, { align: "center", variant: "caption" }, __3("Select any element, then click + next to a setting to expose it.", "elementor")),
937
- /* @__PURE__ */ React2.createElement(
938
- Link2,
939
- {
940
- variant: "caption",
941
- color: "secondary",
942
- sx: { textDecorationLine: "underline" },
943
- onClick: () => setIsOpen(true)
944
- },
945
- __3("Learn more", "elementor")
946
- )
947
- ), /* @__PURE__ */ React2.createElement(
948
- ComponentIntroduction,
949
- {
950
- anchorRef: introductionRef,
951
- shouldShowIntroduction: isOpen,
952
- onClose: () => setIsOpen(false)
785
+ function createComponentType(options) {
786
+ const legacyWindow = window;
787
+ const WidgetType = legacyWindow.elementor.modules.elements.types.Widget;
788
+ const view = createComponentView({ ...options });
789
+ return class extends WidgetType {
790
+ getType() {
791
+ return options.type;
953
792
  }
954
- ));
955
- }
956
-
957
- // src/components/component-properties-panel/properties-group.tsx
958
- import * as React6 from "react";
959
- import { EditableField, MenuListItem as MenuListItem2 } from "@elementor/editor-ui";
960
- import { DotsVerticalIcon } from "@elementor/icons";
961
- import {
962
- bindMenu,
963
- bindTrigger as bindTrigger2,
964
- Box as Box4,
965
- IconButton as IconButton2,
966
- List,
967
- Menu,
968
- Stack as Stack4,
969
- Tooltip,
970
- Typography as Typography5,
971
- usePopupState as usePopupState2
972
- } from "@elementor/ui";
973
- import { __ as __6 } from "@wordpress/i18n";
974
-
975
- // src/components/component-properties-panel/property-item.tsx
976
- import * as React5 from "react";
977
- import { getWidgetsCache } from "@elementor/editor-elements";
978
- import { XIcon } from "@elementor/icons";
979
- import { bindPopover, bindTrigger, Box as Box3, IconButton, Popover as Popover2, Typography as Typography4, usePopupState } from "@elementor/ui";
980
-
981
- // src/components/overridable-props/overridable-prop-form.tsx
982
- import * as React3 from "react";
983
- import { useState as useState2 } from "react";
984
- import { Form, MenuListItem } from "@elementor/editor-ui";
985
- import { Button as Button2, FormLabel, Grid, Select, Stack as Stack3, TextField, Typography as Typography3 } from "@elementor/ui";
986
- import { __ as __5 } from "@wordpress/i18n";
987
-
988
- // src/components/overridable-props/utils/validate-prop-label.ts
989
- import { __ as __4 } from "@wordpress/i18n";
990
- var ERROR_MESSAGES = {
991
- EMPTY_NAME: __4("Property name is required", "elementor"),
992
- DUPLICATE_NAME: __4("Property name already exists", "elementor")
993
- };
994
- function validatePropLabel(label, existingLabels, currentLabel) {
995
- const trimmedLabel = label.trim();
996
- if (!trimmedLabel) {
997
- return { isValid: false, errorMessage: ERROR_MESSAGES.EMPTY_NAME };
998
- }
999
- const normalizedLabel = trimmedLabel.toLowerCase();
1000
- const normalizedCurrentLabel = currentLabel?.trim().toLowerCase();
1001
- const isDuplicate = existingLabels.some((existingLabel) => {
1002
- const normalizedExisting = existingLabel.trim().toLowerCase();
1003
- if (normalizedCurrentLabel && normalizedExisting === normalizedCurrentLabel) {
1004
- return false;
793
+ getView() {
794
+ return view;
1005
795
  }
1006
- return normalizedExisting === normalizedLabel;
1007
- });
1008
- if (isDuplicate) {
1009
- return { isValid: false, errorMessage: ERROR_MESSAGES.DUPLICATE_NAME };
1010
- }
1011
- return { isValid: true, errorMessage: null };
1012
- }
1013
-
1014
- // src/components/overridable-props/overridable-prop-form.tsx
1015
- var SIZE = "tiny";
1016
- var DEFAULT_GROUP = { value: null, label: __5("Default", "elementor") };
1017
- function OverridablePropForm({ onSubmit, groups, currentValue, existingLabels = [], sx }) {
1018
- const [propLabel, setPropLabel] = useState2(currentValue?.label ?? null);
1019
- const [group, setGroup] = useState2(currentValue?.groupId ?? groups?.[0]?.value ?? null);
1020
- const [error, setError] = useState2(null);
1021
- const name = __5("Name", "elementor");
1022
- const groupName = __5("Group Name", "elementor");
1023
- const isCreate = currentValue === void 0;
1024
- const title = isCreate ? __5("Create new property", "elementor") : __5("Update property", "elementor");
1025
- const ctaLabel = isCreate ? __5("Create", "elementor") : __5("Update", "elementor");
1026
- const handleSubmit = () => {
1027
- const validationResult = validatePropLabel(propLabel ?? "", existingLabels, currentValue?.label);
1028
- if (!validationResult.isValid) {
1029
- setError(validationResult.errorMessage);
1030
- return;
796
+ getModel() {
797
+ return createComponentModel();
1031
798
  }
1032
- onSubmit({ label: propLabel ?? "", group });
1033
799
  };
1034
- return /* @__PURE__ */ React3.createElement(Form, { onSubmit: handleSubmit }, /* @__PURE__ */ React3.createElement(Stack3, { alignItems: "start", sx: { width: "268px", ...sx } }, /* @__PURE__ */ React3.createElement(
1035
- Stack3,
1036
- {
1037
- direction: "row",
1038
- alignItems: "center",
1039
- py: 1,
1040
- px: 1.5,
1041
- sx: { columnGap: 0.5, borderBottom: "1px solid", borderColor: "divider", width: "100%", mb: 1.5 }
1042
- },
1043
- /* @__PURE__ */ React3.createElement(Typography3, { variant: "caption", sx: { color: "text.primary", fontWeight: "500", lineHeight: 1 } }, title)
1044
- ), /* @__PURE__ */ React3.createElement(Grid, { container: true, gap: 0.75, alignItems: "start", px: 1.5, mb: 1.5 }, /* @__PURE__ */ React3.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React3.createElement(FormLabel, { size: "tiny" }, name)), /* @__PURE__ */ React3.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React3.createElement(
1045
- TextField,
1046
- {
1047
- name,
1048
- size: SIZE,
1049
- fullWidth: true,
1050
- placeholder: __5("Enter value", "elementor"),
1051
- value: propLabel ?? "",
1052
- onChange: (e) => {
1053
- const newValue = e.target.value;
1054
- setPropLabel(newValue);
1055
- const validationResult = validatePropLabel(
1056
- newValue,
1057
- existingLabels,
1058
- currentValue?.label
1059
- );
1060
- setError(validationResult.errorMessage);
1061
- },
1062
- error: Boolean(error),
1063
- helperText: error
800
+ }
801
+ function createComponentView(options) {
802
+ const legacyWindow = window;
803
+ return class extends createTemplatedElementView(options) {
804
+ eventsManagerConfig = legacyWindow.elementorCommon.eventsManager.config;
805
+ #componentRenderContext;
806
+ isComponentCurrentlyEdited() {
807
+ const currentDocument = getCurrentDocument();
808
+ return currentDocument?.id === this.getComponentId();
1064
809
  }
1065
- ))), /* @__PURE__ */ React3.createElement(Grid, { container: true, gap: 0.75, alignItems: "start", px: 1.5, mb: 1.5 }, /* @__PURE__ */ React3.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React3.createElement(FormLabel, { size: "tiny" }, groupName)), /* @__PURE__ */ React3.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React3.createElement(
1066
- Select,
1067
- {
1068
- name: groupName,
1069
- size: SIZE,
1070
- fullWidth: true,
1071
- value: group ?? null,
1072
- onChange: (e) => setGroup(e.target.value),
1073
- displayEmpty: true,
1074
- renderValue: (selectedValue) => {
1075
- if (!selectedValue || selectedValue === "") {
1076
- const [firstGroup = DEFAULT_GROUP] = groups ?? [];
1077
- return firstGroup.label;
810
+ getRenderContext() {
811
+ const namespaceKey = this.getNamespaceKey();
812
+ const parentContext = this._parent?.getRenderContext?.();
813
+ const parentComponentContext = parentContext?.[namespaceKey];
814
+ if (!this.#componentRenderContext) {
815
+ return parentContext;
816
+ }
817
+ const ownOverrides = this.#componentRenderContext.overrides ?? {};
818
+ const parentOverrides = parentComponentContext?.overrides ?? {};
819
+ return {
820
+ ...parentContext,
821
+ [namespaceKey]: {
822
+ overrides: {
823
+ ...parentOverrides,
824
+ ...ownOverrides
825
+ }
826
+ }
827
+ };
828
+ }
829
+ getResolverRenderContext() {
830
+ const namespaceKey = this.getNamespaceKey();
831
+ const context = this.getRenderContext();
832
+ return context?.[namespaceKey];
833
+ }
834
+ afterSettingsResolve(settings) {
835
+ const componentInstance = settings.component_instance;
836
+ if (componentInstance) {
837
+ this.#componentRenderContext = {
838
+ overrides: componentInstance.overrides ?? {}
839
+ };
840
+ this.collection = legacyWindow.elementor.createBackboneElementsCollection(componentInstance.elements);
841
+ this.collection.models.forEach(setInactiveRecursively);
842
+ settings.component_instance = "<template data-children-placeholder></template>";
843
+ }
844
+ return settings;
845
+ }
846
+ getDomElement() {
847
+ return this.children.findByIndex(0)?.getDomElement() ?? this.$el;
848
+ }
849
+ attachBuffer(collectionView, buffer) {
850
+ const childrenPlaceholder = collectionView.$el.find("[data-children-placeholder]").get(0);
851
+ if (!childrenPlaceholder) {
852
+ super.attachBuffer(collectionView, buffer);
853
+ return;
854
+ }
855
+ childrenPlaceholder.replaceWith(buffer);
856
+ }
857
+ getComponentId() {
858
+ const componentInstance = this.options?.model?.get("settings")?.get("component_instance")?.value;
859
+ return componentInstance.component_id.value;
860
+ }
861
+ getContextMenuGroups() {
862
+ const filteredGroups = super.getContextMenuGroups().filter((group) => group.name !== "save");
863
+ const componentId = this.getComponentId();
864
+ if (!componentId) {
865
+ return filteredGroups;
866
+ }
867
+ const newGroups = updateGroups(
868
+ filteredGroups,
869
+ this._getContextMenuConfig()
870
+ );
871
+ return newGroups;
872
+ }
873
+ _getContextMenuConfig() {
874
+ const isAdministrator = isUserAdministrator();
875
+ const addedGroup = {
876
+ general: {
877
+ index: 1,
878
+ action: {
879
+ name: "edit component",
880
+ icon: "eicon-edit",
881
+ title: () => __2("Edit Component", "elementor"),
882
+ isEnabled: () => true,
883
+ callback: (_, eventData) => this.editComponent(eventData)
884
+ }
885
+ }
886
+ };
887
+ const disabledGroup = {
888
+ clipboard: ["pasteStyle", "resetStyle"]
889
+ };
890
+ return { add: isAdministrator ? addedGroup : {}, disable: disabledGroup };
891
+ }
892
+ async switchDocument() {
893
+ const { isAllowedToSwitchDocument, lockedBy } = await apiClient.getComponentLockStatus(
894
+ this.getComponentId()
895
+ );
896
+ if (!isAllowedToSwitchDocument) {
897
+ options.showLockedByModal?.(lockedBy || "");
898
+ } else {
899
+ switchToComponent(this.getComponentId(), this.model.get("id"), this.el);
900
+ }
901
+ }
902
+ editComponent({ trigger, location, secondaryLocation }) {
903
+ if (this.isComponentCurrentlyEdited()) {
904
+ return;
905
+ }
906
+ this.switchDocument();
907
+ const editorSettings = this.model.get("editor_settings");
908
+ trackComponentEvent({
909
+ action: "edited",
910
+ source: "user",
911
+ component_uid: editorSettings?.component_uid,
912
+ component_name: editorSettings?.title,
913
+ location,
914
+ secondary_location: secondaryLocation,
915
+ trigger
916
+ });
917
+ }
918
+ handleDblClick(e) {
919
+ e.stopPropagation();
920
+ const isAdministrator = isUserAdministrator();
921
+ if (!isAdministrator) {
922
+ return;
923
+ }
924
+ const { triggers, locations, secondaryLocations } = this.eventsManagerConfig;
925
+ this.editComponent({
926
+ trigger: triggers.doubleClick,
927
+ location: locations.canvas,
928
+ secondaryLocation: secondaryLocations.canvasElement
929
+ });
930
+ }
931
+ events() {
932
+ return {
933
+ ...super.events(),
934
+ dblclick: this.handleDblClick
935
+ };
936
+ }
937
+ attributes() {
938
+ return {
939
+ ...super.attributes(),
940
+ "data-elementor-id": this.getComponentId()
941
+ };
942
+ }
943
+ };
944
+ }
945
+ function setInactiveRecursively(model) {
946
+ const editSettings = model.get("editSettings");
947
+ if (editSettings) {
948
+ editSettings.set("inactive", true);
949
+ }
950
+ const elements = model.get("elements");
951
+ if (elements) {
952
+ elements.forEach((childModel) => {
953
+ setInactiveRecursively(childModel);
954
+ });
955
+ }
956
+ }
957
+ function isUserAdministrator() {
958
+ const legacyWindow = window;
959
+ return legacyWindow.elementor.config?.user?.is_administrator ?? false;
960
+ }
961
+ function createComponentModel() {
962
+ const legacyWindow = window;
963
+ const WidgetType = legacyWindow.elementor.modules.elements.types.Widget;
964
+ const widgetTypeInstance = new WidgetType();
965
+ const BaseWidgetModel = widgetTypeInstance.getModel();
966
+ return BaseWidgetModel.extend({
967
+ initialize(attributes, options) {
968
+ BaseWidgetModel.prototype.initialize.call(this, attributes, options);
969
+ const componentInstance = this.get("settings")?.get("component_instance");
970
+ if (componentInstance?.value) {
971
+ const componentId = componentInstance.value.component_id?.value;
972
+ if (componentId && typeof componentId === "number") {
973
+ this.set("componentId", componentId);
1078
974
  }
1079
- return groups?.find(({ value }) => value === selectedValue)?.label ?? selectedValue;
1080
975
  }
976
+ this.set("isGlobal", true);
1081
977
  },
1082
- (groups ?? [DEFAULT_GROUP]).map(({ label: groupLabel, ...props }) => /* @__PURE__ */ React3.createElement(MenuListItem, { key: props.value, ...props, value: props.value ?? "" }, groupLabel))
1083
- ))), /* @__PURE__ */ React3.createElement(Stack3, { direction: "row", justifyContent: "flex-end", alignSelf: "end", mt: 1.5, py: 1, px: 1.5 }, /* @__PURE__ */ React3.createElement(
1084
- Button2,
1085
- {
1086
- type: "submit",
1087
- disabled: !propLabel || Boolean(error),
1088
- variant: "contained",
1089
- color: "primary",
1090
- size: "small"
978
+ getTitle() {
979
+ const editorSettings = this.get("editor_settings");
980
+ const instanceTitle = editorSettings?.title;
981
+ if (instanceTitle) {
982
+ return instanceTitle;
983
+ }
984
+ const componentUid = editorSettings?.component_uid;
985
+ if (componentUid) {
986
+ const component = selectComponentByUid(getState5(), componentUid);
987
+ if (component?.name) {
988
+ return component.name;
989
+ }
990
+ }
991
+ return window.elementor.getElementData(this).title;
1091
992
  },
1092
- ctaLabel
1093
- ))));
993
+ getComponentId() {
994
+ return this.get("componentId") || null;
995
+ },
996
+ getComponentName() {
997
+ return this.getTitle();
998
+ },
999
+ getComponentUid() {
1000
+ const editorSettings = this.get("editor_settings");
1001
+ return editorSettings?.component_uid || null;
1002
+ }
1003
+ });
1094
1004
  }
1095
1005
 
1096
- // src/components/component-properties-panel/sortable.tsx
1097
- import * as React4 from "react";
1098
- import { GripVerticalIcon } from "@elementor/icons";
1099
- import {
1100
- Box as Box2,
1101
- styled,
1102
- UnstableSortableItem,
1103
- UnstableSortableProvider
1104
- } from "@elementor/ui";
1105
- var SortableProvider = (props) => /* @__PURE__ */ React4.createElement(UnstableSortableProvider, { restrictAxis: true, variant: "static", dragPlaceholderStyle: { opacity: "1" }, ...props });
1106
- var SortableTrigger = ({ triggerClassName, ...props }) => /* @__PURE__ */ React4.createElement(
1107
- StyledSortableTrigger,
1108
- {
1109
- ...props,
1110
- role: "button",
1111
- className: `sortable-trigger ${triggerClassName ?? ""}`.trim(),
1112
- "aria-label": "sort"
1113
- },
1114
- /* @__PURE__ */ React4.createElement(GripVerticalIcon, { fontSize: "tiny" })
1115
- );
1116
- var SortableItem = ({ children, id: id2 }) => /* @__PURE__ */ React4.createElement(
1117
- UnstableSortableItem,
1118
- {
1119
- id: id2,
1120
- render: ({
1121
- itemProps,
1122
- isDragged,
1123
- triggerProps,
1124
- itemStyle,
1125
- triggerStyle,
1126
- dropIndicationStyle,
1127
- showDropIndication,
1128
- isDragOverlay,
1129
- isDragPlaceholder
1130
- }) => /* @__PURE__ */ React4.createElement(
1131
- Box2,
1132
- {
1133
- ...itemProps,
1134
- style: itemStyle,
1135
- component: "div",
1136
- role: "listitem",
1137
- sx: {
1138
- backgroundColor: isDragOverlay ? "background.paper" : void 0
1139
- }
1140
- },
1141
- children({
1142
- isDragged,
1143
- isDragPlaceholder,
1144
- triggerProps,
1145
- triggerStyle
1146
- }),
1147
- showDropIndication && /* @__PURE__ */ React4.createElement(SortableItemIndicator, { style: dropIndicationStyle })
1148
- )
1149
- }
1150
- );
1151
- var StyledSortableTrigger = styled("div")(({ theme }) => ({
1152
- position: "absolute",
1153
- left: "-2px",
1154
- top: "50%",
1155
- transform: `translate( -${theme.spacing(1.5)}, -50% )`,
1156
- color: theme.palette.action.active,
1157
- cursor: "grab"
1158
- }));
1159
- var SortableItemIndicator = styled(Box2)`
1160
- width: 100%;
1161
- height: 1px;
1162
- background-color: ${({ theme }) => theme.palette.text.primary};
1163
- `;
1006
+ // src/utils/is-component-instance.ts
1007
+ function isComponentInstance(elementModel) {
1008
+ return [elementModel.widgetType, elementModel.elType].includes(COMPONENT_WIDGET_TYPE);
1009
+ }
1164
1010
 
1165
- // src/components/component-properties-panel/property-item.tsx
1166
- function PropertyItem({
1167
- prop,
1168
- sortableTriggerProps,
1169
- isDragPlaceholder,
1170
- groups,
1171
- existingLabels,
1172
- onDelete,
1173
- onUpdate
1174
- }) {
1175
- const popoverState = usePopupState({
1176
- variant: "popover"
1011
+ // src/utils/revert-element-overridable-setting.ts
1012
+ function revertElementOverridableSetting(elementId, settingKey, originValue, overrideKey) {
1013
+ const container = getContainer(elementId);
1014
+ if (!container) {
1015
+ return;
1016
+ }
1017
+ if (isComponentInstance(container.model.toJSON())) {
1018
+ revertComponentInstanceSetting(elementId, overrideKey);
1019
+ return;
1020
+ }
1021
+ updateElementSettings({
1022
+ id: elementId,
1023
+ props: { [settingKey]: originValue ?? null },
1024
+ withHistory: false
1177
1025
  });
1178
- const icon = getElementIcon(prop);
1179
- const popoverProps = bindPopover(popoverState);
1180
- const handleSubmit = (data) => {
1181
- onUpdate(data);
1182
- popoverState.close();
1183
- };
1184
- const handleDelete = (event) => {
1185
- event.stopPropagation();
1186
- onDelete(prop.overrideKey);
1187
- };
1188
- return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(
1189
- Box3,
1190
- {
1191
- ...bindTrigger(popoverState),
1192
- sx: {
1193
- position: "relative",
1194
- pl: 0.5,
1195
- pr: 1,
1196
- py: 0.25,
1197
- minHeight: 28,
1198
- borderRadius: 1,
1199
- border: "1px solid",
1200
- borderColor: "divider",
1201
- display: "flex",
1202
- alignItems: "center",
1203
- gap: 0.5,
1204
- opacity: isDragPlaceholder ? 0.5 : 1,
1205
- cursor: "pointer",
1206
- "&:hover": {
1207
- backgroundColor: "action.hover"
1208
- },
1209
- "&:hover .sortable-trigger": {
1210
- visibility: "visible"
1211
- },
1212
- "& .sortable-trigger": {
1213
- visibility: "hidden"
1214
- },
1215
- "&:hover .delete-button": {
1216
- visibility: "visible"
1217
- },
1218
- "& .delete-button": {
1219
- visibility: "hidden"
1220
- }
1026
+ }
1027
+ function revertComponentInstanceSetting(elementId, overrideKey) {
1028
+ const setting = getElementSetting(elementId, "component_instance");
1029
+ const componentInstance = componentInstancePropTypeUtil.extract(setting);
1030
+ const overrides = componentInstanceOverridesPropTypeUtil.extract(componentInstance?.overrides);
1031
+ if (!overrides) {
1032
+ return;
1033
+ }
1034
+ const updatedOverrides = getUpdatedComponentInstanceOverrides(overrides, overrideKey);
1035
+ const updatedSetting = componentInstancePropTypeUtil.create({
1036
+ ...componentInstance,
1037
+ overrides: componentInstanceOverridesPropTypeUtil.create(updatedOverrides)
1038
+ });
1039
+ updateElementSettings({
1040
+ id: elementId,
1041
+ props: { component_instance: updatedSetting },
1042
+ withHistory: false
1043
+ });
1044
+ }
1045
+ function getUpdatedComponentInstanceOverrides(overrides, overrideKey) {
1046
+ return overrides.map((item) => {
1047
+ const isOverridable = componentOverridablePropTypeUtil.isValid(item);
1048
+ if (!isOverridable) {
1049
+ return item;
1050
+ }
1051
+ const isOriginValueOverride2 = componentInstanceOverridePropTypeUtil.isValid(item.value.origin_value);
1052
+ if (!isOriginValueOverride2) {
1053
+ return null;
1054
+ }
1055
+ if (item.value.override_key !== overrideKey) {
1056
+ return item;
1057
+ }
1058
+ return item.value.origin_value;
1059
+ }).filter((item) => item !== null);
1060
+ }
1061
+
1062
+ // src/store/actions/delete-overridable-prop.ts
1063
+ function deleteOverridableProp({ componentId, propKey, source }) {
1064
+ const overridableProps = selectOverridableProps(getState6(), componentId);
1065
+ if (!overridableProps) {
1066
+ return;
1067
+ }
1068
+ const prop = overridableProps.props[propKey];
1069
+ if (!prop) {
1070
+ return;
1071
+ }
1072
+ revertElementOverridableSetting(prop.elementId, prop.propKey, prop.originValue, propKey);
1073
+ const { [propKey]: removedProp, ...remainingProps } = overridableProps.props;
1074
+ const updatedGroups = removePropFromAllGroups(overridableProps.groups, propKey);
1075
+ dispatch3(
1076
+ slice.actions.setOverridableProps({
1077
+ componentId,
1078
+ overridableProps: {
1079
+ ...overridableProps,
1080
+ props: remainingProps,
1081
+ groups: updatedGroups
1221
1082
  }
1222
- },
1223
- /* @__PURE__ */ React5.createElement(SortableTrigger, { ...sortableTriggerProps }),
1224
- /* @__PURE__ */ React5.createElement(
1225
- Box3,
1226
- {
1227
- sx: { display: "flex", alignItems: "center", color: "text.primary", fontSize: 12, padding: 0.25 }
1228
- },
1229
- /* @__PURE__ */ React5.createElement("i", { className: icon })
1230
- ),
1231
- /* @__PURE__ */ React5.createElement(Typography4, { variant: "caption", sx: { color: "text.primary", flexGrow: 1, fontSize: 10 } }, prop.label),
1232
- /* @__PURE__ */ React5.createElement(IconButton, { size: "tiny", onClick: handleDelete, "aria-label": "Delete property", sx: { p: 0.25 } }, /* @__PURE__ */ React5.createElement(XIcon, { fontSize: "tiny" }))
1233
- ), /* @__PURE__ */ React5.createElement(
1234
- Popover2,
1235
- {
1236
- ...popoverProps,
1237
- anchorOrigin: { vertical: "bottom", horizontal: "left" },
1238
- transformOrigin: { vertical: "top", horizontal: "left" },
1239
- PaperProps: { sx: { width: popoverState.anchorEl?.getBoundingClientRect().width } }
1240
- },
1241
- /* @__PURE__ */ React5.createElement(
1242
- OverridablePropForm,
1243
- {
1244
- onSubmit: handleSubmit,
1245
- currentValue: prop,
1246
- groups,
1247
- existingLabels,
1248
- sx: { width: "100%" }
1083
+ })
1084
+ );
1085
+ const currentComponent = selectCurrentComponent(getState6());
1086
+ trackComponentEvent({
1087
+ action: "propertyRemoved",
1088
+ source,
1089
+ component_uid: currentComponent?.uid,
1090
+ property_id: removedProp.overrideKey,
1091
+ property_path: removedProp.propKey,
1092
+ property_name: removedProp.label,
1093
+ element_type: removedProp.widgetType ?? removedProp.elType
1094
+ });
1095
+ }
1096
+
1097
+ // src/store/actions/reorder-group-props.ts
1098
+ import { __dispatch as dispatch4, __getState as getState7 } from "@elementor/store";
1099
+ function reorderGroupProps({ componentId, groupId, newPropsOrder }) {
1100
+ const overridableProps = selectOverridableProps(getState7(), componentId);
1101
+ if (!overridableProps) {
1102
+ return;
1103
+ }
1104
+ const group = overridableProps.groups.items[groupId];
1105
+ if (!group) {
1106
+ return;
1107
+ }
1108
+ dispatch4(
1109
+ slice.actions.setOverridableProps({
1110
+ componentId,
1111
+ overridableProps: {
1112
+ ...overridableProps,
1113
+ groups: {
1114
+ ...overridableProps.groups,
1115
+ items: {
1116
+ ...overridableProps.groups.items,
1117
+ [groupId]: {
1118
+ ...group,
1119
+ props: newPropsOrder
1120
+ }
1121
+ }
1122
+ }
1249
1123
  }
1250
- )
1251
- ));
1124
+ })
1125
+ );
1252
1126
  }
1253
- function getElementIcon(prop) {
1254
- const elType = prop.elType === "widget" ? prop.widgetType : prop.elType;
1255
- const widgetsCache = getWidgetsCache();
1256
- if (!widgetsCache) {
1257
- return "eicon-apps";
1127
+
1128
+ // src/store/actions/reorder-overridable-groups.ts
1129
+ import { __dispatch as dispatch5, __getState as getState8 } from "@elementor/store";
1130
+ function reorderOverridableGroups({ componentId, newOrder }) {
1131
+ const overridableProps = selectOverridableProps(getState8(), componentId);
1132
+ if (!overridableProps) {
1133
+ return;
1258
1134
  }
1259
- const widgetConfig = widgetsCache[elType];
1260
- return widgetConfig?.icon || "eicon-apps";
1135
+ dispatch5(
1136
+ slice.actions.setOverridableProps({
1137
+ componentId,
1138
+ overridableProps: {
1139
+ ...overridableProps,
1140
+ groups: {
1141
+ ...overridableProps.groups,
1142
+ order: newOrder
1143
+ }
1144
+ }
1145
+ })
1146
+ );
1261
1147
  }
1262
1148
 
1263
- // src/components/component-properties-panel/properties-group.tsx
1264
- function PropertiesGroup({
1265
- group,
1266
- props,
1267
- allGroups,
1268
- sortableTriggerProps,
1269
- isDragPlaceholder,
1270
- onPropsReorder,
1271
- onPropertyDelete,
1272
- onPropertyUpdate,
1273
- onGroupDelete,
1274
- editableLabelProps
1149
+ // src/store/actions/update-overridable-prop-params.ts
1150
+ import { __dispatch as dispatch6, __getState as getState9 } from "@elementor/store";
1151
+ function updateOverridablePropParams({
1152
+ componentId,
1153
+ overrideKey,
1154
+ label,
1155
+ groupId
1275
1156
  }) {
1276
- const groupProps = group.props.map((propId) => props[propId]).filter((prop) => Boolean(prop));
1277
- const popupState = usePopupState2({
1278
- variant: "popover",
1279
- disableAutoFocus: true
1280
- });
1281
- const { editableRef, isEditing, error, getEditableProps, setEditingGroupId, editingGroupId } = editableLabelProps;
1282
- const hasProperties = group.props.length > 0;
1283
- const isThisGroupEditing = isEditing && editingGroupId === group.id;
1284
- const handleRenameClick = () => {
1285
- popupState.close();
1286
- setEditingGroupId(group.id);
1287
- };
1288
- const handleDeleteClick = () => {
1289
- popupState.close();
1290
- onGroupDelete(group.id);
1157
+ const overridableProps = selectOverridableProps(getState9(), componentId);
1158
+ if (!overridableProps) {
1159
+ return;
1160
+ }
1161
+ const prop = overridableProps.props[overrideKey];
1162
+ if (!prop) {
1163
+ return;
1164
+ }
1165
+ const oldGroupId = prop.groupId;
1166
+ const newGroupId = groupId ?? oldGroupId;
1167
+ const updatedProp = {
1168
+ ...prop,
1169
+ label,
1170
+ groupId: newGroupId
1291
1171
  };
1292
- return /* @__PURE__ */ React6.createElement(
1293
- Box4,
1294
- {
1295
- sx: {
1296
- opacity: isDragPlaceholder ? 0.5 : 1
1172
+ const updatedGroups = movePropBetweenGroups(overridableProps.groups, overrideKey, oldGroupId, newGroupId);
1173
+ dispatch6(
1174
+ slice.actions.setOverridableProps({
1175
+ componentId,
1176
+ overridableProps: {
1177
+ ...overridableProps,
1178
+ props: {
1179
+ ...overridableProps.props,
1180
+ [overrideKey]: updatedProp
1181
+ },
1182
+ groups: updatedGroups
1297
1183
  }
1298
- },
1299
- /* @__PURE__ */ React6.createElement(Stack4, { gap: 1 }, /* @__PURE__ */ React6.createElement(
1300
- Box4,
1301
- {
1302
- className: "group-header",
1303
- sx: {
1304
- position: "relative",
1305
- "&:hover .group-sortable-trigger": {
1306
- visibility: "visible"
1307
- },
1308
- "& .group-sortable-trigger": {
1309
- visibility: "hidden"
1310
- },
1311
- "&:hover .group-menu": {
1312
- visibility: "visible"
1313
- },
1314
- "& .group-menu": {
1315
- visibility: "hidden"
1316
- }
1317
- }
1184
+ })
1185
+ );
1186
+ return updatedProp;
1187
+ }
1188
+
1189
+ // src/components/component-panel-header/use-overridable-props.ts
1190
+ import { __useSelector as useSelector3 } from "@elementor/store";
1191
+ function useOverridableProps2(componentId) {
1192
+ return useSelector3((state) => {
1193
+ if (!componentId) {
1194
+ return void 0;
1195
+ }
1196
+ return selectOverridableProps(state, componentId);
1197
+ });
1198
+ }
1199
+
1200
+ // src/components/component-properties-panel/properties-empty-state.tsx
1201
+ import * as React2 from "react";
1202
+ import { useState } from "react";
1203
+ import { ComponentPropListIcon } from "@elementor/icons";
1204
+ import { Link as Link2, Stack as Stack2, Typography as Typography2 } from "@elementor/ui";
1205
+ import { __ as __4 } from "@wordpress/i18n";
1206
+
1207
+ // src/components/components-tab/component-introduction.tsx
1208
+ import * as React from "react";
1209
+ import { PopoverContent } from "@elementor/editor-controls";
1210
+ import { PopoverHeader } from "@elementor/editor-ui";
1211
+ import { Box, Button, Image, Link, Popover, Stack, Typography } from "@elementor/ui";
1212
+ import { __ as __3 } from "@wordpress/i18n";
1213
+ var ComponentIntroduction = ({
1214
+ anchorRef,
1215
+ shouldShowIntroduction,
1216
+ onClose
1217
+ }) => {
1218
+ if (!anchorRef.current || !shouldShowIntroduction) {
1219
+ return null;
1220
+ }
1221
+ return /* @__PURE__ */ React.createElement(
1222
+ Popover,
1223
+ {
1224
+ anchorEl: anchorRef.current,
1225
+ open: shouldShowIntroduction,
1226
+ anchorOrigin: {
1227
+ vertical: "top",
1228
+ horizontal: "right"
1318
1229
  },
1319
- /* @__PURE__ */ React6.createElement(SortableTrigger, { triggerClassName: "group-sortable-trigger", ...sortableTriggerProps }),
1320
- /* @__PURE__ */ React6.createElement(Stack4, { direction: "row", alignItems: "center", justifyContent: "space-between", gap: 2 }, isThisGroupEditing ? /* @__PURE__ */ React6.createElement(
1321
- Box4,
1322
- {
1323
- sx: {
1324
- flex: 1,
1325
- height: 28,
1326
- display: "flex",
1327
- alignItems: "center",
1328
- border: 2,
1329
- borderColor: "text.secondary",
1330
- borderRadius: 1,
1331
- pl: 0.5
1332
- }
1333
- },
1334
- /* @__PURE__ */ React6.createElement(
1335
- EditableField,
1336
- {
1337
- ref: editableRef,
1338
- as: Typography5,
1339
- variant: "caption",
1340
- error: error ?? void 0,
1341
- sx: { color: "text.primary", fontWeight: 400, lineHeight: 1.66 },
1342
- ...getEditableProps()
1343
- }
1344
- )
1345
- ) : /* @__PURE__ */ React6.createElement(
1346
- Typography5,
1347
- {
1348
- variant: "caption",
1349
- sx: { color: "text.primary", fontWeight: 400, lineHeight: 1.66 }
1350
- },
1351
- group.label
1352
- ), /* @__PURE__ */ React6.createElement(
1353
- IconButton2,
1354
- {
1355
- className: "group-menu",
1356
- size: "tiny",
1357
- sx: { p: 0.25, visibility: isThisGroupEditing ? "visible" : void 0 },
1358
- "aria-label": __6("Group actions", "elementor"),
1359
- ...bindTrigger2(popupState)
1360
- },
1361
- /* @__PURE__ */ React6.createElement(DotsVerticalIcon, { fontSize: "tiny" })
1362
- ))
1363
- ), /* @__PURE__ */ React6.createElement(List, { sx: { p: 0, display: "flex", flexDirection: "column", gap: 1 } }, /* @__PURE__ */ React6.createElement(SortableProvider, { value: group.props, onChange: onPropsReorder }, groupProps.map((prop) => /* @__PURE__ */ React6.createElement(SortableItem, { key: prop.overrideKey, id: prop.overrideKey }, ({ triggerProps, triggerStyle, isDragPlaceholder: isItemDragPlaceholder }) => /* @__PURE__ */ React6.createElement(
1364
- PropertyItem,
1230
+ transformOrigin: {
1231
+ vertical: "top",
1232
+ horizontal: -30
1233
+ },
1234
+ onClose
1235
+ },
1236
+ /* @__PURE__ */ React.createElement(Box, { sx: { width: "296px" } }, /* @__PURE__ */ React.createElement(PopoverHeader, { title: __3("Add your first property", "elementor"), onClose }), /* @__PURE__ */ React.createElement(
1237
+ Image,
1365
1238
  {
1366
- prop,
1367
- sortableTriggerProps: { ...triggerProps, style: triggerStyle },
1368
- isDragPlaceholder: isItemDragPlaceholder,
1369
- groups: allGroups,
1370
- existingLabels: Object.values(props).map((p) => p.label),
1371
- onDelete: onPropertyDelete,
1372
- onUpdate: (data) => onPropertyUpdate(prop.overrideKey, data)
1239
+ sx: { width: "296px", height: "160px" },
1240
+ src: "https://assets.elementor.com/packages/v1/images/components-properties-intro.png",
1241
+ alt: ""
1373
1242
  }
1374
- )))))),
1375
- /* @__PURE__ */ React6.createElement(
1376
- Menu,
1243
+ ), /* @__PURE__ */ React.createElement(PopoverContent, null, /* @__PURE__ */ React.createElement(Stack, { sx: { p: 2 } }, /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, __3("Properties make instances flexible.", "elementor")), /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, __3(
1244
+ "Click next to any setting you want users to customize - like text, images, or links.",
1245
+ "elementor"
1246
+ )), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", sx: { mt: 2 } }, __3(
1247
+ "Your properties will appear in the Properties panel, where you can organize and manage them anytime.",
1248
+ "elementor"
1249
+ )), /* @__PURE__ */ React.createElement(
1250
+ Link,
1251
+ {
1252
+ href: "http://go.elementor.com/components-guide",
1253
+ target: "_blank",
1254
+ sx: { mt: 2 },
1255
+ color: "info.main",
1256
+ variant: "body2"
1257
+ },
1258
+ __3("Learn more", "elementor")
1259
+ ), /* @__PURE__ */ React.createElement(Stack, { direction: "row", alignItems: "center", justifyContent: "flex-end", sx: { pt: 1 } }, /* @__PURE__ */ React.createElement(Button, { size: "medium", variant: "contained", onClick: onClose }, __3("Got it", "elementor"))))))
1260
+ );
1261
+ };
1262
+
1263
+ // src/components/component-properties-panel/properties-empty-state.tsx
1264
+ function PropertiesEmptyState({ introductionRef }) {
1265
+ const [isOpen, setIsOpen] = useState(false);
1266
+ return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(
1267
+ Stack2,
1268
+ {
1269
+ alignItems: "center",
1270
+ justifyContent: "flex-start",
1271
+ height: "100%",
1272
+ color: "text.secondary",
1273
+ sx: { px: 2.5, pt: 10, pb: 5.5 },
1274
+ gap: 1
1275
+ },
1276
+ /* @__PURE__ */ React2.createElement(ComponentPropListIcon, { fontSize: "large" }),
1277
+ /* @__PURE__ */ React2.createElement(Typography2, { align: "center", variant: "subtitle2" }, __4("Add your first property", "elementor")),
1278
+ /* @__PURE__ */ React2.createElement(Typography2, { align: "center", variant: "caption" }, __4("Make instances flexible while keeping design synced.", "elementor")),
1279
+ /* @__PURE__ */ React2.createElement(Typography2, { align: "center", variant: "caption" }, __4("Select any element, then click + next to a setting to expose it.", "elementor")),
1280
+ /* @__PURE__ */ React2.createElement(
1281
+ Link2,
1377
1282
  {
1378
- ...bindMenu(popupState),
1379
- anchorOrigin: { vertical: "bottom", horizontal: "right" },
1380
- transformOrigin: { vertical: "top", horizontal: "right" }
1283
+ variant: "caption",
1284
+ color: "secondary",
1285
+ sx: { textDecorationLine: "underline" },
1286
+ onClick: () => setIsOpen(true)
1381
1287
  },
1382
- /* @__PURE__ */ React6.createElement(MenuListItem2, { sx: { minWidth: "160px" }, onClick: handleRenameClick }, /* @__PURE__ */ React6.createElement(Typography5, { variant: "caption", sx: { color: "text.primary" } }, __6("Rename", "elementor"))),
1383
- /* @__PURE__ */ React6.createElement(
1384
- Tooltip,
1385
- {
1386
- title: hasProperties ? __6("To delete the group, first remove all the properties", "elementor") : "",
1387
- placement: "right"
1388
- },
1389
- /* @__PURE__ */ React6.createElement("span", null, /* @__PURE__ */ React6.createElement(MenuListItem2, { onClick: handleDeleteClick, disabled: hasProperties }, /* @__PURE__ */ React6.createElement(
1390
- Typography5,
1391
- {
1392
- variant: "caption",
1393
- sx: { color: hasProperties ? "text.disabled" : "error.light" }
1394
- },
1395
- __6("Delete", "elementor")
1396
- )))
1397
- )
1288
+ __4("Learn more", "elementor")
1398
1289
  )
1399
- );
1290
+ ), /* @__PURE__ */ React2.createElement(
1291
+ ComponentIntroduction,
1292
+ {
1293
+ anchorRef: introductionRef,
1294
+ shouldShowIntroduction: isOpen,
1295
+ onClose: () => setIsOpen(false)
1296
+ }
1297
+ ));
1400
1298
  }
1401
1299
 
1402
- // src/components/component-properties-panel/use-current-editable-item.ts
1403
- import { useState as useState3 } from "react";
1404
- import { setDocumentModifiedStatus } from "@elementor/editor-documents";
1405
- import { useEditable } from "@elementor/editor-ui";
1406
- import { __ as __8 } from "@wordpress/i18n";
1300
+ // src/components/component-properties-panel/properties-group.tsx
1301
+ import * as React6 from "react";
1302
+ import { EditableField, MenuListItem as MenuListItem2 } from "@elementor/editor-ui";
1303
+ import { DotsVerticalIcon } from "@elementor/icons";
1304
+ import {
1305
+ bindMenu,
1306
+ bindTrigger as bindTrigger2,
1307
+ Box as Box4,
1308
+ IconButton as IconButton2,
1309
+ List,
1310
+ Menu,
1311
+ Stack as Stack4,
1312
+ Tooltip,
1313
+ Typography as Typography5,
1314
+ usePopupState as usePopupState2
1315
+ } from "@elementor/ui";
1316
+ import { __ as __7 } from "@wordpress/i18n";
1407
1317
 
1408
- // src/store/actions/rename-overridable-group.ts
1409
- import { __dispatch as dispatch7, __getState as getState9 } from "@elementor/store";
1410
- function renameOverridableGroup({ componentId, groupId, label }) {
1411
- const overridableProps = selectOverridableProps(getState9(), componentId);
1412
- if (!overridableProps) {
1413
- return false;
1414
- }
1415
- const group = overridableProps.groups.items[groupId];
1416
- if (!group) {
1417
- return false;
1418
- }
1419
- const updatedGroups = renameGroup(overridableProps.groups, groupId, label);
1420
- dispatch7(
1421
- slice.actions.setOverridableProps({
1422
- componentId,
1423
- overridableProps: {
1424
- ...overridableProps,
1425
- groups: updatedGroups
1426
- }
1427
- })
1428
- );
1429
- return true;
1430
- }
1318
+ // src/components/component-properties-panel/property-item.tsx
1319
+ import * as React5 from "react";
1320
+ import { getWidgetsCache } from "@elementor/editor-elements";
1321
+ import { XIcon } from "@elementor/icons";
1322
+ import { bindPopover, bindTrigger, Box as Box3, IconButton, Popover as Popover2, Typography as Typography4, usePopupState } from "@elementor/ui";
1431
1323
 
1432
- // src/components/component-properties-panel/utils/validate-group-label.ts
1433
- import { __ as __7 } from "@wordpress/i18n";
1434
- var ERROR_MESSAGES2 = {
1435
- EMPTY_NAME: __7("Group name is required", "elementor"),
1436
- DUPLICATE_NAME: __7("Group name already exists", "elementor")
1324
+ // src/components/overridable-props/overridable-prop-form.tsx
1325
+ import * as React3 from "react";
1326
+ import { useState as useState2 } from "react";
1327
+ import { Form, MenuListItem } from "@elementor/editor-ui";
1328
+ import { Button as Button2, FormLabel, Grid, Select, Stack as Stack3, TextField, Typography as Typography3 } from "@elementor/ui";
1329
+ import { __ as __6 } from "@wordpress/i18n";
1330
+
1331
+ // src/components/overridable-props/utils/validate-prop-label.ts
1332
+ import { __ as __5 } from "@wordpress/i18n";
1333
+ var ERROR_MESSAGES = {
1334
+ EMPTY_NAME: __5("Property name is required", "elementor"),
1335
+ DUPLICATE_NAME: __5("Property name already exists", "elementor")
1437
1336
  };
1438
- function validateGroupLabel(label, existingGroups) {
1337
+ function validatePropLabel(label, existingLabels, currentLabel) {
1439
1338
  const trimmedLabel = label.trim();
1440
1339
  if (!trimmedLabel) {
1441
- return ERROR_MESSAGES2.EMPTY_NAME;
1442
- }
1443
- const isDuplicate = Object.values(existingGroups).some((group) => group.label === trimmedLabel);
1444
- if (isDuplicate) {
1445
- return ERROR_MESSAGES2.DUPLICATE_NAME;
1340
+ return { isValid: false, errorMessage: ERROR_MESSAGES.EMPTY_NAME };
1446
1341
  }
1447
- return "";
1448
- }
1449
-
1450
- // src/components/component-properties-panel/use-current-editable-item.ts
1451
- function useCurrentEditableItem() {
1452
- const [editingGroupId, setEditingGroupId] = useState3(null);
1453
- const currentComponentId = useCurrentComponentId();
1454
- const overridableProps = useOverridableProps2(currentComponentId);
1455
- const allGroupsRecord = overridableProps?.groups?.items ?? {};
1456
- const currentGroup = editingGroupId ? allGroupsRecord[editingGroupId] : null;
1457
- const validateLabel = (newLabel) => {
1458
- const otherGroups = Object.fromEntries(
1459
- Object.entries(allGroupsRecord).filter(([id2]) => id2 !== editingGroupId)
1460
- );
1461
- return validateGroupLabel(newLabel, otherGroups) || null;
1462
- };
1463
- const handleSubmit = (newLabel) => {
1464
- if (!editingGroupId || !currentComponentId) {
1465
- throw new Error(__8("Group ID or component ID is missing", "elementor"));
1342
+ const normalizedLabel = trimmedLabel.toLowerCase();
1343
+ const normalizedCurrentLabel = currentLabel?.trim().toLowerCase();
1344
+ const isDuplicate = existingLabels.some((existingLabel) => {
1345
+ const normalizedExisting = existingLabel.trim().toLowerCase();
1346
+ if (normalizedCurrentLabel && normalizedExisting === normalizedCurrentLabel) {
1347
+ return false;
1466
1348
  }
1467
- renameOverridableGroup({
1468
- componentId: currentComponentId,
1469
- groupId: editingGroupId,
1470
- label: newLabel
1471
- });
1472
- setDocumentModifiedStatus(true);
1473
- };
1474
- const {
1475
- ref: editableRef,
1476
- openEditMode,
1477
- isEditing,
1478
- error,
1479
- getProps: getEditableProps
1480
- } = useEditable({
1481
- value: currentGroup?.label ?? "",
1482
- onSubmit: handleSubmit,
1483
- validation: validateLabel
1349
+ return normalizedExisting === normalizedLabel;
1484
1350
  });
1485
- return {
1486
- editableRef,
1487
- isEditing,
1488
- error,
1489
- getEditableProps,
1490
- setEditingGroupId: (groupId) => {
1491
- setEditingGroupId(groupId);
1492
- openEditMode();
1493
- },
1494
- editingGroupId
1495
- };
1496
- }
1497
-
1498
- // src/components/component-properties-panel/utils/generate-unique-label.ts
1499
- var DEFAULT_NEW_GROUP_LABEL = "New group";
1500
- function generateUniqueLabel(groups) {
1501
- const existingLabels = new Set(groups.map((group) => group.label));
1502
- if (!existingLabels.has(DEFAULT_NEW_GROUP_LABEL)) {
1503
- return DEFAULT_NEW_GROUP_LABEL;
1504
- }
1505
- let index = 1;
1506
- let newLabel = `${DEFAULT_NEW_GROUP_LABEL}-${index}`;
1507
- while (existingLabels.has(newLabel)) {
1508
- index++;
1509
- newLabel = `${DEFAULT_NEW_GROUP_LABEL}-${index}`;
1351
+ if (isDuplicate) {
1352
+ return { isValid: false, errorMessage: ERROR_MESSAGES.DUPLICATE_NAME };
1510
1353
  }
1511
- return newLabel;
1354
+ return { isValid: true, errorMessage: null };
1512
1355
  }
1513
-
1514
- // src/components/component-properties-panel/component-properties-panel-content.tsx
1515
- function ComponentPropertiesPanelContent({ onClose }) {
1516
- const currentComponentId = useCurrentComponentId();
1517
- const overridableProps = useOverridableProps2(currentComponentId);
1518
- const [isAddingGroup, setIsAddingGroup] = useState4(false);
1519
- const introductionRef = useRef(null);
1520
- const groupLabelEditable = useCurrentEditableItem();
1521
- const groups = useMemo(() => {
1522
- if (!overridableProps) {
1523
- return [];
1524
- }
1525
- return overridableProps.groups.order.map((groupId) => overridableProps.groups.items[groupId] ?? null).filter(Boolean);
1526
- }, [overridableProps]);
1527
- const allGroupsForSelect = useMemo(
1528
- () => groups.map((group) => ({ value: group.id, label: group.label })),
1529
- [groups]
1530
- );
1531
- if (!currentComponentId || !overridableProps) {
1532
- return null;
1533
- }
1534
- const hasGroups = groups.length > 0;
1535
- const showEmptyState = !hasGroups && !isAddingGroup;
1536
- const groupIds = overridableProps.groups.order;
1537
- const handleAddGroupClick = () => {
1538
- if (isAddingGroup) {
1539
- return;
1540
- }
1541
- const newGroupId = generateUniqueId2("group");
1542
- const newLabel = generateUniqueLabel(groups);
1543
- addOverridableGroup({
1544
- componentId: currentComponentId,
1545
- groupId: newGroupId,
1546
- label: newLabel,
1547
- source: "user"
1548
- });
1549
- setDocumentModifiedStatus2(true);
1550
- setIsAddingGroup(false);
1551
- groupLabelEditable.setEditingGroupId(newGroupId);
1552
- };
1553
- const handleGroupsReorder = (newOrder) => {
1554
- reorderOverridableGroups({ componentId: currentComponentId, newOrder });
1555
- setDocumentModifiedStatus2(true);
1556
- };
1557
- const handlePropsReorder = (groupId, newPropsOrder) => {
1558
- reorderGroupProps({ componentId: currentComponentId, groupId, newPropsOrder });
1559
- setDocumentModifiedStatus2(true);
1560
- };
1561
- const handlePropertyDelete = (propKey) => {
1562
- deleteOverridableProp({ componentId: currentComponentId, propKey, source: "user" });
1563
- setDocumentModifiedStatus2(true);
1564
- };
1565
- const handlePropertyUpdate = (overrideKey, data) => {
1566
- updateOverridablePropParams({
1567
- componentId: currentComponentId,
1568
- overrideKey,
1569
- label: data.label,
1570
- groupId: data.group
1571
- });
1572
- setDocumentModifiedStatus2(true);
1573
- };
1574
- const handleGroupDelete = (groupId) => {
1575
- deleteOverridableGroup({ componentId: currentComponentId, groupId });
1576
- setDocumentModifiedStatus2(true);
1356
+
1357
+ // src/components/overridable-props/overridable-prop-form.tsx
1358
+ var SIZE = "tiny";
1359
+ var DEFAULT_GROUP = { value: null, label: __6("Default", "elementor") };
1360
+ function OverridablePropForm({ onSubmit, groups, currentValue, existingLabels = [], sx }) {
1361
+ const [propLabel, setPropLabel] = useState2(currentValue?.label ?? null);
1362
+ const [group, setGroup] = useState2(currentValue?.groupId ?? groups?.[0]?.value ?? null);
1363
+ const [error, setError] = useState2(null);
1364
+ const name = __6("Name", "elementor");
1365
+ const groupName = __6("Group Name", "elementor");
1366
+ const isCreate = currentValue === void 0;
1367
+ const title = isCreate ? __6("Create new property", "elementor") : __6("Update property", "elementor");
1368
+ const ctaLabel = isCreate ? __6("Create", "elementor") : __6("Update", "elementor");
1369
+ const handleSubmit = () => {
1370
+ const validationResult = validatePropLabel(propLabel ?? "", existingLabels, currentValue?.label);
1371
+ if (!validationResult.isValid) {
1372
+ setError(validationResult.errorMessage);
1373
+ return;
1374
+ }
1375
+ onSubmit({ label: propLabel ?? "", group });
1577
1376
  };
1578
- return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(PanelHeader, { sx: { justifyContent: "start", pl: 1.5, pr: 1, py: 1 } }, /* @__PURE__ */ React7.createElement(Stack5, { direction: "row", alignItems: "center", gap: 0.5, flexGrow: 1 }, /* @__PURE__ */ React7.createElement(ComponentPropListIcon2, { fontSize: "tiny" }), /* @__PURE__ */ React7.createElement(PanelHeaderTitle, { variant: "subtitle2" }, __9("Component properties", "elementor"))), !showEmptyState && /* @__PURE__ */ React7.createElement(Tooltip2, { title: __9("Add new group", "elementor") }, /* @__PURE__ */ React7.createElement(
1579
- IconButton3,
1580
- {
1581
- size: "tiny",
1582
- "aria-label": __9("Add new group", "elementor"),
1583
- onClick: handleAddGroupClick
1584
- },
1585
- /* @__PURE__ */ React7.createElement(FolderPlusIcon, { fontSize: "tiny" })
1586
- )), /* @__PURE__ */ React7.createElement(Tooltip2, { title: __9("Close panel", "elementor") }, /* @__PURE__ */ React7.createElement(
1587
- IconButton3,
1377
+ return /* @__PURE__ */ React3.createElement(Form, { onSubmit: handleSubmit }, /* @__PURE__ */ React3.createElement(Stack3, { alignItems: "start", sx: { width: "268px", ...sx } }, /* @__PURE__ */ React3.createElement(
1378
+ Stack3,
1588
1379
  {
1589
- ref: introductionRef,
1590
- size: "tiny",
1591
- "aria-label": __9("Close panel", "elementor"),
1592
- onClick: onClose
1380
+ direction: "row",
1381
+ alignItems: "center",
1382
+ py: 1,
1383
+ px: 1.5,
1384
+ sx: { columnGap: 0.5, borderBottom: "1px solid", borderColor: "divider", width: "100%", mb: 1.5 }
1593
1385
  },
1594
- /* @__PURE__ */ React7.createElement(XIcon2, { fontSize: "tiny" })
1595
- ))), /* @__PURE__ */ React7.createElement(Divider, null), /* @__PURE__ */ React7.createElement(PanelBody, null, showEmptyState ? /* @__PURE__ */ React7.createElement(PropertiesEmptyState, { introductionRef }) : /* @__PURE__ */ React7.createElement(List2, { sx: { p: 2, display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ React7.createElement(SortableProvider, { value: groupIds, onChange: handleGroupsReorder }, groups.map((group) => /* @__PURE__ */ React7.createElement(SortableItem, { key: group.id, id: group.id }, ({ triggerProps, triggerStyle, isDragPlaceholder }) => /* @__PURE__ */ React7.createElement(
1596
- PropertiesGroup,
1386
+ /* @__PURE__ */ React3.createElement(Typography3, { variant: "caption", sx: { color: "text.primary", fontWeight: "500", lineHeight: 1 } }, title)
1387
+ ), /* @__PURE__ */ React3.createElement(Grid, { container: true, gap: 0.75, alignItems: "start", px: 1.5, mb: 1.5 }, /* @__PURE__ */ React3.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React3.createElement(FormLabel, { size: "tiny" }, name)), /* @__PURE__ */ React3.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React3.createElement(
1388
+ TextField,
1597
1389
  {
1598
- group,
1599
- props: overridableProps.props,
1600
- allGroups: allGroupsForSelect,
1601
- allGroupsRecord: overridableProps.groups.items,
1602
- sortableTriggerProps: { ...triggerProps, style: triggerStyle },
1603
- isDragPlaceholder,
1604
- setIsAddingGroup,
1605
- onPropsReorder: (newOrder) => handlePropsReorder(group.id, newOrder),
1606
- onPropertyDelete: handlePropertyDelete,
1607
- onPropertyUpdate: handlePropertyUpdate,
1608
- editableLabelProps: groupLabelEditable,
1609
- onGroupDelete: handleGroupDelete
1390
+ name,
1391
+ size: SIZE,
1392
+ fullWidth: true,
1393
+ placeholder: __6("Enter value", "elementor"),
1394
+ value: propLabel ?? "",
1395
+ onChange: (e) => {
1396
+ const newValue = e.target.value;
1397
+ setPropLabel(newValue);
1398
+ const validationResult = validatePropLabel(
1399
+ newValue,
1400
+ existingLabels,
1401
+ currentValue?.label
1402
+ );
1403
+ setError(validationResult.errorMessage);
1404
+ },
1405
+ error: Boolean(error),
1406
+ helperText: error
1610
1407
  }
1611
- )))))));
1612
- }
1613
-
1614
- // src/components/component-properties-panel/component-properties-panel.tsx
1615
- var id = "component-properties-panel";
1616
- var { panel, usePanelActions } = createPanel({
1617
- id,
1618
- component: ComponentPropertiesPanel
1619
- });
1620
- function ComponentPropertiesPanel() {
1621
- const { element, elementType } = useSelectedElement();
1622
- const { close: closePanel } = usePanelActions();
1623
- const { open: openEditingPanel } = useEditingPanelActions();
1624
- if (!element || !elementType) {
1625
- return null;
1626
- }
1627
- return /* @__PURE__ */ React8.createElement(ThemeProvider, null, /* @__PURE__ */ React8.createElement(ErrorBoundary, { fallback: /* @__PURE__ */ React8.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React8.createElement(ElementProvider, { element, elementType }, /* @__PURE__ */ React8.createElement(Panel, null, /* @__PURE__ */ React8.createElement(
1628
- ComponentPropertiesPanelContent,
1408
+ ))), /* @__PURE__ */ React3.createElement(Grid, { container: true, gap: 0.75, alignItems: "start", px: 1.5, mb: 1.5 }, /* @__PURE__ */ React3.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React3.createElement(FormLabel, { size: "tiny" }, groupName)), /* @__PURE__ */ React3.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React3.createElement(
1409
+ Select,
1629
1410
  {
1630
- onClose: () => {
1631
- closePanel();
1632
- openEditingPanel();
1411
+ name: groupName,
1412
+ size: SIZE,
1413
+ fullWidth: true,
1414
+ value: group ?? null,
1415
+ onChange: (e) => setGroup(e.target.value),
1416
+ displayEmpty: true,
1417
+ renderValue: (selectedValue) => {
1418
+ if (!selectedValue || selectedValue === "") {
1419
+ const [firstGroup = DEFAULT_GROUP] = groups ?? [];
1420
+ return firstGroup.label;
1421
+ }
1422
+ return groups?.find(({ value }) => value === selectedValue)?.label ?? selectedValue;
1633
1423
  }
1634
- }
1635
- )))));
1636
- }
1637
- var ErrorBoundaryFallback = () => /* @__PURE__ */ React8.createElement(Box5, { role: "alert", sx: { minHeight: "100%", p: 2 } }, /* @__PURE__ */ React8.createElement(Alert, { severity: "error", sx: { mb: 2, maxWidth: 400, textAlign: "center" } }, /* @__PURE__ */ React8.createElement("strong", null, __10("Something went wrong", "elementor"))));
1638
-
1639
- // src/components/component-panel-header/component-badge.tsx
1640
- import * as React9 from "react";
1641
- import { useEffect, useRef as useRef2 } from "react";
1642
- import { ComponentPropListIcon as ComponentPropListIcon3 } from "@elementor/icons";
1643
- import { Badge, Box as Box6, keyframes, styled as styled2, ToggleButton } from "@elementor/ui";
1644
- import { __ as __11 } from "@wordpress/i18n";
1645
- var ComponentsBadge = React9.forwardRef(({ overridablePropsCount, onClick }, ref) => {
1646
- const prevCount = usePrevious(overridablePropsCount);
1647
- const isFirstExposedProperty = prevCount === 0 && overridablePropsCount === 1;
1648
- return /* @__PURE__ */ React9.createElement(
1649
- StyledBadge,
1424
+ },
1425
+ (groups ?? [DEFAULT_GROUP]).map(({ label: groupLabel, ...props }) => /* @__PURE__ */ React3.createElement(MenuListItem, { key: props.value, ...props, value: props.value ?? "" }, groupLabel))
1426
+ ))), /* @__PURE__ */ React3.createElement(Stack3, { direction: "row", justifyContent: "flex-end", alignSelf: "end", mt: 1.5, py: 1, px: 1.5 }, /* @__PURE__ */ React3.createElement(
1427
+ Button2,
1650
1428
  {
1651
- ref,
1429
+ type: "submit",
1430
+ disabled: !propLabel || Boolean(error),
1431
+ variant: "contained",
1652
1432
  color: "primary",
1653
- key: overridablePropsCount,
1654
- invisible: overridablePropsCount === 0,
1655
- animate: isFirstExposedProperty,
1656
- anchorOrigin: { vertical: "top", horizontal: "right" },
1657
- badgeContent: /* @__PURE__ */ React9.createElement(Box6, { sx: { animation: !isFirstExposedProperty ? `${slideUp} 300ms ease-out` : "none" } }, overridablePropsCount)
1433
+ size: "small"
1658
1434
  },
1659
- /* @__PURE__ */ React9.createElement(
1660
- ToggleButton,
1435
+ ctaLabel
1436
+ ))));
1437
+ }
1438
+
1439
+ // src/components/component-properties-panel/sortable.tsx
1440
+ import * as React4 from "react";
1441
+ import { GripVerticalIcon } from "@elementor/icons";
1442
+ import {
1443
+ Box as Box2,
1444
+ styled,
1445
+ UnstableSortableItem,
1446
+ UnstableSortableProvider
1447
+ } from "@elementor/ui";
1448
+ var SortableProvider = (props) => /* @__PURE__ */ React4.createElement(UnstableSortableProvider, { restrictAxis: true, variant: "static", dragPlaceholderStyle: { opacity: "1" }, ...props });
1449
+ var SortableTrigger = ({ triggerClassName, ...props }) => /* @__PURE__ */ React4.createElement(
1450
+ StyledSortableTrigger,
1451
+ {
1452
+ ...props,
1453
+ role: "button",
1454
+ className: `sortable-trigger ${triggerClassName ?? ""}`.trim(),
1455
+ "aria-label": "sort"
1456
+ },
1457
+ /* @__PURE__ */ React4.createElement(GripVerticalIcon, { fontSize: "tiny" })
1458
+ );
1459
+ var SortableItem = ({ children, id: id2 }) => /* @__PURE__ */ React4.createElement(
1460
+ UnstableSortableItem,
1461
+ {
1462
+ id: id2,
1463
+ render: ({
1464
+ itemProps,
1465
+ isDragged,
1466
+ triggerProps,
1467
+ itemStyle,
1468
+ triggerStyle,
1469
+ dropIndicationStyle,
1470
+ showDropIndication,
1471
+ isDragOverlay,
1472
+ isDragPlaceholder
1473
+ }) => /* @__PURE__ */ React4.createElement(
1474
+ Box2,
1661
1475
  {
1662
- value: "exposed properties",
1663
- size: "tiny",
1664
- onClick,
1665
- "aria-label": __11("View exposed properties", "elementor")
1476
+ ...itemProps,
1477
+ style: itemStyle,
1478
+ component: "div",
1479
+ role: "listitem",
1480
+ sx: {
1481
+ backgroundColor: isDragOverlay ? "background.paper" : void 0
1482
+ }
1666
1483
  },
1667
- /* @__PURE__ */ React9.createElement(ComponentPropListIcon3, { fontSize: "tiny" })
1484
+ children({
1485
+ isDragged,
1486
+ isDragPlaceholder,
1487
+ triggerProps,
1488
+ triggerStyle
1489
+ }),
1490
+ showDropIndication && /* @__PURE__ */ React4.createElement(SortableItemIndicator, { style: dropIndicationStyle })
1668
1491
  )
1669
- );
1670
- });
1671
- var StyledBadge = styled2(Badge, { shouldForwardProp: (prop) => prop !== "animate" })(
1672
- ({ theme, animate }) => ({
1673
- "& .MuiBadge-badge": {
1674
- minWidth: theme.spacing(2),
1675
- height: theme.spacing(2),
1676
- minHeight: theme.spacing(2),
1677
- maxWidth: theme.spacing(2),
1678
- fontSize: theme.typography.caption.fontSize,
1679
- animation: animate ? `${bounceIn} 300ms ease-out` : "none"
1680
- }
1681
- })
1492
+ }
1682
1493
  );
1683
- function usePrevious(value) {
1684
- const ref = useRef2(value);
1685
- useEffect(() => {
1686
- ref.current = value;
1687
- }, [value]);
1688
- return ref.current;
1689
- }
1690
- var bounceIn = keyframes`
1691
- 0% { transform: scale(0) translate(50%, 50%); opacity: 0; }
1692
- 70% { transform: scale(1.1) translate(50%, -50%); opacity: 1; }
1693
- 100% { transform: scale(1) translate(50%, -50%); opacity: 1; }
1694
- `;
1695
- var slideUp = keyframes`
1696
- from { transform: translateY(100%); opacity: 0; }
1697
- to { transform: translateY(0); opacity: 1; }
1494
+ var StyledSortableTrigger = styled("div")(({ theme }) => ({
1495
+ position: "absolute",
1496
+ left: "-2px",
1497
+ top: "50%",
1498
+ transform: `translate( -${theme.spacing(1.5)}, -50% )`,
1499
+ color: theme.palette.action.active,
1500
+ cursor: "grab"
1501
+ }));
1502
+ var SortableItemIndicator = styled(Box2)`
1503
+ width: 100%;
1504
+ height: 1px;
1505
+ background-color: ${({ theme }) => theme.palette.text.primary};
1698
1506
  `;
1699
1507
 
1700
- // src/components/component-panel-header/component-panel-header.tsx
1701
- var MESSAGE_KEY = "components-properties-introduction";
1702
- var ComponentPanelHeader = () => {
1703
- const { id: currentComponentId, uid: componentUid } = useCurrentComponent() ?? { id: null, uid: null };
1704
- const overridableProps = useOverridableProps2(currentComponentId);
1705
- const onBack = useNavigateBack();
1706
- const componentName = getComponentName();
1707
- const [isMessageSuppressed, suppressMessage] = useSuppressedMessage(MESSAGE_KEY);
1708
- const [shouldShowIntroduction, setShouldShowIntroduction] = React10.useState(!isMessageSuppressed);
1709
- const { open: openPropertiesPanel } = usePanelActions();
1710
- const overridablePropsCount = overridableProps ? Object.keys(overridableProps.props).length : 0;
1711
- const anchorRef = React10.useRef(null);
1712
- if (!currentComponentId) {
1713
- return null;
1714
- }
1715
- const handleCloseIntroduction = () => {
1716
- suppressMessage();
1717
- setShouldShowIntroduction(false);
1508
+ // src/components/component-properties-panel/property-item.tsx
1509
+ function PropertyItem({
1510
+ prop,
1511
+ sortableTriggerProps,
1512
+ isDragPlaceholder,
1513
+ groups,
1514
+ existingLabels,
1515
+ onDelete,
1516
+ onUpdate
1517
+ }) {
1518
+ const popoverState = usePopupState({
1519
+ variant: "popover"
1520
+ });
1521
+ const icon = getElementIcon(prop);
1522
+ const popoverProps = bindPopover(popoverState);
1523
+ const handleSubmit = (data) => {
1524
+ onUpdate(data);
1525
+ popoverState.close();
1718
1526
  };
1719
- const handleOpenPropertiesPanel = () => {
1720
- openPropertiesPanel();
1721
- trackComponentEvent({
1722
- action: "propertiesPanelOpened",
1723
- source: "user",
1724
- component_uid: componentUid,
1725
- properties_count: overridablePropsCount
1726
- });
1527
+ const handleDelete = (event) => {
1528
+ event.stopPropagation();
1529
+ onDelete(prop.overrideKey);
1727
1530
  };
1728
- return /* @__PURE__ */ React10.createElement(Box7, null, /* @__PURE__ */ React10.createElement(
1729
- Stack6,
1531
+ return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(
1532
+ Box3,
1730
1533
  {
1731
- direction: "row",
1732
- alignItems: "center",
1733
- justifyContent: "space-between",
1734
- sx: { height: 48, pl: 1.5, pr: 2, py: 1 }
1534
+ ...bindTrigger(popoverState),
1535
+ sx: {
1536
+ position: "relative",
1537
+ pl: 0.5,
1538
+ pr: 1,
1539
+ py: 0.25,
1540
+ minHeight: 28,
1541
+ borderRadius: 1,
1542
+ border: "1px solid",
1543
+ borderColor: "divider",
1544
+ display: "flex",
1545
+ alignItems: "center",
1546
+ gap: 0.5,
1547
+ opacity: isDragPlaceholder ? 0.5 : 1,
1548
+ cursor: "pointer",
1549
+ "&:hover": {
1550
+ backgroundColor: "action.hover"
1551
+ },
1552
+ "&:hover .sortable-trigger": {
1553
+ visibility: "visible"
1554
+ },
1555
+ "& .sortable-trigger": {
1556
+ visibility: "hidden"
1557
+ },
1558
+ "&:hover .delete-button": {
1559
+ visibility: "visible"
1560
+ },
1561
+ "& .delete-button": {
1562
+ visibility: "hidden"
1563
+ }
1564
+ }
1735
1565
  },
1736
- /* @__PURE__ */ React10.createElement(Stack6, { direction: "row", alignItems: "center" }, /* @__PURE__ */ React10.createElement(Tooltip3, { title: __12("Back", "elementor") }, /* @__PURE__ */ React10.createElement(IconButton4, { size: "tiny", onClick: onBack, "aria-label": __12("Back", "elementor") }, /* @__PURE__ */ React10.createElement(ArrowLeftIcon, { fontSize: "tiny" }))), /* @__PURE__ */ React10.createElement(Stack6, { direction: "row", alignItems: "center", gap: 0.5 }, /* @__PURE__ */ React10.createElement(ComponentsFilledIcon, { fontSize: "tiny", stroke: "currentColor" }), /* @__PURE__ */ React10.createElement(Typography6, { variant: "caption", sx: { fontWeight: 500 } }, componentName))),
1737
- /* @__PURE__ */ React10.createElement(
1738
- ComponentsBadge,
1566
+ /* @__PURE__ */ React5.createElement(SortableTrigger, { ...sortableTriggerProps }),
1567
+ /* @__PURE__ */ React5.createElement(
1568
+ Box3,
1739
1569
  {
1740
- overridablePropsCount,
1741
- ref: anchorRef,
1742
- onClick: handleOpenPropertiesPanel
1570
+ sx: { display: "flex", alignItems: "center", color: "text.primary", fontSize: 12, padding: 0.25 }
1571
+ },
1572
+ /* @__PURE__ */ React5.createElement("i", { className: icon })
1573
+ ),
1574
+ /* @__PURE__ */ React5.createElement(Typography4, { variant: "caption", sx: { color: "text.primary", flexGrow: 1, fontSize: 10 } }, prop.label),
1575
+ /* @__PURE__ */ React5.createElement(IconButton, { size: "tiny", onClick: handleDelete, "aria-label": "Delete property", sx: { p: 0.25 } }, /* @__PURE__ */ React5.createElement(XIcon, { fontSize: "tiny" }))
1576
+ ), /* @__PURE__ */ React5.createElement(
1577
+ Popover2,
1578
+ {
1579
+ ...popoverProps,
1580
+ anchorOrigin: { vertical: "bottom", horizontal: "left" },
1581
+ transformOrigin: { vertical: "top", horizontal: "left" },
1582
+ PaperProps: { sx: { width: popoverState.anchorEl?.getBoundingClientRect().width } }
1583
+ },
1584
+ /* @__PURE__ */ React5.createElement(
1585
+ OverridablePropForm,
1586
+ {
1587
+ onSubmit: handleSubmit,
1588
+ currentValue: prop,
1589
+ groups,
1590
+ existingLabels,
1591
+ sx: { width: "100%" }
1743
1592
  }
1744
1593
  )
1745
- ), /* @__PURE__ */ React10.createElement(Divider2, null), /* @__PURE__ */ React10.createElement(
1746
- ComponentIntroduction,
1747
- {
1748
- anchorRef,
1749
- shouldShowIntroduction,
1750
- onClose: handleCloseIntroduction
1751
- }
1752
1594
  ));
1753
- };
1754
- function getComponentName() {
1755
- const state = getState10();
1756
- const path = state[SLICE_NAME].path;
1757
- const { instanceTitle } = path.at(-1) ?? {};
1758
- if (instanceTitle) {
1759
- return instanceTitle;
1595
+ }
1596
+ function getElementIcon(prop) {
1597
+ const elType = prop.elType === "widget" ? prop.widgetType : prop.elType;
1598
+ const widgetsCache = getWidgetsCache();
1599
+ if (!widgetsCache) {
1600
+ return "eicon-apps";
1760
1601
  }
1761
- const documentsManager = getV1DocumentsManager3();
1762
- const currentDocument = documentsManager.getCurrent();
1763
- return currentDocument?.container?.settings?.get("post_title") ?? "";
1602
+ const widgetConfig = widgetsCache[elType];
1603
+ return widgetConfig?.icon || "eicon-apps";
1764
1604
  }
1765
1605
 
1766
- // src/components/components-tab/components.tsx
1767
- import * as React19 from "react";
1768
- import { ThemeProvider as ThemeProvider2 } from "@elementor/editor-ui";
1769
-
1770
- // src/hooks/use-components.ts
1771
- import { __useSelector as useSelector4 } from "@elementor/store";
1772
- var useComponents = () => {
1773
- const components = useSelector4(selectComponents);
1774
- const isLoading = useSelector4(selectLoadIsPending);
1775
- return { components, isLoading };
1776
- };
1777
-
1778
- // src/utils/is-pro-user.ts
1779
- function isProUser() {
1780
- const extendedWindow = window;
1781
- const hasPro = extendedWindow.elementor?.helpers?.hasPro?.() ?? false;
1782
- if (!hasPro) {
1783
- return false;
1784
- }
1785
- const isProActive = extendedWindow.elementorPro?.config?.isActive ?? false;
1786
- return isProActive;
1606
+ // src/components/component-properties-panel/properties-group.tsx
1607
+ function PropertiesGroup({
1608
+ group,
1609
+ props,
1610
+ allGroups,
1611
+ sortableTriggerProps,
1612
+ isDragPlaceholder,
1613
+ onPropsReorder,
1614
+ onPropertyDelete,
1615
+ onPropertyUpdate,
1616
+ onGroupDelete,
1617
+ editableLabelProps
1618
+ }) {
1619
+ const groupProps = group.props.map((propId) => props[propId]).filter((prop) => Boolean(prop));
1620
+ const popupState = usePopupState2({
1621
+ variant: "popover",
1622
+ disableAutoFocus: true
1623
+ });
1624
+ const { editableRef, isEditing, error, getEditableProps, setEditingGroupId, editingGroupId } = editableLabelProps;
1625
+ const hasProperties = group.props.length > 0;
1626
+ const isThisGroupEditing = isEditing && editingGroupId === group.id;
1627
+ const handleRenameClick = () => {
1628
+ popupState.close();
1629
+ setEditingGroupId(group.id);
1630
+ };
1631
+ const handleDeleteClick = () => {
1632
+ popupState.close();
1633
+ onGroupDelete(group.id);
1634
+ };
1635
+ return /* @__PURE__ */ React6.createElement(
1636
+ Box4,
1637
+ {
1638
+ sx: {
1639
+ opacity: isDragPlaceholder ? 0.5 : 1
1640
+ }
1641
+ },
1642
+ /* @__PURE__ */ React6.createElement(Stack4, { gap: 1 }, /* @__PURE__ */ React6.createElement(
1643
+ Box4,
1644
+ {
1645
+ className: "group-header",
1646
+ sx: {
1647
+ position: "relative",
1648
+ "&:hover .group-sortable-trigger": {
1649
+ visibility: "visible"
1650
+ },
1651
+ "& .group-sortable-trigger": {
1652
+ visibility: "hidden"
1653
+ },
1654
+ "&:hover .group-menu": {
1655
+ visibility: "visible"
1656
+ },
1657
+ "& .group-menu": {
1658
+ visibility: "hidden"
1659
+ }
1660
+ }
1661
+ },
1662
+ /* @__PURE__ */ React6.createElement(SortableTrigger, { triggerClassName: "group-sortable-trigger", ...sortableTriggerProps }),
1663
+ /* @__PURE__ */ React6.createElement(Stack4, { direction: "row", alignItems: "center", justifyContent: "space-between", gap: 2 }, isThisGroupEditing ? /* @__PURE__ */ React6.createElement(
1664
+ Box4,
1665
+ {
1666
+ sx: {
1667
+ flex: 1,
1668
+ height: 28,
1669
+ display: "flex",
1670
+ alignItems: "center",
1671
+ border: 2,
1672
+ borderColor: "text.secondary",
1673
+ borderRadius: 1,
1674
+ pl: 0.5
1675
+ }
1676
+ },
1677
+ /* @__PURE__ */ React6.createElement(
1678
+ EditableField,
1679
+ {
1680
+ ref: editableRef,
1681
+ as: Typography5,
1682
+ variant: "caption",
1683
+ error: error ?? void 0,
1684
+ sx: { color: "text.primary", fontWeight: 400, lineHeight: 1.66 },
1685
+ ...getEditableProps()
1686
+ }
1687
+ )
1688
+ ) : /* @__PURE__ */ React6.createElement(
1689
+ Typography5,
1690
+ {
1691
+ variant: "caption",
1692
+ sx: { color: "text.primary", fontWeight: 400, lineHeight: 1.66 }
1693
+ },
1694
+ group.label
1695
+ ), /* @__PURE__ */ React6.createElement(
1696
+ IconButton2,
1697
+ {
1698
+ className: "group-menu",
1699
+ size: "tiny",
1700
+ sx: { p: 0.25, visibility: isThisGroupEditing ? "visible" : void 0 },
1701
+ "aria-label": __7("Group actions", "elementor"),
1702
+ ...bindTrigger2(popupState)
1703
+ },
1704
+ /* @__PURE__ */ React6.createElement(DotsVerticalIcon, { fontSize: "tiny" })
1705
+ ))
1706
+ ), /* @__PURE__ */ React6.createElement(List, { sx: { p: 0, display: "flex", flexDirection: "column", gap: 1 } }, /* @__PURE__ */ React6.createElement(SortableProvider, { value: group.props, onChange: onPropsReorder }, groupProps.map((prop) => /* @__PURE__ */ React6.createElement(SortableItem, { key: prop.overrideKey, id: prop.overrideKey }, ({ triggerProps, triggerStyle, isDragPlaceholder: isItemDragPlaceholder }) => /* @__PURE__ */ React6.createElement(
1707
+ PropertyItem,
1708
+ {
1709
+ prop,
1710
+ sortableTriggerProps: { ...triggerProps, style: triggerStyle },
1711
+ isDragPlaceholder: isItemDragPlaceholder,
1712
+ groups: allGroups,
1713
+ existingLabels: Object.values(props).map((p) => p.label),
1714
+ onDelete: onPropertyDelete,
1715
+ onUpdate: (data) => onPropertyUpdate(prop.overrideKey, data)
1716
+ }
1717
+ )))))),
1718
+ /* @__PURE__ */ React6.createElement(
1719
+ Menu,
1720
+ {
1721
+ ...bindMenu(popupState),
1722
+ anchorOrigin: { vertical: "bottom", horizontal: "right" },
1723
+ transformOrigin: { vertical: "top", horizontal: "right" }
1724
+ },
1725
+ /* @__PURE__ */ React6.createElement(MenuListItem2, { sx: { minWidth: "160px" }, onClick: handleRenameClick }, /* @__PURE__ */ React6.createElement(Typography5, { variant: "caption", sx: { color: "text.primary" } }, __7("Rename", "elementor"))),
1726
+ /* @__PURE__ */ React6.createElement(
1727
+ Tooltip,
1728
+ {
1729
+ title: hasProperties ? __7("To delete the group, first remove all the properties", "elementor") : "",
1730
+ placement: "right"
1731
+ },
1732
+ /* @__PURE__ */ React6.createElement("span", null, /* @__PURE__ */ React6.createElement(MenuListItem2, { onClick: handleDeleteClick, disabled: hasProperties }, /* @__PURE__ */ React6.createElement(
1733
+ Typography5,
1734
+ {
1735
+ variant: "caption",
1736
+ sx: { color: hasProperties ? "text.disabled" : "error.light" }
1737
+ },
1738
+ __7("Delete", "elementor")
1739
+ )))
1740
+ )
1741
+ )
1742
+ );
1787
1743
  }
1788
1744
 
1789
- // src/components/components-tab/component-search.tsx
1790
- import * as React12 from "react";
1791
- import { SearchIcon } from "@elementor/icons";
1792
- import { Box as Box8, InputAdornment, Stack as Stack7, TextField as TextField2 } from "@elementor/ui";
1793
- import { __ as __13 } from "@wordpress/i18n";
1745
+ // src/components/component-properties-panel/use-current-editable-item.ts
1746
+ import { useState as useState3 } from "react";
1747
+ import { setDocumentModifiedStatus } from "@elementor/editor-documents";
1748
+ import { useEditable } from "@elementor/editor-ui";
1749
+ import { __ as __9 } from "@wordpress/i18n";
1794
1750
 
1795
- // src/components/components-tab/search-provider.tsx
1796
- import * as React11 from "react";
1797
- import { createContext, useContext } from "react";
1798
- import { useSearchState } from "@elementor/utils";
1799
- var SearchContext = createContext(void 0);
1800
- var SearchProvider = ({
1801
- children,
1802
- localStorageKey
1803
- }) => {
1804
- const { debouncedValue, handleChange, inputValue } = useSearchState({ localStorageKey });
1805
- const clearSearch = () => {
1806
- handleChange("");
1807
- };
1808
- return /* @__PURE__ */ React11.createElement(SearchContext.Provider, { value: { handleChange, clearSearch, searchValue: debouncedValue, inputValue } }, children);
1809
- };
1810
- var useSearch = () => {
1811
- const context = useContext(SearchContext);
1812
- if (!context) {
1813
- throw new Error("useSearch must be used within a SearchProvider");
1751
+ // src/store/actions/rename-overridable-group.ts
1752
+ import { __dispatch as dispatch7, __getState as getState10 } from "@elementor/store";
1753
+ function renameOverridableGroup({ componentId, groupId, label }) {
1754
+ const overridableProps = selectOverridableProps(getState10(), componentId);
1755
+ if (!overridableProps) {
1756
+ return false;
1814
1757
  }
1815
- return context;
1816
- };
1817
-
1818
- // src/components/components-tab/component-search.tsx
1819
- var ComponentSearch = () => {
1820
- const { inputValue, handleChange } = useSearch();
1821
- return /* @__PURE__ */ React12.createElement(Stack7, { direction: "row", gap: 0.5, sx: { width: "100%", px: 2, py: 1.5 } }, /* @__PURE__ */ React12.createElement(Box8, { sx: { flexGrow: 1 } }, /* @__PURE__ */ React12.createElement(
1822
- TextField2,
1823
- {
1824
- role: "search",
1825
- fullWidth: true,
1826
- size: "tiny",
1827
- value: inputValue,
1828
- placeholder: __13("Search", "elementor"),
1829
- onChange: (e) => handleChange(e.target.value),
1830
- InputProps: {
1831
- startAdornment: /* @__PURE__ */ React12.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React12.createElement(SearchIcon, { fontSize: "tiny" }))
1758
+ const group = overridableProps.groups.items[groupId];
1759
+ if (!group) {
1760
+ return false;
1761
+ }
1762
+ const updatedGroups = renameGroup(overridableProps.groups, groupId, label);
1763
+ dispatch7(
1764
+ slice.actions.setOverridableProps({
1765
+ componentId,
1766
+ overridableProps: {
1767
+ ...overridableProps,
1768
+ groups: updatedGroups
1832
1769
  }
1833
- }
1834
- )));
1835
- };
1836
-
1837
- // src/components/components-tab/components-list.tsx
1838
- import * as React17 from "react";
1839
- import { useState as useState7 } from "react";
1840
- import { getAngieSdk } from "@elementor/editor-mcp";
1841
- import { AIIcon, ComponentsIcon as ComponentsIcon2 } from "@elementor/icons";
1842
- import { Box as Box11, Button as Button4, Divider as Divider3, Link as Link3, List as List3, Stack as Stack10, Typography as Typography9 } from "@elementor/ui";
1843
- import { __ as __20 } from "@wordpress/i18n";
1770
+ })
1771
+ );
1772
+ return true;
1773
+ }
1844
1774
 
1845
- // src/hooks/use-components-permissions.ts
1846
- import { useCurrentUserCapabilities } from "@elementor/editor-current-user";
1847
- var useComponentsPermissions = () => {
1848
- const { isAdmin } = useCurrentUserCapabilities();
1849
- return {
1850
- canCreate: isAdmin,
1851
- canEdit: isAdmin,
1852
- canDelete: isAdmin,
1853
- canRename: isAdmin
1854
- };
1775
+ // src/components/component-properties-panel/utils/validate-group-label.ts
1776
+ import { __ as __8 } from "@wordpress/i18n";
1777
+ var ERROR_MESSAGES2 = {
1778
+ EMPTY_NAME: __8("Group name is required", "elementor"),
1779
+ DUPLICATE_NAME: __8("Group name already exists", "elementor")
1855
1780
  };
1781
+ function validateGroupLabel(label, existingGroups) {
1782
+ const trimmedLabel = label.trim();
1783
+ if (!trimmedLabel) {
1784
+ return ERROR_MESSAGES2.EMPTY_NAME;
1785
+ }
1786
+ const isDuplicate = Object.values(existingGroups).some((group) => group.label === trimmedLabel);
1787
+ if (isDuplicate) {
1788
+ return ERROR_MESSAGES2.DUPLICATE_NAME;
1789
+ }
1790
+ return "";
1791
+ }
1856
1792
 
1857
- // src/store/actions/rename-component.ts
1858
- import { getV1DocumentsManager as getV1DocumentsManager4, setDocumentModifiedStatus as setDocumentModifiedStatus3 } from "@elementor/editor-documents";
1859
- import { getAllDescendants } from "@elementor/editor-elements";
1860
- import { __dispatch as dispatch8 } from "@elementor/store";
1861
-
1862
- // src/create-component-type.ts
1863
- import {
1864
- createTemplatedElementView
1865
- } from "@elementor/editor-canvas";
1866
- import { getCurrentDocument } from "@elementor/editor-documents";
1867
- import { __getState as getState11 } from "@elementor/store";
1868
- import { __ as __14 } from "@wordpress/i18n";
1869
- var COMPONENT_WIDGET_TYPE = "e-component";
1870
- var updateGroups = (groups, config) => {
1871
- const disableMap = new Map(Object.entries(config.disable ?? {}));
1872
- const addMap = new Map(Object.entries(config.add ?? {}));
1873
- return groups.map((group) => {
1874
- const disabledActions = disableMap.get(group.name) ?? [];
1875
- const addConfig = addMap.get(group.name);
1876
- const updatedActions = group.actions.map(
1877
- (action) => disabledActions.includes(action.name) ? { ...action, isEnabled: () => false } : action
1793
+ // src/components/component-properties-panel/use-current-editable-item.ts
1794
+ function useCurrentEditableItem() {
1795
+ const [editingGroupId, setEditingGroupId] = useState3(null);
1796
+ const currentComponentId = useCurrentComponentId();
1797
+ const overridableProps = useOverridableProps2(currentComponentId);
1798
+ const allGroupsRecord = overridableProps?.groups?.items ?? {};
1799
+ const currentGroup = editingGroupId ? allGroupsRecord[editingGroupId] : null;
1800
+ const validateLabel = (newLabel) => {
1801
+ const otherGroups = Object.fromEntries(
1802
+ Object.entries(allGroupsRecord).filter(([id2]) => id2 !== editingGroupId)
1878
1803
  );
1879
- if (addConfig) {
1880
- updatedActions.splice(addConfig.index, 0, addConfig.action);
1881
- }
1882
- return { ...group, actions: updatedActions };
1883
- });
1884
- };
1885
- function createComponentType(options) {
1886
- const legacyWindow = window;
1887
- const WidgetType = legacyWindow.elementor.modules.elements.types.Widget;
1888
- const view = createComponentView({ ...options });
1889
- return class extends WidgetType {
1890
- getType() {
1891
- return options.type;
1892
- }
1893
- getView() {
1894
- return view;
1895
- }
1896
- getModel() {
1897
- return createComponentModel();
1898
- }
1804
+ return validateGroupLabel(newLabel, otherGroups) || null;
1899
1805
  };
1900
- }
1901
- function createComponentView(options) {
1902
- const legacyWindow = window;
1903
- return class extends createTemplatedElementView(options) {
1904
- eventsManagerConfig = legacyWindow.elementorCommon.eventsManager.config;
1905
- #componentRenderContext;
1906
- isComponentCurrentlyEdited() {
1907
- const currentDocument = getCurrentDocument();
1908
- return currentDocument?.id === this.getComponentId();
1909
- }
1910
- getRenderContext() {
1911
- const namespaceKey = this.getNamespaceKey();
1912
- const parentContext = this._parent?.getRenderContext?.();
1913
- const parentComponentContext = parentContext?.[namespaceKey];
1914
- if (!this.#componentRenderContext) {
1915
- return parentContext;
1916
- }
1917
- const ownOverrides = this.#componentRenderContext.overrides ?? {};
1918
- const parentOverrides = parentComponentContext?.overrides ?? {};
1919
- return {
1920
- ...parentContext,
1921
- [namespaceKey]: {
1922
- overrides: {
1923
- ...parentOverrides,
1924
- ...ownOverrides
1925
- }
1926
- }
1927
- };
1928
- }
1929
- getResolverRenderContext() {
1930
- const namespaceKey = this.getNamespaceKey();
1931
- const context = this.getRenderContext();
1932
- return context?.[namespaceKey];
1933
- }
1934
- afterSettingsResolve(settings) {
1935
- const componentInstance = settings.component_instance;
1936
- if (componentInstance) {
1937
- this.#componentRenderContext = {
1938
- overrides: componentInstance.overrides ?? {}
1939
- };
1940
- this.collection = legacyWindow.elementor.createBackboneElementsCollection(componentInstance.elements);
1941
- this.collection.models.forEach(setInactiveRecursively);
1942
- settings.component_instance = "<template data-children-placeholder></template>";
1943
- }
1944
- return settings;
1945
- }
1946
- getDomElement() {
1947
- return this.children.findByIndex(0)?.getDomElement() ?? this.$el;
1948
- }
1949
- attachBuffer(collectionView, buffer) {
1950
- const childrenPlaceholder = collectionView.$el.find("[data-children-placeholder]").get(0);
1951
- if (!childrenPlaceholder) {
1952
- super.attachBuffer(collectionView, buffer);
1953
- return;
1954
- }
1955
- childrenPlaceholder.replaceWith(buffer);
1956
- }
1957
- getComponentId() {
1958
- const componentInstance = this.options?.model?.get("settings")?.get("component_instance")?.value;
1959
- return componentInstance.component_id.value;
1960
- }
1961
- getContextMenuGroups() {
1962
- const filteredGroups = super.getContextMenuGroups().filter((group) => group.name !== "save");
1963
- const componentId = this.getComponentId();
1964
- if (!componentId) {
1965
- return filteredGroups;
1966
- }
1967
- const newGroups = updateGroups(
1968
- filteredGroups,
1969
- this._getContextMenuConfig()
1970
- );
1971
- return newGroups;
1806
+ const handleSubmit = (newLabel) => {
1807
+ if (!editingGroupId || !currentComponentId) {
1808
+ throw new Error(__9("Group ID or component ID is missing", "elementor"));
1972
1809
  }
1973
- _getContextMenuConfig() {
1974
- const isAdministrator = isUserAdministrator();
1975
- const addedGroup = {
1976
- general: {
1977
- index: 1,
1978
- action: {
1979
- name: "edit component",
1980
- icon: "eicon-edit",
1981
- title: () => __14("Edit Component", "elementor"),
1982
- isEnabled: () => true,
1983
- callback: (_, eventData) => this.editComponent(eventData)
1984
- }
1985
- }
1986
- };
1987
- const disabledGroup = {
1988
- clipboard: ["pasteStyle", "resetStyle"]
1989
- };
1990
- return { add: isAdministrator ? addedGroup : {}, disable: disabledGroup };
1810
+ renameOverridableGroup({
1811
+ componentId: currentComponentId,
1812
+ groupId: editingGroupId,
1813
+ label: newLabel
1814
+ });
1815
+ setDocumentModifiedStatus(true);
1816
+ };
1817
+ const {
1818
+ ref: editableRef,
1819
+ openEditMode,
1820
+ isEditing,
1821
+ error,
1822
+ getProps: getEditableProps
1823
+ } = useEditable({
1824
+ value: currentGroup?.label ?? "",
1825
+ onSubmit: handleSubmit,
1826
+ validation: validateLabel
1827
+ });
1828
+ return {
1829
+ editableRef,
1830
+ isEditing,
1831
+ error,
1832
+ getEditableProps,
1833
+ setEditingGroupId: (groupId) => {
1834
+ setEditingGroupId(groupId);
1835
+ openEditMode();
1836
+ },
1837
+ editingGroupId
1838
+ };
1839
+ }
1840
+
1841
+ // src/components/component-properties-panel/utils/generate-unique-label.ts
1842
+ var DEFAULT_NEW_GROUP_LABEL = "New group";
1843
+ function generateUniqueLabel(groups) {
1844
+ const existingLabels = new Set(groups.map((group) => group.label));
1845
+ if (!existingLabels.has(DEFAULT_NEW_GROUP_LABEL)) {
1846
+ return DEFAULT_NEW_GROUP_LABEL;
1847
+ }
1848
+ let index = 1;
1849
+ let newLabel = `${DEFAULT_NEW_GROUP_LABEL}-${index}`;
1850
+ while (existingLabels.has(newLabel)) {
1851
+ index++;
1852
+ newLabel = `${DEFAULT_NEW_GROUP_LABEL}-${index}`;
1853
+ }
1854
+ return newLabel;
1855
+ }
1856
+
1857
+ // src/components/component-properties-panel/component-properties-panel-content.tsx
1858
+ function ComponentPropertiesPanelContent({ onClose }) {
1859
+ const currentComponentId = useCurrentComponentId();
1860
+ const overridableProps = useOverridableProps2(currentComponentId);
1861
+ const [isAddingGroup, setIsAddingGroup] = useState4(false);
1862
+ const introductionRef = useRef(null);
1863
+ const groupLabelEditable = useCurrentEditableItem();
1864
+ const groups = useMemo(() => {
1865
+ if (!overridableProps) {
1866
+ return [];
1991
1867
  }
1992
- async switchDocument() {
1993
- const { isAllowedToSwitchDocument, lockedBy } = await apiClient.getComponentLockStatus(
1994
- this.getComponentId()
1995
- );
1996
- if (!isAllowedToSwitchDocument) {
1997
- options.showLockedByModal?.(lockedBy || "");
1998
- } else {
1999
- switchToComponent(this.getComponentId(), this.model.get("id"), this.el);
2000
- }
1868
+ return overridableProps.groups.order.map((groupId) => overridableProps.groups.items[groupId] ?? null).filter(Boolean);
1869
+ }, [overridableProps]);
1870
+ const allGroupsForSelect = useMemo(
1871
+ () => groups.map((group) => ({ value: group.id, label: group.label })),
1872
+ [groups]
1873
+ );
1874
+ if (!currentComponentId || !overridableProps) {
1875
+ return null;
1876
+ }
1877
+ const hasGroups = groups.length > 0;
1878
+ const showEmptyState = !hasGroups && !isAddingGroup;
1879
+ const groupIds = overridableProps.groups.order;
1880
+ const handleAddGroupClick = () => {
1881
+ if (isAddingGroup) {
1882
+ return;
2001
1883
  }
2002
- editComponent({ trigger, location, secondaryLocation }) {
2003
- if (this.isComponentCurrentlyEdited()) {
2004
- return;
2005
- }
2006
- this.switchDocument();
2007
- const editorSettings = this.model.get("editor_settings");
2008
- trackComponentEvent({
2009
- action: "edited",
2010
- source: "user",
2011
- component_uid: editorSettings?.component_uid,
2012
- component_name: editorSettings?.title,
2013
- location,
2014
- secondary_location: secondaryLocation,
2015
- trigger
2016
- });
1884
+ const newGroupId = generateUniqueId2("group");
1885
+ const newLabel = generateUniqueLabel(groups);
1886
+ addOverridableGroup({
1887
+ componentId: currentComponentId,
1888
+ groupId: newGroupId,
1889
+ label: newLabel,
1890
+ source: "user"
1891
+ });
1892
+ setDocumentModifiedStatus2(true);
1893
+ setIsAddingGroup(false);
1894
+ groupLabelEditable.setEditingGroupId(newGroupId);
1895
+ };
1896
+ const handleGroupsReorder = (newOrder) => {
1897
+ reorderOverridableGroups({ componentId: currentComponentId, newOrder });
1898
+ setDocumentModifiedStatus2(true);
1899
+ };
1900
+ const handlePropsReorder = (groupId, newPropsOrder) => {
1901
+ reorderGroupProps({ componentId: currentComponentId, groupId, newPropsOrder });
1902
+ setDocumentModifiedStatus2(true);
1903
+ };
1904
+ const handlePropertyDelete = (propKey) => {
1905
+ deleteOverridableProp({ componentId: currentComponentId, propKey, source: "user" });
1906
+ setDocumentModifiedStatus2(true);
1907
+ };
1908
+ const handlePropertyUpdate = (overrideKey, data) => {
1909
+ updateOverridablePropParams({
1910
+ componentId: currentComponentId,
1911
+ overrideKey,
1912
+ label: data.label,
1913
+ groupId: data.group
1914
+ });
1915
+ setDocumentModifiedStatus2(true);
1916
+ };
1917
+ const handleGroupDelete = (groupId) => {
1918
+ deleteOverridableGroup({ componentId: currentComponentId, groupId });
1919
+ setDocumentModifiedStatus2(true);
1920
+ };
1921
+ return /* @__PURE__ */ React7.createElement(React7.Fragment, null, /* @__PURE__ */ React7.createElement(PanelHeader, { sx: { justifyContent: "start", pl: 1.5, pr: 1, py: 1 } }, /* @__PURE__ */ React7.createElement(Stack5, { direction: "row", alignItems: "center", gap: 0.5, flexGrow: 1 }, /* @__PURE__ */ React7.createElement(ComponentPropListIcon2, { fontSize: "tiny" }), /* @__PURE__ */ React7.createElement(PanelHeaderTitle, { variant: "subtitle2" }, __10("Component properties", "elementor"))), !showEmptyState && /* @__PURE__ */ React7.createElement(Tooltip2, { title: __10("Add new group", "elementor") }, /* @__PURE__ */ React7.createElement(
1922
+ IconButton3,
1923
+ {
1924
+ size: "tiny",
1925
+ "aria-label": __10("Add new group", "elementor"),
1926
+ onClick: handleAddGroupClick
1927
+ },
1928
+ /* @__PURE__ */ React7.createElement(FolderPlusIcon, { fontSize: "tiny" })
1929
+ )), /* @__PURE__ */ React7.createElement(Tooltip2, { title: __10("Close panel", "elementor") }, /* @__PURE__ */ React7.createElement(
1930
+ IconButton3,
1931
+ {
1932
+ ref: introductionRef,
1933
+ size: "tiny",
1934
+ "aria-label": __10("Close panel", "elementor"),
1935
+ onClick: onClose
1936
+ },
1937
+ /* @__PURE__ */ React7.createElement(XIcon2, { fontSize: "tiny" })
1938
+ ))), /* @__PURE__ */ React7.createElement(Divider, null), /* @__PURE__ */ React7.createElement(PanelBody, null, showEmptyState ? /* @__PURE__ */ React7.createElement(PropertiesEmptyState, { introductionRef }) : /* @__PURE__ */ React7.createElement(List2, { sx: { p: 2, display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ React7.createElement(SortableProvider, { value: groupIds, onChange: handleGroupsReorder }, groups.map((group) => /* @__PURE__ */ React7.createElement(SortableItem, { key: group.id, id: group.id }, ({ triggerProps, triggerStyle, isDragPlaceholder }) => /* @__PURE__ */ React7.createElement(
1939
+ PropertiesGroup,
1940
+ {
1941
+ group,
1942
+ props: overridableProps.props,
1943
+ allGroups: allGroupsForSelect,
1944
+ allGroupsRecord: overridableProps.groups.items,
1945
+ sortableTriggerProps: { ...triggerProps, style: triggerStyle },
1946
+ isDragPlaceholder,
1947
+ setIsAddingGroup,
1948
+ onPropsReorder: (newOrder) => handlePropsReorder(group.id, newOrder),
1949
+ onPropertyDelete: handlePropertyDelete,
1950
+ onPropertyUpdate: handlePropertyUpdate,
1951
+ editableLabelProps: groupLabelEditable,
1952
+ onGroupDelete: handleGroupDelete
2017
1953
  }
2018
- handleDblClick(e) {
2019
- e.stopPropagation();
2020
- const isAdministrator = isUserAdministrator();
2021
- if (!isAdministrator) {
2022
- return;
1954
+ )))))));
1955
+ }
1956
+
1957
+ // src/components/component-properties-panel/component-properties-panel.tsx
1958
+ var id = "component-properties-panel";
1959
+ var { panel, usePanelActions } = createPanel({
1960
+ id,
1961
+ component: ComponentPropertiesPanel
1962
+ });
1963
+ function ComponentPropertiesPanel() {
1964
+ const { element, elementType } = useSelectedElement();
1965
+ const { close: closePanel } = usePanelActions();
1966
+ const { open: openEditingPanel } = useEditingPanelActions();
1967
+ if (!element || !elementType) {
1968
+ return null;
1969
+ }
1970
+ return /* @__PURE__ */ React8.createElement(ThemeProvider, null, /* @__PURE__ */ React8.createElement(ErrorBoundary, { fallback: /* @__PURE__ */ React8.createElement(ErrorBoundaryFallback, null) }, /* @__PURE__ */ React8.createElement(ElementProvider, { element, elementType }, /* @__PURE__ */ React8.createElement(Panel, null, /* @__PURE__ */ React8.createElement(
1971
+ ComponentPropertiesPanelContent,
1972
+ {
1973
+ onClose: () => {
1974
+ closePanel();
1975
+ openEditingPanel();
2023
1976
  }
2024
- const { triggers, locations, secondaryLocations } = this.eventsManagerConfig;
2025
- this.editComponent({
2026
- trigger: triggers.doubleClick,
2027
- location: locations.canvas,
2028
- secondaryLocation: secondaryLocations.canvasElement
2029
- });
2030
- }
2031
- events() {
2032
- return {
2033
- ...super.events(),
2034
- dblclick: this.handleDblClick
2035
- };
2036
1977
  }
2037
- attributes() {
2038
- return {
2039
- ...super.attributes(),
2040
- "data-elementor-id": this.getComponentId()
2041
- };
1978
+ )))));
1979
+ }
1980
+ var ErrorBoundaryFallback = () => /* @__PURE__ */ React8.createElement(Box5, { role: "alert", sx: { minHeight: "100%", p: 2 } }, /* @__PURE__ */ React8.createElement(Alert, { severity: "error", sx: { mb: 2, maxWidth: 400, textAlign: "center" } }, /* @__PURE__ */ React8.createElement("strong", null, __11("Something went wrong", "elementor"))));
1981
+
1982
+ // src/components/component-panel-header/component-badge.tsx
1983
+ import * as React9 from "react";
1984
+ import { useEffect, useRef as useRef2 } from "react";
1985
+ import { ComponentPropListIcon as ComponentPropListIcon3 } from "@elementor/icons";
1986
+ import { Badge, Box as Box6, keyframes, styled as styled2, ToggleButton, Tooltip as Tooltip3 } from "@elementor/ui";
1987
+ import { __ as __12 } from "@wordpress/i18n";
1988
+ var ComponentsBadge = React9.forwardRef(({ overridablePropsCount, onClick }, ref) => {
1989
+ const prevCount = usePrevious(overridablePropsCount);
1990
+ const isFirstExposedProperty = prevCount === 0 && overridablePropsCount === 1;
1991
+ return /* @__PURE__ */ React9.createElement(
1992
+ StyledBadge,
1993
+ {
1994
+ ref,
1995
+ color: "primary",
1996
+ key: overridablePropsCount,
1997
+ invisible: overridablePropsCount === 0,
1998
+ animate: isFirstExposedProperty,
1999
+ anchorOrigin: { vertical: "top", horizontal: "right" },
2000
+ badgeContent: /* @__PURE__ */ React9.createElement(Box6, { sx: { animation: !isFirstExposedProperty ? `${slideUp} 300ms ease-out` : "none" } }, overridablePropsCount)
2001
+ },
2002
+ /* @__PURE__ */ React9.createElement(Tooltip3, { title: __12("Component properties", "elementor") }, /* @__PURE__ */ React9.createElement(
2003
+ ToggleButton,
2004
+ {
2005
+ value: "exposed properties",
2006
+ size: "tiny",
2007
+ onClick,
2008
+ "aria-label": __12("Component properties", "elementor")
2009
+ },
2010
+ /* @__PURE__ */ React9.createElement(ComponentPropListIcon3, { fontSize: "tiny" })
2011
+ ))
2012
+ );
2013
+ });
2014
+ var StyledBadge = styled2(Badge, { shouldForwardProp: (prop) => prop !== "animate" })(
2015
+ ({ theme, animate }) => ({
2016
+ "& .MuiBadge-badge": {
2017
+ minWidth: theme.spacing(2),
2018
+ height: theme.spacing(2),
2019
+ minHeight: theme.spacing(2),
2020
+ maxWidth: theme.spacing(2),
2021
+ fontSize: theme.typography.caption.fontSize,
2022
+ animation: animate ? `${bounceIn} 300ms ease-out` : "none"
2042
2023
  }
2043
- };
2024
+ })
2025
+ );
2026
+ function usePrevious(value) {
2027
+ const ref = useRef2(value);
2028
+ useEffect(() => {
2029
+ ref.current = value;
2030
+ }, [value]);
2031
+ return ref.current;
2044
2032
  }
2045
- function setInactiveRecursively(model) {
2046
- const editSettings = model.get("editSettings");
2047
- if (editSettings) {
2048
- editSettings.set("inactive", true);
2033
+ var bounceIn = keyframes`
2034
+ 0% { transform: scale(0) translate(50%, 50%); opacity: 0; }
2035
+ 70% { transform: scale(1.1) translate(50%, -50%); opacity: 1; }
2036
+ 100% { transform: scale(1) translate(50%, -50%); opacity: 1; }
2037
+ `;
2038
+ var slideUp = keyframes`
2039
+ from { transform: translateY(100%); opacity: 0; }
2040
+ to { transform: translateY(0); opacity: 1; }
2041
+ `;
2042
+
2043
+ // src/components/component-panel-header/component-panel-header.tsx
2044
+ var MESSAGE_KEY = "components-properties-introduction";
2045
+ var ComponentPanelHeader = () => {
2046
+ const { id: currentComponentId, uid: componentUid } = useCurrentComponent() ?? { id: null, uid: null };
2047
+ const overridableProps = useOverridableProps2(currentComponentId);
2048
+ const onBack = useNavigateBack();
2049
+ const componentName = getComponentName();
2050
+ const [isMessageSuppressed, suppressMessage] = useSuppressedMessage(MESSAGE_KEY);
2051
+ const [shouldShowIntroduction, setShouldShowIntroduction] = React10.useState(!isMessageSuppressed);
2052
+ const { open: openPropertiesPanel } = usePanelActions();
2053
+ const overridablePropsCount = overridableProps ? Object.keys(overridableProps.props).length : 0;
2054
+ const anchorRef = React10.useRef(null);
2055
+ if (!currentComponentId) {
2056
+ return null;
2049
2057
  }
2050
- const elements = model.get("elements");
2051
- if (elements) {
2052
- elements.forEach((childModel) => {
2053
- setInactiveRecursively(childModel);
2058
+ const handleCloseIntroduction = () => {
2059
+ suppressMessage();
2060
+ setShouldShowIntroduction(false);
2061
+ };
2062
+ const handleOpenPropertiesPanel = () => {
2063
+ openPropertiesPanel();
2064
+ trackComponentEvent({
2065
+ action: "propertiesPanelOpened",
2066
+ source: "user",
2067
+ component_uid: componentUid,
2068
+ properties_count: overridablePropsCount
2054
2069
  });
2070
+ };
2071
+ return /* @__PURE__ */ React10.createElement(Box7, null, /* @__PURE__ */ React10.createElement(
2072
+ Stack6,
2073
+ {
2074
+ direction: "row",
2075
+ alignItems: "center",
2076
+ justifyContent: "space-between",
2077
+ sx: { height: 48, pl: 1.5, pr: 2, py: 1 }
2078
+ },
2079
+ /* @__PURE__ */ React10.createElement(Stack6, { direction: "row", alignItems: "center" }, /* @__PURE__ */ React10.createElement(Tooltip4, { title: __13("Back", "elementor") }, /* @__PURE__ */ React10.createElement(IconButton4, { size: "tiny", onClick: onBack, "aria-label": __13("Back", "elementor") }, /* @__PURE__ */ React10.createElement(ArrowLeftIcon, { fontSize: "tiny" }))), /* @__PURE__ */ React10.createElement(Stack6, { direction: "row", alignItems: "center", gap: 0.5 }, /* @__PURE__ */ React10.createElement(ComponentsFilledIcon, { fontSize: "tiny", stroke: "currentColor" }), /* @__PURE__ */ React10.createElement(Typography6, { variant: "caption", sx: { fontWeight: 500 } }, componentName))),
2080
+ /* @__PURE__ */ React10.createElement(
2081
+ ComponentsBadge,
2082
+ {
2083
+ overridablePropsCount,
2084
+ ref: anchorRef,
2085
+ onClick: handleOpenPropertiesPanel
2086
+ }
2087
+ )
2088
+ ), /* @__PURE__ */ React10.createElement(Divider2, null), /* @__PURE__ */ React10.createElement(
2089
+ ComponentIntroduction,
2090
+ {
2091
+ anchorRef,
2092
+ shouldShowIntroduction,
2093
+ onClose: handleCloseIntroduction
2094
+ }
2095
+ ));
2096
+ };
2097
+ function getComponentName() {
2098
+ const state = getState11();
2099
+ const path = state[SLICE_NAME].path;
2100
+ const { instanceTitle } = path.at(-1) ?? {};
2101
+ if (instanceTitle) {
2102
+ return instanceTitle;
2055
2103
  }
2104
+ const documentsManager = getV1DocumentsManager3();
2105
+ const currentDocument = documentsManager.getCurrent();
2106
+ return currentDocument?.container?.settings?.get("post_title") ?? "";
2056
2107
  }
2057
- function isUserAdministrator() {
2058
- const legacyWindow = window;
2059
- return legacyWindow.elementor.config?.user?.is_administrator ?? false;
2108
+
2109
+ // src/components/components-tab/components.tsx
2110
+ import * as React19 from "react";
2111
+ import { ThemeProvider as ThemeProvider2 } from "@elementor/editor-ui";
2112
+
2113
+ // src/hooks/use-components.ts
2114
+ import { __useSelector as useSelector4 } from "@elementor/store";
2115
+ var useComponents = () => {
2116
+ const components = useSelector4(selectComponents);
2117
+ const isLoading = useSelector4(selectLoadIsPending);
2118
+ return { components, isLoading };
2119
+ };
2120
+
2121
+ // src/utils/is-pro-user.ts
2122
+ function isProUser() {
2123
+ const extendedWindow = window;
2124
+ const hasPro = extendedWindow.elementor?.helpers?.hasPro?.() ?? false;
2125
+ if (!hasPro) {
2126
+ return false;
2127
+ }
2128
+ const isProActive = extendedWindow.elementorPro?.config?.isActive ?? false;
2129
+ return isProActive;
2060
2130
  }
2061
- function createComponentModel() {
2062
- const legacyWindow = window;
2063
- const WidgetType = legacyWindow.elementor.modules.elements.types.Widget;
2064
- const widgetTypeInstance = new WidgetType();
2065
- const BaseWidgetModel = widgetTypeInstance.getModel();
2066
- return BaseWidgetModel.extend({
2067
- initialize(attributes, options) {
2068
- BaseWidgetModel.prototype.initialize.call(this, attributes, options);
2069
- const componentInstance = this.get("settings")?.get("component_instance");
2070
- if (componentInstance?.value) {
2071
- const componentId = componentInstance.value.component_id?.value;
2072
- if (componentId && typeof componentId === "number") {
2073
- this.set("componentId", componentId);
2074
- }
2075
- }
2076
- this.set("isGlobal", true);
2077
- },
2078
- getTitle() {
2079
- const editorSettings = this.get("editor_settings");
2080
- const instanceTitle = editorSettings?.title;
2081
- if (instanceTitle) {
2082
- return instanceTitle;
2083
- }
2084
- const componentUid = editorSettings?.component_uid;
2085
- if (componentUid) {
2086
- const component = selectComponentByUid(getState11(), componentUid);
2087
- if (component?.name) {
2088
- return component.name;
2089
- }
2131
+
2132
+ // src/components/components-tab/component-search.tsx
2133
+ import * as React12 from "react";
2134
+ import { SearchIcon } from "@elementor/icons";
2135
+ import { Box as Box8, InputAdornment, Stack as Stack7, TextField as TextField2 } from "@elementor/ui";
2136
+ import { __ as __14 } from "@wordpress/i18n";
2137
+
2138
+ // src/components/components-tab/search-provider.tsx
2139
+ import * as React11 from "react";
2140
+ import { createContext, useContext } from "react";
2141
+ import { useSearchState } from "@elementor/utils";
2142
+ var SearchContext = createContext(void 0);
2143
+ var SearchProvider = ({
2144
+ children,
2145
+ localStorageKey
2146
+ }) => {
2147
+ const { debouncedValue, handleChange, inputValue } = useSearchState({ localStorageKey });
2148
+ const clearSearch = () => {
2149
+ handleChange("");
2150
+ };
2151
+ return /* @__PURE__ */ React11.createElement(SearchContext.Provider, { value: { handleChange, clearSearch, searchValue: debouncedValue, inputValue } }, children);
2152
+ };
2153
+ var useSearch = () => {
2154
+ const context = useContext(SearchContext);
2155
+ if (!context) {
2156
+ throw new Error("useSearch must be used within a SearchProvider");
2157
+ }
2158
+ return context;
2159
+ };
2160
+
2161
+ // src/components/components-tab/component-search.tsx
2162
+ var ComponentSearch = () => {
2163
+ const { inputValue, handleChange } = useSearch();
2164
+ return /* @__PURE__ */ React12.createElement(Stack7, { direction: "row", gap: 0.5, sx: { width: "100%", px: 2, py: 1.5 } }, /* @__PURE__ */ React12.createElement(Box8, { sx: { flexGrow: 1 } }, /* @__PURE__ */ React12.createElement(
2165
+ TextField2,
2166
+ {
2167
+ role: "search",
2168
+ fullWidth: true,
2169
+ size: "tiny",
2170
+ value: inputValue,
2171
+ placeholder: __14("Search", "elementor"),
2172
+ onChange: (e) => handleChange(e.target.value),
2173
+ InputProps: {
2174
+ startAdornment: /* @__PURE__ */ React12.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React12.createElement(SearchIcon, { fontSize: "tiny" }))
2090
2175
  }
2091
- return window.elementor.getElementData(this).title;
2092
- },
2093
- getComponentId() {
2094
- return this.get("componentId") || null;
2095
- },
2096
- getComponentName() {
2097
- return this.getTitle();
2098
- },
2099
- getComponentUid() {
2100
- const editorSettings = this.get("editor_settings");
2101
- return editorSettings?.component_uid || null;
2102
2176
  }
2103
- });
2104
- }
2177
+ )));
2178
+ };
2179
+
2180
+ // src/components/components-tab/components-list.tsx
2181
+ import * as React17 from "react";
2182
+ import { useState as useState7 } from "react";
2183
+ import { getAngieSdk } from "@elementor/editor-mcp";
2184
+ import { AIIcon, ComponentsIcon as ComponentsIcon2 } from "@elementor/icons";
2185
+ import { Box as Box11, Button as Button4, Divider as Divider3, Link as Link3, List as List3, Stack as Stack10, Typography as Typography9 } from "@elementor/ui";
2186
+ import { __ as __20 } from "@wordpress/i18n";
2187
+
2188
+ // src/hooks/use-components-permissions.ts
2189
+ import { useCurrentUserCapabilities } from "@elementor/editor-current-user";
2190
+ var useComponentsPermissions = () => {
2191
+ const { isAdmin } = useCurrentUserCapabilities();
2192
+ return {
2193
+ canCreate: isAdmin,
2194
+ canEdit: isAdmin,
2195
+ canDelete: isAdmin,
2196
+ canRename: isAdmin
2197
+ };
2198
+ };
2105
2199
 
2106
2200
  // src/store/actions/rename-component.ts
2201
+ import { getV1DocumentsManager as getV1DocumentsManager4, setDocumentModifiedStatus as setDocumentModifiedStatus3 } from "@elementor/editor-documents";
2202
+ import { getAllDescendants } from "@elementor/editor-elements";
2203
+ import { __dispatch as dispatch8 } from "@elementor/store";
2107
2204
  var TITLE_EXTERNAL_CHANGE_COMMAND = "title_external_change";
2108
2205
  var renameComponent = (componentUid, newName) => {
2109
2206
  dispatch8(slice.actions.rename({ componentUid, name: newName }));
@@ -2222,11 +2319,6 @@ var archiveComponent = (componentId, componentName) => {
2222
2319
  // src/store/actions/load-components-assets.ts
2223
2320
  import { isDocumentDirty, setDocumentModifiedStatus as setDocumentModifiedStatus5 } from "@elementor/editor-documents";
2224
2321
 
2225
- // src/utils/is-component-instance.ts
2226
- function isComponentInstance(elementModel) {
2227
- return [elementModel.widgetType, elementModel.elType].includes(COMPONENT_WIDGET_TYPE);
2228
- }
2229
-
2230
2322
  // src/utils/get-component-ids.ts
2231
2323
  var getComponentIds = async (elements) => {
2232
2324
  const components = elements.map(async ({ widgetType, elType, elements: childElements, settings }) => {
@@ -2331,13 +2423,13 @@ async function updateDocumentState(componentIds) {
2331
2423
  import { __getState as getState14 } from "@elementor/store";
2332
2424
 
2333
2425
  // src/components/create-component-form/utils/component-form-schema.ts
2334
- import { z } from "@elementor/schema";
2426
+ import { z as z5 } from "@elementor/schema";
2335
2427
  import { __ as __17 } from "@wordpress/i18n";
2336
2428
  var MIN_NAME_LENGTH = 2;
2337
2429
  var MAX_NAME_LENGTH = 50;
2338
- var baseComponentSchema = z.string().trim().max(MAX_NAME_LENGTH, __17("Component name is too long. Please keep it under 50 characters.", "elementor"));
2430
+ var baseComponentSchema = z5.string().trim().max(MAX_NAME_LENGTH, __17("Component name is too long. Please keep it under 50 characters.", "elementor"));
2339
2431
  var createBaseComponentSchema = (existingNames) => {
2340
- return z.object({
2432
+ return z5.object({
2341
2433
  componentName: baseComponentSchema.refine((value) => !existingNames.includes(value), {
2342
2434
  message: __17("Component name already exists", "elementor")
2343
2435
  })
@@ -3561,66 +3653,12 @@ import { useSelectedElement as useSelectedElement2 } from "@elementor/editor-ele
3561
3653
  import { PanelBody as PanelBody2, PanelHeader as PanelHeader2, PanelHeaderTitle as PanelHeaderTitle2 } from "@elementor/editor-panels";
3562
3654
  import { EllipsisWithTooltip as EllipsisWithTooltip2 } from "@elementor/editor-ui";
3563
3655
  import { ComponentsIcon as ComponentsIcon4, PencilIcon as PencilIcon2 } from "@elementor/icons";
3564
- import { Divider as Divider4, IconButton as IconButton6, Stack as Stack17, Tooltip as Tooltip4 } from "@elementor/ui";
3656
+ import { Divider as Divider4, IconButton as IconButton6, Stack as Stack17, Tooltip as Tooltip5 } from "@elementor/ui";
3565
3657
  import { __ as __27 } from "@wordpress/i18n";
3566
3658
 
3567
3659
  // src/hooks/use-component-instance-settings.ts
3568
3660
  import { useElement } from "@elementor/editor-editing-panel";
3569
3661
  import { useElementSetting } from "@elementor/editor-elements";
3570
-
3571
- // src/prop-types/component-instance-prop-type.ts
3572
- import { createPropUtils as createPropUtils4, numberPropTypeUtil } from "@elementor/editor-props";
3573
- import { z as z5 } from "@elementor/schema";
3574
-
3575
- // src/prop-types/component-instance-overrides-prop-type.ts
3576
- import { createPropUtils as createPropUtils3 } from "@elementor/editor-props";
3577
- import { z as z4 } from "@elementor/schema";
3578
-
3579
- // src/prop-types/component-instance-override-prop-type.ts
3580
- import { createPropUtils } from "@elementor/editor-props";
3581
- import { z as z2 } from "@elementor/schema";
3582
- var componentInstanceOverridePropTypeUtil = createPropUtils(
3583
- "override",
3584
- z2.object({
3585
- override_key: z2.string(),
3586
- override_value: z2.unknown(),
3587
- schema_source: z2.object({
3588
- type: z2.literal("component"),
3589
- id: z2.number()
3590
- })
3591
- })
3592
- );
3593
-
3594
- // src/prop-types/component-overridable-prop-type.ts
3595
- import { createPropUtils as createPropUtils2 } from "@elementor/editor-props";
3596
- import { z as z3 } from "@elementor/schema";
3597
- var componentOverridablePropTypeUtil = createPropUtils2(
3598
- "overridable",
3599
- z3.object({
3600
- override_key: z3.string(),
3601
- origin_value: z3.object({
3602
- $$type: z3.string(),
3603
- value: z3.unknown()
3604
- }).nullable()
3605
- })
3606
- );
3607
-
3608
- // src/prop-types/component-instance-overrides-prop-type.ts
3609
- var componentInstanceOverridesPropTypeUtil = createPropUtils3(
3610
- "overrides",
3611
- z4.array(z4.union([componentInstanceOverridePropTypeUtil.schema, componentOverridablePropTypeUtil.schema])).optional().default([])
3612
- );
3613
-
3614
- // src/prop-types/component-instance-prop-type.ts
3615
- var componentInstancePropTypeUtil = createPropUtils4(
3616
- "component-instance",
3617
- z5.object({
3618
- component_id: numberPropTypeUtil.schema,
3619
- overrides: z5.optional(componentInstanceOverridesPropTypeUtil.schema)
3620
- })
3621
- );
3622
-
3623
- // src/hooks/use-component-instance-settings.ts
3624
3662
  function useComponentInstanceSettings() {
3625
3663
  const { element } = useElement();
3626
3664
  const settings = useElementSetting(element.id, "component_instance");
@@ -4054,7 +4092,7 @@ function InstanceEditingPanel() {
4054
4092
  const isNonEmptyGroup = (group) => group !== null && group.props.length > 0;
4055
4093
  const groups = overridableProps.groups.order.map((groupId) => overridableProps.groups.items[groupId] ?? null).filter(isNonEmptyGroup);
4056
4094
  const isEmpty = groups.length === 0 || Object.keys(overridableProps.props).length === 0;
4057
- return /* @__PURE__ */ React29.createElement(React29.Fragment, null, /* @__PURE__ */ React29.createElement(PanelHeader2, { sx: { justifyContent: "start", px: 2 } }, /* @__PURE__ */ React29.createElement(Stack17, { direction: "row", alignItems: "center", flexGrow: 1, gap: 1, maxWidth: "100%" }, /* @__PURE__ */ React29.createElement(ComponentsIcon4, { fontSize: "small", sx: { color: "text.tertiary" } }), /* @__PURE__ */ React29.createElement(EllipsisWithTooltip2, { title: component.name, as: PanelHeaderTitle2 }), canEdit && /* @__PURE__ */ React29.createElement(Tooltip4, { title: panelTitle }, /* @__PURE__ */ React29.createElement(IconButton6, { size: "tiny", onClick: handleEditComponent, "aria-label": panelTitle }, /* @__PURE__ */ React29.createElement(PencilIcon2, { fontSize: "tiny" }))))), /* @__PURE__ */ React29.createElement(PanelBody2, null, /* @__PURE__ */ React29.createElement(ControlAdornmentsProvider, { items: getFieldIndicators("settings") }, isEmpty ? /* @__PURE__ */ React29.createElement(EmptyState2, { onEditComponent: handleEditComponent }) : /* @__PURE__ */ React29.createElement(Stack17, { direction: "column", alignItems: "stretch" }, groups.map((group) => /* @__PURE__ */ React29.createElement(React29.Fragment, { key: group.id }, /* @__PURE__ */ React29.createElement(
4095
+ return /* @__PURE__ */ React29.createElement(React29.Fragment, null, /* @__PURE__ */ React29.createElement(PanelHeader2, { sx: { justifyContent: "start", px: 2 } }, /* @__PURE__ */ React29.createElement(Stack17, { direction: "row", alignItems: "center", flexGrow: 1, gap: 1, maxWidth: "100%" }, /* @__PURE__ */ React29.createElement(ComponentsIcon4, { fontSize: "small", sx: { color: "text.tertiary" } }), /* @__PURE__ */ React29.createElement(EllipsisWithTooltip2, { title: component.name, as: PanelHeaderTitle2 }), canEdit && /* @__PURE__ */ React29.createElement(Tooltip5, { title: panelTitle }, /* @__PURE__ */ React29.createElement(IconButton6, { size: "tiny", onClick: handleEditComponent, "aria-label": panelTitle }, /* @__PURE__ */ React29.createElement(PencilIcon2, { fontSize: "tiny" }))))), /* @__PURE__ */ React29.createElement(PanelBody2, null, /* @__PURE__ */ React29.createElement(ControlAdornmentsProvider, { items: getFieldIndicators("settings") }, isEmpty ? /* @__PURE__ */ React29.createElement(EmptyState2, { onEditComponent: handleEditComponent }) : /* @__PURE__ */ React29.createElement(Stack17, { direction: "column", alignItems: "stretch" }, groups.map((group) => /* @__PURE__ */ React29.createElement(React29.Fragment, { key: group.id }, /* @__PURE__ */ React29.createElement(
4058
4096
  OverridePropsGroup,
4059
4097
  {
4060
4098
  group,
@@ -4147,7 +4185,7 @@ import * as React32 from "react";
4147
4185
  import { useBoundProp as useBoundProp3 } from "@elementor/editor-controls";
4148
4186
  import { useElement as useElement4 } from "@elementor/editor-editing-panel";
4149
4187
  import { getWidgetsCache as getWidgetsCache3 } from "@elementor/editor-elements";
4150
- import { bindPopover as bindPopover2, bindTrigger as bindTrigger4, Popover as Popover4, Tooltip as Tooltip5, usePopupState as usePopupState4 } from "@elementor/ui";
4188
+ import { bindPopover as bindPopover2, bindTrigger as bindTrigger4, Popover as Popover4, Tooltip as Tooltip6, usePopupState as usePopupState4 } from "@elementor/ui";
4151
4189
  import { __ as __29 } from "@wordpress/i18n";
4152
4190
 
4153
4191
  // src/store/actions/set-overridable-prop.ts
@@ -4365,7 +4403,7 @@ function Content2({ componentId, overridableProps }) {
4365
4403
  popupState.close();
4366
4404
  };
4367
4405
  const overridableConfig = overridableValue ? getOverridableProp({ componentId, overrideKey: overridableValue.override_key }) : void 0;
4368
- return /* @__PURE__ */ React32.createElement(React32.Fragment, null, /* @__PURE__ */ React32.createElement(Tooltip5, { placement: "top", title: __29("Override Property", "elementor") }, /* @__PURE__ */ React32.createElement(Indicator2, { ...triggerProps, isOpen: !!popoverProps.open, isOverridable: !!overridableValue })), /* @__PURE__ */ React32.createElement(
4406
+ return /* @__PURE__ */ React32.createElement(React32.Fragment, null, /* @__PURE__ */ React32.createElement(Tooltip6, { placement: "top", title: __29("Override Property", "elementor") }, /* @__PURE__ */ React32.createElement(Indicator2, { ...triggerProps, isOpen: !!popoverProps.open, isOverridable: !!overridableValue })), /* @__PURE__ */ React32.createElement(
4369
4407
  Popover4,
4370
4408
  {
4371
4409
  disableScrollLock: true,