@rowsncolumns/spreadsheet 10.5.17 → 10.6.4
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/cf-data-bar.d.ts +73 -0
- package/dist/cjs/api/cf-data-bar.d.ts.map +1 -0
- package/dist/cjs/api/cf-data-bar.js +182 -0
- package/dist/cjs/api/cf-icons.d.ts +73 -0
- package/dist/cjs/api/cf-icons.d.ts.map +1 -0
- package/dist/cjs/api/cf-icons.js +322 -0
- package/dist/cjs/api/cf-overlays.d.ts +89 -3
- package/dist/cjs/api/cf-overlays.d.ts.map +1 -1
- package/dist/cjs/api/cf-overlays.js +256 -80
- package/dist/cjs/api/cf-priority.d.ts +34 -0
- package/dist/cjs/api/cf-priority.d.ts.map +1 -0
- package/dist/cjs/api/cf-priority.js +94 -0
- package/dist/cjs/api/heatmap.d.ts +7 -1
- package/dist/cjs/api/heatmap.d.ts.map +1 -1
- package/dist/cjs/api/heatmap.js +27 -11
- package/dist/cjs/api/selections.d.ts +2 -2
- package/dist/cjs/api/validation.d.ts +6 -0
- package/dist/cjs/api/validation.d.ts.map +1 -1
- package/dist/cjs/api/validation.js +10 -1
- package/dist/cjs/atoms/goal-seek-dialog.atom.d.ts +8 -3
- package/dist/cjs/atoms/goal-seek-dialog.atom.d.ts.map +1 -1
- package/dist/cjs/atoms/index.d.ts +4 -0
- package/dist/cjs/atoms/index.d.ts.map +1 -1
- package/dist/cjs/atoms/index.js +4 -0
- package/dist/cjs/components/canvas-grid/index.d.ts.map +1 -1
- package/dist/cjs/components/canvas-grid/index.js +194 -51
- package/dist/cjs/components/canvas-grid/overflow.d.ts +37 -0
- package/dist/cjs/components/canvas-grid/overflow.d.ts.map +1 -0
- package/dist/cjs/components/canvas-grid/overflow.js +49 -0
- package/dist/cjs/components/canvas-grid/page-breaks.d.ts +15 -0
- package/dist/cjs/components/canvas-grid/page-breaks.d.ts.map +1 -0
- package/dist/cjs/components/canvas-grid/page-breaks.js +77 -0
- package/dist/cjs/components/canvas-grid/typings.d.ts +32 -3
- package/dist/cjs/components/canvas-grid/typings.d.ts.map +1 -1
- package/dist/cjs/components/cell/alignment.d.ts +58 -1
- package/dist/cjs/components/cell/alignment.d.ts.map +1 -1
- package/dist/cjs/components/cell/alignment.js +144 -1
- package/dist/cjs/components/cell/cell-background.d.ts +2 -0
- package/dist/cjs/components/cell/cell-background.d.ts.map +1 -1
- package/dist/cjs/components/cell/cell-background.js +5 -6
- package/dist/cjs/components/cell/cell-backgrounds.d.ts.map +1 -1
- package/dist/cjs/components/cell/cell-backgrounds.js +5 -1
- package/dist/cjs/components/cell/cell-text-runs.js +1 -1
- package/dist/cjs/components/cell/index.d.ts.map +1 -1
- package/dist/cjs/components/cell/index.js +378 -37
- package/dist/cjs/components/cell/number-format-layout.d.ts +35 -0
- package/dist/cjs/components/cell/number-format-layout.d.ts.map +1 -0
- package/dist/cjs/components/cell/number-format-layout.js +106 -0
- package/dist/cjs/components/cell/typings.d.ts +22 -0
- package/dist/cjs/components/cell/typings.d.ts.map +1 -1
- package/dist/cjs/components/cell-editor/index.js +2 -2
- package/dist/cjs/components/cell-filter/index.d.ts.map +1 -1
- package/dist/cjs/components/cell-filter/index.js +3 -3
- package/dist/cjs/components/cell-overlay/index.d.ts +20 -0
- package/dist/cjs/components/cell-overlay/index.d.ts.map +1 -1
- package/dist/cjs/components/cell-overlay/index.js +155 -28
- package/dist/cjs/components/cf-icon-preview/index.d.ts +16 -0
- package/dist/cjs/components/cf-icon-preview/index.d.ts.map +1 -0
- package/dist/cjs/components/cf-icon-preview/index.js +48 -0
- package/dist/cjs/components/context-menu/index.d.ts.map +1 -1
- package/dist/cjs/components/context-menu/index.js +11 -3
- package/dist/cjs/components/embeds/embed-component.d.ts.map +1 -1
- package/dist/cjs/components/embeds/embed-component.js +3 -2
- package/dist/cjs/components/goal-seek-dialog/index.d.ts +15 -5
- package/dist/cjs/components/goal-seek-dialog/index.d.ts.map +1 -1
- package/dist/cjs/components/goal-seek-dialog/index.js +145 -42
- package/dist/cjs/components/hidden-markers/index.d.ts.map +1 -1
- package/dist/cjs/components/hidden-markers/index.js +8 -7
- package/dist/cjs/components/hidden-markers/style.d.ts +7 -0
- package/dist/cjs/components/hidden-markers/style.d.ts.map +1 -1
- package/dist/cjs/components/hidden-markers/style.js +13 -2
- package/dist/cjs/components/protect-sheet-dialog/index.d.ts +67 -0
- package/dist/cjs/components/protect-sheet-dialog/index.d.ts.map +1 -0
- package/dist/cjs/components/protect-sheet-dialog/index.js +196 -0
- package/dist/cjs/components/toolbar/types.d.ts +1 -1
- package/dist/cjs/components/toolbar/types.d.ts.map +1 -1
- package/dist/cjs/config.d.ts +13 -1
- package/dist/cjs/config.d.ts.map +1 -1
- package/dist/cjs/config.js +15 -3
- package/dist/cjs/helpers.d.ts +10 -5
- package/dist/cjs/helpers.d.ts.map +1 -1
- package/dist/cjs/helpers.js +43 -31
- package/dist/cjs/hooks/use-border-styles.d.ts.map +1 -1
- package/dist/cjs/hooks/use-border-styles.js +5 -28
- package/dist/cjs/hooks/use-cell-renderer.d.ts +35 -3
- package/dist/cjs/hooks/use-cell-renderer.d.ts.map +1 -1
- package/dist/cjs/hooks/use-cell-renderer.js +85 -47
- package/dist/cjs/hooks/use-conditional-formatting.d.ts +13 -1
- package/dist/cjs/hooks/use-conditional-formatting.d.ts.map +1 -1
- package/dist/cjs/hooks/use-conditional-formatting.js +281 -230
- package/dist/cjs/index.d.ts +7 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +13 -1
- package/dist/cjs/release-date.js +1 -1
- package/dist/cjs/themes.d.ts +8 -0
- package/dist/cjs/themes.d.ts.map +1 -1
- package/dist/cjs/themes.js +21 -3
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/cjs/types.d.ts +115 -5
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/esm/api/cf-data-bar.d.ts +73 -0
- package/dist/esm/api/cf-data-bar.d.ts.map +1 -0
- package/dist/esm/api/cf-data-bar.js +178 -0
- package/dist/esm/api/cf-icons.d.ts +73 -0
- package/dist/esm/api/cf-icons.d.ts.map +1 -0
- package/dist/esm/api/cf-icons.js +306 -0
- package/dist/esm/api/cf-overlays.d.ts +89 -3
- package/dist/esm/api/cf-overlays.d.ts.map +1 -1
- package/dist/esm/api/cf-overlays.js +223 -67
- package/dist/esm/api/cf-priority.d.ts +34 -0
- package/dist/esm/api/cf-priority.d.ts.map +1 -0
- package/dist/esm/api/cf-priority.js +61 -0
- package/dist/esm/api/heatmap.d.ts +7 -1
- package/dist/esm/api/heatmap.d.ts.map +1 -1
- package/dist/esm/api/heatmap.js +24 -9
- package/dist/esm/api/selections.d.ts +2 -2
- package/dist/esm/api/validation.d.ts +6 -0
- package/dist/esm/api/validation.d.ts.map +1 -1
- package/dist/esm/api/validation.js +6 -0
- package/dist/esm/atoms/goal-seek-dialog.atom.d.ts +8 -3
- package/dist/esm/atoms/goal-seek-dialog.atom.d.ts.map +1 -1
- package/dist/esm/atoms/index.d.ts +4 -0
- package/dist/esm/atoms/index.d.ts.map +1 -1
- package/dist/esm/atoms/index.js +4 -0
- package/dist/esm/components/canvas-grid/index.d.ts.map +1 -1
- package/dist/esm/components/canvas-grid/index.js +163 -47
- package/dist/esm/components/canvas-grid/overflow.d.ts +37 -0
- package/dist/esm/components/canvas-grid/overflow.d.ts.map +1 -0
- package/dist/esm/components/canvas-grid/overflow.js +39 -0
- package/dist/esm/components/canvas-grid/page-breaks.d.ts +15 -0
- package/dist/esm/components/canvas-grid/page-breaks.d.ts.map +1 -0
- package/dist/esm/components/canvas-grid/page-breaks.js +50 -0
- package/dist/esm/components/canvas-grid/typings.d.ts +32 -3
- package/dist/esm/components/canvas-grid/typings.d.ts.map +1 -1
- package/dist/esm/components/cell/alignment.d.ts +58 -1
- package/dist/esm/components/cell/alignment.d.ts.map +1 -1
- package/dist/esm/components/cell/alignment.js +110 -1
- package/dist/esm/components/cell/cell-background.d.ts +2 -0
- package/dist/esm/components/cell/cell-background.d.ts.map +1 -1
- package/dist/esm/components/cell/cell-background.js +4 -5
- package/dist/esm/components/cell/cell-backgrounds.d.ts.map +1 -1
- package/dist/esm/components/cell/cell-backgrounds.js +5 -1
- package/dist/esm/components/cell/cell-text-runs.js +2 -2
- package/dist/esm/components/cell/index.d.ts.map +1 -1
- package/dist/esm/components/cell/index.js +339 -39
- package/dist/esm/components/cell/number-format-layout.d.ts +35 -0
- package/dist/esm/components/cell/number-format-layout.d.ts.map +1 -0
- package/dist/esm/components/cell/number-format-layout.js +99 -0
- package/dist/esm/components/cell/typings.d.ts +22 -0
- package/dist/esm/components/cell/typings.d.ts.map +1 -1
- package/dist/esm/components/cell-editor/index.js +2 -2
- package/dist/esm/components/cell-filter/index.d.ts.map +1 -1
- package/dist/esm/components/cell-filter/index.js +4 -4
- package/dist/esm/components/cell-overlay/index.d.ts +20 -0
- package/dist/esm/components/cell-overlay/index.d.ts.map +1 -1
- package/dist/esm/components/cell-overlay/index.js +111 -25
- package/dist/esm/components/cf-icon-preview/index.d.ts +16 -0
- package/dist/esm/components/cf-icon-preview/index.d.ts.map +1 -0
- package/dist/esm/components/cf-icon-preview/index.js +41 -0
- package/dist/esm/components/context-menu/index.d.ts.map +1 -1
- package/dist/esm/components/context-menu/index.js +11 -3
- package/dist/esm/components/embeds/embed-component.d.ts.map +1 -1
- package/dist/esm/components/embeds/embed-component.js +4 -3
- package/dist/esm/components/goal-seek-dialog/index.d.ts +15 -5
- package/dist/esm/components/goal-seek-dialog/index.d.ts.map +1 -1
- package/dist/esm/components/goal-seek-dialog/index.js +126 -29
- package/dist/esm/components/hidden-markers/index.d.ts.map +1 -1
- package/dist/esm/components/hidden-markers/index.js +9 -8
- package/dist/esm/components/hidden-markers/style.d.ts +7 -0
- package/dist/esm/components/hidden-markers/style.d.ts.map +1 -1
- package/dist/esm/components/hidden-markers/style.js +8 -1
- package/dist/esm/components/protect-sheet-dialog/index.d.ts +67 -0
- package/dist/esm/components/protect-sheet-dialog/index.d.ts.map +1 -0
- package/dist/esm/components/protect-sheet-dialog/index.js +154 -0
- package/dist/esm/components/toolbar/types.d.ts +1 -1
- package/dist/esm/components/toolbar/types.d.ts.map +1 -1
- package/dist/esm/config.d.ts +13 -1
- package/dist/esm/config.d.ts.map +1 -1
- package/dist/esm/config.js +13 -1
- package/dist/esm/helpers.d.ts +10 -5
- package/dist/esm/helpers.d.ts.map +1 -1
- package/dist/esm/helpers.js +40 -28
- package/dist/esm/hooks/use-border-styles.d.ts.map +1 -1
- package/dist/esm/hooks/use-border-styles.js +5 -26
- package/dist/esm/hooks/use-cell-renderer.d.ts +35 -3
- package/dist/esm/hooks/use-cell-renderer.d.ts.map +1 -1
- package/dist/esm/hooks/use-cell-renderer.js +83 -42
- package/dist/esm/hooks/use-conditional-formatting.d.ts +13 -1
- package/dist/esm/hooks/use-conditional-formatting.d.ts.map +1 -1
- package/dist/esm/hooks/use-conditional-formatting.js +215 -120
- package/dist/esm/index.d.ts +7 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +7 -0
- package/dist/esm/release-date.js +1 -1
- package/dist/esm/themes.d.ts +8 -0
- package/dist/esm/themes.d.ts.map +1 -1
- package/dist/esm/themes.js +20 -3
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/types.d.ts +115 -5
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/spreadsheet.min.css +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/goal-seek-dialog/index.tsx"],"names":[],"mappings":"AAaA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/goal-seek-dialog/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA0D,MAAM,OAAO,CAAC;AAM/E,OAAO,KAAK,EAEV,cAAc,EACd,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,mBAAmB,GAAG;IAChC,2BAA2B;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,4DAA4D;IAC5D,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,OAAO,CACL,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAC;IACvC,mEAAmE;IACnE,QAAQ,CAAC,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtD,CAAC;AAKF,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,GAC7B,SAAS,MAAM,EACf,QAAQ,cAAc,GAAG,SAAS,KACjC,MAKF,CAAC;AAEF,4FAA4F;AAC5F,eAAO,MAAM,wBAAwB,GAAI,aAAa,MAAM,WACF,CAAC;AAW3D,4DAA4D;AAC5D,eAAO,MAAM,4BAA4B,GACvC,SAAS,MAAM,EACf,QAAQ,cAAc,GAAG,SAAS,EAClC,aAAa,MAAM,EACnB,SAAS,qBAAqB,KAC7B,MASF,CAAC;AAUF;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,wFACmC,mBAAmB,uBA0ShF,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB;;;CAqB9B,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Cross1Icon } from "@rowsncolumns/icons";
|
|
2
2
|
import { Button, Dialog, DialogBody, DialogCloseButton, DialogContent, DialogDescription, DialogTitle, Input, Separator, } from "@rowsncolumns/ui";
|
|
3
3
|
import { addressToCell } from "@rowsncolumns/utils";
|
|
4
|
-
import React, { memo, useCallback, useEffect, useState } from "react";
|
|
4
|
+
import React, { memo, useCallback, useEffect, useMemo, useState } from "react";
|
|
5
5
|
import { useGoalSeekDialogState, useRegisterGoalSeekDialogHost, } from "../../atoms/goal-seek-dialog.atom";
|
|
6
6
|
const isCellReference = (text) => /^\$?[A-Za-z]{1,3}\$?\d+$/.test(text.trim()) && addressToCell(text.trim()) != null;
|
|
7
7
|
/** Excel's status sentence for a finished search. */
|
|
@@ -12,32 +12,65 @@ export const goalSeekStatusText = (setCell, result) => {
|
|
|
12
12
|
? `Goal Seeking with Cell ${setCell} found a solution.`
|
|
13
13
|
: `Goal Seeking with Cell ${setCell} may not have found a solution.`;
|
|
14
14
|
};
|
|
15
|
+
/** A one-sided or rounded search's default tolerance: 1% of the target (0.001 for zero). */
|
|
16
|
+
export const defaultGoalSeekTolerance = (targetValue) => targetValue === 0 ? 0.001 : Math.abs(targetValue) * 0.01;
|
|
17
|
+
/** A value as the status list shows it: up to 12 significant digits, no binary noise. */
|
|
18
|
+
const formatGoalSeekNumber = (value) => String(Number(value.toPrecision(12)));
|
|
19
|
+
const MODE_LABELS = {
|
|
20
|
+
exact: "exactly",
|
|
21
|
+
atLeast: "at least",
|
|
22
|
+
atMost: "at most",
|
|
23
|
+
};
|
|
24
|
+
/** The status sentence of a one-sided or rounded search. */
|
|
25
|
+
export const goalSeekCandidatesStatusText = (setCell, result, targetValue, options) => {
|
|
26
|
+
const count = result?.candidates?.length ?? 0;
|
|
27
|
+
const goal = `${MODE_LABELS[options.mode ?? "exact"]} ${formatGoalSeekNumber(targetValue)}`;
|
|
28
|
+
if (count === 0) {
|
|
29
|
+
const within = options.tolerance ?? defaultGoalSeekTolerance(targetValue);
|
|
30
|
+
return `Goal Seeking with Cell ${setCell} found no value ${goal} within ${formatGoalSeekNumber(within)}.`;
|
|
31
|
+
}
|
|
32
|
+
const answers = count === 1 ? "1 value" : `${count} values`;
|
|
33
|
+
return `Goal Seeking with Cell ${setCell} found ${answers} ${goal}.`;
|
|
34
|
+
};
|
|
15
35
|
/**
|
|
16
36
|
* Excel's Goal Seek dialog: Set cell / To value / By changing cell, then the
|
|
17
|
-
* Goal Seek Status sentence with target and current value.
|
|
37
|
+
* Goal Seek Status sentence with target and current value. Beyond Excel, the
|
|
38
|
+
* target can be one-sided ("at least" / "at most") and the answer rounded to a
|
|
39
|
+
* natural number within a tolerance: the status then lists up to three
|
|
40
|
+
* candidates, and the picked one is applied.
|
|
18
41
|
*/
|
|
19
|
-
export const GoalSeekDialog = memo(({ open, onOpenChange, initialSetCell, onApply }) => {
|
|
42
|
+
export const GoalSeekDialog = memo(({ open, onOpenChange, initialSetCell, onApply, onCommit }) => {
|
|
20
43
|
const [setCell, setSetCell] = useState(initialSetCell);
|
|
21
44
|
const [target, setTarget] = useState("");
|
|
22
45
|
const [changingCell, setChangingCell] = useState("");
|
|
46
|
+
const [mode, setMode] = useState("exact");
|
|
47
|
+
const [round, setRound] = useState(false);
|
|
48
|
+
const [tolerance, setTolerance] = useState("");
|
|
23
49
|
const [error, setError] = useState(undefined);
|
|
24
50
|
const [busy, setBusy] = useState(false);
|
|
25
|
-
const [
|
|
51
|
+
const [outcome, setOutcome] = useState(undefined);
|
|
52
|
+
const [picked, setPicked] = useState(0);
|
|
26
53
|
useEffect(() => {
|
|
27
54
|
if (open) {
|
|
28
55
|
setSetCell(initialSetCell);
|
|
29
56
|
setTarget("");
|
|
30
57
|
setChangingCell("");
|
|
58
|
+
setMode("exact");
|
|
59
|
+
setRound(false);
|
|
60
|
+
setTolerance("");
|
|
31
61
|
setError(undefined);
|
|
32
62
|
setBusy(false);
|
|
33
|
-
|
|
63
|
+
setOutcome(undefined);
|
|
64
|
+
setPicked(0);
|
|
34
65
|
}
|
|
35
66
|
// Only reset on open transitions.
|
|
36
67
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
37
68
|
}, [open]);
|
|
69
|
+
const beyondExcel = round || mode !== "exact";
|
|
38
70
|
const submit = useCallback(async (event) => {
|
|
39
71
|
event.preventDefault();
|
|
40
72
|
const targetValue = Number(target.trim());
|
|
73
|
+
const toleranceValue = Number(tolerance.trim());
|
|
41
74
|
if (!isCellReference(setCell)) {
|
|
42
75
|
setError("Set cell must be a single cell reference, e.g. B4.");
|
|
43
76
|
return;
|
|
@@ -50,11 +83,29 @@ export const GoalSeekDialog = memo(({ open, onOpenChange, initialSetCell, onAppl
|
|
|
50
83
|
setError("By changing cell must be a single cell reference, e.g. A1.");
|
|
51
84
|
return;
|
|
52
85
|
}
|
|
86
|
+
if (beyondExcel &&
|
|
87
|
+
tolerance.trim() !== "" &&
|
|
88
|
+
(!Number.isFinite(toleranceValue) || toleranceValue < 0)) {
|
|
89
|
+
setError("Within must be a positive number.");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const options = beyondExcel
|
|
93
|
+
? {
|
|
94
|
+
mode,
|
|
95
|
+
round,
|
|
96
|
+
...(tolerance.trim() !== "" ? { tolerance: toleranceValue } : {}),
|
|
97
|
+
}
|
|
98
|
+
: undefined;
|
|
99
|
+
const set = setCell.trim().toUpperCase();
|
|
100
|
+
const changing = changingCell.trim().toUpperCase();
|
|
53
101
|
setError(undefined);
|
|
54
102
|
setBusy(true);
|
|
55
103
|
try {
|
|
56
|
-
const
|
|
57
|
-
|
|
104
|
+
const result = options
|
|
105
|
+
? await onApply(set, targetValue, changing, options)
|
|
106
|
+
: await onApply(set, targetValue, changing);
|
|
107
|
+
setPicked(0);
|
|
108
|
+
setOutcome({ setCell: set, changingCell: changing, targetValue, options, result });
|
|
58
109
|
}
|
|
59
110
|
catch (err) {
|
|
60
111
|
setError(err instanceof Error ? err.message : "Goal Seek failed.");
|
|
@@ -62,43 +113,87 @@ export const GoalSeekDialog = memo(({ open, onOpenChange, initialSetCell, onAppl
|
|
|
62
113
|
finally {
|
|
63
114
|
setBusy(false);
|
|
64
115
|
}
|
|
65
|
-
}, [setCell, target, changingCell, onApply]);
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
116
|
+
}, [setCell, target, changingCell, mode, round, tolerance, beyondExcel, onApply]);
|
|
117
|
+
const candidates = useMemo(() => (outcome?.options ? (outcome.result?.candidates ?? []) : []), [outcome]);
|
|
118
|
+
const applyPicked = useCallback(() => {
|
|
119
|
+
const candidate = candidates[picked];
|
|
120
|
+
if (outcome && candidate)
|
|
121
|
+
onCommit?.(outcome.changingCell, candidate.value);
|
|
122
|
+
onOpenChange(false);
|
|
123
|
+
}, [candidates, picked, outcome, onCommit, onOpenChange]);
|
|
124
|
+
const renderStatus = (current) => {
|
|
125
|
+
if (!current.options) {
|
|
126
|
+
return (React.createElement(React.Fragment, null,
|
|
127
|
+
React.createElement("div", null, goalSeekStatusText(current.setCell, current.result)),
|
|
128
|
+
current.result ? (React.createElement("dl", { className: "grid grid-cols-2 gap-1 text-xs" },
|
|
75
129
|
React.createElement("dt", { className: "text-rnc-foreground/70" }, "Target value:"),
|
|
76
|
-
React.createElement("dd", null,
|
|
130
|
+
React.createElement("dd", null, current.result.targetValue),
|
|
77
131
|
React.createElement("dt", { className: "text-rnc-foreground/70" }, "Current value:"),
|
|
78
|
-
React.createElement("dd", null,
|
|
132
|
+
React.createElement("dd", null, current.result.currentValue === undefined
|
|
79
133
|
? "—"
|
|
80
|
-
: String(
|
|
134
|
+
: String(current.result.currentValue)))) : null,
|
|
81
135
|
React.createElement(Separator, null),
|
|
82
136
|
React.createElement("div", { className: "flex justify-end gap-2" },
|
|
83
|
-
React.createElement(Button, { size: "sm", type: "button", onClick: () => onOpenChange(false) }, "OK"))))
|
|
137
|
+
React.createElement(Button, { size: "sm", type: "button", onClick: () => onOpenChange(false) }, "OK"))));
|
|
138
|
+
}
|
|
139
|
+
return (React.createElement(React.Fragment, null,
|
|
140
|
+
React.createElement("div", null, goalSeekCandidatesStatusText(current.setCell, current.result, current.targetValue, current.options)),
|
|
141
|
+
candidates.length > 0 ? (React.createElement("fieldset", { className: "flex flex-col gap-1 min-w-0" },
|
|
142
|
+
React.createElement("legend", { className: "text-xs font-medium mb-1" },
|
|
143
|
+
"Value for ",
|
|
144
|
+
current.changingCell,
|
|
145
|
+
":"),
|
|
146
|
+
candidates.map((candidate, index) => (React.createElement("label", { key: candidate.value, className: "flex items-center gap-2 text-xs py-0.5 cursor-pointer" },
|
|
147
|
+
React.createElement("input", { type: "radio", name: "goal-seek-candidate", value: index, checked: picked === index, onChange: () => setPicked(index) }),
|
|
148
|
+
React.createElement("span", null,
|
|
149
|
+
formatGoalSeekNumber(candidate.value),
|
|
150
|
+
React.createElement("span", { className: "text-rnc-foreground/70" },
|
|
151
|
+
" ",
|
|
152
|
+
"\u2192 ",
|
|
153
|
+
current.setCell,
|
|
154
|
+
" = ",
|
|
155
|
+
formatGoalSeekNumber(candidate.currentValue)))))))) : null,
|
|
156
|
+
React.createElement(Separator, null),
|
|
157
|
+
React.createElement("div", { className: "flex justify-end gap-2" }, candidates.length > 0 ? (React.createElement(React.Fragment, null,
|
|
158
|
+
React.createElement(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onOpenChange(false) }, "Cancel"),
|
|
159
|
+
React.createElement(Button, { size: "sm", type: "button", onClick: applyPicked }, "Apply"))) : (React.createElement(Button, { size: "sm", type: "button", onClick: () => onOpenChange(false) }, "OK")))));
|
|
160
|
+
};
|
|
161
|
+
return (React.createElement(Dialog, { open: open, onOpenChange: onOpenChange },
|
|
162
|
+
React.createElement(DialogContent, { className: "w-[360px] max-w-[92vw] pointer-events-auto" },
|
|
163
|
+
React.createElement(DialogTitle, null, outcome ? "Goal Seek Status" : "Goal Seek"),
|
|
164
|
+
React.createElement(DialogDescription, null, "Find the input value that makes a formula reach a target."),
|
|
165
|
+
React.createElement(DialogCloseButton, { onClick: () => onOpenChange(false) },
|
|
166
|
+
React.createElement(Cross1Icon, null)),
|
|
167
|
+
React.createElement(DialogBody, { className: "flex flex-col gap-3 font-system text-sm" }, outcome ? (React.createElement("div", { className: "flex flex-col gap-2", role: "status" }, renderStatus(outcome))) : (React.createElement("form", { className: "flex flex-col gap-3", onSubmit: submit },
|
|
84
168
|
React.createElement("label", { className: "flex flex-col gap-1 text-xs font-medium" },
|
|
85
169
|
"Set cell:",
|
|
86
170
|
React.createElement(Input, { autoFocus: true, value: setCell, "aria-label": "Set cell", onChange: (e) => {
|
|
87
171
|
setSetCell(e.target.value);
|
|
88
172
|
setError(undefined);
|
|
89
173
|
} })),
|
|
90
|
-
React.createElement("
|
|
174
|
+
React.createElement("div", { className: "flex flex-col gap-1 text-xs font-medium" },
|
|
91
175
|
"To value:",
|
|
92
|
-
React.createElement(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
176
|
+
React.createElement("div", { className: "flex gap-2" },
|
|
177
|
+
React.createElement("select", { className: "h-8 rounded border border-rnc-border bg-transparent px-2 text-sm", value: mode, "aria-label": "Target", onChange: (e) => setMode(e.target.value) }, Object.keys(MODE_LABELS).map((key) => (React.createElement("option", { key: key, value: key }, MODE_LABELS[key])))),
|
|
178
|
+
React.createElement(Input, { value: target, "aria-label": "To value", inputMode: "decimal", onChange: (e) => {
|
|
179
|
+
setTarget(e.target.value);
|
|
180
|
+
setError(undefined);
|
|
181
|
+
} }))),
|
|
96
182
|
React.createElement("label", { className: "flex flex-col gap-1 text-xs font-medium" },
|
|
97
183
|
"By changing cell:",
|
|
98
184
|
React.createElement(Input, { value: changingCell, "aria-label": "By changing cell", onChange: (e) => {
|
|
99
185
|
setChangingCell(e.target.value);
|
|
100
186
|
setError(undefined);
|
|
101
187
|
} })),
|
|
188
|
+
React.createElement("label", { className: "flex items-center gap-2 text-xs" },
|
|
189
|
+
React.createElement("input", { type: "checkbox", checked: round, onChange: (e) => setRound(e.target.checked) }),
|
|
190
|
+
"Round to a natural number"),
|
|
191
|
+
beyondExcel ? (React.createElement("label", { className: "flex flex-col gap-1 text-xs font-medium" },
|
|
192
|
+
"Within:",
|
|
193
|
+
React.createElement(Input, { value: tolerance, "aria-label": "Within", inputMode: "decimal", placeholder: "1% of the target", onChange: (e) => {
|
|
194
|
+
setTolerance(e.target.value);
|
|
195
|
+
setError(undefined);
|
|
196
|
+
} }))) : null,
|
|
102
197
|
error ? (React.createElement("div", { role: "alert", className: "text-xs text-rnc-destructive" }, error)) : null,
|
|
103
198
|
React.createElement(Separator, null),
|
|
104
199
|
React.createElement("div", { className: "flex justify-end gap-2" },
|
|
@@ -118,8 +213,10 @@ export const GoalSeekDialogHost = () => {
|
|
|
118
213
|
return (React.createElement(GoalSeekDialog, { open: request != null, onOpenChange: (open) => {
|
|
119
214
|
if (!open)
|
|
120
215
|
close();
|
|
121
|
-
}, initialSetCell: request?.setCell ?? "", onApply: (setCell, targetValue, changingCell) => request
|
|
122
|
-
?
|
|
123
|
-
|
|
216
|
+
}, initialSetCell: request?.setCell ?? "", onApply: (setCell, targetValue, changingCell, options) => request
|
|
217
|
+
? options
|
|
218
|
+
? request.onApply(setCell, targetValue, changingCell, options)
|
|
219
|
+
: request.onApply(setCell, targetValue, changingCell)
|
|
220
|
+
: Promise.resolve(undefined), onCommit: (changingCell, value) => request?.onCommit?.(changingCell, value) }));
|
|
124
221
|
};
|
|
125
222
|
GoalSeekDialogHost.displayName = "GoalSeekDialogHost";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/hidden-markers/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/hidden-markers/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,KAAK,UAAU,GAAG;IAChB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,kBAAkB,EAAE,MAAM,EAAE,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,UAAU,GAAG;IAClD,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG;IAC/C,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACxC,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,yDAIjC,wBAAwB,sBA0B1B,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,sDAI9B,qBAAqB,sBA8BvB,CAAC"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useGridContext } from "@rowsncolumns/grid";
|
|
2
|
-
import { TriangleDownIcon, TriangleLeftIcon, TriangleRightIcon, TriangleUpIcon, } from "@rowsncolumns/icons";
|
|
3
2
|
import React from "react";
|
|
4
|
-
import { StyledHiddenMarkerButton } from "./style";
|
|
3
|
+
import { HiddenDoubleLine, StyledHiddenMarkerButton } from "./style";
|
|
5
4
|
export const HiddenColumnMarkers = ({ hiddenDimensions, expandedDimensions, onShowColumn, }) => {
|
|
6
5
|
const { getCellOffsetFromCoords } = useGridContext();
|
|
7
6
|
const markers = hiddenDimensions.map((columnIndex, index) => {
|
|
@@ -9,12 +8,13 @@ export const HiddenColumnMarkers = ({ hiddenDimensions, expandedDimensions, onSh
|
|
|
9
8
|
rowIndex: 0,
|
|
10
9
|
columnIndex,
|
|
11
10
|
});
|
|
12
|
-
const { x = 0, y = 0 } = position ?? {};
|
|
11
|
+
const { x = 0, y = 0, height = 0 } = position ?? {};
|
|
12
|
+
// Excel marks hidden columns with a double line on the header boundary.
|
|
13
13
|
return (React.createElement(StyledHiddenMarkerButton, { style: {
|
|
14
14
|
transform: `translate3d(${x}px, ${y}px, 0)`,
|
|
15
|
+
height,
|
|
15
16
|
}, key: columnIndex, onClick: () => onShowColumn?.(expandedDimensions[index]), "aria-label": "Show column", tooltip: "Show column" },
|
|
16
|
-
React.createElement(
|
|
17
|
-
React.createElement(TriangleRightIcon, null)));
|
|
17
|
+
React.createElement(HiddenDoubleLine, null)));
|
|
18
18
|
});
|
|
19
19
|
return React.createElement(React.Fragment, null, markers);
|
|
20
20
|
};
|
|
@@ -25,15 +25,16 @@ export const HiddenRowMarkers = ({ hiddenDimensions, expandedDimensions, onShowR
|
|
|
25
25
|
rowIndex,
|
|
26
26
|
columnIndex: 0,
|
|
27
27
|
});
|
|
28
|
-
const { x = 0, y = 0 } = position ?? {};
|
|
28
|
+
const { x = 0, y = 0, width = 0 } = position ?? {};
|
|
29
|
+
// Excel marks hidden rows with a double line on the header boundary.
|
|
29
30
|
return (React.createElement(StyledHiddenMarkerButton, { style: {
|
|
30
31
|
position: "absolute",
|
|
31
32
|
left: x,
|
|
32
33
|
top: y,
|
|
34
|
+
width,
|
|
33
35
|
pointerEvents: "all",
|
|
34
36
|
}, key: rowIndex, onClick: () => onShowRow?.(expandedDimensions[index]), isVertical: true, "aria-label": "Show row", tooltip: "Show row" },
|
|
35
|
-
React.createElement(
|
|
36
|
-
React.createElement(TriangleDownIcon, null)));
|
|
37
|
+
React.createElement(HiddenDoubleLine, { isVertical: true })));
|
|
37
38
|
});
|
|
38
39
|
return React.createElement(React.Fragment, null, markers);
|
|
39
40
|
};
|
|
@@ -2,4 +2,11 @@ import React from "react";
|
|
|
2
2
|
export declare const StyledHiddenMarkerButton: React.ForwardRefExoticComponent<Omit<import("@rowsncolumns/ui").IconButtonProps & React.RefAttributes<HTMLButtonElement>, "ref"> & {
|
|
3
3
|
isVertical?: boolean;
|
|
4
4
|
} & React.RefAttributes<HTMLButtonElement>>;
|
|
5
|
+
/**
|
|
6
|
+
* Two 1 px lines with a 1 px gap — Excel's marker for hidden rows / columns
|
|
7
|
+
* in the headers.
|
|
8
|
+
*/
|
|
9
|
+
export declare const HiddenDoubleLine: ({ isVertical }: {
|
|
10
|
+
isVertical?: boolean;
|
|
11
|
+
}) => React.JSX.Element;
|
|
5
12
|
//# sourceMappingURL=style.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../../../components/hidden-markers/style.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,eAAO,MAAM,wBAAwB;iBAEgC,OAAO;2CAY1E,CAAC"}
|
|
1
|
+
{"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../../../components/hidden-markers/style.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,eAAO,MAAM,wBAAwB;iBAEgC,OAAO;2CAY1E,CAAC;AAIH;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,gBAAgB;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,sBAWxE,CAAC"}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { cn, IconButton } from "@rowsncolumns/ui";
|
|
2
2
|
import React from "react";
|
|
3
|
-
export const StyledHiddenMarkerButton = React.forwardRef(({ className, isVertical, ...props }, ref) => (React.createElement(IconButton, { ref: ref, className: cn("flex absolute border-none p-0 rounded-
|
|
3
|
+
export const StyledHiddenMarkerButton = React.forwardRef(({ className, isVertical, ...props }, ref) => (React.createElement(IconButton, { ref: ref, className: cn("flex absolute border-none p-0 rounded-none left-0 top-0 pointer-events-auto w-[5px] -ml-[2px] justify-center items-stretch", "bg-transparent hover:bg-transparent print:hidden min-h-0 min-w-0", isVertical ? "h-[5px] -mt-[2px] ml-0 flex-col" : undefined, className), ...props })));
|
|
4
4
|
StyledHiddenMarkerButton.displayName = "StyledHiddenMarkerButton";
|
|
5
|
+
/**
|
|
6
|
+
* Two 1 px lines with a 1 px gap — Excel's marker for hidden rows / columns
|
|
7
|
+
* in the headers.
|
|
8
|
+
*/
|
|
9
|
+
export const HiddenDoubleLine = ({ isVertical }) => (React.createElement("span", { "aria-hidden": true, "data-hidden-double-line": "", className: cn("block border-rnc-foreground/60", isVertical
|
|
10
|
+
? "w-full h-[3px] border-y border-solid"
|
|
11
|
+
: "h-full w-[3px] border-x border-solid") }));
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { SheetProtection } from "../../types";
|
|
3
|
+
/** An OOXML `CT_SheetProtection` action flag the Protect Sheet dialog offers. */
|
|
4
|
+
export type SheetProtectionAllowFlag = "selectLockedCells" | "selectUnlockedCells" | "formatCells" | "formatColumns" | "formatRows" | "insertColumns" | "insertRows" | "insertHyperlinks" | "deleteColumns" | "deleteRows" | "sort" | "autoFilter" | "pivotTables" | "objects" | "scenarios";
|
|
5
|
+
/**
|
|
6
|
+
* Excel's "Allow all users of this worksheet to:" list, in the dialog's order
|
|
7
|
+
* (support.microsoft.com "Protect a worksheet"), with the dialog defaults:
|
|
8
|
+
* only selecting locked and unlocked cells is ticked.
|
|
9
|
+
*/
|
|
10
|
+
export declare const SHEET_PROTECTION_ALLOW_OPTIONS: ReadonlyArray<{
|
|
11
|
+
flag: SheetProtectionAllowFlag;
|
|
12
|
+
label: string;
|
|
13
|
+
defaultAllowed: boolean;
|
|
14
|
+
}>;
|
|
15
|
+
export type SheetProtectionAllowState = Record<SheetProtectionAllowFlag, boolean>;
|
|
16
|
+
/** The dialog's ticked boxes for a sheet's last protection (or the defaults). */
|
|
17
|
+
export declare const sheetProtectionToAllowState: (protection?: SheetProtection | null) => SheetProtectionAllowState;
|
|
18
|
+
/**
|
|
19
|
+
* The ticked boxes → OOXML flags, where `true` PROHIBITS the action. Every
|
|
20
|
+
* flag is written explicitly so the stored protection never depends on a
|
|
21
|
+
* schema default.
|
|
22
|
+
*/
|
|
23
|
+
export declare const allowStateToSheetProtection: (state: SheetProtectionAllowState) => Omit<SheetProtection, "password" | "algorithmName" | "hashValue" | "saltValue" | "spinCount">;
|
|
24
|
+
/** Excel's text when the re-entered password differs. */
|
|
25
|
+
export declare const CONFIRM_PASSWORD_MISMATCH = "Confirmation password is not identical.";
|
|
26
|
+
export type ProtectSheetDialogProps = {
|
|
27
|
+
open: boolean;
|
|
28
|
+
onOpenChange(open: boolean): void;
|
|
29
|
+
/** The sheet's previous protection, to pre-tick its choices. */
|
|
30
|
+
initial?: SheetProtection | null;
|
|
31
|
+
/**
|
|
32
|
+
* OK: the OOXML flags and the plaintext password (empty = none). rnc engine:
|
|
33
|
+
* `onProtectSheet(sheetId, { sheetProtection, password })`, which stores only
|
|
34
|
+
* the password's hash.
|
|
35
|
+
*/
|
|
36
|
+
onConfirm(options: {
|
|
37
|
+
sheetProtection: ReturnType<typeof allowStateToSheetProtection>;
|
|
38
|
+
password?: string;
|
|
39
|
+
}): void;
|
|
40
|
+
};
|
|
41
|
+
/** Review ▸ Protect Sheet (support.microsoft.com "Protect a worksheet"). */
|
|
42
|
+
export declare const ProtectSheetDialog: React.MemoExoticComponent<({ open, onOpenChange, initial, onConfirm }: ProtectSheetDialogProps) => React.JSX.Element>;
|
|
43
|
+
export type ProtectWorkbookDialogProps = {
|
|
44
|
+
open: boolean;
|
|
45
|
+
onOpenChange(open: boolean): void;
|
|
46
|
+
/** OK: rnc engine `onProtectWorkbook({ lockStructure, password })`. */
|
|
47
|
+
onConfirm(options: {
|
|
48
|
+
lockStructure: boolean;
|
|
49
|
+
password?: string;
|
|
50
|
+
}): void;
|
|
51
|
+
};
|
|
52
|
+
/** Review ▸ Protect Workbook (support.microsoft.com "Protect a workbook"). */
|
|
53
|
+
export declare const ProtectWorkbookDialog: React.MemoExoticComponent<({ open, onOpenChange, onConfirm }: ProtectWorkbookDialogProps) => React.JSX.Element>;
|
|
54
|
+
export type UnprotectDialogProps = {
|
|
55
|
+
open: boolean;
|
|
56
|
+
onOpenChange(open: boolean): void;
|
|
57
|
+
/** `"Unprotect Sheet"` or `"Unprotect Workbook"`. */
|
|
58
|
+
title: string;
|
|
59
|
+
/**
|
|
60
|
+
* OK with the typed password. The engine verifies it and refuses a wrong one
|
|
61
|
+
* (`incorrect-password`, shown by the host's rejection dialog).
|
|
62
|
+
*/
|
|
63
|
+
onConfirm(password: string): void;
|
|
64
|
+
};
|
|
65
|
+
/** The password prompt Excel shows for Unprotect Sheet / Unprotect Workbook. */
|
|
66
|
+
export declare const UnprotectDialog: React.MemoExoticComponent<({ open, onOpenChange, title, onConfirm }: UnprotectDialogProps) => React.JSX.Element>;
|
|
67
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/protect-sheet-dialog/index.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAyB,MAAM,OAAO,CAAC;AAE9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,iFAAiF;AACjF,MAAM,MAAM,wBAAwB,GAChC,mBAAmB,GACnB,qBAAqB,GACrB,aAAa,GACb,eAAe,GACf,YAAY,GACZ,eAAe,GACf,YAAY,GACZ,kBAAkB,GAClB,eAAe,GACf,YAAY,GACZ,MAAM,GACN,YAAY,GACZ,aAAa,GACb,SAAS,GACT,WAAW,CAAC;AAEhB;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,EAAE,aAAa,CAAC;IACzD,IAAI,EAAE,wBAAwB,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;CACzB,CAgBA,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;AAElF,iFAAiF;AACjF,eAAO,MAAM,2BAA2B,GACtC,aAAa,eAAe,GAAG,IAAI,KAClC,yBAOF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,GACtC,OAAO,yBAAyB,KAC/B,IAAI,CACL,eAAe,EACf,UAAU,GAAG,eAAe,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAOvE,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,yBAAyB,4CAA4C,CAAC;AA4DnF,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,gEAAgE;IAChE,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC;;;;OAIG;IACH,SAAS,CAAC,OAAO,EAAE;QACjB,eAAe,EAAE,UAAU,CAAC,OAAO,2BAA2B,CAAC,CAAC;QAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI,CAAC;CACV,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,yEACgB,uBAAuB,uBAoErE,CAAC;AAIF,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,uEAAuE;IACvE,SAAS,CAAC,OAAO,EAAE;QAAE,aAAa,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACzE,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,gEACI,0BAA0B,uBAwD/D,CAAC;AAIF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,eAAe,uEACiB,oBAAoB,uBAmChE,CAAC"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { Button, Dialog, DialogBody, DialogCloseButton, DialogContent, DialogTitle, Input, Separator, } from "@rowsncolumns/ui";
|
|
2
|
+
import React, { memo, useState } from "react";
|
|
3
|
+
/**
|
|
4
|
+
* Excel's "Allow all users of this worksheet to:" list, in the dialog's order
|
|
5
|
+
* (support.microsoft.com "Protect a worksheet"), with the dialog defaults:
|
|
6
|
+
* only selecting locked and unlocked cells is ticked.
|
|
7
|
+
*/
|
|
8
|
+
export const SHEET_PROTECTION_ALLOW_OPTIONS = [
|
|
9
|
+
{ flag: "selectLockedCells", label: "Select locked cells", defaultAllowed: true },
|
|
10
|
+
{ flag: "selectUnlockedCells", label: "Select unlocked cells", defaultAllowed: true },
|
|
11
|
+
{ flag: "formatCells", label: "Format cells", defaultAllowed: false },
|
|
12
|
+
{ flag: "formatColumns", label: "Format columns", defaultAllowed: false },
|
|
13
|
+
{ flag: "formatRows", label: "Format rows", defaultAllowed: false },
|
|
14
|
+
{ flag: "insertColumns", label: "Insert columns", defaultAllowed: false },
|
|
15
|
+
{ flag: "insertRows", label: "Insert rows", defaultAllowed: false },
|
|
16
|
+
{ flag: "insertHyperlinks", label: "Insert hyperlinks", defaultAllowed: false },
|
|
17
|
+
{ flag: "deleteColumns", label: "Delete columns", defaultAllowed: false },
|
|
18
|
+
{ flag: "deleteRows", label: "Delete rows", defaultAllowed: false },
|
|
19
|
+
{ flag: "sort", label: "Sort", defaultAllowed: false },
|
|
20
|
+
{ flag: "autoFilter", label: "Use AutoFilter", defaultAllowed: false },
|
|
21
|
+
{ flag: "pivotTables", label: "Use PivotTable & PivotChart", defaultAllowed: false },
|
|
22
|
+
{ flag: "objects", label: "Edit objects", defaultAllowed: false },
|
|
23
|
+
{ flag: "scenarios", label: "Edit scenarios", defaultAllowed: false },
|
|
24
|
+
];
|
|
25
|
+
/** The dialog's ticked boxes for a sheet's last protection (or the defaults). */
|
|
26
|
+
export const sheetProtectionToAllowState = (protection) => {
|
|
27
|
+
const state = {};
|
|
28
|
+
for (const { flag, defaultAllowed } of SHEET_PROTECTION_ALLOW_OPTIONS) {
|
|
29
|
+
const prohibited = protection?.[flag];
|
|
30
|
+
state[flag] = typeof prohibited === "boolean" ? !prohibited : defaultAllowed;
|
|
31
|
+
}
|
|
32
|
+
return state;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The ticked boxes → OOXML flags, where `true` PROHIBITS the action. Every
|
|
36
|
+
* flag is written explicitly so the stored protection never depends on a
|
|
37
|
+
* schema default.
|
|
38
|
+
*/
|
|
39
|
+
export const allowStateToSheetProtection = (state) => {
|
|
40
|
+
const protection = { sheet: true };
|
|
41
|
+
for (const { flag } of SHEET_PROTECTION_ALLOW_OPTIONS) {
|
|
42
|
+
protection[flag] = !state[flag];
|
|
43
|
+
}
|
|
44
|
+
return protection;
|
|
45
|
+
};
|
|
46
|
+
/** Excel's text when the re-entered password differs. */
|
|
47
|
+
export const CONFIRM_PASSWORD_MISMATCH = "Confirmation password is not identical.";
|
|
48
|
+
/** Password + "Reenter password to proceed", as Excel's Confirm Password step. */
|
|
49
|
+
const PasswordFields = ({ label, password, confirm, mismatch, onPassword, onConfirm, }) => (React.createElement(React.Fragment, null,
|
|
50
|
+
React.createElement("label", { className: "flex flex-col gap-1 text-xs font-medium" },
|
|
51
|
+
label,
|
|
52
|
+
React.createElement(Input, { type: "password", autoComplete: "new-password", value: password, onChange: (e) => onPassword(e.target.value), "data-testid": "protection-password" })),
|
|
53
|
+
password !== "" && (React.createElement("label", { className: "flex flex-col gap-1 text-xs font-medium" },
|
|
54
|
+
"Reenter password to proceed:",
|
|
55
|
+
React.createElement(Input, { type: "password", autoComplete: "new-password", value: confirm, onChange: (e) => onConfirm(e.target.value), "data-testid": "protection-password-confirm" }))),
|
|
56
|
+
mismatch && (React.createElement("p", { role: "alert", className: "text-xs text-red-600" }, CONFIRM_PASSWORD_MISMATCH))));
|
|
57
|
+
const DialogButtons = ({ onCancel }) => (React.createElement("div", { className: "flex justify-end gap-2" },
|
|
58
|
+
React.createElement(Button, { type: "button", variant: "outline", size: "sm", onClick: onCancel }, "Cancel"),
|
|
59
|
+
React.createElement(Button, { type: "submit", size: "sm" }, "OK")));
|
|
60
|
+
/** Review ▸ Protect Sheet (support.microsoft.com "Protect a worksheet"). */
|
|
61
|
+
export const ProtectSheetDialog = memo(({ open, onOpenChange, initial, onConfirm }) => {
|
|
62
|
+
const [allow, setAllow] = useState(() => sheetProtectionToAllowState(initial));
|
|
63
|
+
const [password, setPassword] = useState("");
|
|
64
|
+
const [confirm, setConfirm] = useState("");
|
|
65
|
+
const [mismatch, setMismatch] = useState(false);
|
|
66
|
+
return (React.createElement(Dialog, { open: open, onOpenChange: onOpenChange, modal: true },
|
|
67
|
+
React.createElement(DialogContent, { className: "w-[360px] max-w-[92vw] pointer-events-auto" },
|
|
68
|
+
React.createElement(DialogTitle, null, "Protect Sheet"),
|
|
69
|
+
React.createElement(DialogCloseButton, null),
|
|
70
|
+
React.createElement(DialogBody, null,
|
|
71
|
+
React.createElement("form", { className: "flex flex-col gap-3", onSubmit: (e) => {
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
if (password !== "" && password !== confirm) {
|
|
74
|
+
setMismatch(true);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
onConfirm({
|
|
78
|
+
sheetProtection: allowStateToSheetProtection(allow),
|
|
79
|
+
...(password ? { password } : {}),
|
|
80
|
+
});
|
|
81
|
+
onOpenChange(false);
|
|
82
|
+
} },
|
|
83
|
+
React.createElement(PasswordFields, { label: "Password to unprotect sheet:", password: password, confirm: confirm, mismatch: mismatch, onPassword: (v) => {
|
|
84
|
+
setPassword(v);
|
|
85
|
+
setMismatch(false);
|
|
86
|
+
}, onConfirm: (v) => {
|
|
87
|
+
setConfirm(v);
|
|
88
|
+
setMismatch(false);
|
|
89
|
+
} }),
|
|
90
|
+
React.createElement("fieldset", { className: "flex flex-col gap-1" },
|
|
91
|
+
React.createElement("legend", { className: "mb-1 text-xs font-medium" }, "Allow all users of this worksheet to:"),
|
|
92
|
+
React.createElement("div", { className: "flex max-h-56 flex-col gap-1 overflow-y-auto rounded border p-2" }, SHEET_PROTECTION_ALLOW_OPTIONS.map(({ flag, label }) => (React.createElement("label", { key: flag, className: "flex items-center gap-2 text-xs" },
|
|
93
|
+
React.createElement("input", { type: "checkbox", checked: allow[flag], "data-testid": `protect-allow-${flag}`, onChange: (e) => setAllow((prev) => ({ ...prev, [flag]: e.target.checked })) }),
|
|
94
|
+
label))))),
|
|
95
|
+
React.createElement(Separator, null),
|
|
96
|
+
React.createElement(DialogButtons, { onCancel: () => onOpenChange(false) }))))));
|
|
97
|
+
});
|
|
98
|
+
ProtectSheetDialog.displayName = "ProtectSheetDialog";
|
|
99
|
+
/** Review ▸ Protect Workbook (support.microsoft.com "Protect a workbook"). */
|
|
100
|
+
export const ProtectWorkbookDialog = memo(({ open, onOpenChange, onConfirm }) => {
|
|
101
|
+
const [structure, setStructure] = useState(true);
|
|
102
|
+
const [password, setPassword] = useState("");
|
|
103
|
+
const [confirm, setConfirm] = useState("");
|
|
104
|
+
const [mismatch, setMismatch] = useState(false);
|
|
105
|
+
return (React.createElement(Dialog, { open: open, onOpenChange: onOpenChange, modal: true },
|
|
106
|
+
React.createElement(DialogContent, { className: "w-[340px] max-w-[92vw] pointer-events-auto" },
|
|
107
|
+
React.createElement(DialogTitle, null, "Protect Structure and Windows"),
|
|
108
|
+
React.createElement(DialogCloseButton, null),
|
|
109
|
+
React.createElement(DialogBody, null,
|
|
110
|
+
React.createElement("form", { className: "flex flex-col gap-3", onSubmit: (e) => {
|
|
111
|
+
e.preventDefault();
|
|
112
|
+
if (password !== "" && password !== confirm) {
|
|
113
|
+
setMismatch(true);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (structure) {
|
|
117
|
+
onConfirm({ lockStructure: true, ...(password ? { password } : {}) });
|
|
118
|
+
}
|
|
119
|
+
onOpenChange(false);
|
|
120
|
+
} },
|
|
121
|
+
React.createElement("label", { className: "flex items-center gap-2 text-xs font-medium" },
|
|
122
|
+
React.createElement("input", { type: "checkbox", checked: structure, "data-testid": "protect-workbook-structure", onChange: (e) => setStructure(e.target.checked) }),
|
|
123
|
+
"Structure"),
|
|
124
|
+
React.createElement(PasswordFields, { label: "Password (optional):", password: password, confirm: confirm, mismatch: mismatch, onPassword: (v) => {
|
|
125
|
+
setPassword(v);
|
|
126
|
+
setMismatch(false);
|
|
127
|
+
}, onConfirm: (v) => {
|
|
128
|
+
setConfirm(v);
|
|
129
|
+
setMismatch(false);
|
|
130
|
+
} }),
|
|
131
|
+
React.createElement(Separator, null),
|
|
132
|
+
React.createElement(DialogButtons, { onCancel: () => onOpenChange(false) }))))));
|
|
133
|
+
});
|
|
134
|
+
ProtectWorkbookDialog.displayName = "ProtectWorkbookDialog";
|
|
135
|
+
/** The password prompt Excel shows for Unprotect Sheet / Unprotect Workbook. */
|
|
136
|
+
export const UnprotectDialog = memo(({ open, onOpenChange, title, onConfirm }) => {
|
|
137
|
+
const [password, setPassword] = useState("");
|
|
138
|
+
return (React.createElement(Dialog, { open: open, onOpenChange: onOpenChange, modal: true },
|
|
139
|
+
React.createElement(DialogContent, { className: "w-[320px] max-w-[92vw] pointer-events-auto" },
|
|
140
|
+
React.createElement(DialogTitle, null, title),
|
|
141
|
+
React.createElement(DialogCloseButton, null),
|
|
142
|
+
React.createElement(DialogBody, null,
|
|
143
|
+
React.createElement("form", { className: "flex flex-col gap-3", onSubmit: (e) => {
|
|
144
|
+
e.preventDefault();
|
|
145
|
+
onConfirm(password);
|
|
146
|
+
onOpenChange(false);
|
|
147
|
+
} },
|
|
148
|
+
React.createElement("label", { className: "flex flex-col gap-1 text-xs font-medium" },
|
|
149
|
+
"Password:",
|
|
150
|
+
React.createElement(Input, { type: "password", autoComplete: "current-password", autoFocus: true, value: password, onChange: (e) => setPassword(e.target.value), "data-testid": "unprotect-password" })),
|
|
151
|
+
React.createElement(Separator, null),
|
|
152
|
+
React.createElement(DialogButtons, { onCancel: () => onOpenChange(false) }))))));
|
|
153
|
+
});
|
|
154
|
+
UnprotectDialog.displayName = "UnprotectDialog";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type BorderLocation = "all" | "outer" | "inner" | "vertical" | "horizontal" | "left" | "right" | "bottom" | "top";
|
|
1
|
+
export type BorderLocation = "all" | "outer" | "inner" | "vertical" | "horizontal" | "left" | "right" | "bottom" | "top" | "diagonalUp" | "diagonalDown" | "none";
|
|
2
2
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../components/toolbar/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GACtB,KAAK,GACL,OAAO,GACP,OAAO,GACP,UAAU,GACV,YAAY,GACZ,MAAM,GACN,OAAO,GACP,QAAQ,GACR,KAAK,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../components/toolbar/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GACtB,KAAK,GACL,OAAO,GACP,OAAO,GACP,UAAU,GACV,YAAY,GACZ,MAAM,GACN,OAAO,GACP,QAAQ,GACR,KAAK,GAGL,YAAY,GACZ,cAAc,GACd,MAAM,CAAC"}
|
package/dist/esm/config.d.ts
CHANGED
|
@@ -19,7 +19,19 @@ export declare const COLUMN_HEADER_HEIGHT = 24;
|
|
|
19
19
|
export declare const OUTLINE_GUTTER_LEVEL_PX = 17;
|
|
20
20
|
export declare const OUTLINE_GUTTER_PAD_PX = 4;
|
|
21
21
|
export declare const DEFAULT_CELL_SPACING = 2.5;
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* One indent level (Format Cells ▸ Alignment ▸ Indent) at 100 % zoom. ECMA-376
|
|
24
|
+
* §18.8.1 defines a level as three spaces of the Normal font — 3 × 3.3 px for
|
|
25
|
+
* 11 pt Calibri at 96 dpi. Callers multiply it by the zoom scale.
|
|
26
|
+
*/
|
|
27
|
+
export declare const INDENT_SPACING = 10;
|
|
28
|
+
/**
|
|
29
|
+
* Excel's AutoFilter / table header button: a light grey square with a grey
|
|
30
|
+
* border and a dark grey glyph.
|
|
31
|
+
*/
|
|
32
|
+
export declare const FILTER_BUTTON_GLYPH_COLOR = "#444444";
|
|
33
|
+
export declare const FILTER_BUTTON_BORDER_COLOR = "#ABABAB";
|
|
34
|
+
export declare const FILTER_BUTTON_FILL_COLOR = "#F3F3F3";
|
|
23
35
|
export declare const MIN_COLUMN_WIDTH = 24;
|
|
24
36
|
export declare const CELL_VERTICAL_ALIGNMENT = "bottom";
|
|
25
37
|
export declare const CELL_HORIZONTAL_ALIGNMENT = "left";
|
package/dist/esm/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEzE,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE3D,eAAO,MAAM,mBAAmB,EAAE,aAGhC,CAAC;AACH,eAAO,MAAM,kBAAkB,kBAAoB,CAAC;AACpD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,GAAG,CAAM,CAAC;AAC5C,eAAO,MAAM,kBAAkB,kBAAqB,CAAC;AACrD,eAAO,MAAM,uBAAuB,EAAE,YAGpC,CAAC;AAEH,eAAO,MAAM,aAAa,UAAY,CAAC;AAEvC,eAAO,MAAM,gBAAgB,QAAS,CAAC;AAGvC,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,oBAAoB,MAAM,CAAC;AACxC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAMvC,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAC1C,eAAO,MAAM,qBAAqB,IAAI,CAAC;AACvC,eAAO,MAAM,oBAAoB,MAAM,CAAC;AACxC,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../config.ts"],"names":[],"mappings":"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"}
|