@kgalexander/mcreate 0.0.16 → 1.0.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
@@ -60,7 +60,7 @@ import {
60
60
  setupDragImage,
61
61
  useEditorStore,
62
62
  useSidebarContext
63
- } from "./chunk-L3OWFBEU.mjs";
63
+ } from "./chunk-G7F7GRJC.mjs";
64
64
 
65
65
  // src/core/editor/components/email-template-v2/header.tsx
66
66
  import { ArrowLeftIcon, CopyIcon, MegaphoneIcon, MoreHorizontalIcon, PencilIcon, SendIcon, TrashIcon } from "lucide-react";
@@ -81,11 +81,20 @@ function TemplateJsonView() {
81
81
  }
82
82
 
83
83
  // src/core/editor/components/template-size-indicator.tsx
84
+ import { useEffect } from "react";
84
85
  import { jsxs as jsxs2 } from "react/jsx-runtime";
86
+ var POLLING_INTERVAL_MS = 3e4;
85
87
  function TemplateSizeIndicator() {
86
88
  const templateSize = useEditorStore((state) => state.templateSize);
87
89
  const isAtSizeLimit = useEditorStore((state) => state.isAtSizeLimit);
88
- console.log("templateSize", templateSize, isAtSizeLimit);
90
+ const sizeTrackingMode = useEditorStore((state) => state.sizeTrackingMode);
91
+ const recheckTemplateSize = useEditorStore((state) => state.recheckTemplateSize);
92
+ useEffect(() => {
93
+ if (sizeTrackingMode !== "polling") return;
94
+ const id = setInterval(recheckTemplateSize, POLLING_INTERVAL_MS);
95
+ return () => clearInterval(id);
96
+ }, [sizeTrackingMode, recheckTemplateSize]);
97
+ if (sizeTrackingMode === "polling") return null;
89
98
  const sizeKB = (templateSize / 1024).toFixed(0);
90
99
  const maxKB = (MAX_TEMPLATE_SIZE / 1024).toFixed(0);
91
100
  const percentage = templateSize / MAX_TEMPLATE_SIZE * 100;
@@ -203,6 +212,8 @@ function TemplateHeader() {
203
212
  const isSaving = useEditorStore((s) => s.isSaving);
204
213
  const setIsSaving = useEditorStore((s) => s.setIsSaving);
205
214
  const onExit = useEditorStore((s) => s.onExit);
215
+ const onDuplicate = useEditorStore((s) => s.onDuplicate);
216
+ const onDelete = useEditorStore((s) => s.onDelete);
206
217
  const templateName = useEditorStore((s) => s.template?.name);
207
218
  const handleExit = async () => {
208
219
  console.log("handleExit - templateId:", templateId);
@@ -252,12 +263,12 @@ function TemplateHeader() {
252
263
  /* @__PURE__ */ jsx4(MegaphoneIcon, { className: "w-4 h-4" }),
253
264
  "Start new campaign"
254
265
  ] }),
255
- /* @__PURE__ */ jsxs5(DropdownMenuItem, { className: "cursor-pointer", children: [
266
+ /* @__PURE__ */ jsxs5(DropdownMenuItem, { className: "cursor-pointer", onClick: () => templateId && onDuplicate?.(templateId, useEditorStore.getState().template), children: [
256
267
  /* @__PURE__ */ jsx4(CopyIcon, { className: "w-4 h-4" }),
257
268
  "Duplicate"
258
269
  ] }),
259
270
  /* @__PURE__ */ jsx4(DropdownMenuSeparator, {}),
260
- /* @__PURE__ */ jsxs5(DropdownMenuItem, { variant: "destructive", className: "cursor-pointer", children: [
271
+ /* @__PURE__ */ jsxs5(DropdownMenuItem, { variant: "destructive", className: "cursor-pointer", onClick: () => templateId && onDelete?.(templateId), children: [
261
272
  /* @__PURE__ */ jsx4(TrashIcon, { className: "w-4 h-4" }),
262
273
  "Delete"
263
274
  ] })
@@ -272,7 +283,7 @@ function TemplateHeader() {
272
283
  }
273
284
 
274
285
  // src/core/editor/components/email-template-v2/sidebar/sidebar.tsx
275
- import { useCallback as useCallback18, useEffect as useEffect4, useRef as useRef6, useMemo as useMemo7, useState as useState10 } from "react";
286
+ import { useCallback as useCallback18, useEffect as useEffect5, useRef as useRef6, useMemo as useMemo7, useState as useState10 } from "react";
276
287
  import { BlocksIcon, Paintbrush, PanelLeftClose, PanelLeftOpen, FileIcon } from "lucide-react";
277
288
 
278
289
  // src/core/editor/components/email-template-v2/sidebar/view/elements/main.tsx
@@ -283,7 +294,7 @@ import { useCallback as useCallback3 } from "react";
283
294
  import { ArrowLeftIcon as ArrowLeftIcon2 } from "lucide-react";
284
295
 
285
296
  // src/core/editor/hooks/use-recently-used.ts
286
- import { useState as useState2, useCallback, useEffect } from "react";
297
+ import { useState as useState2, useCallback, useEffect as useEffect2 } from "react";
287
298
 
288
299
  // src/pre-elements/columns.json
289
300
  var columns_default = [
@@ -1208,7 +1219,7 @@ function resolveAll(refs) {
1208
1219
  }
1209
1220
  function useRecentlyUsed() {
1210
1221
  const [refs, setRefs] = useState2(() => readRefs());
1211
- useEffect(() => {
1222
+ useEffect2(() => {
1212
1223
  const handler = (e) => {
1213
1224
  if (e.key === STORAGE_KEY) {
1214
1225
  setRefs(readRefs());
@@ -1230,7 +1241,7 @@ function useRecentlyUsed() {
1230
1241
  }
1231
1242
 
1232
1243
  // src/core/editor/components/email-template-v2/sidebar/view/elements/_components/preview-section.tsx
1233
- import { useRef, useState as useState3, useCallback as useCallback2, useEffect as useEffect2 } from "react";
1244
+ import { useRef, useState as useState3, useCallback as useCallback2, useEffect as useEffect3 } from "react";
1234
1245
  import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
1235
1246
  import { jsx as jsx5, jsxs as jsxs6 } from "react/jsx-runtime";
1236
1247
  function PreviewSection({
@@ -1251,7 +1262,7 @@ function PreviewSection({
1251
1262
  setCanGoLeft(el.scrollLeft > 0);
1252
1263
  setCanGoRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
1253
1264
  }, []);
1254
- useEffect2(() => {
1265
+ useEffect3(() => {
1255
1266
  updateScrollState();
1256
1267
  const el = scrollRef.current;
1257
1268
  if (!el) return;
@@ -2710,7 +2721,7 @@ import {
2710
2721
  memo,
2711
2722
  useCallback as useCallback15,
2712
2723
  useContext,
2713
- useEffect as useEffect3,
2724
+ useEffect as useEffect4,
2714
2725
  useMemo as useMemo4,
2715
2726
  useRef as useRef3,
2716
2727
  useState as useState6
@@ -2742,22 +2753,55 @@ var ColorPicker = ({
2742
2753
  );
2743
2754
  const [alpha, setAlpha] = useState6(selectedColor.alpha() * 100 || defaultColor.alpha() * 100);
2744
2755
  const [mode, setMode] = useState6("hex");
2745
- useEffect3(() => {
2756
+ const hueRef = useRef3(hue);
2757
+ const saturationRef = useRef3(saturation);
2758
+ const lightnessRef = useRef3(lightness);
2759
+ const alphaRef = useRef3(alpha);
2760
+ hueRef.current = hue;
2761
+ saturationRef.current = saturation;
2762
+ lightnessRef.current = lightness;
2763
+ alphaRef.current = alpha;
2764
+ useEffect4(() => {
2746
2765
  if (value) {
2747
- const color = Color.rgb(value).rgb().object();
2748
- setHue(color.r);
2749
- setSaturation(color.g);
2750
- setLightness(color.b);
2751
- setAlpha(color.a);
2766
+ const color = Color(value);
2767
+ const hsl = color.hsl().object();
2768
+ setHue(hsl.h);
2769
+ setSaturation(hsl.s);
2770
+ setLightness(hsl.l);
2771
+ setAlpha(color.alpha() * 100);
2772
+ hueRef.current = hsl.h;
2773
+ saturationRef.current = hsl.s;
2774
+ lightnessRef.current = hsl.l;
2775
+ alphaRef.current = color.alpha() * 100;
2752
2776
  }
2753
2777
  }, [value]);
2754
- useEffect3(() => {
2778
+ const updateColor = useCallback15((updates) => {
2779
+ const newH = updates.h ?? hueRef.current;
2780
+ const newS = updates.s ?? saturationRef.current;
2781
+ const newL = updates.l ?? lightnessRef.current;
2782
+ const newA = updates.a ?? alphaRef.current;
2783
+ if (updates.h !== void 0) {
2784
+ setHue(updates.h);
2785
+ hueRef.current = updates.h;
2786
+ }
2787
+ if (updates.s !== void 0) {
2788
+ setSaturation(updates.s);
2789
+ saturationRef.current = updates.s;
2790
+ }
2791
+ if (updates.l !== void 0) {
2792
+ setLightness(updates.l);
2793
+ lightnessRef.current = updates.l;
2794
+ }
2795
+ if (updates.a !== void 0) {
2796
+ setAlpha(updates.a);
2797
+ alphaRef.current = updates.a;
2798
+ }
2755
2799
  if (onChange) {
2756
- const color = Color.hsl(hue, saturation, lightness).alpha(alpha / 100);
2800
+ const color = Color.hsl(newH, newS, newL).alpha(newA / 100);
2757
2801
  const rgba = color.rgb().array();
2758
- onChange([rgba[0], rgba[1], rgba[2], alpha / 100]);
2802
+ onChange([rgba[0], rgba[1], rgba[2], newA / 100]);
2759
2803
  }
2760
- }, [hue, saturation, lightness, alpha, onChange]);
2804
+ }, [onChange]);
2761
2805
  return /* @__PURE__ */ jsx25(
2762
2806
  ColorPickerContext.Provider,
2763
2807
  {
@@ -2767,10 +2811,7 @@ var ColorPicker = ({
2767
2811
  lightness,
2768
2812
  alpha,
2769
2813
  mode,
2770
- setHue,
2771
- setSaturation,
2772
- setLightness,
2773
- setAlpha,
2814
+ updateColor,
2774
2815
  setMode
2775
2816
  },
2776
2817
  children: /* @__PURE__ */ jsx25("div", { className: cn("flex size-full flex-col gap-4", className), ...props })
@@ -2782,7 +2823,7 @@ var ColorPickerSelection = memo(({ className, ...props }) => {
2782
2823
  const [isDragging, setIsDragging] = useState6(false);
2783
2824
  const [positionX, setPositionX] = useState6(0);
2784
2825
  const [positionY, setPositionY] = useState6(0);
2785
- const { hue, setSaturation, setLightness } = useColorPicker();
2826
+ const { hue, updateColor } = useColorPicker();
2786
2827
  const backgroundGradient = useMemo4(() => {
2787
2828
  return `linear-gradient(0deg, rgba(0,0,0,1), rgba(0,0,0,0)),
2788
2829
  linear-gradient(90deg, rgba(255,255,255,1), rgba(255,255,255,0)),
@@ -2798,14 +2839,14 @@ var ColorPickerSelection = memo(({ className, ...props }) => {
2798
2839
  const y = Math.max(0, Math.min(1, (event.clientY - rect.top) / rect.height));
2799
2840
  setPositionX(x);
2800
2841
  setPositionY(y);
2801
- setSaturation(x * 100);
2842
+ const newSaturation = x * 100;
2802
2843
  const topLightness = x < 0.01 ? 100 : 50 + 50 * (1 - x);
2803
- const lightness = topLightness * (1 - y);
2804
- setLightness(lightness);
2844
+ const newLightness = topLightness * (1 - y);
2845
+ updateColor({ s: newSaturation, l: newLightness });
2805
2846
  },
2806
- [isDragging, setSaturation, setLightness]
2847
+ [isDragging, updateColor]
2807
2848
  );
2808
- useEffect3(() => {
2849
+ useEffect4(() => {
2809
2850
  const handlePointerUp = () => setIsDragging(false);
2810
2851
  if (isDragging) {
2811
2852
  window.addEventListener("pointermove", handlePointerMove);
@@ -2846,13 +2887,13 @@ var ColorPickerSelection = memo(({ className, ...props }) => {
2846
2887
  });
2847
2888
  ColorPickerSelection.displayName = "ColorPickerSelection";
2848
2889
  var ColorPickerHue = ({ className, ...props }) => {
2849
- const { hue, setHue } = useColorPicker();
2890
+ const { hue, updateColor } = useColorPicker();
2850
2891
  return /* @__PURE__ */ jsxs23(
2851
2892
  Slider.Root,
2852
2893
  {
2853
2894
  className: cn("relative flex h-4 w-full touch-none", className),
2854
2895
  max: 360,
2855
- onValueChange: ([hue2]) => setHue(hue2),
2896
+ onValueChange: ([h]) => updateColor({ h }),
2856
2897
  step: 1,
2857
2898
  value: [hue],
2858
2899
  ...props,
@@ -2864,17 +2905,14 @@ var ColorPickerHue = ({ className, ...props }) => {
2864
2905
  );
2865
2906
  };
2866
2907
  var ColorPickerEyeDropper = ({ className, ...props }) => {
2867
- const { setHue, setSaturation, setLightness, setAlpha } = useColorPicker();
2908
+ const { updateColor } = useColorPicker();
2868
2909
  const handleEyeDropper = async () => {
2869
2910
  try {
2870
2911
  const eyeDropper = new EyeDropper();
2871
2912
  const result = await eyeDropper.open();
2872
2913
  const color = Color(result.sRGBHex);
2873
2914
  const [h, s, l] = color.hsl().array();
2874
- setHue(h);
2875
- setSaturation(s);
2876
- setLightness(l);
2877
- setAlpha(100);
2915
+ updateColor({ h, s, l, a: 100 });
2878
2916
  } catch (error) {
2879
2917
  console.error("EyeDropper failed:", error);
2880
2918
  }
@@ -3670,7 +3708,7 @@ function TemplateSidebar({ editorLoading }) {
3670
3708
  const previousFocusIdxRef = useRef6(null);
3671
3709
  const [openSidebar, setOpenSidebar] = useState10(true);
3672
3710
  const [updateCounter, forceUpdate] = useState10(0);
3673
- useEffect4(() => {
3711
+ useEffect5(() => {
3674
3712
  if (!tiptapEditor) return;
3675
3713
  const handler = () => forceUpdate((n) => n + 1);
3676
3714
  tiptapEditor.on("selectionUpdate", handler);
@@ -3733,7 +3771,7 @@ function TemplateSidebar({ editorLoading }) {
3733
3771
  return null;
3734
3772
  }
3735
3773
  }, [colorTarget, focusIdx, focusedElementAttrs, parentElementAttrs, focusedElementType, pageBgColor, linkColor, tiptapEditor, updateCounter]);
3736
- useEffect4(() => {
3774
+ useEffect5(() => {
3737
3775
  if (!focusIdx || !focusedElementType) {
3738
3776
  previousElementTypeRef.current = void 0;
3739
3777
  return;
@@ -4037,11 +4075,13 @@ function TemplateSidebar({ editorLoading }) {
4037
4075
  attributes: { ...element.attributes, [attributeName]: imageSrc }
4038
4076
  });
4039
4077
  }, [imageTarget]);
4040
- useEffect4(() => {
4078
+ const prevActiveViewRef = useRef6(activeView);
4079
+ if (activeView !== prevActiveViewRef.current) {
4080
+ prevActiveViewRef.current = activeView;
4041
4081
  if (PICKER_VIEWS.has(activeView)) {
4042
4082
  setOpenSidebar(true);
4043
4083
  }
4044
- }, [activeView]);
4084
+ }
4045
4085
  const handleCloseSidebar = () => setOpenSidebar(!openSidebar);
4046
4086
  const handleViewClick = (view) => {
4047
4087
  setActiveView(view);
@@ -4309,7 +4349,7 @@ var PlainToolbar = () => {
4309
4349
  };
4310
4350
 
4311
4351
  // src/core/editor/components/element-gear/text/toolbar.tsx
4312
- import { useEffect as useEffect10, useState as useState16, useCallback as useCallback26, useMemo as useMemo14 } from "react";
4352
+ import { useEffect as useEffect7, useState as useState17, useCallback as useCallback27, useMemo as useMemo14 } from "react";
4313
4353
  import { BoldIcon, BracesIcon, CaseUpperIcon, CheckIcon as CheckIcon5, EllipsisIcon, HighlighterIcon, ItalicIcon, Strikethrough, Underline } from "lucide-react";
4314
4354
 
4315
4355
  // src/core/editor/components/paragraph-text-settings.tsx
@@ -4377,13 +4417,79 @@ function Slider2({
4377
4417
  }
4378
4418
 
4379
4419
  // src/core/editor/components/paragraph-text-settings.tsx
4380
- import { useState as useState11, useEffect as useEffect5, useMemo as useMemo11, useCallback as useCallback21, memo as memo2 } from "react";
4420
+ import { useState as useState12, useEffect as useEffect6, useMemo as useMemo11, useCallback as useCallback22, memo as memo2 } from "react";
4421
+
4422
+ // src/core/editor/hooks/use-editable-value.ts
4423
+ import { useState as useState11, useCallback as useCallback21 } from "react";
4424
+ function useEditableValue(options) {
4425
+ const { externalValue, onChange, toLocal, toExternal } = options;
4426
+ const convert = toLocal ?? String;
4427
+ const [localValue, setLocalValue] = useState11(convert(externalValue));
4428
+ const [isFocused, setIsFocused] = useState11(false);
4429
+ const displayValue = isFocused ? localValue : convert(externalValue);
4430
+ const handleFocus = useCallback21(() => {
4431
+ setLocalValue(convert(externalValue));
4432
+ setIsFocused(true);
4433
+ }, [externalValue, convert]);
4434
+ const handleBlur = useCallback21(() => {
4435
+ setIsFocused(false);
4436
+ if (toExternal) {
4437
+ const parsed = toExternal(localValue);
4438
+ if (parsed !== null) {
4439
+ onChange(parsed);
4440
+ }
4441
+ } else {
4442
+ onChange(localValue);
4443
+ }
4444
+ }, [localValue, toExternal, onChange]);
4445
+ const handleKeyDown = useCallback21((e) => {
4446
+ if (e.key === "Enter") {
4447
+ e.currentTarget.blur();
4448
+ }
4449
+ }, []);
4450
+ return {
4451
+ displayValue,
4452
+ setLocalValue,
4453
+ handleFocus,
4454
+ handleBlur,
4455
+ handleKeyDown,
4456
+ isFocused
4457
+ };
4458
+ }
4459
+ function useEditableNumber(options) {
4460
+ const { value, onChange, min = -Infinity, max = Infinity } = options;
4461
+ return useEditableValue({
4462
+ externalValue: value,
4463
+ onChange,
4464
+ toLocal: (n) => n.toString(),
4465
+ toExternal: (s) => {
4466
+ const parsed = parseInt(s, 10);
4467
+ if (isNaN(parsed)) return null;
4468
+ return Math.max(min, Math.min(max, parsed));
4469
+ }
4470
+ });
4471
+ }
4472
+ function useEditableFloat(options) {
4473
+ const { value, onChange, min = -Infinity, max = Infinity } = options;
4474
+ return useEditableValue({
4475
+ externalValue: value,
4476
+ onChange,
4477
+ toLocal: (n) => n.toString(),
4478
+ toExternal: (s) => {
4479
+ const parsed = parseFloat(s);
4480
+ if (isNaN(parsed) || s === "") return null;
4481
+ return Math.max(min, Math.min(max, parsed));
4482
+ }
4483
+ });
4484
+ }
4485
+
4486
+ // src/core/editor/components/paragraph-text-settings.tsx
4381
4487
  import { jsx as jsx39, jsxs as jsxs31 } from "react/jsx-runtime";
4382
4488
  var ParagraphTextSettings = memo2(function ParagraphTextSettings2() {
4383
- const [isOpen, setIsOpen] = useState11(false);
4489
+ const [isOpen, setIsOpen] = useState12(false);
4384
4490
  const tiptapEditor = useEditorStore((s) => s.tiptapEditor);
4385
- const [updateCounter, forceUpdate] = useState11(0);
4386
- useEffect5(() => {
4491
+ const [updateCounter, forceUpdate] = useState12(0);
4492
+ useEffect6(() => {
4387
4493
  if (!tiptapEditor) return;
4388
4494
  const handler = () => forceUpdate((n) => n + 1);
4389
4495
  tiptapEditor.on("selectionUpdate", handler);
@@ -4409,92 +4515,34 @@ var ParagraphTextSettings = memo2(function ParagraphTextSettings2() {
4409
4515
  }
4410
4516
  return DEFAULT_LINE_HEIGHT;
4411
4517
  }, [tiptapEditor, updateCounter]);
4412
- const [letterSpacingInputValue, setLetterSpacingInputValue] = useState11(
4413
- String(currentLetterSpacing)
4414
- );
4415
- const [isLetterSpacingInputFocused, setIsLetterSpacingInputFocused] = useState11(false);
4416
- const [lineHeightInputValue, setLineHeightInputValue] = useState11(
4417
- String(currentLineHeight)
4418
- );
4419
- const [isLineHeightInputFocused, setIsLineHeightInputFocused] = useState11(false);
4420
- useEffect5(() => {
4421
- if (!isLetterSpacingInputFocused) {
4422
- setLetterSpacingInputValue(String(currentLetterSpacing));
4423
- }
4424
- }, [currentLetterSpacing, isLetterSpacingInputFocused]);
4425
- useEffect5(() => {
4426
- if (!isLineHeightInputFocused) {
4427
- setLineHeightInputValue(String(currentLineHeight));
4428
- }
4429
- }, [currentLineHeight, isLineHeightInputFocused]);
4430
- const handleLetterSpacingSliderChange = useCallback21((values) => {
4518
+ const commitLetterSpacing = useCallback22((value) => {
4431
4519
  if (!tiptapEditor) return;
4432
- const value = values[0];
4433
- setLetterSpacingInputValue(String(value));
4434
4520
  tiptapEditor.chain().setLetterSpacing(`${value}px`).run();
4435
4521
  forceUpdate((n) => n + 1);
4436
4522
  }, [tiptapEditor]);
4437
- const handleLetterSpacingInputChange = useCallback21((e) => {
4438
- setLetterSpacingInputValue(e.target.value);
4439
- }, []);
4440
- const applyLetterSpacing = useCallback21(() => {
4441
- if (!tiptapEditor) return;
4442
- const parsed = parseFloat(letterSpacingInputValue);
4443
- if (isNaN(parsed) || letterSpacingInputValue === "") {
4444
- setLetterSpacingInputValue(String(currentLetterSpacing));
4445
- tiptapEditor.chain().focus().run();
4446
- return;
4447
- }
4448
- const clampedValue = Math.max(MIN_LETTER_SPACING, Math.min(parsed, MAX_LETTER_SPACING));
4449
- setLetterSpacingInputValue(String(clampedValue));
4450
- tiptapEditor.chain().focus().setLetterSpacing(`${clampedValue}px`).run();
4451
- forceUpdate((n) => n + 1);
4452
- }, [tiptapEditor, letterSpacingInputValue, currentLetterSpacing]);
4453
- const handleLetterSpacingInputBlur = useCallback21(() => {
4454
- setIsLetterSpacingInputFocused(false);
4455
- applyLetterSpacing();
4456
- }, [applyLetterSpacing]);
4457
- const handleLetterSpacingInputKeyDown = useCallback21((e) => {
4458
- if (e.key === "Enter") {
4459
- e.preventDefault();
4460
- applyLetterSpacing();
4461
- e.target.blur();
4462
- }
4463
- }, [applyLetterSpacing]);
4464
- const handleLineHeightSliderChange = useCallback21((values) => {
4523
+ const commitLineHeight = useCallback22((value) => {
4465
4524
  if (!tiptapEditor) return;
4466
- const value = values[0];
4467
- setLineHeightInputValue(String(value));
4468
4525
  tiptapEditor.chain().setLineHeight(String(value)).run();
4469
4526
  forceUpdate((n) => n + 1);
4470
4527
  }, [tiptapEditor]);
4471
- const handleLineHeightInputChange = useCallback21((e) => {
4472
- setLineHeightInputValue(e.target.value);
4473
- }, []);
4474
- const applyLineHeight = useCallback21(() => {
4475
- if (!tiptapEditor) return;
4476
- const parsed = parseFloat(lineHeightInputValue);
4477
- if (isNaN(parsed) || lineHeightInputValue === "") {
4478
- setLineHeightInputValue(String(currentLineHeight));
4479
- tiptapEditor.chain().focus().run();
4480
- return;
4481
- }
4482
- const clampedValue = Math.max(MIN_LINE_HEIGHT, Math.min(parsed, MAX_LINE_HEIGHT));
4483
- setLineHeightInputValue(String(clampedValue));
4484
- tiptapEditor.chain().focus().setLineHeight(String(clampedValue)).run();
4485
- forceUpdate((n) => n + 1);
4486
- }, [tiptapEditor, lineHeightInputValue, currentLineHeight]);
4487
- const handleLineHeightInputBlur = useCallback21(() => {
4488
- setIsLineHeightInputFocused(false);
4489
- applyLineHeight();
4490
- }, [applyLineHeight]);
4491
- const handleLineHeightInputKeyDown = useCallback21((e) => {
4492
- if (e.key === "Enter") {
4493
- e.preventDefault();
4494
- applyLineHeight();
4495
- e.target.blur();
4496
- }
4497
- }, [applyLineHeight]);
4528
+ const letterSpacingInput = useEditableFloat({
4529
+ value: currentLetterSpacing,
4530
+ onChange: commitLetterSpacing,
4531
+ min: MIN_LETTER_SPACING,
4532
+ max: MAX_LETTER_SPACING
4533
+ });
4534
+ const lineHeightInput = useEditableFloat({
4535
+ value: currentLineHeight,
4536
+ onChange: commitLineHeight,
4537
+ min: MIN_LINE_HEIGHT,
4538
+ max: MAX_LINE_HEIGHT
4539
+ });
4540
+ const handleLetterSpacingSliderChange = useCallback22((values) => {
4541
+ commitLetterSpacing(values[0]);
4542
+ }, [commitLetterSpacing]);
4543
+ const handleLineHeightSliderChange = useCallback22((values) => {
4544
+ commitLineHeight(values[0]);
4545
+ }, [commitLineHeight]);
4498
4546
  return /* @__PURE__ */ jsxs31(Tooltip, { children: [
4499
4547
  /* @__PURE__ */ jsxs31(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
4500
4548
  /* @__PURE__ */ jsx39(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx39(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx39(
@@ -4531,11 +4579,11 @@ var ParagraphTextSettings = memo2(function ParagraphTextSettings2() {
4531
4579
  Input,
4532
4580
  {
4533
4581
  type: "number",
4534
- value: letterSpacingInputValue,
4535
- onChange: handleLetterSpacingInputChange,
4536
- onFocus: () => setIsLetterSpacingInputFocused(true),
4537
- onBlur: handleLetterSpacingInputBlur,
4538
- onKeyDown: handleLetterSpacingInputKeyDown,
4582
+ value: letterSpacingInput.displayValue,
4583
+ onChange: (e) => letterSpacingInput.setLocalValue(e.target.value),
4584
+ onFocus: letterSpacingInput.handleFocus,
4585
+ onBlur: letterSpacingInput.handleBlur,
4586
+ onKeyDown: letterSpacingInput.handleKeyDown,
4539
4587
  className: "w-25 shadow-none rounded-[12px]",
4540
4588
  min: MIN_LETTER_SPACING,
4541
4589
  max: MAX_LETTER_SPACING,
@@ -4562,11 +4610,11 @@ var ParagraphTextSettings = memo2(function ParagraphTextSettings2() {
4562
4610
  Input,
4563
4611
  {
4564
4612
  type: "number",
4565
- value: lineHeightInputValue,
4566
- onChange: handleLineHeightInputChange,
4567
- onFocus: () => setIsLineHeightInputFocused(true),
4568
- onBlur: handleLineHeightInputBlur,
4569
- onKeyDown: handleLineHeightInputKeyDown,
4613
+ value: lineHeightInput.displayValue,
4614
+ onChange: (e) => lineHeightInput.setLocalValue(e.target.value),
4615
+ onFocus: lineHeightInput.handleFocus,
4616
+ onBlur: lineHeightInput.handleBlur,
4617
+ onKeyDown: lineHeightInput.handleKeyDown,
4570
4618
  className: "w-25 shadow-none rounded-[12px]",
4571
4619
  min: MIN_LINE_HEIGHT,
4572
4620
  max: MAX_LINE_HEIGHT,
@@ -4630,7 +4678,7 @@ var FontFamilyDropdown = ({
4630
4678
  };
4631
4679
 
4632
4680
  // src/core/editor/components/font-size-control.tsx
4633
- import { useState as useState12, useEffect as useEffect6, useCallback as useCallback22, memo as memo3 } from "react";
4681
+ import { useState as useState13, useCallback as useCallback23, memo as memo3 } from "react";
4634
4682
 
4635
4683
  // src/components/ui/button-group.tsx
4636
4684
  import { Slot as Slot2 } from "@radix-ui/react-slot";
@@ -4772,59 +4820,37 @@ var FontSizeControl = memo3(function FontSizeControl2({
4772
4820
  max = MAX_FONT_SIZE,
4773
4821
  step = FONT_SIZE_STEP
4774
4822
  }) {
4775
- const [inputValue, setInputValue] = useState12(String(value));
4776
- const [isFocused, setIsFocused] = useState12(false);
4777
- const [isPopoverOpen, setIsPopoverOpen] = useState12(false);
4778
- useEffect6(() => {
4779
- if (!isFocused) {
4780
- setInputValue(String(value));
4781
- }
4782
- }, [value, isFocused]);
4783
- const applySize = useCallback22(() => {
4784
- const parsed = parseInt(inputValue, 10);
4785
- if (isNaN(parsed) || inputValue === "") {
4786
- setInputValue(String(value));
4787
- return;
4788
- }
4789
- const clampedSize = Math.max(min, Math.min(parsed, max));
4790
- setInputValue(String(clampedSize));
4791
- onChange(clampedSize);
4792
- }, [inputValue, value, min, max, onChange]);
4793
- const handleIncrease = useCallback22(() => {
4823
+ const [isPopoverOpen, setIsPopoverOpen] = useState13(false);
4824
+ const input = useEditableNumber({ value, onChange, min, max });
4825
+ const handleIncrease = useCallback23(() => {
4794
4826
  const newSize = Math.min(value + step, max);
4795
4827
  onChange(newSize);
4796
4828
  }, [value, step, max, onChange]);
4797
- const handleDecrease = useCallback22(() => {
4829
+ const handleDecrease = useCallback23(() => {
4798
4830
  const newSize = Math.max(value - step, min);
4799
4831
  onChange(newSize);
4800
4832
  }, [value, step, min, onChange]);
4801
- const handleInputChange = useCallback22((e) => {
4802
- setInputValue(e.target.value);
4803
- }, []);
4804
- const handleFocus = useCallback22(() => {
4805
- setIsFocused(true);
4833
+ const handleFocus = useCallback23(() => {
4834
+ input.handleFocus();
4806
4835
  setIsPopoverOpen(true);
4807
- }, []);
4808
- const handleBlur = useCallback22(() => {
4809
- setIsFocused(false);
4810
- applySize();
4836
+ }, [input.handleFocus]);
4837
+ const handleBlur = useCallback23(() => {
4838
+ input.handleBlur();
4811
4839
  setTimeout(() => setIsPopoverOpen(false), 150);
4812
- }, [applySize]);
4813
- const handleKeyDown = useCallback22((e) => {
4840
+ }, [input.handleBlur]);
4841
+ const handleKeyDown = useCallback23((e) => {
4814
4842
  if (e.key === "Enter") {
4815
4843
  e.preventDefault();
4816
- applySize();
4817
4844
  setIsPopoverOpen(false);
4818
- e.target.blur();
4845
+ e.currentTarget.blur();
4819
4846
  }
4820
4847
  if (e.key === "Escape") {
4821
4848
  setIsPopoverOpen(false);
4822
- e.target.blur();
4849
+ e.currentTarget.blur();
4823
4850
  }
4824
- }, [applySize]);
4825
- const handlePresetSelect = useCallback22((size) => {
4851
+ }, []);
4852
+ const handlePresetSelect = useCallback23((size) => {
4826
4853
  onChange(size);
4827
- setInputValue(String(size));
4828
4854
  setIsPopoverOpen(false);
4829
4855
  }, [onChange]);
4830
4856
  return /* @__PURE__ */ jsx43("div", { className: "grid w-full max-w-sm gap-6", children: /* @__PURE__ */ jsxs33(ButtonGroup, { children: [
@@ -4851,8 +4877,8 @@ var FontSizeControl = memo3(function FontSizeControl2({
4851
4877
  type: "number",
4852
4878
  className: "text-center w-12 border-0 shadow-none px-0",
4853
4879
  placeholder: "--",
4854
- value: inputValue,
4855
- onChange: handleInputChange,
4880
+ value: input.displayValue,
4881
+ onChange: (e) => input.setLocalValue(e.target.value),
4856
4882
  onFocus: handleFocus,
4857
4883
  onBlur: handleBlur,
4858
4884
  onKeyDown: handleKeyDown,
@@ -4907,44 +4933,22 @@ var FontSizeControl = memo3(function FontSizeControl2({
4907
4933
  });
4908
4934
 
4909
4935
  // src/core/editor/components/element-gear/column-styles.tsx
4910
- import { useCallback as useCallback25, useMemo as useMemo13 } from "react";
4936
+ import { useCallback as useCallback26, useMemo as useMemo13 } from "react";
4911
4937
 
4912
4938
  // src/core/editor/components/border-radius.tsx
4913
- import { useState as useState13, useEffect as useEffect7 } from "react";
4939
+ import { useState as useState14 } from "react";
4914
4940
  import { SquareRoundCorner } from "lucide-react";
4915
4941
  import { jsx as jsx44, jsxs as jsxs34 } from "react/jsx-runtime";
4916
4942
  var BorderRadius = ({
4917
4943
  value,
4918
4944
  onChange,
4919
4945
  tooltipText = "Border Radius",
4920
- max = 100
4946
+ max = 50
4921
4947
  }) => {
4922
- const [inputValue, setInputValue] = useState13(value.toString());
4923
- const [isOpen, setIsOpen] = useState13(false);
4924
- useEffect7(() => {
4925
- setInputValue(value.toString());
4926
- }, [value]);
4948
+ const [isOpen, setIsOpen] = useState14(false);
4949
+ const input = useEditableNumber({ value, onChange, min: 0, max });
4927
4950
  const handleSliderChange = (values) => {
4928
- const newValue = values[0];
4929
- onChange(newValue);
4930
- };
4931
- const handleInputChange = (e) => {
4932
- setInputValue(e.target.value);
4933
- };
4934
- const handleInputBlur = () => {
4935
- const parsed = parseInt(inputValue, 10);
4936
- if (isNaN(parsed)) {
4937
- setInputValue(value.toString());
4938
- } else {
4939
- const clamped = Math.max(0, Math.min(max, parsed));
4940
- onChange(clamped);
4941
- setInputValue(clamped.toString());
4942
- }
4943
- };
4944
- const handleInputKeyDown = (e) => {
4945
- if (e.key === "Enter") {
4946
- e.currentTarget.blur();
4947
- }
4951
+ onChange(values[0]);
4948
4952
  };
4949
4953
  return /* @__PURE__ */ jsxs34(Tooltip, { children: [
4950
4954
  /* @__PURE__ */ jsxs34(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
@@ -4974,10 +4978,11 @@ var BorderRadius = ({
4974
4978
  Input,
4975
4979
  {
4976
4980
  type: "number",
4977
- value: inputValue,
4978
- onChange: handleInputChange,
4979
- onBlur: handleInputBlur,
4980
- onKeyDown: handleInputKeyDown,
4981
+ value: input.displayValue,
4982
+ onChange: (e) => input.setLocalValue(e.target.value),
4983
+ onFocus: input.handleFocus,
4984
+ onBlur: input.handleBlur,
4985
+ onKeyDown: input.handleKeyDown,
4981
4986
  className: "w-25 shadow-none rounded-[12px]",
4982
4987
  min: 0,
4983
4988
  max
@@ -4992,7 +4997,7 @@ var BorderRadius = ({
4992
4997
 
4993
4998
  // src/core/editor/components/stroke-weight.tsx
4994
4999
  import { BanIcon, MinusIcon as MinusIcon2 } from "lucide-react";
4995
- import { useState as useState14, useEffect as useEffect8 } from "react";
5000
+ import { useState as useState15 } from "react";
4996
5001
  import { jsx as jsx45, jsxs as jsxs35 } from "react/jsx-runtime";
4997
5002
  var StrokeWeight = ({
4998
5003
  width,
@@ -5002,32 +5007,10 @@ var StrokeWeight = ({
5002
5007
  tooltipText = "Stroke Weight",
5003
5008
  max = 50
5004
5009
  }) => {
5005
- const [isOpen, setIsOpen] = useState14(false);
5006
- const [inputValue, setInputValue] = useState14(width.toString());
5007
- useEffect8(() => {
5008
- setInputValue(width.toString());
5009
- }, [width]);
5010
+ const [isOpen, setIsOpen] = useState15(false);
5011
+ const input = useEditableNumber({ value: width, onChange: onWidthChange, min: 1, max });
5010
5012
  const handleSliderChange = (values) => {
5011
- const newWidth = values[0];
5012
- onWidthChange(newWidth);
5013
- };
5014
- const handleInputChange = (e) => {
5015
- setInputValue(e.target.value);
5016
- };
5017
- const handleInputBlur = () => {
5018
- const parsed = parseInt(inputValue, 10);
5019
- if (isNaN(parsed)) {
5020
- setInputValue(width.toString());
5021
- } else {
5022
- const clamped = Math.max(1, Math.min(max, parsed));
5023
- onWidthChange(clamped);
5024
- setInputValue(clamped.toString());
5025
- }
5026
- };
5027
- const handleInputKeyDown = (e) => {
5028
- if (e.key === "Enter") {
5029
- e.currentTarget.blur();
5030
- }
5013
+ onWidthChange(values[0]);
5031
5014
  };
5032
5015
  return /* @__PURE__ */ jsxs35(Tooltip, { children: [
5033
5016
  /* @__PURE__ */ jsxs35(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
@@ -5078,10 +5061,11 @@ var StrokeWeight = ({
5078
5061
  Input,
5079
5062
  {
5080
5063
  type: "number",
5081
- value: inputValue,
5082
- onChange: handleInputChange,
5083
- onBlur: handleInputBlur,
5084
- onKeyDown: handleInputKeyDown,
5064
+ value: input.displayValue,
5065
+ onChange: (e) => input.setLocalValue(e.target.value),
5066
+ onFocus: input.handleFocus,
5067
+ onBlur: input.handleBlur,
5068
+ onKeyDown: input.handleKeyDown,
5085
5069
  className: "w-25 shadow-none rounded-[12px]",
5086
5070
  min: 1,
5087
5071
  max
@@ -5128,10 +5112,10 @@ function CollapsibleContent2({
5128
5112
 
5129
5113
  // src/core/editor/components/better-padding.tsx
5130
5114
  import { ChevronDownIcon as ChevronDownIcon3, PanelBottomDashedIcon, PanelLeftDashedIcon, PanelRightDashedIcon, PanelTopDashedIcon, SquareSquare } from "lucide-react";
5131
- import { useState as useState15, useEffect as useEffect9, useCallback as useCallback24 } from "react";
5115
+ import { useState as useState16, useCallback as useCallback25 } from "react";
5132
5116
 
5133
5117
  // src/core/editor/hooks/use-padding.ts
5134
- import { useMemo as useMemo12, useCallback as useCallback23 } from "react";
5118
+ import { useMemo as useMemo12, useCallback as useCallback24 } from "react";
5135
5119
  import { get as lodashGet3 } from "lodash";
5136
5120
 
5137
5121
  // src/core/editor/utils/padding.ts
@@ -5200,7 +5184,7 @@ var usePadding = (options = {}) => {
5200
5184
  const uniformValue = useMemo12(() => {
5201
5185
  return getUniformValue(parsedPadding);
5202
5186
  }, [parsedPadding]);
5203
- const updatePadding = useCallback23((updates) => {
5187
+ const updatePadding = useCallback24((updates) => {
5204
5188
  if (!effectiveIdx || !template || !element) return;
5205
5189
  const newPadding = {
5206
5190
  ...parsedPadding,
@@ -5213,19 +5197,19 @@ var usePadding = (options = {}) => {
5213
5197
  }
5214
5198
  });
5215
5199
  }, [effectiveIdx, template, element, parsedPadding, updateElement, attributeName]);
5216
- const setTop = useCallback23((value) => {
5200
+ const setTop = useCallback24((value) => {
5217
5201
  updatePadding({ top: value });
5218
5202
  }, [updatePadding]);
5219
- const setRight = useCallback23((value) => {
5203
+ const setRight = useCallback24((value) => {
5220
5204
  updatePadding({ right: value });
5221
5205
  }, [updatePadding]);
5222
- const setBottom = useCallback23((value) => {
5206
+ const setBottom = useCallback24((value) => {
5223
5207
  updatePadding({ bottom: value });
5224
5208
  }, [updatePadding]);
5225
- const setLeft = useCallback23((value) => {
5209
+ const setLeft = useCallback24((value) => {
5226
5210
  updatePadding({ left: value });
5227
5211
  }, [updatePadding]);
5228
- const setUniform = useCallback23((value) => {
5212
+ const setUniform = useCallback24((value) => {
5229
5213
  updatePadding({ top: value, right: value, bottom: value, left: value });
5230
5214
  }, [updatePadding]);
5231
5215
  return {
@@ -5255,19 +5239,19 @@ var BetterPadding = ({
5255
5239
  targetIdx,
5256
5240
  tooltipText = "Padding"
5257
5241
  }) => {
5258
- const [isOpen, setIsOpen] = useState15(false);
5259
- const [openSection, setOpenSection] = useState15(null);
5242
+ const [isOpen, setIsOpen] = useState16(false);
5243
+ const [openSection, setOpenSection] = useState16(null);
5260
5244
  const padding = usePadding({ targetIdx });
5261
5245
  const innerPadding = usePadding({ attributeName: "inner-padding", targetIdx });
5262
5246
  const iconPadding = usePadding({ attributeName: "icon-padding", targetIdx });
5263
5247
  const textPadding = usePadding({ attributeName: "text-padding", targetIdx });
5264
- const handleToggle = useCallback24((section) => {
5248
+ const handleToggle = useCallback25((section) => {
5265
5249
  setOpenSection((prev) => prev === section ? null : section);
5266
5250
  }, []);
5267
- const handleToggleNormal = useCallback24(() => handleToggle("normal"), [handleToggle]);
5268
- const handleToggleInner = useCallback24(() => handleToggle("inner"), [handleToggle]);
5269
- const handleToggleIcon = useCallback24(() => handleToggle("icon"), [handleToggle]);
5270
- const handleToggleText = useCallback24(() => handleToggle("text"), [handleToggle]);
5251
+ const handleToggleNormal = useCallback25(() => handleToggle("normal"), [handleToggle]);
5252
+ const handleToggleInner = useCallback25(() => handleToggle("inner"), [handleToggle]);
5253
+ const handleToggleIcon = useCallback25(() => handleToggle("icon"), [handleToggle]);
5254
+ const handleToggleText = useCallback25(() => handleToggle("text"), [handleToggle]);
5271
5255
  return /* @__PURE__ */ jsxs36(Tooltip, { children: [
5272
5256
  /* @__PURE__ */ jsxs36(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
5273
5257
  /* @__PURE__ */ jsx47(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx47(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx47(
@@ -5322,105 +5306,14 @@ var BetterPadding = ({
5322
5306
  ] });
5323
5307
  };
5324
5308
  var PaddingSectionUI = ({ label, isOpen, onToggle, data }) => {
5325
- const [sliderValue, setSliderValue] = useState15(data.uniformValue ?? data.top);
5326
- const [sliderInputValue, setSliderInputValue] = useState15((data.uniformValue ?? data.top).toString());
5327
- const [topInput, setTopInput] = useState15(data.top.toString());
5328
- const [rightInput, setRightInput] = useState15(data.right.toString());
5329
- const [bottomInput, setBottomInput] = useState15(data.bottom.toString());
5330
- const [leftInput, setLeftInput] = useState15(data.left.toString());
5331
- useEffect9(() => {
5332
- setSliderValue(data.uniformValue ?? data.top);
5333
- setSliderInputValue((data.uniformValue ?? data.top).toString());
5334
- }, [data.uniformValue, data.top]);
5335
- useEffect9(() => {
5336
- setTopInput(data.top.toString());
5337
- }, [data.top]);
5338
- useEffect9(() => {
5339
- setRightInput(data.right.toString());
5340
- }, [data.right]);
5341
- useEffect9(() => {
5342
- setBottomInput(data.bottom.toString());
5343
- }, [data.bottom]);
5344
- useEffect9(() => {
5345
- setLeftInput(data.left.toString());
5346
- }, [data.left]);
5347
- const handleKeyDown = useCallback24((e) => {
5348
- if (e.key === "Enter") {
5349
- e.currentTarget.blur();
5350
- }
5351
- }, []);
5352
- const handleSliderChange = useCallback24((values) => {
5353
- const newValue = values[0];
5354
- setSliderValue(newValue);
5355
- setSliderInputValue(newValue.toString());
5356
- data.setUniform(newValue);
5309
+ const sliderInput = useEditableNumber({ value: data.uniformValue ?? data.top, onChange: data.setUniform, min: 0, max: PADDING_MAX });
5310
+ const topInput = useEditableNumber({ value: data.top, onChange: data.setTop, min: 0, max: PADDING_MAX });
5311
+ const rightInput = useEditableNumber({ value: data.right, onChange: data.setRight, min: 0, max: PADDING_MAX });
5312
+ const bottomInput = useEditableNumber({ value: data.bottom, onChange: data.setBottom, min: 0, max: PADDING_MAX });
5313
+ const leftInput = useEditableNumber({ value: data.left, onChange: data.setLeft, min: 0, max: PADDING_MAX });
5314
+ const handleSliderChange = useCallback25((values) => {
5315
+ data.setUniform(values[0]);
5357
5316
  }, [data]);
5358
- const handleSliderInputChange = useCallback24((e) => {
5359
- setSliderInputValue(e.target.value);
5360
- }, []);
5361
- const handleSliderInputBlur = useCallback24(() => {
5362
- const parsed = parseInt(sliderInputValue, 10);
5363
- if (isNaN(parsed) || sliderInputValue === "") {
5364
- setSliderInputValue(sliderValue.toString());
5365
- } else {
5366
- const clamped = Math.max(0, Math.min(PADDING_MAX, parsed));
5367
- setSliderValue(clamped);
5368
- setSliderInputValue(clamped.toString());
5369
- data.setUniform(clamped);
5370
- }
5371
- }, [sliderInputValue, sliderValue, data]);
5372
- const handleTopChange = useCallback24((e) => {
5373
- setTopInput(e.target.value);
5374
- }, []);
5375
- const handleTopBlur = useCallback24(() => {
5376
- const parsed = parseInt(topInput, 10);
5377
- if (isNaN(parsed)) {
5378
- setTopInput(data.top.toString());
5379
- } else {
5380
- const clamped = Math.max(0, Math.min(PADDING_MAX, parsed));
5381
- data.setTop(clamped);
5382
- setTopInput(clamped.toString());
5383
- }
5384
- }, [topInput, data]);
5385
- const handleRightChange = useCallback24((e) => {
5386
- setRightInput(e.target.value);
5387
- }, []);
5388
- const handleRightBlur = useCallback24(() => {
5389
- const parsed = parseInt(rightInput, 10);
5390
- if (isNaN(parsed)) {
5391
- setRightInput(data.right.toString());
5392
- } else {
5393
- const clamped = Math.max(0, Math.min(PADDING_MAX, parsed));
5394
- data.setRight(clamped);
5395
- setRightInput(clamped.toString());
5396
- }
5397
- }, [rightInput, data]);
5398
- const handleBottomChange = useCallback24((e) => {
5399
- setBottomInput(e.target.value);
5400
- }, []);
5401
- const handleBottomBlur = useCallback24(() => {
5402
- const parsed = parseInt(bottomInput, 10);
5403
- if (isNaN(parsed)) {
5404
- setBottomInput(data.bottom.toString());
5405
- } else {
5406
- const clamped = Math.max(0, Math.min(PADDING_MAX, parsed));
5407
- data.setBottom(clamped);
5408
- setBottomInput(clamped.toString());
5409
- }
5410
- }, [bottomInput, data]);
5411
- const handleLeftChange = useCallback24((e) => {
5412
- setLeftInput(e.target.value);
5413
- }, []);
5414
- const handleLeftBlur = useCallback24(() => {
5415
- const parsed = parseInt(leftInput, 10);
5416
- if (isNaN(parsed)) {
5417
- setLeftInput(data.left.toString());
5418
- } else {
5419
- const clamped = Math.max(0, Math.min(PADDING_MAX, parsed));
5420
- data.setLeft(clamped);
5421
- setLeftInput(clamped.toString());
5422
- }
5423
- }, [leftInput, data]);
5424
5317
  return /* @__PURE__ */ jsxs36(Collapsible, { open: isOpen, onOpenChange: onToggle, children: [
5425
5318
  /* @__PURE__ */ jsx47(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsx47(Button, { variant: "outline", className: "w-full shadow-none rounded-[12px]", children: /* @__PURE__ */ jsxs36("div", { className: "w-full flex flex-row items-center justify-between gap-2", children: [
5426
5319
  /* @__PURE__ */ jsx47("p", { children: label }),
@@ -5431,7 +5324,7 @@ var PaddingSectionUI = ({ label, isOpen, onToggle, data }) => {
5431
5324
  /* @__PURE__ */ jsx47(
5432
5325
  Slider2,
5433
5326
  {
5434
- value: [sliderValue],
5327
+ value: [data.uniformValue ?? data.top],
5435
5328
  onValueChange: handleSliderChange,
5436
5329
  min: 0,
5437
5330
  max: PADDING_MAX,
@@ -5442,10 +5335,11 @@ var PaddingSectionUI = ({ label, isOpen, onToggle, data }) => {
5442
5335
  Input,
5443
5336
  {
5444
5337
  type: "number",
5445
- value: sliderInputValue,
5446
- onChange: handleSliderInputChange,
5447
- onBlur: handleSliderInputBlur,
5448
- onKeyDown: handleKeyDown,
5338
+ value: sliderInput.displayValue,
5339
+ onChange: (e) => sliderInput.setLocalValue(e.target.value),
5340
+ onFocus: sliderInput.handleFocus,
5341
+ onBlur: sliderInput.handleBlur,
5342
+ onKeyDown: sliderInput.handleKeyDown,
5449
5343
  className: "w-25 shadow-none rounded-[12px]",
5450
5344
  min: 0,
5451
5345
  max: PADDING_MAX
@@ -5460,10 +5354,11 @@ var PaddingSectionUI = ({ label, isOpen, onToggle, data }) => {
5460
5354
  Input,
5461
5355
  {
5462
5356
  type: "number",
5463
- value: topInput,
5464
- onChange: handleTopChange,
5465
- onBlur: handleTopBlur,
5466
- onKeyDown: handleKeyDown,
5357
+ value: topInput.displayValue,
5358
+ onChange: (e) => topInput.setLocalValue(e.target.value),
5359
+ onFocus: topInput.handleFocus,
5360
+ onBlur: topInput.handleBlur,
5361
+ onKeyDown: topInput.handleKeyDown,
5467
5362
  className: "w-20 shadow-none rounded-[12px]",
5468
5363
  min: 0,
5469
5364
  max: PADDING_MAX
@@ -5476,10 +5371,11 @@ var PaddingSectionUI = ({ label, isOpen, onToggle, data }) => {
5476
5371
  Input,
5477
5372
  {
5478
5373
  type: "number",
5479
- value: bottomInput,
5480
- onChange: handleBottomChange,
5481
- onBlur: handleBottomBlur,
5482
- onKeyDown: handleKeyDown,
5374
+ value: bottomInput.displayValue,
5375
+ onChange: (e) => bottomInput.setLocalValue(e.target.value),
5376
+ onFocus: bottomInput.handleFocus,
5377
+ onBlur: bottomInput.handleBlur,
5378
+ onKeyDown: bottomInput.handleKeyDown,
5483
5379
  className: "w-20 shadow-none rounded-[12px]",
5484
5380
  min: 0,
5485
5381
  max: PADDING_MAX
@@ -5494,10 +5390,11 @@ var PaddingSectionUI = ({ label, isOpen, onToggle, data }) => {
5494
5390
  Input,
5495
5391
  {
5496
5392
  type: "number",
5497
- value: leftInput,
5498
- onChange: handleLeftChange,
5499
- onBlur: handleLeftBlur,
5500
- onKeyDown: handleKeyDown,
5393
+ value: leftInput.displayValue,
5394
+ onChange: (e) => leftInput.setLocalValue(e.target.value),
5395
+ onFocus: leftInput.handleFocus,
5396
+ onBlur: leftInput.handleBlur,
5397
+ onKeyDown: leftInput.handleKeyDown,
5501
5398
  className: "w-20 shadow-none rounded-[12px]",
5502
5399
  min: 0,
5503
5400
  max: PADDING_MAX
@@ -5510,10 +5407,11 @@ var PaddingSectionUI = ({ label, isOpen, onToggle, data }) => {
5510
5407
  Input,
5511
5408
  {
5512
5409
  type: "number",
5513
- value: rightInput,
5514
- onChange: handleRightChange,
5515
- onBlur: handleRightBlur,
5516
- onKeyDown: handleKeyDown,
5410
+ value: rightInput.displayValue,
5411
+ onChange: (e) => rightInput.setLocalValue(e.target.value),
5412
+ onFocus: rightInput.handleFocus,
5413
+ onBlur: rightInput.handleBlur,
5414
+ onKeyDown: rightInput.handleKeyDown,
5517
5415
  className: "w-20 shadow-none rounded-[12px]",
5518
5416
  min: 0,
5519
5417
  max: PADDING_MAX
@@ -5597,24 +5495,24 @@ var ColumnStyles = () => {
5597
5495
  const paddingUniformValue = useMemo13(() => {
5598
5496
  return getUniformValue(padding);
5599
5497
  }, [padding]);
5600
- const handleOpenBgColorPicker = useCallback25(() => {
5498
+ const handleOpenBgColorPicker = useCallback26(() => {
5601
5499
  setColorType("Column color");
5602
5500
  setColorTarget("columnBgColor");
5603
5501
  setActiveView("color");
5604
5502
  }, [setColorType, setColorTarget, setActiveView]);
5605
- const handleOpenStrokeColorPicker = useCallback25(() => {
5503
+ const handleOpenStrokeColorPicker = useCallback26(() => {
5606
5504
  setColorType("Column Stroke");
5607
5505
  setColorTarget("columnStrokeColor");
5608
5506
  setActiveView("color");
5609
5507
  }, [setColorType, setColorTarget, setActiveView]);
5610
- const handleStrokeWidthChange = useCallback25((width) => {
5508
+ const handleStrokeWidthChange = useCallback26((width) => {
5611
5509
  if (!columnIdx || !column) return;
5612
5510
  const newBorder = formatBorder({ ...border, width });
5613
5511
  updateElement(columnIdx, {
5614
5512
  attributes: { ...column.attributes, border: newBorder }
5615
5513
  });
5616
5514
  }, [columnIdx, column, border, updateElement]);
5617
- const handleStrokeEnabledChange = useCallback25((enabled) => {
5515
+ const handleStrokeEnabledChange = useCallback26((enabled) => {
5618
5516
  if (!columnIdx || !column) return;
5619
5517
  const newBorder = formatBorder({
5620
5518
  ...border,
@@ -5624,32 +5522,32 @@ var ColumnStyles = () => {
5624
5522
  attributes: { ...column.attributes, border: newBorder }
5625
5523
  });
5626
5524
  }, [columnIdx, column, border, updateElement]);
5627
- const handleBorderRadiusChange = useCallback25((value) => {
5525
+ const handleBorderRadiusChange = useCallback26((value) => {
5628
5526
  if (!columnIdx || !column) return;
5629
5527
  updateElement(columnIdx, {
5630
5528
  attributes: { ...column.attributes, "border-radius": formatBorderRadius(value) }
5631
5529
  });
5632
5530
  }, [columnIdx, column, updateElement]);
5633
- const updatePadding = useCallback25((updates) => {
5531
+ const updatePadding = useCallback26((updates) => {
5634
5532
  if (!columnIdx || !column) return;
5635
5533
  const newPadding = { ...padding, ...updates };
5636
5534
  updateElement(columnIdx, {
5637
5535
  attributes: { ...column.attributes, padding: formatPadding(newPadding) }
5638
5536
  });
5639
5537
  }, [columnIdx, column, padding, updateElement]);
5640
- const handlePaddingTopChange = useCallback25((value) => {
5538
+ const handlePaddingTopChange = useCallback26((value) => {
5641
5539
  updatePadding({ top: value });
5642
5540
  }, [updatePadding]);
5643
- const handlePaddingRightChange = useCallback25((value) => {
5541
+ const handlePaddingRightChange = useCallback26((value) => {
5644
5542
  updatePadding({ right: value });
5645
5543
  }, [updatePadding]);
5646
- const handlePaddingBottomChange = useCallback25((value) => {
5544
+ const handlePaddingBottomChange = useCallback26((value) => {
5647
5545
  updatePadding({ bottom: value });
5648
5546
  }, [updatePadding]);
5649
- const handlePaddingLeftChange = useCallback25((value) => {
5547
+ const handlePaddingLeftChange = useCallback26((value) => {
5650
5548
  updatePadding({ left: value });
5651
5549
  }, [updatePadding]);
5652
- const handlePaddingUniformChange = useCallback25((value) => {
5550
+ const handlePaddingUniformChange = useCallback26((value) => {
5653
5551
  updatePadding({ top: value, right: value, bottom: value, left: value });
5654
5552
  }, [updatePadding]);
5655
5553
  return /* @__PURE__ */ jsxs38(Fragment3, { children: [
@@ -5737,8 +5635,8 @@ var TextToolbar = () => {
5737
5635
  const template = useEditorStore((s) => s.template);
5738
5636
  const mergeFields = useEditorStore((s) => s.mergeFields);
5739
5637
  const { activeView, colorTarget, setActiveView, setColorType, setColorTarget } = useSidebarContext();
5740
- const [updateCounter, forceUpdate] = useState16(0);
5741
- const [overflowOpen, setOverflowOpen] = useState16(false);
5638
+ const [updateCounter, forceUpdate] = useState17(0);
5639
+ const [overflowOpen, setOverflowOpen] = useState17(false);
5742
5640
  const isInSectionColumn = useMemo14(() => {
5743
5641
  if (!focusIdx || !template) return false;
5744
5642
  const columnIdx = getParentIdx(focusIdx);
@@ -5748,7 +5646,7 @@ var TextToolbar = () => {
5748
5646
  const section = getValueByIdx(template, sectionIdx);
5749
5647
  return section?.type === "section-column";
5750
5648
  }, [focusIdx, template]);
5751
- useEffect10(() => {
5649
+ useEffect7(() => {
5752
5650
  if (!tiptapEditor) return;
5753
5651
  const handler = () => forceUpdate((n) => n + 1);
5754
5652
  tiptapEditor.on("selectionUpdate", handler);
@@ -5783,7 +5681,7 @@ var TextToolbar = () => {
5783
5681
  const multiplier = HEADING_MULTIPLIERS[activeType] || 1;
5784
5682
  return Math.round(baseFontSize * multiplier);
5785
5683
  }, [tiptapEditor, updateCounter, activeType, baseFontSize]);
5786
- const handleFontSizeChange = useCallback26((size) => {
5684
+ const handleFontSizeChange = useCallback27((size) => {
5787
5685
  if (!tiptapEditor) return;
5788
5686
  tiptapEditor.chain().focus().setFontSize(`${size}px`).run();
5789
5687
  forceUpdate((n) => n + 1);
@@ -5794,7 +5692,7 @@ var TextToolbar = () => {
5794
5692
  if (paragraphAttrs.textAlign) return paragraphAttrs.textAlign;
5795
5693
  return "left";
5796
5694
  }, [tiptapEditor, updateCounter]);
5797
- const handleCycleAlignment = useCallback26(() => {
5695
+ const handleCycleAlignment = useCallback27(() => {
5798
5696
  if (!tiptapEditor) return;
5799
5697
  const currentIndex = ALIGNMENTS.indexOf(currentAlignment);
5800
5698
  const nextIndex = (currentIndex + 1) % ALIGNMENTS.length;
@@ -5802,30 +5700,30 @@ var TextToolbar = () => {
5802
5700
  tiptapEditor.chain().focus().setTextAlign(nextAlignment).run();
5803
5701
  forceUpdate((n) => n + 1);
5804
5702
  }, [tiptapEditor, currentAlignment]);
5805
- const handleCycleList = useCallback26(() => {
5703
+ const handleCycleList = useCallback27(() => {
5806
5704
  }, [tiptapEditor]);
5807
5705
  const isInHeading = useMemo14(() => {
5808
5706
  if (!tiptapEditor) return false;
5809
5707
  const paragraphAttrs = tiptapEditor.getAttributes("paragraph");
5810
5708
  return (paragraphAttrs.headingLevel || 0) > 0;
5811
5709
  }, [tiptapEditor, updateCounter]);
5812
- const handleToggleBold = useCallback26(() => {
5710
+ const handleToggleBold = useCallback27(() => {
5813
5711
  if (!tiptapEditor) return;
5814
5712
  if (isInHeading) return;
5815
5713
  tiptapEditor.chain().focus().toggleBold().run();
5816
5714
  forceUpdate((n) => n + 1);
5817
5715
  }, [tiptapEditor, isInHeading]);
5818
- const handleToggleItalic = useCallback26(() => {
5716
+ const handleToggleItalic = useCallback27(() => {
5819
5717
  if (!tiptapEditor) return;
5820
5718
  tiptapEditor.chain().focus().toggleItalic().run();
5821
5719
  forceUpdate((n) => n + 1);
5822
5720
  }, [tiptapEditor]);
5823
- const handleToggleUnderline = useCallback26(() => {
5721
+ const handleToggleUnderline = useCallback27(() => {
5824
5722
  if (!tiptapEditor) return;
5825
5723
  tiptapEditor.chain().focus().toggleUnderline().run();
5826
5724
  forceUpdate((n) => n + 1);
5827
5725
  }, [tiptapEditor]);
5828
- const handleToggleStrike = useCallback26(() => {
5726
+ const handleToggleStrike = useCallback27(() => {
5829
5727
  if (!tiptapEditor) return;
5830
5728
  tiptapEditor.chain().focus().toggleStrike().run();
5831
5729
  forceUpdate((n) => n + 1);
@@ -5847,7 +5745,7 @@ var TextToolbar = () => {
5847
5745
  if (!tiptapEditor) return false;
5848
5746
  return tiptapEditor.isActive("strike");
5849
5747
  }, [tiptapEditor, updateCounter]);
5850
- const handleSetType = useCallback26((type) => {
5748
+ const handleSetType = useCallback27((type) => {
5851
5749
  if (!tiptapEditor) return;
5852
5750
  const levelMap = {
5853
5751
  paragraph: 0,
@@ -5867,12 +5765,12 @@ var TextToolbar = () => {
5867
5765
  deleteElement(focusIdx);
5868
5766
  }
5869
5767
  };
5870
- const handleOpenTextColorPicker = useCallback26(() => {
5768
+ const handleOpenTextColorPicker = useCallback27(() => {
5871
5769
  setColorType("Text color");
5872
5770
  setColorTarget("textColor");
5873
5771
  setActiveView("color");
5874
5772
  }, [setColorType, setColorTarget, setActiveView]);
5875
- const handleOpenHighlightColorPicker = useCallback26(() => {
5773
+ const handleOpenHighlightColorPicker = useCallback27(() => {
5876
5774
  setColorType("Highlight color");
5877
5775
  setColorTarget("highlightColor");
5878
5776
  setActiveView("color");
@@ -5885,7 +5783,7 @@ var TextToolbar = () => {
5885
5783
  if (!tiptapEditor) return "transparent";
5886
5784
  return tiptapEditor.getAttributes("textStyle").backgroundColor || "transparent";
5887
5785
  }, [tiptapEditor, updateCounter]);
5888
- const extractKnownFont = useCallback26((fontStack) => {
5786
+ const extractKnownFont = useCallback27((fontStack) => {
5889
5787
  if (!fontStack) return "Arial";
5890
5788
  const fonts = fontStack.split(",").map((f) => f.trim().replace(/['"]/g, ""));
5891
5789
  for (const font of fonts) {
@@ -5902,7 +5800,7 @@ var TextToolbar = () => {
5902
5800
  }
5903
5801
  return extractKnownFont(textEditingStyles?.fontFamily);
5904
5802
  }, [tiptapEditor, updateCounter, textEditingStyles?.fontFamily, extractKnownFont]);
5905
- const handleSetFontFamily = useCallback26((font) => {
5803
+ const handleSetFontFamily = useCallback27((font) => {
5906
5804
  if (!tiptapEditor) return;
5907
5805
  tiptapEditor.chain().focus().setFontFamily(font).run();
5908
5806
  forceUpdate((n) => n + 1);
@@ -6442,12 +6340,12 @@ var MergeFieldItem = ({ isResponsive, isInSectionColumn, tiptapEditor, mergeFiel
6442
6340
  };
6443
6341
 
6444
6342
  // src/core/editor/components/element-gear/button/toolbar.tsx
6445
- import { useCallback as useCallback31, useMemo as useMemo19 } from "react";
6343
+ import { useCallback as useCallback32, useMemo as useMemo19 } from "react";
6446
6344
  import { get as lodashGet7 } from "lodash";
6447
6345
  import { BoldIcon as BoldIcon2, CaseUpperIcon as CaseUpperIcon2, ItalicIcon as ItalicIcon2, Strikethrough as Strikethrough2, Underline as Underline2 } from "lucide-react";
6448
6346
 
6449
6347
  // src/core/editor/hooks/use-border-radius.ts
6450
- import { useMemo as useMemo15, useCallback as useCallback27 } from "react";
6348
+ import { useMemo as useMemo15, useCallback as useCallback28 } from "react";
6451
6349
  import { get as lodashGet4 } from "lodash";
6452
6350
  var useBorderRadius = (options = {}) => {
6453
6351
  const { focusIdx, updateElement, template } = useEditorStore();
@@ -6459,7 +6357,7 @@ var useBorderRadius = (options = {}) => {
6459
6357
  const rawValue = element?.attributes?.[attributeName];
6460
6358
  return parseBorderRadius(rawValue);
6461
6359
  }, [focusIdx, template, attributeName]);
6462
- const handleChange = useCallback27((value) => {
6360
+ const handleChange = useCallback28((value) => {
6463
6361
  if (!focusIdx || !template) return;
6464
6362
  const path = focusIdx.startsWith("content.") ? focusIdx.replace("content.", "content[0].").replace(/\.\[(\d+)\]/g, "[$1]") : focusIdx;
6465
6363
  const element = lodashGet4(template, path);
@@ -6478,7 +6376,7 @@ var useBorderRadius = (options = {}) => {
6478
6376
  };
6479
6377
 
6480
6378
  // src/core/editor/hooks/use-border.ts
6481
- import { useMemo as useMemo16, useCallback as useCallback28 } from "react";
6379
+ import { useMemo as useMemo16, useCallback as useCallback29 } from "react";
6482
6380
  import { get as lodashGet5 } from "lodash";
6483
6381
  var useBorder = (options = {}) => {
6484
6382
  const { focusIdx, updateElement, template } = useEditorStore();
@@ -6495,7 +6393,7 @@ var useBorder = (options = {}) => {
6495
6393
  const width = parsedBorder.width;
6496
6394
  const color = parsedBorder.color;
6497
6395
  const isEnabled = width > 0;
6498
- const updateBorder = useCallback28((updates) => {
6396
+ const updateBorder = useCallback29((updates) => {
6499
6397
  if (!focusIdx || !template || !element) return;
6500
6398
  const newBorder = {
6501
6399
  ...parsedBorder,
@@ -6508,13 +6406,13 @@ var useBorder = (options = {}) => {
6508
6406
  }
6509
6407
  });
6510
6408
  }, [focusIdx, template, element, parsedBorder, updateElement, attributeName]);
6511
- const setWidth = useCallback28((newWidth) => {
6409
+ const setWidth = useCallback29((newWidth) => {
6512
6410
  updateBorder({ width: newWidth });
6513
6411
  }, [updateBorder]);
6514
- const setColor = useCallback28((newColor) => {
6412
+ const setColor = useCallback29((newColor) => {
6515
6413
  updateBorder({ color: newColor });
6516
6414
  }, [updateBorder]);
6517
- const setEnabled = useCallback28((enabled) => {
6415
+ const setEnabled = useCallback29((enabled) => {
6518
6416
  if (enabled) {
6519
6417
  updateBorder({ width: parsedBorder.width === 0 ? 1 : parsedBorder.width });
6520
6418
  } else {
@@ -6532,7 +6430,7 @@ var useBorder = (options = {}) => {
6532
6430
  };
6533
6431
 
6534
6432
  // src/core/editor/hooks/use-size.ts
6535
- import { useMemo as useMemo17, useCallback as useCallback29 } from "react";
6433
+ import { useMemo as useMemo17, useCallback as useCallback30 } from "react";
6536
6434
  import { get as lodashGet6 } from "lodash";
6537
6435
  var parseSize = (value, defaultValue) => {
6538
6436
  if (!value) return defaultValue;
@@ -6560,13 +6458,13 @@ var useSize = (options = {}) => {
6560
6458
  height: parseSize(el?.attributes?.[heightAttribute], defaultHeight)
6561
6459
  };
6562
6460
  }, [focusIdx, template, widthAttribute, heightAttribute, defaultWidth, defaultHeight]);
6563
- const setWidth = useCallback29((value) => {
6461
+ const setWidth = useCallback30((value) => {
6564
6462
  if (!focusIdx || !template || !element) return;
6565
6463
  updateElement(focusIdx, {
6566
6464
  attributes: { ...element.attributes, [widthAttribute]: formatSize(value, widthUnit) }
6567
6465
  });
6568
6466
  }, [focusIdx, template, element, updateElement, widthAttribute, widthUnit]);
6569
- const setHeight = useCallback29((value) => {
6467
+ const setHeight = useCallback30((value) => {
6570
6468
  if (!focusIdx || !template || !element) return;
6571
6469
  updateElement(focusIdx, {
6572
6470
  attributes: { ...element.attributes, [heightAttribute]: formatSize(value, heightUnit) }
@@ -6577,10 +6475,10 @@ var useSize = (options = {}) => {
6577
6475
 
6578
6476
  // src/core/editor/components/button-text-settings.tsx
6579
6477
  import { TypeIcon as TypeIcon2 } from "lucide-react";
6580
- import { useState as useState17, useEffect as useEffect11, useMemo as useMemo18, useCallback as useCallback30, memo as memo4 } from "react";
6478
+ import { useState as useState18, useMemo as useMemo18, useCallback as useCallback31, memo as memo4 } from "react";
6581
6479
  import { jsx as jsx51, jsxs as jsxs40 } from "react/jsx-runtime";
6582
6480
  var ButtonTextSettings = memo4(function ButtonTextSettings2() {
6583
- const [isOpen, setIsOpen] = useState17(false);
6481
+ const [isOpen, setIsOpen] = useState18(false);
6584
6482
  const focusIdx = useEditorStore((s) => s.focusIdx);
6585
6483
  const template = useEditorStore((s) => s.template);
6586
6484
  const updateElement = useEditorStore((s) => s.updateElement);
@@ -6597,114 +6495,40 @@ var ButtonTextSettings = memo4(function ButtonTextSettings2() {
6597
6495
  const parsed = parseFloat(buttonElement.attributes["line-height"]);
6598
6496
  return isNaN(parsed) ? DEFAULT_LINE_HEIGHT : parsed;
6599
6497
  }, [buttonElement]);
6600
- const [letterSpacingInputValue, setLetterSpacingInputValue] = useState17(
6601
- String(currentLetterSpacing)
6602
- );
6603
- const [isLetterSpacingInputFocused, setIsLetterSpacingInputFocused] = useState17(false);
6604
- const [lineHeightInputValue, setLineHeightInputValue] = useState17(
6605
- String(currentLineHeight)
6606
- );
6607
- const [isLineHeightInputFocused, setIsLineHeightInputFocused] = useState17(false);
6608
- useEffect11(() => {
6609
- if (!isLetterSpacingInputFocused) {
6610
- setLetterSpacingInputValue(String(currentLetterSpacing));
6611
- }
6612
- }, [currentLetterSpacing, isLetterSpacingInputFocused]);
6613
- useEffect11(() => {
6614
- if (!isLineHeightInputFocused) {
6615
- setLineHeightInputValue(String(currentLineHeight));
6616
- }
6617
- }, [currentLineHeight, isLineHeightInputFocused]);
6618
- const handleLetterSpacingSliderChange = useCallback30((values) => {
6498
+ const commitLetterSpacing = useCallback31((value) => {
6619
6499
  if (!focusIdx) return;
6620
- const value = values[0];
6621
- setLetterSpacingInputValue(String(value));
6622
6500
  const currentTemplate = useEditorStore.getState().template;
6623
6501
  const element = getValueByIdx(currentTemplate, focusIdx);
6624
6502
  updateElement(focusIdx, {
6625
- attributes: {
6626
- ...element?.attributes,
6627
- "letter-spacing": `${value}px`
6628
- }
6503
+ attributes: { ...element?.attributes, "letter-spacing": `${value}px` }
6629
6504
  });
6630
6505
  }, [focusIdx, updateElement]);
6631
- const handleLetterSpacingInputChange = useCallback30((e) => {
6632
- setLetterSpacingInputValue(e.target.value);
6633
- }, []);
6634
- const applyLetterSpacing = useCallback30(() => {
6506
+ const commitLineHeight = useCallback31((value) => {
6635
6507
  if (!focusIdx) return;
6636
- const parsed = parseFloat(letterSpacingInputValue);
6637
- if (isNaN(parsed) || letterSpacingInputValue === "") {
6638
- setLetterSpacingInputValue(String(currentLetterSpacing));
6639
- return;
6640
- }
6641
- const clampedValue = Math.max(MIN_LETTER_SPACING, Math.min(parsed, MAX_LETTER_SPACING));
6642
- setLetterSpacingInputValue(String(clampedValue));
6643
6508
  const currentTemplate = useEditorStore.getState().template;
6644
6509
  const element = getValueByIdx(currentTemplate, focusIdx);
6645
6510
  updateElement(focusIdx, {
6646
- attributes: {
6647
- ...element?.attributes,
6648
- "letter-spacing": `${clampedValue}px`
6649
- }
6650
- });
6651
- }, [focusIdx, letterSpacingInputValue, currentLetterSpacing, updateElement]);
6652
- const handleLetterSpacingInputBlur = useCallback30(() => {
6653
- setIsLetterSpacingInputFocused(false);
6654
- applyLetterSpacing();
6655
- }, [applyLetterSpacing]);
6656
- const handleLetterSpacingInputKeyDown = useCallback30((e) => {
6657
- if (e.key === "Enter") {
6658
- e.preventDefault();
6659
- applyLetterSpacing();
6660
- e.target.blur();
6661
- }
6662
- }, [applyLetterSpacing]);
6663
- const handleLineHeightSliderChange = useCallback30((values) => {
6664
- if (!focusIdx) return;
6665
- const value = values[0];
6666
- setLineHeightInputValue(String(value));
6667
- const currentTemplate = useEditorStore.getState().template;
6668
- const element = getValueByIdx(currentTemplate, focusIdx);
6669
- updateElement(focusIdx, {
6670
- attributes: {
6671
- ...element?.attributes,
6672
- "line-height": String(value)
6673
- }
6511
+ attributes: { ...element?.attributes, "line-height": String(value) }
6674
6512
  });
6675
6513
  }, [focusIdx, updateElement]);
6676
- const handleLineHeightInputChange = useCallback30((e) => {
6677
- setLineHeightInputValue(e.target.value);
6678
- }, []);
6679
- const applyLineHeight = useCallback30(() => {
6680
- if (!focusIdx) return;
6681
- const parsed = parseFloat(lineHeightInputValue);
6682
- if (isNaN(parsed) || lineHeightInputValue === "") {
6683
- setLineHeightInputValue(String(currentLineHeight));
6684
- return;
6685
- }
6686
- const clampedValue = Math.max(MIN_LINE_HEIGHT, Math.min(parsed, MAX_LINE_HEIGHT));
6687
- setLineHeightInputValue(String(clampedValue));
6688
- const currentTemplate = useEditorStore.getState().template;
6689
- const element = getValueByIdx(currentTemplate, focusIdx);
6690
- updateElement(focusIdx, {
6691
- attributes: {
6692
- ...element?.attributes,
6693
- "line-height": String(clampedValue)
6694
- }
6695
- });
6696
- }, [focusIdx, lineHeightInputValue, currentLineHeight, updateElement]);
6697
- const handleLineHeightInputBlur = useCallback30(() => {
6698
- setIsLineHeightInputFocused(false);
6699
- applyLineHeight();
6700
- }, [applyLineHeight]);
6701
- const handleLineHeightInputKeyDown = useCallback30((e) => {
6702
- if (e.key === "Enter") {
6703
- e.preventDefault();
6704
- applyLineHeight();
6705
- e.target.blur();
6706
- }
6707
- }, [applyLineHeight]);
6514
+ const letterSpacingInput = useEditableFloat({
6515
+ value: currentLetterSpacing,
6516
+ onChange: commitLetterSpacing,
6517
+ min: MIN_LETTER_SPACING,
6518
+ max: MAX_LETTER_SPACING
6519
+ });
6520
+ const lineHeightInput = useEditableFloat({
6521
+ value: currentLineHeight,
6522
+ onChange: commitLineHeight,
6523
+ min: MIN_LINE_HEIGHT,
6524
+ max: MAX_LINE_HEIGHT
6525
+ });
6526
+ const handleLetterSpacingSliderChange = useCallback31((values) => {
6527
+ commitLetterSpacing(values[0]);
6528
+ }, [commitLetterSpacing]);
6529
+ const handleLineHeightSliderChange = useCallback31((values) => {
6530
+ commitLineHeight(values[0]);
6531
+ }, [commitLineHeight]);
6708
6532
  return /* @__PURE__ */ jsxs40(Tooltip, { children: [
6709
6533
  /* @__PURE__ */ jsxs40(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
6710
6534
  /* @__PURE__ */ jsx51(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx51(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx51(
@@ -6741,11 +6565,11 @@ var ButtonTextSettings = memo4(function ButtonTextSettings2() {
6741
6565
  Input,
6742
6566
  {
6743
6567
  type: "number",
6744
- value: letterSpacingInputValue,
6745
- onChange: handleLetterSpacingInputChange,
6746
- onFocus: () => setIsLetterSpacingInputFocused(true),
6747
- onBlur: handleLetterSpacingInputBlur,
6748
- onKeyDown: handleLetterSpacingInputKeyDown,
6568
+ value: letterSpacingInput.displayValue,
6569
+ onChange: (e) => letterSpacingInput.setLocalValue(e.target.value),
6570
+ onFocus: letterSpacingInput.handleFocus,
6571
+ onBlur: letterSpacingInput.handleBlur,
6572
+ onKeyDown: letterSpacingInput.handleKeyDown,
6749
6573
  className: "w-25 shadow-none rounded-[12px]",
6750
6574
  min: MIN_LETTER_SPACING,
6751
6575
  max: MAX_LETTER_SPACING,
@@ -6772,11 +6596,11 @@ var ButtonTextSettings = memo4(function ButtonTextSettings2() {
6772
6596
  Input,
6773
6597
  {
6774
6598
  type: "number",
6775
- value: lineHeightInputValue,
6776
- onChange: handleLineHeightInputChange,
6777
- onFocus: () => setIsLineHeightInputFocused(true),
6778
- onBlur: handleLineHeightInputBlur,
6779
- onKeyDown: handleLineHeightInputKeyDown,
6599
+ value: lineHeightInput.displayValue,
6600
+ onChange: (e) => lineHeightInput.setLocalValue(e.target.value),
6601
+ onFocus: lineHeightInput.handleFocus,
6602
+ onBlur: lineHeightInput.handleBlur,
6603
+ onKeyDown: lineHeightInput.handleKeyDown,
6780
6604
  className: "w-25 shadow-none rounded-[12px]",
6781
6605
  min: MIN_LINE_HEIGHT,
6782
6606
  max: MAX_LINE_HEIGHT,
@@ -6845,36 +6669,36 @@ var ButtonToolbar = () => {
6845
6669
  deleteElement(focusIdx);
6846
6670
  }
6847
6671
  };
6848
- const handleOpenBgColorPicker = useCallback31(() => {
6672
+ const handleOpenBgColorPicker = useCallback32(() => {
6849
6673
  setColorType("Button Color");
6850
6674
  setColorTarget("buttonBgColor");
6851
6675
  setActiveView("color");
6852
6676
  }, [setColorType, setColorTarget, setActiveView]);
6853
- const handleOpenStrokeColorPicker = useCallback31(() => {
6677
+ const handleOpenStrokeColorPicker = useCallback32(() => {
6854
6678
  setColorType("Stroke Color");
6855
6679
  setColorTarget("buttonStrokeColor");
6856
6680
  setActiveView("color");
6857
6681
  }, [setColorType, setColorTarget, setActiveView]);
6858
- const handleOpenTextColorPicker = useCallback31(() => {
6682
+ const handleOpenTextColorPicker = useCallback32(() => {
6859
6683
  setColorType("Text Color");
6860
6684
  setColorTarget("buttonTextColor");
6861
6685
  setActiveView("color");
6862
6686
  }, [setColorType, setColorTarget, setActiveView]);
6863
- const handleToggleBold = useCallback31(() => {
6687
+ const handleToggleBold = useCallback32(() => {
6864
6688
  if (!focusIdx || !currentElement) return;
6865
6689
  const newWeight = isBold ? "normal" : "bold";
6866
6690
  updateElement(focusIdx, {
6867
6691
  attributes: { ...currentElement.attributes, "font-weight": newWeight }
6868
6692
  });
6869
6693
  }, [focusIdx, currentElement, isBold, updateElement]);
6870
- const handleToggleItalic = useCallback31(() => {
6694
+ const handleToggleItalic = useCallback32(() => {
6871
6695
  if (!focusIdx || !currentElement) return;
6872
6696
  const newStyle = isItalic ? "normal" : "italic";
6873
6697
  updateElement(focusIdx, {
6874
6698
  attributes: { ...currentElement.attributes, "font-style": newStyle }
6875
6699
  });
6876
6700
  }, [focusIdx, currentElement, isItalic, updateElement]);
6877
- const handleToggleUnderline = useCallback31(() => {
6701
+ const handleToggleUnderline = useCallback32(() => {
6878
6702
  if (!focusIdx || !currentElement) return;
6879
6703
  const currentDecoration = currentElement.attributes?.["text-decoration"] || "";
6880
6704
  let newDecoration;
@@ -6887,7 +6711,7 @@ var ButtonToolbar = () => {
6887
6711
  attributes: { ...currentElement.attributes, "text-decoration": newDecoration || "none" }
6888
6712
  });
6889
6713
  }, [focusIdx, currentElement, isUnderline, updateElement]);
6890
- const handleToggleStrike = useCallback31(() => {
6714
+ const handleToggleStrike = useCallback32(() => {
6891
6715
  if (!focusIdx || !currentElement) return;
6892
6716
  const currentDecoration = currentElement.attributes?.["text-decoration"] || "";
6893
6717
  let newDecoration;
@@ -6900,7 +6724,7 @@ var ButtonToolbar = () => {
6900
6724
  attributes: { ...currentElement.attributes, "text-decoration": newDecoration || "none" }
6901
6725
  });
6902
6726
  }, [focusIdx, currentElement, isStrikethrough, updateElement]);
6903
- const handleCycleAlignment = useCallback31(() => {
6727
+ const handleCycleAlignment = useCallback32(() => {
6904
6728
  if (!focusIdx || !currentElement) return;
6905
6729
  const currentIndex = BUTTON_ALIGNMENTS.indexOf(currentAlignment);
6906
6730
  const nextIndex = (currentIndex + 1) % BUTTON_ALIGNMENTS.length;
@@ -6909,7 +6733,7 @@ var ButtonToolbar = () => {
6909
6733
  attributes: { ...currentElement.attributes, "text-align": nextAlignment }
6910
6734
  });
6911
6735
  }, [focusIdx, currentElement, currentAlignment, updateElement]);
6912
- const handleCycleButtonAlign = useCallback31(() => {
6736
+ const handleCycleButtonAlign = useCallback32(() => {
6913
6737
  if (!focusIdx || !currentElement) return;
6914
6738
  const currentIndex = BUTTON_ALIGNMENTS.indexOf(currentButtonAlign);
6915
6739
  const nextIndex = (currentIndex + 1) % BUTTON_ALIGNMENTS.length;
@@ -6918,13 +6742,13 @@ var ButtonToolbar = () => {
6918
6742
  attributes: { ...currentElement.attributes, "align": nextAlign }
6919
6743
  });
6920
6744
  }, [focusIdx, currentElement, currentButtonAlign, updateElement]);
6921
- const handleSetFontFamily = useCallback31((font) => {
6745
+ const handleSetFontFamily = useCallback32((font) => {
6922
6746
  if (!focusIdx || !currentElement) return;
6923
6747
  updateElement(focusIdx, {
6924
6748
  attributes: { ...currentElement.attributes, "font-family": font }
6925
6749
  });
6926
6750
  }, [focusIdx, currentElement, updateElement]);
6927
- const handleFontSizeChange = useCallback31((size2) => {
6751
+ const handleFontSizeChange = useCallback32((size2) => {
6928
6752
  if (!focusIdx || !currentElement) return;
6929
6753
  updateElement(focusIdx, {
6930
6754
  attributes: { ...currentElement.attributes, "font-size": `${size2}px` }
@@ -7112,15 +6936,15 @@ var ButtonToolbar = () => {
7112
6936
  };
7113
6937
 
7114
6938
  // src/core/editor/components/element-gear/section/toolbar.tsx
7115
- import { useCallback as useCallback33, useMemo as useMemo21 } from "react";
6939
+ import { useCallback as useCallback34, useMemo as useMemo21 } from "react";
7116
6940
  import { get as lodashGet9 } from "lodash";
7117
6941
 
7118
6942
  // src/core/editor/components/image-menu.tsx
7119
6943
  import { ImageIcon, TrashIcon as TrashIcon4, UploadIcon } from "lucide-react";
7120
- import { useState as useState18 } from "react";
6944
+ import { useState as useState19 } from "react";
7121
6945
 
7122
6946
  // src/core/editor/hooks/use-image.ts
7123
- import { useMemo as useMemo20, useCallback as useCallback32 } from "react";
6947
+ import { useMemo as useMemo20, useCallback as useCallback33 } from "react";
7124
6948
  import { get as lodashGet8 } from "lodash";
7125
6949
  var useImage = (options = {}) => {
7126
6950
  const { type = "background" } = options;
@@ -7152,13 +6976,13 @@ var useImage = (options = {}) => {
7152
6976
  height: el?.attributes?.["height"] || "auto"
7153
6977
  };
7154
6978
  }, [focusIdx, template, attributeName]);
7155
- const setUrl = useCallback32((newUrl) => {
6979
+ const setUrl = useCallback33((newUrl) => {
7156
6980
  if (!focusIdx || !element) return;
7157
6981
  updateElement(focusIdx, {
7158
6982
  attributes: { ...element.attributes, [attributeName]: newUrl }
7159
6983
  });
7160
6984
  }, [focusIdx, element, updateElement, attributeName]);
7161
- const removeUrl = useCallback32(() => {
6985
+ const removeUrl = useCallback33(() => {
7162
6986
  if (!focusIdx || !element) return;
7163
6987
  if (type === "background") {
7164
6988
  const newAttributes = { ...element.attributes };
@@ -7171,37 +6995,37 @@ var useImage = (options = {}) => {
7171
6995
  });
7172
6996
  }
7173
6997
  }, [focusIdx, element, updateElement, attributeName, type]);
7174
- const setPositionX = useCallback32((value) => {
6998
+ const setPositionX = useCallback33((value) => {
7175
6999
  if (!focusIdx || !element) return;
7176
7000
  updateElement(focusIdx, {
7177
7001
  attributes: { ...element.attributes, "background-position-x": value }
7178
7002
  });
7179
7003
  }, [focusIdx, element, updateElement]);
7180
- const setPositionY = useCallback32((value) => {
7004
+ const setPositionY = useCallback33((value) => {
7181
7005
  if (!focusIdx || !element) return;
7182
7006
  updateElement(focusIdx, {
7183
7007
  attributes: { ...element.attributes, "background-position-y": value }
7184
7008
  });
7185
7009
  }, [focusIdx, element, updateElement]);
7186
- const setBackgroundSize = useCallback32((value) => {
7010
+ const setBackgroundSize = useCallback33((value) => {
7187
7011
  if (!focusIdx || !element) return;
7188
7012
  updateElement(focusIdx, {
7189
7013
  attributes: { ...element.attributes, "background-size": value }
7190
7014
  });
7191
7015
  }, [focusIdx, element, updateElement]);
7192
- const setBackgroundRepeat = useCallback32((value) => {
7016
+ const setBackgroundRepeat = useCallback33((value) => {
7193
7017
  if (!focusIdx || !element) return;
7194
7018
  updateElement(focusIdx, {
7195
7019
  attributes: { ...element.attributes, "background-repeat": value }
7196
7020
  });
7197
7021
  }, [focusIdx, element, updateElement]);
7198
- const setWidth = useCallback32((value) => {
7022
+ const setWidth = useCallback33((value) => {
7199
7023
  if (!focusIdx || !element) return;
7200
7024
  updateElement(focusIdx, {
7201
7025
  attributes: { ...element.attributes, width: value }
7202
7026
  });
7203
7027
  }, [focusIdx, element, updateElement]);
7204
- const setHeight = useCallback32((value) => {
7028
+ const setHeight = useCallback33((value) => {
7205
7029
  if (!focusIdx || !element) return;
7206
7030
  updateElement(focusIdx, {
7207
7031
  attributes: { ...element.attributes, height: value }
@@ -7357,7 +7181,7 @@ var BgImgOptions = () => {
7357
7181
  // src/core/editor/components/image-menu.tsx
7358
7182
  import { Fragment as Fragment5, jsx as jsx55, jsxs as jsxs44 } from "react/jsx-runtime";
7359
7183
  var ImageMenu = ({ type }) => {
7360
- const [isOpen, setIsOpen] = useState18(false);
7184
+ const [isOpen, setIsOpen] = useState19(false);
7361
7185
  const { setActiveView, setImageTarget } = useSidebarContext();
7362
7186
  const { url, removeUrl } = useImage({ type });
7363
7187
  const handleSelectImage = () => {
@@ -7376,9 +7200,9 @@ var ImageMenu = ({ type }) => {
7376
7200
  Button,
7377
7201
  {
7378
7202
  variant: "outline",
7379
- className: "shadow-none transition-none cursor-pointer rounded-[12px]",
7203
+ className: "shadow-none transition-none cursor-pointer rounded-[12px] p-0.5 ",
7380
7204
  size: "icon",
7381
- children: url && !url.includes("placeholder_image.png") && url !== DEFAULT_PROPERTY_PLACEHOLDER_IMAGE ? /* @__PURE__ */ jsx55("img", { src: url, alt: "Background Image", className: "w-full h-full object-cover rounded-[12px]" }) : /* @__PURE__ */ jsx55(ImageIcon, { className: "w-4 h-4" })
7205
+ children: url && !url.includes("placeholder_image.png") && url !== DEFAULT_PROPERTY_PLACEHOLDER_IMAGE ? /* @__PURE__ */ jsx55("img", { src: url, alt: "Background Image", className: "w-full h-full object-cover rounded-[8px]" }) : /* @__PURE__ */ jsx55(ImageIcon, { className: "w-4 h-4" })
7382
7206
  }
7383
7207
  ) }) }),
7384
7208
  /* @__PURE__ */ jsxs44(PopoverContent, { className: "w-64 z-51 mt-1 rounded-[12px] p-3", children: [
@@ -7418,12 +7242,12 @@ var SectionToolbar = () => {
7418
7242
  deleteElement(focusIdx);
7419
7243
  }
7420
7244
  };
7421
- const handleOpenBgColorPicker = useCallback33(() => {
7245
+ const handleOpenBgColorPicker = useCallback34(() => {
7422
7246
  setColorType("Background Color");
7423
7247
  setColorTarget("sectionBgColor");
7424
7248
  setActiveView("color");
7425
7249
  }, [setColorType, setColorTarget, setActiveView]);
7426
- const handleOpenStrokeColorPicker = useCallback33(() => {
7250
+ const handleOpenStrokeColorPicker = useCallback34(() => {
7427
7251
  setColorType("Stroke Color");
7428
7252
  setColorTarget("strokeColor");
7429
7253
  setActiveView("color");
@@ -7486,7 +7310,7 @@ var SectionToolbar = () => {
7486
7310
  };
7487
7311
 
7488
7312
  // src/core/editor/components/element-gear/section-column/toolbar.tsx
7489
- import { useCallback as useCallback34, useMemo as useMemo22, useState as useState19 } from "react";
7313
+ import { useCallback as useCallback35, useMemo as useMemo22, useState as useState20 } from "react";
7490
7314
  import { CheckIcon as CheckIcon6, Columns2Icon, Columns3Icon, Columns4Icon } from "lucide-react";
7491
7315
  import { get as lodashGet10 } from "lodash";
7492
7316
  import { jsx as jsx57, jsxs as jsxs46 } from "react/jsx-runtime";
@@ -7494,8 +7318,8 @@ var VERTICAL_ALIGNMENTS = ["top", "middle", "bottom"];
7494
7318
  var SectionColumnToolbar = () => {
7495
7319
  const { focusIdx, deleteElement, template, setColumnCount, updateElement } = useEditorStore();
7496
7320
  const { activeView, colorTarget, setActiveView, setColorType, setColorTarget } = useSidebarContext();
7497
- const [columnCountOpen, setColumnCountOpen] = useState19(false);
7498
- const [verticalAlignOpen, setVerticalAlignOpen] = useState19(false);
7321
+ const [columnCountOpen, setColumnCountOpen] = useState20(false);
7322
+ const [verticalAlignOpen, setVerticalAlignOpen] = useState20(false);
7499
7323
  const element = useMemo22(() => {
7500
7324
  if (!focusIdx || !template) return null;
7501
7325
  const path = focusIdx.startsWith("content.") ? focusIdx.replace("content.", "content[0].").replace(/\.\[(\d+)\]/g, "[$1]") : focusIdx;
@@ -7515,17 +7339,17 @@ var SectionColumnToolbar = () => {
7515
7339
  deleteElement(focusIdx);
7516
7340
  }
7517
7341
  };
7518
- const handleOpenBgColorPicker = useCallback34(() => {
7342
+ const handleOpenBgColorPicker = useCallback35(() => {
7519
7343
  setColorType("Background Color");
7520
7344
  setColorTarget("sectionBgColor");
7521
7345
  setActiveView("color");
7522
7346
  }, [setColorType, setColorTarget, setActiveView]);
7523
- const handleOpenStrokeColorPicker = useCallback34(() => {
7347
+ const handleOpenStrokeColorPicker = useCallback35(() => {
7524
7348
  setColorType("Stroke Color");
7525
7349
  setColorTarget("strokeColor");
7526
7350
  setActiveView("color");
7527
7351
  }, [setColorType, setColorTarget, setActiveView]);
7528
- const handleVerticalAlignChange = useCallback34((align) => {
7352
+ const handleVerticalAlignChange = useCallback35((align) => {
7529
7353
  if (!focusIdx || !element?.children) return;
7530
7354
  const updatedChildren = element.children.map((child) => ({
7531
7355
  ...child,
@@ -7640,7 +7464,7 @@ var SectionColumnToolbar = () => {
7640
7464
  };
7641
7465
 
7642
7466
  // src/core/editor/components/element-gear/page/toolbar.tsx
7643
- import { useCallback as useCallback35, useMemo as useMemo23 } from "react";
7467
+ import { useCallback as useCallback36, useMemo as useMemo23 } from "react";
7644
7468
  import { jsx as jsx58, jsxs as jsxs47 } from "react/jsx-runtime";
7645
7469
  var PageToolbar = () => {
7646
7470
  const { focusIdx, template } = useEditorStore();
@@ -7650,7 +7474,7 @@ var PageToolbar = () => {
7650
7474
  const page = template.content?.[0];
7651
7475
  return page?.attributes?.["background-color"];
7652
7476
  }, [focusIdx, template]);
7653
- const handleOpenBgColorPicker = useCallback35(() => {
7477
+ const handleOpenBgColorPicker = useCallback36(() => {
7654
7478
  setColorType("Background Color");
7655
7479
  setColorTarget("sectionBgColor");
7656
7480
  setActiveView("color");
@@ -7671,10 +7495,10 @@ var PageToolbar = () => {
7671
7495
  };
7672
7496
 
7673
7497
  // src/core/editor/components/element-gear/spacer/toolbar.tsx
7674
- import { useCallback as useCallback37, useMemo as useMemo25 } from "react";
7498
+ import { useCallback as useCallback38, useMemo as useMemo25 } from "react";
7675
7499
 
7676
7500
  // src/core/editor/hooks/use-height.ts
7677
- import { useMemo as useMemo24, useCallback as useCallback36 } from "react";
7501
+ import { useMemo as useMemo24, useCallback as useCallback37 } from "react";
7678
7502
  import { get as lodashGet11 } from "lodash";
7679
7503
  var useHeight = () => {
7680
7504
  const { focusIdx, updateElement, template } = useEditorStore();
@@ -7687,7 +7511,7 @@ var useHeight = () => {
7687
7511
  const parsed = parseInt(rawValue.replace("px", ""), 10);
7688
7512
  return isNaN(parsed) ? 12 : Math.max(4, parsed);
7689
7513
  }, [focusIdx, template]);
7690
- const handleChange = useCallback36((value) => {
7514
+ const handleChange = useCallback37((value) => {
7691
7515
  if (!focusIdx || !template) return;
7692
7516
  const path = focusIdx.startsWith("content.") ? focusIdx.replace("content.", "content[0].").replace(/\.\[(\d+)\]/g, "[$1]") : focusIdx;
7693
7517
  const element = lodashGet11(template, path);
@@ -7719,7 +7543,7 @@ var SpacerToolbar = () => {
7719
7543
  const element = lodashGet12(template, path);
7720
7544
  return element?.attributes?.["container-background-color"];
7721
7545
  }, [focusIdx, template]);
7722
- const handleOpenBgColorPicker = useCallback37(() => {
7546
+ const handleOpenBgColorPicker = useCallback38(() => {
7723
7547
  setColorType("Background Color");
7724
7548
  setColorTarget("spacerBgColor");
7725
7549
  setActiveView("color");
@@ -7743,14 +7567,14 @@ var SpacerToolbar = () => {
7743
7567
 
7744
7568
  // src/core/editor/components/element-gear/social/toolbar.tsx
7745
7569
  import { AlignCenterIcon, AlignLeftIcon, AlignRightIcon, BoldIcon as BoldIcon3, CaseUpperIcon as CaseUpperIcon3, CheckIcon as CheckIcon7, ItalicIcon as ItalicIcon3, Scan, Strikethrough as Strikethrough3, Underline as Underline3 } from "lucide-react";
7746
- import { useCallback as useCallback39, useMemo as useMemo27 } from "react";
7570
+ import { useCallback as useCallback40, useMemo as useMemo27 } from "react";
7747
7571
 
7748
7572
  // src/core/editor/components/social-line-spacing.tsx
7749
7573
  import { TypeIcon as TypeIcon3 } from "lucide-react";
7750
- import { useState as useState20, useEffect as useEffect12, useMemo as useMemo26, useCallback as useCallback38, memo as memo5 } from "react";
7574
+ import { useState as useState21, useMemo as useMemo26, useCallback as useCallback39, memo as memo5 } from "react";
7751
7575
  import { jsx as jsx60, jsxs as jsxs49 } from "react/jsx-runtime";
7752
7576
  var SocialLineSpacing = memo5(function SocialLineSpacing2() {
7753
- const [isOpen, setIsOpen] = useState20(false);
7577
+ const [isOpen, setIsOpen] = useState21(false);
7754
7578
  const focusIdx = useEditorStore((s) => s.focusIdx);
7755
7579
  const template = useEditorStore((s) => s.template);
7756
7580
  const updateElement = useEditorStore((s) => s.updateElement);
@@ -7762,60 +7586,23 @@ var SocialLineSpacing = memo5(function SocialLineSpacing2() {
7762
7586
  const parsed = parseFloat(socialElement.attributes["line-height"]);
7763
7587
  return isNaN(parsed) ? DEFAULT_LINE_HEIGHT : parsed;
7764
7588
  }, [socialElement]);
7765
- const [lineHeightInputValue, setLineHeightInputValue] = useState20(
7766
- String(currentLineHeight)
7767
- );
7768
- const [isLineHeightInputFocused, setIsLineHeightInputFocused] = useState20(false);
7769
- useEffect12(() => {
7770
- if (!isLineHeightInputFocused) {
7771
- setLineHeightInputValue(String(currentLineHeight));
7772
- }
7773
- }, [currentLineHeight, isLineHeightInputFocused]);
7774
- const handleLineHeightSliderChange = useCallback38((values) => {
7589
+ const commitLineHeight = useCallback39((value) => {
7775
7590
  if (!focusIdx) return;
7776
- const value = values[0];
7777
- setLineHeightInputValue(String(value));
7778
7591
  const currentTemplate = useEditorStore.getState().template;
7779
7592
  const element = getValueByIdx(currentTemplate, focusIdx);
7780
7593
  updateElement(focusIdx, {
7781
- attributes: {
7782
- ...element?.attributes,
7783
- "line-height": String(value)
7784
- }
7594
+ attributes: { ...element?.attributes, "line-height": String(value) }
7785
7595
  });
7786
7596
  }, [focusIdx, updateElement]);
7787
- const handleLineHeightInputChange = useCallback38((e) => {
7788
- setLineHeightInputValue(e.target.value);
7789
- }, []);
7790
- const applyLineHeight = useCallback38(() => {
7791
- if (!focusIdx) return;
7792
- const parsed = parseFloat(lineHeightInputValue);
7793
- if (isNaN(parsed) || lineHeightInputValue === "") {
7794
- setLineHeightInputValue(String(currentLineHeight));
7795
- return;
7796
- }
7797
- const clampedValue = Math.max(MIN_LINE_HEIGHT, Math.min(parsed, MAX_LINE_HEIGHT));
7798
- setLineHeightInputValue(String(clampedValue));
7799
- const currentTemplate = useEditorStore.getState().template;
7800
- const element = getValueByIdx(currentTemplate, focusIdx);
7801
- updateElement(focusIdx, {
7802
- attributes: {
7803
- ...element?.attributes,
7804
- "line-height": String(clampedValue)
7805
- }
7806
- });
7807
- }, [focusIdx, lineHeightInputValue, currentLineHeight, updateElement]);
7808
- const handleLineHeightInputBlur = useCallback38(() => {
7809
- setIsLineHeightInputFocused(false);
7810
- applyLineHeight();
7811
- }, [applyLineHeight]);
7812
- const handleLineHeightInputKeyDown = useCallback38((e) => {
7813
- if (e.key === "Enter") {
7814
- e.preventDefault();
7815
- applyLineHeight();
7816
- e.target.blur();
7817
- }
7818
- }, [applyLineHeight]);
7597
+ const lineHeightInput = useEditableFloat({
7598
+ value: currentLineHeight,
7599
+ onChange: commitLineHeight,
7600
+ min: MIN_LINE_HEIGHT,
7601
+ max: MAX_LINE_HEIGHT
7602
+ });
7603
+ const handleLineHeightSliderChange = useCallback39((values) => {
7604
+ commitLineHeight(values[0]);
7605
+ }, [commitLineHeight]);
7819
7606
  return /* @__PURE__ */ jsxs49(Tooltip, { children: [
7820
7607
  /* @__PURE__ */ jsxs49(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
7821
7608
  /* @__PURE__ */ jsx60(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx60(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx60(
@@ -7851,11 +7638,11 @@ var SocialLineSpacing = memo5(function SocialLineSpacing2() {
7851
7638
  Input,
7852
7639
  {
7853
7640
  type: "number",
7854
- value: lineHeightInputValue,
7855
- onChange: handleLineHeightInputChange,
7856
- onFocus: () => setIsLineHeightInputFocused(true),
7857
- onBlur: handleLineHeightInputBlur,
7858
- onKeyDown: handleLineHeightInputKeyDown,
7641
+ value: lineHeightInput.displayValue,
7642
+ onChange: (e) => lineHeightInput.setLocalValue(e.target.value),
7643
+ onFocus: lineHeightInput.handleFocus,
7644
+ onBlur: lineHeightInput.handleBlur,
7645
+ onKeyDown: lineHeightInput.handleKeyDown,
7859
7646
  className: "w-25 shadow-none rounded-[12px]",
7860
7647
  min: MIN_LINE_HEIGHT,
7861
7648
  max: MAX_LINE_HEIGHT,
@@ -7927,12 +7714,12 @@ var SocialToolbar = () => {
7927
7714
  const firstChild = socialElement?.children?.[0];
7928
7715
  return firstChild?.attributes?.["align"] || "center";
7929
7716
  }, [socialElement]);
7930
- const handleOpenBgColorPicker = useCallback39(() => {
7717
+ const handleOpenBgColorPicker = useCallback40(() => {
7931
7718
  setColorType("Background Color");
7932
7719
  setColorTarget("socialBgColor");
7933
7720
  setActiveView("color");
7934
7721
  }, [setColorType, setColorTarget, setActiveView]);
7935
- const handleSocialStyleChange = useCallback39((value) => {
7722
+ const handleSocialStyleChange = useCallback40((value) => {
7936
7723
  if (!focusIdx) return;
7937
7724
  const currentTemplate = useEditorStore.getState().template;
7938
7725
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -7947,7 +7734,7 @@ var SocialToolbar = () => {
7947
7734
  }
7948
7735
  });
7949
7736
  }, [focusIdx, updateElement]);
7950
- const handleIconSizeChange = useCallback39((value) => {
7737
+ const handleIconSizeChange = useCallback40((value) => {
7951
7738
  if (!focusIdx) return;
7952
7739
  const currentTemplate = useEditorStore.getState().template;
7953
7740
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -7962,7 +7749,7 @@ var SocialToolbar = () => {
7962
7749
  }
7963
7750
  });
7964
7751
  }, [focusIdx, updateElement]);
7965
- const handleIconStyleChange = useCallback39((value) => {
7752
+ const handleIconStyleChange = useCallback40((value) => {
7966
7753
  if (!focusIdx) return;
7967
7754
  const currentTemplate = useEditorStore.getState().template;
7968
7755
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -7977,7 +7764,7 @@ var SocialToolbar = () => {
7977
7764
  }
7978
7765
  });
7979
7766
  }, [focusIdx, updateElement]);
7980
- const handleIconColorChange = useCallback39((value) => {
7767
+ const handleIconColorChange = useCallback40((value) => {
7981
7768
  if (!focusIdx) return;
7982
7769
  const currentTemplate = useEditorStore.getState().template;
7983
7770
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -7992,7 +7779,7 @@ var SocialToolbar = () => {
7992
7779
  }
7993
7780
  });
7994
7781
  }, [focusIdx, updateElement]);
7995
- const handleSetFontFamily = useCallback39((font) => {
7782
+ const handleSetFontFamily = useCallback40((font) => {
7996
7783
  if (!focusIdx) return;
7997
7784
  const currentTemplate = useEditorStore.getState().template;
7998
7785
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8003,7 +7790,7 @@ var SocialToolbar = () => {
8003
7790
  }
8004
7791
  });
8005
7792
  }, [focusIdx, updateElement]);
8006
- const handleFontSizeChange = useCallback39((size) => {
7793
+ const handleFontSizeChange = useCallback40((size) => {
8007
7794
  if (!focusIdx) return;
8008
7795
  const currentTemplate = useEditorStore.getState().template;
8009
7796
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8014,12 +7801,12 @@ var SocialToolbar = () => {
8014
7801
  }
8015
7802
  });
8016
7803
  }, [focusIdx, updateElement]);
8017
- const handleOpenTextColorPicker = useCallback39(() => {
7804
+ const handleOpenTextColorPicker = useCallback40(() => {
8018
7805
  setColorType("Text Color");
8019
7806
  setColorTarget("socialTextColor");
8020
7807
  setActiveView("color");
8021
7808
  }, [setColorType, setColorTarget, setActiveView]);
8022
- const handleToggleBold = useCallback39(() => {
7809
+ const handleToggleBold = useCallback40(() => {
8023
7810
  if (!focusIdx) return;
8024
7811
  const currentTemplate = useEditorStore.getState().template;
8025
7812
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8031,7 +7818,7 @@ var SocialToolbar = () => {
8031
7818
  }
8032
7819
  });
8033
7820
  }, [focusIdx, isBold, updateElement]);
8034
- const handleToggleItalic = useCallback39(() => {
7821
+ const handleToggleItalic = useCallback40(() => {
8035
7822
  if (!focusIdx) return;
8036
7823
  const currentTemplate = useEditorStore.getState().template;
8037
7824
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8043,7 +7830,7 @@ var SocialToolbar = () => {
8043
7830
  }
8044
7831
  });
8045
7832
  }, [focusIdx, isItalic, updateElement]);
8046
- const handleToggleUnderline = useCallback39(() => {
7833
+ const handleToggleUnderline = useCallback40(() => {
8047
7834
  if (!focusIdx) return;
8048
7835
  const currentTemplate = useEditorStore.getState().template;
8049
7836
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8061,7 +7848,7 @@ var SocialToolbar = () => {
8061
7848
  }
8062
7849
  });
8063
7850
  }, [focusIdx, isUnderline, updateElement]);
8064
- const handleToggleStrike = useCallback39(() => {
7851
+ const handleToggleStrike = useCallback40(() => {
8065
7852
  if (!focusIdx) return;
8066
7853
  const currentTemplate = useEditorStore.getState().template;
8067
7854
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8079,7 +7866,7 @@ var SocialToolbar = () => {
8079
7866
  }
8080
7867
  });
8081
7868
  }, [focusIdx, isStrikethrough, updateElement]);
8082
- const handleModeChange = useCallback39((mode) => {
7869
+ const handleModeChange = useCallback40((mode) => {
8083
7870
  if (!focusIdx) return;
8084
7871
  const currentTemplate = useEditorStore.getState().template;
8085
7872
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8090,7 +7877,7 @@ var SocialToolbar = () => {
8090
7877
  }
8091
7878
  });
8092
7879
  }, [focusIdx, updateElement]);
8093
- const handleCycleAlign = useCallback39(() => {
7880
+ const handleCycleAlign = useCallback40(() => {
8094
7881
  if (!focusIdx) return;
8095
7882
  const currentTemplate = useEditorStore.getState().template;
8096
7883
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8109,7 +7896,7 @@ var SocialToolbar = () => {
8109
7896
  children: updatedChildren
8110
7897
  });
8111
7898
  }, [focusIdx, currentAlign, updateElement]);
8112
- const handleCycleSocialItemAlign = useCallback39(() => {
7899
+ const handleCycleSocialItemAlign = useCallback40(() => {
8113
7900
  if (!focusIdx) return;
8114
7901
  const currentTemplate = useEditorStore.getState().template;
8115
7902
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8353,7 +8140,7 @@ var SocialToolbar = () => {
8353
8140
 
8354
8141
  // src/core/editor/components/element-gear/social-item/toolbar.tsx
8355
8142
  import { AlignCenterIcon as AlignCenterIcon2, AlignLeftIcon as AlignLeftIcon2, AlignRightIcon as AlignRightIcon2, BoldIcon as BoldIcon4, CaseUpperIcon as CaseUpperIcon4, ItalicIcon as ItalicIcon4, RemoveFormatting, Strikethrough as Strikethrough4, Underline as Underline4 } from "lucide-react";
8356
- import { useCallback as useCallback40, useMemo as useMemo28 } from "react";
8143
+ import { useCallback as useCallback41, useMemo as useMemo28 } from "react";
8357
8144
  import { Fragment as Fragment7, jsx as jsx62, jsxs as jsxs51 } from "react/jsx-runtime";
8358
8145
  var ALIGNMENTS3 = ["left", "center", "right"];
8359
8146
  var SOCIAL_ITEM_ALIGNMENT_ICONS2 = {
@@ -8395,7 +8182,7 @@ var SocialItemToolbar = () => {
8395
8182
  const currentAlign = useMemo28(() => {
8396
8183
  return socialItemElement?.attributes?.["align"] || "center";
8397
8184
  }, [socialItemElement]);
8398
- const handleSetFontFamily = useCallback40((font) => {
8185
+ const handleSetFontFamily = useCallback41((font) => {
8399
8186
  if (!focusIdx) return;
8400
8187
  const currentTemplate = useEditorStore.getState().template;
8401
8188
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8406,7 +8193,7 @@ var SocialItemToolbar = () => {
8406
8193
  }
8407
8194
  });
8408
8195
  }, [focusIdx, updateElement]);
8409
- const handleFontSizeChange = useCallback40((size) => {
8196
+ const handleFontSizeChange = useCallback41((size) => {
8410
8197
  if (!focusIdx) return;
8411
8198
  const currentTemplate = useEditorStore.getState().template;
8412
8199
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8417,12 +8204,12 @@ var SocialItemToolbar = () => {
8417
8204
  }
8418
8205
  });
8419
8206
  }, [focusIdx, updateElement]);
8420
- const handleOpenTextColorPicker = useCallback40(() => {
8207
+ const handleOpenTextColorPicker = useCallback41(() => {
8421
8208
  setColorType("Text Color");
8422
8209
  setColorTarget("socialItemTextColor");
8423
8210
  setActiveView("color");
8424
8211
  }, [setColorType, setColorTarget, setActiveView]);
8425
- const handleToggleBold = useCallback40(() => {
8212
+ const handleToggleBold = useCallback41(() => {
8426
8213
  if (!focusIdx) return;
8427
8214
  const currentTemplate = useEditorStore.getState().template;
8428
8215
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8434,7 +8221,7 @@ var SocialItemToolbar = () => {
8434
8221
  }
8435
8222
  });
8436
8223
  }, [focusIdx, isBold, updateElement]);
8437
- const handleToggleItalic = useCallback40(() => {
8224
+ const handleToggleItalic = useCallback41(() => {
8438
8225
  if (!focusIdx) return;
8439
8226
  const currentTemplate = useEditorStore.getState().template;
8440
8227
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8446,7 +8233,7 @@ var SocialItemToolbar = () => {
8446
8233
  }
8447
8234
  });
8448
8235
  }, [focusIdx, isItalic, updateElement]);
8449
- const handleToggleUnderline = useCallback40(() => {
8236
+ const handleToggleUnderline = useCallback41(() => {
8450
8237
  if (!focusIdx) return;
8451
8238
  const currentTemplate = useEditorStore.getState().template;
8452
8239
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8464,7 +8251,7 @@ var SocialItemToolbar = () => {
8464
8251
  }
8465
8252
  });
8466
8253
  }, [focusIdx, isUnderline, updateElement]);
8467
- const handleToggleStrike = useCallback40(() => {
8254
+ const handleToggleStrike = useCallback41(() => {
8468
8255
  if (!focusIdx) return;
8469
8256
  const currentTemplate = useEditorStore.getState().template;
8470
8257
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8482,7 +8269,7 @@ var SocialItemToolbar = () => {
8482
8269
  }
8483
8270
  });
8484
8271
  }, [focusIdx, isStrikethrough, updateElement]);
8485
- const handleRemoveFormatting = useCallback40(() => {
8272
+ const handleRemoveFormatting = useCallback41(() => {
8486
8273
  if (!focusIdx) return;
8487
8274
  const currentTemplate = useEditorStore.getState().template;
8488
8275
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8500,7 +8287,7 @@ var SocialItemToolbar = () => {
8500
8287
  attributes: restAttributes
8501
8288
  });
8502
8289
  }, [focusIdx, updateElement]);
8503
- const handleCycleAlign = useCallback40(() => {
8290
+ const handleCycleAlign = useCallback41(() => {
8504
8291
  if (!focusIdx) return;
8505
8292
  const currentTemplate = useEditorStore.getState().template;
8506
8293
  const element = getValueByIdx(currentTemplate, focusIdx);
@@ -8646,7 +8433,7 @@ var SocialItemToolbar = () => {
8646
8433
 
8647
8434
  // src/core/editor/components/element-gear/divider/_components/stroke-weight.tsx
8648
8435
  import { MinusIcon as MinusIcon4 } from "lucide-react";
8649
- import { useState as useState21, useEffect as useEffect13, useCallback as useCallback41 } from "react";
8436
+ import { useState as useState22, useCallback as useCallback42 } from "react";
8650
8437
  import { jsx as jsx63, jsxs as jsxs52 } from "react/jsx-runtime";
8651
8438
  var StrokeWeight2 = ({
8652
8439
  width,
@@ -8655,34 +8442,11 @@ var StrokeWeight2 = ({
8655
8442
  onStyleChange,
8656
8443
  tooltipText = "Stroke Weight"
8657
8444
  }) => {
8658
- const [isOpen, setIsOpen] = useState21(false);
8659
- const [inputValue, setInputValue] = useState21(width.toString());
8660
- useEffect13(() => {
8661
- setInputValue(width.toString());
8662
- }, [width]);
8663
- const handleSliderChange = useCallback41((values) => {
8664
- const newWidth = values[0];
8665
- setInputValue(newWidth.toString());
8666
- onWidthChange(newWidth);
8445
+ const [isOpen, setIsOpen] = useState22(false);
8446
+ const input = useEditableNumber({ value: width, onChange: onWidthChange, min: 1, max: 50 });
8447
+ const handleSliderChange = useCallback42((values) => {
8448
+ onWidthChange(values[0]);
8667
8449
  }, [onWidthChange]);
8668
- const handleInputChange = useCallback41((e) => {
8669
- setInputValue(e.target.value);
8670
- }, []);
8671
- const handleInputBlur = useCallback41(() => {
8672
- const parsed = parseInt(inputValue, 10);
8673
- if (isNaN(parsed)) {
8674
- setInputValue(width.toString());
8675
- return;
8676
- }
8677
- const clamped = Math.max(1, Math.min(50, parsed));
8678
- setInputValue(clamped.toString());
8679
- onWidthChange(clamped);
8680
- }, [inputValue, width, onWidthChange]);
8681
- const handleInputKeyDown = useCallback41((e) => {
8682
- if (e.key === "Enter") {
8683
- handleInputBlur();
8684
- }
8685
- }, [handleInputBlur]);
8686
8450
  return /* @__PURE__ */ jsxs52(Tooltip, { children: [
8687
8451
  /* @__PURE__ */ jsxs52(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
8688
8452
  /* @__PURE__ */ jsx63(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx63(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx63(
@@ -8748,10 +8512,11 @@ var StrokeWeight2 = ({
8748
8512
  Input,
8749
8513
  {
8750
8514
  type: "number",
8751
- value: inputValue,
8752
- onChange: handleInputChange,
8753
- onBlur: handleInputBlur,
8754
- onKeyDown: handleInputKeyDown,
8515
+ value: input.displayValue,
8516
+ onChange: (e) => input.setLocalValue(e.target.value),
8517
+ onFocus: input.handleFocus,
8518
+ onBlur: input.handleBlur,
8519
+ onKeyDown: input.handleKeyDown,
8755
8520
  className: "w-25 shadow-none rounded-[12px]",
8756
8521
  min: 1,
8757
8522
  max: 50
@@ -8766,7 +8531,7 @@ var StrokeWeight2 = ({
8766
8531
  };
8767
8532
 
8768
8533
  // src/core/editor/hooks/use-divider-border.ts
8769
- import { useMemo as useMemo29, useCallback as useCallback42 } from "react";
8534
+ import { useMemo as useMemo29, useCallback as useCallback43 } from "react";
8770
8535
  var useDividerBorder = () => {
8771
8536
  const { focusIdx, updateElement, template } = useEditorStore();
8772
8537
  const { element, width, style, color } = useMemo29(() => {
@@ -8787,7 +8552,7 @@ var useDividerBorder = () => {
8787
8552
  color: rawColor
8788
8553
  };
8789
8554
  }, [focusIdx, template]);
8790
- const setWidth = useCallback42((newWidth) => {
8555
+ const setWidth = useCallback43((newWidth) => {
8791
8556
  if (!focusIdx || !template || !element) return;
8792
8557
  const clampedWidth = Math.max(1, Math.min(50, newWidth));
8793
8558
  updateElement(focusIdx, {
@@ -8797,7 +8562,7 @@ var useDividerBorder = () => {
8797
8562
  }
8798
8563
  });
8799
8564
  }, [focusIdx, template, element, updateElement]);
8800
- const setStyle = useCallback42((newStyle) => {
8565
+ const setStyle = useCallback43((newStyle) => {
8801
8566
  if (!focusIdx || !template || !element) return;
8802
8567
  updateElement(focusIdx, {
8803
8568
  attributes: {
@@ -8816,7 +8581,7 @@ var useDividerBorder = () => {
8816
8581
  };
8817
8582
 
8818
8583
  // src/core/editor/hooks/use-width.ts
8819
- import { useMemo as useMemo30, useCallback as useCallback43 } from "react";
8584
+ import { useMemo as useMemo30, useCallback as useCallback44 } from "react";
8820
8585
  var useWidth = () => {
8821
8586
  const { focusIdx, updateElement, template } = useEditorStore();
8822
8587
  const currentValue = useMemo30(() => {
@@ -8827,7 +8592,7 @@ var useWidth = () => {
8827
8592
  const parsed = parseFloat(rawValue.replace("%", ""));
8828
8593
  return isNaN(parsed) ? 100 : Math.max(10, Math.min(100, parsed));
8829
8594
  }, [focusIdx, template]);
8830
- const handleChange = useCallback43((value) => {
8595
+ const handleChange = useCallback44((value) => {
8831
8596
  if (!focusIdx || !template) return;
8832
8597
  const element = getValueByIdx(template, focusIdx);
8833
8598
  if (!element) return;
@@ -8846,7 +8611,7 @@ var useWidth = () => {
8846
8611
  };
8847
8612
 
8848
8613
  // src/core/editor/components/element-gear/divider/toolbar.tsx
8849
- import { useCallback as useCallback44, useMemo as useMemo31 } from "react";
8614
+ import { useCallback as useCallback45, useMemo as useMemo31 } from "react";
8850
8615
  import lodashGet13 from "lodash/get";
8851
8616
  import { jsx as jsx64, jsxs as jsxs53 } from "react/jsx-runtime";
8852
8617
  var DIVIDER_ALIGNMENTS = ["left", "center", "right"];
@@ -8863,17 +8628,17 @@ var DividerToolbar = () => {
8863
8628
  }, [focusIdx, template]);
8864
8629
  const currentAlign = currentElement?.attributes?.align || "center";
8865
8630
  const currentBgColor = currentElement?.attributes?.["container-background-color"];
8866
- const handleOpenBgColorPicker = useCallback44(() => {
8631
+ const handleOpenBgColorPicker = useCallback45(() => {
8867
8632
  setColorType("Background Color");
8868
8633
  setColorTarget("dividerBgColor");
8869
8634
  setActiveView("color");
8870
8635
  }, [setColorType, setColorTarget, setActiveView]);
8871
- const handleOpenStrokeColorPicker = useCallback44(() => {
8636
+ const handleOpenStrokeColorPicker = useCallback45(() => {
8872
8637
  setColorType("Stroke Color");
8873
8638
  setColorTarget("dividerBorderColor");
8874
8639
  setActiveView("color");
8875
8640
  }, [setColorType, setColorTarget, setActiveView]);
8876
- const handleCycleAlign = useCallback44(() => {
8641
+ const handleCycleAlign = useCallback45(() => {
8877
8642
  if (!focusIdx || !currentElement) return;
8878
8643
  const currentIndex = DIVIDER_ALIGNMENTS.indexOf(currentAlign);
8879
8644
  const nextIndex = (currentIndex + 1) % DIVIDER_ALIGNMENTS.length;
@@ -8946,7 +8711,7 @@ var DividerToolbar = () => {
8946
8711
  };
8947
8712
 
8948
8713
  // src/core/editor/components/element-gear/image/toolbar.tsx
8949
- import { useCallback as useCallback45, useMemo as useMemo32 } from "react";
8714
+ import { useCallback as useCallback46, useMemo as useMemo32 } from "react";
8950
8715
  import { get as lodashGet14 } from "lodash";
8951
8716
  import { jsx as jsx65, jsxs as jsxs54 } from "react/jsx-runtime";
8952
8717
  var ImageToolbar = () => {
@@ -8966,17 +8731,17 @@ var ImageToolbar = () => {
8966
8731
  const border = useBorder();
8967
8732
  const borderRadius = useBorderRadius();
8968
8733
  const padding = usePadding();
8969
- const handleOpenBgColorPicker = useCallback45(() => {
8734
+ const handleOpenBgColorPicker = useCallback46(() => {
8970
8735
  setColorType("Background Color");
8971
8736
  setColorTarget("imageBgColor");
8972
8737
  setActiveView("color");
8973
8738
  }, [setColorType, setColorTarget, setActiveView]);
8974
- const handleOpenStrokeColorPicker = useCallback45(() => {
8739
+ const handleOpenStrokeColorPicker = useCallback46(() => {
8975
8740
  setColorType("Stroke Color");
8976
8741
  setColorTarget("strokeColor");
8977
8742
  setActiveView("color");
8978
8743
  }, [setColorType, setColorTarget, setActiveView]);
8979
- const handleCycleAlign = useCallback45(() => {
8744
+ const handleCycleAlign = useCallback46(() => {
8980
8745
  if (!focusIdx || !currentElement) return;
8981
8746
  const currentIndex = BUTTON_ALIGNMENTS.indexOf(currentAlign);
8982
8747
  const nextIndex = (currentIndex + 1) % BUTTON_ALIGNMENTS.length;
@@ -9059,11 +8824,11 @@ var ImageToolbar = () => {
9059
8824
  };
9060
8825
 
9061
8826
  // src/core/editor/components/element-gear/property/toolbar.tsx
9062
- import { useMemo as useMemo34, useCallback as useCallback47 } from "react";
8827
+ import { useMemo as useMemo34, useCallback as useCallback48 } from "react";
9063
8828
 
9064
8829
  // src/core/editor/components/property-edit-menu.tsx
9065
- import { ChevronDownIcon as ChevronDownIcon4, CircleCheckIcon, HouseIcon } from "lucide-react";
9066
- import { useState as useState22, useCallback as useCallback46, useMemo as useMemo33, useEffect as useEffect14 } from "react";
8830
+ import { ChevronDownIcon as ChevronDownIcon4, CircleCheckIcon, SquarePen } from "lucide-react";
8831
+ import { useState as useState23, useCallback as useCallback47, useMemo as useMemo33 } from "react";
9067
8832
 
9068
8833
  // src/components/ui/checkbox.tsx
9069
8834
  import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
@@ -9144,12 +8909,16 @@ var CARD_FEATURES = {
9144
8909
  var PropertyEditMenu = () => {
9145
8910
  const { focusIdx, template, updateElement } = useEditorStore();
9146
8911
  const { activeView, colorTarget, setActiveView, setColorType, setColorTarget } = useSidebarContext();
9147
- const [isOpen, setIsOpen] = useState22(false);
9148
- const [openSection, setOpenSection] = useState22(null);
9149
- const [openhouseEnabled, setOpenhouseEnabled] = useState22(true);
9150
- const [openhouseDate, setOpenhouseDate] = useState22(/* @__PURE__ */ new Date());
9151
- const [openhouseStartTime, setOpenhouseStartTime] = useState22("12:00");
9152
- const [openhouseEndTime, setOpenhouseEndTime] = useState22("13:00");
8912
+ const [isOpen, setIsOpen] = useState23(false);
8913
+ const [openSection, setOpenSection] = useState23(null);
8914
+ const [openhouseDate, setOpenhouseDate] = useState23(/* @__PURE__ */ new Date());
8915
+ const [openhouseStartTime, setOpenhouseStartTime] = useState23("12:00");
8916
+ const [openhouseEndTime, setOpenhouseEndTime] = useState23("13:00");
8917
+ const [addressLine1Input, setAddressLine1Input] = useState23("");
8918
+ const [addressLine2Input, setAddressLine2Input] = useState23("");
8919
+ const [cityInput, setCityInput] = useState23("");
8920
+ const [stateInput, setStateInput] = useState23("");
8921
+ const [zipInput, setZipInput] = useState23("");
9153
8922
  const propertyElement = useMemo33(() => {
9154
8923
  if (!focusIdx || !template) return null;
9155
8924
  return getValueByIdx(template, focusIdx);
@@ -9160,20 +8929,6 @@ var PropertyEditMenu = () => {
9160
8929
  const rawPrice = propertyElement?.attributes?.["price"] || "";
9161
8930
  return parsePrice(rawPrice);
9162
8931
  }, [propertyElement]);
9163
- const [priceInput, setPriceInput] = useState22(currentPrice);
9164
- useEffect14(() => {
9165
- setPriceInput(currentPrice);
9166
- }, [currentPrice]);
9167
- const handlePriceBlur = useCallback46(() => {
9168
- if (!focusIdx || !propertyElement) return;
9169
- if (priceInput === currentPrice) return;
9170
- updateElement(focusIdx, {
9171
- attributes: {
9172
- ...propertyElement.attributes,
9173
- "price": priceInput
9174
- }
9175
- });
9176
- }, [focusIdx, propertyElement, priceInput, currentPrice, updateElement]);
9177
8932
  const currentBeds = useMemo33(() => propertyElement?.attributes?.["beds"] || "", [propertyElement]);
9178
8933
  const currentBaths = useMemo33(() => propertyElement?.attributes?.["baths"] || "", [propertyElement]);
9179
8934
  const currentSqft = useMemo33(() => propertyElement?.attributes?.["sqft"] || "", [propertyElement]);
@@ -9191,200 +8946,57 @@ var PropertyEditMenu = () => {
9191
8946
  const currentAddress = useMemo33(() => propertyElement?.attributes?.["address"] || "", [propertyElement]);
9192
8947
  const currentCity = useMemo33(() => propertyElement?.attributes?.["city"] || "", [propertyElement]);
9193
8948
  const currentCountry = useMemo33(() => propertyElement?.attributes?.["country"] || "USA", [propertyElement]);
9194
- const [bedsInput, setBedsInput] = useState22(currentBeds);
9195
- const [bathsInput, setBathsInput] = useState22(currentBaths);
9196
- const [sqftInput, setSqftInput] = useState22(currentSqft);
9197
- const [descriptionInput, setDescriptionInput] = useState22(currentDescription);
9198
- const [isDescriptionEnabled, setIsDescriptionEnabled] = useState22(!!currentIsDescription);
9199
- const [brokerageInput, setBrokerageInput] = useState22(currentBrokerage);
9200
- const [isBrokerageEnabled, setIsBrokerageEnabled] = useState22(!!currentIsBrokerage);
9201
- const [statusInput, setStatusInput] = useState22(currentStatus);
9202
- const [isStatusEnabled, setIsStatusEnabled] = useState22(!!currentIsStatus);
9203
- const [isNewEnabled, setIsNewEnabled] = useState22(!!currentIsNew);
9204
- const [addressLine1Input, setAddressLine1Input] = useState22("");
9205
- const [addressLine2Input, setAddressLine2Input] = useState22("");
9206
- const [cityInput, setCityInput] = useState22("");
9207
- const [stateInput, setStateInput] = useState22("");
9208
- const [zipInput, setZipInput] = useState22("");
9209
- const [countryInput, setCountryInput] = useState22("USA");
9210
- useEffect14(() => {
9211
- setBedsInput(currentBeds);
9212
- }, [currentBeds]);
9213
- useEffect14(() => {
9214
- setBathsInput(currentBaths);
9215
- }, [currentBaths]);
9216
- useEffect14(() => {
9217
- setSqftInput(currentSqft);
9218
- }, [currentSqft]);
9219
- useEffect14(() => {
9220
- setDescriptionInput(currentDescription);
9221
- }, [currentDescription]);
9222
- useEffect14(() => {
9223
- setIsDescriptionEnabled(!!currentIsDescription);
9224
- }, [currentIsDescription]);
9225
- useEffect14(() => {
9226
- setBrokerageInput(currentBrokerage);
9227
- }, [currentBrokerage]);
9228
- useEffect14(() => {
9229
- setIsBrokerageEnabled(!!currentIsBrokerage);
9230
- }, [currentIsBrokerage]);
9231
- useEffect14(() => {
9232
- setStatusInput(currentStatus);
9233
- }, [currentStatus]);
9234
- useEffect14(() => {
9235
- setIsStatusEnabled(!!currentIsStatus);
9236
- }, [currentIsStatus]);
9237
- useEffect14(() => {
9238
- setIsNewEnabled(!!currentIsNew);
9239
- }, [currentIsNew]);
9240
- useEffect14(() => {
9241
- setOpenhouseEnabled(!!currentIsOpenHouse);
9242
- }, [currentIsOpenHouse]);
9243
- useEffect14(() => {
9244
- if (currentOpenHouseDate) {
9245
- const parsed = new Date(currentOpenHouseDate);
9246
- if (!isNaN(parsed.getTime())) {
9247
- setOpenhouseDate(parsed);
9248
- }
9249
- }
9250
- }, [currentOpenHouseDate]);
9251
- useEffect14(() => {
9252
- if (currentOpenHouseTime) {
9253
- const [start, end] = currentOpenHouseTime.split("-");
9254
- if (start) setOpenhouseStartTime(start);
9255
- if (end) setOpenhouseEndTime(end);
9256
- }
9257
- }, [currentOpenHouseTime]);
9258
- useEffect14(() => {
9259
- setAddressLine1Input(currentAddress);
9260
- setAddressLine2Input("");
9261
- }, [currentAddress]);
9262
- useEffect14(() => {
9263
- const match = currentCity.match(/^(.+),\s*(\w{2})\s*(\d{5})?$/);
9264
- if (match) {
9265
- setCityInput(match[1] || "");
9266
- setStateInput(match[2] || "");
9267
- setZipInput(match[3] || "");
9268
- } else {
9269
- setCityInput(currentCity);
9270
- setStateInput("");
9271
- setZipInput("");
9272
- }
9273
- }, [currentCity]);
9274
- useEffect14(() => {
9275
- setCountryInput(currentCountry);
9276
- }, [currentCountry]);
9277
- const handleBedsBlur = useCallback46(() => {
9278
- if (!focusIdx || !propertyElement) return;
9279
- if (bedsInput === currentBeds) return;
9280
- updateElement(focusIdx, {
9281
- attributes: {
9282
- ...propertyElement.attributes,
9283
- "beds": bedsInput
9284
- }
9285
- });
9286
- }, [focusIdx, propertyElement, bedsInput, currentBeds, updateElement]);
9287
- const handleBathsBlur = useCallback46(() => {
9288
- if (!focusIdx || !propertyElement) return;
9289
- if (bathsInput === currentBaths) return;
9290
- updateElement(focusIdx, {
9291
- attributes: {
9292
- ...propertyElement.attributes,
9293
- "baths": bathsInput
9294
- }
9295
- });
9296
- }, [focusIdx, propertyElement, bathsInput, currentBaths, updateElement]);
9297
- const handleSqftBlur = useCallback46(() => {
9298
- if (!focusIdx || !propertyElement) return;
9299
- if (sqftInput === currentSqft) return;
9300
- updateElement(focusIdx, {
9301
- attributes: {
9302
- ...propertyElement.attributes,
9303
- "sqft": sqftInput
9304
- }
9305
- });
9306
- }, [focusIdx, propertyElement, sqftInput, currentSqft, updateElement]);
9307
- const handleDescriptionBlur = useCallback46(() => {
9308
- if (!focusIdx || !propertyElement) return;
9309
- if (descriptionInput === currentDescription) return;
9310
- updateElement(focusIdx, {
9311
- attributes: {
9312
- ...propertyElement.attributes,
9313
- "description": descriptionInput
9314
- }
9315
- });
9316
- }, [focusIdx, propertyElement, descriptionInput, currentDescription, updateElement]);
9317
- const handleIsDescriptionChange = useCallback46((checked) => {
9318
- setIsDescriptionEnabled(checked);
8949
+ const commitAttribute = useCallback47((key, value) => {
9319
8950
  if (!focusIdx || !propertyElement) return;
9320
8951
  updateElement(focusIdx, {
9321
- attributes: {
9322
- ...propertyElement.attributes,
9323
- "is-description": checked ? "show" : ""
9324
- }
8952
+ attributes: { ...propertyElement.attributes, [key]: value }
9325
8953
  });
9326
8954
  }, [focusIdx, propertyElement, updateElement]);
9327
- const handleBrokerageBlur = useCallback46(() => {
9328
- if (!focusIdx || !propertyElement) return;
9329
- if (brokerageInput === currentBrokerage) return;
9330
- updateElement(focusIdx, {
9331
- attributes: {
9332
- ...propertyElement.attributes,
9333
- "brokerage": brokerageInput
9334
- }
9335
- });
9336
- }, [focusIdx, propertyElement, brokerageInput, currentBrokerage, updateElement]);
9337
- const handleIsBrokerageChange = useCallback46((checked) => {
9338
- setIsBrokerageEnabled(checked);
8955
+ const commitPrice = useCallback47((v) => commitAttribute("price", v), [commitAttribute]);
8956
+ const commitBeds = useCallback47((v) => commitAttribute("beds", v), [commitAttribute]);
8957
+ const commitBaths = useCallback47((v) => commitAttribute("baths", v), [commitAttribute]);
8958
+ const commitSqft = useCallback47((v) => commitAttribute("sqft", v), [commitAttribute]);
8959
+ const commitDescription = useCallback47((v) => commitAttribute("description", v), [commitAttribute]);
8960
+ const commitBrokerage = useCallback47((v) => commitAttribute("brokerage", v), [commitAttribute]);
8961
+ const commitStatus = useCallback47((v) => commitAttribute("status", v), [commitAttribute]);
8962
+ const priceInput = useEditableValue({ externalValue: currentPrice, onChange: commitPrice });
8963
+ const bedsInput = useEditableValue({ externalValue: currentBeds, onChange: commitBeds });
8964
+ const bathsInput = useEditableValue({ externalValue: currentBaths, onChange: commitBaths });
8965
+ const sqftInput = useEditableValue({ externalValue: currentSqft, onChange: commitSqft });
8966
+ const descriptionInput = useEditableValue({ externalValue: currentDescription, onChange: commitDescription });
8967
+ const brokerageInput = useEditableValue({ externalValue: currentBrokerage, onChange: commitBrokerage });
8968
+ const statusInput = useEditableValue({ externalValue: currentStatus, onChange: commitStatus });
8969
+ const handleIsDescriptionChange = useCallback47((checked) => {
9339
8970
  if (!focusIdx || !propertyElement) return;
9340
8971
  updateElement(focusIdx, {
9341
- attributes: {
9342
- ...propertyElement.attributes,
9343
- "is-brokerage": checked ? "show" : ""
9344
- }
8972
+ attributes: { ...propertyElement.attributes, "is-description": checked ? "show" : "" }
9345
8973
  });
9346
8974
  }, [focusIdx, propertyElement, updateElement]);
9347
- const handleStatusBlur = useCallback46(() => {
8975
+ const handleIsBrokerageChange = useCallback47((checked) => {
9348
8976
  if (!focusIdx || !propertyElement) return;
9349
- if (statusInput === currentStatus) return;
9350
8977
  updateElement(focusIdx, {
9351
- attributes: {
9352
- ...propertyElement.attributes,
9353
- "status": statusInput
9354
- }
8978
+ attributes: { ...propertyElement.attributes, "is-brokerage": checked ? "show" : "" }
9355
8979
  });
9356
- }, [focusIdx, propertyElement, statusInput, currentStatus, updateElement]);
9357
- const handleIsStatusChange = useCallback46((checked) => {
9358
- setIsStatusEnabled(checked);
8980
+ }, [focusIdx, propertyElement, updateElement]);
8981
+ const handleIsStatusChange = useCallback47((checked) => {
9359
8982
  if (!focusIdx || !propertyElement) return;
9360
8983
  updateElement(focusIdx, {
9361
- attributes: {
9362
- ...propertyElement.attributes,
9363
- "is-status": checked ? "show" : ""
9364
- }
8984
+ attributes: { ...propertyElement.attributes, "is-status": checked ? "show" : "" }
9365
8985
  });
9366
8986
  }, [focusIdx, propertyElement, updateElement]);
9367
- const handleIsNewChange = useCallback46((checked) => {
9368
- setIsNewEnabled(checked);
8987
+ const handleIsNewChange = useCallback47((checked) => {
9369
8988
  if (!focusIdx || !propertyElement) return;
9370
8989
  updateElement(focusIdx, {
9371
- attributes: {
9372
- ...propertyElement.attributes,
9373
- "is-new": checked ? "show" : ""
9374
- }
8990
+ attributes: { ...propertyElement.attributes, "is-new": checked ? "show" : "" }
9375
8991
  });
9376
8992
  }, [focusIdx, propertyElement, updateElement]);
9377
- const handleIsOpenHouseChange = useCallback46((checked) => {
9378
- setOpenhouseEnabled(checked);
8993
+ const handleIsOpenHouseChange = useCallback47((checked) => {
9379
8994
  if (!focusIdx || !propertyElement) return;
9380
8995
  updateElement(focusIdx, {
9381
- attributes: {
9382
- ...propertyElement.attributes,
9383
- "is-open-house": checked ? "show" : ""
9384
- }
8996
+ attributes: { ...propertyElement.attributes, "is-open-house": checked ? "show" : "" }
9385
8997
  });
9386
8998
  }, [focusIdx, propertyElement, updateElement]);
9387
- const handleOpenHouseDateBlur = useCallback46(() => {
8999
+ const handleOpenHouseDateBlur = useCallback47(() => {
9388
9000
  if (!focusIdx || !propertyElement) return;
9389
9001
  const newDate = openhouseDate ? openhouseDate.toISOString().split("T")[0] : "";
9390
9002
  if (newDate === currentOpenHouseDate) return;
@@ -9395,7 +9007,7 @@ var PropertyEditMenu = () => {
9395
9007
  }
9396
9008
  });
9397
9009
  }, [focusIdx, propertyElement, openhouseDate, currentOpenHouseDate, updateElement]);
9398
- const handleOpenHouseTimeBlur = useCallback46(() => {
9010
+ const handleOpenHouseTimeBlur = useCallback47(() => {
9399
9011
  if (!focusIdx || !propertyElement) return;
9400
9012
  const newTime = `${openhouseStartTime}-${openhouseEndTime}`;
9401
9013
  if (newTime === currentOpenHouseTime) return;
@@ -9406,7 +9018,7 @@ var PropertyEditMenu = () => {
9406
9018
  }
9407
9019
  });
9408
9020
  }, [focusIdx, propertyElement, openhouseStartTime, openhouseEndTime, currentOpenHouseTime, updateElement]);
9409
- const handleAddressBlur = useCallback46(() => {
9021
+ const handleAddressBlur = useCallback47(() => {
9410
9022
  if (!focusIdx || !propertyElement) return;
9411
9023
  const newAddress = addressLine2Input ? `${addressLine1Input}, ${addressLine2Input}` : addressLine1Input;
9412
9024
  if (newAddress === currentAddress) return;
@@ -9417,7 +9029,7 @@ var PropertyEditMenu = () => {
9417
9029
  }
9418
9030
  });
9419
9031
  }, [focusIdx, propertyElement, addressLine1Input, addressLine2Input, currentAddress, updateElement]);
9420
- const handleCityBlur = useCallback46(() => {
9032
+ const handleCityBlur = useCallback47(() => {
9421
9033
  if (!focusIdx || !propertyElement) return;
9422
9034
  const newCity = zipInput ? `${cityInput}, ${stateInput} ${zipInput}` : stateInput ? `${cityInput}, ${stateInput}` : cityInput;
9423
9035
  if (newCity === currentCity) return;
@@ -9428,41 +9040,68 @@ var PropertyEditMenu = () => {
9428
9040
  }
9429
9041
  });
9430
9042
  }, [focusIdx, propertyElement, cityInput, stateInput, zipInput, currentCity, updateElement]);
9431
- const handleCountryChange = useCallback46((value) => {
9432
- setCountryInput(value);
9043
+ const handleCountryChange = useCallback47((value) => {
9433
9044
  if (!focusIdx || !propertyElement) return;
9434
9045
  updateElement(focusIdx, {
9435
- attributes: {
9436
- ...propertyElement.attributes,
9437
- "country": value
9438
- }
9046
+ attributes: { ...propertyElement.attributes, "country": value }
9439
9047
  });
9440
9048
  }, [focusIdx, propertyElement, updateElement]);
9441
- const handleOpenStatusColorPicker = useCallback46(() => {
9049
+ const handleOpenStatusColorPicker = useCallback47(() => {
9442
9050
  setColorType("Status Color");
9443
9051
  setColorTarget("statusColor");
9444
9052
  setActiveView("color");
9445
9053
  }, [setColorType, setColorTarget, setActiveView]);
9446
- const handleToggle = useCallback46((section) => {
9054
+ const handleToggle = useCallback47((section) => {
9447
9055
  setOpenSection((prev) => prev === section ? null : section);
9448
9056
  }, []);
9449
- const handleTogglePrice = useCallback46(() => handleToggle("price"), [handleToggle]);
9450
- const handleToggleDetails = useCallback46(() => handleToggle("details"), [handleToggle]);
9451
- const handleToggleAddress = useCallback46(() => handleToggle("address"), [handleToggle]);
9452
- const handleToggleStatus = useCallback46(() => handleToggle("status"), [handleToggle]);
9453
- const handleToggleOpenhouse = useCallback46(() => handleToggle("openhouse"), [handleToggle]);
9454
- const handleToggleBrokerage = useCallback46(() => handleToggle("brokerage"), [handleToggle]);
9455
- const handleToggleDescription = useCallback46(() => handleToggle("description"), [handleToggle]);
9456
- const handleToggleMLS = useCallback46(() => handleToggle("mls"), [handleToggle]);
9057
+ const handleTogglePrice = useCallback47(() => handleToggle("price"), [handleToggle]);
9058
+ const handleToggleDetails = useCallback47(() => handleToggle("details"), [handleToggle]);
9059
+ const handleToggleAddress = useCallback47(() => {
9060
+ const isOpening = openSection !== "address";
9061
+ handleToggle("address");
9062
+ if (isOpening) {
9063
+ setAddressLine1Input(currentAddress);
9064
+ setAddressLine2Input("");
9065
+ const match = currentCity.match(/^(.+),\s*(\w{2})\s*(\d{5})?$/);
9066
+ if (match) {
9067
+ setCityInput(match[1] || "");
9068
+ setStateInput(match[2] || "");
9069
+ setZipInput(match[3] || "");
9070
+ } else {
9071
+ setCityInput(currentCity);
9072
+ setStateInput("");
9073
+ setZipInput("");
9074
+ }
9075
+ }
9076
+ }, [handleToggle, openSection, currentAddress, currentCity]);
9077
+ const handleToggleStatus = useCallback47(() => handleToggle("status"), [handleToggle]);
9078
+ const handleToggleOpenhouse = useCallback47(() => {
9079
+ const isOpening = openSection !== "openhouse";
9080
+ handleToggle("openhouse");
9081
+ if (isOpening) {
9082
+ if (currentOpenHouseDate) {
9083
+ const parsed = new Date(currentOpenHouseDate);
9084
+ if (!isNaN(parsed.getTime())) setOpenhouseDate(parsed);
9085
+ }
9086
+ if (currentOpenHouseTime) {
9087
+ const [start, end] = currentOpenHouseTime.split("-");
9088
+ if (start) setOpenhouseStartTime(start);
9089
+ if (end) setOpenhouseEndTime(end);
9090
+ }
9091
+ }
9092
+ }, [handleToggle, openSection, currentOpenHouseDate, currentOpenHouseTime]);
9093
+ const handleToggleBrokerage = useCallback47(() => handleToggle("brokerage"), [handleToggle]);
9094
+ const handleToggleDescription = useCallback47(() => handleToggle("description"), [handleToggle]);
9095
+ const handleToggleMLS = useCallback47(() => handleToggle("mls"), [handleToggle]);
9457
9096
  return /* @__PURE__ */ jsxs55(Tooltip, { children: [
9458
9097
  /* @__PURE__ */ jsxs55(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
9459
9098
  /* @__PURE__ */ jsx68(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx68(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx68(
9460
9099
  Button,
9461
9100
  {
9462
- variant: "outline",
9101
+ variant: "ghost",
9463
9102
  className: "shadow-none transition-none cursor-pointer rounded-[12px]",
9464
9103
  size: "icon",
9465
- children: /* @__PURE__ */ jsx68(HouseIcon, { className: "w-4 h-4" })
9104
+ children: /* @__PURE__ */ jsx68(SquarePen, { className: "w-4 h-4" })
9466
9105
  }
9467
9106
  ) }) }),
9468
9107
  /* @__PURE__ */ jsxs55(PopoverContent, { className: "w-84 z-51 mt-1 rounded-[12px] p-2 gap-2 flex flex-col z-50001", children: [
@@ -9480,9 +9119,11 @@ var PropertyEditMenu = () => {
9480
9119
  type: "number",
9481
9120
  placeholder: "Price",
9482
9121
  className: "w-full shadow-none rounded-[12px]",
9483
- value: priceInput,
9484
- onChange: (e) => setPriceInput(e.target.value),
9485
- onBlur: handlePriceBlur
9122
+ value: priceInput.displayValue,
9123
+ onChange: (e) => priceInput.setLocalValue(e.target.value),
9124
+ onFocus: priceInput.handleFocus,
9125
+ onBlur: priceInput.handleBlur,
9126
+ onKeyDown: priceInput.handleKeyDown
9486
9127
  }
9487
9128
  ) }) })
9488
9129
  ] }),
@@ -9501,9 +9142,11 @@ var PropertyEditMenu = () => {
9501
9142
  type: "number",
9502
9143
  placeholder: "Bd",
9503
9144
  className: "w-1/3 shadow-none rounded-[12px]",
9504
- value: bedsInput,
9505
- onChange: (e) => setBedsInput(e.target.value),
9506
- onBlur: handleBedsBlur
9145
+ value: bedsInput.displayValue,
9146
+ onChange: (e) => bedsInput.setLocalValue(e.target.value),
9147
+ onFocus: bedsInput.handleFocus,
9148
+ onBlur: bedsInput.handleBlur,
9149
+ onKeyDown: bedsInput.handleKeyDown
9507
9150
  }
9508
9151
  ),
9509
9152
  /* @__PURE__ */ jsx68(
@@ -9512,9 +9155,11 @@ var PropertyEditMenu = () => {
9512
9155
  type: "number",
9513
9156
  placeholder: "Ba",
9514
9157
  className: "w-1/3 shadow-none rounded-[12px]",
9515
- value: bathsInput,
9516
- onChange: (e) => setBathsInput(e.target.value),
9517
- onBlur: handleBathsBlur
9158
+ value: bathsInput.displayValue,
9159
+ onChange: (e) => bathsInput.setLocalValue(e.target.value),
9160
+ onFocus: bathsInput.handleFocus,
9161
+ onBlur: bathsInput.handleBlur,
9162
+ onKeyDown: bathsInput.handleKeyDown
9518
9163
  }
9519
9164
  ),
9520
9165
  /* @__PURE__ */ jsx68(
@@ -9523,9 +9168,11 @@ var PropertyEditMenu = () => {
9523
9168
  type: "number",
9524
9169
  placeholder: "Sqft",
9525
9170
  className: "w-2/4 shadow-none rounded-[12px]",
9526
- value: sqftInput,
9527
- onChange: (e) => setSqftInput(e.target.value),
9528
- onBlur: handleSqftBlur
9171
+ value: sqftInput.displayValue,
9172
+ onChange: (e) => sqftInput.setLocalValue(e.target.value),
9173
+ onFocus: sqftInput.handleFocus,
9174
+ onBlur: sqftInput.handleBlur,
9175
+ onKeyDown: sqftInput.handleKeyDown
9529
9176
  }
9530
9177
  )
9531
9178
  ] }) })
@@ -9586,7 +9233,7 @@ var PropertyEditMenu = () => {
9586
9233
  )
9587
9234
  ] }),
9588
9235
  /* @__PURE__ */ jsxs55("div", { className: "flex flex-row items-start justify-start gap-2", children: [
9589
- /* @__PURE__ */ jsxs55(Select, { value: countryInput, onValueChange: handleCountryChange, children: [
9236
+ /* @__PURE__ */ jsxs55(Select, { value: currentCountry, onValueChange: handleCountryChange, children: [
9590
9237
  /* @__PURE__ */ jsx68(SelectTrigger, { className: "w-3/4 shadow-none rounded-[12px]", children: /* @__PURE__ */ jsx68(SelectValue, { placeholder: "Country" }) }),
9591
9238
  /* @__PURE__ */ jsx68(SelectContent, { className: "w-full shadow-none rounded-[12px] z-50001", children: /* @__PURE__ */ jsx68(SelectItem, { value: "USA", children: "United States" }) })
9592
9239
  ] }),
@@ -9616,11 +9263,11 @@ var PropertyEditMenu = () => {
9616
9263
  Checkbox,
9617
9264
  {
9618
9265
  className: " shadow-none rounded-[12px] w-9 h-9",
9619
- checked: isStatusEnabled,
9266
+ checked: !!currentIsStatus,
9620
9267
  onCheckedChange: (checked) => handleIsStatusChange(checked === "indeterminate" ? false : checked)
9621
9268
  }
9622
9269
  ) }),
9623
- /* @__PURE__ */ jsx68(TooltipContent, { side: "bottom", className: "z-50001", children: isStatusEnabled ? "Hide Status" : "Show Status" })
9270
+ /* @__PURE__ */ jsx68(TooltipContent, { side: "bottom", className: "z-50001", children: !!currentIsStatus ? "Hide Status" : "Show Status" })
9624
9271
  ] }),
9625
9272
  /* @__PURE__ */ jsx68(
9626
9273
  BackgroundColorBtn,
@@ -9634,13 +9281,15 @@ var PropertyEditMenu = () => {
9634
9281
  /* @__PURE__ */ jsx68(
9635
9282
  Input,
9636
9283
  {
9637
- disabled: !isStatusEnabled,
9284
+ disabled: !currentIsStatus,
9638
9285
  type: "text",
9639
9286
  placeholder: "Just Listed",
9640
9287
  className: "w-full shadow-none rounded-[12px]",
9641
- value: statusInput,
9642
- onChange: (e) => setStatusInput(e.target.value),
9643
- onBlur: handleStatusBlur
9288
+ value: statusInput.displayValue,
9289
+ onChange: (e) => statusInput.setLocalValue(e.target.value),
9290
+ onFocus: statusInput.handleFocus,
9291
+ onBlur: statusInput.handleBlur,
9292
+ onKeyDown: statusInput.handleKeyDown
9644
9293
  }
9645
9294
  )
9646
9295
  ] }),
@@ -9651,7 +9300,7 @@ var PropertyEditMenu = () => {
9651
9300
  "aria-label": "Toggle new label",
9652
9301
  size: "sm",
9653
9302
  variant: "outline",
9654
- pressed: isNewEnabled,
9303
+ pressed: !!currentIsNew,
9655
9304
  onPressedChange: handleIsNewChange,
9656
9305
  children: [
9657
9306
  /* @__PURE__ */ jsx68(CircleCheckIcon, { className: "group-aria-pressed/toggle:fill-foreground" }),
@@ -9673,16 +9322,16 @@ var PropertyEditMenu = () => {
9673
9322
  Checkbox,
9674
9323
  {
9675
9324
  className: "shadow-none rounded-[12px] w-9 h-9",
9676
- checked: openhouseEnabled,
9325
+ checked: !!currentIsOpenHouse,
9677
9326
  onCheckedChange: (checked) => handleIsOpenHouseChange(checked === "indeterminate" ? false : checked)
9678
9327
  }
9679
9328
  ) }),
9680
- /* @__PURE__ */ jsx68(TooltipContent, { side: "bottom", className: "z-50001", children: openhouseEnabled ? "Disable Open House" : "Enable Open House" })
9329
+ /* @__PURE__ */ jsx68(TooltipContent, { side: "bottom", className: "z-50001", children: !!currentIsOpenHouse ? "Disable Open House" : "Enable Open House" })
9681
9330
  ] }),
9682
9331
  /* @__PURE__ */ jsx68(
9683
9332
  Input,
9684
9333
  {
9685
- disabled: !openhouseEnabled,
9334
+ disabled: !currentIsOpenHouse,
9686
9335
  type: "date",
9687
9336
  value: openhouseDate ? openhouseDate.toISOString().split("T")[0] : "",
9688
9337
  onChange: (e) => setOpenhouseDate(e.target.value ? new Date(e.target.value) : void 0),
@@ -9695,7 +9344,7 @@ var PropertyEditMenu = () => {
9695
9344
  /* @__PURE__ */ jsx68(
9696
9345
  Input,
9697
9346
  {
9698
- disabled: !openhouseEnabled,
9347
+ disabled: !currentIsOpenHouse,
9699
9348
  type: "time",
9700
9349
  value: openhouseStartTime,
9701
9350
  onChange: (e) => setOpenhouseStartTime(e.target.value),
@@ -9706,7 +9355,7 @@ var PropertyEditMenu = () => {
9706
9355
  /* @__PURE__ */ jsx68(
9707
9356
  Input,
9708
9357
  {
9709
- disabled: !openhouseEnabled,
9358
+ disabled: !currentIsOpenHouse,
9710
9359
  type: "time",
9711
9360
  value: openhouseEndTime,
9712
9361
  onChange: (e) => setOpenhouseEndTime(e.target.value),
@@ -9729,22 +9378,24 @@ var PropertyEditMenu = () => {
9729
9378
  Checkbox,
9730
9379
  {
9731
9380
  className: "shadow-none rounded-[12px] w-9 h-9",
9732
- checked: isBrokerageEnabled,
9381
+ checked: !!currentIsBrokerage,
9733
9382
  onCheckedChange: (checked) => handleIsBrokerageChange(checked === "indeterminate" ? false : checked)
9734
9383
  }
9735
9384
  ) }),
9736
- /* @__PURE__ */ jsx68(TooltipContent, { side: "bottom", className: "z-50001", children: isBrokerageEnabled ? "Hide Brokerage" : "Show Brokerage" })
9385
+ /* @__PURE__ */ jsx68(TooltipContent, { side: "bottom", className: "z-50001", children: !!currentIsBrokerage ? "Hide Brokerage" : "Show Brokerage" })
9737
9386
  ] }),
9738
9387
  /* @__PURE__ */ jsx68(
9739
9388
  Input,
9740
9389
  {
9741
- disabled: !isBrokerageEnabled,
9390
+ disabled: !currentIsBrokerage,
9742
9391
  type: "text",
9743
9392
  placeholder: "New Era Real Estate",
9744
9393
  className: "w-full shadow-none rounded-[12px]",
9745
- value: brokerageInput,
9746
- onChange: (e) => setBrokerageInput(e.target.value),
9747
- onBlur: handleBrokerageBlur
9394
+ value: brokerageInput.displayValue,
9395
+ onChange: (e) => brokerageInput.setLocalValue(e.target.value),
9396
+ onFocus: brokerageInput.handleFocus,
9397
+ onBlur: brokerageInput.handleBlur,
9398
+ onKeyDown: brokerageInput.handleKeyDown
9748
9399
  }
9749
9400
  )
9750
9401
  ] }),
@@ -9762,33 +9413,41 @@ var PropertyEditMenu = () => {
9762
9413
  Checkbox,
9763
9414
  {
9764
9415
  className: "shadow-none rounded-[12px] w-9 h-9",
9765
- checked: isDescriptionEnabled,
9416
+ checked: !!currentIsDescription,
9766
9417
  onCheckedChange: (checked) => handleIsDescriptionChange(checked === "indeterminate" ? false : checked)
9767
9418
  }
9768
9419
  ) }),
9769
- /* @__PURE__ */ jsx68(TooltipContent, { side: "bottom", className: "z-50001", children: isDescriptionEnabled ? "Hide Description" : "Show Description" })
9420
+ /* @__PURE__ */ jsx68(TooltipContent, { side: "bottom", className: "z-50001", children: !!currentIsDescription ? "Hide Description" : "Show Description" })
9770
9421
  ] }),
9771
- /* @__PURE__ */ jsx68(
9772
- Textarea,
9773
- {
9774
- disabled: !isDescriptionEnabled,
9775
- placeholder: "Beautiful home in the heart of the New Jersey Shore",
9776
- className: "w-full shadow-none rounded-[12px] min-h-fit max-h-34",
9777
- value: descriptionInput,
9778
- onChange: (e) => setDescriptionInput(e.target.value),
9779
- onBlur: handleDescriptionBlur
9780
- }
9781
- )
9422
+ /* @__PURE__ */ jsxs55("div", { className: "flex flex-col w-full gap-1", children: [
9423
+ /* @__PURE__ */ jsx68(
9424
+ Textarea,
9425
+ {
9426
+ disabled: !currentIsDescription,
9427
+ placeholder: "Beautiful home in the heart of the New Jersey Shore",
9428
+ className: "w-full shadow-none rounded-[12px] min-h-fit max-h-34",
9429
+ maxLength: 200,
9430
+ value: descriptionInput.displayValue,
9431
+ onChange: (e) => descriptionInput.setLocalValue(e.target.value.slice(0, 200)),
9432
+ onFocus: descriptionInput.handleFocus,
9433
+ onBlur: descriptionInput.handleBlur
9434
+ }
9435
+ ),
9436
+ /* @__PURE__ */ jsxs55("p", { className: "text-xs text-muted-foreground text-right", children: [
9437
+ (descriptionInput.displayValue || "").length,
9438
+ "/200"
9439
+ ] })
9440
+ ] })
9782
9441
  ] }) })
9783
9442
  ] })
9784
9443
  ] })
9785
9444
  ] }),
9786
- /* @__PURE__ */ jsx68(TooltipContent, { side: "bottom", className: "z-50001", children: "Edit" })
9445
+ /* @__PURE__ */ jsx68(TooltipContent, { side: "bottom", className: "z-50001", children: "Information" })
9787
9446
  ] });
9788
9447
  };
9789
9448
 
9790
9449
  // src/core/editor/components/element-gear/property/toolbar.tsx
9791
- import { CaseUpperIcon as CaseUpperIcon6 } from "lucide-react";
9450
+ import { CaseUpperIcon as CaseUpperIcon5 } from "lucide-react";
9792
9451
  import { jsx as jsx69, jsxs as jsxs56 } from "react/jsx-runtime";
9793
9452
  function PropertyToolbar() {
9794
9453
  const { focusIdx, template, updateElement } = useEditorStore();
@@ -9822,22 +9481,22 @@ function PropertyToolbar() {
9822
9481
  const currentTextColor = useMemo34(() => {
9823
9482
  return propertyElement?.attributes?.["text-color"] || "#111116";
9824
9483
  }, [propertyElement]);
9825
- const handleOpenBgColorPicker = useCallback47(() => {
9484
+ const handleOpenBgColorPicker = useCallback48(() => {
9826
9485
  setColorType("Background Color");
9827
9486
  setColorTarget("propertyBgColor");
9828
9487
  setActiveView("color");
9829
9488
  }, [setColorType, setColorTarget, setActiveView]);
9830
- const handleOpenStrokeColorPicker = useCallback47(() => {
9489
+ const handleOpenStrokeColorPicker = useCallback48(() => {
9831
9490
  setColorType("Stroke Color");
9832
9491
  setColorTarget("propertyStrokeColor");
9833
9492
  setActiveView("color");
9834
9493
  }, [setColorType, setColorTarget, setActiveView]);
9835
- const handleOpenTextColorPicker = useCallback47(() => {
9494
+ const handleOpenTextColorPicker = useCallback48(() => {
9836
9495
  setColorType("Text Color");
9837
9496
  setColorTarget("propertyTextColor");
9838
9497
  setActiveView("color");
9839
9498
  }, [setColorType, setColorTarget, setActiveView]);
9840
- const handleFontChange = useCallback47((font) => {
9499
+ const handleFontChange = useCallback48((font) => {
9841
9500
  if (!focusIdx || !propertyElement) return;
9842
9501
  updateElement(focusIdx, {
9843
9502
  attributes: {
@@ -9846,7 +9505,7 @@ function PropertyToolbar() {
9846
9505
  }
9847
9506
  });
9848
9507
  }, [focusIdx, propertyElement, updateElement]);
9849
- const handleBorderWidthChange = useCallback47((width) => {
9508
+ const handleBorderWidthChange = useCallback48((width) => {
9850
9509
  if (!columnIdx || !columnElement || !focusIdx || !propertyElement) return;
9851
9510
  const newBorder = { ...border, width };
9852
9511
  const formattedBorder = formatBorder(newBorder);
@@ -9863,7 +9522,7 @@ function PropertyToolbar() {
9863
9522
  }
9864
9523
  });
9865
9524
  }, [columnIdx, columnElement, focusIdx, propertyElement, border, updateElement]);
9866
- const handleBorderEnabledChange = useCallback47((enabled) => {
9525
+ const handleBorderEnabledChange = useCallback48((enabled) => {
9867
9526
  if (!columnIdx || !columnElement || !focusIdx || !propertyElement) return;
9868
9527
  const newWidth = enabled ? border.width === 0 ? 1 : border.width : 0;
9869
9528
  const newBorder = { ...border, width: newWidth };
@@ -9881,7 +9540,7 @@ function PropertyToolbar() {
9881
9540
  }
9882
9541
  });
9883
9542
  }, [columnIdx, columnElement, focusIdx, propertyElement, border, updateElement]);
9884
- const handleBorderRadiusChange = useCallback47((value) => {
9543
+ const handleBorderRadiusChange = useCallback48((value) => {
9885
9544
  if (!columnIdx || !columnElement || !focusIdx || !propertyElement) return;
9886
9545
  const formattedRadius = formatBorderRadius(value);
9887
9546
  updateElement(columnIdx, {
@@ -9911,6 +9570,7 @@ function PropertyToolbar() {
9911
9570
  }
9912
9571
  ),
9913
9572
  /* @__PURE__ */ jsx69(ImageMenu, { type: "property" }),
9573
+ /* @__PURE__ */ jsx69(PropertyEditMenu, {}),
9914
9574
  /* @__PURE__ */ jsx69(ToolbarSeparator, {}),
9915
9575
  /* @__PURE__ */ jsx69(ToolbarContent, { children: /* @__PURE__ */ jsx69(
9916
9576
  FontFamilyDropdown,
@@ -9929,7 +9589,7 @@ function PropertyToolbar() {
9929
9589
  size: "icon",
9930
9590
  onClick: handleOpenTextColorPicker,
9931
9591
  children: [
9932
- /* @__PURE__ */ jsx69(CaseUpperIcon6, {}),
9592
+ /* @__PURE__ */ jsx69(CaseUpperIcon5, {}),
9933
9593
  /* @__PURE__ */ jsx69(
9934
9594
  "span",
9935
9595
  {
@@ -9981,24 +9641,22 @@ function PropertyToolbar() {
9981
9641
  tooltipText: "Corner Rounding",
9982
9642
  max: 18
9983
9643
  }
9984
- ),
9985
- /* @__PURE__ */ jsx69(ToolbarSeparator, {}),
9986
- /* @__PURE__ */ jsx69(PropertyEditMenu, {})
9644
+ )
9987
9645
  ] })
9988
9646
  ] });
9989
9647
  }
9990
9648
 
9991
9649
  // src/core/editor/components/element-gear/property/triple/toolbar.tsx
9992
- import { useCallback as useCallback49, useMemo as useMemo36 } from "react";
9650
+ import { useCallback as useCallback50, useMemo as useMemo36 } from "react";
9993
9651
 
9994
9652
  // src/core/editor/components/property-triple-edit-menu.tsx
9995
- import { ChevronDownIcon as ChevronDownIcon5, HouseIcon as HouseIcon2 } from "lucide-react";
9996
- import { useState as useState23, useCallback as useCallback48, useMemo as useMemo35, useEffect as useEffect15 } from "react";
9653
+ import { ChevronDownIcon as ChevronDownIcon5, SquarePen as SquarePen2 } from "lucide-react";
9654
+ import { useState as useState24, useCallback as useCallback49, useMemo as useMemo35 } from "react";
9997
9655
  import { jsx as jsx70, jsxs as jsxs57 } from "react/jsx-runtime";
9998
9656
  var PropertyTripleEditMenu = () => {
9999
9657
  const { focusIdx, template, updateElement } = useEditorStore();
10000
- const [isOpen, setIsOpen] = useState23(false);
10001
- const [openSection, setOpenSection] = useState23(null);
9658
+ const [isOpen, setIsOpen] = useState24(false);
9659
+ const [openSection, setOpenSection] = useState24(null);
10002
9660
  const propertyElement = useMemo35(() => {
10003
9661
  if (!focusIdx || !template) return null;
10004
9662
  return getValueByIdx(template, focusIdx);
@@ -10007,95 +9665,41 @@ var PropertyTripleEditMenu = () => {
10007
9665
  const rawPrice = propertyElement?.attributes?.["price"] || "";
10008
9666
  return parsePrice(rawPrice);
10009
9667
  }, [propertyElement]);
10010
- const [priceInput, setPriceInput] = useState23(currentPrice);
10011
- useEffect15(() => {
10012
- setPriceInput(currentPrice);
10013
- }, [currentPrice]);
10014
- const handlePriceBlur = useCallback48(() => {
10015
- if (!focusIdx || !propertyElement) return;
10016
- if (priceInput === currentPrice) return;
10017
- updateElement(focusIdx, {
10018
- attributes: {
10019
- ...propertyElement.attributes,
10020
- "price": priceInput
10021
- }
10022
- });
10023
- }, [focusIdx, propertyElement, priceInput, currentPrice, updateElement]);
10024
9668
  const currentBeds = useMemo35(() => propertyElement?.attributes?.["beds"] || "", [propertyElement]);
10025
9669
  const currentBaths = useMemo35(() => propertyElement?.attributes?.["baths"] || "", [propertyElement]);
10026
9670
  const currentSqft = useMemo35(() => propertyElement?.attributes?.["sqft"] || "", [propertyElement]);
10027
9671
  const currentCity = useMemo35(() => propertyElement?.attributes?.["city"] || "", [propertyElement]);
10028
- const [bedsInput, setBedsInput] = useState23(currentBeds);
10029
- const [bathsInput, setBathsInput] = useState23(currentBaths);
10030
- const [sqftInput, setSqftInput] = useState23(currentSqft);
10031
- const [cityInput, setCityInput] = useState23(currentCity);
10032
- useEffect15(() => {
10033
- setBedsInput(currentBeds);
10034
- }, [currentBeds]);
10035
- useEffect15(() => {
10036
- setBathsInput(currentBaths);
10037
- }, [currentBaths]);
10038
- useEffect15(() => {
10039
- setSqftInput(currentSqft);
10040
- }, [currentSqft]);
10041
- useEffect15(() => {
10042
- setCityInput(currentCity);
10043
- }, [currentCity]);
10044
- const handleBedsBlur = useCallback48(() => {
10045
- if (!focusIdx || !propertyElement) return;
10046
- if (bedsInput === currentBeds) return;
10047
- updateElement(focusIdx, {
10048
- attributes: {
10049
- ...propertyElement.attributes,
10050
- "beds": bedsInput
10051
- }
10052
- });
10053
- }, [focusIdx, propertyElement, bedsInput, currentBeds, updateElement]);
10054
- const handleBathsBlur = useCallback48(() => {
10055
- if (!focusIdx || !propertyElement) return;
10056
- if (bathsInput === currentBaths) return;
10057
- updateElement(focusIdx, {
10058
- attributes: {
10059
- ...propertyElement.attributes,
10060
- "baths": bathsInput
10061
- }
10062
- });
10063
- }, [focusIdx, propertyElement, bathsInput, currentBaths, updateElement]);
10064
- const handleSqftBlur = useCallback48(() => {
9672
+ const commitAttribute = useCallback49((key, value) => {
10065
9673
  if (!focusIdx || !propertyElement) return;
10066
- if (sqftInput === currentSqft) return;
10067
9674
  updateElement(focusIdx, {
10068
- attributes: {
10069
- ...propertyElement.attributes,
10070
- "sqft": sqftInput
10071
- }
9675
+ attributes: { ...propertyElement.attributes, [key]: value }
10072
9676
  });
10073
- }, [focusIdx, propertyElement, sqftInput, currentSqft, updateElement]);
10074
- const handleCityBlur = useCallback48(() => {
10075
- if (!focusIdx || !propertyElement) return;
10076
- if (cityInput === currentCity) return;
10077
- updateElement(focusIdx, {
10078
- attributes: {
10079
- ...propertyElement.attributes,
10080
- "city": cityInput
10081
- }
10082
- });
10083
- }, [focusIdx, propertyElement, cityInput, currentCity, updateElement]);
10084
- const handleToggle = useCallback48((section) => {
9677
+ }, [focusIdx, propertyElement, updateElement]);
9678
+ const commitPrice = useCallback49((v) => commitAttribute("price", v), [commitAttribute]);
9679
+ const commitBeds = useCallback49((v) => commitAttribute("beds", v), [commitAttribute]);
9680
+ const commitBaths = useCallback49((v) => commitAttribute("baths", v), [commitAttribute]);
9681
+ const commitSqft = useCallback49((v) => commitAttribute("sqft", v), [commitAttribute]);
9682
+ const commitCity = useCallback49((v) => commitAttribute("city", v), [commitAttribute]);
9683
+ const priceInput = useEditableValue({ externalValue: currentPrice, onChange: commitPrice });
9684
+ const bedsInput = useEditableValue({ externalValue: currentBeds, onChange: commitBeds });
9685
+ const bathsInput = useEditableValue({ externalValue: currentBaths, onChange: commitBaths });
9686
+ const sqftInput = useEditableValue({ externalValue: currentSqft, onChange: commitSqft });
9687
+ const cityInput = useEditableValue({ externalValue: currentCity, onChange: commitCity });
9688
+ const handleToggle = useCallback49((section) => {
10085
9689
  setOpenSection((prev) => prev === section ? null : section);
10086
9690
  }, []);
10087
- const handleTogglePrice = useCallback48(() => handleToggle("price"), [handleToggle]);
10088
- const handleToggleDetails = useCallback48(() => handleToggle("details"), [handleToggle]);
10089
- const handleToggleAddress = useCallback48(() => handleToggle("address"), [handleToggle]);
9691
+ const handleTogglePrice = useCallback49(() => handleToggle("price"), [handleToggle]);
9692
+ const handleToggleDetails = useCallback49(() => handleToggle("details"), [handleToggle]);
9693
+ const handleToggleAddress = useCallback49(() => handleToggle("address"), [handleToggle]);
10090
9694
  return /* @__PURE__ */ jsxs57(Tooltip, { children: [
10091
9695
  /* @__PURE__ */ jsxs57(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
10092
9696
  /* @__PURE__ */ jsx70(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx70(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx70(
10093
9697
  Button,
10094
9698
  {
10095
- variant: "outline",
9699
+ variant: "ghost",
10096
9700
  className: "shadow-none transition-none cursor-pointer rounded-[12px]",
10097
9701
  size: "icon",
10098
- children: /* @__PURE__ */ jsx70(HouseIcon2, { className: "w-4 h-4" })
9702
+ children: /* @__PURE__ */ jsx70(SquarePen2, { className: "w-4 h-4" })
10099
9703
  }
10100
9704
  ) }) }),
10101
9705
  /* @__PURE__ */ jsxs57(PopoverContent, { className: "w-84 z-51 mt-1 rounded-[12px] p-2 gap-2 flex flex-col z-50001", children: [
@@ -10113,9 +9717,11 @@ var PropertyTripleEditMenu = () => {
10113
9717
  type: "number",
10114
9718
  placeholder: "Price",
10115
9719
  className: "w-full shadow-none rounded-[12px]",
10116
- value: priceInput,
10117
- onChange: (e) => setPriceInput(e.target.value),
10118
- onBlur: handlePriceBlur
9720
+ value: priceInput.displayValue,
9721
+ onChange: (e) => priceInput.setLocalValue(e.target.value),
9722
+ onFocus: priceInput.handleFocus,
9723
+ onBlur: priceInput.handleBlur,
9724
+ onKeyDown: priceInput.handleKeyDown
10119
9725
  }
10120
9726
  ) }) })
10121
9727
  ] }),
@@ -10134,9 +9740,11 @@ var PropertyTripleEditMenu = () => {
10134
9740
  type: "number",
10135
9741
  placeholder: "Bd",
10136
9742
  className: "w-1/3 shadow-none rounded-[12px]",
10137
- value: bedsInput,
10138
- onChange: (e) => setBedsInput(e.target.value),
10139
- onBlur: handleBedsBlur
9743
+ value: bedsInput.displayValue,
9744
+ onChange: (e) => bedsInput.setLocalValue(e.target.value),
9745
+ onFocus: bedsInput.handleFocus,
9746
+ onBlur: bedsInput.handleBlur,
9747
+ onKeyDown: bedsInput.handleKeyDown
10140
9748
  }
10141
9749
  ),
10142
9750
  /* @__PURE__ */ jsx70(
@@ -10145,9 +9753,11 @@ var PropertyTripleEditMenu = () => {
10145
9753
  type: "number",
10146
9754
  placeholder: "Ba",
10147
9755
  className: "w-1/3 shadow-none rounded-[12px]",
10148
- value: bathsInput,
10149
- onChange: (e) => setBathsInput(e.target.value),
10150
- onBlur: handleBathsBlur
9756
+ value: bathsInput.displayValue,
9757
+ onChange: (e) => bathsInput.setLocalValue(e.target.value),
9758
+ onFocus: bathsInput.handleFocus,
9759
+ onBlur: bathsInput.handleBlur,
9760
+ onKeyDown: bathsInput.handleKeyDown
10151
9761
  }
10152
9762
  ),
10153
9763
  /* @__PURE__ */ jsx70(
@@ -10156,9 +9766,11 @@ var PropertyTripleEditMenu = () => {
10156
9766
  type: "number",
10157
9767
  placeholder: "Sqft",
10158
9768
  className: "w-2/4 shadow-none rounded-[12px]",
10159
- value: sqftInput,
10160
- onChange: (e) => setSqftInput(e.target.value),
10161
- onBlur: handleSqftBlur
9769
+ value: sqftInput.displayValue,
9770
+ onChange: (e) => sqftInput.setLocalValue(e.target.value),
9771
+ onFocus: sqftInput.handleFocus,
9772
+ onBlur: sqftInput.handleBlur,
9773
+ onKeyDown: sqftInput.handleKeyDown
10162
9774
  }
10163
9775
  )
10164
9776
  ] }) })
@@ -10177,20 +9789,22 @@ var PropertyTripleEditMenu = () => {
10177
9789
  type: "text",
10178
9790
  placeholder: "Egg Harbor City",
10179
9791
  className: "w-full shadow-none rounded-[12px]",
10180
- value: cityInput,
10181
- onChange: (e) => setCityInput(e.target.value),
10182
- onBlur: handleCityBlur
9792
+ value: cityInput.displayValue,
9793
+ onChange: (e) => cityInput.setLocalValue(e.target.value),
9794
+ onFocus: cityInput.handleFocus,
9795
+ onBlur: cityInput.handleBlur,
9796
+ onKeyDown: cityInput.handleKeyDown
10183
9797
  }
10184
9798
  ) }) })
10185
9799
  ] })
10186
9800
  ] })
10187
9801
  ] }),
10188
- /* @__PURE__ */ jsx70(TooltipContent, { side: "bottom", className: "z-50001", children: "Edit" })
9802
+ /* @__PURE__ */ jsx70(TooltipContent, { side: "bottom", className: "z-50001", children: "Information" })
10189
9803
  ] });
10190
9804
  };
10191
9805
 
10192
9806
  // src/core/editor/components/element-gear/property/triple/toolbar.tsx
10193
- import { CaseUpperIcon as CaseUpperIcon7 } from "lucide-react";
9807
+ import { CaseUpperIcon as CaseUpperIcon6 } from "lucide-react";
10194
9808
  import { jsx as jsx71, jsxs as jsxs58 } from "react/jsx-runtime";
10195
9809
  var PropertyTripleItemToolbar = () => {
10196
9810
  const focusIdx = useEditorStore((state) => state.focusIdx);
@@ -10222,22 +9836,22 @@ var PropertyTripleItemToolbar = () => {
10222
9836
  const currentFontFamily = useMemo36(() => {
10223
9837
  return parentElement?.attributes?.["font-family"] || "Arial, sans-serif";
10224
9838
  }, [parentElement]);
10225
- const handleOpenBgColorPicker = useCallback49(() => {
9839
+ const handleOpenBgColorPicker = useCallback50(() => {
10226
9840
  setColorType("Background Color");
10227
9841
  setColorTarget("propertyBgColor");
10228
9842
  setActiveView("color");
10229
9843
  }, [setColorType, setColorTarget, setActiveView]);
10230
- const handleOpenStrokeColorPicker = useCallback49(() => {
9844
+ const handleOpenStrokeColorPicker = useCallback50(() => {
10231
9845
  setColorType("Stroke Color");
10232
9846
  setColorTarget("propertyStrokeColor");
10233
9847
  setActiveView("color");
10234
9848
  }, [setColorType, setColorTarget, setActiveView]);
10235
- const handleOpenTextColorPicker = useCallback49(() => {
9849
+ const handleOpenTextColorPicker = useCallback50(() => {
10236
9850
  setColorType("Text Color");
10237
9851
  setColorTarget("propertyTextColor");
10238
9852
  setActiveView("color");
10239
9853
  }, [setColorType, setColorTarget, setActiveView]);
10240
- const handleFontChange = useCallback49((font) => {
9854
+ const handleFontChange = useCallback50((font) => {
10241
9855
  if (!parentIdx || !parentElement) return;
10242
9856
  updateElement(parentIdx, {
10243
9857
  attributes: {
@@ -10246,7 +9860,7 @@ var PropertyTripleItemToolbar = () => {
10246
9860
  }
10247
9861
  });
10248
9862
  }, [parentIdx, parentElement, updateElement]);
10249
- const handleBorderWidthChange = useCallback49((width) => {
9863
+ const handleBorderWidthChange = useCallback50((width) => {
10250
9864
  if (!parentIdx || !parentElement) return;
10251
9865
  const newBorder = { ...border, width };
10252
9866
  const formattedBorder = formatBorder(newBorder);
@@ -10257,7 +9871,7 @@ var PropertyTripleItemToolbar = () => {
10257
9871
  }
10258
9872
  });
10259
9873
  }, [parentIdx, parentElement, border, updateElement]);
10260
- const handleBorderEnabledChange = useCallback49((enabled) => {
9874
+ const handleBorderEnabledChange = useCallback50((enabled) => {
10261
9875
  if (!parentIdx || !parentElement) return;
10262
9876
  const newWidth = enabled ? border.width === 0 ? 1 : border.width : 0;
10263
9877
  const newBorder = { ...border, width: newWidth };
@@ -10269,7 +9883,7 @@ var PropertyTripleItemToolbar = () => {
10269
9883
  }
10270
9884
  });
10271
9885
  }, [parentIdx, parentElement, border, updateElement]);
10272
- const handleBorderRadiusChange = useCallback49((value) => {
9886
+ const handleBorderRadiusChange = useCallback50((value) => {
10273
9887
  if (!parentIdx || !parentElement) return;
10274
9888
  const formattedRadius = formatBorderRadius(value);
10275
9889
  updateElement(parentIdx, {
@@ -10293,6 +9907,7 @@ var PropertyTripleItemToolbar = () => {
10293
9907
  }
10294
9908
  ),
10295
9909
  /* @__PURE__ */ jsx71(ImageMenu, { type: "property" }),
9910
+ /* @__PURE__ */ jsx71(PropertyTripleEditMenu, {}),
10296
9911
  /* @__PURE__ */ jsx71(ToolbarSeparator, {}),
10297
9912
  /* @__PURE__ */ jsx71(
10298
9913
  FontFamilyDropdown,
@@ -10311,7 +9926,7 @@ var PropertyTripleItemToolbar = () => {
10311
9926
  size: "icon",
10312
9927
  onClick: handleOpenTextColorPicker,
10313
9928
  children: [
10314
- /* @__PURE__ */ jsx71(CaseUpperIcon7, {}),
9929
+ /* @__PURE__ */ jsx71(CaseUpperIcon6, {}),
10315
9930
  /* @__PURE__ */ jsx71(
10316
9931
  "span",
10317
9932
  {
@@ -10363,9 +9978,7 @@ var PropertyTripleItemToolbar = () => {
10363
9978
  tooltipText: "Corner Rounding",
10364
9979
  max: 18
10365
9980
  }
10366
- ),
10367
- /* @__PURE__ */ jsx71(ToolbarSeparator, {}),
10368
- /* @__PURE__ */ jsx71(PropertyTripleEditMenu, {})
9981
+ )
10369
9982
  ] })
10370
9983
  ] });
10371
9984
  };
@@ -10444,14 +10057,14 @@ function Skeleton({ className, ...props }) {
10444
10057
  }
10445
10058
 
10446
10059
  // src/core/editor/components/email-template-v2/template-page.tsx
10447
- import { Suspense, useState as useState24, lazy } from "react";
10060
+ import { Suspense, useState as useState25, lazy } from "react";
10448
10061
 
10449
10062
  // src/core/editor/hooks/use-auto-save.ts
10450
- import { useEffect as useEffect16, useRef as useRef7 } from "react";
10063
+ import { useEffect as useEffect8, useRef as useRef7 } from "react";
10451
10064
  var AUTO_SAVE_INTERVAL = 30 * 1e3;
10452
10065
  function useAutoSave() {
10453
10066
  const intervalRef = useRef7(null);
10454
- useEffect16(() => {
10067
+ useEffect8(() => {
10455
10068
  intervalRef.current = setInterval(async () => {
10456
10069
  const { template, templateId, onSave, hasUnsavedChanges, markAsSaved, isSaving, setIsSaving } = useEditorStore.getState();
10457
10070
  if (isSaving || !templateId || !onSave || !hasUnsavedChanges()) {
@@ -10479,7 +10092,7 @@ function useAutoSave() {
10479
10092
  // src/core/editor/components/email-template-v2/template-page.tsx
10480
10093
  import "react-json-view-lite/dist/index.css";
10481
10094
  import { jsx as jsx74, jsxs as jsxs59 } from "react/jsx-runtime";
10482
- var Editor2 = lazy(() => import("./core-AMEHYBIM.mjs").then((module) => ({
10095
+ var Editor2 = lazy(() => import("./core-P3XCQRWR.mjs").then((module) => ({
10483
10096
  default: module.Editor
10484
10097
  })));
10485
10098
  function TemplatePage({
@@ -10489,14 +10102,16 @@ function TemplatePage({
10489
10102
  onToast,
10490
10103
  onExit,
10491
10104
  onImageUpload,
10105
+ onDuplicate,
10106
+ onDelete,
10492
10107
  data
10493
10108
  }) {
10494
- useState24(() => {
10495
- useEditorStore.getState().initializeWithTemplate(templateId, initialTemplate, onSave, onToast, data, onExit, onImageUpload);
10109
+ useState25(() => {
10110
+ useEditorStore.getState().initializeWithTemplate(templateId, initialTemplate, onSave, onToast, data, onExit, onImageUpload, onDuplicate, onDelete);
10496
10111
  });
10497
10112
  useAutoSave();
10498
- const [editorLoading, setEditorLoading] = useState24(false);
10499
- const [isPageHovered, setIsPageHovered] = useState24(false);
10113
+ const [editorLoading, setEditorLoading] = useState25(false);
10114
+ const [isPageHovered, setIsPageHovered] = useState25(false);
10500
10115
  const previewMode = useEditorStore((state) => state.previewMode);
10501
10116
  const focusIdx = useEditorStore((state) => state.focusIdx);
10502
10117
  const setFocusIdx = useEditorStore((state) => state.setFocusIdx);