@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
package/dist/designer.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  setShadowStyles,
14
14
  t,
15
15
  uiFontCss
16
- } from "./chunk-B5ZCT3UK.js";
16
+ } from "./chunk-4XZRLUHN.js";
17
17
  import {
18
18
  customFonts,
19
19
  fontsBase,
@@ -24,7 +24,7 @@ import {
24
24
  setAssetBase,
25
25
  setFetchPolicy,
26
26
  setStandalone
27
- } from "./chunk-ES2LYZ6S.js";
27
+ } from "./chunk-DVJYE7HZ.js";
28
28
  import {
29
29
  BASE_STYLE,
30
30
  DEFAULT_THEME,
@@ -69,7 +69,7 @@ import {
69
69
  validate,
70
70
  withPartProps,
71
71
  xmlRowPaths
72
- } from "./chunk-ZGRJJ6OW.js";
72
+ } from "./chunk-OMCWZYRI.js";
73
73
  import {
74
74
  PAGE_SIZES,
75
75
  fromPt,
@@ -113,13 +113,13 @@ function toPt2(v, fallback = 0) {
113
113
  (m[2] || "pt").toLowerCase()
114
114
  ]) : fallback;
115
115
  }
116
- 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\
117
- 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\
118
- 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\
119
- 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\
120
- 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\
121
- 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\
122
- ,thistle:d8bfd8,tomato:ff6347,turquoise:40e0d0,violet:ee82ee,wheat:f5deb3,white:ffffff,whitesmoke:f5f5f5,yellow:ffff00,yellowgreen:9acd32".split(",").map((p) => p.split(":")));
116
+ 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"+
117
+ "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"+
118
+ "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"+
119
+ "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"+
120
+ "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"+
121
+ "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"+
122
+ ",thistle:d8bfd8,tomato:ff6347,turquoise:40e0d0,violet:ee82ee,wheat:f5deb3,white:ffffff,whitesmoke:f5f5f5,yellow:ffff00,yellowgreen:9acd32").split(",").map((p) => p.split(":")));
123
123
  function hexColor(c) {
124
124
  if (c == null || c === "") return void 0;
125
125
  const s = String(c).trim().toLowerCase();
@@ -996,6 +996,8 @@ function newContext() {
996
996
  /** @type {Set<string>} part libraries referenced (report ids) */
997
997
  libraries: /* @__PURE__ */ new Set(),
998
998
  cells: 0,
999
+ /** @type {any[]} every item tracked, with what happened to it (see items() in importRdlx's result) */
1000
+ items: [],
999
1001
  warn(msg) {
1000
1002
  if (!cx.warnings.includes(msg)) cx.warnings.push(msg);
1001
1003
  }
@@ -1005,24 +1007,35 @@ function newContext() {
1005
1007
  function track(cx, ar, label) {
1006
1008
  cx.stats.items++;
1007
1009
  const name2 = String(ar?.Name || label || ar?.Type || "item");
1010
+ const say = (kind, msg) => {
1011
+ if (!t3.notes.some((n) => n.message === msg)) t3.notes.push({ kind, message: msg });
1012
+ cx.warn(`${name2}: ${msg}`);
1013
+ };
1008
1014
  const t3 = {
1009
1015
  name: name2,
1010
1016
  state: "mapped",
1017
+ pos: typeof ar?.__pos === "number" ? ar.__pos : void 0,
1018
+ /** @type {{ kind: string, message: string }[]} */
1019
+ notes: [],
1020
+ /** @type {string[]} expressions that could not be translated */
1021
+ exprs: [],
1011
1022
  /** in the report, with something lost or changed */
1012
1023
  approx(msg) {
1013
1024
  if (t3.state === "mapped") t3.state = "approximated";
1014
- cx.warn(`${name2}: ${msg}`);
1025
+ say("approximated", msg);
1015
1026
  },
1016
1027
  /** for information only */
1017
1028
  note(msg) {
1018
- cx.warn(`${name2}: ${msg}`);
1029
+ say("info", msg);
1019
1030
  },
1020
1031
  /** not in the report */
1021
1032
  drop(msg) {
1022
1033
  t3.state = "dropped";
1023
- cx.warn(`${name2}: ${msg}`);
1034
+ say("dropped", msg);
1024
1035
  }
1025
1036
  };
1037
+ cx.items.push(t3);
1038
+ for (const x of Array.isArray(ar?.__exprs) ? ar.__exprs : []) if (typeof x === "string" && !t3.exprs.includes(x)) t3.exprs.push(x);
1026
1039
  for (const n of Array.isArray(ar?.__notes) ? ar.__notes : []) t3.approx(n);
1027
1040
  for (const n of Array.isArray(ar?.__info) ? ar.__info : []) t3.note(n);
1028
1041
  return t3;
@@ -1040,6 +1053,7 @@ function uniq(cx, base2, generated = false) {
1040
1053
  }
1041
1054
  function ex(cx, t3, v, ctx, opt = {}) {
1042
1055
  const r = translateExpression(v, { text: opt.text, fields: opt.fields, lit: opt.lit, region: ctx.region, scopes: cx.scopes, runScopes: cx.runScopes });
1056
+ if (!r.ok && typeof v === "string" && !t3.exprs.includes(v)) t3.exprs.push(v);
1043
1057
  if (!r.ok) t3.approx(`${r.notes.join("; ")}; ${opt.text ? "the expression is shown as text" : `${opt.what || "that setting"} is left out`}.`);
1044
1058
  else for (const n of r.notes) t3.approx(`${n}.`);
1045
1059
  return r.value;
@@ -1276,12 +1290,13 @@ function convertItem(ar, cx, ctx) {
1276
1290
  dropInside(ar, cx);
1277
1291
  return finish(cx, t3, null);
1278
1292
  }
1279
- const snap = { ...cx.stats };
1293
+ const snap = { ...cx.stats }, tracked = cx.items.length;
1280
1294
  try {
1281
1295
  return conv(ar, cx, ctx);
1282
1296
  } catch (e) {
1283
1297
  if (e instanceof ImportBudgetError) throw e;
1284
1298
  Object.assign(cx.stats, snap);
1299
+ cx.items.length = tracked;
1285
1300
  const t3 = track(cx, ar);
1286
1301
  t3.drop(`it could not be converted (${e instanceof Error ? e.message : e}), so it was left out.`);
1287
1302
  dropInside(ar, cx);
@@ -3313,7 +3328,7 @@ function convertReport(ar, cx, opts) {
3313
3328
  if (cx.columns) body.columns = cx.columns;
3314
3329
  if (more.length) body.name = sec0?.Name || "Section1";
3315
3330
  return {
3316
- $schema: "pagewright/report@1",
3331
+ $schema: "reportwright/report@1",
3317
3332
  name: name2,
3318
3333
  locale: lang2,
3319
3334
  ...currencyOf(lang2) ? { currency: currencyOf(lang2) } : {},
@@ -3354,13 +3369,15 @@ function importRdlx(input, opts = {}) {
3354
3369
  } catch (e) {
3355
3370
  if (e instanceof ImportBudgetError) {
3356
3371
  const error = `The report is too large to import: ${e.message}`;
3357
- return { definition: convertReport({}, newContext(), opts), warnings: [`${error}.`], stats: { items: 0, mapped: 0, approximated: 0, dropped: 0 }, error };
3372
+ return { definition: convertReport({}, newContext(), opts), warnings: [`${error}.`], stats: { items: 0, mapped: 0, approximated: 0, dropped: 0 }, items: [], error };
3358
3373
  }
3359
3374
  cx.warn(`The import stopped early (${e instanceof Error ? e.message : e}), so parts of the report are missing.`);
3360
3375
  definition = convertReport({}, newContext(), opts);
3361
3376
  }
3362
- return { definition, warnings: cx.warnings, stats: cx.stats };
3377
+ return { definition, warnings: cx.warnings, stats: cx.stats, items: importedItems(cx.items) };
3363
3378
  }
3379
+ 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 }));
3380
+ var rewordItems = (items, f) => (items || []).map((i2) => ({ ...i2, notes: i2.notes.map((n) => ({ ...n, message: f(n.message) })) }));
3364
3381
 
3365
3382
  // src/importers/rdl.js
3366
3383
  var RDL_NS = /^http:\/\/schemas\.microsoft\.com\/sqlserver\/reporting\/(\d{4})\/\d{2}\/reportdefinition$/i;
@@ -3388,7 +3405,7 @@ function importRdl(input, opts = {}) {
3388
3405
  const notes = [];
3389
3406
  let ar;
3390
3407
  try {
3391
- ar = toRdlx(root, notes, m ? Number(m[1]) : 2016);
3408
+ ar = toRdlx(root, notes, m ? Number(m[1]) : 2016, opts.resolve);
3392
3409
  } catch (e) {
3393
3410
  if (e instanceof ImportBudgetError) {
3394
3411
  const error = `The report is too large to import: ${e.message}`;
@@ -3402,10 +3419,12 @@ function importRdl(input, opts = {}) {
3402
3419
  const def = r.definition;
3403
3420
  for (const p of def.parameters || []) if (ar.__hidden?.has(p.name)) p.hidden = true;
3404
3421
  if (ar.__code) def.customCode = ar.__code;
3405
- const warnings = [...notes, ...r.warnings.filter((w) => !/is hidden in ActiveReports; ReportWright shows it/.test(w))].map((w) => w.replace(/ActiveReports/g, "SSRS"));
3406
- return { definition: def, warnings: [...new Set(warnings)], stats: r.stats };
3422
+ const hiddenNote = /is hidden in ActiveReports; ReportWright shows it/;
3423
+ const warnings = [...notes, ...r.warnings.filter((w) => !hiddenNote.test(w))].map((w) => w.replace(/ActiveReports/g, "SSRS"));
3424
+ const items = rewordItems(r.items.map((i2) => ({ ...i2, notes: i2.notes.filter((n) => !hiddenNote.test(n.message)) })), (w) => w.replace(/ActiveReports/g, "SSRS"));
3425
+ return { definition: def, warnings: [...new Set(warnings)], stats: r.stats, items };
3407
3426
  }
3408
- function toRdlx(root, notes, year) {
3427
+ function toRdlx(root, notes, year, resolve2) {
3409
3428
  const NS = root.ns;
3410
3429
  const kids = (e, name2) => e ? e.children.filter((c) => c.ns === NS && (name2 == null || c.name === name2)) : [];
3411
3430
  const kid = (e, name2) => e?.children.find((c) => c.ns === NS && c.name === name2);
@@ -3572,6 +3591,7 @@ function toRdlx(root, notes, year) {
3572
3591
  Name: e.attrs.Name,
3573
3592
  __notes: itemNotes,
3574
3593
  __info: itemInfo,
3594
+ __pos: e.pos,
3575
3595
  Left: raw(e, "Left"),
3576
3596
  Top: raw(e, "Top"),
3577
3597
  Width: raw(e, "Width"),
@@ -4107,17 +4127,46 @@ function toRdlx(root, notes, year) {
4107
4127
  const r = e.name === "Tablix" || e.name === "Chart" ? e.attrs.Name || reg : reg;
4108
4128
  for (const c of e.children) prepass(c, r);
4109
4129
  })(root, null);
4130
+ function sharedSource(ref) {
4131
+ let text;
4132
+ try {
4133
+ text = resolve2?.("datasource", ref);
4134
+ } catch {
4135
+ text = null;
4136
+ }
4137
+ if (typeof text !== "string") return null;
4138
+ let doc2;
4139
+ try {
4140
+ doc2 = parseXml(text);
4141
+ } catch (e) {
4142
+ notes.push(`The shared data source "${ref}" could not be read (${e instanceof Error ? e.message : e}); it is treated as SQL Server.`);
4143
+ return null;
4144
+ }
4145
+ const sub = (e, n) => e?.children.find((c) => c.name === n);
4146
+ const props = doc2.name === "RptDataSource" ? sub(doc2, "ConnectionProperties") : doc2.name === "DataSourceDefinition" ? doc2 : null;
4147
+ if (!props) {
4148
+ notes.push(`The shared data source "${ref}" is not an SSRS data source (its root is <${doc2.name}>); it is treated as SQL Server.`);
4149
+ return null;
4150
+ }
4151
+ return { provider: (sub(props, "Extension")?.text || "SQL").trim(), connect: (sub(props, "ConnectString")?.text ?? "").trim() };
4152
+ }
4110
4153
  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;
4111
4154
  const DataSources = list2(root, "DataSources", "DataSource").map((d) => {
4112
4155
  const name2 = d.attrs.Name;
4113
4156
  const cp = kid(d, "ConnectionProperties");
4114
4157
  let provider = raw(cp, "DataProvider") || "";
4158
+ let connect = raw(cp, "ConnectString") ?? "";
4115
4159
  if (!cp && kid(d, "DataSourceReference")) {
4116
- provider = "SQL";
4117
- 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.`);
4160
+ const ref = raw(d, "DataSourceReference") ?? "";
4161
+ const shared = sharedSource(ref);
4162
+ if (shared) ({ provider, connect } = shared);
4163
+ else {
4164
+ provider = "SQL";
4165
+ notes.push(`Data source "${name2}" is the shared data source "${ref}", whose connection is not in the file; it is treated as SQL Server.`);
4166
+ }
4118
4167
  }
4119
4168
  if (/^(OLEDB-MD|ESSBASE|SAPBW|SQLAS|HYPERION)/i.test(provider)) provider = `${provider} (MDX)`;
4120
- return { Name: name2, ConnectionProperties: { DataProvider: provider, ConnectString: raw(cp, "ConnectString") ?? "" } };
4169
+ return { Name: name2, ConnectionProperties: { DataProvider: provider, ConnectString: connect } };
4121
4170
  });
4122
4171
  const entered = /* @__PURE__ */ new Map();
4123
4172
  const providers = new Map(DataSources.map((d) => [d.Name, String(d.ConnectionProperties.DataProvider).toUpperCase()]));
@@ -4958,7 +5007,7 @@ function importJrxml(input, opts = {}) {
4958
5007
  const charts = /* @__PURE__ */ new Map();
4959
5008
  let ar;
4960
5009
  try {
4961
- ar = toRdlx2(root, notes, charts, opts.name || root.attrs.name);
5010
+ ar = toRdlx2(root, notes, charts, opts.name || root.attrs.name, opts.resolve);
4962
5011
  } catch (e) {
4963
5012
  if (e instanceof ImportBudgetError) {
4964
5013
  const error = `The report is too large to import: ${e.message}`;
@@ -4984,7 +5033,7 @@ function importJrxml(input, opts = {}) {
4984
5033
  r.definition.arithmetic = "double";
4985
5034
  placeCharts(r.definition, charts);
4986
5035
  const warnings = [...notes, ...r.warnings].map((w) => w.replace(/ActiveReports/g, "JasperReports"));
4987
- return { definition: r.definition, warnings: [...new Set(warnings)], stats: r.stats };
5036
+ return { definition: r.definition, warnings: [...new Set(warnings)], stats: r.stats, items: rewordItems(r.items, (w) => w.replace(/ActiveReports/g, "JasperReports")) };
4988
5037
  }
4989
5038
  function stripJasperDoctype(s) {
4990
5039
  const i2 = s.indexOf("<!DOCTYPE");
@@ -4993,9 +5042,9 @@ function stripJasperDoctype(s) {
4993
5042
  if (e < 0) return s;
4994
5043
  const decl = s.slice(i2, e + 1);
4995
5044
  if (decl.includes("[") || !/^<!DOCTYPE\s+jasperReport\s/.test(decl)) return s;
4996
- return s.slice(0, i2) + s.slice(e + 1);
5045
+ return s.slice(0, i2) + decl.replace(/[^\n]/g, " ") + s.slice(e + 1);
4997
5046
  }
4998
- function toRdlx2(root, notes, charts, reportName) {
5047
+ function toRdlx2(root, notes, charts, reportName, resolve2) {
4999
5048
  const kid = (e, n) => e?.children.find((c) => c.name === n);
5000
5049
  const kids = (e, n) => e ? e.children.filter((c) => n == null || c.name === n) : [];
5001
5050
  const txt = (e, n) => {
@@ -5179,6 +5228,7 @@ function toRdlx2(root, notes, charts, reportName) {
5179
5228
  return "=" + v.s;
5180
5229
  } catch (e) {
5181
5230
  if (!(e instanceof Untranslatable2)) throw e;
5231
+ (item2.__exprs || (item2.__exprs = [])).push(s);
5182
5232
  (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.`);
5183
5233
  return s.startsWith("=") ? `="${s.replace(/"/g, '""')}"` : s;
5184
5234
  }
@@ -5188,12 +5238,50 @@ function toRdlx2(root, notes, charts, reportName) {
5188
5238
  return "=" + vb2(String(src).trim(), c);
5189
5239
  } catch (e) {
5190
5240
  if (!(e instanceof Untranslatable2)) throw e;
5241
+ (item2.__exprs || (item2.__exprs = [])).push(String(src).trim());
5191
5242
  (item2.__notes || (item2.__notes = [])).push(`${what} uses ${e.message}, which has no ReportWright equivalent, so it is left out.`);
5192
5243
  return void 0;
5193
5244
  }
5194
5245
  }
5195
5246
  const styles = new Map(kids(root, "style").map((s) => [s.attrs.name, s]));
5196
- const defStyle = kids(root, "style").find((s) => s.attrs.isDefault === "true" || s.attrs.default === "true");
5247
+ const seenTemplates = /* @__PURE__ */ new Set();
5248
+ (function templates(el, depth) {
5249
+ for (const t3 of kids(el, "template")) {
5250
+ const src = (kid(t3, "expression")?.text ?? t3.text).trim();
5251
+ const lit2 = /^"([^"]+)"$/.exec(src);
5252
+ const ref = lit2 ? lit2[1] : depth > 0 && !/["$(){}+]/.test(src) ? src : null;
5253
+ if (!ref) {
5254
+ if (src) note(`A style template is chosen by an expression (${src.slice(0, 120)}), so its styles are missing.`);
5255
+ continue;
5256
+ }
5257
+ if (seenTemplates.has(ref) || seenTemplates.size >= 32) continue;
5258
+ seenTemplates.add(ref);
5259
+ let text;
5260
+ try {
5261
+ text = resolve2?.("template", ref);
5262
+ } catch {
5263
+ text = null;
5264
+ }
5265
+ if (typeof text !== "string") {
5266
+ note(`The style template "${ref}" is not in the file, so items that use its styles have the default style.`);
5267
+ continue;
5268
+ }
5269
+ let doc2;
5270
+ try {
5271
+ doc2 = parseXml(text);
5272
+ } catch (e) {
5273
+ note(`The style template "${ref}" could not be read (${e instanceof Error ? e.message : e}), so its styles are missing.`);
5274
+ continue;
5275
+ }
5276
+ if (doc2.name !== "jasperTemplate") {
5277
+ note(`The style template "${ref}" is not a JasperReports template (its root is <${doc2.name}>), so its styles are missing.`);
5278
+ continue;
5279
+ }
5280
+ for (const s of kids(doc2, "style")) if (s.attrs.name && !styles.has(s.attrs.name)) styles.set(s.attrs.name, s);
5281
+ if (depth < 8) templates(doc2, depth + 1);
5282
+ }
5283
+ })(root, 0);
5284
+ const defStyle = [...styles.values()].find((s) => s.attrs.isDefault === "true" || s.attrs.default === "true");
5197
5285
  function styleAttrs(name2, seen = 0) {
5198
5286
  const s = styles.get(name2);
5199
5287
  if (!s || seen > 10) return {};
@@ -5348,7 +5436,7 @@ function toRdlx2(root, notes, charts, reportName) {
5348
5436
  }
5349
5437
  function item(n, c) {
5350
5438
  const a = n.a, re = n.re, e = n.el;
5351
- const base2 = { Name: nameFor(n, n.kind), Left: pt(a.x), Top: pt(a.y), Width: pt(a.width), Height: pt(a.height) };
5439
+ 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) };
5352
5440
  const it = { ...base2 };
5353
5441
  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")) };
5354
5442
  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.`);
@@ -5954,7 +6042,7 @@ function importBirt(input, opts = {}) {
5954
6042
  r.definition.nullOrder = "low";
5955
6043
  r.definition.arithmetic = "double";
5956
6044
  r.definition.bandRows = "first-last";
5957
- return { definition: r.definition, warnings: [...new Set(warnings)], stats: r.stats };
6045
+ return { definition: r.definition, warnings: [...new Set(warnings)], stats: r.stats, items: rewordItems(r.items, (w) => w.replace(/ActiveReports/g, "BIRT")) };
5958
6046
  }
5959
6047
  var PROPS = /* @__PURE__ */ new Set(["property", "text-property", "expression", "xml-property", "html-property", "encrypted-property"]);
5960
6048
  var prop = (e, name2) => e?.children.find((c) => PROPS.has(c.name) && c.attrs.name === name2)?.text;
@@ -6177,6 +6265,7 @@ function toRdlx3(root, notes, reportName) {
6177
6265
  return "=" + vb2(s, c);
6178
6266
  } catch (e) {
6179
6267
  if (!(e instanceof Untranslatable2)) throw e;
6268
+ (item2.__exprs || (item2.__exprs = [])).push(s);
6180
6269
  (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.`);
6181
6270
  return s.startsWith("=") ? `="${s.replace(/"/g, '""')}"` : s;
6182
6271
  }
@@ -6186,6 +6275,7 @@ function toRdlx3(root, notes, reportName) {
6186
6275
  return "=" + vb2(src, c);
6187
6276
  } catch (e) {
6188
6277
  if (!(e instanceof Untranslatable2)) throw e;
6278
+ (item2.__exprs || (item2.__exprs = [])).push(String(src));
6189
6279
  (item2.__notes || (item2.__notes = [])).push(`${what} uses ${e.message}, which has no ReportWright equivalent, so it is left out.`);
6190
6280
  return void 0;
6191
6281
  }
@@ -6366,7 +6456,7 @@ function toRdlx3(root, notes, reportName) {
6366
6456
  const w = Math.min(W, len(prop(e, "width"), W, W)) || W;
6367
6457
  const given = len(prop(e, "height"), 0, 0);
6368
6458
  const x = len(prop(e, "x"), W, 0);
6369
- const it = { Name: nameFor(e, e.name.replace(/(^|-)(\w)/g, (_, __, ch) => ch.toUpperCase())), Left: pt(x), Width: pt(w) };
6459
+ const it = { __pos: e.pos, Name: nameFor(e, e.name.replace(/(^|-)(\w)/g, (_, __, ch) => ch.toUpperCase())), Left: pt(x), Width: pt(w) };
6370
6460
  const vis = listProp(e, "visibility")[0];
6371
6461
  if (vis) {
6372
6462
  const ve = prop(vis, "valueExpr");
@@ -6424,6 +6514,7 @@ function toRdlx3(root, notes, reportName) {
6424
6514
  v = "=" + binding(b, c, 0);
6425
6515
  } catch (er) {
6426
6516
  if (!(er instanceof Untranslatable2)) throw er;
6517
+ (it.__exprs || (it.__exprs = [])).push(String(prop(b, "expression") ?? col));
6427
6518
  (it.__notes || (it.__notes = [])).push(`its column "${col}" uses ${er.message}, so it is shown as text.`);
6428
6519
  v = col;
6429
6520
  }
@@ -6452,6 +6543,7 @@ function toRdlx3(root, notes, reportName) {
6452
6543
  pieces.push(`(${vb2(decodeHtml(p.e), c)})`);
6453
6544
  } catch (er) {
6454
6545
  if (!(er instanceof Untranslatable2)) throw er;
6546
+ (it.__exprs || (it.__exprs = [])).push(decodeHtml(p.e));
6455
6547
  (it.__notes || (it.__notes = [])).push(`a <value-of> uses ${er.message}, so it is left out.`);
6456
6548
  }
6457
6549
  }
@@ -6968,7 +7060,7 @@ function nestedFields(rows) {
6968
7060
  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 })) }));
6969
7061
  }
6970
7062
 
6971
- // node_modules/zustand/esm/vanilla.mjs
7063
+ // ../reportwright/node_modules/zustand/esm/vanilla.mjs
6972
7064
  var createStoreImpl = (createState) => {
6973
7065
  let state;
6974
7066
  const listeners = /* @__PURE__ */ new Set();
@@ -6992,7 +7084,7 @@ var createStoreImpl = (createState) => {
6992
7084
  };
6993
7085
  var createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);
6994
7086
 
6995
- // node_modules/zustand/esm/react.mjs
7087
+ // ../reportwright/node_modules/zustand/esm/react.mjs
6996
7088
  var import_react = __toESM(require_react(), 1);
6997
7089
  var identity = (arg) => arg;
6998
7090
  function useStore(api, selector = identity) {
@@ -7008,7 +7100,7 @@ function useStore(api, selector = identity) {
7008
7100
  // src/designer/store.js
7009
7101
  var import_react2 = __toESM(require_react(), 1);
7010
7102
 
7011
- // node_modules/immer/dist/immer.mjs
7103
+ // ../reportwright/node_modules/immer/dist/immer.mjs
7012
7104
  var NOTHING = /* @__PURE__ */ Symbol.for("immer-nothing");
7013
7105
  var DRAFTABLE = /* @__PURE__ */ Symbol.for("immer-draftable");
7014
7106
  var DRAFT_STATE = /* @__PURE__ */ Symbol.for("immer-state");
@@ -8154,7 +8246,7 @@ function minSize(it) {
8154
8246
  }
8155
8247
  for (const k of ["w", "h"]) if (typeof it[k] === "number" && it[k] < 1) it[k] = 1;
8156
8248
  }
8157
- function moveItems(ids, dx, dy) {
8249
+ function moveItems(ids, dx, dy, { nudge = false } = {}) {
8158
8250
  if (!dx && !dy) return;
8159
8251
  if (S().cells && wouldOverlap(S().def, ids, (it) => ({ x: it.x + dx, y: it.y + dy, w: it.w, h: it.h }))) {
8160
8252
  S().setUi({ saveError: CELL_TAKEN() });
@@ -8166,7 +8258,7 @@ function moveItems(ids, dx, dy) {
8166
8258
  const f = findItem(d, id);
8167
8259
  if (!f) continue;
8168
8260
  const room = roomFor(d, f);
8169
- f.item.x = round(clamp(f.item.x + dx, 0, Math.max(0, room - f.item.w)));
8261
+ 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)));
8170
8262
  f.item.y = round(Math.max(0, f.item.y + dy));
8171
8263
  growToFit(d, f);
8172
8264
  }
@@ -8616,6 +8708,7 @@ function alignItems(ids, how, toPage = false) {
8616
8708
  });
8617
8709
  }
