@chiralkit/design-system 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +11 -0
  3. package/dist/chiralkit-ds/chiralkit-ds.css +1 -0
  4. package/dist/chiralkit-ds/chiralkit-ds.esm.js +1 -0
  5. package/dist/chiralkit-ds/index.esm.js +1 -0
  6. package/dist/chiralkit-ds/p-038fa008.entry.js +1 -0
  7. package/dist/chiralkit-ds/p-2fdc1012.entry.js +1 -0
  8. package/dist/chiralkit-ds/p-306ec33b.entry.js +1 -0
  9. package/dist/chiralkit-ds/p-3f704698.entry.js +1 -0
  10. package/dist/chiralkit-ds/p-41081d22.entry.js +1 -0
  11. package/dist/chiralkit-ds/p-7d7e5aac.entry.js +1 -0
  12. package/dist/chiralkit-ds/p-84b801f8.entry.js +1 -0
  13. package/dist/chiralkit-ds/p-a28c71b4.entry.js +1 -0
  14. package/dist/chiralkit-ds/p-be84312f.entry.js +1 -0
  15. package/dist/chiralkit-ds/p-c8015fe6.entry.js +1 -0
  16. package/dist/chiralkit-ds/p-d36a6bea.entry.js +1 -0
  17. package/dist/chiralkit-ds/p-e-glNjK6.js +2 -0
  18. package/dist/chiralkit-ds/p-f0f9ff61.entry.js +1 -0
  19. package/dist/cjs/chiralkit-ds.cjs.js +24 -0
  20. package/dist/cjs/ds-badge.cjs.entry.js +18 -0
  21. package/dist/cjs/ds-button.cjs.entry.js +26 -0
  22. package/dist/cjs/ds-card.cjs.entry.js +17 -0
  23. package/dist/cjs/ds-checkbox.cjs.entry.js +67 -0
  24. package/dist/cjs/ds-code-block.cjs.entry.js +39 -0
  25. package/dist/cjs/ds-dialog.cjs.entry.js +67 -0
  26. package/dist/cjs/ds-input.cjs.entry.js +50 -0
  27. package/dist/cjs/ds-loader.cjs.entry.js +26 -0
  28. package/dist/cjs/ds-select.cjs.entry.js +85 -0
  29. package/dist/cjs/ds-tabs.cjs.entry.js +138 -0
  30. package/dist/cjs/ds-textarea.cjs.entry.js +50 -0
  31. package/dist/cjs/ds-tooltip.cjs.entry.js +233 -0
  32. package/dist/cjs/index-mMvyq7U_.js +2018 -0
  33. package/dist/cjs/index.cjs.js +10 -0
  34. package/dist/cjs/loader.cjs.js +12 -0
  35. package/dist/collection/collection-manifest.json +24 -0
  36. package/dist/collection/components/ds-badge/ds-badge.css +36 -0
  37. package/dist/collection/components/ds-badge/ds-badge.js +93 -0
  38. package/dist/collection/components/ds-button/ds-button.css +66 -0
  39. package/dist/collection/components/ds-button/ds-button.js +197 -0
  40. package/dist/collection/components/ds-card/ds-card.css +12 -0
  41. package/dist/collection/components/ds-card/ds-card.js +68 -0
  42. package/dist/collection/components/ds-checkbox/ds-checkbox.css +22 -0
  43. package/dist/collection/components/ds-checkbox/ds-checkbox.js +339 -0
  44. package/dist/collection/components/ds-code-block/ds-code-block.css +65 -0
  45. package/dist/collection/components/ds-code-block/ds-code-block.js +162 -0
  46. package/dist/collection/components/ds-dialog/ds-dialog.css +30 -0
  47. package/dist/collection/components/ds-dialog/ds-dialog.js +313 -0
  48. package/dist/collection/components/ds-input/ds-input.css +38 -0
  49. package/dist/collection/components/ds-input/ds-input.js +353 -0
  50. package/dist/collection/components/ds-loader/ds-loader.css +94 -0
  51. package/dist/collection/components/ds-loader/ds-loader.js +149 -0
  52. package/dist/collection/components/ds-select/ds-select.css +69 -0
  53. package/dist/collection/components/ds-select/ds-select.js +235 -0
  54. package/dist/collection/components/ds-tabs/ds-tabs.css +59 -0
  55. package/dist/collection/components/ds-tabs/ds-tabs.js +248 -0
  56. package/dist/collection/components/ds-textarea/ds-textarea.css +41 -0
  57. package/dist/collection/components/ds-textarea/ds-textarea.js +342 -0
  58. package/dist/collection/components/ds-tooltip/ds-tooltip.css +31 -0
  59. package/dist/collection/components/ds-tooltip/ds-tooltip.js +318 -0
  60. package/dist/collection/components.js +2 -0
  61. package/dist/collection/index.js +1 -0
  62. package/dist/components/ds-badge.d.ts +11 -0
  63. package/dist/components/ds-badge.js +1 -0
  64. package/dist/components/ds-button.d.ts +11 -0
  65. package/dist/components/ds-button.js +1 -0
  66. package/dist/components/ds-card.d.ts +11 -0
  67. package/dist/components/ds-card.js +1 -0
  68. package/dist/components/ds-checkbox.d.ts +11 -0
  69. package/dist/components/ds-checkbox.js +1 -0
  70. package/dist/components/ds-code-block.d.ts +11 -0
  71. package/dist/components/ds-code-block.js +1 -0
  72. package/dist/components/ds-dialog.d.ts +11 -0
  73. package/dist/components/ds-dialog.js +1 -0
  74. package/dist/components/ds-input.d.ts +11 -0
  75. package/dist/components/ds-input.js +1 -0
  76. package/dist/components/ds-loader.d.ts +11 -0
  77. package/dist/components/ds-loader.js +1 -0
  78. package/dist/components/ds-select.d.ts +11 -0
  79. package/dist/components/ds-select.js +1 -0
  80. package/dist/components/ds-tabs.d.ts +11 -0
  81. package/dist/components/ds-tabs.js +1 -0
  82. package/dist/components/ds-textarea.d.ts +11 -0
  83. package/dist/components/ds-textarea.js +1 -0
  84. package/dist/components/ds-tooltip.d.ts +11 -0
  85. package/dist/components/ds-tooltip.js +1 -0
  86. package/dist/components/index.d.ts +35 -0
  87. package/dist/components/index.js +1 -0
  88. package/dist/components/p-DDUZow8F.js +1 -0
  89. package/dist/components/p-ZsYP0VBq.js +1 -0
  90. package/dist/components/p-k0ywxWpC.js +1 -0
  91. package/dist/esm/chiralkit-ds.js +20 -0
  92. package/dist/esm/ds-badge.entry.js +16 -0
  93. package/dist/esm/ds-button.entry.js +24 -0
  94. package/dist/esm/ds-card.entry.js +15 -0
  95. package/dist/esm/ds-checkbox.entry.js +65 -0
  96. package/dist/esm/ds-code-block.entry.js +37 -0
  97. package/dist/esm/ds-dialog.entry.js +65 -0
  98. package/dist/esm/ds-input.entry.js +48 -0
  99. package/dist/esm/ds-loader.entry.js +24 -0
  100. package/dist/esm/ds-select.entry.js +83 -0
  101. package/dist/esm/ds-tabs.entry.js +136 -0
  102. package/dist/esm/ds-textarea.entry.js +48 -0
  103. package/dist/esm/ds-tooltip.entry.js +231 -0
  104. package/dist/esm/index-e-glNjK6.js +2008 -0
  105. package/dist/esm/index.js +3 -0
  106. package/dist/esm/loader.js +10 -0
  107. package/dist/index.cjs.js +1 -0
  108. package/dist/index.js +1 -0
  109. package/dist/layouts/app-shell.css +84 -0
  110. package/dist/tests/a11y.js +55 -0
  111. package/dist/types/Users/alex/projects/MyGitHub/chiralkit/packages/design-system/.stencil/tests/a11y.d.ts +17 -0
  112. package/dist/types/components/ds-badge/ds-badge.d.ts +54 -0
  113. package/dist/types/components/ds-button/ds-button.d.ts +75 -0
  114. package/dist/types/components/ds-card/ds-card.d.ts +53 -0
  115. package/dist/types/components/ds-checkbox/ds-checkbox.d.ts +94 -0
  116. package/dist/types/components/ds-code-block/ds-code-block.d.ts +83 -0
  117. package/dist/types/components/ds-dialog/ds-dialog.d.ts +148 -0
  118. package/dist/types/components/ds-input/ds-input.d.ts +104 -0
  119. package/dist/types/components/ds-loader/ds-loader.d.ts +64 -0
  120. package/dist/types/components/ds-select/ds-select.d.ts +123 -0
  121. package/dist/types/components/ds-tabs/ds-tabs.d.ts +155 -0
  122. package/dist/types/components/ds-textarea/ds-textarea.d.ts +93 -0
  123. package/dist/types/components/ds-tooltip/ds-tooltip.d.ts +26 -0
  124. package/dist/types/components.d.ts +3068 -0
  125. package/dist/types/index.d.ts +1 -0
  126. package/dist/types/stencil-public-runtime.d.ts +1861 -0
  127. package/docs.json +2112 -0
  128. package/loader/cdn.js +1 -0
  129. package/loader/index.cjs.js +1 -0
  130. package/loader/index.d.ts +24 -0
  131. package/loader/index.es2017.js +1 -0
  132. package/loader/index.js +2 -0
  133. package/package.json +78 -0
  134. package/react/components/ds-badge.tsx +25 -0
  135. package/react/components/ds-button.tsx +25 -0
  136. package/react/components/ds-card.tsx +25 -0
  137. package/react/components/ds-checkbox.tsx +25 -0
  138. package/react/components/ds-code-block.tsx +25 -0
  139. package/react/components/ds-dialog.tsx +31 -0
  140. package/react/components/ds-input.tsx +25 -0
  141. package/react/components/ds-loader.tsx +25 -0
  142. package/react/components/ds-select.tsx +25 -0
  143. package/react/components/ds-tabs.tsx +25 -0
  144. package/react/components/ds-textarea.tsx +25 -0
  145. package/react/components/ds-tooltip.tsx +25 -0
  146. package/react/components.ts +162 -0
