@reportwright/viewer 0.12.1 → 0.13.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 (81) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +16 -1
  3. package/THIRD-PARTY-NOTICES.md +52 -0
  4. package/dist/{chunk-S2IUUI6N.js → chunk-BF7GCWZY.js} +67 -49
  5. package/dist/chunk-BF7GCWZY.js.map +6 -0
  6. package/dist/chunk-BR5K6SBL.js +324 -0
  7. package/dist/chunk-BR5K6SBL.js.map +6 -0
  8. package/dist/{peer/chunk-BQFI3DHK.js → chunk-CNDUJ7IV.js} +289 -25
  9. package/dist/chunk-CNDUJ7IV.js.map +6 -0
  10. package/dist/{chunk-VNOWPSE6.js → chunk-EK5CJY22.js} +1223 -899
  11. package/dist/chunk-EK5CJY22.js.map +6 -0
  12. package/dist/{chunk-2BPBQMH2.js → chunk-F5EPQTPF.js} +3 -3
  13. package/dist/chunk-FEM2QVOO.js +18 -0
  14. package/dist/{chunk-3D2KFKG2.js → chunk-IFYCJZNS.js} +8 -6
  15. package/dist/chunk-IFYCJZNS.js.map +6 -0
  16. package/dist/{chunk-NR2G4TMG.js → chunk-L6YEIVVD.js} +43 -22
  17. package/dist/chunk-L6YEIVVD.js.map +6 -0
  18. package/dist/{chunk-DPVJEFKP.js → chunk-PQNM6ET7.js} +4 -4
  19. package/dist/{chunk-DPVJEFKP.js.map → chunk-PQNM6ET7.js.map} +1 -1
  20. package/dist/{chunk-Z7MKH66Z.js → chunk-QFLVVM3H.js} +225 -11
  21. package/dist/chunk-QFLVVM3H.js.map +6 -0
  22. package/dist/{chunk-PGP3QA6L.js → chunk-TZXEEVKE.js} +1301 -70
  23. package/dist/chunk-TZXEEVKE.js.map +6 -0
  24. package/dist/{chunk-Q6MMPKQA.js → chunk-UHHURTSV.js} +11 -10
  25. package/dist/chunk-UHHURTSV.js.map +6 -0
  26. package/dist/{chunk-M6AYND5G.js → chunk-UJL7C2AS.js} +16 -7
  27. package/dist/chunk-UJL7C2AS.js.map +6 -0
  28. package/dist/chunk-YIX3OJXU.js +34 -0
  29. package/dist/designer.d.ts +11 -3
  30. package/dist/designer.js +587 -386
  31. package/dist/designer.js.map +3 -3
  32. package/dist/engine.worker.js +16729 -18
  33. package/dist/engine.worker.js.map +3 -3
  34. package/dist/peer/{chunk-6I2EAAVN.js → chunk-2CD5COHN.js} +43 -22
  35. package/dist/peer/chunk-2CD5COHN.js.map +6 -0
  36. package/dist/peer/{chunk-BMAXIBP2.js → chunk-3CBV5SAI.js} +4 -4
  37. package/dist/peer/{chunk-BMAXIBP2.js.map → chunk-3CBV5SAI.js.map} +1 -1
  38. package/dist/peer/{chunk-WSNRD2AQ.js → chunk-45GVDKP5.js} +11 -10
  39. package/dist/{chunk-Q6MMPKQA.js.map → peer/chunk-45GVDKP5.js.map} +1 -1
  40. package/dist/peer/{chunk-R4VX5UC7.js → chunk-LWXQX3NJ.js} +3 -3
  41. package/dist/{chunk-6TPZ7G74.js → peer/chunk-MKY3SDXU.js} +289 -25
  42. package/dist/peer/chunk-MKY3SDXU.js.map +6 -0
  43. package/dist/peer/chunk-S6LSPHSU.js +17 -0
  44. package/dist/peer/chunk-S6LSPHSU.js.map +6 -0
  45. package/dist/peer/{chunk-TSC4RAH3.js → chunk-VZHHNQYB.js} +1301 -70
  46. package/dist/peer/chunk-VZHHNQYB.js.map +6 -0
  47. package/dist/peer/{chunk-WQGENQZO.js → chunk-YITWGAR4.js} +8 -6
  48. package/dist/peer/chunk-YITWGAR4.js.map +6 -0
  49. package/dist/peer/chunk-Z5II55QT.js +33 -0
  50. package/dist/peer/chunk-Z5II55QT.js.map +6 -0
  51. package/dist/peer/designer.js +444 -243
  52. package/dist/peer/designer.js.map +3 -3
  53. package/dist/peer/engine.worker.js +16729 -17
  54. package/dist/peer/engine.worker.js.map +3 -3
  55. package/dist/peer/viewer.js +14 -11
  56. package/dist/peer/viewer.js.map +1 -1
  57. package/dist/viewer.d.ts +2 -1
  58. package/dist/viewer.js +14 -11
  59. package/dist/viewer.js.map +1 -1
  60. package/package.json +4 -2
  61. package/dist/chunk-3D2KFKG2.js.map +0 -6
  62. package/dist/chunk-6TPZ7G74.js.map +0 -6
  63. package/dist/chunk-BRB34AJ2.js +0 -16
  64. package/dist/chunk-M6AYND5G.js.map +0 -6
  65. package/dist/chunk-NR2G4TMG.js.map +0 -6
  66. package/dist/chunk-PGP3QA6L.js.map +0 -6
  67. package/dist/chunk-S2IUUI6N.js.map +0 -6
  68. package/dist/chunk-ULKEEARQ.js +0 -553
  69. package/dist/chunk-ULKEEARQ.js.map +0 -6
  70. package/dist/chunk-VNOWPSE6.js.map +0 -6
  71. package/dist/chunk-Z7MKH66Z.js.map +0 -6
  72. package/dist/peer/chunk-2FZTYEDE.js +0 -15
  73. package/dist/peer/chunk-6I2EAAVN.js.map +0 -6
  74. package/dist/peer/chunk-BQFI3DHK.js.map +0 -6
  75. package/dist/peer/chunk-TSC4RAH3.js.map +0 -6
  76. package/dist/peer/chunk-WQGENQZO.js.map +0 -6
  77. package/dist/peer/chunk-WSNRD2AQ.js.map +0 -6
  78. /package/dist/{chunk-2BPBQMH2.js.map → chunk-F5EPQTPF.js.map} +0 -0
  79. /package/dist/{chunk-BRB34AJ2.js.map → chunk-FEM2QVOO.js.map} +0 -0
  80. /package/dist/{peer/chunk-2FZTYEDE.js.map → chunk-YIX3OJXU.js.map} +0 -0
  81. /package/dist/peer/{chunk-R4VX5UC7.js.map → chunk-LWXQX3NJ.js.map} +0 -0
package/dist/designer.js CHANGED
@@ -13,16 +13,18 @@ import {
13
13
  setShadowStyles,
14
14
  t,
15
15
  uiFontCss
16
- } from "./chunk-NR2G4TMG.js";
16
+ } from "./chunk-L6YEIVVD.js";
17
17
  import {
18
18
  customFonts,
19
- fontStore,
20
19
  fontsBase,
20
+ loadFontStore,
21
21
  loadModelFonts,
22
22
  origin,
23
+ reportFetch,
23
24
  setAssetBase,
25
+ setFetchPolicy,
24
26
  setStandalone
25
- } from "./chunk-6TPZ7G74.js";
27
+ } from "./chunk-CNDUJ7IV.js";
26
28
  import {
27
29
  BASE_STYLE,
28
30
  DEFAULT_THEME,
@@ -31,10 +33,10 @@ import {
31
33
  ITEMS,
32
34
  ODATA_DEFAULT_PAGES,
33
35
  ODATA_MAX_PAGES,
34
- PAGE_SIZES,
35
36
  PALETTES,
36
37
  TEXT_STYLE_PROPS,
37
38
  THEME_COLORS,
39
+ TextMeasurer,
38
40
  XmlError,
39
41
  bestXmlRows,
40
42
  buildDataSets,
@@ -43,7 +45,7 @@ import {
43
45
  detectFields,
44
46
  evalValue,
45
47
  findItemNamed,
46
- fromPt,
48
+ finishText,
47
49
  functionTable,
48
50
  isDynamic,
49
51
  isTablix,
@@ -52,31 +54,29 @@ import {
52
54
  layoutItems,
53
55
  loadBarcodes,
54
56
  loadSources,
55
- normBox,
56
57
  normalizeMatrix,
57
58
  odataMetadata,
58
59
  parseBorder,
59
60
  parseXml,
60
61
  render,
61
- reportFetch,
62
- resolvePage,
63
62
  resolveParameters,
64
- setFetchPolicy,
65
63
  shiftItems,
66
64
  sourceRows,
67
65
  sourceUrl,
68
66
  stylePropsFor,
69
67
  themeContext,
70
- toPt,
71
68
  toText,
72
69
  validate,
73
70
  withPartProps,
74
71
  xmlRowPaths
75
- } from "./chunk-VNOWPSE6.js";
72
+ } from "./chunk-EK5CJY22.js";
76
73
  import {
77
- TextMeasurer,
78
- finishText
79
- } from "./chunk-ULKEEARQ.js";
74
+ PAGE_SIZES,
75
+ fromPt,
76
+ normBox,
77
+ resolvePage,
78
+ toPt
79
+ } from "./chunk-BR5K6SBL.js";
80
80
  import "./chunk-72S6DETS.js";
81
81
  import {
82
82
  currencyOf
@@ -86,20 +86,20 @@ import {
86
86
  fontFaceCss,
87
87
  fontFamilyCss,
88
88
  pageToSvg
89
- } from "./chunk-M6AYND5G.js";
89
+ } from "./chunk-UJL7C2AS.js";
90
90
  import {
91
91
  BUNDLED_FAMILIES,
92
92
  FONT_FAMILIES,
93
93
  allFontKeys,
94
94
  fallbackKeys,
95
95
  resolveFontKey
96
- } from "./chunk-Z7MKH66Z.js";
96
+ } from "./chunk-QFLVVM3H.js";
97
97
  import {
98
98
  __toESM
99
99
  } from "./chunk-OLLMACWA.js";
100
100
 
101
101
  // src/embed/designer.js
102
- var import_react22 = __toESM(require_react(), 1);
102
+ var import_react23 = __toESM(require_react(), 1);
103
103
  var import_client = __toESM(require_client(), 1);
104
104
 
105
105
  // src/importers/rdlx.js
@@ -6867,10 +6867,10 @@ function readReportFile(name2, text) {
6867
6867
  }
6868
6868
 
6869
6869
  // src/designer/Designer.jsx
6870
- var import_react21 = __toESM(require_react(), 1);
6870
+ var import_react22 = __toESM(require_react(), 1);
6871
6871
 
6872
6872
  // src/designer/ui.jsx
6873
- var import_react2 = __toESM(require_react(), 1);
6873
+ var import_react3 = __toESM(require_react(), 1);
6874
6874
 
6875
6875
  // src/designer/fieldCheck.js
