@rowsncolumns/spreadsheet 10.2.73 → 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.
- package/dist/cjs/api/evaluate-formula.d.ts +17 -0
- package/dist/cjs/api/evaluate-formula.d.ts.map +1 -0
- package/dist/cjs/api/evaluate-formula.js +141 -0
- package/dist/cjs/api/go-to.d.ts +19 -0
- package/dist/cjs/api/go-to.d.ts.map +1 -0
- package/dist/cjs/api/go-to.js +49 -0
- package/dist/cjs/atoms/evaluate-formula-dialog.atom.d.ts +36 -0
- package/dist/cjs/atoms/evaluate-formula-dialog.atom.d.ts.map +1 -0
- package/dist/cjs/atoms/evaluate-formula-dialog.atom.js +36 -0
- package/dist/cjs/atoms/go-to-dialog.atom.d.ts +36 -0
- package/dist/cjs/atoms/go-to-dialog.atom.d.ts.map +1 -0
- package/dist/cjs/atoms/go-to-dialog.atom.js +34 -0
- package/dist/cjs/atoms/index.d.ts +4 -0
- package/dist/cjs/atoms/index.d.ts.map +1 -1
- package/dist/cjs/atoms/index.js +4 -0
- package/dist/cjs/atoms/paste-special-dialog.atom.d.ts +29 -0
- package/dist/cjs/atoms/paste-special-dialog.atom.d.ts.map +1 -0
- package/dist/cjs/atoms/paste-special-dialog.atom.js +34 -0
- package/dist/cjs/atoms/remove-duplicates-dialog.atom.d.ts +45 -0
- package/dist/cjs/atoms/remove-duplicates-dialog.atom.d.ts.map +1 -0
- package/dist/cjs/atoms/remove-duplicates-dialog.atom.js +37 -0
- package/dist/cjs/components/canvas-grid/index.d.ts.map +1 -1
- package/dist/cjs/components/canvas-grid/index.js +109 -3
- package/dist/cjs/components/canvas-grid/typings.d.ts +54 -8
- package/dist/cjs/components/canvas-grid/typings.d.ts.map +1 -1
- package/dist/cjs/components/context-menu/index.d.ts +16 -3
- package/dist/cjs/components/context-menu/index.d.ts.map +1 -1
- package/dist/cjs/components/context-menu/index.js +112 -5
- package/dist/cjs/components/context-menu/total-row-functions.d.ts +32 -0
- package/dist/cjs/components/context-menu/total-row-functions.d.ts.map +1 -0
- package/dist/cjs/components/context-menu/total-row-functions.js +62 -0
- package/dist/cjs/components/evaluate-formula-dialog/index.d.ts +34 -0
- package/dist/cjs/components/evaluate-formula-dialog/index.d.ts.map +1 -0
- package/dist/cjs/components/evaluate-formula-dialog/index.js +106 -0
- package/dist/cjs/components/go-to-dialog/index.d.ts +35 -0
- package/dist/cjs/components/go-to-dialog/index.d.ts.map +1 -0
- package/dist/cjs/components/go-to-dialog/index.js +93 -0
- package/dist/cjs/components/paste-special-dialog/index.d.ts +29 -0
- package/dist/cjs/components/paste-special-dialog/index.d.ts.map +1 -0
- package/dist/cjs/components/paste-special-dialog/index.js +99 -0
- package/dist/cjs/components/remove-duplicates-dialog/index.d.ts +37 -0
- package/dist/cjs/components/remove-duplicates-dialog/index.d.ts.map +1 -0
- package/dist/cjs/components/remove-duplicates-dialog/index.js +91 -0
- package/dist/cjs/components/toolbar/index.d.ts +1 -0
- package/dist/cjs/components/toolbar/index.d.ts.map +1 -1
- package/dist/cjs/components/toolbar/index.js +1 -0
- package/dist/cjs/components/toolbar/text-rotation-selector.d.ts +29 -0
- package/dist/cjs/components/toolbar/text-rotation-selector.d.ts.map +1 -0
- package/dist/cjs/components/toolbar/text-rotation-selector.js +78 -0
- package/dist/cjs/components/toolbar/text-wrap-selector.d.ts +7 -1
- package/dist/cjs/components/toolbar/text-wrap-selector.d.ts.map +1 -1
- package/dist/cjs/components/toolbar/text-wrap-selector.js +10 -3
- package/dist/cjs/hooks/use-copy-paste-cut.d.ts +20 -1
- package/dist/cjs/hooks/use-copy-paste-cut.d.ts.map +1 -1
- package/dist/cjs/hooks/use-copy-paste-cut.js +25 -20
- package/dist/cjs/hooks/use-keyboard-handler.d.ts +17 -2
- package/dist/cjs/hooks/use-keyboard-handler.d.ts.map +1 -1
- package/dist/cjs/hooks/use-keyboard-handler.js +182 -19
- package/dist/cjs/index.d.ts +6 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +7 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/cjs/types.d.ts +173 -1
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/esm/api/evaluate-formula.d.ts +17 -0
- package/dist/esm/api/evaluate-formula.d.ts.map +1 -0
- package/dist/esm/api/evaluate-formula.js +109 -0
- package/dist/esm/api/go-to.d.ts +19 -0
- package/dist/esm/api/go-to.d.ts.map +1 -0
- package/dist/esm/api/go-to.js +41 -0
- package/dist/esm/atoms/evaluate-formula-dialog.atom.d.ts +36 -0
- package/dist/esm/atoms/evaluate-formula-dialog.atom.d.ts.map +1 -0
- package/dist/esm/atoms/evaluate-formula-dialog.atom.js +25 -0
- package/dist/esm/atoms/go-to-dialog.atom.d.ts +36 -0
- package/dist/esm/atoms/go-to-dialog.atom.d.ts.map +1 -0
- package/dist/esm/atoms/go-to-dialog.atom.js +25 -0
- package/dist/esm/atoms/index.d.ts +4 -0
- package/dist/esm/atoms/index.d.ts.map +1 -1
- package/dist/esm/atoms/index.js +4 -0
- package/dist/esm/atoms/paste-special-dialog.atom.d.ts +29 -0
- package/dist/esm/atoms/paste-special-dialog.atom.d.ts.map +1 -0
- package/dist/esm/atoms/paste-special-dialog.atom.js +25 -0
- package/dist/esm/atoms/remove-duplicates-dialog.atom.d.ts +45 -0
- package/dist/esm/atoms/remove-duplicates-dialog.atom.d.ts.map +1 -0
- package/dist/esm/atoms/remove-duplicates-dialog.atom.js +26 -0
- package/dist/esm/components/canvas-grid/index.d.ts.map +1 -1
- package/dist/esm/components/canvas-grid/index.js +107 -3
- package/dist/esm/components/canvas-grid/typings.d.ts +54 -8
- package/dist/esm/components/canvas-grid/typings.d.ts.map +1 -1
- package/dist/esm/components/context-menu/index.d.ts +16 -3
- package/dist/esm/components/context-menu/index.d.ts.map +1 -1
- package/dist/esm/components/context-menu/index.js +114 -7
- package/dist/esm/components/context-menu/total-row-functions.d.ts +32 -0
- package/dist/esm/components/context-menu/total-row-functions.d.ts.map +1 -0
- package/dist/esm/components/context-menu/total-row-functions.js +50 -0
- package/dist/esm/components/evaluate-formula-dialog/index.d.ts +34 -0
- package/dist/esm/components/evaluate-formula-dialog/index.d.ts.map +1 -0
- package/dist/esm/components/evaluate-formula-dialog/index.js +86 -0
- package/dist/esm/components/go-to-dialog/index.d.ts +35 -0
- package/dist/esm/components/go-to-dialog/index.d.ts.map +1 -0
- package/dist/esm/components/go-to-dialog/index.js +84 -0
- package/dist/esm/components/paste-special-dialog/index.d.ts +29 -0
- package/dist/esm/components/paste-special-dialog/index.d.ts.map +1 -0
- package/dist/esm/components/paste-special-dialog/index.js +90 -0
- package/dist/esm/components/remove-duplicates-dialog/index.d.ts +37 -0
- package/dist/esm/components/remove-duplicates-dialog/index.d.ts.map +1 -0
- package/dist/esm/components/remove-duplicates-dialog/index.js +82 -0
- package/dist/esm/components/toolbar/index.d.ts +1 -0
- package/dist/esm/components/toolbar/index.d.ts.map +1 -1
- package/dist/esm/components/toolbar/index.js +1 -0
- package/dist/esm/components/toolbar/text-rotation-selector.d.ts +29 -0
- package/dist/esm/components/toolbar/text-rotation-selector.d.ts.map +1 -0
- package/dist/esm/components/toolbar/text-rotation-selector.js +71 -0
- package/dist/esm/components/toolbar/text-wrap-selector.d.ts +7 -1
- package/dist/esm/components/toolbar/text-wrap-selector.d.ts.map +1 -1
- package/dist/esm/components/toolbar/text-wrap-selector.js +10 -3
- package/dist/esm/hooks/use-copy-paste-cut.d.ts +20 -1
- package/dist/esm/hooks/use-copy-paste-cut.d.ts.map +1 -1
- package/dist/esm/hooks/use-copy-paste-cut.js +8 -3
- package/dist/esm/hooks/use-keyboard-handler.d.ts +17 -2
- package/dist/esm/hooks/use-keyboard-handler.d.ts.map +1 -1
- package/dist/esm/hooks/use-keyboard-handler.js +169 -19
- package/dist/esm/index.d.ts +6 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +5 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/types.d.ts +173 -1
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/spreadsheet.min.css +1 -1
- package/package.json +5 -5
|
@@ -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;
|
|
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: (
|
|
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;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,eAAO,MAAM,eAAe,GAAI,0EAQ7B,oBAAoB
|
|
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"}
|
|
@@ -216,16 +216,16 @@ var useCopyPasteCut = function (_a) {
|
|
|
216
216
|
focusSheet();
|
|
217
217
|
}, [cellEditorInstance, focusSheet]);
|
|
218
218
|
// From contextmenu
|
|
219
|
-
var paste = (0, react_1.useCallback)(function (
|
|
219
|
+
var paste = (0, react_1.useCallback)(function (pasteSpecial) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
|
|
220
220
|
function getClipboardContents() {
|
|
221
221
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
222
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;
|
|
223
223
|
var e_2, _c, e_1, _d;
|
|
224
|
-
var _e, _f, _g;
|
|
225
|
-
return tslib_1.__generator(this, function (
|
|
226
|
-
switch (
|
|
224
|
+
var _e, _f, _g, _h;
|
|
225
|
+
return tslib_1.__generator(this, function (_j) {
|
|
226
|
+
switch (_j.label) {
|
|
227
227
|
case 0:
|
|
228
|
-
|
|
228
|
+
_j.trys.push([0, 17, , 18]);
|
|
229
229
|
editorEl = (_e = cellEditorInstance === null || cellEditorInstance === void 0 ? void 0 : cellEditorInstance.el) === null || _e === void 0 ? void 0 : _e.call(cellEditorInstance);
|
|
230
230
|
// Focus editor
|
|
231
231
|
cellEditorInstance === null || cellEditorInstance === void 0 ? void 0 : cellEditorInstance.focus();
|
|
@@ -237,37 +237,37 @@ var useCopyPasteCut = function (_a) {
|
|
|
237
237
|
});
|
|
238
238
|
return [4 /*yield*/, navigator.clipboard.read()];
|
|
239
239
|
case 1:
|
|
240
|
-
clipboardItems =
|
|
241
|
-
|
|
240
|
+
clipboardItems = _j.sent();
|
|
241
|
+
_j.label = 2;
|
|
242
242
|
case 2:
|
|
243
|
-
|
|
243
|
+
_j.trys.push([2, 14, 15, 16]);
|
|
244
244
|
clipboardItems_1 = tslib_1.__values(clipboardItems), clipboardItems_1_1 = clipboardItems_1.next();
|
|
245
|
-
|
|
245
|
+
_j.label = 3;
|
|
246
246
|
case 3:
|
|
247
247
|
if (!!clipboardItems_1_1.done) return [3 /*break*/, 13];
|
|
248
248
|
clipboardItem = clipboardItems_1_1.value;
|
|
249
|
-
|
|
249
|
+
_j.label = 4;
|
|
250
250
|
case 4:
|
|
251
|
-
|
|
251
|
+
_j.trys.push([4, 10, 11, 12]);
|
|
252
252
|
_a = (e_1 = void 0, tslib_1.__values(clipboardItem.types)), _b = _a.next();
|
|
253
|
-
|
|
253
|
+
_j.label = 5;
|
|
254
254
|
case 5:
|
|
255
255
|
if (!!_b.done) return [3 /*break*/, 9];
|
|
256
256
|
type = _b.value;
|
|
257
257
|
return [4 /*yield*/, clipboardItem.getType(type)];
|
|
258
258
|
case 6:
|
|
259
|
-
blob =
|
|
259
|
+
blob = _j.sent();
|
|
260
260
|
return [4 /*yield*/, blob.text()];
|
|
261
261
|
case 7:
|
|
262
|
-
text =
|
|
262
|
+
text = _j.sent();
|
|
263
263
|
(_f = evt.clipboardData) === null || _f === void 0 ? void 0 : _f.setData(type, text);
|
|
264
|
-
|
|
264
|
+
_j.label = 8;
|
|
265
265
|
case 8:
|
|
266
266
|
_b = _a.next();
|
|
267
267
|
return [3 /*break*/, 5];
|
|
268
268
|
case 9: return [3 /*break*/, 12];
|
|
269
269
|
case 10:
|
|
270
|
-
e_1_1 =
|
|
270
|
+
e_1_1 = _j.sent();
|
|
271
271
|
e_1 = { error: e_1_1 };
|
|
272
272
|
return [3 /*break*/, 12];
|
|
273
273
|
case 11:
|
|
@@ -281,7 +281,7 @@ var useCopyPasteCut = function (_a) {
|
|
|
281
281
|
return [3 /*break*/, 3];
|
|
282
282
|
case 13: return [3 /*break*/, 16];
|
|
283
283
|
case 14:
|
|
284
|
-
e_2_1 =
|
|
284
|
+
e_2_1 = _j.sent();
|
|
285
285
|
e_2 = { error: e_2_1 };
|
|
286
286
|
return [3 /*break*/, 16];
|
|
287
287
|
case 15:
|
|
@@ -291,15 +291,20 @@ var useCopyPasteCut = function (_a) {
|
|
|
291
291
|
finally { if (e_2) throw e_2.error; }
|
|
292
292
|
return [7 /*endfinally*/];
|
|
293
293
|
case 16:
|
|
294
|
-
|
|
295
|
-
|
|
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));
|
|
296
301
|
}
|
|
297
302
|
if (editorEl) {
|
|
298
303
|
editorEl.dispatchEvent(evt);
|
|
299
304
|
}
|
|
300
305
|
return [3 /*break*/, 18];
|
|
301
306
|
case 17:
|
|
302
|
-
err_1 =
|
|
307
|
+
err_1 = _j.sent();
|
|
303
308
|
console.error(err_1);
|
|
304
309
|
return [3 /*break*/, 18];
|
|
305
310
|
case 18: return [2 /*return*/];
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import type { CellInterface, SelectionArea } from "@rowsncolumns/grid";
|
|
2
2
|
import type React from "react";
|
|
3
3
|
import type { CanvasGridProps, SelectionAttributes } from "../components/canvas-grid/typings";
|
|
4
|
-
import type { CellFormat, SheetRange } from "../types";
|
|
4
|
+
import type { CellFormat, ExtendedValue, Maybe, SheetRange } from "../types";
|
|
5
5
|
import type { useContextMenu } from "./use-context-menu";
|
|
6
6
|
type FormattingKeyboardProps = {
|
|
7
7
|
sheetId: number;
|
|
8
8
|
locale?: string;
|
|
9
9
|
showFormulas?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Resolves the Excel-vs-Sheets shortcut conflicts; defaults to "sheets".
|
|
12
|
+
*/
|
|
13
|
+
keymap?: CanvasGridProps["keymap"];
|
|
10
14
|
defaultFontSizePoint: NonNullable<CanvasGridProps["defaultFontSizePoint"]>;
|
|
11
15
|
canEditCell(sheetId: number, cell: CellInterface): boolean;
|
|
12
16
|
onChangeFormatting: CanvasGridProps["onChangeFormatting"];
|
|
@@ -20,6 +24,9 @@ type FormattingKeyboardProps = {
|
|
|
20
24
|
selections: SelectionArea<SelectionAttributes>[];
|
|
21
25
|
selectedRows: Record<string, boolean>;
|
|
22
26
|
selectedColumns: Record<string, boolean>;
|
|
27
|
+
/** Whole rows / columns selected through their headers */
|
|
28
|
+
selectedRowHeadersIds?: number[];
|
|
29
|
+
selectedColumnHeadersIds?: number[];
|
|
23
30
|
onSelectNextSheet: CanvasGridProps["onSelectNextSheet"];
|
|
24
31
|
onSelectPreviousSheet: CanvasGridProps["onSelectPreviousSheet"];
|
|
25
32
|
onCreateNewSheet: CanvasGridProps["onCreateNewSheet"];
|
|
@@ -51,7 +58,15 @@ type FormattingKeyboardProps = {
|
|
|
51
58
|
onShowContextMenu: ReturnType<typeof useContextMenu>["showContextMenu"];
|
|
52
59
|
onAddQuickEdit(range: SheetRange): void;
|
|
53
60
|
isSheetFocused(): boolean;
|
|
61
|
+
onCalculateNow?: CanvasGridProps["onCalculateNow"];
|
|
62
|
+
onRequestGoTo?: CanvasGridProps["onRequestGoTo"];
|
|
63
|
+
/** Ctrl+Alt+V — Paste Special dialog (Excel). */
|
|
64
|
+
onRequestPasteSpecial?: () => void;
|
|
65
|
+
/** Ctrl+' / Ctrl+Shift+" write the cell above into the active cell */
|
|
66
|
+
onChangeBatch?: CanvasGridProps["onChangeBatch"];
|
|
67
|
+
getUserEnteredValue?(sheetId: number, rowIndex: number, columnIndex: number): string | undefined | null;
|
|
68
|
+
getEffectiveValue?(sheetId: number, rowIndex: number, columnIndex: number): Maybe<ExtendedValue>;
|
|
54
69
|
};
|
|
55
|
-
export declare const useKeyboardHandler: ({ sheetId, locale, selectedRows, selectedColumns, showFormulas, defaultFontSizePoint, onShowFormulas, onChangeFormatting, onRepeatFormatting, onClearFormatting, onSelectNextSheet, onSelectPreviousSheet, onCreateNewSheet, onFillRange, disableFillRightShortcut, onInsertTime, onInsertDate, onInsertDateTime, onInsertNote, onInsertAutoSum, onRedo, onUndo, onRequestSearch, onRequestReplace, onRequestFormatCells, onRequestInsertComment, onRequestInsertLink, onCreateTable, onCreateBasicFilter, clearCopiedSelections, getCellFormat, onShowContextMenu, onHideColumn, onGroupColumns, onUngroupColumns, onHideRow, onGroupRows, onUngroupRows, onDeleteRow, onInsertRow, onAddQuickEdit, canEditCell, isSheetFocused, activeCell, selections, }: FormattingKeyboardProps) => (e: React.KeyboardEvent<HTMLDivElement>) => void;
|
|
70
|
+
export declare const useKeyboardHandler: ({ sheetId, locale, selectedRows, selectedColumns, selectedRowHeadersIds, selectedColumnHeadersIds, showFormulas, keymap, defaultFontSizePoint, onShowFormulas, onChangeFormatting, onRepeatFormatting, onClearFormatting, onSelectNextSheet, onSelectPreviousSheet, onCreateNewSheet, onFillRange, disableFillRightShortcut, onInsertTime, onInsertDate, onInsertDateTime, onInsertNote, onInsertAutoSum, onRedo, onUndo, onRequestSearch, onRequestReplace, onRequestFormatCells, onRequestInsertComment, onRequestInsertLink, onCreateTable, onCreateBasicFilter, clearCopiedSelections, getCellFormat, onShowContextMenu, onHideColumn, onShowColumn, onGroupColumns, onUngroupColumns, onHideRow, onShowRow, onGroupRows, onUngroupRows, onDeleteRow, onInsertRow, onAddQuickEdit, onCalculateNow, onRequestGoTo, onRequestPasteSpecial, onChangeBatch, getUserEnteredValue, getEffectiveValue, canEditCell, isSheetFocused, activeCell, selections, }: FormattingKeyboardProps) => (e: React.KeyboardEvent<HTMLDivElement>) => void;
|
|
56
71
|
export {};
|
|
57
72
|
//# sourceMappingURL=use-keyboard-handler.d.ts.map
|