@wildwinter/app-shell 0.38.0 → 0.40.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 (168) hide show
  1. package/LICENSES.md +62 -0
  2. package/README.md +8 -0
  3. package/dist/about.css +17 -38
  4. package/dist/about.css.map +1 -1
  5. package/dist/anchored.css +9 -9
  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-DS4XXAZS.js +56 -0
  16. package/dist/chunk-DS4XXAZS.js.map +1 -0
  17. package/dist/chunk-EHR2KBZC.js +82 -0
  18. package/dist/chunk-EHR2KBZC.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-OPZPFOPS.js +66 -0
  22. package/dist/chunk-OPZPFOPS.js.map +1 -0
  23. package/dist/chunk-P4G4ERG6.js +60 -0
  24. package/dist/chunk-P4G4ERG6.js.map +1 -0
  25. package/dist/chunk-P6WLAEKZ.js +71 -0
  26. package/dist/chunk-P6WLAEKZ.js.map +1 -0
  27. package/dist/chunk-R3NXPHRZ.js +534 -0
  28. package/dist/chunk-R3NXPHRZ.js.map +1 -0
  29. package/dist/chunk-SDOKZTAR.js +87 -0
  30. package/dist/chunk-SDOKZTAR.js.map +1 -0
  31. package/dist/chunk-SEWJLUOD.js +70 -0
  32. package/dist/chunk-SEWJLUOD.js.map +1 -0
  33. package/dist/chunk-UG2P777F.js +587 -0
  34. package/dist/chunk-UG2P777F.js.map +1 -0
  35. package/dist/chunk-YRFJLJUH.js +55 -0
  36. package/dist/chunk-YRFJLJUH.js.map +1 -0
  37. package/dist/chunk-YWMSQFXX.js +146 -0
  38. package/dist/chunk-YWMSQFXX.js.map +1 -0
  39. package/dist/comments.css +16 -14
  40. package/dist/comments.css.map +1 -1
  41. package/dist/confirm.css +2 -55
  42. package/dist/confirm.css.map +1 -1
  43. package/dist/context-menu.cjs +250 -0
  44. package/dist/context-menu.cjs.map +1 -0
  45. package/dist/context-menu.css +64 -0
  46. package/dist/context-menu.css.map +1 -0
  47. package/dist/context-menu.d.cts +25 -0
  48. package/dist/context-menu.d.ts +25 -0
  49. package/dist/context-menu.js +5 -0
  50. package/dist/context-menu.js.map +1 -0
  51. package/dist/controls.css +214 -0
  52. package/dist/controls.css.map +1 -0
  53. package/dist/dialog.cjs +222 -0
  54. package/dist/dialog.cjs.map +1 -0
  55. package/dist/dialog.css +56 -0
  56. package/dist/dialog.css.map +1 -0
  57. package/dist/dialog.d.cts +28 -0
  58. package/dist/dialog.d.ts +28 -0
  59. package/dist/dialog.js +5 -0
  60. package/dist/dialog.js.map +1 -0
  61. package/dist/floating.cjs +83 -0
  62. package/dist/floating.cjs.map +1 -0
  63. package/dist/floating.d.cts +25 -0
  64. package/dist/floating.d.ts +25 -0
  65. package/dist/floating.js +4 -0
  66. package/dist/floating.js.map +1 -0
  67. package/dist/identity.css +15 -50
  68. package/dist/identity.css.map +1 -1
  69. package/dist/index.cjs +1553 -260
  70. package/dist/index.cjs.map +1 -1
  71. package/dist/index.d.cts +385 -152
  72. package/dist/index.d.ts +385 -152
  73. package/dist/index.js +264 -823
  74. package/dist/index.js.map +1 -1
  75. package/dist/job.css +24 -1
  76. package/dist/job.css.map +1 -1
  77. package/dist/keys.cjs +155 -0
  78. package/dist/keys.cjs.map +1 -0
  79. package/dist/keys.css +41 -0
  80. package/dist/keys.css.map +1 -0
  81. package/dist/keys.d.cts +57 -0
  82. package/dist/keys.d.ts +57 -0
  83. package/dist/keys.js +3 -0
  84. package/dist/keys.js.map +1 -0
  85. package/dist/link-status.cjs +430 -0
  86. package/dist/link-status.cjs.map +1 -0
  87. package/dist/link-status.css +76 -0
  88. package/dist/link-status.css.map +1 -0
  89. package/dist/link-status.d.cts +53 -0
  90. package/dist/link-status.d.ts +53 -0
  91. package/dist/link-status.js +5 -0
  92. package/dist/link-status.js.map +1 -0
  93. package/dist/menu.cjs +62 -1
  94. package/dist/menu.cjs.map +1 -1
  95. package/dist/menu.d.cts +88 -1
  96. package/dist/menu.d.ts +88 -1
  97. package/dist/menu.js +1 -1
  98. package/dist/notes-editor.css +9 -52
  99. package/dist/notes-editor.css.map +1 -1
  100. package/dist/pane-shell.css +23 -5
  101. package/dist/pane-shell.css.map +1 -1
  102. package/dist/problems.cjs +61 -0
  103. package/dist/problems.cjs.map +1 -0
  104. package/dist/problems.d.cts +57 -0
  105. package/dist/problems.d.ts +57 -0
  106. package/dist/problems.js +3 -0
  107. package/dist/problems.js.map +1 -0
  108. package/dist/property-list-D3VZCJzi.d.cts +162 -0
  109. package/dist/property-list-D3VZCJzi.d.ts +162 -0
  110. package/dist/property-list.cjs +784 -0
  111. package/dist/property-list.cjs.map +1 -0
  112. package/dist/property-list.d.cts +1 -0
  113. package/dist/property-list.d.ts +1 -0
  114. package/dist/property-list.js +4 -0
  115. package/dist/property-list.js.map +1 -0
  116. package/dist/save.css +1 -1
  117. package/dist/save.css.map +1 -1
  118. package/dist/settings.css +62 -18
  119. package/dist/settings.css.map +1 -1
  120. package/dist/stale.css +4 -1
  121. package/dist/stale.css.map +1 -1
  122. package/dist/stepper.css +47 -3
  123. package/dist/stepper.css.map +1 -1
  124. package/dist/toast.css +5 -5
  125. package/dist/toast.css.map +1 -1
  126. package/dist/tokens.css +20 -0
  127. package/dist/tokens.css.map +1 -1
  128. package/dist/tool-window.cjs +63 -0
  129. package/dist/tool-window.cjs.map +1 -1
  130. package/dist/tool-window.css +8 -4
  131. package/dist/tool-window.css.map +1 -1
  132. package/dist/tool-window.d.cts +67 -1
  133. package/dist/tool-window.d.ts +67 -1
  134. package/dist/tool-window.js +63 -1
  135. package/dist/tool-window.js.map +1 -1
  136. package/dist/tooltip.css +3 -3
  137. package/dist/tooltip.css.map +1 -1
  138. package/dist/updater-view.cjs +283 -0
  139. package/dist/updater-view.cjs.map +1 -0
  140. package/dist/updater-view.d.cts +23 -0
  141. package/dist/updater-view.d.ts +23 -0
  142. package/dist/updater-view.js +6 -0
  143. package/dist/updater-view.js.map +1 -0
  144. package/dist/updater.cjs +12 -16
  145. package/dist/updater.cjs.map +1 -1
  146. package/dist/updater.css +44 -0
  147. package/dist/updater.css.map +1 -0
  148. package/dist/updater.js +12 -16
  149. package/dist/updater.js.map +1 -1
  150. package/dist/util.cjs +78 -0
  151. package/dist/util.cjs.map +1 -0
  152. package/dist/util.d.cts +37 -0
  153. package/dist/util.d.ts +37 -0
  154. package/dist/util.js +3 -0
  155. package/dist/util.js.map +1 -0
  156. package/dist/vc.css +4 -3
  157. package/dist/vc.css.map +1 -1
  158. package/dist/welcome.cjs +215 -0
  159. package/dist/welcome.cjs.map +1 -0
  160. package/dist/welcome.css +112 -0
  161. package/dist/welcome.css.map +1 -0
  162. package/dist/welcome.d.cts +55 -0
  163. package/dist/welcome.d.ts +55 -0
  164. package/dist/welcome.js +4 -0
  165. package/dist/welcome.js.map +1 -0
  166. package/package.json +72 -2
  167. package/dist/chunk-QDPFU4WX.js +0 -43
  168. package/dist/chunk-QDPFU4WX.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/notes-editor.css"],"sourcesContent":["/* The documentation-notes editor (notes-editor.ts): a modal, because notes are\n prose and the popover Patterpad tried first was too cramped. */\n.shell-notes {\n width: min(560px, 92vw);\n border: 1px solid var(--line); border-radius: var(--radius-md);\n background: var(--surface); color: var(--ink);\n padding: 16px 18px;\n box-shadow: var(--shadow-2, var(--shadow-1));\n}\n.shell-notes::backdrop { background: rgba(0, 0, 0, 0.28); }\n.shell-notes-title { font: 600 0.95rem/1.3 var(--font-ui); margin-bottom: 10px; }\n.shell-notes-body { display: flex; flex-direction: column; gap: 10px; max-height: 60vh; overflow-y: auto; }\n.shell-notes-caption {\n font: 0.72rem/1 var(--font-ui); color: var(--muted);\n text-transform: uppercase; letter-spacing: 0.04em;\n}\n.shell-notes-class { display: flex; flex-direction: column; gap: 4px; }\n.shell-notes-text {\n width: 100%; box-sizing: border-box; resize: vertical;\n border: 1px solid var(--line-soft); border-radius: var(--radius-sm);\n background: var(--card); color: var(--ink);\n font: 0.85rem/1.45 var(--font-read, var(--font-ui)); padding: 6px 8px;\n}\n.shell-notes-text:focus { outline: none; border-color: var(--accent); }\n/* Inherited notes read as CONTEXT rather than as fields: no box, no cursor. */\n.shell-notes-inherited {\n display: flex; flex-direction: column; gap: 6px;\n padding-bottom: 4px; border-bottom: 1px solid var(--line-soft);\n}\n.shell-notes-level { display: flex; flex-direction: column; gap: 2px; }\n.shell-notes-level-label { font: 0.72rem/1 var(--font-ui); color: var(--muted); }\n.shell-notes-line { font: 0.82rem/1.4 var(--font-read, var(--font-ui)); color: var(--muted); }\n.shell-notes-cls {\n font: 0.68rem/1 var(--font-ui); color: var(--muted);\n border: 1px solid var(--line-soft); border-radius: var(--radius-pill);\n padding: 1px 6px; margin-right: 6px;\n}\n.shell-notes-hint { font: 0.72rem/1 var(--font-ui); color: var(--muted); margin: 0; }\n.shell-notes-add { font: 0.78rem/1 var(--font-ui); align-self: flex-start; }\n.shell-notes-actions { display: flex; justify-content: flex-end; margin-top: 12px; }\n.shell-notes-btn {\n font: 0.8rem/1 var(--font-ui); padding: 6px 14px;\n border-radius: var(--radius-sm); border: 1px solid var(--line);\n background: var(--card); color: var(--ink); cursor: pointer;\n}\n.shell-notes-btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent, #fff); }\n"],"mappings":";AAEA,CAAC;AACC,SAAO,IAAI,KAAK,EAAE;AAClB,UAAQ,IAAI,MAAM,IAAI;AAAS,iBAAe,IAAI;AAClD,cAAY,IAAI;AAAY,SAAO,IAAI;AACvC,WAAS,KAAK;AACd,cAAY,IAAI,UAAU,EAAE,IAAI;AAClC;AACA,CAPC,WAOW;AAAa,cAAY,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAAO;AAC1D,CAAC;AAAoB,QAAM,IAAI,OAAO,CAAC,IAAI,IAAI;AAAY,iBAAe;AAAM;AAChF,CAAC;AAAmB,WAAS;AAAM,kBAAgB;AAAQ,OAAK;AAAM,cAAY;AAAM,cAAY;AAAM;AAC1G,CAAC;AACC,QAAM,OAAO,CAAC,EAAE,IAAI;AAAY,SAAO,IAAI;AAC3C,kBAAgB;AAAW,kBAAgB;AAC7C;AACA,CAAC;AAAoB,WAAS;AAAM,kBAAgB;AAAQ,OAAK;AAAK;AACtE,CAAC;AACC,SAAO;AAAM,cAAY;AAAY,UAAQ;AAC7C,UAAQ,IAAI,MAAM,IAAI;AAAc,iBAAe,IAAI;AACvD,cAAY,IAAI;AAAS,SAAO,IAAI;AACpC,QAAM,OAAO,CAAC,KAAK,IAAI,WAAW,EAAE,IAAI;AAAa,WAAS,IAAI;AACpE;AACA,CANC,gBAMgB;AAAS,WAAS;AAAM,gBAAc,IAAI;AAAW;AAEtE,CAAC;AACC,WAAS;AAAM,kBAAgB;AAAQ,OAAK;AAC5C,kBAAgB;AAAK,iBAAe,IAAI,MAAM,IAAI;AACpD;AACA,CAAC;AAAoB,WAAS;AAAM,kBAAgB;AAAQ,OAAK;AAAK;AACtE,CAAC;AAA0B,QAAM,OAAO,CAAC,EAAE,IAAI;AAAY,SAAO,IAAI;AAAU;AAChF,CAAC;AAAmB,QAAM,OAAO,CAAC,IAAI,IAAI,WAAW,EAAE,IAAI;AAAa,SAAO,IAAI;AAAU;AAC7F,CAAC;AACC,QAAM,OAAO,CAAC,EAAE,IAAI;AAAY,SAAO,IAAI;AAC3C,UAAQ,IAAI,MAAM,IAAI;AAAc,iBAAe,IAAI;AACvD,WAAS,IAAI;AAAK,gBAAc;AAClC;AACA,CAAC;AAAmB,QAAM,OAAO,CAAC,EAAE,IAAI;AAAY,SAAO,IAAI;AAAU,UAAQ;AAAG;AACpF,CAAC;AAAkB,QAAM,OAAO,CAAC,EAAE,IAAI;AAAY,cAAY;AAAY;AAC3E,CAAC;AAAsB,WAAS;AAAM,mBAAiB;AAAU,cAAY;AAAM;AACnF,CAAC;AACC,QAAM,MAAM,CAAC,EAAE,IAAI;AAAY,WAAS,IAAI;AAC5C,iBAAe,IAAI;AAAc,UAAQ,IAAI,MAAM,IAAI;AACvD,cAAY,IAAI;AAAS,SAAO,IAAI;AAAQ,UAAQ;AACtD;AACA,CALC,eAKe,CAAC;AAAU,cAAY,IAAI;AAAW,gBAAc,IAAI;AAAW,SAAO,IAAI,WAAW,EAAE;AAAO;","names":[]}
