@rowsncolumns/spreadsheet-state 29.2.0 → 29.3.3
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/border.d.ts +1 -1
- package/dist/cjs/api/border.d.ts.map +1 -1
- package/dist/cjs/api/paste-special.d.ts +33 -2
- package/dist/cjs/api/paste-special.d.ts.map +1 -1
- package/dist/cjs/api/paste-special.js +62 -19
- package/dist/cjs/commands.d.ts +208 -3
- package/dist/cjs/commands.d.ts.map +1 -1
- package/dist/cjs/components/editors/cell-format/alignment-tab.d.ts +27 -0
- package/dist/cjs/components/editors/cell-format/alignment-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/alignment-tab.js +83 -0
- package/dist/cjs/components/editors/cell-format/border-edges.d.ts +42 -0
- package/dist/cjs/components/editors/cell-format/border-edges.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/border-edges.js +118 -0
- package/dist/cjs/components/editors/cell-format/border-tab.d.ts +21 -0
- package/dist/cjs/components/editors/cell-format/border-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/border-tab.js +123 -0
- package/dist/cjs/components/editors/cell-format/fill-tab.d.ts +14 -0
- package/dist/cjs/components/editors/cell-format/fill-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/fill-tab.js +54 -0
- package/dist/cjs/components/editors/cell-format/font-tab.d.ts +18 -0
- package/dist/cjs/components/editors/cell-format/font-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/font-tab.js +99 -0
- package/dist/cjs/components/editors/cell-format/list-box.d.ts +35 -0
- package/dist/cjs/components/editors/cell-format/list-box.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/list-box.js +37 -0
- package/dist/cjs/components/editors/cell-format/number-formats.d.ts +90 -0
- package/dist/cjs/components/editors/cell-format/number-formats.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/number-formats.js +403 -0
- package/dist/cjs/components/editors/cell-format/number-tab.d.ts +12 -0
- package/dist/cjs/components/editors/cell-format/number-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/number-tab.js +194 -0
- package/dist/cjs/components/editors/cell-format/protection-tab.d.ts +13 -0
- package/dist/cjs/components/editors/cell-format/protection-tab.d.ts.map +1 -0
- package/dist/cjs/components/editors/cell-format/protection-tab.js +13 -0
- package/dist/cjs/components/editors/cell-format-editor.d.ts +31 -3
- package/dist/cjs/components/editors/cell-format-editor.d.ts.map +1 -1
- package/dist/cjs/components/editors/cell-format-editor.js +182 -636
- package/dist/cjs/components/editors/conditional-format-data-bar-options.d.ts +16 -0
- package/dist/cjs/components/editors/conditional-format-data-bar-options.d.ts.map +1 -0
- package/dist/cjs/components/editors/conditional-format-data-bar-options.js +166 -0
- package/dist/cjs/components/editors/conditional-format-editor.d.ts +7 -1
- package/dist/cjs/components/editors/conditional-format-editor.d.ts.map +1 -1
- package/dist/cjs/components/editors/conditional-format-editor.js +51 -9
- package/dist/cjs/components/editors/conditional-format-icon-set-options.d.ts +17 -0
- package/dist/cjs/components/editors/conditional-format-icon-set-options.d.ts.map +1 -0
- package/dist/cjs/components/editors/conditional-format-icon-set-options.js +163 -0
- package/dist/cjs/components/editors/conditional-format-rule-editor.d.ts +9 -0
- package/dist/cjs/components/editors/conditional-format-rule-editor.d.ts.map +1 -1
- package/dist/cjs/components/editors/conditional-format-rule-editor.js +97 -125
- package/dist/cjs/components/editors/sheet-filter.d.ts +20 -9
- package/dist/cjs/components/editors/sheet-filter.d.ts.map +1 -1
- package/dist/cjs/components/editors/sheet-filter.js +44 -12
- package/dist/cjs/constants.d.ts +3 -1
- package/dist/cjs/constants.d.ts.map +1 -1
- package/dist/cjs/constants.js +3 -0
- package/dist/cjs/hooks/use-conditional-formatting-rules.d.ts +2 -0
- package/dist/cjs/hooks/use-conditional-formatting-rules.d.ts.map +1 -1
- package/dist/cjs/hooks/use-conditional-formatting-rules.js +22 -1
- package/dist/cjs/hooks/use-on-paste.d.ts.map +1 -1
- package/dist/cjs/hooks/use-on-paste.js +8 -1
- package/dist/cjs/hooks/use-sparkline-groups.d.ts +1 -0
- package/dist/cjs/hooks/use-sparkline-groups.d.ts.map +1 -1
- package/dist/cjs/hooks/use-sparkline-groups.js +28 -1
- package/dist/cjs/hooks/use-spreadsheet-state.d.ts +3 -0
- package/dist/cjs/hooks/use-spreadsheet-state.d.ts.map +1 -1
- package/dist/cjs/hooks/use-spreadsheet-state.js +11 -6
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/interface/change-border.d.ts.map +1 -1
- package/dist/cjs/interface/change-border.js +8 -1
- package/dist/cjs/interface/conditional-formatting-rules.d.ts +11 -1
- package/dist/cjs/interface/conditional-formatting-rules.d.ts.map +1 -1
- package/dist/cjs/interface/conditional-formatting-rules.js +44 -1
- package/dist/cjs/sheet-cell.d.ts +8 -0
- package/dist/cjs/sheet-cell.d.ts.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/api/border.d.ts +1 -1
- package/dist/esm/api/border.d.ts.map +1 -1
- package/dist/esm/api/paste-special.d.ts +33 -2
- package/dist/esm/api/paste-special.d.ts.map +1 -1
- package/dist/esm/api/paste-special.js +62 -13
- package/dist/esm/commands.d.ts +208 -3
- package/dist/esm/commands.d.ts.map +1 -1
- package/dist/esm/components/editors/cell-format/alignment-tab.d.ts +27 -0
- package/dist/esm/components/editors/cell-format/alignment-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/alignment-tab.js +81 -0
- package/dist/esm/components/editors/cell-format/border-edges.d.ts +42 -0
- package/dist/esm/components/editors/cell-format/border-edges.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/border-edges.js +79 -0
- package/dist/esm/components/editors/cell-format/border-tab.d.ts +21 -0
- package/dist/esm/components/editors/cell-format/border-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/border-tab.js +103 -0
- package/dist/esm/components/editors/cell-format/fill-tab.d.ts +14 -0
- package/dist/esm/components/editors/cell-format/fill-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/fill-tab.js +49 -0
- package/dist/esm/components/editors/cell-format/font-tab.d.ts +18 -0
- package/dist/esm/components/editors/cell-format/font-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/font-tab.js +88 -0
- package/dist/esm/components/editors/cell-format/list-box.d.ts +35 -0
- package/dist/esm/components/editors/cell-format/list-box.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/list-box.js +30 -0
- package/dist/esm/components/editors/cell-format/number-formats.d.ts +90 -0
- package/dist/esm/components/editors/cell-format/number-formats.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/number-formats.js +383 -0
- package/dist/esm/components/editors/cell-format/number-tab.d.ts +12 -0
- package/dist/esm/components/editors/cell-format/number-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/number-tab.js +165 -0
- package/dist/esm/components/editors/cell-format/protection-tab.d.ts +13 -0
- package/dist/esm/components/editors/cell-format/protection-tab.d.ts.map +1 -0
- package/dist/esm/components/editors/cell-format/protection-tab.js +9 -0
- package/dist/esm/components/editors/cell-format-editor.d.ts +31 -3
- package/dist/esm/components/editors/cell-format-editor.d.ts.map +1 -1
- package/dist/esm/components/editors/cell-format-editor.js +148 -615
- package/dist/esm/components/editors/conditional-format-data-bar-options.d.ts +16 -0
- package/dist/esm/components/editors/conditional-format-data-bar-options.d.ts.map +1 -0
- package/dist/esm/components/editors/conditional-format-data-bar-options.js +145 -0
- package/dist/esm/components/editors/conditional-format-editor.d.ts +7 -1
- package/dist/esm/components/editors/conditional-format-editor.d.ts.map +1 -1
- package/dist/esm/components/editors/conditional-format-editor.js +39 -8
- package/dist/esm/components/editors/conditional-format-icon-set-options.d.ts +17 -0
- package/dist/esm/components/editors/conditional-format-icon-set-options.d.ts.map +1 -0
- package/dist/esm/components/editors/conditional-format-icon-set-options.js +139 -0
- package/dist/esm/components/editors/conditional-format-rule-editor.d.ts +9 -0
- package/dist/esm/components/editors/conditional-format-rule-editor.d.ts.map +1 -1
- package/dist/esm/components/editors/conditional-format-rule-editor.js +60 -85
- package/dist/esm/components/editors/sheet-filter.d.ts +20 -9
- package/dist/esm/components/editors/sheet-filter.d.ts.map +1 -1
- package/dist/esm/components/editors/sheet-filter.js +31 -11
- package/dist/esm/constants.d.ts +3 -1
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/constants.js +3 -0
- package/dist/esm/hooks/use-conditional-formatting-rules.d.ts +2 -0
- package/dist/esm/hooks/use-conditional-formatting-rules.d.ts.map +1 -1
- package/dist/esm/hooks/use-conditional-formatting-rules.js +19 -1
- package/dist/esm/hooks/use-on-paste.d.ts.map +1 -1
- package/dist/esm/hooks/use-on-paste.js +8 -1
- package/dist/esm/hooks/use-sparkline-groups.d.ts +1 -0
- package/dist/esm/hooks/use-sparkline-groups.d.ts.map +1 -1
- package/dist/esm/hooks/use-sparkline-groups.js +20 -1
- package/dist/esm/hooks/use-spreadsheet-state.d.ts +3 -0
- package/dist/esm/hooks/use-spreadsheet-state.d.ts.map +1 -1
- package/dist/esm/hooks/use-spreadsheet-state.js +11 -4
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/interface/change-border.d.ts.map +1 -1
- package/dist/esm/interface/change-border.js +8 -1
- package/dist/esm/interface/conditional-formatting-rules.d.ts +11 -1
- package/dist/esm/interface/conditional-formatting-rules.d.ts.map +1 -1
- package/dist/esm/interface/conditional-formatting-rules.js +29 -1
- package/dist/esm/sheet-cell.d.ts +8 -0
- package/dist/esm/sheet-cell.d.ts.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +7 -7
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { __assign } from "tslib";
|
|
2
|
+
import { Input } from "@rowsncolumns/ui";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { CheckboxField, SelectField } from "./list-box";
|
|
5
|
+
/** Excel's Horizontal list, in Excel's order. */
|
|
6
|
+
export var HORIZONTAL_OPTIONS = [
|
|
7
|
+
{ value: "general", label: "General" },
|
|
8
|
+
{ value: "left", label: "Left (Indent)" },
|
|
9
|
+
{ value: "center", label: "Center" },
|
|
10
|
+
{ value: "right", label: "Right (Indent)" },
|
|
11
|
+
{ value: "fill", label: "Fill" },
|
|
12
|
+
{ value: "justify", label: "Justify" },
|
|
13
|
+
{ value: "centerContinuous", label: "Center Across Selection" },
|
|
14
|
+
{ value: "distributed", label: "Distributed (Indent)" },
|
|
15
|
+
];
|
|
16
|
+
/** Excel's Vertical list. */
|
|
17
|
+
export var VERTICAL_OPTIONS = [
|
|
18
|
+
{ value: "top", label: "Top" },
|
|
19
|
+
{ value: "middle", label: "Center" },
|
|
20
|
+
{ value: "bottom", label: "Bottom" },
|
|
21
|
+
{ value: "justify", label: "Justify" },
|
|
22
|
+
{ value: "distributed", label: "Distributed" },
|
|
23
|
+
];
|
|
24
|
+
export var TEXT_DIRECTION_OPTIONS = [
|
|
25
|
+
{ value: "context", label: "Context" },
|
|
26
|
+
{ value: "ltr", label: "Left-to-Right" },
|
|
27
|
+
{ value: "rtl", label: "Right-to-Left" },
|
|
28
|
+
];
|
|
29
|
+
/** Horizontal modes Excel lets you indent. */
|
|
30
|
+
var INDENTABLE = new Set(["left", "right", "distributed"]);
|
|
31
|
+
/** Format Cells → Alignment. */
|
|
32
|
+
export var AlignmentTab = function (_a) {
|
|
33
|
+
var _b, _c, _d, _e;
|
|
34
|
+
var format = _a.format, onChange = _a.onChange, merged = _a.merged, onChangeMerged = _a.onChangeMerged;
|
|
35
|
+
var horizontal = (_b = format.horizontalAlignment) !== null && _b !== void 0 ? _b : "general";
|
|
36
|
+
var vertical = (_c = format.verticalAlignment) !== null && _c !== void 0 ? _c : "bottom";
|
|
37
|
+
var rotation = format.textRotation;
|
|
38
|
+
var stacked = rotation === "vertical";
|
|
39
|
+
var degrees = typeof rotation === "number" ? rotation : 0;
|
|
40
|
+
var wrap = format.wrapStrategy === "wrap";
|
|
41
|
+
var shrink = !!format.shrinkToFit;
|
|
42
|
+
return (React.createElement("div", { className: "grid grid-cols-[1fr_160px] gap-4" },
|
|
43
|
+
React.createElement("div", { className: "flex flex-col gap-3" },
|
|
44
|
+
React.createElement("fieldset", { className: "flex flex-col gap-2 border-0 p-0" },
|
|
45
|
+
React.createElement("legend", { className: "pb-1 font-system text-sm" }, "Text alignment"),
|
|
46
|
+
React.createElement("div", { className: "grid grid-cols-[1fr_90px] gap-2" },
|
|
47
|
+
React.createElement(SelectField, { label: "Horizontal", value: horizontal, options: HORIZONTAL_OPTIONS, onChange: function (value) {
|
|
48
|
+
return onChange(__assign({ horizontalAlignment: value === "general" ? undefined : value }, (INDENTABLE.has(value) ? {} : { indent: 0 })));
|
|
49
|
+
} }),
|
|
50
|
+
React.createElement("label", { className: "flex flex-col gap-1 font-system text-sm" },
|
|
51
|
+
"Indent",
|
|
52
|
+
React.createElement(Input, { "aria-label": "Indent", type: "number", min: 0, max: 250, className: "text-xs", disabled: !INDENTABLE.has(horizontal), value: (_d = format.indent) !== null && _d !== void 0 ? _d : 0, onChange: function (event) {
|
|
53
|
+
var n = parseInt(event.target.value, 10);
|
|
54
|
+
onChange({
|
|
55
|
+
indent: Number.isFinite(n) ? Math.max(0, Math.min(250, n)) : 0,
|
|
56
|
+
});
|
|
57
|
+
} }))),
|
|
58
|
+
React.createElement(SelectField, { label: "Vertical", value: vertical, options: VERTICAL_OPTIONS, onChange: function (value) { return onChange({ verticalAlignment: value }); } })),
|
|
59
|
+
React.createElement("fieldset", { className: "flex flex-col gap-1.5 border-0 p-0" },
|
|
60
|
+
React.createElement("legend", { className: "pb-1 font-system text-sm" }, "Text control"),
|
|
61
|
+
React.createElement(CheckboxField, { label: "Wrap text", checked: wrap, onChange: function (checked) {
|
|
62
|
+
return onChange(__assign({ wrapStrategy: checked ? "wrap" : "overflow" }, (checked ? { shrinkToFit: false } : {})));
|
|
63
|
+
} }),
|
|
64
|
+
React.createElement(CheckboxField, { label: "Shrink to fit", checked: shrink, disabled: wrap, onChange: function (checked) { return onChange({ shrinkToFit: checked }); } }),
|
|
65
|
+
React.createElement(CheckboxField, { label: "Merge cells", checked: merged, onChange: onChangeMerged })),
|
|
66
|
+
React.createElement("fieldset", { className: "flex flex-col gap-1 border-0 p-0" },
|
|
67
|
+
React.createElement("legend", { className: "pb-1 font-system text-sm" }, "Right-to-left"),
|
|
68
|
+
React.createElement(SelectField, { label: "Text direction", value: (_e = format.readingOrder) !== null && _e !== void 0 ? _e : "context", options: TEXT_DIRECTION_OPTIONS, onChange: function (value) { return onChange({ readingOrder: value }); } }))),
|
|
69
|
+
React.createElement("fieldset", { className: "flex flex-col gap-2 border-0 p-0" },
|
|
70
|
+
React.createElement("legend", { className: "pb-1 font-system text-sm" }, "Orientation"),
|
|
71
|
+
React.createElement("button", { type: "button", "aria-pressed": stacked, "aria-label": "Vertical text", className: "flex h-20 w-8 flex-col items-center justify-center rounded-sm border border-solid text-xs leading-tight ".concat(stacked ? "border-rnc-primary" : "border-rnc-border"), onClick: function () { return onChange({ textRotation: stacked ? 0 : "vertical" }); } }, "Text".split("").map(function (ch, i) { return (React.createElement("span", { key: i }, ch)); })),
|
|
72
|
+
React.createElement("input", { "aria-label": "Orientation", type: "range", min: -90, max: 90, step: 1, value: degrees, disabled: stacked, onChange: function (event) {
|
|
73
|
+
return onChange({ textRotation: Number(event.target.value) });
|
|
74
|
+
} }),
|
|
75
|
+
React.createElement("label", { className: "flex items-center gap-1 font-system text-xs" },
|
|
76
|
+
React.createElement(Input, { "aria-label": "Degrees", type: "number", min: -90, max: 90, className: "w-16 text-xs", value: degrees, disabled: stacked, onChange: function (event) {
|
|
77
|
+
var n = parseInt(event.target.value, 10);
|
|
78
|
+
onChange({
|
|
79
|
+
textRotation: Number.isFinite(n) ? Math.max(-90, Math.min(90, n)) : 0,
|
|
80
|
+
});
|
|
81
|
+
} }),
|
|
82
|
+
"Degrees"))));
|
|
83
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { BorderLocation, Borders, BorderStyle, Color } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
export type EdgeKey = "top" | "insideHorizontal" | "bottom" | "left" | "insideVertical" | "right" | "diagonalUp" | "diagonalDown";
|
|
3
|
+
export type EdgeLine = {
|
|
4
|
+
style: BorderStyle;
|
|
5
|
+
color: Color;
|
|
6
|
+
};
|
|
7
|
+
/** `null` = no border on that edge. */
|
|
8
|
+
export type EdgeState = EdgeLine | null;
|
|
9
|
+
export type EdgeMap = Partial<Record<EdgeKey, EdgeState>>;
|
|
10
|
+
/** The line style the Line Style list picks; `"none"` removes the edge clicked. */
|
|
11
|
+
export type LineStyleChoice = BorderStyle | "none";
|
|
12
|
+
/** Excel's Line Style list, in Excel's order (None, then thin → thick). */
|
|
13
|
+
export declare const LINE_STYLES: {
|
|
14
|
+
value: LineStyleChoice;
|
|
15
|
+
label: string;
|
|
16
|
+
}[];
|
|
17
|
+
export declare const EDGE_LOCATION: Record<EdgeKey, BorderLocation>;
|
|
18
|
+
export declare const ALL_EDGES: EdgeKey[];
|
|
19
|
+
/** The active cell's own edges, as the preview opens on them. */
|
|
20
|
+
export declare const edgesFromBorders: (borders: Borders | null | undefined) => EdgeMap;
|
|
21
|
+
/**
|
|
22
|
+
* Click an edge: Excel removes it when it already carries the current style
|
|
23
|
+
* and colour (or the style is None), otherwise draws it in them.
|
|
24
|
+
*/
|
|
25
|
+
export declare const toggleEdge: (shown: EdgeMap, key: EdgeKey, lineStyle: LineStyleChoice, color: Color) => EdgeState;
|
|
26
|
+
/** The None / Outline / Inside presets: the edges they set. */
|
|
27
|
+
export declare const presetEdges: (preset: "none" | "outline" | "inside", lineStyle: LineStyleChoice, color: Color) => EdgeMap;
|
|
28
|
+
export type BorderCommand = {
|
|
29
|
+
location: BorderLocation;
|
|
30
|
+
/** Both `undefined` = remove the edge (the `onChangeBorder` clear contract). */
|
|
31
|
+
color: Color | undefined;
|
|
32
|
+
style: BorderStyle | undefined;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The `onChangeBorder` calls for the edited edges. A None preset that touched
|
|
36
|
+
* every edge is one `"none"` command (clears diagonals too); everything else
|
|
37
|
+
* is one command per edited edge, removals first so a redraw lands on top.
|
|
38
|
+
*/
|
|
39
|
+
export declare const toBorderCommands: (edits: EdgeMap, options?: {
|
|
40
|
+
clearedAll?: boolean;
|
|
41
|
+
}) => BorderCommand[];
|
|
42
|
+
//# sourceMappingURL=border-edges.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"border-edges.d.ts","sourceRoot":"","sources":["../../../../../components/editors/cell-format/border-edges.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,cAAc,EACd,OAAO,EACP,WAAW,EACX,KAAK,EACN,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,OAAO,GACf,KAAK,GACL,kBAAkB,GAClB,QAAQ,GACR,MAAM,GACN,gBAAgB,GAChB,OAAO,GACP,YAAY,GACZ,cAAc,CAAC;AAEnB,MAAM,MAAM,QAAQ,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAC5D,uCAAuC;AACvC,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,IAAI,CAAC;AACxC,MAAM,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;AAE1D,mFAAmF;AACnF,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,MAAM,CAAC;AAEnD,2EAA2E;AAC3E,eAAO,MAAM,WAAW,EAAE;IAAE,KAAK,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAelE,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,OAAO,EAAE,cAAc,CASzD,CAAC;AAIF,eAAO,MAAM,SAAS,EAAE,OAAO,EAA0D,CAAC;AAE1F,iEAAiE;AACjE,eAAO,MAAM,gBAAgB,GAAI,SAAS,OAAO,GAAG,IAAI,GAAG,SAAS,KAAG,OAOtE,CAAC;AAKF;;;GAGG;AACH,eAAO,MAAM,UAAU,GACrB,OAAO,OAAO,EACd,KAAK,OAAO,EACZ,WAAW,eAAe,EAC1B,OAAO,KAAK,KACX,SAG8B,CAAC;AAElC,+DAA+D;AAC/D,eAAO,MAAM,WAAW,GACtB,QAAQ,MAAM,GAAG,SAAS,GAAG,QAAQ,EACrC,WAAW,eAAe,EAC1B,OAAO,KAAK,KACX,OAYF,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,cAAc,CAAC;IACzB,gFAAgF;IAChF,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;IACzB,KAAK,EAAE,WAAW,GAAG,SAAS,CAAC;CAChC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAC3B,OAAO,OAAO,EACd,UAAS;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,KACrC,aAAa,EAgBf,CAAC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { __read, __spreadArray, __values } from "tslib";
|
|
2
|
+
/** Excel's Line Style list, in Excel's order (None, then thin → thick). */
|
|
3
|
+
export var LINE_STYLES = [
|
|
4
|
+
{ value: "none", label: "None" },
|
|
5
|
+
{ value: "hair", label: "Hair" },
|
|
6
|
+
{ value: "dotted", label: "Dotted" },
|
|
7
|
+
{ value: "dashDotDot", label: "Dash dot dot" },
|
|
8
|
+
{ value: "dashDot", label: "Dash dot" },
|
|
9
|
+
{ value: "dashed", label: "Dashed" },
|
|
10
|
+
{ value: "solid", label: "Thin" },
|
|
11
|
+
{ value: "mediumDashDotDot", label: "Medium dash dot dot" },
|
|
12
|
+
{ value: "slantDashDot", label: "Slanted dash dot" },
|
|
13
|
+
{ value: "mediumDashDot", label: "Medium dash dot" },
|
|
14
|
+
{ value: "mediumDashed", label: "Medium dashed" },
|
|
15
|
+
{ value: "solid_medium", label: "Medium" },
|
|
16
|
+
{ value: "solid_thick", label: "Thick" },
|
|
17
|
+
{ value: "double", label: "Double" },
|
|
18
|
+
];
|
|
19
|
+
export var EDGE_LOCATION = {
|
|
20
|
+
top: "top",
|
|
21
|
+
insideHorizontal: "horizontal",
|
|
22
|
+
bottom: "bottom",
|
|
23
|
+
left: "left",
|
|
24
|
+
insideVertical: "vertical",
|
|
25
|
+
right: "right",
|
|
26
|
+
diagonalUp: "diagonalUp",
|
|
27
|
+
diagonalDown: "diagonalDown",
|
|
28
|
+
};
|
|
29
|
+
var OUTLINE = ["top", "bottom", "left", "right"];
|
|
30
|
+
var INSIDE = ["insideHorizontal", "insideVertical"];
|
|
31
|
+
export var ALL_EDGES = __spreadArray(__spreadArray(__spreadArray([], __read(OUTLINE), false), __read(INSIDE), false), ["diagonalUp", "diagonalDown"], false);
|
|
32
|
+
/** The active cell's own edges, as the preview opens on them. */
|
|
33
|
+
export var edgesFromBorders = function (borders) {
|
|
34
|
+
var e_1, _a;
|
|
35
|
+
var _b;
|
|
36
|
+
var map = {};
|
|
37
|
+
try {
|
|
38
|
+
for (var _c = __values(["top", "bottom", "left", "right", "diagonalUp", "diagonalDown"]), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
39
|
+
var key = _d.value;
|
|
40
|
+
var b = borders === null || borders === void 0 ? void 0 : borders[key];
|
|
41
|
+
if (b === null || b === void 0 ? void 0 : b.style)
|
|
42
|
+
map[key] = { style: b.style, color: (_b = b.color) !== null && _b !== void 0 ? _b : "#000000" };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
46
|
+
finally {
|
|
47
|
+
try {
|
|
48
|
+
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
49
|
+
}
|
|
50
|
+
finally { if (e_1) throw e_1.error; }
|
|
51
|
+
}
|
|
52
|
+
return map;
|
|
53
|
+
};
|
|
54
|
+
var sameLine = function (a, b) {
|
|
55
|
+
return !!a && a.style === b.style && JSON.stringify(a.color) === JSON.stringify(b.color);
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Click an edge: Excel removes it when it already carries the current style
|
|
59
|
+
* and colour (or the style is None), otherwise draws it in them.
|
|
60
|
+
*/
|
|
61
|
+
export var toggleEdge = function (shown, key, lineStyle, color) {
|
|
62
|
+
return lineStyle === "none" || sameLine(shown[key], { style: lineStyle, color: color })
|
|
63
|
+
? null
|
|
64
|
+
: { style: lineStyle, color: color };
|
|
65
|
+
};
|
|
66
|
+
/** The None / Outline / Inside presets: the edges they set. */
|
|
67
|
+
export var presetEdges = function (preset, lineStyle, color) {
|
|
68
|
+
if (preset === "none" || lineStyle === "none") {
|
|
69
|
+
return Object.fromEntries((preset === "none" ? ALL_EDGES : preset === "outline" ? OUTLINE : INSIDE).map(function (k) { return [k, null]; }));
|
|
70
|
+
}
|
|
71
|
+
var line = { style: lineStyle, color: color };
|
|
72
|
+
return Object.fromEntries((preset === "outline" ? OUTLINE : INSIDE).map(function (k) { return [k, line]; }));
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* The `onChangeBorder` calls for the edited edges. A None preset that touched
|
|
76
|
+
* every edge is one `"none"` command (clears diagonals too); everything else
|
|
77
|
+
* is one command per edited edge, removals first so a redraw lands on top.
|
|
78
|
+
*/
|
|
79
|
+
export var toBorderCommands = function (edits, options) {
|
|
80
|
+
var e_2, _a, e_3, _b;
|
|
81
|
+
if (options === void 0) { options = {}; }
|
|
82
|
+
var commands = [];
|
|
83
|
+
if (options.clearedAll) {
|
|
84
|
+
commands.push({ location: "none", color: undefined, style: undefined });
|
|
85
|
+
}
|
|
86
|
+
var keys = ALL_EDGES.filter(function (k) { return k in edits; });
|
|
87
|
+
try {
|
|
88
|
+
for (var keys_1 = __values(keys), keys_1_1 = keys_1.next(); !keys_1_1.done; keys_1_1 = keys_1.next()) {
|
|
89
|
+
var key = keys_1_1.value;
|
|
90
|
+
if (edits[key] === null && !options.clearedAll) {
|
|
91
|
+
commands.push({ location: EDGE_LOCATION[key], color: undefined, style: undefined });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
96
|
+
finally {
|
|
97
|
+
try {
|
|
98
|
+
if (keys_1_1 && !keys_1_1.done && (_a = keys_1.return)) _a.call(keys_1);
|
|
99
|
+
}
|
|
100
|
+
finally { if (e_2) throw e_2.error; }
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
for (var keys_2 = __values(keys), keys_2_1 = keys_2.next(); !keys_2_1.done; keys_2_1 = keys_2.next()) {
|
|
104
|
+
var key = keys_2_1.value;
|
|
105
|
+
var line = edits[key];
|
|
106
|
+
if (line)
|
|
107
|
+
commands.push({ location: EDGE_LOCATION[key], color: line.color, style: line.style });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
111
|
+
finally {
|
|
112
|
+
try {
|
|
113
|
+
if (keys_2_1 && !keys_2_1.done && (_b = keys_2.return)) _b.call(keys_2);
|
|
114
|
+
}
|
|
115
|
+
finally { if (e_3) throw e_3.error; }
|
|
116
|
+
}
|
|
117
|
+
return commands;
|
|
118
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Color, SpreadsheetTheme } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { type EdgeMap, type LineStyleChoice } from "./border-edges";
|
|
4
|
+
export type BorderTabProps = {
|
|
5
|
+
/** The edges as shown: the active cell's, with the user's edits on top. */
|
|
6
|
+
edges: EdgeMap;
|
|
7
|
+
onEdit(edits: EdgeMap, options?: {
|
|
8
|
+
clearedAll?: boolean;
|
|
9
|
+
}): void;
|
|
10
|
+
lineStyle: LineStyleChoice;
|
|
11
|
+
onLineStyle(style: LineStyleChoice): void;
|
|
12
|
+
color: Color;
|
|
13
|
+
onColor(color: Color): void;
|
|
14
|
+
/** Inside edges exist only for a multi-row / multi-column selection. */
|
|
15
|
+
hasInsideRows: boolean;
|
|
16
|
+
hasInsideColumns: boolean;
|
|
17
|
+
theme: SpreadsheetTheme;
|
|
18
|
+
};
|
|
19
|
+
/** Format Cells → Border. */
|
|
20
|
+
export declare const BorderTab: ({ edges, onEdit, lineStyle, onLineStyle, color, onColor, hasInsideRows, hasInsideColumns, theme, }: BorderTabProps) => React.JSX.Element;
|
|
21
|
+
//# sourceMappingURL=border-tab.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"border-tab.d.ts","sourceRoot":"","sources":["../../../../../components/editors/cell-format/border-tab.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAEzE,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAEL,KAAK,OAAO,EAEZ,KAAK,eAAe,EAGrB,MAAM,gBAAgB,CAAC;AA2FxB,MAAM,MAAM,cAAc,GAAG;IAC3B,2EAA2E;IAC3E,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACjE,SAAS,EAAE,eAAe,CAAC;IAC3B,WAAW,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC1C,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC5B,wEAAwE;IACxE,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,KAAK,EAAE,gBAAgB,CAAC;CACzB,CAAC;AAEF,6BAA6B;AAC7B,eAAO,MAAM,SAAS,GAAI,oGAUvB,cAAc,sBA+HhB,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { __read } from "tslib";
|
|
2
|
+
import { BorderColorSelector, getStringifiedColor } from "@rowsncolumns/spreadsheet";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { LINE_STYLES, presetEdges, toggleEdge, } from "./border-edges";
|
|
5
|
+
import { ListBox } from "./list-box";
|
|
6
|
+
var DASH = {
|
|
7
|
+
hair: "1 1",
|
|
8
|
+
dotted: "1 2",
|
|
9
|
+
dashDotDot: "4 2 1 2 1 2",
|
|
10
|
+
dashDot: "4 2 1 2",
|
|
11
|
+
dashed: "3 2",
|
|
12
|
+
mediumDashDotDot: "4 2 1 2 1 2",
|
|
13
|
+
slantDashDot: "4 2 1 2",
|
|
14
|
+
mediumDashDot: "4 2 1 2",
|
|
15
|
+
mediumDashed: "4 2",
|
|
16
|
+
};
|
|
17
|
+
var WIDTH = {
|
|
18
|
+
mediumDashDotDot: 2,
|
|
19
|
+
slantDashDot: 2,
|
|
20
|
+
mediumDashDot: 2,
|
|
21
|
+
mediumDashed: 2,
|
|
22
|
+
solid_medium: 2,
|
|
23
|
+
solid_thick: 3,
|
|
24
|
+
};
|
|
25
|
+
/** One SVG line in a style's dash / weight (double = two thin lines). */
|
|
26
|
+
var StyledLine = function (_a) {
|
|
27
|
+
var _b;
|
|
28
|
+
var x1 = _a.x1, y1 = _a.y1, x2 = _a.x2, y2 = _a.y2, style = _a.style, color = _a.color;
|
|
29
|
+
if (style === "none")
|
|
30
|
+
return null;
|
|
31
|
+
if (style === "double") {
|
|
32
|
+
var dx = y2 - y1;
|
|
33
|
+
var dy = x1 - x2;
|
|
34
|
+
var len = Math.hypot(dx, dy) || 1;
|
|
35
|
+
var _c = __read([(dx / len) * 1.5, (dy / len) * 1.5], 2), ox = _c[0], oy = _c[1];
|
|
36
|
+
return (React.createElement(React.Fragment, null,
|
|
37
|
+
React.createElement("line", { x1: x1 + ox, y1: y1 + oy, x2: x2 + ox, y2: y2 + oy, stroke: color, strokeWidth: 1 }),
|
|
38
|
+
React.createElement("line", { x1: x1 - ox, y1: y1 - oy, x2: x2 - ox, y2: y2 - oy, stroke: color, strokeWidth: 1 })));
|
|
39
|
+
}
|
|
40
|
+
return (React.createElement("line", { x1: x1, y1: y1, x2: x2, y2: y2, stroke: color, strokeWidth: (_b = WIDTH[style]) !== null && _b !== void 0 ? _b : 1, strokeDasharray: DASH[style] }));
|
|
41
|
+
};
|
|
42
|
+
/** Preview geometry (a 2×2 grid when the selection has inside edges). */
|
|
43
|
+
var W = 160;
|
|
44
|
+
var H = 100;
|
|
45
|
+
var EDGE_GEOMETRY = {
|
|
46
|
+
top: [10, 10, W - 10, 10],
|
|
47
|
+
insideHorizontal: [10, H / 2, W - 10, H / 2],
|
|
48
|
+
bottom: [10, H - 10, W - 10, H - 10],
|
|
49
|
+
left: [10, 10, 10, H - 10],
|
|
50
|
+
insideVertical: [W / 2, 10, W / 2, H - 10],
|
|
51
|
+
right: [W - 10, 10, W - 10, H - 10],
|
|
52
|
+
diagonalUp: [10, H - 10, W - 10, 10],
|
|
53
|
+
diagonalDown: [10, 10, W - 10, H - 10],
|
|
54
|
+
};
|
|
55
|
+
var EDGE_BUTTONS = [
|
|
56
|
+
{ key: "top", label: "Top border" },
|
|
57
|
+
{ key: "insideHorizontal", label: "Inside horizontal border" },
|
|
58
|
+
{ key: "bottom", label: "Bottom border" },
|
|
59
|
+
{ key: "diagonalUp", label: "Diagonal up border" },
|
|
60
|
+
{ key: "left", label: "Left border" },
|
|
61
|
+
{ key: "insideVertical", label: "Inside vertical border" },
|
|
62
|
+
{ key: "right", label: "Right border" },
|
|
63
|
+
{ key: "diagonalDown", label: "Diagonal down border" },
|
|
64
|
+
];
|
|
65
|
+
/** Format Cells → Border. */
|
|
66
|
+
export var BorderTab = function (_a) {
|
|
67
|
+
var edges = _a.edges, onEdit = _a.onEdit, lineStyle = _a.lineStyle, onLineStyle = _a.onLineStyle, color = _a.color, onColor = _a.onColor, hasInsideRows = _a.hasInsideRows, hasInsideColumns = _a.hasInsideColumns, theme = _a.theme;
|
|
68
|
+
var enabled = function (key) {
|
|
69
|
+
return key === "insideHorizontal" ? hasInsideRows : key === "insideVertical" ? hasInsideColumns : true;
|
|
70
|
+
};
|
|
71
|
+
var cssColor = function (c) { var _a; return (_a = getStringifiedColor(c, theme)) !== null && _a !== void 0 ? _a : "#000000"; };
|
|
72
|
+
return (React.createElement("div", { className: "grid grid-cols-[150px_1fr] gap-4" },
|
|
73
|
+
React.createElement("div", { className: "flex flex-col gap-2" },
|
|
74
|
+
React.createElement("span", { className: "font-system text-sm" }, "Line style"),
|
|
75
|
+
React.createElement(ListBox, { label: "Line style", value: lineStyle, className: "max-h-[220px]", items: LINE_STYLES.map(function (_a) {
|
|
76
|
+
var value = _a.value, label = _a.label;
|
|
77
|
+
return ({
|
|
78
|
+
value: value,
|
|
79
|
+
label: (React.createElement("span", { className: "flex items-center gap-1", title: label }, value === "none" ? ("None") : (React.createElement("svg", { width: "90", height: "8", "aria-label": label },
|
|
80
|
+
React.createElement(StyledLine, { x1: 0, y1: 4, x2: 90, y2: 4, style: value, color: "currentColor" }))))),
|
|
81
|
+
});
|
|
82
|
+
}), onChange: onLineStyle }),
|
|
83
|
+
React.createElement("span", { className: "font-system text-sm" }, "Color"),
|
|
84
|
+
React.createElement(BorderColorSelector, { color: color, onChange: onColor, theme: theme })),
|
|
85
|
+
React.createElement("div", { className: "flex flex-col gap-2" },
|
|
86
|
+
React.createElement("span", { className: "font-system text-sm" }, "Presets"),
|
|
87
|
+
React.createElement("div", { className: "flex gap-2" }, [
|
|
88
|
+
["none", "None"],
|
|
89
|
+
["outline", "Outline"],
|
|
90
|
+
["inside", "Inside"],
|
|
91
|
+
].map(function (_a) {
|
|
92
|
+
var _b = __read(_a, 2), preset = _b[0], label = _b[1];
|
|
93
|
+
return (React.createElement("button", { type: "button", key: preset, className: "rounded-sm border border-solid border-rnc-border px-2 py-1 text-xs", disabled: preset === "inside" && !hasInsideRows && !hasInsideColumns, onClick: function () {
|
|
94
|
+
return onEdit(presetEdges(preset, lineStyle, color), {
|
|
95
|
+
clearedAll: preset === "none",
|
|
96
|
+
});
|
|
97
|
+
} }, label));
|
|
98
|
+
})),
|
|
99
|
+
React.createElement("span", { className: "font-system text-sm" }, "Border"),
|
|
100
|
+
React.createElement("div", { className: "flex gap-2" },
|
|
101
|
+
React.createElement("div", { className: "grid grid-cols-2 gap-1", role: "group", "aria-label": "Border edges" }, EDGE_BUTTONS.map(function (_a) {
|
|
102
|
+
var key = _a.key, label = _a.label;
|
|
103
|
+
return (React.createElement("button", { type: "button", key: key, "aria-label": label, "aria-pressed": !!edges[key], disabled: !enabled(key), className: "h-7 w-7 rounded-sm border border-solid text-[10px] ".concat(edges[key] ? "border-rnc-primary bg-rnc-muted" : "border-rnc-border"), onClick: function () {
|
|
104
|
+
var _a;
|
|
105
|
+
return onEdit((_a = {}, _a[key] = toggleEdge(edges, key, lineStyle, color), _a));
|
|
106
|
+
} },
|
|
107
|
+
React.createElement("svg", { width: "16", height: "16", "aria-hidden": "true" }, (function () {
|
|
108
|
+
var _a = __read(EDGE_GEOMETRY[key], 4), x1 = _a[0], y1 = _a[1], x2 = _a[2], y2 = _a[3];
|
|
109
|
+
return (React.createElement("line", { x1: (x1 / W) * 16, y1: (y1 / H) * 16, x2: (x2 / W) * 16, y2: (y2 / H) * 16, stroke: "currentColor" }));
|
|
110
|
+
})())));
|
|
111
|
+
})),
|
|
112
|
+
React.createElement("svg", { "data-testid": "border-preview", width: W, height: H, className: "rounded-sm border border-solid border-rnc-border bg-rnc-background" },
|
|
113
|
+
React.createElement("text", { x: W / 2, y: H / 2 + 4, textAnchor: "middle", fontSize: "11", fill: "currentColor" }, "Text"),
|
|
114
|
+
Object.keys(EDGE_GEOMETRY).map(function (key) {
|
|
115
|
+
var line = edges[key];
|
|
116
|
+
if (!line || !enabled(key))
|
|
117
|
+
return null;
|
|
118
|
+
var _a = __read(EDGE_GEOMETRY[key], 4), x1 = _a[0], y1 = _a[1], x2 = _a[2], y2 = _a[3];
|
|
119
|
+
return (React.createElement("g", { key: key, "data-edge": key },
|
|
120
|
+
React.createElement(StyledLine, { x1: x1, y1: y1, x2: x2, y2: y2, style: line.style, color: cssColor(line.color) })));
|
|
121
|
+
}))),
|
|
122
|
+
React.createElement("p", { className: "font-system text-xs text-rnc-muted-foreground" }, "The selected border style can be applied by clicking the presets, preview diagram or the buttons above."))));
|
|
123
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CellFill, SpreadsheetTheme } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
import React from "react";
|
|
3
|
+
export type FillTabProps = {
|
|
4
|
+
fill: CellFill;
|
|
5
|
+
onChange(fill: CellFill): void;
|
|
6
|
+
theme: SpreadsheetTheme;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Format Cells → Fill: Background Color (No Color, the palette, More
|
|
10
|
+
* Colors…), Fill Effects… (two-colour gradient), Pattern Color and Pattern
|
|
11
|
+
* Style, and a Sample. A solid colour replaces a gradient, as in Excel.
|
|
12
|
+
*/
|
|
13
|
+
export declare const FillTab: ({ fill, onChange, theme }: FillTabProps) => React.JSX.Element;
|
|
14
|
+
//# sourceMappingURL=fill-tab.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fill-tab.d.ts","sourceRoot":"","sources":["../../../../../components/editors/cell-format/fill-tab.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAS5E,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,gBAAgB,CAAC;CACzB,CAAC;AAYF;;;;GAIG;AACH,eAAO,MAAM,OAAO,GAAI,2BAA2B,YAAY,sBA8E9D,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { __assign, __read } from "tslib";
|
|
2
|
+
import { getStringifiedColor, gradientToCss, GradientFillPicker, PatternFillPicker, STANDARD_COLORS, } from "@rowsncolumns/spreadsheet";
|
|
3
|
+
import { Button, ColorPicker, HexColorPicker } from "@rowsncolumns/ui";
|
|
4
|
+
import React, { useState } from "react";
|
|
5
|
+
/** CSS for the Sample box (gradient, else the solid colour; patterns show their base colour). */
|
|
6
|
+
var sampleStyle = function (fill, theme) {
|
|
7
|
+
var _a, _b;
|
|
8
|
+
return ((_b = (_a = fill.gradient) === null || _a === void 0 ? void 0 : _a.stops) === null || _b === void 0 ? void 0 : _b.length)
|
|
9
|
+
? { backgroundImage: gradientToCss(fill.gradient) }
|
|
10
|
+
: {
|
|
11
|
+
backgroundColor: fill.backgroundColor
|
|
12
|
+
? getStringifiedColor(fill.backgroundColor, theme)
|
|
13
|
+
: undefined,
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Format Cells → Fill: Background Color (No Color, the palette, More
|
|
18
|
+
* Colors…), Fill Effects… (two-colour gradient), Pattern Color and Pattern
|
|
19
|
+
* Style, and a Sample. A solid colour replaces a gradient, as in Excel.
|
|
20
|
+
*/
|
|
21
|
+
export var FillTab = function (_a) {
|
|
22
|
+
var fill = _a.fill, onChange = _a.onChange, theme = _a.theme;
|
|
23
|
+
var _b = __read(useState("none"), 2), panel = _b[0], setPanel = _b[1];
|
|
24
|
+
var solid = fill.backgroundColor
|
|
25
|
+
? getStringifiedColor(fill.backgroundColor, theme)
|
|
26
|
+
: undefined;
|
|
27
|
+
var pickSolid = function (color) {
|
|
28
|
+
return onChange(__assign(__assign({}, fill), { backgroundColor: color, gradient: undefined }));
|
|
29
|
+
};
|
|
30
|
+
return (React.createElement("div", { className: "grid grid-cols-[1fr_200px] gap-4" },
|
|
31
|
+
React.createElement("div", { className: "flex flex-col gap-2" },
|
|
32
|
+
React.createElement("span", { className: "font-system text-sm" }, "Background Color"),
|
|
33
|
+
React.createElement(Button, { size: "xs", variant: "outline", className: "justify-center", onClick: function () {
|
|
34
|
+
return onChange({
|
|
35
|
+
backgroundColor: undefined,
|
|
36
|
+
fillPattern: undefined,
|
|
37
|
+
foregroundColor: undefined,
|
|
38
|
+
gradient: undefined,
|
|
39
|
+
});
|
|
40
|
+
} }, "No Color"),
|
|
41
|
+
React.createElement("div", { role: "group", "aria-label": "Background color", className: "flex flex-col gap-1" },
|
|
42
|
+
React.createElement(ColorPicker, { value: solid, onChange: pickSolid, className: "flex-wrap gap-1" }),
|
|
43
|
+
React.createElement(ColorPicker, { value: solid, colors: STANDARD_COLORS, onChange: pickSolid, className: "gap-1" })),
|
|
44
|
+
React.createElement("div", { className: "flex gap-2" },
|
|
45
|
+
React.createElement(Button, { size: "xs", variant: "outline", "aria-expanded": panel === "effects", onClick: function () { return setPanel(panel === "effects" ? "none" : "effects"); } }, "Fill Effects..."),
|
|
46
|
+
React.createElement(Button, { size: "xs", variant: "outline", "aria-expanded": panel === "more", onClick: function () { return setPanel(panel === "more" ? "none" : "more"); } }, "More Colors...")),
|
|
47
|
+
panel === "more" ? (React.createElement(HexColorPicker, { value: solid !== null && solid !== void 0 ? solid : "#FFFFFF", onChange: pickSolid })) : null,
|
|
48
|
+
panel === "effects" ? (React.createElement("div", { "data-testid": "fill-effects" },
|
|
49
|
+
React.createElement(GradientFillPicker, { fill: fill, theme: theme, onChangeFill: onChange }))) : null),
|
|
50
|
+
React.createElement("div", { className: "flex flex-col gap-2" },
|
|
51
|
+
React.createElement(PatternFillPicker, { fill: fill, theme: theme, onChangeFill: onChange }),
|
|
52
|
+
React.createElement("span", { className: "font-system text-sm" }, "Sample"),
|
|
53
|
+
React.createElement("div", { "data-testid": "fill-sample", className: "h-10 rounded-sm border border-solid border-rnc-border", style: sampleStyle(fill, theme) }))));
|
|
54
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SpreadsheetTheme, TextFormat, UnderlineStyle } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
import React from "react";
|
|
3
|
+
type UnderlineChoice = "none" | UnderlineStyle;
|
|
4
|
+
/** Excel's Underline list. */
|
|
5
|
+
export declare const UNDERLINE_OPTIONS: {
|
|
6
|
+
value: UnderlineChoice;
|
|
7
|
+
label: string;
|
|
8
|
+
}[];
|
|
9
|
+
export type FontTabProps = {
|
|
10
|
+
textFormat: TextFormat;
|
|
11
|
+
onChange(patch: Partial<TextFormat>): void;
|
|
12
|
+
theme: SpreadsheetTheme;
|
|
13
|
+
isDarkMode?: boolean;
|
|
14
|
+
};
|
|
15
|
+
/** Format Cells → Font. */
|
|
16
|
+
export declare const FontTab: ({ textFormat, onChange, theme, isDarkMode, }: FontTabProps) => React.JSX.Element;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=font-tab.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font-tab.d.ts","sourceRoot":"","sources":["../../../../../components/editors/cell-format/font-tab.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EACV,cAAc,EACf,MAAM,2BAA2B,CAAC;AAOnC,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,KAAK,eAAe,GAAG,MAAM,GAAG,cAAc,CAAC;AAS/C,8BAA8B;AAC9B,eAAO,MAAM,iBAAiB,EAAE;IAAE,KAAK,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAMxE,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IAC3C,KAAK,EAAE,gBAAgB,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAoCF,2BAA2B;AAC3B,eAAO,MAAM,OAAO,GAAI,8CAKrB,YAAY,sBA2Gd,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { FontFamilySelector, FontSizeSelector, getStringifiedColor, TextColorSelector, } from "@rowsncolumns/spreadsheet";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { CheckboxField, ListBox, SelectField } from "./list-box";
|
|
4
|
+
var FONT_STYLES = [
|
|
5
|
+
{ value: "regular", label: "Regular" },
|
|
6
|
+
{ value: "italic", label: "Italic" },
|
|
7
|
+
{ value: "bold", label: "Bold" },
|
|
8
|
+
{ value: "boldItalic", label: "Bold Italic" },
|
|
9
|
+
];
|
|
10
|
+
/** Excel's Underline list. */
|
|
11
|
+
export var UNDERLINE_OPTIONS = [
|
|
12
|
+
{ value: "none", label: "None" },
|
|
13
|
+
{ value: "single", label: "Single" },
|
|
14
|
+
{ value: "double", label: "Double" },
|
|
15
|
+
{ value: "singleAccounting", label: "Single Accounting" },
|
|
16
|
+
{ value: "doubleAccounting", label: "Double Accounting" },
|
|
17
|
+
];
|
|
18
|
+
/** CSS for the Preview box: the double / accounting underlines as CSS decorations. */
|
|
19
|
+
var previewStyle = function (tf, theme) {
|
|
20
|
+
var _a, _b;
|
|
21
|
+
var style = tf.underline ? (_a = tf.underlineStyle) !== null && _a !== void 0 ? _a : "single" : undefined;
|
|
22
|
+
var lines = [
|
|
23
|
+
style ? "underline" : "",
|
|
24
|
+
tf.strikethrough ? "line-through" : "",
|
|
25
|
+
]
|
|
26
|
+
.filter(Boolean)
|
|
27
|
+
.join(" ");
|
|
28
|
+
return {
|
|
29
|
+
fontFamily: (_b = tf.fontFamily) !== null && _b !== void 0 ? _b : undefined,
|
|
30
|
+
fontSize: tf.fontSize ? "".concat(tf.fontSize, "pt") : undefined,
|
|
31
|
+
fontWeight: tf.bold ? "bold" : undefined,
|
|
32
|
+
fontStyle: tf.italic ? "italic" : undefined,
|
|
33
|
+
color: tf.color ? getStringifiedColor(tf.color, theme) : undefined,
|
|
34
|
+
textDecorationLine: lines || undefined,
|
|
35
|
+
textDecorationStyle: style === "double" || style === "doubleAccounting" ? "double" : undefined,
|
|
36
|
+
textUnderlineOffset: style === "singleAccounting" || style === "doubleAccounting"
|
|
37
|
+
? "0.3em"
|
|
38
|
+
: undefined,
|
|
39
|
+
verticalAlign: tf.baselineOffset === "superscript"
|
|
40
|
+
? "super"
|
|
41
|
+
: tf.baselineOffset === "subscript"
|
|
42
|
+
? "sub"
|
|
43
|
+
: undefined,
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
/** Format Cells → Font. */
|
|
47
|
+
export var FontTab = function (_a) {
|
|
48
|
+
var _b;
|
|
49
|
+
var textFormat = _a.textFormat, onChange = _a.onChange, theme = _a.theme, isDarkMode = _a.isDarkMode;
|
|
50
|
+
var fontStyle = textFormat.bold && textFormat.italic
|
|
51
|
+
? "boldItalic"
|
|
52
|
+
: textFormat.bold
|
|
53
|
+
? "bold"
|
|
54
|
+
: textFormat.italic
|
|
55
|
+
? "italic"
|
|
56
|
+
: "regular";
|
|
57
|
+
var underline = textFormat.underline
|
|
58
|
+
? (_b = textFormat.underlineStyle) !== null && _b !== void 0 ? _b : "single"
|
|
59
|
+
: "none";
|
|
60
|
+
return (React.createElement("div", { className: "flex flex-col gap-3" },
|
|
61
|
+
React.createElement("div", { className: "grid grid-cols-[1fr_120px_80px] gap-2" },
|
|
62
|
+
React.createElement("div", { className: "flex flex-col gap-1" },
|
|
63
|
+
React.createElement("span", { className: "font-system text-sm" }, "Font"),
|
|
64
|
+
React.createElement(FontFamilySelector, { theme: theme, value: textFormat.fontFamily, onChange: function (fontFamily) { return onChange({ fontFamily: fontFamily }); }, triggerVariant: "outline" })),
|
|
65
|
+
React.createElement("div", { className: "flex flex-col gap-1" },
|
|
66
|
+
React.createElement("span", { className: "font-system text-sm" }, "Font style"),
|
|
67
|
+
React.createElement(ListBox, { label: "Font style", value: fontStyle, items: FONT_STYLES, onChange: function (value) {
|
|
68
|
+
return onChange({
|
|
69
|
+
bold: value === "bold" || value === "boldItalic",
|
|
70
|
+
italic: value === "italic" || value === "boldItalic",
|
|
71
|
+
});
|
|
72
|
+
} })),
|
|
73
|
+
React.createElement("div", { className: "flex flex-col gap-1" },
|
|
74
|
+
React.createElement("span", { className: "font-system text-sm" }, "Size"),
|
|
75
|
+
React.createElement(FontSizeSelector, { value: textFormat.fontSize, onChange: function (fontSize) { return onChange({ fontSize: fontSize }); } }))),
|
|
76
|
+
React.createElement("div", { className: "grid grid-cols-2 gap-2" },
|
|
77
|
+
React.createElement(SelectField, { label: "Underline", value: underline, options: UNDERLINE_OPTIONS, onChange: function (value) {
|
|
78
|
+
return onChange(value === "none"
|
|
79
|
+
? { underline: false }
|
|
80
|
+
: { underline: true, underlineStyle: value });
|
|
81
|
+
} }),
|
|
82
|
+
React.createElement("div", { className: "flex flex-col gap-1" },
|
|
83
|
+
React.createElement("span", { className: "font-system text-sm" }, "Color"),
|
|
84
|
+
React.createElement(TextColorSelector, { color: textFormat.color, theme: theme, isDarkMode: isDarkMode, onChange: function (color) { return onChange({ color: color }); } }))),
|
|
85
|
+
React.createElement("div", { className: "grid grid-cols-2 gap-2" },
|
|
86
|
+
React.createElement("fieldset", { className: "flex flex-col gap-1.5 border-0 p-0" },
|
|
87
|
+
React.createElement("legend", { className: "pb-1 font-system text-sm" }, "Effects"),
|
|
88
|
+
React.createElement(CheckboxField, { label: "Strikethrough", checked: !!textFormat.strikethrough, onChange: function (strikethrough) { return onChange({ strikethrough: strikethrough }); } }),
|
|
89
|
+
React.createElement(CheckboxField, { label: "Superscript", checked: textFormat.baselineOffset === "superscript", onChange: function (on) {
|
|
90
|
+
return onChange({ baselineOffset: on ? "superscript" : null });
|
|
91
|
+
} }),
|
|
92
|
+
React.createElement(CheckboxField, { label: "Subscript", checked: textFormat.baselineOffset === "subscript", onChange: function (on) {
|
|
93
|
+
return onChange({ baselineOffset: on ? "subscript" : null });
|
|
94
|
+
} })),
|
|
95
|
+
React.createElement("div", { className: "flex flex-col gap-1" },
|
|
96
|
+
React.createElement("span", { className: "font-system text-sm" }, "Preview"),
|
|
97
|
+
React.createElement("div", { "data-testid": "font-preview", className: "flex h-14 items-center justify-center overflow-hidden rounded-sm border border-solid border-rnc-border bg-rnc-background" },
|
|
98
|
+
React.createElement("span", { style: previewStyle(textFormat, theme) }, "AaBbCcYyZz"))))));
|
|
99
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export type ListBoxItem<T extends string> = {
|
|
3
|
+
value: T;
|
|
4
|
+
label: React.ReactNode;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Excel's always-open selection lists (Category, Type, Font style, Line
|
|
8
|
+
* style …): a listbox with arrow-key navigation, not a dropdown.
|
|
9
|
+
*/
|
|
10
|
+
export declare const ListBox: <T extends string>({ label, items, value, onChange, className, }: {
|
|
11
|
+
label: string;
|
|
12
|
+
items: ListBoxItem<T>[];
|
|
13
|
+
value: T | undefined;
|
|
14
|
+
onChange(value: T): void;
|
|
15
|
+
className?: string;
|
|
16
|
+
}) => React.JSX.Element;
|
|
17
|
+
/** A labelled native checkbox (Excel's Text control / Effects / Protection boxes). */
|
|
18
|
+
export declare const CheckboxField: ({ label, checked, disabled, onChange, }: {
|
|
19
|
+
label: string;
|
|
20
|
+
checked: boolean;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
onChange(checked: boolean): void;
|
|
23
|
+
}) => React.JSX.Element;
|
|
24
|
+
/** A labelled native select for the short option lists. */
|
|
25
|
+
export declare const SelectField: <T extends string>({ label, value, options, onChange, disabled, }: {
|
|
26
|
+
label: string;
|
|
27
|
+
value: T;
|
|
28
|
+
options: {
|
|
29
|
+
value: T;
|
|
30
|
+
label: string;
|
|
31
|
+
}[];
|
|
32
|
+
onChange(value: T): void;
|
|
33
|
+
disabled?: boolean;
|
|
34
|
+
}) => React.JSX.Element;
|
|
35
|
+
//# sourceMappingURL=list-box.d.ts.map
|