@rowsncolumns/spreadsheet 10.2.72 → 10.2.74

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.
Files changed (132) hide show
  1. package/dist/cjs/api/evaluate-formula.d.ts +17 -0
  2. package/dist/cjs/api/evaluate-formula.d.ts.map +1 -0
  3. package/dist/cjs/api/evaluate-formula.js +141 -0
  4. package/dist/cjs/api/go-to.d.ts +19 -0
  5. package/dist/cjs/api/go-to.d.ts.map +1 -0
  6. package/dist/cjs/api/go-to.js +49 -0
  7. package/dist/cjs/atoms/evaluate-formula-dialog.atom.d.ts +36 -0
  8. package/dist/cjs/atoms/evaluate-formula-dialog.atom.d.ts.map +1 -0
  9. package/dist/cjs/atoms/evaluate-formula-dialog.atom.js +36 -0
  10. package/dist/cjs/atoms/go-to-dialog.atom.d.ts +36 -0
  11. package/dist/cjs/atoms/go-to-dialog.atom.d.ts.map +1 -0
  12. package/dist/cjs/atoms/go-to-dialog.atom.js +34 -0
  13. package/dist/cjs/atoms/index.d.ts +4 -0
  14. package/dist/cjs/atoms/index.d.ts.map +1 -1
  15. package/dist/cjs/atoms/index.js +4 -0
  16. package/dist/cjs/atoms/paste-special-dialog.atom.d.ts +29 -0
  17. package/dist/cjs/atoms/paste-special-dialog.atom.d.ts.map +1 -0
  18. package/dist/cjs/atoms/paste-special-dialog.atom.js +34 -0
  19. package/dist/cjs/atoms/remove-duplicates-dialog.atom.d.ts +45 -0
  20. package/dist/cjs/atoms/remove-duplicates-dialog.atom.d.ts.map +1 -0
  21. package/dist/cjs/atoms/remove-duplicates-dialog.atom.js +37 -0
  22. package/dist/cjs/components/canvas-grid/index.d.ts.map +1 -1
  23. package/dist/cjs/components/canvas-grid/index.js +109 -3
  24. package/dist/cjs/components/canvas-grid/typings.d.ts +54 -8
  25. package/dist/cjs/components/canvas-grid/typings.d.ts.map +1 -1
  26. package/dist/cjs/components/context-menu/index.d.ts +16 -3
  27. package/dist/cjs/components/context-menu/index.d.ts.map +1 -1
  28. package/dist/cjs/components/context-menu/index.js +112 -5
  29. package/dist/cjs/components/context-menu/total-row-functions.d.ts +32 -0
  30. package/dist/cjs/components/context-menu/total-row-functions.d.ts.map +1 -0
  31. package/dist/cjs/components/context-menu/total-row-functions.js +62 -0
  32. package/dist/cjs/components/evaluate-formula-dialog/index.d.ts +34 -0
  33. package/dist/cjs/components/evaluate-formula-dialog/index.d.ts.map +1 -0
  34. package/dist/cjs/components/evaluate-formula-dialog/index.js +106 -0
  35. package/dist/cjs/components/go-to-dialog/index.d.ts +35 -0
  36. package/dist/cjs/components/go-to-dialog/index.d.ts.map +1 -0
  37. package/dist/cjs/components/go-to-dialog/index.js +93 -0
  38. package/dist/cjs/components/paste-special-dialog/index.d.ts +29 -0
  39. package/dist/cjs/components/paste-special-dialog/index.d.ts.map +1 -0
  40. package/dist/cjs/components/paste-special-dialog/index.js +99 -0
  41. package/dist/cjs/components/remove-duplicates-dialog/index.d.ts +37 -0
  42. package/dist/cjs/components/remove-duplicates-dialog/index.d.ts.map +1 -0
  43. package/dist/cjs/components/remove-duplicates-dialog/index.js +91 -0
  44. package/dist/cjs/components/toolbar/index.d.ts +1 -0
  45. package/dist/cjs/components/toolbar/index.d.ts.map +1 -1
  46. package/dist/cjs/components/toolbar/index.js +1 -0
  47. package/dist/cjs/components/toolbar/text-rotation-selector.d.ts +29 -0
  48. package/dist/cjs/components/toolbar/text-rotation-selector.d.ts.map +1 -0
  49. package/dist/cjs/components/toolbar/text-rotation-selector.js +78 -0
  50. package/dist/cjs/components/toolbar/text-wrap-selector.d.ts +7 -1
  51. package/dist/cjs/components/toolbar/text-wrap-selector.d.ts.map +1 -1
  52. package/dist/cjs/components/toolbar/text-wrap-selector.js +10 -3
  53. package/dist/cjs/hooks/use-copy-paste-cut.d.ts +20 -1
  54. package/dist/cjs/hooks/use-copy-paste-cut.d.ts.map +1 -1
  55. package/dist/cjs/hooks/use-copy-paste-cut.js +27 -21
  56. package/dist/cjs/hooks/use-keyboard-handler.d.ts +17 -2
  57. package/dist/cjs/hooks/use-keyboard-handler.d.ts.map +1 -1
  58. package/dist/cjs/hooks/use-keyboard-handler.js +186 -21
  59. package/dist/cjs/index.d.ts +6 -1
  60. package/dist/cjs/index.d.ts.map +1 -1
  61. package/dist/cjs/index.js +7 -1
  62. package/dist/cjs/release-date.js +1 -1
  63. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  64. package/dist/cjs/types.d.ts +173 -1
  65. package/dist/cjs/types.d.ts.map +1 -1
  66. package/dist/esm/api/evaluate-formula.d.ts +17 -0
  67. package/dist/esm/api/evaluate-formula.d.ts.map +1 -0
  68. package/dist/esm/api/evaluate-formula.js +109 -0
  69. package/dist/esm/api/go-to.d.ts +19 -0
  70. package/dist/esm/api/go-to.d.ts.map +1 -0
  71. package/dist/esm/api/go-to.js +41 -0
  72. package/dist/esm/atoms/evaluate-formula-dialog.atom.d.ts +36 -0
  73. package/dist/esm/atoms/evaluate-formula-dialog.atom.d.ts.map +1 -0
  74. package/dist/esm/atoms/evaluate-formula-dialog.atom.js +25 -0
  75. package/dist/esm/atoms/go-to-dialog.atom.d.ts +36 -0
  76. package/dist/esm/atoms/go-to-dialog.atom.d.ts.map +1 -0
  77. package/dist/esm/atoms/go-to-dialog.atom.js +25 -0
  78. package/dist/esm/atoms/index.d.ts +4 -0
  79. package/dist/esm/atoms/index.d.ts.map +1 -1
  80. package/dist/esm/atoms/index.js +4 -0
  81. package/dist/esm/atoms/paste-special-dialog.atom.d.ts +29 -0
  82. package/dist/esm/atoms/paste-special-dialog.atom.d.ts.map +1 -0
  83. package/dist/esm/atoms/paste-special-dialog.atom.js +25 -0
  84. package/dist/esm/atoms/remove-duplicates-dialog.atom.d.ts +45 -0
  85. package/dist/esm/atoms/remove-duplicates-dialog.atom.d.ts.map +1 -0
  86. package/dist/esm/atoms/remove-duplicates-dialog.atom.js +26 -0
  87. package/dist/esm/components/canvas-grid/index.d.ts.map +1 -1
  88. package/dist/esm/components/canvas-grid/index.js +107 -3
  89. package/dist/esm/components/canvas-grid/typings.d.ts +54 -8
  90. package/dist/esm/components/canvas-grid/typings.d.ts.map +1 -1
  91. package/dist/esm/components/context-menu/index.d.ts +16 -3
  92. package/dist/esm/components/context-menu/index.d.ts.map +1 -1
  93. package/dist/esm/components/context-menu/index.js +114 -7
  94. package/dist/esm/components/context-menu/total-row-functions.d.ts +32 -0
  95. package/dist/esm/components/context-menu/total-row-functions.d.ts.map +1 -0
  96. package/dist/esm/components/context-menu/total-row-functions.js +50 -0
  97. package/dist/esm/components/evaluate-formula-dialog/index.d.ts +34 -0
  98. package/dist/esm/components/evaluate-formula-dialog/index.d.ts.map +1 -0
  99. package/dist/esm/components/evaluate-formula-dialog/index.js +86 -0
  100. package/dist/esm/components/go-to-dialog/index.d.ts +35 -0
  101. package/dist/esm/components/go-to-dialog/index.d.ts.map +1 -0
  102. package/dist/esm/components/go-to-dialog/index.js +84 -0
  103. package/dist/esm/components/paste-special-dialog/index.d.ts +29 -0
  104. package/dist/esm/components/paste-special-dialog/index.d.ts.map +1 -0
  105. package/dist/esm/components/paste-special-dialog/index.js +90 -0
  106. package/dist/esm/components/remove-duplicates-dialog/index.d.ts +37 -0
  107. package/dist/esm/components/remove-duplicates-dialog/index.d.ts.map +1 -0
  108. package/dist/esm/components/remove-duplicates-dialog/index.js +82 -0
  109. package/dist/esm/components/toolbar/index.d.ts +1 -0
  110. package/dist/esm/components/toolbar/index.d.ts.map +1 -1
  111. package/dist/esm/components/toolbar/index.js +1 -0
  112. package/dist/esm/components/toolbar/text-rotation-selector.d.ts +29 -0
  113. package/dist/esm/components/toolbar/text-rotation-selector.d.ts.map +1 -0
  114. package/dist/esm/components/toolbar/text-rotation-selector.js +71 -0
  115. package/dist/esm/components/toolbar/text-wrap-selector.d.ts +7 -1
  116. package/dist/esm/components/toolbar/text-wrap-selector.d.ts.map +1 -1
  117. package/dist/esm/components/toolbar/text-wrap-selector.js +10 -3
  118. package/dist/esm/hooks/use-copy-paste-cut.d.ts +20 -1
  119. package/dist/esm/hooks/use-copy-paste-cut.d.ts.map +1 -1
  120. package/dist/esm/hooks/use-copy-paste-cut.js +10 -4
  121. package/dist/esm/hooks/use-keyboard-handler.d.ts +17 -2
  122. package/dist/esm/hooks/use-keyboard-handler.d.ts.map +1 -1
  123. package/dist/esm/hooks/use-keyboard-handler.js +173 -21
  124. package/dist/esm/index.d.ts +6 -1
  125. package/dist/esm/index.d.ts.map +1 -1
  126. package/dist/esm/index.js +5 -0
  127. package/dist/esm/release-date.js +1 -1
  128. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  129. package/dist/esm/types.d.ts +173 -1
  130. package/dist/esm/types.d.ts.map +1 -1
  131. package/dist/spreadsheet.min.css +1 -1
  132. package/package.json +6 -6
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PasteSpecialDialogHost = exports.PasteSpecialDialog = void 0;
4
+ var tslib_1 = require("tslib");
5
+ var ui_1 = require("@rowsncolumns/ui");
6
+ var react_1 = tslib_1.__importStar(require("react"));
7
+ var paste_special_dialog_atom_1 = require("../../atoms/paste-special-dialog.atom");
8
+ var PASTE_MODES = [
9
+ { value: "all", label: "All" },
10
+ { value: "formulas", label: "Formulas" },
11
+ { value: "values", label: "Values" },
12
+ { value: "formats", label: "Formats" },
13
+ ];
14
+ var OPERATIONS = [
15
+ { value: "none", label: "None" },
16
+ { value: "add", label: "Add" },
17
+ { value: "subtract", label: "Subtract" },
18
+ { value: "multiply", label: "Multiply" },
19
+ { value: "divide", label: "Divide" },
20
+ ];
21
+ var RadioGroup = function (_a) {
22
+ var name = _a.name, legend = _a.legend, value = _a.value, options = _a.options, onChange = _a.onChange, disabled = _a.disabled;
23
+ return (react_1.default.createElement("fieldset", { className: "flex flex-col gap-1 min-w-0 disabled:opacity-50", disabled: disabled },
24
+ react_1.default.createElement("legend", { className: "text-xs font-medium mb-1" }, legend),
25
+ options.map(function (option) { return (react_1.default.createElement("label", { key: option.value, className: "flex items-center gap-2 text-xs py-0.5 cursor-pointer" },
26
+ react_1.default.createElement("input", { type: "radio", name: name, value: option.value, checked: value === option.value, disabled: disabled, onChange: function () { return onChange(option.value); } }),
27
+ option.label)); })));
28
+ };
29
+ /**
30
+ * Excel's Paste Special dialog: what to paste (all / formulas / values /
31
+ * formats), an arithmetic operation against the destination, skip blanks and
32
+ * transpose. Every choice composes into one `PasteSpecialOptions` request.
33
+ */
34
+ exports.PasteSpecialDialog = (0, react_1.memo)(function (_a) {
35
+ var open = _a.open, onOpenChange = _a.onOpenChange, onApply = _a.onApply;
36
+ var _b = tslib_1.__read((0, react_1.useState)("all"), 2), paste = _b[0], setPaste = _b[1];
37
+ var _c = tslib_1.__read((0, react_1.useState)("none"), 2), operation = _c[0], setOperation = _c[1];
38
+ var _d = tslib_1.__read((0, react_1.useState)(false), 2), skipBlanks = _d[0], setSkipBlanks = _d[1];
39
+ var _e = tslib_1.__read((0, react_1.useState)(false), 2), transpose = _e[0], setTranspose = _e[1];
40
+ // Excel greys Operation out under Paste → Formats (a formats paste never
41
+ // changes destination values); the choice is kept but not applied.
42
+ var operationDisabled = paste === "formats";
43
+ var commit = (0, react_1.useCallback)(function () {
44
+ onApply({
45
+ paste: paste,
46
+ operation: operation === "none" || operationDisabled ? undefined : operation,
47
+ skipBlanks: skipBlanks,
48
+ transpose: transpose,
49
+ });
50
+ onOpenChange(false);
51
+ }, [
52
+ onApply,
53
+ onOpenChange,
54
+ paste,
55
+ operation,
56
+ operationDisabled,
57
+ skipBlanks,
58
+ transpose,
59
+ ]);
60
+ return (react_1.default.createElement(ui_1.Dialog, { open: open, onOpenChange: onOpenChange, modal: true },
61
+ react_1.default.createElement(ui_1.DialogContent, { className: "w-[380px] max-w-[92vw] pointer-events-auto" },
62
+ react_1.default.createElement(ui_1.DialogTitle, null, "Paste Special"),
63
+ react_1.default.createElement(ui_1.DialogCloseButton, null),
64
+ react_1.default.createElement(ui_1.DialogBody, { className: "flex flex-col gap-4" },
65
+ react_1.default.createElement("div", { className: "grid grid-cols-2 gap-4" },
66
+ react_1.default.createElement(RadioGroup, { name: "paste-special-paste", legend: "Paste", value: paste, options: PASTE_MODES, onChange: setPaste }),
67
+ react_1.default.createElement(RadioGroup, { name: "paste-special-operation", legend: "Operation", value: operation, options: OPERATIONS, onChange: setOperation, disabled: operationDisabled })),
68
+ react_1.default.createElement("div", { className: "flex flex-col gap-1" },
69
+ react_1.default.createElement("label", { className: "flex items-center gap-2 text-xs py-0.5 cursor-pointer" },
70
+ react_1.default.createElement("input", { type: "checkbox", checked: skipBlanks, onChange: function (e) { return setSkipBlanks(e.target.checked); } }),
71
+ "Skip blanks"),
72
+ react_1.default.createElement("label", { className: "flex items-center gap-2 text-xs py-0.5 cursor-pointer" },
73
+ react_1.default.createElement("input", { type: "checkbox", checked: transpose, onChange: function (e) { return setTranspose(e.target.checked); } }),
74
+ "Transpose")),
75
+ react_1.default.createElement(ui_1.Separator, null),
76
+ react_1.default.createElement("div", { className: "flex justify-end gap-2" },
77
+ react_1.default.createElement(ui_1.Button, { variant: "outline", size: "sm", onClick: function () { return onOpenChange(false); } }, "Cancel"),
78
+ react_1.default.createElement(ui_1.Button, { size: "sm", onClick: commit }, "OK"))))));
79
+ });
80
+ exports.PasteSpecialDialog.displayName = "PasteSpecialDialog";
81
+ /**
82
+ * Host-mounted, atom-driven wrapper around {@link PasteSpecialDialog}. Mount
83
+ * it once in the host alongside the other editor dialogs; the grid opens it
84
+ * from the context menu ("Paste special…") and `Ctrl+Alt+V`. Remounted per
85
+ * request so each opening starts from Excel's defaults.
86
+ */
87
+ var PasteSpecialDialogHost = function () {
88
+ (0, paste_special_dialog_atom_1.useRegisterPasteSpecialDialogHost)();
89
+ var _a = tslib_1.__read((0, paste_special_dialog_atom_1.usePasteSpecialDialogState)(), 2), request = _a[0], setRequest = _a[1];
90
+ var close = (0, react_1.useCallback)(function () { return setRequest(null); }, [setRequest]);
91
+ if (!request)
92
+ return null;
93
+ return (react_1.default.createElement(exports.PasteSpecialDialog, { open: true, onOpenChange: function (open) {
94
+ if (!open)
95
+ close();
96
+ }, onApply: request.onApply }));
97
+ };
98
+ exports.PasteSpecialDialogHost = PasteSpecialDialogHost;
99
+ exports.PasteSpecialDialogHost.displayName = "PasteSpecialDialogHost";
@@ -0,0 +1,37 @@
1
+ import React from "react";
2
+ import { type RemoveDuplicatesDialogColumn } from "../../atoms/remove-duplicates-dialog.atom";
3
+ import type { RemoveDuplicatesOptions } from "../../types";
4
+ export type { RemoveDuplicatesDialogColumn };
5
+ export type RemoveDuplicatesDialogProps = {
6
+ /** Controls visibility. */
7
+ open: boolean;
8
+ onOpenChange(open: boolean): void;
9
+ /** Columns of the range, in sheet order. All start checked. */
10
+ columns: RemoveDuplicatesDialogColumn[];
11
+ /** Initial state of "My data has headers". */
12
+ initialHasHeader?: boolean;
13
+ /**
14
+ * Emits the chosen compare columns and header flag. The host routes these
15
+ * to `onRemoveDuplicates`; the dialog never touches state directly.
16
+ */
17
+ onApply(options: RemoveDuplicatesOptions): void;
18
+ };
19
+ /**
20
+ * Excel's "Remove Duplicates" dialog: a "My data has headers" toggle plus a
21
+ * checklist of the columns that decide whether two rows are duplicates.
22
+ * Unchecked columns still travel with their row — only the comparison
23
+ * narrows.
24
+ */
25
+ export declare const RemoveDuplicatesDialog: React.MemoExoticComponent<({ open, onOpenChange, columns, initialHasHeader, onApply, }: RemoveDuplicatesDialogProps) => React.JSX.Element>;
26
+ /**
27
+ * Host-mounted, atom-driven wrapper around {@link RemoveDuplicatesDialog}.
28
+ * Mount this once in the host (alongside the other editor dialogs); the
29
+ * context menu opens it via `useOpenRemoveDuplicatesDialog`. While no host is
30
+ * mounted the context menu keeps its one-click de-dupe, so adopting the
31
+ * dialog is opt-in per host.
32
+ */
33
+ export declare const RemoveDuplicatesDialogHost: {
34
+ (): React.JSX.Element;
35
+ displayName: string;
36
+ };
37
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/remove-duplicates-dialog/index.tsx"],"names":[],"mappings":"AAWA,OAAO,KAA0D,MAAM,OAAO,CAAC;AAE/E,OAAO,EACL,KAAK,4BAA4B,EAGlC,MAAM,2CAA2C,CAAC;AACnD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,YAAY,EAAE,4BAA4B,EAAE,CAAC;AAE7C,MAAM,MAAM,2BAA2B,GAAG;IACxC,2BAA2B;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,+DAA+D;IAC/D,OAAO,EAAE,4BAA4B,EAAE,CAAC;IACxC,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,OAAO,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI,CAAC;CACjD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,0FAO9B,2BAA2B,uBAqI/B,CAAC;AAIF;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B;;;CAetC,CAAC"}
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RemoveDuplicatesDialogHost = exports.RemoveDuplicatesDialog = void 0;
4
+ var tslib_1 = require("tslib");
5
+ var icons_1 = require("@rowsncolumns/icons");
6
+ var ui_1 = require("@rowsncolumns/ui");
7
+ var react_1 = tslib_1.__importStar(require("react"));
8
+ var remove_duplicates_dialog_atom_1 = require("../../atoms/remove-duplicates-dialog.atom");
9
+ /**
10
+ * Excel's "Remove Duplicates" dialog: a "My data has headers" toggle plus a
11
+ * checklist of the columns that decide whether two rows are duplicates.
12
+ * Unchecked columns still travel with their row — only the comparison
13
+ * narrows.
14
+ */
15
+ exports.RemoveDuplicatesDialog = (0, react_1.memo)(function (_a) {
16
+ var open = _a.open, onOpenChange = _a.onOpenChange, columns = _a.columns, _b = _a.initialHasHeader, initialHasHeader = _b === void 0 ? false : _b, onApply = _a.onApply;
17
+ var allColumnIndexes = (0, react_1.useMemo)(function () { return columns.map(function (column) { return column.columnIndex; }); }, [columns]);
18
+ var _c = tslib_1.__read((0, react_1.useState)(initialHasHeader), 2), hasHeader = _c[0], setHasHeader = _c[1];
19
+ var _d = tslib_1.__read((0, react_1.useState)(function () { return new Set(allColumnIndexes); }), 2), checked = _d[0], setChecked = _d[1];
20
+ // Re-seed when reopened for a different range.
21
+ (0, react_1.useEffect)(function () {
22
+ if (open) {
23
+ setHasHeader(initialHasHeader);
24
+ setChecked(new Set(allColumnIndexes));
25
+ }
26
+ // Only reset on open transitions.
27
+ // eslint-disable-next-line react-hooks/exhaustive-deps
28
+ }, [open]);
29
+ var toggleColumn = (0, react_1.useCallback)(function (columnIndex) {
30
+ setChecked(function (prev) {
31
+ var next = new Set(prev);
32
+ if (next.has(columnIndex)) {
33
+ next.delete(columnIndex);
34
+ }
35
+ else {
36
+ next.add(columnIndex);
37
+ }
38
+ return next;
39
+ });
40
+ }, []);
41
+ var commit = (0, react_1.useCallback)(function () {
42
+ var columnIndices = allColumnIndexes.filter(function (columnIndex) {
43
+ return checked.has(columnIndex);
44
+ });
45
+ onApply({ columnIndices: columnIndices, hasHeader: hasHeader });
46
+ onOpenChange(false);
47
+ }, [allColumnIndexes, checked, hasHeader, onApply, onOpenChange]);
48
+ return (react_1.default.createElement(ui_1.Dialog, { open: open, onOpenChange: onOpenChange },
49
+ react_1.default.createElement(ui_1.DialogContent, { className: "w-[420px] max-w-[92vw] pointer-events-auto" },
50
+ react_1.default.createElement(ui_1.DialogTitle, null, "Remove duplicates"),
51
+ react_1.default.createElement(ui_1.DialogDescription, null, "Select the columns that contain duplicate values. Rows that match in every selected column are removed, keeping the first one."),
52
+ react_1.default.createElement(ui_1.DialogCloseButton, { onClick: function () { return onOpenChange(false); } },
53
+ react_1.default.createElement(icons_1.Cross1Icon, null)),
54
+ react_1.default.createElement(ui_1.DialogBody, { className: "flex flex-col gap-3" },
55
+ react_1.default.createElement("label", { className: "font-system text-sm flex items-center gap-1" },
56
+ react_1.default.createElement("input", { type: "checkbox", name: "hasHeader", checked: hasHeader, onChange: function (e) { return setHasHeader(e.target.checked); } }),
57
+ "My data has headers"),
58
+ react_1.default.createElement("div", { className: "flex gap-2" },
59
+ react_1.default.createElement(ui_1.Button, { variant: "outline", size: "xs", type: "button", onClick: function () { return setChecked(new Set(allColumnIndexes)); } }, "Select all"),
60
+ react_1.default.createElement(ui_1.Button, { variant: "outline", size: "xs", type: "button", onClick: function () { return setChecked(new Set()); } }, "Unselect all")),
61
+ react_1.default.createElement("div", { className: "flex flex-col gap-1 max-h-[240px] overflow-y-auto border border-rnc-border rounded p-2", role: "group", "aria-label": "Columns" }, columns.map(function (column) {
62
+ var text = hasHeader && column.header ? column.header : column.label;
63
+ return (react_1.default.createElement("label", { key: column.columnIndex, className: "font-system text-sm flex items-center gap-1" },
64
+ react_1.default.createElement("input", { type: "checkbox", name: "column-".concat(column.columnIndex), checked: checked.has(column.columnIndex), onChange: function () { return toggleColumn(column.columnIndex); } }),
65
+ react_1.default.createElement("span", { className: "truncate", title: text }, text)));
66
+ })),
67
+ react_1.default.createElement(ui_1.Separator, null),
68
+ react_1.default.createElement("div", { className: "flex justify-end gap-2" },
69
+ react_1.default.createElement(ui_1.Button, { variant: "outline", size: "sm", type: "button", onClick: function () { return onOpenChange(false); } }, "Cancel"),
70
+ react_1.default.createElement(ui_1.Button, { size: "sm", type: "button", onClick: commit, disabled: checked.size === 0 }, "OK"))))));
71
+ });
72
+ exports.RemoveDuplicatesDialog.displayName = "RemoveDuplicatesDialog";
73
+ /**
74
+ * Host-mounted, atom-driven wrapper around {@link RemoveDuplicatesDialog}.
75
+ * Mount this once in the host (alongside the other editor dialogs); the
76
+ * context menu opens it via `useOpenRemoveDuplicatesDialog`. While no host is
77
+ * mounted the context menu keeps its one-click de-dupe, so adopting the
78
+ * dialog is opt-in per host.
79
+ */
80
+ var RemoveDuplicatesDialogHost = function () {
81
+ var _a;
82
+ (0, remove_duplicates_dialog_atom_1.useRegisterRemoveDuplicatesDialogHost)();
83
+ var _b = tslib_1.__read((0, remove_duplicates_dialog_atom_1.useRemoveDuplicatesDialogState)(), 2), request = _b[0], setRequest = _b[1];
84
+ var close = (0, react_1.useCallback)(function () { return setRequest(null); }, [setRequest]);
85
+ return (react_1.default.createElement(exports.RemoveDuplicatesDialog, { open: request != null, onOpenChange: function (open) {
86
+ if (!open)
87
+ close();
88
+ }, columns: (_a = request === null || request === void 0 ? void 0 : request.columns) !== null && _a !== void 0 ? _a : [], initialHasHeader: request === null || request === void 0 ? void 0 : request.hasHeader, onApply: function (options) { return request === null || request === void 0 ? void 0 : request.onApply(options); } }));
89
+ };
90
+ exports.RemoveDuplicatesDialogHost = RemoveDuplicatesDialogHost;
91
+ exports.RemoveDuplicatesDialogHost.displayName = "RemoveDuplicatesDialogHost";
@@ -10,6 +10,7 @@ export * from "./font-family-selector";
10
10
  export * from "./text-horizontal-align-selector";
