@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
@@ -10,16 +10,18 @@ import {
10
10
  setShadowStyles,
11
11
  t,
12
12
  uiFontCss
13
- } from "./chunk-6I2EAAVN.js";
13
+ } from "./chunk-7IP67PA6.js";
14
14
  import {
15
15
  customFonts,
16
- fontStore,
17
16
  fontsBase,
17
+ loadFontStore,
18
18
  loadModelFonts,
19
19
  origin,
20
+ reportFetch,
20
21
  setAssetBase,
22
+ setFetchPolicy,
21
23
  setStandalone
22
- } from "./chunk-BQFI3DHK.js";
24
+ } from "./chunk-RKFP7SDY.js";
23
25
  import {
24
26
  BASE_STYLE,
25
27
  DEFAULT_THEME,
@@ -28,10 +30,10 @@ import {
28
30
  ITEMS,
29
31
  ODATA_DEFAULT_PAGES,
30
32
  ODATA_MAX_PAGES,
31
- PAGE_SIZES,
32
33
  PALETTES,
33
34
  TEXT_STYLE_PROPS,
34
35
  THEME_COLORS,
36
+ TextMeasurer,
35
37
  XmlError,
36
38
  bestXmlRows,
37
39
  buildDataSets,
@@ -40,7 +42,7 @@ import {
40
42
  detectFields,
41
43
  evalValue,
42
44
  findItemNamed,
43
- fromPt,
45
+ finishText,
44
46
  functionTable,
45
47
  isDynamic,
46
48
  isTablix,
@@ -49,48 +51,46 @@ import {
49
51
  layoutItems,
50
52
  loadBarcodes,
51
53
  loadSources,
52
- normBox,
53
54
  normalizeMatrix,
54
55
  odataMetadata,
55
56
  parseBorder,
56
57
  parseXml,
57
58
  render,
58
- reportFetch,
59
- resolvePage,
60
59
  resolveParameters,
61
- setFetchPolicy,
62
60
  shiftItems,
63
61
  sourceRows,
64
62
  sourceUrl,
65
63
  stylePropsFor,
66
64
  themeContext,
67
- toPt,
68
65
  toText,
69
66
  validate,
70
67
  withPartProps,
71
68
  xmlRowPaths
72
- } from "../chunk-VNOWPSE6.js";
73
- import {
74
- TextMeasurer,
75
- finishText
76
- } from "../chunk-ULKEEARQ.js";
77
- import "../chunk-72S6DETS.js";
69
+ } from "./chunk-WVQQCD4M.js";
78
70
  import {
79
- currencyOf
80
- } from "../chunk-GJS242RR.js";
71
+ PAGE_SIZES,
72
+ fromPt,
73
+ normBox,
74
+ resolvePage,
75
+ toPt
76
+ } from "../chunk-BR5K6SBL.js";
81
77
  import "../chunk-F6RMRXIN.js";
82
78
  import {
83
79
  fontFaceCss,
84
80
  fontFamilyCss,
85
81
  pageToSvg
86
- } from "../chunk-M6AYND5G.js";
82
+ } from "./chunk-MXR6JBMP.js";
83
+ import "../chunk-72S6DETS.js";
87
84
  import {
88
85
  BUNDLED_FAMILIES,
89
86
  FONT_FAMILIES,
90
87
  allFontKeys,
91
88
  fallbackKeys,
92
89
  resolveFontKey
93
- } from "../chunk-Z7MKH66Z.js";
90
+ } from "./chunk-JQTRDHQP.js";
91
+ import {
92
+ currencyOf
93
+ } from "../chunk-GJS242RR.js";
94
94
 
95
95
  // src/embed/designer.js
96
96
  import { createElement as createElement2 } from "react";
@@ -6861,10 +6861,10 @@ function readReportFile(name2, text) {
6861
6861
  }
6862
6862
 
6863
6863
  // src/designer/Designer.jsx
6864
- import { Fragment as Fragment13, useEffect as useEffect13, useLayoutEffect as useLayoutEffect3, useMemo as useMemo5, useRef as useRef7, useState as useState17 } from "react";
6864
+ import { Fragment as Fragment13, useEffect as useEffect13, useLayoutEffect as useLayoutEffect3, useMemo as useMemo5, useRef as useRef8, useState as useState17 } from "react";
6865
6865
 
6866
6866
  // src/designer/ui.jsx
6867
- import { createContext, useContext, useEffect, useState } from "react";
6867
+ import { createContext as createContext2, useContext as useContext2, useEffect, useRef, useState } from "react";
6868
6868
 
6869
6869
  // src/designer/fieldCheck.js