8618
8710
  var round = (v) => Math.round(v * 100) / 100;
8711
+ var nudgeStep = ({ snap, grid, cells, cellSize }, shift2) => (cells ? cellSize : snap ? grid : 1) * (shift2 ? 10 : 1);
8619
8712
  var clamp = (v, a, b) => Math.max(a, Math.min(b, v));
8620
8713
  var CELL_TAKEN = () => t(S().lang, "cellTaken");
8621
8714
  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;
@@ -8706,7 +8799,47 @@ function ExprInput({ value, onChange, onOpen, placeholder: placeholder2 }) {
8706
8799
  issues.map((i2, k) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "warn", "data-testid": "field-warning", children: issueText(T, i2) }, k))
8707
8800
  ] });
8708
8801
  }
8802
+ function InfoTip({ text, id }) {
8803
+ const T = useT();
8804
+ const own = (0, import_react3.useId)();
8805
+ const tipId = id || `tip${own.replace(/:/g, "")}`;
8806
+ const [open, setOpen] = (0, import_react3.useState)(false);
8807
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "infotip", onMouseEnter: () => setOpen(true), onMouseLeave: () => setOpen(false), children: [
8808
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
8809
+ "button",
8810
+ {
8811
+ type: "button",
8812
+ className: "infotip-btn",
8813
+ "aria-label": T("c132_moreInfo"),
8814
+ "aria-describedby": tipId,
8815
+ "aria-expanded": open,
8816
+ onClick: () => setOpen((v) => !v),
8817
+ onFocus: () => setOpen(true),
8818
+ onBlur: () => setOpen(false),
8819
+ onKeyDown: (e) => {
8820
+ if (e.key === "Escape" && open) {
8821
+ e.preventDefault();
8822
+ e.stopPropagation();
8823
+ setOpen(false);
8824
+ }
8825
+ },
8826
+ children: "ⓘ"
8827
+ }
8828
+ ),
8829
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { role: "tooltip", id: tipId, className: "infotip-text", hidden: !open, children: text })
8830
+ ] });
8831
+ }
8832
+ var LONG_HINT = 90;
8709
8833
  function Field({ label, children, hint }) {
8834
+ if (typeof hint === "string" && hint.length > LONG_HINT) {
8835
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "field-tip", children: [
8836
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "field", children: [
8837
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: label }),
8838
+ children
8839
+ ] }),
8840
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InfoTip, { text: hint })
8841
+ ] });
8842
+ }
8710
8843
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "field", children: [
8711
8844
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: label }),
8712
8845
  children,
