@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.
- 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 +27 -21
- 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 +186 -21
- 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/release-date.js +1 -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 +10 -4
- 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 +173 -21
- 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/release-date.js +1 -1
- 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 +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;
|
|
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;
|
|
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 ||
|
|
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 (
|
|
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 (
|
|
225
|
-
switch (
|
|
224
|
+
var _e, _f, _g, _h;
|
|
225
|
+
return tslib_1.__generator(this, function (_j) {
|
|
226
|
+
switch (_j.label) {
|
|
226
227
|
case 0:
|
|
227
|
-
|
|
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 =
|
|
240
|
-
|
|
240
|
+
clipboardItems = _j.sent();
|
|
241
|
+
_j.label = 2;
|
|
241
242
|
case 2:
|
|
242
|
-
|
|
243
|
+
_j.trys.push([2, 14, 15, 16]);
|
|
243
244
|
clipboardItems_1 = tslib_1.__values(clipboardItems), clipboardItems_1_1 = clipboardItems_1.next();
|
|
244
|
-
|
|
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
|
-
|
|
249
|
+
_j.label = 4;
|
|
249
250
|
case 4:
|
|
250
|
-
|
|
251
|
+
_j.trys.push([4, 10, 11, 12]);
|
|
251
252
|
_a = (e_1 = void 0, tslib_1.__values(clipboardItem.types)), _b = _a.next();
|
|
252
|
-
|
|
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 =
|
|
259
|
+
blob = _j.sent();
|
|
259
260
|
return [4 /*yield*/, blob.text()];
|
|
260
261
|
case 7:
|
|
261
|
-
text =
|
|
262
|
+
text = _j.sent();
|
|
262
263
|
(_f = evt.clipboardData) === null || _f === void 0 ? void 0 : _f.setData(type, text);
|
|
263
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
294
|
-
|
|
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 =
|
|
307
|
+
err_1 = _j.sent();
|
|
302
308
|
console.error(err_1);
|
|
303
309
|
return [3 /*break*/, 18];
|
|
304
310
|
case 18: return [2 /*return*/];
|