@pixerate/editor-react 0.11.0 → 0.12.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.cjs CHANGED
@@ -31,25 +31,40 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  BubbleMenu: () => BubbleMenu,
34
- DirtyTracker: () => import_editor7.DirtyTracker,
34
+ CommentButton: () => CommentButton,
35
+ CommentsPanel: () => CommentsPanel,
36
+ DirtyTracker: () => import_editor15.DirtyTracker,
35
37
  EditorContent: () => EditorContent,
36
38
  EditorSlotsProvider: () => EditorSlotsProvider,
37
- HistoryManager: () => import_editor7.HistoryManager,
39
+ FormulaHints: () => FormulaHints,
40
+ HistoryManager: () => import_editor15.HistoryManager,
38
41
  ImageEditor: () => ImageEditor,
42
+ OutlinePanel: () => OutlinePanel,
43
+ ReviewToolbar: () => ReviewToolbar,
44
+ SpreadsheetContextMenu: () => SpreadsheetContextMenu,
39
45
  SpreadsheetEditor: () => SpreadsheetEditor,
46
+ SpreadsheetGroupRow: () => SpreadsheetGroupRow,
40
47
  TemplateRenderer: () => TemplateRenderer,
41
- createDirtyTracker: () => import_editor7.createDirtyTracker,
42
- createHistoryManager: () => import_editor7.createHistoryManager,
43
- defaultIsEqual: () => import_editor7.defaultIsEqual,
48
+ VariableForm: () => VariableForm,
49
+ createDirtyTracker: () => import_editor15.createDirtyTracker,
50
+ createHistoryManager: () => import_editor15.createHistoryManager,
51
+ defaultIsEqual: () => import_editor15.defaultIsEqual,
52
+ useAgentToolProvider: () => useAgentToolProvider,
53
+ useComments: () => useComments,
44
54
  useDismissGuard: () => useDismissGuard,
45
55
  useEditor: () => useEditor2,
46
56
  useEditorSlots: () => useEditorSlots,
57
+ useFileImport: () => useFileImport,
58
+ useFillHandle: () => useFillHandle,
47
59
  useHistory: () => useHistory,
48
60
  useHistoryShortcuts: () => useHistoryShortcuts,
49
61
  useImageEditor: () => useImageEditor,
50
62
  useNavigationGuard: () => useNavigationGuard,
63
+ useOutline: () => useOutline,
51
64
  usePromptEditor: () => usePromptEditor,
52
- useSpreadsheetEditor: () => useSpreadsheetEditor
65
+ useSpreadsheetClipboard: () => useSpreadsheetClipboard,
66
+ useSpreadsheetEditor: () => useSpreadsheetEditor,
67
+ useTrackChanges: () => useTrackChanges
53
68
  });
54
69
  module.exports = __toCommonJS(src_exports);
55
70
 
@@ -83,8 +98,12 @@ function usePromptEditor({
83
98
  onMilestone,
84
99
  containerId = "editor-container",
85
100
  jsonVariables,
86
- speed = 2
101
+ speed = 2,
102
+ fileImport
87
103
  }) {
104
+ const fileImportRef = (0, import_react.useRef)(fileImport);
105
+ fileImportRef.current = fileImport;
106
+ const fileImportEnabled = !!fileImport;
88
107
  const slashCommandActiveRef = (0, import_react.useRef)(slashCommandActive);
89
108
  slashCommandActiveRef.current = slashCommandActive;
90
109
  const clearSlashCommandRef = (0, import_react.useRef)(clearSlashCommand);
@@ -139,7 +158,14 @@ function usePromptEditor({
139
158
  import_editor.TemplateSuggestions.configure({
140
159
  templates
141
160
  }),
142
- import_editor.LoadingNode
161
+ import_editor.LoadingNode,
162
+ ...fileImportEnabled ? [
163
+ import_editor.FileImport.configure({
164
+ ...typeof fileImportRef.current === "object" ? fileImportRef.current : {},
165
+ // Prompt editors only ever receive plain text.
166
+ asPlainText: true
167
+ })
168
+ ] : []
143
169
  ],
144
170
  content: (0, import_editor.plainTextToTipTapHtml)(content),
145
171
  onUpdate: ({ editor: ed }) => {
@@ -236,7 +262,7 @@ function usePromptEditor({
236
262
  },
237
263
  // Only options baked into extensions recreate the editor; editable state,
238
264
  // placeholder, class names and content are applied to the live instance.
239
- [resolvedColorMap, templateKey, speed, jsonVariablesKey]
265
+ [resolvedColorMap, templateKey, speed, jsonVariablesKey, fileImportEnabled]
240
266
  );
241
267
  (0, import_react.useEffect)(() => {
242
268
  if (editor && !editor.isDestroyed) {
@@ -284,8 +310,18 @@ function usePromptEditor({
284
310
  var import_react3 = require("@tiptap/react");
285
311
  var import_editor2 = require("@pixerate/editor");
286
312
  function useEditor2(options = {}) {
287
- const { richTextOptions, extensions = [], ...editorOptions } = options;
288
- const preset = (0, import_editor2.createRichTextPreset)(richTextOptions);
313
+ const {
314
+ richTextOptions,
315
+ fileImport,
316
+ richClipboard,
317
+ extensions = [],
318
+ ...editorOptions
319
+ } = options;
320
+ const preset = (0, import_editor2.createRichTextPreset)({
321
+ ...fileImport !== void 0 ? { fileImport } : {},
322
+ ...richClipboard !== void 0 ? { richClipboard } : {},
323
+ ...richTextOptions
324
+ });
289
325
  const combinedExtensions = [...preset, ...extensions];
290
326
  return (0, import_react3.useEditor)({
291
327
  extensions: combinedExtensions,
@@ -512,19 +548,53 @@ function useHistoryShortcuts(manager, options = {}) {
512
548
  }, [manager, enabled, target, ignoreEditableElements]);
513
549
  }
514
550
 
551
+ // src/hooks/useFileImport.ts
552
+ var import_react8 = require("react");
553
+ var import_editor4 = require("@pixerate/editor");
554
+ function useFileImport(editor, options = {}) {
555
+ const editorRef = (0, import_react8.useRef)(editor);
556
+ editorRef.current = editor;
557
+ const controller = (0, import_react8.useMemo)(
558
+ () => new import_editor4.FileImportController(() => {
559
+ const current = editorRef.current;
560
+ return current && !current.isDestroyed ? current : null;
561
+ }, options),
562
+ []
563
+ );
564
+ (0, import_react8.useEffect)(() => {
565
+ controller.setOptions(options);
566
+ });
567
+ const state = (0, import_react8.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
568
+ return {
569
+ ...state,
570
+ accept: controller.accept,
571
+ openFilePicker: controller.openFilePicker,
572
+ importFiles: controller.importFiles
573
+ };
574
+ }
575
+
576
+ // src/hooks/useAgentToolProvider.ts
577
+ var import_react9 = require("react");
578
+ function useAgentToolProvider(registry, provider) {
579
+ (0, import_react9.useEffect)(() => {
580
+ if (!registry || !provider) return;
581
+ return registry.register(provider);
582
+ }, [registry, provider]);
583
+ }
584
+
515
585
  // src/components/EditorContent.tsx
516
- var import_react8 = require("@tiptap/react");
586
+ var import_react10 = require("@tiptap/react");
517
587
  var import_jsx_runtime = require("react/jsx-runtime");
518
588
  var EditorContent = ({
519
589
  className,
520
590
  editor,
521
591
  ...props
522
592
  }) => {
523
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react8.EditorContent, { editor, ...props }) });
593
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react10.EditorContent, { editor, ...props }) });
524
594
  };
525
595
 
526
596
  // src/components/BubbleMenu.tsx
527
- var import_react9 = require("react");
597
+ var import_react11 = require("react");
528
598
  var import_react_dom = require("react-dom");
529
599
  var import_extension_bubble_menu = require("@tiptap/extension-bubble-menu");
530
600
  var BubbleMenu = ({
@@ -536,12 +606,12 @@ var BubbleMenu = ({
536
606
  pluginKey = "bubbleMenu",
537
607
  updateDelay
538
608
  }) => {
539
- const menuEl = (0, import_react9.useRef)(null);
540
- const [mounted, setMounted] = (0, import_react9.useState)(false);
609
+ const menuEl = (0, import_react11.useRef)(null);
610
+ const [mounted, setMounted] = (0, import_react11.useState)(false);
541
611
  if (!menuEl.current && typeof document !== "undefined") {
542
612
  menuEl.current = document.createElement("div");
543
613
  }
544
- (0, import_react9.useEffect)(() => {
614
+ (0, import_react11.useEffect)(() => {
545
615
  if (!editor || !menuEl.current || editor.isDestroyed) {
546
616
  return;
547
617
  }
@@ -572,25 +642,28 @@ var BubbleMenu = ({
572
642
  };
573
643
 
574
644
  // src/components/TemplateRenderer.tsx
575
- var import_react10 = require("react");
576
- var import_editor4 = require("@pixerate/editor");
645
+ var import_react12 = require("react");
646
+ var import_editor5 = require("@pixerate/editor");
577
647
  var import_jsx_runtime2 = require("react/jsx-runtime");
648
+ var CONDITIONAL_PREFIX = { if: "?", unless: "!", end: "/" };
578
649
  var TemplateRenderer = ({
579
650
  content,
580
651
  templates = [],
581
652
  templateColorMap,
582
653
  resolve = false,
654
+ bindings,
655
+ values,
583
656
  className = "font-mono text-sm leading-relaxed whitespace-pre-wrap break-words",
584
657
  onTemplateClick,
585
658
  onVariableClick
586
659
  }) => {
587
- const displayText = (0, import_react10.useMemo)(() => {
660
+ const displayText = (0, import_react12.useMemo)(() => {
588
661
  if (!resolve || templates.length === 0) return content;
589
- return (0, import_editor4.resolveTemplates)(content, templates);
590
- }, [content, templates, resolve]);
591
- const tokens = (0, import_react10.useMemo)(() => {
592
- return (0, import_editor4.tokenizePrompt)(displayText);
593
- }, [displayText]);
662
+ return (0, import_editor5.resolveTemplates)(content, templates, { bindings });
663
+ }, [content, templates, resolve, bindings]);
664
+ const tokens = (0, import_react12.useMemo)(() => {
665
+ return (0, import_editor5.evaluatePromptTokens)(displayText, values);
666
+ }, [displayText, values]);
594
667
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className, children: tokens.map((token, index) => {
595
668
  if (token.type === "template") {
596
669
  const colors = templateColorMap?.get(token.value) || {
@@ -614,13 +687,49 @@ var TemplateRenderer = ({
614
687
  );
615
688
  }
616
689
  if (token.type === "variable") {
617
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
690
+ const details = [
691
+ `Variable: ${token.value}`,
692
+ token.description,
693
+ token.defaultValue !== void 0 ? `Default: ${token.defaultValue || "(empty)"}` : void 0
694
+ ].filter(Boolean).join("\n");
695
+ if (token.resolvedValue !== void 0) {
696
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
697
+ "span",
698
+ {
699
+ onClick: () => onVariableClick?.(token.value),
700
+ "data-variable": token.value,
701
+ "data-value-source": token.valueSource,
702
+ className: token.valueSource === "value" ? "inline px-1 mx-0.5 rounded-md bg-emerald-400/15 text-emerald-700 dark:text-emerald-300 border-b border-emerald-400/60 cursor-pointer" : "inline px-1 mx-0.5 rounded-md bg-violet-400/10 text-violet-600 dark:text-violet-300 italic border-b border-dashed border-violet-400/60 cursor-pointer",
703
+ title: details,
704
+ children: token.resolvedValue
705
+ },
706
+ index
707
+ );
708
+ }
709
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
618
710
  "span",
619
711
  {
620
712
  onClick: () => onVariableClick?.(token.value),
713
+ "data-variable": token.value,
621
714
  className: "inline-flex items-center px-1.5 py-0.5 mx-0.5 text-xs font-medium rounded-md border border-violet-400/40 bg-violet-400/15 text-violet-600 dark:text-violet-300 hover:brightness-110 cursor-pointer transition-all",
622
- title: `Variable: ${token.value}`,
623
- children: `{${token.value}}`
715
+ title: details,
716
+ children: [
717
+ `{${token.value}`,
718
+ token.defaultValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "opacity-60", children: `|${token.defaultValue}` }),
719
+ "}"
720
+ ]
721
+ },
722
+ index
723
+ );
724
+ }
725
+ if (token.type === "conditional" && token.conditional) {
726
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
727
+ "span",
728
+ {
729
+ "data-conditional": token.conditional,
730
+ className: "inline-flex items-center px-1 py-0.5 mx-0.5 text-xs font-medium rounded-md border border-amber-400/40 bg-amber-400/15 text-amber-700 dark:text-amber-300",
731
+ title: token.conditional === "end" ? `End of section: ${token.value}` : token.conditional === "if" ? `Shown when "${token.value}" has a value` : `Shown when "${token.value}" is empty`,
732
+ children: `{${CONDITIONAL_PREFIX[token.conditional]}${token.value}}`
624
733
  },
625
734
  index
626
735
  );
@@ -640,18 +749,152 @@ var TemplateRenderer = ({
640
749
  }) });
641
750
  };
642
751
 
643
- // src/index.ts
752
+ // src/components/VariableForm.tsx
753
+ var import_react13 = require("react");
754
+ var import_editor6 = require("@pixerate/editor");
755
+ var import_jsx_runtime3 = require("react/jsx-runtime");
756
+ var VariableForm = ({
757
+ content,
758
+ templates,
759
+ bindings,
760
+ values,
761
+ defaultValues,
762
+ onChange,
763
+ className = "flex flex-col gap-3 text-sm"
764
+ }) => {
765
+ const idPrefix = (0, import_react13.useId)();
766
+ const [internal, setInternal] = (0, import_react13.useState)(
767
+ () => defaultValues ?? {}
768
+ );
769
+ const entered = values ?? internal;
770
+ const fields = (0, import_react13.useMemo)(
771
+ () => (0, import_editor6.getVariableFormFields)(content, { templates, bindings }),
772
+ [content, templates, bindings]
773
+ );
774
+ const update = (name, value) => {
775
+ const next = { ...entered, [name]: value };
776
+ if (values === void 0) setInternal(next);
777
+ onChange?.((0, import_editor6.compactVariableValues)(next), next);
778
+ };
779
+ if (fields.length === 0) return null;
780
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("form", { className, onSubmit: (event) => event.preventDefault(), children: fields.map((field) => {
781
+ const id = `${idPrefix}-${field.name}`;
782
+ if (field.conditionOnly) {
783
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
784
+ "label",
785
+ {
786
+ htmlFor: id,
787
+ className: "flex items-center gap-2",
788
+ "data-variable-field": field.name,
789
+ children: [
790
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
791
+ "input",
792
+ {
793
+ id,
794
+ name: field.name,
795
+ type: "checkbox",
796
+ checked: (entered[field.name] ?? "") !== "",
797
+ onChange: (event) => update(field.name, event.target.checked ? "true" : "")
798
+ }
799
+ ),
800
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: field.label })
801
+ ]
802
+ },
803
+ field.name
804
+ );
805
+ }
806
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
807
+ "label",
808
+ {
809
+ htmlFor: id,
810
+ className: "flex flex-col gap-1",
811
+ "data-variable-field": field.name,
812
+ children: [
813
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "font-medium", children: [
814
+ field.label,
815
+ field.required && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-rose-500", "aria-hidden": "true", children: " *" })
816
+ ] }),
817
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
818
+ "input",
819
+ {
820
+ id,
821
+ name: field.name,
822
+ type: "text",
823
+ value: entered[field.name] ?? "",
824
+ placeholder: field.placeholder,
825
+ "aria-required": field.required || void 0,
826
+ onChange: (event) => update(field.name, event.target.value),
827
+ className: "px-2 py-1 rounded-md border border-violet-400/40 bg-transparent"
828
+ }
829
+ )
830
+ ]
831
+ },
832
+ field.name
833
+ );
834
+ }) });
835
+ };
836
+
837
+ // src/hooks/useOutline.ts
838
+ var import_react14 = require("react");
644
839
  var import_editor7 = require("@pixerate/editor");
840
+ function useOutline(editor) {
841
+ const store = (0, import_react14.useMemo)(() => (0, import_editor7.createOutlineStore)(editor), [editor]);
842
+ return (0, import_react14.useSyncExternalStore)(store.subscribe, store.getSnapshot, store.getSnapshot);
843
+ }
844
+
845
+ // src/components/OutlinePanel.tsx
846
+ var import_editor8 = require("@pixerate/editor");
847
+ var import_jsx_runtime4 = require("react/jsx-runtime");
848
+ var OutlinePanel = ({
849
+ editor,
850
+ title = "Outline",
851
+ emptyState = "Add headings to see the outline.",
852
+ maxLevel = 6,
853
+ focusOnNavigate = true,
854
+ className = "flex flex-col gap-1 text-sm",
855
+ itemClassName = "w-full truncate rounded px-2 py-1 text-left hover:bg-black/5",
856
+ activeItemClassName = "font-semibold bg-black/5",
857
+ onNavigate
858
+ }) => {
859
+ const { headings, activeId } = useOutline(editor);
860
+ const visible = headings.filter((h) => h.level <= maxLevel);
861
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("nav", { className, "aria-label": "Document outline", "data-outline-panel": "", children: [
862
+ title != null && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "pixerate-outline-title", children: title }),
863
+ visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "pixerate-outline-empty", children: emptyState }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { role: "list", style: { listStyle: "none", margin: 0, padding: 0 }, children: visible.map((heading) => {
864
+ const active = heading.id === activeId;
865
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { "data-level": heading.level, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
866
+ "button",
867
+ {
868
+ type: "button",
869
+ className: active ? `${itemClassName} ${activeItemClassName}` : itemClassName,
870
+ style: { paddingLeft: `${0.5 + heading.depth * 0.75}rem` },
871
+ "aria-current": active ? "location" : void 0,
872
+ "data-heading-id": heading.id,
873
+ onClick: () => {
874
+ if (!editor) return;
875
+ if ((0, import_editor8.navigateToHeading)(editor, heading, { focus: focusOnNavigate })) {
876
+ onNavigate?.(heading);
877
+ }
878
+ },
879
+ children: heading.text || "Untitled"
880
+ }
881
+ ) }, heading.id);
882
+ }) })
883
+ ] });
884
+ };
885
+
886
+ // src/index.ts
887
+ var import_editor15 = require("@pixerate/editor");
645
888
 
