@signal9/era-ui 4.12.1 → 4.14.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/dist/ai/conversation/conversation-empty-state.svelte +1 -1
- package/dist/ai/error-panel/error-panel.svelte +1 -1
- package/dist/ai/message/message-content.svelte +1 -1
- package/dist/ai/prompt-input/prompt-input-textarea.svelte +1 -1
- package/dist/ai/response/response.svelte +1 -1
- package/dist/ai/swarm/swarm-artifact.svelte +1 -1
- package/dist/ai/tool/tool-output.svelte +1 -1
- package/dist/apps/llm-shell/llm-shell.svelte +1 -1
- package/dist/dev/audit/audits/index.d.ts +2 -1
- package/dist/dev/audit/audits/index.js +3 -1
- package/dist/dev/audit/audits/prose-leading.d.ts +2 -0
- package/dist/dev/audit/audits/prose-leading.js +91 -0
- package/dist/era-ui.css +1 -1
- package/dist/generated-docs/dialog.md +14 -0
- package/dist/generated-docs/llms-full.txt +14 -0
- package/dist/generated-docs/manifest.json +3 -2
- package/dist/os/notification-center.svelte +3 -1
- package/dist/os/toast.svelte +6 -3
- package/dist/styles/density.css +19 -0
- package/dist/styles/index.css +4 -0
- package/dist/styles/themes.css +21 -9
- package/dist/ui/accordion/accordion-content.svelte +1 -1
- package/dist/ui/alert-dialog/alert-dialog-content.svelte +1 -1
- package/dist/ui/alert-dialog/alert-dialog-description.svelte +1 -1
- package/dist/ui/code-block/code-block.svelte +1 -1
- package/dist/ui/dialog/dialog-content.svelte +25 -3
- package/dist/ui/dialog/dialog-content.svelte.d.ts +12 -1
- package/dist/ui/dialog/dialog-description.svelte +1 -1
- package/dist/ui/dialog/dialog-header.svelte +56 -0
- package/dist/ui/dialog/dialog-header.svelte.d.ts +10 -0
- package/dist/ui/dialog/index.d.ts +1 -0
- package/dist/ui/dialog/index.js +1 -0
- package/dist/ui/sheet/index.d.ts +1 -1
- package/dist/ui/sheet/index.js +1 -1
- package/dist/ui/sheet/sheet-content.svelte +44 -9
- package/dist/ui/sheet/sheet-content.svelte.d.ts +49 -13
- package/package.json +1 -1
|
@@ -16,6 +16,7 @@ Composed from sub-components — compose explicitly at the call site:
|
|
|
16
16
|
- `Dialog.Title`
|
|
17
17
|
- `Dialog.Description`
|
|
18
18
|
- `Dialog.Close`
|
|
19
|
+
- `Dialog.Header`
|
|
19
20
|
|
|
20
21
|
## Dialog.Trigger
|
|
21
22
|
|
|
@@ -33,6 +34,11 @@ Inherits all props from `PartProps<Dialog.ContentProps>`.
|
|
|
33
34
|
|
|
34
35
|
| Prop | Type | Default | Notes |
|
|
35
36
|
|------|------|---------|-------|
|
|
37
|
+
| `header?` | `Snippet` | — | A top bar in the pane's grammar — pass `Dialog.Header` (usually holding
|
|
38
|
+
`Dialog.Title`). With it the panel goes sectioned like a Card: the bar
|
|
39
|
+
runs edge to edge, the body keeps the padding, and the radius drops to
|
|
40
|
+
rd-md because the panel's corners are now formed by an md bar holding xxs
|
|
41
|
+
controls — the identical law that sizes the pane's own corners. |
|
|
36
42
|
| `ref?` | `(forwarded)` | `null` | bindable |
|
|
37
43
|
|
|
38
44
|
## Dialog.Overlay
|
|
@@ -68,3 +74,11 @@ Inherits all props from `Omit<ButtonVariants, 'active'>`.
|
|
|
68
74
|
|------|------|---------|-------|
|
|
69
75
|
| `children?` | `Snippet` | — | — |
|
|
70
76
|
| `ref?` | `(forwarded)` | `null` | bindable |
|
|
77
|
+
|
|
78
|
+
## Dialog.Header
|
|
79
|
+
|
|
80
|
+
| Prop | Type | Default | Notes |
|
|
81
|
+
|------|------|---------|-------|
|
|
82
|
+
| `dismissable?` | `boolean` | `true` | Render the trailing × (a `Dialog.Close`). Off for flows that must resolve. |
|
|
83
|
+
| `children?` | `Snippet` | — | — |
|
|
84
|
+
| `class?` | `string` | — | — |
|
|
@@ -2594,6 +2594,7 @@ Composed from sub-components — compose explicitly at the call site:
|
|
|
2594
2594
|
- `Dialog.Title`
|
|
2595
2595
|
- `Dialog.Description`
|
|
2596
2596
|
- `Dialog.Close`
|
|
2597
|
+
- `Dialog.Header`
|
|
2597
2598
|
|
|
2598
2599
|
## Dialog.Trigger
|
|
2599
2600
|
|
|
@@ -2611,6 +2612,11 @@ Inherits all props from `PartProps<Dialog.ContentProps>`.
|
|
|
2611
2612
|
|
|
2612
2613
|
| Prop | Type | Default | Notes |
|
|
2613
2614
|
|------|------|---------|-------|
|
|
2615
|
+
| `header?` | `Snippet` | — | A top bar in the pane's grammar — pass `Dialog.Header` (usually holding
|
|
2616
|
+
`Dialog.Title`). With it the panel goes sectioned like a Card: the bar
|
|
2617
|
+
runs edge to edge, the body keeps the padding, and the radius drops to
|
|
2618
|
+
rd-md because the panel's corners are now formed by an md bar holding xxs
|
|
2619
|
+
controls — the identical law that sizes the pane's own corners. |
|
|
2614
2620
|
| `ref?` | `(forwarded)` | `null` | bindable |
|
|
2615
2621
|
|
|
2616
2622
|
## Dialog.Overlay
|
|
@@ -2647,6 +2653,14 @@ Inherits all props from `Omit<ButtonVariants, 'active'>`.
|
|
|
2647
2653
|
| `children?` | `Snippet` | — | — |
|
|
2648
2654
|
| `ref?` | `(forwarded)` | `null` | bindable |
|
|
2649
2655
|
|
|
2656
|
+
## Dialog.Header
|
|
2657
|
+
|
|
2658
|
+
| Prop | Type | Default | Notes |
|
|
2659
|
+
|------|------|---------|-------|
|
|
2660
|
+
| `dismissable?` | `boolean` | `true` | Render the trailing × (a `Dialog.Close`). Off for flows that must resolve. |
|
|
2661
|
+
| `children?` | `Snippet` | — | — |
|
|
2662
|
+
| `class?` | `string` | — | — |
|
|
2663
|
+
|
|
2650
2664
|
<!-- end: dialog -->
|
|
2651
2665
|
|
|
2652
2666
|
<!-- begin: dropdown-menu -->
|
|
@@ -572,7 +572,7 @@
|
|
|
572
572
|
"slug": "dialog",
|
|
573
573
|
"title": "Dialog",
|
|
574
574
|
"summary": "A modal window for content or user input.",
|
|
575
|
-
"tokenEstimate":
|
|
575
|
+
"tokenEstimate": 576,
|
|
576
576
|
"sections": [
|
|
577
577
|
"Import",
|
|
578
578
|
"Dialog.Trigger",
|
|
@@ -580,7 +580,8 @@
|
|
|
580
580
|
"Dialog.Overlay",
|
|
581
581
|
"Dialog.Title",
|
|
582
582
|
"Dialog.Description",
|
|
583
|
-
"Dialog.Close"
|
|
583
|
+
"Dialog.Close",
|
|
584
|
+
"Dialog.Header"
|
|
584
585
|
],
|
|
585
586
|
"file": "dialog.md"
|
|
586
587
|
},
|
|
@@ -83,7 +83,9 @@
|
|
|
83
83
|
<p class="min-w-0 flex-1 truncate text-body text-bright">{n.title}</p>
|
|
84
84
|
<span class="shrink-0 text-body text-muted tabular-nums">{ago(n.createdAt)}</span>
|
|
85
85
|
</div>
|
|
86
|
-
{#if n.body}<p class="mt-0.5 text-body break-words text-muted">
|
|
86
|
+
{#if n.body}<p class="mt-0.5 text-body leading-body break-words text-muted">
|
|
87
|
+
{n.body}
|
|
88
|
+
</p>{/if}
|
|
87
89
|
</div>
|
|
88
90
|
</div>
|
|
89
91
|
{:else}
|
package/dist/os/toast.svelte
CHANGED
|
@@ -31,17 +31,20 @@
|
|
|
31
31
|
<div class="min-w-0 flex-1">
|
|
32
32
|
<div class="flex items-start gap-(--era-gap)">
|
|
33
33
|
<p class="min-w-0 flex-1 truncate text-body text-bright">{n.title}</p>
|
|
34
|
+
<!-- The dismiss family's ×: xxs tier, whose default glyph is the 12px
|
|
35
|
+
dismiss ink (the size class that sat on the <X> lost to the Button
|
|
36
|
+
variant's [&_svg] selector and never applied). -->
|
|
34
37
|
<Button
|
|
35
38
|
icon
|
|
36
|
-
size="
|
|
39
|
+
size="xxs"
|
|
37
40
|
aria-label="Dismiss"
|
|
38
41
|
class="-mt-1 -mr-1 shrink-0"
|
|
39
42
|
onclick={() => notif.dismiss(n.id)}
|
|
40
43
|
>
|
|
41
|
-
<X
|
|
44
|
+
<X />
|
|
42
45
|
</Button>
|
|
43
46
|
</div>
|
|
44
|
-
{#if n.body}<p class="mt-0.5 text-body break-words text-muted">{n.body}</p>{/if}
|
|
47
|
+
{#if n.body}<p class="mt-0.5 text-body leading-body break-words text-muted">{n.body}</p>{/if}
|
|
45
48
|
{#if n.actions.length}
|
|
46
49
|
<div class="mt-(--era-inset-sm) flex flex-wrap gap-(--era-gap)">
|
|
47
50
|
{#each n.actions as action (action.label)}
|
package/dist/styles/density.css
CHANGED
|
@@ -154,6 +154,25 @@
|
|
|
154
154
|
/* Inter-item gap */
|
|
155
155
|
--era-gap: calc(var(--era-sp) * 0.5); /* 4/5/6 */
|
|
156
156
|
|
|
157
|
+
/* PROSE LEADING — the line-height of text that WRAPS.
|
|
158
|
+
*
|
|
159
|
+
* Single-line control text has no leading question: era-text-trim collapses
|
|
160
|
+
* the line box to 1 and centres the ink, which is the whole point of it.
|
|
161
|
+
* Wrapping text is the opposite problem — the space BETWEEN lines is the
|
|
162
|
+
* only thing holding the paragraph apart, and it must never inherit a
|
|
163
|
+
* control's line-height (a `leading-none` row with a wrapping child sets its
|
|
164
|
+
* lines colliding).
|
|
165
|
+
*
|
|
166
|
+
* A ratio, not a length: leading scales with the type, not with --era-sp, so
|
|
167
|
+
* it stays a single number across every density mode — dense's 12px text
|
|
168
|
+
* gets 19.2px lines, balanced's 14px gets 22.4px, both the same paragraph
|
|
169
|
+
* colour. It replaces a 50/50 split of Tailwind's leading-relaxed (1.625)
|
|
170
|
+
* and leading-normal (1.5) that had grown between the prose components; 1.6
|
|
171
|
+
* is between them and is the value long-form UI text is usually set at.
|
|
172
|
+
*
|
|
173
|
+
* Public name: `leading-body`, the pair to `text-body`. */
|
|
174
|
+
--era-leading: 1.6;
|
|
175
|
+
|
|
157
176
|
/* Content insets — text-symmetric padding (vertical centering, reused as
|
|
158
177
|
horizontal only where the content is a single square glyph). */
|
|
159
178
|
--era-inset-xxs: max(0px, calc((var(--era-h-xxs) - var(--era-text)) / 2)); /* 3/3/4/6 */
|
package/dist/styles/index.css
CHANGED
|
@@ -298,6 +298,10 @@
|
|
|
298
298
|
@theme inline {
|
|
299
299
|
/* Density-derived body size: `text-body` replaces text-[length:var(--era-text)] */
|
|
300
300
|
--text-body: var(--era-text);
|
|
301
|
+
/* Prose leading — `leading-body` is the pair to `text-body`, and every piece
|
|
302
|
+
* of text in the library that can wrap to a second line carries it. Enforced
|
|
303
|
+
* at runtime by typography/prose-leading. */
|
|
304
|
+
--leading-body: var(--era-leading);
|
|
301
305
|
/* Radius ladder — Tailwind's own rounded-* names now walk era's concentric
|
|
302
306
|
* ladder (rd-T = rd-xs + (h-T − h-xs)/2), ride the corners toggle, and
|
|
303
307
|
* collapse to 0 on square. rounded-item is the menu-row radius
|
package/dist/styles/themes.css
CHANGED
|
@@ -50,7 +50,19 @@
|
|
|
50
50
|
--color-hover: oklch(0.25 0 0);
|
|
51
51
|
--color-fg: var(--color-11);
|
|
52
52
|
--color-bright: var(--color-12);
|
|
53
|
-
|
|
53
|
+
/* Muted is body copy, not a de-emphasis wash — the /text page sets whole
|
|
54
|
+
* paragraphs in it — so it does NOT sit flat on step 10: it leans 30% of the
|
|
55
|
+
* way to --color-fg. Step 10 alone read as "greyed out" at paragraph length
|
|
56
|
+
* (7.80:1 on the default dark page); the lean lands it at 9.11:1, still a
|
|
57
|
+
* clear step below fg for the mixed-tone case (muted prose beside a bright
|
|
58
|
+
* literal) but no longer receding. The lean is toward fg rather than a fixed
|
|
59
|
+
* lightness so it mirrors correctly in light mode (muted DARKENS toward fg)
|
|
60
|
+
* and keeps each theme's own hue family — the tinted scales (adobe, sand)
|
|
61
|
+
* interpolate between two steps of their own ramp, never toward neutral.
|
|
62
|
+
*
|
|
63
|
+
* signalnine sets its muted by hand from measured source colours and is
|
|
64
|
+
* deliberately exempt. */
|
|
65
|
+
--color-muted: color-mix(in oklch, var(--color-10) 70%, var(--color-fg));
|
|
54
66
|
/* Inline link ink. Declared once here and inherited by every theme —
|
|
55
67
|
* var(--color-bright) resolves in the element's own context, so a theme only
|
|
56
68
|
* names this if it wants links to differ from emphasis text (signalnine
|
|
@@ -121,7 +133,7 @@
|
|
|
121
133
|
--color-hover: oklch(0.8 0 0);
|
|
122
134
|
--color-fg: var(--color-11);
|
|
123
135
|
--color-bright: var(--color-12);
|
|
124
|
-
--color-muted: var(--color-10);
|
|
136
|
+
--color-muted: color-mix(in oklch, var(--color-10) 70%, var(--color-fg));
|
|
125
137
|
|
|
126
138
|
/* Accent tokens */
|
|
127
139
|
--color-primary: var(--color-fg);
|
|
@@ -160,7 +172,7 @@
|
|
|
160
172
|
--color-hover: oklch(0.8 0 0);
|
|
161
173
|
--color-fg: var(--color-11);
|
|
162
174
|
--color-bright: var(--color-12);
|
|
163
|
-
--color-muted: var(--color-10);
|
|
175
|
+
--color-muted: color-mix(in oklch, var(--color-10) 70%, var(--color-fg));
|
|
164
176
|
|
|
165
177
|
/* Accent tokens */
|
|
166
178
|
--color-primary: var(--color-fg);
|
|
@@ -204,7 +216,7 @@
|
|
|
204
216
|
--color-hover: oklch(0.252 0.024 56);
|
|
205
217
|
--color-fg: var(--color-11);
|
|
206
218
|
--color-bright: var(--color-12);
|
|
207
|
-
--color-muted: var(--color-10);
|
|
219
|
+
--color-muted: color-mix(in oklch, var(--color-10) 70%, var(--color-fg));
|
|
208
220
|
|
|
209
221
|
/* Warm sandstone primary + unexpected turquoise support. */
|
|
210
222
|
--color-primary: oklch(0.74 0.108 68);
|
|
@@ -248,7 +260,7 @@
|
|
|
248
260
|
--color-hover: oklch(0.81 0.022 73);
|
|
249
261
|
--color-fg: var(--color-11);
|
|
250
262
|
--color-bright: var(--color-12);
|
|
251
|
-
--color-muted: var(--color-10);
|
|
263
|
+
--color-muted: color-mix(in oklch, var(--color-10) 70%, var(--color-fg));
|
|
252
264
|
|
|
253
265
|
--color-primary: oklch(0.515 0.16 38);
|
|
254
266
|
--color-primary-fg: oklch(0.96 0.014 78);
|
|
@@ -283,7 +295,7 @@
|
|
|
283
295
|
--color-hover: oklch(0.81 0.022 73);
|
|
284
296
|
--color-fg: var(--color-11);
|
|
285
297
|
--color-bright: var(--color-12);
|
|
286
|
-
--color-muted: var(--color-10);
|
|
298
|
+
--color-muted: color-mix(in oklch, var(--color-10) 70%, var(--color-fg));
|
|
287
299
|
|
|
288
300
|
--color-primary: oklch(0.515 0.16 38);
|
|
289
301
|
--color-primary-fg: oklch(0.96 0.014 78);
|
|
@@ -321,7 +333,7 @@
|
|
|
321
333
|
--color-hover: color-mix(in oklch, var(--color-3) 80%, var(--color-2));
|
|
322
334
|
--color-fg: var(--color-11);
|
|
323
335
|
--color-bright: var(--color-12);
|
|
324
|
-
--color-muted: var(--color-10);
|
|
336
|
+
--color-muted: color-mix(in oklch, var(--color-10) 70%, var(--color-fg));
|
|
325
337
|
|
|
326
338
|
--color-primary: oklch(0.8 0.034 54);
|
|
327
339
|
--color-primary-fg: var(--color-1);
|
|
@@ -359,7 +371,7 @@
|
|
|
359
371
|
--color-hover: oklch(0.88 0.016 72);
|
|
360
372
|
--color-fg: var(--color-11);
|
|
361
373
|
--color-bright: var(--color-12);
|
|
362
|
-
--color-muted: var(--color-10);
|
|
374
|
+
--color-muted: color-mix(in oklch, var(--color-10) 70%, var(--color-fg));
|
|
363
375
|
|
|
364
376
|
--color-primary: oklch(0.55 0.12 58);
|
|
365
377
|
--color-primary-fg: oklch(0.97 0.008 80);
|
|
@@ -394,7 +406,7 @@
|
|
|
394
406
|
--color-hover: oklch(0.88 0.016 72);
|
|
395
407
|
--color-fg: var(--color-11);
|
|
396
408
|
--color-bright: var(--color-12);
|
|
397
|
-
--color-muted: var(--color-10);
|
|
409
|
+
--color-muted: color-mix(in oklch, var(--color-10) 70%, var(--color-fg));
|
|
398
410
|
|
|
399
411
|
--color-primary: oklch(0.55 0.12 58);
|
|
400
412
|
--color-primary-fg: oklch(0.97 0.008 80);
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<Accordion.Content
|
|
9
9
|
bind:ref
|
|
10
10
|
class={cn(
|
|
11
|
-
'overflow-hidden border-t border-divider-faded p-(--era-content-p) text-body leading-
|
|
11
|
+
'overflow-hidden border-t border-divider-faded p-(--era-content-p) text-body leading-body text-muted',
|
|
12
12
|
className
|
|
13
13
|
)}
|
|
14
14
|
{...restProps}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<AlertDialog.Content
|
|
16
16
|
bind:ref
|
|
17
17
|
class={cn(
|
|
18
|
-
'fixed top-1/2 left-1/2 z-50 flex w-full max-w-md -translate-x-1/2 -translate-y-1/2 flex-col gap-(--era-gap) rounded-(--era-rd-lg) bg-(--era-surface-bg) p-(--era-pad-md) shadow-(--era-shadow-lg) glass-blur',
|
|
18
|
+
'fixed top-1/2 left-1/2 z-50 flex w-full max-w-md -translate-x-1/2 -translate-y-1/2 flex-col gap-(--era-gap) rounded-(--era-rd-lg) border border-divider bg-(--era-surface-bg) p-(--era-pad-md) shadow-(--era-shadow-lg) glass-blur',
|
|
19
19
|
className
|
|
20
20
|
)}
|
|
21
21
|
{...restProps}
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
{...restProps}
|
|
46
46
|
>
|
|
47
47
|
<pre
|
|
48
|
-
class="overflow-x-auto px-(--era-field-px) py-(--era-inset-md) pr-[calc(var(--era-field-px)+var(--era-h-sm)+var(--era-field-px))] font-mono text-body leading-
|
|
48
|
+
class="overflow-x-auto px-(--era-field-px) py-(--era-inset-md) pr-[calc(var(--era-field-px)+var(--era-h-sm)+var(--era-field-px))] font-mono text-body leading-body text-fg"><code
|
|
49
49
|
>{#if children}{@render children()}{:else}{code}{/if}</code
|
|
50
50
|
></pre>
|
|
51
51
|
{#if copyable}
|
|
@@ -1,25 +1,47 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
2
3
|
import { Dialog } from 'bits-ui';
|
|
3
4
|
import { cn, type PartProps } from '../../utils/index.js';
|
|
4
5
|
|
|
5
6
|
let {
|
|
6
7
|
ref = $bindable(null),
|
|
7
8
|
children,
|
|
9
|
+
header,
|
|
8
10
|
class: className,
|
|
9
11
|
...restProps
|
|
10
|
-
}: PartProps<Dialog.ContentProps>
|
|
12
|
+
}: PartProps<Dialog.ContentProps> & {
|
|
13
|
+
/**
|
|
14
|
+
* A top bar in the pane's grammar — pass `Dialog.Header` (usually holding
|
|
15
|
+
* `Dialog.Title`). With it the panel goes sectioned like a Card: the bar
|
|
16
|
+
* runs edge to edge, the body keeps the padding, and the radius drops to
|
|
17
|
+
* rd-md because the panel's corners are now formed by an md bar holding xxs
|
|
18
|
+
* controls — the identical law that sizes the pane's own corners.
|
|
19
|
+
*/
|
|
20
|
+
header?: Snippet;
|
|
21
|
+
} = $props();
|
|
11
22
|
</script>
|
|
12
23
|
|
|
13
24
|
<Dialog.Portal>
|
|
14
25
|
<Dialog.Overlay class="fixed inset-0 z-50 bg-(--era-overlay-bg)" />
|
|
26
|
+
<!-- border-divider: the pane's hairline-edge law. A floating panel must be
|
|
27
|
+
separable from what's behind it, and on the flat surface shadow-lg
|
|
28
|
+
collapses to none — without the hairline the whole edge was a tone step. -->
|
|
15
29
|
<Dialog.Content
|
|
16
30
|
bind:ref
|
|
17
31
|
class={cn(
|
|
18
|
-
'fixed top-1/2 left-1/2 z-50 flex w-full max-w-md -translate-x-1/2 -translate-y-1/2 flex-col
|
|
32
|
+
'fixed top-1/2 left-1/2 z-50 flex w-full max-w-md -translate-x-1/2 -translate-y-1/2 flex-col border border-divider bg-(--era-surface-bg) shadow-(--era-shadow-lg) glass-blur',
|
|
33
|
+
header ? 'rounded-(--era-rd-md)' : 'gap-(--era-gap) rounded-(--era-rd-lg) p-(--era-pad-md)',
|
|
19
34
|
className
|
|
20
35
|
)}
|
|
21
36
|
{...restProps}
|
|
22
37
|
>
|
|
23
|
-
{
|
|
38
|
+
{#if header}
|
|
39
|
+
{@render header()}
|
|
40
|
+
<div class="flex min-h-0 flex-col gap-(--era-gap) p-(--era-pad-md)">
|
|
41
|
+
{@render children?.()}
|
|
42
|
+
</div>
|
|
43
|
+
{:else}
|
|
44
|
+
{@render children?.()}
|
|
45
|
+
{/if}
|
|
24
46
|
</Dialog.Content>
|
|
25
47
|
</Dialog.Portal>
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
1
2
|
import { Dialog } from 'bits-ui';
|
|
2
3
|
import { type PartProps } from '../../utils/index.js';
|
|
3
|
-
|
|
4
|
+
type $$ComponentProps = PartProps<Dialog.ContentProps> & {
|
|
5
|
+
/**
|
|
6
|
+
* A top bar in the pane's grammar — pass `Dialog.Header` (usually holding
|
|
7
|
+
* `Dialog.Title`). With it the panel goes sectioned like a Card: the bar
|
|
8
|
+
* runs edge to edge, the body keeps the padding, and the radius drops to
|
|
9
|
+
* rd-md because the panel's corners are now formed by an md bar holding xxs
|
|
10
|
+
* controls — the identical law that sizes the pane's own corners.
|
|
11
|
+
*/
|
|
12
|
+
header?: Snippet;
|
|
13
|
+
};
|
|
14
|
+
declare const DialogContent: import("svelte").Component<$$ComponentProps, {}, "ref">;
|
|
4
15
|
type DialogContent = ReturnType<typeof DialogContent>;
|
|
5
16
|
export default DialogContent;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { Dialog } from 'bits-ui';
|
|
4
|
+
import X from '@lucide/svelte/icons/x';
|
|
5
|
+
import { Bar } from '../bar';
|
|
6
|
+
import { Button } from '../button';
|
|
7
|
+
import { cn } from '../../utils/index.js';
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
dismissable = true,
|
|
11
|
+
children,
|
|
12
|
+
class: className
|
|
13
|
+
}: {
|
|
14
|
+
/** Render the trailing × (a `Dialog.Close`). Off for flows that must resolve. */
|
|
15
|
+
dismissable?: boolean;
|
|
16
|
+
children?: Snippet;
|
|
17
|
+
class?: string;
|
|
18
|
+
} = $props();
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<!-- The pane handle's chrome, verbatim, for an overlay's top bar — one grammar
|
|
22
|
+
for every floating panel's header so a dialog and a pane read as the same
|
|
23
|
+
kind of surface:
|
|
24
|
+
|
|
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
|
+
· the leading side at --era-inset-md: a title has no corner to nest, so
|
|
29
|
+
it takes the text inset, the same asymmetry the pane and the
|
|
30
|
+
Conversations row document
|
|
31
|
+
· the × is the dismiss family's: an xxs Button whose tier default IS the
|
|
32
|
+
12px ink, destructive like Pane.Close
|
|
33
|
+
|
|
34
|
+
Rendered flush by Dialog.Content / Sheet.Content when passed as their
|
|
35
|
+
`header` snippet, so the bar spans the panel edge to edge and the panel's
|
|
36
|
+
radius follows this corner region (rd-md — the same law that sizes the
|
|
37
|
+
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
|
+
>
|
|
46
|
+
{@render children?.()}
|
|
47
|
+
{#if dismissable}
|
|
48
|
+
<Dialog.Close>
|
|
49
|
+
{#snippet child({ props })}
|
|
50
|
+
<Button icon size="xxs" tone="destructive" aria-label="Close" class="ml-auto" {...props}>
|
|
51
|
+
<X />
|
|
52
|
+
</Button>
|
|
53
|
+
{/snippet}
|
|
54
|
+
</Dialog.Close>
|
|
55
|
+
{/if}
|
|
56
|
+
</Bar>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
/** Render the trailing × (a `Dialog.Close`). Off for flows that must resolve. */
|
|
4
|
+
dismissable?: boolean;
|
|
5
|
+
children?: Snippet;
|
|
6
|
+
class?: string;
|
|
7
|
+
};
|
|
8
|
+
declare const DialogHeader: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
|
+
type DialogHeader = ReturnType<typeof DialogHeader>;
|
|
10
|
+
export default DialogHeader;
|
|
@@ -7,3 +7,4 @@ export { default as Overlay } from './dialog-overlay.svelte';
|
|
|
7
7
|
export { default as Title } from './dialog-title.svelte';
|
|
8
8
|
export { default as Description } from './dialog-description.svelte';
|
|
9
9
|
export { default as Close } from './dialog-close.svelte';
|
|
10
|
+
export { default as Header } from './dialog-header.svelte';
|
package/dist/ui/dialog/index.js
CHANGED
|
@@ -7,3 +7,4 @@ export { default as Overlay } from './dialog-overlay.svelte';
|
|
|
7
7
|
export { default as Title } from './dialog-title.svelte';
|
|
8
8
|
export { default as Description } from './dialog-description.svelte';
|
|
9
9
|
export { default as Close } from './dialog-close.svelte';
|
|
10
|
+
export { default as Header } from './dialog-header.svelte';
|
package/dist/ui/sheet/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Root, Portal, Trigger, Title, Description, Close } from '../dialog/index.js';
|
|
1
|
+
export { Root, Portal, Trigger, Title, Description, Close, Header } from '../dialog/index.js';
|
|
2
2
|
export { default as Content, sheetVariants } from './sheet-content.svelte';
|
package/dist/ui/sheet/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Sheet is a Dialog anchored to a screen edge. Root/Trigger/Title/Description/
|
|
2
2
|
// Close are the Dialog wrappers verbatim (same behavior); only Content differs
|
|
3
3
|
// (edge-positioned, with a `side` prop).
|
|
4
|
-
export { Root, Portal, Trigger, Title, Description, Close } from '../dialog/index.js';
|
|
4
|
+
export { Root, Portal, Trigger, Title, Description, Close, Header } from '../dialog/index.js';
|
|
5
5
|
export { default as Content, sheetVariants } from './sheet-content.svelte';
|
|
@@ -4,38 +4,73 @@
|
|
|
4
4
|
// A Sheet is a Dialog pinned to a screen edge — the idiomatic mobile drawer
|
|
5
5
|
// (bottom for controls, left/right for navigation). Positioning + which
|
|
6
6
|
// corners round follow the `side`; everything else is the dialog surface.
|
|
7
|
+
// border-divider on every side: the pane's hairline-edge law — on flat,
|
|
8
|
+
// shadow-lg collapses to none and the sheet's edge was a bare tone step.
|
|
7
9
|
export const sheetVariants = tv({
|
|
8
|
-
base: 'fixed z-50 flex flex-col
|
|
10
|
+
base: 'fixed z-50 flex flex-col border border-divider bg-(--era-surface-bg) shadow-(--era-shadow-lg) glass-blur',
|
|
9
11
|
variants: {
|
|
10
12
|
side: {
|
|
11
|
-
top: 'inset-x-0 top-0 max-h-[85dvh]
|
|
12
|
-
bottom: 'inset-x-0 bottom-0 max-h-[85dvh]
|
|
13
|
-
left: 'inset-y-0 left-0 w-[min(20rem,85vw)]
|
|
14
|
-
right: 'inset-y-0 right-0 w-[min(20rem,85vw)]
|
|
15
|
-
}
|
|
13
|
+
top: 'inset-x-0 top-0 max-h-[85dvh]',
|
|
14
|
+
bottom: 'inset-x-0 bottom-0 max-h-[85dvh]',
|
|
15
|
+
left: 'inset-y-0 left-0 w-[min(20rem,85vw)]',
|
|
16
|
+
right: 'inset-y-0 right-0 w-[min(20rem,85vw)]'
|
|
17
|
+
},
|
|
18
|
+
/**
|
|
19
|
+
* With a header the sheet is sectioned (the bar flush, the BODY scrolls
|
|
20
|
+
* — scrolling the root would carry the bar away with the content) and
|
|
21
|
+
* its detached corners drop to rd-md: they are formed by an md bar
|
|
22
|
+
* holding xxs controls, the pane's own corner law. Without one, the
|
|
23
|
+
* padded rd-lg surface is unchanged.
|
|
24
|
+
*/
|
|
25
|
+
header: { true: '', false: 'gap-(--era-gap) overflow-y-auto p-(--era-pad-md)' }
|
|
16
26
|
},
|
|
17
|
-
|
|
27
|
+
compoundVariants: [
|
|
28
|
+
{ side: 'top', header: false, class: 'rounded-b-(--era-rd-lg)' },
|
|
29
|
+
{ side: 'bottom', header: false, class: 'rounded-t-(--era-rd-lg)' },
|
|
30
|
+
{ side: 'left', header: false, class: 'rounded-r-(--era-rd-lg)' },
|
|
31
|
+
{ side: 'right', header: false, class: 'rounded-l-(--era-rd-lg)' },
|
|
32
|
+
{ side: 'top', header: true, class: 'rounded-b-(--era-rd-md)' },
|
|
33
|
+
{ side: 'bottom', header: true, class: 'rounded-t-(--era-rd-md)' },
|
|
34
|
+
{ side: 'left', header: true, class: 'rounded-r-(--era-rd-md)' },
|
|
35
|
+
{ side: 'right', header: true, class: 'rounded-l-(--era-rd-md)' }
|
|
36
|
+
],
|
|
37
|
+
defaultVariants: { side: 'bottom', header: false }
|
|
18
38
|
});
|
|
19
39
|
</script>
|
|
20
40
|
|
|
21
41
|
<script lang="ts">
|
|
42
|
+
import type { Snippet } from 'svelte';
|
|
22
43
|
import { Dialog } from 'bits-ui';
|
|
23
44
|
|
|
24
45
|
let {
|
|
25
46
|
ref = $bindable(null),
|
|
26
47
|
side = 'bottom',
|
|
27
48
|
children,
|
|
49
|
+
header,
|
|
28
50
|
class: className,
|
|
29
51
|
...restProps
|
|
30
52
|
}: PartProps<Dialog.ContentProps> & {
|
|
31
53
|
/** Screen edge the sheet is anchored to. */
|
|
32
54
|
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
55
|
+
/** A top bar in the pane's grammar — pass `Sheet.Header` holding `Sheet.Title`. */
|
|
56
|
+
header?: Snippet;
|
|
33
57
|
} = $props();
|
|
34
58
|
</script>
|
|
35
59
|
|
|
36
60
|
<Dialog.Portal>
|
|
37
61
|
<Dialog.Overlay class="fixed inset-0 z-50 bg-(--era-overlay-bg)" />
|
|
38
|
-
<Dialog.Content
|
|
39
|
-
|
|
62
|
+
<Dialog.Content
|
|
63
|
+
bind:ref
|
|
64
|
+
class={cn(sheetVariants({ side, header: header != null }), className)}
|
|
65
|
+
{...restProps}
|
|
66
|
+
>
|
|
67
|
+
{#if header}
|
|
68
|
+
{@render header()}
|
|
69
|
+
<div class="flex min-h-0 flex-1 flex-col gap-(--era-gap) overflow-y-auto p-(--era-pad-md)">
|
|
70
|
+
{@render children?.()}
|
|
71
|
+
</div>
|
|
72
|
+
{:else}
|
|
73
|
+
{@render children?.()}
|
|
74
|
+
{/if}
|
|
40
75
|
</Dialog.Content>
|
|
41
76
|
</Dialog.Portal>
|
|
@@ -1,30 +1,66 @@
|
|
|
1
1
|
import { type PartProps } from '../../utils/index.js';
|
|
2
2
|
export declare const sheetVariants: import("tailwind-variants").TVReturnType<{
|
|
3
3
|
side: {
|
|
4
|
-
top: "inset-x-0 top-0 max-h-[85dvh]
|
|
5
|
-
bottom: "inset-x-0 bottom-0 max-h-[85dvh]
|
|
6
|
-
left: "inset-y-0 left-0 w-[min(20rem,85vw)]
|
|
7
|
-
right: "inset-y-0 right-0 w-[min(20rem,85vw)]
|
|
4
|
+
top: "inset-x-0 top-0 max-h-[85dvh]";
|
|
5
|
+
bottom: "inset-x-0 bottom-0 max-h-[85dvh]";
|
|
6
|
+
left: "inset-y-0 left-0 w-[min(20rem,85vw)]";
|
|
7
|
+
right: "inset-y-0 right-0 w-[min(20rem,85vw)]";
|
|
8
8
|
};
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* With a header the sheet is sectioned (the bar flush, the BODY scrolls
|
|
11
|
+
* — scrolling the root would carry the bar away with the content) and
|
|
12
|
+
* its detached corners drop to rd-md: they are formed by an md bar
|
|
13
|
+
* holding xxs controls, the pane's own corner law. Without one, the
|
|
14
|
+
* padded rd-lg surface is unchanged.
|
|
15
|
+
*/
|
|
16
|
+
header: {
|
|
17
|
+
true: "";
|
|
18
|
+
false: "gap-(--era-gap) overflow-y-auto p-(--era-pad-md)";
|
|
19
|
+
};
|
|
20
|
+
}, undefined, "fixed z-50 flex flex-col border border-divider bg-(--era-surface-bg) shadow-(--era-shadow-lg) glass-blur", {
|
|
10
21
|
side: {
|
|
11
|
-
top: "inset-x-0 top-0 max-h-[85dvh]
|
|
12
|
-
bottom: "inset-x-0 bottom-0 max-h-[85dvh]
|
|
13
|
-
left: "inset-y-0 left-0 w-[min(20rem,85vw)]
|
|
14
|
-
right: "inset-y-0 right-0 w-[min(20rem,85vw)]
|
|
22
|
+
top: "inset-x-0 top-0 max-h-[85dvh]";
|
|
23
|
+
bottom: "inset-x-0 bottom-0 max-h-[85dvh]";
|
|
24
|
+
left: "inset-y-0 left-0 w-[min(20rem,85vw)]";
|
|
25
|
+
right: "inset-y-0 right-0 w-[min(20rem,85vw)]";
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* With a header the sheet is sectioned (the bar flush, the BODY scrolls
|
|
29
|
+
* — scrolling the root would carry the bar away with the content) and
|
|
30
|
+
* its detached corners drop to rd-md: they are formed by an md bar
|
|
31
|
+
* holding xxs controls, the pane's own corner law. Without one, the
|
|
32
|
+
* padded rd-lg surface is unchanged.
|
|
33
|
+
*/
|
|
34
|
+
header: {
|
|
35
|
+
true: "";
|
|
36
|
+
false: "gap-(--era-gap) overflow-y-auto p-(--era-pad-md)";
|
|
15
37
|
};
|
|
16
38
|
}, undefined, import("tailwind-variants").TVReturnTypeLike<{
|
|
17
39
|
side: {
|
|
18
|
-
top: "inset-x-0 top-0 max-h-[85dvh]
|
|
19
|
-
bottom: "inset-x-0 bottom-0 max-h-[85dvh]
|
|
20
|
-
left: "inset-y-0 left-0 w-[min(20rem,85vw)]
|
|
21
|
-
right: "inset-y-0 right-0 w-[min(20rem,85vw)]
|
|
40
|
+
top: "inset-x-0 top-0 max-h-[85dvh]";
|
|
41
|
+
bottom: "inset-x-0 bottom-0 max-h-[85dvh]";
|
|
42
|
+
left: "inset-y-0 left-0 w-[min(20rem,85vw)]";
|
|
43
|
+
right: "inset-y-0 right-0 w-[min(20rem,85vw)]";
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* With a header the sheet is sectioned (the bar flush, the BODY scrolls
|
|
47
|
+
* — scrolling the root would carry the bar away with the content) and
|
|
48
|
+
* its detached corners drop to rd-md: they are formed by an md bar
|
|
49
|
+
* holding xxs controls, the pane's own corner law. Without one, the
|
|
50
|
+
* padded rd-lg surface is unchanged.
|
|
51
|
+
*/
|
|
52
|
+
header: {
|
|
53
|
+
true: "";
|
|
54
|
+
false: "gap-(--era-gap) overflow-y-auto p-(--era-pad-md)";
|
|
22
55
|
};
|
|
23
56
|
}, undefined>>;
|
|
57
|
+
import type { Snippet } from 'svelte';
|
|
24
58
|
import { Dialog } from 'bits-ui';
|
|
25
59
|
type $$ComponentProps = PartProps<Dialog.ContentProps> & {
|
|
26
60
|
/** Screen edge the sheet is anchored to. */
|
|
27
61
|
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
62
|
+
/** A top bar in the pane's grammar — pass `Sheet.Header` holding `Sheet.Title`. */
|
|
63
|
+
header?: Snippet;
|
|
28
64
|
};
|
|
29
65
|
declare const SheetContent: import("svelte").Component<$$ComponentProps, {}, "ref">;
|
|
30
66
|
type SheetContent = ReturnType<typeof SheetContent>;
|