@reportwright/viewer 0.12.0 → 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 (89) hide show
  1. package/CHANGELOG.md +133 -1
  2. package/README.md +43 -6
  3. package/THIRD-PARTY-NOTICES.md +52 -0
  4. package/dist/{chunk-SBD55ZES.js → chunk-BF7GCWZY.js} +103 -41
  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/chunk-CNDUJ7IV.js +758 -0
  9. package/dist/chunk-CNDUJ7IV.js.map +6 -0
  10. package/dist/{chunk-RYHJUQSV.js → chunk-DXHLIJEY.js} +2 -2
  11. package/dist/{chunk-M6GENFAH.js → chunk-EK5CJY22.js} +4021 -4631
  12. package/dist/chunk-EK5CJY22.js.map +6 -0
  13. package/dist/{chunk-KJTRZJHN.js → chunk-F5EPQTPF.js} +4 -3
  14. package/dist/chunk-F5EPQTPF.js.map +6 -0
  15. package/dist/{chunk-SR2TQ2ZK.js → chunk-F6RMRXIN.js} +2 -2
  16. package/dist/chunk-F6RMRXIN.js.map +6 -0
  17. package/dist/chunk-FEM2QVOO.js +18 -0
  18. package/dist/{chunk-ODREGGKA.js → chunk-IFYCJZNS.js} +9 -6
  19. package/dist/chunk-IFYCJZNS.js.map +6 -0
  20. package/dist/{chunk-EOVGKHAS.js → chunk-L6YEIVVD.js} +86 -57
  21. package/dist/chunk-L6YEIVVD.js.map +6 -0
  22. package/dist/{chunk-APRPSQOD.js → chunk-PQNM6ET7.js} +28 -9
  23. package/dist/chunk-PQNM6ET7.js.map +6 -0
  24. package/dist/chunk-QFLVVM3H.js +856 -0
  25. package/dist/chunk-QFLVVM3H.js.map +6 -0
  26. package/dist/{chunk-5N6OFCHJ.js → chunk-TZXEEVKE.js} +1319 -76
  27. package/dist/chunk-TZXEEVKE.js.map +6 -0
  28. package/dist/{chunk-FARG6X2U.js → chunk-UHHURTSV.js} +15 -9
  29. package/dist/chunk-UHHURTSV.js.map +6 -0
  30. package/dist/chunk-UJL7C2AS.js +546 -0
  31. package/dist/chunk-UJL7C2AS.js.map +6 -0
  32. package/dist/chunk-YIX3OJXU.js +34 -0
  33. package/dist/designer.d.ts +19 -4
  34. package/dist/designer.js +616 -405
  35. package/dist/designer.js.map +3 -3
  36. package/dist/{peer/chunk-GBITRNHE.js → engine.worker.js} +11006 -9030
  37. package/dist/engine.worker.js.map +6 -0
  38. package/dist/peer/{chunk-NPYKZINU.js → chunk-2CD5COHN.js} +66 -37
  39. package/dist/peer/chunk-2CD5COHN.js.map +6 -0
  40. package/dist/peer/{chunk-IPU2YRL2.js → chunk-3CBV5SAI.js} +28 -9
  41. package/dist/peer/chunk-3CBV5SAI.js.map +6 -0
  42. package/dist/peer/{chunk-MCJPN2KL.js → chunk-45GVDKP5.js} +15 -9
  43. package/dist/peer/chunk-45GVDKP5.js.map +6 -0
  44. package/dist/peer/{chunk-76ZABVTI.js → chunk-LWXQX3NJ.js} +4 -3
  45. package/dist/peer/chunk-MKY3SDXU.js +758 -0
  46. package/dist/peer/chunk-MKY3SDXU.js.map +6 -0
  47. package/dist/peer/chunk-S6LSPHSU.js +17 -0
  48. package/dist/peer/chunk-S6LSPHSU.js.map +6 -0
  49. package/dist/peer/{chunk-M4AGFUWE.js → chunk-V42KN7HD.js} +2 -2
  50. package/dist/peer/{chunk-KBT6ZGGO.js → chunk-VZHHNQYB.js} +1319 -76
  51. package/dist/peer/chunk-VZHHNQYB.js.map +6 -0
  52. package/dist/peer/{chunk-Y5CAHLXS.js → chunk-YITWGAR4.js} +9 -6
  53. package/dist/peer/chunk-YITWGAR4.js.map +6 -0
  54. package/dist/peer/chunk-Z5II55QT.js +33 -0
  55. package/dist/peer/chunk-Z5II55QT.js.map +6 -0
  56. package/dist/peer/designer.js +473 -262
  57. package/dist/peer/designer.js.map +3 -3
  58. package/dist/peer/engine.worker.js +16782 -0
  59. package/dist/peer/engine.worker.js.map +6 -0
  60. package/dist/peer/viewer.js +17 -7
  61. package/dist/peer/viewer.js.map +1 -1
  62. package/dist/viewer.d.ts +11 -2
  63. package/dist/viewer.js +17 -7
  64. package/dist/viewer.js.map +1 -1
  65. package/package.json +4 -2
  66. package/dist/chunk-3D43XGIN.js +0 -1167
  67. package/dist/chunk-3D43XGIN.js.map +0 -6
  68. package/dist/chunk-5N6OFCHJ.js.map +0 -6
  69. package/dist/chunk-AH47FS6Y.js +0 -13
  70. package/dist/chunk-APRPSQOD.js.map +0 -6
  71. package/dist/chunk-EOVGKHAS.js.map +0 -6
  72. package/dist/chunk-FARG6X2U.js.map +0 -6
  73. package/dist/chunk-M6GENFAH.js.map +0 -6
  74. package/dist/chunk-ODREGGKA.js.map +0 -6
  75. package/dist/chunk-SBD55ZES.js.map +0 -6
  76. package/dist/chunk-SR2TQ2ZK.js.map +0 -6
  77. package/dist/peer/chunk-76ZABVTI.js.map +0 -6
  78. package/dist/peer/chunk-GBITRNHE.js.map +0 -6
  79. package/dist/peer/chunk-IMQRHDR4.js +0 -12
  80. package/dist/peer/chunk-IPU2YRL2.js.map +0 -6
  81. package/dist/peer/chunk-KBT6ZGGO.js.map +0 -6
  82. package/dist/peer/chunk-MCJPN2KL.js.map +0 -6
  83. package/dist/peer/chunk-NPYKZINU.js.map +0 -6
  84. package/dist/peer/chunk-Y5CAHLXS.js.map +0 -6
  85. /package/dist/{chunk-RYHJUQSV.js.map → chunk-DXHLIJEY.js.map} +0 -0
  86. /package/dist/{chunk-AH47FS6Y.js.map → chunk-FEM2QVOO.js.map} +0 -0
  87. /package/dist/{peer/chunk-IMQRHDR4.js.map → chunk-YIX3OJXU.js.map} +0 -0
  88. /package/dist/{chunk-KJTRZJHN.js.map → peer/chunk-LWXQX3NJ.js.map} +0 -0
  89. /package/dist/peer/{chunk-M4AGFUWE.js.map → chunk-V42KN7HD.js.map} +0 -0
