@reliability-design/web 1.4.6 → 1.4.8

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 (148) hide show
  1. package/CHANGELOG.md +246 -49
  2. package/dist/components/rel-accordion/README.md +133 -132
  3. package/dist/components/rel-alert/README.md +145 -141
  4. package/dist/components/rel-autocomplete/README.md +172 -61
  5. package/dist/components/rel-avatar/README.md +118 -130
  6. package/dist/components/rel-badge/README.md +97 -93
  7. package/dist/components/rel-breadcrumb/README.md +96 -102
  8. package/dist/components/rel-button/README.md +190 -130
  9. package/dist/components/rel-calendar/README.md +109 -109
  10. package/dist/components/rel-card/README.md +75 -94
  11. package/dist/components/rel-cardmedia/README.md +100 -127
  12. package/dist/components/rel-carousel/README.md +186 -166
  13. package/dist/components/rel-checkbox/README.md +96 -75
  14. package/dist/components/rel-chip/README.md +138 -121
  15. package/dist/components/rel-container/README.md +107 -99
  16. package/dist/components/rel-date-picker/README.md +200 -289
  17. package/dist/components/rel-divider/README.md +88 -100
  18. package/dist/components/rel-drawer/README.md +187 -200
  19. package/dist/components/rel-kbd/README.md +141 -151
  20. package/dist/components/rel-layout/README.md +34 -0
  21. package/dist/components/rel-menu/README.md +180 -151
  22. package/dist/components/rel-menubar/README.md +218 -329
  23. package/dist/components/rel-otp/README.md +171 -440
  24. package/dist/components/rel-pagination/README.md +100 -424
  25. package/dist/components/rel-popover/README.md +203 -568
  26. package/dist/components/rel-progress/README.md +88 -110
  27. package/dist/components/rel-radio/README.md +131 -138
  28. package/dist/components/rel-range-picker/README.md +165 -0
  29. package/dist/components/rel-resizable/README.md +199 -140
  30. package/dist/components/rel-segmented-button/README.md +156 -141
  31. package/dist/components/rel-select/README.md +156 -93
  32. package/dist/components/rel-sheet/README.md +168 -224
  33. package/dist/components/rel-skeleton/README.md +104 -0
  34. package/dist/components/rel-slider/README.md +131 -135
  35. package/dist/components/rel-snackbar/README.md +168 -134
  36. package/dist/components/rel-stepper/README.md +162 -160
  37. package/dist/components/rel-switch/README.md +117 -102
  38. package/dist/components/rel-tab/README.md +173 -163
  39. package/dist/components/rel-textfield/README.md +176 -69
  40. package/dist/components/rel-time-picker/README.md +122 -157
  41. package/dist/components/rel-toast/README.md +165 -148
  42. package/dist/components/rel-tooltip/README.md +119 -111
  43. package/dist/components/rel-upload/README.md +220 -0
  44. package/dist/index.d.mts +1726 -447
  45. package/dist/index.d.ts +1726 -447
  46. package/dist/index.js +13715 -10870
  47. package/dist/index.js.map +1 -1
  48. package/dist/index.mjs +14018 -11163
  49. package/dist/index.mjs.map +1 -1
  50. package/dist/styles/focus-ring.ts +84 -0
  51. package/dist/styles/vars.css +892 -866
  52. package/dist/{vars-XNMTSRVN.css → vars-DXX6QOAG.css} +892 -866
  53. package/package.json +3 -2
  54. package/dist/components/rel-accordion/rel-accordion.ts +0 -336
  55. package/dist/components/rel-alert/rel-alert.ts +0 -305
  56. package/dist/components/rel-autocomplete/rel-autocomplete.ts +0 -720
  57. package/dist/components/rel-avatar/rel-avatar.ts +0 -142
  58. package/dist/components/rel-badge/rel-badge.ts +0 -175
  59. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +0 -106
  60. package/dist/components/rel-button/rel-button.ts +0 -560
  61. package/dist/components/rel-calendar/index.ts +0 -1
  62. package/dist/components/rel-calendar/rel-calendar.ts +0 -565
  63. package/dist/components/rel-card/rel-card.ts +0 -88
  64. package/dist/components/rel-cardmedia/rel-cardmedia.ts +0 -88
  65. package/dist/components/rel-carousel/index.ts +0 -1
  66. package/dist/components/rel-carousel/rel-carousel.ts +0 -723
  67. package/dist/components/rel-chart/README.md +0 -286
  68. package/dist/components/rel-chart/index.ts +0 -1
  69. package/dist/components/rel-chart/rel-chart.ts +0 -754
  70. package/dist/components/rel-checkbox/rel-checkbox.ts +0 -382
  71. package/dist/components/rel-chip/rel-chip.ts +0 -483
  72. package/dist/components/rel-container/rel-container.ts +0 -95
  73. package/dist/components/rel-date-picker/date-format.test.ts +0 -43
  74. package/dist/components/rel-date-picker/date-format.ts +0 -47
  75. package/dist/components/rel-date-picker/date-parse.test.ts +0 -116
  76. package/dist/components/rel-date-picker/date-parse.ts +0 -178
  77. package/dist/components/rel-date-picker/index.ts +0 -1
  78. package/dist/components/rel-date-picker/rel-date-picker.ts +0 -1676
  79. package/dist/components/rel-divider/rel-divider.ts +0 -54
  80. package/dist/components/rel-drawer/index.ts +0 -1
  81. package/dist/components/rel-drawer/rel-drawer-footer.ts +0 -27
  82. package/dist/components/rel-drawer/rel-drawer.ts +0 -607
  83. package/dist/components/rel-kbd/rel-kbd.ts +0 -188
  84. package/dist/components/rel-layout/rel-layout.ts +0 -49
  85. package/dist/components/rel-menu/rel-menu.ts +0 -541
  86. package/dist/components/rel-menubar/index.ts +0 -2
  87. package/dist/components/rel-menubar/rel-menubar-menu.css +0 -3
  88. package/dist/components/rel-menubar/rel-menubar-menu.ts +0 -17
  89. package/dist/components/rel-menubar/rel-menubar.ts +0 -777
  90. package/dist/components/rel-nav-menu/README.md +0 -289
  91. package/dist/components/rel-nav-menu/index.ts +0 -3
  92. package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +0 -243
  93. package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +0 -72
  94. package/dist/components/rel-nav-menu/rel-nav-menu.ts +0 -270
  95. package/dist/components/rel-navbar/README.md +0 -126
  96. package/dist/components/rel-navbar/rel-navbar.ts +0 -105
  97. package/dist/components/rel-otp/index.ts +0 -1
  98. package/dist/components/rel-otp/rel-otp.ts +0 -527
  99. package/dist/components/rel-pagination/index.ts +0 -1
  100. package/dist/components/rel-pagination/rel-pagination.ts +0 -522
  101. package/dist/components/rel-popover/index.ts +0 -2
  102. package/dist/components/rel-popover/rel-popover-content.ts +0 -81
  103. package/dist/components/rel-popover/rel-popover.ts +0 -475
  104. package/dist/components/rel-progress/rel-progress.ts +0 -234
  105. package/dist/components/rel-radio/rel-radio.ts +0 -481
  106. package/dist/components/rel-range-picker/rel-range-picker.ts +0 -1688
  107. package/dist/components/rel-resizable/index.ts +0 -3
  108. package/dist/components/rel-resizable/rel-resizable-group.ts +0 -405
  109. package/dist/components/rel-resizable/rel-resizable-handle.ts +0 -150
  110. package/dist/components/rel-resizable/rel-resizable-panel.ts +0 -58
  111. package/dist/components/rel-segmented-button/rel-segmented-button.ts +0 -217
  112. package/dist/components/rel-select/rel-select.ts +0 -1416
  113. package/dist/components/rel-sheet/rel-sheet.ts +0 -610
  114. package/dist/components/rel-sidebar/README.md +0 -209
  115. package/dist/components/rel-sidebar/rel-sidebar.ts +0 -1191
  116. package/dist/components/rel-skeleton/rel-skeleton.ts +0 -143
  117. package/dist/components/rel-slider/rel-slider.ts +0 -673
  118. package/dist/components/rel-snackbar/rel-snackbar.ts +0 -329
  119. package/dist/components/rel-stepper/rel-stepper.ts +0 -567
  120. package/dist/components/rel-switch/rel-switch.ts +0 -199
  121. package/dist/components/rel-tab/rel-tab.ts +0 -264
  122. package/dist/components/rel-table/README.md +0 -178
  123. package/dist/components/rel-table/rel-table-body.ts +0 -22
  124. package/dist/components/rel-table/rel-table-caption.ts +0 -30
  125. package/dist/components/rel-table/rel-table-cell.ts +0 -43
  126. package/dist/components/rel-table/rel-table-footer.ts +0 -24
  127. package/dist/components/rel-table/rel-table-head.ts +0 -47
  128. package/dist/components/rel-table/rel-table-header.ts +0 -22
  129. package/dist/components/rel-table/rel-table-row.ts +0 -37
  130. package/dist/components/rel-table/rel-table.ts +0 -62
  131. package/dist/components/rel-textfield/rel-textfield.ts +0 -1054
  132. package/dist/components/rel-time-picker/rel-time-picker.ts +0 -1482
  133. package/dist/components/rel-time-picker/time-parse.test.ts +0 -67
  134. package/dist/components/rel-time-picker/time-parse.ts +0 -85
  135. package/dist/components/rel-toast/rel-toast.ts +0 -206
  136. package/dist/components/rel-tooltip/rel-tooltip.ts +0 -193
  137. package/dist/components/rel-topbar/rel-topbar-actions.ts +0 -27
  138. package/dist/components/rel-topbar/rel-topbar-brand.ts +0 -54
  139. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +0 -69
  140. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +0 -31
  141. package/dist/components/rel-topbar/rel-topbar-item.ts +0 -324
  142. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +0 -27
  143. package/dist/components/rel-topbar/rel-topbar-profile.ts +0 -243
  144. package/dist/components/rel-topbar/rel-topbar-utilities.ts +0 -27
  145. package/dist/components/rel-topbar/rel-topbar.ts +0 -446
  146. package/dist/components/rel-upload/UPLOAD-DESIGN-CHANGES.md +0 -134
  147. package/dist/components/rel-upload/rel-upload-actions.ts +0 -163
  148. package/dist/components/rel-upload/rel-upload.ts +0 -968
package/dist/index.d.ts CHANGED
@@ -3,13 +3,45 @@ import * as lit from 'lit';
3
3
  import { LitElement, PropertyValues, TemplateResult } from 'lit';
4
4
  export * from '@reliability-design/icons';
5
5
 
