@signal9/era-ui 9.0.0 → 10.1.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 (78) hide show
  1. package/dist/ai/artifact/artifact-close.svelte +2 -2
  2. package/dist/ai/checkpoint.svelte +1 -1
  3. package/dist/ai/context/context.svelte +1 -1
  4. package/dist/ai/conversation/conversation-scroll-button.svelte +1 -1
  5. package/dist/ai/conversations/conversations-item.svelte +3 -3
  6. package/dist/ai/index.js +1 -1
  7. package/dist/ai/message/message-branch-selector.svelte +2 -2
  8. package/dist/ai/message/message-usage.svelte +1 -1
  9. package/dist/ai/prompt-input/prompt-input-add-attachments.svelte +1 -1
  10. package/dist/ai/prompt-input/prompt-input-attachments.svelte +1 -1
  11. package/dist/ai/prompt-input/prompt-input-submit.svelte +1 -1
  12. package/dist/ai/run-status/run-status.svelte +4 -3
  13. package/dist/ai/suggestion/suggestion.svelte +1 -1
  14. package/dist/ai/swarm/swarm-actions.svelte +2 -2
  15. package/dist/ai/swarm/swarm-agent.svelte +2 -2
  16. package/dist/ai/swarm/swarm-artifact.svelte +1 -1
  17. package/dist/ai/swarm/swarm-barrier.svelte +1 -1
  18. package/dist/ai/swarm/swarm-footer.svelte +3 -2
  19. package/dist/ai/swarm/swarm-header.svelte +1 -1
  20. package/dist/ai/swarm/swarm-node.svelte +1 -1
  21. package/dist/ai/swarm/swarm-role.svelte +5 -2
  22. package/dist/ai/tool/tool-chip.svelte +1 -1
  23. package/dist/ai/web-preview/web-preview.svelte +2 -2
  24. package/dist/apps/index.d.ts +3 -3
  25. package/dist/apps/index.js +3 -3
  26. package/dist/apps/notes/editor/bubble-toolbar.svelte +3 -3
  27. package/dist/apps/notes/editor/slash-menu.svelte +2 -4
  28. package/dist/apps/notes/notes.svelte +12 -12
  29. package/dist/dev/audit/audits/anonymous-text.d.ts +2 -0
  30. package/dist/dev/audit/audits/anonymous-text.js +73 -0
  31. package/dist/dev/audit/audits/index.d.ts +2 -1
  32. package/dist/dev/audit/audits/index.js +3 -1
  33. package/dist/dev/audit/types.d.ts +1 -1
  34. package/dist/docs/css-utilities.js +1 -1
  35. package/dist/docs/llms-txt.js +2 -2
  36. package/dist/docs/notes.md +3 -3
  37. package/dist/era-ui.css +1 -1
  38. package/dist/generated-docs/bar.md +2 -2
  39. package/dist/generated-docs/button.md +1 -1
  40. package/dist/generated-docs/chip.md +1 -1
  41. package/dist/generated-docs/input.md +1 -1
  42. package/dist/generated-docs/llms-full.txt +101 -21
  43. package/dist/generated-docs/llms.txt +11 -7
  44. package/dist/generated-docs/manifest.json +32 -11
  45. package/dist/generated-docs/notes.md +3 -3
  46. package/dist/generated-docs/utilities.json +23 -4
  47. package/dist/generated-docs/utilities.md +82 -6
  48. package/dist/os/notification-center.svelte +1 -1
  49. package/dist/os/pane.svelte +2 -2
  50. package/dist/os/taskbar.svelte +4 -4
  51. package/dist/os/toast.svelte +2 -2
  52. package/dist/styles/index.css +43 -5
  53. package/dist/ui/bar/bar.svelte +13 -13
  54. package/dist/ui/bar/bar.svelte.d.ts +15 -15
  55. package/dist/ui/button/button.svelte +15 -4
  56. package/dist/ui/button/button.svelte.d.ts +1 -1
  57. package/dist/ui/button/index.d.ts +1 -1
  58. package/dist/ui/button/variants.d.ts +10 -13
  59. package/dist/ui/button/variants.js +13 -15
  60. package/dist/ui/chip/chip.svelte +25 -15
  61. package/dist/ui/chip/chip.svelte.d.ts +8 -8
  62. package/dist/ui/command/command-item.svelte +1 -1
  63. package/dist/ui/command/command-link-item.svelte +1 -1
  64. package/dist/ui/command-bar/command-bar.svelte +1 -1
  65. package/dist/ui/copy-button/copy-button.svelte +1 -1
  66. package/dist/ui/dialog/dialog-header.svelte +7 -2
  67. package/dist/ui/index.js +1 -1
  68. package/dist/ui/input/input.svelte +3 -3
  69. package/dist/ui/input/input.svelte.d.ts +1 -1
  70. package/dist/ui/input/variants.d.ts +6 -6
  71. package/dist/ui/input/variants.js +3 -3
  72. package/dist/ui/kv/kv.svelte +1 -1
  73. package/dist/ui/pane/pane-close.svelte +2 -2
  74. package/dist/ui/pane/pane-handle.svelte +3 -3
  75. package/dist/ui/select/select-trigger.svelte +1 -1
  76. package/dist/ui/select/select-value.svelte +1 -1
  77. package/dist/ui/step/step-summary.svelte +1 -1
  78. package/package.json +1 -1
