@rowsncolumns/spreadsheet 10.2.74 → 10.2.76
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/excel-validation-kinds.d.ts +71 -0
- package/dist/cjs/api/excel-validation-kinds.d.ts.map +1 -0
- package/dist/cjs/api/excel-validation-kinds.js +304 -0
- package/dist/cjs/api/fill-series.d.ts +38 -0
- package/dist/cjs/api/fill-series.d.ts.map +1 -0
- package/dist/cjs/api/fill-series.js +89 -0
- package/dist/cjs/api/go-to-special.d.ts +32 -0
- package/dist/cjs/api/go-to-special.d.ts.map +1 -0
- package/dist/cjs/api/go-to-special.js +111 -0
- package/dist/cjs/api/spreadsheet-api.d.ts +6 -2
- package/dist/cjs/api/spreadsheet-api.d.ts.map +1 -1
- package/dist/cjs/api/spreadsheet-api.js +9 -3
- package/dist/cjs/api/validation-tooltip.d.ts +17 -0
- package/dist/cjs/api/validation-tooltip.d.ts.map +1 -0
- package/dist/cjs/api/validation-tooltip.js +42 -0
- package/dist/cjs/atoms/advanced-filter-dialog.atom.d.ts +28 -0
- package/dist/cjs/atoms/advanced-filter-dialog.atom.d.ts.map +1 -0
- package/dist/cjs/atoms/advanced-filter-dialog.atom.js +32 -0
- package/dist/cjs/atoms/fill-options.atom.d.ts +36 -0
- package/dist/cjs/atoms/fill-options.atom.d.ts.map +1 -0
- package/dist/cjs/atoms/fill-options.atom.js +11 -0
- package/dist/cjs/atoms/fill-series-dialog.atom.d.ts +26 -0
- package/dist/cjs/atoms/fill-series-dialog.atom.d.ts.map +1 -0
- package/dist/cjs/atoms/fill-series-dialog.atom.js +14 -0
- package/dist/cjs/atoms/go-to-dialog.atom.d.ts +11 -1
- package/dist/cjs/atoms/go-to-dialog.atom.d.ts.map +1 -1
- package/dist/cjs/atoms/goal-seek-dialog.atom.d.ts +29 -0
- package/dist/cjs/atoms/goal-seek-dialog.atom.d.ts.map +1 -0
- package/dist/cjs/atoms/goal-seek-dialog.atom.js +30 -0
- package/dist/cjs/atoms/index.d.ts +3 -0
- package/dist/cjs/atoms/index.d.ts.map +1 -1
- package/dist/cjs/atoms/index.js +3 -0
- package/dist/cjs/atoms/subtotal-dialog.atom.d.ts +39 -0
- package/dist/cjs/atoms/subtotal-dialog.atom.d.ts.map +1 -0
- package/dist/cjs/atoms/subtotal-dialog.atom.js +30 -0
- package/dist/cjs/atoms/text-to-columns-dialog.atom.d.ts +34 -0
- package/dist/cjs/atoms/text-to-columns-dialog.atom.d.ts.map +1 -0
- package/dist/cjs/atoms/text-to-columns-dialog.atom.js +36 -0
- package/dist/cjs/atoms/watch-window.atom.d.ts +37 -0
- package/dist/cjs/atoms/watch-window.atom.d.ts.map +1 -0
- package/dist/cjs/atoms/watch-window.atom.js +61 -0
- package/dist/cjs/components/advanced-filter-dialog/index.d.ts +28 -0
- package/dist/cjs/components/advanced-filter-dialog/index.d.ts.map +1 -0
- package/dist/cjs/components/advanced-filter-dialog/index.js +134 -0
- package/dist/cjs/components/calculation-options-dialog/index.d.ts +33 -0
- package/dist/cjs/components/calculation-options-dialog/index.d.ts.map +1 -0
- package/dist/cjs/components/calculation-options-dialog/index.js +69 -0
- package/dist/cjs/components/canvas-grid/index.d.ts.map +1 -1
- package/dist/cjs/components/canvas-grid/index.js +328 -71
- package/dist/cjs/components/canvas-grid/typings.d.ts +31 -5
- package/dist/cjs/components/canvas-grid/typings.d.ts.map +1 -1
- package/dist/cjs/components/cell/alignment.d.ts +30 -0
- package/dist/cjs/components/cell/alignment.d.ts.map +1 -1
- package/dist/cjs/components/cell/alignment.js +56 -1
- package/dist/cjs/components/cell/index.d.ts.map +1 -1
- package/dist/cjs/components/cell/index.js +15 -7
- package/dist/cjs/components/cell-diff/index.d.ts +3 -2
- package/dist/cjs/components/cell-diff/index.d.ts.map +1 -1
- package/dist/cjs/components/cell-editor/helpers.d.ts +9 -0
- package/dist/cjs/components/cell-editor/helpers.d.ts.map +1 -1
- package/dist/cjs/components/cell-editor/helpers.js +8 -1
- package/dist/cjs/components/cell-editor/helpers.spec.js +14 -0
- package/dist/cjs/components/cell-editor/index.d.ts.map +1 -1
- package/dist/cjs/components/cell-editor/index.js +7 -3
- package/dist/cjs/components/context-menu/index.d.ts +6 -1
- package/dist/cjs/components/context-menu/index.d.ts.map +1 -1
- package/dist/cjs/components/context-menu/index.js +146 -3
- package/dist/cjs/components/embeds/embed-component.d.ts.map +1 -1
- package/dist/cjs/components/embeds/embed-component.js +16 -1
- package/dist/cjs/components/fill-series-dialog/index.d.ts +29 -0
- package/dist/cjs/components/fill-series-dialog/index.d.ts.map +1 -0
- package/dist/cjs/components/fill-series-dialog/index.js +156 -0
- package/dist/cjs/components/go-to-dialog/index.d.ts +11 -1
- package/dist/cjs/components/go-to-dialog/index.d.ts.map +1 -1
- package/dist/cjs/components/go-to-dialog/index.js +67 -24
- package/dist/cjs/components/goal-seek-dialog/index.d.ts +32 -0
- package/dist/cjs/components/goal-seek-dialog/index.d.ts.map +1 -0
- package/dist/cjs/components/goal-seek-dialog/index.js +149 -0
- package/dist/cjs/components/selection/fill-options-menu.d.ts +32 -0
- package/dist/cjs/components/selection/fill-options-menu.d.ts.map +1 -0
- package/dist/cjs/components/selection/fill-options-menu.js +65 -0
- package/dist/cjs/components/selection/index.d.ts +1 -1
- package/dist/cjs/components/selection/index.d.ts.map +1 -1
- package/dist/cjs/components/selection/index.js +4 -2
- package/dist/cjs/components/selection/types.d.ts +11 -1
- package/dist/cjs/components/selection/types.d.ts.map +1 -1
- package/dist/cjs/components/subtotal-dialog/index.d.ts +30 -0
- package/dist/cjs/components/subtotal-dialog/index.d.ts.map +1 -0
- package/dist/cjs/components/subtotal-dialog/index.js +126 -0
- package/dist/cjs/components/text-to-columns-dialog/index.d.ts +37 -0
- package/dist/cjs/components/text-to-columns-dialog/index.d.ts.map +1 -0
- package/dist/cjs/components/text-to-columns-dialog/index.js +166 -0
- package/dist/cjs/components/toolbar/background-color-selector.d.ts +13 -1
- package/dist/cjs/components/toolbar/background-color-selector.d.ts.map +1 -1
- package/dist/cjs/components/toolbar/background-color-selector.js +57 -11
- package/dist/cjs/components/toolbar/cell-style-selector.d.ts +15 -2
- package/dist/cjs/components/toolbar/cell-style-selector.d.ts.map +1 -1
- package/dist/cjs/components/toolbar/cell-style-selector.js +56 -3
- package/dist/cjs/components/toolbar/fill-selectors.d.ts +49 -0
- package/dist/cjs/components/toolbar/fill-selectors.d.ts.map +1 -0
- package/dist/cjs/components/toolbar/fill-selectors.js +196 -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-format-selector.d.ts +9 -0
- package/dist/cjs/components/toolbar/text-format-selector.d.ts.map +1 -1
- package/dist/cjs/components/toolbar/text-format-selector.js +15 -3
- package/dist/cjs/components/toolbar/text-horizontal-align-selector.d.ts +8 -0
- package/dist/cjs/components/toolbar/text-horizontal-align-selector.d.ts.map +1 -1
- package/dist/cjs/components/toolbar/text-horizontal-align-selector.js +23 -4
- package/dist/cjs/components/watch-window/index.d.ts +25 -0
- package/dist/cjs/components/watch-window/index.d.ts.map +1 -0
- package/dist/cjs/components/watch-window/index.js +63 -0
- package/dist/cjs/hooks/use-cell-renderer.d.ts.map +1 -1
- package/dist/cjs/hooks/use-cell-renderer.js +17 -6
- package/dist/cjs/hooks/use-editable.d.ts +11 -2
- package/dist/cjs/hooks/use-editable.d.ts.map +1 -1
- package/dist/cjs/hooks/use-editable.js +8 -0
- package/dist/cjs/hooks/use-editor-submit.d.ts +32 -3
- package/dist/cjs/hooks/use-editor-submit.d.ts.map +1 -1
- package/dist/cjs/hooks/use-editor-submit.js +111 -2
- package/dist/cjs/hooks/use-get-tooltip.d.ts.map +1 -1
- package/dist/cjs/hooks/use-get-tooltip.js +7 -2
- package/dist/cjs/hooks/use-keyboard-handler.d.ts.map +1 -1
- package/dist/cjs/hooks/use-keyboard-handler.js +27 -14
- package/dist/cjs/hooks/use-selection-renderer.d.ts +13 -2
- package/dist/cjs/hooks/use-selection-renderer.d.ts.map +1 -1
- package/dist/cjs/hooks/use-selection-renderer.js +21 -4
- package/dist/cjs/hooks/use-selection.d.ts +54 -4
- package/dist/cjs/hooks/use-selection.d.ts.map +1 -1
- package/dist/cjs/hooks/use-selection.js +232 -37
- package/dist/cjs/index.d.ts +12 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +11 -0
- package/dist/cjs/release-date.js +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/cjs/types.d.ts +156 -5
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/cjs/types.js +19 -1
- package/dist/esm/api/excel-validation-kinds.d.ts +71 -0
- package/dist/esm/api/excel-validation-kinds.d.ts.map +1 -0
- package/dist/esm/api/excel-validation-kinds.js +287 -0
- package/dist/esm/api/fill-series.d.ts +38 -0
- package/dist/esm/api/fill-series.d.ts.map +1 -0
- package/dist/esm/api/fill-series.js +78 -0
- package/dist/esm/api/go-to-special.d.ts +32 -0
- package/dist/esm/api/go-to-special.d.ts.map +1 -0
- package/dist/esm/api/go-to-special.js +96 -0
- package/dist/esm/api/spreadsheet-api.d.ts +6 -2
- package/dist/esm/api/spreadsheet-api.d.ts.map +1 -1
- package/dist/esm/api/spreadsheet-api.js +8 -3
- package/dist/esm/api/validation-tooltip.d.ts +17 -0
- package/dist/esm/api/validation-tooltip.d.ts.map +1 -0
- package/dist/esm/api/validation-tooltip.js +34 -0
- package/dist/esm/atoms/advanced-filter-dialog.atom.d.ts +28 -0
- package/dist/esm/atoms/advanced-filter-dialog.atom.d.ts.map +1 -0
- package/dist/esm/atoms/advanced-filter-dialog.atom.js +21 -0
- package/dist/esm/atoms/fill-options.atom.d.ts +36 -0
- package/dist/esm/atoms/fill-options.atom.d.ts.map +1 -0
- package/dist/esm/atoms/fill-options.atom.js +5 -0
- package/dist/esm/atoms/fill-series-dialog.atom.d.ts +26 -0
- package/dist/esm/atoms/fill-series-dialog.atom.d.ts.map +1 -0
- package/dist/esm/atoms/fill-series-dialog.atom.js +9 -0
- package/dist/esm/atoms/go-to-dialog.atom.d.ts +11 -1
- package/dist/esm/atoms/go-to-dialog.atom.d.ts.map +1 -1
- package/dist/esm/atoms/goal-seek-dialog.atom.d.ts +29 -0
- package/dist/esm/atoms/goal-seek-dialog.atom.d.ts.map +1 -0
- package/dist/esm/atoms/goal-seek-dialog.atom.js +21 -0
- package/dist/esm/atoms/index.d.ts +3 -0
- package/dist/esm/atoms/index.d.ts.map +1 -1
- package/dist/esm/atoms/index.js +3 -0
- package/dist/esm/atoms/subtotal-dialog.atom.d.ts +39 -0
- package/dist/esm/atoms/subtotal-dialog.atom.d.ts.map +1 -0
- package/dist/esm/atoms/subtotal-dialog.atom.js +21 -0
- package/dist/esm/atoms/text-to-columns-dialog.atom.d.ts +34 -0
- package/dist/esm/atoms/text-to-columns-dialog.atom.d.ts.map +1 -0
- package/dist/esm/atoms/text-to-columns-dialog.atom.js +25 -0
- package/dist/esm/atoms/watch-window.atom.d.ts +37 -0
- package/dist/esm/atoms/watch-window.atom.d.ts.map +1 -0
- package/dist/esm/atoms/watch-window.atom.js +37 -0
- package/dist/esm/components/advanced-filter-dialog/index.d.ts +28 -0
- package/dist/esm/components/advanced-filter-dialog/index.d.ts.map +1 -0
- package/dist/esm/components/advanced-filter-dialog/index.js +125 -0
- package/dist/esm/components/calculation-options-dialog/index.d.ts +33 -0
- package/dist/esm/components/calculation-options-dialog/index.d.ts.map +1 -0
- package/dist/esm/components/calculation-options-dialog/index.js +61 -0
- package/dist/esm/components/canvas-grid/index.d.ts.map +1 -1
- package/dist/esm/components/canvas-grid/index.js +266 -26
- package/dist/esm/components/canvas-grid/typings.d.ts +31 -5
- package/dist/esm/components/canvas-grid/typings.d.ts.map +1 -1
- package/dist/esm/components/cell/alignment.d.ts +30 -0
- package/dist/esm/components/cell/alignment.d.ts.map +1 -1
- package/dist/esm/components/cell/alignment.js +51 -0
- package/dist/esm/components/cell/index.d.ts.map +1 -1
- package/dist/esm/components/cell/index.js +16 -8
- package/dist/esm/components/cell-diff/index.d.ts +3 -2
- package/dist/esm/components/cell-diff/index.d.ts.map +1 -1
- package/dist/esm/components/cell-editor/helpers.d.ts +9 -0
- package/dist/esm/components/cell-editor/helpers.d.ts.map +1 -1
- package/dist/esm/components/cell-editor/helpers.js +6 -0
- package/dist/esm/components/cell-editor/helpers.spec.js +15 -1
- package/dist/esm/components/cell-editor/index.d.ts.map +1 -1
- package/dist/esm/components/cell-editor/index.js +8 -4
- package/dist/esm/components/context-menu/index.d.ts +6 -1
- package/dist/esm/components/context-menu/index.d.ts.map +1 -1
- package/dist/esm/components/context-menu/index.js +139 -4
- package/dist/esm/components/embeds/embed-component.d.ts.map +1 -1
- package/dist/esm/components/embeds/embed-component.js +17 -1
- package/dist/esm/components/fill-series-dialog/index.d.ts +29 -0
- package/dist/esm/components/fill-series-dialog/index.d.ts.map +1 -0
- package/dist/esm/components/fill-series-dialog/index.js +151 -0
- package/dist/esm/components/go-to-dialog/index.d.ts +11 -1
- package/dist/esm/components/go-to-dialog/index.d.ts.map +1 -1
- package/dist/esm/components/go-to-dialog/index.js +63 -23
- package/dist/esm/components/goal-seek-dialog/index.d.ts +32 -0
- package/dist/esm/components/goal-seek-dialog/index.d.ts.map +1 -0
- package/dist/esm/components/goal-seek-dialog/index.js +125 -0
- package/dist/esm/components/selection/fill-options-menu.d.ts +32 -0
- package/dist/esm/components/selection/fill-options-menu.d.ts.map +1 -0
- package/dist/esm/components/selection/fill-options-menu.js +63 -0
- package/dist/esm/components/selection/index.d.ts +1 -1
- package/dist/esm/components/selection/index.d.ts.map +1 -1
- package/dist/esm/components/selection/index.js +4 -2
- package/dist/esm/components/selection/types.d.ts +11 -1
- package/dist/esm/components/selection/types.d.ts.map +1 -1
- package/dist/esm/components/subtotal-dialog/index.d.ts +30 -0
- package/dist/esm/components/subtotal-dialog/index.d.ts.map +1 -0
- package/dist/esm/components/subtotal-dialog/index.js +115 -0
- package/dist/esm/components/text-to-columns-dialog/index.d.ts +37 -0
- package/dist/esm/components/text-to-columns-dialog/index.d.ts.map +1 -0
- package/dist/esm/components/text-to-columns-dialog/index.js +147 -0
- package/dist/esm/components/toolbar/background-color-selector.d.ts +13 -1
- package/dist/esm/components/toolbar/background-color-selector.d.ts.map +1 -1
- package/dist/esm/components/toolbar/background-color-selector.js +61 -11
- package/dist/esm/components/toolbar/cell-style-selector.d.ts +15 -2
- package/dist/esm/components/toolbar/cell-style-selector.d.ts.map +1 -1
- package/dist/esm/components/toolbar/cell-style-selector.js +46 -2
- package/dist/esm/components/toolbar/fill-selectors.d.ts +49 -0
- package/dist/esm/components/toolbar/fill-selectors.d.ts.map +1 -0
- package/dist/esm/components/toolbar/fill-selectors.js +162 -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-format-selector.d.ts +9 -0
- package/dist/esm/components/toolbar/text-format-selector.d.ts.map +1 -1
- package/dist/esm/components/toolbar/text-format-selector.js +14 -2
- package/dist/esm/components/toolbar/text-horizontal-align-selector.d.ts +8 -0
- package/dist/esm/components/toolbar/text-horizontal-align-selector.d.ts.map +1 -1
- package/dist/esm/components/toolbar/text-horizontal-align-selector.js +21 -5
- package/dist/esm/components/watch-window/index.d.ts +25 -0
- package/dist/esm/components/watch-window/index.d.ts.map +1 -0
- package/dist/esm/components/watch-window/index.js +54 -0
- package/dist/esm/hooks/use-cell-renderer.d.ts.map +1 -1
- package/dist/esm/hooks/use-cell-renderer.js +17 -6
- package/dist/esm/hooks/use-editable.d.ts +11 -2
- package/dist/esm/hooks/use-editable.d.ts.map +1 -1
- package/dist/esm/hooks/use-editable.js +8 -0
- package/dist/esm/hooks/use-editor-submit.d.ts +32 -3
- package/dist/esm/hooks/use-editor-submit.d.ts.map +1 -1
- package/dist/esm/hooks/use-editor-submit.js +82 -3
- package/dist/esm/hooks/use-get-tooltip.d.ts.map +1 -1
- package/dist/esm/hooks/use-get-tooltip.js +7 -2
- package/dist/esm/hooks/use-keyboard-handler.d.ts.map +1 -1
- package/dist/esm/hooks/use-keyboard-handler.js +27 -14
- package/dist/esm/hooks/use-selection-renderer.d.ts +13 -2
- package/dist/esm/hooks/use-selection-renderer.d.ts.map +1 -1
- package/dist/esm/hooks/use-selection-renderer.js +22 -5
- package/dist/esm/hooks/use-selection.d.ts +54 -4
- package/dist/esm/hooks/use-selection.d.ts.map +1 -1
- package/dist/esm/hooks/use-selection.js +220 -36
- package/dist/esm/index.d.ts +12 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +11 -0
- package/dist/esm/release-date.js +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/types.d.ts +156 -5
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/types.js +18 -0
- package/dist/spreadsheet.min.css +1 -1
- package/package.json +7 -7
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { Cross1Icon } from "@rowsncolumns/icons";
|
|
2
|
+
import { Button, Dialog, DialogBody, DialogCloseButton, DialogContent, DialogDescription, DialogTitle, Input, Separator, } from "@rowsncolumns/ui";
|
|
3
|
+
import React, { memo, useCallback, useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { useRegisterTextToColumnsDialogHost, useTextToColumnsDialogState, } from "../../atoms/text-to-columns-dialog.atom";
|
|
5
|
+
const DELIMITERS = [
|
|
6
|
+
{ label: "Comma", value: "," },
|
|
7
|
+
{ label: "Semicolon", value: ";" },
|
|
8
|
+
{ label: "Tab", value: "\t" },
|
|
9
|
+
{ label: "Space", value: " " },
|
|
10
|
+
{ label: "Period", value: "." },
|
|
11
|
+
{ label: "Pipe", value: "|" },
|
|
12
|
+
];
|
|
13
|
+
/** Cuts `text` at ascending character positions (the dialog's own preview). */
|
|
14
|
+
const cutAt = (text, breaks) => {
|
|
15
|
+
const parts = [];
|
|
16
|
+
let start = 0;
|
|
17
|
+
for (const position of breaks) {
|
|
18
|
+
parts.push(text.slice(start, position));
|
|
19
|
+
start = position;
|
|
20
|
+
}
|
|
21
|
+
parts.push(text.slice(start));
|
|
22
|
+
return parts;
|
|
23
|
+
};
|
|
24
|
+
const parseBreaks = (text) => [
|
|
25
|
+
...new Set(text
|
|
26
|
+
.split(/[\s,;]+/)
|
|
27
|
+
.map((part) => Number.parseInt(part, 10))
|
|
28
|
+
.filter((n) => Number.isInteger(n) && n > 0)),
|
|
29
|
+
].sort((a, b) => a - b);
|
|
30
|
+
/**
|
|
31
|
+
* Excel's Convert Text to Columns wizard, condensed: choose Delimited (pick
|
|
32
|
+
* a delimiter or type another) or Fixed width (click the ruler to add or
|
|
33
|
+
* remove break lines, or type the positions), with a live preview of the
|
|
34
|
+
* first rows.
|
|
35
|
+
*/
|
|
36
|
+
export const TextToColumnsDialog = memo(({ open, onOpenChange, preview, initialMode = "delimited", onApply, }) => {
|
|
37
|
+
const [mode, setMode] = useState(initialMode);
|
|
38
|
+
const [delimiter, setDelimiter] = useState(",");
|
|
39
|
+
const [customDelimiter, setCustomDelimiter] = useState("");
|
|
40
|
+
const [breaks, setBreaks] = useState([]);
|
|
41
|
+
const [breaksText, setBreaksText] = useState("");
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (open) {
|
|
44
|
+
setMode(initialMode);
|
|
45
|
+
setDelimiter(",");
|
|
46
|
+
setCustomDelimiter("");
|
|
47
|
+
setBreaks([]);
|
|
48
|
+
setBreaksText("");
|
|
49
|
+
}
|
|
50
|
+
// Only reset on open transitions.
|
|
51
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
52
|
+
}, [open]);
|
|
53
|
+
const sample = useMemo(() => preview.slice(0, 6), [preview]);
|
|
54
|
+
const rulerLength = useMemo(() => Math.min(120, Math.max(10, ...sample.map((text) => text.length))), [sample]);
|
|
55
|
+
const toggleBreak = useCallback((position) => {
|
|
56
|
+
setBreaks((prev) => {
|
|
57
|
+
const next = prev.includes(position)
|
|
58
|
+
? prev.filter((p) => p !== position)
|
|
59
|
+
: [...prev, position].sort((a, b) => a - b);
|
|
60
|
+
setBreaksText(next.join(", "));
|
|
61
|
+
return next;
|
|
62
|
+
});
|
|
63
|
+
}, []);
|
|
64
|
+
const effectiveDelimiter = delimiter === "custom" ? customDelimiter : delimiter;
|
|
65
|
+
const canApply = mode === "delimited" ? effectiveDelimiter.length > 0 : breaks.length > 0;
|
|
66
|
+
const commit = useCallback(() => {
|
|
67
|
+
if (mode === "fixed") {
|
|
68
|
+
onApply({ delimiter: ",", columnBreaks: breaks });
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
onApply({ delimiter: effectiveDelimiter });
|
|
72
|
+
}
|
|
73
|
+
onOpenChange(false);
|
|
74
|
+
}, [mode, breaks, effectiveDelimiter, onApply, onOpenChange]);
|
|
75
|
+
return (React.createElement(Dialog, { open: open, onOpenChange: onOpenChange },
|
|
76
|
+
React.createElement(DialogContent, { className: "w-[520px] max-w-[92vw] pointer-events-auto" },
|
|
77
|
+
React.createElement(DialogTitle, null, "Text to columns"),
|
|
78
|
+
React.createElement(DialogDescription, null, "Split the selected column into several columns."),
|
|
79
|
+
React.createElement(DialogCloseButton, { onClick: () => onOpenChange(false) },
|
|
80
|
+
React.createElement(Cross1Icon, null)),
|
|
81
|
+
React.createElement(DialogBody, { className: "flex flex-col gap-3 font-system text-sm" },
|
|
82
|
+
React.createElement("div", { className: "flex gap-4", role: "radiogroup", "aria-label": "Original data type" },
|
|
83
|
+
React.createElement("label", { className: "flex items-center gap-1" },
|
|
84
|
+
React.createElement("input", { type: "radio", name: "text-to-columns-mode", value: "delimited", checked: mode === "delimited", onChange: () => setMode("delimited") }),
|
|
85
|
+
"Delimited"),
|
|
86
|
+
React.createElement("label", { className: "flex items-center gap-1" },
|
|
87
|
+
React.createElement("input", { type: "radio", name: "text-to-columns-mode", value: "fixed", checked: mode === "fixed", onChange: () => setMode("fixed") }),
|
|
88
|
+
"Fixed width")),
|
|
89
|
+
mode === "delimited" ? (React.createElement("div", { className: "flex flex-col gap-2" },
|
|
90
|
+
React.createElement("label", { className: "flex flex-col gap-1 text-xs font-medium" },
|
|
91
|
+
"Delimiter",
|
|
92
|
+
React.createElement("select", { className: "h-8 rounded border border-rnc-border bg-transparent px-2 text-sm", value: delimiter, onChange: (e) => setDelimiter(e.target.value), "aria-label": "Delimiter" },
|
|
93
|
+
DELIMITERS.map((option) => (React.createElement("option", { key: option.value, value: option.value }, option.label))),
|
|
94
|
+
React.createElement("option", { value: "custom" }, "Other\u2026"))),
|
|
95
|
+
delimiter === "custom" ? (React.createElement("label", { className: "flex flex-col gap-1 text-xs font-medium" },
|
|
96
|
+
"Other delimiter",
|
|
97
|
+
React.createElement(Input, { value: customDelimiter, maxLength: 5, "aria-label": "Other delimiter", onChange: (e) => setCustomDelimiter(e.target.value) }))) : null)) : (React.createElement("div", { className: "flex flex-col gap-2" },
|
|
98
|
+
React.createElement("div", { className: "text-xs text-rnc-foreground/70" }, "Click the ruler to create a break line; click it again to remove it."),
|
|
99
|
+
React.createElement("div", { className: "overflow-x-auto rounded border border-rnc-border p-2 font-mono text-xs leading-5", "data-testid": "fixed-width-ruler" },
|
|
100
|
+
React.createElement("div", { className: "flex select-none" }, Array.from({ length: rulerLength }, (_, index) => {
|
|
101
|
+
const position = index + 1;
|
|
102
|
+
const active = breaks.includes(position);
|
|
103
|
+
return (React.createElement("button", { key: position, type: "button", "aria-label": `Break after character ${position}`, "aria-pressed": active, className: `w-[1ch] shrink-0 border-r ${active ? "border-rnc-primary bg-rnc-primary/20" : "border-transparent"} hover:bg-rnc-accent`, onClick: () => toggleBreak(position) }, position % 10 === 0 ? String(position / 10) : "·"));
|
|
104
|
+
})),
|
|
105
|
+
sample.map((text, rowIndex) => (React.createElement("div", { key: rowIndex, className: "flex whitespace-pre" }, Array.from({ length: rulerLength }, (_, index) => {
|
|
106
|
+
const position = index + 1;
|
|
107
|
+
const active = breaks.includes(position);
|
|
108
|
+
return (React.createElement("span", { key: position, className: `w-[1ch] shrink-0 border-r ${active ? "border-rnc-primary" : "border-transparent"}` }, text[index] ?? " "));
|
|
109
|
+
}))))),
|
|
110
|
+
React.createElement("label", { className: "flex flex-col gap-1 text-xs font-medium" },
|
|
111
|
+
"Break positions (characters before each break)",
|
|
112
|
+
React.createElement(Input, { value: breaksText, placeholder: "e.g. 4, 10", "aria-label": "Break positions", onChange: (e) => {
|
|
113
|
+
setBreaksText(e.target.value);
|
|
114
|
+
setBreaks(parseBreaks(e.target.value));
|
|
115
|
+
} })))),
|
|
116
|
+
React.createElement("div", { className: "flex flex-col gap-1" },
|
|
117
|
+
React.createElement("span", { className: "text-xs font-medium" }, "Data preview"),
|
|
118
|
+
React.createElement("div", { className: "max-h-[120px] overflow-auto rounded border border-rnc-border p-2 font-mono text-xs", "data-testid": "text-to-columns-preview" }, sample.map((text, rowIndex) => {
|
|
119
|
+
const parts = mode === "fixed"
|
|
120
|
+
? cutAt(text, breaks)
|
|
121
|
+
: effectiveDelimiter
|
|
122
|
+
? text.split(effectiveDelimiter)
|
|
123
|
+
: [text];
|
|
124
|
+
return (React.createElement("div", { key: rowIndex, className: "flex gap-1 whitespace-pre" }, parts.map((part, partIndex) => (React.createElement("span", { key: partIndex, className: "border-r border-rnc-border pr-1 last:border-r-0" }, part.trim() || " ")))));
|
|
125
|
+
}))),
|
|
126
|
+
React.createElement(Separator, null),
|
|
127
|
+
React.createElement("div", { className: "flex justify-end gap-2" },
|
|
128
|
+
React.createElement(Button, { variant: "outline", size: "sm", type: "button", onClick: () => onOpenChange(false) }, "Cancel"),
|
|
129
|
+
React.createElement(Button, { size: "sm", type: "button", onClick: commit, disabled: !canApply }, "Finish"))))));
|
|
130
|
+
});
|
|
131
|
+
TextToColumnsDialog.displayName = "TextToColumnsDialog";
|
|
132
|
+
/**
|
|
133
|
+
* Host-mounted, atom-driven wrapper around {@link TextToColumnsDialog}.
|
|
134
|
+
* Mount once in the host (alongside the other editor dialogs); the context
|
|
135
|
+
* menu opens it via `useOpenTextToColumnsDialog`. Without a host the menu
|
|
136
|
+
* keeps its one-click delimiter items only.
|
|
137
|
+
*/
|
|
138
|
+
export const TextToColumnsDialogHost = () => {
|
|
139
|
+
useRegisterTextToColumnsDialogHost();
|
|
140
|
+
const [request, setRequest] = useTextToColumnsDialogState();
|
|
141
|
+
const close = useCallback(() => setRequest(null), [setRequest]);
|
|
142
|
+
return (React.createElement(TextToColumnsDialog, { open: request != null, onOpenChange: (open) => {
|
|
143
|
+
if (!open)
|
|
144
|
+
close();
|
|
145
|
+
}, preview: request?.preview ?? [], initialMode: "fixed", onApply: (options) => request?.onApply(options) }));
|
|
146
|
+
};
|
|
147
|
+
TextToColumnsDialogHost.displayName = "TextToColumnsDialogHost";
|
|
@@ -4,16 +4,28 @@ import type { Color } from "../../types";
|
|
|
4
4
|
import type { SpreadsheetTheme } from "../canvas-grid/typings";
|
|
5
5
|
import type { ColorSelectorProps } from "./color-selector";
|
|
6
6
|
import { ColorSelector } from "./color-selector";
|
|
7
|
+
import { type CellFill } from "./fill-selectors";
|
|
7
8
|
type BackgroundColorSelectorProps = {
|
|
8
9
|
disabled?: boolean;
|
|
9
10
|
color?: Color | null;
|
|
10
11
|
theme?: SpreadsheetTheme;
|
|
11
12
|
onChange?(color: Color | undefined): void;
|
|
13
|
+
/**
|
|
14
|
+
* The active cell's fill (pattern / gradient fields) — enables the
|
|
15
|
+
* Pattern and Gradient tabs together with `onChangeFill`. Without
|
|
16
|
+
* `onChangeFill` the popover is the solid colour picker only.
|
|
17
|
+
*/
|
|
18
|
+
fill?: CellFill | null;
|
|
19
|
+
/**
|
|
20
|
+
* Apply a pattern or gradient fill (Excel: Format Cells → Fill → Pattern /
|
|
21
|
+
* Fill Effects). Receives the full fill slice so cleared fields reset.
|
|
22
|
+
*/
|
|
23
|
+
onChangeFill?(fill: CellFill): void;
|
|
12
24
|
/**
|
|
13
25
|
* Custom color selector component
|
|
14
26
|
*/
|
|
15
27
|
ColorSelector?: ComponentType<ColorSelectorProps>;
|
|
16
28
|
} & Pick<ComponentProps<typeof ColorSelector>, "userDefinedColors" | "onAddUserDefinedColor">;
|
|
17
|
-
export declare const BackgroundColorSelector: ({ color, theme, onChange, onAddUserDefinedColor, userDefinedColors, disabled, ColorSelector: ColorSelectorComponent, }: BackgroundColorSelectorProps) => React.JSX.Element;
|
|
29
|
+
export declare const BackgroundColorSelector: ({ color, theme, onChange, fill, onChangeFill, onAddUserDefinedColor, userDefinedColors, disabled, ColorSelector: ColorSelectorComponent, }: BackgroundColorSelectorProps) => React.JSX.Element;
|
|
18
30
|
export {};
|
|
19
31
|
//# sourceMappingURL=background-color-selector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"background-color-selector.d.ts","sourceRoot":"","sources":["../../../../components/toolbar/background-color-selector.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"background-color-selector.d.ts","sourceRoot":"","sources":["../../../../components/toolbar/background-color-selector.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EACL,KAAK,QAAQ,EAId,MAAM,kBAAkB,CAAC;AAE1B,KAAK,4BAA4B,GAAG;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,QAAQ,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC;IAC1C;;;;OAIG;IACH,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACvB;;;OAGG;IACH,YAAY,CAAC,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACpC;;OAEG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;CACnD,GAAG,IAAI,CACN,cAAc,CAAC,OAAO,aAAa,CAAC,EACpC,mBAAmB,GAAG,uBAAuB,CAC9C,CAAC;AACF,eAAO,MAAM,uBAAuB,GAAI,4IAUrC,4BAA4B,sBA+G9B,CAAC"}
|
|
@@ -1,28 +1,78 @@
|
|
|
1
1
|
import { IoMdColorFill } from "@rowsncolumns/icons";
|
|
2
2
|
import { Popover, PopoverContent, PopoverTrigger } from "@rowsncolumns/ui";
|
|
3
|
-
import { IconButton } from "@rowsncolumns/ui";
|
|
3
|
+
import { IconButton, Tabs, TabsContent, TabsList, TabsTrigger, } from "@rowsncolumns/ui";
|
|
4
4
|
import React from "react";
|
|
5
5
|
import { useState } from "react";
|
|
6
6
|
import { useFocusSheet } from "../../atoms";
|
|
7
7
|
import { defaultSpreadsheetTheme } from "../../config";
|
|
8
8
|
import { getStringifiedColor } from "../../themes";
|
|
9
9
|
import { ColorSelector } from "./color-selector";
|
|
10
|
-
|
|
10
|
+
import { gradientToCss, GradientFillPicker, PatternFillPicker, } from "./fill-selectors";
|
|
11
|
+
export const BackgroundColorSelector = ({ color = "transparent", theme = defaultSpreadsheetTheme, onChange, fill, onChangeFill, onAddUserDefinedColor, userDefinedColors, disabled, ColorSelector: ColorSelectorComponent = ColorSelector, }) => {
|
|
11
12
|
const [isOpen, setIsOpen] = useState(false);
|
|
12
13
|
const close = () => setIsOpen(false);
|
|
13
14
|
const open = () => setIsOpen(true);
|
|
14
15
|
const colorString = getStringifiedColor(color, theme);
|
|
15
16
|
const focusSheet = useFocusSheet();
|
|
17
|
+
// The trigger underline previews the effective fill: gradient, then the
|
|
18
|
+
// pattern colour, then the solid colour.
|
|
19
|
+
const swatchStyle = fill?.gradient
|
|
20
|
+
? {
|
|
21
|
+
borderBottom: "4px solid transparent",
|
|
22
|
+
borderImage: `${gradientToCss(fill.gradient)} 1`,
|
|
23
|
+
}
|
|
24
|
+
: {
|
|
25
|
+
borderBottom: `4px ${fill?.fillPattern &&
|
|
26
|
+
fill.fillPattern !== "none" &&
|
|
27
|
+
fill.foregroundColor
|
|
28
|
+
? getStringifiedColor(fill.foregroundColor, theme)
|
|
29
|
+
: colorString} solid`,
|
|
30
|
+
};
|
|
31
|
+
const solidPicker = (React.createElement(ColorSelectorComponent, { color: color, onChange: (color) => {
|
|
32
|
+
// A solid pick replaces a gradient (Excel keeps them exclusive) and,
|
|
33
|
+
// with "No fill", clears the pattern too.
|
|
34
|
+
if (onChangeFill && (fill?.gradient || (!color && fill?.fillPattern))) {
|
|
35
|
+
onChangeFill({
|
|
36
|
+
backgroundColor: color,
|
|
37
|
+
fillPattern: color ? fill?.fillPattern ?? undefined : undefined,
|
|
38
|
+
foregroundColor: color
|
|
39
|
+
? fill?.foregroundColor ?? undefined
|
|
40
|
+
: undefined,
|
|
41
|
+
gradient: undefined,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
onChange?.(color);
|
|
46
|
+
}
|
|
47
|
+
focusSheet?.();
|
|
48
|
+
close();
|
|
49
|
+
}, theme: theme, resetButtonTitle: "No fill", userDefinedColors: userDefinedColors, onAddUserDefinedColor: onAddUserDefinedColor }));
|
|
50
|
+
const applyFill = (next) => {
|
|
51
|
+
onChangeFill?.(next);
|
|
52
|
+
focusSheet?.();
|
|
53
|
+
};
|
|
16
54
|
return (React.createElement(Popover, { modal: false, open: isOpen, onOpenChange: setIsOpen },
|
|
17
55
|
React.createElement(PopoverTrigger, { asChild: true },
|
|
18
|
-
React.createElement(IconButton, { className: "text-base flex-row", style:
|
|
19
|
-
borderBottom: `4px ${colorString} solid`,
|
|
20
|
-
}, tooltip: "Fill color", onClick: open, disabled: disabled },
|
|
56
|
+
React.createElement(IconButton, { className: "text-base flex-row", style: swatchStyle, tooltip: "Fill color", "aria-label": "Fill color", onClick: open, disabled: disabled },
|
|
21
57
|
React.createElement(IoMdColorFill, null))),
|
|
22
|
-
React.createElement(PopoverContent, { align: "start" },
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
58
|
+
React.createElement(PopoverContent, { align: "start" }, onChangeFill ? (React.createElement(Tabs, { defaultValue: fill?.gradient
|
|
59
|
+
? "gradient"
|
|
60
|
+
: fill?.fillPattern && fill.fillPattern !== "none"
|
|
61
|
+
? "pattern"
|
|
62
|
+
: "solid" },
|
|
63
|
+
React.createElement(TabsList, { className: "grid-cols-3 mb-2" },
|
|
64
|
+
React.createElement(TabsTrigger, { value: "solid" }, "Solid"),
|
|
65
|
+
React.createElement(TabsTrigger, { value: "pattern" }, "Pattern"),
|
|
66
|
+
React.createElement(TabsTrigger, { value: "gradient" }, "Gradient")),
|
|
67
|
+
React.createElement(TabsContent, { value: "solid" }, solidPicker),
|
|
68
|
+
React.createElement(TabsContent, { value: "pattern" },
|
|
69
|
+
React.createElement(PatternFillPicker, { fill: {
|
|
70
|
+
...fill,
|
|
71
|
+
backgroundColor: fill?.backgroundColor ?? color,
|
|
72
|
+
}, theme: theme, onChangeFill: applyFill })),
|
|
73
|
+
React.createElement(TabsContent, { value: "gradient" },
|
|
74
|
+
React.createElement(GradientFillPicker, { fill: {
|
|
75
|
+
...fill,
|
|
76
|
+
backgroundColor: fill?.backgroundColor ?? color,
|
|
77
|
+
}, theme: theme, onChangeFill: applyFill })))) : (solidPicker))));
|
|
28
78
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import type { CellFormat } from "../../types";
|
|
2
|
+
import type { CellFormat, NamedCellStyle } from "../../types";
|
|
3
3
|
import type { SpreadsheetTheme } from "../canvas-grid/typings";
|
|
4
4
|
type WithCellFormat = (value: CellFormat) => void;
|
|
5
5
|
type WithTypeValue<T extends keyof CellFormat> = (type: T, value: CellFormat[T]) => void;
|
|
@@ -8,6 +8,13 @@ export type CellStyleSelectorProps = {
|
|
|
8
8
|
locale?: string;
|
|
9
9
|
theme: SpreadsheetTheme;
|
|
10
10
|
userDefinedStyles?: [string, CellFormat][];
|
|
11
|
+
/**
|
|
12
|
+
* Workbook named cell styles imported from `<cellStyles>` ("Heading 1",
|
|
13
|
+
* "Good", "Accent 1", …). Shown as a "Workbook styles" section ahead of
|
|
14
|
+
* the built-in gallery; hidden entries and the "Normal" base style are
|
|
15
|
+
* skipped, as is any entry whose xf resolved to no formatting.
|
|
16
|
+
*/
|
|
17
|
+
namedCellStyles?: NamedCellStyle[] | null;
|
|
11
18
|
selectedFormat?: CellFormat | null;
|
|
12
19
|
onAddUserDefinedStyle?(name: string): void;
|
|
13
20
|
onChangeFormatting: (...args: Parameters<WithCellFormat | WithTypeValue<keyof CellFormat>>) => void;
|
|
@@ -19,7 +26,13 @@ type StyleList = [
|
|
|
19
26
|
format: CellFormat,
|
|
20
27
|
style?: React.CSSProperties
|
|
21
28
|
];
|
|
29
|
+
/** Named styles worth showing in the gallery (see `namedCellStyles` prop). */
|
|
30
|
+
export declare const getGalleryNamedCellStyles: (namedCellStyles: NamedCellStyle[] | null | undefined) => Array<NamedCellStyle & {
|
|
31
|
+
format: CellFormat;
|
|
32
|
+
}>;
|
|
33
|
+
/** CSS preview of a named style's format for the gallery swatch. */
|
|
34
|
+
export declare const getNamedCellStylePreview: (format: CellFormat | undefined, theme: SpreadsheetTheme) => React.CSSProperties;
|
|
22
35
|
export declare const getCellStyles: (theme: SpreadsheetTheme, currencySymbol?: string) => Map<string, StyleList[]>;
|
|
23
|
-
export declare const CellStyleSelector: React.MemoExoticComponent<({ currency, locale, theme, selectedFormat, canAddCustomStyle, onChangeFormatting, onClearFormatting, }: CellStyleSelectorProps) => React.JSX.Element>;
|
|
36
|
+
export declare const CellStyleSelector: React.MemoExoticComponent<({ currency, locale, theme, selectedFormat, namedCellStyles, canAddCustomStyle, onChangeFormatting, onClearFormatting, }: CellStyleSelectorProps) => React.JSX.Element>;
|
|
24
37
|
export {};
|
|
25
38
|
//# sourceMappingURL=cell-style-selector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell-style-selector.d.ts","sourceRoot":"","sources":["../../../../components/toolbar/cell-style-selector.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAMrD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"cell-style-selector.d.ts","sourceRoot":"","sources":["../../../../components/toolbar/cell-style-selector.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAMrD,OAAO,KAAK,EACV,UAAU,EAEV,cAAc,EAEf,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,KAAK,cAAc,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;AAClD,KAAK,aAAa,CAAC,CAAC,SAAS,MAAM,UAAU,IAAI,CAC/C,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KACjB,IAAI,CAAC;AAEV,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,gBAAgB,CAAC;IACxB,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC;IAC3C;;;;;OAKG;IACH,eAAe,CAAC,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;IAC1C,cAAc,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACnC,qBAAqB,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,kBAAkB,EAAE,CAClB,GAAG,IAAI,EAAE,UAAU,CAAC,cAAc,GAAG,aAAa,CAAC,MAAM,UAAU,CAAC,CAAC,KAClE,IAAI,CAAC;IACV,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,MAAM,IAAI,CAAC;CAC/B,CAAC;AAEF,KAAK,SAAS,GAAG;IACf,QAAQ,EAAE,MAAM;IAChB,MAAM,EAAE,UAAU;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa;CAC5B,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,yBAAyB,GACpC,iBAAiB,cAAc,EAAE,GAAG,IAAI,GAAG,SAAS,KACnD,KAAK,CAAC,cAAc,GAAG;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,CAQ7C,CAAC;AAcJ,oEAAoE;AACpE,eAAO,MAAM,wBAAwB,GACnC,QAAQ,UAAU,GAAG,SAAS,EAC9B,OAAO,gBAAgB,KACtB,KAAK,CAAC,aAqBR,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,OAAO,gBAAgB,EACvB,iBAAiB,MAAM,6BAgYxB,CAAC;AAEF,eAAO,MAAM,iBAAiB,sJAUzB,sBAAsB,uBAsO1B,CAAC"}
|
|
@@ -8,6 +8,45 @@ import React, { memo, useMemo, useRef } from "react";
|
|
|
8
8
|
import { useFocusSheet } from "../../atoms";
|
|
9
9
|
import { getCurrencySymbol } from "../../helpers";
|
|
10
10
|
import { getStringifiedColor } from "../../themes";
|
|
11
|
+
/** Named styles worth showing in the gallery (see `namedCellStyles` prop). */
|
|
12
|
+
export const getGalleryNamedCellStyles = (namedCellStyles) => (namedCellStyles ?? []).filter((style) => !style.hidden &&
|
|
13
|
+
style.builtinId !== 0 &&
|
|
14
|
+
style.name !== "Normal" &&
|
|
15
|
+
!!style.format &&
|
|
16
|
+
Object.keys(style.format).length > 0);
|
|
17
|
+
const previewBorder = (border, theme) => border
|
|
18
|
+
? `${border.width ?? 1}px ${border.style === "double" ? "double" : "solid"} ${getStringifiedColor(border.color, theme)}`
|
|
19
|
+
: undefined;
|
|
20
|
+
/** CSS preview of a named style's format for the gallery swatch. */
|
|
21
|
+
export const getNamedCellStylePreview = (format, theme) => {
|
|
22
|
+
if (!format)
|
|
23
|
+
return {};
|
|
24
|
+
const style = {};
|
|
25
|
+
if (format.backgroundColor) {
|
|
26
|
+
style.backgroundColor = getStringifiedColor(format.backgroundColor, theme);
|
|
27
|
+
}
|
|
28
|
+
const text = format.textFormat;
|
|
29
|
+
if (text?.color)
|
|
30
|
+
style.color = getStringifiedColor(text.color, theme);
|
|
31
|
+
if (text?.bold)
|
|
32
|
+
style.fontWeight = "bold";
|
|
33
|
+
if (text?.italic)
|
|
34
|
+
style.fontStyle = "italic";
|
|
35
|
+
if (text?.underline)
|
|
36
|
+
style.textDecoration = "underline";
|
|
37
|
+
if (text?.fontSize)
|
|
38
|
+
style.fontSize = text.fontSize;
|
|
39
|
+
if (text?.fontFamily)
|
|
40
|
+
style.fontFamily = text.fontFamily;
|
|
41
|
+
const borders = format.borders;
|
|
42
|
+
if (borders) {
|
|
43
|
+
style.borderTop = previewBorder(borders.top, theme);
|
|
44
|
+
style.borderBottom = previewBorder(borders.bottom, theme);
|
|
45
|
+
style.borderLeft = previewBorder(borders.left, theme);
|
|
46
|
+
style.borderRight = previewBorder(borders.right, theme);
|
|
47
|
+
}
|
|
48
|
+
return style;
|
|
49
|
+
};
|
|
11
50
|
export const getCellStyles = (theme, currencySymbol) => {
|
|
12
51
|
return new Map([
|
|
13
52
|
[
|
|
@@ -383,13 +422,14 @@ export const getCellStyles = (theme, currencySymbol) => {
|
|
|
383
422
|
],
|
|
384
423
|
]);
|
|
385
424
|
};
|
|
386
|
-
export const CellStyleSelector = memo(({ currency, locale, theme, selectedFormat, canAddCustomStyle = false, onChangeFormatting, onClearFormatting, }) => {
|
|
425
|
+
export const CellStyleSelector = memo(({ currency, locale, theme, selectedFormat, namedCellStyles, canAddCustomStyle = false, onChangeFormatting, onClearFormatting, }) => {
|
|
387
426
|
const colorIndexes = [4, 5, 6, 7, 8, 9];
|
|
388
427
|
const colorTints = [0.8, 0.6, 0.4, 0];
|
|
389
428
|
const currencySymbol = getCurrencySymbol(locale, currency);
|
|
390
429
|
const shouldFocusSheetRef = useRef(true);
|
|
391
430
|
const focusSheet = useFocusSheet();
|
|
392
431
|
const cellStyles = useMemo(() => [...getCellStyles(theme, currencySymbol).entries()], [theme, currencySymbol]);
|
|
432
|
+
const workbookStyles = useMemo(() => getGalleryNamedCellStyles(namedCellStyles), [namedCellStyles]);
|
|
393
433
|
// Number formats
|
|
394
434
|
const numberFormats = [
|
|
395
435
|
[
|
|
@@ -434,7 +474,7 @@ export const CellStyleSelector = memo(({ currency, locale, theme, selectedFormat
|
|
|
434
474
|
const gridClass = "grid grid-cols-3 md:grid-cols-6 gap-1 pb-1";
|
|
435
475
|
return (React.createElement(DropdownMenu, { modal: false },
|
|
436
476
|
React.createElement(DropdownMenuTrigger, { asChild: true },
|
|
437
|
-
React.createElement(IconButton, { size: "xl", tooltip: "Cell styles", className: "gap-1" },
|
|
477
|
+
React.createElement(IconButton, { size: "xl", tooltip: "Cell styles", "aria-label": "Cell styles", className: "gap-1" },
|
|
438
478
|
React.createElement(MdBrush, null),
|
|
439
479
|
React.createElement("div", { className: "text-xs" }, "Cell styles"),
|
|
440
480
|
React.createElement(MdOutlineArrowDropDown, null))),
|
|
@@ -448,6 +488,10 @@ export const CellStyleSelector = memo(({ currency, locale, theme, selectedFormat
|
|
|
448
488
|
shouldFocusSheetRef.current = false;
|
|
449
489
|
} },
|
|
450
490
|
React.createElement("div", { className: "max-w-dropdown md:min-w-[400px] p-2 pt-0" },
|
|
491
|
+
workbookStyles.length ? (React.createElement("div", null,
|
|
492
|
+
React.createElement("div", { className: headingClass }, "Workbook styles"),
|
|
493
|
+
React.createElement(Separator, { className: "mb-2" }),
|
|
494
|
+
React.createElement("div", { className: gridClass }, workbookStyles.map((namedStyle) => (React.createElement(DropdownMenuItem, { onClick: () => onChangeFormatting(namedStyle.format), className: hoverClass, key: `${namedStyle.name}-${namedStyle.xfId}`, style: getNamedCellStylePreview(namedStyle.format, theme) }, namedStyle.name)))))) : null,
|
|
451
495
|
cellStyles.map(([category, cellStyleList]) => {
|
|
452
496
|
return (React.createElement("div", { key: category },
|
|
453
497
|
React.createElement("div", { className: headingClass }, category),
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { CellFormat, FillPattern, GradientFill } from "../../types";
|
|
3
|
+
import type { SpreadsheetTheme } from "../canvas-grid/typings";
|
|
4
|
+
/** The fill-related slice of a cell format the fill popover authors. */
|
|
5
|
+
export type CellFill = Pick<CellFormat, "backgroundColor" | "fillPattern" | "foregroundColor" | "gradient">;
|
|
6
|
+
/** Excel's Format Cells → Fill → Pattern Style menu, in Excel's order. */
|
|
7
|
+
export declare const FILL_PATTERN_OPTIONS: ReadonlyArray<{
|
|
8
|
+
pattern: FillPattern;
|
|
9
|
+
label: string;
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* Excel's Fill Effects → Shading styles. `degree` follows OOXML
|
|
13
|
+
* `<gradientFill degree>`: 0 runs left → right, 90 top → bottom.
|
|
14
|
+
*/
|
|
15
|
+
export declare const GRADIENT_PRESETS: ReadonlyArray<{
|
|
16
|
+
label: string;
|
|
17
|
+
gradient: Omit<GradientFill, "stops">;
|
|
18
|
+
}>;
|
|
19
|
+
/** Two-stop gradient from a preset and two colours. */
|
|
20
|
+
export declare const buildGradientFill: (preset: Omit<GradientFill, "stops">, color1: string, color2: string) => GradientFill;
|
|
21
|
+
/**
|
|
22
|
+
* CSS preview of a gradient fill. OOXML measures the linear angle from the
|
|
23
|
+
* left→right axis; CSS from the bottom→top axis, so CSS = degree + 90.
|
|
24
|
+
*/
|
|
25
|
+
export declare const gradientToCss: (gradient: GradientFill) => string;
|
|
26
|
+
export type PatternFillPickerProps = {
|
|
27
|
+
fill?: CellFill | null;
|
|
28
|
+
theme: SpreadsheetTheme;
|
|
29
|
+
onChangeFill(fill: CellFill): void;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Pattern fill authoring (Excel: Format Cells → Fill → Pattern Color /
|
|
33
|
+
* Pattern Style). The pattern paints in `foregroundColor` over the solid
|
|
34
|
+
* `backgroundColor`; a gradient on the cell is cleared, as Excel treats the
|
|
35
|
+
* two as exclusive.
|
|
36
|
+
*/
|
|
37
|
+
export declare const PatternFillPicker: ({ fill, theme, onChangeFill, }: PatternFillPickerProps) => React.JSX.Element;
|
|
38
|
+
export type GradientFillPickerProps = {
|
|
39
|
+
fill?: CellFill | null;
|
|
40
|
+
theme: SpreadsheetTheme;
|
|
41
|
+
onChangeFill(fill: CellFill): void;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Gradient fill authoring (Excel: Fill Effects → Gradient, two colours +
|
|
45
|
+
* shading style). Picking a style applies immediately with the two colours;
|
|
46
|
+
* changing a colour re-applies when the cell already has a gradient.
|
|
47
|
+
*/
|
|
48
|
+
export declare const GradientFillPicker: ({ fill, theme, onChangeFill, }: GradientFillPickerProps) => React.JSX.Element;
|
|
49
|
+
//# sourceMappingURL=fill-selectors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fill-selectors.d.ts","sourceRoot":"","sources":["../../../../components/toolbar/fill-selectors.tsx"],"names":[],"mappings":"AACA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAIjD,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,wEAAwE;AACxE,MAAM,MAAM,QAAQ,GAAG,IAAI,CACzB,UAAU,EACV,iBAAiB,GAAG,aAAa,GAAG,iBAAiB,GAAG,UAAU,CACnE,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,oBAAoB,EAAE,aAAa,CAAC;IAC/C,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf,CAkBA,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,aAAa,CAAC;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;CACvC,CASA,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,EACnC,QAAQ,MAAM,EACd,QAAQ,MAAM,KACb,YAMD,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,UAAU,YAAY,KAAG,MAUtD,CAAC;AAqCF,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,gBAAgB,CAAC;IACxB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;CACpC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAAI,gCAI/B,sBAAsB,sBA+ExB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,gBAAgB,CAAC;IACxB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;CACpC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,gCAIhC,uBAAuB,sBA8FzB,CAAC"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { Button, ColorPicker, HexColorPicker, Stack } from "@rowsncolumns/ui";
|
|
2
|
+
import React, { useMemo, useState } from "react";
|
|
3
|
+
import { getPatternCanvas } from "../../api/fill-patterns";
|
|
4
|
+
import { getStringifiedColor, STANDARD_COLORS } from "../../themes";
|
|
5
|
+
/** Excel's Format Cells → Fill → Pattern Style menu, in Excel's order. */
|
|
6
|
+
export const FILL_PATTERN_OPTIONS = [
|
|
7
|
+
{ pattern: "gray0625", label: "6.25% Gray" },
|
|
8
|
+
{ pattern: "gray125", label: "12.5% Gray" },
|
|
9
|
+
{ pattern: "lightGray", label: "25% Gray" },
|
|
10
|
+
{ pattern: "mediumGray", label: "50% Gray" },
|
|
11
|
+
{ pattern: "darkGray", label: "75% Gray" },
|
|
12
|
+
{ pattern: "darkHorizontal", label: "Horizontal Stripe" },
|
|
13
|
+
{ pattern: "darkVertical", label: "Vertical Stripe" },
|
|
14
|
+
{ pattern: "darkDown", label: "Reverse Diagonal Stripe" },
|
|
15
|
+
{ pattern: "darkUp", label: "Diagonal Stripe" },
|
|
16
|
+
{ pattern: "darkGrid", label: "Diagonal Crosshatch" },
|
|
17
|
+
{ pattern: "darkTrellis", label: "Thick Diagonal Crosshatch" },
|
|
18
|
+
{ pattern: "lightHorizontal", label: "Thin Horizontal Stripe" },
|
|
19
|
+
{ pattern: "lightVertical", label: "Thin Vertical Stripe" },
|
|
20
|
+
{ pattern: "lightDown", label: "Thin Reverse Diagonal Stripe" },
|
|
21
|
+
{ pattern: "lightUp", label: "Thin Diagonal Stripe" },
|
|
22
|
+
{ pattern: "lightGrid", label: "Thin Horizontal Crosshatch" },
|
|
23
|
+
{ pattern: "lightTrellis", label: "Thin Diagonal Crosshatch" },
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* Excel's Fill Effects → Shading styles. `degree` follows OOXML
|
|
27
|
+
* `<gradientFill degree>`: 0 runs left → right, 90 top → bottom.
|
|
28
|
+
*/
|
|
29
|
+
export const GRADIENT_PRESETS = [
|
|
30
|
+
{ label: "Horizontal", gradient: { type: "linear", degree: 90 } },
|
|
31
|
+
{ label: "Vertical", gradient: { type: "linear", degree: 0 } },
|
|
32
|
+
{ label: "Diagonal up", gradient: { type: "linear", degree: 45 } },
|
|
33
|
+
{ label: "Diagonal down", gradient: { type: "linear", degree: 135 } },
|
|
34
|
+
{
|
|
35
|
+
label: "From center",
|
|
36
|
+
gradient: { type: "path", left: 0.5, right: 0.5, top: 0.5, bottom: 0.5 },
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
/** Two-stop gradient from a preset and two colours. */
|
|
40
|
+
export const buildGradientFill = (preset, color1, color2) => ({
|
|
41
|
+
...preset,
|
|
42
|
+
stops: [
|
|
43
|
+
{ position: 0, color: color1 },
|
|
44
|
+
{ position: 1, color: color2 },
|
|
45
|
+
],
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* CSS preview of a gradient fill. OOXML measures the linear angle from the
|
|
49
|
+
* left→right axis; CSS from the bottom→top axis, so CSS = degree + 90.
|
|
50
|
+
*/
|
|
51
|
+
export const gradientToCss = (gradient) => {
|
|
52
|
+
const stops = gradient.stops
|
|
53
|
+
.slice()
|
|
54
|
+
.sort((a, b) => a.position - b.position)
|
|
55
|
+
.map((stop) => `${stop.color} ${Math.round(stop.position * 100)}%`)
|
|
56
|
+
.join(", ");
|
|
57
|
+
if (gradient.type === "path") {
|
|
58
|
+
return `radial-gradient(circle, ${stops})`;
|
|
59
|
+
}
|
|
60
|
+
return `linear-gradient(${((gradient.degree ?? 0) + 90) % 360}deg, ${stops})`;
|
|
61
|
+
};
|
|
62
|
+
const DEFAULT_PATTERN_COLOR = "#000000";
|
|
63
|
+
const PatternSwatch = ({ pattern, foregroundColor, backgroundColor, label, }) => {
|
|
64
|
+
const url = useMemo(() => {
|
|
65
|
+
const canvas = getPatternCanvas(pattern, foregroundColor, backgroundColor);
|
|
66
|
+
try {
|
|
67
|
+
return canvas?.toDataURL() ?? undefined;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
}, [pattern, foregroundColor, backgroundColor]);
|
|
73
|
+
return (React.createElement("span", { "aria-hidden": "true", className: "block w-full h-full border border-solid border-rnc-border", style: url
|
|
74
|
+
? { backgroundImage: `url(${url})`, backgroundRepeat: "repeat" }
|
|
75
|
+
: { backgroundColor }, title: label }));
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Pattern fill authoring (Excel: Format Cells → Fill → Pattern Color /
|
|
79
|
+
* Pattern Style). The pattern paints in `foregroundColor` over the solid
|
|
80
|
+
* `backgroundColor`; a gradient on the cell is cleared, as Excel treats the
|
|
81
|
+
* two as exclusive.
|
|
82
|
+
*/
|
|
83
|
+
export const PatternFillPicker = ({ fill, theme, onChangeFill, }) => {
|
|
84
|
+
const background = fill?.backgroundColor
|
|
85
|
+
? getStringifiedColor(fill.backgroundColor, theme)
|
|
86
|
+
: undefined;
|
|
87
|
+
const patternColor = fill?.foregroundColor
|
|
88
|
+
? getStringifiedColor(fill.foregroundColor, theme)
|
|
89
|
+
: DEFAULT_PATTERN_COLOR;
|
|
90
|
+
const activePattern = fill?.fillPattern &&
|
|
91
|
+
fill.fillPattern !== "none" &&
|
|
92
|
+
fill.fillPattern !== "solid"
|
|
93
|
+
? fill.fillPattern
|
|
94
|
+
: undefined;
|
|
95
|
+
const apply = (pattern, foregroundColor) => onChangeFill({
|
|
96
|
+
backgroundColor: fill?.backgroundColor ?? undefined,
|
|
97
|
+
fillPattern: pattern,
|
|
98
|
+
foregroundColor: pattern ? foregroundColor : undefined,
|
|
99
|
+
gradient: undefined,
|
|
100
|
+
});
|
|
101
|
+
return (React.createElement(Stack, { direction: "vertical", className: "gap-1" },
|
|
102
|
+
React.createElement(Button, { variant: "outline", size: "xs", tabIndex: -1, className: "justify-center py-1", onClick: () => apply(undefined, undefined) }, "No pattern"),
|
|
103
|
+
React.createElement("div", { className: "pt-2 text-xs text-left" }, "Pattern style"),
|
|
104
|
+
React.createElement("div", { role: "group", "aria-label": "Pattern style", className: "grid grid-cols-6 gap-1" }, FILL_PATTERN_OPTIONS.map(({ pattern, label }) => (React.createElement("button", { type: "button", key: pattern, "aria-label": label, "aria-pressed": activePattern === pattern, className: `w-6 h-6 p-0 border-2 border-solid rounded-sm bg-transparent cursor-pointer ${activePattern === pattern
|
|
105
|
+
? "border-rnc-primary"
|
|
106
|
+
: "border-transparent"}`, onClick: () => apply(pattern, fill?.foregroundColor ? patternColor : undefined) },
|
|
107
|
+
React.createElement(PatternSwatch, { pattern: pattern, foregroundColor: patternColor, backgroundColor: background, label: label }))))),
|
|
108
|
+
React.createElement("div", { className: "pt-2 text-xs text-left" }, "Pattern color"),
|
|
109
|
+
React.createElement(ColorPicker, { value: patternColor, colors: STANDARD_COLORS, onChange: (color) => apply(activePattern ?? "darkGray", color), className: "gap-1" }),
|
|
110
|
+
React.createElement("div", { className: "flex items-center gap-1" },
|
|
111
|
+
React.createElement(HexColorPicker, { value: patternColor, onChange: (color) => apply(activePattern ?? "darkGray", color) }))));
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Gradient fill authoring (Excel: Fill Effects → Gradient, two colours +
|
|
115
|
+
* shading style). Picking a style applies immediately with the two colours;
|
|
116
|
+
* changing a colour re-applies when the cell already has a gradient.
|
|
117
|
+
*/
|
|
118
|
+
export const GradientFillPicker = ({ fill, theme, onChangeFill, }) => {
|
|
119
|
+
const existing = fill?.gradient ?? undefined;
|
|
120
|
+
const [color1, setColor1] = useState(() => existing?.stops?.[0]?.color ??
|
|
121
|
+
(fill?.backgroundColor
|
|
122
|
+
? getStringifiedColor(fill.backgroundColor, theme)
|
|
123
|
+
: "#FFFFFF"));
|
|
124
|
+
const [color2, setColor2] = useState(() => existing?.stops?.[existing.stops.length - 1]?.color ?? "#4472C4");
|
|
125
|
+
const apply = (preset, c1 = color1, c2 = color2) => onChangeFill({
|
|
126
|
+
backgroundColor: undefined,
|
|
127
|
+
fillPattern: undefined,
|
|
128
|
+
foregroundColor: undefined,
|
|
129
|
+
gradient: buildGradientFill(preset, c1, c2),
|
|
130
|
+
});
|
|
131
|
+
const reapply = (c1, c2) => {
|
|
132
|
+
if (!existing)
|
|
133
|
+
return;
|
|
134
|
+
const { stops: _stops, ...preset } = existing;
|
|
135
|
+
apply(preset, c1, c2);
|
|
136
|
+
};
|
|
137
|
+
const isActive = (preset) => !!existing &&
|
|
138
|
+
existing.type === preset.type &&
|
|
139
|
+
(preset.type === "path" || (existing.degree ?? 0) === (preset.degree ?? 0));
|
|
140
|
+
return (React.createElement(Stack, { direction: "vertical", className: "gap-1" },
|
|
141
|
+
React.createElement(Button, { variant: "outline", size: "xs", tabIndex: -1, className: "justify-center py-1", onClick: () => onChangeFill({
|
|
142
|
+
backgroundColor: fill?.backgroundColor ?? undefined,
|
|
143
|
+
fillPattern: fill?.fillPattern ?? undefined,
|
|
144
|
+
foregroundColor: fill?.foregroundColor ?? undefined,
|
|
145
|
+
gradient: undefined,
|
|
146
|
+
}) }, "No gradient"),
|
|
147
|
+
React.createElement("div", { className: "grid grid-cols-[auto_1fr] items-center gap-2 pt-2 text-xs" },
|
|
148
|
+
React.createElement("span", null, "Color 1"),
|
|
149
|
+
React.createElement(HexColorPicker, { value: color1, onChange: (color) => {
|
|
150
|
+
setColor1(color);
|
|
151
|
+
reapply(color, color2);
|
|
152
|
+
} }),
|
|
153
|
+
React.createElement("span", null, "Color 2"),
|
|
154
|
+
React.createElement(HexColorPicker, { value: color2, onChange: (color) => {
|
|
155
|
+
setColor2(color);
|
|
156
|
+
reapply(color1, color);
|
|
157
|
+
} })),
|
|
158
|
+
React.createElement("div", { className: "pt-2 text-xs text-left" }, "Shading style"),
|
|
159
|
+
React.createElement("div", { role: "group", "aria-label": "Shading style", className: "grid grid-cols-5 gap-1" }, GRADIENT_PRESETS.map(({ label, gradient }) => (React.createElement("button", { type: "button", key: label, "aria-label": label, "aria-pressed": isActive(gradient), className: `w-8 h-6 p-0 border-2 border-solid rounded-sm cursor-pointer ${isActive(gradient) ? "border-rnc-primary" : "border-rnc-border"}`, style: {
|
|
160
|
+
backgroundImage: gradientToCss(buildGradientFill(gradient, color1, color2)),
|
|
161
|
+
}, onClick: () => apply(gradient) }))))));
|
|
162
|
+
};
|
|
@@ -4,6 +4,7 @@ export * from "./scale-selector";
|
|
|
4
4
|
export * from "./font-size-selector";
|
|
5
5
|
export * from "./text-color-selector";
|
|
6
6
|
export * from "./background-color-selector";
|
|
7
|
+
export * from "./fill-selectors";
|
|
7
8
|
export * from "./merge-cells-selector";
|
|
8
9
|
export * from "./border-selector";
|
|
9
10
|
export * from "./font-family-selector";
|
|
@@ -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,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"}
|
|
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,kBAAkB,CAAC;AACjC,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"}
|