@sheetpane/grid 0.1.0 → 0.4.0

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.
Files changed (86) hide show
  1. package/README.md +294 -13
  2. package/custom-elements.json +292 -27
  3. package/dist/check.d.ts +75 -0
  4. package/dist/check.d.ts.map +1 -0
  5. package/dist/check.js +151 -0
  6. package/dist/check.js.map +1 -0
  7. package/dist/errors/element.d.ts +90 -12
  8. package/dist/errors/element.d.ts.map +1 -1
  9. package/dist/errors/element.js +572 -50
  10. package/dist/errors/element.js.map +1 -1
  11. package/dist/excel/element.d.ts +168 -15
  12. package/dist/excel/element.d.ts.map +1 -1
  13. package/dist/excel/element.js +752 -90
  14. package/dist/excel/element.js.map +1 -1
  15. package/dist/excel/link.d.ts +40 -0
  16. package/dist/excel/link.d.ts.map +1 -0
  17. package/dist/excel/link.js +90 -0
  18. package/dist/excel/link.js.map +1 -0
  19. package/dist/excel/styles.d.ts.map +1 -1
  20. package/dist/excel/styles.js +37 -5
  21. package/dist/excel/styles.js.map +1 -1
  22. package/dist/frameworks/elements.d.ts +57 -17
  23. package/dist/frameworks/jsx.d.ts +15 -9
  24. package/dist/frameworks/solid.d.ts +51 -11
  25. package/dist/frameworks/svelte.d.ts +28 -16
  26. package/dist/frameworks/vue.d.ts +15 -9
  27. package/dist/index.d.ts +9 -4
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +8 -2
  30. package/dist/index.js.map +1 -1
  31. package/dist/llms-full.txt +3290 -544
  32. package/dist/llms.txt +92 -89
  33. package/dist/pane/protection.d.ts +61 -0
  34. package/dist/pane/protection.d.ts.map +1 -0
  35. package/dist/pane/protection.js +89 -0
  36. package/dist/pane/protection.js.map +1 -0
  37. package/dist/pane/rules.d.ts +1 -1
  38. package/dist/pane/rules.d.ts.map +1 -1
  39. package/dist/pane/store.d.ts +336 -15
  40. package/dist/pane/store.d.ts.map +1 -1
  41. package/dist/pane/store.js +891 -44
  42. package/dist/pane/store.js.map +1 -1
  43. package/dist/pane/structure.d.ts +58 -0
  44. package/dist/pane/structure.d.ts.map +1 -0
  45. package/dist/pane/structure.js +238 -0
  46. package/dist/pane/structure.js.map +1 -0
  47. package/dist/pane/types.d.ts +195 -6
  48. package/dist/pane/types.d.ts.map +1 -1
  49. package/dist/pane/types.js +57 -0
  50. package/dist/pane/types.js.map +1 -1
  51. package/dist/plugins/types.d.ts +34 -6
  52. package/dist/plugins/types.d.ts.map +1 -1
  53. package/dist/plugins/types.js.map +1 -1
  54. package/dist/shared/detail.d.ts +24 -0
  55. package/dist/shared/detail.d.ts.map +1 -0
  56. package/dist/shared/detail.js +75 -0
  57. package/dist/shared/detail.js.map +1 -0
  58. package/dist/shared/dom.d.ts +3 -0
  59. package/dist/shared/dom.d.ts.map +1 -1
  60. package/dist/shared/dom.js +3 -0
  61. package/dist/shared/dom.js.map +1 -1
  62. package/dist/static.d.ts +81 -0
  63. package/dist/static.d.ts.map +1 -0
  64. package/dist/static.js +352 -0
  65. package/dist/static.js.map +1 -0
  66. package/dist/style.css +3 -3
  67. package/dist/tokens.d.ts +1 -0
  68. package/dist/tokens.d.ts.map +1 -1
  69. package/dist/tokens.js +2 -2
  70. package/dist/tokens.js.map +1 -1
  71. package/dist/vscode.css-custom-data.json +11 -1
  72. package/dist/vscode.html-custom-data.json +89 -2
  73. package/dist/web-types.json +204 -21
  74. package/package.json +13 -7
  75. package/dist/errors/index.d.ts +0 -2
  76. package/dist/errors/index.d.ts.map +0 -1
  77. package/dist/errors/index.js +0 -3
  78. package/dist/errors/index.js.map +0 -1
  79. package/dist/excel/index.d.ts +0 -2
  80. package/dist/excel/index.d.ts.map +0 -1
  81. package/dist/excel/index.js +0 -3
  82. package/dist/excel/index.js.map +0 -1
  83. package/dist/pane/index.d.ts +0 -2
  84. package/dist/pane/index.d.ts.map +0 -1
  85. package/dist/pane/index.js +0 -3
  86. package/dist/pane/index.js.map +0 -1