6870
6870
  function exprParts(value) {
@@ -6998,13 +6998,9 @@ function useStore(api, selector = identity) {
6998
6998
  React.useDebugValue(slice);
6999
6999
  return slice;
7000
7000
  }
7001
- var createImpl = (createState) => {
7002
- const api = createStore(createState);
7003
- const useBoundStore = (selector) => useStore(api, selector);
7004
- Object.assign(useBoundStore, api);
7005
- return useBoundStore;
7006
- };
7007
- var create = ((createState) => createState ? createImpl(createState) : createImpl);
7001
+
7002
+ // src/designer/store.js
7003
+ import { createContext, useContext } from "react";
7008
7004
 
7009
7005
  // node_modules/immer/dist/immer.mjs
7010
7006
  var NOTHING = /* @__PURE__ */ Symbol.for("immer-nothing");
@@ -7853,6 +7849,17 @@ function pageOf2(def, key2 = "body") {
7853
7849
  return resolvePage({ ...def.page || {}, ...sec?.page || {} });
7854
7850
  }
7855
7851
  var rid = () => Math.random().toString(36).slice(2, 10);
7852
+ function stableId(key2, taken) {
7853
+ let h = 2166136261;
7854
+ for (let i2 = 0; i2 < key2.length; i2++) {
7855
+ h ^= key2.charCodeAt(i2);
7856
+ h = Math.imul(h, 16777619);
7857
+ }
7858
+ let id = `i${(h >>> 0).toString(36)}`;
7859
+ for (let k = 2; taken.has(id); k++) id = `i${(h >>> 0).toString(36)}_${k}`;
7860
+ taken.add(id);
7861
+ return id;
7862
+ }
7856
7863
  function walk(def, fn3) {
7857
7864
  const go = (list2, parent, section) => list2.forEach((it, i2) => {
7858
7865
  fn3(it, list2, i2, parent, section);
@@ -7878,9 +7885,15 @@ function normalize(def) {
7878
7885
  if (x && typeof x === "object") x.items || (x.items = []);
7879
7886
  }
7880
7887
  const used = allNames(d);
7888
+ const ids = /* @__PURE__ */ new Set();
7881
7889
  walk(d, (it) => {
7882
- it.id || (it.id = rid());
7890
+ if (it.id) ids.add(it.id);
7891
+ });
7892
+ const path = /* @__PURE__ */ new Map();
7893
+ walk(d, (it, list2, i2, parent, section) => {
7894
+ path.set(it, `${parent ? path.get(parent) : section}/${i2}`);
7883
7895
  if (!it.name) it.name = uniqueName(used, ITEMS[it.type]?.label.replace(/\s/g, "") || "Item");
7896
+ it.id || (it.id = stableId(`${path.get(it)}/${it.name}`, ids));
7884
7897
  if (NESTING.has(it.type)) it.items || (it.items = []);
7885
7898
  if (it.type === "table" && Array.isArray(it.columns)) tableSync(it);
7886
7899
  });
@@ -7904,7 +7917,7 @@ function findItem(def, id) {
7904
7917
  });
7905
7918
  return hit;
7906
7919
  }
7907
- var useDesigner = create((set2, get2) => ({
7920
+ var newDesignerStore = () => createStore((set2, get2) => ({
7908
7921
  id: null,
7909
7922
  def: null,
7910
7923
  saved: true,
@@ -8035,7 +8048,18 @@ var useDesigner = create((set2, get2) => ({
8035
8048
  set2({ rev: (res.headers.get("etag") || "").replace(/^W\/|"/g, "") || null, conflict: null });
8036
8049
  }
8037
8050
  }));
8038
- var S = () => useDesigner.getState();
8051
+ var active = newDesignerStore();
8052
+ var DesignerStore = createContext(null);
8053
+ var activateStore = (store) => {
8054
+ active = store;
8055
+ };
8056
+ var activeStore2 = () => active;
8057
+ var useDesignerStore = () => useContext(DesignerStore) || active;
8058
+ var useDesigner = (sel) => useStore(useDesignerStore(), sel);
8059
+ useDesigner.getState = () => active.getState();
8060
+ useDesigner.setState = (...a) => active.setState(...a);
8061
+ useDesigner.subscribe = (fn3) => active.subscribe(fn3);
8062
+ var S = () => active.getState();
8039
8063
  function bodyWidth(def, key2 = "body") {
8040
8064
  return pageOf2(def, key2).bodyWidth;
8041
8065
  }
@@ -8083,7 +8107,7 @@ function addItem(type, section, x, y, extra = {}, parentId = null) {
8083
8107
  } else {
8084
8108
  const sec = secOf(d, section);
8085
8109
  sec.items.push(it);
8086
- if (it.y + it.h > sec.height) sec.height = Math.ceil(it.y + it.h + (isBodyKey(section) ? 24 : 4));
8110
+ if (it.y + it.h > (sec.height || 0)) sec.height = Math.ceil(it.y + it.h + (isBodyKey(section) ? 24 : 4));
8087
8111
  }
8088
8112
  });
8089
8113
  S().select({ kind: "items", ids: [id] });
@@ -8109,9 +8133,21 @@ function insertItem(type, section, x, y, extra = {}, parentId = null) {
8109
8133
  function updateItem(id, recipe, key2) {
8110
8134
  S().apply((d) => {
8111
8135
  const f = findItem(d, id);
8112
- if (f) recipe(f.item, d, f.section, f);
8136
+ if (!f) return;
8137
+ recipe(f.item, d, f.section, f);
8138
+ minSize(f.item);
8139
+ const nf = findItem(d, id);
8140
+ if (nf) growToFit(d, nf);
8113
8141
  }, key2);
8114
8142
  }
8143
+ function minSize(it) {
8144
+ for (const k of ["w", "h"]) if (typeof it[k] === "number" && !(it[k] >= 0)) it[k] = 0;
8145
+ if (it.type === "line") {
8146
+ if (it.w === 0 && it.h === 0) it.w = 1;
8147
+ return;
8148
+ }
8149
+ for (const k of ["w", "h"]) if (typeof it[k] === "number" && it[k] < 1) it[k] = 1;
8150
+ }
8115
8151
  function moveItems(ids, dx, dy) {
8116
8152
  if (!dx && !dy) return;
8117
8153
  if (S().cells && wouldOverlap(S().def, ids, (it) => ({ x: it.x + dx, y: it.y + dy, w: it.w, h: it.h }))) {
@@ -8242,14 +8278,23 @@ function duplicateSelection() {
8242
8278
  const f = findItem(d, id);
8243
8279
  if (!f) continue;
8244
8280
  const copy = cloneWithIds(f.item, used);
8245
- copy.x += 8;
8246
- copy.y += 8;
8281
+ offsetCopy(f.list, copy);
8282
+ growToFit(d, { ...f, item: copy });
8247
8283
  f.list.push(copy);
8248
8284
  newIds.push(copy.id);
8249
8285
  }
8250
8286
  });
8251
8287
  if (newIds.length) S().select({ kind: "items", ids: newIds });
8252
8288
  }
8289
+ var PASTE_OFFSET = 12;
8290
+ function offsetCopy(list2, c) {
8291
+ for (const k of ["x", "y"]) if (!Number.isFinite(c[k])) c[k] = 0;
8292
+ for (let n = 0; n <= list2.length; n++) {
8293
+ c.x += PASTE_OFFSET;
8294
+ c.y += PASTE_OFFSET;
8295
+ if (!list2.some((i2) => i2 !== c && i2.x === c.x && i2.y === c.y)) return;
8296
+ }
8297
+ }
8253
8298
  var CLIP = "pagewright/items@1";
8254
8299
  async function copySelection() {
8255
8300
  const { sel, def } = S();
@@ -8264,43 +8309,40 @@ async function copySelection() {
8264
8309
  return items.length;
8265
8310
  }
8266
8311
  var memClip = null;
8267
- async function pasteItems(section = "body") {
8268
- let text = null;
8269
- try {
8270
- text = await navigator.clipboard.readText();
8271
- } catch {
8272
- text = memClip;
8273
- }
8274
- if (!text || !text.includes(CLIP)) text = memClip;
8275
- let data;
8312
+ var clipOf = (text) => {
8276
8313
  try {
8277
- data = JSON.parse(text);
8314
+ const d = JSON.parse(text);
8315
+ return d?.kind === CLIP && Array.isArray(d.items) ? d : null;
8278
8316
  } catch {
8279
- return 0;
8317
+ return null;
8280
8318
  }
8281
- if (data?.kind !== CLIP || !Array.isArray(data.items)) return 0;
8319
+ };
8320
+ function pasteItems(section = "body", text = null) {
8321
+ const st = active;
8322
+ const data = clipOf(text) || clipOf(memClip);
8323
+ if (!data) return 0;
8282
8324
  const ids = [];
8283
- S().apply((d) => {
8325
+ st.getState().apply((d) => {
8284
8326
  const used = allNames(d);
8285
8327
  for (const it of data.items) {
8286
8328
  const c = cloneWithIds(it, used);
8287
- c.x += 12;
8288
- c.y += 12;
8289
8329
  if (c.type === "table" && !isBodyKey(section)) continue;
8330
+ offsetCopy(secOf(d, section).items, c);
8290
8331
  secOf(d, section).items.push(c);
8332
+ growToFit(d, { section, parent: null, item: c });
8291
8333
  ids.push(c.id);
8292
8334
  }
8293
8335
  });
8294
- if (ids.length) S().select({ kind: "items", ids });
8336
+ if (ids.length) st.getState().select({ kind: "items", ids });
8295
8337
  return ids.length;
8296
8338
  }
8297
- function rowsOf(t3, part, create2 = false) {
8339
+ function rowsOf(t3, part, create = false) {
8298
8340
  const m = /^g(\d+)([hf])$/.exec(part);
8299
8341
  const holder = m ? t3.groups?.[Number(m[1])] : t3;
8300
8342
  if (!holder) return null;
8301
8343
  const key2 = m ? m[2] === "h" ? "header" : "footer" : part;
8302
8344
  if (!holder[key2]) {
8303
- if (!create2) return [];
8345
+ if (!create) return [];
8304
8346
  holder[key2] = [];
8305
8347
  }
8306
8348
  return holder[key2];
@@ -8500,6 +8542,7 @@ function tableRemoveGroup(id, level) {
8500
8542
  }
8501
8543
  var IMAGE_MAX = 10 * 1024 * 1024;
8502
8544
  async function uploadImages(files, T) {
8545
+ const st = active;
8503
8546
  const names = [];
8504
8547
  let err = null;
8505
8548
  for (const f of files) {
@@ -8518,7 +8561,7 @@ async function uploadImages(files, T) {
8518
8561
  r.readAsDataURL(f);
8519
8562
  });
8520
8563
  const base2 = f.name.replace(/\.[^.]+$/, "").replace(/\W+/g, "_").replace(/^_+|_+$/g, "") || "image";
8521
- S().apply((d) => {
8564
+ st.getState().apply((d) => {
8522
8565
  d.images || (d.images = {});
8523
8566
  let n = base2, k = 2;
8524
8567
  while (d.images[n]) n = `${base2}${k++}`;
@@ -8585,6 +8628,13 @@ function wouldOverlap(def, ids, rectOf2) {
8585
8628
  }
8586
8629
  return false;
8587
8630
  }
8631
+ function setMatrixShow(v, show) {
8632
+ const pct = !!show && show !== "value";
8633
+ if (pct) v.show = show;
8634
+ else delete v.show;
8635
+ if (pct && (!v.format || v.format === "N0")) v.format = "P1";
8636
+ else if (!pct && v.format === "P1") v.format = "N0";
8637
+ }
8588
8638
 
8589
8639
  // src/designer/ui.jsx
8590
8640
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -8633,18 +8683,18 @@ function ColorInput({ value, onChange }) {
8633
8683
  /* @__PURE__ */ jsx(TextInput, { value, onChange: (v) => onChange(v === "" ? void 0 : v), mono: true, placeholder: T("i_colorPh") })
8634
8684
  ] });
8635
8685
  }
8636
- var FieldScope = createContext(void 0);
8686
+ var FieldScope = createContext2(void 0);
8637
8687
  var issueText = (T, i2) => i2.suggest ? T("ux_unknownFieldSuggest", { name: i2.name, suggest: i2.suggest }) : T("ux_unknownField", { name: i2.name });
8638
8688
  function ExprInput({ value, onChange, onOpen, placeholder: placeholder2 }) {
8639
8689
  const T = useT();
8640
- const scope = useContext(FieldScope);
8690
+ const scope = useContext2(FieldScope);
8641
8691
  const dataSets = useDesigner((s) => s.def?.dataSets);
8642
8692
  const err = value ? checkValue(value) : null;
8643
8693
  const issues = !err && value && scope !== void 0 ? fieldIssues(value, dataSets, scope) : [];
8644
8694
  return /* @__PURE__ */ jsxs("div", { children: [
8645
8695
  /* @__PURE__ */ jsxs("div", { className: "expr-row", children: [
8646
8696
  /* @__PURE__ */ 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") }),
8647
- /* @__PURE__ */ jsx("button", { className: "fx", title: T("i_openExprEditor"), "aria-label": T("i_openExprEditor"), onClick: onOpen, type: "button", children: "fx" })
8697
+ /* @__PURE__ */ jsx("button", { className: "fx", title: T("i_openExprEditor"), "aria-label": `fx: ${T("i_openExprEditor")}`, onClick: onOpen, type: "button", children: "fx" })
8648
8698
  ] }),
8649
8699
  err && /* @__PURE__ */ jsx("div", { className: "err", children: err }),
8650
8700
  issues.map((i2, k) => /* @__PURE__ */ jsx("div", { className: "warn", "data-testid": "field-warning", children: issueText(T, i2) }, k))
@@ -8664,14 +8714,19 @@ function Check({ label, checked, onChange }) {
8664
8714
  ] });
8665
8715
  }
8666
8716
  function Dialog({ title, children, onClose, footer, wide, className = "" }) {
8717
+ const ref = useRef(null);
8667
8718
  useEffect(() => {
8719
+ const inOther = (e) => {
8720
+ const mine = ref.current?.closest(".designer");
8721
+ return e.composedPath().some((n) => n !== mine && n?.classList?.contains("designer"));
8722
+ };
8668
8723
  const k = (e) => {
8669
- if (e.key === "Escape" && !e.defaultPrevented) onClose();
8724
+ if (e.key === "Escape" && !e.defaultPrevented && !inOther(e)) onClose();
8670
8725
  };
8671
8726
  window.addEventListener("keydown", k);
8672
8727
  return () => window.removeEventListener("keydown", k);
8673
8728
  }, [onClose]);
8674
- return /* @__PURE__ */ jsx("div", { className: "scrim", onPointerDown: (e) => {
8729
+ return /* @__PURE__ */ jsx("div", { className: "scrim", ref, onPointerDown: (e) => {
8675
8730
  if (e.target === e.currentTarget) onClose();
8676
8731
  }, children: /* @__PURE__ */ jsxs("div", { className: `dialog${wide ? " wide" : ""}${className ? ` ${className}` : ""}`, role: "dialog", "aria-modal": "true", "aria-label": title, children: [
8677
8732
  /* @__PURE__ */ jsx("header", { children: title }),
@@ -8687,10 +8742,10 @@ function Link({ href, children, prefetch, replace: replace2, scroll, shallow, ..
8687
8742
  }
8688
8743
 
8689
8744
  // src/designer/SvgHtml.jsx
8690
- import { useLayoutEffect, useRef } from "react";
8745
+ import { useLayoutEffect, useRef as useRef2 } from "react";
8691
8746
  import { jsx as jsx2 } from "react/jsx-runtime";
8692
8747
  function SvgHtml({ html, as: Tag2 = "span", ...rest }) {
8693
- const ref = useRef(
8748
+ const ref = useRef2(
8694
8749
  /** @type {HTMLElement|null} */
8695
8750
  null
8696
8751
  );
@@ -8703,7 +8758,7 @@ function SvgHtml({ html, as: Tag2 = "span", ...rest }) {
8703
8758
  }
8704
8759
 
8705
8760
  // src/designer/Canvas.jsx
8706
- import { createContext as createContext2, useContext as useContext2, useEffect as useEffect3, useMemo, useRef as useRef2, useState as useState4 } from "react";
8761
+ import { createContext as createContext3, useContext as useContext3, useEffect as useEffect3, useMemo, useRef as useRef3, useState as useState4 } from "react";
8707
8762
 
8708
8763
  // src/designer/tableGen.js
8709
8764
  var HEAD = { fontWeight: "bold", backgroundColor: "#f1f5f9", borderBottom: "0.75 solid #94a3b8" };
@@ -8844,7 +8899,11 @@ function useFontFamilies() {
8844
8899
  const fonts = useDesigner((s) => s.fonts);
8845
8900
  return [...BUNDLED_FAMILIES, ...[...new Set(fonts.map((f) => f.family))].sort()];
8846
8901
  }
8847
- var refresh = async () => useDesigner.getState().setUi({ fonts: await customFonts(true) });
8902
+ var refresh = async () => {
8903
+ const api = activeStore2();
8904
+ const fonts = await customFonts(true);
8905
+ api.getState().setUi({ fonts });
8906
+ };
8848
8907
  function FontsDialog({ onClose }) {
8849
8908
  const fonts = useDesigner((s) => s.fonts);
8850
8909
  const [file, setFile] = useState2(null);
@@ -8943,24 +9002,27 @@ var apply = (fn3, key2) => S2().apply(fn3, key2);
8943
9002
  var server = () => S2().embed?.server || "";
8944
9003
  var noServer = () => !!S2().embed && !S2().embed.server;
8945
9004
  var pending = /* @__PURE__ */ new Map();
8946
- function fetchReused(id, force = false) {
9005
+ function fetchReused(id, force = false, api = activeStore2()) {
8947
9006
  if (!id || typeof id !== "string" || id.startsWith("=")) return Promise.resolve(null);
8948
- if (!force && S2().reused[id]) return Promise.resolve(S2().reused[id]);
8949
- if (pending.has(id)) return pending.get(id);
8950
- if (noServer()) return Promise.resolve(null);
8951
- 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) => {
8952
- pending.delete(id);
8953
- useDesigner.setState((s) => ({ reused: { ...s.reused, [id]: d } }));
9007
+ const st = api.getState();
9008
+ if (!force && st.reused[id]) return Promise.resolve(st.reused[id]);
9009
+ const server2 = st.embed?.server || "", key2 = `${server2} ${id}`;
9010
+ const keep = (d) => {
9011
+ api.setState((s) => ({ reused: { ...s.reused, [id]: d } }));
8954
9012
  return d;
8955
- });
8956
- pending.set(id, p);
8957
- return p;
9013
+ };
9014
+ if (pending.has(key2)) return pending.get(key2).then(keep);
9015
+ if (st.embed && !server2) return Promise.resolve(null);
9016
+ const p = fetch(`${server2}/api/reports/${encodeURIComponent(id)}`).then((r) => r.ok ? r.json() : { __error: `HTTP ${r.status}` }).catch((e) => ({ __error: e.message })).finally(() => pending.delete(key2));
9017
+ pending.set(key2, p);
9018
+ return p.then(keep);
8958
9019
  }
8959
9020
  function useReused(id) {
9021
+ const api = useDesignerStore();
8960
9022
  const d = useDesigner((s) => id ? s.reused[id] : void 0);
8961
9023
  useEffect2(() => {
8962
- fetchReused(id);
8963
- }, [id]);
9024
+ fetchReused(id, false, api);
9025
+ }, [id, api]);
8964
9026
  return d && !d.__error ? d : null;
8965
9027
  }
8966
9028
  var listCache = null;
@@ -9529,7 +9591,7 @@ function useDesignIssues() {
9529
9591
  return [...designIssues(def, bands, extents || {}), ...checkIssues(bands, [...validate(def).errors, ...saveCheck?.missing || []])];
9530
9592
  }, [def, extents, saveCheck]);
9531
9593
  }
9532
- var IssueMap = createContext2(/* @__PURE__ */ new Map());
9594
+ var IssueMap = createContext3(/* @__PURE__ */ new Map());
9533
9595
  function issueLine(T, i2) {
9534
9596
  if (i2.kind === "overlap") return T("ux_issueOverlap", { name: i2.name, other: i2.other });
9535
9597
  if (i2.kind === "wide") return T("ux_issueWide", { name: i2.name, width: i2.width, room: i2.room });
@@ -9594,7 +9656,7 @@ function Canvas() {
9594
9656
  const bands = sectionList(def);
9595
9657
  const widths2 = Object.fromEntries(bands.map((s) => [s.key, bodyWidth(def, s.key)]));
9596
9658
  const bw = Math.max(...Object.values(widths2));
9597
- const scrollRef = useRef2(null);
9659
+ const scrollRef = useRef3(null);
9598
9660
  const [fitW, setFitW] = useState4(0);
9599
9661
  useEffect3(() => {
9600
9662
  if (zoom !== "fit" || !scrollRef.current) return;
@@ -9688,7 +9750,7 @@ function Band({ section, label, scale, bw: bandW, drag, setDrag, phBox = null })
9688
9750
  const off = phBox || mb?.off || null;
9689
9751
  const contentList = useDesigner((s) => s.def.sections?.content);
9690
9752
  const bw = off?.w || bandW;
9691
- const ref = useRef2(null);
9753
+ const ref = useRef3(null);
9692
9754
  const [marquee, setMarquee] = useState4(null);
9693
9755
  const [dropping, setDropping] = useState4(false);
9694
9756
  const h = drag?.mode === "band" && drag.section === section ? drag.h : sec.height || 0;
@@ -9864,8 +9926,9 @@ var alerted = 0;
9864
9926
  function alertOnce(msg) {
9865
9927
  if (Date.now() - alerted > 3e3) {
9866
9928
  alerted = Date.now();
9867
- useDesigner.setState({ saveError: msg });
9868
- setTimeout(() => useDesigner.setState({ saveError: null }), 3e3);
9929
+ const api = activeStore2();
9930
+ api.setState({ saveError: msg });
9931
+ setTimeout(() => api.setState({ saveError: null }), 3e3);
9869
9932
  }
9870
9933
  }
9871
9934
  function fieldStyle(f) {
@@ -9873,11 +9936,31 @@ function fieldStyle(f) {
9873
9936
  const format = formatFor({ name: f.field, type: f.type }, (st.sample?.dataSets?.[f.dataSet] || []).slice(0, 200), { currency: st.def?.currency });
9874
9937
  return format ? { format } : {};
9875
9938
  }
9939
+ function useItemKeys(item) {
9940
+ const T = useT2();
9941
+ const type = T(`item_${item.type}`) === `item_${item.type}` ? ITEMS[item.type]?.label || item.type : T(`item_${item.type}`);
9942
+ return {
9943
+ tabIndex: 0,
9944
+ role: "group",
9945
+ "data-item-key": item.id,
9946
+ "aria-label": T("b9_itemLabel", { type, name: item.name, x: round(item.x), y: round(item.y) }),
9947
+ onKeyDown: (e) => {
9948
+ if (e.target !== e.currentTarget || e.key !== "Enter" && e.key !== " ") return;
9949
+ e.preventDefault();
9950
+ e.stopPropagation();
9951
+ const st = useDesigner.getState();
9952
+ const cur2 = st.sel.kind === "items" ? st.sel.ids : [];
9953
+ const ids = !e.shiftKey ? [item.id] : cur2.includes(item.id) ? cur2.filter((i2) => i2 !== item.id) : [...cur2, item.id];
9954
+ st.select(ids.length ? { kind: "items", ids } : { kind: "report" });
9955
+ }
9956
+ };
9957
+ }
9876
9958
  function useItemDrag(item, scale, setDrag) {
9877
9959
  return (e) => {
9878
9960
  if (e.button !== 0) return;
9879
9961
  e.preventDefault();
9880
9962
  e.stopPropagation();
9963
+ e.currentTarget.closest?.("[data-item-key]")?.focus({ preventScroll: true });
9881
9964
  const st = useDesigner.getState();
9882
9965
  let ids;
9883
9966
  if (e.shiftKey) {
@@ -9950,7 +10033,7 @@ function AnyItem(props) {
9950
10033
  return layer?.locked ? /* @__PURE__ */ jsx6("div", { className: "layer-locked", "data-locked": props.item.name, children: el }) : el;
9951
10034
  }
9952
10035
  function NestChildren({ item, scale, drag, setDrag, section }) {
9953
- const ref = useRef2(null);
10036
+ const ref = useRef3(null);
9954
10037
  const [over, setOver] = useState4(false);
9955
10038
  const accepts = (e) => e.dataTransfer.types.includes(MIME_TOOL) || e.dataTransfer.types.includes(MIME_FIELD) || e.dataTransfer.types.includes(MIME_PART);
9956
10039
  const onDrop = (e) => {
@@ -9996,8 +10079,9 @@ function ItemView({ item, scale, drag, setDrag, bw, nest, section }) {
9996
10079
  const selected = useDesigner((s) => s.sel.kind === "items" && s.sel.ids.includes(item.id));
9997
10080
  const single = useDesigner((s) => s.sel.kind === "items" && s.sel.ids.length === 1);
9998
10081
  const onDown = useItemDrag(item, scale, setDrag);
10082
+ const keys = useItemKeys(item);
9999
10083
  const r = rectOf(item, drag);
10000
- const problems = useContext2(IssueMap).get(item.id);
10084
+ const problems = useContext3(IssueMap).get(item.id);
10001
10085
  const onHandle = (dir) => (e) => {
10002
10086
  e.preventDefault();
10003
10087
  e.stopPropagation();
@@ -10056,6 +10140,7 @@ function ItemView({ item, scale, drag, setDrag, bw, nest, section }) {
10056
10140
  title: problems?.join("\n"),
10057
10141
  style: { left: r.x * scale, top: r.y * scale, width: Math.max(r.w * scale, 2), height: Math.max(r.h * scale, 2) },
10058
10142
  onPointerDown: onDown,
10143
+ ...keys,
10059
10144
  children: [
10060
10145
  nest ? /* @__PURE__ */ jsx6(NestBox, { item: { ...item, ...r }, scale }) : /* @__PURE__ */ jsx6(ItemBody, { item: { ...item, ...r }, scale }),
10061
10146
  nest && /* @__PURE__ */ jsx6(NestChildren, { item, scale, drag, setDrag, section }),
@@ -10073,8 +10158,8 @@ function NestBox({ item, scale }) {
10073
10158
  }
10074
10159
  var LIVE = /* @__PURE__ */ new Set(["chart", "matrix", "barcode", "sparkline", "databar", "bullet", "iconset", "rangebar", "richtext"]);
10075
10160
  var measurer = null;
10076
- async function paintItemSvg(shape2, def, sample) {
10077
- const store = fontStore();
10161
+ async function paintItemSvg(shape2, def, sample, api = activeStore2()) {
10162
+ const store = await loadFontStore();
10078
10163
  await Promise.all([store.load(), customFonts()]);
10079
10164
  if (shape2.type === "barcode" || hasType(shape2.items, "barcode")) await loadBarcodes();
10080
10165
  measurer || (measurer = new TextMeasurer(store));
@@ -10085,7 +10170,7 @@ async function paintItemSvg(shape2, def, sample) {
10085
10170
  } catch {
10086
10171
  }
10087
10172
  const base2 = { fontFamily: "Inter", fontSize: 9, color: "#1f2937", padding: 2, lineHeight: 1.25, textAlign: "auto", verticalAlign: "top", ...def.styles?.base || {} };
10088
- const theme3 = themeContext(typeof def.theme === "string" && useDesigner.getState().reused[def.theme]?.themeDef || def.themeDef);
10173
+ const theme3 = themeContext(typeof def.theme === "string" && api.getState().reused[def.theme]?.themeDef || def.themeDef);
10089
10174
  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 };
10090
10175
  let seq = 0;
10091
10176
  const lc = {
@@ -10127,6 +10212,7 @@ async function paintItemSvg(shape2, def, sample) {
10127
10212
  return { html: pageToSvg({ items }, shape2.w, h, { background: false }), h, w };
10128
10213
  }
10129
10214
  function LivePreview({ item, scale }) {
10215
+ const api = useDesignerStore();
10130
10216
  const sample = useDesigner((s) => s.sample);
10131
10217
  const def = useDesigner((s) => s.def);
10132
10218
  const [svg, setSvg] = useState4(null);
@@ -10136,11 +10222,11 @@ function LivePreview({ item, scale }) {
10136
10222
  let alive = true;
10137
10223
  const t3 = setTimeout(async () => {
10138
10224
  try {
10139
- const out = await paintItemSvg(shape2, def, sample);
10225
+ const out = await paintItemSvg(shape2, def, sample, api);
10140
10226
  if (alive) {
10141
10227
  setSvg(out);
10142
- const ex2 = useDesigner.getState().extents || {};
10143
- if (Math.round(ex2[item.id]?.w || 0) !== Math.round(out.w)) useDesigner.setState({ extents: { ...ex2, [item.id]: { w: out.w } } });
10228
+ const ex2 = api.getState().extents || {};
10229
+ if (Math.round(ex2[item.id]?.w || 0) !== Math.round(out.w)) api.setState({ extents: { ...ex2, [item.id]: { w: out.w } } });
10144
10230
  }
10145
10231
  } catch (e) {
10146
10232
  if (alive) setSvg({ error: e.message });
@@ -10274,17 +10360,18 @@ function TableView({ item, scale, drag, setDrag }) {
10274
10360
  const readOnly2 = useDesigner((s) => s.readOnly);
10275
10361
  const tableSelected = sel.kind === "items" && sel.ids.includes(item.id);
10276
10362
  const onGrip = useItemDrag(item, scale, setDrag);
10363
+ const keys = useItemKeys(item);
10277
10364
  const r = rectOf(item, drag);
10278
10365
  const widths2 = item.columns.map((c, i2) => drag?.mode === "col" && drag.id === item.id && drag.col === i2 ? drag.w : c.width);
10279
10366
  const [dropCell, setDropCell] = useState4(null);
10280
10367
  const [menu, setMenu] = useState4(null);
10281
- const problems = useContext2(IssueMap).get(item.id);
10282
- const tblRef = useRef2(null);
10368
+ const problems = useContext3(IssueMap).get(item.id);
10369
+ const tblRef = useRef3(null);
10283
10370
  const chosen = sel.kind === "cell" && sel.id === item.id ? selCells(sel) : [];
10284
10371
  useEffect3(() => {
10285
10372
  if (!menu) return void 0;
10286
10373
  const close = (e) => {
10287
- if (e.type === "keydown" ? e.key === "Escape" : !e.target.closest?.(".cell-menu")) setMenu(null);
10374
+ if (e.type === "keydown" ? e.key === "Escape" : !e.composedPath().some((n) => n.classList?.contains("cell-menu"))) setMenu(null);
10288
10375
  };
10289
10376
  window.addEventListener("pointerdown", close, true);
10290
10377
  window.addEventListener("keydown", close);
@@ -10297,6 +10384,7 @@ function TableView({ item, scale, drag, setDrag }) {
10297
10384
  e.stopPropagation();
10298
10385
  if (e.button !== 0) return;
10299
10386
  e.preventDefault();
10387
+ e.currentTarget.closest("[data-item-key]")?.focus({ preventScroll: true });
10300
10388
  const st = useDesigner.getState();
10301
10389
  const here = { part, row: ri, col: ci };
10302
10390
  const cur2 = st.sel.kind === "cell" && st.sel.id === item.id ? st.sel : null;
@@ -10372,7 +10460,7 @@ function TableView({ item, scale, drag, setDrag }) {
10372
10460
  const h = t3.header?.[t3.header.length - 1]?.cells?.[ci];
10373
10461
  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());
10374
10462
  if (h && f.type === "number") h.style = { ...h.style || {}, textAlign: "right" };
10375
- } else if ((part === "footer" || /^g\d+f$/.test(part)) && f.type === "number") {
10463
+ } else if ((part === "footer" || /^g\d+[hf]$/.test(part)) && f.type === "number") {
10376
10464
  cell.value = `=Sum(Fields.${f.field})`;
10377
10465
  cell.style = { ...cell.style || {}, ...fieldStyle(f) };
10378
10466
  } else cell.value = `=Fields.${f.field}`;
@@ -10380,7 +10468,7 @@ function TableView({ item, scale, drag, setDrag }) {
10380
10468
  useDesigner.getState().select({ kind: "cell", id: item.id, part, row: ri, col: ci });
10381
10469
  };
10382
10470
  let first = true;
10383
- return /* @__PURE__ */ jsxs4("div", { ref: tblRef, className: `tbl${tableSelected ? " sel" : ""}${problems ? " issue" : ""}`, "data-item": item.name, style: { left: r.x * scale, top: r.y * scale }, children: [
10471
+ return /* @__PURE__ */ jsxs4("div", { ref: tblRef, className: `tbl${tableSelected ? " sel" : ""}${problems ? " issue" : ""}`, "data-item": item.name, style: { left: r.x * scale, top: r.y * scale }, ...keys, children: [
10384
10472
  problems && /* @__PURE__ */ jsx6("div", { className: "issue-tag", title: problems.join("\n"), "aria-label": problems.join(". "), children: "!" }),
10385
10473
  /* @__PURE__ */ jsx6("div", { className: "grip", title: "Select or move the table", onPointerDown: onGrip, children: "⠿" }),
10386
10474
  /* @__PURE__ */ jsx6("div", { className: "col-handles", "aria-label": T("ux_columns"), role: "group", children: widths2.map((w, ci) => /* @__PURE__ */ jsx6(
@@ -10510,13 +10598,13 @@ function TableView({ item, scale, drag, setDrag }) {
10510
10598
  }
10511
10599
 
10512
10600
  // src/designer/Inspector.jsx
10513
- import { Fragment as Fragment5, useEffect as useEffect5, useLayoutEffect as useLayoutEffect2, useRef as useRef5, useState as useState7 } from "react";
10601
+ import { Fragment as Fragment5, useEffect as useEffect5, useLayoutEffect as useLayoutEffect2, useRef as useRef6, useState as useState7 } from "react";
10514
10602
 
10515
10603
  // src/designer/ExpressionEditor.jsx
10516
- import { useMemo as useMemo2, useRef as useRef4, useState as useState5 } from "react";
10604
+ import { useMemo as useMemo2, useRef as useRef5, useState as useState5 } from "react";
10517
10605
 
10518
10606
  // src/designer/ExprCode.jsx
10519
- import { forwardRef, useEffect as useEffect4, useImperativeHandle, useRef as useRef3 } from "react";
10607
+ import { forwardRef, useEffect as useEffect4, useImperativeHandle, useRef as useRef4 } from "react";
10520
10608
 
10521
10609
  // node_modules/@marijn/find-cluster-break/src/index.js
10522
10610
  var rangeFrom = [];
@@ -12260,8 +12348,8 @@ var StateField = class _StateField {
12260
12348
  way it is initialized. Can be useful when you need to provide a
12261
12349
  non-default starting value for the field.
12262
12350
  */
12263
- init(create2) {
12264
- return [this, initField.of({ field: this, create: create2 })];
12351
+ init(create) {
12352
+ return [this, initField.of({ field: this, create })];
12265
12353
  }
12266
12354
  /**
12267
12355
  State field instances can be used as
@@ -13489,10 +13577,10 @@ var RangeSet = class _RangeSet {
13489
13577
  for (; ; ) {
13490
13578
  let curTo = Math.min(cursor.to, to);
13491
13579
  if (cursor.point) {
13492
- let active = cursor.activeForPoint(cursor.to);
13493
- let openCount = cursor.pointFrom < from ? active.length + 1 : cursor.point.startSide < 0 ? active.length : Math.min(active.length, openRanges);
13494
- iterator.point(pos, curTo, cursor.point, active, openCount, cursor.pointRank);
13495
- openRanges = Math.min(cursor.openEnd(curTo), active.length);
13580
+ let active2 = cursor.activeForPoint(cursor.to);
13581
+ let openCount = cursor.pointFrom < from ? active2.length + 1 : cursor.point.startSide < 0 ? active2.length : Math.min(active2.length, openRanges);
13582
+ iterator.point(pos, curTo, cursor.point, active2, openCount, cursor.pointRank);
13583
+ openRanges = Math.min(cursor.openEnd(curTo), active2.length);
13496
13584
  } else if (curTo > pos) {
13497
13585
  iterator.span(pos, curTo, cursor.active, openRanges);
13498
13586
  openRanges = cursor.openEnd(curTo);
@@ -13906,14 +13994,14 @@ var SpanCursor = class {
13906
13994
  activeForPoint(to) {
13907
13995
  if (!this.active.length)
13908
13996
  return this.active;
13909
- let active = [];
13997
+ let active2 = [];
13910
13998
  for (let i2 = this.active.length - 1; i2 >= 0; i2--) {
13911
13999
  if (this.activeRank[i2] < this.pointRank)
13912
14000
  break;
13913
14001
  if (this.activeTo[i2] > to || this.activeTo[i2] == to && this.active[i2].endSide >= this.point.endSide)
13914
- active.push(this.active[i2]);
14002
+ active2.push(this.active[i2]);
13915
14003
  }
13916
- return active.reverse();
14004
+ return active2.reverse();
13917
14005
  }
13918
14006
  openEnd(to) {
13919
14007
  let open = 0;
@@ -15432,9 +15520,9 @@ var viewPlugin = /* @__PURE__ */ Facet.define({
15432
15520
  }
15433
15521
  });
15434
15522
  var ViewPlugin = class _ViewPlugin {
15435
- constructor(id, create2, domEventHandlers, domEventObservers, buildExtensions) {
15523
+ constructor(id, create, domEventHandlers, domEventObservers, buildExtensions) {
15436
15524
  this.id = id;
15437
- this.create = create2;
15525
+ this.create = create;
15438
15526
  this.domEventHandlers = domEventHandlers;
15439
15527
  this.domEventObservers = domEventObservers;
15440
15528
  this.baseExtensions = buildExtensions(this);
@@ -15450,9 +15538,9 @@ var ViewPlugin = class _ViewPlugin {
15450
15538
  Define a plugin from a constructor function that creates the
15451
15539
  plugin's value, given an editor view.
15452
15540
  */
15453
- static define(create2, spec) {
15541
+ static define(create, spec) {
15454
15542
  const { eventHandlers, eventObservers, provide, decorations: deco } = spec || {};
15455
- return new _ViewPlugin(nextPluginID++, create2, eventHandlers, eventObservers, (plugin) => {
15543
+ return new _ViewPlugin(nextPluginID++, create, eventHandlers, eventObservers, (plugin) => {
15456
15544
  let ext = [];
15457
15545
  if (deco)
15458
15546
  ext.push(decorations.of((view) => {
@@ -15540,11 +15628,11 @@ function getIsolatedRanges(view, line2) {
15540
15628
  RangeSet.spans(sets, line2.from, line2.to, {
15541
15629
  point() {
15542
15630
  },
15543
- span(fromDoc, toDoc, active, open) {
15631
+ span(fromDoc, toDoc, active2, open) {
15544
15632
  let from = fromDoc - line2.from, to = toDoc - line2.from;
15545
15633
  let level = result;
15546
- for (let i2 = active.length - 1; i2 >= 0; i2--, open--) {
15547
- let direction = active[i2].spec.bidiIsolate, update;
15634
+ for (let i2 = active2.length - 1; i2 >= 0; i2--, open--) {
15635
+ let direction = active2[i2].spec.bidiIsolate, update;
15548
15636
  if (direction == null)
15549
15637
  direction = autoDirection(line2.text, from, to);
15550
15638
  if (open > 0 && level.length && (update = level[level.length - 1]).to == from && update.direction == direction) {
@@ -16774,7 +16862,7 @@ var TileUpdate = class {
16774
16862
  let pendingLineAttrs = null;
16775
16863
  let b = this.builder, markCount = -1;
16776
16864
  let openEnd = RangeSet.spans(this.decorations, from, to, {
16777
- point: (from2, to2, deco, active, openStart, index) => {
16865
+ point: (from2, to2, deco, active2, openStart, index) => {
16778
16866
  if (deco instanceof PointDecoration) {
16779
16867
  if (this.disallowBlockEffectsFor[index]) {
16780
16868
  if (deco.block)
@@ -16782,8 +16870,8 @@ var TileUpdate = class {
16782
16870
  if (to2 > this.view.state.doc.lineAt(from2).to)
16783
16871
  throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
16784
16872
  }
16785
- markCount = active.length;
16786
- if (openStart > active.length) {
16873
+ markCount = active2.length;
16874
+ if (openStart > active2.length) {
16787
16875
  b.continueWidget(to2 - from2);
16788
16876
  } else {
16789
16877
  let widget = deco.widget || (deco.block ? NullWidget.block : NullWidget.inline);
@@ -16795,7 +16883,7 @@ var TileUpdate = class {
16795
16883
  b.addBlockWidget(tile);
16796
16884
  } else {
16797
16885
  b.ensureLine(pendingLineAttrs);
16798
- b.addInlineWidget(tile, active, openStart);
16886
+ b.addInlineWidget(tile, active2, openStart);
16799
16887
  }
16800
16888
  }
16801
16889
  pendingLineAttrs = null;
@@ -16805,7 +16893,7 @@ var TileUpdate = class {
16805
16893
  if (to2 > from2)
16806
16894
  this.text.skip(to2 - from2);
16807
16895
  },
16808
- span: (from2, to2, active, openStart) => {
16896
+ span: (from2, to2, active2, openStart) => {
16809
16897
  for (let pos = from2; pos < to2; ) {
16810
16898
  let chars = this.text.next(Math.min(512, to2 - pos));
16811
16899
  if (chars == null) {
@@ -16814,12 +16902,12 @@ var TileUpdate = class {
16814
16902
  pos++;
16815
16903
  } else {
16816
16904
  b.ensureLine(pendingLineAttrs);
16817
- b.addText(chars, active, pos == from2 ? openStart : active.length);
16905
+ b.addText(chars, active2, pos == from2 ? openStart : active2.length);
16818
16906
  pos += chars.length;
16819
16907
  }
16820
16908
  pendingLineAttrs = null;
16821
16909
  }
16822
- markCount = active.length;
16910
+ markCount = active2.length;
16823
16911
  }
16824
16912
  });
16825
16913
  if (markCount > -1)
@@ -18808,9 +18896,9 @@ handlers.mousedown = (view, event) => {
18808
18896
  if (mustFocus)
18809
18897
  view.observer.ignore(() => {
18810
18898
  focusPreventScroll(view.contentDOM);
18811
- let active = view.root.activeElement;
18812
- if (active && !active.contains(view.contentDOM))
18813
- active.blur();
18899
+ let active2 = view.root.activeElement;
18900
+ if (active2 && !active2.contains(view.contentDOM))
18901
+ active2.blur();
18814
18902
  });
18815
18903
  let mouseSel = view.inputState.mouseSelection;
18816
18904
  if (mouseSel) {
@@ -28853,7 +28941,7 @@ function scrollIntoView2(container2, element) {
28853
28941
  function score(option) {
28854
28942
  return (option.boost || 0) * 100 + (option.apply ? 10 : 0) + (option.info ? 5 : 0) + (option.type ? 1 : 0);
28855
28943
  }
28856
- function sortOptions(active, state) {
28944
+ function sortOptions(active2, state) {
28857
28945
  let options = [];
28858
28946
  let sections = null, dynamicSectionScore = null;
28859
28947
  let addOption = (option) => {
@@ -28868,7 +28956,7 @@ function sortOptions(active, state) {
28868
28956
  }
28869
28957
  };
28870
28958
  let conf = state.facet(completionConfig);
28871
- for (let a of active)
28959
+ for (let a of active2)
28872
28960
  if (a.hasResult()) {
28873
28961
  let getMatch = a.result.getMatch;
28874
28962
  if (a.result.filter === false) {
@@ -28931,12 +29019,12 @@ var CompletionDialog = class _CompletionDialog {
28931
29019
  setSelected(selected, id) {
28932
29020
  return selected == this.selected || selected >= this.options.length ? this : new _CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected, this.disabled);
28933
29021
  }
28934
- static build(active, state, id, prev, conf, didSetActive) {
28935
- if (prev && !didSetActive && active.some((s) => s.isPending))
29022
+ static build(active2, state, id, prev, conf, didSetActive) {
29023
+ if (prev && !didSetActive && active2.some((s) => s.isPending))
28936
29024
  return prev.setDisabled();
28937
- let options = sortOptions(active, state);
29025
+ let options = sortOptions(active2, state);
28938
29026
  if (!options.length)
28939
- return prev && active.some((a) => a.isPending) ? prev.setDisabled() : null;
29027
+ return prev && active2.some((a) => a.isPending) ? prev.setDisabled() : null;
28940
29028
  let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1;
28941
29029
  if (prev && prev.selected != selected && prev.selected != -1) {
28942
29030
  let selectedValue = prev.options[prev.selected].completion;
@@ -28947,7 +29035,7 @@ var CompletionDialog = class _CompletionDialog {
28947
29035
  }
28948
29036
  }
28949
29037
  return new _CompletionDialog(options, makeAttrs(id, selected), {
28950
- pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
29038
+ pos: active2.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
28951
29039
  create: createTooltip,
28952
29040
  above: conf.aboveCursor
28953
29041
  }, prev ? prev.timestamp : Date.now(), selected, false);
@@ -28960,8 +29048,8 @@ var CompletionDialog = class _CompletionDialog {
28960
29048
  }
28961
29049
  };
28962
29050
  var CompletionState = class _CompletionState {
28963
- constructor(active, id, open) {
28964
- this.active = active;
29051
+ constructor(active2, id, open) {
29052
+ this.active = active2;
28965
29053
  this.id = id;
28966
29054
  this.open = open;
28967
29055
  }
@@ -28971,7 +29059,7 @@ var CompletionState = class _CompletionState {
28971
29059
  update(tr) {
28972
29060
  let { state } = tr, conf = state.facet(completionConfig);
28973
29061
  let sources = conf.override || state.languageDataAt("autocomplete", cur(state)).map(asSource);
28974
- let active = sources.map((source) => {
29062
+ let active2 = sources.map((source) => {
28975
29063
  let value = this.active.find((s) => s.source == source) || new ActiveSource(
28976
29064
  source,
28977
29065
  this.active.some(
@@ -28982,17 +29070,17 @@ var CompletionState = class _CompletionState {
28982
29070
  );
28983
29071
  return value.update(tr, conf);
28984
29072
  });
28985
- if (active.length == this.active.length && active.every((a, i2) => a == this.active[i2]))
28986
- active = this.active;
29073
+ if (active2.length == this.active.length && active2.every((a, i2) => a == this.active[i2]))
29074
+ active2 = this.active;
28987
29075
  let open = this.open, didSet = tr.effects.some((e) => e.is(setActiveEffect));
28988
29076
  if (open && tr.docChanged)
28989
29077
  open = open.map(tr.changes);
28990
- if (tr.selection || active.some((a) => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) || !sameResults(active, this.active) || didSet)
28991
- open = CompletionDialog.build(active, state, this.id, open, conf, didSet);
28992
- else if (open && open.disabled && !active.some((a) => a.isPending))
29078
+ if (tr.selection || active2.some((a) => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) || !sameResults(active2, this.active) || didSet)
29079
+ open = CompletionDialog.build(active2, state, this.id, open, conf, didSet);
29080
+ else if (open && open.disabled && !active2.some((a) => a.isPending))
28993
29081
  open = null;
28994
- if (!open && active.every((a) => !a.isPending) && active.some((a) => a.hasResult()))
28995
- active = active.map((a) => a.hasResult() ? new ActiveSource(
29082
+ if (!open && active2.every((a) => !a.isPending) && active2.some((a) => a.hasResult()))
29083
+ active2 = active2.map((a) => a.hasResult() ? new ActiveSource(
28996
29084
  a.source,
28997
29085
  0
28998
29086
  /* State.Inactive */
@@ -29000,7 +29088,7 @@ var CompletionState = class _CompletionState {
29000
29088
  for (let effect of tr.effects)
29001
29089
  if (effect.is(setSelectedEffect))
29002
29090
  open = open && open.setSelected(effect.value, this.id);
29003
- return active == this.active && open == this.open ? this : new _CompletionState(active, this.id, open);
29091
+ return active2 == this.active && open == this.open ? this : new _CompletionState(active2, this.id, open);
29004
29092
  }
29005
29093
  get tooltip() {
29006
29094
  return this.open ? this.open.tooltip : null;
@@ -29085,9 +29173,9 @@ var ActiveSource = class _ActiveSource {
29085
29173
  /* State.Inactive */
29086
29174
  );
29087
29175
  else if (effect.is(setActiveEffect)) {
29088
- for (let active of effect.value)
29089
- if (active.source == value.source)
29090
- value = active;
29176
+ for (let active2 of effect.value)
29177
+ if (active2.source == value.source)
29178
+ value = active2;
29091
29179
  }
29092
29180
  }
29093
29181
  return value;
@@ -29231,8 +29319,8 @@ var closeCompletion = (view) => {
29231
29319
  return true;
29232
29320
  };
29233
29321
  var RunningQuery = class {
29234
- constructor(active, context) {
29235
- this.active = active;
29322
+ constructor(active2, context) {
29323
+ this.active = active2;
29236
29324
  this.context = context;
29237
29325
  this.time = Date.now();
29238
29326
  this.updates = [];
@@ -29249,9 +29337,9 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29249
29337
  this.debounceAccept = -1;
29250
29338
  this.pendingStart = false;
29251
29339
  this.composing = 0;
29252
- for (let active of view.state.field(completionState).active)
29253
- if (active.isPending)
29254
- this.startQuery(active);
29340
+ for (let active2 of view.state.field(completionState).active)
29341
+ if (active2.isPending)
29342
+ this.startQuery(active2);
29255
29343
  }
29256
29344
  update(update) {
29257
29345
  let cState = update.state.field(completionState);
@@ -29296,19 +29384,19 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29296
29384
  this.debounceUpdate = -1;
29297
29385
  this.pendingStart = false;
29298
29386
  let { state } = this.view, cState = state.field(completionState);
29299
- for (let active of cState.active) {
29300
- if (active.isPending && !this.running.some((r) => r.active.source == active.source))
29301
- this.startQuery(active);
29387
+ for (let active2 of cState.active) {
29388
+ if (active2.isPending && !this.running.some((r) => r.active.source == active2.source))
29389
+ this.startQuery(active2);
29302
29390
  }
29303
29391
  if (this.running.length && cState.open && cState.open.disabled)
29304
29392
  this.debounceAccept = setTimeout(() => this.accept(), this.view.state.facet(completionConfig).updateSyncTime);
29305
29393
  }
29306
- startQuery(active) {
29394
+ startQuery(active2) {
29307
29395
  let { state } = this.view, pos = cur(state);
29308
- let context = new CompletionContext(state, pos, active.explicit, this.view);
29309
- let pending2 = new RunningQuery(active, context);
29396
+ let context = new CompletionContext(state, pos, active2.explicit, this.view);
29397
+ let pending2 = new RunningQuery(active2, context);
29310
29398
  this.running.push(pending2);
29311
- Promise.resolve(active.source(context)).then((result) => {
29399
+ Promise.resolve(active2.source(context)).then((result) => {
29312
29400
  if (!pending2.context.aborted) {
29313
29401
  pending2.done = result || null;
29314
29402
  this.scheduleAccept();
@@ -29341,26 +29429,26 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29341
29429
  if (query.done) {
29342
29430
  let pos = cur(query.updates.length ? query.updates[0].startState : this.view.state);
29343
29431
  let limit = Math.min(pos, query.done.from + (query.active.explicit ? 0 : 1));
29344
- 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);
29432
+ 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);
29345
29433
  for (let tr of query.updates)
29346
- active = active.update(tr, conf);
29347
- if (active.hasResult()) {
29348
- updated.push(active);
29434
+ active2 = active2.update(tr, conf);
29435
+ if (active2.hasResult()) {
29436
+ updated.push(active2);
29349
29437
  continue;
29350
29438
  }
29351
29439
  }
29352
29440
  let current2 = cState.active.find((a) => a.source == query.active.source);
29353
29441
  if (current2 && current2.isPending) {
29354
29442
  if (query.done == null) {
29355
- let active = new ActiveSource(
29443
+ let active2 = new ActiveSource(
29356
29444
  query.active.source,
29357
29445
  0
29358
29446
  /* State.Inactive */
29359
29447
  );
29360
29448
  for (let tr of query.updates)
29361
- active = active.update(tr, conf);
29362
- if (!active.isPending)
29363
- updated.push(active);
29449
+ active2 = active2.update(tr, conf);
29450
+ if (!active2.isPending)
29451
+ updated.push(active2);
29364
29452
  } else {
29365
29453
  this.startQuery(current2);
29366
29454
  }
@@ -29818,9 +29906,9 @@ var theme2 = EditorView.theme({
29818
29906
  });
29819
29907
  var UNKNOWN = Decoration.mark({ class: "cm-unknown-field" });
29820
29908
  var ExprCode = forwardRef(function ExprCode2({ value, onChange, fields, parameters, invalid, check }, ref) {
29821
- const host = useRef3(null);
29822
- const view = useRef3(null);
29823
- const latest2 = useRef3({ onChange, fields, parameters, check });
29909
+ const host = useRef4(null);
29910
+ const view = useRef4(null);
29911
+ const latest2 = useRef4({ onChange, fields, parameters, check });
29824
29912
  latest2.current = { onChange, fields, parameters, check };
29825
29913
  useImperativeHandle(ref, () => ({
29826
29914
  insert(text) {
@@ -29926,7 +30014,7 @@ function ExpressionEditor({ value, dataSet, onSave, onClose, title }) {
29926
30014
  const def = useDesigner((s) => s.def);
29927
30015
  const sample = useDesigner((s) => s.sample);
29928
30016
  const [text, setText] = useState5(value ?? "");
29929
- const ta = useRef4(null);
30017
+ const ta = useRef5(null);
29930
30018
  const dsName = dataSet || def.dataSets?.[0]?.name;
29931
30019
  const ds = def.dataSets?.find((d) => d.name === dsName);
29932
30020
  const fields = fieldNames(ds).filter((n) => !(ds?.fields || []).some((f) => f.name === n && f.type === "object"));
@@ -30235,7 +30323,7 @@ function Inspector() {
30235
30323
  const one = sel.kind === "items" && sel.ids.length === 1 ? findItem(def, sel.ids[0])?.item : sel.kind === "cell" ? findItem(def, sel.id)?.item : null;
30236
30324
  const scope = one ? one.dataSet || def.dataSets?.[0]?.name || null : void 0;
30237
30325
  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 || ""}`;
30238
- const ref = useRef5(null);
30326
+ const ref = useRef6(null);
30239
30327
  useLayoutEffect2(() => {
30240
30328
  const pane = ref.current?.closest(".dright");
30241
30329
  if (pane) pane.scrollTop = 0;
@@ -30264,9 +30352,9 @@ function Inspector() {
30264
30352
  expr && /* @__PURE__ */ jsx10(ExpressionEditor, { ...expr, onClose: () => setExpr(null) })
30265
30353
  ] });
30266
30354
  }
30267
- function Geo({ label, value, onChange }) {
30355
+ function Geo({ label, value, onChange, min }) {
30268
30356
  const unit = useDesigner((s) => s.unit);
30269
- return /* @__PURE__ */ jsx10(Field, { label: `${label} (${unit})`, children: /* @__PURE__ */ jsx10(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))) }) });
30357
+ return /* @__PURE__ */ jsx10(Field, { label: `${label} (${unit})`, children: /* @__PURE__ */ jsx10(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))) }) });
30270
30358
  }
30271
30359
  function PropEditor({ p: spec, value, onChange, openExpr, dataSet, item }) {
30272
30360
  const T = useT3();
@@ -30369,17 +30457,18 @@ function PaletteEditor({ label, value, onChange }) {
30369
30457
  custom && /* @__PURE__ */ jsx10("div", { style: { display: "flex", gap: 3, flexWrap: "wrap" }, "aria-hidden": "true", children: value.map((c, i2) => /* @__PURE__ */ jsx10("span", { style: { width: 14, height: 14, borderRadius: 3, background: c, border: "1px solid var(--line)" } }, i2)) })
30370
30458
  ] });
30371
30459
  }
30372
- var reportList = null;
30460
+ var reportLists = /* @__PURE__ */ new Map();
30373
30461
  function ReportPicker({ value, onChange }) {
30374
- const [list2, setList] = useState7(reportList || []);
30462
+ const [list2, setList] = useState7(() => reportLists.get(useDesigner.getState().embed?.server || "") || []);
30375
30463
  const listId = useState7(() => `reports-${Math.random().toString(36).slice(2, 8)}`)[0];
30376
30464
  useEffect5(() => {
30377
30465
  const embed = useDesigner.getState().embed;
30378
- if (reportList || embed && !embed.server) return;
30379
30466
  const server2 = embed?.server || "";
30467
+ if (reportLists.has(server2) || embed && !embed.server) return;
30380
30468
  fetch(`${server2}/api/reports`).then((r) => r.ok ? r.json() : []).then((l) => {
30381
- reportList = Array.isArray(l) ? l : [];
30382
- setList(reportList);
30469
+ const v = Array.isArray(l) ? l : [];
30470
+ reportLists.set(server2, v);
30471
+ setList(v);
30383
30472
  }).catch(() => {
30384
30473
  });
30385
30474
  }, []);
@@ -30465,8 +30554,8 @@ function ItemProps({ item, section, openExpr }) {
30465
30554
  /* @__PURE__ */ jsxs7("div", { className: "grid2", children: [
30466
30555
  /* @__PURE__ */ jsx10(Geo, { label: "X", value: item.x, onChange: (v) => setGeo("x", Math.max(0, v)) }),
30467
30556
  /* @__PURE__ */ jsx10(Geo, { label: "Y", value: item.y, onChange: (v) => setGeo("y", Math.max(0, v)) }),
30468
- item.type !== "table" && /* @__PURE__ */ jsx10(Geo, { label: T("i_width"), value: item.w, onChange: (v) => setGeo("w", Math.max(0, v)) }),
30469
- item.type !== "table" && /* @__PURE__ */ jsx10(Geo, { label: T("i_height"), value: item.h, onChange: (v) => setGeo("h", Math.max(0, v)) }),
30557
+ item.type !== "table" && /* @__PURE__ */ jsx10(Geo, { label: T("i_width"), value: item.w, min: item.type === "line" ? 0 : 1, onChange: (v) => setGeo("w", Math.max(0, v)) }),
30558
+ item.type !== "table" && /* @__PURE__ */ jsx10(Geo, { label: T("i_height"), value: item.h, min: item.type === "line" ? 0 : 1, onChange: (v) => setGeo("h", Math.max(0, v)) }),
30470
30559
  item.type === "table" && /* @__PURE__ */ jsx10(Field, { label: T("tableSize"), hint: T("tableSizeHint"), children: /* @__PURE__ */ jsx10(TextInput, { value: `${round(item.w)} × ${round(item.h)} pt`, readOnly: true, "data-testid": "table-size" }) })
30471
30560
  ] }),
30472
30561
  /* @__PURE__ */ jsx10("div", { className: "hint", children: (() => {
@@ -30636,7 +30725,17 @@ function PivotEditor({ item, openExpr }) {
30636
30725
  /* @__PURE__ */ jsx10(Field, { label: T("groupExpandLevels"), children: /* @__PURE__ */ jsx10(NumberInput, { value: g.expandLevels ?? "", step: 1, onChange: (v) => setK(list2, i2, "expandLevels", Number.isFinite(v) && v >= 0 ? Math.round(v) : void 0) }) })
30637
30726
  ] })
30638
30727
  ] }),
30639
- (i2 < spec[list2].length - 1 || list2 === "rowGroups" && g.parent) && /* @__PURE__ */ jsx10(Check, { label: T("pivotCollapsible"), checked: g.collapsible, onChange: (v) => setK(list2, i2, "collapsible", v) }),
30728
+ (i2 < spec[list2].length - 1 || list2 === "rowGroups" && g.parent) && /* @__PURE__ */ jsx10(Check, { label: T("pivotCollapsible"), checked: g.collapsible, onChange: (v) => edit((it) => {
30729
+ const o = it[list2][i2];
30730
+ if (v) {
30731
+ o.collapsible = true;
30732
+ o.initiallyCollapsed = true;
30733
+ } else {
30734
+ delete o.collapsible;
30735
+ delete o.initiallyCollapsed;
30736
+ }
30737
+ }, `${item.id}.${list2}${i2}.collapsible`) }),
30738
+ " ",
30640
30739
  g.collapsible && /* @__PURE__ */ jsx10(Check, { label: T("pivotStartCollapsed"), checked: g.initiallyCollapsed, onChange: (v) => setK(list2, i2, "initiallyCollapsed", v) }),
30641
30740
  /* @__PURE__ */ jsx10("div", { "data-testid": `pivot-${list2}${i2}-action`, children: /* @__PURE__ */ jsx10(ActionEditor, { label: T("ux_headerAction"), value: g.action, onChange: (v) => setK(list2, i2, "action", v), openExpr, dataSet: item.dataSet }) }),
30642
30741
  g.total && g.total !== "none" && /* @__PURE__ */ jsx10("div", { "data-testid": `pivot-${list2}${i2}-total-action`, children: /* @__PURE__ */ jsx10(ActionEditor, { label: T("ux_totalAction"), value: g.totalAction, onChange: (v) => setK(list2, i2, "totalAction", v), openExpr, dataSet: item.dataSet }) })
@@ -30662,7 +30761,7 @@ function PivotEditor({ item, openExpr }) {
30662
30761
  /* @__PURE__ */ jsxs7("div", { className: "grid2", children: [
30663
30762
  /* @__PURE__ */ jsx10(Field, { label: T("pivotLabel"), children: /* @__PURE__ */ jsx10(TextInput, { value: v.label || "", onChange: (x) => setK("values", i2, "label", x) }) }),
30664
30763
  /* @__PURE__ */ jsx10(Field, { label: T("pivotFormat"), children: /* @__PURE__ */ jsx10(TextInput, { value: v.format || "", onChange: (x) => setK("values", i2, "format", x), placeholder: "N0" }) }),
30665
- /* @__PURE__ */ jsx10(Field, { label: T("pivotShow"), children: /* @__PURE__ */ jsx10(Select, { value: v.show || "value", options: shows, onChange: (x) => setK("values", i2, "show", x === "value" ? void 0 : x) }) })
30764
+ /* @__PURE__ */ jsx10(Field, { label: T("pivotShow"), children: /* @__PURE__ */ jsx10(Select, { value: v.show || "value", options: shows, onChange: (x) => edit((it) => setMatrixShow(it.values[i2], x), `${item.id}.values${i2}.show`) }) })
30666
30765
  ] }),
30667
30766
  /* @__PURE__ */ jsx10("div", { "data-testid": `pivot-values${i2}-action`, children: /* @__PURE__ */ jsx10(ActionEditor, { label: T("ux_cellAction"), value: v.action, onChange: (x) => setK("values", i2, "action", x), openExpr, dataSet: item.dataSet }) }),
30668
30767
  /* @__PURE__ */ jsx10(Field, { label: T("cellBookmark"), children: exprField("values", i2, "bookmark", v.bookmark, T("cellBookmark")) })
@@ -31011,14 +31110,16 @@ function VisualEditor({ cell, setCell, openExpr, dataSet }) {
31011
31110
  }
31012
31111
  var reportParams = /* @__PURE__ */ new Map();
31013
31112
  function useReportParams(id) {
31014
- const [list2, setList] = useState7(() => reportParams.get(id) ?? null);
31113
+ const srv = () => useDesigner.getState().embed?.server || "";
31114
+ const [list2, setList] = useState7(() => reportParams.get(`${srv()} ${id}`) ?? null);
31015
31115
  useEffect5(() => {
31016
31116
  if (!id || isDynamic(id)) {
31017
31117
  setList(null);
31018
31118
  return;
31019
31119
  }
31020
- if (reportParams.has(id)) {
31021
- setList(reportParams.get(id));
31120
+ const key2 = `${srv()} ${id}`;
31121
+ if (reportParams.has(key2)) {
31122
+ setList(reportParams.get(key2));
31022
31123
  return;
31023
31124
  }
31024
31125
  let alive = true;
@@ -31031,7 +31132,7 @@ function useReportParams(id) {
31031
31132
  fetch(`${server2}/api/reports/${encodeURIComponent(id)}`).then((r) => r.ok ? r.json() : null).then((r) => {
31032
31133
  const d = r?.definition || r;
31033
31134
  const ps = d && typeof d === "object" ? (d.parameters || []).map((p) => ({ name: p.name, required: !!p.required && p.default == null, prompt: p.prompt })) : null;
31034
- if (ps) reportParams.set(id, ps);
31135
+ if (ps) reportParams.set(key2, ps);
31035
31136
  if (alive) setList(ps);
31036
31137
  }).catch(() => {
31037
31138
  if (alive) setList(null);
@@ -32159,17 +32260,18 @@ function JoinAdder({ allCols, split, onAdd, T }) {
32159
32260
  import { Fragment as Fragment8, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
32160
32261
  var NAME2 = /^[A-Za-z_][\w]*$/;
32161
32262
  var noSourceKey = (def) => (def?.dataSources || []).length ? null : "r4_noDataSource";
32162
- async function loadSample() {
32163
- const { def } = useDesigner.getState();
32164
- useDesigner.setState({ sample: { loading: true } });
32263
+ async function loadSample(store) {
32264
+ const api = store?.getState ? store : activeStore();
32265
+ const { def } = api.getState();
32266
+ api.setState({ sample: { loading: true } });
32165
32267
  try {
32166
32268
  const params = resolveParameters(def, {});
32167
32269
  const sources = await loadSources(def, { params, baseUrl: origin(), sqlPreview: true, fetch: reportFetch(origin(), void 0, { sqlPreview: true }) });
32168
32270
  const ctx = { params, globals: { ExecutionTime: /* @__PURE__ */ new Date() }, dataSets: {}, fields: null, locale: def.locale, currency: def.currency, functions: functionTable(def) };
32169
32271
  const dataSets = buildDataSets(def, sources, ctx);
32170
- useDesigner.setState({ sample: { dataSets, sources, at: Date.now() } });
32272
+ api.setState({ sample: { dataSets, sources, at: Date.now() } });
32171
32273
  } catch (e) {
32172
- useDesigner.setState({ sample: { error: e.message } });
32274
+ api.setState({ sample: { error: e.message } });
32173
32275
  }
32174
32276
  }
32175
32277
  function DataPanel() {
@@ -32990,7 +33092,7 @@ function DataSetDialog({ index, onClose, onSaved }) {
32990
33092
  }
32991
33093
 
32992
33094
  // src/designer/Outline.jsx
32993
- import { useRef as useRef6, useState as useState11 } from "react";
33095
+ import { useRef as useRef7, useState as useState11 } from "react";
32994
33096
  import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
32995
33097
  var MIME = "application/x-pw-outline";
32996
33098
  function Outline() {
@@ -33001,9 +33103,30 @@ function Outline() {
33001
33103
  const T = (k, v) => t(lang2, k, v);
33002
33104
  const [drop, setDrop] = useState11(null);
33003
33105
  const [said, setSaid] = useState11("");
33004
- const dragged = useRef6(null);
33005
- const body = useRef6(null);
33106
+ const [cur2, setCur] = useState11(null);
33107
+ const dragged = useRef7(null);
33108
+ const body = useRef7(null);
33006
33109
  const chosen = new Set(sel.kind === "items" ? sel.ids : sel.kind === "cell" ? [sel.id] : []);
33110
+ const keys = sectionList(def).flatMap(({ key: key2 }) => {
33111
+ const out = [`band:${key2}`];
33112
+ const go = (l) => l.forEach((it) => {
33113
+ out.push(it.id);
33114
+ if (NESTING.has(it.type)) go(it.items || []);
33115
+ });
33116
+ go(secOf(def, key2)?.items || []);
33117
+ return out;
33118
+ });
33119
+ const stop = keys.includes(cur2) ? cur2 : keys.find((k) => chosen.has(k) || sel.kind === "section" && k === `band:${sel.section}`) || keys[0];
33120
+ const roving = (k) => ({ tabIndex: k === stop ? 0 : -1, onFocus: () => setCur(k) });
33121
+ const nav2 = (e) => {
33122
+ if (e.defaultPrevented || e.altKey || e.metaKey || e.ctrlKey || !e.target.hasAttribute("data-opt")) return;
33123
+ const all = [...e.currentTarget.querySelectorAll("[data-opt]")];
33124
+ const i2 = all.indexOf(e.target);
33125
+ const j = e.key === "ArrowDown" ? i2 + 1 : e.key === "ArrowUp" ? i2 - 1 : e.key === "Home" ? 0 : e.key === "End" ? all.length - 1 : null;
33126
+ if (j == null) return;
33127
+ e.preventDefault();
33128
+ all[Math.max(0, Math.min(all.length - 1, j))]?.focus();
33129
+ };
33007
33130
  const pick = (e, id) => {
33008
33131
  const st = useDesigner.getState();
33009
33132
  if (e.shiftKey && st.sel.kind === "items") {
@@ -33115,30 +33238,32 @@ function Outline() {
33115
33238
  };
33116
33239
  const rows = (list2, parent, depth, section) => list2.map((it, i2) => {
33117
33240
  const mark = drop && drop.id != null && drop.id === it.id ? ` drop-${drop.where}` : "";
33118
- return /* @__PURE__ */ jsxs11("li", { children: [
33241
+ return /* @__PURE__ */ jsxs11("li", { role: "none", children: [
33119
33242
  /* @__PURE__ */ jsxs11("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: [
33120
33243
  !readOnly2 && /* @__PURE__ */ jsx14("span", { className: "grip", "aria-hidden": "true", children: "⠿" }),
33121
- /* @__PURE__ */ jsx14("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 }),
33244
+ /* @__PURE__ */ jsx14("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 }),
33122
33245
  /* @__PURE__ */ jsx14("span", { className: "ty", children: T(`item_${it.type}`) === `item_${it.type}` ? ITEMS[it.type]?.label || it.type : T(`item_${it.type}`) }),
33123
33246
  !readOnly2 && /* @__PURE__ */ jsxs11("span", { className: "act", style: { display: "inline-flex", gap: 2 }, children: [
33124
- /* @__PURE__ */ jsx14("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: "↑" }),
33125
- /* @__PURE__ */ jsx14("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: "↓" }),
33126
- parent && /* @__PURE__ */ jsx14("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: "⇱" })
33247
+ /* @__PURE__ */ jsx14("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: "↑" }),
33248
+ /* @__PURE__ */ jsx14("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: "↓" }),
33249
+ parent && /* @__PURE__ */ jsx14("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: "⇱" })
33127
33250
  ] })
33128
33251
  ] }),
33129
- NESTING.has(it.type) && (it.items || []).length > 0 && /* @__PURE__ */ jsx14("ul", { className: "tree", children: rows(it.items, it, depth + 1, section) })
33252
+ NESTING.has(it.type) && (it.items || []).length > 0 && /* @__PURE__ */ jsx14("ul", { className: "tree", role: "none", children: rows(it.items, it, depth + 1, section) })
33130
33253
  ] }, it.id);
33131
33254
  });
33132
33255
  return /* @__PURE__ */ jsxs11("div", { className: "pane", "data-testid": "outline", children: [
33133
33256
  /* @__PURE__ */ jsx14("h4", { children: T("outline") }),
33134
33257
  /* @__PURE__ */ jsxs11("div", { className: "pane-body", ref: body, children: [
33135
- sectionList(def).map(({ key: key2, label }) => {
33258
+ /* @__PURE__ */ jsx14("div", { role: "group", "aria-label": T("outline"), onKeyDown: nav2, children: sectionList(def).map(({ key: key2, label }) => {
33136
33259
  const items = secOf(def, key2)?.items || [];
33137
- return /* @__PURE__ */ jsxs11("div", { className: `outline-sec${drop?.band === key2 ? " drop-band" : ""}`, "data-outline-band": key2, ...bandDrop(key2), children: [
33138
- /* @__PURE__ */ jsx14("button", { type: "button", className: `linklike outline-band${sel.kind === "section" && sel.section === key2 ? " sel" : ""}`, onClick: () => useDesigner.getState().select({ kind: "section", section: key2 }), children: /* @__PURE__ */ jsx14("b", { children: label }) }),
33139
- /* @__PURE__ */ jsx14("ul", { className: "tree", children: items.length ? rows(items, null, 1, key2) : /* @__PURE__ */ jsx14("li", { className: "subtle", children: T("outlineEmpty") }) })
33260
+ return /* @__PURE__ */ jsxs11("div", { role: "group", "aria-label": label, className: `outline-sec${drop?.band === key2 ? " drop-band" : ""}`, "data-outline-band": key2, ...bandDrop(key2), children: [
33261
+ /* @__PURE__ */ jsx14("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}`), children: /* @__PURE__ */ jsx14(
33262
+ "b", { children: label }) }),
33263
+ /* @__PURE__ */ jsx14("ul", { className: "tree", role: "none", children: items.length ? rows(items, null, 1, key2) : /* @__PURE__ */ jsx14("li", { className: "subtle", role: "none", children: T("outlineEmpty") }) })
33140
33264
  ] }, key2);
33141
- }),
33265
+ }) }),
33266
+ /* @__PURE__ */ jsx14("div", { className: "sr-only", id: "outline-nav", children: T("b9_outlineKeys") }),
33142
33267
  /* @__PURE__ */ jsx14("div", { className: "hint", children: T("outlineHint") }),
33143
33268
  !readOnly2 && /* @__PURE__ */ jsx14("div", { className: "hint", id: "outline-keys", children: T("outlineKeys") }),
33144
33269
  /* @__PURE__ */ jsx14("div", { className: "sr-only", role: "status", "aria-live": "polite", children: said })
@@ -33563,6 +33688,7 @@ function TableWizard() {
33563
33688
  const wiz = useDesigner((s) => s.tableWizard);
33564
33689
  const def = useDesigner((s) => s.def);
33565
33690
  const sample = useDesigner((s) => s.sample);
33691
+ const lang2 = useDesigner((s) => s.lang);
33566
33692
  const close = () => useDesigner.getState().setUi({ tableWizard: null });
33567
33693
  const parent = wiz?.parentId ? findItem(def, wiz.parentId)?.item : null;
33568
33694
  const width = Math.max(120, Math.round((parent ? parent.w : bodyWidth(def, wiz?.section || "body")) - (wiz?.x || 0)));
@@ -33629,7 +33755,7 @@ function TableWizard() {
33629
33755
  /* @__PURE__ */ jsxs14("button", { className: "btn ghost", onClick: () => {
33630
33756
  useDesigner.getState().setUi({ tableWizard: null, pivotWizard: { section: wiz.section, x: wiz.x, y: wiz.y, parentId: wiz.parentId, dataSet: c.dataSet } });
33631
33757
  }, "data-testid": "open-pivot-wizard", children: [
33632
- t(useDesigner.getState().lang, "pivotWizard"),
33758
+ t(lang2, "pivotWizard"),
33633
33759
  "…"
33634
33760
  ] }),
33635
33761
  /* @__PURE__ */ jsx17("button", { className: "btn", onClick: close, children: "Cancel" }),
@@ -33642,7 +33768,7 @@ function TableWizard() {
33642
33768
  /* @__PURE__ */ jsxs14("section", { className: "cw-side", "aria-label": "Data for the table", children: [
33643
33769
  /* @__PURE__ */ jsx17(Field, { label: "Data set", children: /* @__PURE__ */ jsx17(Select, { value: c.dataSet, options: (def.dataSets || []).map((d) => d.name), onChange: (v) => set2({ dataSet: v, fields: null, groupBy: "", mRows: "", mCols: "", mValue: "" }) }) }),
33644
33770
  sample?.loading && /* @__PURE__ */ jsx17("span", { className: "hint", children: "Calling the API…" }),
33645
- noSourceKey(def) && /* @__PURE__ */ jsx17("span", { className: "hint", role: "status", "data-testid": "no-source", children: t(useDesigner.getState().lang, noSourceKey(def)) }),
33771
+ noSourceKey(def) && /* @__PURE__ */ jsx17("span", { className: "hint", role: "status", "data-testid": "no-source", children: t(lang2, noSourceKey(def)) }),
33646
33772
  sample?.error && /* @__PURE__ */ jsx17("span", { className: "err", children: sample.error }),
33647
33773
  c.layout !== "matrix" && /* @__PURE__ */ jsxs14(Fragment10, { children: [
33648
33774
  c.layout !== "list" && /* @__PURE__ */ jsx17(Field, { label: "Group by", children: /* @__PURE__ */ jsx17(Select, { value: groupBy2, options: text.map((f) => f.name), onChange: (v) => set2({ groupBy: v }) }) }),
@@ -33704,7 +33830,7 @@ function AskAi({ onClose }) {
33704
33830
  let preview = null;
33705
33831
  try {
33706
33832
  const params = resolveParameters(out.definition, {}, { lenient: true });
33707
- 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()) });
33833
+ 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()) });
33708
33834
  preview = { html: pageToSvg(model.pages[0], model.width, model.height), pages: model.pages.length };
33709
33835
  } catch (e) {
33710
33836
  preview = { error: e.message };
@@ -34176,9 +34302,10 @@ var TOOLS = [
34176
34302
  ] }) }
34177
34303
  ];
34178
34304
  function Toolbox({ T, hide = [] }) {
34305
+ const api = useDesignerStore();
34179
34306
  const name2 = (type) => T(`item_${type}`) === `item_${type}` ? ITEMS[type].label : T(`item_${type}`);
34180
34307
  const add = (type) => {
34181
- const s = useDesigner.getState();
34308
+ const s = api.getState();
34182
34309
  const at2 = insertSpot(s.def, s.sel);
34183
34310
  insertItem(type, at2.section, 0, at2.y, {}, at2.parentId);
34184
34311
  };
@@ -34227,12 +34354,15 @@ var TbGroup = ({ label, children }) => /* @__PURE__ */ jsxs17("div", { className
34227
34354
  ] });
34228
34355
  var QUICK = [["textbox", "text"], ["table", "table"], ["chart", "chart"], ["image", "image"]];
34229
34356
  function LeftRail({ T, readOnly: readOnly2, embed }) {
34230
- const body = useRef7(null);
34357
+ const body = useRef8(null);
34231
34358
  const [at2, setAt] = useState17("tools");
34232
34359
  const tabs = [!readOnly2 && ["tools", "b2_toolbox", "tools"], embed?.panels?.data !== false && ["data", "b2_data", "data"], ["outline", "b2_outline", "outline"]].filter(Boolean);
34233
34360
  const go = (id) => {
34234
34361
  const el = body.current?.querySelector(`[data-rail="${id}"]`);
34235
- if (el) body.current.scrollTo({ top: el.offsetTop - body.current.offsetTop, behavior: "smooth" });
34362
+ if (el) {
34363
+ body.current.scrollTo({ top: el.offsetTop - body.current.offsetTop, behavior: "smooth" });
34364
+ (el.querySelector('[data-opt][tabindex="0"]') || el.querySelector("button, input, select, textarea"))?.focus({ preventScroll: true });
34365
+ }
34236
34366
  setAt(id);
34237
34367
  };
34238
34368
  const spy = () => {
@@ -34334,6 +34464,7 @@ var framed = () => {
34334
34464
  }
34335
34465
  };
34336
34466
  function useAutosave(id, T, lang2, user) {
34467
+ const api = useDesignerStore();
34337
34468
  const [offer, setOffer] = useState17(null);
34338
34469
  useEffect13(() => {
34339
34470
  if (!id || user == null || framed()) return void 0;
@@ -34345,10 +34476,10 @@ function useAutosave(id, T, lang2, user) {
34345
34476
  }
34346
34477
  clearDrafts(store, user);
34347
34478
  const d = readDraft(store, user, id);
34348
- if (d && plain(mergeDraft(d.def, useDesigner.getState().def)) !== plain(useDesigner.getState().def)) setOffer(d);
34479
+ if (d && plain(mergeDraft(d.def, api.getState().def)) !== plain(api.getState().def)) setOffer(d);
34349
34480
  else if (d) clearDraft(store, user, id);
34350
34481
  const keep = () => {
34351
- const s = useDesigner.getState();
34482
+ const s = api.getState();
34352
34483
  if (!s.saved && !s.readOnly) writeDraft(store, user, id, s.def, Date.now(), s.rev || null);
34353
34484
  };
34354
34485
  const t3 = setInterval(keep, AUTOSAVE_MS);
@@ -34357,7 +34488,7 @@ function useAutosave(id, T, lang2, user) {
34357
34488
  };
34358
34489
  window.addEventListener("pagehide", keep);
34359
34490
  document.addEventListener("visibilitychange", hide);
34360
- const unsub = useDesigner.subscribe((s, prev) => {
34491
+ const unsub = api.subscribe((s, prev) => {
34361
34492
  if (s.saved && !prev.saved) clearDraft(store, user, id);
34362
34493
  });
34363
34494
  return () => {
@@ -34369,13 +34500,13 @@ function useAutosave(id, T, lang2, user) {
34369
34500
  }, [id, user]);
34370
34501
  if (!offer) return null;
34371
34502
  const when = new Date(offer.at).toLocaleString(lang2 === "en" ? "en-IN" : lang2, { dateStyle: "medium", timeStyle: "short" });
34372
- const stale = staleDraft(offer, useDesigner.getState().rev);
34503
+ const stale = staleDraft(offer, api.getState().rev);
34373
34504
  return /* @__PURE__ */ jsxs17("div", { className: "draft-bar", role: "alert", "data-testid": "draft-offer", "data-stale": stale || void 0, children: [
34374
34505
  /* @__PURE__ */ jsx20("span", { children: T(stale ? "ux_draftStale" : "ux_draftFound", { when }) }),
34375
34506
  /* @__PURE__ */ jsx20("button", { className: `btn sm${stale ? "" : " primary"}`, "data-testid": "draft-restore", onClick: () => {
34376
- const d = mergeDraft(offer.def, useDesigner.getState().def);
34377
- useDesigner.getState().apply(() => JSON.parse(JSON.stringify(d)));
34378
- useDesigner.getState().fixSelection();
34507
+ const d = mergeDraft(offer.def, api.getState().def);
34508
+ api.getState().apply(() => JSON.parse(JSON.stringify(d)));
34509
+ api.getState().fixSelection();
34379
34510
  setOffer(null);
34380
34511
  }, children: T(stale ? "ux_draftRestoreAnyway" : "ux_draftRestore") }),
34381
34512
  /* @__PURE__ */ jsx20("button", { className: "btn sm", "data-testid": "draft-discard", onClick: () => {
@@ -34388,12 +34519,13 @@ function useAutosave(id, T, lang2, user) {
34388
34519
  ] });
34389
34520
  }
34390
34521
  function ConflictBar({ T }) {
34522
+ const api = useDesignerStore();
34391
34523
  const conflict = useDesigner((s) => s.conflict);
34392
34524
  if (!conflict) return null;
34393
34525
  return /* @__PURE__ */ jsxs17("div", { className: "draft-bar", role: "alert", "data-testid": "save-conflict", children: [
34394
34526
  /* @__PURE__ */ jsx20("span", { children: T("ux_conflict") }),
34395
- /* @__PURE__ */ jsx20("button", { className: "btn sm", "data-testid": "conflict-mine", onClick: () => useDesigner.getState().save({ overwrite: true }), children: T("ux_conflictMine") }),
34396
- /* @__PURE__ */ jsx20("button", { className: "btn sm", "data-testid": "conflict-theirs", onClick: () => useDesigner.getState().takeTheirs(), children: T("ux_conflictTheirs") })
34527
+ /* @__PURE__ */ jsx20("button", { className: "btn sm", "data-testid": "conflict-mine", onClick: () => api.getState().save({ overwrite: true }), children: T("ux_conflictMine") }),
34528
+ /* @__PURE__ */ jsx20("button", { className: "btn sm", "data-testid": "conflict-theirs", onClick: () => api.getState().takeTheirs(), children: T("ux_conflictTheirs") })
34397
34529
  ] });
34398
34530
  }
34399
34531
  var AL = (d) => /* @__PURE__ */ jsx20("svg", { width: "16", height: "14", viewBox: "0 0 16 14", "aria-hidden": "true", children: d });
@@ -34458,12 +34590,13 @@ function AlignBar({ T }) {
34458
34590
  ] });
34459
34591
  }
34460
34592
  function IssuesButton({ T }) {
34593
+ const api = useDesignerStore();
34461
34594
  const issues = useDesignIssues();
34462
34595
  const [open, setOpen] = useState17(false);
34463
34596
  useEffect13(() => {
34464
34597
  if (!issues.length) setOpen(false);
34465
34598
  }, [issues.length]);
34466
- const listRef = useRef7(null);
34599
+ const listRef = useRef8(null);
34467
34600
  useLayoutEffect3(() => {
34468
34601
  const el = listRef.current;
34469
34602
  if (!el) return void 0;
@@ -34481,7 +34614,7 @@ function IssuesButton({ T }) {
34481
34614
  return /* @__PURE__ */ jsxs17("span", { className: "issues-wrap", children: [
34482
34615
  /* @__PURE__ */ jsx20("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 }) }),
34483
34616
  open && /* @__PURE__ */ jsx20("ul", { className: "issues-list", "data-testid": "issues-list", ref: listRef, children: issues.map((i2, k) => /* @__PURE__ */ jsx20("li", { children: /* @__PURE__ */ jsx20("button", { type: "button", className: "linklike", onClick: () => {
34484
- if (i2.id) useDesigner.getState().select({ kind: "items", ids: [i2.id] });
34617
+ if (i2.id) api.getState().select({ kind: "items", ids: [i2.id] });
34485
34618
  }, children: issueLine(T, i2) }) }, k)) })
34486
34619
  ] });
34487
34620
  }
@@ -34505,6 +34638,7 @@ var SHORTCUTS = [
34505
34638
  ["?", "sc_help"]
34506
34639
  ];
34507
34640
  function HistoryDialog({ id, onClose, T, lang: lang2 }) {
34641
+ const api = useDesignerStore();
34508
34642
  const [list2, setList] = useState17(null);
34509
34643
  const [err, setErr] = useState17(null);
34510
34644
  useEffect13(() => {
@@ -34517,7 +34651,7 @@ function HistoryDialog({ id, onClose, T, lang: lang2 }) {
34517
34651
  return;
34518
34652
  }
34519
34653
  const def = await res.json();
34520
- useDesigner.getState().init(id, def);
34654
+ api.getState().init(id, def);
34521
34655
  onClose();
34522
34656
  };
34523
34657
  return /* @__PURE__ */ jsxs17(Dialog, { title: T("versionHistory"), onClose, footer: /* @__PURE__ */ jsx20("button", { className: "btn", onClick: onClose, children: T("close") }), children: [
@@ -34539,18 +34673,48 @@ function HistoryDialog({ id, onClose, T, lang: lang2 }) {
34539
34673
  ] }, v.version))
34540
34674
  ] });
34541
34675
  }
34542
- function Designer({ id, initial, rev = null, lang: langIn, embed = null, user = null, ai = false }) {
34676
+ function Designer({ store: storeIn = null, ...props }) {
34677
+ const [store] = useState17(() => {
34678
+ const s = storeIn || newDesignerStore();
34679
+ activateStore(s);
34680
+ return s;
34681
+ });
34682
+ return /* @__PURE__ */ jsx20(DesignerStore.Provider, { value: store, children: /* @__PURE__ */ jsx20(DesignerIn, { ...props }) });
34683
+ }
34684
+ var ACTIVATE = [
34685
+ "onPointerDownCapture",
34686
+ "onMouseDownCapture",
34687
+ "onKeyDownCapture",
34688
+ "onFocusCapture",
34689
+ "onClickCapture",
34690
+ "onInputCapture",
34691
+ "onChangeCapture",
34692
+ "onDragStartCapture",
34693
+ "onDragOverCapture",
34694
+ "onDropCapture",
34695
+ "onPasteCapture",
34696
+ "onWheelCapture",
34697
+ "onContextMenuCapture",
34698
+ "onDoubleClickCapture",
34699
+ "onSubmitCapture"
34700
+ ];
34701
+ function DesignerIn({ id, initial, rev = null, lang: langIn, embed = null, user = null, ai = false }) {
34702
+ const api = useDesignerStore();
34703
+ const activators = useMemo5(() => {
34704
+ const on = () => activateStore(api);
34705
+ return Object.fromEntries(ACTIVATE.map((k) => [k, on]));
34706
+ }, [api]);
34543
34707
  const lang2 = pickLang(langIn);
34544
34708
  const T = (k, v) => t(lang2, k, v);
34545
34709
  const q2 = lang2 === "en" ? "" : `?lang=${encodeURIComponent(lang2)}`;
34546
- const ready = useRef7(false);
34710
+ const ready = useRef8(false);
34547
34711
  if (!ready.current && typeof window !== "undefined") {
34548
- useDesigner.getState().init(id, initial);
34549
- useDesigner.getState().setUi({ lang: lang2, embed, readOnly: !!embed?.readOnly, rev, conflict: null });
34712
+ api.getState().init(id, initial);
34713
+ api.getState().setUi({ lang: lang2, embed, readOnly: !!embed?.readOnly, rev, conflict: null });
34550
34714
  ready.current = true;
34551
34715
  }
34552
34716
  const readOnly2 = !!embed?.readOnly;
34553
- const rootRef = useRef7(null);
34717
+ const rootRef = useRef8(null);
34554
34718
  const def = useDesigner((s) => s.def);
34555
34719
  const tab = useDesigner((s) => s.tab);
34556
34720
  const saved = useDesigner((s) => s.saved);
@@ -34565,15 +34729,15 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34565
34729
  if (embed) declareDocumentStyles("pw-designer-fonts", fontCss);
34566
34730
  }, [embed, fontCss]);
34567
34731
  useEffect13(() => {
34568
- customFonts().then((list2) => useDesigner.getState().setUi({ fonts: list2 }));
34732
+ customFonts().then((list2) => api.getState().setUi({ fonts: list2 }));
34569
34733
  }, []);
34570
34734
  useEffect13(() => {
34571
34735
  const z = savedZoom();
34572
- if (z != null) useDesigner.getState().setUi({ zoom: z });
34736
+ if (z != null) api.getState().setUi({ zoom: z });
34573
34737
  }, []);
34574
34738
  const canUndo = useDesigner((s) => s.past.length > 0);
34575
34739
  const canRedo = useDesigner((s) => s.future.length > 0);
34576
- const st = useDesigner.getState;
34740
+ const st = api.getState;
34577
34741
  const [dialog, setDialog] = useState17(null);
34578
34742
  const [showLeft, setShowLeft] = useState17(true);
34579
34743
  const [showRight, setShowRight] = useState17(true);
@@ -34586,11 +34750,17 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34586
34750
  const cellSize = useDesigner((s) => s.cellSize);
34587
34751
  const dataKey = useDesigner((s) => `${(s.def?.dataSources || []).map((x) => x.name)}|${(s.def?.dataSets || []).map((x) => x.name)}`);
34588
34752
  useEffect13(() => {
34589
- loadSample();
34753
+ loadSample(api);
34590
34754
  }, [dataKey]);
34591
34755
  useEffect13(() => {
34756
+ let lastInside = false;
34757
+ const inside = (e) => (e.composedPath?.() || []).includes(rootRef.current);
34758
+ const onDown = (e) => {
34759
+ lastInside = inside(e);
34760
+ };
34761
+ const ours = (e) => inside(e) || lastInside && (e.target === document.body || e.target === document.documentElement);
34592
34762
  const onKey = (e) => {
34593
- if (embed && !(e.composedPath?.() || []).includes(rootRef.current)) return;
34763
+ if (embed && !ours(e)) return;
34594
34764
  const mod = e.metaKey || e.ctrlKey;
34595
34765
  if (mod && e.key.toLowerCase() === "s") {
34596
34766
  e.preventDefault();
@@ -34609,7 +34779,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34609
34779
  st().save();
34610
34780
  return;
34611
34781
  }
34612
- if (isTyping(e) || st().tab !== "design") return;
34782
+ if (isTyping(e) || st().tab !== "design" || e.defaultPrevented) return;
34613
34783
  if (mod && e.key.toLowerCase() === "z") {
34614
34784
  e.preventDefault();
34615
34785
  e.shiftKey ? st().redo() : st().undo();
@@ -34632,11 +34802,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34632
34802
  }
34633
34803
  return;
34634
34804
  }
34635
- if (mod && e.key.toLowerCase() === "v") {
34636
- e.preventDefault();
34637
- pasteItems(st().sel.kind === "section" ? st().sel.section : "body");
34638
- return;
34639
- }
34805
+ if (mod && e.key.toLowerCase() === "v") return;
34640
34806
  if (e.key === "Delete" || e.key === "Backspace") {
34641
34807
  if (st().sel.kind === "items") {
34642
34808
  e.preventDefault();
@@ -34668,10 +34834,24 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34668
34834
  e.returnValue = "";
34669
34835
  }
34670
34836
  };
34837
+ const onPaste = (e) => {
34838
+ if (embed && !ours(e) || isTyping(e) || st().tab !== "design") return;
34839
+ e.preventDefault();
34840
+ if (!pasteItems(st().sel.kind === "section" ? st().sel.section : "body", e.clipboardData?.getData("text/plain"))) {
34841
+ st().setUi({ saveError: t(lang2, "b9_nothingToPaste") });
34842
+ setTimeout(() => st().setUi({ saveError: null }), 3e3);
34843
+ }
34844
+ };
34671
34845
  window.addEventListener("keydown", onKey);
34846
+ window.addEventListener("paste", onPaste);
34847
+ window.addEventListener("pointerdown", onDown, true);
34848
+ window.addEventListener("focusin", onDown, true);
34672
34849
  if (!embed) window.addEventListener("beforeunload", onLeave);
34673
34850
  return () => {
34674
34851
  window.removeEventListener("keydown", onKey);
34852
+ window.removeEventListener("paste", onPaste);
34853
+ window.removeEventListener("pointerdown", onDown, true);
34854
+ window.removeEventListener("focusin", onDown, true);
34675
34855
  window.removeEventListener("beforeunload", onLeave);
34676
34856
  };
34677
34857
  }, [st, embed]);
@@ -34690,17 +34870,17 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34690
34870
  const d = await embed.onOpen();
34691
34871
  if (d && typeof d === "object") {
34692
34872
  st().init(id, d);
34693
- loadSample();
34873
+ loadSample(api);
34694
34874
  }
34695
34875
  };
34696
- const importInput = useRef7(null);
34876
+ const importInput = useRef8(null);
34697
34877
  const [imported, setImported] = useState17(null);
34698
34878
  const importFile = async (file) => {
34699
34879
  if (!file) return;
34700
34880
  const r = readReportFile(file.name, await file.text());
34701
34881
  if (r.definition) {
34702
34882
  st().init(id, r.definition);
34703
- loadSample();
34883
+ loadSample(api);
34704
34884
  }
34705
34885
  setImported({ name: file.name, ok: !!r.definition, warnings: r.warnings || [], error: r.error });
34706
34886
  };
@@ -34714,7 +34894,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34714
34894
  ] }),
34715
34895
  /* @__PURE__ */ jsx20("span", { className: "hint", children: T("loadingDesigner") })
34716
34896
  ] }) });
34717
- return /* @__PURE__ */ jsxs17("div", { className: "designer", "data-testid": "designer", dir: dirOf(lang2), lang: lang2, ref: rootRef, "data-readonly": readOnly2 || void 0, children: [
34897
+ return /* @__PURE__ */ jsxs17("div", { className: "designer", "data-testid": "designer", dir: dirOf(lang2), lang: lang2, ref: rootRef, "data-readonly": readOnly2 || void 0, ...activators, children: [
34718
34898
  !embed && /* @__PURE__ */ jsx20("style", { children: fontCss }),
34719
34899
  /* @__PURE__ */ jsxs17("header", { className: "dtop dbar", children: [
34720
34900
  embed ? /* @__PURE__ */ jsxs17("span", { className: "brand", children: [
@@ -34902,6 +35082,7 @@ var CSS2 = true ? `/* Layout: a drafting table. Cool grey workspace, white paper
34902
35082
  --ink: #16202a;
34903
35083
  --muted: #5f6b77;
34904
35084
  --faint: #64717e; /* 5:1 on panel (was #8e99a4, 2.9:1) */
35085
+ --faint-desk: #5a6672; /* small text on the desk: 4.85:1 on #e6eaee (--faint is 4.13:1 there) */
34905
35086
  --line-strong: #848f9b; /* control borders, 3:1 */
34906
35087
  --accent: #0e7490;
34907
35088
  --accent-ink: #ffffff;
@@ -34955,6 +35136,7 @@ var CSS2 = true ? `/* Layout: a drafting table. Cool grey workspace, white paper
34955
35136
  --ink: #e6edf3;
34956
35137
  --muted: #a3afbb;
34957
35138
  --faint: #8693a0;
35139
+ --faint-desk: #8693a0;
34958
35140
  --accent: #3cbfd4;
34959
35141
  --accent-ink: #03222a;
34960
35142
  --accent-soft: #123a44;
@@ -35252,6 +35434,7 @@ a.cell-name:hover { color: var(--accent); }
35252
35434
  .outline-row.sel { background: var(--accent-soft); }
35253
35435
  .outline-row .linklike.nm, .outline-band { text-decoration: none; color: var(--ink); text-align: start; }
35254
35436
  .outline-row.sel .linklike.nm, .outline-band.sel { color: var(--accent); }
35437
+ .outline-row.sel .ty { color: var(--muted); } /* --faint is 4.38:1 on --accent-soft; --muted passes in both themes */
35255
35438
  .outline-row.sel .act, .outline-row:focus-within .act { opacity: 1; }
35256
35439
  .outline-row[draggable="true"] { cursor: grab; }
35257
35440
  .outline-row .grip { color: var(--faint); font-size: 10px; line-height: 1; margin-inline-start: -2px; opacity: .55; }
@@ -35293,7 +35476,7 @@ a.cell-name:hover { color: var(--accent); }
35293
35476
  .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); }
35294
35477
  .tbl.sel .grip { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
35295
35478
  .tbl .row { position: relative; display: flex; }
35296
- .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%; }
35479
+ .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%; }
35297
35480
  .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; }
35298
35481
  .tbl .cell:first-child { border-left: 1px dashed rgba(95,107,119,.3); }
35299
35482
  .tbl .row:first-child .cell { border-top: 1px dashed rgba(95,107,119,.3); }
@@ -35813,7 +35996,7 @@ input[type=checkbox], input[type=radio] { width: 16px; height: 16px; accent-colo
35813
35996
 
35814
35997
  .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}
35815
35998
  ` : "";
35816
- var BLANK = { $schema: "pagewright/report@1", name: "New report", page: { size: "A4", margins: [36, 36, 36, 36] }, dataSources: [], dataSets: [], sections: { body: { items: [] } } };
35999
+ var BLANK = { $schema: "pagewright/report@1", name: "Untitled report", page: { size: "A4", margins: [36, 36, 36, 36] }, dataSources: [], dataSets: [], sections: { body: { items: [] } } };
35817
36000
  function mountDesigner(target, opts = {}) {
35818
36001
  const el = typeof target === "string" ? document.querySelector(target) : target;
35819
36002
  if (!el) throw new Error(`mountDesigner: no element for ${target}`);
@@ -35831,18 +36014,43 @@ function mountDesigner(target, opts = {}) {
35831
36014
  );
35832
36015
  box.style.height = opts.height || "760px";
35833
36016
  const root = createRoot(box);
36017
+ const store = newDesignerStore();
35834
36018
  const embed = { onSave: opts.onSave, onOpen: opts.onOpen, readOnly: !!opts.readOnly, toolbox: opts.toolbox, panels: opts.panels, dataSourceTemplates: opts.dataSourceTemplates, server: server2 };
35835
36019
  const show = (definition) => loadLanguage(opts.lang).catch(() => {
35836
- }).then(() => root.render(createElement2(Designer, { id: opts.report, initial: definition, lang: opts.lang, embed })));
36020
+ }).then(() => root.render(createElement2(Designer, { id: opts.report, initial: definition, lang: opts.lang, embed, store })));
35837
36021
  if (opts.definition || !opts.report) show(opts.definition || BLANK);
35838
36022
  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) => {
35839
36023
  box.innerHTML = `<div class="vmsg error">The report did not load: ${String(e.message).replace(/</g, "&lt;")}</div>`;
35840
36024
  });
36025
+ const onLeave = (e) => {
36026
+ e.preventDefault();
36027
+ e.returnValue = "";
36028
+ };
36029
+ let dirty = false;
36030
+ const unsub = store.subscribe((s) => {
36031
+ if (!s.saved === dirty) return;
36032
+ dirty = !s.saved;
36033
+ if (opts.warnOnLeave !== false) {
36034
+ if (dirty) window.addEventListener("beforeunload", onLeave);
36035
+ else window.removeEventListener("beforeunload", onLeave);
36036
+ }
36037
+ try {
36038
+ opts.onDirtyChange?.(dirty);
36039
+ } catch (e) {
36040
+ console.error(e);
36041
+ }
36042
+ });
35841
36043
  return {
35842
- unmount: () => root.unmount(),
36044
+ unmount: () => {
36045
+ unsub();
36046
+ window.removeEventListener("beforeunload", onLeave);
36047
+ root.unmount();
36048
+ },
36049
+ /** whether there are changes not saved yet */
36050
+ isDirty: () => !store.getState().saved,
35843
36051
  /** the definition as it is now (a plain copy) */
35844
- getDefinition: () => JSON.parse(JSON.stringify(useDesigner.getState().def)),
35845
- save: () => useDesigner.getState().save()
36052
+ getDefinition: () => JSON.parse(JSON.stringify(store.getState().def)),
36053
+ save: () => store.getState().save()
35846
36054
  };
35847
36055
  }
35848
36056
  export {