@wildwinter/app-shell 0.46.4 → 0.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/LICENSES.md +5 -4
  2. package/dist/{chunk-EHR2KBZC.js → chunk-5SQHL4YV.js} +3 -3
  3. package/dist/{chunk-EHR2KBZC.js.map → chunk-5SQHL4YV.js.map} +1 -1
  4. package/dist/{chunk-J6RSONXM.js → chunk-FPXEQKWM.js} +4 -4
  5. package/dist/{chunk-J6RSONXM.js.map → chunk-FPXEQKWM.js.map} +1 -1
  6. package/dist/{chunk-R3NXPHRZ.js → chunk-IFWLNIBR.js} +13 -5
  7. package/dist/chunk-IFWLNIBR.js.map +1 -0
  8. package/dist/{chunk-CUFREPJ5.js → chunk-IK3LWBQL.js} +4 -4
  9. package/dist/{chunk-CUFREPJ5.js.map → chunk-IK3LWBQL.js.map} +1 -1
  10. package/dist/{chunk-WKPKBAXS.js → chunk-NKL6DNBZ.js} +4 -4
  11. package/dist/{chunk-WKPKBAXS.js.map → chunk-NKL6DNBZ.js.map} +1 -1
  12. package/dist/{chunk-UG2P777F.js → chunk-QLVBKME7.js} +34 -6
  13. package/dist/chunk-QLVBKME7.js.map +1 -0
  14. package/dist/{chunk-P6WLAEKZ.js → chunk-QVACRWG7.js} +13 -3
  15. package/dist/chunk-QVACRWG7.js.map +1 -0
  16. package/dist/{chunk-2ECJUTSX.js → chunk-T25WXWPB.js} +3 -2
  17. package/dist/chunk-T25WXWPB.js.map +1 -0
  18. package/dist/{chunk-YRFJLJUH.js → chunk-XR4DRDMA.js} +3 -3
  19. package/dist/{chunk-YRFJLJUH.js.map → chunk-XR4DRDMA.js.map} +1 -1
  20. package/dist/{chunk-G2JT3HZH.js → chunk-XXDJCOXN.js} +9 -9
  21. package/dist/{chunk-G2JT3HZH.js.map → chunk-XXDJCOXN.js.map} +1 -1
  22. package/dist/context-menu.cjs.map +1 -1
  23. package/dist/context-menu.js +2 -2
  24. package/dist/dialog.cjs.map +1 -1
  25. package/dist/dialog.js +2 -2
  26. package/dist/index.cjs +80 -17
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +85 -12
  29. package/dist/index.d.ts +85 -12
  30. package/dist/index.js +34 -20
  31. package/dist/index.js.map +1 -1
  32. package/dist/kit-gallery.cjs.map +1 -1
  33. package/dist/kit-gallery.js +3 -3
  34. package/dist/link-status.cjs +12 -5
  35. package/dist/link-status.cjs.map +1 -1
  36. package/dist/link-status.d.cts +1 -1
  37. package/dist/link-status.d.ts +1 -1
  38. package/dist/link-status.js +3 -3
  39. package/dist/menu.cjs +1 -0
  40. package/dist/menu.cjs.map +1 -1
  41. package/dist/menu.d.cts +8 -4
  42. package/dist/menu.d.ts +8 -4
  43. package/dist/menu.js +1 -1
  44. package/dist/{property-list-D3VZCJzi.d.cts → property-list-5mS4J2uy.d.cts} +8 -2
  45. package/dist/{property-list-D3VZCJzi.d.ts → property-list-5mS4J2uy.d.ts} +8 -2
  46. package/dist/property-list.cjs +10 -2
  47. package/dist/property-list.cjs.map +1 -1
  48. package/dist/property-list.d.cts +1 -1
  49. package/dist/property-list.d.ts +1 -1
  50. package/dist/property-list.js +2 -2
  51. package/dist/settings.css +54 -0
  52. package/dist/settings.css.map +1 -1
  53. package/dist/updater-view.cjs.map +1 -1
  54. package/dist/updater-view.js +3 -3
  55. package/dist/util.cjs +11 -0
  56. package/dist/util.cjs.map +1 -1
  57. package/dist/util.d.cts +18 -1
  58. package/dist/util.d.ts +18 -1
  59. package/dist/util.js +1 -1
  60. package/dist/welcome.cjs.map +1 -1
  61. package/dist/welcome.js +4 -4
  62. package/package.json +1 -1
  63. package/dist/chunk-2ECJUTSX.js.map +0 -1
  64. package/dist/chunk-P6WLAEKZ.js.map +0 -1
  65. package/dist/chunk-R3NXPHRZ.js.map +0 -1
  66. package/dist/chunk-UG2P777F.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -285,11 +285,18 @@ var DRAWN = {
285
285
  viewNode: stroked('<path d="m10.586 5.414-5.172 5.172"/><path d="m18.586 13.414-5.172 5.172"/><path d="M6 12h12"/><circle cx="12" cy="20" r="2"/><circle cx="12" cy="4" r="2"/><circle cx="20" cy="12" r="2"/><circle cx="4" cy="12" r="2"/>'),
286
286
  /** Record: the disc, in whatever colour the button is. (a disc; see DISC_LARGE) */
287
287
  record: DISC_LARGE,
288
+ /** Sound: play with audio. (volume-2: the cone and two waves. Patterpad's
289
+ * hand-drawn one had a single wave, which at 14px reads as quiet rather
290
+ * than as sound.) */
291
+ speaker: stroked('<path d="M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z"/><path d="M16 9a5 5 0 0 1 0 6"/><path d="M19.364 18.364a9 9 0 0 0 0-12.728"/>'),
288
292
  // --- handling -------------------------------------------------------------
289
293
  /** The drag grip on a reorderable row. (grip-vertical) */
290
294
  grip: stroked('<circle cx="9" cy="12" r="1"/><circle cx="9" cy="5" r="1"/><circle cx="9" cy="19" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="15" cy="5" r="1"/><circle cx="15" cy="19" r="1"/>'),
291
295
  /** Add one of whatever this list holds. (plus) */
292
296
  add: stroked('<path d="M5 12h14"/><path d="M12 5v14"/>'),
297
+ /** Copy this to the clipboard. (copy: the front sheet whole, the back
298
+ * sheet showing round two of its sides) */
299
+ copy: stroked('<rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>'),
293
300
  /** Connect: to a server, a live link, a running game. (plug) */
294
301
  connect: stroked('<path d="M12 22v-5"/><path d="M15 8V2"/><path d="M17 8a1 1 0 0 1 1 1v4a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1z"/><path d="M9 8V2"/>'),
295
302
  /** Search. (search) */
@@ -379,15 +386,36 @@ function iconBtn(name, title, onClick, disabled = false, danger = false) {
379
386
  b.addEventListener("click", onClick);
380
387
  return b;
381
388
  }
382
- function labelled(label2, control) {
389
+ function labelled(label2, control, hint) {
383
390
  const target = control.matches("input, select, textarea") ? control : control.querySelector("input:not([type=button]):not([type=submit]), select, textarea");
384
391
  const w = el(target ? "label" : "div", "shell-labelled");
385
392
  w.append(el("span", "shell-fieldcap", label2), control);
386
393
  if (target) {
387
- if (!target.id) target.id = `shell-f-${Math.random().toString(36).slice(2, 9)}`;
394
+ if (!target.id) target.id = uid();
388
395
  w.htmlFor = target.id;
389
396
  }
390
- return w;
397
+ if (hint === void 0) return w;
398
+ const note = el("p", "shell-fieldhint");
399
+ note.append(...Array.isArray(hint) ? hint : [hint]);
400
+ note.id = uid();
401
+ if (target) {
402
+ const by = target.getAttribute("aria-describedby");
403
+ target.setAttribute("aria-describedby", by ? `${by} ${note.id}` : note.id);
404
+ }
405
+ return el("div", "shell-field", w, note);
406
+ }
407
+ var uid = () => `shell-f-${Math.random().toString(36).slice(2, 9)}`;
408
+ function labelledToggle(label2, opts = {}) {
409
+ const input = el("input", "shell-toggle-input");
410
+ input.type = "checkbox";
411
+ input.checked = opts.checked ?? false;
412
+ input.disabled = opts.disabled ?? false;
413
+ const { onChange } = opts;
414
+ if (onChange) input.addEventListener("change", () => onChange(input.checked));
415
+ const row = labelled(label2, input, opts.hint);
416
+ (row.matches(".shell-labelled") ? row : row.querySelector(".shell-labelled"))?.classList.add("shell-toggle");
417
+ if (opts.sub) row.classList.add("shell-suboption");
418
+ return { row, input };
391
419
  }
392
420
  function moveItem(arr, i, delta) {
393
421
  const j = i + delta;
@@ -935,6 +963,7 @@ var FILE_MENU = {
935
963
  projectSettings: { label: "Project Settings\u2026", accelerator: "CmdOrCtrl+," }
936
964
  };
937
965
  var PLAY_MENU = {
966
+ play: { accelerator: "CmdOrCtrl+P" },
938
967
  liveLink: { label: "Live Link" }
939
968
  };
940
969
  var REVIEW_MENU = {
@@ -1197,9 +1226,17 @@ function mountSettingsDialog(opts) {
1197
1226
  error.hidden = false;
1198
1227
  return;
1199
1228
  }
1229
+ save.disabled = true;
1200
1230
  void (async () => {
1201
- await opts.onSave();
1202
- dialog.close("save");
1231
+ let saved;
1232
+ try {
1233
+ saved = await opts.onSave();
1234
+ } catch (err) {
1235
+ saved = false;
1236
+ console.error("Settings save failed:", err);
1237
+ }
1238
+ save.disabled = false;
1239
+ if (saved !== false) dialog.close("save");
1203
1240
  })();
1204
1241
  });
1205
1242
  return {
@@ -1289,6 +1326,16 @@ function relativeTime(date, now = Date.now()) {
1289
1326
  if (days < 7) return `${days} days ago`;
1290
1327
  return new Date(then).toLocaleDateString(void 0, { day: "numeric", month: "short", year: "numeric" });
1291
1328
  }
1329
+ function isLocalOrigin(origin) {
1330
+ if (origin === void 0 || origin === "") return true;
1331
+ let host;
1332
+ try {
1333
+ host = new URL(/^[a-z][a-z0-9+.-]*:\/\//i.test(origin) ? origin : `http://${origin}`).hostname;
1334
+ } catch {
1335
+ return false;
1336
+ }
1337
+ return host === "localhost" || host === "127.0.0.1" || host === "[::1]";
1338
+ }
1292
1339
 
1293
1340
  // src/tool-window-web.ts
1294
1341
  function pinButton(opts) {
@@ -2094,16 +2141,19 @@ var CLASS_LABEL = {
2094
2141
  everyone: "Everyone",
2095
2142
  writing: "Writing",
2096
2143
  vo: "Voice (VO)",
2097
- loc: "Localisers"
2144
+ loc: "Localisers",
2145
+ editor: "Editors"
2098
2146
  };
2099
2147
  var label = (cls) => cls === EDITOR_ONLY ? "Note (editor-only)" : CLASS_LABEL[cls] ?? cls[0].toUpperCase() + cls.slice(1);
2100
2148
  var PLACEHOLDER = {
2101
2149
  vo: "Direction for the voice actor or director",
2102
- loc: "Context for translators"
2150
+ loc: "Context for translators",
2151
+ editor: "Context for an outside editor"
2103
2152
  };
2104
2153
  var placeholder = (cls) => cls === EDITOR_ONLY ? "An internal note, never exported" : PLACEHOLDER[cls] ?? "Why this is here";
2105
2154
  function openNotesEditor(opts) {
2106
2155
  const { notes } = opts;
2156
+ const inherited = notes.inherited ?? [];
2107
2157
  const seed = /* @__PURE__ */ new Map();
2108
2158
  for (const line of notes.own) {
2109
2159
  const key = line.type ?? EDITOR_ONLY;
@@ -2111,6 +2161,8 @@ function openNotesEditor(opts) {
2111
2161
  ${line.text}` : line.text);
2112
2162
  }
2113
2163
  const shown = [...seed.keys()];
2164
+ const focus = opts.focus !== void 0 && (opts.focus === EDITOR_ONLY || notes.classes.includes(opts.focus) || seed.has(opts.focus)) ? opts.focus : void 0;
2165
+ if (focus !== void 0 && !shown.includes(focus)) shown.push(focus);
2114
2166
  if (shown.length === 0) shown.push(notes.classes[0] ?? EDITOR_ONLY);
2115
2167
  const areas = /* @__PURE__ */ new Map();
2116
2168
  const value = () => {
@@ -2128,13 +2180,13 @@ ${line.text}` : line.text);
2128
2180
  const body = el("div", "shell-notes-body");
2129
2181
  const render = () => {
2130
2182
  body.replaceChildren();
2131
- if (notes.inherited.length > 0) {
2183
+ if (inherited.length > 0) {
2132
2184
  const from = el(
2133
2185
  "div",
2134
2186
  { className: "shell-notes-inherited" },
2135
2187
  el("div", "shell-notes-caption", "Inherited")
2136
2188
  );
2137
- for (const level of notes.inherited) {
2189
+ for (const level of inherited) {
2138
2190
  from.append(el(
2139
2191
  "div",
2140
2192
  { className: "shell-notes-level" },
@@ -2191,7 +2243,12 @@ ${line.text}` : line.text);
2191
2243
  const next = value();
2192
2244
  if (JSON.stringify(next) !== before) opts.save(next);
2193
2245
  };
2194
- const frame = dialogFrame({ title: `Notes: ${opts.subject}`, className: "shell-notes", onClose: commit });
2246
+ const frame = dialogFrame({
2247
+ title: opts.subject !== void 0 ? `Notes: ${opts.subject}` : "Notes",
2248
+ ...opts.sub !== void 0 ? { sub: opts.sub } : {},
2249
+ className: "shell-notes",
2250
+ onClose: commit
2251
+ });
2195
2252
  frame.body.append(body);
2196
2253
  frame.actions.append(done);
2197
2254
  done.addEventListener("click", () => {
@@ -2199,7 +2256,7 @@ ${line.text}` : line.text);
2199
2256
  frame.close();
2200
2257
  });
2201
2258
  frame.open();
2202
- areas.get(shown[0] ?? EDITOR_ONLY)?.focus();
2259
+ areas.get(focus ?? shown[0] ?? EDITOR_ONLY)?.focus();
2203
2260
  }
2204
2261
 
2205
2262
  // src/comments.ts
@@ -2532,7 +2589,7 @@ function staleBar(opts) {
2532
2589
  { className: "stale-bar" },
2533
2590
  el("span", {
2534
2591
  className: "stale-bar-msg",
2535
- text: `${opts.subject} changed in the editor. ${opts.advice ?? "Restart to play the new version."}`
2592
+ text: `${opts.message ?? `${opts.subject} changed in the editor.`} ${opts.advice ?? "Restart to play the new version."}`
2536
2593
  }),
2537
2594
  // The icon is a node beside the word, not a character inside it; the
2538
2595
  // button's flex gap sets the space (stale.css).
@@ -2934,16 +2991,16 @@ function linkStatusClass(s) {
2934
2991
  function linkStatusTip(s) {
2935
2992
  switch (s.state) {
2936
2993
  case "off":
2937
- return "Live link is off. Click to start listening.";
2994
+ return "Live Link is off. Click to start listening.";
2938
2995
  case "error":
2939
- return `Live link failed (${s.message}). Click to retry.`;
2996
+ return `Live Link failed (${s.message}). Click to retry.`;
2940
2997
  case "listening":
2941
- return "Live link is listening for a game. Click to stop.";
2998
+ return "Live Link is listening for a game. Click to stop.";
2942
2999
  case "connected": {
2943
3000
  const who = s.project !== void 0 ? ` to ${s.project}` : "";
2944
3001
  const build = s.build === "stale" ? " on a different build, so save or rebuild to re-sync" : s.build === "match" ? " and in sync" : "";
2945
3002
  const note = s.note ? ` ${s.note}` : "";
2946
- return `Live link is connected${who}${build}.${note} Click to stop.`;
3003
+ return `Live Link is connected${who}${build}.${note} Click to stop.`;
2947
3004
  }
2948
3005
  }
2949
3006
  }
@@ -2983,7 +3040,7 @@ function mountLinkStatus(host, opts) {
2983
3040
  const addr = linkAddress(status);
2984
3041
  if (addr !== void 0) {
2985
3042
  url.textContent = addr;
2986
- url.dataset["tip"] = "Click to copy the live link address";
3043
+ url.dataset["tip"] = "Click to copy the Live Link address";
2987
3044
  url.hidden = false;
2988
3045
  } else url.hidden = true;
2989
3046
  publishReserve();
@@ -3212,6 +3269,10 @@ function createNavHistory(opts) {
3212
3269
  },
3213
3270
  canForward() {
3214
3271
  return ahead.length > 0;
3272
+ },
3273
+ clear() {
3274
+ past = [];
3275
+ ahead = [];
3215
3276
  }
3216
3277
  };
3217
3278
  }
@@ -3299,6 +3360,7 @@ exports.isCaseOnlyPropertyName = isCaseOnlyPropertyName;
3299
3360
  exports.isEditableTarget = isEditableTarget;
3300
3361
  exports.isIconName = isIconName;
3301
3362
  exports.isKeyCombo = isKeyCombo;
3363
+ exports.isLocalOrigin = isLocalOrigin;
3302
3364
  exports.isValidGameId = isValidGameId;
3303
3365
  exports.isValidPropertyName = isValidPropertyName;
3304
3366
  exports.keyHint = keyHint;
@@ -3307,6 +3369,7 @@ exports.keyLegends = keyLegends;
3307
3369
  exports.keyPlatform = keyPlatform;
3308
3370
  exports.kitTile = kitTile;
3309
3371
  exports.labelled = labelled;
3372
+ exports.labelledToggle = labelledToggle;
3310
3373
  exports.linkAddress = linkAddress;
3311
3374
  exports.linkStatusClass = linkStatusClass;
3312
3375
  exports.linkStatusTip = linkStatusTip;