@@ -0,0 +1,40 @@
1
+ import { type RangePos } from '@sheetpane/export';
2
+ /** The key of sheetpane's part of a URL fragment: `sheetpane=<pane>:<Sheet>!<ref>`. */
3
+ export declare const LINK_KEY = "sheetpane";
4
+ /** A cell or range to open at: the sheet it names (none: the sheet shown) and its A1 corners. */
5
+ export interface LinkTarget {
6
+ sheet?: string;
7
+ range: RangePos;
8
+ }
9
+ /** `Data!B3` → `{ sheet: 'Data', ref: 'B3' }`; `'Q3 data'!B3` is unquoted; `B3` names no sheet. */
10
+ export declare function splitSheetRef(text: string): {
11
+ sheet?: string;
12
+ ref: string;
13
+ };
14
+ /**
15
+ * Reads `B4`, `Data!B4`, `'Q3 data'!B4:D8` — a cell or an A1 range, with or without its sheet.
16
+ * @param text - The reference as a host or a link writes it.
17
+ * @returns The target, or `undefined` when the text is not a cell or range (the sheet is checked by the caller).
18
+ */
19
+ export declare function parseTarget(text: string): LinkTarget | undefined;
20
+ /**
21
+ * The link for a pane in a URL fragment, as `Sheet!B4` text.
22
+ * @param hash - `location.hash`, with or without its `#`.
23
+ * @param pane - The element's `pane` (`''` when it has none).
24
+ * @returns The reference text (`'Q3 data'!B4` when the sheet needs quoting), or `undefined` when the fragment names nothing for this pane.
25
+ */
26
+ export declare function readLink(hash: string, pane: string): string | undefined;
27
+ /**
28
+ * A fragment with this pane's link set (or removed), every other part kept as it was: the link replaces the
29
+ * pane's old one where it stood; a new one goes after a hash router's path with `?` (`#/reports/12?sheetpane=…`),
30
+ * after anything else with `&`, or alone.
31
+ * @param hash - `location.hash`, with or without its `#`.
32
+ * @param pane - The element's `pane` (`''` when it has none).
33
+ * @param at - The sheet and the cell or range (`B4`, `B4:D8`) to link to; `undefined` removes the pane's link.
34
+ * @returns The new fragment, without its `#` (`''`: no fragment).
35
+ */
36
+ export declare function writeLink(hash: string, pane: string, at: {
37
+ sheet: string;
38
+ ref: string;
39
+ } | undefined): string;
40
+ //# sourceMappingURL=link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../src/excel/link.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE9D,uFAAuF;AACvF,eAAO,MAAM,QAAQ,cAAc,CAAC;AAEpC,iGAAiG;AACjG,MAAM,WAAW,UAAU;IAAG,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE;AAE/D,mGAAmG;AACnG,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAM3E;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAIhE;AAwBD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GAAG,MAAM,CAO5G"}
@@ -0,0 +1,90 @@
1
+ // W-66: the cell a page opens at — the `ref` attribute's text and the opt-in `link="hash"` fragment,
2
+ // `#sheetpane=<pane>:<Sheet>!<ref>`. Pure string work, no DOM: the element reads `location.hash` and
3
+ // writes it back with `history.replaceState`. A URL fragment is never sent to a server (SR-LAW-11).
4
+ import { parseRange } from '@sheetpane/export';
5
+ /** The key of sheetpane's part of a URL fragment: `sheetpane=<pane>:<Sheet>!<ref>`. */
6
+ export const LINK_KEY = 'sheetpane';
7
+ /** `Data!B3` → `{ sheet: 'Data', ref: 'B3' }`; `'Q3 data'!B3` is unquoted; `B3` names no sheet. */
8
+ export function splitSheetRef(text) {
9
+ const i = text.lastIndexOf('!');
10
+ if (i < 0)
11
+ return { ref: text.trim() };
12
+ let sheet = text.slice(0, i).trim();
13
+ if (sheet.length >= 2 && sheet.startsWith("'") && sheet.endsWith("'"))
14
+ sheet = sheet.slice(1, -1).replace(/''/g, "'");
15
+ return { sheet, ref: text.slice(i + 1).trim() };
16
+ }
17
+ /**
18
+ * Reads `B4`, `Data!B4`, `'Q3 data'!B4:D8` — a cell or an A1 range, with or without its sheet.
19
+ * @param text - The reference as a host or a link writes it.
20
+ * @returns The target, or `undefined` when the text is not a cell or range (the sheet is checked by the caller).
21
+ */
22
+ export function parseTarget(text) {
23
+ const at = splitSheetRef(text), range = parseRange(at.ref);
24
+ if (!range || at.sheet === '')
25
+ return undefined;
26
+ return at.sheet === undefined ? { range } : { sheet: at.sheet, range };
27
+ }
28
+ // The value is `<pane>:<Sheet>!<ref>`, the pane and sheet percent-encoded with `!` too, so the last literal `!`
29
+ // ends the sheet and the one literal `:` before it ends the pane (a range's own `:` comes after the `!`).
30
+ // No pane: `<Sheet>!<ref>`. No sheet (written by hand; sheetpane always writes it): `<pane>:<ref>`.
31
+ const enc = (s) => encodeURIComponent(s).replace(/!/g, '%21').replace(/'/g, '%27');
32
+ const dec = (s) => { try {
33
+ return decodeURIComponent(s);
34
+ }
35
+ catch {
36
+ return s;
37
+ } };
38
+ /** The fragment's parts: a hash router's path (`/reports/12`, `!/x`) and the `&`-separated parameters after it. */
39
+ function partsOf(hash) {
40
+ const h = hash.startsWith('#') ? hash.slice(1) : hash;
41
+ if (/^!?\//.test(h)) {
42
+ const q = h.indexOf('?');
43
+ return { path: q < 0 ? h : h.slice(0, q), params: q < 0 ? [] : h.slice(q + 1).split('&').filter(Boolean) };
44
+ }
45
+ return { path: undefined, params: h.split('&').filter(Boolean) };
46
+ }
47
+ /** A `sheetpane=` parameter's pane (`''` for none), sheet and ref — `undefined` when the parameter is not ours. */
48
+ function valueOf(param) {
49
+ if (!param.startsWith(`${LINK_KEY}=`))
50
+ return undefined;
51
+ const v = param.slice(LINK_KEY.length + 1), j = v.lastIndexOf('!');
52
+ const head = j < 0 ? v : v.slice(0, j), i = head.indexOf(':');
53
+ if (j < 0)
54
+ return i < 0 ? { pane: '', ref: dec(v) } : { pane: dec(v.slice(0, i)), ref: dec(v.slice(i + 1)) };
55
+ const sheet = dec(i < 0 ? head : head.slice(i + 1));
56
+ return { pane: i < 0 ? '' : dec(head.slice(0, i)), sheet, ref: dec(v.slice(j + 1)) };
57
+ }
58
+ /**
59
+ * The link for a pane in a URL fragment, as `Sheet!B4` text.
60
+ * @param hash - `location.hash`, with or without its `#`.
61
+ * @param pane - The element's `pane` (`''` when it has none).
62
+ * @returns The reference text (`'Q3 data'!B4` when the sheet needs quoting), or `undefined` when the fragment names nothing for this pane.
63
+ */
64
+ export function readLink(hash, pane) {
65
+ const at = partsOf(hash).params.map(valueOf).find((x) => x?.pane === pane);
66
+ if (!at)
67
+ return undefined;
68
+ if (at.sheet === undefined)
69
+ return at.ref;
70
+ return `${/^[\w.]+$/.test(at.sheet) ? at.sheet : `'${at.sheet.replace(/'/g, "''")}'`}!${at.ref}`;
71
+ }
72
+ /**
73
+ * A fragment with this pane's link set (or removed), every other part kept as it was: the link replaces the
74
+ * pane's old one where it stood; a new one goes after a hash router's path with `?` (`#/reports/12?sheetpane=…`),
75
+ * after anything else with `&`, or alone.
76
+ * @param hash - `location.hash`, with or without its `#`.
77
+ * @param pane - The element's `pane` (`''` when it has none).
78
+ * @param at - The sheet and the cell or range (`B4`, `B4:D8`) to link to; `undefined` removes the pane's link.
79
+ * @returns The new fragment, without its `#` (`''`: no fragment).
80
+ */
81
+ export function writeLink(hash, pane, at) {
82
+ const { path, params } = partsOf(hash);
83
+ const mine = at && `${LINK_KEY}=${pane ? `${enc(pane)}:` : ''}${enc(at.sheet)}!${at.ref}`;
84
+ const i = params.findIndex((x) => valueOf(x)?.pane === pane);
85
+ const kept = params.flatMap((x, k) => (valueOf(x)?.pane !== pane ? [x] : k === i && mine ? [mine] : []));
86
+ if (i < 0 && mine)
87
+ kept.push(mine);
88
+ return path === undefined ? kept.join('&') : `${path}${kept.length ? `?${kept.join('&')}` : ''}`;
89
+ }
90
+ //# sourceMappingURL=link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/excel/link.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/excel/styles.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,QAAQ,QAiCpB,CAAC;AAEF,eAAO,MAAM,SAAS,QAsKrB,CAAC"}
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/excel/styles.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,QAAQ,QAmCpB,CAAC;AAEF,eAAO,MAAM,SAAS,QAoMrB,CAAC"}
@@ -28,20 +28,30 @@ button,input,select,textarea{font:inherit;color:inherit}
28
28
  .chip-warn{background:var(--sp-warn-soft);color:var(--sp-warn)}
