@reportwright/viewer 0.12.1 → 0.13.1

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 (101) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.md +18 -1
  3. package/THIRD-PARTY-NOTICES.md +52 -0
  4. package/dist/{chunk-DXHLIJEY.js → chunk-47ZAKRVN.js} +6 -6
  5. package/dist/{chunk-NR2G4TMG.js → chunk-B5ZCT3UK.js} +47 -26
  6. package/dist/chunk-B5ZCT3UK.js.map +6 -0
  7. package/dist/chunk-BR5K6SBL.js +324 -0
  8. package/dist/chunk-BR5K6SBL.js.map +6 -0
  9. package/dist/chunk-CCH7CFU5.js +5026 -0
  10. package/dist/chunk-CCH7CFU5.js.map +6 -0
  11. package/dist/{peer/chunk-BQFI3DHK.js → chunk-ES2LYZ6S.js} +292 -25
  12. package/dist/chunk-ES2LYZ6S.js.map +6 -0
  13. package/dist/{chunk-S2IUUI6N.js → chunk-GOCWG6FG.js} +67 -49
  14. package/dist/chunk-GOCWG6FG.js.map +6 -0
  15. package/dist/{chunk-3D2KFKG2.js → chunk-GRYITZPG.js} +11 -9
  16. package/dist/chunk-GRYITZPG.js.map +6 -0
  17. package/dist/{chunk-2BPBQMH2.js → chunk-H422SRD3.js} +8 -8
  18. package/dist/chunk-JD6EJ3LI.js +18 -0
  19. package/dist/{chunk-Z7MKH66Z.js → chunk-MS2LQC2O.js} +236 -12
  20. package/dist/chunk-MS2LQC2O.js.map +6 -0
  21. package/dist/{chunk-Q6MMPKQA.js → chunk-PF4RFKX2.js} +13 -12
  22. package/dist/chunk-PF4RFKX2.js.map +6 -0
  23. package/dist/{chunk-PGP3QA6L.js → chunk-PKXTMC4J.js} +1351 -75
  24. package/dist/chunk-PKXTMC4J.js.map +6 -0
  25. package/dist/{chunk-M6AYND5G.js → chunk-U2ZY2NPQ.js} +16 -7
  26. package/dist/chunk-U2ZY2NPQ.js.map +6 -0
  27. package/dist/{chunk-DPVJEFKP.js → chunk-WOBRKNIA.js} +13 -13
  28. package/dist/{chunk-DPVJEFKP.js.map → chunk-WOBRKNIA.js.map} +1 -1
  29. package/dist/chunk-XXTAPZO4.js +34 -0
  30. package/dist/{chunk-VNOWPSE6.js → chunk-ZGRJJ6OW.js} +1226 -887
  31. package/dist/chunk-ZGRJJ6OW.js.map +6 -0
  32. package/dist/designer.d.ts +11 -3
  33. package/dist/designer.js +598 -390
  34. package/dist/designer.js.map +3 -3
  35. package/dist/engine.worker.bwip.js +51422 -0
  36. package/dist/engine.worker.bwip.js.map +6 -0
  37. package/dist/engine.worker.js +59582 -26
  38. package/dist/engine.worker.js.map +3 -3
  39. package/dist/peer/{chunk-WSNRD2AQ.js → chunk-3EYYRJR4.js} +13 -12
  40. package/dist/{chunk-Q6MMPKQA.js.map → peer/chunk-3EYYRJR4.js.map} +1 -1
  41. package/dist/peer/{chunk-TSC4RAH3.js → chunk-3XZY54LM.js} +1351 -75
  42. package/dist/peer/chunk-3XZY54LM.js.map +6 -0
  43. package/dist/peer/chunk-5RUNOIS7.js +33 -0
  44. package/dist/peer/chunk-5RUNOIS7.js.map +6 -0
  45. package/dist/peer/{chunk-6I2EAAVN.js → chunk-7IP67PA6.js} +47 -26
  46. package/dist/peer/chunk-7IP67PA6.js.map +6 -0
  47. package/dist/peer/{chunk-R4VX5UC7.js → chunk-A6UXBSTP.js} +8 -8
  48. package/dist/peer/{chunk-V42KN7HD.js → chunk-CFTFTV2O.js} +6 -6
  49. package/dist/peer/chunk-JQTRDHQP.js +866 -0
  50. package/dist/peer/chunk-JQTRDHQP.js.map +6 -0
  51. package/dist/peer/chunk-KD6CDYGE.js +5024 -0
  52. package/dist/peer/chunk-KD6CDYGE.js.map +6 -0
  53. package/dist/peer/chunk-MXR6JBMP.js +546 -0
  54. package/dist/peer/chunk-MXR6JBMP.js.map +6 -0
  55. package/dist/peer/chunk-N42DCZZA.js +378 -0
  56. package/dist/peer/chunk-N42DCZZA.js.map +6 -0
  57. package/dist/{chunk-6TPZ7G74.js → peer/chunk-RKFP7SDY.js} +292 -25
  58. package/dist/peer/chunk-RKFP7SDY.js.map +6 -0
  59. package/dist/peer/{chunk-BMAXIBP2.js → chunk-WABYQWMT.js} +13 -13
  60. package/dist/peer/{chunk-BMAXIBP2.js.map → chunk-WABYQWMT.js.map} +1 -1
  61. package/dist/peer/chunk-WVQQCD4M.js +14211 -0
  62. package/dist/peer/chunk-WVQQCD4M.js.map +6 -0
  63. package/dist/peer/chunk-XHCRHVRK.js +17 -0
  64. package/dist/peer/chunk-XHCRHVRK.js.map +6 -0
  65. package/dist/peer/{chunk-WQGENQZO.js → chunk-ZS3J4WBH.js} +11 -9
  66. package/dist/peer/chunk-ZS3J4WBH.js.map +6 -0
  67. package/dist/peer/designer.js +455 -247
  68. package/dist/peer/designer.js.map +3 -3
  69. package/dist/peer/engine.worker.bwip.js +51422 -0
  70. package/dist/peer/engine.worker.bwip.js.map +6 -0
  71. package/dist/peer/engine.worker.js +59582 -25
  72. package/dist/peer/engine.worker.js.map +3 -3
  73. package/dist/peer/viewer.js +16 -12
  74. package/dist/peer/viewer.js.map +1 -1
  75. package/dist/viewer.d.ts +2 -1
  76. package/dist/viewer.js +16 -12
  77. package/dist/viewer.js.map +1 -1
  78. package/package.json +3 -2
  79. package/dist/chunk-3D2KFKG2.js.map +0 -6
  80. package/dist/chunk-6TPZ7G74.js.map +0 -6
  81. package/dist/chunk-BRB34AJ2.js +0 -16
  82. package/dist/chunk-M6AYND5G.js.map +0 -6
  83. package/dist/chunk-NR2G4TMG.js.map +0 -6
  84. package/dist/chunk-PGP3QA6L.js.map +0 -6
  85. package/dist/chunk-S2IUUI6N.js.map +0 -6
  86. package/dist/chunk-ULKEEARQ.js +0 -553
  87. package/dist/chunk-ULKEEARQ.js.map +0 -6
  88. package/dist/chunk-VNOWPSE6.js.map +0 -6
  89. package/dist/chunk-Z7MKH66Z.js.map +0 -6
  90. package/dist/peer/chunk-2FZTYEDE.js +0 -15
  91. package/dist/peer/chunk-6I2EAAVN.js.map +0 -6
  92. package/dist/peer/chunk-BQFI3DHK.js.map +0 -6
  93. package/dist/peer/chunk-TSC4RAH3.js.map +0 -6
  94. package/dist/peer/chunk-WQGENQZO.js.map +0 -6
  95. package/dist/peer/chunk-WSNRD2AQ.js.map +0 -6
  96. /package/dist/{chunk-DXHLIJEY.js.map → chunk-47ZAKRVN.js.map} +0 -0
  97. /package/dist/{chunk-2BPBQMH2.js.map → chunk-H422SRD3.js.map} +0 -0
  98. /package/dist/{chunk-BRB34AJ2.js.map → chunk-JD6EJ3LI.js.map} +0 -0
  99. /package/dist/{peer/chunk-2FZTYEDE.js.map → chunk-XXTAPZO4.js.map} +0 -0
  100. /package/dist/peer/{chunk-R4VX5UC7.js.map → chunk-A6UXBSTP.js.map} +0 -0
  101. /package/dist/peer/{chunk-V42KN7HD.js.map → chunk-CFTFTV2O.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-B5ZCT3UK.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-ES2LYZ6S.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,54 +54,52 @@ 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";
76
- import {
77
- TextMeasurer,
78
- finishText
79
- } from "./chunk-ULKEEARQ.js";
80
- import "./chunk-72S6DETS.js";
72
+ } from "./chunk-ZGRJJ6OW.js";
81
73
  import {
82
- currencyOf
83
- } from "./chunk-GJS242RR.js";
74
+ PAGE_SIZES,
75
+ fromPt,
76
+ normBox,
77
+ resolvePage,
78
+ toPt
79
+ } from "./chunk-BR5K6SBL.js";
84
80
  import "./chunk-F6RMRXIN.js";
85
81
  import {
86
82
  fontFaceCss,
87
83
  fontFamilyCss,
88
84
  pageToSvg
89
- } from "./chunk-M6AYND5G.js";
85
+ } from "./chunk-U2ZY2NPQ.js";
86
+ import "./chunk-72S6DETS.js";
90
87
  import {
91
88
  BUNDLED_FAMILIES,
92
89
  FONT_FAMILIES,
93
90
  allFontKeys,
94
91
  fallbackKeys,
95
92
  resolveFontKey
96
- } from "./chunk-Z7MKH66Z.js";
93
+ } from "./chunk-MS2LQC2O.js";
94
+ import {
95
+ currencyOf
96
+ } from "./chunk-GJS242RR.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,23 @@ 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
+ offsetCopy(f.list, copy);
8288
+ growToFit(d, { ...f, item: copy });
8253
8289
  f.list.push(copy);
8254
8290
  newIds.push(copy.id);
8255
8291
  }
8256
8292
  });
8257
8293
  if (newIds.length) S().select({ kind: "items", ids: newIds });
8258
8294
  }
8295
+ var PASTE_OFFSET = 12;
8296
+ function offsetCopy(list2, c) {
8297
+ for (const k of ["x", "y"]) if (!Number.isFinite(c[k])) c[k] = 0;
8298
+ for (let n = 0; n <= list2.length; n++) {
8299
+ c.x += PASTE_OFFSET;
8300
+ c.y += PASTE_OFFSET;
8301
+ if (!list2.some((i2) => i2 !== c && i2.x === c.x && i2.y === c.y)) return;
8302
+ }
8303
+ }
8259
8304
  var CLIP = "pagewright/items@1";