646
889
  // src/spreadsheet/useSpreadsheetEditor.ts
647
- var import_react11 = require("react");
648
- var import_editor5 = require("@pixerate/editor");
890
+ var import_react15 = require("react");
891
+ var import_editor9 = require("@pixerate/editor");
649
892
  function useSpreadsheetEditor(options = {}) {
650
- const optionsRef = (0, import_react11.useRef)(options);
893
+ const optionsRef = (0, import_react15.useRef)(options);
651
894
  optionsRef.current = options;
652
- const settersRef = (0, import_react11.useRef)({});
653
- const [controller] = (0, import_react11.useState)(
654
- () => new import_editor5.SpreadsheetController({
895
+ const settersRef = (0, import_react15.useRef)({});
896
+ const [controller] = (0, import_react15.useState)(
897
+ () => new import_editor9.SpreadsheetController({
655
898
  ...options,
656
899
  onDocumentChange: (updated) => {
657
900
  settersRef.current.setDoc?.({ ...updated });
@@ -667,91 +910,93 @@ function useSpreadsheetEditor(options = {}) {
667
910
  }
668
911
  })
669
912
  );
670
- const [doc, setDoc] = (0, import_react11.useState)(() => ({ ...controller.document }));
671
- const [activeCell, setActiveCell] = (0, import_react11.useState)(controller.activeCell);
672
- const [selectedRange, setSelectedRange] = (0, import_react11.useState)(controller.selectedRange);
673
- const [editingCell, setEditingCell] = (0, import_react11.useState)(null);
674
- const [draftValue, setDraftValue] = (0, import_react11.useState)("");
913
+ const [doc, setDoc] = (0, import_react15.useState)(() => ({ ...controller.document }));
914
+ const [activeCell, setActiveCell] = (0, import_react15.useState)(controller.activeCell);
915
+ const [selectedRange, setSelectedRange] = (0, import_react15.useState)(controller.selectedRange);
916
+ const [editingCell, setEditingCell] = (0, import_react15.useState)(null);
917
+ const [draftValue, setDraftValue] = (0, import_react15.useState)("");
675
918
  settersRef.current = { setDoc, setActiveCell, setSelectedRange };
676
- const setCellValue = (0, import_react11.useCallback)((rowId, colId, raw) => {
919
+ const setCellValue = (0, import_react15.useCallback)((rowId, colId, raw) => {
677
920
  controller.setCellValue(rowId, colId, raw);
678
921
  setDoc({ ...controller.document });
679
922
  }, [controller]);
680
- const selectCell = (0, import_react11.useCallback)((row, col, extendSelection = false) => {
923
+ const selectCell = (0, import_react15.useCallback)((row, col, extendSelection = false) => {
681
924
  controller.selectCell(row, col, extendSelection);
682
925
  setActiveCell(controller.activeCell);
683
926
  setSelectedRange(controller.selectedRange);
684
927
  }, [controller]);
685
- const selectRange = (0, import_react11.useCallback)((range) => {
928
+ const selectRange = (0, import_react15.useCallback)((range) => {
686
929
  controller.selectRange(range);
687
930
  setSelectedRange(controller.selectedRange);
688
931
  }, [controller]);
689
- const startEditing = (0, import_react11.useCallback)((row, col, initialVal) => {
932
+ const startEditing = (0, import_react15.useCallback)((row, col, initialVal) => {
690
933
  controller.startEditing(row, col, initialVal);
691
934
  setActiveCell(controller.activeCell);
692
935
  setEditingCell(controller.editingCell);
693
936
  setDraftValue(controller.draftValue);
694
937
  }, [controller]);
695
- const commitEditing = (0, import_react11.useCallback)((val) => {
938
+ const commitEditing = (0, import_react15.useCallback)((val) => {
696
939
  controller.commitEditing(val);
697
940
  setEditingCell(null);
698
941
  setDraftValue("");
699
942
  setDoc({ ...controller.document });
700
943
  }, [controller]);
701
- const cancelEditing = (0, import_react11.useCallback)(() => {
944
+ const cancelEditing = (0, import_react15.useCallback)(() => {
702
945
  controller.cancelEditing();
703
946
  setEditingCell(null);
704
947
  setDraftValue("");
705
948
  }, [controller]);
706
- const moveCursor = (0, import_react11.useCallback)((dir, extend = false) => {
949
+ const moveCursor = (0, import_react15.useCallback)((dir, extend = false) => {
707
950
  controller.moveCursor(dir, extend);
708
951
  setActiveCell(controller.activeCell);
709
952
  setSelectedRange(controller.selectedRange);
710
953
  }, [controller]);
711
- const insertColumn = (0, import_react11.useCallback)((index, config) => {
954
+ const insertColumn = (0, import_react15.useCallback)((index, config) => {
712
955
  controller.insertColumn(index, config);
713
956
  setDoc({ ...controller.document });
714
957
  }, [controller]);
715
- const deleteColumn = (0, import_react11.useCallback)((colId) => {
958
+ const deleteColumn = (0, import_react15.useCallback)((colId) => {
716
959
  controller.deleteColumn(colId);
717
960
  setDoc({ ...controller.document });
718
961
  }, [controller]);
719
- const insertRow = (0, import_react11.useCallback)((index, config) => {
962
+ const insertRow = (0, import_react15.useCallback)((index, config) => {
720
963
  controller.insertRow(index, config);
721
964
  setDoc({ ...controller.document });
722
965
  }, [controller]);
723
- const deleteRow = (0, import_react11.useCallback)((rowId) => {
966
+ const deleteRow = (0, import_react15.useCallback)((rowId) => {
724
967
  controller.deleteRow(rowId);
725
968
  setDoc({ ...controller.document });
726
969
  }, [controller]);
727
- const setColumnWidth = (0, import_react11.useCallback)((colId, width) => {
970
+ const setColumnWidth = (0, import_react15.useCallback)((colId, width) => {
728
971
  controller.setColumnWidth(colId, width);
729
972
  setDoc({ ...controller.document });
730
973
  }, [controller]);
731
- const autoFitColumnWidth = (0, import_react11.useCallback)((colId, customWidth) => {
974
+ const autoFitColumnWidth = (0, import_react15.useCallback)((colId, customWidth) => {
732
975
  controller.autoFitColumnWidth(colId, customWidth);
733
976
  setDoc({ ...controller.document });
734
977
  }, [controller]);
735
- const registerDataSource = (0, import_react11.useCallback)((ds) => {
978
+ const registerDataSource = (0, import_react15.useCallback)((ds) => {
736
979
  controller.registerDataSource(ds);
737
980
  setDoc({ ...controller.document });
738
981
  }, [controller]);
739
- const setPrimaryDataSource = (0, import_react11.useCallback)((id) => {
982
+ const setPrimaryDataSource = (0, import_react15.useCallback)((id) => {
740
983
  controller.setPrimaryDataSource(id);
741
984
  setDoc({ ...controller.document });
742
985
  }, [controller]);
743
- const recalculateAll = (0, import_react11.useCallback)(() => {
986
+ const recalculateAll = (0, import_react15.useCallback)(() => {
744
987
  controller.recalculateAll();
745
988
  setDoc({ ...controller.document });
746
989
  }, [controller]);
747
- const undo = (0, import_react11.useCallback)(() => {
990
+ const undo = (0, import_react15.useCallback)(() => {
748
991
  controller.undo();
749
992
  setDoc({ ...controller.document });
750
993
  }, [controller]);
751
- const redo = (0, import_react11.useCallback)(() => {
994
+ const redo = (0, import_react15.useCallback)(() => {
752
995
  controller.redo();
753
996
  setDoc({ ...controller.document });
754
997
  }, [controller]);
998
+ const tableActions = (0, import_react15.useMemo)(() => (0, import_editor9.bindSpreadsheetTableActions)(controller), [controller]);
999
+ const viewModel = (0, import_react15.useMemo)(() => controller.getViewModel(), [controller, doc]);
755
1000
  return {
756
1001
  document: doc,
757
1002
  activeCell,
@@ -795,15 +1040,355 @@ function useSpreadsheetEditor(options = {}) {
795
1040
  controller.importFromTsv(data);
796
1041
  setDoc({ ...controller.document });
797
1042
  },
1043
+ ...tableActions,
1044
+ viewModel,
798
1045
  undo,
799
1046
  redo
800
1047
  };
801
1048
  }
802
1049
 
803
1050
  // src/spreadsheet/SpreadsheetEditor.tsx
804
- var import_react12 = require("react");
805
- var import_editor6 = require("@pixerate/editor");
806
- var import_jsx_runtime3 = require("react/jsx-runtime");
1051
+ var import_react19 = require("react");
1052
+ var import_editor12 = require("@pixerate/editor");
1053
+
1054
+ // src/spreadsheet/SpreadsheetContextMenu.tsx
1055
+ var import_react16 = __toESM(require("react"), 1);
1056
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1057
+ var SpreadsheetContextMenu = ({ items, x, y, onClose }) => {
1058
+ const menuRef = (0, import_react16.useRef)(null);
1059
+ const onCloseRef = (0, import_react16.useRef)(onClose);
1060
+ onCloseRef.current = onClose;
1061
+ (0, import_react16.useEffect)(() => {
1062
+ const handlePointer = (e) => {
1063
+ if (!menuRef.current?.contains(e.target)) onCloseRef.current();
1064
+ };
1065
+ const handleKey = (e) => {
1066
+ if (e.key === "Escape") onCloseRef.current();
1067
+ };
1068
+ window.addEventListener("mousedown", handlePointer);
1069
+ window.addEventListener("keydown", handleKey);
1070
+ return () => {
1071
+ window.removeEventListener("mousedown", handlePointer);
1072
+ window.removeEventListener("keydown", handleKey);
1073
+ };
1074
+ }, []);
1075
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1076
+ "div",
1077
+ {
1078
+ ref: menuRef,
1079
+ role: "menu",
1080
+ "aria-label": "Table actions",
1081
+ className: "fixed z-50 min-w-[14rem] rounded-md border border-border bg-popover py-1 text-xs text-popover-foreground shadow-lg",
1082
+ style: { left: x, top: y, background: "var(--popover, var(--background, #fff))" },
1083
+ onContextMenu: (e) => e.preventDefault(),
1084
+ onKeyDown: (e) => e.stopPropagation(),
1085
+ children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react16.default.Fragment, { children: [
1086
+ item.separatorBefore && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { role: "separator", className: "my-1 h-px bg-border" }),
1087
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1088
+ "button",
1089
+ {
1090
+ type: "button",
1091
+ role: "menuitem",
1092
+ "data-action": item.id,
1093
+ disabled: item.disabled,
1094
+ className: "block w-full px-3 py-1 text-left hover:bg-muted disabled:cursor-default disabled:opacity-40 disabled:hover:bg-transparent",
1095
+ onClick: () => {
1096
+ onClose();
1097
+ item.run();
1098
+ },
1099
+ children: item.label
1100
+ }
1101
+ )
1102
+ ] }, item.id))
1103
+ }
1104
+ );
1105
+ };
1106
+
1107
+ // src/spreadsheet/SpreadsheetGroupRow.tsx
1108
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1109
+ var formatSummary = (value) => value === null ? "\u2013" : String(value);
1110
+ var SpreadsheetGroupRow = ({
1111
+ group,
1112
+ columns,
1113
+ groupColId,
1114
+ onToggle,
1115
+ trailingCell
1116
+ }) => {
1117
+ const labelColId = columns.some((c) => c.column.id === groupColId) ? groupColId : columns[0]?.column.id;
1118
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("tr", { className: "border-b border-border bg-muted/40 font-semibold", "data-group-key": group.key, style: { height: 28 }, children: [
1119
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted/60 border-r border-border text-center", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1120
+ "button",
1121
+ {
1122
+ type: "button",
1123
+ "aria-label": `${group.collapsed ? "Expand" : "Collapse"} group ${group.label}`,
1124
+ "aria-expanded": !group.collapsed,
1125
+ className: "h-5 w-5 rounded text-[10px] text-muted-foreground hover:bg-muted",
1126
+ onClick: (e) => {
1127
+ e.stopPropagation();
1128
+ onToggle(group.key);
1129
+ },
1130
+ children: group.collapsed ? "\u25B8" : "\u25BE"
1131
+ }
1132
+ ) }),
1133
+ columns.map(({ column }) => {
1134
+ const summary = group.summaries[column.id];
1135
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-r border-border px-2 py-1 truncate max-w-0 text-foreground", style: { maxWidth: 0, overflow: "hidden" }, children: column.id === labelColId ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "truncate", children: [
1136
+ group.label,
1137
+ " ",
1138
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "font-normal text-muted-foreground", children: [
1139
+ "(",
1140
+ group.rowIndices.length,
1141
+ ")"
1142
+ ] })
1143
+ ] }) : summary !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "truncate", "data-summary": column.id, children: formatSummary(summary) }) : null }, column.id);
1144
+ }),
1145
+ trailingCell && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "w-10 min-w-[2.5rem] bg-muted/10 border-r border-border" })
1146
+ ] });
1147
+ };
1148
+
1149
+ // src/spreadsheet/useSpreadsheetTableInteractions.ts
1150
+ var import_react17 = require("react");
1151
+ var import_editor10 = require("@pixerate/editor");
1152
+ function gridHasFocus(grid) {
1153
+ if (!grid || typeof document === "undefined") return false;
1154
+ const active = document.activeElement;
1155
+ if (!active || !grid.contains(active)) return false;
1156
+ return !(active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement);
1157
+ }
1158
+ function useSpreadsheetClipboard(gridRef, state, readOnly) {
1159
+ const stateRef = (0, import_react17.useRef)(state);
1160
+ stateRef.current = state;
1161
+ const readOnlyRef = (0, import_react17.useRef)(readOnly);
1162
+ readOnlyRef.current = readOnly;
1163
+ const copiedRef = (0, import_react17.useRef)(false);
1164
+ (0, import_react17.useEffect)(() => {
1165
+ if (typeof document === "undefined") return;
1166
+ const handleCopy = (e) => {
1167
+ const s = stateRef.current;
1168
+ if (!gridHasFocus(gridRef.current) || s.editingCell || !e.clipboardData || !s.selectedRange) return;
1169
+ for (const [type, data] of Object.entries(s.copyToClipboardData(s.selectedRange))) {
1170
+ e.clipboardData.setData(type, data);
1171
+ }
1172
+ copiedRef.current = true;
1173
+ e.preventDefault();
1174
+ };
1175
+ const handlePaste = (e) => {
1176
+ const s = stateRef.current;
1177
+ if (readOnlyRef.current || !gridHasFocus(gridRef.current) || s.editingCell || !e.clipboardData) return;
1178
+ if (s.pasteClipboardData(e.clipboardData)) e.preventDefault();
1179
+ };
1180
+ document.addEventListener("copy", handleCopy);
1181
+ document.addEventListener("paste", handlePaste);
1182
+ return () => {
1183
+ document.removeEventListener("copy", handleCopy);
1184
+ document.removeEventListener("paste", handlePaste);
1185
+ };
1186
+ }, [gridRef]);
1187
+ const copyShortcutFallback = (0, import_react17.useCallback)(() => {
1188
+ copiedRef.current = false;
1189
+ setTimeout(() => {
1190
+ if (copiedRef.current) return;
1191
+ const s = stateRef.current;
1192
+ navigator.clipboard?.writeText(s.exportToTsv(s.selectedRange));
1193
+ }, 0);
1194
+ }, []);
1195
+ return { copyShortcutFallback };
1196
+ }
1197
+ function useFillHandle(state) {
1198
+ const [drag, setDrag] = (0, import_react17.useState)(null);
1199
+ const dragRef = (0, import_react17.useRef)(drag);
1200
+ dragRef.current = drag;
1201
+ const stateRef = (0, import_react17.useRef)(state);
1202
+ stateRef.current = state;
1203
+ const dragging = drag !== null;
1204
+ (0, import_react17.useEffect)(() => {
1205
+ if (!dragging) return;
1206
+ const handleMouseUp = () => {
1207
+ const current = dragRef.current;
1208
+ setDrag(null);
1209
+ if (current?.target) stateRef.current.autofill(current.source, current.target);
1210
+ };
1211
+ window.addEventListener("mouseup", handleMouseUp);
1212
+ return () => window.removeEventListener("mouseup", handleMouseUp);
1213
+ }, [dragging]);
1214
+ const startFill = (0, import_react17.useCallback)((e) => {
1215
+ e.preventDefault();
1216
+ e.stopPropagation();
1217
+ const range = stateRef.current.selectedRange;
1218
+ if (range) setDrag({ source: (0, import_editor10.normalizeRange)(range), target: null });
1219
+ }, []);
1220
+ const extendFill = (0, import_react17.useCallback)((row, col) => {
1221
+ const current = dragRef.current;
1222
+ if (!current) return;
1223
+ setDrag({ source: current.source, target: (0, import_editor10.computeFillTarget)(current.source, { row, col }) });
1224
+ }, []);
1225
+ return { fillTarget: drag?.target ?? null, isFilling: dragging, startFill, extendFill };
1226
+ }
1227
+
1228
+ // src/spreadsheet/FormulaHints.tsx
1229
+ var import_react18 = require("react");
1230
+ var import_editor11 = require("@pixerate/editor");
1231
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1232
+ var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
1233
+ const [caret, setCaret] = (0, import_react18.useState)(null);
1234
+ const [focused, setFocused] = (0, import_react18.useState)(false);
1235
+ const [selected, setSelected] = (0, import_react18.useState)(0);
1236
+ const [dismissed, setDismissed] = (0, import_react18.useState)(false);
1237
+ const [position, setPosition] = (0, import_react18.useState)(null);
1238
+ const pendingCaret = (0, import_react18.useRef)(null);
1239
+ const hints = (0, import_react18.useMemo)(
1240
+ () => (0, import_editor11.getFormulaHints)(value, caret ?? value.length, { limit }),
1241
+ [value, caret, limit]
1242
+ );
1243
+ const suggestions = dismissed ? [] : hints.suggestions;
1244
+ const selectedIndex = Math.max(0, Math.min(selected, suggestions.length - 1));
1245
+ const visible = focused && value.trimStart().startsWith("=") && (suggestions.length > 0 || !!hints.activeCall);
1246
+ const latest = (0, import_react18.useRef)({ suggestions, selected: selectedIndex, value, caret, onAccept });
1247
+ latest.current = { suggestions, selected: selectedIndex, value, caret, onAccept };
1248
+ const accept = (index) => {
1249
+ const { suggestions: list, value: current, caret: at, onAccept: commit } = latest.current;
1250
+ const suggestion = list[index];
1251
+ if (!suggestion) return;
1252
+ const next = (0, import_editor11.applyFormulaSuggestion)(current, at ?? current.length, suggestion.name);
1253
+ pendingCaret.current = next.caret;
1254
+ commit(next.value);
1255
+ };
1256
+ (0, import_react18.useEffect)(() => {
1257
+ const input = inputRef.current;
1258
+ if (!input) return;
1259
+ const syncCaret = () => setCaret(input.selectionStart ?? input.value.length);
1260
+ const onInput = () => {
1261
+ setDismissed(false);
1262
+ setSelected(0);
1263
+ syncCaret();
1264
+ };
1265
+ const onFocus = () => {
1266
+ setFocused(true);
1267
+ syncCaret();
1268
+ };
1269
+ const onBlur = () => setFocused(false);
1270
+ const onKeyDown = (e) => {
1271
+ const { suggestions: list } = latest.current;
1272
+ if (list.length === 0) return;
1273
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
1274
+ e.preventDefault();
1275
+ e.stopPropagation();
1276
+ const step = e.key === "ArrowDown" ? 1 : -1;
1277
+ setSelected((i) => (i + step + list.length) % list.length);
1278
+ } else if (e.key === "Tab" && !e.shiftKey) {
1279
+ e.preventDefault();
1280
+ e.stopPropagation();
1281
+ accept(latest.current.selected);
1282
+ } else if (e.key === "Escape") {
1283
+ e.preventDefault();
1284
+ e.stopPropagation();
1285
+ setDismissed(true);
1286
+ }
1287
+ };
1288
+ input.addEventListener("input", onInput);
1289
+ input.addEventListener("keyup", syncCaret);
1290
+ input.addEventListener("click", syncCaret);
1291
+ input.addEventListener("select", syncCaret);
1292
+ input.addEventListener("focus", onFocus);
1293
+ input.addEventListener("blur", onBlur);
1294
+ input.addEventListener("keydown", onKeyDown);
1295
+ if (typeof document !== "undefined" && document.activeElement === input) onFocus();
1296
+ return () => {
1297
+ input.removeEventListener("input", onInput);
1298
+ input.removeEventListener("keyup", syncCaret);
1299
+ input.removeEventListener("click", syncCaret);
1300
+ input.removeEventListener("select", syncCaret);
1301
+ input.removeEventListener("focus", onFocus);
1302
+ input.removeEventListener("blur", onBlur);
1303
+ input.removeEventListener("keydown", onKeyDown);
1304
+ };
1305
+ }, [inputRef]);
1306
+ (0, import_react18.useLayoutEffect)(() => {
1307
+ const input = inputRef.current;
1308
+ const at = pendingCaret.current;
1309
+ if (!input || at === null || input.value !== value) return;
1310
+ pendingCaret.current = null;
1311
+ input.setSelectionRange(at, at);
1312
+ setCaret(at);
1313
+ setSelected(0);
1314
+ }, [value, inputRef]);
1315
+ (0, import_react18.useLayoutEffect)(() => {
1316
+ const input = inputRef.current;
1317
+ if (!visible || !input) return;
1318
+ const rect = input.getBoundingClientRect();
1319
+ setPosition({ top: rect.bottom + 2, left: rect.left, width: rect.width });
1320
+ }, [visible, value, inputRef]);
1321
+ if (!visible) return null;
1322
+ const { activeCall } = hints;
1323
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1324
+ "div",
1325
+ {
1326
+ "data-formula-hints": "",
1327
+ className: "rounded-md border border-border bg-popover text-popover-foreground shadow-md text-xs font-sans overflow-hidden",
1328
+ style: {
1329
+ position: "fixed",
1330
+ top: position?.top ?? 0,
1331
+ left: position?.left ?? 0,
1332
+ minWidth: Math.max(260, position?.width ?? 0),
1333
+ maxWidth: 440,
1334
+ zIndex: 50,
1335
+ visibility: position ? "visible" : "hidden"
1336
+ },
1337
+ onMouseDown: (e) => e.preventDefault(),
1338
+ children: [
1339
+ activeCall && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { "data-formula-signature": "", className: "px-2 py-1.5 border-b border-border bg-muted/30", children: [
1340
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "font-mono", children: activeCall.parts.map((part, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1341
+ "span",
1342
+ {
1343
+ "data-active": part.active ? "" : void 0,
1344
+ className: part.active ? "font-bold text-primary underline" : "",
1345
+ children: part.text
1346
+ },
1347
+ i
1348
+ )) }),
1349
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mt-0.5 text-muted-foreground", children: activeCall.argument ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1350
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-semibold", children: activeCall.argument.name }),
1351
+ ": ",
1352
+ activeCall.argument.description
1353
+ ] }) : activeCall.description })
1354
+ ] }),
1355
+ suggestions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { role: "listbox", "aria-label": "Formula suggestions", className: "max-h-64 overflow-auto py-1 m-0 list-none p-0", children: suggestions.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1356
+ "li",
1357
+ {
1358
+ role: "option",
1359
+ "aria-selected": i === selectedIndex,
1360
+ className: `cursor-pointer px-2 py-1 ${i === selectedIndex ? "bg-primary/10" : "hover:bg-muted/50"}`,
1361
+ onMouseEnter: () => setSelected(i),
1362
+ onMouseDown: (e) => {
1363
+ e.preventDefault();
1364
+ accept(i);
1365
+ },
1366
+ children: [
1367
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "font-mono font-semibold text-foreground", children: s.signature }),
1368
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-muted-foreground truncate", children: s.description })
1369
+ ]
1370
+ },
1371
+ s.name
1372
+ )) })
1373
+ ]
1374
+ }
1375
+ );
1376
+ };
1377
+
1378
+ // src/spreadsheet/SpreadsheetEditor.tsx
1379
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1380
+ var COLUMN_HEADER_HEIGHT = 28;
1381
+ var ROW_HEADER_WIDTH = 48;
1382
+ function frozenCellStyle(viewRow, viewCol) {
1383
+ if (!viewRow.frozen && !viewCol.frozen) return void 0;
1384
+ return {
1385
+ position: "sticky",
1386
+ ...viewRow.frozen ? { top: COLUMN_HEADER_HEIGHT + viewRow.stickyTop } : {},
1387
+ ...viewCol.frozen ? { left: ROW_HEADER_WIDTH + viewCol.stickyLeft } : {},
1388
+ zIndex: viewRow.frozen && viewCol.frozen ? 14 : viewRow.frozen ? 12 : 11,
1389
+ background: "var(--background, #fff)"
1390
+ };
1391
+ }
807
1392
  var SpreadsheetEditor = ({
808
1393
  state: externalState,
809
1394
  readOnly = false,
@@ -814,27 +1399,47 @@ var SpreadsheetEditor = ({
814
1399
  }) => {
815
1400
  const defaultState = useSpreadsheetEditor();
816
1401
  const state = externalState || defaultState;
817
- const gridRef = (0, import_react12.useRef)(null);
818
- const [resizingColId, setResizingColId] = (0, import_react12.useState)(null);
819
- const [hoveredColId, setHoveredColId] = (0, import_react12.useState)(null);
820
- const [resizeStartX, setResizeStartX] = (0, import_react12.useState)(0);
821
- const [resizeStartWidth, setResizeStartWidth] = (0, import_react12.useState)(0);
822
- const activeRawValue = (0, import_react12.useMemo)(() => {
1402
+ const gridRef = (0, import_react19.useRef)(null);
1403
+ const formulaBarRef = (0, import_react19.useRef)(null);
1404
+ const cellInputRef = (0, import_react19.useRef)(null);
1405
+ const [resizingColId, setResizingColId] = (0, import_react19.useState)(null);
1406
+ const [hoveredColId, setHoveredColId] = (0, import_react19.useState)(null);
1407
+ const [resizeStartX, setResizeStartX] = (0, import_react19.useState)(0);
1408
+ const [resizeStartWidth, setResizeStartWidth] = (0, import_react19.useState)(0);
1409
+ const view = state.viewModel;
1410
+ const { copyShortcutFallback } = useSpreadsheetClipboard(gridRef, state, readOnly);
1411
+ const { fillTarget, startFill, extendFill } = useFillHandle(state);
1412
+ const [menu, setMenu] = (0, import_react19.useState)(null);
1413
+ const filter = state.document.table?.filter;
1414
+ const filteredColIds = (0, import_react19.useMemo)(
1415
+ () => new Set(filter?.enabled ? filter.rules.map((r) => r.colId) : []),
1416
+ [filter]
1417
+ );
1418
+ const handleCellContextMenu = (0, import_react19.useCallback)((rIdx, cIdx, e) => {
1419
+ if (readOnly) return;
1420
+ e.preventDefault();
1421
+ if (state.editingCell) state.commitEditing();
1422
+ if (!state.selectedRange || !(0, import_editor12.rangeContains)(state.selectedRange, rIdx, cIdx)) {
1423
+ state.selectCell(rIdx, cIdx);
1424
+ }
1425
+ setMenu({ x: e.clientX, y: e.clientY, items: (0, import_editor12.getSpreadsheetMenuItems)(state.controller, { row: rIdx, col: cIdx }) });
1426
+ }, [readOnly, state]);
1427
+ const activeRawValue = (0, import_react19.useMemo)(() => {
823
1428
  if (!state.activeCell) return "";
824
1429
  const row = state.document.rows[state.activeCell.row];
825
1430
  const col = state.document.columns[state.activeCell.col];
826
1431
  if (!row || !col) return "";
827
1432
  return state.getCell(row.id, col.id).raw;
828
1433
  }, [state.activeCell, state.document]);
829
- const coordLabel = (0, import_react12.useMemo)(() => {
1434
+ const coordLabel = (0, import_react19.useMemo)(() => {
830
1435
  if (!state.activeCell) return "--";
831
- const colName = (0, import_editor6.indexToColName)(state.activeCell.col);
1436
+ const colName = (0, import_editor12.indexToColName)(state.activeCell.col);
832
1437
  return `${colName}${state.activeCell.row + 1}`;
833
1438
  }, [state.activeCell]);
834
- const [formulaDraft, setFormulaDraft] = (0, import_react12.useState)(null);
1439
+ const [formulaDraft, setFormulaDraft] = (0, import_react19.useState)(null);
835
1440
  const activeColumn = state.activeCell ? state.document.columns[state.activeCell.col] : void 0;
836
1441
  const formulaBarReadOnly = readOnly || !state.activeCell || !!activeColumn?.readOnly;
837
- (0, import_react12.useEffect)(() => {
1442
+ (0, import_react19.useEffect)(() => {
838
1443
  setFormulaDraft(null);
839
1444
  }, [state.activeCell?.row, state.activeCell?.col]);
840
1445
  const commitFormulaBar = () => {
@@ -850,19 +1455,19 @@ var SpreadsheetEditor = ({
850
1455
  }
851
1456
  setFormulaDraft(null);
852
1457
  };
853
- const handleCellClick = (0, import_react12.useCallback)((rIdx, cIdx, e) => {
1458
+ const handleCellClick = (0, import_react19.useCallback)((rIdx, cIdx, e) => {
854
1459
  if (state.editingCell && (state.editingCell.row !== rIdx || state.editingCell.col !== cIdx)) {
855
1460
  state.commitEditing();
856
1461
  }
857
1462
  state.selectCell(rIdx, cIdx, e.shiftKey);
858
1463
  }, [state]);
859
- const handleCellDblClick = (0, import_react12.useCallback)((rIdx, cIdx) => {
1464
+ const handleCellDblClick = (0, import_react19.useCallback)((rIdx, cIdx) => {
860
1465
  if (readOnly) return;
861
1466
  const col = state.document.columns[cIdx];
862
1467
  if (col?.readOnly) return;
863
1468
  state.startEditing(rIdx, cIdx);
864
1469
  }, [readOnly, state]);
865
- const handleKeyDown = (0, import_react12.useCallback)((e) => {
1470
+ const handleKeyDown = (0, import_react19.useCallback)((e) => {
866
1471
  if (state.editingCell) {
867
1472
  if (e.key === "Enter") {
868
1473
  e.preventDefault();
@@ -919,21 +1524,19 @@ var SpreadsheetEditor = ({
919
1524
  e.preventDefault();
920
1525
  state.redo();
921
1526
  } else if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "c") {
922
- e.preventDefault();
923
- const tsv = state.exportToTsv(state.selectedRange);
924
- navigator.clipboard?.writeText(tsv);
1527
+ copyShortcutFallback();
925
1528
  } else if (!readOnly && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
926
1529
  const col = state.document.columns[state.activeCell.col];
927
1530
  if (!col?.readOnly) {
928
1531
  state.startEditing(state.activeCell.row, state.activeCell.col, e.key);
929
1532
  }
930
1533
  }
931
- }, [readOnly, state]);
932
- const stateRef = (0, import_react12.useRef)(state);
1534
+ }, [readOnly, state, copyShortcutFallback]);
1535
+ const stateRef = (0, import_react19.useRef)(state);
933
1536
  stateRef.current = state;
934
- const onColumnResizeRef = (0, import_react12.useRef)(onColumnResize);
1537
+ const onColumnResizeRef = (0, import_react19.useRef)(onColumnResize);
935
1538
  onColumnResizeRef.current = onColumnResize;
936
- (0, import_react12.useEffect)(() => {
1539
+ (0, import_react19.useEffect)(() => {
937
1540
  if (!resizingColId) return;
938
1541
  if (typeof document !== "undefined") {
939
1542
  document.body.style.cursor = "col-resize";
@@ -984,7 +1587,7 @@ var SpreadsheetEditor = ({
984
1587
  window.removeEventListener("mouseup", handleMouseUp);
985
1588
  };
986
1589
  }, [resizingColId, resizeStartX, resizeStartWidth]);
987
- const measureElementContentWidth = (0, import_react12.useCallback)((el, container) => {
1590
+ const measureElementContentWidth = (0, import_react19.useCallback)((el, container) => {
988
1591
  if (typeof document === "undefined") return 0;
989
1592
  let maxW = el.scrollWidth || 0;
990
1593
  const firstChild = el.firstElementChild;
@@ -1032,15 +1635,14 @@ var SpreadsheetEditor = ({
1032
1635
  }
1033
1636
  return maxW;
1034
1637
  }, []);
1035
- const autoFitColumn = (0, import_react12.useCallback)((colId, colIndex) => {
1638
+ const autoFitColumn = (0, import_react19.useCallback)((colId, colIndex) => {
1036
1639
  const col = state.document.columns.find((c) => c.id === colId);
1037
1640
  if (!col) return;
1038
1641
  let calculatedWidth = 0;
1039
1642
  if (gridRef.current && typeof document !== "undefined") {
1040
1643
  const table = gridRef.current.querySelector("table");
1041
1644
  if (table) {
1042
- const thElements = table.querySelectorAll("thead th");
1043
- const th = thElements[colIndex + 1];
1645
+ const th = table.querySelector(`thead th[data-col="${colIndex}"]`);
1044
1646
  if (th) {
1045
1647
  const headerInner = th.firstElementChild || th;
1046
1648
  const headerW = measureElementContentWidth(headerInner, gridRef.current);
@@ -1050,7 +1652,7 @@ var SpreadsheetEditor = ({
1050
1652
  const sampleLimit = Math.min(rows.length, 150);
1051
1653
  for (let r = 0; r < sampleLimit; r++) {
1052
1654
  const tr = rows[r];
1053
- const td = tr.children[colIndex + 1];
1655
+ const td = tr.querySelector(`td[data-col="${colIndex}"][colspan="1"]`);
1054
1656
  if (td) {
1055
1657
  const cellW = measureElementContentWidth(td, gridRef.current);
1056
1658
  calculatedWidth = Math.max(calculatedWidth, cellW + 20);
@@ -1069,12 +1671,12 @@ var SpreadsheetEditor = ({
1069
1671
  onColumnResize(updatedCol.id, updatedCol.width || 130);
1070
1672
  }
1071
1673
  }, [state, measureElementContentWidth, onColumnResize]);
1072
- const handleResizeDblClick = (0, import_react12.useCallback)((colId, colIndex, e) => {
1674
+ const handleResizeDblClick = (0, import_react19.useCallback)((colId, colIndex, e) => {
1073
1675
  e.preventDefault();
1074
1676
  e.stopPropagation();
1075
1677
  autoFitColumn(colId, colIndex);
1076
1678
  }, [autoFitColumn]);
1077
- const handleHeaderDblClick = (0, import_react12.useCallback)((colId, colIndex, e) => {
1679
+ const handleHeaderDblClick = (0, import_react19.useCallback)((colId, colIndex, e) => {
1078
1680
  const target = e.currentTarget;
1079
1681
  if (target) {
1080
1682
  const rect = target.getBoundingClientRect();
@@ -1096,7 +1698,7 @@ var SpreadsheetEditor = ({
1096
1698
  const isActiveCell = (rIdx, cIdx) => {
1097
1699
  return state.activeCell?.row === rIdx && state.activeCell?.col === cIdx;
1098
1700
  };
1099
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1701
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1100
1702
  "div",
1101
1703
  {
1102
1704
  ref: gridRef,
@@ -1106,12 +1708,13 @@ var SpreadsheetEditor = ({
1106
1708
  role: "grid",
1107
1709
  "aria-label": "Spreadsheet",
1108
1710
  children: [
1109
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2 border-b border-border bg-muted/20 px-3 py-1.5 text-xs font-mono", children: [
1110
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex h-6 min-w-[3rem] items-center justify-center rounded border border-border bg-background px-1.5 font-semibold text-foreground", children: coordLabel }),
1111
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex items-center text-muted-foreground select-none", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "italic font-serif font-bold text-sm text-primary", children: "fx" }) }),
1112
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1711
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2 border-b border-border bg-muted/20 px-3 py-1.5 text-xs font-mono", children: [
1712
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex h-6 min-w-[3rem] items-center justify-center rounded border border-border bg-background px-1.5 font-semibold text-foreground", children: coordLabel }),
1713
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex items-center text-muted-foreground select-none", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "italic font-serif font-bold text-sm text-primary", children: "fx" }) }),
1714
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1113
1715
  "input",
1114
1716
  {
1717
+ ref: formulaBarRef,
1115
1718
  type: "text",
1116
1719
  className: "flex-1 bg-transparent px-2 py-0.5 outline-none font-sans text-xs text-foreground placeholder:text-muted-foreground/60 focus:bg-background focus:ring-1 focus:ring-primary rounded",
1117
1720
  placeholder: "Enter a value or formula (e.g. =SUM(A1:A5))",
@@ -1141,28 +1744,44 @@ var SpreadsheetEditor = ({
1141
1744
  }
1142
1745
  }
1143
1746
  }
1747
+ ),
1748
+ !formulaBarReadOnly && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1749
+ FormulaHints,
1750
+ {
1751
+ inputRef: formulaBarRef,
1752
+ value: state.editingCell ? state.draftValue : formulaDraft ?? activeRawValue,
1753
+ onAccept: (next) => state.editingCell ? state.setDraftValue(next) : setFormulaDraft(next)
1754
+ }
1144
1755
  )
1145
1756
  ] }),
1146
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "relative flex-1 overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("table", { className: "border-collapse table-fixed w-max min-w-full", children: [
1147
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { className: "h-7 bg-muted/60 sticky top-0 z-20 border-b border-border shadow-xs", children: [
1148
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { className: "w-12 min-w-[3rem] sticky left-0 z-30 bg-muted/90 border-r border-border text-center text-[10px] text-muted-foreground font-medium", children: "#" }),
1149
- state.document.columns.map((col, cIdx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1757
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "relative flex-1 overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("table", { className: "border-collapse table-fixed w-max min-w-full", children: [
1758
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { className: "h-7 bg-muted/60 sticky top-0 z-20 border-b border-border shadow-xs", children: [
1759
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { className: "w-12 min-w-[3rem] sticky left-0 z-30 bg-muted/90 border-r border-border text-center text-[10px] text-muted-foreground font-medium", children: "#" }),
1760
+ view.columns.map(({ column: col, index: cIdx, frozen, stickyLeft }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1150
1761
  "th",
1151
1762
  {
1763
+ "data-col": cIdx,
1152
1764
  className: `relative border-r border-border px-2 text-left font-medium text-muted-foreground hover:bg-muted/90 transition-colors group overflow-hidden max-w-0 ${onColumnHeaderClick ? "cursor-pointer" : "cursor-default"}`,
1153
- style: { width: col.width || 130, minWidth: col.width || 130, maxWidth: col.width || 130, overflow: "hidden" },
1765
+ style: {
1766
+ width: col.width || 130,
1767
+ minWidth: col.width || 130,
1768
+ maxWidth: col.width || 130,
1769
+ overflow: "hidden",
1770
+ ...frozen ? { position: "sticky", left: ROW_HEADER_WIDTH + stickyLeft, zIndex: 25, background: "var(--muted, #f4f4f5)" } : {}
1771
+ },
1154
1772
  onClick: () => onColumnHeaderClick?.(col),
1155
1773
  onDoubleClick: (e) => handleHeaderDblClick(col.id, cIdx, e),
1156
1774
  children: [
1157
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center justify-between gap-1 min-w-0 overflow-hidden truncate", children: [
1158
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "truncate font-semibold text-foreground text-xs min-w-0", children: col.title }),
1159
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "text-[10px] text-muted-foreground/70 font-mono font-normal shrink-0", children: [
1775
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center justify-between gap-1 min-w-0 overflow-hidden truncate", children: [
1776
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "truncate font-semibold text-foreground text-xs min-w-0", children: col.title }),
1777
+ filteredColIds.has(col.id) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-[10px] text-primary shrink-0", title: "Filtered", "data-filtered": "true", children: "\u23F7" }),
1778
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "text-[10px] text-muted-foreground/70 font-mono font-normal shrink-0", children: [
1160
1779
  "(",
1161
1780
  col.key,
1162
1781
  ")"
1163
1782
  ] })
1164
1783
  ] }),
1165
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1784
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1166
1785
  "div",
1167
1786
  {
1168
1787
  className: "col-resize-handle",
@@ -1179,7 +1798,7 @@ var SpreadsheetEditor = ({
1179
1798
  onDoubleClick: (e) => handleResizeDblClick(col.id, cIdx, e),
1180
1799
  role: "separator",
1181
1800
  "aria-orientation": "vertical",
1182
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1801
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1183
1802
  "div",
1184
1803
  {
1185
1804
  className: "col-resize-handle-line",
@@ -1198,49 +1817,136 @@ var SpreadsheetEditor = ({
1198
1817
  },
1199
1818
  col.id
1200
1819
  )),
1201
- onAddColumnClick && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1820
+ onAddColumnClick && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1202
1821
  "th",
1203
1822
  {
1204
1823
  className: "w-10 min-w-[2.5rem] px-1 text-center bg-muted/40 hover:bg-muted cursor-pointer transition-colors",
1205
1824
  onClick: onAddColumnClick,
1206
1825
  title: "Add Column",
1207
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-xs font-bold text-muted-foreground", children: "+" })
1826
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-xs font-bold text-muted-foreground", children: "+" })
1208
1827
  }
1209
1828
  )
1210
1829
  ] }) }),
1211
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tbody", { children: state.document.rows.map((row, rIdx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { className: "border-b border-border hover:bg-muted/10 transition-colors", style: { height: row.height || 32 }, children: [
1212
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted/50 border-r border-border text-center text-[10px] text-muted-foreground font-mono select-none", children: rIdx + 1 }),
1213
- state.document.columns.map((col, cIdx) => {
1214
- const cell = state.getCell(row.id, col.id);
1215
- const selected = isCellSelected(rIdx, cIdx);
1216
- const active = isActiveCell(rIdx, cIdx);
1217
- const isEditing = state.editingCell?.row === rIdx && state.editingCell?.col === cIdx;
1218
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1219
- "td",
1830
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("tbody", { children: view.rows.map((viewRow) => {
1831
+ if (viewRow.kind === "group") {
1832
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1833
+ SpreadsheetGroupRow,
1220
1834
  {
1221
- className: `relative border-r border-border px-2 py-1 truncate max-w-0 text-foreground transition-colors ${selected ? "bg-primary/10" : ""} ${active ? "ring-2 ring-primary ring-inset z-10" : ""}`,
1222
- style: { maxWidth: 0, overflow: "hidden" },
1223
- onClick: (e) => handleCellClick(rIdx, cIdx, e),
1224
- onDoubleClick: () => handleCellDblClick(rIdx, cIdx),
1225
- children: isEditing ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1226
- "input",
1227
- {
1228
- type: "text",
1229
- className: "absolute inset-0 w-full h-full px-2 py-1 bg-background text-foreground outline-none font-sans text-xs border-2 border-primary z-20",
1230
- value: state.draftValue,
1231
- onChange: (e) => state.setDraftValue(e.target.value),
1232
- onBlur: () => state.commitEditing(),
1233
- autoFocus: true
1234
- }
1235
- ) : customCellRenderer ? customCellRenderer({ row, col, cell }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: `truncate block max-w-full ${cell.error ? "text-destructive font-semibold" : ""}`, children: cell.error || (cell.value ?? "") })
1835
+ group: viewRow.group,
1836
+ columns: view.columns,
1837
+ groupColId: state.document.table?.grouping?.colId ?? "",
1838
+ onToggle: state.toggleGroupCollapsed,
1839
+ trailingCell: !!onAddColumnClick
1236
1840
  },
1237
- col.id
1841
+ `group:${viewRow.group.key}`
1238
1842
  );
1239
- }),
1240
- onAddColumnClick && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { className: "w-10 min-w-[2.5rem] bg-muted/10 border-r border-border" })
1241
- ] }, row.id)) })
1843
+ }
1844
+ const displayRowIndex = viewRow.index;
1845
+ const selection = state.selectedRange ? (0, import_editor12.normalizeRange)(state.selectedRange) : null;
1846
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1847
+ "tr",
1848
+ {
1849
+ "data-row": displayRowIndex,
1850
+ className: `border-b border-border hover:bg-muted/10 transition-colors ${viewRow.section !== "body" ? "bg-muted/30 font-semibold" : ""}`,
1851
+ style: { height: viewRow.row.height || 32 },
1852
+ children: [
1853
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1854
+ "td",
1855
+ {
1856
+ className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted/50 border-r border-border text-center text-[10px] text-muted-foreground font-mono select-none",
1857
+ style: viewRow.frozen ? { top: COLUMN_HEADER_HEIGHT + viewRow.stickyTop, zIndex: 15 } : void 0,
1858
+ children: displayRowIndex + 1
1859
+ }
1860
+ ),
1861
+ view.columns.map((viewCol) => {
1862
+ const span = view.getCellSpan(displayRowIndex, viewCol.index);
1863
+ if (!span) return null;
1864
+ const rIdx = span.source.row;
1865
+ const cIdx = span.source.col;
1866
+ const row = state.document.rows[rIdx];
1867
+ const col = state.document.columns[cIdx];
1868
+ const cell = state.getCell(row.id, col.id);
1869
+ const selected = isCellSelected(rIdx, cIdx);
1870
+ const active = isActiveCell(rIdx, cIdx);
1871
+ const isEditing = state.editingCell?.row === rIdx && state.editingCell?.col === cIdx;
1872
+ const inFillPreview = !!fillTarget && !selected && (0, import_editor12.rangeContains)(fillTarget, displayRowIndex, viewCol.index);
1873
+ const showFillHandle = !readOnly && !isEditing && !!selection && (span.merge ? (0, import_editor12.rangeContains)(span.merge, selection.endRow, selection.endCol) : selection.endRow === rIdx && selection.endCol === cIdx);
1874
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1875
+ "td",
1876
+ {
1877
+ "data-row": rIdx,
1878
+ "data-col": cIdx,
1879
+ rowSpan: span.rowSpan,
1880
+ colSpan: span.colSpan,
1881
+ className: `relative border-r border-border px-2 py-1 truncate max-w-0 text-foreground transition-colors ${selected ? "bg-primary/10" : ""} ${active ? "ring-2 ring-primary ring-inset z-10" : ""} ${viewCol.header ? "font-semibold" : ""}`,
1882
+ style: {
1883
+ maxWidth: 0,
1884
+ overflow: "hidden",
1885
+ ...frozenCellStyle(viewRow, viewCol),
1886
+ ...inFillPreview ? { outline: "1px dashed var(--primary, #6366f1)", outlineOffset: -1 } : {}
1887
+ },
1888
+ onClick: (e) => handleCellClick(rIdx, cIdx, e),
1889
+ onDoubleClick: () => handleCellDblClick(rIdx, cIdx),
1890
+ onContextMenu: (e) => handleCellContextMenu(rIdx, cIdx, e),
1891
+ onMouseOver: () => extendFill(displayRowIndex, viewCol.index),
1892
+ children: [
1893
+ isEditing ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1894
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1895
+ "input",
1896
+ {
1897
+ ref: cellInputRef,
1898
+ type: "text",
1899
+ className: "absolute inset-0 w-full h-full px-2 py-1 bg-background text-foreground outline-none font-sans text-xs border-2 border-primary z-20",
1900
+ value: state.draftValue,
1901
+ onChange: (e) => state.setDraftValue(e.target.value),
1902
+ onBlur: () => state.commitEditing(),
1903
+ autoFocus: true
1904
+ }
1905
+ ),
1906
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FormulaHints, { inputRef: cellInputRef, value: state.draftValue, onAccept: state.setDraftValue })
1907
+ ] }) : customCellRenderer ? customCellRenderer({ row, col, cell }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1908
+ "span",
1909
+ {
1910
+ className: `truncate block max-w-full ${cell.error ? "text-destructive font-semibold" : ""}`,
1911
+ title: cell.error ? cell.errorMessage ?? cell.error : void 0,
1912
+ children: cell.error || (cell.value ?? "")
1913
+ }
1914
+ ),
1915
+ showFillHandle && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1916
+ "div",
1917
+ {
1918
+ className: "spreadsheet-fill-handle",
1919
+ "aria-label": "Fill handle",
1920
+ onMouseDown: startFill,
1921
+ onClick: (e) => e.stopPropagation(),
1922
+ style: { position: "absolute", right: 0, bottom: 0, width: 7, height: 7, background: "var(--primary, #6366f1)", cursor: "crosshair", zIndex: 25 }
1923
+ }
1924
+ )
1925
+ ]
1926
+ },
1927
+ viewCol.column.id
1928
+ );
1929
+ }),
1930
+ onAddColumnClick && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { className: "w-10 min-w-[2.5rem] bg-muted/10 border-r border-border" })
1931
+ ]
1932
+ },
1933
+ viewRow.row.id
1934
+ );
1935
+ }) })
1242
1936
  ] }) }),
1243
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: `
1937
+ menu && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1938
+ SpreadsheetContextMenu,
1939
+ {
1940
+ items: menu.items,
1941
+ x: menu.x,
1942
+ y: menu.y,
1943
+ onClose: () => {
1944
+ setMenu(null);
1945
+ gridRef.current?.focus();
1946
+ }
1947
+ }
1948
+ ),
1949
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("style", { children: `
1244
1950
  .col-resize-handle:hover .col-resize-handle-line {
1245
1951
  background-color: var(--primary, #6366f1);
1246
1952
  opacity: 0.75;
@@ -1263,10 +1969,10 @@ var SpreadsheetEditor = ({
1263
1969
  };
1264
1970
 
1265
1971
  // src/slots.tsx
1266
- var import_react13 = require("react");
1267
- var import_jsx_runtime4 = require("react/jsx-runtime");
1972
+ var import_react20 = require("react");
1973
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1268
1974
  var defaultSlots = {
1269
- Button: (props) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1975
+ Button: (props) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1270
1976
  "button",
1271
1977
  {
1272
1978
  type: "button",
@@ -1276,111 +1982,111 @@ var defaultSlots = {
1276
1982
  children: props.children
1277
1983
  }
1278
1984
  ),
1279
- Tooltip: (props) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: `pixerate-tooltip-container ${props.className || ""}`, title: String(props.content), children: props.children }),
1280
- NodeHeader: (props) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `pixerate-node-header flex items-center justify-between ${props.className || ""}`, children: [
1281
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-2", children: [
1985
+ Tooltip: (props) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `pixerate-tooltip-container ${props.className || ""}`, title: String(props.content), children: props.children }),
1986
+ NodeHeader: (props) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: `pixerate-node-header flex items-center justify-between ${props.className || ""}`, children: [
1987
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2", children: [
1282
1988
  props.icon,
1283
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "font-semibold", children: props.title })
1989
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold", children: props.title })
1284
1990
  ] }),
1285
- props.onClose && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", onClick: props.onClose, className: "opacity-70 hover:opacity-100", children: "\xD7" })
1991
+ props.onClose && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", onClick: props.onClose, className: "opacity-70 hover:opacity-100", children: "\xD7" })
1286
1992
  ] })
1287
1993
  };
1288
- var EditorSlotsContext = (0, import_react13.createContext)(defaultSlots);
1994
+ var EditorSlotsContext = (0, import_react20.createContext)(defaultSlots);
1289
1995
  function EditorSlotsProvider({ slots, children }) {
1290
- const mergedSlots = (0, import_react13.useMemo)(() => ({ ...defaultSlots, ...slots }), [slots]);
1291
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(EditorSlotsContext.Provider, { value: mergedSlots, children });
1996
+ const mergedSlots = (0, import_react20.useMemo)(() => ({ ...defaultSlots, ...slots }), [slots]);
1997
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(EditorSlotsContext.Provider, { value: mergedSlots, children });
1292
1998
  }
1293
1999
  function useEditorSlots() {
1294
- return (0, import_react13.useContext)(EditorSlotsContext);
2000
+ return (0, import_react20.useContext)(EditorSlotsContext);
1295
2001
  }
1296
2002
 
1297
2003
  // src/image-editor/useImageEditor.ts
1298
- var import_react14 = require("react");
2004
+ var import_react21 = require("react");
1299
2005
  var import_image_editor = require("@pixerate/editor/image-editor");
1300
2006
  function useImageEditor(options = {}) {
1301
- const controllerRef = (0, import_react14.useRef)(null);
2007
+ const controllerRef = (0, import_react21.useRef)(null);
1302
2008
  if (!controllerRef.current) {
1303
2009
  controllerRef.current = new import_image_editor.ImageEditorController(options);
1304
2010
  }
1305
2011
  const controller = controllerRef.current;
1306
- const [state, setState] = (0, import_react14.useState)(() => controller.getState());
1307
- const [historyTicks, setHistoryTicks] = (0, import_react14.useState)(0);
1308
- (0, import_react14.useEffect)(() => {
2012
+ const [state, setState] = (0, import_react21.useState)(() => controller.getState());
2013
+ const [historyTicks, setHistoryTicks] = (0, import_react21.useState)(0);
2014
+ (0, import_react21.useEffect)(() => {
1309
2015
  const unsub = controller.subscribe((next) => {
1310
2016
  setState(next);
1311
2017
  setHistoryTicks((t) => t + 1);
1312
2018
  });
1313
2019
  return unsub;
1314
2020
  }, [controller]);
1315
- const loadedImageRef = (0, import_react14.useRef)(options.image);
1316
- (0, import_react14.useEffect)(() => {
2021
+ const loadedImageRef = (0, import_react21.useRef)(options.image);
2022
+ (0, import_react21.useEffect)(() => {
1317
2023
  if (options.image === loadedImageRef.current) return;
1318
2024
  loadedImageRef.current = options.image;
1319
2025
  if (options.image) {
1320
2026
  controller.loadImage(options.image);
1321
2027
  }
1322
2028
  }, [options.image, controller]);
1323
- const setTool = (0, import_react14.useCallback)((tool) => controller.setTool(tool), [controller]);
1324
- const setCrop = (0, import_react14.useCallback)(
2029
+ const setTool = (0, import_react21.useCallback)((tool) => controller.setTool(tool), [controller]);
2030
+ const setCrop = (0, import_react21.useCallback)(
1325
2031
  (crop, addToHistory = true) => controller.setCrop(crop, addToHistory),
1326
2032
  [controller]
1327
2033
  );
1328
- const applyCropPreset = (0, import_react14.useCallback)((ratio) => controller.applyCropPreset(ratio), [controller]);
1329
- const resetCrop = (0, import_react14.useCallback)(() => controller.resetCrop(), [controller]);
1330
- const rotate = (0, import_react14.useCallback)((deg) => controller.rotate(deg), [controller]);
1331
- const setRotation = (0, import_react14.useCallback)((deg) => controller.setRotation(deg), [controller]);
1332
- const flipHorizontal = (0, import_react14.useCallback)(() => controller.flipHorizontal(), [controller]);
1333
- const flipVertical = (0, import_react14.useCallback)(() => controller.flipVertical(), [controller]);
1334
- const setAdjustments = (0, import_react14.useCallback)(
2034
+ const applyCropPreset = (0, import_react21.useCallback)((ratio) => controller.applyCropPreset(ratio), [controller]);
2035
+ const resetCrop = (0, import_react21.useCallback)(() => controller.resetCrop(), [controller]);
2036
+ const rotate = (0, import_react21.useCallback)((deg) => controller.rotate(deg), [controller]);
2037
+ const setRotation = (0, import_react21.useCallback)((deg) => controller.setRotation(deg), [controller]);
2038
+ const flipHorizontal = (0, import_react21.useCallback)(() => controller.flipHorizontal(), [controller]);
2039
+ const flipVertical = (0, import_react21.useCallback)(() => controller.flipVertical(), [controller]);
2040
+ const setAdjustments = (0, import_react21.useCallback)(
1335
2041
  (partial, commitToHistory = true) => controller.setAdjustments(partial, commitToHistory),
1336
2042
  [controller]
1337
2043
  );
1338
- const resetAdjustments = (0, import_react14.useCallback)(() => controller.resetAdjustments(), [controller]);
1339
- const setDepthMask = (0, import_react14.useCallback)((partial) => controller.setDepthMask(partial), [controller]);
1340
- const resetDepthMask = (0, import_react14.useCallback)(() => controller.resetDepthMask(), [controller]);
1341
- const addAnnotation = (0, import_react14.useCallback)((ann) => controller.addAnnotation(ann), [controller]);
1342
- const updateAnnotation = (0, import_react14.useCallback)(
2044
+ const resetAdjustments = (0, import_react21.useCallback)(() => controller.resetAdjustments(), [controller]);
2045
+ const setDepthMask = (0, import_react21.useCallback)((partial) => controller.setDepthMask(partial), [controller]);
2046
+ const resetDepthMask = (0, import_react21.useCallback)(() => controller.resetDepthMask(), [controller]);
2047
+ const addAnnotation = (0, import_react21.useCallback)((ann) => controller.addAnnotation(ann), [controller]);
2048
+ const updateAnnotation = (0, import_react21.useCallback)(
1343
2049
  (id, partial, commitToHistory = true) => controller.updateAnnotation(id, partial, commitToHistory),
1344
2050
  [controller]
1345
2051
  );
1346
- const removeAnnotation = (0, import_react14.useCallback)((id) => controller.removeAnnotation(id), [controller]);
1347
- const clearAnnotations = (0, import_react14.useCallback)(() => controller.clearAnnotations(), [controller]);
1348
- const selectAnnotation = (0, import_react14.useCallback)((id) => controller.selectAnnotation(id), [controller]);
1349
- const undo = (0, import_react14.useCallback)(() => controller.undo(), [controller]);
1350
- const redo = (0, import_react14.useCallback)(() => controller.redo(), [controller]);
1351
- const reset = (0, import_react14.useCallback)(() => controller.reset(), [controller]);
1352
- const zoomIn = (0, import_react14.useCallback)((factor) => controller.zoomIn(factor), [controller]);
1353
- const zoomOut = (0, import_react14.useCallback)((factor) => controller.zoomOut(factor), [controller]);
1354
- const resetZoom = (0, import_react14.useCallback)(() => controller.resetZoom(), [controller]);
1355
- const setZoom = (0, import_react14.useCallback)((zoom) => controller.setZoom(zoom), [controller]);
1356
- const setPan = (0, import_react14.useCallback)((pan) => controller.setPan(pan), [controller]);
1357
- const setComparing = (0, import_react14.useCallback)((comp) => controller.setComparing(comp), [controller]);
1358
- const loadImage = (0, import_react14.useCallback)((src) => controller.loadImage(src), [controller]);
1359
- const toDataURL = (0, import_react14.useCallback)((opts) => controller.toDataURL(opts), [controller]);
1360
- const toBlob = (0, import_react14.useCallback)((opts) => controller.toBlob(opts), [controller]);
1361
- const toJSON = (0, import_react14.useCallback)(() => controller.toJSON(), [controller]);
1362
- const loadJSON = (0, import_react14.useCallback)((data) => controller.loadJSON(data), [controller]);
1363
- const renderMask = (0, import_react14.useCallback)(
2052
+ const removeAnnotation = (0, import_react21.useCallback)((id) => controller.removeAnnotation(id), [controller]);
2053
+ const clearAnnotations = (0, import_react21.useCallback)(() => controller.clearAnnotations(), [controller]);
2054
+ const selectAnnotation = (0, import_react21.useCallback)((id) => controller.selectAnnotation(id), [controller]);
2055
+ const undo = (0, import_react21.useCallback)(() => controller.undo(), [controller]);
2056
+ const redo = (0, import_react21.useCallback)(() => controller.redo(), [controller]);
2057
+ const reset = (0, import_react21.useCallback)(() => controller.reset(), [controller]);
2058
+ const zoomIn = (0, import_react21.useCallback)((factor) => controller.zoomIn(factor), [controller]);
2059
+ const zoomOut = (0, import_react21.useCallback)((factor) => controller.zoomOut(factor), [controller]);
2060
+ const resetZoom = (0, import_react21.useCallback)(() => controller.resetZoom(), [controller]);
2061
+ const setZoom = (0, import_react21.useCallback)((zoom) => controller.setZoom(zoom), [controller]);
2062
+ const setPan = (0, import_react21.useCallback)((pan) => controller.setPan(pan), [controller]);
2063
+ const setComparing = (0, import_react21.useCallback)((comp) => controller.setComparing(comp), [controller]);
2064
+ const loadImage = (0, import_react21.useCallback)((src) => controller.loadImage(src), [controller]);
2065
+ const toDataURL = (0, import_react21.useCallback)((opts) => controller.toDataURL(opts), [controller]);
2066
+ const toBlob = (0, import_react21.useCallback)((opts) => controller.toBlob(opts), [controller]);
2067
+ const toJSON = (0, import_react21.useCallback)(() => controller.toJSON(), [controller]);
2068
+ const loadJSON = (0, import_react21.useCallback)((data) => controller.loadJSON(data), [controller]);
2069
+ const renderMask = (0, import_react21.useCallback)(
1364
2070
  (opts) => controller.renderMask(opts),
1365
2071
  [controller]
1366
2072
  );
1367
- const toMaskDataURL = (0, import_react14.useCallback)(
2073
+ const toMaskDataURL = (0, import_react21.useCallback)(
1368
2074
  (opts) => controller.toMaskDataURL(opts),
1369
2075
  [controller]
1370
2076
  );
1371
- const toSourceDataURL = (0, import_react14.useCallback)(
2077
+ const toSourceDataURL = (0, import_react21.useCallback)(
1372
2078
  (opts) => controller.toSourceDataURL(opts),
1373
2079
  [controller]
1374
2080
  );
1375
- const applyInpaintedImage = (0, import_react14.useCallback)(
2081
+ const applyInpaintedImage = (0, import_react21.useCallback)(
1376
2082
  (newDataUrl) => controller.applyInpaintedImage(newDataUrl),
1377
2083
  [controller]
1378
2084
  );
1379
- const applyBackgroundRemovedImage = (0, import_react14.useCallback)(
2085
+ const applyBackgroundRemovedImage = (0, import_react21.useCallback)(
1380
2086
  (newDataUrl) => controller.applyBackgroundRemovedImage(newDataUrl),
1381
2087
  [controller]
1382
2088
  );
1383
- return (0, import_react14.useMemo)(
2089
+ return (0, import_react21.useMemo)(
1384
2090
  () => ({
1385
2091
  controller,
1386
2092
  state,
@@ -1429,9 +2135,9 @@ function useImageEditor(options = {}) {
1429
2135
  }
1430
2136
 
1431
2137
  // src/image-editor/ImageEditor.tsx
1432
- var import_react15 = require("react");
2138
+ var import_react22 = require("react");
1433
2139
  var import_image_editor2 = require("@pixerate/editor/image-editor");
1434
- var import_jsx_runtime5 = require("react/jsx-runtime");
2140
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1435
2141
  var ImageEditor = ({
1436
2142
  editor: externalEditor,
1437
2143
  src,
@@ -1446,16 +2152,16 @@ var ImageEditor = ({
1446
2152
  const internalEditor = useImageEditor({ image: src });
1447
2153
  const editor = externalEditor || internalEditor;
1448
2154
  const { state, controller } = editor;
1449
- const canvasRef = (0, import_react15.useRef)(null);
1450
- const containerRef = (0, import_react15.useRef)(null);
1451
- const [activeTab, setActiveTab] = (0, import_react15.useState)("crop");
1452
- const [activeCropRatio, setActiveCropRatio] = (0, import_react15.useState)(null);
1453
- const [inpaintPrompt, setInpaintPrompt] = (0, import_react15.useState)("");
1454
- const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react15.useState)("annotations");
1455
- const [isRemovingBg, setIsRemovingBg] = (0, import_react15.useState)(false);
1456
- const [isInpainting, setIsInpainting] = (0, import_react15.useState)(false);
1457
- const [aiError, setAiError] = (0, import_react15.useState)(null);
1458
- const [aiSuccess, setAiSuccess] = (0, import_react15.useState)(null);
2155
+ const canvasRef = (0, import_react22.useRef)(null);
2156
+ const containerRef = (0, import_react22.useRef)(null);
2157
+ const [activeTab, setActiveTab] = (0, import_react22.useState)("crop");
2158
+ const [activeCropRatio, setActiveCropRatio] = (0, import_react22.useState)(null);
2159
+ const [inpaintPrompt, setInpaintPrompt] = (0, import_react22.useState)("");
2160
+ const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react22.useState)("annotations");
2161
+ const [isRemovingBg, setIsRemovingBg] = (0, import_react22.useState)(false);
2162
+ const [isInpainting, setIsInpainting] = (0, import_react22.useState)(false);
2163
+ const [aiError, setAiError] = (0, import_react22.useState)(null);
2164
+ const [aiSuccess, setAiSuccess] = (0, import_react22.useState)(null);
1459
2165
  const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
1460
2166
  const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
1461
2167
  const handleRemoveBackground = async () => {
@@ -1517,18 +2223,18 @@ var ImageEditor = ({
1517
2223
  setIsInpainting(false);
1518
2224
  }
1519
2225
  };
1520
- const [activeColor, setActiveColor] = (0, import_react15.useState)("#ef4444");
1521
- const [strokeWidth, setStrokeWidth] = (0, import_react15.useState)(3);
1522
- const [fontSize, setFontSize] = (0, import_react15.useState)(24);
1523
- const [textInput, setTextInput] = (0, import_react15.useState)("");
1524
- const draftAnnotationRef = (0, import_react15.useRef)(null);
1525
- const draftCropRef = (0, import_react15.useRef)(null);
1526
- const cropDragInfoRef = (0, import_react15.useRef)(null);
1527
- const annotationDragInfoRef = (0, import_react15.useRef)(null);
1528
- const isDrawingRef = (0, import_react15.useRef)(false);
1529
- const currentPathRef = (0, import_react15.useRef)([]);
1530
- const dragStartPointRef = (0, import_react15.useRef)(null);
1531
- const renderCanvas = (0, import_react15.useCallback)(
2226
+ const [activeColor, setActiveColor] = (0, import_react22.useState)("#ef4444");
2227
+ const [strokeWidth, setStrokeWidth] = (0, import_react22.useState)(3);
2228
+ const [fontSize, setFontSize] = (0, import_react22.useState)(24);
2229
+ const [textInput, setTextInput] = (0, import_react22.useState)("");
2230
+ const draftAnnotationRef = (0, import_react22.useRef)(null);
2231
+ const draftCropRef = (0, import_react22.useRef)(null);
2232
+ const cropDragInfoRef = (0, import_react22.useRef)(null);
2233
+ const annotationDragInfoRef = (0, import_react22.useRef)(null);
2234
+ const isDrawingRef = (0, import_react22.useRef)(false);
2235
+ const currentPathRef = (0, import_react22.useRef)([]);
2236
+ const dragStartPointRef = (0, import_react22.useRef)(null);
2237
+ const renderCanvas = (0, import_react22.useCallback)(
1532
2238
  async (draftAnnotation, draftCrop) => {
1533
2239
  const canvas = canvasRef.current;
1534
2240
  const container = containerRef.current;
@@ -1547,7 +2253,7 @@ var ImageEditor = ({
1547
2253
  },
1548
2254
  [controller, activeTab]
1549
2255
  );
1550
- (0, import_react15.useEffect)(() => {
2256
+ (0, import_react22.useEffect)(() => {
1551
2257
  const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
1552
2258
  const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
1553
2259
  const animId = raf(() => {
@@ -1555,12 +2261,12 @@ var ImageEditor = ({
1555
2261
  });
1556
2262
  return () => caf(animId);
1557
2263
  }, [renderCanvas, state]);
1558
- (0, import_react15.useEffect)(() => {
2264
+ (0, import_react22.useEffect)(() => {
1559
2265
  if (activeTab === "crop" && editor.state.activeTool !== "crop") {
1560
2266
  editor.setTool("crop");
1561
2267
  }
1562
2268
  }, [activeTab, editor]);
1563
- (0, import_react15.useEffect)(() => {
2269
+ (0, import_react22.useEffect)(() => {
1564
2270
  const container = containerRef.current;
1565
2271
  if (!container) return;
1566
2272
  if (typeof ResizeObserver !== "undefined") {
@@ -1918,15 +2624,15 @@ var ImageEditor = ({
1918
2624
  link.click();
1919
2625
  }
1920
2626
  };
1921
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2627
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1922
2628
  "div",
1923
2629
  {
1924
2630
  className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
1925
2631
  style,
1926
2632
  children: [
1927
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-wrap items-center justify-between px-4 py-3 bg-slate-950/80 border-b border-slate-800 gap-3", children: [
1928
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
1929
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2633
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-wrap items-center justify-between px-4 py-3 bg-slate-950/80 border-b border-slate-800 gap-3", children: [
2634
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-1 bg-slate-900 p-1 rounded-lg border border-slate-800 text-xs", children: [
2635
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1930
2636
  "button",
1931
2637
  {
1932
2638
  type: "button",
@@ -1938,7 +2644,7 @@ var ImageEditor = ({
1938
2644
  children: "Transform & Crop"
1939
2645
  }
1940
2646
  ),
1941
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2647
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1942
2648
  "button",
1943
2649
  {
1944
2650
  type: "button",
@@ -1950,7 +2656,7 @@ var ImageEditor = ({
1950
2656
  children: "Adjustments"
1951
2657
  }
1952
2658
  ),
1953
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2659
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1954
2660
  "button",
1955
2661
  {
1956
2662
  type: "button",
@@ -1962,7 +2668,7 @@ var ImageEditor = ({
1962
2668
  children: "Annotations"
1963
2669
  }
1964
2670
  ),
1965
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2671
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1966
2672
  "button",
1967
2673
  {
1968
2674
  type: "button",
@@ -1974,7 +2680,7 @@ var ImageEditor = ({
1974
2680
  children: "Depth Mask"
1975
2681
  }
1976
2682
  ),
1977
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2683
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1978
2684
  "button",
1979
2685
  {
1980
2686
  type: "button",
@@ -1984,14 +2690,14 @@ var ImageEditor = ({
1984
2690
  },
1985
2691
  className: `px-3 py-1.5 rounded-md font-medium transition-colors flex items-center gap-1.5 ${activeTab === "ai" ? "bg-indigo-600 text-white shadow" : "text-slate-400 hover:text-slate-200"}`,
1986
2692
  children: [
1987
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
2693
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
1988
2694
  "AI Tools"
1989
2695
  ]
1990
2696
  }
1991
2697
  )
1992
2698
  ] }),
1993
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
1994
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2699
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
2700
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1995
2701
  "button",
1996
2702
  {
1997
2703
  type: "button",
@@ -2002,7 +2708,7 @@ var ImageEditor = ({
2002
2708
  children: "\u21A9"
2003
2709
  }
2004
2710
  ),
2005
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2711
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2006
2712
  "button",
2007
2713
  {
2008
2714
  type: "button",
@@ -2013,7 +2719,7 @@ var ImageEditor = ({
2013
2719
  children: "\u21AA"
2014
2720
  }
2015
2721
  ),
2016
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2722
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2017
2723
  "button",
2018
2724
  {
2019
2725
  type: "button",
@@ -2022,8 +2728,8 @@ var ImageEditor = ({
2022
2728
  children: "Reset"
2023
2729
  }
2024
2730
  ),
2025
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2026
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2731
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2732
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2027
2733
  "button",
2028
2734
  {
2029
2735
  type: "button",
@@ -2033,11 +2739,11 @@ var ImageEditor = ({
2033
2739
  children: "-"
2034
2740
  }
2035
2741
  ),
2036
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
2742
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
2037
2743
  Math.round(state.zoom * 100),
2038
2744
  "%"
2039
2745
  ] }),
2040
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2746
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2041
2747
  "button",
2042
2748
  {
2043
2749
  type: "button",
@@ -2047,8 +2753,8 @@ var ImageEditor = ({
2047
2753
  children: "+"
2048
2754
  }
2049
2755
  ),
2050
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2051
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2756
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-4 w-px bg-slate-800 mx-1" }),
2757
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2052
2758
  "button",
2053
2759
  {
2054
2760
  type: "button",
@@ -2059,7 +2765,7 @@ var ImageEditor = ({
2059
2765
  children: "Hold Compare"
2060
2766
  }
2061
2767
  ),
2062
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2768
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2063
2769
  "button",
2064
2770
  {
2065
2771
  type: "button",
@@ -2070,13 +2776,13 @@ var ImageEditor = ({
2070
2776
  )
2071
2777
  ] })
2072
2778
  ] }),
2073
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
2074
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2779
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]", children: [
2780
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2075
2781
  "div",
2076
2782
  {
2077
2783
  ref: containerRef,
2078
2784
  className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
2079
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2785
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2080
2786
  "canvas",
2081
2787
  {
2082
2788
  ref: canvasRef,
@@ -2089,11 +2795,11 @@ var ImageEditor = ({
2089
2795
  )
2090
2796
  }
2091
2797
  ),
2092
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w-full md:w-80 bg-slate-900/90 border-t md:border-t-0 md:border-l border-slate-800 p-4 overflow-y-auto h-auto md:h-full md:max-h-[560px]", children: [
2093
- activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2094
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
2095
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
2096
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2798
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "w-full md:w-80 bg-slate-900/90 border-t md:border-t-0 md:border-l border-slate-800 p-4 overflow-y-auto h-auto md:h-full md:max-h-[560px]", children: [
2799
+ activeTab === "crop" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2800
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Aspect Ratio Presets" }),
2801
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "grid grid-cols-3 gap-2", children: [
2802
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2097
2803
  "button",
2098
2804
  {
2099
2805
  type: "button",
@@ -2105,7 +2811,7 @@ var ImageEditor = ({
2105
2811
  children: "Freeform"
2106
2812
  }
2107
2813
  ),
2108
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2814
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2109
2815
  "button",
2110
2816
  {
2111
2817
  type: "button",
@@ -2117,7 +2823,7 @@ var ImageEditor = ({
2117
2823
  children: "1:1 Square"
2118
2824
  }
2119
2825
  ),
2120
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2826
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2121
2827
  "button",
2122
2828
  {
2123
2829
  type: "button",
@@ -2129,7 +2835,7 @@ var ImageEditor = ({
2129
2835
  children: "4:3 Standard"
2130
2836
  }
2131
2837
  ),
2132
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2838
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2133
2839
  "button",
2134
2840
  {
2135
2841
  type: "button",
@@ -2141,7 +2847,7 @@ var ImageEditor = ({
2141
2847
  children: "16:9 Wide"
2142
2848
  }
2143
2849
  ),
2144
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2850
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2145
2851
  "button",
2146
2852
  {
2147
2853
  type: "button",
@@ -2153,7 +2859,7 @@ var ImageEditor = ({
2153
2859
  children: "3:2 Photo"
2154
2860
  }
2155
2861
  ),
2156
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2862
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2157
2863
  "button",
2158
2864
  {
2159
2865
  type: "button",
@@ -2166,10 +2872,10 @@ var ImageEditor = ({
2166
2872
  }
2167
2873
  )
2168
2874
  ] }),
2169
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2170
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
2171
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
2172
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2875
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2876
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Orientation & Flips" }),
2877
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
2878
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2173
2879
  "button",
2174
2880
  {
2175
2881
  type: "button",
@@ -2178,7 +2884,7 @@ var ImageEditor = ({
2178
2884
  children: "Rotate -90\xB0"
2179
2885
  }
2180
2886
  ),
2181
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2887
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2182
2888
  "button",
2183
2889
  {
2184
2890
  type: "button",
@@ -2187,7 +2893,7 @@ var ImageEditor = ({
2187
2893
  children: "Rotate +90\xB0"
2188
2894
  }
2189
2895
  ),
2190
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2896
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2191
2897
  "button",
2192
2898
  {
2193
2899
  type: "button",
@@ -2196,7 +2902,7 @@ var ImageEditor = ({
2196
2902
  children: "Flip Horizontal"
2197
2903
  }
2198
2904
  ),
2199
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2905
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2200
2906
  "button",
2201
2907
  {
2202
2908
  type: "button",
@@ -2207,10 +2913,10 @@ var ImageEditor = ({
2207
2913
  )
2208
2914
  ] })
2209
2915
  ] }),
2210
- activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2211
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
2212
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
2213
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2916
+ activeTab === "adjust" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2917
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
2918
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Color Adjustments" }),
2919
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2214
2920
  "button",
2215
2921
  {
2216
2922
  type: "button",
@@ -2220,12 +2926,12 @@ var ImageEditor = ({
2220
2926
  }
2221
2927
  )
2222
2928
  ] }),
2223
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
2224
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2225
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Brightness" }),
2226
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: state.adjustments.brightness })
2929
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
2930
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2931
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Brightness" }),
2932
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.adjustments.brightness })
2227
2933
  ] }),
2228
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2934
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2229
2935
  "input",
2230
2936
  {
2231
2937
  type: "range",
@@ -2237,12 +2943,12 @@ var ImageEditor = ({
2237
2943
  }
2238
2944
  )
2239
2945
  ] }),
2240
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
2241
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2242
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Contrast" }),
2243
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: state.adjustments.contrast })
2946
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
2947
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2948
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Contrast" }),
2949
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.adjustments.contrast })
2244
2950
  ] }),
2245
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2951
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2246
2952
  "input",
2247
2953
  {
2248
2954
  type: "range",
@@ -2254,12 +2960,12 @@ var ImageEditor = ({
2254
2960
  }
2255
2961
  )
2256
2962
  ] }),
2257
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
2258
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2259
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Saturation" }),
2260
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: state.adjustments.saturation })
2963
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
2964
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2965
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Saturation" }),
2966
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.adjustments.saturation })
2261
2967
  ] }),
2262
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2968
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2263
2969
  "input",
2264
2970
  {
2265
2971
  type: "range",
@@ -2271,12 +2977,12 @@ var ImageEditor = ({
2271
2977
  }
2272
2978
  )
2273
2979
  ] }),
2274
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
2275
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2276
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Exposure" }),
2277
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: state.adjustments.exposure })
2980
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
2981
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2982
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Exposure" }),
2983
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.adjustments.exposure })
2278
2984
  ] }),
2279
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2985
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2280
2986
  "input",
2281
2987
  {
2282
2988
  type: "range",
@@ -2288,12 +2994,12 @@ var ImageEditor = ({
2288
2994
  }
2289
2995
  )
2290
2996
  ] }),
2291
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
2292
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2293
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Warmth / Temperature" }),
2294
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: state.adjustments.temperature })
2997
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
2998
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2999
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Warmth / Temperature" }),
3000
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.adjustments.temperature })
2295
3001
  ] }),
2296
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3002
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2297
3003
  "input",
2298
3004
  {
2299
3005
  type: "range",
@@ -2305,15 +3011,15 @@ var ImageEditor = ({
2305
3011
  }
2306
3012
  )
2307
3013
  ] }),
2308
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
2309
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2310
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Blur" }),
2311
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-mono", children: [
3014
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
3015
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3016
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Blur" }),
3017
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-mono", children: [
2312
3018
  state.adjustments.blur,
2313
3019
  "px"
2314
3020
  ] })
2315
3021
  ] }),