@@ -10,7 +10,18 @@ import {
10
10
  setShadowStyles,
11
11
  t,
12
12
  uiFontCss
13
- } from "./chunk-NPYKZINU.js";
13
+ } from "./chunk-2CD5COHN.js";
14
+ import {
15
+ customFonts,
16
+ fontsBase,
17
+ loadFontStore,
18
+ loadModelFonts,
19
+ origin,
20
+ reportFetch,
21
+ setAssetBase,
22
+ setFetchPolicy,
23
+ setStandalone
24
+ } from "./chunk-MKY3SDXU.js";
14
25
  import {
15
26
  BASE_STYLE,
16
27
  DEFAULT_THEME,
@@ -19,7 +30,6 @@ import {
19
30
  ITEMS,
20
31
  ODATA_DEFAULT_PAGES,
21
32
  ODATA_MAX_PAGES,
22
- PAGE_SIZES,
23
33
  PALETTES,
24
34
  TEXT_STYLE_PROPS,
25
35
  THEME_COLORS,
@@ -29,14 +39,10 @@ import {
29
39
  buildDataSets,
30
40
  checkFunctions,
31
41
  checkValue,
32
- customFonts,
33
42
  detectFields,
34
43
  evalValue,
35
44
  findItemNamed,
36
45
  finishText,
37
- fontStore,
38
- fontsBase,
39
- fromPt,
40
46
  functionTable,
41
47
  isDynamic,
42
48
  isTablix,
@@ -44,46 +50,47 @@ import {
44
50
  jsonPath,
45
51
  layoutItems,
46
52
  loadBarcodes,
47
- loadModelFonts,
48
53
  loadSources,
49
- normBox,
50
54
  normalizeMatrix,
51
55
  odataMetadata,
52
- origin,
53
56
  parseBorder,
54
57
  parseXml,
55
58
  render,
56
- reportFetch,
57
- resolvePage,
58
59
  resolveParameters,
59
- setAssetBase,
60
- setStandalone,
61
60
  shiftItems,
62
61
  sourceRows,
63
62
  sourceUrl,
64
63
  stylePropsFor,
65
64
  themeContext,
66
- toPt,
67
65
  toText,
68
66
  validate,
69
67
  withPartProps,
70
68
  xmlRowPaths
71
- } from "./chunk-GBITRNHE.js";
69
+ } from "../chunk-EK5CJY22.js";
70
+ import {
71
+ PAGE_SIZES,
72
+ fromPt,
73
+ normBox,
74
+ resolvePage,
75
+ toPt
76
+ } from "../chunk-BR5K6SBL.js";
77
+ import "../chunk-72S6DETS.js";
72
78
  import {
73
79
  currencyOf
74
80
  } from "../chunk-GJS242RR.js";
75
- import "../chunk-72S6DETS.js";
76
- import "../chunk-SR2TQ2ZK.js";
81
+ import "../chunk-F6RMRXIN.js";
82
+ import {
83
+ fontFaceCss,
84
+ fontFamilyCss,
85
+ pageToSvg
86
+ } from "../chunk-UJL7C2AS.js";
77
87
  import {
78
88
  BUNDLED_FAMILIES,
79
89
  FONT_FAMILIES,
80
90
  allFontKeys,
81
91
  fallbackKeys,
82
- fontFaceCss,
83
- fontFamilyCss,
84
- pageToSvg,
85
92
  resolveFontKey
86
- } from "../chunk-3D43XGIN.js";
93
+ } from "../chunk-QFLVVM3H.js";
87
94
 
88
95
  // src/embed/designer.js
89
96
  import { createElement as createElement2 } from "react";
@@ -6140,7 +6147,8 @@ function toRdlx3(root, notes, reportName) {
6140
6147
  const on = prop(b, "aggregateOn") ?? simpleList(b, "aggregateOn")[0]?.text;
6141
6148
  const gc = { ...c, group: on && on !== "All" ? on : void 0 };
6142
6149
  if (fn3) {
6143
- const arg = listProp(b, "arguments").map((x) => prop(x, "value")).find((x) => x != null);
6150
+ const arg = listProp(b, "arguments").map((x) => prop(x, "value")).find((x) => x != null) ?? prop(b, "expression");
6151
+ if (arg == null && fn3 !== "count") throw new Untranslatable2(`the aggregate ${fn3.toUpperCase()} with no expression`);
6144
6152
  const inner2 = arg != null ? vb2(arg, { ...c, inSet: false }, depth) : "1";
6145
6153
  if (prop(b, "filterExpr")) throw new Untranslatable2(`the bound column "${prop(b, "name")}", an aggregate with a filter`);
6146
6154
  const all = gc.group ?? c.region;
@@ -6853,10 +6861,10 @@ function readReportFile(name2, text) {
6853
6861
  }
6854
6862
 
6855
6863
  // src/designer/Designer.jsx
6856
- 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";
6857
6865
 
6858
6866
  // src/designer/ui.jsx
6859
- import { createContext, useContext, useEffect, useState } from "react";
6867
+ import { createContext as createContext2, useContext as useContext2, useEffect, useRef, useState } from "react";
6860
6868
 
6861
6869
  // src/designer/fieldCheck.js
6862
6870
  function exprParts(value) {
@@ -6954,7 +6962,7 @@ function nestedFields(rows) {
6954
6962
  return [...top2].filter(([, m]) => m.size).map(([name2, m]) => ({ name: name2, type: "object", fields: [...m].map(([n, t3]) => ({ name: n, type: t3 === "null" ? "string" : t3 })) }));
6955
6963
  }
6956
6964
 
6957
- // ../reportwright/node_modules/zustand/esm/vanilla.mjs
6965
+ // node_modules/zustand/esm/vanilla.mjs
6958
6966
  var createStoreImpl = (createState) => {
6959
6967
  let state;
6960
6968
  const listeners = /* @__PURE__ */ new Set();
@@ -6978,7 +6986,7 @@ var createStoreImpl = (createState) => {
6978
6986
  };
6979
6987
  var createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);
6980
6988
 
6981
- // ../reportwright/node_modules/zustand/esm/react.mjs
6989
+ // node_modules/zustand/esm/react.mjs
6982
6990
  import React from "react";
6983
6991
  var identity = (arg) => arg;
6984
6992
  function useStore(api, selector = identity) {
@@ -6990,15 +6998,11 @@ function useStore(api, selector = identity) {
6990
6998
  React.useDebugValue(slice);
6991
6999
  return slice;
6992
7000
  }
6993
- var createImpl = (createState) => {
6994
- const api = createStore(createState);
6995
- const useBoundStore = (selector) => useStore(api, selector);
6996
- Object.assign(useBoundStore, api);
6997
- return useBoundStore;
6998
- };
6999
- var create = ((createState) => createState ? createImpl(createState) : createImpl);
7000
7001
 
7001
- // ../reportwright/node_modules/immer/dist/immer.mjs
7002
+ // src/designer/store.js
7003
+ import { createContext, useContext } from "react";
7004
+
7005
+ // node_modules/immer/dist/immer.mjs
7002
7006
  var NOTHING = /* @__PURE__ */ Symbol.for("immer-nothing");
7003
7007
  var DRAFTABLE = /* @__PURE__ */ Symbol.for("immer-draftable");
7004
7008
  var DRAFT_STATE = /* @__PURE__ */ Symbol.for("immer-state");
@@ -7845,6 +7849,17 @@ function pageOf2(def, key2 = "body") {
7845
7849
  return resolvePage({ ...def.page || {}, ...sec?.page || {} });
7846
7850
  }
7847
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
+ }
7848
7863
  function walk(def, fn3) {
7849
7864
  const go = (list2, parent, section) => list2.forEach((it, i2) => {
7850
7865
  fn3(it, list2, i2, parent, section);
@@ -7870,9 +7885,15 @@ function normalize(def) {
7870
7885
  if (x && typeof x === "object") x.items || (x.items = []);
7871
7886
  }
7872
7887
  const used = allNames(d);
7888
+ const ids = /* @__PURE__ */ new Set();
7873
7889
  walk(d, (it) => {
7874
- 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}`);
7875
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));
7876
7897
  if (NESTING.has(it.type)) it.items || (it.items = []);
7877
7898
  if (it.type === "table" && Array.isArray(it.columns)) tableSync(it);
7878
7899
  });
@@ -7896,7 +7917,7 @@ function findItem(def, id) {
7896
7917
  });
7897
7918
  return hit;
7898
7919
  }
7899
- var useDesigner = create((set2, get2) => ({
7920
+ var newDesignerStore = () => createStore((set2, get2) => ({
7900
7921
  id: null,
7901
7922
  def: null,
7902
7923
  saved: true,
@@ -8027,7 +8048,18 @@ var useDesigner = create((set2, get2) => ({
8027
8048
  set2({ rev: (res.headers.get("etag") || "").replace(/^W\/|"/g, "") || null, conflict: null });
8028
8049
  }
8029
8050
  }));
8030
- 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();
8031
8063
  function bodyWidth(def, key2 = "body") {
8032
8064
  return pageOf2(def, key2).bodyWidth;
8033
8065
  }
@@ -8075,7 +8107,7 @@ function addItem(type, section, x, y, extra = {}, parentId = null) {
8075
8107
  } else {
8076
8108
  const sec = secOf(d, section);
8077
8109
  sec.items.push(it);
8078
- 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));
8079
8111
  }
8080
8112
  });
8081
8113
  S().select({ kind: "items", ids: [id] });
@@ -8101,9 +8133,21 @@ function insertItem(type, section, x, y, extra = {}, parentId = null) {
8101
8133
  function updateItem(id, recipe, key2) {
8102
8134
  S().apply((d) => {
8103
8135
  const f = findItem(d, id);
8104
- 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);
8105
8141
  }, key2);
8106
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
+ }
8107
8151
  function moveItems(ids, dx, dy) {
8108
8152
  if (!dx && !dy) return;
8109
8153
  if (S().cells && wouldOverlap(S().def, ids, (it) => ({ x: it.x + dx, y: it.y + dy, w: it.w, h: it.h }))) {
@@ -8234,14 +8278,16 @@ function duplicateSelection() {
8234
8278
  const f = findItem(d, id);
8235
8279
  if (!f) continue;
8236
8280
  const copy = cloneWithIds(f.item, used);
8237
- copy.x += 8;
8238
- copy.y += 8;
8281
+ copy.x += PASTE_OFFSET;
8282
+ copy.y += PASTE_OFFSET;
8283
+ growToFit(d, { ...f, item: copy });
8239
8284
  f.list.push(copy);
8240
8285
  newIds.push(copy.id);
8241
8286
  }
8242
8287
  });
8243
8288
  if (newIds.length) S().select({ kind: "items", ids: newIds });
8244
8289
  }
8290
+ var PASTE_OFFSET = 12;
8245
8291
  var CLIP = "pagewright/items@1";
8246
8292
  async function copySelection() {
8247
8293
  const { sel, def } = S();
@@ -8256,43 +8302,41 @@ async function copySelection() {
8256
8302
  return items.length;
8257
8303
  }
8258
8304
  var memClip = null;
8259
- async function pasteItems(section = "body") {
8260
- let text = null;
8305
+ var clipOf = (text) => {
8261
8306
  try {
8262
- text = await navigator.clipboard.readText();
8307
+ const d = JSON.parse(text);
8308
+ return d?.kind === CLIP && Array.isArray(d.items) ? d : null;
8263
8309
  } catch {
8264
- text = memClip;
8265
- }
8266
- if (!text || !text.includes(CLIP)) text = memClip;
8267
- let data;
8268
- try {
8269
- data = JSON.parse(text);
8270
- } catch {
8271
- return 0;
8310
+ return null;
8272
8311
  }
8273
- 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;
8274
8317
  const ids = [];
8275
- S().apply((d) => {
8318
+ st.getState().apply((d) => {
8276
8319
  const used = allNames(d);
8277
8320
  for (const it of data.items) {
8278
8321
  const c = cloneWithIds(it, used);
8279
- c.x += 12;
8280
- c.y += 12;
8322
+ c.x += PASTE_OFFSET;
8323
+ c.y += PASTE_OFFSET;
8281
8324
  if (c.type === "table" && !isBodyKey(section)) continue;
8282
8325
  secOf(d, section).items.push(c);
8326
+ growToFit(d, { section, parent: null, item: c });
8283
8327
  ids.push(c.id);
8284
8328
  }
8285
8329
  });
8286
- if (ids.length) S().select({ kind: "items", ids });
8330
+ if (ids.length) st.getState().select({ kind: "items", ids });
8287
8331
  return ids.length;
8288
8332
  }
8289
- function rowsOf(t3, part, create2 = false) {
8333
+ function rowsOf(t3, part, create = false) {
8290
8334
  const m = /^g(\d+)([hf])$/.exec(part);
8291
8335
  const holder = m ? t3.groups?.[Number(m[1])] : t3;
8292
8336
  if (!holder) return null;
8293
8337
  const key2 = m ? m[2] === "h" ? "header" : "footer" : part;
8294
8338
  if (!holder[key2]) {
8295
- if (!create2) return [];
8339
+ if (!create) return [];
8296
8340
  holder[key2] = [];
8297
8341
  }
8298
8342
  return holder[key2];
@@ -8492,6 +8536,7 @@ function tableRemoveGroup(id, level) {
8492
8536
  }
8493
8537
  var IMAGE_MAX = 10 * 1024 * 1024;
8494
8538
  async function uploadImages(files, T) {
8539
+ const st = active;
8495
8540
  const names = [];
8496
8541
  let err = null;
8497
8542
  for (const f of files) {
@@ -8510,7 +8555,7 @@ async function uploadImages(files, T) {
8510
8555
  r.readAsDataURL(f);
8511
8556
  });
8512
8557
  const base2 = f.name.replace(/\.[^.]+$/, "").replace(/\W+/g, "_").replace(/^_+|_+$/g, "") || "image";
8513
- S().apply((d) => {
8558
+ st.getState().apply((d) => {
8514
8559
  d.images || (d.images = {});
8515
8560
  let n = base2, k = 2;
8516
8561
  while (d.images[n]) n = `${base2}${k++}`;
@@ -8577,6 +8622,13 @@ function wouldOverlap(def, ids, rectOf2) {
8577
8622
  }
8578
8623
  return false;
8579
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
+ }
8580
8632
 
8581
8633
  // src/designer/ui.jsx
8582
8634
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -8625,18 +8677,18 @@ function ColorInput({ value, onChange }) {
8625
8677
  /* @__PURE__ */ jsx(TextInput, { value, onChange: (v) => onChange(v === "" ? void 0 : v), mono: true, placeholder: T("i_colorPh") })
8626
8678
  ] });
8627
8679
  }
8628
- var FieldScope = createContext(void 0);
8680
+ var FieldScope = createContext2(void 0);
8629
8681
  var issueText = (T, i2) => i2.suggest ? T("ux_unknownFieldSuggest", { name: i2.name, suggest: i2.suggest }) : T("ux_unknownField", { name: i2.name });
8630
8682
  function ExprInput({ value, onChange, onOpen, placeholder: placeholder2 }) {
8631
8683
  const T = useT();
8632
- const scope = useContext(FieldScope);
8684
+ const scope = useContext2(FieldScope);
8633
8685
  const dataSets = useDesigner((s) => s.def?.dataSets);
8634
8686
  const err = value ? checkValue(value) : null;
8635
8687
  const issues = !err && value && scope !== void 0 ? fieldIssues(value, dataSets, scope) : [];
8636
8688
  return /* @__PURE__ */ jsxs("div", { children: [
8637
8689
  /* @__PURE__ */ jsxs("div", { className: "expr-row", children: [
8638
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") }),
8639
- /* @__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" })
8640
8692
  ] }),
8641
8693
  err && /* @__PURE__ */ jsx("div", { className: "err", children: err }),
8642
8694
  issues.map((i2, k) => /* @__PURE__ */ jsx("div", { className: "warn", "data-testid": "field-warning", children: issueText(T, i2) }, k))
@@ -8656,14 +8708,19 @@ function Check({ label, checked, onChange }) {
8656
8708
  ] });
8657
8709
  }
8658
8710
  function Dialog({ title, children, onClose, footer, wide, className = "" }) {
8711
+ const ref = useRef(null);
8659
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
+ };
8660
8717
  const k = (e) => {
8661
- if (e.key === "Escape" && !e.defaultPrevented) onClose();
8718
+ if (e.key === "Escape" && !e.defaultPrevented && !inOther(e)) onClose();
8662
8719
  };
8663
8720
  window.addEventListener("keydown", k);
8664
8721
  return () => window.removeEventListener("keydown", k);
8665
8722
  }, [onClose]);
8666
- return /* @__PURE__ */ jsx("div", { className: "scrim", onPointerDown: (e) => {
8723
+ return /* @__PURE__ */ jsx("div", { className: "scrim", ref, onPointerDown: (e) => {
8667
8724
  if (e.target === e.currentTarget) onClose();
8668
8725
  }, children: /* @__PURE__ */ jsxs("div", { className: `dialog${wide ? " wide" : ""}${className ? ` ${className}` : ""}`, role: "dialog", "aria-modal": "true", "aria-label": title, children: [
8669
8726
  /* @__PURE__ */ jsx("header", { children: title }),
@@ -8679,10 +8736,10 @@ function Link({ href, children, prefetch, replace: replace2, scroll, shallow, ..
8679
8736
  }
8680
8737
 
8681
8738
  // src/designer/SvgHtml.jsx
8682
- import { useLayoutEffect, useRef } from "react";
8739
+ import { useLayoutEffect, useRef as useRef2 } from "react";
8683
8740
  import { jsx as jsx2 } from "react/jsx-runtime";
8684
8741
  function SvgHtml({ html, as: Tag2 = "span", ...rest }) {
8685
- const ref = useRef(
8742
+ const ref = useRef2(
8686
8743
  /** @type {HTMLElement|null} */
8687
8744
  null
8688
8745
  );
@@ -8695,7 +8752,7 @@ function SvgHtml({ html, as: Tag2 = "span", ...rest }) {
8695
8752
  }
8696
8753
 
8697
8754
  // src/designer/Canvas.jsx
8698
- 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";
8699
8756
 
8700
8757
  // src/designer/tableGen.js
8701
8758
  var HEAD = { fontWeight: "bold", backgroundColor: "#f1f5f9", borderBottom: "0.75 solid #94a3b8" };
@@ -8836,7 +8893,11 @@ function useFontFamilies() {
8836
8893
  const fonts = useDesigner((s) => s.fonts);
8837
8894
  return [...BUNDLED_FAMILIES, ...[...new Set(fonts.map((f) => f.family))].sort()];
8838
8895
  }
8839
- 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
+ };
8840
8901
  function FontsDialog({ onClose }) {
8841
8902
  const fonts = useDesigner((s) => s.fonts);
8842
8903
  const [file, setFile] = useState2(null);
@@ -8935,24 +8996,27 @@ var apply = (fn3, key2) => S2().apply(fn3, key2);
8935
8996
  var server = () => S2().embed?.server || "";
8936
8997
  var noServer = () => !!S2().embed && !S2().embed.server;
8937
8998
  var pending = /* @__PURE__ */ new Map();
8938
- function fetchReused(id, force = false) {
8999
+ function fetchReused(id, force = false, api = activeStore2()) {
8939
9000
  if (!id || typeof id !== "string" || id.startsWith("=")) return Promise.resolve(null);
8940
- if (!force && S2().reused[id]) return Promise.resolve(S2().reused[id]);
8941
- if (pending.has(id)) return pending.get(id);
8942
- if (noServer()) return Promise.resolve(null);
8943
- 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) => {
8944
- pending.delete(id);
8945
- 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 } }));
8946
9006
  return d;
8947
- });
8948
- pending.set(id, p);
8949
- 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);
8950
9013
  }
8951
9014
  function useReused(id) {
9015
+ const api = useDesignerStore();
8952
9016
  const d = useDesigner((s) => id ? s.reused[id] : void 0);
8953
9017
  useEffect2(() => {
8954
- fetchReused(id);
8955
- }, [id]);
9018
+ fetchReused(id, false, api);
9019
+ }, [id, api]);
8956
9020
  return d && !d.__error ? d : null;
8957
9021
  }
8958
9022
  var listCache = null;
@@ -9521,7 +9585,7 @@ function useDesignIssues() {
9521
9585
  return [...designIssues(def, bands, extents || {}), ...checkIssues(bands, [...validate(def).errors, ...saveCheck?.missing || []])];
9522
9586
  }, [def, extents, saveCheck]);
9523
9587
  }
9524
- var IssueMap = createContext2(/* @__PURE__ */ new Map());
9588
+ var IssueMap = createContext3(/* @__PURE__ */ new Map());
9525
9589
  function issueLine(T, i2) {
9526
9590
  if (i2.kind === "overlap") return T("ux_issueOverlap", { name: i2.name, other: i2.other });
9527
9591
  if (i2.kind === "wide") return T("ux_issueWide", { name: i2.name, width: i2.width, room: i2.room });
@@ -9586,7 +9650,7 @@ function Canvas() {
9586
9650
  const bands = sectionList(def);
9587
9651
  const widths2 = Object.fromEntries(bands.map((s) => [s.key, bodyWidth(def, s.key)]));
9588
9652
  const bw = Math.max(...Object.values(widths2));
9589
- const scrollRef = useRef2(null);
9653
+ const scrollRef = useRef3(null);
9590
9654
  const [fitW, setFitW] = useState4(0);
9591
9655
  useEffect3(() => {
9592
9656
  if (zoom !== "fit" || !scrollRef.current) return;
@@ -9680,7 +9744,7 @@ function Band({ section, label, scale, bw: bandW, drag, setDrag, phBox = null })
9680
9744
  const off = phBox || mb?.off || null;
9681
9745
  const contentList = useDesigner((s) => s.def.sections?.content);
9682
9746
  const bw = off?.w || bandW;
9683
- const ref = useRef2(null);
9747
+ const ref = useRef3(null);
9684
9748
  const [marquee, setMarquee] = useState4(null);
9685
9749
  const [dropping, setDropping] = useState4(false);
9686
9750
  const h = drag?.mode === "band" && drag.section === section ? drag.h : sec.height || 0;
@@ -9856,8 +9920,9 @@ var alerted = 0;
9856
9920
  function alertOnce(msg) {
9857
9921
  if (Date.now() - alerted > 3e3) {
9858
9922
  alerted = Date.now();
9859
- useDesigner.setState({ saveError: msg });
9860
- setTimeout(() => useDesigner.setState({ saveError: null }), 3e3);
9923
+ const api = activeStore2();
9924
+ api.setState({ saveError: msg });
9925
+ setTimeout(() => api.setState({ saveError: null }), 3e3);
9861
9926
  }
9862
9927
  }
9863
9928
  function fieldStyle(f) {
@@ -9865,11 +9930,31 @@ function fieldStyle(f) {
9865
9930
  const format = formatFor({ name: f.field, type: f.type }, (st.sample?.dataSets?.[f.dataSet] || []).slice(0, 200), { currency: st.def?.currency });
9866
9931
  return format ? { format } : {};
9867
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
+ }
9868
9952
  function useItemDrag(item, scale, setDrag) {
9869
9953
  return (e) => {
9870
9954
  if (e.button !== 0) return;
9871
9955
  e.preventDefault();
9872
9956
  e.stopPropagation();
9957
+ e.currentTarget.closest?.("[data-item-key]")?.focus({ preventScroll: true });
9873
9958
  const st = useDesigner.getState();
9874
9959
  let ids;
9875
9960
  if (e.shiftKey) {
@@ -9942,7 +10027,7 @@ function AnyItem(props) {
9942
10027
  return layer?.locked ? /* @__PURE__ */ jsx6("div", { className: "layer-locked", "data-locked": props.item.name, children: el }) : el;
9943
10028
  }
9944
10029
  function NestChildren({ item, scale, drag, setDrag, section }) {
9945
- const ref = useRef2(null);
10030
+ const ref = useRef3(null);
9946
10031
  const [over, setOver] = useState4(false);
9947
10032
  const accepts = (e) => e.dataTransfer.types.includes(MIME_TOOL) || e.dataTransfer.types.includes(MIME_FIELD) || e.dataTransfer.types.includes(MIME_PART);
9948
10033
  const onDrop = (e) => {
@@ -9988,8 +10073,9 @@ function ItemView({ item, scale, drag, setDrag, bw, nest, section }) {
9988
10073
  const selected = useDesigner((s) => s.sel.kind === "items" && s.sel.ids.includes(item.id));
9989
10074
  const single = useDesigner((s) => s.sel.kind === "items" && s.sel.ids.length === 1);
9990
10075
  const onDown = useItemDrag(item, scale, setDrag);
10076
+ const keys = useItemKeys(item);
9991
10077
  const r = rectOf(item, drag);
9992
- const problems = useContext2(IssueMap).get(item.id);
10078
+ const problems = useContext3(IssueMap).get(item.id);
9993
10079
  const onHandle = (dir) => (e) => {
9994
10080
  e.preventDefault();
9995
10081
  e.stopPropagation();
@@ -10048,6 +10134,7 @@ function ItemView({ item, scale, drag, setDrag, bw, nest, section }) {
10048
10134
  title: problems?.join("\n"),
10049
10135
  style: { left: r.x * scale, top: r.y * scale, width: Math.max(r.w * scale, 2), height: Math.max(r.h * scale, 2) },
10050
10136
  onPointerDown: onDown,
10137
+ ...keys,
10051
10138
  children: [
10052
10139
  nest ? /* @__PURE__ */ jsx6(NestBox, { item: { ...item, ...r }, scale }) : /* @__PURE__ */ jsx6(ItemBody, { item: { ...item, ...r }, scale }),
10053
10140
  nest && /* @__PURE__ */ jsx6(NestChildren, { item, scale, drag, setDrag, section }),
@@ -10065,8 +10152,8 @@ function NestBox({ item, scale }) {
10065
10152
  }
10066
10153
  var LIVE = /* @__PURE__ */ new Set(["chart", "matrix", "barcode", "sparkline", "databar", "bullet", "iconset", "rangebar", "richtext"]);
10067
10154
  var measurer = null;
10068
- async function paintItemSvg(shape2, def, sample) {
10069
- const store = fontStore();
10155
+ async function paintItemSvg(shape2, def, sample, api = activeStore2()) {
10156
+ const store = await loadFontStore();
10070
10157
  await Promise.all([store.load(), customFonts()]);
10071
10158
  if (shape2.type === "barcode" || hasType(shape2.items, "barcode")) await loadBarcodes();
10072
10159
  measurer || (measurer = new TextMeasurer(store));
@@ -10077,7 +10164,7 @@ async function paintItemSvg(shape2, def, sample) {
10077
10164
  } catch {
10078
10165
  }
10079
10166
  const base2 = { fontFamily: "Inter", fontSize: 9, color: "#1f2937", padding: 2, lineHeight: 1.25, textAlign: "auto", verticalAlign: "top", ...def.styles?.base || {} };
10080
- 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);
10081
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 };
10082
10169
  let seq = 0;
10083
10170
  const lc = {
@@ -10119,6 +10206,7 @@ async function paintItemSvg(shape2, def, sample) {
10119
10206
  return { html: pageToSvg({ items }, shape2.w, h, { background: false }), h, w };
10120
10207
  }
10121
10208
  function LivePreview({ item, scale }) {
10209
+ const api = useDesignerStore();
10122
10210
  const sample = useDesigner((s) => s.sample);
10123
10211
  const def = useDesigner((s) => s.def);
10124
10212
  const [svg, setSvg] = useState4(null);
@@ -10128,11 +10216,11 @@ function LivePreview({ item, scale }) {
10128
10216
  let alive = true;
10129
10217
  const t3 = setTimeout(async () => {
10130
10218
  try {
10131
- const out = await paintItemSvg(shape2, def, sample);
10219
+ const out = await paintItemSvg(shape2, def, sample, api);
10132
10220
  if (alive) {
10133
10221
  setSvg(out);
10134
- const ex2 = useDesigner.getState().extents || {};
10135
- 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 } } });
10136
10224
  }
10137
10225
  } catch (e) {
10138
10226
  if (alive) setSvg({ error: e.message });
@@ -10266,17 +10354,18 @@ function TableView({ item, scale, drag, setDrag }) {
10266
10354
  const readOnly2 = useDesigner((s) => s.readOnly);
10267
10355
  const tableSelected = sel.kind === "items" && sel.ids.includes(item.id);
10268
10356
  const onGrip = useItemDrag(item, scale, setDrag);
10357
+ const keys = useItemKeys(item);
10269
10358
  const r = rectOf(item, drag);
10270
10359
  const widths2 = item.columns.map((c, i2) => drag?.mode === "col" && drag.id === item.id && drag.col === i2 ? drag.w : c.width);
10271
10360
  const [dropCell, setDropCell] = useState4(null);
10272
10361
  const [menu, setMenu] = useState4(null);
10273
- const problems = useContext2(IssueMap).get(item.id);
10274
- const tblRef = useRef2(null);
10362
+ const problems = useContext3(IssueMap).get(item.id);
10363
+ const tblRef = useRef3(null);
10275
10364
  const chosen = sel.kind === "cell" && sel.id === item.id ? selCells(sel) : [];
10276
10365
  useEffect3(() => {
10277
10366
  if (!menu) return void 0;
10278
10367
  const close = (e) => {
10279
- 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);
10280
10369
  };
10281
10370
  window.addEventListener("pointerdown", close, true);
10282
10371
  window.addEventListener("keydown", close);
@@ -10289,6 +10378,7 @@ function TableView({ item, scale, drag, setDrag }) {
10289
10378
  e.stopPropagation();
10290
10379
  if (e.button !== 0) return;
10291
10380
  e.preventDefault();
10381
+ e.currentTarget.closest("[data-item-key]")?.focus({ preventScroll: true });
10292
10382
  const st = useDesigner.getState();
10293
10383
  const here = { part, row: ri, col: ci };
10294
10384
  const cur2 = st.sel.kind === "cell" && st.sel.id === item.id ? st.sel : null;
@@ -10364,7 +10454,7 @@ function TableView({ item, scale, drag, setDrag }) {
10364
10454
  const h = t3.header?.[t3.header.length - 1]?.cells?.[ci];
10365
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());
10366
10456
  if (h && f.type === "number") h.style = { ...h.style || {}, textAlign: "right" };
10367
- } 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") {
10368
10458
  cell.value = `=Sum(Fields.${f.field})`;
10369
10459
  cell.style = { ...cell.style || {}, ...fieldStyle(f) };
10370
10460
  } else cell.value = `=Fields.${f.field}`;
@@ -10372,7 +10462,7 @@ function TableView({ item, scale, drag, setDrag }) {
10372
10462
  useDesigner.getState().select({ kind: "cell", id: item.id, part, row: ri, col: ci });
10373
10463
  };
10374
10464
  let first = true;
10375
- 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: [
10376
10466
  problems && /* @__PURE__ */ jsx6("div", { className: "issue-tag", title: problems.join("\n"), "aria-label": problems.join(". "), children: "!" }),
10377
10467
  /* @__PURE__ */ jsx6("div", { className: "grip", title: "Select or move the table", onPointerDown: onGrip, children: "⠿" }),
10378
10468
  /* @__PURE__ */ jsx6("div", { className: "col-handles", "aria-label": T("ux_columns"), role: "group", children: widths2.map((w, ci) => /* @__PURE__ */ jsx6(
@@ -10502,15 +10592,15 @@ function TableView({ item, scale, drag, setDrag }) {
10502
10592
  }
10503
10593
 
10504
10594
  // src/designer/Inspector.jsx
10505
- 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";
10506
10596
 
10507
10597
  // src/designer/ExpressionEditor.jsx
10508
- 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";
10509
10599
 
10510
10600
  // src/designer/ExprCode.jsx
10511
- import { forwardRef, useEffect as useEffect4, useImperativeHandle, useRef as useRef3 } from "react";
10601
+ import { forwardRef, useEffect as useEffect4, useImperativeHandle, useRef as useRef4 } from "react";
10512
10602
 
10513
- // ../reportwright/node_modules/@marijn/find-cluster-break/src/index.js
10603
+ // node_modules/@marijn/find-cluster-break/src/index.js
10514
10604
  var rangeFrom = [];
10515
10605
  var rangeTo = [];
10516
10606
  (() => {
@@ -10587,7 +10677,7 @@ function codePointSize(code2) {
10587
10677
  return code2 < 65536 ? 1 : 2;
10588
10678
  }
10589
10679
 
10590
- // ../reportwright/node_modules/@codemirror/state/dist/index.js
10680
+ // node_modules/@codemirror/state/dist/index.js
10591
10681
  var Text = class _Text {
10592
10682
  /**
10593
10683
  Get the line description around the given position.
@@ -12252,8 +12342,8 @@ var StateField = class _StateField {
12252
12342
  way it is initialized. Can be useful when you need to provide a
12253
12343
  non-default starting value for the field.
12254
12344
  */
12255
- init(create2) {
12256
- return [this, initField.of({ field: this, create: create2 })];
12345
+ init(create) {
12346
+ return [this, initField.of({ field: this, create })];
12257
12347
  }
12258
12348
  /**
12259
12349
  State field instances can be used as
@@ -13481,10 +13571,10 @@ var RangeSet = class _RangeSet {
13481
13571
  for (; ; ) {
13482
13572
  let curTo = Math.min(cursor.to, to);
13483
13573
  if (cursor.point) {
13484
- let active = cursor.activeForPoint(cursor.to);
13485
- let openCount = cursor.pointFrom < from ? active.length + 1 : cursor.point.startSide < 0 ? active.length : Math.min(active.length, openRanges);
13486
- iterator.point(pos, curTo, cursor.point, active, openCount, cursor.pointRank);
13487
- 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);
13488
13578
  } else if (curTo > pos) {
13489
13579
  iterator.span(pos, curTo, cursor.active, openRanges);
13490
13580
  openRanges = cursor.openEnd(curTo);
@@ -13898,14 +13988,14 @@ var SpanCursor = class {
13898
13988
  activeForPoint(to) {
13899
13989
  if (!this.active.length)
13900
13990
  return this.active;
13901
- let active = [];
13991
+ let active2 = [];
13902
13992
  for (let i2 = this.active.length - 1; i2 >= 0; i2--) {
13903
13993
  if (this.activeRank[i2] < this.pointRank)
13904
13994
  break;
13905
13995
  if (this.activeTo[i2] > to || this.activeTo[i2] == to && this.active[i2].endSide >= this.point.endSide)
13906
- active.push(this.active[i2]);
13996
+ active2.push(this.active[i2]);
13907
13997
  }
13908
- return active.reverse();
13998
+ return active2.reverse();
13909
13999
  }
13910
14000
  openEnd(to) {
13911
14001
  let open = 0;
@@ -13999,7 +14089,7 @@ function findColumn(string2, col, tabSize, strict) {
13999
14089
  return strict === true ? -1 : string2.length;
14000
14090
  }
14001
14091
 
14002
- // ../reportwright/node_modules/style-mod/src/style-mod.js
14092
+ // node_modules/style-mod/src/style-mod.js
14003
14093
  var C = "ͼ";
14004
14094
  var COUNT = typeof Symbol == "undefined" ? "__" + C : Symbol.for(C);
14005
14095
  var SET = typeof Symbol == "undefined" ? "__styleSet" + Math.floor(Math.random() * 1e8) : /* @__PURE__ */ Symbol("styleSet");
@@ -14135,7 +14225,7 @@ var StyleSet = class {
14135
14225
  }
14136
14226
  };
14137
14227
 
14138
- // ../reportwright/node_modules/w3c-keyname/index.js
14228
+ // node_modules/w3c-keyname/index.js
14139
14229
  var base = {
14140
14230
  8: "Backspace",
14141
14231
  9: "Tab",
@@ -14241,7 +14331,7 @@ function keyName(event) {
14241
14331
  return name2;
14242
14332
  }
14243
14333
 
14244
- // ../reportwright/node_modules/@codemirror/view/dist/index.js
14334
+ // node_modules/@codemirror/view/dist/index.js
14245
14335
  var nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
14246
14336
  var doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
14247
14337
  var ie_edge = /* @__PURE__ */ /Edge\/(\d+)/.exec(nav.userAgent);
@@ -15424,9 +15514,9 @@ var viewPlugin = /* @__PURE__ */ Facet.define({
15424
15514
  }
15425
15515
  });
15426
15516
  var ViewPlugin = class _ViewPlugin {
15427
- constructor(id, create2, domEventHandlers, domEventObservers, buildExtensions) {
15517
+ constructor(id, create, domEventHandlers, domEventObservers, buildExtensions) {
15428
15518
  this.id = id;
15429
- this.create = create2;
15519
+ this.create = create;
15430
15520
  this.domEventHandlers = domEventHandlers;
15431
15521
  this.domEventObservers = domEventObservers;
15432
15522
  this.baseExtensions = buildExtensions(this);
@@ -15442,9 +15532,9 @@ var ViewPlugin = class _ViewPlugin {
15442
15532
  Define a plugin from a constructor function that creates the
15443
15533
  plugin's value, given an editor view.
15444
15534
  */
15445
- static define(create2, spec) {
15535
+ static define(create, spec) {
15446
15536
  const { eventHandlers, eventObservers, provide, decorations: deco } = spec || {};
15447
- return new _ViewPlugin(nextPluginID++, create2, eventHandlers, eventObservers, (plugin) => {
15537
+ return new _ViewPlugin(nextPluginID++, create, eventHandlers, eventObservers, (plugin) => {
15448
15538
  let ext = [];
15449
15539
  if (deco)
15450
15540
  ext.push(decorations.of((view) => {
@@ -15532,11 +15622,11 @@ function getIsolatedRanges(view, line2) {
15532
15622
  RangeSet.spans(sets, line2.from, line2.to, {
15533
15623
  point() {
15534
15624
  },
15535
- span(fromDoc, toDoc, active, open) {
15625
+ span(fromDoc, toDoc, active2, open) {
15536
15626
  let from = fromDoc - line2.from, to = toDoc - line2.from;
15537
15627
  let level = result;
15538
- for (let i2 = active.length - 1; i2 >= 0; i2--, open--) {
15539
- 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;
15540
15630
  if (direction == null)
15541
15631
  direction = autoDirection(line2.text, from, to);
15542
15632
  if (open > 0 && level.length && (update = level[level.length - 1]).to == from && update.direction == direction) {
@@ -16766,7 +16856,7 @@ var TileUpdate = class {
16766
16856
  let pendingLineAttrs = null;
16767
16857
  let b = this.builder, markCount = -1;
16768
16858
  let openEnd = RangeSet.spans(this.decorations, from, to, {
16769
- point: (from2, to2, deco, active, openStart, index) => {
16859
+ point: (from2, to2, deco, active2, openStart, index) => {
16770
16860
  if (deco instanceof PointDecoration) {
16771
16861
  if (this.disallowBlockEffectsFor[index]) {
16772
16862
  if (deco.block)
@@ -16774,8 +16864,8 @@ var TileUpdate = class {
16774
16864
  if (to2 > this.view.state.doc.lineAt(from2).to)
16775
16865
  throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
16776
16866
  }
16777
- markCount = active.length;
16778
- if (openStart > active.length) {
16867
+ markCount = active2.length;
16868
+ if (openStart > active2.length) {
16779
16869
  b.continueWidget(to2 - from2);
16780
16870
  } else {
16781
16871
  let widget = deco.widget || (deco.block ? NullWidget.block : NullWidget.inline);
@@ -16787,7 +16877,7 @@ var TileUpdate = class {
16787
16877
  b.addBlockWidget(tile);
16788
16878
  } else {
16789
16879
  b.ensureLine(pendingLineAttrs);
16790
- b.addInlineWidget(tile, active, openStart);
16880
+ b.addInlineWidget(tile, active2, openStart);
16791
16881
  }
16792
16882
  }
16793
16883
  pendingLineAttrs = null;
@@ -16797,7 +16887,7 @@ var TileUpdate = class {
16797
16887
  if (to2 > from2)
16798
16888
  this.text.skip(to2 - from2);
16799
16889
  },
16800
- span: (from2, to2, active, openStart) => {
16890
+ span: (from2, to2, active2, openStart) => {
16801
16891
  for (let pos = from2; pos < to2; ) {
16802
16892
  let chars = this.text.next(Math.min(512, to2 - pos));
16803
16893
  if (chars == null) {
@@ -16806,12 +16896,12 @@ var TileUpdate = class {
16806
16896
  pos++;
16807
16897
  } else {
16808
16898
  b.ensureLine(pendingLineAttrs);
16809
- b.addText(chars, active, pos == from2 ? openStart : active.length);
16899
+ b.addText(chars, active2, pos == from2 ? openStart : active2.length);
16810
16900
  pos += chars.length;
16811
16901
  }
16812
16902
  pendingLineAttrs = null;
16813
16903
  }
16814
- markCount = active.length;
16904
+ markCount = active2.length;
16815
16905
  }
16816
16906
  });
16817
16907
  if (markCount > -1)
@@ -18800,9 +18890,9 @@ handlers.mousedown = (view, event) => {
18800
18890
  if (mustFocus)
18801
18891
  view.observer.ignore(() => {
18802
18892
  focusPreventScroll(view.contentDOM);
18803
- let active = view.root.activeElement;
18804
- if (active && !active.contains(view.contentDOM))
18805
- active.blur();
18893
+ let active2 = view.root.activeElement;
18894
+ if (active2 && !active2.contains(view.contentDOM))
18895
+ active2.blur();
18806
18896
  });
18807
18897
  let mouseSel = view.inputState.mouseSelection;
18808
18898
  if (mouseSel) {
@@ -23117,7 +23207,7 @@ GutterMarker.prototype.mapMode = MapMode.TrackBefore;
23117
23207
  GutterMarker.prototype.startSide = GutterMarker.prototype.endSide = -1;
23118
23208
  GutterMarker.prototype.point = true;
23119
23209
 
23120
- // ../reportwright/node_modules/@lezer/common/dist/index.js
23210
+ // node_modules/@lezer/common/dist/index.js
23121
23211
  var DefaultBufferLength = 1024;
23122
23212
  var nextPropID = 0;
23123
23213
  var Range2 = class {
@@ -24741,7 +24831,7 @@ var StringInput = class {
24741
24831
  };
24742
24832
  var stoppedInner = new NodeProp({ perNode: true });
24743
24833
 
24744
- // ../reportwright/node_modules/@lezer/highlight/dist/index.js
24834
+ // node_modules/@lezer/highlight/dist/index.js
24745
24835
  var nextTagID = 0;
24746
24836
  var Tag = class _Tag {
24747
24837
  /**
@@ -25465,7 +25555,7 @@ var classHighlighter = tagHighlighter([
25465
25555
  { tag: tags.punctuation, class: "tok-punctuation" }
25466
25556
  ]);
25467
25557
 
25468
- // ../reportwright/node_modules/@codemirror/language/dist/index.js
25558
+ // node_modules/@codemirror/language/dist/index.js
25469
25559
  var _a;
25470
25560
  var languageDataProp = /* @__PURE__ */ new NodeProp();
25471
25561
  function defineLanguageFacet(baseData) {
@@ -27092,7 +27182,7 @@ var marks = {
27092
27182
  auto: /* @__PURE__ */ Decoration.mark({ class: "cm-iso", inclusive: true, attributes: { dir: "auto" }, bidiIsolate: null })
27093
27183
  };
27094
27184
 
27095
- // ../reportwright/node_modules/@codemirror/commands/dist/index.js
27185
+ // node_modules/@codemirror/commands/dist/index.js
27096
27186
  var toggleComment = (target) => {
27097
27187
  let { state } = target, line2 = state.doc.lineAt(state.selection.main.from), config2 = getConfig(target.state, line2.from);
27098
27188
  return config2.line ? toggleLineComment(target) : config2.block ? toggleBlockCommentByLine(target) : false;
@@ -28186,7 +28276,7 @@ var defaultKeymap = /* @__PURE__ */ [
28186
28276
  { key: "Ctrl-m", mac: "Shift-Alt-m", run: toggleTabFocusMode }
28187
28277
  ].concat(standardKeymap);
28188
28278
 
28189
- // ../reportwright/node_modules/@codemirror/autocomplete/dist/index.js
28279
+ // node_modules/@codemirror/autocomplete/dist/index.js
28190
28280
  var CompletionContext = class {
28191
28281
  /**
28192
28282
  Create a new completion context. (Mostly useful for testing
@@ -28845,7 +28935,7 @@ function scrollIntoView2(container2, element) {
28845
28935
  function score(option) {
28846
28936
  return (option.boost || 0) * 100 + (option.apply ? 10 : 0) + (option.info ? 5 : 0) + (option.type ? 1 : 0);
28847
28937
  }
28848
- function sortOptions(active, state) {
28938
+ function sortOptions(active2, state) {
28849
28939
  let options = [];
28850
28940
  let sections = null, dynamicSectionScore = null;
28851
28941
  let addOption = (option) => {
@@ -28860,7 +28950,7 @@ function sortOptions(active, state) {
28860
28950
  }
28861
28951
  };
28862
28952
  let conf = state.facet(completionConfig);
28863
- for (let a of active)
28953
+ for (let a of active2)
28864
28954
  if (a.hasResult()) {
28865
28955
  let getMatch = a.result.getMatch;
28866
28956
  if (a.result.filter === false) {
@@ -28923,12 +29013,12 @@ var CompletionDialog = class _CompletionDialog {
28923
29013
  setSelected(selected, id) {
28924
29014
  return selected == this.selected || selected >= this.options.length ? this : new _CompletionDialog(this.options, makeAttrs(id, selected), this.tooltip, this.timestamp, selected, this.disabled);
28925
29015
  }
28926
- static build(active, state, id, prev, conf, didSetActive) {
28927
- 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))
28928
29018
  return prev.setDisabled();
28929
- let options = sortOptions(active, state);
29019
+ let options = sortOptions(active2, state);
28930
29020
  if (!options.length)
28931
- return prev && active.some((a) => a.isPending) ? prev.setDisabled() : null;
29021
+ return prev && active2.some((a) => a.isPending) ? prev.setDisabled() : null;
28932
29022
  let selected = state.facet(completionConfig).selectOnOpen ? 0 : -1;
28933
29023
  if (prev && prev.selected != selected && prev.selected != -1) {
28934
29024
  let selectedValue = prev.options[prev.selected].completion;
@@ -28939,7 +29029,7 @@ var CompletionDialog = class _CompletionDialog {
28939
29029
  }
28940
29030
  }
28941
29031
  return new _CompletionDialog(options, makeAttrs(id, selected), {
28942
- 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),
28943
29033
  create: createTooltip,
28944
29034
  above: conf.aboveCursor
28945
29035
  }, prev ? prev.timestamp : Date.now(), selected, false);
@@ -28952,8 +29042,8 @@ var CompletionDialog = class _CompletionDialog {
28952
29042
  }
28953
29043
  };
28954
29044
  var CompletionState = class _CompletionState {
28955
- constructor(active, id, open) {
28956
- this.active = active;
29045
+ constructor(active2, id, open) {
29046
+ this.active = active2;
28957
29047
  this.id = id;
28958
29048
  this.open = open;
28959
29049
  }
@@ -28963,7 +29053,7 @@ var CompletionState = class _CompletionState {
28963
29053
  update(tr) {
28964
29054
  let { state } = tr, conf = state.facet(completionConfig);
28965
29055
  let sources = conf.override || state.languageDataAt("autocomplete", cur(state)).map(asSource);
28966
- let active = sources.map((source) => {
29056
+ let active2 = sources.map((source) => {
28967
29057
  let value = this.active.find((s) => s.source == source) || new ActiveSource(
28968
29058
  source,
28969
29059
  this.active.some(
@@ -28974,17 +29064,17 @@ var CompletionState = class _CompletionState {
28974
29064
  );
28975
29065
  return value.update(tr, conf);
28976
29066
  });
28977
- if (active.length == this.active.length && active.every((a, i2) => a == this.active[i2]))
28978
- active = this.active;
29067
+ if (active2.length == this.active.length && active2.every((a, i2) => a == this.active[i2]))
29068
+ active2 = this.active;
28979
29069
  let open = this.open, didSet = tr.effects.some((e) => e.is(setActiveEffect));
28980
29070
  if (open && tr.docChanged)
28981
29071
  open = open.map(tr.changes);
28982
- if (tr.selection || active.some((a) => a.hasResult() && tr.changes.touchesRange(a.from, a.to)) || !sameResults(active, this.active) || didSet)
28983
- open = CompletionDialog.build(active, state, this.id, open, conf, didSet);
28984
- 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))
28985
29075
  open = null;
28986
- if (!open && active.every((a) => !a.isPending) && active.some((a) => a.hasResult()))
28987
- 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(
28988
29078
  a.source,
28989
29079
  0
28990
29080
  /* State.Inactive */
@@ -28992,7 +29082,7 @@ var CompletionState = class _CompletionState {
28992
29082
  for (let effect of tr.effects)
28993
29083
  if (effect.is(setSelectedEffect))
28994
29084
  open = open && open.setSelected(effect.value, this.id);
28995
- 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);
28996
29086
  }
28997
29087
  get tooltip() {
28998
29088
  return this.open ? this.open.tooltip : null;
@@ -29077,9 +29167,9 @@ var ActiveSource = class _ActiveSource {
29077
29167
  /* State.Inactive */
29078
29168
  );
29079
29169
  else if (effect.is(setActiveEffect)) {
29080
- for (let active of effect.value)
29081
- if (active.source == value.source)
29082
- value = active;
29170
+ for (let active2 of effect.value)
29171
+ if (active2.source == value.source)
29172
+ value = active2;
29083
29173
  }
29084
29174
  }
29085
29175
  return value;
@@ -29223,8 +29313,8 @@ var closeCompletion = (view) => {
29223
29313
  return true;
29224
29314
  };
29225
29315
  var RunningQuery = class {
29226
- constructor(active, context) {
29227
- this.active = active;
29316
+ constructor(active2, context) {
29317
+ this.active = active2;
29228
29318
  this.context = context;
29229
29319
  this.time = Date.now();
29230
29320
  this.updates = [];
@@ -29241,9 +29331,9 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29241
29331
  this.debounceAccept = -1;
29242
29332
  this.pendingStart = false;
29243
29333
  this.composing = 0;
29244
- for (let active of view.state.field(completionState).active)
29245
- if (active.isPending)
29246
- this.startQuery(active);
29334
+ for (let active2 of view.state.field(completionState).active)
29335
+ if (active2.isPending)
29336
+ this.startQuery(active2);
29247
29337
  }
29248
29338
  update(update) {
29249
29339
  let cState = update.state.field(completionState);
@@ -29288,19 +29378,19 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29288
29378
  this.debounceUpdate = -1;
29289
29379
  this.pendingStart = false;
29290
29380
  let { state } = this.view, cState = state.field(completionState);
29291
- for (let active of cState.active) {
29292
- if (active.isPending && !this.running.some((r) => r.active.source == active.source))
29293
- 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);
29294
29384
  }
29295
29385
  if (this.running.length && cState.open && cState.open.disabled)
29296
29386
  this.debounceAccept = setTimeout(() => this.accept(), this.view.state.facet(completionConfig).updateSyncTime);
29297
29387
  }
29298
- startQuery(active) {
29388
+ startQuery(active2) {
29299
29389
  let { state } = this.view, pos = cur(state);
29300
- let context = new CompletionContext(state, pos, active.explicit, this.view);
29301
- let pending2 = new RunningQuery(active, context);
29390
+ let context = new CompletionContext(state, pos, active2.explicit, this.view);
29391
+ let pending2 = new RunningQuery(active2, context);
29302
29392
  this.running.push(pending2);
29303
- Promise.resolve(active.source(context)).then((result) => {
29393
+ Promise.resolve(active2.source(context)).then((result) => {
29304
29394
  if (!pending2.context.aborted) {
29305
29395
  pending2.done = result || null;
29306
29396
  this.scheduleAccept();
@@ -29333,26 +29423,26 @@ var completionPlugin = /* @__PURE__ */ ViewPlugin.fromClass(class {
29333
29423
  if (query.done) {
29334
29424
  let pos = cur(query.updates.length ? query.updates[0].startState : this.view.state);
29335
29425
  let limit = Math.min(pos, query.done.from + (query.active.explicit ? 0 : 1));
29336
- 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);
29337
29427
  for (let tr of query.updates)
29338
- active = active.update(tr, conf);
29339
- if (active.hasResult()) {
29340
- updated.push(active);
29428
+ active2 = active2.update(tr, conf);
29429
+ if (active2.hasResult()) {
29430
+ updated.push(active2);
29341
29431
  continue;
29342
29432
  }
29343
29433
  }
29344
29434
  let current2 = cState.active.find((a) => a.source == query.active.source);
29345
29435
  if (current2 && current2.isPending) {
29346
29436
  if (query.done == null) {
29347
- let active = new ActiveSource(
29437
+ let active2 = new ActiveSource(
29348
29438
  query.active.source,
29349
29439
  0
29350
29440
  /* State.Inactive */
29351
29441
  );
29352
29442
  for (let tr of query.updates)
29353
- active = active.update(tr, conf);
29354
- if (!active.isPending)
29355
- updated.push(active);
29443
+ active2 = active2.update(tr, conf);
29444
+ if (!active2.isPending)
29445
+ updated.push(active2);
29356
29446
  } else {
29357
29447
  this.startQuery(current2);
29358
29448
  }
@@ -29810,9 +29900,9 @@ var theme2 = EditorView.theme({
29810
29900
  });
29811
29901
  var UNKNOWN = Decoration.mark({ class: "cm-unknown-field" });
29812
29902
  var ExprCode = forwardRef(function ExprCode2({ value, onChange, fields, parameters, invalid, check }, ref) {
29813
- const host = useRef3(null);
29814
- const view = useRef3(null);
29815
- 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 });
29816
29906
  latest2.current = { onChange, fields, parameters, check };
29817
29907
  useImperativeHandle(ref, () => ({
29818
29908
  insert(text) {
@@ -29918,7 +30008,7 @@ function ExpressionEditor({ value, dataSet, onSave, onClose, title }) {
29918
30008
  const def = useDesigner((s) => s.def);
29919
30009
  const sample = useDesigner((s) => s.sample);
29920
30010
  const [text, setText] = useState5(value ?? "");
29921
- const ta = useRef4(null);
30011
+ const ta = useRef5(null);
29922
30012
  const dsName = dataSet || def.dataSets?.[0]?.name;
29923
30013
  const ds = def.dataSets?.find((d) => d.name === dsName);
29924
30014
  const fields = fieldNames(ds).filter((n) => !(ds?.fields || []).some((f) => f.name === n && f.type === "object"));
@@ -30227,7 +30317,7 @@ function Inspector() {
30227
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;
30228
30318
  const scope = one ? one.dataSet || def.dataSets?.[0]?.name || null : void 0;
30229
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 || ""}`;
30230
- const ref = useRef5(null);
30320
+ const ref = useRef6(null);
30231
30321
  useLayoutEffect2(() => {
30232
30322
  const pane = ref.current?.closest(".dright");
30233
30323
  if (pane) pane.scrollTop = 0;
@@ -30256,9 +30346,9 @@ function Inspector() {
30256
30346
  expr && /* @__PURE__ */ jsx10(ExpressionEditor, { ...expr, onClose: () => setExpr(null) })
30257
30347
  ] });
30258
30348
  }
30259
- function Geo({ label, value, onChange }) {
30349
+ function Geo({ label, value, onChange, min }) {
30260
30350
  const unit = useDesigner((s) => s.unit);
30261
- 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))) }) });
30262
30352
  }
30263
30353
  function PropEditor({ p: spec, value, onChange, openExpr, dataSet, item }) {
30264
30354
  const T = useT3();
@@ -30361,17 +30451,18 @@ function PaletteEditor({ label, value, onChange }) {
30361
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)) })
30362
30452
  ] });