6876
6876
  function exprParts(value) {
@@ -7004,13 +7004,9 @@ function useStore(api, selector = identity) {
7004
7004
  import_react.default.useDebugValue(slice);
7005
7005
  return slice;
7006
7006
  }
7007
- var createImpl = (createState) => {
7008
- const api = createStore(createState);
7009
- const useBoundStore = (selector) => useStore(api, selector);
7010
- Object.assign(useBoundStore, api);
7011
- return useBoundStore;
7012
- };
7013
- var create = ((createState) => createState ? createImpl(createState) : createImpl);
7007
+
7008
+ // src/designer/store.js
7009
+ var import_react2 = __toESM(require_react(), 1);
7014
7010
 
7015
7011
  // node_modules/immer/dist/immer.mjs
7016
7012
  var NOTHING = /* @__PURE__ */ Symbol.for("immer-nothing");
@@ -7859,6 +7855,17 @@ function pageOf2(def, key2 = "body") {
7859
7855
  return resolvePage({ ...def.page || {}, ...sec?.page || {} });
7860
7856
  }
7861
7857
  var rid = () => Math.random().toString(36).slice(2, 10);
7858
+ function stableId(key2, taken) {
7859
+ let h = 2166136261;
7860
+ for (let i2 = 0; i2 < key2.length; i2++) {
7861
+ h ^= key2.charCodeAt(i2);
7862
+ h = Math.imul(h, 16777619);
7863
+ }
7864
+ let id = `i${(h >>> 0).toString(36)}`;
7865
+ for (let k = 2; taken.has(id); k++) id = `i${(h >>> 0).toString(36)}_${k}`;
7866
+ taken.add(id);
7867
+ return id;
7868
+ }
7862
7869
  function walk(def, fn3) {
7863
7870
  const go = (list2, parent, section) => list2.forEach((it, i2) => {
7864
7871
  fn3(it, list2, i2, parent, section);
@@ -7884,9 +7891,15 @@ function normalize(def) {
7884
7891
  if (x && typeof x === "object") x.items || (x.items = []);
7885
7892
  }
7886
7893
  const used = allNames(d);
7894
+ const ids = /* @__PURE__ */ new Set();
7887
7895
  walk(d, (it) => {
7888
- it.id || (it.id = rid());
7896
+ if (it.id) ids.add(it.id);
7897
+ });
7898
+ const path = /* @__PURE__ */ new Map();
7899
+ walk(d, (it, list2, i2, parent, section) => {
7900
+ path.set(it, `${parent ? path.get(parent) : section}/${i2}`);
7889
7901
  if (!it.name) it.name = uniqueName(used, ITEMS[it.type]?.label.replace(/\s/g, "") || "Item");
7902
+ it.id || (it.id = stableId(`${path.get(it)}/${it.name}`, ids));
7890
7903
  if (NESTING.has(it.type)) it.items || (it.items = []);
7891
7904
  if (it.type === "table" && Array.isArray(it.columns)) tableSync(it);
7892
7905
  });
@@ -7910,7 +7923,7 @@ function findItem(def, id) {
7910
7923
  });
7911
7924
  return hit;
7912
7925
  }
7913
- var useDesigner = create((set2, get2) => ({
7926
+ var newDesignerStore = () => createStore((set2, get2) => ({
7914
7927
  id: null,
7915
7928
  def: null,
7916
7929
  saved: true,
@@ -8041,7 +8054,18 @@ var useDesigner = create((set2, get2) => ({
8041
8054
  set2({ rev: (res.headers.get("etag") || "").replace(/^W\/|"/g, "") || null, conflict: null });
8042
8055
  }
8043
8056
  }));
8044
- var S = () => useDesigner.getState();
8057
+ var active = newDesignerStore();
8058
+ var DesignerStore = (0, import_react2.createContext)(null);
8059
+ var activateStore = (store) => {
8060
+ active = store;
8061
+ };
8062
+ var activeStore2 = () => active;
8063
+ var useDesignerStore = () => (0, import_react2.useContext)(DesignerStore) || active;
8064
+ var useDesigner = (sel) => useStore(useDesignerStore(), sel);
8065
+ useDesigner.getState = () => active.getState();
8066
+ useDesigner.setState = (...a) => active.setState(...a);
8067
+ useDesigner.subscribe = (fn3) => active.subscribe(fn3);
8068
+ var S = () => active.getState();
8045
8069
  function bodyWidth(def, key2 = "body") {
8046
8070
  return pageOf2(def, key2).bodyWidth;
8047
8071
  }
@@ -8089,7 +8113,7 @@ function addItem(type, section, x, y, extra = {}, parentId = null) {
8089
8113
  } else {
8090
8114
  const sec = secOf(d, section);
8091
8115
  sec.items.push(it);
8092
- if (it.y + it.h > sec.height) sec.height = Math.ceil(it.y + it.h + (isBodyKey(section) ? 24 : 4));
8116
+ if (it.y + it.h > (sec.height || 0)) sec.height = Math.ceil(it.y + it.h + (isBodyKey(section) ? 24 : 4));
8093
8117
  }
8094
8118
  });
8095
8119
  S().select({ kind: "items", ids: [id] });
@@ -8115,9 +8139,21 @@ function insertItem(type, section, x, y, extra = {}, parentId = null) {
8115
8139
  function updateItem(id, recipe, key2) {
8116
8140
  S().apply((d) => {
8117
8141
  const f = findItem(d, id);
8118
- if (f) recipe(f.item, d, f.section, f);
8142
+ if (!f) return;
8143
+ recipe(f.item, d, f.section, f);
8144
+ minSize(f.item);
8145
+ const nf = findItem(d, id);
8146
+ if (nf) growToFit(d, nf);
8119
8147
  }, key2);
8120
8148
  }
8149
+ function minSize(it) {
8150
+ for (const k of ["w", "h"]) if (typeof it[k] === "number" && !(it[k] >= 0)) it[k] = 0;
8151
+ if (it.type === "line") {
8152
+ if (it.w === 0 && it.h === 0) it.w = 1;
8153
+ return;
8154
+ }
8155
+ for (const k of ["w", "h"]) if (typeof it[k] === "number" && it[k] < 1) it[k] = 1;
8156
+ }
8121
8157
  function moveItems(ids, dx, dy) {
8122
8158
  if (!dx && !dy) return;
8123
8159
  if (S().cells && wouldOverlap(S().def, ids, (it) => ({ x: it.x + dx, y: it.y + dy, w: it.w, h: it.h }))) {
@@ -8248,14 +8284,16 @@ function duplicateSelection() {
8248
8284
  const f = findItem(d, id);
8249
8285
  if (!f) continue;
8250
8286
  const copy = cloneWithIds(f.item, used);
8251
- copy.x += 8;
8252
- copy.y += 8;
8287
+ copy.x += PASTE_OFFSET;
8288
+ copy.y += PASTE_OFFSET;
8289
+ growToFit(d, { ...f, item: copy });
8253
8290
  f.list.push(copy);
8254
8291
  newIds.push(copy.id);
8255
8292
  }
8256
8293
  });
8257
8294
  if (newIds.length) S().select({ kind: "items", ids: newIds });
8258
8295
  }
8296
+ var PASTE_OFFSET = 12;
8259
8297
  var CLIP = "pagewright/items@1";
8260
8298
  async function copySelection() {
8261
8299
  const { sel, def } = S();
@@ -8270,43 +8308,41 @@ async function copySelection() {
8270
8308
  return items.length;
8271
8309
  }
8272
8310
  var memClip = null;
8273
- async function pasteItems(section = "body") {
8274
- let text = null;
8275
- try {
8276
- text = await navigator.clipboard.readText();
8277
- } catch {
8278
- text = memClip;
8279
- }
8280
- if (!text || !text.includes(CLIP)) text = memClip;
8281
- let data;
8311
+ var clipOf = (text) => {
8282
8312
  try {
8283
- data = JSON.parse(text);
8313
+ const d = JSON.parse(text);
8314
+ return d?.kind === CLIP && Array.isArray(d.items) ? d : null;
8284
8315
  } catch {
8285
- return 0;
8316
+ return null;
8286
8317
  }
8287
- if (data?.kind !== CLIP || !Array.isArray(data.items)) return 0;
8318
+ };
8319
+ function pasteItems(section = "body", text = null) {
8320
+ const st = active;
8321
+ const data = clipOf(text) || clipOf(memClip);
8322
+ if (!data) return 0;
8288
8323
  const ids = [];
8289
- S().apply((d) => {
8324
+ st.getState().apply((d) => {
8290
8325
  const used = allNames(d);
8291
8326
  for (const it of data.items) {
8292
8327
  const c = cloneWithIds(it, used);
8293
- c.x += 12;
8294
- c.y += 12;
8328
+ c.x += PASTE_OFFSET;
8329
+ c.y += PASTE_OFFSET;
8295
8330
  if (c.type === "table" && !isBodyKey(section)) continue;
8296
8331
  secOf(d, section).items.push(c);
8332
+ growToFit(d, { section, parent: null, item: c });
8297
8333
  ids.push(c.id);
8298
8334
  }
8299
8335
  });
8300
- if (ids.length) S().select({ kind: "items", ids });
8336
+ if (ids.length) st.getState().select({ kind: "items", ids });
8301
8337
  return ids.length;
8302
8338
  }
8303
- function rowsOf(t3, part, create2 = false) {
8339
+ function rowsOf(t3, part, create = false) {
8304
8340
  const m = /^g(\d+)([hf])$/.exec(part);
8305
8341
  const holder = m ? t3.groups?.[Number(m[1])] : t3;
8306
8342
  if (!holder) return null;
8307
8343
  const key2 = m ? m[2] === "h" ? "header" : "footer" : part;
8308
8344
  if (!holder[key2]) {
8309
- if (!create2) return [];
8345
+ if (!create) return [];
8310
8346
  holder[key2] = [];
8311
8347
  }
8312
8348
  return holder[key2];
@@ -8506,6 +8542,7 @@ function tableRemoveGroup(id, level) {
8506
8542
  }
8507
8543
  var IMAGE_MAX = 10 * 1024 * 1024;
8508
8544
  async function uploadImages(files, T) {
8545
+ const st = active;
8509
8546
  const names = [];
8510
8547
  let err = null;
8511
8548
  for (const f of files) {
@@ -8524,7 +8561,7 @@ async function uploadImages(files, T) {
8524
8561
  r.readAsDataURL(f);
8525
8562
  });
8526
8563
  const base2 = f.name.replace(/\.[^.]+$/, "").replace(/\W+/g, "_").replace(/^_+|_+$/g, "") || "image";
8527
- S().apply((d) => {
8564
+ st.getState().apply((d) => {
8528
8565
  d.images || (d.images = {});
8529
8566
  let n = base2, k = 2;
8530
8567
  while (d.images[n]) n = `${base2}${k++}`;
@@ -8591,6 +8628,13 @@ function wouldOverlap(def, ids, rectOf2) {
8591
8628
  }
8592
8629
  return false;
8593
8630
  }
8631
+ function setMatrixShow(v, show) {
8632
+ const pct = !!show && show !== "value";
8633
+ if (pct) v.show = show;
8634
+ else delete v.show;
8635
+ if (pct && (!v.format || v.format === "N0")) v.format = "P1";
8636
+ else if (!pct && v.format === "P1") v.format = "N0";
8637
+ }
8594
8638
 
8595
8639
  // src/designer/ui.jsx
8596
8640
  var import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
@@ -8602,8 +8646,8 @@ function TextInput({ value, onChange, mono, invalid, className, ...rest }) {
8602
8646
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { className: `input${mono ? " mono" : ""}${invalid ? " invalid" : ""}${className ? ` ${className}` : ""}`, value: value ?? "", onChange: (e) => onChange(e.target.value), ...rest });
8603
8647
  }
8604
8648
  function NumberInput({ value, onChange, step = 0.5, min, ...rest }) {
8605
- const [draft, setDraft] = (0, import_react2.useState)(value ?? "");
8606
- (0, import_react2.useEffect)(() => {
8649
+ const [draft, setDraft] = (0, import_react3.useState)(value ?? "");
8650
+ (0, import_react3.useEffect)(() => {
8607
8651
  setDraft(value ?? "");
8608
8652
  }, [value]);
8609
8653
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -8639,18 +8683,18 @@ function ColorInput({ value, onChange }) {
8639
8683
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextInput, { value, onChange: (v) => onChange(v === "" ? void 0 : v), mono: true, placeholder: T("i_colorPh") })
8640
8684
  ] });
8641
8685
  }
8642
- var FieldScope = (0, import_react2.createContext)(void 0);
8686
+ var FieldScope = (0, import_react3.createContext)(void 0);
8643
8687
  var issueText = (T, i2) => i2.suggest ? T("ux_unknownFieldSuggest", { name: i2.name, suggest: i2.suggest }) : T("ux_unknownField", { name: i2.name });
8644
8688
  function ExprInput({ value, onChange, onOpen, placeholder: placeholder2 }) {
8645
8689
  const T = useT();
8646
- const scope = (0, import_react2.useContext)(FieldScope);
8690
+ const scope = (0, import_react3.useContext)(FieldScope);
8647
8691
  const dataSets = useDesigner((s) => s.def?.dataSets);
8648
8692
  const err = value ? checkValue(value) : null;
8649
8693
  const issues = !err && value && scope !== void 0 ? fieldIssues(value, dataSets, scope) : [];
8650
8694
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
8651
8695
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "expr-row", children: [
8652
8696
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextInput, { value, onChange, mono: true, invalid: !!err, className: issues.length ? "squiggle" : void 0, "aria-invalid": err || issues.length ? true : void 0, placeholder: placeholder2 || T("i_exprPh") }),
8653
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "fx", title: T("i_openExprEditor"), "aria-label": T("i_openExprEditor"), onClick: onOpen, type: "button", children: "fx" })
8697
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "fx", title: T("i_openExprEditor"), "aria-label": `fx: ${T("i_openExprEditor")}`, onClick: onOpen, type: "button", children: "fx" })
8654
8698
  ] }),
8655
8699
  err && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "err", children: err }),
8656
8700
  issues.map((i2, k) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "warn", "data-testid": "field-warning", children: issueText(T, i2) }, k))
@@ -8670,14 +8714,19 @@ function Check({ label, checked, onChange }) {
8670
8714
  ] });
8671
8715
  }
8672
8716
  function Dialog({ title, children, onClose, footer, wide, className = "" }) {
8673
- (0, import_react2.useEffect)(() => {
8717
+ const ref = (0, import_react3.useRef)(null);
8718
+ (0, import_react3.useEffect)(() => {
8719
+ const inOther = (e) => {
8720
+ const mine = ref.current?.closest(".designer");
8721
+ return e.composedPath().some((n) => n !== mine && n?.classList?.contains("designer"));
8722
+ };
8674
8723
  const k = (e) => {
8675
- if (e.key === "Escape" && !e.defaultPrevented) onClose();
8724
+ if (e.key === "Escape" && !e.defaultPrevented && !inOther(e)) onClose();
8676
8725
  };
8677
8726
  window.addEventListener("keydown", k);
8678
8727
  return () => window.removeEventListener("keydown", k);
8679
8728
  }, [onClose]);
8680
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "scrim", onPointerDown: (e) => {
8729
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "scrim", ref, onPointerDown: (e) => {
8681
8730
  if (e.target === e.currentTarget) onClose();
8682
8731
  }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `dialog${wide ? " wide" : ""}${className ? ` ${className}` : ""}`, role: "dialog", "aria-modal": "true", "aria-label": title, children: [
8683
8732
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("header", { children: title }),
@@ -8687,20 +8736,20 @@ function Dialog({ title, children, onClose, footer, wide, className = "" }) {
8687
8736
  }
8688
8737
 
8689
8738
  // src/embed/link.js
8690
- var import_react3 = __toESM(require_react(), 1);
8739
+ var import_react4 = __toESM(require_react(), 1);
8691
8740
  function Link({ href, children, prefetch, replace: replace2, scroll, shallow, ...rest }) {
8692
- return (0, import_react3.createElement)("a", { href: typeof href === "string" ? href : String(href?.pathname || ""), ...rest }, children);
8741
+ return (0, import_react4.createElement)("a", { href: typeof href === "string" ? href : String(href?.pathname || ""), ...rest }, children);
8693
8742
  }
8694
8743
 
8695
8744
  // src/designer/SvgHtml.jsx
8696
- var import_react4 = __toESM(require_react(), 1);
8745
+ var import_react5 = __toESM(require_react(), 1);
8697
8746
  var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
8698
8747
  function SvgHtml({ html, as: Tag2 = "span", ...rest }) {
8699
- const ref = (0, import_react4.useRef)(
8748
+ const ref = (0, import_react5.useRef)(
8700
8749
  /** @type {HTMLElement|null} */
8701
8750
  null
8702
8751
  );
8703
- (0, import_react4.useLayoutEffect)(() => {
8752
+ (0, import_react5.useLayoutEffect)(() => {
8704
8753
  if (!ref.current) return;
8705
8754
  ref.current.innerHTML = deferStyleAttributes(html);
8706
8755
  applyStyleAttributes(ref.current);
@@ -8709,7 +8758,7 @@ function SvgHtml({ html, as: Tag2 = "span", ...rest }) {
8709
8758
  }
8710
8759
 
8711
8760
  // src/designer/Canvas.jsx
8712
- var import_react7 = __toESM(require_react(), 1);
8761
+ var import_react8 = __toESM(require_react(), 1);
8713
8762
 
8714
8763
  // src/designer/tableGen.js
8715
8764
  var HEAD = { fontWeight: "bold", backgroundColor: "#f1f5f9", borderBottom: "0.75 solid #94a3b8" };
@@ -8841,24 +8890,28 @@ function instantPicks(fields, rows = []) {
8841
8890
  }
8842
8891
 
8843
8892
  // src/designer/Reuse.jsx
8844
- var import_react6 = __toESM(require_react(), 1);
8893
+ var import_react7 = __toESM(require_react(), 1);
8845
8894
 
8846
8895
  // src/designer/Fonts.jsx
8847
- var import_react5 = __toESM(require_react(), 1);
8896
+ var import_react6 = __toESM(require_react(), 1);
8848
8897
  var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
8849
8898
  function useFontFamilies() {
8850
8899
  const fonts = useDesigner((s) => s.fonts);
8851
8900
  return [...BUNDLED_FAMILIES, ...[...new Set(fonts.map((f) => f.family))].sort()];
8852
8901
  }
8853
- var refresh = async () => useDesigner.getState().setUi({ fonts: await customFonts(true) });
8902
+ var refresh = async () => {
8903
+ const api = activeStore2();
8904
+ const fonts = await customFonts(true);
8905
+ api.getState().setUi({ fonts });
8906
+ };
8854
8907
  function FontsDialog({ onClose }) {
8855
8908
  const fonts = useDesigner((s) => s.fonts);
8856
- const [file, setFile] = (0, import_react5.useState)(null);
8857
- const [family, setFamily] = (0, import_react5.useState)("");
8858
- const [weight, setWeight] = (0, import_react5.useState)("");
8859
- const [style, setStyle] = (0, import_react5.useState)("");
8860
- const [busy, setBusy] = (0, import_react5.useState)(false);
8861
- const [msg, setMsg] = (0, import_react5.useState)(null);
8909
+ const [file, setFile] = (0, import_react6.useState)(null);
8910
+ const [family, setFamily] = (0, import_react6.useState)("");
8911
+ const [weight, setWeight] = (0, import_react6.useState)("");
8912
+ const [style, setStyle] = (0, import_react6.useState)("");
8913
+ const [busy, setBusy] = (0, import_react6.useState)(false);
8914
+ const [msg, setMsg] = (0, import_react6.useState)(null);
8862
8915
  const upload = async () => {
8863
8916
  if (!file) return;
8864
8917
  setBusy(true);
@@ -8949,30 +9002,33 @@ var apply = (fn3, key2) => S2().apply(fn3, key2);
8949
9002
  var server = () => S2().embed?.server || "";
8950
9003
  var noServer = () => !!S2().embed && !S2().embed.server;
8951
9004
  var pending = /* @__PURE__ */ new Map();
8952
- function fetchReused(id, force = false) {
9005
+ function fetchReused(id, force = false, api = activeStore2()) {
8953
9006
  if (!id || typeof id !== "string" || id.startsWith("=")) return Promise.resolve(null);
8954
- if (!force && S2().reused[id]) return Promise.resolve(S2().reused[id]);
8955
- if (pending.has(id)) return pending.get(id);
8956
- if (noServer()) return Promise.resolve(null);
8957
- const p = fetch(`${server()}/api/reports/${encodeURIComponent(id)}`).then((r) => r.ok ? r.json() : { __error: `HTTP ${r.status}` }).catch((e) => ({ __error: e.message })).then((d) => {
8958
- pending.delete(id);
8959
- useDesigner.setState((s) => ({ reused: { ...s.reused, [id]: d } }));
9007
+ const st = api.getState();
9008
+ if (!force && st.reused[id]) return Promise.resolve(st.reused[id]);
9009
+ const server2 = st.embed?.server || "", key2 = `${server2} ${id}`;
9010
+ const keep = (d) => {
9011
+ api.setState((s) => ({ reused: { ...s.reused, [id]: d } }));
8960
9012
  return d;
8961
- });
8962
- pending.set(id, p);
8963
- return p;
9013
+ };
9014
+ if (pending.has(key2)) return pending.get(key2).then(keep);
9015
+ if (st.embed && !server2) return Promise.resolve(null);
9016
+ const p = fetch(`${server2}/api/reports/${encodeURIComponent(id)}`).then((r) => r.ok ? r.json() : { __error: `HTTP ${r.status}` }).catch((e) => ({ __error: e.message })).finally(() => pending.delete(key2));
9017
+ pending.set(key2, p);
9018
+ return p.then(keep);
8964
9019
  }
8965
9020
  function useReused(id) {
9021
+ const api = useDesignerStore();
8966
9022
  const d = useDesigner((s) => id ? s.reused[id] : void 0);
8967
- (0, import_react6.useEffect)(() => {
8968
- fetchReused(id);
8969
- }, [id]);
9023
+ (0, import_react7.useEffect)(() => {
9024
+ fetchReused(id, false, api);
9025
+ }, [id, api]);
8970
9026
  return d && !d.__error ? d : null;
8971
9027
  }
8972
9028
  var listCache = null;
8973
9029
  function ReportSelect({ value, onChange, exclude, ...rest }) {
8974
- const [list2, setList] = (0, import_react6.useState)(listCache || []);
8975
- (0, import_react6.useEffect)(() => {
9030
+ const [list2, setList] = (0, import_react7.useState)(listCache || []);
9031
+ (0, import_react7.useEffect)(() => {
8976
9032
  if (noServer()) return;
8977
9033
  fetch(`${server()}/api/reports`).then((r) => r.ok ? r.json() : []).then((l) => {
8978
9034
  listCache = Array.isArray(l) ? l : [];
@@ -9039,7 +9095,7 @@ function ThemeSection() {
9039
9095
  const id = useDesigner((s) => s.id);
9040
9096
  const families = useFontFamilies();
9041
9097
  const src = def.theme;
9042
- const [mode, setMode] = (0, import_react6.useState)(!src ? "own" : String(src).startsWith("=") ? "expr" : "report");
9098
+ const [mode, setMode] = (0, import_react7.useState)(!src ? "own" : String(src).startsWith("=") ? "expr" : "report");
9043
9099
  const td = def.themeDef || {};
9044
9100
  const setTd = (fn3, key2) => apply((d) => {
9045
9101
  d.themeDef || (d.themeDef = {});
@@ -9058,7 +9114,7 @@ function ThemeSection() {
9058
9114
  else x.fonts[k][p] = v;
9059
9115
  }, `theme.font.${k}.${p}`);
9060
9116
  const consts = Object.entries(td.constants || {});
9061
- const [newConst, setNewConst] = (0, import_react6.useState)("");
9117
+ const [newConst, setNewConst] = (0, import_react7.useState)("");
9062
9118
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "cat", "data-testid": "theme", children: [
9063
9119
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CatHead, { children: T("theme") }),
9064
9120
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Field, { label: T("themeSource"), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
@@ -9118,7 +9174,7 @@ function LayersPanel() {
9118
9174
  const T = useT2();
9119
9175
  const layers = useDesigner((s) => s.def.layers) || [];
9120
9176
  const readOnly2 = useDesigner((s) => s.readOnly);
9121
- const [name2, setName] = (0, import_react6.useState)("");
9177
+ const [name2, setName] = (0, import_react7.useState)("");
9122
9178
  const set2 = (fn3, key2) => apply((d) => {
9123
9179
  d.layers || (d.layers = []);
9124
9180
  fn3(d.layers, d);
@@ -9273,7 +9329,7 @@ function PartsPanel() {
9273
9329
  const libs = useDesigner((s) => s.def.libraries) || [];
9274
9330
  const id = useDesigner((s) => s.id);
9275
9331
  const readOnly2 = useDesigner((s) => s.readOnly);
9276
- const [pick, setPick] = (0, import_react6.useState)("");
9332
+ const [pick, setPick] = (0, import_react7.useState)("");
9277
9333
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "pane", "data-testid": "parts-panel", children: [
9278
9334
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("h4", { children: [
9279
9335
  T("parts"),
@@ -9402,7 +9458,7 @@ function PublishPart({ item }) {
9402
9458
  if (v === void 0 || v === "") delete q2[k];
9403
9459
  else q2[k] = v;
9404
9460
  }, `part${i2}.q${j}.${k}`);
9405
- const [newProp, setNewProp] = (0, import_react6.useState)("");
9461
+ const [newProp, setNewProp] = (0, import_react7.useState)("");
9406
9462
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "cat", "data-testid": "publish-part", children: [
9407
9463
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CatHead, { children: T("reportPart") }),
9408
9464
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Check, { label: T("publishPart"), checked: !!p, onChange: (on) => set2((l) => {
@@ -9531,12 +9587,12 @@ function useDesignIssues() {
9531
9587
  const def = useDesigner((s) => s.def);
9532
9588
  const extents = useDesigner((s) => s.extents);
9533
9589
  const saveCheck = useDesigner((s) => s.saveCheck);
9534
- return (0, import_react7.useMemo)(() => {
9590
+ return (0, import_react8.useMemo)(() => {
9535
9591
  const bands = sectionList(def).map((s) => ({ key: s.key, items: secOf(def, s.key)?.items || [], width: bodyWidth(def, s.key) }));
9536
9592
  return [...designIssues(def, bands, extents || {}), ...checkIssues(bands, [...validate(def).errors, ...saveCheck?.missing || []])];
9537
9593
  }, [def, extents, saveCheck]);
9538
9594
  }
9539
- var IssueMap = (0, import_react7.createContext)(/* @__PURE__ */ new Map());
9595
+ var IssueMap = (0, import_react8.createContext)(/* @__PURE__ */ new Map());
9540
9596
  function issueLine(T, i2) {
9541
9597
  if (i2.kind === "overlap") return T("ux_issueOverlap", { name: i2.name, other: i2.other });
9542
9598
  if (i2.kind === "wide") return T("ux_issueWide", { name: i2.name, width: i2.width, room: i2.room });
@@ -9601,9 +9657,9 @@ function Canvas() {
9601
9657
  const bands = sectionList(def);
9602
9658
  const widths2 = Object.fromEntries(bands.map((s) => [s.key, bodyWidth(def, s.key)]));
9603
9659
  const bw = Math.max(...Object.values(widths2));
9604
- const scrollRef = (0, import_react7.useRef)(null);
9605
- const [fitW, setFitW] = (0, import_react7.useState)(0);
9606
- (0, import_react7.useEffect)(() => {
9660
+ const scrollRef = (0, import_react8.useRef)(null);
9661
+ const [fitW, setFitW] = (0, import_react8.useState)(0);
9662
+ (0, import_react8.useEffect)(() => {
9607
9663
  if (zoom !== "fit" || !scrollRef.current) return;
9608
9664
  const el = scrollRef.current;
9609
9665
  const ro = new ResizeObserver(() => setFitW(el.clientWidth));
@@ -9611,10 +9667,10 @@ function Canvas() {
9611
9667
  return () => ro.disconnect();
9612
9668
  }, [zoom]);
9613
9669
  const scale = zoom === "fit" ? Math.max(0.3, Math.min(3, ((fitW || 900) - 80) / bw)) : zoom * PX;
9614
- const [drag, setDrag] = (0, import_react7.useState)(null);
9670
+ const [drag, setDrag] = (0, import_react8.useState)(null);
9615
9671
  const T = useT2();
9616
9672
  const issues = useDesignIssues();
9617
- const byId = (0, import_react7.useMemo)(() => {
9673
+ const byId = (0, import_react8.useMemo)(() => {
9618
9674
  const m = /* @__PURE__ */ new Map();
9619
9675
  for (const i2 of issues) m.set(i2.id, [...m.get(i2.id) || [], issueLine(T, i2)]);
9620
9676
  return m;
@@ -9695,9 +9751,9 @@ function Band({ section, label, scale, bw: bandW, drag, setDrag, phBox = null })
9695
9751
  const off = phBox || mb?.off || null;
9696
9752
  const contentList = useDesigner((s) => s.def.sections?.content);
9697
9753
  const bw = off?.w || bandW;
9698
- const ref = (0, import_react7.useRef)(null);
9699
- const [marquee, setMarquee] = (0, import_react7.useState)(null);
9700
- const [dropping, setDropping] = (0, import_react7.useState)(false);
9754
+ const ref = (0, import_react8.useRef)(null);
9755
+ const [marquee, setMarquee] = (0, import_react8.useState)(null);
9756
+ const [dropping, setDropping] = (0, import_react8.useState)(false);
9701
9757
  const h = drag?.mode === "band" && drag.section === section ? drag.h : sec.height || 0;
9702
9758
  const DROP_ROOM = 96;
9703
9759
  const toPt3 = (e) => {
@@ -9871,8 +9927,9 @@ var alerted = 0;
9871
9927
  function alertOnce(msg) {
9872
9928
  if (Date.now() - alerted > 3e3) {
9873
9929
  alerted = Date.now();
9874
- useDesigner.setState({ saveError: msg });
9875
- setTimeout(() => useDesigner.setState({ saveError: null }), 3e3);
9930
+ const api = activeStore2();
9931
+ api.setState({ saveError: msg });
9932
+ setTimeout(() => api.setState({ saveError: null }), 3e3);
9876
9933
  }
9877
9934
  }
9878
9935
  function fieldStyle(f) {
@@ -9880,11 +9937,31 @@ function fieldStyle(f) {
9880
9937
  const format = formatFor({ name: f.field, type: f.type }, (st.sample?.dataSets?.[f.dataSet] || []).slice(0, 200), { currency: st.def?.currency });
9881
9938
  return format ? { format } : {};
9882
9939
  }
9940
+ function useItemKeys(item) {
9941
+ const T = useT2();
9942
+ const type = T(`item_${item.type}`) === `item_${item.type}` ? ITEMS[item.type]?.label || item.type : T(`item_${item.type}`);
9943
+ return {
9944
+ tabIndex: 0,
9945
+ role: "group",
9946
+ "data-item-key": item.id,
9947
+ "aria-label": T("b9_itemLabel", { type, name: item.name, x: round(item.x), y: round(item.y) }),
9948
+ onKeyDown: (e) => {
9949
+ if (e.target !== e.currentTarget || e.key !== "Enter" && e.key !== " ") return;
9950
+ e.preventDefault();
9951
+ e.stopPropagation();
9952
+ const st = useDesigner.getState();
9953
+ const cur2 = st.sel.kind === "items" ? st.sel.ids : [];
9954
+ const ids = !e.shiftKey ? [item.id] : cur2.includes(item.id) ? cur2.filter((i2) => i2 !== item.id) : [...cur2, item.id];
9955
+ st.select(ids.length ? { kind: "items", ids } : { kind: "report" });
9956
+ }
9957
+ };
9958
+ }
9883
9959
  function useItemDrag(item, scale, setDrag) {
9884
9960
  return (e) => {
9885
9961
  if (e.button !== 0) return;
9886
9962
  e.preventDefault();
9887
9963
  e.stopPropagation();
9964
+ e.currentTarget.closest?.("[data-item-key]")?.focus({ preventScroll: true });
9888
9965
  const st = useDesigner.getState();
9889
9966
  let ids;
9890
9967
  if (e.shiftKey) {
@@ -9957,8 +10034,8 @@ function AnyItem(props) {
9957
10034
  return layer?.locked ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "layer-locked", "data-locked": props.item.name, children: el }) : el;
9958
10035
  }
9959
10036
  function NestChildren({ item, scale, drag, setDrag, section }) {
9960
- const ref = (0, import_react7.useRef)(null);
9961
- const [over, setOver] = (0, import_react7.useState)(false);
10037
+ const ref = (0, import_react8.useRef)(null);
10038
+ const [over, setOver] = (0, import_react8.useState)(false);
9962
10039
  const accepts = (e) => e.dataTransfer.types.includes(MIME_TOOL) || e.dataTransfer.types.includes(MIME_FIELD) || e.dataTransfer.types.includes(MIME_PART);
9963
10040
  const onDrop = (e) => {
9964
10041
  setOver(false);
@@ -10003,8 +10080,9 @@ function ItemView({ item, scale, drag, setDrag, bw, nest, section }) {
10003
10080
  const selected = useDesigner((s) => s.sel.kind === "items" && s.sel.ids.includes(item.id));
10004
10081
  const single = useDesigner((s) => s.sel.kind === "items" && s.sel.ids.length === 1);
10005
10082
  const onDown = useItemDrag(item, scale, setDrag);
10083
+ const keys = useItemKeys(item);
10006
10084
  const r = rectOf(item, drag);
10007
- const problems = (0, import_react7.useContext)(IssueMap).get(item.id);
10085
+ const problems = (0, import_react8.useContext)(IssueMap).get(item.id);
10008
10086
  const onHandle = (dir) => (e) => {
10009
10087
  e.preventDefault();
10010
10088
  e.stopPropagation();
@@ -10063,6 +10141,7 @@ function ItemView({ item, scale, drag, setDrag, bw, nest, section }) {
10063
10141
  title: problems?.join("\n"),
10064
10142
  style: { left: r.x * scale, top: r.y * scale, width: Math.max(r.w * scale, 2), height: Math.max(r.h * scale, 2) },
10065
10143
  onPointerDown: onDown,
10144
+ ...keys,
10066
10145
  children: [
10067
10146
  nest ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NestBox, { item: { ...item, ...r }, scale }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ItemBody, { item: { ...item, ...r }, scale }),
10068
10147
  nest && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NestChildren, { item, scale, drag, setDrag, section }),
@@ -10080,8 +10159,8 @@ function NestBox({ item, scale }) {
10080
10159
  }
10081
10160
  var LIVE = /* @__PURE__ */ new Set(["chart", "matrix", "barcode", "sparkline", "databar", "bullet", "iconset", "rangebar", "richtext"]);
10082
10161
  var measurer = null;
10083
- async function paintItemSvg(shape2, def, sample) {
10084
- const store = fontStore();
10162
+ async function paintItemSvg(shape2, def, sample, api = activeStore2()) {
10163
+ const store = await loadFontStore();
10085
10164
  await Promise.all([store.load(), customFonts()]);
10086
10165
  if (shape2.type === "barcode" || hasType(shape2.items, "barcode")) await loadBarcodes();
10087
10166
  measurer || (measurer = new TextMeasurer(store));
@@ -10092,7 +10171,7 @@ async function paintItemSvg(shape2, def, sample) {
10092
10171
  } catch {
10093
10172
  }
10094
10173
  const base2 = { fontFamily: "Inter", fontSize: 9, color: "#1f2937", padding: 2, lineHeight: 1.25, textAlign: "auto", verticalAlign: "top", ...def.styles?.base || {} };
10095
- const theme3 = themeContext(typeof def.theme === "string" && useDesigner.getState().reused[def.theme]?.themeDef || def.themeDef);
10174
+ const theme3 = themeContext(typeof def.theme === "string" && api.getState().reused[def.theme]?.themeDef || def.themeDef);
10096
10175
  const ctxBase = { params, globals: { PageNumber: 1, TotalPages: 1, ExecutionTime: /* @__PURE__ */ new Date(), ReportName: def.name }, dataSets, fields: null, locale: def.locale, currency: def.currency, functions: functionTable(def), theme: theme3 };
10097
10176
  let seq = 0;
10098
10177
  const lc = {
@@ -10134,20 +10213,21 @@ async function paintItemSvg(shape2, def, sample) {
10134
10213
  return { html: pageToSvg({ items }, shape2.w, h, { background: false }), h, w };
10135
10214
  }
10136
10215
  function LivePreview({ item, scale }) {
10216
+ const api = useDesignerStore();
10137
10217
  const sample = useDesigner((s) => s.sample);
10138
10218
  const def = useDesigner((s) => s.def);
10139
- const [svg, setSvg] = (0, import_react7.useState)(null);
10219
+ const [svg, setSvg] = (0, import_react8.useState)(null);
10140
10220
  const { x, y, ...shape2 } = item;
10141
10221
  const key2 = JSON.stringify(shape2);
10142
- (0, import_react7.useEffect)(() => {
10222
+ (0, import_react8.useEffect)(() => {
10143
10223
  let alive = true;
10144
10224
  const t3 = setTimeout(async () => {
10145
10225
  try {
10146
- const out = await paintItemSvg(shape2, def, sample);
10226
+ const out = await paintItemSvg(shape2, def, sample, api);
10147
10227
  if (alive) {
10148
10228
  setSvg(out);
10149
- const ex2 = useDesigner.getState().extents || {};
10150
- if (Math.round(ex2[item.id]?.w || 0) !== Math.round(out.w)) useDesigner.setState({ extents: { ...ex2, [item.id]: { w: out.w } } });
10229
+ const ex2 = api.getState().extents || {};
10230
+ if (Math.round(ex2[item.id]?.w || 0) !== Math.round(out.w)) api.setState({ extents: { ...ex2, [item.id]: { w: out.w } } });
10151
10231
  }
10152
10232
  } catch (e) {
10153
10233
  if (alive) setSvg({ error: e.message });
@@ -10169,9 +10249,9 @@ function PartPreview({ item, scale }) {
10169
10249
  const p = (lib?.parts || []).find((q2) => q2.name === item.part);
10170
10250
  const src = p && findItemNamed(lib, p.item);
10171
10251
  const props = { ...Object.fromEntries((p?.properties || []).map((q2) => [q2.name, q2.default ?? null])), ...item.properties || {} };
10172
- const [svg, setSvg] = (0, import_react7.useState)(null);
10252
+ const [svg, setSvg] = (0, import_react8.useState)(null);
10173
10253
  const key2 = JSON.stringify([src, props]);
10174
- (0, import_react7.useEffect)(() => {
10254
+ (0, import_react8.useEffect)(() => {
10175
10255
  if (!src) return void 0;
10176
10256
  let alive = true;
10177
10257
  const t3 = setTimeout(() => {
@@ -10281,17 +10361,18 @@ function TableView({ item, scale, drag, setDrag }) {
10281
10361
  const readOnly2 = useDesigner((s) => s.readOnly);
10282
10362
  const tableSelected = sel.kind === "items" && sel.ids.includes(item.id);
10283
10363
  const onGrip = useItemDrag(item, scale, setDrag);
10364
+ const keys = useItemKeys(item);
10284
10365
  const r = rectOf(item, drag);
10285
10366
  const widths2 = item.columns.map((c, i2) => drag?.mode === "col" && drag.id === item.id && drag.col === i2 ? drag.w : c.width);
10286
- const [dropCell, setDropCell] = (0, import_react7.useState)(null);
10287
- const [menu, setMenu] = (0, import_react7.useState)(null);
10288
- const problems = (0, import_react7.useContext)(IssueMap).get(item.id);
10289
- const tblRef = (0, import_react7.useRef)(null);
10367
+ const [dropCell, setDropCell] = (0, import_react8.useState)(null);
10368
+ const [menu, setMenu] = (0, import_react8.useState)(null);
10369
+ const problems = (0, import_react8.useContext)(IssueMap).get(item.id);
10370
+ const tblRef = (0, import_react8.useRef)(null);
10290
10371
  const chosen = sel.kind === "cell" && sel.id === item.id ? selCells(sel) : [];
10291
- (0, import_react7.useEffect)(() => {
10372
+ (0, import_react8.useEffect)(() => {
10292
10373
  if (!menu) return void 0;
10293
10374
  const close = (e) => {
10294
- if (e.type === "keydown" ? e.key === "Escape" : !e.target.closest?.(".cell-menu")) setMenu(null);
10375
+ if (e.type === "keydown" ? e.key === "Escape" : !e.composedPath().some((n) => n.classList?.contains("cell-menu"))) setMenu(null);
10295
10376
  };
10296
10377
  window.addEventListener("pointerdown", close, true);
10297
10378
  window.addEventListener("keydown", close);
@@ -10304,6 +10385,7 @@ function TableView({ item, scale, drag, setDrag }) {
10304
10385
  e.stopPropagation();
10305
10386
  if (e.button !== 0) return;
10306
10387
  e.preventDefault();
10388
+ e.currentTarget.closest("[data-item-key]")?.focus({ preventScroll: true });
10307
10389
  const st = useDesigner.getState();
10308
10390
  const here = { part, row: ri, col: ci };
10309
10391
  const cur2 = st.sel.kind === "cell" && st.sel.id === item.id ? st.sel : null;
@@ -10379,7 +10461,7 @@ function TableView({ item, scale, drag, setDrag }) {
10379
10461
  const h = t3.header?.[t3.header.length - 1]?.cells?.[ci];
10380
10462
  if (h && (!h.value || /^Column \d+$/.test(h.value))) h.value = f.field.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^./, (c) => c.toUpperCase());
10381
10463
  if (h && f.type === "number") h.style = { ...h.style || {}, textAlign: "right" };
10382
- } else if ((part === "footer" || /^g\d+f$/.test(part)) && f.type === "number") {
10464
+ } else if ((part === "footer" || /^g\d+[hf]$/.test(part)) && f.type === "number") {
10383
10465
  cell.value = `=Sum(Fields.${f.field})`;
10384
10466
  cell.style = { ...cell.style || {}, ...fieldStyle(f) };
10385
10467
  } else cell.value = `=Fields.${f.field}`;
@@ -10387,7 +10469,7 @@ function TableView({ item, scale, drag, setDrag }) {
10387
10469
  useDesigner.getState().select({ kind: "cell", id: item.id, part, row: ri, col: ci });
10388
10470
  };
10389
10471
  let first = true;
10390
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: tblRef, className: `tbl${tableSelected ? " sel" : ""}${problems ? " issue" : ""}`, "data-item": item.name, style: { left: r.x * scale, top: r.y * scale }, children: [
10472
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: tblRef, className: `tbl${tableSelected ? " sel" : ""}${problems ? " issue" : ""}`, "data-item": item.name, style: { left: r.x * scale, top: r.y * scale }, ...keys, children: [
10391
10473
  problems && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "issue-tag", title: problems.join("\n"), "aria-label": problems.join(". "), children: "!" }),
10392
10474
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "grip", title: "Select or move the table", onPointerDown: onGrip, children: "⠿" }),
10393
10475
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "col-handles", "aria-label": T("ux_columns"), role: "group", children: widths2.map((w, ci) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
@@ -10517,13 +10599,13 @@ function TableView({ item, scale, drag, setDrag }) {
10517
10599
  }
10518
10600
 
10519
10601
  // src/designer/Inspector.jsx
10520
- var import_react11 = __toESM(require_react(), 1);
10602
+ var import_react12 = __toESM(require_react(), 1);
10521
10603
 
10522
10604
  // src/designer/ExpressionEditor.jsx
10523
- var import_react9 = __toESM(require_react(), 1);
10605
+ var import_react10 = __toESM(require_react(), 1);
10524
10606
 
10525
10607
  // src/designer/ExprCode.jsx
10526
- var import_react8 = __toESM(require_react(), 1);
10608
+ var import_react9 = __toESM(require_react(), 1);
10527
10609
 
10528
10610
  // node_modules/@marijn/find-cluster-break/src/index.js
10529
10611
  var rangeFrom = [];
@@ -12267,8 +12349,8 @@ var StateField = class _StateField {
12267
12349
  way it is initialized. Can be useful when you need to provide a
12268
12350
  non-default starting value for the field.
12269
12351
  */
12270
- init(create2) {
12271
- return [this, initField.of({ field: this, create: create2 })];
12352
+ init(create) {
12353
+ return [this, initField.of({ field: this, create })];
12272
12354
  }
12273
12355
  /**
12274
12356
  State field instances can be used as
@@ -13496,10 +13578,10 @@ var RangeSet = class _RangeSet {
13496
13578
  for (; ; ) {
13497
13579
  let curTo = Math.min(cursor.to, to);
13498
13580
  if (cursor.point) {
13499
- let active = cursor.activeForPoint(cursor.to);
13500
- let openCount = cursor.pointFrom < from ? active.length + 1 : cursor.point.startSide < 0 ? active.length : Math.min(active.length, openRanges);
13501
- iterator.point(pos, curTo, cursor.point, active, openCount, cursor.pointRank);
13502
- openRanges = Math.min(cursor.openEnd(curTo), active.length);
13581
+ let active2 = cursor.activeForPoint(cursor.to);
13582
+ let openCount = cursor.pointFrom < from ? active2.length + 1 : cursor.point.startSide < 0 ? active2.length : Math.min(active2.length, openRanges);
13583
+ iterator.point(pos, curTo, cursor.point, active2, openCount, cursor.pointRank);
13584
+ openRanges = Math.min(cursor.openEnd(curTo), active2.length);
13503
13585
  } else if (curTo > pos) {
13504
13586
  iterator.span(pos, curTo, cursor.active, openRanges);
13505
13587
  openRanges = cursor.openEnd(curTo);
@@ -13913,14 +13995,14 @@ var SpanCursor = class {
13913
13995
  activeForPoint(to) {
13914
13996
  if (!this.active.length)
13915
13997
  return this.active;
13916
- let active = [];
13998
+ let active2 = [];
13917
13999
  for (let i2 = this.active.length - 1; i2 >= 0; i2--) {
13918
14000
  if (this.activeRank[i2] < this.pointRank)
13919
14001
  break;
13920
14002
  if (this.activeTo[i2] > to || this.activeTo[i2] == to && this.active[i2].endSide >= this.point.endSide)
13921
- active.push(this.active[i2]);
14003
+ active2.push(this.active[i2]);
13922
14004
  }
13923
- return active.reverse();
14005
+ return active2.reverse();
13924
14006
  }
13925
14007
  openEnd(to) {
13926
14008
  let open = 0;
@@ -15439,9 +15521,9 @@ var viewPlugin = /* @__PURE__ */ Facet.define({
15439
15521
  }
15440
15522
  });
15441
15523
  var ViewPlugin = class _ViewPlugin {
15442
- constructor(id, create2, domEventHandlers, domEventObservers, buildExtensions) {
15524
+ constructor(id, create, domEventHandlers, domEventObservers, buildExtensions) {
15443
15525
  this.id = id;
15444
- this.create = create2;
15526
+ this.create = create;
15445
15527
  this.domEventHandlers = domEventHandlers;
15446
15528
  this.domEventObservers = domEventObservers;
15447
15529
  this.baseExtensions = buildExtensions(this);
@@ -15457,9 +15539,9 @@ var ViewPlugin = class _ViewPlugin {
15457
15539
  Define a plugin from a constructor function that creates the
15458
15540
  plugin's value, given an editor view.
15459
15541
  */
15460
- static define(create2, spec) {
15542
+ static define(create, spec) {
15461
15543
  const { eventHandlers, eventObservers, provide, decorations: deco } = spec || {};
15462
- return new _ViewPlugin(nextPluginID++, create2, eventHandlers, eventObservers, (plugin) => {
15544
+ return new _ViewPlugin(nextPluginID++, create, eventHandlers, eventObservers, (plugin) => {
15463
15545
  let ext = [];
15464
15546
  if (deco)
15465
15547
  ext.push(decorations.of((view) => {
@@ -15547,11 +15629,11 @@ function getIsolatedRanges(view, line2) {
15547
15629
  RangeSet.spans(sets, line2.from, line2.to, {
15548
15630
  point() {
15549
15631
  },
15550
- span(fromDoc, toDoc, active, open) {
15632
+ span(fromDoc, toDoc, active2, open) {
15551
15633
  let from = fromDoc - line2.from, to = toDoc - line2.from;
15552
15634
  let level = result;
15553
- for (let i2 = active.length - 1; i2 >= 0; i2--, open--) {
15554
- let direction = active[i2].spec.bidiIsolate, update;
15635
+ for (let i2 = active2.length - 1; i2 >= 0; i2--, open--) {
15636
+ let direction = active2[i2].spec.bidiIsolate, update;
15555
15637
  if (direction == null)
15556
15638
  direction = autoDirection(line2.text, from, to);
15557
15639
  if (open > 0 && level.length && (update = level[level.length - 1]).to == from && update.direction == direction) {
@@ -16781,7 +16863,7 @@ var TileUpdate = class {
16781
16863
  let pendingLineAttrs = null;
16782
16864
  let b = this.builder, markCount = -1;
16783
16865
  let openEnd = RangeSet.spans(this.decorations, from, to, {
16784
- point: (from2, to2, deco, active, openStart, index) => {
16866
+ point: (from2, to2, deco, active2, openStart, index) => {
16785
16867
  if (deco instanceof PointDecoration) {
16786
16868
  if (this.disallowBlockEffectsFor[index]) {
16787
16869
  if (deco.block)
@@ -16789,8 +16871,8 @@ var TileUpdate = class {
16789
16871
  if (to2 > this.view.state.doc.lineAt(from2).to)
16790
16872
  throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
16791
16873
  }
16792
- markCount = active.length;
16793
- if (openStart > active.length) {
16874
+ markCount = active2.length;
16875
+ if (openStart > active2.length) {
16794
16876
  b.continueWidget(to2 - from2);
16795
16877
  } else {
16796
16878
  let widget = deco.widget || (deco.block ? NullWidget.block : NullWidget.inline);
@@ -16802,7 +16884,7 @@ var TileUpdate = class {
16802
16884
  b.addBlockWidget(tile);
16803
16885
  } else {
16804
16886
  b.ensureLine(pendingLineAttrs);
16805
- b.addInlineWidget(tile, active, openStart);
16887
+ b.addInlineWidget(tile, active2, openStart);
16806
16888
  }
16807
16889
  }
16808
16890
  pendingLineAttrs = null;
@@ -16812,7 +16894,7 @@ var TileUpdate = class {
16812
16894
  if (to2 > from2)
16813
16895
  this.text.skip(to2 - from2);
16814
16896
  },
16815
- span: (from2, to2, active, openStart) => {
16897
+ span: (from2, to2, active2, openStart) => {
16816
16898
  for (let pos = from2; pos < to2; ) {
16817
16899
  let chars = this.text.next(Math.min(512, to2 - pos));
16818
16900
  if (chars == null) {
@@ -16821,12 +16903,12 @@ var TileUpdate = class {
16821
16903
  pos++;
16822
16904
  } else {
16823
16905
  b.ensureLine(pendingLineAttrs);
16824
- b.addText(chars, active, pos == from2 ? openStart : active.length);
16906
+ b.addText(chars, active2, pos == from2 ? openStart : active2.length);
16825
16907
  pos += chars.length;
16826
16908
  }
16827
16909
  pendingLineAttrs = null;
16828
16910
  }
16829
- markCount = active.length;
16911
+ markCount = active2.length;
16830
16912
  }
16831
16913
  });
16832
16914
  if (markCount > -1)
@@ -18815,9 +18897,9 @@ handlers.mousedown = (view, event) => {
18815
18897
  if (mustFocus)
18816
18898
  view.observer.ignore(() => {
18817
18899
  focusPreventScroll(view.contentDOM);
18818
- let active = view.root.activeElement;
18819
- if (active && !active.contains(view.contentDOM))
18820
- active.blur();
18900
+ let active2 = view.root.activeElement;
18901
+ if (active2 && !active2.contains(view.contentDOM))
18902
+ active2.blur();
18821
18903
  });
18822
18904
  let mouseSel = view.inputState.mouseSelection;
18823
18905
  if (mouseSel) {
@@ -28860,7 +28942,7 @@ function scrollIntoView2(container2, element) {
28860
28942
  function score(option) {
28861
28943
  return (option.boost || 0) * 100 + (option.apply ? 10 : 0) + (option.info ? 5 : 0) + (option.type ? 1 : 0);
28862
28944
  }
28863
- function sortOptions(active, state) {
28945
+ function sortOptions(active2, state) {
28864
28946
  let options = [];
28865
28947
  let sections = null, dynamicSectionScore = null;
28866
28948
  let addOption = (option) => {
@@ -28875,7 +28957,7 @@ function sortOptions(active, state) {
28875
28957
  }
28876
28958
  };
28877
28959
  let conf = state.facet(completionConfig);
28878
- for (let a of active)
28960
+ for (let a of active2)
28879
28961
  if (a.hasResult()) {
28880
28962
  let getMatch = a.result.getMatch;
28881
28963
  if (a.result.filter === false) {
@@ -28938,12 +29020,12 @@ var CompletionDialog = class _CompletionDialog {
28938
29020
  setSelected(selected, id) {
28939
29021
  return selected == this.selected || selected >= this.options.length ? this : new _CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected, this.disabled);
28940
29022
  }
28941
- static build(active, state, id, prev, conf, didSetActive) {
28942
- if (prev && !didSetActive && active.some((s) => s.isPending))
29023
+ static build(active2, state, id, prev, conf, didSetActive) {
29024
+ if (prev && !didSetActive && active2.some((s) => s.isPending))
28943
29025
  return prev.setDisabled();
28944
- let options = sortOptions(active, state);
29026
+ let options = sortOptions(active2, state);
28945
29027
  if (!options.length)
28946
- return prev && active.some((a) => a.isPending) ? prev.setDisabled() : null;
29028
+ return prev && active2.some((a) => a.isPending) ? prev.setDisabled() : null;
28947
29029
  let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1;
28948
29030
  if (prev && prev.selected != selected && prev.selected != -1) {
28949
29031
  let selectedValue = prev.options[prev.selected].completion;
@@ -28954,7 +29036,7 @@ var CompletionDialog = class _CompletionDialog {
28954
29036
  }
28955
29037
  }
28956
29038
  return new _CompletionDialog(options, makeAttrs(id, selected), {
28957
- pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
29039
+ pos: active2.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
28958
29040
  create: createTooltip,
28959
29041
  above: conf.aboveCursor
28960
29042
  }, prev ? prev.timestamp : Date.now(), selected, false);
@@ -28967,8 +29049,8 @@ var CompletionDialog = class _CompletionDialog {
28967
29049
  }
28968
29050
  };
28969
29051
  var CompletionState = class _CompletionState {
28970
- constructor(active, id, open) {
28971
- this.active = active;
29052
+ constructor(active2, id, open) {
29053
+ this.active = active2;
28972
29054
  this.id = id;
28973
29055
  this.open = open;
28974
29056
  }
@@ -28978,7 +29060,7 @@ var CompletionState = class _CompletionState {
28978
29060
  update(tr) {
28979
29061
  let { state } = tr, conf = state.facet(completionConfig);
28980
29062
  let sources = conf.override || state.languageDataAt("autocomplete", cur(state)).map(asSource);
28981
- let active = sources.map((source) => {
29063
+ let active2 = sources.map((source) => {
28982
29064
  let value = this.active.find((s) => s.source == source) || new ActiveSource(
28983
29065
  source,
28984
29066
  this.active.some(
@@ -28989,17 +29071,17 @@ var CompletionState = class _CompletionState {
28989
29071
  );
28990
29072
  return value.update(tr, conf);
28991
29073
  });
28992
- if (active.length == this.active.length && active.every((a, i2) => a == this.active[i2]))
28993
- active = this.active;
29074
+ if (active2.length == this.active.length && active2.every((a, i2) => a == this.active[i2]))
29075
+ active2 = this.active;
28994
29076
  let open = this.open, didSet = tr.effects.some((e) => e.is(setActiveEffect));
28995
29077
  if (open && tr.docChanged)
28996
29078
  open = open.map(tr.changes);
28997
- if (tr.selection || active.some((a) => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) || !sameResults(active, this.active) || didSet)
28998
- open = CompletionDialog.build(active, state, this.id, open, conf, didSet);
28999
- else if (open && open.disabled && !active.some((a) => a.isPending))
29079
+ if (tr.selection || active2.some((a) => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) || !sameResults(active2, this.active) || didSet)
29080
+ open = CompletionDialog.build(active2, state, this.id, open, conf, didSet);
29081
+ else if (open && open.disabled && !active2.some((a) => a.isPending))
29000
29082
  open = null;
29001
- if (!open && active.every((a) => !a.isPending) && active.some((a) => a.hasResult()))
29002
- active = active.map((a) => a.hasResult() ? new ActiveSource(
29083
+ if (!open && active2.every((a) => !a.isPending) && active2.some((a) => a.hasResult()))
29084
+ active2 = active2.map((a) => a.hasResult() ? new ActiveSource(
29003
29085
  a.source,
29004
29086
  0
29005
29087
  /* State.Inactive */
@@ -29007,7 +29089,7 @@ var CompletionState = class _CompletionState {
29007
29089
  for (let effect of tr.effects)
29008
29090
  if (effect.is(setSelectedEffect))
29009
29091
  open = open && open.setSelected(effect.value, this.id);
29010
- return active == this.active && open == this.open ? this : new _CompletionState(active, this.id, open);
29092
+ return active2 == this.active && open == this.open ? this : new _CompletionState(active2, this.id, open);
29011
29093
  }
29012
29094
  get tooltip() {
29013
29095
  return this.open ? this.open.tooltip : null;
@@ -29092,9 +29174,9 @@ var ActiveSource = class _ActiveSource {
29092
29174
  /* State.Inactive */
29093
29175
  );
29094
29176
  else if (effect.is(setActiveEffect)) {
29095
- for (let active of effect.value)
29096
- if (active.source == value.source)
29097
- value = active;
29177
+ for (let active2 of effect.value)
29178
+ if (active2.source == value.source)
29179
+ value = active2;
29098
29180
  }
29099
29181
  }
29100
29182
  return value;
@@ -29238,8 +29320,8 @@ var closeCompletion = (view) => {
29238
29320
  return true;
29239
29321
  };
29240
29322
  var RunningQuery = class {
29241
- constructor(active, context) {
29242
- this.active = active;
29323
+ constructor(active2, context) {
29324
+ this.active = active2;
29243
29325
  this.context = context;
29244
29326
  this.time = Date.now();
29245
29327
  this.updates = [];
@@ -29256,9 +29338,9 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29256
29338
  this.debounceAccept = -1;
29257
29339
  this.pendingStart = false;
29258
29340
  this.composing = 0;
29259
- for (let active of view.state.field(completionState).active)
29260
- if (active.isPending)
29261
- this.startQuery(active);
29341
+ for (let active2 of view.state.field(completionState).active)
29342
+ if (active2.isPending)
29343
+ this.startQuery(active2);
29262
29344
  }
29263
29345
  update(update) {
29264
29346
  let cState = update.state.field(completionState);
@@ -29303,19 +29385,19 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29303
29385
  this.debounceUpdate = -1;
29304
29386
  this.pendingStart = false;
29305
29387
  let { state } = this.view, cState = state.field(completionState);
29306
- for (let active of cState.active) {
29307
- if (active.isPending && !this.running.some((r) => r.active.source == active.source))
29308
- this.startQuery(active);
29388
+ for (let active2 of cState.active) {
29389
+ if (active2.isPending && !this.running.some((r) => r.active.source == active2.source))
29390
+ this.startQuery(active2);
29309
29391
  }
29310
29392
  if (this.running.length && cState.open && cState.open.disabled)
29311
29393
  this.debounceAccept = setTimeout(() => this.accept(), this.view.state.facet(completionConfig).updateSyncTime);
29312
29394
  }
29313
- startQuery(active) {
29395
+ startQuery(active2) {
29314
29396
  let { state } = this.view, pos = cur(state);
29315
- let context = new CompletionContext(state, pos, active.explicit, this.view);
29316
- let pending2 = new RunningQuery(active, context);
29397
+ let context = new CompletionContext(state, pos, active2.explicit, this.view);
29398
+ let pending2 = new RunningQuery(active2, context);
29317
29399
  this.running.push(pending2);
29318
- Promise.resolve(active.source(context)).then((result) => {
29400
+ Promise.resolve(active2.source(context)).then((result) => {
29319
29401
  if (!pending2.context.aborted) {
29320
29402
  pending2.done = result || null;
29321
29403
  this.scheduleAccept();
@@ -29348,26 +29430,26 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29348
29430
  if (query.done) {
29349
29431
  let pos = cur(query.updates.length ? query.updates[0].startState : this.view.state);
29350
29432
  let limit = Math.min(pos, query.done.from + (query.active.explicit ? 0 : 1));
29351
- let active = new ActiveResult(query.active.source, query.active.explicit, limit, query.done, query.done.from, (_a2 = query.done.to) !== null && _a2 !== void 0 ? _a2 : pos);
29433
+ let active2 = new ActiveResult(query.active.source, query.active.explicit, limit, query.done, query.done.from, (_a2 = query.done.to) !== null && _a2 !== void 0 ? _a2 : pos);
29352
29434
  for (let tr of query.updates)
29353
- active = active.update(tr, conf);
29354
- if (active.hasResult()) {
29355
- updated.push(active);
29435
+ active2 = active2.update(tr, conf);
29436
+ if (active2.hasResult()) {
29437
+ updated.push(active2);
29356
29438
  continue;
29357
29439
  }
29358
29440
  }
29359
29441
  let current2 = cState.active.find((a) => a.source == query.active.source);
29360
29442
  if (current2 && current2.isPending) {
29361
29443
  if (query.done == null) {
29362
- let active = new ActiveSource(
29444
+ let active2 = new ActiveSource(
29363
29445
  query.active.source,
29364
29446
  0
29365
29447
  /* State.Inactive */
29366
29448
  );
29367
29449
  for (let tr of query.updates)
29368
- active = active.update(tr, conf);
29369
- if (!active.isPending)
29370
- updated.push(active);
29450
+ active2 = active2.update(tr, conf);
29451
+ if (!active2.isPending)
29452
+ updated.push(active2);
29371
29453
  } else {
29372
29454
  this.startQuery(current2);
29373
29455
  }
@@ -29824,12 +29906,12 @@ var theme2 = EditorView.theme({
29824
29906
  "&.cm-focused .cm-selectionBackground, .cm-selectionBackground": { background: "var(--accent-soft)" }
29825
29907
  });
29826
29908
  var UNKNOWN = Decoration.mark({ class: "cm-unknown-field" });
29827
- var ExprCode = (0, import_react8.forwardRef)(function ExprCode2({ value, onChange, fields, parameters, invalid, check }, ref) {
29828
- const host = (0, import_react8.useRef)(null);
29829
- const view = (0, import_react8.useRef)(null);
29830
- const latest2 = (0, import_react8.useRef)({ onChange, fields, parameters, check });
29909
+ var ExprCode = (0, import_react9.forwardRef)(function ExprCode2({ value, onChange, fields, parameters, invalid, check }, ref) {
29910
+ const host = (0, import_react9.useRef)(null);
29911
+ const view = (0, import_react9.useRef)(null);
29912
+ const latest2 = (0, import_react9.useRef)({ onChange, fields, parameters, check });
29831
29913
  latest2.current = { onChange, fields, parameters, check };
29832
- (0, import_react8.useImperativeHandle)(ref, () => ({
29914
+ (0, import_react9.useImperativeHandle)(ref, () => ({
29833
29915
  insert(text) {
29834
29916
  const v = view.current;
29835
29917
  if (!v) return;
@@ -29843,7 +29925,7 @@ var ExprCode = (0, import_react8.forwardRef)(function ExprCode2({ value, onChang
29843
29925
  view.current?.focus();
29844
29926
  }
29845
29927
  }));
29846
- (0, import_react8.useEffect)(() => {
29928
+ (0, import_react9.useEffect)(() => {
29847
29929
  const complete = (ctx) => {
29848
29930
  const m = ctx.matchBefore(/(Fields|Parameters|Globals)\.\w*$/);
29849
29931
  if (m) {
@@ -29932,8 +30014,8 @@ var SNIPPETS = {
29932
30014
  function ExpressionEditor({ value, dataSet, onSave, onClose, title }) {
29933
30015
  const def = useDesigner((s) => s.def);
29934
30016
  const sample = useDesigner((s) => s.sample);
29935
- const [text, setText] = (0, import_react9.useState)(value ?? "");
29936
- const ta = (0, import_react9.useRef)(null);
30017
+ const [text, setText] = (0, import_react10.useState)(value ?? "");
30018
+ const ta = (0, import_react10.useRef)(null);
29937
30019
  const dsName = dataSet || def.dataSets?.[0]?.name;
29938
30020
  const ds = def.dataSets?.find((d) => d.name === dsName);
29939
30021
  const fields = fieldNames(ds).filter((n) => !(ds?.fields || []).some((f) => f.name === n && f.type === "object"));
@@ -29943,7 +30025,7 @@ function ExpressionEditor({ value, dataSet, onSave, onClose, title }) {
29943
30025
  const insert2 = (s) => ta.current?.insert(s);
29944
30026
  const err = checkValue(text);
29945
30027
  const issues = err ? [] : check(text);
29946
- const preview = (0, import_react9.useMemo)(() => {
30028
+ const preview = (0, import_react10.useMemo)(() => {
29947
30029
  if (err || !sample?.dataSets) return null;
29948
30030
  const rows = sample.dataSets[dsName] || [];
29949
30031
  const params = Object.fromEntries((def.parameters || []).map((p) => [p.name, p.default ?? null]));
@@ -30016,7 +30098,7 @@ function ExpressionEditor({ value, dataSet, onSave, onClose, title }) {
30016
30098
  }
30017
30099
 
30018
30100
  // src/designer/CondFormat.jsx
30019
- var import_react10 = __toESM(require_react(), 1);
30101
+ var import_react11 = __toESM(require_react(), 1);
30020
30102
 
30021
30103
  // src/designer/cfRules.js
30022
30104
  var CF_OPS = ["eq", "ne", "lt", "le", "gt", "ge", "between", "top", "bottom", "aboveAvg", "belowAvg", "contains", "startsWith", "empty", "notEmpty"];
@@ -30136,7 +30218,7 @@ function CondFormat({ title, cf: start, fields, thisValue, kind, custom, onApply
30136
30218
  const lang2 = useDesigner((s) => s.lang);
30137
30219
  const T = (k, v) => t(lang2, k, v);
30138
30220
  const blank = () => ({ field: thisValue ? void 0 : fields[0], op: "gt", value: "", format: kind === "chart" ? { backgroundColor: "#dc2626" } : { color: "#b42318", fontWeight: "bold" } });
30139
- const [cf, setCf] = (0, import_react10.useState)(() => JSON.parse(JSON.stringify(start || { mode: "first", rules: [blank()] })));
30221
+ const [cf, setCf] = (0, import_react11.useState)(() => JSON.parse(JSON.stringify(start || { mode: "first", rules: [blank()] })));
30140
30222
  const rules = cf.rules || [];
30141
30223
  const setRule = (i2, patch) => setCf((c) => ({ ...c, rules: c.rules.map((r, j) => j === i2 ? { ...r, ...patch } : r) }));
30142
30224
  const setFmt = (i2, k, v) => setCf((c) => ({ ...c, rules: c.rules.map((r, j) => {
@@ -30227,7 +30309,7 @@ var catLabel = (tk, cat) => tk(`cat_${cat}`, cat);
30227
30309
  function Inspector() {
30228
30310
  const sel = useDesigner((s) => s.sel);
30229
30311
  const def = useDesigner((s) => s.def);
30230
- const [expr, setExpr] = (0, import_react11.useState)(null);
30312
+ const [expr, setExpr] = (0, import_react12.useState)(null);
30231
30313
  const openExpr = (cfg) => setExpr(cfg);
30232
30314
  let body;
30233
30315
  if (sel.kind === "items" && sel.ids.length > 1) body = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Multi, { ids: sel.ids });
@@ -30242,13 +30324,13 @@ function Inspector() {
30242
30324
  const one = sel.kind === "items" && sel.ids.length === 1 ? findItem(def, sel.ids[0])?.item : sel.kind === "cell" ? findItem(def, sel.id)?.item : null;
30243
30325
  const scope = one ? one.dataSet || def.dataSets?.[0]?.name || null : void 0;
30244
30326
  const selKey = sel.kind === "items" ? `i:${sel.ids.join(",")}` : sel.kind === "cell" ? `c:${sel.id}:${sel.part}:${sel.row}:${sel.col}:${sel.cells?.length || 0}` : `${sel.kind}:${sel.section || ""}`;
30245
- const ref = (0, import_react11.useRef)(null);
30246
- (0, import_react11.useLayoutEffect)(() => {
30327
+ const ref = (0, import_react12.useRef)(null);
30328
+ (0, import_react12.useLayoutEffect)(() => {
30247
30329
  const pane = ref.current?.closest(".dright");
30248
30330
  if (pane) pane.scrollTop = 0;
30249
30331
  }, [selKey]);
30250
- const [closed, setClosed] = (0, import_react11.useState)(() => /* @__PURE__ */ new Set());
30251
- (0, import_react11.useLayoutEffect)(() => {
30332
+ const [closed, setClosed] = (0, import_react12.useState)(() => /* @__PURE__ */ new Set());
30333
+ (0, import_react12.useLayoutEffect)(() => {
30252
30334
  for (const h of ref.current?.querySelectorAll(".cat > h5") || []) {
30253
30335
  const shut = closed.has(h.textContent);
30254
30336
  h.querySelector("button")?.setAttribute("aria-expanded", String(!shut));
@@ -30267,13 +30349,13 @@ function Inspector() {
30267
30349
  });
30268
30350
  };
30269
30351
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { "data-testid": "inspector", ref, onClick: toggle, children: [
30270
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FieldScope.Provider, { value: scope, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react11.Fragment, { children: body }, selKey) }),
30352
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FieldScope.Provider, { value: scope, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react12.Fragment, { children: body }, selKey) }),
30271
30353
  expr && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ExpressionEditor, { ...expr, onClose: () => setExpr(null) })
30272
30354
  ] });
30273
30355
  }
30274
- function Geo({ label, value, onChange }) {
30356
+ function Geo({ label, value, onChange, min }) {
30275
30357
  const unit = useDesigner((s) => s.unit);
30276
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: `${label} (${unit})`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NumberInput, { value: round(fromPt(value ?? 0, unit) * 100) / 100, step: unit === "pt" ? 1 : unit === "in" ? 0.05 : 0.5, onChange: (v) => onChange(round(toPt(v, unit))) }) });
30358
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: `${label} (${unit})`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NumberInput, { value: round(fromPt(value ?? 0, unit) * 100) / 100, min: min == null ? void 0 : round(fromPt(min, unit) * 100) / 100, step: unit === "pt" ? 1 : unit === "in" ? 0.05 : 0.5, onChange: (v) => onChange(round(toPt(v, unit))) }) });
30277
30359
  }
30278
30360
  function PropEditor({ p: spec, value, onChange, openExpr, dataSet, item }) {
30279
30361
  const T = useT3();
@@ -30338,7 +30420,7 @@ function OverflowTarget({ value, onChange, self }) {
30338
30420
  }
30339
30421
  function ExprOr({ p, value, onChange, openExpr, dataSet, children }) {
30340
30422
  const T = useT3();
30341
- const [on, setOn] = (0, import_react11.useState)(isDynamic(value));
30423
+ const [on, setOn] = (0, import_react12.useState)(isDynamic(value));
30342
30424
  const label = T(on ? "useFixed" : "useExpr");
30343
30425
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: p.label, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "expr-row", children: [
30344
30426
  on ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ExprInput, { value, onChange: (v) => onChange(v || void 0), onOpen: () => openExpr({ value, dataSet, onSave: onChange, title: p.label }), placeholder: "=IIf(Fields.amount < 0, 'bold', 'normal')" }) : children,
@@ -30351,7 +30433,7 @@ function ExprOr({ p, value, onChange, openExpr, dataSet, children }) {
30351
30433
  function PaletteEditor({ label, value, onChange }) {
30352
30434
  const T = useT3();
30353
30435
  const custom = Array.isArray(value);
30354
- const [text, setText] = (0, import_react11.useState)(custom ? value.join(", ") : "");
30436
+ const [text, setText] = (0, import_react12.useState)(custom ? value.join(", ") : "");
30355
30437
  const parse2 = (t3) => t3.split(/[\s,;]+/).map((x) => x.trim()).filter((x) => /^#[0-9a-f]{6}$/i.test(x));
30356
30438
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { display: "grid", gap: 6 }, children: [
30357
30439
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
@@ -30378,17 +30460,18 @@ function PaletteEditor({ label, value, onChange }) {
30378
30460
  custom && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { display: "flex", gap: 3, flexWrap: "wrap" }, "aria-hidden": "true", children: value.map((c, i2) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { width: 14, height: 14, borderRadius: 3, background: c, border: "1px solid var(--line)" } }, i2)) })
30379
30461
  ] });
30380
30462
  }
30381
- var reportList = null;
30463
+ var reportLists = /* @__PURE__ */ new Map();
30382
30464
  function ReportPicker({ value, onChange }) {
30383
- const [list2, setList] = (0, import_react11.useState)(reportList || []);
30384
- const listId = (0, import_react11.useState)(() => `reports-${Math.random().toString(36).slice(2, 8)}`)[0];
30385
- (0, import_react11.useEffect)(() => {
30465
+ const [list2, setList] = (0, import_react12.useState)(() => reportLists.get(useDesigner.getState().embed?.server || "") || []);
30466
+ const listId = (0, import_react12.useState)(() => `reports-${Math.random().toString(36).slice(2, 8)}`)[0];
30467
+ (0, import_react12.useEffect)(() => {
30386
30468
  const embed = useDesigner.getState().embed;
30387
- if (reportList || embed && !embed.server) return;
30388
30469
  const server2 = embed?.server || "";
30470
+ if (reportLists.has(server2) || embed && !embed.server) return;
30389
30471
  fetch(`${server2}/api/reports`).then((r) => r.ok ? r.json() : []).then((l) => {
30390
- reportList = Array.isArray(l) ? l : [];
30391
- setList(reportList);
30472
+ const v = Array.isArray(l) ? l : [];
30473
+ reportLists.set(server2, v);
30474
+ setList(v);
30392
30475
  }).catch(() => {
30393
30476
  });
30394
30477
  }, []);
@@ -30422,8 +30505,8 @@ function ItemProps({ item, section, openExpr }) {
30422
30505
  const tk = useTk();
30423
30506
  const def = useDesigner((s) => s.def);
30424
30507
  const spec = ITEMS[item.type];
30425
- const [nameErr, setNameErr] = (0, import_react11.useState)(null);
30426
- const [find2, setFind] = (0, import_react11.useState)("");
30508
+ const [nameErr, setNameErr] = (0, import_react12.useState)(null);
30509
+ const [find2, setFind] = (0, import_react12.useState)("");
30427
30510
  const q2 = find2.trim().toLowerCase();
30428
30511
  const hit = (p, type) => !q2 || propLabel(tk, p, type).toLowerCase().includes(q2) || p.key.toLowerCase().includes(q2);
30429
30512
  const props = (spec?.props || []).filter((p) => (!p.showIf || p.showIf(item)) && hit(p, item.type));
@@ -30475,8 +30558,8 @@ function ItemProps({ item, section, openExpr }) {
30475
30558
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "grid2", children: [
30476
30559
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Geo, { label: "X", value: item.x, onChange: (v) => setGeo("x", Math.max(0, v)) }),
30477
30560
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Geo, { label: "Y", value: item.y, onChange: (v) => setGeo("y", Math.max(0, v)) }),
30478
- item.type !== "table" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Geo, { label: T("i_width"), value: item.w, onChange: (v) => setGeo("w", Math.max(0, v)) }),
30479
- item.type !== "table" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Geo, { label: T("i_height"), value: item.h, onChange: (v) => setGeo("h", Math.max(0, v)) }),
30561
+ item.type !== "table" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Geo, { label: T("i_width"), value: item.w, min: item.type === "line" ? 0 : 1, onChange: (v) => setGeo("w", Math.max(0, v)) }),
30562
+ item.type !== "table" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Geo, { label: T("i_height"), value: item.h, min: item.type === "line" ? 0 : 1, onChange: (v) => setGeo("h", Math.max(0, v)) }),
30480
30563
  item.type === "table" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("tableSize"), hint: T("tableSizeHint"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TextInput, { value: `${round(item.w)} × ${round(item.h)} pt`, readOnly: true, "data-testid": "table-size" }) })
30481
30564
  ] }),
30482
30565
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "hint", children: (() => {
@@ -30567,7 +30650,7 @@ function PivotEditor({ item, openExpr }) {
30567
30650
  const def = useDesigner((s) => s.def);
30568
30651
  const fields = fieldsOf2(def, item.dataSet);
30569
30652
  const spec = normalizeMatrix(item);
30570
- const [pick, setPick] = (0, import_react11.useState)({ rowGroups: "", columnGroups: "", values: "" });
30653
+ const [pick, setPick] = (0, import_react12.useState)({ rowGroups: "", columnGroups: "", values: "" });
30571
30654
  const edit = (fn3, key2) => updateItem(item.id, (it) => {
30572
30655
  if (!isTablix(it)) {
30573
30656
  const n = normalizeMatrix(it);
@@ -30646,7 +30729,17 @@ function PivotEditor({ item, openExpr }) {
30646
30729
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("groupExpandLevels"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NumberInput, { value: g.expandLevels ?? "", step: 1, onChange: (v) => setK(list2, i2, "expandLevels", Number.isFinite(v) && v >= 0 ? Math.round(v) : void 0) }) })
30647
30730
  ] })
30648
30731
  ] }),
30649
- (i2 < spec[list2].length - 1 || list2 === "rowGroups" && g.parent) && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Check, { label: T("pivotCollapsible"), checked: g.collapsible, onChange: (v) => setK(list2, i2, "collapsible", v) }),
30732
+ (i2 < spec[list2].length - 1 || list2 === "rowGroups" && g.parent) && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Check, { label: T("pivotCollapsible"), checked: g.collapsible, onChange: (v) => edit((it) => {
30733
+ const o = it[list2][i2];
30734
+ if (v) {
30735
+ o.collapsible = true;
30736
+ o.initiallyCollapsed = true;
30737
+ } else {
30738
+ delete o.collapsible;
30739
+ delete o.initiallyCollapsed;
30740
+ }
30741
+ }, `${item.id}.${list2}${i2}.collapsible`) }),
30742
+ " ",
30650
30743
  g.collapsible && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Check, { label: T("pivotStartCollapsed"), checked: g.initiallyCollapsed, onChange: (v) => setK(list2, i2, "initiallyCollapsed", v) }),
30651
30744
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { "data-testid": `pivot-${list2}${i2}-action`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ActionEditor, { label: T("ux_headerAction"), value: g.action, onChange: (v) => setK(list2, i2, "action", v), openExpr, dataSet: item.dataSet }) }),
30652
30745
  g.total && g.total !== "none" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { "data-testid": `pivot-${list2}${i2}-total-action`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ActionEditor, { label: T("ux_totalAction"), value: g.totalAction, onChange: (v) => setK(list2, i2, "totalAction", v), openExpr, dataSet: item.dataSet }) })
@@ -30672,7 +30765,7 @@ function PivotEditor({ item, openExpr }) {
30672
30765
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "grid2", children: [
30673
30766
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("pivotLabel"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TextInput, { value: v.label || "", onChange: (x) => setK("values", i2, "label", x) }) }),
30674
30767
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("pivotFormat"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TextInput, { value: v.format || "", onChange: (x) => setK("values", i2, "format", x), placeholder: "N0" }) }),
30675
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("pivotShow"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Select, { value: v.show || "value", options: shows, onChange: (x) => setK("values", i2, "show", x === "value" ? void 0 : x) }) })
30768
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("pivotShow"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Select, { value: v.show || "value", options: shows, onChange: (x) => edit((it) => setMatrixShow(it.values[i2], x), `${item.id}.values${i2}.show`) }) })
30676
30769
  ] }),
30677
30770
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { "data-testid": `pivot-values${i2}-action`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ActionEditor, { label: T("ux_cellAction"), value: v.action, onChange: (x) => setK("values", i2, "action", x), openExpr, dataSet: item.dataSet }) }),
30678
30771
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("cellBookmark"), children: exprField("values", i2, "bookmark", v.bookmark, T("cellBookmark")) })
@@ -30714,8 +30807,8 @@ function GroupsEditor({ table: table2, openExpr }) {
30714
30807
  const T = useT3();
30715
30808
  const def = useDesigner((s) => s.def);
30716
30809
  const fields = fieldsOf2(def, table2.dataSet);
30717
- const [pick, setPick] = (0, import_react11.useState)("");
30718
- const [drill, setDrill] = (0, import_react11.useState)(false);
30810
+ const [pick, setPick] = (0, import_react12.useState)("");
30811
+ const [drill, setDrill] = (0, import_react12.useState)(false);
30719
30812
  const setG = (i2, k, v) => updateItem(table2.id, (t3) => {
30720
30813
  if (v === void 0 || v === "" || v === false) delete t3.groups[i2][k];
30721
30814
  else t3.groups[i2][k] = v;
@@ -30957,7 +31050,7 @@ rimary" ? void 0 : v), "aria-label": `${T("overlayAxis")} ${i2 + 1}` }) }),
30957
31050
  }
30958
31051
  function CfButton({ label, title, target, at: at2, kind, fields, apply: apply2, testid }) {
30959
31052
  const T = useT3();
30960
- const [open, setOpen] = (0, import_react11.useState)(false);
31053
+ const [open, setOpen] = (0, import_react12.useState)(false);
30961
31054
  const n = target?.cf?.rules?.length || 0;
30962
31055
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
30963
31056
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("button", { type: "button", className: "btn sm", onClick: () => setOpen(true), "data-testid": testid, children: [
@@ -31024,14 +31117,16 @@ function VisualEditor({ cell, setCell, openExpr, dataSet }) {
31024
31117
  }
31025
31118
  var reportParams = /* @__PURE__ */ new Map();
31026
31119
  function useReportParams(id) {
31027
- const [list2, setList] = (0, import_react11.useState)(() => reportParams.get(id) ?? null);
31028
- (0, import_react11.useEffect)(() => {
31120
+ const srv = () => useDesigner.getState().embed?.server || "";
31121
+ const [list2, setList] = (0, import_react12.useState)(() => reportParams.get(`${srv()} ${id}`) ?? null);
31122
+ (0, import_react12.useEffect)(() => {
31029
31123
  if (!id || isDynamic(id)) {
31030
31124
  setList(null);
31031
31125
  return;
31032
31126
  }
31033
- if (reportParams.has(id)) {
31034
- setList(reportParams.get(id));
31127
+ const key2 = `${srv()} ${id}`;
31128
+ if (reportParams.has(key2)) {
31129
+ setList(reportParams.get(key2));
31035
31130
  return;
31036
31131
  }
31037
31132
  let alive = true;
@@ -31044,7 +31139,7 @@ function useReportParams(id) {
31044
31139
  fetch(`${server2}/api/reports/${encodeURIComponent(id)}`).then((r) => r.ok ? r.json() : null).then((r) => {
31045
31140
  const d = r?.definition || r;
31046
31141
  const ps = d && typeof d === "object" ? (d.parameters || []).map((p) => ({ name: p.name, required: !!p.required && p.default == null, prompt: p.prompt })) : null;
31047
- if (ps) reportParams.set(id, ps);
31142
+ if (ps) reportParams.set(key2, ps);
31048
31143
  if (alive) setList(ps);
31049
31144
  }).catch(() => {
31050
31145
  if (alive) setList(null);
@@ -31058,7 +31153,7 @@ function useReportParams(id) {
31058
31153
  function ParamMap({ value, onChange, known, openExpr, dataSet, testid }) {
31059
31154
  const T = useT3();
31060
31155
  const map = value || {};
31061
- const [extra, setExtra] = (0, import_react11.useState)("");
31156
+ const [extra, setExtra] = (0, import_react12.useState)("");
31062
31157
  const knownNames = new Set((known || []).map((p) => p.name));
31063
31158
  const names = [...(known || []).map((p) => p.name), ...Object.keys(map).filter((k) => !knownNames.has(k))];
31064
31159
  const set2 = (k, v, keep) => {
@@ -31477,7 +31572,7 @@ function ReportProps() {
31477
31572
  const T = useT3();
31478
31573
  const def = useDesigner((s) => s.def);
31479
31574
  const families = useFontFamilies();
31480
- const [fontsOpen, setFontsOpen] = (0, import_react11.useState)(false);
31575
+ const [fontsOpen, setFontsOpen] = (0, import_react12.useState)(false);
31481
31576
  const set2 = (fn3, key2) => useDesigner.getState().apply(fn3, key2);
31482
31577
  const m = Array.isArray(def.page?.margins) ? def.page.margins : [36, 36, 36, 36];
31483
31578
  const base2 = def.styles?.base || {};
@@ -31556,7 +31651,7 @@ function ReportProps() {
31556
31651
  function ReportImages() {
31557
31652
  const T = useT3();
31558
31653
  const images = useDesigner((s) => s.def.images) || {};
31559
- const [err, setErr] = (0, import_react11.useState)(null);
31654
+ const [err, setErr] = (0, import_react12.useState)(null);
31560
31655
  const set2 = (fn3) => useDesigner.getState().apply((d) => {
31561
31656
  d.images || (d.images = {});
31562
31657
  fn3(d.images);
@@ -31595,7 +31690,7 @@ function EmbeddedPicker({ item, onPick }) {
31595
31690
  const images = useDesigner((s) => s.def.images) || {};
31596
31691
  const names = Object.keys(images);
31597
31692
  const cur2 = /^embedded:(.+)$/.exec(String(item.src || ""))?.[1];
31598
- const [err, setErr] = (0, import_react11.useState)(null);
31693
+ const [err, setErr] = (0, import_react12.useState)(null);
31599
31694
  const upload = async (files) => {
31600
31695
  setErr(null);
31601
31696
  const r = await uploadImages(files, T);
@@ -31680,7 +31775,7 @@ function NamedStyles() {
31680
31775
  const styleNames = useStyleNames();
31681
31776
  const def = useDesigner((s) => s.def);
31682
31777
  const named = def.styles?.named || {};
31683
- const [newName, setNewName] = (0, import_react11.useState)("");
31778
+ const [newName, setNewName] = (0, import_react12.useState)("");
31684
31779
  const setS = (name2, k, v) => useDesigner.getState().apply((d) => {
31685
31780
  var _a2, _b;
31686
31781
  d.styles || (d.styles = {});
@@ -31715,7 +31810,7 @@ function NamedStyles() {
31715
31810
  }
31716
31811
 
31717
31812
  // src/designer/DataPanel.jsx
31718
- var import_react14 = __toESM(require_react(), 1);
31813
+ var import_react15 = __toESM(require_react(), 1);
31719
31814
 
31720
31815
  // src/designer/explore.js
31721
31816
  var key = (k) => /^[A-Za-z_$][\w$]*$/.test(k) ? `.${k}` : `['${k}']`;
@@ -31751,7 +31846,7 @@ function bestRows(root) {
31751
31846
  }
31752
31847
 
31753
31848
  // src/designer/ODataEditor.jsx
31754
- var import_react12 = __toESM(require_react(), 1);
31849
+ var import_react13 = __toESM(require_react(), 1);
31755
31850
  var import_jsx_runtime11 = __toESM(require_jsx_runtime(), 1);
31756
31851
  var OPS3 = ["eq", "ne", "gt", "ge", "lt", "le", "contains", "startswith", "endswith"];
31757
31852
  var OP_LABEL = { eq: "=", ne: "≠", gt: ">", ge: "≥", lt: "<", le: "≤" };
@@ -31766,7 +31861,7 @@ async function readMetadata(s) {
31766
31861
  return odataMetadata(await res.text());
31767
31862
  }
31768
31863
  function ODataEditor({ s, setS, T }) {
31769
- const [meta2, setMeta] = (0, import_react12.useState)(null);
31864
+ const [meta2, setMeta] = (0, import_react13.useState)(null);
31770
31865
  const sets = meta2?.sets || [];
31771
31866
  const set2 = sets.find((x) => x.name === s.entitySet);
31772
31867
  const props = set2 ? set2.properties : (s.select || []).map((name2) => ({ name: name2, type: s.types?.[name2] || "" }));
@@ -31857,7 +31952,7 @@ function ODataEditor({ s, setS, T }) {
31857
31952
  }
31858
31953
 
31859
31954
  // src/designer/SqlBuilder.jsx
31860
- var import_react13 = __toESM(require_react(), 1);
31955
+ var import_react14 = __toESM(require_react(), 1);
31861
31956
 
31862
31957
  // src/designer/sqlBuild.js
31863
31958
  var FILTER_OPS2 = ["=", "<>", "<", "<=", ">", ">=", "like", "in", "is null", "is not null"];
@@ -31930,8 +32025,8 @@ function normalizeSchema(body) {
31930
32025
  return tables;
31931
32026
  }
31932
32027
  function useSchema(connection) {
31933
- const [st, setSt] = (0, import_react13.useState)(() => schemas.has(connection) ? { tables: schemas.get(connection) } : { loading: !!connection });
31934
- (0, import_react13.useEffect)(() => {
32028
+ const [st, setSt] = (0, import_react14.useState)(() => schemas.has(connection) ? { tables: schemas.get(connection) } : { loading: !!connection });
32029
+ (0, import_react14.useEffect)(() => {
31935
32030
  if (!connection) {
31936
32031
  setSt({});
31937
32032
  return void 0;
@@ -31965,8 +32060,8 @@ function SqlBuilder({ s, setS, T, kind, onManual }) {
31965
32060
  const nb = { ...b, ...patch };
31966
32061
  setS({ ...s, builder: nb, query: buildSql(nb, kind) });
31967
32062
  };
31968
- const [find2, setFind] = (0, import_react13.useState)("");
31969
- const [preview, setPreview] = (0, import_react13.useState)(null);
32063
+ const [find2, setFind] = (0, import_react14.useState)("");
32064
+ const [preview, setPreview] = (0, import_react14.useState)(null);
31970
32065
  const sql = buildSql(b, kind);
31971
32066
  const tableOf2 = (name2) => (schema.tables || []).find((t3) => t3.name === name2);
31972
32067
  const colsOf = (alias) => tableOf2(b.tables.find((t3) => t3.alias === alias)?.name)?.columns || [];
@@ -31995,7 +32090,7 @@ function SqlBuilder({ s, setS, T, kind, onManual }) {
31995
32090
  if (from.t === to.t || b.joins.some((j) => j.from.t === from.t && j.from.c === from.c && j.to.t === to.t && j.to.c === to.c)) return;
31996
32091
  set2({ joins: [...b.joins, { type: "inner", from, to }] });
31997
32092
  };
31998
- const offered = (0, import_react13.useMemo)(() => b.tables.flatMap((t3) => suggestJoins(b, schema.tables, t3.alias)).filter((j, i2, a) => !b.joins.some((x) => x.from.t === j.from.t && x.from.c === j.from.c && x.to.t === j.to.t && x.to.c === j.to.c) && a.findIndex((y) => JSON.stringify(y) === JSON.stringify(j)) === i2), [b, schema.tables]);
32093
+ const offered = (0, import_react14.useMemo)(() => b.tables.flatMap((t3) => suggestJoins(b, schema.tables, t3.alias)).filter((j, i2, a) => !b.joins.some((x) => x.from.t === j.from.t && x.from.c === j.from.c && x.to.t === j.to.t && x.to.c === j.to.c) && a.findIndex((y) => JSON.stringify(y) === JSON.stringify(j)) === i2), [b, schema.tables]);
31999
32094
  const runPreview = async () => {
32000
32095
  setPreview({ loading: true });
32001
32096
  try {
@@ -32158,7 +32253,7 @@ function SqlBuilder({ s, setS, T, kind, onManual }) {
32158
32253
  ] });
32159
32254
  }
32160
32255
  function JoinAdder({ allCols, split, onAdd, T }) {
32161
- const [a, setA] = (0, import_react13.useState)(""), [z, setZ] = (0, import_react13.useState)("");
32256
+ const [a, setA] = (0, import_react14.useState)(""), [z, setZ] = (0, import_react14.useState)("");
32162
32257
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "qb-row", children: [
32163
32258
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Select, { value: a, allowEmpty: true, options: allCols, onChange: (v) => setA(v || ""), "aria-label": T("qb_joinFrom") }),
32164
32259
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: "=" }),
@@ -32175,17 +32270,18 @@ function JoinAdder({ allCols, split, onAdd, T }) {
32175
32270
  var import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
32176
32271
  var NAME2 = /^[A-Za-z_][\w]*$/;
32177
32272
  var noSourceKey = (def) => (def?.dataSources || []).length ? null : "r4_noDataSource";
32178
- async function loadSample() {
32179
- const { def } = useDesigner.getState();
32180
- useDesigner.setState({ sample: { loading: true } });
32273
+ async function loadSample(store) {
32274
+ const api = store?.getState ? store : activeStore();
32275
+ const { def } = api.getState();
32276
+ api.setState({ sample: { loading: true } });
32181
32277
  try {
32182
32278
  const params = resolveParameters(def, {});
32183
32279
  const sources = await loadSources(def, { params, baseUrl: origin(), sqlPreview: true, fetch: reportFetch(origin(), void 0, { sqlPreview: true }) });
32184
32280
  const ctx = { params, globals: { ExecutionTime: /* @__PURE__ */ new Date() }, dataSets: {}, fields: null, locale: def.locale, currency: def.currency, functions: functionTable(def) };
32185
32281
  const dataSets = buildDataSets(def, sources, ctx);
32186
- useDesigner.setState({ sample: { dataSets, sources, at: Date.now() } });
32282
+ api.setState({ sample: { dataSets, sources, at: Date.now() } });
32187
32283
  } catch (e) {
32188
- useDesigner.setState({ sample: { error: e.message } });
32284
+ api.setState({ sample: { error: e.message } });
32189
32285
  }
32190
32286
  }
32191
32287
  function DataPanel() {
@@ -32193,8 +32289,8 @@ function DataPanel() {
32193
32289
  const lang2 = useDesigner((s) => s.lang);
32194
32290
  const T = (k, v) => t(lang2, k, v);
32195
32291
  const sample = useDesigner((s) => s.sample);
32196
- const [dlg, setDlg] = (0, import_react14.useState)(null);
32197
- const [open, setOpen] = (0, import_react14.useState)(() => new Set((def.dataSets || []).map((d) => d.name)));
32292
+ const [dlg, setDlg] = (0, import_react15.useState)(null);
32293
+ const [open, setOpen] = (0, import_react15.useState)(() => new Set((def.dataSets || []).map((d) => d.name)));
32198
32294
  const toggle = (n) => setOpen((s) => {
32199
32295
  const x = new Set(s);
32200
32296
  x.has(n) ? x.delete(n) : x.add(n);
@@ -32343,10 +32439,10 @@ function ParamDialog({ index, onClose }) {
32343
32439
  const lang2 = useDesigner((s) => s.lang);
32344
32440
  const T = (k, v) => t(lang2, k, v);
32345
32441
  const orig = index != null ? def.parameters[index] : null;
32346
- const [p, setP] = (0, import_react14.useState)(orig || { name: "", type: "string", prompt: "", default: "", required: false });
32347
- const [columns, setColumns] = (0, import_react14.useState)(String(def.parameterLayout?.columns || 1));
32348
- const [live, setLive] = (0, import_react14.useState)(def.liveParameters !== false);
32349
- const [choicesText, setChoicesText] = (0, import_react14.useState)(() => (p.options || []).map(optionLine).join("\n"));
32442
+ const [p, setP] = (0, import_react15.useState)(orig || { name: "", type: "string", prompt: "", default: "", required: false });
32443
+ const [columns, setColumns] = (0, import_react15.useState)(String(def.parameterLayout?.columns || 1));
32444
+ const [live, setLive] = (0, import_react15.useState)(def.liveParameters !== false);
32445
+ const [choicesText, setChoicesText] = (0, import_react15.useState)(() => (p.options || []).map(optionLine).join("\n"));
32350
32446
  const fromFields = (def.dataSets?.find((d) => d.name === p.optionsFrom?.dataSet)?.fields || []).map((f) => f.name);
32351
32447
  const labelOpts = [...fromFields.map((f) => ({ value: `=Fields.${f}`, label: f })), ...p.optionsFrom?.label && !fromFields.some((f) => `=Fields.${f}` === p.optionsFrom.label) ? [{ value: p.optionsFrom.label, label: p.optionsFrom.label }] : []];
32352
32448
  const err = !NAME2.test(p.name) ? T("paramNameRule") : !uniqueIn(def.parameters, p.name, index) ? T("paramNameTaken") : p.optionsFrom && !p.optionsFrom.value ? T("ux_paramPickValueField") : null;
@@ -32493,7 +32589,7 @@ function SourceDialog({ index, onClose }) {
32493
32589
  const lang2 = useDesigner((s2) => s2.lang);
32494
32590
  const T = (k, v) => t(lang2, k, v);
32495
32591
  const orig = index != null ? def.dataSources[index] : null;
32496
- const [s, setS] = (0, import_react14.useState)(() => ({
32592
+ const [s, setS] = (0, import_react15.useState)(() => ({
32497
32593
  name: "",
32498
32594
  type: "rest",
32499
32595
  method: "GET",
@@ -32557,11 +32653,11 @@ function SourceDialog({ index, onClose }) {
32557
32653
  if (!err && s.type === "sql" && !s.connection) err = "Pick a connection";
32558
32654
  if (!err && s.type === "sql" && s.procedure != null && !s.procedure) err = "Pick a stored procedure";
32559
32655
  if (!err && s.type === "sql" && s.procedure == null && !/^\s*(select|with)\b/i.test(s.query || "")) err = "Write a SELECT query";
32560
- const [conns, setConns] = (0, import_react14.useState)(null);
32656
+ const [conns, setConns] = (0, import_react15.useState)(null);
32561
32657
  const procs = (conns || []).find((c) => c.name === s.connection)?.procs || [];
32562
32658
  const sqlKind = (conns || []).find((c) => c.name === s.connection)?.kind || "sqlite";
32563
- const [probe, setProbe] = (0, import_react14.useState)(null);
32564
- (0, import_react14.useEffect)(() => {
32659
+ const [probe, setProbe] = (0, import_react15.useState)(null);
32660
+ (0, import_react15.useEffect)(() => {
32565
32661
  if (s.type !== "sql" || conns) return;
32566
32662
  fetch("/api/data/sql/connections").then((r) => r.ok ? r.json() : []).then(setConns).catch(() => setConns([]));
32567
32663
  }, [s.type, conns]);
@@ -32754,13 +32850,13 @@ function DataSetDialog({ index, onClose, onSaved }) {
32754
32850
  const lang2 = useDesigner((s) => s.lang);
32755
32851
  const T = (k, v) => t(lang2, k, v);
32756
32852
  const orig = index != null ? def.dataSets[index] : null;
32757
- const [d, setD] = (0, import_react14.useState)(() => ({ name: "", source: def.dataSources?.[0]?.name, path: "$", fields: [], sort: [], ...orig ? JSON.parse(JSON.stringify(orig)) : {} }));
32758
- const [detect, setDetect] = (0, import_react14.useState)({ state: "idle" });
32759
- const [pathTyped, setPathTyped] = (0, import_react14.useState)(!!orig);
32853
+ const [d, setD] = (0, import_react15.useState)(() => ({ name: "", source: def.dataSources?.[0]?.name, path: "$", fields: [], sort: [], ...orig ? JSON.parse(JSON.stringify(orig)) : {} }));
32854
+ const [detect, setDetect] = (0, import_react15.useState)({ state: "idle" });
32855
+ const [pathTyped, setPathTyped] = (0, import_react15.useState)(!!orig);
32760
32856
  const nested = !!d.relation;
32761
32857
  const parents = (def.dataSets || []).filter((x, i2) => i2 !== index && x.name !== d.name);
32762
32858
  const err = !NAME2.test(d.name) ? T("dsNameRule") : !uniqueIn(def.dataSets, d.name, index) ? T("dsNameTaken") : nested ? !d.relation.parent ? T("dsPickParent") : null : !d.source ? T("dsPickSource") : null;
32763
- const [explore, setExplore] = (0, import_react14.useState)(null);
32859
+ const [explore, setExplore] = (0, import_react15.useState)(null);
32764
32860
  const loadSourceRaw = async (name2) => {
32765
32861
  const params = resolveParameters(useDesigner.getState().def, {});
32766
32862
  const src = useDesigner.getState().def.dataSources.find((s) => s.name === name2);
@@ -33010,7 +33106,7 @@ function DataSetDialog({ index, onClose, onSaved }) {
33010
33106
  }
33011
33107
 
33012
33108
  // src/designer/Outline.jsx
33013
- var import_react15 = __toESM(require_react(), 1);
33109
+ var import_react16 = __toESM(require_react(), 1);
33014
33110
  var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
33015
33111
  var MIME = "application/x-pw-outline";
33016
33112
  function Outline() {
@@ -33019,11 +33115,32 @@ function Outline() {
33019
33115
  const lang2 = useDesigner((s) => s.lang);
33020
33116
  const readOnly2 = useDesigner((s) => s.readOnly);
33021
33117
  const T = (k, v) => t(lang2, k, v);
33022
- const [drop, setDrop] = (0, import_react15.useState)(null);
33023
- const [said, setSaid] = (0, import_react15.useState)("");
33024
- const dragged = (0, import_react15.useRef)(null);
33025
- const body = (0, import_react15.useRef)(null);
33118
+ const [drop, setDrop] = (0, import_react16.useState)(null);
33119
+ const [said, setSaid] = (0, import_react16.useState)("");
33120
+ const [cur2, setCur] = (0, import_react16.useState)(null);
33121
+ const dragged = (0, import_react16.useRef)(null);
33122
+ const body = (0, import_react16.useRef)(null);
33026
33123
  const chosen = new Set(sel.kind === "items" ? sel.ids : sel.kind === "cell" ? [sel.id] : []);
33124
+ const keys = sectionList(def).flatMap(({ key: key2 }) => {
33125
+ const out = [`band:${key2}`];
33126
+ const go = (l) => l.forEach((it) => {
33127
+ out.push(it.id);
33128
+ if (NESTING.has(it.type)) go(it.items || []);
33129
+ });
33130
+ go(secOf(def, key2)?.items || []);
33131
+ return out;
33132
+ });
33133
+ const stop = keys.includes(cur2) ? cur2 : keys.find((k) => chosen.has(k) || sel.kind === "section" && k === `band:${sel.section}`) || keys[0];
33134
+ const roving = (k) => ({ tabIndex: k === stop ? 0 : -1, onFocus: () => setCur(k) });
33135
+ const nav2 = (e) => {
33136
+ if (e.defaultPrevented || e.altKey || e.metaKey || e.ctrlKey || e.target.getAttribute("role") !== "option") return;
33137
+ const all = [...e.currentTarget.querySelectorAll("[role=option]")];
33138
+ const i2 = all.indexOf(e.target);
33139
+ const j = e.key === "ArrowDown" ? i2 + 1 : e.key === "ArrowUp" ? i2 - 1 : e.key === "Home" ? 0 : e.key === "End" ? all.length - 1 : null;
33140
+ if (j == null) return;
33141
+ e.preventDefault();
33142
+ all[Math.max(0, Math.min(all.length - 1, j))]?.focus();
33143
+ };
33027
33144
  const pick = (e, id) => {
33028
33145
  const st = useDesigner.getState();
33029
33146
  if (e.shiftKey && st.sel.kind === "items") {
@@ -33135,30 +33252,32 @@ function Outline() {
33135
33252
  };
33136
33253
  const rows = (list2, parent, depth, section) => list2.map((it, i2) => {
33137
33254
  const mark = drop && drop.id != null && drop.id === it.id ? ` drop-${drop.where}` : "";
33138
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("li", { children: [
33255
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("li", { role: "none", children: [
33139
33256
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: `trow outline-row${chosen.has(it.id) ? " sel" : ""}${mark}`, style: { paddingInlineStart: depth * 14 }, "data-outline": it.name, "data-outline-id": it.id, ...dragProps(it, i2, parent, section), children: [
33140
33257
  !readOnly2 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "grip", "aria-hidden": "true", children: "⠿" }),
33141
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "linklike nm", onClick: (e) => pick(e, it.id), onKeyDown: (e) => onKey(e, it, list2, i2, parent), "aria-pressed": chosen.has(it.id), "aria-describedby": readOnly2 ? void 0 : "outline-keys", children: it.name }),
33258
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", role: "option", className: "linklike nm", onClick: (e) => pick(e, it.id), onKeyDown: (e) => onKey(e, it, list2, i2, parent), "aria-selected": chosen.has(it.id), "aria-describedby": readOnly2 ? "outline-nav" : "outline-nav outline-keys", ...roving(it.id), children: it.name }),
33142
33259
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ty", children: T(`item_${it.type}`) === `item_${it.type}` ? ITEMS[it.type]?.label || it.type : T(`item_${it.type}`) }),
33143
33260
  !readOnly2 && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "act", style: { display: "inline-flex", gap: 2 }, children: [
33144
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "btn sm ghost icon", disabled: i2 === 0, onClick: () => reorderItem(it.id, -1), title: T("outlineBackward"), "aria-label": `${T("outlineBackward")}: ${it.name}`, children: "↑" }),
33145
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "btn sm ghost icon", disabled: i2 === list2.length - 1, onClick: () => reorderItem(it.id, 1), title: T("outlineForward"), "aria-label": `${T("outlineForward")}: ${it.name}`, children: "↓" }),
33146
- parent && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "btn sm ghost icon", onClick: () => moveOutOfParent(it.id), title: T("outlineMoveOut", { name: parent.name }), "aria-label": `${T("outlineMoveOut", { name: parent.name })}: ${it.name}`, children: "⇱" })
33261
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "btn sm ghost icon", tabIndex: -1, disabled: i2 === 0, onClick: () => reorderItem(it.id, -1), title: T("outlineBackward"), "aria-label": `${T("outlineBackward")}: ${it.name}`, children: "↑" }),
33262
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "btn sm ghost icon", tabIndex: -1, disabled: i2 === list2.length - 1, onClick: () => reorderItem(it.id, 1), title: T("outlineForward"), "aria-label": `${T("outlineForward")}: ${it.name}`, children: "↓" }),
33263
+ parent && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "btn sm ghost icon", tabIndex: -1, onClick: () => moveOutOfParent(it.id), title: T("outlineMoveOut", { name: parent.name }), "aria-label": `${T("outlineMoveOut", { name: parent.name })}: ${it.name}`, children: "⇱" })
33147
33264
  ] })
33148
33265
  ] }),
33149
- NESTING.has(it.type) && (it.items || []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("ul", { className: "tree", children: rows(it.items, it, depth + 1, section) })
33266
+ NESTING.has(it.type) && (it.items || []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("ul", { className: "tree", role: "none", children: rows(it.items, it, depth + 1, section) })
33150
33267
  ] }, it.id);
33151
33268
  });
33152
33269
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "pane", "data-testid": "outline", children: [
33153
33270
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h4", { children: T("outline") }),
33154
33271
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "pane-body", ref: body, children: [
33155
- sectionList(def).map(({ key: key2, label }) => {
33272
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { role: "listbox", "aria-label": T("outline"), "aria-multiselectable": "true", onKeyDown: nav2, children: sectionList(def).map(({ key: key2, label }) => {
33156
33273
  const items = secOf(def, key2)?.items || [];
33157
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: `outline-sec${drop?.band === key2 ? " drop-band" : ""}`, "data-outline-band": key2, ...bandDrop(key2), children: [
33158
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: `linklike outline-band${sel.kind === "section" && sel.section === key2 ? " sel" : ""}`, onClick: () => useDesigner.getState().select({ kind: "section", section: key2 }), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("b", { children: label }) }),
33159
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("ul", { className: "tree", children: items.length ? rows(items, null, 1, key2) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("li", { className: "subtle", children: T("outlineEmpty") }) })
33274
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { role: "group", "aria-label": label, className: `outline-sec${drop?.band === key2 ? " drop-band" : ""}`, "data-outline-band": key2, ...bandDrop(key2), children: [
33275
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", role: "option", "aria-selected": sel.kind === "section" && sel.section === key2, "aria-describedby": "outline-nav", className: `linklike outline-band${sel.kind === "section" && sel.section === key2 ? " sel" : ""}`, onClick: () => useDesigner.getState().select({ kind: "section", section: key2 }), ...roving(`band:${key2}`),
33276
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("b", { children: label }) }),
33277
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("ul", { className: "tree", role: "none", children: items.length ? rows(items, null, 1, key2) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("li", { className: "subtle", role: "none", children: T("outlineEmpty") }) })
33160
33278
  ] }, key2);
33161
- }),
33279
+ }) }),
33280
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "sr-only", id: "outline-nav", children: T("b9_outlineKeys") }),
33162
33281
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "hint", children: T("outlineHint") }),
33163
33282
  !readOnly2 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "hint", id: "outline-keys", children: T("outlineKeys") }),
33164
33283
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "sr-only", role: "status", "aria-live": "polite", children: said })
@@ -33167,7 +33286,7 @@ function Outline() {
33167
33286
  }
33168
33287
 
33169
33288
  // src/theme/ThemeToggle.jsx
33170
- var import_react16 = __toESM(require_react(), 1);
33289
+ var import_react17 = __toESM(require_react(), 1);
33171
33290
 
33172
33291
  // src/theme/theme.js
33173
33292
  var THEME_KEY = "pw-theme";
@@ -33209,8 +33328,8 @@ function Icon2({ pref }) {
33209
33328
  ] });
33210
33329
  }
33211
33330
  function ThemeToggle({ className = "btn sm ghost icon" }) {
33212
- const [pref, setPref] = (0, import_react16.useState)("system");
33213
- (0, import_react16.useEffect)(() => {
33331
+ const [pref, setPref] = (0, import_react17.useState)("system");
33332
+ (0, import_react17.useEffect)(() => {
33214
33333
  setPref(readPreference());
33215
33334
  const mq = window.matchMedia("(prefers-color-scheme: dark)");
33216
33335
  const onChange = () => {
@@ -33228,7 +33347,7 @@ function ThemeToggle({ className = "btn sm ghost icon" }) {
33228
33347
  }
33229
33348
 
33230
33349
  // src/designer/ChartWizard.jsx
33231
- var import_react17 = __toESM(require_react(), 1);
33350
+ var import_react18 = __toESM(require_react(), 1);
33232
33351
  var import_jsx_runtime16 = __toESM(require_jsx_runtime(), 1);
33233
33352
  var TYPES = ["column", "bar", "line", "area", "pie", "donut", "scatter", "bubble", "radar", "funnel", "gauge", "treemap", "histogram", "boxplot", "waterfall", "gantt"];
33234
33353
  var PER_ROW = /* @__PURE__ */ new Set(["scatter", "bubble"]);
@@ -33344,14 +33463,14 @@ function ChartWizard() {
33344
33463
  const close = () => useDesigner.getState().setUi({ wizard: null });
33345
33464
  const lang2 = useDesigner((s) => s.lang);
33346
33465
  const tr = (k, v) => t(lang2, `cw_${k}`, v);
33347
- const [c, setC] = (0, import_react17.useState)(() => {
33466
+ const [c, setC] = (0, import_react18.useState)(() => {
33348
33467
  if (editing) return configFromChart(editing);
33349
33468
  const score2 = (d) => ((d.fields || []).some((f) => f.type === "number") ? 1e6 : 0) + (sample?.dataSets?.[d.name]?.length || 0);
33350
33469
  const ds2 = [...def.dataSets || []].sort((a, b) => score2(b) - score2(a))[0];
33351
33470
  return { title: "", split: "", stacked: false, format: "N0", ...guess(ds2, sample?.dataSets?.[ds2?.name] || []) };
33352
33471
  });
33353
33472
  const set2 = (patch) => setC((x) => ({ ...x, ...patch, custom: false }));
33354
- (0, import_react17.useEffect)(() => {
33473
+ (0, import_react18.useEffect)(() => {
33355
33474
  if (!sample?.dataSets && !sample?.loading) loadSample();
33356
33475
  }, []);
33357
33476
  const ds = (def.dataSets || []).find((d) => d.name === c.dataSet);
@@ -33362,7 +33481,7 @@ function ChartWizard() {
33362
33481
  const good = suggested(c, rows, fields);
33363
33482
  const dateCategory = fields.find((f) => f.name === c.category)?.type === "date";
33364
33483
  const monthish = fields.find((f) => f.name === c.category)?.type === "number" && /month/i.test(c.category) && rows.length > 0 && rows.every((r) => r[c.category] == null || Number.isInteger(r[c.category]) && r[c.category] >= 1 && r[c.category] <= 12);
33365
- const compact = (0, import_react17.useMemo)(() => {
33484
+ const compact = (0, import_react18.useMemo)(() => {
33366
33485
  if (!c.value || c.agg === "Count" || c.format === "P1") return null;
33367
33486
  const per = /* @__PURE__ */ new Map();
33368
33487
  for (const r of rows) {
@@ -33378,14 +33497,14 @@ function ChartWizard() {
33378
33497
  const d = def.dataSets.find((x) => x.name === name2);
33379
33498
  setC((x) => ({ ...x, split: "", ...guess(d, sample?.dataSets?.[name2] || []) }));
33380
33499
  };
33381
- (0, import_react17.useEffect)(() => {
33500
+ (0, import_react18.useEffect)(() => {
33382
33501
  if (editing || !rows.length || c.touched) return;
33383
33502
  setC((x) => ({ ...x, ...guess(ds, rows), touched: true }));
33384
33503
  }, [rows.length]);
33385
- const [thumbs, setThumbs] = (0, import_react17.useState)({});
33386
- const [big, setBig] = (0, import_react17.useState)(null);
33504
+ const [thumbs, setThumbs] = (0, import_react18.useState)({});
33505
+ const [big, setBig] = (0, import_react18.useState)(null);
33387
33506
  const cfgKey = JSON.stringify({ ...c, touched: void 0 });
33388
- (0, import_react17.useEffect)(() => {
33507
+ (0, import_react18.useEffect)(() => {
33389
33508
  if (!sample?.dataSets || !c.dataSet) return;
33390
33509
  let alive = true;
33391
33510
  const t3 = setTimeout(async () => {
@@ -33573,7 +33692,7 @@ function rawText(raw) {
33573
33692
  }
33574
33693
 
33575
33694
  // src/designer/TableWizard.jsx
33576
- var import_react18 = __toESM(require_react(), 1);
33695
+ var import_react19 = __toESM(require_react(), 1);
33577
33696
  var import_jsx_runtime17 = __toESM(require_jsx_runtime(), 1);
33578
33697
  var LAYOUTS = [
33579
33698
  { id: "list", label: "List", when: "Every row, with totals" },
@@ -33586,12 +33705,13 @@ function TableWizard() {
33586
33705
  const wiz = useDesigner((s) => s.tableWizard);
33587
33706
  const def = useDesigner((s) => s.def);
33588
33707
  const sample = useDesigner((s) => s.sample);
33708
+ const lang2 = useDesigner((s) => s.lang);
33589
33709
  const close = () => useDesigner.getState().setUi({ tableWizard: null });
33590
33710
  const parent = wiz?.parentId ? findItem(def, wiz.parentId)?.item : null;
33591
33711
  const width = Math.max(120, Math.round((parent ? parent.w : bodyWidth(def, wiz?.section || "body")) - (wiz?.x || 0)));
33592
- const [c, setC] = (0, import_react18.useState)(() => ({ dataSet: wiz?.dataSet || def.dataSets?.[0]?.name, layout: wiz?.type === "matrix" ? "matrix" : "list", groupBy: "", fields: null, mRows: "", mCols: "", mValue: "" }));
33712
+ const [c, setC] = (0, import_react19.useState)(() => ({ dataSet: wiz?.dataSet || def.dataSets?.[0]?.name, layout: wiz?.type === "matrix" ? "matrix" : "list", groupBy: "", fields: null, mRows: "", mCols: "", mValue: "" }));
33593
33713
  const set2 = (patch) => setC((x) => ({ ...x, ...patch }));
33594
- (0, import_react18.useEffect)(() => {
33714
+ (0, import_react19.useEffect)(() => {
33595
33715
  if (!sample?.dataSets && !sample?.loading) loadSample();
33596
33716
  }, []);
33597
33717
  const ds = (def.dataSets || []).find((d) => d.name === c.dataSet);
@@ -33605,9 +33725,9 @@ function TableWizard() {
33605
33725
  const groupBy2 = c.groupBy || groupGuess;
33606
33726
  const mRows = c.mRows || groupBy2, mCols = c.mCols || text.find((f) => f.name !== mRows)?.name || "", mValue = c.mValue || nums[0]?.name || "";
33607
33727
  const itemFor = (layout, w) => layout === "matrix" ? mRows && mCols ? matrixFor(ds, { rows: mRows, columns: mCols, value: mValue, agg: mValue ? "Sum" : "Count", width: w, sample: rows, currency: def.currency }) : null : tableFor(ds, { layout, groupBy: groupBy2, width: w, rows, fields: chosen, currency: def.currency });
33608
- const [thumbs, setThumbs] = (0, import_react18.useState)({});
33728
+ const [thumbs, setThumbs] = (0, import_react19.useState)({});
33609
33729
  const key2 = JSON.stringify([c, groupBy2, mRows, mCols, mValue, chosen]);
33610
- (0, import_react18.useEffect)(() => {
33730
+ (0, import_react19.useEffect)(() => {
33611
33731
  if (!ds || !sample?.dataSets) return;
33612
33732
  let alive = true;
33613
33733
  const t3 = setTimeout(async () => {
@@ -33652,7 +33772,7 @@ function TableWizard() {
33652
33772
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { className: "btn ghost", onClick: () => {
33653
33773
  useDesigner.getState().setUi({ tableWizard: null, pivotWizard: { section: wiz.section, x: wiz.x, y: wiz.y, parentId: wiz.parentId, dataSet: c.dataSet } });
33654
33774
  }, "data-testid": "open-pivot-wizard", children: [
33655
- t(useDesigner.getState().lang, "pivotWizard"),
33775
+ t(lang2, "pivotWizard"),
33656
33776
  "…"
33657
33777
  ] }),
33658
33778
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { className: "btn", onClick: close, children: "Cancel" }),
@@ -33665,7 +33785,7 @@ function TableWizard() {
33665
33785
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "cw-side", "aria-label": "Data for the table", children: [
33666
33786
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Field, { label: "Data set", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Select, { value: c.dataSet, options: (def.dataSets || []).map((d) => d.name), onChange: (v) => set2({ dataSet: v, fields: null, groupBy: "", mRows: "", mCols: "", mValue: "" }) }) }),
33667
33787
  sample?.loading && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "hint", children: "Calling the API…" }),
33668
- noSourceKey(def) && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "hint", role: "status", "data-testid": "no-source", children: t(useDesigner.getState().lang, noSourceKey(def)) }),
33788
+ noSourceKey(def) && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "hint", role: "status", "data-testid": "no-source", children: t(lang2, noSourceKey(def)) }),
33669
33789
  sample?.error && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "err", children: sample.error }),
33670
33790
  c.layout !== "matrix" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
33671
33791
  c.layout !== "list" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Field, { label: "Group by", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Select, { value: groupBy2, options: text.map((f) => f.name), onChange: (v) => set2({ groupBy: v }) }) }),
@@ -33695,7 +33815,7 @@ function TableWizard() {
33695
33815
  }
33696
33816
 
33697
33817
  // src/designer/AskAi.jsx
33698
- var import_react19 = __toESM(require_react(), 1);
33818
+ var import_react20 = __toESM(require_react(), 1);
33699
33819
  var import_jsx_runtime18 = __toESM(require_jsx_runtime(), 1);
33700
33820
  var trim = (v, n = 200) => Array.isArray(v) ? v.slice(0, n).map((x) => trim(x, n)) : v && typeof v === "object" ? Object.fromEntries(Object.entries(v).map(([k, x]) => [k, trim(x, n)])) : v;
33701
33821
  function changes(before, after) {
@@ -33711,9 +33831,9 @@ function changes(before, after) {
33711
33831
  function AskAi({ onClose }) {
33712
33832
  const def = useDesigner((s) => s.def);
33713
33833
  const sample = useDesigner((s) => s.sample);
33714
- const [prompt, setPrompt] = (0, import_react19.useState)("");
33715
- const [st, setSt] = (0, import_react19.useState)({ state: "idle" });
33716
- (0, import_react19.useEffect)(() => {
33834
+ const [prompt, setPrompt] = (0, import_react20.useState)("");
33835
+ const [st, setSt] = (0, import_react20.useState)({ state: "idle" });
33836
+ (0, import_react20.useEffect)(() => {
33717
33837
  if (!sample?.dataSets && !sample?.loading) loadSample();
33718
33838
  }, []);
33719
33839
  const ask = async () => {
@@ -33727,7 +33847,7 @@ function AskAi({ onClose }) {
33727
33847
  let preview = null;
33728
33848
  try {
33729
33849
  const params = resolveParameters(out.definition, {}, { lenient: true });
33730
- const model = await render(out.definition, { fontStore: fontStore(), parameters: params, sources: sources ? Object.fromEntries((out.definition.dataSources || []).map((s) => [s.name, sources[s.name] ?? (s.type === "json" ? s.data : [])])) : void 0, baseUrl: origin(), fetch: reportFetch(origin()) });
33850
+ const model = await render(out.definition, { fontStore: await loadFontStore(), parameters: params, sources: sources ? Object.fromEntries((out.definition.dataSources || []).map((s) => [s.name, sources[s.name] ?? (s.type === "json" ? s.data : [])])) : void 0, baseUrl: origin(), fetch: reportFetch(origin()) });
33731
33851
  preview = { html: pageToSvg(model.pages[0], model.width, model.height), pages: model.pages.length };
33732
33852
  } catch (e) {
33733
33853
  preview = { error: e.message };
@@ -33798,7 +33918,7 @@ function AskAi({ onClose }) {
33798
33918
  }
33799
33919
 
33800
33920
  // src/designer/PivotWizard.jsx
33801
- var import_react20 = __toESM(require_react(), 1);
33921
+ var import_react21 = __toESM(require_react(), 1);
33802
33922
  var import_jsx_runtime19 = __toESM(require_jsx_runtime(), 1);
33803
33923
  var MIME_PF = "application/x-pw-pivot-field";
33804
33924
  var AGGS2 = ["Sum", "Avg", "Count", "Min", "Max"];
@@ -33830,9 +33950,9 @@ function Thumb({ item }) {
33830
33950
  const T = useT2();
33831
33951
  const def = useDesigner((s) => s.def);
33832
33952
  const sample = useDesigner((s) => s.sample);
33833
- const [svg, setSvg] = (0, import_react20.useState)(null);
33953
+ const [svg, setSvg] = (0, import_react21.useState)(null);
33834
33954
  const key2 = JSON.stringify(item);
33835
- (0, import_react20.useEffect)(() => {
33955
+ (0, import_react21.useEffect)(() => {
33836
33956
  if (!item || !sample?.dataSets) return void 0;
33837
33957
  let alive = true;
33838
33958
  const t3 = setTimeout(() => {
@@ -33854,7 +33974,7 @@ function Thumb({ item }) {
33854
33974
  function useData(name2) {
33855
33975
  const def = useDesigner((s) => s.def);
33856
33976
  const sample = useDesigner((s) => s.sample);
33857
- (0, import_react20.useEffect)(() => {
33977
+ (0, import_react21.useEffect)(() => {
33858
33978
  if (!sample?.dataSets && !sample?.loading) loadSample();
33859
33979
  }, []);
33860
33980
  const ds = (def.dataSets || []).find((d) => d.name === name2);
@@ -33869,10 +33989,10 @@ function placeOf(w, def) {
33869
33989
  function PivotWizard() {
33870
33990
  const T = useT2();
33871
33991
  const w = useDesigner((s) => s.pivotWizard);
33872
- const [dsName, setDs] = (0, import_react20.useState)(() => w?.dataSet || useDesigner.getState().def.dataSets?.[0]?.name);
33992
+ const [dsName, setDs] = (0, import_react21.useState)(() => w?.dataSet || useDesigner.getState().def.dataSets?.[0]?.name);
33873
33993
  const { def, ds, fields, rows } = useData(dsName);
33874
- const [lay, setLay] = (0, import_react20.useState)({ rows: [], columns: [], values: [] });
33875
- const [totals, setTotals] = (0, import_react20.useState)(true);
33994
+ const [lay, setLay] = (0, import_react21.useState)({ rows: [], columns: [], values: [] });
33995
+ const [totals, setTotals] = (0, import_react21.useState)(true);
33876
33996
  const close = () => useDesigner.getState().setUi({ pivotWizard: null });
33877
33997
  const width = Math.round(bodyWidth(def, w?.section || "body") - (w?.x || 0));
33878
33998
  const add = (zone2, f) => setLay((l) => {
@@ -33993,13 +34113,13 @@ function InstantVisuals() {
33993
34113
  const T = useT2();
33994
34114
  const w = useDesigner((s) => s.instantVisuals);
33995
34115
  const { def, ds, fields, rows } = useData(w?.dataSet);
33996
- const [picked, setPickedRaw] = (0, import_react20.useState)(() => instantPicks(ds?.fields || [], rows));
33997
- const [touched, setTouched] = (0, import_react20.useState)(false);
34116
+ const [picked, setPickedRaw] = (0, import_react21.useState)(() => instantPicks(ds?.fields || [], rows));
34117
+ const [touched, setTouched] = (0, import_react21.useState)(false);
33998
34118
  const setPicked = (fn3) => {
33999
34119
  setTouched(true);
34000
34120
  setPickedRaw(fn3);
34001
34121
  };
34002
- (0, import_react20.useEffect)(() => {
34122
+ (0, import_react21.useEffect)(() => {
34003
34123
  if (!touched) setPickedRaw(instantPicks(ds?.fields || [], rows));
34004
34124
  }, [rows.length, ds]);
34005
34125
  const close = () => useDesigner.getState().setUi({ instantVisuals: null });
@@ -34199,9 +34319,10 @@ var TOOLS = [
34199
34319
  ] }) }
34200
34320
  ];
34201
34321
  function Toolbox({ T, hide = [] }) {
34322
+ const api = useDesignerStore();
34202
34323
  const name2 = (type) => T(`item_${type}`) === `item_${type}` ? ITEMS[type].label : T(`item_${type}`);
34203
34324
  const add = (type) => {
34204
- const s = useDesigner.getState();
34325
+ const s = api.getState();
34205
34326
  const at2 = insertSpot(s.def, s.sel);
34206
34327
  insertItem(type, at2.section, 0, at2.y, {}, at2.parentId);
34207
34328
  };
@@ -34250,12 +34371,15 @@ var TbGroup = ({ label, children }) => /* @__PURE__ */ (0, import_jsx_runtime20.
34250
34371
  ] });
34251
34372
  var QUICK = [["textbox", "text"], ["table", "table"], ["chart", "chart"], ["image", "image"]];
34252
34373
  function LeftRail({ T, readOnly: readOnly2, embed }) {
34253
- const body = (0, import_react21.useRef)(null);
34254
- const [at2, setAt] = (0, import_react21.useState)("tools");
34374
+ const body = (0, import_react22.useRef)(null);
34375
+ const [at2, setAt] = (0, import_react22.useState)("tools");
34255
34376
  const tabs = [!readOnly2 && ["tools", "b2_toolbox", "tools"], embed?.panels?.data !== false && ["data", "b2_data", "data"], ["outline", "b2_outline", "outline"]].filter(Boolean);
34256
34377
  const go = (id) => {
34257
34378
  const el = body.current?.querySelector(`[data-rail="${id}"]`);
34258
- if (el) body.current.scrollTo({ top: el.offsetTop - body.current.offsetTop, behavior: "smooth" });
34379
+ if (el) {
34380
+ body.current.scrollTo({ top: el.offsetTop - body.current.offsetTop, behavior: "smooth" });
34381
+ (el.querySelector('[role=listbox] [tabindex="0"]') || el.querySelector("button, input, select, textarea"))?.focus({ preventScroll: true });
34382
+ }
34259
34383
  setAt(id);
34260
34384
  };
34261
34385
  const spy = () => {
@@ -34357,8 +34481,9 @@ var framed = () => {
34357
34481
  }
34358
34482
  };
34359
34483
  function useAutosave(id, T, lang2, user) {
34360
- const [offer, setOffer] = (0, import_react21.useState)(null);
34361
- (0, import_react21.useEffect)(() => {
34484
+ const api = useDesignerStore();
34485
+ const [offer, setOffer] = (0, import_react22.useState)(null);
34486
+ (0, import_react22.useEffect)(() => {
34362
34487
  if (!id || user == null || framed()) return void 0;
34363
34488
  let store;
34364
34489
  try {
@@ -34368,10 +34493,10 @@ function useAutosave(id, T, lang2, user) {
34368
34493
  }
34369
34494
  clearDrafts(store, user);
34370
34495
  const d = readDraft(store, user, id);
34371
- if (d && plain(mergeDraft(d.def, useDesigner.getState().def)) !== plain(useDesigner.getState().def)) setOffer(d);
34496
+ if (d && plain(mergeDraft(d.def, api.getState().def)) !== plain(api.getState().def)) setOffer(d);
34372
34497
  else if (d) clearDraft(store, user, id);
34373
34498
  const keep = () => {
34374
- const s = useDesigner.getState();
34499
+ const s = api.getState();
34375
34500
  if (!s.saved && !s.readOnly) writeDraft(store, user, id, s.def, Date.now(), s.rev || null);
34376
34501
  };
34377
34502
  const t3 = setInterval(keep, AUTOSAVE_MS);
@@ -34380,7 +34505,7 @@ function useAutosave(id, T, lang2, user) {
34380
34505
  };
34381
34506
  window.addEventListener("pagehide", keep);
34382
34507
  document.addEventListener("visibilitychange", hide);
34383
- const unsub = useDesigner.subscribe((s, prev) => {
34508
+ const unsub = api.subscribe((s, prev) => {
34384
34509
  if (s.saved && !prev.saved) clearDraft(store, user, id);
34385
34510
  });
34386
34511
  return () => {
@@ -34392,13 +34517,13 @@ function useAutosave(id, T, lang2, user) {
34392
34517
  }, [id, user]);
34393
34518
  if (!offer) return null;
34394
34519
  const when = new Date(offer.at).toLocaleString(lang2 === "en" ? "en-IN" : lang2, { dateStyle: "medium", timeStyle: "short" });
34395
- const stale = staleDraft(offer, useDesigner.getState().rev);
34520
+ const stale = staleDraft(offer, api.getState().rev);
34396
34521
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "draft-bar", role: "alert", "data-testid": "draft-offer", "data-stale": stale || void 0, children: [
34397
34522
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: T(stale ? "ux_draftStale" : "ux_draftFound", { when }) }),
34398
34523
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { className: `btn sm${stale ? "" : " primary"}`, "data-testid": "draft-restore", onClick: () => {
34399
- const d = mergeDraft(offer.def, useDesigner.getState().def);
34400
- useDesigner.getState().apply(() => JSON.parse(JSON.stringify(d)));
34401
- useDesigner.getState().fixSelection();
34524
+ const d = mergeDraft(offer.def, api.getState().def);
34525
+ api.getState().apply(() => JSON.parse(JSON.stringify(d)));
34526
+ api.getState().fixSelection();
34402
34527
  setOffer(null);
34403
34528
  }, children: T(stale ? "ux_draftRestoreAnyway" : "ux_draftRestore") }),
34404
34529
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { className: "btn sm", "data-testid": "draft-discard", onClick: () => {
@@ -34411,12 +34536,13 @@ function useAutosave(id, T, lang2, user) {
34411
34536
  ] });
34412
34537
  }
34413
34538
  function ConflictBar({ T }) {
34539
+ const api = useDesignerStore();
34414
34540
  const conflict = useDesigner((s) => s.conflict);
34415
34541
  if (!conflict) return null;
34416
34542
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "draft-bar", role: "alert", "data-testid": "save-conflict", children: [
34417
34543
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: T("ux_conflict") }),
34418
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { className: "btn sm", "data-testid": "conflict-mine", onClick: () => useDesigner.getState().save({ overwrite: true }), children: T("ux_conflictMine") }),
34419
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { className: "btn sm", "data-testid": "conflict-theirs", onClick: () => useDesigner.getState().takeTheirs(), children: T("ux_conflictTheirs") })
34544
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { className: "btn sm", "data-testid": "conflict-mine", onClick: () => api.getState().save({ overwrite: true }), children: T("ux_conflictMine") }),
34545
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { className: "btn sm", "data-testid": "conflict-theirs", onClick: () => api.getState().takeTheirs(), children: T("ux_conflictTheirs") })
34420
34546
  ] });
34421
34547
  }
34422
34548
  var AL = (d) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("svg", { width: "16", height: "14", viewBox: "0 0 16 14", "aria-hidden": "true", children: d });
@@ -34466,7 +34592,7 @@ var ALIGN2 = [
34466
34592
  ];
34467
34593
  function AlignBar({ T }) {
34468
34594
  const sel = useDesigner((s) => s.sel);
34469
- const [toPage, setToPage] = (0, import_react21.useState)(false);
34595
+ const [toPage, setToPage] = (0, import_react22.useState)(false);
34470
34596
  if (sel.kind !== "items" || !sel.ids.length) return null;
34471
34597
  const n = sel.ids.length;
34472
34598
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "align-bar", role: "toolbar", "aria-label": T("ux_alignBar"), "data-testid": "align-bar", children: [
@@ -34481,13 +34607,14 @@ function AlignBar({ T }) {
34481
34607
  ] });
34482
34608
  }
34483
34609
  function IssuesButton({ T }) {
34610
+ const api = useDesignerStore();
34484
34611
  const issues = useDesignIssues();
34485
- const [open, setOpen] = (0, import_react21.useState)(false);
34486
- (0, import_react21.useEffect)(() => {
34612
+ const [open, setOpen] = (0, import_react22.useState)(false);
34613
+ (0, import_react22.useEffect)(() => {
34487
34614
  if (!issues.length) setOpen(false);
34488
34615
  }, [issues.length]);
34489
- const listRef = (0, import_react21.useRef)(null);
34490
- (0, import_react21.useLayoutEffect)(() => {
34616
+ const listRef = (0, import_react22.useRef)(null);
34617
+ (0, import_react22.useLayoutEffect)(() => {
34491
34618
  const el = listRef.current;
34492
34619
  if (!el) return void 0;
34493
34620
  const place = () => {
@@ -34504,7 +34631,7 @@ function IssuesButton({ T }) {
34504
34631
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "issues-wrap", children: [
34505
34632
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", className: "btn sm issues-btn", "aria-expanded": open, onClick: () => setOpen((v) => !v), "data-testid": "issues", children: T("ux_issues", { n: issues.length }) }),
34506
34633
  open && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ul", { className: "issues-list", "data-testid": "issues-list", ref: listRef, children: issues.map((i2, k) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", className: "linklike", onClick: () => {
34507
- if (i2.id) useDesigner.getState().select({ kind: "items", ids: [i2.id] });
34634
+ if (i2.id) api.getState().select({ kind: "items", ids: [i2.id] });
34508
34635
  }, children: issueLine(T, i2) }) }, k)) })
34509
34636
  ] });
34510
34637
  }
@@ -34528,9 +34655,10 @@ var SHORTCUTS = [
34528
34655
  ["?", "sc_help"]
34529
34656
  ];
34530
34657
  function HistoryDialog({ id, onClose, T, lang: lang2 }) {
34531
- const [list2, setList] = (0, import_react21.useState)(null);
34532
- const [err, setErr] = (0, import_react21.useState)(null);
34533
- (0, import_react21.useEffect)(() => {
34658
+ const api = useDesignerStore();
34659
+ const [list2, setList] = (0, import_react22.useState)(null);
34660
+ const [err, setErr] = (0, import_react22.useState)(null);
34661
+ (0, import_react22.useEffect)(() => {
34534
34662
  fetch(`/api/reports/${id}/versions`).then((r) => r.json()).then(setList).catch((e) => setErr(e.message));
34535
34663
  }, [id]);
34536
34664
  const restore = async (v) => {
@@ -34540,7 +34668,7 @@ function HistoryDialog({ id, onClose, T, lang: lang2 }) {
34540
34668
  return;
34541
34669
  }
34542
34670
  const def = await res.json();
34543
- useDesigner.getState().init(id, def);
34671
+ api.getState().init(id, def);
34544
34672
  onClose();
34545
34673
  };
34546
34674
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Dialog, { title: T("versionHistory"), onClose, footer: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { className: "btn", onClick: onClose, children: T("close") }), children: [
@@ -34562,18 +34690,48 @@ function HistoryDialog({ id, onClose, T, lang: lang2 }) {
34562
34690
  ] }, v.version))
34563
34691
  ] });
34564
34692
  }
34565
- function Designer({ id, initial, rev = null, lang: langIn, embed = null, user = null, ai = false }) {
34693
+ function Designer({ store: storeIn = null, ...props }) {
34694
+ const [store] = (0, import_react22.useState)(() => {
34695
+ const s = storeIn || newDesignerStore();
34696
+ activateStore(s);
34697
+ return s;
34698
+ });
34699
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DesignerStore.Provider, { value: store, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DesignerIn, { ...props }) });
34700
+ }
34701
+ var ACTIVATE = [
34702
+ "onPointerDownCapture",
34703
+ "onMouseDownCapture",
34704
+ "onKeyDownCapture",
34705
+ "onFocusCapture",
34706
+ "onClickCapture",
34707
+ "onInputCapture",
34708
+ "onChangeCapture",
34709
+ "onDragStartCapture",
34710
+ "onDragOverCapture",
34711
+ "onDropCapture",
34712
+ "onPasteCapture",
34713
+ "onWheelCapture",
34714
+ "onContextMenuCapture",
34715
+ "onDoubleClickCapture",
34716
+ "onSubmitCapture"
34717
+ ];
34718
+ function DesignerIn({ id, initial, rev = null, lang: langIn, embed = null, user = null, ai = false }) {
34719
+ const api = useDesignerStore();
34720
+ const activators = (0, import_react22.useMemo)(() => {
34721
+ const on = () => activateStore(api);
34722
+ return Object.fromEntries(ACTIVATE.map((k) => [k, on]));
34723
+ }, [api]);
34566
34724
  const lang2 = pickLang(langIn);
34567
34725
  const T = (k, v) => t(lang2, k, v);
34568
34726
  const q2 = lang2 === "en" ? "" : `?lang=${encodeURIComponent(lang2)}`;
34569
- const ready = (0, import_react21.useRef)(false);
34727
+ const ready = (0, import_react22.useRef)(false);
34570
34728
  if (!ready.current && typeof window !== "undefined") {
34571
- useDesigner.getState().init(id, initial);
34572
- useDesigner.getState().setUi({ lang: lang2, embed, readOnly: !!embed?.readOnly, rev, conflict: null });
34729
+ api.getState().init(id, initial);
34730
+ api.getState().setUi({ lang: lang2, embed, readOnly: !!embed?.readOnly, rev, conflict: null });
34573
34731
  ready.current = true;
34574
34732
  }
34575
34733
  const readOnly2 = !!embed?.readOnly;
34576
- const rootRef = (0, import_react21.useRef)(null);
34734
+ const rootRef = (0, import_react22.useRef)(null);
34577
34735
  const def = useDesigner((s) => s.def);
34578
34736
  const tab = useDesigner((s) => s.tab);
34579
34737
  const saved = useDesigner((s) => s.saved);
@@ -34583,23 +34741,23 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34583
34741
  const snap = useDesigner((s) => s.snap);
34584
34742
  const unit = useDesigner((s) => s.unit);
34585
34743
  const fonts = useDesigner((s) => s.fonts);
34586
- const fontCss = (0, import_react21.useMemo)(() => fontFaceCss(allFontKeys(), fontsBase().replace(/\/$/, "")), [fonts]);
34587
- (0, import_react21.useEffect)(() => {
34744
+ const fontCss = (0, import_react22.useMemo)(() => fontFaceCss(allFontKeys(), fontsBase().replace(/\/$/, "")), [fonts]);
34745
+ (0, import_react22.useEffect)(() => {
34588
34746
  if (embed) declareDocumentStyles("pw-designer-fonts", fontCss);
34589
34747
  }, [embed, fontCss]);
34590
- (0, import_react21.useEffect)(() => {
34591
- customFonts().then((list2) => useDesigner.getState().setUi({ fonts: list2 }));
34748
+ (0, import_react22.useEffect)(() => {
34749
+ customFonts().then((list2) => api.getState().setUi({ fonts: list2 }));
34592
34750
  }, []);
34593
- (0, import_react21.useEffect)(() => {
34751
+ (0, import_react22.useEffect)(() => {
34594
34752
  const z = savedZoom();
34595
- if (z != null) useDesigner.getState().setUi({ zoom: z });
34753
+ if (z != null) api.getState().setUi({ zoom: z });
34596
34754
  }, []);
34597
34755
  const canUndo = useDesigner((s) => s.past.length > 0);
34598
34756
  const canRedo = useDesigner((s) => s.future.length > 0);
34599
- const st = useDesigner.getState;
34600
- const [dialog, setDialog] = (0, import_react21.useState)(null);
34601
- const [showLeft, setShowLeft] = (0, import_react21.useState)(true);
34602
- const [showRight, setShowRight] = (0, import_react21.useState)(true);
34757
+ const st = api.getState;
34758
+ const [dialog, setDialog] = (0, import_react22.useState)(null);
34759
+ const [showLeft, setShowLeft] = (0, import_react22.useState)(true);
34760
+ const [showRight, setShowRight] = (0, import_react22.useState)(true);
34603
34761
  const selKind = useDesigner((s) => s.sel.kind);
34604
34762
  const wizard = useDesigner((s) => s.wizard);
34605
34763
  const tableWizard = useDesigner((s) => s.tableWizard);
@@ -34608,12 +34766,18 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34608
34766
  const cells = useDesigner((s) => s.cells);
34609
34767
  const cellSize = useDesigner((s) => s.cellSize);
34610
34768
  const dataKey = useDesigner((s) => `${(s.def?.dataSources || []).map((x) => x.name)}|${(s.def?.dataSets || []).map((x) => x.name)}`);
34611
- (0, import_react21.useEffect)(() => {
34612
- loadSample();
34769
+ (0, import_react22.useEffect)(() => {
34770
+ loadSample(api);
34613
34771
  }, [dataKey]);
34614
- (0, import_react21.useEffect)(() => {
34772
+ (0, import_react22.useEffect)(() => {
34773
+ let lastInside = false;
34774
+ const inside = (e) => (e.composedPath?.() || []).includes(rootRef.current);
34775
+ const onDown = (e) => {
34776
+ lastInside = inside(e);
34777
+ };
34778
+ const ours = (e) => inside(e) || lastInside && (e.target === document.body || e.target === document.documentElement);
34615
34779
  const onKey = (e) => {
34616
- if (embed && !(e.composedPath?.() || []).includes(rootRef.current)) return;
34780
+ if (embed && !ours(e)) return;
34617
34781
  const mod = e.metaKey || e.ctrlKey;
34618
34782
  if (mod && e.key.toLowerCase() === "s") {
34619
34783
  e.preventDefault();
@@ -34632,7 +34796,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34632
34796
  st().save();
34633
34797
  return;
34634
34798
  }
34635
- if (isTyping(e) || st().tab !== "design") return;
34799
+ if (isTyping(e) || st().tab !== "design" || e.defaultPrevented) return;
34636
34800
  if (mod && e.key.toLowerCase() === "z") {
34637
34801
  e.preventDefault();
34638
34802
  e.shiftKey ? st().redo() : st().undo();
@@ -34655,11 +34819,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34655
34819
  }
34656
34820
  return;
34657
34821
  }
34658
- if (mod && e.key.toLowerCase() === "v") {
34659
- e.preventDefault();
34660
- pasteItems(st().sel.kind === "section" ? st().sel.section : "body");
34661
- return;
34662
- }
34822
+ if (mod && e.key.toLowerCase() === "v") return;
34663
34823
  if (e.key === "Delete" || e.key === "Backspace") {
34664
34824
  if (st().sel.kind === "items") {
34665
34825
  e.preventDefault();
@@ -34691,10 +34851,24 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34691
34851
  e.returnValue = "";
34692
34852
  }
34693
34853
  };
34854
+ const onPaste = (e) => {
34855
+ if (embed && !ours(e) || isTyping(e) || st().tab !== "design") return;
34856
+ e.preventDefault();
34857
+ if (!pasteItems(st().sel.kind === "section" ? st().sel.section : "body", e.clipboardData?.getData("text/plain"))) {
34858
+ st().setUi({ saveError: t(lang2, "b9_nothingToPaste") });
34859
+ setTimeout(() => st().setUi({ saveError: null }), 3e3);
34860
+ }
34861
+ };
34694
34862
  window.addEventListener("keydown", onKey);
34863
+ window.addEventListener("paste", onPaste);
34864
+ window.addEventListener("pointerdown", onDown, true);
34865
+ window.addEventListener("focusin", onDown, true);
34695
34866
  if (!embed) window.addEventListener("beforeunload", onLeave);
34696
34867
  return () => {
34697
34868
  window.removeEventListener("keydown", onKey);
34869
+ window.removeEventListener("paste", onPaste);
34870
+ window.removeEventListener("pointerdown", onDown, true);
34871
+ window.removeEventListener("focusin", onDown, true);
34698
34872
  window.removeEventListener("beforeunload", onLeave);
34699
34873
  };
34700
34874
  }, [st, embed]);
@@ -34713,17 +34887,17 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34713
34887
  const d = await embed.onOpen();
34714
34888
  if (d && typeof d === "object") {
34715
34889
  st().init(id, d);
34716
- loadSample();
34890
+ loadSample(api);
34717
34891
  }
34718
34892
  };
34719
- const importInput = (0, import_react21.useRef)(null);
34720
- const [imported, setImported] = (0, import_react21.useState)(null);
34893
+ const importInput = (0, import_react22.useRef)(null);
34894
+ const [imported, setImported] = (0, import_react22.useState)(null);
34721
34895
  const importFile = async (file) => {
34722
34896
  if (!file) return;
34723
34897
  const r = readReportFile(file.name, await file.text());
34724
34898
  if (r.definition) {
34725
34899
  st().init(id, r.definition);
34726
- loadSample();
34900
+ loadSample(api);
34727
34901
  }
34728
34902
  setImported({ name: file.name, ok: !!r.definition, warnings: r.warnings || [], error: r.error });
34729
34903
  };
@@ -34737,7 +34911,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34737
34911
  ] }),
34738
34912
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "hint", children: T("loadingDesigner") })
34739
34913
  ] }) });
34740
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "designer", "data-testid": "designer", dir: dirOf(lang2), lang: lang2, ref: rootRef, "data-readonly": readOnly2 || void 0, children: [
34914
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "designer", "data-testid": "designer", dir: dirOf(lang2), lang: lang2, ref: rootRef, "data-readonly": readOnly2 || void 0, ...activators, children: [
34741
34915
  !embed && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("style", { children: fontCss }),
34742
34916
  /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("header", { className: "dtop dbar", children: [
34743
34917
  embed ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "brand", children: [
@@ -34844,7 +35018,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34844
35018
  imported.warnings.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ul", { children: imported.warnings.map((w, i2) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("li", { children: w }, i2)) })
34845
35019
  ] }),
34846
35020
  dialog === "keys" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Dialog, { title: T("shortcuts"), onClose: () => setDialog(null), footer: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { className: "btn", onClick: () => setDialog(null), children: T("close") }), children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "kbd-grid", children: SHORTCUTS.map(([k, d]) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
34847
- import_react21.Fragment, { children: [
35021
+ import_react22.Fragment, { children: [
34848
35022
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "kbd", children: k }),
34849
35023
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: T(d) })
34850
35024
  ] }, d)) }) }),
@@ -34926,6 +35100,7 @@ var CSS2 = true ? `/* Layout: a drafting table. Cool grey workspace, white paper
34926
35100
  --ink: #16202a;
34927
35101
  --muted: #5f6b77;
34928
35102
  --faint: #64717e; /* 5:1 on panel (was #8e99a4, 2.9:1) */
35103
+ --faint-desk: #5a6672; /* small text on the desk: 4.85:1 on #e6eaee (--faint is 4.13:1 there) */
34929
35104
  --line-strong: #848f9b; /* control borders, 3:1 */
34930
35105
  --accent: #0e7490;
34931
35106
  --accent-ink: #ffffff;
@@ -34979,6 +35154,7 @@ var CSS2 = true ? `/* Layout: a drafting table. Cool grey workspace, white paper
34979
35154
  --ink: #e6edf3;
34980
35155
  --muted: #a3afbb;
34981
35156
  --faint: #8693a0;
35157
+ --faint-desk: #8693a0;
34982
35158
  --accent: #3cbfd4;
34983
35159
  --accent-ink: #03222a;
34984
35160
  --accent-soft: #123a44;
@@ -35317,7 +35493,7 @@ a.cell-name:hover { color: var(--accent); }
35317
35493
  .tbl .grip { position: absolute; left: -18px; top: -18px; width: 14px; height: 14px; border-radius: 3px; background: var(--panel-2); border: 1px solid var(--line); display: grid; place-items: center; cursor: move; font-size: var(--fs-2xs); color: var(--muted); }
35318
35494
  .tbl.sel .grip { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
35319
35495
  .tbl .row { position: relative; display: flex; }
35320
- .tbl .row-tag { position: absolute; left: -18px; width: 14px; display: grid; place-items: center; font: var(--fs-2xs) var(--mono); color: var(--faint); height: 100%; }
35496
+ .tbl .row-tag { position: absolute; left: -18px; width: 14px; display: grid; place-items: center; font: var(--fs-2xs) var(--mono); color: var(--faint-desk); height: 100%; }
35321
35497
  .tbl .cell { position: relative; overflow: hidden; display: flex; border-right: 1px dashed rgba(95,107,119,.3); border-bottom: 1px dashed rgba(95,107,119,.3); cursor: cell; }
35322
35498
  .tbl .cell:first-child { border-left: 1px dashed rgba(95,107,119,.3); }
35323
35499
  .tbl .row:first-child .cell { border-top: 1px dashed rgba(95,107,119,.3); }
@@ -35837,7 +36013,7 @@ input[type=checkbox], input[type=radio] { width: 16px; height: 16px; accent-colo
35837
36013
 
35838
36014
  .pw-embed{display:block;font:var(--fw-regular) var(--fs-base)/var(--lh) var(--ui);color:var(--ink);background:var(--desk);border:1px solid var(--line);border-radius:8px;overflow:hidden}
35839
36015
  ` : "";
35840
- var BLANK = { $schema: "pagewright/report@1", name: "New report", page: { size: "A4", margins: [36, 36, 36, 36] }, dataSources: [], dataSets: [], sections: { body: { items: [] } } };
36016
+ var BLANK = { $schema: "pagewright/report@1", name: "Untitled report", page: { size: "A4", margins: [36, 36, 36, 36] }, dataSources: [], dataSets: [], sections: { body: { items: [] } } };
35841
36017
  function mountDesigner(target, opts = {}) {
35842
36018
  const el = typeof target === "string" ? document.querySelector(target) : target;
35843
36019
  if (!el) throw new Error(`mountDesigner: no element for ${target}`);
@@ -35855,18 +36031,43 @@ function mountDesigner(target, opts = {}) {
35855
36031
  );
35856
36032
  box.style.height = opts.height || "760px";
35857
36033
  const root = (0, import_client.createRoot)(box);
36034
+ const store = newDesignerStore();
35858
36035
  const embed = { onSave: opts.onSave, onOpen: opts.onOpen, readOnly: !!opts.readOnly, toolbox: opts.toolbox, panels: opts.panels, dataSourceTemplates: opts.dataSourceTemplates, server: server2 };
35859
36036
  const show = (definition) => loadLanguage(opts.lang).catch(() => {
35860
- }).then(() => root.render((0, import_react22.createElement)(Designer, { id: opts.report, initial: definition, lang: opts.lang, embed })));
36037
+ }).then(() => root.render((0, import_react23.createElement)(Designer, { id: opts.report, initial: definition, lang: opts.lang, embed, store })));
35861
36038
  if (opts.definition || !opts.report) show(opts.definition || BLANK);
35862
36039
  else fetch(`${server2}/api/reports/${encodeURIComponent(opts.report)}`).then((r) => r.ok ? r.json() : r.json().then((j) => Promise.reject(new Error(j.error || `HTTP ${r.status}`)))).then(show).catch((e) => {
35863
36040
  box.innerHTML = `<div class="vmsg error">The report did not load: ${String(e.message).replace(/</g, "&lt;")}</div>`;
35864
36041
  });
36042
+ const onLeave = (e) => {
36043
+ e.preventDefault();
36044
+ e.returnValue = "";
36045
+ };
36046
+ let dirty = false;
36047
+ const unsub = store.subscribe((s) => {
36048
+ if (!s.saved === dirty) return;
36049
+ dirty = !s.saved;
36050
+ if (opts.warnOnLeave !== false) {
36051
+ if (dirty) window.addEventListener("beforeunload", onLeave);
36052
+ else window.removeEventListener("beforeunload", onLeave);
36053
+ }
36054
+ try {
36055
+ opts.onDirtyChange?.(dirty);
36056
+ } catch (e) {
36057
+ console.error(e);
36058
+ }
36059
+ });
35865
36060
  return {
35866
- unmount: () => root.unmount(),
36061
+ unmount: () => {
36062
+ unsub();
36063
+ window.removeEventListener("beforeunload", onLeave);
36064
+ root.unmount();
36065
+ },
36066
+ /** whether there are changes not saved yet */
36067
+ isDirty: () => !store.getState().saved,
35867
36068
  /** the definition as it is now (a plain copy) */
35868
- getDefinition: () => JSON.parse(JSON.stringify(useDesigner.getState().def)),
35869
- save: () => useDesigner.getState().save()
36069
+ getDefinition: () => JSON.parse(JSON.stringify(store.getState().def)),
36070
+ save: () => store.getState().save()
35870
36071
  };
35871
36072
  }
35872
36073
  export {