@reportwright/viewer 0.13.1 → 0.13.2-rc.2

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 (56) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +146 -5
  3. package/dist/{chunk-B5ZCT3UK.js → chunk-4XZRLUHN.js} +73 -46
  4. package/dist/{chunk-B5ZCT3UK.js.map → chunk-4XZRLUHN.js.map} +2 -2
  5. package/dist/{chunk-XXTAPZO4.js → chunk-D7S5DL46.js} +2 -2
  6. package/dist/{chunk-ES2LYZ6S.js → chunk-DVJYE7HZ.js} +3 -3
  7. package/dist/chunk-GOCWG6FG.js +12 -12
  8. package/dist/chunk-GRYITZPG.js +23 -23
  9. package/dist/chunk-H422SRD3.js +21 -21
  10. package/dist/{chunk-PF4RFKX2.js → chunk-NARXO3DB.js} +3 -3
  11. package/dist/{chunk-PKXTMC4J.js → chunk-OED3YZYP.js} +5 -5
  12. package/dist/{chunk-ZGRJJ6OW.js → chunk-OMCWZYRI.js} +32 -17
  13. package/dist/chunk-OMCWZYRI.js.map +6 -0
  14. package/dist/chunk-U2ZY2NPQ.js +2 -2
  15. package/dist/designer.js +331 -135
  16. package/dist/designer.js.map +3 -3
  17. package/dist/engine.worker.bwip.js +4780 -51421
  18. package/dist/engine.worker.bwip.js.map +3 -3
  19. package/dist/engine.worker.js +5675 -59626
  20. package/dist/engine.worker.js.map +3 -3
  21. package/dist/pdfstreamworker.js +4 -0
  22. package/dist/peer/{chunk-7IP67PA6.js → chunk-4AFSC6JI.js} +48 -21
  23. package/dist/peer/{chunk-7IP67PA6.js.map → chunk-4AFSC6JI.js.map} +1 -1
  24. package/dist/peer/chunk-A6UXBSTP.js +21 -21
  25. package/dist/peer/{chunk-3EYYRJR4.js → chunk-FN3FXACD.js} +3 -3
  26. package/dist/peer/{chunk-WVQQCD4M.js → chunk-ILBTPBOA.js} +32 -17
  27. package/dist/peer/chunk-ILBTPBOA.js.map +6 -0
  28. package/dist/peer/{chunk-3XZY54LM.js → chunk-JQDW5OR3.js} +5 -5
  29. package/dist/peer/chunk-MXR6JBMP.js +2 -2
  30. package/dist/peer/chunk-N42DCZZA.js +12 -12
  31. package/dist/peer/{chunk-RKFP7SDY.js → chunk-OUTKMWFM.js} +3 -3
  32. package/dist/peer/{chunk-5RUNOIS7.js → chunk-VJLMUGUI.js} +2 -2
  33. package/dist/peer/chunk-ZS3J4WBH.js +23 -23
  34. package/dist/peer/designer.js +317 -122
  35. package/dist/peer/designer.js.map +3 -3
  36. package/dist/peer/engine.worker.bwip.js +4780 -51421
  37. package/dist/peer/engine.worker.bwip.js.map +3 -3
  38. package/dist/peer/engine.worker.js +5675 -59626
  39. package/dist/peer/engine.worker.js.map +3 -3
  40. package/dist/peer/pdfstreamworker.js +4 -0
  41. package/dist/peer/viewer.js +41 -9
  42. package/dist/peer/viewer.js.map +1 -1
  43. package/dist/viewer.d.ts +2 -0
  44. package/dist/viewer.js +41 -9
  45. package/dist/viewer.js.map +1 -1
  46. package/package.json +1 -1
  47. package/dist/chunk-ZGRJJ6OW.js.map +0 -6
  48. package/dist/peer/chunk-WVQQCD4M.js.map +0 -6
  49. /package/dist/{chunk-XXTAPZO4.js.map → chunk-D7S5DL46.js.map} +0 -0
  50. /package/dist/{chunk-ES2LYZ6S.js.map → chunk-DVJYE7HZ.js.map} +0 -0
  51. /package/dist/{chunk-PF4RFKX2.js.map → chunk-NARXO3DB.js.map} +0 -0
  52. /package/dist/{chunk-PKXTMC4J.js.map → chunk-OED3YZYP.js.map} +0 -0
  53. /package/dist/peer/{chunk-3EYYRJR4.js.map → chunk-FN3FXACD.js.map} +0 -0
  54. /package/dist/peer/{chunk-3XZY54LM.js.map → chunk-JQDW5OR3.js.map} +0 -0
  55. /package/dist/peer/{chunk-RKFP7SDY.js.map → chunk-OUTKMWFM.js.map} +0 -0
  56. /package/dist/peer/{chunk-5RUNOIS7.js.map → chunk-VJLMUGUI.js.map} +0 -0
@@ -10,7 +10,7 @@ import {
10
10
  setShadowStyles,
11
11
  t,
12
12
  uiFontCss
13
- } from "./chunk-7IP67PA6.js";
13
+ } from "./chunk-4AFSC6JI.js";
14
14
  import {
15
15
  customFonts,
16
16
  fontsBase,
@@ -21,7 +21,7 @@ import {
21
21
  setAssetBase,
22
22
  setFetchPolicy,
23
23
  setStandalone
24
- } from "./chunk-RKFP7SDY.js";
24
+ } from "./chunk-OUTKMWFM.js";
25
25
  import {
26
26
  BASE_STYLE,
27
27
  DEFAULT_THEME,
@@ -66,7 +66,7 @@ import {
66
66
  validate,
67
67
  withPartProps,
68
68
  xmlRowPaths
69
- } from "./chunk-WVQQCD4M.js";
69
+ } from "./chunk-ILBTPBOA.js";
70
70
  import {
71
71
  PAGE_SIZES,
72
72
  fromPt,
@@ -107,13 +107,13 @@ function toPt2(v, fallback = 0) {
107
107
  (m[2] || "pt").toLowerCase()
108
108
  ]) : fallback;
109
109
  }
