@wildwinter/app-shell 0.17.0 → 0.19.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.
- package/README.md +52 -4
- package/dist/anchored.css +5 -0
- package/dist/anchored.css.map +1 -1
- package/dist/comments.css +7 -0
- package/dist/comments.css.map +1 -1
- package/dist/index.cjs +129 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +101 -1
- package/dist/index.d.ts +101 -1
- package/dist/index.js +126 -16
- package/dist/index.js.map +1 -1
- package/dist/notes-editor.css +1 -1
- package/dist/notes-editor.css.map +1 -1
- package/dist/save.css +37 -0
- package/dist/save.css.map +1 -0
- package/dist/stale.css +30 -0
- package/dist/stale.css.map +1 -0
- package/dist/stepper.css +98 -0
- package/dist/stepper.css.map +1 -0
- package/dist/tokens.css +2 -1
- package/dist/tokens.css.map +1 -1
- package/package.json +13 -1
package/README.md
CHANGED
|
@@ -64,13 +64,61 @@ event loop (16ms), so a fast inner loop neither floods IPC nor stutters.
|
|
|
64
64
|
**A strip, not a modal.** The window that started the job shows it; the rest of
|
|
65
65
|
the app stays usable.
|
|
66
66
|
|
|
67
|
+
## v0.18 (the bars, and the third semantic colour)
|
|
68
|
+
|
|
69
|
+
Three drawings each app had grown its own copy of, and the token the family kept
|
|
70
|
+
needing and never had.
|
|
71
|
+
|
|
72
|
+
- **`renderStepperBar`** - a bottom bar that walks a list of things to attend to,
|
|
73
|
+
one at a time: count, previous, position, next, the entry as a button, an
|
|
74
|
+
action slot. Four bars across the two apps are this shape (problems, review
|
|
75
|
+
walks). It knows about a list and an index; it knows nothing about what a
|
|
76
|
+
problem or a comment is.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { renderStepperBar } from "@wildwinter/app-shell";
|
|
80
|
+
import "@wildwinter/app-shell/stepper.css";
|
|
81
|
+
renderStepperBar(host, {
|
|
82
|
+
items: problems.map((p) => ({ kind: p.severity, kindClass: `sev-${p.severity}`, where: p.path, text: p.message })),
|
|
83
|
+
at, tone: "danger", onStep: (i) => { at = i; paint(); }, onGo: (i) => jumpTo(problems[i]),
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Whether stepping NAVIGATES is the caller's decision, and the bar takes no view:
|
|
88
|
+
an ambient surface moves the view and never the focus; a mode you entered may
|
|
89
|
+
take you somewhere.
|
|
90
|
+
|
|
91
|
+
- **`saveIndicator`** - the six lines that draw what `createSaveController`
|
|
92
|
+
already computes. Three states, always present: a dot that only ever appears
|
|
93
|
+
to worry you leaves "did that get written?" unanswered.
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
const ind = saveIndicator();
|
|
97
|
+
topbar.append(ind.el);
|
|
98
|
+
const saver = createSaveController({ write, onStatus: ind.set });
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- **`staleBar`** - a running session that has fallen behind its source. The app
|
|
102
|
+
supplies the noun and the callback; the sentence is shared, because both apps
|
|
103
|
+
had written it independently and landed a word apart.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
staleBar({ subject: "The project", onRestart: () => void rebuild() });
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- **`--ok`** joins `--danger` and `--warn` in `tokens.css`, with a `light-dark()`
|
|
110
|
+
default every palette should override in its own `theme.css`. It is the only
|
|
111
|
+
colour in the grammar layer, and it is there because it kept not being
|
|
112
|
+
anywhere: "all is well" was being met with raw green literals that could not
|
|
113
|
+
theme-shift.
|
|
114
|
+
|
|
67
115
|
## Roadmap
|
|
68
116
|
|
|
69
117
|
Later slices lift the rest of the common shell from Patterpad (canonical),
|
|
70
|
-
reconciling Storylet Studio's variants: the pane grid + toggles, the
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
118
|
+
reconciling Storylet Studio's variants: the pane grid + toggles, the command
|
|
119
|
+
palette, and version control's renderer half. Storylet Studio migrates each
|
|
120
|
+
first (proving app-agnosticism); Patterpad follows - see
|
|
121
|
+
`patterkit/design/from-storylets/patterpad-onto-the-shell.md` for that order.
|
|
74
122
|
|
|
75
123
|
## Release
|
|
76
124
|
|
package/dist/anchored.css
CHANGED
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
color: var(--ink);
|
|
11
11
|
box-shadow: var(--shadow-2, var(--shadow-1));
|
|
12
12
|
overflow: hidden;
|
|
13
|
+
animation: var(--anim-panel-in);
|
|
14
|
+
}
|
|
15
|
+
.shell-anchored.closing {
|
|
16
|
+
animation: var(--anim-panel-out);
|
|
17
|
+
pointer-events: none;
|
|
13
18
|
}
|
|
14
19
|
.shell-anchored-head {
|
|
15
20
|
flex: none;
|
package/dist/anchored.css.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/anchored.css"],"sourcesContent":["/* The anchored panel (anchored.ts): a floating panel hung off the thing it is\n about. Sized and positioned in script (the placement has to measure); this is\n only what it looks like. Its body scrolls, because the placement caps the\n height rather than letting a long thread run off the screen. */\n.shell-anchored {\n position: fixed; z-index: 40;\n display: flex; flex-direction: column;\n border: 1px solid var(--line);\n border-radius: var(--radius-md);\n background: var(--surface); color: var(--ink);\n box-shadow: var(--shadow-2, var(--shadow-1));\n overflow: hidden;\n}\n.shell-anchored-head {\n flex: none;\n display: flex; align-items: center; justify-content: space-between; gap: 8px;\n padding: 8px 10px;\n border-bottom: 1px solid var(--line-soft);\n}\n.shell-anchored-title {\n font: 600 0.72rem/1 var(--font-ui);\n text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted);\n}\n.shell-anchored-close {\n border: 0; background: none; color: var(--muted);\n font-size: 0.8rem; line-height: 1; padding: 0 2px; cursor: pointer;\n}\n.shell-anchored-close:hover { color: var(--accent); }\n.shell-anchored-body {\n flex: 1; min-height: 0; overflow-y: auto;\n display: flex; flex-direction: column; gap: 8px;\n padding: 10px;\n}\n\n/* The gameId editor (id-editor.ts). Refusal is the whole point of the design, so\n it has to LOOK refused: the hint reddens and Set goes flat. */\n.shell-id-editor .shell-anchored-body { display: flex; flex-direction: column; gap: 8px; }\n.shell-id-input {\n font: 0.82rem var(--font-mono, monospace);\n padding: 5px 8px; border: 1px solid var(--line); border-radius: var(--radius-sm);\n background: var(--card); color: var(--ink);\n}\n.shell-id-hint { font: 0.74rem/1.4 var(--font-ui); color: var(--muted); }\n.shell-id-hint.bad { color: var(--danger, #b00); }\n.shell-id-actions { display: flex; align-items: center; justify-content: space-between; gap: 8px; }\n.shell-id-reset {\n font: 0.74rem var(--font-ui); padding: 3px 10px; cursor: pointer;\n background: none; border: 1px dashed var(--line); border-radius: var(--radius-sm); color: var(--muted);\n}\n.shell-id-reset:hover { border-color: var(--accent); color: var(--accent); }\n.shell-id-set {\n font: 0.78rem var(--font-ui); padding: 3px 12px; cursor: pointer;\n border: 1px solid var(--accent); border-radius: var(--radius-sm);\n background: var(--accent); color: var(--surface);\n}\n.shell-id-set:disabled {\n cursor: default; background: none; color: var(--muted); border-color: var(--line);\n}\n"],"mappings":";AAIA,CAAC;AACC,YAAU;AAAO,WAAS;AAC1B,WAAS;AAAM,kBAAgB;AAC/B,UAAQ,IAAI,MAAM,IAAI;AACtB,iBAAe,IAAI;AACnB,cAAY,IAAI;AAAY,SAAO,IAAI;AACvC,cAAY,IAAI,UAAU,EAAE,IAAI;AAChC,YAAU;
|
|
1
|
+
{"version":3,"sources":["../src/anchored.css"],"sourcesContent":["/* The anchored panel (anchored.ts): a floating panel hung off the thing it is\n about. Sized and positioned in script (the placement has to measure); this is\n only what it looks like. Its body scrolls, because the placement caps the\n height rather than letting a long thread run off the screen. */\n.shell-anchored {\n position: fixed; z-index: 40;\n display: flex; flex-direction: column;\n border: 1px solid var(--line);\n border-radius: var(--radius-md);\n background: var(--surface); color: var(--ink);\n box-shadow: var(--shadow-2, var(--shadow-1));\n overflow: hidden;\n /* The family's panel motion. Placement is set in script as left/top, so a\n transform-based keyframe composes with it rather than fighting it. */\n animation: var(--anim-panel-in);\n}\n/* Exit: .closing swaps the enter keyframe for its reverse, and the fading panel\n stops taking clicks so a second press cannot reach a control on its way out.\n Zero-duration under prefers-reduced-motion, where teardown is immediate. */\n.shell-anchored.closing { animation: var(--anim-panel-out); pointer-events: none; }\n.shell-anchored-head {\n flex: none;\n display: flex; align-items: center; justify-content: space-between; gap: 8px;\n padding: 8px 10px;\n border-bottom: 1px solid var(--line-soft);\n}\n.shell-anchored-title {\n font: 600 0.72rem/1 var(--font-ui);\n text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted);\n}\n.shell-anchored-close {\n border: 0; background: none; color: var(--muted);\n font-size: 0.8rem; line-height: 1; padding: 0 2px; cursor: pointer;\n}\n.shell-anchored-close:hover { color: var(--accent); }\n.shell-anchored-body {\n flex: 1; min-height: 0; overflow-y: auto;\n display: flex; flex-direction: column; gap: 8px;\n padding: 10px;\n}\n\n/* The gameId editor (id-editor.ts). Refusal is the whole point of the design, so\n it has to LOOK refused: the hint reddens and Set goes flat. */\n.shell-id-editor .shell-anchored-body { display: flex; flex-direction: column; gap: 8px; }\n.shell-id-input {\n font: 0.82rem var(--font-mono, monospace);\n padding: 5px 8px; border: 1px solid var(--line); border-radius: var(--radius-sm);\n background: var(--card); color: var(--ink);\n}\n.shell-id-hint { font: 0.74rem/1.4 var(--font-ui); color: var(--muted); }\n.shell-id-hint.bad { color: var(--danger, #b00); }\n.shell-id-actions { display: flex; align-items: center; justify-content: space-between; gap: 8px; }\n.shell-id-reset {\n font: 0.74rem var(--font-ui); padding: 3px 10px; cursor: pointer;\n background: none; border: 1px dashed var(--line); border-radius: var(--radius-sm); color: var(--muted);\n}\n.shell-id-reset:hover { border-color: var(--accent); color: var(--accent); }\n.shell-id-set {\n font: 0.78rem var(--font-ui); padding: 3px 12px; cursor: pointer;\n border: 1px solid var(--accent); border-radius: var(--radius-sm);\n background: var(--accent); color: var(--surface);\n}\n.shell-id-set:disabled {\n cursor: default; background: none; color: var(--muted); border-color: var(--line);\n}\n"],"mappings":";AAIA,CAAC;AACC,YAAU;AAAO,WAAS;AAC1B,WAAS;AAAM,kBAAgB;AAC/B,UAAQ,IAAI,MAAM,IAAI;AACtB,iBAAe,IAAI;AACnB,cAAY,IAAI;AAAY,SAAO,IAAI;AACvC,cAAY,IAAI,UAAU,EAAE,IAAI;AAChC,YAAU;AAGV,aAAW,IAAI;AACjB;AAIA,CAfC,cAec,CAAC;AAAU,aAAW,IAAI;AAAmB,kBAAgB;AAAM;AAClF,CAAC;AACC,QAAM;AACN,WAAS;AAAM,eAAa;AAAQ,mBAAiB;AAAe,OAAK;AACzE,WAAS,IAAI;AACb,iBAAe,IAAI,MAAM,IAAI;AAC/B;AACA,CAAC;AACC,QAAM,IAAI,OAAO,CAAC,EAAE,IAAI;AACxB,kBAAgB;AAAW,kBAAgB;AAAQ,SAAO,IAAI;AAChE;AACA,CAAC;AACC,UAAQ;AAAG,cAAY;AAAM,SAAO,IAAI;AACxC,aAAW;AAAQ,eAAa;AAAG,WAAS,EAAE;AAAK,UAAQ;AAC7D;AACA,CAJC,oBAIoB;AAAS,SAAO,IAAI;AAAW;AACpD,CAAC;AACC,QAAM;AAAG,cAAY;AAAG,cAAY;AACpC,WAAS;AAAM,kBAAgB;AAAQ,OAAK;AAC5C,WAAS;AACX;AAIA,CAAC,gBAAgB,CARhB;AAQuC,WAAS;AAAM,kBAAgB;AAAQ,OAAK;AAAK;AACzF,CAAC;AACC,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,WAAS,IAAI;AAAK,UAAQ,IAAI,MAAM,IAAI;AAAS,iBAAe,IAAI;AACpE,cAAY,IAAI;AAAS,SAAO,IAAI;AACtC;AACA,CAAC;AAAgB,QAAM,OAAO,CAAC,IAAI,IAAI;AAAY,SAAO,IAAI;AAAU;AACxE,CADC,aACa,CAAC;AAAM,SAAO,IAAI,QAAQ,EAAE;AAAO;AACjD,CAAC;AAAmB,WAAS;AAAM,eAAa;AAAQ,mBAAiB;AAAe,OAAK;AAAK;AAClG,CAAC;AACC,QAAM,QAAQ,IAAI;AAAY,WAAS,IAAI;AAAM,UAAQ;AACzD,cAAY;AAAM,UAAQ,IAAI,OAAO,IAAI;AAAS,iBAAe,IAAI;AAAc,SAAO,IAAI;AAChG;AACA,CAJC,cAIc;AAAS,gBAAc,IAAI;AAAW,SAAO,IAAI;AAAW;AAC3E,CAAC;AACC,QAAM,QAAQ,IAAI;AAAY,WAAS,IAAI;AAAM,UAAQ;AACzD,UAAQ,IAAI,MAAM,IAAI;AAAW,iBAAe,IAAI;AACpD,cAAY,IAAI;AAAW,SAAO,IAAI;AACxC;AACA,CALC,YAKY;AACX,UAAQ;AAAS,cAAY;AAAM,SAAO,IAAI;AAAU,gBAAc,IAAI;AAC5E;","names":[]}
|
package/dist/comments.css
CHANGED
package/dist/comments.css.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/comments.css"],"sourcesContent":["/* A comment thread inside the anchored panel (comments.ts). */\n.shell-cmt-list { display: flex; flex-direction: column; gap: 8px; }\n.shell-cmt-list.resolved { opacity: 0.55; }\n.shell-cmt-msg-head { display: flex; gap: 8px; align-items: baseline; }\n/* The delete: QUIET but always there.\n It was rollover-revealed at first, following the grip grammar the lists use,\n and that was the wrong borrowing: a list row hides its grip because a dense\n column of them would be clutter, whereas this popover holds two or three\n messages and is already a surface you opened on purpose. Hidden, the only\n way to delete a comment was to discover that hovering one exact row revealed\n something - which is to say there was no way to delete a comment. Reported as\n \"there is apparently no delete option\", which is exactly right.\n Low contrast carries \"secondary\"; invisibility carries \"absent\". */\n.shell-cmt-del {\n margin-left: auto; flex: none; padding: 0 4px; line-height: 1;\n background: none; border: none; cursor: pointer;\n font-size: 0.72rem; color: var(--muted); opacity: 0.55;\n transition: opacity var(--dur-quick, 120ms) var(--ease-standard, ease),\n color var(--dur-quick, 120ms) var(--ease-standard, ease);\n}\n.shell-cmt-msg:hover .shell-cmt-del, .shell-cmt-del:focus-visible { opacity: 1; }\n.shell-cmt-del:hover { opacity: 1; color: var(--danger, #b00); }\n/* A withdrawn message keeps its place in the thread and stops asking to be read. */\n.shell-cmt-msg.gone .shell-cmt-body { font-style: italic; color: var(--muted); }\n.shell-cmt-author { font: 600 0.76rem/1.2 var(--font-ui); }\n.shell-cmt-ts { font: 0.68rem/1.2 var(--font-ui); color: var(--muted); }\n.shell-cmt-body { font: 0.82rem/1.45 var(--font-read, var(--font-ui)); white-space: pre-wrap; }\n.shell-cmt-input {\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.82rem/1.4 var(--font-read, var(--font-ui)); padding: 6px 8px;\n}\n.shell-cmt-input:focus { outline: none; border-color: var(--accent); }\n.shell-cmt-actions { display: flex; gap: 6px; justify-content: flex-end; }\n.shell-cmt-btn {\n font: 0.76rem/1 var(--font-ui); padding: 5px 10px;\n border-radius: var(--radius-sm); border: 1px solid var(--line);\n background: var(--card); color: var(--ink); cursor: pointer;\n}\n.shell-cmt-btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent, #fff); }\n/* The picker, when one thing has more than one thread. */\n.shell-cmt-row {\n display: flex; gap: 6px; align-items: baseline; width: 100%; text-align: left;\n border: 0; background: none; color: var(--ink); cursor: pointer;\n padding: 6px 4px; border-radius: var(--radius-sm);\n}\n.shell-cmt-row:hover { background: var(--accent-soft); }\n.shell-cmt-row.resolved { opacity: 0.55; }\n.shell-cmt-row-author { font: 600 0.74rem/1.2 var(--font-ui); flex: none; }\n.shell-cmt-row-gist {\n font: 0.78rem/1.3 var(--font-read, var(--font-ui)); color: var(--muted);\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n}\n.shell-cmt-row-count { margin-left: auto; font: 0.7rem/1 var(--font-ui); color: var(--muted); }\n.shell-cmt-new {\n align-self: flex-start; font: 0.76rem/1 var(--font-ui);\n border: 1px dashed var(--line); background: none; color: var(--muted);\n border-radius: var(--radius-sm); padding: 5px 10px; cursor: pointer;\n}\n.shell-cmt-new:hover { color: var(--accent); border-color: var(--accent); }\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../src/comments.css"],"sourcesContent":["/* A comment thread inside the anchored panel (comments.ts). */\n\n/* The span the thread is pinned to (quoteFor). A quotation rather than a heading:\n these are somebody else's words, not a title the panel gave itself. */\n.shell-cmt-quote {\n margin: 0; padding: 0.2rem 0.5rem;\n border-left: 2px solid var(--accent);\n color: var(--muted); font: italic 0.8rem var(--font-ui);\n}\n\n.shell-cmt-list { display: flex; flex-direction: column; gap: 8px; }\n.shell-cmt-list.resolved { opacity: 0.55; }\n.shell-cmt-msg-head { display: flex; gap: 8px; align-items: baseline; }\n/* The delete: QUIET but always there.\n It was rollover-revealed at first, following the grip grammar the lists use,\n and that was the wrong borrowing: a list row hides its grip because a dense\n column of them would be clutter, whereas this popover holds two or three\n messages and is already a surface you opened on purpose. Hidden, the only\n way to delete a comment was to discover that hovering one exact row revealed\n something - which is to say there was no way to delete a comment. Reported as\n \"there is apparently no delete option\", which is exactly right.\n Low contrast carries \"secondary\"; invisibility carries \"absent\". */\n.shell-cmt-del {\n margin-left: auto; flex: none; padding: 0 4px; line-height: 1;\n background: none; border: none; cursor: pointer;\n font-size: 0.72rem; color: var(--muted); opacity: 0.55;\n transition: opacity var(--dur-quick, 120ms) var(--ease-standard, ease),\n color var(--dur-quick, 120ms) var(--ease-standard, ease);\n}\n.shell-cmt-msg:hover .shell-cmt-del, .shell-cmt-del:focus-visible { opacity: 1; }\n.shell-cmt-del:hover { opacity: 1; color: var(--danger, #b00); }\n/* A withdrawn message keeps its place in the thread and stops asking to be read. */\n.shell-cmt-msg.gone .shell-cmt-body { font-style: italic; color: var(--muted); }\n.shell-cmt-author { font: 600 0.76rem/1.2 var(--font-ui); }\n.shell-cmt-ts { font: 0.68rem/1.2 var(--font-ui); color: var(--muted); }\n.shell-cmt-body { font: 0.82rem/1.45 var(--font-read, var(--font-ui)); white-space: pre-wrap; }\n.shell-cmt-input {\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.82rem/1.4 var(--font-read, var(--font-ui)); padding: 6px 8px;\n}\n.shell-cmt-input:focus { outline: none; border-color: var(--accent); }\n.shell-cmt-actions { display: flex; gap: 6px; justify-content: flex-end; }\n.shell-cmt-btn {\n font: 0.76rem/1 var(--font-ui); padding: 5px 10px;\n border-radius: var(--radius-sm); border: 1px solid var(--line);\n background: var(--card); color: var(--ink); cursor: pointer;\n}\n.shell-cmt-btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent, #fff); }\n/* The picker, when one thing has more than one thread. */\n.shell-cmt-row {\n display: flex; gap: 6px; align-items: baseline; width: 100%; text-align: left;\n border: 0; background: none; color: var(--ink); cursor: pointer;\n padding: 6px 4px; border-radius: var(--radius-sm);\n}\n.shell-cmt-row:hover { background: var(--accent-soft); }\n.shell-cmt-row.resolved { opacity: 0.55; }\n.shell-cmt-row-author { font: 600 0.74rem/1.2 var(--font-ui); flex: none; }\n.shell-cmt-row-gist {\n font: 0.78rem/1.3 var(--font-read, var(--font-ui)); color: var(--muted);\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n}\n.shell-cmt-row-count { margin-left: auto; font: 0.7rem/1 var(--font-ui); color: var(--muted); }\n.shell-cmt-new {\n align-self: flex-start; font: 0.76rem/1 var(--font-ui);\n border: 1px dashed var(--line); background: none; color: var(--muted);\n border-radius: var(--radius-sm); padding: 5px 10px; cursor: pointer;\n}\n.shell-cmt-new:hover { color: var(--accent); border-color: var(--accent); }\n"],"mappings":";AAIA,CAAC;AACC,UAAQ;AAAG,WAAS,OAAO;AAC3B,eAAa,IAAI,MAAM,IAAI;AAC3B,SAAO,IAAI;AAAU,QAAM,OAAO,OAAO,IAAI;AAC/C;AAEA,CAAC;AAAiB,WAAS;AAAM,kBAAgB;AAAQ,OAAK;AAAK;AACnE,CADC,cACc,CAAC;AAAW,WAAS;AAAM;AAC1C,CAAC;AAAqB,WAAS;AAAM,OAAK;AAAK,eAAa;AAAU;AAUtE,CAAC;AACC,eAAa;AAAM,QAAM;AAAM,WAAS,EAAE;AAAK,eAAa;AAC5D,cAAY;AAAM,UAAQ;AAAM,UAAQ;AACxC,aAAW;AAAS,SAAO,IAAI;AAAU,WAAS;AAClD,cAAY,QAAQ,IAAI,WAAW,EAAE,OAAO,IAAI,eAAe,EAAE,KAAK,EACpE,MAAM,IAAI,WAAW,EAAE,OAAO,IAAI,eAAe,EAAE;AACvD;AACA,CAAC,aAAa,OAAO,CAPpB;AAOoC,CAPpC,aAOkD;AAAiB,WAAS;AAAG;AAChF,CARC,aAQa;AAAS,WAAS;AAAG,SAAO,IAAI,QAAQ,EAAE;AAAO;AAE/D,CAHC,aAGa,CAAC,KAAK,CAAC;AAAiB,cAAY;AAAQ,SAAO,IAAI;AAAU;AAC/E,CAAC;AAAmB,QAAM,IAAI,OAAO,CAAC,IAAI,IAAI;AAAY;AAC1D,CAAC;AAAe,QAAM,OAAO,CAAC,IAAI,IAAI;AAAY,SAAO,IAAI;AAAU;AACvE,CAHqB;AAGH,QAAM,OAAO,CAAC,KAAK,IAAI,WAAW,EAAE,IAAI;AAAa,eAAa;AAAU;AAC9F,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,IAAI,IAAI,WAAW,EAAE,IAAI;AAAa,WAAS,IAAI;AACnE;AACA,CANC,eAMe;AAAS,WAAS;AAAM,gBAAc,IAAI;AAAW;AACrE,CAAC;AAAoB,WAAS;AAAM,OAAK;AAAK,mBAAiB;AAAU;AACzE,CAAC;AACC,QAAM,OAAO,CAAC,EAAE,IAAI;AAAY,WAAS,IAAI;AAC7C,iBAAe,IAAI;AAAc,UAAQ,IAAI,MAAM,IAAI;AACvD,cAAY,IAAI;AAAS,SAAO,IAAI;AAAQ,UAAQ;AACtD;AACA,CALC,aAKa,CAAC;AAAU,cAAY,IAAI;AAAW,gBAAc,IAAI;AAAW,SAAO,IAAI,WAAW,EAAE;AAAO;AAEhH,CAAC;AACC,WAAS;AAAM,OAAK;AAAK,eAAa;AAAU,SAAO;AAAM,cAAY;AACzE,UAAQ;AAAG,cAAY;AAAM,SAAO,IAAI;AAAQ,UAAQ;AACxD,WAAS,IAAI;AAAK,iBAAe,IAAI;AACvC;AACA,CALC,aAKa;AAAS,cAAY,IAAI;AAAgB;AACvD,CANC,aAMa,CA9CE;AA8CU,WAAS;AAAM;AACzC,CAAC;AAAuB,QAAM,IAAI,OAAO,CAAC,IAAI,IAAI;AAAY,QAAM;AAAM;AAC1E,CAAC;AACC,QAAM,OAAO,CAAC,IAAI,IAAI,WAAW,EAAE,IAAI;AAAa,SAAO,IAAI;AAC/D,YAAU;AAAQ,iBAAe;AAAU,eAAa;AAC1D;AACA,CAAC;AAAsB,eAAa;AAAM,QAAM,MAAM,CAAC,EAAE,IAAI;AAAY,SAAO,IAAI;AAAU;AAC9F,CAAC;AACC,cAAY;AAAY,QAAM,OAAO,CAAC,EAAE,IAAI;AAC5C,UAAQ,IAAI,OAAO,IAAI;AAAS,cAAY;AAAM,SAAO,IAAI;AAC7D,iBAAe,IAAI;AAAc,WAAS,IAAI;AAAM,UAAQ;AAC9D;AACA,CALC,aAKa;AAAS,SAAO,IAAI;AAAW,gBAAc,IAAI;AAAW;","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -488,6 +488,29 @@ function pinButton(opts) {
|
|
|
488
488
|
return b;
|
|
489
489
|
}
|
|
490
490
|
|
|
491
|
+
// src/exit.ts
|
|
492
|
+
function closeWithExit(element, done) {
|
|
493
|
+
element.classList.add("closing");
|
|
494
|
+
const seconds = parseFloat(getComputedStyle(element).animationDuration) || 0;
|
|
495
|
+
if (seconds === 0) {
|
|
496
|
+
done();
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
let fired = false;
|
|
500
|
+
const finish = () => {
|
|
501
|
+
if (fired) return;
|
|
502
|
+
fired = true;
|
|
503
|
+
element.removeEventListener("animationend", onEnd);
|
|
504
|
+
clearTimeout(timer2);
|
|
505
|
+
done();
|
|
506
|
+
};
|
|
507
|
+
const onEnd = (e) => {
|
|
508
|
+
if (e.target === element) finish();
|
|
509
|
+
};
|
|
510
|
+
element.addEventListener("animationend", onEnd);
|
|
511
|
+
const timer2 = setTimeout(finish, seconds * 1e3 + 120);
|
|
512
|
+
}
|
|
513
|
+
|
|
491
514
|
// src/confirm.ts
|
|
492
515
|
function confirmDialog(opts) {
|
|
493
516
|
return new Promise((resolve) => {
|
|
@@ -509,21 +532,9 @@ function confirmDialog(opts) {
|
|
|
509
532
|
if (done) return;
|
|
510
533
|
done = true;
|
|
511
534
|
resolve(ok);
|
|
512
|
-
dlg
|
|
513
|
-
const dur = parseFloat(getComputedStyle(dlg).animationDuration) || 0;
|
|
514
|
-
const teardown = () => {
|
|
535
|
+
closeWithExit(dlg, () => {
|
|
515
536
|
dlg.close();
|
|
516
537
|
dlg.remove();
|
|
517
|
-
};
|
|
518
|
-
if (dur === 0) {
|
|
519
|
-
teardown();
|
|
520
|
-
return;
|
|
521
|
-
}
|
|
522
|
-
const timer2 = setTimeout(teardown, dur * 1e3 + 120);
|
|
523
|
-
dlg.addEventListener("animationend", (e) => {
|
|
524
|
-
if (e.target !== dlg) return;
|
|
525
|
-
clearTimeout(timer2);
|
|
526
|
-
teardown();
|
|
527
538
|
});
|
|
528
539
|
};
|
|
529
540
|
cancel.addEventListener("click", () => finish(false));
|
|
@@ -616,8 +627,10 @@ function openAnchoredPanel(opts) {
|
|
|
616
627
|
if (current?.panel === panel) current = null;
|
|
617
628
|
document.removeEventListener("pointerdown", onDown, true);
|
|
618
629
|
document.removeEventListener("keydown", onKey, true);
|
|
619
|
-
panel
|
|
620
|
-
|
|
630
|
+
closeWithExit(panel, () => {
|
|
631
|
+
opts.onClose?.();
|
|
632
|
+
panel.remove();
|
|
633
|
+
});
|
|
621
634
|
};
|
|
622
635
|
closeBtn.addEventListener("click", close);
|
|
623
636
|
const onDown = (e) => {
|
|
@@ -1037,6 +1050,10 @@ function openComments(opts) {
|
|
|
1037
1050
|
}
|
|
1038
1051
|
const thread = open;
|
|
1039
1052
|
if (thread) {
|
|
1053
|
+
const quote = opts.quoteFor?.(thread);
|
|
1054
|
+
if (quote !== void 0 && quote !== "") {
|
|
1055
|
+
body.append(el("blockquote", { className: "shell-cmt-quote", text: quote }));
|
|
1056
|
+
}
|
|
1040
1057
|
const list = el("div", { className: `shell-cmt-list${thread.resolved === true ? " resolved" : ""}` });
|
|
1041
1058
|
thread.messages.forEach((message, index) => {
|
|
1042
1059
|
const head = el(
|
|
@@ -1388,6 +1405,99 @@ function createSaveController(opts) {
|
|
|
1388
1405
|
};
|
|
1389
1406
|
}
|
|
1390
1407
|
|
|
1408
|
+
// src/save-view.ts
|
|
1409
|
+
var WORDS = {
|
|
1410
|
+
saved: "Saved",
|
|
1411
|
+
saving: "Saving\u2026",
|
|
1412
|
+
unsaved: "Unsaved"
|
|
1413
|
+
};
|
|
1414
|
+
function saveIndicator(initial = "saved") {
|
|
1415
|
+
const node = el("span");
|
|
1416
|
+
const set = (status) => {
|
|
1417
|
+
node.className = `savestat ${status}`;
|
|
1418
|
+
node.textContent = WORDS[status];
|
|
1419
|
+
};
|
|
1420
|
+
set(initial);
|
|
1421
|
+
return { el: node, set };
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
// src/stale.ts
|
|
1425
|
+
function staleBar(opts) {
|
|
1426
|
+
const label2 = opts.restartLabel ?? "Restart";
|
|
1427
|
+
return el(
|
|
1428
|
+
"div",
|
|
1429
|
+
{ className: "stale-bar" },
|
|
1430
|
+
el("span", {
|
|
1431
|
+
className: "stale-bar-msg",
|
|
1432
|
+
text: `${opts.subject} changed in the editor. ${opts.advice ?? "Restart to play the new version."}`
|
|
1433
|
+
}),
|
|
1434
|
+
el("button", {
|
|
1435
|
+
className: "stale-bar-go",
|
|
1436
|
+
text: `${icon.restart} ${label2}`,
|
|
1437
|
+
onClick: () => opts.onRestart()
|
|
1438
|
+
})
|
|
1439
|
+
);
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
// src/stepper.ts
|
|
1443
|
+
function renderStepperBar(host, opts) {
|
|
1444
|
+
const { items } = opts;
|
|
1445
|
+
const close = opts.onClose === void 0 ? null : el("button", {
|
|
1446
|
+
className: "stepbar-nav stepbar-close",
|
|
1447
|
+
text: icon.close,
|
|
1448
|
+
tip: opts.closeTip ?? "Close",
|
|
1449
|
+
onClick: opts.onClose
|
|
1450
|
+
});
|
|
1451
|
+
const actions = (opts.actions ?? []).filter((a) => a !== null && a !== void 0);
|
|
1452
|
+
if (items.length === 0) {
|
|
1453
|
+
if (opts.empty === void 0) {
|
|
1454
|
+
host.hidden = true;
|
|
1455
|
+
host.replaceChildren();
|
|
1456
|
+
return;
|
|
1457
|
+
}
|
|
1458
|
+
host.hidden = false;
|
|
1459
|
+
host.replaceChildren(
|
|
1460
|
+
el("span", { className: "stepbar-count muted", text: "0" }),
|
|
1461
|
+
el("span", { className: "stepbar-empty", text: opts.empty }),
|
|
1462
|
+
...actions,
|
|
1463
|
+
...close ? [close] : []
|
|
1464
|
+
);
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
host.hidden = false;
|
|
1468
|
+
const index = Math.min(Math.max(opts.at, 0), items.length - 1);
|
|
1469
|
+
const item = items[index];
|
|
1470
|
+
const step = (delta) => opts.onStep((index + delta + items.length) % items.length);
|
|
1471
|
+
const nav = items.length > 1 ? [
|
|
1472
|
+
el("button", {
|
|
1473
|
+
className: "stepbar-nav",
|
|
1474
|
+
text: icon.back,
|
|
1475
|
+
tip: opts.tips?.prev ?? "Previous",
|
|
1476
|
+
onClick: () => step(-1)
|
|
1477
|
+
}),
|
|
1478
|
+
el("span", { className: "stepbar-of", text: `${index + 1}/${items.length}` }),
|
|
1479
|
+
el("button", {
|
|
1480
|
+
className: "stepbar-nav",
|
|
1481
|
+
text: icon.forward,
|
|
1482
|
+
tip: opts.tips?.next ?? "Next",
|
|
1483
|
+
onClick: () => step(1)
|
|
1484
|
+
})
|
|
1485
|
+
] : [];
|
|
1486
|
+
host.replaceChildren(
|
|
1487
|
+
el("span", { className: `stepbar-count ${opts.tone ?? "muted"}`, text: String(items.length) }),
|
|
1488
|
+
...nav,
|
|
1489
|
+
el(
|
|
1490
|
+
"button",
|
|
1491
|
+
{ className: "stepbar-cur", tip: opts.tips?.go ?? "Go to this", onClick: () => opts.onGo(index) },
|
|
1492
|
+
item.kind === void 0 ? null : el("span", { className: `stepbar-cat${item.kindClass ? ` ${item.kindClass}` : ""}`, text: item.kind }),
|
|
1493
|
+
item.where === void 0 ? null : el("span", { className: "stepbar-where", text: item.where }),
|
|
1494
|
+
el("span", { className: "stepbar-msg", text: item.text })
|
|
1495
|
+
),
|
|
1496
|
+
...actions,
|
|
1497
|
+
...close ? [close] : []
|
|
1498
|
+
);
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1391
1501
|
exports.EDIT_MENU = EDIT_MENU;
|
|
1392
1502
|
exports.JOB_PROGRESS = JOB_PROGRESS;
|
|
1393
1503
|
exports.PALETTE = PALETTE;
|
|
@@ -1395,6 +1505,7 @@ exports.PALETTE_SIZE = PALETTE_SIZE;
|
|
|
1395
1505
|
exports.PANE_MENU = PANE_MENU;
|
|
1396
1506
|
exports.askIdentity = askIdentity;
|
|
1397
1507
|
exports.closeAnchoredPanel = closeAnchoredPanel;
|
|
1508
|
+
exports.closeWithExit = closeWithExit;
|
|
1398
1509
|
exports.colourFor = colourFor;
|
|
1399
1510
|
exports.colourIndex = colourIndex;
|
|
1400
1511
|
exports.confirmDialog = confirmDialog;
|
|
@@ -1425,7 +1536,10 @@ exports.openNotesEditor = openNotesEditor;
|
|
|
1425
1536
|
exports.paintVcBadges = paintVcBadges;
|
|
1426
1537
|
exports.pinButton = pinButton;
|
|
1427
1538
|
exports.placeAnchored = placeAnchored;
|
|
1539
|
+
exports.renderStepperBar = renderStepperBar;
|
|
1540
|
+
exports.saveIndicator = saveIndicator;
|
|
1428
1541
|
exports.showAbout = showAbout;
|
|
1542
|
+
exports.staleBar = staleBar;
|
|
1429
1543
|
exports.tagChips = tagChips;
|
|
1430
1544
|
exports.tipAt = tipAt;
|
|
1431
1545
|
exports.tipBold = tipBold;
|