@reliability-design/web 1.4.7 → 1.4.9

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 (48) hide show
  1. package/CHANGELOG.md +98 -2
  2. package/dist/components/rel-accordion/README.md +2 -1
  3. package/dist/components/rel-alert/README.md +1 -1
  4. package/dist/components/rel-autocomplete/README.md +22 -5
  5. package/dist/components/rel-avatar/README.md +9 -7
  6. package/dist/components/rel-badge/README.md +4 -5
  7. package/dist/components/rel-button/README.md +32 -2
  8. package/dist/components/rel-card/README.md +3 -3
  9. package/dist/components/rel-carousel/README.md +3 -0
  10. package/dist/components/rel-checkbox/README.md +8 -4
  11. package/dist/components/rel-chip/README.md +13 -7
  12. package/dist/components/rel-container/README.md +8 -8
  13. package/dist/components/rel-date-picker/README.md +8 -2
  14. package/dist/components/rel-divider/README.md +11 -1
  15. package/dist/components/rel-kbd/README.md +2 -2
  16. package/dist/components/rel-layout/README.md +34 -0
  17. package/dist/components/rel-menu/README.md +3 -1
  18. package/dist/components/rel-menubar/README.md +1 -1
  19. package/dist/components/rel-otp/README.md +4 -3
  20. package/dist/components/rel-pagination/README.md +2 -2
  21. package/dist/components/rel-popover/README.md +5 -5
  22. package/dist/components/rel-progress/README.md +3 -3
  23. package/dist/components/rel-radio/README.md +1 -1
  24. package/dist/components/rel-range-picker/README.md +11 -2
  25. package/dist/components/rel-segmented-button/README.md +7 -5
  26. package/dist/components/rel-select/README.md +11 -6
  27. package/dist/components/rel-sheet/README.md +3 -3
  28. package/dist/components/rel-skeleton/README.md +5 -4
  29. package/dist/components/rel-slider/README.md +3 -2
  30. package/dist/components/rel-snackbar/README.md +13 -7
  31. package/dist/components/rel-stepper/README.md +23 -10
  32. package/dist/components/rel-switch/README.md +16 -7
  33. package/dist/components/rel-tab/README.md +5 -2
  34. package/dist/components/rel-textfield/README.md +19 -2
  35. package/dist/components/rel-time-picker/README.md +6 -0
  36. package/dist/components/rel-toast/README.md +14 -6
  37. package/dist/components/rel-tooltip/README.md +13 -2
  38. package/dist/components/rel-upload/README.md +2 -2
  39. package/dist/index.d.mts +825 -240
  40. package/dist/index.d.ts +825 -240
  41. package/dist/index.js +8617 -5213
  42. package/dist/index.js.map +1 -1
  43. package/dist/index.mjs +8424 -5020
  44. package/dist/index.mjs.map +1 -1
  45. package/dist/styles/focus-ring.ts +84 -0
  46. package/dist/styles/vars.css +75 -60
  47. package/dist/{vars-JHTUGNRG.css → vars-DXX6QOAG.css} +75 -60
  48. package/package.json +1 -1
@@ -51,11 +51,11 @@ Loading placeholder that reserves the space of content still being fetched: a ne
51
51
 
52
52
  | Property | Attribute | Type | Default | Description |
53
53
  | --- | --- | --- | --- | --- |
54
- | `shape` | `shape` | `"line" \| "circle" \| "block"` | `"block"` | Placeholder shape: `block` fills the host (min 16px tall), `circle` is a square-aspect disc sized by the host width, `line` renders `lines` 14px text bars with the last one at 65% width. Reflected. |
55
- | `lines` | `lines` | `number` | `1` | Number of text bars when `shape="line"` (minimum 1, 8px apart); ignored by the other shapes. |
54
+ | `shape` | `shape` | `"line" \| "circle" \| "block"` | `"block"` | Placeholder shape: `block` fills the host (min 16px tall), `circle` is a square-aspect disc sized by the host width, `line` renders `lines` 16px text bars with the last one at 65% width. Reflected. |
55
+ | `lines` | `lines` | `number` | `1` | Number of text bars when `shape="line"` (minimum 1, --rel-spacing-xs apart); ignored by the other shapes. |
56
56
  | `width` | `width` | `string` | `""` | Any CSS width (e.g. `"240px"`, `"50%"`) applied to the host's inline style. Empty leaves the host at its natural block width. |
57
57
  | `height` | `height` | `string` | `""` | Any CSS height (e.g. `"120px"`) applied to the host's inline style. Not needed for `circle`, which derives its height from the width. |