29
29
  .chip-info{background:var(--sp-accent-soft);color:var(--sp-accent-ink)}
30
30
  .chip-pass{background:var(--sp-pass-soft);color:var(--sp-pass)}
31
+ .chip-skip{background:var(--sp-sunken);color:var(--sp-ink-2)}
31
32
  .input{height:28px;border:1px solid var(--sp-line-strong);border-radius:var(--sp-r);padding:0 8px;background:var(--sp-surface);min-width:0;font-size:13px}
32
33
  .input:focus{outline:2px solid var(--sp-accent);outline-offset:-1px;border-color:var(--sp-accent)}
33
34
  textarea.input{height:auto;min-height:56px;padding:6px 8px;resize:vertical;width:100%;line-height:1.45}
34
35
  .num{font-variant-numeric:tabular-nums}
35
36
  .xs{font-size:12px}.faint{color:var(--sp-ink-3)}.muted{color:var(--sp-ink-2)}
36
37
  .g{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:var(--sp-r-sm);font-size:10px;font-weight:700;color:var(--sp-on-solid);flex:none}
37
- .g-error{background:var(--sp-fail)}.g-warning{background:var(--sp-warn)}.g-note{background:var(--sp-accent)}.g-pass{background:var(--sp-pass)}
38
+ .g-error{background:var(--sp-fail)}.g-warning{background:var(--sp-warn)}.g-note{background:var(--sp-accent)}.g-pass{background:var(--sp-pass)}.g-accepted{background:var(--sp-surface);color:var(--sp-ink-2);box-shadow:inset 0 0 0 1.5px var(--sp-ink-3)}
39
+ .acceptance{display:flex;flex-direction:column;gap:2px;font-size:13px;margin:0;overflow-wrap:anywhere}
38
40
  `;
39
41
  export const EXCEL_CSS = `${BASE_CSS}
40
42
  .sp{display:flex;flex-direction:column;height:100%;min-height:320px;background:var(--sp-surface);border:1px solid var(--sp-line);border-radius:var(--sp-r-lg);overflow:hidden}
41
43
  :host([display=popup]) .sp{border:0;border-radius:var(--sp-r-xl)}
42
44
  dialog{padding:0;border:0;border-radius:var(--sp-r-xl);width:min(1240px,calc(100vw - 48px));height:min(760px,calc(100vh - 48px));max-width:none;max-height:none;box-shadow:var(--sp-shadow-lg);background:var(--sp-surface);color:inherit;font:inherit}
43
45
  dialog::backdrop{background:rgba(22,23,26,.42)}
44
- .bar{display:flex;align-items:center;gap:6px;padding:8px 10px;border-bottom:1px solid var(--sp-line);flex-wrap:wrap}
46
+ .sp{container:sp/inline-size}
47
+ /* one toolbar row (design: Sheetpane board); as the element narrows it sheds, in order, the changes label (the Download badge keeps the count), find's width, the counts (the errors panel and tab counts keep them) and the file meta (kept in the name's tooltip); only below 860 px may it wrap */
48
+ .bar{display:flex;align-items:center;gap:6px;padding:8px 10px;border-bottom:1px solid var(--sp-line);flex-wrap:nowrap;white-space:nowrap}
49
+ @container sp (max-width: 1240px){.bar .changes{display:none}}
50
+ @container sp (max-width: 1140px){.find input{width:84px}}
51
+ @container sp (max-width: 1040px){.bar .counts{display:none}}
52
+ @container sp (max-width: 960px){.bar .meta{display:none}}
53
+ @container sp (max-width: 860px){.bar{flex-wrap:wrap}}
54
+ .dlmore svg{width:12px;height:12px}
45
55
  .bar .ico{width:18px;height:18px;color:var(--sp-ink-3);flex:none}
46
56
  .fname{font-weight:600;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px;min-width:40px;flex:0 1 auto}
47
57
  .counts{display:inline-flex;gap:4px}
@@ -51,6 +61,7 @@ dialog::backdrop{background:rgba(22,23,26,.42)}
51
61
  .find input{padding-left:28px;width:112px}
52
62
  .zoom{width:70px;padding:0 2px}
53
63
  .find .cnt{font-size:11px;color:var(--sp-ink-3);margin-left:6px;min-width:44px}
64
+ .find .cnt:empty{display:none}
54
65
  .input.cell[aria-invalid]{outline:2px solid var(--sp-fail);outline-offset:-1px}
55
66
  .ptext{display:inline-flex;align-items:center;height:24px;padding:0 8px;border:1px dashed var(--sp-line-strong);border-radius:var(--sp-r-sm);color:var(--sp-ink-2);font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:40ch;font-variant-numeric:tabular-nums}
56
67
  .fx{display:flex;align-items:center;gap:8px;padding:6px 10px;border-bottom:1px solid var(--sp-line);min-height:41px;font-size:13px;flex-wrap:wrap}
@@ -58,13 +69,24 @@ dialog::backdrop{background:rgba(22,23,26,.42)}
58
69
  .fx .val{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
59
70
  .fx input.cell{flex:1;max-width:460px;border-color:var(--sp-accent)}
60
71
  .tag{font-size:10px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--sp-ink-3);border:1px solid var(--sp-line-strong);border-radius:4px;padding:3px 5px}