@@ -9137,8 +9270,8 @@ function ThemeSection() {
9137
9270
  }
9138
9271
  ) }),
9139
9272
  mode === "report" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Field, { label: T("themeReportPick"), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ReportSelect, { value: src, exclude: id, onChange: setSrc, "data-testid": "theme-picker", "aria-label": T("themeReportPick") }) }),
9140
- mode === "expr" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Field, { label: T("themeExprLabel"), hint: T("themeExprHint"), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TextInput, { mono: true, value: src || "", onChange: (v) => setSrc(v ? v.startsWith("=") ? v : `=${v}` : void 0), placeholder: '=IIf(Parameters.Dark, "dark-theme", "light-theme")', "data-testid": "theme-expr", "ari\
9141
- a-label": T("themeExprLabel") }) }),
9273
+ mode === "expr" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Field, { label: T("themeExprLabel"), hint: T("themeExprHint"), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TextInput, { mono: true, value: src || "", onChange: (v) => setSrc(v ? v.startsWith("=") ? v : `=${v}` : void 0), placeholder: '=IIf(Parameters.Dark, "dark-theme", "light-theme")', "data-testid": "theme-expr", [("ari"+
9274
+ "a-label")]: T("themeExprLabel") }) }),
9142
9275
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hint", children: mode === "own" ? T("themeOwnHint") : T("themeFallbackHint") }),
9143
9276
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "grid2", "data-testid": "theme-colors", children: THEME_COLORS.map((k) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Field, { label: k, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ColorInput, { value: td.colors?.[k] ?? DEFAULT_THEME.colors[k], onChange: (v) => setTd((x) => {
9144
9277
  x.colors || (x.colors = {});
@@ -9202,7 +9335,11 @@ function LayersPanel() {
9202
9335
  });
9203
9336
  });
9204
9337
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "pane", "data-testid": "layers", children: [
9205
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", { children: T("layers") }),
9338
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
9339
+ T("layers"),
9340
+ " ",
9341
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(InfoTip, { text: T("layersHint") })
9342
+ ] }) }),
9206
9343
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "pane-body", children: [
9207
9344
  layers.map((l, i2) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "layer-row", "data-layer": l.name, children: [
9208
9345
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TextInput, { value: l.name, onChange: (v) => rename(i2, v.replace(/[^\w -]/g, "")), "aria-label": T("layerName"), readOnly: readOnly2 }),
@@ -9247,8 +9384,7 @@ function LayersPanel() {
9247
9384
  children: T("layerAdd")
9248
9385
  }
9249
9386
  )
9250
- ] }),
9251
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hint", children: T("layersHint") })
9387
+ ] })
9252
9388
  ] })
