@elementor/editor-controls 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  // src/controls/image-control.tsx
2
2
  import * as React9 from "react";
3
+ import { imagePropTypeUtil } from "@elementor/editor-props";
3
4
  import { Grid, Stack as Stack2 } from "@elementor/ui";
4
5
  import { __ as __2 } from "@wordpress/i18n";
5
6
 
@@ -10,12 +11,26 @@ var BoundPropContext = createContext(null);
10
11
  var BoundPropProvider = ({ children, value, setValue, bind }) => {
11
12
  return /* @__PURE__ */ React.createElement(BoundPropContext.Provider, { value: { value, setValue, bind } }, children);
12
13
  };
13
- function useBoundProp(defaultValue) {
14
+ function useBoundProp(propTypeUtil) {
14
15
  const boundPropContext = useContext(BoundPropContext);
15
16
  if (!boundPropContext) {
16
- throw new Error("useBoundProp must be used within a BoundPropContext");
17
+ throw new Error("useBoundProp must be used within a BoundPropProvider");
17
18
  }
18
- return { ...boundPropContext, value: boundPropContext.value ?? defaultValue };
19
+ if (!propTypeUtil) {
20
+ return boundPropContext;
21
+ }
22
+ function setValue(value2, options) {
23
+ if (value2 === null) {
24
+ return boundPropContext.setValue(null);
25
+ }
26
+ return boundPropContext.setValue(propTypeUtil?.create(value2, options));
27
+ }
28
+ const value = propTypeUtil.extract(boundPropContext.value);
29
+ return {
30
+ ...boundPropContext,
31
+ setValue,
32
+ value
33
+ };
19
34
  }
20
35
 
21
36
  // src/components/control-label.tsx
@@ -75,6 +90,7 @@ function createControl(Component, { supportsReplacements = true } = {}) {
75
90
 
76
91
  // src/controls/image-media-control.tsx
77
92
  import * as React7 from "react";
93
+ import { imageSrcPropTypeUtil } from "@elementor/editor-props";
78
94
  import { UploadIcon } from "@elementor/icons";
79
95
  import { Button, Card, CardMedia, CardOverlay, CircularProgress, Stack } from "@elementor/ui";
80
96
  import { useWpMediaAttachment, useWpMediaFrame } from "@elementor/wp-media";
@@ -116,8 +132,8 @@ function ControlActions({ children }) {
116
132
 
117
133
  // src/controls/image-media-control.tsx
118
134
  var ImageMediaControl = createControl(() => {
119
- const { value, setValue } = useBoundProp();
120
- const { id, url } = value?.value ?? {};
135
+ const { value, setValue } = useBoundProp(imageSrcPropTypeUtil);
136
+ const { id, url } = value ?? {};
121
137
  const { data: attachment, isFetching } = useWpMediaAttachment(id?.value || null);
122
138
  const src = attachment?.url ?? url;
123
139
  const { open } = useWpMediaFrame({
@@ -126,14 +142,11 @@ var ImageMediaControl = createControl(() => {
126
142
  selected: id?.value || null,
127
143
  onSelect: (selectedAttachment) => {
128
144
  setValue({
129
- $$type: "image-src",
130
- value: {
131
- id: {
132
- $$type: "image-attachment-id",
133
- value: selectedAttachment.id
134
- },
135
- url: null
136
- }
145
+ id: {
146
+ $$type: "image-attachment-id",
147
+ value: selectedAttachment.id
148
+ },
149
+ url: null
137
150
  });
138
151
  }
139
152
  });
@@ -161,9 +174,10 @@ var ImageMediaControl = createControl(() => {
161
174
 
162
175
  // src/controls/select-control.tsx
163
176
  import * as React8 from "react";
177
+ import { stringPropTypeUtil } from "@elementor/editor-props";
164
178
  import { MenuItem, Select } from "@elementor/ui";
165
179
  var SelectControl = createControl(({ options }) => {
166
- const { value, setValue } = useBoundProp();
180
+ const { value, setValue } = useBoundProp(stringPropTypeUtil);
167
181
  const handleChange = (event) => {
168
182
  setValue(event.target.value);
169
183
  };
@@ -172,24 +186,18 @@ var SelectControl = createControl(({ options }) => {
172
186
 
173
187
  // src/controls/image-control.tsx
174
188
  var ImageControl = createControl((props) => {
175
- const { value, setValue } = useBoundProp();
176
- const { src, size } = value?.value || {};
189
+ const { value, setValue } = useBoundProp(imagePropTypeUtil);
190
+ const { src, size } = value || {};
177
191
  const setImageSrc = (newValue) => {
178
192
  setValue({
179
- $$type: "image",
180
- value: {
181
- src: newValue,
182
- size
183
- }
193
+ src: newValue,
194
+ size
184
195
  });
185
196
  };
186
197
  const setImageSize = (newValue) => {
187
198
  setValue({
188
- $$type: "image",
189
- value: {
190
- src,
191
- size: newValue
192
- }
199
+ src,
200
+ size: newValue
193
201
  });
194
202
  };
195
203
  return /* @__PURE__ */ React9.createElement(Stack2, { gap: 1.5 }, /* @__PURE__ */ React9.createElement(BoundPropProvider, { value: src, setValue: setImageSrc, bind: "src" }, /* @__PURE__ */ React9.createElement(ImageMediaControl, null)), /* @__PURE__ */ React9.createElement(BoundPropProvider, { value: size, setValue: setImageSize, bind: "size" }, /* @__PURE__ */ React9.createElement(Grid, { container: true, gap: 2, alignItems: "center", flexWrap: "nowrap" }, /* @__PURE__ */ React9.createElement(Grid, { item: true, xs: 6 }, /* @__PURE__ */ React9.createElement(ControlLabel, null, " ", __2("Image Resolution", "elementor"))), /* @__PURE__ */ React9.createElement(Grid, { item: true, xs: 6 }, /* @__PURE__ */ React9.createElement(SelectControl, { options: props.sizes })))));
@@ -197,18 +205,20 @@ var ImageControl = createControl((props) => {
197
205
 
198
206
  // src/controls/text-control.tsx
199
207
  import * as React10 from "react";
208
+ import { stringPropTypeUtil as stringPropTypeUtil2 } from "@elementor/editor-props";
200
209
  import { TextField } from "@elementor/ui";
201
210
  var TextControl = createControl(({ placeholder }) => {
202
- const { value, setValue } = useBoundProp("");
211
+ const { value, setValue } = useBoundProp(stringPropTypeUtil2);
203
212
  const handleChange = (event) => setValue(event.target.value);
204
213
  return /* @__PURE__ */ React10.createElement(ControlActions, null, /* @__PURE__ */ React10.createElement(TextField, { size: "tiny", fullWidth: true, value, onChange: handleChange, placeholder }));
205
214
  });
206
215
 
207
216
  // src/controls/text-area-control.tsx
208
217
  import * as React11 from "react";
218
+ import { stringPropTypeUtil as stringPropTypeUtil3 } from "@elementor/editor-props";
209
219
  import { TextField as TextField2 } from "@elementor/ui";
210
220
  var TextAreaControl = createControl(({ placeholder }) => {
211
- const { value, setValue } = useBoundProp();
221
+ const { value, setValue } = useBoundProp(stringPropTypeUtil3);
212
222
  const handleChange = (event) => {
213
223
  setValue(event.target.value);
214
224
  };
@@ -228,6 +238,7 @@ var TextAreaControl = createControl(({ placeholder }) => {
228
238
 
229
239
  // src/controls/size-control.tsx
230
240
  import * as React13 from "react";
241
+ import { sizePropTypeUtil } from "@elementor/editor-props";
231
242
  import { InputAdornment as InputAdornment2 } from "@elementor/ui";
232
243
 
233
244
  // src/components/text-field-inner-selection.tsx
@@ -291,7 +302,7 @@ var useSyncExternalState = ({
291
302
  if (persistWhen(internalValue)) {
292
303
  return internalValue;
293
304
  }
294
- return void 0;
305
+ return null;
295
306
  }
296
307
  function toInternal(externalValue, internalValue) {
297
308
  if (!externalValue) {
@@ -299,7 +310,7 @@ var useSyncExternalState = ({
299
310
  }
300
311
  return externalValue;
301
312
  }
302
- const [internal, setInternal] = useState(toInternal(external, void 0));
313
+ const [internal, setInternal] = useState(toInternal(external, null));
303
314
  useEffect(() => {
304
315
  setInternal((prevInternal) => toInternal(external, prevInternal));
305
316
  }, [external]);
@@ -317,33 +328,24 @@ var defaultUnits = ["px", "%", "em", "rem", "vw", "vh"];
317
328
  var defaultUnit = "px";
318
329
  var defaultSize = NaN;
319
330
  var SizeControl = createControl(({ units: units2 = defaultUnits, placeholder, startIcon }) => {
320
- const { value, setValue } = useBoundProp();
331
+ const { value, setValue } = useBoundProp(sizePropTypeUtil);
321
332
  const [state, setState] = useSyncExternalState({
322
333
  external: value,
323
334
  setExternal: setValue,
324
- persistWhen: (controlValue) => !!controlValue?.value?.size || controlValue?.value?.size === 0,
325
- fallback: (controlValue) => ({
326
- $$type: "size",
327
- value: { unit: controlValue?.value?.unit || defaultUnit, size: defaultSize }
328
- })
335
+ persistWhen: (controlValue) => !!controlValue?.size || controlValue?.size === 0,
336
+ fallback: (controlValue) => ({ unit: controlValue?.unit || defaultUnit, size: defaultSize })
329
337
  });
330
338
  const handleUnitChange = (unit) => {
331
339
  setState((prev) => ({
332
- ...prev,
333
- value: {
334
- ...prev.value,
335
- unit
336
- }
340
+ size: prev?.size ?? defaultSize,
341
+ unit
337
342
  }));
338
343
  };
339
344
  const handleSizeChange = (event) => {
340
345
  const { value: size } = event.target;
341
346
  setState((prev) => ({
342
347
  ...prev,
343
- value: {
344
- ...prev.value,
345
- size: size || size === "0" ? parseFloat(size) : defaultSize
346
- }
348
+ size: size || size === "0" ? parseFloat(size) : defaultSize
347
349
  }));
348
350
  };
349
351
  return /* @__PURE__ */ React13.createElement(ControlActions, null, /* @__PURE__ */ React13.createElement(
@@ -354,13 +356,13 @@ var SizeControl = createControl(({ units: units2 = defaultUnits, placeholder, st
354
356
  {
355
357
  options: units2,
356
358
  onClick: handleUnitChange,
357
- value: state.value.unit ?? defaultUnit
359
+ value: state?.unit ?? defaultUnit
358
360
  }
359
361
  ),
360
362
  placeholder,
361
363
  startAdornment: startIcon ?? /* @__PURE__ */ React13.createElement(InputAdornment2, { position: "start" }, startIcon),
362
364
  type: "number",
363
- value: Number.isNaN(state.value.size) ? "" : state.value.size,
365
+ value: Number.isNaN(state?.size) ? "" : state?.size,
364
366
  onChange: handleSizeChange
365
367
  }
366
368
  ));
@@ -368,80 +370,48 @@ var SizeControl = createControl(({ units: units2 = defaultUnits, placeholder, st
368
370
 
369
371
  // src/controls/stroke-control.tsx
370
372
  import * as React15 from "react";
373
+ import { strokePropTypeUtil } from "@elementor/editor-props";
371
374
  import { Grid as Grid2, Stack as Stack3 } from "@elementor/ui";
372
375
  import { __ as __3 } from "@wordpress/i18n";
373
376
 
374
377
  // src/controls/color-control.tsx
375
378
  import * as React14 from "react";
379
+ import { colorPropTypeUtil } from "@elementor/editor-props";
376
380
  import { UnstableColorField } from "@elementor/ui";
377
381
  var ColorControl = createControl(
378
382
  (props) => {
379
- const { value, setValue } = useBoundProp();
383
+ const { value, setValue } = useBoundProp(colorPropTypeUtil);
380
384
  const handleChange = (selectedColor) => {
381
- setValue({
382
- $$type: "color",
383
- value: selectedColor
384
- });
385
+ setValue(selectedColor);
385
386
  };
386
- return /* @__PURE__ */ React14.createElement(ControlActions, null, /* @__PURE__ */ React14.createElement(
387
- UnstableColorField,
388
- {
389
- size: "tiny",
390
- ...props,
391
- value: value?.value,
392
- onChange: handleChange,
393
- fullWidth: true
394
- }
395
- ));
387
+ return /* @__PURE__ */ React14.createElement(ControlActions, null, /* @__PURE__ */ React14.createElement(UnstableColorField, { size: "tiny", ...props, value, onChange: handleChange, fullWidth: true }));
396
388
  }
397
389
  );
398
390
 
399
391
  // src/controls/stroke-control.tsx
400
- var defaultStrokeControlValue = {
401
- $$type: "stroke",
402
- value: {
403
- color: {
404
- $$type: "color",
405
- value: "#000000"
406
- },
407
- width: {
408
- $$type: "size",
409
- value: {
410
- unit: "px",
411
- size: NaN
412
- }
413
- }
414
- }
415
- };
416
392
  var units = ["px", "em", "rem"];
417
393
  var StrokeControl = createControl(() => {
418
- const { value, setValue } = useBoundProp(defaultStrokeControlValue);
394
+ const { value, setValue } = useBoundProp(strokePropTypeUtil);
419
395
  const setStrokeWidth = (newValue) => {
420
396
  const updatedValue = {
421
- ...value?.value ?? defaultStrokeControlValue.value,
397
+ ...value,
422
398
  width: newValue
423
399
  };
424
- setValue({
425
- $$type: "stroke",
426
- value: updatedValue
427
- });
400
+ setValue(updatedValue);
428
401
  };
429
402
  const setStrokeColor = (newValue) => {
430
403
  const updatedValue = {
431
- ...value?.value ?? defaultStrokeControlValue.value,
404
+ ...value,
432
405
  color: newValue
433
406
  };
434
- setValue({
435
- $$type: "stroke",
436
- value: updatedValue
437
- });
407
+ setValue(updatedValue);
438
408
  };
439
409
  return /* @__PURE__ */ React15.createElement(Stack3, { gap: 1.5 }, /* @__PURE__ */ React15.createElement(
440
410
  Control,
441
411
  {
442
412
  bind: "width",
443
413
  label: __3("Stroke Width", "elementor"),
444
- value: value?.value.width ?? defaultStrokeControlValue.value.width,
414
+ value: value?.width,
445
415
  setValue: setStrokeWidth
446
416
  },
447
417
  /* @__PURE__ */ React15.createElement(SizeControl, { units })
@@ -450,22 +420,19 @@ var StrokeControl = createControl(() => {
450
420
  {
451
421
  bind: "color",
452
422
  label: __3("Stroke Color", "elementor"),
453
- value: value?.value.color ?? defaultStrokeControlValue.value.color,
423
+ value: value?.color,
454
424
  setValue: setStrokeColor
455
425
  },
456
426
  /* @__PURE__ */ React15.createElement(ColorControl, null)
457
427
  ));
458
428
  });
459
- var Control = ({
460
- bind,
461
- value,
462
- setValue,
463
- label,
464
- children
465
- }) => /* @__PURE__ */ React15.createElement(BoundPropProvider, { bind, value, setValue }, /* @__PURE__ */ React15.createElement(Grid2, { container: true, gap: 2, alignItems: "center", flexWrap: "nowrap" }, /* @__PURE__ */ React15.createElement(Grid2, { item: true, xs: 6 }, /* @__PURE__ */ React15.createElement(ControlLabel, null, label)), /* @__PURE__ */ React15.createElement(Grid2, { item: true, xs: 6 }, children)));
429
+ var Control = ({ bind, value, setValue, label, children }) => /* @__PURE__ */ React15.createElement(BoundPropProvider, { bind, value, setValue }, /* @__PURE__ */ React15.createElement(Grid2, { container: true, gap: 2, alignItems: "center", flexWrap: "nowrap" }, /* @__PURE__ */ React15.createElement(Grid2, { item: true, xs: 6 }, /* @__PURE__ */ React15.createElement(ControlLabel, null, label)), /* @__PURE__ */ React15.createElement(Grid2, { item: true, xs: 6 }, children)));
466
430
 
467
431
  // src/controls/box-shadow-repeater-control.tsx
468
432
  import * as React17 from "react";
433
+ import {
434
+ boxShadowPropTypeUtil
435
+ } from "@elementor/editor-props";
469
436
  import { Grid as Grid3, Stack as Stack5, Typography as Typography3, UnstableColorIndicator } from "@elementor/ui";
470
437
  import { __ as __5 } from "@wordpress/i18n";
471
438
 
@@ -609,18 +576,14 @@ var RepeaterItem = ({
609
576
 
610
577
  // src/controls/box-shadow-repeater-control.tsx
611
578
  var BoxShadowRepeaterControl = createControl(() => {
612
- const { value, setValue } = useBoundProp();
613
- const boxShadowValues = value?.value;
579
+ const { value: boxShadowValues, setValue } = useBoundProp(boxShadowPropTypeUtil);
614
580
  const setBoxShadow = (newValue) => {
615
- setValue({
616
- $$type: "box-shadow",
617
- value: newValue
618
- });
581
+ setValue(newValue);
619
582
  };
620
583
  return /* @__PURE__ */ React17.createElement(
621
584
  Repeater,
622
585
  {
623
- values: boxShadowValues,
586
+ values: boxShadowValues ?? [],
624
587
  setValues: setBoxShadow,
625
588
  label: __5("Box shadow", "elementor"),
626
589
  itemSettings: {
@@ -775,16 +738,15 @@ var initialShadow = {
775
738
 
776
739
  // src/controls/background-overlay-repeater-control.tsx
777
740
  import * as React18 from "react";
741
+ import {
742
+ backgroundImagePropTypeUtil
743
+ } from "@elementor/editor-props";
778
744
  import { Grid as Grid4, Stack as Stack6, Typography as Typography4, UnstableColorIndicator as UnstableColorIndicator2 } from "@elementor/ui";
779
745
  import { __ as __6 } from "@wordpress/i18n";
780
746
  var BackgroundOverlayRepeaterControl = createControl(() => {
781
- const { value, setValue } = useBoundProp();
782
- const colorOverlayValues = value?.value;
747
+ const { value: colorOverlayValues, setValue } = useBoundProp(backgroundImagePropTypeUtil);
783
748
  const setColorOverlay = (newValue) => {
784
- setValue({
785
- $$type: "background-image",
786
- value: newValue
787
- });
749
+ setValue(newValue);
788
750
  };
789
751
  return /* @__PURE__ */ React18.createElement(
790
752
  Repeater,
@@ -846,6 +808,7 @@ var initialGradient = {
846
808
 
847
809
  // src/controls/toggle-control.tsx
848
810
  import * as React20 from "react";
811
+ import { stringPropTypeUtil as stringPropTypeUtil4 } from "@elementor/editor-props";
849
812
 
850
813
  // src/components/control-toggle-button-group.tsx
851
814
  import * as React19 from "react";
@@ -853,7 +816,8 @@ import {
853
816
  styled as styled2,
854
817
  ToggleButton,
855
818
  ToggleButtonGroup,
856
- Tooltip
819
+ Tooltip,
820
+ useTheme
857
821
  } from "@elementor/ui";
858
822
  var StyledToggleButtonGroup = styled2(ToggleButtonGroup)`
859
823
  ${({ justify }) => `justify-content: ${justify};`}
@@ -867,28 +831,41 @@ var ControlToggleButtonGroup = ({
867
831
  exclusive = false,
868
832
  fullWidth = false
869
833
  }) => {
834
+ const isRtl = "rtl" === useTheme().direction;
870
835
  const handleChange = (_, newValue) => {
871
836
  onChange(newValue);
872
837
  };
873
- return /* @__PURE__ */ React19.createElement(StyledToggleButtonGroup, { justify, value, onChange: handleChange, exclusive }, items.map(
874
- ({ label, value: buttonValue, renderContent: Content, showTooltip }) => showTooltip ? /* @__PURE__ */ React19.createElement(Tooltip, { key: buttonValue, title: label, disableFocusListener: true, placement: "top" }, /* @__PURE__ */ React19.createElement(ToggleButton, { value: buttonValue, "aria-label": label, size, fullWidth }, /* @__PURE__ */ React19.createElement(Content, { size }))) : /* @__PURE__ */ React19.createElement(
875
- ToggleButton,
876
- {
877
- key: buttonValue,
878
- value: buttonValue,
879
- "aria-label": label,
880
- size,
881
- fullWidth
882
- },
883
- /* @__PURE__ */ React19.createElement(Content, { size })
838
+ return /* @__PURE__ */ React19.createElement(
839
+ StyledToggleButtonGroup,
840
+ {
841
+ justify,
842
+ value,
843
+ onChange: handleChange,
844
+ exclusive,
845
+ sx: {
846
+ direction: isRtl ? "rtl /* @noflip */" : "ltr /* @noflip */"
847
+ }
848
+ },
849
+ items.map(
850
+ ({ label, value: buttonValue, renderContent: Content, showTooltip }) => showTooltip ? /* @__PURE__ */ React19.createElement(Tooltip, { key: buttonValue, title: label, disableFocusListener: true, placement: "top" }, /* @__PURE__ */ React19.createElement(ToggleButton, { value: buttonValue, "aria-label": label, size, fullWidth }, /* @__PURE__ */ React19.createElement(Content, { size }))) : /* @__PURE__ */ React19.createElement(
851
+ ToggleButton,
852
+ {
853
+ key: buttonValue,
854
+ value: buttonValue,
855
+ "aria-label": label,
856
+ size,
857
+ fullWidth
858
+ },
859
+ /* @__PURE__ */ React19.createElement(Content, { size })
860
+ )
884
861
  )
885
- ));
862
+ );
886
863
  };
887
864
 
888
865
  // src/controls/toggle-control.tsx
889
866
  var ToggleControl = createControl(
890
867
  ({ options, fullWidth = false, size = "tiny" }) => {
891
- const { value, setValue } = useBoundProp();
868
+ const { value, setValue } = useBoundProp(stringPropTypeUtil4);
892
869
  const handleToggle = (option) => {
893
870
  setValue(option);
894
871
  };
@@ -896,7 +873,7 @@ var ToggleControl = createControl(
896
873
  ControlToggleButtonGroup,
897
874
  {
898
875
  items: options,
899
- value: value || null,
876
+ value: value ?? null,
900
877
  onChange: handleToggle,
901
878
  exclusive: true,
902
879
  fullWidth,
@@ -908,76 +885,91 @@ var ToggleControl = createControl(
908
885
 
909
886
  // src/controls/number-control.tsx
910
887
  import * as React21 from "react";
888
+ import { numberPropTypeUtil } from "@elementor/editor-props";
911
889
  import { TextField as TextField4 } from "@elementor/ui";
912
- var isEmptyOrNaN = (value) => value === void 0 || value === "" || Number.isNaN(Number(value));
913
- var NumberControl = createControl(({ placeholder }) => {
914
- const { value, setValue } = useBoundProp();
915
- const handleChange = (event) => {
916
- const eventValue = event.target.value;
917
- setValue(isEmptyOrNaN(eventValue) ? void 0 : Number(eventValue));
918
- };
919
- return /* @__PURE__ */ React21.createElement(ControlActions, null, /* @__PURE__ */ React21.createElement(
920
- TextField4,
921
- {
922
- size: "tiny",
923
- type: "number",
924
- fullWidth: true,
925
- value: isEmptyOrNaN(value) ? "" : value,
926
- onChange: handleChange,
927
- placeholder
928
- }
929
- ));
930
- });
890
+ var isEmptyOrNaN = (value) => value === null || value === void 0 || value === "" || Number.isNaN(Number(value));
891
+ var NumberControl = createControl(
892
+ ({
893
+ placeholder,
894
+ max = Number.MAX_VALUE,
895
+ min = -Number.MAX_VALUE,
896
+ step = 1,
897
+ shouldForceInt = false
898
+ }) => {
899
+ const { value, setValue } = useBoundProp(numberPropTypeUtil);
900
+ const handleChange = (event) => {
901
+ const eventValue = event.target.value;
902
+ if (isEmptyOrNaN(eventValue)) {
903
+ setValue(null);
904
+ return;
905
+ }
906
+ const formattedValue = shouldForceInt ? +parseInt(eventValue) : Number(eventValue);
907
+ setValue(Math.min(Math.max(formattedValue, min), max));
908
+ };
909
+ return /* @__PURE__ */ React21.createElement(ControlActions, null, /* @__PURE__ */ React21.createElement(
910
+ TextField4,
911
+ {
912
+ size: "tiny",
913
+ type: "number",
914
+ fullWidth: true,
915
+ value: isEmptyOrNaN(value) ? "" : value,
916
+ onChange: handleChange,
917
+ placeholder,
918
+ inputProps: { step }
919
+ }
920
+ ));
921
+ }
922
+ );
931
923
 
932
924
  // src/controls/equal-unequal-sizes-control.tsx
933
925
  import * as React22 from "react";
934
926
  import { useId as useId3, useRef as useRef2 } from "react";
927
+ import {
928
+ sizePropTypeUtil as sizePropTypeUtil2
929
+ } from "@elementor/editor-props";
935
930
  import { bindPopover as bindPopover2, bindToggle, Grid as Grid5, Popover as Popover2, Stack as Stack7, ToggleButton as ToggleButton2, usePopupState as usePopupState3 } from "@elementor/ui";
936
931
  import { __ as __7 } from "@wordpress/i18n";
937
- function hasMixedSizes(values) {
932
+ var isEqualSizes = (values, items) => {
933
+ if (values.length !== items.length) {
934
+ return false;
935
+ }
938
936
  const [firstValue, ...restValues] = values;
939
- return restValues.some(
940
- (value) => value?.value?.size !== firstValue?.value?.size || value?.value?.unit !== firstValue?.value?.unit
937
+ return restValues.every(
938
+ (value) => value.value?.size === firstValue.value?.size && value.value?.unit === firstValue.value?.unit
941
939
  );
942
- }
943
- function getMultiSizeProps(controlValue, items) {
944
- return controlValue?.$$type === "size" ? items.reduce((values, item) => {
945
- const { bind } = item;
946
- values[bind] = controlValue;
947
- return values;
948
- }, {}) : controlValue?.value ?? {};
949
- }
950
- function EqualUnequalSizesControl({ label, icon, items, multiSizeType }) {
940
+ };
941
+ function EqualUnequalSizesControl({
942
+ label,
943
+ icon,
944
+ items,
945
+ multiSizePropTypeUtil
946
+ }) {
951
947
  const popupId = useId3();
952
948
  const controlRef = useRef2(null);
953
- const { value: controlValue, setValue: setControlValue } = useBoundProp();
954
- const setMultiSizeValue = (newValue) => {
955
- setControlValue({ $$type: multiSizeType, value: newValue });
949
+ const popupState = usePopupState3({ variant: "popover", popupId });
950
+ const { value: sizeValue, setValue: setSizeValue } = useBoundProp(sizePropTypeUtil2);
951
+ const { value: multiSizeValue, setValue: setMultiSizeValue } = useBoundProp(multiSizePropTypeUtil);
952
+ const splitEqualValue = () => {
953
+ return items.reduce((acc, item) => ({ ...acc, [item.bind]: sizePropTypeUtil2.create(sizeValue) }), {});
956
954
  };
957
- const mappedValues = getMultiSizeProps(controlValue, items);
958
955
  const setNestedProp = (item, newValue) => {
959
- const { bind } = item;
960
956
  const newMappedValues = {
961
- ...mappedValues,
962
- [bind]: newValue
957
+ ...multiSizeValue ?? splitEqualValue(),
958
+ [item.bind]: newValue
963
959
  };
964
- const sizes = Object.values(newMappedValues);
965
- const isMixed = hasMixedSizes(sizes);
966
- if (isMixed) {
967
- setMultiSizeValue(newMappedValues);
968
- return;
960
+ const isEqual = isEqualSizes(Object.values(newMappedValues), items);
961
+ if (isEqual) {
962
+ return setSizeValue(newValue?.value);
969
963
  }
970
- setControlValue(newValue);
964
+ setMultiSizeValue(newMappedValues);
971
965
  };
972
- const popupState = usePopupState3({
973
- variant: "popover",
974
- popupId
975
- });
976
966
  return /* @__PURE__ */ React22.createElement(React22.Fragment, null, /* @__PURE__ */ React22.createElement(Grid5, { container: true, gap: 2, alignItems: "center", flexWrap: "nowrap", ref: controlRef }, /* @__PURE__ */ React22.createElement(Grid5, { item: true, xs: 6 }, /* @__PURE__ */ React22.createElement(ControlLabel, null, label)), /* @__PURE__ */ React22.createElement(Grid5, { item: true, xs: 6 }, /* @__PURE__ */ React22.createElement(
977
- EqualValuesControl,
967
+ EqualSizeControl,
978
968
  {
979
- value: mappedValues,
980
- setValue: setControlValue,
969
+ items,
970
+ value: sizeValue,
971
+ multiSizeValue,
972
+ setValue: setSizeValue,
981
973
  iconButton: /* @__PURE__ */ React22.createElement(
982
974
  ToggleButton2,
983
975
  {
@@ -1009,79 +1001,86 @@ function EqualUnequalSizesControl({ label, icon, items, multiSizeType }) {
1009
1001
  }
1010
1002
  },
1011
1003
  /* @__PURE__ */ React22.createElement(Stack7, { gap: 1.5 }, /* @__PURE__ */ React22.createElement(Grid5, { container: true, gap: 2, alignItems: "center", flexWrap: "nowrap" }, /* @__PURE__ */ React22.createElement(
1012
- NestedValueControl,
1004
+ MultiSizeValueControl,
1013
1005
  {
1014
1006
  item: items[0],
1015
- value: mappedValues,
1016
- setNestedProp
1007
+ value: multiSizeValue,
1008
+ setNestedProp,
1009
+ splitEqualValue
1017
1010
  }
1018
1011
  ), /* @__PURE__ */ React22.createElement(
1019
- NestedValueControl,
1012
+ MultiSizeValueControl,
1020
1013
  {
1021
1014
  item: items[1],
1022
- value: mappedValues,
1023
- setNestedProp
1015
+ value: multiSizeValue,
1016
+ setNestedProp,
1017
+ splitEqualValue
1024
1018
  }
1025
1019
  )), /* @__PURE__ */ React22.createElement(Grid5, { container: true, gap: 2, alignItems: "center", flexWrap: "nowrap" }, /* @__PURE__ */ React22.createElement(
1026
- NestedValueControl,
1020
+ MultiSizeValueControl,
1027
1021
  {
1028
1022
  item: items[3],
1029
- value: mappedValues,
1030
- setNestedProp
1023
+ value: multiSizeValue,
1024
+ setNestedProp,
1025
+ splitEqualValue
1031
1026
  }
1032
1027
  ), /* @__PURE__ */ React22.createElement(
1033
- NestedValueControl,
1028
+ MultiSizeValueControl,
1034
1029
  {
1035
1030
  item: items[2],
1036
- value: mappedValues,
1037
- setNestedProp
1031
+ value: multiSizeValue,
1032
+ setNestedProp,
1033
+ splitEqualValue
1038
1034
  }
1039
1035
  )))
1040
1036
  ));
1041
1037
  }
1042
- var NestedValueControl = ({
1038
+ var MultiSizeValueControl = ({
1043
1039
  item,
1044
1040
  value,
1045
- setNestedProp
1041
+ setNestedProp,
1042
+ splitEqualValue
1046
1043
  }) => {
1047
- const { bind } = item;
1048
- const nestedValue = value?.[bind] ? value[bind] : void 0;
1049
- return /* @__PURE__ */ React22.createElement(
1050
- BoundPropProvider,
1051
- {
1052
- bind: "",
1053
- setValue: (val) => setNestedProp(item, val),
1054
- value: nestedValue
1055
- },
1056
- /* @__PURE__ */ React22.createElement(Grid5, { item: true, xs: 6 }, /* @__PURE__ */ React22.createElement(Grid5, { container: true, gap: 1, alignItems: "center" }, /* @__PURE__ */ React22.createElement(Grid5, { item: true, xs: 12 }, /* @__PURE__ */ React22.createElement(ControlLabel, null, item.label)), /* @__PURE__ */ React22.createElement(Grid5, { item: true, xs: 12 }, /* @__PURE__ */ React22.createElement(SizeControl, { startIcon: item.icon }))))
1057
- );
1044
+ const handleChange = (val) => setNestedProp(item, val);
1045
+ const getMultiSizeValues = () => {
1046
+ if (value) {
1047
+ return value?.[item.bind] ?? null;
1048
+ }
1049
+ return splitEqualValue()?.[item.bind] ?? null;
1050
+ };
1051
+ return /* @__PURE__ */ React22.createElement(BoundPropProvider, { bind: "", setValue: handleChange, value: getMultiSizeValues() }, /* @__PURE__ */ React22.createElement(Grid5, { item: true, xs: 6 }, /* @__PURE__ */ React22.createElement(Grid5, { container: true, gap: 1, alignItems: "center" }, /* @__PURE__ */ React22.createElement(Grid5, { item: true, xs: 12 }, /* @__PURE__ */ React22.createElement(ControlLabel, null, item.label)), /* @__PURE__ */ React22.createElement(Grid5, { item: true, xs: 12 }, /* @__PURE__ */ React22.createElement(SizeControl, { startIcon: item.icon })))));
1058
1052
  };
1059
- var EqualValuesControl = ({
1053
+ var EqualSizeControl = ({
1060
1054
  value,
1055
+ items,
1061
1056
  setValue,
1062
- iconButton
1057
+ iconButton,
1058
+ multiSizeValue
1063
1059
  }) => {
1064
- const values = Object.values(value ?? {});
1065
- const isMixed = hasMixedSizes(values);
1066
- return /* @__PURE__ */ React22.createElement(
1067
- BoundPropProvider,
1068
- {
1069
- bind: "",
1070
- setValue: (val) => setValue(val),
1071
- value: isMixed ? void 0 : values[0]
1072
- },
1073
- /* @__PURE__ */ React22.createElement(Stack7, { direction: "row", alignItems: "center", gap: 1 }, /* @__PURE__ */ React22.createElement(SizeControl, { placeholder: __7("MIXED", "elementor") }), iconButton)
1074
- );
1060
+ const handleChange = (newValue) => {
1061
+ setValue(newValue.value);
1062
+ };
1063
+ const getDisplayValue = () => {
1064
+ if (value) {
1065
+ return sizePropTypeUtil2.create(value);
1066
+ }
1067
+ const multiValues = Object.values(multiSizeValue ?? {});
1068
+ if (isEqualSizes(multiValues, items)) {
1069
+ return sizePropTypeUtil2.create(multiValues[0].value);
1070
+ }
1071
+ };
1072
+ return /* @__PURE__ */ React22.createElement(BoundPropProvider, { bind: "", setValue: handleChange, value: getDisplayValue() ?? null }, /* @__PURE__ */ React22.createElement(Stack7, { direction: "row", alignItems: "center", gap: 1 }, /* @__PURE__ */ React22.createElement(SizeControl, { placeholder: __7("MIXED", "elementor") }), iconButton));
1075
1073
  };
1076
1074
 
1077
1075
  // src/controls/linked-dimensions-control.tsx
1078
1076
  import * as React23 from "react";
1077
+ import { linkedDimensionsPropTypeUtil } from "@elementor/editor-props";
1079
1078
  import { DetachIcon, LinkIcon, SideBottomIcon, SideLeftIcon, SideRightIcon, SideTopIcon } from "@elementor/icons";
1080
1079
  import { Grid as Grid6, Stack as Stack8, ToggleButton as ToggleButton3 } from "@elementor/ui";
1081
1080
  import { __ as __8 } from "@wordpress/i18n";
1082
1081
  var LinkedDimensionsControl = createControl(({ label }) => {
1083
- const { value, setValue } = useBoundProp();
1084
- const { top, right, bottom, left, isLinked = true } = value?.value || {};
1082
+ const { value, setValue } = useBoundProp(linkedDimensionsPropTypeUtil);
1083
+ const { top, right, bottom, left, isLinked = true } = value || {};
1085
1084
  const setLinkedValue = (position, newValue) => {
1086
1085
  const updatedValue = {
1087
1086
  isLinked,
@@ -1091,10 +1090,7 @@ var LinkedDimensionsControl = createControl(({ label }) => {
1091
1090
  left: isLinked ? newValue : left,
1092
1091
  [position]: newValue
1093
1092
  };
1094
- setValue({
1095
- $$type: "linked-dimensions",
1096
- value: updatedValue
1097
- });
1093
+ setValue(updatedValue);
1098
1094
  };
1099
1095
  const toggleLinked = () => {
1100
1096
  const updatedValue = {
@@ -1104,10 +1100,7 @@ var LinkedDimensionsControl = createControl(({ label }) => {
1104
1100
  bottom: !isLinked ? top : bottom,
1105
1101
  left: !isLinked ? top : left
1106
1102
  };
1107
- setValue({
1108
- $$type: "linked-dimensions",
1109
- value: updatedValue
1110
- });
1103
+ setValue(updatedValue);
1111
1104
  };
1112
1105
  const LinkedIcon = isLinked ? LinkIcon : DetachIcon;
1113
1106
  return /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(Stack8, { direction: "row", gap: 2, flexWrap: "nowrap" }, /* @__PURE__ */ React23.createElement(ControlLabel, null, label), /* @__PURE__ */ React23.createElement(
@@ -1165,6 +1158,7 @@ var Control4 = ({
1165
1158
  // src/controls/font-family-control.tsx
1166
1159
  import { Fragment as Fragment4, useId as useId4, useState as useState3 } from "react";
1167
1160
  import * as React24 from "react";
1161
+ import { stringPropTypeUtil as stringPropTypeUtil5 } from "@elementor/editor-props";
1168
1162
  import { ChevronDownIcon, EditIcon, PhotoIcon, SearchIcon, XIcon as XIcon2 } from "@elementor/icons";
1169
1163
  import {
1170
1164
  bindPopover as bindPopover3,
@@ -1219,8 +1213,8 @@ var useFilteredFontFamilies = (fontFamilies, searchValue) => {
1219
1213
  // src/controls/font-family-control.tsx
1220
1214
  var SIZE2 = "tiny";
1221
1215
  var FontFamilyControl = createControl(({ fontFamilies }) => {
1222
- const { value: fontFamily, setValue: setFontFamily } = useBoundProp();
1223
1216
  const [searchValue, setSearchValue] = useState3("");
1217
+ const { value: fontFamily, setValue: setFontFamily } = useBoundProp(stringPropTypeUtil5);
1224
1218
  const popupId = useId4();
1225
1219
  const popoverState = usePopupState4({ variant: "popover", popupId });
1226
1220
  const filteredFontFamilies = useFilteredFontFamilies(fontFamilies, searchValue);
@@ -1293,6 +1287,87 @@ var FontFamilyControl = createControl(({ fontFamilies }) => {
1293
1287
  ), "\xA0", __10("and try again.", "elementor")))))
1294
1288
  ));
1295
1289
  });
1290
+
1291
+ // src/controls/url-control.tsx
1292
+ import * as React25 from "react";
1293
+ import { TextField as TextField6 } from "@elementor/ui";
1294
+ var UrlControl = createControl(({ placeholder }) => {
1295
+ const { value, setValue } = useBoundProp();
1296
+ const handleChange = (event) => setValue({
1297
+ $$type: "url",
1298
+ value: event.target.value
1299
+ });
1300
+ return /* @__PURE__ */ React25.createElement(ControlActions, null, /* @__PURE__ */ React25.createElement(
1301
+ TextField6,
1302
+ {
1303
+ size: "tiny",
1304
+ fullWidth: true,
1305
+ value: value?.value,
1306
+ onChange: handleChange,
1307
+ placeholder
1308
+ }
1309
+ ));
1310
+ });
1311
+
1312
+ // src/controls/link-control.tsx
1313
+ import * as React26 from "react";
1314
+ import { MinusIcon, PlusIcon as PlusIcon2 } from "@elementor/icons";
1315
+ import { Collapse, Divider as Divider2, Grid as Grid7, IconButton as IconButton3, Stack as Stack10, Switch } from "@elementor/ui";
1316
+ import { __ as __11 } from "@wordpress/i18n";
1317
+ var SIZE3 = "tiny";
1318
+ var DEFAULT_LINK_CONTROL_VALUE = {
1319
+ $$type: "link",
1320
+ value: {
1321
+ enabled: false,
1322
+ href: {
1323
+ $$type: "url",
1324
+ value: ""
1325
+ },
1326
+ isTargetBlank: false
1327
+ }
1328
+ };
1329
+ var LinkControl = createControl(() => {
1330
+ const { value = DEFAULT_LINK_CONTROL_VALUE, setValue } = useBoundProp();
1331
+ const { enabled, href, isTargetBlank } = value?.value || {};
1332
+ const handleOnChange = (key, newValue) => {
1333
+ setValue({
1334
+ $$type: "link",
1335
+ value: {
1336
+ ...value?.value ?? DEFAULT_LINK_CONTROL_VALUE.value,
1337
+ [key]: newValue
1338
+ }
1339
+ });
1340
+ };
1341
+ return /* @__PURE__ */ React26.createElement(Stack10, { gap: 1.5 }, /* @__PURE__ */ React26.createElement(Divider2, null), /* @__PURE__ */ React26.createElement(
1342
+ Stack10,
1343
+ {
1344
+ direction: "row",
1345
+ sx: {
1346
+ justifyContent: "space-between",
1347
+ alignItems: "center"
1348
+ }
1349
+ },
1350
+ /* @__PURE__ */ React26.createElement(ControlLabel, null, __11("Link", "elementor")),
1351
+ /* @__PURE__ */ React26.createElement(IconButton3, { size: SIZE3, onClick: () => handleOnChange("enabled", !enabled) }, enabled ? /* @__PURE__ */ React26.createElement(MinusIcon, { fontSize: SIZE3 }) : /* @__PURE__ */ React26.createElement(PlusIcon2, { fontSize: SIZE3 }))
1352
+ ), /* @__PURE__ */ React26.createElement(Collapse, { in: enabled, timeout: "auto", unmountOnExit: true }, /* @__PURE__ */ React26.createElement(Stack10, { gap: 1.5 }, /* @__PURE__ */ React26.createElement(
1353
+ BoundPropProvider,
1354
+ {
1355
+ value: href,
1356
+ setValue: (newHref) => handleOnChange("href", newHref),
1357
+ bind: "href"
1358
+ },
1359
+ /* @__PURE__ */ React26.createElement(UrlControl, { placeholder: __11("Paste URL or type", "elementor") })
1360
+ ), /* @__PURE__ */ React26.createElement(
1361
+ SwitchControl,
1362
+ {
1363
+ value: isTargetBlank,
1364
+ onSwitch: () => handleOnChange("isTargetBlank", !isTargetBlank)
1365
+ }
1366
+ ))));
1367
+ });
1368
+ var SwitchControl = ({ value, onSwitch }) => {
1369
+ return /* @__PURE__ */ React26.createElement(Grid7, { container: true, alignItems: "center", flexWrap: "nowrap", justifyContent: "space-between" }, /* @__PURE__ */ React26.createElement(Grid7, { item: true }, /* @__PURE__ */ React26.createElement(ControlLabel, null, __11("Open in new tab", "elementor"))), /* @__PURE__ */ React26.createElement(Grid7, { item: true }, /* @__PURE__ */ React26.createElement(Switch, { checked: value, onChange: onSwitch })));
1370
+ };
1296
1371
  export {
1297
1372
  BackgroundOverlayRepeaterControl,
1298
1373
  BoundPropProvider,
@@ -1301,9 +1376,11 @@ export {
1301
1376
  ControlActionsProvider,
1302
1377
  ControlLabel,
1303
1378
  ControlReplacementProvider,
1379
+ ControlToggleButtonGroup,
1304
1380
  EqualUnequalSizesControl,
1305
1381
  FontFamilyControl,
1306
1382
  ImageControl,
1383
+ LinkControl,
1307
1384
  LinkedDimensionsControl,
1308
1385
  NumberControl,
1309
1386
  SelectControl,
@@ -1312,6 +1389,7 @@ export {
1312
1389
  TextAreaControl,
1313
1390
  TextControl,
1314
1391
  ToggleControl,
1392
+ UrlControl,
1315
1393
  createControlReplacement,
1316
1394
  useBoundProp,
1317
1395
  useControlActions,