@signal9/era-ui 30.8.0 → 31.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.
Files changed (83) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/ai/conversations/conversations-item.svelte +1 -1
  3. package/dist/ai/plan/plan-header.svelte +1 -1
  4. package/dist/ai/prompt-input/prompt-input-attachments.svelte +2 -6
  5. package/dist/ai/swarm/swarm-node.svelte +1 -1
  6. package/dist/ai/todo/todo-header.svelte +1 -1
  7. package/dist/ai/todo/todo-item.svelte +1 -1
  8. package/dist/ai/tool/tool-chip.svelte +1 -1
  9. package/dist/ai/web-preview/web-preview.svelte +1 -1
  10. package/dist/dev/audit/audits/wall-is-isotropic.js +1 -1
  11. package/dist/docs/css-utilities.js +7 -3
  12. package/dist/era-ui.css +1 -1
  13. package/dist/generated-docs/badge.md +1 -1
  14. package/dist/generated-docs/bar.md +22 -4
  15. package/dist/generated-docs/button.md +38 -4
  16. package/dist/generated-docs/card.md +35 -5
  17. package/dist/generated-docs/chip.md +16 -0
  18. package/dist/generated-docs/llms-full.txt +310 -49
  19. package/dist/generated-docs/llms.txt +4 -3
  20. package/dist/generated-docs/manifest.json +45 -21
  21. package/dist/generated-docs/meter.md +79 -1
  22. package/dist/generated-docs/nav.md +8 -1
  23. package/dist/generated-docs/separator.md +18 -0
  24. package/dist/generated-docs/utilities.json +32 -9
  25. package/dist/generated-docs/utilities.md +89 -30
  26. package/dist/styles/density.css +15 -25
  27. package/dist/styles/index.css +32 -27
  28. package/dist/ui/accordion/accordion-trigger.svelte +1 -1
  29. package/dist/ui/badge/badge.svelte +8 -2
  30. package/dist/ui/badge/badge.svelte.d.ts +1 -1
  31. package/dist/ui/bar/bar.svelte +95 -26
  32. package/dist/ui/bar/bar.svelte.d.ts +71 -31
  33. package/dist/ui/button/button.svelte +5 -0
  34. package/dist/ui/button/button.svelte.d.ts +2 -0
  35. package/dist/ui/button/variants.js +4 -9
  36. package/dist/ui/calendar/calendar-day.svelte +1 -1
  37. package/dist/ui/card/card.svelte +22 -9
  38. package/dist/ui/card/card.svelte.d.ts +19 -7
  39. package/dist/ui/chip/chip.svelte +5 -2
  40. package/dist/ui/chip/chip.svelte.d.ts +6 -6
  41. package/dist/ui/collapsible/collapsible-trigger.svelte +1 -1
  42. package/dist/ui/combobox/combobox-trigger.svelte +1 -1
  43. package/dist/ui/command/command-item.svelte +1 -1
  44. package/dist/ui/command/command-link-item.svelte +1 -1
  45. package/dist/ui/command/command-root.svelte +3 -5
  46. package/dist/ui/date-field/date-field-segment.svelte +1 -1
  47. package/dist/ui/date-picker/date-picker-day.svelte +1 -1
  48. package/dist/ui/date-picker/date-picker-segment.svelte +1 -1
  49. package/dist/ui/date-picker/date-picker-trigger.svelte +1 -1
  50. package/dist/ui/date-range-field/date-range-field-segment.svelte +1 -1
  51. package/dist/ui/date-range-picker/date-range-picker-day.svelte +1 -1
  52. package/dist/ui/date-range-picker/date-range-picker-segment.svelte +1 -1
  53. package/dist/ui/date-range-picker/date-range-picker-trigger.svelte +1 -1
  54. package/dist/ui/dialog/dialog-content.svelte +19 -1
  55. package/dist/ui/dropdown-menu/dropdown-menu-trigger.svelte +1 -1
  56. package/dist/ui/file-upload/file-upload.svelte +1 -1
  57. package/dist/ui/input/variants.d.ts +6 -6
  58. package/dist/ui/input/variants.js +2 -2
  59. package/dist/ui/kv/kv.svelte +1 -1
  60. package/dist/ui/menubar/menubar-root.svelte +1 -1
  61. package/dist/ui/menubar/menubar-trigger.svelte +1 -1
  62. package/dist/ui/nav/nav-bar.svelte +9 -4
  63. package/dist/ui/nav/nav-bar.svelte.d.ts +2 -1
  64. package/dist/ui/pane/pane-root.svelte +3 -12
  65. package/dist/ui/pane/pane-tab.svelte +1 -1
  66. package/dist/ui/select/select-trigger.svelte +1 -1
  67. package/dist/ui/slider/slider-thumb.svelte +1 -1
  68. package/dist/ui/step/step-summary.svelte +1 -1
  69. package/dist/ui/switch/switch.svelte +2 -2
  70. package/dist/ui/time-field/time-field-segment.svelte +1 -1
  71. package/dist/ui/time-range-field/time-range-field-segment.svelte +1 -1
  72. package/dist/ui/timeline/timeline-step.svelte +1 -1
  73. package/dist/ui/toggle-group/toggle-group-item.svelte +2 -2
  74. package/dist/ui/toggle-group/toggle-group-item.svelte.d.ts +6 -6
  75. package/dist/ui/toggle-group/toggle-group-root.svelte +1 -2
  76. package/dist/ui/toggle-group/toggle-group-root.svelte.d.ts +3 -3
  77. package/dist/ui/tooltip/tooltip-content.svelte +1 -1
  78. package/dist/ui/tree/tree-item.svelte +1 -1
  79. package/dist/ui/video-player/video-player.svelte +1 -1
  80. package/dist/utils/tw-merge-config.d.ts +3 -0
  81. package/dist/utils/tw-merge-config.js +4 -0
  82. package/package.json +4 -3
  83. package/skill/SKILL.md +17 -17