9253
9389
  ] });
9254
9390
  }
@@ -9338,7 +9474,11 @@ function PartsPanel() {
9338
9474
  const [pick, setPick] = (0, import_react7.useState)("");
9339
9475
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "pane", "data-testid": "parts-panel", children: [
9340
9476
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("h4", { children: [
9341
- T("parts"),
9477
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
9478
+ T("parts"),
9479
+ " ",
9480
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(InfoTip, { text: T("partsHint") })
9481
+ ] }),
9342
9482
  libs.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "btn sm ghost", onClick: () => libs.forEach((l) => fetchReused(l, true)), title: T("partsReloadHint"), children: T("partsReload") })
9343
9483
  ] }),
9344
9484
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "pane-body", children: [
@@ -9361,8 +9501,7 @@ function PartsPanel() {
9361
9501
  children: T("libraryAdd")
9362
9502
  }
9363
9503
  )
9364
- ] }),
9365
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hint", children: T("partsHint") })
9504
+ ] })
9366
9505
  ] })
9367
9506
  ] });
9368
9507
  }
@@ -9913,8 +10052,8 @@ function Band({ section, label, scale, bw: bandW, drag, setDrag, phBox = null })
9913
10052
  (mb.extras || []).map((p) => {
9914
10053
  const i2 = (contentList || []).findIndex((e) => e?.placeholder === p.name);
9915
10054
  if (i2 >= 0) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Band, { section: `content:${i2}`, scale, bw: p.w, drag, setDrag, phBox: p }, p.name);
9916
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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__ */ (0, import_jsx_runtime6.jsx)("button", { className: "\
9917
- btn sm", onClick: () => fillPlaceholder(p), "data-testid": `fill-placeholder-${p.name}`, children: T("fillPlaceholder", { name: p.name }) }) }, p.name);
10055
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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__ */ (0, import_jsx_runtime6.jsx)("button", { className: (""+
10056
+ "btn sm"), onClick: () => fillPlaceholder(p), "data-testid": `fill-placeholder-${p.name}`, children: T("fillPlaceholder", { name: p.name }) }) }, p.name);
9918
10057
  })
9919
10058
  ] }) : surface
9920
10059
  ] });
@@ -10286,6 +10425,13 @@ function PartPreview({ item, scale }) {
10286
10425
  tag
10287
10426
  ] });
10288
10427
  }
10428
+ function checkedOnCanvas(v) {
10429
+ if (v == null || typeof v === "boolean" || typeof v === "number") return v === true || v === 1;
10430
+ const s = String(v).trim();
10431
+ if (!isDynamic(s)) return ["true", "yes", "y", "1"].includes(s.toLowerCase());
10432
+ const lit2 = /^=\s*(true|false|1|0)\s*$/i.exec(s)?.[1]?.toLowerCase();
10433
+ return lit2 ? lit2 === "true" || lit2 === "1" : null;
10434
+ }
10289
10435
  function ItemBody({ item, scale }) {
10290
10436
  const base2 = useDesigner((s) => s.def.styles?.base);
10291
10437
  const images = useDesigner((s) => s.def.images);
@@ -10348,8 +10494,9 @@ function ItemBody({ item, scale }) {
10348
10494
  if (item.type === "checkbox") {
10349
10495
  const c = textCss([base2, item.style], scale, false);
10350
10496
  const size = Math.min(item.h, (Number(item.style?.fontSize) || Number(base2?.fontSize) || 9) + 2) * scale;
10497
+ const on = checkedOnCanvas(item.value);
10351
10498
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "box", style: { ...c.box, alignItems: "center", gap: 4 * scale, padding: 0 }, children: [
10352
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { width: size, height: size, border: "1px solid #1f2328", borderRadius: 2, flex: "none", display: "grid", placeItems: "center", fontSize: size * 0.8 }, children: "✓" }),
10499
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("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 ? "✓" : "" }),
10353
10500
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: `tx${isDynamic(item.text) ? " dyn" : ""}`, style: c.text, children: shown(item.text) })
10354
10501
  ] });
10355
10502
  }
@@ -10613,14 +10760,14 @@ var import_react10 = __toESM(require_react(), 1);
10613
10760
  // src/designer/ExprCode.jsx
10614
10761
  var import_react9 = __toESM(require_react(), 1);
10615
10762
 
10616
- // node_modules/@marijn/find-cluster-break/src/index.js
10763
+ // ../reportwright/node_modules/@marijn/find-cluster-break/src/index.js
10617
10764
  var rangeFrom = [];
10618
10765
  var rangeTo = [];
10619
10766
  (() => {
10620
- 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,,,,,,\
10621
- 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,\
10622
- 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,\
10623
- 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);
10767
+ 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,,,,,,"+
10768
+ "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,"+
10769
+ "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,"+
10770
+ "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);
10624
10771
  for (let i2 = 0, n = 0; i2 < numbers.length; i2++)
10625
10772
  (i2 % 2 ? rangeTo : rangeFrom).push(n = n + numbers[i2]);
10626
10773
  })();
@@ -10690,7 +10837,7 @@ function codePointSize(code2) {
10690
10837
  return code2 < 65536 ? 1 : 2;
10691
10838
  }
10692
10839
 
10693
- // node_modules/@codemirror/state/dist/index.js
10840
+ // ../reportwright/node_modules/@codemirror/state/dist/index.js
10694
10841
  var Text = class _Text {
10695
10842
  /**
10696
10843
  Get the line description around the given position.
@@ -14102,7 +14249,7 @@ function findColumn(string2, col, tabSize, strict) {
14102
14249
  return strict === true ? -1 : string2.length;
14103
14250
  }
14104
14251
 
14105
- // node_modules/style-mod/src/style-mod.js
14252
+ // ../reportwright/node_modules/style-mod/src/style-mod.js
14106
14253
  var C = "ͼ";
14107
14254
  var COUNT = typeof Symbol == "undefined" ? "__" + C : Symbol.for(C);
14108
14255
  var SET = typeof Symbol == "undefined" ? "__styleSet" + Math.floor(Math.random() * 1e8) : /* @__PURE__ */ Symbol("styleSet");
@@ -14238,7 +14385,7 @@ var StyleSet = class {
14238
14385
  }
14239
14386
  };
14240
14387
 
