@signal9/era-ui 4.15.0 → 4.15.2
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/dist/apps/notes/note-editor.svelte +20 -0
- package/dist/apps/notes/notes.svelte +32 -46
- package/dist/dev/audit/audits/prose-leading.js +24 -11
- package/dist/era-ui.css +1 -1
- package/dist/generated-docs/bar.md +1 -0
- package/dist/generated-docs/llms-full.txt +1 -0
- package/dist/generated-docs/manifest.json +1 -1
- package/dist/os/index.d.ts +1 -1
- package/dist/os/index.js +1 -1
- package/dist/os/pane-manager.svelte.d.ts +4 -0
- package/dist/os/pane-manager.svelte.js +6 -0
- package/dist/styles/themes.css +50 -67
- package/dist/ui/bar/bar.svelte +27 -2
- package/dist/ui/bar/bar.svelte.d.ts +68 -0
- package/dist/ui/context-menu/context-menu-content.svelte +6 -9
- package/dist/ui/dialog/dialog-content.svelte +2 -1
- package/dist/ui/dialog/dialog-header.svelte +10 -25
- package/dist/ui/dropdown-menu/dropdown-menu-content.svelte +6 -9
- package/dist/ui/menubar/menubar-content.svelte +6 -9
- package/dist/ui/pane/pane-handle.svelte +12 -19
- package/dist/ui/select/select-content.svelte +7 -2
- package/dist/ui/sheet/sheet-content.svelte +14 -16
- package/dist/ui/sheet/sheet-content.svelte.d.ts +18 -18
- package/package.json +19 -19
|
@@ -915,6 +915,7 @@ Inherits all props from `HTMLAttributes<HTMLDivElement>`.
|
|
|
915
915
|
| `content?` | `'tier' \| 'xxs'` | `'tier'` | Tier of the controls inside — drives the bar's padding and gap so they
|
|
916
916
|
stay concentric to them. `tier` (default) is one tier smaller; `xxs` is
|
|
917
917
|
the compact pairing (xxs pills/fields in an sm or md bar). |
|
|
918
|
+
| `divider?` | `boolean` | `false` | The flush cap-a-panel chrome: outset divider below, bottom rd-md. |
|
|
918
919
|
| `children?` | `Snippet` | — | — |
|
|
919
920
|
|
|
920
921
|
<!-- end: bar -->
|
package/dist/os/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { PaneManager, getPaneManager, setPaneManagerContext, type Point, type Size, type Rect, type Insets, type Frame, type AppDefinition, type AppPane, type AppComponent, type AppProps, type PaneState, type JsonValue, type PaneSnapshot, type WorkspaceSnapshot, SNAPSHOT_VERSION, readSnapshot } from './pane-manager.svelte.js';
|
|
1
|
+
export { PaneManager, getPaneManager, tryGetPaneManager, setPaneManagerContext, type Point, type Size, type Rect, type Insets, type Frame, type AppDefinition, type AppPane, type AppComponent, type AppProps, type PaneState, type JsonValue, type PaneSnapshot, type WorkspaceSnapshot, SNAPSHOT_VERSION, readSnapshot } from './pane-manager.svelte.js';
|
|
2
2
|
export { persistWorkspace, loadWorkspace, saveWorkspace, clearWorkspace, WORKSPACE_STORAGE_KEY } from './workspace-storage.svelte.js';
|
|
3
3
|
export { type SnapZone, type Workspace } from './pane-manager.svelte.js';
|
|
4
4
|
export { NotificationService, getNotifications, setNotificationContext, type AppNotification, type NotifyOptions, type NotificationAction, type NotificationTone } from './notifications.svelte.js';
|
package/dist/os/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Two stores (pane manager + notifications) shared via context, and the
|
|
3
3
|
// components that render them: Desktop host, Pane, Taskbar (with its
|
|
4
4
|
// built-in command bar), Toaster, NotificationCenter.
|
|
5
|
-
export { PaneManager, getPaneManager, setPaneManagerContext, SNAPSHOT_VERSION, readSnapshot } from './pane-manager.svelte.js';
|
|
5
|
+
export { PaneManager, getPaneManager, tryGetPaneManager, setPaneManagerContext, SNAPSHOT_VERSION, readSnapshot } from './pane-manager.svelte.js';
|
|
6
6
|
export { persistWorkspace, loadWorkspace, saveWorkspace, clearWorkspace, WORKSPACE_STORAGE_KEY } from './workspace-storage.svelte.js';
|
|
7
7
|
export {} from './pane-manager.svelte.js';
|
|
8
8
|
export { NotificationService, getNotifications, setNotificationContext } from './notifications.svelte.js';
|
|
@@ -296,3 +296,7 @@ export declare class PaneManager {
|
|
|
296
296
|
}
|
|
297
297
|
export declare function setPaneManagerContext(pm: PaneManager): PaneManager;
|
|
298
298
|
export declare function getPaneManager(): PaneManager;
|
|
299
|
+
/** The optional form, for content that renders both inside and outside a
|
|
300
|
+
* Desktop (a docs route under ?bare, a component demoed standalone):
|
|
301
|
+
* undefined instead of a throw when no shell is up. */
|
|
302
|
+
export declare function tryGetPaneManager(): PaneManager | undefined;
|
|
@@ -448,3 +448,9 @@ export function getPaneManager() {
|
|
|
448
448
|
throw new Error('getPaneManager() must be used inside a <Desktop>.');
|
|
449
449
|
return pm;
|
|
450
450
|
}
|
|
451
|
+
/** The optional form, for content that renders both inside and outside a
|
|
452
|
+
* Desktop (a docs route under ?bare, a component demoed standalone):
|
|
453
|
+
* undefined instead of a throw when no shell is up. */
|
|
454
|
+
export function tryGetPaneManager() {
|
|
455
|
+
return getContext(PM_KEY);
|
|
456
|
+
}
|
package/dist/styles/themes.css
CHANGED
|
@@ -49,54 +49,8 @@
|
|
|
49
49
|
--color-surface: var(--color-2);
|
|
50
50
|
--color-hover: oklch(0.25 0 none);
|
|
51
51
|
--color-fg: var(--color-11);
|
|
52
|
-
/*
|
|
53
|
-
*
|
|
54
|
-
* Step 12 is the ramp's extreme, and at the extreme a neutral ramp has run out
|
|
55
|
-
* of colour — so `bright` came out pure white on the dark themes and pure
|
|
56
|
-
* black on signalnine light. That is the one place a themed UI should NOT go
|
|
57
|
-
* achromatic: bright is the emphasis ink (headings, titles, the sentence you
|
|
58
|
-
* are meant to read first), so it is the text carrying the most identity and
|
|
59
|
-
* it was carrying none.
|
|
60
|
-
*
|
|
61
|
-
* It now takes 12% of --color-primary — the theme's own accent, which is also
|
|
62
|
-
* what the accent picker writes, so choosing an accent tints the emphasis text
|
|
63
|
-
* with it live. 12% is a cast, not a colour: it moves lightness by ~0.02 (the
|
|
64
|
-
* default dark page keeps 11.6:1) and lands chroma near 0.013, which reads as
|
|
65
|
-
* "warm white" or "blue-black" rather than as a coloured heading.
|
|
66
|
-
*
|
|
67
|
-
* A theme whose accent IS neutral (the default) is unchanged by construction —
|
|
68
|
-
* there is no hue to lend — which is the correct behaviour rather than an
|
|
69
|
-
* exception.
|
|
70
|
-
*
|
|
71
|
-
* The achromatic step 12s are written with hue `none` rather than hue 0, and
|
|
72
|
-
* that is load-bearing: hue 0 is a REAL hue (red), so oklch interpolation
|
|
73
|
-
* walks it round to the accent's the short way and a black-plus-blue mix came
|
|
74
|
-
* out magenta (signalnine light's #000 landed on hue 349). `none` marks the
|
|
75
|
-
* hue as powerless — which it is at chroma 0 — so the mix adopts the accent's
|
|
76
|
-
* hue instead of travelling to it. The colours themselves are unchanged
|
|
77
|
-
* everywhere else: at chroma 0 the hue paints nothing. */
|
|
78
|
-
--color-bright: color-mix(in oklch, var(--color-12) 88%, var(--color-primary));
|
|
79
|
-
/* Muted is body copy, not a de-emphasis wash — the /text page sets whole
|
|
80
|
-
* paragraphs in it — so it does NOT sit flat on step 10: it leans 40% of the
|
|
81
|
-
* way to --color-bright. Step 10 alone read as "greyed out" at paragraph
|
|
82
|
-
* length (7.80:1 on the default dark page); the lean lands it at 10.43:1, and
|
|
83
|
-
* the ordering muted < fg < bright still holds by a clear margin (0.80 / 0.86
|
|
84
|
-
* / 0.93 in dark), so the mixed-tone case — muted prose beside a bright
|
|
85
|
-
* literal — keeps all three of its levels.
|
|
86
|
-
*
|
|
87
|
-
* It aims at BRIGHT rather than fg on purpose: fg is the ink of controls and
|
|
88
|
-
* labels, bright is the ink of the sentence you are meant to read, and body
|
|
89
|
-
* copy belongs with the second one. It also means muted inherits the theme's
|
|
90
|
-
* tint through bright, so prose is never a neutral grey on a themed page.
|
|
91
|
-
*
|
|
92
|
-
* The lean is toward a TOKEN rather than a fixed lightness so it mirrors
|
|
93
|
-
* correctly in light mode (muted DARKENS toward bright) and keeps each theme's
|
|
94
|
-
* own hue family — the tinted scales interpolate between two steps of their
|
|
95
|
-
* own ramp, never toward neutral.
|
|
96
|
-
*
|
|
97
|
-
* signalnine sets its muted by hand from measured source colours and is
|
|
98
|
-
* deliberately exempt. */
|
|
99
|
-
--color-muted: color-mix(in oklch, var(--color-10) 60%, var(--color-bright));
|
|
52
|
+
/* --color-bright / --color-muted: declared once for every theme — see the
|
|
53
|
+
* shared rule right after this block. */
|
|
100
54
|
/* Inline link ink. Declared once here and inherited by every theme —
|
|
101
55
|
* var(--color-bright) resolves in the element's own context, so a theme only
|
|
102
56
|
* names this if it wants links to differ from emphasis text (signalnine
|
|
@@ -142,6 +96,54 @@
|
|
|
142
96
|
--color-warning-fg: oklch(0.162 0 none);
|
|
143
97
|
}
|
|
144
98
|
|
|
99
|
+
/* -------------------------------------------------- */
|
|
100
|
+
/* Emphasis + body ink — one law for every theme */
|
|
101
|
+
/* -------------------------------------------------- */
|
|
102
|
+
/* Declared ONCE and inherited, exactly like --color-link below in the base
|
|
103
|
+
* block: every theme selector targets the same elements (:root / a .dark or
|
|
104
|
+
* .light subtree), and the mixes reference tokens that resolve against THAT
|
|
105
|
+
* element's own ramp and accent — so each theme gets its own result from one
|
|
106
|
+
* formula, and a new theme cannot forget the law by not copying it.
|
|
107
|
+
*
|
|
108
|
+
* EMPHASIS INK IS TINTED BY THE THEME, not pinned to the top of the ramp.
|
|
109
|
+
* Step 12 is the ramp's extreme, and at the extreme a neutral ramp has run
|
|
110
|
+
* out of colour — bright used to come out pure white on the dark themes and
|
|
111
|
+
* literally #000 on signalnine light. That is the one place a themed UI
|
|
112
|
+
* should NOT go achromatic: bright is the emphasis ink (headings, titles,
|
|
113
|
+
* the sentence you are meant to read first), so it is the text carrying the
|
|
114
|
+
* most identity and it was carrying none. It takes 12% of --color-primary —
|
|
115
|
+
* the theme's own accent, and the property the accent picker writes, so
|
|
116
|
+
* choosing an accent tints the emphasis text live. 12% is a cast, not a
|
|
117
|
+
* colour: lightness moves ~0.02 (the default dark page keeps 11.6:1) and
|
|
118
|
+
* chroma lands near 0.013 — "warm white" / "blue-black", never a coloured
|
|
119
|
+
* heading. A theme whose accent IS neutral is unchanged by construction.
|
|
120
|
+
*
|
|
121
|
+
* The achromatic ramp steps are written with hue `none` rather than hue 0,
|
|
122
|
+
* and that is load-bearing here: hue 0 is a REAL hue (red), so oklch
|
|
123
|
+
* interpolation walks it toward the accent's hue the short way — #000 mixed
|
|
124
|
+
* with a CTA blue came out magenta. `none` marks the hue powerless (which it
|
|
125
|
+
* is at chroma 0), so the mix ADOPTS the accent's hue instead of travelling
|
|
126
|
+
* to it.
|
|
127
|
+
*
|
|
128
|
+
* MUTED IS BODY COPY, not a de-emphasis wash — the /text page sets whole
|
|
129
|
+
* paragraphs in it — so it does not sit flat on step 10: it leans 40% of the
|
|
130
|
+
* way to bright (10.43:1 on the default dark page; step 10 alone read as
|
|
131
|
+
* "greyed out" at paragraph length). It aims at BRIGHT rather than fg on
|
|
132
|
+
* purpose: fg is the ink of controls and labels, bright is the ink of the
|
|
133
|
+
* sentence you are meant to read, and body copy belongs with the second one
|
|
134
|
+
* — which also hands muted the theme's tint. The ordering muted < fg <
|
|
135
|
+
* bright holds by a clear margin (0.80 / 0.86 / 0.93 in dark).
|
|
136
|
+
*
|
|
137
|
+
* signalnine overrides muted only (measured source colours — Tomorrow's
|
|
138
|
+
* comment grey, yahoo's #5c7eb8): the single deliberate exception, and it
|
|
139
|
+
* wins on specificity, not on order. */
|
|
140
|
+
:root,
|
|
141
|
+
.dark,
|
|
142
|
+
.light {
|
|
143
|
+
--color-bright: color-mix(in oklch, var(--color-12) 88%, var(--color-primary));
|
|
144
|
+
--color-muted: color-mix(in oklch, var(--color-10) 60%, var(--color-bright));
|
|
145
|
+
}
|
|
146
|
+
|
|
145
147
|
/* -------------------------------------------------- */
|
|
146
148
|
/* Light theme (reversed scale) */
|
|
147
149
|
/* -------------------------------------------------- */
|
|
@@ -166,8 +168,6 @@
|
|
|
166
168
|
--color-surface: var(--color-2);
|
|
167
169
|
--color-hover: oklch(0.8 0 none);
|
|
168
170
|
--color-fg: var(--color-11);
|
|
169
|
-
--color-bright: color-mix(in oklch, var(--color-12) 88%, var(--color-primary));
|
|
170
|
-
--color-muted: color-mix(in oklch, var(--color-10) 60%, var(--color-bright));
|
|
171
171
|
|
|
172
172
|
/* Accent tokens */
|
|
173
173
|
--color-primary: var(--color-fg);
|
|
@@ -205,8 +205,6 @@
|
|
|
205
205
|
--color-surface: var(--color-2);
|
|
206
206
|
--color-hover: oklch(0.8 0 none);
|
|
207
207
|
--color-fg: var(--color-11);
|
|
208
|
-
--color-bright: color-mix(in oklch, var(--color-12) 88%, var(--color-primary));
|
|
209
|
-
--color-muted: color-mix(in oklch, var(--color-10) 60%, var(--color-bright));
|
|
210
208
|
|
|
211
209
|
/* Accent tokens */
|
|
212
210
|
--color-primary: var(--color-fg);
|
|
@@ -249,8 +247,6 @@
|
|
|
249
247
|
--color-surface: var(--color-2);
|
|
250
248
|
--color-hover: oklch(0.252 0.024 56);
|
|
251
249
|
--color-fg: var(--color-11);
|
|
252
|
-
--color-bright: color-mix(in oklch, var(--color-12) 88%, var(--color-primary));
|
|
253
|
-
--color-muted: color-mix(in oklch, var(--color-10) 60%, var(--color-bright));
|
|
254
250
|
|
|
255
251
|
/* Warm sandstone primary + unexpected turquoise support. */
|
|
256
252
|
--color-primary: oklch(0.74 0.108 68);
|
|
@@ -293,8 +289,6 @@
|
|
|
293
289
|
--color-surface: var(--color-2);
|
|
294
290
|
--color-hover: oklch(0.81 0.022 73);
|
|
295
291
|
--color-fg: var(--color-11);
|
|
296
|
-
--color-bright: color-mix(in oklch, var(--color-12) 88%, var(--color-primary));
|
|
297
|
-
--color-muted: color-mix(in oklch, var(--color-10) 60%, var(--color-bright));
|
|
298
292
|
|
|
299
293
|
--color-primary: oklch(0.515 0.16 38);
|
|
300
294
|
--color-primary-fg: oklch(0.96 0.014 78);
|
|
@@ -328,8 +322,6 @@
|
|
|
328
322
|
--color-surface: var(--color-2);
|
|
329
323
|
--color-hover: oklch(0.81 0.022 73);
|
|
330
324
|
--color-fg: var(--color-11);
|
|
331
|
-
--color-bright: color-mix(in oklch, var(--color-12) 88%, var(--color-primary));
|
|
332
|
-
--color-muted: color-mix(in oklch, var(--color-10) 60%, var(--color-bright));
|
|
333
325
|
|
|
334
326
|
--color-primary: oklch(0.515 0.16 38);
|
|
335
327
|
--color-primary-fg: oklch(0.96 0.014 78);
|
|
@@ -366,8 +358,6 @@
|
|
|
366
358
|
--color-surface: var(--color-2);
|
|
367
359
|
--color-hover: color-mix(in oklch, var(--color-3) 80%, var(--color-2));
|
|
368
360
|
--color-fg: var(--color-11);
|
|
369
|
-
--color-bright: color-mix(in oklch, var(--color-12) 88%, var(--color-primary));
|
|
370
|
-
--color-muted: color-mix(in oklch, var(--color-10) 60%, var(--color-bright));
|
|
371
361
|
|
|
372
362
|
--color-primary: oklch(0.8 0.034 54);
|
|
373
363
|
--color-primary-fg: var(--color-1);
|
|
@@ -404,8 +394,6 @@
|
|
|
404
394
|
--color-surface: var(--color-2);
|
|
405
395
|
--color-hover: oklch(0.88 0.016 72);
|
|
406
396
|
--color-fg: var(--color-11);
|
|
407
|
-
--color-bright: color-mix(in oklch, var(--color-12) 88%, var(--color-primary));
|
|
408
|
-
--color-muted: color-mix(in oklch, var(--color-10) 60%, var(--color-bright));
|
|
409
397
|
|
|
410
398
|
--color-primary: oklch(0.55 0.12 58);
|
|
411
399
|
--color-primary-fg: oklch(0.97 0.008 80);
|
|
@@ -439,8 +427,6 @@
|
|
|
439
427
|
--color-surface: var(--color-2);
|
|
440
428
|
--color-hover: oklch(0.88 0.016 72);
|
|
441
429
|
--color-fg: var(--color-11);
|
|
442
|
-
--color-bright: color-mix(in oklch, var(--color-12) 88%, var(--color-primary));
|
|
443
|
-
--color-muted: color-mix(in oklch, var(--color-10) 60%, var(--color-bright));
|
|
444
430
|
|
|
445
431
|
--color-primary: oklch(0.55 0.12 58);
|
|
446
432
|
--color-primary-fg: oklch(0.97 0.008 80);
|
|
@@ -513,7 +499,6 @@
|
|
|
513
499
|
--color-surface: var(--color-2);
|
|
514
500
|
--color-hover: oklch(0.255 0.006 84);
|
|
515
501
|
--color-fg: var(--color-11);
|
|
516
|
-
--color-bright: color-mix(in oklch, var(--color-12) 88%, var(--color-primary));
|
|
517
502
|
/* Tomorrow's comment grey, which is what it uses for de-emphasised text. */
|
|
518
503
|
--color-muted: var(--color-8);
|
|
519
504
|
/* The link follows the accent — one ink for "this is interactive". */
|
|
@@ -608,7 +593,6 @@
|
|
|
608
593
|
--color-surface: var(--color-2);
|
|
609
594
|
--color-hover: oklch(0.97 0.014 268.5); /* #f1f5ff */
|
|
610
595
|
--color-fg: var(--color-11);
|
|
611
|
-
--color-bright: color-mix(in oklch, var(--color-12) 88%, var(--color-primary));
|
|
612
596
|
--color-muted: var(--color-7);
|
|
613
597
|
--color-link: var(--color-10);
|
|
614
598
|
/* Cards read --era-surface-bg, which the surface contract defines as
|
|
@@ -651,7 +635,6 @@
|
|
|
651
635
|
--color-surface: var(--color-2);
|
|
652
636
|
--color-hover: oklch(0.97 0.014 268.5); /* #f1f5ff */
|
|
653
637
|
--color-fg: var(--color-11);
|
|
654
|
-
--color-bright: color-mix(in oklch, var(--color-12) 88%, var(--color-primary));
|
|
655
638
|
--color-muted: var(--color-7);
|
|
656
639
|
--color-link: var(--color-10);
|
|
657
640
|
/* Cards read --era-surface-bg, which the surface contract defines as
|
package/dist/ui/bar/bar.svelte
CHANGED
|
@@ -34,6 +34,28 @@
|
|
|
34
34
|
content: {
|
|
35
35
|
tier: 'gap-(--era-xs-inset-sm) px-(--era-xs-inset-sm)',
|
|
36
36
|
xxs: ''
|
|
37
|
+
},
|
|
38
|
+
/**
|
|
39
|
+
* The flush header bar capping a panel — Pane.Handle, Dialog.Header,
|
|
40
|
+
* an app's own section bars. One variant because the law kept getting
|
|
41
|
+
* restated by hand at every site:
|
|
42
|
+
*
|
|
43
|
+
* - shrink-0: the bar holds its tier height in a flex column.
|
|
44
|
+
* - The divider is drawn OUTSIDE the box (0 1px 0, never inset). An
|
|
45
|
+
* inset shadow paints over the bar's last pixel row, which belongs to
|
|
46
|
+
* the content's own bottom gap — a centred 18px control in a 24px bar
|
|
47
|
+
* has 3px above and 3 below, and the inset line ate one of the three.
|
|
48
|
+
* Outset costs no layout and puts the line on the boundary between
|
|
49
|
+
* the bar and what's beneath it.
|
|
50
|
+
* - Corners: the TOP defers to the panel's own radius (transparent bar,
|
|
51
|
+
* rounded surface behind), the BOTTOM rounds to rd-md so the divider
|
|
52
|
+
* curves up at the ends and the bar reads as a long pill. A square
|
|
53
|
+
* in-app bar (Notes) passes `rounded-none` and tailwind-merge drops
|
|
54
|
+
* both. Collapses to flat in square mode like every radius.
|
|
55
|
+
*/
|
|
56
|
+
divider: {
|
|
57
|
+
true: 'shrink-0 rounded-t-none rounded-b-(--era-rd-md) [box-shadow:0_1px_0_var(--color-divider-faded)]',
|
|
58
|
+
false: ''
|
|
37
59
|
}
|
|
38
60
|
},
|
|
39
61
|
compoundVariants: [
|
|
@@ -45,7 +67,7 @@
|
|
|
45
67
|
// token because nothing pairs a page header with pill-tier controls.)
|
|
46
68
|
{ size: 'sm', content: 'xxs', class: 'gap-(--era-xxs-inset-sm) px-(--era-xxs-inset-sm)' }
|
|
47
69
|
],
|
|
48
|
-
defaultVariants: { size: 'lg', content: 'tier' }
|
|
70
|
+
defaultVariants: { size: 'lg', content: 'tier', divider: false }
|
|
49
71
|
});
|
|
50
72
|
</script>
|
|
51
73
|
|
|
@@ -57,6 +79,7 @@
|
|
|
57
79
|
ref = $bindable(null),
|
|
58
80
|
size = 'lg',
|
|
59
81
|
content = 'tier',
|
|
82
|
+
divider = false,
|
|
60
83
|
children,
|
|
61
84
|
class: className,
|
|
62
85
|
...restProps
|
|
@@ -70,10 +93,12 @@
|
|
|
70
93
|
* the compact pairing (xxs pills/fields in an sm or md bar).
|
|
71
94
|
*/
|
|
72
95
|
content?: 'tier' | 'xxs';
|
|
96
|
+
/** The flush cap-a-panel chrome: outset divider below, bottom rd-md. */
|
|
97
|
+
divider?: boolean;
|
|
73
98
|
children?: Snippet;
|
|
74
99
|
} = $props();
|
|
75
100
|
</script>
|
|
76
101
|
|
|
77
|
-
<div bind:this={ref} class={cn(barVariants({ size, content }), className)} {...restProps}>
|
|
102
|
+
<div bind:this={ref} class={cn(barVariants({ size, content, divider }), className)} {...restProps}>
|
|
78
103
|
{@render children?.()}
|
|
79
104
|
</div>
|
|
@@ -22,6 +22,28 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
|
|
|
22
22
|
tier: "gap-(--era-xs-inset-sm) px-(--era-xs-inset-sm)";
|
|
23
23
|
xxs: "";
|
|
24
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* The flush header bar capping a panel — Pane.Handle, Dialog.Header,
|
|
27
|
+
* an app's own section bars. One variant because the law kept getting
|
|
28
|
+
* restated by hand at every site:
|
|
29
|
+
*
|
|
30
|
+
* - shrink-0: the bar holds its tier height in a flex column.
|
|
31
|
+
* - The divider is drawn OUTSIDE the box (0 1px 0, never inset). An
|
|
32
|
+
* inset shadow paints over the bar's last pixel row, which belongs to
|
|
33
|
+
* the content's own bottom gap — a centred 18px control in a 24px bar
|
|
34
|
+
* has 3px above and 3 below, and the inset line ate one of the three.
|
|
35
|
+
* Outset costs no layout and puts the line on the boundary between
|
|
36
|
+
* the bar and what's beneath it.
|
|
37
|
+
* - Corners: the TOP defers to the panel's own radius (transparent bar,
|
|
38
|
+
* rounded surface behind), the BOTTOM rounds to rd-md so the divider
|
|
39
|
+
* curves up at the ends and the bar reads as a long pill. A square
|
|
40
|
+
* in-app bar (Notes) passes `rounded-none` and tailwind-merge drops
|
|
41
|
+
* both. Collapses to flat in square mode like every radius.
|
|
42
|
+
*/
|
|
43
|
+
divider: {
|
|
44
|
+
true: "shrink-0 rounded-t-none rounded-b-(--era-rd-md) [box-shadow:0_1px_0_var(--color-divider-faded)]";
|
|
45
|
+
false: "";
|
|
46
|
+
};
|
|
25
47
|
}, undefined, "flex items-center era-text-trim", {
|
|
26
48
|
size: {
|
|
27
49
|
sm: "h-(--era-h-sm) rounded-(--era-rd-sm)";
|
|
@@ -46,6 +68,28 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
|
|
|
46
68
|
tier: "gap-(--era-xs-inset-sm) px-(--era-xs-inset-sm)";
|
|
47
69
|
xxs: "";
|
|
48
70
|
};
|
|
71
|
+
/**
|
|
72
|
+
* The flush header bar capping a panel — Pane.Handle, Dialog.Header,
|
|
73
|
+
* an app's own section bars. One variant because the law kept getting
|
|
74
|
+
* restated by hand at every site:
|
|
75
|
+
*
|
|
76
|
+
* - shrink-0: the bar holds its tier height in a flex column.
|
|
77
|
+
* - The divider is drawn OUTSIDE the box (0 1px 0, never inset). An
|
|
78
|
+
* inset shadow paints over the bar's last pixel row, which belongs to
|
|
79
|
+
* the content's own bottom gap — a centred 18px control in a 24px bar
|
|
80
|
+
* has 3px above and 3 below, and the inset line ate one of the three.
|
|
81
|
+
* Outset costs no layout and puts the line on the boundary between
|
|
82
|
+
* the bar and what's beneath it.
|
|
83
|
+
* - Corners: the TOP defers to the panel's own radius (transparent bar,
|
|
84
|
+
* rounded surface behind), the BOTTOM rounds to rd-md so the divider
|
|
85
|
+
* curves up at the ends and the bar reads as a long pill. A square
|
|
86
|
+
* in-app bar (Notes) passes `rounded-none` and tailwind-merge drops
|
|
87
|
+
* both. Collapses to flat in square mode like every radius.
|
|
88
|
+
*/
|
|
89
|
+
divider: {
|
|
90
|
+
true: "shrink-0 rounded-t-none rounded-b-(--era-rd-md) [box-shadow:0_1px_0_var(--color-divider-faded)]";
|
|
91
|
+
false: "";
|
|
92
|
+
};
|
|
49
93
|
}, undefined, import("tailwind-variants").TVReturnTypeLike<{
|
|
50
94
|
size: {
|
|
51
95
|
sm: "h-(--era-h-sm) rounded-(--era-rd-sm)";
|
|
@@ -70,6 +114,28 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
|
|
|
70
114
|
tier: "gap-(--era-xs-inset-sm) px-(--era-xs-inset-sm)";
|
|
71
115
|
xxs: "";
|
|
72
116
|
};
|
|
117
|
+
/**
|
|
118
|
+
* The flush header bar capping a panel — Pane.Handle, Dialog.Header,
|
|
119
|
+
* an app's own section bars. One variant because the law kept getting
|
|
120
|
+
* restated by hand at every site:
|
|
121
|
+
*
|
|
122
|
+
* - shrink-0: the bar holds its tier height in a flex column.
|
|
123
|
+
* - The divider is drawn OUTSIDE the box (0 1px 0, never inset). An
|
|
124
|
+
* inset shadow paints over the bar's last pixel row, which belongs to
|
|
125
|
+
* the content's own bottom gap — a centred 18px control in a 24px bar
|
|
126
|
+
* has 3px above and 3 below, and the inset line ate one of the three.
|
|
127
|
+
* Outset costs no layout and puts the line on the boundary between
|
|
128
|
+
* the bar and what's beneath it.
|
|
129
|
+
* - Corners: the TOP defers to the panel's own radius (transparent bar,
|
|
130
|
+
* rounded surface behind), the BOTTOM rounds to rd-md so the divider
|
|
131
|
+
* curves up at the ends and the bar reads as a long pill. A square
|
|
132
|
+
* in-app bar (Notes) passes `rounded-none` and tailwind-merge drops
|
|
133
|
+
* both. Collapses to flat in square mode like every radius.
|
|
134
|
+
*/
|
|
135
|
+
divider: {
|
|
136
|
+
true: "shrink-0 rounded-t-none rounded-b-(--era-rd-md) [box-shadow:0_1px_0_var(--color-divider-faded)]";
|
|
137
|
+
false: "";
|
|
138
|
+
};
|
|
73
139
|
}, undefined>>;
|
|
74
140
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
75
141
|
import type { Snippet } from 'svelte';
|
|
@@ -83,6 +149,8 @@ type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
|
|
|
83
149
|
* the compact pairing (xxs pills/fields in an sm or md bar).
|
|
84
150
|
*/
|
|
85
151
|
content?: 'tier' | 'xxs';
|
|
152
|
+
/** The flush cap-a-panel chrome: outset divider below, bottom rd-md. */
|
|
153
|
+
divider?: boolean;
|
|
86
154
|
children?: Snippet;
|
|
87
155
|
};
|
|
88
156
|
declare const Bar: import("svelte").Component<$$ComponentProps, {}, "ref">;
|
|
@@ -15,16 +15,13 @@
|
|
|
15
15
|
<ContextMenu.Content
|
|
16
16
|
bind:ref
|
|
17
17
|
align="start"
|
|
18
|
-
// p-
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// conversations rail already documents). It is >= the panel inset at every
|
|
24
|
-
// density, so glass and bevel keep the frame protection the inset exists
|
|
25
|
-
// for.
|
|
18
|
+
// p-(--era-panel-inset), SURFACE-owned on purpose: 0 on flat — rows run the
|
|
19
|
+
// panel's full width, flush, and the first row sits directly under the
|
|
20
|
+
// anchor bar (the reference terminal look) — while glass and bevel keep the
|
|
21
|
+
// 2px frame that stops a full-width highlight from breaking their chrome.
|
|
22
|
+
// A fixed gutter was tried here and rejected: it padded flat menus too.
|
|
26
23
|
class={cn(
|
|
27
|
-
'z-50 w-max overflow-hidden rounded-(--era-rd-md) bg-(--era-surface-bg-elevated) p-
|
|
24
|
+
'z-50 w-max overflow-hidden rounded-(--era-rd-md) bg-(--era-surface-bg-elevated) p-(--era-panel-inset) shadow-(--era-shadow-lg) glass-blur',
|
|
28
25
|
className
|
|
29
26
|
)}
|
|
30
27
|
{sideOffset}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import { Dialog } from 'bits-ui';
|
|
4
|
+
import Overlay from './dialog-overlay.svelte';
|
|
4
5
|
import { cn, type PartProps } from '../../utils/index.js';
|
|
5
6
|
|
|
6
7
|
let {
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
</script>
|
|
23
24
|
|
|
24
25
|
<Dialog.Portal>
|
|
25
|
-
<
|
|
26
|
+
<Overlay />
|
|
26
27
|
<!-- border-divider: the pane's hairline-edge law. A floating panel must be
|
|
27
28
|
separable from what's behind it, and on the flat surface shadow-lg
|
|
28
29
|
collapses to none — without the hairline the whole edge was a tone step. -->
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
-
import { Dialog } from 'bits-ui';
|
|
4
3
|
import X from '@lucide/svelte/icons/x';
|
|
5
4
|
import { Bar } from '../bar';
|
|
6
|
-
import { Button } from '../button';
|
|
7
5
|
import { cn } from '../../utils/index.js';
|
|
6
|
+
import Close from './dialog-close.svelte';
|
|
8
7
|
|
|
9
8
|
let {
|
|
10
9
|
dismissable = true,
|
|
@@ -18,39 +17,25 @@
|
|
|
18
17
|
} = $props();
|
|
19
18
|
</script>
|
|
20
19
|
|
|
21
|
-
<!-- The pane handle's chrome
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
<!-- The pane handle's chrome — by reference, not by copy: Bar's `divider`
|
|
21
|
+
variant IS the cap law (outset divider, rd-md corners), shared with
|
|
22
|
+
Pane.Handle. What this part adds:
|
|
24
23
|
|
|
25
|
-
· an md bar holding xxs controls, walls and gap --era-xxs-inset-md
|
|
26
|
-
· the divider drawn OUTSIDE the box (an inset one eats a pixel of every
|
|
27
|
-
child's bottom gap — see Pane.Handle)
|
|
28
24
|
· the leading side at --era-inset-md: a title has no corner to nest, so
|
|
29
25
|
it takes the text inset, the same asymmetry the pane and the
|
|
30
26
|
Conversations row document
|
|
31
|
-
· the × is the dismiss family's: an xxs
|
|
32
|
-
12px ink, destructive like Pane.Close
|
|
27
|
+
· the × is the dismiss family's: an xxs `Dialog.Close` whose tier
|
|
28
|
+
default IS the 12px ink, destructive like Pane.Close
|
|
33
29
|
|
|
34
30
|
Rendered flush by Dialog.Content / Sheet.Content when passed as their
|
|
35
31
|
`header` snippet, so the bar spans the panel edge to edge and the panel's
|
|
36
32
|
radius follows this corner region (rd-md — the same law that sizes the
|
|
37
33
|
pane's own corners). -->
|
|
38
|
-
<Bar
|
|
39
|
-
size="md"
|
|
40
|
-
content="xxs"
|
|
41
|
-
class={cn(
|
|
42
|
-
'shrink-0 rounded-t-none rounded-b-(--era-rd-md) pl-(--era-inset-md) [box-shadow:0_1px_0_var(--color-divider-faded)] select-none',
|
|
43
|
-
className
|
|
44
|
-
)}
|
|
45
|
-
>
|
|
34
|
+
<Bar size="md" content="xxs" divider class={cn('pl-(--era-inset-md) select-none', className)}>
|
|
46
35
|
{@render children?.()}
|
|
47
36
|
{#if dismissable}
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
<X />
|
|
52
|
-
</Button>
|
|
53
|
-
{/snippet}
|
|
54
|
-
</Dialog.Close>
|
|
37
|
+
<Close icon size="xxs" tone="destructive" aria-label="Close" class="ml-auto">
|
|
38
|
+
<X />
|
|
39
|
+
</Close>
|
|
55
40
|
{/if}
|
|
56
41
|
</Bar>
|
|
@@ -15,16 +15,13 @@
|
|
|
15
15
|
<DropdownMenu.Content
|
|
16
16
|
bind:ref
|
|
17
17
|
align="start"
|
|
18
|
-
// p-
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// conversations rail already documents). It is >= the panel inset at every
|
|
24
|
-
// density, so glass and bevel keep the frame protection the inset exists
|
|
25
|
-
// for.
|
|
18
|
+
// p-(--era-panel-inset), SURFACE-owned on purpose: 0 on flat — rows run the
|
|
19
|
+
// panel's full width, flush, and the first row sits directly under the
|
|
20
|
+
// anchor bar (the reference terminal look) — while glass and bevel keep the
|
|
21
|
+
// 2px frame that stops a full-width highlight from breaking their chrome.
|
|
22
|
+
// A fixed gutter was tried here and rejected: it padded flat menus too.
|
|
26
23
|
class={cn(
|
|
27
|
-
'z-50 w-max min-w-(--bits-dropdown-menu-anchor-width) overflow-hidden rounded-(--era-rd-md) bg-(--era-surface-bg-elevated) p-
|
|
24
|
+
'z-50 w-max min-w-(--bits-dropdown-menu-anchor-width) overflow-hidden rounded-(--era-rd-md) bg-(--era-surface-bg-elevated) p-(--era-panel-inset) shadow-(--era-shadow-lg) glass-blur data-[side=bottom]:rounded-t-none data-[side=top]:rounded-b-none',
|
|
28
25
|
className
|
|
29
26
|
)}
|
|
30
27
|
{sideOffset}
|
|
@@ -15,16 +15,13 @@
|
|
|
15
15
|
<Menubar.Content
|
|
16
16
|
bind:ref
|
|
17
17
|
align="start"
|
|
18
|
-
// p-
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// conversations rail already documents). It is >= the panel inset at every
|
|
24
|
-
// density, so glass and bevel keep the frame protection the inset exists
|
|
25
|
-
// for.
|
|
18
|
+
// p-(--era-panel-inset), SURFACE-owned on purpose: 0 on flat — rows run the
|
|
19
|
+
// panel's full width, flush, and the first row sits directly under the
|
|
20
|
+
// anchor bar (the reference terminal look) — while glass and bevel keep the
|
|
21
|
+
// 2px frame that stops a full-width highlight from breaking their chrome.
|
|
22
|
+
// A fixed gutter was tried here and rejected: it padded flat menus too.
|
|
26
23
|
class={cn(
|
|
27
|
-
'z-50 w-max min-w-(--bits-menubar-menu-anchor-width) overflow-hidden rounded-(--era-rd-md) bg-(--era-surface-bg-elevated) p-
|
|
24
|
+
'z-50 w-max min-w-(--bits-menubar-menu-anchor-width) overflow-hidden rounded-(--era-rd-md) bg-(--era-surface-bg-elevated) p-(--era-panel-inset) shadow-(--era-shadow-lg) glass-blur data-[side=bottom]:rounded-t-none data-[side=top]:rounded-b-none',
|
|
28
25
|
className
|
|
29
26
|
)}
|
|
30
27
|
{sideOffset}
|
|
@@ -42,22 +42,12 @@
|
|
|
42
42
|
data-pane-handle
|
|
43
43
|
size="md"
|
|
44
44
|
content="xxs"
|
|
45
|
+
divider
|
|
45
46
|
class={cn(
|
|
46
|
-
// The
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
// bar has 3px above and 3px below, and the inset line ate one of the three
|
|
51
|
-
// below it. Every child of the bar therefore read 3px on top and right but
|
|
52
|
-
// 2px on the bottom — even by the box, visibly tight to the eye, which
|
|
53
|
-
// measures to the LINE.
|
|
54
|
-
//
|
|
55
|
-
// Outset costs no layout (so the bar keeps its full 24px content box and the
|
|
56
|
-
// concentric 3px walls) and puts the line where it belongs: the boundary
|
|
57
|
-
// between the bar and the content beneath it, rather than a pixel of the
|
|
58
|
-
// bar itself. It still follows the bottom radius, so the divider curves up
|
|
59
|
-
// at the ends exactly as before.
|
|
60
|
-
'shrink-0 rounded-t-none rounded-b-(--era-rd-md) [box-shadow:0_1px_0_var(--color-divider-faded)] select-none',
|
|
47
|
+
// The cap chrome (outset divider, rd-md bottom corners) is Bar's `divider`
|
|
48
|
+
// variant — the law and its full rationale live there, shared with
|
|
49
|
+
// Dialog.Header and any app's own section bars.
|
|
50
|
+
'select-none',
|
|
61
51
|
// THE CENTRE LAW — [minmax(0,1fr) minmax(0,auto) minmax(0,1fr)].
|
|
62
52
|
//
|
|
63
53
|
// A centred title must be centred on the BAR, not on whatever space the
|
|
@@ -77,16 +67,19 @@
|
|
|
77
67
|
{...restProps}
|
|
78
68
|
>
|
|
79
69
|
{#if center}
|
|
80
|
-
|
|
70
|
+
<!-- gap-[inherit] on every cluster: whatever gap the Bar resolved — its
|
|
71
|
+
content pairing, or a caller's override (the os pane sets --era-gap) —
|
|
72
|
+
is also the rhythm INSIDE each cluster, so the two can never drift. -->
|
|
73
|
+
<div class="flex min-w-0 items-center gap-[inherit]">{@render children?.()}</div>
|
|
81
74
|
<!-- Anything interactive dropped in here (an editable title, a picker)
|
|
82
75
|
carries data-pane-control itself: the bar is the drag zone, and only
|
|
83
76
|
the control can know that a press on it means caret, not drag. -->
|
|
84
|
-
<div class="flex min-w-0 items-center justify-center gap-
|
|
85
|
-
<div class="flex min-w-0 items-center justify-end gap-
|
|
77
|
+
<div class="flex min-w-0 items-center justify-center gap-[inherit]">{@render center()}</div>
|
|
78
|
+
<div class="flex min-w-0 items-center justify-end gap-[inherit]">{@render trail?.()}</div>
|
|
86
79
|
{:else}
|
|
87
80
|
{@render children?.()}
|
|
88
81
|
{#if trail}
|
|
89
|
-
<div class="ml-auto flex shrink-0 items-center gap-
|
|
82
|
+
<div class="ml-auto flex shrink-0 items-center gap-[inherit]">{@render trail()}</div>
|
|
90
83
|
{/if}
|
|
91
84
|
{/if}
|
|
92
85
|
</Bar>
|