@pixerate/editor-react 0.13.0 → 0.15.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 +5 -4
- package/dist/canvas/index.cjs +329 -84
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +82 -4
- package/dist/canvas/index.d.ts +82 -4
- package/dist/canvas/index.js +266 -18
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-4ZC2WCUO.js +196 -0
- package/dist/chunk-4ZC2WCUO.js.map +1 -0
- package/dist/{chunk-TL27COKM.js → chunk-LPFZMZ3L.js} +45 -2
- package/dist/chunk-LPFZMZ3L.js.map +1 -0
- package/dist/{chunk-MHTAR3RS.js → chunk-QVQYYHJ5.js} +87 -29
- package/dist/chunk-QVQYYHJ5.js.map +1 -0
- package/dist/commands/index.cjs +232 -0
- package/dist/commands/index.cjs.map +1 -0
- package/dist/commands/index.d.cts +69 -0
- package/dist/commands/index.d.ts +69 -0
- package/dist/commands/index.js +13 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/image-editor/index.cjs +41 -0
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +2 -0
- package/dist/image-editor/index.d.ts +2 -0
- package/dist/image-editor/index.js +1 -1
- package/dist/index.cjs +624 -268
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -9
- package/dist/index.d.ts +57 -9
- package/dist/index.js +147 -71
- package/dist/index.js.map +1 -1
- package/dist/spreadsheet/index.cjs +79 -22
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +2 -3
- package/dist/spreadsheet/index.d.ts +2 -3
- package/dist/spreadsheet/index.js +1 -1
- package/package.json +10 -2
- package/dist/chunk-MHTAR3RS.js.map +0 -1
- package/dist/chunk-TL27COKM.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -31,13 +31,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var src_exports = {};
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
BubbleMenu: () => BubbleMenu,
|
|
34
|
+
CommandPalette: () => CommandPalette,
|
|
34
35
|
CommentButton: () => CommentButton,
|
|
35
36
|
CommentsPanel: () => CommentsPanel,
|
|
36
|
-
DirtyTracker: () =>
|
|
37
|
+
DirtyTracker: () => import_editor12.DirtyTracker,
|
|
37
38
|
EditorContent: () => EditorContent,
|
|
38
39
|
EditorSlotsProvider: () => EditorSlotsProvider,
|
|
39
40
|
FormulaHints: () => FormulaHints,
|
|
40
|
-
HistoryManager: () =>
|
|
41
|
+
HistoryManager: () => import_editor12.HistoryManager,
|
|
41
42
|
ImageEditor: () => ImageEditor,
|
|
42
43
|
OutlinePanel: () => OutlinePanel,
|
|
43
44
|
ReviewToolbar: () => ReviewToolbar,
|
|
@@ -46,10 +47,13 @@ __export(src_exports, {
|
|
|
46
47
|
SpreadsheetGroupRow: () => SpreadsheetGroupRow,
|
|
47
48
|
TemplateRenderer: () => TemplateRenderer,
|
|
48
49
|
VariableForm: () => VariableForm,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
bindDirtyToHistory: () => import_editor12.bindDirtyToHistory,
|
|
51
|
+
createDirtyTracker: () => import_editor12.createDirtyTracker,
|
|
52
|
+
createHistoryManager: () => import_editor12.createHistoryManager,
|
|
53
|
+
defaultIsEqual: () => import_editor12.defaultIsEqual,
|
|
52
54
|
useAgentToolProvider: () => useAgentToolProvider,
|
|
55
|
+
useCommandPalette: () => useCommandPalette,
|
|
56
|
+
useCommandShortcuts: () => useCommandShortcuts,
|
|
53
57
|
useComments: () => useComments,
|
|
54
58
|
useDismissGuard: () => useDismissGuard,
|
|
55
59
|
useEditor: () => useEditor2,
|
|
@@ -57,14 +61,17 @@ __export(src_exports, {
|
|
|
57
61
|
useFileImport: () => useFileImport,
|
|
58
62
|
useFillHandle: () => useFillHandle,
|
|
59
63
|
useHistory: () => useHistory,
|
|
64
|
+
useHistoryDirty: () => useHistoryDirty,
|
|
60
65
|
useHistoryShortcuts: () => useHistoryShortcuts,
|
|
61
66
|
useImageEditor: () => useImageEditor,
|
|
62
67
|
useNavigationGuard: () => useNavigationGuard,
|
|
63
68
|
useOutline: () => useOutline,
|
|
64
69
|
usePromptEditor: () => usePromptEditor,
|
|
70
|
+
useRegisterCommands: () => useRegisterCommands,
|
|
65
71
|
useSpreadsheetClipboard: () => useSpreadsheetClipboard,
|
|
66
72
|
useSpreadsheetEditor: () => useSpreadsheetEditor,
|
|
67
|
-
useTrackChanges: () => useTrackChanges
|
|
73
|
+
useTrackChanges: () => useTrackChanges,
|
|
74
|
+
withoutDirty: () => import_editor12.withoutDirty
|
|
68
75
|
});
|
|
69
76
|
module.exports = __toCommonJS(src_exports);
|
|
70
77
|
|
|
@@ -470,6 +477,7 @@ function useHistory(managerOrOptions) {
|
|
|
470
477
|
() => manager.getState(),
|
|
471
478
|
() => manager.getState()
|
|
472
479
|
);
|
|
480
|
+
const entries = (0, import_react6.useMemo)(() => manager.getEntries(), [manager, state]);
|
|
473
481
|
const undo = (0, import_react6.useCallback)(() => manager.undo(), [manager]);
|
|
474
482
|
const redo = (0, import_react6.useCallback)(() => manager.redo(), [manager]);
|
|
475
483
|
const clear = (0, import_react6.useCallback)(() => manager.clear(), [manager]);
|
|
@@ -485,60 +493,102 @@ function useHistory(managerOrOptions) {
|
|
|
485
493
|
(name, fn) => manager.batch(name, fn),
|
|
486
494
|
[manager]
|
|
487
495
|
);
|
|
496
|
+
const goTo = (0, import_react6.useCallback)((index) => manager.goTo(index), [manager]);
|
|
497
|
+
const mark = (0, import_react6.useCallback)(() => manager.mark(), [manager]);
|
|
498
|
+
const revertTo = (0, import_react6.useCallback)(
|
|
499
|
+
(m) => manager.revertTo(m),
|
|
500
|
+
[manager]
|
|
501
|
+
);
|
|
502
|
+
const beginGesture = (0, import_react6.useCallback)(
|
|
503
|
+
(key) => manager.beginGesture(key),
|
|
504
|
+
[manager]
|
|
505
|
+
);
|
|
506
|
+
const endGesture = (0, import_react6.useCallback)(() => manager.endGesture(), [manager]);
|
|
488
507
|
return {
|
|
489
508
|
...state,
|
|
490
509
|
manager,
|
|
510
|
+
entries,
|
|
491
511
|
undo,
|
|
492
512
|
redo,
|
|
493
513
|
clear,
|
|
494
514
|
execute,
|
|
495
515
|
executeMerged,
|
|
496
|
-
batch
|
|
516
|
+
batch,
|
|
517
|
+
goTo,
|
|
518
|
+
mark,
|
|
519
|
+
revertTo,
|
|
520
|
+
beginGesture,
|
|
521
|
+
endGesture
|
|
497
522
|
};
|
|
498
523
|
}
|
|
499
524
|
|
|
500
|
-
// src/hooks/
|
|
525
|
+
// src/hooks/useHistoryDirty.ts
|
|
501
526
|
var import_react7 = require("react");
|
|
527
|
+
var import_editor4 = require("@pixerate/editor");
|
|
528
|
+
function useHistoryDirty(options) {
|
|
529
|
+
const getValueRef = (0, import_react7.useRef)(options.getValue);
|
|
530
|
+
getValueRef.current = options.getValue;
|
|
531
|
+
const [tracker] = (0, import_react7.useState)(
|
|
532
|
+
() => options.tracker ?? new import_editor4.DirtyTracker(options.getValue(), {
|
|
533
|
+
isEqual: options.isEqual,
|
|
534
|
+
normalize: options.normalize
|
|
535
|
+
})
|
|
536
|
+
);
|
|
537
|
+
const bindingRef = (0, import_react7.useRef)(null);
|
|
538
|
+
(0, import_react7.useEffect)(() => {
|
|
539
|
+
const binding = (0, import_editor4.bindDirtyToHistory)({
|
|
540
|
+
history: options.history,
|
|
541
|
+
getValue: () => getValueRef.current(),
|
|
542
|
+
tracker
|
|
543
|
+
});
|
|
544
|
+
bindingRef.current = binding;
|
|
545
|
+
return () => {
|
|
546
|
+
binding.destroy();
|
|
547
|
+
if (bindingRef.current === binding) bindingRef.current = null;
|
|
548
|
+
};
|
|
549
|
+
}, [options.history, tracker]);
|
|
550
|
+
const isDirty = (0, import_react7.useSyncExternalStore)(
|
|
551
|
+
(0, import_react7.useCallback)((onChange) => tracker.subscribe(onChange), [tracker]),
|
|
552
|
+
() => tracker.dirty,
|
|
553
|
+
() => tracker.dirty
|
|
554
|
+
);
|
|
555
|
+
const markClean = (0, import_react7.useCallback)(
|
|
556
|
+
() => tracker.markClean(getValueRef.current()),
|
|
557
|
+
[tracker]
|
|
558
|
+
);
|
|
559
|
+
const suppress = (0, import_react7.useCallback)(
|
|
560
|
+
(fn) => bindingRef.current ? bindingRef.current.suppress(fn) : tracker.suppress(fn),
|
|
561
|
+
[tracker]
|
|
562
|
+
);
|
|
563
|
+
const refresh = (0, import_react7.useCallback)(
|
|
564
|
+
() => tracker.update(getValueRef.current()),
|
|
565
|
+
[tracker]
|
|
566
|
+
);
|
|
567
|
+
return { isDirty, markClean, suppress, refresh, tracker };
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// src/hooks/useHistoryShortcuts.ts
|
|
571
|
+
var import_react8 = require("react");
|
|
572
|
+
var import_commands = require("@pixerate/editor/commands");
|
|
502
573
|
function useHistoryShortcuts(manager, options = {}) {
|
|
503
574
|
const {
|
|
504
575
|
enabled = true,
|
|
505
576
|
target,
|
|
506
577
|
ignoreEditableElements = true
|
|
507
578
|
} = options;
|
|
508
|
-
(0,
|
|
579
|
+
(0, import_react8.useEffect)(() => {
|
|
509
580
|
if (!enabled) return;
|
|
510
581
|
const eventTarget = target ?? (typeof window !== "undefined" ? window : null);
|
|
511
582
|
if (!eventTarget) return;
|
|
512
583
|
const handleKeyDown = (event) => {
|
|
513
584
|
const e = event;
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
const isInput = tagName === "input" || tagName === "textarea";
|
|
522
|
-
const isContentEditable = targetEl.isContentEditable || targetEl.getAttribute?.("contenteditable") === "true";
|
|
523
|
-
if (isInput || isContentEditable) {
|
|
524
|
-
return;
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
const key = e.key.toLowerCase();
|
|
529
|
-
if (key === "z" && !e.shiftKey) {
|
|
530
|
-
if (manager.getState().canUndo) {
|
|
531
|
-
e.preventDefault();
|
|
532
|
-
manager.undo();
|
|
533
|
-
}
|
|
534
|
-
return;
|
|
535
|
-
}
|
|
536
|
-
const isRedoKey = key === "z" && e.shiftKey || !isMac && key === "y" && !e.shiftKey;
|
|
537
|
-
if (isRedoKey) {
|
|
538
|
-
if (manager.getState().canRedo) {
|
|
539
|
-
e.preventDefault();
|
|
540
|
-
manager.redo();
|
|
541
|
-
}
|
|
585
|
+
const action = (0, import_commands.matchHistoryShortcut)(e, { allowInEditable: !ignoreEditableElements });
|
|
586
|
+
if (action === "undo" && manager.getState().canUndo) {
|
|
587
|
+
e.preventDefault();
|
|
588
|
+
manager.undo();
|
|
589
|
+
} else if (action === "redo" && manager.getState().canRedo) {
|
|
590
|
+
e.preventDefault();
|
|
591
|
+
manager.redo();
|
|
542
592
|
}
|
|
543
593
|
};
|
|
544
594
|
eventTarget.addEventListener("keydown", handleKeyDown);
|
|
@@ -549,22 +599,22 @@ function useHistoryShortcuts(manager, options = {}) {
|
|
|
549
599
|
}
|
|
550
600
|
|
|
551
601
|
// src/hooks/useFileImport.ts
|
|
552
|
-
var
|
|
553
|
-
var
|
|
602
|
+
var import_react9 = require("react");
|
|
603
|
+
var import_editor5 = require("@pixerate/editor");
|
|
554
604
|
function useFileImport(editor, options = {}) {
|
|
555
|
-
const editorRef = (0,
|
|
605
|
+
const editorRef = (0, import_react9.useRef)(editor);
|
|
556
606
|
editorRef.current = editor;
|
|
557
|
-
const controller = (0,
|
|
558
|
-
() => new
|
|
607
|
+
const controller = (0, import_react9.useMemo)(
|
|
608
|
+
() => new import_editor5.FileImportController(() => {
|
|
559
609
|
const current = editorRef.current;
|
|
560
610
|
return current && !current.isDestroyed ? current : null;
|
|
561
611
|
}, options),
|
|
562
612
|
[]
|
|
563
613
|
);
|
|
564
|
-
(0,
|
|
614
|
+
(0, import_react9.useEffect)(() => {
|
|
565
615
|
controller.setOptions(options);
|
|
566
616
|
});
|
|
567
|
-
const state = (0,
|
|
617
|
+
const state = (0, import_react9.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
|
|
568
618
|
return {
|
|
569
619
|
...state,
|
|
570
620
|
accept: controller.accept,
|
|
@@ -574,27 +624,27 @@ function useFileImport(editor, options = {}) {
|
|
|
574
624
|
}
|
|
575
625
|
|
|
576
626
|
// src/hooks/useAgentToolProvider.ts
|
|
577
|
-
var
|
|
627
|
+
var import_react10 = require("react");
|
|
578
628
|
function useAgentToolProvider(registry, provider) {
|
|
579
|
-
(0,
|
|
629
|
+
(0, import_react10.useEffect)(() => {
|
|
580
630
|
if (!registry || !provider) return;
|
|
581
631
|
return registry.register(provider);
|
|
582
632
|
}, [registry, provider]);
|
|
583
633
|
}
|
|
584
634
|
|
|
585
635
|
// src/components/EditorContent.tsx
|
|
586
|
-
var
|
|
636
|
+
var import_react11 = require("@tiptap/react");
|
|
587
637
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
588
638
|
var EditorContent = ({
|
|
589
639
|
className,
|
|
590
640
|
editor,
|
|
591
641
|
...props
|
|
592
642
|
}) => {
|
|
593
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
643
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react11.EditorContent, { editor, ...props }) });
|
|
594
644
|
};
|
|
595
645
|
|
|
596
646
|
// src/components/BubbleMenu.tsx
|
|
597
|
-
var
|
|
647
|
+
var import_react12 = require("react");
|
|
598
648
|
var import_react_dom = require("react-dom");
|
|
599
649
|
var import_extension_bubble_menu = require("@tiptap/extension-bubble-menu");
|
|
600
650
|
var BubbleMenu = ({
|
|
@@ -606,12 +656,12 @@ var BubbleMenu = ({
|
|
|
606
656
|
pluginKey = "bubbleMenu",
|
|
607
657
|
updateDelay
|
|
608
658
|
}) => {
|
|
609
|
-
const menuEl = (0,
|
|
610
|
-
const [mounted, setMounted] = (0,
|
|
659
|
+
const menuEl = (0, import_react12.useRef)(null);
|
|
660
|
+
const [mounted, setMounted] = (0, import_react12.useState)(false);
|
|
611
661
|
if (!menuEl.current && typeof document !== "undefined") {
|
|
612
662
|
menuEl.current = document.createElement("div");
|
|
613
663
|
}
|
|
614
|
-
(0,
|
|
664
|
+
(0, import_react12.useEffect)(() => {
|
|
615
665
|
if (!editor || !menuEl.current || editor.isDestroyed) {
|
|
616
666
|
return;
|
|
617
667
|
}
|
|
@@ -642,8 +692,8 @@ var BubbleMenu = ({
|
|
|
642
692
|
};
|
|
643
693
|
|
|
644
694
|
// src/components/TemplateRenderer.tsx
|
|
645
|
-
var
|
|
646
|
-
var
|
|
695
|
+
var import_react13 = require("react");
|
|
696
|
+
var import_editor6 = require("@pixerate/editor");
|
|
647
697
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
648
698
|
var CONDITIONAL_PREFIX = { if: "?", unless: "!", end: "/" };
|
|
649
699
|
var TemplateRenderer = ({
|
|
@@ -657,12 +707,12 @@ var TemplateRenderer = ({
|
|
|
657
707
|
onTemplateClick,
|
|
658
708
|
onVariableClick
|
|
659
709
|
}) => {
|
|
660
|
-
const displayText = (0,
|
|
710
|
+
const displayText = (0, import_react13.useMemo)(() => {
|
|
661
711
|
if (!resolve || templates.length === 0) return content;
|
|
662
|
-
return (0,
|
|
712
|
+
return (0, import_editor6.resolveTemplates)(content, templates, { bindings });
|
|
663
713
|
}, [content, templates, resolve, bindings]);
|
|
664
|
-
const tokens = (0,
|
|
665
|
-
return (0,
|
|
714
|
+
const tokens = (0, import_react13.useMemo)(() => {
|
|
715
|
+
return (0, import_editor6.evaluatePromptTokens)(displayText, values);
|
|
666
716
|
}, [displayText, values]);
|
|
667
717
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className, children: tokens.map((token, index) => {
|
|
668
718
|
if (token.type === "template") {
|
|
@@ -750,8 +800,8 @@ var TemplateRenderer = ({
|
|
|
750
800
|
};
|
|
751
801
|
|
|
752
802
|
// src/components/VariableForm.tsx
|
|
753
|
-
var
|
|
754
|
-
var
|
|
803
|
+
var import_react14 = require("react");
|
|
804
|
+
var import_editor7 = require("@pixerate/editor");
|
|
755
805
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
756
806
|
var VariableForm = ({
|
|
757
807
|
content,
|
|
@@ -762,19 +812,19 @@ var VariableForm = ({
|
|
|
762
812
|
onChange,
|
|
763
813
|
className = "flex flex-col gap-3 text-sm"
|
|
764
814
|
}) => {
|
|
765
|
-
const idPrefix = (0,
|
|
766
|
-
const [internal, setInternal] = (0,
|
|
815
|
+
const idPrefix = (0, import_react14.useId)();
|
|
816
|
+
const [internal, setInternal] = (0, import_react14.useState)(
|
|
767
817
|
() => defaultValues ?? {}
|
|
768
818
|
);
|
|
769
819
|
const entered = values ?? internal;
|
|
770
|
-
const fields = (0,
|
|
771
|
-
() => (0,
|
|
820
|
+
const fields = (0, import_react14.useMemo)(
|
|
821
|
+
() => (0, import_editor7.getVariableFormFields)(content, { templates, bindings }),
|
|
772
822
|
[content, templates, bindings]
|
|
773
823
|
);
|
|
774
824
|
const update = (name, value) => {
|
|
775
825
|
const next = { ...entered, [name]: value };
|
|
776
826
|
if (values === void 0) setInternal(next);
|
|
777
|
-
onChange?.((0,
|
|
827
|
+
onChange?.((0, import_editor7.compactVariableValues)(next), next);
|
|
778
828
|
};
|
|
779
829
|
if (fields.length === 0) return null;
|
|
780
830
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("form", { className, onSubmit: (event) => event.preventDefault(), children: fields.map((field) => {
|
|
@@ -835,15 +885,15 @@ var VariableForm = ({
|
|
|
835
885
|
};
|
|
836
886
|
|
|
837
887
|
// src/hooks/useOutline.ts
|
|
838
|
-
var
|
|
839
|
-
var
|
|
888
|
+
var import_react15 = require("react");
|
|
889
|
+
var import_editor8 = require("@pixerate/editor");
|
|
840
890
|
function useOutline(editor) {
|
|
841
|
-
const store = (0,
|
|
842
|
-
return (0,
|
|
891
|
+
const store = (0, import_react15.useMemo)(() => (0, import_editor8.createOutlineStore)(editor), [editor]);
|
|
892
|
+
return (0, import_react15.useSyncExternalStore)(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
843
893
|
}
|
|
844
894
|
|
|
845
895
|
// src/components/OutlinePanel.tsx
|
|
846
|
-
var
|
|
896
|
+
var import_editor9 = require("@pixerate/editor");
|
|
847
897
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
848
898
|
var OutlinePanel = ({
|
|
849
899
|
editor,
|
|
@@ -872,7 +922,7 @@ var OutlinePanel = ({
|
|
|
872
922
|
"data-heading-id": heading.id,
|
|
873
923
|
onClick: () => {
|
|
874
924
|
if (!editor) return;
|
|
875
|
-
if ((0,
|
|
925
|
+
if ((0, import_editor9.navigateToHeading)(editor, heading, { focus: focusOnNavigate })) {
|
|
876
926
|
onNavigate?.(heading);
|
|
877
927
|
}
|
|
878
928
|
},
|
|
@@ -884,16 +934,16 @@ var OutlinePanel = ({
|
|
|
884
934
|
};
|
|
885
935
|
|
|
886
936
|
// src/index.ts
|
|
887
|
-
var
|
|
937
|
+
var import_editor12 = require("@pixerate/editor");
|
|
888
938
|
|
|
889
939
|
// src/spreadsheet/useSpreadsheetEditor.ts
|
|
890
|
-
var
|
|
940
|
+
var import_react16 = require("react");
|
|
891
941
|
var import_spreadsheet = require("@pixerate/editor/spreadsheet");
|
|
892
942
|
function useSpreadsheetEditor(options = {}) {
|
|
893
|
-
const optionsRef = (0,
|
|
943
|
+
const optionsRef = (0, import_react16.useRef)(options);
|
|
894
944
|
optionsRef.current = options;
|
|
895
|
-
const settersRef = (0,
|
|
896
|
-
const [controller] = (0,
|
|
945
|
+
const settersRef = (0, import_react16.useRef)({});
|
|
946
|
+
const [controller] = (0, import_react16.useState)(
|
|
897
947
|
() => new import_spreadsheet.SpreadsheetController({
|
|
898
948
|
...options,
|
|
899
949
|
onDocumentChange: (updated) => {
|
|
@@ -910,93 +960,97 @@ function useSpreadsheetEditor(options = {}) {
|
|
|
910
960
|
}
|
|
911
961
|
})
|
|
912
962
|
);
|
|
913
|
-
const [doc, setDoc] = (0,
|
|
914
|
-
const [activeCell, setActiveCell] = (0,
|
|
915
|
-
const [selectedRange, setSelectedRange] = (0,
|
|
916
|
-
const [editingCell, setEditingCell] = (0,
|
|
917
|
-
const [draftValue,
|
|
963
|
+
const [doc, setDoc] = (0, import_react16.useState)(() => ({ ...controller.document }));
|
|
964
|
+
const [activeCell, setActiveCell] = (0, import_react16.useState)(controller.activeCell);
|
|
965
|
+
const [selectedRange, setSelectedRange] = (0, import_react16.useState)(controller.selectedRange);
|
|
966
|
+
const [editingCell, setEditingCell] = (0, import_react16.useState)(null);
|
|
967
|
+
const [draftValue, setDraftState] = (0, import_react16.useState)("");
|
|
918
968
|
settersRef.current = { setDoc, setActiveCell, setSelectedRange };
|
|
919
|
-
const
|
|
969
|
+
const setDraftValue = (0, import_react16.useCallback)((value) => {
|
|
970
|
+
controller.draftValue = value;
|
|
971
|
+
setDraftState(value);
|
|
972
|
+
}, [controller]);
|
|
973
|
+
const setCellValue = (0, import_react16.useCallback)((rowId, colId, raw) => {
|
|
920
974
|
controller.setCellValue(rowId, colId, raw);
|
|
921
975
|
setDoc({ ...controller.document });
|
|
922
976
|
}, [controller]);
|
|
923
|
-
const selectCell = (0,
|
|
977
|
+
const selectCell = (0, import_react16.useCallback)((row, col, extendSelection = false) => {
|
|
924
978
|
controller.selectCell(row, col, extendSelection);
|
|
925
979
|
setActiveCell(controller.activeCell);
|
|
926
980
|
setSelectedRange(controller.selectedRange);
|
|
927
981
|
}, [controller]);
|
|
928
|
-
const selectRange = (0,
|
|
982
|
+
const selectRange = (0, import_react16.useCallback)((range) => {
|
|
929
983
|
controller.selectRange(range);
|
|
930
984
|
setSelectedRange(controller.selectedRange);
|
|
931
985
|
}, [controller]);
|
|
932
|
-
const startEditing = (0,
|
|
986
|
+
const startEditing = (0, import_react16.useCallback)((row, col, initialVal) => {
|
|
933
987
|
controller.startEditing(row, col, initialVal);
|
|
934
988
|
setActiveCell(controller.activeCell);
|
|
935
989
|
setEditingCell(controller.editingCell);
|
|
936
990
|
setDraftValue(controller.draftValue);
|
|
937
991
|
}, [controller]);
|
|
938
|
-
const commitEditing = (0,
|
|
992
|
+
const commitEditing = (0, import_react16.useCallback)((val) => {
|
|
939
993
|
controller.commitEditing(val);
|
|
940
994
|
setEditingCell(null);
|
|
941
995
|
setDraftValue("");
|
|
942
996
|
setDoc({ ...controller.document });
|
|
943
997
|
}, [controller]);
|
|
944
|
-
const cancelEditing = (0,
|
|
998
|
+
const cancelEditing = (0, import_react16.useCallback)(() => {
|
|
945
999
|
controller.cancelEditing();
|
|
946
1000
|
setEditingCell(null);
|
|
947
1001
|
setDraftValue("");
|
|
948
1002
|
}, [controller]);
|
|
949
|
-
const moveCursor = (0,
|
|
1003
|
+
const moveCursor = (0, import_react16.useCallback)((dir, extend = false) => {
|
|
950
1004
|
controller.moveCursor(dir, extend);
|
|
951
1005
|
setActiveCell(controller.activeCell);
|
|
952
1006
|
setSelectedRange(controller.selectedRange);
|
|
953
1007
|
}, [controller]);
|
|
954
|
-
const insertColumn = (0,
|
|
1008
|
+
const insertColumn = (0, import_react16.useCallback)((index, config) => {
|
|
955
1009
|
controller.insertColumn(index, config);
|
|
956
1010
|
setDoc({ ...controller.document });
|
|
957
1011
|
}, [controller]);
|
|
958
|
-
const deleteColumn = (0,
|
|
1012
|
+
const deleteColumn = (0, import_react16.useCallback)((colId) => {
|
|
959
1013
|
controller.deleteColumn(colId);
|
|
960
1014
|
setDoc({ ...controller.document });
|
|
961
1015
|
}, [controller]);
|
|
962
|
-
const insertRow = (0,
|
|
1016
|
+
const insertRow = (0, import_react16.useCallback)((index, config) => {
|
|
963
1017
|
controller.insertRow(index, config);
|
|
964
1018
|
setDoc({ ...controller.document });
|
|
965
1019
|
}, [controller]);
|
|
966
|
-
const deleteRow = (0,
|
|
1020
|
+
const deleteRow = (0, import_react16.useCallback)((rowId) => {
|
|
967
1021
|
controller.deleteRow(rowId);
|
|
968
1022
|
setDoc({ ...controller.document });
|
|
969
1023
|
}, [controller]);
|
|
970
|
-
const setColumnWidth = (0,
|
|
1024
|
+
const setColumnWidth = (0, import_react16.useCallback)((colId, width) => {
|
|
971
1025
|
controller.setColumnWidth(colId, width);
|
|
972
1026
|
setDoc({ ...controller.document });
|
|
973
1027
|
}, [controller]);
|
|
974
|
-
const autoFitColumnWidth = (0,
|
|
1028
|
+
const autoFitColumnWidth = (0, import_react16.useCallback)((colId, customWidth) => {
|
|
975
1029
|
controller.autoFitColumnWidth(colId, customWidth);
|
|
976
1030
|
setDoc({ ...controller.document });
|
|
977
1031
|
}, [controller]);
|
|
978
|
-
const registerDataSource = (0,
|
|
1032
|
+
const registerDataSource = (0, import_react16.useCallback)((ds) => {
|
|
979
1033
|
controller.registerDataSource(ds);
|
|
980
1034
|
setDoc({ ...controller.document });
|
|
981
1035
|
}, [controller]);
|
|
982
|
-
const setPrimaryDataSource = (0,
|
|
1036
|
+
const setPrimaryDataSource = (0, import_react16.useCallback)((id) => {
|
|
983
1037
|
controller.setPrimaryDataSource(id);
|
|
984
1038
|
setDoc({ ...controller.document });
|
|
985
1039
|
}, [controller]);
|
|
986
|
-
const recalculateAll = (0,
|
|
1040
|
+
const recalculateAll = (0, import_react16.useCallback)(() => {
|
|
987
1041
|
controller.recalculateAll();
|
|
988
1042
|
setDoc({ ...controller.document });
|
|
989
1043
|
}, [controller]);
|
|
990
|
-
const undo = (0,
|
|
1044
|
+
const undo = (0, import_react16.useCallback)(() => {
|
|
991
1045
|
controller.undo();
|
|
992
1046
|
setDoc({ ...controller.document });
|
|
993
1047
|
}, [controller]);
|
|
994
|
-
const redo = (0,
|
|
1048
|
+
const redo = (0, import_react16.useCallback)(() => {
|
|
995
1049
|
controller.redo();
|
|
996
1050
|
setDoc({ ...controller.document });
|
|
997
1051
|
}, [controller]);
|
|
998
|
-
const tableActions = (0,
|
|
999
|
-
const viewModel = (0,
|
|
1052
|
+
const tableActions = (0, import_react16.useMemo)(() => (0, import_spreadsheet.bindSpreadsheetTableActions)(controller), [controller]);
|
|
1053
|
+
const viewModel = (0, import_react16.useMemo)(() => controller.getViewModel(), [controller, doc]);
|
|
1000
1054
|
return {
|
|
1001
1055
|
document: doc,
|
|
1002
1056
|
activeCell,
|
|
@@ -1048,17 +1102,32 @@ function useSpreadsheetEditor(options = {}) {
|
|
|
1048
1102
|
}
|
|
1049
1103
|
|
|
1050
1104
|
// src/spreadsheet/SpreadsheetEditor.tsx
|
|
1051
|
-
var
|
|
1052
|
-
var
|
|
1105
|
+
var import_react20 = require("react");
|
|
1106
|
+
var import_spreadsheet5 = require("@pixerate/editor/spreadsheet");
|
|
1053
1107
|
|
|
1054
1108
|
// src/spreadsheet/SpreadsheetContextMenu.tsx
|
|
1055
|
-
var
|
|
1109
|
+
var import_react17 = __toESM(require("react"), 1);
|
|
1110
|
+
var import_spreadsheet2 = require("@pixerate/editor/spreadsheet");
|
|
1056
1111
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1112
|
+
var VIEWPORT_MARGIN = 4;
|
|
1057
1113
|
var SpreadsheetContextMenu = ({ items, x, y, onClose }) => {
|
|
1058
|
-
const menuRef = (0,
|
|
1059
|
-
const onCloseRef = (0,
|
|
1114
|
+
const menuRef = (0, import_react17.useRef)(null);
|
|
1115
|
+
const onCloseRef = (0, import_react17.useRef)(onClose);
|
|
1060
1116
|
onCloseRef.current = onClose;
|
|
1061
|
-
(0,
|
|
1117
|
+
const [position, setPosition] = (0, import_react17.useState)({ x, y });
|
|
1118
|
+
(0, import_react17.useLayoutEffect)(() => {
|
|
1119
|
+
const menu = menuRef.current;
|
|
1120
|
+
if (!menu || typeof window === "undefined") return;
|
|
1121
|
+
const { width, height } = menu.getBoundingClientRect();
|
|
1122
|
+
const next = (0, import_spreadsheet2.clampMenuPosition)(
|
|
1123
|
+
{ x, y },
|
|
1124
|
+
{ width, height },
|
|
1125
|
+
{ width: window.innerWidth, height: window.innerHeight },
|
|
1126
|
+
VIEWPORT_MARGIN
|
|
1127
|
+
);
|
|
1128
|
+
setPosition((prev) => prev.x === next.x && prev.y === next.y ? prev : next);
|
|
1129
|
+
}, [x, y, items]);
|
|
1130
|
+
(0, import_react17.useEffect)(() => {
|
|
1062
1131
|
const handlePointer = (e) => {
|
|
1063
1132
|
if (!menuRef.current?.contains(e.target)) onCloseRef.current();
|
|
1064
1133
|
};
|
|
@@ -1079,10 +1148,16 @@ var SpreadsheetContextMenu = ({ items, x, y, onClose }) => {
|
|
|
1079
1148
|
role: "menu",
|
|
1080
1149
|
"aria-label": "Table actions",
|
|
1081
1150
|
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: {
|
|
1151
|
+
style: {
|
|
1152
|
+
left: position.x,
|
|
1153
|
+
top: position.y,
|
|
1154
|
+
maxHeight: `calc(100vh - ${VIEWPORT_MARGIN * 2}px)`,
|
|
1155
|
+
overflowY: "auto",
|
|
1156
|
+
background: "var(--popover, var(--background, #fff))"
|
|
1157
|
+
},
|
|
1083
1158
|
onContextMenu: (e) => e.preventDefault(),
|
|
1084
1159
|
onKeyDown: (e) => e.stopPropagation(),
|
|
1085
|
-
children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1160
|
+
children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react17.default.Fragment, { children: [
|
|
1086
1161
|
item.separatorBefore && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { role: "separator", className: "my-1 h-px bg-border" }),
|
|
1087
1162
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1088
1163
|
"button",
|
|
@@ -1116,7 +1191,7 @@ var SpreadsheetGroupRow = ({
|
|
|
1116
1191
|
}) => {
|
|
1117
1192
|
const labelColId = columns.some((c) => c.column.id === groupColId) ? groupColId : columns[0]?.column.id;
|
|
1118
1193
|
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
|
|
1194
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted border-r border-border text-center", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1120
1195
|
"button",
|
|
1121
1196
|
{
|
|
1122
1197
|
type: "button",
|
|
@@ -1147,8 +1222,8 @@ var SpreadsheetGroupRow = ({
|
|
|
1147
1222
|
};
|
|
1148
1223
|
|
|
1149
1224
|
// src/spreadsheet/useSpreadsheetTableInteractions.ts
|
|
1150
|
-
var
|
|
1151
|
-
var
|
|
1225
|
+
var import_react18 = require("react");
|
|
1226
|
+
var import_spreadsheet3 = require("@pixerate/editor/spreadsheet");
|
|
1152
1227
|
function gridHasFocus(grid) {
|
|
1153
1228
|
if (!grid || typeof document === "undefined") return false;
|
|
1154
1229
|
const active = document.activeElement;
|
|
@@ -1156,12 +1231,12 @@ function gridHasFocus(grid) {
|
|
|
1156
1231
|
return !(active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement);
|
|
1157
1232
|
}
|
|
1158
1233
|
function useSpreadsheetClipboard(gridRef, state, readOnly) {
|
|
1159
|
-
const stateRef = (0,
|
|
1234
|
+
const stateRef = (0, import_react18.useRef)(state);
|
|
1160
1235
|
stateRef.current = state;
|
|
1161
|
-
const readOnlyRef = (0,
|
|
1236
|
+
const readOnlyRef = (0, import_react18.useRef)(readOnly);
|
|
1162
1237
|
readOnlyRef.current = readOnly;
|
|
1163
|
-
const copiedRef = (0,
|
|
1164
|
-
(0,
|
|
1238
|
+
const copiedRef = (0, import_react18.useRef)(false);
|
|
1239
|
+
(0, import_react18.useEffect)(() => {
|
|
1165
1240
|
if (typeof document === "undefined") return;
|
|
1166
1241
|
const handleCopy = (e) => {
|
|
1167
1242
|
const s = stateRef.current;
|
|
@@ -1184,24 +1259,25 @@ function useSpreadsheetClipboard(gridRef, state, readOnly) {
|
|
|
1184
1259
|
document.removeEventListener("paste", handlePaste);
|
|
1185
1260
|
};
|
|
1186
1261
|
}, [gridRef]);
|
|
1187
|
-
const copyShortcutFallback = (0,
|
|
1262
|
+
const copyShortcutFallback = (0, import_react18.useCallback)(() => {
|
|
1188
1263
|
copiedRef.current = false;
|
|
1189
1264
|
setTimeout(() => {
|
|
1190
1265
|
if (copiedRef.current) return;
|
|
1191
1266
|
const s = stateRef.current;
|
|
1192
|
-
navigator.clipboard?.writeText(s.exportToTsv(s.selectedRange))
|
|
1267
|
+
Promise.resolve(navigator.clipboard?.writeText(s.exportToTsv(s.selectedRange))).catch(() => {
|
|
1268
|
+
});
|
|
1193
1269
|
}, 0);
|
|
1194
1270
|
}, []);
|
|
1195
1271
|
return { copyShortcutFallback };
|
|
1196
1272
|
}
|
|
1197
1273
|
function useFillHandle(state) {
|
|
1198
|
-
const [drag, setDrag] = (0,
|
|
1199
|
-
const dragRef = (0,
|
|
1274
|
+
const [drag, setDrag] = (0, import_react18.useState)(null);
|
|
1275
|
+
const dragRef = (0, import_react18.useRef)(drag);
|
|
1200
1276
|
dragRef.current = drag;
|
|
1201
|
-
const stateRef = (0,
|
|
1277
|
+
const stateRef = (0, import_react18.useRef)(state);
|
|
1202
1278
|
stateRef.current = state;
|
|
1203
1279
|
const dragging = drag !== null;
|
|
1204
|
-
(0,
|
|
1280
|
+
(0, import_react18.useEffect)(() => {
|
|
1205
1281
|
if (!dragging) return;
|
|
1206
1282
|
const handleMouseUp = () => {
|
|
1207
1283
|
const current = dragRef.current;
|
|
@@ -1211,49 +1287,49 @@ function useFillHandle(state) {
|
|
|
1211
1287
|
window.addEventListener("mouseup", handleMouseUp);
|
|
1212
1288
|
return () => window.removeEventListener("mouseup", handleMouseUp);
|
|
1213
1289
|
}, [dragging]);
|
|
1214
|
-
const startFill = (0,
|
|
1290
|
+
const startFill = (0, import_react18.useCallback)((e) => {
|
|
1215
1291
|
e.preventDefault();
|
|
1216
1292
|
e.stopPropagation();
|
|
1217
1293
|
const range = stateRef.current.selectedRange;
|
|
1218
|
-
if (range) setDrag({ source: (0,
|
|
1294
|
+
if (range) setDrag({ source: (0, import_spreadsheet3.normalizeRange)(range), target: null });
|
|
1219
1295
|
}, []);
|
|
1220
|
-
const extendFill = (0,
|
|
1296
|
+
const extendFill = (0, import_react18.useCallback)((row, col) => {
|
|
1221
1297
|
const current = dragRef.current;
|
|
1222
1298
|
if (!current) return;
|
|
1223
|
-
setDrag({ source: current.source, target: (0,
|
|
1299
|
+
setDrag({ source: current.source, target: (0, import_spreadsheet3.computeFillTarget)(current.source, { row, col }) });
|
|
1224
1300
|
}, []);
|
|
1225
1301
|
return { fillTarget: drag?.target ?? null, isFilling: dragging, startFill, extendFill };
|
|
1226
1302
|
}
|
|
1227
1303
|
|
|
1228
1304
|
// src/spreadsheet/FormulaHints.tsx
|
|
1229
|
-
var
|
|
1230
|
-
var
|
|
1305
|
+
var import_react19 = require("react");
|
|
1306
|
+
var import_spreadsheet4 = require("@pixerate/editor/spreadsheet");
|
|
1231
1307
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1232
1308
|
var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
1233
|
-
const [caret, setCaret] = (0,
|
|
1234
|
-
const [focused, setFocused] = (0,
|
|
1235
|
-
const [selected, setSelected] = (0,
|
|
1236
|
-
const [dismissed, setDismissed] = (0,
|
|
1237
|
-
const [position, setPosition] = (0,
|
|
1238
|
-
const pendingCaret = (0,
|
|
1239
|
-
const hints = (0,
|
|
1240
|
-
() => (0,
|
|
1309
|
+
const [caret, setCaret] = (0, import_react19.useState)(null);
|
|
1310
|
+
const [focused, setFocused] = (0, import_react19.useState)(false);
|
|
1311
|
+
const [selected, setSelected] = (0, import_react19.useState)(0);
|
|
1312
|
+
const [dismissed, setDismissed] = (0, import_react19.useState)(false);
|
|
1313
|
+
const [position, setPosition] = (0, import_react19.useState)(null);
|
|
1314
|
+
const pendingCaret = (0, import_react19.useRef)(null);
|
|
1315
|
+
const hints = (0, import_react19.useMemo)(
|
|
1316
|
+
() => (0, import_spreadsheet4.getFormulaHints)(value, caret ?? value.length, { limit }),
|
|
1241
1317
|
[value, caret, limit]
|
|
1242
1318
|
);
|
|
1243
1319
|
const suggestions = dismissed ? [] : hints.suggestions;
|
|
1244
1320
|
const selectedIndex = Math.max(0, Math.min(selected, suggestions.length - 1));
|
|
1245
1321
|
const visible = focused && value.trimStart().startsWith("=") && (suggestions.length > 0 || !!hints.activeCall);
|
|
1246
|
-
const latest = (0,
|
|
1322
|
+
const latest = (0, import_react19.useRef)({ suggestions, selected: selectedIndex, value, caret, onAccept });
|
|
1247
1323
|
latest.current = { suggestions, selected: selectedIndex, value, caret, onAccept };
|
|
1248
1324
|
const accept = (index) => {
|
|
1249
1325
|
const { suggestions: list, value: current, caret: at, onAccept: commit } = latest.current;
|
|
1250
1326
|
const suggestion = list[index];
|
|
1251
1327
|
if (!suggestion) return;
|
|
1252
|
-
const next = (0,
|
|
1328
|
+
const next = (0, import_spreadsheet4.applyFormulaSuggestion)(current, at ?? current.length, suggestion.name);
|
|
1253
1329
|
pendingCaret.current = next.caret;
|
|
1254
1330
|
commit(next.value);
|
|
1255
1331
|
};
|
|
1256
|
-
(0,
|
|
1332
|
+
(0, import_react19.useEffect)(() => {
|
|
1257
1333
|
const input = inputRef.current;
|
|
1258
1334
|
if (!input) return;
|
|
1259
1335
|
const syncCaret = () => setCaret(input.selectionStart ?? input.value.length);
|
|
@@ -1303,7 +1379,7 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
|
1303
1379
|
input.removeEventListener("keydown", onKeyDown);
|
|
1304
1380
|
};
|
|
1305
1381
|
}, [inputRef]);
|
|
1306
|
-
(0,
|
|
1382
|
+
(0, import_react19.useLayoutEffect)(() => {
|
|
1307
1383
|
const input = inputRef.current;
|
|
1308
1384
|
const at = pendingCaret.current;
|
|
1309
1385
|
if (!input || at === null || input.value !== value) return;
|
|
@@ -1312,7 +1388,7 @@ var FormulaHints = ({ inputRef, value, onAccept, limit = 8 }) => {
|
|
|
1312
1388
|
setCaret(at);
|
|
1313
1389
|
setSelected(0);
|
|
1314
1390
|
}, [value, inputRef]);
|
|
1315
|
-
(0,
|
|
1391
|
+
(0, import_react19.useLayoutEffect)(() => {
|
|
1316
1392
|
const input = inputRef.current;
|
|
1317
1393
|
if (!visible || !input) return;
|
|
1318
1394
|
const rect = input.getBoundingClientRect();
|
|
@@ -1389,6 +1465,20 @@ function frozenCellStyle(viewRow, viewCol) {
|
|
|
1389
1465
|
background: "var(--background, #fff)"
|
|
1390
1466
|
};
|
|
1391
1467
|
}
|
|
1468
|
+
var coordKey = (cell) => cell ? `${(0, import_spreadsheet5.indexToColName)(cell.col)}${cell.row + 1}` : "";
|
|
1469
|
+
function spillBorderStyle(range, row, col) {
|
|
1470
|
+
const line = "1px solid color-mix(in srgb, var(--primary, #6366f1) 60%, transparent)";
|
|
1471
|
+
return {
|
|
1472
|
+
position: "absolute",
|
|
1473
|
+
inset: 0,
|
|
1474
|
+
pointerEvents: "none",
|
|
1475
|
+
zIndex: 5,
|
|
1476
|
+
borderTop: row === range.startRow ? line : void 0,
|
|
1477
|
+
borderBottom: row === range.endRow ? line : void 0,
|
|
1478
|
+
borderLeft: col === range.startCol ? line : void 0,
|
|
1479
|
+
borderRight: col === range.endCol ? line : void 0
|
|
1480
|
+
};
|
|
1481
|
+
}
|
|
1392
1482
|
var SpreadsheetEditor = ({
|
|
1393
1483
|
state: externalState,
|
|
1394
1484
|
readOnly = false,
|
|
@@ -1399,47 +1489,53 @@ var SpreadsheetEditor = ({
|
|
|
1399
1489
|
}) => {
|
|
1400
1490
|
const defaultState = useSpreadsheetEditor();
|
|
1401
1491
|
const state = externalState || defaultState;
|
|
1402
|
-
const gridRef = (0,
|
|
1403
|
-
const formulaBarRef = (0,
|
|
1404
|
-
const cellInputRef = (0,
|
|
1405
|
-
const [resizingColId, setResizingColId] = (0,
|
|
1406
|
-
const [hoveredColId, setHoveredColId] = (0,
|
|
1407
|
-
const [resizeStartX, setResizeStartX] = (0,
|
|
1408
|
-
const [resizeStartWidth, setResizeStartWidth] = (0,
|
|
1492
|
+
const gridRef = (0, import_react20.useRef)(null);
|
|
1493
|
+
const formulaBarRef = (0, import_react20.useRef)(null);
|
|
1494
|
+
const cellInputRef = (0, import_react20.useRef)(null);
|
|
1495
|
+
const [resizingColId, setResizingColId] = (0, import_react20.useState)(null);
|
|
1496
|
+
const [hoveredColId, setHoveredColId] = (0, import_react20.useState)(null);
|
|
1497
|
+
const [resizeStartX, setResizeStartX] = (0, import_react20.useState)(0);
|
|
1498
|
+
const [resizeStartWidth, setResizeStartWidth] = (0, import_react20.useState)(0);
|
|
1409
1499
|
const view = state.viewModel;
|
|
1410
1500
|
const { copyShortcutFallback } = useSpreadsheetClipboard(gridRef, state, readOnly);
|
|
1411
1501
|
const { fillTarget, startFill, extendFill } = useFillHandle(state);
|
|
1412
|
-
const [menu, setMenu] = (0,
|
|
1502
|
+
const [menu, setMenu] = (0, import_react20.useState)(null);
|
|
1413
1503
|
const filter = state.document.table?.filter;
|
|
1414
|
-
const filteredColIds = (0,
|
|
1504
|
+
const filteredColIds = (0, import_react20.useMemo)(
|
|
1415
1505
|
() => new Set(filter?.enabled ? filter.rules.map((r) => r.colId) : []),
|
|
1416
1506
|
[filter]
|
|
1417
1507
|
);
|
|
1418
|
-
const handleCellContextMenu = (0,
|
|
1508
|
+
const handleCellContextMenu = (0, import_react20.useCallback)((rIdx, cIdx, e) => {
|
|
1419
1509
|
if (readOnly) return;
|
|
1420
1510
|
e.preventDefault();
|
|
1421
1511
|
if (state.editingCell) state.commitEditing();
|
|
1422
|
-
if (!state.selectedRange || !(0,
|
|
1512
|
+
if (!state.selectedRange || !(0, import_spreadsheet5.rangeContains)(state.selectedRange, rIdx, cIdx)) {
|
|
1423
1513
|
state.selectCell(rIdx, cIdx);
|
|
1424
1514
|
}
|
|
1425
|
-
setMenu({ x: e.clientX, y: e.clientY, items: (0,
|
|
1515
|
+
setMenu({ x: e.clientX, y: e.clientY, items: (0, import_spreadsheet5.getSpreadsheetMenuItems)(state.controller, { row: rIdx, col: cIdx }) });
|
|
1426
1516
|
}, [readOnly, state]);
|
|
1427
|
-
const activeRawValue = (0,
|
|
1517
|
+
const activeRawValue = (0, import_react20.useMemo)(() => {
|
|
1428
1518
|
if (!state.activeCell) return "";
|
|
1429
1519
|
const row = state.document.rows[state.activeCell.row];
|
|
1430
1520
|
const col = state.document.columns[state.activeCell.col];
|
|
1431
1521
|
if (!row || !col) return "";
|
|
1432
1522
|
return state.getCell(row.id, col.id).raw;
|
|
1433
1523
|
}, [state.activeCell, state.document]);
|
|
1434
|
-
const
|
|
1524
|
+
const activeSpill = (0, import_react20.useMemo)(
|
|
1525
|
+
() => state.activeCell ? state.controller.getSpillAt(state.activeCell.row, state.activeCell.col) : null,
|
|
1526
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1527
|
+
[state.controller, state.activeCell, state.document]
|
|
1528
|
+
);
|
|
1529
|
+
const spillFormula = activeSpill && !activeRawValue && activeSpill.key !== coordKey(state.activeCell) ? activeSpill.formula : "";
|
|
1530
|
+
const coordLabel = (0, import_react20.useMemo)(() => {
|
|
1435
1531
|
if (!state.activeCell) return "--";
|
|
1436
|
-
const colName = (0,
|
|
1532
|
+
const colName = (0, import_spreadsheet5.indexToColName)(state.activeCell.col);
|
|
1437
1533
|
return `${colName}${state.activeCell.row + 1}`;
|
|
1438
1534
|
}, [state.activeCell]);
|
|
1439
|
-
const [formulaDraft, setFormulaDraft] = (0,
|
|
1535
|
+
const [formulaDraft, setFormulaDraft] = (0, import_react20.useState)(null);
|
|
1440
1536
|
const activeColumn = state.activeCell ? state.document.columns[state.activeCell.col] : void 0;
|
|
1441
1537
|
const formulaBarReadOnly = readOnly || !state.activeCell || !!activeColumn?.readOnly;
|
|
1442
|
-
(0,
|
|
1538
|
+
(0, import_react20.useEffect)(() => {
|
|
1443
1539
|
setFormulaDraft(null);
|
|
1444
1540
|
}, [state.activeCell?.row, state.activeCell?.col]);
|
|
1445
1541
|
const commitFormulaBar = () => {
|
|
@@ -1455,19 +1551,19 @@ var SpreadsheetEditor = ({
|
|
|
1455
1551
|
}
|
|
1456
1552
|
setFormulaDraft(null);
|
|
1457
1553
|
};
|
|
1458
|
-
const handleCellClick = (0,
|
|
1554
|
+
const handleCellClick = (0, import_react20.useCallback)((rIdx, cIdx, e) => {
|
|
1459
1555
|
if (state.editingCell && (state.editingCell.row !== rIdx || state.editingCell.col !== cIdx)) {
|
|
1460
1556
|
state.commitEditing();
|
|
1461
1557
|
}
|
|
1462
1558
|
state.selectCell(rIdx, cIdx, e.shiftKey);
|
|
1463
1559
|
}, [state]);
|
|
1464
|
-
const handleCellDblClick = (0,
|
|
1560
|
+
const handleCellDblClick = (0, import_react20.useCallback)((rIdx, cIdx) => {
|
|
1465
1561
|
if (readOnly) return;
|
|
1466
1562
|
const col = state.document.columns[cIdx];
|
|
1467
1563
|
if (col?.readOnly) return;
|
|
1468
1564
|
state.startEditing(rIdx, cIdx);
|
|
1469
1565
|
}, [readOnly, state]);
|
|
1470
|
-
const handleKeyDown = (0,
|
|
1566
|
+
const handleKeyDown = (0, import_react20.useCallback)((e) => {
|
|
1471
1567
|
if (state.editingCell) {
|
|
1472
1568
|
if (e.key === "Enter") {
|
|
1473
1569
|
e.preventDefault();
|
|
@@ -1480,7 +1576,10 @@ var SpreadsheetEditor = ({
|
|
|
1480
1576
|
e.preventDefault();
|
|
1481
1577
|
state.commitEditing();
|
|
1482
1578
|
state.moveCursor(e.shiftKey ? "left" : "right");
|
|
1579
|
+
} else {
|
|
1580
|
+
return;
|
|
1483
1581
|
}
|
|
1582
|
+
gridRef.current?.focus();
|
|
1484
1583
|
return;
|
|
1485
1584
|
}
|
|
1486
1585
|
if (!state.activeCell) return;
|
|
@@ -1528,15 +1627,16 @@ var SpreadsheetEditor = ({
|
|
|
1528
1627
|
} else if (!readOnly && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
1529
1628
|
const col = state.document.columns[state.activeCell.col];
|
|
1530
1629
|
if (!col?.readOnly) {
|
|
1630
|
+
e.preventDefault();
|
|
1531
1631
|
state.startEditing(state.activeCell.row, state.activeCell.col, e.key);
|
|
1532
1632
|
}
|
|
1533
1633
|
}
|
|
1534
1634
|
}, [readOnly, state, copyShortcutFallback]);
|
|
1535
|
-
const stateRef = (0,
|
|
1635
|
+
const stateRef = (0, import_react20.useRef)(state);
|
|
1536
1636
|
stateRef.current = state;
|
|
1537
|
-
const onColumnResizeRef = (0,
|
|
1637
|
+
const onColumnResizeRef = (0, import_react20.useRef)(onColumnResize);
|
|
1538
1638
|
onColumnResizeRef.current = onColumnResize;
|
|
1539
|
-
(0,
|
|
1639
|
+
(0, import_react20.useEffect)(() => {
|
|
1540
1640
|
if (!resizingColId) return;
|
|
1541
1641
|
if (typeof document !== "undefined") {
|
|
1542
1642
|
document.body.style.cursor = "col-resize";
|
|
@@ -1587,7 +1687,7 @@ var SpreadsheetEditor = ({
|
|
|
1587
1687
|
window.removeEventListener("mouseup", handleMouseUp);
|
|
1588
1688
|
};
|
|
1589
1689
|
}, [resizingColId, resizeStartX, resizeStartWidth]);
|
|
1590
|
-
const measureElementContentWidth = (0,
|
|
1690
|
+
const measureElementContentWidth = (0, import_react20.useCallback)((el, container) => {
|
|
1591
1691
|
if (typeof document === "undefined") return 0;
|
|
1592
1692
|
let maxW = el.scrollWidth || 0;
|
|
1593
1693
|
const firstChild = el.firstElementChild;
|
|
@@ -1635,7 +1735,7 @@ var SpreadsheetEditor = ({
|
|
|
1635
1735
|
}
|
|
1636
1736
|
return maxW;
|
|
1637
1737
|
}, []);
|
|
1638
|
-
const autoFitColumn = (0,
|
|
1738
|
+
const autoFitColumn = (0, import_react20.useCallback)((colId, colIndex) => {
|
|
1639
1739
|
const col = state.document.columns.find((c) => c.id === colId);
|
|
1640
1740
|
if (!col) return;
|
|
1641
1741
|
let calculatedWidth = 0;
|
|
@@ -1671,12 +1771,12 @@ var SpreadsheetEditor = ({
|
|
|
1671
1771
|
onColumnResize(updatedCol.id, updatedCol.width || 130);
|
|
1672
1772
|
}
|
|
1673
1773
|
}, [state, measureElementContentWidth, onColumnResize]);
|
|
1674
|
-
const handleResizeDblClick = (0,
|
|
1774
|
+
const handleResizeDblClick = (0, import_react20.useCallback)((colId, colIndex, e) => {
|
|
1675
1775
|
e.preventDefault();
|
|
1676
1776
|
e.stopPropagation();
|
|
1677
1777
|
autoFitColumn(colId, colIndex);
|
|
1678
1778
|
}, [autoFitColumn]);
|
|
1679
|
-
const handleHeaderDblClick = (0,
|
|
1779
|
+
const handleHeaderDblClick = (0, import_react20.useCallback)((colId, colIndex, e) => {
|
|
1680
1780
|
const target = e.currentTarget;
|
|
1681
1781
|
if (target) {
|
|
1682
1782
|
const rect = target.getBoundingClientRect();
|
|
@@ -1720,7 +1820,9 @@ var SpreadsheetEditor = ({
|
|
|
1720
1820
|
placeholder: "Enter a value or formula (e.g. =SUM(A1:A5))",
|
|
1721
1821
|
"aria-label": "Formula bar",
|
|
1722
1822
|
readOnly: formulaBarReadOnly,
|
|
1723
|
-
|
|
1823
|
+
"data-spill-formula": !state.editingCell && formulaDraft === null && spillFormula ? "true" : void 0,
|
|
1824
|
+
style: !state.editingCell && formulaDraft === null && spillFormula ? { color: "var(--muted-foreground, #94a3b8)" } : void 0,
|
|
1825
|
+
value: state.editingCell ? state.draftValue : formulaDraft ?? (activeRawValue || spillFormula),
|
|
1724
1826
|
onFocus: () => {
|
|
1725
1827
|
if (!state.editingCell) setFormulaDraft(activeRawValue);
|
|
1726
1828
|
},
|
|
@@ -1755,8 +1857,8 @@ var SpreadsheetEditor = ({
|
|
|
1755
1857
|
)
|
|
1756
1858
|
] }),
|
|
1757
1859
|
/* @__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
|
|
1759
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { className: "w-12 min-w-[3rem] sticky left-0 z-30 bg-muted
|
|
1860
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { className: "h-7 bg-muted sticky top-0 z-20 border-b border-border shadow-xs", children: [
|
|
1861
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { className: "w-12 min-w-[3rem] sticky left-0 z-30 bg-muted border-r border-border text-center text-[10px] text-muted-foreground font-medium", children: "#" }),
|
|
1760
1862
|
view.columns.map(({ column: col, index: cIdx, frozen, stickyLeft }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1761
1863
|
"th",
|
|
1762
1864
|
{
|
|
@@ -1842,7 +1944,7 @@ var SpreadsheetEditor = ({
|
|
|
1842
1944
|
);
|
|
1843
1945
|
}
|
|
1844
1946
|
const displayRowIndex = viewRow.index;
|
|
1845
|
-
const selection = state.selectedRange ? (0,
|
|
1947
|
+
const selection = state.selectedRange ? (0, import_spreadsheet5.normalizeRange)(state.selectedRange) : null;
|
|
1846
1948
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1847
1949
|
"tr",
|
|
1848
1950
|
{
|
|
@@ -1853,7 +1955,7 @@ var SpreadsheetEditor = ({
|
|
|
1853
1955
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1854
1956
|
"td",
|
|
1855
1957
|
{
|
|
1856
|
-
className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted
|
|
1958
|
+
className: "w-12 min-w-[3rem] sticky left-0 z-10 bg-muted border-r border-border text-center text-[10px] text-muted-foreground font-mono select-none",
|
|
1857
1959
|
style: viewRow.frozen ? { top: COLUMN_HEADER_HEIGHT + viewRow.stickyTop, zIndex: 15 } : void 0,
|
|
1858
1960
|
children: displayRowIndex + 1
|
|
1859
1961
|
}
|
|
@@ -1869,8 +1971,8 @@ var SpreadsheetEditor = ({
|
|
|
1869
1971
|
const selected = isCellSelected(rIdx, cIdx);
|
|
1870
1972
|
const active = isActiveCell(rIdx, cIdx);
|
|
1871
1973
|
const isEditing = state.editingCell?.row === rIdx && state.editingCell?.col === cIdx;
|
|
1872
|
-
const inFillPreview = !!fillTarget && !selected && (0,
|
|
1873
|
-
const showFillHandle = !readOnly && !isEditing && !!selection && (span.merge ? (0,
|
|
1974
|
+
const inFillPreview = !!fillTarget && !selected && (0, import_spreadsheet5.rangeContains)(fillTarget, displayRowIndex, viewCol.index);
|
|
1975
|
+
const showFillHandle = !readOnly && !isEditing && !!selection && (span.merge ? (0, import_spreadsheet5.rangeContains)(span.merge, selection.endRow, selection.endCol) : selection.endRow === rIdx && selection.endCol === cIdx);
|
|
1874
1976
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1875
1977
|
"td",
|
|
1876
1978
|
{
|
|
@@ -1900,6 +2002,10 @@ var SpreadsheetEditor = ({
|
|
|
1900
2002
|
value: state.draftValue,
|
|
1901
2003
|
onChange: (e) => state.setDraftValue(e.target.value),
|
|
1902
2004
|
onBlur: () => state.commitEditing(),
|
|
2005
|
+
onFocus: (e) => {
|
|
2006
|
+
const end = e.currentTarget.value.length;
|
|
2007
|
+
e.currentTarget.setSelectionRange(end, end);
|
|
2008
|
+
},
|
|
1903
2009
|
autoFocus: true
|
|
1904
2010
|
}
|
|
1905
2011
|
),
|
|
@@ -1909,9 +2015,10 @@ var SpreadsheetEditor = ({
|
|
|
1909
2015
|
{
|
|
1910
2016
|
className: `truncate block max-w-full ${cell.error ? "text-destructive font-semibold" : ""}`,
|
|
1911
2017
|
title: cell.error ? cell.errorMessage ?? cell.error : void 0,
|
|
1912
|
-
children:
|
|
2018
|
+
children: (0, import_spreadsheet5.formatCellDisplay)(cell)
|
|
1913
2019
|
}
|
|
1914
2020
|
),
|
|
2021
|
+
activeSpill && (0, import_spreadsheet5.rangeContains)(activeSpill.range, rIdx, cIdx) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "aria-hidden": "true", className: "spreadsheet-spill-border", style: spillBorderStyle(activeSpill.range, rIdx, cIdx) }),
|
|
1915
2022
|
showFillHandle && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1916
2023
|
"div",
|
|
1917
2024
|
{
|
|
@@ -1969,7 +2076,7 @@ var SpreadsheetEditor = ({
|
|
|
1969
2076
|
};
|
|
1970
2077
|
|
|
1971
2078
|
// src/slots.tsx
|
|
1972
|
-
var
|
|
2079
|
+
var import_react21 = require("react");
|
|
1973
2080
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1974
2081
|
var defaultSlots = {
|
|
1975
2082
|
Button: (props) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
@@ -1991,102 +2098,103 @@ var defaultSlots = {
|
|
|
1991
2098
|
props.onClose && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", onClick: props.onClose, className: "opacity-70 hover:opacity-100", children: "\xD7" })
|
|
1992
2099
|
] })
|
|
1993
2100
|
};
|
|
1994
|
-
var EditorSlotsContext = (0,
|
|
2101
|
+
var EditorSlotsContext = (0, import_react21.createContext)(defaultSlots);
|
|
1995
2102
|
function EditorSlotsProvider({ slots, children }) {
|
|
1996
|
-
const mergedSlots = (0,
|
|
2103
|
+
const mergedSlots = (0, import_react21.useMemo)(() => ({ ...defaultSlots, ...slots }), [slots]);
|
|
1997
2104
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(EditorSlotsContext.Provider, { value: mergedSlots, children });
|
|
1998
2105
|
}
|
|
1999
2106
|
function useEditorSlots() {
|
|
2000
|
-
return (0,
|
|
2107
|
+
return (0, import_react21.useContext)(EditorSlotsContext);
|
|
2001
2108
|
}
|
|
2002
2109
|
|
|
2003
2110
|
// src/image-editor/useImageEditor.ts
|
|
2004
|
-
var
|
|
2111
|
+
var import_react22 = require("react");
|
|
2005
2112
|
var import_image_editor = require("@pixerate/editor/image-editor");
|
|
2006
2113
|
function useImageEditor(options = {}) {
|
|
2007
|
-
const controllerRef = (0,
|
|
2114
|
+
const controllerRef = (0, import_react22.useRef)(null);
|
|
2008
2115
|
if (!controllerRef.current) {
|
|
2009
2116
|
controllerRef.current = new import_image_editor.ImageEditorController(options);
|
|
2010
2117
|
}
|
|
2011
2118
|
const controller = controllerRef.current;
|
|
2012
|
-
const [state, setState] = (0,
|
|
2013
|
-
const [historyTicks, setHistoryTicks] = (0,
|
|
2014
|
-
(0,
|
|
2119
|
+
const [state, setState] = (0, import_react22.useState)(() => controller.getState());
|
|
2120
|
+
const [historyTicks, setHistoryTicks] = (0, import_react22.useState)(0);
|
|
2121
|
+
(0, import_react22.useEffect)(() => {
|
|
2015
2122
|
const unsub = controller.subscribe((next) => {
|
|
2016
2123
|
setState(next);
|
|
2017
2124
|
setHistoryTicks((t) => t + 1);
|
|
2018
2125
|
});
|
|
2019
2126
|
return unsub;
|
|
2020
2127
|
}, [controller]);
|
|
2021
|
-
const loadedImageRef = (0,
|
|
2022
|
-
(0,
|
|
2128
|
+
const loadedImageRef = (0, import_react22.useRef)(options.image);
|
|
2129
|
+
(0, import_react22.useEffect)(() => {
|
|
2023
2130
|
if (options.image === loadedImageRef.current) return;
|
|
2024
2131
|
loadedImageRef.current = options.image;
|
|
2025
2132
|
if (options.image) {
|
|
2026
2133
|
controller.loadImage(options.image);
|
|
2027
2134
|
}
|
|
2028
2135
|
}, [options.image, controller]);
|
|
2029
|
-
const setTool = (0,
|
|
2030
|
-
const setCrop = (0,
|
|
2136
|
+
const setTool = (0, import_react22.useCallback)((tool) => controller.setTool(tool), [controller]);
|
|
2137
|
+
const setCrop = (0, import_react22.useCallback)(
|
|
2031
2138
|
(crop, addToHistory = true) => controller.setCrop(crop, addToHistory),
|
|
2032
2139
|
[controller]
|
|
2033
2140
|
);
|
|
2034
|
-
const applyCropPreset = (0,
|
|
2035
|
-
const resetCrop = (0,
|
|
2036
|
-
const rotate = (0,
|
|
2037
|
-
const setRotation = (0,
|
|
2038
|
-
const flipHorizontal = (0,
|
|
2039
|
-
const flipVertical = (0,
|
|
2040
|
-
const setAdjustments = (0,
|
|
2141
|
+
const applyCropPreset = (0, import_react22.useCallback)((ratio) => controller.applyCropPreset(ratio), [controller]);
|
|
2142
|
+
const resetCrop = (0, import_react22.useCallback)(() => controller.resetCrop(), [controller]);
|
|
2143
|
+
const rotate = (0, import_react22.useCallback)((deg) => controller.rotate(deg), [controller]);
|
|
2144
|
+
const setRotation = (0, import_react22.useCallback)((deg) => controller.setRotation(deg), [controller]);
|
|
2145
|
+
const flipHorizontal = (0, import_react22.useCallback)(() => controller.flipHorizontal(), [controller]);
|
|
2146
|
+
const flipVertical = (0, import_react22.useCallback)(() => controller.flipVertical(), [controller]);
|
|
2147
|
+
const setAdjustments = (0, import_react22.useCallback)(
|
|
2041
2148
|
(partial, commitToHistory = true) => controller.setAdjustments(partial, commitToHistory),
|
|
2042
2149
|
[controller]
|
|
2043
2150
|
);
|
|
2044
|
-
const resetAdjustments = (0,
|
|
2045
|
-
const
|
|
2046
|
-
const
|
|
2047
|
-
const
|
|
2048
|
-
const
|
|
2151
|
+
const resetAdjustments = (0, import_react22.useCallback)(() => controller.resetAdjustments(), [controller]);
|
|
2152
|
+
const upgradeProcess = (0, import_react22.useCallback)(() => controller.upgradeProcess(), [controller]);
|
|
2153
|
+
const setDepthMask = (0, import_react22.useCallback)((partial) => controller.setDepthMask(partial), [controller]);
|
|
2154
|
+
const resetDepthMask = (0, import_react22.useCallback)(() => controller.resetDepthMask(), [controller]);
|
|
2155
|
+
const addAnnotation = (0, import_react22.useCallback)((ann) => controller.addAnnotation(ann), [controller]);
|
|
2156
|
+
const updateAnnotation = (0, import_react22.useCallback)(
|
|
2049
2157
|
(id, partial, commitToHistory = true) => controller.updateAnnotation(id, partial, commitToHistory),
|
|
2050
2158
|
[controller]
|
|
2051
2159
|
);
|
|
2052
|
-
const removeAnnotation = (0,
|
|
2053
|
-
const clearAnnotations = (0,
|
|
2054
|
-
const selectAnnotation = (0,
|
|
2055
|
-
const undo = (0,
|
|
2056
|
-
const redo = (0,
|
|
2057
|
-
const reset = (0,
|
|
2058
|
-
const zoomIn = (0,
|
|
2059
|
-
const zoomOut = (0,
|
|
2060
|
-
const resetZoom = (0,
|
|
2061
|
-
const setZoom = (0,
|
|
2062
|
-
const setPan = (0,
|
|
2063
|
-
const setComparing = (0,
|
|
2064
|
-
const loadImage = (0,
|
|
2065
|
-
const toDataURL = (0,
|
|
2066
|
-
const toBlob = (0,
|
|
2067
|
-
const toJSON = (0,
|
|
2068
|
-
const loadJSON = (0,
|
|
2069
|
-
const renderMask = (0,
|
|
2160
|
+
const removeAnnotation = (0, import_react22.useCallback)((id) => controller.removeAnnotation(id), [controller]);
|
|
2161
|
+
const clearAnnotations = (0, import_react22.useCallback)(() => controller.clearAnnotations(), [controller]);
|
|
2162
|
+
const selectAnnotation = (0, import_react22.useCallback)((id) => controller.selectAnnotation(id), [controller]);
|
|
2163
|
+
const undo = (0, import_react22.useCallback)(() => controller.undo(), [controller]);
|
|
2164
|
+
const redo = (0, import_react22.useCallback)(() => controller.redo(), [controller]);
|
|
2165
|
+
const reset = (0, import_react22.useCallback)(() => controller.reset(), [controller]);
|
|
2166
|
+
const zoomIn = (0, import_react22.useCallback)((factor) => controller.zoomIn(factor), [controller]);
|
|
2167
|
+
const zoomOut = (0, import_react22.useCallback)((factor) => controller.zoomOut(factor), [controller]);
|
|
2168
|
+
const resetZoom = (0, import_react22.useCallback)(() => controller.resetZoom(), [controller]);
|
|
2169
|
+
const setZoom = (0, import_react22.useCallback)((zoom) => controller.setZoom(zoom), [controller]);
|
|
2170
|
+
const setPan = (0, import_react22.useCallback)((pan) => controller.setPan(pan), [controller]);
|
|
2171
|
+
const setComparing = (0, import_react22.useCallback)((comp) => controller.setComparing(comp), [controller]);
|
|
2172
|
+
const loadImage = (0, import_react22.useCallback)((src) => controller.loadImage(src), [controller]);
|
|
2173
|
+
const toDataURL = (0, import_react22.useCallback)((opts) => controller.toDataURL(opts), [controller]);
|
|
2174
|
+
const toBlob = (0, import_react22.useCallback)((opts) => controller.toBlob(opts), [controller]);
|
|
2175
|
+
const toJSON = (0, import_react22.useCallback)(() => controller.toJSON(), [controller]);
|
|
2176
|
+
const loadJSON = (0, import_react22.useCallback)((data) => controller.loadJSON(data), [controller]);
|
|
2177
|
+
const renderMask = (0, import_react22.useCallback)(
|
|
2070
2178
|
(opts) => controller.renderMask(opts),
|
|
2071
2179
|
[controller]
|
|
2072
2180
|
);
|
|
2073
|
-
const toMaskDataURL = (0,
|
|
2181
|
+
const toMaskDataURL = (0, import_react22.useCallback)(
|
|
2074
2182
|
(opts) => controller.toMaskDataURL(opts),
|
|
2075
2183
|
[controller]
|
|
2076
2184
|
);
|
|
2077
|
-
const toSourceDataURL = (0,
|
|
2185
|
+
const toSourceDataURL = (0, import_react22.useCallback)(
|
|
2078
2186
|
(opts) => controller.toSourceDataURL(opts),
|
|
2079
2187
|
[controller]
|
|
2080
2188
|
);
|
|
2081
|
-
const applyInpaintedImage = (0,
|
|
2189
|
+
const applyInpaintedImage = (0, import_react22.useCallback)(
|
|
2082
2190
|
(newDataUrl) => controller.applyInpaintedImage(newDataUrl),
|
|
2083
2191
|
[controller]
|
|
2084
2192
|
);
|
|
2085
|
-
const applyBackgroundRemovedImage = (0,
|
|
2193
|
+
const applyBackgroundRemovedImage = (0, import_react22.useCallback)(
|
|
2086
2194
|
(newDataUrl) => controller.applyBackgroundRemovedImage(newDataUrl),
|
|
2087
2195
|
[controller]
|
|
2088
2196
|
);
|
|
2089
|
-
return (0,
|
|
2197
|
+
return (0, import_react22.useMemo)(
|
|
2090
2198
|
() => ({
|
|
2091
2199
|
controller,
|
|
2092
2200
|
state,
|
|
@@ -2102,6 +2210,7 @@ function useImageEditor(options = {}) {
|
|
|
2102
2210
|
flipVertical,
|
|
2103
2211
|
setAdjustments,
|
|
2104
2212
|
resetAdjustments,
|
|
2213
|
+
upgradeProcess,
|
|
2105
2214
|
setDepthMask,
|
|
2106
2215
|
resetDepthMask,
|
|
2107
2216
|
addAnnotation,
|
|
@@ -2135,7 +2244,7 @@ function useImageEditor(options = {}) {
|
|
|
2135
2244
|
}
|
|
2136
2245
|
|
|
2137
2246
|
// src/image-editor/ImageEditor.tsx
|
|
2138
|
-
var
|
|
2247
|
+
var import_react23 = require("react");
|
|
2139
2248
|
var import_image_editor2 = require("@pixerate/editor/image-editor");
|
|
2140
2249
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2141
2250
|
var ImageEditor = ({
|
|
@@ -2152,16 +2261,17 @@ var ImageEditor = ({
|
|
|
2152
2261
|
const internalEditor = useImageEditor({ image: src });
|
|
2153
2262
|
const editor = externalEditor || internalEditor;
|
|
2154
2263
|
const { state, controller } = editor;
|
|
2155
|
-
const
|
|
2156
|
-
const
|
|
2157
|
-
const
|
|
2158
|
-
const [
|
|
2159
|
-
const [
|
|
2160
|
-
const [
|
|
2161
|
-
const [
|
|
2162
|
-
const [
|
|
2163
|
-
const [
|
|
2164
|
-
const [
|
|
2264
|
+
const legacyProcess = (0, import_image_editor2.normalizeProcessVersion)(state.adjustments.process) < import_image_editor2.LATEST_PROCESS_VERSION;
|
|
2265
|
+
const canvasRef = (0, import_react23.useRef)(null);
|
|
2266
|
+
const containerRef = (0, import_react23.useRef)(null);
|
|
2267
|
+
const [activeTab, setActiveTab] = (0, import_react23.useState)("crop");
|
|
2268
|
+
const [activeCropRatio, setActiveCropRatio] = (0, import_react23.useState)(null);
|
|
2269
|
+
const [inpaintPrompt, setInpaintPrompt] = (0, import_react23.useState)("");
|
|
2270
|
+
const [inpaintMaskMode, setInpaintMaskMode] = (0, import_react23.useState)("annotations");
|
|
2271
|
+
const [isRemovingBg, setIsRemovingBg] = (0, import_react23.useState)(false);
|
|
2272
|
+
const [isInpainting, setIsInpainting] = (0, import_react23.useState)(false);
|
|
2273
|
+
const [aiError, setAiError] = (0, import_react23.useState)(null);
|
|
2274
|
+
const [aiSuccess, setAiSuccess] = (0, import_react23.useState)(null);
|
|
2165
2275
|
const effectiveOnInpaint = onInpaint || aiHooks?.onInpaint;
|
|
2166
2276
|
const effectiveOnRemoveBg = onRemoveBackground || aiHooks?.onRemoveBackground;
|
|
2167
2277
|
const handleRemoveBackground = async () => {
|
|
@@ -2223,18 +2333,18 @@ var ImageEditor = ({
|
|
|
2223
2333
|
setIsInpainting(false);
|
|
2224
2334
|
}
|
|
2225
2335
|
};
|
|
2226
|
-
const [activeColor, setActiveColor] = (0,
|
|
2227
|
-
const [strokeWidth, setStrokeWidth] = (0,
|
|
2228
|
-
const [fontSize, setFontSize] = (0,
|
|
2229
|
-
const [textInput, setTextInput] = (0,
|
|
2230
|
-
const draftAnnotationRef = (0,
|
|
2231
|
-
const draftCropRef = (0,
|
|
2232
|
-
const cropDragInfoRef = (0,
|
|
2233
|
-
const annotationDragInfoRef = (0,
|
|
2234
|
-
const isDrawingRef = (0,
|
|
2235
|
-
const currentPathRef = (0,
|
|
2236
|
-
const dragStartPointRef = (0,
|
|
2237
|
-
const renderCanvas = (0,
|
|
2336
|
+
const [activeColor, setActiveColor] = (0, import_react23.useState)("#ef4444");
|
|
2337
|
+
const [strokeWidth, setStrokeWidth] = (0, import_react23.useState)(3);
|
|
2338
|
+
const [fontSize, setFontSize] = (0, import_react23.useState)(24);
|
|
2339
|
+
const [textInput, setTextInput] = (0, import_react23.useState)("");
|
|
2340
|
+
const draftAnnotationRef = (0, import_react23.useRef)(null);
|
|
2341
|
+
const draftCropRef = (0, import_react23.useRef)(null);
|
|
2342
|
+
const cropDragInfoRef = (0, import_react23.useRef)(null);
|
|
2343
|
+
const annotationDragInfoRef = (0, import_react23.useRef)(null);
|
|
2344
|
+
const isDrawingRef = (0, import_react23.useRef)(false);
|
|
2345
|
+
const currentPathRef = (0, import_react23.useRef)([]);
|
|
2346
|
+
const dragStartPointRef = (0, import_react23.useRef)(null);
|
|
2347
|
+
const renderCanvas = (0, import_react23.useCallback)(
|
|
2238
2348
|
async (draftAnnotation, draftCrop) => {
|
|
2239
2349
|
const canvas = canvasRef.current;
|
|
2240
2350
|
const container = containerRef.current;
|
|
@@ -2253,7 +2363,7 @@ var ImageEditor = ({
|
|
|
2253
2363
|
},
|
|
2254
2364
|
[controller, activeTab]
|
|
2255
2365
|
);
|
|
2256
|
-
(0,
|
|
2366
|
+
(0, import_react23.useEffect)(() => {
|
|
2257
2367
|
const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
|
|
2258
2368
|
const caf = typeof cancelAnimationFrame !== "undefined" ? cancelAnimationFrame : (id) => clearTimeout(id);
|
|
2259
2369
|
const animId = raf(() => {
|
|
@@ -2261,12 +2371,12 @@ var ImageEditor = ({
|
|
|
2261
2371
|
});
|
|
2262
2372
|
return () => caf(animId);
|
|
2263
2373
|
}, [renderCanvas, state]);
|
|
2264
|
-
(0,
|
|
2374
|
+
(0, import_react23.useEffect)(() => {
|
|
2265
2375
|
if (activeTab === "crop" && editor.state.activeTool !== "crop") {
|
|
2266
2376
|
editor.setTool("crop");
|
|
2267
2377
|
}
|
|
2268
2378
|
}, [activeTab, editor]);
|
|
2269
|
-
(0,
|
|
2379
|
+
(0, import_react23.useEffect)(() => {
|
|
2270
2380
|
const container = containerRef.current;
|
|
2271
2381
|
if (!container) return;
|
|
2272
2382
|
if (typeof ResizeObserver !== "undefined") {
|
|
@@ -3011,6 +3121,44 @@ var ImageEditor = ({
|
|
|
3011
3121
|
}
|
|
3012
3122
|
)
|
|
3013
3123
|
] }),
|
|
3124
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
|
|
3125
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
3126
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Tint" }),
|
|
3127
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "font-mono", children: state.adjustments.tint ?? 0 })
|
|
3128
|
+
] }),
|
|
3129
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3130
|
+
"input",
|
|
3131
|
+
{
|
|
3132
|
+
type: "range",
|
|
3133
|
+
min: "-100",
|
|
3134
|
+
max: "100",
|
|
3135
|
+
"aria-label": "Tint",
|
|
3136
|
+
disabled: legacyProcess,
|
|
3137
|
+
value: state.adjustments.tint ?? 0,
|
|
3138
|
+
onChange: (e) => editor.setAdjustments({ tint: Number(e.target.value) }),
|
|
3139
|
+
className: "w-full accent-indigo-500 disabled:opacity-40"
|
|
3140
|
+
}
|
|
3141
|
+
)
|
|
3142
|
+
] }),
|
|
3143
|
+
legacyProcess && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
3144
|
+
"div",
|
|
3145
|
+
{
|
|
3146
|
+
className: "flex items-center justify-between gap-2 rounded border border-amber-500/30 bg-amber-500/10 px-2 py-1.5 text-[10px] text-amber-200",
|
|
3147
|
+
"data-testid": "image-editor-process-notice",
|
|
3148
|
+
children: [
|
|
3149
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Legacy rendering (process 1). Tint needs the current process." }),
|
|
3150
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3151
|
+
"button",
|
|
3152
|
+
{
|
|
3153
|
+
type: "button",
|
|
3154
|
+
onClick: () => editor.upgradeProcess(),
|
|
3155
|
+
className: "shrink-0 rounded bg-amber-500/20 px-2 py-0.5 hover:bg-amber-500/30",
|
|
3156
|
+
children: "Update"
|
|
3157
|
+
}
|
|
3158
|
+
)
|
|
3159
|
+
]
|
|
3160
|
+
}
|
|
3161
|
+
),
|
|
3014
3162
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
|
|
3015
3163
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex justify-between text-slate-400 mb-1", children: [
|
|
3016
3164
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: "Blur" }),
|
|
@@ -3406,8 +3554,8 @@ var ImageEditor = ({
|
|
|
3406
3554
|
};
|
|
3407
3555
|
|
|
3408
3556
|
// src/review/useReview.ts
|
|
3409
|
-
var
|
|
3410
|
-
var
|
|
3557
|
+
var import_react24 = require("react");
|
|
3558
|
+
var import_editor10 = require("@pixerate/editor");
|
|
3411
3559
|
var EMPTY_COMMENTS = Object.freeze({
|
|
3412
3560
|
threads: [],
|
|
3413
3561
|
activeThreadId: null
|
|
@@ -3424,24 +3572,24 @@ function isCommentStore(value) {
|
|
|
3424
3572
|
return !!value && typeof value.getSnapshot === "function" && typeof value.createThread === "function";
|
|
3425
3573
|
}
|
|
3426
3574
|
function useComments(source) {
|
|
3427
|
-
const store = isCommentStore(source) ? source : (0,
|
|
3428
|
-
const subscribe = (0,
|
|
3575
|
+
const store = isCommentStore(source) ? source : (0, import_editor10.getCommentStore)(source);
|
|
3576
|
+
const subscribe = (0, import_react24.useCallback)(
|
|
3429
3577
|
(onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
|
|
3430
3578
|
[store]
|
|
3431
3579
|
);
|
|
3432
3580
|
const getSnapshot = () => store?.getSnapshot() ?? EMPTY_COMMENTS;
|
|
3433
|
-
const snapshot = (0,
|
|
3434
|
-
return (0,
|
|
3581
|
+
const snapshot = (0, import_react24.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
3582
|
+
return (0, import_react24.useMemo)(() => ({ ...snapshot, store }), [snapshot, store]);
|
|
3435
3583
|
}
|
|
3436
3584
|
function useTrackChanges(editor) {
|
|
3437
|
-
const store = (0,
|
|
3438
|
-
const subscribe = (0,
|
|
3585
|
+
const store = (0, import_editor10.getTrackChangesStore)(editor ?? null);
|
|
3586
|
+
const subscribe = (0, import_react24.useCallback)(
|
|
3439
3587
|
(onChange) => store ? store.subscribe(() => onChange()) : noopUnsubscribe,
|
|
3440
3588
|
[store]
|
|
3441
3589
|
);
|
|
3442
3590
|
const getSnapshot = () => store?.getSnapshot() ?? EMPTY_TRACK_CHANGES;
|
|
3443
|
-
const snapshot = (0,
|
|
3444
|
-
return (0,
|
|
3591
|
+
const snapshot = (0, import_react24.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
3592
|
+
return (0, import_react24.useMemo)(() => {
|
|
3445
3593
|
const run = (fn) => () => {
|
|
3446
3594
|
if (editor && !editor.isDestroyed) fn(editor);
|
|
3447
3595
|
};
|
|
@@ -3461,8 +3609,8 @@ function useTrackChanges(editor) {
|
|
|
3461
3609
|
}
|
|
3462
3610
|
|
|
3463
3611
|
// src/review/CommentsPanel.tsx
|
|
3464
|
-
var
|
|
3465
|
-
var
|
|
3612
|
+
var import_react25 = require("react");
|
|
3613
|
+
var import_editor11 = require("@pixerate/editor");
|
|
3466
3614
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
3467
3615
|
var buttonClass = "rounded px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50";
|
|
3468
3616
|
var primaryButtonClass = "rounded px-2 py-1 text-xs bg-primary/10 text-primary hover:bg-primary/20 disabled:opacity-50";
|
|
@@ -3473,12 +3621,12 @@ var CommentsPanel = ({
|
|
|
3473
3621
|
author: authorProp,
|
|
3474
3622
|
showResolved: showResolvedInitial = false,
|
|
3475
3623
|
className = "flex flex-col gap-2 text-sm text-foreground",
|
|
3476
|
-
formatTime = (t) => (0,
|
|
3624
|
+
formatTime = (t) => (0, import_editor11.formatReviewTime)(t),
|
|
3477
3625
|
emptyMessage = "No comments yet. Select text and add a comment."
|
|
3478
3626
|
}) => {
|
|
3479
3627
|
const { threads, activeThreadId, store } = useComments(storeProp ?? editor);
|
|
3480
|
-
const [showResolved, setShowResolved] = (0,
|
|
3481
|
-
const author = authorProp ?? (0,
|
|
3628
|
+
const [showResolved, setShowResolved] = (0, import_react25.useState)(showResolvedInitial);
|
|
3629
|
+
const author = authorProp ?? (0, import_editor11.getCommentAuthor)(editor) ?? { id: "anonymous", name: "Anonymous" };
|
|
3482
3630
|
const visible = threads.filter((t) => showResolved || !t.resolved);
|
|
3483
3631
|
const resolvedCount = threads.filter((t) => t.resolved).length;
|
|
3484
3632
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("aside", { className, "aria-label": "Comments", children: [
|
|
@@ -3521,7 +3669,7 @@ var CommentThreadCard = ({
|
|
|
3521
3669
|
author,
|
|
3522
3670
|
formatTime
|
|
3523
3671
|
}) => {
|
|
3524
|
-
const [draft, setDraft] = (0,
|
|
3672
|
+
const [draft, setDraft] = (0, import_react25.useState)("");
|
|
3525
3673
|
const isDraft = thread.body === "";
|
|
3526
3674
|
const quote = thread.anchor?.quote ?? thread.lastQuote ?? "";
|
|
3527
3675
|
const live = editor && !editor.isDestroyed ? editor : null;
|
|
@@ -3631,10 +3779,13 @@ var CommentThreadCard = ({
|
|
|
3631
3779
|
|
|
3632
3780
|
// src/review/ReviewToolbar.tsx
|
|
3633
3781
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
3782
|
+
var defaultDescriptionClass = "max-w-[16rem] truncate px-1 text-xs text-muted-foreground";
|
|
3634
3783
|
var buttonClass2 = "rounded px-2 py-1 text-xs text-foreground hover:bg-muted disabled:opacity-40 disabled:hover:bg-transparent";
|
|
3635
3784
|
var ReviewToolbar = ({
|
|
3636
3785
|
editor,
|
|
3637
|
-
className = "flex flex-wrap items-center gap-1 rounded-md border border-border bg-background p-1 text-sm"
|
|
3786
|
+
className = "flex flex-wrap items-center gap-1 rounded-md border border-border bg-background p-1 text-sm",
|
|
3787
|
+
showDescription = true,
|
|
3788
|
+
descriptionClassName = defaultDescriptionClass
|
|
3638
3789
|
}) => {
|
|
3639
3790
|
const review = useTrackChanges(editor);
|
|
3640
3791
|
const count = review.changes.length;
|
|
@@ -3676,6 +3827,18 @@ var ReviewToolbar = ({
|
|
|
3676
3827
|
children: "\u203A"
|
|
3677
3828
|
}
|
|
3678
3829
|
),
|
|
3830
|
+
showDescription && current && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
3831
|
+
"span",
|
|
3832
|
+
{
|
|
3833
|
+
className: descriptionClassName,
|
|
3834
|
+
"data-change-type": current.type,
|
|
3835
|
+
title: `${current.author.name}: ${current.description}`,
|
|
3836
|
+
children: [
|
|
3837
|
+
current.author.name ? `${current.author.name}: ` : "",
|
|
3838
|
+
current.description
|
|
3839
|
+
]
|
|
3840
|
+
}
|
|
3841
|
+
),
|
|
3679
3842
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
|
|
3680
3843
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3681
3844
|
"button",
|
|
@@ -3718,9 +3881,196 @@ var CommentButton = ({
|
|
|
3718
3881
|
children
|
|
3719
3882
|
}
|
|
3720
3883
|
);
|
|
3884
|
+
|
|
3885
|
+
// src/commands/useCommandPalette.ts
|
|
3886
|
+
var import_react26 = require("react");
|
|
3887
|
+
var import_commands2 = require("@pixerate/editor/commands");
|
|
3888
|
+
function useCommandPalette(registry, options = {}) {
|
|
3889
|
+
const optionsRef = (0, import_react26.useRef)(options);
|
|
3890
|
+
optionsRef.current = options;
|
|
3891
|
+
const controller = (0, import_react26.useMemo)(
|
|
3892
|
+
() => (0, import_commands2.createCommandPaletteController)(registry, {
|
|
3893
|
+
context: () => {
|
|
3894
|
+
const c = optionsRef.current.context;
|
|
3895
|
+
if (c === void 0) return registry.context;
|
|
3896
|
+
return typeof c === "function" ? c() : c;
|
|
3897
|
+
},
|
|
3898
|
+
scope: () => {
|
|
3899
|
+
const s = optionsRef.current.scope;
|
|
3900
|
+
return typeof s === "function" ? s() : s;
|
|
3901
|
+
},
|
|
3902
|
+
recents: options.recents,
|
|
3903
|
+
recentLimit: options.recentLimit,
|
|
3904
|
+
limit: options.limit,
|
|
3905
|
+
platform: options.platform,
|
|
3906
|
+
onRecentsChange: (recents) => optionsRef.current.onRecentsChange?.(recents),
|
|
3907
|
+
onRun: (result) => optionsRef.current.onRun?.(result)
|
|
3908
|
+
}),
|
|
3909
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3910
|
+
[registry]
|
|
3911
|
+
);
|
|
3912
|
+
const state = (0, import_react26.useSyncExternalStore)(controller.subscribe, controller.getState, controller.getState);
|
|
3913
|
+
const { hotkey, hotkeyTarget } = options;
|
|
3914
|
+
(0, import_react26.useEffect)(() => {
|
|
3915
|
+
if (!hotkey) return;
|
|
3916
|
+
const target = hotkeyTarget ?? (typeof window !== "undefined" ? window : null);
|
|
3917
|
+
if (!target) return;
|
|
3918
|
+
const onKeyDown = (event) => {
|
|
3919
|
+
const e = event;
|
|
3920
|
+
if (e.defaultPrevented || !(0, import_commands2.matchPaletteHotkey)(e, hotkey, optionsRef.current.platform)) return;
|
|
3921
|
+
e.preventDefault();
|
|
3922
|
+
controller.toggle();
|
|
3923
|
+
};
|
|
3924
|
+
target.addEventListener("keydown", onKeyDown);
|
|
3925
|
+
return () => target.removeEventListener("keydown", onKeyDown);
|
|
3926
|
+
}, [controller, hotkey, hotkeyTarget]);
|
|
3927
|
+
return {
|
|
3928
|
+
...state,
|
|
3929
|
+
controller,
|
|
3930
|
+
setOpen: controller.setOpen,
|
|
3931
|
+
toggle: controller.toggle,
|
|
3932
|
+
setQuery: controller.setQuery,
|
|
3933
|
+
setActiveIndex: controller.setActiveIndex,
|
|
3934
|
+
move: controller.move,
|
|
3935
|
+
run: controller.run,
|
|
3936
|
+
runActive: controller.runActive,
|
|
3937
|
+
handleKeyDown: controller.handleKeyDown
|
|
3938
|
+
};
|
|
3939
|
+
}
|
|
3940
|
+
|
|
3941
|
+
// src/commands/CommandPalette.tsx
|
|
3942
|
+
var import_react27 = __toESM(require("react"), 1);
|
|
3943
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
3944
|
+
function HighlightedLabel({ item }) {
|
|
3945
|
+
if (item.labelIndices.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: item.label });
|
|
3946
|
+
const marked = new Set(item.labelIndices);
|
|
3947
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: Array.from(item.label).map(
|
|
3948
|
+
(ch, i) => marked.has(i) ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-semibold text-foreground", "data-match": "", children: ch }, i) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react27.default.Fragment, { children: ch }, i)
|
|
3949
|
+
) });
|
|
3950
|
+
}
|
|
3951
|
+
var CommandPalette = ({
|
|
3952
|
+
palette,
|
|
3953
|
+
placeholder = "Type a command\u2026",
|
|
3954
|
+
emptyMessage = "No matching commands",
|
|
3955
|
+
className = ""
|
|
3956
|
+
}) => {
|
|
3957
|
+
const inputRef = (0, import_react27.useRef)(null);
|
|
3958
|
+
const listRef = (0, import_react27.useRef)(null);
|
|
3959
|
+
const baseId = (0, import_react27.useId)();
|
|
3960
|
+
const listId = `${baseId}-list`;
|
|
3961
|
+
const optionId = (index) => `${baseId}-option-${index}`;
|
|
3962
|
+
const { open, query, items, activeIndex } = palette;
|
|
3963
|
+
(0, import_react27.useEffect)(() => {
|
|
3964
|
+
if (open) inputRef.current?.focus();
|
|
3965
|
+
}, [open]);
|
|
3966
|
+
(0, import_react27.useEffect)(() => {
|
|
3967
|
+
if (!open) return;
|
|
3968
|
+
const active = listRef.current?.querySelector('[aria-selected="true"]');
|
|
3969
|
+
active?.scrollIntoView?.({ block: "nearest" });
|
|
3970
|
+
}, [open, activeIndex]);
|
|
3971
|
+
if (!open) return null;
|
|
3972
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3973
|
+
"div",
|
|
3974
|
+
{
|
|
3975
|
+
className: "fixed inset-0 z-50 flex items-start justify-center bg-black/30 px-4 pt-[15vh]",
|
|
3976
|
+
"data-command-palette-backdrop": "",
|
|
3977
|
+
onMouseDown: (e) => {
|
|
3978
|
+
if (e.target === e.currentTarget) palette.setOpen(false);
|
|
3979
|
+
},
|
|
3980
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
3981
|
+
"div",
|
|
3982
|
+
{
|
|
3983
|
+
role: "dialog",
|
|
3984
|
+
"aria-modal": "true",
|
|
3985
|
+
"aria-label": "Command palette",
|
|
3986
|
+
className: `w-full max-w-lg overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-xl ${className}`,
|
|
3987
|
+
style: { background: "var(--popover, var(--background, #fff))" },
|
|
3988
|
+
children: [
|
|
3989
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3990
|
+
"input",
|
|
3991
|
+
{
|
|
3992
|
+
ref: inputRef,
|
|
3993
|
+
type: "text",
|
|
3994
|
+
role: "combobox",
|
|
3995
|
+
"aria-expanded": "true",
|
|
3996
|
+
"aria-controls": listId,
|
|
3997
|
+
"aria-autocomplete": "list",
|
|
3998
|
+
"aria-activedescendant": items.length ? optionId(activeIndex) : void 0,
|
|
3999
|
+
"aria-label": "Search commands",
|
|
4000
|
+
placeholder,
|
|
4001
|
+
value: query,
|
|
4002
|
+
onChange: (e) => palette.setQuery(e.target.value),
|
|
4003
|
+
onKeyDown: (e) => {
|
|
4004
|
+
if (palette.handleKeyDown(e.nativeEvent)) e.stopPropagation();
|
|
4005
|
+
},
|
|
4006
|
+
className: "w-full border-b border-border bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground"
|
|
4007
|
+
}
|
|
4008
|
+
),
|
|
4009
|
+
items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("ul", { ref: listRef, id: listId, role: "listbox", "aria-label": "Commands", className: "max-h-80 overflow-y-auto py-1", children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
4010
|
+
"li",
|
|
4011
|
+
{
|
|
4012
|
+
id: optionId(index),
|
|
4013
|
+
role: "option",
|
|
4014
|
+
"aria-selected": index === activeIndex,
|
|
4015
|
+
"aria-disabled": !item.enabled || void 0,
|
|
4016
|
+
"data-command-id": item.id,
|
|
4017
|
+
"data-recent": item.recent ? "" : void 0,
|
|
4018
|
+
title: item.disabledReason,
|
|
4019
|
+
onMouseMove: () => index !== activeIndex && palette.setActiveIndex(index),
|
|
4020
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4021
|
+
onClick: () => palette.run(item.id),
|
|
4022
|
+
className: `flex cursor-pointer items-center gap-2 px-3 py-1.5 text-sm ${index === activeIndex ? "bg-muted" : ""} ${item.enabled ? "" : "cursor-default opacity-50"}`,
|
|
4023
|
+
children: [
|
|
4024
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "min-w-0 flex-1 truncate", children: [
|
|
4025
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(HighlightedLabel, { item }),
|
|
4026
|
+
item.disabledReason && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ml-2 text-xs text-muted-foreground", "data-disabled-reason": "", children: item.disabledReason })
|
|
4027
|
+
] }),
|
|
4028
|
+
item.group && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.group }),
|
|
4029
|
+
item.shortcut && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("kbd", { className: "shrink-0 rounded border border-border px-1.5 font-mono text-[10px] text-muted-foreground", children: item.shortcut })
|
|
4030
|
+
]
|
|
4031
|
+
},
|
|
4032
|
+
item.id
|
|
4033
|
+
)) })
|
|
4034
|
+
]
|
|
4035
|
+
}
|
|
4036
|
+
)
|
|
4037
|
+
}
|
|
4038
|
+
);
|
|
4039
|
+
};
|
|
4040
|
+
|
|
4041
|
+
// src/commands/useCommandShortcuts.ts
|
|
4042
|
+
var import_react28 = require("react");
|
|
4043
|
+
function useCommandShortcuts(registry, options = {}) {
|
|
4044
|
+
const optionsRef = (0, import_react28.useRef)(options);
|
|
4045
|
+
optionsRef.current = options;
|
|
4046
|
+
const { enabled = true, target } = options;
|
|
4047
|
+
(0, import_react28.useEffect)(() => {
|
|
4048
|
+
if (!registry || !enabled) return;
|
|
4049
|
+
const eventTarget = target ?? (typeof window !== "undefined" ? window : null);
|
|
4050
|
+
if (!eventTarget) return;
|
|
4051
|
+
const onKeyDown = (event) => {
|
|
4052
|
+
const { scopes, context, allowInEditable, onRun } = optionsRef.current;
|
|
4053
|
+
const result = registry.handleKeyDown(event, {
|
|
4054
|
+
scopes,
|
|
4055
|
+
...allowInEditable !== void 0 ? { allowInEditable } : {},
|
|
4056
|
+
...context !== void 0 ? { context } : {}
|
|
4057
|
+
});
|
|
4058
|
+
if (result) onRun?.(result);
|
|
4059
|
+
};
|
|
4060
|
+
eventTarget.addEventListener("keydown", onKeyDown);
|
|
4061
|
+
return () => eventTarget.removeEventListener("keydown", onKeyDown);
|
|
4062
|
+
}, [registry, enabled, target]);
|
|
4063
|
+
}
|
|
4064
|
+
function useRegisterCommands(registry, specs) {
|
|
4065
|
+
(0, import_react28.useEffect)(() => {
|
|
4066
|
+
if (!registry || !specs || specs.length === 0) return;
|
|
4067
|
+
return registry.register(specs);
|
|
4068
|
+
}, [registry, specs]);
|
|
4069
|
+
}
|
|
3721
4070
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3722
4071
|
0 && (module.exports = {
|
|
3723
4072
|
BubbleMenu,
|
|
4073
|
+
CommandPalette,
|
|
3724
4074
|
CommentButton,
|
|
3725
4075
|
CommentsPanel,
|
|
3726
4076
|
DirtyTracker,
|
|
@@ -3736,10 +4086,13 @@ var CommentButton = ({
|
|
|
3736
4086
|
SpreadsheetGroupRow,
|
|
3737
4087
|
TemplateRenderer,
|
|
3738
4088
|
VariableForm,
|
|
4089
|
+
bindDirtyToHistory,
|
|
3739
4090
|
createDirtyTracker,
|
|
3740
4091
|
createHistoryManager,
|
|
3741
4092
|
defaultIsEqual,
|
|
3742
4093
|
useAgentToolProvider,
|
|
4094
|
+
useCommandPalette,
|
|
4095
|
+
useCommandShortcuts,
|
|
3743
4096
|
useComments,
|
|
3744
4097
|
useDismissGuard,
|
|
3745
4098
|
useEditor,
|
|
@@ -3747,13 +4100,16 @@ var CommentButton = ({
|
|
|
3747
4100
|
useFileImport,
|
|
3748
4101
|
useFillHandle,
|
|
3749
4102
|
useHistory,
|
|
4103
|
+
useHistoryDirty,
|
|
3750
4104
|
useHistoryShortcuts,
|
|
3751
4105
|
useImageEditor,
|
|
3752
4106
|
useNavigationGuard,
|
|
3753
4107
|
useOutline,
|
|
3754
4108
|
usePromptEditor,
|
|
4109
|
+
useRegisterCommands,
|
|
3755
4110
|
useSpreadsheetClipboard,
|
|
3756
4111
|
useSpreadsheetEditor,
|
|
3757
|
-
useTrackChanges
|
|
4112
|
+
useTrackChanges,
|
|
4113
|
+
withoutDirty
|
|
3758
4114
|
});
|
|
3759
4115
|
//# sourceMappingURL=index.cjs.map
|