14241
- // node_modules/w3c-keyname/index.js
14388
+ // ../reportwright/node_modules/w3c-keyname/index.js
14242
14389
  var base = {
14243
14390
  8: "Backspace",
14244
14391
  9: "Tab",
@@ -14344,7 +14491,7 @@ function keyName(event) {
14344
14491
  return name2;
14345
14492
  }
14346
14493
 
14347
- // node_modules/@codemirror/view/dist/index.js
14494
+ // ../reportwright/node_modules/@codemirror/view/dist/index.js
14348
14495
  var nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
14349
14496
  var doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
14350
14497
  var ie_edge = /* @__PURE__ */ /Edge\/(\d+)/.exec(nav.userAgent);
@@ -23220,7 +23367,7 @@ GutterMarker.prototype.mapMode = MapMode.TrackBefore;
23220
23367
  GutterMarker.prototype.startSide = GutterMarker.prototype.endSide = -1;
23221
23368
  GutterMarker.prototype.point = true;
23222
23369
 
23223
- // node_modules/@lezer/common/dist/index.js
23370
+ // ../reportwright/node_modules/@lezer/common/dist/index.js
23224
23371
  var DefaultBufferLength = 1024;
23225
23372
  var nextPropID = 0;
23226
23373
  var Range2 = class {
@@ -24844,7 +24991,7 @@ var StringInput = class {
24844
24991
  };
24845
24992
  var stoppedInner = new NodeProp({ perNode: true });
24846
24993
 
24847
- // node_modules/@lezer/highlight/dist/index.js
24994
+ // ../reportwright/node_modules/@lezer/highlight/dist/index.js
24848
24995
  var nextTagID = 0;
24849
24996
  var Tag = class _Tag {
24850
24997
  /**
@@ -25568,7 +25715,7 @@ var classHighlighter = tagHighlighter([
25568
25715
  { tag: tags.punctuation, class: "tok-punctuation" }
25569
25716
  ]);
25570
25717
 
25571
- // node_modules/@codemirror/language/dist/index.js
25718
+ // ../reportwright/node_modules/@codemirror/language/dist/index.js
25572
25719
  var _a;
25573
25720
  var languageDataProp = /* @__PURE__ */ new NodeProp();
25574
25721
  function defineLanguageFacet(baseData) {
@@ -27195,7 +27342,7 @@ var marks = {
27195
27342
  auto: /* @__PURE__ */ Decoration.mark({ class: "cm-iso", inclusive: true, attributes: { dir: "auto" }, bidiIsolate: null })
27196
27343
  };
27197
27344
 
27198
- // node_modules/@codemirror/commands/dist/index.js
27345
+ // ../reportwright/node_modules/@codemirror/commands/dist/index.js
27199
27346
  var toggleComment = (target) => {
27200
27347
  let { state } = target, line2 = state.doc.lineAt(state.selection.main.from), config2 = getConfig(target.state, line2.from);
27201
27348
  return config2.line ? toggleLineComment(target) : config2.block ? toggleBlockCommentByLine(target) : false;
@@ -28289,7 +28436,7 @@ var defaultKeymap = /* @__PURE__ */ [
28289
28436
  { key: "Ctrl-m", mac: "Shift-Alt-m", run: toggleTabFocusMode }
28290
28437
  ].concat(standardKeymap);
28291
28438
 
28292
- // node_modules/@codemirror/autocomplete/dist/index.js
28439
+ // ../reportwright/node_modules/@codemirror/autocomplete/dist/index.js
28293
28440
  var CompletionContext = class {
28294
28441
  /**
28295
28442
  Create a new completion context. (Mostly useful for testing
@@ -30851,8 +30998,8 @@ function GroupsEditor({ table: table2, openExpr }) {
30851
30998
  }
30852
30999
  }, `${table2.id}.g${i2}.collapsible`) }),
30853
31000
  g.collapsible && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Check, { label: T("i_startCollapsed"), checked: g.initiallyCollapsed, onChange: (v) => setG(i2, "initiallyCollapsed", v) }),
30854
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("groupParent"), hint: T("groupParentHint"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ExprInput, { value: g.parent || "", onChange: (v) => setG(i2, "parent", v), onOpen: () => openExpr({ value: g.parent || "", dataSet: table2.dataSet, onSave: (v) => setG(i2, "parent", v), title: T("groupParent") }), placeholder: "=\
30855
- Fields.managerId" }) }),
31001
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("groupParent"), hint: T("groupParentHint"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ExprInput, { value: g.parent || "", onChange: (v) => setG(i2, "parent", v), onOpen: () => openExpr({ value: g.parent || "", dataSet: table2.dataSet, onSave: (v) => setG(i2, "parent", v), title: T("groupParent") }), placeholder: ("="+
31002
+ "Fields.managerId") }) }),
30856
31003
  g.parent && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "grid2", children: [
30857
31004
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("groupIndent"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NumberInput, { value: g.indent || 0, step: 1, onChange: (v) => setG(i2, "indent", Math.max(0, v) || void 0) }) }),
30858
31005
  g.collapsible && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("groupExpandLevels"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NumberInput, { value: g.expandLevels ?? "", step: 1, onChange: (v) => setG(i2, "expandLevels", Number.isFinite(v) && v >= 0 ? Math.round(v) : void 0) }) })
@@ -31045,8 +31192,8 @@ function OverlaysEditor({ value, onChange, openExpr, dataSet, chartType }) {
31045
31192
  numOrExpr(o, i2, "from", T("i_from")),
31046
31193
  numOrExpr(o, i2, "to", T("i_to"))
31047
31194
  ] }),
31048
- (o.type === "line" || o.type === "band") && chartType !== "gauge" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("overlayAxis"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Select, { value: o.axis || "primary", options: [{ value: "primary", label: T("axisPrimary") }, { value: "secondary", label: T("axisSecondary") }], onChange: (v) => set2(i2, "axis", v === "p\
31049
- rimary" ? void 0 : v), "aria-label": `${T("overlayAxis")} ${i2 + 1}` }) }),
31195
+ (o.type === "line" || o.type === "band") && chartType !== "gauge" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("overlayAxis"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Select, { value: o.axis || "primary", options: [{ value: "primary", label: T("axisPrimary") }, { value: "secondary", label: T("axisSecondary") }], onChange: (v) => set2(i2, "axis", v === ("p"+
31196
+ "rimary") ? void 0 : v), "aria-label": `${T("overlayAxis")} ${i2 + 1}` }) }),
31050
31197
  o.type === "line" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Check, { label: T("overlayShowValue"), checked: o.showValue !== false, onChange: (v) => set2(i2, "showValue", v ? void 0 : false) }),
31051
31198
  chartType !== "gauge" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Check, { label: T("overlayInLegend"), checked: o.legend !== false, onChange: (v) => set2(i2, "legend", v ? void 0 : false) }),
31052
31199
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("i_label"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TextInput, { value: o.label, onChange: (v) => set2(i2, "label", v), "aria-label": T("i_overlayLabel") }) })
@@ -31208,8 +31355,8 @@ function ActionEditor({ value, onChange, openExpr, dataSet, label }) {
31208
31355
  const target = useReportParams(a.type === "report" ? a.report : null);
31209
31356
  const own = (def.parameters || []).map((p) => ({ name: p.name, prompt: p.prompt }));
31210
31357
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { display: "grid", gap: 6 }, children: [
31211
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: label || T("i_actionOnClick"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(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_actBo\
31212
- okmark") }, { value: "toggleItem", label: T("actionToggleItem") }], onChange: (v) => set2({ type: v || "none" }) }) }),
31358
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: label || T("i_actionOnClick"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(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_actBo"+
31359
+ "okmark")) }, { value: "toggleItem", label: T("actionToggleItem") }], onChange: (v) => set2({ type: v || "none" }) }) }),
31213
31360
  a.type === "toggleItem" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("actionToggleTarget"), hint: T("actionToggleHint"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Select, { value: a.target, allowEmpty: true, options: itemNames, onChange: (v) => set2({ target: v }), "data-testid": "toggle-target" }) }),
31214
31361
  a.type === "url" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("i_url"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ExprInput, { value: a.url, onChange: (v) => set2({ url: v }), onOpen: () => openExpr({ value: a.url, dataSet, onSave: (v) => set2({ url: v }), title: T("i_url") }) }) }),
31215
31362
  a.type === "bookmark" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("jumpToBookmark"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ExprInput, { value: a.target, onChange: (v) => set2({ target: v }), onOpen: () => openExpr({ value: a.target, dataSet, onSave: (v) => set2({ target: v }), title: T("jumpToBookmark") }) }) }),
@@ -31343,8 +31490,8 @@ function CellProps({ table: table2, sel, openExpr }) {
31343
31490
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("i_heightPt"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NumberInput, { value: row.height || 18, step: 1, onChange: (v) => setRow("height", Math.max(6, v)) }) }),
31344
31491
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Check, { label: T("rowCanGrow"), checked: row.canGrow !== false, onChange: (v) => setRow("canGrow", v ? void 0 : false) })
31345
31492
  ] }),
31346
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("rowHidden"), hint: T("rowHiddenHint"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ExprInput, { value: row.hidden, onChange: (v) => setRow("hidden", v || void 0), onOpen: () => openExpr({ value: row.hidden, dataSet: table2.dataSet, onSave: (v) => setRow("hidden", v || void 0), title: T("rowHidden") }), placeholder: "\
31347
- =Fields.amount = 0" }) }),
31493
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("rowHidden"), hint: T("rowHiddenHint"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ExprInput, { value: row.hidden, onChange: (v) => setRow("hidden", v || void 0), onOpen: () => openExpr({ value: row.hidden, dataSet: table2.dataSet, onSave: (v) => setRow("hidden", v || void 0), title: T("rowHidden") }), placeholder: (""+
31494
+ "=Fields.amount = 0") }) }),
31348
31495
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "grid2", children: ROW_STYLE.map((p) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: p.type === "color" || p.type === "text" ? { gridColumn: "1 / -1" } : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PropEditor, { p, value: row.style?.[p.key], onChange: (v) => setRowStyle(p.key, v), openExpr,
31349
31496
  dataSet: table2.dataSet }) }, p.key)) }),
31350
31497
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "hint", children: T("rowStyleHint") }),
@@ -31617,9 +31764,10 @@ function ReportProps() {
31617
31764
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("i_currency"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TextInput, { value: def.currency, onChange: (v) => set2((d) => {
31618
31765
  d.currency = v.toUpperCase() || void 0;
31619
31766
  }, "currency"), placeholder: "USD" }) }),
31620
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("i_nonFinite"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Select, { value: def.nonFinite || "", options: [{ value: "", label: T("i_nonFiniteSsrs") }, { value: "blank", label: T("i_nonFiniteBlank") }, { value: "error", label: "#Error" }], onChange: (v) => set2((d) => {
31767
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { gridColumn: "1 / -1" }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Field, { label: T("i_nonFinite"), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Select, { value: def.nonFinite || "", options: [{ value: "", label: T("i_nonFiniteSsrs") }, { value: "blank", label: T("i_nonFiniteBlank") }, { value: "error",
31768
+ label: "#Error" }], onChange: (v) => set2((d) => {
31621
31769
  d.nonFinite = v || void 0;
31622
- }, "nonFinite") }) })
31770
+ }, "nonFinite") }) }) })
31623
31771
  ] })
31624
31772
  ] }),
31625
31773
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "cat", children: [
@@ -32290,6 +32438,19 @@ async function loadSample(store) {
32290
32438
  api.setState({ sample: { error: e.message } });
32291
32439
  }
32292
32440
  }
32441
+ function detectedFields(ds, def, sampleRows) {
32442
+ if ((ds?.fields || []).length) return null;
32443
+ let rows = Array.isArray(sampleRows) ? sampleRows : null;
32444
+ if (!rows) {
32445
+ const src = (def?.dataSources || []).find((x) => x.name === ds?.source);
32446
+ try {
32447
+ rows = src?.type === "json" && src.data != null ? sourceRows(src.data, ds.path) : null;
32448
+ } catch {
32449
+ rows = null;
32450
+ }
32451
+ }
32452
+ return rows?.length ? detectFields(rows.slice(0, 50), { dates: ds.detectDates !== false }) : null;
32453
+ }
32293
32454
  function DataPanel() {
32294
32455
  const def = useDesigner((s) => s.def);
32295
32456
  const lang2 = useDesigner((s) => s.lang);
@@ -32391,32 +32552,41 @@ function DataPanel() {
32391
32552
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: "btn sm ghost", onClick: () => useDesigner.getState().setUi({ instantVisuals: { dataSet: d.name } }), "data-testid": `instant-${d.name}`, children: T("instantVisuals") }),
32392
32553
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: "btn sm ghost", onClick: () => useDesigner.getState().setUi({ pivotWizard: { dataSet: d.name } }), "data-testid": `pivot-wizard-${d.name}`, children: T("pivotWizard") })
32393
32554
  ] }),
32394
- open.has(d.name) && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("ul", { className: "tree", style: { paddingLeft: 18 }, children: [
32395
- (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__ */ (0, import_jsx_runtime13.jsxs)(
32396
- "li",
32397
- {
32398
- className: `trow field-chip${f.nested ? " nested" : ""}`,
32399
- draggable: true,
32400
- title: "Drag onto the page or a table cell",
32401
- "data-field": f.name,
32402
- onDragStart: (e) => {
32403
- e.dataTransfer.setData(MIME_FIELD, JSON.stringify({ dataSet: d.name, field: f.name, type: f.type }));
32404
- e.dataTransfer.effectAllowed = "copy";
32555
+ open.has(d.name) && (() => {
32556
+ const found = detectedFields(d, def, sample?.dataSets?.[d.name]);
32557
+ const list2 = (d.fields || []).length ? d.fields : found || [];
32558
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("ul", { className: "tree", style: { paddingLeft: 18 }, "data-testid": `fields-${d.name}`, children: [
32559
+ found && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("li", { className: "subtle", "data-testid": `detected-${d.name}`, children: T("c132_detectedHint") }),
32560
+ list2.flatMap((f) => f.type === "object" ? (f.fields || []).map((c) => ({ name: `${f.name}.${c.name}`, type: c.type, nested: true })) : [f]).map((f) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
32561
+ "li",
32562
+ {
32563
+ className: `trow field-chip${f.nested ? " nested" : ""}`,
32564
+ draggable: true,
32565
+ title: "Drag onto the page or a table cell",
32566
+ "data-field": f.name,
32567
+ "data-detected": found ? "" : void 0,
32568
+ onDragStart: (e) => {
32569
+ e.dataTransfer.setData(MIME_FIELD, JSON.stringify({ dataSet: d.name, field: f.name, type: f.type }));
32570
+ e.dataTransfer.effectAllowed = "copy";
32571
+ },
32572
+ children: [
32573
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "nm", children: f.name }),
32574
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "ty", children: [
32575
+ f.type,
32576
+ found ? ` · ${T("c132_detected")}` : ""
32577
+ ] })
32578
+ ]
32405
32579
  },
32406
- children: [
32407
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "nm", children: f.name }),
32408
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "ty", children: f.type })
32409
- ]
32410
- },
32411
- f.name
32412
- )),
32413
- !(d.fields || []).length && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("li", { className: "subtle", children: "No fields. Edit the data set and detect them." })
32414
- ] })
32580
+ f.name
32581
+ )),
32582
+ !list2.length && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("li", { className: "subtle", children: "No fields. Edit the data set and detect them." })
32583
+ ] });
32584
+ })()
32415
32585
  ] }, d.name)),
