@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,313 @@
1
+ import { h, Host, } from "@stencil/core";
2
+ /**
3
+ * ## Accessibility
4
+ *
5
+ * **Category:** state-machine
6
+ * **APG pattern:** https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
7
+ *
8
+ * This component wraps the **native `<dialog>` element** rather than
9
+ * scratch-building the APG pattern on top of a `<div role="dialog">`.
10
+ * `<dialog>` opened via `showModal()` gives us — from the browser,
11
+ * verified by the platform, not by us:
12
+ *
13
+ * - Focus trap: Tab / Shift+Tab cycle only through focusable
14
+ * descendants (including slotted light-DOM descendants; the flattened
15
+ * accessibility tree is what the trap operates on).
16
+ * - Escape: closes the dialog and returns focus to the previously
17
+ * focused element (native, not implemented here).
18
+ * - Inert background: everything outside the dialog is inert while it
19
+ * is open — no mouse, no keyboard, not part of the a11y tree.
20
+ * - Return focus: on close, focus returns to whatever element had it
21
+ * before `showModal()` — native, not implemented here.
22
+ * - Initial focus: browser auto-focuses the first `autofocus` element
23
+ * inside, or the first focusable if none — native.
24
+ * - `role="dialog"` and `aria-modal="true"` semantics: implicit on
25
+ * `<dialog>`, no ARIA needed from us.
26
+ *
27
+ * This is the deliberate answer to the a11y spec §D warning about
28
+ * scratch-building Tier 2 components: the native element removes the
29
+ * "compiles, axe passes, screen-reader user gets trapped" failure
30
+ * mode by delegating the state machine to the platform.
31
+ *
32
+ * **Keyboard interactions (all handled by the native element unless
33
+ * noted otherwise):**
34
+ * - Tab: cycles focus within the dialog's focusable descendants
35
+ * (native focus trap).
36
+ * - Shift+Tab: reverse cycle (native).
37
+ * - Escape: closes the dialog and fires the `close` event (native).
38
+ * Consumers who need to prevent dismissal on Escape (destructive
39
+ * flows: e.g. an unsaved-changes guard) must call
40
+ * `event.preventDefault()` inside their own `keydown` listener on
41
+ * the dialog before it reaches the browser — that is an escape
42
+ * hatch, not a default we impose.
43
+ * - Enter / Space: no special dialog behavior; forwarded to
44
+ * whatever descendant has focus (a button will activate).
45
+ * - Home / End / Arrow keys: no special dialog behavior; forwarded
46
+ * to descendants.
47
+ * - Printable characters: forwarded to descendants (e.g. typing
48
+ * inside a slotted `<ds-input>`).
49
+ *
50
+ * **ARIA attributes and value triggers:**
51
+ * - Implicit `role="dialog"` on the native `<dialog>`.
52
+ * - Implicit `aria-modal="true"` when opened via `showModal()`
53
+ * (which is what this component always uses; `show()` — the
54
+ * non-modal form — is intentionally not exposed in v1).
55
+ * - `aria-label` set from the `label` prop onto the `<dialog>`.
56
+ * Consumers who prefer an in-content title can pass a
57
+ * `labelledBy` prop instead, whose value is the id of a heading
58
+ * element they render inside the slot — `aria-labelledby`
59
+ * resolves that id through the flattened tree.
60
+ * - `aria-describedby` from the `describedBy` prop, resolving a
61
+ * light-DOM id of a descriptive block (e.g. the dialog body copy
62
+ * when the label is short).
63
+ *
64
+ * **Focus lifecycle:**
65
+ * - Opening: `showModal()` moves focus to the first `autofocus`
66
+ * element inside, or the first focusable if none. Consumers who
67
+ * want a specific initial focus target should mark that element
68
+ * with `autofocus`.
69
+ * - While open: focus is trapped within the flattened tree of the
70
+ * `<dialog>`; Tab / Shift+Tab cycle through slotted descendants.
71
+ * Focus cannot escape into the inert background.
72
+ * - Closing: `close()` (either from Escape, from a form-submit with
73
+ * `method="dialog"`, from a light-dismiss backdrop click handler
74
+ * the consumer wires up, or from `open=false`) returns focus to
75
+ * the element that had it immediately before `showModal()` was
76
+ * called. The `dsClose` event fires after focus has been restored.
77
+ *
78
+ * **ARIA labelling contract (choose one):**
79
+ * - **`label`** (string) — sets `aria-label` on the dialog. Simplest
80
+ * for short titles.
81
+ * - **`labelledBy`** (id) — sets `aria-labelledby` to reference a
82
+ * heading rendered inside the slot. Preferred when the dialog has
83
+ * a visible title so the accessible name matches the visible name.
84
+ *
85
+ * If both are omitted, axe reports `dialog-name` — the dialog has no
86
+ * accessible name. The a11y test for this component asserts that at
87
+ * least one of the two is provided.
88
+ *
89
+ * **Motion:**
90
+ * - Animations: none applied by the component. Consumers who want an
91
+ * entrance transition can style `::backdrop` and `dialog[open]`
92
+ * with their own animation, gated on `@media
93
+ * (prefers-reduced-motion: no-preference)`.
94
+ * - Reduced-motion behavior: N/A — no animation to collapse. If a
95
+ * consumer adds one, they own the reduced-motion fallback.
96
+ *
97
+ * **Contrast:**
98
+ * - Text: inherits `color: inherit`; consumer theme owns contrast.
99
+ * - Non-text: subtle bordered surface via
100
+ * `color-mix(in oklch, currentColor N%, transparent)` matching
101
+ * `ds-card`. Backdrop is a semi-transparent black by default.
102
+ *
103
+ * **Screen reader announcement:**
104
+ * - Rendered state (closed): dialog is not in the a11y tree.
105
+ * - Opened: AT announces "dialog" plus the accessible name from
106
+ * `label` / `labelledBy`, then reads the content following focus
107
+ * (or the descriptive block referenced by `describedBy` first,
108
+ * depending on AT).
109
+ * - State change: on close, AT returns to the element that regained
110
+ * focus (the trigger); no `aria-live` announcement is added.
111
+ *
112
+ * **Consumer contract:**
113
+ * - Set `open` to true to show; set to false to close. The component
114
+ * syncs the DOM state via `showModal()` / `close()` in a Watch.
115
+ * - Listen to `dsClose` to know when the dialog was dismissed (by
116
+ * Escape, by `open=false`, or by a form submit with
117
+ * `method="dialog"`). Listen to `dsOpen` for the mirror event.
118
+ * - The default backdrop is opaque and NOT click-to-dismiss. Consumers
119
+ * who want light-dismiss can add a click listener on the dialog
120
+ * that closes when the click target is the dialog itself (not a
121
+ * descendant): `if (e.target === dialog) dialog.close()`.
122
+ * - Put focus targets (form fields, primary action button) inside
123
+ * the slot. Use `autofocus` on the element that should receive
124
+ * focus first.
125
+ *
126
+ * **Pending manual verification (see commit message TODO):**
127
+ * - VoiceOver on macOS: confirm the dialog announces its accessible
128
+ * name + "dialog" on open, focus lands on the correct element,
129
+ * Escape closes and focus returns to the trigger.
130
+ * - Chromium high-contrast / forced-colors: confirm the surface
131
+ * still reads as a bordered container with the native ::backdrop
132
+ * dim.
133
+ */
134
+ export class DsDialog {
135
+ dialogEl;
136
+ open = false;
137
+ label;
138
+ labelledBy;
139
+ describedBy;
140
+ dsOpen;
141
+ dsClose;
142
+ watchOpen(newValue) {
143
+ this.syncOpen(newValue);
144
+ }
145
+ componentDidLoad() {
146
+ // The `close` event on the native <dialog> is not composed by
147
+ // default, so it does not bubble out of the shadow root. Wire it
148
+ // here rather than in the JSX so we can re-emit as a Stencil
149
+ // Event that composed-crosses the boundary.
150
+ this.dialogEl?.addEventListener("close", this.onNativeClose);
151
+ if (this.open) {
152
+ this.syncOpen(true);
153
+ }
154
+ }
155
+ disconnectedCallback() {
156
+ this.dialogEl?.removeEventListener("close", this.onNativeClose);
157
+ }
158
+ syncOpen(shouldOpen) {
159
+ if (!this.dialogEl)
160
+ return;
161
+ const isOpen = this.dialogEl.open;
162
+ if (shouldOpen && !isOpen) {
163
+ // showModal() is the modal form — traps focus, adds the ::backdrop,
164
+ // makes background inert. show() (non-modal) is intentionally not
165
+ // exposed in v1.
166
+ this.dialogEl.showModal();
167
+ this.dsOpen.emit();
168
+ }
169
+ else if (!shouldOpen && isOpen) {
170
+ this.dialogEl.close();
171
+ // dsClose is emitted by onNativeClose to also cover Escape /
172
+ // form-submit paths — no need to emit here.
173
+ }
174
+ }
175
+ onNativeClose = () => {
176
+ this.dsClose.emit();
177
+ };
178
+ render() {
179
+ return (h(Host, { key: '8b25b70865ea028c81405f77a4d016348507aae6' }, h("dialog", { key: '0c82754fe4e4ecf68232a93616bbff3621866375', class: "ds-dialog", "aria-label": this.label, "aria-labelledby": this.labelledBy, "aria-describedby": this.describedBy, ref: (el) => (this.dialogEl = el) }, h("slot", { key: '30131eed9eec7db67a407770b5caefe42c78b68a' }))));
180
+ }
181
+ static get is() { return "ds-dialog"; }
182
+ static get encapsulation() { return "shadow"; }
183
+ static get originalStyleUrls() {
184
+ return {
185
+ "$": ["ds-dialog.css"]
186
+ };
187
+ }
188
+ static get styleUrls() {
189
+ return {
190
+ "$": ["ds-dialog.css"]
191
+ };
192
+ }
193
+ static get properties() {
194
+ return {
195
+ "open": {
196
+ "type": "boolean",
197
+ "mutable": false,
198
+ "complexType": {
199
+ "original": "boolean",
200
+ "resolved": "boolean",
201
+ "references": {}
202
+ },
203
+ "required": false,
204
+ "optional": false,
205
+ "docs": {
206
+ "tags": [],
207
+ "text": ""
208
+ },
209
+ "getter": false,
210
+ "setter": false,
211
+ "reflect": false,
212
+ "attribute": "open",
213
+ "defaultValue": "false"
214
+ },
215
+ "label": {
216
+ "type": "string",
217
+ "mutable": false,
218
+ "complexType": {
219
+ "original": "string",
220
+ "resolved": "string | undefined",
221
+ "references": {}
222
+ },
223
+ "required": false,
224
+ "optional": true,
225
+ "docs": {
226
+ "tags": [],
227
+ "text": ""
228
+ },
229
+ "getter": false,
230
+ "setter": false,
231
+ "reflect": false,
232
+ "attribute": "label"
233
+ },
234
+ "labelledBy": {
235
+ "type": "string",
236
+ "mutable": false,
237
+ "complexType": {
238
+ "original": "string",
239
+ "resolved": "string | undefined",
240
+ "references": {}
241
+ },
242
+ "required": false,
243
+ "optional": true,
244
+ "docs": {
245
+ "tags": [],
246
+ "text": ""
247
+ },
248
+ "getter": false,
249
+ "setter": false,
250
+ "reflect": false,
251
+ "attribute": "labelled-by"
252
+ },
253
+ "describedBy": {
254
+ "type": "string",
255
+ "mutable": false,
256
+ "complexType": {
257
+ "original": "string",
258
+ "resolved": "string | undefined",
259
+ "references": {}
260
+ },
261
+ "required": false,
262
+ "optional": true,
263
+ "docs": {
264
+ "tags": [],
265
+ "text": ""
266
+ },
267
+ "getter": false,
268
+ "setter": false,
269
+ "reflect": false,
270
+ "attribute": "described-by"
271
+ }
272
+ };
273
+ }
274
+ static get events() {
275
+ return [{
276
+ "method": "dsOpen",
277
+ "name": "dsOpen",
278
+ "bubbles": true,
279
+ "cancelable": true,
280
+ "composed": true,
281
+ "docs": {
282
+ "tags": [],
283
+ "text": ""
284
+ },
285
+ "complexType": {
286
+ "original": "void",
287
+ "resolved": "void",
288
+ "references": {}
289
+ }
290
+ }, {
291
+ "method": "dsClose",
292
+ "name": "dsClose",
293
+ "bubbles": true,
294
+ "cancelable": true,
295
+ "composed": true,
296
+ "docs": {
297
+ "tags": [],
298
+ "text": ""
299
+ },
300
+ "complexType": {
301
+ "original": "void",
302
+ "resolved": "void",
303
+ "references": {}
304
+ }
305
+ }];
306
+ }
307
+ static get watchers() {
308
+ return [{
309
+ "propName": "open",
310
+ "methodName": "watchOpen"
311
+ }];
312
+ }
313
+ }
@@ -0,0 +1,38 @@
1
+ :host {
2
+ display: inline-block;
3
+ }
4
+
5
+ .ds-input {
6
+ font-family: var(--ds-font-family);
7
+ font-size: var(--ds-font-size-md);
8
+ background-color: transparent;
9
+ color: inherit;
10
+ border: 1px solid color-mix(in oklch, currentColor 22%, transparent);
11
+ -webkit-appearance: none;
12
+ appearance: none;
13
+ box-sizing: border-box;
14
+ width: 100%;
15
+ }
16
+
17
+ .ds-input::placeholder {
18
+ color: color-mix(in oklch, currentColor 45%, transparent);
19
+ }
20
+
21
+ .ds-input:disabled {
22
+ opacity: 0.5;
23
+ cursor: not-allowed;
24
+ }
25
+
26
+ .ds-input[aria-invalid="true"] {
27
+ border-color: color-mix(in oklch, currentColor 55%, transparent);
28
+ }
29
+
30
+ .ds-input--md {
31
+ border-radius: var(--ds-radius-sm);
32
+ padding: var(--ds-spacing-sm) var(--ds-spacing-lg);
33
+ }
34
+
35
+ .ds-input--lg {
36
+ border-radius: var(--ds-radius-md);
37
+ padding: var(--ds-spacing-md) var(--ds-spacing-xl);
38
+ }