@elementor/editor-controls 0.21.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -29,7 +29,8 @@ var PropProvider = ({
29
29
  children,
30
30
  value,
31
31
  setValue,
32
- propType
32
+ propType,
33
+ placeholder
33
34
  }) => {
34
35
  return /* @__PURE__ */ React.createElement(
35
36
  PropContext.Provider,
@@ -37,7 +38,8 @@ var PropProvider = ({
37
38
  value: {
38
39
  value,
39
40
  propType,
40
- setValue
41
+ setValue,
42
+ placeholder
41
43
  }
42
44
  },
43
45
  children
@@ -84,11 +86,12 @@ var ObjectPropKeyProvider = ({ children, bind }) => {
84
86
  return context?.setValue(newValue, options, { ...meta, bind });
85
87
  };
86
88
  const value = context.value?.[bind];
89
+ const placeholder = context.placeholder?.[bind];
87
90
  const propType = context.propType.shape[bind];
88
91
  return /* @__PURE__ */ React2.createElement(
89
92
  PropKeyContext.Provider,
90
93
  {
91
- value: { ...context, value, setValue, bind, propType, path: [...path ?? [], bind] }
94
+ value: { ...context, value, setValue, placeholder, bind, propType, path: [...path ?? [], bind] }
92
95
  },
93
96
  children
94
97
  );
@@ -122,12 +125,17 @@ var usePropKeyContext = () => {
122
125
  };
123
126
 
124
127
  // src/bound-prop-context/use-bound-prop.ts
128
+ import { useState } from "react";
125
129
  function useBoundProp(propTypeUtil) {
126
130
  const propKeyContext = usePropKeyContext();
131
+ const { isValid, validate, restoreValue } = useValidation(propKeyContext.propType);
127
132
  if (!propTypeUtil) {
128
133
  return propKeyContext;
129
134
  }
130
135
  function setValue(value2, options, meta) {
136
+ if (!validate(value2)) {
137
+ return;
138
+ }
131
139
  if (value2 === null) {
132
140
  return propKeyContext?.setValue(null, options, meta);
133
141
  }
@@ -135,13 +143,34 @@ function useBoundProp(propTypeUtil) {
135
143
  }
136
144
  const propType = resolveUnionPropType(propKeyContext.propType, propTypeUtil.key);
137
145
  const value = propTypeUtil.extract(propKeyContext.value ?? propType.default ?? null);
146
+ const placeholder = propTypeUtil.extract(propKeyContext.placeholder ?? null);
138
147
  return {
139
148
  ...propKeyContext,
149
+ propType,
140
150
  setValue,
141
- value,
142
- propType
151
+ value: isValid ? value : null,
152
+ restoreValue,
153
+ placeholder
143
154
  };
144
155
  }
156
+ var useValidation = (propType) => {
157
+ const [isValid, setIsValid] = useState(true);
158
+ const validate = (value) => {
159
+ let valid = true;
160
+ if (propType.settings.required && value === null) {
161
+ valid = false;
162
+ }
163
+ setIsValid(valid);
164
+ return valid;
165
+ };
166
+ const restoreValue = () => setIsValid(true);
167
+ return {
168
+ isValid,
169
+ setIsValid,
170
+ validate,
171
+ restoreValue
172
+ };
173
+ };
145
174
  var resolveUnionPropType = (propType, key) => {
146
175
  let resolvedPropType = propType;
147
176
  if (propType.kind === "union") {
@@ -420,21 +449,32 @@ import { forwardRef, useId } from "react";
420
449
  import { MenuListItem as MenuListItem2 } from "@elementor/editor-ui";
421
450
  import { bindMenu, bindTrigger, Button as Button2, InputAdornment, Menu, TextField as TextField3, usePopupState } from "@elementor/ui";
422
451
  var TextFieldInnerSelection = forwardRef(
423
- ({ placeholder, type, value, onChange, endAdornment, startAdornment }, ref) => {
452
+ ({
453
+ placeholder,
454
+ type,
455
+ value,
456
+ onChange,
457
+ onBlur,
458
+ onKeyDown,
459
+ endAdornment,
460
+ startAdornment
461
+ }, ref) => {
424
462
  return /* @__PURE__ */ React13.createElement(
425
463
  TextField3,
426
464
  {
465
+ ref,
427
466
  size: "tiny",
428
467
  fullWidth: true,
429
468
  type,
430
469
  value,
431
470
  onChange,
471
+ onKeyDown,
472
+ onBlur,
432
473
  placeholder,
433
474
  InputProps: {
434
475
  endAdornment,
435
476
  startAdornment
436
- },
437
- ref
477
+ }
438
478
  }
439
479
  );
440
480
  }
@@ -456,16 +496,16 @@ var SelectionEndAdornment = ({
456
496
  Button2,
457
497
  {
458
498
  size: "small",
459
- color: "inherit",
460
- sx: { font: "inherit", minWidth: "initial" },
499
+ color: "secondary",
500
+ sx: { font: "inherit", minWidth: "initial", textTransform: "uppercase" },
461
501
  ...bindTrigger(popupState)
462
502
  },
463
- value.toUpperCase()
503
+ value
464
504
  ), /* @__PURE__ */ React13.createElement(Menu, { MenuListProps: { dense: true }, ...bindMenu(popupState) }, options.map((option, index) => /* @__PURE__ */ React13.createElement(MenuListItem2, { key: option, onClick: () => handleMenuItemClick(index) }, option.toUpperCase()))));
465
505
  };
466
506
 
467
507
  // src/hooks/use-sync-external-state.tsx
468
- import { useEffect, useState } from "react";
508
+ import { useEffect, useState as useState2 } from "react";
469
509
  var useSyncExternalState = ({
470
510
  external,
471
511
  setExternal,
@@ -484,7 +524,7 @@ var useSyncExternalState = ({
484
524
  }
485
525
  return externalValue;
486
526
  }
487
- const [internal, setInternal] = useState(toInternal(external, null));
527
+ const [internal, setInternal] = useState2(toInternal(external, null));
488
528
  useEffect(() => {
489
529
  setInternal((prevInternal) => toInternal(external, prevInternal));
490
530
  }, [external]);
@@ -503,7 +543,7 @@ var defaultUnit = "px";
503
543
  var defaultSize = NaN;
504
544
  var SizeControl = createControl(
505
545
  ({ units: units2 = defaultUnits, extendedValues = [], placeholder, startIcon }) => {
506
- const { value: sizeValue, setValue: setSizeValue } = useBoundProp(sizePropTypeUtil);
546
+ const { value: sizeValue, setValue: setSizeValue, restoreValue } = useBoundProp(sizePropTypeUtil);
507
547
  const [state, setState] = useSyncExternalState({
508
548
  external: sizeValue,
509
549
  setExternal: setSizeValue,
@@ -523,20 +563,21 @@ var SizeControl = createControl(
523
563
  size: size || size === "0" ? parseFloat(size) : defaultSize
524
564
  }));
525
565
  };
526
- const inputProps = {
527
- size: state.size,
528
- unit: state.unit,
529
- placeholder,
530
- startIcon,
531
- units: units2,
532
- extendedValues,
533
- handleSizeChange,
534
- handleUnitChange
535
- };
536
- if (extendedValues?.length) {
537
- return /* @__PURE__ */ React14.createElement(ExtendedSizeInput, { ...inputProps });
538
- }
539
- return /* @__PURE__ */ React14.createElement(SizeInput, { ...inputProps });
566
+ const Input = extendedValues?.length ? ExtendedSizeInput : SizeInput;
567
+ return /* @__PURE__ */ React14.createElement(
568
+ Input,
569
+ {
570
+ size: state.size,
571
+ unit: state.unit,
572
+ placeholder,
573
+ startIcon,
574
+ units: units2,
575
+ extendedValues,
576
+ handleSizeChange,
577
+ handleUnitChange,
578
+ onBlur: restoreValue
579
+ }
580
+ );
540
581
  }
541
582
  );
542
583
  var ExtendedSizeInput = (props) => {
@@ -560,12 +601,14 @@ var ExtendedSizeInput = (props) => {
560
601
  }
561
602
  );
562
603
  };
604
+ var RESTRICTED_INPUT_KEYS = ["e", "E", "+", "-"];
563
605
  var SizeInput = ({
564
606
  units: units2,
565
607
  handleUnitChange,
566
608
  handleSizeChange,
567
609
  placeholder,
568
610
  startIcon,
611
+ onBlur,
569
612
  size,
570
613
  unit
571
614
  }) => {
@@ -584,7 +627,13 @@ var SizeInput = ({
584
627
  startAdornment: startIcon ? /* @__PURE__ */ React14.createElement(InputAdornment2, { position: "start" }, startIcon) : void 0,
585
628
  type: "number",
586
629
  value: Number.isNaN(size) ? "" : size,
587
- onChange: handleSizeChange
630
+ onChange: handleSizeChange,
631
+ onBlur,
632
+ onKeyDown: (event) => {
633
+ if (RESTRICTED_INPUT_KEYS.includes(event.key)) {
634
+ event.preventDefault();
635
+ }
636
+ }
588
637
  }
589
638
  ));
590
639
  };
@@ -643,7 +692,7 @@ var PopoverGridContainer = ({
643
692
 
644
693
  // src/components/repeater.tsx
645
694
  import * as React23 from "react";
646
- import { useEffect as useEffect2, useState as useState2 } from "react";
695
+ import { useEffect as useEffect2, useState as useState3 } from "react";
647
696
  import { CopyIcon, EyeIcon, EyeOffIcon, PlusIcon, XIcon } from "@elementor/icons";
648
697
  import {
649
698
  bindPopover,
@@ -705,21 +754,10 @@ var SortableItem = ({ id, children }) => {
705
754
  triggerProps,
706
755
  itemStyle,
707
756
  triggerStyle,
708
- isDragOverlay,
709
757
  showDropIndication,
710
758
  dropIndicationStyle
711
759
  }) => {
712
- return /* @__PURE__ */ React22.createElement(
713
- StyledListItem,
714
- {
715
- ...itemProps,
716
- style: itemStyle,
717
- sx: { backgroundColor: isDragOverlay ? "background.paper" : void 0 }
718
- },
719
- /* @__PURE__ */ React22.createElement(SortableTrigger, { ...triggerProps, style: triggerStyle }),
720
- children,
721
- showDropIndication && /* @__PURE__ */ React22.createElement(StyledDivider, { style: dropIndicationStyle })
722
- );
760
+ return /* @__PURE__ */ React22.createElement(StyledListItem, { ...itemProps, style: itemStyle }, /* @__PURE__ */ React22.createElement(SortableTrigger, { ...triggerProps, style: triggerStyle }), children, showDropIndication && /* @__PURE__ */ React22.createElement(StyledDivider, { style: dropIndicationStyle }));
723
761
  }
724
762
  }
725
763
  );
@@ -742,6 +780,11 @@ var StyledListItem = styled2(ListItem)`
742
780
  transform: translate( -75%, -50% );
743
781
  }
744
782
 
783
+ &[aria-describedby=''] > .MuiTag-root {
784
+ background-color: ${({ theme }) => theme.palette.background.paper};
785
+ box-shadow: ${({ theme }) => theme.shadows[3]};
786
+ }
787
+
745
788
  &:hover {
746
789
  & .class-item-sortable-trigger {
747
790
  visibility: visible;
@@ -768,6 +811,7 @@ var StyledDivider = styled2(Divider)`
768
811
 
769
812
  // src/components/repeater.tsx
770
813
  var SIZE = "tiny";
814
+ var EMPTY_OPEN_ITEM = -1;
771
815
  var Repeater = ({
772
816
  label,
773
817
  itemSettings,
@@ -776,14 +820,14 @@ var Repeater = ({
776
820
  values: repeaterValues = [],
777
821
  setValues: setRepeaterValues
778
822
  }) => {
779
- const [openItem, setOpenItem] = useState2(-1);
823
+ const [openItem, setOpenItem] = useState3(EMPTY_OPEN_ITEM);
780
824
  const [items, setItems] = useSyncExternalState({
781
825
  external: repeaterValues,
782
826
  // @ts-expect-error - as long as persistWhen => true, value will never be null
783
827
  setExternal: setRepeaterValues,
784
828
  persistWhen: () => true
785
829
  });
786
- const [uniqueKeys, setUniqueKeys] = useState2(items.map((_, index) => index));
830
+ const [uniqueKeys, setUniqueKeys] = useState3(items.map((_, index) => index));
787
831
  const generateNextKey = (source) => {
788
832
  return 1 + Math.max(0, ...source);
789
833
  };
@@ -857,14 +901,14 @@ var Repeater = ({
857
901
  return /* @__PURE__ */ React23.createElement(SortableItem, { id: key, key: `sortable-${key}` }, /* @__PURE__ */ React23.createElement(
858
902
  RepeaterItem,
859
903
  {
860
- bind: String(index),
861
904
  disabled: value?.disabled,
862
905
  label: /* @__PURE__ */ React23.createElement(itemSettings.Label, { value }),
863
906
  startIcon: /* @__PURE__ */ React23.createElement(itemSettings.Icon, { value }),
864
907
  removeItem: () => removeRepeaterItem(index),
865
908
  duplicateItem: () => duplicateRepeaterItem(index),
866
909
  toggleDisableItem: () => toggleDisableRepeaterItem(index),
867
- openOnMount: openOnAdd && openItem === key
910
+ openOnMount: openOnAdd && openItem === key,
911
+ onOpen: () => setOpenItem(EMPTY_OPEN_ITEM)
868
912
  },
869
913
  (props) => /* @__PURE__ */ React23.createElement(itemSettings.Content, { ...props, value, bind: String(index) })
870
914
  ));
@@ -878,10 +922,11 @@ var RepeaterItem = ({
878
922
  removeItem,
879
923
  duplicateItem,
880
924
  toggleDisableItem,
881
- openOnMount
925
+ openOnMount,
926
+ onOpen
882
927
  }) => {
883
- const [anchorEl, setAnchorEl] = useState2(null);
884
- const { popoverState, popoverProps, ref, setRef } = usePopover(openOnMount);
928
+ const [anchorEl, setAnchorEl] = useState3(null);
929
+ const { popoverState, popoverProps, ref, setRef } = usePopover(openOnMount, onOpen);
885
930
  const duplicateLabel = __4("Duplicate", "elementor");
886
931
  const toggleLabel = disabled ? __4("Show", "elementor") : __4("Hide", "elementor");
887
932
  const removeLabel = __4("Remove", "elementor");
@@ -896,8 +941,7 @@ var RepeaterItem = ({
896
941
  "aria-label": __4("Open item", "elementor"),
897
942
  ...bindTrigger2(popoverState),
898
943
  startIcon,
899
- actions: /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(Tooltip, { title: duplicateLabel, placement: "top" }, /* @__PURE__ */ React23.createElement(IconButton, { size: SIZE, onClick: duplicateItem, "aria-label": duplicateLabel }, /* @__PURE__ */ React23.createElement(CopyIcon, { fontSize: SIZE }))), /* @__PURE__ */ React23.createElement(Tooltip, { title: toggleLabel, placement: "top" }, /* @__PURE__ */ React23.createElement(IconButton, { size: SIZE, onClick: toggleDisableItem, "aria-label": toggleLabel }, disabled ? /* @__PURE__ */ React23.createElement(EyeOffIcon, { fontSize: SIZE }) : /* @__PURE__ */ React23.createElement(EyeIcon, { fontSize: SIZE }))), /* @__PURE__ */ React23.createElement(Tooltip, { title: removeLabel, placement: "top" }, /* @__PURE__ */ React23.createElement(IconButton, { size: SIZE, onClick: removeItem, "aria-label": removeLabel }, /* @__PURE__ */ React23.createElement(XIcon, { fontSize: SIZE })))),
900
- sx: { backgroundColor: "background.paper" }
944
+ actions: /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(Tooltip, { title: duplicateLabel, placement: "top" }, /* @__PURE__ */ React23.createElement(IconButton, { size: SIZE, onClick: duplicateItem, "aria-label": duplicateLabel }, /* @__PURE__ */ React23.createElement(CopyIcon, { fontSize: SIZE }))), /* @__PURE__ */ React23.createElement(Tooltip, { title: toggleLabel, placement: "top" }, /* @__PURE__ */ React23.createElement(IconButton, { size: SIZE, onClick: toggleDisableItem, "aria-label": toggleLabel }, disabled ? /* @__PURE__ */ React23.createElement(EyeOffIcon, { fontSize: SIZE }) : /* @__PURE__ */ React23.createElement(EyeIcon, { fontSize: SIZE }))), /* @__PURE__ */ React23.createElement(Tooltip, { title: removeLabel, placement: "top" }, /* @__PURE__ */ React23.createElement(IconButton, { size: SIZE, onClick: removeItem, "aria-label": removeLabel }, /* @__PURE__ */ React23.createElement(XIcon, { fontSize: SIZE }))))
901
945
  }
902
946
  ), /* @__PURE__ */ React23.createElement(
903
947
  Popover,
@@ -916,13 +960,14 @@ var RepeaterItem = ({
916
960
  /* @__PURE__ */ React23.createElement(Box, null, children({ anchorEl }))
917
961
  ));
918
962
  };
919
- var usePopover = (openOnMount) => {
920
- const [ref, setRef] = useState2(null);
963
+ var usePopover = (openOnMount, onOpen) => {
964
+ const [ref, setRef] = useState3(null);
921
965
  const popoverState = usePopupState2({ variant: "popover" });
922
966
  const popoverProps = bindPopover(popoverState);
923
967
  useEffect2(() => {
924
968
  if (openOnMount && ref) {
925
969
  popoverState.open(ref);
970
+ onOpen?.();
926
971
  }
927
972
  }, [ref]);
928
973
  return {
@@ -1100,7 +1145,7 @@ var ToggleControl = createControl(
1100
1145
  size = "tiny",
1101
1146
  exclusive = true
1102
1147
  }) => {
1103
- const { value, setValue } = useBoundProp(stringPropTypeUtil5);
1148
+ const { value, setValue, placeholder } = useBoundProp(stringPropTypeUtil5);
1104
1149
  const exclusiveValues = options.filter((option) => option.exclusive).map((option) => option.value);
1105
1150
  const handleNonExclusiveToggle = (selectedValues) => {
1106
1151
  const newSelectedValue = selectedValues[selectedValues.length - 1];
@@ -1117,7 +1162,7 @@ var ToggleControl = createControl(
1117
1162
  ControlToggleButtonGroup,
1118
1163
  {
1119
1164
  ...toggleButtonGroupProps,
1120
- value: value ?? null,
1165
+ value: value ?? placeholder ?? null,
1121
1166
  onChange: setValue,
1122
1167
  exclusive: true
1123
1168
  }
@@ -1125,7 +1170,7 @@ var ToggleControl = createControl(
1125
1170
  ControlToggleButtonGroup,
1126
1171
  {
1127
1172
  ...toggleButtonGroupProps,
1128
- value: value?.split(" ") ?? [],
1173
+ value: (value ?? placeholder)?.split(" ") ?? [],
1129
1174
  onChange: handleNonExclusiveToggle,
1130
1175
  exclusive: false
1131
1176
  }
@@ -1138,6 +1183,7 @@ import * as React27 from "react";
1138
1183
  import { numberPropTypeUtil } from "@elementor/editor-props";
1139
1184
  import { TextField as TextField4 } from "@elementor/ui";
1140
1185
  var isEmptyOrNaN = (value) => value === null || value === void 0 || value === "" || Number.isNaN(Number(value));
1186
+ var RESTRICTED_INPUT_KEYS2 = ["e", "E", "+", "-"];
1141
1187
  var NumberControl = createControl(
1142
1188
  ({
1143
1189
  placeholder,
@@ -1165,7 +1211,12 @@ var NumberControl = createControl(
1165
1211
  value: isEmptyOrNaN(value) ? "" : value,
1166
1212
  onChange: handleChange,
1167
1213
  placeholder,
1168
- inputProps: { step }
1214
+ inputProps: { step },
1215
+ onKeyDown: (event) => {
1216
+ if (RESTRICTED_INPUT_KEYS2.includes(event.key)) {
1217
+ event.preventDefault();
1218
+ }
1219
+ }
1169
1220
  }
1170
1221
  ));
1171
1222
  }
@@ -1370,7 +1421,7 @@ var Control3 = ({
1370
1421
 
1371
1422
  // src/controls/font-family-control/font-family-control.tsx
1372
1423
  import * as React31 from "react";
1373
- import { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
1424
+ import { useEffect as useEffect3, useRef as useRef2, useState as useState4 } from "react";
1374
1425
  import { stringPropTypeUtil as stringPropTypeUtil6 } from "@elementor/editor-props";
1375
1426
  import { ChevronDownIcon, SearchIcon, TextIcon, XIcon as XIcon2 } from "@elementor/icons";
1376
1427
  import {
@@ -1420,7 +1471,7 @@ var enqueueFont = (fontFamily, context = "editor") => {
1420
1471
  // src/controls/font-family-control/font-family-control.tsx
1421
1472
  var SIZE2 = "tiny";
1422
1473
  var FontFamilyControl = createControl(({ fontFamilies }) => {
1423
- const [searchValue, setSearchValue] = useState3("");
1474
+ const [searchValue, setSearchValue] = useState4("");
1424
1475
  const { value: fontFamily, setValue: setFontFamily } = useBoundProp(stringPropTypeUtil6);
1425
1476
  const popoverState = usePopupState4({ variant: "popover" });
1426
1477
  const filteredFontFamilies = useFilteredFontFamilies(fontFamilies, searchValue);
@@ -1452,6 +1503,7 @@ var FontFamilyControl = createControl(({ fontFamilies }) => {
1452
1503
  /* @__PURE__ */ React31.createElement(Stack9, null, /* @__PURE__ */ React31.createElement(Stack9, { direction: "row", alignItems: "center", pl: 1.5, pr: 0.5, py: 1.5 }, /* @__PURE__ */ React31.createElement(TextIcon, { fontSize: SIZE2, sx: { mr: 0.5 } }), /* @__PURE__ */ React31.createElement(Typography2, { variant: "subtitle2" }, __8("Font Family", "elementor")), /* @__PURE__ */ React31.createElement(IconButton2, { size: SIZE2, sx: { ml: "auto" }, onClick: handleClose }, /* @__PURE__ */ React31.createElement(XIcon2, { fontSize: SIZE2 }))), /* @__PURE__ */ React31.createElement(Box2, { px: 1.5, pb: 1 }, /* @__PURE__ */ React31.createElement(
1453
1504
  TextField5,
1454
1505
  {
1506
+ autoFocus: true,
1455
1507
  fullWidth: true,
1456
1508
  size: SIZE2,
1457
1509
  value: searchValue,
@@ -1608,7 +1660,9 @@ var StyledMenuList = styled4(MenuList)(({ theme }) => ({
1608
1660
  position: "absolute",
1609
1661
  top: 0,
1610
1662
  left: 0,
1611
- width: "100%"
1663
+ width: "100%",
1664
+ display: "flex",
1665
+ alignItems: "center"
1612
1666
  },
1613
1667
  '& > [role="option"]': {
1614
1668
  ...theme.typography.caption,
@@ -1627,7 +1681,7 @@ var StyledMenuList = styled4(MenuList)(({ theme }) => ({
1627
1681
  position: "relative"
1628
1682
  }));
1629
1683
  var useDebounce = (fn, delay) => {
1630
- const [debouncedFn] = useState3(() => debounce(fn, delay));
1684
+ const [debouncedFn] = useState4(() => debounce(fn, delay));
1631
1685
  useEffect3(() => () => debouncedFn.cancel(), [debouncedFn]);
1632
1686
  return debouncedFn;
1633
1687
  };
@@ -1653,8 +1707,8 @@ var UrlControl = createControl(({ placeholder }) => {
1653
1707
 
1654
1708
  // src/controls/link-control.tsx
1655
1709
  import * as React34 from "react";
1656
- import { useMemo, useState as useState4 } from "react";
1657
- import { getAncestorWithAnchorTag, getDescendantWithAnchorTag } from "@elementor/editor-elements";
1710
+ import { useMemo, useState as useState5 } from "react";
1711
+ import { getLinkInLinkRestriction, selectElement } from "@elementor/editor-elements";
1658
1712
  import {
1659
1713
  booleanPropTypeUtil,
1660
1714
  linkPropTypeUtil,
@@ -1662,10 +1716,11 @@ import {
1662
1716
  stringPropTypeUtil as stringPropTypeUtil7,
1663
1717
  urlPropTypeUtil as urlPropTypeUtil2
1664
1718
  } from "@elementor/editor-props";
1719
+ import { InfoTipCard } from "@elementor/editor-ui";
1665
1720
  import { httpService as httpService2 } from "@elementor/http";
1666
- import { MinusIcon, PlusIcon as PlusIcon2 } from "@elementor/icons";
1721
+ import { AlertTriangleIcon, MinusIcon, PlusIcon as PlusIcon2 } from "@elementor/icons";
1667
1722
  import { useSessionStorage } from "@elementor/session";
1668
- import { Collapse, Divider as Divider3, Grid as Grid7, IconButton as IconButton4, Stack as Stack10, Switch } from "@elementor/ui";
1723
+ import { Box as Box4, Collapse, Divider as Divider3, Grid as Grid7, IconButton as IconButton4, Infotip, Stack as Stack10, Switch } from "@elementor/ui";
1669
1724
  import { debounce as debounce2 } from "@elementor/utils";
1670
1725
  import { __ as __9 } from "@wordpress/i18n";
1671
1726
 
@@ -1783,10 +1838,14 @@ function _factoryFilter(newValue, options, minInputLength) {
1783
1838
 
1784
1839
  // src/controls/link-control.tsx
1785
1840
  var SIZE3 = "tiny";
1841
+ var learnMoreButton = {
1842
+ label: __9("Learn More", "elementor"),
1843
+ href: "https://go.elementor.com/element-link-inside-link-infotip"
1844
+ };
1786
1845
  var LinkControl = createControl((props) => {
1787
1846
  const { value, path, setValue, ...propContext } = useBoundProp(linkPropTypeUtil);
1788
1847
  const [linkSessionValue, setLinkSessionValue] = useSessionStorage(path.join("/"));
1789
- const [isEnabled, setIsEnabled] = useState4(!!value);
1848
+ const [isActive, setIsActive] = useState5(!!value);
1790
1849
  const {
1791
1850
  allowCustomValues,
1792
1851
  queryOptions: { endpoint = "", requestParams = {} },
@@ -1794,17 +1853,19 @@ var LinkControl = createControl((props) => {
1794
1853
  minInputLength = 2,
1795
1854
  context: { elementId }
1796
1855
  } = props || {};
1797
- const [options, setOptions] = useState4(
1856
+ const [linkInLinkRestriction, setLinkInLinkRestriction] = useState5(getLinkInLinkRestriction(elementId));
1857
+ const [options, setOptions] = useState5(
1798
1858
  generateFirstLoadedOption(value)
1799
1859
  );
1860
+ const shouldDisableAddingLink = !isActive && linkInLinkRestriction.shouldRestrict;
1800
1861
  const onEnabledChange = () => {
1801
- const shouldRestrict = getAncestorWithAnchorTag(elementId) || getDescendantWithAnchorTag(elementId);
1802
- if (shouldRestrict && !isEnabled) {
1862
+ setLinkInLinkRestriction(getLinkInLinkRestriction(elementId));
1863
+ if (linkInLinkRestriction.shouldRestrict && !isActive) {
1803
1864
  return;
1804
1865
  }
1805
- setIsEnabled((prevState) => !prevState);
1806
- setValue(isEnabled ? null : linkSessionValue?.value ?? null);
1807
- setLinkSessionValue({ value, meta: { isEnabled: !isEnabled } });
1866
+ setIsActive((prevState) => !prevState);
1867
+ setValue(isActive ? null : linkSessionValue?.value ?? null);
1868
+ setLinkSessionValue({ value, meta: { isEnabled: !isActive } });
1808
1869
  };
1809
1870
  const onOptionChange = (newValue) => {
1810
1871
  const valueToSave = newValue ? {
@@ -1854,15 +1915,16 @@ var LinkControl = createControl((props) => {
1854
1915
  }
1855
1916
  },
1856
1917
  /* @__PURE__ */ React34.createElement(ControlFormLabel, null, __9("Link", "elementor")),
1857
- /* @__PURE__ */ React34.createElement(
1918
+ /* @__PURE__ */ React34.createElement(ConditionalInfoTip, { isVisible: !isActive, linkInLinkRestriction }, /* @__PURE__ */ React34.createElement(
1858
1919
  ToggleIconControl,
1859
1920
  {
1860
- enabled: isEnabled,
1921
+ disabled: shouldDisableAddingLink,
1922
+ active: isActive,
1861
1923
  onIconClick: onEnabledChange,
1862
1924
  label: __9("Toggle link", "elementor")
1863
1925
  }
1864
- )
1865
- ), /* @__PURE__ */ React34.createElement(Collapse, { in: isEnabled, timeout: "auto", unmountOnExit: true }, /* @__PURE__ */ React34.createElement(Stack10, { gap: 1.5 }, /* @__PURE__ */ React34.createElement(PropKeyProvider, { bind: "destination" }, /* @__PURE__ */ React34.createElement(ControlActions, null, /* @__PURE__ */ React34.createElement(
1926
+ ))
1927
+ ), /* @__PURE__ */ React34.createElement(Collapse, { in: isActive, timeout: "auto", unmountOnExit: true }, /* @__PURE__ */ React34.createElement(Stack10, { gap: 1.5 }, /* @__PURE__ */ React34.createElement(PropKeyProvider, { bind: "destination" }, /* @__PURE__ */ React34.createElement(ControlActions, null, /* @__PURE__ */ React34.createElement(
1866
1928
  Autocomplete,
1867
1929
  {
1868
1930
  options,
@@ -1873,17 +1935,22 @@ var LinkControl = createControl((props) => {
1873
1935
  onTextChange,
1874
1936
  minInputLength
1875
1937
  }
1876
- ))), /* @__PURE__ */ React34.createElement(PropKeyProvider, { bind: "isTargetBlank" }, /* @__PURE__ */ React34.createElement(SwitchControl, null))))));
1938
+ ))), /* @__PURE__ */ React34.createElement(PropKeyProvider, { bind: "isTargetBlank" }, /* @__PURE__ */ React34.createElement(SwitchControl, { disabled: !value }))))));
1877
1939
  });
1878
- var ToggleIconControl = ({ enabled, onIconClick, label }) => {
1879
- return /* @__PURE__ */ React34.createElement(IconButton4, { size: SIZE3, onClick: onIconClick, "aria-label": label }, enabled ? /* @__PURE__ */ React34.createElement(MinusIcon, { fontSize: SIZE3 }) : /* @__PURE__ */ React34.createElement(PlusIcon2, { fontSize: SIZE3 }));
1940
+ var ToggleIconControl = ({ disabled, active, onIconClick, label }) => {
1941
+ return /* @__PURE__ */ React34.createElement(IconButton4, { size: SIZE3, onClick: onIconClick, "aria-label": label, disabled }, active ? /* @__PURE__ */ React34.createElement(MinusIcon, { fontSize: SIZE3 }) : /* @__PURE__ */ React34.createElement(PlusIcon2, { fontSize: SIZE3 }));
1880
1942
  };
1881
- var SwitchControl = () => {
1943
+ var SwitchControl = ({ disabled }) => {
1882
1944
  const { value = false, setValue } = useBoundProp(booleanPropTypeUtil);
1883
1945
  const onClick = () => {
1884
1946
  setValue(!value);
1885
1947
  };
1886
- return /* @__PURE__ */ React34.createElement(Grid7, { container: true, alignItems: "center", flexWrap: "nowrap", justifyContent: "space-between" }, /* @__PURE__ */ React34.createElement(Grid7, { item: true }, /* @__PURE__ */ React34.createElement(ControlFormLabel, null, __9("Open in a new tab", "elementor"))), /* @__PURE__ */ React34.createElement(Grid7, { item: true }, /* @__PURE__ */ React34.createElement(Switch, { checked: value, onClick })));
1948
+ const inputProps = disabled ? {
1949
+ style: {
1950
+ opacity: 0
1951
+ }
1952
+ } : {};
1953
+ return /* @__PURE__ */ React34.createElement(Grid7, { container: true, alignItems: "center", flexWrap: "nowrap", justifyContent: "space-between" }, /* @__PURE__ */ React34.createElement(Grid7, { item: true }, /* @__PURE__ */ React34.createElement(ControlFormLabel, null, __9("Open in a new tab", "elementor"))), /* @__PURE__ */ React34.createElement(Grid7, { item: true }, /* @__PURE__ */ React34.createElement(Switch, { checked: value, onClick, disabled, inputProps })));
1887
1954
  };
1888
1955
  async function fetchOptions(ajaxUrl, params) {
1889
1956
  if (!params || !ajaxUrl) {
@@ -1913,6 +1980,37 @@ function generateFirstLoadedOption(unionValue) {
1913
1980
  }
1914
1981
  ] : [];
1915
1982
  }
1983
+ var ConditionalInfoTip = ({ linkInLinkRestriction, isVisible, children }) => {
1984
+ const { shouldRestrict, reason, elementId } = linkInLinkRestriction;
1985
+ const handleTakeMeClick = () => {
1986
+ if (elementId) {
1987
+ selectElement(elementId);
1988
+ }
1989
+ };
1990
+ return shouldRestrict && isVisible ? /* @__PURE__ */ React34.createElement(
1991
+ Infotip,
1992
+ {
1993
+ placement: "right",
1994
+ content: /* @__PURE__ */ React34.createElement(
1995
+ InfoTipCard,
1996
+ {
1997
+ content: INFOTIP_CONTENT[reason],
1998
+ svgIcon: /* @__PURE__ */ React34.createElement(AlertTriangleIcon, null),
1999
+ learnMoreButton,
2000
+ ctaButton: {
2001
+ label: __9("Take me there", "elementor"),
2002
+ onClick: handleTakeMeClick
2003
+ }
2004
+ }
2005
+ )
2006
+ },
2007
+ /* @__PURE__ */ React34.createElement(Box4, null, children)
2008
+ ) : /* @__PURE__ */ React34.createElement(React34.Fragment, null, children);
2009
+ };
2010
+ var INFOTIP_CONTENT = {
2011
+ descendant: /* @__PURE__ */ React34.createElement(React34.Fragment, null, __9("To add a link to this container,", "elementor"), /* @__PURE__ */ React34.createElement("br", null), __9("first remove the link from the elements inside of it.", "elementor")),
2012
+ ancestor: /* @__PURE__ */ React34.createElement(React34.Fragment, null, __9("To add a link to this element,", "elementor"), /* @__PURE__ */ React34.createElement("br", null), __9("first remove the link from its parent container.", "elementor"))
2013
+ };
1916
2014
 
1917
2015
  // src/controls/gap-control.tsx
1918
2016
  import * as React35 from "react";
@@ -1965,7 +2063,7 @@ var Control4 = ({ bind, isLinked }) => {
1965
2063
 
1966
2064
  // src/controls/svg-media-control.tsx
1967
2065
  import * as React37 from "react";
1968
- import { useState as useState6 } from "react";
2066
+ import { useState as useState7 } from "react";
1969
2067
  import { imageSrcPropTypeUtil as imageSrcPropTypeUtil2 } from "@elementor/editor-props";
1970
2068
  import { UploadIcon as UploadIcon2 } from "@elementor/icons";
1971
2069
  import { Button as Button4, Card as Card2, CardMedia as CardMedia2, CardOverlay as CardOverlay2, CircularProgress as CircularProgress3, Stack as Stack12, styled as styled5 } from "@elementor/ui";
@@ -1974,7 +2072,7 @@ import { __ as __12 } from "@wordpress/i18n";
1974
2072
 
1975
2073
  // src/components/enable-unfiltered-modal.tsx
1976
2074
  import * as React36 from "react";
1977
- import { useState as useState5 } from "react";
2075
+ import { useState as useState6 } from "react";
1978
2076
  import { useCurrentUserCapabilities } from "@elementor/editor-current-user";
1979
2077
  import {
1980
2078
  Button as Button3,
@@ -2007,7 +2105,7 @@ var WAIT_FOR_CLOSE_TIMEOUT_MS = 300;
2007
2105
  var EnableUnfilteredModal = (props) => {
2008
2106
  const { mutateAsync, isPending } = useUpdateUnfilteredFilesUpload();
2009
2107
  const { canUser } = useCurrentUserCapabilities();
2010
- const [isError, setIsError] = useState5(false);
2108
+ const [isError, setIsError] = useState6(false);
2011
2109
  const canManageOptions = canUser("manage_options");
2012
2110
  const onClose = (enabled) => {
2013
2111
  props.onClose(enabled);
@@ -2072,7 +2170,7 @@ var SvgMediaControl = createControl(() => {
2072
2170
  const { data: attachment, isFetching } = useWpMediaAttachment2(id?.value || null);
2073
2171
  const src = attachment?.url ?? url?.value ?? null;
2074
2172
  const { data: allowSvgUpload } = useUnfilteredFilesUpload();
2075
- const [unfilteredModalOpenState, setUnfilteredModalOpenState] = useState6(false);
2173
+ const [unfilteredModalOpenState, setUnfilteredModalOpenState] = useState7(false);
2076
2174
  const { open } = useWpMediaFrame2({
2077
2175
  mediaTypes: ["svg"],
2078
2176
  multiple: false,
@@ -2154,7 +2252,7 @@ import {
2154
2252
  backgroundOverlayPropTypeUtil,
2155
2253
  colorPropTypeUtil as colorPropTypeUtil3
2156
2254
  } from "@elementor/editor-props";
2157
- import { Box as Box4, CardMedia as CardMedia3, Grid as Grid13, styled as styled6, Tab, TabPanel, Tabs, UnstableColorIndicator as UnstableColorIndicator2 } from "@elementor/ui";
2255
+ import { Box as Box5, CardMedia as CardMedia3, Grid as Grid13, styled as styled6, Tab, TabPanel, Tabs, UnstableColorIndicator as UnstableColorIndicator2 } from "@elementor/ui";
2158
2256
  import { useWpMediaAttachment as useWpMediaAttachment3 } from "@elementor/wp-media";
2159
2257
  import { __ as __17 } from "@wordpress/i18n";
2160
2258
 
@@ -2534,7 +2632,7 @@ var Content2 = () => {
2534
2632
  color: initialBackgroundColorOverlay.value,
2535
2633
  gradient: initialBackgroundGradientOverlay.value
2536
2634
  });
2537
- return /* @__PURE__ */ React43.createElement(Box4, { sx: { width: "100%" } }, /* @__PURE__ */ React43.createElement(Box4, { sx: { borderBottom: 1, borderColor: "divider" } }, /* @__PURE__ */ React43.createElement(
2635
+ return /* @__PURE__ */ React43.createElement(Box5, { sx: { width: "100%" } }, /* @__PURE__ */ React43.createElement(Box5, { sx: { borderBottom: 1, borderColor: "divider" } }, /* @__PURE__ */ React43.createElement(
2538
2636
  Tabs,
2539
2637
  {
2540
2638
  size: "small",
@@ -2636,7 +2734,7 @@ var useImage = (image) => {
2636
2734
  const imageSrc = image?.value.image.value?.src.value;
2637
2735
  const { data: attachment } = useWpMediaAttachment3(imageSrc.id?.value || null);
2638
2736
  if (imageSrc.id) {
2639
- const imageFileTypeExtension = attachment?.subtype ? `.${attachment.subtype}` : "";
2737
+ const imageFileTypeExtension = getFileExtensionFromFilename(attachment?.filename);
2640
2738
  imageTitle = `${attachment?.title}${imageFileTypeExtension}` || null;
2641
2739
  imageUrl = attachment?.url || null;
2642
2740
  } else if (imageSrc.url) {
@@ -2645,6 +2743,13 @@ var useImage = (image) => {
2645
2743
  }
2646
2744
  return { imageTitle, imageUrl };
2647
2745
  };
2746
+ var getFileExtensionFromFilename = (filename) => {
2747
+ if (!filename) {
2748
+ return "";
2749
+ }
2750
+ const extension = filename.substring(filename.lastIndexOf(".") + 1);
2751
+ return `.${extension}`;
2752
+ };
2648
2753
  var getGradientValue = (value) => {
2649
2754
  const gradient = value.value;
2650
2755
  const stops = gradient.stops.value?.map(({ value: { color, offset } }) => `${color.value} ${offset.value ?? 0}%`)?.join(",");