@@ -0,0 +1,3068 @@
1
+ /* eslint-disable */
2
+ /* tslint:disable */
3
+ /**
4
+ * This is an autogenerated file created by the Stencil compiler.
5
+ * It contains typing information for all components that exist in this project.
6
+ */
7
+ import { HTMLStencilElement, JSXBase } from "./stencil-public-runtime";
8
+ import { DsSelectOption } from "./components/ds-select/ds-select";
9
+ import { DsTabItem } from "./components/ds-tabs/ds-tabs";
10
+ export { DsSelectOption } from "./components/ds-select/ds-select";
11
+ export { DsTabItem } from "./components/ds-tabs/ds-tabs";
12
+ export namespace Components {
13
+ /**
14
+ * ## Accessibility
15
+ * **Category:** static-display
16
+ * **APG pattern:** N/A — non-interactive text label.
17
+ * **Keyboard interactions:**
18
+ * - Tab: N/A — the badge is not focusable and does not appear in tab order.
19
+ * - Enter: N/A.
20
+ * - Escape: N/A.
21
+ * - Arrow keys: N/A.
22
+ * - Printable characters: N/A.
23
+ * **ARIA:**
24
+ * - Roles used: none — renders a plain `<span>` around a `<slot />`. The
25
+ * `variant` prop is a purely visual axis and MUST NOT be the sole carrier
26
+ * of information (color/style alone fails WCAG 1.4.1 Use of Color); the
27
+ * textual content inside the slot must convey the same meaning.
28
+ * - State attributes: none.
29
+ * - Labeling strategy: visible text via `<slot />`. Consumers place the
30
+ * readable label directly inside the tag.
31
+ * **Focus:**
32
+ * - On mount: nothing auto-focuses.
33
+ * - On activate/open: N/A — non-interactive.
34
+ * - On close/deactivate: N/A.
35
+ * - Focus indicator: N/A — the host is not focusable. If a consumer wraps
36
+ * `ds-badge` in an interactive element (e.g. `<button>`, `<a>`), that
37
+ * wrapper owns the focus indicator via the DS `--ds-color-focus` token
38
+ * and its own `:focus-visible` rule.
39
+ * **Motion:**
40
+ * - Animations: none.
41
+ * - Reduced-motion behavior: N/A.
42
+ * **Contrast:**
43
+ * - Text: inherits `color: inherit` / `currentColor` from the host page and
44
+ * the variant-specific style; not verified in isolation here. Consumers
45
+ * are responsible for confirming ≥ 4.5:1 (WCAG 1.4.3) against the surface
46
+ * the badge is placed on.
47
+ * - Non-text: no state-conveying icons or borders that need the 3:1
48
+ * non-text contrast threshold.
49
+ * **Screen reader announcement:**
50
+ * - Rendered state: announces the slot text as inline content within its
51
+ * surrounding context (no role means AT reads it as plain text). The
52
+ * `variant` value is not announced — that is intentional; the label text
53
+ * is the source of truth for meaning.
54
+ * - State change: N/A — no dynamic state owned by this component.
55
+ */
56
+ interface DsBadge {
57
+ /**
58
+ * @default "neutral"
59
+ */
60
+ "variant": | "neutral"
61
+ | "ui-component"
62
+ | "recipe"
63
+ | "agent"
64
+ | "config";
65
+ }
66
+ /**
67
+ * ## Accessibility
68
+ * **Category:** interactive-display
69
+ * **APG pattern:** Button — https://www.w3.org/WAI/ARIA/apg/patterns/button/
70
+ * (satisfied natively by the underlying `<button>` element). When `href` is
71
+ * set, the component renders `<a href>` instead — a link, not a button — and
72
+ * that surface follows native `<a>` semantics rather than the Button pattern.
73
+ * **Keyboard interactions:**
74
+ * - Tab: moves focus to the internal `<button>` or `<a>` (shadow DOM does not
75
+ * interrupt tab order).
76
+ * - Enter: activates (fires click on `<button>`, navigates on `<a>`).
77
+ * - Space: activates the `<button>` variant only (native behavior); on the
78
+ * `<a>` variant Space scrolls the page as usual.
79
+ * - Escape: N/A — no dismissible state owned by this component.
80
+ * - Arrow keys: N/A.
81
+ * - Printable characters: N/A.
82
+ * **ARIA:**
83
+ * - Roles used: none explicit — the native `<button>` / `<a href>` supplies
84
+ * the implicit `button` / `link` role.
85
+ * - State attributes: `disabled` (native attribute on `<button>`, not
86
+ * `aria-disabled`). The `<a>` variant does not accept `disabled` — a
87
+ * disabled navigation is a spec smell (see spec §"Button vs Link"); if a
88
+ * link needs a disabled state, model it as a `<button>` action instead.
89
+ * - Labeling strategy: visible text via `<slot />`. Consumers MUST place
90
+ * readable text (or a labeled icon) inside the tag. An empty slot leaves
91
+ * the button/link without an accessible name and fails
92
+ * `button-name` / `link-name` axe rules. Icon-only usage is out of contract
93
+ * for `ds-button`; use a future `ds-icon-button` with a required
94
+ * `aria-label` prop when that lands.
95
+ * **Focus:**
96
+ * - On mount: nothing auto-focuses.
97
+ * - On activate: focus stays on the element (native click behavior; the
98
+ * component does not move focus on its own).
99
+ * - On close/deactivate: N/A.
100
+ * - Focus indicator: 2px `outline` in `var(--ds-color-focus)` with 2px
101
+ * `outline-offset`, applied via `:focus-visible` — replaces the browser
102
+ * default so both `<button>` and `<a>` variants use the same DS ring
103
+ * (spec universal rule 3, WCAG 1.4.11 non-text contrast ≥ 3:1).
104
+ * **Motion:**
105
+ * - Animations: 150ms `background-color` ease-in-out transition on
106
+ * `primary`/`secondary` variants (hover).
107
+ * - Reduced-motion behavior: N/A — 150ms is below the spec's 200ms threshold
108
+ * for `prefers-reduced-motion` handling, and the transition animates color
109
+ * only (no motion of position, scale, or opacity).
110
+ * **Contrast:**
111
+ * - Text: `primary` and `secondary` variants pair `--ds-color-{primary,secondary}`
112
+ * with `--ds-color-text-on-{primary,secondary}` — the token pairs are
113
+ * authored to meet WCAG 2.1 AA (≥ 4.5:1). The `ghost` variant inherits
114
+ * `color: inherit` and pins `opacity: 0.85`, so its effective contrast
115
+ * depends on the consumer's surface — verify per site.
116
+ * - Non-text (border on `ghost`): 1px `currentColor`; contrast tracks the
117
+ * text color 1:1, subject to the same host-page caveat.
118
+ * **Screen reader announcement:**
119
+ * - Rendered state: announces the slot text followed by "button" (or "link"
120
+ * for the `href` variant), plus "dimmed" / "unavailable" when `disabled`
121
+ * is set (browser/AT dependent wording).
122
+ * - State change: N/A — this component does not own toggle state. A pressed
123
+ * toggle needs `aria-pressed`, which is out of scope here; model that as
124
+ * a distinct component or extend the API deliberately per the spec.
125
+ */
126
+ interface DsButton {
127
+ /**
128
+ * @default false
129
+ */
130
+ "disabled": boolean;
131
+ "href"?: string;
132
+ /**
133
+ * @default "md"
134
+ */
135
+ "size": "md" | "lg";
136
+ /**
137
+ * @default "button"
138
+ */
139
+ "type": "button" | "submit" | "reset";
140
+ /**
141
+ * @default "primary"
142
+ */
143
+ "variant": "primary" | "secondary" | "ghost";
144
+ }
145
+ /**
146
+ * ## Accessibility
147
+ * **Category:** static-display
148
+ * **APG pattern:** N/A — a container surface with no interactive
149
+ * behavior of its own. If a consumer nests interactive elements
150
+ * inside (button, link, form field), those elements satisfy their
151
+ * own a11y bucket independently.
152
+ * **Keyboard interactions:**
153
+ * - Tab / Shift+Tab: N/A — the card itself is not focusable. Any
154
+ * interactive descendant carries its own tab semantics.
155
+ * - Enter / Space / Arrow / Escape / Printable: N/A.
156
+ * **ARIA:**
157
+ * - Roles used: none. `<ds-card>` is a purely visual grouping and
158
+ * deliberately does not carry `role="region"` — that would demand
159
+ * a labelledby target, which would only be correct in a subset of
160
+ * uses. Consumers that need a labeled landmark should render a
161
+ * `<section aria-labelledby>` around the card.
162
+ * - State attributes: none.
163
+ * - Labeling strategy: none applied by the component; consumer's
164
+ * heading structure inside the slot supplies the accessible name
165
+ * when needed.
166
+ * **Focus:**
167
+ * - On mount: nothing auto-focuses.
168
+ * - Focus indicator: N/A — the card itself is not focusable.
169
+ * **Motion:**
170
+ * - Animations: none.
171
+ * - Reduced-motion behavior: N/A.
172
+ * **Contrast:**
173
+ * - Text: inherits `color: inherit` / `currentColor`; the card does
174
+ * not impose a text color, so contrast is the consumer theme's
175
+ * responsibility.
176
+ * - Non-text (border, subtle background tint): both derived from
177
+ * `color-mix(in oklch, currentColor N%, transparent)`, matching
178
+ * the pattern used by `ds-input` and `ds-select`. WCAG 1.4.11
179
+ * (3:1 non-text contrast) is met in themes where the surface has
180
+ * enough delta against the page background; the component does
181
+ * not override the consumer's palette to force it.
182
+ * **Screen reader announcement:**
183
+ * - Rendered state: no announcement of the card itself. AT
184
+ * navigates to the slotted content directly, using whatever
185
+ * heading and landmark structure the consumer places inside.
186
+ * - State change: N/A.
187
+ */
188
+ interface DsCard {
189
+ }
190
+ /**
191
+ * ## Accessibility
192
+ * **Category:** form-field
193
+ * **APG pattern:** N/A — native element. This wraps a native
194
+ * `<input type="checkbox">`; the browser already implements the
195
+ * checkbox role and its state semantics. Reference:
196
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox
197
+ * Note: `ds-checkbox` intentionally does NOT reach for the WAI-ARIA
198
+ * APG "tri-state checkbox" pattern (indeterminate + on + off) as a
199
+ * scratch-built ARIA widget. The native input already exposes the
200
+ * `indeterminate` DOM property and browsers report it to AT
201
+ * correctly; the `indeterminate` prop here forwards to that DOM
202
+ * property so the native mechanism carries the semantics.
203
+ * **Keyboard interactions:**
204
+ * - Tab: moves focus to the native `<input type="checkbox">`.
205
+ * - Space: toggles the checked state (native behavior).
206
+ * - Enter: no native effect on a checkbox (unlike button). Form
207
+ * submission triggered by Enter comes from the enclosing form's
208
+ * default submit button, not from the checkbox itself.
209
+ * **ARIA:**
210
+ * - Roles used: none explicit — the native checkbox supplies the
211
+ * implicit `checkbox` role.
212
+ * - State attributes: `checked` (DOM property, kept in sync via
213
+ * componentDidRender because Stencil does not JSX-forward the
214
+ * attribute cleanly for controlled use), `disabled` (native
215
+ * attribute, not `aria-disabled`), `aria-invalid` (from the
216
+ * `invalid` prop), `aria-required` (from the `required` prop),
217
+ * `aria-describedby` (from the `describedBy` prop).
218
+ * - Labeling strategy: `aria-label` set from the `label` prop onto
219
+ * the internal checkbox. This is the **canonical, recommended**
220
+ * mode. Wrapping the host in a light-DOM `<label>` also produces
221
+ * an accessible name in Chromium via flattened-tree resolution —
222
+ * same secondary mode documented on `ds-input`.
223
+ * **Focus:**
224
+ * - On mount: nothing auto-focuses.
225
+ * - On toggle: focus remains on the native checkbox.
226
+ * - Focus indicator: browser default `:focus-visible` ring, kept on
227
+ * purpose until the DS ships a themed focus utility using
228
+ * `--ds-color-focus`. Not overridden by `ds-checkbox.css`.
229
+ * **Motion:**
230
+ * - Animations: none.
231
+ * - Reduced-motion behavior: N/A.
232
+ * **Contrast:**
233
+ * - Text: N/A — the checkbox itself renders no text (labels are
234
+ * supplied by the consumer via `label` prop or wrapping <label>).
235
+ * - Non-text (the box and its check glyph): browser default rendering
236
+ * is kept on purpose (no `appearance: none` override); this
237
+ * preserves the OS/browser accessibility rendering that AT and
238
+ * forced-color modes rely on. A themed override is a future
239
+ * decision once the DS commits to a checkbox visual language that
240
+ * still passes 3:1 non-text contrast in every theme.
241
+ * **Screen reader announcement:**
242
+ * - Rendered state: announces the `label` prop text as the
243
+ * accessible name, followed by "checkbox", followed by "checked"
244
+ * / "not checked" / "mixed" per the current DOM state.
245
+ * - State change: on toggle, AT announces the new state (native
246
+ * behavior); no `aria-live` added.
247
+ * **Consumer contract:**
248
+ * - `checked` is the source of truth for controlled use. Reading
249
+ * `event.detail` from `dsChange` gives the new state; the internal
250
+ * input is kept in sync via a Watch + a re-sync in componentDidRender.
251
+ * - `indeterminate` is a visual/AT state, not a value — it is NOT
252
+ * submitted with a form and clears on the next user toggle.
253
+ */
254
+ interface DsCheckbox {
255
+ /**
256
+ * @default false
257
+ */
258
+ "checked": boolean;
259
+ "describedBy"?: string;
260
+ /**
261
+ * @default false
262
+ */
263
+ "disabled": boolean;
264
+ /**
265
+ * @default false
266
+ */
267
+ "indeterminate": boolean;
268
+ /**
269
+ * @default false
270
+ */
271
+ "invalid": boolean;
272
+ "label"?: string;
273
+ "name"?: string;
274
+ /**
275
+ * @default false
276
+ */
277
+ "required": boolean;
278
+ "value"?: string;
279
+ }
280
+ /**
281
+ * ## Accessibility
282
+ * **Category:** interactive-display
283
+ * **APG pattern:** Button — https://www.w3.org/WAI/ARIA/apg/patterns/button/
284
+ * (for the internal copy control; the code readout itself is static text).
285
+ * **Keyboard interactions:**
286
+ * - Tab: moves focus into the internal copy `<button>`; the code readout
287
+ * (`<pre><code>`) is not focusable itself, but its container is
288
+ * horizontally scrollable and remains reachable via the browser's caret
289
+ * browsing / find-in-page path.
290
+ * - Enter: activates the copy button (writes `code` to the clipboard).
291
+ * - Space: activates the copy button (native `<button>` behavior).
292
+ * - Escape: N/A — the "Copied" state auto-clears after 1.4s; no dismissible
293
+ * modal state.
294
+ * - Arrow keys: N/A.
295
+ * - Printable characters: N/A.
296
+ * **ARIA:**
297
+ * - Roles used: none explicit — the native `<button>` supplies the implicit
298
+ * `button` role; `<pre>` and `<code>` supply their semantic roles.
299
+ * - State attributes: none. The `copied` flag lives only in the button's
300
+ * accessible name (see below); it is intentionally not surfaced via
301
+ * `aria-pressed` because it is not a toggle — it is a transient
302
+ * post-action confirmation.
303
+ * - Labeling strategy: `aria-label` on the copy button — "Copy code" in the
304
+ * resting state, "Copied" while the confirmation is visible. This is
305
+ * authoritative because the button carries both an icon and the words
306
+ * "Copy" / "Copied", and mixed icon+text needs an explicit accessible
307
+ * name to avoid AT reading the SVG as a separate node.
308
+ * **Focus:**
309
+ * - On mount: nothing auto-focuses.
310
+ * - On activate: focus stays on the copy button (clipboard write is
311
+ * synchronous from the user's perspective; no focus is moved).
312
+ * - On close/deactivate: N/A — no popup or overlay to close.
313
+ * - Focus indicator: 2px `outline` in `var(--ds-color-focus)` with 2px
314
+ * `outline-offset`, applied to `.ds-code-block__copy:focus-visible`. The
315
+ * readout itself is not focusable and has no focus indicator by design.
316
+ * **Motion:**
317
+ * - Animations: 120ms `color` / `border-color` ease transition on the copy
318
+ * button (hover/focus).
319
+ * - Reduced-motion behavior: N/A — 120ms is below the spec's 200ms
320
+ * threshold, and the transition animates color only.
321
+ * **Contrast:**
322
+ * - Text (code readout): inherits `color: currentColor`; contrast depends
323
+ * on the host page's text color vs. the block's tinted background
324
+ * (`color-mix(currentColor 4%, transparent)`). Verify per site.
325
+ * - Text (copy button): `color-mix(in oklch, currentColor 70%, transparent)`
326
+ * at rest, `currentColor` on hover. The 70%-mixed resting color can drop
327
+ * below 4.5:1 on low-contrast surfaces — audit per usage site, and lean
328
+ * on the hover/focus states (both restore full `currentColor`) as the
329
+ * accessible fallback.
330
+ * - Non-text (button border, language tag border-bottom): both use
331
+ * `color-mix(currentColor <15|12>%, transparent)` — decorative separators,
332
+ * they do not convey state, so the 3:1 non-text contrast rule does not
333
+ * apply. Focus and hover borders shift up to 30% for clearer edges.
334
+ * **Screen reader announcement:**
335
+ * - Rendered state: announces "Copy code, button" (the `aria-label`), then
336
+ * the code content when the user navigates into the `<pre><code>` block
337
+ * (usually announced as a code block on VoiceOver).
338
+ * - State change: after clicking Copy, the button's `aria-label` flips to
339
+ * "Copied"; AT will announce this on the next focus or re-read of the
340
+ * button, but NOT proactively — there is no `aria-live` region. This is
341
+ * deliberate per spec §"What we explicitly do NOT do" (avoid live-region
342
+ * overuse), and the trade-off is that a screen-reader-only user does not
343
+ * get an unsolicited confirmation. If a future review decides that
344
+ * confirmation must be audible, add a visually-hidden
345
+ * `aria-live="polite"` element whose text toggles on `copied`.
346
+ */
347
+ interface DsCodeBlock {
348
+ "code": string;
349
+ /**
350
+ * @default "bash"
351
+ */
352
+ "language": string;
353
+ }
354
+ /**
355
+ * ## Accessibility
356
+ * **Category:** state-machine
357
+ * **APG pattern:** https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
358
+ * This component wraps the **native `<dialog>` element** rather than
359
+ * scratch-building the APG pattern on top of a `<div role="dialog">`.
360
+ * `<dialog>` opened via `showModal()` gives us — from the browser,
361
+ * verified by the platform, not by us:
362
+ * - Focus trap: Tab / Shift+Tab cycle only through focusable
363
+ * descendants (including slotted light-DOM descendants; the flattened
364
+ * accessibility tree is what the trap operates on).
365
+ * - Escape: closes the dialog and returns focus to the previously
366
+ * focused element (native, not implemented here).
367
+ * - Inert background: everything outside the dialog is inert while it
368
+ * is open — no mouse, no keyboard, not part of the a11y tree.
369
+ * - Return focus: on close, focus returns to whatever element had it
370
+ * before `showModal()` — native, not implemented here.
371
+ * - Initial focus: browser auto-focuses the first `autofocus` element
372
+ * inside, or the first focusable if none — native.
373
+ * - `role="dialog"` and `aria-modal="true"` semantics: implicit on
374
+ * `<dialog>`, no ARIA needed from us.
375
+ * This is the deliberate answer to the a11y spec §D warning about
376
+ * scratch-building Tier 2 components: the native element removes the
377
+ * "compiles, axe passes, screen-reader user gets trapped" failure
378
+ * mode by delegating the state machine to the platform.
379
+ * **Keyboard interactions (all handled by the native element unless
380
+ * noted otherwise):**
381
+ * - Tab: cycles focus within the dialog's focusable descendants
382
+ * (native focus trap).
383
+ * - Shift+Tab: reverse cycle (native).
384
+ * - Escape: closes the dialog and fires the `close` event (native).
385
+ * Consumers who need to prevent dismissal on Escape (destructive
386
+ * flows: e.g. an unsaved-changes guard) must call
387
+ * `event.preventDefault()` inside their own `keydown` listener on
388
+ * the dialog before it reaches the browser — that is an escape
389
+ * hatch, not a default we impose.
390
+ * - Enter / Space: no special dialog behavior; forwarded to
391
+ * whatever descendant has focus (a button will activate).
392
+ * - Home / End / Arrow keys: no special dialog behavior; forwarded
393
+ * to descendants.
394
+ * - Printable characters: forwarded to descendants (e.g. typing
395
+ * inside a slotted `<ds-input>`).
396
+ * **ARIA attributes and value triggers:**
397
+ * - Implicit `role="dialog"` on the native `<dialog>`.
398
+ * - Implicit `aria-modal="true"` when opened via `showModal()`
399
+ * (which is what this component always uses; `show()` — the
400
+ * non-modal form — is intentionally not exposed in v1).
401
+ * - `aria-label` set from the `label` prop onto the `<dialog>`.
402
+ * Consumers who prefer an in-content title can pass a
403
+ * `labelledBy` prop instead, whose value is the id of a heading
404
+ * element they render inside the slot — `aria-labelledby`
405
+ * resolves that id through the flattened tree.
406
+ * - `aria-describedby` from the `describedBy` prop, resolving a
407
+ * light-DOM id of a descriptive block (e.g. the dialog body copy
408
+ * when the label is short).
409
+ * **Focus lifecycle:**
410
+ * - Opening: `showModal()` moves focus to the first `autofocus`
411
+ * element inside, or the first focusable if none. Consumers who
412
+ * want a specific initial focus target should mark that element
413
+ * with `autofocus`.
414
+ * - While open: focus is trapped within the flattened tree of the
415
+ * `<dialog>`; Tab / Shift+Tab cycle through slotted descendants.
416
+ * Focus cannot escape into the inert background.
417
+ * - Closing: `close()` (either from Escape, from a form-submit with
418
+ * `method="dialog"`, from a light-dismiss backdrop click handler
419
+ * the consumer wires up, or from `open=false`) returns focus to
420
+ * the element that had it immediately before `showModal()` was
421
+ * called. The `dsClose` event fires after focus has been restored.
422
+ * **ARIA labelling contract (choose one):**
423
+ * - **`label`** (string) — sets `aria-label` on the dialog. Simplest
424
+ * for short titles.
425
+ * - **`labelledBy`** (id) — sets `aria-labelledby` to reference a
426
+ * heading rendered inside the slot. Preferred when the dialog has
427
+ * a visible title so the accessible name matches the visible name.
428
+ * If both are omitted, axe reports `dialog-name` — the dialog has no
429
+ * accessible name. The a11y test for this component asserts that at
430
+ * least one of the two is provided.
431
+ * **Motion:**
432
+ * - Animations: none applied by the component. Consumers who want an
433
+ * entrance transition can style `::backdrop` and `dialog[open]`
434
+ * with their own animation, gated on `@media
435
+ * (prefers-reduced-motion: no-preference)`.
436
+ * - Reduced-motion behavior: N/A — no animation to collapse. If a
437
+ * consumer adds one, they own the reduced-motion fallback.
438
+ * **Contrast:**
439
+ * - Text: inherits `color: inherit`; consumer theme owns contrast.
440
+ * - Non-text: subtle bordered surface via
441
+ * `color-mix(in oklch, currentColor N%, transparent)` matching
442
+ * `ds-card`. Backdrop is a semi-transparent black by default.
443
+ * **Screen reader announcement:**
444
+ * - Rendered state (closed): dialog is not in the a11y tree.
445
+ * - Opened: AT announces "dialog" plus the accessible name from
446
+ * `label` / `labelledBy`, then reads the content following focus
447
+ * (or the descriptive block referenced by `describedBy` first,
448
+ * depending on AT).
449
+ * - State change: on close, AT returns to the element that regained
450
+ * focus (the trigger); no `aria-live` announcement is added.
451
+ * **Consumer contract:**
452
+ * - Set `open` to true to show; set to false to close. The component
453
+ * syncs the DOM state via `showModal()` / `close()` in a Watch.
454
+ * - Listen to `dsClose` to know when the dialog was dismissed (by
455
+ * Escape, by `open=false`, or by a form submit with
456
+ * `method="dialog"`). Listen to `dsOpen` for the mirror event.
457
+ * - The default backdrop is opaque and NOT click-to-dismiss. Consumers
458
+ * who want light-dismiss can add a click listener on the dialog
459
+ * that closes when the click target is the dialog itself (not a
460
+ * descendant): `if (e.target === dialog) dialog.close()`.
461
+ * - Put focus targets (form fields, primary action button) inside
462
+ * the slot. Use `autofocus` on the element that should receive
463
+ * focus first.
464
+ * **Pending manual verification (see commit message TODO):**
465
+ * - VoiceOver on macOS: confirm the dialog announces its accessible
466
+ * name + "dialog" on open, focus lands on the correct element,
467
+ * Escape closes and focus returns to the trigger.
468
+ * - Chromium high-contrast / forced-colors: confirm the surface
469
+ * still reads as a bordered container with the native ::backdrop
470
+ * dim.
471
+ */
472
+ interface DsDialog {
473
+ "describedBy"?: string;
474
+ "label"?: string;
475
+ "labelledBy"?: string;
476
+ /**
477
+ * @default false
478
+ */
479
+ "open": boolean;
480
+ }
481
+ /**
482
+ * ## Accessibility
483
+ * **Category:** form-field
484
+ * **APG pattern:** N/A — native element. This wraps a native `<input>`;
485
+ * there is no WAI-ARIA APG pattern for a plain text input because the
486
+ * browser already implements it natively. Reference:
487
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
488
+ * **Keyboard interactions:**
489
+ * - Tab: moves focus to the native `<input>` (shadow DOM does not
490
+ * interrupt tab order).
491
+ * - Printable characters: insert at the caret position (native).
492
+ * - Backspace / Delete: native editing.
493
+ * - Arrow keys: move the caret within the value (native); for
494
+ * `type="number"` Up/Down step the numeric value (native).
495
+ * - Enter: on `type="search"` may submit the enclosing form (native);
496
+ * no custom handling.
497
+ * - Escape: no native meaning for a text input.
498
+ * **ARIA:**
499
+ * - Roles used: none explicit — the native `<input>` supplies its
500
+ * implicit role (`textbox`, `searchbox`, etc. depending on `type`).
501
+ * - State attributes: `disabled` (native attribute, not `aria-disabled`),
502
+ * `aria-invalid` (from the `invalid` prop), `aria-required` (from the
503
+ * `required` prop), `aria-describedby` (from the `describedBy` prop,
504
+ * expected to reference a light-DOM node id — typically a hint or
505
+ * error message rendered by the consumer alongside the field).
506
+ * - Labeling strategy: `aria-label` set from the `label` prop onto the
507
+ * internal `<input>`. This is the **canonical, recommended** mode —
508
+ * explicit and independent of DOM structure. Consumers MUST pass
509
+ * `label` (or otherwise give the field an accessible name) — an
510
+ * `<input>` with no accessible name is a WCAG failure (axe rule
511
+ * `label`). Wrapping the host in a light-DOM `<label>` (e.g.
512
+ * `<label>Email <ds-input></ds-input></label>`) also produces an
513
+ * accessible name in Chromium via flattened-tree resolution — the
514
+ * same secondary mode documented on `ds-select`, verified in this
515
+ * component's e2e tests. Setting `aria-label` directly on the
516
+ * `<ds-input>` host does NOT work: shadow-DOM attribute forwarding
517
+ * would be required — use the `label` prop instead.
518
+ * **Focus:**
519
+ * - On mount: nothing auto-focuses.
520
+ * - On value change: focus remains on the native `<input>`.
521
+ * - Focus indicator: the browser default `:focus-visible` ring is kept
522
+ * on purpose — a themed focus ring using `--ds-color-focus` is a
523
+ * future decision once the DS ships a shared focus utility. Not
524
+ * overridden by `ds-input.css`.
525
+ * **Motion:**
526
+ * - Animations: none.
527
+ * - Reduced-motion behavior: N/A — no animation to collapse.
528
+ * **Contrast:**
529
+ * - Text: inherits `color: inherit` / `currentColor`; ratio depends on
530
+ * the consumer's theme, not verified in isolation here.
531
+ * - Border: `color-mix(in oklch, currentColor 22%, transparent)`,
532
+ * matching `ds-select` — inherits whatever contrast the host page
533
+ * sets. WCAG 1.4.11 (3:1 non-text) is the consumer's responsibility
534
+ * in themes that override the surface.
535
+ * **Screen reader announcement:**
536
+ * - Rendered state: announces the `label` prop text as the accessible
537
+ * name, followed by the browser/AT's role announcement for the
538
+ * input type ("edit text", "search text", "password", "phone
539
+ * number", "email"…). When `required=true` the announcement
540
+ * includes "required"; when `invalid=true` it includes "invalid".
541
+ * - State change: on value edit, AT typically echoes the typed
542
+ * character (native input behavior); no `aria-live` added, per the
543
+ * spec's guidance against live-region overuse.
544
+ * **Consumer contract:**
545
+ * - `placeholder` is a hint, not a label. It disappears on focus in
546
+ * most browsers and is not reliably announced by every AT — always
547
+ * pair with `label`.
548
+ * - For `type="password"` in a real form, pair with a light-DOM
549
+ * `<input type="hidden">` or a form-associated ancestor that gives
550
+ * the browser's password manager an `autocomplete` hint. This
551
+ * component intentionally does not expose `autocomplete` in v1;
552
+ * consumers that need it can render a native `<input>` for that
553
+ * field until the prop is added.
554
+ * - When `invalid=true`, pair with a `describedBy` id that points at
555
+ * a visible error message; `aria-invalid` alone gives the AT the
556
+ * status but not the reason.
557
+ */
558
+ interface DsInput {
559
+ "describedBy"?: string;
560
+ /**
561
+ * @default false
562
+ */
563
+ "disabled": boolean;
564
+ /**
565
+ * @default false
566
+ */
567
+ "invalid": boolean;
568
+ "label"?: string;
569
+ "name"?: string;
570
+ "placeholder"?: string;
571
+ /**
572
+ * @default false
573
+ */
574
+ "required": boolean;
575
+ /**
576
+ * @default "md"
577
+ */
578
+ "size": "md" | "lg";
579
+ /**
580
+ * @default "text"
581
+ */
582
+ "type": | "text"
583
+ | "email"
584
+ | "password"
585
+ | "search"
586
+ | "tel"
587
+ | "url"
588
+ | "number";
589
+ "value"?: string;
590
+ }
591
+ /**
592
+ * ## Accessibility
593
+ * **Category:** static-display (indeterminate progress indicator)
594
+ * **APG pattern:** N/A — the loader is a passive presence indicator, not a
595
+ * `progressbar` (no measurable value). Uses `role="status"` per WAI-ARIA
596
+ * live-region semantics for indeterminate loading states.
597
+ * **Keyboard interactions:**
598
+ * - Tab: N/A — not focusable.
599
+ * - Enter: N/A.
600
+ * - Escape: N/A.
601
+ * - Arrow keys: N/A.
602
+ * - Printable characters: N/A.
603
+ * **ARIA:**
604
+ * - Roles used: `role="status"` on the host — an implicit polite live
605
+ * region ARIA lists as valid for "advisory information" including
606
+ * in-progress operations. The inner `<svg>` is decorative and carries
607
+ * `aria-hidden="true"` + `focusable="false"` so it never becomes a
608
+ * parallel target for screen readers.
609
+ * - State attributes: none. The loader has no state changes to announce
610
+ * beyond its own presence; the polite live region on mount is the
611
+ * announcement.
612
+ * - Labeling strategy: `aria-label` from the `label` prop (default
613
+ * "Loading"). Consumers pass a more specific string when the context
614
+ * warrants ("Loading ceremonies", "Signing in", …).
615
+ * **Focus:**
616
+ * - On mount: nothing auto-focuses.
617
+ * - On activate/open: N/A — not interactive.
618
+ * - On close/deactivate: N/A.
619
+ * - Focus indicator: N/A — the host is not focusable.
620
+ * **Motion:**
621
+ * - Animations: two mirrored halves of the logo path oscillate
622
+ * symmetrically around the visual center, meeting at the ring midpoint
623
+ * and separating again. Cycle 1.4s by default (`speed="normal"`);
624
+ * `speed="slow"` = 2.2s, `speed="fast"` = 0.9s.
625
+ * - Reduced-motion behavior: `@media (prefers-reduced-motion: reduce)`
626
+ * collapses both halves to a static rendering with a slow opacity
627
+ * pulse (2s ease-in-out). No rotation, no lateral movement.
628
+ * **Contrast:**
629
+ * - Text: N/A — the visible surface is the SVG stroke, not text.
630
+ * - Non-text: stroke inherits `currentColor` from the host. Consumers are
631
+ * responsible for confirming the stroke against its background meets
632
+ * the ≥ 3:1 non-text contrast threshold (WCAG 1.4.11) where the loader
633
+ * conveys state (e.g. distinguishing "still loading" from "idle").
634
+ * **Screen reader announcement:**
635
+ * - Rendered state: the polite live region announces the label
636
+ * (e.g. "Loading") when the loader mounts.
637
+ * - State change: N/A — the loader itself has no state that changes.
638
+ * Consumers unmount the loader when the awaited work completes; that
639
+ * removal is silent, which is the intended behavior (the arriving
640
+ * content is the announcement).
641
+ */
642
+ interface DsLoader {
643
+ /**
644
+ * @default "Loading"
645
+ */
646
+ "label": string;
647
+ /**
648
+ * @default "md"
649
+ */
650
+ "size": "sm" | "md" | "lg";
651
+ /**
652
+ * @default "normal"
653
+ */
654
+ "speed": "slow" | "normal" | "fast";
655
+ }
656
+ interface DsSelect {
657
+ /**
658
+ * @default false
659
+ */
660
+ "disabled": boolean;
661
+ "label"?: string;
662
+ "name"?: string;
663
+ /**
664
+ * Options rendered inside the internal shadow `<select>`. Accepts either: - a JSON string (SSR-friendly — server-rendered HTML can only set string attributes, and Stencil does not JSON-parse array attributes), e.g. `options='[{"value":"en","label":"EN"}]'` - an array property set from client-side JS, e.g. `el.options = [{ value: 'en', label: 'EN' }]` Malformed JSON fails safe to an empty list rather than throwing, so the component still renders a visible (if empty) select.
665
+ * @default "[]"
666
+ */
667
+ "options": string | ReadonlyArray<DsSelectOption>;
668
+ /**
669
+ * @default "md"
670
+ */
671
+ "size": "md" | "lg";
672
+ "value"?: string;
673
+ }
674
+ interface DsTabs {
675
+ "active"?: string;
676
+ /**
677
+ * @default "[]"
678
+ */
679
+ "items": string | ReadonlyArray<DsTabItem>;
680
+ "label"?: string;
681
+ /**
682
+ * @default "horizontal"
683
+ */
684
+ "orientation": "horizontal" | "vertical";
685
+ }
686
+ /**
687
+ * ## Accessibility
688
+ * **Category:** form-field
689
+ * **APG pattern:** N/A — native element. This wraps a native
690
+ * `<textarea>`; there is no WAI-ARIA APG pattern for a plain
691
+ * multi-line text field because the browser already implements it
692
+ * natively. Reference:
693
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea
694
+ * **Keyboard interactions:**
695
+ * - Tab: moves focus to the native `<textarea>`; Tab inside the
696
+ * textarea inserts a tab character only when the browser is
697
+ * configured to do so (default behavior: Tab moves focus out).
698
+ * - Printable characters: insert at the caret position (native).
699
+ * - Enter: inserts a newline within the value (native), does not
700
+ * submit the enclosing form (unlike a single-line input).
701
+ * - Backspace / Delete: native editing.
702
+ * - Arrow keys: move the caret within the value (native).
703
+ * - Escape: no native meaning for a text area.
704
+ * **ARIA:**
705
+ * - Roles used: none explicit — the native `<textarea>` supplies
706
+ * the implicit `textbox` role with multiline behavior.
707
+ * - State attributes: `disabled` (native attribute, not
708
+ * `aria-disabled`), `aria-invalid` (from the `invalid` prop),
709
+ * `aria-required` (from the `required` prop), `aria-describedby`
710
+ * (from the `describedBy` prop, expected to reference a light-DOM
711
+ * node id — typically a hint or error message rendered by the
712
+ * consumer alongside the field).
713
+ * - Labeling strategy: `aria-label` set from the `label` prop onto
714
+ * the internal `<textarea>`. This is the **canonical, recommended**
715
+ * mode. Wrapping the host in a light-DOM `<label>` also produces
716
+ * an accessible name in Chromium via flattened-tree resolution —
717
+ * same secondary mode documented on `ds-input` and `ds-select`,
718
+ * verified in this component's e2e tests. Setting `aria-label`
719
+ * directly on the `<ds-textarea>` host does NOT work: shadow-DOM
720
+ * attribute forwarding would be required — use the `label` prop.
721
+ * **Focus:**
722
+ * - On mount: nothing auto-focuses.
723
+ * - On value change: focus remains on the native `<textarea>`.
724
+ * - Focus indicator: the browser default `:focus-visible` ring is
725
+ * kept on purpose — a themed focus ring using `--ds-color-focus`
726
+ * is a future decision once the DS ships a shared focus utility.
727
+ * **Motion:**
728
+ * - Animations: none.
729
+ * - Reduced-motion behavior: N/A — no animation to collapse.
730
+ * **Contrast:**
731
+ * - Text: inherits `color: inherit` / `currentColor`; ratio depends
732
+ * on the consumer's theme, not verified in isolation.
733
+ * - Border: `color-mix(in oklch, currentColor 22%, transparent)`,
734
+ * matching `ds-input`.
735
+ * **Screen reader announcement:**
736
+ * - Rendered state: announces the `label` prop text as the
737
+ * accessible name, followed by "edit text, multiline" (browser/AT
738
+ * wording varies). When `required=true` the announcement includes
739
+ * "required"; when `invalid=true` it includes "invalid".
740
+ * - State change: on value edit, AT typically echoes the typed
741
+ * character (native behavior); no `aria-live` added.
742
+ * **Consumer contract:**
743
+ * - `placeholder` is a hint, not a label — always pair with `label`.
744
+ * - When `invalid=true`, pair with a `describedBy` id that points at
745
+ * a visible error message; `aria-invalid` alone gives the AT the
746
+ * status but not the reason.
747
+ * - `rows` sets the initial visible line count. Vertical resize is
748
+ * left to the native default (`resize: vertical`) so users can
749
+ * grow the field for long entries; the consumer's CSS can pin it
750
+ * with `resize: none` when a fixed height matters.
751
+ */
752
+ interface DsTextarea {
753
+ "describedBy"?: string;
754
+ /**
755
+ * @default false
756
+ */
757
+ "disabled": boolean;
758
+ /**
759
+ * @default false
760
+ */
761
+ "invalid": boolean;
762
+ "label"?: string;
763
+ "name"?: string;
764
+ "placeholder"?: string;
765
+ /**
766
+ * @default false
767
+ */
768
+ "required": boolean;
769
+ /**
770
+ * @default 3
771
+ */
772
+ "rows": number;
773
+ /**
774
+ * @default "md"
775
+ */
776
+ "size": "md" | "lg";
777
+ "value"?: string;
778
+ }
779
+ interface DsTooltip {
780
+ /**
781
+ * @default 100
782
+ */
783
+ "closeDelay": number;
784
+ "label": string;
785
+ /**
786
+ * @default 250
787
+ */
788
+ "openDelay": number;
789
+ /**
790
+ * @default "bottom"
791
+ */
792
+ "placement": "top" | "bottom";
793
+ }
794
+ }
795
+ export interface DsCheckboxCustomEvent<T> extends CustomEvent<T> {
796
+ detail: T;
797
+ target: HTMLDsCheckboxElement;
798
+ }
799
+ export interface DsDialogCustomEvent<T> extends CustomEvent<T> {
800
+ detail: T;
801
+ target: HTMLDsDialogElement;
802
+ }
803
+ export interface DsInputCustomEvent<T> extends CustomEvent<T> {
804
+ detail: T;
805
+ target: HTMLDsInputElement;
806
+ }
807
+ export interface DsSelectCustomEvent<T> extends CustomEvent<T> {
808
+ detail: T;
809
+ target: HTMLDsSelectElement;
810
+ }
811
+ export interface DsTabsCustomEvent<T> extends CustomEvent<T> {
812
+ detail: T;
813
+ target: HTMLDsTabsElement;
814
+ }
815
+ export interface DsTextareaCustomEvent<T> extends CustomEvent<T> {
816
+ detail: T;
817
+ target: HTMLDsTextareaElement;
818
+ }
819
+ declare global {
820
+ /**
821
+ * ## Accessibility
822
+ * **Category:** static-display
823
+ * **APG pattern:** N/A — non-interactive text label.
824
+ * **Keyboard interactions:**
825
+ * - Tab: N/A — the badge is not focusable and does not appear in tab order.
826
+ * - Enter: N/A.
827
+ * - Escape: N/A.
828
+ * - Arrow keys: N/A.
829
+ * - Printable characters: N/A.
830
+ * **ARIA:**
831
+ * - Roles used: none — renders a plain `<span>` around a `<slot />`. The
832
+ * `variant` prop is a purely visual axis and MUST NOT be the sole carrier
833
+ * of information (color/style alone fails WCAG 1.4.1 Use of Color); the
834
+ * textual content inside the slot must convey the same meaning.
835
+ * - State attributes: none.
836
+ * - Labeling strategy: visible text via `<slot />`. Consumers place the
837
+ * readable label directly inside the tag.
838
+ * **Focus:**
839
+ * - On mount: nothing auto-focuses.
840
+ * - On activate/open: N/A — non-interactive.
841
+ * - On close/deactivate: N/A.
842
+ * - Focus indicator: N/A — the host is not focusable. If a consumer wraps
843
+ * `ds-badge` in an interactive element (e.g. `<button>`, `<a>`), that
844
+ * wrapper owns the focus indicator via the DS `--ds-color-focus` token
845
+ * and its own `:focus-visible` rule.
846
+ * **Motion:**
847
+ * - Animations: none.
848
+ * - Reduced-motion behavior: N/A.
849
+ * **Contrast:**
850
+ * - Text: inherits `color: inherit` / `currentColor` from the host page and
851
+ * the variant-specific style; not verified in isolation here. Consumers
852
+ * are responsible for confirming ≥ 4.5:1 (WCAG 1.4.3) against the surface
853
+ * the badge is placed on.
854
+ * - Non-text: no state-conveying icons or borders that need the 3:1
855
+ * non-text contrast threshold.
856
+ * **Screen reader announcement:**
857
+ * - Rendered state: announces the slot text as inline content within its
858
+ * surrounding context (no role means AT reads it as plain text). The
859
+ * `variant` value is not announced — that is intentional; the label text
860
+ * is the source of truth for meaning.
861
+ * - State change: N/A — no dynamic state owned by this component.
862
+ */
863
+ interface HTMLDsBadgeElement extends Components.DsBadge, HTMLStencilElement {
864
+ }
865
+ var HTMLDsBadgeElement: {
866
+ prototype: HTMLDsBadgeElement;
867
+ new (): HTMLDsBadgeElement;
868
+ };
869
+ /**
870
+ * ## Accessibility
871
+ * **Category:** interactive-display
872
+ * **APG pattern:** Button — https://www.w3.org/WAI/ARIA/apg/patterns/button/
873
+ * (satisfied natively by the underlying `<button>` element). When `href` is
874
+ * set, the component renders `<a href>` instead — a link, not a button — and
875
+ * that surface follows native `<a>` semantics rather than the Button pattern.
876
+ * **Keyboard interactions:**
877
+ * - Tab: moves focus to the internal `<button>` or `<a>` (shadow DOM does not
878
+ * interrupt tab order).
879
+ * - Enter: activates (fires click on `<button>`, navigates on `<a>`).
880
+ * - Space: activates the `<button>` variant only (native behavior); on the
881
+ * `<a>` variant Space scrolls the page as usual.
882
+ * - Escape: N/A — no dismissible state owned by this component.
883
+ * - Arrow keys: N/A.
884
+ * - Printable characters: N/A.
885
+ * **ARIA:**
886
+ * - Roles used: none explicit — the native `<button>` / `<a href>` supplies
887
+ * the implicit `button` / `link` role.
888
+ * - State attributes: `disabled` (native attribute on `<button>`, not
889
+ * `aria-disabled`). The `<a>` variant does not accept `disabled` — a
890
+ * disabled navigation is a spec smell (see spec §"Button vs Link"); if a
891
+ * link needs a disabled state, model it as a `<button>` action instead.
892
+ * - Labeling strategy: visible text via `<slot />`. Consumers MUST place
893
+ * readable text (or a labeled icon) inside the tag. An empty slot leaves
894
+ * the button/link without an accessible name and fails
895
+ * `button-name` / `link-name` axe rules. Icon-only usage is out of contract
896
+ * for `ds-button`; use a future `ds-icon-button` with a required
897
+ * `aria-label` prop when that lands.
898
+ * **Focus:**
899
+ * - On mount: nothing auto-focuses.
900
+ * - On activate: focus stays on the element (native click behavior; the
901
+ * component does not move focus on its own).
902
+ * - On close/deactivate: N/A.
903
+ * - Focus indicator: 2px `outline` in `var(--ds-color-focus)` with 2px
904
+ * `outline-offset`, applied via `:focus-visible` — replaces the browser
905
+ * default so both `<button>` and `<a>` variants use the same DS ring
906
+ * (spec universal rule 3, WCAG 1.4.11 non-text contrast ≥ 3:1).
907
+ * **Motion:**
908
+ * - Animations: 150ms `background-color` ease-in-out transition on
909
+ * `primary`/`secondary` variants (hover).
910
+ * - Reduced-motion behavior: N/A — 150ms is below the spec's 200ms threshold
911
+ * for `prefers-reduced-motion` handling, and the transition animates color
912
+ * only (no motion of position, scale, or opacity).
913
+ * **Contrast:**
914
+ * - Text: `primary` and `secondary` variants pair `--ds-color-{primary,secondary}`
915
+ * with `--ds-color-text-on-{primary,secondary}` — the token pairs are
916
+ * authored to meet WCAG 2.1 AA (≥ 4.5:1). The `ghost` variant inherits
917
+ * `color: inherit` and pins `opacity: 0.85`, so its effective contrast
918
+ * depends on the consumer's surface — verify per site.
919
+ * - Non-text (border on `ghost`): 1px `currentColor`; contrast tracks the
920
+ * text color 1:1, subject to the same host-page caveat.
921
+ * **Screen reader announcement:**
922
+ * - Rendered state: announces the slot text followed by "button" (or "link"
923
+ * for the `href` variant), plus "dimmed" / "unavailable" when `disabled`
924
+ * is set (browser/AT dependent wording).
925
+ * - State change: N/A — this component does not own toggle state. A pressed
926
+ * toggle needs `aria-pressed`, which is out of scope here; model that as
927
+ * a distinct component or extend the API deliberately per the spec.
928
+ */
929
+ interface HTMLDsButtonElement extends Components.DsButton, HTMLStencilElement {
930
+ }
931
+ var HTMLDsButtonElement: {
932
+ prototype: HTMLDsButtonElement;
933
+ new (): HTMLDsButtonElement;
934
+ };
935
+ /**
936
+ * ## Accessibility
937
+ * **Category:** static-display
938
+ * **APG pattern:** N/A — a container surface with no interactive
939
+ * behavior of its own. If a consumer nests interactive elements
940
+ * inside (button, link, form field), those elements satisfy their
941
+ * own a11y bucket independently.
942
+ * **Keyboard interactions:**
943
+ * - Tab / Shift+Tab: N/A — the card itself is not focusable. Any
944
+ * interactive descendant carries its own tab semantics.
945
+ * - Enter / Space / Arrow / Escape / Printable: N/A.
946
+ * **ARIA:**
947
+ * - Roles used: none. `<ds-card>` is a purely visual grouping and
948
+ * deliberately does not carry `role="region"` — that would demand
949
+ * a labelledby target, which would only be correct in a subset of
950
+ * uses. Consumers that need a labeled landmark should render a
951
+ * `<section aria-labelledby>` around the card.
952
+ * - State attributes: none.
953
+ * - Labeling strategy: none applied by the component; consumer's
954
+ * heading structure inside the slot supplies the accessible name
955
+ * when needed.
956
+ * **Focus:**
957
+ * - On mount: nothing auto-focuses.
958
+ * - Focus indicator: N/A — the card itself is not focusable.
959
+ * **Motion:**
960
+ * - Animations: none.
961
+ * - Reduced-motion behavior: N/A.
962
+ * **Contrast:**
963
+ * - Text: inherits `color: inherit` / `currentColor`; the card does
964
+ * not impose a text color, so contrast is the consumer theme's
965
+ * responsibility.
966
+ * - Non-text (border, subtle background tint): both derived from
967
+ * `color-mix(in oklch, currentColor N%, transparent)`, matching
968
+ * the pattern used by `ds-input` and `ds-select`. WCAG 1.4.11
969
+ * (3:1 non-text contrast) is met in themes where the surface has
970
+ * enough delta against the page background; the component does
971
+ * not override the consumer's palette to force it.
972
+ * **Screen reader announcement:**
973
+ * - Rendered state: no announcement of the card itself. AT
974
+ * navigates to the slotted content directly, using whatever
975
+ * heading and landmark structure the consumer places inside.
976
+ * - State change: N/A.
977
+ */
978
+ interface HTMLDsCardElement extends Components.DsCard, HTMLStencilElement {
979
+ }
980
+ var HTMLDsCardElement: {
981
+ prototype: HTMLDsCardElement;
982
+ new (): HTMLDsCardElement;
983
+ };
984
+ interface HTMLDsCheckboxElementEventMap {
985
+ "dsChange": boolean;
986
+ }
987
+ /**
988
+ * ## Accessibility
989
+ * **Category:** form-field
990
+ * **APG pattern:** N/A — native element. This wraps a native
991
+ * `<input type="checkbox">`; the browser already implements the
992
+ * checkbox role and its state semantics. Reference:
993
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox
994
+ * Note: `ds-checkbox` intentionally does NOT reach for the WAI-ARIA
995
+ * APG "tri-state checkbox" pattern (indeterminate + on + off) as a
996
+ * scratch-built ARIA widget. The native input already exposes the
997
+ * `indeterminate` DOM property and browsers report it to AT
998
+ * correctly; the `indeterminate` prop here forwards to that DOM
999
+ * property so the native mechanism carries the semantics.
1000
+ * **Keyboard interactions:**
1001
+ * - Tab: moves focus to the native `<input type="checkbox">`.
1002
+ * - Space: toggles the checked state (native behavior).
1003
+ * - Enter: no native effect on a checkbox (unlike button). Form
1004
+ * submission triggered by Enter comes from the enclosing form's
1005
+ * default submit button, not from the checkbox itself.
1006
+ * **ARIA:**
1007
+ * - Roles used: none explicit — the native checkbox supplies the
1008
+ * implicit `checkbox` role.
1009
+ * - State attributes: `checked` (DOM property, kept in sync via
1010
+ * componentDidRender because Stencil does not JSX-forward the
1011
+ * attribute cleanly for controlled use), `disabled` (native
1012
+ * attribute, not `aria-disabled`), `aria-invalid` (from the
1013
+ * `invalid` prop), `aria-required` (from the `required` prop),
1014
+ * `aria-describedby` (from the `describedBy` prop).
1015
+ * - Labeling strategy: `aria-label` set from the `label` prop onto
1016
+ * the internal checkbox. This is the **canonical, recommended**
1017
+ * mode. Wrapping the host in a light-DOM `<label>` also produces
1018
+ * an accessible name in Chromium via flattened-tree resolution —
1019
+ * same secondary mode documented on `ds-input`.
1020
+ * **Focus:**
1021
+ * - On mount: nothing auto-focuses.
1022
+ * - On toggle: focus remains on the native checkbox.
1023
+ * - Focus indicator: browser default `:focus-visible` ring, kept on
1024
+ * purpose until the DS ships a themed focus utility using
1025
+ * `--ds-color-focus`. Not overridden by `ds-checkbox.css`.
1026
+ * **Motion:**
1027
+ * - Animations: none.
1028
+ * - Reduced-motion behavior: N/A.
1029
+ * **Contrast:**
1030
+ * - Text: N/A — the checkbox itself renders no text (labels are
1031
+ * supplied by the consumer via `label` prop or wrapping <label>).
1032
+ * - Non-text (the box and its check glyph): browser default rendering
1033
+ * is kept on purpose (no `appearance: none` override); this
1034
+ * preserves the OS/browser accessibility rendering that AT and
1035
+ * forced-color modes rely on. A themed override is a future
1036
+ * decision once the DS commits to a checkbox visual language that
1037
+ * still passes 3:1 non-text contrast in every theme.
1038
+ * **Screen reader announcement:**
1039
+ * - Rendered state: announces the `label` prop text as the
1040
+ * accessible name, followed by "checkbox", followed by "checked"
1041
+ * / "not checked" / "mixed" per the current DOM state.
1042
+ * - State change: on toggle, AT announces the new state (native
1043
+ * behavior); no `aria-live` added.
1044
+ * **Consumer contract:**
1045
+ * - `checked` is the source of truth for controlled use. Reading
1046
+ * `event.detail` from `dsChange` gives the new state; the internal
1047
+ * input is kept in sync via a Watch + a re-sync in componentDidRender.
1048
+ * - `indeterminate` is a visual/AT state, not a value — it is NOT
1049
+ * submitted with a form and clears on the next user toggle.
1050
+ */
1051
+ interface HTMLDsCheckboxElement extends Components.DsCheckbox, HTMLStencilElement {
1052
+ addEventListener<K extends keyof HTMLDsCheckboxElementEventMap>(type: K, listener: (this: HTMLDsCheckboxElement, ev: DsCheckboxCustomEvent<HTMLDsCheckboxElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
1053
+ addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
1054
+ addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
1055
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
1056
+ removeEventListener<K extends keyof HTMLDsCheckboxElementEventMap>(type: K, listener: (this: HTMLDsCheckboxElement, ev: DsCheckboxCustomEvent<HTMLDsCheckboxElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
1057
+ removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
1058
+ removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
1059
+ removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
1060
+ }
1061
+ var HTMLDsCheckboxElement: {
1062
+ prototype: HTMLDsCheckboxElement;
1063
+ new (): HTMLDsCheckboxElement;
1064
+ };
1065
+ /**
1066
+ * ## Accessibility
1067
+ * **Category:** interactive-display
1068
+ * **APG pattern:** Button — https://www.w3.org/WAI/ARIA/apg/patterns/button/
1069
+ * (for the internal copy control; the code readout itself is static text).
1070
+ * **Keyboard interactions:**
1071
+ * - Tab: moves focus into the internal copy `<button>`; the code readout
1072
+ * (`<pre><code>`) is not focusable itself, but its container is
1073
+ * horizontally scrollable and remains reachable via the browser's caret
1074
+ * browsing / find-in-page path.
1075
+ * - Enter: activates the copy button (writes `code` to the clipboard).
1076
+ * - Space: activates the copy button (native `<button>` behavior).
1077
+ * - Escape: N/A — the "Copied" state auto-clears after 1.4s; no dismissible
1078
+ * modal state.
1079
+ * - Arrow keys: N/A.
1080
+ * - Printable characters: N/A.
1081
+ * **ARIA:**
1082
+ * - Roles used: none explicit — the native `<button>` supplies the implicit
1083
+ * `button` role; `<pre>` and `<code>` supply their semantic roles.
1084
+ * - State attributes: none. The `copied` flag lives only in the button's
1085
+ * accessible name (see below); it is intentionally not surfaced via
1086
+ * `aria-pressed` because it is not a toggle — it is a transient
1087
+ * post-action confirmation.
1088
+ * - Labeling strategy: `aria-label` on the copy button — "Copy code" in the
1089
+ * resting state, "Copied" while the confirmation is visible. This is
1090
+ * authoritative because the button carries both an icon and the words
1091
+ * "Copy" / "Copied", and mixed icon+text needs an explicit accessible
1092
+ * name to avoid AT reading the SVG as a separate node.
1093
+ * **Focus:**
1094
+ * - On mount: nothing auto-focuses.
1095
+ * - On activate: focus stays on the copy button (clipboard write is
1096
+ * synchronous from the user's perspective; no focus is moved).
1097
+ * - On close/deactivate: N/A — no popup or overlay to close.
1098
+ * - Focus indicator: 2px `outline` in `var(--ds-color-focus)` with 2px
1099
+ * `outline-offset`, applied to `.ds-code-block__copy:focus-visible`. The
1100
+ * readout itself is not focusable and has no focus indicator by design.
1101
+ * **Motion:**
1102
+ * - Animations: 120ms `color` / `border-color` ease transition on the copy
1103
+ * button (hover/focus).
1104
+ * - Reduced-motion behavior: N/A — 120ms is below the spec's 200ms
1105
+ * threshold, and the transition animates color only.
1106
+ * **Contrast:**
1107
+ * - Text (code readout): inherits `color: currentColor`; contrast depends
1108
+ * on the host page's text color vs. the block's tinted background
1109
+ * (`color-mix(currentColor 4%, transparent)`). Verify per site.
1110
+ * - Text (copy button): `color-mix(in oklch, currentColor 70%, transparent)`
1111
+ * at rest, `currentColor` on hover. The 70%-mixed resting color can drop
1112
+ * below 4.5:1 on low-contrast surfaces — audit per usage site, and lean
1113
+ * on the hover/focus states (both restore full `currentColor`) as the
1114
+ * accessible fallback.
1115
+ * - Non-text (button border, language tag border-bottom): both use
1116
+ * `color-mix(currentColor <15|12>%, transparent)` — decorative separators,
1117
+ * they do not convey state, so the 3:1 non-text contrast rule does not
1118
+ * apply. Focus and hover borders shift up to 30% for clearer edges.
1119
+ * **Screen reader announcement:**
1120
+ * - Rendered state: announces "Copy code, button" (the `aria-label`), then
1121
+ * the code content when the user navigates into the `<pre><code>` block
1122
+ * (usually announced as a code block on VoiceOver).
1123
+ * - State change: after clicking Copy, the button's `aria-label` flips to
1124
+ * "Copied"; AT will announce this on the next focus or re-read of the
1125
+ * button, but NOT proactively — there is no `aria-live` region. This is
1126
+ * deliberate per spec §"What we explicitly do NOT do" (avoid live-region
1127
+ * overuse), and the trade-off is that a screen-reader-only user does not
1128
+ * get an unsolicited confirmation. If a future review decides that
1129
+ * confirmation must be audible, add a visually-hidden
1130
+ * `aria-live="polite"` element whose text toggles on `copied`.
1131
+ */
1132
+ interface HTMLDsCodeBlockElement extends Components.DsCodeBlock, HTMLStencilElement {
1133
+ }
1134
+ var HTMLDsCodeBlockElement: {
1135
+ prototype: HTMLDsCodeBlockElement;
1136
+ new (): HTMLDsCodeBlockElement;
1137
+ };
1138
+ interface HTMLDsDialogElementEventMap {
1139
+ "dsOpen": void;
1140
+ "dsClose": void;
1141
+ }
1142
+ /**
1143
+ * ## Accessibility
1144
+ * **Category:** state-machine
1145
+ * **APG pattern:** https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
1146
+ * This component wraps the **native `<dialog>` element** rather than
1147
+ * scratch-building the APG pattern on top of a `<div role="dialog">`.
1148
+ * `<dialog>` opened via `showModal()` gives us — from the browser,
1149
+ * verified by the platform, not by us:
1150
+ * - Focus trap: Tab / Shift+Tab cycle only through focusable
1151
+ * descendants (including slotted light-DOM descendants; the flattened
1152
+ * accessibility tree is what the trap operates on).
1153
+ * - Escape: closes the dialog and returns focus to the previously
1154
+ * focused element (native, not implemented here).
1155
+ * - Inert background: everything outside the dialog is inert while it
1156
+ * is open — no mouse, no keyboard, not part of the a11y tree.
1157
+ * - Return focus: on close, focus returns to whatever element had it
1158
+ * before `showModal()` — native, not implemented here.
1159
+ * - Initial focus: browser auto-focuses the first `autofocus` element
1160
+ * inside, or the first focusable if none — native.
1161
+ * - `role="dialog"` and `aria-modal="true"` semantics: implicit on
1162
+ * `<dialog>`, no ARIA needed from us.
1163
+ * This is the deliberate answer to the a11y spec §D warning about
1164
+ * scratch-building Tier 2 components: the native element removes the
1165
+ * "compiles, axe passes, screen-reader user gets trapped" failure
1166
+ * mode by delegating the state machine to the platform.
1167
+ * **Keyboard interactions (all handled by the native element unless
1168
+ * noted otherwise):**
1169
+ * - Tab: cycles focus within the dialog's focusable descendants
1170
+ * (native focus trap).
1171
+ * - Shift+Tab: reverse cycle (native).
1172
+ * - Escape: closes the dialog and fires the `close` event (native).
1173
+ * Consumers who need to prevent dismissal on Escape (destructive
1174
+ * flows: e.g. an unsaved-changes guard) must call
1175
+ * `event.preventDefault()` inside their own `keydown` listener on
1176
+ * the dialog before it reaches the browser — that is an escape
1177
+ * hatch, not a default we impose.
1178
+ * - Enter / Space: no special dialog behavior; forwarded to
1179
+ * whatever descendant has focus (a button will activate).
1180
+ * - Home / End / Arrow keys: no special dialog behavior; forwarded
1181
+ * to descendants.
1182
+ * - Printable characters: forwarded to descendants (e.g. typing
1183
+ * inside a slotted `<ds-input>`).
1184
+ * **ARIA attributes and value triggers:**
1185
+ * - Implicit `role="dialog"` on the native `<dialog>`.
1186
+ * - Implicit `aria-modal="true"` when opened via `showModal()`
1187
+ * (which is what this component always uses; `show()` — the
1188
+ * non-modal form — is intentionally not exposed in v1).
1189
+ * - `aria-label` set from the `label` prop onto the `<dialog>`.
1190
+ * Consumers who prefer an in-content title can pass a
1191
+ * `labelledBy` prop instead, whose value is the id of a heading
1192
+ * element they render inside the slot — `aria-labelledby`
1193
+ * resolves that id through the flattened tree.
1194
+ * - `aria-describedby` from the `describedBy` prop, resolving a
1195
+ * light-DOM id of a descriptive block (e.g. the dialog body copy
1196
+ * when the label is short).
1197
+ * **Focus lifecycle:**
1198
+ * - Opening: `showModal()` moves focus to the first `autofocus`
1199
+ * element inside, or the first focusable if none. Consumers who
1200
+ * want a specific initial focus target should mark that element
1201
+ * with `autofocus`.
1202
+ * - While open: focus is trapped within the flattened tree of the
1203
+ * `<dialog>`; Tab / Shift+Tab cycle through slotted descendants.
1204
+ * Focus cannot escape into the inert background.
1205
+ * - Closing: `close()` (either from Escape, from a form-submit with
1206
+ * `method="dialog"`, from a light-dismiss backdrop click handler
1207
+ * the consumer wires up, or from `open=false`) returns focus to
1208
+ * the element that had it immediately before `showModal()` was
1209
+ * called. The `dsClose` event fires after focus has been restored.
1210
+ * **ARIA labelling contract (choose one):**
1211
+ * - **`label`** (string) — sets `aria-label` on the dialog. Simplest
1212
+ * for short titles.
1213
+ * - **`labelledBy`** (id) — sets `aria-labelledby` to reference a
1214
+ * heading rendered inside the slot. Preferred when the dialog has
1215
+ * a visible title so the accessible name matches the visible name.
1216
+ * If both are omitted, axe reports `dialog-name` — the dialog has no
1217
+ * accessible name. The a11y test for this component asserts that at
1218
+ * least one of the two is provided.
1219
+ * **Motion:**
1220
+ * - Animations: none applied by the component. Consumers who want an
1221
+ * entrance transition can style `::backdrop` and `dialog[open]`
1222
+ * with their own animation, gated on `@media
1223
+ * (prefers-reduced-motion: no-preference)`.
1224
+ * - Reduced-motion behavior: N/A — no animation to collapse. If a
1225
+ * consumer adds one, they own the reduced-motion fallback.
1226
+ * **Contrast:**
1227
+ * - Text: inherits `color: inherit`; consumer theme owns contrast.
1228
+ * - Non-text: subtle bordered surface via
1229
+ * `color-mix(in oklch, currentColor N%, transparent)` matching
1230
+ * `ds-card`. Backdrop is a semi-transparent black by default.
1231
+ * **Screen reader announcement:**
1232
+ * - Rendered state (closed): dialog is not in the a11y tree.
1233
+ * - Opened: AT announces "dialog" plus the accessible name from
1234
+ * `label` / `labelledBy`, then reads the content following focus
1235
+ * (or the descriptive block referenced by `describedBy` first,
1236
+ * depending on AT).
1237
+ * - State change: on close, AT returns to the element that regained
1238
+ * focus (the trigger); no `aria-live` announcement is added.
1239
+ * **Consumer contract:**
1240
+ * - Set `open` to true to show; set to false to close. The component
1241
+ * syncs the DOM state via `showModal()` / `close()` in a Watch.
1242
+ * - Listen to `dsClose` to know when the dialog was dismissed (by
1243
+ * Escape, by `open=false`, or by a form submit with
1244
+ * `method="dialog"`). Listen to `dsOpen` for the mirror event.
1245
+ * - The default backdrop is opaque and NOT click-to-dismiss. Consumers
1246
+ * who want light-dismiss can add a click listener on the dialog
1247
+ * that closes when the click target is the dialog itself (not a
1248
+ * descendant): `if (e.target === dialog) dialog.close()`.
1249
+ * - Put focus targets (form fields, primary action button) inside
1250
+ * the slot. Use `autofocus` on the element that should receive
1251
+ * focus first.
1252
+ * **Pending manual verification (see commit message TODO):**
1253
+ * - VoiceOver on macOS: confirm the dialog announces its accessible
1254
+ * name + "dialog" on open, focus lands on the correct element,
1255
+ * Escape closes and focus returns to the trigger.
1256
+ * - Chromium high-contrast / forced-colors: confirm the surface
1257
+ * still reads as a bordered container with the native ::backdrop
1258
+ * dim.
1259
+ */
1260
+ interface HTMLDsDialogElement extends Components.DsDialog, HTMLStencilElement {
1261
+ addEventListener<K extends keyof HTMLDsDialogElementEventMap>(type: K, listener: (this: HTMLDsDialogElement, ev: DsDialogCustomEvent<HTMLDsDialogElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
1262
+ addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
1263
+ addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
1264
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
1265
+ removeEventListener<K extends keyof HTMLDsDialogElementEventMap>(type: K, listener: (this: HTMLDsDialogElement, ev: DsDialogCustomEvent<HTMLDsDialogElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
1266
+ removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
1267
+ removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
1268
+ removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
1269
+ }
1270
+ var HTMLDsDialogElement: {
1271
+ prototype: HTMLDsDialogElement;
1272
+ new (): HTMLDsDialogElement;
1273
+ };
1274
+ interface HTMLDsInputElementEventMap {
1275
+ "dsInput": string;
1276
+ }
1277
+ /**
1278
+ * ## Accessibility
1279
+ * **Category:** form-field
1280
+ * **APG pattern:** N/A — native element. This wraps a native `<input>`;
1281
+ * there is no WAI-ARIA APG pattern for a plain text input because the
1282
+ * browser already implements it natively. Reference:
1283
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
1284
+ * **Keyboard interactions:**
1285
+ * - Tab: moves focus to the native `<input>` (shadow DOM does not
1286
+ * interrupt tab order).
1287
+ * - Printable characters: insert at the caret position (native).
1288
+ * - Backspace / Delete: native editing.
1289
+ * - Arrow keys: move the caret within the value (native); for
1290
+ * `type="number"` Up/Down step the numeric value (native).
1291
+ * - Enter: on `type="search"` may submit the enclosing form (native);
1292
+ * no custom handling.
1293
+ * - Escape: no native meaning for a text input.
1294
+ * **ARIA:**
1295
+ * - Roles used: none explicit — the native `<input>` supplies its
1296
+ * implicit role (`textbox`, `searchbox`, etc. depending on `type`).
1297
+ * - State attributes: `disabled` (native attribute, not `aria-disabled`),
1298
+ * `aria-invalid` (from the `invalid` prop), `aria-required` (from the
1299
+ * `required` prop), `aria-describedby` (from the `describedBy` prop,
1300
+ * expected to reference a light-DOM node id — typically a hint or
1301
+ * error message rendered by the consumer alongside the field).
1302
+ * - Labeling strategy: `aria-label` set from the `label` prop onto the
1303
+ * internal `<input>`. This is the **canonical, recommended** mode —
1304
+ * explicit and independent of DOM structure. Consumers MUST pass
1305
+ * `label` (or otherwise give the field an accessible name) — an
1306
+ * `<input>` with no accessible name is a WCAG failure (axe rule
1307
+ * `label`). Wrapping the host in a light-DOM `<label>` (e.g.
1308
+ * `<label>Email <ds-input></ds-input></label>`) also produces an
1309
+ * accessible name in Chromium via flattened-tree resolution — the
1310
+ * same secondary mode documented on `ds-select`, verified in this
1311
+ * component's e2e tests. Setting `aria-label` directly on the
1312
+ * `<ds-input>` host does NOT work: shadow-DOM attribute forwarding
1313
+ * would be required — use the `label` prop instead.
1314
+ * **Focus:**
1315
+ * - On mount: nothing auto-focuses.
1316
+ * - On value change: focus remains on the native `<input>`.
1317
+ * - Focus indicator: the browser default `:focus-visible` ring is kept
1318
+ * on purpose — a themed focus ring using `--ds-color-focus` is a
1319
+ * future decision once the DS ships a shared focus utility. Not
1320
+ * overridden by `ds-input.css`.
1321
+ * **Motion:**
1322
+ * - Animations: none.
1323
+ * - Reduced-motion behavior: N/A — no animation to collapse.
1324
+ * **Contrast:**
1325
+ * - Text: inherits `color: inherit` / `currentColor`; ratio depends on
1326
+ * the consumer's theme, not verified in isolation here.
1327
+ * - Border: `color-mix(in oklch, currentColor 22%, transparent)`,
1328
+ * matching `ds-select` — inherits whatever contrast the host page
1329
+ * sets. WCAG 1.4.11 (3:1 non-text) is the consumer's responsibility
1330
+ * in themes that override the surface.
1331
+ * **Screen reader announcement:**
1332
+ * - Rendered state: announces the `label` prop text as the accessible
1333
+ * name, followed by the browser/AT's role announcement for the
1334
+ * input type ("edit text", "search text", "password", "phone
1335
+ * number", "email"…). When `required=true` the announcement
1336
+ * includes "required"; when `invalid=true` it includes "invalid".
1337
+ * - State change: on value edit, AT typically echoes the typed
1338
+ * character (native input behavior); no `aria-live` added, per the
1339
+ * spec's guidance against live-region overuse.
1340
+ * **Consumer contract:**
1341
+ * - `placeholder` is a hint, not a label. It disappears on focus in
1342
+ * most browsers and is not reliably announced by every AT — always
1343
+ * pair with `label`.
1344
+ * - For `type="password"` in a real form, pair with a light-DOM
1345
+ * `<input type="hidden">` or a form-associated ancestor that gives
1346
+ * the browser's password manager an `autocomplete` hint. This
1347
+ * component intentionally does not expose `autocomplete` in v1;
1348
+ * consumers that need it can render a native `<input>` for that
1349
+ * field until the prop is added.
1350
+ * - When `invalid=true`, pair with a `describedBy` id that points at
1351
+ * a visible error message; `aria-invalid` alone gives the AT the
1352
+ * status but not the reason.
1353
+ */
1354
+ interface HTMLDsInputElement extends Components.DsInput, HTMLStencilElement {
1355
+ addEventListener<K extends keyof HTMLDsInputElementEventMap>(type: K, listener: (this: HTMLDsInputElement, ev: DsInputCustomEvent<HTMLDsInputElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
1356
+ addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
1357
+ addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
1358
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
1359
+ removeEventListener<K extends keyof HTMLDsInputElementEventMap>(type: K, listener: (this: HTMLDsInputElement, ev: DsInputCustomEvent<HTMLDsInputElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
1360
+ removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
1361
+ removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
1362
+ removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
1363
+ }
1364
+ var HTMLDsInputElement: {
1365
+ prototype: HTMLDsInputElement;
1366
+ new (): HTMLDsInputElement;
1367
+ };
1368
+ /**
1369
+ * ## Accessibility
1370
+ * **Category:** static-display (indeterminate progress indicator)
1371
+ * **APG pattern:** N/A — the loader is a passive presence indicator, not a
1372
+ * `progressbar` (no measurable value). Uses `role="status"` per WAI-ARIA
1373
+ * live-region semantics for indeterminate loading states.
1374
+ * **Keyboard interactions:**
1375
+ * - Tab: N/A — not focusable.
1376
+ * - Enter: N/A.
1377
+ * - Escape: N/A.
1378
+ * - Arrow keys: N/A.
1379
+ * - Printable characters: N/A.
1380
+ * **ARIA:**
1381
+ * - Roles used: `role="status"` on the host — an implicit polite live
1382
+ * region ARIA lists as valid for "advisory information" including
1383
+ * in-progress operations. The inner `<svg>` is decorative and carries
1384
+ * `aria-hidden="true"` + `focusable="false"` so it never becomes a
1385
+ * parallel target for screen readers.
1386
+ * - State attributes: none. The loader has no state changes to announce
1387
+ * beyond its own presence; the polite live region on mount is the
1388
+ * announcement.
1389
+ * - Labeling strategy: `aria-label` from the `label` prop (default
1390
+ * "Loading"). Consumers pass a more specific string when the context
1391
+ * warrants ("Loading ceremonies", "Signing in", …).
1392
+ * **Focus:**
1393
+ * - On mount: nothing auto-focuses.
1394
+ * - On activate/open: N/A — not interactive.
1395
+ * - On close/deactivate: N/A.
1396
+ * - Focus indicator: N/A — the host is not focusable.
1397
+ * **Motion:**
1398
+ * - Animations: two mirrored halves of the logo path oscillate
1399
+ * symmetrically around the visual center, meeting at the ring midpoint
1400
+ * and separating again. Cycle 1.4s by default (`speed="normal"`);
1401
+ * `speed="slow"` = 2.2s, `speed="fast"` = 0.9s.
1402
+ * - Reduced-motion behavior: `@media (prefers-reduced-motion: reduce)`
1403
+ * collapses both halves to a static rendering with a slow opacity
1404
+ * pulse (2s ease-in-out). No rotation, no lateral movement.
1405
+ * **Contrast:**
1406
+ * - Text: N/A — the visible surface is the SVG stroke, not text.
1407
+ * - Non-text: stroke inherits `currentColor` from the host. Consumers are
1408
+ * responsible for confirming the stroke against its background meets
1409
+ * the ≥ 3:1 non-text contrast threshold (WCAG 1.4.11) where the loader
1410
+ * conveys state (e.g. distinguishing "still loading" from "idle").
1411
+ * **Screen reader announcement:**
1412
+ * - Rendered state: the polite live region announces the label
1413
+ * (e.g. "Loading") when the loader mounts.
1414
+ * - State change: N/A — the loader itself has no state that changes.
1415
+ * Consumers unmount the loader when the awaited work completes; that
1416
+ * removal is silent, which is the intended behavior (the arriving
1417
+ * content is the announcement).
1418
+ */
1419
+ interface HTMLDsLoaderElement extends Components.DsLoader, HTMLStencilElement {
1420
+ }
1421
+ var HTMLDsLoaderElement: {
1422
+ prototype: HTMLDsLoaderElement;
1423
+ new (): HTMLDsLoaderElement;
1424
+ };
1425
+ interface HTMLDsSelectElementEventMap {
1426
+ "dsChange": string;
1427
+ }
1428
+ interface HTMLDsSelectElement extends Components.DsSelect, HTMLStencilElement {
1429
+ addEventListener<K extends keyof HTMLDsSelectElementEventMap>(type: K, listener: (this: HTMLDsSelectElement, ev: DsSelectCustomEvent<HTMLDsSelectElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
1430
+ addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
1431
+ addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
1432
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
1433
+ removeEventListener<K extends keyof HTMLDsSelectElementEventMap>(type: K, listener: (this: HTMLDsSelectElement, ev: DsSelectCustomEvent<HTMLDsSelectElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
1434
+ removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
1435
+ removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
1436
+ removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
1437
+ }
1438
+ var HTMLDsSelectElement: {
1439
+ prototype: HTMLDsSelectElement;
1440
+ new (): HTMLDsSelectElement;
1441
+ };
1442
+ interface HTMLDsTabsElementEventMap {
1443
+ "dsChange": string;
1444
+ }
1445
+ interface HTMLDsTabsElement extends Components.DsTabs, HTMLStencilElement {
1446
+ addEventListener<K extends keyof HTMLDsTabsElementEventMap>(type: K, listener: (this: HTMLDsTabsElement, ev: DsTabsCustomEvent<HTMLDsTabsElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
1447
+ addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
1448
+ addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
1449
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
1450
+ removeEventListener<K extends keyof HTMLDsTabsElementEventMap>(type: K, listener: (this: HTMLDsTabsElement, ev: DsTabsCustomEvent<HTMLDsTabsElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
1451
+ removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
1452
+ removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
1453
+ removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
1454
+ }
1455
+ var HTMLDsTabsElement: {
1456
+ prototype: HTMLDsTabsElement;
1457
+ new (): HTMLDsTabsElement;
1458
+ };
1459
+ interface HTMLDsTextareaElementEventMap {
1460
+ "dsInput": string;
1461
+ }
1462
+ /**
1463
+ * ## Accessibility
1464
+ * **Category:** form-field
1465
+ * **APG pattern:** N/A — native element. This wraps a native
1466
+ * `<textarea>`; there is no WAI-ARIA APG pattern for a plain
1467
+ * multi-line text field because the browser already implements it
1468
+ * natively. Reference:
1469
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea
1470
+ * **Keyboard interactions:**
1471
+ * - Tab: moves focus to the native `<textarea>`; Tab inside the
1472
+ * textarea inserts a tab character only when the browser is
1473
+ * configured to do so (default behavior: Tab moves focus out).
1474
+ * - Printable characters: insert at the caret position (native).
1475
+ * - Enter: inserts a newline within the value (native), does not
1476
+ * submit the enclosing form (unlike a single-line input).
1477
+ * - Backspace / Delete: native editing.
1478
+ * - Arrow keys: move the caret within the value (native).
1479
+ * - Escape: no native meaning for a text area.
1480
+ * **ARIA:**
1481
+ * - Roles used: none explicit — the native `<textarea>` supplies
1482
+ * the implicit `textbox` role with multiline behavior.
1483
+ * - State attributes: `disabled` (native attribute, not
1484
+ * `aria-disabled`), `aria-invalid` (from the `invalid` prop),
1485
+ * `aria-required` (from the `required` prop), `aria-describedby`
1486
+ * (from the `describedBy` prop, expected to reference a light-DOM
1487
+ * node id — typically a hint or error message rendered by the
1488
+ * consumer alongside the field).
1489
+ * - Labeling strategy: `aria-label` set from the `label` prop onto
1490
+ * the internal `<textarea>`. This is the **canonical, recommended**
1491
+ * mode. Wrapping the host in a light-DOM `<label>` also produces
1492
+ * an accessible name in Chromium via flattened-tree resolution —
1493
+ * same secondary mode documented on `ds-input` and `ds-select`,
1494
+ * verified in this component's e2e tests. Setting `aria-label`
1495
+ * directly on the `<ds-textarea>` host does NOT work: shadow-DOM
1496
+ * attribute forwarding would be required — use the `label` prop.
1497
+ * **Focus:**
1498
+ * - On mount: nothing auto-focuses.
1499
+ * - On value change: focus remains on the native `<textarea>`.
1500
+ * - Focus indicator: the browser default `:focus-visible` ring is
1501
+ * kept on purpose — a themed focus ring using `--ds-color-focus`
1502
+ * is a future decision once the DS ships a shared focus utility.
1503
+ * **Motion:**
1504
+ * - Animations: none.
1505
+ * - Reduced-motion behavior: N/A — no animation to collapse.
1506
+ * **Contrast:**
1507
+ * - Text: inherits `color: inherit` / `currentColor`; ratio depends
1508
+ * on the consumer's theme, not verified in isolation.
1509
+ * - Border: `color-mix(in oklch, currentColor 22%, transparent)`,
1510
+ * matching `ds-input`.
1511
+ * **Screen reader announcement:**
1512
+ * - Rendered state: announces the `label` prop text as the
1513
+ * accessible name, followed by "edit text, multiline" (browser/AT
1514
+ * wording varies). When `required=true` the announcement includes
1515
+ * "required"; when `invalid=true` it includes "invalid".
1516
+ * - State change: on value edit, AT typically echoes the typed
1517
+ * character (native behavior); no `aria-live` added.
1518
+ * **Consumer contract:**
1519
+ * - `placeholder` is a hint, not a label — always pair with `label`.
1520
+ * - When `invalid=true`, pair with a `describedBy` id that points at
1521
+ * a visible error message; `aria-invalid` alone gives the AT the
1522
+ * status but not the reason.
1523
+ * - `rows` sets the initial visible line count. Vertical resize is
1524
+ * left to the native default (`resize: vertical`) so users can
1525
+ * grow the field for long entries; the consumer's CSS can pin it
1526
+ * with `resize: none` when a fixed height matters.
1527
+ */
1528
+ interface HTMLDsTextareaElement extends Components.DsTextarea, HTMLStencilElement {
1529
+ addEventListener<K extends keyof HTMLDsTextareaElementEventMap>(type: K, listener: (this: HTMLDsTextareaElement, ev: DsTextareaCustomEvent<HTMLDsTextareaElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
1530
+ addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
1531
+ addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
1532
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
1533
+ removeEventListener<K extends keyof HTMLDsTextareaElementEventMap>(type: K, listener: (this: HTMLDsTextareaElement, ev: DsTextareaCustomEvent<HTMLDsTextareaElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
1534
+ removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
1535
+ removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
1536
+ removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
1537
+ }
1538
+ var HTMLDsTextareaElement: {
1539
+ prototype: HTMLDsTextareaElement;
1540
+ new (): HTMLDsTextareaElement;
1541
+ };
1542
+ interface HTMLDsTooltipElement extends Components.DsTooltip, HTMLStencilElement {
1543
+ }
1544
+ var HTMLDsTooltipElement: {
1545
+ prototype: HTMLDsTooltipElement;
1546
+ new (): HTMLDsTooltipElement;
1547
+ };
1548
+ interface HTMLElementTagNameMap {
1549
+ "ds-badge": HTMLDsBadgeElement;
1550
+ "ds-button": HTMLDsButtonElement;
1551
+ "ds-card": HTMLDsCardElement;
1552
+ "ds-checkbox": HTMLDsCheckboxElement;
1553
+ "ds-code-block": HTMLDsCodeBlockElement;
1554
+ "ds-dialog": HTMLDsDialogElement;
1555
+ "ds-input": HTMLDsInputElement;
1556
+ "ds-loader": HTMLDsLoaderElement;
1557
+ "ds-select": HTMLDsSelectElement;
1558
+ "ds-tabs": HTMLDsTabsElement;
1559
+ "ds-textarea": HTMLDsTextareaElement;
1560
+ "ds-tooltip": HTMLDsTooltipElement;
1561
+ }
1562
+ }
1563
+ declare namespace LocalJSX {
1564
+ type OneOf<K extends string, PropT, AttrT = PropT> = { [P in K]: PropT } & { [P in `attr:${K}` | `prop:${K}`]?: never } | { [P in `attr:${K}`]: AttrT } & { [P in K | `prop:${K}`]?: never } | { [P in `prop:${K}`]: PropT } & { [P in K | `attr:${K}`]?: never };
1565
+
1566
+ /**
1567
+ * ## Accessibility
1568
+ * **Category:** static-display
1569
+ * **APG pattern:** N/A — non-interactive text label.
1570
+ * **Keyboard interactions:**
1571
+ * - Tab: N/A — the badge is not focusable and does not appear in tab order.
1572
+ * - Enter: N/A.
1573
+ * - Escape: N/A.
1574
+ * - Arrow keys: N/A.
1575
+ * - Printable characters: N/A.
1576
+ * **ARIA:**
1577
+ * - Roles used: none — renders a plain `<span>` around a `<slot />`. The
1578
+ * `variant` prop is a purely visual axis and MUST NOT be the sole carrier
1579
+ * of information (color/style alone fails WCAG 1.4.1 Use of Color); the
1580
+ * textual content inside the slot must convey the same meaning.
1581
+ * - State attributes: none.
1582
+ * - Labeling strategy: visible text via `<slot />`. Consumers place the
1583
+ * readable label directly inside the tag.
1584
+ * **Focus:**
1585
+ * - On mount: nothing auto-focuses.
1586
+ * - On activate/open: N/A — non-interactive.
1587
+ * - On close/deactivate: N/A.
1588
+ * - Focus indicator: N/A — the host is not focusable. If a consumer wraps
1589
+ * `ds-badge` in an interactive element (e.g. `<button>`, `<a>`), that
1590
+ * wrapper owns the focus indicator via the DS `--ds-color-focus` token
1591
+ * and its own `:focus-visible` rule.
1592
+ * **Motion:**
1593
+ * - Animations: none.
1594
+ * - Reduced-motion behavior: N/A.
1595
+ * **Contrast:**
1596
+ * - Text: inherits `color: inherit` / `currentColor` from the host page and
1597
+ * the variant-specific style; not verified in isolation here. Consumers
1598
+ * are responsible for confirming ≥ 4.5:1 (WCAG 1.4.3) against the surface
1599
+ * the badge is placed on.
1600
+ * - Non-text: no state-conveying icons or borders that need the 3:1
1601
+ * non-text contrast threshold.
1602
+ * **Screen reader announcement:**
1603
+ * - Rendered state: announces the slot text as inline content within its
1604
+ * surrounding context (no role means AT reads it as plain text). The
1605
+ * `variant` value is not announced — that is intentional; the label text
1606
+ * is the source of truth for meaning.
1607
+ * - State change: N/A — no dynamic state owned by this component.
1608
+ */
1609
+ interface DsBadge {
1610
+ /**
1611
+ * @default "neutral"
1612
+ */
1613
+ "variant"?: | "neutral"
1614
+ | "ui-component"
1615
+ | "recipe"
1616
+ | "agent"
1617
+ | "config";
1618
+ }
1619
+ /**
1620
+ * ## Accessibility
1621
+ * **Category:** interactive-display
1622
+ * **APG pattern:** Button — https://www.w3.org/WAI/ARIA/apg/patterns/button/
1623
+ * (satisfied natively by the underlying `<button>` element). When `href` is
1624
+ * set, the component renders `<a href>` instead — a link, not a button — and
1625
+ * that surface follows native `<a>` semantics rather than the Button pattern.
1626
+ * **Keyboard interactions:**
1627
+ * - Tab: moves focus to the internal `<button>` or `<a>` (shadow DOM does not
1628
+ * interrupt tab order).
1629
+ * - Enter: activates (fires click on `<button>`, navigates on `<a>`).
1630
+ * - Space: activates the `<button>` variant only (native behavior); on the
1631
+ * `<a>` variant Space scrolls the page as usual.
1632
+ * - Escape: N/A — no dismissible state owned by this component.
1633
+ * - Arrow keys: N/A.
1634
+ * - Printable characters: N/A.
1635
+ * **ARIA:**
1636
+ * - Roles used: none explicit — the native `<button>` / `<a href>` supplies
1637
+ * the implicit `button` / `link` role.
1638
+ * - State attributes: `disabled` (native attribute on `<button>`, not
1639
+ * `aria-disabled`). The `<a>` variant does not accept `disabled` — a
1640
+ * disabled navigation is a spec smell (see spec §"Button vs Link"); if a
1641
+ * link needs a disabled state, model it as a `<button>` action instead.
1642
+ * - Labeling strategy: visible text via `<slot />`. Consumers MUST place
1643
+ * readable text (or a labeled icon) inside the tag. An empty slot leaves
1644
+ * the button/link without an accessible name and fails
1645
+ * `button-name` / `link-name` axe rules. Icon-only usage is out of contract
1646
+ * for `ds-button`; use a future `ds-icon-button` with a required
1647
+ * `aria-label` prop when that lands.
1648
+ * **Focus:**
1649
+ * - On mount: nothing auto-focuses.
1650
+ * - On activate: focus stays on the element (native click behavior; the
1651
+ * component does not move focus on its own).
1652
+ * - On close/deactivate: N/A.
1653
+ * - Focus indicator: 2px `outline` in `var(--ds-color-focus)` with 2px
1654
+ * `outline-offset`, applied via `:focus-visible` — replaces the browser
1655
+ * default so both `<button>` and `<a>` variants use the same DS ring
1656
+ * (spec universal rule 3, WCAG 1.4.11 non-text contrast ≥ 3:1).
1657
+ * **Motion:**
1658
+ * - Animations: 150ms `background-color` ease-in-out transition on
1659
+ * `primary`/`secondary` variants (hover).
1660
+ * - Reduced-motion behavior: N/A — 150ms is below the spec's 200ms threshold
1661
+ * for `prefers-reduced-motion` handling, and the transition animates color
1662
+ * only (no motion of position, scale, or opacity).
1663
+ * **Contrast:**
1664
+ * - Text: `primary` and `secondary` variants pair `--ds-color-{primary,secondary}`
1665
+ * with `--ds-color-text-on-{primary,secondary}` — the token pairs are
1666
+ * authored to meet WCAG 2.1 AA (≥ 4.5:1). The `ghost` variant inherits
1667
+ * `color: inherit` and pins `opacity: 0.85`, so its effective contrast
1668
+ * depends on the consumer's surface — verify per site.
1669
+ * - Non-text (border on `ghost`): 1px `currentColor`; contrast tracks the
1670
+ * text color 1:1, subject to the same host-page caveat.
1671
+ * **Screen reader announcement:**
1672
+ * - Rendered state: announces the slot text followed by "button" (or "link"
1673
+ * for the `href` variant), plus "dimmed" / "unavailable" when `disabled`
1674
+ * is set (browser/AT dependent wording).
1675
+ * - State change: N/A — this component does not own toggle state. A pressed
1676
+ * toggle needs `aria-pressed`, which is out of scope here; model that as
1677
+ * a distinct component or extend the API deliberately per the spec.
1678
+ */
1679
+ interface DsButton {
1680
+ /**
1681
+ * @default false
1682
+ */
1683
+ "disabled"?: boolean;
1684
+ "href"?: string;
1685
+ /**
1686
+ * @default "md"
1687
+ */
1688
+ "size"?: "md" | "lg";
1689
+ /**
1690
+ * @default "button"
1691
+ */
1692
+ "type"?: "button" | "submit" | "reset";
1693
+ /**
1694
+ * @default "primary"
1695
+ */
1696
+ "variant"?: "primary" | "secondary" | "ghost";
1697
+ }
1698
+ /**
1699
+ * ## Accessibility
1700
+ * **Category:** static-display
1701
+ * **APG pattern:** N/A — a container surface with no interactive
1702
+ * behavior of its own. If a consumer nests interactive elements
1703
+ * inside (button, link, form field), those elements satisfy their
1704
+ * own a11y bucket independently.
1705
+ * **Keyboard interactions:**
1706
+ * - Tab / Shift+Tab: N/A — the card itself is not focusable. Any
1707
+ * interactive descendant carries its own tab semantics.
1708
+ * - Enter / Space / Arrow / Escape / Printable: N/A.
1709
+ * **ARIA:**
1710
+ * - Roles used: none. `<ds-card>` is a purely visual grouping and
1711
+ * deliberately does not carry `role="region"` — that would demand
1712
+ * a labelledby target, which would only be correct in a subset of
1713
+ * uses. Consumers that need a labeled landmark should render a
1714
+ * `<section aria-labelledby>` around the card.
1715
+ * - State attributes: none.
1716
+ * - Labeling strategy: none applied by the component; consumer's
1717
+ * heading structure inside the slot supplies the accessible name
1718
+ * when needed.
1719
+ * **Focus:**
1720
+ * - On mount: nothing auto-focuses.
1721
+ * - Focus indicator: N/A — the card itself is not focusable.
1722
+ * **Motion:**
1723
+ * - Animations: none.
1724
+ * - Reduced-motion behavior: N/A.
1725
+ * **Contrast:**
1726
+ * - Text: inherits `color: inherit` / `currentColor`; the card does
1727
+ * not impose a text color, so contrast is the consumer theme's
1728
+ * responsibility.
1729
+ * - Non-text (border, subtle background tint): both derived from
1730
+ * `color-mix(in oklch, currentColor N%, transparent)`, matching
1731
+ * the pattern used by `ds-input` and `ds-select`. WCAG 1.4.11
1732
+ * (3:1 non-text contrast) is met in themes where the surface has
1733
+ * enough delta against the page background; the component does
1734
+ * not override the consumer's palette to force it.
1735
+ * **Screen reader announcement:**
1736
+ * - Rendered state: no announcement of the card itself. AT
1737
+ * navigates to the slotted content directly, using whatever
1738
+ * heading and landmark structure the consumer places inside.
1739
+ * - State change: N/A.
1740
+ */
1741
+ interface DsCard {
1742
+ }
1743
+ /**
1744
+ * ## Accessibility
1745
+ * **Category:** form-field
1746
+ * **APG pattern:** N/A — native element. This wraps a native
1747
+ * `<input type="checkbox">`; the browser already implements the
1748
+ * checkbox role and its state semantics. Reference:
1749
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox
1750
+ * Note: `ds-checkbox` intentionally does NOT reach for the WAI-ARIA
1751
+ * APG "tri-state checkbox" pattern (indeterminate + on + off) as a
1752
+ * scratch-built ARIA widget. The native input already exposes the
1753
+ * `indeterminate` DOM property and browsers report it to AT
1754
+ * correctly; the `indeterminate` prop here forwards to that DOM
1755
+ * property so the native mechanism carries the semantics.
1756
+ * **Keyboard interactions:**
1757
+ * - Tab: moves focus to the native `<input type="checkbox">`.
1758
+ * - Space: toggles the checked state (native behavior).
1759
+ * - Enter: no native effect on a checkbox (unlike button). Form
1760
+ * submission triggered by Enter comes from the enclosing form's
1761
+ * default submit button, not from the checkbox itself.
1762
+ * **ARIA:**
1763
+ * - Roles used: none explicit — the native checkbox supplies the
1764
+ * implicit `checkbox` role.
1765
+ * - State attributes: `checked` (DOM property, kept in sync via
1766
+ * componentDidRender because Stencil does not JSX-forward the
1767
+ * attribute cleanly for controlled use), `disabled` (native
1768
+ * attribute, not `aria-disabled`), `aria-invalid` (from the
1769
+ * `invalid` prop), `aria-required` (from the `required` prop),
1770
+ * `aria-describedby` (from the `describedBy` prop).
1771
+ * - Labeling strategy: `aria-label` set from the `label` prop onto
1772
+ * the internal checkbox. This is the **canonical, recommended**
1773
+ * mode. Wrapping the host in a light-DOM `<label>` also produces
1774
+ * an accessible name in Chromium via flattened-tree resolution —
1775
+ * same secondary mode documented on `ds-input`.
1776
+ * **Focus:**
1777
+ * - On mount: nothing auto-focuses.
1778
+ * - On toggle: focus remains on the native checkbox.
1779
+ * - Focus indicator: browser default `:focus-visible` ring, kept on
1780
+ * purpose until the DS ships a themed focus utility using
1781
+ * `--ds-color-focus`. Not overridden by `ds-checkbox.css`.
1782
+ * **Motion:**
1783
+ * - Animations: none.
1784
+ * - Reduced-motion behavior: N/A.
1785
+ * **Contrast:**
1786
+ * - Text: N/A — the checkbox itself renders no text (labels are
1787
+ * supplied by the consumer via `label` prop or wrapping <label>).
1788
+ * - Non-text (the box and its check glyph): browser default rendering
1789
+ * is kept on purpose (no `appearance: none` override); this
1790
+ * preserves the OS/browser accessibility rendering that AT and
1791
+ * forced-color modes rely on. A themed override is a future
1792
+ * decision once the DS commits to a checkbox visual language that
1793
+ * still passes 3:1 non-text contrast in every theme.
1794
+ * **Screen reader announcement:**
1795
+ * - Rendered state: announces the `label` prop text as the
1796
+ * accessible name, followed by "checkbox", followed by "checked"
1797
+ * / "not checked" / "mixed" per the current DOM state.
1798
+ * - State change: on toggle, AT announces the new state (native
1799
+ * behavior); no `aria-live` added.
1800
+ * **Consumer contract:**
1801
+ * - `checked` is the source of truth for controlled use. Reading
1802
+ * `event.detail` from `dsChange` gives the new state; the internal
1803
+ * input is kept in sync via a Watch + a re-sync in componentDidRender.
1804
+ * - `indeterminate` is a visual/AT state, not a value — it is NOT
1805
+ * submitted with a form and clears on the next user toggle.
1806
+ */
1807
+ interface DsCheckbox {
1808
+ /**
1809
+ * @default false
1810
+ */
1811
+ "checked"?: boolean;
1812
+ "describedBy"?: string;
1813
+ /**
1814
+ * @default false
1815
+ */
1816
+ "disabled"?: boolean;
1817
+ /**
1818
+ * @default false
1819
+ */
1820
+ "indeterminate"?: boolean;
1821
+ /**
1822
+ * @default false
1823
+ */
1824
+ "invalid"?: boolean;
1825
+ "label"?: string;
1826
+ "name"?: string;
1827
+ "onDsChange"?: (event: DsCheckboxCustomEvent<boolean>) => void;
1828
+ /**
1829
+ * @default false
1830
+ */
1831
+ "required"?: boolean;
1832
+ "value"?: string;
1833
+ }
1834
+ /**
1835
+ * ## Accessibility
1836
+ * **Category:** interactive-display
1837
+ * **APG pattern:** Button — https://www.w3.org/WAI/ARIA/apg/patterns/button/
1838
+ * (for the internal copy control; the code readout itself is static text).
1839
+ * **Keyboard interactions:**
1840
+ * - Tab: moves focus into the internal copy `<button>`; the code readout
1841
+ * (`<pre><code>`) is not focusable itself, but its container is
1842
+ * horizontally scrollable and remains reachable via the browser's caret
1843
+ * browsing / find-in-page path.
1844
+ * - Enter: activates the copy button (writes `code` to the clipboard).
1845
+ * - Space: activates the copy button (native `<button>` behavior).
1846
+ * - Escape: N/A — the "Copied" state auto-clears after 1.4s; no dismissible
1847
+ * modal state.
1848
+ * - Arrow keys: N/A.
1849
+ * - Printable characters: N/A.
1850
+ * **ARIA:**
1851
+ * - Roles used: none explicit — the native `<button>` supplies the implicit
1852
+ * `button` role; `<pre>` and `<code>` supply their semantic roles.
1853
+ * - State attributes: none. The `copied` flag lives only in the button's
1854
+ * accessible name (see below); it is intentionally not surfaced via
1855
+ * `aria-pressed` because it is not a toggle — it is a transient
1856
+ * post-action confirmation.
1857
+ * - Labeling strategy: `aria-label` on the copy button — "Copy code" in the
1858
+ * resting state, "Copied" while the confirmation is visible. This is
1859
+ * authoritative because the button carries both an icon and the words
1860
+ * "Copy" / "Copied", and mixed icon+text needs an explicit accessible
1861
+ * name to avoid AT reading the SVG as a separate node.
1862
+ * **Focus:**
1863
+ * - On mount: nothing auto-focuses.
1864
+ * - On activate: focus stays on the copy button (clipboard write is
1865
+ * synchronous from the user's perspective; no focus is moved).
1866
+ * - On close/deactivate: N/A — no popup or overlay to close.
1867
+ * - Focus indicator: 2px `outline` in `var(--ds-color-focus)` with 2px
1868
+ * `outline-offset`, applied to `.ds-code-block__copy:focus-visible`. The
1869
+ * readout itself is not focusable and has no focus indicator by design.
1870
+ * **Motion:**
1871
+ * - Animations: 120ms `color` / `border-color` ease transition on the copy
1872
+ * button (hover/focus).
1873
+ * - Reduced-motion behavior: N/A — 120ms is below the spec's 200ms
1874
+ * threshold, and the transition animates color only.
1875
+ * **Contrast:**
1876
+ * - Text (code readout): inherits `color: currentColor`; contrast depends
1877
+ * on the host page's text color vs. the block's tinted background
1878
+ * (`color-mix(currentColor 4%, transparent)`). Verify per site.
1879
+ * - Text (copy button): `color-mix(in oklch, currentColor 70%, transparent)`
1880
+ * at rest, `currentColor` on hover. The 70%-mixed resting color can drop
1881
+ * below 4.5:1 on low-contrast surfaces — audit per usage site, and lean
1882
+ * on the hover/focus states (both restore full `currentColor`) as the
1883
+ * accessible fallback.
1884
+ * - Non-text (button border, language tag border-bottom): both use
1885
+ * `color-mix(currentColor <15|12>%, transparent)` — decorative separators,
1886
+ * they do not convey state, so the 3:1 non-text contrast rule does not
1887
+ * apply. Focus and hover borders shift up to 30% for clearer edges.
1888
+ * **Screen reader announcement:**
1889
+ * - Rendered state: announces "Copy code, button" (the `aria-label`), then
1890
+ * the code content when the user navigates into the `<pre><code>` block
1891
+ * (usually announced as a code block on VoiceOver).
1892
+ * - State change: after clicking Copy, the button's `aria-label` flips to
1893
+ * "Copied"; AT will announce this on the next focus or re-read of the
1894
+ * button, but NOT proactively — there is no `aria-live` region. This is
1895
+ * deliberate per spec §"What we explicitly do NOT do" (avoid live-region
1896
+ * overuse), and the trade-off is that a screen-reader-only user does not
1897
+ * get an unsolicited confirmation. If a future review decides that
1898
+ * confirmation must be audible, add a visually-hidden
1899
+ * `aria-live="polite"` element whose text toggles on `copied`.
1900
+ */
1901
+ interface DsCodeBlock {
1902
+ "code": string;
1903
+ /**
1904
+ * @default "bash"
1905
+ */
1906
+ "language"?: string;
1907
+ }
1908
+ /**
1909
+ * ## Accessibility
1910
+ * **Category:** state-machine
1911
+ * **APG pattern:** https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
1912
+ * This component wraps the **native `<dialog>` element** rather than
1913
+ * scratch-building the APG pattern on top of a `<div role="dialog">`.
1914
+ * `<dialog>` opened via `showModal()` gives us — from the browser,
1915
+ * verified by the platform, not by us:
1916
+ * - Focus trap: Tab / Shift+Tab cycle only through focusable
1917
+ * descendants (including slotted light-DOM descendants; the flattened
1918
+ * accessibility tree is what the trap operates on).
1919
+ * - Escape: closes the dialog and returns focus to the previously
1920
+ * focused element (native, not implemented here).
1921
+ * - Inert background: everything outside the dialog is inert while it
1922
+ * is open — no mouse, no keyboard, not part of the a11y tree.
1923
+ * - Return focus: on close, focus returns to whatever element had it
1924
+ * before `showModal()` — native, not implemented here.
1925
+ * - Initial focus: browser auto-focuses the first `autofocus` element
1926
+ * inside, or the first focusable if none — native.
1927
+ * - `role="dialog"` and `aria-modal="true"` semantics: implicit on
1928
+ * `<dialog>`, no ARIA needed from us.
1929
+ * This is the deliberate answer to the a11y spec §D warning about
1930
+ * scratch-building Tier 2 components: the native element removes the
1931
+ * "compiles, axe passes, screen-reader user gets trapped" failure
1932
+ * mode by delegating the state machine to the platform.
1933
+ * **Keyboard interactions (all handled by the native element unless
1934
+ * noted otherwise):**
1935
+ * - Tab: cycles focus within the dialog's focusable descendants
1936
+ * (native focus trap).
1937
+ * - Shift+Tab: reverse cycle (native).
1938
+ * - Escape: closes the dialog and fires the `close` event (native).
1939
+ * Consumers who need to prevent dismissal on Escape (destructive
1940
+ * flows: e.g. an unsaved-changes guard) must call
1941
+ * `event.preventDefault()` inside their own `keydown` listener on
1942
+ * the dialog before it reaches the browser — that is an escape
1943
+ * hatch, not a default we impose.
1944
+ * - Enter / Space: no special dialog behavior; forwarded to
1945
+ * whatever descendant has focus (a button will activate).
1946
+ * - Home / End / Arrow keys: no special dialog behavior; forwarded
1947
+ * to descendants.
1948
+ * - Printable characters: forwarded to descendants (e.g. typing
1949
+ * inside a slotted `<ds-input>`).
1950
+ * **ARIA attributes and value triggers:**
1951
+ * - Implicit `role="dialog"` on the native `<dialog>`.
1952
+ * - Implicit `aria-modal="true"` when opened via `showModal()`
1953
+ * (which is what this component always uses; `show()` — the
1954
+ * non-modal form — is intentionally not exposed in v1).
1955
+ * - `aria-label` set from the `label` prop onto the `<dialog>`.
1956
+ * Consumers who prefer an in-content title can pass a
1957
+ * `labelledBy` prop instead, whose value is the id of a heading
1958
+ * element they render inside the slot — `aria-labelledby`
1959
+ * resolves that id through the flattened tree.
1960
+ * - `aria-describedby` from the `describedBy` prop, resolving a
1961
+ * light-DOM id of a descriptive block (e.g. the dialog body copy
1962
+ * when the label is short).
1963
+ * **Focus lifecycle:**
1964
+ * - Opening: `showModal()` moves focus to the first `autofocus`
1965
+ * element inside, or the first focusable if none. Consumers who
1966
+ * want a specific initial focus target should mark that element
1967
+ * with `autofocus`.
1968
+ * - While open: focus is trapped within the flattened tree of the
1969
+ * `<dialog>`; Tab / Shift+Tab cycle through slotted descendants.
1970
+ * Focus cannot escape into the inert background.
1971
+ * - Closing: `close()` (either from Escape, from a form-submit with
1972
+ * `method="dialog"`, from a light-dismiss backdrop click handler
1973
+ * the consumer wires up, or from `open=false`) returns focus to
1974
+ * the element that had it immediately before `showModal()` was
1975
+ * called. The `dsClose` event fires after focus has been restored.
1976
+ * **ARIA labelling contract (choose one):**
1977
+ * - **`label`** (string) — sets `aria-label` on the dialog. Simplest
1978
+ * for short titles.
1979
+ * - **`labelledBy`** (id) — sets `aria-labelledby` to reference a
1980
+ * heading rendered inside the slot. Preferred when the dialog has
1981
+ * a visible title so the accessible name matches the visible name.
1982
+ * If both are omitted, axe reports `dialog-name` — the dialog has no
1983
+ * accessible name. The a11y test for this component asserts that at
1984
+ * least one of the two is provided.
1985
+ * **Motion:**
1986
+ * - Animations: none applied by the component. Consumers who want an
1987
+ * entrance transition can style `::backdrop` and `dialog[open]`
1988
+ * with their own animation, gated on `@media
1989
+ * (prefers-reduced-motion: no-preference)`.
1990
+ * - Reduced-motion behavior: N/A — no animation to collapse. If a
1991
+ * consumer adds one, they own the reduced-motion fallback.
1992
+ * **Contrast:**
1993
+ * - Text: inherits `color: inherit`; consumer theme owns contrast.
1994
+ * - Non-text: subtle bordered surface via
1995
+ * `color-mix(in oklch, currentColor N%, transparent)` matching
1996
+ * `ds-card`. Backdrop is a semi-transparent black by default.
1997
+ * **Screen reader announcement:**
1998
+ * - Rendered state (closed): dialog is not in the a11y tree.
1999
+ * - Opened: AT announces "dialog" plus the accessible name from
2000
+ * `label` / `labelledBy`, then reads the content following focus
2001
+ * (or the descriptive block referenced by `describedBy` first,
2002
+ * depending on AT).
2003
+ * - State change: on close, AT returns to the element that regained
2004
+ * focus (the trigger); no `aria-live` announcement is added.
2005
+ * **Consumer contract:**
2006
+ * - Set `open` to true to show; set to false to close. The component
2007
+ * syncs the DOM state via `showModal()` / `close()` in a Watch.
2008
+ * - Listen to `dsClose` to know when the dialog was dismissed (by
2009
+ * Escape, by `open=false`, or by a form submit with
2010
+ * `method="dialog"`). Listen to `dsOpen` for the mirror event.
2011
+ * - The default backdrop is opaque and NOT click-to-dismiss. Consumers
2012
+ * who want light-dismiss can add a click listener on the dialog
2013
+ * that closes when the click target is the dialog itself (not a
2014
+ * descendant): `if (e.target === dialog) dialog.close()`.
2015
+ * - Put focus targets (form fields, primary action button) inside
2016
+ * the slot. Use `autofocus` on the element that should receive
2017
+ * focus first.
2018
+ * **Pending manual verification (see commit message TODO):**
2019
+ * - VoiceOver on macOS: confirm the dialog announces its accessible
2020
+ * name + "dialog" on open, focus lands on the correct element,
2021
+ * Escape closes and focus returns to the trigger.
2022
+ * - Chromium high-contrast / forced-colors: confirm the surface
2023
+ * still reads as a bordered container with the native ::backdrop
2024
+ * dim.
2025
+ */
2026
+ interface DsDialog {
2027
+ "describedBy"?: string;
2028
+ "label"?: string;
2029
+ "labelledBy"?: string;
2030
+ "onDsClose"?: (event: DsDialogCustomEvent<void>) => void;
2031
+ "onDsOpen"?: (event: DsDialogCustomEvent<void>) => void;
2032
+ /**
2033
+ * @default false
2034
+ */
2035
+ "open"?: boolean;
2036
+ }
2037
+ /**
2038
+ * ## Accessibility
2039
+ * **Category:** form-field
2040
+ * **APG pattern:** N/A — native element. This wraps a native `<input>`;
2041
+ * there is no WAI-ARIA APG pattern for a plain text input because the
2042
+ * browser already implements it natively. Reference:
2043
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
2044
+ * **Keyboard interactions:**
2045
+ * - Tab: moves focus to the native `<input>` (shadow DOM does not
2046
+ * interrupt tab order).
2047
+ * - Printable characters: insert at the caret position (native).
2048
+ * - Backspace / Delete: native editing.
2049
+ * - Arrow keys: move the caret within the value (native); for
2050
+ * `type="number"` Up/Down step the numeric value (native).
2051
+ * - Enter: on `type="search"` may submit the enclosing form (native);
2052
+ * no custom handling.
2053
+ * - Escape: no native meaning for a text input.
2054
+ * **ARIA:**
2055
+ * - Roles used: none explicit — the native `<input>` supplies its
2056
+ * implicit role (`textbox`, `searchbox`, etc. depending on `type`).
2057
+ * - State attributes: `disabled` (native attribute, not `aria-disabled`),
2058
+ * `aria-invalid` (from the `invalid` prop), `aria-required` (from the
2059
+ * `required` prop), `aria-describedby` (from the `describedBy` prop,
2060
+ * expected to reference a light-DOM node id — typically a hint or
2061
+ * error message rendered by the consumer alongside the field).
2062
+ * - Labeling strategy: `aria-label` set from the `label` prop onto the
2063
+ * internal `<input>`. This is the **canonical, recommended** mode —
2064
+ * explicit and independent of DOM structure. Consumers MUST pass
2065
+ * `label` (or otherwise give the field an accessible name) — an
2066
+ * `<input>` with no accessible name is a WCAG failure (axe rule
2067
+ * `label`). Wrapping the host in a light-DOM `<label>` (e.g.
2068
+ * `<label>Email <ds-input></ds-input></label>`) also produces an
2069
+ * accessible name in Chromium via flattened-tree resolution — the
2070
+ * same secondary mode documented on `ds-select`, verified in this
2071
+ * component's e2e tests. Setting `aria-label` directly on the
2072
+ * `<ds-input>` host does NOT work: shadow-DOM attribute forwarding
2073
+ * would be required — use the `label` prop instead.
2074
+ * **Focus:**
2075
+ * - On mount: nothing auto-focuses.
2076
+ * - On value change: focus remains on the native `<input>`.
2077
+ * - Focus indicator: the browser default `:focus-visible` ring is kept
2078
+ * on purpose — a themed focus ring using `--ds-color-focus` is a
2079
+ * future decision once the DS ships a shared focus utility. Not
2080
+ * overridden by `ds-input.css`.
2081
+ * **Motion:**
2082
+ * - Animations: none.
2083
+ * - Reduced-motion behavior: N/A — no animation to collapse.
2084
+ * **Contrast:**
2085
+ * - Text: inherits `color: inherit` / `currentColor`; ratio depends on
2086
+ * the consumer's theme, not verified in isolation here.
2087
+ * - Border: `color-mix(in oklch, currentColor 22%, transparent)`,
2088
+ * matching `ds-select` — inherits whatever contrast the host page
2089
+ * sets. WCAG 1.4.11 (3:1 non-text) is the consumer's responsibility
2090
+ * in themes that override the surface.
2091
+ * **Screen reader announcement:**
2092
+ * - Rendered state: announces the `label` prop text as the accessible
2093
+ * name, followed by the browser/AT's role announcement for the
2094
+ * input type ("edit text", "search text", "password", "phone
2095
+ * number", "email"…). When `required=true` the announcement
2096
+ * includes "required"; when `invalid=true` it includes "invalid".
2097
+ * - State change: on value edit, AT typically echoes the typed
2098
+ * character (native input behavior); no `aria-live` added, per the
2099
+ * spec's guidance against live-region overuse.
2100
+ * **Consumer contract:**
2101
+ * - `placeholder` is a hint, not a label. It disappears on focus in
2102
+ * most browsers and is not reliably announced by every AT — always
2103
+ * pair with `label`.
2104
+ * - For `type="password"` in a real form, pair with a light-DOM
2105
+ * `<input type="hidden">` or a form-associated ancestor that gives
2106
+ * the browser's password manager an `autocomplete` hint. This
2107
+ * component intentionally does not expose `autocomplete` in v1;
2108
+ * consumers that need it can render a native `<input>` for that
2109
+ * field until the prop is added.
2110
+ * - When `invalid=true`, pair with a `describedBy` id that points at
2111
+ * a visible error message; `aria-invalid` alone gives the AT the
2112
+ * status but not the reason.
2113
+ */
2114
+ interface DsInput {
2115
+ "describedBy"?: string;
2116
+ /**
2117
+ * @default false
2118
+ */
2119
+ "disabled"?: boolean;
2120
+ /**
2121
+ * @default false
2122
+ */
2123
+ "invalid"?: boolean;
2124
+ "label"?: string;
2125
+ "name"?: string;
2126
+ "onDsInput"?: (event: DsInputCustomEvent<string>) => void;
2127
+ "placeholder"?: string;
2128
+ /**
2129
+ * @default false
2130
+ */
2131
+ "required"?: boolean;
2132
+ /**
2133
+ * @default "md"
2134
+ */
2135
+ "size"?: "md" | "lg";
2136
+ /**
2137
+ * @default "text"
2138
+ */
2139
+ "type"?: | "text"
2140
+ | "email"
2141
+ | "password"
2142
+ | "search"
2143
+ | "tel"
2144
+ | "url"
2145
+ | "number";
2146
+ "value"?: string;
2147
+ }
2148
+ /**
2149
+ * ## Accessibility
2150
+ * **Category:** static-display (indeterminate progress indicator)
2151
+ * **APG pattern:** N/A — the loader is a passive presence indicator, not a
2152
+ * `progressbar` (no measurable value). Uses `role="status"` per WAI-ARIA
2153
+ * live-region semantics for indeterminate loading states.
2154
+ * **Keyboard interactions:**
2155
+ * - Tab: N/A — not focusable.
2156
+ * - Enter: N/A.
2157
+ * - Escape: N/A.
2158
+ * - Arrow keys: N/A.
2159
+ * - Printable characters: N/A.
2160
+ * **ARIA:**
2161
+ * - Roles used: `role="status"` on the host — an implicit polite live
2162
+ * region ARIA lists as valid for "advisory information" including
2163
+ * in-progress operations. The inner `<svg>` is decorative and carries
2164
+ * `aria-hidden="true"` + `focusable="false"` so it never becomes a
2165
+ * parallel target for screen readers.
2166
+ * - State attributes: none. The loader has no state changes to announce
2167
+ * beyond its own presence; the polite live region on mount is the
2168
+ * announcement.
2169
+ * - Labeling strategy: `aria-label` from the `label` prop (default
2170
+ * "Loading"). Consumers pass a more specific string when the context
2171
+ * warrants ("Loading ceremonies", "Signing in", …).
2172
+ * **Focus:**
2173
+ * - On mount: nothing auto-focuses.
2174
+ * - On activate/open: N/A — not interactive.
2175
+ * - On close/deactivate: N/A.
2176
+ * - Focus indicator: N/A — the host is not focusable.
2177
+ * **Motion:**
2178
+ * - Animations: two mirrored halves of the logo path oscillate
2179
+ * symmetrically around the visual center, meeting at the ring midpoint
2180
+ * and separating again. Cycle 1.4s by default (`speed="normal"`);
2181
+ * `speed="slow"` = 2.2s, `speed="fast"` = 0.9s.
2182
+ * - Reduced-motion behavior: `@media (prefers-reduced-motion: reduce)`
2183
+ * collapses both halves to a static rendering with a slow opacity
2184
+ * pulse (2s ease-in-out). No rotation, no lateral movement.
2185
+ * **Contrast:**
2186
+ * - Text: N/A — the visible surface is the SVG stroke, not text.
2187
+ * - Non-text: stroke inherits `currentColor` from the host. Consumers are
2188
+ * responsible for confirming the stroke against its background meets
2189
+ * the ≥ 3:1 non-text contrast threshold (WCAG 1.4.11) where the loader
2190
+ * conveys state (e.g. distinguishing "still loading" from "idle").
2191
+ * **Screen reader announcement:**
2192
+ * - Rendered state: the polite live region announces the label
2193
+ * (e.g. "Loading") when the loader mounts.
2194
+ * - State change: N/A — the loader itself has no state that changes.
2195
+ * Consumers unmount the loader when the awaited work completes; that
2196
+ * removal is silent, which is the intended behavior (the arriving
2197
+ * content is the announcement).
2198
+ */
2199
+ interface DsLoader {
2200
+ /**
2201
+ * @default "Loading"
2202
+ */
2203
+ "label"?: string;
2204
+ /**
2205
+ * @default "md"
2206
+ */
2207
+ "size"?: "sm" | "md" | "lg";
2208
+ /**
2209
+ * @default "normal"
2210
+ */
2211
+ "speed"?: "slow" | "normal" | "fast";
2212
+ }
2213
+ interface DsSelect {
2214
+ /**
2215
+ * @default false
2216
+ */
2217
+ "disabled"?: boolean;
2218
+ "label"?: string;
2219
+ "name"?: string;
2220
+ "onDsChange"?: (event: DsSelectCustomEvent<string>) => void;
2221
+ /**
2222
+ * Options rendered inside the internal shadow `<select>`. Accepts either: - a JSON string (SSR-friendly — server-rendered HTML can only set string attributes, and Stencil does not JSON-parse array attributes), e.g. `options='[{"value":"en","label":"EN"}]'` - an array property set from client-side JS, e.g. `el.options = [{ value: 'en', label: 'EN' }]` Malformed JSON fails safe to an empty list rather than throwing, so the component still renders a visible (if empty) select.
2223
+ * @default "[]"
2224
+ */
2225
+ "options"?: string | ReadonlyArray<DsSelectOption>;
2226
+ /**
2227
+ * @default "md"
2228
+ */
2229
+ "size"?: "md" | "lg";
2230
+ "value"?: string;
2231
+ }
2232
+ interface DsTabs {
2233
+ "active"?: string;
2234
+ /**
2235
+ * @default "[]"
2236
+ */
2237
+ "items"?: string | ReadonlyArray<DsTabItem>;
2238
+ "label"?: string;
2239
+ "onDsChange"?: (event: DsTabsCustomEvent<string>) => void;
2240
+ /**
2241
+ * @default "horizontal"
2242
+ */
2243
+ "orientation"?: "horizontal" | "vertical";
2244
+ }
2245
+ /**
2246
+ * ## Accessibility
2247
+ * **Category:** form-field
2248
+ * **APG pattern:** N/A — native element. This wraps a native
2249
+ * `<textarea>`; there is no WAI-ARIA APG pattern for a plain
2250
+ * multi-line text field because the browser already implements it
2251
+ * natively. Reference:
2252
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea
2253
+ * **Keyboard interactions:**
2254
+ * - Tab: moves focus to the native `<textarea>`; Tab inside the
2255
+ * textarea inserts a tab character only when the browser is
2256
+ * configured to do so (default behavior: Tab moves focus out).
2257
+ * - Printable characters: insert at the caret position (native).
2258
+ * - Enter: inserts a newline within the value (native), does not
2259
+ * submit the enclosing form (unlike a single-line input).
2260
+ * - Backspace / Delete: native editing.
2261
+ * - Arrow keys: move the caret within the value (native).
2262
+ * - Escape: no native meaning for a text area.
2263
+ * **ARIA:**
2264
+ * - Roles used: none explicit — the native `<textarea>` supplies
2265
+ * the implicit `textbox` role with multiline behavior.
2266
+ * - State attributes: `disabled` (native attribute, not
2267
+ * `aria-disabled`), `aria-invalid` (from the `invalid` prop),
2268
+ * `aria-required` (from the `required` prop), `aria-describedby`
2269
+ * (from the `describedBy` prop, expected to reference a light-DOM
2270
+ * node id — typically a hint or error message rendered by the
2271
+ * consumer alongside the field).
2272
+ * - Labeling strategy: `aria-label` set from the `label` prop onto
2273
+ * the internal `<textarea>`. This is the **canonical, recommended**
2274
+ * mode. Wrapping the host in a light-DOM `<label>` also produces
2275
+ * an accessible name in Chromium via flattened-tree resolution —
2276
+ * same secondary mode documented on `ds-input` and `ds-select`,
2277
+ * verified in this component's e2e tests. Setting `aria-label`
2278
+ * directly on the `<ds-textarea>` host does NOT work: shadow-DOM
2279
+ * attribute forwarding would be required — use the `label` prop.
2280
+ * **Focus:**
2281
+ * - On mount: nothing auto-focuses.
2282
+ * - On value change: focus remains on the native `<textarea>`.
2283
+ * - Focus indicator: the browser default `:focus-visible` ring is
2284
+ * kept on purpose — a themed focus ring using `--ds-color-focus`
2285
+ * is a future decision once the DS ships a shared focus utility.
2286
+ * **Motion:**
2287
+ * - Animations: none.
2288
+ * - Reduced-motion behavior: N/A — no animation to collapse.
2289
+ * **Contrast:**
2290
+ * - Text: inherits `color: inherit` / `currentColor`; ratio depends
2291
+ * on the consumer's theme, not verified in isolation.
2292
+ * - Border: `color-mix(in oklch, currentColor 22%, transparent)`,
2293
+ * matching `ds-input`.
2294
+ * **Screen reader announcement:**
2295
+ * - Rendered state: announces the `label` prop text as the
2296
+ * accessible name, followed by "edit text, multiline" (browser/AT
2297
+ * wording varies). When `required=true` the announcement includes
2298
+ * "required"; when `invalid=true` it includes "invalid".
2299
+ * - State change: on value edit, AT typically echoes the typed
2300
+ * character (native behavior); no `aria-live` added.
2301
+ * **Consumer contract:**
2302
+ * - `placeholder` is a hint, not a label — always pair with `label`.
2303
+ * - When `invalid=true`, pair with a `describedBy` id that points at
2304
+ * a visible error message; `aria-invalid` alone gives the AT the
2305
+ * status but not the reason.
2306
+ * - `rows` sets the initial visible line count. Vertical resize is
2307
+ * left to the native default (`resize: vertical`) so users can
2308
+ * grow the field for long entries; the consumer's CSS can pin it
2309
+ * with `resize: none` when a fixed height matters.
2310
+ */
2311
+ interface DsTextarea {
2312
+ "describedBy"?: string;
2313
+ /**
2314
+ * @default false
2315
+ */
2316
+ "disabled"?: boolean;
2317
+ /**
2318
+ * @default false
2319
+ */
2320
+ "invalid"?: boolean;
2321
+ "label"?: string;
2322
+ "name"?: string;
2323
+ "onDsInput"?: (event: DsTextareaCustomEvent<string>) => void;
2324
+ "placeholder"?: string;
2325
+ /**
2326
+ * @default false
2327
+ */
2328
+ "required"?: boolean;
2329
+ /**
2330
+ * @default 3
2331
+ */
2332
+ "rows"?: number;
2333
+ /**
2334
+ * @default "md"
2335
+ */
2336
+ "size"?: "md" | "lg";
2337
+ "value"?: string;
2338
+ }
2339
+ interface DsTooltip {
2340
+ /**
2341
+ * @default 100
2342
+ */
2343
+ "closeDelay"?: number;
2344
+ "label": string;
2345
+ /**
2346
+ * @default 250
2347
+ */
2348
+ "openDelay"?: number;
2349
+ /**
2350
+ * @default "bottom"
2351
+ */
2352
+ "placement"?: "top" | "bottom";
2353
+ }
2354
+
2355
+ interface DsBadgeAttributes {
2356
+ "variant": | "neutral"
2357
+ | "ui-component"
2358
+ | "recipe"
2359
+ | "agent"
2360
+ | "config";
2361
+ }
2362
+ interface DsButtonAttributes {
2363
+ "variant": "primary" | "secondary" | "ghost";
2364
+ "size": "md" | "lg";
2365
+ "disabled": boolean;
2366
+ "type": "button" | "submit" | "reset";
2367
+ "href": string;
2368
+ }
2369
+ interface DsCheckboxAttributes {
2370
+ "checked": boolean;
2371
+ "indeterminate": boolean;
2372
+ "name": string;
2373
+ "value": string;
2374
+ "disabled": boolean;
2375
+ "required": boolean;
2376
+ "invalid": boolean;
2377
+ "describedBy": string;
2378
+ "label": string;
2379
+ }
2380
+ interface DsCodeBlockAttributes {
2381
+ "code": string;
2382
+ "language": string;
2383
+ }
2384
+ interface DsDialogAttributes {
2385
+ "open": boolean;
2386
+ "label": string;
2387
+ "labelledBy": string;
2388
+ "describedBy": string;
2389
+ }
2390
+ interface DsInputAttributes {
2391
+ "value": string;
2392
+ "name": string;
2393
+ "type": | "text"
2394
+ | "email"
2395
+ | "password"
2396
+ | "search"
2397
+ | "tel"
2398
+ | "url"
2399
+ | "number";
2400
+ "placeholder": string;
2401
+ "disabled": boolean;
2402
+ "required": boolean;
2403
+ "invalid": boolean;
2404
+ "describedBy": string;
2405
+ "label": string;
2406
+ "size": "md" | "lg";
2407
+ }
2408
+ interface DsLoaderAttributes {
2409
+ "size": "sm" | "md" | "lg";
2410
+ "label": string;
2411
+ "speed": "slow" | "normal" | "fast";
2412
+ }
2413
+ interface DsSelectAttributes {
2414
+ "value": string;
2415
+ "name": string;
2416
+ "disabled": boolean;
2417
+ "size": "md" | "lg";
2418
+ "label": string;
2419
+ "options": string | ReadonlyArray<DsSelectOption>;
2420
+ }
2421
+ interface DsTabsAttributes {
2422
+ "items": string | ReadonlyArray<DsTabItem>;
2423
+ "active": string;
2424
+ "orientation": "horizontal" | "vertical";
2425
+ "label": string;
2426
+ }
2427
+ interface DsTextareaAttributes {
2428
+ "value": string;
2429
+ "name": string;
2430
+ "placeholder": string;
2431
+ "disabled": boolean;
2432
+ "required": boolean;
2433
+ "invalid": boolean;
2434
+ "describedBy": string;
2435
+ "label": string;
2436
+ "rows": number;
2437
+ "size": "md" | "lg";
2438
+ }
2439
+ interface DsTooltipAttributes {
2440
+ "label": string;
2441
+ "openDelay": number;
2442
+ "closeDelay": number;
2443
+ "placement": "top" | "bottom";
2444
+ }
2445
+
2446
+ interface IntrinsicElements {
2447
+ "ds-badge": Omit<DsBadge, keyof DsBadgeAttributes> & { [K in keyof DsBadge & keyof DsBadgeAttributes]?: DsBadge[K] } & { [K in keyof DsBadge & keyof DsBadgeAttributes as `attr:${K}`]?: DsBadgeAttributes[K] } & { [K in keyof DsBadge & keyof DsBadgeAttributes as `prop:${K}`]?: DsBadge[K] };
2448
+ "ds-button": Omit<DsButton, keyof DsButtonAttributes> & { [K in keyof DsButton & keyof DsButtonAttributes]?: DsButton[K] } & { [K in keyof DsButton & keyof DsButtonAttributes as `attr:${K}`]?: DsButtonAttributes[K] } & { [K in keyof DsButton & keyof DsButtonAttributes as `prop:${K}`]?: DsButton[K] };
2449
+ "ds-card": DsCard;
2450
+ "ds-checkbox": Omit<DsCheckbox, keyof DsCheckboxAttributes> & { [K in keyof DsCheckbox & keyof DsCheckboxAttributes]?: DsCheckbox[K] } & { [K in keyof DsCheckbox & keyof DsCheckboxAttributes as `attr:${K}`]?: DsCheckboxAttributes[K] } & { [K in keyof DsCheckbox & keyof DsCheckboxAttributes as `prop:${K}`]?: DsCheckbox[K] };
2451
+ "ds-code-block": Omit<DsCodeBlock, keyof DsCodeBlockAttributes> & { [K in keyof DsCodeBlock & keyof DsCodeBlockAttributes]?: DsCodeBlock[K] } & { [K in keyof DsCodeBlock & keyof DsCodeBlockAttributes as `attr:${K}`]?: DsCodeBlockAttributes[K] } & { [K in keyof DsCodeBlock & keyof DsCodeBlockAttributes as `prop:${K}`]?: DsCodeBlock[K] } & OneOf<"code", DsCodeBlock["code"], DsCodeBlockAttributes["code"]>;
2452
+ "ds-dialog": Omit<DsDialog, keyof DsDialogAttributes> & { [K in keyof DsDialog & keyof DsDialogAttributes]?: DsDialog[K] } & { [K in keyof DsDialog & keyof DsDialogAttributes as `attr:${K}`]?: DsDialogAttributes[K] } & { [K in keyof DsDialog & keyof DsDialogAttributes as `prop:${K}`]?: DsDialog[K] };
2453
+ "ds-input": Omit<DsInput, keyof DsInputAttributes> & { [K in keyof DsInput & keyof DsInputAttributes]?: DsInput[K] } & { [K in keyof DsInput & keyof DsInputAttributes as `attr:${K}`]?: DsInputAttributes[K] } & { [K in keyof DsInput & keyof DsInputAttributes as `prop:${K}`]?: DsInput[K] };
2454
+ "ds-loader": Omit<DsLoader, keyof DsLoaderAttributes> & { [K in keyof DsLoader & keyof DsLoaderAttributes]?: DsLoader[K] } & { [K in keyof DsLoader & keyof DsLoaderAttributes as `attr:${K}`]?: DsLoaderAttributes[K] } & { [K in keyof DsLoader & keyof DsLoaderAttributes as `prop:${K}`]?: DsLoader[K] };
2455
+ "ds-select": Omit<DsSelect, keyof DsSelectAttributes> & { [K in keyof DsSelect & keyof DsSelectAttributes]?: DsSelect[K] } & { [K in keyof DsSelect & keyof DsSelectAttributes as `attr:${K}`]?: DsSelectAttributes[K] } & { [K in keyof DsSelect & keyof DsSelectAttributes as `prop:${K}`]?: DsSelect[K] };
2456
+ "ds-tabs": Omit<DsTabs, keyof DsTabsAttributes> & { [K in keyof DsTabs & keyof DsTabsAttributes]?: DsTabs[K] } & { [K in keyof DsTabs & keyof DsTabsAttributes as `attr:${K}`]?: DsTabsAttributes[K] } & { [K in keyof DsTabs & keyof DsTabsAttributes as `prop:${K}`]?: DsTabs[K] };
2457
+ "ds-textarea": Omit<DsTextarea, keyof DsTextareaAttributes> & { [K in keyof DsTextarea & keyof DsTextareaAttributes]?: DsTextarea[K] } & { [K in keyof DsTextarea & keyof DsTextareaAttributes as `attr:${K}`]?: DsTextareaAttributes[K] } & { [K in keyof DsTextarea & keyof DsTextareaAttributes as `prop:${K}`]?: DsTextarea[K] };
2458
+ "ds-tooltip": Omit<DsTooltip, keyof DsTooltipAttributes> & { [K in keyof DsTooltip & keyof DsTooltipAttributes]?: DsTooltip[K] } & { [K in keyof DsTooltip & keyof DsTooltipAttributes as `attr:${K}`]?: DsTooltipAttributes[K] } & { [K in keyof DsTooltip & keyof DsTooltipAttributes as `prop:${K}`]?: DsTooltip[K] } & OneOf<"label", DsTooltip["label"], DsTooltipAttributes["label"]>;
2459
+ }
2460
+ }
2461
+ export { LocalJSX as JSX };
2462
+ declare module "@stencil/core" {
2463
+ export namespace JSX {
2464
+ interface IntrinsicElements {
2465
+ /**
2466
+ * ## Accessibility
2467
+ * **Category:** static-display
2468
+ * **APG pattern:** N/A — non-interactive text label.
2469
+ * **Keyboard interactions:**
2470
+ * - Tab: N/A — the badge is not focusable and does not appear in tab order.
2471
+ * - Enter: N/A.
2472
+ * - Escape: N/A.
2473
+ * - Arrow keys: N/A.
2474
+ * - Printable characters: N/A.
2475
+ * **ARIA:**
2476
+ * - Roles used: none — renders a plain `<span>` around a `<slot />`. The
2477
+ * `variant` prop is a purely visual axis and MUST NOT be the sole carrier
2478
+ * of information (color/style alone fails WCAG 1.4.1 Use of Color); the
2479
+ * textual content inside the slot must convey the same meaning.
2480
+ * - State attributes: none.
2481
+ * - Labeling strategy: visible text via `<slot />`. Consumers place the
2482
+ * readable label directly inside the tag.
2483
+ * **Focus:**
2484
+ * - On mount: nothing auto-focuses.
2485
+ * - On activate/open: N/A — non-interactive.
2486
+ * - On close/deactivate: N/A.
2487
+ * - Focus indicator: N/A — the host is not focusable. If a consumer wraps
2488
+ * `ds-badge` in an interactive element (e.g. `<button>`, `<a>`), that
2489
+ * wrapper owns the focus indicator via the DS `--ds-color-focus` token
2490
+ * and its own `:focus-visible` rule.
2491
+ * **Motion:**
2492
+ * - Animations: none.
2493
+ * - Reduced-motion behavior: N/A.
2494
+ * **Contrast:**
2495
+ * - Text: inherits `color: inherit` / `currentColor` from the host page and
2496
+ * the variant-specific style; not verified in isolation here. Consumers
2497
+ * are responsible for confirming ≥ 4.5:1 (WCAG 1.4.3) against the surface
2498
+ * the badge is placed on.
2499
+ * - Non-text: no state-conveying icons or borders that need the 3:1
2500
+ * non-text contrast threshold.
2501
+ * **Screen reader announcement:**
2502
+ * - Rendered state: announces the slot text as inline content within its
2503
+ * surrounding context (no role means AT reads it as plain text). The
2504
+ * `variant` value is not announced — that is intentional; the label text
2505
+ * is the source of truth for meaning.
2506
+ * - State change: N/A — no dynamic state owned by this component.
2507
+ */
2508
+ "ds-badge": LocalJSX.IntrinsicElements["ds-badge"] & JSXBase.HTMLAttributes<HTMLDsBadgeElement>;
2509
+ /**
2510
+ * ## Accessibility
2511
+ * **Category:** interactive-display
2512
+ * **APG pattern:** Button — https://www.w3.org/WAI/ARIA/apg/patterns/button/
2513
+ * (satisfied natively by the underlying `<button>` element). When `href` is
2514
+ * set, the component renders `<a href>` instead — a link, not a button — and
2515
+ * that surface follows native `<a>` semantics rather than the Button pattern.
2516
+ * **Keyboard interactions:**
2517
+ * - Tab: moves focus to the internal `<button>` or `<a>` (shadow DOM does not
2518
+ * interrupt tab order).
2519
+ * - Enter: activates (fires click on `<button>`, navigates on `<a>`).
2520
+ * - Space: activates the `<button>` variant only (native behavior); on the
2521
+ * `<a>` variant Space scrolls the page as usual.
2522
+ * - Escape: N/A — no dismissible state owned by this component.
2523
+ * - Arrow keys: N/A.
2524
+ * - Printable characters: N/A.
2525
+ * **ARIA:**
2526
+ * - Roles used: none explicit — the native `<button>` / `<a href>` supplies
2527
+ * the implicit `button` / `link` role.
2528
+ * - State attributes: `disabled` (native attribute on `<button>`, not
2529
+ * `aria-disabled`). The `<a>` variant does not accept `disabled` — a
2530
+ * disabled navigation is a spec smell (see spec §"Button vs Link"); if a
2531
+ * link needs a disabled state, model it as a `<button>` action instead.
2532
+ * - Labeling strategy: visible text via `<slot />`. Consumers MUST place
2533
+ * readable text (or a labeled icon) inside the tag. An empty slot leaves
2534
+ * the button/link without an accessible name and fails
2535
+ * `button-name` / `link-name` axe rules. Icon-only usage is out of contract
2536
+ * for `ds-button`; use a future `ds-icon-button` with a required
2537
+ * `aria-label` prop when that lands.
2538
+ * **Focus:**
2539
+ * - On mount: nothing auto-focuses.
2540
+ * - On activate: focus stays on the element (native click behavior; the
2541
+ * component does not move focus on its own).
2542
+ * - On close/deactivate: N/A.
2543
+ * - Focus indicator: 2px `outline` in `var(--ds-color-focus)` with 2px
2544
+ * `outline-offset`, applied via `:focus-visible` — replaces the browser
2545
+ * default so both `<button>` and `<a>` variants use the same DS ring
2546
+ * (spec universal rule 3, WCAG 1.4.11 non-text contrast ≥ 3:1).
2547
+ * **Motion:**
2548
+ * - Animations: 150ms `background-color` ease-in-out transition on
2549
+ * `primary`/`secondary` variants (hover).
2550
+ * - Reduced-motion behavior: N/A — 150ms is below the spec's 200ms threshold
2551
+ * for `prefers-reduced-motion` handling, and the transition animates color
2552
+ * only (no motion of position, scale, or opacity).
2553
+ * **Contrast:**
2554
+ * - Text: `primary` and `secondary` variants pair `--ds-color-{primary,secondary}`
2555
+ * with `--ds-color-text-on-{primary,secondary}` — the token pairs are
2556
+ * authored to meet WCAG 2.1 AA (≥ 4.5:1). The `ghost` variant inherits
2557
+ * `color: inherit` and pins `opacity: 0.85`, so its effective contrast
2558
+ * depends on the consumer's surface — verify per site.
2559
+ * - Non-text (border on `ghost`): 1px `currentColor`; contrast tracks the
2560
+ * text color 1:1, subject to the same host-page caveat.
2561
+ * **Screen reader announcement:**
2562
+ * - Rendered state: announces the slot text followed by "button" (or "link"
2563
+ * for the `href` variant), plus "dimmed" / "unavailable" when `disabled`
2564
+ * is set (browser/AT dependent wording).
2565
+ * - State change: N/A — this component does not own toggle state. A pressed
2566
+ * toggle needs `aria-pressed`, which is out of scope here; model that as
2567
+ * a distinct component or extend the API deliberately per the spec.
2568
+ */
2569
+ "ds-button": LocalJSX.IntrinsicElements["ds-button"] & JSXBase.HTMLAttributes<HTMLDsButtonElement>;
2570
+ /**
2571
+ * ## Accessibility
2572
+ * **Category:** static-display
2573
+ * **APG pattern:** N/A — a container surface with no interactive
2574
+ * behavior of its own. If a consumer nests interactive elements
2575
+ * inside (button, link, form field), those elements satisfy their
2576
+ * own a11y bucket independently.
2577
+ * **Keyboard interactions:**
2578
+ * - Tab / Shift+Tab: N/A — the card itself is not focusable. Any
2579
+ * interactive descendant carries its own tab semantics.
2580
+ * - Enter / Space / Arrow / Escape / Printable: N/A.
2581
+ * **ARIA:**
2582
+ * - Roles used: none. `<ds-card>` is a purely visual grouping and
2583
+ * deliberately does not carry `role="region"` — that would demand
2584
+ * a labelledby target, which would only be correct in a subset of
2585
+ * uses. Consumers that need a labeled landmark should render a
2586
+ * `<section aria-labelledby>` around the card.
2587
+ * - State attributes: none.
2588
+ * - Labeling strategy: none applied by the component; consumer's
2589
+ * heading structure inside the slot supplies the accessible name
2590
+ * when needed.
2591
+ * **Focus:**
2592
+ * - On mount: nothing auto-focuses.
2593
+ * - Focus indicator: N/A — the card itself is not focusable.
2594
+ * **Motion:**
2595
+ * - Animations: none.
2596
+ * - Reduced-motion behavior: N/A.
2597
+ * **Contrast:**
2598
+ * - Text: inherits `color: inherit` / `currentColor`; the card does
2599
+ * not impose a text color, so contrast is the consumer theme's
2600
+ * responsibility.
2601
+ * - Non-text (border, subtle background tint): both derived from
2602
+ * `color-mix(in oklch, currentColor N%, transparent)`, matching
2603
+ * the pattern used by `ds-input` and `ds-select`. WCAG 1.4.11
2604
+ * (3:1 non-text contrast) is met in themes where the surface has
2605
+ * enough delta against the page background; the component does
2606
+ * not override the consumer's palette to force it.
2607
+ * **Screen reader announcement:**
2608
+ * - Rendered state: no announcement of the card itself. AT
2609
+ * navigates to the slotted content directly, using whatever
2610
+ * heading and landmark structure the consumer places inside.
2611
+ * - State change: N/A.
2612
+ */
2613
+ "ds-card": LocalJSX.IntrinsicElements["ds-card"] & JSXBase.HTMLAttributes<HTMLDsCardElement>;
2614
+ /**
2615
+ * ## Accessibility
2616
+ * **Category:** form-field
2617
+ * **APG pattern:** N/A — native element. This wraps a native
2618
+ * `<input type="checkbox">`; the browser already implements the
2619
+ * checkbox role and its state semantics. Reference:
2620
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox
2621
+ * Note: `ds-checkbox` intentionally does NOT reach for the WAI-ARIA
2622
+ * APG "tri-state checkbox" pattern (indeterminate + on + off) as a
2623
+ * scratch-built ARIA widget. The native input already exposes the
2624
+ * `indeterminate` DOM property and browsers report it to AT
2625
+ * correctly; the `indeterminate` prop here forwards to that DOM
2626
+ * property so the native mechanism carries the semantics.
2627
+ * **Keyboard interactions:**
2628
+ * - Tab: moves focus to the native `<input type="checkbox">`.
2629
+ * - Space: toggles the checked state (native behavior).
2630
+ * - Enter: no native effect on a checkbox (unlike button). Form
2631
+ * submission triggered by Enter comes from the enclosing form's
2632
+ * default submit button, not from the checkbox itself.
2633
+ * **ARIA:**
2634
+ * - Roles used: none explicit — the native checkbox supplies the
2635
+ * implicit `checkbox` role.
2636
+ * - State attributes: `checked` (DOM property, kept in sync via
2637
+ * componentDidRender because Stencil does not JSX-forward the
2638
+ * attribute cleanly for controlled use), `disabled` (native
2639
+ * attribute, not `aria-disabled`), `aria-invalid` (from the
2640
+ * `invalid` prop), `aria-required` (from the `required` prop),
2641
+ * `aria-describedby` (from the `describedBy` prop).
2642
+ * - Labeling strategy: `aria-label` set from the `label` prop onto
2643
+ * the internal checkbox. This is the **canonical, recommended**
2644
+ * mode. Wrapping the host in a light-DOM `<label>` also produces
2645
+ * an accessible name in Chromium via flattened-tree resolution —
2646
+ * same secondary mode documented on `ds-input`.
2647
+ * **Focus:**
2648
+ * - On mount: nothing auto-focuses.
2649
+ * - On toggle: focus remains on the native checkbox.
2650
+ * - Focus indicator: browser default `:focus-visible` ring, kept on
2651
+ * purpose until the DS ships a themed focus utility using
2652
+ * `--ds-color-focus`. Not overridden by `ds-checkbox.css`.
2653
+ * **Motion:**
2654
+ * - Animations: none.
2655
+ * - Reduced-motion behavior: N/A.
2656
+ * **Contrast:**
2657
+ * - Text: N/A — the checkbox itself renders no text (labels are
2658
+ * supplied by the consumer via `label` prop or wrapping <label>).
2659
+ * - Non-text (the box and its check glyph): browser default rendering
2660
+ * is kept on purpose (no `appearance: none` override); this
2661
+ * preserves the OS/browser accessibility rendering that AT and
2662
+ * forced-color modes rely on. A themed override is a future
2663
+ * decision once the DS commits to a checkbox visual language that
2664
+ * still passes 3:1 non-text contrast in every theme.
2665
+ * **Screen reader announcement:**
2666
+ * - Rendered state: announces the `label` prop text as the
2667
+ * accessible name, followed by "checkbox", followed by "checked"
2668
+ * / "not checked" / "mixed" per the current DOM state.
2669
+ * - State change: on toggle, AT announces the new state (native
2670
+ * behavior); no `aria-live` added.
2671
+ * **Consumer contract:**
2672
+ * - `checked` is the source of truth for controlled use. Reading
2673
+ * `event.detail` from `dsChange` gives the new state; the internal
2674
+ * input is kept in sync via a Watch + a re-sync in componentDidRender.
2675
+ * - `indeterminate` is a visual/AT state, not a value — it is NOT
2676
+ * submitted with a form and clears on the next user toggle.
2677
+ */
2678
+ "ds-checkbox": LocalJSX.IntrinsicElements["ds-checkbox"] & JSXBase.HTMLAttributes<HTMLDsCheckboxElement>;
2679
+ /**
2680
+ * ## Accessibility
2681
+ * **Category:** interactive-display
2682
+ * **APG pattern:** Button — https://www.w3.org/WAI/ARIA/apg/patterns/button/
2683
+ * (for the internal copy control; the code readout itself is static text).
2684
+ * **Keyboard interactions:**
2685
+ * - Tab: moves focus into the internal copy `<button>`; the code readout
2686
+ * (`<pre><code>`) is not focusable itself, but its container is
2687
+ * horizontally scrollable and remains reachable via the browser's caret
2688
+ * browsing / find-in-page path.
2689
+ * - Enter: activates the copy button (writes `code` to the clipboard).
2690
+ * - Space: activates the copy button (native `<button>` behavior).
2691
+ * - Escape: N/A — the "Copied" state auto-clears after 1.4s; no dismissible
2692
+ * modal state.
2693
+ * - Arrow keys: N/A.
2694
+ * - Printable characters: N/A.
2695
+ * **ARIA:**
2696
+ * - Roles used: none explicit — the native `<button>` supplies the implicit
2697
+ * `button` role; `<pre>` and `<code>` supply their semantic roles.
2698
+ * - State attributes: none. The `copied` flag lives only in the button's
2699
+ * accessible name (see below); it is intentionally not surfaced via
2700
+ * `aria-pressed` because it is not a toggle — it is a transient
2701
+ * post-action confirmation.
2702
+ * - Labeling strategy: `aria-label` on the copy button — "Copy code" in the
2703
+ * resting state, "Copied" while the confirmation is visible. This is
2704
+ * authoritative because the button carries both an icon and the words
2705
+ * "Copy" / "Copied", and mixed icon+text needs an explicit accessible
2706
+ * name to avoid AT reading the SVG as a separate node.
2707
+ * **Focus:**
2708
+ * - On mount: nothing auto-focuses.
2709
+ * - On activate: focus stays on the copy button (clipboard write is
2710
+ * synchronous from the user's perspective; no focus is moved).
2711
+ * - On close/deactivate: N/A — no popup or overlay to close.
2712
+ * - Focus indicator: 2px `outline` in `var(--ds-color-focus)` with 2px
2713
+ * `outline-offset`, applied to `.ds-code-block__copy:focus-visible`. The
2714
+ * readout itself is not focusable and has no focus indicator by design.
2715
+ * **Motion:**
2716
+ * - Animations: 120ms `color` / `border-color` ease transition on the copy
2717
+ * button (hover/focus).
2718
+ * - Reduced-motion behavior: N/A — 120ms is below the spec's 200ms
2719
+ * threshold, and the transition animates color only.
2720
+ * **Contrast:**
2721
+ * - Text (code readout): inherits `color: currentColor`; contrast depends
2722
+ * on the host page's text color vs. the block's tinted background
2723
+ * (`color-mix(currentColor 4%, transparent)`). Verify per site.
2724
+ * - Text (copy button): `color-mix(in oklch, currentColor 70%, transparent)`
2725
+ * at rest, `currentColor` on hover. The 70%-mixed resting color can drop
2726
+ * below 4.5:1 on low-contrast surfaces — audit per usage site, and lean
2727
+ * on the hover/focus states (both restore full `currentColor`) as the
2728
+ * accessible fallback.
2729
+ * - Non-text (button border, language tag border-bottom): both use
2730
+ * `color-mix(currentColor <15|12>%, transparent)` — decorative separators,
2731
+ * they do not convey state, so the 3:1 non-text contrast rule does not
2732
+ * apply. Focus and hover borders shift up to 30% for clearer edges.
2733
+ * **Screen reader announcement:**
2734
+ * - Rendered state: announces "Copy code, button" (the `aria-label`), then
2735
+ * the code content when the user navigates into the `<pre><code>` block
2736
+ * (usually announced as a code block on VoiceOver).
2737
+ * - State change: after clicking Copy, the button's `aria-label` flips to
2738
+ * "Copied"; AT will announce this on the next focus or re-read of the
2739
+ * button, but NOT proactively — there is no `aria-live` region. This is
2740
+ * deliberate per spec §"What we explicitly do NOT do" (avoid live-region
2741
+ * overuse), and the trade-off is that a screen-reader-only user does not
2742
+ * get an unsolicited confirmation. If a future review decides that
2743
+ * confirmation must be audible, add a visually-hidden
2744
+ * `aria-live="polite"` element whose text toggles on `copied`.
2745
+ */
2746
+ "ds-code-block": LocalJSX.IntrinsicElements["ds-code-block"] & JSXBase.HTMLAttributes<HTMLDsCodeBlockElement>;
2747
+ /**
2748
+ * ## Accessibility
2749
+ * **Category:** state-machine
2750
+ * **APG pattern:** https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
2751
+ * This component wraps the **native `<dialog>` element** rather than
2752
+ * scratch-building the APG pattern on top of a `<div role="dialog">`.
2753
+ * `<dialog>` opened via `showModal()` gives us — from the browser,
2754
+ * verified by the platform, not by us:
2755
+ * - Focus trap: Tab / Shift+Tab cycle only through focusable
2756
+ * descendants (including slotted light-DOM descendants; the flattened
2757
+ * accessibility tree is what the trap operates on).
2758
+ * - Escape: closes the dialog and returns focus to the previously
2759
+ * focused element (native, not implemented here).
2760
+ * - Inert background: everything outside the dialog is inert while it
2761
+ * is open — no mouse, no keyboard, not part of the a11y tree.
2762
+ * - Return focus: on close, focus returns to whatever element had it
2763
+ * before `showModal()` — native, not implemented here.
2764
+ * - Initial focus: browser auto-focuses the first `autofocus` element
2765
+ * inside, or the first focusable if none — native.
2766
+ * - `role="dialog"` and `aria-modal="true"` semantics: implicit on
2767
+ * `<dialog>`, no ARIA needed from us.
2768
+ * This is the deliberate answer to the a11y spec §D warning about
2769
+ * scratch-building Tier 2 components: the native element removes the
2770
+ * "compiles, axe passes, screen-reader user gets trapped" failure
2771
+ * mode by delegating the state machine to the platform.
2772
+ * **Keyboard interactions (all handled by the native element unless
2773
+ * noted otherwise):**
2774
+ * - Tab: cycles focus within the dialog's focusable descendants
2775
+ * (native focus trap).
2776
+ * - Shift+Tab: reverse cycle (native).
2777
+ * - Escape: closes the dialog and fires the `close` event (native).
2778
+ * Consumers who need to prevent dismissal on Escape (destructive
2779
+ * flows: e.g. an unsaved-changes guard) must call
2780
+ * `event.preventDefault()` inside their own `keydown` listener on
2781
+ * the dialog before it reaches the browser — that is an escape
2782
+ * hatch, not a default we impose.
2783
+ * - Enter / Space: no special dialog behavior; forwarded to
2784
+ * whatever descendant has focus (a button will activate).
2785
+ * - Home / End / Arrow keys: no special dialog behavior; forwarded
2786
+ * to descendants.
2787
+ * - Printable characters: forwarded to descendants (e.g. typing
2788
+ * inside a slotted `<ds-input>`).
2789
+ * **ARIA attributes and value triggers:**
2790
+ * - Implicit `role="dialog"` on the native `<dialog>`.
2791
+ * - Implicit `aria-modal="true"` when opened via `showModal()`
2792
+ * (which is what this component always uses; `show()` — the
2793
+ * non-modal form — is intentionally not exposed in v1).
2794
+ * - `aria-label` set from the `label` prop onto the `<dialog>`.
2795
+ * Consumers who prefer an in-content title can pass a
2796
+ * `labelledBy` prop instead, whose value is the id of a heading
2797
+ * element they render inside the slot — `aria-labelledby`
2798
+ * resolves that id through the flattened tree.
2799
+ * - `aria-describedby` from the `describedBy` prop, resolving a
2800
+ * light-DOM id of a descriptive block (e.g. the dialog body copy
2801
+ * when the label is short).
2802
+ * **Focus lifecycle:**
2803
+ * - Opening: `showModal()` moves focus to the first `autofocus`
2804
+ * element inside, or the first focusable if none. Consumers who
2805
+ * want a specific initial focus target should mark that element
2806
+ * with `autofocus`.
2807
+ * - While open: focus is trapped within the flattened tree of the
2808
+ * `<dialog>`; Tab / Shift+Tab cycle through slotted descendants.
2809
+ * Focus cannot escape into the inert background.
2810
+ * - Closing: `close()` (either from Escape, from a form-submit with
2811
+ * `method="dialog"`, from a light-dismiss backdrop click handler
2812
+ * the consumer wires up, or from `open=false`) returns focus to
2813
+ * the element that had it immediately before `showModal()` was
2814
+ * called. The `dsClose` event fires after focus has been restored.
2815
+ * **ARIA labelling contract (choose one):**
2816
+ * - **`label`** (string) — sets `aria-label` on the dialog. Simplest
2817
+ * for short titles.
2818
+ * - **`labelledBy`** (id) — sets `aria-labelledby` to reference a
2819
+ * heading rendered inside the slot. Preferred when the dialog has
2820
+ * a visible title so the accessible name matches the visible name.
2821
+ * If both are omitted, axe reports `dialog-name` — the dialog has no
2822
+ * accessible name. The a11y test for this component asserts that at
2823
+ * least one of the two is provided.
2824
+ * **Motion:**
2825
+ * - Animations: none applied by the component. Consumers who want an
2826
+ * entrance transition can style `::backdrop` and `dialog[open]`
2827
+ * with their own animation, gated on `@media
2828
+ * (prefers-reduced-motion: no-preference)`.
2829
+ * - Reduced-motion behavior: N/A — no animation to collapse. If a
2830
+ * consumer adds one, they own the reduced-motion fallback.
2831
+ * **Contrast:**
2832
+ * - Text: inherits `color: inherit`; consumer theme owns contrast.
2833
+ * - Non-text: subtle bordered surface via
2834
+ * `color-mix(in oklch, currentColor N%, transparent)` matching
2835
+ * `ds-card`. Backdrop is a semi-transparent black by default.
2836
+ * **Screen reader announcement:**
2837
+ * - Rendered state (closed): dialog is not in the a11y tree.
2838
+ * - Opened: AT announces "dialog" plus the accessible name from
2839
+ * `label` / `labelledBy`, then reads the content following focus
2840
+ * (or the descriptive block referenced by `describedBy` first,
2841
+ * depending on AT).
2842
+ * - State change: on close, AT returns to the element that regained
2843
+ * focus (the trigger); no `aria-live` announcement is added.
2844
+ * **Consumer contract:**
2845
+ * - Set `open` to true to show; set to false to close. The component
2846
+ * syncs the DOM state via `showModal()` / `close()` in a Watch.
2847
+ * - Listen to `dsClose` to know when the dialog was dismissed (by
2848
+ * Escape, by `open=false`, or by a form submit with
2849
+ * `method="dialog"`). Listen to `dsOpen` for the mirror event.
2850
+ * - The default backdrop is opaque and NOT click-to-dismiss. Consumers
2851
+ * who want light-dismiss can add a click listener on the dialog
2852
+ * that closes when the click target is the dialog itself (not a
2853
+ * descendant): `if (e.target === dialog) dialog.close()`.
2854
+ * - Put focus targets (form fields, primary action button) inside
2855
+ * the slot. Use `autofocus` on the element that should receive
2856
+ * focus first.
2857
+ * **Pending manual verification (see commit message TODO):**
2858
+ * - VoiceOver on macOS: confirm the dialog announces its accessible
2859
+ * name + "dialog" on open, focus lands on the correct element,
2860
+ * Escape closes and focus returns to the trigger.
2861
+ * - Chromium high-contrast / forced-colors: confirm the surface
2862
+ * still reads as a bordered container with the native ::backdrop
2863
+ * dim.
2864
+ */
2865
+ "ds-dialog": LocalJSX.IntrinsicElements["ds-dialog"] & JSXBase.HTMLAttributes<HTMLDsDialogElement>;
2866
+ /**
2867
+ * ## Accessibility
2868
+ * **Category:** form-field
2869
+ * **APG pattern:** N/A — native element. This wraps a native `<input>`;
2870
+ * there is no WAI-ARIA APG pattern for a plain text input because the
2871
+ * browser already implements it natively. Reference:
2872
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
2873
+ * **Keyboard interactions:**
2874
+ * - Tab: moves focus to the native `<input>` (shadow DOM does not
2875
+ * interrupt tab order).
2876
+ * - Printable characters: insert at the caret position (native).
2877
+ * - Backspace / Delete: native editing.
2878
+ * - Arrow keys: move the caret within the value (native); for
2879
+ * `type="number"` Up/Down step the numeric value (native).
2880
+ * - Enter: on `type="search"` may submit the enclosing form (native);
2881
+ * no custom handling.
2882
+ * - Escape: no native meaning for a text input.
2883
+ * **ARIA:**
2884
+ * - Roles used: none explicit — the native `<input>` supplies its
2885
+ * implicit role (`textbox`, `searchbox`, etc. depending on `type`).
2886
+ * - State attributes: `disabled` (native attribute, not `aria-disabled`),
2887
+ * `aria-invalid` (from the `invalid` prop), `aria-required` (from the
2888
+ * `required` prop), `aria-describedby` (from the `describedBy` prop,
2889
+ * expected to reference a light-DOM node id — typically a hint or
2890
+ * error message rendered by the consumer alongside the field).
2891
+ * - Labeling strategy: `aria-label` set from the `label` prop onto the
2892
+ * internal `<input>`. This is the **canonical, recommended** mode —
2893
+ * explicit and independent of DOM structure. Consumers MUST pass
2894
+ * `label` (or otherwise give the field an accessible name) — an
2895
+ * `<input>` with no accessible name is a WCAG failure (axe rule
2896
+ * `label`). Wrapping the host in a light-DOM `<label>` (e.g.
2897
+ * `<label>Email <ds-input></ds-input></label>`) also produces an
2898
+ * accessible name in Chromium via flattened-tree resolution — the
2899
+ * same secondary mode documented on `ds-select`, verified in this
2900
+ * component's e2e tests. Setting `aria-label` directly on the
2901
+ * `<ds-input>` host does NOT work: shadow-DOM attribute forwarding
2902
+ * would be required — use the `label` prop instead.
2903
+ * **Focus:**
2904
+ * - On mount: nothing auto-focuses.
2905
+ * - On value change: focus remains on the native `<input>`.
2906
+ * - Focus indicator: the browser default `:focus-visible` ring is kept
2907
+ * on purpose — a themed focus ring using `--ds-color-focus` is a
2908
+ * future decision once the DS ships a shared focus utility. Not
2909
+ * overridden by `ds-input.css`.
2910
+ * **Motion:**
2911
+ * - Animations: none.
2912
+ * - Reduced-motion behavior: N/A — no animation to collapse.
2913
+ * **Contrast:**
2914
+ * - Text: inherits `color: inherit` / `currentColor`; ratio depends on
2915
+ * the consumer's theme, not verified in isolation here.
2916
+ * - Border: `color-mix(in oklch, currentColor 22%, transparent)`,
2917
+ * matching `ds-select` — inherits whatever contrast the host page
2918
+ * sets. WCAG 1.4.11 (3:1 non-text) is the consumer's responsibility
2919
+ * in themes that override the surface.
2920
+ * **Screen reader announcement:**
2921
+ * - Rendered state: announces the `label` prop text as the accessible
2922
+ * name, followed by the browser/AT's role announcement for the
2923
+ * input type ("edit text", "search text", "password", "phone
2924
+ * number", "email"…). When `required=true` the announcement
2925
+ * includes "required"; when `invalid=true` it includes "invalid".
2926
+ * - State change: on value edit, AT typically echoes the typed
2927
+ * character (native input behavior); no `aria-live` added, per the
2928
+ * spec's guidance against live-region overuse.
2929
+ * **Consumer contract:**
2930
+ * - `placeholder` is a hint, not a label. It disappears on focus in
2931
+ * most browsers and is not reliably announced by every AT — always
2932
+ * pair with `label`.
2933
+ * - For `type="password"` in a real form, pair with a light-DOM
2934
+ * `<input type="hidden">` or a form-associated ancestor that gives
2935
+ * the browser's password manager an `autocomplete` hint. This
2936
+ * component intentionally does not expose `autocomplete` in v1;
2937
+ * consumers that need it can render a native `<input>` for that
2938
+ * field until the prop is added.
2939
+ * - When `invalid=true`, pair with a `describedBy` id that points at
2940
+ * a visible error message; `aria-invalid` alone gives the AT the
2941
+ * status but not the reason.
2942
+ */
2943
+ "ds-input": LocalJSX.IntrinsicElements["ds-input"] & JSXBase.HTMLAttributes<HTMLDsInputElement>;
2944
+ /**
2945
+ * ## Accessibility
2946
+ * **Category:** static-display (indeterminate progress indicator)
2947
+ * **APG pattern:** N/A — the loader is a passive presence indicator, not a
2948
+ * `progressbar` (no measurable value). Uses `role="status"` per WAI-ARIA
2949
+ * live-region semantics for indeterminate loading states.
2950
+ * **Keyboard interactions:**
2951
+ * - Tab: N/A — not focusable.
2952
+ * - Enter: N/A.
2953
+ * - Escape: N/A.
2954
+ * - Arrow keys: N/A.
2955
+ * - Printable characters: N/A.
2956
+ * **ARIA:**
2957
+ * - Roles used: `role="status"` on the host — an implicit polite live
2958
+ * region ARIA lists as valid for "advisory information" including
2959
+ * in-progress operations. The inner `<svg>` is decorative and carries
2960
+ * `aria-hidden="true"` + `focusable="false"` so it never becomes a
2961
+ * parallel target for screen readers.
2962
+ * - State attributes: none. The loader has no state changes to announce
2963
+ * beyond its own presence; the polite live region on mount is the
2964
+ * announcement.
2965
+ * - Labeling strategy: `aria-label` from the `label` prop (default
2966
+ * "Loading"). Consumers pass a more specific string when the context
2967
+ * warrants ("Loading ceremonies", "Signing in", …).
2968
+ * **Focus:**
2969
+ * - On mount: nothing auto-focuses.
2970
+ * - On activate/open: N/A — not interactive.
2971
+ * - On close/deactivate: N/A.
2972
+ * - Focus indicator: N/A — the host is not focusable.
2973
+ * **Motion:**
2974
+ * - Animations: two mirrored halves of the logo path oscillate
2975
+ * symmetrically around the visual center, meeting at the ring midpoint
2976
+ * and separating again. Cycle 1.4s by default (`speed="normal"`);
2977
+ * `speed="slow"` = 2.2s, `speed="fast"` = 0.9s.
2978
+ * - Reduced-motion behavior: `@media (prefers-reduced-motion: reduce)`
2979
+ * collapses both halves to a static rendering with a slow opacity
2980
+ * pulse (2s ease-in-out). No rotation, no lateral movement.
2981
+ * **Contrast:**
2982
+ * - Text: N/A — the visible surface is the SVG stroke, not text.
2983
+ * - Non-text: stroke inherits `currentColor` from the host. Consumers are
2984
+ * responsible for confirming the stroke against its background meets
2985
+ * the ≥ 3:1 non-text contrast threshold (WCAG 1.4.11) where the loader
2986
+ * conveys state (e.g. distinguishing "still loading" from "idle").
2987
+ * **Screen reader announcement:**
2988
+ * - Rendered state: the polite live region announces the label
2989
+ * (e.g. "Loading") when the loader mounts.
2990
+ * - State change: N/A — the loader itself has no state that changes.
2991
+ * Consumers unmount the loader when the awaited work completes; that
2992
+ * removal is silent, which is the intended behavior (the arriving
2993
+ * content is the announcement).
2994
+ */
2995
+ "ds-loader": LocalJSX.IntrinsicElements["ds-loader"] & JSXBase.HTMLAttributes<HTMLDsLoaderElement>;
2996
+ "ds-select": LocalJSX.IntrinsicElements["ds-select"] & JSXBase.HTMLAttributes<HTMLDsSelectElement>;
2997
+ "ds-tabs": LocalJSX.IntrinsicElements["ds-tabs"] & JSXBase.HTMLAttributes<HTMLDsTabsElement>;
2998
+ /**
2999
+ * ## Accessibility
3000
+ * **Category:** form-field
3001
+ * **APG pattern:** N/A — native element. This wraps a native
3002
+ * `<textarea>`; there is no WAI-ARIA APG pattern for a plain
3003
+ * multi-line text field because the browser already implements it
3004
+ * natively. Reference:
3005
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea
3006
+ * **Keyboard interactions:**
3007
+ * - Tab: moves focus to the native `<textarea>`; Tab inside the
3008
+ * textarea inserts a tab character only when the browser is
3009
+ * configured to do so (default behavior: Tab moves focus out).
3010
+ * - Printable characters: insert at the caret position (native).
3011
+ * - Enter: inserts a newline within the value (native), does not
3012
+ * submit the enclosing form (unlike a single-line input).
3013
+ * - Backspace / Delete: native editing.
3014
+ * - Arrow keys: move the caret within the value (native).
3015
+ * - Escape: no native meaning for a text area.
3016
+ * **ARIA:**
3017
+ * - Roles used: none explicit — the native `<textarea>` supplies
3018
+ * the implicit `textbox` role with multiline behavior.
3019
+ * - State attributes: `disabled` (native attribute, not
3020
+ * `aria-disabled`), `aria-invalid` (from the `invalid` prop),
3021
+ * `aria-required` (from the `required` prop), `aria-describedby`
3022
+ * (from the `describedBy` prop, expected to reference a light-DOM
3023
+ * node id — typically a hint or error message rendered by the
3024
+ * consumer alongside the field).
3025
+ * - Labeling strategy: `aria-label` set from the `label` prop onto
3026
+ * the internal `<textarea>`. This is the **canonical, recommended**
3027
+ * mode. Wrapping the host in a light-DOM `<label>` also produces
3028
+ * an accessible name in Chromium via flattened-tree resolution —
3029
+ * same secondary mode documented on `ds-input` and `ds-select`,
3030
+ * verified in this component's e2e tests. Setting `aria-label`
3031
+ * directly on the `<ds-textarea>` host does NOT work: shadow-DOM
3032
+ * attribute forwarding would be required — use the `label` prop.
3033
+ * **Focus:**
3034
+ * - On mount: nothing auto-focuses.
3035
+ * - On value change: focus remains on the native `<textarea>`.
3036
+ * - Focus indicator: the browser default `:focus-visible` ring is
3037
+ * kept on purpose — a themed focus ring using `--ds-color-focus`
3038
+ * is a future decision once the DS ships a shared focus utility.
3039
+ * **Motion:**
3040
+ * - Animations: none.
3041
+ * - Reduced-motion behavior: N/A — no animation to collapse.
3042
+ * **Contrast:**
3043
+ * - Text: inherits `color: inherit` / `currentColor`; ratio depends
3044
+ * on the consumer's theme, not verified in isolation.
3045
+ * - Border: `color-mix(in oklch, currentColor 22%, transparent)`,
3046
+ * matching `ds-input`.
3047
+ * **Screen reader announcement:**
3048
+ * - Rendered state: announces the `label` prop text as the
3049
+ * accessible name, followed by "edit text, multiline" (browser/AT
3050
+ * wording varies). When `required=true` the announcement includes
3051
+ * "required"; when `invalid=true` it includes "invalid".
3052
+ * - State change: on value edit, AT typically echoes the typed
3053
+ * character (native behavior); no `aria-live` added.
3054
+ * **Consumer contract:**
3055
+ * - `placeholder` is a hint, not a label — always pair with `label`.
3056
+ * - When `invalid=true`, pair with a `describedBy` id that points at
3057
+ * a visible error message; `aria-invalid` alone gives the AT the
3058
+ * status but not the reason.
3059
+ * - `rows` sets the initial visible line count. Vertical resize is
3060
+ * left to the native default (`resize: vertical`) so users can
3061
+ * grow the field for long entries; the consumer's CSS can pin it
3062
+ * with `resize: none` when a fixed height matters.
3063
+ */
3064
+ "ds-textarea": LocalJSX.IntrinsicElements["ds-textarea"] & JSXBase.HTMLAttributes<HTMLDsTextareaElement>;
3065
+ "ds-tooltip": LocalJSX.IntrinsicElements["ds-tooltip"] & JSXBase.HTMLAttributes<HTMLDsTooltipElement>;
3066
+ }
3067
+ }
3068
+ }