@@ -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: "h-chip rounded-chip";
4
- control: "h-control rounded-control";
5
- bar: "h-bar rounded-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
- * - `tier` (default) one tier smaller, the pairing above. Each size gets
16
- * its OWN token, from the compounds below.
17
- * - `pill` the compact pairing: pills and fields (a filter beside a
18
- * pill-tier icon button, a title bar). Two tiers down, so the inset
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
- tier: "";
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: "h-chip rounded-chip";
70
- control: "h-control rounded-control";
71
- bar: "h-bar rounded-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
- * - `tier` (default) one tier smaller, the pairing above. Each size gets
82
- * its OWN token, from the compounds below.
83
- * - `pill` the compact pairing: pills and fields (a filter beside a
84
- * pill-tier icon button, a title bar). Two tiers down, so the inset
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
- tier: "";
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: "h-chip rounded-chip";
136
- control: "h-control rounded-control";
137
- bar: "h-bar rounded-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
- * - `tier` (default) one tier smaller, the pairing above. Each size gets
148
- * its OWN token, from the compounds below.
149
- * - `pill` the compact pairing: pills and fields (a filter beside a
150
- * pill-tier icon button, a title bar). Two tiers down, so the inset
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
- tier: "";
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. `tier` (default) is one tier smaller; `pill` is
209
- * the compact pairing (pills/fields in an sm or md bar).
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">;
@@ -19,6 +19,7 @@
19
19
  lead,
20
20
  trail,
21
21
  caps = false,
22
+ topology = 'bounded',
22
23
  children,
23
24
  class: className,
24
25
  ...restProps
@@ -126,6 +127,8 @@
126
127
  * which is the whole reason those snippets exist.
127
128
  */
128
129
  caps?: boolean;
130
+ /** `docked` joins this control to a neighbour and removes one or more curves. */
131
+ topology?: 'bounded' | 'docked';
129
132
  children?: Snippet;
130
133
  } = $props();
131
134
 
@@ -156,6 +159,8 @@
156
159
  aria-busy={inFlight || undefined}
157
160
  data-state={active ? 'on' : undefined}
158
161
  data-size={size}
