@nodegx/mcp 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/dist/backend/cli.js +102959 -0
  2. package/dist/cloud-bundle.cjs +34595 -1691
  3. package/dist/kit-extract.cjs +506 -319
  4. package/dist/kit-extract.inputs.json +2 -0
  5. package/dist/node-catalog.json +502 -59
  6. package/dist/noodl-mcp.cjs +52739 -16423
  7. package/dist/package.json +6 -0
  8. package/dist/preset-fonts/dm-sans/OFL.txt +93 -0
  9. package/dist/preset-fonts/dm-sans/dm-sans-latin-ext-wght-normal.woff2 +0 -0
  10. package/dist/preset-fonts/dm-sans/dm-sans-latin-wght-normal.woff2 +0 -0
  11. package/dist/preset-fonts/dm-sans/manifest.json +9 -0
  12. package/dist/preset-fonts/dm-sans/styles.css +25 -0
  13. package/dist/preset-fonts/nunito/OFL.txt +93 -0
  14. package/dist/preset-fonts/nunito/manifest.json +9 -0
  15. package/dist/preset-fonts/nunito/nunito-latin-ext-wght-normal.woff2 +0 -0
  16. package/dist/preset-fonts/nunito/nunito-latin-wght-normal.woff2 +0 -0
  17. package/dist/preset-fonts/nunito/styles.css +25 -0
  18. package/dist/preset-fonts/source-sans-3/OFL.txt +93 -0
  19. package/dist/preset-fonts/source-sans-3/manifest.json +9 -0
  20. package/dist/preset-fonts/source-sans-3/source-sans-3-latin-ext-wght-normal.woff2 +0 -0
  21. package/dist/preset-fonts/source-sans-3/source-sans-3-latin-wght-normal.woff2 +0 -0
  22. package/dist/preset-fonts/source-sans-3/styles.css +25 -0
  23. package/dist/render-harness/data/node-catalog-enriched.json +93883 -0
  24. package/dist/render-harness/data/node-catalog.json +65289 -0
  25. package/dist/render-harness/data/tokens.ts +674 -0
  26. package/dist/render-harness/drive-steps.js +2924 -0
  27. package/dist/render-harness/measure-from-disk.js +2476 -0
  28. package/dist/render-harness/node_modules/ws/LICENSE +20 -0
  29. package/dist/render-harness/node_modules/ws/README.md +548 -0
  30. package/dist/render-harness/node_modules/ws/browser.js +8 -0
  31. package/dist/render-harness/node_modules/ws/index.js +22 -0
  32. package/dist/render-harness/node_modules/ws/lib/buffer-util.js +131 -0
  33. package/dist/render-harness/node_modules/ws/lib/constants.js +19 -0
  34. package/dist/render-harness/node_modules/ws/lib/event-target.js +292 -0
  35. package/dist/render-harness/node_modules/ws/lib/extension.js +203 -0
  36. package/dist/render-harness/node_modules/ws/lib/limiter.js +55 -0
  37. package/dist/render-harness/node_modules/ws/lib/permessage-deflate.js +528 -0
  38. package/dist/render-harness/node_modules/ws/lib/receiver.js +743 -0
  39. package/dist/render-harness/node_modules/ws/lib/sender.js +607 -0
  40. package/dist/render-harness/node_modules/ws/lib/stream.js +161 -0
  41. package/dist/render-harness/node_modules/ws/lib/subprotocol.js +62 -0
  42. package/dist/render-harness/node_modules/ws/lib/validation.js +152 -0
  43. package/dist/render-harness/node_modules/ws/lib/websocket-server.js +562 -0
  44. package/dist/render-harness/node_modules/ws/lib/websocket.js +1407 -0
  45. package/dist/render-harness/node_modules/ws/package.json +74 -0
  46. package/dist/render-harness/node_modules/ws/wrapper.mjs +21 -0
  47. package/dist/render-harness/render-from-disk.js +7306 -0
  48. package/dist/src/external/viewer/global.d.ts.keep +718 -0
  49. package/dist/src/external/viewer/index.html +126 -0
  50. package/dist/src/external/viewer/load_terminator.js +1 -0
  51. package/dist/src/external/viewer/ndl_assets/OpenSans-Bold.ttf +0 -0
  52. package/dist/src/external/viewer/ndl_assets/OpenSans-Regular.ttf +0 -0
  53. package/dist/src/external/viewer/ndl_assets/home-icon.svg +3 -0
  54. package/dist/src/external/viewer/ndl_assets/make-home-instructions@2x.png +0 -0
  55. package/dist/src/external/viewer/ndl_assets/noodl-logo-black.svg +3 -0
  56. package/dist/src/external/viewer/noodl-app.png +0 -0
  57. package/dist/src/external/viewer/noodl.viewer.js +2 -0
  58. package/dist/src/external/viewer/noodl.viewer.js.LICENSE.txt +20 -0
  59. package/dist/src/external/viewer/react-dom.production.min.js +267 -0
  60. package/dist/src/external/viewer/react.production.min.js +31 -0
  61. package/dist/src/external/viewer/react19/VERSION +2 -0
  62. package/dist/src/external/viewer/react19/react-dom.production.min.js +51 -0
  63. package/dist/src/external/viewer/react19/react.production.min.js +21 -0
  64. package/dist/starter-assets/noodl_modules/inter/Inter-Bold.woff2 +0 -0
  65. package/dist/starter-assets/noodl_modules/inter/Inter-Medium.woff2 +0 -0
  66. package/dist/starter-assets/noodl_modules/inter/Inter-Regular.woff2 +0 -0
  67. package/dist/starter-assets/noodl_modules/inter/Inter-SemiBold.woff2 +0 -0
  68. package/dist/starter-assets/noodl_modules/inter/LICENSE.txt +93 -0
  69. package/dist/starter-assets/noodl_modules/inter/manifest.json +7 -0
  70. package/dist/starter-assets/noodl_modules/inter/styles.css +49 -0
  71. package/dist/starter-assets/noodl_modules/lucide-icons/lucide.woff2 +0 -0
  72. package/dist/starter-assets/noodl_modules/lucide-icons/manifest.json +229 -0
  73. package/dist/starter-assets/noodl_modules/lucide-icons/styles.css +2007 -0
  74. package/dist/starter-assets/noodl_modules/starter-imagery/LICENCES.json +445 -0
  75. package/dist/starter-assets/noodl_modules/starter-imagery/animal-cat.webp +0 -0
  76. package/dist/starter-assets/noodl_modules/starter-imagery/animal-dog.webp +0 -0
  77. package/dist/starter-assets/noodl_modules/starter-imagery/animal-horse.webp +0 -0
  78. package/dist/starter-assets/noodl_modules/starter-imagery/animal-sheep.webp +0 -0
  79. package/dist/starter-assets/noodl_modules/starter-imagery/avatar-1.webp +0 -0
  80. package/dist/starter-assets/noodl_modules/starter-imagery/avatar-2.webp +0 -0
  81. package/dist/starter-assets/noodl_modules/starter-imagery/avatar-3.webp +0 -0
  82. package/dist/starter-assets/noodl_modules/starter-imagery/avatar-4.webp +0 -0
  83. package/dist/starter-assets/noodl_modules/starter-imagery/avatar-5.webp +0 -0
  84. package/dist/starter-assets/noodl_modules/starter-imagery/avatar-6.webp +0 -0
  85. package/dist/starter-assets/noodl_modules/starter-imagery/food-bakery.webp +0 -0
  86. package/dist/starter-assets/noodl_modules/starter-imagery/food-board.webp +0 -0
  87. package/dist/starter-assets/noodl_modules/starter-imagery/food-bread.webp +0 -0
  88. package/dist/starter-assets/noodl_modules/starter-imagery/food-carrots.webp +0 -0
  89. package/dist/starter-assets/noodl_modules/starter-imagery/food-grocer.webp +0 -0
  90. package/dist/starter-assets/noodl_modules/starter-imagery/food-market.webp +0 -0
  91. package/dist/starter-assets/noodl_modules/starter-imagery/food-plate.webp +0 -0
  92. package/dist/starter-assets/noodl_modules/starter-imagery/ground-aurora.svg +28 -0
  93. package/dist/starter-assets/noodl_modules/starter-imagery/ground-canyon.webp +0 -0
  94. package/dist/starter-assets/noodl_modules/starter-imagery/ground-city-dusk.webp +0 -0
  95. package/dist/starter-assets/noodl_modules/starter-imagery/ground-coast.webp +0 -0
  96. package/dist/starter-assets/noodl_modules/starter-imagery/ground-dune.webp +0 -0
  97. package/dist/starter-assets/noodl_modules/starter-imagery/ground-forest-fog.webp +0 -0
  98. package/dist/starter-assets/noodl_modules/starter-imagery/ground-red-rock.webp +0 -0
  99. package/dist/starter-assets/noodl_modules/starter-imagery/ground-ridge.svg +28 -0
  100. package/dist/starter-assets/noodl_modules/starter-imagery/ground-shore.webp +0 -0
  101. package/dist/starter-assets/noodl_modules/starter-imagery/ground-skyline.webp +0 -0
  102. package/dist/starter-assets/noodl_modules/starter-imagery/manifest.json +4 -0
  103. package/dist/starter-assets/noodl_modules/starter-imagery/people-cafe.webp +0 -0
  104. package/dist/starter-assets/noodl_modules/starter-imagery/people-coffee-shop.webp +0 -0
  105. package/dist/starter-assets/noodl_modules/starter-imagery/people-desk.webp +0 -0
  106. package/dist/starter-assets/noodl_modules/starter-imagery/people-market.webp +0 -0
  107. package/dist/starter-assets/noodl_modules/starter-imagery/people-meeting.webp +0 -0
  108. package/dist/starter-assets/noodl_modules/starter-imagery/portrait.svg +11 -0
  109. package/dist/starter-assets/noodl_modules/starter-imagery/texture-brick.webp +0 -0
  110. package/dist/starter-assets/noodl_modules/starter-imagery/texture-coffee.webp +0 -0
  111. package/dist/starter-assets/noodl_modules/starter-imagery/texture-earth.webp +0 -0
  112. package/dist/starter-assets/noodl_modules/starter-imagery/texture-pebbles.webp +0 -0
  113. package/dist/starter-assets/noodl_modules/starter-imagery/texture-snow.webp +0 -0
  114. package/dist/starter-assets/noodl_modules/starter-imagery/texture-soil.webp +0 -0
  115. package/dist/starter-assets/noodl_modules/starter-imagery/tile-1.svg +17 -0
  116. package/dist/starter-assets/noodl_modules/starter-imagery/tile-2.svg +17 -0
  117. package/dist/starter-assets/noodl_modules/starter-imagery/tile-3.svg +17 -0
  118. package/dist/starter-assets/noodl_modules/starter-imagery/work-baker.webp +0 -0
  119. package/dist/starter-assets/noodl_modules/starter-imagery/work-carpenter.webp +0 -0
  120. package/dist/starter-assets/noodl_modules/starter-imagery/work-chef.webp +0 -0
  121. package/dist/starter-assets/noodl_modules/starter-imagery/work-hands-clay.webp +0 -0
  122. package/dist/starter-assets/noodl_modules/starter-imagery/work-leather-bench.webp +0 -0
  123. package/dist/starter-assets/noodl_modules/starter-imagery/work-machine-shop.webp +0 -0
  124. package/dist/starter-assets/noodl_modules/starter-imagery/work-potter.webp +0 -0
  125. package/dist/starter-assets/noodl_modules/starter-imagery/work-welder.webp +0 -0
  126. package/package.json +9 -2
@@ -13726,10 +13726,98 @@ var require_editorconnection = __commonJS({
13726
13726
  }
13727
13727
  });
13728
13728
 
13729
+ // ../nodegx-project-contract/typecasts.ts
13730
+ var TYPECASTS;
13731
+ var init_typecasts = __esm({
13732
+ "../nodegx-project-contract/typecasts.ts"() {
13733
+ "use strict";
13734
+ TYPECASTS = [
13735
+ {
13736
+ from: "string",
13737
+ to: ["number", "boolean", "image", "color", "enum", "textStyle", "dimension", "array", "object"]
13738
+ },
13739
+ {
13740
+ from: "boolean",
13741
+ to: ["number", "string", "signal"]
13742
+ },
13743
+ {
13744
+ from: "number",
13745
+ to: ["boolean", "string", "dimension"]
13746
+ },
13747
+ {
13748
+ from: "date",
13749
+ to: ["string"]
13750
+ },
13751
+ {
13752
+ from: "signal",
13753
+ to: ["boolean", "number"]
13754
+ },
13755
+ {
13756
+ from: "image",
13757
+ to: []
13758
+ },
13759
+ {
13760
+ from: "cloudfile",
13761
+ to: ["string", "image"]
13762
+ },
13763
+ {
13764
+ // The resolved color string (context.styles.resolveColor already
13765
+ // produces it), so a Color variable can feed anything that takes text.
13766
+ from: "color",
13767
+ to: ["string"]
13768
+ },
13769
+ {
13770
+ // P88 GAM-023 ruling (Richard, 2026-09-17): an enum is a string. An enum value is
13771
+ // already the option's string, so a dropdown's value wired into a text port (or a
13772
+ // component output typed string) arrives as it is. Only `string`: an enum into
13773
+ // `number` still has nothing to convert it.
13774
+ from: "enum",
13775
+ to: ["string"]
13776
+ },
13777
+ {
13778
+ // PORT-TYPE-CONTRACT.md: declaring `object` must not strand the port.
13779
+ // The string form is JSON — the conversion lives in
13780
+ // Node.setInputValue, which mirrors the existing string -> object
13781
+ // parse on the way out.
13782
+ from: "object",
13783
+ to: ["string"]
13784
+ },
13785
+ {
13786
+ from: "domelement",
13787
+ to: []
13788
+ },
13789
+ {
13790
+ from: "reference",
13791
+ to: []
13792
+ },
13793
+ {
13794
+ from: "font",
13795
+ to: []
13796
+ },
13797
+ {
13798
+ from: "textStyle",
13799
+ to: ["string"]
13800
+ },
13801
+ {
13802
+ // Collection is deprecated but supported via typecasts
13803
+ from: "collection",
13804
+ to: ["array"]
13805
+ },
13806
+ {
13807
+ // R21 (2026-10-11): `optionslist` — a Dropdown's Items has been an `optionslist` since 2026-09-05, and a list
13808
+ // wired into it is what it holds (the Dropdown reads it as its options).
13809
+ from: "array",
13810
+ to: ["collection", "string", "optionslist"]
13811
+ }
13812
+ ];
13813
+ }
13814
+ });
13815
+
13729
13816
  // ../noodl-runtime/src/nodelibraryexport.ts