61
- .frow{display:flex;align-items:center;gap:4px;padding:4px 10px;border-bottom:1px solid var(--sp-line);flex-wrap:wrap;background:var(--sp-ground)}
72
+ .frow{display:flex;align-items:center;gap:4px;padding:4px 10px;border-bottom:1px solid var(--sp-line);flex-wrap:nowrap;background:var(--sp-ground);position:relative;z-index:6}
73
+ /* one row: groups that do not fit move into More ▾ from the right (W-14); Number format and Text never move */
74
+ .fgrp{display:inline-flex;align-items:center;gap:4px;flex:none}
75
+ .fmore{position:relative;display:inline-flex;margin-left:auto;flex:none}
76
+ .fmore[hidden]{display:none}
77
+ .fmore-btn svg{width:12px;height:12px}
78
+ .fmenu{position:absolute;top:calc(100% + 4px);right:0;z-index:9;display:flex;flex-direction:column;gap:6px;padding:8px;min-width:200px}
79
+ .fmenu[hidden]{display:none}
80
+ .fmenu .fgrp{flex-wrap:wrap}
81
+ .fmenu .fgrp+.fgrp{border-top:1px solid var(--sp-line);padding-top:6px}
82
+ .fmenu .sep{display:none}
62
83
  .frow .sep{width:1px;height:20px;background:var(--sp-line-strong);margin:0 4px}
63
84
  .frow button[aria-pressed=true]{background:var(--sp-accent-soft);border-color:var(--sp-accent)}
64
85
  .body{flex:1;min-height:0;display:flex;position:relative}
65
86
  .scroller{flex:1;min-width:0;overflow:auto;position:relative;background:var(--sp-cell)}
66
87
  .grid{outline:none}
67
- .scroller:has(.grid:focus-visible){box-shadow:inset 0 0 0 2px var(--sp-accent)}
88
+ /* the grid's focus ring: keyboard only (a click's focus is shown by the active cell), drawn over the cells, not under them */
89
+ .sp[data-kbd] .body:has(.grid:focus)::after{content:"";position:absolute;inset:0;box-shadow:inset 0 0 0 2px var(--sp-accent);pointer-events:none;z-index:8}
68
90
  .sheet{position:relative}
69
91
  .hrow{position:sticky;top:0;z-index:5;display:flex;background:var(--sp-head)}
70
92
  .row{position:absolute;left:0;display:flex}
@@ -111,14 +133,21 @@ dialog::backdrop{background:rgba(22,23,26,.42)}
111
133
  .c.m-warning{box-shadow:inset 0 0 0 1.5px var(--sp-warn)}.c.m-warning::before{background:var(--sp-warn-soft)}
112
134
  .c.m-note{box-shadow:inset 0 0 0 1.5px var(--sp-accent)}.c.m-note::before{background:var(--sp-accent-soft)}
113
135
  .c.m-pass{box-shadow:inset 0 0 0 1.5px var(--sp-pass)}
136
+ .c.m-accepted{box-shadow:inset 0 0 0 1.5px var(--sp-ink-3)}
137
+ .c>.rmk{position:absolute;left:3px;bottom:2px;z-index:2;font-size:.69em;font-weight:700;line-height:1;pointer-events:none}
138
+ .rmk.pass{color:var(--sp-pass)}.rmk.skipped{color:var(--sp-skip)}
114
139
  .c.stale>.v{color:var(--sp-ink-3);font-style:italic}
115
140
  .c.stale>.v::before{content:"≈ ";color:var(--sp-warn);font-style:normal}
116
141
  .c.derived>.v{color:var(--sp-accent-ink)}
117
142
  .c .mk{position:absolute;z-index:2;right:2px;top:50%;transform:translateY(-50%);border:0;background:transparent;padding:0 2px;cursor:pointer;color:var(--sp-ink-3)}
118
143
  .overlay{position:absolute;inset:0;pointer-events:none;z-index:4}
119
144
  .overlay>*{pointer-events:auto}
145
+ .overlay>.hl,.hlbox{pointer-events:none}
146
+ .hlbox{position:absolute;box-sizing:border-box;border:2px solid var(--sp-accent);border-radius:var(--sp-r-sm);box-shadow:0 0 0 2px var(--sp-accent-soft)}
147
+ .hlbox.pass{border-color:var(--sp-pass);box-shadow:0 0 0 2px var(--sp-pass-soft)}
148
+ .hlbox.fail{border-color:var(--sp-fail);box-shadow:0 0 0 2px var(--sp-fail-soft)}
120
149
  .pin{position:absolute;min-width:18px;height:18px;padding:0 4px;border-radius:9px;border:0;font-size:10px;font-weight:700;line-height:18px;color:var(--sp-on-solid);text-align:center;box-shadow:0 0 0 2px var(--sp-cell),0 1px 4px rgba(22,23,26,.3);cursor:pointer;font-variant-numeric:tabular-nums}
121
- .pin.error{background:var(--sp-fail)}.pin.warning{background:var(--sp-warn)}.pin.note{background:var(--sp-accent)}.pin.resolved{background:var(--sp-pass)}
150
+ .pin.error{background:var(--sp-fail)}.pin.warning{background:var(--sp-warn)}.pin.note{background:var(--sp-accent)}.pin.resolved{background:var(--sp-pass)}.pin.accepted{background:var(--sp-surface);color:var(--sp-ink-2);box-shadow:0 0 0 2px var(--sp-cell),inset 0 0 0 1.5px var(--sp-ink-3)}
122
151
  .pin.on{box-shadow:0 0 0 2px var(--sp-cell),0 0 0 4px var(--sp-ink)}
123
152
  .pin.square{border-radius:3px;min-width:16px;height:16px;line-height:16px;padding:0 2px}
124
153
  .pin.pending{background:var(--sp-cell);color:var(--sp-accent);box-shadow:0 0 0 1.5px var(--sp-accent)}
@@ -138,6 +167,9 @@ dialog::backdrop{background:rgba(22,23,26,.42)}
138
167
  /* plugin buttons stay in the bar while it is wide, and fold into ⋯ before Flag issue moves */
139
168
  .moremenu .fold{display:none}
140
169
  @container (max-width: 720px){.dock .plug{display:none}.moremenu .fold{display:flex}}
170
+ /* …and also whenever they would squeeze the value field below 200 px (measured: fitDock) */
171
+ .fx.folded .dock .plug{display:none}
172
+ .fx.folded .moremenu .fold{display:flex}
141
173
  .warn-t{color:var(--sp-warn)}
142
174
  .export .badge-n{min-width:18px;height:18px;padding:0 5px;border-radius:9px;background:var(--sp-sunken);color:var(--sp-ink);font-size:11px;font-weight:700;line-height:18px;text-align:center}
143
175
  .split{position:relative;display:inline-flex}
