@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.
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/dist/chiralkit-ds/chiralkit-ds.css +1 -0
- package/dist/chiralkit-ds/chiralkit-ds.esm.js +1 -0
- package/dist/chiralkit-ds/index.esm.js +1 -0
- package/dist/chiralkit-ds/p-038fa008.entry.js +1 -0
- package/dist/chiralkit-ds/p-2fdc1012.entry.js +1 -0
- package/dist/chiralkit-ds/p-306ec33b.entry.js +1 -0
- package/dist/chiralkit-ds/p-3f704698.entry.js +1 -0
- package/dist/chiralkit-ds/p-41081d22.entry.js +1 -0
- package/dist/chiralkit-ds/p-7d7e5aac.entry.js +1 -0
- package/dist/chiralkit-ds/p-84b801f8.entry.js +1 -0
- package/dist/chiralkit-ds/p-a28c71b4.entry.js +1 -0
- package/dist/chiralkit-ds/p-be84312f.entry.js +1 -0
- package/dist/chiralkit-ds/p-c8015fe6.entry.js +1 -0
- package/dist/chiralkit-ds/p-d36a6bea.entry.js +1 -0
- package/dist/chiralkit-ds/p-e-glNjK6.js +2 -0
- package/dist/chiralkit-ds/p-f0f9ff61.entry.js +1 -0
- package/dist/cjs/chiralkit-ds.cjs.js +24 -0
- package/dist/cjs/ds-badge.cjs.entry.js +18 -0
- package/dist/cjs/ds-button.cjs.entry.js +26 -0
- package/dist/cjs/ds-card.cjs.entry.js +17 -0
- package/dist/cjs/ds-checkbox.cjs.entry.js +67 -0
- package/dist/cjs/ds-code-block.cjs.entry.js +39 -0
- package/dist/cjs/ds-dialog.cjs.entry.js +67 -0
- package/dist/cjs/ds-input.cjs.entry.js +50 -0
- package/dist/cjs/ds-loader.cjs.entry.js +26 -0
- package/dist/cjs/ds-select.cjs.entry.js +85 -0
- package/dist/cjs/ds-tabs.cjs.entry.js +138 -0
- package/dist/cjs/ds-textarea.cjs.entry.js +50 -0
- package/dist/cjs/ds-tooltip.cjs.entry.js +233 -0
- package/dist/cjs/index-mMvyq7U_.js +2018 -0
- package/dist/cjs/index.cjs.js +10 -0
- package/dist/cjs/loader.cjs.js +12 -0
- package/dist/collection/collection-manifest.json +24 -0
- package/dist/collection/components/ds-badge/ds-badge.css +36 -0
- package/dist/collection/components/ds-badge/ds-badge.js +93 -0
- package/dist/collection/components/ds-button/ds-button.css +66 -0
- package/dist/collection/components/ds-button/ds-button.js +197 -0
- package/dist/collection/components/ds-card/ds-card.css +12 -0
- package/dist/collection/components/ds-card/ds-card.js +68 -0
- package/dist/collection/components/ds-checkbox/ds-checkbox.css +22 -0
- package/dist/collection/components/ds-checkbox/ds-checkbox.js +339 -0
- package/dist/collection/components/ds-code-block/ds-code-block.css +65 -0
- package/dist/collection/components/ds-code-block/ds-code-block.js +162 -0
- package/dist/collection/components/ds-dialog/ds-dialog.css +30 -0
- package/dist/collection/components/ds-dialog/ds-dialog.js +313 -0
- package/dist/collection/components/ds-input/ds-input.css +38 -0
- package/dist/collection/components/ds-input/ds-input.js +353 -0
- package/dist/collection/components/ds-loader/ds-loader.css +94 -0
- package/dist/collection/components/ds-loader/ds-loader.js +149 -0
- package/dist/collection/components/ds-select/ds-select.css +69 -0
- package/dist/collection/components/ds-select/ds-select.js +235 -0
- package/dist/collection/components/ds-tabs/ds-tabs.css +59 -0
- package/dist/collection/components/ds-tabs/ds-tabs.js +248 -0
- package/dist/collection/components/ds-textarea/ds-textarea.css +41 -0
- package/dist/collection/components/ds-textarea/ds-textarea.js +342 -0
- package/dist/collection/components/ds-tooltip/ds-tooltip.css +31 -0
- package/dist/collection/components/ds-tooltip/ds-tooltip.js +318 -0
- package/dist/collection/components.js +2 -0
- package/dist/collection/index.js +1 -0
- package/dist/components/ds-badge.d.ts +11 -0
- package/dist/components/ds-badge.js +1 -0
- package/dist/components/ds-button.d.ts +11 -0
- package/dist/components/ds-button.js +1 -0
- package/dist/components/ds-card.d.ts +11 -0
- package/dist/components/ds-card.js +1 -0
- package/dist/components/ds-checkbox.d.ts +11 -0
- package/dist/components/ds-checkbox.js +1 -0
- package/dist/components/ds-code-block.d.ts +11 -0
- package/dist/components/ds-code-block.js +1 -0
- package/dist/components/ds-dialog.d.ts +11 -0
- package/dist/components/ds-dialog.js +1 -0
- package/dist/components/ds-input.d.ts +11 -0
- package/dist/components/ds-input.js +1 -0
- package/dist/components/ds-loader.d.ts +11 -0
- package/dist/components/ds-loader.js +1 -0
- package/dist/components/ds-select.d.ts +11 -0
- package/dist/components/ds-select.js +1 -0
- package/dist/components/ds-tabs.d.ts +11 -0
- package/dist/components/ds-tabs.js +1 -0
- package/dist/components/ds-textarea.d.ts +11 -0
- package/dist/components/ds-textarea.js +1 -0
- package/dist/components/ds-tooltip.d.ts +11 -0
- package/dist/components/ds-tooltip.js +1 -0
- package/dist/components/index.d.ts +35 -0
- package/dist/components/index.js +1 -0
- package/dist/components/p-DDUZow8F.js +1 -0
- package/dist/components/p-ZsYP0VBq.js +1 -0
- package/dist/components/p-k0ywxWpC.js +1 -0
- package/dist/esm/chiralkit-ds.js +20 -0
- package/dist/esm/ds-badge.entry.js +16 -0
- package/dist/esm/ds-button.entry.js +24 -0
- package/dist/esm/ds-card.entry.js +15 -0
- package/dist/esm/ds-checkbox.entry.js +65 -0
- package/dist/esm/ds-code-block.entry.js +37 -0
- package/dist/esm/ds-dialog.entry.js +65 -0
- package/dist/esm/ds-input.entry.js +48 -0
- package/dist/esm/ds-loader.entry.js +24 -0
- package/dist/esm/ds-select.entry.js +83 -0
- package/dist/esm/ds-tabs.entry.js +136 -0
- package/dist/esm/ds-textarea.entry.js +48 -0
- package/dist/esm/ds-tooltip.entry.js +231 -0
- package/dist/esm/index-e-glNjK6.js +2008 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/loader.js +10 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/layouts/app-shell.css +84 -0
- package/dist/tests/a11y.js +55 -0
- package/dist/types/Users/alex/projects/MyGitHub/chiralkit/packages/design-system/.stencil/tests/a11y.d.ts +17 -0
- package/dist/types/components/ds-badge/ds-badge.d.ts +54 -0
- package/dist/types/components/ds-button/ds-button.d.ts +75 -0
- package/dist/types/components/ds-card/ds-card.d.ts +53 -0
- package/dist/types/components/ds-checkbox/ds-checkbox.d.ts +94 -0
- package/dist/types/components/ds-code-block/ds-code-block.d.ts +83 -0
- package/dist/types/components/ds-dialog/ds-dialog.d.ts +148 -0
- package/dist/types/components/ds-input/ds-input.d.ts +104 -0
- package/dist/types/components/ds-loader/ds-loader.d.ts +64 -0
- package/dist/types/components/ds-select/ds-select.d.ts +123 -0
- package/dist/types/components/ds-tabs/ds-tabs.d.ts +155 -0
- package/dist/types/components/ds-textarea/ds-textarea.d.ts +93 -0
- package/dist/types/components/ds-tooltip/ds-tooltip.d.ts +26 -0
- package/dist/types/components.d.ts +3068 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/stencil-public-runtime.d.ts +1861 -0
- package/docs.json +2112 -0
- package/loader/cdn.js +1 -0
- package/loader/index.cjs.js +1 -0
- package/loader/index.d.ts +24 -0
- package/loader/index.es2017.js +1 -0
- package/loader/index.js +2 -0
- package/package.json +78 -0
- package/react/components/ds-badge.tsx +25 -0
- package/react/components/ds-button.tsx +25 -0
- package/react/components/ds-card.tsx +25 -0
- package/react/components/ds-checkbox.tsx +25 -0
- package/react/components/ds-code-block.tsx +25 -0
- package/react/components/ds-dialog.tsx +31 -0
- package/react/components/ds-input.tsx +25 -0
- package/react/components/ds-loader.tsx +25 -0
- package/react/components/ds-select.tsx +25 -0
- package/react/components/ds-tabs.tsx +25 -0
- package/react/components/ds-textarea.tsx +25 -0
- package/react/components/ds-tooltip.tsx +25 -0
- 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
|
+
}
|