110
- var NAMED = Object.fromEntries("aliceblue:f0f8ff,antiquewhite:faebd7,aqua:00ffff,aquamarine:7fffd4,azure:f0ffff,beige:f5f5dc,bisque:ffe4c4,black:000000,blanchedalmond:ffebcd,blue:0000ff,blueviolet:8a2be2,brown:a52a2a,burlywood:deb887,cadetblue:5f9ea0,chartreuse:7fff00,chocolate:d2691e,coral:ff7f50,cornflowerblue:6495ed,cornsilk:fff8dc,crimson:dc143c,cyan:00ffff,darkblue:00008b,darkcyan:008b8b,dark\
111
- goldenrod:b8860b,darkgray:a9a9a9,darkgreen:006400,darkgrey:a9a9a9,darkkhaki:bdb76b,darkmagenta:8b008b,darkolivegreen:556b2f,darkorange:ff8c00,darkorchid:9932cc,darkred:8b0000,darksalmon:e9967a,darkseagreen:8fbc8f,darkslateblue:483d8b,darkslategray:2f4f4f,darkslategrey:2f4f4f,darkturquoise:00ced1,darkviolet:9400d3,deeppink:ff1493,deepskyblue:00bfff,dimgray:696969,dimgrey:696969,dodgerblue:1e90ff,fi\
112
- rebrick:b22222,floralwhite:fffaf0,forestgreen:228b22,fuchsia:ff00ff,gainsboro:dcdcdc,ghostwhite:f8f8ff,gold:ffd700,goldenrod:daa520,gray:808080,green:008000,greenyellow:adff2f,grey:808080,honeydew:f0fff0,hotpink:ff69b4,indianred:cd5c5c,indigo:4b0082,ivory:fffff0,khaki:f0e68c,lavender:e6e6fa,lavenderblush:fff0f5,lawngreen:7cfc00,lemonchiffon:fffacd,lightblue:add8e6,lightcoral:f08080,lightcyan:e0fff\
113
- f,lightgoldenrodyellow:fafad2,lightgray:d3d3d3,lightgreen:90ee90,lightgrey:d3d3d3,lightpink:ffb6c1,lightsalmon:ffa07a,lightseagreen:20b2aa,lightskyblue:87cefa,lightslategray:778899,lightslategrey:778899,lightsteelblue:b0c4de,lightyellow:ffffe0,lime:00ff00,limegreen:32cd32,linen:faf0e6,magenta:ff00ff,maroon:800000,mediumaquamarine:66cdaa,mediumblue:0000cd,mediumorchid:ba55d3,mediumpurple:9370db,med\
114
- iumseagreen:3cb371,mediumslateblue:7b68ee,mediumspringgreen:00fa9a,mediumturquoise:48d1cc,mediumvioletred:c71585,midnightblue:191970,mintcream:f5fffa,mistyrose:ffe4e1,moccasin:ffe4b5,navajowhite:ffdead,navy:000080,oldlace:fdf5e6,olive:808000,olivedrab:6b8e23,orange:ffa500,orangered:ff4500,orchid:da70d6,palegoldenrod:eee8aa,palegreen:98fb98,paleturquoise:afeeee,palevioletred:db7093,papayawhip:ffefd\
115
- 5,peachpuff:ffdab9,peru:cd853f,pink:ffc0cb,plum:dda0dd,powderblue:b0e0e6,purple:800080,rebeccapurple:663399,red:ff0000,rosybrown:bc8f8f,royalblue:4169e1,saddlebrown:8b4513,salmon:fa8072,sandybrown:f4a460,seagreen:2e8b57,seashell:fff5ee,sienna:a0522d,silver:c0c0c0,skyblue:87ceeb,slateblue:6a5acd,slategray:708090,slategrey:708090,snow:fffafa,springgreen:00ff7f,steelblue:4682b4,tan:d2b48c,teal:008080\
116
- ,thistle:d8bfd8,tomato:ff6347,turquoise:40e0d0,violet:ee82ee,wheat:f5deb3,white:ffffff,whitesmoke:f5f5f5,yellow:ffff00,yellowgreen:9acd32".split(",").map((p) => p.split(":")));
110
+ var NAMED = Object.fromEntries(("aliceblue:f0f8ff,antiquewhite:faebd7,aqua:00ffff,aquamarine:7fffd4,azure:f0ffff,beige:f5f5dc,bisque:ffe4c4,black:000000,blanchedalmond:ffebcd,blue:0000ff,blueviolet:8a2be2,brown:a52a2a,burlywood:deb887,cadetblue:5f9ea0,chartreuse:7fff00,chocolate:d2691e,coral:ff7f50,cornflowerblue:6495ed,cornsilk:fff8dc,crimson:dc143c,cyan:00ffff,darkblue:00008b,darkcyan:008b8b,dark"+
111
+ "goldenrod:b8860b,darkgray:a9a9a9,darkgreen:006400,darkgrey:a9a9a9,darkkhaki:bdb76b,darkmagenta:8b008b,darkolivegreen:556b2f,darkorange:ff8c00,darkorchid:9932cc,darkred:8b0000,darksalmon:e9967a,darkseagreen:8fbc8f,darkslateblue:483d8b,darkslategray:2f4f4f,darkslategrey:2f4f4f,darkturquoise:00ced1,darkviolet:9400d3,deeppink:ff1493,deepskyblue:00bfff,dimgray:696969,dimgrey:696969,dodgerblue:1e90ff,fi"+
112
+ "rebrick:b22222,floralwhite:fffaf0,forestgreen:228b22,fuchsia:ff00ff,gainsboro:dcdcdc,ghostwhite:f8f8ff,gold:ffd700,goldenrod:daa520,gray:808080,green:008000,greenyellow:adff2f,grey:808080,honeydew:f0fff0,hotpink:ff69b4,indianred:cd5c5c,indigo:4b0082,ivory:fffff0,khaki:f0e68c,lavender:e6e6fa,lavenderblush:fff0f5,lawngreen:7cfc00,lemonchiffon:fffacd,lightblue:add8e6,lightcoral:f08080,lightcyan:e0fff"+
113
+ "f,lightgoldenrodyellow:fafad2,lightgray:d3d3d3,lightgreen:90ee90,lightgrey:d3d3d3,lightpink:ffb6c1,lightsalmon:ffa07a,lightseagreen:20b2aa,lightskyblue:87cefa,lightslategray:778899,lightslategrey:778899,lightsteelblue:b0c4de,lightyellow:ffffe0,lime:00ff00,limegreen:32cd32,linen:faf0e6,magenta:ff00ff,maroon:800000,mediumaquamarine:66cdaa,mediumblue:0000cd,mediumorchid:ba55d3,mediumpurple:9370db,med"+
114
+ "iumseagreen:3cb371,mediumslateblue:7b68ee,mediumspringgreen:00fa9a,mediumturquoise:48d1cc,mediumvioletred:c71585,midnightblue:191970,mintcream:f5fffa,mistyrose:ffe4e1,moccasin:ffe4b5,navajowhite:ffdead,navy:000080,oldlace:fdf5e6,olive:808000,olivedrab:6b8e23,orange:ffa500,orangered:ff4500,orchid:da70d6,palegoldenrod:eee8aa,palegreen:98fb98,paleturquoise:afeeee,palevioletred:db7093,papayawhip:ffefd"+
115
+ "5,peachpuff:ffdab9,peru:cd853f,pink:ffc0cb,plum:dda0dd,powderblue:b0e0e6,purple:800080,rebeccapurple:663399,red:ff0000,rosybrown:bc8f8f,royalblue:4169e1,saddlebrown:8b4513,salmon:fa8072,sandybrown:f4a460,seagreen:2e8b57,seashell:fff5ee,sienna:a0522d,silver:c0c0c0,skyblue:87ceeb,slateblue:6a5acd,slategray:708090,slategrey:708090,snow:fffafa,springgreen:00ff7f,steelblue:4682b4,tan:d2b48c,teal:008080"+
116
+ ",thistle:d8bfd8,tomato:ff6347,turquoise:40e0d0,violet:ee82ee,wheat:f5deb3,white:ffffff,whitesmoke:f5f5f5,yellow:ffff00,yellowgreen:9acd32").split(",").map((p) => p.split(":")));
117
117
  function hexColor(c) {
118
118
  if (c == null || c === "") return void 0;
119
119
  const s = String(c).trim().toLowerCase();
@@ -990,6 +990,8 @@ function newContext() {
990
990
  /** @type {Set<string>} part libraries referenced (report ids) */
991
991
  libraries: /* @__PURE__ */ new Set(),
992
992
  cells: 0,
993
+ /** @type {any[]} every item tracked, with what happened to it (see items() in importRdlx's result) */
994
+ items: [],
993
995
  warn(msg) {
994
996
  if (!cx.warnings.includes(msg)) cx.warnings.push(msg);
995
997
  }
@@ -999,24 +1001,35 @@ function newContext() {
999
1001
  function track(cx, ar, label) {
1000
1002
  cx.stats.items++;
1001
1003
  const name2 = String(ar?.Name || label || ar?.Type || "item");
1004
+ const say = (kind, msg) => {
1005
+ if (!t3.notes.some((n) => n.message === msg)) t3.notes.push({ kind, message: msg });
1006
+ cx.warn(`${name2}: ${msg}`);
1007
+ };
1002
1008
  const t3 = {
1003
1009
  name: name2,
1004
1010
  state: "mapped",
1011
+ pos: typeof ar?.__pos === "number" ? ar.__pos : void 0,
1012
+ /** @type {{ kind: string, message: string }[]} */
1013
+ notes: [],
1014
+ /** @type {string[]} expressions that could not be translated */
1015
+ exprs: [],
1005
1016
  /** in the report, with something lost or changed */
1006
1017
  approx(msg) {
1007
1018
  if (t3.state === "mapped") t3.state = "approximated";
1008
- cx.warn(`${name2}: ${msg}`);
1019
+ say("approximated", msg);
1009
1020
  },
1010
1021
  /** for information only */
1011
1022
  note(msg) {
1012
- cx.warn(`${name2}: ${msg}`);
1023
+ say("info", msg);
1013
1024
  },
1014
1025
  /** not in the report */
1015
1026
  drop(msg) {
1016
1027
  t3.state = "dropped";
1017
- cx.warn(`${name2}: ${msg}`);
1028
+ say("dropped", msg);
1018
1029
  }
1019
1030
  };
1031
+ cx.items.push(t3);
1032
+ for (const x of Array.isArray(ar?.__exprs) ? ar.__exprs : []) if (typeof x === "string" && !t3.exprs.includes(x)) t3.exprs.push(x);
1020
1033
  for (const n of Array.isArray(ar?.__notes) ? ar.__notes : []) t3.approx(n);
1021
1034
  for (const n of Array.isArray(ar?.__info) ? ar.__info : []) t3.note(n);
1022
1035
  return t3;
@@ -1034,6 +1047,7 @@ function uniq(cx, base2, generated = false) {
1034
1047
  }
1035
1048
  function ex(cx, t3, v, ctx, opt = {}) {
1036
1049
  const r = translateExpression(v, { text: opt.text, fields: opt.fields, lit: opt.lit, region: ctx.region, scopes: cx.scopes, runScopes: cx.runScopes });
1050
+ if (!r.ok && typeof v === "string" && !t3.exprs.includes(v)) t3.exprs.push(v);
1037
1051
  if (!r.ok) t3.approx(`${r.notes.join("; ")}; ${opt.text ? "the expression is shown as text" : `${opt.what || "that setting"} is left out`}.`);
1038
1052
  else for (const n of r.notes) t3.approx(`${n}.`);
1039
1053
  return r.value;
@@ -1270,12 +1284,13 @@ function convertItem(ar, cx, ctx) {
1270
1284
  dropInside(ar, cx);
1271
1285
  return finish(cx, t3, null);
1272
1286
  }
1273
- const snap = { ...cx.stats };
1287
+ const snap = { ...cx.stats }, tracked = cx.items.length;
1274
1288
  try {
1275
1289
  return conv(ar, cx, ctx);
1276
1290
  } catch (e) {
1277
1291
  if (e instanceof ImportBudgetError) throw e;
1278
1292
  Object.assign(cx.stats, snap);
1293
+ cx.items.length = tracked;
1279
1294
  const t3 = track(cx, ar);
1280
1295
  t3.drop(`it could not be converted (${e instanceof Error ? e.message : e}), so it was left out.`);
1281
1296
  dropInside(ar, cx);
@@ -3307,7 +3322,7 @@ function convertReport(ar, cx, opts) {
3307
3322
  if (cx.columns) body.columns = cx.columns;
3308
3323
  if (more.length) body.name = sec0?.Name || "Section1";
3309
3324
  return {
3310
- $schema: "pagewright/report@1",
3325
+ $schema: "reportwright/report@1",
3311
3326
  name: name2,
3312
3327
  locale: lang2,
3313
3328
  ...currencyOf(lang2) ? { currency: currencyOf(lang2) } : {},
@@ -3348,13 +3363,15 @@ function importRdlx(input, opts = {}) {
3348
3363
  } catch (e) {
3349
3364
  if (e instanceof ImportBudgetError) {
3350
3365
  const error = `The report is too large to import: ${e.message}`;
3351
- return { definition: convertReport({}, newContext(), opts), warnings: [`${error}.`], stats: { items: 0, mapped: 0, approximated: 0, dropped: 0 }, error };
3366
+ return { definition: convertReport({}, newContext(), opts), warnings: [`${error}.`], stats: { items: 0, mapped: 0, approximated: 0, dropped: 0 }, items: [], error };
3352
3367
  }
3353
3368
  cx.warn(`The import stopped early (${e instanceof Error ? e.message : e}), so parts of the report are missing.`);
3354
3369
  definition = convertReport({}, newContext(), opts);
3355
3370
  }
3356
- return { definition, warnings: cx.warnings, stats: cx.stats };
3371
+ return { definition, warnings: cx.warnings, stats: cx.stats, items: importedItems(cx.items) };
3357
3372
  }
3373
+ var importedItems = (items) => items.filter((t3) => t3.state !== "mapped" || t3.notes.length || t3.exprs.length).map((t3) => ({ name: t3.name, state: t3.state, ...t3.pos != null ? { pos: t3.pos } : {}, notes: t3.notes, exprs: t3.exprs }));
3374
+ var rewordItems = (items, f) => (items || []).map((i2) => ({ ...i2, notes: i2.notes.map((n) => ({ ...n, message: f(n.message) })) }));
3358
3375
 
3359
3376
  // src/importers/rdl.js
3360
3377
  var RDL_NS = /^http:\/\/schemas\.microsoft\.com\/sqlserver\/reporting\/(\d{4})\/\d{2}\/reportdefinition$/i;
@@ -3382,7 +3399,7 @@ function importRdl(input, opts = {}) {
3382
3399
  const notes = [];
3383
3400
  let ar;
3384
3401
  try {
3385
- ar = toRdlx(root, notes, m ? Number(m[1]) : 2016);
3402
+ ar = toRdlx(root, notes, m ? Number(m[1]) : 2016, opts.resolve);
3386
3403
  } catch (e) {
3387
3404
  if (e instanceof ImportBudgetError) {
3388
3405
  const error = `The report is too large to import: ${e.message}`;
@@ -3396,10 +3413,12 @@ function importRdl(input, opts = {}) {
3396
3413
  const def = r.definition;
3397
3414
  for (const p of def.parameters || []) if (ar.__hidden?.has(p.name)) p.hidden = true;
3398
3415
  if (ar.__code) def.customCode = ar.__code;
3399
- const warnings = [...notes, ...r.warnings.filter((w) => !/is hidden in ActiveReports; ReportWright shows it/.test(w))].map((w) => w.replace(/ActiveReports/g, "SSRS"));
3400
- return { definition: def, warnings: [...new Set(warnings)], stats: r.stats };
3416
+ const hiddenNote = /is hidden in ActiveReports; ReportWright shows it/;
3417
+ const warnings = [...notes, ...r.warnings.filter((w) => !hiddenNote.test(w))].map((w) => w.replace(/ActiveReports/g, "SSRS"));
3418
+ const items = rewordItems(r.items.map((i2) => ({ ...i2, notes: i2.notes.filter((n) => !hiddenNote.test(n.message)) })), (w) => w.replace(/ActiveReports/g, "SSRS"));
3419
+ return { definition: def, warnings: [...new Set(warnings)], stats: r.stats, items };
3401
3420
  }
3402
- function toRdlx(root, notes, year) {
3421
+ function toRdlx(root, notes, year, resolve2) {
3403
3422
  const NS = root.ns;
3404
3423
  const kids = (e, name2) => e ? e.children.filter((c) => c.ns === NS && (name2 == null || c.name === name2)) : [];
3405
3424
  const kid = (e, name2) => e?.children.find((c) => c.ns === NS && c.name === name2);
@@ -3566,6 +3585,7 @@ function toRdlx(root, notes, year) {
3566
3585
  Name: e.attrs.Name,
3567
3586
  __notes: itemNotes,
3568
3587
  __info: itemInfo,
3588
+ __pos: e.pos,
3569
3589
  Left: raw(e, "Left"),
3570
3590
  Top: raw(e, "Top"),
3571
3591
  Width: raw(e, "Width"),
@@ -4101,17 +4121,46 @@ function toRdlx(root, notes, year) {
4101
4121
  const r = e.name === "Tablix" || e.name === "Chart" ? e.attrs.Name || reg : reg;
4102
4122
  for (const c of e.children) prepass(c, r);
4103
4123
  })(root, null);
4124
+ function sharedSource(ref) {
4125
+ let text;
4126
+ try {
4127
+ text = resolve2?.("datasource", ref);
4128
+ } catch {
4129
+ text = null;
4130
+ }
4131
+ if (typeof text !== "string") return null;
4132
+ let doc2;
4133
+ try {
4134
+ doc2 = parseXml(text);
4135
+ } catch (e) {
4136
+ notes.push(`The shared data source "${ref}" could not be read (${e instanceof Error ? e.message : e}); it is treated as SQL Server.`);
4137
+ return null;
4138
+ }
4139
+ const sub = (e, n) => e?.children.find((c) => c.name === n);
4140
+ const props = doc2.name === "RptDataSource" ? sub(doc2, "ConnectionProperties") : doc2.name === "DataSourceDefinition" ? doc2 : null;
4141
+ if (!props) {
4142
+ notes.push(`The shared data source "${ref}" is not an SSRS data source (its root is <${doc2.name}>); it is treated as SQL Server.`);
4143
+ return null;
4144
+ }
4145
+ return { provider: (sub(props, "Extension")?.text || "SQL").trim(), connect: (sub(props, "ConnectString")?.text ?? "").trim() };
4146
+ }
4104
4147
  const TYPE_OF = (t3) => /datetime|date$/i.test(t3) ? "date" : /int|decimal|double|single|byte|float/i.test(t3) ? "number" : /boolean/i.test(t3) ? "boolean" : null;
4105
4148
  const DataSources = list2(root, "DataSources", "DataSource").map((d) => {
4106
4149
  const name2 = d.attrs.Name;
4107
4150
  const cp = kid(d, "ConnectionProperties");
4108
4151
  let provider = raw(cp, "DataProvider") || "";
4152
+ let connect = raw(cp, "ConnectString") ?? "";
4109
4153
  if (!cp && kid(d, "DataSourceReference")) {
4110
- provider = "SQL";
4111
- notes.push(`Data source "${name2}" is the shared data source "${raw(d, "DataSourceReference")}", whose connection is not in the file; it is treated as SQL Server.`);
4154
+ const ref = raw(d, "DataSourceReference") ?? "";
4155
+ const shared = sharedSource(ref);
4156
+ if (shared) ({ provider, connect } = shared);
4157
+ else {
4158
+ provider = "SQL";
4159
+ notes.push(`Data source "${name2}" is the shared data source "${ref}", whose connection is not in the file; it is treated as SQL Server.`);
4160
+ }
4112
4161
  }
4113
4162
  if (/^(OLEDB-MD|ESSBASE|SAPBW|SQLAS|HYPERION)/i.test(provider)) provider = `${provider} (MDX)`;
4114
- return { Name: name2, ConnectionProperties: { DataProvider: provider, ConnectString: raw(cp, "ConnectString") ?? "" } };
4163
+ return { Name: name2, ConnectionProperties: { DataProvider: provider, ConnectString: connect } };
4115
4164
  });
4116
4165
  const entered = /* @__PURE__ */ new Map();
4117
4166
  const providers = new Map(DataSources.map((d) => [d.Name, String(d.ConnectionProperties.DataProvider).toUpperCase()]));
@@ -4952,7 +5001,7 @@ function importJrxml(input, opts = {}) {
4952
5001
  const charts = /* @__PURE__ */ new Map();
4953
5002
  let ar;
4954
5003
  try {
4955
- ar = toRdlx2(root, notes, charts, opts.name || root.attrs.name);
5004
+ ar = toRdlx2(root, notes, charts, opts.name || root.attrs.name, opts.resolve);
4956
5005
  } catch (e) {
4957
5006
  if (e instanceof ImportBudgetError) {
4958
5007
  const error = `The report is too large to import: ${e.message}`;
@@ -4978,7 +5027,7 @@ function importJrxml(input, opts = {}) {
4978
5027
  r.definition.arithmetic = "double";
4979
5028
  placeCharts(r.definition, charts);
4980
5029
  const warnings = [...notes, ...r.warnings].map((w) => w.replace(/ActiveReports/g, "JasperReports"));
4981
- return { definition: r.definition, warnings: [...new Set(warnings)], stats: r.stats };
5030
+ return { definition: r.definition, warnings: [...new Set(warnings)], stats: r.stats, items: rewordItems(r.items, (w) => w.replace(/ActiveReports/g, "JasperReports")) };
4982
5031
  }
4983
5032
  function stripJasperDoctype(s) {
4984
5033
  const i2 = s.indexOf("<!DOCTYPE");
@@ -4987,9 +5036,9 @@ function stripJasperDoctype(s) {
4987
5036
  if (e < 0) return s;
4988
5037
  const decl = s.slice(i2, e + 1);
4989
5038
  if (decl.includes("[") || !/^<!DOCTYPE\s+jasperReport\s/.test(decl)) return s;
4990
- return s.slice(0, i2) + s.slice(e + 1);
5039
+ return s.slice(0, i2) + decl.replace(/[^\n]/g, " ") + s.slice(e + 1);
4991
5040
  }
4992
- function toRdlx2(root, notes, charts, reportName) {
5041
+ function toRdlx2(root, notes, charts, reportName, resolve2) {
4993
5042
  const kid = (e, n) => e?.children.find((c) => c.name === n);
4994
5043
  const kids = (e, n) => e ? e.children.filter((c) => n == null || c.name === n) : [];
4995
5044
  const txt = (e, n) => {
@@ -5173,6 +5222,7 @@ function toRdlx2(root, notes, charts, reportName) {
5173
5222
  return "=" + v.s;
5174
5223
  } catch (e) {
5175
5224
  if (!(e instanceof Untranslatable2)) throw e;
5225
+ (item2.__exprs || (item2.__exprs = [])).push(s);
5176
5226
  (item2.__notes || (item2.__notes = [])).push(`${e.message} has no ReportWright equivalent, so the expression ${s.length > 200 ? s.slice(0, 200) + "…" : s} is shown as text.`);
5177
5227
  return s.startsWith("=") ? `="${s.replace(/"/g, '""')}"` : s;
5178
5228
  }
@@ -5182,12 +5232,50 @@ function toRdlx2(root, notes, charts, reportName) {
5182
5232
  return "=" + vb2(String(src).trim(), c);
5183
5233
  } catch (e) {
5184
5234
  if (!(e instanceof Untranslatable2)) throw e;
5235
+ (item2.__exprs || (item2.__exprs = [])).push(String(src).trim());
5185
5236
  (item2.__notes || (item2.__notes = [])).push(`${what} uses ${e.message}, which has no ReportWright equivalent, so it is left out.`);
5186
5237
  return void 0;
5187
5238
  }
5188
5239
  }
5189
5240
  const styles = new Map(kids(root, "style").map((s) => [s.attrs.name, s]));
5190
- const defStyle = kids(root, "style").find((s) => s.attrs.isDefault === "true" || s.attrs.default === "true");
5241
+ const seenTemplates = /* @__PURE__ */ new Set();
5242
+ (function templates(el, depth) {
5243
+ for (const t3 of kids(el, "template")) {
5244
+ const src = (kid(t3, "expression")?.text ?? t3.text).trim();
5245
+ const lit2 = /^"([^"]+)"$/.exec(src);
5246
+ const ref = lit2 ? lit2[1] : depth > 0 && !/["$(){}+]/.test(src) ? src : null;
5247
+ if (!ref) {
5248
+ if (src) note(`A style template is chosen by an expression (${src.slice(0, 120)}), so its styles are missing.`);
5249
+ continue;
5250
+ }
5251
+ if (seenTemplates.has(ref) || seenTemplates.size >= 32) continue;
5252
+ seenTemplates.add(ref);
5253
+ let text;
5254
+ try {
5255
+ text = resolve2?.("template", ref);
5256
+ } catch {
5257
+ text = null;
5258
+ }
5259
+ if (typeof text !== "string") {
5260
+ note(`The style template "${ref}" is not in the file, so items that use its styles have the default style.`);
5261
+ continue;
5262
+ }
5263
+ let doc2;
5264
+ try {
5265
+ doc2 = parseXml(text);
5266
+ } catch (e) {
5267
+ note(`The style template "${ref}" could not be read (${e instanceof Error ? e.message : e}), so its styles are missing.`);
5268
+ continue;
5269
+ }
5270
+ if (doc2.name !== "jasperTemplate") {
5271
+ note(`The style template "${ref}" is not a JasperReports template (its root is <${doc2.name}>), so its styles are missing.`);
5272
+ continue;
5273
+ }
5274
+ for (const s of kids(doc2, "style")) if (s.attrs.name && !styles.has(s.attrs.name)) styles.set(s.attrs.name, s);
5275
+ if (depth < 8) templates(doc2, depth + 1);
5276
+ }
5277
+ })(root, 0);
5278
+ const defStyle = [...styles.values()].find((s) => s.attrs.isDefault === "true" || s.attrs.default === "true");
5191
5279
  function styleAttrs(name2, seen = 0) {
5192
5280
  const s = styles.get(name2);
5193
5281
  if (!s || seen > 10) return {};
@@ -5342,7 +5430,7 @@ function toRdlx2(root, notes, charts, reportName) {
5342
5430
  }
5343
5431
  function item(n, c) {
5344
5432
  const a = n.a, re = n.re, e = n.el;
5345
- const base2 = { Name: nameFor(n, n.kind), Left: pt(a.x), Top: pt(a.y), Width: pt(a.width), Height: pt(a.height) };
5433
+ const base2 = { __pos: e.pos, Name: nameFor(n, n.kind), Left: pt(a.x), Top: pt(a.y), Width: pt(a.width), Height: pt(a.height) };
5346
5434
  const it = { ...base2 };
5347
5435
  const st = { ...defStyle ? styleAttrs(defStyle.attrs.name) : {}, ...a.style ? styleAttrs(a.style) : {}, ...stripUndef(normAttrs(re.attrs === e.attrs ? e.attrs : { ...re.attrs, ...e.attrs, ...n.te?.attrs || {}, ...kid(n.te, "font")?.attrs || {} })), ...boxAttrs(kid(e, "box")) };
5348
5436
  if (a.style && !styles.has(a.style)) (it.__notes || (it.__notes = [])).push(`its style "${a.style}" is not in the file (a style template?), so it has the default style.`);
@@ -5948,7 +6036,7 @@ function importBirt(input, opts = {}) {
5948
6036
  r.definition.nullOrder = "low";
5949
6037
  r.definition.arithmetic = "double";
5950
6038
  r.definition.bandRows = "first-last";
5951
- return { definition: r.definition, warnings: [...new Set(warnings)], stats: r.stats };
6039
+ return { definition: r.definition, warnings: [...new Set(warnings)], stats: r.stats, items: rewordItems(r.items, (w) => w.replace(/ActiveReports/g, "BIRT")) };
5952
6040
  }
5953
6041
  var PROPS = /* @__PURE__ */ new Set(["property", "text-property", "expression", "xml-property", "html-property", "encrypted-property"]);
5954
6042
  var prop = (e, name2) => e?.children.find((c) => PROPS.has(c.name) && c.attrs.name === name2)?.text;
@@ -6171,6 +6259,7 @@ function toRdlx3(root, notes, reportName) {
6171
6259
  return "=" + vb2(s, c);
6172
6260
  } catch (e) {
6173
6261
  if (!(e instanceof Untranslatable2)) throw e;
6262
+ (item2.__exprs || (item2.__exprs = [])).push(s);
6174
6263
  (item2.__notes || (item2.__notes = [])).push(`${e.message} has no ReportWright equivalent, so the expression ${s.length > 200 ? s.slice(0, 200) + "…" : s} is shown as text.`);
6175
6264
  return s.startsWith("=") ? `="${s.replace(/"/g, '""')}"` : s;
6176
6265
  }
@@ -6180,6 +6269,7 @@ function toRdlx3(root, notes, reportName) {
6180
6269
  return "=" + vb2(src, c);
6181
6270
  } catch (e) {
6182
6271
  if (!(e instanceof Untranslatable2)) throw e;
6272
+ (item2.__exprs || (item2.__exprs = [])).push(String(src));
6183
6273
  (item2.__notes || (item2.__notes = [])).push(`${what} uses ${e.message}, which has no ReportWright equivalent, so it is left out.`);
6184
6274
  return void 0;
6185
6275
  }
@@ -6360,7 +6450,7 @@ function toRdlx3(root, notes, reportName) {
6360
6450
  const w = Math.min(W, len(prop(e, "width"), W, W)) || W;
6361
6451
  const given = len(prop(e, "height"), 0, 0);
6362
6452
  const x = len(prop(e, "x"), W, 0);
6363
- const it = { Name: nameFor(e, e.name.replace(/(^|-)(\w)/g, (_, __, ch) => ch.toUpperCase())), Left: pt(x), Width: pt(w) };
6453
+ const it = { __pos: e.pos, Name: nameFor(e, e.name.replace(/(^|-)(\w)/g, (_, __, ch) => ch.toUpperCase())), Left: pt(x), Width: pt(w) };
6364
6454
  const vis = listProp(e, "visibility")[0];
6365
6455
  if (vis) {
6366
6456
  const ve = prop(vis, "valueExpr");
@@ -6418,6 +6508,7 @@ function toRdlx3(root, notes, reportName) {
6418
6508
  v = "=" + binding(b, c, 0);
6419
6509
  } catch (er) {
6420
6510
  if (!(er instanceof Untranslatable2)) throw er;
6511
+ (it.__exprs || (it.__exprs = [])).push(String(prop(b, "expression") ?? col));
6421
6512
  (it.__notes || (it.__notes = [])).push(`its column "${col}" uses ${er.message}, so it is shown as text.`);
6422
6513
  v = col;
6423
6514
  }
@@ -6446,6 +6537,7 @@ function toRdlx3(root, notes, reportName) {
6446
6537
  pieces.push(`(${vb2(decodeHtml(p.e), c)})`);
6447
6538
  } catch (er) {
6448
6539
  if (!(er instanceof Untranslatable2)) throw er;
6540
+ (it.__exprs || (it.__exprs = [])).push(decodeHtml(p.e));
6449
6541
  (it.__notes || (it.__notes = [])).push(`a <value-of> uses ${er.message}, so it is left out.`);
6450
6542
  }
6451
6543
  }
@@ -6864,7 +6956,7 @@ function readReportFile(name2, text) {
6864
6956
  import { Fragment as Fragment13, useEffect as useEffect13, useLayoutEffect as useLayoutEffect3, useMemo as useMemo5, useRef as useRef8, useState as useState17 } from "react";
6865
6957
 
6866
6958
  // src/designer/ui.jsx
6867
- import { createContext as createContext2, useContext as useContext2, useEffect, useRef, useState } from "react";
6959
+ import { createContext as createContext2, useContext as useContext2, useEffect, useId, useRef, useState } from "react";
6868
6960
 
6869
6961
  // src/designer/fieldCheck.js
6870
6962
  function exprParts(value) {
@@ -6962,7 +7054,7 @@ function nestedFields(rows) {
6962
7054
  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 })) }));
6963
7055
  }
6964
7056
 
6965
- // node_modules/zustand/esm/vanilla.mjs
7057
+ // ../reportwright/node_modules/zustand/esm/vanilla.mjs
6966
7058
  var createStoreImpl = (createState) => {
6967
7059
  let state;
6968
7060
  const listeners = /* @__PURE__ */ new Set();
@@ -6986,7 +7078,7 @@ var createStoreImpl = (createState) => {
6986
7078
  };
6987
7079
  var createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);
6988
7080
 
6989
- // node_modules/zustand/esm/react.mjs
7081
+ // ../reportwright/node_modules/zustand/esm/react.mjs
6990
7082
  import React from "react";
6991
7083
  var identity = (arg) => arg;
6992
7084
  function useStore(api, selector = identity) {
@@ -7002,7 +7094,7 @@ function useStore(api, selector = identity) {
7002
7094
  // src/designer/store.js
7003
7095
  import { createContext, useContext } from "react";
7004
7096
 
7005
- // node_modules/immer/dist/immer.mjs
7097
+ // ../reportwright/node_modules/immer/dist/immer.mjs
7006
7098
  var NOTHING = /* @__PURE__ */ Symbol.for("immer-nothing");
7007
7099
  var DRAFTABLE = /* @__PURE__ */ Symbol.for("immer-draftable");
7008
7100
  var DRAFT_STATE = /* @__PURE__ */ Symbol.for("immer-state");
@@ -8148,7 +8240,7 @@ function minSize(it) {
8148
8240
  }
8149
8241
  for (const k of ["w", "h"]) if (typeof it[k] === "number" && it[k] < 1) it[k] = 1;
8150
8242
  }
8151
- function moveItems(ids, dx, dy) {
8243
+ function moveItems(ids, dx, dy, { nudge = false } = {}) {
8152
8244
  if (!dx && !dy) return;
8153
8245
  if (S().cells && wouldOverlap(S().def, ids, (it) => ({ x: it.x + dx, y: it.y + dy, w: it.w, h: it.h }))) {
8154
8246
  S().setUi({ saveError: CELL_TAKEN() });
@@ -8160,7 +8252,7 @@ function moveItems(ids, dx, dy) {
8160
8252
  const f = findItem(d, id);
8161
8253
  if (!f) continue;
8162
8254
  const room = roomFor(d, f);
8163
- f.item.x = round(clamp(f.item.x + dx, 0, Math.max(0, room - f.item.w)));
8255
+ f.item.x = round(nudge ? Math.max(0, f.item.x + dx) : clamp(f.item.x + dx, 0, Math.max(0, room - f.item.w)));
8164
8256
  f.item.y = round(Math.max(0, f.item.y + dy));
8165
8257
  growToFit(d, f);
8166
8258
  }
@@ -8610,6 +8702,7 @@ function alignItems(ids, how, toPage = false) {
8610
8702
  });
8611
8703
  }
8612
8704
  var round = (v) => Math.round(v * 100) / 100;
8705
+ var nudgeStep = ({ snap, grid, cells, cellSize }, shift2) => (cells ? cellSize : snap ? grid : 1) * (shift2 ? 10 : 1);
8613
8706
  var clamp = (v, a, b) => Math.max(a, Math.min(b, v));
8614
8707
  var CELL_TAKEN = () => t(S().lang, "cellTaken");
8615
8708
  var overlap = (a, b) => a.x < b.x + Math.max(b.w, 1) - 0.01 && b.x < a.x + Math.max(a.w, 1) - 0.01 && a.y < b.y + Math.max(b.h, 1) - 0.01 && b.y < a.y + Math.max(a.h, 1) - 0.01;
@@ -8700,7 +8793,47 @@ function ExprInput({ value, onChange, onOpen, placeholder: placeholder2 }) {
8700
8793
  issues.map((i2, k) => /* @__PURE__ */ jsx("div", { className: "warn", "data-testid": "field-warning", children: issueText(T, i2) }, k))
8701
8794
  ] });
8702
8795
  }
8796
+ function InfoTip({ text, id }) {
8797
+ const T = useT();
8798
+ const own = useId();
8799
+ const tipId = id || `tip${own.replace(/:/g, "")}`;
8800
+ const [open, setOpen] = useState(false);
8801
+ return /* @__PURE__ */ jsxs("span", { className: "infotip", onMouseEnter: () => setOpen(true), onMouseLeave: () => setOpen(false), children: [
8802
+ /* @__PURE__ */ jsx(
8803
+ "button",
8804
+ {
8805
+ type: "button",
8806
+ className: "infotip-btn",
8807
+ "aria-label": T("c132_moreInfo"),
8808
+ "aria-describedby": tipId,
8809
+ "aria-expanded": open,
8810
+ onClick: () => setOpen((v) => !v),
8811
+ onFocus: () => setOpen(true),
8812
+ onBlur: () => setOpen(false),
8813
+ onKeyDown: (e) => {
8814
+ if (e.key === "Escape" && open) {
8815
+ e.preventDefault();
8816
+ e.stopPropagation();
8817
+ setOpen(false);
8818
+ }
8819
+ },
8820
+ children: "ⓘ"
8821
+ }
8822
+ ),
8823
+ /* @__PURE__ */ jsx("span", { role: "tooltip", id: tipId, className: "infotip-text", hidden: !open, children: text })
8824
+ ] });
8825
+ }
8826
+ var LONG_HINT = 90;
8703
8827
  function Field({ label, children, hint }) {
8828
+ if (typeof hint === "string" && hint.length > LONG_HINT) {
8829
+ return /* @__PURE__ */ jsxs("div", { className: "field-tip", children: [
8830
+ /* @__PURE__ */ jsxs("label", { className: "field", children: [
8831
+ /* @__PURE__ */ jsx("span", { children: label }),
8832
+ children
8833
+ ] }),
8834
+ /* @__PURE__ */ jsx(InfoTip, { text: hint })
8835
+ ] });
8836
+ }
8704
8837
  return /* @__PURE__ */ jsxs("label", { className: "field", children: [
8705
8838
  /* @__PURE__ */ jsx("span", { children: label }),
8706
8839
  children,
@@ -9195,7 +9328,11 @@ function LayersPanel() {
9195
9328
  });
9196
9329
  });
9197
9330
  return /* @__PURE__ */ jsxs3("div", { className: "pane", "data-testid": "layers", children: [
9198
- /* @__PURE__ */ jsx5("h4", { children: T("layers") }),
9331
+ /* @__PURE__ */ jsx5("h4", { children: /* @__PURE__ */ jsxs3("span", { children: [
9332
+ T("layers"),
9333
+ " ",
9334
+ /* @__PURE__ */ jsx5(InfoTip, { text: T("layersHint") })
9335
+ ] }) }),
9199
9336
  /* @__PURE__ */ jsxs3("div", { className: "pane-body", children: [
9200
9337
  layers.map((l, i2) => /* @__PURE__ */ jsxs3("div", { className: "layer-row", "data-layer": l.name, children: [
9201
9338
  /* @__PURE__ */ jsx5(TextInput, { value: l.name, onChange: (v) => rename(i2, v.replace(/[^\w -]/g, "")), "aria-label": T("layerName"), readOnly: readOnly2 }),
@@ -9240,8 +9377,7 @@ function LayersPanel() {
9240
9377
  children: T("layerAdd")
9241
9378
  }
9242
9379
  )
9243
- ] }),
9244
- /* @__PURE__ */ jsx5("div", { className: "hint", children: T("layersHint") })
9380
+ ] })
9245
9381
  ] })
9246
9382
  ] });
9247
9383
  }
@@ -9331,7 +9467,11 @@ function PartsPanel() {
9331
9467
  const [pick, setPick] = useState3("");
9332
9468
  return /* @__PURE__ */ jsxs3("div", { className: "pane", "data-testid": "parts-panel", children: [
9333
9469
  /* @__PURE__ */ jsxs3("h4", { children: [
9334
- T("parts"),
9470
+ /* @__PURE__ */ jsxs3("span", { children: [
9471
+ T("parts"),
9472
+ " ",
9473
+ /* @__PURE__ */ jsx5(InfoTip, { text: T("partsHint") })
9474
+ ] }),
9335
9475
  libs.length > 0 && /* @__PURE__ */ jsx5("button", { type: "button", className: "btn sm ghost", onClick: () => libs.forEach((l) => fetchReused(l, true)), title: T("partsReloadHint"), children: T("partsReload") })
9336
9476
  ] }),
9337
9477
  /* @__PURE__ */ jsxs3("div", { className: "pane-body", children: [
@@ -9354,8 +9494,7 @@ function PartsPanel() {
9354
9494
  children: T("libraryAdd")
9355
9495
  }
9356
9496
  )
9357
- ] }),
9358
- /* @__PURE__ */ jsx5("div", { className: "hint", children: T("partsHint") })
9497
+ ] })
9359
9498
  ] })
9360
9499
  ] });
9361
9500
  }
@@ -9906,8 +10045,8 @@ function Band({ section, label, scale, bw: bandW, drag, setDrag, phBox = null })
9906
10045
  (mb.extras || []).map((p) => {
9907
10046
  const i2 = (contentList || []).findIndex((e) => e?.placeholder === p.name);
9908
10047
  if (i2 >= 0) return /* @__PURE__ */ jsx6(Band, { section: `content:${i2}`, scale, bw: p.w, drag, setDrag, phBox: p }, p.name);
9909
- return /* @__PURE__ */ jsx6("div", { className: "band master-content", style: { position: "absolute", left: p.x * scale, top: p.y * scale, width: p.w * scale, height: p.h * scale, display: "flex", alignItems: "center", justifyContent: "center" }, "data-placeholder": p.name, children: !readOnly2 && /* @__PURE__ */ jsx6("button", { className: "btn sm", onClick: () => fillPlaceholder(p), "dat\
9910
- a-testid": `fill-placeholder-${p.name}`, children: T("fillPlaceholder", { name: p.name }) }) }, p.name);
10048
+ return /* @__PURE__ */ jsx6("div", { className: "band master-content", style: { position: "absolute", left: p.x * scale, top: p.y * scale, width: p.w * scale, height: p.h * scale, display: "flex", alignItems: "center", justifyContent: "center" }, "data-placeholder": p.name, children: !readOnly2 && /* @__PURE__ */ jsx6("button", { className: "btn sm", onClick: () => fillPlaceholder(p), [("dat"+
10049
+ "a-testid")]: `fill-placeholder-${p.name}`, children: T("fillPlaceholder", { name: p.name }) }) }, p.name);
9911
10050
  })
9912
10051
  ] }) : surface
9913
10052
  ] });
@@ -10279,6 +10418,13 @@ function PartPreview({ item, scale }) {
10279
10418
  tag
10280
10419
  ] });
10281
10420
  }
10421
+ function checkedOnCanvas(v) {
10422
+ if (v == null || typeof v === "boolean" || typeof v === "number") return v === true || v === 1;
10423
+ const s = String(v).trim();
10424
+ if (!isDynamic(s)) return ["true", "yes", "y", "1"].includes(s.toLowerCase());
10425
+ const lit2 = /^=\s*(true|false|1|0)\s*$/i.exec(s)?.[1]?.toLowerCase();
10426
+ return lit2 ? lit2 === "true" || lit2 === "1" : null;
10427
+ }
10282
10428
  function ItemBody({ item, scale }) {
10283
10429
  const base2 = useDesigner((s) => s.def.styles?.base);
10284
10430
  const images = useDesigner((s) => s.def.images);
@@ -10341,8 +10487,9 @@ function ItemBody({ item, scale }) {
10341
10487
  if (item.type === "checkbox") {
10342
10488
  const c = textCss([base2, item.style], scale, false);
10343
10489
  const size = Math.min(item.h, (Number(item.style?.fontSize) || Number(base2?.fontSize) || 9) + 2) * scale;
10490
+ const on = checkedOnCanvas(item.value);
10344
10491
  return /* @__PURE__ */ jsxs4("div", { className: "box", style: { ...c.box, alignItems: "center", gap: 4 * scale, padding: 0 }, children: [
10345
- /* @__PURE__ */ jsx6("span", { style: { width: size, height: size, border: "1px solid #1f2328", borderRadius: 2, flex: "none", display: "grid", placeItems: "center", fontSize: size * 0.8 }, children: "✓" }),
10492
+ /* @__PURE__ */ jsx6("span", { "data-checked": String(on), style: { width: size, height: size, border: "1px solid #1f2328", borderRadius: 2, flex: "none", display: "grid", placeItems: "center", fontSize: size * 0.8, opacity: on == null ? 0.4 : 1 }, children: on !== false ? "✓" : "" }),
10346
10493
  /* @__PURE__ */ jsx6("div", { className: `tx${isDynamic(item.text) ? " dyn" : ""}`, style: c.text, children: shown(item.text) })
10347
10494
  ] });
10348
10495
  }
@@ -10606,14 +10753,14 @@ import { useMemo as useMemo2, useRef as useRef5, useState as useState5 } from "r
10606
10753
  // src/designer/ExprCode.jsx
10607
10754
  import { forwardRef, useEffect as useEffect4, useImperativeHandle, useRef as useRef4 } from "react";
10608
10755
 
10609
- // node_modules/@marijn/find-cluster-break/src/index.js
10756
+ // ../reportwright/node_modules/@marijn/find-cluster-break/src/index.js
10610
10757
  var rangeFrom = [];
10611
10758
  var rangeTo = [];
10612
10759
  (() => {
10613
- let numbers = "lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,1n,9,16,o,,x,1i,3,,i,,7,a,2,t,3,1k,,,7,2,2,2,3,9,,a,2,q,,2,3,1k,,,5,4,2,2,3,3,,u,2,3,,b,3,1k,,,8,,3,,3,k,2,m,6,,3,1k,,,7,2,2,2,3,7,3,a,2,u,,1n,5,3,3,,4,9,,14,5,1j,,,7,,3,,4,7,2,b,2,t,3,1k,,,7,,3,,4,7,2,b,2,f,,c,4,1j,2,,7,,3,,4,9,,a,2,t,3,1y,,4,6,,,,8,i,2,1p,,,8,c,8,2q,,,a,b,7,21,2,r,,,,,,\
10614
- 4,2,1d,k,,2,5,b,,10,9,,2u,b,,6,n,4,4,3,g,4,d,,,3,6,,f,,jj,3,qa,4,s,3,t,2,u,2,1s,w,9,,19,3,,,39,2,y,,3a,c,4,c,63,5,1l,a,,,,,2,o,2,,1c,1a,2,c,k,5,1b,h,12,9,c,3,u,d,1k,e,1c,k,48,3,,l,4,,6,,2,3,5i,1s,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,n,5,4,,2b,2,1e,i,q,i,d,,12,8,p,d,18,4,1b,e,10,,1v,e,c,,8,2,1a,,1f,,,3,2,2,5,2,,,15,5,5,2,6k,8,,2,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,\
10615
- 14,3,4,,4l,2,fx,4,1t,5,8t,2,25,6,1y,b,1d,4,3e,3,1h,f,15,,2,2,a,4,19,b,7,,1p,3,10,e,g,2,18,,c,3,1c,e,8,4,,2,2k,c,6,,2,,4d,c,l,4,1j,2,,7,2,2,2,3,9,,a,2,2,7,3,5,1v,9,,,2,,,4,,5,,,e,2,2a,i,n,,29,k,6j,7,2,9,r,2,2a,h,2y,d,2t,3,2,a,74,f,6t,6,,2,2,4,,,,2,3x,7,2,7,3,,s,a,14,7,,4,8,,9,b,1a,g,5i,8,5j,8,,8,2a,m,,e,3e,6,3,,,2,,7,,,1u,5,,2,,5,9n,4,9,2,,,1c,7,3,5,n,,44l,,6,f,8ug,i,1xc,5,1n,7,t4,,,1j,7,4,29,,b,2,\
10616
- f57,2,3mp,1a,2,n,f2,5,3,6,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,2s,,4g,7,af,,1p,4,e4,4,72,2,6r,,2,,7,2,5,,d6,7,31,7,240,5".split(",").map((s) => s ? parseInt(s, 36) : 1);
10760
+ let numbers = ("lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,1n,9,16,o,,x,1i,3,,i,,7,a,2,t,3,1k,,,7,2,2,2,3,9,,a,2,q,,2,3,1k,,,5,4,2,2,3,3,,u,2,3,,b,3,1k,,,8,,3,,3,k,2,m,6,,3,1k,,,7,2,2,2,3,7,3,a,2,u,,1n,5,3,3,,4,9,,14,5,1j,,,7,,3,,4,7,2,b,2,t,3,1k,,,7,,3,,4,7,2,b,2,f,,c,4,1j,2,,7,,3,,4,9,,a,2,t,3,1y,,4,6,,,,8,i,2,1p,,,8,c,8,2q,,,a,b,7,21,2,r,,,,,,"+
10761
+ "4,2,1d,k,,2,5,b,,10,9,,2u,b,,6,n,4,4,3,g,4,d,,,3,6,,f,,jj,3,qa,4,s,3,t,2,u,2,1s,w,9,,19,3,,,39,2,y,,3a,c,4,c,63,5,1l,a,,,,,2,o,2,,1c,1a,2,c,k,5,1b,h,12,9,c,3,u,d,1k,e,1c,k,48,3,,l,4,,6,,2,3,5i,1s,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,n,5,4,,2b,2,1e,i,q,i,d,,12,8,p,d,18,4,1b,e,10,,1v,e,c,,8,2,1a,,1f,,,3,2,2,5,2,,,15,5,5,2,6k,8,,2,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,"+
10762
+ "14,3,4,,4l,2,fx,4,1t,5,8t,2,25,6,1y,b,1d,4,3e,3,1h,f,15,,2,2,a,4,19,b,7,,1p,3,10,e,g,2,18,,c,3,1c,e,8,4,,2,2k,c,6,,2,,4d,c,l,4,1j,2,,7,2,2,2,3,9,,a,2,2,7,3,5,1v,9,,,2,,,4,,5,,,e,2,2a,i,n,,29,k,6j,7,2,9,r,2,2a,h,2y,d,2t,3,2,a,74,f,6t,6,,2,2,4,,,,2,3x,7,2,7,3,,s,a,14,7,,4,8,,9,b,1a,g,5i,8,5j,8,,8,2a,m,,e,3e,6,3,,,2,,7,,,1u,5,,2,,5,9n,4,9,2,,,1c,7,3,5,n,,44l,,6,f,8ug,i,1xc,5,1n,7,t4,,,1j,7,4,29,,b,2,"+
10763
+ "f57,2,3mp,1a,2,n,f2,5,3,6,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,2s,,4g,7,af,,1p,4,e4,4,72,2,6r,,2,,7,2,5,,d6,7,31,7,240,5").split(",").map((s) => s ? parseInt(s, 36) : 1);
10617
10764
  for (let i2 = 0, n = 0; i2 < numbers.length; i2++)
10618
10765
  (i2 % 2 ? rangeTo : rangeFrom).push(n = n + numbers[i2]);
10619
10766
  })();
@@ -10683,7 +10830,7 @@ function codePointSize(code2) {
10683
10830
  return code2 < 65536 ? 1 : 2;
10684
10831
  }
10685
10832
 
10686
- // node_modules/@codemirror/state/dist/index.js
10833
+ // ../reportwright/node_modules/@codemirror/state/dist/index.js
10687
10834
  var Text = class _Text {
10688
10835
  /**
10689
10836
  Get the line description around the given position.
@@ -14095,7 +14242,7 @@ function findColumn(string2, col, tabSize, strict) {
14095
14242
  return strict === true ? -1 : string2.length;
14096
14243
  }
14097
14244
 
14098
- // node_modules/style-mod/src/style-mod.js
14245
+ // ../reportwright/node_modules/style-mod/src/style-mod.js
14099
14246
  var C = "ͼ";
14100
14247
  var COUNT = typeof Symbol == "undefined" ? "__" + C : Symbol.for(C);
14101
14248
  var SET = typeof Symbol == "undefined" ? "__styleSet" + Math.floor(Math.random() * 1e8) : /* @__PURE__ */ Symbol("styleSet");
@@ -14231,7 +14378,7 @@ var StyleSet = class {
14231
14378
  }
14232
14379
  };
14233
14380
 
14234
- // node_modules/w3c-keyname/index.js
14381
+ // ../reportwright/node_modules/w3c-keyname/index.js
14235
14382
  var base = {
14236
14383
  8: "Backspace",
14237
14384
  9: "Tab",
@@ -14337,7 +14484,7 @@ function keyName(event) {
14337
14484
  return name2;
14338
14485
  }
14339
14486
 
14340
- // node_modules/@codemirror/view/dist/index.js
14487
+ // ../reportwright/node_modules/@codemirror/view/dist/index.js
14341
14488
  var nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
14342
14489
  var doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
14343
14490
  var ie_edge = /* @__PURE__ */ /Edge\/(\d+)/.exec(nav.userAgent);
@@ -23213,7 +23360,7 @@ GutterMarker.prototype.mapMode = MapMode.TrackBefore;
23213
23360
  GutterMarker.prototype.startSide = GutterMarker.prototype.endSide = -1;
23214
23361
  GutterMarker.prototype.point = true;
23215
23362
 
23216
- // node_modules/@lezer/common/dist/index.js
23363
+ // ../reportwright/node_modules/@lezer/common/dist/index.js
23217
23364
  var DefaultBufferLength = 1024;
23218
23365
  var nextPropID = 0;
23219
23366
  var Range2 = class {
@@ -24837,7 +24984,7 @@ var StringInput = class {
24837
24984
  };
24838
24985
  var stoppedInner = new NodeProp({ perNode: true });
24839
24986
 
24840
- // node_modules/@lezer/highlight/dist/index.js
24987
+ // ../reportwright/node_modules/@lezer/highlight/dist/index.js
24841
24988
  var nextTagID = 0;
24842
24989
  var Tag = class _Tag {
24843
24990
  /**
@@ -25561,7 +25708,7 @@ var classHighlighter = tagHighlighter([
25561
25708
  { tag: tags.punctuation, class: "tok-punctuation" }
25562
25709
  ]);
25563
25710
 
25564
- // node_modules/@codemirror/language/dist/index.js
25711
+ // ../reportwright/node_modules/@codemirror/language/dist/index.js
25565
25712
  var _a;
25566
25713
  var languageDataProp = /* @__PURE__ */ new NodeProp();
25567
25714
  function defineLanguageFacet(baseData) {
@@ -27188,7 +27335,7 @@ var marks = {
27188
27335
  auto: /* @__PURE__ */ Decoration.mark({ class: "cm-iso", inclusive: true, attributes: { dir: "auto" }, bidiIsolate: null })
27189
27336
  };
27190
27337
 
27191
- // node_modules/@codemirror/commands/dist/index.js
27338
+ // ../reportwright/node_modules/@codemirror/commands/dist/index.js
27192
27339
  var toggleComment = (target) => {
27193
27340
  let { state } = target, line2 = state.doc.lineAt(state.selection.main.from), config2 = getConfig(target.state, line2.from);
27194
27341
  return config2.line ? toggleLineComment(target) : config2.block ? toggleBlockCommentByLine(target) : false;
@@ -28282,7 +28429,7 @@ var defaultKeymap = /* @__PURE__ */ [
28282
28429
  { key: "Ctrl-m", mac: "Shift-Alt-m", run: toggleTabFocusMode }
28283
28430
  ].concat(standardKeymap);
28284
28431
 
28285
- // node_modules/@codemirror/autocomplete/dist/index.js
28432
+ // ../reportwright/node_modules/@codemirror/autocomplete/dist/index.js
28286
28433
  var CompletionContext = class {
28287
28434
  /**
28288
28435
  Create a new completion context. (Mostly useful for testing
@@ -30943,8 +31090,8 @@ function SeriesEditor({ value, onChange, openExpr, dataSet, chartType }) {
30943
31090
  COMBO.has(chartType) && /* @__PURE__ */ jsxs7("div", { className: "grid2", children: [
30944
31091
  /* @__PURE__ */ jsx10(Field, { label: T("i_drawAs"), children: /* @__PURE__ */ jsx10(Select, { value: sr.type, allowEmpty: true, options: (chartType === "bar" ? ["bar", "line", "area"] : ["column", "line", "area"]).map((v) => ({ value: v, label: T(`o_chartType_${v}`) })), onChange: (v) => set2(i2, "type", v), "aria-label": T("i_seriesType") }) }),
30945
31092
  /* @__PURE__ */ jsx10(Field, { label: T("i_axis"), children: /* @__PURE__ */ jsx10(Select, { value: sr.axis || "primary", options: [{ value: "primary", label: T("axisPrimary") }, { value: "secondary", label: T("axisSecondary") }], onChange: (v) => set2(i2, "axis", v === "primary" ? void 0 : v), "aria-label": T("i_seriesAxis") }) }),
30946
- ["line", "area"].includes(sr.type || chartType) && /* @__PURE__ */ jsx10(Field, { label: T("seriesLine"), children: /* @__PURE__ */ jsx10(Select, { value: sr.line, allowEmpty: true, options: [{ value: "straight", label: T("lineStraight") }, { value: "smooth", label: T("lineSmooth") }, { value: "step", label: T("lineStep") }], onChange: (v) => set2(i2, "line", v), "aria-label": `${T("seri\
30947
- esLine")} ${i2 + 1}` }) })
31093
+ ["line", "area"].includes(sr.type || chartType) && /* @__PURE__ */ jsx10(Field, { label: T("seriesLine"), children: /* @__PURE__ */ jsx10(Select, { value: sr.line, allowEmpty: true, options: [{ value: "straight", label: T("lineStraight") }, { value: "smooth", label: T("lineSmooth") }, { value: "step", label: T("lineStep") }], onChange: (v) => set2(i2, "line", v), "aria-label": `${T(("seri"+
31094
+ "esLine"))} ${i2 + 1}` }) })
30948
31095
  ] }),
30949
31096
  COMBO.has(chartType) && !fin && /* @__PURE__ */ jsx10(Check, { label: T("i_range"), checked: range, onChange: (on) => onChange(list2.map((x, j) => {
30950
31097
  if (j !== i2) return x;
@@ -31032,8 +31179,8 @@ function OverlaysEditor({ value, onChange, openExpr, dataSet, chartType }) {
31032
31179
  numOrExpr(o, i2, "from", T("i_from")),
31033
31180
  numOrExpr(o, i2, "to", T("i_to"))
31034
31181
  ] }),
31035
- (o.type === "line" || o.type === "band") && chartType !== "gauge" && /* @__PURE__ */ jsx10(Field, { label: T("overlayAxis"), children: /* @__PURE__ */ jsx10(Select, { value: o.axis || "primary", options: [{ value: "primary", label: T("axisPrimary") }, { value: "secondary", label: T("axisSecondary") }], onChange: (v) => set2(i2, "axis", v === "primary" ? void 0 : v), "aria-label": `${T("overl\
31036
- ayAxis")} ${i2 + 1}` }) }),
31182
+ (o.type === "line" || o.type === "band") && chartType !== "gauge" && /* @__PURE__ */ jsx10(Field, { label: T("overlayAxis"), children: /* @__PURE__ */ jsx10(Select, { value: o.axis || "primary", options: [{ value: "primary", label: T("axisPrimary") }, { value: "secondary", label: T("axisSecondary") }], onChange: (v) => set2(i2, "axis", v === "primary" ? void 0 : v), "aria-label": `${T(("overl"+
31183
+ "ayAxis"))} ${i2 + 1}` }) }),
31037
31184
  o.type === "line" && /* @__PURE__ */ jsx10(Check, { label: T("overlayShowValue"), checked: o.showValue !== false, onChange: (v) => set2(i2, "showValue", v ? void 0 : false) }),
31038
31185
  chartType !== "gauge" && /* @__PURE__ */ jsx10(Check, { label: T("overlayInLegend"), checked: o.legend !== false, onChange: (v) => set2(i2, "legend", v ? void 0 : false) }),
31039
31186
  /* @__PURE__ */ jsx10(Field, { label: T("i_label"), children: /* @__PURE__ */ jsx10(TextInput, { value: o.label, onChange: (v) => set2(i2, "label", v), "aria-label": T("i_overlayLabel") }) })
@@ -31195,8 +31342,8 @@ function ActionEditor({ value, onChange, openExpr, dataSet, label }) {
31195
31342
  const target = useReportParams(a.type === "report" ? a.report : null);
31196
31343
  const own = (def.parameters || []).map((p) => ({ name: p.name, prompt: p.prompt }));
31197
31344
  return /* @__PURE__ */ jsxs7("div", { style: { display: "grid", gap: 6 }, children: [
31198
- /* @__PURE__ */ jsx10(Field, { label: label || T("i_actionOnClick"), children: /* @__PURE__ */ jsx10(Select, { value: a.type, options: [{ value: "none", label: T("i_actNone") }, { value: "url", label: T("i_actUrl") }, { value: "report", label: T("i_actReport") }, { value: "params", label: T("i_actParams") }, { value: "bookmark", label: T("i_actBookmark") }, { value: "toggleItem", label: T("act\
31199
- ionToggleItem") }], onChange: (v) => set2({ type: v || "none" }) }) }),
31345
+ /* @__PURE__ */ jsx10(Field, { label: label || T("i_actionOnClick"), children: /* @__PURE__ */ jsx10(Select, { value: a.type, options: [{ value: "none", label: T("i_actNone") }, { value: "url", label: T("i_actUrl") }, { value: "report", label: T("i_actReport") }, { value: "params", label: T("i_actParams") }, { value: "bookmark", label: T("i_actBookmark") }, { value: "toggleItem", label: T(("act"+
31346
+ "ionToggleItem")) }], onChange: (v) => set2({ type: v || "none" }) }) }),
31200
31347
  a.type === "toggleItem" && /* @__PURE__ */ jsx10(Field, { label: T("actionToggleTarget"), hint: T("actionToggleHint"), children: /* @__PURE__ */ jsx10(Select, { value: a.target, allowEmpty: true, options: itemNames, onChange: (v) => set2({ target: v }), "data-testid": "toggle-target" }) }),
31201
31348
  a.type === "url" && /* @__PURE__ */ jsx10(Field, { label: T("i_url"), children: /* @__PURE__ */ jsx10(ExprInput, { value: a.url, onChange: (v) => set2({ url: v }), onOpen: () => openExpr({ value: a.url, dataSet, onSave: (v) => set2({ url: v }), title: T("i_url") }) }) }),
31202
31349
  a.type === "bookmark" && /* @__PURE__ */ jsx10(Field, { label: T("jumpToBookmark"), children: /* @__PURE__ */ jsx10(ExprInput, { value: a.target, onChange: (v) => set2({ target: v }), onOpen: () => openExpr({ value: a.target, dataSet, onSave: (v) => set2({ target: v }), title: T("jumpToBookmark") }) }) }),
@@ -31263,8 +31410,8 @@ function CellProps({ table: table2, sel, openExpr }) {
31263
31410
  ] }),
31264
31411
  /* @__PURE__ */ jsxs7("div", { className: "cat", children: [
31265
31412
  /* @__PURE__ */ jsx10(CatHead, { "data-icon": "i_interactivity", children: T("i_interactivity") }),
31266
- sel.part === "header" && /* @__PURE__ */ jsx10(Field, { label: T("i_interactiveSort"), hint: T("i_interactiveSortHint"), children: /* @__PURE__ */ jsx10(ExprInput, { value: cell.sortBy, onChange: (v) => setCell("sortBy", v || void 0), onOpen: () => openExpr({ value: cell.sortBy, dataSet: table2.dataSet, onSave: (v) => setCell("sortBy", v || void 0), title: T("sfSortBy") }), placeholder: "=Fi\
31267
- elds.amount" }) }),
31413
+ sel.part === "header" && /* @__PURE__ */ jsx10(Field, { label: T("i_interactiveSort"), hint: T("i_interactiveSortHint"), children: /* @__PURE__ */ jsx10(ExprInput, { value: cell.sortBy, onChange: (v) => setCell("sortBy", v || void 0), onOpen: () => openExpr({ value: cell.sortBy, dataSet: table2.dataSet, onSave: (v) => setCell("sortBy", v || void 0), title: T("sfSortBy") }), placeholder: ("=Fi"+
31414
+ "elds.amount") }) }),
31268
31415
  /* @__PURE__ */ jsx10(Field, { label: T("cellBookmark"), children: /* @__PURE__ */ jsx10(ExprInput, { value: cell.bookmark, onChange: (v) => setCell("bookmark", v || void 0), onOpen: () => openExpr({ value: cell.bookmark, dataSet: table2.dataSet, onSave: (v) => setCell("bookmark", v || void 0), title: T("cellBookmark") }) }) }),
31269
31416
  /* @__PURE__ */ jsx10(ActionEditor, { value: cell.action, onChange: (v) => setCell("action", v), openExpr, dataSet: table2.dataSet })
31270
31417
  ] }),
@@ -31602,9 +31749,9 @@ function ReportProps() {
31602
31749
  /* @__PURE__ */ jsx10(Field, { label: T("i_currency"), children: /* @__PURE__ */ jsx10(TextInput, { value: def.currency, onChange: (v) => set2((d) => {
31603
31750
  d.currency = v.toUpperCase() || void 0;
31604
31751
  }, "currency"), placeholder: "USD" }) }),
31605
- /* @__PURE__ */ jsx10(Field, { label: T("i_nonFinite"), children: /* @__PURE__ */ jsx10(Select, { value: def.nonFinite || "", options: [{ value: "", label: T("i_nonFiniteSsrs") }, { value: "blank", label: T("i_nonFiniteBlank") }, { value: "error", label: "#Error" }], onChange: (v) => set2((d) => {
31752
+ /* @__PURE__ */ jsx10("div", { style: { gridColumn: "1 / -1" }, children: /* @__PURE__ */ jsx10(Field, { label: T("i_nonFinite"), children: /* @__PURE__ */ jsx10(Select, { value: def.nonFinite || "", options: [{ value: "", label: T("i_nonFiniteSsrs") }, { value: "blank", label: T("i_nonFiniteBlank") }, { value: "error", label: "#Error" }], onChange: (v) => set2((d) => {
31606
31753
  d.nonFinite = v || void 0;
31607
- }, "nonFinite") }) })
31754
+ }, "nonFinite") }) }) })
31608
31755
  ] })
31609
31756
  ] }),
31610
31757
  /* @__PURE__ */ jsxs7("div", { className: "cat", children: [
@@ -32274,6 +32421,19 @@ async function loadSample(store) {
32274
32421
  api.setState({ sample: { error: e.message } });
32275
32422
  }
32276
32423
  }
32424
+ function detectedFields(ds, def, sampleRows) {
32425
+ if ((ds?.fields || []).length) return null;
32426
+ let rows = Array.isArray(sampleRows) ? sampleRows : null;
32427
+ if (!rows) {
32428
+ const src = (def?.dataSources || []).find((x) => x.name === ds?.source);
32429
+ try {
32430
+ rows = src?.type === "json" && src.data != null ? sourceRows(src.data, ds.path) : null;
32431
+ } catch {
32432
+ rows = null;
32433
+ }
32434
+ }
32435
+ return rows?.length ? detectFields(rows.slice(0, 50), { dates: ds.detectDates !== false }) : null;
32436
+ }
32277
32437
  function DataPanel() {
32278
32438
  const def = useDesigner((s) => s.def);
32279
32439
  const lang2 = useDesigner((s) => s.lang);
@@ -32375,27 +32535,36 @@ function DataPanel() {
32375
32535
  /* @__PURE__ */ jsx13("button", { type: "button", className: "btn sm ghost", onClick: () => useDesigner.getState().setUi({ instantVisuals: { dataSet: d.name } }), "data-testid": `instant-${d.name}`, children: T("instantVisuals") }),
32376
32536
  /* @__PURE__ */ jsx13("button", { type: "button", className: "btn sm ghost", onClick: () => useDesigner.getState().setUi({ pivotWizard: { dataSet: d.name } }), "data-testid": `pivot-wizard-${d.name}`, children: T("pivotWizard") })
32377
32537
  ] }),
32378
- open.has(d.name) && /* @__PURE__ */ jsxs10("ul", { className: "tree", style: { paddingLeft: 18 }, children: [
32379
- (d.fields || []).flatMap((f) => f.type === "object" ? (f.fields || []).map((c) => ({ name: `${f.name}.${c.name}`, type: c.type, nested: true })) : [f]).map((f) => /* @__PURE__ */ jsxs10(
32380
- "li",
32381
- {
32382
- className: `trow field-chip${f.nested ? " nested" : ""}`,
32383
- draggable: true,
32384
- title: "Drag onto the page or a table cell",
32385
- "data-field": f.name,
32386
- onDragStart: (e) => {
32387
- e.dataTransfer.setData(MIME_FIELD, JSON.stringify({ dataSet: d.name, field: f.name, type: f.type }));
32388
- e.dataTransfer.effectAllowed = "copy";
32538
+ open.has(d.name) && (() => {
32539
+ const found = detectedFields(d, def, sample?.dataSets?.[d.name]);
32540
+ const list2 = (d.fields || []).length ? d.fields : found || [];
32541
+ return /* @__PURE__ */ jsxs10("ul", { className: "tree", style: { paddingLeft: 18 }, "data-testid": `fields-${d.name}`, children: [
32542
+ found && /* @__PURE__ */ jsx13("li", { className: "subtle", "data-testid": `detected-${d.name}`, children: T("c132_detectedHint") }),
32543
+ list2.flatMap((f) => f.type === "object" ? (f.fields || []).map((c) => ({ name: `${f.name}.${c.name}`, type: c.type, nested: true })) : [f]).map((f) => /* @__PURE__ */ jsxs10(
32544
+ "li",
32545
+ {
32546
+ className: `trow field-chip${f.nested ? " nested" : ""}`,
32547
+ draggable: true,
32548
+ title: "Drag onto the page or a table cell",
32549
+ "data-field": f.name,
32550
+ "data-detected": found ? "" : void 0,
32551
+ onDragStart: (e) => {
32552
+ e.dataTransfer.setData(MIME_FIELD, JSON.stringify({ dataSet: d.name, field: f.name, type: f.type }));
32553
+ e.dataTransfer.effectAllowed = "copy";
32554
+ },
32555
+ children: [
32556
+ /* @__PURE__ */ jsx13("span", { className: "nm", children: f.name }),
32557
+ /* @__PURE__ */ jsxs10("span", { className: "ty", children: [
32558
+ f.type,
32559
+ found ? ` · ${T("c132_detected")}` : ""
32560
+ ] })
32561
+ ]
32389
32562
  },
32390
- children: [
32391
- /* @__PURE__ */ jsx13("span", { className: "nm", children: f.name }),
32392
- /* @__PURE__ */ jsx13("span", { className: "ty", children: f.type })
32393
- ]
32394
- },
32395
- f.name
32396
- )),
32397
- !(d.fields || []).length && /* @__PURE__ */ jsx13("li", { className: "subtle", children: "No fields. Edit the data set and detect them." })
32398
- ] })
32563
+ f.name
32564
+ )),
32565
+ !list2.length && /* @__PURE__ */ jsx13("li", { className: "subtle", children: "No fields. Edit the data set and detect them." })
32566
+ ] });
32567
+ })()
32399
32568
  ] }, d.name)),
32400
32569
  !(def.dataSets || []).length && /* @__PURE__ */ jsx13("li", { className: "subtle", children: "None" })
32401
32570
  ] }),
@@ -32533,18 +32702,17 @@ function ParamDialog({ index, onClose }) {
32533
32702
  }
32534
32703
  ) }),
32535
32704
  /* @__PURE__ */ jsxs10("div", { className: "grid2", children: [
32536
- /* @__PURE__ */ jsx13(Field, { label: T("choicesFrom"), children: /* @__PURE__ */ jsx13(Select, { value: p.optionsFrom?.dataSet, options: (def.dataSets || []).map((d) => d.name), allowEmpty: true, onChange: pickChoiceSet, "data-testid": "param-choices-from" }) }),
32705
+ /* @__PURE__ */ jsx13(Field, { label: T("choicesFrom"), hint: T("cascadeHint"), children: /* @__PURE__ */ jsx13(Select, { value: p.optionsFrom?.dataSet, options: (def.dataSets || []).map((d) => d.name), allowEmpty: true, onChange: pickChoiceSet, "data-testid": "param-choices-from" }) }),
32537
32706
  p.optionsFrom && /* @__PURE__ */ jsx13(Field, { label: T("valueField"), children: /* @__PURE__ */ jsx13(Select, { value: fieldOf(p.optionsFrom.value) || "", options: [{ value: "", label: T("ux_choose") }, ...fromFields], onChange: (v) => setP({ ...p, optionsFrom: { ...p.optionsFrom, value: v ? `=Fields.${v}` : "" } }), "data-testid": "param-value-field", "aria-invalid": !p.optionsFrom.value ||
32538
32707
  void 0 }) }),
32539
32708
  p.optionsFrom && /* @__PURE__ */ jsx13(Field, { label: T("labelField"), hint: T("labelFieldHint"), children: /* @__PURE__ */ jsx13(Select, { value: p.optionsFrom.label, options: labelOpts, allowEmpty: true, onChange: (v) => setP({ ...p, optionsFrom: { ...p.optionsFrom, label: v || void 0 } }), "data-testid": "param-label-field" }) })
32540
32709
  ] }),
32541
32710
  p.optionsFrom && choicePreview && /* @__PURE__ */ jsx13("div", { className: "hint", "data-testid": "param-choice-preview", children: T("ux_choicePreview", { n: choicePreview.length, list: choicePreview.slice(0, 5).join(", ") + (choicePreview.length > 5 ? ", …" : "") }) }),
32542
- p.optionsFrom && /* @__PURE__ */ jsx13("div", { className: "hint", children: T("cascadeHint") }),
32543
32711
  /* @__PURE__ */ jsxs10("div", { className: "grid2", children: [
32544
32712
  /* @__PURE__ */ jsx13(Field, { label: T("editor"), hint: T(`editorHint_${p.editor || "auto"}`), children: /* @__PURE__ */ jsx13(Select, { value: p.editor, allowEmpty: true, onChange: setEditor, options: EDITORS.map((e) => ({ value: e, label: T(`editor_${e}`) })) }) }),
32545
- /* @__PURE__ */ jsx13(Field, { label: T("panelColumns"), hint: T("panelColumnsHint"), children: /* @__PURE__ */ jsx13(Select, { value: columns, onChange: (v) => setColumns(v || "1"), options: ["1", "2", "3", "4"] }) })
32713
+ /* @__PURE__ */ jsx13(Field, { label: T("panelColumns"), hint: T("c132_panelColumnsHint"), children: /* @__PURE__ */ jsx13(Select, { value: columns, onChange: (v) => setColumns(v || "1"), options: ["1", "2", "3", "4"] }) })
32546
32714
  ] }),
32547
- /* @__PURE__ */ jsx13(Check, { label: T("liveParams"), checked: live, onChange: setLive }),
32715
+ /* @__PURE__ */ jsx13(Check, { label: T("c132_liveParams"), checked: live, onChange: setLive }),
32548
32716
  limits && /* @__PURE__ */ jsxs10("div", { className: "grid3", children: [
32549
32717
  /* @__PURE__ */ jsx13(Field, { label: T("minimum"), children: /* @__PURE__ */ jsx13(TextInput, { value: p.min ?? "", onChange: (v) => setP({ ...p, min: limit(v) }), mono: true, type: p.type === "date" ? "date" : "text" }) }),
32550
32718
  /* @__PURE__ */ jsx13(Field, { label: T("maximum"), children: /* @__PURE__ */ jsx13(TextInput, { value: p.max ?? "", onChange: (v) => setP({ ...p, max: limit(v) }), mono: true, type: p.type === "date" ? "date" : "text" }) }),
@@ -32752,8 +32920,8 @@ function SourceDialog({ index, onClose }) {
32752
32920
  children: [
32753
32921
  /* @__PURE__ */ jsxs10("div", { className: "grid2", children: [
32754
32922
  /* @__PURE__ */ jsx13(Field, { label: "Name", children: /* @__PURE__ */ jsx13(TextInput, { value: s.name, onChange: (v) => setS({ ...s, name: v }), autoFocus: true }) }),
32755
- /* @__PURE__ */ jsx13(Field, { label: "Type", children: /* @__PURE__ */ jsx13(Select, { value: s.type, options: [{ value: "rest", label: "REST API (JSON)" }, { value: "json", label: "Inline JSON" }, { value: "csv", label: "CSV" }, { value: "xml", label: T("srcTypeXml") }, { value: "soap", label: T("srcTypeSoap") }, { value: "odata", label: T("srcTypeOData") }, { value: "graphql", label: "\
32756
- GraphQL" }, { value: "sql", label: "SQL database (on the server)" }], onChange: (v) => setS({ ...s, type: v }) }) })
32923
+ /* @__PURE__ */ jsx13(Field, { label: "Type", children: /* @__PURE__ */ jsx13(Select, { value: s.type, options: [{ value: "rest", label: "REST API (JSON)" }, { value: "json", label: "Inline JSON" }, { value: "csv", label: "CSV" }, { value: "xml", label: T("srcTypeXml") }, { value: "soap", label: T("srcTypeSoap") }, { value: "odata", label: T("srcTypeOData") }, { value: "graphql", label: (""+
32924
+ "GraphQL") }, { value: "sql", label: "SQL database (on the server)" }], onChange: (v) => setS({ ...s, type: v }) }) })
32757
32925
  ] }),
32758
32926
  fetched && /* @__PURE__ */ jsxs10(Fragment8, { children: [
32759
32927
  /* @__PURE__ */ jsxs10("div", { style: { display: "grid", gridTemplateColumns: s.type === "soap" || s.type === "odata" ? "1fr" : "110px 1fr", gap: 8 }, children: [
@@ -32807,8 +32975,8 @@ GraphQL" }, { value: "sql", label: "SQL database (on the server)" }], onChange:
32807
32975
  s.builder ? /* @__PURE__ */ jsx13(SqlBuilder, { s, setS, T, kind: sqlKind, onManual: () => {
32808
32976
  const { builder: _b, ...rest } = s;
32809
32977
  setS({ ...rest, query: s.builder ? buildSql(s.builder, sqlKind) : s.query });
32810
- } }) : /* @__PURE__ */ jsx13(Field, { label: "Query", hint: "SELECT only. @name uses the report parameter name (bound, never pasted into the SQL). Lists work with in (@name).", children: /* @__PURE__ */ jsx13("textarea", { className: "textarea", rows: 6, value: s.query || "", onChange: (e) => setS({ ...s, query: e.target.value }), placeholder: "select region, month, sum(amount) as amou\
32811
- nt from sales where year = @year group by region, month", style: { fontFamily: "var(--mono)" } }) })
32978
+ } }) : /* @__PURE__ */ jsx13(Field, { label: "Query", hint: "SELECT only. @name uses the report parameter name (bound, never pasted into the SQL). Lists work with in (@name).", children: /* @__PURE__ */ jsx13("textarea", { className: "textarea", rows: 6, value: s.query || "", onChange: (e) => setS({ ...s, query: e.target.value }), placeholder: ("select region, month, sum(amount) as amou"+
32979
+ "nt from sales where year = @year group by region, month"), style: { fontFamily: "var(--mono)" } }) })
32812
32980
  ] })
32813
32981
  ] }),
32814
32982
  s.type === "csv" && /* @__PURE__ */ jsxs10("div", { className: "grid2", children: [
@@ -33241,19 +33409,25 @@ function Outline() {
33241
33409
  return /* @__PURE__ */ jsxs11("li", { role: "none", children: [
33242
33410
  /* @__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: [
33243
33411
  !readOnly2 && /* @__PURE__ */ jsx14("span", { className: "grip", "aria-hidden": "true", children: "⠿" }),
33244
- /* @__PURE__ */ jsx14("button", { type: "button", "data-opt": "", className: "linklike nm", onClick: (e) => pick(e, it.id), onKeyDown: (e) => onKey(e, it, list2, i2, parent), "aria-pressed": chosen.has(it.id), "aria-describedby": readOnly2 ? "outline-nav" : "outline-nav outline-keys", ...roving(it.id), children: it.name }),
33245
- /* @__PURE__ */ jsx14("span", { className: "ty", children: T(`item_${it.type}`) === `item_${it.type}` ? ITEMS[it.type]?.label || it.type : T(`item_${it.type}`) }),
33246
- !readOnly2 && /* @__PURE__ */ jsxs11("span", { className: "act", style: { display: "inline-flex", gap: 2 }, children: [
33247
- /* @__PURE__ */ jsx14("button", { type: "button", className: "btn sm ghost icon", tabIndex: -1, disabled: i2 === 0, onClick: () => reorderItem(it.id, -1), title: T("outlineBackward"), "aria-label": `${T("outlineBackward")}: ${it.name}`, children: "↑" }),
33248
- /* @__PURE__ */ jsx14("button", { type: "button", className: "btn sm ghost icon", tabIndex: -1, disabled: i2 === list2.length - 1, onClick: () => reorderItem(it.id, 1), title: T("outlineForward"), "aria-label": `${T("outlineForward")}: ${it.name}`, children: "↓" }),
33249
- parent && /* @__PURE__ */ jsx14("button", { type: "button", className: "btn sm ghost icon", tabIndex: -1, onClick: () => moveOutOfParent(it.id), title: T("outlineMoveOut", { name: parent.name }), "aria-label": `${T("outlineMoveOut", { name: parent.name })}: ${it.name}`, children: "⇱" })
33412
+ /* @__PURE__ */ jsx14("button", { type: "button", "data-opt": "", className: "linklike nm", onClick: (e) => pick(e, it.id), onKeyDown: (e) => onKey(e, it, list2, i2, parent), "aria-pressed": chosen.has(it.id), "aria-describedby": readOnly2 ? "outline-nav" : "outline-nav outline-keys", title: it.name, ...roving(it.id), children: it.name }),
33413
+ /* @__PURE__ */ jsxs11("span", { className: "outline-meta", children: [
33414
+ /* @__PURE__ */ jsx14("span", { className: "ty", children: T(`item_${it.type}`) === `item_${it.type}` ? ITEMS[it.type]?.label || it.type : T(`item_${it.type}`) }),
33415
+ !readOnly2 && /* @__PURE__ */ jsxs11("span", { className: "act", style: { display: "inline-flex", gap: 2 }, children: [
33416
+ /* @__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: "↑" }),
33417
+ /* @__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: "↓" }),
33418
+ 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: "⇱" })
33419
+ ] })
33250
33420
  ] })
33251
33421
  ] }),
33252
33422
  NESTING.has(it.type) && (it.items || []).length > 0 && /* @__PURE__ */ jsx14("ul", { className: "tree", role: "none", children: rows(it.items, it, depth + 1, section) })
33253
33423
  ] }, it.id);
33254
33424
  });
33255
33425
  return /* @__PURE__ */ jsxs11("div", { className: "pane", "data-testid": "outline", children: [
33256
- /* @__PURE__ */ jsx14("h4", { children: T("outline") }),
33426
+ /* @__PURE__ */ jsx14("h4", { children: /* @__PURE__ */ jsxs11("span", { children: [
33427
+ T("outline"),
33428
+ " ",
33429
+ /* @__PURE__ */ jsx14(InfoTip, { text: readOnly2 ? T("outlineHint") : `${T("outlineHint")} ${T("outlineKeys")}` })
33430
+ ] }) }),
33257
33431
  /* @__PURE__ */ jsxs11("div", { className: "pane-body", ref: body, children: [
33258
33432
  /* @__PURE__ */ jsx14("div", { role: "group", "aria-label": T("outline"), onKeyDown: nav2, children: sectionList(def).map(({ key: key2, label }) => {
33259
33433
  const items = secOf(def, key2)?.items || [];
@@ -33264,8 +33438,7 @@ function Outline() {
33264
33438
  ] }, key2);
33265
33439
  }) }),
33266
33440
  /* @__PURE__ */ jsx14("div", { className: "sr-only", id: "outline-nav", children: T("b9_outlineKeys") }),
33267
- /* @__PURE__ */ jsx14("div", { className: "hint", children: T("outlineHint") }),
33268
- !readOnly2 && /* @__PURE__ */ jsx14("div", { className: "hint", id: "outline-keys", children: T("outlineKeys") }),
33441
+ !readOnly2 && /* @__PURE__ */ jsx14("div", { className: "sr-only", id: "outline-keys", children: T("outlineKeys") }),
33269
33442
  /* @__PURE__ */ jsx14("div", { className: "sr-only", role: "status", "aria-live": "polite", children: said })
33270
33443
  ] })
33271
33444
  ] });
@@ -34085,8 +34258,8 @@ function suggestions(ds, picked, width, rows, currency) {
34085
34258
  const text = fields.filter((f) => f.type !== "number"), nums = fields.filter((f) => f.type === "number");
34086
34259
  const out = [];
34087
34260
  if (text.length && nums.length) {
34088
- out.push({ kind: "chart", item: { type: "chart", dataSet: ds.name, w: Math.min(width, 420), h: 200, chartType: text.length > 1 ? "column" : nums.length > 1 ? "line" : "column", category: `=Fields.${text[0].name}`, ...text[1] ? { seriesGroup: `=Fields.${text[1].name}` } : {}, series: nums.slice(0, 3).map((n) => ({ name: labelOf(n.name), value: `=Sum(Fields.${n.name})` })), legend: "bottom", valueFormat: "\
34089
- N0", title: `${nums.map((n) => labelOf(n.name)).join(", ")} by ${labelOf(text[0].name)}` } });
34261
+ out.push({ kind: "chart", item: { type: "chart", dataSet: ds.name, w: Math.min(width, 420), h: 200, chartType: text.length > 1 ? "column" : nums.length > 1 ? "line" : "column", category: `=Fields.${text[0].name}`, ...text[1] ? { seriesGroup: `=Fields.${text[1].name}` } : {}, series: nums.slice(0, 3).map((n) => ({ name: labelOf(n.name), value: `=Sum(Fields.${n.name})` })), legend: "bottom", valueFormat: (""+
34262
+ "N0"), title: `${nums.map((n) => labelOf(n.name)).join(", ")} by ${labelOf(text[0].name)}` } });
34090
34263
  }
34091
34264
  if (fields.length) out.push({ kind: "table", item: tableFor(ds, { layout: text.length && nums.length ? "summary" : "list", groupBy: text[0]?.name, width, rows, currency, fields: fields.map((f) => f.name) }) });
34092
34265
  if (text.length) out.push({ kind: "pivot", item: pivotFor(ds, { rows: [text[0].name], columns: text[1] ? [text[1].name] : [], values: nums.slice(0, 2).map((n) => ({ field: n.name, agg: "Sum" })), width, sample: rows, currency }) });
@@ -34436,6 +34609,7 @@ function StatusBar({ T, zoom, setZoom }) {
34436
34609
  /* @__PURE__ */ jsx20("i", { "aria-hidden": "true" }),
34437
34610
  what
34438
34611
  ] }),
34612
+ /* @__PURE__ */ jsx20("span", { className: "hint dstatus-hint", title: T("canvasHint"), children: T("canvasHint") }),
34439
34613
  /* @__PURE__ */ jsx20("span", { className: "dstatus-page", children: page })
34440
34614
  ] });
34441
34615
  }
@@ -34629,8 +34803,8 @@ var SHORTCUTS = [
34629
34803
  ["⌘/Ctrl C / V", "sc_copy"],
34630
34804
  ["⌘/Ctrl D", "sc_duplicate"],
34631
34805
  ["Delete / Backspace", "sc_delete"],
34632
- ["← ↑ → ↓", "sc_nudge"],
34633
- ["⇧ ← ↑ → ↓", "sc_nudge4"],
34806
+ ["← ↑ → ↓", "c132_nudge1"],
34807
+ ["⇧ ← ↑ → ↓", "c132_nudge10"],
34634
34808
  ["⇧ Click", "sc_toggle"],
34635
34809
  ["Drag", "sc_marquee"],
34636
34810
  ["Alt + Drag", "sc_guides"],
@@ -34821,11 +34995,11 @@ function DesignerIn({ id, initial, rev = null, lang: langIn, embed = null, user
34821
34995
  const arrows = { ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, -1], ArrowDown: [0, 1] };
34822
34996
  if (arrows[e.key] && st().sel.kind === "items") {
34823
34997
  e.preventDefault();
34824
- const step = st().cells ? st().cellSize : e.shiftKey ? st().grid * 4 : 1;
34998
+ const step = nudgeStep(st(), e.shiftKey);
34825
34999
  const [dx, dy] = arrows[e.key];
34826
35000
  const s = st();
34827
35001
  s.lastKey = null;
34828
- moveItems(s.sel.ids, dx * step, dy * step);
35002
+ moveItems(s.sel.ids, dx * step, dy * step, { nudge: true });
34829
35003
  }
34830
35004
  };
34831
35005
  const onLeave = (e) => {
@@ -35010,7 +35184,7 @@ function DesignerIn({ id, initial, rev = null, lang: langIn, embed = null, user
35010
35184
  tableWizard && /* @__PURE__ */ jsx20(TableWizard, {}),
35011
35185
  pivotWizard && /* @__PURE__ */ jsx20(PivotWizard, {}),
35012
35186
  instantVisuals && /* @__PURE__ */ jsx20(InstantVisuals, {}),
35013
- tab === "preview" ? /* @__PURE__ */ jsx20("main", { className: "dpreview", children: /* @__PURE__ */ jsx20(ReportViewer, { definition: def, reportId: id, compact: true, lang: lang2 }) }) : /* @__PURE__ */ jsxs17(
35187
+ tab === "preview" ? /* @__PURE__ */ jsx20("main", { className: "dpreview", children: /* @__PURE__ */ jsx20(ReportViewer, { definition: def, reportId: id, compact: true, lang: lang2, showWarnings: true }) }) : /* @__PURE__ */ jsxs17(
35014
35188
  "div",
35015
35189
  {
35016
35190
  className: "dmain",
@@ -35041,8 +35215,7 @@ function DesignerIn({ id, initial, rev = null, lang: langIn, embed = null, user
35041
35215
  /* @__PURE__ */ jsx20("select", { className: "select", style: { width: 72 }, value: unit, onChange: (e) => st().setUi({ unit: e.target.value }), children: ["pt", "mm", "cm", "in"].map((u) => /* @__PURE__ */ jsx20("option", { children: u }, u)) })
35042
35216
  ] }),
35043
35217
  /* @__PURE__ */ jsx20(AlignBar, { T }),
35044
- /* @__PURE__ */ jsx20(IssuesButton, { T }),
35045
- /* @__PURE__ */ jsx20("span", { className: "hint cbar-hint", children: T("canvasHint") })
35218
+ /* @__PURE__ */ jsx20(IssuesButton, { T })
35046
35219
  ] }),
35047
35220
  /* @__PURE__ */ jsx20(Canvas, {}),
35048
35221
  /* @__PURE__ */ jsx20(StatusBar, { T, zoom, setZoom: (z) => {
@@ -35186,6 +35359,19 @@ button, input, select, textarea { font: inherit; color: inherit; }
35186
35359
  .input.invalid, .textarea.invalid { border-color: var(--danger); background: var(--danger-soft); }
35187
35360
  .err { color: var(--danger); font-size: var(--fs-xs); }
35188
35361
  .hint { color: var(--faint); font-size: var(--fs-xs); }
35362
+ /* ⓘ help (InfoTip): the text opens on hover, focus or click, over the content; Esc closes it */
35363
+ .infotip { position: relative; display: inline-flex; vertical-align: middle; text-transform: none; letter-spacing: normal; font-weight: normal; }
35364
+ .infotip-btn { border: 0; background: none; padding: 0 2px; margin: 0; font: inherit; font-size: 13px; line-height: 1; color: var(--muted); cursor: help; border-radius: 3px; }
35365
+ .infotip-btn:hover, .infotip-btn[aria-expanded=true] { color: var(--accent); }
35366
+ .infotip-text { position: absolute; z-index: 30; top: calc(100% + 4px); inset-inline-end: -4px; width: max-content; max-width: min(280px, 70vw); padding: 8px 10px; border: 1px solid var(--line-strong); border-radius: 6px; background: var(--panel); color: var(--ink); box-shadow: 0 4px 14px rgb(0 0 0 / .14); font-size: var(--fs-xs); line-height: 1.45; white-space: normal; text-align: start; }
35367
+ .infotip-text[hidden] { display: none; }
35368
+ .field-tip { position: relative; min-width: 0; }
35369
+ .field-tip > .field > span:first-child { padding-inline-end: 18px; }
35370
+ .field-tip > .infotip { position: absolute; top: 0; inset-inline-end: 0; }
35371
+ /* in a panel heading the text spans the panel (the heading is its containing block: sticky) */
35372
+ .pane > h4 { position: relative; }
35373
+ .pane > h4 .infotip { position: static; }
35374
+ .pane > h4 .infotip-text { top: 100%; inset-inline: 8px; width: auto; max-width: none; z-index: 5; }
35189
35375
  .check { display: flex; align-items: center; gap: 7px; cursor: pointer; }
35190
35376
  .kbd { font-family: var(--mono); font-size: var(--fs-2xs); padding: 1px 4px; border: 1px solid var(--line); border-radius: 3px; background: var(--panel-2); color: var(--muted); }
35191
35377
 
@@ -35386,6 +35572,7 @@ a.cell-name:hover { color: var(--accent); }
35386
35572
  .vparams { width: 240px; padding: 14px; border-inline-end: 1px solid var(--line); background: var(--panel); display: grid; gap: 12px; align-content: start; overflow: auto; }
35387
35573
  .vparams h3 { margin: 0; font-size: var(--fs-sm); text-transform: uppercase; font-weight: var(--fw-strong); letter-spacing: var(--track-caps); color: var(--muted); }
35388
35574
  .vpages { overflow: auto; padding: 24px 16px 48px; display: flex; flex-direction: column; align-items: center; gap: 18px; min-width: 0; }
35575
+ .vpages:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; } /* E11: keyboard-scrollable; inset, so overflow does not clip it */
35389
35576
  .vpage { background: var(--paper); color: var(--paper-ink); box-shadow: var(--shadow-page); flex: none; content-visibility: auto; contain-intrinsic-size: auto 1100px; }
35390
35577
  .vpage svg { display: block; width: 100%; height: 100%; }
35391
35578
  .vmsg { margin: 40px auto; max-width: 520px; padding: 16px 18px; border-radius: 8px; background: var(--panel); border: 1px solid var(--line); }
@@ -35433,6 +35620,12 @@ a.cell-name:hover { color: var(--accent); }
35433
35620
  .trow:hover .act, .trow:focus-within .act { opacity: 1; }
35434
35621
  .outline-row.sel { background: var(--accent-soft); }
35435
35622
  .outline-row .linklike.nm, .outline-band { text-decoration: none; color: var(--ink); text-align: start; }
35623
+ /* a long name wraps inside the panel's width (no cut-off text); the type and the buttons keep their size */
35624
+ /* (the type and the buttons, together, go under a name too long to share the line) */
35625
+ .outline-row { flex-wrap: wrap; }
35626
+ .outline-row .linklike.nm { flex: 1 1 auto; white-space: normal; overflow-wrap: anywhere; }
35627
+ .outline-meta { display: inline-flex; align-items: center; gap: 6px; flex: none; margin-inline-start: auto; }
35628
+ .outline-meta .btn.icon { width: 22px; }
35436
35629
  .outline-row.sel .linklike.nm, .outline-band.sel { color: var(--accent); }
35437
35630
  .outline-row.sel .ty { color: var(--muted); } /* --faint is 4.38:1 on --accent-soft; --muted passes in both themes */
35438
35631
  .outline-row.sel .act, .outline-row:focus-within .act { opacity: 1; }
@@ -35949,19 +36142,21 @@ a.cell-name:hover { color: var(--accent); }
35949
36142
  .dleft .tool svg { width: 16px; height: 16px; }
35950
36143
  /* canvas: the page centred on the desk, rulers along the top and beside each band */
35951
36144
  .dcenter { grid-template-rows: auto minmax(0, 1fr) auto; background: var(--desk); }
35952
- .cbar { gap: 8px 16px; padding: 6px 16px; min-height: 40px; background: var(--panel); }
36145
+ /* one row of a fixed height: the align buttons that come with a selection never push the canvas down (c132) */
36146
+ .cbar { gap: 8px 16px; padding: 6px 16px; height: 40px; box-sizing: border-box; flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; background: var(--panel); }
36147
+ .cbar > * { flex: none; white-space: nowrap; }
35953
36148
  .cbar .select { height: 28px; }
35954
- .cbar-hint { margin-inline-start: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 1 1 120px; text-align: end; }
35955
36149
  .cscroll { padding: 24px 40px 80px 56px; }
35956
36150
  .paper { border-radius: 2px; }
35957
36151
  .ruler.v { position: absolute; left: -44px; top: 0; pointer-events: none; overflow: visible; }
35958
- .dstatus { display: flex; align-items: center; gap: 16px; min-height: 32px; padding: 2px 12px; border-top: 1px solid var(--line); background: var(--panel); font-size: var(--fs-xs); color: var(--muted); }
36152
+ .dstatus { display: flex; align-items: center; gap: 16px; height: 32px; box-sizing: border-box; white-space: nowrap; padding: 2px 12px; border-top: 1px solid var(--line); background: var(--panel); font-size: var(--fs-xs); color: var(--muted); }
35959
36153
  .dstatus-zoom { display: inline-flex; align-items: center; gap: 2px; }
35960
36154
  .dstatus-zoom .select { height: 26px; width: 92px; border-color: var(--line); font-size: var(--fs-xs); }
35961
36155
  .dstatus-zoom .btn.icon { width: 26px; height: 26px; }
35962
36156
  .dstatus-sel { display: inline-flex; align-items: center; gap: 8px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink); font-family: var(--mono); }
35963
36157
  .dstatus-sel i { flex: none; width: 8px; height: 8px; border-radius: 2px; background: var(--accent); }
35964
- .dstatus-page { margin-inline-start: auto; white-space: nowrap; font-variant-numeric: tabular-nums; }
36158
+ .dstatus-hint { flex: 1 1 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; text-align: end; }
36159
+ .dstatus-page { white-space: nowrap; font-variant-numeric: tabular-nums; }
35965
36160
  /* inspector: roomier sections */
35966
36161
  .dright .insp-head { position: sticky; top: 0; z-index: 3; background: var(--panel); padding: 12px 16px; }
35967
36162
  .dright .cat { padding: 8px 16px 16px; gap: 8px; }
@@ -35996,7 +36191,7 @@ input[type=checkbox], input[type=radio] { width: 16px; height: 16px; accent-colo
35996
36191
 
35997
36192
  .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}
35998
36193
  ` : "";
35999
- var BLANK = { $schema: "pagewright/report@1", name: "Untitled report", page: { size: "A4", margins: [36, 36, 36, 36] }, dataSources: [], dataSets: [], sections: { body: { items: [] } } };
36194
+ var BLANK = { $schema: "reportwright/report@1", name: "Untitled report", page: { size: "A4", margins: [36, 36, 36, 36] }, dataSources: [], dataSets: [], sections: { body: { items: [] } } };
36000
36195
  function mountDesigner(target, opts = {}) {
36001
36196
  const el = typeof target === "string" ? document.querySelector(target) : target;
36002
36197
  if (!el) throw new Error(`mountDesigner: no element for ${target}`);