1
+ {"version":3,"sources":["../src/notes-editor.css"],"sourcesContent":["/* The documentation-notes editor (notes-editor.ts): a modal, because notes are\n prose and the popover Patterpad tried first was too cramped. The panel,\n scrim, title and actions row are the dialog frame's (dialog.css); the text\n areas and the Done button are controls.css's `.field` and `.btn`. */\n.shell-notes { --dialog-width: 560px; }\n.shell-notes-body { display: flex; flex-direction: column; gap: 10px; max-height: 60vh; overflow-y: auto; }\n/* A caption is sentence-case text at label size, weight 600, in the UI face. */\n.shell-notes-caption {\n font: 600 12.5px/1.2 var(--font-ui); color: var(--muted);\n}\n.shell-notes-class { display: flex; flex-direction: column; gap: 4px; }\n/* Notes are prose, so the area is set in the reading face; the element\n selector out-specifies `.field`, whichever stylesheet loads first. */\ntextarea.shell-notes-text {\n width: 100%; box-sizing: border-box; resize: vertical;\n font: 13.5px/1.45 var(--font-read, var(--font-ui));\n}\n/* Inherited notes read as CONTEXT rather than as fields: no box, no cursor. */\n.shell-notes-inherited {\n display: flex; flex-direction: column; gap: 6px;\n padding-bottom: 4px; border-bottom: 1px solid var(--line-soft);\n}\n.shell-notes-level { display: flex; flex-direction: column; gap: 2px; }\n.shell-notes-level-label { font: 11.5px/1 var(--font-ui); color: var(--muted); }\n.shell-notes-line { font: 13px/1.4 var(--font-read, var(--font-ui)); color: var(--muted); }\n.shell-notes-cls {\n font: 11px/1 var(--font-ui); color: var(--muted);\n border: 1px solid var(--line-soft); border-radius: var(--radius-pill);\n padding: 1px 6px; margin-right: 6px;\n}\n.shell-notes-hint { font: 11.5px/1 var(--font-ui); color: var(--muted); margin: 0; }\n.shell-notes-add { font: 12.5px/1 var(--font-ui); align-self: flex-start; }\n"],"mappings":";AAIA,CAAC;AAAc,kBAAgB;AAAO;AACtC,CAAC;AAAmB,WAAS;AAAM,kBAAgB;AAAQ,OAAK;AAAM,cAAY;AAAM,cAAY;AAAM;AAE1G,CAAC;AACC,QAAM,IAAI,MAAM,CAAC,IAAI,IAAI;AAAY,SAAO,IAAI;AAClD;AACA,CAAC;AAAoB,WAAS;AAAM,kBAAgB;AAAQ,OAAK;AAAK;AAGtE,QAAQ,CAAC;AACP,SAAO;AAAM,cAAY;AAAY,UAAQ;AAC7C,QAAM,MAAM,CAAC,KAAK,IAAI,WAAW,EAAE,IAAI;AACzC;AAEA,CAAC;AACC,WAAS;AAAM,kBAAgB;AAAQ,OAAK;AAC5C,kBAAgB;AAAK,iBAAe,IAAI,MAAM,IAAI;AACpD;AACA,CAAC;AAAoB,WAAS;AAAM,kBAAgB;AAAQ,OAAK;AAAK;AACtE,CAAC;AAA0B,QAAM,MAAM,CAAC,EAAE,IAAI;AAAY,SAAO,IAAI;AAAU;AAC/E,CAAC;AAAmB,QAAM,IAAI,CAAC,IAAI,IAAI,WAAW,EAAE,IAAI;AAAa,SAAO,IAAI;AAAU;AAC1F,CAAC;AACC,QAAM,IAAI,CAAC,EAAE,IAAI;AAAY,SAAO,IAAI;AACxC,UAAQ,IAAI,MAAM,IAAI;AAAc,iBAAe,IAAI;AACvD,WAAS,IAAI;AAAK,gBAAc;AAClC;AACA,CAAC;AAAmB,QAAM,MAAM,CAAC,EAAE,IAAI;AAAY,SAAO,IAAI;AAAU,UAAQ;AAAG;AACnF,CAAC;AAAkB,QAAM,MAAM,CAAC,EAAE,IAAI;AAAY,cAAY;AAAY;","names":[]}
@@ -5,6 +5,11 @@
5
5
  flex-direction: column;
