@reportwright/viewer 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +16 -1
  3. package/THIRD-PARTY-NOTICES.md +52 -0
  4. package/dist/{chunk-S2IUUI6N.js → chunk-BF7GCWZY.js} +67 -49
  5. package/dist/chunk-BF7GCWZY.js.map +6 -0
  6. package/dist/chunk-BR5K6SBL.js +324 -0
  7. package/dist/chunk-BR5K6SBL.js.map +6 -0
  8. package/dist/{peer/chunk-BQFI3DHK.js → chunk-CNDUJ7IV.js} +289 -25
  9. package/dist/chunk-CNDUJ7IV.js.map +6 -0
  10. package/dist/{chunk-VNOWPSE6.js → chunk-EK5CJY22.js} +1223 -899
  11. package/dist/chunk-EK5CJY22.js.map +6 -0
  12. package/dist/{chunk-2BPBQMH2.js → chunk-F5EPQTPF.js} +3 -3
  13. package/dist/chunk-FEM2QVOO.js +18 -0
  14. package/dist/{chunk-3D2KFKG2.js → chunk-IFYCJZNS.js} +8 -6
  15. package/dist/chunk-IFYCJZNS.js.map +6 -0
  16. package/dist/{chunk-NR2G4TMG.js → chunk-L6YEIVVD.js} +43 -22
  17. package/dist/chunk-L6YEIVVD.js.map +6 -0
  18. package/dist/{chunk-DPVJEFKP.js → chunk-PQNM6ET7.js} +4 -4
  19. package/dist/{chunk-DPVJEFKP.js.map → chunk-PQNM6ET7.js.map} +1 -1
  20. package/dist/{chunk-Z7MKH66Z.js → chunk-QFLVVM3H.js} +225 -11
  21. package/dist/chunk-QFLVVM3H.js.map +6 -0
  22. package/dist/{chunk-PGP3QA6L.js → chunk-TZXEEVKE.js} +1301 -70
  23. package/dist/chunk-TZXEEVKE.js.map +6 -0
  24. package/dist/{chunk-Q6MMPKQA.js → chunk-UHHURTSV.js} +11 -10
  25. package/dist/chunk-UHHURTSV.js.map +6 -0
  26. package/dist/{chunk-M6AYND5G.js → chunk-UJL7C2AS.js} +16 -7
  27. package/dist/chunk-UJL7C2AS.js.map +6 -0
  28. package/dist/chunk-YIX3OJXU.js +34 -0
  29. package/dist/designer.d.ts +11 -3
  30. package/dist/designer.js +587 -386
  31. package/dist/designer.js.map +3 -3
  32. package/dist/engine.worker.js +16729 -18
  33. package/dist/engine.worker.js.map +3 -3
  34. package/dist/peer/{chunk-6I2EAAVN.js → chunk-2CD5COHN.js} +43 -22
  35. package/dist/peer/chunk-2CD5COHN.js.map +6 -0
  36. package/dist/peer/{chunk-BMAXIBP2.js → chunk-3CBV5SAI.js} +4 -4
  37. package/dist/peer/{chunk-BMAXIBP2.js.map → chunk-3CBV5SAI.js.map} +1 -1
  38. package/dist/peer/{chunk-WSNRD2AQ.js → chunk-45GVDKP5.js} +11 -10
  39. package/dist/{chunk-Q6MMPKQA.js.map → peer/chunk-45GVDKP5.js.map} +1 -1
  40. package/dist/peer/{chunk-R4VX5UC7.js → chunk-LWXQX3NJ.js} +3 -3
  41. package/dist/{chunk-6TPZ7G74.js → peer/chunk-MKY3SDXU.js} +289 -25
  42. package/dist/peer/chunk-MKY3SDXU.js.map +6 -0
  43. package/dist/peer/chunk-S6LSPHSU.js +17 -0
  44. package/dist/peer/chunk-S6LSPHSU.js.map +6 -0
  45. package/dist/peer/{chunk-TSC4RAH3.js → chunk-VZHHNQYB.js} +1301 -70
  46. package/dist/peer/chunk-VZHHNQYB.js.map +6 -0
  47. package/dist/peer/{chunk-WQGENQZO.js → chunk-YITWGAR4.js} +8 -6
  48. package/dist/peer/chunk-YITWGAR4.js.map +6 -0
  49. package/dist/peer/chunk-Z5II55QT.js +33 -0
  50. package/dist/peer/chunk-Z5II55QT.js.map +6 -0
  51. package/dist/peer/designer.js +444 -243
  52. package/dist/peer/designer.js.map +3 -3
  53. package/dist/peer/engine.worker.js +16729 -17
  54. package/dist/peer/engine.worker.js.map +3 -3
  55. package/dist/peer/viewer.js +14 -11
  56. package/dist/peer/viewer.js.map +1 -1
  57. package/dist/viewer.d.ts +2 -1
  58. package/dist/viewer.js +14 -11
  59. package/dist/viewer.js.map +1 -1
  60. package/package.json +4 -2
  61. package/dist/chunk-3D2KFKG2.js.map +0 -6
  62. package/dist/chunk-6TPZ7G74.js.map +0 -6
  63. package/dist/chunk-BRB34AJ2.js +0 -16
  64. package/dist/chunk-M6AYND5G.js.map +0 -6
  65. package/dist/chunk-NR2G4TMG.js.map +0 -6
  66. package/dist/chunk-PGP3QA6L.js.map +0 -6
  67. package/dist/chunk-S2IUUI6N.js.map +0 -6
  68. package/dist/chunk-ULKEEARQ.js +0 -553
  69. package/dist/chunk-ULKEEARQ.js.map +0 -6
  70. package/dist/chunk-VNOWPSE6.js.map +0 -6
  71. package/dist/chunk-Z7MKH66Z.js.map +0 -6
  72. package/dist/peer/chunk-2FZTYEDE.js +0 -15
  73. package/dist/peer/chunk-6I2EAAVN.js.map +0 -6
  74. package/dist/peer/chunk-BQFI3DHK.js.map +0 -6
  75. package/dist/peer/chunk-TSC4RAH3.js.map +0 -6
  76. package/dist/peer/chunk-WQGENQZO.js.map +0 -6
  77. package/dist/peer/chunk-WSNRD2AQ.js.map +0 -6
  78. /package/dist/{chunk-2BPBQMH2.js.map → chunk-F5EPQTPF.js.map} +0 -0
  79. /package/dist/{chunk-BRB34AJ2.js.map → chunk-FEM2QVOO.js.map} +0 -0
  80. /package/dist/{peer/chunk-2FZTYEDE.js.map → chunk-YIX3OJXU.js.map} +0 -0
  81. /package/dist/peer/{chunk-R4VX5UC7.js.map → chunk-LWXQX3NJ.js.map} +0 -0
@@ -10,16 +10,18 @@ import {
10
10
  setShadowStyles,
11
11
  t,
12
12
  uiFontCss
13
- } from "./chunk-6I2EAAVN.js";
13
+ } from "./chunk-2CD5COHN.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-MKY3SDXU.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,31 +51,29 @@ 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";
69
+ } from "../chunk-EK5CJY22.js";
73
70
  import {
74
- TextMeasurer,
75
- finishText
76
- } from "../chunk-ULKEEARQ.js";
71
+ PAGE_SIZES,
72
+ fromPt,
73
+ normBox,
74
+ resolvePage,
75
+ toPt
76
+ } from "../chunk-BR5K6SBL.js";
77
77
  import "../chunk-72S6DETS.js";
78
78
  import {
79
79
  currencyOf
@@ -83,14 +83,14 @@ import {
83
83
  fontFaceCss,
84
84
  fontFamilyCss,
85
85
  pageToSvg
86
- } from "../chunk-M6AYND5G.js";
86
+ } from "../chunk-UJL7C2AS.js";
87
87
  import {
88
88
  BUNDLED_FAMILIES,
89
89
  FONT_FAMILIES,
90
90
  allFontKeys,
91
91
  fallbackKeys,
92
92
  resolveFontKey
93
- } from "../chunk-Z7MKH66Z.js";
93
+ } from "../chunk-QFLVVM3H.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,16 @@ 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
+ copy.x += PASTE_OFFSET;
8282
+ copy.y += PASTE_OFFSET;
8283
+ growToFit(d, { ...f, item: copy });
8247
8284
  f.list.push(copy);
8248
8285
  newIds.push(copy.id);
8249
8286
  }
8250
8287
  });
8251
8288
  if (newIds.length) S().select({ kind: "items", ids: newIds });
8252
8289
  }
8290
+ var PASTE_OFFSET = 12;
8253
8291
  var CLIP = "pagewright/items@1";