30363
30453
  }
30364
- var reportList = null;
30454
+ var reportLists = /* @__PURE__ */ new Map();
30365
30455
  function ReportPicker({ value, onChange }) {
30366
- const [list2, setList] = useState7(reportList || []);
30456
+ const [list2, setList] = useState7(() => reportLists.get(useDesigner.getState().embed?.server || "") || []);
30367
30457
  const listId = useState7(() => `reports-${Math.random().toString(36).slice(2, 8)}`)[0];
30368
30458
  useEffect5(() => {
30369
30459
  const embed = useDesigner.getState().embed;
30370
- if (reportList || embed && !embed.server) return;
30371
30460
  const server2 = embed?.server || "";
30461
+ if (reportLists.has(server2) || embed && !embed.server) return;
30372
30462
  fetch(`${server2}/api/reports`).then((r) => r.ok ? r.json() : []).then((l) => {
30373
- reportList = Array.isArray(l) ? l : [];
30374
- setList(reportList);
30463
+ const v = Array.isArray(l) ? l : [];
30464
+ reportLists.set(server2, v);
30465
+ setList(v);
30375
30466
  }).catch(() => {
30376
30467
  });
30377
30468
  }, []);
@@ -30457,8 +30548,8 @@ function ItemProps({ item, section, openExpr }) {
30457
30548
  /* @__PURE__ */ jsxs7("div", { className: "grid2", children: [
30458
30549
  /* @__PURE__ */ jsx10(Geo, { label: "X", value: item.x, onChange: (v) => setGeo("x", Math.max(0, v)) }),
30459
30550
  /* @__PURE__ */ jsx10(Geo, { label: "Y", value: item.y, onChange: (v) => setGeo("y", Math.max(0, v)) }),
30460
- item.type !== "table" && /* @__PURE__ */ jsx10(Geo, { label: T("i_width"), value: item.w, onChange: (v) => setGeo("w", Math.max(0, v)) }),
30461
- 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)) }),
30462
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" }) })
30463
30554
  ] }),