2316
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3022
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2317
3023
  "input",
2318
3024
  {
2319
3025
  type: "range",
@@ -2325,15 +3031,15 @@ var ImageEditor = ({
2325
3031
  }
2326
3032
  )
2327
3033
  ] }),
2328
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
2329
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2330
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Opacity" }),
2331
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-mono", children: [
3034
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
3035
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3036
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Opacity" }),
3037
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-mono", children: [
2332
3038
  Math.round(state.adjustments.opacity * 100),
2333
3039
  "%"
2334
3040
  ] })
2335
3041
  ] }),
2336
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3042
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2337
3043
  "input",
2338
3044
  {
2339
3045
  type: "range",
@@ -2347,9 +3053,9 @@ var ImageEditor = ({
2347
3053
  )
2348
3054
  ] })
2349
3055
  ] }),
2350
- activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2351
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
2352
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3056
+ activeTab === "annotate" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
3057
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Draw & Annotate" }),
3058
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "grid grid-cols-3 gap-1.5", children: ["pen", "rect", "circle", "arrow", "line"].map((t) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2353
3059
  "button",
2354
3060
  {
2355
3061
  type: "button",
@@ -2359,9 +3065,9 @@ var ImageEditor = ({
2359
3065
  },
2360
3066
  t
2361
3067
  )) }),