32416
32586
  !(def.dataSets || []).length && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("li", { className: "subtle", children: "None" })
32417
32587
  ] }),
32418
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "btnrow", style: { marginTop: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { className: "btn sm", onClick: loadSample, disabled: sample?.loading || !!noSourceKey(def), title: noSourceKey(def) ? T(noSourceKey(def)) : void 0, "data-testid": "load-sample", children: sample?.loading ? "Loading…" : "Lo\
32419
- ad sample data" }) }),
32588
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "btnrow", style: { marginTop: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { className: "btn sm", onClick: loadSample, disabled: sample?.loading || !!noSourceKey(def), title: noSourceKey(def) ? T(noSourceKey(def)) : void 0, "data-testid": "load-sample", children: sample?.loading ? "Loading…" : ("Lo"+
32589
+ "ad sample data") }) }),
32420
32590
  noSourceKey(def) && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "hint", role: "status", style: { marginTop: 6 }, "data-testid": "no-source", children: T(noSourceKey(def)) }),
32421
32591
  sample?.error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "err", style: { marginTop: 6 }, children: sample.error })
32422
32592
  ] })
@@ -32550,18 +32720,17 @@ function ParamDialog({ index, onClose }) {
32550
32720
  }
32551
32721
  ) }),
32552
32722
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid2", children: [
32553
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: T("choicesFrom"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Select, { value: p.optionsFrom?.dataSet, options: (def.dataSets || []).map((d) => d.name), allowEmpty: true, onChange: pickChoiceSet, "data-testid": "param-choices-from" }) }),
32554
- p.optionsFrom && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: T("valueField"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(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\
32555
- -value-field", "aria-invalid": !p.optionsFrom.value || void 0 }) }),
32723
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: T("choicesFrom"), hint: T("cascadeHint"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Select, { value: p.optionsFrom?.dataSet, options: (def.dataSets || []).map((d) => d.name), allowEmpty: true, onChange: pickChoiceSet, "data-testid": "param-choices-from" }) }),
32724
+ p.optionsFrom && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: T("valueField"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(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"+
32725
+ "-value-field"), "aria-invalid": !p.optionsFrom.value || void 0 }) }),
32556
32726
  p.optionsFrom && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: T("labelField"), hint: T("labelFieldHint"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(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" }) })
32557
32727
  ] }),
32558
32728
  p.optionsFrom && choicePreview && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "hint", "data-testid": "param-choice-preview", children: T("ux_choicePreview", { n: choicePreview.length, list: choicePreview.slice(0, 5).join(", ") + (choicePreview.length > 5 ? ", …" : "") }) }),
32559
- p.optionsFrom && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "hint", children: T("cascadeHint") }),
32560
32729
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid2", children: [
32561
32730
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: T("editor"), hint: T(`editorHint_${p.editor || "auto"}`), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Select, { value: p.editor, allowEmpty: true, onChange: setEditor, options: EDITORS.map((e) => ({ value: e, label: T(`editor_${e}`) })) }) }),
32562
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: T("panelColumns"), hint: T("panelColumnsHint"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Select, { value: columns, onChange: (v) => setColumns(v || "1"), options: ["1", "2", "3", "4"] }) })
32731
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: T("panelColumns"), hint: T("c132_panelColumnsHint"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Select, { value: columns, onChange: (v) => setColumns(v || "1"), options: ["1", "2", "3", "4"] }) })
32563
32732
  ] }),
32564
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Check, { label: T("liveParams"), checked: live, onChange: setLive }),
32733
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Check, { label: T("c132_liveParams"), checked: live, onChange: setLive }),
32565
32734
  limits && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid3", children: [
32566
32735
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: T("minimum"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TextInput, { value: p.min ?? "", onChange: (v) => setP({ ...p, min: limit(v) }), mono: true, type: p.type === "date" ? "date" : "text" }) }),
32567
32736
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: T("maximum"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TextInput, { value: p.max ?? "", onChange: (v) => setP({ ...p, max: limit(v) }), mono: true, type: p.type === "date" ? "date" : "text" }) }),
@@ -32775,8 +32944,8 @@ function SourceDialog({ index, onClose }) {
32775
32944
  fetched && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
32776
32945
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { display: "grid", gridTemplateColumns: s.type === "soap" || s.type === "odata" ? "1fr" : "110px 1fr", gap: 8 }, children: [
32777
32946
  s.type !== "soap" && s.type !== "odata" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: "Method", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Select, { value: s.method, options: ["GET", "POST"], onChange: (v) => setS({ ...s, method: v }) }) }),
32778
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: "URL", hint: s.type === "odata" ? T("odServiceHint") : s.type === "xml" ? T("srcXmlUrlHint") : "Use {Parameters.x} for values. A relative URL calls this app.", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TextInput, { value: s.url, onChange: (v) => setS({ ...s, url: v }), mono: true, placeholder: "/api/... or http\
32779
- s://..." }) })
32947
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: "URL", hint: s.type === "odata" ? T("odServiceHint") : s.type === "xml" ? T("srcXmlUrlHint") : "Use {Parameters.x} for values. A relative URL calls this app.", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TextInput, { value: s.url, onChange: (v) => setS({ ...s, url: v }), mono: true, placeholder: ("/api/... or http"+
32948
+ "s://...") }) })
32780
32949
  ] }),
32781
32950
  s.type === "soap" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "1fr 140px", gap: 8 }, children: [
32782
32951
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: T("srcSoapAction"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TextInput, { value: s.soapAction || "", onChange: (v) => setS({ ...s, soapAction: v }), mono: true, placeholder: "http://tempuri.org/GetOrders" }) }),
@@ -32810,8 +32979,8 @@ s://..." }) })
32810
32979
  label: "Stored procedure" }], onChange: (v) => setS({ ...s, procedure: v === "proc" ? s.procedure ?? procs[0] ?? "" : void 0 }) }) }),
32811
32980
  s.procedure != null ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
32812
32981
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: "Stored procedure", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Select, { value: s.procedure, allowEmpty: true, options: procs.map((p) => ({ value: p, label: p })), onChange: (v) => setS({ ...s, procedure: v }) }) }),
32813
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: "Arguments", hint: "One per line: procedure argument = report parameter (bound, never pasted into SQL). The first result set is the data.", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("textarea", { className: "textarea", rows: 3, value: s.argsText ?? "", onChange: (e) => setS({ ...s, argsText: e.target.value }), placeholder: "\
32814
- region = region\nyear = year", style: { fontFamily: "var(--mono)" } }) })
32982
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Field, { label: "Arguments", hint: "One per line: procedure argument = report parameter (bound, never pasted into SQL). The first result set is the data.", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("textarea", { className: "textarea", rows: 3, value: s.argsText ?? "", onChange: (e) => setS({ ...s, argsText: e.target.value }), placeholder: (""+
32983
+ "region = region\nyear = year"), style: { fontFamily: "var(--mono)" } }) })
32815
32984
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
32816
32985
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "seg", role: "group", "aria-label": T("qb_mode"), children: [
32817
32986
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", "aria-pressed": !!s.builder, onClick: () => {
@@ -32826,8 +32995,8 @@ region = region\nyear = year", style: { fontFamily: "var(--mono)" } }) })
32826
32995
  s.builder ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SqlBuilder, { s, setS, T, kind: sqlKind, onManual: () => {
32827
32996
  const { builder: _b, ...rest } = s;
32828
32997
  setS({ ...rest, query: s.builder ? buildSql(s.builder, sqlKind) : s.query });
32829
- } }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(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__ */ (0, import_jsx_runtime13.jsx)("textarea", { className: "textarea", rows: 6, value: s.query || "", onChange: (e) => setS({ ...s, query: e.target.value }), placeholder: "\
32830
- select region, month, sum(amount) as amount from sales where year = @year group by region, month", style: { fontFamily: "var(--mono)" } }) })
32998
+ } }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(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__ */ (0, import_jsx_runtime13.jsx)("textarea", { className: "textarea", rows: 6, value: s.query || "", onChange: (e) => setS({ ...s, query: e.target.value }), placeholder: (""+
32999
+ "select region, month, sum(amount) as amount from sales where year = @year group by region, month"), style: { fontFamily: "var(--mono)" } }) })
32831
33000
  ] })
