@elementor/editor-controls 0.24.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
  }
@@ -465,7 +505,7 @@ var SelectionEndAdornment = ({
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,
@@ -771,14 +820,14 @@ var Repeater = ({
771
820
  values: repeaterValues = [],
772
821
  setValues: setRepeaterValues
773
822
  }) => {
774
- const [openItem, setOpenItem] = useState2(EMPTY_OPEN_ITEM);
823
+ const [openItem, setOpenItem] = useState3(EMPTY_OPEN_ITEM);
775
824
  const [items, setItems] = useSyncExternalState({
776
825
  external: repeaterValues,
777
826
  // @ts-expect-error - as long as persistWhen => true, value will never be null
778
827
  setExternal: setRepeaterValues,
779
828
  persistWhen: () => true
780
829
  });
781
- const [uniqueKeys, setUniqueKeys] = useState2(items.map((_, index) => index));
830
+ const [uniqueKeys, setUniqueKeys] = useState3(items.map((_, index) => index));
782
831
  const generateNextKey = (source) => {
783
832
  return 1 + Math.max(0, ...source);
784
833
  };
@@ -876,7 +925,7 @@ var RepeaterItem = ({
876
925
  openOnMount,
877
926
  onOpen
878
927
  }) => {
879
- const [anchorEl, setAnchorEl] = useState2(null);
928
+ const [anchorEl, setAnchorEl] = useState3(null);
880
929
  const { popoverState, popoverProps, ref, setRef } = usePopover(openOnMount, onOpen);
881
930
  const duplicateLabel = __4("Duplicate", "elementor");
882
931
  const toggleLabel = disabled ? __4("Show", "elementor") : __4("Hide", "elementor");
@@ -912,7 +961,7 @@ var RepeaterItem = ({
912
961
  ));
913
962
  };
914
963
  var usePopover = (openOnMount, onOpen) => {
915
- const [ref, setRef] = useState2(null);
964
+ const [ref, setRef] = useState3(null);
916
965
  const popoverState = usePopupState2({ variant: "popover" });
917
966
  const popoverProps = bindPopover(popoverState);
918
967
  useEffect2(() => {
@@ -1096,7 +1145,7 @@ var ToggleControl = createControl(
1096
1145
  size = "tiny",
1097
1146
  exclusive = true
1098
1147
  }) => {
1099
- const { value, setValue } = useBoundProp(stringPropTypeUtil5);
1148
+ const { value, setValue, placeholder } = useBoundProp(stringPropTypeUtil5);
1100
1149
  const exclusiveValues = options.filter((option) => option.exclusive).map((option) => option.value);
1101
1150
  const handleNonExclusiveToggle = (selectedValues) => {
1102
1151
  const newSelectedValue = selectedValues[selectedValues.length - 1];
@@ -1113,7 +1162,7 @@ var ToggleControl = createControl(
1113
1162
  ControlToggleButtonGroup,
1114
1163
  {
1115
1164
  ...toggleButtonGroupProps,
1116
- value: value ?? null,
1165
+ value: value ?? placeholder ?? null,
1117
1166
  onChange: setValue,
1118
1167
  exclusive: true
1119
1168
  }
@@ -1121,7 +1170,7 @@ var ToggleControl = createControl(
1121
1170
  ControlToggleButtonGroup,
1122
1171
  {
1123
1172
  ...toggleButtonGroupProps,
1124
- value: value?.split(" ") ?? [],
1173
+ value: (value ?? placeholder)?.split(" ") ?? [],
1125
1174
  onChange: handleNonExclusiveToggle,
1126
1175
  exclusive: false
1127
1176
  }
@@ -1134,6 +1183,7 @@ import * as React27 from "react";
1134
1183
  import { numberPropTypeUtil } from "@elementor/editor-props";
1135
1184
  import { TextField as TextField4 } from "@elementor/ui";
1136
1185
  var isEmptyOrNaN = (value) => value === null || value === void 0 || value === "" || Number.isNaN(Number(value));
1186
+ var RESTRICTED_INPUT_KEYS2 = ["e", "E", "+", "-"];
1137
1187
  var NumberControl = createControl(
1138
1188
  ({
1139
1189
  placeholder,
@@ -1161,7 +1211,12 @@ var NumberControl = createControl(
1161
1211
  value: isEmptyOrNaN(value) ? "" : value,
1162
1212
  onChange: handleChange,
1163
1213
  placeholder,
1164
- inputProps: { step }
1214
+ inputProps: { step },
1215
+ onKeyDown: (event) => {
1216
+ if (RESTRICTED_INPUT_KEYS2.includes(event.key)) {
1217
+ event.preventDefault();
1218
+ }
1219
+ }
1165
1220
  }
1166
1221
  ));
1167
1222
  }
@@ -1366,7 +1421,7 @@ var Control3 = ({
1366
1421
 
1367
1422
  // src/controls/font-family-control/font-family-control.tsx
1368
1423
  import * as React31 from "react";
1369
- 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";
1370
1425
  import { stringPropTypeUtil as stringPropTypeUtil6 } from "@elementor/editor-props";
1371
1426
  import { ChevronDownIcon, SearchIcon, TextIcon, XIcon as XIcon2 } from "@elementor/icons";
1372
1427
  import {
@@ -1416,7 +1471,7 @@ var enqueueFont = (fontFamily, context = "editor") => {
1416
1471
  // src/controls/font-family-control/font-family-control.tsx
1417
1472
  var SIZE2 = "tiny";
1418
1473
  var FontFamilyControl = createControl(({ fontFamilies }) => {
1419
- const [searchValue, setSearchValue] = useState3("");
1474
+ const [searchValue, setSearchValue] = useState4("");
1420
1475
  const { value: fontFamily, setValue: setFontFamily } = useBoundProp(stringPropTypeUtil6);
1421
1476
  const popoverState = usePopupState4({ variant: "popover" });
1422
1477
  const filteredFontFamilies = useFilteredFontFamilies(fontFamilies, searchValue);
@@ -1448,6 +1503,7 @@ var FontFamilyControl = createControl(({ fontFamilies }) => {
1448
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(
1449
1504
  TextField5,
1450
1505
  {
1506
+ autoFocus: true,
1451
1507
  fullWidth: true,
1452
1508
  size: SIZE2,
1453
1509
  value: searchValue,
@@ -1625,7 +1681,7 @@ var StyledMenuList = styled4(MenuList)(({ theme }) => ({
1625
1681
  position: "relative"
1626
1682
  }));
1627
1683
  var useDebounce = (fn, delay) => {
1628
- const [debouncedFn] = useState3(() => debounce(fn, delay));
1684
+ const [debouncedFn] = useState4(() => debounce(fn, delay));
1629
1685
  useEffect3(() => () => debouncedFn.cancel(), [debouncedFn]);
1630
1686
  return debouncedFn;
1631
1687
  };
@@ -1651,7 +1707,7 @@ var UrlControl = createControl(({ placeholder }) => {
1651
1707
 
1652
1708
  // src/controls/link-control.tsx
1653
1709
  import * as React34 from "react";
1654
- import { useMemo, useState as useState4 } from "react";
1710
+ import { useMemo, useState as useState5 } from "react";
1655
1711
  import { getLinkInLinkRestriction, selectElement } from "@elementor/editor-elements";
1656
1712
  import {
1657
1713
  booleanPropTypeUtil,
@@ -1789,7 +1845,7 @@ var learnMoreButton = {
1789
1845
  var LinkControl = createControl((props) => {
1790
1846
  const { value, path, setValue, ...propContext } = useBoundProp(linkPropTypeUtil);
1791
1847
  const [linkSessionValue, setLinkSessionValue] = useSessionStorage(path.join("/"));
1792
- const [isActive, setIsActive] = useState4(!!value);
1848
+ const [isActive, setIsActive] = useState5(!!value);
1793
1849
  const {
1794
1850
  allowCustomValues,
1795
1851
  queryOptions: { endpoint = "", requestParams = {} },
@@ -1797,8 +1853,8 @@ var LinkControl = createControl((props) => {
1797
1853
  minInputLength = 2,
1798
1854
  context: { elementId }
1799
1855
  } = props || {};
1800
- const [linkInLinkRestriction, setLinkInLinkRestriction] = useState4(getLinkInLinkRestriction(elementId));
1801
- const [options, setOptions] = useState4(
1856
+ const [linkInLinkRestriction, setLinkInLinkRestriction] = useState5(getLinkInLinkRestriction(elementId));
1857
+ const [options, setOptions] = useState5(
1802
1858
  generateFirstLoadedOption(value)
1803
1859
  );
1804
1860
  const shouldDisableAddingLink = !isActive && linkInLinkRestriction.shouldRestrict;
@@ -2007,7 +2063,7 @@ var Control4 = ({ bind, isLinked }) => {
2007
2063
 
2008
2064
  // src/controls/svg-media-control.tsx
2009
2065
  import * as React37 from "react";
2010
- import { useState as useState6 } from "react";
2066
+ import { useState as useState7 } from "react";
2011
2067
  import { imageSrcPropTypeUtil as imageSrcPropTypeUtil2 } from "@elementor/editor-props";
2012
2068
  import { UploadIcon as UploadIcon2 } from "@elementor/icons";
2013
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";
@@ -2016,7 +2072,7 @@ import { __ as __12 } from "@wordpress/i18n";
2016
2072
 
2017
2073
  // src/components/enable-unfiltered-modal.tsx
2018
2074
  import * as React36 from "react";
2019
- import { useState as useState5 } from "react";
2075
+ import { useState as useState6 } from "react";
2020
2076
  import { useCurrentUserCapabilities } from "@elementor/editor-current-user";
2021
2077
  import {
2022
2078
  Button as Button3,
@@ -2049,7 +2105,7 @@ var WAIT_FOR_CLOSE_TIMEOUT_MS = 300;
2049
2105
  var EnableUnfilteredModal = (props) => {
2050
2106
  const { mutateAsync, isPending } = useUpdateUnfilteredFilesUpload();
2051
2107
  const { canUser } = useCurrentUserCapabilities();
2052
- const [isError, setIsError] = useState5(false);
2108
+ const [isError, setIsError] = useState6(false);
2053
2109
  const canManageOptions = canUser("manage_options");
2054
2110
  const onClose = (enabled) => {
2055
2111
  props.onClose(enabled);
@@ -2114,7 +2170,7 @@ var SvgMediaControl = createControl(() => {
2114
2170
  const { data: attachment, isFetching } = useWpMediaAttachment2(id?.value || null);
2115
2171
  const src = attachment?.url ?? url?.value ?? null;
2116
2172
  const { data: allowSvgUpload } = useUnfilteredFilesUpload();
2117
- const [unfilteredModalOpenState, setUnfilteredModalOpenState] = useState6(false);
2173
+ const [unfilteredModalOpenState, setUnfilteredModalOpenState] = useState7(false);
2118
2174
  const { open } = useWpMediaFrame2({
2119
2175
  mediaTypes: ["svg"],
2120
2176
  multiple: false,