6
6
  min-height: 0;
7
7
  }
8
+ .topbar,
9
+ .pane-nav,
10
+ .pane-inspector {
11
+ font-size: var(--chrome-size);
12
+ }
8
13
  .topbar {
9
14
  display: flex;
10
15
  align-items: center;
@@ -28,13 +33,15 @@
28
33
  gap: 10px;
29
34
  }
30
35
  .pane-toggle {
36
+ display: inline-flex;
37
+ align-items: center;
38
+ justify-content: center;
31
39
  color: var(--muted);
32
40
  font: inherit;
33
- font-size: 0.95rem;
34
41
  background: none;
35
42
  border: 0;
36
43
  border-radius: var(--radius-sm);
37
- padding: 2px 8px;
44
+ padding: 4px 8px;
38
45
  cursor: pointer;
39
46
  }
40
47
  .pane-toggle:hover {
@@ -50,8 +57,8 @@
50
57
  padding-left: 84px;
51
58
  }
52
59
  .panes {
53
- --nav-open-w: 14rem;
54
- --insp-open-w: 22rem;
60
+ --nav-open-w: 224px;
61
+ --insp-open-w: 384px;
55
62
  --nav-w: var(--nav-open-w);
56
63
  --insp-w: var(--insp-open-w);
57
64
  position: relative;
@@ -103,6 +110,18 @@
103
110
  cursor: col-resize;
104
111
  touch-action: none;
105
112
  }
113
+ .pane-resizer::after {
114
+ content: "";
115
+ position: absolute;
116
+ inset: 0 3px;
117
+ background: transparent;
118
+ transition: background var(--dur-quick) var(--ease-standard);
119
+ }
120
+ .pane-resizer:hover::after,
121
+ .pane-resizer.dragging::after,
122
+ body.pane-resizing .pane-resizer::after {
123
+ background: color-mix(in oklab, var(--accent) 45%, transparent);
124
+ }
106
125
  .pane-resizer-nav {
107
126
  left: calc(var(--nav-w) - 3px);
108
127
  }