2362
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
2363
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "text-slate-400", children: "Color:" }),
2364
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3068
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2 mt-2", children: [
3069
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("label", { className: "text-slate-400", children: "Color:" }),
3070
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2365
3071
  "input",
2366
3072
  {
2367
3073
  type: "color",
@@ -2370,15 +3076,15 @@ var ImageEditor = ({
2370
3076
  className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
2371
3077
  }
2372
3078
  ),
2373
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex-1 ml-2", children: [
2374
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
2375
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Width:" }),
2376
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-mono", children: [
3079
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex-1 ml-2", children: [
3080
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-0.5", children: [
3081
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Width:" }),
3082
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-mono", children: [
2377
3083
  strokeWidth,
2378
3084
  "px"
2379
3085
  ] })
2380
3086
  ] }),
2381
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3087
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2382
3088
  "input",
2383
3089
  {
2384
3090
  type: "range",
@@ -2391,10 +3097,10 @@ var ImageEditor = ({
2391
3097
  )
2392
3098
  ] })
2393
3099
  ] }),
2394
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2395
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
2396
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex gap-2", children: [
2397
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3100
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
3101
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Add Text" }),
3102
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex gap-2", children: [
3103
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2398
3104
  "input",
2399
3105
  {
2400
3106
  type: "text",
@@ -2405,7 +3111,7 @@ var ImageEditor = ({
2405
3111
  className: "flex-1 bg-slate-950 border border-slate-700 rounded-lg px-2.5 py-1.5 text-xs text-slate-100 placeholder-slate-500 focus:outline-none focus:border-indigo-500"
2406
3112
  }
2407
3113
  ),
2408
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3114
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2409
3115
  "button",
2410
3116
  {
2411
3117
  type: "button",
@@ -2415,14 +3121,14 @@ var ImageEditor = ({
2415
3121
  }
2416
3122
  )
2417
3123
  ] }),
