@elementor/editor-controls 0.1.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.
Files changed (36) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +4 -0
  3. package/dist/index.d.mts +148 -0
  4. package/dist/index.d.ts +148 -0
  5. package/dist/index.js +1346 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/index.mjs +1320 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/package.json +52 -0
  10. package/src/bound-prop-context.tsx +30 -0
  11. package/src/components/control-label.tsx +10 -0
  12. package/src/components/control-toggle-button-group.tsx +84 -0
  13. package/src/components/repeater.tsx +200 -0
  14. package/src/components/text-field-inner-selection.tsx +76 -0
  15. package/src/control-actions/control-actions-context.tsx +27 -0
  16. package/src/control-actions/control-actions.tsx +32 -0
  17. package/src/controls/background-overlay-repeater-control.tsx +119 -0
  18. package/src/controls/box-shadow-repeater-control.tsx +227 -0
  19. package/src/controls/color-control.tsx +32 -0
  20. package/src/controls/equal-unequal-sizes-control.tsx +231 -0
  21. package/src/controls/font-family-control.tsx +154 -0
  22. package/src/controls/image-control.tsx +64 -0
  23. package/src/controls/image-media-control.tsx +71 -0
  24. package/src/controls/linked-dimensions-control.tsx +140 -0
  25. package/src/controls/number-control.tsx +31 -0
  26. package/src/controls/select-control.tsx +31 -0
  27. package/src/controls/size-control.tsx +77 -0
  28. package/src/controls/stroke-control.tsx +106 -0
  29. package/src/controls/text-area-control.tsx +32 -0
  30. package/src/controls/text-control.tsx +18 -0
  31. package/src/controls/toggle-control.tsx +34 -0
  32. package/src/create-control-replacement.tsx +54 -0
  33. package/src/create-control.tsx +41 -0
  34. package/src/hooks/use-filtered-font-families.ts +38 -0
  35. package/src/hooks/use-sync-external-state.tsx +51 -0
  36. package/src/index.ts +31 -0