32832
33001
  ] }),
32833
33002
  s.type === "csv" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid2", children: [
@@ -33261,19 +33430,25 @@ function Outline() {
33261
33430
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("li", { role: "none", children: [
33262
33431
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: `trow outline-row${chosen.has(it.id) ? " sel" : ""}${mark}`, style: { paddingInlineStart: depth * 14 }, "data-outline": it.name, "data-outline-id": it.id, ...dragProps(it, i2, parent, section), children: [
33263
33432
  !readOnly2 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "grip", "aria-hidden": "true", children: "⠿" }),
33264
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", "data-opt": "", className: "linklike nm", onClick: (e) => pick(e, it.id), onKeyDown: (e) => onKey(e, it, list2, i2, parent), "aria-pressed": chosen.has(it.id), "aria-describedby": readOnly2 ? "outline-nav" : "outline-nav outline-keys", ...roving(it.id), children: it.name }),
33265
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ty", children: T(`item_${it.type}`) === `item_${it.type}` ? ITEMS[it.type]?.label || it.type : T(`item_${it.type}`) }),
33266
- !readOnly2 && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "act", style: { display: "inline-flex", gap: 2 }, children: [
33267
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "btn sm ghost icon", tabIndex: -1, disabled: i2 === 0, onClick: () => reorderItem(it.id, -1), title: T("outlineBackward"), "aria-label": `${T("outlineBackward")}: ${it.name}`, children: "↑" }),
33268
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "btn sm ghost icon", tabIndex: -1, disabled: i2 === list2.length - 1, onClick: () => reorderItem(it.id, 1), title: T("outlineForward"), "aria-label": `${T("outlineForward")}: ${it.name}`, children: "↓" }),
33269
- parent && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "btn sm ghost icon", tabIndex: -1, onClick: () => moveOutOfParent(it.id), title: T("outlineMoveOut", { name: parent.name }), "aria-label": `${T("outlineMoveOut", { name: parent.name })}: ${it.name}`, children: "⇱" })
33433
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", "data-opt": "", className: "linklike nm", onClick: (e) => pick(e, it.id), onKeyDown: (e) => onKey(e, it, list2, i2, parent), "aria-pressed": chosen.has(it.id), "aria-describedby": readOnly2 ? "outline-nav" : "outline-nav outline-keys", title: it.name, ...roving(it.id), children: it.name }),
33434
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "outline-meta", children: [
33435
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "ty", children: T(`item_${it.type}`) === `item_${it.type}` ? ITEMS[it.type]?.label || it.type : T(`item_${it.type}`) }),
33436
+ !readOnly2 && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "act", style: { display: "inline-flex", gap: 2 }, children: [
33437
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "btn sm ghost icon", tabIndex: -1, disabled: i2 === 0, onClick: () => reorderItem(it.id, -1), title: T("outlineBackward"), "aria-label": `${T("outlineBackward")}: ${it.name}`, children: "↑" }),
33438
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "btn sm ghost icon", tabIndex: -1, disabled: i2 === list2.length - 1, onClick: () => reorderItem(it.id, 1), title: T("outlineForward"), "aria-label": `${T("outlineForward")}: ${it.name}`, children: "↓" }),
33439
+ parent && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "btn sm ghost icon", tabIndex: -1, onClick: () => moveOutOfParent(it.id), title: T("outlineMoveOut", { name: parent.name }), "aria-label": `${T("outlineMoveOut", { name: parent.name })}: ${it.name}`, children: "⇱" })
33440
+ ] })
33270
33441
  ] })
33271
33442
  ] }),
33272
33443
  NESTING.has(it.type) && (it.items || []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("ul", { className: "tree", role: "none", children: rows(it.items, it, depth + 1, section) })
33273
33444
  ] }, it.id);
33274
33445
  });
33275
33446
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "pane", "data-testid": "outline", children: [
33276
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h4", { children: T("outline") }),
33447
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h4", { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { children: [
33448
+ T("outline"),
33449
+ " ",
33450
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(InfoTip, { text: readOnly2 ? T("outlineHint") : `${T("outlineHint")} ${T("outlineKeys")}` })
33451
+ ] }) }),
33277
33452
  /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "pane-body", ref: body, children: [
33278
33453
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { role: "group", "aria-label": T("outline"), onKeyDown: nav2, children: sectionList(def).map(({ key: key2, label }) => {
33279
33454
  const items = secOf(def, key2)?.items || [];
@@ -33284,8 +33459,7 @@ function Outline() {
33284
33459
  ] }, key2);
33285
33460
  }) }),
33286
33461
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "sr-only", id: "outline-nav", children: T("b9_outlineKeys") }),
33287
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "hint", children: T("outlineHint") }),
33288
- !readOnly2 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "hint", id: "outline-keys", children: T("outlineKeys") }),
33462
+ !readOnly2 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "sr-only", id: "outline-keys", children: T("outlineKeys") }),
33289
33463
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "sr-only", role: "status", "aria-live": "polite", children: said })
33290
33464
  ] })
33291
33465
  ] });
@@ -33592,8 +33766,8 @@ function ChartWizard() {
33592
33766
  c.chartType === "gantt" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "grid2", children: [
33593
33767
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Field, { label: tr("start"), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Select, { value: c.start, allowEmpty: true, options: fields.map((f) => ({ value: f.name, label: `${f.name} · ${f.type}` })), onChange: (v) => set2({ start: v || "" }), "data-testid": "cw-gantt-start" }) }),
33594
33768
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Field, { label: tr("end"), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Select, { value: c.end, allowEmpty: true, options: fields.map((f) => ({ value: f.name, label: `${f.name} · ${f.type}` })), onChange: (v) => set2({ end: v || "" }), "data-testid": "cw-gantt-end" }) })
33595
- ] }) : RAW.has(c.chartType) ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Field, { label: tr("rowValue"), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Select, { value: c.value, allowEmpty: true, options: (numFields.length ? numFields : fields).map((f) => f.name), onChange: (v) => set2({ value: v || "" }) }) }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "\
33596
- grid2", children: [
33769
+ ] }) : RAW.has(c.chartType) ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Field, { label: tr("rowValue"), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Select, { value: c.value, allowEmpty: true, options: (numFields.length ? numFields : fields).map((f) => f.name), onChange: (v) => set2({ value: v || "" }) }) }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: (""+
33770
+ "grid2"), children: [
33597
33771
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Field, { label: tr("value"), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Select, { value: c.agg, options: AGGS.map((a) => ({ value: a.value, label: tr(`agg_${a.value}`) })), onChange: (v) => set2({ agg: v }) }) }),
33598
33772
  c.agg !== "Count" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Field, { label: tr("ofField"), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Select, { value: c.value, allowEmpty: true, options: (numFields.length ? numFields : fields).map((f) => f.name), onChange: (v) => set2({ value: v || "" }) }) })
33599
33773
  ] }),
@@ -33626,8 +33800,8 @@ grid2", children: [
33626
33800
  onClick: () => set2({ chartType: type }),
33627
33801
  "data-chart-type": type,
33628
33802
  children: [
33629
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "cw-thumb", children: !sample?.dataSets ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "hint", children: loading ? tr("calling") : tr("noData") }) : PER_ROW.has(type) && fields.find((f) => f.name === c.category)?.type !== "number" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "\
33630
- hint", children: tr("pickNumber") }) : th?.error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "err", children: th.error }) : th ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SvgHtml, { html: th.html }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "hint", children: tr("drawing") }) }),
33803
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "cw-thumb", children: !sample?.dataSets ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "hint", children: loading ? tr("calling") : tr("noData") }) : PER_ROW.has(type) && fields.find((f) => f.name === c.category)?.type !== "number" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: (""+
33804
+ "hint"), children: tr("pickNumber") }) : th?.error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "err", children: th.error }) : th ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SvgHtml, { html: th.html }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "hint", children: tr("drawing") }) }),
33631
33805
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "cw-name", children: [
33632
33806
  tr(`t_${type}`),
33633
33807
  good.includes(type) && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("em", { children: tr("suggested") })
@@ -33641,8 +33815,8 @@ hint", children: tr("pickNumber") }) : th?.error ? /* @__PURE__ */ (0, import_js
33641
33815
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "cw-preview", children: [
33642
33816
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "cw-big", children: [
33643
33817
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h5", { children: tr("preview", { type: tr(`t_${c.chartType}`) }) }),
33644
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "cw-paper", children: big?.error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "err", children: big.error }) : big ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SvgHtml, { as: "div", html: big.html }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "hint", children: tr("dra\
33645
- wing") }) })
33818
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "cw-paper", children: big?.error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "err", children: big.error }) : big ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SvgHtml, { as: "div", html: big.html }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "hint", children: tr(("dra"+
33819
+ "wing")) }) })
33646
33820
  ] }),
33647
33821
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "cw-data", children: [
33648
33822
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h5", { children: tr(ds?.filters?.length ? "apiDataFiltered" : "apiData", { n: rows.length }) }),
@@ -34108,8 +34282,8 @@ function suggestions(ds, picked, width, rows, currency) {
34108
34282
  const text = fields.filter((f) => f.type !== "number"), nums = fields.filter((f) => f.type === "number");
34109
34283
  const out = [];
34110
34284
  if (text.length && nums.length) {
34111
- 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: "\
34112
- N0", title: `${nums.map((n) => labelOf(n.name)).join(", ")} by ${labelOf(text[0].name)}` } });
34285
+ 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: (""+
34286
+ "N0"), title: `${nums.map((n) => labelOf(n.name)).join(", ")} by ${labelOf(text[0].name)}` } });
34113
34287
  }
34114
34288
  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) }) });
34115
34289
  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 }) });
@@ -34459,6 +34633,7 @@ function StatusBar({ T, zoom, setZoom }) {
34459
34633
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("i", { "aria-hidden": "true" }),
34460
34634
  what
34461
34635
  ] }),