8260
8305
  async function copySelection() {
8261
8306
  const { sel, def } = S();
@@ -8270,43 +8315,40 @@ async function copySelection() {
8270
8315
  return items.length;
8271
8316
  }
8272
8317
  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;
8318
+ var clipOf = (text) => {
8282
8319
  try {
8283
- data = JSON.parse(text);
8320
+ const d = JSON.parse(text);
8321
+ return d?.kind === CLIP && Array.isArray(d.items) ? d : null;
8284
8322
  } catch {
8285
- return 0;
8323
+ return null;
8286
8324
  }
8287
- if (data?.kind !== CLIP || !Array.isArray(data.items)) return 0;
8325
+ };
8326
+ function pasteItems(section = "body", text = null) {
8327
+ const st = active;
8328
+ const data = clipOf(text) || clipOf(memClip);
8329
+ if (!data) return 0;
8288
8330
  const ids = [];
8289
- S().apply((d) => {
8331
+ st.getState().apply((d) => {
8290
8332
  const used = allNames(d);
8291
8333
  for (const it of data.items) {
8292
8334
  const c = cloneWithIds(it, used);
8293
- c.x += 12;
8294
- c.y += 12;
8295
8335
  if (c.type === "table" && !isBodyKey(section)) continue;
8336
+ offsetCopy(secOf(d, section).items, c);
8296
8337
  secOf(d, section).items.push(c);
8338
+ growToFit(d, { section, parent: null, item: c });
8297
8339
  ids.push(c.id);
8298
8340
  }
8299
8341
  });
8300
- if (ids.length) S().select({ kind: "items", ids });
8342
+ if (ids.length) st.getState().select({ kind: "items", ids });
8301
8343
  return ids.length;
8302
8344
  }
8303
- function rowsOf(t3, part, create2 = false) {
8345
+ function rowsOf(t3, part, create = false) {
8304
8346
  const m = /^g(\d+)([hf])$/.exec(part);
8305
8347
  const holder = m ? t3.groups?.[Number(m[1])] : t3;
8306
8348
  if (!holder) return null;
8307
8349
  const key2 = m ? m[2] === "h" ? "header" : "footer" : part;
8308
8350
  if (!holder[key2]) {
8309
- if (!create2) return [];
8351
+ if (!create) return [];
8310
8352
  holder[key2] = [];
8311
8353
  }
8312
8354
  return holder[key2];
@@ -8506,6 +8548,7 @@ function tableRemoveGroup(id, level) {
8506
8548
  }
8507
8549
  var IMAGE_MAX = 10 * 1024 * 1024;
8508
8550
  async function uploadImages(files, T) {
8551
+ const st = active;
8509
8552
  const names = [];
8510
8553
  let err = null;
8511
8554
  for (const f of files) {
@@ -8524,7 +8567,7 @@ async function uploadImages(files, T) {
8524
8567
  r.readAsDataURL(f);
8525
8568
  });
8526
8569
  const base2 = f.name.replace(/\.[^.]+$/, "").replace(/\W+/g, "_").replace(/^_+|_+$/g, "") || "image";
8527
- S().apply((d) => {
8570
+ st.getState().apply((d) => {
8528
8571
  d.images || (d.images = {});
8529
8572
  let n = base2, k = 2;
8530
8573
  while (d.images[n]) n = `${base2}${k++}`;
@@ -8591,6 +8634,13 @@ function wouldOverlap(def, ids, rectOf2) {
8591
8634
  }
8592
8635
  return false;
8593
8636
  }
8637
+ function setMatrixShow(v, show) {
8638
+ const pct = !!show && show !== "value";
8639
+ if (pct) v.show = show;
8640
+ else delete v.show;
8641
+ if (pct && (!v.format || v.format === "N0")) v.format = "P1";
8642
+ else if (!pct && v.format === "P1") v.format = "N0";
8643
+ }
8594
8644
 
8595
8645
  // src/designer/ui.jsx
8596
8646
  var import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
@@ -8602,8 +8652,8 @@ function TextInput({ value, onChange, mono, invalid, className, ...rest }) {
8602
8652
  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
8653
  }
8604
8654
  function NumberInput({ value, onChange, step = 0.5, min, ...rest }) {
8605
- const [draft, setDraft] = (0, import_react2.useState)(value ?? "");
8606
- (0, import_react2.useEffect)(() => {
8655
+ const [draft, setDraft] = (0, import_react3.useState)(value ?? "");
8656
+ (0, import_react3.useEffect)(() => {
8607
8657
  setDraft(value ?? "");
8608
8658
  }, [value]);
8609
8659
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -8639,18 +8689,18 @@ function ColorInput({ value, onChange }) {
8639
8689
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextInput, { value, onChange: (v) => onChange(v === "" ? void 0 : v), mono: true, placeholder: T("i_colorPh") })
8640
8690
  ] });
8641
8691
  }
8642
- var FieldScope = (0, import_react2.createContext)(void 0);
8692
+ var FieldScope = (0, import_react3.createContext)(void 0);
8643
8693
  var issueText = (T, i2) => i2.suggest ? T("ux_unknownFieldSuggest", { name: i2.name, suggest: i2.suggest }) : T("ux_unknownField", { name: i2.name });
8644
8694
  function ExprInput({ value, onChange, onOpen, placeholder: placeholder2 }) {
8645
8695
  const T = useT();
8646
- const scope = (0, import_react2.useContext)(FieldScope);
8696
+ const scope = (0, import_react3.useContext)(FieldScope);
8647
8697
  const dataSets = useDesigner((s) => s.def?.dataSets);
8648
8698
  const err = value ? checkValue(value) : null;
8649
8699
  const issues = !err && value && scope !== void 0 ? fieldIssues(value, dataSets, scope) : [];
8650
8700
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
8651
8701
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "expr-row", children: [
8652
8702
  /* @__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" })
8703
+ /* @__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
8704
  ] }),
8655
8705
  err && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "err", children: err }),
8656
8706
  issues.map((i2, k) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "warn", "data-testid": "field-warning", children: issueText(T, i2) }, k))
@@ -8670,14 +8720,19 @@ function Check({ label, checked, onChange }) {
8670
8720
  ] });
8671
8721
  }
8672
8722
  function Dialog({ title, children, onClose, footer, wide, className = "" }) {
8673
- (0, import_react2.useEffect)(() => {
8723
+ const ref = (0, import_react3.useRef)(null);
8724
+ (0, import_react3.useEffect)(() => {
8725
+ const inOther = (e) => {
8726
+ const mine = ref.current?.closest(".designer");
8727
+ return e.composedPath().some((n) => n !== mine && n?.classList?.contains("designer"));
8728
+ };
8674
8729
  const k = (e) => {
8675
- if (e.key === "Escape" && !e.defaultPrevented) onClose();
8730
+ if (e.key === "Escape" && !e.defaultPrevented && !inOther(e)) onClose();
8676
8731
  };
8677
8732
  window.addEventListener("keydown", k);
8678
8733
  return () => window.removeEventListener("keydown", k);
8679
8734
  }, [onClose]);
8680
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "scrim", onPointerDown: (e) => {
8735
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "scrim", ref, onPointerDown: (e) => {
8681
8736
  if (e.target === e.currentTarget) onClose();
8682
8737
  }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `dialog${wide ? " wide" : ""}${className ? ` ${className}` : ""}`, role: "dialog", "aria-modal": "true", "aria-label": title, children: [
8683
8738
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("header", { children: title }),
@@ -8687,20 +8742,20 @@ function Dialog({ title, children, onClose, footer, wide, className = "" }) {
8687
8742
  }
8688
8743
 
8689
8744
  // src/embed/link.js
8690
- var import_react3 = __toESM(require_react(), 1);
8745
+ var import_react4 = __toESM(require_react(), 1);
8691
8746
  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);
8747
+ return (0, import_react4.createElement)("a", { href: typeof href === "string" ? href : String(href?.pathname || ""), ...rest }, children);
8693
8748
  }
8694
8749
 
8695
8750
  // src/designer/SvgHtml.jsx
8696
- var import_react4 = __toESM(require_react(), 1);
8751
+ var import_react5 = __toESM(require_react(), 1);
8697
8752
  var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
8698
8753
  function SvgHtml({ html, as: Tag2 = "span", ...rest }) {
8699
- const ref = (0, import_react4.useRef)(
8754
+ const ref = (0, import_react5.useRef)(
8700
8755
  /** @type {HTMLElement|null} */
8701
8756
  null
8702
8757
  );
8703
- (0, import_react4.useLayoutEffect)(() => {
8758
+ (0, import_react5.useLayoutEffect)(() => {
8704
8759
  if (!ref.current) return;
8705
8760
  ref.current.innerHTML = deferStyleAttributes(html);
8706
8761
  applyStyleAttributes(ref.current);
@@ -8709,7 +8764,7 @@ function SvgHtml({ html, as: Tag2 = "span", ...rest }) {
8709
8764
  }
8710
8765
 
8711
8766
  // src/designer/Canvas.jsx
8712
- var import_react7 = __toESM(require_react(), 1);
8767
+ var import_react8 = __toESM(require_react(), 1);
8713
8768
 
8714
8769
  // src/designer/tableGen.js
8715
8770
  var HEAD = { fontWeight: "bold", backgroundColor: "#f1f5f9", borderBottom: "0.75 solid #94a3b8" };
@@ -8841,24 +8896,28 @@ function instantPicks(fields, rows = []) {
8841
8896
  }
8842
8897
 
8843
8898
  // src/designer/Reuse.jsx
8844
- var import_react6 = __toESM(require_react(), 1);
8899
+ var import_react7 = __toESM(require_react(), 1);
8845
8900
 
8846
8901
  // src/designer/Fonts.jsx
8847
- var import_react5 = __toESM(require_react(), 1);
8902
+ var import_react6 = __toESM(require_react(), 1);
8848
8903
  var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
8849
8904
  function useFontFamilies() {
8850
8905
  const fonts = useDesigner((s) => s.fonts);
8851
8906
  return [...BUNDLED_FAMILIES, ...[...new Set(fonts.map((f) => f.family))].sort()];
8852
8907
  }
8853
- var refresh = async () => useDesigner.getState().setUi({ fonts: await customFonts(true) });
8908
+ var refresh = async () => {
8909
+ const api = activeStore2();
8910
+ const fonts = await customFonts(true);
8911
+ api.getState().setUi({ fonts });
8912
+ };
8854
8913
  function FontsDialog({ onClose }) {
8855
8914
  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);
8915
+ const [file, setFile] = (0, import_react6.useState)(null);
8916
+ const [family, setFamily] = (0, import_react6.useState)("");
8917
+ const [weight, setWeight] = (0, import_react6.useState)("");
8918
+ const [style, setStyle] = (0, import_react6.useState)("");
8919
+ const [busy, setBusy] = (0, import_react6.useState)(false);
8920
+ const [msg, setMsg] = (0, import_react6.useState)(null);
8862
8921
  const upload = async () => {
8863
8922
  if (!file) return;
8864
8923
  setBusy(true);
@@ -8949,30 +9008,33 @@ var apply = (fn3, key2) => S2().apply(fn3, key2);
8949
9008
  var server = () => S2().embed?.server || "";
8950
9009
  var noServer = () => !!S2().embed && !S2().embed.server;
8951
9010
  var pending = /* @__PURE__ */ new Map();
8952
- function fetchReused(id, force = false) {
9011
+ function fetchReused(id, force = false, api = activeStore2()) {
8953
9012
  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 } }));
9013
+ const st = api.getState();
9014
+ if (!force && st.reused[id]) return Promise.resolve(st.reused[id]);
9015
+ const server2 = st.embed?.server || "", key2 = `${server2} ${id}`;
9016
+ const keep = (d) => {
9017
+ api.setState((s) => ({ reused: { ...s.reused, [id]: d } }));
8960
9018
  return d;
8961
- });
8962
- pending.set(id, p);
8963
- return p;
9019
+ };
9020
+ if (pending.has(key2)) return pending.get(key2).then(keep);
9021
+ if (st.embed && !server2) return Promise.resolve(null);
9022
+ 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));
9023
+ pending.set(key2, p);
9024
+ return p.then(keep);
8964
9025
  }
8965
9026
  function useReused(id) {
9027
+ const api = useDesignerStore();
8966
9028
  const d = useDesigner((s) => id ? s.reused[id] : void 0);
8967
- (0, import_react6.useEffect)(() => {
8968
- fetchReused(id);
8969
- }, [id]);
9029
+ (0, import_react7.useEffect)(() => {
9030
+ fetchReused(id, false, api);
9031
+ }, [id, api]);
8970
9032
  return d && !d.__error ? d : null;
8971
9033
  }
8972
9034
  var listCache = null;
8973
9035
  function ReportSelect({ value, onChange, exclude, ...rest }) {
8974
- const [list2, setList] = (0, import_react6.useState)(listCache || []);
8975
- (0, import_react6.useEffect)(() => {
9036
+ const [list2, setList] = (0, import_react7.useState)(listCache || []);
9037
+ (0, import_react7.useEffect)(() => {
8976
9038
  if (noServer()) return;
8977
9039
  fetch(`${server()}/api/reports`).then((r) => r.ok ? r.json() : []).then((l) => {
8978
9040
  listCache = Array.isArray(l) ? l : [];
@@ -9039,7 +9101,7 @@ function ThemeSection() {
9039
9101
  const id = useDesigner((s) => s.id);
9040
9102
  const families = useFontFamilies();
9041
9103
  const src = def.theme;
9042
- const [mode, setMode] = (0, import_react6.useState)(!src ? "own" : String(src).startsWith("=") ? "expr" : "report");
9104
+ const [mode, setMode] = (0, import_react7.useState)(!src ? "own" : String(src).startsWith("=") ? "expr" : "report");
9043
9105
  const td = def.themeDef || {};
9044
9106
  const setTd = (fn3, key2) => apply((d) => {
9045
9107
  d.themeDef || (d.themeDef = {});
@@ -9058,7 +9120,7 @@ function ThemeSection() {
9058
9120
  else x.fonts[k][p] = v;
9059
9121
  }, `theme.font.${k}.${p}`);
9060
9122
  const consts = Object.entries(td.constants || {});
9061
- const [newConst, setNewConst] = (0, import_react6.useState)("");
9123
+ const [newConst, setNewConst] = (0, import_react7.useState)("");
9062
9124
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "cat", "data-testid": "theme", children: [
9063
9125
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CatHead, { children: T("theme") }),
9064
9126
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Field, { label: T("themeSource"), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
@@ -9118,7 +9180,7 @@ function LayersPanel() {
9118
9180
  const T = useT2();
9119
9181
  const layers = useDesigner((s) => s.def.layers) || [];
9120
9182
  const readOnly2 = useDesigner((s) => s.readOnly);
9121
- const [name2, setName] = (0, import_react6.useState)("");
9183
+ const [name2, setName] = (0, import_react7.useState)("");
9122
9184
  const set2 = (fn3, key2) => apply((d) => {
9123
9185
  d.layers || (d.layers = []);
9124
9186
  fn3(d.layers, d);
@@ -9273,7 +9335,7 @@ function PartsPanel() {
9273
9335
  const libs = useDesigner((s) => s.def.libraries) || [];
9274
9336
  const id = useDesigner((s) => s.id);
9275
9337
  const readOnly2 = useDesigner((s) => s.readOnly);
9276
- const [pick, setPick] = (0, import_react6.useState)("");
9338
+ const [pick, setPick] = (0, import_react7.useState)("");
9277
9339
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "pane", "data-testid": "parts-panel", children: [
9278
9340
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("h4", { children: [
9279
9341
  T("parts"),
@@ -9402,7 +9464,7 @@ function PublishPart({ item }) {
9402
9464
  if (v === void 0 || v === "") delete q2[k];
9403
9465
  else q2[k] = v;
9404
9466
  }, `part${i2}.q${j}.${k}`);
9405
- const [newProp, setNewProp] = (0, import_react6.useState)("");
9467
+ const [newProp, setNewProp] = (0, import_react7.useState)("");
9406
9468
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "cat", "data-testid": "publish-part", children: [
9407
9469
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CatHead, { children: T("reportPart") }),
9408
9470
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Check, { label: T("publishPart"), checked: !!p, onChange: (on) => set2((l) => {
@@ -9531,12 +9593,12 @@ function useDesignIssues() {
9531
9593
  const def = useDesigner((s) => s.def);
9532
9594
  const extents = useDesigner((s) => s.extents);
9533
9595
  const saveCheck = useDesigner((s) => s.saveCheck);
9534
- return (0, import_react7.useMemo)(() => {
9596
+ return (0, import_react8.useMemo)(() => {
9535
9597
  const bands = sectionList(def).map((s) => ({ key: s.key, items: secOf(def, s.key)?.items || [], width: bodyWidth(def, s.key) }));
9536
9598
  return [...designIssues(def, bands, extents || {}), ...checkIssues(bands, [...validate(def).errors, ...saveCheck?.missing || []])];
9537
9599
  }, [def, extents, saveCheck]);
9538
9600
  }
9539
- var IssueMap = (0, import_react7.createContext)(/* @__PURE__ */ new Map());
9601
+ var IssueMap = (0, import_react8.createContext)(/* @__PURE__ */ new Map());
9540
9602
  function issueLine(T, i2) {
9541
9603
  if (i2.kind === "overlap") return T("ux_issueOverlap", { name: i2.name, other: i2.other });
9542
9604
  if (i2.kind === "wide") return T("ux_issueWide", { name: i2.name, width: i2.width, room: i2.room });
@@ -9601,9 +9663,9 @@ function Canvas() {
9601
9663
  const bands = sectionList(def);
9602
9664
  const widths2 = Object.fromEntries(bands.map((s) => [s.key, bodyWidth(def, s.key)]));
9603
9665
  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)(() => {
9666
+ const scrollRef = (0, import_react8.useRef)(null);
9667
+ const [fitW, setFitW] = (0, import_react8.useState)(0);
9668
+ (0, import_react8.useEffect)(() => {
9607
9669
  if (zoom !== "fit" || !scrollRef.current) return;
9608
9670
  const el = scrollRef.current;
9609
9671
  const ro = new ResizeObserver(() => setFitW(el.clientWidth));
@@ -9611,10 +9673,10 @@ function Canvas() {
9611
9673
  return () => ro.disconnect();
9612
9674
  }, [zoom]);
9613
9675
  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);
9676
+ const [drag, setDrag] = (0, import_react8.useState)(null);
9615
9677
  const T = useT2();
9616
9678
  const issues = useDesignIssues();
9617
- const byId = (0, import_react7.useMemo)(() => {
9679
+ const byId = (0, import_react8.useMemo)(() => {
9618
9680
  const m = /* @__PURE__ */ new Map();
9619
9681
  for (const i2 of issues) m.set(i2.id, [...m.get(i2.id) || [], issueLine(T, i2)]);
9620
9682
  return m;
@@ -9695,9 +9757,9 @@ function Band({ section, label, scale, bw: bandW, drag, setDrag, phBox = null })
9695
9757
  const off = phBox || mb?.off || null;
9696
9758
  const contentList = useDesigner((s) => s.def.sections?.content);
9697
9759
  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);
9760
+ const ref = (0, import_react8.useRef)(null);
9761
+ const [marquee, setMarquee] = (0, import_react8.useState)(null);
9762
+ const [dropping, setDropping] = (0, import_react8.useState)(false);
9701
9763
  const h = drag?.mode === "band" && drag.section === section ? drag.h : sec.height || 0;
9702
9764
  const DROP_ROOM = 96;
9703
9765
  const toPt3 = (e) => {
@@ -9871,8 +9933,9 @@ var alerted = 0;
9871
9933
  function alertOnce(msg) {
9872
9934
  if (Date.now() - alerted > 3e3) {
9873
9935
  alerted = Date.now();
9874
- useDesigner.setState({ saveError: msg });
9875
- setTimeout(() => useDesigner.setState({ saveError: null }), 3e3);
9936
+ const api = activeStore2();
9937
+ api.setState({ saveError: msg });
9938
+ setTimeout(() => api.setState({ saveError: null }), 3e3);
9876
9939
  }
9877
9940
  }
9878
9941
  function fieldStyle(f) {
@@ -9880,11 +9943,31 @@ function fieldStyle(f) {
9880
9943
  const format = formatFor({ name: f.field, type: f.type }, (st.sample?.dataSets?.[f.dataSet] || []).slice(0, 200), { currency: st.def?.currency });
9881
9944
  return format ? { format } : {};
9882
9945
  }
9946
+ function useItemKeys(item) {
9947
+ const T = useT2();
9948
+ const type = T(`item_${item.type}`) === `item_${item.type}` ? ITEMS[item.type]?.label || item.type : T(`item_${item.type}`);
9949
+ return {
9950
+ tabIndex: 0,
9951
+ role: "group",
9952
+ "data-item-key": item.id,
9953
+ "aria-label": T("b9_itemLabel", { type, name: item.name, x: round(item.x), y: round(item.y) }),
9954
+ onKeyDown: (e) => {
9955
+ if (e.target !== e.currentTarget || e.key !== "Enter" && e.key !== " ") return;
9956
+ e.preventDefault();
9957
+ e.stopPropagation();
9958
+ const st = useDesigner.getState();
9959
+ const cur2 = st.sel.kind === "items" ? st.sel.ids : [];
9960
+ const ids = !e.shiftKey ? [item.id] : cur2.includes(item.id) ? cur2.filter((i2) => i2 !== item.id) : [...cur2, item.id];
9961
+ st.select(ids.length ? { kind: "items", ids } : { kind: "report" });
9962
+ }
9963
+ };
9964
+ }
9883
9965
  function useItemDrag(item, scale, setDrag) {
9884
9966
  return (e) => {
9885
9967
  if (e.button !== 0) return;
9886
9968
  e.preventDefault();
9887
9969
  e.stopPropagation();
9970
+ e.currentTarget.closest?.("[data-item-key]")?.focus({ preventScroll: true });
9888
9971
  const st = useDesigner.getState();
9889
9972
  let ids;
9890
9973
  if (e.shiftKey) {
@@ -9957,8 +10040,8 @@ function AnyItem(props) {
9957
10040
  return layer?.locked ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "layer-locked", "data-locked": props.item.name, children: el }) : el;
9958
10041
  }
9959
10042
  function NestChildren({ item, scale, drag, setDrag, section }) {
9960
- const ref = (0, import_react7.useRef)(null);
9961
- const [over, setOver] = (0, import_react7.useState)(false);
10043
+ const ref = (0, import_react8.useRef)(null);
10044
+ const [over, setOver] = (0, import_react8.useState)(false);
9962
10045
  const accepts = (e) => e.dataTransfer.types.includes(MIME_TOOL) || e.dataTransfer.types.includes(MIME_FIELD) || e.dataTransfer.types.includes(MIME_PART);
9963
10046
  const onDrop = (e) => {
9964
10047
  setOver(false);
@@ -10003,8 +10086,9 @@ function ItemView({ item, scale, drag, setDrag, bw, nest, section }) {
10003
10086
  const selected = useDesigner((s) => s.sel.kind === "items" && s.sel.ids.includes(item.id));
10004
10087
  const single = useDesigner((s) => s.sel.kind === "items" && s.sel.ids.length === 1);
10005
10088
  const onDown = useItemDrag(item, scale, setDrag);
10089
+ const keys = useItemKeys(item);
10006
10090
  const r = rectOf(item, drag);
10007
- const problems = (0, import_react7.useContext)(IssueMap).get(item.id);
10091
+ const problems = (0, import_react8.useContext)(IssueMap).get(item.id);
10008
10092
  const onHandle = (dir) => (e) => {
10009
10093
  e.preventDefault();
10010
10094
  e.stopPropagation();
@@ -10063,6 +10147,7 @@ function ItemView({ item, scale, drag, setDrag, bw, nest, section }) {
10063
10147
  title: problems?.join("\n"),
10064
10148
  style: { left: r.x * scale, top: r.y * scale, width: Math.max(r.w * scale, 2), height: Math.max(r.h * scale, 2) },
10065
10149
  onPointerDown: onDown,
10150
+ ...keys,
10066
10151
  children: [
10067
10152
  nest ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NestBox, { item: { ...item, ...r }, scale }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ItemBody, { item: { ...item, ...r }, scale }),
10068
10153
  nest && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NestChildren, { item, scale, drag, setDrag, section }),
@@ -10080,8 +10165,8 @@ function NestBox({ item, scale }) {
10080
10165
  }
10081
10166
  var LIVE = /* @__PURE__ */ new Set(["chart", "matrix", "barcode", "sparkline", "databar", "bullet", "iconset", "rangebar", "richtext"]);
10082
10167
  var measurer = null;
10083
- async function paintItemSvg(shape2, def, sample) {
10084
- const store = fontStore();
10168
+ async function paintItemSvg(shape2, def, sample, api = activeStore2()) {
10169
+ const store = await loadFontStore();
10085
10170
  await Promise.all([store.load(), customFonts()]);
10086
10171
  if (shape2.type === "barcode" || hasType(shape2.items, "barcode")) await loadBarcodes();
10087
10172
  measurer || (measurer = new TextMeasurer(store));
@@ -10092,7 +10177,7 @@ async function paintItemSvg(shape2, def, sample) {
10092
10177
  } catch {
10093
10178
  }
10094
10179
  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);
10180
+ const theme3 = themeContext(typeof def.theme === "string" && api.getState().reused[def.theme]?.themeDef || def.themeDef);
10096
10181
  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
10182
  let seq = 0;
10098
10183
  const lc = {
@@ -10134,20 +10219,21 @@ async function paintItemSvg(shape2, def, sample) {
10134
10219
  return { html: pageToSvg({ items }, shape2.w, h, { background: false }), h, w };
10135
10220
  }
10136
10221
  function LivePreview({ item, scale }) {
10222
+ const api = useDesignerStore();
10137
10223
  const sample = useDesigner((s) => s.sample);
10138
10224
  const def = useDesigner((s) => s.def);
10139
- const [svg, setSvg] = (0, import_react7.useState)(null);
10225
+ const [svg, setSvg] = (0, import_react8.useState)(null);
10140
10226
  const { x, y, ...shape2 } = item;
10141
10227
  const key2 = JSON.stringify(shape2);
10142
- (0, import_react7.useEffect)(() => {
10228
+ (0, import_react8.useEffect)(() => {
10143
10229
  let alive = true;
10144
10230
  const t3 = setTimeout(async () => {
10145
10231
  try {
10146
- const out = await paintItemSvg(shape2, def, sample);
10232
+ const out = await paintItemSvg(shape2, def, sample, api);
10147
10233
  if (alive) {
10148
10234
  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 } } });
10235
+ const ex2 = api.getState().extents || {};
10236
+ if (Math.round(ex2[item.id]?.w || 0) !== Math.round(out.w)) api.setState({ extents: { ...ex2, [item.id]: { w: out.w } } });
10151
10237
  }
10152
10238
  } catch (e) {
10153
10239
  if (alive) setSvg({ error: e.message });
@@ -10169,9 +10255,9 @@ function PartPreview({ item, scale }) {
10169
10255
  const p = (lib?.parts || []).find((q2) => q2.name === item.part);
10170
10256
  const src = p && findItemNamed(lib, p.item);
10171
10257
  const props = { ...Object.fromEntries((p?.properties || []).map((q2) => [q2.name, q2.default ?? null])), ...item.properties || {} };
10172
- const [svg, setSvg] = (0, import_react7.useState)(null);
10258
+ const [svg, setSvg] = (0, import_react8.useState)(null);
10173
10259
  const key2 = JSON.stringify([src, props]);
10174
- (0, import_react7.useEffect)(() => {
10260
+ (0, import_react8.useEffect)(() => {
10175
10261
  if (!src) return void 0;
10176
10262
  let alive = true;
10177
10263
  const t3 = setTimeout(() => {
@@ -10281,17 +10367,18 @@ function TableView({ item, scale, drag, setDrag }) {
10281
10367
  const readOnly2 = useDesigner((s) => s.readOnly);
10282
10368
  const tableSelected = sel.kind === "items" && sel.ids.includes(item.id);
10283
10369
  const onGrip = useItemDrag(item, scale, setDrag);
10370
+ const keys = useItemKeys(item);
10284
10371
  const r = rectOf(item, drag);
10285
10372
  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);
10373
+ const [dropCell, setDropCell] = (0, import_react8.useState)(null);
10374
+ const [menu, setMenu] = (0, import_react8.useState)(null);
10375
+ const problems = (0, import_react8.useContext)(IssueMap).get(item.id);
10376
+ const tblRef = (0, import_react8.useRef)(null);
10290
10377
  const chosen = sel.kind === "cell" && sel.id === item.id ? selCells(sel) : [];
10291
- (0, import_react7.useEffect)(() => {
10378
+ (0, import_react8.useEffect)(() => {
10292
10379
  if (!menu) return void 0;
10293
10380
  const close = (e) => {
10294
- if (e.type === "keydown" ? e.key === "Escape" : !e.target.closest?.(".cell-menu")) setMenu(null);
10381
+ if (e.type === "keydown" ? e.key === "Escape" : !e.composedPath().some((n) => n.classList?.contains("cell-menu"))) setMenu(null);
10295
10382
  };
10296
10383
  window.addEventListener("pointerdown", close, true);
10297
10384
  window.addEventListener("keydown", close);
@@ -10304,6 +10391,7 @@ function TableView({ item, scale, drag, setDrag }) {
10304
10391
  e.stopPropagation();
10305
10392
  if (e.button !== 0) return;
10306
10393
  e.preventDefault();
10394
+ e.currentTarget.closest("[data-item-key]")?.focus({ preventScroll: true });
10307
10395
  const st = useDesigner.getState();
10308
10396
  const here = { part, row: ri, col: ci };
10309
10397
  const cur2 = st.sel.kind === "cell" && st.sel.id === item.id ? st.sel : null;
@@ -10379,7 +10467,7 @@ function TableView({ item, scale, drag, setDrag }) {
10379
10467
  const h = t3.header?.[t3.header.length - 1]?.cells?.[ci];
10380
10468
  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
10469
  if (h && f.type === "number") h.style = { ...h.style || {}, textAlign: "right" };
10382
- } else if ((part === "footer" || /^g\d+f$/.test(part)) && f.type === "number") {
10470
+ } else if ((part === "footer" || /^g\d+[hf]$/.test(part)) && f.type === "number") {
10383
10471
  cell.value = `=Sum(Fields.${f.field})`;
10384
10472
  cell.style = { ...cell.style || {}, ...fieldStyle(f) };
10385
10473
  } else cell.value = `=Fields.${f.field}`;
@@ -10387,7 +10475,7 @@ function TableView({ item, scale, drag, setDrag }) {
10387
10475
  useDesigner.getState().select({ kind: "cell", id: item.id, part, row: ri, col: ci });
10388
10476
  };
10389
10477
  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: [
10478
+ 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
10479
  problems && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "issue-tag", title: problems.join("\n"), "aria-label": problems.join(". "), children: "!" }),
10392
10480
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "grip", title: "Select or move the table", onPointerDown: onGrip, children: "⠿" }),
10393
10481
  /* @__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 +10605,13 @@ function TableView({ item, scale, drag, setDrag }) {
10517
10605
  }
10518
10606
 
10519
10607
  // src/designer/Inspector.jsx
10520
- var import_react11 = __toESM(require_react(), 1);
10608
+ var import_react12 = __toESM(require_react(), 1);
10521
10609
 
10522
10610
  // src/designer/ExpressionEditor.jsx
10523
- var import_react9 = __toESM(require_react(), 1);
10611
+ var import_react10 = __toESM(require_react(), 1);
10524
10612
 
10525
10613
  // src/designer/ExprCode.jsx
10526
- var import_react8 = __toESM(require_react(), 1);
10614
+ var import_react9 = __toESM(require_react(), 1);
10527
10615
 
10528
10616
  // node_modules/@marijn/find-cluster-break/src/index.js
10529
10617
  var rangeFrom = [];
@@ -12267,8 +12355,8 @@ var StateField = class _StateField {
12267
12355
  way it is initialized. Can be useful when you need to provide a
12268
12356
  non-default starting value for the field.
12269
12357
  */
12270
- init(create2) {
12271
- return [this, initField.of({ field: this, create: create2 })];
12358
+ init(create) {
12359
+ return [this, initField.of({ field: this, create })];
12272
12360
  }
12273
12361
  /**
12274
12362
  State field instances can be used as
@@ -13496,10 +13584,10 @@ var RangeSet = class _RangeSet {
13496
13584
  for (; ; ) {
13497
13585
  let curTo = Math.min(cursor.to, to);
13498
13586
  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);
13587
+ let active2 = cursor.activeForPoint(cursor.to);
13588
+ let openCount = cursor.pointFrom < from ? active2.length + 1 : cursor.point.startSide < 0 ? active2.length : Math.min(active2.length, openRanges);
13589
+ iterator.point(pos, curTo, cursor.point, active2, openCount, cursor.pointRank);
13590
+ openRanges = Math.min(cursor.openEnd(curTo), active2.length);
13503
13591
  } else if (curTo > pos) {
13504
13592
  iterator.span(pos, curTo, cursor.active, openRanges);
13505
13593
  openRanges = cursor.openEnd(curTo);
@@ -13913,14 +14001,14 @@ var SpanCursor = class {
13913
14001
  activeForPoint(to) {
13914
14002
  if (!this.active.length)
13915
14003
  return this.active;
13916
- let active = [];
14004
+ let active2 = [];
13917
14005
  for (let i2 = this.active.length - 1; i2 >= 0; i2--) {
13918
14006
  if (this.activeRank[i2] < this.pointRank)
13919
14007
  break;
13920
14008
  if (this.activeTo[i2] > to || this.activeTo[i2] == to && this.active[i2].endSide >= this.point.endSide)
13921
- active.push(this.active[i2]);
14009
+ active2.push(this.active[i2]);
13922
14010
  }
13923
- return active.reverse();
14011
+ return active2.reverse();
13924
14012
  }
13925
14013
  openEnd(to) {
13926
14014
  let open = 0;
@@ -15439,9 +15527,9 @@ var viewPlugin = /* @__PURE__ */ Facet.define({
15439
15527
  }
15440
15528
  });
15441
15529
  var ViewPlugin = class _ViewPlugin {
15442
- constructor(id, create2, domEventHandlers, domEventObservers, buildExtensions) {
15530
+ constructor(id, create, domEventHandlers, domEventObservers, buildExtensions) {
15443
15531
  this.id = id;
15444
- this.create = create2;
15532
+ this.create = create;
15445
15533
  this.domEventHandlers = domEventHandlers;
15446
15534
  this.domEventObservers = domEventObservers;
15447
15535
  this.baseExtensions = buildExtensions(this);
@@ -15457,9 +15545,9 @@ var ViewPlugin = class _ViewPlugin {
15457
15545
  Define a plugin from a constructor function that creates the
15458
15546
  plugin's value, given an editor view.
15459
15547
  */
15460
- static define(create2, spec) {
15548
+ static define(create, spec) {
15461
15549
  const { eventHandlers, eventObservers, provide, decorations: deco } = spec || {};
15462
- return new _ViewPlugin(nextPluginID++, create2, eventHandlers, eventObservers, (plugin) => {
15550
+ return new _ViewPlugin(nextPluginID++, create, eventHandlers, eventObservers, (plugin) => {
15463
15551
  let ext = [];
15464
15552
  if (deco)
15465
15553
  ext.push(decorations.of((view) => {
@@ -15547,11 +15635,11 @@ function getIsolatedRanges(view, line2) {
15547
15635
  RangeSet.spans(sets, line2.from, line2.to, {
15548
15636
  point() {
15549
15637
  },
15550
- span(fromDoc, toDoc, active, open) {
15638
+ span(fromDoc, toDoc, active2, open) {
15551
15639
  let from = fromDoc - line2.from, to = toDoc - line2.from;
15552
15640
  let level = result;
15553
- for (let i2 = active.length - 1; i2 >= 0; i2--, open--) {
15554
- let direction = active[i2].spec.bidiIsolate, update;
15641
+ for (let i2 = active2.length - 1; i2 >= 0; i2--, open--) {
15642
+ let direction = active2[i2].spec.bidiIsolate, update;
15555
15643
  if (direction == null)
15556
15644
  direction = autoDirection(line2.text, from, to);
15557
15645
  if (open > 0 && level.length && (update = level[level.length - 1]).to == from && update.direction == direction) {
@@ -16781,7 +16869,7 @@ var TileUpdate = class {
16781
16869
  let pendingLineAttrs = null;
16782
16870
  let b = this.builder, markCount = -1;
16783
16871
  let openEnd = RangeSet.spans(this.decorations, from, to, {
16784
- point: (from2, to2, deco, active, openStart, index) => {
16872
+ point: (from2, to2, deco, active2, openStart, index) => {
16785
16873
  if (deco instanceof PointDecoration) {
16786
16874
  if (this.disallowBlockEffectsFor[index]) {
16787
16875
  if (deco.block)
@@ -16789,8 +16877,8 @@ var TileUpdate = class {
16789
16877
  if (to2 > this.view.state.doc.lineAt(from2).to)
16790
16878
  throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
16791
16879
  }
16792
- markCount = active.length;
16793
- if (openStart > active.length) {
16880
+ markCount = active2.length;
16881
+ if (openStart > active2.length) {
16794
16882
  b.continueWidget(to2 - from2);
16795
16883
  } else {
16796
16884
  let widget = deco.widget || (deco.block ? NullWidget.block : NullWidget.inline);
@@ -16802,7 +16890,7 @@ var TileUpdate = class {
16802
16890
  b.addBlockWidget(tile);
16803
16891
  } else {
16804
16892
  b.ensureLine(pendingLineAttrs);
16805
- b.addInlineWidget(tile, active, openStart);
16893
+ b.addInlineWidget(tile, active2, openStart);
16806
16894
  }
16807
16895
  }
16808
16896
  pendingLineAttrs = null;
@@ -16812,7 +16900,7 @@ var TileUpdate = class {
16812
16900
  if (to2 > from2)
16813
16901
  this.text.skip(to2 - from2);
16814
16902
  },
16815
- span: (from2, to2, active, openStart) => {
16903
+ span: (from2, to2, active2, openStart) => {
16816
16904
  for (let pos = from2; pos < to2; ) {
16817
16905
  let chars = this.text.next(Math.min(512, to2 - pos));
16818
16906
  if (chars == null) {
@@ -16821,12 +16909,12 @@ var TileUpdate = class {
16821
16909
  pos++;
16822
16910
  } else {
16823
16911
  b.ensureLine(pendingLineAttrs);
16824
- b.addText(chars, active, pos == from2 ? openStart : active.length);
16912
+ b.addText(chars, active2, pos == from2 ? openStart : active2.length);
16825
16913
  pos += chars.length;
16826
16914
  }
16827
16915
  pendingLineAttrs = null;
16828
16916
  }
16829
- markCount = active.length;
16917
+ markCount = active2.length;
16830
16918
  }
16831
16919
  });
16832
16920
  if (markCount > -1)
@@ -18815,9 +18903,9 @@ handlers.mousedown = (view, event) => {
18815
18903
  if (mustFocus)
18816
18904
  view.observer.ignore(() => {
18817
18905
  focusPreventScroll(view.contentDOM);
18818
- let active = view.root.activeElement;
18819
- if (active && !active.contains(view.contentDOM))
18820
- active.blur();
18906
+ let active2 = view.root.activeElement;
18907
+ if (active2 && !active2.contains(view.contentDOM))
18908
+ active2.blur();
18821
18909
  });
18822
18910
  let mouseSel = view.inputState.mouseSelection;
18823
18911
  if (mouseSel) {
@@ -28860,7 +28948,7 @@ function scrollIntoView2(container2, element) {
28860
28948
  function score(option) {
28861
28949
  return (option.boost || 0) * 100 + (option.apply ? 10 : 0) + (option.info ? 5 : 0) + (option.type ? 1 : 0);
28862
28950
  }
28863
- function sortOptions(active, state) {
28951
+ function sortOptions(active2, state) {
28864
28952
  let options = [];
28865
28953
  let sections = null, dynamicSectionScore = null;
28866
28954
  let addOption = (option) => {
@@ -28875,7 +28963,7 @@ function sortOptions(active, state) {
28875
28963
  }
28876
28964
  };
28877
28965
  let conf = state.facet(completionConfig);
28878
- for (let a of active)
28966
+ for (let a of active2)
28879
28967
  if (a.hasResult()) {
28880
28968
  let getMatch = a.result.getMatch;
28881
28969
  if (a.result.filter === false) {
@@ -28938,12 +29026,12 @@ var CompletionDialog = class _CompletionDialog {
28938
29026
  setSelected(selected, id) {
28939
29027
  return selected == this.selected || selected >= this.options.length ? this : new _CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected, this.disabled);
28940
29028
  }
28941
- static build(active, state, id, prev, conf, didSetActive) {
28942
- if (prev && !didSetActive && active.some((s) => s.isPending))
29029
+ static build(active2, state, id, prev, conf, didSetActive) {
29030
+ if (prev && !didSetActive && active2.some((s) => s.isPending))
28943
29031
  return prev.setDisabled();
28944
- let options = sortOptions(active, state);
29032
+ let options = sortOptions(active2, state);
28945
29033
  if (!options.length)
28946
- return prev && active.some((a) => a.isPending) ? prev.setDisabled() : null;
29034
+ return prev && active2.some((a) => a.isPending) ? prev.setDisabled() : null;
28947
29035
  let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1;
28948
29036
  if (prev && prev.selected != selected && prev.selected != -1) {
28949
29037
  let selectedValue = prev.options[prev.selected].completion;
@@ -28954,7 +29042,7 @@ var CompletionDialog = class _CompletionDialog {
28954
29042
  }
28955
29043
  }
28956
29044
  return new _CompletionDialog(options, makeAttrs(id, selected), {
28957
- pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
29045
+ pos: active2.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
28958
29046
  create: createTooltip,
28959
29047
  above: conf.aboveCursor
28960
29048
  }, prev ? prev.timestamp : Date.now(), selected, false);
@@ -28967,8 +29055,8 @@ var CompletionDialog = class _CompletionDialog {
28967
29055
  }
28968
29056
  };
28969
29057
  var CompletionState = class _CompletionState {
28970
- constructor(active, id, open) {
28971
- this.active = active;
29058
+ constructor(active2, id, open) {
29059
+ this.active = active2;
28972
29060
  this.id = id;
28973
29061
  this.open = open;
28974
29062
  }
@@ -28978,7 +29066,7 @@ var CompletionState = class _CompletionState {
28978
29066
  update(tr) {
28979
29067
  let { state } = tr, conf = state.facet(completionConfig);
28980
29068
  let sources = conf.override || state.languageDataAt("autocomplete", cur(state)).map(asSource);
28981
- let active = sources.map((source) => {
29069
+ let active2 = sources.map((source) => {
28982
29070
  let value = this.active.find((s) => s.source == source) || new ActiveSource(
28983
29071
  source,
28984
29072
  this.active.some(
@@ -28989,17 +29077,17 @@ var CompletionState = class _CompletionState {
28989
29077
  );
28990
29078
  return value.update(tr, conf);
28991
29079
  });
28992
- if (active.length == this.active.length && active.every((a, i2) => a == this.active[i2]))
28993
- active = this.active;
29080
+ if (active2.length == this.active.length && active2.every((a, i2) => a == this.active[i2]))
29081
+ active2 = this.active;
28994
29082
  let open = this.open, didSet = tr.effects.some((e) => e.is(setActiveEffect));
28995
29083
  if (open && tr.docChanged)
28996
29084
  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))
29085
+ if (tr.selection || active2.some((a) => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) || !sameResults(active2, this.active) || didSet)
29086
+ open = CompletionDialog.build(active2, state, this.id, open, conf, didSet);
29087
+ else if (open && open.disabled && !active2.some((a) => a.isPending))
29000
29088
  open = null;
29001
- if (!open && active.every((a) => !a.isPending) && active.some((a) => a.hasResult()))
29002
- active = active.map((a) => a.hasResult() ? new ActiveSource(
29089
+ if (!open && active2.every((a) => !a.isPending) && active2.some((a) => a.hasResult()))
29090
+ active2 = active2.map((a) => a.hasResult() ? new ActiveSource(
29003
29091
  a.source,
29004
29092
  0
29005
29093
  /* State.Inactive */
@@ -29007,7 +29095,7 @@ var CompletionState = class _CompletionState {
29007
29095
  for (let effect of tr.effects)
29008
29096
  if (effect.is(setSelectedEffect))
29009
29097
  open = open && open.setSelected(effect.value, this.id);
29010
- return active == this.active && open == this.open ? this : new _CompletionState(active, this.id, open);
29098
+ return active2 == this.active && open == this.open ? this : new _CompletionState(active2, this.id, open);
29011
29099
  }
29012
29100
  get tooltip() {
29013
29101
  return this.open ? this.open.tooltip : null;
@@ -29092,9 +29180,9 @@ var ActiveSource = class _ActiveSource {
29092
29180
  /* State.Inactive */
29093
29181
  );
29094
29182
  else if (effect.is(setActiveEffect)) {
29095
- for (let active of effect.value)
29096
- if (active.source == value.source)
29097
- value = active;
29183
+ for (let active2 of effect.value)
29184
+ if (active2.source == value.source)
29185
+ value = active2;
29098
29186
  }
29099
29187
  }
29100
29188
  return value;
@@ -29238,8 +29326,8 @@ var closeCompletion = (view) => {
29238
29326
  return true;
29239
29327
  };
29240
29328
  var RunningQuery = class {
29241
- constructor(active, context) {
29242
- this.active = active;
29329
+ constructor(active2, context) {
29330
+ this.active = active2;
29243
29331
  this.context = context;
29244
29332
  this.time = Date.now();
29245
29333
  this.updates = [];
@@ -29256,9 +29344,9 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29256
29344
  this.debounceAccept = -1;
29257
29345
  this.pendingStart = false;
29258
29346
  this.composing = 0;
29259
- for (let active of view.state.field(completionState).active)
29260
- if (active.isPending)
29261
- this.startQuery(active);
29347
+ for (let active2 of view.state.field(completionState).active)
29348
+ if (active2.isPending)
29349
+ this.startQuery(active2);
29262
29350
  }
29263
29351
  update(update) {
29264
29352
  let cState = update.state.field(completionState);
@@ -29303,19 +29391,19 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29303
29391
  this.debounceUpdate = -1;
29304
29392
  this.pendingStart = false;
29305
29393
  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);
29394
+ for (let active2 of cState.active) {
29395
+ if (active2.isPending && !this.running.some((r) => r.active.source == active2.source))
29396
+ this.startQuery(active2);
29309
29397
  }
29310
29398
  if (this.running.length && cState.open && cState.open.disabled)
29311
29399
  this.debounceAccept = setTimeout(() => this.accept(), this.view.state.facet(completionConfig).updateSyncTime);
29312
29400
  }
29313
- startQuery(active) {
29401
+ startQuery(active2) {
29314
29402
  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);
29403
+ let context = new CompletionContext(state, pos, active2.explicit, this.view);
29404
+ let pending2 = new RunningQuery(active2, context);
29317
29405
  this.running.push(pending2);
29318
- Promise.resolve(active.source(context)).then((result) => {
29406
+ Promise.resolve(active2.source(context)).then((result) => {
29319
29407
  if (!pending2.context.aborted) {
29320
29408
  pending2.done = result || null;
29321
29409
  this.scheduleAccept();
@@ -29348,26 +29436,26 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29348
29436
  if (query.done) {
29349
29437
  let pos = cur(query.updates.length ? query.updates[0].startState : this.view.state);
29350
29438
  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);
29439
+ 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
29440
  for (let tr of query.updates)
29353
- active = active.update(tr, conf);
29354
- if (active.hasResult()) {
29355
- updated.push(active);
29441
+ active2 = active2.update(tr, conf);
29442
+ if (active2.hasResult()) {
29443
+ updated.push(active2);
29356
29444
  continue;
29357
29445
  }
29358
29446
  }
29359
29447
  let current2 = cState.active.find((a) => a.source == query.active.source);
29360
29448
  if (current2 && current2.isPending) {
29361
29449
  if (query.done == null) {
29362
- let active = new ActiveSource(
29450
+ let active2 = new ActiveSource(
29363
29451
  query.active.source,
29364
29452
  0
29365
29453
  /* State.Inactive */
29366
29454
  );
29367
29455
  for (let tr of query.updates)
29368
- active = active.update(tr, conf);
29369
- if (!active.isPending)
29370
- updated.push(active);
29456
+ active2 = active2.update(tr, conf);
29457
+ if (!active2.isPending)
29458
+ updated.push(active2);
29371
29459
  } else {
29372
29460
  this.startQuery(current2);
29373
29461
  }
@@ -29824,12 +29912,12 @@ var theme2 = EditorView.theme({
29824
29912
  "&.cm-focused .cm-selectionBackground, .cm-selectionBackground": { background: "var(--accent-soft)" }
29825
29913
  });
29826
29914
  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 });
29915
+ var ExprCode = (0, import_react9.forwardRef)(function ExprCode2({ value, onChange, fields, parameters, invalid, check }, ref) {
29916
+ const host = (0, import_react9.useRef)(null);
29917
+ const view = (0, import_react9.useRef)(null);
29918
+ const latest2 = (0, import_react9.useRef)({ onChange, fields, parameters, check });
29831
29919
  latest2.current = { onChange, fields, parameters, check };
29832
- (0, import_react8.useImperativeHandle)(ref, () => ({
29920
+ (0, import_react9.useImperativeHandle)(ref, () => ({
29833
29921
  insert(text) {
29834
29922
  const v = view.current;
29835
29923
  if (!v) return;
@@ -29843,7 +29931,7 @@ var ExprCode = (0, import_react8.forwardRef)(function ExprCode2({ value, onChang
29843
29931
  view.current?.focus();
29844
29932
  }
29845
29933
  }));
29846
- (0, import_react8.useEffect)(() => {
29934
+ (0, import_react9.useEffect)(() => {
29847
29935
  const complete = (ctx) => {
29848
29936
  const m = ctx.matchBefore(/(Fields|Parameters|Globals)\.\w*$/);
29849
29937
  if (m) {
@@ -29932,8 +30020,8 @@ var SNIPPETS = {
29932
30020
  function ExpressionEditor({ value, dataSet, onSave, onClose, title }) {
29933
30021
  const def = useDesigner((s) => s.def);
29934
30022
  const sample = useDesigner((s) => s.sample);
29935
- const [text, setText] = (0, import_react9.useState)(value ?? "");
29936
- const ta = (0, import_react9.useRef)(null);
30023
+ const [text, setText] = (0, import_react10.useState)(value ?? "");
30024
+ const ta = (0, import_react10.useRef)(null);
29937
30025
  const dsName = dataSet || def.dataSets?.[0]?.name;
29938
30026
  const ds = def.dataSets?.find((d) => d.name === dsName);
29939
30027
  const fields = fieldNames(ds).filter((n) => !(ds?.fields || []).some((f) => f.name === n && f.type === "object"));
@@ -29943,7 +30031,7 @@ function ExpressionEditor({ value, dataSet, onSave, onClose, title }) {
29943
30031
  const insert2 = (s) => ta.current?.insert(s);
29944
30032
  const err = checkValue(text);
29945
30033
  const issues = err ? [] : check(text);
29946
- const preview = (0, import_react9.useMemo)(() => {
30034
+ const preview = (0, import_react10.useMemo)(() => {
29947
30035
  if (err || !sample?.dataSets) return null;
29948
30036
  const rows = sample.dataSets[dsName] || [];
29949
30037
  const params = Object.fromEntries((def.parameters || []).map((p) => [p.name, p.default ?? null]));
@@ -30016,7 +30104,7 @@ function ExpressionEditor({ value, dataSet, onSave, onClose, title }) {
30016
30104
  }
30017
30105
 
30018
30106
  // src/designer/CondFormat.jsx
30019
- var import_react10 = __toESM(require_react(), 1);
30107
+ var import_react11 = __toESM(require_react(), 1);
30020
30108
 
30021
30109
  // src/designer/cfRules.js
30022
30110
  var CF_OPS = ["eq", "ne", "lt", "le", "gt", "ge", "between", "top", "bottom", "aboveAvg", "belowAvg", "contains", "startsWith", "empty", "notEmpty"];
@@ -30136,7 +30224,7 @@ function CondFormat({ title, cf: start, fields, thisValue, kind, custom, onApply
30136
30224
  const lang2 = useDesigner((s) => s.lang);
30137
30225
  const T = (k, v) => t(lang2, k, v);
30138
30226
  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()] })));
30227
+ const [cf, setCf] = (0, import_react11.useState)(() => JSON.parse(JSON.stringify(start || { mode: "first", rules: [blank()] })));
30140
30228
  const rules = cf.rules || [];
30141
30229
  const setRule = (i2, patch) => setCf((c) => ({ ...c, rules: c.rules.map((r, j) => j === i2 ? { ...r, ...patch } : r) }));
30142
30230
  const setFmt = (i2, k, v) => setCf((c) => ({ ...c, rules: c.rules.map((r, j) => {
@@ -30227,7 +30315,7 @@ var catLabel = (tk, cat) => tk(`cat_${cat}`, cat);
30227
30315
  function Inspector() {
30228
30316
  const sel = useDesigner((s) => s.sel);
30229
30317
  const def = useDesigner((s) => s.def);
30230
- const [expr, setExpr] = (0, import_react11.useState)(null);
30318
+ const [expr, setExpr] = (0, import_react12.useState)(null);
30231
30319
  const openExpr = (cfg) => setExpr(cfg);
30232
30320
  let body;
30233
30321
  if (sel.kind === "items" && sel.ids.length > 1) body = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Multi, { ids: sel.ids });
@@ -30242,13 +30330,13 @@ function Inspector() {
30242
30330
  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
30331
  const scope = one ? one.dataSet || def.dataSets?.[0]?.name || null : void 0;
30244
30332
  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)(() => {
30333
+ const ref = (0, import_react12.useRef)(null);
30334
+ (0, import_react12.useLayoutEffect)(() => {
30247
30335
  const pane = ref.current?.closest(".dright");
30248
30336
  if (pane) pane.scrollTop = 0;
30249
30337
  }, [selKey]);
30250
- const [closed, setClosed] = (0, import_react11.useState)(() => /* @__PURE__ */ new Set());
30251
- (0, import_react11.useLayoutEffect)(() => {
30338
+ const [closed, setClosed] = (0, import_react12.useState)(() => /* @__PURE__ */ new Set());
30339
+ (0, import_react12.useLayoutEffect)(() => {
30252
30340
  for (const h of ref.current?.querySelectorAll(".cat > h5") || []) {
30253
30341
  const shut = closed.has(h.textContent);
30254
30342
  h.querySelector("button")?.setAttribute("aria-expanded", String(!shut));
@@ -30267,13 +30355,13 @@ function Inspector() {
30267
30355
  });
30268
30356
  };
30269
30357
  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) }),
30358
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FieldScope.Provider, { value: scope, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react12.Fragment, { children: body }, selKey) }),
30271
30359
  expr && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ExpressionEditor, { ...expr, onClose: () => setExpr(null) })
30272
30360
  ] });
30273
30361
  }
30274
- function Geo({ label, value, onChange }) {
30362
+ function Geo({ label, value, onChange, min }) {
30275
30363
  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))) }) });
30364
+ 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
30365
  }
30278
30366
  function PropEditor({ p: spec, value, onChange, openExpr, dataSet, item }) {
30279
30367
  const T = useT3();
@@ -30338,7 +30426,7 @@ function OverflowTarget({ value, onChange, self }) {
30338
30426
  }
30339
30427
  function ExprOr({ p, value, onChange, openExpr, dataSet, children }) {
30340
30428
  const T = useT3();
30341
- const [on, setOn] = (0, import_react11.useState)(isDynamic(value));
30429
+ const [on, setOn] = (0, import_react12.useState)(isDynamic(value));
30342
30430
  const label = T(on ? "useFixed" : "useExpr");
30343
30431
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: p.label, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "expr-row", children: [
30344
30432
  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 +30439,7 @@ function ExprOr({ p, value, onChange, openExpr, dataSet, children }) {
30351
30439
  function PaletteEditor({ label, value, onChange }) {
30352
30440
  const T = useT3();
30353
30441
  const custom = Array.isArray(value);
30354
- const [text, setText] = (0, import_react11.useState)(custom ? value.join(", ") : "");
30442
+ const [text, setText] = (0, import_react12.useState)(custom ? value.join(", ") : "");
30355
30443
  const parse2 = (t3) => t3.split(/[\s,;]+/).map((x) => x.trim()).filter((x) => /^#[0-9a-f]{6}$/i.test(x));
30356
30444
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { display: "grid", gap: 6 }, children: [
30357
30445
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
@@ -30378,17 +30466,18 @@ function PaletteEditor({ label, value, onChange }) {
30378
30466
  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
30467
  ] });
30380
30468
  }
30381
- var reportList = null;
30469
+ var reportLists = /* @__PURE__ */ new Map();
30382
30470
  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)(() => {
30471
+ const [list2, setList] = (0, import_react12.useState)(() => reportLists.get(useDesigner.getState().embed?.server || "") || []);
30472
+ const listId = (0, import_react12.useState)(() => `reports-${Math.random().toString(36).slice(2, 8)}`)[0];
30473
+ (0, import_react12.useEffect)(() => {
30386
30474
  const embed = useDesigner.getState().embed;
30387
- if (reportList || embed && !embed.server) return;
30388
30475
  const server2 = embed?.server || "";
30476
+ if (reportLists.has(server2) || embed && !embed.server) return;
30389
30477
  fetch(`${server2}/api/reports`).then((r) => r.ok ? r.json() : []).then((l) => {
30390
- reportList = Array.isArray(l) ? l : [];
30391
- setList(reportList);
30478
+ const v = Array.isArray(l) ? l : [];
30479
+ reportLists.set(server2, v);
30480
+ setList(v);
30392
30481
  }).catch(() => {
30393
30482
  });
30394
30483
  }, []);
@@ -30422,8 +30511,8 @@ function ItemProps({ item, section, openExpr }) {
30422
30511
  const tk = useTk();
30423
30512
  const def = useDesigner((s) => s.def);
30424
30513
  const spec = ITEMS[item.type];
30425
- const [nameErr, setNameErr] = (0, import_react11.useState)(null);
30426
- const [find2, setFind] = (0, import_react11.useState)("");
30514
+ const [nameErr, setNameErr] = (0, import_react12.useState)(null);
30515
+ const [find2, setFind] = (0, import_react12.useState)("");
30427
30516
  const q2 = find2.trim().toLowerCase();
30428
30517
  const hit = (p, type) => !q2 || propLabel(tk, p, type).toLowerCase().includes(q2) || p.key.toLowerCase().includes(q2);
30429
30518
  const props = (spec?.props || []).filter((p) => (!p.showIf || p.showIf(item)) && hit(p, item.type));
@@ -30475,8 +30564,8 @@ function ItemProps({ item, section, openExpr }) {
30475
30564
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "grid2", children: [
30476
30565
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Geo, { label: "X", value: item.x, onChange: (v) => setGeo("x", Math.max(0, v)) }),
30477
30566
  /* @__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)) }),
30567
+ 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)) }),
30568
+ 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
30569
  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
30570
  ] }),
30482
30571
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "hint", children: (() => {
@@ -30567,7 +30656,7 @@ function PivotEditor({ item, openExpr }) {
30567
30656
  const def = useDesigner((s) => s.def);
30568
30657
  const fields = fieldsOf2(def, item.dataSet);
30569
30658
  const spec = normalizeMatrix(item);
30570
- const [pick, setPick] = (0, import_react11.useState)({ rowGroups: "", columnGroups: "", values: "" });
30659
+ const [pick, setPick] = (0, import_react12.useState)({ rowGroups: "", columnGroups: "", values: "" });
30571
30660
  const edit = (fn3, key2) => updateItem(item.id, (it) => {
30572
30661
  if (!isTablix(it)) {
30573
30662
  const n = normalizeMatrix(it);
@@ -30646,7 +30735,17 @@ function PivotEditor({ item, openExpr }) {
30646
30735
  /* @__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
30736
  ] })
30648
30737
  ] }),
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) }),
30738
+ (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) => {
30739
+ const o = it[list2][i2];
30740
+ if (v) {
30741
+ o.collapsible = true;
30742
+ o.initiallyCollapsed = true;
30743
+ } else {
30744
+ delete o.collapsible;
30745
+ delete o.initiallyCollapsed;
30746
+ }
30747
+ }, `${item.id}.${list2}${i2}.collapsible`) }),
30748
+ " ",
30650
30749
  g.collapsible && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Check, { label: T("pivotStartCollapsed"), checked: g.initiallyCollapsed, onChange: (v) => setK(list2, i2, "initiallyCollapsed", v) }),
30651
30750
  /* @__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
30751
  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 +30771,7 @@ function PivotEditor({ item, openExpr }) {
30672
30771
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "grid2", children: [
30673
30772
  /* @__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
30773
  /* @__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) }) })
30774
+ /* @__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
30775
  ] }),
30677
30776
  /* @__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
30777
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("cellBookmark"), children: exprField("values", i2, "bookmark", v.bookmark, T("cellBookmark")) })
@@ -30714,8 +30813,8 @@ function GroupsEditor({ table: table2, openExpr }) {
30714
30813
  const T = useT3();
30715
30814
  const def = useDesigner((s) => s.def);
30716
30815
  const fields = fieldsOf2(def, table2.dataSet);
30717
- const [pick, setPick] = (0, import_react11.useState)("");
30718
- const [drill, setDrill] = (0, import_react11.useState)(false);
30816
+ const [pick, setPick] = (0, import_react12.useState)("");
30817
+ const [drill, setDrill] = (0, import_react12.useState)(false);
30719
30818
  const setG = (i2, k, v) => updateItem(table2.id, (t3) => {
30720
30819
  if (v === void 0 || v === "" || v === false) delete t3.groups[i2][k];
30721
30820
  else t3.groups[i2][k] = v;
@@ -30957,7 +31056,7 @@ rimary" ? void 0 : v), "aria-label": `${T("overlayAxis")} ${i2 + 1}` }) }),
30957
31056
  }
30958
31057
  function CfButton({ label, title, target, at: at2, kind, fields, apply: apply2, testid }) {
30959
31058
  const T = useT3();
30960
- const [open, setOpen] = (0, import_react11.useState)(false);
31059
+ const [open, setOpen] = (0, import_react12.useState)(false);
30961
31060
  const n = target?.cf?.rules?.length || 0;
30962
31061
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
30963
31062
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("button", { type: "button", className: "btn sm", onClick: () => setOpen(true), "data-testid": testid, children: [
@@ -31024,14 +31123,16 @@ function VisualEditor({ cell, setCell, openExpr, dataSet }) {
31024
31123
  }
31025
31124
  var reportParams = /* @__PURE__ */ new Map();
31026
31125
  function useReportParams(id) {
31027
- const [list2, setList] = (0, import_react11.useState)(() => reportParams.get(id) ?? null);
31028
- (0, import_react11.useEffect)(() => {
31126
+ const srv = () => useDesigner.getState().embed?.server || "";
31127
+ const [list2, setList] = (0, import_react12.useState)(() => reportParams.get(`${srv()} ${id}`) ?? null);
31128
+ (0, import_react12.useEffect)(() => {
31029
31129
  if (!id || isDynamic(id)) {
31030
31130
  setList(null);
31031
31131
  return;
31032
31132
  }
31033
- if (reportParams.has(id)) {
31034
- setList(reportParams.get(id));
31133
+ const key2 = `${srv()} ${id}`;
31134
+ if (reportParams.has(key2)) {
31135
+ setList(reportParams.get(key2));
31035
31136
  return;
31036
31137
  }
31037
31138
  let alive = true;
@@ -31044,7 +31145,7 @@ function useReportParams(id) {
31044
31145
  fetch(`${server2}/api/reports/${encodeURIComponent(id)}`).then((r) => r.ok ? r.json() : null).then((r) => {
31045
31146
  const d = r?.definition || r;
31046
31147
  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);
31148
+ if (ps) reportParams.set(key2, ps);
31048
31149
  if (alive) setList(ps);
31049
31150
  }).catch(() => {
31050
31151
  if (alive) setList(null);
@@ -31058,7 +31159,7 @@ function useReportParams(id) {
31058
31159
  function ParamMap({ value, onChange, known, openExpr, dataSet, testid }) {
31059
31160
  const T = useT3();
31060
31161
  const map = value || {};
31061
- const [extra, setExtra] = (0, import_react11.useState)("");
31162
+ const [extra, setExtra] = (0, import_react12.useState)("");
31062
31163
  const knownNames = new Set((known || []).map((p) => p.name));
31063
31164
  const names = [...(known || []).map((p) => p.name), ...Object.keys(map).filter((k) => !knownNames.has(k))];
31064
31165
  const set2 = (k, v, keep) => {
@@ -31477,7 +31578,7 @@ function ReportProps() {
31477
31578
  const T = useT3();
31478
31579
  const def = useDesigner((s) => s.def);
31479
31580
  const families = useFontFamilies();
31480
- const [fontsOpen, setFontsOpen] = (0, import_react11.useState)(false);
31581
+ const [fontsOpen, setFontsOpen] = (0, import_react12.useState)(false);
31481
31582
  const set2 = (fn3, key2) => useDesigner.getState().apply(fn3, key2);
31482
31583
  const m = Array.isArray(def.page?.margins) ? def.page.margins : [36, 36, 36, 36];
31483
31584
  const base2 = def.styles?.base || {};
@@ -31556,7 +31657,7 @@ function ReportProps() {
31556
31657
  function ReportImages() {
31557
31658
  const T = useT3();
31558
31659
  const images = useDesigner((s) => s.def.images) || {};
31559
- const [err, setErr] = (0, import_react11.useState)(null);
31660
+ const [err, setErr] = (0, import_react12.useState)(null);
31560
31661
  const set2 = (fn3) => useDesigner.getState().apply((d) => {
31561
31662
  d.images || (d.images = {});
31562
31663
  fn3(d.images);
@@ -31595,7 +31696,7 @@ function EmbeddedPicker({ item, onPick }) {
31595
31696
  const images = useDesigner((s) => s.def.images) || {};
31596
31697
  const names = Object.keys(images);
31597
31698
  const cur2 = /^embedded:(.+)$/.exec(String(item.src || ""))?.[1];
31598
- const [err, setErr] = (0, import_react11.useState)(null);
31699
+ const [err, setErr] = (0, import_react12.useState)(null);
31599
31700
  const upload = async (files) => {
31600
31701
  setErr(null);
31601
31702
  const r = await uploadImages(files, T);
@@ -31680,7 +31781,7 @@ function NamedStyles() {
31680
31781
  const styleNames = useStyleNames();
31681
31782
  const def = useDesigner((s) => s.def);
31682
31783
  const named = def.styles?.named || {};
31683
- const [newName, setNewName] = (0, import_react11.useState)("");
31784
+ const [newName, setNewName] = (0, import_react12.useState)("");
31684
31785
  const setS = (name2, k, v) => useDesigner.getState().apply((d) => {
31685
31786
  var _a2, _b;
31686
31787
  d.styles || (d.styles = {});
@@ -31715,7 +31816,7 @@ function NamedStyles() {
31715
31816
  }
31716
31817
 
31717
31818
  // src/designer/DataPanel.jsx
31718
- var import_react14 = __toESM(require_react(), 1);
31819
+ var import_react15 = __toESM(require_react(), 1);
31719
31820
 
31720
31821
  // src/designer/explore.js
31721
31822
  var key = (k) => /^[A-Za-z_$][\w$]*$/.test(k) ? `.${k}` : `['${k}']`;
@@ -31751,7 +31852,7 @@ function bestRows(root) {
31751
31852
  }
31752
31853
 
31753
31854
  // src/designer/ODataEditor.jsx
31754
- var import_react12 = __toESM(require_react(), 1);
31855
+ var import_react13 = __toESM(require_react(), 1);
31755
31856
  var import_jsx_runtime11 = __toESM(require_jsx_runtime(), 1);
31756
31857
  var OPS3 = ["eq", "ne", "gt", "ge", "lt", "le", "contains", "startswith", "endswith"];
31757
31858
  var OP_LABEL = { eq: "=", ne: "≠", gt: ">", ge: "≥", lt: "<", le: "≤" };
@@ -31766,7 +31867,7 @@ async function readMetadata(s) {
31766
31867
  return odataMetadata(await res.text());
31767
31868
  }
31768
31869
  function ODataEditor({ s, setS, T }) {
31769
- const [meta2, setMeta] = (0, import_react12.useState)(null);
31870
+ const [meta2, setMeta] = (0, import_react13.useState)(null);
31770
31871
  const sets = meta2?.sets || [];
31771
31872
  const set2 = sets.find((x) => x.name === s.entitySet);
31772
31873
  const props = set2 ? set2.properties : (s.select || []).map((name2) => ({ name: name2, type: s.types?.[name2] || "" }));
@@ -31857,7 +31958,7 @@ function ODataEditor({ s, setS, T }) {
31857
31958
  }
31858
31959
 
31859
31960
  // src/designer/SqlBuilder.jsx
31860
- var import_react13 = __toESM(require_react(), 1);
31961
+ var import_react14 = __toESM(require_react(), 1);
31861
31962
 
31862
31963
  // src/designer/sqlBuild.js
31863
31964
  var FILTER_OPS2 = ["=", "<>", "<", "<=", ">", ">=", "like", "in", "is null", "is not null"];
@@ -31930,8 +32031,8 @@ function normalizeSchema(body) {
31930
32031
  return tables;
31931
32032
  }
31932
32033
  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)(() => {
32034
+ const [st, setSt] = (0, import_react14.useState)(() => schemas.has(connection) ? { tables: schemas.get(connection) } : { loading: !!connection });
32035
+ (0, import_react14.useEffect)(() => {
31935
32036
  if (!connection) {
31936
32037
  setSt({});
31937
32038
  return void 0;
@@ -31965,8 +32066,8 @@ function SqlBuilder({ s, setS, T, kind, onManual }) {
31965
32066
  const nb = { ...b, ...patch };
31966
32067
  setS({ ...s, builder: nb, query: buildSql(nb, kind) });
31967
32068
  };
31968
- const [find2, setFind] = (0, import_react13.useState)("");
31969
- const [preview, setPreview] = (0, import_react13.useState)(null);
32069
+ const [find2, setFind] = (0, import_react14.useState)("");
32070
+ const [preview, setPreview] = (0, import_react14.useState)(null);
31970
32071
  const sql = buildSql(b, kind);
31971
32072
  const tableOf2 = (name2) => (schema.tables || []).find((t3) => t3.name === name2);
31972
32073
  const colsOf = (alias) => tableOf2(b.tables.find((t3) => t3.alias === alias)?.name)?.columns || [];
@@ -31995,7 +32096,7 @@ function SqlBuilder({ s, setS, T, kind, onManual }) {
31995
32096
  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
32097
  set2({ joins: [...b.joins, { type: "inner", from, to }] });
31997
32098
  };
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]);
32099
+ 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
32100
  const runPreview = async () => {
32000
32101
  setPreview({ loading: true });
32001
32102
  try {
@@ -32158,7 +32259,7 @@ function SqlBuilder({ s, setS, T, kind, onManual }) {
32158
32259
  ] });
32159
32260
  }
32160
32261
  function JoinAdder({ allCols, split, onAdd, T }) {
32161
- const [a, setA] = (0, import_react13.useState)(""), [z, setZ] = (0, import_react13.useState)("");
32262
+ const [a, setA] = (0, import_react14.useState)(""), [z, setZ] = (0, import_react14.useState)("");
32162
32263
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "qb-row", children: [
32163
32264
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Select, { value: a, allowEmpty: true, options: allCols, onChange: (v) => setA(v || ""), "aria-label": T("qb_joinFrom") }),
32164
32265
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: "=" }),
@@ -32175,17 +32276,18 @@ function JoinAdder({ allCols, split, onAdd, T }) {
32175
32276
  var import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
32176
32277
  var NAME2 = /^[A-Za-z_][\w]*$/;
32177
32278
  var noSourceKey = (def) => (def?.dataSources || []).length ? null : "r4_noDataSource";
32178
- async function loadSample() {
32179
- const { def } = useDesigner.getState();
32180
- useDesigner.setState({ sample: { loading: true } });
32279
+ async function loadSample(store) {
32280
+ const api = store?.getState ? store : activeStore();
32281
+ const { def } = api.getState();
32282
+ api.setState({ sample: { loading: true } });
32181
32283
  try {
32182
32284
  const params = resolveParameters(def, {});
32183
32285
  const sources = await loadSources(def, { params, baseUrl: origin(), sqlPreview: true, fetch: reportFetch(origin(), void 0, { sqlPreview: true }) });
32184
32286
  const ctx = { params, globals: { ExecutionTime: /* @__PURE__ */ new Date() }, dataSets: {}, fields: null, locale: def.locale, currency: def.currency, functions: functionTable(def) };
32185
32287
  const dataSets = buildDataSets(def, sources, ctx);
32186
- useDesigner.setState({ sample: { dataSets, sources, at: Date.now() } });
32288
+ api.setState({ sample: { dataSets, sources, at: Date.now() } });
32187
32289
  } catch (e) {
32188
- useDesigner.setState({ sample: { error: e.message } });
32290
+ api.setState({ sample: { error: e.message } });
32189
32291
  }
32190
32292
  }
32191
32293
  function DataPanel() {
@@ -32193,8 +32295,8 @@ function DataPanel() {
32193
32295
  const lang2 = useDesigner((s) => s.lang);
32194
32296
  const T = (k, v) => t(lang2, k, v);
32195
32297
  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)));
32298
+ const [dlg, setDlg] = (0, import_react15.useState)(null);
32299
+ const [open, setOpen] = (0, import_react15.useState)(() => new Set((def.dataSets || []).map((d) => d.name)));
32198
32300
  const toggle = (n) => setOpen((s) => {
32199
32301
  const x = new Set(s);
32200
32302
  x.has(n) ? x.delete(n) : x.add(n);
@@ -32343,10 +32445,10 @@ function ParamDialog({ index, onClose }) {
32343
32445
  const lang2 = useDesigner((s) => s.lang);
32344
32446
  const T = (k, v) => t(lang2, k, v);
32345
32447
  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"));
32448
+ const [p, setP] = (0, import_react15.useState)(orig || { name: "", type: "string", prompt: "", default: "", required: false });
32449
+ const [columns, setColumns] = (0, import_react15.useState)(String(def.parameterLayout?.columns || 1));
32450
+ const [live, setLive] = (0, import_react15.useState)(def.liveParameters !== false);
32451
+ const [choicesText, setChoicesText] = (0, import_react15.useState)(() => (p.options || []).map(optionLine).join("\n"));
32350
32452
  const fromFields = (def.dataSets?.find((d) => d.name === p.optionsFrom?.dataSet)?.fields || []).map((f) => f.name);
32351
32453
  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
32454
  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 +32595,7 @@ function SourceDialog({ index, onClose }) {
32493
32595
  const lang2 = useDesigner((s2) => s2.lang);
32494
32596
  const T = (k, v) => t(lang2, k, v);
32495
32597
  const orig = index != null ? def.dataSources[index] : null;
32496
- const [s, setS] = (0, import_react14.useState)(() => ({
32598
+ const [s, setS] = (0, import_react15.useState)(() => ({
32497
32599
  name: "",
32498
32600
  type: "rest",
32499
32601
  method: "GET",
@@ -32557,11 +32659,11 @@ function SourceDialog({ index, onClose }) {
32557
32659
  if (!err && s.type === "sql" && !s.connection) err = "Pick a connection";
32558
32660
  if (!err && s.type === "sql" && s.procedure != null && !s.procedure) err = "Pick a stored procedure";
32559
32661
  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);
32662
+ const [conns, setConns] = (0, import_react15.useState)(null);
32561
32663
  const procs = (conns || []).find((c) => c.name === s.connection)?.procs || [];
32562
32664
  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)(() => {
32665
+ const [probe, setProbe] = (0, import_react15.useState)(null);
32666
+ (0, import_react15.useEffect)(() => {
32565
32667
  if (s.type !== "sql" || conns) return;
32566
32668
  fetch("/api/data/sql/connections").then((r) => r.ok ? r.json() : []).then(setConns).catch(() => setConns([]));
32567
32669
  }, [s.type, conns]);
@@ -32754,13 +32856,13 @@ function DataSetDialog({ index, onClose, onSaved }) {
32754
32856
  const lang2 = useDesigner((s) => s.lang);
32755
32857
  const T = (k, v) => t(lang2, k, v);
32756
32858
  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);
32859
+ const [d, setD] = (0, import_react15.useState)(() => ({ name: "", source: def.dataSources?.[0]?.name, path: "$", fields: [], sort: [], ...orig ? JSON.parse(JSON.stringify(orig)) : {} }));
32860
+ const [detect, setDetect] = (0, import_react15.useState)({ state: "idle" });
32861
+ const [pathTyped, setPathTyped] = (0, import_react15.useState)(!!orig);
32760
32862
  const nested = !!d.relation;
32761
32863
  const parents = (def.dataSets || []).filter((x, i2) => i2 !== index && x.name !== d.name);
32762
32864
  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);
32865
+ const [explore, setExplore] = (0, import_react15.useState)(null);
32764
32866
  const loadSourceRaw = async (name2) => {
32765
32867
  const params = resolveParameters(useDesigner.getState().def, {});
32766
32868
  const src = useDesigner.getState().def.dataSources.find((s) => s.name === name2);
@@ -33010,7 +33112,7 @@ function DataSetDialog({ index, onClose, onSaved }) {
33010
33112
  }
33011
33113
 
33012
33114
  // src/designer/Outline.jsx
33013
- var import_react15 = __toESM(require_react(), 1);
33115
+ var import_react16 = __toESM(require_react(), 1);
33014
33116
  var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
33015
33117
  var MIME = "application/x-pw-outline";
33016
33118
  function Outline() {
@@ -33019,11 +33121,32 @@ function Outline() {
33019
33121
  const lang2 = useDesigner((s) => s.lang);
33020
33122
  const readOnly2 = useDesigner((s) => s.readOnly);
33021
33123
  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);
33124
+ const [drop, setDrop] = (0, import_react16.useState)(null);
33125
+ const [said, setSaid] = (0, import_react16.useState)("");
33126
+ const [cur2, setCur] = (0, import_react16.useState)(null);
33127
+ const dragged = (0, import_react16.useRef)(null);
33128
+ const body = (0, import_react16.useRef)(null);
33026
33129
  const chosen = new Set(sel.kind === "items" ? sel.ids : sel.kind === "cell" ? [sel.id] : []);
33130
+ const keys = sectionList(def).flatMap(({ key: key2 }) => {
33131
+ const out = [`band:${key2}`];
33132
+ const go = (l) => l.forEach((it) => {
33133
+ out.push(it.id);
33134
+ if (NESTING.has(it.type)) go(it.items || []);
33135
+ });
33136
+ go(secOf(def, key2)?.items || []);
33137
+ return out;
33138
+ });
33139
+ const stop = keys.includes(cur2) ? cur2 : keys.find((k) => chosen.has(k) || sel.kind === "section" && k === `band:${sel.section}`) || keys[0];
33140
+ const roving = (k) => ({ tabIndex: k === stop ? 0 : -1, onFocus: () => setCur(k) });
33141
+ const nav2 = (e) => {
33142
+ if (e.defaultPrevented || e.altKey || e.metaKey || e.ctrlKey || !e.target.hasAttribute("data-opt")) return;
33143
+ const all = [...e.currentTarget.querySelectorAll("[data-opt]")];
33144
+ const i2 = all.indexOf(e.target);
33145
+ const j = e.key === "ArrowDown" ? i2 + 1 : e.key === "ArrowUp" ? i2 - 1 : e.key === "Home" ? 0 : e.key === "End" ? all.length - 1 : null;
33146
+ if (j == null) return;
33147
+ e.preventDefault();
33148
+ all[Math.max(0, Math.min(all.length - 1, j))]?.focus();
33149
+ };
33027
33150
  const pick = (e, id) => {
33028
33151
  const st = useDesigner.getState();
33029
33152
  if (e.shiftKey && st.sel.kind === "items") {
@@ -33135,30 +33258,32 @@ function Outline() {
33135
33258
  };
33136
33259
  const rows = (list2, parent, depth, section) => list2.map((it, i2) => {
33137
33260
  const mark = drop && drop.id != null && drop.id === it.id ? ` drop-${drop.where}` : "";
33138
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("li", { children: [
33261
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("li", { role: "none", children: [
33139
33262
  /* @__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
33263
  !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 }),
33264
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", "data-opt": "", 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 ? "outline-nav" : "outline-nav outline-keys", ...roving(it.id), children: it.name }),
33142
33265
  /* @__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
33266
  !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: "⇱" })
33267
+ /* @__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: "↑" }),
33268
+ /* @__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: "↓" }),
33269
+ 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
33270
  ] })
33148
33271
  ] }),
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) })
33272
+ 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
33273
  ] }, it.id);
33151
33274
  });
33152
33275
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "pane", "data-testid": "outline", children: [
33153
33276
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h4", { children: T("outline") }),
33154
33277
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "pane-body", ref: body, children: [
33155
- sectionList(def).map(({ key: key2, label }) => {
33278
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { role: "group", "aria-label": T("outline"), onKeyDown: nav2, children: sectionList(def).map(({ key: key2, label }) => {
33156
33279
  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") }) })
33280
+ 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: [
33281
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", "data-opt": "", "aria-pressed": 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}`),
33282
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("b", { children: label }) }),
33283
+ /* @__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
33284
  ] }, key2);
33161
- }),
33285
+ }) }),
33286
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "sr-only", id: "outline-nav", children: T("b9_outlineKeys") }),
33162
33287
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "hint", children: T("outlineHint") }),
33163
33288
  !readOnly2 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "hint", id: "outline-keys", children: T("outlineKeys") }),
33164
33289
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "sr-only", role: "status", "aria-live": "polite", children: said })
@@ -33167,7 +33292,7 @@ function Outline() {
33167
33292
  }
33168
33293
 
33169
33294
  // src/theme/ThemeToggle.jsx
33170
- var import_react16 = __toESM(require_react(), 1);
33295
+ var import_react17 = __toESM(require_react(), 1);
33171
33296
 
33172
33297
  // src/theme/theme.js
33173
33298
  var THEME_KEY = "pw-theme";
@@ -33209,8 +33334,8 @@ function Icon2({ pref }) {
33209
33334
  ] });
33210
33335
  }
33211
33336
  function ThemeToggle({ className = "btn sm ghost icon" }) {
33212
- const [pref, setPref] = (0, import_react16.useState)("system");
33213
- (0, import_react16.useEffect)(() => {
33337
+ const [pref, setPref] = (0, import_react17.useState)("system");
33338
+ (0, import_react17.useEffect)(() => {
33214
33339
  setPref(readPreference());
33215
33340
  const mq = window.matchMedia("(prefers-color-scheme: dark)");
33216
33341
  const onChange = () => {
@@ -33228,7 +33353,7 @@ function ThemeToggle({ className = "btn sm ghost icon" }) {
33228
33353
  }
33229
33354
 
33230
33355
  // src/designer/ChartWizard.jsx
33231
- var import_react17 = __toESM(require_react(), 1);
33356
+ var import_react18 = __toESM(require_react(), 1);
33232
33357
  var import_jsx_runtime16 = __toESM(require_jsx_runtime(), 1);
33233
33358
  var TYPES = ["column", "bar", "line", "area", "pie", "donut", "scatter", "bubble", "radar", "funnel", "gauge", "treemap", "histogram", "boxplot", "waterfall", "gantt"];
33234
33359
  var PER_ROW = /* @__PURE__ */ new Set(["scatter", "bubble"]);
@@ -33344,14 +33469,14 @@ function ChartWizard() {
33344
33469
  const close = () => useDesigner.getState().setUi({ wizard: null });
33345
33470
  const lang2 = useDesigner((s) => s.lang);
33346
33471
  const tr = (k, v) => t(lang2, `cw_${k}`, v);
33347
- const [c, setC] = (0, import_react17.useState)(() => {
33472
+ const [c, setC] = (0, import_react18.useState)(() => {
33348
33473
  if (editing) return configFromChart(editing);
33349
33474
  const score2 = (d) => ((d.fields || []).some((f) => f.type === "number") ? 1e6 : 0) + (sample?.dataSets?.[d.name]?.length || 0);
33350
33475
  const ds2 = [...def.dataSets || []].sort((a, b) => score2(b) - score2(a))[0];
33351
33476
  return { title: "", split: "", stacked: false, format: "N0", ...guess(ds2, sample?.dataSets?.[ds2?.name] || []) };
33352
33477
  });
33353
33478
  const set2 = (patch) => setC((x) => ({ ...x, ...patch, custom: false }));
33354
- (0, import_react17.useEffect)(() => {
33479
+ (0, import_react18.useEffect)(() => {
33355
33480
  if (!sample?.dataSets && !sample?.loading) loadSample();
33356
33481
  }, []);
33357
33482
  const ds = (def.dataSets || []).find((d) => d.name === c.dataSet);
@@ -33362,7 +33487,7 @@ function ChartWizard() {
33362
33487
  const good = suggested(c, rows, fields);
33363
33488
  const dateCategory = fields.find((f) => f.name === c.category)?.type === "date";
33364
33489
  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)(() => {
33490
+ const compact = (0, import_react18.useMemo)(() => {
33366
33491
  if (!c.value || c.agg === "Count" || c.format === "P1") return null;
33367
33492
  const per = /* @__PURE__ */ new Map();
33368
33493
  for (const r of rows) {
@@ -33378,14 +33503,14 @@ function ChartWizard() {
33378
33503
  const d = def.dataSets.find((x) => x.name === name2);
33379
33504
  setC((x) => ({ ...x, split: "", ...guess(d, sample?.dataSets?.[name2] || []) }));
33380
33505
  };
33381
- (0, import_react17.useEffect)(() => {
33506
+ (0, import_react18.useEffect)(() => {
33382
33507
  if (editing || !rows.length || c.touched) return;
33383
33508
  setC((x) => ({ ...x, ...guess(ds, rows), touched: true }));
33384
33509
  }, [rows.length]);
33385
- const [thumbs, setThumbs] = (0, import_react17.useState)({});
33386
- const [big, setBig] = (0, import_react17.useState)(null);
33510
+ const [thumbs, setThumbs] = (0, import_react18.useState)({});
33511
+ const [big, setBig] = (0, import_react18.useState)(null);
33387
33512
  const cfgKey = JSON.stringify({ ...c, touched: void 0 });
33388
- (0, import_react17.useEffect)(() => {
33513
+ (0, import_react18.useEffect)(() => {
33389
33514
  if (!sample?.dataSets || !c.dataSet) return;
33390
33515
  let alive = true;
33391
33516
  const t3 = setTimeout(async () => {
@@ -33573,7 +33698,7 @@ function rawText(raw) {
33573
33698
  }
33574
33699
 
33575
33700
  // src/designer/TableWizard.jsx
33576
- var import_react18 = __toESM(require_react(), 1);
33701
+ var import_react19 = __toESM(require_react(), 1);
33577
33702
  var import_jsx_runtime17 = __toESM(require_jsx_runtime(), 1);
33578
33703
  var LAYOUTS = [
33579
33704
  { id: "list", label: "List", when: "Every row, with totals" },
@@ -33586,12 +33711,13 @@ function TableWizard() {
33586
33711
  const wiz = useDesigner((s) => s.tableWizard);
33587
33712
  const def = useDesigner((s) => s.def);
33588
33713
  const sample = useDesigner((s) => s.sample);
33714
+ const lang2 = useDesigner((s) => s.lang);
33589
33715
  const close = () => useDesigner.getState().setUi({ tableWizard: null });
33590
33716
  const parent = wiz?.parentId ? findItem(def, wiz.parentId)?.item : null;
33591
33717
  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: "" }));
33718
+ 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
33719
  const set2 = (patch) => setC((x) => ({ ...x, ...patch }));
33594
- (0, import_react18.useEffect)(() => {
33720
+ (0, import_react19.useEffect)(() => {
33595
33721
  if (!sample?.dataSets && !sample?.loading) loadSample();
33596
33722
  }, []);
33597
33723
  const ds = (def.dataSets || []).find((d) => d.name === c.dataSet);
@@ -33605,9 +33731,9 @@ function TableWizard() {
33605
33731
  const groupBy2 = c.groupBy || groupGuess;
33606
33732
  const mRows = c.mRows || groupBy2, mCols = c.mCols || text.find((f) => f.name !== mRows)?.name || "", mValue = c.mValue || nums[0]?.name || "";
33607
33733
  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)({});
33734
+ const [thumbs, setThumbs] = (0, import_react19.useState)({});
33609
33735
  const key2 = JSON.stringify([c, groupBy2, mRows, mCols, mValue, chosen]);
33610
- (0, import_react18.useEffect)(() => {
33736
+ (0, import_react19.useEffect)(() => {
33611
33737
  if (!ds || !sample?.dataSets) return;
33612
33738
  let alive = true;
33613
33739
  const t3 = setTimeout(async () => {
@@ -33652,7 +33778,7 @@ function TableWizard() {
33652
33778
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { className: "btn ghost", onClick: () => {
33653
33779
  useDesigner.getState().setUi({ tableWizard: null, pivotWizard: { section: wiz.section, x: wiz.x, y: wiz.y, parentId: wiz.parentId, dataSet: c.dataSet } });
33654
33780
  }, "data-testid": "open-pivot-wizard", children: [
33655
- t(useDesigner.getState().lang, "pivotWizard"),
33781
+ t(lang2, "pivotWizard"),
33656
33782
  "…"
33657
33783
  ] }),
33658
33784
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { className: "btn", onClick: close, children: "Cancel" }),
@@ -33665,7 +33791,7 @@ function TableWizard() {
33665
33791
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "cw-side", "aria-label": "Data for the table", children: [
33666
33792
  /* @__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
33793
  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)) }),
33794
+ noSourceKey(def) && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "hint", role: "status", "data-testid": "no-source", children: t(lang2, noSourceKey(def)) }),
33669
33795
  sample?.error && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "err", children: sample.error }),
33670
33796
  c.layout !== "matrix" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
33671
33797
  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 +33821,7 @@ function TableWizard() {
33695
33821
  }
33696
33822
 
33697
33823
  // src/designer/AskAi.jsx
33698
- var import_react19 = __toESM(require_react(), 1);
33824
+ var import_react20 = __toESM(require_react(), 1);
33699
33825
  var import_jsx_runtime18 = __toESM(require_jsx_runtime(), 1);
33700
33826
  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
33827
  function changes(before, after) {
@@ -33711,9 +33837,9 @@ function changes(before, after) {
33711
33837
  function AskAi({ onClose }) {
33712
33838
  const def = useDesigner((s) => s.def);
33713
33839
  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)(() => {
33840
+ const [prompt, setPrompt] = (0, import_react20.useState)("");
33841
+ const [st, setSt] = (0, import_react20.useState)({ state: "idle" });
33842
+ (0, import_react20.useEffect)(() => {
33717
33843
  if (!sample?.dataSets && !sample?.loading) loadSample();
33718
33844
  }, []);
33719
33845
  const ask = async () => {
@@ -33727,7 +33853,7 @@ function AskAi({ onClose }) {
33727
33853
  let preview = null;
33728
33854
  try {
33729
33855
  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()) });
33856
+ 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
33857
  preview = { html: pageToSvg(model.pages[0], model.width, model.height), pages: model.pages.length };
33732
33858
  } catch (e) {
33733
33859
  preview = { error: e.message };
@@ -33798,7 +33924,7 @@ function AskAi({ onClose }) {
33798
33924
  }
33799
33925
 
33800
33926
  // src/designer/PivotWizard.jsx
33801
- var import_react20 = __toESM(require_react(), 1);
33927
+ var import_react21 = __toESM(require_react(), 1);
33802
33928
  var import_jsx_runtime19 = __toESM(require_jsx_runtime(), 1);
33803
33929
  var MIME_PF = "application/x-pw-pivot-field";
33804
33930
  var AGGS2 = ["Sum", "Avg", "Count", "Min", "Max"];
@@ -33830,9 +33956,9 @@ function Thumb({ item }) {
33830
33956
  const T = useT2();
33831
33957
  const def = useDesigner((s) => s.def);
33832
33958
  const sample = useDesigner((s) => s.sample);
33833
- const [svg, setSvg] = (0, import_react20.useState)(null);
33959
+ const [svg, setSvg] = (0, import_react21.useState)(null);
33834
33960
  const key2 = JSON.stringify(item);
33835
- (0, import_react20.useEffect)(() => {
33961
+ (0, import_react21.useEffect)(() => {
33836
33962
  if (!item || !sample?.dataSets) return void 0;
33837
33963
  let alive = true;
33838
33964
  const t3 = setTimeout(() => {
@@ -33854,7 +33980,7 @@ function Thumb({ item }) {
33854
33980
  function useData(name2) {
33855
33981
  const def = useDesigner((s) => s.def);
33856
33982
  const sample = useDesigner((s) => s.sample);
33857
- (0, import_react20.useEffect)(() => {
33983
+ (0, import_react21.useEffect)(() => {
33858
33984
  if (!sample?.dataSets && !sample?.loading) loadSample();
33859
33985
  }, []);
33860
33986
  const ds = (def.dataSets || []).find((d) => d.name === name2);
@@ -33869,10 +33995,10 @@ function placeOf(w, def) {
33869
33995
  function PivotWizard() {
33870
33996
  const T = useT2();
33871
33997
  const w = useDesigner((s) => s.pivotWizard);
33872
- const [dsName, setDs] = (0, import_react20.useState)(() => w?.dataSet || useDesigner.getState().def.dataSets?.[0]?.name);
33998
+ const [dsName, setDs] = (0, import_react21.useState)(() => w?.dataSet || useDesigner.getState().def.dataSets?.[0]?.name);
33873
33999
  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);
34000
+ const [lay, setLay] = (0, import_react21.useState)({ rows: [], columns: [], values: [] });
34001
+ const [totals, setTotals] = (0, import_react21.useState)(true);
33876
34002
  const close = () => useDesigner.getState().setUi({ pivotWizard: null });
33877
34003
  const width = Math.round(bodyWidth(def, w?.section || "body") - (w?.x || 0));
33878
34004
  const add = (zone2, f) => setLay((l) => {
@@ -33993,13 +34119,13 @@ function InstantVisuals() {
33993
34119
  const T = useT2();
33994
34120
  const w = useDesigner((s) => s.instantVisuals);
33995
34121
  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);
34122
+ const [picked, setPickedRaw] = (0, import_react21.useState)(() => instantPicks(ds?.fields || [], rows));
34123
+ const [touched, setTouched] = (0, import_react21.useState)(false);
33998
34124
  const setPicked = (fn3) => {
33999
34125
  setTouched(true);
34000
34126
  setPickedRaw(fn3);
34001
34127
  };
34002
- (0, import_react20.useEffect)(() => {
34128
+ (0, import_react21.useEffect)(() => {
34003
34129
  if (!touched) setPickedRaw(instantPicks(ds?.fields || [], rows));
34004
34130
  }, [rows.length, ds]);
34005
34131
  const close = () => useDesigner.getState().setUi({ instantVisuals: null });
@@ -34199,9 +34325,10 @@ var TOOLS = [
34199
34325
  ] }) }
34200
34326
  ];
34201
34327
  function Toolbox({ T, hide = [] }) {
34328
+ const api = useDesignerStore();
34202
34329
  const name2 = (type) => T(`item_${type}`) === `item_${type}` ? ITEMS[type].label : T(`item_${type}`);
34203
34330
  const add = (type) => {
34204
- const s = useDesigner.getState();
34331
+ const s = api.getState();
34205
34332
  const at2 = insertSpot(s.def, s.sel);
34206
34333
  insertItem(type, at2.section, 0, at2.y, {}, at2.parentId);
34207
34334
  };
@@ -34250,12 +34377,15 @@ var TbGroup = ({ label, children }) => /* @__PURE__ */ (0, import_jsx_runtime20.
34250
34377
  ] });
34251
34378
  var QUICK = [["textbox", "text"], ["table", "table"], ["chart", "chart"], ["image", "image"]];
34252
34379
  function LeftRail({ T, readOnly: readOnly2, embed }) {
34253
- const body = (0, import_react21.useRef)(null);
34254
- const [at2, setAt] = (0, import_react21.useState)("tools");
34380
+ const body = (0, import_react22.useRef)(null);
34381
+ const [at2, setAt] = (0, import_react22.useState)("tools");
34255
34382
  const tabs = [!readOnly2 && ["tools", "b2_toolbox", "tools"], embed?.panels?.data !== false && ["data", "b2_data", "data"], ["outline", "b2_outline", "outline"]].filter(Boolean);
34256
34383
  const go = (id) => {
34257
34384
  const el = body.current?.querySelector(`[data-rail="${id}"]`);
34258
- if (el) body.current.scrollTo({ top: el.offsetTop - body.current.offsetTop, behavior: "smooth" });
34385
+ if (el) {
34386
+ body.current.scrollTo({ top: el.offsetTop - body.current.offsetTop, behavior: "smooth" });
34387
+ (el.querySelector('[data-opt][tabindex="0"]') || el.querySelector("button, input, select, textarea"))?.focus({ preventScroll: true });
34388
+ }
34259
34389
  setAt(id);
34260
34390
  };
34261
34391
  const spy = () => {
@@ -34357,8 +34487,9 @@ var framed = () => {
34357
34487
  }
34358
34488
  };
34359
34489
  function useAutosave(id, T, lang2, user) {
34360
- const [offer, setOffer] = (0, import_react21.useState)(null);
34361
- (0, import_react21.useEffect)(() => {
34490
+ const api = useDesignerStore();
34491
+ const [offer, setOffer] = (0, import_react22.useState)(null);
34492
+ (0, import_react22.useEffect)(() => {
34362
34493
  if (!id || user == null || framed()) return void 0;
34363
34494
  let store;
34364
34495
  try {
@@ -34368,10 +34499,10 @@ function useAutosave(id, T, lang2, user) {
34368
34499
  }
34369
34500
  clearDrafts(store, user);
34370
34501
  const d = readDraft(store, user, id);
34371
- if (d && plain(mergeDraft(d.def, useDesigner.getState().def)) !== plain(useDesigner.getState().def)) setOffer(d);
34502
+ if (d && plain(mergeDraft(d.def, api.getState().def)) !== plain(api.getState().def)) setOffer(d);
34372
34503
  else if (d) clearDraft(store, user, id);
34373
34504
  const keep = () => {
34374
- const s = useDesigner.getState();
34505
+ const s = api.getState();
34375
34506
  if (!s.saved && !s.readOnly) writeDraft(store, user, id, s.def, Date.now(), s.rev || null);
34376
34507
  };
34377
34508
  const t3 = setInterval(keep, AUTOSAVE_MS);
@@ -34380,7 +34511,7 @@ function useAutosave(id, T, lang2, user) {
34380
34511
  };
34381
34512
  window.addEventListener("pagehide", keep);
34382
34513
  document.addEventListener("visibilitychange", hide);
34383
- const unsub = useDesigner.subscribe((s, prev) => {
34514
+ const unsub = api.subscribe((s, prev) => {
34384
34515
  if (s.saved && !prev.saved) clearDraft(store, user, id);
34385
34516
  });
34386
34517
  return () => {
@@ -34392,13 +34523,13 @@ function useAutosave(id, T, lang2, user) {
34392
34523
  }, [id, user]);
34393
34524
  if (!offer) return null;
34394
34525
  const when = new Date(offer.at).toLocaleString(lang2 === "en" ? "en-IN" : lang2, { dateStyle: "medium", timeStyle: "short" });
34395
- const stale = staleDraft(offer, useDesigner.getState().rev);
34526
+ const stale = staleDraft(offer, api.getState().rev);
34396
34527
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "draft-bar", role: "alert", "data-testid": "draft-offer", "data-stale": stale || void 0, children: [
34397
34528
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: T(stale ? "ux_draftStale" : "ux_draftFound", { when }) }),
34398
34529
  /* @__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();
34530
+ const d = mergeDraft(offer.def, api.getState().def);
34531
+ api.getState().apply(() => JSON.parse(JSON.stringify(d)));
34532
+ api.getState().fixSelection();
34402
34533
  setOffer(null);
34403
34534
  }, children: T(stale ? "ux_draftRestoreAnyway" : "ux_draftRestore") }),
34404
34535
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { className: "btn sm", "data-testid": "draft-discard", onClick: () => {
@@ -34411,12 +34542,13 @@ function useAutosave(id, T, lang2, user) {
34411
34542
  ] });
34412
34543
  }
34413
34544
  function ConflictBar({ T }) {
34545
+ const api = useDesignerStore();
34414
34546
  const conflict = useDesigner((s) => s.conflict);
34415
34547
  if (!conflict) return null;
34416
34548
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "draft-bar", role: "alert", "data-testid": "save-conflict", children: [
34417
34549
  /* @__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") })
34550
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { className: "btn sm", "data-testid": "conflict-mine", onClick: () => api.getState().save({ overwrite: true }), children: T("ux_conflictMine") }),
34551
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { className: "btn sm", "data-testid": "conflict-theirs", onClick: () => api.getState().takeTheirs(), children: T("ux_conflictTheirs") })
34420
34552
  ] });
34421
34553
  }
34422
34554
  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 +34598,7 @@ var ALIGN2 = [
34466
34598
  ];
34467
34599
  function AlignBar({ T }) {
34468
34600
  const sel = useDesigner((s) => s.sel);
34469
- const [toPage, setToPage] = (0, import_react21.useState)(false);
34601
+ const [toPage, setToPage] = (0, import_react22.useState)(false);
34470
34602
  if (sel.kind !== "items" || !sel.ids.length) return null;
34471
34603
  const n = sel.ids.length;
34472
34604
  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 +34613,14 @@ function AlignBar({ T }) {
34481
34613
  ] });
34482
34614
  }
34483
34615
  function IssuesButton({ T }) {
34616
+ const api = useDesignerStore();
34484
34617
  const issues = useDesignIssues();
34485
- const [open, setOpen] = (0, import_react21.useState)(false);
34486
- (0, import_react21.useEffect)(() => {
34618
+ const [open, setOpen] = (0, import_react22.useState)(false);
34619
+ (0, import_react22.useEffect)(() => {
34487
34620
  if (!issues.length) setOpen(false);
34488
34621
  }, [issues.length]);
34489
- const listRef = (0, import_react21.useRef)(null);
34490
- (0, import_react21.useLayoutEffect)(() => {
34622
+ const listRef = (0, import_react22.useRef)(null);
34623
+ (0, import_react22.useLayoutEffect)(() => {
34491
34624
  const el = listRef.current;
34492
34625
  if (!el) return void 0;
34493
34626
  const place = () => {
@@ -34504,7 +34637,7 @@ function IssuesButton({ T }) {
34504
34637
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "issues-wrap", children: [
34505
34638
  /* @__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
34639
  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] });
34640
+ if (i2.id) api.getState().select({ kind: "items", ids: [i2.id] });
34508
34641
  }, children: issueLine(T, i2) }) }, k)) })
34509
34642
  ] });
34510
34643
  }
@@ -34528,9 +34661,10 @@ var SHORTCUTS = [
34528
34661
  ["?", "sc_help"]
34529
34662
  ];
34530
34663
  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)(() => {
34664
+ const api = useDesignerStore();
34665
+ const [list2, setList] = (0, import_react22.useState)(null);
34666
+ const [err, setErr] = (0, import_react22.useState)(null);
34667
+ (0, import_react22.useEffect)(() => {
34534
34668
  fetch(`/api/reports/${id}/versions`).then((r) => r.json()).then(setList).catch((e) => setErr(e.message));
34535
34669
  }, [id]);
34536
34670
  const restore = async (v) => {
@@ -34540,7 +34674,7 @@ function HistoryDialog({ id, onClose, T, lang: lang2 }) {
34540
34674
  return;
34541
34675
  }
34542
34676
  const def = await res.json();
34543
- useDesigner.getState().init(id, def);
34677
+ api.getState().init(id, def);
34544
34678
  onClose();
34545
34679
  };
34546
34680
  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 +34696,48 @@ function HistoryDialog({ id, onClose, T, lang: lang2 }) {
34562
34696
  ] }, v.version))
34563
34697
  ] });
34564
34698
  }
34565
- function Designer({ id, initial, rev = null, lang: langIn, embed = null, user = null, ai = false }) {
34699
+ function Designer({ store: storeIn = null, ...props }) {
34700
+ const [store] = (0, import_react22.useState)(() => {
34701
+ const s = storeIn || newDesignerStore();
34702
+ activateStore(s);
34703
+ return s;
34704
+ });
34705
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DesignerStore.Provider, { value: store, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DesignerIn, { ...props }) });
34706
+ }
34707
+ var ACTIVATE = [
34708
+ "onPointerDownCapture",
34709
+ "onMouseDownCapture",
34710
+ "onKeyDownCapture",
34711
+ "onFocusCapture",
34712
+ "onClickCapture",
34713
+ "onInputCapture",
34714
+ "onChangeCapture",
34715
+ "onDragStartCapture",
34716
+ "onDragOverCapture",
34717
+ "onDropCapture",
34718
+ "onPasteCapture",
34719
+ "onWheelCapture",
34720
+ "onContextMenuCapture",
34721
+ "onDoubleClickCapture",
34722
+ "onSubmitCapture"
34723
+ ];
34724
+ function DesignerIn({ id, initial, rev = null, lang: langIn, embed = null, user = null, ai = false }) {
34725
+ const api = useDesignerStore();
34726
+ const activators = (0, import_react22.useMemo)(() => {
34727
+ const on = () => activateStore(api);
34728
+ return Object.fromEntries(ACTIVATE.map((k) => [k, on]));
34729
+ }, [api]);
34566
34730
  const lang2 = pickLang(langIn);
34567
34731
  const T = (k, v) => t(lang2, k, v);
34568
34732
  const q2 = lang2 === "en" ? "" : `?lang=${encodeURIComponent(lang2)}`;
34569
- const ready = (0, import_react21.useRef)(false);
34733
+ const ready = (0, import_react22.useRef)(false);
34570
34734
  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 });
34735
+ api.getState().init(id, initial);
34736
+ api.getState().setUi({ lang: lang2, embed, readOnly: !!embed?.readOnly, rev, conflict: null });
34573
34737
  ready.current = true;
34574
34738
  }
34575
34739
  const readOnly2 = !!embed?.readOnly;
34576
- const rootRef = (0, import_react21.useRef)(null);
34740
+ const rootRef = (0, import_react22.useRef)(null);
34577
34741
  const def = useDesigner((s) => s.def);
34578
34742
  const tab = useDesigner((s) => s.tab);
34579
34743
  const saved = useDesigner((s) => s.saved);
@@ -34583,23 +34747,23 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34583
34747
  const snap = useDesigner((s) => s.snap);
34584
34748
  const unit = useDesigner((s) => s.unit);
34585
34749
  const fonts = useDesigner((s) => s.fonts);
34586
- const fontCss = (0, import_react21.useMemo)(() => fontFaceCss(allFontKeys(), fontsBase().replace(/\/$/, "")), [fonts]);
34587
- (0, import_react21.useEffect)(() => {
34750
+ const fontCss = (0, import_react22.useMemo)(() => fontFaceCss(allFontKeys(), fontsBase().replace(/\/$/, "")), [fonts]);
34751
+ (0, import_react22.useEffect)(() => {
34588
34752
  if (embed) declareDocumentStyles("pw-designer-fonts", fontCss);
34589
34753
  }, [embed, fontCss]);
34590
- (0, import_react21.useEffect)(() => {
34591
- customFonts().then((list2) => useDesigner.getState().setUi({ fonts: list2 }));
34754
+ (0, import_react22.useEffect)(() => {
34755
+ customFonts().then((list2) => api.getState().setUi({ fonts: list2 }));
34592
34756
  }, []);
34593
- (0, import_react21.useEffect)(() => {
34757
+ (0, import_react22.useEffect)(() => {
34594
34758
  const z = savedZoom();
34595
- if (z != null) useDesigner.getState().setUi({ zoom: z });
34759
+ if (z != null) api.getState().setUi({ zoom: z });
34596
34760
  }, []);
34597
34761
  const canUndo = useDesigner((s) => s.past.length > 0);
34598
34762
  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);
34763
+ const st = api.getState;
34764
+ const [dialog, setDialog] = (0, import_react22.useState)(null);
34765
+ const [showLeft, setShowLeft] = (0, import_react22.useState)(true);
34766
+ const [showRight, setShowRight] = (0, import_react22.useState)(true);
34603
34767
  const selKind = useDesigner((s) => s.sel.kind);
34604
34768
  const wizard = useDesigner((s) => s.wizard);
34605
34769
  const tableWizard = useDesigner((s) => s.tableWizard);
@@ -34608,12 +34772,18 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34608
34772
  const cells = useDesigner((s) => s.cells);
34609
34773
  const cellSize = useDesigner((s) => s.cellSize);
34610
34774
  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();
34775
+ (0, import_react22.useEffect)(() => {
34776
+ loadSample(api);
34613
34777
  }, [dataKey]);
34614
- (0, import_react21.useEffect)(() => {
34778
+ (0, import_react22.useEffect)(() => {
34779
+ let lastInside = false;
34780
+ const inside = (e) => (e.composedPath?.() || []).includes(rootRef.current);
34781
+ const onDown = (e) => {
34782
+ lastInside = inside(e);
34783
+ };
34784
+ const ours = (e) => inside(e) || lastInside && (e.target === document.body || e.target === document.documentElement);
34615
34785
  const onKey = (e) => {
34616
- if (embed && !(e.composedPath?.() || []).includes(rootRef.current)) return;
34786
+ if (embed && !ours(e)) return;
34617
34787
  const mod = e.metaKey || e.ctrlKey;
34618
34788
  if (mod && e.key.toLowerCase() === "s") {
34619
34789
  e.preventDefault();
@@ -34632,7 +34802,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34632
34802
  st().save();
34633
34803
  return;
34634
34804
  }
34635
- if (isTyping(e) || st().tab !== "design") return;
34805
+ if (isTyping(e) || st().tab !== "design" || e.defaultPrevented) return;
34636
34806
  if (mod && e.key.toLowerCase() === "z") {
34637
34807
  e.preventDefault();
34638
34808
  e.shiftKey ? st().redo() : st().undo();
@@ -34655,11 +34825,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34655
34825
  }
34656
34826
  return;
34657
34827
  }
34658
- if (mod && e.key.toLowerCase() === "v") {
34659
- e.preventDefault();
34660
- pasteItems(st().sel.kind === "section" ? st().sel.section : "body");
34661
- return;
34662
- }
34828
+ if (mod && e.key.toLowerCase() === "v") return;
34663
34829
  if (e.key === "Delete" || e.key === "Backspace") {
34664
34830
  if (st().sel.kind === "items") {
34665
34831
  e.preventDefault();
@@ -34691,10 +34857,24 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34691
34857
  e.returnValue = "";
34692
34858
  }
34693
34859
  };
34860
+ const onPaste = (e) => {
34861
+ if (embed && !ours(e) || isTyping(e) || st().tab !== "design") return;
34862
+ e.preventDefault();
34863
+ if (!pasteItems(st().sel.kind === "section" ? st().sel.section : "body", e.clipboardData?.getData("text/plain"))) {
34864
+ st().setUi({ saveError: t(lang2, "b9_nothingToPaste") });
34865
+ setTimeout(() => st().setUi({ saveError: null }), 3e3);
34866
+ }
34867
+ };
34694
34868
  window.addEventListener("keydown", onKey);
34869
+ window.addEventListener("paste", onPaste);
34870
+ window.addEventListener("pointerdown", onDown, true);
34871
+ window.addEventListener("focusin", onDown, true);
34695
34872
  if (!embed) window.addEventListener("beforeunload", onLeave);
34696
34873
  return () => {
34697
34874
  window.removeEventListener("keydown", onKey);
34875
+ window.removeEventListener("paste", onPaste);
34876
+ window.removeEventListener("pointerdown", onDown, true);
34877
+ window.removeEventListener("focusin", onDown, true);
34698
34878
  window.removeEventListener("beforeunload", onLeave);
34699
34879
  };
34700
34880
  }, [st, embed]);
@@ -34713,17 +34893,17 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34713
34893
  const d = await embed.onOpen();
34714
34894
  if (d && typeof d === "object") {
34715
34895
  st().init(id, d);
34716
- loadSample();
34896
+ loadSample(api);
34717
34897
  }
34718
34898
  };
34719
- const importInput = (0, import_react21.useRef)(null);
34720
- const [imported, setImported] = (0, import_react21.useState)(null);
34899
+ const importInput = (0, import_react22.useRef)(null);
34900
+ const [imported, setImported] = (0, import_react22.useState)(null);
34721
34901
  const importFile = async (file) => {
34722
34902
  if (!file) return;
34723
34903
  const r = readReportFile(file.name, await file.text());
34724
34904
  if (r.definition) {
34725
34905
  st().init(id, r.definition);
34726
- loadSample();
34906
+ loadSample(api);
34727
34907
  }
34728
34908
  setImported({ name: file.name, ok: !!r.definition, warnings: r.warnings || [], error: r.error });
34729
34909
  };
@@ -34737,7 +34917,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34737
34917
  ] }),
34738
34918
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "hint", children: T("loadingDesigner") })
34739
34919
  ] }) });
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: [
34920
+ 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
34921
  !embed && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("style", { children: fontCss }),
34742
34922
  /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("header", { className: "dtop dbar", children: [
34743
34923
  embed ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "brand", children: [
@@ -34844,7 +35024,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34844
35024
  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
35025
  ] }),
34846
35026
  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: [
35027
+ import_react22.Fragment, { children: [
34848
35028
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "kbd", children: k }),
34849
35029
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: T(d) })
34850
35030
  ] }, d)) }) }),
@@ -34926,6 +35106,7 @@ var CSS2 = true ? `/* Layout: a drafting table. Cool grey workspace, white paper
34926
35106
  --ink: #16202a;
34927
35107
  --muted: #5f6b77;
34928
35108
  --faint: #64717e; /* 5:1 on panel (was #8e99a4, 2.9:1) */
35109
+ --faint-desk: #5a6672; /* small text on the desk: 4.85:1 on #e6eaee (--faint is 4.13:1 there) */
34929
35110
  --line-strong: #848f9b; /* control borders, 3:1 */
34930
35111
  --accent: #0e7490;
34931
35112
  --accent-ink: #ffffff;
@@ -34979,6 +35160,7 @@ var CSS2 = true ? `/* Layout: a drafting table. Cool grey workspace, white paper
34979
35160
  --ink: #e6edf3;
34980
35161
  --muted: #a3afbb;
34981
35162
  --faint: #8693a0;
35163
+ --faint-desk: #8693a0;
34982
35164
  --accent: #3cbfd4;
34983
35165
  --accent-ink: #03222a;
34984
35166
  --accent-soft: #123a44;
@@ -35276,6 +35458,7 @@ a.cell-name:hover { color: var(--accent); }
35276
35458
  .outline-row.sel { background: var(--accent-soft); }
35277
35459
  .outline-row .linklike.nm, .outline-band { text-decoration: none; color: var(--ink); text-align: start; }
35278
35460
  .outline-row.sel .linklike.nm, .outline-band.sel { color: var(--accent); }
35461
+ .outline-row.sel .ty { color: var(--muted); } /* --faint is 4.38:1 on --accent-soft; --muted passes in both themes */
35279
35462
  .outline-row.sel .act, .outline-row:focus-within .act { opacity: 1; }
35280
35463
  .outline-row[draggable="true"] { cursor: grab; }
35281
35464
  .outline-row .grip { color: var(--faint); font-size: 10px; line-height: 1; margin-inline-start: -2px; opacity: .55; }
@@ -35317,7 +35500,7 @@ a.cell-name:hover { color: var(--accent); }
35317
35500
  .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
35501
  .tbl.sel .grip { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
35319
35502
  .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%; }
35503
+ .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
35504
  .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
35505
  .tbl .cell:first-child { border-left: 1px dashed rgba(95,107,119,.3); }
35323
35506
  .tbl .row:first-child .cell { border-top: 1px dashed rgba(95,107,119,.3); }
@@ -35837,7 +36020,7 @@ input[type=checkbox], input[type=radio] { width: 16px; height: 16px; accent-colo
35837
36020
 
35838
36021
  .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
36022
  ` : "";
35840
- var BLANK = { $schema: "pagewright/report@1", name: "New report", page: { size: "A4", margins: [36, 36, 36, 36] }, dataSources: [], dataSets: [], sections: { body: { items: [] } } };
36023
+ var BLANK = { $schema: "pagewright/report@1", name: "Untitled report", page: { size: "A4", margins: [36, 36, 36, 36] }, dataSources: [], dataSets: [], sections: { body: { items: [] } } };
35841
36024
  function mountDesigner(target, opts = {}) {
35842
36025
  const el = typeof target === "string" ? document.querySelector(target) : target;
35843
36026
  if (!el) throw new Error(`mountDesigner: no element for ${target}`);
@@ -35855,18 +36038,43 @@ function mountDesigner(target, opts = {}) {
35855
36038
  );
35856
36039
  box.style.height = opts.height || "760px";
35857
36040
  const root = (0, import_client.createRoot)(box);
36041
+ const store = newDesignerStore();
35858
36042
  const embed = { onSave: opts.onSave, onOpen: opts.onOpen, readOnly: !!opts.readOnly, toolbox: opts.toolbox, panels: opts.panels, dataSourceTemplates: opts.dataSourceTemplates, server: server2 };
35859
36043
  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 })));
36044
+ }).then(() => root.render((0, import_react23.createElement)(Designer, { id: opts.report, initial: definition, lang: opts.lang, embed, store })));
35861
36045
  if (opts.definition || !opts.report) show(opts.definition || BLANK);
35862
36046
  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
36047
  box.innerHTML = `<div class="vmsg error">The report did not load: ${String(e.message).replace(/</g, "&lt;")}</div>`;
35864
36048
  });
36049
+ const onLeave = (e) => {
36050
+ e.preventDefault();
36051
+ e.returnValue = "";
36052
+ };
36053
+ let dirty = false;
36054
+ const unsub = store.subscribe((s) => {
36055
+ if (!s.saved === dirty) return;
36056
+ dirty = !s.saved;
36057
+ if (opts.warnOnLeave !== false) {
36058
+ if (dirty) window.addEventListener("beforeunload", onLeave);
36059
+ else window.removeEventListener("beforeunload", onLeave);
36060
+ }
36061
+ try {
36062
+ opts.onDirtyChange?.(dirty);
36063
+ } catch (e) {
36064
+ console.error(e);
36065
+ }
36066
+ });
35865
36067
  return {
35866
- unmount: () => root.unmount(),
36068
+ unmount: () => {
36069
+ unsub();
36070
+ window.removeEventListener("beforeunload", onLeave);
36071
+ root.unmount();
36072
+ },
36073
+ /** whether there are changes not saved yet */
36074
+ isDirty: () => !store.getState().saved,
35867
36075
  /** the definition as it is now (a plain copy) */
35868
- getDefinition: () => JSON.parse(JSON.stringify(useDesigner.getState().def)),
35869
- save: () => useDesigner.getState().save()
36076
+ getDefinition: () => JSON.parse(JSON.stringify(store.getState().def)),
36077
+ save: () => store.getState().save()
35870
36078
  };
35871
36079
  }
35872
36080
  export {