@signal9/era-ui 30.8.0 → 32.0.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/CHANGELOG.md +28 -0
- package/dist/ai/artifact/artifact.svelte +1 -1
- package/dist/ai/conversations/conversations-item.svelte +1 -1
- package/dist/ai/plan/plan-header.svelte +1 -1
- package/dist/ai/prompt-input/prompt-input-attachments.svelte +2 -6
- package/dist/ai/swarm/swarm-node.svelte +1 -1
- package/dist/ai/todo/todo-header.svelte +1 -1
- package/dist/ai/todo/todo-item.svelte +1 -1
- package/dist/ai/tool/tool-chip.svelte +1 -1
- package/dist/ai/web-preview/web-preview.svelte +2 -2
- package/dist/ai/workflow/node.svelte +1 -1
- package/dist/dev/audit/audits/wall-is-isotropic.js +1 -1
- package/dist/docs/css-utilities.js +9 -5
- package/dist/era-ui.css +1 -1
- package/dist/generated-docs/badge.md +1 -1
- package/dist/generated-docs/bar.md +22 -4
- package/dist/generated-docs/button.md +38 -4
- package/dist/generated-docs/card.md +35 -5
- package/dist/generated-docs/chip.md +16 -0
- package/dist/generated-docs/llms-full.txt +370 -70
- package/dist/generated-docs/llms.txt +8 -4
- package/dist/generated-docs/manifest.json +85 -28
- package/dist/generated-docs/meter.md +79 -1
- package/dist/generated-docs/nav.md +8 -1
- package/dist/generated-docs/separator.md +18 -0
- package/dist/generated-docs/utilities.json +68 -15
- package/dist/generated-docs/utilities.md +145 -50
- package/dist/os/notification-center.svelte +1 -1
- package/dist/os/taskbar.svelte +1 -1
- package/dist/os/toast.svelte +1 -1
- package/dist/styles/density.css +15 -25
- package/dist/styles/index.css +74 -48
- package/dist/styles/motion.css +1 -1
- package/dist/styles/prose.css +1 -1
- package/dist/styles/surfaces/bevel.css +16 -19
- package/dist/styles/surfaces/contract.css +50 -0
- package/dist/styles/surfaces/flat.css +27 -0
- package/dist/styles/surfaces/glass.css +11 -8
- package/dist/ui/accordion/accordion-trigger.svelte +1 -1
- package/dist/ui/alert-dialog/alert-dialog-content.svelte +1 -1
- package/dist/ui/badge/badge.svelte +8 -2
- package/dist/ui/badge/badge.svelte.d.ts +1 -1
- package/dist/ui/bar/bar.svelte +95 -26
- package/dist/ui/bar/bar.svelte.d.ts +71 -31
- package/dist/ui/button/button.svelte +6 -0
- package/dist/ui/button/button.svelte.d.ts +2 -0
- package/dist/ui/button/variants.d.ts +3 -3
- package/dist/ui/button/variants.js +6 -11
- package/dist/ui/calendar/calendar-day.svelte +1 -1
- package/dist/ui/card/card.svelte +23 -10
- package/dist/ui/card/card.svelte.d.ts +19 -7
- package/dist/ui/chip/chip.svelte +5 -2
- package/dist/ui/chip/chip.svelte.d.ts +6 -6
- package/dist/ui/collapsible/collapsible-trigger.svelte +1 -1
- package/dist/ui/combobox/combobox-content.svelte +1 -1
- package/dist/ui/combobox/combobox-trigger.svelte +1 -1
- package/dist/ui/command/command-item.svelte +1 -1
- package/dist/ui/command/command-link-item.svelte +1 -1
- package/dist/ui/command/command-root.svelte +5 -7
- package/dist/ui/command-bar/command-bar.svelte +3 -3
- package/dist/ui/context-menu/context-menu-content.svelte +1 -4
- package/dist/ui/context-menu/context-menu-sub-content.svelte +1 -4
- package/dist/ui/date-field/date-field-segment.svelte +1 -1
- package/dist/ui/date-picker/date-picker-content.svelte +1 -1
- package/dist/ui/date-picker/date-picker-day.svelte +1 -1
- package/dist/ui/date-picker/date-picker-segment.svelte +1 -1
- package/dist/ui/date-picker/date-picker-trigger.svelte +1 -1
- package/dist/ui/date-range-field/date-range-field-segment.svelte +1 -1
- package/dist/ui/date-range-picker/date-range-picker-content.svelte +1 -1
- package/dist/ui/date-range-picker/date-range-picker-day.svelte +1 -1
- package/dist/ui/date-range-picker/date-range-picker-segment.svelte +1 -1
- package/dist/ui/date-range-picker/date-range-picker-trigger.svelte +1 -1
- package/dist/ui/dialog/dialog-content.svelte +20 -2
- package/dist/ui/dropdown-menu/dropdown-menu-content.svelte +1 -1
- package/dist/ui/dropdown-menu/dropdown-menu-sub-content.svelte +1 -4
- package/dist/ui/dropdown-menu/dropdown-menu-trigger.svelte +1 -1
- package/dist/ui/file-upload/file-upload.svelte +1 -1
- package/dist/ui/input/variants.d.ts +6 -6
- package/dist/ui/input/variants.js +2 -2
- package/dist/ui/kv/kv.svelte +1 -1
- package/dist/ui/link-preview/link-preview-content.svelte +1 -1
- package/dist/ui/menubar/menubar-content.svelte +1 -1
- package/dist/ui/menubar/menubar-root.svelte +1 -1
- package/dist/ui/menubar/menubar-sub-content.svelte +1 -4
- package/dist/ui/menubar/menubar-trigger.svelte +1 -1
- package/dist/ui/meter/meter.svelte +1 -2
- package/dist/ui/nav/nav-bar.svelte +9 -4
- package/dist/ui/nav/nav-bar.svelte.d.ts +2 -1
- package/dist/ui/nav/nav-item.svelte +1 -0
- package/dist/ui/pane/pane-root.svelte +3 -12
- package/dist/ui/pane/pane-tab.svelte +1 -1
- package/dist/ui/popover/popover-content.svelte +1 -1
- package/dist/ui/provider/surfaces.d.ts +1 -1
- package/dist/ui/provider/surfaces.js +1 -1
- package/dist/ui/select/select-content.svelte +1 -1
- package/dist/ui/select/select-trigger.svelte +1 -1
- package/dist/ui/sheet/sheet-content.svelte +1 -1
- package/dist/ui/sheet/sheet-content.svelte.d.ts +1 -1
- package/dist/ui/slider/slider-thumb.svelte +1 -1
- package/dist/ui/step/step-summary.svelte +1 -1
- package/dist/ui/switch/switch.svelte +3 -3
- package/dist/ui/time-field/time-field-segment.svelte +1 -1
- package/dist/ui/time-range-field/time-range-field-segment.svelte +1 -1
- package/dist/ui/timeline/timeline-step.svelte +1 -1
- package/dist/ui/toggle-group/toggle-group-item.svelte +2 -2
- package/dist/ui/toggle-group/toggle-group-item.svelte.d.ts +6 -6
- package/dist/ui/toggle-group/toggle-group-root.svelte +1 -2
- package/dist/ui/toggle-group/toggle-group-root.svelte.d.ts +3 -3
- package/dist/ui/tooltip/tooltip-content.svelte +1 -1
- package/dist/ui/tree/tree-item.svelte +1 -1
- package/dist/ui/video-player/video-player.svelte +2 -2
- package/dist/utils/tw-merge-config.d.ts +6 -1
- package/dist/utils/tw-merge-config.js +6 -2
- package/package.json +5 -3
- package/skill/SKILL.md +26 -21
- package/dist/styles/surfaces/base.css +0 -257
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
* shading reads as lighting, not tilt. Do not remove it.
|
|
24
24
|
*/
|
|
25
25
|
[data-surface='bevel'] {
|
|
26
|
+
--era-border-color: transparent;
|
|
27
|
+
--era-divider-color: var(--color-border);
|
|
28
|
+
--era-surface-bg: var(--color-2);
|
|
29
|
+
--era-field-bg: var(--color-hover);
|
|
26
30
|
/* Horizontal cast ratio — the light-direction knob (see header). Below 1
|
|
27
31
|
* rotates the light toward the top; the vertical cast stays a full pixel. */
|
|
28
32
|
--era-bevel-side: 0.6;
|
|
@@ -46,7 +50,7 @@
|
|
|
46
50
|
),
|
|
47
51
|
var(--era-bevel-rim);
|
|
48
52
|
/* ELEVATION IS A CHISEL, NOT A TONE — bevel's whole premise, and the reason
|
|
49
|
-
* it opts out of the
|
|
53
|
+
* it opts out of the flat implementation's raised-tier tone step. Flat mixes the elevated
|
|
50
54
|
* fill 6% toward --color-bright so flat can separate a floating panel
|
|
51
55
|
* without drawing an edge; bevel already separates one with the slab below,
|
|
52
56
|
* and a panel that was ALSO a lighter grey would read as two mechanisms
|
|
@@ -93,19 +97,28 @@
|
|
|
93
97
|
),
|
|
94
98
|
var(--era-bevel-rim);
|
|
95
99
|
--era-shadow-pressed: var(--era-shadow-well);
|
|
100
|
+
--era-highlight: light-dark(
|
|
101
|
+
color-mix(in oklch, var(--color-bright) 9%, transparent),
|
|
102
|
+
color-mix(in oklch, var(--color-bright) 8%, transparent)
|
|
103
|
+
);
|
|
104
|
+
--era-fill: var(--era-highlight);
|
|
96
105
|
/* The BOX never moves on press, so releasing doesn't pop the button up.
|
|
97
106
|
* Instead the CONTENT sinks straight DOWN 1px while
|
|
98
107
|
* the frame holds still, so the icon/label depresses like a Win95 keycap
|
|
99
108
|
* travelling into its socket. An earlier version also nudged it 1px RIGHT (into
|
|
100
109
|
* the sunken bottom-right corner) but the sideways drift read as the glyph
|
|
101
110
|
* sliding off rather than pressing in — vertical-only is the truer key press.
|
|
102
|
-
*
|
|
111
|
+
* Compact controls select the half-step travel from the same contract. */
|
|
103
112
|
--era-press-sink-x: 0px;
|
|
104
113
|
--era-press-sink-y: 1px;
|
|
114
|
+
--era-press-sink-compact-x: 0px;
|
|
115
|
+
--era-press-sink-compact-y: 0.5px;
|
|
105
116
|
/* Floating panels wear a 2-layer chisel frame; row highlights inset past
|
|
106
117
|
* it with a concentric radius (square under data-corners="square", as
|
|
107
118
|
* the era had it — Win95 drew its selection bar inside the border). */
|
|
108
119
|
--era-panel-inset: 2px;
|
|
120
|
+
--era-overlay-bg: color-mix(in oklch, var(--color-1) 60%, transparent);
|
|
121
|
+
--era-backdrop-filter: none;
|
|
109
122
|
/* Text selection is the period highlight bar: hard, fully opaque, in the
|
|
110
123
|
* ACCENT — Win95 painted selections with the system highlight color, not
|
|
111
124
|
* inverse video. Under the neutral theme primary is the fg step, so it
|
|
@@ -113,21 +126,5 @@
|
|
|
113
126
|
* colored selection. Crisp by definition: no glow, no shadow. */
|
|
114
127
|
--era-selection-bg: var(--color-primary);
|
|
115
128
|
--era-selection-fg: var(--color-primary-fg);
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
/*
|
|
119
|
-
* SMALL-BUTTON SINK — the depression, scaled to the keycap.
|
|
120
|
-
*
|
|
121
|
-
* The 1px content sink is tuned for a default (h-control) button, where it is ~4% of
|
|
122
|
-
* the box. On the h-icon tier — size="xs" and size="icon", the 14px squares a
|
|
123
|
-
* pane's close X is built from — that same 1px is ~7% of the box and the glyph,
|
|
124
|
-
* which fills the button, visibly drops too far on press. Half the sink
|
|
125
|
-
* (proportional: 14/24 ≈ 0.58, rounded to 0.5) puts the small keycap's travel
|
|
126
|
-
* back in step with the large one. Overriding the token (not the transform)
|
|
127
|
-
* means the existing `[&:active>*]` rule keeps applying it; the content wrapper
|
|
128
|
-
* inherits the value.
|
|
129
|
-
*/
|
|
130
|
-
[data-surface='bevel'] button[data-size='xs'],
|
|
131
|
-
[data-surface='bevel'] button[data-size='icon'] {
|
|
132
|
-
--era-press-sink-y: 0.5px;
|
|
129
|
+
--era-selection-shadow: none;
|
|
133
130
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Era UI — material contract
|
|
3
|
+
*
|
|
4
|
+
* Components choose a MATERIAL ROLE; surface implementations provide values.
|
|
5
|
+
* This file contains only relationships shared by every implementation and the
|
|
6
|
+
* global consumers of those values. It deliberately contains no flat, glass,
|
|
7
|
+
* or bevel palette and no component selector.
|
|
8
|
+
*
|
|
9
|
+
* Required primitives (enforced by check:surfaces):
|
|
10
|
+
* paint --era-surface-bg, --era-surface-bg-elevated, --era-field-bg
|
|
11
|
+
* relief --era-shadow, --era-shadow-lg
|
|
12
|
+
* interaction --era-highlight, --era-fill, full/compact press travel
|
|
13
|
+
* frame --era-divider-color, --era-panel-inset, --era-backdrop-filter
|
|
14
|
+
* environment --era-border-color, --era-overlay-bg
|
|
15
|
+
* selection --era-selection-bg/fg/shadow
|
|
16
|
+
*
|
|
17
|
+
* Derived values remain live var() expressions so a nested surface re-resolves
|
|
18
|
+
* them from its own primitives. A surface overrides a derived value only when
|
|
19
|
+
* its material genuinely needs a different treatment.
|
|
20
|
+
*/
|
|
21
|
+
:root,
|
|
22
|
+
[data-surface] {
|
|
23
|
+
--era-divider-faded: color-mix(in oklch, var(--era-divider-color) 40%, transparent);
|
|
24
|
+
--era-field-highlight: color-mix(in oklch, var(--era-field-bg) 96%, var(--color-bright));
|
|
25
|
+
--era-shadow-well: var(--era-shadow);
|
|
26
|
+
--era-shadow-pressed: var(--era-shadow);
|
|
27
|
+
--era-highlight-shadow: var(--era-shadow);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Radius re-derives per element because density/corners may change without a
|
|
31
|
+
* new surface boundary. No surface-specific derived shadow belongs here. */
|
|
32
|
+
* {
|
|
33
|
+
--era-item-rd: max(0px, calc(var(--era-rd-control) - var(--era-panel-inset)));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
::selection {
|
|
37
|
+
background-color: var(--era-selection-bg);
|
|
38
|
+
color: var(--era-selection-fg);
|
|
39
|
+
text-shadow: var(--era-selection-shadow);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Translucent materials become opaque without changing component markup. */
|
|
43
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
44
|
+
:root,
|
|
45
|
+
[data-surface] {
|
|
46
|
+
--era-highlight: var(--color-hover);
|
|
47
|
+
--era-fill: var(--color-hover);
|
|
48
|
+
--era-backdrop-filter: none;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* Flat — solid tone steps with no relief chrome. */
|
|
2
|
+
:root,
|
|
3
|
+
[data-surface='flat'] {
|
|
4
|
+
--era-border-color: transparent;
|
|
5
|
+
--era-divider-color: var(--color-border);
|
|
6
|
+
--era-surface-bg: var(--color-2);
|
|
7
|
+
/* A symmetric tone step separates floating content without drawing an edge. */
|
|
8
|
+
--era-surface-bg-elevated: color-mix(in oklch, var(--era-surface-bg) 94%, var(--color-bright));
|
|
9
|
+
--era-field-bg: var(--color-hover);
|
|
10
|
+
--era-shadow: none;
|
|
11
|
+
--era-shadow-lg: none;
|
|
12
|
+
--era-highlight: light-dark(
|
|
13
|
+
color-mix(in oklch, var(--color-bright) 9%, transparent),
|
|
14
|
+
color-mix(in oklch, var(--color-bright) 8%, transparent)
|
|
15
|
+
);
|
|
16
|
+
--era-fill: var(--era-highlight);
|
|
17
|
+
--era-press-sink-x: 0px;
|
|
18
|
+
--era-press-sink-y: 0px;
|
|
19
|
+
--era-press-sink-compact-x: 0px;
|
|
20
|
+
--era-press-sink-compact-y: 0px;
|
|
21
|
+
--era-panel-inset: 0px;
|
|
22
|
+
--era-overlay-bg: color-mix(in oklch, var(--color-1) 60%, transparent);
|
|
23
|
+
--era-backdrop-filter: none;
|
|
24
|
+
--era-selection-bg: var(--color-bright);
|
|
25
|
+
--era-selection-fg: var(--color-1);
|
|
26
|
+
--era-selection-shadow: none;
|
|
27
|
+
}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* treatment (macOS-style) so row highlights never touch the rim or arcs.
|
|
17
17
|
*/
|
|
18
18
|
[data-surface='glass'] {
|
|
19
|
+
--era-border-color: transparent;
|
|
19
20
|
--era-divider-color: light-dark(
|
|
20
21
|
color-mix(in oklch, var(--color-bright) 12%, transparent),
|
|
21
22
|
color-mix(in oklch, var(--color-bright) 8%, transparent)
|
|
@@ -33,13 +34,13 @@
|
|
|
33
34
|
color-mix(in oklch, var(--color-3) 85%, transparent)
|
|
34
35
|
);
|
|
35
36
|
|
|
36
|
-
/* The same tone the
|
|
37
|
+
/* The same tone the flat implementation defines, held at 72% so the frost still reads
|
|
37
38
|
* through it — the material is the point. Restated rather than inherited
|
|
38
39
|
* because a surface cannot reference the token it is overriding.
|
|
39
40
|
* Light mode is why a field needs its own value here at all: at the panel's
|
|
40
41
|
* own opacity it measured 1.00:1 against its backdrop, i.e. exactly nothing.
|
|
41
42
|
*
|
|
42
|
-
* --era-field-highlight is NOT restated: the
|
|
43
|
+
* --era-field-highlight is NOT restated: the contract derives it against
|
|
43
44
|
* --era-field-bg, so it picks this value up and stays translucent. */
|
|
44
45
|
--era-field-bg: color-mix(in oklch, var(--color-hover) 72%, transparent);
|
|
45
46
|
|
|
@@ -89,6 +90,10 @@
|
|
|
89
90
|
* surface invented). Its highlight was always a wash, so pills inside lit
|
|
90
91
|
* containers were never at risk here. */
|
|
91
92
|
--era-fill: var(--color-hover);
|
|
93
|
+
--era-press-sink-x: 0px;
|
|
94
|
+
--era-press-sink-y: 0px;
|
|
95
|
+
--era-press-sink-compact-x: 0px;
|
|
96
|
+
--era-press-sink-compact-y: 0px;
|
|
92
97
|
--era-highlight-shadow:
|
|
93
98
|
inset 1.5px 1.5px 0 -1px
|
|
94
99
|
light-dark(
|
|
@@ -127,10 +132,9 @@
|
|
|
127
132
|
);
|
|
128
133
|
|
|
129
134
|
--era-panel-inset: 2px;
|
|
130
|
-
--era-
|
|
131
|
-
/* Blur alone reads muddy/gray; saturation restores the backdrop's color
|
|
132
|
-
|
|
133
|
-
--era-saturate: 180%;
|
|
135
|
+
--era-overlay-bg: color-mix(in oklch, var(--color-1) 60%, transparent);
|
|
136
|
+
/* Blur alone reads muddy/gray; saturation restores the backdrop's color. */
|
|
137
|
+
--era-backdrop-filter: blur(20px) saturate(180%);
|
|
134
138
|
}
|
|
135
139
|
|
|
136
140
|
/* Accessibility — honor reduced-transparency: solid fills, no filter,
|
|
@@ -139,8 +143,7 @@
|
|
|
139
143
|
[data-surface='glass'] {
|
|
140
144
|
--era-surface-bg: var(--color-2);
|
|
141
145
|
--era-surface-bg-elevated: var(--color-3);
|
|
142
|
-
--era-
|
|
143
|
-
--era-saturate: 100%;
|
|
146
|
+
--era-backdrop-filter: none;
|
|
144
147
|
/* The field goes solid with everything else — it was left translucent
|
|
145
148
|
* here, so a field kept frosting over its backdrop on the one setting
|
|
146
149
|
* that asks for no frost. */
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<Accordion.Trigger
|
|
15
15
|
bind:ref
|
|
16
16
|
class={cn(
|
|
17
|
-
'flex
|
|
17
|
+
'flex tier-control w-full items-center justify-between gap-icon-inset-chip px-inset-control text-body text-fg hover:bg-highlight hover:shadow-highlight focus:outline-none disabled:opacity-50',
|
|
18
18
|
className
|
|
19
19
|
)}
|
|
20
20
|
{...restProps}
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
bind:ref
|
|
33
33
|
{...relay?.attrs}
|
|
34
34
|
class={cn(
|
|
35
|
-
'fixed top-1/2 left-1/2 z-overlay flex max-h-[85dvh] w-full max-w-md -translate-x-1/2 -translate-y-1/2 flex-col gap-gutter overflow-y-auto rounded-bar
|
|
35
|
+
'fixed top-1/2 left-1/2 z-overlay flex max-h-[85dvh] w-full max-w-md -translate-x-1/2 -translate-y-1/2 flex-col gap-gutter overflow-y-auto rounded-bar material-panel p-card',
|
|
36
36
|
className
|
|
37
37
|
)}
|
|
38
38
|
{...restProps}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// that cost. A badge holding an icon must stay flex to lay the icon out
|
|
20
20
|
// beside the text, and keeps the general trim — its line-height:1 plus
|
|
21
21
|
// flex centring, which is the best available when the text is anonymous.
|
|
22
|
-
base: 'inline-flex
|
|
22
|
+
base: 'inline-flex min-w-pill shrink-0 items-center justify-center gap-gutter tier-pill px-pill font-mono text-body leading-none whitespace-nowrap has-[svg]:gap-inset-pill era-text-trim not-has-[svg]:era-token-ink',
|
|
23
23
|
variants: {
|
|
24
24
|
tone: {
|
|
25
25
|
default: 'bg-fill text-fg',
|
|
@@ -56,7 +56,13 @@
|
|
|
56
56
|
} = $props();
|
|
57
57
|
</script>
|
|
58
58
|
|
|
59
|
-
<span
|
|
59
|
+
<span
|
|
60
|
+
bind:this={ref}
|
|
61
|
+
data-era-geometry="bounded"
|
|
62
|
+
data-era-tier="pill"
|
|
63
|
+
class={cn(badgeVariants({ tone }), className)}
|
|
64
|
+
{...restProps}
|
|
65
|
+
>
|
|
60
66
|
{#if lead}
|
|
61
67
|
{@render lead()}
|
|
62
68
|
{/if}
|
|
@@ -7,7 +7,7 @@ export declare const badgeVariants: import("tailwind-variants").TVReturnType<{
|
|
|
7
7
|
warning: "bg-warning text-warning-fg";
|
|
8
8
|
info: "bg-info text-info-fg";
|
|
9
9
|
};
|
|
10
|
-
}, undefined, "inline-flex
|
|
10
|
+
}, undefined, "inline-flex min-w-pill shrink-0 items-center justify-center gap-gutter tier-pill px-pill font-mono text-body leading-none whitespace-nowrap has-[svg]:gap-inset-pill era-text-trim not-has-[svg]:era-token-ink", {
|
|
11
11
|
tone: {
|
|
12
12
|
default: "bg-fill text-fg";
|
|
13
13
|
accent: "bg-primary text-primary-fg";
|
package/dist/ui/bar/bar.svelte
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
import { cn, tv } from '../../utils/index.js';
|
|
3
3
|
|
|
4
|
+
export type BarSize = 'chip' | 'control' | 'bar';
|
|
5
|
+
export type BarContent = 'icon' | 'pill' | 'chip' | 'control';
|
|
6
|
+
export type BarGeometry =
|
|
7
|
+
| { size: 'chip'; content?: 'icon' | 'pill' }
|
|
8
|
+
| { size: 'control'; content?: 'icon' | 'pill' | 'chip' }
|
|
9
|
+
| { size?: 'bar'; content?: BarContent };
|
|
10
|
+
|
|
11
|
+
const defaultContent: Record<BarSize, BarContent> = {
|
|
12
|
+
chip: 'icon',
|
|
13
|
+
control: 'chip',
|
|
14
|
+
bar: 'control'
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function resolveBarContent(size: BarSize, content?: BarContent): BarContent {
|
|
18
|
+
const resolved = content ?? defaultContent[size];
|
|
19
|
+
const order = ['icon', 'pill', 'chip', 'control', 'bar'];
|
|
20
|
+
if (order.indexOf(resolved) >= order.indexOf(size)) {
|
|
21
|
+
throw new Error(`Bar size="${size}" cannot contain tier "${resolved}"`);
|
|
22
|
+
}
|
|
23
|
+
return resolved;
|
|
24
|
+
}
|
|
25
|
+
|
|
4
26
|
// A Bar is a flex container sized to a tier height, holding smaller controls
|
|
5
27
|
// at the even concentric gap. The height scales with density; pick the tier
|
|
6
28
|
// that fits the content:
|
|
@@ -14,9 +36,9 @@
|
|
|
14
36
|
base: 'flex items-center leading-none',
|
|
15
37
|
variants: {
|
|
16
38
|
size: {
|
|
17
|
-
chip: '
|
|
18
|
-
control: '
|
|
19
|
-
bar: '
|
|
39
|
+
chip: 'tier-chip',
|
|
40
|
+
control: 'tier-control',
|
|
41
|
+
bar: 'tier-bar'
|
|
20
42
|
},
|
|
21
43
|
/**
|
|
22
44
|
* The tier of the CONTROLS inside, because that is what the bar's own
|
|
@@ -26,11 +48,10 @@
|
|
|
26
48
|
* had each restated the two-tier value by hand, and the geometry spec had
|
|
27
49
|
* been rewritten twice chasing which token they were restating.
|
|
28
50
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* differs per size and also comes from the compounds.
|
|
51
|
+
* Name the ACTUAL tier inside. Omitting it means the next canonical rung:
|
|
52
|
+
* chip⊃icon, control⊃chip, bar⊃control. There is deliberately no `tier`
|
|
53
|
+
* shorthand in the public API: it hid which pair supplied the inset and
|
|
54
|
+
* taught the false claim that every adjacent pair had the same value.
|
|
34
55
|
*
|
|
35
56
|
* THIS USED TO BE ONE CLASS FOR ALL THREE SIZES — `px-icon-inset-chip`,
|
|
36
57
|
* on the stated reasoning that "chip⊃icon, control⊃chip and bar⊃control
|
|
@@ -53,8 +74,10 @@
|
|
|
53
74
|
* compared ACROSS the axes. layout/wall-is-isotropic now does.
|
|
54
75
|
*/
|
|
55
76
|
content: {
|
|
56
|
-
|
|
57
|
-
pill: ''
|
|
77
|
+
icon: '',
|
|
78
|
+
pill: '',
|
|
79
|
+
chip: '',
|
|
80
|
+
control: ''
|
|
58
81
|
},
|
|
59
82
|
/**
|
|
60
83
|
* The flush header bar capping a panel — Pane.Handle, Dialog.Header,
|
|
@@ -80,27 +103,34 @@
|
|
|
80
103
|
}
|
|
81
104
|
},
|
|
82
105
|
compoundVariants: [
|
|
83
|
-
// content="tier" — one tier down, each pairing named for itself.
|
|
84
106
|
// chip ⊃ icon = sp/2.
|
|
85
107
|
{
|
|
86
108
|
size: 'chip',
|
|
87
|
-
content: '
|
|
109
|
+
content: 'icon',
|
|
88
110
|
class: 'gap-icon-inset-chip px-icon-inset-chip'
|
|
89
111
|
},
|
|
90
112
|
// control ⊃ chip = (sp−6)/2 — the tight-but-present rung, 1/2/3.
|
|
91
113
|
{
|
|
92
114
|
size: 'control',
|
|
93
|
-
content: '
|
|
115
|
+
content: 'chip',
|
|
94
116
|
class: 'gap-chip-inset-control px-chip-inset-control'
|
|
95
117
|
},
|
|
96
|
-
// bar ⊃ control
|
|
97
|
-
//
|
|
98
|
-
// styles/index.css), so it takes that name rather than borrowing
|
|
99
|
-
// icon-inset-chip's — same number, but a reader can tell why.
|
|
118
|
+
// bar ⊃ control happens to equal the gutter, but it keeps a pair-specific
|
|
119
|
+
// name so geometry never borrows a layout token by numerical coincidence.
|
|
100
120
|
{
|
|
101
121
|
size: 'bar',
|
|
102
|
-
content: '
|
|
103
|
-
class: 'gap-
|
|
122
|
+
content: 'control',
|
|
123
|
+
class: 'gap-control-inset-bar px-control-inset-bar'
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
size: 'control',
|
|
127
|
+
content: 'icon',
|
|
128
|
+
class: 'gap-icon-inset-control px-icon-inset-control'
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
size: 'bar',
|
|
132
|
+
content: 'icon',
|
|
133
|
+
class: 'gap-icon-inset-bar px-icon-inset-bar'
|
|
104
134
|
},
|
|
105
135
|
// control ⊃ pill = (3sp − sp − 10)/2 — the named token.
|
|
106
136
|
{
|
|
@@ -115,6 +145,11 @@
|
|
|
115
145
|
content: 'pill',
|
|
116
146
|
class: 'gap-pill-inset-bar px-pill-inset-bar'
|
|
117
147
|
},
|
|
148
|
+
{
|
|
149
|
+
size: 'bar',
|
|
150
|
+
content: 'chip',
|
|
151
|
+
class: 'gap-chip-inset-bar px-chip-inset-bar'
|
|
152
|
+
},
|
|
118
153
|
// chip ⊃ pill — its own token, not the text inset it used to borrow. The two
|
|
119
154
|
// were the same number only while type was 14px at every density; dense's
|
|
120
155
|
// 12px broke the tie and left this pairing a pixel wide.
|
|
@@ -124,7 +159,7 @@
|
|
|
124
159
|
class: 'gap-pill-inset-chip px-pill-inset-chip'
|
|
125
160
|
}
|
|
126
161
|
],
|
|
127
|
-
defaultVariants: { size: 'bar', content: '
|
|
162
|
+
defaultVariants: { size: 'bar', content: 'control', divider: false }
|
|
128
163
|
});
|
|
129
164
|
</script>
|
|
130
165
|
|
|
@@ -135,8 +170,9 @@
|
|
|
135
170
|
let {
|
|
136
171
|
ref = $bindable(null),
|
|
137
172
|
size = 'bar',
|
|
138
|
-
content
|
|
173
|
+
content,
|
|
139
174
|
divider = false,
|
|
175
|
+
topology = 'nested',
|
|
140
176
|
children,
|
|
141
177
|
class: className,
|
|
142
178
|
...restProps
|
|
@@ -146,16 +182,49 @@
|
|
|
146
182
|
size?: 'chip' | 'control' | 'bar';
|
|
147
183
|
/**
|
|
148
184
|
* Tier of the controls inside — drives the bar's padding and gap so they
|
|
149
|
-
* stay concentric to them.
|
|
150
|
-
* the
|
|
185
|
+
* stay concentric to them. Omit this for the next canonical rung, or name
|
|
186
|
+
* the actual tier when the contents are smaller.
|
|
187
|
+
*/
|
|
188
|
+
content?: BarContent;
|
|
189
|
+
/**
|
|
190
|
+
* The flush cap-a-panel chrome: an outset rule below, and a rounded
|
|
191
|
+
* BOTTOM only — the top defers to the panel's own radius.
|
|
192
|
+
*
|
|
193
|
+
* THE BOTTOM RADIUS IS LOAD-BEARING FOR THE RULE. The divider is an
|
|
194
|
+
* outset `box-shadow`, so it follows the box's corners: the rounded
|
|
195
|
+
* bottom is what curves the line up at the ends and makes the bar read
|
|
196
|
+
* as a long pill. Overriding the radius therefore changes the RULE, not
|
|
197
|
+
* just the corners. Measured against `cn`:
|
|
198
|
+
*
|
|
199
|
+
* - `rounded-none` drops both — a square bar with a dead-straight rule.
|
|
200
|
+
* That is the intended square mode (an in-app Notes bar passes it).
|
|
201
|
+
* - `rounded-b-*` or `rounded-b-none` replaces the curve — this is the
|
|
202
|
+
* one that surprises, because the rule changes shape when the caller
|
|
203
|
+
* thought they were only squaring a corner.
|
|
204
|
+
* - `rounded-t-*` is SAFE: it wins against `rounded-t-none` and leaves
|
|
205
|
+
* `rounded-b-control` standing, so the curve survives.
|
|
206
|
+
*
|
|
207
|
+
* A consumer lost the curve this way. The coupling was already written
|
|
208
|
+
* down — on the variant, inside `<script module>`, where someone
|
|
209
|
+
* hovering this prop never reaches it. Docs are only as good as the
|
|
210
|
+
* place the reader is standing.
|
|
151
211
|
*/
|
|
152
|
-
content?: 'tier' | 'pill';
|
|
153
|
-
/** The flush cap-a-panel chrome: outset divider below, bottom rd-md. */
|
|
154
212
|
divider?: boolean;
|
|
213
|
+
/** `docked` removes one or more exposed curves; strict radius nesting does not apply. */
|
|
214
|
+
topology?: 'nested' | 'docked';
|
|
155
215
|
children?: Snippet;
|
|
156
216
|
} = $props();
|
|
217
|
+
|
|
218
|
+
const resolvedContent = $derived(resolveBarContent(size, content));
|
|
157
219
|
</script>
|
|
158
220
|
|
|
159
|
-
<div
|
|
221
|
+
<div
|
|
222
|
+
bind:this={ref}
|
|
223
|
+
data-era-geometry={divider ? 'docked' : topology}
|
|
224
|
+
data-era-tier={size}
|
|
225
|
+
data-era-contains={resolvedContent}
|
|
226
|
+
class={cn(barVariants({ size, content: resolvedContent, divider }), className)}
|
|
227
|
+
{...restProps}
|
|
228
|
+
>
|
|
160
229
|
{@render children?.()}
|
|
161
230
|
</div>
|
|
@@ -1,8 +1,21 @@
|
|
|
1
|
+
export type BarSize = 'chip' | 'control' | 'bar';
|
|
2
|
+
export type BarContent = 'icon' | 'pill' | 'chip' | 'control';
|
|
3
|
+
export type BarGeometry = {
|
|
4
|
+
size: 'chip';
|
|
5
|
+
content?: 'icon' | 'pill';
|
|
6
|
+
} | {
|
|
7
|
+
size: 'control';
|
|
8
|
+
content?: 'icon' | 'pill' | 'chip';
|
|
9
|
+
} | {
|
|
10
|
+
size?: 'bar';
|
|
11
|
+
content?: BarContent;
|
|
12
|
+
};
|
|
13
|
+
export declare function resolveBarContent(size: BarSize, content?: BarContent): BarContent;
|
|
1
14
|
export declare const barVariants: import("tailwind-variants").TVReturnType<{
|
|
2
15
|
size: {
|
|
3
|
-
chip: "
|
|
4
|
-
control: "
|
|
5
|
-
bar: "
|
|
16
|
+
chip: "tier-chip";
|
|
17
|
+
control: "tier-control";
|
|
18
|
+
bar: "tier-bar";
|
|
6
19
|
};
|
|
7
20
|
/**
|
|
8
21
|
* The tier of the CONTROLS inside, because that is what the bar's own
|
|
@@ -12,11 +25,10 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
|
|
|
12
25
|
* had each restated the two-tier value by hand, and the geometry spec had
|
|
13
26
|
* been rewritten twice chasing which token they were restating.
|
|
14
27
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* differs per size and also comes from the compounds.
|
|
28
|
+
* Name the ACTUAL tier inside. Omitting it means the next canonical rung:
|
|
29
|
+
* chip⊃icon, control⊃chip, bar⊃control. There is deliberately no `tier`
|
|
30
|
+
* shorthand in the public API: it hid which pair supplied the inset and
|
|
31
|
+
* taught the false claim that every adjacent pair had the same value.
|
|
20
32
|
*
|
|
21
33
|
* THIS USED TO BE ONE CLASS FOR ALL THREE SIZES — `px-icon-inset-chip`,
|
|
22
34
|
* on the stated reasoning that "chip⊃icon, control⊃chip and bar⊃control
|
|
@@ -39,8 +51,10 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
|
|
|
39
51
|
* compared ACROSS the axes. layout/wall-is-isotropic now does.
|
|
40
52
|
*/
|
|
41
53
|
content: {
|
|
42
|
-
|
|
54
|
+
icon: "";
|
|
43
55
|
pill: "";
|
|
56
|
+
chip: "";
|
|
57
|
+
control: "";
|
|
44
58
|
};
|
|
45
59
|
/**
|
|
46
60
|
* The flush header bar capping a panel — Pane.Handle, Dialog.Header,
|
|
@@ -66,9 +80,9 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
|
|
|
66
80
|
};
|
|
67
81
|
}, undefined, "flex items-center leading-none", {
|
|
68
82
|
size: {
|
|
69
|
-
chip: "
|
|
70
|
-
control: "
|
|
71
|
-
bar: "
|
|
83
|
+
chip: "tier-chip";
|
|
84
|
+
control: "tier-control";
|
|
85
|
+
bar: "tier-bar";
|
|
72
86
|
};
|
|
73
87
|
/**
|
|
74
88
|
* The tier of the CONTROLS inside, because that is what the bar's own
|
|
@@ -78,11 +92,10 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
|
|
|
78
92
|
* had each restated the two-tier value by hand, and the geometry spec had
|
|
79
93
|
* been rewritten twice chasing which token they were restating.
|
|
80
94
|
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* differs per size and also comes from the compounds.
|
|
95
|
+
* Name the ACTUAL tier inside. Omitting it means the next canonical rung:
|
|
96
|
+
* chip⊃icon, control⊃chip, bar⊃control. There is deliberately no `tier`
|
|
97
|
+
* shorthand in the public API: it hid which pair supplied the inset and
|
|
98
|
+
* taught the false claim that every adjacent pair had the same value.
|
|
86
99
|
*
|
|
87
100
|
* THIS USED TO BE ONE CLASS FOR ALL THREE SIZES — `px-icon-inset-chip`,
|
|
88
101
|
* on the stated reasoning that "chip⊃icon, control⊃chip and bar⊃control
|
|
@@ -105,8 +118,10 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
|
|
|
105
118
|
* compared ACROSS the axes. layout/wall-is-isotropic now does.
|
|
106
119
|
*/
|
|
107
120
|
content: {
|
|
108
|
-
|
|
121
|
+
icon: "";
|
|
109
122
|
pill: "";
|
|
123
|
+
chip: "";
|
|
124
|
+
control: "";
|
|
110
125
|
};
|
|
111
126
|
/**
|
|
112
127
|
* The flush header bar capping a panel — Pane.Handle, Dialog.Header,
|
|
@@ -132,9 +147,9 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
|
|
|
132
147
|
};
|
|
133
148
|
}, undefined, import("tailwind-variants").TVReturnTypeLike<{
|
|
134
149
|
size: {
|
|
135
|
-
chip: "
|
|
136
|
-
control: "
|
|
137
|
-
bar: "
|
|
150
|
+
chip: "tier-chip";
|
|
151
|
+
control: "tier-control";
|
|
152
|
+
bar: "tier-bar";
|
|
138
153
|
};
|
|
139
154
|
/**
|
|
140
155
|
* The tier of the CONTROLS inside, because that is what the bar's own
|
|
@@ -144,11 +159,10 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
|
|
|
144
159
|
* had each restated the two-tier value by hand, and the geometry spec had
|
|
145
160
|
* been rewritten twice chasing which token they were restating.
|
|
146
161
|
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
* differs per size and also comes from the compounds.
|
|
162
|
+
* Name the ACTUAL tier inside. Omitting it means the next canonical rung:
|
|
163
|
+
* chip⊃icon, control⊃chip, bar⊃control. There is deliberately no `tier`
|
|
164
|
+
* shorthand in the public API: it hid which pair supplied the inset and
|
|
165
|
+
* taught the false claim that every adjacent pair had the same value.
|
|
152
166
|
*
|
|
153
167
|
* THIS USED TO BE ONE CLASS FOR ALL THREE SIZES — `px-icon-inset-chip`,
|
|
154
168
|
* on the stated reasoning that "chip⊃icon, control⊃chip and bar⊃control
|
|
@@ -171,8 +185,10 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
|
|
|
171
185
|
* compared ACROSS the axes. layout/wall-is-isotropic now does.
|
|
172
186
|
*/
|
|
173
187
|
content: {
|
|
174
|
-
|
|
188
|
+
icon: "";
|
|
175
189
|
pill: "";
|
|
190
|
+
chip: "";
|
|
191
|
+
control: "";
|
|
176
192
|
};
|
|
177
193
|
/**
|
|
178
194
|
* The flush header bar capping a panel — Pane.Handle, Dialog.Header,
|
|
@@ -205,12 +221,36 @@ type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
|
|
|
205
221
|
size?: 'chip' | 'control' | 'bar';
|
|
206
222
|
/**
|
|
207
223
|
* Tier of the controls inside — drives the bar's padding and gap so they
|
|
208
|
-
* stay concentric to them.
|
|
209
|
-
* the
|
|
224
|
+
* stay concentric to them. Omit this for the next canonical rung, or name
|
|
225
|
+
* the actual tier when the contents are smaller.
|
|
226
|
+
*/
|
|
227
|
+
content?: BarContent;
|
|
228
|
+
/**
|
|
229
|
+
* The flush cap-a-panel chrome: an outset rule below, and a rounded
|
|
230
|
+
* BOTTOM only — the top defers to the panel's own radius.
|
|
231
|
+
*
|
|
232
|
+
* THE BOTTOM RADIUS IS LOAD-BEARING FOR THE RULE. The divider is an
|
|
233
|
+
* outset `box-shadow`, so it follows the box's corners: the rounded
|
|
234
|
+
* bottom is what curves the line up at the ends and makes the bar read
|
|
235
|
+
* as a long pill. Overriding the radius therefore changes the RULE, not
|
|
236
|
+
* just the corners. Measured against `cn`:
|
|
237
|
+
*
|
|
238
|
+
* - `rounded-none` drops both — a square bar with a dead-straight rule.
|
|
239
|
+
* That is the intended square mode (an in-app Notes bar passes it).
|
|
240
|
+
* - `rounded-b-*` or `rounded-b-none` replaces the curve — this is the
|
|
241
|
+
* one that surprises, because the rule changes shape when the caller
|
|
242
|
+
* thought they were only squaring a corner.
|
|
243
|
+
* - `rounded-t-*` is SAFE: it wins against `rounded-t-none` and leaves
|
|
244
|
+
* `rounded-b-control` standing, so the curve survives.
|
|
245
|
+
*
|
|
246
|
+
* A consumer lost the curve this way. The coupling was already written
|
|
247
|
+
* down — on the variant, inside `<script module>`, where someone
|
|
248
|
+
* hovering this prop never reaches it. Docs are only as good as the
|
|
249
|
+
* place the reader is standing.
|
|
210
250
|
*/
|
|
211
|
-
content?: 'tier' | 'pill';
|
|
212
|
-
/** The flush cap-a-panel chrome: outset divider below, bottom rd-md. */
|
|
213
251
|
divider?: boolean;
|
|
252
|
+
/** `docked` removes one or more exposed curves; strict radius nesting does not apply. */
|
|
253
|
+
topology?: 'nested' | 'docked';
|
|
214
254
|
children?: Snippet;
|
|
215
255
|
};
|
|
216
256
|
declare const Bar: import("svelte").Component<$$ComponentProps, {}, "ref">;
|