6
+ /**
7
+ * Single collapsible section (Figma "Accordion", 6021:1085): a clickable header
8
+ * that expands/collapses the slotted body with an animated chevron.
9
+ * @slot - Body content, revealed when `open`
10
+ * @slot icon - Leading icon in the header (`type="action"` only); replaces the default rotating chevron-down
11
+ * @slot trailing-icon - Trailing icon in the header; replaces the default chevron-down (default type) or arrow-expansion (action type)
12
+ * @csspart base - The outer card (`.accordion`) carrying the appearance border / shadow
13
+ * @csspart trigger - The `role="button"` header row
14
+ * @csspart label - The title row (leading icon + title text)
15
+ * @csspart icon - The trailing icon wrapper
16
+ * @csspart content - The `role="region"` body that holds the default slot
17
+ */
6
18
  declare class RelAccordion extends LitElement {
19
+ /** Header text. Note it is also the native HTML `title` attribute, so browsers show it as a tooltip on hover. */
7
20
  title: string;
21
+ /** Whether the body is expanded; toggled by the header and reported via `open-change`. Setting it from code does not fire the event. */
8
22
  open: boolean;
9
- size: "md" | "sm";
23
+ /**
24
+ * Header scale (Figma "Size"): `large` = 56px header / heading-md title, `medium` = 48px / heading-sm,
25
+ * `small` = 44px / heading-xs (new in 1.4.7). The historical spellings stay supported as aliases:
26
+ * `md` = large (the default), `sm` = medium.
27
+ */
28
+ size: "md" | "sm" | "large" | "medium" | "small";
29
+ /**
30
+ * Header layout (Figma "Type"): `default` = title + trailing rotating chevron; `action` = leading icon slot (rotating chevron by default) + static trailing arrow-expansion icon, with the body indented under the title.
31
+ *
32
+ * DELIBERATE DIVERGENCE — do not "fix" this to a button. For `Type=Action`
33
+ * Figma draws the trailing affordance as a full ghost icon Button instance
34
+ * (Size=Medium 40x40, Size=Small 32x32, Style=Ghost, Type=Icon Only); the
35
+ * code keeps a bare icon. Ruled by the user: our behaviour stands and the
36
+ * DESIGN FILE follows our docs here, not the other way round. The whole
37
+ * header is the click target, so a nested button would add a second
38
+ * focusable control inside it and two competing hit areas.
39
+ */
10
40
  type: "default" | "action";
11
- /** Figma "Style" axis — named appearance because `style` collides with the HTML style attribute. */
41
+ /** Figma "Style" axis — named appearance because `style` collides with the HTML style attribute. `shadow` = 4px-radius card with the shadow-sm effect and no border; `plain` = square corners with a 1px border-subtle stroke and no elevation. */
12
42
  appearance: "shadow" | "plain";
43
+ /** Figma "State=Disabled": dims the whole component to 40% and blocks toggling by pointer and keyboard. The header keeps its fill and stroke — the dulling is opacity alone, as Figma specifies. */
44
+ disabled: boolean;
13
45
  static styles: lit.CSSResult;
14
46
  /** Stable id prefix wiring the header to its panel. */
15
47
  private accordionId;
@@ -17,15 +49,44 @@ declare class RelAccordion extends LitElement {
17
49
  render(): lit_html.TemplateResult<1>;
18
50
  }
19
51
 
52
+ /** Canonical semantic tones (Figma "Tone"). */
53
+ type AlertTone = "neutral" | "info" | "success" | "warning" | "destructive";
54
+ /** Deprecated tone spellings, all mapped to "destructive". */
55
+ type AlertToneAlias = "error" | "danger" | "critical";
56
+ type AlertToneInput = AlertTone | AlertToneAlias;
57
+ /**
58
+ * Inline status banner (Figma "Alert"): a tone-coloured box with a leading status icon, a bold title, optional supporting text, an optional link and an optional dismiss button. Use it for persistent page- or section-level messages; use `rel-toast` / `rel-snackbar` for transient feedback.
59
+ * @csspart base - The `role="alert"` container that carries the tone and appearance styling
60
+ * @csspart icon - Wrapper around the leading status `<rel-icon>`
61
+ * @csspart content - Column that stacks the title, helper text and link
62
+ * @csspart label - The primary message (`message1`) paragraph
63
+ * @csspart helper - The secondary message (`message2`) paragraph; rendered only when `message2` is set
64
+ * @csspart action - The inline link; rendered only when both `url-text` and `url-href` are set
65
+ * @csspart close-button - The dismiss (✕) button; rendered only while `dismissible` is true
66
+ */
20
67
  declare class RelAlert extends LitElement {
21
- type: "info" | "success" | "warning" | "error" | "neutral";
22
- /** Visual treatment (Figma "Style"): solid | subtle | outline. "filled" is a deprecated alias of solid. */
68
+ /**
69
+ * Semantic tone (Figma "Tone"): `"neutral"` (default) | `"info"` | `"success"` | `"warning"` | `"destructive"`. Drives the fill/border colour, the title colour and the leading icon (info, check-circle, alert-circle, error). `"error"`, `"danger"` and `"critical"` are deprecated aliases of `"destructive"` and log a one-time console notice. Takes precedence over the deprecated `type` prop.
70
+ */
71
+ tone?: AlertToneInput;
72
+ /** @deprecated 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. */
73
+ type?: AlertToneInput;
74
+ /** Read-only canonical tone actually rendered: explicit `tone` wins, else `type`, else `"neutral"`; deprecated aliases are resolved to `"destructive"`. */
75
+ get resolvedTone(): AlertTone;
76
+ willUpdate(changed: Map<string, unknown>): void;
77
+ /** Visual treatment (Figma "Style"): `"subtle"` (default: tone-light fill, no border) | `"solid"` (tone fill, inverse text, `--rel-shadows-md` elevation) | `"outline"` (transparent fill, tone border). `"filled"` is a deprecated alias of `"solid"` (no console notice). */
23
78
  appearance: "solid" | "subtle" | "outline" | "filled";
79
+ /** Primary message (title), rendered in body-lg medium weight in the tone colour. */
24
80
  message1: string;
81
+ /** Optional secondary message rendered under the title in body-md at 90% opacity; omitted when unset. */
25
82
  message2?: string;
83
+ /** Text of the inline link rendered under the messages. The link appears only when both `urlText` and `urlHref` are set. */
26
84
  urlText?: string;
85
+ /** `href` of the inline link. The link appears only when both `urlText` and `urlHref` are set. */
27
86
  urlHref?: string;
87
+ /** Shows the dismiss (✕) 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. */
28
88
  dismissible: boolean;
89
+ /** True once the alert has been dismissed; hides the host via `:host([dismissed]) { display: none }`. Set it back to `false` to show the alert again. */
29
90
  dismissed: boolean;
30
91
  static styles: lit.CSSResult;
31
92
  private dismissAlert;
@@ -52,12 +113,37 @@ type TextFieldPrefixStyle = "clear" | "divider" | "fill";
52
113
  * `fieldAriaLabelledby` to keep an accessible name
53
114
  */
54
115
  type FieldLabelStyle = "default" | "floating" | "none";
116
+ /**
117
+ * `<rel-textfield>` — single-line or multi-line text input (Figma "Text Field").
118
+ * @slot prefix - Custom content at the far left of the control (e.g. a unit dropdown); shares the prefix block with `prefixIcon` / `prefixText`. Hidden when `multiline` is set.
119
+ * @slot suffix - Custom content at the far right of the control (e.g. an action button); shares the suffix block with `rightIcon` / `suffixText`. Hidden when `multiline` is set.
120
+ * @csspart label - The visible label element (default and floating label styles)
121
+ * @csspart control - The bordered control box (the fieldset in the legend variant)
122
+ * @csspart input - The native input / textarea
123
+ * @csspart prefix - The prefix block (leading icon, prefix text and the `prefix` slot)
124
+ * @csspart suffix - The suffix block (suffix text, trailing icon and the `suffix` slot)
125
+ * @csspart right-icon - The trailing `rel-icon`
126
+ * @csspart helper - The helper / error text line below the control
127
+ * @csspart helper-icon - The leading `rel-icon` in the helper line; rendered only when `helper-icon` is set and there is helper text
128
+ * @cssprop --rel-field-label-reserve - 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).
129
+ * @cssprop --rel-textfield-surface - Colour the floating label's strip paints to mask the border behind it; defaults to the control's own fill (`--rel-bg-neutral`). Set it when the field sits on a tinted or elevated surface, otherwise the strip shows as a light dash across the border.
130
+ */
55
131
  declare class RelTextfield extends LitElement {
132
+ /**
133
+ * Visible label text. Rendered above the control (default), inside it as a
134
+ * floating label (`labelStyle="floating"`) or as the notch of the `legend`
135
+ * variant; omitted entirely under `labelStyle="none"`.
136
+ */
56
137
  label?: string;
138
+ /** Placeholder shown while the field is empty. Under the floating label style it stays hidden until the field is focused. */
57
139
  placeholder: string;
140
+ /** Native input `type` (`text`, `email`, `password`, `number`, …). Ignored when `multiline` is set. */
58
141
  type: string;
142
+ /** Current text. Updated on every keystroke; set it to control the field programmatically. */
59
143
  value: string;
144
+ /** Legacy name for the leading icon (a `rel-icon` name). `prefixIcon` wins when both are set. */
60
145
  leftIcon?: string;
146
+ /** Trailing `rel-icon` name rendered in the suffix block. Decorative unless `clickableRightIcon` is set. */
61
147
  rightIcon?: string;
62
148
  /** Makes the trailing icon interactive (pointer + focusable) and emits
63
149
  * `rel-right-icon-click` — e.g. a password show/hide toggle or clear button. */
@@ -75,8 +161,15 @@ declare class RelTextfield extends LitElement {
75
161
  suffixText?: string;
76
162
  /** Draws a hairline between the input and the suffix block. */
77
163
  suffixDivider: boolean;
164
+ /** Legacy name for the helper line below the control. `helperText` wins when both are set. */
78
165
  supportingText?: string;
166
+ /**
167
+ * Legacy visual state. `"error"` / `"disabled"` behave like the `error` /
168
+ * `disabled` booleans, which are preferred and take precedence. Typing into a
169
+ * `state="error"` field resets it to `"default"` until the value is emptied again.
170
+ */
79
171
  state: TextFieldState;
172
+ /** Control height — `small` 32px, `medium` 40px, `large` 48px — which also scales the text and the affix icons. */
80
173
  size: TextFieldSize;
81
174
  /**
82
175
  * Label presentation. Left `undefined` the deprecated `floatingLabel` boolean
@@ -94,19 +187,35 @@ declare class RelTextfield extends LitElement {
94
187
  fieldAriaLabel?: string;
95
188
  /** IDREF list of external element(s) naming the input. Wins over `fieldAriaLabel`. */
96
189
  fieldAriaLabelledby?: string;
190
+ /** Field chrome: `default` outlined box, `underline` bottom border only, `legend` notched outline with the label sitting in the top border (native fieldset/legend). */
97
191
  variant: TextFieldVariant;
192
+ /** Disables the input (not focusable, not editable) and dims the control. */
98
193
  disabled: boolean;
194
+ /** Marks the input required: sets native `required` / `aria-required` and appends an asterisk to the label. */
99
195
  required: boolean;
196
+ /** Renders a textarea instead of a single-line input (see `rows`). Prefix/suffix blocks and `type` are ignored in this mode. */
100
197
  multiline: boolean;
198
+ /** Visible text rows of the textarea when `multiline` is set. */
101
199
  rows: number;
200
+ /** Leading `rel-icon` name rendered in the prefix block (preferred over the legacy `leftIcon`). */
102
201
  prefixIcon?: string;
202
+ /** Accessible label for the leading icon. Without it the icon is `aria-hidden` (decorative). */
103
203
  prefixIconAriaLabel?: string;
204
+ /** Puts the field in the error state: danger border, `aria-invalid`, and `errorMessage` replacing the helper text. */
104
205
  error: boolean;
206
+ /** Text shown below the control instead of `helperText` while the field is in the error state. */
105
207
  errorMessage?: string;
208
+ /** Helper line below the control (preferred over the legacy `supportingText`); linked to the input via `aria-describedby`. */
106
209
  helperText?: string;
210
+ /** 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. */
211
+ helperIcon?: string;
212
+ /** Makes the input read-only: focusable and selectable but not editable. */
107
213
  readonly: boolean;
214
+ /** Maximum number of characters (native `maxlength`). */
108
215
  maxLength?: number;
216
+ /** Form field name forwarded to the native input, for form submission and autofill. */
109
217
  name?: string;
218
+ /** Fills the parent width as a block element (default). Unset it to render inline at the content's natural width. */
110
219
  fullWidth: boolean;
111
220
  private internalState;
112
221
  /** Whether the `prefix` / `suffix` named slots currently have content. */
@@ -126,6 +235,16 @@ declare class RelTextfield extends LitElement {
126
235
  connectedCallback(): void;
127
236
  disconnectedCallback(): void;
128
237
  private handleSlotChange;
238
+ /**
239
+ * The whole control is the input's hit area. The input already stretches
240
+ * to the row (CSS), but the control's own border, the legend notch, and
241
+ * any padding around slotted content are still container pixels — press
242
+ * there and focus the input, as clicking a <label> would. Skipped when the
243
+ * press is on the input itself (native caret placement), a clickable icon,
244
+ * or slotted content (their own behaviour), and when disabled.
245
+ * preventDefault keeps the press from moving focus to the body first.
246
+ */
247
+ private handleControlMousedown;
129
248
  /** Clicking the (non-interactive) prefix/suffix area focuses the input, as a
130
249
  * label would. Clickable icons and slotted controls keep their own clicks. */
131
250
  private handleAffixClick;
@@ -145,7 +264,191 @@ declare class RelTextfield extends LitElement {
145
264
  render(): lit_html.TemplateResult<1>;
146
265
  }
147
266
 
148
- /** An item is a plain string or any object read through displayField/valueField. */
267
+ type CheckboxState = "default" | "error" | "disabled";
268
+ type CheckboxStatus = "unchecked" | "checked" | "indeterminate";
269
+ type CheckboxSize = "small" | "medium" | "large" | "extra-large";
270
+ type CheckboxDensity = "compact" | "comfortable";
271
+ type CheckboxAlignment = "leading" | "trailing";
272
+ /**
273
+ * Tri-state checkbox (Figma "Checkbox"): a hidden native checkbox behind a custom box, with label, optional prefix icon and supporting text.
274
+ * @csspart base - The outer wrapper that carries the `state` / `status` classes
275
+ * @csspart label - The visible label text
276
+ * @csspart helper - The supporting text (rendered beside the box in comfortable density, under the row in compact)
277
+ */
278
+ declare class RelCheckbox extends LitElement {
279
+ /** Label text rendered next to the box. */
280
+ label: string;
281
+ /** rel-icon name rendered between the checkbox and the label (label prefix icon); scales with `size`. Unset renders no icon and reserves no space. */
282
+ icon: string;
283
+ /** Supporting text under or beside the label; where it renders depends on `density`. */
284
+ supportingtext: string;
285
+ /** Visual and interaction state (Figma State): `"error"` swaps in the danger colours, `"disabled"` blocks input and dims the whole control to 0.4 opacity (colours unchanged, as Figma specifies). */
286
+ state: CheckboxState;
287
+ /** Check state. `"indeterminate"` is programmatic-only — a user toggle always resolves to checked or unchecked. */
288
+ status: CheckboxStatus;
289
+ /** Value reported in the `rel-change` event detail (it is not submitted with a form). */
290
+ value: string;
291
+ /** Control scale (Figma Size), on Figma's four-step ramp of control frames:
292
+ * `"small"` 16px / body-sm, `"medium"` (default) 18px / body-md,
293
+ * `"large"` 20px / body-lg, `"extra-large"` 24px / body-xl. The drawn
294
+ * square is inset to 80% of the frame, so the frame is the layout
295
+ * footprint (what the row gap and the compact indent measure from) rather
296
+ * than the visible square. */
297
+ size: CheckboxSize;
298
+ /** Supporting-text layout (Figma Density). `"compact"` (default) puts the
299
+ * supporting text on its own line under the row, indented past the box;
300
+ * `"comfortable"` stacks label + supporting text beside the box. */
301
+ density: CheckboxDensity;
302
+ /** Box position (Figma Alignment). `"leading"` (default) renders the box
303
+ * before the label; `"trailing"` pushes it to the far edge of the row.
304
+ * Trailing has no compact layout in the spec, so it always renders with
305
+ * comfortable density. */
306
+ alignment: CheckboxAlignment;
307
+ /** Boolean view of `status`: `true` when `status === "checked"`; setting it writes `"checked"` / `"unchecked"`. */
308
+ get checked(): boolean;
309
+ set checked(val: boolean);
310
+ private _onChange;
311
+ private _onTouched;
312
+ static styles: lit.CSSResult;
313
+ protected willUpdate(changed: PropertyValues<this>): void;
314
+ /** Trailing has no compact layout in the spec — trailing wins. */
315
+ private get effectiveDensity();
316
+ private toggle;
317
+ /** @internal Angular ControlValueAccessor bridge. */
318
+ registerOnChange(fn: (value: boolean) => void): void;
319
+ /** @internal Angular ControlValueAccessor bridge. */
320
+ registerOnTouched(fn: () => void): void;
321
+ /** @internal Angular ControlValueAccessor bridge. */
322
+ writeValue(checked: boolean): void;
323
+ render(): lit_html.TemplateResult<1>;
324
+ }
325
+
326
+ /** Diameter step, spelled out. */
327
+ type AvatarSize = "large" | "medium" | "small" | "extra-small";
328
+ /** Alternative spellings, not deprecations — the short names keep working. */
329
+ type AvatarSizeAlias = "lg" | "md" | "sm" | "xs";
330
+ type AvatarSizeInput = AvatarSize | AvatarSizeAlias;
331
+ /**
332
+ * Circular avatar (Figma "Avatar"): shows a photo, text initials or a slotted icon in one of four sizes and three fill variants.
333
+ * @slot - Icon content rendered when `type="icon"` (typically an inline SVG, sized 20 / 18 / 16 / 12px by `size`)
334
+ * @csspart base - The circular wrapper that carries the size, variant and inline `bg` / `color` overrides
335
+ * @csspart icon - The `<img>` (`type="image"`) or the icon wrapper span around the slot (`type="icon"`)
336
+ * @csspart label - The `<span>` holding the initials when `type="text"`
337
+ * @cssprop --rel-avatar-bg-fill - Background colour of the `fill` variant
338
+ * @cssprop --rel-avatar-color-fill - Text / icon colour of the `fill` variant
339
+ * @cssprop --rel-avatar-bg-subtle - Background colour of the `subtle` variant
340
+ * @cssprop --rel-avatar-color-subtle - Text / icon colour of the `subtle` variant
341
+ * @cssprop --rel-avatar-border-outline - 1px border colour of the `outline` variant
342
+ * @cssprop --rel-avatar-color-outline - Text / icon colour of the `outline` variant
343
+ * @cssprop --rel-avatar-icon-size - Overrides the slotted icon's size; defaults to the preset ramp (20 / 18 / 16 / 12px)
344
+ * @cssprop --rel-avatar-bg-outline - Background colour of the `outline` variant; defaults to --rel-bg-neutral
345
+ * @cssprop --rel-avatar-size - Overrides the circle's width/height for sizes between (or below) the `size` presets; defaults to the preset's diameter
346
+ * @cssprop --rel-avatar-font-size - Overrides the initials' font-size, for use alongside `--rel-avatar-size`; defaults to the preset's text role
347
+ */
348
+ declare class RelAvatar extends LitElement {
349
+ /** Diameter step: `large` 40px, `medium` 32px, `small` 24px, `extra-small` 20px; each binds the matching body-*-semibold text role for initials. `lg` / `md` / `sm` / `xs` are alternative spellings and stay supported — they are normalised to the full words, not deprecated. */
350
+ size: AvatarSizeInput;
351
+ /** What is rendered inside the circle: `image` shows `src`, `text` shows the `text` initials, `icon` shows the default slot. */
352
+ type: "image" | "text" | "icon";
353
+ /** Fill style: `fill` = solid inverse background with light text, `subtle` = elevated neutral background, `outline` = transparent with a 1px border. */
354
+ variant: "fill" | "subtle" | "outline";
355
+ /** Image URL for `type="image"`; when empty nothing is rendered inside the circle (there is no fallback to initials). */
356
+ src: string;
357
+ /** Initials shown for `type="text"`; rendered uppercase via `text-transform`. */
358
+ text: string;
359
+ /** Alt text of the `<img>` for `type="image"`; the default is the generic word "Avatar", so pass the person's name. */
360
+ alt: string;
361
+ /** Any CSS colour applied inline as `background-color` on the circle, overriding the variant background. */
362
+ bg: string;
363
+ /** Any CSS colour applied inline as `color` on the circle (initials / icon), overriding the variant text colour. */
364
+ color: string;
365
+ static styles: lit.CSSResult;
366
+ /** Alternative spellings, NOT deprecations — no console notice. Normalising
367
+ * the property rather than duplicating every selector keeps the reflected
368
+ * attribute and the rendered class canonical, so only one spelling reaches
369
+ * the CSS. Same shape as rel-chip and rel-slider. */
370
+ protected willUpdate(changed: Map<string, unknown>): void;
371
+ render(): lit_html.TemplateResult<1>;
372
+ }
373
+
374
+ /** Canonical semantic tones (Figma "Tone"): neutral | destructive | warning | success | info. */
375
+ type ChipTone = "neutral" | "destructive" | "warning" | "success" | "info";
376
+ /** Deprecated spelling: "danger" → destructive. */
377
+ type ChipToneAlias = "danger";
378
+ type ChipToneInput = ChipTone | ChipToneAlias;
379
+ /** Canonical emphasis (Figma "Style"): fill | subtle. */
380
+ type ChipVariant = "fill" | "subtle";
381
+ /** Figma's own spellings of the Style axis, accepted as alternatives. */
382
+ type ChipVariantAlias = "primary" | "secondary";
383
+ type ChipVariantInput = ChipVariant | ChipVariantAlias;
384
+ /** Canonical size steps — full words, as elsewhere in the library. */
385
+ type ChipSize = "small" | "medium" | "large";
386
+ /** Short size spellings, accepted as alternatives. */
387
+ type ChipSizeAlias = "sm" | "md" | "lg";
388
+ type ChipSizeInput = ChipSize | ChipSizeAlias;
389
+ type ChipBorder = "default" | "rounded";
390
+ /**
391
+ * Compact chip (Figma "Chip") for tags, filters and selected values: tone x variant
392
+ * colouring, optional leading icon / avatar / trailing icon, a remove control and
393
+ * opt-in drag-and-drop.
394
+ * @csspart base - The chip body (`.chip`) that carries size, tone, variant and border styling
395
+ * @csspart icon - The leading `<rel-icon>` (rendered only when `leading-icon` is set and no avatar)
396
+ * @csspart label - The label text
397
+ * @cssprop --rel-chip-focus-ring - Colour of the keyboard focus outline; default `var(--rel-border-focus)`
398
+ */
399
+ declare class RelChip extends LitElement {
400
+ static shadowRootOptions: ShadowRootInit;
401
+ /** Text shown in the chip; also its accessible name and the drag payload. */
402
+ label: string;
403
+ /** Colour tone (Figma Tone): `neutral`, `destructive`, `warning`, `success` or `info`. Combined with `variant`. `"danger"` is a deprecated alias of `"destructive"`: it keeps working, logs a one-time console notice, and is normalised to `"destructive"` on the property and the reflected attribute. */
404
+ tone: ChipToneInput;
405
+ /** Emphasis (Figma Style): `fill` = solid tone background, `subtle` = tinted background with tone-coloured text. Figma's own spellings `primary` and `secondary` are accepted and normalised to `fill` / `subtle`. */
406
+ variant: ChipVariantInput;
407
+ /** Height scale (Figma Size): `small` 24px / body-sm, `medium` 28px / body-md, `large` 32px / body-lg. Icon size follows (12 / 14 / 16px). `sm` / `md` / `lg` are accepted and normalised to the full words. */
408
+ size: ChipSizeInput;
409
+ /** Corner shape (Figma Border): `default` = 4px radius, `rounded` = fully rounded with 12px horizontal padding. */
410
+ border: ChipBorder;
411
+ /** Icon name from the generated icon dictionary (e.g. "settings") — rendered via <rel-icon> before the label. Ignored when `avatar` is set. */
412
+ leadingIcon?: string;
413
+ /** Icon name from the generated icon dictionary, rendered after the label. */
414
+ trailingIcon?: string;
415
+ /** Initials text for the avatar (e.g. "JD"), rendered as a `<rel-avatar type="text">` before the label. Mutually exclusive with leadingIcon (avatar wins). */
416
+ avatar?: string;
417
+ /** Shows a remove (close) button after the label; clicking it sets `removed` and fires `removed`. */
418
+ removable: boolean;
419
+ /** `true` once the chip has been removed — the host is hidden via `:host([removed])`. Reflected so CSS and Angular can see it; reset to `false` to show the chip again. */
420
+ removed: boolean;
421
+ /** Opt-in native drag-and-drop: sets `draggable="true"` on the host, shows the Figma "Dragged" state during a real drag gesture, and makes Left/Right arrow keys fire `chip-move`. */
422
+ draggableChip: boolean;
423
+ /** Reflected so CSS can target the Figma "Dragged" visual state. Driven automatically by dragstart/dragend when draggableChip is set. */
424
+ private dragging;
425
+ static styles: lit.CSSResult[];
426
+ private get classes();
427
+ private handleRemove;
428
+ /** The chip body is announced as a button, so it must also act on keys:
429
+ * Enter/Space re-dispatch as a host click (consumers' @click handlers
430
+ * fire), Delete/Backspace remove when removable, and arrow keys ask the
431
+ * container to reorder a draggable chip (`chip-move`) — the keyboard
432
+ * alternative to pointer drag-and-drop. */
433
+ private handleKeydown;
434
+ private onDragStart;
435
+ private onDragEnd;
436
+ protected willUpdate(changed: Map<string, unknown>): void;
437
+ protected updated(changed: Map<string, unknown>): void;
438
+ render(): lit_html.TemplateResult<1>;
439
+ }
440
+ declare global {
441
+ interface HTMLElementTagNameMap {
442
+ "rel-chip": RelChip;
443
+ }
444
+ }
445
+
446
+ /**
447
+ * An item is a plain string or any object read through displayField/valueField.
448
+ * Two keys are read off objects directly, whatever those fields are named:
449
+ * `icon` (a `rel-icon` name shown before the label) and `disabled` (`true`
450
+ * renders the row dulled and makes it unselectable by click or keyboard).
451
+ */
149
452
  type AutocompleteItem = string | Record<string, unknown>;
150
453
  type AutocompleteFilter = "contains" | "starts-with" | "none";
151
454
  type AutocompleteSearchFn = (query: string) => Promise<AutocompleteItem[]>;
@@ -162,9 +465,30 @@ type AutocompleteSearchFn = (query: string) => Promise<AutocompleteItem[]>;
162
465
  * `valueField`) — typing alone emits `rel-change` with the raw text but does
163
466
  * not change `value` until an item is picked (or the text exactly matches an
164
467
  * item's label/value on Enter/blur).
468
+ * @csspart panel - The suggestion listbox container (same node as `list`)
469
+ * @csspart list - Alias of `panel`
470
+ * @csspart option - A suggestion row. Emitted in BOTH single and `multiple` mode, unlike the two parts below
471
+ * @csspart option-label - The row's first line (the matched label). SINGLE-SELECT ROWS ONLY
472
+ * @csspart option-supporting-text - The row's optional second line, rendered only when the item supplies one. SINGLE-SELECT ROWS ONLY — under `multiple` the row is a nested `rel-checkbox` and the second line is that component's own `helper` part, inside its shadow root with nothing forwarding it out, so it cannot be reached with `::part()` at all. Style both modes with the `--rel-*` tokens instead
473
+ * @csspart label - The inner field's label (re-exported from `rel-textfield`)
474
+ * @csspart control - The inner field's bordered control box (re-exported from `rel-textfield`)
475
+ * @csspart input - The inner native input (re-exported from `rel-textfield`)
476
+ * @csspart helper - The inner field's helper / error line (re-exported from `rel-textfield`)
477
+ * @csspart right-icon - The clear icon shown when `clearable` (re-exported from `rel-textfield`)
478
+ * @cssprop --rel-autocomplete-bg - Panel and row background
479
+ * @cssprop --rel-autocomplete-menu-border - Panel border colour. The panel is borderless by design and only draws this on dark surfaces, where its shadow alone can't separate it from the page.
480
+ * @cssprop --rel-autocomplete-menu-radius - Panel corner radius
481
+ * @cssprop --rel-autocomplete-menu-shadow - Panel box-shadow
482
+ * @cssprop --rel-autocomplete-divider - Hairline between rows
483
+ * @cssprop --rel-autocomplete-option-hover - Background of the hovered / keyboard-highlighted / selected row
484
+ * @cssprop --rel-autocomplete-option-pressed - Background of a row while it is being pressed
485
+ * @cssprop --rel-autocomplete-value-color - Suggestion label colour
486
+ * @cssprop --rel-autocomplete-icon-color - Colour of a row's leading `icon`
487
+ * @cssprop --rel-autocomplete-status-color - Colour of the loading / no-results status rows
488
+ * @cssprop --rel-autocomplete-menu-max-height - Scroll ceiling of the suggestion panel; default `360px`. Code-owned rather than Figma-derived — every Figma Menu variant hugs its content with no ceiling, which is not shippable for an unbounded result list.
165
489
  */
166
490
  declare class RelAutocomplete extends LitElement {
167
- /** Local (or fallback initial) suggestion list. Ignored while searchFn drives results. */
491
+ /** Local (or fallback initial) suggestion list. Ignored while searchFn drives results. Object items are read through `displayField` / `valueField` plus the fixed keys `icon`, `disabled` and `supportingText` (the last renamable via `supporting-field`); `supportingText` renders as a second line in the row and is matched by the filter alongside the label. */
168
492
  items: AutocompleteItem[];
169
493
  /** Committed value — the selected item's valueField string ("" = none). */
170
494
  value: string;
@@ -172,6 +496,8 @@ declare class RelAutocomplete extends LitElement {
172
496
  displayField: string;
173
497
  /** Object key read for the committed value when items are objects. */
174
498
  valueField: string;
499
+ /** Object key read for the row's optional second line. Defaults to `supportingText`, the fixed key `rel-select` and `rel-radio` already use; point it elsewhere when your records cannot be reshaped. */
500
+ supportingField: string;
175
501
  /** Local filtering mode. Ignored when searchFn is set (results arrive pre-filtered). */
176
502
  filter: AutocompleteFilter;
177
503
  /** Async data source. When set, local filtering is bypassed entirely. */
@@ -182,18 +508,41 @@ declare class RelAutocomplete extends LitElement {
182
508
  minSearchLength: number;
183
509
  /** Optional cap on rendered suggestions (panel scrolls regardless). */
184
510
  maxSuggestions: number;
511
+ /**
512
+ * Multi-select mode: rows become checkboxes with a Select-all row, and the
513
+ * committed values live in `selectedValues` rather than `value`. Mirrors
514
+ * `rel-select`'s `multiple` rather than introducing a second pattern.
515
+ *
516
+ * THE TEXT INPUT STAYS A SEARCH BOX. In single mode the input shows the
517
+ * selected label, which is the point of a type-ahead; in multi mode there is
518
+ * no single label to show, and writing a value list into the field would
519
+ * destroy the query the user is typing. `rel-select` can put chips inside its
520
+ * trigger because a trigger is not an editable surface — an input is. So the
521
+ * chips render beneath the field, the query clears after each toggle so the
522
+ * next search starts fresh, and the panel stays open.
523
+ */
524
+ multiple: boolean;
525
+ /** Committed values in `multiple` mode (ignored otherwise). Mirrors `rel-select.selectedValues`. */
526
+ selectedValues: string[];
527
+ /** Label of the Select-all row shown at the top of the panel in `multiple` mode. */
528
+ selectAllLabel: string;
185
529
  /** Shows a trailing ✕ that clears the text and the committed value. */
186
530
  clearable: boolean;
187
531
  /** Externally-controlled loading state (internal searchFn loading is automatic). */
188
532
  loading: boolean;
189
533
  /** Row shown when a query yields nothing. */
190
534
  noResultsText: string;
535
+ /** Text shown next to the spinner while suggestions load. */
191
536
  loadingText: string;
537
+ /** Visible label, forwarded to the inner `rel-textfield`. Also names the suggestion panel. */
192
538
  label?: string;
539
+ /** Placeholder of the input, forwarded to the inner `rel-textfield`. */
193
540
  placeholder: string;
541
+ /** Field height — `small` 32px, `medium` 40px, `large` 48px — forwarded to the inner `rel-textfield`. Also drives the suggestion panel's row ramp. */
194
542
  size: TextFieldSize;
543
+ /** Field chrome (`default` outlined, `underline`, `legend` notched outline), forwarded to the inner `rel-textfield`. */
195
544
  variant: TextFieldVariant;
196
- /** See `FieldLabelStyle`. Left `undefined` the deprecated `floatingLabel` decides. */
545
+ /** Label presentation (`default` / `floating` / `none`), forwarded to the inner field. Left `undefined`, the deprecated `floatingLabel` decides. */
197
546
  labelStyle?: FieldLabelStyle;
198
547
  /** @deprecated Use `labelStyle="floating"`. Kept permanently as an alias. */
199
548
  floatingLabel: boolean;
@@ -201,14 +550,23 @@ declare class RelAutocomplete extends LitElement {
201
550
  fieldAriaLabel?: string;
202
551
  /** IDREF list of external element(s) naming the input. Wins over `fieldAriaLabel`. */
203
552
  fieldAriaLabelledby?: string;
553
+ /** Leading `rel-icon` name in the field's prefix block, e.g. `search`. */
204
554
  prefixIcon?: string;
555
+ /** Disables the field; the panel never opens and the clear affordance is hidden. */
205
556
  disabled: boolean;
557
+ /** Read-only field: focusable but not editable; the panel never opens and the clear affordance is hidden. */
206
558
  readonly: boolean;
559
+ /** Marks the input required (native `required` / `aria-required`, asterisk on the label). */
207
560
  required: boolean;
561
+ /** Puts the field in the error state (danger border, `aria-invalid`); pair with `errorMessage`. */
208
562
  error: boolean;
563
+ /** Text shown below the field instead of `helperText` while `error` is set. */
209
564
  errorMessage?: string;
565
+ /** Helper line below the field, linked to the input via `aria-describedby`. */
210
566
  helperText?: string;
567
+ /** Form field name forwarded to the native input. */
211
568
  name?: string;
569
+ /** Fills the parent width as a block element (default). Unset it to render inline at the content's natural width. */
212
570
  fullWidth: boolean;
213
571
  private open;
214
572
  private inputText;
@@ -247,6 +605,14 @@ declare class RelAutocomplete extends LitElement {
247
605
  private openPanel;
248
606
  private closePanel;
249
607
  private showNativePopover;
608
+ /**
609
+ * Gap between the field and the panel. Figma composes the two in a column
610
+ * with gap=--rel-spacing-2xs, so this is a bound token rather than a magic
611
+ * number; the position is computed in JS (the panel is in the top layer), so
612
+ * it is read from the resolved custom property instead of being hardcoded.
613
+ * That way a spacing re-export carries through here as it does in CSS.
614
+ */
615
+ private get panelOffset();
250
616
  private hideNativePopover;
251
617
  private updatePosition;
252
618
  /** Re-evaluates whether the panel should be showing for the current state. */
@@ -254,12 +620,25 @@ declare class RelAutocomplete extends LitElement {
254
620
  private onFieldInput;
255
621
  private announceResults;
256
622
  private runSearch;
623
+ /**
624
+ * Multi rows nest the checkbox at the SAME step as the field, not one below.
625
+ * rel-select records why (rel-select.ts, optionCheckboxSize): the old
626
+ * one-step-down compensated for rel-checkbox sitting a size above the system,
627
+ * and once that ramp was realigned to Figma the compensation became the bug.
628
+ */
629
+ private get optionCheckboxSize();
630
+ private get selectAllStatus();
631
+ private toggleMultiOption;
632
+ private toggleSelectAll;
633
+ private emitMultiChanged;
257
634
  private selectItem;
258
635
  /** Silent commit when typed text exactly matches an item (label or value, case-insensitive). */
259
636
  private commitExactMatch;
260
637
  private emitChanged;
261
638
  private clear;
262
639
  private onKeyDown;
640
+ /** First selectable row at or past `from`, walking in `step`; -1 if none. */
641
+ private nextEnabledIndex;
263
642
  private announceHighlighted;
264
643
  private onFocusIn;
265
644
  private onFocusOut;
@@ -275,24 +654,28 @@ declare global {
275
654
  }
276
655
  }
277
656
 
278
- declare class RelAvatar extends LitElement {
279
- size: "lg" | "md" | "sm" | "xs";
280
- type: "image" | "text" | "icon";
281
- variant: "fill" | "subtle" | "outline";
282
- src: string;
283
- text: string;
284
- alt: string;
285
- bg: string;
286
- color: string;
287
- static styles: lit.CSSResult;
288
- render(): lit_html.TemplateResult<1>;
289
- }
290
-
657
+ /** Canonical size steps — full words, as elsewhere in the library. */
658
+ type BadgeSize = "small" | "medium" | "large" | "extra-large";
659
+ /** Short size spellings, accepted as alternatives. */
660
+ type BadgeSizeAlias = "sm" | "md" | "lg" | "xl";
661
+ type BadgeSizeInput = BadgeSize | BadgeSizeAlias;
662
+ /**
663
+ * Notification badge (Figma "Badge"): a small count pill or an unlabeled dot, usually positioned over an icon or avatar.
664
+ * @csspart base - The `role="status"` pill / dot that carries the size, variant and colour overrides
665
+ * @cssprop --rel-badge-bg - Background colour of the badge; the `color` prop writes this on the host
666
+ * @cssprop --rel-badge-color - Text colour of the count; the `text-color` prop writes this on the host
667
+ * @cssprop --rel-badge-dot-size - Diameter of the `dot` variant; default 6px, the single dot size Figma draws. Set it to restore the larger discs shipped previously.
668
+ */
291
669
  declare class RelBadge extends LitElement {
670
+ /** Text shown in the `number` variant (a count such as "5" or "99+"); not rendered by `variant="dot"` but still used to build the accessible name. */
292
671
  number: string;
672
+ /** Explicit accessible name; when empty it is composed as "<number> <suffix>" or, with no number, "New <suffix>". Attribute is `arialabel`. */
293
673
  ariaLabel: string;
674
+ /** Noun appended to the count in the generated accessible name, e.g. "3 notifications". */
294
675
  suffix: string;
295
- size: "sm" | "md" | "lg" | "xl";
676
+ /** Badge scale (Figma Badge S/M/L/XL): number badges are 20 / 24 / 28 / 40px tall. `sm` / `md` / `lg` / `xl` are accepted and normalised to the full words. Ignored when `variant="dot"` — Figma models `Dot` as a fifth option of the same Size axis, so a dot has one size. */
677
+ size: BadgeSizeInput;
678
+ /** `number` renders the `number` text in a pill that widens with its content; `dot` renders a 6px disc with no text (Figma `Size=Dot`), ignoring `size`. */
296
679
  variant: "dot" | "number";
297
680
  /**
298
681
  * Direct CSS color override for the badge background. Accepts any valid
@@ -309,6 +692,7 @@ declare class RelBadge extends LitElement {
309
692
  */
310
693
  textColor: string;
311
694
  static styles: lit.CSSResult;
695
+ protected willUpdate(changed: PropertyValues<this>): void;
312
696
  private get classes();
313
697
  private get computedAriaLabel();
314
698
  updated(changedProperties: Map<PropertyKey, unknown>): void;
@@ -319,61 +703,106 @@ interface BreadcrumbItem {
319
703
  label: string;
320
704
  url?: string;
321
705
  }
706
+ /**
707
+ * Breadcrumb trail: a `<nav aria-label="Breadcrumb">` ordered list of links with chevron separators, whose last entry is the current page. Use it to show where a page sits in a hierarchy; do not use it as primary navigation.
708
+ * @csspart base - The `<nav>` landmark wrapping the ordered list.
709
+ * @csspart label - The non-link current-page text (`aria-current="page"`), also used for any item without a `url`.
710
+ */
322
711
  declare class RelBreadcrumbs extends LitElement {
712
+ /** Ordered trail, root first: `{ label: string; url?: string }[]`. Items with a `url` render as links except the last one, which is always the current page (and never a link). Set as a property — arrays do not survive attribute serialisation. */
323
713
  items: BreadcrumbItem[];
324
714
  static styles: lit.CSSResult;
325
715
  render(): lit_html.TemplateResult<1>;
326
716
  }
327
717
 
328
718
  /**
329
- * Style axis. Canonical values are the historical ones; "outline"/"ghost" are
330
- * accepted Figma-vocabulary aliases for "secondary"/"text". "static" is the
331
- * Figma Style=Static treatment (transparent, static-light label — for use on
332
- * colored/dark surfaces). Legacy "icon" is the pre-2.0 collapsed icon-button
333
- * variant and keeps its exact behavior; prefer icon-only + a style instead.
719
+ * Style axis (Figma "Style"): primary | secondary | ghost | link | static.
720
+ * "outline" (= secondary) and "text" (= ghost) are the historical spellings
721
+ * and stay supported; "default" is the legacy neutral-fill style. "static" is
722
+ * the Figma Style=Static treatment (transparent, static-light label — for use
723
+ * on colored/dark surfaces). Legacy "icon" is the pre-2.0 collapsed
724
+ * icon-button variant and keeps its exact behavior; prefer icon-only + a
725
+ * style instead.
334
726
  */
335
727
  type ButtonVariant = "default" | "primary" | "secondary" | "text" | "link" | "icon" | "static" | "outline" | "ghost";
336
- /** Tone axis. "neutral"/"brand"/"danger" are Figma-vocabulary aliases. */
337
- type ButtonTone = "default" | "primary" | "secondary" | "critical" | "success" | "neutral" | "brand" | "danger";
728
+ /**
729
+ * Tone axis (Figma "Tone"): neutral | brand | destructive. Historical
730
+ * spellings "default" (= neutral), "primary" (= brand), "critical" and
731
+ * "danger" (= destructive) stay supported; "critical"/"danger" log a one-time
732
+ * deprecation notice. "secondary"/"success" are legacy extras.
733
+ */
734
+ type ButtonTone = "default" | "primary" | "secondary" | "critical" | "success" | "neutral" | "brand" | "danger" | "destructive";
735
+ /**
736
+ * Action button (Figma "Button"): a native `<button>` with the Figma Style / Tone / Size axes, an icon-only mode, a loading spinner and an optional corner badge. Use it for every clickable action; use an anchor for navigation.
737
+ * @slot - Button content: label text, a `rel-icon`, or icon + text (kept on one line with the size's gap).
738
+ * @csspart base - The inner native `<button>` element (padding, min-width, fill, border, focus ring).
739
+ * @csspart indicator - The loading spinner, rendered only while `loading` is set.
740
+ * @cssprop --rel-button-min-width - Overrides the per-size minimum width (Figma small/medium/large = 80/100/120px, ghost small = 56px). Ignored by `icon-only` and `link`.
741
+ */
338
742
  declare class RelButton extends LitElement {
743
+ /** Style axis (Figma "Style"). Canonical: `default` (legacy neutral fill), `primary`, `secondary` (outlined), `ghost` (text-only), `link` (underlined inline text), `static` (transparent, static-light label for dark/colored surfaces). Deprecated aliases still accepted: `outline` = secondary, `text` = ghost, and `icon` (pre-2.0 40px circular icon button — use `icon-only` with a style instead). */
339
744
  variant: ButtonVariant;
340
- tone: ButtonTone;
341
745
  /**
342
- * Figma "Type=Icon Only" as an independent axis: a square button of the
343
- * current style/tone. Unlike legacy variant="icon", this composes with
344
- * every style (outline/ghost/link included).
746
+ * Tone axis (Figma "Tone"). Canonical: `neutral` (= `default`), `brand` (= `primary`), `destructive`. Deprecated aliases `critical` and `danger` map to destructive and log a one-time console notice. `secondary` and `success` are legacy extras with no Figma counterpart (secondary only affects the legacy `icon` variant).
747
+ *
748
+ * Left UNSET it means `neutral`, except on `variant="primary"`, where it
749
+ * still means `brand` for one release — see `effectiveTone`. Write the tone
750
+ * explicitly and you always get what you wrote.
345
751
  */
752
+ tone?: ButtonTone;
753
+ /** Figma "Type=Icon Only": renders a square button (32/40/48px per `size`) of the current style and tone with no padding or min-width. Composes with every `variant`; slot a single `rel-icon` and set `aria-label`. */
346
754
  iconOnly: boolean;
347
- /** Figma "State=Loading": shows a spinner, blocks interaction. */
755
+ /** Figma "State=Loading": replaces the label with a spinner (`indicator` part), sets `aria-busy`, and blocks pointer and programmatic clicks. The button keeps its width. */
348
756
  loading: boolean;
757
+ /** Figma "Size": `small` = 32px, `medium` = 40px, `large` = 48px height, with matching padding, typography and minimum width. */
349
758
  size: "small" | "medium" | "large";
759
+ /** Corner treatment: `corner-radius` = fully rounded pill, `small-corner-radius` = small radius token, `no-corner-radius` = square corners. */
350
760
  border: "corner-radius" | "small-corner-radius" | "no-corner-radius";
761
+ /** Figma "State=Disabled": dims the button to 50% opacity, flattens filled styles to the disabled fill, shows a `not-allowed` cursor and swallows every click (including programmatic `.click()`). */
351
762
  disabled: boolean;
763
+ /** Accessible name forwarded to the inner native `<button>`. Required for `icon-only` buttons, whose slotted icon has no visible text. */
352
764
  ariaLabel: string | null;
353
- /** Numeric/overflow text shown in a corner badge (e.g. "3", "999+"). Ignored when badgeDot is set. */
765
+ /** Text for a small `rel-badge` anchored to the top-right corner (e.g. "3", "999+"). Empty string renders no badge. Ignored when `badge-dot` is set. */
354
766
  badge: string;
355
- /** Shows a small corner dot instead of a numbered badge — takes precedence over `badge`. */
767
+ /** Renders a small dot badge in the top-right corner instead of a numbered badge; takes precedence over `badge`. The dot is inset 2px from the corner so it lands on a circular icon button's edge. */
356
768
  badgeDot: boolean;
357
- static styles: lit.CSSResult;
769
+ static styles: lit.CSSResult[];
358
770
  connectedCallback(): void;
359
771
  disconnectedCallback(): void;
360
772
  private handleHostClick;
361
773
  /** Style axis with Figma-vocabulary aliases folded onto canonical values. */
362
774
  private get styleVariant();
363
- /** Tone axis with Figma-vocabulary aliases folded onto canonical values. */
775
+ /** Tone axis with Figma-vocabulary aliases folded onto the internal class names. */
364
776
  private get effectiveTone();
777
+ willUpdate(changed: Map<string, unknown>): void;
365
778
  private get classes();
366
779
  private handleClick;
367
780
  render(): lit_html.TemplateResult<1>;
368
781
  }
369
782
 
783
+ /**
784
+ * Inline single-date calendar (Figma "Calendar"): a month grid with previous/next
785
+ * navigation, always visible — no trigger or popover. Use rel-date-picker for a form field.
786
+ * @csspart header - Month navigation row (previous button, month/year label, next button)
787
+ * @csspart action - The previous-month and next-month buttons
788
+ * @csspart label - The month/year heading and each weekday column header
789
+ * @csspart list - The weekday-header row and the day grid
790
+ * @csspart item - Each day cell button
791
+ */
370
792
  declare class RelCalendar extends LitElement {
793
+ /** Selected date as an ISO `YYYY-MM-DD` string, or `null` for no selection; setting it also moves the visible month. */
371
794
  value: string | null;
795
+ /** Earliest selectable date (ISO `YYYY-MM-DD`); earlier days render disabled. */
372
796
  min: string | null;
797
+ /** Latest selectable date (ISO `YYYY-MM-DD`); later days render disabled. */
373
798
  max: string | null;
799
+ /** Disables every day cell and the month navigation; the host dims to 40% opacity (Figma State=Disabled). */
374
800
  disabled: boolean;
801
+ /** First column of the week grid: `"sun"` (default) or `"mon"`. */
375
802
  weekStart: "sun" | "mon";
803
+ /** BCP 47 locale for the month name, weekday headers and day cell labels (via `Intl.DateTimeFormat`). */
376
804
  locale: string;
805
+ /** Custom predicate that disables individual days (return `true` to disable); applied on top of `min`/`max`. Property only — assign it from JavaScript. */
377
806
  isDateDisabled?: (date: Date) => boolean;
378
807
  private viewYear;
379
808
  private viewMonth;
@@ -406,6 +835,15 @@ declare class RelCalendar extends LitElement {
406
835
  render(): lit_html.TemplateResult<1>;
407
836
  }
408
837
 
838
+ /**
839
+ * `<rel-card>` — elevated surface that groups related content (Figma "Card").
840
+ * Use `type="media"` with a `<rel-card-media>` in the `media` slot for a flush image header.
841
+ * @slot - Card body; slotted headings and paragraphs receive the Figma card typography
842
+ * @slot media - Flush media region above the body; rendered only when `type="media"`
843
+ * @csspart base - The outer elevated card surface
844
+ * @csspart header - The media region wrapper (present only when `type="media"`)
845
+ * @csspart content - The padded body that wraps the default slot
846
+ */
409
847
  declare class RelCard extends LitElement {
410
848
  /**
411
849
  * Figma "Type" axis: custom (default) renders slotted content with card
@@ -417,24 +855,62 @@ declare class RelCard extends LitElement {
417
855
  render(): lit_html.TemplateResult<1>;
418
856
  }
419
857
 
858
+ /**
859
+ * Slide carousel (Figma "Carousel"): shows one slotted slide at a time in a horizontal or vertical viewport, with optional arrows, dot indicators, drag/swipe, looping and autoplay.
860
+ * @slot - The slides: one light-DOM element per slide (each is sized to one panel and given `role="group"` / `aria-roledescription="slide"`).
861
+ * @csspart viewport - The focusable `role="region"` box that clips the track (also the keyboard target).
862
+ * @csspart track - The flex row / column that translates to reveal the current slide.
863
+ * @csspart ${direction}-button - The two arrow buttons, exposed as `prev-button` and `next-button` (`type="side-arrows"` overlays them on the viewport; `type="bottom-arrows"` inlines them in the dots row).
864
+ * @csspart dots - The indicator row under the viewport (also hosts the arrows for `type="bottom-arrows"`).
865
+ * @csspart dot - One indicator button per reachable position (per slide at `panels="1"`); the active one carries the `active` class and `aria-current="true"`.
866
+ * @csspart dot-group - The row of dots inside `dots` (for `type="bottom-arrows"` it is the middle child, between the two arrows).
867
+ * @cssprop --rel-carousel-height - Viewport height in `orientation="vertical"` (default 320px); the horizontal viewport takes the height of its tallest slide.
868
+ * @cssprop --rel-carousel-nav-size - Width / height of the arrow buttons (default 32px, matching Figma; applies to both side and bottom arrows).
869
+ * @cssprop --rel-carousel-dot-size - Diameter of an inactive dot (default 8px).
870
+ * @cssprop --rel-carousel-dot-size-active - Width of the active (brand-coloured, pill-shaped) dot (default 16px).
871
+ * @cssprop --rel-carousel-slide-width - Written by the component on its own host to the computed panel width (viewport width for `panels="1"`, a fraction of it above that); not meant to be set by consumers (an inline value is overwritten on resize).
872
+ * @cssprop --rel-carousel-slide-height - Written by the component on its own host to the computed panel height (used for vertical slides); not meant to be set by consumers.
873
+ */
420
874
  declare class RelCarousel extends LitElement {
875
+ /** Index of the current slide (0-based). Set it to jump; it is clamped to the slide count and reflected as an attribute. */
421
876
  value: number;
877
+ /** Wrap from the last slide to the first (and back) with a seamless clone transition instead of stopping at the ends. */
422
878
  loop: boolean;
879
+ /** Advance automatically every `interval` ms; implies looping and pauses while hovered (see `pause-on-hover`) or while focus is inside the carousel. */
423
880
  autoplay: boolean;
881
+ /** Autoplay delay between slides, in milliseconds (default 5000). */
424
882
  interval: number;
883
+ /** Pause autoplay while the pointer is over the carousel or while dragging (default true; switch off via the property, e.g. `el.pauseOnHover = false`). */
425
884
  pauseOnHover: boolean;
885
+ /** Legacy toggle for the overlaid previous / next arrows; ignored whenever `type` is set. */
426
886
  showButtons: boolean;
427
- showDots: boolean;
887
+ /**
888
+ * Figma "Show Dots" property. Tri-state: left off it defers to `type` (dots for every type
889
+ * except `default`, and nothing at all when `type` is unset too); `show-dots` turns them on;
890
+ * `show-dots="false"` turns them off even when `type` would have shown them.
891
+ */
892
+ showDots?: boolean;
428
893
  /**
429
894
  * Figma "Type" axis. When set it drives which controls render:
430
895
  * default = content only · only-indicators = dots · side-arrows = overlaid
431
896
  * arrows + dots · bottom-arrows = dots flanked by arrows below the slide.
432
- * When unset, the legacy show-buttons/show-dots booleans apply unchanged.
897
+ * When unset, the legacy show-buttons boolean applies unchanged. The dots a type
898
+ * implies can always be overridden by an explicit `show-dots`.
433
899
  */
434
900
  type?: "default" | "only-indicators" | "side-arrows" | "bottom-arrows";
901
+ /** Slide axis: `horizontal` (default) translates the track left / right; `vertical` stacks slides in a fixed-height viewport (`--rel-carousel-height`) and translates up / down. */
435
902
  orientation: "horizontal" | "vertical";
903
+ /** Accessible name of the carousel region (`aria-label` on the viewport); default "Carousel". */
436
904
  label: string;
437
- gap?: number;
905
+ /** Space between consecutive slides in pixels (applied as the track `gap` and added to each slide step); default 8 (Figma `spacing/xs`), 0 = slides touch. */
906
+ gap: number;
907
+ /**
908
+ * Figma "Multi Panels" axis, as a count: how many slides are visible at once (default 1).
909
+ * Fractions are allowed and produce a peek of the next slide — `panels="1.5"` reproduces the
910
+ * Figma Multi Panels=True variant. Navigation still advances one slide at a time.
911
+ */
912
+ panels: number;
913
+ /** Disables arrows, dots, drag and keyboard navigation, stops autoplay and renders the carousel at 60% opacity. */
438
914
  disabled: boolean;
439
915
  private slideCount;
440
916
  private isDragging;
@@ -454,11 +930,30 @@ declare class RelCarousel extends LitElement {
454
930
  static styles: lit.CSSResult;
455
931
  connectedCallback(): void;
456
932
  firstUpdated(): void;
933
+ /**
934
+ * Write the computed panel size to the custom properties the slides (and the loop clones)
935
+ * are sized from, then re-align the track. The cross axis keeps the raw viewport measurement.
936
+ */
937
+ private measure;
457
938
  disconnectedCallback(): void;
458
939
  private handleSlotChange;
459
940
  private get vertical();
460
941
  /** Translate along the orientation axis. */
461
942
  private axisTransform;
943
+ private get panelCount();
944
+ private get gapPx();
945
+ /**
946
+ * Size of a single panel along the scroll axis. A viewport showing `n` panels contains
947
+ * `ceil(n) - 1` whole gaps — one for a 1.5-panel peek, two for three panels — so those are
948
+ * subtracted before the remainder is split. At `panels="1"` this is just the viewport size.
949
+ */
950
+ private panelSize;
951
+ /**
952
+ * Highest index that may lead the viewport. Without looping the track stops once the last
953
+ * slide is flush with the trailing edge, so multi-panel carousels never scroll into empty
954
+ * space; with clones in play every slide can lead because the clones fill the tail.
955
+ */
956
+ private get maxIndex();
462
957
  private unit;
463
958
  private updateTransform;
464
959
  private goToPrevious;
@@ -479,100 +974,119 @@ declare class RelCarousel extends LitElement {
479
974
  updated(changedProperties: Map<string, any>): void;
480
975
  /** Where nav arrows render, honouring the Figma type when set. */
481
976
  private get buttonPlacement();
977
+ /** Explicit `show-dots` wins; otherwise `type` decides, as it always has. */
482
978
  private get dotsVisible();
483
979
  private renderNavButton;
484
980
  render(): lit_html.TemplateResult<1>;
485
981
  }
486
982
 
983
+ /**
984
+ * Media card: a bordered surface with an optional full-width image on top, then a title, subtitle and slotted body. Use it for previews with a hero image (articles, products, galleries); use `rel-card` for free-form or custom layouts.
985
+ * @slot - Body content rendered inside the padded content area below the title and subtitle.
986
+ * @csspart base - The outer bordered card surface (background, border, radius, overflow clip).
987
+ * @csspart icon - The image wrapper above the content, rendered only when `image-src` is set.
988
+ * @csspart content - The padded area holding the title, subtitle and slotted body.
989
+ */
487
990
  declare class RelCardMedia extends LitElement {
991
+ /** URL of the hero image shown full-width at the top of the card. Empty (the default) omits the image section entirely. */
488
992
  imageSrc: string;
993
+ /** Alternative text for the hero image. Replace the generic default with a real description, or an empty string for purely decorative images. */
489
994
  imageAlt: string;
995
+ /** Heading rendered as an `<h3>` above the subtitle; empty omits it. Note this is also the native `title` attribute, so a value shows as a browser tooltip on hover. */
490
996
  title: string;
997
+ /** Secondary line rendered as a paragraph under the title; empty omits it. */
491
998
  subtitle: string;
492
999
  static styles: lit.CSSResult;
493
1000
  render(): lit_html.TemplateResult<1>;
494
1001
  }
495
1002
 
496
- type CheckboxState = "default" | "error" | "disabled";
497
- type CheckboxStatus = "unchecked" | "checked" | "indeterminate";
498
- type CheckboxSize = "small" | "medium";
499
- type CheckboxDensity = "compact" | "comfortable";
500
- type CheckboxAlignment = "leading" | "trailing";
501
- declare class RelCheckbox extends LitElement {
502
- label: string;
503
- /** rel-icon name rendered between the checkbox and the label (label prefix icon). */
504
- icon: string;
505
- supportingtext: string;
506
- state: CheckboxState;
507
- status: CheckboxStatus;
508
- value: string;
509
- /** Control scale (Figma Size). `"medium"` (default) = 18px box with body-lg
510
- * label; `"small"` = 14px box with body-md label. */
511
- size: CheckboxSize;
512
- /** Supporting-text layout (Figma Density). `"compact"` (default) puts the
513
- * supporting text on its own line under the row, indented past the box;
514
- * `"comfortable"` stacks label + supporting text beside the box. */
515
- density: CheckboxDensity;
516
- /** Box position (Figma Alignment). `"leading"` (default) renders the box
517
- * before the label; `"trailing"` pushes it to the far edge of the row.
518
- * Trailing has no compact layout in the spec, so it always renders with
519
- * comfortable density. */
520
- alignment: CheckboxAlignment;
521
- get checked(): boolean;
522
- set checked(val: boolean);
523
- private _onChange;
524
- private _onTouched;
525
- static styles: lit.CSSResult;
526
- protected willUpdate(changed: PropertyValues<this>): void;
527
- /** Trailing has no compact layout in the spec — trailing wins. */
528
- private get effectiveDensity();
529
- private toggle;
530
- registerOnChange(fn: (value: boolean) => void): void;
531
- registerOnTouched(fn: () => void): void;
532
- writeValue(checked: boolean): void;
533
- render(): lit_html.TemplateResult<1>;
534
- }
535
-
1003
+ /**
1004
+ * Single-date form field (Figma "Date Picker"): a text field with typed date entry plus a
1005
+ * popover calendar whose header pills drill into month and year grids, above
1006
+ * Today/Tomorrow/Yesterday shortcut chips.
1007
+ * Use rel-calendar for an always-visible grid and rel-range-picker for a from/to range.
1008
+ * @csspart base - Outer wrapper carrying the size class (`small` / `medium` / `large`)
1009
+ * @csspart label - The visible field label (rendered only when `label` is set)
1010
+ * @csspart trigger - The field box that wraps the text input and the clear/calendar icons
1011
+ * @csspart value - The editable text input inside the trigger
1012
+ * @csspart shortcuts - The Today / Tomorrow / Yesterday chip row at the top of the popover
1013
+ */
536
1014
  declare class RelDatePicker extends LitElement {
1015
+ /** Selected date as an ISO `YYYY-MM-DD` string, or `null` when empty; setting it also moves the popover to that month. */
537
1016
  value: string | null;
1017
+ /** Placeholder text shown while the field is empty (visual only; the accessible name comes from `label`, or "Select date" when unset). */
538
1018
  placeholder: string;
1019
+ /** Visible label rendered above the field and wired to the input via `aria-labelledby`; `null` renders no label. */
539
1020
  label: string | null;
1021
+ /** Disables the field, the icons and the popover; the host dims to 40% opacity. */
540
1022
  disabled: boolean;
1023
+ /** Appends a `*` to the label and sets `aria-required`; no validation is performed. */
541
1024
  required: boolean;
1025
+ /** Makes the input read-only and stops the field, icon, Enter and ArrowDown from opening the popover. */
542
1026
  readonly: boolean;
1027
+ /** Earliest selectable date (ISO `YYYY-MM-DD`); earlier days are disabled and typed dates before it are rejected. Wins over the deprecated `min`. */
543
1028
  minDate: string | null;
1029
+ /** Latest selectable date (ISO `YYYY-MM-DD`); later days are disabled and typed dates after it are rejected. Wins over the deprecated `max`. */
544
1030
  maxDate: string | null;
545
- /** @deprecated use minDate */
1031
+ /** Legacy alias of `minDate`; ignored when `minDate` is set. @deprecated use minDate */
546
1032
  min: string | null;
547
- /** @deprecated use maxDate */
1033
+ /** Legacy alias of `maxDate`; ignored when `maxDate` is set. @deprecated use maxDate */
548
1034
  max: string | null;
1035
+ /** First column of the calendar grid: `"sun"` (default) or `"mon"`. */
549
1036
  weekStart: "sun" | "mon";
1037
+ /** BCP 47 locale for weekday/month names, the default long-date display, and day/month order when parsing ambiguous typed input. */
550
1038
  locale: string;
1039
+ /** Token pattern for the displayed value (`YYYY`, `YY`, `MMMM`, `MMM`, `MM`, `M`, `DD`, `D`; literal text in `[ ]`), e.g. `DD/MM/YYYY`. Unset → the locale long date. Affects only the visible text, never `value`. */
551
1040
  displayFormat: string | null;
552
1041
  /**
553
- * Full control over the selected-value display; wins over `displayFormat`.
554
- * Reactive (attribute:false) so assigning it after render re-renders the
555
- * trigger — frameworks set callbacks as properties post-creation.
1042
+ * Callback with full control over the displayed value; wins over `displayFormat`.
1043
+ * Assign it from JavaScript; it stays reactive so setting it after render re-renders
1044
+ * the field. The Date it receives is at local midnight.
556
1045
  */
557
1046
  formatDate?: (date: Date) => string;
1047
+ /** Whether the calendar popover is open; set it directly to open/close programmatically (focus then moves into the grid). */
558
1048
  open: boolean;
1049
+ /** Closes the popover after a day is picked in the grid (default `true`). */
559
1050
  closeOnSelect: boolean;
1051
+ /** Shows a clear (×) icon while a value is set; clearing fires `rel-change` with `value: null`. */
560
1052
  clearable: boolean;
1053
+ /**
1054
+ * Figma ".Date Picker Calendar" Show Shortcuts: renders the Today / Tomorrow /
1055
+ * Yesterday chip row and its divider at the top of the popover. On by default —
1056
+ * write `show-shortcuts="false"` to hide both (a plain boolean attribute could
1057
+ * not express a default of `true`). The typed `T` / `T±N` shortcuts and the
1058
+ * in-panel `T` key keep working either way.
1059
+ */
1060
+ showShortcuts: boolean;
1061
+ /** Forces the error style (danger border, `aria-invalid`) and shows `errorMessage` below the field. Typed-entry parse errors set the same style on their own. */
561
1062
  error: boolean;
1063
+ /** Text shown below the field while `error` is set (or a typed date failed to parse); falls back to `helperText`. */
562
1064
  errorMessage?: string;
1065
+ /** Supporting text shown below the field when there is no error. */
563
1066
  helperText?: string;
1067
+ /** When set, renders a hidden `<input name>` carrying the ISO value so the picker submits with a native form. */
564
1068
  name?: string;
1069
+ /** Field height scale shared with rel-textfield / rel-select: `small` 32px, `medium` 40px (default), `large` 48px. */
565
1070
  size: "small" | "medium" | "large";
1071
+ /** Visual style of the field; `outlined` is the only variant today. */
566
1072
  variant: "outlined";
1073
+ /** Stretches the host to fill its parent's width (attribute `fullwidth`); off by default so the field keeps its intrinsic inline width. */
567
1074
  fullWidth: boolean;
1075
+ /** Custom predicate that disables individual days (return `true` to disable); applied on top of `minDate`/`maxDate` and also rejects typed input. Property only — assign it from JavaScript. */
568
1076
  isDateDisabled?: (date: Date) => boolean;
569
1077
  private get minBound();
570
1078
  private get maxBound();
571
1079
  private viewYear;
572
1080
  private viewMonth;
573
1081
  private focusedDate;
574
- private yearDropdownOpen;
575
- private monthDropdownOpen;
1082
+ /** Panel body: the day grid, or the month / year picker reached via the header pills. */
1083
+ private panelView;
1084
+ /** First year of the visible Years page; re-anchored whenever that view opens. */
1085
+ private yearPageStart;
1086
+ /** Period-grid cell the keyboard last moved to; -1 until the user moves. Kept
1087
+ * across a year page turn, since it is a grid POSITION and every page has the
1088
+ * same twelve slots. */
1089
+ private periodRoved;
576
1090
  /** Uncommitted typed text; null → the input shows the committed value. */
577
1091
  private inputText;
578
1092
  /** Parse/range error message for the typed text (cleared on next input). */
@@ -611,8 +1125,16 @@ declare class RelDatePicker extends LitElement {
611
1125
  private dayLabelLocale;
612
1126
  private formatDayLabel;
613
1127
  private announceMonth;
1128
+ /** Short month names for the Months grid (Figma shows "Jan", "Feb", …). */
614
1129
  private getMonthsList;
615
- private getYearsList;
1130
+ /** The 12 years on the current Years page. */
1131
+ private getYearsPage;
1132
+ /**
1133
+ * A month or year is out of bounds only when EVERY day it contains is —
1134
+ * a min of the 10th must not grey out that whole month.
1135
+ */
1136
+ private isMonthOutOfBounds;
1137
+ private isYearOutOfBounds;
616
1138
  private toggleCalendarPopover;
617
1139
  private closeCalendarPopover;
618
1140
  private previousMonth;
@@ -642,44 +1164,119 @@ declare class RelDatePicker extends LitElement {
642
1164
  /** T inside the panel (grid/header focus) applies Today directly. */
643
1165
  private handlePanelKeydown;
644
1166
  private handleDayKeydown;
645
- private toggleMonthDropdown;
646
- private toggleYearDropdown;
647
- private handleDropdownTriggerKeydown;
648
- private focusOpenDropdownSelection;
649
- private handleDropdownKeydown;
1167
+ /**
1168
+ * The chevrons step by whatever the visible body is made of, so they stay
1169
+ * useful in every view: a month, a year, or a whole 12-year page.
1170
+ */
1171
+ private goPrev;
1172
+ private goNext;
1173
+ private announceYearPage;
1174
+ /** A pill toggles its own view; tapping it again returns to the day grid. */
1175
+ private switchView;
1176
+ /** Focus the month/year cell that holds the tab stop, so the keyboard lands
1177
+ * somewhere useful and focus can never disagree with the tab stop. */
1178
+ private focusPanelGridSelection;
650
1179
  private selectMonth;
651
1180
  private selectYear;
1181
+ /** Arrow-key roving across the 3-column month / year grid. */
1182
+ private handlePeriodGridKeydown;
1183
+ /**
1184
+ * The tab stop follows focus, wherever focus came from — arrows, a click, Tab,
1185
+ * or a cell that simply kept focus across a re-render. Doing this on focusin
1186
+ * rather than in the key handler is what keeps the two from disagreeing: a
1187
+ * year page turn reuses the same buttons with new labels, so the focused cell
1188
+ * survives while `selected` moves off-page, and deriving the tab stop from
1189
+ * anything other than focus itself puts them on different cells.
1190
+ */
1191
+ private handlePeriodGridFocusin;
652
1192
  /**
653
1193
  * Index of the single grid cell carrying tabindex="0". The old expression
654
1194
  * (`isSelected || (index === 0 && !value)`) left the grid with ZERO tab
655
1195
  * stops once the user arrowed around without a selection.
656
1196
  */
657
1197
  private getRovingIndex;
1198
+ /** Days view: weekday header + the six week rows. */
1199
+ private renderDaysView;
1200
+ /** Months view: the 3x4 grid the month pill drills into. */
1201
+ private renderMonthsView;
1202
+ /** Years view: one 3x4 page, centred on the year in view. */
1203
+ private renderYearsView;
658
1204
  render(): lit_html.TemplateResult<1>;
659
1205
  }
660
1206
 
1207
+ /** Field scale, matching the other pickers. */
1208
+ type RangePickerSize = "small" | "medium" | "large";
1209
+ /** Alternative spellings, not deprecations. */
1210
+ type RangePickerSizeAlias = "sm" | "md" | "lg";
1211
+ type RangePickerSizeInput = RangePickerSize | RangePickerSizeAlias;
1212
+ /**
1213
+ * Date-range form field (Figma "Date Range Picker"): a text field with typed "from → to"
1214
+ * entry and a two-pane panel — quick-select presets with single-key shortcuts on the left,
1215
+ * a month grid on the right — committed with Apply (Reset / Cancel discard the draft).
1216
+ * Use rel-date-picker for a single date.
1217
+ * @csspart trigger - The field box that wraps the text input and the clear/calendar icons (default trigger variant only)
1218
+ * @csspart value - The editable text input inside the trigger
1219
+ * @csspart overlay - The full-screen backdrop rendered in `mode="popup"` while open
1220
+ * @csspart panel - The floating panel (`role="dialog"`) holding presets and calendar
1221
+ * @csspart list - The preset column and the day grid
1222
+ * @csspart option - Each quick-select preset button
1223
+ * @csspart action - The header's previous and next buttons; they step a month, a year or a 12-year page depending on which view the panel is showing
1224
+ * @csspart footer - The Reset / Cancel / Apply button row
1225
+ */
661
1226
  declare class RelRangePicker extends LitElement {
1227
+ /** Committed range start as an ISO `YYYY-MM-DD` string; empty string when no range is set. */
662
1228
  from: string;
1229
+ /** Committed range end as an ISO `YYYY-MM-DD` string; empty string when no range is set. Always ≥ `from`. */
663
1230
  to: string;
1231
+ /** Locale used to match month names in typed input; the visible trigger text and calendar labels are always `en-US` (`MM/DD/YYYY`). */
664
1232
  locale: string;
1233
+ /** First column of the calendar grid: `"sun"` (default) or `"mon"`. Presets always compute weeks Sunday–Saturday. */
665
1234
  weekStart: "mon" | "sun";
1235
+ /** Earliest selectable date (ISO `YYYY-MM-DD`); earlier days are disabled and typed ranges starting before it are rejected. */
666
1236
  minDate: string;
1237
+ /** Latest selectable date (ISO `YYYY-MM-DD`); later days are disabled and typed ranges ending after it are rejected. */
667
1238
  maxDate: string;
1239
+ /** Disables the trigger, the icons and the panel controls; the host dims to 60% opacity. */
668
1240
  disabled: boolean;
1241
+ /** Whether the panel is open. Setting it directly shows/hides the panel but does not seed the draft from `from`/`to` or fire `rel-open-change` — user interaction does both. */
669
1242
  open: boolean;
1243
+ /** `popover` anchors the panel below the trigger; `popup` centres it in the viewport behind a dimmed backdrop (part `overlay`). */
670
1244
  mode: "popover" | "popup";
1245
+ /** CSS width applied to the host (any CSS length, e.g. `320px`); empty leaves the intrinsic width. */
671
1246
  width: string;
1247
+ /** CSS `min-width` applied to the host. */
672
1248
  minWidth: string;
1249
+ /** CSS `max-width` applied to the host. */
673
1250
  maxWidth: string;
1251
+ /** CSS height applied to the host. */
674
1252
  height: string;
1253
+ /** CSS `min-height` applied to the host. */
675
1254
  minHeight: string;
1255
+ /** CSS `max-height` applied to the host. */
676
1256
  maxHeight: string;
1257
+ /** Placeholder shown in the empty field; also the accessible name of the input (and of the icon trigger while no range is set). */
677
1258
  placeholder: string;
1259
+ /** `default` renders the text field; `icon` renders a single calendar icon button instead (no typed entry, no clear button, parts `trigger`/`value` absent). */
678
1260
  triggerVariant: "default" | "icon";
1261
+ /** Shows a clear (×) icon while a range is set; clearing fires `rel-change` with empty `from`/`to`. Only with the default trigger. */
679
1262
  clearable: boolean;
1263
+ /** Stretches the host to fill its parent's width (attribute `fullwidth`),
1264
+ * mirroring rel-time-picker / rel-date-picker. Off by default so the
1265
+ * existing intrinsic-width (`inline-block`) rendering is unchanged. */
1266
+ fullWidth: boolean;
1267
+ /** Trigger height on the shared field scale — `small` 32 / `medium` 40 / `large` 48px border-box — matching rel-textfield, rel-date-picker and rel-time-picker so the four align in a form row. Also ramps the trigger's text and inline padding. The panel is unaffected: Figma specifies one panel size. `sm` / `md` / `lg` are alternative spellings and stay supported — normalised to the full words, not deprecated. */
1268
+ size: RangePickerSizeInput;
680
1269
  private draftFrom;
681
1270
  private draftTo;
682
1271
  private draftActivePreset;
1272
+ /** Which grid the panel shows. Ported from rel-date-picker so the two
1273
+ * calendars behave the same; reaching January 2023 was ~44 chevron clicks. */
1274
+ private panelView;
1275
+ private yearPageStart;
1276
+ /** Period-grid cell the keyboard last moved to; -1 until the user moves. Kept
1277
+ * across a year page turn, since it is a grid POSITION and every page has the
1278
+ * same twelve slots. */
1279
+ private periodRoved;
683
1280
  private viewYear;
684
1281
  private viewMonth;
685
1282
  private isSelectingRange;
@@ -704,6 +1301,10 @@ declare class RelRangePicker extends LitElement {
704
1301
  private handleClickOutside;
705
1302
  private handleGlobalKeydown;
706
1303
  private toggleOpen;
1304
+ /** Alternative spellings, NOT deprecations — no console notice. Normalising
1305
+ * keeps the reflected attribute canonical so the :host([size=…]) rules only
1306
+ * need the full words. */
1307
+ protected willUpdate(changed: Map<string, unknown>): void;
707
1308
  private openPopover;
708
1309
  private cancelPopover;
709
1310
  private applySelection;
@@ -743,6 +1344,48 @@ declare class RelRangePicker extends LitElement {
743
1344
  private isDateDisabled;
744
1345
  private getQuickSelects;
745
1346
  private selectQuickSelect;
1347
+ private goPrev;
1348
+ private goNext;
1349
+ private announceYearPage;
1350
+ /** A pill toggles its own view; tapping it again returns to the day grid. */
1351
+ private switchView;
1352
+ private selectMonth;
1353
+ private selectYear;
1354
+ /**
1355
+ * Arrow-key roving across the Months / Years grid, matching rel-date-picker
1356
+ * exactly. Without this the grid had ONE reachable cell — the selected one —
1357
+ * because every other cell carries tabindex="-1" under the roving pattern and
1358
+ * nothing moved the focus. A keyboard user could open the view and go nowhere,
1359
+ * while the 44 chevron presses still worked: strictly worse than before the
1360
+ * switcher existed.
1361
+ *
1362
+ * Movement clamps at the edges (shared with the date picker through
1363
+ * periodGridTarget); Escape steps back to the day grid rather than falling
1364
+ * through to the panel's own Escape, which closes the whole picker.
1365
+ */
1366
+ private handlePeriodGridKeydown;
1367
+ /**
1368
+ * The tab stop follows focus, wherever focus came from — arrows, a click, Tab,
1369
+ * or a cell that simply kept focus across a re-render. Doing this on focusin
1370
+ * rather than in the key handler is what keeps the two from disagreeing: a
1371
+ * year page turn reuses the same buttons with new labels, so the focused cell
1372
+ * survives while `selected` moves off-page, and deriving the tab stop from
1373
+ * anything other than focus itself puts them on different cells.
1374
+ */
1375
+ private handlePeriodGridFocusin;
1376
+ /**
1377
+ * Return focus to the day grid after leaving Months / Years. Prefers the
1378
+ * roving tab stop and falls back to the first selectable day, so a month with
1379
+ * every leading cell disabled still lands somewhere. Disabled days here carry
1380
+ * a CLASS, not the :disabled state, because they are not buttons.
1381
+ */
1382
+ private focusDayGrid;
1383
+ /** Put focus in the grid when a view opens, so the keyboard has somewhere to
1384
+ * start; otherwise the arrows have nothing to move from. */
1385
+ private focusPeriodGrid;
1386
+ /** Months or Years, in the same 3x4 grid rel-date-picker uses. */
1387
+ private renderPeriodGrid;
1388
+ private getMonthsList;
746
1389
  private previousMonth;
747
1390
  private nextMonth;
748
1391
  private getMonthName;
@@ -768,59 +1411,48 @@ declare global {
768
1411
  }
769
1412
  }
770
1413
 
771
- type ChipTone = "neutral" | "danger" | "warning" | "success" | "info";
772
- type ChipVariant = "fill" | "subtle";
773
- type ChipSize = "sm" | "md" | "lg";
774
- type ChipBorder = "default" | "rounded";
775
- declare class RelChip extends LitElement {
776
- static shadowRootOptions: ShadowRootInit;
777
- label: string;
778
- tone: ChipTone;
779
- variant: ChipVariant;
780
- size: ChipSize;
781
- border: ChipBorder;
782
- /** Icon name from the generated icon dictionary (e.g. "settings") — rendered via <rel-icon>. */
783
- leadingIcon?: string;
784
- trailingIcon?: string;
785
- /** Initials text for the avatar (e.g. "JD"). Mutually exclusive with leadingIcon. */
786
- avatar?: string;
787
- removable: boolean;
788
- /** IMPORTANT: reflected so CSS + Angular can see it */
789
- removed: boolean;
790
- /** Opt-in native drag-and-drop — reflects the Figma "Dragged" state automatically during a real drag gesture. */
791
- draggableChip: boolean;
792
- /** Reflected so CSS can target the Figma "Dragged" visual state. Driven automatically by dragstart/dragend when draggableChip is set. */
793
- private dragging;
794
- static styles: lit.CSSResult;
795
- private get classes();
796
- private handleRemove;
797
- /** The chip body is announced as a button, so it must also act on keys:
798
- * Enter/Space re-dispatch as a host click (consumers' @click handlers
799
- * fire), Delete/Backspace remove when removable, and arrow keys ask the
800
- * container to reorder a draggable chip (`chip-move`) — the keyboard
801
- * alternative to pointer drag-and-drop. */
802
- private handleKeydown;
803
- private onDragStart;
804
- private onDragEnd;
805
- protected updated(changed: Map<string, unknown>): void;
806
- render(): lit_html.TemplateResult<1>;
807
- }
808
- declare global {
809
- interface HTMLElementTagNameMap {
810
- "rel-chip": RelChip;
811
- }
812
- }
813
-
1414
+ /** Inner padding step, spelled out. */
1415
+ type ContainerPadding = "small" | "medium" | "large" | "extra-large";
1416
+ /** Alternative spellings, not deprecations — the short names keep working. */
1417
+ type ContainerPaddingAlias = "sm" | "md" | "lg" | "xl";
1418
+ type ContainerPaddingInput = ContainerPadding | ContainerPaddingAlias;
1419
+ /** Canonical surface names (audit 12). */
1420
+ type ContainerSurface = "default" | "elevated" | "transparent";
1421
+ /** @deprecated since 1.4.7 — use `ContainerSurface` / the `surface` prop. */
1422
+ type ContainerBackground = "light" | "white" | "none";
1423
+ /**
1424
+ * Padded surface block (Figma "Container"): a full-width wrapper with a surface fill, a padding step and an optional shadow, used to group a section of content.
1425
+ * @slot - Section content; slotted `h1`–`h4` get the headings-sm role and `p` the body-md role
1426
+ * @csspart base - The padded surface `<div>` (same element as `container`)
1427
+ * @csspart container - Alias of `base`, kept for existing `::part(container)` selectors
1428
+ */
814
1429
  declare class RelContainer extends LitElement {
815
- padding: "sm" | "md" | "lg" | "xl";
1430
+ /** Inner padding step: `small` = spacing-xs, `medium` = spacing-md, `large` = spacing-lg. `extra-large` = spacing-2xl is a code-only extension — Figma publishes only the three steps above — and is supported, not deprecated. `sm` / `md` / `lg` / `xl` are alternative spellings and stay supported, normalised to the full words. */
1431
+ padding: ContainerPaddingInput;
1432
+ /** Adds the shadow-300 elevation box-shadow to the surface. */
816
1433
  shadow: boolean;
817
- background: "light" | "white" | "none";
1434
+ /**
1435
+ * Surface fill: default (page surface) | elevated (raised surface) |
1436
+ * transparent. Takes precedence over the deprecated `background` prop.
1437
+ */
1438
+ surface?: ContainerSurface;
1439
+ /** @deprecated Deprecated since 1.4.7 — use `surface` (white→default, light→elevated, none→transparent). */
1440
+ background?: ContainerBackground;
1441
+ /** Resolved surface: explicit `surface` wins, else mapped `background`, else "default". */
1442
+ get resolvedSurface(): ContainerSurface;
1443
+ willUpdate(changed: Map<string, unknown>): void;
818
1444
  static styles: lit.CSSResult;
819
1445
  private get classes();
820
1446
  render(): lit_html.TemplateResult<1>;
821
1447
  }
822
1448
 
1449
+ /**
1450
+ * Thin separator rule that splits content horizontally or vertically. Use it between sections, list groups or toolbar clusters; do not use it as a spacer.
1451
+ * @csspart base - The rendered rule — restyle thickness, colour or margin here.
1452
+ * @cssprop --rel-divider-spacing - Cross-axis margin around the rule; default 16px. Figma specifies none, so set it to `0` for strict parity — the default is kept for back-compat and is planned to become `0` in 3.0.
1453
+ */
823
1454
  declare class RelDivider extends LitElement {
1455
+ /** Axis of the rule: `horizontal` spans the full width with vertical margin; `vertical` is a full-height line with horizontal margin (the parent needs a defined height or a flex row). Mirrored to `aria-orientation` on the host. */
824
1456
  orientation: "horizontal" | "vertical";
825
1457
  static styles: lit.CSSResult;
826
1458
  connectedCallback(): void;
@@ -828,6 +1460,11 @@ declare class RelDivider extends LitElement {
828
1460
  render(): lit_html.TemplateResult<1>;
829
1461
  }
830
1462
 
1463
+ /**
1464
+ * Layout helper used by `<rel-drawer>` for its footer: a right-aligned flex
1465
+ * row with an 8px gap. Can also be used standalone for a matching actions row.
1466
+ * @slot - Footer actions (typically `<rel-button>`s)
1467
+ */
831
1468
  declare class RelDrawerFooter extends LitElement {
832
1469
  static styles: lit.CSSResult;
833
1470
  render(): lit_html.TemplateResult<1>;
@@ -840,19 +1477,51 @@ declare global {
840
1477
 
841
1478
  type DrawerSide = "bottom" | "left" | "right";
842
1479
  type DrawerCloseReason = "backdrop" | "escape" | "drag" | "programmatic";
1480
+ /**
1481
+ * Edge-anchored drawer (Figma "Drawer", 5699:6844): a panel that slides in
1482
+ * from the bottom, left or right over a scrim, with an optional drag handle
1483
+ * (bottom only), a title/description header, a scrollable body and a footer.
1484
+ * @slot - Body content of the drawer
1485
+ * @slot footer - Actions row; rendered inside a `<rel-drawer-footer>` (right-aligned, 8px gap)
1486
+ * @csspart overlay - The full-viewport scrim behind the panel
1487
+ * @csspart panel - The sliding panel (role="dialog")
1488
+ * @csspart handle - The drag-to-close grab bar (bottom drawers only)
1489
+ * @csspart header - Header block holding title, description and close button
1490
+ * @csspart close-button - The "X" close button
1491
+ * @csspart content - Scrollable body wrapper around the default slot
1492
+ * @csspart footer - Footer wrapper around the `footer` slot
1493
+ * @cssprop --rel-drawer-width - Panel width. Default `clamp(640px, 66vw, 952px)` for `side="bottom"`, `clamp(280px, 24vw, 420px)` for left/right. The `width` prop sets this on the panel and wins over a host value
1494
+ * @cssprop --rel-drawer-height - Panel height for `side="bottom"`; default `clamp(360px, 49vh, 600px)`. Left/right drawers are always full height
1495
+ * @cssprop --rel-drawer-transition-duration - Slide/scrim animation duration; default `0.3s`
1496
+ * @cssprop --rel-drawer-transition-timing - Slide/scrim animation easing; default `cubic-bezier(0.32, 0.72, 0, 1)`
1497
+ * @cssprop --rel-drawer-scrim-opacity - Opacity of the scrim while open; default `1`
1498
+ */
843
1499
  declare class RelDrawer extends LitElement {
1500
+ /** Whether the drawer is shown. Toggle it to open/close; every change fires `rel-open-change`. */
844
1501
  open: boolean;
1502
+ /** Edge the panel slides in from. `bottom` is centred horizontally and supports the drag handle; `left`/`right` are full-height side panels. */
845
1503
  side: DrawerSide;
1504
+ /** When false the close button is hidden and backdrop clicks / Escape are ignored (drag-to-close still works). */
846
1505
  dismissible: boolean;
1506
+ /** Modal mode: renders the scrim, sets `role="dialog"` + `aria-modal`, traps Tab inside the panel and moves focus in on open. When false the panel is a `region` with no scrim and no focus trap. */
847
1507
  modal: boolean;
1508
+ /** Close when the scrim is clicked. Only effective while `dismissible` is true. */
848
1509
  closeOnBackdrop: boolean;
1510
+ /** Close on the Escape key. Only effective while `dismissible` is true. */
849
1511
  closeOnEscape: boolean;
1512
+ /** Show the grab bar above the header. Only rendered when `side="bottom"` and `draggable` is true. */
850
1513
  showHandle: boolean;
1514
+ /** Enable drag-to-close on the handle (pointer or touch). Bottom drawers only. */
851
1515
  draggable: boolean;
1516
+ /** Fraction (0–1) of the panel height the user must drag down before release closes the drawer; shorter drags snap back. */
852
1517
  snapThreshold: number;
1518
+ /** Written to the panel as the `--drawer-max-height` custom property (any CSS length). No built-in rule reads it yet; use `--rel-drawer-height` to size a bottom drawer. */
853
1519
  maxHeight: string;
1520
+ /** Explicit panel width (any CSS length). Empty by default, which uses the per-side `--rel-drawer-width` default. */
854
1521
  width: string;
1522
+ /** Heading text (rendered as an `<h2>`, linked via `aria-labelledby`). */
855
1523
  title: string;
1524
+ /** Supporting text under the title (linked via `aria-describedby`). */
856
1525
  description: string;
857
1526
  private isDragging;
858
1527
  private dragOffset;
@@ -862,12 +1531,23 @@ declare class RelDrawer extends LitElement {
862
1531
  private previousFocus;
863
1532
  private startY;
864
1533
  private currentY;
1534
+ /** Scrim opacity at rest, sampled once per drag so the fade starts from it. */
1535
+ private scrimRestingOpacity;
865
1536
  private originalBodyOverflow;
866
1537
  private originalBodyPaddingRight;
867
1538
  static styles: lit.CSSResult;
868
1539
  connectedCallback(): void;
869
1540
  disconnectedCallback(): void;
870
1541
  updated(changed: Map<string, any>): void;
1542
+ /**
1543
+ * The footer divider is conditional: short content (a confirmation message)
1544
+ * has no divider, but a body that scrolls does — it is a scroll affordance,
1545
+ * not decoration (designer, confirmed). CSS cannot ask whether an element
1546
+ * scrolls, so it is measured and reflected onto the host as `body-scrolls`,
1547
+ * re-measured whenever the body or its contents resize.
1548
+ */
1549
+ private bodyScrollObserver?;
1550
+ private watchBodyScroll;
871
1551
  private handleOpen;
872
1552
  private handleClose;
873
1553
  private lockScroll;
@@ -889,11 +1569,31 @@ declare global {
889
1569
  }
890
1570
  }
891
1571
 
1572
+ /**
1573
+ * Key-cap scale (Figma Kbd 6316:284): S 20 / M 24 / L 28px tall with
1574
+ * label-sm / label-md / label-lg type. `sm` / `md` / `lg` are the original
1575
+ * names; the full words are accepted as aliases (Trello 4).
1576
+ */
1577
+ type KbdSize = "sm" | "md" | "lg" | "small" | "medium" | "large";
1578
+ /**
1579
+ * Single key cap (Figma "Kbd", 6316:284) for showing a keyboard key or shortcut
1580
+ * inline with text; the key label is the slotted content.
1581
+ * @slot - The key label (e.g. `Ctrl`, `K`, `⌘`)
1582
+ */
892
1583
  declare class RelKbd extends LitElement {
893
- size: "sm" | "md" | "lg";
1584
+ /** Key-cap scale (Figma Size): `small` 20px tall / label-sm, `medium` 24px / label-md, `large` 28px / label-lg; 4px radius at every size. `sm` / `md` / `lg` are the legacy short spellings and stay accepted. */
1585
+ size: KbdSize;
1586
+ /** Fill / text contrast: `default` = elevated-1 background with label text; `muted` = elevated-2 background with placeholder-tone text for secondary shortcuts. Both carry a 0.5px stroke and the hard 2px bottom edge Figma draws on the key cap. */
894
1587
  variant: "default" | "muted";
1588
+ /**
1589
+ * Fully rounded corners. Logs a one-time console notice when set.
1590
+ * @deprecated The Kbd spec has a single 4px radius at every size (audit
1591
+ * 16); `pill` is kept working as an alias but logs a one-time notice.
1592
+ */
895
1593
  pill: boolean;
1594
+ /** Pressed look: border-strong stroke, 1px downward nudge and (muted variant) a darker fill. */
896
1595
  inset: boolean;
1596
+ protected willUpdate(changed: PropertyValues<this>): void;
897
1597
  static styles: lit.CSSResult;
898
1598
  render(): lit_html.TemplateResult<1>;
899
1599
  }
@@ -902,11 +1602,17 @@ declare class RelKbd extends LitElement {
902
1602
  * entry in `items` with "+" separators between them. Slotted <rel-kbd>
903
1603
  * children may be used instead of the items array.
904
1604
  *
905
- * <rel-kbd-group .items=${["Ctrl", "Shift", "P"]} size="md"></rel-kbd-group>
1605
+ * <rel-kbd-group .items=${["Ctrl", "Shift", "P"]} size="medium"></rel-kbd-group>
1606
+ * @slot - Extra content rendered after the generated keys (e.g. hand-written `<rel-kbd>` children)
1607
+ * @csspart item - Each generated `<rel-kbd>` key cap
1608
+ * @csspart label - The `+` separator between generated keys
906
1609
  */
907
1610
  declare class RelKbdGroup extends LitElement {
1611
+ /** Key labels to render, one `<rel-kbd>` each, joined by `+` separators. Set as a property or as a JSON array attribute (`items='["Ctrl","K"]'`). */
908
1612
  items: string[];
909
- size: "sm" | "md" | "lg";
1613
+ /** Passed through to every generated <rel-kbd>: `small` / `medium` / `large` (legacy `sm` / `md` / `lg` still accepted). */
1614
+ size: KbdSize;
1615
+ /** Passed through to every generated <rel-kbd>: `default` or `muted`. */
910
1616
  variant: "default" | "muted";
911
1617
  static styles: lit.CSSResult;
912
1618
  render(): lit_html.TemplateResult<1>;
@@ -931,23 +1637,48 @@ type StepperType = "default" | "dot" | "number" | "icon";
931
1637
  type LabelPlacement = "top" | "centered" | "inverted";
932
1638
  interface Step {
933
1639
  title: string;
1640
+ /** Optional second line under the title (Figma "Subtitle" / "Show Subtitle"). Omit it and the step stays single-line. */
1641
+ subtitle?: string;
934
1642
  status: StepStatus;
935
1643
  }
1644
+ /**
1645
+ * Multi-step progress indicator (Figma "Stepper"): renders one focusable step per entry in `steps` — a circular indicator (number, check, dot or icon per `type`), a label and a connector line to the next step — in a row or a column.
1646
+ * @csspart indicator - The 24px circle (8px for `type="dot"`) that holds the step number, check mark or icon.
1647
+ * @csspart track - The 1px connector line from a step to the next one (not rendered on the last step).
1648
+ * @csspart label - The step title text.
1649
+ * @csspart subtitle - The optional second line under the title; rendered only when a step sets `subtitle`.
1650
+ * @cssprop --rel-stepper-indicator-size - Indicator diameter (default 24px; `type="dot"` is fixed at 8px).
1651
+ * @cssprop --rel-stepper-connector-length - 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`.
1652
+ * @cssprop --rel-stepper-connector-length-lg - Superseded by `--rel-stepper-connector-length`, which it still falls back to, so an existing override keeps working.
1653
+ * @cssprop --rel-stepper-connector-length-md - No longer applies. It parameterised the code-only `size` axis, and Figma has one connector geometry rather than a scale.
1654
+ * @cssprop --rel-stepper-connector-length-sm - No longer applies, for the same reason as `-md`.
1655
+ */
936
1656
  declare class RelStepper extends LitElement {
1657
+ /** 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. */
937
1658
  steps: Step[];
1659
+ /**
1660
+ * Legacy label placement (attribute `textalign`): `below` (default) puts the label under the indicator, `right` puts it beside the indicator. Ignored whenever `label-placement` is set.
1661
+ * @deprecated Deprecated alias of `label-placement`; use `label-placement="inverted"` instead of `textalign="below"` and `label-placement="centered"` instead of `textalign="right"`.
1662
+ */
938
1663
  textAlign: TextAlign;
1664
+ /** Layout axis: `horizontal` (default) lays the steps out in a centred row; `vertical` stacks them. */
939
1665
  orientation: Orientation;
940
- size: StepperSize;
941
- type: StepperType;
942
1666
  /**
943
- * Figma Typel axis: top = label top-aligned beside the indicator,
944
- * centered = label vertically centered beside it, inverted = indicator above
945
- * the label. When unset, the legacy textAlign prop drives the layout
946
- * (below ≈ inverted, right ≈ centered). Note Figma marks Top+Horizontal
947
- * as an unsupported combination.
1667
+ * No longer has any effect. It used to set the connector length and step gap
1668
+ * (86px for `large`, 60 / 42px for `small`) and to swap the step label to
1669
+ * body/sm/regular at `small`.
1670
+ * @deprecated Figma has no Size axis on the Stepper — the connector geometry
1671
+ * is fixed — so this was a code-only scale. It stays accepted so existing
1672
+ * markup keeps working, and now resolves to the one Figma geometry. Retune it
1673
+ * with `--rel-stepper-connector-length` instead. Logs a one-time notice.
948
1674
  */
1675
+ size: StepperSize;
1676
+ /** 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). */
1677
+ type: StepperType;
1678
+ /** 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. */
949
1679
  labelPlacement?: LabelPlacement;
950
1680
  static styles: lit.CSSResult;
1681
+ protected willUpdate(changed: Map<string, unknown>): void;
951
1682
  private isDone;
952
1683
  private isProgress;
953
1684
  private isDisabled;
@@ -969,20 +1700,43 @@ interface RadioOption {
969
1700
  * Ignored when `icon` is also set. */
970
1701
  avatar?: string;
971
1702
  }
1703
+ /** Control scale, spelled out. */
972
1704
  type RadioSize = "small" | "medium" | "large";
1705
+ /** Alternative spellings, not deprecations — the short names work too. */
1706
+ type RadioSizeAlias = "sm" | "md" | "lg";
1707
+ type RadioSizeInput = RadioSize | RadioSizeAlias;
973
1708
  type RadioDensity = "compact" | "comfortable";
974
1709
  type RadioAlignment = "leading" | "trailing";
1710
+ /**
1711
+ * Single-select radio group (Figma "Radio"): renders one native radio input per
1712
+ * entry in `options`, with optional supporting text, icon or avatar prefix.
1713
+ * @csspart base - The `role="radiogroup"` container that lays out the options
1714
+ * @csspart label - The visible label text of each option
1715
+ */
975
1716
  declare class RelRadio extends LitElement {
1717
+ /** The options to render, in order. Each entry is a `RadioOption` (`value`, `label`,
1718
+ * optional `supportingText`, `disabled`, `icon` or `avatar`). Set as a property
1719
+ * (`.options=`) or as a JSON attribute. */
976
1720
  options: RadioOption[];
1721
+ /** `name` given to every native radio input inside this element. It scopes native
1722
+ * radio-group behaviour (arrow-key movement, mutual exclusion) to this group, so give
1723
+ * each group on a page a distinct name. */
977
1724
  name: string;
978
1725
  /** Layout axis of the option list. `"vertical"` (default) stacks options in
979
1726
  * a column; `"horizontal"` lays them out in a wrapping row. */
980
1727
  orientation: Orientation;
981
- /** Control scale (Figma Size). `"medium"` (default, Figma M) = 20px control
982
- * with body-lg labels; `"large"` (Figma L) = 24px control with body-xl
983
- * labels; `"small"` (Figma S) = 20px control with body-md labels — S and M
984
- * share the control size in the spec, only typography steps down. */
985
- size: RadioSize;
1728
+ /** Control scale. `"medium"` (default, Figma M) = 20px control with body-lg
1729
+ * labels; `"large"` (Figma L) = 24px control with body-xl labels;
1730
+ * `"small"` = 16px control with body-md labels. `sm` / `md` / `lg` are
1731
+ * alternative spellings and stay supported — normalised to the full words,
1732
+ * not deprecated.
1733
+ *
1734
+ * DELIBERATE FIGMA DIVERGENCE on Small. Figma's `.Radio Control` has one
1735
+ * size (20x20) and its row variants pin Small AND Medium to 20, so the two
1736
+ * rendered identically and the Size axis did nothing between them. 16px is
1737
+ * not invented: it is rel-checkbox's Small, and checkbox is radio's sibling
1738
+ * selection control. See the size ramp in the styles below. */
1739
+ size: RadioSizeInput;
986
1740
  /** Supporting-text layout (Figma Density). `"compact"` (default) puts the
987
1741
  * supporting text on its own line under the row, indented past the control;
988
1742
  * `"comfortable"` stacks label + supporting text beside the control. */
@@ -993,13 +1747,27 @@ declare class RelRadio extends LitElement {
993
1747
  * with comfortable density. Meant for vertical orientation — trailing
994
1748
  * options stretch to the group's full width. */
995
1749
  alignment: RadioAlignment;
1750
+ /** `value` of the currently selected option, or `null` when nothing is selected.
1751
+ * Set it to preselect an option; it is updated on every user selection. */
996
1752
  selectedValue: string | null;
1753
+ /** Disables every option (Figma State=Disabled: the whole group at 40% opacity).
1754
+ * Individual options can also be disabled via `RadioOption.disabled`. */
997
1755
  disabled: boolean;
1756
+ /** Error state (Figma State=Error): rings, dots and supporting text turn danger.
1757
+ * Applies to every option while nothing is selected, and only to the selected
1758
+ * option once a choice is made. Selection is still allowed. */
998
1759
  error: boolean;
1760
+ /** Message rendered under the group (live region) while `error` is set; hidden
1761
+ * when `error` is false or the text is empty. */
999
1762
  errorMessage: string;
1000
1763
  /** Accessible name for the radiogroup (it renders no visible group label). */
1001
1764
  fieldAriaLabel?: string;
1765
+ /** Value reported to the Angular forms bridge (`registerOnChange` callback) on each
1766
+ * change and compared by `writeValue`. Not used for rendering; read `selectedValue`
1767
+ * or the `rel-change` detail for the selected option. */
1002
1768
  value: string;
1769
+ /** Set by the Angular forms bridge (`writeValue`) to whether the written form value
1770
+ * equals `value`. Not used for rendering — read `selectedValue` for the selection. */
1003
1771
  checked: boolean;
1004
1772
  private _onChange;
1005
1773
  private _onTouched;
@@ -1008,8 +1776,11 @@ declare class RelRadio extends LitElement {
1008
1776
  /** Trailing has no compact layout in the spec — trailing wins. */
1009
1777
  private get effectiveDensity();
1010
1778
  private onChange;
1779
+ /** @internal Angular ControlValueAccessor bridge. */
1011
1780
  registerOnChange(fn: (value: string) => void): void;
1781
+ /** @internal Angular ControlValueAccessor bridge. */
1012
1782
  registerOnTouched(fn: () => void): void;
1783
+ /** @internal Angular ControlValueAccessor bridge. */
1013
1784
  writeValue(value: string): void;
1014
1785
  private get hasSelection();
1015
1786
  private renderPrefix;
@@ -1017,7 +1788,17 @@ declare class RelRadio extends LitElement {
1017
1788
  render(): lit_html.TemplateResult<1>;
1018
1789
  }
1019
1790
 
1020
- type MenuType = "default" | "checkbox" | "arrow" | "select-option" | "fixed" | "fit";
1791
+ /**
1792
+ * Row shape (Figma ".Menu Item" Type): list | checkbox | select-option.
1793
+ * `default` is the deprecated spelling of `list`. `arrow` is a code-only
1794
+ * extension with no Figma counterpart — it turns on the submenu flyout.
1795
+ * `fixed` / `fit` are deprecated here and now live on `width`.
1796
+ */
1797
+ type MenuType = "list" | "checkbox" | "select-option" | "arrow" | "default" | "fixed" | "fit";
1798
+ /** Sizing mode (Figma "Menu" Type). Both modes are --rel-menu-width wide; the axis varies the HEIGHT: fixed pins the panel to --rel-menu-height and scrolls, fit hugs its rows. */
1799
+ type MenuWidth = "fixed" | "fit";
1800
+ /** Figma ".Menu Item" Size: large (48px rows) | medium (40px) | small (32px). */
1801
+ type MenuSize = "large" | "medium" | "small";
1021
1802
  interface MenuItem {
1022
1803
  label: string;
1023
1804
  active?: boolean;
@@ -1026,16 +1807,67 @@ interface MenuItem {
1026
1807
  submenu?: MenuItem[];
1027
1808
  open?: boolean;
1028
1809
  }
1810
+ /**
1811
+ * Declarative menu-item placeholder. It renders nothing and `<rel-menu>` does not
1812
+ * currently read slotted children — menus are built from the `items` property.
1813
+ * Registered so markup can carry item metadata for future declarative support.
1814
+ */
1029
1815
  declare class RelMenuItem extends LitElement {
1816
+ /** Display text of the item. */
1030
1817
  label: string;
1818
+ /** Value that identifies the item (not used by `rel-menu` today). */
1031
1819
  value: string;
1820
+ /** Marks the item as non-interactive. */
1032
1821
  disabled: boolean;
1822
+ /** `rel-icon` name to render before the label (not used by `rel-menu` today). */
1033
1823
  icon: string;
1034
1824
  createRenderRoot(): this;
1035
1825
  render(): lit_html.TemplateResult<1>;
1036
1826
  }
1827
+ /**
1828
+ * Light-DOM menu (Figma "Menu", 6326:2931) driven by the `items` array: single-select
1829
+ * rows, checkbox rows, radio-style select-option rows, or hover/keyboard submenus.
1830
+ * @csspart list - The `role="menu"` root list (a light-DOM `[part="list"]` attribute)
1831
+ * @csspart panel - A submenu flyout (`type="arrow"` only; light-DOM `[part="panel"]` attribute)
1832
+ * @cssprop --rel-menu-width - Width of the menu in BOTH sizing modes; default 300px
1833
+ * @cssprop --rel-menu-height - Height of the menu when `width="fixed"`, which then scrolls; default 500px. `fit` ignores it and hugs its rows.
1834
+ */
1037
1835
  declare class RelMenu extends LitElement {
1836
+ /**
1837
+ * Row shape (Figma ".Menu Item" Type). `list` (default) = plain rows;
1838
+ * `checkbox` = toggling rows with a checkbox; `select-option` = single-select
1839
+ * rows with a trailing check.
1840
+ * `arrow` is a code-only extension with no Figma counterpart: rows whose
1841
+ * `submenu` opens a flyout. Because it rides this axis, submenus cannot
1842
+ * currently be combined with checkbox or select-option rows — see the README.
1843
+ * DEPRECATED values, all still working: `default` is the old spelling of
1844
+ * `list`; `fixed` / `fit` were width modes and now set `width` instead,
1845
+ * leaving the row shape at `list`.
1846
+ */
1038
1847
  type: MenuType;
1848
+ /**
1849
+ * Sizing mode (Figma "Menu" Type). Both modes are `--rel-menu-width` (300px)
1850
+ * wide — Figma's Fixed and Fit variants are both 300px — and the axis varies
1851
+ * the HEIGHT: `fixed` pins the panel to `--rel-menu-height` (500px) and
1852
+ * scrolls, `fit` hugs its rows. `fit` previously varied the width instead,
1853
+ * which was the wrong dimension. This was also fused into `type`, where
1854
+ * choosing a width silently forced plain rows and choosing a row shape
1855
+ * silently forced the default width.
1856
+ */
1857
+ width?: MenuWidth;
1858
+ /** Row shape actually rendered: the deprecated width values fall back to `list`. */
1859
+ private get resolvedType();
1860
+ /** Width mode actually applied: explicit `width` wins, else the deprecated `type` spelling. */
1861
+ private get resolvedWidth();
1862
+ /**
1863
+ * Row size (Figma ".Menu Item" Size, 6326:616): large = 48px rows with
1864
+ * body-lg labels (Figma default), medium = 40px / body-md, small = 32px /
1865
+ * body-sm. Added in 1.4.7; before that rows were a fixed 36px.
1866
+ */
1867
+ size: MenuSize;
1868
+ /** The rows to render, in order. Each entry is a `MenuItem` (`label`, optional
1869
+ * `active`, `checked`, `disabled`, `submenu`, `open`). The array is copied on
1870
+ * assignment, so mutate and reassign it to update the menu. */
1039
1871
  items: MenuItem[];
1040
1872
  private focusedIndex;
1041
1873
  /** Index inside the open submenu that virtual focus sits on; -1 = main list. */
@@ -1043,7 +1875,7 @@ declare class RelMenu extends LitElement {
1043
1875
  private _items;
1044
1876
  /** Stable id prefix for aria-activedescendant targets. */
1045
1877
  private menuId;
1046
- static readonly _css = "\n :host {\n color: var(--rel-text-default);\n display: inline-block;\n }\n\n .rel-menu {\n position: relative;\n display: inline-block;\n background: var(--rel-bg-neutral);\n color: var(--rel-text-default);\n border-radius: var(--rel-border-radius-md);\n box-shadow: var(--rel-shadows-shadow-300);\n min-width: 220px;\n /* No vertical padding: items fill edge-to-edge so a first/last-item hover\n reaches the menu's top/bottom. NOT overflow:hidden \u2014 that clips the\n type=arrow flyout (position:absolute at left:100%). Instead the first\n and last items carry the outer corner radius so hover backgrounds clip\n to the rounded shape without any overflow. */\n padding: 0;\n outline: none;\n overflow: visible;\n font-family: var(--rel-body-lg-regular-font-family);\n font-weight: var(--rel-body-lg-regular-font-weight);\n font-size: var(--rel-body-lg-regular-font-size);\n line-height: var(--rel-body-lg-regular-line-height);\n letter-spacing: var(--rel-body-lg-regular-letter-spacing);\n }\n\n .rel-menu:focus-visible,\n :host(:focus-visible) .rel-menu {\n outline: 2px solid var(--rel-border-focus);\n outline-offset: 2px;\n }\n\n .rel-menu-item {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--rel-spacing-xs);\n padding: var(--rel-spacing-xs) var(--rel-spacing-sm);\n line-height: var(--rel-body-sm-regular-line-height);\n cursor: pointer;\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n }\n\n /* First/last items carry the menu's outer radius so their hover fill clips\n to the rounded corners (replaces the removed overflow:hidden). */\n .rel-menu > .rel-menu-item:first-child {\n border-top-left-radius: var(--rel-border-radius-md);\n border-top-right-radius: var(--rel-border-radius-md);\n }\n\n .rel-menu > .rel-menu-item:last-child {\n border-bottom-left-radius: var(--rel-border-radius-md);\n border-bottom-right-radius: var(--rel-border-radius-md);\n }\n\n .rel-menu-item:hover {\n background: var(--rel-bg-neutral-elevated-1);\n }\n\n .rel-menu-item:active {\n background: var(--rel-bg-neutral-elevated-1);\n }\n\n .rel-menu-item.active {\n background: var(--rel-bg-neutral-elevated-2);\n font-weight: var(--rel-body-lg-medium-font-weight);\n }\n\n .rel-menu-item.disabled {\n background-color: transparent;\n color: var(--rel-text-disabled);\n /* Keep the item pointer-interactive so cursor:not-allowed actually\n renders; clicks are already neutralised by the item.disabled guard in\n onItemClick/onItemEnter. pointer-events:none here would make the row\n transparent to the pointer and suppress the cursor. */\n cursor: not-allowed;\n }\n\n /* [data-focused] (presence, not =\"true\"): the ?data-focused boolean\n binding renders the attribute with an EMPTY value, so a =\"true\"\n selector never matches. */\n .rel-menu-item[data-focused] {\n outline: 2px solid var(--rel-border-focus);\n outline-offset: -2px;\n }\n\n /* Width modes (Figma Type=Fixed / Type=Fit) */\n .rel-menu.fixed {\n width: var(--rel-menu-width, 300px);\n min-width: 0;\n box-sizing: border-box;\n }\n\n .rel-menu.fit {\n min-width: 0;\n width: max-content;\n }\n\n /* Checkbox (Type=Checkbox) / radio (Type=Select Option) rows render the real\n rel-checkbox / rel-radio. pointer-events:none keeps the whole row the click\n target so onItemClick stays the single source of truth. */\n .menu-control {\n pointer-events: none;\n width: 100%;\n }\n\n .menu-label {\n flex: 1 1 auto;\n }\n\n /* Submenu affordance \u2014 same rel-icon chevron the menubar uses. */\n .submenu-chevron {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n opacity: 0.6;\n pointer-events: none;\n }\n\n /* Shortcut / hint text (Figma body-sm-regular, caption tone) */\n .menu-shortcut,\n ::slotted([slot=\"shortcut\"]) {\n font-family: var(--rel-body-sm-regular-font-family);\n font-weight: var(--rel-body-sm-regular-font-weight);\n font-size: var(--rel-body-sm-regular-font-size);\n line-height: var(--rel-body-sm-regular-line-height);\n letter-spacing: var(--rel-body-sm-regular-letter-spacing);\n color: var(--rel-text-caption);\n margin-left: auto;\n padding-left: var(--rel-spacing-md);\n }\n\n \n .rel-submenu {\n border: 1px solid var(--rel-border-subtle);\n position: absolute;\n top: calc(-1 * var(--rel-spacing-3xs));\n /* flush against the trigger (no gap) so moving the pointer into the flyout\n never crosses a dead zone that would fire the trigger's mouseleave */\n left: 100%;\n min-width: 200px;\n background: var(--rel-bg-neutral);\n color: var(--rel-text-default);\n border-radius: var(--rel-border-radius-md);\n box-shadow: var(--rel-shadows-shadow-300);\n /* padding:0 + overflow:hidden \u2014 safe here (a submenu has no further nested\n flyout to clip) \u2014 so sub-item hovers fill fully and clip to the corners */\n padding: 0;\n overflow: hidden;\n visibility: hidden;\n pointer-events: none;\n z-index: 20;\n }\n\n .rel-submenu.visible {\n visibility: visible;\n pointer-events: auto;\n }\n\n .rel-submenu .rel-menu-item {\n padding: var(--rel-spacing-xs) var(--rel-spacing-sm);\n }\n ";
1878
+ static readonly _css = "\n :host {\n color: var(--rel-text-default);\n display: inline-block;\n }\n\n .rel-menu {\n position: relative;\n display: inline-block;\n background: var(--rel-bg-neutral);\n color: var(--rel-text-default);\n /* Audit 17: 8px (border-radius/sm), was 16px; Figma Menu (6326:2931) = shadow/md */\n border-radius: var(--rel-border-radius-sm);\n box-shadow: var(--rel-shadows-md);\n /* Figma's Menu container is 300px around 288px rows. */\n min-width: 300px;\n /* No vertical padding: items fill edge-to-edge so a first/last-item hover\n reaches the menu's top/bottom. NOT overflow:hidden \u2014 that clips the\n type=arrow flyout (position:absolute at left:100%). Instead the first\n and last items carry the outer corner radius so hover backgrounds clip\n to the rounded shape without any overflow. */\n padding: 0;\n outline: none;\n overflow: visible;\n font-family: var(--rel-body-lg-regular-font-family);\n font-weight: var(--rel-body-lg-regular-font-weight);\n font-size: var(--rel-body-lg-regular-font-size);\n line-height: var(--rel-body-lg-regular-line-height);\n letter-spacing: var(--rel-body-lg-regular-letter-spacing);\n }\n\n .rel-menu:focus-visible,\n :host(:focus-visible) .rel-menu {\n outline: 2px solid var(--rel-border-focus);\n outline-offset: 0;\n }\n\n /* Rows follow Figma \".Menu Item\" (6326:616) per size:\n Large 48px = pad 12/12 + body-lg (24 line-height)\n Medium 40px = pad 8/12 + body-md (22)\n Small 32px = pad 4/8 + body-sm (20)\n (audit 17a \u2014 before 1.4.7 every row was 36px: pad 8/12 + a 20px line-height) */\n .rel-menu-item {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--rel-spacing-md);\n padding: var(--rel-spacing-sm) var(--rel-spacing-sm);\n line-height: var(--rel-body-lg-regular-line-height);\n min-height: 48px;\n cursor: pointer;\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n box-sizing: border-box;\n /* Figma strokes every item with --rel-border-subtle. Drawn as an inset\n shadow on the BOTTOM edge only (the pattern rel-menubar already uses)\n so the rows read as a divided list rather than 45 boxed cells, and so\n it costs no layout height. */\n box-shadow: inset 0 calc(-1 * var(--rel-stroke-sm)) 0 var(--rel-border-subtle);\n }\n\n .rel-menu-item:last-child {\n box-shadow: none;\n }\n\n /* Light-DOM component: :host never matches here, so size rules key off the\n reflected attribute on the <rel-menu> element itself. */\n rel-menu[size=\"medium\"] .rel-menu,\n rel-menu[size=\"medium\"] .rel-submenu {\n font-family: var(--rel-body-md-regular-font-family);\n font-weight: var(--rel-body-md-regular-font-weight);\n font-size: var(--rel-body-md-regular-font-size);\n line-height: var(--rel-body-md-regular-line-height);\n letter-spacing: var(--rel-body-md-regular-letter-spacing);\n }\n\n /* Figma Medium / Small frames are fixed at 40 / 32 (content sums to 38 / 28) */\n rel-menu[size=\"medium\"] .rel-menu-item {\n padding: var(--rel-spacing-xs) var(--rel-spacing-sm);\n line-height: var(--rel-body-md-regular-line-height);\n min-height: 40px;\n }\n\n rel-menu[size=\"small\"] .rel-menu,\n rel-menu[size=\"small\"] .rel-submenu {\n font-family: var(--rel-body-sm-regular-font-family);\n font-weight: var(--rel-body-sm-regular-font-weight);\n font-size: var(--rel-body-sm-regular-font-size);\n line-height: var(--rel-body-sm-regular-line-height);\n letter-spacing: var(--rel-body-sm-regular-letter-spacing);\n }\n\n rel-menu[size=\"small\"] .rel-menu-item {\n padding: var(--rel-spacing-2xs) var(--rel-spacing-xs);\n line-height: var(--rel-body-sm-regular-line-height);\n min-height: 32px;\n }\n\n /* First/last items carry the menu's outer radius so their hover fill clips\n to the rounded corners (replaces the removed overflow:hidden). */\n .rel-menu > .rel-menu-item:first-child {\n border-top-left-radius: var(--rel-border-radius-sm);\n border-top-right-radius: var(--rel-border-radius-sm);\n }\n\n .rel-menu > .rel-menu-item:last-child {\n border-bottom-left-radius: var(--rel-border-radius-sm);\n border-bottom-right-radius: var(--rel-border-radius-sm);\n }\n\n /* Figma states (6326:616): Hover = action overlay 0.05, Pressed = 0.10\n (nearest token: overlay-pressed), Active/selected list row = the hover\n overlay + medium label; Checkbox / Select Option rows keep no fill when\n selected. Disabled = 40% opacity. (audit 17) */\n .rel-menu-item:hover {\n background: var(--rel-action-overlay-hover);\n }\n\n .rel-menu-item:active {\n background: var(--rel-action-overlay-pressed);\n }\n\n .rel-menu-item.active {\n background: var(--rel-action-overlay-hover);\n }\n\n /* The active weight bump follows the row's own size, and applies to plain\n rows only \u2014 a checkbox row carries its state in the control, and Figma\n does not bold its label. */\n .rel-menu:not(.type-checkbox) .rel-menu-item.active {\n font-weight: var(--rel-body-lg-medium-font-weight);\n }\n\n rel-menu[size=\"medium\"] .rel-menu:not(.type-checkbox) .rel-menu-item.active {\n font-weight: var(--rel-body-md-medium-font-weight);\n }\n\n /* Small's active row is Figma's mixed tuple: an xs-medium WEIGHT with\n sm-medium METRICS on the sm-regular family. Large and Medium step only\n their weight and keep regular metrics, which is why they are one line\n each and this one is four. */\n rel-menu[size=\"small\"] .rel-menu:not(.type-checkbox) .rel-menu-item.active {\n font-weight: var(--rel-body-xs-medium-font-weight);\n font-size: var(--rel-body-sm-medium-font-size);\n line-height: var(--rel-body-sm-medium-line-height);\n letter-spacing: var(--rel-body-sm-medium-letter-spacing);\n }\n\n .rel-menu.type-checkbox .rel-menu-item.active,\n .rel-menu.type-select-option .rel-menu-item.active {\n background: transparent;\n }\n\n .rel-menu.type-checkbox .rel-menu-item.active:hover,\n .rel-menu.type-select-option .rel-menu-item.active:hover {\n background: var(--rel-action-overlay-hover);\n }\n\n .rel-menu-item.disabled {\n background-color: transparent;\n opacity: 0.4;\n /* Keep the item pointer-interactive so cursor:not-allowed actually\n renders; clicks are already neutralised by the item.disabled guard in\n onItemClick/onItemEnter. pointer-events:none here would make the row\n transparent to the pointer and suppress the cursor. */\n cursor: not-allowed;\n }\n\n /* [data-focused] (presence, not =\"true\"): the ?data-focused boolean\n binding renders the attribute with an EMPTY value, so a =\"true\"\n selector never matches. */\n /* Inset ring: items run the full width of the panel and butt against its\n padding, so an outside ring would cross the panel edge. rel-menu has no\n State=Focused variant in Figma; kept deliberately. */\n .rel-menu-item[data-focused] {\n outline: 2px solid var(--rel-border-focus);\n outline-offset: -2px;\n }\n\n /* Width modes (Figma Type=Fixed / Type=Fit). BOTH are 300px wide \u2014\n COMPONENT \"Type=Fixed\" is 300x500 sizing=FIXED/FIXED and\n COMPONENT \"Type=Fit\" is 300x48 sizing=FIXED/HUG \u2014 so the axis varies the\n HEIGHT, not the width: Fixed pins a scrolling panel, Fit hugs its rows.\n This had it inverted: fit varied the width (max-content) and neither mode\n constrained the height, so the two modes differed on the wrong dimension. */\n .rel-menu.fixed {\n width: var(--rel-menu-width, 300px);\n height: var(--rel-menu-height, 500px);\n overflow-y: auto;\n min-width: 0;\n box-sizing: border-box;\n }\n\n .rel-menu.fit {\n width: var(--rel-menu-width, 300px);\n min-width: 0;\n box-sizing: border-box;\n }\n\n /* Checkbox (Type=Checkbox) / radio (Type=Select Option) rows render the real\n rel-checkbox / rel-radio. pointer-events:none keeps the whole row the click\n target so onItemClick stays the single source of truth. */\n .menu-control {\n pointer-events: none;\n width: 100%;\n }\n\n .menu-label {\n flex: 1 1 auto;\n }\n\n /* Submenu affordance \u2014 same rel-icon chevron the menubar uses. */\n .submenu-chevron {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n opacity: 0.6;\n pointer-events: none;\n }\n\n /* Shortcut / hint text (Figma body-sm-regular, caption tone) */\n .menu-shortcut,\n ::slotted([slot=\"shortcut\"]) {\n font-family: var(--rel-body-sm-regular-font-family);\n font-weight: var(--rel-body-sm-regular-font-weight);\n font-size: var(--rel-body-sm-regular-font-size);\n line-height: var(--rel-body-sm-regular-line-height);\n letter-spacing: var(--rel-body-sm-regular-letter-spacing);\n color: var(--rel-text-caption);\n margin-left: auto;\n padding-left: var(--rel-spacing-md);\n }\n\n \n /* No border: the flyout is the same surface as the parent menu, which has\n none \u2014 overlapping surfaces are separated by shadow. Min-width tracks the\n parent's 300px rather than a narrower 200px. */\n .rel-submenu {\n position: absolute;\n top: calc(-1 * var(--rel-spacing-3xs));\n /* flush against the trigger (no gap) so moving the pointer into the flyout\n never crosses a dead zone that would fire the trigger's mouseleave */\n left: 100%;\n min-width: 300px;\n background: var(--rel-bg-neutral);\n color: var(--rel-text-default);\n border-radius: var(--rel-border-radius-sm);\n box-shadow: var(--rel-shadows-md);\n /* padding:0 + overflow:hidden \u2014 safe here (a submenu has no further nested\n flyout to clip) \u2014 so sub-item hovers fill fully and clip to the corners */\n padding: 0;\n overflow: hidden;\n visibility: hidden;\n pointer-events: none;\n z-index: 20;\n }\n\n .rel-submenu.visible {\n visibility: visible;\n pointer-events: auto;\n }\n\n .rel-submenu .rel-menu-item {\n padding: var(--rel-spacing-sm) var(--rel-spacing-sm);\n }\n\n rel-menu[size=\"medium\"] .rel-submenu .rel-menu-item {\n padding: var(--rel-spacing-xs) var(--rel-spacing-sm);\n }\n\n rel-menu[size=\"small\"] .rel-submenu .rel-menu-item {\n padding: var(--rel-spacing-2xs) var(--rel-spacing-xs);\n }\n ";
1047
1879
  createRenderRoot(): this;
1048
1880
  connectedCallback(): void;
1049
1881
  disconnectedCallback(): void;
@@ -1064,14 +1896,22 @@ declare class RelMenu extends LitElement {
1064
1896
  render(): lit_html.TemplateResult<1>;
1065
1897
  }
1066
1898
 
1899
+ /** Figma "Menu Bar" Type (8699:4): `fit` hugs the triggers, `fixed` spans the container. */
1900
+ type MenubarType = "fixed" | "fit";
1901
+ /**
1902
+ * Horizontal application menubar (`role="menubar"`) that turns each child `<rel-menubar-menu>` into a trigger button with a dropdown panel of items, separators, submenus, checkbox items and radio groups; renders into light DOM (no slots or parts).
1903
+ * @cssprop --rel-menubar-width - Width of the bar when `type="fixed"`; default 100%
1904
+ * @cssprop --rel-menubar-panel-width - Width of the dropdown and submenu panels; default 300px
1905
+ */
1067
1906
  declare class RelMenubar extends LitElement {
1068
1907
  /**
1069
- * Opt-in: actually BIND the keys declared via data-shortcut (e.g.
1070
- * data-shortcut="Ctrl+Z"), not just display them. "Ctrl" matches Cmd on
1071
- * Apple platforms when written as "Mod". Keystrokes originating in
1072
- * inputs/textareas/contenteditable are ignored.
1908
+ * Opt-in: actually bind the keys declared via `data-shortcut` on items (e.g. `data-shortcut="Ctrl+Z"`) instead of only displaying them; a "Mod" token means Cmd on Apple platforms and Ctrl elsewhere, and keystrokes that originate in inputs, textareas or contenteditable regions are ignored.
1073
1909
  */
1074
1910
  bindShortcuts: boolean;
1911
+ /**
1912
+ * Width mode (Figma "Menu Bar" Type, 8699:4): `fit` sizes the bar to its triggers, `fixed` stretches it across its container (override the stretched width with `--rel-menubar-width`). The default stays `fit`, which is how the bar has always rendered.
1913
+ */
1914
+ type: MenubarType;
1075
1915
  private menus;
1076
1916
  private openMenuIndex;
1077
1917
  private focusedTriggerIndex;
@@ -1084,7 +1924,7 @@ declare class RelMenubar extends LitElement {
1084
1924
  /** Stable id prefix for aria-activedescendant targets (light DOM, so ids
1085
1925
  * must be unique per menubar instance on the page). */
1086
1926
  private menubarId;
1087
- static readonly _css = "\n /* This component renders into LIGHT DOM (createRenderRoot returns this), so\n :host / <slot> don't work here \u2014 the raw <rel-menubar-menu> definitions\n are data holders that must be hidden with a plain selector. Relying on the\n global rel-menubar-menu.css is not enough: it can't cross a consumer's\n shadow boundary AND it's a no-op in the tsup-built package (css:\"copy\"). */\n rel-menubar {\n color: var(--rel-text-default);\n display: block;\n }\n\n rel-menubar-menu {\n display: none;\n }\n\n .menubar-container {\n display: flex;\n align-items: stretch;\n background: var(--rel-bg-surface-elevated);\n border: var(--rel-stroke-sm) solid var(--rel-border-default);\n border-radius: var(--rel-border-radius-sm);\n overflow: hidden;\n padding: 0;\n gap: var(--rel-spacing-3xs);\n height: 40px;\n width: fit-content;\n font-family: var(--rel-body-sm-regular-font-family);\n font-weight: var(--rel-body-sm-regular-font-weight);\n font-size: var(--rel-body-sm-regular-font-size);\n line-height: var(--rel-body-sm-regular-line-height);\n letter-spacing: var(--rel-body-sm-regular-letter-spacing);\n }\n\n .menubar-trigger {\n display: flex;\n align-items: center;\n align-self: stretch;\n height: 100%;\n padding: 0 var(--rel-spacing-sm);\n background: transparent;\n border: none;\n cursor: pointer;\n font-family: inherit;\n font-size: inherit;\n color: var(--rel-text-label);\n transition: background 0.15s ease;\n user-select: none;\n outline: none;\n }\n\n .menubar-trigger:hover,\n .menubar-trigger.active {\n background: var(--rel-bg-neutral-elevated-2);\n }\n\n .menubar-trigger:focus-visible {\n outline: 2px solid var(--rel-border-focus);\n outline-offset: 2px;\n }\n\n .menubar-panel {\n position: fixed;\n min-width: 220px;\n background: var(--rel-bg-surface);\n border: var(--rel-stroke-sm) solid var(--rel-border-default);\n border-radius: var(--rel-border-radius-sm);\n box-shadow: var(--rel-shadows-shadow-300);\n padding: 0;\n overflow: hidden;\n z-index: 1000;\n display: none;\n }\n\n .menubar-panel.open {\n display: block;\n }\n\n .menu-item {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--rel-spacing-sm);\n padding: var(--rel-spacing-xs) var(--rel-spacing-md);\n cursor: pointer;\n transition: background 0.15s ease;\n user-select: none;\n color: var(--rel-text-label);\n line-height: var(--rel-body-sm-regular-line-height);\n }\n\n .menu-item:hover,\n .menu-item.focused {\n background: var(--rel-bg-neutral-elevated-2);\n }\n\n .menu-item[data-disabled=\"true\"] {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .menu-separator {\n height: var(--rel-stroke-sm);\n background: var(--rel-border-default);\n margin: 0;\n padding: 0;\n }\n\n rel-icon {\n display: inline-flex;\n pointer-events: none;\n }\n\n .menu-submenu-trigger {\n position: relative;\n }\n\n .menu-submenu-trigger rel-icon {\n opacity: 0.6;\n }\n\n .submenu-panel {\n position: fixed;\n min-width: 200px;\n background: var(--rel-bg-surface);\n border: var(--rel-stroke-sm) solid var(--rel-border-default);\n border-radius: var(--rel-border-radius-sm);\n box-shadow: var(--rel-shadows-shadow-300);\n padding: 0;\n overflow: hidden;\n z-index: 1001;\n display: none;\n }\n\n .submenu-panel.open {\n display: block;\n }\n\n .menu-shortcut {\n opacity: 0.6;\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: var(--rel-spacing-3xs);\n font-family: var(--rel-body-xs-regular-font-family);\n font-weight: var(--rel-body-xs-regular-font-weight);\n font-size: var(--rel-body-xs-regular-font-size);\n line-height: var(--rel-body-xs-regular-line-height);\n letter-spacing: var(--rel-body-xs-regular-letter-spacing);\n }\n\n .menubar-panel rel-checkbox {\n display: block;\n width: 100%;\n padding: var(--rel-spacing-xs, 8px) var(--rel-spacing-md, 16px);\n box-sizing: border-box;\n cursor: pointer;\n }\n ";
1927
+ static readonly _css = "\n /* This component renders into LIGHT DOM (createRenderRoot returns this), so\n :host / <slot> don't work here \u2014 the raw <rel-menubar-menu> definitions\n are data holders that must be hidden with a plain selector. Relying on the\n global rel-menubar-menu.css is not enough: it can't cross a consumer's\n shadow boundary AND it's a no-op in the tsup-built package (css:\"copy\"). */\n rel-menubar {\n color: var(--rel-text-default);\n display: block;\n /* Figma Menu Bar / .Menu Bar Item (8699:4, 8698:13) label = body/lg.\n Declared on the host, not on .menubar-container, so the position:fixed\n panels \u2014 siblings of the container, not descendants \u2014 inherit it too. */\n font-family: var(--rel-body-lg-regular-font-family);\n font-weight: var(--rel-body-lg-regular-font-weight);\n font-size: var(--rel-body-lg-regular-font-size);\n line-height: var(--rel-body-lg-regular-line-height);\n letter-spacing: var(--rel-body-lg-regular-letter-spacing);\n }\n\n rel-menubar-menu {\n display: none;\n }\n\n /* Figma Menu Bar (8699:4): bg/fill/neutral/default on border-radius/sm,\n clipping its children, gap spacing/none \u2014 no border and no shadow. */\n .menubar-container {\n display: flex;\n align-items: stretch;\n background: var(--rel-bg-neutral);\n border-radius: var(--rel-border-radius-sm);\n overflow: hidden;\n padding: 0;\n gap: 0;\n min-height: 40px;\n width: fit-content;\n }\n\n /* Type=Fit hugs its triggers (the default); Type=Fixed spans its container.\n Light-DOM component: :host never matches, so these key off the reflected\n attribute on the <rel-menubar> element itself. */\n rel-menubar[type=\"fixed\"] .menubar-container {\n width: var(--rel-menubar-width, 100%);\n }\n\n rel-menubar[type=\"fit\"] .menubar-container {\n width: fit-content;\n }\n\n /* Figma .Menu Bar Item (8698:13): spacing/xs vertical + spacing/md\n horizontal padding around a body/lg label = a 40px trigger. */\n .menubar-trigger {\n display: flex;\n align-items: center;\n justify-content: center;\n align-self: stretch;\n padding: var(--rel-spacing-xs) var(--rel-spacing-md);\n background: transparent;\n border: none;\n cursor: pointer;\n font: inherit;\n color: var(--rel-text-default);\n white-space: nowrap;\n transition: background 0.15s ease;\n user-select: none;\n outline: none;\n }\n\n /* State=Hover / State=Pressed / State=Active / State=Disabled. Active (the\n trigger whose menu is open) is the hover overlay plus a medium label \u2014\n hence the .open class rather than .active, which would collide with the\n :active pressed pseudo at equal specificity. */\n .menubar-trigger:hover:not(.disabled) {\n background: var(--rel-action-overlay-hover);\n }\n\n .menubar-trigger:active:not(.disabled) {\n background: var(--rel-action-overlay-pressed);\n }\n\n .menubar-trigger.open:not(.disabled) {\n background: var(--rel-action-overlay-hover);\n font-weight: var(--rel-body-lg-medium-font-weight);\n }\n\n .menubar-trigger.disabled {\n color: var(--rel-text-disabled);\n background: transparent;\n cursor: not-allowed;\n }\n\n /* Inset ring: the container clips (overflow:hidden), so a positive\n outline-offset would be cut off on the first and last trigger. */\n .menubar-trigger:focus-visible {\n outline: 2px solid var(--rel-border-focus);\n outline-offset: -2px;\n }\n\n /* Figma pairs the Menu Bar with the Menu component (6326:2932) for the\n panel each trigger opens: 300px, bg/fill/neutral/default, border\n radius/sm, shadow/md, clipped \u2014 no border. */\n .menubar-panel,\n .submenu-panel {\n position: fixed;\n width: var(--rel-menubar-panel-width, 300px);\n box-sizing: border-box;\n background: var(--rel-bg-neutral);\n border-radius: var(--rel-border-radius-sm);\n box-shadow: var(--rel-shadows-md);\n padding: 0;\n overflow: hidden;\n display: none;\n outline: none;\n }\n\n .menubar-panel {\n z-index: 1000;\n }\n\n .submenu-panel {\n z-index: 1001;\n }\n\n .menubar-panel.open,\n .submenu-panel.open {\n display: block;\n }\n\n /* Rows follow Figma .Menu Item Large (6326:616): spacing/sm padding all\n round on a body/lg label = 48px, with a border/neutral/subtle rule\n between rows. The rule is an INSET shadow, not a border: Figma strokes\n are drawn inside the 48px frame, so a real border-bottom would push\n every row to 49px. */\n .menu-item {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--rel-spacing-md);\n padding: var(--rel-spacing-sm);\n min-height: 48px;\n box-sizing: border-box;\n box-shadow: inset 0 calc(-1 * var(--rel-stroke-sm)) 0 var(--rel-border-subtle);\n cursor: pointer;\n transition: background 0.15s ease;\n user-select: none;\n color: var(--rel-text-default);\n line-height: var(--rel-body-lg-regular-line-height);\n }\n\n .menu-label {\n flex: 1 1 auto;\n }\n\n .menu-item:hover,\n .menu-item.focused {\n background: var(--rel-action-overlay-hover);\n }\n\n .menu-item:active {\n background: var(--rel-action-overlay-pressed);\n }\n\n .menu-item[data-disabled=\"true\"] {\n opacity: 0.4;\n cursor: not-allowed;\n }\n\n .menu-separator {\n height: var(--rel-stroke-sm);\n background: var(--rel-border-default);\n margin: 0;\n padding: 0;\n }\n\n /* An explicit data-separator replaces the preceding row's subtle rule\n instead of stacking a second line on top of it. */\n .menu-item:has(+ .menu-separator),\n .menubar-panel > rel-checkbox:has(+ .menu-separator),\n .menubar-panel > rel-radio:has(+ .menu-separator) {\n box-shadow: none;\n }\n\n rel-icon {\n display: inline-flex;\n pointer-events: none;\n }\n\n .menu-submenu-trigger {\n position: relative;\n }\n\n /* Figma draws the 20px chevron at full contrast \u2014 no dimming. */\n .submenu-chevron {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n pointer-events: none;\n }\n\n .menu-shortcut {\n margin-left: auto;\n padding-left: var(--rel-spacing-md);\n display: flex;\n align-items: center;\n gap: var(--rel-spacing-3xs);\n color: var(--rel-text-caption);\n font-family: var(--rel-body-sm-regular-font-family);\n font-weight: var(--rel-body-sm-regular-font-weight);\n font-size: var(--rel-body-sm-regular-font-size);\n line-height: var(--rel-body-sm-regular-line-height);\n letter-spacing: var(--rel-body-sm-regular-letter-spacing);\n }\n\n /* Checkbox / radio rows are real rel-checkbox / rel-radio elements rendered\n straight into the panel, so they carry the .Menu Item row box themselves. */\n .menubar-panel > rel-checkbox,\n .menubar-panel > rel-radio {\n display: block;\n width: 100%;\n min-height: 48px;\n padding: var(--rel-spacing-sm);\n box-sizing: border-box;\n box-shadow: inset 0 calc(-1 * var(--rel-stroke-sm)) 0 var(--rel-border-subtle);\n }\n\n .menubar-panel > rel-checkbox {\n cursor: pointer;\n transition: background 0.15s ease;\n }\n\n .menubar-panel > rel-checkbox:hover {\n background: var(--rel-action-overlay-hover);\n }\n ";
1088
1928
  createRenderRoot(): this;
1089
1929
  connectedCallback(): void;
1090
1930
  disconnectedCallback(): void;
@@ -1099,6 +1939,8 @@ declare class RelMenubar extends LitElement {
1099
1939
  * openMenuIndex to -1, which used to drop focus to <body>.) */
1100
1940
  private closeAllMenusAndRefocusTrigger;
1101
1941
  private openMenu;
1942
+ /** A disabled <rel-menubar-menu> keeps its trigger focusable but never opens. */
1943
+ private isMenuDisabled;
1102
1944
  private handleTriggerClick;
1103
1945
  private handleTriggerMouseEnter;
1104
1946
  private handleTriggerKeyDown;
@@ -1118,276 +1960,94 @@ declare class RelMenubar extends LitElement {
1118
1960
  render(): lit_html.TemplateResult<1>;
1119
1961
  }
1120
1962
 
1121
- declare class RelMenubarMenu extends LitElement {
1122
- label: string;
1123
- createRenderRoot(): this;
1124
- render(): lit_html.TemplateResult<1>;
1125
- }
1126
-
1127
- /**
1128
- * @deprecated rel-navbar is deprecated and will be removed in a future release.
1129
- * Use rel-topbar and its sub-components instead:
1130
- * rel-topbar, rel-topbar-brand, rel-topbar-actions, rel-topbar-utilities,
1131
- * rel-topbar-item, rel-topbar-dropdown, rel-topbar-dropdown-item
1132
- */
1133
- declare class RelNavbar extends LitElement {
1134
- constructor();
1135
- sticky: boolean;
1136
- device: "desktop" | "tablet" | "mobile";
1137
- static styles: lit.CSSResult;
1138
- render(): lit_html.TemplateResult<1>;
1139
- }
1140
-
1141
1963
  /**
1142
- * @deprecated Part of the deprecated rel-topbar family. Use a plain
1143
- * `<a>`/logo markup inside the "Navbar" recipe at /docs/recipes/navbar.
1964
+ * Declarative menu definition for `<rel-menubar>`: a hidden (`display: none`) light-DOM holder whose children (`data-item`, `data-separator`, `data-submenu`, `data-checkbox`, `data-radio-group`) the parent menubar reads and renders into a dropdown panel.
1144
1965
  */
1145
- declare class RelTopbarBrand extends LitElement {
1146
- src: string;
1147
- href: string;
1966
+ declare class RelMenubarMenu extends LitElement {
1967
+ /** Text of the trigger button the parent menubar renders for this menu. */
1148
1968
  label: string;
1149
- static styles: lit.CSSResult;
1150
- render(): lit_html.TemplateResult<1>;
1151
- }
1152
- declare global {
1153
- interface HTMLElementTagNameMap {
1154
- "rel-topbar-brand": RelTopbarBrand;
1155
- }
1156
- }
1157
-
1158
- /**
1159
- * @deprecated Part of the deprecated rel-topbar family. Use plain
1160
- * `rel-button` elements inside the "Navbar" recipe at /docs/recipes/navbar.
1161
- */
1162
- declare class RelTopbarActions extends LitElement {
1163
- static styles: lit.CSSResult;
1164
- render(): lit_html.TemplateResult<1>;
1165
- }
1166
- declare global {
1167
- interface HTMLElementTagNameMap {
1168
- "rel-topbar-actions": RelTopbarActions;
1169
- }
1170
- }
1171
-
1172
- /**
1173
- * @deprecated Part of the deprecated rel-topbar family. Use plain
1174
- * `rel-button` (icon variant) elements inside the "Navbar" recipe at /docs/recipes/navbar.
1175
- */
1176
- declare class RelTopbarUtilities extends LitElement {
1177
- static styles: lit.CSSResult;
1178
- render(): lit_html.TemplateResult<1>;
1179
- }
1180
- declare global {
1181
- interface HTMLElementTagNameMap {
1182
- "rel-topbar-utilities": RelTopbarUtilities;
1183
- }
1184
- }
1185
-
1186
- /**
1187
- * @deprecated Part of the deprecated rel-topbar family. Use `rel-drawer`
1188
- * for the mobile nav panel in the "Navbar" recipe at /docs/recipes/navbar.
1189
- */
1190
- declare class RelTopbarMobilePanel extends LitElement {
1191
- static styles: lit.CSSResult;
1192
- render(): lit_html.TemplateResult<1>;
1193
- }
1194
- declare global {
1195
- interface HTMLElementTagNameMap {
1196
- "rel-topbar-mobile-panel": RelTopbarMobilePanel;
1197
- }
1198
- }
1199
-
1200
- /**
1201
- * @deprecated Part of the deprecated rel-topbar family. Use `rel-menu` or
1202
- * `rel-popover` for nav dropdowns in the "Navbar" recipe at /docs/recipes/navbar.
1203
- */
1204
- declare class RelTopbarDropdown extends LitElement {
1205
- static styles: lit.CSSResult;
1969
+ /**
1970
+ * Renders this menu's trigger in the Figma State=Disabled style and stops it
1971
+ * opening by pointer, keyboard or hover-switch. The trigger stays in the tab
1972
+ * order and reachable with the arrow keys (`aria-disabled`, not the native
1973
+ * `disabled` attribute), matching how disabled `data-item` rows behave.
1974
+ */
1975
+ disabled: boolean;
1976
+ createRenderRoot(): this;
1206
1977
  render(): lit_html.TemplateResult<1>;
1207
1978
  }
1208
- declare global {
1209
- interface HTMLElementTagNameMap {
1210
- "rel-topbar-dropdown": RelTopbarDropdown;
1211
- }
1212
- }
1213
1979
 
1980
+ /** What the cells accept — digits only, or digits + ASCII letters. */
1981
+ type OtpInputMode = "numeric" | "alphanumeric";
1982
+ /** @deprecated Use `OtpInputMode`. */
1983
+ type OtpType = OtpInputMode;
1214
1984
  /**
1215
- * @deprecated Part of the deprecated rel-topbar family. Use `rel-menu`'s
1216
- * item slots or `rel-popover` content in the "Navbar" recipe at /docs/recipes/navbar.
1985
+ * Cell scale. Canonical values are the full words (shared field scale:
1986
+ * small 32 / medium 40 / large 48); `sm` / `md` / `lg` are the original
1987
+ * names and keep working as aliases.
1217
1988
  */
1218
- declare class RelTopbarDropdownItem extends LitElement {
1219
- label: string;
1220
- href: string;
1221
- active: boolean;
1222
- static styles: lit.CSSResult;
1223
- private _handleClick;
1224
- render(): lit_html.TemplateResult<1>;
1225
- }
1226
- declare global {
1227
- interface HTMLElementTagNameMap {
1228
- "rel-topbar-dropdown-item": RelTopbarDropdownItem;
1229
- }
1230
- }
1231
-
1232
- type TopbarVariant = "customer" | "carrier";
1233
- type TopbarForceLayout = "auto" | "desktop" | "tablet" | "mobile";
1234
- /**
1235
- * `rel-topbar` — Application-level top navigation / header shell.
1236
- *
1237
- * @deprecated This component's fixed slot structure, hardcoded breakpoint,
1238
- * and built-in overflow logic are too rigid for most real layouts. Use the
1239
- * "Navbar" recipe at /docs/recipes/navbar instead, composed from
1240
- * rel-menu/rel-popover, rel-drawer, and rel-button. Still supported, but
1241
- * will be removed in a future major version.
1242
- *
1243
- * Slots:
1244
- * brand — Logo / wordmark region (left)
1245
- * (default) — Primary nav items (rel-topbar-item elements)
1246
- * actions — CTA / action buttons (customer) or dark-pill area (carrier)
1247
- * utilities — Utility icon buttons (notifications, search, etc.)
1248
- * profile — rel-topbar-profile tile
1249
- * mobile-panel — Collapsed nav panel shown when mobileOpen is true
1250
- *
1251
- * Events:
1252
- * rel-menu-toggle — fired when hamburger is clicked { open: boolean }
1253
- * rel-mobile-open-change — alias of rel-menu-toggle for convenience
1254
- * rel-nav-select — bubbled from child rel-topbar-item { value, label }
1255
- */
1256
- declare class RelTopbar extends LitElement {
1257
- /** Visual variant — affects action/profile region styling */
1258
- variant: TopbarVariant;
1259
- /** Whether the mobile nav panel is currently open */
1260
- mobileOpen: boolean;
1261
- /** Whether to render the hamburger / close toggle button */
1262
- showMenuToggle: boolean;
1263
- /** Reduce height to compact (48 px) mode */
1264
- compact: boolean;
1265
- /** Stick topbar to top of viewport while scrolling */
1266
- sticky: boolean;
1267
- /**
1268
- * Override the responsive layout for demos / storybook.
1269
- * 'auto' respects CSS media queries.
1270
- */
1271
- forceLayout: TopbarForceLayout;
1272
- private _overflowItems;
1273
- private _overflowCount;
1274
- private _overflowItemsData;
1275
- private _resizeObserver?;
1276
- private _resizeTimer?;
1277
- private _measuring;
1278
- private _lastNavWidth;
1279
- static styles: lit.CSSResult;
1280
- firstUpdated(): void;
1281
- disconnectedCallback(): void;
1282
- private _measureNav;
1283
- private onRouterSlotChange;
1284
- private get layoutClass();
1285
- private handleMenuToggle;
1286
- render(): lit_html.TemplateResult<1>;
1287
- }
1288
-
1989
+ type OtpSize = "small" | "medium" | "large" | "sm" | "md" | "lg";
1289
1990
  /**
1290
- * `rel-topbar-item` — A navigation item within rel-topbar.
1291
- *
1292
- * @deprecated Part of the deprecated rel-topbar family. Use the "Navbar" recipe at /docs/recipes/navbar, which composes nav links and
1293
- * `rel-menu`/`rel-popover` dropdowns directly instead of a dedicated item component.
1294
- *
1295
- * Renders as an `<a>` when `href` is supplied, otherwise a `<button>`.
1296
- *
1297
- * Slots:
1298
- * (default) — Label text / icon (overrides `label` property)
1299
- * prefix — Icon/content before the label
1300
- * suffix — Icon/content after the label (e.g. badge)
1301
- * dropdown — Expandable panel content shown below the item
1302
- *
1303
- * Events:
1304
- * rel-select — fired when a non-disabled, non-expandable item is activated
1305
- * rel-toggle — fired when an expandable item is opened/closed { open: boolean }
1991
+ * One-time-password input (Figma "OTP Input"): one single-character cell per position, with auto-advance, smart backspace, paste distribution and optional group separators.
1992
+ * @csspart base - The `role="group"` root container (same element as `root`)
1993
+ * @csspart root - Alias of `base`, kept for existing `::part(root)` selectors
1994
+ * @csspart input - Each single-character cell input (same element as `cell`)
1995
+ * @csspart cell - Alias of `input`, kept for existing `::part(cell)` selectors
1996
+ * @csspart separator - The dash rendered between cell groups
1997
+ * @csspart hidden-input - The hidden form input rendered when `name` is set
1306
1998
  */
1307
- declare class RelTopbarItem extends LitElement {
1308
- /** Accessible label — also shown as text when no default slot content */
1309
- label?: string;
1310
- /** Navigation href — renders an anchor element when set */
1311
- href?: string;
1312
- /** Marks this item as the current/active page */
1313
- active: boolean;
1314
- /** Prevents interaction */
1315
- disabled: boolean;
1316
- /** Shows a chevron and enables dropdown panel */
1317
- expandable: boolean;
1318
- /** Controlled open state of the dropdown panel */
1319
- open: boolean;
1320
- /** Optional string value forwarded in rel-select / rel-toggle events */
1321
- value?: string;
1322
- /** @internal tracks whether dropdown slot has content */
1323
- private _hasDropdown;
1324
- static styles: lit.CSSResult;
1325
- connectedCallback(): void;
1326
- disconnectedCallback(): void;
1327
- private _handleOutsideClick;
1328
- private _handleDocKeydown;
1329
- private _setOpen;
1330
- private _handleTriggerClick;
1331
- private _routeSlots;
1332
- private _handleDropdownSlotChange;
1333
- render(): lit_html.TemplateResult<1>;
1334
- }
1335
-
1336
- type TopbarProfileType = "avatar" | "carrier";
1337
- type TopbarRewardTier = "gold" | "silver" | "platinum" | "bronze" | "regular";
1338
- /**
1339
- * `rel-topbar-profile` — Profile / user tile for the topbar right region.
1340
- *
1341
- * @deprecated Part of the deprecated rel-topbar family. Compose `rel-avatar`
1342
- * directly inside the "Navbar" recipe at /docs/recipes/navbar.
1343
- *
1344
- * type="avatar" Customer avatar with initials circle + optional name/subtitle.
1345
- * type="carrier" Carrier reward tile with reward-tier badge + name/subtitle.
1346
- */
1347
- declare class RelTopbarProfile extends LitElement {
1348
- /** Visual mode */
1349
- type: TopbarProfileType;
1350
- /** One or two initials shown in the avatar circle */
1351
- initials?: string;
1352
- /** Primary display name */
1353
- name?: string;
1354
- /** Secondary line (role, plan, etc.) */
1355
- subtitle?: string;
1356
- /** Reward tier — only meaningful when type="carrier" */
1357
- reward: TopbarRewardTier;
1358
- /** Compact mode — avatar only, no text */
1359
- compact: boolean;
1360
- static styles: lit.CSSResult;
1361
- render(): lit_html.TemplateResult<1>;
1362
- private _renderAvatar;
1363
- private _avatarBg;
1364
- private _renderCarrier;
1365
- }
1366
-
1367
- type OtpType = "numeric" | "alphanumeric";
1368
1999
  declare class RelOtp extends LitElement {
2000
+ /** The concatenated code (all cells joined). Set it to fill the cells programmatically; it never exceeds `length` characters. */
1369
2001
  value: string;
2002
+ /** Total number of cells (characters in the code). */
1370
2003
  length: number;
2004
+ /** Cells per visual group; a separator renders between groups. Grouping applies only when `length` divides evenly by this — otherwise the row renders ungrouped, because a ragged final group would put a separator before a lone cell. So the default `length="6"` is 3–3, `length="4"` is one ungrouped row of four, and `group-size="2"` with `length="4"` is 2–2. `0` (or `show-separator` off) also renders one ungrouped row. */
1371
2005
  groupSize: number;
2006
+ /** Placeholder character shown in every empty cell. */
1372
2007
  placeholder: string;
2008
+ /**
2009
+ * Accepted character set (Trello 5). Describes what the field ACCEPTS, not
2010
+ * a semantic input type — hence the name. Explicitly set it wins over the
2011
+ * deprecated `type`; unset (`""`, like the native `inputMode` accessor it
2012
+ * shadows on the host), `type` (default `"numeric"`) applies. Note the
2013
+ * lowercase `inputmode` prop is a different thing: the raw native keyboard
2014
+ * hint forwarded to each cell.
2015
+ */
2016
+ inputMode: OtpInputMode | "";
2017
+ /** @deprecated Deprecated alias of `inputMode` (attribute `input-mode`); use `input-mode` instead. Kept working in 1.x and logs a one-time console notice. */
1373
2018
  type: OtpType;
2019
+ /** Renders the cells as `type="password"` so entered characters are masked. */
1374
2020
  mask: boolean;
2021
+ /** Disables every cell and dims the control to 0.4 opacity (cell fill and border unchanged, as Figma specifies). */
1375
2022
  disabled: boolean;
2023
+ /** Makes every cell read-only: the value is shown but typing, paste and keyboard editing are ignored. */
1376
2024
  readonly: boolean;
2025
+ /** Marks the first cell `required` for native form validation. */
1377
2026
  required: boolean;
2027
+ /** When set, renders a hidden `<input name="…">` (part `hidden-input`) carrying `value` for native form submission. */
1378
2028
  name: string | null;
2029
+ /** Reserved autocomplete hint. Currently every cell always renders `autocomplete="one-time-code"` regardless of this value. */
1379
2030
  autocomplete: string;
2031
+ /** Raw native `inputmode` keyboard hint forwarded to every cell. Unset, it follows the accepted character set: `numeric` for numeric, `text` for alphanumeric. */
1380
2032
  inputmode: "numeric" | "text" | null;
2033
+ /** Native `pattern` attribute forwarded to every cell (per-character regex for form validation). */
1381
2034
  pattern: string | null;
2035
+ /** Accessible name of the whole group; defaults to "One-time password input". Each cell is additionally labelled "Digit/Character N of M". */
1382
2036
  ariaLabel: string | null;
2037
+ /** Error styling (danger border on every cell) and `aria-invalid="true"`. */
1383
2038
  invalid: boolean;
2039
+ /** Renders the dash separator between groups. Boolean attribute: its presence means true — set the property to `false` to hide separators. Even when on, separators appear only if `length` divides evenly by `group-size`; see `groupSize`. */
1384
2040
  showSeparator: boolean;
1385
- size: "sm" | "md" | "lg";
2041
+ /** Cell size on the shared field scale (square, border-box): `small` 32px, `medium` 40px, `large` 48px (the Figma OTP Input cell). `sm` / `md` / `lg` are deprecated aliases of the full words. */
2042
+ size: OtpSize;
1386
2043
  private cells;
1387
2044
  private hiddenInput?;
1388
2045
  private isUpdatingFromValue;
2046
+ /** inputMode supersedes the deprecated type. */
2047
+ private get mode();
1389
2048
  static styles: lit.CSSResult;
1390
2049
  connectedCallback(): void;
2050
+ protected willUpdate(changed: PropertyValues<this>): void;
1391
2051
  updated(changedProperties: Map<string, any>): void;
1392
2052
  private initializeCells;
1393
2053
  private syncCellsFromValue;
@@ -1403,6 +2063,9 @@ declare class RelOtp extends LitElement {
1403
2063
  private handleFocus;
1404
2064
  private handleBlur;
1405
2065
  private focusCell;
2066
+ /** Native `inputmode` hint for the cells (mobile keyboard). The lowercase
2067
+ * `inputmode` prop is a raw passthrough and wins; otherwise it follows
2068
+ * the accepted character set. */
1406
2069
  private getInputMode;
1407
2070
  private getAriaLabel;
1408
2071
  private getGroups;
@@ -1414,23 +2077,40 @@ declare global {
1414
2077
  }
1415
2078
  }
1416
2079
 
2080
+ /**
2081
+ * Page navigation (Figma "Pagination"): prev/next ghost buttons with numbered pages, a compact "Page X of Y" readout, or a "1–10 of 50" item-range readout. Use it under tables and lists that load one page of results at a time; it never fetches data itself — listen for `rel-change`.
2082
+ * @csspart base - The `role="navigation"` root of the extended layout (page buttons plus the optional "Viewing page" label).
2083
+ * @csspart label - The `role="navigation"` root row of the count-text layout (item-range text plus prev/next nav).
2084
+ */
1417
2085
  declare class RelPagination extends LitElement {
1418
- /** Layout type from Figma: extended (numbered pages), compact (prev/next + page text), count-text (range + nav) */
2086
+ /** Figma "Type": `extended` = prev/next + numbered page buttons (auto-collapses to compact under 480px container width), `compact` = prev/next + "Page X of Y", `count-text` = "start–end of total" item range + prev/next around the current page number. */
1419
2087
  type: "extended" | "compact" | "count-text";
1420
- /** Controlled current page */
2088
+ /** Controlled current page (1-based). When set, the element only emits `rel-change` and waits for the parent to update `page`; leave unset for uncontrolled behaviour. */
1421
2089
  page?: number;
1422
- /** Uncontrolled starting page */
2090
+ /** Starting page for uncontrolled use (ignored when `page` is set). Attribute `defaultPage`, also read once as `default-page` on connect. */
1423
2091
  defaultPage: number;
1424
- /** Total number of pages */
2092
+ /** Total number of pages. `0` (the default) lets `totalItems` / `perPage` compute the page count instead. Attribute `totalPages`, also read once as `total-pages` on connect. */
1425
2093
  totalPages: number;
1426
- /** Total items (used with perPage to auto-compute totalPages in count-text mode) */
2094
+ /** Total item count; with `perPage` it computes the page count when `totalPages` is `0` and is the "of N" figure in the count-text readout. Attribute `totalItems`, also read once as `total-items` on connect. */
1427
2095
  totalItems: number;
1428
- /** Items per page (count-text mode) */
2096
+ /** Items per page, used to compute the page count from `totalItems` and the "start–end" range in the count-text readout. Attribute `perPage`, also read once as `per-page` on connect. */
1429
2097
  perPage: number;
1430
- /** Show "Viewing page X of Y" label below extended pagination */
2098
+ /** Shows a "Viewing page X of Y" caption under the extended layout (ignored by the other types). */
2099
+ /**
2100
+ * DELIBERATE DIVERGENCE — do not flip this default to `true`. Figma's
2101
+ * `Type=Extended` has no boolean for the caption: the "Viewing page 1 of 10"
2102
+ * text is a fixed child of both Extended variants and is load-bearing for
2103
+ * their 78px height (40 + spacing-md + 22). Here it stays opt-in. Ruled by
2104
+ * the user: our behaviour stands and the DESIGN FILE follows our docs.
2105
+ * Defaulting it on would silently add 38px to every existing extended
2106
+ * pagination.
2107
+ */
1431
2108
  showLabel: boolean;
2109
+ /** Dims the whole control to 40% opacity, shows a `not-allowed` cursor and ignores every page change. */
1432
2110
  disabled: boolean;
2111
+ /** Reserved for link-mode pagination. Currently accepted but not rendered: every page control is a `<button>`, so navigate in your `rel-change` handler instead. */
1433
2112
  hrefTemplate: string;
2113
+ /** Accessible name of the `role="navigation"` landmark (attribute `ariaLabel`). Set it when a page contains more than one pagination control. */
1434
2114
  ariaLabel: string;
1435
2115
  private currentPage;
1436
2116
  static styles: lit.CSSResult;
@@ -1454,17 +2134,50 @@ declare class RelPagination extends LitElement {
1454
2134
 
1455
2135
  type SideType = "top" | "right" | "bottom" | "left";
1456
2136
  type AlignType = "start" | "center" | "end";
2137
+ /**
2138
+ * Click-to-open floating panel anchored to a trigger (Figma "Popover"): the first child is the trigger, the `content` slot is the panel, which is promoted to the browser top layer and positioned in viewport coordinates.
2139
+ * @slot - The trigger: the first slotted element toggles the panel on pointer down / Enter / Space and receives `aria-haspopup`, `aria-expanded` and `aria-controls` (a bare `<div>` / `<span>` also gets `tabindex="0"` and `role="button"`).
2140
+ * @slot content - The panel body, usually a `<rel-popover-content>`; rendered inside the fixed, top-layer wrapper only while open.
2141
+ * @csspart arrow - The 14×14 chevron box rendered on the panel edge facing the trigger when `arrow` is set (absent otherwise).
2142
+ * @cssprop --rel-popover-arrow-bg - Fill of the `arrow` chevron (default `--rel-bg-neutral`, matching `<rel-popover-content>`).
2143
+ * @cssprop --rel-popover-arrow-border - **Deprecated.** Stroke of the `arrow` chevron's two slanted edges. The panel no longer draws a border — overlapping surfaces are separated by shadow — so this defaults to `transparent` and the chevron has no edge. Set it to restore a stroke.
2144
+ */
1457
2145
  declare class RelPopover extends LitElement {
2146
+ /** Controlled open state. Leave unset for uncontrolled mode; once set (true or false) the component only emits `rel-open-change` and you must update `open` yourself. */
1458
2147
  open?: boolean;
2148
+ /** Initial state in uncontrolled mode (attribute `defaultopen`); ignored when `open` is set. */
1459
2149
  defaultOpen: boolean;
2150
+ /** Blocks trigger interaction and dims the host to 60% opacity; does not close an already-open panel. */
1460
2151
  disabled: boolean;
2152
+ /** Which side of the trigger the panel opens on: `top`, `right`, `bottom` (default) or `left`. The panel is clamped 8px inside the viewport but never flips to another side. */
1461
2153
  side: SideType;
2154
+ /** Alignment along the cross axis: `start` (left / top edge of the trigger), `center` (default) or `end` (right / bottom edge). */
1462
2155
  align: AlignType;
2156
+ /** Gap between trigger and panel in pixels (attribute `sideoffset`, default 8). With `arrow` the effective gap is at least 13px. */
1463
2157
  sideOffset: number;
2158
+ /** Extra shift along the alignment axis in pixels (attribute `alignoffset`, default 0); positive moves right / down. */
1464
2159
  alignOffset: number;
2160
+ /** Keep Tab / Shift+Tab cycling inside the panel while open (attribute `trapfocus`); use for forms. */
1465
2161
  trapFocus: boolean;
2162
+ /** Close on Escape (attribute `closeonescape`, default true; switch off via the property, e.g. `el.closeOnEscape = false`). */
1466
2163
  closeOnEscape: boolean;
2164
+ /** Close on a pointer-down outside the trigger and panel (attribute `closeonoutsideclick`, default true; switch off via the property). Also lets another popover's opening dismiss this one. */
1467
2165
  closeOnOutsideClick: boolean;
2166
+ /**
2167
+ * Opt-in pointer (audit 23a): a 14×11 triangle on the panel edge that faces
2168
+ * the trigger — the Figma Popover "Chevron" — following `side` and tracking
2169
+ * the trigger's centre along the cross axis (clamped inside the panel).
2170
+ * It is drawn with the panel's tokens (`--rel-popover-arrow-bg` /
2171
+ * `--rel-popover-arrow-border`, defaulting to rel-popover-content's
2172
+ * background and border). With the arrow on, the panel keeps at least the
2173
+ * arrow's height plus 2px away from the trigger so the tip never overlaps
2174
+ * it; larger `sideOffset` values still apply. Default off — existing
2175
+ * popovers render exactly as before.
2176
+ */
2177
+ arrow: boolean;
2178
+ /** Figma Popover (6338:563) chevron: 14 wide × 11 tall. */
2179
+ private static readonly ARROW_WIDTH;
2180
+ private static readonly ARROW_HEIGHT;
1468
2181
  private internalOpen;
1469
2182
  private contentStyle;
1470
2183
  private contentWrapper;
@@ -1513,18 +2226,41 @@ declare global {
1513
2226
  }
1514
2227
  }
1515
2228
 
2229
+ /** Figma Size axis, spelled out. */
2230
+ type PopoverContentSize = "small" | "medium" | "large";
2231
+ /** Alternative spellings, not deprecations — the short names keep working. */
2232
+ type PopoverContentSizeAlias = "sm" | "md" | "lg";
2233
+ type PopoverContentSizeInput = PopoverContentSize | PopoverContentSizeAlias;
2234
+ /**
2235
+ * Styled panel body for `<rel-popover>` (Figma "Popover" surface): neutral background, 1px border, 8px radius, shadow-300, max-width 400px, with heading / paragraph typography for slotted content. Place it in the popover's `content` slot; any other element works there too.
2236
+ * @slot - The panel content (headings, paragraphs, form controls, buttons).
2237
+ * @csspart content - The padded `role="dialog"` box that carries the surface, border, shadow and size padding.
2238
+ */
1516
2239
  declare class RelPopoverContent extends LitElement {
2240
+ /** Accessible name applied to the inner `role="dialog"` box (attribute `aria-label`); describe what the panel is for. */
1517
2241
  ariaLabel: string;
1518
- /** Figma Size axis (S/M/L): panel padding 12/16/20px. */
1519
- size: "sm" | "md" | "lg";
2242
+ /** Figma Size axis: panel padding 12px (`small`), 16px (`medium`, default) or 20px (`large`). `sm` / `md` / `lg` are alternative spellings and stay supported — they are normalised to the full words, not deprecated. */
2243
+ size: PopoverContentSizeInput;
2244
+ /** Alternative spellings, NOT deprecations — no console notice. Normalising
2245
+ * keeps the reflected attribute canonical, so the :host([size=…]) rules only
2246
+ * need the full words. */
2247
+ protected willUpdate(changed: Map<string, unknown>): void;
1520
2248
  static styles: lit.CSSResult;
1521
2249
  render(): lit_html.TemplateResult<1>;
1522
2250
  }
1523
2251
 
1524
2252
  type ProgressMode = "linear-determinate" | "linear-indeterminate" | "circular-determinate" | "circular-indeterminate";
2253
+ /**
2254
+ * Progress indicator (Figma "Progress"): a linear bar or a circular ring, each either value-driven (determinate) or looping (indeterminate).
2255
+ * @csspart track - The linear track `<div>` that carries `role="progressbar"` (linear modes only)
2256
+ * @csspart indicator - The filled / sliding bar inside the linear track (linear modes only)
2257
+ */
1525
2258
  declare class RelProgress extends LitElement {
2259
+ /** Shape and behaviour: `linear-*` is a full-width 2px bar, `circular-*` a 36px ring; `*-determinate` fills to `value`, `*-indeterminate` loops an animation and ignores `value`. */
1526
2260
  mode: ProgressMode;
2261
+ /** Completion percentage 0–100 for the determinate modes; out-of-range values are clamped before rendering and before `aria-valuenow`. */
1527
2262
  value: number;
2263
+ /** Accessible name of the progressbar (not rendered visually); defaults to "Progress" for determinate and "Loading" for indeterminate modes. */
1528
2264
  label: string;
1529
2265
  private radius;
1530
2266
  private circumference;
@@ -1538,7 +2274,14 @@ declare class RelProgress extends LitElement {
1538
2274
  render(): lit_html.TemplateResult<1>;
1539
2275
  }
1540
2276
 
2277
+ /**
2278
+ * Flex container that lays out direct-child `<rel-resizable-panel>`s along one axis and lets the user drag or keyboard-nudge the `<rel-resizable-handle>` between two neighbours to trade percentage width/height between them.
2279
+ * @slot - The panels and handles, as direct children in display order (panel, handle, panel, …)
2280
+ * @fires rel-resize - Fired continuously while a handle is dragged. Detail: `{ direction, sizes: number[] }` with one percentage per panel.
2281
+ * @fires rel-resize-end - Fired once when a drag ends (pointerup) and after every keyboard resize step. Detail: `{ direction, sizes: number[] }` with one percentage per panel.
2282
+ */
1541
2283
  declare class RelResizableGroup extends LitElement {
2284
+ /** Layout axis: `horizontal` places panels side by side and resizes widths, `vertical` stacks them and resizes heights; also pushed to every child handle's `orientation`. */
1542
2285
  direction: "horizontal" | "vertical";
1543
2286
  private panels;
1544
2287
  private handles;
@@ -1571,11 +2314,18 @@ declare global {
1571
2314
  }
1572
2315
  }
1573
2316
 
2317
+ /**
2318
+ * One resizable region inside a `<rel-resizable-group>`: a padded, scrollable (`overflow: auto`) flex column whose size along the group axis is a percentage managed by the group.
2319
+ * @slot - The panel's content; slotted `h1`–`h4` get the headings-md role
2320
+ */
1574
2321
  declare class RelResizablePanel extends LitElement {
2322
+ /** Initial size as a percentage of the group; panels without one share whatever is left of 100%, then all sizes are normalised to sum to 100. Attribute is `defaultsize`. */
1575
2323
  defaultSize?: number;
2324
+ /** Smallest size (percentage) the panel can be resized to. Attribute is `minsize`. */
1576
2325
  minSize: number;
2326
+ /** Largest size (percentage) the panel can be resized to. Attribute is `maxsize`. */
1577
2327
  maxSize: number;
1578
- /** Current computed size in percentage */
2328
+ /** Current size as a percentage of the group (also written to the host's `flex-basis`); read-only — the parent group updates it on every resize. */
1579
2329
  currentSize: number;
1580
2330
  static styles: lit.CSSResult;
1581
2331
  render(): lit_html.TemplateResult<1>;
@@ -1586,16 +2336,21 @@ declare global {
1586
2336
  }
1587
2337
  }
1588
2338
 
2339
+ /**
2340
+ * Focusable `role="separator"` splitter placed between two `<rel-resizable-panel>`s inside a `<rel-resizable-group>`; the group owns the drag and keyboard logic, the handle only renders the grab bar and exposes the split via ARIA.
2341
+ */
1589
2342
  declare class RelResizableHandle extends LitElement {
2343
+ /** Axis the handle separates: `horizontal` = 8px-wide vertical bar with `col-resize` cursor, `vertical` = 8px-tall bar with `row-resize`; set automatically from the parent group's `direction` on first render and mirrored to `aria-orientation`. */
1590
2344
  orientation: "horizontal" | "vertical";
1591
- /** Index of this handle in the parent group */
2345
+ /** @internal Index of this handle in the parent group; assigned by the group on first render. */
1592
2346
  handleIndex: number;
1593
- /** Current split value (0-100) for aria-valuenow */
2347
+ /** Current split of the two neighbouring panels as a percentage 0–100 (share held by the leading panel); read-only — the parent group updates it and mirrors it to `aria-valuenow`. */
1594
2348
  splitValue: number;
1595
2349
  static styles: lit.CSSResult;
1596
2350
  connectedCallback(): void;
1597
2351
  updated(changed: Map<string, unknown>): void;
1598
2352
  private updateAriaOrientation;
2353
+ /** @internal Called by the parent group after every resize to store `splitValue` and write `aria-valuenow` / `aria-valuemin` / `aria-valuemax`. */
1599
2354
  updateAriaValue(value: number): void;
1600
2355
  render(): lit_html.TemplateResult<1>;
1601
2356
  }
@@ -1605,17 +2360,38 @@ declare global {
1605
2360
  }
1606
2361
  }
1607
2362
 
1608
- type SegmentSize = "small" | "medium";
2363
+ type SegmentSize = "small" | "medium" | "large";
1609
2364
  type SegmentAlign = "left" | "middle" | "right";
1610
2365
  interface SegmentOption {
1611
2366
  label: string;
1612
2367
  value: string;
1613
2368
  disabled?: boolean;
2369
+ /** `rel-icon` name rendered before the label (Figma "Left Icon"), sized 16 / 18 / 20 with the control. */
2370
+ icon?: string;
2371
+ /**
2372
+ * Trailing badge (Figma "Show Badge" / "Badge"), rendered after the label
2373
+ * inside the segment's own 8px gap. A number or string shows the count at
2374
+ * `medium` and `large`; at `small` Figma switches to the 6px dot, so the
2375
+ * value is not displayed there. Use `true` for a dot at any size.
2376
+ */
2377
+ badge?: number | string | boolean;
1614
2378
  }
2379
+ /**
2380
+ * Single-select segmented button group: renders one `<button role="radio">` per entry in `options` on a 2px-inset track (`role="radiogroup"`), with exactly one segment active at a time.
2381
+ * @csspart base - The `role="radiogroup"` track that lays out the segments.
2382
+ * @csspart option - Each segment's native `<button role="radio">`; the active one carries the `active` class and `aria-checked="true"`.
2383
+ * @csspart icon - A segment's optional leading `rel-icon` element.
2384
+ * @csspart badge - A segment's optional trailing `rel-badge`; rendered only when the option sets `badge`.
2385
+ * @csspart label - The wrapper around a segment's label text.
2386
+ */
1615
2387
  declare class RelSegmentedButton extends LitElement {
2388
+ /** The segments in order, each `{ label: string; value: string; disabled?: boolean; icon?: string; badge?: number | string | boolean }`. Set as a property (or a JSON array attribute); a disabled entry is rendered but cannot be selected, and `icon` names a `rel-icon` drawn before the label. */
1616
2389
  options: SegmentOption[];
2390
+ /** `value` of the currently selected segment. Updated by the component on click / arrow keys; set it to pre-select a segment (an unknown value selects nothing). */
1617
2391
  active: string;
2392
+ /** Control height, matching the TextField ramp: `small` (32px — 28px segments, `action-md` 12px text, 16px icons), `medium` (default, 40px — 36px segments, `action-lg` 14px text, 18px icons) or `large` (48px — 44px segments, `action-xl` 16px text, 20px icons). */
1618
2393
  size: SegmentSize;
2394
+ /** `justify-content` of the group's inline-flex container: `left` (default), `middle` or `right`. Only visible when the host is made wider than its content. */
1619
2395
  align: SegmentAlign;
1620
2396
  /** Accessible name for the radiogroup (it renders no visible group label). */
1621
2397
  fieldAriaLabel?: string;
@@ -1625,6 +2401,13 @@ declare class RelSegmentedButton extends LitElement {
1625
2401
  * one Tab stop (roving tabindex on the selected segment). */
1626
2402
  private onKeyDown;
1627
2403
  private renderSegment;
2404
+ /**
2405
+ * Figma's Show Badge axis: a 20x20 numeric badge at medium and large, and a
2406
+ * 6px dot at small — where the count is not shown at all, so a numeric value
2407
+ * degrades to a dot rather than being squeezed in. `badge: true` asks for the
2408
+ * dot at any size.
2409
+ */
2410
+ private renderBadge;
1628
2411
  render(): lit_html.TemplateResult<1>;
1629
2412
  }
1630
2413
 
@@ -1641,8 +2424,49 @@ interface SelectOptionObject {
1641
2424
  icon?: string;
1642
2425
  }
1643
2426
  type SelectOption = string | SelectOptionObject;
2427
+ /**
2428
+ * `<rel-select>` — combobox-style dropdown (Figma "Dropdown"): single- or multi-select
2429
+ * with an optional in-panel search field and width-adaptive selection chips.
2430
+ * @csspart label - The visible label above the trigger (default label style)
2431
+ * @csspart trigger - The button that opens the panel; styled like a text field
2432
+ * @csspart value - The value area inside the trigger (selected label, placeholder or chips)
2433
+ * @csspart helper - The supporting / error text below the trigger
2434
+ * @csspart panel - The dropdown listbox container (same node as `list`)
2435
+ * @csspart list - Alias of `panel`
2436
+ * @csspart input - The search input inside the panel
2437
+ * @csspart option - A single-select option row
2438
+ * @csspart option-label - A single-select row's first line (the option label)
2439
+ * @csspart option-supporting-text - A single-select row's optional second line; rendered only when the option supplies `supportingText`
2440
+ * @cssprop --rel-field-label-reserve - Height held for the label row whenever no label renders above the trigger — `labelStyle="none"`, and `labelStyle="floating"` where the label sits inside the trigger — so the trigger 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).
2441
+ * @cssprop --rel-select-bg - Background of the trigger, the floating label, the panel and its sticky header
2442
+ * @cssprop --rel-select-bg-disabled - Trigger background when `state="disabled"`
2443
+ * @cssprop --rel-select-border-default - Trigger border colour at rest
2444
+ * @cssprop --rel-select-border-disabled - Trigger border colour when `state="disabled"`
2445
+ * @cssprop --rel-select-border-focus - Trigger border colour on hover, while focused (where it also thickens to 2px) and while the panel is open
2446
+ * @cssprop --rel-select-border-error - Trigger border colour when `state="error"`
2447
+ * @cssprop --rel-select-radius - Trigger corner radius when `border="rounded"`
2448
+ * @cssprop --rel-select-icon-color - Colour of the trigger icons, the search icon and option prefix icons
2449
+ * @cssprop --rel-select-label-color - Colour of the static label and of the floated label
2450
+ * @cssprop --rel-select-value-color - Colour of the selected value, the search text, option labels and the check mark
2451
+ * @cssprop --rel-select-placeholder-color - Placeholder colour (trigger, resting floating label, search field, empty-list message)
2452
+ * @cssprop --rel-select-placeholder-disabled-color - Placeholder colour when disabled
2453
+ * @cssprop --rel-select-supporting-color - Supporting text colour (non-error)
2454
+ * @cssprop --rel-select-menu-border - Panel border colour. The panel is borderless by design and only draws this on dark surfaces, where its shadow alone can't separate it from the page.
2455
+ * @cssprop --rel-select-menu-radius - Panel corner radius
2456
+ * @cssprop --rel-select-menu-shadow - Panel box-shadow
2457
+ * @cssprop --rel-select-search-border - Border colour of the search field inside the panel
2458
+ * @cssprop --rel-select-divider - Hairline under the search field, the Select-all row and every option row
2459
+ * @cssprop --rel-select-option-hover - Background of the hovered / keyboard-highlighted / selected option and Select-all row
2460
+ * @cssprop --rel-select-option-pressed - Background of an option row while it is being pressed
2461
+ */
1644
2462
  declare class RelSelect extends LitElement {
2463
+ /** Visible label. Rendered above the trigger (`labelStyle="default"`) or floating inside it; omitted under `labelStyle="none"`. */
1645
2464
  label: string;
2465
+ /**
2466
+ * Label presentation: `default` static label above the trigger; `floating` label
2467
+ * rests in the value area and floats onto the border when focused, open or filled;
2468
+ * `none` renders no label (supply `fieldAriaLabel` / `fieldAriaLabelledby`).
2469
+ */
1646
2470
  labelStyle: SelectLabelStyle;
1647
2471
  /**
1648
2472
  * Accessible name for the trigger. Required when `labelStyle="none"`, since no
@@ -1651,21 +2475,53 @@ declare class RelSelect extends LitElement {
1651
2475
  fieldAriaLabel?: string;
1652
2476
  /** IDREF list of external element(s) naming the trigger. Wins over `fieldAriaLabel`. */
1653
2477
  fieldAriaLabelledby?: string;
2478
+ /**
2479
+ * Options to list. Each entry is a plain string (used as both value and label) or
2480
+ * `{ value, label?, supportingText?, icon? }`; `icon` is a `rel-icon` name rendered
2481
+ * before the label, `supportingText` renders as a second line in both single- and multi-select rows.
2482
+ *
2483
+ * NOTE — the panel's search matches the LABEL ONLY. `supportingText` is displayed but not
2484
+ * searched, so an option is not findable by its second line here. This differs deliberately from
2485
+ * `rel-autocomplete`, whose filter matches the supporting line as well: there the second line
2486
+ * carries identifying data (a DOT or MC number) that a user types to find the row, whereas a
2487
+ * select's is descriptive ("Read-only", "Can edit, not delete") and matching it would return rows
2488
+ * whose visible label has nothing to do with the query.
2489
+ */
1654
2490
  options: SelectOption[];
1655
- /** Enables multi-select: selected values render as removable chips and options as checkboxes. */
2491
+ /** Enables multi-select: selected values render as removable chips, options as checkboxes, and a Select-all row appears in the panel. */
1656
2492
  multiple: boolean;
1657
- /** Selected value — single-select mode only. */
2493
+ /** Selected option value in single-select mode. Ignored when `multiple` is set. */
1658
2494
  selected: string;
1659
- /** Selected values — multi-select mode only. */
2495
+ /** Selected option values in multi-select mode. Reset to `[]` when `multiple` is turned off. */
1660
2496
  selectedValues: string[];
2497
+ /** Visual / interaction state. `error` colours the border and supporting text and clears itself on the next selection; `disabled` blocks interaction and dims the whole field. */
1661
2498
  state: SelectState;
2499
+ /** Helper line below the trigger; coloured as an error while `state="error"`. */
1662
2500
  supportingText: string;
2501
+ /**
2502
+ * `rel-icon` name shown before the supporting text (16px, 14px at `small`).
2503
+ * Optional: the design pairs the helper line with an icon, but existing
2504
+ * fields without one keep their current single-line look.
2505
+ */
2506
+ supportingIcon: string;
2507
+ /**
2508
+ * Field height — `small` 32px, `medium` 40px, `large` 48px. The whole component
2509
+ * rides this one axis: label and supporting type, trigger padding, icons
2510
+ * (20 / 18 / 16), selection chips, and the panel's rows, search field and
2511
+ * checkboxes all scale with it.
2512
+ */
1663
2513
  size: SelectSize;
2514
+ /** Trigger corners: `rounded` applies the corner radius, `sharp` renders square corners. */
1664
2515
  border: SelectBorder;
2516
+ /** `rel-icon` name rendered at the left edge of the trigger. */
1665
2517
  leftIcon: string;
2518
+ /** `rel-icon` name replacing the default chevron at the right edge of the trigger. A custom icon does not rotate when the panel opens. */
1666
2519
  rightIcon: string;
2520
+ /** Text shown in the trigger while nothing is selected. */
1667
2521
  placeholder: string;
2522
+ /** Placeholder of the in-panel search field (the field is hidden when `noSearch` is set). */
1668
2523
  searchPlaceholder: string;
2524
+ /** Label of the Select-all row shown at the top of the panel in multi-select mode. */
1669
2525
  selectAllLabel: string;
1670
2526
  /**
1671
2527
  * Optional hard cap on visible chips. By default (no cap) the visible
@@ -1674,6 +2530,16 @@ declare class RelSelect extends LitElement {
1674
2530
  */
1675
2531
  maxVisibleChips: number;
1676
2532
  /** Hides the in-panel search field. Figma's "Single Option" dropdown has no search bar at all — use this for short, non-searchable lists. */
2533
+ /**
2534
+ * DELIBERATE DIVERGENCE — do not default this to `!multiple`. Figma's
2535
+ * `.Menu Dropdown` shows the search row only on `Type=Multioption`; its
2536
+ * `Type=Single Option` panels contain five Select Option items and nothing
2537
+ * else. Here the search row renders for single-select too unless this is set.
2538
+ * Ruled by the user: our behaviour stands and the DESIGN FILE follows our
2539
+ * docs. A long single-select list is unusable without search, and making the
2540
+ * default depend on `multiple` would change the panel of every existing
2541
+ * single-select.
2542
+ */
1677
2543
  noSearch: boolean;
1678
2544
  private open;
1679
2545
  private highlightedIndex;
@@ -1691,7 +2557,7 @@ declare class RelSelect extends LitElement {
1691
2557
  private listboxEl;
1692
2558
  private valueEl;
1693
2559
  private chipsMeasureEl;
1694
- /** Must match the `gap` of .select-chips / .select-chips-measure. */
2560
+ /** Must match the `gap` of .select-chips / .select-chips-measure (spacing/xs). */
1695
2561
  private static readonly CHIP_GAP;
1696
2562
  private chipResizeObserver?;
1697
2563
  private uniqueId;
@@ -1713,10 +2579,23 @@ declare class RelSelect extends LitElement {
1713
2579
  /** Options matching the current search text (substring match, case-insensitive). */
1714
2580
  private get filteredOptions();
1715
2581
  private get hasValue();
1716
- /** Icon size scales with the select's own size, matching the trigger. */
1717
- private get iconSize();
1718
- /** The search field uses "small" sizing for both small and medium select — only "large" select bumps it to "medium". */
1719
- private get searchIconSize();
2582
+ /**
2583
+ * Selection chips ramp with the field: rel-chip's sm / md / lg are already
2584
+ * the 24 / 28 / 32 heights the spec asks the multi-select value area for.
2585
+ */
2586
+ private get chipSize();
2587
+ /**
2588
+ * Multi-select rows nest the checkbox at the SAME step as the field. This
2589
+ * used to shift one down, compensating for rel-checkbox sitting a size above
2590
+ * the rest of the system — but that ramp has since been realigned to Figma
2591
+ * (16/18/20/24 with body-sm/md/lg/xl labels), so the compensation is now the
2592
+ * bug: it is what made a small multi-select render 14px labels where Figma
2593
+ * asks for 12px. Figma's option content heights are 20 / 22 / 24 for
2594
+ * small / medium / large, which is exactly body-sm / body-md / body-lg — the
2595
+ * checkbox step of the same name. The rows still land on 32 / 40 / 48
2596
+ * through their own padding and min-height.
2597
+ */
2598
+ private get optionCheckboxSize();
1720
2599
  private get selectAllStatus();
1721
2600
  private addGlobalListeners;
1722
2601
  private removeGlobalListeners;
@@ -1761,12 +2640,25 @@ declare global {
1761
2640
 
1762
2641
  type SkeletonShape = "line" | "circle" | "block";
1763
2642
  type SkeletonAnimation = "pulse" | "shimmer" | "none";
2643
+ /**
2644
+ * Loading placeholder: a neutral block, circle or stack of text lines that pulses or shimmers while real content loads, then hides itself once `loaded` is set. Use it in place of content whose size you already know; use a spinner for indeterminate waits.
2645
+ * @csspart base - Each placeholder surface: the single block/circle, or every bar when `shape="line"`.
2646
+ * @cssprop --rel-skeleton-color - Fill colour of the placeholder (defaults to the elevated-3 neutral background token).
2647
+ * @cssprop --rel-skeleton-line-height - Height of each text bar when `shape="line"`; default 16px (Figma's Line shape).
2648
+ * @cssprop --rel-skeleton-highlight - Lighter band that sweeps across the placeholder when `animation="shimmer"` (defaults to the elevated-2 neutral background token).
2649
+ */
1764
2650
  declare class RelSkeleton extends LitElement {
2651
+ /** 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. */
1765
2652
  shape: SkeletonShape;
2653
+ /** Number of text bars when `shape="line"` (minimum 1, --rel-spacing-xs apart); ignored by the other shapes. */
1766
2654
  lines: number;
2655
+ /** Any CSS width (e.g. `"240px"`, `"50%"`) applied to the host's inline style. Empty leaves the host at its natural block width. */
1767
2656
  width: string;
2657
+ /** Any CSS height (e.g. `"120px"`) applied to the host's inline style. Not needed for `circle`, which derives its height from the width. */
1768
2658
  height: string;
2659
+ /** 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`. */
1769
2660
  animation: SkeletonAnimation;
2661
+ /** Set once the real content is ready: hides the skeleton (`display: none`) and removes its `role="status"` / "Loading" label. */
1770
2662
  loaded: boolean;
1771
2663
  protected updated(changed: Map<string, unknown>): void;
1772
2664
  static styles: lit.CSSResult;
@@ -1779,20 +2671,63 @@ declare global {
1779
2671
  }
1780
2672
 
1781
2673
  type ModalSide = "top" | "bottom" | "center";
1782
- type ModalSize = "sm" | "md" | "lg" | "xl" | "fullscreen";
2674
+ /** Panel width scale, spelled out. `fullscreen` has no short form. */
2675
+ type ModalSize = "small" | "medium" | "large" | "extra-large" | "fullscreen";
2676
+ /** Alternative spellings, not deprecations — the short names keep working. */
2677
+ type ModalSizeAlias = "sm" | "md" | "lg" | "xl";
2678
+ type ModalSizeInput = ModalSize | ModalSizeAlias;
2679
+ /**
2680
+ * `"default"` — the body is a free-form slot (24px padding, your own layout).
2681
+ * `"text"` — the Figma Modal Sheet "Text" slot: a message-only modal whose body
2682
+ * is plain copy (16px vertical / 20px horizontal padding, body-lg type) under
2683
+ * the header divider. Additive, opt-in (audit 20c).
2684
+ */
2685
+ type ModalVariant = "default" | "text";
2686
+ /**
2687
+ * Modal sheet dialog (Figma "Modal Sheet", 8171:3412) — a centred, top- or
2688
+ * bottom-anchored panel over a scrim with a title/description header, a
2689
+ * scrollable body, an optional footer and a loading state. Lives in the
2690
+ * `rel-sheet` folder and is exported as `RelModal`.
2691
+ * @slot - Body content of the modal
2692
+ * @slot header - Extra header content rendered under the title/description (e.g. a stepper or tabs)
2693
+ * @slot footer - Actions row (right-aligned, 8px gap); the footer only renders when this slot has content
2694
+ * @csspart overlay - The full-viewport scrim behind the panel
2695
+ * @csspart panel - The dialog panel (role="dialog")
2696
+ * @csspart header - Header row holding title, description, header slot and close button
2697
+ * @csspart close-button - The "X" close button
2698
+ * @csspart content - Scrollable body wrapper around the default slot
2699
+ * @csspart footer - Footer wrapper around the `footer` slot
2700
+ * @csspart loading - Spinner overlay shown while `loading` is set
2701
+ * @cssprop --rel-modal-width - Panel width; overrides the `size` scale (md default `clamp(360px, 49vw, 708px)`, sm `min(400px, 100vw - 32px)`, lg `min(900px, 100vw - 48px)`, xl `min(1140px, 100vw - 48px)`). Ignored by `fullscreen` and by the responsive collapse below 480px
2702
+ * @cssprop --rel-modal-transition-duration - Open/close animation duration; default `0.3s`
2703
+ * @cssprop --rel-modal-transition-timing - Open/close animation easing; default `cubic-bezier(0.32, 0.72, 0, 1)`
2704
+ */
1783
2705
  declare class RelModal extends LitElement {
2706
+ /** Whether the modal is shown. Toggle it to open/close; every change fires `rel-open-change`. */
1784
2707
  open: boolean;
2708
+ /** Where the panel is anchored: `bottom` (48px above the bottom edge, slides up), `top` (48px below the top edge, slides down) or `center` (fades and scales in). Below 480px with `breakpoint="responsive"` every side collapses to a full-width bottom sheet. */
1785
2709
  side: ModalSide;
2710
+ /** Heading text (rendered as an `<h2>`, linked via `aria-labelledby`). The `title` attribute is stripped from the host after it is read so no native tooltip appears. */
1786
2711
  title: string;
2712
+ /** Supporting text under the title (linked via `aria-describedby`). */
1787
2713
  description: string;
1788
2714
  /** Alias for `description`; rendered only when `description` is empty. */
1789
2715
  subtitle: string;
2716
+ /** Coarse dismissal switch. When false the close button is hidden and backdrop clicks / Escape are ignored regardless of the granular `close-on-*` / `show-close-button` props. */
1790
2717
  dismissible: boolean;
2718
+ /** Modal mode: renders the scrim, sets `role="dialog"` + `aria-modal`, traps Tab inside the panel and moves focus in on open. When false the panel is a `region` with no scrim and no focus trap. */
1791
2719
  modal: boolean;
1792
- /** Panel width scale. `md` matches the Figma Modal Sheet width; `fullscreen` covers the viewport. */
1793
- size: ModalSize;
2720
+ /** Panel width scale. `medium` (default) matches the Figma Modal Sheet width; `fullscreen` covers the viewport. `sm` / `md` / `lg` / `xl` are alternative spellings of `small` / `medium` / `large` / `extra-large` and stay supported — they are normalised to the full words, not deprecated. */
2721
+ size: ModalSizeInput;
2722
+ /** Body treatment — see `ModalVariant`. `"text"` styles the default slot as
2723
+ * the Figma "Text" message slot; the header (and its divider) render as
2724
+ * usual above it. Default rendering is unchanged. */
2725
+ variant: ModalVariant;
2726
+ /** Close when the scrim is clicked. Only effective while `dismissible` is true; ignored while `disabled` or `loading`. */
1794
2727
  closeOnBackdropClick: boolean;
2728
+ /** Close on the Escape key. Only effective while `dismissible` is true; ignored while `disabled`. */
1795
2729
  closeOnEscape: boolean;
2730
+ /** Render the "X" close button in the header. Only effective while `dismissible` is true. */
1796
2731
  showCloseButton: boolean;
1797
2732
  /** Move focus into the panel when opened (modal mode only). */
1798
2733
  autoFocus: boolean;
@@ -1818,8 +2753,18 @@ declare class RelModal extends LitElement {
1818
2753
  private originalBodyPaddingRight;
1819
2754
  static styles: lit.CSSResult;
1820
2755
  connectedCallback(): void;
2756
+ /**
2757
+ * The footer divider is conditional: the designer confirmed that short
2758
+ * content (a confirmation message) has no divider, but a body that scrolls
2759
+ * does — it is a scroll affordance, not decoration. There is no CSS way to
2760
+ * ask "does this element scroll", so it is measured and reflected onto the
2761
+ * host as `body-scrolls`, re-measured whenever the body or its contents
2762
+ * resize.
2763
+ */
2764
+ private bodyScrollObserver?;
2765
+ private watchBodyScroll;
1821
2766
  disconnectedCallback(): void;
1822
- protected willUpdate(): void;
2767
+ protected willUpdate(changed: Map<string, unknown>): void;
1823
2768
  updated(changed: Map<string, unknown>): void;
1824
2769
  private handleOpen;
1825
2770
  private handleClose;
@@ -1842,26 +2787,71 @@ declare global {
1842
2787
  */
1843
2788
  type SliderType = "continuous" | "discrete" | "default" | "range";
1844
2789
  type TrackStyle = "solid" | "dotted";
2790
+ /** Figma Size axis, spelled out as in the design file. */
2791
+ type SliderSize = "small" | "medium" | "large";
2792
+ /** Alternative spellings, not deprecations — the original short names keep working. */
2793
+ type SliderSizeAlias = "sm" | "md" | "lg";
2794
+ type SliderSizeInput = SliderSize | SliderSizeAlias;
2795
+ /**
2796
+ * Slider (Figma "Slider", 6417:1340): a pill track with a stroked round thumb,
2797
+ * optional value tooltip, discrete tick marks and a dual-thumb range mode.
2798
+ * Built on native `<input type="range">` so keyboard and assistive-technology
2799
+ * behaviour come for free.
2800
+ * @csspart track - The rail behind the thumb (the filled portion has no part)
2801
+ * @csspart thumb - The round grab handle (one per thumb in range mode)
2802
+ * @csspart tooltip - The value bubble + chevron above each thumb (only while `showBubble` is on)
2803
+ * @cssprop --rel-slider-track-height - Rail thickness; 6 / 8 / 10px for size sm / md / lg
2804
+ * @cssprop --rel-slider-thumb-size - Thumb diameter; 16 / 20 / 24px for size sm / md / lg
2805
+ * @cssprop --rel-slider-thumb-stroke - Width of the hover / pressed / focus ring around the thumb; default 6px
2806
+ * @cssprop --rel-slider-thumb-halo-color - Colour of the keyboard-focus ring; default `var(--rel-border-default)`
2807
+ * @cssprop --rel-slider-tick-size - Tick-mark diameter in discrete mode; 4 / 5 / 6px for size sm / md / lg
2808
+ * @cssprop --rel-slider-bubble-radius - Corner radius of the value bubble; 8px for size sm, otherwise 10px
2809
+ */
1845
2810
  declare class RelSlider extends LitElement {
2811
+ /** 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`. */
1846
2812
  type: SliderType;
1847
- /** Figma Size axis (S/M/L): scales track, thumb and ticks. */
1848
- size: "sm" | "md" | "lg";
2813
+ /**
2814
+ * Draws the tick marks (Figma's separate `Is Determinated` boolean). Works
2815
+ * with ANY `type` — Figma shows ticks on every variant, where the code used
2816
+ * to gate them behind the code-only `type="discrete"`, so a `default` or
2817
+ * `range` slider could never show them.
2818
+ * Left unset it follows `type="discrete"`, so nothing changes for existing
2819
+ * sliders; set it explicitly to override in either direction.
2820
+ */
2821
+ showTicks?: boolean;
2822
+ /** Whether tick marks render: explicit `show-ticks` wins, else the legacy `type="discrete"`. */
2823
+ private get ticksVisible();
2824
+ /** 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. */
2825
+ size: SliderSizeInput;
2826
+ /** Lowest selectable value. */
1849
2827
  min: number;
2828
+ /** Highest selectable value. */
1850
2829
  max: number;
2830
+ /** Increment between values. In `discrete` mode it also spaces the tick marks; in `continuous` mode the native input always moves in steps of 1. */
1851
2831
  step: number;
2832
+ /** Disables interaction and dims the track, thumb and ticks; the tooltip is hidden. */
1852
2833
  disabled: boolean;
2834
+ /** Style of the filled part of the track: `solid` or a `dotted` pattern. */
1853
2835
  track: TrackStyle;
2836
+ /** Print the numeric value under every tick mark. Only has an effect in `discrete` mode. */
1854
2837
  showTickLabels: boolean;
2838
+ /** Show the value tooltip above the thumb(s). */
1855
2839
  showBubble: boolean;
2840
+ /** Current value (the lower value in `range` mode). */
1856
2841
  value: number;
1857
2842
  /** Upper value when type="range" (attribute value-end). */
1858
2843
  valueEnd: number;
2844
+ /** Accessible name for the native range input. In `range` mode it is suffixed with " minimum" / " maximum" per thumb; without it the two thumbs read "Minimum value" / "Maximum value" and a single slider has no name. */
1859
2845
  fieldAriaLabel?: string;
1860
2846
  private ticks;
1861
2847
  private _onChange;
1862
2848
  private _onTouched;
1863
2849
  static styles: lit.CSSResult;
1864
2850
  connectedCallback(): void;
2851
+ /** Alternative spellings, NOT deprecations — no console notice. Normalising
2852
+ * the property rather than duplicating every [size=] selector keeps the
2853
+ * reflected attribute canonical, so only one spelling can reach the CSS. */
2854
+ protected willUpdate(changed: Map<string, unknown>): void;
1865
2855
  updated(changedProperties: Map<string, any>): void;
1866
2856
  private get isRange();
1867
2857
  private get percentage();
@@ -1879,8 +2869,11 @@ declare class RelSlider extends LitElement {
1879
2869
  private getTickLeftPct;
1880
2870
  private isTickActive;
1881
2871
  private onInput;
2872
+ /** @internal Angular ControlValueAccessor bridge. */
1882
2873
  registerOnChange(fn: (value: number) => void): void;
2874
+ /** @internal Angular ControlValueAccessor bridge. */
1883
2875
  registerOnTouched(fn: () => void): void;
2876
+ /** @internal Angular ControlValueAccessor bridge. */
1884
2877
  writeValue(value: number): void;
1885
2878
  private updateActiveWidth;
1886
2879
  private renderThumbContainer;
@@ -1890,16 +2883,50 @@ declare class RelSlider extends LitElement {
1890
2883
  }
1891
2884
 
1892
2885
  type SnackbarLines = "single" | "double";
2886
+ /** Canonical layout axis (Figma "Type"): default | longer-action. */
2887
+ type SnackbarVariant = "default" | "longer-action";
2888
+ /** Canonical semantic tones (Figma "Tone"): neutral | success | warning | destructive. */
2889
+ type SnackbarTone = "neutral" | "success" | "warning" | "destructive";
2890
+ /** Deprecated spellings: "default" → neutral; "error" | "danger" | "critical" → destructive. */
2891
+ type SnackbarToneAlias = "default" | "error" | "danger" | "critical";
2892
+ type SnackbarToneInput = SnackbarTone | SnackbarToneAlias;
2893
+ /** @deprecated since 1.4.7 — use `SnackbarToneInput`. */
1893
2894
  type SnackbarType = "default" | "success" | "error" | "warning";
2895
+ /**
2896
+ * Snackbar (Figma "Snackbar"): a dark, elevated message bar with an optional tone accent and leading status icon, an optional action button and a close icon, shown via `show` and auto-dismissed after `duration` milliseconds. It is not positioned — place it (fixed or in-flow) yourself. Use it for brief feedback with a single follow-up action ("Undo", "Retry"); use `rel-alert` for persistent messages.
2897
+ * @csspart label - The message text container
2898
+ * @csspart action - The action button; rendered only when `action` is set
2899
+ * @csspart close-button - The close icon button; rendered while `iconclose` is true
2900
+ */
1894
2901
  declare class RelSnackbar extends LitElement {
2902
+ /** 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. */
1895
2903
  message: string;
2904
+ /** Label of the optional action button (Figma trailing button, Static / Small); omitted when unset. Clicking it fires `actionClick` and then dismisses the snackbar. */
1896
2905
  action?: string;
2906
+ /**
2907
+ * 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.
2908
+ */
2909
+ variant?: SnackbarVariant;
2910
+ /** @deprecated — 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. */
1897
2911
  longerAction: boolean;
2912
+ /** 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. */
1898
2913
  iconClose: boolean;
2914
+ /** @deprecated — 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. */
1899
2915
  lines: SnackbarLines;
2916
+ /** 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. */
1900
2917
  duration: number;
1901
- type: SnackbarType;
2918
+ /**
2919
+ * 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.
2920
+ */
2921
+ tone?: SnackbarToneInput;
2922
+ /** @deprecated 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. */
2923
+ type?: SnackbarToneInput;
2924
+ /** 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. */
1902
2925
  show: boolean;
2926
+ /** Read-only canonical layout actually rendered: explicit `variant` wins, else either deprecated prop (`lines="double"` or `longerAction`) promotes to `"longer-action"`, else `"default"`. */
2927
+ get resolvedVariant(): SnackbarVariant;
2928
+ /** Read-only canonical tone actually rendered: explicit `tone` wins, else `type`, else `"neutral"`; deprecated aliases are resolved to `"neutral"` / `"destructive"`. */
2929
+ get resolvedTone(): SnackbarTone;
1903
2930
  private visible;
1904
2931
  private _dismissTimer;
1905
2932
  static styles: lit.CSSResult;
@@ -1915,47 +2942,158 @@ declare class RelSnackbar extends LitElement {
1915
2942
  render(): lit_html.TemplateResult<1>;
1916
2943
  }
1917
2944
 
2945
+ /** Control scale, spelled out. Figma has no Size axis on Switch; see the size ramp in the styles. */
2946
+ type SwitchSize = "small" | "medium" | "large";
2947
+ /** Alternative spellings, not deprecations — the short names work too. */
2948
+ type SwitchSizeAlias = "sm" | "md" | "lg";
2949
+ type SwitchSizeInput = SwitchSize | SwitchSizeAlias;
2950
+ /** Which side of the control the label sits on. */
2951
+ type SwitchLabelPlacement = "end" | "start";
2952
+ /**
2953
+ * Toggle switch (Figma "Switch", 5917:1174, Type=Line): a 44×20 control with a
2954
+ * thin 10px track and a 20px handle that slides 20px. Wraps a native checkbox
2955
+ * with `role="switch"`, so keyboard and screen-reader behaviour are native.
2956
+ * @slot - Rich label content beside the control, as an alternative to the `label` property. Clicking it toggles the switch.
2957
+ * @csspart root - The `<label>` holding the control and its optional text; carries the `label-placement` order
2958
+ * @csspart base - The control box around the hidden input and the track
2959
+ * @csspart track - The thin rail; the handle is its `::before` pseudo-element
2960
+ * @csspart label - The text beside the control; not rendered when there is neither a `label` nor slotted content
2961
+ * @cssprop --rel-switch-track-width - Overall control width; defaults to the `size` ramp (36 / 44 / 52px)
2962
+ * @cssprop --rel-switch-track-height - Overall control height; defaults to the `size` ramp — 16 / 20 / 24px for `type="line"`, 20 / 24 / 28px for `type="pill"`
2963
+ * @cssprop --rel-switch-thumb-size - 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
2964
+ * @cssprop --rel-switch-track - Rail colour; default `var(--rel-bg-neutral-elevated-2)`
2965
+ * @cssprop --rel-switch-knob-on - Handle colour when checked; default `var(--rel-bg-neutral-inverse-2)`
2966
+ * @cssprop --rel-switch-knob-off - Handle colour when unchecked; default `var(--rel-text-static-light)`
2967
+ * @cssprop --rel-switch-disabled - Handle colour while disabled; default `var(--rel-bg-neutral-elevated-1)`
2968
+ */
1918
2969
  declare class RelSwitch extends LitElement {
2970
+ /** Whether the switch is on. Set it to control the state programmatically; user toggles update it and fire `rel-change`. */
1919
2971
  checked: boolean;
2972
+ /**
2973
+ * Shape (Figma "Type"): `"line"` (default) is the 44x20 control with a thin
2974
+ * 40x10 rail and the handle riding on it; `"pill"` is the 44x24 filled track
2975
+ * with the handle inside it.
2976
+ * NOTE: Figma's own default is Pill. We default to `line` deliberately —
2977
+ * flipping it would restyle every existing switch — so this is a recorded
2978
+ * divergence from the design default, not an oversight.
2979
+ */
2980
+ type: "line" | "pill";
2981
+ /** Disables interaction and swaps in the dulled rail / handle fills; the handle shadow is removed. */
1920
2982
  disabled: boolean;
2983
+ /** Arbitrary string echoed in the `rel-change` event detail — useful when one handler serves several switches. */
1921
2984
  value: string;
2985
+ /** 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. */
1922
2986
  fieldAriaLabel?: string;
2987
+ /** 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. */
2988
+ label?: string;
2989
+ /**
2990
+ * Which side the label sits on: `end` (default) puts it after the control, `start` before it.
2991
+ *
2992
+ * Note this is a PHYSICAL side, not a writing-direction one, matching every
2993
+ * other placement prop in the library.
2994
+ */
2995
+ labelPlacement: SwitchLabelPlacement;
2996
+ /**
2997
+ * Control scale: `small`, `medium` (default) or `large`. `sm` / `md` / `lg`
2998
+ * are alternative spellings and stay supported — normalised to the full
2999
+ * words, not deprecated.
3000
+ *
3001
+ * Figma's Switch has axes Type / State / Enabled only, with no Size, so this
3002
+ * ramp is ours. `medium` is exactly the control that shipped before it
3003
+ * existed, so an existing switch is unchanged.
3004
+ *
3005
+ * It does NOT respond to viewport width. Picking a size per breakpoint is the
3006
+ * consuming application's decision — a control that silently resized itself
3007
+ * at some width would be undocumentable behaviour, and the breakpoint that
3008
+ * matters belongs to the layout around it, not to the switch.
3009
+ */
3010
+ size: SwitchSizeInput;
1923
3011
  private _onChange;
1924
3012
  private _onTouched;
1925
3013
  private isFocused;
1926
3014
  private isPressed;
3015
+ private hasSlottedLabel;
3016
+ /** Alternative spellings, NOT deprecations — no console notice. Normalising
3017
+ * keeps the reflected attribute canonical so the :host([size=…]) rules only
3018
+ * need the full words. Same shape as rel-chip, rel-slider and rel-radio. */
3019
+ protected willUpdate(changed: Map<string, unknown>): void;
1927
3020
  static styles: lit.CSSResult;
1928
3021
  private toggle;
3022
+ /** @internal Angular ControlValueAccessor bridge. */
1929
3023
  registerOnChange(fn: (value: boolean) => void): void;
3024
+ /** @internal Angular ControlValueAccessor bridge. */
1930
3025
  registerOnTouched(fn: () => void): void;
3026
+ /** @internal Angular ControlValueAccessor bridge. */
1931
3027
  writeValue(checked: boolean): void;
1932
3028
  private handleFocus;
1933
3029
  private handleBlur;
1934
3030
  private handleMouseDown;
1935
3031
  private handleMouseUp;
1936
3032
  render(): lit_html.TemplateResult<1>;
3033
+ /** Rich label content can be slotted instead of set as text; this keeps the
3034
+ * label span out of the layout entirely when neither is present, so an
3035
+ * unlabelled switch has no stray gap beside it. */
3036
+ private onSlotChange;
1937
3037
  }
1938
3038
 
1939
3039
  interface TabItem {
1940
3040
  label: string;
3041
+ /** 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. */
3042
+ icon?: string;
1941
3043
  badge?: number;
1942
3044
  badgeDot?: boolean;
1943
3045
  disabled?: boolean;
1944
3046
  }
3047
+ /**
3048
+ * Tab-strip scale. `sm` / `md` / `lg` are the original names; the full words
3049
+ * `small` / `medium` / `large` are accepted as aliases (Trello 4). Each step
3050
+ * is an explicit item height — 32 / 40 / 48px (Figma Tab Item S/M/L).
3051
+ */
3052
+ type TabSize = "sm" | "md" | "lg" | "small" | "medium" | "large";
3053
+ /**
3054
+ * Declarative tab definition for `<rel-tab>`. Renders nothing itself — place
3055
+ * it in the parent's `items` slot and the parent reads its properties.
3056
+ */
1945
3057
  declare class RelTabItem extends LitElement {
3058
+ /** Text shown on the tab. */
1946
3059
  label: string;
3060
+ /** 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. */
3061
+ icon: string;
3062
+ /** 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`. */
1947
3063
  value: string;
3064
+ /** Count shown in a small badge after the label; `0` hides the badge. */
1948
3065
  badge: number;
1949
3066
  /** Shows a small dot instead of a numbered badge — takes precedence over `badge`. */
1950
3067
  badgeDot: boolean;
3068
+ /** Greys the tab out and skips it in click, arrow-key and Home/End navigation. */
1951
3069
  disabled: boolean;
1952
3070
  render(): lit_html.TemplateResult<1>;
1953
3071
  }
3072
+ /**
3073
+ * Underline tab strip (Figma "Tab Item", 6473:1075) with roving-tabindex
3074
+ * keyboard navigation, optional count/dot badges and a single shared tabpanel
3075
+ * below the strip. Tabs come either from the `tabs` array or from slotted
3076
+ * `<rel-tab-item>` elements.
3077
+ * @slot items - `<rel-tab-item>` definitions; when present they take precedence over the `tabs` array
3078
+ * @slot - Content of the single tabpanel rendered under the strip (always visible — swap it yourself on `rel-tab-change`)
3079
+ * @csspart list - The `role="tablist"` row
3080
+ * @csspart item - Each `role="tab"` element
3081
+ * @csspart label - The text span inside each tab
3082
+ * @cssprop --rel-tab-active-color - Underline colour of the active tab; default `var(--rel-bg-brand)`
3083
+ * @cssprop --rel-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.
3084
+ * @cssprop --rel-tab-text-default - Label colour of the active tab; default `var(--rel-text-default)`
3085
+ * @cssprop --rel-tab-text-hover - Label colour while hovering an enabled tab; default `var(--rel-text-label)`
3086
+ * @cssprop --rel-tab-text-disabled - Label colour of a disabled tab; default `var(--rel-text-disabled)`
3087
+ * @cssprop --rel-tab-hover-color - Background of an inactive tab on hover; default `var(--rel-bg-neutral-elevated-1)`
3088
+ */
1954
3089
  declare class RelTab extends LitElement {
3090
+ /** Tab definitions as `{ label, badge?, badgeDot?, disabled? }` objects — normally set as a property (as an attribute it must be a JSON string). Assign a new array to update; mutating in place does not re-render. Ignored when `<rel-tab-item>` children are slotted into `items`. */
1955
3091
  tabs: TabItem[];
3092
+ /** Zero-based index of the selected tab. Set it to switch tabs programmatically (no event is fired for programmatic changes). */
1956
3093
  activeIndex: number;
1957
- /** Tab size — styled via :host([size]) rules. */
1958
- size: "sm" | "md" | "lg";
3094
+ /** Tab size — styled via :host([size]) rules. Explicit item heights
3095
+ * 32 / 40 / 48px (audit 34); `small|medium|large` alias `sm|md|lg`. */
3096
+ size: TabSize;
1959
3097
  private _tabItems;
1960
3098
  /** Stable id prefix linking tabs to the shared tabpanel. */
1961
3099
  private tabsId;
@@ -1984,14 +3122,31 @@ declare class RelTab extends LitElement {
1984
3122
  * V1.0, node 8301:3771): fixed panel widths 220/250/280 by size, full-bleed
1985
3123
  * columns with 1px dividers, neutral selected state, and a Now / Cancel / OK
1986
3124
  * footer whose buttons are always size S.
3125
+ *
3126
+ * @csspart base - Outer wrapper; carries the size / error / readonly classes
3127
+ * @csspart label - The field label above the trigger
3128
+ * @csspart trigger - The field box that anchors the panel (wraps the text input and the icons)
3129
+ * @csspart value - The editable text input showing the formatted time
3130
+ * @csspart icon - The trailing clock icon
3131
+ * @csspart panel - The popover panel (`role="dialog"`)
3132
+ * @csspart shortcuts - The typed-shortcut chip row at the top of the panel (N → Now)
3133
+ * @csspart option - Each hour / minute / second / AM-PM entry button
3134
+ * @csspart footer - The Now / Cancel / OK row
3135
+ * @csspart helper - The helper / error text live region under the field
3136
+ * @fires rel-focus - Fired when the text input receives focus. No detail.
1987
3137
  */
1988
3138
  declare class RelTimePicker extends LitElement {
1989
3139
  /** Committed time, 24-hour "HH:mm" or "HH:mm:ss" (e.g. "09:30", "17:05:30"). */
1990
3140
  value: string | null;
3141
+ /** Placeholder shown in the field while no value is committed and nothing is typed. */
1991
3142
  placeholder: string;
3143
+ /** Field label rendered above the trigger; also the input's accessible name (unset → "Select time"). */
1992
3144
  label: string | null;
3145
+ /** Disables the field (0.6 opacity, no pointer events); the panel cannot open. */
1993
3146
  disabled: boolean;
3147
+ /** Renders the `*` mark after the label and sets `aria-required`; not enforced by the component. */
1994
3148
  required: boolean;
3149
+ /** Shows the value but blocks typing and opening the panel. */
1995
3150
  readonly: boolean;
1996
3151
  /** Display format of the trigger text and hour column. Value stays 24-hour. */
1997
3152
  format: "12h" | "24h";
@@ -2003,16 +3158,25 @@ declare class RelTimePicker extends LitElement {
2003
3158
  minTime: string | null;
2004
3159
  /** Latest selectable time, "HH:mm" (inclusive). */
2005
3160
  maxTime: string | null;
3161
+ /** Whether the panel is open. Settable from outside; opening resets the draft from `value` (programmatic changes do not fire `rel-open-change`). */
2006
3162
  open: boolean;
3163
+ /** Shows a clear (×) button inside the field while a value is set; clearing commits `null`. */
2007
3164
  clearable: boolean;
3165
+ /** Error styling (danger border, `aria-invalid`) and shows `errorMessage` below the field. */
2008
3166
  error: boolean;
2009
3167
  /** Alias for `error` (requested-API compat); either flag applies error styling. */
2010
3168
  invalid: boolean;
3169
+ /** Text shown below the field while `error` / `invalid` is set (falls back to the typed-entry parse error, then `helperText`). */
2011
3170
  errorMessage?: string;
3171
+ /** Assistive text shown below the field when not in error. */
2012
3172
  helperText?: string;
3173
+ /** When set, renders a hidden `<input name="…">` carrying `value` for native form submission. */
2013
3174
  name?: string;
3175
+ /** Trigger height on the shared field scale — small 32 / medium 40 / large 48px border-box; also sets the panel width (220 / 250 / 280px) and option row height (32 / 36 / 40px). Small lowers the trigger min-width from 160 to 128px. */
2014
3176
  size: "small" | "medium" | "large";
3177
+ /** Visual style; only `"outlined"` exists today. */
2015
3178
  variant: "outlined";
3179
+ /** Fills the parent width (the host is inline-block with intrinsic width otherwise). The attribute is lowercase `fullwidth`. */
2016
3180
  fullWidth: boolean;
2017
3181
  private draftHour;
2018
3182
  private draftMinute;
@@ -2116,19 +3280,110 @@ declare global {
2116
3280
  }
2117
3281
  }
2118
3282
 
3283
+ /** Canonical semantic tones (Figma "Tone"): neutral | destructive. */
3284
+ type ToastTone = "neutral" | "destructive";
3285
+ /** Deprecated spellings: "default" → neutral; "error" | "danger" | "critical" → destructive. */
3286
+ type ToastToneAlias = "default" | "error" | "danger" | "critical";
3287
+ type ToastToneInput = ToastTone | ToastToneAlias;
3288
+ /** @deprecated since 1.4.7 — use `ToastToneInput`. */
2119
3289
  type ToastType = "default" | "error";
3290
+ /**
3291
+ * Where the toast is anchored in the viewport. PHYSICAL sides, not logical
3292
+ * start/end: nothing else in this library adapts to writing direction, and a
3293
+ * logical model in one component would make it the odd one out.
3294
+ */
3295
+ type ToastPosition = "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right";
3296
+ /** Toast scale, spelled out. Figma has no Size axis on Toast; see the ramp in the styles. */
3297
+ type ToastSize = "small" | "medium" | "large";
3298
+ /** Alternative spellings, not deprecations — the short names work too. */
3299
+ type ToastSizeAlias = "sm" | "md" | "lg";
3300
+ type ToastSizeInput = ToastSize | ToastSizeAlias;
3301
+ /**
3302
+ * Transient notification: a fixed-position card with a message, an optional action button and a dismiss button, shown via `show` / `open()` and hidden again after `duration` milliseconds. Anchors to any of six viewport positions (`position`, default `bottom-center`) at three scales (`size`, default `medium`). Use it for brief, non-blocking confirmations; use `rel-alert` for persistent messages.
3303
+ *
3304
+ * STACKING. Toasts sharing a `position` stack automatically — no wrapper element
3305
+ * and no change to your markup. Up to `max-visible` (default 3) show at once,
3306
+ * newest against the anchor edge; any beyond that WAIT rather than being dropped,
3307
+ * and a waiting toast's `duration` does not start until it is actually on screen.
3308
+ * Dismissing one closes the gap for the rest. The six positions stack
3309
+ * independently. Behaviour change: five toasts at one position used to render on
3310
+ * top of each other; now three show and two wait.
3311
+ * @csspart base - The `role="status"` toast container that carries the tone class
3312
+ * @csspart label - The message text span
3313
+ * @csspart action - The action button; rendered only when `actionlabel` is set
3314
+ * @csspart close-button - The dismiss button; rendered while `dismissible` is true
3315
+ * @cssprop --rel-toast-z - `z-index` of the fixed host (default `9000`); raise it when a modal or drawer layer covers the toast
3316
+ * @cssprop --rel-z-toast - Deprecated alias of `--rel-toast-z`, still read as its fallback
3317
+ */
2120
3318
  declare class RelToast extends LitElement {
3319
+ /** Text of the toast. It is also announced to screen readers through the shared live-region announcer each time `show` becomes true. */
2121
3320
  message: string;
2122
- type: ToastType;
3321
+ /**
3322
+ * 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.
3323
+ */
3324
+ tone?: ToastToneInput;
3325
+ /** @deprecated 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. */
3326
+ type?: ToastToneInput;
3327
+ /** Read-only canonical tone actually rendered: explicit `tone` wins, else `type`, else `"neutral"`; deprecated aliases are resolved to `"neutral"` / `"destructive"`. */
3328
+ get resolvedTone(): ToastTone;
3329
+ /** 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. */
2123
3330
  actionLabel?: string;
3331
+ /** 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. */
2124
3332
  duration: number;
3333
+ /** 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. */
2125
3334
  show: boolean;
3335
+ /** 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. */
3336
+ dismissible: boolean;
3337
+ /**
3338
+ * Where the toast is anchored: `bottom-center` (default, unchanged from
3339
+ * before this prop existed), `bottom-left`, `bottom-right`, `top-left`,
3340
+ * `top-center` or `top-right`. Top anchors also animate in from the top edge
3341
+ * rather than upward from the bottom.
3342
+ *
3343
+ * Figma's Toast has axes Content / Show Button / Show Close Button / Tone and
3344
+ * no position, so this axis is ours.
3345
+ */
3346
+ position: ToastPosition;
3347
+ /**
3348
+ * Toast scale: `small`, `medium` (default, unchanged) or `large`. `sm` / `md`
3349
+ * / `lg` are alternative spellings and stay supported — normalised to the
3350
+ * full words, not deprecated. Scales the padding, the inner gap, the message
3351
+ * type role and the close icon. Figma has no Size axis on Toast.
3352
+ */
3353
+ size: ToastSizeInput;
3354
+ /**
3355
+ * How many toasts may be on screen at once AT THIS POSITION. Further ones
3356
+ * wait their turn rather than being dropped — a notification the user never
3357
+ * saw is worse than a late one — and each toast's `duration` only starts
3358
+ * once it actually becomes visible, so a queued message cannot expire unseen.
3359
+ * Default 3; unbounded stacking just fills the viewport.
3360
+ */
3361
+ maxVisible: number;
2126
3362
  private visible;
2127
3363
  private _dismissTimer;
3364
+ /** The stack this instance is currently registered in, so a `position`
3365
+ * change while shown can leave the old stack before joining the new one. */
3366
+ private _registeredAt;
2128
3367
  static styles: lit.CSSResult;
2129
3368
  willUpdate(changed: Map<string, unknown>): void;
3369
+ private joinStack;
3370
+ private leaveStack;
3371
+ /**
3372
+ * Called by the reflow with this instance's admission state. The
3373
+ * auto-dismiss timer starts HERE, on becoming visible — not when `show` is
3374
+ * set — so a toast waiting its turn cannot expire before anyone has seen it.
3375
+ */
3376
+ private _setVisible;
3377
+ /** Offset from the anchor edge, written by the reflow. Index 0 gets no
3378
+ * transform at all, so a lone toast is untouched by the stacking code. */
3379
+ private _setStackOffset;
3380
+ /** Measured height of the rendered card, for the stack arithmetic. */
3381
+ private get _cardHeight();
3382
+ private get anchorsTop();
2130
3383
  disconnectedCallback(): void;
3384
+ /** Shows the toast: sets `show = true`, which starts the auto-dismiss timer and announces `message`. */
2131
3385
  open(): void;
3386
+ /** Hides the toast, clears the auto-dismiss timer and fires `dismissed`. It fires `dismissed` even when the toast was already hidden. */
2132
3387
  close(): void;
2133
3388
  private handleActionClick;
2134
3389
  render(): lit_html.TemplateResult<1>;
@@ -2136,12 +3391,31 @@ declare class RelToast extends LitElement {
2136
3391
 
2137
3392
  type TooltipPosition = "above" | "below" | "left" | "right";
2138
3393
  type TooltipType = "single-line" | "multi-line";
3394
+ /**
3395
+ * Bubble appearance. `inverse` is the original look — an inverse-surface bubble
3396
+ * that is dark-on-light in light mode and light-on-dark in dark mode.
3397
+ * `neutral` is a light-surface bubble, the same sense the word already carries
3398
+ * on rel-toast, where `tone="neutral"` is likewise the light surface.
3399
+ */
3400
+ type TooltipTone = "inverse" | "neutral";
3401
+ /**
3402
+ * Hover/focus tooltip (Figma "Tooltip"): wraps a trigger element and shows a short inverse-coloured text bubble above, below, left or right of it. Use it for supplementary hints on icons and truncated labels only — the text is not reachable on touch and must never be the only place critical information lives.
3403
+ * @slot - The trigger element (one focusable element such as a button or icon button). It receives `aria-describedby` pointing at the bubble.
3404
+ * @csspart panel - The tooltip bubble (`role="tooltip"`): background, padding, radius, shadow and max-width.
3405
+ * @csspart indicator - The triangular tail pointing at the trigger, rendered only when `show-tail` is set.
3406
+ * @cssprop --rel-tooltip-offset - Gap between the trigger and the bubble; defaults to `6px`, or `13px` when `show-tail` is set so the tail clears the trigger.
3407
+ */
2139
3408
  declare class RelTooltip extends LitElement {
3409
+ /** Plain-text content of the bubble. Empty text still renders an (empty) bubble on hover, so always set it. */
2140
3410
  text: string;
3411
+ /** 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. */
2141
3412
  position: TooltipPosition;
3413
+ /** Renders the triangular tail (`indicator` part) on the bubble's edge facing the trigger. */
2142
3414
  showTail: boolean;
2143
- /** Figma "Type": single-line stays on one line; multi-line wraps at a max width. */
3415
+ /** Figma "Type": `single-line` keeps the text on one line and sizes to content; `multi-line` wraps inside a 200px max-width bubble. */
2144
3416
  type: TooltipType;
3417
+ /** 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. */
3418
+ tone: TooltipTone;
2145
3419
  private uniqueId;
2146
3420
  static styles: lit.CSSResult;
2147
3421
  connectedCallback(): void;
@@ -2217,21 +3491,23 @@ interface UploadState {
2217
3491
  * `<rel-upload-actions>` so they can sit in `<rel-modal>`'s footer slot and
2218
3492
  * stay pinned while this body scrolls.
2219
3493
  *
2220
- * Emits (bubbling + composed):
2221
- * - `rel-files-added` — `{ added: UploadFile[], rejected: UploadRejection[] }`
2222
- * - `rel-invalid` — `{ rejected: UploadRejection[] }`
2223
- * - `rel-change` — selection changed; `{ files: UploadFile[] }`
2224
- * - `rel-remove` — row removed; `{ id, file }`
2225
- * - `rel-upload` — Upload pressed; `{ files: UploadFile[] }`
2226
- * - `rel-retry` — Retry pressed; `{ files: UploadFile[] }`
2227
- * - `rel-cancel` — Cancel pressed
2228
- * - `rel-progress` — `{ id, progress, loaded, total }`
2229
- * - `rel-file-complete`— `{ id, file }`
2230
- * - `rel-file-error` — `{ id, file, error }`
2231
- * - `rel-complete` — batch settled; `{ succeeded, failed }`
2232
- * - `rel-state` — derived snapshot changed; `detail: UploadState`
3494
+ * All events bubble and are composed.
2233
3495
  *
2234
3496
  * @element rel-upload
3497
+ * @fires rel-files-added - Fired after files are picked or dropped and validated. Detail: `{ added: UploadFile[], rejected: UploadRejection[] }`.
3498
+ * @fires rel-invalid - Fired just before `rel-files-added` when at least one picked file fails `accept` / `max-size`. Detail: `{ rejected: UploadRejection[] }`.
3499
+ * @fires rel-change - Fired whenever the file list changes (files added, a row removed, `reset()`). Detail: `{ files: UploadFile[] }`.
3500
+ * @fires rel-remove - Fired when a row is removed via its delete button or `removeFile()`. Detail: `{ id: string, file?: File }`.
3501
+ * @fires rel-upload - Fired when Upload is pressed (or `upload()` is called) with the rows still `ready`; in controlled mode the app performs the transfer. Detail: `{ files: UploadFile[] }`.
3502
+ * @fires rel-retry - Fired when Retry re-queues the retryable failed rows. Detail: `{ files: UploadFile[] }`.
3503
+ * @fires rel-cancel - Fired when Cancel is pressed (or `cancel()` is called); in-flight transfers are aborted, the list is kept. No detail.
3504
+ * @fires rel-progress - Fired on every progress tick in self-driving mode. Detail: `{ id: string, progress: number (0–100), loaded: number, total: number }` (bytes).
3505
+ * @fires rel-file-complete - Fired when one file finishes uploading in self-driving mode. Detail: `{ id: string, file: File }`.
3506
+ * @fires rel-file-error - Fired when one file's `uploader` rejects in self-driving mode. Detail: `{ id: string, file: File, error: string }`.
3507
+ * @fires rel-complete - Fired when the whole self-driving batch settles without being cancelled. Detail: `{ succeeded: UploadFile[], failed: UploadFile[] }`.
3508
+ * @fires rel-state - Fired when the derived `state` snapshot changes (and once after connecting). Detail: `UploadState`.
3509
+ * @cssprop --rel-upload-browse-hover-bg - 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.
3510
+ * @csspart browse - The `rel-button` that opens the file picker (Figma "Browse Button": Size=Medium, Style=Secondary).
2235
3511
  */
2236
3512
  declare class RelUpload extends LitElement {
2237
3513
  /** Comma-separated accept list, e.g. ".pdf,.png,.jpg" or "image/*". */
@@ -2253,7 +3529,7 @@ declare class RelUpload extends LitElement {
2253
3529
  * component also maintains it itself as files are added and removed.
2254
3530
  */
2255
3531
  files: UploadFile[];
2256
- /** Supply to run uploads internally. See {@link Uploader}. */
3532
+ /** Supply an `Uploader` `(file, { file, signal, onProgress }) => Promise<void>` to switch to self-driving mode: the component runs the batch itself with `concurrency`, progress, the delay alert, abort and retry. Unset (default) the component only emits intents. */
2257
3533
  uploader?: Uploader;
2258
3534
  /** Max files transferred at once in self-driving mode. */
2259
3535
  concurrency: number;
@@ -2284,6 +3560,7 @@ declare class RelUpload extends LitElement {
2284
3560
  * rather than re-queueing it blindly.
2285
3561
  */
2286
3562
  private get retryable();
3563
+ /** Whether the primary action is enabled: not disabled, nothing in flight, and either `ready` rows exist or (in the failed phase) at least one failed row can be retried. */
2287
3564
  get canUpload(): boolean;
2288
3565
  /** Footer button label — "Upload", "Upload 3 files" or "Retry upload". */
2289
3566
  get primaryLabel(): string;
@@ -2359,6 +3636,9 @@ declare global {
2359
3636
  * specific `<rel-upload>` by id when a container holds more than one.
2360
3637
  *
2361
3638
  * @element rel-upload-actions
3639
+ * @csspart base - The right-aligned flex row holding the buttons
3640
+ * @csspart cancel - The secondary Cancel `rel-button` (absent when `no-cancel` is set)
3641
+ * @csspart primary - The primary Upload / Retry `rel-button`
2362
3642
  */
2363
3643
  declare class RelUploadActions extends LitElement {
2364
3644
  /** Id of the `<rel-upload>` to control. Omit to auto-discover a sibling. */
@@ -2447,8 +3727,7 @@ declare class FocusTrap {
2447
3727
  *
2448
3728
  * Shortcut strings are written as "+"-joined tokens, e.g. "mod+b",
2449
3729
  * "ctrl+shift+p", "escape". The "mod" token means Cmd on Apple platforms
2450
- * and Ctrl everywhere else (this is the pattern rel-sidebar's Ctrl/Cmd+B
2451
- * toggle established). Matching is case-insensitive.
3730
+ * and Ctrl everywhere else. Matching is case-insensitive.
2452
3731
  */
2453
3732
  type ShortcutHandler = (e: KeyboardEvent) => void;
2454
3733
  interface ParsedShortcut {
@@ -2512,4 +3791,4 @@ type Politeness = "polite" | "assertive";
2512
3791
  */
2513
3792
  declare function announce(message: string, politeness?: Politeness): void;
2514
3793
 
2515
- export { type AutocompleteFilter, type AutocompleteItem, type AutocompleteSearchFn, type BindShortcutOptions, type BreadcrumbItem, type ButtonTone, type ButtonVariant, type ChipBorder, type ChipSize, type ChipTone, type ChipVariant, type DrawerCloseReason, type DrawerSide, type FieldLabelStyle, FocusTrap, type LabelPlacement, type MenuItem, type MenuType, type ModalSide, type ModalSize, type Orientation, type OtpType, type ProgressMode, type RadioOption, RelAccordion, RelAlert, RelAutocomplete, RelAvatar, RelBadge, RelBreadcrumbs, RelButton, RelCalendar, RelCard, RelCardMedia, RelCarousel, RelCheckbox, RelChip, RelContainer, RelDatePicker, RelDivider, RelDrawer, RelDrawerFooter, RelKbd, RelKbdGroup, RelLayout, RelMenu, RelMenuItem, RelMenubar, RelMenubarMenu, RelModal, RelNavbar, RelOtp, RelPagination, RelPopover, RelPopoverContent, RelProgress, RelRadio, RelRangePicker, RelResizableGroup, RelResizableHandle, RelResizablePanel, RelSegmentedButton, RelSelect, RelSkeleton, RelSlider, RelSnackbar, RelStepper, RelSwitch, RelTab, RelTabItem, RelTextfield, RelTimePicker, RelToast, RelTooltip, RelTopbar, RelTopbarActions, RelTopbarBrand, RelTopbarDropdown, RelTopbarDropdownItem, RelTopbarItem, RelTopbarMobilePanel, RelTopbarProfile, RelTopbarUtilities, RelUpload, RelUploadActions, type SegmentAlign, type SegmentOption, type SegmentSize, type SelectBorder, type SelectLabelStyle, type SelectOption, type SelectOptionObject, type SelectSize, type SelectState, type ShortcutHandler, type SkeletonAnimation, type SkeletonShape, type SliderType, type SnackbarLines, type SnackbarType, type Step, type StepStatus, type StepperSize, type StepperType, type TabItem, type TextAlign, type TextFieldPrefixStyle, type TextFieldSize, type TextFieldState, type TextFieldVariant, type ToastType, type TooltipPosition, type TooltipType, type TopbarForceLayout, type TopbarProfileType, type TopbarRewardTier, type TopbarVariant, type TrackStyle, type UploadFile, type UploadPhase, type UploadRejection, type UploadState, type UploadStatus, type Uploader, type UploaderContext, announce, bindShortcut, formatShortcutParts, getDeepActiveElement, getFocusableElements, isApplePlatform, isEditableTarget, matchesShortcut, parseShortcut, trapTabKey };
3794
+ export { type AlertTone, type AlertToneAlias, type AlertToneInput, type AutocompleteFilter, type AutocompleteItem, type AutocompleteSearchFn, type AvatarSize, type AvatarSizeAlias, type AvatarSizeInput, type BadgeSize, type BadgeSizeAlias, type BadgeSizeInput, type BindShortcutOptions, type BreadcrumbItem, type ButtonTone, type ButtonVariant, type ChipBorder, type ChipSize, type ChipSizeAlias, type ChipSizeInput, type ChipTone, type ChipToneAlias, type ChipToneInput, type ChipVariant, type ChipVariantAlias, type ChipVariantInput, type ContainerBackground, type ContainerPadding, type ContainerPaddingAlias, type ContainerPaddingInput, type ContainerSurface, type DrawerCloseReason, type DrawerSide, type FieldLabelStyle, FocusTrap, type KbdSize, type LabelPlacement, type MenuItem, type MenuSize, type MenuType, type MenuWidth, type MenubarType, type ModalSide, type ModalSize, type ModalSizeAlias, type ModalSizeInput, type ModalVariant, type Orientation, type OtpInputMode, type OtpSize, type OtpType, type PopoverContentSize, type PopoverContentSizeAlias, type PopoverContentSizeInput, type ProgressMode, type RadioOption, type RadioSize, type RadioSizeAlias, type RadioSizeInput, type RangePickerSize, type RangePickerSizeAlias, type RangePickerSizeInput, RelAccordion, RelAlert, RelAutocomplete, RelAvatar, RelBadge, RelBreadcrumbs, RelButton, RelCalendar, RelCard, RelCardMedia, RelCarousel, RelCheckbox, RelChip, RelContainer, RelDatePicker, RelDivider, RelDrawer, RelDrawerFooter, RelKbd, RelKbdGroup, RelLayout, RelMenu, RelMenuItem, RelMenubar, RelMenubarMenu, RelModal, RelOtp, RelPagination, RelPopover, RelPopoverContent, RelProgress, RelRadio, RelRangePicker, RelResizableGroup, RelResizableHandle, RelResizablePanel, RelSegmentedButton, RelSelect, RelSkeleton, RelSlider, RelSnackbar, RelStepper, RelSwitch, RelTab, RelTabItem, RelTextfield, RelTimePicker, RelToast, RelTooltip, RelUpload, RelUploadActions, type SegmentAlign, type SegmentOption, type SegmentSize, type SelectBorder, type SelectLabelStyle, type SelectOption, type SelectOptionObject, type SelectSize, type SelectState, type ShortcutHandler, type SkeletonAnimation, type SkeletonShape, type SliderSize, type SliderSizeAlias, type SliderSizeInput, type SliderType, type SnackbarLines, type SnackbarTone, type SnackbarToneAlias, type SnackbarToneInput, type SnackbarType, type SnackbarVariant, type Step, type StepStatus, type StepperSize, type StepperType, type SwitchLabelPlacement, type SwitchSize, type SwitchSizeAlias, type SwitchSizeInput, type TabItem, type TabSize, type TextAlign, type TextFieldPrefixStyle, type TextFieldSize, type TextFieldState, type TextFieldVariant, type ToastPosition, type ToastSize, type ToastSizeAlias, type ToastSizeInput, type ToastTone, type ToastToneAlias, type ToastToneInput, type ToastType, type TooltipPosition, type TooltipTone, type TooltipType, type TrackStyle, type UploadFile, type UploadPhase, type UploadRejection, type UploadState, type UploadStatus, type Uploader, type UploaderContext, announce, bindShortcut, formatShortcutParts, getDeepActiveElement, getFocusableElements, isApplePlatform, isEditableTarget, matchesShortcut, parseShortcut, trapTabKey };