@wildwinter/app-shell 0.37.0 → 0.39.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 (144) hide show
  1. package/LICENSES.md +62 -0
  2. package/README.md +21 -0
  3. package/dist/about.css +13 -34
  4. package/dist/about.css.map +1 -1
  5. package/dist/anchored.css +5 -5
  6. package/dist/anchored.css.map +1 -1
  7. package/dist/app-store.cjs +15 -0
  8. package/dist/app-store.cjs.map +1 -1
  9. package/dist/app-store.d.cts +25 -1
  10. package/dist/app-store.d.ts +25 -1
  11. package/dist/app-store.js +14 -1
  12. package/dist/app-store.js.map +1 -1
  13. package/dist/chunk-2ECJUTSX.js +97 -0
  14. package/dist/chunk-2ECJUTSX.js.map +1 -0
  15. package/dist/chunk-2NMVIM54.js +55 -0
  16. package/dist/chunk-2NMVIM54.js.map +1 -0
  17. package/dist/chunk-C6UVQYKI.js +70 -0
  18. package/dist/chunk-C6UVQYKI.js.map +1 -0
  19. package/dist/chunk-IU7EY6BI.js +26 -0
  20. package/dist/chunk-IU7EY6BI.js.map +1 -0
  21. package/dist/chunk-K2AOLQW4.js +82 -0
  22. package/dist/chunk-K2AOLQW4.js.map +1 -0
  23. package/dist/chunk-KGAMP5LW.js +87 -0
  24. package/dist/chunk-KGAMP5LW.js.map +1 -0
  25. package/dist/chunk-L5HOBEKL.js +534 -0
  26. package/dist/chunk-L5HOBEKL.js.map +1 -0
  27. package/dist/chunk-P4G4ERG6.js +60 -0
  28. package/dist/chunk-P4G4ERG6.js.map +1 -0
  29. package/dist/chunk-P6WLAEKZ.js +71 -0
  30. package/dist/chunk-P6WLAEKZ.js.map +1 -0
  31. package/dist/chunk-S4KWQLYN.js +66 -0
  32. package/dist/chunk-S4KWQLYN.js.map +1 -0
  33. package/dist/chunk-XZYZXY7I.js +554 -0
  34. package/dist/chunk-XZYZXY7I.js.map +1 -0
  35. package/dist/comments.css +5 -3
  36. package/dist/comments.css.map +1 -1
  37. package/dist/confirm.css +1 -54
  38. package/dist/confirm.css.map +1 -1
  39. package/dist/context-menu.cjs +250 -0
  40. package/dist/context-menu.cjs.map +1 -0
  41. package/dist/context-menu.css +64 -0
  42. package/dist/context-menu.css.map +1 -0
  43. package/dist/context-menu.d.cts +25 -0
  44. package/dist/context-menu.d.ts +25 -0
  45. package/dist/context-menu.js +5 -0
  46. package/dist/context-menu.js.map +1 -0
  47. package/dist/controls.css +155 -0
  48. package/dist/controls.css.map +1 -0
  49. package/dist/dialog.cjs +222 -0
  50. package/dist/dialog.cjs.map +1 -0
  51. package/dist/dialog.css +55 -0
  52. package/dist/dialog.css.map +1 -0
  53. package/dist/dialog.d.cts +28 -0
  54. package/dist/dialog.d.ts +28 -0
  55. package/dist/dialog.js +5 -0
  56. package/dist/dialog.js.map +1 -0
  57. package/dist/floating.cjs +83 -0
  58. package/dist/floating.cjs.map +1 -0
  59. package/dist/floating.d.cts +25 -0
  60. package/dist/floating.d.ts +25 -0
  61. package/dist/floating.js +4 -0
  62. package/dist/floating.js.map +1 -0
  63. package/dist/identity.css +15 -50
  64. package/dist/identity.css.map +1 -1
  65. package/dist/index.cjs +1322 -258
  66. package/dist/index.cjs.map +1 -1
  67. package/dist/index.d.cts +349 -131
  68. package/dist/index.d.ts +349 -131
  69. package/dist/index.js +259 -808
  70. package/dist/index.js.map +1 -1
  71. package/dist/job.css +23 -0
  72. package/dist/job.css.map +1 -1
  73. package/dist/link-status.cjs +430 -0
  74. package/dist/link-status.cjs.map +1 -0
  75. package/dist/link-status.css +76 -0
  76. package/dist/link-status.css.map +1 -0
  77. package/dist/link-status.d.cts +53 -0
  78. package/dist/link-status.d.ts +53 -0
  79. package/dist/link-status.js +5 -0
  80. package/dist/link-status.js.map +1 -0
  81. package/dist/menu.cjs +62 -1
  82. package/dist/menu.cjs.map +1 -1
  83. package/dist/menu.d.cts +88 -1
  84. package/dist/menu.d.ts +88 -1
  85. package/dist/menu.js +1 -1
  86. package/dist/notes-editor.css +3 -46
  87. package/dist/notes-editor.css.map +1 -1
  88. package/dist/pane-shell.css +16 -3
  89. package/dist/pane-shell.css.map +1 -1
  90. package/dist/property-list-D3VZCJzi.d.cts +162 -0
  91. package/dist/property-list-D3VZCJzi.d.ts +162 -0
  92. package/dist/property-list.cjs +784 -0
  93. package/dist/property-list.cjs.map +1 -0
  94. package/dist/property-list.d.cts +1 -0
  95. package/dist/property-list.d.ts +1 -0
  96. package/dist/property-list.js +4 -0
  97. package/dist/property-list.js.map +1 -0
  98. package/dist/settings.css +63 -8
  99. package/dist/settings.css.map +1 -1
  100. package/dist/stale.css +3 -0
  101. package/dist/stale.css.map +1 -1
  102. package/dist/stepper.css +35 -0
  103. package/dist/stepper.css.map +1 -1
  104. package/dist/tokens.css +19 -0
  105. package/dist/tokens.css.map +1 -1
  106. package/dist/tool-window.cjs +63 -0
  107. package/dist/tool-window.cjs.map +1 -1
  108. package/dist/tool-window.css +6 -3
  109. package/dist/tool-window.css.map +1 -1
  110. package/dist/tool-window.d.cts +67 -1
  111. package/dist/tool-window.d.ts +67 -1
  112. package/dist/tool-window.js +63 -1
  113. package/dist/tool-window.js.map +1 -1
  114. package/dist/updater-view.cjs +283 -0
  115. package/dist/updater-view.cjs.map +1 -0
  116. package/dist/updater-view.d.cts +23 -0
  117. package/dist/updater-view.d.ts +23 -0
  118. package/dist/updater-view.js +6 -0
  119. package/dist/updater-view.js.map +1 -0
  120. package/dist/updater.cjs +12 -16
  121. package/dist/updater.cjs.map +1 -1
  122. package/dist/updater.css +44 -0
  123. package/dist/updater.css.map +1 -0
  124. package/dist/updater.js +12 -16
  125. package/dist/updater.js.map +1 -1
  126. package/dist/util.cjs +78 -0
  127. package/dist/util.cjs.map +1 -0
  128. package/dist/util.d.cts +37 -0
  129. package/dist/util.d.ts +37 -0
  130. package/dist/util.js +3 -0
  131. package/dist/util.js.map +1 -0
  132. package/dist/vc.css +3 -2
  133. package/dist/vc.css.map +1 -1
  134. package/dist/welcome.cjs +215 -0
  135. package/dist/welcome.cjs.map +1 -0
  136. package/dist/welcome.css +112 -0
  137. package/dist/welcome.css.map +1 -0
  138. package/dist/welcome.d.cts +55 -0
  139. package/dist/welcome.d.ts +55 -0
  140. package/dist/welcome.js +4 -0
  141. package/dist/welcome.js.map +1 -0
  142. package/package.json +58 -2
  143. package/dist/chunk-QDPFU4WX.js +0 -43
  144. package/dist/chunk-QDPFU4WX.js.map +0 -1