package/dist/index.mjs ADDED
@@ -0,0 +1,1320 @@
1
+ // src/controls/image-control.tsx
2
+ import * as React9 from "react";
3
+ import { Grid, Stack as Stack2 } from "@elementor/ui";
4
+ import { __ as __2 } from "@wordpress/i18n";
5
+
6
+ // src/bound-prop-context.tsx
7
+ import * as React from "react";
8
+ import { createContext, useContext } from "react";
9
+ var BoundPropContext = createContext(null);
10
+ var BoundPropProvider = ({ children, value, setValue, bind }) => {
11
+ return /* @__PURE__ */ React.createElement(BoundPropContext.Provider, { value: { value, setValue, bind } }, children);
12
+ };
13
+ function useBoundProp(defaultValue) {
14
+ const boundPropContext = useContext(BoundPropContext);
15
+ if (!boundPropContext) {
16
+ throw new Error("useBoundProp must be used within a BoundPropContext");
17
+ }
18
+ return { ...boundPropContext, value: boundPropContext.value ?? defaultValue };
19
+ }
20
+
21
+ // src/components/control-label.tsx
22
+ import * as React2 from "react";
23
+ import { Typography } from "@elementor/ui";
24
+ var ControlLabel = ({ children }) => {
25
+ return /* @__PURE__ */ React2.createElement(Typography, { component: "label", variant: "caption", color: "text.secondary" }, children);
26
+ };
27
+
28
+ // src/create-control.tsx
29
+ import * as React4 from "react";
30
+ import { ErrorBoundary } from "@elementor/ui";
31
+
32
+ // src/create-control-replacement.tsx
33
+ import * as React3 from "react";
34
+ import { createContext as createContext2, useContext as useContext2 } from "react";
35
+ var ControlReplacementContext = createContext2(void 0);
36
+ var ControlReplacementProvider = ({
37
+ component,
38
+ condition,
39
+ children
40
+ }) => {
41
+ return /* @__PURE__ */ React3.createElement(ControlReplacementContext.Provider, { value: { component, condition } }, children);
42
+ };
43
+ var useControlReplacement = () => {
44
+ const { value } = useBoundProp();
45
+ const controlReplacement = useContext2(ControlReplacementContext);
46
+ let shouldReplace = false;
47
+ try {
48
+ shouldReplace = !!controlReplacement?.condition({ value }) && !!controlReplacement.component;
49
+ } catch {
50
+ }
51
+ return shouldReplace ? controlReplacement?.component : void 0;
52
+ };
53
+ var createControlReplacement = () => {
54
+ let controlReplacement;
55
+ function replaceControl({ component, condition }) {
56
+ controlReplacement = { component, condition };
57
+ }
58
+ function getControlReplacement() {
59
+ return controlReplacement;
60
+ }
61
+ return { replaceControl, getControlReplacement };
62
+ };
63
+
64
+ // src/create-control.tsx
65
+ var brandSymbol = Symbol("control");
66
+ function createControl(Component, { supportsReplacements = true } = {}) {
67
+ return (props) => {
68
+ const ControlReplacement = useControlReplacement();
69
+ if (ControlReplacement && supportsReplacements) {
70
+ return /* @__PURE__ */ React4.createElement(ErrorBoundary, { fallback: null }, /* @__PURE__ */ React4.createElement(ControlReplacement, { ...props }));
71
+ }
72
+ return /* @__PURE__ */ React4.createElement(ErrorBoundary, { fallback: null }, /* @__PURE__ */ React4.createElement(Component, { ...props }));
73
+ };
74
+ }
75
+
76
+ // src/controls/image-media-control.tsx
77
+ import * as React7 from "react";
78
+ import { UploadIcon } from "@elementor/icons";
79
+ import { Button, Card, CardMedia, CardOverlay, CircularProgress, Stack } from "@elementor/ui";
80
+ import { useWpMediaAttachment, useWpMediaFrame } from "@elementor/wp-media";
81
+ import { __ } from "@wordpress/i18n";
82
+
83
+ // src/control-actions/control-actions.tsx
84
+ import * as React6 from "react";
85
+ import { styled, UnstableFloatingActionBar } from "@elementor/ui";
86
+
87
+ // src/control-actions/control-actions-context.tsx
88
+ import * as React5 from "react";
89
+ import { createContext as createContext3, useContext as useContext3 } from "react";
90
+ var Context = createContext3(null);
91
+ var ControlActionsProvider = ({ children, items }) => /* @__PURE__ */ React5.createElement(Context.Provider, { value: { items } }, children);
92
+ var useControlActions = () => {
93
+ const context = useContext3(Context);
94
+ if (!context) {
95
+ throw new Error("useControlActions must be used within a ControlActionsProvider");
96
+ }
97
+ return context;
98
+ };
99
+
100
+ // src/control-actions/control-actions.tsx
101
+ var FloatingBarContainer = styled("span")`
102
+ display: contents;
103
+
104
+ .MuiFloatingActionBar-popper:has( .MuiFloatingActionBar-actions:empty ) {
105
+ display: none;
106
+ }
107
+ `;
108
+ function ControlActions({ children }) {
109
+ const { items } = useControlActions();
110
+ if (items.length === 0) {
111
+ return children;
112
+ }
113
+ const menuItems = items.map(({ MenuItem: MenuItem4, id }) => /* @__PURE__ */ React6.createElement(MenuItem4, { key: id }));
114
+ return /* @__PURE__ */ React6.createElement(FloatingBarContainer, null, /* @__PURE__ */ React6.createElement(UnstableFloatingActionBar, { actions: menuItems }, children));
115
+ }
116
+
117
+ // src/controls/image-media-control.tsx
118
+ var ImageMediaControl = createControl(() => {
119
+ const { value, setValue } = useBoundProp();
120
+ const { id, url } = value?.value ?? {};
121
+ const { data: attachment, isFetching } = useWpMediaAttachment(id?.value || null);
122
+ const src = attachment?.url ?? url;
123
+ const { open } = useWpMediaFrame({
124
+ types: ["image"],
125
+ multiple: false,
126
+ selected: id?.value || null,
127
+ onSelect: (selectedAttachment) => {
128
+ setValue({
129
+ $$type: "image-src",
130
+ value: {
131
+ id: {
132
+ $$type: "image-attachment-id",
133
+ value: selectedAttachment.id
134
+ },
135
+ url: null
136
+ }
137
+ });
138
+ }
139
+ });
140
+ return /* @__PURE__ */ React7.createElement(Card, { variant: "outlined" }, /* @__PURE__ */ React7.createElement(CardMedia, { image: src, sx: { height: 150 } }, isFetching ? /* @__PURE__ */ React7.createElement(Stack, { justifyContent: "center", alignItems: "center", width: "100%", height: "100%" }, /* @__PURE__ */ React7.createElement(CircularProgress, null)) : null), /* @__PURE__ */ React7.createElement(CardOverlay, null, /* @__PURE__ */ React7.createElement(ControlActions, null, /* @__PURE__ */ React7.createElement(Stack, { gap: 1 }, /* @__PURE__ */ React7.createElement(
141
+ Button,
142
+ {
143
+ size: "tiny",
144
+ color: "inherit",
145
+ variant: "outlined",
146
+ onClick: () => open({ mode: "browse" })
147
+ },
148
+ __("Select Image", "elementor")
149
+ ), /* @__PURE__ */ React7.createElement(
150
+ Button,
151
+ {
152
+ size: "tiny",
153
+ variant: "text",
154
+ color: "inherit",
155
+ startIcon: /* @__PURE__ */ React7.createElement(UploadIcon, null),
156
+ onClick: () => open({ mode: "upload" })
157
+ },
158
+ __("Upload Image", "elementor")
159
+ )))));
160
+ });
161
+
162
+ // src/controls/select-control.tsx
163
+ import * as React8 from "react";
164
+ import { MenuItem, Select } from "@elementor/ui";
165
+ var SelectControl = createControl(({ options }) => {
166
+ const { value, setValue } = useBoundProp();
167
+ const handleChange = (event) => {
168
+ setValue(event.target.value);
169
+ };
170
+ return /* @__PURE__ */ React8.createElement(ControlActions, null, /* @__PURE__ */ React8.createElement(Select, { displayEmpty: true, size: "tiny", value: value ?? "", onChange: handleChange, fullWidth: true }, options.map(({ label, ...props }) => /* @__PURE__ */ React8.createElement(MenuItem, { key: props.value, ...props }, label))));
171
+ });
172
+
173
+ // src/controls/image-control.tsx
174
+ var ImageControl = createControl((props) => {
175
+ const { value, setValue } = useBoundProp();
176
+ const { src, size } = value?.value || {};
177
+ const setImageSrc = (newValue) => {
178
+ setValue({
179
+ $$type: "image",
180
+ value: {
181
+ src: newValue,
182
+ size
183
+ }
184
+ });
185
+ };
186
+ const setImageSize = (newValue) => {
187
+ setValue({
188
+ $$type: "image",
189
+ value: {
190
+ src,
191
+ size: newValue
192
+ }
193
+ });
194
+ };
195
+ 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 })))));
196
+ });
197
+
198
+ // src/controls/text-control.tsx
199
+ import * as React10 from "react";
200
+ import { TextField } from "@elementor/ui";
201
+ var TextControl = createControl(({ placeholder }) => {
202
+ const { value, setValue } = useBoundProp("");
203
+ const handleChange = (event) => setValue(event.target.value);
204
+ return /* @__PURE__ */ React10.createElement(ControlActions, null, /* @__PURE__ */ React10.createElement(TextField, { size: "tiny", fullWidth: true, value, onChange: handleChange, placeholder }));
205
+ });
206
+
207
+ // src/controls/text-area-control.tsx
208
+ import * as React11 from "react";
209
+ import { TextField as TextField2 } from "@elementor/ui";
210
+ var TextAreaControl = createControl(({ placeholder }) => {
211
+ const { value, setValue } = useBoundProp();
212
+ const handleChange = (event) => {
213
+ setValue(event.target.value);
214
+ };
215
+ return /* @__PURE__ */ React11.createElement(ControlActions, null, /* @__PURE__ */ React11.createElement(
216
+ TextField2,
217
+ {
218
+ size: "tiny",
219
+ multiline: true,
220
+ fullWidth: true,
221
+ rows: 5,
222
+ value,
223
+ onChange: handleChange,
224
+ placeholder
225
+ }
226
+ ));
227
+ });
228
+
229
+ // src/controls/size-control.tsx
230
+ import * as React13 from "react";
231
+ import { InputAdornment as InputAdornment2 } from "@elementor/ui";
232
+
233
+ // src/components/text-field-inner-selection.tsx
234
+ import * as React12 from "react";
235
+ import { forwardRef, useId } from "react";
236
+ import { bindMenu, bindTrigger, Button as Button2, InputAdornment, Menu, MenuItem as MenuItem2, TextField as TextField3, usePopupState } from "@elementor/ui";
237
+ var TextFieldInnerSelection = forwardRef(
238
+ ({ placeholder, type, value, onChange, endAdornment, startAdornment }, ref) => {
239
+ return /* @__PURE__ */ React12.createElement(
240
+ TextField3,
241
+ {
242
+ size: "tiny",
243
+ fullWidth: true,
244
+ type,
245
+ value,
246
+ onChange,
247
+ placeholder,
248
+ InputProps: {
249
+ endAdornment,
250
+ startAdornment
251
+ },
252
+ ref
253
+ }
254
+ );
255
+ }
256
+ );
257
+ var SelectionEndAdornment = ({
258
+ options,
259
+ onClick,
260
+ value
261
+ }) => {
262
+ const popupState = usePopupState({
263
+ variant: "popover",
264
+ popupId: useId()
265
+ });
266
+ const handleMenuItemClick = (index) => {
267
+ onClick(options[index]);
268
+ popupState.close();
269
+ };
270
+ return /* @__PURE__ */ React12.createElement(InputAdornment, { position: "end" }, /* @__PURE__ */ React12.createElement(
271
+ Button2,
272
+ {
273
+ size: "small",
274
+ color: "inherit",
275
+ sx: { font: "inherit", minWidth: "initial" },
276
+ ...bindTrigger(popupState)
277
+ },
278
+ value.toUpperCase()
279
+ ), /* @__PURE__ */ React12.createElement(Menu, { MenuListProps: { dense: true }, ...bindMenu(popupState) }, options.map((option, index) => /* @__PURE__ */ React12.createElement(MenuItem2, { key: option, onClick: () => handleMenuItemClick(index) }, option.toUpperCase()))));
280
+ };
281
+
282
+ // src/hooks/use-sync-external-state.tsx
283
+ import { useEffect, useState } from "react";
284
+ var useSyncExternalState = ({
285
+ external,
286
+ setExternal,
287
+ persistWhen,
288
+ fallback
289
+ }) => {
290
+ function toExternal(internalValue) {
291
+ if (persistWhen(internalValue)) {
292
+ return internalValue;
293
+ }
294
+ return void 0;
295
+ }
296
+ function toInternal(externalValue, internalValue) {
297
+ if (!externalValue) {
298
+ return fallback(internalValue);
299
+ }
300
+ return externalValue;
301
+ }
302
+ const [internal, setInternal] = useState(toInternal(external, void 0));
303
+ useEffect(() => {
304
+ setInternal((prevInternal) => toInternal(external, prevInternal));
305
+ }, [external]);
306
+ const setInternalValue = (setter) => {
307
+ const setterFn = typeof setter === "function" ? setter : () => setter;
308
+ const updated = setterFn(internal);
309
+ setInternal(updated);
310
+ setExternal(toExternal(updated));
311
+ };
312
+ return [internal, setInternalValue];
313
+ };
314
+
315
+ // src/controls/size-control.tsx
316
+ var defaultUnits = ["px", "%", "em", "rem", "vw", "vh"];
317
+ var defaultUnit = "px";
318
+ var defaultSize = NaN;
319
+ var SizeControl = createControl(({ units: units2 = defaultUnits, placeholder, startIcon }) => {
320
+ const { value, setValue } = useBoundProp();
321
+ const [state, setState] = useSyncExternalState({
322
+ external: value,
323
+ 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
+ })
329
+ });
330
+ const handleUnitChange = (unit) => {
331
+ setState((prev) => ({
332
+ ...prev,
333
+ value: {
334
+ ...prev.value,
335
+ unit
336
+ }
337
+ }));
338
+ };
339
+ const handleSizeChange = (event) => {
340
+ const { value: size } = event.target;
341
+ setState((prev) => ({
342
+ ...prev,
343
+ value: {
344
+ ...prev.value,
345
+ size: size || size === "0" ? parseFloat(size) : defaultSize
346
+ }
347
+ }));
348
+ };
349
+ return /* @__PURE__ */ React13.createElement(ControlActions, null, /* @__PURE__ */ React13.createElement(
350
+ TextFieldInnerSelection,
351
+ {
352
+ endAdornment: /* @__PURE__ */ React13.createElement(
353
+ SelectionEndAdornment,
354
+ {
355
+ options: units2,
356
+ onClick: handleUnitChange,
357
+ value: state.value.unit ?? defaultUnit
358
+ }
359
+ ),
360
+ placeholder,
361
+ startAdornment: startIcon ?? /* @__PURE__ */ React13.createElement(InputAdornment2, { position: "start" }, startIcon),
362
+ type: "number",
363
+ value: Number.isNaN(state.value.size) ? "" : state.value.size,
364
+ onChange: handleSizeChange
365
+ }
366
+ ));
367
+ });
368
+
369
+ // src/controls/stroke-control.tsx
370
+ import * as React15 from "react";
371
+ import { Grid as Grid2, Stack as Stack3 } from "@elementor/ui";
372
+ import { __ as __3 } from "@wordpress/i18n";
373
+
374
+ // src/controls/color-control.tsx
375
+ import * as React14 from "react";
376
+ import { UnstableColorField } from "@elementor/ui";
377
+ var ColorControl = createControl(
378
+ (props) => {
379
+ const { value, setValue } = useBoundProp();
380
+ const handleChange = (selectedColor) => {
381
+ setValue({
382
+ $$type: "color",
383
+ value: selectedColor
384
+ });
385
+ };
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
+ ));
396
+ }
397
+ );
398
+
399
+ // 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
+ var units = ["px", "em", "rem"];
417
+ var StrokeControl = createControl(() => {
418
+ const { value, setValue } = useBoundProp(defaultStrokeControlValue);
419
+ const setStrokeWidth = (newValue) => {
420
+ const updatedValue = {
421
+ ...value?.value ?? defaultStrokeControlValue.value,
422
+ width: newValue
423
+ };
424
+ setValue({
425
+ $$type: "stroke",
426
+ value: updatedValue
427
+ });
428
+ };
429
+ const setStrokeColor = (newValue) => {
430
+ const updatedValue = {
431
+ ...value?.value ?? defaultStrokeControlValue.value,
432
+ color: newValue
433
+ };
434
+ setValue({
435
+ $$type: "stroke",
436
+ value: updatedValue
437
+ });
438
+ };
439
+ return /* @__PURE__ */ React15.createElement(Stack3, { gap: 1.5 }, /* @__PURE__ */ React15.createElement(
440
+ Control,
441
+ {
442
+ bind: "width",
443
+ label: __3("Stroke Width", "elementor"),
444
+ value: value?.value.width ?? defaultStrokeControlValue.value.width,
445
+ setValue: setStrokeWidth
446
+ },
447
+ /* @__PURE__ */ React15.createElement(SizeControl, { units })
448
+ ), /* @__PURE__ */ React15.createElement(
449
+ Control,
450
+ {
451
+ bind: "color",
452
+ label: __3("Stroke Color", "elementor"),
453
+ value: value?.value.color ?? defaultStrokeControlValue.value.color,
454
+ setValue: setStrokeColor
455
+ },
456
+ /* @__PURE__ */ React15.createElement(ColorControl, null)
457
+ ));
458
+ });
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)));
466
+
467
+ // src/controls/box-shadow-repeater-control.tsx
468
+ import * as React17 from "react";
469
+ import { Grid as Grid3, Stack as Stack5, Typography as Typography3, UnstableColorIndicator } from "@elementor/ui";
470
+ import { __ as __5 } from "@wordpress/i18n";
471
+
472
+ // src/components/repeater.tsx
473
+ import * as React16 from "react";
474
+ import { useId as useId2, useRef, useState as useState2 } from "react";
475
+ import { CopyIcon, EyeIcon, EyeOffIcon, PlusIcon, XIcon } from "@elementor/icons";
476
+ import {
477
+ bindPopover,
478
+ bindTrigger as bindTrigger2,
479
+ Box,
480
+ IconButton,
481
+ Popover,
482
+ Stack as Stack4,
483
+ Typography as Typography2,
484
+ UnstableTag,
485
+ usePopupState as usePopupState2
486
+ } from "@elementor/ui";
487
+ import { __ as __4 } from "@wordpress/i18n";
488
+ var SIZE = "tiny";
489
+ var Repeater = ({
490
+ label,
491
+ itemSettings,
492
+ values: repeaterValues = [],
493
+ setValues: setRepeaterValues
494
+ }) => {
495
+ const addRepeaterItem = () => {
496
+ const newItem = structuredClone(itemSettings.initialValues);
497
+ setRepeaterValues([...repeaterValues, newItem]);
498
+ };
499
+ const duplicateRepeaterItem = (index) => {
500
+ setRepeaterValues([
501
+ ...repeaterValues.slice(0, index),
502
+ structuredClone(repeaterValues[index]),
503
+ ...repeaterValues.slice(index)
504
+ ]);
505
+ };
506
+ const removeRepeaterItem = (index) => {
507
+ setRepeaterValues(repeaterValues.filter((_, i) => i !== index));
508
+ };
509
+ const toggleDisableRepeaterItem = (index) => {
510
+ setRepeaterValues(
511
+ repeaterValues.map((value, i) => {
512
+ if (i === index) {
513
+ const { disabled, ...rest } = value;
514
+ return { ...rest, ...disabled ? {} : { disabled: true } };
515
+ }
516
+ return value;
517
+ })
518
+ );
519
+ };
520
+ return /* @__PURE__ */ React16.createElement(Stack4, null, /* @__PURE__ */ React16.createElement(Stack4, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { pb: 1 } }, /* @__PURE__ */ React16.createElement(Typography2, { component: "label", variant: "caption", color: "text.secondary" }, label), /* @__PURE__ */ React16.createElement(IconButton, { size: SIZE, onClick: addRepeaterItem, "aria-label": __4("Add item", "elementor") }, /* @__PURE__ */ React16.createElement(PlusIcon, { fontSize: SIZE }))), /* @__PURE__ */ React16.createElement(Stack4, { gap: 1 }, repeaterValues.map((value, index) => /* @__PURE__ */ React16.createElement(
521
+ RepeaterItem,
522
+ {
523
+ key: index,
524
+ disabled: value.disabled,
525
+ label: /* @__PURE__ */ React16.createElement(itemSettings.Label, { value }),
526
+ startIcon: /* @__PURE__ */ React16.createElement(itemSettings.Icon, { value }),
527
+ removeItem: () => removeRepeaterItem(index),
528
+ duplicateItem: () => duplicateRepeaterItem(index),
529
+ toggleDisableItem: () => toggleDisableRepeaterItem(index)
530
+ },
531
+ (props) => /* @__PURE__ */ React16.createElement(
532
+ itemSettings.Content,
533
+ {
534
+ ...props,
535
+ value,
536
+ setValue: (newValue) => setRepeaterValues(
537
+ repeaterValues.map((item, i) => i === index ? newValue : item)
538
+ )
539
+ }
540
+ )
541
+ ))));
542
+ };
543
+ var RepeaterItem = ({
544
+ label,
545
+ disabled,
546
+ startIcon,
547
+ children,
548
+ removeItem,
549
+ duplicateItem,
550
+ toggleDisableItem
551
+ }) => {
552
+ const popupId = useId2();
553
+ const controlRef = useRef(null);
554
+ const [anchorEl, setAnchorEl] = useState2(null);
555
+ const popoverState = usePopupState2({ popupId, variant: "popover" });
556
+ const popoverProps = bindPopover(popoverState);
557
+ return /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(
558
+ UnstableTag,
559
+ {
560
+ label,
561
+ showActionsOnHover: true,
562
+ ref: controlRef,
563
+ variant: "outlined",
564
+ "aria-label": __4("Open item", "elementor"),
565
+ ...bindTrigger2(popoverState),
566
+ startIcon,
567
+ actions: /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(
568
+ IconButton,
569
+ {
570
+ size: SIZE,
571
+ onClick: duplicateItem,
572
+ "aria-label": __4("Duplicate item", "elementor")
573
+ },
574
+ /* @__PURE__ */ React16.createElement(CopyIcon, { fontSize: SIZE })
575
+ ), /* @__PURE__ */ React16.createElement(
576
+ IconButton,
577
+ {
578
+ size: SIZE,
579
+ onClick: toggleDisableItem,
580
+ "aria-label": disabled ? __4("Enable item", "elementor") : __4("Disable item", "elementor")
581
+ },
582
+ disabled ? /* @__PURE__ */ React16.createElement(EyeOffIcon, { fontSize: SIZE }) : /* @__PURE__ */ React16.createElement(EyeIcon, { fontSize: SIZE })
583
+ ), /* @__PURE__ */ React16.createElement(
584
+ IconButton,
585
+ {
586
+ size: SIZE,
587
+ onClick: removeItem,
588
+ "aria-label": __4("Remove item", "elementor")
589
+ },
590
+ /* @__PURE__ */ React16.createElement(XIcon, { fontSize: SIZE })
591
+ ))
592
+ }
593
+ ), /* @__PURE__ */ React16.createElement(
594
+ Popover,
595
+ {
596
+ disablePortal: true,
597
+ slotProps: {
598
+ paper: {
599
+ ref: setAnchorEl,
600
+ sx: { mt: 0.5, p: 1, pt: 1, width: controlRef.current?.getBoundingClientRect().width }
601
+ }
602
+ },
603
+ anchorOrigin: { vertical: "bottom", horizontal: "left" },
604
+ ...popoverProps
605
+ },
606
+ /* @__PURE__ */ React16.createElement(Box, { p: 0.5 }, children({ anchorEl }))
607
+ ));
608
+ };
609
+
610
+ // src/controls/box-shadow-repeater-control.tsx
611
+ var BoxShadowRepeaterControl = createControl(() => {
612
+ const { value, setValue } = useBoundProp();
613
+ const boxShadowValues = value?.value;
614
+ const setBoxShadow = (newValue) => {
615
+ setValue({
616
+ $$type: "box-shadow",
617
+ value: newValue
618
+ });
619
+ };
620
+ return /* @__PURE__ */ React17.createElement(
621
+ Repeater,
622
+ {
623
+ values: boxShadowValues,
624
+ setValues: setBoxShadow,
625
+ label: __5("Box shadow", "elementor"),
626
+ itemSettings: {
627
+ Icon: ItemIcon,
628
+ Label: ItemLabel,
629
+ Content: ItemContent,
630
+ initialValues: initialShadow
631
+ }
632
+ }
633
+ );
634
+ });
635
+ var ItemIcon = ({ value }) => /* @__PURE__ */ React17.createElement(UnstableColorIndicator, { size: "inherit", component: "span", value: value.value.color.value });
636
+ var ItemContent = ({
637
+ value,
638
+ setValue,
639
+ anchorEl
640
+ }) => {
641
+ const setShadow = (newValue) => {
642
+ setValue({
643
+ $$type: "shadow",
644
+ value: newValue
645
+ });
646
+ };
647
+ return /* @__PURE__ */ React17.createElement(Stack5, { gap: 1.5 }, /* @__PURE__ */ React17.createElement(Grid3, { container: true, gap: 2, flexWrap: "nowrap" }, /* @__PURE__ */ React17.createElement(
648
+ Control2,
649
+ {
650
+ bind: "color",
651
+ value: value.value.color,
652
+ label: __5("Color", "elementor"),
653
+ setValue: (v) => setShadow({ ...value.value, color: v })
654
+ },
655
+ /* @__PURE__ */ React17.createElement(
656
+ ColorControl,
657
+ {
658
+ slotProps: {
659
+ colorPicker: {
660
+ anchorEl,
661
+ anchorOrigin: {
662
+ vertical: "top",
663
+ horizontal: "right"
664
+ },
665
+ transformOrigin: {
666
+ vertical: "top",
667
+ horizontal: -10
668
+ }
669
+ }
670
+ }
671
+ }
672
+ )
673
+ ), /* @__PURE__ */ React17.createElement(
674
+ Control2,
675
+ {
676
+ bind: "position",
677
+ value: value.value.position,
678
+ label: __5("Position", "elementor"),
679
+ setValue: (v) => setShadow({ ...value.value, position: v || null })
680
+ },
681
+ /* @__PURE__ */ React17.createElement(
682
+ SelectControl,
683
+ {
684
+ options: [
685
+ { label: __5("Inset", "elementor"), value: "inset" },
686
+ { label: __5("Outset", "elementor"), value: "" }
687
+ ]
688
+ }
689
+ )
690
+ )), /* @__PURE__ */ React17.createElement(Grid3, { container: true, gap: 2, flexWrap: "nowrap" }, /* @__PURE__ */ React17.createElement(
691
+ Control2,
692
+ {
693
+ bind: "hOffset",
694
+ label: __5("Horizontal", "elementor"),
695
+ value: value.value.hOffset,
696
+ setValue: (v) => setShadow({ ...value.value, hOffset: v })
697
+ },
698
+ /* @__PURE__ */ React17.createElement(SizeControl, null)
699
+ ), /* @__PURE__ */ React17.createElement(
700
+ Control2,
701
+ {
702
+ bind: "vOffset",
703
+ label: __5("Vertical", "elementor"),
704
+ value: value.value.vOffset,
705
+ setValue: (v) => setShadow({ ...value.value, vOffset: v })
706
+ },
707
+ /* @__PURE__ */ React17.createElement(SizeControl, null)
708
+ )), /* @__PURE__ */ React17.createElement(Grid3, { container: true, gap: 2, flexWrap: "nowrap" }, /* @__PURE__ */ React17.createElement(
709
+ Control2,
710
+ {
711
+ bind: "blur",
712
+ value: value.value.blur,
713
+ label: __5("Blur", "elementor"),
714
+ setValue: (v) => setShadow({ ...value.value, blur: v })
715
+ },
716
+ /* @__PURE__ */ React17.createElement(SizeControl, null)
717
+ ), /* @__PURE__ */ React17.createElement(
718
+ Control2,
719
+ {
720
+ bind: "spread",
721
+ label: __5("Spread", "elementor"),
722
+ value: value.value.spread,
723
+ setValue: (v) => setShadow({ ...value.value, spread: v })
724
+ },
725
+ /* @__PURE__ */ React17.createElement(SizeControl, null)
726
+ )));
727
+ };
728
+ var Control2 = ({
729
+ value,
730
+ setValue,
731
+ label,
732
+ bind,
733
+ children
734
+ }) => /* @__PURE__ */ React17.createElement(BoundPropProvider, { value, setValue, bind }, /* @__PURE__ */ React17.createElement(Grid3, { item: true, xs: 6 }, /* @__PURE__ */ React17.createElement(Grid3, { container: true, gap: 1, alignItems: "center" }, /* @__PURE__ */ React17.createElement(Grid3, { item: true, xs: 12 }, /* @__PURE__ */ React17.createElement(Typography3, { component: "label", variant: "caption", color: "text.secondary" }, label)), /* @__PURE__ */ React17.createElement(Grid3, { item: true, xs: 12 }, children))));
735
+ var ItemLabel = ({ value }) => {
736
+ const { position, hOffset, vOffset, blur, spread } = value.value;
737
+ const { size: blurSize = "", unit: blurUnit = "" } = blur?.value || {};
738
+ const { size: spreadSize = "", unit: spreadUnit = "" } = spread?.value || {};
739
+ const { size: hOffsetSize = "unset", unit: hOffsetUnit = "" } = hOffset?.value || {};
740
+ const { size: vOffsetSize = "unset", unit: vOffsetUnit = "" } = vOffset?.value || {};
741
+ const sizes = [
742
+ hOffsetSize + hOffsetUnit,
743
+ vOffsetSize + vOffsetUnit,
744
+ blurSize + blurUnit,
745
+ spreadSize + spreadUnit
746
+ ].join(" ");
747
+ return /* @__PURE__ */ React17.createElement("span", { style: { textTransform: "capitalize" } }, position ?? "outset", ": ", sizes);
748
+ };
749
+ var initialShadow = {
750
+ $$type: "shadow",
751
+ value: {
752
+ hOffset: {
753
+ $$type: "size",
754
+ value: { unit: "px", size: 0 }
755
+ },
756
+ vOffset: {
757
+ $$type: "size",
758
+ value: { unit: "px", size: 0 }
759
+ },
760
+ blur: {
761
+ $$type: "size",
762
+ value: { unit: "px", size: 10 }
763
+ },
764
+ spread: {
765
+ $$type: "size",
766
+ value: { unit: "px", size: 0 }
767
+ },
768
+ color: {
769
+ $$type: "color",
770
+ value: "rgba(0, 0, 0, 1)"
771
+ },
772
+ position: null
773
+ }
774
+ };
775
+
776
+ // src/controls/background-overlay-repeater-control.tsx
777
+ import * as React18 from "react";
778
+ import { Grid as Grid4, Stack as Stack6, Typography as Typography4, UnstableColorIndicator as UnstableColorIndicator2 } from "@elementor/ui";
779
+ import { __ as __6 } from "@wordpress/i18n";
780
+ var BackgroundOverlayRepeaterControl = createControl(() => {
781
+ const { value, setValue } = useBoundProp();
782
+ const colorOverlayValues = value?.value;
783
+ const setColorOverlay = (newValue) => {
784
+ setValue({
785
+ $$type: "background-image",
786
+ value: newValue
787
+ });
788
+ };
789
+ return /* @__PURE__ */ React18.createElement(
790
+ Repeater,
791
+ {
792
+ values: colorOverlayValues,
793
+ setValues: setColorOverlay,
794
+ label: __6("Overlay", "elementor"),
795
+ itemSettings: {
796
+ Icon: ItemIcon2,
797
+ Label: ItemLabel2,
798
+ Content: ItemContent2,
799
+ initialValues: initialGradient
800
+ }
801
+ }
802
+ );
803
+ });
804
+ var ItemIcon2 = ({ value }) => /* @__PURE__ */ React18.createElement(UnstableColorIndicator2, { size: "inherit", component: "span", value: value.value.color.value });
805
+ var ItemContent2 = ({
806
+ value,
807
+ setValue
808
+ }) => {
809
+ const setColor = (newValue) => {
810
+ setValue({
811
+ $$type: "background-overlay",
812
+ value: newValue
813
+ });
814
+ };
815
+ return /* @__PURE__ */ React18.createElement(Stack6, { gap: 1.5 }, /* @__PURE__ */ React18.createElement(
816
+ Control3,
817
+ {
818
+ bind: "color",
819
+ value: value.value.color,
820
+ label: __6("Color", "elementor"),
821
+ setValue: (v) => setColor({ ...value.value, color: v })
822
+ },
823
+ /* @__PURE__ */ React18.createElement(ColorControl, null)
824
+ ));
825
+ };
826
+ var Control3 = ({
827
+ value,
828
+ setValue,
829
+ label,
830
+ bind,
831
+ children
832
+ }) => /* @__PURE__ */ React18.createElement(BoundPropProvider, { value, setValue, bind }, /* @__PURE__ */ React18.createElement(Grid4, { container: true, spacing: 1, alignItems: "center" }, /* @__PURE__ */ React18.createElement(Grid4, { item: true, xs: 12 }, /* @__PURE__ */ React18.createElement(Typography4, { component: "label", variant: "caption", color: "text.secondary" }, label)), /* @__PURE__ */ React18.createElement(Grid4, { item: true, xs: 12 }, children)));
833
+ var ItemLabel2 = ({ value }) => {
834
+ const color = value.value.color.value;
835
+ return /* @__PURE__ */ React18.createElement("span", null, color);
836
+ };
837
+ var initialGradient = {
838
+ $$type: "background-overlay",
839
+ value: {
840
+ color: {
841
+ $$type: "color",
842
+ value: "rgba(0, 0, 0, 0.2)"
843
+ }
844
+ }
845
+ };
846
+
847
+ // src/controls/toggle-control.tsx
848
+ import * as React20 from "react";
849
+
850
+ // src/components/control-toggle-button-group.tsx
851
+ import * as React19 from "react";
852
+ import {
853
+ styled as styled2,
854
+ ToggleButton,
855
+ ToggleButtonGroup,
856
+ Tooltip
857
+ } from "@elementor/ui";
858
+ var StyledToggleButtonGroup = styled2(ToggleButtonGroup)`
859
+ ${({ justify }) => `justify-content: ${justify};`}
860
+ `;
861
+ var ControlToggleButtonGroup = ({
862
+ justify = "end",
863
+ size = "tiny",
864
+ value,
865
+ onChange,
866
+ items,
867
+ exclusive = false,
868
+ fullWidth = false
869
+ }) => {
870
+ const handleChange = (_, newValue) => {
871
+ onChange(newValue);
872
+ };
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 })
884
+ )
885
+ ));
886
+ };
887
+
888
+ // src/controls/toggle-control.tsx
889
+ var ToggleControl = createControl(
890
+ ({ options, fullWidth = false, size = "tiny" }) => {
891
+ const { value, setValue } = useBoundProp();
892
+ const handleToggle = (option) => {
893
+ setValue(option);
894
+ };
895
+ return /* @__PURE__ */ React20.createElement(
896
+ ControlToggleButtonGroup,
897
+ {
898
+ items: options,
899
+ value: value || null,
900
+ onChange: handleToggle,
901
+ exclusive: true,
902
+ fullWidth,
903
+ size
904
+ }
905
+ );
906
+ }
907
+ );
908
+
909
+ // src/controls/number-control.tsx
910
+ import * as React21 from "react";
911
+ 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
+ });
931
+
932
+ // src/controls/equal-unequal-sizes-control.tsx
933
+ import * as React22 from "react";
934
+ import { useId as useId3, useRef as useRef2 } from "react";
935
+ import { bindPopover as bindPopover2, bindToggle, Grid as Grid5, Popover as Popover2, Stack as Stack7, ToggleButton as ToggleButton2, usePopupState as usePopupState3 } from "@elementor/ui";
936
+ import { __ as __7 } from "@wordpress/i18n";
937
+ function hasMixedSizes(values) {
938
+ const [firstValue, ...restValues] = values;
939
+ return restValues.some(
940
+ (value) => value?.value?.size !== firstValue?.value?.size || value?.value?.unit !== firstValue?.value?.unit
941
+ );
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 }) {
951
+ const popupId = useId3();
952
+ const controlRef = useRef2(null);
953
+ const { value: controlValue, setValue: setControlValue } = useBoundProp();
954
+ const setMultiSizeValue = (newValue) => {
955
+ setControlValue({ $$type: multiSizeType, value: newValue });
956
+ };
957
+ const mappedValues = getMultiSizeProps(controlValue, items);
958
+ const setNestedProp = (item, newValue) => {
959
+ const { bind } = item;
960
+ const newMappedValues = {
961
+ ...mappedValues,
962
+ [bind]: newValue
963
+ };
964
+ const sizes = Object.values(newMappedValues);
965
+ const isMixed = hasMixedSizes(sizes);
966
+ if (isMixed) {
967
+ setMultiSizeValue(newMappedValues);
968
+ return;
969
+ }
970
+ setControlValue(newValue);
971
+ };
972
+ const popupState = usePopupState3({
973
+ variant: "popover",
974
+ popupId
975
+ });
976
+ 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,
978
+ {
979
+ value: mappedValues,
980
+ setValue: setControlValue,
981
+ iconButton: /* @__PURE__ */ React22.createElement(
982
+ ToggleButton2,
983
+ {
984
+ size: "tiny",
985
+ value: "check",
986
+ sx: { marginLeft: "auto" },
987
+ ...bindToggle(popupState),
988
+ selected: popupState.isOpen
989
+ },
990
+ icon
991
+ )
992
+ }
993
+ ))), /* @__PURE__ */ React22.createElement(
994
+ Popover2,
995
+ {
996
+ disablePortal: true,
997
+ disableScrollLock: true,
998
+ anchorOrigin: {
999
+ vertical: "bottom",
1000
+ horizontal: "right"
1001
+ },
1002
+ transformOrigin: {
1003
+ vertical: "top",
1004
+ horizontal: "right"
1005
+ },
1006
+ ...bindPopover2(popupState),
1007
+ slotProps: {
1008
+ paper: { sx: { mt: 0.5, p: 2, pt: 1, width: controlRef.current?.getBoundingClientRect().width } }
1009
+ }
1010
+ },
1011
+ /* @__PURE__ */ React22.createElement(Stack7, { gap: 1.5 }, /* @__PURE__ */ React22.createElement(Grid5, { container: true, gap: 2, alignItems: "center", flexWrap: "nowrap" }, /* @__PURE__ */ React22.createElement(
1012
+ NestedValueControl,
1013
+ {
1014
+ item: items[0],
1015
+ value: mappedValues,
1016
+ setNestedProp
1017
+ }
1018
+ ), /* @__PURE__ */ React22.createElement(
1019
+ NestedValueControl,
1020
+ {
1021
+ item: items[1],
1022
+ value: mappedValues,
1023
+ setNestedProp
1024
+ }
1025
+ )), /* @__PURE__ */ React22.createElement(Grid5, { container: true, gap: 2, alignItems: "center", flexWrap: "nowrap" }, /* @__PURE__ */ React22.createElement(
1026
+ NestedValueControl,
1027
+ {
1028
+ item: items[3],
1029
+ value: mappedValues,
1030
+ setNestedProp
1031
+ }
1032
+ ), /* @__PURE__ */ React22.createElement(
1033
+ NestedValueControl,
1034
+ {
1035
+ item: items[2],
1036
+ value: mappedValues,
1037
+ setNestedProp
1038
+ }
1039
+ )))
1040
+ ));
1041
+ }
1042
+ var NestedValueControl = ({
1043
+ item,
1044
+ value,
1045
+ setNestedProp
1046
+ }) => {
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
+ );
1058
+ };
1059
+ var EqualValuesControl = ({
1060
+ value,
1061
+ setValue,
1062
+ iconButton
1063
+ }) => {
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
+ );
1075
+ };
1076
+
1077
+ // src/controls/linked-dimensions-control.tsx
1078
+ import * as React23 from "react";
1079
+ import { DetachIcon, LinkIcon, SideBottomIcon, SideLeftIcon, SideRightIcon, SideTopIcon } from "@elementor/icons";
1080
+ import { Grid as Grid6, Stack as Stack8, ToggleButton as ToggleButton3 } from "@elementor/ui";
1081
+ import { __ as __8 } from "@wordpress/i18n";
1082
+ var LinkedDimensionsControl = createControl(({ label }) => {
1083
+ const { value, setValue } = useBoundProp();
1084
+ const { top, right, bottom, left, isLinked = true } = value?.value || {};
1085
+ const setLinkedValue = (position, newValue) => {
1086
+ const updatedValue = {
1087
+ isLinked,
1088
+ top: isLinked ? newValue : top,
1089
+ right: isLinked ? newValue : right,
1090
+ bottom: isLinked ? newValue : bottom,
1091
+ left: isLinked ? newValue : left,
1092
+ [position]: newValue
1093
+ };
1094
+ setValue({
1095
+ $$type: "linked-dimensions",
1096
+ value: updatedValue
1097
+ });
1098
+ };
1099
+ const toggleLinked = () => {
1100
+ const updatedValue = {
1101
+ isLinked: !isLinked,
1102
+ top,
1103
+ right: !isLinked ? top : right,
1104
+ bottom: !isLinked ? top : bottom,
1105
+ left: !isLinked ? top : left
1106
+ };
1107
+ setValue({
1108
+ $$type: "linked-dimensions",
1109
+ value: updatedValue
1110
+ });
1111
+ };
1112
+ const LinkedIcon = isLinked ? LinkIcon : DetachIcon;
1113
+ 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(
1114
+ ToggleButton3,
1115
+ {
1116
+ "aria-label": __8("Link Inputs", "elementor"),
1117
+ size: "tiny",
1118
+ value: "check",
1119
+ selected: isLinked,
1120
+ sx: { marginLeft: "auto" },
1121
+ onChange: toggleLinked
1122
+ },
1123
+ /* @__PURE__ */ React23.createElement(LinkedIcon, { fontSize: "tiny" })
1124
+ )), /* @__PURE__ */ React23.createElement(Stack8, { direction: "row", gap: 2, flexWrap: "nowrap" }, /* @__PURE__ */ React23.createElement(Grid6, { container: true, gap: 1, alignItems: "center" }, /* @__PURE__ */ React23.createElement(Grid6, { item: true, xs: 12 }, /* @__PURE__ */ React23.createElement(ControlLabel, null, __8("Top", "elementor"))), /* @__PURE__ */ React23.createElement(Grid6, { item: true, xs: 12 }, /* @__PURE__ */ React23.createElement(
1125
+ Control4,
1126
+ {
1127
+ bind: "top",
1128
+ value: top,
1129
+ setValue: setLinkedValue,
1130
+ startIcon: /* @__PURE__ */ React23.createElement(SideTopIcon, { fontSize: "tiny" })
1131
+ }
1132
+ ))), /* @__PURE__ */ React23.createElement(Grid6, { container: true, gap: 1, alignItems: "center" }, /* @__PURE__ */ React23.createElement(Grid6, { item: true, xs: 12 }, /* @__PURE__ */ React23.createElement(ControlLabel, null, __8("Right", "elementor"))), /* @__PURE__ */ React23.createElement(Grid6, { item: true, xs: 12 }, /* @__PURE__ */ React23.createElement(
1133
+ Control4,
1134
+ {
1135
+ bind: "right",
1136
+ value: right,
1137
+ setValue: setLinkedValue,
1138
+ startIcon: /* @__PURE__ */ React23.createElement(SideRightIcon, { fontSize: "tiny" })
1139
+ }
1140
+ )))), /* @__PURE__ */ React23.createElement(Stack8, { direction: "row", gap: 2, flexWrap: "nowrap" }, /* @__PURE__ */ React23.createElement(Grid6, { container: true, gap: 1, alignItems: "center" }, /* @__PURE__ */ React23.createElement(Grid6, { item: true, xs: 12 }, /* @__PURE__ */ React23.createElement(ControlLabel, null, __8("Bottom", "elementor"))), /* @__PURE__ */ React23.createElement(Grid6, { item: true, xs: 12 }, /* @__PURE__ */ React23.createElement(
1141
+ Control4,
1142
+ {
1143
+ bind: "bottom",
1144
+ value: bottom,
1145
+ setValue: setLinkedValue,
1146
+ startIcon: /* @__PURE__ */ React23.createElement(SideBottomIcon, { fontSize: "tiny" })
1147
+ }
1148
+ ))), /* @__PURE__ */ React23.createElement(Grid6, { container: true, gap: 1, alignItems: "center" }, /* @__PURE__ */ React23.createElement(Grid6, { item: true, xs: 12 }, /* @__PURE__ */ React23.createElement(ControlLabel, null, __8("Left", "elementor"))), /* @__PURE__ */ React23.createElement(Grid6, { item: true, xs: 12 }, /* @__PURE__ */ React23.createElement(
1149
+ Control4,
1150
+ {
1151
+ bind: "left",
1152
+ value: left,
1153
+ setValue: setLinkedValue,
1154
+ startIcon: /* @__PURE__ */ React23.createElement(SideLeftIcon, { fontSize: "tiny" })
1155
+ }
1156
+ )))));
1157
+ });
1158
+ var Control4 = ({
1159
+ bind,
1160
+ startIcon,
1161
+ value,
1162
+ setValue
1163
+ }) => /* @__PURE__ */ React23.createElement(BoundPropProvider, { setValue: (newValue) => setValue(bind, newValue), value, bind }, /* @__PURE__ */ React23.createElement(SizeControl, { startIcon }));
1164
+
1165
+ // src/controls/font-family-control.tsx
1166
+ import { Fragment as Fragment4, useId as useId4, useState as useState3 } from "react";
1167
+ import * as React24 from "react";
1168
+ import { ChevronDownIcon, EditIcon, PhotoIcon, SearchIcon, XIcon as XIcon2 } from "@elementor/icons";
1169
+ import {
1170
+ bindPopover as bindPopover3,
1171
+ bindTrigger as bindTrigger3,
1172
+ Box as Box2,
1173
+ Divider,
1174
+ IconButton as IconButton2,
1175
+ InputAdornment as InputAdornment3,
1176
+ Link,
1177
+ ListSubheader,
1178
+ MenuItem as MenuItem3,
1179
+ MenuList,
1180
+ Popover as Popover3,
1181
+ Stack as Stack9,
1182
+ TextField as TextField5,
1183
+ Typography as Typography5,
1184
+ UnstableTag as UnstableTag2,
1185
+ usePopupState as usePopupState4
1186
+ } from "@elementor/ui";
1187
+ import { __ as __10 } from "@wordpress/i18n";
1188
+
1189
+ // src/hooks/use-filtered-font-families.ts
1190
+ import { __ as __9 } from "@wordpress/i18n";
1191
+ var supportedCategories = {
1192
+ system: __9("System", "elementor"),
1193
+ googlefonts: __9("Google Fonts", "elementor"),
1194
+ customfonts: __9("Custom Fonts", "elementor")
1195
+ };
1196
+ var useFilteredFontFamilies = (fontFamilies, searchValue) => {
1197
+ const filteredFontFamilies = Object.entries(fontFamilies).reduce(
1198
+ (acc, [font, category]) => {
1199
+ const isMatch = font.toLowerCase().includes(searchValue.trim().toLowerCase());
1200
+ if (!isMatch) {
1201
+ return acc;
1202
+ }
1203
+ const categoryLabel = supportedCategories[category];
1204
+ if (categoryLabel) {
1205
+ const existingCategory = acc.get(categoryLabel);
1206
+ if (existingCategory) {
1207
+ existingCategory.push(font);
1208
+ } else {
1209
+ acc.set(categoryLabel, [font]);
1210
+ }
1211
+ }
1212
+ return acc;
1213
+ },
1214
+ /* @__PURE__ */ new Map()
1215
+ );
1216
+ return [...filteredFontFamilies];
1217
+ };
1218
+
1219
+ // src/controls/font-family-control.tsx
1220
+ var SIZE2 = "tiny";
1221
+ var FontFamilyControl = createControl(({ fontFamilies }) => {
1222
+ const { value: fontFamily, setValue: setFontFamily } = useBoundProp();
1223
+ const [searchValue, setSearchValue] = useState3("");
1224
+ const popupId = useId4();
1225
+ const popoverState = usePopupState4({ variant: "popover", popupId });
1226
+ const filteredFontFamilies = useFilteredFontFamilies(fontFamilies, searchValue);
1227
+ if (!filteredFontFamilies) {
1228
+ return null;
1229
+ }
1230
+ const handleSearch = (event) => {
1231
+ setSearchValue(event.target.value);
1232
+ };
1233
+ const handleClose = () => {
1234
+ setSearchValue("");
1235
+ popoverState.close();
1236
+ };
1237
+ return /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(
1238
+ UnstableTag2,
1239
+ {
1240
+ variant: "outlined",
1241
+ label: fontFamily,
1242
+ endIcon: /* @__PURE__ */ React24.createElement(ChevronDownIcon, { fontSize: "tiny" }),
1243
+ ...bindTrigger3(popoverState),
1244
+ fullWidth: true
1245
+ }
1246
+ ), /* @__PURE__ */ React24.createElement(
1247
+ Popover3,
1248
+ {
1249
+ disablePortal: true,
1250
+ disableScrollLock: true,
1251
+ anchorOrigin: { vertical: "bottom", horizontal: "left" },
1252
+ ...bindPopover3(popoverState),
1253
+ onClose: handleClose
1254
+ },
1255
+ /* @__PURE__ */ React24.createElement(Stack9, null, /* @__PURE__ */ React24.createElement(Stack9, { direction: "row", alignItems: "center", pl: 1.5, pr: 0.5, py: 1.5 }, /* @__PURE__ */ React24.createElement(EditIcon, { fontSize: SIZE2, sx: { mr: 0.5 } }), /* @__PURE__ */ React24.createElement(Typography5, { variant: "subtitle2" }, __10("Font Family", "elementor")), /* @__PURE__ */ React24.createElement(IconButton2, { size: SIZE2, sx: { ml: "auto" }, onClick: handleClose }, /* @__PURE__ */ React24.createElement(XIcon2, { fontSize: SIZE2 }))), /* @__PURE__ */ React24.createElement(Box2, { px: 1.5, pb: 1 }, /* @__PURE__ */ React24.createElement(
1256
+ TextField5,
1257
+ {
1258
+ fullWidth: true,
1259
+ size: SIZE2,
1260
+ value: searchValue,
1261
+ placeholder: __10("Search", "elementor"),
1262
+ onChange: handleSearch,
1263
+ InputProps: {
1264
+ startAdornment: /* @__PURE__ */ React24.createElement(InputAdornment3, { position: "start" }, /* @__PURE__ */ React24.createElement(SearchIcon, { fontSize: SIZE2 }))
1265
+ }
1266
+ }
1267
+ )), /* @__PURE__ */ React24.createElement(Divider, null), /* @__PURE__ */ React24.createElement(Box2, { sx: { overflowY: "auto", height: 260, width: 220 } }, filteredFontFamilies.length > 0 ? /* @__PURE__ */ React24.createElement(MenuList, { role: "listbox", tabIndex: 0 }, filteredFontFamilies.map(([category, items], index) => /* @__PURE__ */ React24.createElement(Fragment4, { key: index }, /* @__PURE__ */ React24.createElement(ListSubheader, { sx: { typography: "caption", color: "text.tertiary" } }, category), items.map((item) => {
1268
+ const isSelected = item === fontFamily;
1269
+ return /* @__PURE__ */ React24.createElement(
1270
+ MenuItem3,
1271
+ {
1272
+ key: item,
1273
+ selected: isSelected,
1274
+ autoFocus: isSelected,
1275
+ onClick: () => {
1276
+ setFontFamily(item);
1277
+ handleClose();
1278
+ },
1279
+ sx: { typography: "caption" },
1280
+ style: { fontFamily: item }
1281
+ },
1282
+ item
1283
+ );
1284
+ })))) : /* @__PURE__ */ React24.createElement(Stack9, { alignItems: "center", p: 2.5, gap: 1.5 }, /* @__PURE__ */ React24.createElement(PhotoIcon, { fontSize: "large" }), /* @__PURE__ */ React24.createElement(Typography5, { align: "center", variant: "caption", color: "text.secondary" }, __10("Sorry, nothing matched", "elementor"), /* @__PURE__ */ React24.createElement("br", null), "\u201C", searchValue, "\u201D."), /* @__PURE__ */ React24.createElement(Typography5, { align: "center", variant: "caption", color: "text.secondary" }, /* @__PURE__ */ React24.createElement(
1285
+ Link,
1286
+ {
1287
+ color: "secondary",
1288
+ variant: "caption",
1289
+ component: "button",
1290
+ onClick: () => setSearchValue("")
1291
+ },
1292
+ __10("Clear the filters", "elementor")
1293
+ ), "\xA0", __10("and try again.", "elementor")))))
1294
+ ));
1295
+ });
1296
+ export {
1297
+ BackgroundOverlayRepeaterControl,
1298
+ BoundPropProvider,
1299
+ BoxShadowRepeaterControl,
1300
+ ColorControl,
1301
+ ControlActionsProvider,
1302
+ ControlLabel,
1303
+ ControlReplacementProvider,
1304
+ EqualUnequalSizesControl,
1305
+ FontFamilyControl,
1306
+ ImageControl,
1307
+ LinkedDimensionsControl,
1308
+ NumberControl,
1309
+ SelectControl,
1310
+ SizeControl,
1311
+ StrokeControl,
1312
+ TextAreaControl,
1313
+ TextControl,
1314
+ ToggleControl,
1315
+ createControlReplacement,
1316
+ useBoundProp,
1317
+ useControlActions,
1318
+ useSyncExternalState
1319
+ };
1320
+ //# sourceMappingURL=index.mjs.map