162
+ data-era-geometry={variant === 'filled' ? topology : undefined}
163
+ data-era-tier={variant === 'filled' ? size : undefined}
159
164
  class={cn(
160
165
  buttonVariants({ variant, tone, size, icon, active }),
161
166
  // Positioned only while loading — the spinner overlay below needs a
@@ -104,6 +104,8 @@ type $$ComponentProps = Button.RootProps & {
104
104
  * which is the whole reason those snippets exist.
105
105
  */
106
106
  caps?: boolean;
107
+ /** `docked` joins this control to a neighbour and removes one or more curves. */
108
+ topology?: 'bounded' | 'docked';
107
109
  children?: Snippet;
108
110
  };
109
111
  declare const Button: import("svelte").Component<$$ComponentProps, {}, "ref">;
@@ -40,27 +40,22 @@ export const buttonVariants = tv({
40
40
  {
41
41
  variant: 'filled',
42
42
  size: 'control',
43
- class: 'h-control min-w-control rounded-control'
43
+ class: 'min-w-control tier-control'
44
44
  },
45
45
  {
46
46
  variant: 'filled',
47
47
  size: 'chip',
48
- class: 'h-chip min-w-chip rounded-chip'
48
+ class: 'min-w-chip tier-chip'
49
49
  },
50
50
  {
51
51
  variant: 'filled',
52
52
  size: 'pill',
53
- class: 'h-pill min-w-pill rounded-pill'
53
+ class: 'min-w-pill tier-pill'
54
54
  },
55
55
  {
56
56
  variant: 'filled',
57
57
  size: 'icon',
58
- class: 'h-icon min-w-icon rounded-icon'
59
- },
60
- {
61
- variant: 'filled',
62
- size: 'icon',
63
- class: 'h-icon min-w-icon rounded-icon'
58
+ class: 'min-w-icon tier-icon'
64
59
  },
65
60
  // filled insets; icon buttons go square instead. When an icon is present,
66
61
  // gap widens to match the wall inset so the icon sits in rhythm with it.
@@ -15,7 +15,7 @@
15
15
  <Calendar.Day
16
16
  bind:ref
17
17
  class={cn(
18
- 'era-token-ink size-control cursor-default rounded-control text-body text-fg hover:bg-highlight focus:outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[outside-month]:pointer-events-none data-[outside-month]:text-muted/40 data-[selected]:bg-hover data-[selected]:text-bright data-[unavailable]:text-muted data-[unavailable]:line-through',
18
+ 'era-token-ink tier-control w-control cursor-default text-body text-fg hover:bg-highlight focus:outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[outside-month]:pointer-events-none data-[outside-month]:text-muted/40 data-[selected]:bg-hover data-[selected]:text-bright data-[unavailable]:text-muted data-[unavailable]:line-through',
19
19
  className
20
20
  )}
21
21
  {...restProps}
@@ -39,10 +39,11 @@
39
39
  // chisel, that is the difference between a control and a picture of
40
40
  // one. Inert on flat (the token is `none`) and on glass (it resolves
41
41
  // to the resting shadow), so only the surface that has a pressed face
42
- // shows it. No content sink to go with it: the sink moves a control's
43
- // single content wrapper, and a card's children are the consumer's.
42
+ // shows it. Move one library-owned content layer with the face: transforming
43
+ // consumer children separately would pull a card's sections apart, while no
44
+ // wrapper leaves the frame depressed around stationary ink.
44
45
  interactive: {
45
- true: 'cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight active:shadow-pressed era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50'
46
+ true: 'cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight active:shadow-pressed [&:active>[data-card-content]]:translate-x-(--era-press-sink-x) [&:active>[data-card-content]]:translate-y-(--era-press-sink-y) era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50'
46
47
  }
47
48
  },
48
49
  defaultVariants: { tone: 'elevated', sectioned: false, interactive: false }
@@ -124,10 +125,22 @@
124
125
  * A CARD THAT IS PRESSABLE SHOULD USUALLY BE `elevated`. Passing `href`
125
126
  * or `onclick` turns on the interactive face — hover, focus, press — but
126
127
  * it deliberately does NOT override the tier you asked for, so a
127
- * `surface` link card has no resting lift and reads flatter than the
128
- * static cards around it. That combination was reported as a bug and it
129
- * is a choice: a tone that silently changed under an event handler would
130
- * be a worse one.
128
+ * `surface` link card does not get the raised tier's separation and can
129
+ * read flatter than the static cards around it. That combination was
130
+ * reported as a bug and it is a choice: a tone that silently changed
131
+ * under an event handler would be a worse one.
132
+ *
133
+ * HOW THE TIERS DIFFER IS SURFACE-DEPENDENT, so do not go looking for a
134
+ * fill difference on every surface. `base` mixes the elevated fill 6%
135
+ * toward `--color-bright` and adds a resting shadow, so there the tiers
136
+ * differ in COLOUR. `bevel` sets `--era-surface-bg-elevated` to
137
+ * `--era-surface-bg` outright — elevation is a chisel, not a tone, which
138
+ * is bevel's whole premise — so `surface` and `elevated` paint the
139
+ * IDENTICAL fill there and differ only in relief. A consumer measured
140
+ * exactly that on 30.8.0 bevel: both tones `oklch(0.195 0 none)` in dark,
141
+ * `0.863` in light, one variable, side by side. `glass` splits the tiers
142
+ * its own way again. So the tier is real on every surface; the thing
143
+ * carrying it is not always the fill.
131
144
  */
132
145
  tone?: 'elevated' | 'surface' | 'well' | 'flat';
133
146
  /** Rendered above the body with a subtle divider. */
@@ -178,7 +191,7 @@
178
191
  class={cn(cardVariants({ tone, sectioned, interactive: true }), className)}
179
192
  {...restProps}
180
193
  >
181
- {@render body()}
194
+ <div data-card-content>{@render body()}</div>
182
195
  </a>
183
196
  <!-- eslint-enable svelte/no-navigation-without-resolve -->
184
197
  {:else if onclick != null}
@@ -198,7 +211,7 @@
198
211
  class={cn(cardVariants({ tone, sectioned, interactive: true }), className)}
199
212
  {...restProps}
200
213
  >
201
- {@render body()}
214
+ <div data-card-content>{@render body()}</div>
202
215
  </button>
203
216
  {:else}
204
217
  <div
@@ -10,7 +10,7 @@ export declare const cardVariants: import("tailwind-variants").TVReturnType<{
10
10
  false: "p-card";
11
11
  };
12
12
  interactive: {
13
- true: "cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight active:shadow-pressed era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
13
+ true: "cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight active:shadow-pressed [&:active>[data-card-content]]:translate-x-(--era-press-sink-x) [&:active>[data-card-content]]:translate-y-(--era-press-sink-y) era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
14
14
  };
15
15
  }, undefined, "block w-full rounded-bar text-left text-fg", {
16
16
  tone: {
@@ -24,7 +24,7 @@ export declare const cardVariants: import("tailwind-variants").TVReturnType<{
24
24
  false: "p-card";
25
25
  };
26
26
  interactive: {
27
- true: "cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight active:shadow-pressed era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
27
+ true: "cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight active:shadow-pressed [&:active>[data-card-content]]:translate-x-(--era-press-sink-x) [&:active>[data-card-content]]:translate-y-(--era-press-sink-y) era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
28
28
  };
29
29
  }, undefined, import("tailwind-variants").TVReturnTypeLike<{
30
30
  tone: {
@@ -38,7 +38,7 @@ export declare const cardVariants: import("tailwind-variants").TVReturnType<{
38
38
  false: "p-card";
39
39
  };
40
40
  interactive: {
41
- true: "cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight active:shadow-pressed era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
41
+ true: "cursor-pointer hover:bg-highlight hover:shadow-highlight focus-visible:bg-highlight active:shadow-pressed [&:active>[data-card-content]]:translate-x-(--era-press-sink-x) [&:active>[data-card-content]]:translate-y-(--era-press-sink-y) era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
42
42
  };
43
43
  }, undefined>>;
44
44
  import type { Snippet } from 'svelte';
@@ -72,10 +72,22 @@ type $$ComponentProps = HTMLAttributes<HTMLElement> & AnchorBits & ButtonBits &
72
72
  * A CARD THAT IS PRESSABLE SHOULD USUALLY BE `elevated`. Passing `href`
73
73
  * or `onclick` turns on the interactive face — hover, focus, press — but
74
74
  * it deliberately does NOT override the tier you asked for, so a
75
- * `surface` link card has no resting lift and reads flatter than the
76
- * static cards around it. That combination was reported as a bug and it
77
- * is a choice: a tone that silently changed under an event handler would
78
- * be a worse one.
75
+ * `surface` link card does not get the raised tier's separation and can
76
+ * read flatter than the static cards around it. That combination was
77
+ * reported as a bug and it is a choice: a tone that silently changed
78
+ * under an event handler would be a worse one.
79
+ *
80
+ * HOW THE TIERS DIFFER IS SURFACE-DEPENDENT, so do not go looking for a
81
+ * fill difference on every surface. `base` mixes the elevated fill 6%
82
+ * toward `--color-bright` and adds a resting shadow, so there the tiers
83
+ * differ in COLOUR. `bevel` sets `--era-surface-bg-elevated` to
84
+ * `--era-surface-bg` outright — elevation is a chisel, not a tone, which
85
+ * is bevel's whole premise — so `surface` and `elevated` paint the
86
+ * IDENTICAL fill there and differ only in relief. A consumer measured
87
+ * exactly that on 30.8.0 bevel: both tones `oklch(0.195 0 none)` in dark,
88
+ * `0.863` in light, one variable, side by side. `glass` splits the tiers
89
+ * its own way again. So the tier is real on every surface; the thing
90
+ * carrying it is not always the fill.
79
91
  */
80
92
  tone?: 'elevated' | 'surface' | 'well' | 'flat';
81
93
  /** Rendered above the body with a subtle divider. */
@@ -16,8 +16,8 @@
16
16
  base: 'inline-flex shrink-0 items-center bg-fill font-mono text-body leading-none whitespace-nowrap text-fg shadow-sm',
17
17
  variants: {
18
18
  size: {
19
- chip: 'h-chip min-w-chip rounded-chip pl-chip',
20
- pill: 'h-pill min-w-pill rounded-pill pl-pill'
19
+ chip: 'min-w-chip tier-chip pl-chip',
20
+ pill: 'min-w-pill tier-pill pl-pill'
21
21
  },
22
22
  dismissible: { true: '', false: '' }
23
23
  },
@@ -110,6 +110,8 @@
110
110
 
111
111
  <div
112
112
  bind:this={ref}
113
+ data-era-geometry="bounded"
114
+ data-era-tier={size}
113
115
  class={cn(chipVariants({ size, dismissible: !!ondismiss }), className)}
114
116
  {...restProps}
115
117
  >
@@ -156,6 +158,7 @@
156
158
  <Button
157
159
  icon
158
160
  size="pill"
161
+ topology={size === 'pill' ? 'docked' : 'bounded'}
159
162
  tone="destructive"
160
163
  class={size === 'pill' ? 'rounded-l-none' : undefined}
161
164
  onclick={ondismiss}
@@ -1,7 +1,7 @@
1
1
  export declare const chipVariants: import("tailwind-variants").TVReturnType<{
2
2
  size: {
3
- chip: "h-chip min-w-chip rounded-chip pl-chip";
4
- pill: "h-pill min-w-pill rounded-pill pl-pill";
3
+ chip: "min-w-chip tier-chip pl-chip";
4
+ pill: "min-w-pill tier-pill pl-pill";
5
5
  };
6
6
  dismissible: {
7
7
  true: "";
@@ -9,8 +9,8 @@ export declare const chipVariants: import("tailwind-variants").TVReturnType<{
9
9
  };
10
10
  }, undefined, "inline-flex shrink-0 items-center bg-fill font-mono text-body leading-none whitespace-nowrap text-fg shadow-sm", {
11
11
  size: {
12
- chip: "h-chip min-w-chip rounded-chip pl-chip";
13
- pill: "h-pill min-w-pill rounded-pill pl-pill";
12
+ chip: "min-w-chip tier-chip pl-chip";
13
+ pill: "min-w-pill tier-pill pl-pill";
14
14
  };
15
15
  dismissible: {
16
16
  true: "";
@@ -18,8 +18,8 @@ export declare const chipVariants: import("tailwind-variants").TVReturnType<{
18
18
  };
19
19
  }, undefined, import("tailwind-variants").TVReturnTypeLike<{
20
20
  size: {
21
- chip: "h-chip min-w-chip rounded-chip pl-chip";
22
- pill: "h-pill min-w-pill rounded-pill pl-pill";
21
+ chip: "min-w-chip tier-chip pl-chip";
22
+ pill: "min-w-pill tier-pill pl-pill";
23
23
  };
24
24
  dismissible: {
25
25
  true: "";
@@ -13,7 +13,7 @@
13
13
  <Collapsible.Trigger
14
14
  bind:ref
15
15
  class={cn(
16
- 'flex h-control w-full items-center rounded-control px-inset-control text-body text-fg hover:bg-highlight focus:outline-none disabled:opacity-50',
16
+ 'flex tier-control w-full items-center px-inset-control text-body text-fg hover:bg-highlight focus:outline-none disabled:opacity-50',
17
17
  className
18
18
  )}
19
19
  {...restProps}
@@ -14,7 +14,7 @@
14
14
  <Combobox.Trigger
15
15
  bind:ref
16
16
  class={cn(
17
- 'flex size-control shrink-0 items-center justify-center rounded-control text-muted focus:outline-none',
17
+ 'flex tier-control w-control shrink-0 items-center justify-center text-muted focus:outline-none',
18
18
  className
19
19
  )}
20
20
  {...restProps}
@@ -8,7 +8,7 @@
8
8
  <Command.Item
9
9
  bind:ref
10
10
  class={cn(
11
- 'flex h-control cursor-pointer items-center gap-gutter rounded-control px-inset-control text-body leading-none text-fg outline-none select-none not-has-[svg]:era-label-ink data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[selected]:bg-highlight',
11
+ 'flex tier-control cursor-pointer items-center gap-gutter px-inset-control text-body leading-none text-fg outline-none select-none not-has-[svg]:era-label-ink data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[selected]:bg-highlight',
12
12
  className
13
13
  )}
14
14
  {...restProps}
@@ -8,7 +8,7 @@
8
8
  <Command.LinkItem
9
9
  bind:ref
10
10
  class={cn(
11
- 'flex h-control cursor-pointer items-center gap-gutter rounded-control px-inset-control text-body leading-none text-fg no-underline outline-none select-none not-has-[svg]:era-label-ink data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[selected]:bg-highlight',
11
+ 'flex tier-control cursor-pointer items-center gap-gutter px-inset-control text-body leading-none text-fg no-underline outline-none select-none not-has-[svg]:era-label-ink data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[selected]:bg-highlight',
12
12
  className
13
13
  )}
14
14
  {...restProps}
@@ -24,13 +24,11 @@
24
24
  // glass-blur, like every other floating panel (menus, dialogs, pickers):
25
25
  // inert on opaque surfaces, blurs the backdrop when the palette floats.
26
26
  !bare &&
27
- // [--era-container-rd:…] publishes this panel's own radius, so the rows
28
- // inside re-derive against rd-bar rather than the rd-control default.
29
- // rd-bar − gutter IS rd-control, so the palette renders unchanged; what
30
- // changes is that the rows now say WHY they are that radius.
27
+ // The panel is unbounded chrome; its bounded command rows carry their own
28
+ // control tier rather than inheriting geometry from this ancestor.
31
29
  // No border: --era-shadow-lg is the edge on every surface, and a border
32
30
  // alongside it draws two hairlines of the same colour on flat.
33
- 'overflow-hidden rounded-bar bg-well p-gutter shadow-lg glass-blur [--era-container-rd:var(--era-rd-bar)]',
31
+ 'overflow-hidden rounded-bar bg-well p-gutter shadow-lg glass-blur',
34
32
  className
35
33
  )}
36
34
  {...restProps}
@@ -18,7 +18,7 @@
18
18
  <DateField.Segment
19
19
  bind:ref
20
20
  class={cn(
21
- 'era-token-ink h-chip rounded-chip px-[calc(var(--era-sp)/2)] focus:bg-highlight focus:text-bright focus:outline-none aria-[valuetext=Empty]:text-muted data-[segment=literal]:text-muted',
21
+ 'era-token-ink tier-chip px-[calc(var(--era-sp)/2)] focus:bg-highlight focus:text-bright focus:outline-none aria-[valuetext=Empty]:text-muted data-[segment=literal]:text-muted',
22
22
  className
23
23
  )}
24
24
  {...restProps}
@@ -8,7 +8,7 @@
8
8
  <DatePicker.Day
9
9
  bind:ref
10
10
  class={cn(
11
- 'inline-flex size-control cursor-default items-center justify-center rounded-control text-body text-fg hover:bg-highlight focus:outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[outside-month]:pointer-events-none data-[outside-month]:text-muted/40 data-[selected]:bg-hover data-[selected]:text-bright data-[unavailable]:text-muted data-[unavailable]:line-through',
11
+ 'inline-flex tier-control w-control cursor-default items-center justify-center text-body text-fg hover:bg-highlight focus:outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[outside-month]:pointer-events-none data-[outside-month]:text-muted/40 data-[selected]:bg-hover data-[selected]:text-bright data-[unavailable]:text-muted data-[unavailable]:line-through',
12
12
  className
13
13
  )}
14
14
  {...restProps}
@@ -18,7 +18,7 @@
18
18
  <DatePicker.Segment
19
19
  bind:ref
20
20
  class={cn(
21
- 'era-token-ink h-chip rounded-chip px-[calc(var(--era-sp)/2)] focus:bg-highlight focus:text-bright focus:outline-none aria-[valuetext=Empty]:text-muted data-[segment=literal]:text-muted',
21
+ 'era-token-ink tier-chip px-[calc(var(--era-sp)/2)] focus:bg-highlight focus:text-bright focus:outline-none aria-[valuetext=Empty]:text-muted data-[segment=literal]:text-muted',
22
22
  className
23
23
  )}
24
24
  {...restProps}
@@ -14,7 +14,7 @@
14
14
  <DatePicker.Trigger
15
15
  bind:ref
16
16
  class={cn(
17
- 'ml-auto flex size-chip shrink-0 items-center justify-center rounded-chip text-muted hover:bg-highlight hover:text-fg focus:outline-none',
17
+ 'ml-auto flex tier-chip w-chip shrink-0 items-center justify-center text-muted hover:bg-highlight hover:text-fg focus:outline-none',
18
18
  className
19
19
  )}
20
20
  {...restProps}
@@ -22,7 +22,7 @@
22
22
  <DateRangeField.Segment
23
23
  bind:ref
24
24
  class={cn(
25
- 'era-token-ink h-chip rounded-chip px-[calc(var(--era-sp)/2)] focus:bg-highlight focus:text-bright focus:outline-none aria-[valuetext=Empty]:text-muted data-[segment=literal]:text-muted',
25
+ 'era-token-ink tier-chip px-[calc(var(--era-sp)/2)] focus:bg-highlight focus:text-bright focus:outline-none aria-[valuetext=Empty]:text-muted data-[segment=literal]:text-muted',
26
26
  className
27
27
  )}
28
28
  {...restProps}
@@ -12,7 +12,7 @@
12
12
  <DateRangePicker.Day
13
13
  bind:ref
14
14
  class={cn(
15
- 'inline-flex size-control cursor-default items-center justify-center rounded-control text-body text-fg hover:bg-highlight focus:outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[highlighted]:bg-highlight data-[highlighted]:shadow-highlight data-[outside-month]:pointer-events-none data-[outside-month]:text-muted/40 data-[range-end]:bg-primary data-[range-end]:text-primary-fg data-[range-start]:bg-primary data-[range-start]:text-primary-fg data-[selected]:bg-hover data-[selected]:text-bright data-[unavailable]:text-muted data-[unavailable]:line-through',
15
+ 'inline-flex tier-control w-control cursor-default items-center justify-center text-body text-fg hover:bg-highlight focus:outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[highlighted]:bg-highlight data-[highlighted]:shadow-highlight data-[outside-month]:pointer-events-none data-[outside-month]:text-muted/40 data-[range-end]:bg-primary data-[range-end]:text-primary-fg data-[range-start]:bg-primary data-[range-start]:text-primary-fg data-[selected]:bg-hover data-[selected]:text-bright data-[unavailable]:text-muted data-[unavailable]:line-through',
16
16
  className
17
17
  )}
18
18
  {...restProps}
@@ -22,7 +22,7 @@
22
22
  <DateRangePicker.Segment
23
23
  bind:ref
24
24
  class={cn(
25
- 'era-token-ink h-chip rounded-chip px-[calc(var(--era-sp)/2)] focus:bg-highlight focus:text-bright focus:outline-none aria-[valuetext=Empty]:text-muted data-[segment=literal]:text-muted',
25
+ 'era-token-ink tier-chip px-[calc(var(--era-sp)/2)] focus:bg-highlight focus:text-bright focus:outline-none aria-[valuetext=Empty]:text-muted data-[segment=literal]:text-muted',
26
26
  className
27
27
  )}
28
28
  {...restProps}
@@ -14,7 +14,7 @@
14
14
  <DateRangePicker.Trigger
15
15
  bind:ref
16
16
  class={cn(
17
- 'ml-auto flex size-chip shrink-0 items-center justify-center rounded-chip text-muted hover:bg-highlight hover:text-fg focus:outline-none',
17
+ 'ml-auto flex tier-chip w-chip shrink-0 items-center justify-center text-muted hover:bg-highlight hover:text-fg focus:outline-none',
18
18
  className
19
19
  )}
20
20
  {...restProps}
@@ -48,7 +48,25 @@
48
48
 
49
49
  Sheet.Content already had this exact treatment; Dialog and AlertDialog
50
50
  never got it. 85dvh matches Sheet's, deliberately — one ceiling for every
51
- floating panel, not three opinions.
51
+ MODAL panel, not three opinions.
52
+
53
+ SCOPE, and read this before you delete a max-height of your own: this
54
+ covers Dialog, AlertDialog and Sheet. It does NOT cover the anchored
55
+ surfaces — Popover, DropdownMenu, Select, Combobox, Menubar,
56
+ ContextMenu and Tooltip have no ceiling at all today. If you keep a
57
+ local max-height on one of those, KEEP IT; it is load-bearing, not
58
+ vestigial.
59
+
60
+ This paragraph exists because the sentence above it used to read "every
61
+ floating panel", and a consumer reasoned correctly from it: floating
62
+ panels have ceilings, therefore my Popover's max-height is a redundant
63
+ workaround, therefore delete it. Right there, in the exact place you
64
+ come to decide whether a workaround is still needed, and wrong one
65
+ component over. A principle the library does not implement is worse
66
+ than silence — silence sends you to measure. Carrying the ceiling to
67
+ the anchored surfaces (anchor-aware, via bits-ui's
68
+ --bits-*-content-available-height rather than viewport dvh) is the
69
+ actual fix; until it lands, this says what is true instead.
52
70
 
53
71
  The BODY scrolls, not the panel, so a long form's footer stays put
54
72
  instead of scrolling away with the fields. -->
@@ -22,7 +22,7 @@
22
22
  <DropdownMenu.Trigger
23
23
  bind:ref
24
24
  class={cn(
25
- 'flex h-control w-full items-center justify-between gap-icon-inset-chip rounded-control bg-elevated px-inset-control text-body text-fg shadow-sm focus:bg-highlight focus:outline-none disabled:opacity-50 data-[state=open]:rounded-b-none data-[state=open]:shadow-pressed',
25
+ 'flex tier-control w-full items-center justify-between gap-icon-inset-chip bg-elevated px-inset-control text-body text-fg shadow-sm focus:bg-highlight focus:outline-none disabled:opacity-50 data-[state=open]:rounded-b-none data-[state=open]:shadow-pressed',
26
26
  className
27
27
  )}
28
28
  {...restProps}
@@ -74,7 +74,7 @@
74
74
  data-dragging={dragging || undefined}
75
75
  data-disabled={disabled || undefined}
76
76
  class={cn(
77
- 'flex h-control w-full items-center gap-gutter rounded-control bg-elevated px-inset-control font-mono text-body leading-none text-fg shadow-well transition-colors duration-base focus-within:bg-highlight hover:bg-highlight data-[disabled]:pointer-events-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[dragging]:bg-highlight data-[dragging]:text-bright',
77
+ 'flex tier-control w-full items-center gap-gutter bg-elevated px-inset-control font-mono text-body leading-none text-fg shadow-well transition-colors duration-base focus-within:bg-highlight hover:bg-highlight data-[disabled]:pointer-events-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[dragging]:bg-highlight data-[dragging]:text-bright',
78
78
  className
79
79
  )}
80
80
  ondragenter={onDragEnter}