@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,339 @@
1
+ import { h, Host, } from "@stencil/core";
2
+ /**
3
+ * ## Accessibility
4
+ *
5
+ * **Category:** form-field
6
+ * **APG pattern:** N/A — native element. This wraps a native
7
+ * `<input type="checkbox">`; the browser already implements the
8
+ * checkbox role and its state semantics. Reference:
9
+ * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox
10
+ *
11
+ * Note: `ds-checkbox` intentionally does NOT reach for the WAI-ARIA
12
+ * APG "tri-state checkbox" pattern (indeterminate + on + off) as a
13
+ * scratch-built ARIA widget. The native input already exposes the
14
+ * `indeterminate` DOM property and browsers report it to AT
15
+ * correctly; the `indeterminate` prop here forwards to that DOM
16
+ * property so the native mechanism carries the semantics.
17
+ *
18
+ * **Keyboard interactions:**
19
+ * - Tab: moves focus to the native `<input type="checkbox">`.
20
+ * - Space: toggles the checked state (native behavior).
21
+ * - Enter: no native effect on a checkbox (unlike button). Form
22
+ * submission triggered by Enter comes from the enclosing form's
23
+ * default submit button, not from the checkbox itself.
24
+ *
25
+ * **ARIA:**
26
+ * - Roles used: none explicit — the native checkbox supplies the
27
+ * implicit `checkbox` role.
28
+ * - State attributes: `checked` (DOM property, kept in sync via
29
+ * componentDidRender because Stencil does not JSX-forward the
30
+ * attribute cleanly for controlled use), `disabled` (native
31
+ * attribute, not `aria-disabled`), `aria-invalid` (from the
32
+ * `invalid` prop), `aria-required` (from the `required` prop),
33
+ * `aria-describedby` (from the `describedBy` prop).
34
+ * - Labeling strategy: `aria-label` set from the `label` prop onto
35
+ * the internal checkbox. This is the **canonical, recommended**
36
+ * mode. Wrapping the host in a light-DOM `<label>` also produces
37
+ * an accessible name in Chromium via flattened-tree resolution —
38
+ * same secondary mode documented on `ds-input`.
39
+ *
40
+ * **Focus:**
41
+ * - On mount: nothing auto-focuses.
42
+ * - On toggle: focus remains on the native checkbox.
43
+ * - Focus indicator: browser default `:focus-visible` ring, kept on
44
+ * purpose until the DS ships a themed focus utility using
45
+ * `--ds-color-focus`. Not overridden by `ds-checkbox.css`.
46
+ *
47
+ * **Motion:**
48
+ * - Animations: none.
49
+ * - Reduced-motion behavior: N/A.
50
+ *
51
+ * **Contrast:**
52
+ * - Text: N/A — the checkbox itself renders no text (labels are
53
+ * supplied by the consumer via `label` prop or wrapping <label>).
54
+ * - Non-text (the box and its check glyph): browser default rendering
55
+ * is kept on purpose (no `appearance: none` override); this
56
+ * preserves the OS/browser accessibility rendering that AT and
57
+ * forced-color modes rely on. A themed override is a future
58
+ * decision once the DS commits to a checkbox visual language that
59
+ * still passes 3:1 non-text contrast in every theme.
60
+ *
61
+ * **Screen reader announcement:**
62
+ * - Rendered state: announces the `label` prop text as the
63
+ * accessible name, followed by "checkbox", followed by "checked"
64
+ * / "not checked" / "mixed" per the current DOM state.
65
+ * - State change: on toggle, AT announces the new state (native
66
+ * behavior); no `aria-live` added.
67
+ *
68
+ * **Consumer contract:**
69
+ * - `checked` is the source of truth for controlled use. Reading
70
+ * `event.detail` from `dsChange` gives the new state; the internal
71
+ * input is kept in sync via a Watch + a re-sync in componentDidRender.
72
+ * - `indeterminate` is a visual/AT state, not a value — it is NOT
73
+ * submitted with a form and clears on the next user toggle.
74
+ */
75
+ export class DsCheckbox {
76
+ inputEl;
77
+ checked = false;
78
+ indeterminate = false;
79
+ name;
80
+ value;
81
+ disabled = false;
82
+ required = false;
83
+ invalid = false;
84
+ describedBy;
85
+ label;
86
+ dsChange;
87
+ watchChecked(newValue) {
88
+ if (this.inputEl && this.inputEl.checked !== newValue) {
89
+ this.inputEl.checked = newValue;
90
+ }
91
+ }
92
+ watchIndeterminate(newValue) {
93
+ if (this.inputEl && this.inputEl.indeterminate !== newValue) {
94
+ this.inputEl.indeterminate = newValue;
95
+ }
96
+ }
97
+ componentDidLoad() {
98
+ this.syncNativeState();
99
+ }
100
+ componentDidUpdate() {
101
+ this.syncNativeState();
102
+ }
103
+ syncNativeState() {
104
+ if (!this.inputEl)
105
+ return;
106
+ if (this.inputEl.checked !== this.checked) {
107
+ this.inputEl.checked = this.checked;
108
+ }
109
+ if (this.inputEl.indeterminate !== this.indeterminate) {
110
+ this.inputEl.indeterminate = this.indeterminate;
111
+ }
112
+ }
113
+ onChange = (event) => {
114
+ const target = event.target;
115
+ this.dsChange.emit(target.checked);
116
+ };
117
+ render() {
118
+ return (h(Host, { key: 'a935a67c0f4fa5d6cb36c2338d761318344573ef' }, h("input", { key: '4664d7a5a2fbce7987bbaf25b50355ddfc1be97f', class: "ds-checkbox", type: "checkbox", name: this.name, value: this.value, disabled: this.disabled, "aria-label": this.label, "aria-required": this.required ? "true" : undefined, "aria-invalid": this.invalid ? "true" : undefined, "aria-describedby": this.describedBy, ref: (el) => (this.inputEl = el), onChange: this.onChange })));
119
+ }
120
+ static get is() { return "ds-checkbox"; }
121
+ static get encapsulation() { return "shadow"; }
122
+ static get originalStyleUrls() {
123
+ return {
124
+ "$": ["ds-checkbox.css"]
125
+ };
126
+ }
127
+ static get styleUrls() {
128
+ return {
129
+ "$": ["ds-checkbox.css"]
130
+ };
131
+ }
132
+ static get properties() {
133
+ return {
134
+ "checked": {
135
+ "type": "boolean",
136
+ "mutable": false,
137
+ "complexType": {
138
+ "original": "boolean",
139
+ "resolved": "boolean",
140
+ "references": {}
141
+ },
142
+ "required": false,
143
+ "optional": false,
144
+ "docs": {
145
+ "tags": [],
146
+ "text": ""
147
+ },
148
+ "getter": false,
149
+ "setter": false,
150
+ "reflect": false,
151
+ "attribute": "checked",
152
+ "defaultValue": "false"
153
+ },
154
+ "indeterminate": {
155
+ "type": "boolean",
156
+ "mutable": false,
157
+ "complexType": {
158
+ "original": "boolean",
159
+ "resolved": "boolean",
160
+ "references": {}
161
+ },
162
+ "required": false,
163
+ "optional": false,
164
+ "docs": {
165
+ "tags": [],
166
+ "text": ""
167
+ },
168
+ "getter": false,
169
+ "setter": false,
170
+ "reflect": false,
171
+ "attribute": "indeterminate",
172
+ "defaultValue": "false"
173
+ },
174
+ "name": {
175
+ "type": "string",
176
+ "mutable": false,
177
+ "complexType": {
178
+ "original": "string",
179
+ "resolved": "string | undefined",
180
+ "references": {}
181
+ },
182
+ "required": false,
183
+ "optional": true,
184
+ "docs": {
185
+ "tags": [],
186
+ "text": ""
187
+ },
188
+ "getter": false,
189
+ "setter": false,
190
+ "reflect": false,
191
+ "attribute": "name"
192
+ },
193
+ "value": {
194
+ "type": "string",
195
+ "mutable": false,
196
+ "complexType": {
197
+ "original": "string",
198
+ "resolved": "string | undefined",
199
+ "references": {}
200
+ },
201
+ "required": false,
202
+ "optional": true,
203
+ "docs": {
204
+ "tags": [],
205
+ "text": ""
206
+ },
207
+ "getter": false,
208
+ "setter": false,
209
+ "reflect": false,
210
+ "attribute": "value"
211
+ },
212
+ "disabled": {
213
+ "type": "boolean",
214
+ "mutable": false,
215
+ "complexType": {
216
+ "original": "boolean",
217
+ "resolved": "boolean",
218
+ "references": {}
219
+ },
220
+ "required": false,
221
+ "optional": false,
222
+ "docs": {
223
+ "tags": [],
224
+ "text": ""
225
+ },
226
+ "getter": false,
227
+ "setter": false,
228
+ "reflect": false,
229
+ "attribute": "disabled",
230
+ "defaultValue": "false"
231
+ },
232
+ "required": {
233
+ "type": "boolean",
234
+ "mutable": false,
235
+ "complexType": {
236
+ "original": "boolean",
237
+ "resolved": "boolean",
238
+ "references": {}
239
+ },
240
+ "required": false,
241
+ "optional": false,
242
+ "docs": {
243
+ "tags": [],
244
+ "text": ""
245
+ },
246
+ "getter": false,
247
+ "setter": false,
248
+ "reflect": false,
249
+ "attribute": "required",
250
+ "defaultValue": "false"
251
+ },
252
+ "invalid": {
253
+ "type": "boolean",
254
+ "mutable": false,
255
+ "complexType": {
256
+ "original": "boolean",
257
+ "resolved": "boolean",
258
+ "references": {}
259
+ },
260
+ "required": false,
261
+ "optional": false,
262
+ "docs": {
263
+ "tags": [],
264
+ "text": ""
265
+ },
266
+ "getter": false,
267
+ "setter": false,
268
+ "reflect": false,
269
+ "attribute": "invalid",
270
+ "defaultValue": "false"
271
+ },
272
+ "describedBy": {
273
+ "type": "string",
274
+ "mutable": false,
275
+ "complexType": {
276
+ "original": "string",
277
+ "resolved": "string | undefined",
278
+ "references": {}
279
+ },
280
+ "required": false,
281
+ "optional": true,
282
+ "docs": {
283
+ "tags": [],
284
+ "text": ""
285
+ },
286
+ "getter": false,
287
+ "setter": false,
288
+ "reflect": false,
289
+ "attribute": "described-by"
290
+ },
291
+ "label": {
292
+ "type": "string",
293
+ "mutable": false,
294
+ "complexType": {
295
+ "original": "string",
296
+ "resolved": "string | undefined",
297
+ "references": {}
298
+ },
299
+ "required": false,
300
+ "optional": true,
301
+ "docs": {
302
+ "tags": [],
303
+ "text": ""
304
+ },
305
+ "getter": false,
306
+ "setter": false,
307
+ "reflect": false,
308
+ "attribute": "label"
309
+ }
310
+ };
311
+ }
312
+ static get events() {
313
+ return [{
314
+ "method": "dsChange",
315
+ "name": "dsChange",
316
+ "bubbles": true,
317
+ "cancelable": true,
318
+ "composed": true,
319
+ "docs": {
320
+ "tags": [],
321
+ "text": ""
322
+ },
323
+ "complexType": {
324
+ "original": "boolean",
325
+ "resolved": "boolean",
326
+ "references": {}
327
+ }
328
+ }];
329
+ }
330
+ static get watchers() {
331
+ return [{
332
+ "propName": "checked",
333
+ "methodName": "watchChecked"
334
+ }, {
335
+ "propName": "indeterminate",
336
+ "methodName": "watchIndeterminate"
337
+ }];
338
+ }
339
+ }
@@ -0,0 +1,65 @@
1
+ :host {
2
+ display: block;
3
+ }
4
+
5
+ .ds-code-block {
6
+ border: 1px solid var(--ds-code-block-border, currentColor);
7
+ border-color: color-mix(in oklch, currentColor 15%, transparent);
8
+ background: var(--ds-code-block-bg, color-mix(in oklch, currentColor 4%, transparent));
9
+ border-radius: 10px;
10
+ overflow: hidden;
11
+ font-family: var(--ds-font-family);
12
+ font-size: 13px;
13
+ }
14
+
15
+ .ds-code-block__header {
16
+ display: flex;
17
+ align-items: center;
18
+ justify-content: space-between;
19
+ padding: 8px 12px;
20
+ border-bottom: 1px solid color-mix(in oklch, currentColor 12%, transparent);
21
+ color: color-mix(in oklch, currentColor 55%, transparent);
22
+ }
23
+
24
+ .ds-code-block__lang {
25
+ font-size: 11px;
26
+ text-transform: uppercase;
27
+ letter-spacing: 0.06em;
28
+ }
29
+
30
+ .ds-code-block__copy {
31
+ background: transparent;
32
+ border: 1px solid color-mix(in oklch, currentColor 15%, transparent);
33
+ color: color-mix(in oklch, currentColor 70%, transparent);
34
+ padding: 4px 8px;
35
+ border-radius: 6px;
36
+ font: inherit;
37
+ font-size: 12px;
38
+ cursor: pointer;
39
+ display: inline-flex;
40
+ align-items: center;
41
+ gap: 6px;
42
+ transition: color 120ms ease, border-color 120ms ease;
43
+ }
44
+
45
+ .ds-code-block__copy:hover {
46
+ color: currentColor;
47
+ border-color: color-mix(in oklch, currentColor 30%, transparent);
48
+ }
49
+
50
+ .ds-code-block__copy:focus-visible {
51
+ outline: 2px solid var(--ds-color-focus);
52
+ outline-offset: 2px;
53
+ }
54
+
55
+ pre {
56
+ margin: 0;
57
+ padding: 16px;
58
+ overflow-x: auto;
59
+ }
60
+
61
+ code {
62
+ font-family: inherit;
63
+ color: currentColor;
64
+ white-space: pre;
65
+ }
@@ -0,0 +1,162 @@
1
+ import { h, Host } from "@stencil/core";
2
+ /**
3
+ * ## Accessibility
4
+ *
5
+ * **Category:** interactive-display
6
+ * **APG pattern:** Button — https://www.w3.org/WAI/ARIA/apg/patterns/button/
7
+ * (for the internal copy control; the code readout itself is static text).
8
+ *
9
+ * **Keyboard interactions:**
10
+ * - Tab: moves focus into the internal copy `<button>`; the code readout
11
+ * (`<pre><code>`) is not focusable itself, but its container is
12
+ * horizontally scrollable and remains reachable via the browser's caret
13
+ * browsing / find-in-page path.
14
+ * - Enter: activates the copy button (writes `code` to the clipboard).
15
+ * - Space: activates the copy button (native `<button>` behavior).
16
+ * - Escape: N/A — the "Copied" state auto-clears after 1.4s; no dismissible
17
+ * modal state.
18
+ * - Arrow keys: N/A.
19
+ * - Printable characters: N/A.
20
+ *
21
+ * **ARIA:**
22
+ * - Roles used: none explicit — the native `<button>` supplies the implicit
23
+ * `button` role; `<pre>` and `<code>` supply their semantic roles.
24
+ * - State attributes: none. The `copied` flag lives only in the button's
25
+ * accessible name (see below); it is intentionally not surfaced via
26
+ * `aria-pressed` because it is not a toggle — it is a transient
27
+ * post-action confirmation.
28
+ * - Labeling strategy: `aria-label` on the copy button — "Copy code" in the
29
+ * resting state, "Copied" while the confirmation is visible. This is
30
+ * authoritative because the button carries both an icon and the words
31
+ * "Copy" / "Copied", and mixed icon+text needs an explicit accessible
32
+ * name to avoid AT reading the SVG as a separate node.
33
+ *
34
+ * **Focus:**
35
+ * - On mount: nothing auto-focuses.
36
+ * - On activate: focus stays on the copy button (clipboard write is
37
+ * synchronous from the user's perspective; no focus is moved).
38
+ * - On close/deactivate: N/A — no popup or overlay to close.
39
+ * - Focus indicator: 2px `outline` in `var(--ds-color-focus)` with 2px
40
+ * `outline-offset`, applied to `.ds-code-block__copy:focus-visible`. The
41
+ * readout itself is not focusable and has no focus indicator by design.
42
+ *
43
+ * **Motion:**
44
+ * - Animations: 120ms `color` / `border-color` ease transition on the copy
45
+ * button (hover/focus).
46
+ * - Reduced-motion behavior: N/A — 120ms is below the spec's 200ms
47
+ * threshold, and the transition animates color only.
48
+ *
49
+ * **Contrast:**
50
+ * - Text (code readout): inherits `color: currentColor`; contrast depends
51
+ * on the host page's text color vs. the block's tinted background
52
+ * (`color-mix(currentColor 4%, transparent)`). Verify per site.
53
+ * - Text (copy button): `color-mix(in oklch, currentColor 70%, transparent)`
54
+ * at rest, `currentColor` on hover. The 70%-mixed resting color can drop
55
+ * below 4.5:1 on low-contrast surfaces — audit per usage site, and lean
56
+ * on the hover/focus states (both restore full `currentColor`) as the
57
+ * accessible fallback.
58
+ * - Non-text (button border, language tag border-bottom): both use
59
+ * `color-mix(currentColor <15|12>%, transparent)` — decorative separators,
60
+ * they do not convey state, so the 3:1 non-text contrast rule does not
61
+ * apply. Focus and hover borders shift up to 30% for clearer edges.
62
+ *
63
+ * **Screen reader announcement:**
64
+ * - Rendered state: announces "Copy code, button" (the `aria-label`), then
65
+ * the code content when the user navigates into the `<pre><code>` block
66
+ * (usually announced as a code block on VoiceOver).
67
+ * - State change: after clicking Copy, the button's `aria-label` flips to
68
+ * "Copied"; AT will announce this on the next focus or re-read of the
69
+ * button, but NOT proactively — there is no `aria-live` region. This is
70
+ * deliberate per spec §"What we explicitly do NOT do" (avoid live-region
71
+ * overuse), and the trade-off is that a screen-reader-only user does not
72
+ * get an unsolicited confirmation. If a future review decides that
73
+ * confirmation must be audible, add a visually-hidden
74
+ * `aria-live="polite"` element whose text toggles on `copied`.
75
+ */
76
+ export class DsCodeBlock {
77
+ code;
78
+ language = "bash";
79
+ copied = false;
80
+ timer;
81
+ disconnectedCallback() {
82
+ if (this.timer !== undefined)
83
+ window.clearTimeout(this.timer);
84
+ }
85
+ async onCopy() {
86
+ try {
87
+ await navigator.clipboard.writeText(this.code);
88
+ this.copied = true;
89
+ if (this.timer !== undefined)
90
+ window.clearTimeout(this.timer);
91
+ this.timer = window.setTimeout(() => {
92
+ this.copied = false;
93
+ }, 1400);
94
+ }
95
+ catch {
96
+ // Clipboard permissions may be denied; leave state unchanged.
97
+ }
98
+ }
99
+ render() {
100
+ return (h(Host, { key: '27b2c85bb8cf97c4b176c175f818bd077cfaa3f3' }, h("div", { key: '0f08c5d94ce947207d02692bfd733e9d90ca8b59', class: "ds-code-block" }, h("div", { key: '66dcbf8c59d1ecb4c373b5c1daad583f7e7a05ad', class: "ds-code-block__header" }, h("span", { key: 'fddc6fc3943ffcfafc68bf56d84859cfd016dea9', class: "ds-code-block__lang" }, this.language), h("button", { key: '277ef9eee0a8d9aa3ac54a75b11074315f26fa5e', type: "button", class: "ds-code-block__copy", onClick: () => this.onCopy(), "aria-label": this.copied ? "Copied" : "Copy code" }, this.copied ? (h("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "1.6", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polyline", { points: "20 6 9 17 4 12" }))) : (h("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "1.6", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }), h("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" }))), h("span", { key: '81e87579225b696300fd2f2b8035553a55d3c7f0' }, this.copied ? "Copied" : "Copy"))), h("pre", { key: '06dc49a58e9fd80b0d334a349ef1ad9f540d37d7' }, h("code", { key: 'ba689fa980819ee4c12e9d5382d80d21919c8100' }, this.code)))));
101
+ }
102
+ static get is() { return "ds-code-block"; }
103
+ static get encapsulation() { return "shadow"; }
104
+ static get originalStyleUrls() {
105
+ return {
106
+ "$": ["ds-code-block.css"]
107
+ };
108
+ }
109
+ static get styleUrls() {
110
+ return {
111
+ "$": ["ds-code-block.css"]
112
+ };
113
+ }
114
+ static get properties() {
115
+ return {
116
+ "code": {
117
+ "type": "string",
118
+ "mutable": false,
119
+ "complexType": {
120
+ "original": "string",
121
+ "resolved": "string",
122
+ "references": {}
123
+ },
124
+ "required": true,
125
+ "optional": false,
126
+ "docs": {
127
+ "tags": [],
128
+ "text": ""
129
+ },
130
+ "getter": false,
131
+ "setter": false,
132
+ "reflect": false,
133
+ "attribute": "code"
134
+ },
135
+ "language": {
136
+ "type": "string",
137
+ "mutable": false,
138
+ "complexType": {
139
+ "original": "string",
140
+ "resolved": "string",
141
+ "references": {}
142
+ },
143
+ "required": false,
144
+ "optional": false,
145
+ "docs": {
146
+ "tags": [],
147
+ "text": ""
148
+ },
149
+ "getter": false,
150
+ "setter": false,
151
+ "reflect": false,
152
+ "attribute": "language",
153
+ "defaultValue": "\"bash\""
154
+ }
155
+ };
156
+ }
157
+ static get states() {
158
+ return {
159
+ "copied": {}
160
+ };
161
+ }
162
+ }
@@ -0,0 +1,30 @@
1
+ :host {
2
+ display: contents;
3
+ }
4
+
5
+ .ds-dialog {
6
+ color: inherit;
7
+ background-color: color-mix(in oklch, currentColor 4%, Canvas);
8
+ border: 1px solid color-mix(in oklch, currentColor 15%, transparent);
9
+ border-radius: var(--ds-radius-md);
10
+ padding: var(--ds-spacing-xl);
11
+ box-sizing: border-box;
12
+ /*
13
+ * Default the dialog to a comfortable maximum width without pinning
14
+ * it, so short content sits centered and long content wraps. Consumers
15
+ * override via ::part or their own selectors as needed.
16
+ */
17
+ max-width: min(90vw, 32rem);
18
+ max-height: 90vh;
19
+ overflow: auto;
20
+ }
21
+
22
+ .ds-dialog::backdrop {
23
+ /*
24
+ * Neutral dim. Deliberately not using currentColor here — currentColor
25
+ * inside ::backdrop resolves against the pseudo-element itself, not
26
+ * the dialog, and would collapse to black. The rgba() literal keeps
27
+ * the dim readable in both light and dark themes.
28
+ */
29
+ background-color: rgba(0, 0, 0, 0.5);
30
+ }