2418
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
2419
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Font Size:" }),
2420
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-mono", children: [
3124
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between text-slate-400", children: [
3125
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Font Size:" }),
3126
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-mono", children: [
2421
3127
  fontSize,
2422
3128
  "px"
2423
3129
  ] })
2424
3130
  ] }),
2425
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3131
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2426
3132
  "input",
2427
3133
  {
2428
3134
  type: "range",
@@ -2433,14 +3139,14 @@ var ImageEditor = ({
2433
3139
  className: "w-full accent-indigo-500"
2434
3140
  }
2435
3141
  ),
2436
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
2437
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
2438
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-slate-400", children: [
3142
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-px bg-slate-800 my-1" }),
3143
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
3144
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-slate-400", children: [
2439
3145
  "Layers (",
2440
3146
  state.annotations.length,
2441
3147
  ")"
2442
3148
  ] }),
2443
- state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3149
+ state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2444
3150
  "button",
2445
3151
  {
2446
3152
  type: "button",
@@ -2449,7 +3155,7 @@ var ImageEditor = ({
2449
3155
  children: "Delete Selected"
2450
3156
  }
2451
3157
  ),
2452
- state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3158
+ state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2453
3159
  "button",
2454
3160
  {
2455
3161
  type: "button",
@@ -2460,10 +3166,10 @@ var ImageEditor = ({
2460
3166
  )
2461
3167
  ] })