30464
30555
  /* @__PURE__ */ jsx10("div", { className: "hint", children: (() => {
@@ -30628,7 +30719,17 @@ function PivotEditor({ item, openExpr }) {
30628
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) }) })
30629
30720
  ] })
30630
30721
  ] }),
30631
- (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
+ " ",
30632
30733
  g.collapsible && /* @__PURE__ */ jsx10(Check, { label: T("pivotStartCollapsed"), checked: g.initiallyCollapsed, onChange: (v) => setK(list2, i2, "initiallyCollapsed", v) }),
30633
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 }) }),
30634
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 }) })
@@ -30654,7 +30755,7 @@ function PivotEditor({ item, openExpr }) {
30654
30755
  /* @__PURE__ */ jsxs7("div", { className: "grid2", children: [
30655
30756
  /* @__PURE__ */ jsx10(Field, { label: T("pivotLabel"), children: /* @__PURE__ */ jsx10(TextInput, { value: v.label || "", onChange: (x) => setK("values", i2, "label", x) }) }),
30656
30757
  /* @__PURE__ */ jsx10(Field, { label: T("pivotFormat"), children: /* @__PURE__ */ jsx10(TextInput, { value: v.format || "", onChange: (x) => setK("values", i2, "format", x), placeholder: "N0" }) }),
30657
- /* @__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`) }) })
30658
30759
  ] }),
30659
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 }) }),
30660
30761
  /* @__PURE__ */ jsx10(Field, { label: T("cellBookmark"), children: exprField("values", i2, "bookmark", v.bookmark, T("cellBookmark")) })
@@ -31003,14 +31104,16 @@ function VisualEditor({ cell, setCell, openExpr, dataSet }) {
31003
31104
  }
31004
31105
  var reportParams = /* @__PURE__ */ new Map();
31005
31106
  function useReportParams(id) {
31006
- 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);
31007
31109
  useEffect5(() => {
31008
31110
  if (!id || isDynamic(id)) {
31009
31111
  setList(null);
31010
31112
  return;
31011
31113
  }
31012
- if (reportParams.has(id)) {
31013
- setList(reportParams.get(id));
31114
+ const key2 = `${srv()} ${id}`;
31115
+ if (reportParams.has(key2)) {
31116
+ setList(reportParams.get(key2));
31014
31117
  return;
31015
31118
  }
31016
31119
  let alive = true;
@@ -31023,7 +31126,7 @@ function useReportParams(id) {
31023
31126
  fetch(`${server2}/api/reports/${encodeURIComponent(id)}`).then((r) => r.ok ? r.json() : null).then((r) => {
31024
31127
  const d = r?.definition || r;
31025
31128
  const ps = d && typeof d === "object" ? (d.parameters || []).map((p) => ({ name: p.name, required: !!p.required && p.default == null, prompt: p.prompt })) : null;
31026
- if (ps) reportParams.set(id, ps);
31129
+ if (ps) reportParams.set(key2, ps);
31027
31130
  if (alive) setList(ps);
31028
31131
  }).catch(() => {
31029
31132
  if (alive) setList(null);
@@ -32151,17 +32254,18 @@ function JoinAdder({ allCols, split, onAdd, T }) {
32151
32254
  import { Fragment as Fragment8, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
32152
32255
  var NAME2 = /^[A-Za-z_][\w]*$/;
32153
32256
  var noSourceKey = (def) => (def?.dataSources || []).length ? null : "r4_noDataSource";
32154
- async function loadSample() {
32155
- const { def } = useDesigner.getState();
32156
- 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 } });
32157
32261
  try {
32158
32262
  const params = resolveParameters(def, {});
32159
32263
  const sources = await loadSources(def, { params, baseUrl: origin(), sqlPreview: true, fetch: reportFetch(origin(), void 0, { sqlPreview: true }) });
32160
32264
  const ctx = { params, globals: { ExecutionTime: /* @__PURE__ */ new Date() }, dataSets: {}, fields: null, locale: def.locale, currency: def.currency, functions: functionTable(def) };
32161
32265
  const dataSets = buildDataSets(def, sources, ctx);
32162
- useDesigner.setState({ sample: { dataSets, sources, at: Date.now() } });
32266
+ api.setState({ sample: { dataSets, sources, at: Date.now() } });
32163
32267
  } catch (e) {
32164
- useDesigner.setState({ sample: { error: e.message } });
32268
+ api.setState({ sample: { error: e.message } });
32165
32269
  }
32166
32270
  }
32167
32271
  function DataPanel() {
@@ -32982,7 +33086,7 @@ function DataSetDialog({ index, onClose, onSaved }) {
32982
33086
  }
32983
33087
 
32984
33088
  // src/designer/Outline.jsx
32985
- import { useRef as useRef6, useState as useState11 } from "react";
33089
+ import { useRef as useRef7, useState as useState11 } from "react";
32986
33090
  import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
32987
33091
  var MIME = "application/x-pw-outline";
32988
33092
  function Outline() {
@@ -32993,9 +33097,30 @@ function Outline() {
32993
33097
  const T = (k, v) => t(lang2, k, v);
32994
33098
  const [drop, setDrop] = useState11(null);
32995
33099
  const [said, setSaid] = useState11("");
32996
- const dragged = useRef6(null);
32997
- const body = useRef6(null);
33100
+ const [cur2, setCur] = useState11(null);
33101
+ const dragged = useRef7(null);
33102
+ const body = useRef7(null);
32998
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
+ };
32999
33124
  const pick = (e, id) => {
33000
33125
  const st = useDesigner.getState();
33001
33126
  if (e.shiftKey && st.sel.kind === "items") {
@@ -33107,30 +33232,32 @@ function Outline() {
33107
33232
  };
33108
33233
  const rows = (list2, parent, depth, section) => list2.map((it, i2) => {
33109
33234
  const mark = drop && drop.id != null && drop.id === it.id ? ` drop-${drop.where}` : "";
33110
- return /* @__PURE__ */ jsxs11("li", { children: [
33235
+ return /* @__PURE__ */ jsxs11("li", { role: "none", children: [
33111
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: [
33112
33237
  !readOnly2 && /* @__PURE__ */ jsx14("span", { className: "grip", "aria-hidden": "true", children: "⠿" }),
33113
- /* @__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 }),
33114
33239
  /* @__PURE__ */ jsx14("span", { className: "ty", children: T(`item_${it.type}`) === `item_${it.type}` ? ITEMS[it.type]?.label || it.type : T(`item_${it.type}`) }),
33115
33240
  !readOnly2 && /* @__PURE__ */ jsxs11("span", { className: "act", style: { display: "inline-flex", gap: 2 }, children: [
33116
- /* @__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: "↑" }),
33117
- /* @__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: "↓" }),
33118
- 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: "⇱" })
33119
33244
  ] })
33120
33245
  ] }),
33121
- 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) })
33122
33247
  ] }, it.id);
33123
33248
  });
33124
33249
  return /* @__PURE__ */ jsxs11("div", { className: "pane", "data-testid": "outline", children: [
33125
33250
  /* @__PURE__ */ jsx14("h4", { children: T("outline") }),
33126
33251
  /* @__PURE__ */ jsxs11("div", { className: "pane-body", ref: body, children: [
33127
- 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 }) => {
33128
33253
  const items = secOf(def, key2)?.items || [];
33129
- return /* @__PURE__ */ jsxs11("div", { className: `outline-sec${drop?.band === key2 ? " drop-band" : ""}`, "data-outline-band": key2, ...bandDrop(key2), children: [
33130
- /* @__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 }) }),
33131
- /* @__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") }) })
33132
33258
  ] }, key2);
33133
- }),
33259
+ }) }),
33260
+ /* @__PURE__ */ jsx14("div", { className: "sr-only", id: "outline-nav", children: T("b9_outlineKeys") }),
33134
33261
  /* @__PURE__ */ jsx14("div", { className: "hint", children: T("outlineHint") }),
33135
33262
  !readOnly2 && /* @__PURE__ */ jsx14("div", { className: "hint", id: "outline-keys", children: T("outlineKeys") }),
33136
33263
  /* @__PURE__ */ jsx14("div", { className: "sr-only", role: "status", "aria-live": "polite", children: said })
@@ -33555,6 +33682,7 @@ function TableWizard() {
33555
33682
  const wiz = useDesigner((s) => s.tableWizard);
33556
33683
  const def = useDesigner((s) => s.def);
33557
33684
  const sample = useDesigner((s) => s.sample);
33685
+ const lang2 = useDesigner((s) => s.lang);
33558
33686
  const close = () => useDesigner.getState().setUi({ tableWizard: null });
33559
33687
  const parent = wiz?.parentId ? findItem(def, wiz.parentId)?.item : null;
33560
33688
  const width = Math.max(120, Math.round((parent ? parent.w : bodyWidth(def, wiz?.section || "body")) - (wiz?.x || 0)));
@@ -33621,7 +33749,7 @@ function TableWizard() {
33621
33749
  /* @__PURE__ */ jsxs14("button", { className: "btn ghost", onClick: () => {
33622
33750
  useDesigner.getState().setUi({ tableWizard: null, pivotWizard: { section: wiz.section, x: wiz.x, y: wiz.y, parentId: wiz.parentId, dataSet: c.dataSet } });
33623
33751
  }, "data-testid": "open-pivot-wizard", children: [
33624
- t(useDesigner.getState().lang, "pivotWizard"),
33752
+ t(lang2, "pivotWizard"),
33625
33753
  "…"
33626
33754
  ] }),
33627
33755
  /* @__PURE__ */ jsx17("button", { className: "btn", onClick: close, children: "Cancel" }),
@@ -33634,7 +33762,7 @@ function TableWizard() {
33634
33762
  /* @__PURE__ */ jsxs14("section", { className: "cw-side", "aria-label": "Data for the table", children: [
33635
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: "" }) }) }),
33636
33764
  sample?.loading && /* @__PURE__ */ jsx17("span", { className: "hint", children: "Calling the API…" }),
33637
- 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)) }),
33638
33766
  sample?.error && /* @__PURE__ */ jsx17("span", { className: "err", children: sample.error }),
33639
33767
  c.layout !== "matrix" && /* @__PURE__ */ jsxs14(Fragment10, { children: [
33640
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 }) }) }),
@@ -33696,7 +33824,7 @@ function AskAi({ onClose }) {
33696
33824
  let preview = null;
33697
33825
  try {
33698
33826
  const params = resolveParameters(out.definition, {}, { lenient: true });
33699
- 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()) });
33700
33828
  preview = { html: pageToSvg(model.pages[0], model.width, model.height), pages: model.pages.length };
33701
33829
  } catch (e) {
33702
33830
  preview = { error: e.message };
@@ -34168,9 +34296,10 @@ var TOOLS = [
34168
34296
  ] }) }
34169
34297
  ];
34170
34298
  function Toolbox({ T, hide = [] }) {
34299
+ const api = useDesignerStore();
34171
34300
  const name2 = (type) => T(`item_${type}`) === `item_${type}` ? ITEMS[type].label : T(`item_${type}`);
34172
34301
  const add = (type) => {
34173
- const s = useDesigner.getState();
34302
+ const s = api.getState();
34174
34303
  const at2 = insertSpot(s.def, s.sel);
34175
34304
  insertItem(type, at2.section, 0, at2.y, {}, at2.parentId);
34176
34305
  };
@@ -34219,12 +34348,15 @@ var TbGroup = ({ label, children }) => /* @__PURE__ */ jsxs17("div", { className
34219
34348
  ] });
34220
34349
  var QUICK = [["textbox", "text"], ["table", "table"], ["chart", "chart"], ["image", "image"]];
34221
34350
  function LeftRail({ T, readOnly: readOnly2, embed }) {
34222
- const body = useRef7(null);
34351
+ const body = useRef8(null);
34223
34352
  const [at2, setAt] = useState17("tools");
34224
34353
  const tabs = [!readOnly2 && ["tools", "b2_toolbox", "tools"], embed?.panels?.data !== false && ["data", "b2_data", "data"], ["outline", "b2_outline", "outline"]].filter(Boolean);
34225
34354
  const go = (id) => {
34226
34355
  const el = body.current?.querySelector(`[data-rail="${id}"]`);
34227
- 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
+ }
34228
34360
  setAt(id);
34229
34361
  };
34230
34362
  const spy = () => {
@@ -34326,6 +34458,7 @@ var framed = () => {
34326
34458
  }
34327
34459
  };
34328
34460
  function useAutosave(id, T, lang2, user) {
34461
+ const api = useDesignerStore();
34329
34462
  const [offer, setOffer] = useState17(null);
34330
34463
  useEffect13(() => {
34331
34464
  if (!id || user == null || framed()) return void 0;
@@ -34337,10 +34470,10 @@ function useAutosave(id, T, lang2, user) {
34337
34470
  }
34338
34471
  clearDrafts(store, user);
34339
34472
  const d = readDraft(store, user, id);
34340
- 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);
34341
34474
  else if (d) clearDraft(store, user, id);
34342
34475
  const keep = () => {
34343
- const s = useDesigner.getState();
34476
+ const s = api.getState();
34344
34477
  if (!s.saved && !s.readOnly) writeDraft(store, user, id, s.def, Date.now(), s.rev || null);
34345
34478
  };
34346
34479
  const t3 = setInterval(keep, AUTOSAVE_MS);
@@ -34349,7 +34482,7 @@ function useAutosave(id, T, lang2, user) {
34349
34482
  };
34350
34483
  window.addEventListener("pagehide", keep);
34351
34484
  document.addEventListener("visibilitychange", hide);
34352
- const unsub = useDesigner.subscribe((s, prev) => {
34485
+ const unsub = api.subscribe((s, prev) => {
34353
34486
  if (s.saved && !prev.saved) clearDraft(store, user, id);
34354
34487
  });
34355
34488
  return () => {
@@ -34361,13 +34494,13 @@ function useAutosave(id, T, lang2, user) {
34361
34494
  }, [id, user]);
34362
34495
  if (!offer) return null;
34363
34496
  const when = new Date(offer.at).toLocaleString(lang2 === "en" ? "en-IN" : lang2, { dateStyle: "medium", timeStyle: "short" });
34364
- const stale = staleDraft(offer, useDesigner.getState().rev);
34497
+ const stale = staleDraft(offer, api.getState().rev);
34365
34498
  return /* @__PURE__ */ jsxs17("div", { className: "draft-bar", role: "alert", "data-testid": "draft-offer", "data-stale": stale || void 0, children: [
34366
34499
  /* @__PURE__ */ jsx20("span", { children: T(stale ? "ux_draftStale" : "ux_draftFound", { when }) }),
34367
34500
  /* @__PURE__ */ jsx20("button", { className: `btn sm${stale ? "" : " primary"}`, "data-testid": "draft-restore", onClick: () => {
34368
- const d = mergeDraft(offer.def, useDesigner.getState().def);
34369
- useDesigner.getState().apply(() => JSON.parse(JSON.stringify(d)));
34370
- 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();
34371
34504
  setOffer(null);
34372
34505
  }, children: T(stale ? "ux_draftRestoreAnyway" : "ux_draftRestore") }),
34373
34506
  /* @__PURE__ */ jsx20("button", { className: "btn sm", "data-testid": "draft-discard", onClick: () => {
@@ -34380,12 +34513,13 @@ function useAutosave(id, T, lang2, user) {
34380
34513
  ] });
34381
34514
  }
34382
34515
  function ConflictBar({ T }) {
34516
+ const api = useDesignerStore();
34383
34517
  const conflict = useDesigner((s) => s.conflict);
34384
34518
  if (!conflict) return null;
34385
34519
  return /* @__PURE__ */ jsxs17("div", { className: "draft-bar", role: "alert", "data-testid": "save-conflict", children: [
34386
34520
  /* @__PURE__ */ jsx20("span", { children: T("ux_conflict") }),
34387
- /* @__PURE__ */ jsx20("button", { className: "btn sm", "data-testid": "conflict-mine", onClick: () => useDesigner.getState().save({ overwrite: true }), children: T("ux_conflictMine") }),
34388
- /* @__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") })
34389
34523
  ] });
34390
34524
  }
34391
34525
  var AL = (d) => /* @__PURE__ */ jsx20("svg", { width: "16", height: "14", viewBox: "0 0 16 14", "aria-hidden": "true", children: d });
@@ -34450,12 +34584,13 @@ function AlignBar({ T }) {
34450
34584
  ] });
34451
34585
  }
34452
34586
  function IssuesButton({ T }) {
34587
+ const api = useDesignerStore();
34453
34588
  const issues = useDesignIssues();
34454
34589
  const [open, setOpen] = useState17(false);
34455
34590
  useEffect13(() => {
34456
34591
  if (!issues.length) setOpen(false);
34457
34592
  }, [issues.length]);
34458
- const listRef = useRef7(null);
34593
+ const listRef = useRef8(null);
34459
34594
  useLayoutEffect3(() => {
34460
34595
  const el = listRef.current;
34461
34596
  if (!el) return void 0;
@@ -34473,7 +34608,7 @@ function IssuesButton({ T }) {
34473
34608
  return /* @__PURE__ */ jsxs17("span", { className: "issues-wrap", children: [
34474
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 }) }),
34475
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: () => {
34476
- if (i2.id) useDesigner.getState().select({ kind: "items", ids: [i2.id] });
34611
+ if (i2.id) api.getState().select({ kind: "items", ids: [i2.id] });
34477
34612
  }, children: issueLine(T, i2) }) }, k)) })
34478
34613
  ] });
34479
34614
  }
@@ -34497,6 +34632,7 @@ var SHORTCUTS = [
34497
34632
  ["?", "sc_help"]
34498
34633
  ];
34499
34634
  function HistoryDialog({ id, onClose, T, lang: lang2 }) {
34635
+ const api = useDesignerStore();
34500
34636
  const [list2, setList] = useState17(null);
34501
34637
  const [err, setErr] = useState17(null);
34502
34638
  useEffect13(() => {
@@ -34509,7 +34645,7 @@ function HistoryDialog({ id, onClose, T, lang: lang2 }) {
34509
34645
  return;
34510
34646
  }
34511
34647
  const def = await res.json();
34512
- useDesigner.getState().init(id, def);
34648
+ api.getState().init(id, def);
34513
34649
  onClose();
34514
34650
  };
34515
34651
  return /* @__PURE__ */ jsxs17(Dialog, { title: T("versionHistory"), onClose, footer: /* @__PURE__ */ jsx20("button", { className: "btn", onClick: onClose, children: T("close") }), children: [
@@ -34531,18 +34667,48 @@ function HistoryDialog({ id, onClose, T, lang: lang2 }) {
34531
34667
  ] }, v.version))
34532
34668
  ] });
34533
34669
  }
34534
- 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]);
34535
34701
  const lang2 = pickLang(langIn);
34536
34702
  const T = (k, v) => t(lang2, k, v);
34537
34703
  const q2 = lang2 === "en" ? "" : `?lang=${encodeURIComponent(lang2)}`;
34538
- const ready = useRef7(false);
34704
+ const ready = useRef8(false);
34539
34705
  if (!ready.current && typeof window !== "undefined") {
34540
- useDesigner.getState().init(id, initial);
34541
- 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 });
34542
34708
  ready.current = true;
34543
34709
  }
34544
34710
  const readOnly2 = !!embed?.readOnly;
34545
- const rootRef = useRef7(null);
34711
+ const rootRef = useRef8(null);
34546
34712
  const def = useDesigner((s) => s.def);
34547
34713
  const tab = useDesigner((s) => s.tab);
34548
34714
  const saved = useDesigner((s) => s.saved);
@@ -34557,15 +34723,15 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34557
34723
  if (embed) declareDocumentStyles("pw-designer-fonts", fontCss);
34558
34724
  }, [embed, fontCss]);
34559
34725
  useEffect13(() => {
34560
- customFonts().then((list2) => useDesigner.getState().setUi({ fonts: list2 }));
34726
+ customFonts().then((list2) => api.getState().setUi({ fonts: list2 }));
34561
34727
  }, []);
34562
34728
  useEffect13(() => {
34563
34729
  const z = savedZoom();
34564
- if (z != null) useDesigner.getState().setUi({ zoom: z });
34730
+ if (z != null) api.getState().setUi({ zoom: z });
34565
34731
  }, []);
34566
34732
  const canUndo = useDesigner((s) => s.past.length > 0);
34567
34733
  const canRedo = useDesigner((s) => s.future.length > 0);
34568
- const st = useDesigner.getState;
34734
+ const st = api.getState;
34569
34735
  const [dialog, setDialog] = useState17(null);
34570
34736
  const [showLeft, setShowLeft] = useState17(true);
34571
34737
  const [showRight, setShowRight] = useState17(true);
@@ -34578,11 +34744,17 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34578
34744
  const cellSize = useDesigner((s) => s.cellSize);
34579
34745
  const dataKey = useDesigner((s) => `${(s.def?.dataSources || []).map((x) => x.name)}|${(s.def?.dataSets || []).map((x) => x.name)}`);
34580
34746
  useEffect13(() => {
34581
- loadSample();
34747
+ loadSample(api);
34582
34748
  }, [dataKey]);
34583
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);
34584
34756
  const onKey = (e) => {
34585
- if (embed && !(e.composedPath?.() || []).includes(rootRef.current)) return;
34757
+ if (embed && !ours(e)) return;
34586
34758
  const mod = e.metaKey || e.ctrlKey;
34587
34759
  if (mod && e.key.toLowerCase() === "s") {
34588
34760
  e.preventDefault();
@@ -34601,7 +34773,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34601
34773
  st().save();
34602
34774
  return;
34603
34775
  }
34604
- if (isTyping(e) || st().tab !== "design") return;
34776
+ if (isTyping(e) || st().tab !== "design" || e.defaultPrevented) return;
34605
34777
  if (mod && e.key.toLowerCase() === "z") {
34606
34778
  e.preventDefault();
34607
34779
  e.shiftKey ? st().redo() : st().undo();
@@ -34624,11 +34796,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34624
34796
  }
34625
34797
  return;
34626
34798
  }
34627
- if (mod && e.key.toLowerCase() === "v") {
34628
- e.preventDefault();
34629
- pasteItems(st().sel.kind === "section" ? st().sel.section : "body");
34630
- return;
34631
- }
34799
+ if (mod && e.key.toLowerCase() === "v") return;
34632
34800
  if (e.key === "Delete" || e.key === "Backspace") {
34633
34801
  if (st().sel.kind === "items") {
34634
34802
  e.preventDefault();
@@ -34660,10 +34828,24 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34660
34828
  e.returnValue = "";
34661
34829
  }
34662
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
+ };
34663
34839
  window.addEventListener("keydown", onKey);
34840
+ window.addEventListener("paste", onPaste);
34841
+ window.addEventListener("pointerdown", onDown, true);
34842
+ window.addEventListener("focusin", onDown, true);
34664
34843
  if (!embed) window.addEventListener("beforeunload", onLeave);
34665
34844
  return () => {
34666
34845
  window.removeEventListener("keydown", onKey);
34846
+ window.removeEventListener("paste", onPaste);
34847
+ window.removeEventListener("pointerdown", onDown, true);
34848
+ window.removeEventListener("focusin", onDown, true);
34667
34849
  window.removeEventListener("beforeunload", onLeave);
34668
34850
  };
34669
34851
  }, [st, embed]);
@@ -34682,17 +34864,17 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34682
34864
  const d = await embed.onOpen();
34683
34865
  if (d && typeof d === "object") {
34684
34866
  st().init(id, d);
34685
- loadSample();
34867
+ loadSample(api);
34686
34868
  }
34687
34869
  };
34688
- const importInput = useRef7(null);
34870
+ const importInput = useRef8(null);
34689
34871
  const [imported, setImported] = useState17(null);
34690
34872
  const importFile = async (file) => {
34691
34873
  if (!file) return;
34692
34874
  const r = readReportFile(file.name, await file.text());
34693
34875
  if (r.definition) {
34694
34876
  st().init(id, r.definition);
34695
- loadSample();
34877
+ loadSample(api);
34696
34878
  }
34697
34879
  setImported({ name: file.name, ok: !!r.definition, warnings: r.warnings || [], error: r.error });
34698
34880
  };
@@ -34706,7 +34888,7 @@ function Designer({ id, initial, rev = null, lang: langIn, embed = null, user =
34706
34888
  ] }),
34707
34889
  /* @__PURE__ */ jsx20("span", { className: "hint", children: T("loadingDesigner") })
34708
34890
  ] }) });
34709
- 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: [
34710
34892
  !embed && /* @__PURE__ */ jsx20("style", { children: fontCss }),
34711
34893
  /* @__PURE__ */ jsxs17("header", { className: "dtop dbar", children: [
34712
34894
  embed ? /* @__PURE__ */ jsxs17("span", { className: "brand", children: [
@@ -34894,6 +35076,7 @@ var CSS2 = true ? `/* Layout: a drafting table. Cool grey workspace, white paper
34894
35076
  --ink: #16202a;
34895
35077
  --muted: #5f6b77;
34896
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) */
34897
35080
  --line-strong: #848f9b; /* control borders, 3:1 */
34898
35081
  --accent: #0e7490;
34899
35082
  --accent-ink: #ffffff;
@@ -34947,6 +35130,7 @@ var CSS2 = true ? `/* Layout: a drafting table. Cool grey workspace, white paper
34947
35130
  --ink: #e6edf3;
34948
35131
  --muted: #a3afbb;
34949
35132
  --faint: #8693a0;
35133
+ --faint-desk: #8693a0;
34950
35134
  --accent: #3cbfd4;
34951
35135
  --accent-ink: #03222a;
34952
35136
  --accent-soft: #123a44;
@@ -35285,7 +35469,7 @@ a.cell-name:hover { color: var(--accent); }
35285
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); }
35286
35470
  .tbl.sel .grip { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
35287
35471
  .tbl .row { position: relative; display: flex; }
35288
- .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%; }
35289
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; }
35290
35474
  .tbl .cell:first-child { border-left: 1px dashed rgba(95,107,119,.3); }
35291
35475
  .tbl .row:first-child .cell { border-top: 1px dashed rgba(95,107,119,.3); }
@@ -35427,6 +35611,7 @@ a.cell-name:hover { color: var(--accent); }
35427
35611
  .vfrozen-head { position: absolute; top: 0; background: var(--paper); box-shadow: 0 3px 8px rgba(16, 24, 40, .18); pointer-events: none; }
35428
35612
  .vfrozen-head svg { display: block; width: 100%; height: 100%; }
35429
35613
  .search .opt { font-size: var(--fs-xs); font-weight: var(--fw-strong); }
35614
+ .search .opt .ww::before { content: "ab"; text-decoration: underline; } /* CSS, not text: the name is "Whole word" alone */
35430
35615
  .search .opt[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
35431
35616
  .vmatches button { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
35432
35617
  .vmatches button[aria-current] { background: var(--accent-soft); color: var(--accent); }
@@ -35804,13 +35989,14 @@ input[type=checkbox], input[type=radio] { width: 16px; height: 16px; accent-colo
35804
35989
 
35805
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}
35806
35991
  ` : "";
35807
- 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: [] } } };
35808
35993
  function mountDesigner(target, opts = {}) {
35809
35994
  const el = typeof target === "string" ? document.querySelector(target) : target;
35810
35995
  if (!el) throw new Error(`mountDesigner: no element for ${target}`);
35811
35996
  const server2 = String(opts.server || "").replace(/\/$/, "");
35812
35997
  setAssetBase(server2);
35813
35998
  setStandalone({ standalone: !server2, fontsUrl: opts.fontsUrl });
35999
+ setFetchPolicy({ allowHosts: opts.allowHosts, unsafeFetch: opts.unsafeFetch, fetch: opts.fetch });
35814
36000
  if (server2) declareDocumentStyles("pw-embed-fonts", uiFontCss(server2), opts.nonce);
35815
36001
  const shadow = el.shadowRoot || el.attachShadow({ mode: "open" });
35816
36002
  shadow.innerHTML = '<div class="pw-embed"></div>';
@@ -35821,18 +36007,43 @@ function mountDesigner(target, opts = {}) {
35821
36007
  );
35822
36008
  box.style.height = opts.height || "760px";
35823
36009
  const root = createRoot(box);
36010
+ const store = newDesignerStore();
35824
36011
  const embed = { onSave: opts.onSave, onOpen: opts.onOpen, readOnly: !!opts.readOnly, toolbox: opts.toolbox, panels: opts.panels, dataSourceTemplates: opts.dataSourceTemplates, server: server2 };
35825
36012
  const show = (definition) => loadLanguage(opts.lang).catch(() => {
35826
- }).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 })));
35827
36014
  if (opts.definition || !opts.report) show(opts.definition || BLANK);
35828
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) => {
35829
36016
  box.innerHTML = `<div class="vmsg error">The report did not load: ${String(e.message).replace(/</g, "&lt;")}</div>`;
35830
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
+ });
35831
36036
  return {
35832
- 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,
35833
36044
  /** the definition as it is now (a plain copy) */
35834
- getDefinition: () => JSON.parse(JSON.stringify(useDesigner.getState().def)),
35835
- save: () => useDesigner.getState().save()
36045
+ getDefinition: () => JSON.parse(JSON.stringify(store.getState().def)),
36046
+ save: () => store.getState().save()
35836
36047
  };
35837
36048
  }
35838
36049
  export {