58
- | `animation` | `animation` | `"pulse" \| "shimmer" \| "none"` | `"pulse"` | Motion: `pulse` fades opacity between 100% and 40%, `shimmer` sweeps a highlight band left to right, `none` is static. Both animations are disabled under `prefers-reduced-motion: reduce`. Reflected. |
58
+ | `animation` | `animation` | `"pulse" \| "shimmer" \| "none"` | `"pulse"` | Motion: `pulse` fades opacity between 20% and 40% (Figma's Start/End states), `shimmer` sweeps a highlight band left to right, `none` is static. Both animations are disabled under `prefers-reduced-motion: reduce`. Reflected. |
59
59
  | `loaded` | `loaded` | `boolean` | `false` | Set once the real content is ready: hides the skeleton (`display: none`) and removes its `role="status"` / "Loading" label. Reflected. |
60
60
 
61
61
  ## Events
@@ -86,6 +86,7 @@ Set these on the host (or an ancestor) to customise the element without touching
86
86
  | --- | --- | --- |
87
87
  | `--rel-skeleton-color` | `var(--rel-bg-neutral-elevated-3)` | Fill colour of the placeholder (defaults to the elevated-3 neutral background token). |
88
88
  | `--rel-skeleton-highlight` | `var(--rel-bg-neutral-elevated-2)` | Lighter band that sweeps across the placeholder when `animation="shimmer"` (defaults to the elevated-2 neutral background token). |
89
+ | `--rel-skeleton-line-height` | `16px` | Height of each text bar when `shape="line"`; default 16px (Figma's Line shape). |
89
90
 
90
91
  <!-- readme-gen:end -->
91
92
 
@@ -97,7 +98,7 @@ Set these on the host (or an ancestor) to customise the element without touching
97
98
 
98
99
  ## Notes / Edge Cases
99
100
 
100
- - **Sizing.** `width` / `height` are written to the host's inline `style` and accept any CSS length. A `block` with no `height` is 16px tall (its `min-height`); a `circle` needs only a width (`aspect-ratio: 1 / 1`); `line` bars are 14px tall, 8px apart, full width, with the last bar at 65% when there is more than one.
101
+ - **Sizing.** `width` / `height` are written to the host's inline `style` and accept any CSS length. A `block` with no `height` is 16px tall (its `min-height`); a `circle` needs only a width (`aspect-ratio: 1 / 1`); `line` bars are 16px tall, `--rel-spacing-xs` apart, full width, with the last bar at 65% when there is more than one.
101
102
  - **`loaded` hides, it does not remove.** The host switches to `display: none` and stays in the DOM; place the real content as a sibling rather than inside the skeleton (the element has no slot).
102
103
  - **Multiple `base` parts.** With `shape="line"` every bar carries `part="base"`, so `::part(base)` styles all of them.
103
104
  - **Shimmer overrides the fill.** In `shimmer` mode the background becomes a gradient built from `--rel-skeleton-color` and `--rel-skeleton-highlight`; set both when customising colours.
@@ -49,13 +49,14 @@
49
49
  | Property | Attribute | Type | Default | Description |
50
50
  | --- | --- | --- | --- | --- |
51
51
  | `type` | `type` | `"continuous" \| "discrete" \| "default" \| "range"` | `"continuous"` | Slider mode: `continuous` (or its alias `default`) accepts any integer value, `discrete` snaps to `step` and draws tick marks, `range` shows two thumbs bounding `value`…`valueEnd`. Reflected. |
52
- | `size` | `size` | `"sm" \| "md" \| "lg"` | `"md"` | Figma Size axis (S/M/L): scales track, thumb and ticks. Reflected. |
52
+ | `showTicks` | `show-ticks` | `boolean` | `undefined` | Draws the tick marks (Figma's separate `Is Determinated` boolean). Works with ANY `type` — Figma shows ticks on every variant, where the code used to gate them behind the code-only `type="discrete"`, so a `default` or `range` slider could never show them. Left unset it follows `type="discrete"`, so nothing changes for existing sliders; set it explicitly to override in either direction. Reflected. |
53
+ | `size` | `size` | `"small" \| "medium" \| "large" \| "sm" \| "md" \| "lg"` | `"medium"` | Figma Size axis: `small` (6px track / 16px thumb), `medium` (8 / 20, default) or `large` (10 / 24), which also scales the ticks and the value bubble. `sm` / `md` / `lg` are alternative spellings and stay supported — they are normalised to the full words, not deprecated. Reflected. |
53
54
  | `min` | `min` | `number` | `0` | Lowest selectable value. |
54
55
  | `max` | `max` | `number` | `100` | Highest selectable value. |
55
56
  | `step` | `step` | `number` | `1` | Increment between values. In `discrete` mode it also spaces the tick marks; in `continuous` mode the native input always moves in steps of 1. |
56
57
  | `disabled` | `disabled` | `boolean` | `false` | Disables interaction and dims the track, thumb and ticks; the tooltip is hidden. |
57
58
  | `track` | `track` | `"solid" \| "dotted"` | `"solid"` | Style of the filled part of the track: `solid` or a `dotted` pattern. |
58
- | `showTickLabels` | `showticklabels` | `boolean` | `false` | Print the numeric value under every tick mark. Only has an effect in `discrete` mode. |
59
+ | `showTickLabels` | `showticklabels` | `boolean` | `false` | Print the numeric value under every tick mark. Only has an effect in `discrete` mode. Reflected. |
59
60
  | `showBubble` | `showbubble` | `boolean` | `true` | Show the value tooltip above the thumb(s). |
60
61
  | `value` | `value` | `number` | `0` | Current value (the lower value in `range` mode). |
61
62
  | `valueEnd` | `value-end` | `number` | `100` | Upper value when type="range" (attribute value-end). |
@@ -19,16 +19,20 @@
19
19
  <!-- Action button -->
20
20
  <rel-snackbar id="deleted" message="Item deleted" action="Undo"></rel-snackbar>
21
21
 
22
- <!-- Double-line layout with a longer (2 × duration) dismiss delay
23
- (attributes are lower-case: longeraction) -->
22
+ <!-- Double-line layout with a longer (2 × duration) dismiss delay -->
24
23
  <rel-snackbar
25
24
  id="archived"
26
25
  message="12 conversations were archived and will be deleted in 30 days"
27
26
  action="Undo"
28
- lines="double"
29
- longeraction
27
+ variant="longer-action"
30
28
  ></rel-snackbar>
31
29
 
30
+ <!-- Deprecated aliases — both still work and both log a one-time console notice.
31
+ `lines="double"` sets the stacked layout but NOT the doubled delay; `longeraction`
32
+ doubles the delay but does not stack. `variant="longer-action"` above does both.
33
+ Note the attribute is lower-case `longeraction`, not `longer-action`. -->
34
+ <rel-snackbar message="Older markup" action="Undo" lines="double" longeraction></rel-snackbar>
35
+
32
36
  <!-- Persistent, without the close icon (the boolean must be cleared from script — see the js block) -->
33
37
  <rel-snackbar id="busy" message="Processing…" duration="0"></rel-snackbar>
34
38
  ```
@@ -93,10 +97,9 @@ rel-snackbar {
93
97
  | --- | --- | --- | --- | --- |
94
98
  | `message` | `message` | `string` | `"This is a snackbar message"` | Message text. Announced to screen readers through the shared live-region announcer when the snackbar is shown and whenever it changes while shown. The default is a placeholder — always set it. |
95
99
  | `action` | `action` | `string` | `undefined` | Label of the optional action button (Figma trailing button, Static / Small); omitted when unset. Clicking it fires `actionClick` and then dismisses the snackbar. |
96
- | `longerAction` | `longeraction` | `boolean` | `false` | Doubles the auto-dismiss delay (`duration * 2`) so the user has time to read and use the action button. Pair it with `lines="double"` for the Figma Type=Longer Action layout. |
100
+ | `variant` | `variant` | `"default" \| "longer-action"` | `undefined` | Layout and timing (Figma "Type"): `"default"` (message and actions on one row) \| `"longer-action"` (message stacked above the actions, which align to the end, with the auto-dismiss delay doubled so there is time to use the action). Takes precedence over the deprecated `lines` and `longerAction` props. |
97
101
  | `iconClose` | `iconclose` | `boolean` | `true` | Shows the trailing close icon button. Defaults to true; because it is a Lit boolean, `iconclose="false"` is still true — set the property to `false` from script to hide the button. |
98
- | `lines` | `lines` | `"single" \| "double"` | `"single"` | Layout: `"single"` (default) puts the message and the actions on one row; `"double"` stacks the message above the actions, which align to the end (Figma Type=Longer Action). |
99
- | `duration` | `duration` | `number` | `4000` | Auto-dismiss delay in milliseconds (doubled by `longerAction`), started when `show` becomes true and restarted when `duration` or `longerAction` changes while shown. `0` (or a negative value) disables auto-dismiss. |
102
+ | `duration` | `duration` | `number` | `4000` | Auto-dismiss delay in milliseconds (doubled by `variant="longer-action"`), started when `show` becomes true and restarted when `duration` or the layout changes while shown. `0` (or a negative value) disables auto-dismiss. |
100
103
  | `tone` | `tone` | `"neutral" \| "success" \| "warning" \| "destructive" \| "default" \| "error" \| "danger" \| "critical"` | `undefined` | Semantic tone (Figma "Tone"): `"neutral"` (default: no accent, no icon) \| `"success"` \| `"warning"` \| `"destructive"` — the status tones add a 4px left accent and a leading icon (check-circle / warning / error) in the tone colour. `"default"` is a deprecated alias of `"neutral"`; `"error"`, `"danger"` and `"critical"` are deprecated aliases of `"destructive"`; each logs a one-time console notice. Takes precedence over the deprecated `type` prop. |
101
104
  | `show` | `show` | `boolean` | `false` | Whether the snackbar is visible. Set it to true to show the snackbar and start the auto-dismiss timer; it is set back to false by the close icon, the action button and the timer. There is no open/close method — toggle this property. Reflected. |
102
105
 
@@ -104,12 +107,15 @@ rel-snackbar {
104
107
 
105
108
  | Property | Attribute | Type | Use instead |
106
109
  | --- | --- | --- | --- |
110
+ | `longerAction` | `longeraction` | `boolean` | — use `variant="longer-action"`, which also sets the stacked layout. Doubles the auto-dismiss delay (`duration * 2`) on its own. Ignored when `variant` is set. Logs a one-time console notice. |
111
+ | `lines` | `lines` | `"single" \| "double"` | — use `variant`; `lines="double"` maps to `variant="longer-action"`. Sets the stacked layout on its own but not the doubled delay. Ignored when `variant` is set. Logs a one-time console notice. |
107
112
  | `type` | `type` | `"neutral" \| "success" \| "warning" \| "destructive" \| "default" \| "error" \| "danger" \| "critical"` | Deprecated since 1.4.7 — alias of `tone`; use `tone`. Same values as `tone`; `type="error"` maps to `tone="destructive"` and `type="default"` to `tone="neutral"`. Ignored when `tone` is set. Logs a one-time console notice. |
108
113
 
109
114
  ### Public fields / accessors
110
115
 
111
116
  | Name | Type | Description |
112
117
  | --- | --- | --- |
118
+ | `resolvedVariant` | `SnackbarVariant` | Read-only canonical layout actually rendered: explicit `variant` wins, else either deprecated prop (`lines="double"` or `longerAction`) promotes to `"longer-action"`, else `"default"`. |
113
119
  | `resolvedTone` | `SnackbarTone` | Read-only canonical tone actually rendered: explicit `tone` wins, else `type`, else `"neutral"`; deprecated aliases are resolved to `"neutral"` / `"destructive"`. |
114
120
 
115
121
  ## Events
@@ -16,8 +16,13 @@ A multi-step progress indicator implementing the Figma "Stepper" component: its
16
16
  ];
17
17
  </script>
18
18
 
19
- <!-- Vertical, small, label beside the indicator (Figma Typel = Centered) -->
20
- <rel-stepper id="onboarding" orientation="vertical" label-placement="centered" size="small"></rel-stepper>
19
+ <!-- Vertical, label beside the indicator (Figma Type = Centered).
20
+ `size` is DEPRECATED and deliberately omitted: Figma has no Size axis on the
21
+ Stepper — the connector geometry is fixed — so it was a code-only scale. It is
22
+ still accepted so existing markup keeps working, but it now resolves to the one
23
+ Figma geometry and logs a one-time notice. Retune with
24
+ `--rel-stepper-connector-length` instead. -->
25
+ <rel-stepper id="onboarding" orientation="vertical" label-placement="centered"></rel-stepper>
21
26
  <script>
22
27
  document.getElementById('onboarding').steps = [
23
28
  { title: 'Create account', status: 'done' },
@@ -32,6 +37,11 @@ A multi-step progress indicator implementing the Figma "Stepper" component: its
32
37
  <rel-stepper type="number" steps='[{"title":"Plan","status":"done"},{"title":"Build","status":"progress"},{"title":"Ship","status":"disabled"}]'></rel-stepper>
33
38
  <rel-stepper type="icon" steps='[{"title":"Plan","status":"done"},{"title":"Build","status":"progress"},{"title":"Ship","status":"disabled"}]'></rel-stepper>
34
39
 
40
+ <!-- Figma .Line Types axis: the CONNECTOR between steps, dashed 2px on / 2px off.
41
+ Distinct from type="dot" above, which is the indicator disc — combine freely. -->
42
+ <rel-stepper connector="dot" steps='[{"title":"Plan","status":"done"},{"title":"Build","status":"progress"},{"title":"Ship","status":"disabled"}]'></rel-stepper>
43
+ <rel-stepper connector="dot" type="dot" steps='[{"title":"Plan","status":"done"},{"title":"Build","status":"progress"},{"title":"Ship","status":"disabled"}]'></rel-stepper>
44
+
35
45
  <!-- Label placement (Figma Typel): top-aligned beside the indicator, or indicator above the label -->
36
46
  <rel-stepper orientation="vertical" label-placement="top" steps='[{"title":"Review","status":"done"},{"title":"Approve","status":"progress"}]'></rel-stepper>
37
47
  <rel-stepper label-placement="inverted" steps='[{"title":"Review","status":"done"},{"title":"Approve","status":"progress"}]'></rel-stepper>
@@ -60,11 +70,13 @@ A multi-step progress indicator implementing the Figma "Stepper" component: its
60
70
 
61
71
  ```html
62
72
  <!-- textalign="right" → label-placement="centered"; textalign="below" → label-placement="inverted".
63
- Still supported and still the fallback when label-placement is unset; no console notice is logged. -->
73
+ Still supported and still the fallback when label-placement is unset. Since 1.4.9 a
74
+ non-default value logs a one-time console notice; it had been marked deprecated since the
75
+ rename but never said so at runtime. Setting label-placement supersedes it and stays silent. -->
64
76
  <rel-stepper textalign="right" steps='[{"title":"Review","status":"done"},{"title":"Approve","status":"progress"}]'></rel-stepper>
65
77
  ```
66
78
 
67
- The `Step` type and the `StepStatus`, `StepperType` and `LabelPlacement` unions are exported from the package:
79
+ The `Step` type and the `StepStatus`, `StepperType`, `StepperConnector` and `LabelPlacement` unions are exported from the package:
68
80
 
69
81
  ```typescript
70
82
  import type { Step } from '@reliability-design/web';
@@ -86,10 +98,10 @@ const steps: Step[] = [
86
98
 
87
99
  | Property | Attribute | Type | Default | Description |
88
100
  | --- | --- | --- | --- | --- |
89
- | `steps` | `steps` | `Step[]` | `[]` | The steps in order, each `{ title: string; status: "done" \| "progress" \| "disabled" }`. Set as a property (or a JSON array attribute); the component never mutates it — update it from the `rel-step-change` handler. |
101
+ | `steps` | `steps` | `Step[]` | `[]` | The steps in order, each `{ title: string; subtitle?: string; status: "done" \| "progress" \| "disabled" }`. Set as a property (or a JSON array attribute); the component never mutates it — update it from the `rel-step-change` handler. |
90
102
  | `orientation` | `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Layout axis: `horizontal` (default) lays the steps out in a centred row; `vertical` stacks them. |
91
- | `size` | `size` | `"small" \| "large"` | `"large"` | `large` (default) or `small`: controls the label type (body-md vs body-sm) and the connector length / step gap (see the `--rel-stepper-connector-length-*` hooks). |
92
- | `type` | `type` | `"default" \| "dot" \| "number" \| "icon"` | `"default"` | Figma "Type" axis — what the indicator shows: `default` (step number, check mark once done), `dot` (8px dot, no glyph), `number` (always the number) or `icon` (always the check mark). Reflected. |
103
+ | `type` | `type` | `"default" \| "dot" \| "number" \| "icon"` | `"default"` | Figma "Type" axis — what the INDICATOR shows: `default` (step number, check mark once done), `dot` (8px dot, no glyph), `number` (always the number) or `icon` (always the check mark). Not the same axis as `connector="dot"`, which dashes the line between steps. Reflected. |
104
+ | `connector` | `connector` | `"solid" \| "dot"` | `"solid"` | Figma ".Line Types" axis — how the line BETWEEN steps is drawn: `solid` (an unbroken 1px rule) or `dot` (a 1px rule dashed 2px on, 2px off). Applies to both orientations. Not the same axis as `type="dot"`, which is the indicator disc; the two are independent and can be combined. Reflected. |
93
105
  | `labelPlacement` | `label-placement` | `"top" \| "centered" \| "inverted"` | `undefined` | Figma "Typel" axis — where the label sits: `top` (top-aligned beside the indicator), `centered` (vertically centred beside it) or `inverted` (indicator above the label). When unset, the deprecated `textAlign` prop drives the layout (`below` ≈ `inverted`, `right` ≈ `centered`). Figma marks Top + Horizontal as an unsupported combination. Reflected. |
94
106
 
95
107
  #### Deprecated (still supported — removal targeted for 3.0)
@@ -97,6 +109,7 @@ const steps: Step[] = [
97
109
  | Property | Attribute | Type | Use instead |
98
110
  | --- | --- | --- | --- |
99
111
  | `textAlign` | `textalign` | `"right" \| "below"` | Deprecated alias of `label-placement`; use `label-placement="inverted"` instead of `textalign="below"` and `label-placement="centered"` instead of `textalign="right"`. |
112
+ | `size` | `size` | `"small" \| "large"` | Figma has no Size axis on the Stepper — the connector geometry is fixed — so this was a code-only scale. It stays accepted so existing markup keeps working, and now resolves to the one Figma geometry. Retune it with `--rel-stepper-connector-length` instead. Logs a one-time notice. |
100
113
 
101
114
  ## Events
102
115
 
@@ -117,6 +130,7 @@ const steps: Step[] = [
117
130
  | `indicator` | The 24px circle (8px for `type="dot"`) that holds the step number, check mark or icon. |
118
131
  | `track` | The 1px connector line from a step to the next one (not rendered on the last step). |
119
132
  | `label` | The step title text. |
133
+ | `subtitle` | The optional second line under the title; rendered only when a step sets `subtitle`. |
120
134
 
121
135
  ## Tokens / CSS Variables
122
136
 
@@ -126,9 +140,7 @@ Set these on the host (or an ancestor) to customise the element without touching
126
140
 
127
141
  | Custom property | Default | Description |
128
142
  | --- | --- | --- |
129
- | `--rel-stepper-connector-length-lg` | `86px` | Connector length and step gap for `size="large"` in both orientations (default 86px). |
130
- | `--rel-stepper-connector-length-md` | `60px` | Connector length and step gap for `size="small"` in `orientation="horizontal"` (default 60px). |
131
- | `--rel-stepper-connector-length-sm` | `42px` | Connector length and step gap for `size="small"` in `orientation="vertical"` (default 42px). |
143
+ | `--rel-stepper-connector-length` | `var(--rel-stepper-connector-length-lg, 96px)` | Length of the connector line; the step gap is derived from it by adding Figma's clear space at both ends. Defaults to Figma's fixed geometry: 96px horizontally, 34px vertically with `label-placement="centered"`, 51px with `inverted`. |
132
144
  | `--rel-stepper-indicator-size` | `24px` | Indicator diameter (default 24px; `type="dot"` is fixed at 8px). |
133
145
 
134
146
  <!-- readme-gen:end -->
@@ -152,6 +164,7 @@ Set these on the host (or an ancestor) to customise the element without touching
152
164
  - `label-placement` is the canonical layout switch (Figma `Typel`). When it is unset the deprecated `textalign` prop decides: `below` renders like `inverted` (indicator above the label), `right` renders like `centered` (label beside the indicator). `top` differs from `centered` only in aligning the label to the top of the indicator. Figma marks Top + Horizontal as an unsupported combination.
153
165
  - Statuses map to the Figma `.Artwork` states: `done` = inverse fill with a check mark (or the number when `type="number"`, nothing when `type="dot"`), `progress` = neutral fill with a strong 1px border, `disabled` = the same drawn at 40% opacity. Connectors are `border-strong` after a `done` / `progress` step and `border-default` otherwise.
154
166
  - `type="icon"` shows the check mark on every step regardless of status; `type="dot"` shrinks the indicator to 8px and fills it for `done` and `progress`.
167
+ - Two axes spell one value "dot" and they are independent: `type="dot"` is the INDICATOR (an 8px disc replacing the number), `connector="dot"` is the LINE between steps. `connector="dot"` draws a 1px rule dashed 2px on / 2px off, matching Figma `.Line Types` `Type=Dot` (`strokeWeight=1`, `strokeDashes=[2,2]`). It is a repeating gradient rather than a dashed border because no engine lets you state a 2/2 dash period. The dash takes the connector's own state colour, so it goes `border-strong` after a `done` / `progress` step like the solid line does.
155
168
  - Connector length doubles as the gap between steps and depends on `size` and `orientation`: large = `--rel-stepper-connector-length-lg` (86px) in both orientations; small horizontal = `--rel-stepper-connector-length-md` (60px); small vertical = `--rel-stepper-connector-length-sm` (42px). Note the `md` / `sm` suffixes refer to those defaults, not to a size value.
156
169
  - Labels never wrap (`white-space: nowrap`); keep titles short or widen the connector hooks.
157
170
  - `steps` is compared by reference: mutate-in-place changes are not picked up — assign a new array.
@@ -44,9 +44,13 @@
44
44
  | Property | Attribute | Type | Default | Description |
45
45
  | --- | --- | --- | --- | --- |
46
46
  | `checked` | `checked` | `boolean` | `false` | Whether the switch is on. Set it to control the state programmatically; user toggles update it and fire `rel-change`. |
47
- | `disabled` | `disabled` | `boolean` | `false` | Disables interaction, dims the control to 50% and removes the handle shadow. |
47
+ | `type` | `type` | `"line" \| "pill"` | `"line"` | Shape (Figma "Type"): `"line"` (default) is the 44x20 control with a thin 40x10 rail and the handle riding on it; `"pill"` is the 44x24 filled track with the handle inside it. NOTE: Figma's own default is Pill. We default to `line` deliberately — flipping it would restyle every existing switch — so this is a recorded divergence from the design default, not an oversight. Reflected. |
48
+ | `disabled` | `disabled` | `boolean` | `false` | Disables interaction and swaps in the dulled rail / handle fills; the handle shadow is removed. |
48
49
  | `value` | `value` | `string` | `""` | Arbitrary string echoed in the `rel-change` event detail — useful when one handler serves several switches. |
49
50
  | `fieldAriaLabel` | `field-aria-label` | `string` | `undefined` | Accessible name for the native input. Without it the switch has no label of its own, so pair it with a visible `<label>` or set this. |
51
+ | `label` | `label` | `string` | `undefined` | Visible text beside the control. Clicking it toggles the switch, and it becomes the accessible name — use `fieldAriaLabel` instead when the switch has no visible text. For rich content (a bold word, an icon) slot it in the default slot rather than setting this. |
52
+ | `labelPlacement` | `label-placement` | `"end" \| "start"` | `"end"` | Which side the label sits on: `end` (default) puts it after the control, `start` before it. Note this is a PHYSICAL side, not a writing-direction one, matching every other placement prop in the library. Reflected. |
53
+ | `size` | `size` | `"small" \| "medium" \| "large" \| "sm" \| "md" \| "lg"` | `"medium"` | Control scale: `small`, `medium` (default) or `large`. `sm` / `md` / `lg` are alternative spellings and stay supported — normalised to the full words, not deprecated. Figma's Switch has axes Type / State / Enabled only, with no Size, so this ramp is ours. `medium` is exactly the control that shipped before it existed, so an existing switch is unchanged. It does NOT respond to viewport width. Picking a size per breakpoint is the consuming application's decision — a control that silently resized itself at some width would be undocumentable behaviour, and the breakpoint that matters belongs to the layout around it, not to the switch. Reflected. |
50
54
 
51
55
  ## Events
52
56
 
@@ -58,14 +62,16 @@
58
62
 
59
63
  | Slot | Description |
60
64
  | --- | --- |
61
- | — | This element has no slots. |
65
+ | (default) | Rich label content beside the control, as an alternative to the `label` property. Clicking it toggles the switch. |
62
66
 
63
67
  ## CSS Parts
64
68
 
65
69
  | Part | Description |
66
70
  | --- | --- |
67
- | `base` | The `<label>` wrapper around the hidden input and the track |
71
+ | `root` | The `<label>` holding the control and its optional text; carries the `label-placement` order |
72
+ | `base` | The control box around the hidden input and the track |
68
73
  | `track` | The thin rail; the handle is its `::before` pseudo-element |
74
+ | `label` | The text beside the control; not rendered when there is neither a `label` nor slotted content |
69
75
 
70
76
  ## Tokens / CSS Variables
71
77
 
@@ -78,10 +84,11 @@ Set these on the host (or an ancestor) to customise the element without touching
78
84
  | `--rel-switch-disabled` | `var(--switch-disabled)` | Handle colour while disabled; default `var(--rel-bg-neutral-elevated-1)` |
79
85
  | `--rel-switch-knob-off` | `var(--switch-knob-off)` | Handle colour when unchecked; default `var(--rel-text-static-light)` |
80
86
  | `--rel-switch-knob-on` | `var(--switch-knob-on)` | Handle colour when checked; default `var(--rel-bg-neutral-inverse-2)` |
81
- | `--rel-switch-thumb-size` | `20px` | Handle diameter; default 20px (the handle always travels 20px) |
87
+ | `--rel-switch-thumb-size` | `var(--_rel-sw-thumb)` | Handle diameter; defaults to the `size` ramp (16 / 20 / 24px), and the handle always travels its own width minus the 2px inset on each side |
82
88
  | `--rel-switch-track` | `var(--switch-track)` | Rail colour; default `var(--rel-bg-neutral-elevated-2)` |
83
- | `--rel-switch-track-height` | `20px` | Overall control height; default 20px |
84
- | `--rel-switch-track-width` | `44px` | Overall control width; default 44px |
89
+ | `--rel-switch-track-height` | `var(--_rel-sw-h)` | Overall control height; defaults to the `size` ramp — 16 / 20 / 24px for `type="line"`, 20 / 24 / 28px for `type="pill"` |
90
+ | `--rel-switch-track-width` | `var(--_rel-sw-w)` | Overall control width; defaults to the `size` ramp (36 / 44 / 52px) |
91
+ | `--switch-halo` | `var(--rel-action-overlay-hover-strong)` | — |
85
92
 
86
93
  <!-- readme-gen:end -->
87
94
 
@@ -101,7 +108,9 @@ Set these on the host (or an ancestor) to customise the element without touching
101
108
  ## Notes / Edge Cases
102
109
 
103
110
  - `rel-change` fires for user toggles only; setting `checked` from JavaScript updates the visuals but emits nothing.
104
- - Geometry is fixed to the Figma Line switch: 44×20 control, 40×10 track inset 2px, 20px handle. The handle always travels 20px, so changing `--rel-switch-track-width` widens the control without moving the "on" position.
111
+ - Geometry follows the `size` ramp, derived from the Figma Line switch at `medium`: 44×20 control, 40×10 track inset 2px, 20px handle travelling 20px. `small` is 36×16 and `large` 52×24, holding the same invariants (handle = control height, width = 2× height + 4, rail = height ÷ 2, travel = width − 4 − handle). `type="pill"` shares the width, handle and travel but is 4px taller at every size — 20 / 24 / 28 — because its height is the handle plus its 2px inset, where Line's height *is* the handle. Changing `--rel-switch-track-width` widens the control without moving the "on" position.
112
+ - **`size` does not respond to viewport width.** Figma has no Size axis on Switch, so the ramp is ours, and choosing a size per breakpoint is the application's decision — set it from your own media queries or container queries. A control that resized itself at some width would be behaviour a design system cannot document, and the breakpoint that matters belongs to the layout around the switch, not to the switch.
113
+ - A `label` (or slotted content) becomes the switch's accessible name and is clickable, because the root element is the `<label>` that owns the input. Use `field-aria-label` instead when there is no visible text; when both are set, `label` wins.
105
114
  - Figma's default Type=Pill switch (44×24 filled track with the handle inside) is not implemented.
106
115
  - Hover tints the track with the action overlay and raises the handle shadow; pressed shows a 28px overlay disc behind the handle and squashes it to 20×16.
107
116
  - Legacy hook aliases still honoured: `--switch-track`, `--switch-knob-on`, `--switch-knob-off` and `--switch-disabled` are read as fallbacks of the `--rel-switch-*` hooks. The old `--switch-halo` name was never read by any rule and is not a hook.
@@ -81,6 +81,7 @@
81
81
  | Event | Detail | Bubbles / composed | Description |
82
82
  | --- | --- | --- | --- |
83
83
  | `rel-tab-change` | `index` | bubbles / composed | Fired when the user selects a tab by click or keyboard (not on programmatic `activeIndex` changes). Detail: the new active index (number). |
84
+ | `rel-change` | `index` | bubbles / composed | Prefixed alias of `rel-tab-change`, added in 1.4.9 — fired on the same action with the same detail. Both events fire; listen to one. Prefer this in new code, since every interactive component in the library emits `rel-change`. `rel-tab-change` is kept for as long as 1.x. |
84
85
 
85
86
  ### Slots
86
87
 
@@ -95,6 +96,7 @@
95
96
  | --- | --- |
96
97
  | `list` | The `role="tablist"` row |
97
98
  | `item` | Each `role="tab"` element |
99
+ | `icon` | — |
98
100
  | `label` | The text span inside each tab |
99
101
 
100
102
  ### Tokens / CSS Variables
@@ -108,9 +110,9 @@ Set these on the host (or an ancestor) to customise the element without touching
108
110
  | `--rel-tab-active-color` | `var(--tab-active-color)` | Underline colour of the active tab; default `var(--rel-bg-brand)` |
109
111
  | `--rel-tab-hover-color` | `var(--tab-hover-color)` | Background of an inactive tab on hover; default `var(--rel-bg-neutral-elevated-1)` |
110
112
  | `--rel-tab-text-default` | `var(--tab-text-default)` | Label colour of the active tab; default `var(--rel-text-default)` |
111
- | `--rel-tab-text-disabled` | `var(--tab-text-disabled)` | Label colour of a disabled tab; default `var(--rel-text-disabled)` |
113
+ | `--rel-tab-text-disabled` | `inherit` | Label colour of a disabled tab; default `var(--rel-text-disabled)` |
112
114
  | `--rel-tab-text-hover` | `var(--tab-text-hover)` | Label colour while hovering an enabled tab; default `var(--rel-text-label)` |
113
- | `--rel-tab-underline-height` | `var(--tab-underline-height)` | Thickness of the active underline; default 3px |
115
+ | `--rel-tab-underline-height` | `var(--tab-underline-height)` | Thickness of the active underline; default 1px (`--rel-stroke-sm`, the weight Figma draws). Set it to restore the heavier 3px bar shipped previously. |
114
116
 
115
117
  ### `<rel-tab-item>`
116
118
 
@@ -119,6 +121,7 @@ Set these on the host (or an ancestor) to customise the element without touching
119
121
  | Property | Attribute | Type | Default | Description |
120
122
  | --- | --- | --- | --- | --- |
121
123
  | `label` | `label` | `string` | `""` | Text shown on the tab. |
124
+ | `icon` | `icon` | `string` | `""` | Icon name from the generated icon dictionary, rendered before the label (Figma "Show Icon" / "Icon"). Sized 20 / 18 / 16px with the tab's own size step. |
122
125
  | `value` | `value` | `string` | `""` | Optional identifier for the tab. `<rel-tab>` does not read it; look it up from the item at `event.detail` when handling `rel-tab-change`. |
123
126
  | `badge` | `badge` | `number` | `0` | Count shown in a small badge after the label; `0` hides the badge. |
124
127
  | `badgeDot` | `badge-dot` | `boolean` | `false` | Shows a small dot instead of a numbered badge — takes precedence over `badge`. |
@@ -110,6 +110,7 @@
110
110
  | `error` | `error` | `boolean` | `false` | Puts the field in the error state: danger border, `aria-invalid`, and `errorMessage` replacing the helper text. |
111
111
  | `errorMessage` | `errormessage` | `string` | `undefined` | Text shown below the control instead of `helperText` while the field is in the error state. |
112
112
  | `helperText` | `helpertext` | `string` | `undefined` | Helper line below the control (preferred over the legacy `supportingText`); linked to the input via `aria-describedby`. |
113
+ | `helperIcon` | `helper-icon` | `string` | `undefined` | Icon name from the generated icon dictionary, rendered before the helper line (Figma "Supporting Icon"). Sized 16px, or 14px at `size="small"`, and it takes the helper's colour — so it turns `--rel-text-danger` in the error state. Decorative: it is hidden from screen readers, since the helper text it sits beside is already announced. |
113
114
  | `readonly` | `readonly` | `boolean` | `false` | Makes the input read-only: focusable and selectable but not editable. |
114
115
  | `maxLength` | `maxlength` | `number` | `undefined` | Maximum number of characters (native `maxlength`). |
115
116
  | `name` | `name` | `string` | `undefined` | Form field name forwarded to the native input, for form submission and autofill. |
@@ -151,7 +152,8 @@
151
152
  | `prefix` | The prefix block (leading icon, prefix text and the `prefix` slot) |
152
153
  | `suffix` | The suffix block (suffix text, trailing icon and the `suffix` slot) |
153
154
  | `helper` | The helper / error text line below the control |
154
- | `control` | The bordered control box (the fieldset in the legend variant) |
155
+ | `helper-icon` | The leading `rel-icon` in the helper line; rendered only when `helper-icon` is set and there is helper text |
156
+ | `control` | The bordered control box. **Changed in 1.4.9:** in `variant="legend"` this is now the same `div` as every other variant, not the `fieldset` — the fieldset was demoted to a decorative outline layer behind the content so the control sits on the 32/40/48 size ladder and centres its value like the other variants. `::part(control)` still matches; only rules that depended on it being a fieldset do not. |
155
157
 
156
158
  ## Tokens / CSS Variables
157
159
 
@@ -161,7 +163,8 @@ Set these on the host (or an ancestor) to customise the element without touching
161
163
 
162
164
  | Custom property | Default | Description |
163
165
  | --- | --- | --- |
164
- | `--rel-field-label-reserve` | `calc(var(--rel-body-sm-medium-line-height) + var(--rel-spacing-2xs))` | Height held for the absent label row under `labelStyle="none"` so the control bottom-aligns with labelled siblings; defaults to the label line-height plus the wrapper gap. Set to `0` to collapse the row entirely (toolbars, table cells). |
166
+ | `--rel-field-label-reserve` | `calc(var(--rel-body-md-regular-line-height) + var(--rel-spacing-2xs))` | Height held for the label row whenever no label renders above the control — `labelStyle="none"`, and `labelStyle="floating"` where the label sits inside the control — so the control still lines up with labelled siblings in a form row. Defaults to that size's label line-height plus the wrapper gap (24px at `small`, 26px at `medium` and `large`). Set to `0` to collapse the row entirely (toolbars, table cells). |
167
+ | `--rel-textfield-surface` | `var(--rel-bg-neutral)` | Colour of the strip the floating label lays over the control's top border and focus ring so the label appears to sit in a notch. It overshoots the band by 2px on the page side, so it must match the surface the field sits on; defaults to the control's own fill (`--rel-bg-neutral`). Set it on a tinted or elevated surface, otherwise the strip shows as a light dash across the border. |
165
168
 
166
169
  <!-- readme-gen:end -->
167
170
 
@@ -183,6 +186,20 @@ Focus behaviour: `focus()` on the host focuses the inner input / textarea (the h
183
186
  ## Notes / Edge Cases
184
187
 
185
188
  - Attribute spellings: props declared with an explicit `attribute` use kebab-case (`label-style`, `prefix-text`, `clickable-right-icon`, `field-aria-label`, …). The others have Lit's default all-lowercase attribute — `prefixicon`, `righticon`, `helpertext`, `errormessage`, `maxlength`, `fullwidth`, `supportingtext`, `floatinglabel` — see the Attribute column above. HTML attribute names are case-insensitive, so `helperText="…"` in markup also works.
189
+ - **The same logical prop can take a _different_ spelling on `rel-autocomplete` / `rel-select`.** Those components declare an explicit kebab `attribute` where this one falls back to Lit's all-lowercase default, so `prefix-icon` works on `<rel-autocomplete>` and is silently ignored on `<rel-textfield>`. There is no error when this happens — an attribute a component does not observe is inert, so the icon simply never appears. The pairs that differ today:
190
+
191
+ | Prop | `rel-textfield` | `rel-autocomplete` / `rel-select` |
192
+ | --- | --- | --- |
193
+ | `prefixIcon` | `prefixicon` | `prefix-icon` (autocomplete) |
194
+ | `helperText` | `helpertext` | `helper-text` (autocomplete) |
195
+ | `errorMessage` | `errormessage` | `error-message` (autocomplete) |
196
+ | `floatingLabel` | `floatinglabel` | `floating-label` (autocomplete) |
197
+ | `fullWidth` | `fullwidth` | `full-width` (autocomplete) |
198
+ | `leftIcon` | `lefticon` | `left-icon` (select) |
199
+ | `rightIcon` | `righticon` | `right-icon` (select) |
200
+ | `supportingText` | `supportingtext` | `supporting-text` (select) |
201
+
202
+ All three agree on `label-style`, `field-aria-label` and `field-aria-labelledby`. This is an inconsistency, not a design decision: the kebab spellings are the intended direction, and unifying on them means retiring the lowercase ones, which only a major version can do — so it is targeted for 3.0. Until then the Attribute column above is the authority for **this** component. In a Lit template you can sidestep the whole question with a property binding (`.prefixIcon=${…}`), which is spelling-independent; that is also how `rel-autocomplete` drives the field it wraps, so its own forwarding is unaffected by the mismatch.
186
203
  - Legacy names still work but the canonical ones win when both are set: `leftIcon` → `prefixIcon`, `supportingText` → `helperText`, `state="error"` → `error`, `state="disabled"` → `disabled`. `lefticon` / `righticon` attributes are also read once at connect time.
187
204
  - `errorMessage` replaces the helper line only while the field is in the error state **and** the message is set; otherwise the helper text stays visible. There is no built-in validation — set `error` from your form layer.
188
205
  - `state="error"` (legacy) auto-clears to `"default"` as soon as the user types a non-empty value and comes back once the value is emptied again; the `error` boolean never auto-clears.
@@ -127,6 +127,12 @@ Typing into the field and pressing `Enter` (or leaving the field) commits the te
127
127
 
128
128
  <!-- readme-gen:end -->
129
129
 
130
+
131
+ ## CSS Custom Properties
132
+
133
+ | Custom property | Default | Description |
134
+ | --- | --- | --- |
135
+ | `--rel-overlay-fallback-z` | `1001` | z-index of the panel on the **no-Popover-API fallback path only**. Wherever the browser top layer is available the panel is promoted into it and this value is inert, because top-layer elements are not in the page stacking order at all. Shared with the other overlays (select, autocomplete, the three pickers) so the whole family can be moved from one place. |
130
136
  ## Accessibility
131
137
 
132
138
  - The editable field is an `<input type="text" role="combobox">` with `aria-haspopup="dialog"`, `aria-expanded`, `aria-controls` pointing at the panel, `aria-required` (from `required`), `aria-invalid` (from `error` / `invalid` / a typed-entry error) and `aria-describedby` pointing at the helper / error text. Its accessible name is the `label` (via `aria-labelledby`), falling back to `aria-label="Select time"`.
@@ -1,6 +1,6 @@
1
1
  # rel-toast
2
2
 
3
- `<rel-toast>` is the transient notification of the Reliability Design System: a dark pill fixed to the bottom centre of the viewport that shows a short message, an optional action button ("Undo", "Retry") and a dismiss button, then hides itself after `duration` milliseconds. It has two tones — `default` and `destructive` — and is driven by the `show` property (or `open()` / `close()`). Use it for brief confirmations that need no reply; use `<rel-snackbar>` when you need the status tones, a stacked layout or your own positioning, and `<rel-alert>` for messages that must stay on the page.
3
+ `<rel-toast>` is the transient notification of the Reliability Design System: a card anchored to one of six viewport positions (bottom centre by default) that shows a short message, an optional action button ("Undo", "Retry") and a dismiss button, then hides itself after `duration` milliseconds. It has two tones — `default` and `destructive` — and is driven by the `show` property (or `open()` / `close()`). Use it for brief confirmations that need no reply; use `<rel-snackbar>` when you need the status tones, a stacked layout or your own positioning, and `<rel-alert>` for messages that must stay on the page.
4
4
 
5
5
  ## Usage
6
6
 
@@ -74,22 +74,26 @@ rel-toast { --rel-z-toast: 10000; }
74
74
  | Property | Attribute | Type | Default | Description |
75
75
  | --- | --- | --- | --- | --- |
76
76
  | `message` | `message` | `string` | `""` | Text of the toast. It is also announced to screen readers through the shared live-region announcer each time `show` becomes true. |
77
- | `tone` | `tone` | `"default" \| "destructive" \| "error" \| "danger" \| "critical"` | `undefined` | Semantic tone: `"default"` (dark neutral pill) \| `"destructive"` (danger fill, announced assertively). `"error"`, `"danger"` and `"critical"` are deprecated aliases of `"destructive"` and log a one-time console notice. Takes precedence over the deprecated `type` prop. |
77
+ | `tone` | `tone` | `"neutral" \| "destructive" \| "default" \| "error" \| "danger" \| "critical"` | `undefined` | Semantic tone (Figma "Tone"): `"neutral"` (default: neutral surface) \| `"destructive"` (danger fill, announced assertively). `"default"` is a deprecated alias of `"neutral"`; `"error"`, `"danger"` and `"critical"` are deprecated aliases of `"destructive"`; each logs a one-time console notice. Takes precedence over the deprecated `type` prop. |
78
78
  | `actionLabel` | `actionlabel` | `string` | `undefined` | Label of the optional action button rendered between the message and the dismiss button; the button is omitted when unset. Clicking it fires `action` and then closes the toast. |
79
79
  | `duration` | `duration` | `number` | `4000` | Auto-dismiss delay in milliseconds, started each time `show` becomes true. `0` (or a negative value) disables auto-dismiss so the toast stays until `close()` or the dismiss button. Changing it while the toast is visible does not restart the running timer. |
80
80
  | `show` | `show` | `boolean` | `false` | Whether the toast is visible. Set it to true (or call `open()`) to show the toast and start the auto-dismiss timer; it is set back to false by `close()`, the dismiss button, the action button and the timer. Reflected. |
81
+ | `dismissible` | `dismissible` | `boolean` | `true` | Shows the trailing dismiss button (Figma "Show Close Button"). Defaults to true; because it is a Lit boolean, `dismissible="false"` is still true — set the property to `false` from script to hide the button. |
82
+ | `position` | `position` | `"top-left" \| "top-center" \| "top-right" \| "bottom-left" \| "bottom-center" \| "bottom-right"` | `"bottom-center"` | Where the toast is anchored: `bottom-center` (default, unchanged from before this prop existed), `bottom-left`, `bottom-right`, `top-left`, `top-center` or `top-right`. Top anchors also animate in from the top edge rather than upward from the bottom. Figma's Toast has axes Content / Show Button / Show Close Button / Tone and no position, so this axis is ours. Reflected. |
83
+ | `size` | `size` | `"small" \| "medium" \| "large" \| "sm" \| "md" \| "lg"` | `"medium"` | Toast scale: `small`, `medium` (default, unchanged) or `large`. `sm` / `md` / `lg` are alternative spellings and stay supported — normalised to the full words, not deprecated. Scales the padding, the inner gap, the message type role and the close icon. Figma has no Size axis on Toast. Reflected. |
84
+ | `maxVisible` | `max-visible` | `number` | `3` | How many toasts may be on screen at once AT THIS POSITION. Further ones wait their turn rather than being dropped — a notification the user never saw is worse than a late one — and each toast's `duration` only starts once it actually becomes visible, so a queued message cannot expire unseen. Default 3; unbounded stacking just fills the viewport. |
81
85
 
82
86
  #### Deprecated (still supported — removal targeted for 3.0)
83
87
 
84
88
  | Property | Attribute | Type | Use instead |
85
89
  | --- | --- | --- | --- |
86
- | `type` | `type` | `"default" \| "destructive" \| "error" \| "danger" \| "critical"` | Deprecated since 1.4.7 — alias of `tone`; use `tone`. Same values as `tone`; `type="error"` maps to `tone="destructive"`. Ignored when `tone` is set. Logs a one-time console notice. |
90
+ | `type` | `type` | `"neutral" \| "destructive" \| "default" \| "error" \| "danger" \| "critical"` | Deprecated since 1.4.7 — alias of `tone`; use `tone`. Same values as `tone`; `type="error"` maps to `tone="destructive"` and `type="default"` to `tone="neutral"`. Ignored when `tone` is set. Logs a one-time console notice. |
87
91
 
88
92
  ### Public fields / accessors
89
93
 
90
94
  | Name | Type | Description |
91
95
  | --- | --- | --- |
92
- | `resolvedTone` | `ToastTone` | Read-only canonical tone actually rendered: explicit `tone` wins, else `type`, else `"default"`; deprecated aliases are resolved to `"destructive"`. |
96
+ | `resolvedTone` | `ToastTone` | Read-only canonical tone actually rendered: explicit `tone` wins, else `type`, else `"neutral"`; deprecated aliases are resolved to `"neutral"` / `"destructive"`. |
93
97
 
94
98
  ### Methods
95
99
 
@@ -118,7 +122,7 @@ rel-toast { --rel-z-toast: 10000; }
118
122
  | `base` | The `role="status"` toast container that carries the tone class |
119
123
  | `label` | The message text span |
120
124
  | `action` | The action button; rendered only when `actionlabel` is set |
121
- | `close-button` | The dismiss (✕) button |
125
+ | `close-button` | The dismiss button; rendered while `dismissible` is true |
122
126
 
123
127
  ## Tokens / CSS Variables
124
128
 
@@ -149,7 +153,11 @@ Set these on the host (or an ancestor) to customise the element without touching
149
153
  ## Notes / Edge Cases
150
154
 
151
155
  - `show` is a boolean **property**, not a method: `toast.show()` throws. Use `toast.show = true` or `toast.open()`; the old README's `show()` call was wrong.
152
- - The host is `position: fixed; bottom: 24px; left: 50%` with `pointer-events: none` (the pill itself restores `pointer-events: all`), so it never blocks clicks around it. There is no stacking manager: two visible toasts overlap at the same spot — reuse one element and update `message`.
156
+ - The host is a full-width `position: fixed` bar (`left: 0; right: 0`) pinned to the edge named by `position`, with `pointer-events: none` (the pill itself restores `pointer-events: all`), so it never blocks clicks around it. The corner positions add a 24px side inset so the toast does not sit flush against the viewport edge; the centred ones keep the full width to centre in, which is why `bottom-center` is unchanged from before the axis existed.
157
+ - Top-anchored toasts animate in from the top edge (`fadeInDown`) rather than sliding upward, which would have read as the toast escaping its own anchor.
158
+ - **Toasts at the same `position` stack automatically.** No wrapper element and no change to your markup: each `rel-toast` registers itself, and up to `max-visible` (default 3) show at once with the newest against the anchor edge. Dismissing one closes the gap for the rest, animated. The six positions are independent stacks, and a toast whose `position` changes while it is showing leaves one and joins the other.
159
+ - **Overflow waits; it is never dropped.** Beyond `max-visible`, further toasts queue in arrival order and appear as earlier ones dismiss. A toast's `duration` does not begin until it is actually on screen, so a queued message cannot expire before anyone has seen it. *Behaviour change*: five toasts at one position used to render on top of each other — now three show and two wait.
160
+ - A single toast is unaffected by any of this: the stack only writes a transform from the second card onward, so a lone toast renders exactly as it did before stacking existed.
153
161
  - The auto-dismiss timer starts only when `show` changes to true; changing `duration` on a visible toast does not restart it. Re-showing a visible toast (setting `show = true` again) is a no-op because the value did not change — `close()` it first.
154
162
  - `close()` always fires `dismissed`, even when the toast was already hidden.
155
163
  - The action button's hover state swaps to `--rel-bg-neutral` / `--rel-text-default` at 75% opacity.
@@ -60,9 +60,10 @@ Hover/focus tooltip implementing the Figma "Tooltip" component: wraps a trigger
60
60
  | Property | Attribute | Type | Default | Description |
61
61
  | --- | --- | --- | --- | --- |
62
62
  | `text` | `text` | `string` | `""` | Plain-text content of the bubble. Empty text still renders an (empty) bubble on hover, so always set it. |
63
- | `position` | `position` | `"above" \| "below" \| "left" \| "right"` | `"above"` | Side of the trigger the bubble appears on, 6px away and centred: `above`, `below`, `left` or `right`. No collision detection — pick a side with room in the viewport. |
63
+ | `position` | `position` | `"above" \| "below" \| "left" \| "right"` | `"above"` | Side of the trigger the bubble appears on, centred and 6px away (13px when `show-tail` is set, so the tail clears the trigger; override with `--rel-tooltip-offset`): `above`, `below`, `left` or `right`. No collision detection — pick a side with room in the viewport. |
64
64
  | `showTail` | `show-tail` | `boolean` | `false` | Renders the triangular tail (`indicator` part) on the bubble's edge facing the trigger. |
65
- | `type` | `type` | `"single-line" \| "multi-line"` | `"single-line"` | Figma "Type": `single-line` keeps the text on one line and sizes to content; `multi-line` wraps inside a 220px max-width bubble. Reflected. |
65
+ | `type` | `type` | `"single-line" \| "multi-line"` | `"single-line"` | Figma "Type": `single-line` keeps the text on one line and sizes to content; `multi-line` wraps inside a 200px max-width bubble. Reflected. |
66
+ | `tone` | `tone` | `"inverse" \| "neutral"` | `"inverse"` | Bubble appearance: `inverse` (default) is the original inverse-surface bubble, unchanged; `neutral` is a light surface — `--rel-bg-neutral` with `--rel-text-default` and a 1px `--rel-border-default`, tail included. Figma has no such variant; this is a deliberate addition. Reflected. |
66
67
 
67
68
  ## Events
68
69
 
@@ -83,6 +84,16 @@ Hover/focus tooltip implementing the Figma "Tooltip" component: wraps a trigger
83
84
  | `panel` | The tooltip bubble (`role="tooltip"`): background, padding, radius, shadow and max-width. |
84
85
  | `indicator` | The triangular tail pointing at the trigger, rendered only when `show-tail` is set. |
85
86
 
87
+ ## Tokens / CSS Variables
88
+
89
+ ### Component hooks
90
+
91
+ Set these on the host (or an ancestor) to customise the element without touching design tokens.
92
+
93
+ | Custom property | Default | Description |
94
+ | --- | --- | --- |
95
+ | `--rel-tooltip-offset` | `6px` | Gap between the trigger and the bubble; defaults to `6px`, or `13px` when `show-tail` is set so the tail clears the trigger. |
96
+
86
97
  <!-- readme-gen:end -->
87
98
 
88
99
  ## Accessibility
@@ -146,7 +146,7 @@ File upload: `<rel-upload>` renders the dropzone, the format / size hint, the st
146
146
 
147
147
  | Part | Description |
148
148
  | --- | --- |
149
- | — | None exposed. |
149
+ | `browse` | The `rel-button` that opens the file picker (Figma "Browse Button": Size=Medium, Style=Secondary). |
150
150
 
151
151
  ### Tokens / CSS Variables
152
152
 
@@ -156,7 +156,7 @@ Set these on the host (or an ancestor) to customise the element without touching
156
156
 
157
157
  | Custom property | Default | Description |
158
158
  | --- | --- | --- |
159
- | `--rel-upload-browse-hover-bg` | `var(--rel-action-neutral-outline-hover, var(--rel-bg-surface-elevated))` | Background of the Browse button on hover; falls back to `--rel-action-neutral-outline-hover`, then `--rel-bg-surface-elevated` |
159
+ | `--rel-upload-browse-hover-bg` | `transparent` | Background of the Browse button on hover. Defaults to `transparent`, which is what the underlying `rel-button` secondary style draws (Figma's outline button reacts on its border, not its fill), so this only takes effect when you set it. |
160
160
 
161
161
  ### `<rel-upload-actions>`
162
162