2462
3168
  ] }),
2463
- activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
2464
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
2465
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
2466
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3169
+ activeTab === "depth" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-3 text-xs", children: [
3170
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
3171
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px]", children: "Depth Masking" }),
3172
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2467
3173
  "button",
2468
3174
  {
2469
3175
  type: "button",
@@ -2473,8 +3179,8 @@ var ImageEditor = ({
2473
3179
  }
2474
3180
  )
2475
3181
  ] }),
2476
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
2477
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3182
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300", children: [
3183
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2478
3184
  "input",
2479
3185
  {
2480
3186
  type: "checkbox",
@@ -2483,12 +3189,12 @@ var ImageEditor = ({
2483
3189
  className: "rounded accent-indigo-500"
2484
3190
  }
2485
3191
  ),
2486
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Enable Depth / Alpha Mask" })
3192
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Enable Depth / Alpha Mask" })
2487
3193
  ] }),
2488
- state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
2489
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
2490
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
2491
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3194
+ state.depthMask.enabled && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
3195
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
3196
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("label", { className: "text-slate-400 block mb-1", children: "Mask Image URL:" }),
3197
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2492
3198
  "input",
2493
3199
  {
2494
3200
  type: "text",
@@ -2499,8 +3205,8 @@ var ImageEditor = ({
2499
3205
  }
2500
3206
  )
2501
3207
  ] }),
