@pixerate/editor-react 0.11.0 → 0.13.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/README.md +29 -2
- package/dist/canvas/index.cjs +283 -36
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +135 -3
- package/dist/canvas/index.d.ts +135 -3
- package/dist/canvas/index.js +251 -1
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-MHTAR3RS.js +1103 -0
- package/dist/chunk-MHTAR3RS.js.map +1 -0
- package/dist/index.cjs +1424 -389
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +181 -50
- package/dist/index.d.ts +181 -50
- package/dist/index.js +604 -647
- package/dist/index.js.map +1 -1
- package/dist/spreadsheet/index.cjs +1134 -0
- package/dist/spreadsheet/index.cjs.map +1 -0
- package/dist/spreadsheet/index.d.cts +160 -0
- package/dist/spreadsheet/index.d.ts +160 -0
- package/dist/spreadsheet/index.js +19 -0
- package/dist/spreadsheet/index.js.map +1 -0
- package/package.json +15 -2
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
|
-
|
|
34
|
+
CommentButton: () => CommentButton,
|
|
35
|
+
CommentsPanel: () => CommentsPanel,
|
|
36
|
+
DirtyTracker: () => import_editor11.DirtyTracker,
|
|
35
37
|
EditorContent: () => EditorContent,
|
|
36
38
|
EditorSlotsProvider: () => EditorSlotsProvider,
|
|
37
|
-
|
|
39
|
+
FormulaHints: () => FormulaHints,
|
|
40
|
+
HistoryManager: () => import_editor11.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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
VariableForm: () => VariableForm,
|
|
49
|
+
createDirtyTracker: () => import_editor11.createDirtyTracker,
|
|
50
|
+
createHistoryManager: () => import_editor11.createHistoryManager,
|
|
51
|
+
defaultIsEqual: () => import_editor11.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
|
-
|
|
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 {
|
|
288
|
-
|
|
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
|
|
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)(
|
|
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
|
|
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,
|
|
540
|
-
const [mounted, setMounted] = (0,
|
|
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,
|
|
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
|
|
576
|
-
var
|
|
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,
|
|
660
|
+
const displayText = (0, import_react12.useMemo)(() => {
|
|
588
661
|
if (!resolve || templates.length === 0) return content;
|
|
589
|
-
return (0,
|
|
590
|
-
}, [content, templates, resolve]);
|
|
591
|
-
const tokens = (0,
|
|
592
|
-
return (0,
|
|
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
|
-
|
|
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:
|
|
623
|
-
children:
|
|
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/
|
|
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_editor11 = require("@pixerate/editor");
|
|
645
888
|
|
|
646
889
|
// src/spreadsheet/useSpreadsheetEditor.ts
|
|
647
|
-
var
|
|
648
|
-
var
|
|
890
|
+
var import_react15 = require("react");
|
|
891
|
+
var import_spreadsheet = require("@pixerate/editor/spreadsheet");
|
|
649
892
|
function useSpreadsheetEditor(options = {}) {
|
|
650
|
-
const optionsRef = (0,
|
|
893
|
+
const optionsRef = (0, import_react15.useRef)(options);
|
|
651
894
|
optionsRef.current = options;
|
|
652
|
-
const settersRef = (0,
|
|
653
|
-
const [controller] = (0,
|
|
654
|
-
() => new
|
|
895
|
+
const settersRef = (0, import_react15.useRef)({});
|
|
896
|
+
const [controller] = (0, import_react15.useState)(
|
|
897
|
+
() => new import_spreadsheet.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,
|
|
671
|
-
const [activeCell, setActiveCell] = (0,
|
|
672
|
-
const [selectedRange, setSelectedRange] = (0,
|
|
673
|
-
const [editingCell, setEditingCell] = (0,
|
|
674
|
-
const [draftValue, setDraftValue] = (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
986
|
+
const recalculateAll = (0, import_react15.useCallback)(() => {
|
|
744
987
|
controller.recalculateAll();
|
|
745
988
|
setDoc({ ...controller.document });
|
|
746
989
|
}, [controller]);
|
|
747
|
-
const undo = (0,
|
|
990
|
+
const undo = (0, import_react15.useCallback)(() => {
|
|
748
991
|
controller.undo();
|
|
749
992
|
setDoc({ ...controller.document });
|
|
750
993
|
}, [controller]);
|
|
751
|
-
const redo = (0,
|
|
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_spreadsheet.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
|
|
805
|
-
var
|
|
806
|
-
|
|
1051
|
+
var import_react19 = require("react");
|
|
1052
|
+
var import_spreadsheet4 = require("@pixerate/editor/spreadsheet");
|
|
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_spreadsheet2 = require("@pixerate/editor/spreadsheet");
|
|
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_spreadsheet2.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_spreadsheet2.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_spreadsheet3 = require("@pixerate/editor/spreadsheet");
|
|
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_spreadsheet3.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_spreadsheet3.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,
|
|
818
|
-
const
|
|
819
|
-
const
|
|
820
|
-
const [
|
|
821
|
-
const [
|
|
822
|
-
const
|
|
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_spreadsheet4.rangeContains)(state.selectedRange, rIdx, cIdx)) {
|
|
1423
|
+
state.selectCell(rIdx, cIdx);
|
|
1424
|
+
}
|
|
1425
|
+
setMenu({ x: e.clientX, y: e.clientY, items: (0, import_spreadsheet4.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,
|
|
1434
|
+
const coordLabel = (0, import_react19.useMemo)(() => {
|
|
830
1435
|
if (!state.activeCell) return "--";
|
|
831
|
-
const colName = (0,
|
|
1436
|
+
const colName = (0, import_spreadsheet4.indexToColName)(state.activeCell.col);
|
|
832
1437
|
return `${colName}${state.activeCell.row + 1}`;
|
|
833
1438
|
}, [state.activeCell]);
|
|
834
|
-
const [formulaDraft, setFormulaDraft] = (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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,
|
|
1534
|
+
}, [readOnly, state, copyShortcutFallback]);
|
|
1535
|
+
const stateRef = (0, import_react19.useRef)(state);
|
|
933
1536
|
stateRef.current = state;
|
|
934
|
-
const onColumnResizeRef = (0,
|
|
1537
|
+
const onColumnResizeRef = (0, import_react19.useRef)(onColumnResize);
|
|
935
1538
|
onColumnResizeRef.current = onColumnResize;
|
|
936
|
-
(0,
|
|
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,
|
|
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,
|
|
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
|
|
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.
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
1110
|
-
/* @__PURE__ */ (0,
|
|
1111
|
-
/* @__PURE__ */ (0,
|
|
1112
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
1147
|
-
/* @__PURE__ */ (0,
|
|
1148
|
-
/* @__PURE__ */ (0,
|
|
1149
|
-
|
|
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: {
|
|
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,
|
|
1158
|
-
/* @__PURE__ */ (0,
|
|
1159
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
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
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
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
|
-
|
|
1841
|
+
`group:${viewRow.group.key}`
|
|
1238
1842
|
);
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1843
|
+
}
|
|
1844
|
+
const displayRowIndex = viewRow.index;
|
|
1845
|
+
const selection = state.selectedRange ? (0, import_spreadsheet4.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_spreadsheet4.rangeContains)(fillTarget, displayRowIndex, viewCol.index);
|
|
1873
|
+
const showFillHandle = !readOnly && !isEditing && !!selection && (span.merge ? (0, import_spreadsheet4.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,
|
|
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
|
|
1267
|
-
var
|
|
1972
|
+
var import_react20 = require("react");
|
|
1973
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1268
1974
|
var defaultSlots = {
|
|
1269
|
-
Button: (props) => /* @__PURE__ */ (0,
|
|
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,
|
|
1280
|
-
NodeHeader: (props) => /* @__PURE__ */ (0,
|
|
1281
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
1989
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "font-semibold", children: props.title })
|
|
1284
1990
|
] }),
|
|
1285
|
-
props.onClose && /* @__PURE__ */ (0,
|
|
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,
|
|
1994
|
+
var EditorSlotsContext = (0, import_react20.createContext)(defaultSlots);
|
|
1289
1995
|
function EditorSlotsProvider({ slots, children }) {
|
|
1290
|
-
const mergedSlots = (0,
|
|
1291
|
-
return /* @__PURE__ */ (0,
|
|
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,
|
|
2000
|
+
return (0, import_react20.useContext)(EditorSlotsContext);
|
|
1295
2001
|
}
|
|
1296
2002
|
|
|
1297
2003
|
// src/image-editor/useImageEditor.ts
|
|
1298
|
-
var
|
|
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,
|
|
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,
|
|
1307
|
-
const [historyTicks, setHistoryTicks] = (0,
|
|
1308
|
-
(0,
|
|
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,
|
|
1316
|
-
(0,
|
|
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,
|
|
1324
|
-
const setCrop = (0,
|
|
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,
|
|
1329
|
-
const resetCrop = (0,
|
|
1330
|
-
const rotate = (0,
|
|
1331
|
-
const setRotation = (0,
|
|
1332
|
-
const flipHorizontal = (0,
|
|
1333
|
-
const flipVertical = (0,
|
|
1334
|
-
const setAdjustments = (0,
|
|
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,
|
|
1339
|
-
const setDepthMask = (0,
|
|
1340
|
-
const resetDepthMask = (0,
|
|
1341
|
-
const addAnnotation = (0,
|
|
1342
|
-
const updateAnnotation = (0,
|
|
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,
|
|
1347
|
-
const clearAnnotations = (0,
|
|
1348
|
-
const selectAnnotation = (0,
|
|
1349
|
-
const undo = (0,
|
|
1350
|
-
const redo = (0,
|
|
1351
|
-
const reset = (0,
|
|
1352
|
-
const zoomIn = (0,
|
|
1353
|
-
const zoomOut = (0,
|
|
1354
|
-
const resetZoom = (0,
|
|
1355
|
-
const setZoom = (0,
|
|
1356
|
-
const setPan = (0,
|
|
1357
|
-
const setComparing = (0,
|
|
1358
|
-
const loadImage = (0,
|
|
1359
|
-
const toDataURL = (0,
|
|
1360
|
-
const toBlob = (0,
|
|
1361
|
-
const toJSON = (0,
|
|
1362
|
-
const loadJSON = (0,
|
|
1363
|
-
const renderMask = (0,
|
|
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,
|
|
2073
|
+
const toMaskDataURL = (0, import_react21.useCallback)(
|
|
1368
2074
|
(opts) => controller.toMaskDataURL(opts),
|
|
1369
2075
|
[controller]
|
|
1370
2076
|
);
|
|
1371
|
-
const toSourceDataURL = (0,
|
|
2077
|
+
const toSourceDataURL = (0, import_react21.useCallback)(
|
|
1372
2078
|
(opts) => controller.toSourceDataURL(opts),
|
|
1373
2079
|
[controller]
|
|
1374
2080
|
);
|
|
1375
|
-
const applyInpaintedImage = (0,
|
|
2081
|
+
const applyInpaintedImage = (0, import_react21.useCallback)(
|
|
1376
2082
|
(newDataUrl) => controller.applyInpaintedImage(newDataUrl),
|
|
1377
2083
|
[controller]
|
|
1378
2084
|
);
|
|
1379
|
-
const applyBackgroundRemovedImage = (0,
|
|
2085
|
+
const applyBackgroundRemovedImage = (0, import_react21.useCallback)(
|
|
1380
2086
|
(newDataUrl) => controller.applyBackgroundRemovedImage(newDataUrl),
|
|
1381
2087
|
[controller]
|
|
1382
2088
|
);
|
|
1383
|
-
return (0,
|
|
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
|
|
2138
|
+
var import_react22 = require("react");
|
|
1433
2139
|
var import_image_editor2 = require("@pixerate/editor/image-editor");
|
|
1434
|
-
var
|
|
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,
|
|
1450
|
-
const containerRef = (0,
|
|
1451
|
-
const [activeTab, setActiveTab] = (0,
|
|
1452
|
-
const [activeCropRatio, setActiveCropRatio] = (0,
|
|
1453
|
-
const [inpaintPrompt, setInpaintPrompt] = (0,
|
|
1454
|
-
const [inpaintMaskMode, setInpaintMaskMode] = (0,
|
|
1455
|
-
const [isRemovingBg, setIsRemovingBg] = (0,
|
|
1456
|
-
const [isInpainting, setIsInpainting] = (0,
|
|
1457
|
-
const [aiError, setAiError] = (0,
|
|
1458
|
-
const [aiSuccess, setAiSuccess] = (0,
|
|
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,
|
|
1521
|
-
const [strokeWidth, setStrokeWidth] = (0,
|
|
1522
|
-
const [fontSize, setFontSize] = (0,
|
|
1523
|
-
const [textInput, setTextInput] = (0,
|
|
1524
|
-
const draftAnnotationRef = (0,
|
|
1525
|
-
const draftCropRef = (0,
|
|
1526
|
-
const cropDragInfoRef = (0,
|
|
1527
|
-
const annotationDragInfoRef = (0,
|
|
1528
|
-
const isDrawingRef = (0,
|
|
1529
|
-
const currentPathRef = (0,
|
|
1530
|
-
const dragStartPointRef = (0,
|
|
1531
|
-
const renderCanvas = (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
1928
|
-
/* @__PURE__ */ (0,
|
|
1929
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
1994
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
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,
|
|
2026
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
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,
|
|
2051
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2074
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2093
|
-
activeTab === "crop" && /* @__PURE__ */ (0,
|
|
2094
|
-
/* @__PURE__ */ (0,
|
|
2095
|
-
/* @__PURE__ */ (0,
|
|
2096
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
2170
|
-
/* @__PURE__ */ (0,
|
|
2171
|
-
/* @__PURE__ */ (0,
|
|
2172
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
2211
|
-
/* @__PURE__ */ (0,
|
|
2212
|
-
/* @__PURE__ */ (0,
|
|
2213
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
2224
|
-
/* @__PURE__ */ (0,
|
|
2225
|
-
/* @__PURE__ */ (0,
|
|
2226
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2241
|
-
/* @__PURE__ */ (0,
|
|
2242
|
-
/* @__PURE__ */ (0,
|
|
2243
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2258
|
-
/* @__PURE__ */ (0,
|
|
2259
|
-
/* @__PURE__ */ (0,
|
|
2260
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2275
|
-
/* @__PURE__ */ (0,
|
|
2276
|
-
/* @__PURE__ */ (0,
|
|
2277
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2292
|
-
/* @__PURE__ */ (0,
|
|
2293
|
-
/* @__PURE__ */ (0,
|
|
2294
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2309
|
-
/* @__PURE__ */ (0,
|
|
2310
|
-
/* @__PURE__ */ (0,
|
|
2311
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2329
|
-
/* @__PURE__ */ (0,
|
|
2330
|
-
/* @__PURE__ */ (0,
|
|
2331
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2351
|
-
/* @__PURE__ */ (0,
|
|
2352
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
2363
|
-
/* @__PURE__ */ (0,
|
|
2364
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
2374
|
-
/* @__PURE__ */ (0,
|
|
2375
|
-
/* @__PURE__ */ (0,
|
|
2376
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2395
|
-
/* @__PURE__ */ (0,
|
|
2396
|
-
/* @__PURE__ */ (0,
|
|
2397
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2419
|
-
/* @__PURE__ */ (0,
|
|
2420
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2437
|
-
/* @__PURE__ */ (0,
|
|
2438
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
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,
|
|
2464
|
-
/* @__PURE__ */ (0,
|
|
2465
|
-
/* @__PURE__ */ (0,
|
|
2466
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
2477
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
3192
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Enable Depth / Alpha Mask" })
|
|
2487
3193
|
] }),
|
|
2488
|
-
state.depthMask.enabled && /* @__PURE__ */ (0,
|
|
2489
|
-
/* @__PURE__ */ (0,
|
|
2490
|
-
/* @__PURE__ */ (0,
|
|
2491
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
2503
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2523
|
-
/* @__PURE__ */ (0,
|
|
2524
|
-
/* @__PURE__ */ (0,
|
|
2525
|
-
/* @__PURE__ */ (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,
|
|
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,
|
|
2542
|
-
/* @__PURE__ */ (0,
|
|
2543
|
-
/* @__PURE__ */ (0,
|
|
2544
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2561
|
-
/* @__PURE__ */ (0,
|
|
2562
|
-
/* @__PURE__ */ (0,
|
|
2563
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2578
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
3293
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Invert Mask" })
|
|
2588
3294
|
] })
|
|
2589
3295
|
] })
|
|
2590
3296
|
] }),
|
|
2591
|
-
activeTab === "ai" && /* @__PURE__ */ (0,
|
|
2592
|
-
/* @__PURE__ */ (0,
|
|
2593
|
-
/* @__PURE__ */ (0,
|
|
2594
|
-
/* @__PURE__ */ (0,
|
|
2595
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2601
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
2609
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
2612
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
2619
|
-
/* @__PURE__ */ (0,
|
|
2620
|
-
/* @__PURE__ */ (0,
|
|
2621
|
-
/* @__PURE__ */ (0,
|
|
2622
|
-
/* @__PURE__ */ (0,
|
|
2623
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2630
|
-
/* @__PURE__ */ (0,
|
|
2631
|
-
/* @__PURE__ */ (0,
|
|
2632
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
2645
|
-
/* @__PURE__ */ (0,
|
|
2646
|
-
/* @__PURE__ */ (0,
|
|
2647
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
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,
|
|
2683
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
2686
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
2693
|
-
aiSuccess && /* @__PURE__ */ (0,
|
|
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_editor9 = 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_editor9.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_editor9.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_editor10 = 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_editor10.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_editor10.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
|
-
|
|
3755
|
+
useSpreadsheetClipboard,
|
|
3756
|
+
useSpreadsheetEditor,
|
|
3757
|
+
useTrackChanges
|
|
2723
3758
|
});
|
|
2724
3759
|
//# sourceMappingURL=index.cjs.map
|