13730
13817
  var require_nodelibraryexport = __commonJS({
13731
13818
  "../noodl-runtime/src/nodelibraryexport.ts"(exports2, module2) {
13732
13819
  "use strict";
13820
+ init_typecasts();
13733
13821
  function formatDynamicPorts(nodeMetadata) {
13734
13822
  const dynamicports = [];
13735
13823
  for (const dp of nodeMetadata.dynamicports) {
@@ -13801,84 +13889,9 @@ var require_nodelibraryexport = __commonJS({
13801
13889
  function generateNodeLibrary2(nodeRegister, options) {
13802
13890
  const isCloud = options?.runtimeType === "cloud";
13803
13891
  const obj = {
13804
- //note: needs to include ALL types
13805
- typecasts: [
13806
- {
13807
- from: "string",
13808
- to: ["number", "boolean", "image", "color", "enum", "textStyle", "dimension", "array", "object"]
13809
- },
13810
- {
13811
- from: "boolean",
13812
- to: ["number", "string", "signal"]
13813
- },
13814
- {
13815
- from: "number",
13816
- to: ["boolean", "string", "dimension"]
13817
- },
13818
- {
13819
- from: "date",
13820
- to: ["string"]
13821
- },
13822
- {
13823
- from: "signal",
13824
- to: ["boolean", "number"]
13825
- },
13826
- {
13827
- from: "image",
13828
- to: []
13829
- },
13830
- {
13831
- from: "cloudfile",
13832
- to: ["string", "image"]
13833
- },
13834
- {
13835
- // The resolved color string (context.styles.resolveColor already
13836
- // produces it), so a Color variable can feed anything that takes text.
13837
- from: "color",
13838
- to: ["string"]
13839
- },
13840
- {
13841
- // P88 GAM-023 ruling (Richard, 2026-09-17): an enum is a string. An enum value is
13842
- // already the option's string, so a dropdown's value wired into a text port (or a
13843
- // component output typed string) arrives as it is. Only `string`: an enum into
13844
- // `number` still has nothing to convert it.
13845
- from: "enum",
13846
- to: ["string"]
13847
- },
13848
- {
13849
- // PORT-TYPE-CONTRACT.md: declaring `object` must not strand the port.
13850
- // The string form is JSON — the conversion lives in
13851
- // Node.setInputValue, which mirrors the existing string -> object
13852
- // parse on the way out.
13853
- from: "object",
13854
- to: ["string"]
13855
- },
13856
- {
13857
- from: "domelement",
13858
- to: []
13859
- },
13860
- {
13861
- from: "reference",
13862
- to: []
13863
- },
13864
- {
13865
- from: "font",
13866
- to: []
13867
- },
13868
- {
13869
- from: "textStyle",
13870
- to: ["string"]
13871
- },
13872
- {
13873
- // Collection is deprecated but supported via typecasts
13874
- from: "collection",
13875
- to: ["array"]
13876
- },
13877
- {
13878
- from: "array",
13879
- to: ["collection", "string"]
13880
- }
13881
- ],
13892
+ // P107 NSP-021 (s88): the one table, `@nodegx/project-contract/typecasts` — the editor's canvas, Ports tab and
13893
+ // validator read the same rows. A copy, so nothing here can change the shared one.
13894
+ typecasts: TYPECASTS.map((cast) => ({ from: cast.from, to: [...cast.to] })),
13882
13895
  dynamicports: [
13883
13896
  {
13884
13897
  type: "conditionalports",
@@ -14012,6 +14025,9 @@ var require_nodelibraryexport = __commonJS({
14012
14025
  if (nodeMetadata.deprecated) {
14013
14026
  nodeObj.deprecated = true;
14014
14027
  }
14028
+ if (typeof nodeMetadata.replacedBy === "string") {
14029
+ nodeObj.replacedBy = nodeMetadata.replacedBy;
14030
+ }
14015
14031
  if (nodeMetadata.haveComponentPorts) {
14016
14032
  nodeObj.haveComponentPorts = true;
14017
14033
  }
@@ -15614,6 +15630,7 @@ var require_nodedefinition = __commonJS({
15614
15630
  name: opts.name,
15615
15631
  displayNodeName: opts.displayNodeName || opts.displayName,
15616
15632
  deprecated: opts.deprecated,
15633
+ replacedBy: opts.replacedBy,
15617
15634
  haveComponentPorts: opts.haveComponentPorts,
15618
15635
  // P77 SBR-008 §9 — ports under this prefix are declared by the author's wires. Carried
15619
15636
  // through to the editor so it stops calling such a wire broken before the runtime has
@@ -17021,6 +17038,7 @@ var require_restnode = __commonJS({
17021
17038
  // would strand the one capability that has no mechanical conversion. The conversion path
17022
17039
  // belongs to LIB-006.
17023
17040
  deprecated: true,
17041
+ replacedBy: "net.noodl.HTTP",
17024
17042
  category: "Data",
17025
17043
  color: "data",
17026
17044
  searchTags: ["http", "request", "fetch"],
@@ -20228,7 +20246,7 @@ var require_simplejavascript = __commonJS({
20228
20246
  function _managePortsForNode(node) {
20229
20247
  function _updatePorts() {
20230
20248
  const ports = [];
20231
- const _outputTypeEnums = inputTypeEnums.concat([
20249
+ const _outputTypeEnums = [{ value: "*", label: "Any" }].concat(inputTypeEnums, [
20232
20250
  {
20233
20251
  value: "signal",
20234
20252
  label: "Signal"
@@ -20247,7 +20265,7 @@ var require_simplejavascript = __commonJS({
20247
20265
  enums: _outputTypeEnums,
20248
20266
  allowEditOnly: true
20249
20267
  },
20250
- default: "string",
20268
+ default: "*",
20251
20269
  parent: "scriptOutputs",
20252
20270
  parentItemId: p.id
20253
20271
  });
@@ -23061,7 +23079,7 @@ function recordFilterBackendType(ctx, fallback) {
23061
23079
  var PARSE_PORT_TYPES, PARSE_SYSTEM_CLASSES;
23062
23080
  var init_record_ports = __esm({
23063
23081
  "../noodl-runtime/src/nodes/std-library/data/record-ports.ts"() {
23064
- init_resolveBackend();
23082
+ init_resolveBackend_pure();
23065
23083
  init_schema_ports();
23066
23084
  PARSE_PORT_TYPES = Object.freeze({
23067
23085
  String: "string",
@@ -25300,6 +25318,7 @@ async function planDelete(ctx, collection, objectId) {
25300
25318
  async function deleteKeepingLinks(ctx, collection, objectId, acl) {
25301
25319
  const plan = await planDelete(ctx, collection, objectId);
25302
25320
  if (plan && plan.blocked.length) throw new StillLinked(collection, objectId, plan.blocked);
25321
+ if (plan && ctx.held) await ctx.held(plan);
25303
25322
  await ctx.delete(collection, objectId, acl);
25304
25323
  if (!plan) return null;
25305
25324
  for (const u of plan.unlinked) await ctx.save(u.collection, u.objectId, { [u.field]: null });
@@ -25403,6 +25422,9 @@ async function dryRunMigration(ctx, plan) {
25403
25422
  }
25404
25423
  const over = Array.from(seen.values()).filter((n) => n > 1).reduce((a, n) => a + n, 0);
25405
25424
  if (over > 0) dry.refusals.push({ says: c.says, rows: over });
25425
+ } else if (c.refuse === "empty") {
25426
+ const empty = (await allRows(ctx, c.collection)).filter((r) => r[c.field] === void 0 || r[c.field] === null).length;
25427
+ if (empty > 0) dry.refusals.push({ says: c.says, rows: empty });
25406
25428
  } else if (c.refuse === "more-than-one") {
25407
25429
  const seen = /* @__PURE__ */ new Map();
25408
25430
  for (const row of await allRows(ctx, c.record)) {
@@ -25425,6 +25447,14 @@ async function dryRunMigration(ctx, plan) {
25425
25447
  }
25426
25448
  }
25427
25449
  for (const s of plan.steps) {
25450
+ if ("schema" in s && s.schema.action === "setSeries") {
25451
+ const put = Object.entries(s.schema.columns).filter(([, series]) => series !== null);
25452
+ if (put.length) {
25453
+ const rows = await allRows(ctx, s.schema.table);
25454
+ for (const [field] of put) dry.moves.push({ says: s.says, rows: rows.filter((r) => isEmpty(r[field])).length });
25455
+ }
25456
+ continue;
25457
+ }
25428
25458
  if (!("move" in s)) continue;
25429
25459
  if ("linkToRecord" in s.move) {
25430
25460
  const m = s.move.linkToRecord;
@@ -25462,6 +25492,14 @@ function applySchema(ctx, body) {
25462
25492
  if (typeof sm.setWhenTargetGoes !== "function") throw new Error("the schema surface cannot say what happens to a link when its record goes");
25463
25493
  sm.setWhenTargetGoes(body.table, body.columns);
25464
25494
  return;
25495
+ case "setSeries":
25496
+ if (typeof sm.setSeries !== "function") throw new Error("the schema surface cannot hand out numbers");
25497
+ sm.setSeries(body.table, body.columns);
25498
+ return;
25499
+ case "setRequired":
25500
+ if (typeof sm.setRequired !== "function") throw new Error("the schema surface cannot make a field required or optional");
25501
+ sm.setRequired(body.table, body.columns);
25502
+ return;
25465
25503
  case "setChecks":
25466
25504
  if (typeof sm.reconcileChecks !== "function") throw new Error("the schema surface has no reconcileChecks");
25467
25505
  sm.reconcileChecks(body.table, body.checks);
@@ -25560,6 +25598,12 @@ function migrationPlanProblems(plan) {
25560
25598
  const r = s.rules;
25561
25599
  if (!isObject(r) || !isWords(r.collection)) out.push(`${at}: the rules name their collection`);
25562
25600
  else if (r.onlyWhile !== null && !isObject(r.onlyWhile)) out.push(`${at}: the rules are { update?, delete? }, or null for none`);
25601
+ for (const key of ["fields", "wasFields"]) {
25602
+ const f = isObject(r) ? r[key] : void 0;
25603
+ if (f === void 0 || f === null) continue;
25604
+ if (!isObject(f) || Object.values(f).some((rule) => !isObject(rule) || rule.read !== "nobody"))
25605
+ out.push(`${at}: the ${key === "fields" ? "" : "earlier "}field rules are { <field>: { "read": "nobody" } }, or null for none`);
25606
+ }
25563
25607
  }
25564
25608
  if ("backup" in s && s.backup !== true) out.push(`${at}: a backup step is { backup: true }`);
25565
25609
  if ("schema" in s) {
@@ -25569,6 +25613,12 @@ function migrationPlanProblems(plan) {
25569
25613
  else if (b.action === "createTable" || b.action === "addColumn") {
25570
25614
  const cols = b.action === "createTable" ? b.columns : [b.column];
25571
25615
  if (Array.isArray(cols)) for (const p of whenTargetGoesProblems(String(b.table), cols.filter(isObject))) out.push(`${at}: ${p}`);
25616
+ } else if (b.action === "setSeries") {
25617
+ if (!isObject(b.columns) || Object.values(b.columns).some((v) => v !== null && (!isObject(v) || !isWords(v.format))))
25618
+ out.push(`${at}: a series change is { columns: { <field>: { format, restart?, gapFree? } or null } }`);
25619
+ } else if (b.action === "setRequired") {
25620
+ if (!isObject(b.columns) || !Object.keys(b.columns).length || Object.values(b.columns).some((v) => typeof v !== "boolean"))
25621
+ out.push(`${at}: a required change is { columns: { <field>: true (required) or false (optional) } }`);
25572
25622
  }
25573
25623
  }
25574
25624
  if ("move" in s) {
@@ -25656,13 +25706,15 @@ var init_migration = __esm({
25656
25706
  "renameColumn",
25657
25707
  "describeTable",
25658
25708
  "setWhenTargetGoes",
25709
+ "setSeries",
25710
+ "setRequired",
25659
25711
  "setChecks",
25660
25712
  "setIndexes",
25661
25713
  "dropColumn",
25662
25714
  "deleteTable"
25663
25715
  ];
25664
25716
  MOVES = ["linkToRecord", "recordToLink", "fieldAcross"];
25665
- REFUSALS = ["more-than-one", "none", "rows", "outside-list", "duplicates"];
25717
+ REFUSALS = ["more-than-one", "none", "rows", "outside-list", "duplicates", "empty"];
25666
25718
  LOSSES = ["values", "rows"];
25667
25719
  isObject = (v) => !!v && typeof v === "object" && !Array.isArray(v);
25668
25720
  isWords = (v) => typeof v === "string" && v.trim() !== "";
@@ -26328,8 +26380,9 @@ var init_ParseWireAdapter = __esm({
26328
26380
  });
26329
26381
  options.success(res);
26330
26382
  },
26331
- error: function() {
26332
- options.error();
26383
+ // P107-S99-AGGWORDS: the server's words, as `query` passes them since HLT-023.
26384
+ error: function(res) {
26385
+ options.error(res && res.error);
26333
26386
  }
26334
26387
  });
26335
26388
  }
@@ -26342,8 +26395,9 @@ var init_ParseWireAdapter = __esm({
26342
26395
  success: function(response) {
26343
26396
  options.success(response.count);
26344
26397
  },
26345
- error: function() {
26346
- options.error();
26398
+ // P107-S99-AGGWORDS: the server's words, as `query` passes them since HLT-023.
26399
+ error: function(res) {
26400
+ options.error(res && res.error);
26347
26401
  }
26348
26402
  });
26349
26403
  }
@@ -26355,8 +26409,9 @@ var init_ParseWireAdapter = __esm({
26355
26409
  success: function(response) {
26356
26410
  options.success(response.results);
26357
26411
  },
26358
- error: function() {
26359
- options.error();
26412
+ // P107-S99-AGGWORDS: the server's words, as `query` passes them since HLT-023.
26413
+ error: function(res) {
26414
+ options.error(res && res.error);
26360
26415
  }
26361
26416
  });
26362
26417
  }
@@ -37490,8 +37545,12 @@ var require_variablenode2 = __commonJS({
37490
37545
  group: "General",
37491
37546
  getter: function() {
37492
37547
  const internal2 = this._internal;
37493
- if (!internal2.name) return;
37494
- return internal2.variablesModel.get(internal2.name);
37548
+ if (internal2.name) return internal2.variablesModel.get(internal2.name);
37549
+ const name2 = this.model?.parameters?.name;
37550
+ if (!name2 || typeof name2 !== "string") return;
37551
+ const value2 = internal2.variablesModel.get(name2);
37552
+ internal2.seeded = { name: name2, value: value2 };
37553
+ return value2;
37495
37554
  }
37496
37555
  }
37497
37556
  },
@@ -37558,9 +37617,11 @@ var require_variablenode2 = __commonJS({
37558
37617
  });
37559
37618
  },
37560
37619
  setVariableName: function(name2) {
37620
+ const seeded = this._internal.seeded;
37621
+ this._internal.seeded = void 0;
37561
37622
  this._internal.name = name2;
37562
37623
  this.flagOutputDirty("name");
37563
- this.flagOutputDirty("value");
37624
+ if (!seeded || seeded.name !== name2 || this._internal.variablesModel.get(name2) !== seeded.value) this.flagOutputDirty("value");
37564
37625
  this.sendSignalOnOutput("fetched");
37565
37626
  },
37566
37627
  _onNodeDeleted: function() {
@@ -39867,6 +39928,11 @@ var require_counter = __commonJS({
39867
39928
  "../noodl-runtime/src/nodes/std-library/counter.ts"(exports2, module2) {
39868
39929
  "use strict";
39869
39930
  init_outcome();
39931
+ var MIN_ABOVE_MAX = "counter/min-above-max";
39932
+ function checkLimits(node) {
39933
+ const { limitsMin: min, limitsMax: max } = node._internal;
39934
+ node.setDiagnostic(MIN_ABOVE_MAX, min > max ? `Min Value ${min} is above Max Value ${max}. With Limits Enabled on, the count gets stuck.` : null);
39935
+ }
39870
39936
  var CounterNode = {
39871
39937
  name: "Counter",
39872
39938
  docs: "https://docs.noodl.net/nodes/math/counter",
@@ -39942,7 +40008,8 @@ var require_counter = __commonJS({
39942
40008
  if (this._internal.startValueSet === false) {
39943
40009
  this._internal.startValueSet = true;
39944
40010
  this._internal.currentValue = this._internal.startValue;
39945
- this.flagOutputDirty("currentCount");
40011
+ if (this._internal.seededCount !== this._internal.currentValue) this.flagOutputDirty("currentCount");
40012
+ this._internal.seededCount = void 0;
39946
40013
  this.sendSignalOnOutput("countChanged");
39947
40014
  }
39948
40015
  }
@@ -39957,6 +40024,7 @@ var require_counter = __commonJS({
39957
40024
  default: 0,
39958
40025
  set: function(value2) {
39959
40026
  this._internal.limitsMin = Number(value2);
40027
+ checkLimits(this);
39960
40028
  }
39961
40029
  },
39962
40030
  limitsMax: {
@@ -39969,6 +40037,7 @@ var require_counter = __commonJS({
39969
40037
  default: 0,
39970
40038
  set: function(value2) {
39971
40039
  this._internal.limitsMax = Number(value2);
40040
+ checkLimits(this);
39972
40041
  }
39973
40042
  },
39974
40043
  limitsEnabled: {
@@ -39991,6 +40060,13 @@ var require_counter = __commonJS({
39991
40060
  type: "number",
39992
40061
  description: "The count as it stands",
39993
40062
  getter: function() {
40063
+ if (this._internal.startValueSet === false) {
40064
+ const start = this.model?.parameters?.startValue;
40065
+ if (start !== void 0 && start !== null && start !== "" && !isNaN(Number(start))) {
40066
+ this._internal.seededCount = Number(start);
40067
+ return Number(start);
40068
+ }
40069
+ }
39994
40070
  return this._internal.currentValue;
39995
40071
  }
39996
40072
  },
@@ -43482,7 +43558,7 @@ function parseXML(text2, options = {}) {
43482
43558
  return {
43483
43559
  error: {
43484
43560
  code: "xml/too-large",
43485
- message: `This XML is ${Math.round(text2.length / 1024)} KB, over the ${Math.round(maxBytes / 1024)} KB limit. Raise Max Bytes on the node if the source really is this big`
43561
+ message: `This XML is ${Math.round(text2.length / 1024)} K characters, over the ${Math.round(maxBytes / 1024)} K limit. Raise Max Characters on the node if the source really is this big`
43486
43562
  }
43487
43563
  };
43488
43564
  }
@@ -43602,10 +43678,10 @@ var require_parsexml = __commonJS({
43602
43678
  },
43603
43679
  maxBytes: {
43604
43680
  type: "number",
43605
- displayName: "Max Bytes",
43681
+ displayName: "Max Characters",
43606
43682
  group: "General",
43607
43683
  default: DEFAULT_MAX_BYTES,
43608
- description: "Refuse a document larger than this, before parsing it. A big document costs many times its own size in memory once it is an object, and a server can always send more than you expected",
43684
+ description: "Refuse a document longer than this many characters (not bytes), before parsing it. A big document costs many times its own size in memory once it is an object, and a server can always send more than you expected",
43609
43685
  set: function(value2) {
43610
43686
  const n = Number(value2);
43611
43687
  this._internal.maxBytes = isFinite(n) && n > 0 ? n : DEFAULT_MAX_BYTES;
@@ -43981,10 +44057,10 @@ var require_parsefeed = __commonJS({
43981
44057
  },
43982
44058
  maxBytes: {
43983
44059
  type: "number",
43984
- displayName: "Max Bytes",
44060
+ displayName: "Max Characters",
43985
44061
  group: "General",
43986
44062
  default: DEFAULT_MAX_BYTES,
43987
- description: "Refuse a document larger than this, before parsing it. Raise it for a source that really does publish its whole archive in one file",
44063
+ description: "Refuse a document longer than this many characters (not bytes), before parsing it. Raise it for a source that really does publish its whole archive in one file",
43988
44064
  set: function(value2) {
43989
44065
  const n = Number(value2);
43990
44066
  this._internal.maxBytes = isFinite(n) && n > 0 ? n : DEFAULT_MAX_BYTES;
@@ -44699,12 +44775,11 @@ function userBackendPickerPorts(ctx) {
44699
44775
  function userPropertyPorts(ctx, options) {
44700
44776
  const ports = [];
44701
44777
  if (!ctx.selectedCollection) return ports;
44702
- const parseWire = isParseWireContext(ctx);
44703
44778
  for (const field of ctx.selectedCollection.fields || []) {
44704
44779
  if (!field || !field.name) continue;
44705
44780
  if (options.ignore.indexOf(field.name) !== -1) continue;
44706
44781
  if (isRelationField(field)) continue;
44707
- if (!parseWire && !shouldShowField(field)) continue;
44782
+ if (!shouldShowField(field)) continue;
44708
44783
  ports.push({
44709
44784
  name: "prop-" + field.name,
44710
44785
  displayName: field.displayName || field.name,
@@ -59482,7 +59557,7 @@ var init_node_shared_port_definitions = __esm({
59482
59557
  var require_react_dom_production = __commonJS({
59483
59558
  "../../../../OpenNoodl/node_modules/react-dom/cjs/react-dom.production.js"(exports2) {
59484
59559
  "use strict";
59485
- var React32 = require_react();
59560
+ var React33 = require_react();
59486
59561
  function formatProdErrorMessage(code) {
59487
59562
  var url = "https://react.dev/errors/" + code;
59488
59563
  if (1 < arguments.length) {
@@ -59522,7 +59597,7 @@ var require_react_dom_production = __commonJS({
59522
59597
  implementation
59523
59598
  };
59524
59599
  }
59525
- var ReactSharedInternals = React32.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
59600
+ var ReactSharedInternals = React33.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
59526
59601
  function getCrossOriginStringAs(as, input2) {
59527
59602
  if ("font" === as) return "";
59528
59603
  if ("string" === typeof input2)
@@ -59676,7 +59751,7 @@ var require_react_dom_development = __commonJS({
59676
59751
  return dispatcher;
59677
59752
  }
59678
59753
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
59679
- var React32 = require_react(), Internals = {
59754
+ var React33 = require_react(), Internals = {
59680
59755
  d: {
59681
59756
  f: noop2,
59682
59757
  r: function() {
@@ -59694,7 +59769,7 @@ var require_react_dom_development = __commonJS({
59694
59769
  },
59695
59770
  p: 0,
59696
59771
  findDOMNode: null
59697
- }, REACT_PORTAL_TYPE = Symbol.for("react.portal"), ReactSharedInternals = React32.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
59772
+ }, REACT_PORTAL_TYPE = Symbol.for("react.portal"), ReactSharedInternals = React33.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
59698
59773
  "function" === typeof Map && null != Map.prototype && "function" === typeof Map.prototype.forEach && "function" === typeof Set && null != Set.prototype && "function" === typeof Set.prototype.clear && "function" === typeof Set.prototype.forEach || console.error(
59699
59774
  "React depends on Map and Set built-in types. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"
59700
59775
  );
@@ -59897,6 +59972,48 @@ var require_react_dom = __commonJS({
59897
59972
  }
59898
59973
  });
59899
59974
 
59975
+ // ../noodl-viewer-react/src/kit-node-boundary.ts
59976
+ function kitNodeFailedMessage(nodeName, error) {
59977
+ const reason = error instanceof Error ? error.message : String(error);
59978
+ return `The kit node "${nodeName}" failed while drawing and shows nothing: ${reason}`;
59979
+ }
59980
+ function nodeFailedMessage(nodeName, error) {
59981
+ const reason = error instanceof Error ? error.message : String(error);
59982
+ return `The node "${nodeName}" failed while drawing and shows nothing; the rest of the page keeps drawing: ${reason}`;
59983
+ }
59984
+ function withNodeBoundary(node, element) {
59985
+ return import_react3.default.createElement(KitNodeBoundary, { node, code: NODE_FAILED, describe: nodeFailedMessage }, element);
59986
+ }
59987
+ var import_react3, KIT_NODE_FAILED, NODE_FAILED, KitNodeBoundary, BOUNDED;
59988
+ var init_kit_node_boundary = __esm({
59989
+ "../noodl-viewer-react/src/kit-node-boundary.ts"() {
59990
+ import_react3 = __toESM(require_react());
59991
+ KIT_NODE_FAILED = "kit-node/render-failed";
59992
+ NODE_FAILED = "node/render-failed";
59993
+ KitNodeBoundary = class extends import_react3.default.Component {
59994
+ constructor() {
59995
+ super(...arguments);
59996
+ this.state = { failed: false };
59997
+ }
59998
+ static getDerivedStateFromError() {
59999
+ return { failed: true };
60000
+ }
60001
+ componentDidCatch(error) {
60002
+ const { node, code = KIT_NODE_FAILED, describe: describe2 = kitNodeFailedMessage } = this.props;
60003
+ const message = describe2(node.name ?? "unknown", error);
60004
+ try {
60005
+ node.raiseRuntimeError && node.raiseRuntimeError(code, message, { error: String(error) });
60006
+ } catch (e) {
60007
+ }
60008
+ }
60009
+ render() {
60010
+ return this.state.failed ? null : this.props.children;
60011
+ }
60012
+ };
60013
+ BOUNDED = Symbol("kit-node-boundary");
60014
+ }
60015
+ });
60016
+
59900
60017
  // ../noodl-viewer-react/src/components/visual/Icon/iconSourceProblem.ts
59901
60018
  function iconSourceProblem(value2, displayName = "This icon input") {
59902
60019
  if (value2 === void 0 || value2 === null) return null;
@@ -60903,6 +61020,7 @@ function createNodeFromReactComponent(def2) {
60903
61020
  displayNodeName: def2.displayNodeName || def2.displayName,
60904
61021
  category: "Visual",
60905
61022
  deprecated: def2.deprecated,
61023
+ replacedBy: def2.replacedBy,
60906
61024
  ssr: def2.ssr,
60907
61025
  allowChildren: def2.allowChildren === void 0 ? true : def2.allowChildren,
60908
61026
  //default to true
@@ -61371,7 +61489,7 @@ function createNodeFromReactComponent(def2) {
61371
61489
  if (!this.wantsToBeMounted) {
61372
61490
  return;
61373
61491
  }
61374
- return import_react3.default.createElement(NoodlReactComponent, {
61492
+ return import_react4.default.createElement(NoodlReactComponent, {
61375
61493
  key: this.reactKey,
61376
61494
  noodlNode: this,
61377
61495
  ref: (ref) => {
@@ -61760,7 +61878,7 @@ function createNodeFromReactComponent(def2) {
61760
61878
  index: 9999,
61761
61879
  type: "boolean",
61762
61880
  group: "General",
61763
- description: "Removes the element from the page entirely when false, unlike Visible which leaves its space behind",
61881
+ description: "Removes the element from the page entirely when false, unlike Visible which leaves its space behind. Wired, it counts as true until the first value arrives, so set it to false here to start hidden (a lock, a private screen)",
61764
61882
  default: true,
61765
61883
  set(value2) {
61766
61884
  value2 = value2 ? true : false;
@@ -61924,12 +62042,13 @@ function createNodeFromReactComponent(def2) {
61924
62042
  function isObject4(item) {
61925
62043
  return item && typeof item === "object" && !Array.isArray(item);
61926
62044
  }
61927
- var import_react3, import_react_dom, ICON_SOURCE_DIAGNOSTIC, DATA_ATTRIBUTE_NAME_PATTERN, DATA_ATTRIBUTE_NAME, DATA_ATTRIBUTES_PARAMETER, DATA_ATTRIBUTES_RULE, SCROLL_ALIGNMENTS, NoodlReactComponent, reactKeyCounter;
62045
+ var import_react4, import_react_dom, ICON_SOURCE_DIAGNOSTIC, DATA_ATTRIBUTE_NAME_PATTERN, DATA_ATTRIBUTE_NAME, DATA_ATTRIBUTES_PARAMETER, DATA_ATTRIBUTES_RULE, SCROLL_ALIGNMENTS, NoodlReactComponent, reactKeyCounter;
61928
62046
  var init_react_component_node = __esm({
61929
62047
  "../noodl-viewer-react/src/react-component-node.ts"() {
61930
62048
  "use strict";
61931
- import_react3 = __toESM(require_react());
62049
+ import_react4 = __toESM(require_react());
61932
62050
  import_react_dom = __toESM(require_react_dom());
62051
+ init_kit_node_boundary();
61933
62052
  init_iconSourceProblem();
61934
62053
  init_dom_boundingbox_oberver();
61935
62054
  init_drag_drop();
@@ -61961,7 +62080,7 @@ var init_react_component_node = __esm({
61961
62080
  }
61962
62081
  };
61963
62082
  SCROLL_ALIGNMENTS = ["nearest", "start", "center", "end"];
61964
- NoodlReactComponent = class extends import_react3.default.Component {
62083
+ NoodlReactComponent = class extends import_react4.default.Component {
61965
62084
  componentDidMount() {
61966
62085
  const node = this.props.noodlNode;
61967
62086
  if (node._pendingScrollIntoView && node.getDOMElement()) {
@@ -62036,7 +62155,7 @@ var init_react_component_node = __esm({
62036
62155
  layout_default.size(finalStyle, props);
62037
62156
  layout_default.align(finalStyle, props);
62038
62157
  }
62039
- return import_react3.default.createElement(noodlNode.reactComponent, props, noodlNode.renderChildren());
62158
+ return withNodeBoundary(noodlNode, import_react4.default.createElement(noodlNode.reactComponent, props, noodlNode.renderChildren()));
62040
62159
  }
62041
62160
  };
62042
62161
  reactKeyCounter = 0;
@@ -62179,11 +62298,11 @@ var init_labelText = __esm({
62179
62298
 
62180
62299
  // ../noodl-viewer-react/src/components/controls/Checkbox/Checkbox.tsx
62181
62300
  function Checkbox(props) {
62182
- const [checked, setChecked] = (0, import_react4.useState)(props.checked);
62183
- (0, import_react4.useEffect)(() => {
62301
+ const [checked, setChecked] = (0, import_react5.useState)(props.checked);
62302
+ (0, import_react5.useEffect)(() => {
62184
62303
  setChecked(!!props.checked);
62185
62304
  }, []);
62186
- (0, import_react4.useEffect)(() => {
62305
+ (0, import_react5.useEffect)(() => {
62187
62306
  setChecked(!!props.checked);
62188
62307
  }, [props.checked, props.checkedWrites]);
62189
62308
  const style2 = { ...props.style };
@@ -62215,7 +62334,7 @@ function Checkbox(props) {
62215
62334
  function _renderIcon() {
62216
62335
  if (!checked) return null;
62217
62336
  if (props.iconSourceType === "image" && props.iconImageSource !== void 0)
62218
- return /* @__PURE__ */ import_react4.default.createElement(
62337
+ return /* @__PURE__ */ import_react5.default.createElement(
62219
62338
  "img",
62220
62339
  {
62221
62340
  alt: "",
@@ -62233,7 +62352,7 @@ function Checkbox(props) {
62233
62352
  color: props.iconColor,
62234
62353
  position: "absolute"
62235
62354
  };
62236
- return /* @__PURE__ */ import_react4.default.createElement(IconGlyph, { source: props.iconIconSource, style: style3 });
62355
+ return /* @__PURE__ */ import_react5.default.createElement(IconGlyph, { source: props.iconIconSource, style: style3 });
62237
62356
  }
62238
62357
  return null;
62239
62358
  }
@@ -62241,7 +62360,7 @@ function Checkbox(props) {
62241
62360
  if (!checked) return null;
62242
62361
  if (props.iconSourceType === "image" && props.iconImageSource !== void 0) return null;
62243
62362
  if (props.iconSourceType === "icon" && props.iconIconSource !== void 0) return null;
62244
- return /* @__PURE__ */ import_react4.default.createElement(
62363
+ return /* @__PURE__ */ import_react5.default.createElement(
62245
62364
  "svg",
62246
62365
  {
62247
62366
  "aria-hidden": "true",
@@ -62258,7 +62377,7 @@ function Checkbox(props) {
62258
62377
  color: props.styles.checkbox?.borderTopColor || props.styles.checkbox?.borderColor || "currentColor"
62259
62378
  }
62260
62379
  },
62261
- /* @__PURE__ */ import_react4.default.createElement(
62380
+ /* @__PURE__ */ import_react5.default.createElement(
62262
62381
  "path",
62263
62382
  {
62264
62383
  d: "M3.5 8.5l3 3 6-6",
@@ -62271,7 +62390,7 @@ function Checkbox(props) {
62271
62390
  )
62272
62391
  );
62273
62392
  }
62274
- const checkbox = /* @__PURE__ */ import_react4.default.createElement(
62393
+ const checkbox = /* @__PURE__ */ import_react5.default.createElement(
62275
62394
  "div",
62276
62395
  {
62277
62396
  ref: props.useLabel ? void 0 : noodlRootRef(props.noodlNode),
@@ -62281,7 +62400,7 @@ function Checkbox(props) {
62281
62400
  "noodl-style-tag": "checkbox"
62282
62401
  },
62283
62402
  props.useIcon ? _renderIcon() || _renderDefaultCheck() : null,
62284
- /* @__PURE__ */ import_react4.default.createElement(
62403
+ /* @__PURE__ */ import_react5.default.createElement(
62285
62404
  "input",
62286
62405
  {
62287
62406
  type: "checkbox",
@@ -62304,7 +62423,7 @@ function Checkbox(props) {
62304
62423
  labelStyle.cursor = "default";
62305
62424
  }
62306
62425
  labelStyle.color = props.noodlNode.context.styles.resolveColor(labelStyle.color);
62307
- return /* @__PURE__ */ import_react4.default.createElement(
62426
+ return /* @__PURE__ */ import_react5.default.createElement(
62308
62427
  "div",
62309
62428
  {
62310
62429
  ref: noodlRootRef(props.noodlNode),
@@ -62313,16 +62432,16 @@ function Checkbox(props) {
62313
62432
  ...utils_default.controlEvents(props)
62314
62433
  },
62315
62434
  checkbox,
62316
- /* @__PURE__ */ import_react4.default.createElement("label", { className: "ndl-controls-pointer", style: labelStyle, htmlFor: props.id, "noodl-style-tag": "label" }, labelText(props.label))
62435
+ /* @__PURE__ */ import_react5.default.createElement("label", { className: "ndl-controls-pointer", style: labelStyle, htmlFor: props.id, "noodl-style-tag": "label" }, labelText(props.label))
62317
62436
  );
62318
62437
  } else {
62319
- return /* @__PURE__ */ import_react4.default.createElement("div", { style: { ...clearedRootStyles(style2), display: "contents" } }, checkbox, null);
62438
+ return /* @__PURE__ */ import_react5.default.createElement("div", { style: { ...clearedRootStyles(style2), display: "contents" } }, checkbox, null);
62320
62439
  }
62321
62440
  }
62322
- var import_react4;
62441
+ var import_react5;
62323
62442
  var init_Checkbox = __esm({
62324
62443
  "../noodl-viewer-react/src/components/controls/Checkbox/Checkbox.tsx"() {
62325
- import_react4 = __toESM(require_react());
62444
+ import_react5 = __toESM(require_react());
62326
62445
  init_layout();
62327
62446
  init_utils2();
62328
62447
  init_noodl_root_ref();
@@ -62569,8 +62688,8 @@ var init_checkbox = __esm({
62569
62688
 
62570
62689
  // ../noodl-viewer-react/src/components/controls/Select/Select.tsx
62571
62690
  function Select(props) {
62572
- const [value2, setValue] = (0, import_react5.useState)(props.value);
62573
- (0, import_react5.useEffect)(() => {
62691
+ const [value2, setValue] = (0, import_react6.useState)(props.value);
62692
+ (0, import_react6.useEffect)(() => {
62574
62693
  setValue(props.value);
62575
62694
  props.valueChanged(props.value);
62576
62695
  }, [props.value, props.items, props.valueWrites]);
@@ -62585,12 +62704,12 @@ function Select(props) {
62585
62704
  const { height, ...otherStyles } = style2;
62586
62705
  function _renderIcon() {
62587
62706
  if (props.iconSourceType === "image" && props.iconImageSource !== void 0)
62588
- return /* @__PURE__ */ import_react5.default.createElement("img", { alt: "", src: props.iconImageSource, style: { width: props.iconSize, height: props.iconSize } });
62707
+ return /* @__PURE__ */ import_react6.default.createElement("img", { alt: "", src: props.iconImageSource, style: { width: props.iconSize, height: props.iconSize } });
62589
62708
  else if (props.iconSourceType === "icon" && props.iconIconSource !== void 0) {
62590
62709
  const style3 = { fontSize: props.iconSize, color: props.iconColor };
62591
62710
  if (props.iconPlacement === "left" || props.iconPlacement === void 0) style3.marginRight = props.iconSpacing;
62592
62711
  else style3.marginLeft = props.iconSpacing;
62593
- return /* @__PURE__ */ import_react5.default.createElement(IconGlyph, { source: props.iconIconSource, style: style3 });
62712
+ return /* @__PURE__ */ import_react6.default.createElement(IconGlyph, { source: props.iconIconSource, style: style3 });
62594
62713
  }
62595
62714
  return null;
62596
62715
  }
@@ -62630,9 +62749,9 @@ function Select(props) {
62630
62749
  }
62631
62750
  let options = [];
62632
62751
  if (props.items) {
62633
- options = props.items.map((i2) => /* @__PURE__ */ import_react5.default.createElement("option", { key: i2.Value, value: i2.Value, disabled: i2.Disabled === "true" || i2.Disabled === true ? true : void 0 }, i2.Label));
62752
+ options = props.items.map((i2) => /* @__PURE__ */ import_react6.default.createElement("option", { key: i2.Value, value: i2.Value, disabled: i2.Disabled === "true" || i2.Disabled === true ? true : void 0 }, i2.Label));
62634
62753
  }
62635
- const chevron = props.showChevron === false ? null : /* @__PURE__ */ import_react5.default.createElement(
62754
+ const chevron = props.showChevron === false ? null : /* @__PURE__ */ import_react6.default.createElement(
62636
62755
  "span",
62637
62756
  {
62638
62757
  style: {
@@ -62643,7 +62762,7 @@ function Select(props) {
62643
62762
  pointerEvents: "none"
62644
62763
  }
62645
62764
  },
62646
- /* @__PURE__ */ import_react5.default.createElement("svg", { width: "10", height: "6", viewBox: "0 0 10 6", fill: "none", focusable: "false", "aria-hidden": "true" }, /* @__PURE__ */ import_react5.default.createElement(
62765
+ /* @__PURE__ */ import_react6.default.createElement("svg", { width: "10", height: "6", viewBox: "0 0 10 6", fill: "none", focusable: "false", "aria-hidden": "true" }, /* @__PURE__ */ import_react6.default.createElement(
62647
62766
  "path",
62648
62767
  {
62649
62768
  d: "M1 1l4 4 4-4",
@@ -62656,11 +62775,11 @@ function Select(props) {
62656
62775
  );
62657
62776
  let label = null;
62658
62777
  if (selectedIndex >= 0 && selectedIndex < props.items.length) {
62659
- label = /* @__PURE__ */ import_react5.default.createElement("span", null, props.items[selectedIndex].Label);
62778
+ label = /* @__PURE__ */ import_react6.default.createElement("span", null, props.items[selectedIndex].Label);
62660
62779
  } else if (props.placeholder) {
62661
- label = /* @__PURE__ */ import_react5.default.createElement("span", { style: { opacity: props.placeholderOpacity } }, labelText(props.placeholder));
62780
+ label = /* @__PURE__ */ import_react6.default.createElement("span", { style: { opacity: props.placeholderOpacity } }, labelText(props.placeholder));
62662
62781
  }
62663
- const inputWrapper = /* @__PURE__ */ import_react5.default.createElement(
62782
+ const inputWrapper = /* @__PURE__ */ import_react6.default.createElement(
62664
62783
  "div",
62665
62784
  {
62666
62785
  ref: props.useLabel ? void 0 : noodlRootRef(props.noodlNode),
@@ -62670,7 +62789,7 @@ function Select(props) {
62670
62789
  "noodl-style-tag": "inputWrapper"
62671
62790
  },
62672
62791
  props.useIcon && props.iconPlacement === "left" ? _renderIcon() : null,
62673
- /* @__PURE__ */ import_react5.default.createElement(
62792
+ /* @__PURE__ */ import_react6.default.createElement(
62674
62793
  "div",
62675
62794
  {
62676
62795
  style: {
@@ -62684,7 +62803,7 @@ function Select(props) {
62684
62803
  ),
62685
62804
  props.useIcon && props.iconPlacement === "right" ? _renderIcon() : null,
62686
62805
  chevron,
62687
- /* @__PURE__ */ import_react5.default.createElement(
62806
+ /* @__PURE__ */ import_react6.default.createElement(
62688
62807
  "select",
62689
62808
  {
62690
62809
  ...inputProps,
@@ -62696,7 +62815,7 @@ function Select(props) {
62696
62815
  props.valueChanged && props.valueChanged(e.target.value);
62697
62816
  }
62698
62817
  },
62699
- /* @__PURE__ */ import_react5.default.createElement("option", { value: "", disabled: true, selected: true, hidden: true }),
62818
+ /* @__PURE__ */ import_react6.default.createElement("option", { value: "", disabled: true, selected: true, hidden: true }),
62700
62819
  options
62701
62820
  )
62702
62821
  );
@@ -62713,7 +62832,7 @@ function Select(props) {
62713
62832
  // P107-C80 / C66 (P109 ISL-031, ruled "keeps the keyboard" and "Fix it with the label work"): ONE tree whether the label
62714
62833
  // shows or not, so React keeps the select (and the keyboard on it) when Enable Label changes, and one element carries
62715
62834
  // the root ref. Without a label the outer div makes no box (display: contents) and the input wrapper is the root, as before.
62716
- /* @__PURE__ */ import_react5.default.createElement("div", { ref: noodlRootRef(props.noodlNode), ...dataAttributeProps(props.dom), style: outerWrapperStyle }, /* @__PURE__ */ import_react5.default.createElement(
62835
+ /* @__PURE__ */ import_react6.default.createElement("div", { ref: noodlRootRef(props.noodlNode), ...dataAttributeProps(props.dom), style: outerWrapperStyle }, /* @__PURE__ */ import_react6.default.createElement(
62717
62836
  "label",
62718
62837
  {
62719
62838
  htmlFor: props.id,
@@ -62728,13 +62847,13 @@ function Select(props) {
62728
62847
  ), inputWrapper)
62729
62848
  );
62730
62849
  } else {
62731
- return /* @__PURE__ */ import_react5.default.createElement("div", { style: { ...clearedRootStyles(style2), display: "contents" } }, null, inputWrapper);
62850
+ return /* @__PURE__ */ import_react6.default.createElement("div", { style: { ...clearedRootStyles(style2), display: "contents" } }, null, inputWrapper);
62732
62851
  }
62733
62852
  }
62734
- var import_react5;
62853
+ var import_react6;
62735
62854
  var init_Select = __esm({
62736
62855
  "../noodl-viewer-react/src/components/controls/Select/Select.tsx"() {
62737
- import_react5 = __toESM(require_react());
62856
+ import_react6 = __toESM(require_react());
62738
62857
  init_layout();
62739
62858
  init_utils2();
62740
62859
  init_noodl_root_ref();
@@ -62755,7 +62874,8 @@ function optionItems(items) {
62755
62874
  if (!items) return items;
62756
62875
  if (typeof items === "string") return readItems(items);
62757
62876
  if (!Array.isArray(items)) return [];
62758
- return items.some((item) => item === null || item === void 0) ? items.filter((item) => item !== null && item !== void 0) : items;
62877
+ if (!items.some((item) => item === null || item === void 0 || typeof item !== "object")) return items;
62878
+ return items.filter((item) => item !== null && item !== void 0).map((item) => typeof item === "object" ? item : { Label: String(item), Value: String(item) });
62759
62879
  }
62760
62880
  function readItems(stored) {
62761
62881
  let source2 = stored;
@@ -63070,11 +63190,11 @@ var init_options = __esm({
63070
63190
  });
63071
63191
 
63072
63192
  // ../noodl-viewer-react/src/contexts/radiobuttoncontext.ts
63073
- var import_react6, RadioButtonContext, radiobuttoncontext_default;
63193
+ var import_react7, RadioButtonContext, radiobuttoncontext_default;
63074
63194
  var init_radiobuttoncontext = __esm({
63075
63195
  "../noodl-viewer-react/src/contexts/radiobuttoncontext.ts"() {
63076
- import_react6 = __toESM(require_react());
63077
- RadioButtonContext = import_react6.default.createContext(null);
63196
+ import_react7 = __toESM(require_react());
63197
+ RadioButtonContext = import_react7.default.createContext(null);
63078
63198
  radiobuttoncontext_default = RadioButtonContext;
63079
63199
  }
63080
63200
  });
@@ -63084,7 +63204,7 @@ function isPercentage2(size) {
63084
63204
  return size && size[size.length - 1] === "%";
63085
63205
  }
63086
63206
  function RadioButton(props) {
63087
- const radioButtonGroup = (0, import_react7.useContext)(radiobuttoncontext_default);
63207
+ const radioButtonGroup = (0, import_react8.useContext)(radiobuttoncontext_default);
63088
63208
  const style2 = { ...props.style };
63089
63209
  if (props.parentLayout === "none") {
63090
63210
  style2.position = "absolute";
@@ -63092,12 +63212,12 @@ function RadioButton(props) {
63092
63212
  layout_default.align(style2, props);
63093
63213
  const checked = radioButtonGroup ? radioButtonGroup.selected === props.value : false;
63094
63214
  const hasGroup = radioButtonGroup !== null;
63095
- (0, import_react7.useEffect)(() => {
63215
+ (0, import_react8.useEffect)(() => {
63096
63216
  if (!hasGroup) props.groupMissing && props.groupMissing();
63097
63217
  }, [hasGroup, props.groupMissing]);
63098
63218
  const click = radioButtonGroup ? radioButtonGroup.click : null;
63099
- const seen = (0, import_react7.useRef)(click ? click.seq : 0);
63100
- (0, import_react7.useEffect)(() => {
63219
+ const seen = (0, import_react8.useRef)(click ? click.seq : 0);
63220
+ (0, import_react8.useEffect)(() => {
63101
63221
  let fromClick = false;
63102
63222
  if (click && click.seq !== seen.current) {
63103
63223
  seen.current = click.seq;
@@ -63134,10 +63254,10 @@ function RadioButton(props) {
63134
63254
  function _renderIcon() {
63135
63255
  if (!checked) return null;
63136
63256
  if (props.iconSourceType === "image" && props.iconImageSource !== void 0)
63137
- return /* @__PURE__ */ import_react7.default.createElement("img", { alt: "", src: props.iconImageSource, style: { width: props.iconSize, height: props.iconSize } });
63257
+ return /* @__PURE__ */ import_react8.default.createElement("img", { alt: "", src: props.iconImageSource, style: { width: props.iconSize, height: props.iconSize } });
63138
63258
  else if (props.iconSourceType === "icon" && props.iconIconSource !== void 0) {
63139
63259
  const style3 = { fontSize: props.iconSize, color: props.iconColor };
63140
- return /* @__PURE__ */ import_react7.default.createElement(IconGlyph, { source: props.iconIconSource, style: style3, className: "ndl-controls-abs-center" });
63260
+ return /* @__PURE__ */ import_react8.default.createElement(IconGlyph, { source: props.iconIconSource, style: style3, className: "ndl-controls-abs-center" });
63141
63261
  }
63142
63262
  return null;
63143
63263
  }
@@ -63152,7 +63272,7 @@ function RadioButton(props) {
63152
63272
  borderRadius: "inherit",
63153
63273
  position: "absolute"
63154
63274
  };
63155
- const radioButton = /* @__PURE__ */ import_react7.default.createElement(
63275
+ const radioButton = /* @__PURE__ */ import_react8.default.createElement(
63156
63276
  "div",
63157
63277
  {
63158
63278
  ref: props.useLabel ? void 0 : noodlRootRef(props.noodlNode),
@@ -63161,9 +63281,9 @@ function RadioButton(props) {
63161
63281
  style: props.useLabel ? { ...clearedRootStyles(style2), ...inputWrapperStyle } : inputWrapperStyle,
63162
63282
  "noodl-style-tag": "radio"
63163
63283
  },
63164
- /* @__PURE__ */ import_react7.default.createElement("div", { style: fillStyle, "noodl-style-tag": "fill" }),
63284
+ /* @__PURE__ */ import_react8.default.createElement("div", { style: fillStyle, "noodl-style-tag": "fill" }),
63165
63285
  props.useIcon ? _renderIcon() : null,
63166
- /* @__PURE__ */ import_react7.default.createElement(
63286
+ /* @__PURE__ */ import_react8.default.createElement(
63167
63287
  "input",
63168
63288
  {
63169
63289
  type: "radio",
@@ -63191,15 +63311,15 @@ function RadioButton(props) {
63191
63311
  if (isPercentage2(props.styles.radio.height)) {
63192
63312
  wrapperStyle.height = props.styles.radio.height;
63193
63313
  }
63194
- return /* @__PURE__ */ import_react7.default.createElement("div", { ref: noodlRootRef(props.noodlNode), ...dataAttributeProps(props.dom), style: wrapperStyle, ...utils_default.controlEvents(props) }, radioButton, /* @__PURE__ */ import_react7.default.createElement("label", { className: "ndl-controls-pointer", style: labelStyle, htmlFor: props.id, "noodl-style-tag": "label" }, labelText(props.label)));
63314
+ return /* @__PURE__ */ import_react8.default.createElement("div", { ref: noodlRootRef(props.noodlNode), ...dataAttributeProps(props.dom), style: wrapperStyle, ...utils_default.controlEvents(props) }, radioButton, /* @__PURE__ */ import_react8.default.createElement("label", { className: "ndl-controls-pointer", style: labelStyle, htmlFor: props.id, "noodl-style-tag": "label" }, labelText(props.label)));
63195
63315
  } else {
63196
- return /* @__PURE__ */ import_react7.default.createElement("div", { style: { ...clearedRootStyles(style2), display: "contents" } }, radioButton, null);
63316
+ return /* @__PURE__ */ import_react8.default.createElement("div", { style: { ...clearedRootStyles(style2), display: "contents" } }, radioButton, null);
63197
63317
  }
63198
63318
  }
63199
- var import_react7;
63319
+ var import_react8;
63200
63320
  var init_RadioButton = __esm({
63201
63321
  "../noodl-viewer-react/src/components/controls/RadioButton/RadioButton.tsx"() {
63202
- import_react7 = __toESM(require_react());
63322
+ import_react8 = __toESM(require_react());
63203
63323
  init_radiobuttoncontext();
63204
63324
  init_layout();
63205
63325
  init_utils2();
@@ -63404,8 +63524,8 @@ var init_radiobutton = __esm({
63404
63524
 
63405
63525
  // ../noodl-viewer-react/src/components/controls/RadioButtonGroup/RadioButtonGroup.tsx
63406
63526
  function RadioButtonGroup(props) {
63407
- const [selection, setSelection] = (0, import_react8.useState)({ value: props.value, click: null });
63408
- const clicks = (0, import_react8.useRef)(0);
63527
+ const [selection, setSelection] = (0, import_react9.useState)({ value: props.value, click: null });
63528
+ const clicks = (0, import_react9.useRef)(0);
63409
63529
  const context = {
63410
63530
  selected: selection.value,
63411
63531
  click: selection.click,
@@ -63416,7 +63536,7 @@ function RadioButtonGroup(props) {
63416
63536
  props.valueChanged && props.valueChanged(value2);
63417
63537
  }
63418
63538
  };
63419
- (0, import_react8.useEffect)(() => {
63539
+ (0, import_react9.useEffect)(() => {
63420
63540
  setSelection({ value: props.value, click: null });
63421
63541
  }, [props.value, props.valueWrites]);
63422
63542
  const style2 = { ...props.style };
@@ -63425,12 +63545,12 @@ function RadioButtonGroup(props) {
63425
63545
  let className = "ndl-controls-radiobuttongroup";
63426
63546
  if (props.className) className = className + " " + props.className;
63427
63547
  const defaultsClass = layerDefaults(style2);
63428
- return /* @__PURE__ */ import_react8.default.createElement(radiobuttoncontext_default.Provider, { value: context }, /* @__PURE__ */ import_react8.default.createElement("div", { ref: noodlRootRef(props.noodlNode), ...dataAttributeProps(props.dom), className: withDefaultsClass(className, defaultsClass), style: style2 }, props.children));
63548
+ return /* @__PURE__ */ import_react9.default.createElement(radiobuttoncontext_default.Provider, { value: context }, /* @__PURE__ */ import_react9.default.createElement("div", { ref: noodlRootRef(props.noodlNode), ...dataAttributeProps(props.dom), className: withDefaultsClass(className, defaultsClass), style: style2 }, props.children));
63429
63549
  }
63430
- var import_react8;
63550
+ var import_react9;
63431
63551
  var init_RadioButtonGroup = __esm({
63432
63552
  "../noodl-viewer-react/src/components/controls/RadioButtonGroup/RadioButtonGroup.tsx"() {
63433
- import_react8 = __toESM(require_react());
63553
+ import_react9 = __toESM(require_react());
63434
63554
  init_radiobuttoncontext();
63435
63555
  init_default_style_layer();
63436
63556
  init_layout();
@@ -63635,8 +63755,8 @@ function hasUnitPx(value2) {
63635
63755
  return value2 && value2[value2.length - 1] === "x";
63636
63756
  }
63637
63757
  function Slider(props) {
63638
- const [value2, setValue] = (0, import_react9.useState)(props.handle);
63639
- (0, import_react9.useEffect)(() => {
63758
+ const [value2, setValue] = (0, import_react10.useState)(props.handle);
63759
+ (0, import_react10.useEffect)(() => {
63640
63760
  setValue(props.drawHandle());
63641
63761
  }, [props.valueWrites]);
63642
63762
  function onValueChanged(value3) {
@@ -63701,7 +63821,7 @@ function Slider(props) {
63701
63821
  setBorderStyle(thumbStyle, "thumb", props);
63702
63822
  setBorderRadius(thumbStyle, "thumb", props);
63703
63823
  setShadow(thumbStyle, "thumb", props);
63704
- return /* @__PURE__ */ import_react9.default.createElement("div", { ref: noodlRootRef(props.noodlNode), ...dataAttributeProps(props.dom), style: divStyle }, /* @__PURE__ */ import_react9.default.createElement("div", { style: trackStyle }), /* @__PURE__ */ import_react9.default.createElement("div", { style: thumbStyle }), /* @__PURE__ */ import_react9.default.createElement(
63824
+ return /* @__PURE__ */ import_react10.default.createElement("div", { ref: noodlRootRef(props.noodlNode), ...dataAttributeProps(props.dom), style: divStyle }, /* @__PURE__ */ import_react10.default.createElement("div", { style: trackStyle }), /* @__PURE__ */ import_react10.default.createElement("div", { style: thumbStyle }), /* @__PURE__ */ import_react10.default.createElement(
63705
63825
  "input",
63706
63826
  {
63707
63827
  className,
@@ -63714,10 +63834,10 @@ function Slider(props) {
63714
63834
  }
63715
63835
  ));
63716
63836
  }
63717
- var import_react9;
63837
+ var import_react10;
63718
63838
  var init_Slider = __esm({
63719
63839
  "../noodl-viewer-react/src/components/controls/Slider/Slider.tsx"() {
63720
- import_react9 = __toESM(require_react());
63840
+ import_react10 = __toESM(require_react());
63721
63841
  init_layout();
63722
63842
  init_utils2();
63723
63843
  init_noodl_root_ref();
@@ -64001,7 +64121,7 @@ function addShadowInputs(definition4, opts) {
64001
64121
  }
64002
64122
  });
64003
64123
  }
64004
- var thumbPopout, trackPopout, RangeNode, slider_default;
64124
+ var thumbPopout, MAX_BELOW_MIN, trackPopout, RangeNode, slider_default;
64005
64125
  var init_slider = __esm({
64006
64126
  "../noodl-viewer-react/src/nodes/controls/slider.ts"() {
64007
64127
  init_Slider2();
@@ -64010,6 +64130,7 @@ var init_slider = __esm({
64010
64130
  init_react_component_node();
64011
64131
  init_utils2();
64012
64132
  thumbPopout = { group: "thumb-styles", label: "Thumb Styles" };
64133
+ MAX_BELOW_MIN = "slider/max-below-min";
64013
64134
  trackPopout = { group: "track-styles", label: "Track Styles" };
64014
64135
  RangeNode = {
64015
64136
  name: "net.noodl.controls.range",
@@ -64227,6 +64348,9 @@ var init_slider = __esm({
64227
64348
  },
64228
64349
  /** Min, Max or Step written: the next paint draws the handle against them (C74) — no word for it */
64229
64350
  _attributeChanged() {
64351
+ const min = rangeAttribute(this.props.min) ?? 0;
64352
+ const max = rangeAttribute(this.props.max) ?? 100;
64353
+ this.setDiagnostic(MAX_BELOW_MIN, max < min ? `Max ${max} is below Min ${min}, so the handle stays at Min and cannot be moved.` : null);
64230
64354
  this.props.valueWrites++;
64231
64355
  this.forceUpdate();
64232
64356
  },
@@ -64305,17 +64429,17 @@ function preventGlobalFocusChange(e) {
64305
64429
  e.stopPropagation();
64306
64430
  window.removeEventListener("click", preventGlobalFocusChange, true);
64307
64431
  }
64308
- var import_react10, TextInput;
64432
+ var import_react11, TextInput;
64309
64433
  var init_TextInput = __esm({
64310
64434
  "../noodl-viewer-react/src/components/controls/TextInput/TextInput.tsx"() {
64311
- import_react10 = __toESM(require_react());
64435
+ import_react11 = __toESM(require_react());
64312
64436
  init_layout();
64313
64437
  init_utils2();
64314
64438
  init_textInputValue();
64315
64439
  init_noodl_root_ref();
64316
64440
  init_IconGlyph();
64317
64441
  init_labelText();
64318
- TextInput = class extends import_react10.default.Component {
64442
+ TextInput = class extends import_react11.default.Component {
64319
64443
  constructor(props) {
64320
64444
  super(props);
64321
64445
  /**
@@ -64334,7 +64458,7 @@ var init_TextInput = __esm({
64334
64458
  value: props.startValue === null || props.startValue === void 0 ? "" : String(props.startValue)
64335
64459
  };
64336
64460
  this.text = this.state.value;
64337
- this.ref = import_react10.default.createRef();
64461
+ this.ref = import_react11.default.createRef();
64338
64462
  }
64339
64463
  /** P107-C72 — the Type or Max length as it stands on the node, not as React last drew it. */
64340
64464
  live(key) {
@@ -64372,7 +64496,7 @@ var init_TextInput = __esm({
64372
64496
  const props = this.props;
64373
64497
  const _renderIcon = () => {
64374
64498
  if (props.iconSourceType === "image" && props.iconImageSource !== void 0)
64375
- return /* @__PURE__ */ import_react10.default.createElement(
64499
+ return /* @__PURE__ */ import_react11.default.createElement(
64376
64500
  "img",
64377
64501
  {
64378
64502
  alt: "",
@@ -64392,7 +64516,7 @@ var init_TextInput = __esm({
64392
64516
  };
64393
64517
  if (props.iconPlacement === "left" || props.iconPlacement === void 0) style3.marginRight = props.iconSpacing;
64394
64518
  else style3.marginLeft = props.iconSpacing;
64395
- return /* @__PURE__ */ import_react10.default.createElement(IconGlyph, { source: props.iconIconSource, style: style3 });
64519
+ return /* @__PURE__ */ import_react11.default.createElement(IconGlyph, { source: props.iconIconSource, style: style3 });
64396
64520
  }
64397
64521
  return null;
64398
64522
  };
@@ -64427,7 +64551,7 @@ var init_TextInput = __esm({
64427
64551
  onChange: (e) => this.onChange(e)
64428
64552
  };
64429
64553
  if (props.type !== "textArea") {
64430
- inputContent = /* @__PURE__ */ import_react10.default.createElement(
64554
+ inputContent = /* @__PURE__ */ import_react11.default.createElement(
64431
64555
  "input",
64432
64556
  {
64433
64557
  ref: (ref) => {
@@ -64445,7 +64569,7 @@ var init_TextInput = __esm({
64445
64569
  );
64446
64570
  } else {
64447
64571
  inputProps.style.resize = "none";
64448
- inputContent = /* @__PURE__ */ import_react10.default.createElement(
64572
+ inputContent = /* @__PURE__ */ import_react11.default.createElement(
64449
64573
  "textarea",
64450
64574
  {
64451
64575
  ref: (ref) => {
@@ -64483,7 +64607,7 @@ var init_TextInput = __esm({
64483
64607
  if (props.type !== "textArea") {
64484
64608
  inputWrapperStyle.alignItems = "center";
64485
64609
  }
64486
- const inputWithWrapper = /* @__PURE__ */ import_react10.default.createElement(
64610
+ const inputWithWrapper = /* @__PURE__ */ import_react11.default.createElement(
64487
64611
  "div",
64488
64612
  {
64489
64613
  ref: props.useLabel ? void 0 : noodlRootRef(this.props.noodlNode),
@@ -64509,10 +64633,10 @@ var init_TextInput = __esm({
64509
64633
  // P107-C80 / C66 (P109 ISL-031, ruled "keeps the keyboard" and "Fix it with the label work"): ONE tree whether the label
64510
64634
  // shows or not, so React keeps the field (and the keyboard on it) when Enable Label changes, and one element carries
64511
64635
  // the root ref. Without a label the outer div makes no box (display: contents) and the wrapper is the root, as before.
64512
- /* @__PURE__ */ import_react10.default.createElement("div", { ref: noodlRootRef(this.props.noodlNode), ...dataAttributeProps(props.dom), style: otherStyles }, /* @__PURE__ */ import_react10.default.createElement("label", { htmlFor: props.id, style: labelStyle, "noodl-style-tag": "label" }, labelText(props.label)), inputWithWrapper)
64636
+ /* @__PURE__ */ import_react11.default.createElement("div", { ref: noodlRootRef(this.props.noodlNode), ...dataAttributeProps(props.dom), style: otherStyles }, /* @__PURE__ */ import_react11.default.createElement("label", { htmlFor: props.id, style: labelStyle, "noodl-style-tag": "label" }, labelText(props.label)), inputWithWrapper)
64513
64637
  );
64514
64638
  } else {
64515
- return /* @__PURE__ */ import_react10.default.createElement("div", { style: { ...clearedRootStyles(style2), display: "contents" } }, null, inputWithWrapper);
64639
+ return /* @__PURE__ */ import_react11.default.createElement("div", { style: { ...clearedRootStyles(style2), display: "contents" } }, null, inputWithWrapper);
64516
64640
  }
64517
64641
  }
64518
64642
  onKeyDown(e) {
@@ -65647,18 +65771,18 @@ function decodeOrKeep(text2) {
65647
65771
  }
65648
65772
  function PageStackReactComponent(props) {
65649
65773
  const { didMount, willUnmount, style: style2, children } = props;
65650
- (0, import_react11.useEffect)(() => {
65774
+ (0, import_react12.useEffect)(() => {
65651
65775
  didMount();
65652
65776
  return () => {
65653
65777
  willUnmount();
65654
65778
  };
65655
65779
  }, []);
65656
- return /* @__PURE__ */ import_react11.default.createElement("div", { ref: noodlRootRef(props.noodlNode), ...dataAttributeProps(props.dom), style: style2 }, children);
65780
+ return /* @__PURE__ */ import_react12.default.createElement("div", { ref: noodlRootRef(props.noodlNode), ...dataAttributeProps(props.dom), style: style2 }, children);
65657
65781
  }
65658
- var import_react11, import_runtime, PageStack, navigation_stack_default;
65782
+ var import_react12, import_runtime, PageStack, navigation_stack_default;
65659
65783
  var init_navigation_stack = __esm({
65660
65784
  "../noodl-viewer-react/src/nodes/navigation/navigation-stack.tsx"() {
65661
- import_react11 = __toESM(require_react());
65785
+ import_react12 = __toESM(require_react());
65662
65786
  import_runtime = __toESM(require_noodl_runtime());
65663
65787
  init_outcome();
65664
65788
  init_async_queue();
@@ -66624,9 +66748,9 @@ var init_navigation_stack = __esm({
66624
66748
  }
66625
66749
  });
66626
66750
 
66627
- // type-stub:/Users/richardosborne/vscode_projects/OpenNoodl-worktrees/own011-publish/packages/noodl-viewer-react/src/types.ts
66751
+ // type-stub:/Users/richardosborne/vscode_projects/OpenNoodl-worktrees/npm021-pack/packages/noodl-viewer-react/src/types.ts
66628
66752
  var require_types2 = __commonJS({
66629
- "type-stub:/Users/richardosborne/vscode_projects/OpenNoodl-worktrees/own011-publish/packages/noodl-viewer-react/src/types.ts"(exports2, module2) {
66753
+ "type-stub:/Users/richardosborne/vscode_projects/OpenNoodl-worktrees/npm021-pack/packages/noodl-viewer-react/src/types.ts"(exports2, module2) {
66630
66754
  var noop2 = new Proxy(function() {
66631
66755
  }, { get: () => noop2, apply: () => noop2 });
66632
66756
  module2.exports = new Proxy({}, { get: () => noop2 });
@@ -66649,12 +66773,12 @@ function Page(props) {
66649
66773
  if (!inBrowser2) {
66650
66774
  applyMetaTags();
66651
66775
  }
66652
- (0, import_react12.useEffect)(() => {
66776
+ (0, import_react13.useEffect)(() => {
66653
66777
  if (!inBrowser2) return;
66654
66778
  applyMetaTags();
66655
66779
  });
66656
66780
  const defaultsClass = layerDefaults(style2);
66657
- return /* @__PURE__ */ import_react12.default.createElement(
66781
+ return /* @__PURE__ */ import_react13.default.createElement(
66658
66782
  "div",
66659
66783
  {
66660
66784
  ref: noodlRootRef(props.noodlNode),
@@ -66665,10 +66789,10 @@ function Page(props) {
66665
66789
  children
66666
66790
  );
66667
66791
  }
66668
- var import_react12, import_types4, ogPopout, twitterPopout, OG_TYPES, TWITTER_CARDS, META_TAGS;
66792
+ var import_react13, import_types4, ogPopout, twitterPopout, OG_TYPES, TWITTER_CARDS, META_TAGS;
66669
66793
  var init_Page = __esm({
66670
66794
  "../noodl-viewer-react/src/components/navigation/Page/Page.tsx"() {
66671
- import_react12 = __toESM(require_react());
66795
+ import_react13 = __toESM(require_react());
66672
66796
  init_default_style_layer();
66673
66797
  init_layout();
66674
66798
  import_types4 = __toESM(require_types2());
@@ -66912,6 +67036,7 @@ var init_page = __esm({
66912
67036
  type: "string",
66913
67037
  set: function(value2) {
66914
67038
  this._internal.title = value2;
67039
+ if (this._internal.onTitleChanged) this._internal.onTitleChanged();
66915
67040
  }
66916
67041
  },
66917
67042
  urlPath: {
@@ -67039,6 +67164,7 @@ var init_page = __esm({
67039
67164
  },*/
67040
67165
  setTitle: function(value2) {
67041
67166
  this._internal.title = value2;
67167
+ if (this._internal.onTitleChanged) this._internal.onTitleChanged();
67042
67168
  },
67043
67169
  setUrlPath: function(value2) {
67044
67170
  this._internal.urlPath = value2;
@@ -67211,13 +67337,13 @@ var init_router_handler = __esm({
67211
67337
  // ../noodl-viewer-react/src/nodes/navigation/router.tsx
67212
67338
  function RouterReactComponent(props) {
67213
67339
  const { didMount, willUnmount, children, style: style2 } = props;
67214
- (0, import_react13.useEffect)(() => {
67340
+ (0, import_react14.useEffect)(() => {
67215
67341
  didMount();
67216
67342
  return () => {
67217
67343
  willUnmount();
67218
67344
  };
67219
67345
  }, []);
67220
- return /* @__PURE__ */ import_react13.default.createElement(
67346
+ return /* @__PURE__ */ import_react14.default.createElement(
67221
67347
  "div",
67222
67348
  {
67223
67349
  ref: noodlRootRef(props.noodlNode),
@@ -67269,10 +67395,10 @@ function shallowObjectsEqual(object1, object2) {
67269
67395
  }
67270
67396
  return keys1.every((key) => object1[key] === object2[key]);
67271
67397
  }
67272
- var import_react13, import_runtime3, import_types5, RESET_DIAGNOSIS_CODES, RouterNode, router_default;
67398
+ var import_react14, import_runtime3, import_types5, RESET_DIAGNOSIS_CODES, RouterNode, router_default;
67273
67399
  var init_router = __esm({
67274
67400
  "../noodl-viewer-react/src/nodes/navigation/router.tsx"() {
67275
- import_react13 = __toESM(require_react());
67401
+ import_react14 = __toESM(require_react());
67276
67402
  import_runtime3 = __toESM(require_noodl_runtime());
67277
67403
  init_outcome();
67278
67404
  init_async_queue();
@@ -67587,6 +67713,29 @@ var init_router = __esm({
67587
67713
  }
67588
67714
  return kept;
67589
67715
  },
67716
+ /**
67717
+ * P109-S45-WIREDTITLE — the browser tab is named by the Page node's current Title, the typed one from the Pages list
67718
+ * when it has none.
67719
+ *
67720
+ * The tab used to be set once, from the router index's entry, which the exporter builds from the Page node's
67721
+ * *parameters*: a Title wired from a Translation or a record reached the Page node and never the tab. A wired value
67722
+ * arrives after the page is shown, and can change while it shows, so the Page node calls back on every Title it is
67723
+ * given, and the callback names the tab only while this Router is still showing that page (a page left, or kept and
67724
+ * hidden, names nothing). Current Page Title still reads the Pages list, as its description says.
67725
+ */
67726
+ _nameTabFromPage(content) {
67727
+ const pages = content && content.nodeScope ? content.nodeScope.getNodesWithType("Page") : void 0;
67728
+ const pageNode = pages && pages.length === 1 && pages[0]._internal && typeof pages[0].getTitle === "function" ? pages[0] : void 0;
67729
+ const nameTab = () => {
67730
+ if (this._internal.currentPageComponent !== content || !this._internal.currentPage) return;
67731
+ const title = pageNode ? pageNode.getTitle() : void 0;
67732
+ import_types5.Noodl.SEO.setTitle(
67733
+ title !== void 0 && title !== null && title !== "" ? String(title) : this._internal.currentPage.title
67734
+ );
67735
+ };
67736
+ if (pageNode) pageNode._internal.onTitleChanged = nameTab;
67737
+ nameTab();
67738
+ },
67590
67739
  _showKeptPage(content) {
67591
67740
  _eachNodeOf(content, (n) => n._onPageShown && n._onPageShown());
67592
67741
  },
@@ -67700,7 +67849,7 @@ var init_router = __esm({
67700
67849
  this._internal.currentParams = params;
67701
67850
  this.flagOutputDirty("currentPageTitle");
67702
67851
  this.flagOutputDirty("currentPageComponent");
67703
- import_types5.Noodl.SEO.setTitle(this._internal.currentPage.title);
67852
+ this._nameTabFromPage(content);
67704
67853
  this._updatePageInputs(this._internal.currentPageComponent.nodeScope, params);
67705
67854
  const group = kept || this.createPageContainer();
67706
67855
  if (!kept) {
@@ -67970,7 +68119,7 @@ var init_router = __esm({
67970
68119
  this._internal.currentParams = args.params;
67971
68120
  this.flagOutputDirty("currentPageTitle");
67972
68121
  this.flagOutputDirty("currentPageComponent");
67973
- import_types5.Noodl.SEO.setTitle(this._internal.currentPage.title);
68122
+ this._nameTabFromPage(content);
67974
68123
  const pageInputNodes = content.nodeScope.getNodesWithType("PageInputs");
67975
68124
  if (pageInputNodes !== void 0 && pageInputNodes.length > 0) {
67976
68125
  pageInputNodes.forEach((node) => {
@@ -68264,17 +68413,17 @@ function shapePoints(shape, size, points) {
68264
68413
  return starPoints(size, points);
68265
68414
  }
68266
68415
  }
68267
- var import_react14, MAX_POINTS, Circle;
68416
+ var import_react15, MAX_POINTS, Circle;
68268
68417
  var init_Circle = __esm({
68269
68418
  "../noodl-viewer-react/src/components/visual/Circle/Circle.tsx"() {
68270
- import_react14 = __toESM(require_react());
68419
+ import_react15 = __toESM(require_react());
68271
68420
  init_default_style_layer();
68272
68421
  init_layout();
68273
68422
  init_pointerlisteners();
68274
68423
  init_sanitize_inline_svg();
68275
68424
  init_noodl_root_ref();
68276
68425
  MAX_POINTS = 500;
68277
- Circle = class extends import_react14.default.Component {
68426
+ Circle = class extends import_react15.default.Component {
68278
68427
  constructor(props) {
68279
68428
  super(props);
68280
68429
  }
@@ -68286,7 +68435,7 @@ var init_Circle = __esm({
68286
68435
  const { startAngle, endAngle } = this.props;
68287
68436
  let custom = null;
68288
68437
  if (shape === "svg") {
68289
- custom = /* @__PURE__ */ import_react14.default.createElement(
68438
+ custom = /* @__PURE__ */ import_react15.default.createElement(
68290
68439
  "span",
68291
68440
  {
68292
68441
  "data-ndl-drawing": "",
@@ -68296,13 +68445,13 @@ var init_Circle = __esm({
68296
68445
  );
68297
68446
  } else if (shape === "circle") {
68298
68447
  if (this.props.fillEnabled) {
68299
- fill = /* @__PURE__ */ import_react14.default.createElement("path", { d: filledArc(r, r, r, startAngle, endAngle), fill: this.props.fillColor });
68448
+ fill = /* @__PURE__ */ import_react15.default.createElement("path", { d: filledArc(r, r, r, startAngle, endAngle), fill: this.props.fillColor });
68300
68449
  }
68301
68450
  if (this.props.strokeEnabled) {
68302
68451
  const { strokeColor, strokeWidth, strokeLineCap } = this.props;
68303
68452
  const strokeRadius = r - this.props.strokeWidth / 2;
68304
68453
  const path2 = arc(r, r, strokeRadius, startAngle, endAngle);
68305
- stroke = /* @__PURE__ */ import_react14.default.createElement(
68454
+ stroke = /* @__PURE__ */ import_react15.default.createElement(
68306
68455
  "path",
68307
68456
  {
68308
68457
  d: path2,
@@ -68318,12 +68467,12 @@ var init_Circle = __esm({
68318
68467
  const cornerRadius = Math.max(0, this.props.cornerRadius ?? 0);
68319
68468
  const points = shapePoints(shape, this.props.size, pointCount);
68320
68469
  if (this.props.fillEnabled) {
68321
- fill = /* @__PURE__ */ import_react14.default.createElement("path", { d: roundedPolygonPath(points, cornerRadius), fill: this.props.fillColor });
68470
+ fill = /* @__PURE__ */ import_react15.default.createElement("path", { d: roundedPolygonPath(points, cornerRadius), fill: this.props.fillColor });
68322
68471
  }
68323
68472
  if (this.props.strokeEnabled) {
68324
68473
  const { strokeColor, strokeWidth } = this.props;
68325
68474
  const inset = insetPolygon(points, strokeWidth / 2);
68326
- stroke = /* @__PURE__ */ import_react14.default.createElement(
68475
+ stroke = /* @__PURE__ */ import_react15.default.createElement(
68327
68476
  "path",
68328
68477
  {
68329
68478
  d: roundedPolygonPath(inset, Math.max(0, cornerRadius - strokeWidth / 2)),
@@ -68341,7 +68490,7 @@ var init_Circle = __esm({
68341
68490
  style2.pointerEvents = "none";
68342
68491
  }
68343
68492
  const defaultsClass = layerDefaults(style2);
68344
- return /* @__PURE__ */ import_react14.default.createElement(
68493
+ return /* @__PURE__ */ import_react15.default.createElement(
68345
68494
  "div",
68346
68495
  {
68347
68496
  ref: noodlRootRef(this.props.noodlNode),
@@ -68350,7 +68499,7 @@ var init_Circle = __esm({
68350
68499
  ...pointerProps(this.props),
68351
68500
  style: style2
68352
68501
  },
68353
- custom ?? /* @__PURE__ */ import_react14.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: this.props.size, height: this.props.size }, fill, stroke)
68502
+ custom ?? /* @__PURE__ */ import_react15.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: this.props.size, height: this.props.size }, fill, stroke)
68354
68503
  );
68355
68504
  }
68356
68505
  };
@@ -68620,7 +68769,7 @@ function itemsProblem(value2) {
68620
68769
  }
68621
68770
  function ForEachComponent(props) {
68622
68771
  const { didMount, willUnmount } = props;
68623
- (0, import_react15.useEffect)(() => {
68772
+ (0, import_react16.useEffect)(() => {
68624
68773
  didMount();
68625
68774
  return () => {
68626
68775
  willUnmount();
@@ -68632,10 +68781,10 @@ function _typeName(t) {
68632
68781
  if (typeof t === "object") return t.name;
68633
68782
  else return t;
68634
68783
  }
68635
- var import_react15, import_runtime4, import_collection, import_model2, ITEMS_DIAGNOSTIC, defaultDynamicScript, ForEachDefinition, defaultMapCode, ForEachModule, foreach_default;
68784
+ var import_react16, import_runtime4, import_collection, import_model2, ITEMS_DIAGNOSTIC, defaultDynamicScript, ForEachDefinition, defaultMapCode, ForEachModule, foreach_default;
68636
68785
  var init_foreach = __esm({
68637
68786
  "../noodl-viewer-react/src/nodes/std-library/data/foreach.tsx"() {
68638
- import_react15 = __toESM(require_react());
68787
+ import_react16 = __toESM(require_react());
68639
68788
  import_runtime4 = __toESM(require_noodl_runtime());
68640
68789
  import_collection = __toESM(require_collection());
68641
68790
  import_model2 = __toESM(require_model());
@@ -69168,7 +69317,7 @@ var init_foreach = __esm({
69168
69317
  this.unbindCurrentCollection();
69169
69318
  },
69170
69319
  render() {
69171
- return /* @__PURE__ */ import_react15.default.createElement(ForEachComponent, { key: this.id, didMount: () => this.didMount(), willUnmount: () => this.willUnmount() });
69320
+ return /* @__PURE__ */ import_react16.default.createElement(ForEachComponent, { key: this.id, didMount: () => this.didMount(), willUnmount: () => this.willUnmount() });
69172
69321
  },
69173
69322
  didMount() {
69174
69323
  this.isMounted = true;
@@ -69521,7 +69670,7 @@ function calcAutoFit(minWidth, containerWidth, marginX, childCount) {
69521
69670
  }
69522
69671
  function partitionColumnChildren(slot) {
69523
69672
  const childArray = Array.isArray(slot) ? slot : [slot];
69524
- const elements = childArray.filter((child) => (0, import_react16.isValidElement)(child));
69673
+ const elements = childArray.filter((child) => (0, import_react17.isValidElement)(child));
69525
69674
  return {
69526
69675
  children: elements.filter((child) => child.type !== ForEachComponent),
69527
69676
  // `filter`, not `find`: a Columns node can hold more than one Repeater, and only the
@@ -69562,13 +69711,13 @@ function readColumnLayoutString(value2) {
69562
69711
  }
69563
69712
  }
69564
69713
  function Columns(props) {
69565
- const [containerWidth, setContainerWidth] = (0, import_react16.useState)(null);
69566
- const [containerElement, setContainerElement] = (0, import_react16.useState)(null);
69567
- const rootRef = (0, import_react16.useCallback)((el) => {
69714
+ const [containerWidth, setContainerWidth] = (0, import_react17.useState)(null);
69715
+ const [containerElement, setContainerElement] = (0, import_react17.useState)(null);
69716
+ const rootRef = (0, import_react17.useCallback)((el) => {
69568
69717
  setContainerElement(el);
69569
69718
  props.noodlNode?.setDOMElement(el);
69570
69719
  }, []);
69571
- (0, import_react16.useEffect)(() => {
69720
+ (0, import_react17.useEffect)(() => {
69572
69721
  if (!containerElement) {
69573
69722
  setContainerWidth(null);
69574
69723
  return;
@@ -69584,10 +69733,10 @@ function Columns(props) {
69584
69733
  }, [containerElement, props.marginX]);
69585
69734
  const { children, forEachComponents } = partitionColumnChildren(props.children);
69586
69735
  const masonry = props.packing === "masonry";
69587
- const itemElements = (0, import_react16.useRef)([]);
69588
- const columnAmountRef = (0, import_react16.useRef)(1);
69589
- const [masonryOffsets, setMasonryOffsets] = (0, import_react16.useState)(null);
69590
- (0, import_react16.useLayoutEffect)(() => {
69736
+ const itemElements = (0, import_react17.useRef)([]);
69737
+ const columnAmountRef = (0, import_react17.useRef)(1);
69738
+ const [masonryOffsets, setMasonryOffsets] = (0, import_react17.useState)(null);
69739
+ (0, import_react17.useLayoutEffect)(() => {
69591
69740
  if (!masonry) {
69592
69741
  setMasonryOffsets(null);
69593
69742
  return;
@@ -69610,14 +69759,14 @@ function Columns(props) {
69610
69759
  const columnLayout = readColumnLayoutString(props.layoutString);
69611
69760
  const resolved = columnLayout === null ? null : resolveColumnLayout(columnLayout, props, containerWidth, children.length);
69612
69761
  const breakpoint = resolved?.breakpoint ?? "Default";
69613
- (0, import_react16.useEffect)(() => {
69762
+ (0, import_react17.useEffect)(() => {
69614
69763
  props.onBreakpointChanged?.(breakpoint);
69615
69764
  if (breakpoint === "Medium") props.onAtMedium?.();
69616
69765
  else if (breakpoint === "Small") props.onAtSmall?.();
69617
69766
  }, [breakpoint]);
69618
69767
  if (!props.children) return null;
69619
69768
  if (resolved === null) {
69620
- return /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, props.children);
69769
+ return /* @__PURE__ */ import_react17.default.createElement(import_react17.default.Fragment, null, props.children);
69621
69770
  }
69622
69771
  const { layout, columnAmount, fractionSize } = resolved;
69623
69772
  columnAmountRef.current = columnAmount;
@@ -69660,7 +69809,7 @@ function Columns(props) {
69660
69809
  ...props.style
69661
69810
  };
69662
69811
  const defaultsClass = layerDefaults(containerStyle, COLUMNS_CONTAINER_SOURCES);
69663
- return /* @__PURE__ */ import_react16.default.createElement(
69812
+ return /* @__PURE__ */ import_react17.default.createElement(
69664
69813
  "div",
69665
69814
  {
69666
69815
  className: withDefaultsClass(["columns-container", props.className].join(" "), defaultsClass),
@@ -69671,7 +69820,7 @@ function Columns(props) {
69671
69820
  forEachComponents,
69672
69821
  children.map((child, i2) => {
69673
69822
  const column = i2 % columnAmount;
69674
- return /* @__PURE__ */ import_react16.default.createElement(
69823
+ return /* @__PURE__ */ import_react17.default.createElement(
69675
69824
  "div",
69676
69825
  {
69677
69826
  className: masonry ? "column-item column-item--masonry" : "column-item",
@@ -69705,10 +69854,10 @@ function Columns(props) {
69705
69854
  })
69706
69855
  );
69707
69856
  }
69708
- var import_react16, COLUMNS_CONTAINER_SOURCES;
69857
+ var import_react17, COLUMNS_CONTAINER_SOURCES;
69709
69858
  var init_Columns = __esm({
69710
69859
  "../noodl-viewer-react/src/components/visual/Columns/Columns.tsx"() {
69711
- import_react16 = __toESM(require_react());
69860
+ import_react17 = __toESM(require_react());
69712
69861
  init_foreach();
69713
69862
  init_noodl_root_ref();
69714
69863
  init_default_style_layer();
@@ -71561,7 +71710,7 @@ var require_DraggableCore = __commonJS({
71561
71710
  value: true
71562
71711
  });
71563
71712
  exports2.default = void 0;
71564
- var React32 = _interopRequireWildcard(require_react());
71713
+ var React33 = _interopRequireWildcard(require_react());
71565
71714
  var _propTypes = _interopRequireDefault(require_prop_types());
71566
71715
  var _reactDom = _interopRequireDefault(require_react_dom());
71567
71716
  var _domFns = require_domFns();
@@ -71615,7 +71764,7 @@ var require_DraggableCore = __commonJS({
71615
71764
  }
71616
71765
  };
71617
71766
  var dragEventFor = eventsFor.mouse;
71618
- var DraggableCore = class extends React32.Component {
71767
+ var DraggableCore = class extends React33.Component {
71619
71768
  constructor() {
71620
71769
  super(...arguments);
71621
71770
  _defineProperty(this, "dragging", false);
@@ -71766,7 +71915,7 @@ var require_DraggableCore = __commonJS({
71766
71915
  return this.props?.nodeRef ? this.props?.nodeRef?.current : _reactDom.default.findDOMNode(this);
71767
71916
  }
71768
71917
  render() {
71769
- return /* @__PURE__ */ React32.cloneElement(React32.Children.only(this.props.children), {
71918
+ return /* @__PURE__ */ React33.cloneElement(React33.Children.only(this.props.children), {
71770
71919
  // Note: mouseMove handler is attached to document so it will still function
71771
71920
  // when the user drags quickly and leaves the bounds of the element.
71772
71921
  onMouseDown: this.onMouseDown,
@@ -71945,7 +72094,7 @@ var require_Draggable = __commonJS({
71945
72094
  }
71946
72095
  });
71947
72096
  exports2.default = void 0;
71948
- var React32 = _interopRequireWildcard(require_react());
72097
+ var React33 = _interopRequireWildcard(require_react());
71949
72098
  var _propTypes = _interopRequireDefault(require_prop_types());
71950
72099
  var _reactDom = _interopRequireDefault(require_react_dom());
71951
72100
  var _clsx = require_clsx();
@@ -71997,7 +72146,7 @@ var require_Draggable = __commonJS({
71997
72146
  }
71998
72147
  return ("string" === r ? String : Number)(t);
71999
72148
  }
72000
- var Draggable2 = class extends React32.Component {
72149
+ var Draggable2 = class extends React33.Component {
72001
72150
  // React 16.3+
72002
72151
  // Arity (props, state)
72003
72152
  static getDerivedStateFromProps(_ref, _ref2) {
@@ -72159,11 +72308,11 @@ var require_Draggable = __commonJS({
72159
72308
  [defaultClassNameDragging]: this.state.dragging,
72160
72309
  [defaultClassNameDragged]: this.state.dragged
72161
72310
  });
72162
- return /* @__PURE__ */ React32.createElement(_DraggableCore.default, _extends({}, draggableCoreProps, {
72311
+ return /* @__PURE__ */ React33.createElement(_DraggableCore.default, _extends({}, draggableCoreProps, {
72163
72312
  onStart: this.onDragStart,
72164
72313
  onDrag: this.onDrag,
72165
72314
  onStop: this.onDragStop
72166
- }), /* @__PURE__ */ React32.cloneElement(React32.Children.only(children), {
72315
+ }), /* @__PURE__ */ React33.cloneElement(React33.Children.only(children), {
72167
72316
  className,
72168
72317
  style: {
72169
72318
  ...children.props.style,
@@ -72323,18 +72472,22 @@ function setDragValues(event, props) {
72323
72472
  function canDrag(axis, on) {
72324
72473
  return axis === on || axis === "both";
72325
72474
  }
72326
- var import_react17, import_react_draggable, DRAG_CANCEL, Drag;
72475
+ function dragEnabled(enabled) {
72476
+ if (enabled === void 0 || enabled === null) return true;
72477
+ return !!enabled && enabled !== "false";
72478
+ }
72479
+ var import_react18, import_react_draggable, DRAG_CANCEL, Drag;
72327
72480
  var init_Drag = __esm({
72328
72481
  "../noodl-viewer-react/src/components/visual/Drag/Drag.tsx"() {
72329
- import_react17 = __toESM(require_react());
72482
+ import_react18 = __toESM(require_react());
72330
72483
  import_react_draggable = __toESM(require_cjs());
72331
72484
  init_easecurves();
72332
72485
  DRAG_CANCEL = "input, textarea, select, button, a, [contenteditable]";
72333
- Drag = class extends import_react17.default.Component {
72486
+ Drag = class extends import_react18.default.Component {
72334
72487
  constructor(props) {
72335
72488
  super(props);
72336
72489
  /** P107-C103 — the element a Drag with more than one child wraps them in, and moves. */
72337
- this.wrapperRef = import_react17.default.createRef();
72490
+ this.wrapperRef = import_react18.default.createRef();
72338
72491
  this.state = { x: 0, y: 0 };
72339
72492
  const self2 = this;
72340
72493
  this.draggableNodeRef = {
@@ -72458,13 +72611,13 @@ var init_Drag = __esm({
72458
72611
  render() {
72459
72612
  const props = this.props;
72460
72613
  const bounds = props.useParentBounds ? "parent" : void 0;
72461
- const children = import_react17.default.Children.toArray(props.children);
72614
+ const children = import_react18.default.Children.toArray(props.children);
72462
72615
  if (children.length === 0) return null;
72463
72616
  const look = {
72464
72617
  ...props.className ? { className: props.className } : {},
72465
72618
  ...props.style && Object.keys(props.style).length > 0 ? { style: props.style } : {}
72466
72619
  };
72467
- const moved = children.length === 1 ? import_react17.default.cloneElement(children[0], { parentLayout: props.parentLayout, ...look }) : /* @__PURE__ */ import_react17.default.createElement(
72620
+ const moved = children.length === 1 ? import_react18.default.cloneElement(children[0], { parentLayout: props.parentLayout, ...look }) : /* @__PURE__ */ import_react18.default.createElement(
72468
72621
  "div",
72469
72622
  {
72470
72623
  ref: this.wrapperRef,
@@ -72477,15 +72630,15 @@ var init_Drag = __esm({
72477
72630
  ...look.style
72478
72631
  }
72479
72632
  },
72480
- children.map((c) => import_react17.default.cloneElement(c, { parentLayout: "column" }))
72633
+ children.map((c) => import_react18.default.cloneElement(c, { parentLayout: "column" }))
72481
72634
  );
72482
- return /* @__PURE__ */ import_react17.default.createElement(
72635
+ return /* @__PURE__ */ import_react18.default.createElement(
72483
72636
  import_react_draggable.default,
72484
72637
  {
72485
72638
  nodeRef: this.draggableNodeRef,
72486
72639
  axis: props.axis,
72487
72640
  bounds,
72488
- disabled: props.enabled === false,
72641
+ disabled: !dragEnabled(props.enabled),
72489
72642
  cancel: DRAG_CANCEL,
72490
72643
  scale: props.scale || 1,
72491
72644
  position: { x: this.state.x, y: this.state.y },
@@ -72651,7 +72804,7 @@ var init_drag = __esm({
72651
72804
  enabled: {
72652
72805
  group: "Drag",
72653
72806
  displayName: "Enabled",
72654
- description: "Lets the user drag this element; when off it still renders and still responds to the Snap actions",
72807
+ description: 'Lets the user drag this element; when off (false, 0, empty or the text "false") it still renders and still responds to the Snap actions',
72655
72808
  type: "boolean",
72656
72809
  default: true
72657
72810
  },
@@ -76620,13 +76773,13 @@ function safely(value2) {
76620
76773
  }
76621
76774
  return safeAlignment ? `safe ${value2}` : value2;
76622
76775
  }
76623
- var import_core, import_mouse_wheel, import_scroll_bar, import_react18, import_patched_momentum_scroll, safeAlignment, Group;
76776
+ var import_core, import_mouse_wheel, import_scroll_bar, import_react19, import_patched_momentum_scroll, safeAlignment, Group;
76624
76777
  var init_Group = __esm({
76625
76778
  "../noodl-viewer-react/src/components/visual/Group/Group.tsx"() {
76626
76779
  import_core = __toESM(require_core3());
76627
76780
  import_mouse_wheel = __toESM(require_mouse_wheel_min());
76628
76781
  import_scroll_bar = __toESM(require_scroll_bar_min());
76629
- import_react18 = __toESM(require_react());
76782
+ import_react19 = __toESM(require_react());
76630
76783
  init_default_style_layer();
76631
76784
  init_layout();
76632
76785
  init_pointerlisteners();
@@ -76637,7 +76790,7 @@ var init_Group = __esm({
76637
76790
  import_core.default.use(nested_scroll_plugin_default);
76638
76791
  import_core.default.use(import_mouse_wheel.default);
76639
76792
  import_core.default.use(slide_scroll_plugin_default);
76640
- Group = class extends import_react18.default.Component {
76793
+ Group = class extends import_react19.default.Component {
76641
76794
  constructor(props) {
76642
76795
  super(props);
76643
76796
  this.state = {};
@@ -76647,7 +76800,7 @@ var init_Group = __esm({
76647
76800
  if (el) el.noodlNode = this.props.noodlNode;
76648
76801
  };
76649
76802
  this.scrollNeedsToInit = false;
76650
- this.scrollRef = import_react18.default.createRef();
76803
+ this.scrollRef = import_react19.default.createRef();
76651
76804
  }
76652
76805
  componentDidMount() {
76653
76806
  if (this.props.scrollEnabled && !this.props.nativeScroll) {
@@ -76842,7 +76995,7 @@ var init_Group = __esm({
76842
76995
  }
76843
76996
  return (
76844
76997
  // `data-ndl-slots`: the cards sit in here, not in the Group's own element — drag-drop.ts counts Drop Index among them (P107-C88)
76845
- /* @__PURE__ */ import_react18.default.createElement("div", { className: "scroll-wrapper-internal", "data-ndl-slots": "", style: childStyle }, this.props.children)
76998
+ /* @__PURE__ */ import_react19.default.createElement("div", { className: "scroll-wrapper-internal", "data-ndl-slots": "", style: childStyle }, this.props.children)
76846
76999
  );
76847
77000
  }
76848
77001
  /**
@@ -76903,7 +77056,7 @@ var init_Group = __esm({
76903
77056
  style2.pointerEvents = "none";
76904
77057
  }
76905
77058
  const defaultsClass = layerDefaults(style2);
76906
- return /* @__PURE__ */ import_react18.default.createElement(
77059
+ return /* @__PURE__ */ import_react19.default.createElement(
76907
77060
  Component,
76908
77061
  {
76909
77062
  className: withDefaultsClass(props.className, defaultsClass),
@@ -77452,24 +77605,24 @@ function Icon(props) {
77452
77605
  if (props.iconSourceType === "image" && props.iconImageSource !== void 0) {
77453
77606
  style3.width = props.iconSize;
77454
77607
  style3.height = props.iconSize;
77455
- return /* @__PURE__ */ import_react19.default.createElement("img", { alt: "", src: props.iconImageSource, style: style3 });
77608
+ return /* @__PURE__ */ import_react20.default.createElement("img", { alt: "", src: props.iconImageSource, style: style3 });
77456
77609
  } else if (props.iconSourceType === "icon" && props.iconIconSource !== void 0) {
77457
77610
  style3.fontSize = props.iconSize;
77458
77611
  style3.color = props.iconColor;
77459
77612
  style3.lineHeight = 1;
77460
- return /* @__PURE__ */ import_react19.default.createElement("div", { style: { lineHeight: 0 } }, /* @__PURE__ */ import_react19.default.createElement(IconGlyph, { source: props.iconIconSource, style: style3 }));
77613
+ return /* @__PURE__ */ import_react20.default.createElement("div", { style: { lineHeight: 0 } }, /* @__PURE__ */ import_react20.default.createElement(IconGlyph, { source: props.iconIconSource, style: style3 }));
77461
77614
  }
77462
77615
  return null;
77463
77616
  }
77464
77617
  let className = "ndl-visual-icon";
77465
77618
  if (props.className) className = className + " " + props.className;
77466
77619
  const defaultsClass = layerDefaults(style2);
77467
- return /* @__PURE__ */ import_react19.default.createElement("div", { ref: noodlRootRef(props.noodlNode), ...dataAttributeProps(props.dom), className: withDefaultsClass(className, defaultsClass), style: style2 }, _renderIcon());
77620
+ return /* @__PURE__ */ import_react20.default.createElement("div", { ref: noodlRootRef(props.noodlNode), ...dataAttributeProps(props.dom), className: withDefaultsClass(className, defaultsClass), style: style2 }, _renderIcon());
77468
77621
  }
77469
- var import_react19;
77622
+ var import_react20;
77470
77623
  var init_Icon = __esm({
77471
77624
  "../noodl-viewer-react/src/components/visual/Icon/Icon.tsx"() {
77472
- import_react19 = __toESM(require_react());
77625
+ import_react20 = __toESM(require_react());
77473
77626
  init_default_style_layer();
77474
77627
  init_layout();
77475
77628
  init_noodl_root_ref();
@@ -77549,7 +77702,7 @@ function Image(props) {
77549
77702
  }
77550
77703
  }
77551
77704
  const defaultsClass = layerDefaults(style2);
77552
- return /* @__PURE__ */ import_react20.default.createElement(
77705
+ return /* @__PURE__ */ import_react21.default.createElement(
77553
77706
  "img",
77554
77707
  {
77555
77708
  ref: noodlRootRef(props.noodlNode),
@@ -77562,10 +77715,10 @@ function Image(props) {
77562
77715
  }
77563
77716
  );
77564
77717
  }
77565
- var import_react20, import_types6;
77718
+ var import_react21, import_types6;
77566
77719
  var init_Image = __esm({
77567
77720
  "../noodl-viewer-react/src/components/visual/Image/Image.tsx"() {
77568
- import_react20 = __toESM(require_react());
77721
+ import_react21 = __toESM(require_react());
77569
77722
  init_default_style_layer();
77570
77723
  init_layout();
77571
77724
  init_pointerlisteners();
@@ -77809,7 +77962,7 @@ function Text(props) {
77809
77962
  style2.pointerEvents = "none";
77810
77963
  }
77811
77964
  const defaultsClass = layerDefaults(style2);
77812
- return /* @__PURE__ */ import_react21.default.createElement(
77965
+ return /* @__PURE__ */ import_react22.default.createElement(
77813
77966
  Component,
77814
77967
  {
77815
77968
  ref: noodlRootRef(props.noodlNode),
@@ -77821,10 +77974,10 @@ function Text(props) {
77821
77974
  renderableText(props.text)
77822
77975
  );
77823
77976
  }
77824
- var import_react21;
77977
+ var import_react22;
77825
77978
  var init_Text = __esm({
77826
77979
  "../noodl-viewer-react/src/components/visual/Text/Text.tsx"() {
77827
- import_react21 = __toESM(require_react());
77980
+ import_react22 = __toESM(require_react());
77828
77981
  init_default_style_layer();
77829
77982
  init_layout();
77830
77983
  init_pointerlisteners();
@@ -78050,6 +78203,9 @@ function seconds(value2) {
78050
78203
  if (!isFinite(n)) return void 0;
78051
78204
  return Math.max(0, n);
78052
78205
  }
78206
+ function startSeconds(startTime) {
78207
+ return seconds(startTime) ?? 0;
78208
+ }
78053
78209
  function withMediaFragment(src, startTime, endTime) {
78054
78210
  if (typeof src !== "string" || src === "") return src;
78055
78211
  const start = seconds(startTime);
@@ -78158,10 +78314,10 @@ var init_video_embed = __esm({
78158
78314
  });
78159
78315
 
78160
78316
  // ../noodl-viewer-react/src/components/visual/Video/Video.tsx
78161
- var import_react22, import_types7, SILENT_PLAY_REJECTIONS, CachedVideo, Video;
78317
+ var import_react23, import_types7, SILENT_PLAY_REJECTIONS, CachedVideo, Video;
78162
78318
  var init_Video = __esm({
78163
78319
  "../noodl-viewer-react/src/components/visual/Video/Video.tsx"() {
78164
- import_react22 = __toESM(require_react());
78320
+ import_react23 = __toESM(require_react());
78165
78321
  init_default_style_layer();
78166
78322
  init_layout();
78167
78323
  init_pointerlisteners();
@@ -78169,7 +78325,7 @@ var init_Video = __esm({
78169
78325
  init_video_embed();
78170
78326
  import_types7 = __toESM(require_types2());
78171
78327
  SILENT_PLAY_REJECTIONS = ["AbortError"];
78172
- CachedVideo = class extends import_react22.default.PureComponent {
78328
+ CachedVideo = class extends import_react23.default.PureComponent {
78173
78329
  componentDidUpdate() {
78174
78330
  if (this.video) {
78175
78331
  this.video.muted = this.props.muted;
@@ -78188,7 +78344,7 @@ var init_Video = __esm({
78188
78344
  src = baseUrl + src.substring(1);
78189
78345
  }
78190
78346
  }
78191
- return /* @__PURE__ */ import_react22.default.createElement(
78347
+ return /* @__PURE__ */ import_react23.default.createElement(
78192
78348
  "video",
78193
78349
  {
78194
78350
  ...videoProps,
@@ -78203,7 +78359,7 @@ var init_Video = __esm({
78203
78359
  );
78204
78360
  }
78205
78361
  };
78206
- Video = class extends import_react22.default.Component {
78362
+ Video = class extends import_react23.default.Component {
78207
78363
  constructor(props) {
78208
78364
  super(props);
78209
78365
  this.wantToPlay = false;
@@ -78262,7 +78418,7 @@ var init_Video = __esm({
78262
78418
  restart() {
78263
78419
  this.wantToPlay = true;
78264
78420
  if (this.canPlay) {
78265
- this.video.currentTime = 0;
78421
+ this.video.currentTime = startSeconds(this.props.dom?.startTime);
78266
78422
  this.startPlayback();
78267
78423
  }
78268
78424
  }
@@ -78273,7 +78429,7 @@ var init_Video = __esm({
78273
78429
  reset() {
78274
78430
  this.wantToPlay = false;
78275
78431
  if (this.video) {
78276
- this.video.currentTime = 0;
78432
+ this.video.currentTime = startSeconds(this.props.dom?.startTime);
78277
78433
  this.video.pause();
78278
78434
  }
78279
78435
  }
@@ -78298,7 +78454,7 @@ var init_Video = __esm({
78298
78454
  muted: props.dom?.muted
78299
78455
  });
78300
78456
  if (embed.kind === "iframe") {
78301
- return /* @__PURE__ */ import_react22.default.createElement(
78457
+ return /* @__PURE__ */ import_react23.default.createElement(
78302
78458
  "iframe",
78303
78459
  {
78304
78460
  className: withDefaultsClass(props.className, defaultsClass),
@@ -78315,7 +78471,7 @@ var init_Video = __esm({
78315
78471
  }
78316
78472
  );
78317
78473
  }
78318
- return /* @__PURE__ */ import_react22.default.createElement(
78474
+ return /* @__PURE__ */ import_react23.default.createElement(
78319
78475
  CachedVideo,
78320
78476
  {
78321
78477
  ...props.dom,
@@ -78420,7 +78576,7 @@ var init_video = __esm({
78420
78576
  type: "signal",
78421
78577
  group: "Video Actions",
78422
78578
  displayName: "Restart",
78423
- description: "Seeks to the beginning and plays, then fires Done",
78579
+ description: "Seeks to Start Time (the beginning when there is none) and plays, then fires Done",
78424
78580
  tooltip: {
78425
78581
  standard: "Restart the video from the beginning"
78426
78582
  },
@@ -78455,7 +78611,7 @@ var init_video = __esm({
78455
78611
  type: "signal",
78456
78612
  group: "Video Actions",
78457
78613
  displayName: "Reset",
78458
- description: "Stops playback and seeks to the beginning",
78614
+ description: "Stops playback and seeks to Start Time (the beginning when there is none)",
78459
78615
  valueChangedToTrue() {
78460
78616
  this.outcomeOnInnerComponent((inner) => inner.reset(), { code: "video/reset-failed" });
78461
78617
  }
@@ -78965,7 +79121,7 @@ var init_utils3 = __esm({
78965
79121
 
78966
79122
  // ../noodl-viewer-react/src/nodes-deprecated/controls/button.tsx
78967
79123
  function Button2(props) {
78968
- (0, import_react23.useEffect)(() => {
79124
+ (0, import_react24.useEffect)(() => {
78969
79125
  props.focusChanged && props.focusChanged(false);
78970
79126
  props.hoverChanged && props.hoverChanged(false);
78971
79127
  props.pressedChanged && props.pressedChanged(false);
@@ -78981,7 +79137,7 @@ function Button2(props) {
78981
79137
  }
78982
79138
  let className = "ndl-controls-button";
78983
79139
  if (props.className) className = className + " " + props.className;
78984
- return /* @__PURE__ */ import_react23.default.createElement(
79140
+ return /* @__PURE__ */ import_react24.default.createElement(
78985
79141
  "button",
78986
79142
  {
78987
79143
  className,
@@ -78995,10 +79151,10 @@ function Button2(props) {
78995
79151
  props.children
78996
79152
  );
78997
79153
  }
78998
- var import_react23, ButtonNode2, definition, button_default2;
79154
+ var import_react24, ButtonNode2, definition, button_default2;
78999
79155
  var init_button2 = __esm({
79000
79156
  "../noodl-viewer-react/src/nodes-deprecated/controls/button.tsx"() {
79001
- import_react23 = __toESM(require_react());
79157
+ import_react24 = __toESM(require_react());
79002
79158
  init_fontloader();
79003
79159
  init_guid();
79004
79160
  init_layout();
@@ -79014,6 +79170,7 @@ var init_button2 = __esm({
79014
79170
  // `displayName`. The picker therefore offered two entries reading the same word, and
79015
79171
  // the one an author was most likely to reach for was this one.
79016
79172
  deprecated: true,
79173
+ replacedBy: "net.noodl.controls.button",
79017
79174
  docs: "https://docs.noodl.net/nodes/visual/button",
79018
79175
  allowChildren: true,
79019
79176
  noodlNodeAsProp: true,
@@ -79396,11 +79553,11 @@ function _styleTemplate3(_class, props) {
79396
79553
  `;
79397
79554
  }
79398
79555
  function CheckBox(props) {
79399
- const [checked, setChecked] = (0, import_react24.useState)(props.checked);
79400
- (0, import_react24.useEffect)(() => {
79556
+ const [checked, setChecked] = (0, import_react25.useState)(props.checked);
79557
+ (0, import_react25.useEffect)(() => {
79401
79558
  setChecked(!!props.checked);
79402
79559
  }, []);
79403
- (0, import_react24.useEffect)(() => {
79560
+ (0, import_react25.useEffect)(() => {
79404
79561
  setChecked(!!props.checked);
79405
79562
  }, [props.checked]);
79406
79563
  const style2 = { ...props.style };
@@ -79417,7 +79574,7 @@ function CheckBox(props) {
79417
79574
  );
79418
79575
  let className = "ndl-controls-checkbox-" + props._nodeId + " ndl-controls-checkbox";
79419
79576
  if (props.className) className = className + " " + props.className;
79420
- return /* @__PURE__ */ import_react24.default.createElement(
79577
+ return /* @__PURE__ */ import_react25.default.createElement(
79421
79578
  "input",
79422
79579
  {
79423
79580
  className,
@@ -79434,10 +79591,10 @@ function CheckBox(props) {
79434
79591
  }
79435
79592
  );
79436
79593
  }
79437
- var import_react24, CheckBoxNode2, checkbox_default2;
79594
+ var import_react25, CheckBoxNode2, checkbox_default2;
79438
79595
  var init_checkbox2 = __esm({
79439
79596
  "../noodl-viewer-react/src/nodes-deprecated/controls/checkbox.tsx"() {
79440
- import_react24 = __toESM(require_react());
79597
+ import_react25 = __toESM(require_react());
79441
79598
  init_guid();
79442
79599
  init_layout();
79443
79600
  init_node_shared_port_definitions();
@@ -79452,6 +79609,7 @@ var init_checkbox2 = __esm({
79452
79609
  // `displayName`. The picker therefore offered two entries reading the same word, and
79453
79610
  // the one an author was most likely to reach for was this one.
79454
79611
  deprecated: true,
79612
+ replacedBy: "net.noodl.controls.checkbox",
79455
79613
  displayName: "Checkbox",
79456
79614
  docs: "https://docs.noodl.net/nodes/visual/checkbox",
79457
79615
  allowChildren: false,
@@ -79711,12 +79869,12 @@ function FieldSet(props) {
79711
79869
  layout_default.align(style2, props);
79712
79870
  let className = "ndl-controls-fieldset";
79713
79871
  if (props.className) className = className + " " + props.className;
79714
- return /* @__PURE__ */ import_react25.default.createElement("fieldset", { className, ...dataAttributeProps(props.dom), style: style2 }, props.children);
79872
+ return /* @__PURE__ */ import_react26.default.createElement("fieldset", { className, ...dataAttributeProps(props.dom), style: style2 }, props.children);
79715
79873
  }
79716
- var import_react25, FieldSetNode, fieldset_default;
79874
+ var import_react26, FieldSetNode, fieldset_default;
79717
79875
  var init_fieldset = __esm({
79718
79876
  "../noodl-viewer-react/src/nodes-deprecated/controls/fieldset.tsx"() {
79719
- import_react25 = __toESM(require_react());
79877
+ import_react26 = __toESM(require_react());
79720
79878
  init_flex();
79721
79879
  init_layout();
79722
79880
  init_node_shared_port_definitions();
@@ -79792,7 +79950,7 @@ function Form(props) {
79792
79950
  layout_default.align(style2, props);
79793
79951
  let className = "ndl-controls-form";
79794
79952
  if (props.className) className = className + " " + props.className;
79795
- return /* @__PURE__ */ import_react26.default.createElement(
79953
+ return /* @__PURE__ */ import_react27.default.createElement(
79796
79954
  "form",
79797
79955
  {
79798
79956
  className,
@@ -79806,10 +79964,10 @@ function Form(props) {
79806
79964
  props.children
79807
79965
  );
79808
79966
  }
79809
- var import_react26, FormNode, form_default;
79967
+ var import_react27, FormNode, form_default;
79810
79968
  var init_form = __esm({
79811
79969
  "../noodl-viewer-react/src/nodes-deprecated/controls/form.tsx"() {
79812
- import_react26 = __toESM(require_react());
79970
+ import_react27 = __toESM(require_react());
79813
79971
  init_flex();
79814
79972
  init_layout();
79815
79973
  init_node_shared_port_definitions();
@@ -79895,12 +80053,12 @@ function Label(props) {
79895
80053
  };
79896
80054
  let className = "ndl-controls-label";
79897
80055
  if (props.className) className = className + " " + props.className;
79898
- return /* @__PURE__ */ import_react27.default.createElement("label", { className, style: style2, ...tagProps, ...dataAttributeProps(props.dom) }, props.text);
80056
+ return /* @__PURE__ */ import_react28.default.createElement("label", { className, style: style2, ...tagProps, ...dataAttributeProps(props.dom) }, props.text);
79899
80057
  }
79900
- var import_react27, LabelNode, label_default;
80058
+ var import_react28, LabelNode, label_default;
79901
80059
  var init_label = __esm({
79902
80060
  "../noodl-viewer-react/src/nodes-deprecated/controls/label.tsx"() {
79903
- import_react27 = __toESM(require_react());
80061
+ import_react28 = __toESM(require_react());
79904
80062
  init_layout();
79905
80063
  init_node_shared_port_definitions();
79906
80064
  init_react_component_node();
@@ -79912,6 +80070,7 @@ var init_label = __esm({
79912
80070
  allowChildren: true,
79913
80071
  noodlNodeAsProp: true,
79914
80072
  deprecated: true,
80073
+ replacedBy: "Text",
79915
80074
  getReactComponent() {
79916
80075
  return Label;
79917
80076
  },
@@ -79937,11 +80096,11 @@ var init_label = __esm({
79937
80096
 
79938
80097
  // ../noodl-viewer-react/src/nodes-deprecated/controls/options.tsx
79939
80098
  function Options(props) {
79940
- const [value2, setValue] = (0, import_react28.useState)(props.value);
79941
- (0, import_react28.useEffect)(() => {
80099
+ const [value2, setValue] = (0, import_react29.useState)(props.value);
80100
+ (0, import_react29.useEffect)(() => {
79942
80101
  setValue(props.value);
79943
80102
  }, []);
79944
- (0, import_react28.useEffect)(() => {
80103
+ (0, import_react29.useEffect)(() => {
79945
80104
  setValue(props.value);
79946
80105
  }, [props.value]);
79947
80106
  let style2 = { ...props.style };
@@ -79957,7 +80116,7 @@ function Options(props) {
79957
80116
  const tagProps = { id: props.id, style: style2, onClick: props.onClick };
79958
80117
  let className = "ndl-controls-select";
79959
80118
  if (props.className) className = className + " " + props.className;
79960
- return /* @__PURE__ */ import_react28.default.createElement(
80119
+ return /* @__PURE__ */ import_react29.default.createElement(
79961
80120
  "select",
79962
80121
  {
79963
80122
  className,
@@ -79974,7 +80133,7 @@ function Options(props) {
79974
80133
  props.valueChanged && props.valueChanged(e.target.value);
79975
80134
  }
79976
80135
  },
79977
- props.items !== void 0 ? props.items.map((i2) => /* @__PURE__ */ import_react28.default.createElement(
80136
+ props.items !== void 0 ? props.items.map((i2) => /* @__PURE__ */ import_react29.default.createElement(
79978
80137
  "option",
79979
80138
  {
79980
80139
  value: i2.Value,
@@ -79985,10 +80144,10 @@ function Options(props) {
79985
80144
  )) : null
79986
80145
  );
79987
80146
  }
79988
- var import_react28, OptionsNode2, definition2, options_default2;
80147
+ var import_react29, OptionsNode2, definition2, options_default2;
79989
80148
  var init_options2 = __esm({
79990
80149
  "../noodl-viewer-react/src/nodes-deprecated/controls/options.tsx"() {
79991
- import_react28 = __toESM(require_react());
80150
+ import_react29 = __toESM(require_react());
79992
80151
  init_fontloader();
79993
80152
  init_guid();
79994
80153
  init_layout();
@@ -80004,6 +80163,7 @@ var init_options2 = __esm({
80004
80163
  // `displayName`. The picker therefore offered two entries reading the same word, and
80005
80164
  // the one an author was most likely to reach for was this one.
80006
80165
  deprecated: true,
80166
+ replacedBy: "net.noodl.controls.options",
80007
80167
  displayName: "Options",
80008
80168
  docs: "https://docs.noodl.net/nodes/visual/options",
80009
80169
  allowChildren: false,
@@ -80335,7 +80495,7 @@ function _styleTemplate4(_class, props) {
80335
80495
  `;
80336
80496
  }
80337
80497
  function RadioButton2(props) {
80338
- const radioButtonGroup = (0, import_react29.useContext)(radiobuttoncontext_default);
80498
+ const radioButtonGroup = (0, import_react30.useContext)(radiobuttoncontext_default);
80339
80499
  const style2 = { ...props.style };
80340
80500
  layout_default.size(style2, props);
80341
80501
  layout_default.align(style2, props);
@@ -80351,7 +80511,7 @@ function RadioButton2(props) {
80351
80511
  );
80352
80512
  let className = "ndl-controls-radiobutton-" + props._nodeId + " ndl-controls-radiobutton";
80353
80513
  if (props.className) className = className + " " + props.className;
80354
- return /* @__PURE__ */ import_react29.default.createElement(
80514
+ return /* @__PURE__ */ import_react30.default.createElement(
80355
80515
  "input",
80356
80516
  {
80357
80517
  className,
@@ -80368,10 +80528,10 @@ function RadioButton2(props) {
80368
80528
  }
80369
80529
  );
80370
80530
  }
80371
- var import_react29, RadioButtonNode2, radiobutton_default2;
80531
+ var import_react30, RadioButtonNode2, radiobutton_default2;
80372
80532
  var init_radiobutton2 = __esm({
80373
80533
  "../noodl-viewer-react/src/nodes-deprecated/controls/radiobutton.tsx"() {
80374
- import_react29 = __toESM(require_react());
80534
+ import_react30 = __toESM(require_react());
80375
80535
  init_radiobuttoncontext();
80376
80536
  init_guid();
80377
80537
  init_layout();
@@ -80387,6 +80547,7 @@ var init_radiobutton2 = __esm({
80387
80547
  // `displayName`. The picker therefore offered two entries reading the same word, and
80388
80548
  // the one an author was most likely to reach for was this one.
80389
80549
  deprecated: true,
80550
+ replacedBy: "net.noodl.controls.radiobutton",
80390
80551
  displayName: "Radio Button",
80391
80552
  docs: "https://docs.noodl.net/nodes/visual/radiobutton",
80392
80553
  allowChildren: false,
@@ -80692,11 +80853,11 @@ function _styleTemplate5(_class, props) {
80692
80853
  `;
80693
80854
  }
80694
80855
  function Range(props) {
80695
- const [value2, setValue] = (0, import_react30.useState)(props.value);
80696
- (0, import_react30.useEffect)(() => {
80856
+ const [value2, setValue] = (0, import_react31.useState)(props.value);
80857
+ (0, import_react31.useEffect)(() => {
80697
80858
  setValue(props.value);
80698
80859
  }, []);
80699
- (0, import_react30.useEffect)(() => {
80860
+ (0, import_react31.useEffect)(() => {
80700
80861
  setValue(props.value);
80701
80862
  }, [props.value]);
80702
80863
  const style2 = { ...props.style };
@@ -80706,7 +80867,7 @@ function Range(props) {
80706
80867
  utils_default2.updateStylesForClass("ndl-controls-range-" + props._nodeId, props, _styleTemplate5);
80707
80868
  let className = "ndl-controls-range-" + props._nodeId + " ndl-controls-range";
80708
80869
  if (props.className) className = className + " " + props.className;
80709
- return /* @__PURE__ */ import_react30.default.createElement(
80870
+ return /* @__PURE__ */ import_react31.default.createElement(
80710
80871
  "input",
80711
80872
  {
80712
80873
  className,
@@ -80723,10 +80884,10 @@ function Range(props) {
80723
80884
  }
80724
80885
  );
80725
80886
  }
80726
- var import_react30, RangeNode2, range_default;
80887
+ var import_react31, RangeNode2, range_default;
80727
80888
  var init_range = __esm({
80728
80889
  "../noodl-viewer-react/src/nodes-deprecated/controls/range.tsx"() {
80729
- import_react30 = __toESM(require_react());
80890
+ import_react31 = __toESM(require_react());
80730
80891
  init_guid();
80731
80892
  init_layout();
80732
80893
  init_node_shared_port_definitions();
@@ -80741,6 +80902,7 @@ var init_range = __esm({
80741
80902
  // `displayName`. The picker therefore offered two entries reading the same word, and
80742
80903
  // the one an author was most likely to reach for was this one.
80743
80904
  deprecated: true,
80905
+ replacedBy: "net.noodl.controls.range",
80744
80906
  docs: "https://docs.noodl.net/nodes/visual/range",
80745
80907
  allowChildren: false,
80746
80908
  noodlNodeAsProp: true,
@@ -81002,10 +81164,10 @@ function preventGlobalFocusChange2(e) {
81002
81164
  e.stopPropagation();
81003
81165
  window.removeEventListener("click", preventGlobalFocusChange2, true);
81004
81166
  }
81005
- var import_react31, TextFieldComponent, TextInput2, definition3, text_input_default2;
81167
+ var import_react32, TextFieldComponent, TextInput2, definition3, text_input_default2;
81006
81168
  var init_text_input2 = __esm({
81007
81169
  "../noodl-viewer-react/src/nodes-deprecated/controls/text-input.tsx"() {
81008
- import_react31 = __toESM(require_react());
81170
+ import_react32 = __toESM(require_react());
81009
81171
  init_fontloader();
81010
81172
  init_guid();
81011
81173
  init_layout();
@@ -81013,13 +81175,13 @@ var init_text_input2 = __esm({
81013
81175
  init_react_component_node();
81014
81176
  init_noodl_root_ref();
81015
81177
  init_utils3();
81016
- TextFieldComponent = class extends import_react31.default.Component {
81178
+ TextFieldComponent = class extends import_react32.default.Component {
81017
81179
  constructor(props) {
81018
81180
  super(props);
81019
81181
  this.state = {
81020
81182
  value: props.startValue
81021
81183
  };
81022
- this.ref = import_react31.default.createRef();
81184
+ this.ref = import_react32.default.createRef();
81023
81185
  }
81024
81186
  setText(value2) {
81025
81187
  this.setState({ value: value2 });
@@ -81049,7 +81211,7 @@ var init_text_input2 = __esm({
81049
81211
  onChange: (e) => this.onChange(e)
81050
81212
  };
81051
81213
  if (this.props.type !== "textArea") {
81052
- return /* @__PURE__ */ import_react31.default.createElement(
81214
+ return /* @__PURE__ */ import_react32.default.createElement(
81053
81215
  "input",
81054
81216
  {
81055
81217
  ref: this.ref,
@@ -81061,7 +81223,7 @@ var init_text_input2 = __esm({
81061
81223
  );
81062
81224
  } else {
81063
81225
  sharedProps.style.resize = "none";
81064
- return /* @__PURE__ */ import_react31.default.createElement(
81226
+ return /* @__PURE__ */ import_react32.default.createElement(
81065
81227
  "textarea",
81066
81228
  {
81067
81229
  ref: this.ref,
@@ -81095,6 +81257,7 @@ var init_text_input2 = __esm({
81095
81257
  // `displayName`. The picker therefore offered two entries reading the same word, and
81096
81258
  // the one an author was most likely to reach for was this one.
81097
81259
  deprecated: true,
81260
+ replacedBy: "net.noodl.controls.textinput",
81098
81261
  docs: "https://docs.noodl.net/nodes/visual/text-input",
81099
81262
  allowChildren: false,
81100
81263
  noodlNodeAsProp: true,
@@ -82372,9 +82535,14 @@ function _typename(type) {
82372
82535
  if (typeof type === "string") return type;
82373
82536
  else return type.name;
82374
82537
  }
82538
+ function _isSignalPort(node, plug, name2) {
82539
+ const modelPort = (plug === "input" ? node.model.inputPorts : node.model.outputPorts)[name2];
82540
+ const type = modelPort !== void 0 ? modelPort.type : node._internal.codePorts[plug][name2];
82541
+ return type !== void 0 && _typename(type) === "signal";
82542
+ }
82375
82543
  function userInputSetter(name2, value2) {
82376
82544
  if (this._internal.hasParsedCode === true) {
82377
- if (this.model.inputPorts[name2] !== void 0 && _typename(this.model.inputPorts[name2].type) === "signal") {
82545
+ if (_isSignalPort(this, "input", name2)) {
82378
82546
  if (this._internal.definedObject && typeof this._internal.definedObject[name2] === "function") {
82379
82547
  if (value2) scheduleSignal.call(this, name2);
82380
82548
  }
@@ -82462,6 +82630,7 @@ var init_javascript = __esm({
82462
82630
  internal2.destroyFunction = void 0;
82463
82631
  internal2.setupFunction = void 0;
82464
82632
  internal2.hasParsedCode = false;
82633
+ internal2.codePorts = { input: {}, output: {} };
82465
82634
  internal2.changedInputs = {};
82466
82635
  internal2.signalScheduled = {};
82467
82636
  internal2.killed = false;
@@ -82659,7 +82828,13 @@ var init_javascript = __esm({
82659
82828
  }
82660
82829
  }
82661
82830
  });
82662
- Object.keys(this.model.outputPorts).forEach((name2) => {
82831
+ const codePorts = { input: {}, output: {} };
82832
+ for (const p of parser.getPorts()) {
82833
+ if ((p.plug === "input" || p.plug === "output") && p.type !== void 0) codePorts[p.plug][p.name] = p.type;
82834
+ }
82835
+ this._internal.codePorts = codePorts;
82836
+ const codeSignals = Object.keys(codePorts.output).filter((name2) => _typename(codePorts.output[name2]) === "signal");
82837
+ (/* @__PURE__ */ new Set([...Object.keys(this.model.outputPorts), ...codeSignals])).forEach((name2) => {
82663
82838
  this.registerOutputIfNeeded(name2);
82664
82839
  });
82665
82840
  this._internal.setupFunction = parser.setup;
@@ -82696,15 +82871,15 @@ var init_javascript = __esm({
82696
82871
  return;
82697
82872
  }
82698
82873
  const self2 = this;
82699
- const isSignal = _typename(this.model.outputPorts[name2].type) === "signal";
82874
+ const isSignal = () => _isSignalPort(self2, "output", name2);
82700
82875
  Object.defineProperty(this._internal.outputProperties, name2, {
82701
82876
  set: function(value2) {
82702
- if (isSignal) return;
82877
+ if (isSignal()) return;
82703
82878
  self2._internal.outputValues[name2] = value2;
82704
82879
  self2.flagOutputDirty(name2);
82705
82880
  },
82706
82881
  get: function() {
82707
- if (isSignal)
82882
+ if (isSignal())
82708
82883
  return () => {
82709
82884
  if (self2.hasOutput(name2)) self2.sendSignalOnOutput(name2);
82710
82885
  };
@@ -82830,6 +83005,10 @@ var init_javascript = __esm({
82830
83005
  }
82831
83006
  ];
82832
83007
  const _outputTypeEnums = [
83008
+ {
83009
+ value: "*",
83010
+ label: "Any"
83011
+ },
82833
83012
  {
82834
83013
  value: "string",
82835
83014
  label: "String"
@@ -82868,7 +83047,7 @@ var init_javascript = __esm({
82868
83047
  enums: _outputTypeEnums,
82869
83048
  allowEditOnly: true
82870
83049
  },
82871
- default: "string",
83050
+ default: "*",
82872
83051
  parent: "scriptOutputs",
82873
83052
  parentItemId: p.id
82874
83053
  });
@@ -89334,7 +89513,7 @@ function updatePorts6(nodeId, _parameters, editorConnection, systemCollections)
89334
89513
  const c = systemCollections.find((c2) => c2.name === "_User");
89335
89514
  if (c && c.schema && c.schema.properties) {
89336
89515
  const props = c.schema.properties;
89337
- const _ignoreKeys = ["authData", "password", "username", "createdAt", "updatedAt", "emailVerified", "email"];
89516
+ const _ignoreKeys = ["authData", "password", "username", "createdAt", "updatedAt", "emailVerified", "email", "ACL"];
89338
89517
  for (const key in props) {
89339
89518
  if (_ignoreKeys.indexOf(key) !== -1) continue;
89340
89519
  const p = props[key];
@@ -90735,6 +90914,7 @@ var init_cloudfunction = __esm({
90735
90914
  usePortAsLabel: "functionName",
90736
90915
  docs: "https://docs.noodl.net/nodes/data/cloud-data/cloud-function",
90737
90916
  deprecated: true,
90917
+ replacedBy: "CloudFunction2",
90738
90918
  initialize: function() {
90739
90919
  this._internal.paramsValues = {};
90740
90920
  },
@@ -91012,6 +91192,7 @@ var init_componentstate = __esm({
91012
91192
  color: "component",
91013
91193
  docs: "https://docs.noodl.net/nodes/component-utilities/component-object",
91014
91194
  deprecated: true,
91195
+ replacedBy: "net.noodl.ComponentObject",
91015
91196
  initialize: function() {
91016
91197
  this._internal.inputValues = {};
91017
91198
  this._internal.onModelChangedCallback = (args) => {
@@ -91224,6 +91405,7 @@ var init_parentcomponentstate = __esm({
91224
91405
  color: "component",
91225
91406
  docs: "https://docs.noodl.net/nodes/component-utilities/parent-component-object",
91226
91407
  deprecated: true,
91408
+ replacedBy: "net.noodl.ParentComponentObject",
91227
91409
  initialize() {
91228
91410
  this._internal.inputValues = {};
91229
91411
  this._internal.onModelChangedCallback = (args) => {
@@ -91497,6 +91679,7 @@ var init_modelnode = __esm({
91497
91679
  color: "data",
91498
91680
  deprecated: true,
91499
91681
  // Use new model node
91682
+ replacedBy: "Model2",
91500
91683
  initialize: function() {
91501
91684
  const internal2 = this._internal;
91502
91685
  internal2.inputValues = {};
@@ -91749,6 +91932,7 @@ var init_variablenode = __esm({
91749
91932
  color: "data",
91750
91933
  deprecated: true,
91751
91934
  // use newvariable instead
91935
+ replacedBy: "Variable2",
91752
91936
  initialize: function() {
91753
91937
  const _this = this;
91754
91938
  const internal2 = this._internal;
@@ -93928,6 +94112,7 @@ var init_dbmodelnode = __esm({
93928
94112
  color: "data",
93929
94113
  deprecated: true,
93930
94114
  // Use record node
94115
+ replacedBy: "DbModel2",
93931
94116
  initialize: function() {
93932
94117
  const internal2 = this._internal;
93933
94118
  internal2.inputValues = {};
@@ -94792,6 +94977,7 @@ var init_dbcollectionnode = __esm({
94792
94977
  color: "data",
94793
94978
  deprecated: true,
94794
94979
  // Use Query Records
94980
+ replacedBy: "DbCollection2",
94795
94981
  initialize: function() {
94796
94982
  const _this = this;
94797
94983
  let collectionChangedScheduled = false;
@@ -95153,6 +95339,7 @@ var init_collectionnode = __esm({
95153
95339
  color: "data",
95154
95340
  deprecated: true,
95155
95341
  // Use new array node
95342
+ replacedBy: "Collection2",
95156
95343
  initialize: function() {
95157
95344
  const _this = this;
95158
95345
  let collectionChangedScheduled = false;