2502
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex gap-2", children: [
2503
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3208
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex gap-2", children: [
3209
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2504
3210
  "button",
2505
3211
  {
2506
3212
  type: "button",
@@ -2509,7 +3215,7 @@ var ImageEditor = ({
2509
3215
  children: "Threshold Mode"
2510
3216
  }
2511
3217
  ),
2512
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3218
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2513
3219
  "button",
2514
3220
  {
2515
3221
  type: "button",
@@ -2519,12 +3225,12 @@ var ImageEditor = ({
2519
3225
  }
2520
3226
  )
2521
3227
  ] }),
2522
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
2523
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2524
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Depth Start (Lower):" }),
2525
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
3228
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
3229
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3230
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Depth Start (Lower):" }),
3231
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[0] })
2526
3232
  ] }),
2527
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3233
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2528
3234
  "input",
2529
3235
  {
2530
3236
  type: "range",
@@ -2538,12 +3244,12 @@ var ImageEditor = ({
2538
3244
  }
2539
3245
  )
2540
3246
  ] }),
2541
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
2542
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2543
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Depth Stop (Upper):" }),
2544
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
3247
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
3248
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3249
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Depth Stop (Upper):" }),
3250
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.depthMask.depthRange[1] })
2545
3251
  ] }),
2546
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3252
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2547
3253
  "input",
2548
3254
  {
2549
3255
  type: "range",
@@ -2557,12 +3263,12 @@ var ImageEditor = ({
2557
3263
  }
2558
3264
  )
2559
3265
  ] }),
2560
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
2561
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
2562
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Softness:" }),
2563
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
3266
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
3267
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
3268
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Softness:" }),
3269
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.depthMask.softness })
2564
3270
  ] }),
2565
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3271
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2566
3272
  "input",
2567
3273
  {
2568
3274
  type: "range",
@@ -2574,8 +3280,8 @@ var ImageEditor = ({
2574
3280
  }
2575
3281
  )
2576
3282
  ] }),
2577
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
2578
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3283
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer text-slate-300 mt-1", children: [
3284
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2579
3285
  "input",
2580
3286
  {
2581
3287
  type: "checkbox",
@@ -2584,52 +3290,52 @@ var ImageEditor = ({
2584
3290
  className: "rounded accent-indigo-500"
2585
3291
  }
2586
3292
  ),
2587
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Invert Mask" })
3293
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Invert Mask" })
2588
3294
  ] })
2589
3295
  ] })
2590
3296
  ] }),
2591
- activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
2592
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
2593
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
2594
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
2595
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" }) }),
3297
+ activeTab === "ai" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-4 text-xs", children: [
3298
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3299
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
3300
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3301
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-3.5 h-3.5 text-indigo-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M6 3v12M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" }) }),
2596
3302
  "Background Removal"
2597
3303
  ] }),
2598
- isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-indigo-900/60 text-indigo-300 animate-pulse", children: "Removing..." })
3304
+ isRemovingBg && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-indigo-900/60 text-indigo-300 animate-pulse", children: "Removing..." })
2599
3305
  ] }),
2600
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
2601
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3306
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Isolate foreground subject with AI alpha transparency segmentation." }),
3307
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2602
3308
  "button",
2603
3309
  {
2604
3310
  type: "button",
2605
3311
  onClick: handleRemoveBackground,
2606
3312
  disabled: isRemovingBg || isInpainting,
2607
3313
  className: "mt-1 px-3 py-2 rounded-lg bg-indigo-600 hover:bg-indigo-500 disabled:opacity-50 text-white font-medium shadow transition-colors flex items-center justify-center gap-2",
2608
- children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
2609
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
3314
+ children: isRemovingBg ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
3315
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
2610
3316
  "Removing Background..."
2611
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
2612
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
3317
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
3318
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
2613
3319
  "Remove Background"
2614
3320
  ] })
2615
3321
  }
2616
3322
  )
2617
3323
  ] }),
2618
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
2619
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between", children: [
2620
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
2621
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
2622
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m21.64 3.64-1.28-1.28a1.2 1.2 0 0 0-1.7 0l-9.72 9.72-1.94 4.86 4.86-1.94 9.72-9.72a1.2 1.2 0 0 0 .06-1.64z" }),
2623
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m14 7 3 3" })
3324
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "p-3 rounded-lg bg-slate-950/60 border border-slate-800 flex flex-col gap-2.5", children: [
3325
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
3326
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-semibold text-slate-200 uppercase tracking-wider text-[11px] flex items-center gap-1.5", children: [
3327
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { className: "w-3.5 h-3.5 text-purple-400", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
3328
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "m21.64 3.64-1.28-1.28a1.2 1.2 0 0 0-1.7 0l-9.72 9.72-1.94 4.86 4.86-1.94 9.72-9.72a1.2 1.2 0 0 0 .06-1.64z" }),
3329
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "m14 7 3 3" })
2624
3330
  ] }),
2625
3331
  "Generative Inpainting"
2626
3332
  ] }),
2627
- isInpainting && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-900/60 text-purple-300 animate-pulse", children: "Inpainting..." })
3333
+ isInpainting && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-purple-900/60 text-purple-300 animate-pulse", children: "Inpainting..." })
2628
3334
  ] }),
2629
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
2630
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-1", children: [
2631
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
2632
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3335
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-slate-400 text-[11px] leading-relaxed", children: "Replace, modify, or fill selected regions using prompt-guided generative inpainting." }),
3336
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-1", children: [
3337
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("label", { htmlFor: "ai-inpaint-prompt-react", className: "text-slate-300 text-[11px] font-medium", children: "Prompt" }),
3338
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2633
3339
  "textarea",
2634
3340
  {
2635
3341
  id: "ai-inpaint-prompt-react",
@@ -2641,10 +3347,10 @@ var ImageEditor = ({
2641
3347
  }
2642
3348
  )
2643
3349
  ] }),
2644
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col gap-1", children: [
2645
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
2646
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
2647
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3350
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-1", children: [
3351
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-slate-300 text-[11px] font-medium", children: "Target Mask Region" }),
3352
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "grid grid-cols-2 gap-1.5", children: [
3353
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2648
3354
  "button",
2649
3355
  {
2650
3356
  type: "button",
@@ -2657,7 +3363,7 @@ var ImageEditor = ({
2657
3363
  ]
2658
3364
  }
2659
3365
  ),
2660
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3366
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2661
3367
  "button",
2662
3368
  {
2663
3369
  type: "button",
@@ -2672,25 +3378,25 @@ var ImageEditor = ({
2672
3378
  )
2673
3379
  ] })
2674
3380
  ] }),
2675
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3381
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2676
3382
  "button",
2677
3383
  {
2678
3384
  type: "button",
2679
3385
  onClick: handleInpaint,
2680
3386
  disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
2681
3387
  className: "mt-1 px-3 py-2 rounded-lg bg-purple-600 hover:bg-purple-500 disabled:opacity-50 text-white font-medium shadow transition-colors flex items-center justify-center gap-2",
2682
- children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
2683
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
3388
+ children: isInpainting ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
3389
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin" }),
2684
3390
  "Generating Inpaint..."
2685
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
2686
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
3391
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
3392
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" }) }),
2687
3393
  "Apply Inpainting"
2688
3394
  ] })
