@pixerate/editor-react 0.10.5 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -1
- 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-H7HCHLZU.js → chunk-TL27COKM.js} +11 -5
- package/dist/chunk-TL27COKM.js.map +1 -0
- package/dist/image-editor/index.cjs +10 -4
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +1 -0
- package/dist/image-editor/index.d.ts +1 -0
- package/dist/image-editor/index.js +1 -1
- package/dist/index.cjs +1433 -392
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +292 -7
- package/dist/index.d.ts +292 -7
- package/dist/index.js +1160 -119
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-H7HCHLZU.js.map +0 -1
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_editor15.DirtyTracker,
|
|
35
37
|
EditorContent: () => EditorContent,
|
|
36
38
|
EditorSlotsProvider: () => EditorSlotsProvider,
|
|
37
|
-
|
|
39
|
+
FormulaHints: () => FormulaHints,
|
|
40
|
+
HistoryManager: () => import_editor15.HistoryManager,
|
|
38
41
|
ImageEditor: () => ImageEditor,
|
|
42
|
+
OutlinePanel: () => OutlinePanel,
|
|
43
|
+
ReviewToolbar: () => ReviewToolbar,
|
|
44
|
+
SpreadsheetContextMenu: () => SpreadsheetContextMenu,
|
|
39
45
|
SpreadsheetEditor: () => SpreadsheetEditor,
|
|
46
|
+
SpreadsheetGroupRow: () => SpreadsheetGroupRow,
|
|
40
47
|
TemplateRenderer: () => TemplateRenderer,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
VariableForm: () => VariableForm,
|
|
49
|
+
createDirtyTracker: () => import_editor15.createDirtyTracker,
|
|
50
|
+
createHistoryManager: () => import_editor15.createHistoryManager,
|
|
51
|
+
defaultIsEqual: () => import_editor15.defaultIsEqual,
|
|
52
|
+
useAgentToolProvider: () => useAgentToolProvider,
|
|
53
|
+
useComments: () => useComments,
|
|
44
54
|
useDismissGuard: () => useDismissGuard,
|
|
45
55
|
useEditor: () => useEditor2,
|
|
46
56
|
useEditorSlots: () => useEditorSlots,
|
|
57
|
+
useFileImport: () => useFileImport,
|
|
58
|
+
useFillHandle: () => useFillHandle,
|
|
47
59
|
useHistory: () => useHistory,
|
|
48
60
|
useHistoryShortcuts: () => useHistoryShortcuts,
|
|
49
61
|
useImageEditor: () => useImageEditor,
|
|
50
62
|
useNavigationGuard: () => useNavigationGuard,
|
|
63
|
+
useOutline: () => useOutline,
|
|
51
64
|
usePromptEditor: () => usePromptEditor,
|
|
52
|
-
|
|
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_editor15 = require("@pixerate/editor");
|
|
645
888
|
|
|
646
889
|
// src/spreadsheet/useSpreadsheetEditor.ts
|
|
647
|
-
var
|
|
648
|
-
var
|
|
890
|
+
var import_react15 = require("react");
|
|
891
|
+
var import_editor9 = require("@pixerate/editor");
|
|
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_editor9.SpreadsheetController({
|
|
655
898
|
...options,
|
|
656
899
|
onDocumentChange: (updated) => {
|
|
657
900
|
settersRef.current.setDoc?.({ ...updated });
|
|
@@ -667,91 +910,93 @@ function useSpreadsheetEditor(options = {}) {
|
|
|
667
910
|
}
|
|
668
911
|
})
|
|
669
912
|
);
|
|
670
|
-
const [doc, setDoc] = (0,
|
|
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_editor9.bindSpreadsheetTableActions)(controller), [controller]);
|
|
999
|
+
const viewModel = (0, import_react15.useMemo)(() => controller.getViewModel(), [controller, doc]);
|
|
755
1000
|
return {
|
|
756
1001
|
document: doc,
|
|
757
1002
|
activeCell,
|
|
@@ -795,15 +1040,355 @@ function useSpreadsheetEditor(options = {}) {
|
|
|
795
1040
|
controller.importFromTsv(data);
|
|
796
1041
|
setDoc({ ...controller.document });
|
|
797
1042
|
},
|
|
1043
|
+
...tableActions,
|
|
1044
|
+
viewModel,
|
|
798
1045
|
undo,
|
|
799
1046
|
redo
|
|
800
1047
|
};
|
|
801
1048
|
}
|
|
802
1049
|
|
|
803
1050
|
// src/spreadsheet/SpreadsheetEditor.tsx
|
|
804
|
-
var
|
|
805
|
-
var
|
|
806
|
-
|
|
1051
|
+
var import_react19 = require("react");
|
|
1052
|
+
var import_editor12 = require("@pixerate/editor");
|
|
1053
|
+
|
|
1054
|
+
// src/spreadsheet/SpreadsheetContextMenu.tsx
|
|
1055
|
+
var import_react16 = __toESM(require("react"), 1);
|
|
1056
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1057
|
+
var SpreadsheetContextMenu = ({ items, x, y, onClose }) => {
|
|
1058
|
+
const menuRef = (0, import_react16.useRef)(null);
|
|
1059
|
+
const onCloseRef = (0, import_react16.useRef)(onClose);
|
|
1060
|
+
onCloseRef.current = onClose;
|
|
1061
|
+
(0, import_react16.useEffect)(() => {
|
|
1062
|
+
const handlePointer = (e) => {
|
|
1063
|
+
if (!menuRef.current?.contains(e.target)) onCloseRef.current();
|
|
1064
|
+
};
|
|
1065
|
+
const handleKey = (e) => {
|
|
1066
|
+
if (e.key === "Escape") onCloseRef.current();
|
|
1067
|
+
};
|
|
1068
|
+
window.addEventListener("mousedown", handlePointer);
|
|
1069
|
+
window.addEventListener("keydown", handleKey);
|
|
1070
|
+
return () => {
|
|
1071
|
+
window.removeEventListener("mousedown", handlePointer);
|
|
1072
|
+
window.removeEventListener("keydown", handleKey);
|
|
1073
|
+
};
|
|
1074
|
+
}, []);
|
|
1075
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1076
|
+
"div",
|
|
1077
|
+
{
|
|
1078
|
+
ref: menuRef,
|
|
1079
|
+
role: "menu",
|
|
1080
|
+
"aria-label": "Table actions",
|
|
1081
|
+
className: "fixed z-50 min-w-[14rem] rounded-md border border-border bg-popover py-1 text-xs text-popover-foreground shadow-lg",
|
|
1082
|
+
style: { left: x, top: y, background: "var(--popover, var(--background, #fff))" },
|
|
1083
|
+
onContextMenu: (e) => e.preventDefault(),
|
|
1084
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
1085
|
+
children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react16.default.Fragment, { children: [
|
|
1086
|
+
item.separatorBefore && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { role: "separator", className: "my-1 h-px bg-border" }),
|
|
1087
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1088
|
+
"button",
|
|
1089
|
+
{
|
|
1090
|
+
type: "button",
|
|
1091
|
+
role: "menuitem",
|
|
1092
|
+
"data-action": item.id,
|
|
1093
|
+
disabled: item.disabled,
|
|
1094
|
+
className: "block w-full px-3 py-1 text-left hover:bg-muted disabled:cursor-default disabled:opacity-40 disabled:hover:bg-transparent",
|
|
1095
|
+
onClick: () => {
|
|
1096
|
+
onClose();
|
|
1097
|
+
item.run();
|
|
1098
|
+
},
|
|
1099
|
+
children: item.label
|
|
1100
|
+
}
|
|
1101
|
+
)
|
|
1102
|
+
] }, item.id))
|
|
1103
|
+
}
|
|
1104
|
+
);
|
|
1105
|
+
};
|
|
1106
|
+
|
|
1107
|
+
// src/spreadsheet/SpreadsheetGroupRow.tsx
|
|
1108
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1109
|
+
var formatSummary = (value) => value === null ? "\u2013" : String(value);
|
|
1110
|
+
var SpreadsheetGroupRow = ({
|
|
1111
|
+
group,
|
|
1112
|
+
columns,
|
|
1113
|
+
groupColId,
|
|
1114
|
+
onToggle,
|
|
1115
|
+
trailingCell
|
|
1116
|
+
}) => {
|
|
1117
|
+
const labelColId = columns.some((c) => c.column.id === groupColId) ? groupColId : columns[0]?.column.id;
|
|
1118
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("tr", { className: "border-b border-border bg-muted/40 font-semibold", "data-group-key": group.key, style: { height: 28 }, children: [
|
|
1119
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted/60 border-r border-border text-center", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1120
|
+
"button",
|
|
1121
|
+
{
|
|
1122
|
+
type: "button",
|
|
1123
|
+
"aria-label": `${group.collapsed ? "Expand" : "Collapse"} group ${group.label}`,
|
|
1124
|
+
"aria-expanded": !group.collapsed,
|
|
1125
|
+
className: "h-5 w-5 rounded text-[10px] text-muted-foreground hover:bg-muted",
|
|
1126
|
+
onClick: (e) => {
|
|
1127
|
+
e.stopPropagation();
|
|
1128
|
+
onToggle(group.key);
|
|
1129
|
+
},
|
|
1130
|
+
children: group.collapsed ? "\u25B8" : "\u25BE"
|
|
1131
|
+
}
|
|
1132
|
+
) }),
|
|
1133
|
+
columns.map(({ column }) => {
|
|
1134
|
+
const summary = group.summaries[column.id];
|
|
1135
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-r border-border px-2 py-1 truncate max-w-0 text-foreground", style: { maxWidth: 0, overflow: "hidden" }, children: column.id === labelColId ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "truncate", children: [
|
|
1136
|
+
group.label,
|
|
1137
|
+
" ",
|
|
1138
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "font-normal text-muted-foreground", children: [
|
|
1139
|
+
"(",
|
|
1140
|
+
group.rowIndices.length,
|
|
1141
|
+
")"
|
|
1142
|
+
] })
|
|
1143
|
+
] }) : summary !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "truncate", "data-summary": column.id, children: formatSummary(summary) }) : null }, column.id);
|
|
1144
|
+
}),
|
|
1145
|
+
trailingCell && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "w-10 min-w-[2.5rem] bg-muted/10 border-r border-border" })
|
|
1146
|
+
] });
|
|
1147
|
+
};
|
|
1148
|
+
|
|
1149
|
+
// src/spreadsheet/useSpreadsheetTableInteractions.ts
|
|
1150
|
+
var import_react17 = require("react");
|
|
1151
|
+
var import_editor10 = require("@pixerate/editor");
|
|
1152
|
+
function gridHasFocus(grid) {
|
|
1153
|
+
if (!grid || typeof document === "undefined") return false;
|
|
1154
|
+
const active = document.activeElement;
|
|
1155
|
+
if (!active || !grid.contains(active)) return false;
|
|
1156
|
+
return !(active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement);
|
|
1157
|
+
}
|
|
1158
|
+
function useSpreadsheetClipboard(gridRef, state, readOnly) {
|
|
1159
|
+
const stateRef = (0, import_react17.useRef)(state);
|
|
1160
|
+
stateRef.current = state;
|
|
1161
|
+
const readOnlyRef = (0, import_react17.useRef)(readOnly);
|
|
1162
|
+
readOnlyRef.current = readOnly;
|
|
1163
|
+
const copiedRef = (0, import_react17.useRef)(false);
|
|
1164
|
+
(0, import_react17.useEffect)(() => {
|
|
1165
|
+
if (typeof document === "undefined") return;
|
|
1166
|
+
const handleCopy = (e) => {
|
|
1167
|
+
const s = stateRef.current;
|
|
1168
|
+
if (!gridHasFocus(gridRef.current) || s.editingCell || !e.clipboardData || !s.selectedRange) return;
|
|
1169
|
+
for (const [type, data] of Object.entries(s.copyToClipboardData(s.selectedRange))) {
|
|
1170
|
+
e.clipboardData.setData(type, data);
|
|
1171
|
+
}
|
|
1172
|
+
copiedRef.current = true;
|
|
1173
|
+
e.preventDefault();
|
|
1174
|
+
};
|
|
1175
|
+
const handlePaste = (e) => {
|
|
1176
|
+
const s = stateRef.current;
|
|
1177
|
+
if (readOnlyRef.current || !gridHasFocus(gridRef.current) || s.editingCell || !e.clipboardData) return;
|
|
1178
|
+
if (s.pasteClipboardData(e.clipboardData)) e.preventDefault();
|
|
1179
|
+
};
|
|
1180
|
+
document.addEventListener("copy", handleCopy);
|
|
1181
|
+
document.addEventListener("paste", handlePaste);
|
|
1182
|
+
return () => {
|
|
1183
|
+
document.removeEventListener("copy", handleCopy);
|
|
1184
|
+
document.removeEventListener("paste", handlePaste);
|
|
1185
|
+
};
|
|
1186
|
+
}, [gridRef]);
|
|
1187
|
+
const copyShortcutFallback = (0, import_react17.useCallback)(() => {
|
|
1188
|
+
copiedRef.current = false;
|
|
1189
|
+
setTimeout(() => {
|
|
1190
|
+
if (copiedRef.current) return;
|
|
1191
|
+
const s = stateRef.current;
|
|
1192
|
+
navigator.clipboard?.writeText(s.exportToTsv(s.selectedRange));
|
|
1193
|
+
}, 0);
|
|
1194
|
+
}, []);
|
|
1195
|
+
return { copyShortcutFallback };
|
|
1196
|
+
}
|
|
1197
|
+
function useFillHandle(state) {
|
|
1198
|
+
const [drag, setDrag] = (0, import_react17.useState)(null);
|
|
1199
|
+
const dragRef = (0, import_react17.useRef)(drag);
|
|
1200
|
+
dragRef.current = drag;
|
|
1201
|
+
const stateRef = (0, import_react17.useRef)(state);
|
|
1202
|
+
stateRef.current = state;
|
|
1203
|
+
const dragging = drag !== null;
|
|
1204
|
+
(0, import_react17.useEffect)(() => {
|
|
1205
|
+
if (!dragging) return;
|
|
1206
|
+
const handleMouseUp = () => {
|
|
1207
|
+
const current = dragRef.current;
|
|
1208
|
+
setDrag(null);
|
|
1209
|
+
if (current?.target) stateRef.current.autofill(current.source, current.target);
|
|
1210
|
+
};
|
|
1211
|
+
window.addEventListener("mouseup", handleMouseUp);
|
|
1212
|
+
return () => window.removeEventListener("mouseup", handleMouseUp);
|
|
1213
|
+
}, [dragging]);
|
|
1214
|
+
const startFill = (0, import_react17.useCallback)((e) => {
|
|
1215
|
+
e.preventDefault();
|
|
1216
|
+
e.stopPropagation();
|
|
1217
|
+
const range = stateRef.current.selectedRange;
|
|
1218
|
+
if (range) setDrag({ source: (0, import_editor10.normalizeRange)(range), target: null });
|
|
1219
|
+
}, []);
|
|
1220
|
+
const extendFill = (0, import_react17.useCallback)((row, col) => {
|
|
1221
|
+
const current = dragRef.current;
|
|
1222
|
+
if (!current) return;
|
|
1223
|
+
setDrag({ source: current.source, target: (0, import_editor10.computeFillTarget)(current.source, { row, col }) });
|
|
1224
|
+
}, []);
|
|
1225
|
+
return { fillTarget: drag?.target ?? null, isFilling: dragging, startFill, extendFill };
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// src/spreadsheet/FormulaHints.tsx
|
|
1229
|
+
var import_react18 = require("react");
|
|
1230
|
+
var import_editor11 = require("@pixerate/editor");
|
|
1231
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1232
|
+
var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
1233
|
+
const [caret, setCaret] = (0, import_react18.useState)(null);
|
|
1234
|
+
const [focused, setFocused] = (0, import_react18.useState)(false);
|
|
1235
|
+
const [selected, setSelected] = (0, import_react18.useState)(0);
|
|
1236
|
+
const [dismissed, setDismissed] = (0, import_react18.useState)(false);
|
|
1237
|
+
const [position, setPosition] = (0, import_react18.useState)(null);
|
|
1238
|
+
const pendingCaret = (0, import_react18.useRef)(null);
|
|
1239
|
+
const hints = (0, import_react18.useMemo)(
|
|
1240
|
+
() => (0, import_editor11.getFormulaHints)(value, caret ?? value.length, { limit }),
|
|
1241
|
+
[value, caret, limit]
|
|
1242
|
+
);
|
|
1243
|
+
const suggestions = dismissed ? [] : hints.suggestions;
|
|
1244
|
+
const selectedIndex = Math.max(0, Math.min(selected, suggestions.length - 1));
|
|
1245
|
+
const visible = focused && value.trimStart().startsWith("=") && (suggestions.length > 0 || !!hints.activeCall);
|
|
1246
|
+
const latest = (0, import_react18.useRef)({ suggestions, selected: selectedIndex, value, caret, onAccept });
|
|
1247
|
+
latest.current = { suggestions, selected: selectedIndex, value, caret, onAccept };
|
|
1248
|
+
const accept = (index) => {
|
|
1249
|
+
const { suggestions: list, value: current, caret: at, onAccept: commit } = latest.current;
|
|
1250
|
+
const suggestion = list[index];
|
|
1251
|
+
if (!suggestion) return;
|
|
1252
|
+
const next = (0, import_editor11.applyFormulaSuggestion)(current, at ?? current.length, suggestion.name);
|
|
1253
|
+
pendingCaret.current = next.caret;
|
|
1254
|
+
commit(next.value);
|
|
1255
|
+
};
|
|
1256
|
+
(0, import_react18.useEffect)(() => {
|
|
1257
|
+
const input = inputRef.current;
|
|
1258
|
+
if (!input) return;
|
|
1259
|
+
const syncCaret = () => setCaret(input.selectionStart ?? input.value.length);
|
|
1260
|
+
const onInput = () => {
|
|
1261
|
+
setDismissed(false);
|
|
1262
|
+
setSelected(0);
|
|
1263
|
+
syncCaret();
|
|
1264
|
+
};
|
|
1265
|
+
const onFocus = () => {
|
|
1266
|
+
setFocused(true);
|
|
1267
|
+
syncCaret();
|
|
1268
|
+
};
|
|
1269
|
+
const onBlur = () => setFocused(false);
|
|
1270
|
+
const onKeyDown = (e) => {
|
|
1271
|
+
const { suggestions: list } = latest.current;
|
|
1272
|
+
if (list.length === 0) return;
|
|
1273
|
+
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
1274
|
+
e.preventDefault();
|
|
1275
|
+
e.stopPropagation();
|
|
1276
|
+
const step = e.key === "ArrowDown" ? 1 : -1;
|
|
1277
|
+
setSelected((i) => (i + step + list.length) % list.length);
|
|
1278
|
+
} else if (e.key === "Tab" && !e.shiftKey) {
|
|
1279
|
+
e.preventDefault();
|
|
1280
|
+
e.stopPropagation();
|
|
1281
|
+
accept(latest.current.selected);
|
|
1282
|
+
} else if (e.key === "Escape") {
|
|
1283
|
+
e.preventDefault();
|
|
1284
|
+
e.stopPropagation();
|
|
1285
|
+
setDismissed(true);
|
|
1286
|
+
}
|
|
1287
|
+
};
|
|
1288
|
+
input.addEventListener("input", onInput);
|
|
1289
|
+
input.addEventListener("keyup", syncCaret);
|
|
1290
|
+
input.addEventListener("click", syncCaret);
|
|
1291
|
+
input.addEventListener("select", syncCaret);
|
|
1292
|
+
input.addEventListener("focus", onFocus);
|
|
1293
|
+
input.addEventListener("blur", onBlur);
|
|
1294
|
+
input.addEventListener("keydown", onKeyDown);
|
|
1295
|
+
if (typeof document !== "undefined" && document.activeElement === input) onFocus();
|
|
1296
|
+
return () => {
|
|
1297
|
+
input.removeEventListener("input", onInput);
|
|
1298
|
+
input.removeEventListener("keyup", syncCaret);
|
|
1299
|
+
input.removeEventListener("click", syncCaret);
|
|
1300
|
+
input.removeEventListener("select", syncCaret);
|
|
1301
|
+
input.removeEventListener("focus", onFocus);
|
|
1302
|
+
input.removeEventListener("blur", onBlur);
|
|
1303
|
+
input.removeEventListener("keydown", onKeyDown);
|
|
1304
|
+
};
|
|
1305
|
+
}, [inputRef]);
|
|
1306
|
+
(0, import_react18.useLayoutEffect)(() => {
|
|
1307
|
+
const input = inputRef.current;
|
|
1308
|
+
const at = pendingCaret.current;
|
|
1309
|
+
if (!input || at === null || input.value !== value) return;
|
|
1310
|
+
pendingCaret.current = null;
|
|
1311
|
+
input.setSelectionRange(at, at);
|
|
1312
|
+
setCaret(at);
|
|
1313
|
+
setSelected(0);
|
|
1314
|
+
}, [value, inputRef]);
|
|
1315
|
+
(0, import_react18.useLayoutEffect)(() => {
|
|
1316
|
+
const input = inputRef.current;
|
|
1317
|
+
if (!visible || !input) return;
|
|
1318
|
+
const rect = input.getBoundingClientRect();
|
|
1319
|
+
setPosition({ top: rect.bottom + 2, left: rect.left, width: rect.width });
|
|
1320
|
+
}, [visible, value, inputRef]);
|
|
1321
|
+
if (!visible) return null;
|
|
1322
|
+
const { activeCall } = hints;
|
|
1323
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1324
|
+
"div",
|
|
1325
|
+
{
|
|
1326
|
+
"data-formula-hints": "",
|
|
1327
|
+
className: "rounded-md border border-border bg-popover text-popover-foreground shadow-md text-xs font-sans overflow-hidden",
|
|
1328
|
+
style: {
|
|
1329
|
+
position: "fixed",
|
|
1330
|
+
top: position?.top ?? 0,
|
|
1331
|
+
left: position?.left ?? 0,
|
|
1332
|
+
minWidth: Math.max(260, position?.width ?? 0),
|
|
1333
|
+
maxWidth: 440,
|
|
1334
|
+
zIndex: 50,
|
|
1335
|
+
visibility: position ? "visible" : "hidden"
|
|
1336
|
+
},
|
|
1337
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
1338
|
+
children: [
|
|
1339
|
+
activeCall && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { "data-formula-signature": "", className: "px-2 py-1.5 border-b border-border bg-muted/30", children: [
|
|
1340
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "font-mono", children: activeCall.parts.map((part, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1341
|
+
"span",
|
|
1342
|
+
{
|
|
1343
|
+
"data-active": part.active ? "" : void 0,
|
|
1344
|
+
className: part.active ? "font-bold text-primary underline" : "",
|
|
1345
|
+
children: part.text
|
|
1346
|
+
},
|
|
1347
|
+
i
|
|
1348
|
+
)) }),
|
|
1349
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mt-0.5 text-muted-foreground", children: activeCall.argument ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1350
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-semibold", children: activeCall.argument.name }),
|
|
1351
|
+
": ",
|
|
1352
|
+
activeCall.argument.description
|
|
1353
|
+
] }) : activeCall.description })
|
|
1354
|
+
] }),
|
|
1355
|
+
suggestions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { role: "listbox", "aria-label": "Formula suggestions", className: "max-h-64 overflow-auto py-1 m-0 list-none p-0", children: suggestions.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1356
|
+
"li",
|
|
1357
|
+
{
|
|
1358
|
+
role: "option",
|
|
1359
|
+
"aria-selected": i === selectedIndex,
|
|
1360
|
+
className: `cursor-pointer px-2 py-1 ${i === selectedIndex ? "bg-primary/10" : "hover:bg-muted/50"}`,
|
|
1361
|
+
onMouseEnter: () => setSelected(i),
|
|
1362
|
+
onMouseDown: (e) => {
|
|
1363
|
+
e.preventDefault();
|
|
1364
|
+
accept(i);
|
|
1365
|
+
},
|
|
1366
|
+
children: [
|
|
1367
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "font-mono font-semibold text-foreground", children: s.signature }),
|
|
1368
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-muted-foreground truncate", children: s.description })
|
|
1369
|
+
]
|
|
1370
|
+
},
|
|
1371
|
+
s.name
|
|
1372
|
+
)) })
|
|
1373
|
+
]
|
|
1374
|
+
}
|
|
1375
|
+
);
|
|
1376
|
+
};
|
|
1377
|
+
|
|
1378
|
+
// src/spreadsheet/SpreadsheetEditor.tsx
|
|
1379
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1380
|
+
var COLUMN_HEADER_HEIGHT = 28;
|
|
1381
|
+
var ROW_HEADER_WIDTH = 48;
|
|
1382
|
+
function frozenCellStyle(viewRow, viewCol) {
|
|
1383
|
+
if (!viewRow.frozen && !viewCol.frozen) return void 0;
|
|
1384
|
+
return {
|
|
1385
|
+
position: "sticky",
|
|
1386
|
+
...viewRow.frozen ? { top: COLUMN_HEADER_HEIGHT + viewRow.stickyTop } : {},
|
|
1387
|
+
...viewCol.frozen ? { left: ROW_HEADER_WIDTH + viewCol.stickyLeft } : {},
|
|
1388
|
+
zIndex: viewRow.frozen && viewCol.frozen ? 14 : viewRow.frozen ? 12 : 11,
|
|
1389
|
+
background: "var(--background, #fff)"
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
807
1392
|
var SpreadsheetEditor = ({
|
|
808
1393
|
state: externalState,
|
|
809
1394
|
readOnly = false,
|
|
@@ -814,27 +1399,47 @@ var SpreadsheetEditor = ({
|
|
|
814
1399
|
}) => {
|
|
815
1400
|
const defaultState = useSpreadsheetEditor();
|
|
816
1401
|
const state = externalState || defaultState;
|
|
817
|
-
const gridRef = (0,
|
|
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_editor12.rangeContains)(state.selectedRange, rIdx, cIdx)) {
|
|
1423
|
+
state.selectCell(rIdx, cIdx);
|
|
1424
|
+
}
|
|
1425
|
+
setMenu({ x: e.clientX, y: e.clientY, items: (0, import_editor12.getSpreadsheetMenuItems)(state.controller, { row: rIdx, col: cIdx }) });
|
|
1426
|
+
}, [readOnly, state]);
|
|
1427
|
+
const activeRawValue = (0, import_react19.useMemo)(() => {
|
|
823
1428
|
if (!state.activeCell) return "";
|
|
824
1429
|
const row = state.document.rows[state.activeCell.row];
|
|
825
1430
|
const col = state.document.columns[state.activeCell.col];
|
|
826
1431
|
if (!row || !col) return "";
|
|
827
1432
|
return state.getCell(row.id, col.id).raw;
|
|
828
1433
|
}, [state.activeCell, state.document]);
|
|
829
|
-
const coordLabel = (0,
|
|
1434
|
+
const coordLabel = (0, import_react19.useMemo)(() => {
|
|
830
1435
|
if (!state.activeCell) return "--";
|
|
831
|
-
const colName = (0,
|
|
1436
|
+
const colName = (0, import_editor12.indexToColName)(state.activeCell.col);
|
|
832
1437
|
return `${colName}${state.activeCell.row + 1}`;
|
|
833
1438
|
}, [state.activeCell]);
|
|
834
|
-
const [formulaDraft, setFormulaDraft] = (0,
|
|
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_editor12.normalizeRange)(state.selectedRange) : null;
|
|
1846
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1847
|
+
"tr",
|
|
1848
|
+
{
|
|
1849
|
+
"data-row": displayRowIndex,
|
|
1850
|
+
className: `border-b border-border hover:bg-muted/10 transition-colors ${viewRow.section !== "body" ? "bg-muted/30 font-semibold" : ""}`,
|
|
1851
|
+
style: { height: viewRow.row.height || 32 },
|
|
1852
|
+
children: [
|
|
1853
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1854
|
+
"td",
|
|
1855
|
+
{
|
|
1856
|
+
className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted/50 border-r border-border text-center text-[10px] text-muted-foreground font-mono select-none",
|
|
1857
|
+
style: viewRow.frozen ? { top: COLUMN_HEADER_HEIGHT + viewRow.stickyTop, zIndex: 15 } : void 0,
|
|
1858
|
+
children: displayRowIndex + 1
|
|
1859
|
+
}
|
|
1860
|
+
),
|
|
1861
|
+
view.columns.map((viewCol) => {
|
|
1862
|
+
const span = view.getCellSpan(displayRowIndex, viewCol.index);
|
|
1863
|
+
if (!span) return null;
|
|
1864
|
+
const rIdx = span.source.row;
|
|
1865
|
+
const cIdx = span.source.col;
|
|
1866
|
+
const row = state.document.rows[rIdx];
|
|
1867
|
+
const col = state.document.columns[cIdx];
|
|
1868
|
+
const cell = state.getCell(row.id, col.id);
|
|
1869
|
+
const selected = isCellSelected(rIdx, cIdx);
|
|
1870
|
+
const active = isActiveCell(rIdx, cIdx);
|
|
1871
|
+
const isEditing = state.editingCell?.row === rIdx && state.editingCell?.col === cIdx;
|
|
1872
|
+
const inFillPreview = !!fillTarget && !selected && (0, import_editor12.rangeContains)(fillTarget, displayRowIndex, viewCol.index);
|
|
1873
|
+
const showFillHandle = !readOnly && !isEditing && !!selection && (span.merge ? (0, import_editor12.rangeContains)(span.merge, selection.endRow, selection.endCol) : selection.endRow === rIdx && selection.endCol === cIdx);
|
|
1874
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1875
|
+
"td",
|
|
1876
|
+
{
|
|
1877
|
+
"data-row": rIdx,
|
|
1878
|
+
"data-col": cIdx,
|
|
1879
|
+
rowSpan: span.rowSpan,
|
|
1880
|
+
colSpan: span.colSpan,
|
|
1881
|
+
className: `relative border-r border-border px-2 py-1 truncate max-w-0 text-foreground transition-colors ${selected ? "bg-primary/10" : ""} ${active ? "ring-2 ring-primary ring-inset z-10" : ""} ${viewCol.header ? "font-semibold" : ""}`,
|
|
1882
|
+
style: {
|
|
1883
|
+
maxWidth: 0,
|
|
1884
|
+
overflow: "hidden",
|
|
1885
|
+
...frozenCellStyle(viewRow, viewCol),
|
|
1886
|
+
...inFillPreview ? { outline: "1px dashed var(--primary, #6366f1)", outlineOffset: -1 } : {}
|
|
1887
|
+
},
|
|
1888
|
+
onClick: (e) => handleCellClick(rIdx, cIdx, e),
|
|
1889
|
+
onDoubleClick: () => handleCellDblClick(rIdx, cIdx),
|
|
1890
|
+
onContextMenu: (e) => handleCellContextMenu(rIdx, cIdx, e),
|
|
1891
|
+
onMouseOver: () => extendFill(displayRowIndex, viewCol.index),
|
|
1892
|
+
children: [
|
|
1893
|
+
isEditing ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1894
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1895
|
+
"input",
|
|
1896
|
+
{
|
|
1897
|
+
ref: cellInputRef,
|
|
1898
|
+
type: "text",
|
|
1899
|
+
className: "absolute inset-0 w-full h-full px-2 py-1 bg-background text-foreground outline-none font-sans text-xs border-2 border-primary z-20",
|
|
1900
|
+
value: state.draftValue,
|
|
1901
|
+
onChange: (e) => state.setDraftValue(e.target.value),
|
|
1902
|
+
onBlur: () => state.commitEditing(),
|
|
1903
|
+
autoFocus: true
|
|
1904
|
+
}
|
|
1905
|
+
),
|
|
1906
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FormulaHints, { inputRef: cellInputRef, value: state.draftValue, onAccept: state.setDraftValue })
|
|
1907
|
+
] }) : customCellRenderer ? customCellRenderer({ row, col, cell }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1908
|
+
"span",
|
|
1909
|
+
{
|
|
1910
|
+
className: `truncate block max-w-full ${cell.error ? "text-destructive font-semibold" : ""}`,
|
|
1911
|
+
title: cell.error ? cell.errorMessage ?? cell.error : void 0,
|
|
1912
|
+
children: cell.error || (cell.value ?? "")
|
|
1913
|
+
}
|
|
1914
|
+
),
|
|
1915
|
+
showFillHandle && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1916
|
+
"div",
|
|
1917
|
+
{
|
|
1918
|
+
className: "spreadsheet-fill-handle",
|
|
1919
|
+
"aria-label": "Fill handle",
|
|
1920
|
+
onMouseDown: startFill,
|
|
1921
|
+
onClick: (e) => e.stopPropagation(),
|
|
1922
|
+
style: { position: "absolute", right: 0, bottom: 0, width: 7, height: 7, background: "var(--primary, #6366f1)", cursor: "crosshair", zIndex: 25 }
|
|
1923
|
+
}
|
|
1924
|
+
)
|
|
1925
|
+
]
|
|
1926
|
+
},
|
|
1927
|
+
viewCol.column.id
|
|
1928
|
+
);
|
|
1929
|
+
}),
|
|
1930
|
+
onAddColumnClick && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { className: "w-10 min-w-[2.5rem] bg-muted/10 border-r border-border" })
|
|
1931
|
+
]
|
|
1932
|
+
},
|
|
1933
|
+
viewRow.row.id
|
|
1934
|
+
);
|
|
1935
|
+
}) })
|
|
1242
1936
|
] }) }),
|
|
1243
|
-
/* @__PURE__ */ (0,
|
|
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,107 +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
|
|
2077
|
+
const toSourceDataURL = (0, import_react21.useCallback)(
|
|
2078
|
+
(opts) => controller.toSourceDataURL(opts),
|
|
2079
|
+
[controller]
|
|
2080
|
+
);
|
|
2081
|
+
const applyInpaintedImage = (0, import_react21.useCallback)(
|
|
1372
2082
|
(newDataUrl) => controller.applyInpaintedImage(newDataUrl),
|
|
1373
2083
|
[controller]
|
|
1374
2084
|
);
|
|
1375
|
-
const applyBackgroundRemovedImage = (0,
|
|
2085
|
+
const applyBackgroundRemovedImage = (0, import_react21.useCallback)(
|
|
1376
2086
|
(newDataUrl) => controller.applyBackgroundRemovedImage(newDataUrl),
|
|
1377
2087
|
[controller]
|
|
1378
2088
|
);
|
|
1379
|
-
return (0,
|
|
2089
|
+
return (0, import_react21.useMemo)(
|
|
1380
2090
|
() => ({
|
|
1381
2091
|
controller,
|
|
1382
2092
|
state,
|
|
@@ -1415,6 +2125,7 @@ function useImageEditor(options = {}) {
|
|
|
1415
2125
|
loadJSON,
|
|
1416
2126
|
renderMask,
|
|
1417
2127
|
toMaskDataURL,
|
|
2128
|
+
toSourceDataURL,
|
|
1418
2129
|
applyInpaintedImage,
|
|
1419
2130
|
applyBackgroundRemovedImage
|
|
1420
2131
|
}),
|
|
@@ -1424,9 +2135,9 @@ function useImageEditor(options = {}) {
|
|
|
1424
2135
|
}
|
|
1425
2136
|
|
|
1426
2137
|
// src/image-editor/ImageEditor.tsx
|
|
1427
|
-
var
|
|
2138
|
+
var import_react22 = require("react");
|
|
1428
2139
|
var import_image_editor2 = require("@pixerate/editor/image-editor");
|
|
1429
|
-
var
|
|
2140
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1430
2141
|
var ImageEditor = ({
|
|
1431
2142
|
editor: externalEditor,
|
|
1432
2143
|
src,
|
|
@@ -1441,16 +2152,16 @@ var ImageEditor = ({
|
|
|
1441
2152
|
const internalEditor = useImageEditor({ image: src });
|
|
1442
2153
|
const editor = externalEditor || internalEditor;
|
|
1443
2154
|
const { state, controller } = editor;
|
|
1444
|
-
const canvasRef = (0,
|
|
1445
|
-
const containerRef = (0,
|
|
1446
|
-
const [activeTab, setActiveTab] = (0,
|
|
1447
|
-
const [activeCropRatio, setActiveCropRatio] = (0,
|
|
1448
|
-
const [inpaintPrompt, setInpaintPrompt] = (0,
|
|
1449
|
-
const [inpaintMaskMode, setInpaintMaskMode] = (0,
|
|
1450
|
-
const [isRemovingBg, setIsRemovingBg] = (0,
|
|
1451
|
-
const [isInpainting, setIsInpainting] = (0,
|
|
1452
|
-
const [aiError, setAiError] = (0,
|
|
1453
|
-
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);
|
|
1454
2165
|
const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
|
|
1455
2166
|
const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
|
|
1456
2167
|
const handleRemoveBackground = async () => {
|
|
@@ -1462,7 +2173,7 @@ var ImageEditor = ({
|
|
|
1462
2173
|
setAiSuccess(null);
|
|
1463
2174
|
setIsRemovingBg(true);
|
|
1464
2175
|
try {
|
|
1465
|
-
const imageDataUrl = await editor.
|
|
2176
|
+
const imageDataUrl = await editor.toSourceDataURL();
|
|
1466
2177
|
const result = await effectiveOnRemoveBg({ imageDataUrl });
|
|
1467
2178
|
if (typeof result === "string") {
|
|
1468
2179
|
await editor.applyBackgroundRemovedImage(result);
|
|
@@ -1489,7 +2200,7 @@ var ImageEditor = ({
|
|
|
1489
2200
|
setAiSuccess(null);
|
|
1490
2201
|
setIsInpainting(true);
|
|
1491
2202
|
try {
|
|
1492
|
-
const imageDataUrl = await editor.
|
|
2203
|
+
const imageDataUrl = await editor.toSourceDataURL();
|
|
1493
2204
|
const maskDataUrl = await editor.toMaskDataURL({
|
|
1494
2205
|
useAnnotations: inpaintMaskMode === "annotations",
|
|
1495
2206
|
useCrop: inpaintMaskMode === "crop"
|
|
@@ -1512,18 +2223,18 @@ var ImageEditor = ({
|
|
|
1512
2223
|
setIsInpainting(false);
|
|
1513
2224
|
}
|
|
1514
2225
|
};
|
|
1515
|
-
const [activeColor, setActiveColor] = (0,
|
|
1516
|
-
const [strokeWidth, setStrokeWidth] = (0,
|
|
1517
|
-
const [fontSize, setFontSize] = (0,
|
|
1518
|
-
const [textInput, setTextInput] = (0,
|
|
1519
|
-
const draftAnnotationRef = (0,
|
|
1520
|
-
const draftCropRef = (0,
|
|
1521
|
-
const cropDragInfoRef = (0,
|
|
1522
|
-
const annotationDragInfoRef = (0,
|
|
1523
|
-
const isDrawingRef = (0,
|
|
1524
|
-
const currentPathRef = (0,
|
|
1525
|
-
const dragStartPointRef = (0,
|
|
1526
|
-
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)(
|
|
1527
2238
|
async (draftAnnotation, draftCrop) => {
|
|
1528
2239
|
const canvas = canvasRef.current;
|
|
1529
2240
|
const container = containerRef.current;
|
|
@@ -1542,7 +2253,7 @@ var ImageEditor = ({
|
|
|
1542
2253
|
},
|
|
1543
2254
|
[controller, activeTab]
|
|
1544
2255
|
);
|
|
1545
|
-
(0,
|
|
2256
|
+
(0, import_react22.useEffect)(() => {
|
|
1546
2257
|
const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
|
|
1547
2258
|
const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
|
|
1548
2259
|
const animId = raf(() => {
|
|
@@ -1550,12 +2261,12 @@ var ImageEditor = ({
|
|
|
1550
2261
|
});
|
|
1551
2262
|
return () => caf(animId);
|
|
1552
2263
|
}, [renderCanvas, state]);
|
|
1553
|
-
(0,
|
|
2264
|
+
(0, import_react22.useEffect)(() => {
|
|
1554
2265
|
if (activeTab === "crop" && editor.state.activeTool !== "crop") {
|
|
1555
2266
|
editor.setTool("crop");
|
|
1556
2267
|
}
|
|
1557
2268
|
}, [activeTab, editor]);
|
|
1558
|
-
(0,
|
|
2269
|
+
(0, import_react22.useEffect)(() => {
|
|
1559
2270
|
const container = containerRef.current;
|
|
1560
2271
|
if (!container) return;
|
|
1561
2272
|
if (typeof ResizeObserver !== "undefined") {
|
|
@@ -1675,7 +2386,8 @@ var ImageEditor = ({
|
|
|
1675
2386
|
currentImgPt,
|
|
1676
2387
|
state.imageDimensions.width,
|
|
1677
2388
|
state.imageDimensions.height,
|
|
1678
|
-
activeCropRatio
|
|
2389
|
+
activeCropRatio,
|
|
2390
|
+
state.transform
|
|
1679
2391
|
);
|
|
1680
2392
|
}
|
|
1681
2393
|
draftCropRef.current = newCrop;
|
|
@@ -1688,7 +2400,7 @@ var ImageEditor = ({
|
|
|
1688
2400
|
height: state.imageDimensions.height
|
|
1689
2401
|
};
|
|
1690
2402
|
const handle = (0, import_image_editor2.hitTestCrop)(canvasPt, state, canvas.width, canvas.height, 14, activeCrop);
|
|
1691
|
-
canvas.style.cursor = (0, import_image_editor2.getCropCursor)(handle);
|
|
2403
|
+
canvas.style.cursor = (0, import_image_editor2.getCropCursor)(handle, state.transform);
|
|
1692
2404
|
}
|
|
1693
2405
|
return;
|
|
1694
2406
|
}
|
|
@@ -1912,15 +2624,15 @@ var ImageEditor = ({
|
|
|
1912
2624
|
link.click();
|
|
1913
2625
|
}
|
|
1914
2626
|
};
|
|
1915
|
-
return /* @__PURE__ */ (0,
|
|
2627
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1916
2628
|
"div",
|
|
1917
2629
|
{
|
|
1918
2630
|
className: `flex flex-col bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-2xl text-slate-100 ${className}`,
|
|
1919
2631
|
style,
|
|
1920
2632
|
children: [
|
|
1921
|
-
/* @__PURE__ */ (0,
|
|
1922
|
-
/* @__PURE__ */ (0,
|
|
1923
|
-
/* @__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)(
|
|
1924
2636
|
"button",
|
|
1925
2637
|
{
|
|
1926
2638
|
type: "button",
|
|
@@ -1932,7 +2644,7 @@ var ImageEditor = ({
|
|
|
1932
2644
|
children: "Transform & Crop"
|
|
1933
2645
|
}
|
|
1934
2646
|
),
|
|
1935
|
-
/* @__PURE__ */ (0,
|
|
2647
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1936
2648
|
"button",
|
|
1937
2649
|
{
|
|
1938
2650
|
type: "button",
|
|
@@ -1944,7 +2656,7 @@ var ImageEditor = ({
|
|
|
1944
2656
|
children: "Adjustments"
|
|
1945
2657
|
}
|
|
1946
2658
|
),
|
|
1947
|
-
/* @__PURE__ */ (0,
|
|
2659
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1948
2660
|
"button",
|
|
1949
2661
|
{
|
|
1950
2662
|
type: "button",
|
|
@@ -1956,7 +2668,7 @@ var ImageEditor = ({
|
|
|
1956
2668
|
children: "Annotations"
|
|
1957
2669
|
}
|
|
1958
2670
|
),
|
|
1959
|
-
/* @__PURE__ */ (0,
|
|
2671
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1960
2672
|
"button",
|
|
1961
2673
|
{
|
|
1962
2674
|
type: "button",
|
|
@@ -1968,7 +2680,7 @@ var ImageEditor = ({
|
|
|
1968
2680
|
children: "Depth Mask"
|
|
1969
2681
|
}
|
|
1970
2682
|
),
|
|
1971
|
-
/* @__PURE__ */ (0,
|
|
2683
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1972
2684
|
"button",
|
|
1973
2685
|
{
|
|
1974
2686
|
type: "button",
|
|
@@ -1978,14 +2690,14 @@ var ImageEditor = ({
|
|
|
1978
2690
|
},
|
|
1979
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"}`,
|
|
1980
2692
|
children: [
|
|
1981
|
-
/* @__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" }) }),
|
|
1982
2694
|
"AI Tools"
|
|
1983
2695
|
]
|
|
1984
2696
|
}
|
|
1985
2697
|
)
|
|
1986
2698
|
] }),
|
|
1987
|
-
/* @__PURE__ */ (0,
|
|
1988
|
-
/* @__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)(
|
|
1989
2701
|
"button",
|
|
1990
2702
|
{
|
|
1991
2703
|
type: "button",
|
|
@@ -1996,7 +2708,7 @@ var ImageEditor = ({
|
|
|
1996
2708
|
children: "\u21A9"
|
|
1997
2709
|
}
|
|
1998
2710
|
),
|
|
1999
|
-
/* @__PURE__ */ (0,
|
|
2711
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2000
2712
|
"button",
|
|
2001
2713
|
{
|
|
2002
2714
|
type: "button",
|
|
@@ -2007,7 +2719,7 @@ var ImageEditor = ({
|
|
|
2007
2719
|
children: "\u21AA"
|
|
2008
2720
|
}
|
|
2009
2721
|
),
|
|
2010
|
-
/* @__PURE__ */ (0,
|
|
2722
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2011
2723
|
"button",
|
|
2012
2724
|
{
|
|
2013
2725
|
type: "button",
|
|
@@ -2016,8 +2728,8 @@ var ImageEditor = ({
|
|
|
2016
2728
|
children: "Reset"
|
|
2017
2729
|
}
|
|
2018
2730
|
),
|
|
2019
|
-
/* @__PURE__ */ (0,
|
|
2020
|
-
/* @__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)(
|
|
2021
2733
|
"button",
|
|
2022
2734
|
{
|
|
2023
2735
|
type: "button",
|
|
@@ -2027,11 +2739,11 @@ var ImageEditor = ({
|
|
|
2027
2739
|
children: "-"
|
|
2028
2740
|
}
|
|
2029
2741
|
),
|
|
2030
|
-
/* @__PURE__ */ (0,
|
|
2742
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "font-mono text-slate-400 w-10 text-center", children: [
|
|
2031
2743
|
Math.round(state.zoom * 100),
|
|
2032
2744
|
"%"
|
|
2033
2745
|
] }),
|
|
2034
|
-
/* @__PURE__ */ (0,
|
|
2746
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2035
2747
|
"button",
|
|
2036
2748
|
{
|
|
2037
2749
|
type: "button",
|
|
@@ -2041,8 +2753,8 @@ var ImageEditor = ({
|
|
|
2041
2753
|
children: "+"
|
|
2042
2754
|
}
|
|
2043
2755
|
),
|
|
2044
|
-
/* @__PURE__ */ (0,
|
|
2045
|
-
/* @__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)(
|
|
2046
2758
|
"button",
|
|
2047
2759
|
{
|
|
2048
2760
|
type: "button",
|
|
@@ -2053,7 +2765,7 @@ var ImageEditor = ({
|
|
|
2053
2765
|
children: "Hold Compare"
|
|
2054
2766
|
}
|
|
2055
2767
|
),
|
|
2056
|
-
/* @__PURE__ */ (0,
|
|
2768
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2057
2769
|
"button",
|
|
2058
2770
|
{
|
|
2059
2771
|
type: "button",
|
|
@@ -2064,13 +2776,13 @@ var ImageEditor = ({
|
|
|
2064
2776
|
)
|
|
2065
2777
|
] })
|
|
2066
2778
|
] }),
|
|
2067
|
-
/* @__PURE__ */ (0,
|
|
2068
|
-
/* @__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)(
|
|
2069
2781
|
"div",
|
|
2070
2782
|
{
|
|
2071
2783
|
ref: containerRef,
|
|
2072
2784
|
className: "relative flex-1 h-[360px] md:h-full min-h-[320px] bg-slate-950 overflow-hidden select-none",
|
|
2073
|
-
children: /* @__PURE__ */ (0,
|
|
2785
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2074
2786
|
"canvas",
|
|
2075
2787
|
{
|
|
2076
2788
|
ref: canvasRef,
|
|
@@ -2083,11 +2795,11 @@ var ImageEditor = ({
|
|
|
2083
2795
|
)
|
|
2084
2796
|
}
|
|
2085
2797
|
),
|
|
2086
|
-
/* @__PURE__ */ (0,
|
|
2087
|
-
activeTab === "crop" && /* @__PURE__ */ (0,
|
|
2088
|
-
/* @__PURE__ */ (0,
|
|
2089
|
-
/* @__PURE__ */ (0,
|
|
2090
|
-
/* @__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)(
|
|
2091
2803
|
"button",
|
|
2092
2804
|
{
|
|
2093
2805
|
type: "button",
|
|
@@ -2099,7 +2811,7 @@ var ImageEditor = ({
|
|
|
2099
2811
|
children: "Freeform"
|
|
2100
2812
|
}
|
|
2101
2813
|
),
|
|
2102
|
-
/* @__PURE__ */ (0,
|
|
2814
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2103
2815
|
"button",
|
|
2104
2816
|
{
|
|
2105
2817
|
type: "button",
|
|
@@ -2111,7 +2823,7 @@ var ImageEditor = ({
|
|
|
2111
2823
|
children: "1:1 Square"
|
|
2112
2824
|
}
|
|
2113
2825
|
),
|
|
2114
|
-
/* @__PURE__ */ (0,
|
|
2826
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2115
2827
|
"button",
|
|
2116
2828
|
{
|
|
2117
2829
|
type: "button",
|
|
@@ -2123,7 +2835,7 @@ var ImageEditor = ({
|
|
|
2123
2835
|
children: "4:3 Standard"
|
|
2124
2836
|
}
|
|
2125
2837
|
),
|
|
2126
|
-
/* @__PURE__ */ (0,
|
|
2838
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2127
2839
|
"button",
|
|
2128
2840
|
{
|
|
2129
2841
|
type: "button",
|
|
@@ -2135,7 +2847,7 @@ var ImageEditor = ({
|
|
|
2135
2847
|
children: "16:9 Wide"
|
|
2136
2848
|
}
|
|
2137
2849
|
),
|
|
2138
|
-
/* @__PURE__ */ (0,
|
|
2850
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2139
2851
|
"button",
|
|
2140
2852
|
{
|
|
2141
2853
|
type: "button",
|
|
@@ -2147,7 +2859,7 @@ var ImageEditor = ({
|
|
|
2147
2859
|
children: "3:2 Photo"
|
|
2148
2860
|
}
|
|
2149
2861
|
),
|
|
2150
|
-
/* @__PURE__ */ (0,
|
|
2862
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2151
2863
|
"button",
|
|
2152
2864
|
{
|
|
2153
2865
|
type: "button",
|
|
@@ -2160,10 +2872,10 @@ var ImageEditor = ({
|
|
|
2160
2872
|
}
|
|
2161
2873
|
)
|
|
2162
2874
|
] }),
|
|
2163
|
-
/* @__PURE__ */ (0,
|
|
2164
|
-
/* @__PURE__ */ (0,
|
|
2165
|
-
/* @__PURE__ */ (0,
|
|
2166
|
-
/* @__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)(
|
|
2167
2879
|
"button",
|
|
2168
2880
|
{
|
|
2169
2881
|
type: "button",
|
|
@@ -2172,7 +2884,7 @@ var ImageEditor = ({
|
|
|
2172
2884
|
children: "Rotate -90\xB0"
|
|
2173
2885
|
}
|
|
2174
2886
|
),
|
|
2175
|
-
/* @__PURE__ */ (0,
|
|
2887
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2176
2888
|
"button",
|
|
2177
2889
|
{
|
|
2178
2890
|
type: "button",
|
|
@@ -2181,7 +2893,7 @@ var ImageEditor = ({
|
|
|
2181
2893
|
children: "Rotate +90\xB0"
|
|
2182
2894
|
}
|
|
2183
2895
|
),
|
|
2184
|
-
/* @__PURE__ */ (0,
|
|
2896
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2185
2897
|
"button",
|
|
2186
2898
|
{
|
|
2187
2899
|
type: "button",
|
|
@@ -2190,7 +2902,7 @@ var ImageEditor = ({
|
|
|
2190
2902
|
children: "Flip Horizontal"
|
|
2191
2903
|
}
|
|
2192
2904
|
),
|
|
2193
|
-
/* @__PURE__ */ (0,
|
|
2905
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2194
2906
|
"button",
|
|
2195
2907
|
{
|
|
2196
2908
|
type: "button",
|
|
@@ -2201,10 +2913,10 @@ var ImageEditor = ({
|
|
|
2201
2913
|
)
|
|
2202
2914
|
] })
|
|
2203
2915
|
] }),
|
|
2204
|
-
activeTab === "adjust" && /* @__PURE__ */ (0,
|
|
2205
|
-
/* @__PURE__ */ (0,
|
|
2206
|
-
/* @__PURE__ */ (0,
|
|
2207
|
-
/* @__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)(
|
|
2208
2920
|
"button",
|
|
2209
2921
|
{
|
|
2210
2922
|
type: "button",
|
|
@@ -2214,12 +2926,12 @@ var ImageEditor = ({
|
|
|
2214
2926
|
}
|
|
2215
2927
|
)
|
|
2216
2928
|
] }),
|
|
2217
|
-
/* @__PURE__ */ (0,
|
|
2218
|
-
/* @__PURE__ */ (0,
|
|
2219
|
-
/* @__PURE__ */ (0,
|
|
2220
|
-
/* @__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 })
|
|
2221
2933
|
] }),
|
|
2222
|
-
/* @__PURE__ */ (0,
|
|
2934
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2223
2935
|
"input",
|
|
2224
2936
|
{
|
|
2225
2937
|
type: "range",
|
|
@@ -2231,12 +2943,12 @@ var ImageEditor = ({
|
|
|
2231
2943
|
}
|
|
2232
2944
|
)
|
|
2233
2945
|
] }),
|
|
2234
|
-
/* @__PURE__ */ (0,
|
|
2235
|
-
/* @__PURE__ */ (0,
|
|
2236
|
-
/* @__PURE__ */ (0,
|
|
2237
|
-
/* @__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 })
|
|
2238
2950
|
] }),
|
|
2239
|
-
/* @__PURE__ */ (0,
|
|
2951
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2240
2952
|
"input",
|
|
2241
2953
|
{
|
|
2242
2954
|
type: "range",
|
|
@@ -2248,12 +2960,12 @@ var ImageEditor = ({
|
|
|
2248
2960
|
}
|
|
2249
2961
|
)
|
|
2250
2962
|
] }),
|
|
2251
|
-
/* @__PURE__ */ (0,
|
|
2252
|
-
/* @__PURE__ */ (0,
|
|
2253
|
-
/* @__PURE__ */ (0,
|
|
2254
|
-
/* @__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 })
|
|
2255
2967
|
] }),
|
|
2256
|
-
/* @__PURE__ */ (0,
|
|
2968
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2257
2969
|
"input",
|
|
2258
2970
|
{
|
|
2259
2971
|
type: "range",
|
|
@@ -2265,12 +2977,12 @@ var ImageEditor = ({
|
|
|
2265
2977
|
}
|
|
2266
2978
|
)
|
|
2267
2979
|
] }),
|
|
2268
|
-
/* @__PURE__ */ (0,
|
|
2269
|
-
/* @__PURE__ */ (0,
|
|
2270
|
-
/* @__PURE__ */ (0,
|
|
2271
|
-
/* @__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 })
|
|
2272
2984
|
] }),
|
|
2273
|
-
/* @__PURE__ */ (0,
|
|
2985
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2274
2986
|
"input",
|
|
2275
2987
|
{
|
|
2276
2988
|
type: "range",
|
|
@@ -2282,12 +2994,12 @@ var ImageEditor = ({
|
|
|
2282
2994
|
}
|
|
2283
2995
|
)
|
|
2284
2996
|
] }),
|
|
2285
|
-
/* @__PURE__ */ (0,
|
|
2286
|
-
/* @__PURE__ */ (0,
|
|
2287
|
-
/* @__PURE__ */ (0,
|
|
2288
|
-
/* @__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 })
|
|
2289
3001
|
] }),
|
|
2290
|
-
/* @__PURE__ */ (0,
|
|
3002
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2291
3003
|
"input",
|
|
2292
3004
|
{
|
|
2293
3005
|
type: "range",
|
|
@@ -2299,15 +3011,15 @@ var ImageEditor = ({
|
|
|
2299
3011
|
}
|
|
2300
3012
|
)
|
|
2301
3013
|
] }),
|
|
2302
|
-
/* @__PURE__ */ (0,
|
|
2303
|
-
/* @__PURE__ */ (0,
|
|
2304
|
-
/* @__PURE__ */ (0,
|
|
2305
|
-
/* @__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: [
|
|
2306
3018
|
state.adjustments.blur,
|
|
2307
3019
|
"px"
|
|
2308
3020
|
] })
|
|
2309
3021
|
] }),
|
|
2310
|
-
/* @__PURE__ */ (0,
|
|
3022
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2311
3023
|
"input",
|
|
2312
3024
|
{
|
|
2313
3025
|
type: "range",
|
|
@@ -2319,15 +3031,15 @@ var ImageEditor = ({
|
|
|
2319
3031
|
}
|
|
2320
3032
|
)
|
|
2321
3033
|
] }),
|
|
2322
|
-
/* @__PURE__ */ (0,
|
|
2323
|
-
/* @__PURE__ */ (0,
|
|
2324
|
-
/* @__PURE__ */ (0,
|
|
2325
|
-
/* @__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: [
|
|
2326
3038
|
Math.round(state.adjustments.opacity * 100),
|
|
2327
3039
|
"%"
|
|
2328
3040
|
] })
|
|
2329
3041
|
] }),
|
|
2330
|
-
/* @__PURE__ */ (0,
|
|
3042
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2331
3043
|
"input",
|
|
2332
3044
|
{
|
|
2333
3045
|
type: "range",
|
|
@@ -2341,9 +3053,9 @@ var ImageEditor = ({
|
|
|
2341
3053
|
)
|
|
2342
3054
|
] })
|
|
2343
3055
|
] }),
|
|
2344
|
-
activeTab === "annotate" && /* @__PURE__ */ (0,
|
|
2345
|
-
/* @__PURE__ */ (0,
|
|
2346
|
-
/* @__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)(
|
|
2347
3059
|
"button",
|
|
2348
3060
|
{
|
|
2349
3061
|
type: "button",
|
|
@@ -2353,9 +3065,9 @@ var ImageEditor = ({
|
|
|
2353
3065
|
},
|
|
2354
3066
|
t
|
|
2355
3067
|
)) }),
|
|
2356
|
-
/* @__PURE__ */ (0,
|
|
2357
|
-
/* @__PURE__ */ (0,
|
|
2358
|
-
/* @__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)(
|
|
2359
3071
|
"input",
|
|
2360
3072
|
{
|
|
2361
3073
|
type: "color",
|
|
@@ -2364,15 +3076,15 @@ var ImageEditor = ({
|
|
|
2364
3076
|
className: "w-8 h-8 rounded border border-slate-700 cursor-pointer bg-transparent"
|
|
2365
3077
|
}
|
|
2366
3078
|
),
|
|
2367
|
-
/* @__PURE__ */ (0,
|
|
2368
|
-
/* @__PURE__ */ (0,
|
|
2369
|
-
/* @__PURE__ */ (0,
|
|
2370
|
-
/* @__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: [
|
|
2371
3083
|
strokeWidth,
|
|
2372
3084
|
"px"
|
|
2373
3085
|
] })
|
|
2374
3086
|
] }),
|
|
2375
|
-
/* @__PURE__ */ (0,
|
|
3087
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2376
3088
|
"input",
|
|
2377
3089
|
{
|
|
2378
3090
|
type: "range",
|
|
@@ -2385,10 +3097,10 @@ var ImageEditor = ({
|
|
|
2385
3097
|
)
|
|
2386
3098
|
] })
|
|
2387
3099
|
] }),
|
|
2388
|
-
/* @__PURE__ */ (0,
|
|
2389
|
-
/* @__PURE__ */ (0,
|
|
2390
|
-
/* @__PURE__ */ (0,
|
|
2391
|
-
/* @__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)(
|
|
2392
3104
|
"input",
|
|
2393
3105
|
{
|
|
2394
3106
|
type: "text",
|
|
@@ -2399,7 +3111,7 @@ var ImageEditor = ({
|
|
|
2399
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"
|
|
2400
3112
|
}
|
|
2401
3113
|
),
|
|
2402
|
-
/* @__PURE__ */ (0,
|
|
3114
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2403
3115
|
"button",
|
|
2404
3116
|
{
|
|
2405
3117
|
type: "button",
|
|
@@ -2409,14 +3121,14 @@ var ImageEditor = ({
|
|
|
2409
3121
|
}
|
|
2410
3122
|
)
|
|
2411
3123
|
] }),
|
|
2412
|
-
/* @__PURE__ */ (0,
|
|
2413
|
-
/* @__PURE__ */ (0,
|
|
2414
|
-
/* @__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: [
|
|
2415
3127
|
fontSize,
|
|
2416
3128
|
"px"
|
|
2417
3129
|
] })
|
|
2418
3130
|
] }),
|
|
2419
|
-
/* @__PURE__ */ (0,
|
|
3131
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2420
3132
|
"input",
|
|
2421
3133
|
{
|
|
2422
3134
|
type: "range",
|
|
@@ -2427,14 +3139,14 @@ var ImageEditor = ({
|
|
|
2427
3139
|
className: "w-full accent-indigo-500"
|
|
2428
3140
|
}
|
|
2429
3141
|
),
|
|
2430
|
-
/* @__PURE__ */ (0,
|
|
2431
|
-
/* @__PURE__ */ (0,
|
|
2432
|
-
/* @__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: [
|
|
2433
3145
|
"Layers (",
|
|
2434
3146
|
state.annotations.length,
|
|
2435
3147
|
")"
|
|
2436
3148
|
] }),
|
|
2437
|
-
state.selectedAnnotationId && /* @__PURE__ */ (0,
|
|
3149
|
+
state.selectedAnnotationId && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2438
3150
|
"button",
|
|
2439
3151
|
{
|
|
2440
3152
|
type: "button",
|
|
@@ -2443,7 +3155,7 @@ var ImageEditor = ({
|
|
|
2443
3155
|
children: "Delete Selected"
|
|
2444
3156
|
}
|
|
2445
3157
|
),
|
|
2446
|
-
state.annotations.length > 0 && /* @__PURE__ */ (0,
|
|
3158
|
+
state.annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2447
3159
|
"button",
|
|
2448
3160
|
{
|
|
2449
3161
|
type: "button",
|
|
@@ -2454,10 +3166,10 @@ var ImageEditor = ({
|
|
|
2454
3166
|
)
|
|
2455
3167
|
] })
|
|
2456
3168
|
] }),
|
|
2457
|
-
activeTab === "depth" && /* @__PURE__ */ (0,
|
|
2458
|
-
/* @__PURE__ */ (0,
|
|
2459
|
-
/* @__PURE__ */ (0,
|
|
2460
|
-
/* @__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)(
|
|
2461
3173
|
"button",
|
|
2462
3174
|
{
|
|
2463
3175
|
type: "button",
|
|
@@ -2467,8 +3179,8 @@ var ImageEditor = ({
|
|
|
2467
3179
|
}
|
|
2468
3180
|
)
|
|
2469
3181
|
] }),
|
|
2470
|
-
/* @__PURE__ */ (0,
|
|
2471
|
-
/* @__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)(
|
|
2472
3184
|
"input",
|
|
2473
3185
|
{
|
|
2474
3186
|
type: "checkbox",
|
|
@@ -2477,12 +3189,12 @@ var ImageEditor = ({
|
|
|
2477
3189
|
className: "rounded accent-indigo-500"
|
|
2478
3190
|
}
|
|
2479
3191
|
),
|
|
2480
|
-
/* @__PURE__ */ (0,
|
|
3192
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Enable Depth / Alpha Mask" })
|
|
2481
3193
|
] }),
|
|
2482
|
-
state.depthMask.enabled && /* @__PURE__ */ (0,
|
|
2483
|
-
/* @__PURE__ */ (0,
|
|
2484
|
-
/* @__PURE__ */ (0,
|
|
2485
|
-
/* @__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)(
|
|
2486
3198
|
"input",
|
|
2487
3199
|
{
|
|
2488
3200
|
type: "text",
|
|
@@ -2493,8 +3205,8 @@ var ImageEditor = ({
|
|
|
2493
3205
|
}
|
|
2494
3206
|
)
|
|
2495
3207
|
] }),
|
|
2496
|
-
/* @__PURE__ */ (0,
|
|
2497
|
-
/* @__PURE__ */ (0,
|
|
3208
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex gap-2", children: [
|
|
3209
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2498
3210
|
"button",
|
|
2499
3211
|
{
|
|
2500
3212
|
type: "button",
|
|
@@ -2503,7 +3215,7 @@ var ImageEditor = ({
|
|
|
2503
3215
|
children: "Threshold Mode"
|
|
2504
3216
|
}
|
|
2505
3217
|
),
|
|
2506
|
-
/* @__PURE__ */ (0,
|
|
3218
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2507
3219
|
"button",
|
|
2508
3220
|
{
|
|
2509
3221
|
type: "button",
|
|
@@ -2513,12 +3225,12 @@ var ImageEditor = ({
|
|
|
2513
3225
|
}
|
|
2514
3226
|
)
|
|
2515
3227
|
] }),
|
|
2516
|
-
/* @__PURE__ */ (0,
|
|
2517
|
-
/* @__PURE__ */ (0,
|
|
2518
|
-
/* @__PURE__ */ (0,
|
|
2519
|
-
/* @__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] })
|
|
2520
3232
|
] }),
|
|
2521
|
-
/* @__PURE__ */ (0,
|
|
3233
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2522
3234
|
"input",
|
|
2523
3235
|
{
|
|
2524
3236
|
type: "range",
|
|
@@ -2532,12 +3244,12 @@ var ImageEditor = ({
|
|
|
2532
3244
|
}
|
|
2533
3245
|
)
|
|
2534
3246
|
] }),
|
|
2535
|
-
/* @__PURE__ */ (0,
|
|
2536
|
-
/* @__PURE__ */ (0,
|
|
2537
|
-
/* @__PURE__ */ (0,
|
|
2538
|
-
/* @__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] })
|
|
2539
3251
|
] }),
|
|
2540
|
-
/* @__PURE__ */ (0,
|
|
3252
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2541
3253
|
"input",
|
|
2542
3254
|
{
|
|
2543
3255
|
type: "range",
|
|
@@ -2551,12 +3263,12 @@ var ImageEditor = ({
|
|
|
2551
3263
|
}
|
|
2552
3264
|
)
|
|
2553
3265
|
] }),
|
|
2554
|
-
/* @__PURE__ */ (0,
|
|
2555
|
-
/* @__PURE__ */ (0,
|
|
2556
|
-
/* @__PURE__ */ (0,
|
|
2557
|
-
/* @__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 })
|
|
2558
3270
|
] }),
|
|
2559
|
-
/* @__PURE__ */ (0,
|
|
3271
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2560
3272
|
"input",
|
|
2561
3273
|
{
|
|
2562
3274
|
type: "range",
|
|
@@ -2568,8 +3280,8 @@ var ImageEditor = ({
|
|
|
2568
3280
|
}
|
|
2569
3281
|
)
|
|
2570
3282
|
] }),
|
|
2571
|
-
/* @__PURE__ */ (0,
|
|
2572
|
-
/* @__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)(
|
|
2573
3285
|
"input",
|
|
2574
3286
|
{
|
|
2575
3287
|
type: "checkbox",
|
|
@@ -2578,52 +3290,52 @@ var ImageEditor = ({
|
|
|
2578
3290
|
className: "rounded accent-indigo-500"
|
|
2579
3291
|
}
|
|
2580
3292
|
),
|
|
2581
|
-
/* @__PURE__ */ (0,
|
|
3293
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Invert Mask" })
|
|
2582
3294
|
] })
|
|
2583
3295
|
] })
|
|
2584
3296
|
] }),
|
|
2585
|
-
activeTab === "ai" && /* @__PURE__ */ (0,
|
|
2586
|
-
/* @__PURE__ */ (0,
|
|
2587
|
-
/* @__PURE__ */ (0,
|
|
2588
|
-
/* @__PURE__ */ (0,
|
|
2589
|
-
/* @__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" }) }),
|
|
2590
3302
|
"Background Removal"
|
|
2591
3303
|
] }),
|
|
2592
|
-
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..." })
|
|
2593
3305
|
] }),
|
|
2594
|
-
/* @__PURE__ */ (0,
|
|
2595
|
-
/* @__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)(
|
|
2596
3308
|
"button",
|
|
2597
3309
|
{
|
|
2598
3310
|
type: "button",
|
|
2599
3311
|
onClick: handleRemoveBackground,
|
|
2600
3312
|
disabled: isRemovingBg || isInpainting,
|
|
2601
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",
|
|
2602
|
-
children: isRemovingBg ? /* @__PURE__ */ (0,
|
|
2603
|
-
/* @__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" }),
|
|
2604
3316
|
"Removing Background..."
|
|
2605
|
-
] }) : /* @__PURE__ */ (0,
|
|
2606
|
-
/* @__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" }) }),
|
|
2607
3319
|
"Remove Background"
|
|
2608
3320
|
] })
|
|
2609
3321
|
}
|
|
2610
3322
|
)
|
|
2611
3323
|
] }),
|
|
2612
|
-
/* @__PURE__ */ (0,
|
|
2613
|
-
/* @__PURE__ */ (0,
|
|
2614
|
-
/* @__PURE__ */ (0,
|
|
2615
|
-
/* @__PURE__ */ (0,
|
|
2616
|
-
/* @__PURE__ */ (0,
|
|
2617
|
-
/* @__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" })
|
|
2618
3330
|
] }),
|
|
2619
3331
|
"Generative Inpainting"
|
|
2620
3332
|
] }),
|
|
2621
|
-
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..." })
|
|
2622
3334
|
] }),
|
|
2623
|
-
/* @__PURE__ */ (0,
|
|
2624
|
-
/* @__PURE__ */ (0,
|
|
2625
|
-
/* @__PURE__ */ (0,
|
|
2626
|
-
/* @__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)(
|
|
2627
3339
|
"textarea",
|
|
2628
3340
|
{
|
|
2629
3341
|
id: "ai-inpaint-prompt-react",
|
|
@@ -2635,10 +3347,10 @@ var ImageEditor = ({
|
|
|
2635
3347
|
}
|
|
2636
3348
|
)
|
|
2637
3349
|
] }),
|
|
2638
|
-
/* @__PURE__ */ (0,
|
|
2639
|
-
/* @__PURE__ */ (0,
|
|
2640
|
-
/* @__PURE__ */ (0,
|
|
2641
|
-
/* @__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)(
|
|
2642
3354
|
"button",
|
|
2643
3355
|
{
|
|
2644
3356
|
type: "button",
|
|
@@ -2651,7 +3363,7 @@ var ImageEditor = ({
|
|
|
2651
3363
|
]
|
|
2652
3364
|
}
|
|
2653
3365
|
),
|
|
2654
|
-
/* @__PURE__ */ (0,
|
|
3366
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
2655
3367
|
"button",
|
|
2656
3368
|
{
|
|
2657
3369
|
type: "button",
|
|
@@ -2666,25 +3378,25 @@ var ImageEditor = ({
|
|
|
2666
3378
|
)
|
|
2667
3379
|
] })
|
|
2668
3380
|
] }),
|
|
2669
|
-
/* @__PURE__ */ (0,
|
|
3381
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2670
3382
|
"button",
|
|
2671
3383
|
{
|
|
2672
3384
|
type: "button",
|
|
2673
3385
|
onClick: handleInpaint,
|
|
2674
3386
|
disabled: isInpainting || isRemovingBg || !inpaintPrompt.trim(),
|
|
2675
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",
|
|
2676
|
-
children: isInpainting ? /* @__PURE__ */ (0,
|
|
2677
|
-
/* @__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" }),
|
|
2678
3390
|
"Generating Inpaint..."
|
|
2679
|
-
] }) : /* @__PURE__ */ (0,
|
|
2680
|
-
/* @__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" }) }),
|
|
2681
3393
|
"Apply Inpainting"
|
|
2682
3394
|
] })
|
|
2683
3395
|
}
|
|
2684
3396
|
)
|
|
2685
3397
|
] }),
|
|
2686
|
-
aiError && /* @__PURE__ */ (0,
|
|
2687
|
-
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 })
|
|
2688
3400
|
] })
|
|
2689
3401
|
] })
|
|
2690
3402
|
] })
|
|
@@ -2692,27 +3404,356 @@ var ImageEditor = ({
|
|
|
2692
3404
|
}
|
|
2693
3405
|
);
|
|
2694
3406
|
};
|
|
3407
|
+
|
|
3408
|
+
// src/review/useReview.ts
|
|
3409
|
+
var import_react23 = require("react");
|
|
3410
|
+
var import_editor13 = require("@pixerate/editor");
|
|
3411
|
+
var EMPTY_COMMENTS = Object.freeze({
|
|
3412
|
+
threads: [],
|
|
3413
|
+
activeThreadId: null
|
|
3414
|
+
});
|
|
3415
|
+
var EMPTY_TRACK_CHANGES = Object.freeze({
|
|
3416
|
+
enabled: false,
|
|
3417
|
+
author: { id: "anonymous", name: "Anonymous" },
|
|
3418
|
+
changes: [],
|
|
3419
|
+
currentChangeId: null
|
|
3420
|
+
});
|
|
3421
|
+
var noopUnsubscribe = () => {
|
|
3422
|
+
};
|
|
3423
|
+
function isCommentStore(value) {
|
|
3424
|
+
return !!value && typeof value.getSnapshot === "function" && typeof value.createThread === "function";
|
|
3425
|
+
}
|
|
3426
|
+
function useComments(source) {
|
|
3427
|
+
const store = isCommentStore(source) ? source : (0, import_editor13.getCommentStore)(source);
|
|
3428
|
+
const subscribe = (0, import_react23.useCallback)(
|
|
3429
|
+
(onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
|
|
3430
|
+
[store]
|
|
3431
|
+
);
|
|
3432
|
+
const getSnapshot = () => store?.getSnapshot() ?? EMPTY_COMMENTS;
|
|
3433
|
+
const snapshot = (0, import_react23.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
3434
|
+
return (0, import_react23.useMemo)(() => ({ ...snapshot, store }), [snapshot, store]);
|
|
3435
|
+
}
|
|
3436
|
+
function useTrackChanges(editor) {
|
|
3437
|
+
const store = (0, import_editor13.getTrackChangesStore)(editor ?? null);
|
|
3438
|
+
const subscribe = (0, import_react23.useCallback)(
|
|
3439
|
+
(onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
|
|
3440
|
+
[store]
|
|
3441
|
+
);
|
|
3442
|
+
const getSnapshot = () => store?.getSnapshot() ?? EMPTY_TRACK_CHANGES;
|
|
3443
|
+
const snapshot = (0, import_react23.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
3444
|
+
return (0, import_react23.useMemo)(() => {
|
|
3445
|
+
const run = (fn) => () => {
|
|
3446
|
+
if (editor && !editor.isDestroyed) fn(editor);
|
|
3447
|
+
};
|
|
3448
|
+
return {
|
|
3449
|
+
...snapshot,
|
|
3450
|
+
currentChange: snapshot.changes.find((c) => c.id === snapshot.currentChangeId) ?? null,
|
|
3451
|
+
setEnabled: (enabled) => run((e) => e.commands.setTrackChanges(enabled))(),
|
|
3452
|
+
toggle: run((e) => e.commands.toggleTrackChanges()),
|
|
3453
|
+
accept: (id) => run((e) => e.commands.acceptChange(id))(),
|
|
3454
|
+
reject: (id) => run((e) => e.commands.rejectChange(id))(),
|
|
3455
|
+
acceptAll: run((e) => e.commands.acceptAllChanges()),
|
|
3456
|
+
rejectAll: run((e) => e.commands.rejectAllChanges()),
|
|
3457
|
+
next: run((e) => e.chain().focus().selectNextChange().run()),
|
|
3458
|
+
previous: run((e) => e.chain().focus().selectPreviousChange().run())
|
|
3459
|
+
};
|
|
3460
|
+
}, [snapshot, editor]);
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3463
|
+
// src/review/CommentsPanel.tsx
|
|
3464
|
+
var import_react24 = require("react");
|
|
3465
|
+
var import_editor14 = require("@pixerate/editor");
|
|
3466
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
3467
|
+
var buttonClass = "rounded px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50";
|
|
3468
|
+
var primaryButtonClass = "rounded px-2 py-1 text-xs bg-primary/10 text-primary hover:bg-primary/20 disabled:opacity-50";
|
|
3469
|
+
var textareaClass = "w-full resize-y rounded-md border border-input bg-background p-2 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-primary";
|
|
3470
|
+
var CommentsPanel = ({
|
|
3471
|
+
editor,
|
|
3472
|
+
store: storeProp,
|
|
3473
|
+
author: authorProp,
|
|
3474
|
+
showResolved: showResolvedInitial = false,
|
|
3475
|
+
className = "flex flex-col gap-2 text-sm text-foreground",
|
|
3476
|
+
formatTime = (t) => (0, import_editor14.formatReviewTime)(t),
|
|
3477
|
+
emptyMessage = "No comments yet. Select text and add a comment."
|
|
3478
|
+
}) => {
|
|
3479
|
+
const { threads, activeThreadId, store } = useComments(storeProp ?? editor);
|
|
3480
|
+
const [showResolved, setShowResolved] = (0, import_react24.useState)(showResolvedInitial);
|
|
3481
|
+
const author = authorProp ?? (0, import_editor14.getCommentAuthor)(editor) ?? { id: "anonymous", name: "Anonymous" };
|
|
3482
|
+
const visible = threads.filter((t) => showResolved || !t.resolved);
|
|
3483
|
+
const resolvedCount = threads.filter((t) => t.resolved).length;
|
|
3484
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("aside", { className, "aria-label": "Comments", children: [
|
|
3485
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
|
|
3486
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "text-xs font-medium text-muted-foreground", children: [
|
|
3487
|
+
threads.length - resolvedCount,
|
|
3488
|
+
" open",
|
|
3489
|
+
resolvedCount > 0 ? ` \xB7 ${resolvedCount} resolved` : ""
|
|
3490
|
+
] }),
|
|
3491
|
+
resolvedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3492
|
+
"button",
|
|
3493
|
+
{
|
|
3494
|
+
type: "button",
|
|
3495
|
+
className: buttonClass,
|
|
3496
|
+
"aria-pressed": showResolved,
|
|
3497
|
+
onClick: () => setShowResolved((v) => !v),
|
|
3498
|
+
children: showResolved ? "Hide resolved" : "Show resolved"
|
|
3499
|
+
}
|
|
3500
|
+
)
|
|
3501
|
+
] }),
|
|
3502
|
+
visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("ul", { className: "flex flex-col gap-2", role: "list", children: visible.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3503
|
+
CommentThreadCard,
|
|
3504
|
+
{
|
|
3505
|
+
thread,
|
|
3506
|
+
active: thread.id === activeThreadId,
|
|
3507
|
+
editor,
|
|
3508
|
+
store,
|
|
3509
|
+
author,
|
|
3510
|
+
formatTime
|
|
3511
|
+
},
|
|
3512
|
+
thread.id
|
|
3513
|
+
)) })
|
|
3514
|
+
] });
|
|
3515
|
+
};
|
|
3516
|
+
var CommentThreadCard = ({
|
|
3517
|
+
thread,
|
|
3518
|
+
active,
|
|
3519
|
+
editor,
|
|
3520
|
+
store,
|
|
3521
|
+
author,
|
|
3522
|
+
formatTime
|
|
3523
|
+
}) => {
|
|
3524
|
+
const [draft, setDraft] = (0, import_react24.useState)("");
|
|
3525
|
+
const isDraft = thread.body === "";
|
|
3526
|
+
const quote = thread.anchor?.quote ?? thread.lastQuote ?? "";
|
|
3527
|
+
const live = editor && !editor.isDestroyed ? editor : null;
|
|
3528
|
+
const focus = () => {
|
|
3529
|
+
if (!active) {
|
|
3530
|
+
if (live && !thread.orphaned) live.commands.focusComment(thread.id);
|
|
3531
|
+
else store?.setActiveThread(thread.id);
|
|
3532
|
+
}
|
|
3533
|
+
};
|
|
3534
|
+
const remove = () => {
|
|
3535
|
+
if (live) live.commands.deleteComment(thread.id);
|
|
3536
|
+
else store?.deleteThread(thread.id);
|
|
3537
|
+
};
|
|
3538
|
+
const setResolved = (resolved) => {
|
|
3539
|
+
if (live) live.commands.resolveComment(thread.id, resolved);
|
|
3540
|
+
else store?.resolveThread(thread.id, resolved, author);
|
|
3541
|
+
};
|
|
3542
|
+
const submit = () => {
|
|
3543
|
+
const body = draft.trim();
|
|
3544
|
+
if (!body || !store) return;
|
|
3545
|
+
if (isDraft) store.editComment(thread.id, body);
|
|
3546
|
+
else store.addReply(thread.id, { body, author });
|
|
3547
|
+
setDraft("");
|
|
3548
|
+
};
|
|
3549
|
+
const stop = (e) => e.stopPropagation();
|
|
3550
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
3551
|
+
"li",
|
|
3552
|
+
{
|
|
3553
|
+
className: `flex flex-col gap-2 rounded-md border bg-background p-3 cursor-pointer ${active ? "border-primary ring-1 ring-primary" : "border-border"} ${thread.resolved ? "opacity-70" : ""}`,
|
|
3554
|
+
"data-thread-id": thread.id,
|
|
3555
|
+
"data-active": active || void 0,
|
|
3556
|
+
"aria-current": active || void 0,
|
|
3557
|
+
tabIndex: 0,
|
|
3558
|
+
onClick: focus,
|
|
3559
|
+
onKeyDown: (e) => {
|
|
3560
|
+
if (e.target === e.currentTarget && (e.key === "Enter" || e.key === " ")) {
|
|
3561
|
+
e.preventDefault();
|
|
3562
|
+
focus();
|
|
3563
|
+
}
|
|
3564
|
+
},
|
|
3565
|
+
children: [
|
|
3566
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-baseline justify-between gap-2", children: [
|
|
3567
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-medium", children: thread.author.name }),
|
|
3568
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-xs text-muted-foreground", children: formatTime(thread.createdAt) })
|
|
3569
|
+
] }),
|
|
3570
|
+
quote && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("blockquote", { className: "border-l-2 border-border pl-2 text-xs text-muted-foreground line-clamp-2", children: quote }),
|
|
3571
|
+
thread.orphaned && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-xs text-destructive", children: "The commented text was deleted." }),
|
|
3572
|
+
thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-xs text-muted-foreground", children: "Resolved" }),
|
|
3573
|
+
!isDraft && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "whitespace-pre-wrap break-words", children: thread.body }),
|
|
3574
|
+
thread.replies.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("ul", { className: "flex flex-col gap-2 border-l border-border pl-3", role: "list", children: thread.replies.map((reply) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("li", { className: "flex flex-col gap-0.5", "data-reply-id": reply.id, children: [
|
|
3575
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: "text-xs", children: [
|
|
3576
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-medium", children: reply.author.name }),
|
|
3577
|
+
" ",
|
|
3578
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-muted-foreground", children: formatTime(reply.createdAt) })
|
|
3579
|
+
] }),
|
|
3580
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "whitespace-pre-wrap break-words", children: reply.body })
|
|
3581
|
+
] }, reply.id)) }),
|
|
3582
|
+
(active || isDraft) && !thread.resolved && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-1", onClick: stop, children: [
|
|
3583
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3584
|
+
"textarea",
|
|
3585
|
+
{
|
|
3586
|
+
className: textareaClass,
|
|
3587
|
+
rows: 2,
|
|
3588
|
+
value: draft,
|
|
3589
|
+
"aria-label": isDraft ? "Comment" : "Reply",
|
|
3590
|
+
placeholder: isDraft ? "Add a comment\u2026" : "Reply\u2026",
|
|
3591
|
+
autoFocus: isDraft,
|
|
3592
|
+
onChange: (e) => setDraft(e.target.value),
|
|
3593
|
+
onKeyDown: (e) => {
|
|
3594
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
3595
|
+
e.preventDefault();
|
|
3596
|
+
submit();
|
|
3597
|
+
}
|
|
3598
|
+
}
|
|
3599
|
+
}
|
|
3600
|
+
),
|
|
3601
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex justify-end gap-1", children: [
|
|
3602
|
+
isDraft && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: buttonClass, onClick: remove, children: "Cancel" }),
|
|
3603
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3604
|
+
"button",
|
|
3605
|
+
{
|
|
3606
|
+
type: "button",
|
|
3607
|
+
className: primaryButtonClass,
|
|
3608
|
+
disabled: !draft.trim(),
|
|
3609
|
+
onClick: submit,
|
|
3610
|
+
children: isDraft ? "Comment" : "Reply"
|
|
3611
|
+
}
|
|
3612
|
+
)
|
|
3613
|
+
] })
|
|
3614
|
+
] }),
|
|
3615
|
+
!isDraft && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex justify-end gap-1", onClick: stop, children: [
|
|
3616
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", className: buttonClass, onClick: () => setResolved(!thread.resolved), children: thread.resolved ? "Reopen" : "Resolve" }),
|
|
3617
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3618
|
+
"button",
|
|
3619
|
+
{
|
|
3620
|
+
type: "button",
|
|
3621
|
+
className: `${buttonClass} hover:text-destructive`,
|
|
3622
|
+
onClick: remove,
|
|
3623
|
+
children: "Delete"
|
|
3624
|
+
}
|
|
3625
|
+
)
|
|
3626
|
+
] })
|
|
3627
|
+
]
|
|
3628
|
+
}
|
|
3629
|
+
);
|
|
3630
|
+
};
|
|
3631
|
+
|
|
3632
|
+
// src/review/ReviewToolbar.tsx
|
|
3633
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
3634
|
+
var buttonClass2 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
|
|
3635
|
+
var ReviewToolbar = ({
|
|
3636
|
+
editor,
|
|
3637
|
+
className = "flex flex-wrap items-center gap-1 rounded-md border border-border bg-background p-1 text-sm"
|
|
3638
|
+
}) => {
|
|
3639
|
+
const review = useTrackChanges(editor);
|
|
3640
|
+
const count = review.changes.length;
|
|
3641
|
+
const current = review.currentChange;
|
|
3642
|
+
const index = current ? review.changes.findIndex((c) => c.id === current.id) + 1 : 0;
|
|
3643
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className, role: "toolbar", "aria-label": "Review", children: [
|
|
3644
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3645
|
+
"button",
|
|
3646
|
+
{
|
|
3647
|
+
type: "button",
|
|
3648
|
+
className: `${buttonClass2} ${review.enabled ? "bg-primary/10 text-primary" : ""}`,
|
|
3649
|
+
"aria-pressed": review.enabled,
|
|
3650
|
+
disabled: !editor,
|
|
3651
|
+
onClick: review.toggle,
|
|
3652
|
+
children: review.enabled ? "Tracking on" : "Track changes"
|
|
3653
|
+
}
|
|
3654
|
+
),
|
|
3655
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
|
|
3656
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3657
|
+
"button",
|
|
3658
|
+
{
|
|
3659
|
+
type: "button",
|
|
3660
|
+
className: buttonClass2,
|
|
3661
|
+
"aria-label": "Previous change",
|
|
3662
|
+
disabled: count === 0,
|
|
3663
|
+
onClick: review.previous,
|
|
3664
|
+
children: "\u2039"
|
|
3665
|
+
}
|
|
3666
|
+
),
|
|
3667
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "min-w-[4rem] text-center text-xs text-muted-foreground", "aria-live": "polite", children: count === 0 ? "No changes" : current ? `${index} of ${count}` : `${count} changes` }),
|
|
3668
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3669
|
+
"button",
|
|
3670
|
+
{
|
|
3671
|
+
type: "button",
|
|
3672
|
+
className: buttonClass2,
|
|
3673
|
+
"aria-label": "Next change",
|
|
3674
|
+
disabled: count === 0,
|
|
3675
|
+
onClick: review.next,
|
|
3676
|
+
children: "\u203A"
|
|
3677
|
+
}
|
|
3678
|
+
),
|
|
3679
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
|
|
3680
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3681
|
+
"button",
|
|
3682
|
+
{
|
|
3683
|
+
type: "button",
|
|
3684
|
+
className: buttonClass2,
|
|
3685
|
+
disabled: !current,
|
|
3686
|
+
onClick: () => current && review.accept(current.id),
|
|
3687
|
+
children: "Accept"
|
|
3688
|
+
}
|
|
3689
|
+
),
|
|
3690
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3691
|
+
"button",
|
|
3692
|
+
{
|
|
3693
|
+
type: "button",
|
|
3694
|
+
className: buttonClass2,
|
|
3695
|
+
disabled: !current,
|
|
3696
|
+
onClick: () => current && review.reject(current.id),
|
|
3697
|
+
children: "Reject"
|
|
3698
|
+
}
|
|
3699
|
+
),
|
|
3700
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: buttonClass2, disabled: count === 0, onClick: review.acceptAll, children: "Accept all" }),
|
|
3701
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: buttonClass2, disabled: count === 0, onClick: review.rejectAll, children: "Reject all" })
|
|
3702
|
+
] });
|
|
3703
|
+
};
|
|
3704
|
+
|
|
3705
|
+
// src/review/CommentButton.tsx
|
|
3706
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
3707
|
+
var CommentButton = ({
|
|
3708
|
+
editor,
|
|
3709
|
+
className = "rounded px-2 py-1 text-xs text-popover-foreground hover:bg-muted",
|
|
3710
|
+
children = "Comment"
|
|
3711
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
3712
|
+
"button",
|
|
3713
|
+
{
|
|
3714
|
+
type: "button",
|
|
3715
|
+
className,
|
|
3716
|
+
disabled: !editor,
|
|
3717
|
+
onClick: () => editor?.chain().focus().addComment().run(),
|
|
3718
|
+
children
|
|
3719
|
+
}
|
|
3720
|
+
);
|
|
2695
3721
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2696
3722
|
0 && (module.exports = {
|
|
2697
3723
|
BubbleMenu,
|
|
3724
|
+
CommentButton,
|
|
3725
|
+
CommentsPanel,
|
|
2698
3726
|
DirtyTracker,
|
|
2699
3727
|
EditorContent,
|
|
2700
3728
|
EditorSlotsProvider,
|
|
3729
|
+
FormulaHints,
|
|
2701
3730
|
HistoryManager,
|
|
2702
3731
|
ImageEditor,
|
|
3732
|
+
OutlinePanel,
|
|
3733
|
+
ReviewToolbar,
|
|
3734
|
+
SpreadsheetContextMenu,
|
|
2703
3735
|
SpreadsheetEditor,
|
|
3736
|
+
SpreadsheetGroupRow,
|
|
2704
3737
|
TemplateRenderer,
|
|
3738
|
+
VariableForm,
|
|
2705
3739
|
createDirtyTracker,
|
|
2706
3740
|
createHistoryManager,
|
|
2707
3741
|
defaultIsEqual,
|
|
3742
|
+
useAgentToolProvider,
|
|
3743
|
+
useComments,
|
|
2708
3744
|
useDismissGuard,
|
|
2709
3745
|
useEditor,
|
|
2710
3746
|
useEditorSlots,
|
|
3747
|
+
useFileImport,
|
|
3748
|
+
useFillHandle,
|
|
2711
3749
|
useHistory,
|
|
2712
3750
|
useHistoryShortcuts,
|
|
2713
3751
|
useImageEditor,
|
|
2714
3752
|
useNavigationGuard,
|
|
3753
|
+
useOutline,
|
|
2715
3754
|
usePromptEditor,
|
|
2716
|
-
|
|
3755
|
+
useSpreadsheetClipboard,
|
|
3756
|
+
useSpreadsheetEditor,
|
|
3757
|
+
useTrackChanges
|
|
2717
3758
|
});
|
|
2718
3759
|
//# sourceMappingURL=index.cjs.map
|