8254
8292
  async function copySelection() {
8255
8293
  const { sel, def } = S();
@@ -8264,43 +8302,41 @@ async function copySelection() {
8264
8302
  return items.length;
8265
8303
  }
8266
8304
  var memClip = null;
8267
- async function pasteItems(section = "body") {
8268
- let text = null;
8305
+ var clipOf = (text) => {
8269
8306
  try {
8270
- text = await navigator.clipboard.readText();
8307
+ const d = JSON.parse(text);
8308
+ return d?.kind === CLIP && Array.isArray(d.items) ? d : null;
8271
8309
  } catch {
8272
- text = memClip;
8273
- }
8274
- if (!text || !text.includes(CLIP)) text = memClip;
8275
- let data;
8276
- try {
8277
- data = JSON.parse(text);
8278
- } catch {
8279
- return 0;
8310
+ return null;
8280
8311
  }
8281
- if (data?.kind !== CLIP || !Array.isArray(data.items)) return 0;
8312
+ };
8313
+ function pasteItems(section = "body", text = null) {
8314
+ const st = active;
8315
+ const data = clipOf(text) || clipOf(memClip);
8316
+ if (!data) return 0;
8282
8317
  const ids = [];
8283
- S().apply((d) => {
8318
+ st.getState().apply((d) => {
8284
8319
  const used = allNames(d);
8285
8320
  for (const it of data.items) {
8286
8321
  const c = cloneWithIds(it, used);
8287
- c.x += 12;
8288
- c.y += 12;
8322
+ c.x += PASTE_OFFSET;
8323
+ c.y += PASTE_OFFSET;
8289
8324
  if (c.type === "table" && !isBodyKey(section)) continue;
8290
8325
  secOf(d, section).items.push(c);
8326
+ growToFit(d, { section, parent: null, item: c });
8291
8327
  ids.push(c.id);
8292
8328
  }
8293
8329
  });
8294
- if (ids.length) S().select({ kind: "items", ids });
8330
+ if (ids.length) st.getState().select({ kind: "items", ids });
8295
8331
  return ids.length;
8296
8332
  }
8297
- function rowsOf(t3, part, create2 = false) {
8333
+ function rowsOf(t3, part, create = false) {
8298
8334
  const m = /^g(\d+)([hf])$/.exec(part);
8299
8335
  const holder = m ? t3.groups?.[Number(m[1])] : t3;
8300
8336
  if (!holder) return null;
8301
8337
  const key2 = m ? m[2] === "h" ? "header" : "footer" : part;
8302
8338
  if (!holder[key2]) {
8303
- if (!create2) return [];
8339
+ if (!create) return [];
8304
8340
  holder[key2] = [];
8305
8341
  }
8306
8342
  return holder[key2];
@@ -8500,6 +8536,7 @@ function tableRemoveGroup(id, level) {
8500
8536
  }
8501
8537
  var IMAGE_MAX = 10 * 1024 * 1024;
8502
8538
  async function uploadImages(files, T) {
8539
+ const st = active;
8503
8540
  const names = [];
8504
8541
  let err = null;
8505
8542
  for (const f of files) {
@@ -8518,7 +8555,7 @@ async function uploadImages(files, T) {
8518
8555
  r.readAsDataURL(f);
8519
8556
  });
8520
8557
  const base2 = f.name.replace(/\.[^.]+$/, "").replace(/\W+/g, "_").replace(/^_+|_+$/g, "") || "image";
8521
- S().apply((d) => {
8558
+ st.getState().apply((d) => {
8522
8559
  d.images || (d.images = {});
8523
8560
  let n = base2, k = 2;
8524
8561
  while (d.images[n]) n = `${base2}${k++}`;
@@ -8585,6 +8622,13 @@ function wouldOverlap(def, ids, rectOf2) {
8585
8622
  }
8586
8623
  return false;
8587
8624
  }
8625
+ function setMatrixShow(v, show) {
8626
+ const pct = !!show && show !== "value";
8627
+ if (pct) v.show = show;
8628
+ else delete v.show;
8629
+ if (pct && (!v.format || v.format === "N0")) v.format = "P1";
8630
+ else if (!pct && v.format === "P1") v.format = "N0";
8631
+ }
8588
8632
 
8589
8633
  // src/designer/ui.jsx
8590
8634
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -8633,18 +8677,18 @@ function ColorInput({ value, onChange }) {
8633
8677
  /* @__PURE__ */ jsx(TextInput, { value, onChange: (v) => onChange(v === "" ? void 0 : v), mono: true, placeholder: T("i_colorPh") })
8634
8678
  ] });
8635
8679
  }
8636
- var FieldScope = createContext(void 0);
8680
+ var FieldScope = createContext2(void 0);
8637
8681
  var issueText = (T, i2) => i2.suggest ? T("ux_unknownFieldSuggest", { name: i2.name, suggest: i2.suggest }) : T("ux_unknownField", { name: i2.name });
8638
8682
  function ExprInput({ value, onChange, onOpen, placeholder: placeholder2 }) {
8639
8683
  const T = useT();
8640
- const scope = useContext(FieldScope);
8684
+ const scope = useContext2(FieldScope);
8641
8685
  const dataSets = useDesigner((s) => s.def?.dataSets);
8642
8686
  const err = value ? checkValue(value) : null;
8643
8687
  const issues = !err && value && scope !== void 0 ? fieldIssues(value, dataSets, scope) : [];
8644
8688
  return /* @__PURE__ */ jsxs("div", { children: [
8645
8689
  /* @__PURE__ */ jsxs("div", { className: "expr-row", children: [
8646
8690
  /* @__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" })
8691
+ /* @__PURE__ */ jsx("button", { className: "fx", title: T("i_openExprEditor"), "aria-label": `fx: ${T("i_openExprEditor")}`, onClick: onOpen, type: "button", children: "fx" })
8648
8692
  ] }),
8649
8693
  err && /* @__PURE__ */ jsx("div", { className: "err", children: err }),
8650
8694
  issues.map((i2, k) => /* @__PURE__ */ jsx("div", { className: "warn", "data-testid": "field-warning", children: issueText(T, i2) }, k))
@@ -8664,14 +8708,19 @@ function Check({ label, checked, onChange }) {
8664
8708
  ] });
8665
8709
  }
8666
8710
  function Dialog({ title, children, onClose, footer, wide, className = "" }) {
8711
+ const ref = useRef(null);
8667
8712
  useEffect(() => {
8713
+ const inOther = (e) => {
8714
+ const mine = ref.current?.closest(".designer");
8715
+ return e.composedPath().some((n) => n !== mine && n?.classList?.contains("designer"));
8716
+ };
8668
8717
  const k = (e) => {
8669
- if (e.key === "Escape" && !e.defaultPrevented) onClose();
8718
+ if (e.key === "Escape" && !e.defaultPrevented && !inOther(e)) onClose();
8670
8719
  };
8671
8720
  window.addEventListener("keydown", k);
8672
8721
  return () => window.removeEventListener("keydown", k);
8673
8722
  }, [onClose]);
8674
- return /* @__PURE__ */ jsx("div", { className: "scrim", onPointerDown: (e) => {
8723
+ return /* @__PURE__ */ jsx("div", { className: "scrim", ref, onPointerDown: (e) => {
8675
8724
  if (e.target === e.currentTarget) onClose();
8676
8725
  }, children: /* @__PURE__ */ jsxs("div", { className: `dialog${wide ? " wide" : ""}${className ? ` ${className}` : ""}`, role: "dialog", "aria-modal": "true", "aria-label": title, children: [
8677
8726
  /* @__PURE__ */ jsx("header", { children: title }),
@@ -8687,10 +8736,10 @@ function Link({ href, children, prefetch, replace: replace2, scroll, shallow, ..
8687
8736
  }
8688
8737
 
8689
8738
  // src/designer/SvgHtml.jsx
8690
- import { useLayoutEffect, useRef } from "react";
8739
+ import { useLayoutEffect, useRef as useRef2 } from "react";
8691
8740
  import { jsx as jsx2 } from "react/jsx-runtime";
8692
8741
  function SvgHtml({ html, as: Tag2 = "span", ...rest }) {
8693
- const ref = useRef(
8742
+ const ref = useRef2(
8694
8743
  /** @type {HTMLElement|null} */
8695
8744
  null
8696
8745
  );
@@ -8703,7 +8752,7 @@ function SvgHtml({ html, as: Tag2 = "span", ...rest }) {
8703
8752
  }
8704
8753
 
8705
8754
  // src/designer/Canvas.jsx
8706
- import { createContext as createContext2, useContext as useContext2, useEffect as useEffect3, useMemo, useRef as useRef2, useState as useState4 } from "react";
8755
+ import { createContext as createContext3, useContext as useContext3, useEffect as useEffect3, useMemo, useRef as useRef3, useState as useState4 } from "react";
8707
8756
 
8708
8757
  // src/designer/tableGen.js
8709
8758
  var HEAD = { fontWeight: "bold", backgroundColor: "#f1f5f9", borderBottom: "0.75 solid #94a3b8" };
@@ -8844,7 +8893,11 @@ function useFontFamilies() {
8844
8893
  const fonts = useDesigner((s) => s.fonts);
8845
8894
  return [...BUNDLED_FAMILIES, ...[...new Set(fonts.map((f) => f.family))].sort()];
8846
8895
  }
8847
- var refresh = async () => useDesigner.getState().setUi({ fonts: await customFonts(true) });
8896
+ var refresh = async () => {
8897
+ const api = activeStore2();
8898
+ const fonts = await customFonts(true);
8899
+ api.getState().setUi({ fonts });
8900
+ };
8848
8901
  function FontsDialog({ onClose }) {
8849
8902
  const fonts = useDesigner((s) => s.fonts);
8850
8903
  const [file, setFile] = useState2(null);
@@ -8943,24 +8996,27 @@ var apply = (fn3, key2) => S2().apply(fn3, key2);
8943
8996
  var server = () => S2().embed?.server || "";
8944
8997
  var noServer = () => !!S2().embed && !S2().embed.server;
8945
8998
  var pending = /* @__PURE__ */ new Map();
8946
- function fetchReused(id, force = false) {
8999
+ function fetchReused(id, force = false, api = activeStore2()) {
8947
9000
  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 } }));
9001
+ const st = api.getState();
9002
+ if (!force && st.reused[id]) return Promise.resolve(st.reused[id]);
9003
+ const server2 = st.embed?.server || "", key2 = `${server2} ${id}`;
9004
+ const keep = (d) => {
9005
+ api.setState((s) => ({ reused: { ...s.reused, [id]: d } }));
8954
9006
  return d;
8955
- });
8956
- pending.set(id, p);
8957
- return p;
9007
+ };
9008
+ if (pending.has(key2)) return pending.get(key2).then(keep);
9009
+ if (st.embed && !server2) return Promise.resolve(null);
9010
+ 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));
9011
+ pending.set(key2, p);
9012
+ return p.then(keep);
8958
9013
  }
8959
9014
  function useReused(id) {
9015
+ const api = useDesignerStore();
8960
9016
  const d = useDesigner((s) => id ? s.reused[id] : void 0);
8961
9017
  useEffect2(() => {
8962
- fetchReused(id);
8963
- }, [id]);
9018
+ fetchReused(id, false, api);
9019
+ }, [id, api]);
8964
9020
  return d && !d.__error ? d : null;
8965
9021
  }
8966
9022
  var listCache = null;
@@ -9529,7 +9585,7 @@ function useDesignIssues() {
9529
9585
  return [...designIssues(def, bands, extents || {}), ...checkIssues(bands, [...validate(def).errors, ...saveCheck?.missing || []])];
9530
9586
  }, [def, extents, saveCheck]);
9531
9587
  }
9532
- var IssueMap = createContext2(/* @__PURE__ */ new Map());
9588
+ var IssueMap = createContext3(/* @__PURE__ */ new Map());
9533
9589
  function issueLine(T, i2) {
9534
9590
  if (i2.kind === "overlap") return T("ux_issueOverlap", { name: i2.name, other: i2.other });
9535
9591
  if (i2.kind === "wide") return T("ux_issueWide", { name: i2.name, width: i2.width, room: i2.room });
@@ -9594,7 +9650,7 @@ function Canvas() {
9594
9650
  const bands = sectionList(def);
9595
9651
  const widths2 = Object.fromEntries(bands.map((s) => [s.key, bodyWidth(def, s.key)]));
9596
9652
  const bw = Math.max(...Object.values(widths2));
9597
- const scrollRef = useRef2(null);
9653
+ const scrollRef = useRef3(null);
9598
9654
  const [fitW, setFitW] = useState4(0);
9599
9655
  useEffect3(() => {
9600
9656
  if (zoom !== "fit" || !scrollRef.current) return;
@@ -9688,7 +9744,7 @@ function Band({ section, label, scale, bw: bandW, drag, setDrag, phBox = null })
9688
9744
  const off = phBox || mb?.off || null;
9689
9745
  const contentList = useDesigner((s) => s.def.sections?.content);
9690
9746
  const bw = off?.w || bandW;
9691
- const ref = useRef2(null);
9747
+ const ref = useRef3(null);
9692
9748
  const [marquee, setMarquee] = useState4(null);
9693
9749
  const [dropping, setDropping] = useState4(false);
9694
9750
  const h = drag?.mode === "band" && drag.section === section ? drag.h : sec.height || 0;
@@ -9864,8 +9920,9 @@ var alerted = 0;
9864
9920
  function alertOnce(msg) {
9865
9921
  if (Date.now() - alerted > 3e3) {
9866
9922
  alerted = Date.now();
9867
- useDesigner.setState({ saveError: msg });
9868
- setTimeout(() => useDesigner.setState({ saveError: null }), 3e3);
9923
+ const api = activeStore2();
9924
+ api.setState({ saveError: msg });
9925
+ setTimeout(() => api.setState({ saveError: null }), 3e3);
9869
9926
  }
9870
9927
  }
9871
9928
  function fieldStyle(f) {
@@ -9873,11 +9930,31 @@ function fieldStyle(f) {
9873
9930
  const format = formatFor({ name: f.field, type: f.type }, (st.sample?.dataSets?.[f.dataSet] || []).slice(0, 200), { currency: st.def?.currency });
9874
9931
  return format ? { format } : {};
9875
9932
  }
9933
+ function useItemKeys(item) {
9934
+ const T = useT2();
9935
+ const type = T(`item_${item.type}`) === `item_${item.type}` ? ITEMS[item.type]?.label || item.type : T(`item_${item.type}`);
9936
+ return {
9937
+ tabIndex: 0,
9938
+ role: "group",
9939
+ "data-item-key": item.id,
9940
+ "aria-label": T("b9_itemLabel", { type, name: item.name, x: round(item.x), y: round(item.y) }),
9941
+ onKeyDown: (e) => {
9942
+ if (e.target !== e.currentTarget || e.key !== "Enter" && e.key !== " ") return;
9943
+ e.preventDefault();
9944
+ e.stopPropagation();
9945
+ const st = useDesigner.getState();
9946
+ const cur2 = st.sel.kind === "items" ? st.sel.ids : [];
9947
+ const ids = !e.shiftKey ? [item.id] : cur2.includes(item.id) ? cur2.filter((i2) => i2 !== item.id) : [...cur2, item.id];
9948
+ st.select(ids.length ? { kind: "items", ids } : { kind: "report" });
9949
+ }
9950
+ };
9951
+ }
9876
9952
  function useItemDrag(item, scale, setDrag) {
9877
9953
  return (e) => {
9878
9954
  if (e.button !== 0) return;
9879
9955
  e.preventDefault();
9880
9956
  e.stopPropagation();
9957
+ e.currentTarget.closest?.("[data-item-key]")?.focus({ preventScroll: true });
9881
9958
  const st = useDesigner.getState();
9882
9959
  let ids;
9883
9960
  if (e.shiftKey) {
@@ -9950,7 +10027,7 @@ function AnyItem(props) {
9950
10027
  return layer?.locked ? /* @__PURE__ */ jsx6("div", { className: "layer-locked", "data-locked": props.item.name, children: el }) : el;
9951
10028
  }
9952
10029
  function NestChildren({ item, scale, drag, setDrag, section }) {
9953
- const ref = useRef2(null);
10030
+ const ref = useRef3(null);
9954
10031
  const [over, setOver] = useState4(false);
9955
10032
  const accepts = (e) => e.dataTransfer.types.includes(MIME_TOOL) || e.dataTransfer.types.includes(MIME_FIELD) || e.dataTransfer.types.includes(MIME_PART);
9956
10033
  const onDrop = (e) => {
@@ -9996,8 +10073,9 @@ function ItemView({ item, scale, drag, setDrag, bw, nest, section }) {
9996
10073
  const selected = useDesigner((s) => s.sel.kind === "items" && s.sel.ids.includes(item.id));
9997
10074
  const single = useDesigner((s) => s.sel.kind === "items" && s.sel.ids.length === 1);
9998
10075
  const onDown = useItemDrag(item, scale, setDrag);
10076
+ const keys = useItemKeys(item);
9999
10077
  const r = rectOf(item, drag);
10000
- const problems = useContext2(IssueMap).get(item.id);
10078
+ const problems = useContext3(IssueMap).get(item.id);
10001
10079
  const onHandle = (dir) => (e) => {
10002
10080
  e.preventDefault();
10003
10081
  e.stopPropagation();
@@ -10056,6 +10134,7 @@ function ItemView({ item, scale, drag, setDrag, bw, nest, section }) {
10056
10134
  title: problems?.join("\n"),
10057
10135
  style: { left: r.x * scale, top: r.y * scale, width: Math.max(r.w * scale, 2), height: Math.max(r.h * scale, 2) },
10058
10136
  onPointerDown: onDown,
10137
+ ...keys,
10059
10138
  children: [
10060
10139
  nest ? /* @__PURE__ */ jsx6(NestBox, { item: { ...item, ...r }, scale }) : /* @__PURE__ */ jsx6(ItemBody, { item: { ...item, ...r }, scale }),
10061
10140
  nest && /* @__PURE__ */ jsx6(NestChildren, { item, scale, drag, setDrag, section }),
@@ -10073,8 +10152,8 @@ function NestBox({ item, scale }) {
10073
10152
  }
10074
10153
  var LIVE = /* @__PURE__ */ new Set(["chart", "matrix", "barcode", "sparkline", "databar", "bullet", "iconset", "rangebar", "richtext"]);
10075
10154
  var measurer = null;
10076
- async function paintItemSvg(shape2, def, sample) {
10077
- const store = fontStore();
10155
+ async function paintItemSvg(shape2, def, sample, api = activeStore2()) {
10156
+ const store = await loadFontStore();
10078
10157
  await Promise.all([store.load(), customFonts()]);
10079
10158
  if (shape2.type === "barcode" || hasType(shape2.items, "barcode")) await loadBarcodes();
10080
10159
  measurer || (measurer = new TextMeasurer(store));
@@ -10085,7 +10164,7 @@ async function paintItemSvg(shape2, def, sample) {
10085
10164
  } catch {
10086
10165
  }
10087
10166
  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);
10167
+ const theme3 = themeContext(typeof def.theme === "string" && api.getState().reused[def.theme]?.themeDef || def.themeDef);
10089
10168
  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
10169
  let seq = 0;
10091
10170
  const lc = {
@@ -10127,6 +10206,7 @@ async function paintItemSvg(shape2, def, sample) {
10127
10206
  return { html: pageToSvg({ items }, shape2.w, h, { background: false }), h, w };
10128
10207
  }
10129
10208
  function LivePreview({ item, scale }) {
10209
+ const api = useDesignerStore();
10130
10210
  const sample = useDesigner((s) => s.sample);
10131
10211
  const def = useDesigner((s) => s.def);
10132
10212
  const [svg, setSvg] = useState4(null);
@@ -10136,11 +10216,11 @@ function LivePreview({ item, scale }) {
10136
10216
  let alive = true;
10137
10217
  const t3 = setTimeout(async () => {
10138
10218
  try {
10139
- const out = await paintItemSvg(shape2, def, sample);
10219
+ const out = await paintItemSvg(shape2, def, sample, api);
10140
10220
  if (alive) {
10141
10221
  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 } } });
10222
+ const ex2 = api.getState().extents || {};
10223
+ if (Math.round(ex2[item.id]?.w || 0) !== Math.round(out.w)) api.setState({ extents: { ...ex2, [item.id]: { w: out.w } } });
10144
10224
  }
10145
10225
  } catch (e) {
10146
10226
  if (alive) setSvg({ error: e.message });
@@ -10274,17 +10354,18 @@ function TableView({ item, scale, drag, setDrag }) {
10274
10354
  const readOnly2 = useDesigner((s) => s.readOnly);
10275
10355
  const tableSelected = sel.kind === "items" && sel.ids.includes(item.id);
10276
10356
  const onGrip = useItemDrag(item, scale, setDrag);
10357
+ const keys = useItemKeys(item);
10277
10358
  const r = rectOf(item, drag);
10278
10359
  const widths2 = item.columns.map((c, i2) => drag?.mode === "col" && drag.id === item.id && drag.col === i2 ? drag.w : c.width);
10279
10360
  const [dropCell, setDropCell] = useState4(null);
10280
10361
  const [menu, setMenu] = useState4(null);
10281
- const problems = useContext2(IssueMap).get(item.id);
10282
- const tblRef = useRef2(null);
10362
+ const problems = useContext3(IssueMap).get(item.id);
10363
+ const tblRef = useRef3(null);
10283
10364
  const chosen = sel.kind === "cell" && sel.id === item.id ? selCells(sel) : [];
10284
10365
  useEffect3(() => {
10285
10366
  if (!menu) return void 0;
10286
10367
  const close = (e) => {
10287
- if (e.type === "keydown" ? e.key === "Escape" : !e.target.closest?.(".cell-menu")) setMenu(null);
10368
+ if (e.type === "keydown" ? e.key === "Escape" : !e.composedPath().some((n) => n.classList?.contains("cell-menu"))) setMenu(null);
10288
10369
  };
10289
10370
  window.addEventListener("pointerdown", close, true);
10290
10371
  window.addEventListener("keydown", close);
@@ -10297,6 +10378,7 @@ function TableView({ item, scale, drag, setDrag }) {
10297
10378
  e.stopPropagation();
10298
10379
  if (e.button !== 0) return;
10299
10380
  e.preventDefault();
10381
+ e.currentTarget.closest("[data-item-key]")?.focus({ preventScroll: true });
10300
10382
  const st = useDesigner.getState();
10301
10383
  const here = { part, row: ri, col: ci };
10302
10384
  const cur2 = st.sel.kind === "cell" && st.sel.id === item.id ? st.sel : null;
@@ -10372,7 +10454,7 @@ function TableView({ item, scale, drag, setDrag }) {
10372
10454
  const h = t3.header?.[t3.header.length - 1]?.cells?.[ci];
10373
10455
  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
10456
  if (h && f.type === "number") h.style = { ...h.style || {}, textAlign: "right" };
10375
- } else if ((part === "footer" || /^g\d+f$/.test(part)) && f.type === "number") {
10457
+ } else if ((part === "footer" || /^g\d+[hf]$/.test(part)) && f.type === "number") {
10376
10458
  cell.value = `=Sum(Fields.${f.field})`;
10377
10459
  cell.style = { ...cell.style || {}, ...fieldStyle(f) };
10378
10460
  } else cell.value = `=Fields.${f.field}`;
@@ -10380,7 +10462,7 @@ function TableView({ item, scale, drag, setDrag }) {
10380
10462
  useDesigner.getState().select({ kind: "cell", id: item.id, part, row: ri, col: ci });
10381
10463
  };
10382
10464
  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: [
10465
+ 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
10466
  problems && /* @__PURE__ */ jsx6("div", { className: "issue-tag", title: problems.join("\n"), "aria-label": problems.join(". "), children: "!" }),
10385
10467
  /* @__PURE__ */ jsx6("div", { className: "grip", title: "Select or move the table", onPointerDown: onGrip, children: "⠿" }),
10386
10468
  /* @__PURE__ */ jsx6("div", { className: "col-handles", "aria-label": T("ux_columns"), role: "group", children: widths2.map((w, ci) => /* @__PURE__ */ jsx6(
@@ -10510,13 +10592,13 @@ function TableView({ item, scale, drag, setDrag }) {
10510
10592
  }
10511
10593
 
10512
10594
  // src/designer/Inspector.jsx
10513
- import { Fragment as Fragment5, useEffect as useEffect5, useLayoutEffect as useLayoutEffect2, useRef as useRef5, useState as useState7 } from "react";
10595
+ import { Fragment as Fragment5, useEffect as useEffect5, useLayoutEffect as useLayoutEffect2, useRef as useRef6, useState as useState7 } from "react";
10514
10596
 
10515
10597
  // src/designer/ExpressionEditor.jsx
10516
- import { useMemo as useMemo2, useRef as useRef4, useState as useState5 } from "react";
10598
+ import { useMemo as useMemo2, useRef as useRef5, useState as useState5 } from "react";
10517
10599
 
10518
10600
  // src/designer/ExprCode.jsx
10519
- import { forwardRef, useEffect as useEffect4, useImperativeHandle, useRef as useRef3 } from "react";
10601
+ import { forwardRef, useEffect as useEffect4, useImperativeHandle, useRef as useRef4 } from "react";
10520
10602
 
10521
10603
  // node_modules/@marijn/find-cluster-break/src/index.js
10522
10604
  var rangeFrom = [];
@@ -12260,8 +12342,8 @@ var StateField = class _StateField {
12260
12342
  way it is initialized. Can be useful when you need to provide a
12261
12343
  non-default starting value for the field.
12262
12344
  */
12263
- init(create2) {
12264
- return [this, initField.of({ field: this, create: create2 })];
12345
+ init(create) {
12346
+ return [this, initField.of({ field: this, create })];
12265
12347
  }
12266
12348
  /**
12267
12349
  State field instances can be used as
@@ -13489,10 +13571,10 @@ var RangeSet = class _RangeSet {
13489
13571
  for (; ; ) {
13490
13572
  let curTo = Math.min(cursor.to, to);
13491
13573
  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);
13574
+ let active2 = cursor.activeForPoint(cursor.to);
13575
+ let openCount = cursor.pointFrom < from ? active2.length + 1 : cursor.point.startSide < 0 ? active2.length : Math.min(active2.length, openRanges);
13576
+ iterator.point(pos, curTo, cursor.point, active2, openCount, cursor.pointRank);
13577
+ openRanges = Math.min(cursor.openEnd(curTo), active2.length);
13496
13578
  } else if (curTo > pos) {
13497
13579
  iterator.span(pos, curTo, cursor.active, openRanges);
13498
13580
  openRanges = cursor.openEnd(curTo);
@@ -13906,14 +13988,14 @@ var SpanCursor = class {
13906
13988
  activeForPoint(to) {
13907
13989
  if (!this.active.length)
13908
13990
  return this.active;
13909
- let active = [];
13991
+ let active2 = [];
13910
13992
  for (let i2 = this.active.length - 1; i2 >= 0; i2--) {
13911
13993
  if (this.activeRank[i2] < this.pointRank)
13912
13994
  break;
13913
13995
  if (this.activeTo[i2] > to || this.activeTo[i2] == to && this.active[i2].endSide >= this.point.endSide)
13914
- active.push(this.active[i2]);
13996
+ active2.push(this.active[i2]);
13915
13997
  }
13916
- return active.reverse();
13998
+ return active2.reverse();
13917
13999
  }
13918
14000
  openEnd(to) {
13919
14001
  let open = 0;
@@ -15432,9 +15514,9 @@ var viewPlugin = /* @__PURE__ */ Facet.define({
15432
15514
  }
15433
15515
  });
15434
15516
  var ViewPlugin = class _ViewPlugin {
15435
- constructor(id, create2, domEventHandlers, domEventObservers, buildExtensions) {
15517
+ constructor(id, create, domEventHandlers, domEventObservers, buildExtensions) {
15436
15518
  this.id = id;
15437
- this.create = create2;
15519
+ this.create = create;
15438
15520
  this.domEventHandlers = domEventHandlers;
15439
15521
  this.domEventObservers = domEventObservers;
15440
15522
  this.baseExtensions = buildExtensions(this);
@@ -15450,9 +15532,9 @@ var ViewPlugin = class _ViewPlugin {
15450
15532
  Define a plugin from a constructor function that creates the
15451
15533
  plugin's value, given an editor view.
15452
15534
  */
15453
- static define(create2, spec) {
15535
+ static define(create, spec) {
15454
15536
  const { eventHandlers, eventObservers, provide, decorations: deco } = spec || {};
15455
- return new _ViewPlugin(nextPluginID++, create2, eventHandlers, eventObservers, (plugin) => {
15537
+ return new _ViewPlugin(nextPluginID++, create, eventHandlers, eventObservers, (plugin) => {
15456
15538
  let ext = [];
15457
15539
  if (deco)
15458
15540
  ext.push(decorations.of((view) => {
@@ -15540,11 +15622,11 @@ function getIsolatedRanges(view, line2) {
15540
15622
  RangeSet.spans(sets, line2.from, line2.to, {
15541
15623
  point() {
15542
15624
  },
15543
- span(fromDoc, toDoc, active, open) {
15625
+ span(fromDoc, toDoc, active2, open) {
15544
15626
  let from = fromDoc - line2.from, to = toDoc - line2.from;
15545
15627
  let level = result;
15546
- for (let i2 = active.length - 1; i2 >= 0; i2--, open--) {
15547
- let direction = active[i2].spec.bidiIsolate, update;
15628
+ for (let i2 = active2.length - 1; i2 >= 0; i2--, open--) {
15629
+ let direction = active2[i2].spec.bidiIsolate, update;
15548
15630
  if (direction == null)
15549
15631
  direction = autoDirection(line2.text, from, to);
15550
15632
  if (open > 0 && level.length && (update = level[level.length - 1]).to == from && update.direction == direction) {
@@ -16774,7 +16856,7 @@ var TileUpdate = class {
16774
16856
  let pendingLineAttrs = null;
16775
16857
  let b = this.builder, markCount = -1;
16776
16858
  let openEnd = RangeSet.spans(this.decorations, from, to, {
16777
- point: (from2, to2, deco, active, openStart, index) => {
16859
+ point: (from2, to2, deco, active2, openStart, index) => {
16778
16860
  if (deco instanceof PointDecoration) {
16779
16861
  if (this.disallowBlockEffectsFor[index]) {
16780
16862
  if (deco.block)
@@ -16782,8 +16864,8 @@ var TileUpdate = class {
16782
16864
  if (to2 > this.view.state.doc.lineAt(from2).to)
16783
16865
  throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
16784
16866
  }
16785
- markCount = active.length;
16786
- if (openStart > active.length) {
16867
+ markCount = active2.length;
16868
+ if (openStart > active2.length) {
16787
16869
  b.continueWidget(to2 - from2);
16788
16870
  } else {
16789
16871
  let widget = deco.widget || (deco.block ? NullWidget.block : NullWidget.inline);
@@ -16795,7 +16877,7 @@ var TileUpdate = class {
16795
16877
  b.addBlockWidget(tile);
16796
16878
  } else {
16797
16879
  b.ensureLine(pendingLineAttrs);
16798
- b.addInlineWidget(tile, active, openStart);
16880
+ b.addInlineWidget(tile, active2, openStart);
16799
16881
  }
16800
16882
  }
16801
16883
  pendingLineAttrs = null;
@@ -16805,7 +16887,7 @@ var TileUpdate = class {
16805
16887
  if (to2 > from2)
16806
16888
  this.text.skip(to2 - from2);
16807
16889
  },
16808
- span: (from2, to2, active, openStart) => {
16890
+ span: (from2, to2, active2, openStart) => {
16809
16891
  for (let pos = from2; pos < to2; ) {
16810
16892
  let chars = this.text.next(Math.min(512, to2 - pos));
16811
16893
  if (chars == null) {
@@ -16814,12 +16896,12 @@ var TileUpdate = class {
16814
16896
  pos++;
16815
16897
  } else {
16816
16898
  b.ensureLine(pendingLineAttrs);
16817
- b.addText(chars, active, pos == from2 ? openStart : active.length);
16899
+ b.addText(chars, active2, pos == from2 ? openStart : active2.length);
16818
16900
  pos += chars.length;
16819
16901
  }
16820
16902
  pendingLineAttrs = null;
16821
16903
  }
16822
- markCount = active.length;
16904
+ markCount = active2.length;
16823
16905
  }
16824
16906
  });
16825
16907
  if (markCount > -1)
@@ -18808,9 +18890,9 @@ handlers.mousedown = (view, event) => {
18808
18890
  if (mustFocus)
18809
18891
  view.observer.ignore(() => {
18810
18892
  focusPreventScroll(view.contentDOM);
18811
- let active = view.root.activeElement;
18812
- if (active && !active.contains(view.contentDOM))
18813
- active.blur();
18893
+ let active2 = view.root.activeElement;
18894
+ if (active2 && !active2.contains(view.contentDOM))
18895
+ active2.blur();
18814
18896
  });
18815
18897
  let mouseSel = view.inputState.mouseSelection;
18816
18898
  if (mouseSel) {
@@ -28853,7 +28935,7 @@ function scrollIntoView2(container2, element) {
28853
28935
  function score(option) {
28854
28936
  return (option.boost || 0) * 100 + (option.apply ? 10 : 0) + (option.info ? 5 : 0) + (option.type ? 1 : 0);
28855
28937
  }
28856
- function sortOptions(active, state) {
28938
+ function sortOptions(active2, state) {
28857
28939
  let options = [];
28858
28940
  let sections = null, dynamicSectionScore = null;
28859
28941
  let addOption = (option) => {
@@ -28868,7 +28950,7 @@ function sortOptions(active, state) {
28868
28950
  }
28869
28951
  };
28870
28952
  let conf = state.facet(completionConfig);
28871
- for (let a of active)
28953
+ for (let a of active2)
28872
28954
  if (a.hasResult()) {
28873
28955
  let getMatch = a.result.getMatch;
28874
28956
  if (a.result.filter === false) {
@@ -28931,12 +29013,12 @@ var CompletionDialog = class _CompletionDialog {
28931
29013
  setSelected(selected, id) {
28932
29014
  return selected == this.selected || selected >= this.options.length ? this : new _CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected, this.disabled);
28933
29015
  }
28934
- static build(active, state, id, prev, conf, didSetActive) {
28935
- if (prev && !didSetActive && active.some((s) => s.isPending))
29016
+ static build(active2, state, id, prev, conf, didSetActive) {
29017
+ if (prev && !didSetActive && active2.some((s) => s.isPending))
28936
29018
  return prev.setDisabled();
28937
- let options = sortOptions(active, state);
29019
+ let options = sortOptions(active2, state);
28938
29020
  if (!options.length)
28939
- return prev && active.some((a) => a.isPending) ? prev.setDisabled() : null;
29021
+ return prev && active2.some((a) => a.isPending) ? prev.setDisabled() : null;
28940
29022
  let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1;
28941
29023
  if (prev && prev.selected != selected && prev.selected != -1) {
28942
29024
  let selectedValue = prev.options[prev.selected].completion;
@@ -28947,7 +29029,7 @@ var CompletionDialog = class _CompletionDialog {
28947
29029
  }
28948
29030
  }
28949
29031
  return new _CompletionDialog(options, makeAttrs(id, selected), {
28950
- pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
29032
+ pos: active2.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
28951
29033
  create: createTooltip,
28952
29034
  above: conf.aboveCursor
28953
29035
  }, prev ? prev.timestamp : Date.now(), selected, false);
@@ -28960,8 +29042,8 @@ var CompletionDialog = class _CompletionDialog {
28960
29042
  }
28961
29043
  };
28962
29044
  var CompletionState = class _CompletionState {
28963
- constructor(active, id, open) {
28964
- this.active = active;
29045
+ constructor(active2, id, open) {
29046
+ this.active = active2;
28965
29047
  this.id = id;
28966
29048
  this.open = open;
28967
29049
  }
@@ -28971,7 +29053,7 @@ var CompletionState = class _CompletionState {
28971
29053
  update(tr) {
28972
29054
  let { state } = tr, conf = state.facet(completionConfig);
28973
29055
  let sources = conf.override || state.languageDataAt("autocomplete", cur(state)).map(asSource);
28974
- let active = sources.map((source) => {
29056
+ let active2 = sources.map((source) => {
28975
29057
  let value = this.active.find((s) => s.source == source) || new ActiveSource(
28976
29058
  source,
28977
29059
  this.active.some(
@@ -28982,17 +29064,17 @@ var CompletionState = class _CompletionState {
28982
29064
  );
28983
29065
  return value.update(tr, conf);
28984
29066
  });
28985
- if (active.length == this.active.length && active.every((a, i2) => a == this.active[i2]))
28986
- active = this.active;
29067
+ if (active2.length == this.active.length && active2.every((a, i2) => a == this.active[i2]))
29068
+ active2 = this.active;
28987
29069
  let open = this.open, didSet = tr.effects.some((e) => e.is(setActiveEffect));
28988
29070
  if (open && tr.docChanged)
28989
29071
  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))
29072
+ if (tr.selection || active2.some((a) => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) || !sameResults(active2, this.active) || didSet)
29073
+ open = CompletionDialog.build(active2, state, this.id, open, conf, didSet);
29074
+ else if (open && open.disabled && !active2.some((a) => a.isPending))
28993
29075
  open = null;
28994
- if (!open && active.every((a) => !a.isPending) && active.some((a) => a.hasResult()))
28995
- active = active.map((a) => a.hasResult() ? new ActiveSource(
29076
+ if (!open && active2.every((a) => !a.isPending) && active2.some((a) => a.hasResult()))
29077
+ active2 = active2.map((a) => a.hasResult() ? new ActiveSource(
28996
29078
  a.source,
28997
29079
  0
28998
29080
  /* State.Inactive */
@@ -29000,7 +29082,7 @@ var CompletionState = class _CompletionState {
29000
29082
  for (let effect of tr.effects)
29001
29083
  if (effect.is(setSelectedEffect))
29002
29084
  open = open && open.setSelected(effect.value, this.id);
29003
- return active == this.active && open == this.open ? this : new _CompletionState(active, this.id, open);
29085
+ return active2 == this.active && open == this.open ? this : new _CompletionState(active2, this.id, open);
29004
29086
  }
29005
29087
  get tooltip() {
29006
29088
  return this.open ? this.open.tooltip : null;
@@ -29085,9 +29167,9 @@ var ActiveSource = class _ActiveSource {
29085
29167
  /* State.Inactive */
29086
29168
  );
29087
29169
  else if (effect.is(setActiveEffect)) {
29088
- for (let active of effect.value)
29089
- if (active.source == value.source)
29090
- value = active;
29170
+ for (let active2 of effect.value)
29171
+ if (active2.source == value.source)
29172
+ value = active2;
29091
29173
  }
29092
29174
  }
29093
29175
  return value;
@@ -29231,8 +29313,8 @@ var closeCompletion = (view) => {
29231
29313
  return true;
29232
29314
  };
29233
29315
  var RunningQuery = class {
29234
- constructor(active, context) {
29235
- this.active = active;
29316
+ constructor(active2, context) {
29317
+ this.active = active2;
29236
29318
  this.context = context;
29237
29319
  this.time = Date.now();
29238
29320
  this.updates = [];
@@ -29249,9 +29331,9 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29249
29331
  this.debounceAccept = -1;
29250
29332
  this.pendingStart = false;
29251
29333
  this.composing = 0;
29252
- for (let active of view.state.field(completionState).active)
29253
- if (active.isPending)
29254
- this.startQuery(active);
29334
+ for (let active2 of view.state.field(completionState).active)
29335
+ if (active2.isPending)
29336
+ this.startQuery(active2);
29255
29337
  }
29256
29338
  update(update) {
29257
29339
  let cState = update.state.field(completionState);
@@ -29296,19 +29378,19 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29296
29378
  this.debounceUpdate = -1;
29297
29379
  this.pendingStart = false;
29298
29380
  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);
29381
+ for (let active2 of cState.active) {
29382
+ if (active2.isPending && !this.running.some((r) => r.active.source == active2.source))
29383
+ this.startQuery(active2);
29302
29384
  }
29303
29385
  if (this.running.length && cState.open && cState.open.disabled)
29304
29386
  this.debounceAccept = setTimeout(() => this.accept(), this.view.state.facet(completionConfig).updateSyncTime);
29305
29387
  }
29306
- startQuery(active) {
29388
+ startQuery(active2) {
29307
29389
  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);
29390
+ let context = new CompletionContext(state, pos, active2.explicit, this.view);
29391
+ let pending2 = new RunningQuery(active2, context);
29310
29392
  this.running.push(pending2);
29311
- Promise.resolve(active.source(context)).then((result) => {
29393
+ Promise.resolve(active2.source(context)).then((result) => {
29312
29394
  if (!pending2.context.aborted) {
29313
29395
  pending2.done = result || null;
29314
29396
  this.scheduleAccept();
@@ -29341,26 +29423,26 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29341
29423
  if (query.done) {
29342
29424
  let pos = cur(query.updates.length ? query.updates[0].startState : this.view.state);
29343
29425
  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);
29426
+ 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
29427
  for (let tr of query.updates)
29346
- active = active.update(tr, conf);
29347
- if (active.hasResult()) {
29348
- updated.push(active);
29428
+ active2 = active2.update(tr, conf);
29429
+ if (active2.hasResult()) {
29430
+ updated.push(active2);
29349
29431
  continue;
29350
29432
  }
29351
29433
  }
29352
29434
  let current2 = cState.active.find((a) => a.source == query.active.source);
29353
29435
  if (current2 && current2.isPending) {
29354
29436
  if (query.done == null) {
29355
- let active = new ActiveSource(
29437
+ let active2 = new ActiveSource(
29356
29438
  query.active.source,
29357
29439
  0
29358
29440
  /* State.Inactive */
29359
29441
  );
29360
29442
  for (let tr of query.updates)
29361
- active = active.update(tr, conf);
29362
- if (!active.isPending)
29363
- updated.push(active);
29443
+ active2 = active2.update(tr, conf);
29444
+ if (!active2.isPending)
29445
+ updated.push(active2);
29364
29446
  } else {
29365
29447
  this.startQuery(current2);
29366
29448
  }
@@ -29818,9 +29900,9 @@ var theme2 = EditorView.theme({
29818
29900
  });
29819
29901
  var UNKNOWN = Decoration.mark({ class: "cm-unknown-field" });
29820
29902
  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 });
29903
+ const host = useRef4(null);
29904
+ const view = useRef4(null);
29905
+ const latest2 = useRef4({ onChange, fields, parameters, check });
29824
29906
  latest2.current = { onChange, fields, parameters, check };
29825
29907
  useImperativeHandle(ref, () => ({
29826
29908
  insert(text) {
@@ -29926,7 +30008,7 @@ function ExpressionEditor({ value, dataSet, onSave, onClose, title }) {
29926
30008
  const def = useDesigner((s) => s.def);
29927
30009
  const sample = useDesigner((s) => s.sample);
29928
30010
  const [text, setText] = useState5(value ?? "");
29929
- const ta = useRef4(null);
30011
+ const ta = useRef5(null);
29930
30012
  const dsName = dataSet || def.dataSets?.[0]?.name;
29931
30013
  const ds = def.dataSets?.find((d) => d.name === dsName);
29932
30014
  const fields = fieldNames(ds).filter((n) => !(ds?.fields || []).some((f) => f.name === n && f.type === "object"));
@@ -30235,7 +30317,7 @@ function Inspector() {
30235
30317
  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
30318
  const scope = one ? one.dataSet || def.dataSets?.[0]?.name || null : void 0;
30237
30319
  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);
30320
+ const ref = useRef6(null);
30239
30321
  useLayoutEffect2(() => {
30240
30322
  const pane = ref.current?.closest(".dright");
30241
30323
  if (pane) pane.scrollTop = 0;
@@ -30264,9 +30346,9 @@ function Inspector() {
30264
30346
  expr && /* @__PURE__ */ jsx10(ExpressionEditor, { ...expr, onClose: () => setExpr(null) })
30265
30347
  ] });
30266
30348
  }
30267
- function Geo({ label, value, onChange }) {
30349
+ function Geo({ label, value, onChange, min }) {
30268
30350
  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))) }) });
30351
+ 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
30352
  }
30271
30353
  function PropEditor({ p: spec, value, onChange, openExpr, dataSet, item }) {
30272
30354
  const T = useT3();
@@ -30369,17 +30451,18 @@ function PaletteEditor({ label, value, onChange }) {
30369
30451
  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
30452
  ] });
30371
30453
  }
30372
- var reportList = null;
30454
+ var reportLists = /* @__PURE__ */ new Map();
30373
30455
  function ReportPicker({ value, onChange }) {
30374
- const [list2, setList] = useState7(reportList || []);
30456
+ const [list2, setList] = useState7(() => reportLists.get(useDesigner.getState().embed?.server || "") || []);
30375
30457
  const listId = useState7(() => `reports-${Math.random().toString(36).slice(2, 8)}`)[0];
30376
30458
  useEffect5(() => {
30377
30459
  const embed = useDesigner.getState().embed;
30378
- if (reportList || embed && !embed.server) return;
30379
30460
  const server2 = embed?.server || "";
30461
+ if (reportLists.has(server2) || embed && !embed.server) return;
30380
30462
  fetch(`${server2}/api/reports`).then((r) => r.ok ? r.json() : []).then((l) => {
30381
- reportList = Array.isArray(l) ? l : [];
30382
- setList(reportList);
30463
+ const v = Array.isArray(l) ? l : [];
30464
+ reportLists.set(server2, v);
30465
+ setList(v);
30383
30466
  }).catch(() => {
30384
30467
  });
30385
30468
  }, []);
@@ -30465,8 +30548,8 @@ function ItemProps({ item, section, openExpr }) {
30465
30548
  /* @__PURE__ */ jsxs7("div", { className: "grid2", children: [
30466
30549
  /* @__PURE__ */ jsx10(Geo, { label: "X", value: item.x, onChange: (v) => setGeo("x", Math.max(0, v)) }),
30467
30550
  /* @__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)) }),
30551
+ 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)) }),
30552
+ 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
30553
  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
30554
  ] }),
30472
30555
  /* @__PURE__ */ jsx10("div", { className: "hint", children: (() => {
@@ -30636,7 +30719,17 @@ function PivotEditor({ item, openExpr }) {
30636
30719
  /* @__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
30720
  ] })
30638
30721
  ] }),
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) }),
30722
+ (i2 < spec[list2].length - 1 || list2 === "rowGroups" && g.parent) && /* @__PURE__ */ jsx10(Check, { label: T("pivotCollapsible"), checked: g.collapsible, onChange: (v) => edit((it) => {
30723
+ const o = it[list2][i2];
30724
+ if (v) {
30725
+ o.collapsible = true;
30726
+ o.initiallyCollapsed = true;
30727
+ } else {
30728
+ delete o.collapsible;
30729
+ delete o.initiallyCollapsed;
30730
+ }
30731
+ }, `${item.id}.${list2}${i2}.collapsible`) }),
30732
+ " ",
30640
30733
  g.collapsible && /* @__PURE__ */ jsx10(Check, { label: T("pivotStartCollapsed"), checked: g.initiallyCollapsed, onChange: (v) => setK(list2, i2, "initiallyCollapsed", v) }),
30641
30734
  /* @__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
30735
  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 +30755,7 @@ function PivotEditor({ item, openExpr }) {
30662
30755
  /* @__PURE__ */ jsxs7("div", { className: "grid2", children: [
30663
30756
  /* @__PURE__ */ jsx10(Field, { label: T("pivotLabel"), children: /* @__PURE__ */ jsx10(TextInput, { value: v.label || "", onChange: (x) => setK("values", i2, "label", x) }) }),
30664
30757
  /* @__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) }) })
30758
+ /* @__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
30759
  ] }),
30667
30760
  /* @__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
30761
  /* @__PURE__ */ jsx10(Field, { label: T("cellBookmark"), children: exprField("values", i2, "bookmark", v.bookmark, T("cellBookmark")) })
@@ -31011,14 +31104,16 @@ function VisualEditor({ cell, setCell, openExpr, dataSet }) {
31011
31104
  }
31012
31105
  var reportParams = /* @__PURE__ */ new Map();
31013
31106
  function useReportParams(id) {
31014
- const [list2, setList] = useState7(() => reportParams.get(id) ?? null);
31107
+ const srv = () => useDesigner.getState().embed?.server || "";
31108
+ const [list2, setList] = useState7(() => reportParams.get(`${srv()} ${id}`) ?? null);
31015
31109
  useEffect5(() => {
31016
31110
  if (!id || isDynamic(id)) {
31017
31111
  setList(null);
31018
31112
  return;
31019
31113
  }
31020
- if (reportParams.has(id)) {
31021
- setList(reportParams.get(id));
31114
+ const key2 = `${srv()} ${id}`;
31115
+ if (reportParams.has(key2)) {
31116
+ setList(reportParams.get(key2));
31022
31117
  return;
31023
31118
  }
31024
31119
  let alive = true;
@@ -31031,7 +31126,7 @@ function useReportParams(id) {
31031
31126
  fetch(`${server2}/api/reports/${encodeURIComponent(id)}`).then((r) => r.ok ? r.json() : null).then((r) => {
31032
31127
  const d = r?.definition || r;
31033
31128
  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);
31129
+ if (ps) reportParams.set(key2, ps);
31035
31130
  if (alive) setList(ps);
31036
31131
  }).catch(() => {
31037
31132
  if (alive) setList(null);
@@ -32159,17 +32254,18 @@ function JoinAdder({ allCols, split, onAdd, T }) {
32159
32254
  import { Fragment as Fragment8, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
32160
32255
  var NAME2 = /^[A-Za-z_][\w]*$/;
32161
32256
  var noSourceKey = (def) => (def?.dataSources || []).length ? null : "r4_noDataSource";
32162
- async function loadSample() {
32163
- const { def } = useDesigner.getState();
32164
- useDesigner.setState({ sample: { loading: true } });
32257
+ async function loadSample(store) {
32258
+ const api = store?.getState ? store : activeStore();
32259
+ const { def } = api.getState();
32260
+ api.setState({ sample: { loading: true } });
32165
32261
  try {
32166
32262
  const params = resolveParameters(def, {});
32167
32263
  const sources = await loadSources(def, { params, baseUrl: origin(), sqlPreview: true, fetch: reportFetch(origin(), void 0, { sqlPreview: true }) });
32168
32264
  const ctx = { params, globals: { ExecutionTime: /* @__PURE__ */ new Date() }, dataSets: {}, fields: null, locale: def.locale, currency: def.currency, functions: functionTable(def) };
32169
32265
  const dataSets = buildDataSets(def, sources, ctx);
32170
- useDesigner.setState({ sample: { dataSets, sources, at: Date.now() } });
32266
+ api.setState({ sample: { dataSets, sources, at: Date.now() } });
32171
32267
  } catch (e) {
32172
- useDesigner.setState({ sample: { error: e.message } });
32268
+ api.setState({ sample: { error: e.message } });
32173
32269
  }
32174
32270
  }
32175
32271
  function DataPanel() {
@@ -32990,7 +33086,7 @@ function DataSetDialog({ index, onClose, onSaved }) {
32990
33086
  }
32991
33087
 
32992
33088
  // src/designer/Outline.jsx
32993
- import { useRef as useRef6, useState as useState11 } from "react";
33089
+ import { useRef as useRef7, useState as useState11 } from "react";
32994
33090
  import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
32995
33091
  var MIME = "application/x-pw-outline";
32996
33092
  function Outline() {
@@ -33001,9 +33097,30 @@ function Outline() {
33001
33097
  const T = (k, v) => t(lang2, k, v);
33002
33098
  const [drop, setDrop] = useState11(null);
33003
33099
  const [said, setSaid] = useState11("");
33004
- const dragged = useRef6(null);
33005
- const body = useRef6(null);
33100
+ const [cur2, setCur] = useState11(null);
33101
+ const dragged = useRef7(null);
33102
+ const body = useRef7(null);
33006
33103
  const chosen = new Set(sel.kind === "items" ? sel.ids : sel.kind === "cell" ? [sel.id] : []);
33104
+ const keys = sectionList(def).flatMap(({ key: key2 }) => {
33105
+ const out = [`band:${key2}`];
33106
+ const go = (l) => l.forEach((it) => {
33107
+ out.push(it.id);
33108
+ if (NESTING.has(it.type)) go(it.items || []);
33109
+ });
33110
+ go(secOf(def, key2)?.items || []);
33111
+ return out;
33112
+ });
33113
+ const stop = keys.includes(cur2) ? cur2 : keys.find((k) => chosen.has(k) || sel.kind === "section" && k === `band:${sel.section}`) || keys[0];
33114
+ const roving = (k) => ({ tabIndex: k === stop ? 0 : -1, onFocus: () => setCur(k) });
33115
+ const nav2 = (e) => {
33116
+ if (e.defaultPrevented || e.altKey || e.metaKey || e.ctrlKey || e.target.getAttribute("role") !== "option") return;
33117
+ const all = [...e.currentTarget.querySelectorAll("[role=option]")];
33118
+ const i2 = all.indexOf(e.target);
33119
+ const j = e.key === "ArrowDown" ? i2 + 1 : e.key === "ArrowUp" ? i2 - 1 : e.key === "Home" ? 0 : e.key === "End" ? all.length - 1 : null;
33120
+ if (j == null) return;
33121
+ e.preventDefault();
33122
+ all[Math.max(0, Math.min(all.length - 1, j))]?.focus();
33123
+ };
33007
33124
  const pick = (e, id) => {
33008
33125
  const st = useDesigner.getState();
33009
33126
  if (e.shiftKey && st.sel.kind === "items") {
@@ -33115,30 +33232,32 @@ function Outline() {
33115
33232
  };
33116
33233
  const rows = (list2, parent, depth, section) => list2.map((it, i2) => {
33117
33234
  const mark = drop && drop.id != null && drop.id === it.id ? ` drop-${drop.where}` : "";
33118
- return /* @__PURE__ */ jsxs11("li", { children: [
33235
+ return /* @__PURE__ */ jsxs11("li", { role: "none", children: [
33119
33236
  /* @__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
33237
  !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 }),
33238
+ /* @__PURE__ */ jsx14("button", { type: "button", role: "option", className: "linklike nm", onClick: (e) => pick(e, it.id), onKeyDown: (e) => onKey(e, it, list2, i2, parent), "aria-selected": chosen.has(it.id), "aria-describedby": readOnly2 ? "outline-nav" : "outline-nav outline-keys", ...roving(it.id), children: it.name }),
33122
33239
  /* @__PURE__ */ jsx14("span", { className: "ty", children: T(`item_${it.type}`) === `item_${it.type}` ? ITEMS[it.type]?.label || it.type : T(`item_${it.type}`) }),
33123
33240
  !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: "⇱" })
33241
+ /* @__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: "↑" }),
33242
+ /* @__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: "↓" }),
33243
+ 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
33244
  ] })
33128
33245
  ] }),
33129
- NESTING.has(it.type) && (it.items || []).length > 0 && /* @__PURE__ */ jsx14("ul", { className: "tree", children: rows(it.items, it, depth + 1, section) })
33246
+ NESTING.has(it.type) && (it.items || []).length > 0 && /* @__PURE__ */ jsx14("ul", { className: "tree", role: "none", children: rows(it.items, it, depth + 1, section) })
33130
33247
  ] }, it.id);
33131
33248
  });
33132
33249
  return /* @__PURE__ */ jsxs11("div", { className: "pane", "data-testid": "outline", children: [
33133
33250
  /* @__PURE__ */ jsx14("h4", { children: T("outline") }),
33134
33251
  /* @__PURE__ */ jsxs11("div", { className: "pane-body", ref: body, children: [
33135
- sectionList(def).map(({ key: key2, label }) => {
33252
+ /* @__PURE__ */ jsx14("div", { role: "listbox", "aria-label": T("outline"), "aria-multiselectable": "true", onKeyDown: nav2, children: sectionList(def).map(({ key: key2, label }) => {
33136
33253
  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") }) })
33254
+ return /* @__PURE__ */ jsxs11("div", { role: "group", "aria-label": label, className: `outline-sec${drop?.band === key2 ? " drop-band" : ""}`, "data-outline-band": key2, ...bandDrop(key2), children: [
33255
+ /* @__PURE__ */ jsx14("button", { type: "button", role: "option", "aria-selected": sel.kind === "section" && sel.section === key2, "aria-describedby": "outline-nav", className: `linklike outline-band${sel.kind === "section" && sel.section === key2 ? " sel" : ""}`, onClick: () => useDesigner.getState().select({ kind: "section", section: key2 }), ...roving(`band:${key2}`), children: /* @__PURE__ */ jsx14(
33256
+ "b", { children: label }) }),
33257
+ /* @__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
33258
  ] }, key2);
33141
- }),
33259
+ }) }),
33260
+ /* @__PURE__ */ jsx14("div", { className: "sr-only", id: "outline-nav", children: T("b9_outlineKeys") }),
33142
33261
  /* @__PURE__ */ jsx14("div", { className: "hint", children: T("outlineHint") }),
33143
33262
  !readOnly2 && /* @__PURE__ */ jsx14("div", { className: "hint", id: "outline-keys", children: T("outlineKeys") }),
33144
33263
  /* @__PURE__ */ jsx14("div", { className: "sr-only", role: "status", "aria-live": "polite", children: said })
@@ -33563,6 +33682,7 @@ function TableWizard() {
33563
33682
  const wiz = useDesigner((s) => s.tableWizard);
33564
33683
  const def = useDesigner((s) => s.def);
33565
33684
  const sample = useDesigner((s) => s.sample);
33685
+ const lang2 = useDesigner((s) => s.lang);
33566
33686
  const close = () => useDesigner.getState().setUi({ tableWizard: null });
33567
33687
  const parent = wiz?.parentId ? findItem(def, wiz.parentId)?.item : null;
33568
33688
  const width = Math.max(120, Math.round((parent ? parent.w : bodyWidth(def, wiz?.section || "body")) - (wiz?.x || 0)));
@@ -33629,7 +33749,7 @@ function TableWizard() {
33629
33749
  /* @__PURE__ */ jsxs14("button", { className: "btn ghost", onClick: () => {
33630
33750
  useDesigner.getState().setUi({ tableWizard: null, pivotWizard: { section: wiz.section, x: wiz.x, y: wiz.y, parentId: wiz.parentId, dataSet: c.dataSet } });
33631
33751
  }, "data-testid": "open-pivot-wizard", children: [
33632
- t(useDesigner.getState().lang, "pivotWizard"),
33752
+ t(lang2, "pivotWizard"),
33633
33753
  "…"
33634
33754
  ] }),
33635
33755
  /* @__PURE__ */ jsx17("button", { className: "btn", onClick: close, children: "Cancel" }),
@@ -33642,7 +33762,7 @@ function TableWizard() {
33642
33762
  /* @__PURE__ */ jsxs14("section", { className: "cw-side", "aria-label": "Data for the table", children: [
33643
33763
  /* @__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
33764
  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)) }),
33765
+ noSourceKey(def) && /* @__PURE__ */ jsx17("span", { className: "hint", role: "status", "data-testid": "no-source", children: t(lang2, noSourceKey(def)) }),
33646
33766
  sample?.error && /* @__PURE__ */ jsx17("span", { className: "err", children: sample.error }),
33647
33767
  c.layout !== "matrix" && /* @__PURE__ */ jsxs14(Fragment10, { children: [
33648
33768
  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 +33824,7 @@ function AskAi({ onClose }) {
33704
33824
  let preview = null;
33705
33825
  try {
33706
33826
  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()) });
33827
+ 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
33828
  preview = { html: pageToSvg(model.pages[0], model.width, model.height), pages: model.pages.length };
33709
33829
  } catch (e) {
33710
33830
  preview = { error: e.message };
@@ -34176,9 +34296,10 @@ var TOOLS = [
34176
34296
  ] }) }
34177
34297
  ];
34178
34298
  function Toolbox({ T, hide = [] }) {
34299
+ const api = useDesignerStore();
34179
34300
  const name2 = (type) => T(`item_${type}`) === `item_${type}` ? ITEMS[type].label : T(`item_${type}`);
34180
34301
  const add = (type) => {
34181
- const s = useDesigner.getState();
34302
+ const s = api.getState();
34182
34303
  const at2 = insertSpot(s.def, s.sel);
34183
34304
  insertItem(type, at2.section, 0, at2.y, {}, at2.parentId);
34184
34305
  };
@@ -34227,12 +34348,15 @@ var TbGroup = ({ label, children }) => /* @__PURE__ */ jsxs17("div", { className
34227
34348
  ] });
34228
34349
  var QUICK = [["textbox", "text"], ["table", "table"], ["chart", "chart"], ["image", "image"]];
34229
34350
  function LeftRail({ T, readOnly: readOnly2, embed }) {
34230
- const body = useRef7(null);
34351
+ const body = useRef8(null);
34231
34352
  const [at2, setAt] = useState17("tools");
34232
34353
  const tabs = [!readOnly2 && ["tools", "b2_toolbox", "tools"], embed?.panels?.data !== false && ["data", "b2_data", "data"], ["outline", "b2_outline", "outline"]].filter(Boolean);
34233
34354
  const go = (id) => {
34234
34355
  const el = body.current?.querySelector(`[data-rail="${id}"]`);
34235
- if (el) body.current.scrollTo({ top: el.offsetTop - body.current.offsetTop, behavior: "smooth" });
34356
+ if (el) {
34357
+ body.current.scrollTo({ top: el.offsetTop - body.current.offsetTop, behavior: "smooth" });
34358
+ (el.querySelector('[role=listbox] [tabindex="0"]') || el.querySelector("button, input, select, textarea"))?.focus({ preventScroll: true });
34359
+ }
34236
34360
  setAt(id);
34237
34361
  };
34238
34362
  const spy = () => {
@@ -34334,6 +34458,7 @@ var framed = () => {
34334
34458
  }
34335
34459
  };
34336
34460
  function useAutosave(id, T, lang2, user) {
34461
+ const api = useDesignerStore();
34337
34462
  const [offer, setOffer] = useState17(null);
34338
34463
  useEffect13(() => {
34339
34464
  if (!id || user == null || framed()) return void 0;
@@ -34345,10 +34470,10 @@ function useAutosave(id, T, lang2, user) {
34345
34470
  }
34346
34471
  clearDrafts(store, user);
34347
34472
  const d = readDraft(store, user, id);
34348
- if (d && plain(mergeDraft(d.def, useDesigner.getState().def)) !== plain(useDesigner.getState().def)) setOffer(d);
34473
+ if (d && plain(mergeDraft(d.def, api.getState().def)) !== plain(api.getState().def)) setOffer(d);
34349
34474
  else if (d) clearDraft(store, user, id);
34350
34475
  const keep = () => {
34351
- const s = useDesigner.getState();
34476
+ const s = api.getState();
34352
34477
  if (!s.saved && !s.readOnly) writeDraft(store, user, id, s.def, Date.now(), s.rev || null);
34353
34478
  };
34354
34479
  const t3 = setInterval(keep, AUTOSAVE_MS);
@@ -34357,7 +34482,7 @@ function useAutosave(id, T, lang2, user) {
34357
34482
  };
34358
34483
  window.addEventListener("pagehide", keep);
34359
34484
  document.addEventListener("visibilitychange", hide);
34360
- const unsub = useDesigner.subscribe((s, prev) => {
34485
+ const unsub = api.subscribe((s, prev) => {
34361
34486
  if (s.saved && !prev.saved) clearDraft(store, user, id);
34362
34487
  });
34363
34488
  return () => {
@@ -34369,13 +34494,13 @@ function useAutosave(id, T, lang2, user) {
34369
34494
  }, [id, user]);
34370
34495
  if (!offer) return null;
34371
34496
  const when = new Date(offer.at).toLocaleString(lang2 === "en" ? "en-IN" : lang2, { dateStyle: "medium", timeStyle: "short" });
34372
- const stale = staleDraft(offer, useDesigner.getState().rev);
34497
+ const stale = staleDraft(offer, api.getState().rev);
34373
34498
  return /* @__PURE__ */ jsxs17("div", { className: "draft-bar", role: "alert", "data-testid": "draft-offer", "data-stale": stale || void 0, children: [
34374
34499
  /* @__PURE__ */ jsx20("span", { children: T(stale ? "ux_draftStale" : "ux_draftFound", { when }) }),
34375
34500
  /* @__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();
34501
+ const d = mergeDraft(offer.def, api.getState().def);
34502
+ api.getState().apply(() => JSON.parse(JSON.stringify(d)));
34503
+ api.getState().fixSelection();
34379
34504
  setOffer(null);
34380
34505
  }, children: T(stale ? "ux_draftRestoreAnyway" : "ux_draftRestore") }),
34381
34506
  /* @__PURE__ */ jsx20("button", { className: "btn sm", "data-testid": "draft-discard", onClick: () => {
@@ -34388,12 +34513,13 @@ function useAutosave(id, T, lang2, user) {
34388
34513
  ] });
34389
34514
  }
34390
34515
  function ConflictBar({ T }) {
34516
+ const api = useDesignerStore();
34391
34517
  const conflict = useDesigner((s) => s.conflict);
34392
34518
  if (!conflict) return null;
34393
34519
  return /* @__PURE__ */ jsxs17("div", { className: "draft-bar", role: "alert", "data-testid": "save-conflict", children: [
34394
34520
  /* @__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") })
34521
+ /* @__PURE__ */ jsx20("button", { className: "btn sm", "data-testid": "conflict-mine", onClick: () => api.getState().save({ overwrite: true }), children: T("ux_conflictMine") }),
34522
+ /* @__PURE__ */ jsx20("button", { className: "btn sm", "data-testid": "conflict-theirs", onClick: () => api.getState().takeTheirs(), children: T("ux_conflictTheirs") })
34397
34523
  ] });
34398
34524
  }
34399
34525
  var AL = (d) => /* @__PURE__ */ jsx20("svg", { width: "16", height: "14", viewBox: "0 0 16 14", "aria-hidden": "true", children: d });
@@ -34458,12 +34584,13 @@ function AlignBar({ T }) {
34458
34584
  ] });
34459
34585
  }
34460
34586
  function IssuesButton({ T }) {
34587
+ const api = useDesignerStore();
34461
34588
  const issues = useDesignIssues();
34462
34589
  const [open, setOpen] = useState17(false);
34463
34590
  useEffect13(() => {
34464
34591
  if (!issues.length) setOpen(false);
34465
34592
  }, [issues.length]);
34466
- const listRef = useRef7(null);
34593
+ const listRef = useRef8(null);
34467
34594
  useLayoutEffect3(() => {
34468
34595
  const el = listRef.current;
34469
34596
  if (!el) return void 0;
@@ -34481,7 +34608,7 @@ function IssuesButton({ T }) {
34481
34608
  return /* @__PURE__ */ jsxs17("span", { className: "issues-wrap", children: [
34482
34609
  /* @__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
34610
  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] });
34611
+ if (i2.id) api.getState().select({ kind: "items", ids: [i2.id] });
34485
34612
  }, children: issueLine(T, i2) }) }, k)) })
34486
34613
  ] });
34487
34614
  }
@@ -34505,6 +34632,7 @@ var SHORTCUTS = [
34505
34632
  ["?", "sc_help"]
34506
34633
  ];
34507
34634
  function HistoryDialog({ id, onClose, T, lang: lang2 }) {
34635
+ const api = useDesignerStore();
34508
34636
  const [list2, setList] = useState17(null);
34509
34637
  const [err, setErr] = useState17(null);
34510
34638
  useEffect13(() => {
@@ -34517,7 +34645,7 @@ function HistoryDialog({ id, onClose, T, lang: lang2 }) {
34517
34645
  return;
34518
34646
  }
34519
34647
  const def = await res.json();
34520
- useDesigner.getState().init(id, def);
34648
+ api.getState().init(id, def);
34521
34649
  onClose();
34522
34650
  };
34523
34651
  return /* @__PURE__ */ jsxs17(Dialog, { title: T("versionHistory"), onClose, footer: /* @__PURE__ */ jsx20("button", { className: "btn", onClick: onClose, children: T("close") }), children: [
@@ -34539,18 +34667,48 @@ function HistoryDialog({ id, onClose, T, lang: lang2 }) {
34539
34667
  ] }, v.version))
34540
34668
  ] });
34541
34669
  }
34542
- function Designer({ id, initial, rev = null, lang: langIn, embed = null, user = null, ai = false }) {
34670
+ function Designer({ store: storeIn = null, ...props }) {
34671
+ const [store] = useState17(() => {
34672
+ const s = storeIn || newDesignerStore();
34673
+ activateStore(s);
34674
+ return s;
34675
+ });
34676
+ return /* @__PURE__ */ jsx20(DesignerStore.Provider, { value: store, children: /* @__PURE__ */ jsx20(DesignerIn, { ...props }) });
34677
+ }
34678
+ var ACTIVATE = [
34679
+ "onPointerDownCapture",
34680
+ "onMouseDownCapture",
34681
+ "onKeyDownCapture",
34682
+ "onFocusCapture",
34683
+ "onClickCapture",
34684
+ "onInputCapture",
34685
+ "onChangeCapture",
34686
+ "onDragStartCapture",
34687
+ "onDragOverCapture",
34688
+ "onDropCapture",
34689
+ "onPasteCapture",
34690
+ "onWheelCapture",
34691
+ "onContextMenuCapture",
34692
+ "onDoubleClickCapture",
34693
+ "onSubmitCapture"
34694
+ ];
34695
+ function DesignerIn({ id, initial, rev = null, lang: langIn, embed = null, user = null, ai = false }) {
34696
+ const api = useDesignerStore();
34697
+ const activators = useMemo5(() => {
34698
+ const on = () => activateStore(api);
34699
+ return Object.fromEntries(ACTIVATE.map((k) => [k, on]));
34700
+ }, [api]);
34543
34701
  const lang2 = pickLang(langIn);
34544
34702
  const T = (k, v) => t(lang2, k, v);
34545
34703
  const q2 = lang2 === "en" ? "" : `?lang=${encodeURIComponent(lang2)}`;
34546
- const ready = useRef7(false);
34704
+ const ready = useRef8(false);
34547
34705
  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 });
34706
+ api.getState().init(id, initial);
34707
+ api.getState().setUi({ lang: lang2, embed, readOnly: !!embed?.readOnly, rev, conflict: null });
34550
34708
  ready.current = true;
34551
34709
  }
34552
34710
  const readOnly2 = !!embed?.readOnly;
34553
- const rootRef = useRef7(null);
34711
+ const rootRef = useRef8(null);
34554
34712
  const def = useDesigner((s) => s.def);
34555
34713
  const tab = useDesigner((s) => s.tab);
34556
34714
  const saved = useDesigner((s) => s.saved);
@@ -34565,15 +34723,15 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34565
34723
  if (embed) declareDocumentStyles("pw-designer-fonts", fontCss);
34566
34724
  }, [embed, fontCss]);
34567
34725
  useEffect13(() => {
34568
- customFonts().then((list2) => useDesigner.getState().setUi({ fonts: list2 }));
34726
+ customFonts().then((list2) => api.getState().setUi({ fonts: list2 }));
34569
34727
  }, []);
34570
34728
  useEffect13(() => {
34571
34729
  const z = savedZoom();
34572
- if (z != null) useDesigner.getState().setUi({ zoom: z });
34730
+ if (z != null) api.getState().setUi({ zoom: z });
34573
34731
  }, []);
34574
34732
  const canUndo = useDesigner((s) => s.past.length > 0);
34575
34733
  const canRedo = useDesigner((s) => s.future.length > 0);
34576
- const st = useDesigner.getState;
34734
+ const st = api.getState;
34577
34735
  const [dialog, setDialog] = useState17(null);
34578
34736
  const [showLeft, setShowLeft] = useState17(true);
34579
34737
  const [showRight, setShowRight] = useState17(true);
@@ -34586,11 +34744,17 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34586
34744
  const cellSize = useDesigner((s) => s.cellSize);
34587
34745
  const dataKey = useDesigner((s) => `${(s.def?.dataSources || []).map((x) => x.name)}|${(s.def?.dataSets || []).map((x) => x.name)}`);
34588
34746
  useEffect13(() => {
34589
- loadSample();
34747
+ loadSample(api);
34590
34748
  }, [dataKey]);
34591
34749
  useEffect13(() => {
34750
+ let lastInside = false;
34751
+ const inside = (e) => (e.composedPath?.() || []).includes(rootRef.current);
34752
+ const onDown = (e) => {
34753
+ lastInside = inside(e);
34754
+ };
34755
+ const ours = (e) => inside(e) || lastInside && (e.target === document.body || e.target === document.documentElement);
34592
34756
  const onKey = (e) => {
34593
- if (embed && !(e.composedPath?.() || []).includes(rootRef.current)) return;
34757
+ if (embed && !ours(e)) return;
34594
34758
  const mod = e.metaKey || e.ctrlKey;
34595
34759
  if (mod && e.key.toLowerCase() === "s") {
34596
34760
  e.preventDefault();
@@ -34609,7 +34773,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34609
34773
  st().save();
34610
34774
  return;
34611
34775
  }
34612
- if (isTyping(e) || st().tab !== "design") return;
34776
+ if (isTyping(e) || st().tab !== "design" || e.defaultPrevented) return;
34613
34777
  if (mod && e.key.toLowerCase() === "z") {
34614
34778
  e.preventDefault();
34615
34779
  e.shiftKey ? st().redo() : st().undo();
@@ -34632,11 +34796,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34632
34796
  }
34633
34797
  return;
34634
34798
  }
34635
- if (mod && e.key.toLowerCase() === "v") {
34636
- e.preventDefault();
34637
- pasteItems(st().sel.kind === "section" ? st().sel.section : "body");
34638
- return;
34639
- }
34799
+ if (mod && e.key.toLowerCase() === "v") return;
34640
34800
  if (e.key === "Delete" || e.key === "Backspace") {
34641
34801
  if (st().sel.kind === "items") {
34642
34802
  e.preventDefault();
@@ -34668,10 +34828,24 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34668
34828
  e.returnValue = "";
34669
34829
  }
34670
34830
  };
34831
+ const onPaste = (e) => {
34832
+ if (embed && !ours(e) || isTyping(e) || st().tab !== "design") return;
34833
+ e.preventDefault();
34834
+ if (!pasteItems(st().sel.kind === "section" ? st().sel.section : "body", e.clipboardData?.getData("text/plain"))) {
34835
+ st().setUi({ saveError: t(lang2, "b9_nothingToPaste") });
34836
+ setTimeout(() => st().setUi({ saveError: null }), 3e3);
34837
+ }
34838
+ };
34671
34839
  window.addEventListener("keydown", onKey);
34840
+ window.addEventListener("paste", onPaste);
34841
+ window.addEventListener("pointerdown", onDown, true);
34842
+ window.addEventListener("focusin", onDown, true);
34672
34843
  if (!embed) window.addEventListener("beforeunload", onLeave);
34673
34844
  return () => {
34674
34845
  window.removeEventListener("keydown", onKey);
34846
+ window.removeEventListener("paste", onPaste);
34847
+ window.removeEventListener("pointerdown", onDown, true);
34848
+ window.removeEventListener("focusin", onDown, true);
34675
34849
  window.removeEventListener("beforeunload", onLeave);
34676
34850
  };
34677
34851
  }, [st, embed]);
@@ -34690,17 +34864,17 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34690
34864
  const d = await embed.onOpen();
34691
34865
  if (d && typeof d === "object") {
34692
34866
  st().init(id, d);
34693
- loadSample();
34867
+ loadSample(api);
34694
34868
  }
34695
34869
  };
34696
- const importInput = useRef7(null);
34870
+ const importInput = useRef8(null);
34697
34871
  const [imported, setImported] = useState17(null);
34698
34872
  const importFile = async (file) => {
34699
34873
  if (!file) return;
34700
34874
  const r = readReportFile(file.name, await file.text());
34701
34875
  if (r.definition) {
34702
34876
  st().init(id, r.definition);
34703
- loadSample();
34877
+ loadSample(api);
34704
34878
  }
34705
34879
  setImported({ name: file.name, ok: !!r.definition, warnings: r.warnings || [], error: r.error });
34706
34880
  };
@@ -34714,7 +34888,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34714
34888
  ] }),
34715
34889
  /* @__PURE__ */ jsx20("span", { className: "hint", children: T("loadingDesigner") })
34716
34890
  ] }) });
34717
- return /* @__PURE__ */ jsxs17("div", { className: "designer", "data-testid": "designer", dir: dirOf(lang2), lang: lang2, ref: rootRef, "data-readonly": readOnly2 || void 0, children: [
34891
+ return /* @__PURE__ */ jsxs17("div", { className: "designer", "data-testid": "designer", dir: dirOf(lang2), lang: lang2, ref: rootRef, "data-readonly": readOnly2 || void 0, ...activators, children: [
34718
34892
  !embed && /* @__PURE__ */ jsx20("style", { children: fontCss }),
34719
34893
  /* @__PURE__ */ jsxs17("header", { className: "dtop dbar", children: [
34720
34894
  embed ? /* @__PURE__ */ jsxs17("span", { className: "brand", children: [
@@ -34902,6 +35076,7 @@ var CSS2 = true ? `/* Layout: a drafting table. Cool grey workspace, white paper
34902
35076
  --ink: #16202a;
34903
35077
  --muted: #5f6b77;
34904
35078
  --faint: #64717e; /* 5:1 on panel (was #8e99a4, 2.9:1) */
35079
+ --faint-desk: #5a6672; /* small text on the desk: 4.85:1 on #e6eaee (--faint is 4.13:1 there) */
34905
35080
  --line-strong: #848f9b; /* control borders, 3:1 */
34906
35081
  --accent: #0e7490;
34907
35082
  --accent-ink: #ffffff;
@@ -34955,6 +35130,7 @@ var CSS2 = true ? `/* Layout: a drafting table. Cool grey workspace, white paper
34955
35130
  --ink: #e6edf3;
34956
35131
  --muted: #a3afbb;
34957
35132
  --faint: #8693a0;
35133
+ --faint-desk: #8693a0;
34958
35134
  --accent: #3cbfd4;
34959
35135
  --accent-ink: #03222a;
34960
35136
  --accent-soft: #123a44;
@@ -35293,7 +35469,7 @@ a.cell-name:hover { color: var(--accent); }
35293
35469
  .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
35470
  .tbl.sel .grip { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
35295
35471
  .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%; }
35472
+ .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
35473
  .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
35474
  .tbl .cell:first-child { border-left: 1px dashed rgba(95,107,119,.3); }
35299
35475
  .tbl .row:first-child .cell { border-top: 1px dashed rgba(95,107,119,.3); }
@@ -35813,7 +35989,7 @@ input[type=checkbox], input[type=radio] { width: 16px; height: 16px; accent-colo
35813
35989
 
35814
35990
  .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
35991
  ` : "";
35816
- var BLANK = { $schema: "pagewright/report@1", name: "New report", page: { size: "A4", margins: [36, 36, 36, 36] }, dataSources: [], dataSets: [], sections: { body: { items: [] } } };
35992
+ var BLANK = { $schema: "pagewright/report@1", name: "Untitled report", page: { size: "A4", margins: [36, 36, 36, 36] }, dataSources: [], dataSets: [], sections: { body: { items: [] } } };
35817
35993
  function mountDesigner(target, opts = {}) {
35818
35994
  const el = typeof target === "string" ? document.querySelector(target) : target;
35819
35995
  if (!el) throw new Error(`mountDesigner: no element for ${target}`);
@@ -35831,18 +36007,43 @@ function mountDesigner(target, opts = {}) {
35831
36007
  );
35832
36008
  box.style.height = opts.height || "760px";
35833
36009
  const root = createRoot(box);
36010
+ const store = newDesignerStore();
35834
36011
  const embed = { onSave: opts.onSave, onOpen: opts.onOpen, readOnly: !!opts.readOnly, toolbox: opts.toolbox, panels: opts.panels, dataSourceTemplates: opts.dataSourceTemplates, server: server2 };
35835
36012
  const show = (definition) => loadLanguage(opts.lang).catch(() => {
35836
- }).then(() => root.render(createElement2(Designer, { id: opts.report, initial: definition, lang: opts.lang, embed })));
36013
+ }).then(() => root.render(createElement2(Designer, { id: opts.report, initial: definition, lang: opts.lang, embed, store })));
35837
36014
  if (opts.definition || !opts.report) show(opts.definition || BLANK);
35838
36015
  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
36016
  box.innerHTML = `<div class="vmsg error">The report did not load: ${String(e.message).replace(/</g, "&lt;")}</div>`;
35840
36017
  });
36018
+ const onLeave = (e) => {
36019
+ e.preventDefault();
36020
+ e.returnValue = "";
36021
+ };
36022
+ let dirty = false;
36023
+ const unsub = store.subscribe((s) => {
36024
+ if (!s.saved === dirty) return;
36025
+ dirty = !s.saved;
36026
+ if (opts.warnOnLeave !== false) {
36027
+ if (dirty) window.addEventListener("beforeunload", onLeave);
36028
+ else window.removeEventListener("beforeunload", onLeave);
36029
+ }
36030
+ try {
36031
+ opts.onDirtyChange?.(dirty);
36032
+ } catch (e) {
36033
+ console.error(e);
36034
+ }
36035
+ });
35841
36036
  return {
35842
- unmount: () => root.unmount(),
36037
+ unmount: () => {
36038
+ unsub();
36039
+ window.removeEventListener("beforeunload", onLeave);
36040
+ root.unmount();
36041
+ },
36042
+ /** whether there are changes not saved yet */
36043
+ isDirty: () => !store.getState().saved,
35843
36044
  /** the definition as it is now (a plain copy) */
35844
- getDefinition: () => JSON.parse(JSON.stringify(useDesigner.getState().def)),
35845
- save: () => useDesigner.getState().save()
36045
+ getDefinition: () => JSON.parse(JSON.stringify(store.getState().def)),
36046
+ save: () => store.getState().save()
35846
36047
  };
35847
36048
  }
35848
36049
  export {