@@ -234,7 +234,7 @@
234
234
  {#if pinned.length}
235
235
  <div class="flex shrink-0 items-center gap-(--era-gap)">
236
236
  {#each pinned as p (p.appId)}
237
- <Button icon size="default" aria-label={p.title} onclick={() => pm.open(p.appId)}>
237
+ <Button icon size="control" aria-label={p.title} onclick={() => pm.open(p.appId)}>
238
238
  {#if p.icon}{@const Icon = p.icon}<Icon class="size-(--era-h-icon)" />{/if}
239
239
  </Button>
240
240
  {/each}
@@ -288,7 +288,7 @@
288
288
  {#each pm.workspaces as ws, i (ws.id)}
289
289
  <Button
290
290
  icon
291
- size="default"
291
+ size="control"
292
292
  active={pm.activeWorkspaceId === ws.id}
293
293
  title={ws.name}
294
294
  aria-label="Switch to workspace {i + 1} ({ws.name})"
@@ -308,7 +308,7 @@
308
308
  consumers' own affordances). -->
309
309
  {#if notif.unread > 0}
310
310
  <div class="relative">
311
- <Button icon size="default" aria-label="Notifications" onclick={onNotifications}>
311
+ <Button icon size="control" aria-label="Notifications" onclick={onNotifications}>
312
312
  <Bell class="size-(--era-h-icon)" />
313
313
  </Button>
314
314
  <span
@@ -347,7 +347,7 @@
347
347
  add rounded-full — a circle is not era's button language. -->
348
348
  <Button
349
349
  icon
350
- size="default"
350
+ size="control"
351
351
  tone="accent"
352
352
  aria-label="Open command bar"
353
353
  class="shadow-(--era-shadow-lg)"
@@ -36,7 +36,7 @@
36
36
  variant's [&_svg] selector and never applied). -->
37
37
  <Button
38
38
  icon
39
- size="xxs"
39
+ size="pill"
40
40
  aria-label="Dismiss"
41
41
  class="-mt-1 -mr-1 shrink-0"
42
42
  onclick={() => notif.dismiss(n.id)}
@@ -49,7 +49,7 @@
49
49
  <div class="mt-(--era-inset-chip) flex flex-wrap gap-(--era-gap)">
50
50
  {#each n.actions as action (action.label)}
51
51
  <Button
52
- size="xs"
52
+ size="icon"
53
53
  tone={n.tone === 'default' ? 'default' : n.tone}
54
54
  onclick={() => {
55
55
  action.onClick();
@@ -227,7 +227,9 @@
227
227
  * the pair so the runtime audit can point at it). It exists so the failure mode
228
228
  * is a no-op instead of unreadable text. */
229
229
  .era-text-trim.truncate,
230
- .era-text-trim-caps.truncate {
230
+ .era-text-trim-caps.truncate,
231
+ .era-label-ink.truncate,
232
+ .era-token-ink.truncate {
231
233
  line-height: normal;
232
234
  text-box: normal;
233
235
  }
@@ -271,6 +273,10 @@
271
273
  *
272
274
  * @use on a native single-line <input> (or the text layer that must mirror
273
275
  * one) inside a fixed-height field — never alongside era-text-trim. */
276
+ @utility era-ink-center {
277
+ padding-bottom: 0.08em;
278
+ }
279
+
274
280
  /* TOKEN INK — the ink centring for a pill whose content is a TOKEN: an id, a
275
281
  * count, a status, a tag. Font-independent, unlike everything it replaces.
276
282
  *
@@ -299,8 +305,9 @@
299
305
  * Prose and sentence-case labels keep era-text-trim; this is for tokens.
300
306
  *
301
307
  * @use the ink centring for a token pill — a badge, a KV value, any short
302
- * caps-or-digits label in a fixed-height box; it needs no icon sibling (with
303
- * one the box must stay flex, and the general trim applies). */
308
+ * caps-or-digits label in a fixed-height box, CENTRED horizontally and with no
309
+ * icon sibling. For a left-aligned sentence-case label use era-label-ink; when
310
+ * an icon really must sit beside the text, see the note there. */
304
311
  @utility era-token-ink {
305
312
  display: block;
306
313
  align-content: center;
@@ -309,8 +316,39 @@
309
316
  text-box: trim-both cap alphabetic;
310
317
  }
311
318
 
312
- @utility era-ink-center {
313
- padding-bottom: 0.08em;
319
+ /* LABEL INK — era-token-ink's mixed-case sibling, and the general answer to
320
+ * "this fixed-height control holds one line of text".
321
+ *
322
+ * Same mechanism, same reason: `text-box-trim` needs a BLOCK box, so the row
323
+ * becomes one and `align-content` (block-container alignment) does the
324
+ * centring. What differs is the band and the alignment, because the content
325
+ * class differs — a label is sentence case, so the x-height band is the visual
326
+ * mass to centre (cap-band reads low on "System"), and it is laid out against
327
+ * the row's padding rather than centred in it.
328
+ *
329
+ * WHY IT EXISTS AT ALL: era's controls are flex, and a flex container's bare
330
+ * text is an ANONYMOUS flex item — a box no selector reaches and no
331
+ * non-inherited property touches. So `era-text-trim` on a flex row is inert,
332
+ * contributing only its `line-height: 1`, and the ink falls back to line-box
333
+ * centring by font metrics. era-token-ink already fixed that for centred
334
+ * tokens; this fixes it for everything else.
335
+ *
336
+ * THE ICON CASE IS NOT SOLVED, and cannot be from CSS: an icon beside the text
337
+ * needs the box to stay flex, which re-creates the anonymous item. A component
338
+ * whose children are an opaque slot therefore guards it —
339
+ * `not-has-[svg]:era-label-ink` — and ink-centres the text-only case while
340
+ * leaving the icon case on line-box centring. Splitting icon and label into
341
+ * separate slots is what would close it; typography/inert-trim reports every
342
+ * site still on the fallback.
343
+ *
344
+ * @use the ink centring for a fixed-height control holding ONE line of
345
+ * sentence-case text and no icon — a menu item, a nav trigger, a button label.
346
+ * Never alongside `truncate` (the trimmed box becomes the clip). */
347
+ @utility era-label-ink {
348
+ display: block;
349
+ align-content: center;
350
+ line-height: 1;
351
+ text-box: trim-both ex alphabetic;
314
352
  }
315
353
 
316
354
  /* In-progress text shimmer — a bright sweep through muted text (the standard
@@ -10,12 +10,12 @@
10
10
  // Radius stays concentric to the height; gap/px are sp/2 (xs-inset-sm),
11
11
  // the even gap for one-tier-smaller content at every size.
12
12
  export const barVariants = tv({
13
- base: 'flex items-center era-text-trim',
13
+ base: 'flex items-center leading-none',
14
14
  variants: {
15
15
  size: {
16
- sm: 'h-(--era-h-chip) rounded-(--era-rd-chip)',
17
- md: 'h-(--era-h-control) rounded-(--era-rd-control)',
18
- lg: 'h-(--era-h-bar) rounded-(--era-rd-bar)'
16
+ chip: 'h-(--era-h-chip) rounded-(--era-rd-chip)',
17
+ control: 'h-(--era-h-control) rounded-(--era-rd-control)',
18
+ bar: 'h-(--era-h-bar) rounded-(--era-rd-bar)'
19
19
  },
20
20
  /**
21
21
  * The tier of the CONTROLS inside, because that is what the bar's own
@@ -33,7 +33,7 @@
33
33
  */
34
34
  content: {
35
35
  tier: 'gap-(--era-icon-inset-chip) px-(--era-icon-inset-chip)',
36
- xxs: ''
36
+ pill: ''
37
37
  },
38
38
  /**
39
39
  * The flush header bar capping a panel — Pane.Handle, Dialog.Header,
@@ -61,8 +61,8 @@
61
61
  compoundVariants: [
62
62
  // control ⊃ pill = (3sp − sp − 10)/2 — the named token.
63
63
  {
64
- size: 'md',
65
- content: 'xxs',
64
+ size: 'control',
65
+ content: 'pill',
66
66
  class: 'gap-(--era-pill-inset-control) px-(--era-pill-inset-control)'
67
67
  },
68
68
  // chip ⊃ pill — its own token, not the text inset it used to borrow. The two
@@ -70,12 +70,12 @@
70
70
  // 12px broke the tie and left this pairing a pixel wide. (bar ⊃ pill has no
71
71
  // token because nothing pairs a page header with pill-tier controls.)
72
72
  {
73
- size: 'sm',
74
- content: 'xxs',
73
+ size: 'chip',
74
+ content: 'pill',
75
75
  class: 'gap-(--era-pill-inset-chip) px-(--era-pill-inset-chip)'
76
76
  }
77
77
  ],
78
- defaultVariants: { size: 'lg', content: 'tier', divider: false }
78
+ defaultVariants: { size: 'bar', content: 'tier', divider: false }
79
79
  });
80
80
  </script>
81
81
 
@@ -85,7 +85,7 @@
85
85
 
86
86
  let {
87
87
  ref = $bindable(null),
88
- size = 'lg',
88
+ size = 'bar',
89
89
  content = 'tier',
90
90
  divider = false,
91
91
  children,
@@ -94,13 +94,13 @@
94
94
  }: HTMLAttributes<HTMLDivElement> & {
95
95
  ref?: HTMLDivElement | null;
96
96
  /** Height tier (scales with density). Default `lg` — a full toolbar. */
97
- size?: 'sm' | 'md' | 'lg';
97
+ size?: 'chip' | 'control' | 'bar';
98
98
  /**
99
99
  * Tier of the controls inside — drives the bar's padding and gap so they
100
100
  * stay concentric to them. `tier` (default) is one tier smaller; `pill` is
101
101
  * the compact pairing (pills/fields in an sm or md bar).
102
102
  */
103
- content?: 'tier' | 'xxs';
103
+ content?: 'tier' | 'pill';
104
104
  /** The flush cap-a-panel chrome: outset divider below, bottom rd-md. */
105
105
  divider?: boolean;
106
106
  children?: Snippet;
@@ -1,8 +1,8 @@
1
1
  export declare const barVariants: import("tailwind-variants").TVReturnType<{
2
2
  size: {
3
- sm: "h-(--era-h-chip) rounded-(--era-rd-chip)";
4
- md: "h-(--era-h-control) rounded-(--era-rd-control)";
5
- lg: "h-(--era-h-bar) rounded-(--era-rd-bar)";
3
+ chip: "h-(--era-h-chip) rounded-(--era-rd-chip)";
4
+ control: "h-(--era-h-control) rounded-(--era-rd-control)";
5
+ bar: "h-(--era-h-bar) rounded-(--era-rd-bar)";
6
6
  };
7
7
  /**
8
8
  * The tier of the CONTROLS inside, because that is what the bar's own
@@ -20,7 +20,7 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
20
20
  */
21
21
  content: {
22
22
  tier: "gap-(--era-icon-inset-chip) px-(--era-icon-inset-chip)";
23
- xxs: "";
23
+ pill: "";
24
24
  };
25
25
  /**
26
26
  * The flush header bar capping a panel — Pane.Handle, Dialog.Header,
@@ -44,11 +44,11 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
44
44
  true: "shrink-0 rounded-t-none rounded-b-(--era-rd-control) [box-shadow:0_1px_0_var(--color-divider-faded)]";
45
45
  false: "";
46
46
  };
47
- }, undefined, "flex items-center era-text-trim", {
47
+ }, undefined, "flex items-center leading-none", {
48
48
  size: {
49
- sm: "h-(--era-h-chip) rounded-(--era-rd-chip)";
50
- md: "h-(--era-h-control) rounded-(--era-rd-control)";
51
- lg: "h-(--era-h-bar) rounded-(--era-rd-bar)";
49
+ chip: "h-(--era-h-chip) rounded-(--era-rd-chip)";
50
+ control: "h-(--era-h-control) rounded-(--era-rd-control)";
51
+ bar: "h-(--era-h-bar) rounded-(--era-rd-bar)";
52
52
  };
53
53
  /**
54
54
  * The tier of the CONTROLS inside, because that is what the bar's own
@@ -66,7 +66,7 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
66
66
  */
67
67
  content: {
68
68
  tier: "gap-(--era-icon-inset-chip) px-(--era-icon-inset-chip)";
69
- xxs: "";
69
+ pill: "";
70
70
  };
71
71
  /**
72
72
  * The flush header bar capping a panel — Pane.Handle, Dialog.Header,
@@ -92,9 +92,9 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
92
92
  };
93
93
  }, undefined, import("tailwind-variants").TVReturnTypeLike<{
94
94
  size: {
95
- sm: "h-(--era-h-chip) rounded-(--era-rd-chip)";
96
- md: "h-(--era-h-control) rounded-(--era-rd-control)";
97
- lg: "h-(--era-h-bar) rounded-(--era-rd-bar)";
95
+ chip: "h-(--era-h-chip) rounded-(--era-rd-chip)";
96
+ control: "h-(--era-h-control) rounded-(--era-rd-control)";
97
+ bar: "h-(--era-h-bar) rounded-(--era-rd-bar)";
98
98
  };
99
99
  /**
100
100
  * The tier of the CONTROLS inside, because that is what the bar's own
@@ -112,7 +112,7 @@ export declare const barVariants: import("tailwind-variants").TVReturnType<{
112
112
  */
113
113
  content: {
114
114
  tier: "gap-(--era-icon-inset-chip) px-(--era-icon-inset-chip)";
115
- xxs: "";
115
+ pill: "";
116
116
  };
117
117
  /**
118
118
  * The flush header bar capping a panel — Pane.Handle, Dialog.Header,
@@ -142,13 +142,13 @@ import type { Snippet } from 'svelte';
142
142
  type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
143
143
  ref?: HTMLDivElement | null;
144
144
  /** Height tier (scales with density). Default `lg` — a full toolbar. */
145
- size?: 'sm' | 'md' | 'lg';
145
+ size?: 'chip' | 'control' | 'bar';
146
146
  /**
147
147
  * Tier of the controls inside — drives the bar's padding and gap so they
148
148
  * stay concentric to them. `tier` (default) is one tier smaller; `pill` is
149
149
  * the compact pairing (pills/fields in an sm or md bar).
150
150
  */
151
- content?: 'tier' | 'xxs';
151
+ content?: 'tier' | 'pill';
152
152
  /** The flush cap-a-panel chrome: outset divider below, bottom rd-md. */
153
153
  divider?: boolean;
154
154
  children?: Snippet;
@@ -8,7 +8,7 @@
8
8
  let {
9
9
  ref = $bindable(null),
10
10
  tone = 'default',
11
- size = 'default',
11
+ size = 'control',
12
12
  variant = 'filled',
13
13
  active = false,
14
14
  icon = false,
@@ -20,7 +20,7 @@
20
20
  ...restProps
21
21
  }: Button.RootProps & {
22
22
  tone?: 'default' | 'accent' | 'destructive' | 'success' | 'warning';
23
- size?: 'default' | 'sm' | 'xxs' | 'xs' | 'icon';
23
+ size?: 'control' | 'chip' | 'pill' | 'icon';
24
24
  variant?: 'filled' | 'link';
25
25
  active?: boolean;
26
26
  icon?: boolean;
@@ -50,7 +50,7 @@
50
50
  `size` is exposed for the same reason: bevel sinks a pressed icon by a fixed
51
51
  1px, which is ~4% of a default button but ~7% of a 14px icon button, so the
52
52
  smallest tier reads as over-travelling. The surface halves the sink for
53
- size="xs"/"icon" (see bevel.css), and it can only do that if the size is on the
53
+ size="icon"/"icon" (see bevel.css), and it can only do that if the size is on the
54
54
  DOM. Geometry lives in tv() compound classes, which CSS cannot query.
55
55
  -->
56
56
  <Button.Root
@@ -70,7 +70,18 @@
70
70
  and they separated on press. Wrapping unifies them, and `gap: inherit`
71
71
  forwards the button's own gap so the icon/label spacing is unchanged.
72
72
  -->
73
- <span data-button-content class="inline-flex items-center justify-center [gap:inherit]">
73
+ <!--
74
+ not-has-[svg]:era-label-ink — a text-only button ink-centres its label.
75
+ The span is otherwise a flex box, and a flex box's bare text is an
76
+ ANONYMOUS item that `text-box-trim` can never reach, so the label fell back
77
+ to line-box centring by font metrics (the bug era-label-ink documents).
78
+ With an icon present the box must stay flex for the gap, and that case is
79
+ still on the fallback — typography/inert-trim reports it.
80
+ -->
81
+ <span
82
+ data-button-content
83
+ class="inline-flex items-center justify-center [gap:inherit] not-has-[svg]:era-label-ink"
84
+ >
74
85
  {#if loading}
75
86
  <LoaderCircle class="size-(--era-h-icon) shrink-0 animate-spin" aria-hidden="true" />
76
87
  {#if loadingLabel}<span class="sr-only">{loadingLabel}</span>{/if}
@@ -2,7 +2,7 @@ import type { Snippet } from 'svelte';
2
2
  import { Button } from 'bits-ui';
3
3
  type $$ComponentProps = Button.RootProps & {
4
4
  tone?: 'default' | 'accent' | 'destructive' | 'success' | 'warning';
5
- size?: 'default' | 'sm' | 'xxs' | 'xs' | 'icon';
5
+ size?: 'control' | 'chip' | 'pill' | 'icon';
6
6
  variant?: 'filled' | 'link';
7
7
  active?: boolean;
8
8
  icon?: boolean;
@@ -3,7 +3,7 @@ export { Button };
3
3
  export { buttonVariants } from './variants.js';
4
4
  export interface ButtonVariants {
5
5
  tone?: 'default' | 'accent' | 'destructive' | 'success' | 'warning';
6
- size?: 'default' | 'sm' | 'xxs' | 'xs' | 'icon';
6
+ size?: 'control' | 'chip' | 'pill' | 'icon';
7
7
  variant?: 'filled' | 'link';
8
8
  icon?: boolean;
9
9
  active?: boolean;
@@ -11,10 +11,9 @@ export declare const buttonVariants: import("tailwind-variants").TVReturnType<{
11
11
  warning: "";
12
12
  };
13
13
  size: {
14
- default: "";
15
- sm: "";
16
- xxs: "";
17
- xs: "";
14
+ control: "";
15
+ chip: "";
16
+ pill: "";
18
17
  icon: "";
19
18
  };
20
19
  icon: {
@@ -23,7 +22,7 @@ export declare const buttonVariants: import("tailwind-variants").TVReturnType<{
23
22
  active: {
24
23
  true: "";
25
24
  };
26
- }, undefined, "items-center gap-(--era-gap) text-body era-interactive era-text-trim", {
25
+ }, undefined, "items-center gap-(--era-gap) text-body era-interactive leading-none", {
27
26
  variant: {
28
27
  filled: "flex justify-center shadow-(--era-shadow) hover:shadow-(--era-highlight-shadow) active:shadow-(--era-shadow-pressed) [&:active>*]:translate-x-(--era-press-sink-x) [&:active>*]:translate-y-(--era-press-sink-y)";
29
28
  link: "inline-flex underline-offset-2 hover:underline";
@@ -36,10 +35,9 @@ export declare const buttonVariants: import("tailwind-variants").TVReturnType<{
36
35
  warning: "";
37
36
  };
38
37
  size: {
39
- default: "";
40
- sm: "";
41
- xxs: "";
42
- xs: "";
38
+ control: "";
39
+ chip: "";
40
+ pill: "";
43
41
  icon: "";
44
42
  };
45
43
  icon: {
@@ -61,10 +59,9 @@ export declare const buttonVariants: import("tailwind-variants").TVReturnType<{
61
59
  warning: "";
62
60
  };
63
61
  size: {
64
- default: "";
65
- sm: "";
66
- xxs: "";
67
- xs: "";
62
+ control: "";
63
+ chip: "";
64
+ pill: "";
68
65
  icon: "";
69
66
  };
70
67
  icon: {
@@ -3,7 +3,7 @@ import { tv } from '../../utils/index.js';
3
3
  // entirely, so all geometry lives on filled compound variants rather than a
4
4
  // plain size variant.
5
5
  export const buttonVariants = tv({
6
- base: 'items-center gap-(--era-gap) text-body era-interactive era-text-trim',
6
+ base: 'items-center gap-(--era-gap) text-body era-interactive leading-none',
7
7
  variants: {
8
8
  variant: {
9
9
  // The active: press treatment is inert outside the bevel surface —
@@ -16,7 +16,7 @@ export const buttonVariants = tv({
16
16
  link: 'inline-flex underline-offset-2 hover:underline'
17
17
  },
18
18
  tone: { default: '', accent: '', destructive: '', success: '', warning: '' },
19
- size: { default: '', sm: '', xxs: '', xs: '', icon: '' },
19
+ size: { control: '', chip: '', pill: '', icon: '' },
20
20
  icon: { true: '' },
21
21
  active: { true: '' }
22
22
  },
@@ -24,22 +24,22 @@ export const buttonVariants = tv({
24
24
  // filled geometry
25
25
  {
26
26
  variant: 'filled',
27
- size: 'default',
27
+ size: 'control',
28
28
  class: 'h-(--era-h-control) min-w-(--era-h-control) rounded-(--era-rd-control)'
29
29
  },
30
30
  {
31
31
  variant: 'filled',
32
- size: 'sm',
32
+ size: 'chip',
33
33
  class: 'h-(--era-h-chip) min-w-(--era-h-chip) rounded-(--era-rd-chip)'
34
34
  },
35
35
  {
36
36
  variant: 'filled',
37
- size: 'xxs',
37
+ size: 'pill',
38
38
  class: 'h-(--era-h-pill) min-w-(--era-h-pill) rounded-(--era-rd-pill)'
39
39
  },
40
40
  {
41
41
  variant: 'filled',
42
- size: 'xs',
42
+ size: 'icon',
43
43
  class: 'h-(--era-h-icon) min-w-(--era-h-icon) rounded-(--era-rd-icon)'
44
44
  },
45
45
  {
@@ -52,17 +52,16 @@ export const buttonVariants = tv({
52
52
  {
53
53
  variant: 'filled',
54
54
  icon: false,
55
- size: 'default',
55
+ size: 'control',
56
56
  class: 'px-(--era-inset-control) has-[svg]:gap-(--era-inset-control)'
57
57
  },
58
58
  {
59
59
  variant: 'filled',
60
60
  icon: false,
61
- size: 'sm',
61
+ size: 'chip',
62
62
  class: 'px-(--era-inset-chip) has-[svg]:gap-(--era-inset-chip)'
63
63
  },
64
- { variant: 'filled', icon: false, size: 'xxs', class: 'px-(--era-pill-px)' },
65
- { variant: 'filled', icon: false, size: 'xs', class: 'px-(--era-gap)' },
64
+ { variant: 'filled', icon: false, size: 'pill', class: 'px-(--era-pill-px)' },
66
65
  { variant: 'filled', icon: false, size: 'icon', class: 'px-(--era-gap)' },
67
66
  { variant: 'filled', icon: true, class: 'aspect-square px-0' },
68
67
  // Icon glyph sizing. The glyph is the icon tier (h-icon) at default/sm —
@@ -78,10 +77,9 @@ export const buttonVariants = tv({
78
77
  // notes "new note" button rendered a 24px glyph in a 24px box — flush,
79
78
  // no padding at all. Stating them makes the documented intent real and
80
79
  // removes the dependency on every call site remembering.
81
- { icon: true, size: 'default', class: '[&_svg]:size-(--era-h-icon)' },
82
- { icon: true, size: 'sm', class: '[&_svg]:size-(--era-h-icon)' },
83
- { icon: true, size: 'xxs', class: '[&_svg]:size-(--era-glyph-pill)' },
84
- { icon: true, size: 'xs', class: '[&_svg]:size-(--era-glyph-icon)' },
80
+ { icon: true, size: 'control', class: '[&_svg]:size-(--era-h-icon)' },
81
+ { icon: true, size: 'chip', class: '[&_svg]:size-(--era-h-icon)' },
82
+ { icon: true, size: 'pill', class: '[&_svg]:size-(--era-glyph-pill)' },
85
83
  { icon: true, size: 'icon', class: '[&_svg]:size-(--era-glyph-icon)' },
86
84
  // filled tones
87
85
  {
@@ -123,7 +121,7 @@ export const buttonVariants = tv({
123
121
  defaultVariants: {
124
122
  variant: 'filled',
125
123
  tone: 'default',
126
- size: 'default',
124
+ size: 'control',
127
125
  icon: false,
128
126
  active: false
129
127
  }
@@ -13,39 +13,49 @@
13
13
  export const chipVariants = tv({
14
14
  // shrink-0 + nowrap for the same reason Badge carries them: the pill is
15
15
  // already exactly its text's size, so any squeeze puts ink outside the fill.
16
- base: 'inline-flex shrink-0 items-center bg-fill font-mono text-body leading-none whitespace-nowrap text-fg shadow-(--era-shadow) era-text-trim',
16
+ base: 'inline-flex shrink-0 items-center bg-fill font-mono text-body leading-none whitespace-nowrap text-fg shadow-(--era-shadow)',
17
17
  variants: {
18
18
  size: {
19
- sm: 'h-(--era-h-chip) min-w-(--era-h-chip) rounded-(--era-rd-chip) pl-(--era-chip-px)',
20
- xxs: 'h-(--era-h-pill) min-w-(--era-h-pill) rounded-(--era-rd-pill) pl-(--era-pill-px)'
19
+ chip: 'h-(--era-h-chip) min-w-(--era-h-chip) rounded-(--era-rd-chip) pl-(--era-chip-px)',
20
+ pill: 'h-(--era-h-pill) min-w-(--era-h-pill) rounded-(--era-rd-pill) pl-(--era-pill-px)'
21
21
  },
22
22
  dismissible: { true: '', false: '' }
23
23
  },
24
24
  compoundVariants: [
25
25
  // Text-only: symmetric pill padding, inter-element gap for a lead icon.
26
- { size: 'sm', dismissible: false, class: 'gap-(--era-gap) pr-(--era-chip-px)' },
27
- { size: 'xxs', dismissible: false, class: 'gap-(--era-gap) pr-(--era-pill-px)' },
26
+ {
27
+ size: 'chip',
28
+ dismissible: false,
29
+ class:
30
+ 'gap-(--era-gap) pr-(--era-chip-px) not-has-[svg]:era-label-ink not-has-[svg]:text-center'
31
+ },
32
+ {
33
+ size: 'pill',
34
+ dismissible: false,
35
+ class:
36
+ 'gap-(--era-gap) pr-(--era-pill-px) not-has-[svg]:era-label-ink not-has-[svg]:text-center'
37
+ },
28
38
  // Dismissible, two geometries because the two tiers afford different ones:
29
39
  //
30
- // sm — the xxs-tier button NESTS, with its concentric gap mirrored as
40
+ // chip — the pill-tier button NESTS, with its concentric gap mirrored as
31
41
  // the right padding (--era-pill-inset-chip). 18px of hit target, and
32
42
  // since the dismiss glyph is 12px in every box, the ink sits where
33
43
  // the old 14px button put it — (h − glyph)/2 telescopes.
34
- // xxs — nesting has run out of road: density.css's own note says xxs
44
+ // pill — nesting has run out of road: density.css's own note says xxs
35
45
  // "is sized around text, not as a container", and the best a
36
46
  // nested button managed here was 1px of pad. So the dismiss is a
37
47
  // flush END-CAP instead — a full-height segment of the pill
38
48
  // (pr-0; the button supplies the right edge). Flush means offset
39
49
  // zero, and at offset zero concentric radius = the chip's own, so
40
- // the cap shares rd-xxs exactly rather than approximating it.
50
+ // the cap shares rd-pill exactly rather than approximating it.
41
51
  {
42
- size: 'sm',
52
+ size: 'chip',
43
53
  dismissible: true,
44
54
  class: 'gap-(--era-pill-inset-chip) pr-(--era-pill-inset-chip)'
45
55
  },
46
- { size: 'xxs', dismissible: true, class: 'gap-(--era-icon-inset-pill) pr-0' }
56
+ { size: 'pill', dismissible: true, class: 'gap-(--era-icon-inset-pill) pr-0' }
47
57
  ],
48
- defaultVariants: { size: 'sm', dismissible: false }
58
+ defaultVariants: { size: 'chip', dismissible: false }
49
59
  });
50
60
  </script>
51
61
 
@@ -58,7 +68,7 @@
58
68
 
59
69
  let {
60
70
  ref = $bindable(null),
61
- size = 'sm',
71
+ size = 'chip',
62
72
  ondismiss,
63
73
  children,
64
74
  class: className,
@@ -67,7 +77,7 @@
67
77
  ref?: HTMLDivElement | null;
68
78
  /** `sm` (default) is the standalone free chip; `pill` is the smaller pill
69
79
  * that nests inside an md container (a select trigger, a button). */
70
- size?: 'sm' | 'xxs';
80
+ size?: 'chip' | 'pill';
71
81
  ondismiss?: () => void;
72
82
  children?: Snippet;
73
83
  } = $props();
@@ -93,9 +103,9 @@
93
103
  what reads as "segment of this pill" rather than "pill on a pill". -->
94
104
  <Button
95
105
  icon
96
- size="xxs"
106
+ size="pill"
97
107
  tone="destructive"
98
- class={size === 'xxs' ? 'rounded-l-none' : undefined}
108
+ class={size === 'pill' ? 'rounded-l-none' : undefined}
99
109
  onclick={ondismiss}
100
110
  onpointerdown={(e: PointerEvent) => e.stopPropagation()}
101
111
  onpointerup={(e: PointerEvent) => e.stopPropagation()}
@@ -1,16 +1,16 @@
1
1
  export declare const chipVariants: import("tailwind-variants").TVReturnType<{
2
2
  size: {
3
- sm: "h-(--era-h-chip) min-w-(--era-h-chip) rounded-(--era-rd-chip) pl-(--era-chip-px)";
4
- xxs: "h-(--era-h-pill) min-w-(--era-h-pill) rounded-(--era-rd-pill) pl-(--era-pill-px)";
3
+ chip: "h-(--era-h-chip) min-w-(--era-h-chip) rounded-(--era-rd-chip) pl-(--era-chip-px)";
4
+ pill: "h-(--era-h-pill) min-w-(--era-h-pill) rounded-(--era-rd-pill) pl-(--era-pill-px)";
5
5
  };
6
6
  dismissible: {
7
7
  true: "";
8
8
  false: "";
9
9
  };
10
- }, undefined, "inline-flex shrink-0 items-center bg-fill font-mono text-body leading-none whitespace-nowrap text-fg shadow-(--era-shadow) era-text-trim", {
10
+ }, undefined, "inline-flex shrink-0 items-center bg-fill font-mono text-body leading-none whitespace-nowrap text-fg shadow-(--era-shadow)", {
11
11
  size: {
12
- sm: "h-(--era-h-chip) min-w-(--era-h-chip) rounded-(--era-rd-chip) pl-(--era-chip-px)";
13
- xxs: "h-(--era-h-pill) min-w-(--era-h-pill) rounded-(--era-rd-pill) pl-(--era-pill-px)";
12
+ chip: "h-(--era-h-chip) min-w-(--era-h-chip) rounded-(--era-rd-chip) pl-(--era-chip-px)";
13
+ pill: "h-(--era-h-pill) min-w-(--era-h-pill) rounded-(--era-rd-pill) pl-(--era-pill-px)";
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
- sm: "h-(--era-h-chip) min-w-(--era-h-chip) rounded-(--era-rd-chip) pl-(--era-chip-px)";
22
- xxs: "h-(--era-h-pill) min-w-(--era-h-pill) rounded-(--era-rd-pill) pl-(--era-pill-px)";
21
+ chip: "h-(--era-h-chip) min-w-(--era-h-chip) rounded-(--era-rd-chip) pl-(--era-chip-px)";
22
+ pill: "h-(--era-h-pill) min-w-(--era-h-pill) rounded-(--era-rd-pill) pl-(--era-pill-px)";
23
23
  };
24
24
  dismissible: {
25
25
  true: "";
@@ -32,7 +32,7 @@ type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
32
32
  ref?: HTMLDivElement | null;
33
33
  /** `sm` (default) is the standalone free chip; `pill` is the smaller pill
34
34
  * that nests inside an md container (a select trigger, a button). */
35
- size?: 'sm' | 'xxs';
35
+ size?: 'chip' | 'pill';
36
36
  ondismiss?: () => void;
37
37
  children?: Snippet;
38
38
  };
@@ -8,7 +8,7 @@
8
8
  <Command.Item
9
9
  bind:ref
10
10
  class={cn(
11
- 'flex h-(--era-h-control) cursor-pointer items-center gap-(--era-gap) rounded-(--era-rd-control) px-(--era-inset-control) text-body era-text-trim text-fg outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[selected]:bg-(--era-highlight)',
11
+ 'flex h-(--era-h-control) cursor-pointer items-center gap-(--era-gap) rounded-(--era-rd-control) px-(--era-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-(--era-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-(--era-h-control) cursor-pointer items-center gap-(--era-gap) rounded-(--era-rd-control) px-(--era-inset-control) text-body era-text-trim text-fg no-underline outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[selected]:bg-(--era-highlight)',
11
+ 'flex h-(--era-h-control) cursor-pointer items-center gap-(--era-gap) rounded-(--era-rd-control) px-(--era-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-(--era-highlight)',
12
12
  className
13
13
  )}
14
14
  {...restProps}