2689
3395
  }
2690
3396
  )
2691
3397
  ] }),
2692
- aiError && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
2693
- aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
3398
+ aiError && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "p-2.5 rounded-lg bg-rose-950/60 border border-rose-800 text-rose-300 text-[11px]", children: aiError }),
3399
+ aiSuccess && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "p-2.5 rounded-lg bg-emerald-950/60 border border-emerald-800 text-emerald-300 text-[11px]", children: aiSuccess })
2694
3400
  ] })
2695
3401
  ] })
2696
3402
  ] })
@@ -2698,27 +3404,356 @@ var ImageEditor = ({
2698
3404
  }
2699
3405
  );
2700
3406
  };
3407
+
3408
+ // src/review/useReview.ts
3409
+ var import_react23 = require("react");
3410
+ var import_editor13 = require("@pixerate/editor");
3411
+ var EMPTY_COMMENTS = Object.freeze({
3412
+ threads: [],
3413
+ activeThreadId: null
3414
+ });
3415
+ var EMPTY_TRACK_CHANGES = Object.freeze({
3416
+ enabled: false,
3417
+ author: { id: "anonymous", name: "Anonymous" },
3418
+ changes: [],
3419
+ currentChangeId: null
3420
+ });
3421
+ var noopUnsubscribe = () => {
3422
+ };
3423
+ function isCommentStore(value) {
3424
+ return !!value && typeof value.getSnapshot === "function" && typeof value.createThread === "function";
3425
+ }
3426
+ function useComments(source) {
3427
+ const store = isCommentStore(source) ? source : (0, import_editor13.getCommentStore)(source);
3428
+ const subscribe = (0, import_react23.useCallback)(
3429
+ (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
3430
+ [store]
3431
+ );
3432
+ const getSnapshot = () => store?.getSnapshot() ?? EMPTY_COMMENTS;
3433
+ const snapshot = (0, import_react23.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
3434
+ return (0, import_react23.useMemo)(() => ({ ...snapshot, store }), [snapshot, store]);
3435
+ }
3436
+ function useTrackChanges(editor) {
3437
+ const store = (0, import_editor13.getTrackChangesStore)(editor ?? null);
3438
+ const subscribe = (0, import_react23.useCallback)(
3439
+ (onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
3440
+ [store]
3441
+ );
3442
+ const getSnapshot = () => store?.getSnapshot() ?? EMPTY_TRACK_CHANGES;
3443
+ const snapshot = (0, import_react23.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
3444
+ return (0, import_react23.useMemo)(() => {
3445
+ const run = (fn) => () => {
3446
+ if (editor && !editor.isDestroyed) fn(editor);
3447
+ };
3448
+ return {
3449
+ ...snapshot,
3450
+ currentChange: snapshot.changes.find((c) => c.id === snapshot.currentChangeId) ?? null,
3451
+ setEnabled: (enabled) => run((e) => e.commands.setTrackChanges(enabled))(),
3452
+ toggle: run((e) => e.commands.toggleTrackChanges()),
3453
+ accept: (id) => run((e) => e.commands.acceptChange(id))(),
3454
+ reject: (id) => run((e) => e.commands.rejectChange(id))(),
3455
+ acceptAll: run((e) => e.commands.acceptAllChanges()),
3456
+ rejectAll: run((e) => e.commands.rejectAllChanges()),
3457
+ next: run((e) => e.chain().focus().selectNextChange().run()),
3458
+ previous: run((e) => e.chain().focus().selectPreviousChange().run())
3459
+ };
3460
+ }, [snapshot, editor]);
3461
+ }
3462
+
3463
+ // src/review/CommentsPanel.tsx
3464
+ var import_react24 = require("react");
3465
+ var import_editor14 = require("@pixerate/editor");
3466
+ var import_jsx_runtime11 = require("react/jsx-runtime");
3467
+ var buttonClass = "rounded px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50";
3468
+ var primaryButtonClass = "rounded px-2 py-1 text-xs bg-primary/10 text-primary hover:bg-primary/20 disabled:opacity-50";
3469
+ var textareaClass = "w-full resize-y rounded-md border border-input bg-background p-2 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-primary";
3470
+ var CommentsPanel = ({
3471
+ editor,
3472
+ store: storeProp,
3473
+ author: authorProp,
3474
+ showResolved: showResolvedInitial = false,
3475
+ className = "flex flex-col gap-2 text-sm text-foreground",
3476
+ formatTime = (t) => (0, import_editor14.formatReviewTime)(t),
3477
+ emptyMessage = "No comments yet. Select text and add a comment."
3478
+ }) => {
3479
+ const { threads, activeThreadId, store } = useComments(storeProp ?? editor);
3480
+ const [showResolved, setShowResolved] = (0, import_react24.useState)(showResolvedInitial);
3481
+ const author = authorProp ?? (0, import_editor14.getCommentAuthor)(editor) ?? { id: "anonymous", name: "Anonymous" };
3482
+ const visible = threads.filter((t) => showResolved || !t.resolved);
3483
+ const resolvedCount = threads.filter((t) => t.resolved).length;
3484
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("aside", { className, "aria-label": "Comments", children: [
3485
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
3486
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "text-xs font-medium text-muted-foreground", children: [
3487
+ threads.length - resolvedCount,
3488
+ " open",
3489
+ resolvedCount > 0 ? ` \xB7 ${resolvedCount} resolved` : ""
3490
+ ] }),
3491
+ resolvedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3492
+ "button",
3493
+ {
3494
+ type: "button",
3495
+ className: buttonClass,
3496
+ "aria-pressed": showResolved,
3497
+ onClick: () => setShowResolved((v) => !v),
3498
+ children: showResolved ? "Hide resolved" : "Show resolved"
3499
+ }
3500
+ )
3501
+ ] }),
3502
+ visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("ul", { className: "flex flex-col gap-2", role: "list", children: visible.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3503
+ CommentThreadCard,
3504
+ {
3505
+ thread,
3506
+ active: thread.id === activeThreadId,
3507
+ editor,
3508
+ store,
3509
+ author,
3510
+ formatTime
3511
+ },
3512
+ thread.id
3513
+ )) })
3514
+ ] });
3515
+ };
3516
+ var CommentThreadCard = ({
3517
+ thread,
3518
+ active,
3519
+ editor,
3520
+ store,
3521
+ author,
3522
+ formatTime
3523
+ }) => {
3524
+ const [draft, setDraft] = (0, import_react24.useState)("");
3525
+ const isDraft = thread.body === "";
3526
+ const quote = thread.anchor?.quote ?? thread.lastQuote ?? "";
3527
+ const live = editor && !editor.isDestroyed ? editor : null;
3528
+ const focus = () => {
3529
+ if (!active) {
3530
+ if (live && !thread.orphaned) live.commands.focusComment(thread.id);
3531
+ else store?.setActiveThread(thread.id);
3532
+ }
3533
+ };
3534
+ const remove = () => {
3535
+ if (live) live.commands.deleteComment(thread.id);
3536
+ else store?.deleteThread(thread.id);
3537
+ };
3538
+ const setResolved = (resolved) => {
3539
+ if (live) live.commands.resolveComment(thread.id, resolved);
3540
+ else store?.resolveThread(thread.id, resolved, author);
3541
+ };
3542
+ const submit = () => {
3543
+ const body = draft.trim();
3544
+ if (!body || !store) return;
3545
+ if (isDraft) store.editComment(thread.id, body);
3546
+ else store.addReply(thread.id, { body, author });
3547
+ setDraft("");
3548
+ };
3549
+ const stop = (e) => e.stopPropagation();
3550
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3551
+ "li",
3552
+ {
3553
+ className: `flex flex-col gap-2 rounded-md border bg-background p-3 cursor-pointer ${active ? "border-primary ring-1 ring-primary" : "border-border"} ${thread.resolved ? "opacity-70" : ""}`,
3554
+ "data-thread-id": thread.id,
3555
+ "data-active": active || void 0,
3556
+ "aria-current": active || void 0,
3557
+ tabIndex: 0,
3558
+ onClick: focus,
3559
+ onKeyDown: (e) => {
3560
+ if (e.target === e.currentTarget && (e.key === "Enter" || e.key === " ")) {
3561
+ e.preventDefault();
3562
+ focus();
3563
+ }
3564
+ },
3565
+ children: [
3566
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-baseline justify-between gap-2", children: [
3567
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-medium", children: thread.author.name }),
3568
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-xs text-muted-foreground", children: formatTime(thread.createdAt) })
3569
+ ] }),
3570
+ quote && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("blockquote", { className: "border-l-2 border-border pl-2 text-xs text-muted-foreground line-clamp-2", children: quote }),
3571
+ thread.orphaned && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-xs text-destructive", children: "The commented text was deleted." }),
3572
+ thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-xs text-muted-foreground", children: "Resolved" }),
3573
+ !isDraft && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "whitespace-pre-wrap break-words", children: thread.body }),
3574
+ thread.replies.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("ul", { className: "flex flex-col gap-2 border-l border-border pl-3", role: "list", children: thread.replies.map((reply) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("li", { className: "flex flex-col gap-0.5", "data-reply-id": reply.id, children: [
3575
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "text-xs", children: [
3576
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-medium", children: reply.author.name }),
3577
+ " ",
3578
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-muted-foreground", children: formatTime(reply.createdAt) })
3579
+ ] }),
3580
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "whitespace-pre-wrap break-words", children: reply.body })
3581
+ ] }, reply.id)) }),
3582
+ (active || isDraft) && !thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-1", onClick: stop, children: [
3583
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3584
+ "textarea",
3585
+ {
3586
+ className: textareaClass,
3587
+ rows: 2,
3588
+ value: draft,
3589
+ "aria-label": isDraft ? "Comment" : "Reply",
3590
+ placeholder: isDraft ? "Add a comment\u2026" : "Reply\u2026",
3591
+ autoFocus: isDraft,
3592
+ onChange: (e) => setDraft(e.target.value),
3593
+ onKeyDown: (e) => {
3594
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
3595
+ e.preventDefault();
3596
+ submit();
3597
+ }
3598
+ }
3599
+ }
3600
+ ),
3601
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex justify-end gap-1", children: [
3602
+ isDraft && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: buttonClass, onClick: remove, children: "Cancel" }),
3603
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3604
+ "button",
3605
+ {
3606
+ type: "button",
3607
+ className: primaryButtonClass,
3608
+ disabled: !draft.trim(),
3609
+ onClick: submit,
3610
+ children: isDraft ? "Comment" : "Reply"
3611
+ }
3612
+ )
3613
+ ] })
3614
+ ] }),
3615
+ !isDraft && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex justify-end gap-1", onClick: stop, children: [
3616
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: buttonClass, onClick: () => setResolved(!thread.resolved), children: thread.resolved ? "Reopen" : "Resolve" }),
3617
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3618
+ "button",
3619
+ {
3620
+ type: "button",
3621
+ className: `${buttonClass} hover:text-destructive`,
3622
+ onClick: remove,
3623
+ children: "Delete"
3624
+ }
3625
+ )
3626
+ ] })
3627
+ ]
3628
+ }
3629
+ );
3630
+ };
3631
+
3632
+ // src/review/ReviewToolbar.tsx
3633
+ var import_jsx_runtime12 = require("react/jsx-runtime");
3634
+ var buttonClass2 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
3635
+ var ReviewToolbar = ({
3636
+ editor,
3637
+ className = "flex flex-wrap items-center gap-1 rounded-md border border-border bg-background p-1 text-sm"
3638
+ }) => {
3639
+ const review = useTrackChanges(editor);
3640
+ const count = review.changes.length;
3641
+ const current = review.currentChange;
3642
+ const index = current ? review.changes.findIndex((c) => c.id === current.id) + 1 : 0;
3643
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className, role: "toolbar", "aria-label": "Review", children: [
3644
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3645
+ "button",
3646
+ {
3647
+ type: "button",
3648
+ className: `${buttonClass2} ${review.enabled ? "bg-primary/10 text-primary" : ""}`,
3649
+ "aria-pressed": review.enabled,
3650
+ disabled: !editor,
3651
+ onClick: review.toggle,
3652
+ children: review.enabled ? "Tracking on" : "Track changes"
3653
+ }
3654
+ ),
3655
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
3656
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3657
+ "button",
3658
+ {
3659
+ type: "button",
3660
+ className: buttonClass2,
3661
+ "aria-label": "Previous change",
3662
+ disabled: count === 0,
3663
+ onClick: review.previous,
3664
+ children: "\u2039"
3665
+ }
3666
+ ),
3667
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "min-w-[4rem] text-center text-xs text-muted-foreground", "aria-live": "polite", children: count === 0 ? "No changes" : current ? `${index} of ${count}` : `${count} changes` }),
3668
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3669
+ "button",
3670
+ {
3671
+ type: "button",
3672
+ className: buttonClass2,
3673
+ "aria-label": "Next change",
3674
+ disabled: count === 0,
3675
+ onClick: review.next,
3676
+ children: "\u203A"
3677
+ }
3678
+ ),
3679
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
3680
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3681
+ "button",
3682
+ {
3683
+ type: "button",
3684
+ className: buttonClass2,
3685
+ disabled: !current,
3686
+ onClick: () => current && review.accept(current.id),
3687
+ children: "Accept"
3688
+ }
3689
+ ),
3690
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3691
+ "button",
3692
+ {
3693
+ type: "button",
3694
+ className: buttonClass2,
3695
+ disabled: !current,
3696
+ onClick: () => current && review.reject(current.id),
3697
+ children: "Reject"
3698
+ }
3699
+ ),
3700
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: buttonClass2, disabled: count === 0, onClick: review.acceptAll, children: "Accept all" }),
3701
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: buttonClass2, disabled: count === 0, onClick: review.rejectAll, children: "Reject all" })
3702
+ ] });
3703
+ };
3704
+
3705
+ // src/review/CommentButton.tsx
3706
+ var import_jsx_runtime13 = require("react/jsx-runtime");
3707
+ var CommentButton = ({
3708
+ editor,
3709
+ className = "rounded px-2 py-1 text-xs text-popover-foreground hover:bg-muted",
3710
+ children = "Comment"
3711
+ }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3712
+ "button",
3713
+ {
3714
+ type: "button",
3715
+ className,
3716
+ disabled: !editor,
3717
+ onClick: () => editor?.chain().focus().addComment().run(),
3718
+ children
3719
+ }
3720
+ );
2701
3721
  // Annotate the CommonJS export names for ESM import in node:
2702
3722
  0 && (module.exports = {
2703
3723
  BubbleMenu,
3724
+ CommentButton,
3725
+ CommentsPanel,
2704
3726
  DirtyTracker,
2705
3727
  EditorContent,
2706
3728
  EditorSlotsProvider,
3729
+ FormulaHints,
2707
3730
  HistoryManager,
2708
3731
  ImageEditor,
3732
+ OutlinePanel,
3733
+ ReviewToolbar,
3734
+ SpreadsheetContextMenu,
2709
3735
  SpreadsheetEditor,
3736
+ SpreadsheetGroupRow,
2710
3737
  TemplateRenderer,
3738
+ VariableForm,
2711
3739
  createDirtyTracker,
2712
3740
  createHistoryManager,
2713
3741
  defaultIsEqual,
3742
+ useAgentToolProvider,
3743
+ useComments,
2714
3744
  useDismissGuard,
2715
3745
  useEditor,
2716
3746
  useEditorSlots,
3747
+ useFileImport,
3748
+ useFillHandle,
2717
3749
  useHistory,
2718
3750
  useHistoryShortcuts,
2719
3751
  useImageEditor,
2720
3752
  useNavigationGuard,
3753
+ useOutline,
2721
3754
  usePromptEditor,
2722
- useSpreadsheetEditor
3755
+ useSpreadsheetClipboard,
3756
+ useSpreadsheetEditor,
3757
+ useTrackChanges
2723
3758
  });
2724
3759
  //# sourceMappingURL=index.cjs.map