@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.
- package/LICENSES.md +62 -0
- package/README.md +8 -0
- package/dist/about.css +17 -38
- package/dist/about.css.map +1 -1
- package/dist/anchored.css +9 -9
- package/dist/anchored.css.map +1 -1
- package/dist/app-store.cjs +15 -0
- package/dist/app-store.cjs.map +1 -1
- package/dist/app-store.d.cts +25 -1
- package/dist/app-store.d.ts +25 -1
- package/dist/app-store.js +14 -1
- package/dist/app-store.js.map +1 -1
- package/dist/chunk-2ECJUTSX.js +97 -0
- package/dist/chunk-2ECJUTSX.js.map +1 -0
- package/dist/chunk-DS4XXAZS.js +56 -0
- package/dist/chunk-DS4XXAZS.js.map +1 -0
- package/dist/chunk-EHR2KBZC.js +82 -0
- package/dist/chunk-EHR2KBZC.js.map +1 -0
- package/dist/chunk-IU7EY6BI.js +26 -0
- package/dist/chunk-IU7EY6BI.js.map +1 -0
- package/dist/chunk-OPZPFOPS.js +66 -0
- package/dist/chunk-OPZPFOPS.js.map +1 -0
- package/dist/chunk-P4G4ERG6.js +60 -0
- package/dist/chunk-P4G4ERG6.js.map +1 -0
- package/dist/chunk-P6WLAEKZ.js +71 -0
- package/dist/chunk-P6WLAEKZ.js.map +1 -0
- package/dist/chunk-R3NXPHRZ.js +534 -0
- package/dist/chunk-R3NXPHRZ.js.map +1 -0
- package/dist/chunk-SDOKZTAR.js +87 -0
- package/dist/chunk-SDOKZTAR.js.map +1 -0
- package/dist/chunk-SEWJLUOD.js +70 -0
- package/dist/chunk-SEWJLUOD.js.map +1 -0
- package/dist/chunk-UG2P777F.js +587 -0
- package/dist/chunk-UG2P777F.js.map +1 -0
- package/dist/chunk-YRFJLJUH.js +55 -0
- package/dist/chunk-YRFJLJUH.js.map +1 -0
- package/dist/chunk-YWMSQFXX.js +146 -0
- package/dist/chunk-YWMSQFXX.js.map +1 -0
- package/dist/comments.css +16 -14
- package/dist/comments.css.map +1 -1
- package/dist/confirm.css +2 -55
- package/dist/confirm.css.map +1 -1
- package/dist/context-menu.cjs +250 -0
- package/dist/context-menu.cjs.map +1 -0
- package/dist/context-menu.css +64 -0
- package/dist/context-menu.css.map +1 -0
- package/dist/context-menu.d.cts +25 -0
- package/dist/context-menu.d.ts +25 -0
- package/dist/context-menu.js +5 -0
- package/dist/context-menu.js.map +1 -0
- package/dist/controls.css +214 -0
- package/dist/controls.css.map +1 -0
- package/dist/dialog.cjs +222 -0
- package/dist/dialog.cjs.map +1 -0
- package/dist/dialog.css +56 -0
- package/dist/dialog.css.map +1 -0
- package/dist/dialog.d.cts +28 -0
- package/dist/dialog.d.ts +28 -0
- package/dist/dialog.js +5 -0
- package/dist/dialog.js.map +1 -0
- package/dist/floating.cjs +83 -0
- package/dist/floating.cjs.map +1 -0
- package/dist/floating.d.cts +25 -0
- package/dist/floating.d.ts +25 -0
- package/dist/floating.js +4 -0
- package/dist/floating.js.map +1 -0
- package/dist/identity.css +15 -50
- package/dist/identity.css.map +1 -1
- package/dist/index.cjs +1553 -260
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +385 -152
- package/dist/index.d.ts +385 -152
- package/dist/index.js +264 -823
- package/dist/index.js.map +1 -1
- package/dist/job.css +24 -1
- package/dist/job.css.map +1 -1
- package/dist/keys.cjs +155 -0
- package/dist/keys.cjs.map +1 -0
- package/dist/keys.css +41 -0
- package/dist/keys.css.map +1 -0
- package/dist/keys.d.cts +57 -0
- package/dist/keys.d.ts +57 -0
- package/dist/keys.js +3 -0
- package/dist/keys.js.map +1 -0
- package/dist/link-status.cjs +430 -0
- package/dist/link-status.cjs.map +1 -0
- package/dist/link-status.css +76 -0
- package/dist/link-status.css.map +1 -0
- package/dist/link-status.d.cts +53 -0
- package/dist/link-status.d.ts +53 -0
- package/dist/link-status.js +5 -0
- package/dist/link-status.js.map +1 -0
- package/dist/menu.cjs +62 -1
- package/dist/menu.cjs.map +1 -1
- package/dist/menu.d.cts +88 -1
- package/dist/menu.d.ts +88 -1
- package/dist/menu.js +1 -1
- package/dist/notes-editor.css +9 -52
- package/dist/notes-editor.css.map +1 -1
- package/dist/pane-shell.css +23 -5
- package/dist/pane-shell.css.map +1 -1
- package/dist/problems.cjs +61 -0
- package/dist/problems.cjs.map +1 -0
- package/dist/problems.d.cts +57 -0
- package/dist/problems.d.ts +57 -0
- package/dist/problems.js +3 -0
- package/dist/problems.js.map +1 -0
- package/dist/property-list-D3VZCJzi.d.cts +162 -0
- package/dist/property-list-D3VZCJzi.d.ts +162 -0
- package/dist/property-list.cjs +784 -0
- package/dist/property-list.cjs.map +1 -0
- package/dist/property-list.d.cts +1 -0
- package/dist/property-list.d.ts +1 -0
- package/dist/property-list.js +4 -0
- package/dist/property-list.js.map +1 -0
- package/dist/save.css +1 -1
- package/dist/save.css.map +1 -1
- package/dist/settings.css +62 -18
- package/dist/settings.css.map +1 -1
- package/dist/stale.css +4 -1
- package/dist/stale.css.map +1 -1
- package/dist/stepper.css +47 -3
- package/dist/stepper.css.map +1 -1
- package/dist/toast.css +5 -5
- package/dist/toast.css.map +1 -1
- package/dist/tokens.css +20 -0
- package/dist/tokens.css.map +1 -1
- package/dist/tool-window.cjs +63 -0
- package/dist/tool-window.cjs.map +1 -1
- package/dist/tool-window.css +8 -4
- package/dist/tool-window.css.map +1 -1
- package/dist/tool-window.d.cts +67 -1
- package/dist/tool-window.d.ts +67 -1
- package/dist/tool-window.js +63 -1
- package/dist/tool-window.js.map +1 -1
- package/dist/tooltip.css +3 -3
- package/dist/tooltip.css.map +1 -1
- package/dist/updater-view.cjs +283 -0
- package/dist/updater-view.cjs.map +1 -0
- package/dist/updater-view.d.cts +23 -0
- package/dist/updater-view.d.ts +23 -0
- package/dist/updater-view.js +6 -0
- package/dist/updater-view.js.map +1 -0
- package/dist/updater.cjs +12 -16
- package/dist/updater.cjs.map +1 -1
- package/dist/updater.css +44 -0
- package/dist/updater.css.map +1 -0
- package/dist/updater.js +12 -16
- package/dist/updater.js.map +1 -1
- package/dist/util.cjs +78 -0
- package/dist/util.cjs.map +1 -0
- package/dist/util.d.cts +37 -0
- package/dist/util.d.ts +37 -0
- package/dist/util.js +3 -0
- package/dist/util.js.map +1 -0
- package/dist/vc.css +4 -3
- package/dist/vc.css.map +1 -1
- package/dist/welcome.cjs +215 -0
- package/dist/welcome.cjs.map +1 -0
- package/dist/welcome.css +112 -0
- package/dist/welcome.css.map +1 -0
- package/dist/welcome.d.cts +55 -0
- package/dist/welcome.d.ts +55 -0
- package/dist/welcome.js +4 -0
- package/dist/welcome.js.map +1 -0
- package/package.json +72 -2
- package/dist/chunk-QDPFU4WX.js +0 -43
- package/dist/chunk-QDPFU4WX.js.map +0 -1
package/dist/dialog.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
interface DialogFrameOptions {
|
|
2
|
+
/** The heading. Also the dialog's accessible name. */
|
|
3
|
+
title: string;
|
|
4
|
+
/** One plain sentence under the heading, if the title needs one. */
|
|
5
|
+
sub?: string;
|
|
6
|
+
/** Extra class(es) on the <dialog>, for the caller's own content rules and
|
|
7
|
+
* width (`--dialog-width` on the class; see dialog.css). */
|
|
8
|
+
className?: string;
|
|
9
|
+
/** Runs once, after the dialog has left the document, however it closed. */
|
|
10
|
+
onClose?: () => void;
|
|
11
|
+
}
|
|
12
|
+
interface DialogFrame {
|
|
13
|
+
readonly dialog: HTMLDialogElement;
|
|
14
|
+
/** Fill this with the content. */
|
|
15
|
+
readonly body: HTMLElement;
|
|
16
|
+
/** Fill this with the buttons, right-aligned; empty, it draws nothing. */
|
|
17
|
+
readonly actions: HTMLElement;
|
|
18
|
+
/** Show modally. Records what had focus so `close()` can give it back. */
|
|
19
|
+
open(): void;
|
|
20
|
+
/** Play the exit, tear down, restore focus. Idempotent. */
|
|
21
|
+
close(): void;
|
|
22
|
+
isOpen(): boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Build a dialog on the family's frame. Appended to <body> at once (so an
|
|
25
|
+
* `open()` on the next line has nothing to wait for); shown only on `open()`. */
|
|
26
|
+
declare function dialogFrame(opts: DialogFrameOptions): DialogFrame;
|
|
27
|
+
|
|
28
|
+
export { type DialogFrame, type DialogFrameOptions, dialogFrame };
|
package/dist/dialog.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"dialog.js"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/exit.ts
|
|
4
|
+
function closeWithExit(element, done) {
|
|
5
|
+
element.classList.add("closing");
|
|
6
|
+
const seconds = parseFloat(getComputedStyle(element).animationDuration) || 0;
|
|
7
|
+
if (seconds === 0) {
|
|
8
|
+
done();
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
let fired = false;
|
|
12
|
+
const finish = () => {
|
|
13
|
+
if (fired) return;
|
|
14
|
+
fired = true;
|
|
15
|
+
element.removeEventListener("animationend", onEnd);
|
|
16
|
+
clearTimeout(timer);
|
|
17
|
+
done();
|
|
18
|
+
};
|
|
19
|
+
const onEnd = (e) => {
|
|
20
|
+
if (e.target === element) finish();
|
|
21
|
+
};
|
|
22
|
+
element.addEventListener("animationend", onEnd);
|
|
23
|
+
const timer = setTimeout(finish, seconds * 1e3 + 120);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/floating.ts
|
|
27
|
+
function followOnScroll(reposition) {
|
|
28
|
+
const onMove = () => reposition();
|
|
29
|
+
window.addEventListener("scroll", onMove, true);
|
|
30
|
+
window.addEventListener("resize", onMove);
|
|
31
|
+
return () => {
|
|
32
|
+
window.removeEventListener("scroll", onMove, true);
|
|
33
|
+
window.removeEventListener("resize", onMove);
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function createFloating(className, opts = {}) {
|
|
37
|
+
const el = document.createElement("div");
|
|
38
|
+
el.className = className;
|
|
39
|
+
el.style.display = "none";
|
|
40
|
+
(opts.host ?? document.body).appendChild(el);
|
|
41
|
+
let open = false;
|
|
42
|
+
let detach = null;
|
|
43
|
+
let outside = null;
|
|
44
|
+
let closeToken = 0;
|
|
45
|
+
const close = () => {
|
|
46
|
+
if (!open) return;
|
|
47
|
+
open = false;
|
|
48
|
+
detach?.();
|
|
49
|
+
detach = null;
|
|
50
|
+
if (outside) {
|
|
51
|
+
document.removeEventListener("mousedown", outside, true);
|
|
52
|
+
outside = null;
|
|
53
|
+
}
|
|
54
|
+
const myToken = ++closeToken;
|
|
55
|
+
closeWithExit(el, () => {
|
|
56
|
+
if (myToken !== closeToken) return;
|
|
57
|
+
el.style.display = "none";
|
|
58
|
+
el.replaceChildren();
|
|
59
|
+
el.classList.remove("closing");
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
const show = (reposition) => {
|
|
63
|
+
closeToken++;
|
|
64
|
+
el.classList.remove("closing");
|
|
65
|
+
open = true;
|
|
66
|
+
el.style.display = "block";
|
|
67
|
+
reposition();
|
|
68
|
+
detach ??= followOnScroll(reposition);
|
|
69
|
+
};
|
|
70
|
+
const dismissOnOutside = (onOutside, isInside) => {
|
|
71
|
+
if (outside) return;
|
|
72
|
+
outside = (e) => {
|
|
73
|
+
const t = e.target;
|
|
74
|
+
if (!el.contains(t) && !(isInside?.(t) ?? false)) onOutside();
|
|
75
|
+
};
|
|
76
|
+
document.addEventListener("mousedown", outside, true);
|
|
77
|
+
};
|
|
78
|
+
return { el, show, dismissOnOutside, close, isOpen: () => open };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
exports.createFloating = createFloating;
|
|
82
|
+
//# sourceMappingURL=floating.cjs.map
|
|
83
|
+
//# sourceMappingURL=floating.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/exit.ts","../src/floating.ts"],"names":[],"mappings":"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","file":"floating.cjs","sourcesContent":["// ---------------------------------------------------------------------------\n// The exit half of the panel motion vocabulary.\n//\n// Enters are pure CSS: they run on insertion. Exits cannot be, because the node\n// has to OUTLIVE the close for the animation to play and then be torn down. So\n// every closing surface routes its teardown through here instead of removing\n// itself directly.\n//\n// Patterpad's `closeWithExit`, lifted. It was already app-agnostic, and the\n// shell had grown a second copy of the same twelve lines inside `confirm.ts`,\n// which is the drift this package exists to stop: one motion vocabulary, drawn\n// one way. `tokens.css` already carried the keyframes and the durations; this\n// is the missing half that plays them.\n// ---------------------------------------------------------------------------\n\n/**\n * Play the close animation on `element`, then run `done` exactly once.\n *\n * `done` does the real teardown: remove the node, drop listeners, unmount\n * whatever was inside it. Under `prefers-reduced-motion` the duration reads 0\n * and `done` runs synchronously, so reduced motion means instant rather than\n * an invisible wait.\n */\nexport function closeWithExit(element: HTMLElement, done: () => void): void {\n element.classList.add(\"closing\");\n // getComputedStyle flushes pending style, so this reflects the `.closing`\n // rule we just added rather than the state before it.\n const seconds = parseFloat(getComputedStyle(element).animationDuration) || 0;\n if (seconds === 0) { done(); return; }\n\n let fired = false;\n const finish = (): void => {\n if (fired) return;\n fired = true;\n element.removeEventListener(\"animationend\", onEnd);\n clearTimeout(timer);\n done();\n };\n // Only OUR animation ending counts. Content inside the panel (rows, pills,\n // spinners) raises its own animationend, and an inner one firing first would\n // tear the panel down mid-fade.\n const onEnd = (e: AnimationEvent): void => { if (e.target === element) finish(); };\n element.addEventListener(\"animationend\", onEnd);\n // Fallback: animationend is missed if the element is hidden or the animation\n // is interrupted, and a panel that never tears down is worse than an abrupt one.\n const timer = setTimeout(finish, seconds * 1000 + 120);\n}\n","// ---------------------------------------------------------------------------\n// The floating-layer lifecycle every popup and menu shares: a body-appended\n// element, display toggling, a scroll / resize follower that keeps it glued to\n// its anchor, a click-away dismiss, and the family's exit motion on close.\n//\n// Patterpad's surface had it (four popups: the cue picker, the slash menu, the\n// action menu, the jump picker) and Storyletter's context menu had the same\n// idea in eleven lines without the follower (ui-review-2026-09, finding 5).\n// This is the surface's, lifted whole. Positioning stays the caller's, because\n// it differs per popup: pass a `reposition` closure to `show()` and the\n// follower re-runs it on scroll and resize until `close()`.\n//\n// The element is REUSED across opens (a popup that re-renders on every\n// keystroke must not tear itself down each time), which is why a stale exit\n// teardown has a token to lose against a reopen.\n// ---------------------------------------------------------------------------\n\nimport { closeWithExit } from \"./exit.js\";\n\nexport interface Floating {\n /** The floating element. Build content into it; it is appended to <body>\n * (or the `host` given), hidden until `show()`. */\n readonly el: HTMLElement;\n /** Show `el` and keep `reposition` glued to the anchor on scroll / resize.\n * Safe to call repeatedly (on every re-render): the follower attaches once. */\n show(reposition: () => void): void;\n /** While open, call `onOutside` on a pointer-down outside `el`, and outside\n * anything `isInside` accepts (a second flyout, the anchor button).\n * Idempotent: arms once. */\n dismissOnOutside(onOutside: () => void, isInside?: (target: Node) => boolean): void;\n /** Play the exit, then hide `el`, clear its children, and drop the follower\n * and any outside listener. */\n close(): void;\n isOpen(): boolean;\n}\n\n/** Re-run `reposition` on any scroll or resize until the returned disposer runs. */\nfunction followOnScroll(reposition: () => void): () => void {\n const onMove = (): void => reposition();\n window.addEventListener(\"scroll\", onMove, true);\n window.addEventListener(\"resize\", onMove);\n return () => { window.removeEventListener(\"scroll\", onMove, true); window.removeEventListener(\"resize\", onMove); };\n}\n\nexport interface FloatingOptions {\n /** Where the element is appended. Default <body>. Under a modal <dialog> a\n * body-level node sits behind the scrim, inert, so a popup opened from\n * inside one passes the dialog here and paints in its top layer. */\n host?: HTMLElement;\n}\n\nexport function createFloating(className: string, opts: FloatingOptions = {}): Floating {\n const el = document.createElement(\"div\"); el.className = className; el.style.display = \"none\";\n (opts.host ?? document.body).appendChild(el);\n let open = false;\n let detach: (() => void) | null = null;\n let outside: ((e: MouseEvent) => void) | null = null;\n let closeToken = 0; // bumped on every show / close so a stale exit teardown cannot clobber a reopen\n\n const close = (): void => {\n if (!open) return;\n open = false;\n detach?.(); detach = null; // stop following + dismissing immediately; it is on its way out\n if (outside) { document.removeEventListener(\"mousedown\", outside, true); outside = null; }\n const myToken = ++closeToken;\n // Play the exit, THEN hide + clear. A reopen during the fade must win:\n // show() bumps closeToken, and this guard abandons the stale teardown.\n closeWithExit(el, () => {\n if (myToken !== closeToken) return;\n el.style.display = \"none\"; el.replaceChildren(); el.classList.remove(\"closing\");\n });\n };\n\n const show = (reposition: () => void): void => {\n closeToken++; el.classList.remove(\"closing\"); // cancel any in-flight exit, undo its class\n open = true; el.style.display = \"block\"; reposition();\n detach ??= followOnScroll(reposition);\n };\n\n const dismissOnOutside = (onOutside: () => void, isInside?: (target: Node) => boolean): void => {\n if (outside) return; // already armed\n outside = (e: MouseEvent): void => {\n const t = e.target as Node;\n if (!el.contains(t) && !(isInside?.(t) ?? false)) onOutside();\n };\n document.addEventListener(\"mousedown\", outside, true);\n };\n\n return { el, show, dismissOnOutside, close, isOpen: () => open };\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface Floating {
|
|
2
|
+
/** The floating element. Build content into it; it is appended to <body>
|
|
3
|
+
* (or the `host` given), hidden until `show()`. */
|
|
4
|
+
readonly el: HTMLElement;
|
|
5
|
+
/** Show `el` and keep `reposition` glued to the anchor on scroll / resize.
|
|
6
|
+
* Safe to call repeatedly (on every re-render): the follower attaches once. */
|
|
7
|
+
show(reposition: () => void): void;
|
|
8
|
+
/** While open, call `onOutside` on a pointer-down outside `el`, and outside
|
|
9
|
+
* anything `isInside` accepts (a second flyout, the anchor button).
|
|
10
|
+
* Idempotent: arms once. */
|
|
11
|
+
dismissOnOutside(onOutside: () => void, isInside?: (target: Node) => boolean): void;
|
|
12
|
+
/** Play the exit, then hide `el`, clear its children, and drop the follower
|
|
13
|
+
* and any outside listener. */
|
|
14
|
+
close(): void;
|
|
15
|
+
isOpen(): boolean;
|
|
16
|
+
}
|
|
17
|
+
interface FloatingOptions {
|
|
18
|
+
/** Where the element is appended. Default <body>. Under a modal <dialog> a
|
|
19
|
+
* body-level node sits behind the scrim, inert, so a popup opened from
|
|
20
|
+
* inside one passes the dialog here and paints in its top layer. */
|
|
21
|
+
host?: HTMLElement;
|
|
22
|
+
}
|
|
23
|
+
declare function createFloating(className: string, opts?: FloatingOptions): Floating;
|
|
24
|
+
|
|
25
|
+
export { type Floating, type FloatingOptions, createFloating };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface Floating {
|
|
2
|
+
/** The floating element. Build content into it; it is appended to <body>
|
|
3
|
+
* (or the `host` given), hidden until `show()`. */
|
|
4
|
+
readonly el: HTMLElement;
|
|
5
|
+
/** Show `el` and keep `reposition` glued to the anchor on scroll / resize.
|
|
6
|
+
* Safe to call repeatedly (on every re-render): the follower attaches once. */
|
|
7
|
+
show(reposition: () => void): void;
|
|
8
|
+
/** While open, call `onOutside` on a pointer-down outside `el`, and outside
|
|
9
|
+
* anything `isInside` accepts (a second flyout, the anchor button).
|
|
10
|
+
* Idempotent: arms once. */
|
|
11
|
+
dismissOnOutside(onOutside: () => void, isInside?: (target: Node) => boolean): void;
|
|
12
|
+
/** Play the exit, then hide `el`, clear its children, and drop the follower
|
|
13
|
+
* and any outside listener. */
|
|
14
|
+
close(): void;
|
|
15
|
+
isOpen(): boolean;
|
|
16
|
+
}
|
|
17
|
+
interface FloatingOptions {
|
|
18
|
+
/** Where the element is appended. Default <body>. Under a modal <dialog> a
|
|
19
|
+
* body-level node sits behind the scrim, inert, so a popup opened from
|
|
20
|
+
* inside one passes the dialog here and paints in its top layer. */
|
|
21
|
+
host?: HTMLElement;
|
|
22
|
+
}
|
|
23
|
+
declare function createFloating(className: string, opts?: FloatingOptions): Floating;
|
|
24
|
+
|
|
25
|
+
export { type Floating, type FloatingOptions, createFloating };
|
package/dist/floating.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"floating.js"}
|
package/dist/identity.css
CHANGED
|
@@ -1,62 +1,27 @@
|
|
|
1
1
|
/* src/identity.css */
|
|
2
2
|
.shell-ident {
|
|
3
|
-
width:
|
|
4
|
-
border: 1px solid var(--line);
|
|
5
|
-
border-radius: var(--radius-md);
|
|
6
|
-
background: var(--surface);
|
|
7
|
-
color: var(--ink);
|
|
8
|
-
padding: 16px 18px;
|
|
9
|
-
box-shadow: var(--shadow-2, var(--shadow-1));
|
|
10
|
-
}
|
|
11
|
-
.shell-ident::backdrop {
|
|
12
|
-
background: rgba(0, 0, 0, 0.28);
|
|
13
|
-
}
|
|
14
|
-
.shell-ident-title {
|
|
15
|
-
font: 600 0.95rem/1.3 var(--font-ui);
|
|
16
|
-
}
|
|
17
|
-
.shell-ident-hint {
|
|
18
|
-
font: 0.78rem/1.45 var(--font-ui);
|
|
19
|
-
color: var(--muted);
|
|
20
|
-
margin: 6px 0 0;
|
|
3
|
+
--dialog-width: 400px;
|
|
21
4
|
}
|
|
22
5
|
.shell-ident-fields {
|
|
23
6
|
display: flex;
|
|
24
7
|
flex-direction: column;
|
|
25
|
-
gap:
|
|
26
|
-
margin-top:
|
|
27
|
-
}
|
|
28
|
-
.shell-ident-input {
|
|
29
|
-
width: 100%;
|
|
30
|
-
box-sizing: border-box;
|
|
31
|
-
border: 1px solid var(--line-soft);
|
|
32
|
-
border-radius: var(--radius-sm);
|
|
33
|
-
background: var(--card);
|
|
34
|
-
color: var(--ink);
|
|
35
|
-
font: 0.85rem/1.4 var(--font-ui);
|
|
36
|
-
padding: 6px 8px;
|
|
37
|
-
}
|
|
38
|
-
.shell-ident-input:focus {
|
|
39
|
-
outline: none;
|
|
40
|
-
border-color: var(--accent);
|
|
8
|
+
gap: 10px;
|
|
9
|
+
margin-top: 4px;
|
|
41
10
|
}
|
|
42
|
-
.shell-ident-
|
|
11
|
+
.shell-ident .shell-labelled {
|
|
43
12
|
display: flex;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
align-items: stretch;
|
|
15
|
+
gap: 4px;
|
|
16
|
+
font-size: 13.5px;
|
|
47
17
|
}
|
|
48
|
-
.shell-ident-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
border: 1px solid var(--line);
|
|
53
|
-
background: var(--card);
|
|
54
|
-
color: var(--ink);
|
|
55
|
-
cursor: pointer;
|
|
18
|
+
.shell-ident .shell-fieldcap {
|
|
19
|
+
min-width: 0;
|
|
20
|
+
font: 12.5px/1.3 var(--font-ui);
|
|
21
|
+
color: var(--muted);
|
|
56
22
|
}
|
|
57
|
-
.shell-ident-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
color: var(--on-accent, #fff);
|
|
23
|
+
.shell-ident-input {
|
|
24
|
+
width: 100%;
|
|
25
|
+
box-sizing: border-box;
|
|
61
26
|
}
|
|
62
27
|
/*# sourceMappingURL=identity.css.map */
|
package/dist/identity.css.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/identity.css"],"sourcesContent":["/* The identity dialog (identity.ts): asked once, skippable, and the same in\n every app in the family.
|
|
1
|
+
{"version":3,"sources":["../src/identity.css"],"sourcesContent":["/* The identity dialog (identity.ts): asked once, skippable, and the same in\n every app in the family. The panel, scrim, title, sub line and actions row\n are the dialog frame's (dialog.css); the fields and buttons are\n controls.css's `.field` and `.btn`. Only the fields' layout is identity's own.\n The captions are `labelled` rows (dom.ts) stood on end: settings.css lays a\n `.shell-labelled` out as a row with a fixed-width caption, which suits a\n settings grid and not a two-field form, so the rules here say everything\n the row needs and hold whether or not settings.css is loaded beside them. */\n.shell-ident { --dialog-width: 400px; }\n.shell-ident-fields { display: flex; flex-direction: column; gap: 10px; margin-top: 4px; }\n.shell-ident .shell-labelled {\n display: flex; flex-direction: column; align-items: stretch; gap: 4px;\n font-size: 13.5px;\n}\n.shell-ident .shell-fieldcap { min-width: 0; font: 12.5px/1.3 var(--font-ui); color: var(--muted); }\n.shell-ident-input { width: 100%; box-sizing: border-box; }\n"],"mappings":";AAQA,CAAC;AAAc,kBAAgB;AAAO;AACtC,CAAC;AAAqB,WAAS;AAAM,kBAAgB;AAAQ,OAAK;AAAM,cAAY;AAAK;AACzF,CAFC,YAEY,CAAC;AACZ,WAAS;AAAM,kBAAgB;AAAQ,eAAa;AAAS,OAAK;AAClE,aAAW;AACb;AACA,CANC,YAMY,CAAC;AAAiB,aAAW;AAAG,QAAM,MAAM,CAAC,IAAI,IAAI;AAAY,SAAO,IAAI;AAAU;AACnG,CAAC;AAAoB,SAAO;AAAM,cAAY;AAAY;","names":[]}
|