34636
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "hint dstatus-hint", title: T("canvasHint"), children: T("canvasHint") }),
34462
34637
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "dstatus-page", children: page })
34463
34638
  ] });
34464
34639
  }
@@ -34652,8 +34827,8 @@ var SHORTCUTS = [
34652
34827
  ["⌘/Ctrl C / V", "sc_copy"],
34653
34828
  ["⌘/Ctrl D", "sc_duplicate"],
34654
34829
  ["Delete / Backspace", "sc_delete"],
34655
- ["← ↑ → ↓", "sc_nudge"],
34656
- ["⇧ ← ↑ → ↓", "sc_nudge4"],
34830
+ ["← ↑ → ↓", "c132_nudge1"],
34831
+ ["⇧ ← ↑ → ↓", "c132_nudge10"],
34657
34832
  ["⇧ Click", "sc_toggle"],
34658
34833
  ["Drag", "sc_marquee"],
34659
34834
  ["Alt + Drag", "sc_guides"],
@@ -34844,11 +35019,11 @@ function DesignerIn({ id, initial, rev = null, lang: langIn, embed = null, user
34844
35019
  const arrows = { ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, -1], ArrowDown: [0, 1] };
34845
35020
  if (arrows[e.key] && st().sel.kind === "items") {
34846
35021
  e.preventDefault();
34847
- const step = st().cells ? st().cellSize : e.shiftKey ? st().grid * 4 : 1;
35022
+ const step = nudgeStep(st(), e.shiftKey);
34848
35023
  const [dx, dy] = arrows[e.key];
34849
35024
  const s = st();
34850
35025
  s.lastKey = null;
34851
- moveItems(s.sel.ids, dx * step, dy * step);
35026
+ moveItems(s.sel.ids, dx * step, dy * step, { nudge: true });
34852
35027
  }
34853
35028
  };
34854
35029
  const onLeave = (e) => {
@@ -35034,7 +35209,7 @@ function DesignerIn({ id, initial, rev = null, lang: langIn, embed = null, user
35034
35209
  tableWizard && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TableWizard, {}),
35035
35210
  pivotWizard && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PivotWizard, {}),
35036
35211
  instantVisuals && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(InstantVisuals, {}),
35037
- tab === "preview" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("main", { className: "dpreview", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ReportViewer, { definition: def, reportId: id, compact: true, lang: lang2 }) }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
35212
+ tab === "preview" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("main", { className: "dpreview", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ReportViewer, { definition: def, reportId: id, compact: true, lang: lang2, showWarnings: true }) }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
35038
35213
  "div",
35039
35214
  {
35040
35215
  className: "dmain",
@@ -35065,8 +35240,7 @@ function DesignerIn({ id, initial, rev = null, lang: langIn, embed = null, user
35065
35240
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("select", { className: "select", style: { width: 72 }, value: unit, onChange: (e) => st().setUi({ unit: e.target.value }), children: ["pt", "mm", "cm", "in"].map((u) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("option", { children: u }, u)) })
35066
35241
  ] }),
35067
35242
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(AlignBar, { T }),
35068
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(IssuesButton, { T }),
35069
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "hint cbar-hint", children: T("canvasHint") })
35243
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(IssuesButton, { T })
35070
35244
  ] }),
35071
35245
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Canvas, {}),
35072
35246
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StatusBar, { T, zoom, setZoom: (z) => {
@@ -35210,6 +35384,19 @@ button, input, select, textarea { font: inherit; color: inherit; }
35210
35384
  .input.invalid, .textarea.invalid { border-color: var(--danger); background: var(--danger-soft); }
35211
35385
  .err { color: var(--danger); font-size: var(--fs-xs); }
35212
35386
  .hint { color: var(--faint); font-size: var(--fs-xs); }
35387
+ /* ⓘ help (InfoTip): the text opens on hover, focus or click, over the content; Esc closes it */
35388
+ .infotip { position: relative; display: inline-flex; vertical-align: middle; text-transform: none; letter-spacing: normal; font-weight: normal; }
35389
+ .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; }
35390
+ .infotip-btn:hover, .infotip-btn[aria-expanded=true] { color: var(--accent); }
35391
+ .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; }
35392
+ .infotip-text[hidden] { display: none; }
35393
+ .field-tip { position: relative; min-width: 0; }
35394
+ .field-tip > .field > span:first-child { padding-inline-end: 18px; }
35395
+ .field-tip > .infotip { position: absolute; top: 0; inset-inline-end: 0; }
35396
+ /* in a panel heading the text spans the panel (the heading is its containing block: sticky) */
35397
+ .pane > h4 { position: relative; }
35398
+ .pane > h4 .infotip { position: static; }
35399
+ .pane > h4 .infotip-text { top: 100%; inset-inline: 8px; width: auto; max-width: none; z-index: 5; }
35213
35400
  .check { display: flex; align-items: center; gap: 7px; cursor: pointer; }
35214
35401
  .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); }
35215
35402
 
@@ -35410,6 +35597,7 @@ a.cell-name:hover { color: var(--accent); }
35410
35597
  .vparams { width: 240px; padding: 14px; border-inline-end: 1px solid var(--line); background: var(--panel); display: grid; gap: 12px; align-content: start; overflow: auto; }
35411
35598
  .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); }
35412
35599
  .vpages { overflow: auto; padding: 24px 16px 48px; display: flex; flex-direction: column; align-items: center; gap: 18px; min-width: 0; }
35600
+ .vpages:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; } /* E11: keyboard-scrollable; inset, so overflow does not clip it */
35413
35601
  .vpage { background: var(--paper); color: var(--paper-ink); box-shadow: var(--shadow-page); flex: none; content-visibility: auto; contain-intrinsic-size: auto 1100px; }
35414
35602
  .vpage svg { display: block; width: 100%; height: 100%; }
35415
35603
  .vmsg { margin: 40px auto; max-width: 520px; padding: 16px 18px; border-radius: 8px; background: var(--panel); border: 1px solid var(--line); }
@@ -35457,6 +35645,12 @@ a.cell-name:hover { color: var(--accent); }
35457
35645
  .trow:hover .act, .trow:focus-within .act { opacity: 1; }
35458
35646
  .outline-row.sel { background: var(--accent-soft); }
35459
35647
  .outline-row .linklike.nm, .outline-band { text-decoration: none; color: var(--ink); text-align: start; }
35648
+ /* a long name wraps inside the panel's width (no cut-off text); the type and the buttons keep their size */
35649
+ /* (the type and the buttons, together, go under a name too long to share the line) */
35650
+ .outline-row { flex-wrap: wrap; }
35651
+ .outline-row .linklike.nm { flex: 1 1 auto; white-space: normal; overflow-wrap: anywhere; }
35652
+ .outline-meta { display: inline-flex; align-items: center; gap: 6px; flex: none; margin-inline-start: auto; }
35653
+ .outline-meta .btn.icon { width: 22px; }
35460
35654
  .outline-row.sel .linklike.nm, .outline-band.sel { color: var(--accent); }
35461
35655
  .outline-row.sel .ty { color: var(--muted); } /* --faint is 4.38:1 on --accent-soft; --muted passes in both themes */
35462
35656
  .outline-row.sel .act, .outline-row:focus-within .act { opacity: 1; }
@@ -35973,19 +36167,21 @@ a.cell-name:hover { color: var(--accent); }
35973
36167
  .dleft .tool svg { width: 16px; height: 16px; }
35974
36168
  /* canvas: the page centred on the desk, rulers along the top and beside each band */
35975
36169
  .dcenter { grid-template-rows: auto minmax(0, 1fr) auto; background: var(--desk); }
35976
- .cbar { gap: 8px 16px; padding: 6px 16px; min-height: 40px; background: var(--panel); }
36170
+ /* one row of a fixed height: the align buttons that come with a selection never push the canvas down (c132) */
36171
+ .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); }
36172
+ .cbar > * { flex: none; white-space: nowrap; }
35977
36173
  .cbar .select { height: 28px; }
35978
- .cbar-hint { margin-inline-start: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 1 1 120px; text-align: end; }
35979
36174
  .cscroll { padding: 24px 40px 80px 56px; }
35980
36175
  .paper { border-radius: 2px; }
35981
36176
  .ruler.v { position: absolute; left: -44px; top: 0; pointer-events: none; overflow: visible; }
35982
- .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); }
36177
+ .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); }
35983
36178
  .dstatus-zoom { display: inline-flex; align-items: center; gap: 2px; }
35984
36179
  .dstatus-zoom .select { height: 26px; width: 92px; border-color: var(--line); font-size: var(--fs-xs); }
35985
36180
  .dstatus-zoom .btn.icon { width: 26px; height: 26px; }
35986
36181
  .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); }
35987
36182
  .dstatus-sel i { flex: none; width: 8px; height: 8px; border-radius: 2px; background: var(--accent); }
35988
- .dstatus-page { margin-inline-start: auto; white-space: nowrap; font-variant-numeric: tabular-nums; }
36183
+ .dstatus-hint { flex: 1 1 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; text-align: end; }
36184
+ .dstatus-page { white-space: nowrap; font-variant-numeric: tabular-nums; }
35989
36185
  /* inspector: roomier sections */
35990
36186
  .dright .insp-head { position: sticky; top: 0; z-index: 3; background: var(--panel); padding: 12px 16px; }
35991
36187
  .dright .cat { padding: 8px 16px 16px; gap: 8px; }
@@ -36020,7 +36216,7 @@ input[type=checkbox], input[type=radio] { width: 16px; height: 16px; accent-colo
36020
36216
 
36021
36217
  .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}
36022
36218
  ` : "";
36023
- var BLANK = { $schema: "pagewright/report@1", name: "Untitled report", page: { size: "A4", margins: [36, 36, 36, 36] }, dataSources: [], dataSets: [], sections: { body: { items: [] } } };
36219
+ var BLANK = { $schema: "reportwright/report@1", name: "Untitled report", page: { size: "A4", margins: [36, 36, 36, 36] }, dataSources: [], dataSets: [], sections: { body: { items: [] } } };
36024
36220
  function mountDesigner(target, opts = {}) {
36025
36221
  const el = typeof target === "string" ? document.querySelector(target) : target;
36026
36222
  if (!el) throw new Error(`mountDesigner: no element for ${target}`);