@@ -1 +1 @@
1
- {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/excel/styles.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,0EAA0E;AAC1E,uEAAuE;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCpC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsKnC,CAAC"}
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/excel/styles.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,0EAA0E;AAC1E,uEAAuE;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCpC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoMnC,CAAC"}
@@ -3,34 +3,38 @@ import type { ChangeKind, Mode, SheetpaneError, SheetpaneErrors, SheetpaneExcel,
3
3
 
4
4
  /** The events `<sheetpane-excel>` dispatches, by name; each bubbles and is composed. */
5
5
  export interface SheetpaneExcelEventMap {
6
- /** `{ status: 'ready', name, kind, sheets, readMs }` when a file is read, or the refusal `{ status: 'error', code, spCode, message, name, detail? }`. */
7
- 'sheetpane-load': CustomEvent<{ status: 'ready'; name: string; kind: 'xlsx' | 'csv'; sheets: string[]; readMs: number } | { status: 'error'; code: string; spCode: SpCode; message: string; name: string; detail?: string }>;
8
- /** `{ sheet, ref, kind, was, now }` for each change, undo and redo included. */
9
- 'sheetpane-change': CustomEvent<{ sheet: string; ref: string; kind: ChangeKind; was: unknown; now: unknown }>;
10
- /** `{ errors, plugins }` when the pane's errors change. */
11
- 'sheetpane-errors': CustomEvent<{ errors: SheetpaneError[]; plugins: string[] }>;
6
+ /** `{ status: 'ready', name, kind, sheets, readMs, sha256 }` when a file is read (`sha256`: the file's SHA-256, W-65), or the refusal `{ status: 'error', code, spCode, message, name, detail? }`. */
7
+ 'sheetpane-load': CustomEvent<{ status: 'ready'; name: string; kind: 'xlsx' | 'csv'; sheets: string[]; readMs: number; sha256: string | undefined } | { status: 'error'; code: string; spCode: SpCode; message: string; name: string; detail?: string }>;
8
+ /** `{ sheet, ref, kind, was, now, op?, at?, count? }` for each change, undo and redo included; rows or columns inserted or deleted (W-52) are one event, `kind: 'structure'`, with `op`, `at` (0-based) and `count`. */
9
+ 'sheetpane-change': CustomEvent<{ sheet: string; ref: string; kind: ChangeKind; was: unknown; now: unknown; op?: 'insertRows' | 'deleteRows' | 'insertCols' | 'deleteCols'; at?: number; count?: number }>;
10
+ /** `{ v, errors, plugins, layers, changed }` when the pane's errors change — the envelope to save a review (`v: 2`, W-51); `changed` names the layers whose errors changed. */
11
+ 'sheetpane-errors': CustomEvent<{ v: 2; errors: SheetpaneError[]; plugins: string[]; layers: string[]; changed: string[] }>;
12
+ /** `{ visible, layers }` when the visible review layers change (W-51). */
13
+ 'sheetpane-layers': CustomEvent<{ visible: string[]; layers: string[] }>;
12
14
  /** `{ sheet, ref, range, column, value }` when the selection settles — `range` (`B3:D8`) when more than one cell is selected; a drag fires once, on release. */
13
15
  'sheetpane-select': CustomEvent<{ sheet: string; ref: string; range: string | undefined; column: { index: number; letter: string; header: string }; value: unknown }>;
14
16
  /** `{ sheet, axis, indexes, hidden, via }` when rows, columns or a sheet are hidden, unhidden or shown for viewing (`via: 'reveal'`) (W-49). */
15
17
  'sheetpane-visibility': CustomEvent<{ sheet: string; axis: 'row' | 'col' | 'sheet'; indexes: number[]; hidden: boolean; via: 'menu' | 'key' | 'marker' | 'reveal' }>;
16
18
  /** `{ sheet, axis, indexes, px, via }` when a column width or row height is set by a drag, a fit, the header menu or a reset — on release, never during a drag (W-47). */
17
19
  'sheetpane-resize': CustomEvent<{ sheet: string; axis: 'col' | 'row'; indexes: number[]; px: number | number[]; via: 'drag' | 'fit' | 'menu' | 'reset' }>;
20
+ /** `{ sheet, ref, column }` when a mouse or pen pointer moves onto another cell (a merge's top-left), at most once per frame, or `null` when it leaves the cells; never for a finger (W-56). */
21
+ 'sheetpane-hover': CustomEvent<{ sheet: string; ref: string; column: { index: number; letter: string; header: string } } | null>;
18
22
  /** `{ sheet }` when the selection moves to another sheet. */
19
23
  'sheetpane-sheet': CustomEvent<{ sheet: string }>;
20
24
  /** `{ mode }` when the pane switches between View and Edit. */
21
25
  'sheetpane-mode': CustomEvent<{ mode: Mode }>;
22
26
  /** `{ reason, canUndo, canRedo }` on undo, redo, or the stack cleared by `setErrors()`. */
23
27
  'sheetpane-history': CustomEvent<{ reason: 'undo' | 'redo' | 'cleared'; canUndo: boolean; canRedo: boolean }>;
24
- /** `{ sheet, ref, column, value }` before a cell edit starts; cancellable — the cell stays read-only. */
25
- 'sheetpane-editstart': CustomEvent<{ sheet: string; ref: string; column: { index: number; letter: string; header: string }; value: unknown }>;
28
+ /** `{ sheet, ref, column, value, richText?: true }` before a cell edit starts (`richText: true` on a rich-text cell, whose edit saves plain text — W-53); cancellable — the cell stays read-only. */
29
+ 'sheetpane-editstart': CustomEvent<{ sheet: string; ref: string; column: { index: number; letter: string; header: string }; value: unknown; richText?: true }>;
26
30
  /** `{ sheet, ref, column, draft, was }` as the cell-bar draft is typed. */
27
31
  'sheetpane-input': CustomEvent<{ sheet: string; ref: string; column: { index: number; letter: string; header: string }; draft: string; was: unknown }>;
28
32
  /** `{ sheet, ref, column, was, now }` before a value is stored; cancellable — the value is refused. */
29
33
  'sheetpane-beforechange': CustomEvent<{ sheet: string; ref: string; column: { index: number; letter: string; header: string }; was: unknown; now: unknown }>;
30
- /** `{ sheet, ref }` when Esc restores a draft, or `{ sheet, ref, reason: 'blocked', code: 'SP-6003', message }` when a `block` rule refuses it. */
31
- 'sheetpane-editcancel': CustomEvent<{ sheet: string; ref: string } | { sheet: string; ref: string; reason: 'blocked'; code: 'SP-6003'; message: string }>;
32
- /** `{ blob, kind, name, guarded, format, converted, original? }` on `export()` and Download; cancellable — the Download control then saves nothing. */
33
- 'sheetpane-export': CustomEvent<{ blob: Blob; kind: 'xlsx' | 'csv'; name: string; guarded: string[] | false; format: 'xlsx' | 'csv'; converted: boolean; original?: boolean }>;
34
+ /** `{ sheet, ref }` when Esc restores a draft, `{ sheet, ref, reason: 'blocked', code: 'SP-6003', message }` when a `block` rule refuses it, or `{ sheet, ref, reason: 'locked', code: 'SP-3026', message }` when the cell is locked on a protected sheet (W-62). */
35
+ 'sheetpane-editcancel': CustomEvent<{ sheet: string; ref: string } | { sheet: string; ref: string; reason: 'blocked'; code: 'SP-6003'; message: string } | { sheet: string; ref: string; reason: 'locked'; code: 'SP-3026'; message: string }>;
36
+ /** `{ blob, kind, name, guarded, format, converted, sha256, original? }` on `export()` and Download (`sha256`: the blob's SHA-256, W-65); cancellable — the Download control then saves nothing. */
37
+ 'sheetpane-export': CustomEvent<{ blob: Blob; kind: 'xlsx' | 'csv'; name: string; guarded: string[] | false; format: 'xlsx' | 'csv'; converted: boolean; sha256: string | undefined; original?: boolean }>;
34
38
  /** `{}` when the pop-up closes. */
35
39
  'sheetpane-close': CustomEvent<Record<string, never>>;
36
40
  }
@@ -61,6 +65,16 @@ export interface SheetpaneExcelAttributes {
61
65
  'rules-src'?: string | undefined;
62
66
  /** `on` (the default) or `off`: no Flag issue anywhere. */
63
67
  flagging?: 'on' | 'off' | undefined;
68
+ /** The cell or range selected once a file is read, scrolled into view: `B4`, `Data!B4`, `'Q3 data'!B4:D8`; setting it later selects it then. One that names no cell is warned (SP-3019) and the sheet opens at A1. React, Vue and Solid keep `ref` for their own refs — set it with `setAttribute`. */
69
+ ref?: string | undefined;
70
+ /** `none` (the default) or `hash`: the selection is kept in the URL fragment as `#sheetpane=<pane>:<Sheet>!<ref>`, read when a file is read and on back and forward, and *Copy link* joins the cell menu. The rest of the fragment is the host's and is kept as it was. */
71
+ link?: 'none' | 'hash' | undefined;
72
+ /** `summary` (the default), `marks` or `off`: how `pass` and `skipped` results show, pane-wide (W-50). */
73
+ results?: 'summary' | 'marks' | 'off' | undefined;
74
+ /** Space-separated review layers to show (W-51); none shows every layer. Shared by the pane's elements. */
75
+ layers?: string | undefined;
76
+ /** `honour` (the default) or `ignore`: whether a protected sheet's locked cells refuse edits and a protected structure keeps its sheets, pane-wide (W-62). `ignore` is the host's decision; the file is unchanged. */
77
+ protection?: 'honour' | 'ignore' | undefined;
64
78
  }
65
79
 
66
80
  /** The properties a framework may set on `<sheetpane-excel>`, typed as the element declares them. */
@@ -71,8 +85,12 @@ export interface SheetpaneExcelProperties {
71
85
  errors?: SheetpaneExcel['errors'] | undefined;
72
86
  /** The types offered in the Flag issue form; an empty list falls back to `DEFAULT_ERROR_TYPES`. */
73
87
  errorTypes?: SheetpaneExcel['errorTypes'] | undefined;
88
+ /** The host's extra detail for an error (W-68): called with a copy of the error when its card opens in the sheet, and drawn after the message in a `part="detail"` region. A string is text, never HTML; a Node is the host's own. Called again only when the error changes (its `meta` included) or this is replaced; a throw is logged as SP-3017. Set it on each element that should show it — `<sheetpane-errors>` has its own. */
89
+ renderDetail?: SheetpaneExcel['renderDetail'] | undefined;
74
90
  /** Loads a file, like `load()`; `null` does nothing. */
75
91
  file?: SheetpaneExcel['file'] | undefined;
92
+ /** The review layers shown (W-51) — the pane's, shared with `<sheetpane-errors>`: every layer until the `layers` attribute or the switch names some. Setting it sets the attribute; `null` or `[]` shows every layer. */
93
+ layers?: SheetpaneExcel['layers'] | undefined;
76
94
  /** The pane's mode, `view` or `edit`; setting it sets the `mode` attribute. */
77
95
  mode?: SheetpaneExcel['mode'] | undefined;
78
96
  /** `light` (the default), `dark`, or `auto` (follows `prefers-color-scheme`) — colour only; the file's own colours never change (W-29). */
@@ -81,6 +99,10 @@ export interface SheetpaneExcelProperties {
81
99
  rules?: SheetpaneExcel['rules'] | undefined;
82
100
  /** `flagging="off"`: no Flag issue anywhere, no composer, no callout card — the errors panel is the one place errors are read. */
83
101
  flagging?: SheetpaneExcel['flagging'] | undefined;
102
+ /** The pane's results level (W-50): `summary` (the default), `marks` or `off`; setting it sets the `results` attribute. */
103
+ results?: SheetpaneExcel['results'] | undefined;
104
+ /** The pane's protection mode (W-62): `honour` (the default) keeps the file's protection; `ignore` is the host's decision. Setting it sets the `protection` attribute. */
105
+ protection?: SheetpaneExcel['protection'] | undefined;
84
106
  /** Rules by column title, as plain JSON (`required`, `type`, `min`, `max`, `minLength`, `maxLength`, `pattern`, `oneOf`, `unique`, `message`, `severity`, `onInvalid`). */
85
107
  columns?: SheetpaneExcel['columns'] | undefined;
86
108
  /** `validate(ctx, signal)`, sync or async: `null`, or `{ severity, message, expected? }`. */
@@ -91,19 +113,25 @@ export interface SheetpaneExcelProperties {
91
113
  sizes?: SheetpaneExcel['sizes'] | undefined;
92
114
  /** The `src` attribute; `null`, `undefined` or `''` removes it. */
93
115
  src?: SheetpaneExcel['src'] | undefined;
116
+ /** The `ref` attribute: the cell or range selected once a file is read (W-66); `null`, `undefined` or `''` removes it. */
117
+ ref?: SheetpaneExcel['ref'] | undefined;
118
+ /** `none` (the default) or `hash`: the selection kept in the URL fragment, and *Copy link* in the cell menu (W-66). */
119
+ link?: SheetpaneExcel['link'] | undefined;
94
120
  }
95
121
 
96
122
  /** The events `<sheetpane-errors>` dispatches, by name; each bubbles and is composed. */
97
123
  export interface SheetpaneErrorsEventMap {
98
- /** `{ errors, plugins }` when the pane's errors change — the envelope to save a review. */
99
- 'sheetpane-errors': CustomEvent<{ errors: SheetpaneError[]; plugins: string[] }>;
124
+ /** `{ v, errors, plugins, layers, changed }` when the pane's errors change — the envelope to save a review (`v: 2`, W-51); `changed` names the layers whose errors changed. */
125
+ 'sheetpane-errors': CustomEvent<{ v: 2; errors: SheetpaneError[]; plugins: string[]; layers: string[]; changed: string[] }>;
126
+ /** `{ visible, layers }` when the visible review layers change — the switch or the `layers` attribute (W-51). */
127
+ 'sheetpane-layers': CustomEvent<{ visible: string[]; layers: string[] }>;
100
128
  /** `{ sheet, ref, kind, was, now }` when a cell changes from here ("Also change the cell", undo, redo). */
101
129
  'sheetpane-change': CustomEvent<{ sheet: string; ref: string; kind: ChangeKind; was: unknown; now: unknown }>;
102
130
  /** `{ sheet, ref }` when picking a row selects its cell. */
103
131
  'sheetpane-select': CustomEvent<{ sheet: string; ref: string }>;
104
132
  /** `{ reason, canUndo, canRedo }` on undo, redo, or the stack cleared by `setErrors()`. */
105
133
  'sheetpane-history': CustomEvent<{ reason: 'undo' | 'redo' | 'cleared'; canUndo: boolean; canRedo: boolean }>;
106
- /** `{ error }` on Show in sheet, so the host can switch tab or open the pop-up. */
134
+ /** `{ error }` on Show in sheet, so the host can switch tab or open the pop-up — for a whole-sheet error too (its tab is opened); never for a workbook-level one (W-55); for a result group's Show ▸, its first entry (W-50). */
107
135
  'sheetpane-reveal': CustomEvent<{ error: SheetpaneError }>;
108
136
  }
109
137
 
@@ -111,14 +139,18 @@ export interface SheetpaneErrorsEventMap {
111
139
  export interface SheetpaneErrorsAttributes {
112
140
  /** The pane id shared with the sheet; none gives the element its own store. */
113
141
  pane?: string | undefined;
114
- /** Hides the form, Resolve, Delete, Undo and Redo (a sign-off screen). */
142
+ /** Hides the form, Resolve, Accept…, Delete, Undo and Redo (a sign-off screen). */
115
143
  readonly?: boolean | undefined;
116
- /** Written into the errors this element's user adds. */
144
+ /** Written into the errors this element's user adds, and as who accepted one (W-69). */
117
145
  author?: string | undefined;
118
146
  /** Space-separated registered plugin ids; fixed per pane. */
119
147
  plugins?: string | undefined;
120
148
  /** `light` (the default), `dark` or `auto`. */
121
149
  theme?: 'light' | 'dark' | 'auto' | undefined;
150
+ /** `summary` (the default), `marks` or `off`: how `pass` and `skipped` results show, pane-wide (W-50). */
151
+ results?: 'summary' | 'marks' | 'off' | undefined;
152
+ /** Space-separated review layers to show (W-51); none shows every layer. Shared by the pane's elements; with two or more layers the header shows a switch. */
153
+ layers?: string | undefined;
122
154
  }
123
155
 
124
156
  /** The properties a framework may set on `<sheetpane-errors>`, typed as the element declares them. */
@@ -133,4 +165,12 @@ export interface SheetpaneErrorsProperties {
133
165
  readOnly?: SheetpaneErrors['readOnly'] | undefined;
134
166
  /** `light` (the default), `dark` or `auto` — the same tokens as the sheet (W-29). */
135
167
  theme?: SheetpaneErrors['theme'] | undefined;
168
+ /** The host's extra detail for an error (W-68): called with a copy of the error when its row is opened, and drawn after the message in a `part="detail"` region. A string is text, never HTML; a Node is the host's own. Called again only when the error changes (its `meta` included) or this is replaced; a throw is logged as SP-3017. Set it on each element that should show it — the sheet's error card has its own. */
169
+ renderDetail?: SheetpaneErrors['renderDetail'] | undefined;
170
+ /** The pane's results level (W-50): `summary` (the default), `marks` or `off`; setting it sets the `results` attribute. */
171
+ results?: SheetpaneErrors['results'] | undefined;
172
+ /** The review layers shown (W-51) — the pane's, shared with `<sheetpane-excel>`: every layer until the `layers` attribute or the switch names some. Setting it sets the attribute; `null` or `[]` shows every layer. */
173
+ layers?: SheetpaneErrors['layers'] | undefined;
174
+ /** What the switch and the rows call each layer (W-51), e.g. `{ pdf: 'PDF check' }`; a layer not named here shows its name (`review` as *Review*). */
175
+ layerNames?: SheetpaneErrors['layerNames'] | undefined;
136
176
  }
@@ -7,34 +7,38 @@ import type { SheetpaneErrorsAttributes, SheetpaneErrorsEventMap, SheetpaneError
7
7
  export type { SheetpaneErrorsAttributes, SheetpaneErrorsEventMap, SheetpaneErrorsProperties, SheetpaneExcelAttributes, SheetpaneExcelEventMap, SheetpaneExcelProperties } from './elements.js';
8
8
 
9
9
  /** `<sheetpane-excel>` in React 19 JSX: attributes, properties and `onsheetpane-…` event props (React 19 sets properties and listens to custom events). */
10
- export type SheetpaneExcelReactProps = SheetpaneExcelAttributes & SheetpaneExcelProperties & {
11
- /** `{ status: 'ready', name, kind, sheets, readMs }` when a file is read, or the refusal `{ status: 'error', code, spCode, message, name, detail? }`. */
10
+ export type SheetpaneExcelReactProps = Omit<SheetpaneExcelAttributes, 'ref'> & Omit<SheetpaneExcelProperties, 'ref'> & {
11
+ /** `{ status: 'ready', name, kind, sheets, readMs, sha256 }` when a file is read (`sha256`: the file's SHA-256, W-65), or the refusal `{ status: 'error', code, spCode, message, name, detail? }`. */
12
12
  'onsheetpane-load'?: ((event: SheetpaneExcelEventMap['sheetpane-load']) => void) | undefined;
13
- /** `{ sheet, ref, kind, was, now }` for each change, undo and redo included. */
13
+ /** `{ sheet, ref, kind, was, now, op?, at?, count? }` for each change, undo and redo included; rows or columns inserted or deleted (W-52) are one event, `kind: 'structure'`, with `op`, `at` (0-based) and `count`. */
14
14
  'onsheetpane-change'?: ((event: SheetpaneExcelEventMap['sheetpane-change']) => void) | undefined;
15
- /** `{ errors, plugins }` when the pane's errors change. */
15
+ /** `{ v, errors, plugins, layers, changed }` when the pane's errors change — the envelope to save a review (`v: 2`, W-51); `changed` names the layers whose errors changed. */
16
16
  'onsheetpane-errors'?: ((event: SheetpaneExcelEventMap['sheetpane-errors']) => void) | undefined;
17
+ /** `{ visible, layers }` when the visible review layers change (W-51). */
18
+ 'onsheetpane-layers'?: ((event: SheetpaneExcelEventMap['sheetpane-layers']) => void) | undefined;
17
19
  /** `{ sheet, ref, range, column, value }` when the selection settles — `range` (`B3:D8`) when more than one cell is selected; a drag fires once, on release. */
18
20
  'onsheetpane-select'?: ((event: SheetpaneExcelEventMap['sheetpane-select']) => void) | undefined;
19
21
  /** `{ sheet, axis, indexes, hidden, via }` when rows, columns or a sheet are hidden, unhidden or shown for viewing (`via: 'reveal'`) (W-49). */
20
22
  'onsheetpane-visibility'?: ((event: SheetpaneExcelEventMap['sheetpane-visibility']) => void) | undefined;
21
23
  /** `{ sheet, axis, indexes, px, via }` when a column width or row height is set by a drag, a fit, the header menu or a reset — on release, never during a drag (W-47). */
22
24
  'onsheetpane-resize'?: ((event: SheetpaneExcelEventMap['sheetpane-resize']) => void) | undefined;
25
+ /** `{ sheet, ref, column }` when a mouse or pen pointer moves onto another cell (a merge's top-left), at most once per frame, or `null` when it leaves the cells; never for a finger (W-56). */
26
+ 'onsheetpane-hover'?: ((event: SheetpaneExcelEventMap['sheetpane-hover']) => void) | undefined;
23
27
  /** `{ sheet }` when the selection moves to another sheet. */
24
28
  'onsheetpane-sheet'?: ((event: SheetpaneExcelEventMap['sheetpane-sheet']) => void) | undefined;
25
29
  /** `{ mode }` when the pane switches between View and Edit. */
26
30
  'onsheetpane-mode'?: ((event: SheetpaneExcelEventMap['sheetpane-mode']) => void) | undefined;
27
31
  /** `{ reason, canUndo, canRedo }` on undo, redo, or the stack cleared by `setErrors()`. */
28
32
  'onsheetpane-history'?: ((event: SheetpaneExcelEventMap['sheetpane-history']) => void) | undefined;
29
- /** `{ sheet, ref, column, value }` before a cell edit starts; cancellable — the cell stays read-only. */
33
+ /** `{ sheet, ref, column, value, richText?: true }` before a cell edit starts (`richText: true` on a rich-text cell, whose edit saves plain text — W-53); cancellable — the cell stays read-only. */
30
34
  'onsheetpane-editstart'?: ((event: SheetpaneExcelEventMap['sheetpane-editstart']) => void) | undefined;
31
35
  /** `{ sheet, ref, column, draft, was }` as the cell-bar draft is typed. */
32
36
  'onsheetpane-input'?: ((event: SheetpaneExcelEventMap['sheetpane-input']) => void) | undefined;
33
37
  /** `{ sheet, ref, column, was, now }` before a value is stored; cancellable — the value is refused. */
34
38
  'onsheetpane-beforechange'?: ((event: SheetpaneExcelEventMap['sheetpane-beforechange']) => void) | undefined;
35
- /** `{ sheet, ref }` when Esc restores a draft, or `{ sheet, ref, reason: 'blocked', code: 'SP-6003', message }` when a `block` rule refuses it. */
39
+ /** `{ sheet, ref }` when Esc restores a draft, `{ sheet, ref, reason: 'blocked', code: 'SP-6003', message }` when a `block` rule refuses it, or `{ sheet, ref, reason: 'locked', code: 'SP-3026', message }` when the cell is locked on a protected sheet (W-62). */
36
40
  'onsheetpane-editcancel'?: ((event: SheetpaneExcelEventMap['sheetpane-editcancel']) => void) | undefined;
37
- /** `{ blob, kind, name, guarded, format, converted, original? }` on `export()` and Download; cancellable — the Download control then saves nothing. */
41
+ /** `{ blob, kind, name, guarded, format, converted, sha256, original? }` on `export()` and Download (`sha256`: the blob's SHA-256, W-65); cancellable — the Download control then saves nothing. */
38
42
  'onsheetpane-export'?: ((event: SheetpaneExcelEventMap['sheetpane-export']) => void) | undefined;
39
43
  /** `{}` when the pop-up closes. */
40
44
  'onsheetpane-close'?: ((event: SheetpaneExcelEventMap['sheetpane-close']) => void) | undefined;
@@ -42,15 +46,17 @@ export type SheetpaneExcelReactProps = SheetpaneExcelAttributes & SheetpaneExcel
42
46
 
43
47
  /** `<sheetpane-errors>` in React 19 JSX: attributes, properties and `onsheetpane-…` event props (React 19 sets properties and listens to custom events). */
44
48
  export type SheetpaneErrorsReactProps = SheetpaneErrorsAttributes & SheetpaneErrorsProperties & {
45
- /** `{ errors, plugins }` when the pane's errors change — the envelope to save a review. */
49
+ /** `{ v, errors, plugins, layers, changed }` when the pane's errors change — the envelope to save a review (`v: 2`, W-51); `changed` names the layers whose errors changed. */
46
50
  'onsheetpane-errors'?: ((event: SheetpaneErrorsEventMap['sheetpane-errors']) => void) | undefined;
51
+ /** `{ visible, layers }` when the visible review layers change — the switch or the `layers` attribute (W-51). */
52
+ 'onsheetpane-layers'?: ((event: SheetpaneErrorsEventMap['sheetpane-layers']) => void) | undefined;
47
53
  /** `{ sheet, ref, kind, was, now }` when a cell changes from here ("Also change the cell", undo, redo). */
48
54
  'onsheetpane-change'?: ((event: SheetpaneErrorsEventMap['sheetpane-change']) => void) | undefined;
49
55
  /** `{ sheet, ref }` when picking a row selects its cell. */
50
56
  'onsheetpane-select'?: ((event: SheetpaneErrorsEventMap['sheetpane-select']) => void) | undefined;
51
57
  /** `{ reason, canUndo, canRedo }` on undo, redo, or the stack cleared by `setErrors()`. */
52
58
  'onsheetpane-history'?: ((event: SheetpaneErrorsEventMap['sheetpane-history']) => void) | undefined;
53
- /** `{ error }` on Show in sheet, so the host can switch tab or open the pop-up. */
59
+ /** `{ error }` on Show in sheet, so the host can switch tab or open the pop-up — for a whole-sheet error too (its tab is opened); never for a workbook-level one (W-55); for a result group's Show ▸, its first entry (W-50). */
54
60
  'onsheetpane-reveal'?: ((event: SheetpaneErrorsEventMap['sheetpane-reveal']) => void) | undefined;
55
61
  };
56
62