@@ -136,7 +155,6 @@ body.pane-resizing .panes {
136
155
  border-radius: var(--radius-sm);
137
156
  background: none;
138
157
  color: var(--muted);
139
- font-size: 0.95rem;
140
158
  line-height: 1;
141
159
  cursor: pointer;
142
160
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/pane-shell.css"],"sourcesContent":["/* ============================================================================\n The pane-shell frame: top bar + nav | centre | inspector grid with collapse\n and drag-resize. Reads the shared token grammar (tokens.css) and the app's\n palette vars (--surface / --ink / --muted / --line / --accent, and an\n optional --line-soft). The host fills the pane bodies and the top-bar\n lead/trail slots.\n ============================================================================ */\n\n.pane-shell { flex: 1; display: flex; flex-direction: column; min-height: 0; }\n\n.topbar {\n display: flex; align-items: center; gap: 10px;\n padding: 8px 14px;\n border-bottom: 1px solid var(--line-soft, var(--line));\n background: var(--surface);\n}\n.topbar-lead { display: flex; align-items: center; gap: 8px; min-width: 0; }\n.topbar-spacer { flex: 1; }\n.topbar-trail { display: flex; align-items: center; gap: 10px; }\n.pane-toggle {\n color: var(--muted); font: inherit; font-size: 0.95rem;\n background: none; border: 0; border-radius: var(--radius-sm); padding: 2px 8px; cursor: pointer;\n}\n.pane-toggle:hover { color: var(--accent); }\n\n/* --- the fused title bar (the family ruling, 2026-08-27) --------------------\n On macOS the topbar IS the window's title bar: the app's main window uses\n titleBarStyle \"hiddenInset\" and marks the bar with these classes, so one\n row carries the traffic lights, the identity and the top-level controls\n instead of a native strip whose only cargo is a title. `titlebar` makes the\n bar the drag surface (its controls stay clickable; add `no-drag` to any\n other interactive thing the host mounts); `titlebar-inset` leaves room for\n the traffic lights and is added ONLY on macOS - elsewhere the window keeps\n its native frame and the same bar sits beneath it, identically in every\n app of the family. */\n.topbar.titlebar { -webkit-app-region: drag; }\n.topbar.titlebar :is(button, input, select, a, .no-drag) { -webkit-app-region: no-drag; }\n.topbar.titlebar-inset { padding-left: 84px; }\n\n.panes {\n --nav-open-w: 14rem; --insp-open-w: 22rem;\n --nav-w: var(--nav-open-w); --insp-w: var(--insp-open-w);\n position: relative; flex: 1; min-height: 0;\n display: grid; grid-template-columns: var(--nav-w) minmax(0, 1fr) var(--insp-w);\n transition: grid-template-columns var(--dur-panel) var(--ease-standard);\n}\n.panes.no-nav { --nav-w: 0px; }\n.panes.no-inspector { --insp-w: 0px; }\n\n/* Side panes clip; their inner holds a fixed width so a collapse wipes cleanly\n rather than reflowing while the column animates to 0. */\n.pane { overflow: hidden; min-height: 0; }\n.pane-inner { height: 100%; overflow: auto; }\n.pane-nav .pane-inner { width: var(--nav-open-w); }\n.pane-inspector .pane-inner { width: var(--insp-open-w); }\n.pane-centre { min-width: 0; min-height: 0; overflow: auto; }\n\n.panes > .pane { transition: opacity var(--dur-panel) var(--ease-standard); }\n.panes.no-nav > .pane-nav, .panes.no-inspector > .pane-inspector { opacity: 0; pointer-events: none; }\n\n/* Drag seams over each side pane's inner edge, tracking the grid columns. */\n.pane-resizer { position: absolute; top: 0; bottom: 0; width: 7px; z-index: 6; cursor: col-resize; touch-action: none; }\n.pane-resizer-nav { left: calc(var(--nav-w) - 3px); }\n.pane-resizer-insp { right: calc(var(--insp-w) - 3px); }\n.panes.no-nav .pane-resizer-nav, .panes.no-inspector .pane-resizer-insp { display: none; }\nbody.pane-resizing { cursor: col-resize; user-select: none; }\nbody.pane-resizing .panes { transition: none; } /* 1:1 feel: suspend the grid tween mid-drag */\n\n/* --- the back/forward pair (nav-history.ts) --------------------------------\n VS Code's quietness: two plain chevrons, borderless, greyed where there is\n nowhere to go. They sit to the LEFT of the app's normal navigation (the\n crumb trail here, whatever the host's equivalent is), so they read as part\n of the chrome, not a control demanding attention. */\n.shell-histnav { display: inline-flex; gap: 2px; margin-right: 6px; }\n.shell-histnav-btn { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; padding: 0; border: none; border-radius: var(--radius-sm); background: none; color: var(--muted); font-size: 0.95rem; line-height: 1; cursor: pointer; }\n.shell-histnav-btn:hover:not(:disabled) { color: var(--ink); background: var(--accent-soft); }\n.shell-histnav-btn:disabled { opacity: 0.35; cursor: default; }\n"],"mappings":";AAQA,CAAC;AAAa,QAAM;AAAG,WAAS;AAAM,kBAAgB;AAAQ,cAAY;AAAG;AAE7E,CAAC;AACC,WAAS;AAAM,eAAa;AAAQ,OAAK;AACzC,WAAS,IAAI;AACb,iBAAe,IAAI,MAAM,IAAI,WAAW,EAAE,IAAI;AAC9C,cAAY,IAAI;AAClB;AACA,CAAC;AAAc,WAAS;AAAM,eAAa;AAAQ,OAAK;AAAK,aAAW;AAAG;AAC3E,CAAC;AAAgB,QAAM;AAAG;AAC1B,CAAC;AAAe,WAAS;AAAM,eAAa;AAAQ,OAAK;AAAM;AAC/D,CAAC;AACC,SAAO,IAAI;AAAU,QAAM;AAAS,aAAW;AAC/C,cAAY;AAAM,UAAQ;AAAG,iBAAe,IAAI;AAAc,WAAS,IAAI;AAAK,UAAQ;AAC1F;AACA,CAJC,WAIW;AAAS,SAAO,IAAI;AAAW;AAY3C,CAzBC,MAyBM,CAAC;AAAW,sBAAoB;AAAM;AAC7C,CA1BC,MA0BM,CADC,SACS,IAAI,QAAQ,OAAO,QAAQ,GAAG,CAAC;AAAW,sBAAoB;AAAS;AACxF,CA3BC,MA2BM,CAAC;AAAiB,gBAAc;AAAM;AAE7C,CAAC;AACC,gBAAc;AAAO,iBAAe;AACpC,WAAS,IAAI;AAAe,YAAU,IAAI;AAC1C,YAAU;AAAU,QAAM;AAAG,cAAY;AACzC,WAAS;AAAM,yBAAuB,IAAI,SAAS,OAAO,CAAC,EAAE,KAAK,IAAI;AACtE,cAAY,sBAAsB,IAAI,aAAa,IAAI;AACzD;AACA,CAPC,KAOK,CAAC;AAAS,WAAS;AAAK;AAC9B,CARC,KAQK,CAAC;AAAe,YAAU;AAAK;AAIrC,CAAC;AAAO,YAAU;AAAQ,cAAY;AAAG;AACzC,CAAC;AAAa,UAAQ;AAAM,YAAU;AAAM;AAC5C,CAAC,SAAS,CADT;AACuB,SAAO,IAAI;AAAe;AAClD,CAAC,eAAe,CAFf;AAE6B,SAAO,IAAI;AAAgB;AACzD,CAAC;AAAc,aAAW;AAAG,cAAY;AAAG,YAAU;AAAM;AAE5D,CAlBC,MAkBM,EAAE,CANR;AAMgB,cAAY,QAAQ,IAAI,aAAa,IAAI;AAAkB;AAC5E,CAnBC,KAmBK,CAZC,OAYO,EAAE,CALf;AAK0B,CAnB1B,KAmBgC,CAX1B,aAWwC,EAAE,CAJhD;AAIkE,WAAS;AAAG,kBAAgB;AAAM;AAGrG,CAAC;AAAe,YAAU;AAAU,OAAK;AAAG,UAAQ;AAAG,SAAO;AAAK,WAAS;AAAG,UAAQ;AAAY,gBAAc;AAAM;AACvH,CAAC;AAAmB,QAAM,KAAK,IAAI,SAAS,EAAE;AAAM;AACpD,CAAC;AAAoB,SAAO,KAAK,IAAI,UAAU,EAAE;AAAM;AACvD,CAzBC,KAyBK,CAlBC,OAkBO,CAFb;AAEgC,CAzBhC,KAyBsC,CAjBhC,aAiB8C,CADpD;AACyE,WAAS;AAAM;AACzF,IAAI,CAAC;AAAgB,UAAQ;AAAY,eAAa;AAAM;AAC5D,IAAI,CADC,cACc,CA3BlB;AA2B2B,cAAY;AAAM;AAO9C,CAAC;AAAgB,WAAS;AAAa,OAAK;AAAK,gBAAc;AAAK;AACpE,CAAC;AAAoB,WAAS;AAAa,eAAa;AAAQ,mBAAiB;AAAQ,SAAO;AAAM,UAAQ;AAAM,WAAS;AAAG,UAAQ;AAAM,iBAAe,IAAI;AAAc,cAAY;AAAM,SAAO,IAAI;AAAU,aAAW;AAAS,eAAa;AAAG,UAAQ;AAAS;AAC3Q,CADC,iBACiB,MAAM,KAAK;AAAa,SAAO,IAAI;AAAQ,cAAY,IAAI;AAAgB;AAC7F,CAFC,iBAEiB;AAAY,WAAS;AAAM,UAAQ;AAAS;","names":[]}
1
+ {"version":3,"sources":["../src/pane-shell.css"],"sourcesContent":["/* ============================================================================\n The pane-shell frame: top bar + nav | centre | inspector grid with collapse\n and drag-resize. Reads the shared token grammar (tokens.css) and the app's\n palette vars (--surface / --ink / --muted / --line / --accent, and an\n optional --line-soft). The host fills the pane bodies and the top-bar\n lead/trail slots.\n ============================================================================ */\n\n/* The chrome base (tokens.css) is set on the CHROME panes only: the top bar,\n the navigator and the inspector read at 14px whatever the app's reading root\n is. The centre pane is the app's content and inherits the app's own size:\n pinning the whole shell pulled Patterpad's script down to 14px. */\n.pane-shell { flex: 1; display: flex; flex-direction: column; min-height: 0; }\n.topbar, .pane-nav, .pane-inspector { font-size: var(--chrome-size); }\n\n.topbar {\n display: flex; align-items: center; gap: 10px;\n padding: 8px 14px;\n border-bottom: 1px solid var(--line-soft, var(--line));\n background: var(--surface);\n}\n.topbar-lead { display: flex; align-items: center; gap: 8px; min-width: 0; }\n.topbar-spacer { flex: 1; }\n.topbar-trail { display: flex; align-items: center; gap: 10px; }\n.pane-toggle {\n display: inline-flex; align-items: center; justify-content: center;\n color: var(--muted); font: inherit;\n background: none; border: 0; border-radius: var(--radius-sm); padding: 4px 8px; cursor: pointer;\n}\n.pane-toggle:hover { color: var(--accent); }\n\n/* --- the fused title bar (the family ruling, 2026-08-27) --------------------\n On macOS the topbar IS the window's title bar: the app's main window uses\n titleBarStyle \"hiddenInset\" and marks the bar with these classes, so one\n row carries the traffic lights, the identity and the top-level controls\n instead of a native strip whose only cargo is a title. `titlebar` makes the\n bar the drag surface (its controls stay clickable; add `no-drag` to any\n other interactive thing the host mounts); `titlebar-inset` leaves room for\n the traffic lights and is added ONLY on macOS - elsewhere the window keeps\n its native frame and the same bar sits beneath it, identically in every\n app of the family. */\n.topbar.titlebar { -webkit-app-region: drag; }\n.topbar.titlebar :is(button, input, select, a, .no-drag) { -webkit-app-region: no-drag; }\n.topbar.titlebar-inset { padding-left: 84px; }\n\n.panes {\n --nav-open-w: 224px; --insp-open-w: 384px;\n --nav-w: var(--nav-open-w); --insp-w: var(--insp-open-w);\n position: relative; flex: 1; min-height: 0;\n display: grid; grid-template-columns: var(--nav-w) minmax(0, 1fr) var(--insp-w);\n transition: grid-template-columns var(--dur-panel) var(--ease-standard);\n}\n.panes.no-nav { --nav-w: 0px; }\n.panes.no-inspector { --insp-w: 0px; }\n\n/* Side panes clip; their inner holds a fixed width so a collapse wipes cleanly\n rather than reflowing while the column animates to 0. */\n.pane { overflow: hidden; min-height: 0; }\n.pane-inner { height: 100%; overflow: auto; }\n.pane-nav .pane-inner { width: var(--nav-open-w); }\n.pane-inspector .pane-inner { width: var(--insp-open-w); }\n.pane-centre { min-width: 0; min-height: 0; overflow: auto; }\n\n.panes > .pane { transition: opacity var(--dur-panel) var(--ease-standard); }\n.panes.no-nav > .pane-nav, .panes.no-inspector > .pane-inspector { opacity: 0; pointer-events: none; }\n\n/* Drag seams over each side pane's inner edge, tracking the grid columns. The\n seam is invisible at rest and lights up under the pointer and while dragging\n (quiet chrome, shown on hover): a colour change only, at --dur-quick. */\n.pane-resizer { position: absolute; top: 0; bottom: 0; width: 7px; z-index: 6; cursor: col-resize; touch-action: none; }\n.pane-resizer::after { content: \"\"; position: absolute; inset: 0 3px; background: transparent; transition: background var(--dur-quick) var(--ease-standard); }\n.pane-resizer:hover::after, .pane-resizer.dragging::after, body.pane-resizing .pane-resizer::after { background: color-mix(in oklab, var(--accent) 45%, transparent); }\n.pane-resizer-nav { left: calc(var(--nav-w) - 3px); }\n.pane-resizer-insp { right: calc(var(--insp-w) - 3px); }\n.panes.no-nav .pane-resizer-nav, .panes.no-inspector .pane-resizer-insp { display: none; }\nbody.pane-resizing { cursor: col-resize; user-select: none; }\nbody.pane-resizing .panes { transition: none; } /* 1:1 feel: suspend the grid tween mid-drag */\n\n/* --- the back/forward pair (nav-history.ts) --------------------------------\n VS Code's quietness: two plain chevrons, borderless, greyed where there is\n nowhere to go. They sit to the LEFT of the app's normal navigation (the\n crumb trail here, whatever the host's equivalent is), so they read as part\n of the chrome, not a control demanding attention. */\n.shell-histnav { display: inline-flex; gap: 2px; margin-right: 6px; }\n.shell-histnav-btn { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; padding: 0; border: none; border-radius: var(--radius-sm); background: none; color: var(--muted); line-height: 1; cursor: pointer; }\n.shell-histnav-btn:hover:not(:disabled) { color: var(--ink); background: var(--accent-soft); }\n.shell-histnav-btn:disabled { opacity: 0.35; cursor: default; }\n"],"mappings":"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","names":[]}
@@ -0,0 +1,61 @@
1
+ 'use strict';
2
+
3
+ // src/problems.ts
4
+ function problemName(p, dangling = false) {
5
+ if (p.title) return `\u201C${p.title}\u201D`;
6
+ if (dangling && p.where) return `(id ${p.where})`;
7
+ return "This";
8
+ }
9
+ function describeProblem(problem, table = {}) {
10
+ const entry = problem.code ? table[problem.code] : void 0;
11
+ if (entry) {
12
+ const copy = entry(problem);
13
+ const text = copy.dangling && !problem.title && problem.where && !copy.text.includes(`(id ${problem.where})`) ? `${copy.text} (id ${problem.where})` : copy.text;
14
+ return copy.next ? { text, next: copy.next } : { text };
15
+ }
16
+ const message = problem.message.replace(/\s*\[[^\]]*\]\s*$/, "").trim();
17
+ return { text: problem.title ? `${problem.title}: ${message}` : message };
18
+ }
19
+ function problemLine(problem, table) {
20
+ const { text, next } = describeProblem(problem, table);
21
+ return next ? `${text} ${next}` : text;
22
+ }
23
+ var defaultProblemCopy = {
24
+ "duplicate-gameid": (p) => ({
25
+ text: `The Game ID on ${problemName(p)} is already used elsewhere.`,
26
+ next: "Each one must be unique; change one of them."
27
+ }),
28
+ "invalid-gameid": (p) => ({
29
+ text: `The Game ID on ${problemName(p)} isn't valid.`,
30
+ next: "Use lowercase letters, digits and hyphens."
31
+ }),
32
+ "dangling-reference": (p) => ({
33
+ text: `${problemName(p, true)} points at something that no longer exists.`,
34
+ next: "Choose where it goes.",
35
+ dangling: true
36
+ }),
37
+ "unknown-property": (p) => ({
38
+ text: `${problemName(p)} uses a property that isn't set up yet.`,
39
+ next: "Declare it in the project settings, or fix the name."
40
+ }),
41
+ "missing-name": (p) => ({ text: `${problemName(p)} needs a name.` }),
42
+ "empty": (p) => ({
43
+ text: `${problemName(p)} is empty.`,
44
+ next: "Add something inside it, or remove it."
45
+ }),
46
+ "stale-build": (p) => ({
47
+ text: `Your playable build${p.path ? ` (${p.path})` : ""} is out of date.`,
48
+ next: "It refreshes the next time you publish."
49
+ }),
50
+ "merge-conflict": (p) => ({
51
+ text: `${p.path ?? "This file"} still has an unresolved merge conflict in it.`,
52
+ next: "Resolve it in your version control tool, then reopen the project."
53
+ })
54
+ };
55
+
56
+ exports.defaultProblemCopy = defaultProblemCopy;
57
+ exports.describeProblem = describeProblem;
58
+ exports.problemLine = problemLine;
59
+ exports.problemName = problemName;
60
+ //# sourceMappingURL=problems.cjs.map
61
+ //# sourceMappingURL=problems.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/problems.ts"],"names":[],"mappings":"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","file":"problems.cjs","sourcesContent":["// ---------------------------------------------------------------------------\n// Problem copy: a validator's diagnostic rewritten for the person at the\n// keyboard, through a table the app fills.\n//\n// Patterpad's `humanizeProblem` (its renderer.ts) proved the shape: a dozen\n// validator categories each mapped to a plain sentence with a next step, naming\n// things by their title, and a fallback that softens the technical tells.\n// Storyletter showed the raw compiler string and labelled it `path [where]`\n// (ui-review-2026-09, finding 17), the bracketed id that \"Diagnostics name what\n// the author can see\" (design-language.md) rules out for anything but a\n// DANGLING reference. This module is the translator; the tables are the\n// apps', because the codes are theirs. `defaultProblemCopy` covers the handful\n// of codes both validators raise in some form, as a floor an app spreads into\n// its own table.\n// ---------------------------------------------------------------------------\n\n/** What a translator needs to know about a problem. `code` is the app's own\n * category (Patterpad's `detail`, or a code Storyletter derives from its\n * compiler message); `title` is the author-facing name of the thing the\n * problem is about, when the app can resolve one; `where` is the raw\n * reference (an id) for when it cannot. */\nexport interface ProblemLike {\n code?: string;\n message: string;\n path?: string;\n where?: string;\n title?: string;\n}\n\nexport interface ProblemCopy {\n /** The sentence: what is wrong, in the author's words. */\n text: string;\n /** What to do about it, when there is one thing to do. */\n next?: string;\n /** The reference this problem is about no longer has a name to give, so the\n * raw id may be shown, written `(id ...)` so it cannot be mistaken for a\n * name. Set by the table entry; the translator never guesses it. */\n dangling?: boolean;\n}\n\nexport type ProblemCopyEntry = (problem: ProblemLike) => ProblemCopy;\nexport type ProblemCopyTable = Record<string, ProblemCopyEntry>;\n\n/** The name to call the thing a problem is about: its title in curly quotes,\n * \"(id ...)\" only when the reference dangles and there is nothing else,\n * and \"This\" otherwise, because the bar's \"go to\" shows the reader what\n * \"this\" is and an id is not something they can look for. */\nexport function problemName(p: ProblemLike, dangling = false): string {\n if (p.title) return `“${p.title}”`;\n if (dangling && p.where) return `(id ${p.where})`;\n return \"This\";\n}\n\n/**\n * Translate `problem` through `table`. A matching entry decides the copy; with\n * no entry the raw message is kept and prefixed by the title when there is one\n * (\"Burner Rig: duplicate id\"). Nothing here ever writes `[where]`; an id\n * appears only as `(id ...)`, only when the entry says the reference dangles,\n * and only when there is no title to say instead.\n */\nexport function describeProblem(problem: ProblemLike, table: ProblemCopyTable = {}): ProblemCopy {\n const entry = problem.code ? table[problem.code] : undefined;\n if (entry) {\n const copy = entry(problem);\n const text = copy.dangling && !problem.title && problem.where && !copy.text.includes(`(id ${problem.where})`)\n ? `${copy.text} (id ${problem.where})`\n : copy.text;\n return copy.next ? { text, next: copy.next } : { text };\n }\n const message = problem.message.replace(/\\s*\\[[^\\]]*\\]\\s*$/, \"\").trim();\n return { text: problem.title ? `${problem.title}: ${message}` : message };\n}\n\n/** `describeProblem` as one line for a bar that has room for one: the sentence,\n * then the next step after a space. */\nexport function problemLine(problem: ProblemLike, table?: ProblemCopyTable): string {\n const { text, next } = describeProblem(problem, table);\n return next ? `${text} ${next}` : text;\n}\n\n/**\n * The codes both validators raise in some form, in the family's voice. An app\n * spreads this into its own table and adds its own codes over it; a code an\n * app does not raise costs nothing.\n *\n * duplicate-gameid two things share one Game ID\n * invalid-gameid a Game ID that breaks the address rule\n * dangling-reference a jump / tag / property points at something gone\n * unknown-property a condition or effect names an undeclared property\n * missing-name a thing that needs a name has none\n * empty a container with nothing in it\n * stale-build the playable build is older than the source\n * merge-conflict a file still carries conflict markers\n */\nexport const defaultProblemCopy: ProblemCopyTable = {\n \"duplicate-gameid\": (p) => ({\n text: `The Game ID on ${problemName(p)} is already used elsewhere.`,\n next: \"Each one must be unique; change one of them.\",\n }),\n \"invalid-gameid\": (p) => ({\n text: `The Game ID on ${problemName(p)} isn't valid.`,\n next: \"Use lowercase letters, digits and hyphens.\",\n }),\n \"dangling-reference\": (p) => ({\n text: `${problemName(p, true)} points at something that no longer exists.`,\n next: \"Choose where it goes.\",\n dangling: true,\n }),\n \"unknown-property\": (p) => ({\n text: `${problemName(p)} uses a property that isn't set up yet.`,\n next: \"Declare it in the project settings, or fix the name.\",\n }),\n \"missing-name\": (p) => ({ text: `${problemName(p)} needs a name.` }),\n \"empty\": (p) => ({\n text: `${problemName(p)} is empty.`,\n next: \"Add something inside it, or remove it.\",\n }),\n \"stale-build\": (p) => ({\n text: `Your playable build${p.path ? ` (${p.path})` : \"\"} is out of date.`,\n next: \"It refreshes the next time you publish.\",\n }),\n \"merge-conflict\": (p) => ({\n text: `${p.path ?? \"This file\"} still has an unresolved merge conflict in it.`,\n next: \"Resolve it in your version control tool, then reopen the project.\",\n }),\n};\n"]}
@@ -0,0 +1,57 @@
1
+ /** What a translator needs to know about a problem. `code` is the app's own
2
+ * category (Patterpad's `detail`, or a code Storyletter derives from its
3
+ * compiler message); `title` is the author-facing name of the thing the
4
+ * problem is about, when the app can resolve one; `where` is the raw
5
+ * reference (an id) for when it cannot. */
6
+ interface ProblemLike {
7
+ code?: string;
8
+ message: string;
9
+ path?: string;
10
+ where?: string;
11
+ title?: string;
12
+ }
13
+ interface ProblemCopy {
14
+ /** The sentence: what is wrong, in the author's words. */
15
+ text: string;
16
+ /** What to do about it, when there is one thing to do. */
17
+ next?: string;
18
+ /** The reference this problem is about no longer has a name to give, so the
19
+ * raw id may be shown, written `(id ...)` so it cannot be mistaken for a
20
+ * name. Set by the table entry; the translator never guesses it. */
21
+ dangling?: boolean;
22
+ }
23
+ type ProblemCopyEntry = (problem: ProblemLike) => ProblemCopy;
24
+ type ProblemCopyTable = Record<string, ProblemCopyEntry>;
25
+ /** The name to call the thing a problem is about: its title in curly quotes,
26
+ * "(id ...)" only when the reference dangles and there is nothing else,
27
+ * and "This" otherwise, because the bar's "go to" shows the reader what
28
+ * "this" is and an id is not something they can look for. */
29
+ declare function problemName(p: ProblemLike, dangling?: boolean): string;
30
+ /**
31
+ * Translate `problem` through `table`. A matching entry decides the copy; with
32
+ * no entry the raw message is kept and prefixed by the title when there is one
33
+ * ("Burner Rig: duplicate id"). Nothing here ever writes `[where]`; an id
34
+ * appears only as `(id ...)`, only when the entry says the reference dangles,
35
+ * and only when there is no title to say instead.
36
+ */
37
+ declare function describeProblem(problem: ProblemLike, table?: ProblemCopyTable): ProblemCopy;
38
+ /** `describeProblem` as one line for a bar that has room for one: the sentence,
39
+ * then the next step after a space. */
40
+ declare function problemLine(problem: ProblemLike, table?: ProblemCopyTable): string;
41
+ /**
42
+ * The codes both validators raise in some form, in the family's voice. An app
43
+ * spreads this into its own table and adds its own codes over it; a code an
44
+ * app does not raise costs nothing.
45
+ *
46
+ * duplicate-gameid two things share one Game ID
47
+ * invalid-gameid a Game ID that breaks the address rule
48
+ * dangling-reference a jump / tag / property points at something gone
49
+ * unknown-property a condition or effect names an undeclared property
50
+ * missing-name a thing that needs a name has none
51
+ * empty a container with nothing in it
52
+ * stale-build the playable build is older than the source
53
+ * merge-conflict a file still carries conflict markers
54
+ */
55
+ declare const defaultProblemCopy: ProblemCopyTable;
56
+
57
+ export { type ProblemCopy, type ProblemCopyEntry, type ProblemCopyTable, type ProblemLike, defaultProblemCopy, describeProblem, problemLine, problemName };
@@ -0,0 +1,57 @@
1
+ /** What a translator needs to know about a problem. `code` is the app's own
2
+ * category (Patterpad's `detail`, or a code Storyletter derives from its
3
+ * compiler message); `title` is the author-facing name of the thing the
4
+ * problem is about, when the app can resolve one; `where` is the raw
5
+ * reference (an id) for when it cannot. */
6
+ interface ProblemLike {
7
+ code?: string;
8
+ message: string;
9
+ path?: string;
10
+ where?: string;
11
+ title?: string;
12
+ }
13
+ interface ProblemCopy {
14
+ /** The sentence: what is wrong, in the author's words. */
15
+ text: string;
16
+ /** What to do about it, when there is one thing to do. */
17
+ next?: string;
18
+ /** The reference this problem is about no longer has a name to give, so the
19
+ * raw id may be shown, written `(id ...)` so it cannot be mistaken for a
20
+ * name. Set by the table entry; the translator never guesses it. */
21
+ dangling?: boolean;
22
+ }
23
+ type ProblemCopyEntry = (problem: ProblemLike) => ProblemCopy;
24
+ type ProblemCopyTable = Record<string, ProblemCopyEntry>;
25
+ /** The name to call the thing a problem is about: its title in curly quotes,
26
+ * "(id ...)" only when the reference dangles and there is nothing else,
27
+ * and "This" otherwise, because the bar's "go to" shows the reader what
28
+ * "this" is and an id is not something they can look for. */
29
+ declare function problemName(p: ProblemLike, dangling?: boolean): string;
30
+ /**
31
+ * Translate `problem` through `table`. A matching entry decides the copy; with
32
+ * no entry the raw message is kept and prefixed by the title when there is one
33
+ * ("Burner Rig: duplicate id"). Nothing here ever writes `[where]`; an id
34
+ * appears only as `(id ...)`, only when the entry says the reference dangles,
35
+ * and only when there is no title to say instead.
36
+ */
37
+ declare function describeProblem(problem: ProblemLike, table?: ProblemCopyTable): ProblemCopy;
38
+ /** `describeProblem` as one line for a bar that has room for one: the sentence,
39
+ * then the next step after a space. */
40
+ declare function problemLine(problem: ProblemLike, table?: ProblemCopyTable): string;
41
+ /**
42
+ * The codes both validators raise in some form, in the family's voice. An app
43
+ * spreads this into its own table and adds its own codes over it; a code an
44
+ * app does not raise costs nothing.
45
+ *
46
+ * duplicate-gameid two things share one Game ID
47
+ * invalid-gameid a Game ID that breaks the address rule
48
+ * dangling-reference a jump / tag / property points at something gone
49
+ * unknown-property a condition or effect names an undeclared property
50
+ * missing-name a thing that needs a name has none
51
+ * empty a container with nothing in it
52
+ * stale-build the playable build is older than the source
53
+ * merge-conflict a file still carries conflict markers
54
+ */
55
+ declare const defaultProblemCopy: ProblemCopyTable;
56
+
57
+ export { type ProblemCopy, type ProblemCopyEntry, type ProblemCopyTable, type ProblemLike, defaultProblemCopy, describeProblem, problemLine, problemName };
@@ -0,0 +1,3 @@
1
+ export { defaultProblemCopy, describeProblem, problemLine, problemName } from './chunk-DS4XXAZS.js';
2
+ //# sourceMappingURL=problems.js.map
3
+ //# sourceMappingURL=problems.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"problems.js"}
@@ -0,0 +1,162 @@
1
+ /** A compact list row: a single `.set-rowline` (inline controls) plus, when
2
+ * `details` are given, a disclosure that reveals a `.set-details` panel below,
3
+ * so a list scans like a table with secondary fields tucked away. `name` is
4
+ * what the row declares (a property's name, a field's), stamped on it as
5
+ * `data-name` so `revealRow` can land on it. */
6
+ declare function expandableRow(opts: {
7
+ line: HTMLElement[];
8
+ details?: HTMLElement[];
9
+ name?: string;
10
+ }): HTMLElement;
11
+ /**
12
+ * Land on one row of a list by the `name` it was built with: open its details
13
+ * (an enum's values sit behind the disclosure, and they are usually what the
14
+ * jump was for), bring it to the middle of its scroller, and light it for a
15
+ * moment (`.set-row.landed` in settings.css). "Go to definition" in both apps
16
+ * used to open the page a property is declared on and stop there, with the
17
+ * declaration below the fold and nothing marking it (Storyletter, 2026-09-14).
18
+ *
19
+ * Returns false when no row carries the name, so a host whose page fills in
20
+ * asynchronously can ask again on a later frame; asking again is the host's,
21
+ * since only the host knows what opens on its own time. The row is matched by
22
+ * reading the stamp rather than by an attribute selector, so a name needs no
23
+ * escaping.
24
+ */
25
+ declare function revealRow(within: ParentNode, name: string): boolean;
26
+ /**
27
+ * `revealRow`, retried over the next frames until the row exists or the tries
28
+ * run out: for a page that fills in on its own time after a navigation. Both
29
+ * apps hand-rolled this as `landOn` with the same twelve tries
30
+ * (ui-review-2026-09, finding 29). Resolves true when it landed, false when it
31
+ * gave up, and giving up is quiet: a name no page shows as a row is not a fault.
32
+ */
33
+ declare function revealRowWhenReady(within: ParentNode, name: string, tries?: number): Promise<boolean>;
34
+ /** After a "+ Add" re-renders a list, bring the new (last) row into view and
35
+ * focus its name input (`.set-name`, else the first input). */
36
+ declare function focusNewRow(listEl: HTMLElement | null | undefined): void;
37
+ interface DupGuard {
38
+ /** Forget the previous render's inputs (call at the top of render). */
39
+ reset(): void;
40
+ /** Register a name input; `key` returns the comparison string (default the
41
+ * input's value). Re-checks live on input. `also` = extra inputs that change the key. */
42
+ track(input: HTMLInputElement, key?: () => string, also?: HTMLInputElement[]): void;
43
+ /** Re-paint duplicates; true if any two non-blank keys collide. */
44
+ check(): boolean;
45
+ /** The first input currently flagged (after a fresh check), or null. */
46
+ firstDuplicate(): HTMLInputElement | null;
47
+ }
48
+ /** Case-insensitive duplicate-name detection: paints clashing inputs `.invalid`
49
+ * and lets a Save gate block + jump via `firstDuplicate()`. */
50
+ declare function dupGuard(): DupGuard;
51
+ interface SettingsSectionHandle {
52
+ /** The first invalid control to jump to, blocking Save (e.g. a duplicate
53
+ * name). Return `{ el, message }` to say WHICH fault in the error line;
54
+ * a bare element says it through its own `data-tip` (the dup guard's, a
55
+ * property-name field's), and the line falls back to a generic sentence
56
+ * when it has neither. */
57
+ firstInvalid?(): HTMLElement | {
58
+ el: HTMLElement;
59
+ message?: string;
60
+ } | null;
61
+ }
62
+ interface SettingsSection {
63
+ id: string;
64
+ label: string;
65
+ /** Optional left-rail group heading above this tab. */
66
+ group?: string;
67
+ /** Build the section body into `host`; called fresh on each open so it reads
68
+ * the current data. Return a handle (for the Save gate). */
69
+ mount(host: HTMLElement): SettingsSectionHandle;
70
+ /** Why this tab cannot be used right now, or null when it can. A reason
71
+ * renders the tab dimmed and inert with the reason as its rollover
72
+ * (Patterpad's Audio tab while the project is not voiced). Read on open
73
+ * and on `refreshTabs()`, so a control inside the dialog can flip it. */
74
+ disabled?: () => string | null;
75
+ }
76
+ interface SettingsDialogOptions {
77
+ title: string;
78
+ sections: SettingsSection[];
79
+ /** Fired when Save is clicked and every section validates. The app reads its
80
+ * own section state and persists. May be async; the dialog stays open until
81
+ * it resolves, then closes. */
82
+ onSave: () => void | Promise<void>;
83
+ }
84
+ interface SettingsDialog {
85
+ /** Open (optionally on a given tab id). Sections re-mount from current data. */
86
+ open(tabId?: string): void;
87
+ /** Re-read every section's `disabled()`; a tab that has just become
88
+ * disabled while showing hands over to the first usable one. */
89
+ refreshTabs(): void;
90
+ destroy(): void;
91
+ }
92
+ /** Build a settings dialog. The frame owns the modal, the tab rail, save-on-Save
93
+ * (with a validation gate), and Cancel; the sections own their content + state. */
94
+ declare function mountSettingsDialog(opts: SettingsDialogOptions): SettingsDialog;
95
+
96
+ /** The six types both apps declare. */
97
+ type PropertyListType = "number" | "boolean" | "string" | "enum" | "flags" | "quality";
98
+ /** The shape a row edits. Apps' DTOs carry more (shared, writable, durable);
99
+ * those ride through untouched. */
100
+ interface PropertyDeclLike {
101
+ name: string;
102
+ type: string;
103
+ default?: unknown;
104
+ /** enum / flags */
105
+ values?: string[];
106
+ /** quality: the ladder, in order */
107
+ stages?: string[];
108
+ purpose?: string;
109
+ }
110
+ /** The type list, in the family's order, with the words the select shows. */
111
+ declare const PROPERTY_TYPES: ReadonlyArray<readonly [PropertyListType, string]>;
112
+ interface DefaultControlOptions {
113
+ /**
114
+ * How the default is stored. `false` (default): the string the field shows,
115
+ * "" for none (Storyletter's DTO). `true`: a typed value (boolean, number,
116
+ * string), and none DELETES the key (Patterpad's model).
117
+ */
118
+ typed?: boolean;
119
+ }
120
+ /**
121
+ * The type-appropriate control for a declaration's DEFAULT: a true / false
122
+ * picker for a boolean, the value list for an enum, the stage list for a
123
+ * quality (blank = the first rung), a note for flags (a set starts empty), a
124
+ * number or text field otherwise. The one label for "no default" is "(none)".
125
+ */
126
+ declare function defaultControl(p: PropertyDeclLike, onChange?: () => void, opts?: DefaultControlOptions): HTMLElement;
127
+ interface PropertyListOptions<T extends PropertyDeclLike> extends DefaultControlOptions {
128
+ /** Called after every mutation; a centre editor feeds its autosave here. */
129
+ onChange?: () => void;
130
+ /** The add button's label. Default "+ Add property". */
131
+ addLabel?: string;
132
+ /** The empty sentence. Default "No properties yet." */
133
+ emptyText?: string;
134
+ /** The type select's entries; default `PROPERTY_TYPES`. */
135
+ types?: ReadonlyArray<readonly [string, string]>;
136
+ /** A fresh declaration for the add button. Default: a blank of the first type. */
137
+ newDecl?: () => T;
138
+ /** Controls on the row's line, between the default and the movers
139
+ * (Storyletter's "uses" affordance). */
140
+ extraLine?: (decl: T, index: number) => (HTMLElement | null)[];
141
+ /** Fields behind the disclosure, before Values / Stages / Purpose
142
+ * (Shared, Temporary, Read-only, Durable). */
143
+ extraDetails?: (decl: T, index: number) => (HTMLElement | null)[];
144
+ /** Offer the Purpose field. Default true. */
145
+ purpose?: boolean;
146
+ }
147
+ interface PropertyListHandle extends SettingsSectionHandle {
148
+ /** Both faults, for the Save gate: a duplicate first, then an illegal name. */
149
+ firstInvalid(): HTMLInputElement | null;
150
+ /** The first name that clashes with another, or null. */
151
+ firstDuplicate(): HTMLInputElement | null;
152
+ /** The first name no expression could reach, or null. */
153
+ firstIllegalName(): HTMLInputElement | null;
154
+ /** Redraw from `decls` (after an outside change). */
155
+ render(): void;
156
+ }
157
+ /** Mount the list into `host`. Mutates `decls` in place; the caller reads
158
+ * them back on save (pruning blank names is the caller's, since only it
159
+ * knows its DTO). */
160
+ declare function mountPropertyList<T extends PropertyDeclLike>(host: HTMLElement, decls: T[], opts?: PropertyListOptions<T>): PropertyListHandle;
161
+
162
+ export { type DefaultControlOptions as D, PROPERTY_TYPES as P, type SettingsDialog as S, type DupGuard as a, type PropertyDeclLike as b, type PropertyListHandle as c, type PropertyListOptions as d, type PropertyListType as e, type SettingsDialogOptions as f, type SettingsSection as g, type SettingsSectionHandle as h, defaultControl as i, dupGuard as j, expandableRow as k, focusNewRow as l, mountPropertyList as m, mountSettingsDialog as n, revealRowWhenReady as o, revealRow as r };