11
11
  export * from "./text-vertical-align-selector";
12
12
  export * from "./text-wrap-selector";
13
+ export * from "./text-rotation-selector";
13
14
  export * from "./text-format-selector";
14
15
  export * from "./theme-selector";
15
16
  export * from "./table-actions";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/toolbar/index.tsx"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/toolbar/index.tsx"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC"}
@@ -13,6 +13,7 @@ tslib_1.__exportStar(require("./font-family-selector"), exports);
13
13
  tslib_1.__exportStar(require("./text-horizontal-align-selector"), exports);
14
14
  tslib_1.__exportStar(require("./text-vertical-align-selector"), exports);
15
15
  tslib_1.__exportStar(require("./text-wrap-selector"), exports);
16
+ tslib_1.__exportStar(require("./text-rotation-selector"), exports);
16
17
  tslib_1.__exportStar(require("./text-format-selector"), exports);
17
18
  tslib_1.__exportStar(require("./theme-selector"), exports);
18
19
  tslib_1.__exportStar(require("./table-actions"), exports);
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+ import type { CellFormat } from "../../types";
3
+ export type TextRotationValue = NonNullable<CellFormat["textRotation"]>;
4
+ type TextRotationPreset = {
5
+ label: string;
6
+ value: TextRotationValue;
7
+ };
8
+ /**
9
+ * Excel's Orientation menu. Degrees are counter-clockwise positive (Excel's
10
+ * convention, what the renderer and the xlsx round-trip use), so "clockwise"
11
+ * presets are negative. `0` is horizontal — used instead of clearing the
12
+ * property so both engines apply it as a plain format write.
13
+ */
14
+ export declare const TEXT_ROTATION_PRESETS: TextRotationPreset[];
15
+ export declare const MIN_TEXT_ROTATION = -90;
16
+ export declare const MAX_TEXT_ROTATION = 90;
17
+ /**
18
+ * Coerce free-form degree input into the supported -90…90 range. Returns
19
+ * `undefined` for input that is not a finite number.
20
+ */
21
+ export declare const clampTextRotation: (input: string | number) => number | undefined;
22
+ type TextRotationSelectorProps = {
23
+ disabled?: boolean;
24
+ value?: CellFormat["textRotation"];
25
+ onChange(value: TextRotationValue): void;
26
+ };
27
+ export declare const TextRotationSelector: ({ value, onChange, disabled, }: TextRotationSelectorProps) => React.JSX.Element;
28
+ export {};
29
+ //# sourceMappingURL=text-rotation-selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-rotation-selector.d.ts","sourceRoot":"","sources":["../../../../components/toolbar/text-rotation-selector.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,MAAM,iBAAiB,GAAG,WAAW,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC;AAExE,KAAK,kBAAkB,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,iBAAiB,CAAC;CAC1B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,kBAAkB,EAOrD,CAAC;AAEF,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,GAAG,MAAM,uBAMvD,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,UAAU,CAAC,cAAc,CAAC,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;CAC1C,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,gCAIlC,yBAAyB,sBAoF3B,CAAC"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TextRotationSelector = exports.clampTextRotation = exports.MAX_TEXT_ROTATION = exports.MIN_TEXT_ROTATION = exports.TEXT_ROTATION_PRESETS = void 0;
4
+ var tslib_1 = require("tslib");
5
+ var icons_1 = require("@rowsncolumns/icons");
6
+ var ui_1 = require("@rowsncolumns/ui");
7
+ var react_1 = tslib_1.__importStar(require("react"));
8
+ var atoms_1 = require("../../atoms");
9
+ /**
10
+ * Excel's Orientation menu. Degrees are counter-clockwise positive (Excel's
11
+ * convention, what the renderer and the xlsx round-trip use), so "clockwise"
12
+ * presets are negative. `0` is horizontal — used instead of clearing the
13
+ * property so both engines apply it as a plain format write.
14
+ */
15
+ exports.TEXT_ROTATION_PRESETS = [
16
+ { label: "Horizontal", value: 0 },
17
+ { label: "Angle counterclockwise", value: 45 },
18
+ { label: "Angle clockwise", value: -45 },
19
+ { label: "Vertical text", value: "vertical" },
20
+ { label: "Rotate text up", value: 90 },
21
+ { label: "Rotate text down", value: -90 },
22
+ ];
23
+ exports.MIN_TEXT_ROTATION = -90;
24
+ exports.MAX_TEXT_ROTATION = 90;
25
+ /**
26
+ * Coerce free-form degree input into the supported -90…90 range. Returns
27
+ * `undefined` for input that is not a finite number.
28
+ */
29
+ var clampTextRotation = function (input) {
30
+ var value = typeof input === "number" ? input : Number(input);
31
+ if (!Number.isFinite(value)) {
32
+ return undefined;
33
+ }
34
+ return Math.max(exports.MIN_TEXT_ROTATION, Math.min(exports.MAX_TEXT_ROTATION, value));
35
+ };
36
+ exports.clampTextRotation = clampTextRotation;
37
+ var TextRotationSelector = function (_a) {
38
+ var value = _a.value, onChange = _a.onChange, disabled = _a.disabled;
39
+ var focusSheet = (0, atoms_1.useFocusSheet)();
40
+ var _b = tslib_1.__read((0, react_1.useState)(false), 2), isOpen = _b[0], onOpenChange = _b[1];
41
+ var current = value !== null && value !== void 0 ? value : 0;
42
+ var _c = tslib_1.__read((0, react_1.useState)(typeof current === "number" ? String(current) : ""), 2), degrees = _c[0], setDegrees = _c[1];
43
+ // Reflect the active cell's rotation in the custom-degrees field whenever
44
+ // the popover opens on a different value.
45
+ (0, react_1.useEffect)(function () {
46
+ if (isOpen) {
47
+ setDegrees(typeof current === "number" ? String(current) : "");
48
+ }
49
+ }, [isOpen, current]);
50
+ var close = function () { return onOpenChange(false); };
51
+ var apply = function (next) {
52
+ onChange(next);
53
+ focusSheet === null || focusSheet === void 0 ? void 0 : focusSheet();
54
+ close();
55
+ };
56
+ var applyDegrees = function () {
57
+ var next = (0, exports.clampTextRotation)(degrees);
58
+ if (next !== undefined) {
59
+ apply(next);
60
+ }
61
+ };
62
+ return (react_1.default.createElement(ui_1.Popover, { open: isOpen, onOpenChange: onOpenChange },
63
+ react_1.default.createElement(ui_1.PopoverTrigger, { asChild: true },
64
+ react_1.default.createElement(ui_1.IconButton, { size: "lg", tooltip: "Text orientation", "aria-label": "Text orientation", disabled: disabled },
65
+ react_1.default.createElement(icons_1.RotateCounterClockwiseIcon, null),
66
+ react_1.default.createElement(icons_1.MdOutlineArrowDropDown, null))),
67
+ react_1.default.createElement(ui_1.PopoverContent, { align: "start" },
68
+ react_1.default.createElement(ui_1.Stack, { direction: "vertical", className: "gap-1 min-w-[200px]" },
69
+ exports.TEXT_ROTATION_PRESETS.map(function (preset) { return (react_1.default.createElement(ui_1.Button, { key: preset.label, size: "xs", variant: current === preset.value ? "primary" : "ghost", className: "justify-start", "aria-pressed": current === preset.value, onClick: function () { return apply(preset.value); } }, preset.label)); }),
70
+ react_1.default.createElement("form", { className: "flex items-center gap-1 pt-1 m-0", onSubmit: function (e) {
71
+ e.preventDefault();
72
+ applyDegrees();
73
+ } },
74
+ react_1.default.createElement("label", { className: "font-system text-xs shrink-0", htmlFor: "rnc-text-rotation-degrees" }, "Degrees"),
75
+ react_1.default.createElement(ui_1.Input, { id: "rnc-text-rotation-degrees", type: "number", min: exports.MIN_TEXT_ROTATION, max: exports.MAX_TEXT_ROTATION, step: 1, value: degrees, onChange: function (e) { return setDegrees(e.target.value); }, className: "w-[72px]" }),
76
+ react_1.default.createElement(ui_1.Button, { size: "xs", type: "submit" }, "Apply"))))));
77
+ };
78
+ exports.TextRotationSelector = TextRotationSelector;
@@ -3,7 +3,13 @@ import type { WrapStrategy } from "../../types";
3
3
  type TextWrapSelectorProps = {
4
4
  value?: WrapStrategy | null;
5
5
  onChange(value: WrapStrategy): void;
6
+ /**
7
+ * Excel's "Shrink to fit": scale the font down so the text fits the cell.
8
+ * The toggle only renders when `onChangeShrinkToFit` is provided.
9
+ */
10
+ shrinkToFit?: boolean | null;
11
+ onChangeShrinkToFit?(value: boolean): void;
6
12
  };