package/dist/job.css CHANGED
@@ -36,11 +36,34 @@
36
36
  transition: none;
37
37
  }
38
38
  }
39
+ .job-strip.indeterminate .job-fill {
40
+ width: 25%;
41
+ transition: none;
42
+ animation: var(--anim-job-band, none);
43
+ }
44
+ @keyframes job-band {
45
+ from {
46
+ transform: translateX(-100%);
47
+ }
48
+ to {
49
+ transform: translateX(400%);
50
+ }
51
+ }
52
+ @media (prefers-reduced-motion: reduce) {
53
+ .job-strip.indeterminate .job-fill {
54
+ width: 100%;
55
+ opacity: 0.35;
56
+ }
57
+ }
39
58
  .job-count,
40
59
  .job-time {
41
60
  flex: none;
42
61
  font-variant-numeric: tabular-nums;
43
62
  }
63
+ .job-count[hidden],
64
+ .job-cancel[hidden] {
65
+ display: none;
66
+ }
44
67
  .job-time {
45
68
  opacity: 0.8;
46
69
  }
package/dist/job.css.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/job.css"],"sourcesContent":["/* The long-job progress strip. Consumes the app's tokens only, so it wears\n whichever palette the host is in. Quiet: it is a status line, not an alarm. */\n\n.job-strip {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 7px 18px;\n border-bottom: 1px solid var(--line-soft, var(--line));\n background: var(--surface);\n font-size: 0.8rem;\n color: var(--muted);\n}\n.job-strip[hidden] { display: none; }\n\n.job-label { flex: none; }\n\n.job-bar {\n flex: 1;\n min-width: 80px;\n height: 6px;\n background: var(--line-soft, var(--line));\n border-radius: var(--radius-pill, 999px);\n overflow: hidden;\n}\n.job-fill {\n display: block;\n height: 100%;\n width: 0;\n background: var(--accent);\n border-radius: var(--radius-pill, 999px);\n transition: width var(--dur-quick, 120ms) linear;\n}\n@media (prefers-reduced-motion: reduce) {\n .job-fill { transition: none; }\n}\n\n.job-count,\n.job-time {\n flex: none;\n font-variant-numeric: tabular-nums;\n}\n.job-time { opacity: 0.8; }\n\n.job-cancel {\n flex: none;\n font: inherit;\n color: var(--muted);\n background: none;\n border: 1px solid var(--line);\n border-radius: var(--radius-sm, 4px);\n padding: 3px 10px;\n cursor: pointer;\n}\n.job-cancel:hover:not(:disabled) { color: var(--danger); border-color: var(--danger); background: none; }\n.job-cancel:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }\n.job-cancel:disabled { opacity: 0.6; cursor: default; }\n"],"mappings":";AAGA,CAAC;AACC,WAAS;AACT,eAAa;AACb,OAAK;AACL,WAAS,IAAI;AACb,iBAAe,IAAI,MAAM,IAAI,WAAW,EAAE,IAAI;AAC9C,cAAY,IAAI;AAChB,aAAW;AACX,SAAO,IAAI;AACb;AACA,CAVC,SAUS,CAAC;AAAU,WAAS;AAAM;AAEpC,CAAC;AAAY,QAAM;AAAM;AAEzB,CAAC;AACC,QAAM;AACN,aAAW;AACX,UAAQ;AACR,cAAY,IAAI,WAAW,EAAE,IAAI;AACjC,iBAAe,IAAI,aAAa,EAAE;AAClC,YAAU;AACZ;AACA,CAAC;AACC,WAAS;AACT,UAAQ;AACR,SAAO;AACP,cAAY,IAAI;AAChB,iBAAe,IAAI,aAAa,EAAE;AAClC,cAAY,MAAM,IAAI,WAAW,EAAE,OAAO;AAC5C;AACA,QAAO,wBAAyB;AAC9B,GATD;AASa,gBAAY;AAAM;AAChC;AAEA,CAAC;AACD,CAAC;AACC,QAAM;AACN,wBAAsB;AACxB;AACA,CAJC;AAIW,WAAS;AAAK;AAE1B,CAAC;AACC,QAAM;AACN,QAAM;AACN,SAAO,IAAI;AACX,cAAY;AACZ,UAAQ,IAAI,MAAM,IAAI;AACtB,iBAAe,IAAI,WAAW,EAAE;AAChC,WAAS,IAAI;AACb,UAAQ;AACV;AACA,CAVC,UAUU,MAAM,KAAK;AAAa,SAAO,IAAI;AAAW,gBAAc,IAAI;AAAW,cAAY;AAAM;AACxG,CAXC,UAWU;AAAiB,WAAS,IAAI,MAAM,IAAI;AAAW,kBAAgB;AAAK;AACnF,CAZC,UAYU;AAAY,WAAS;AAAK,UAAQ;AAAS;","names":[]}
1
+ {"version":3,"sources":["../src/job.css"],"sourcesContent":["/* The long-job progress strip. Consumes the app's tokens only, so it wears\n whichever palette the host is in. Quiet: it is a status line, not an alarm. */\n\n.job-strip {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 7px 18px;\n border-bottom: 1px solid var(--line-soft, var(--line));\n background: var(--surface);\n font-size: 0.8rem;\n color: var(--muted);\n}\n.job-strip[hidden] { display: none; }\n\n.job-label { flex: none; }\n\n.job-bar {\n flex: 1;\n min-width: 80px;\n height: 6px;\n background: var(--line-soft, var(--line));\n border-radius: var(--radius-pill, 999px);\n overflow: hidden;\n}\n.job-fill {\n display: block;\n height: 100%;\n width: 0;\n background: var(--accent);\n border-radius: var(--radius-pill, 999px);\n transition: width var(--dur-quick, 120ms) linear;\n}\n@media (prefers-reduced-motion: reduce) {\n .job-fill { transition: none; }\n}\n\n/* The indeterminate band: a job that has not said how big it is (total 0, the\n host's \"no idea yet\") or one that never will (a publish, a pull). A quarter\n of the bar sweeps left to right on the family's motion token; the count is\n hidden by the view. Under reduced motion the token is `none`, and the band\n would otherwise sit still at a quarter and read as stuck, so it becomes a\n full, translucent bar: \"busy\", said without movement. */\n.job-strip.indeterminate .job-fill {\n width: 25%;\n transition: none;\n animation: var(--anim-job-band, none);\n}\n@keyframes job-band {\n from { transform: translateX(-100%); }\n to { transform: translateX(400%); }\n}\n@media (prefers-reduced-motion: reduce) {\n .job-strip.indeterminate .job-fill { width: 100%; opacity: 0.35; }\n}\n\n.job-count,\n.job-time {\n flex: none;\n font-variant-numeric: tabular-nums;\n}\n.job-count[hidden],\n.job-cancel[hidden] { display: none; }\n.job-time { opacity: 0.8; }\n\n.job-cancel {\n flex: none;\n font: inherit;\n color: var(--muted);\n background: none;\n border: 1px solid var(--line);\n border-radius: var(--radius-sm, 4px);\n padding: 3px 10px;\n cursor: pointer;\n}\n.job-cancel:hover:not(:disabled) { color: var(--danger); border-color: var(--danger); background: none; }\n.job-cancel:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }\n.job-cancel:disabled { opacity: 0.6; cursor: default; }\n"],"mappings":";AAGA,CAAC;AACC,WAAS;AACT,eAAa;AACb,OAAK;AACL,WAAS,IAAI;AACb,iBAAe,IAAI,MAAM,IAAI,WAAW,EAAE,IAAI;AAC9C,cAAY,IAAI;AAChB,aAAW;AACX,SAAO,IAAI;AACb;AACA,CAVC,SAUS,CAAC;AAAU,WAAS;AAAM;AAEpC,CAAC;AAAY,QAAM;AAAM;AAEzB,CAAC;AACC,QAAM;AACN,aAAW;AACX,UAAQ;AACR,cAAY,IAAI,WAAW,EAAE,IAAI;AACjC,iBAAe,IAAI,aAAa,EAAE;AAClC,YAAU;AACZ;AACA,CAAC;AACC,WAAS;AACT,UAAQ;AACR,SAAO;AACP,cAAY,IAAI;AAChB,iBAAe,IAAI,aAAa,EAAE;AAClC,cAAY,MAAM,IAAI,WAAW,EAAE,OAAO;AAC5C;AACA,QAAO,wBAAyB;AAC9B,GATD;AASa,gBAAY;AAAM;AAChC;AAQA,CAxCC,SAwCS,CAAC,cAAc,CAlBxB;AAmBC,SAAO;AACP,cAAY;AACZ,aAAW,IAAI,eAAe,EAAE;AAClC;AACA,WAAW;AACT;AAAO,eAAW,WAAW;AAAQ;AACrC;AAAK,eAAW,WAAW;AAAO;AACpC;AACA,QAAO,wBAAyB;AAC9B,GAlDD,SAkDW,CAVD,cAUgB,CA5B1B;AA4BsC,WAAO;AAAM,aAAS;AAAM;AACnE;AAEA,CAAC;AACD,CAAC;AACC,QAAM;AACN,wBAAsB;AACxB;AACA,CALC,SAKS,CAAC;AACX,CAAC,UAAU,CAAC;AAAU,WAAS;AAAM;AACrC,CANC;AAMW,WAAS;AAAK;AAE1B,CAHC;AAIC,QAAM;AACN,QAAM;AACN,SAAO,IAAI;AACX,cAAY;AACZ,UAAQ,IAAI,MAAM,IAAI;AACtB,iBAAe,IAAI,WAAW,EAAE;AAChC,WAAS,IAAI;AACb,UAAQ;AACV;AACA,CAbC,UAaU,MAAM,KAAK;AAAa,SAAO,IAAI;AAAW,gBAAc,IAAI;AAAW,cAAY;AAAM;AACxG,CAdC,UAcU;AAAiB,WAAS,IAAI,MAAM,IAAI;AAAW,kBAAgB;AAAK;AACnF,CAfC,UAeU;AAAY,WAAS;AAAK,UAAQ;AAAS;","names":[]}
@@ -0,0 +1,430 @@
1
+ 'use strict';
2
+
3
+ // src/tooltip.ts
4
+ function renderTip(host, text) {
5
+ host.textContent = "";
6
+ const re = /\u0002([^\u0003]*)\u0003/g;
7
+ let last = 0;
8
+ let m;
9
+ while ((m = re.exec(text)) !== null) {
10
+ if (m.index > last) host.append(text.slice(last, m.index));
11
+ const strong = document.createElement("strong");
12
+ strong.textContent = m[1] ?? "";
13
+ host.append(strong);
14
+ last = m.index + m[0].length;
15
+ }
16
+ if (last < text.length) host.append(text.slice(last));
17
+ }
18
+ var inited = false;
19
+ var checked = false;
20
+ var suppressed;
21
+ var SHOW_DELAY = 350;
22
+ var EDGE = 6;
23
+ var GAP = 7;
24
+ var tip = null;
25
+ var timer = 0;
26
+ var active = null;
27
+ function ensureEl() {
28
+ if (tip) return tip;
29
+ const el2 = document.createElement("div");
30
+ el2.className = "tooltip";
31
+ el2.setAttribute("role", "tooltip");
32
+ el2.hidden = true;
33
+ document.body.appendChild(el2);
34
+ tip = el2;
35
+ return el2;
36
+ }
37
+ var rectOf = (anchor) => anchor instanceof HTMLElement ? anchor.getBoundingClientRect() : anchor;
38
+ function place(anchor) {
39
+ const t = ensureEl();
40
+ const r = rectOf(anchor);
41
+ const tr = t.getBoundingClientRect();
42
+ let top = r.top - tr.height - GAP;
43
+ if (top < EDGE) top = r.top + r.height + GAP;
44
+ let left = r.left + r.width / 2 - tr.width / 2;
45
+ left = Math.max(EDGE, Math.min(left, window.innerWidth - tr.width - EDGE));
46
+ t.style.left = `${Math.round(left)}px`;
47
+ t.style.top = `${Math.round(top)}px`;
48
+ }
49
+ function show(anchor) {
50
+ const text = anchor.dataset["tip"];
51
+ if (!text) return;
52
+ paint(anchor, text);
53
+ }
54
+ function paint(anchor, text) {
55
+ if (suppressed?.()) return;
56
+ const t = ensureEl();
57
+ const host = (anchor instanceof HTMLElement ? anchor.closest("dialog[open]") : null) ?? document.body;
58
+ if (t.parentElement !== host) host.appendChild(t);
59
+ active = anchor instanceof HTMLElement ? anchor : null;
60
+ renderTip(t, text);
61
+ t.hidden = false;
62
+ t.classList.remove("show");
63
+ void t.offsetWidth;
64
+ place(anchor);
65
+ t.classList.add("show");
66
+ }
67
+ function hide() {
68
+ if (timer) {
69
+ window.clearTimeout(timer);
70
+ timer = 0;
71
+ }
72
+ active = null;
73
+ if (tip) {
74
+ tip.hidden = true;
75
+ tip.classList.remove("show");
76
+ }
77
+ }
78
+ function schedule(anchor) {
79
+ if (anchor === active) return;
80
+ if (timer) window.clearTimeout(timer);
81
+ timer = window.setTimeout(() => show(anchor), SHOW_DELAY);
82
+ }
83
+ function ensureTooltipHost() {
84
+ initTooltips();
85
+ }
86
+ function checkTooltipHost() {
87
+ if (checked) return;
88
+ checked = true;
89
+ setTimeout(() => {
90
+ if (inited || typeof document === "undefined") return;
91
+ if (document.querySelector("[data-tip]")) {
92
+ console.warn("app-shell: something set `data-tip` but no tooltip host is mounted, so those rollovers will not draw. Call initTooltips() once per window.");
93
+ }
94
+ }, 0);
95
+ }
96
+ var tipAncestor = (n) => n instanceof Element ? n.closest("[data-tip]") : null;
97
+ function initTooltips(opts = {}) {
98
+ if (opts.suppressed !== void 0) suppressed = opts.suppressed;
99
+ if (inited) return;
100
+ inited = true;
101
+ document.addEventListener("pointerover", (e) => {
102
+ const el2 = tipAncestor(e.target);
103
+ if (el2) schedule(el2);
104
+ });
105
+ document.addEventListener("pointerout", (e) => {
106
+ const el2 = tipAncestor(e.target);
107
+ if (!el2) return;
108
+ const to = e.relatedTarget;
109
+ if (to instanceof Node && el2.contains(to)) return;
110
+ hide();
111
+ });
112
+ document.addEventListener("focusin", (e) => {
113
+ const el2 = tipAncestor(e.target);
114
+ if (el2) schedule(el2);
115
+ });
116
+ document.addEventListener("focusout", () => hide());
117
+ document.addEventListener("pointerdown", () => hide(), true);
118
+ document.addEventListener("scroll", () => {
119
+ if (active) hide();
120
+ }, true);
121
+ document.addEventListener("keydown", (e) => {
122
+ if (e.key === "Escape") hide();
123
+ });
124
+ window.addEventListener("blur", () => hide());
125
+ }
126
+
127
+ // src/icons.ts
128
+ var icon = {
129
+ // --- dismissing and revealing ---------------------------------------------
130
+ /** Close a panel, a dialog, a popover. Patterpad's, twelve times over. */
131
+ close: "\u2715",
132
+ /** The overflow menu on a document or a row: "more about this". */
133
+ more: "\u22EF",
134
+ /** Collapsed disclosure, pointing at what would open. */
135
+ collapsed: "\u25B8",
136
+ /** Expanded disclosure. */
137
+ expanded: "\u25BE",
138
+ /** A dropdown's affordance, where it is not a real <select>. */
139
+ dropdown: "\u25BE",
140
+ // --- moving through things ------------------------------------------------
141
+ /** Back / previous, in a breadcrumb or a stepper. */
142
+ back: "\u2039",
143
+ /** Forward / next. */
144
+ forward: "\u203A",
145
+ /** Up one, in a list. */
146
+ up: "\u2191",
147
+ /** Down one. */
148
+ down: "\u2193",
149
+ // --- state ----------------------------------------------------------------
150
+ /** Done, applied, agreed. */
151
+ tick: "\u2713",
152
+ /** Somebody else holds this: the version-control lock. */
153
+ locked: "\u2298",
154
+ /** Read-only on disk with no other holder: the resting state of everything
155
+ * in a lock-based working copy that nobody has checked out yet. */
156
+ readOnly: "\u25CB",
157
+ /** YOU hold this one: checked out / opened by the current user, still yours to
158
+ * edit. Shares its glyph with `note`, which the table permits: an entry is a
159
+ * MEANING, and two meanings may draw the same shape. */
160
+ checkedOut: "\u270E",
161
+ /** Tracked, with local changes not yet committed. */
162
+ modified: "\u25CF",
163
+ /** Not in version control yet: new since the last commit. */
164
+ untracked: "+",
165
+ /** Something needs attention but is not fatal. */
166
+ warning: "\u203C",
167
+ /** A live thing: the running position, an active marker. */
168
+ dot: "\u25CF",
169
+ /** Play, in the sense of "run this". */
170
+ play: "\u25B6",
171
+ /** Start the thing again from the top: a play session, a sweep. Named for the
172
+ * act, not the arrow, which is the table's rule. */
173
+ restart: "\u27F2",
174
+ /** The three ways a collection can be shown. Named by what you get rather than
175
+ * by the glyph, so a second app can pick the same three without copying
176
+ * somebody's taste in symbols. */
177
+ viewCards: "\u25A6",
178
+ viewTable: "\u2630",
179
+ viewNode: "\u25C8",
180
+ // --- handling -------------------------------------------------------------
181
+ /** The drag grip on a reorderable row. */
182
+ grip: "\u283F",
183
+ /** Add one of whatever this list holds. */
184
+ add: "+",
185
+ // --- annotation -----------------------------------------------------------
186
+ /** Documentation notes: the pencil. Both apps had chosen it independently,
187
+ * which is the happiest way for a vocabulary entry to arrive. */
188
+ note: "\u270E",
189
+ /** A comment thread. Speech, not a pencil: documentation states the reason,
190
+ * comments are the conversation, and the two must never look alike. */
191
+ comment: "\u275D"
192
+ };
193
+ var STROKE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.571" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">';
194
+ var FILL = '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">';
195
+ var stroked = (inner) => `${STROKE}${inner}</svg>`;
196
+ var filled = (inner) => `${FILL}${inner}</svg>`;
197
+ var DISC = filled('<circle cx="12" cy="12" r="6"/>');
198
+ var DISC_LARGE = filled('<circle cx="12" cy="12" r="9"/>');
199
+ var DRAWN = {
200
+ // --- dismissing and revealing ---------------------------------------------
201
+ /** Close a panel, a dialog, a popover. (x) */
202
+ close: stroked('<path d="M18 6 6 18"/><path d="m6 6 12 12"/>'),
203
+ /** The overflow menu on a document or a row: "more about this". (ellipsis) */
204
+ more: stroked('<circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/>'),
205
+ /** Collapsed disclosure, pointing at what would open. (chevron-right) */
206
+ collapsed: stroked('<path d="m9 18 6-6-6-6"/>'),
207
+ /** Expanded disclosure. (chevron-down) */
208
+ expanded: stroked('<path d="m6 9 6 6 6-6"/>'),
209
+ /** A dropdown's affordance, where it is not a real <select>. (chevron-down) */
210
+ dropdown: stroked('<path d="m6 9 6 6 6-6"/>'),
211
+ // --- moving through things ------------------------------------------------
212
+ /** Back / previous, in a breadcrumb or a stepper. (chevron-left) */
213
+ back: stroked('<path d="m15 18-6-6 6-6"/>'),
214
+ /** Forward / next. (chevron-right) */
215
+ forward: stroked('<path d="m9 18 6-6-6-6"/>'),
216
+ /** Up one, in a list. (arrow-up) */
217
+ up: stroked('<path d="m5 12 7-7 7 7"/><path d="M12 19V5"/>'),
218
+ /** Down one. (arrow-down) */
219
+ down: stroked('<path d="M12 5v14"/><path d="m19 12-7 7-7-7"/>'),
220
+ /** History back. (arrow-left) */
221
+ arrowLeft: stroked('<path d="m12 19-7-7 7-7"/><path d="M19 12H5"/>'),
222
+ /** History forward; "go there". (arrow-right) */
223
+ arrowRight: stroked('<path d="M5 12h14"/><path d="m12 5 7 7-7 7"/>'),
224
+ // --- state ----------------------------------------------------------------
225
+ /** Done, applied, agreed. (check) */
226
+ tick: stroked('<path d="M20 6 9 17l-5-5"/>'),
227
+ /** Somebody else holds this: the version-control lock. (lock) */
228
+ locked: stroked('<rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>'),
229
+ /** Read-only on disk with no other holder. (lock-open) An open lock rather
230
+ * than a struck-out eye: this state is not a prohibition. Nobody holds the
231
+ * file, saving checks it out, and it is the resting state of everything the
232
+ * author has not touched yet under a lock-based VCS. eye-off would say "you
233
+ * cannot", which is false here; the open lock says "not held", beside
234
+ * `locked`, which is the shut one, so the two read as a pair. */
235
+ readOnly: stroked('<rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 9.9-1"/>'),
236
+ /** YOU hold this one: checked out, still yours to edit. (pencil) */
237
+ checkedOut: stroked('<path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"/><path d="m15 5 4 4"/>'),
238
+ /** Tracked, with local changes not yet committed. (a disc; see DISC) */
239
+ modified: DISC,
240
+ /** Not in version control yet: new since the last commit. (plus) */
241
+ untracked: stroked('<path d="M5 12h14"/><path d="M12 5v14"/>'),
242
+ /** Something needs attention but is not fatal. (triangle-alert) */
243
+ warning: stroked('<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/>'),
244
+ /** A live thing: the running position, an active marker. (a disc) */
245
+ dot: DISC,
246
+ /** Play, in the sense of "run this". (play) */
247
+ play: stroked('<path d="M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z"/>'),
248
+ /** Start the thing again from the top: a play session, a sweep. (rotate-ccw) */
249
+ restart: stroked('<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/>'),
250
+ /** The three ways a collection can be shown, named by what you get. */
251
+ /** Cards. (layout-grid) */
252
+ viewCards: stroked('<rect width="7" height="7" x="3" y="3" rx="1"/><rect width="7" height="7" x="14" y="3" rx="1"/><rect width="7" height="7" x="14" y="14" rx="1"/><rect width="7" height="7" x="3" y="14" rx="1"/>'),
253
+ /** A table. (rows-3: a ruled box, which is a table. `list` is bullets, and
254
+ * the view is not a list.) */
255
+ viewTable: stroked('<rect width="18" height="18" x="3" y="3" rx="2"/><path d="M21 9H3"/><path d="M21 15H3"/>'),
256
+ /** A node graph. (waypoints: four nodes on edges reads as a graph.
257
+ * `git-fork` reads as version control, which this family also draws, and
258
+ * a picture that means two things is the fault this table exists to
259
+ * prevent.) */
260
+ 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"/>'),
261
+ /** Record: the disc, in whatever colour the button is. (a disc; see DISC_LARGE) */
262
+ record: DISC_LARGE,
263
+ // --- handling -------------------------------------------------------------
264
+ /** The drag grip on a reorderable row. (grip-vertical) */
265
+ 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"/>'),
266
+ /** Add one of whatever this list holds. (plus) */
267
+ add: stroked('<path d="M5 12h14"/><path d="M12 5v14"/>'),
268
+ /** Connect: to a server, a live link, a running game. (plug) */
269
+ 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"/>'),
270
+ /** Search. (search) */
271
+ search: stroked('<path d="m21 21-4.34-4.34"/><circle cx="11" cy="11" r="8"/>'),
272
+ /** Keep this window on top. (pin) */
273
+ pin: stroked('<path d="M12 17v5"/><path d="M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z"/>'),
274
+ /** Settings. (settings) */
275
+ settings: stroked('<path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915"/><circle cx="12" cy="12" r="3"/>'),
276
+ // --- annotation -----------------------------------------------------------
277
+ /** Documentation notes: a document with lines on it. (file-text) The glyph
278
+ * table drew a pencil and shared it with `checkedOut`; the drawn set gives
279
+ * the two meanings two shapes, and notes get the document, which is what
280
+ * the shell's own noteFilled/noteOutline pair had always drawn. */
281
+ note: stroked('<path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/><path d="M14 2v5a1 1 0 0 0 1 1h5"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/>'),
282
+ /** A comment thread. Speech, not a document: documentation states the
283
+ * reason, comments are the conversation, and the two must never look
284
+ * alike. (message-square) */
285
+ comment: stroked('<path d="M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z"/>')
286
+ };
287
+ var ICON_SIZE = 14;
288
+ var templates = /* @__PURE__ */ new Map();
289
+ function iconNode(name, size = ICON_SIZE) {
290
+ let tpl = templates.get(name);
291
+ if (!tpl) {
292
+ const holder = document.createElement("template");
293
+ holder.innerHTML = DRAWN[name];
294
+ tpl = holder.content.firstElementChild;
295
+ tpl.setAttribute("data-icon", name);
296
+ templates.set(name, tpl);
297
+ }
298
+ const node = tpl.cloneNode(true);
299
+ node.setAttribute("width", String(size));
300
+ node.setAttribute("height", String(size));
301
+ return node;
302
+ }
303
+ var BY_GLYPH = /* @__PURE__ */ new Map();
304
+ for (const [name, glyph] of Object.entries(icon)) {
305
+ if (!BY_GLYPH.has(glyph)) BY_GLYPH.set(glyph, name);
306
+ }
307
+
308
+ // src/dom.ts
309
+ function el(tag, classNameOrProps, ...children) {
310
+ const node = document.createElement(tag);
311
+ const props = typeof classNameOrProps === "string" ? { className: classNameOrProps } : classNameOrProps ?? {};
312
+ if (props.className) node.className = props.className;
313
+ if (props.text !== void 0 && props.text !== null) node.textContent = props.text;
314
+ if (props.title !== void 0) node.title = props.title;
315
+ if (props.tip !== void 0) {
316
+ node.dataset["tip"] = props.tip;
317
+ node.setAttribute("aria-label", props.tip);
318
+ ensureTooltipHost();
319
+ }
320
+ if (props.onClick) node.addEventListener("click", props.onClick);
321
+ for (const child of children) {
322
+ if (child === null || child === void 0) continue;
323
+ node.append(child);
324
+ }
325
+ checkTooltipHost();
326
+ return node;
327
+ }
328
+
329
+ // src/util.ts
330
+ var copyTimers = /* @__PURE__ */ new WeakMap();
331
+ function copyWithFeedback(el2, text, ms = 1e3) {
332
+ const write = typeof navigator !== "undefined" && navigator.clipboard ? navigator.clipboard.writeText(text).catch(() => {
333
+ }) : Promise.resolve();
334
+ el2.classList.add("copied");
335
+ const prior = copyTimers.get(el2);
336
+ if (prior !== void 0) clearTimeout(prior);
337
+ copyTimers.set(el2, setTimeout(() => {
338
+ el2.classList.remove("copied");
339
+ copyTimers.delete(el2);
340
+ }, ms));
341
+ return write;
342
+ }
343
+
344
+ // src/link-status.ts
345
+ function linkStatusClass(s) {
346
+ if (s.state === "off" || s.state === "error") return "off";
347
+ if (s.state === "listening") return "listening";
348
+ return s.build === "stale" ? "stale" : "live";
349
+ }
350
+ function linkStatusTip(s) {
351
+ switch (s.state) {
352
+ case "off":
353
+ return "Live link is off. Click to start listening.";
354
+ case "error":
355
+ return `Live link failed (${s.message}). Click to retry.`;
356
+ case "listening":
357
+ return "Live link is listening for a game. Click to stop.";
358
+ case "connected": {
359
+ const who = s.project !== void 0 ? ` to ${s.project}` : "";
360
+ const build = s.build === "stale" ? " on a different build, so save or rebuild to re-sync" : s.build === "match" ? " and in sync" : "";
361
+ const note = s.note ? ` ${s.note}` : "";
362
+ return `Live link is connected${who}${build}.${note} Click to stop.`;
363
+ }
364
+ }
365
+ }
366
+ function linkAddress(s) {
367
+ if (s.state !== "listening" && s.state !== "connected") return void 0;
368
+ return s.address ?? `ws://127.0.0.1:${s.port}`;
369
+ }
370
+ function mountLinkStatus(host, opts) {
371
+ const wrap = el("div", "linkstatus");
372
+ wrap.hidden = true;
373
+ const url = el("button", "linkstatus-url");
374
+ url.type = "button";
375
+ url.hidden = true;
376
+ const toggle = el("button", "linkstatus-toggle off");
377
+ toggle.type = "button";
378
+ toggle.append(iconNode("connect"));
379
+ if (opts.label !== void 0) wrap.append(el("span", "linkstatus-word", opts.label));
380
+ wrap.append(...opts.lead ?? [], url, toggle);
381
+ host.append(wrap);
382
+ let status = { state: "off" };
383
+ const render = () => {
384
+ toggle.className = `linkstatus-toggle ${linkStatusClass(status)}`;
385
+ const tip2 = linkStatusTip(status);
386
+ toggle.dataset["tip"] = tip2;
387
+ toggle.setAttribute("aria-label", tip2);
388
+ const addr = linkAddress(status);
389
+ if (addr !== void 0) {
390
+ url.textContent = addr;
391
+ url.dataset["tip"] = "Click to copy the live link address";
392
+ url.hidden = false;
393
+ } else url.hidden = true;
394
+ };
395
+ const apply = (s) => {
396
+ status = s;
397
+ render();
398
+ };
399
+ render();
400
+ toggle.addEventListener("click", () => {
401
+ const out = opts.onToggle(status);
402
+ void Promise.resolve(out).then((next) => {
403
+ if (next) apply(next);
404
+ });
405
+ });
406
+ url.addEventListener("click", () => {
407
+ const addr = url.textContent ?? "";
408
+ if (!addr) return;
409
+ void copyWithFeedback(url, addr);
410
+ opts.onCopy?.(addr);
411
+ });
412
+ return {
413
+ el: wrap,
414
+ apply,
415
+ status: () => status,
416
+ setVisible(on) {
417
+ wrap.hidden = !on;
418
+ },
419
+ toggle() {
420
+ toggle.click();
421
+ }
422
+ };
423
+ }
424
+
425
+ exports.linkAddress = linkAddress;
426
+ exports.linkStatusClass = linkStatusClass;
427
+ exports.linkStatusTip = linkStatusTip;
428
+ exports.mountLinkStatus = mountLinkStatus;
429
+ //# sourceMappingURL=link-status.cjs.map
430
+ //# sourceMappingURL=link-status.cjs.map