7
- export declare const TextWrapSelector: ({ value, onChange, }: TextWrapSelectorProps) => React.JSX.Element;
13
+ export declare const TextWrapSelector: ({ value, onChange, shrinkToFit, onChangeShrinkToFit, }: TextWrapSelectorProps) => React.JSX.Element;
8
14
  export {};
9
15
  //# sourceMappingURL=text-wrap-selector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"text-wrap-selector.d.ts","sourceRoot":"","sources":["../../../../components/toolbar/text-wrap-selector.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,KAAK,qBAAqB,GAAG;IAC3B,KAAK,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;CACrC,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,sBAG9B,qBAAqB,sBA8DvB,CAAC"}
1
+ {"version":3,"file":"text-wrap-selector.d.ts","sourceRoot":"","sources":["../../../../components/toolbar/text-wrap-selector.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,KAAK,qBAAqB,GAAG;IAC3B,KAAK,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7B,mBAAmB,CAAC,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;CAC5C,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,wDAK9B,qBAAqB,sBAoFvB,CAAC"}
@@ -8,13 +8,13 @@ var ui_1 = require("@rowsncolumns/ui");
8
8
  var react_1 = tslib_1.__importStar(require("react"));
9
9
  var atoms_1 = require("../../atoms");
10
10
  var TextWrapSelector = function (_a) {
11
- var _b = _a.value, value = _b === void 0 ? "overflow" : _b, onChange = _a.onChange;
11
+ var _b = _a.value, value = _b === void 0 ? "overflow" : _b, onChange = _a.onChange, shrinkToFit = _a.shrinkToFit, onChangeShrinkToFit = _a.onChangeShrinkToFit;
12
12
  var focusSheet = (0, atoms_1.useFocusSheet)();
13
13
  var _c = tslib_1.__read((0, react_1.useState)(false), 2), isOpen = _c[0], onOpenChange = _c[1];
14
14
  var close = function () { return onOpenChange(false); };
15
15
  return (react_1.default.createElement(ui_1.Popover, { open: isOpen, onOpenChange: onOpenChange },
16
16
  react_1.default.createElement(ui_1.PopoverTrigger, { asChild: true },
17
- react_1.default.createElement(ui_1.IconButton, { size: "lg", tooltip: "Text wrapping" },
17
+ react_1.default.createElement(ui_1.IconButton, { size: "lg", tooltip: "Text wrapping", "aria-label": "Text wrapping" },
18
18
  value === "overflow" ? (react_1.default.createElement(icons_1.TextOverflowIcon, null)) : value === "wrap" ? (react_1.default.createElement(icons_1.TextOverflowWrapIcon, null)) : (react_1.default.createElement(icons_1.TextoverflowClipIcon, null)),
19
19
  react_1.default.createElement(icons_2.MdOutlineArrowDropDown, null))),
20
20
  react_1.default.createElement(ui_1.PopoverContent, { align: "start" },
@@ -36,6 +36,13 @@ var TextWrapSelector = function (_a) {
36
36
  focusSheet === null || focusSheet === void 0 ? void 0 : focusSheet();
37
37
  close();
38
38
  } },
39
- react_1.default.createElement(icons_1.TextoverflowClipIcon, null))))));
39
+ react_1.default.createElement(icons_1.TextoverflowClipIcon, null)),
40
+ onChangeShrinkToFit ? (react_1.default.createElement(ui_1.IconButton, { size: "lg", isActive: !!shrinkToFit, "aria-pressed": !!shrinkToFit, tooltip: "Shrink text to fit the cell", "aria-label": "Shrink text to fit the cell", className: "w-full justify-start gap-1", onClick: function () {
41
+ onChangeShrinkToFit(!shrinkToFit);
42
+ focusSheet === null || focusSheet === void 0 ? void 0 : focusSheet();
43
+ close();
44
+ } },
45
+ react_1.default.createElement(icons_1.TextoverflowClipIcon, null),
46
+ react_1.default.createElement("span", { className: "text-xs" }, "Shrink to fit"))) : null))));
40
47
  };
41
48
  exports.TextWrapSelector = TextWrapSelector;
@@ -31,11 +31,30 @@ export type UseCopyPasteCutProps = {
31
31
  onCut: CanvasGridProps["onCut"];
32
32
  };
33
33
  export type PasteSpecialType = "Transposed" | "Formatting" | "Value" | "Formula" | "Link";
34
+ /** Excel Paste Special → Operation: combine each pasted cell with the cell it lands on. */
35
+ export type PasteSpecialOperation = "add" | "subtract" | "multiply" | "divide";
36
+ /**
37
+ * Excel's Paste Special dialog as one request. `paste` picks what is
38
+ * pasted (all / values / formulas / formats), `operation` combines the pasted
39
+ * value with the destination (`=dest+source`, formulas stay formulas),
40
+ * `skipBlanks` leaves the destination untouched where the clipboard cell is
41
+ * empty and `transpose` swaps rows and columns. Every flag composes with the
42
+ * others; the legacy single-mode {@link PasteSpecialType} strings map onto
43
+ * the same fields.
44
+ */
45
+ export type PasteSpecialOptions = {
46
+ paste?: "all" | "values" | "formulas" | "formats";
47
+ operation?: PasteSpecialOperation;
48
+ skipBlanks?: boolean;
49
+ transpose?: boolean;
50
+ };
51
+ /** Argument accepted by `paste()` — a legacy single mode or the full dialog request. */
52
+ export type PasteSpecialRequest = PasteSpecialType | PasteSpecialOptions;
34
53
  export declare const useCopyPasteCut: ({ selections, activeCell, sheetId, onPaste, onCopy, onCut, focusSheet, }: UseCopyPasteCutProps) => {
35
54
  selections: SelectionArea[];
36
55
  copy: () => void;
37
56
  cut: () => void;
38
- paste: (pasteSpecialType?: PasteSpecialType) => Promise<void>;
57
+ paste: (pasteSpecial?: PasteSpecialRequest) => Promise<void>;
39
58
  copiedSelections: any[];
40
59
  clearCopiedSelections: () => void;
41
60
  onInternalCopy: (e: ClipboardEvent, isCutOperation?: boolean) => boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"use-copy-paste-cut.d.ts","sourceRoot":"","sources":["../../../hooks/use-copy-paste-cut.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAWvE,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,mCAAmC,CAAC;AAK3C,MAAM,MAAM,oBAAoB,GAAG;IACjC;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,UAAU,EAAE,aAAa,CAAC;IAC1B;;OAEG;IACH,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B;;OAEG;IACH,UAAU,IAAI,IAAI,CAAC;IACnB;;OAEG;IACH,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;IACpC;;OAEG;IACH,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC;IAClC;;OAEG;IACH,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GACxB,YAAY,GACZ,YAAY,GACZ,OAAO,GACP,SAAS,GACT,MAAM,CAAC;AAEX,eAAO,MAAM,eAAe,GAAI,0EAQ7B,oBAAoB;;;;+BAoRO,gBAAgB;;;wBA1KtC,cAAc;yBAuDd,cAAc;uBAtBd,cAAc;CAmMrB,CAAC"}
1
+ {"version":3,"file":"use-copy-paste-cut.d.ts","sourceRoot":"","sources":["../../../hooks/use-copy-paste-cut.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAYvE,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,mCAAmC,CAAC;AAK3C,MAAM,MAAM,oBAAoB,GAAG;IACjC;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,UAAU,EAAE,aAAa,CAAC;IAC1B;;OAEG;IACH,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B;;OAEG;IACH,UAAU,IAAI,IAAI,CAAC;IACnB;;OAEG;IACH,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;IACpC;;OAEG;IACH,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC;IAClC;;OAEG;IACH,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GACxB,YAAY,GACZ,YAAY,GACZ,OAAO,GACP,SAAS,GACT,MAAM,CAAC;AAEX,2FAA2F;AAC3F,MAAM,MAAM,qBAAqB,GAAG,KAAK,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE/E;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IAClD,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wFAAwF;AACxF,MAAM,MAAM,mBAAmB,GAAG,gBAAgB,GAAG,mBAAmB,CAAC;AAEzE,eAAO,MAAM,eAAe,GAAI,0EAQ7B,oBAAoB;;;;2BAoRG,mBAAmB;;;wBA1KrC,cAAc;yBAuDd,cAAc;uBAtBd,cAAc;CA0MrB,CAAC"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useCopyPasteCut = void 0;
4
4
  var tslib_1 = require("tslib");
5
5
  var grid_1 = require("@rowsncolumns/grid");
6
+ var utils_1 = require("@rowsncolumns/utils");
6
7
  var react_1 = require("react");
7
8
  var copy_paste_1 = require("../api/copy-paste");
8
9
  var selections_1 = require("../api/selections");
@@ -63,7 +64,7 @@ var useCopyPasteCut = function (_a) {
63
64
  return;
64
65
  }
65
66
  var handleKeyDown = function (e) {
66
- if (!e.key || e.key.toLowerCase() !== "v") {
67
+ if (!e.key || (0, utils_1.getHotkeyKey)(e) !== "v") {
67
68
  return;
68
69
  }
69
70
  if (!e.metaKey && !e.ctrlKey) {
@@ -215,16 +216,16 @@ var useCopyPasteCut = function (_a) {
215
216
  focusSheet();
216
217
  }, [cellEditorInstance, focusSheet]);
217
218
  // From contextmenu
218
- var paste = (0, react_1.useCallback)(function (pasteSpecialType) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
219
+ var paste = (0, react_1.useCallback)(function (pasteSpecial) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
219
220
  function getClipboardContents() {
220
221
  return tslib_1.__awaiter(this, void 0, void 0, function () {
221
222
  var editorEl, dataTransfer, evt, clipboardItems, clipboardItems_1, clipboardItems_1_1, clipboardItem, _a, _b, type, blob, text, e_1_1, e_2_1, err_1;
222
223
  var e_2, _c, e_1, _d;
223
- var _e, _f, _g;
224
- return tslib_1.__generator(this, function (_h) {
225
- switch (_h.label) {
224
+ var _e, _f, _g, _h;
225
+ return tslib_1.__generator(this, function (_j) {
226
+ switch (_j.label) {
226
227
  case 0:
227
- _h.trys.push([0, 17, , 18]);
228
+ _j.trys.push([0, 17, , 18]);
228
229
  editorEl = (_e = cellEditorInstance === null || cellEditorInstance === void 0 ? void 0 : cellEditorInstance.el) === null || _e === void 0 ? void 0 : _e.call(cellEditorInstance);
229
230
  // Focus editor
230
231
  cellEditorInstance === null || cellEditorInstance === void 0 ? void 0 : cellEditorInstance.focus();
@@ -236,37 +237,37 @@ var useCopyPasteCut = function (_a) {
236
237
  });
237
238
  return [4 /*yield*/, navigator.clipboard.read()];
238
239
  case 1:
239
- clipboardItems = _h.sent();
240
- _h.label = 2;
240
+ clipboardItems = _j.sent();
241
+ _j.label = 2;
241
242
  case 2:
242
- _h.trys.push([2, 14, 15, 16]);
243
+ _j.trys.push([2, 14, 15, 16]);
243
244
  clipboardItems_1 = tslib_1.__values(clipboardItems), clipboardItems_1_1 = clipboardItems_1.next();
244
- _h.label = 3;
245
+ _j.label = 3;
245
246
  case 3:
246
247
  if (!!clipboardItems_1_1.done) return [3 /*break*/, 13];
247
248
  clipboardItem = clipboardItems_1_1.value;
248
- _h.label = 4;
249
+ _j.label = 4;
249
250
  case 4:
250
- _h.trys.push([4, 10, 11, 12]);
251
+ _j.trys.push([4, 10, 11, 12]);
251
252
  _a = (e_1 = void 0, tslib_1.__values(clipboardItem.types)), _b = _a.next();
252
- _h.label = 5;
253
+ _j.label = 5;
253
254
  case 5:
254
255
  if (!!_b.done) return [3 /*break*/, 9];
255
256
  type = _b.value;
256
257
  return [4 /*yield*/, clipboardItem.getType(type)];
257
258
  case 6:
258
- blob = _h.sent();
259
+ blob = _j.sent();
259
260
  return [4 /*yield*/, blob.text()];
260
261
  case 7:
261
- text = _h.sent();
262
+ text = _j.sent();
262
263
  (_f = evt.clipboardData) === null || _f === void 0 ? void 0 : _f.setData(type, text);
263
- _h.label = 8;
264
+ _j.label = 8;
264
265
  case 8:
265
266
  _b = _a.next();
266
267
  return [3 /*break*/, 5];
267
268
  case 9: return [3 /*break*/, 12];
268
269
  case 10:
269
- e_1_1 = _h.sent();
270
+ e_1_1 = _j.sent();
270
271
  e_1 = { error: e_1_1 };
271
272
  return [3 /*break*/, 12];
272
273
  case 11:
@@ -280,7 +281,7 @@ var useCopyPasteCut = function (_a) {
280
281
  return [3 /*break*/, 3];
281
282
  case 13: return [3 /*break*/, 16];
282
283
  case 14:
283
- e_2_1 = _h.sent();
284
+ e_2_1 = _j.sent();
284
285
  e_2 = { error: e_2_1 };
285
286
  return [3 /*break*/, 16];
286
287
  case 15:
@@ -290,15 +291,20 @@ var useCopyPasteCut = function (_a) {
290
291
  finally { if (e_2) throw e_2.error; }
291
292
  return [7 /*endfinally*/];
292
293
  case 16:
293
- if (pasteSpecialType) {
294
- (_g = evt.clipboardData) === null || _g === void 0 ? void 0 : _g.setData("pasteSpecialType", pasteSpecialType);
294
+ // The paste pipelines read the request back from these synthetic
295
+ // clipboard keys (`resolvePasteSpecialOptions` in spreadsheet-state).
296
+ if (typeof pasteSpecial === "string") {
297
+ (_g = evt.clipboardData) === null || _g === void 0 ? void 0 : _g.setData("pasteSpecialType", pasteSpecial);
298
+ }
299
+ else if (pasteSpecial) {
300
+ (_h = evt.clipboardData) === null || _h === void 0 ? void 0 : _h.setData("pasteSpecialOptions", JSON.stringify(pasteSpecial));
295
301
  }
296
302
  if (editorEl) {
297
303
  editorEl.dispatchEvent(evt);
298
304
  }
299
305
  return [3 /*break*/, 18];
300
306
  case 17:
301
- err_1 = _h.sent();
307
+ err_1 = _j.sent();
302
308
  console.error(err_1);
303
309
  return [3 /*break*/, 18];
304
310
  case 18: return [2 /*return*/];