@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,235 @@
|
|
|
1
|
+
import { h, Host, } from "@stencil/core";
|
|
2
|
+
export class DsSelect {
|
|
3
|
+
selectEl;
|
|
4
|
+
value;
|
|
5
|
+
name;
|
|
6
|
+
disabled = false;
|
|
7
|
+
size = "md";
|
|
8
|
+
label;
|
|
9
|
+
/**
|
|
10
|
+
* Options rendered inside the internal shadow `<select>`. Accepts either:
|
|
11
|
+
* - a JSON string (SSR-friendly — server-rendered HTML can only set
|
|
12
|
+
* string attributes, and Stencil does not JSON-parse array attributes),
|
|
13
|
+
* e.g. `options='[{"value":"en","label":"EN"}]'`
|
|
14
|
+
* - an array property set from client-side JS,
|
|
15
|
+
* e.g. `el.options = [{ value: 'en', label: 'EN' }]`
|
|
16
|
+
*
|
|
17
|
+
* Malformed JSON fails safe to an empty list rather than throwing, so the
|
|
18
|
+
* component still renders a visible (if empty) select.
|
|
19
|
+
*/
|
|
20
|
+
options = "[]";
|
|
21
|
+
dsChange;
|
|
22
|
+
watchValue(newValue) {
|
|
23
|
+
if (this.selectEl && this.selectEl.value !== newValue) {
|
|
24
|
+
this.selectEl.value = newValue ?? "";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Empty-bodied on purpose: `options` is already a @Prop, so Stencil
|
|
28
|
+
// schedules a re-render on its own whenever it changes — this watcher
|
|
29
|
+
// exists only to document that `options` is reactive. The actual value
|
|
30
|
+
// re-sync happens in componentDidUpdate, once the new <option> elements
|
|
31
|
+
// are actually in the DOM (syncing here, before that render lands, would
|
|
32
|
+
// assign `this.value` against the *old* option list and get dropped).
|
|
33
|
+
watchOptions() { }
|
|
34
|
+
componentDidLoad() {
|
|
35
|
+
this.syncValue();
|
|
36
|
+
}
|
|
37
|
+
componentDidUpdate() {
|
|
38
|
+
this.syncValue();
|
|
39
|
+
}
|
|
40
|
+
syncValue() {
|
|
41
|
+
if (this.selectEl && this.value !== undefined) {
|
|
42
|
+
this.selectEl.value = this.value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
parseOptions() {
|
|
46
|
+
if (typeof this.options === "string") {
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(this.options);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
console.warn("[ds-select] failed to parse options prop:", this.options);
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return this.options;
|
|
56
|
+
}
|
|
57
|
+
onChange = (event) => {
|
|
58
|
+
const value = event.target.value;
|
|
59
|
+
this.dsChange.emit(value);
|
|
60
|
+
};
|
|
61
|
+
render() {
|
|
62
|
+
const cls = `ds-select ds-select--${this.size}`;
|
|
63
|
+
return (h(Host, { key: '9c5755ca98a3a3a1340414de0109133ffb6617c4' }, h("select", { key: '7ac471b32e083e754c398ed22baf8ba993997ee5', class: cls, name: this.name, disabled: this.disabled, "aria-label": this.label, ref: (el) => (this.selectEl = el), onChange: this.onChange }, this.parseOptions().map((o) => (h("option", { value: o.value }, o.label))))));
|
|
64
|
+
}
|
|
65
|
+
static get is() { return "ds-select"; }
|
|
66
|
+
static get encapsulation() { return "shadow"; }
|
|
67
|
+
static get originalStyleUrls() {
|
|
68
|
+
return {
|
|
69
|
+
"$": ["ds-select.css"]
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
static get styleUrls() {
|
|
73
|
+
return {
|
|
74
|
+
"$": ["ds-select.css"]
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
static get properties() {
|
|
78
|
+
return {
|
|
79
|
+
"value": {
|
|
80
|
+
"type": "string",
|
|
81
|
+
"mutable": false,
|
|
82
|
+
"complexType": {
|
|
83
|
+
"original": "string",
|
|
84
|
+
"resolved": "string | undefined",
|
|
85
|
+
"references": {}
|
|
86
|
+
},
|
|
87
|
+
"required": false,
|
|
88
|
+
"optional": true,
|
|
89
|
+
"docs": {
|
|
90
|
+
"tags": [],
|
|
91
|
+
"text": ""
|
|
92
|
+
},
|
|
93
|
+
"getter": false,
|
|
94
|
+
"setter": false,
|
|
95
|
+
"reflect": false,
|
|
96
|
+
"attribute": "value"
|
|
97
|
+
},
|
|
98
|
+
"name": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"mutable": false,
|
|
101
|
+
"complexType": {
|
|
102
|
+
"original": "string",
|
|
103
|
+
"resolved": "string | undefined",
|
|
104
|
+
"references": {}
|
|
105
|
+
},
|
|
106
|
+
"required": false,
|
|
107
|
+
"optional": true,
|
|
108
|
+
"docs": {
|
|
109
|
+
"tags": [],
|
|
110
|
+
"text": ""
|
|
111
|
+
},
|
|
112
|
+
"getter": false,
|
|
113
|
+
"setter": false,
|
|
114
|
+
"reflect": false,
|
|
115
|
+
"attribute": "name"
|
|
116
|
+
},
|
|
117
|
+
"disabled": {
|
|
118
|
+
"type": "boolean",
|
|
119
|
+
"mutable": false,
|
|
120
|
+
"complexType": {
|
|
121
|
+
"original": "boolean",
|
|
122
|
+
"resolved": "boolean",
|
|
123
|
+
"references": {}
|
|
124
|
+
},
|
|
125
|
+
"required": false,
|
|
126
|
+
"optional": false,
|
|
127
|
+
"docs": {
|
|
128
|
+
"tags": [],
|
|
129
|
+
"text": ""
|
|
130
|
+
},
|
|
131
|
+
"getter": false,
|
|
132
|
+
"setter": false,
|
|
133
|
+
"reflect": false,
|
|
134
|
+
"attribute": "disabled",
|
|
135
|
+
"defaultValue": "false"
|
|
136
|
+
},
|
|
137
|
+
"size": {
|
|
138
|
+
"type": "string",
|
|
139
|
+
"mutable": false,
|
|
140
|
+
"complexType": {
|
|
141
|
+
"original": "\"md\" | \"lg\"",
|
|
142
|
+
"resolved": "\"lg\" | \"md\"",
|
|
143
|
+
"references": {}
|
|
144
|
+
},
|
|
145
|
+
"required": false,
|
|
146
|
+
"optional": false,
|
|
147
|
+
"docs": {
|
|
148
|
+
"tags": [],
|
|
149
|
+
"text": ""
|
|
150
|
+
},
|
|
151
|
+
"getter": false,
|
|
152
|
+
"setter": false,
|
|
153
|
+
"reflect": false,
|
|
154
|
+
"attribute": "size",
|
|
155
|
+
"defaultValue": "\"md\""
|
|
156
|
+
},
|
|
157
|
+
"label": {
|
|
158
|
+
"type": "string",
|
|
159
|
+
"mutable": false,
|
|
160
|
+
"complexType": {
|
|
161
|
+
"original": "string",
|
|
162
|
+
"resolved": "string | undefined",
|
|
163
|
+
"references": {}
|
|
164
|
+
},
|
|
165
|
+
"required": false,
|
|
166
|
+
"optional": true,
|
|
167
|
+
"docs": {
|
|
168
|
+
"tags": [],
|
|
169
|
+
"text": ""
|
|
170
|
+
},
|
|
171
|
+
"getter": false,
|
|
172
|
+
"setter": false,
|
|
173
|
+
"reflect": false,
|
|
174
|
+
"attribute": "label"
|
|
175
|
+
},
|
|
176
|
+
"options": {
|
|
177
|
+
"type": "string",
|
|
178
|
+
"mutable": false,
|
|
179
|
+
"complexType": {
|
|
180
|
+
"original": "string | ReadonlyArray<DsSelectOption>",
|
|
181
|
+
"resolved": "readonly DsSelectOption[] | string",
|
|
182
|
+
"references": {
|
|
183
|
+
"ReadonlyArray": {
|
|
184
|
+
"location": "global",
|
|
185
|
+
"id": "global::ReadonlyArray"
|
|
186
|
+
},
|
|
187
|
+
"DsSelectOption": {
|
|
188
|
+
"location": "local",
|
|
189
|
+
"path": "/Users/alex/projects/MyGitHub/chiralkit/packages/design-system/src/components/ds-select/ds-select.tsx",
|
|
190
|
+
"id": "src/components/ds-select/ds-select.tsx::DsSelectOption"
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
"required": false,
|
|
195
|
+
"optional": false,
|
|
196
|
+
"docs": {
|
|
197
|
+
"tags": [],
|
|
198
|
+
"text": "Options rendered inside the internal shadow `<select>`. Accepts either:\n- a JSON string (SSR-friendly \u2014 server-rendered HTML can only set\n string attributes, and Stencil does not JSON-parse array attributes),\n e.g. `options='[{\"value\":\"en\",\"label\":\"EN\"}]'`\n- an array property set from client-side JS,\n e.g. `el.options = [{ value: 'en', label: 'EN' }]`\n\nMalformed JSON fails safe to an empty list rather than throwing, so the\ncomponent still renders a visible (if empty) select."
|
|
199
|
+
},
|
|
200
|
+
"getter": false,
|
|
201
|
+
"setter": false,
|
|
202
|
+
"reflect": false,
|
|
203
|
+
"attribute": "options",
|
|
204
|
+
"defaultValue": "\"[]\""
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
static get events() {
|
|
209
|
+
return [{
|
|
210
|
+
"method": "dsChange",
|
|
211
|
+
"name": "dsChange",
|
|
212
|
+
"bubbles": true,
|
|
213
|
+
"cancelable": true,
|
|
214
|
+
"composed": true,
|
|
215
|
+
"docs": {
|
|
216
|
+
"tags": [],
|
|
217
|
+
"text": ""
|
|
218
|
+
},
|
|
219
|
+
"complexType": {
|
|
220
|
+
"original": "string",
|
|
221
|
+
"resolved": "string",
|
|
222
|
+
"references": {}
|
|
223
|
+
}
|
|
224
|
+
}];
|
|
225
|
+
}
|
|
226
|
+
static get watchers() {
|
|
227
|
+
return [{
|
|
228
|
+
"propName": "value",
|
|
229
|
+
"methodName": "watchValue"
|
|
230
|
+
}, {
|
|
231
|
+
"propName": "options",
|
|
232
|
+
"methodName": "watchOptions"
|
|
233
|
+
}];
|
|
234
|
+
}
|
|
235
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ds-tabs uses shadow: false so the tab <button> ids are addressable
|
|
3
|
+
* from consumers' light-DOM tabpanels via aria-labelledby. Selectors
|
|
4
|
+
* here match on the class hooks emitted by the component so consumer
|
|
5
|
+
* CSS can override without specificity wars.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
ds-tabs {
|
|
9
|
+
display: block;
|
|
10
|
+
color: inherit;
|
|
11
|
+
font-family: var(--ds-font-family);
|
|
12
|
+
font-size: var(--ds-font-size-md);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.ds-tabs {
|
|
16
|
+
display: flex;
|
|
17
|
+
gap: var(--ds-spacing-sm);
|
|
18
|
+
border-bottom: 1px solid color-mix(in oklch, currentColor 15%, transparent);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.ds-tabs--vertical {
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
align-items: stretch;
|
|
24
|
+
border-bottom: none;
|
|
25
|
+
border-right: 1px solid color-mix(in oklch, currentColor 15%, transparent);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.ds-tab {
|
|
29
|
+
font: inherit;
|
|
30
|
+
color: inherit;
|
|
31
|
+
background-color: transparent;
|
|
32
|
+
border: none;
|
|
33
|
+
padding: var(--ds-spacing-sm) var(--ds-spacing-lg);
|
|
34
|
+
cursor: pointer;
|
|
35
|
+
border-bottom: 2px solid transparent;
|
|
36
|
+
margin-bottom: -1px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.ds-tabs--vertical .ds-tab {
|
|
40
|
+
text-align: left;
|
|
41
|
+
border-bottom: none;
|
|
42
|
+
border-right: 2px solid transparent;
|
|
43
|
+
margin-bottom: 0;
|
|
44
|
+
margin-right: -1px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.ds-tab--active {
|
|
48
|
+
border-bottom-color: currentColor;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.ds-tabs--vertical .ds-tab--active {
|
|
52
|
+
border-bottom-color: transparent;
|
|
53
|
+
border-right-color: currentColor;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.ds-tab:disabled {
|
|
57
|
+
opacity: 0.5;
|
|
58
|
+
cursor: not-allowed;
|
|
59
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { h, Host, } from "@stencil/core";
|
|
2
|
+
export class DsTabs {
|
|
3
|
+
tabRefs = new Map();
|
|
4
|
+
pendingFocusId;
|
|
5
|
+
items = "[]";
|
|
6
|
+
active;
|
|
7
|
+
orientation = "horizontal";
|
|
8
|
+
label;
|
|
9
|
+
dsChange;
|
|
10
|
+
watchItems() {
|
|
11
|
+
// Re-reconcile the active id when items change: if the current
|
|
12
|
+
// active is no longer in the list, fall back to the first enabled.
|
|
13
|
+
const parsed = this.parseItems();
|
|
14
|
+
if (parsed.length === 0)
|
|
15
|
+
return;
|
|
16
|
+
if (!parsed.some((it) => it.id === this.active && !it.disabled)) {
|
|
17
|
+
const firstEnabled = parsed.find((it) => !it.disabled);
|
|
18
|
+
if (firstEnabled) {
|
|
19
|
+
this.active = firstEnabled.id;
|
|
20
|
+
this.dsChange.emit(firstEnabled.id);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
componentWillLoad() {
|
|
25
|
+
const parsed = this.parseItems();
|
|
26
|
+
if (parsed.length === 0)
|
|
27
|
+
return;
|
|
28
|
+
// Reconcile initial active — if the consumer passed an id that
|
|
29
|
+
// isn't in items (or none at all), fall back to the first enabled
|
|
30
|
+
// and emit dsChange once so their state matches ours.
|
|
31
|
+
if (!this.active || !parsed.some((it) => it.id === this.active && !it.disabled)) {
|
|
32
|
+
const firstEnabled = parsed.find((it) => !it.disabled);
|
|
33
|
+
if (firstEnabled) {
|
|
34
|
+
this.active = firstEnabled.id;
|
|
35
|
+
this.dsChange.emit(firstEnabled.id);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
componentDidRender() {
|
|
40
|
+
// Move programmatic focus to the newly selected tab after
|
|
41
|
+
// arrow/Home/End nav so the visible focus ring tracks selection.
|
|
42
|
+
// Click-driven selection does not set pendingFocusId — the native
|
|
43
|
+
// button click already lands focus on the clicked element.
|
|
44
|
+
if (this.pendingFocusId) {
|
|
45
|
+
const target = this.tabRefs.get(this.pendingFocusId);
|
|
46
|
+
target?.focus();
|
|
47
|
+
this.pendingFocusId = undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
parseItems() {
|
|
51
|
+
if (typeof this.items === "string") {
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(this.items);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
console.warn("[ds-tabs] failed to parse items prop:", this.items);
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return this.items;
|
|
61
|
+
}
|
|
62
|
+
enabledItems() {
|
|
63
|
+
return this.parseItems().filter((it) => !it.disabled);
|
|
64
|
+
}
|
|
65
|
+
selectAndFocus(id) {
|
|
66
|
+
if (id === this.active)
|
|
67
|
+
return;
|
|
68
|
+
this.active = id;
|
|
69
|
+
this.pendingFocusId = id;
|
|
70
|
+
this.dsChange.emit(id);
|
|
71
|
+
}
|
|
72
|
+
onClick = (id) => {
|
|
73
|
+
if (id === this.active)
|
|
74
|
+
return;
|
|
75
|
+
this.active = id;
|
|
76
|
+
// No pendingFocusId: click already focused the button natively.
|
|
77
|
+
this.dsChange.emit(id);
|
|
78
|
+
};
|
|
79
|
+
onKeyDown = (event, currentId) => {
|
|
80
|
+
const enabled = this.enabledItems();
|
|
81
|
+
if (enabled.length === 0)
|
|
82
|
+
return;
|
|
83
|
+
const isHorizontal = this.orientation === "horizontal";
|
|
84
|
+
const nextKey = isHorizontal ? "ArrowRight" : "ArrowDown";
|
|
85
|
+
const prevKey = isHorizontal ? "ArrowLeft" : "ArrowUp";
|
|
86
|
+
const currentIdx = enabled.findIndex((it) => it.id === currentId);
|
|
87
|
+
if (event.key === nextKey) {
|
|
88
|
+
event.preventDefault();
|
|
89
|
+
const nextIdx = (currentIdx + 1) % enabled.length;
|
|
90
|
+
this.selectAndFocus(enabled[nextIdx].id);
|
|
91
|
+
}
|
|
92
|
+
else if (event.key === prevKey) {
|
|
93
|
+
event.preventDefault();
|
|
94
|
+
const prevIdx = (currentIdx - 1 + enabled.length) % enabled.length;
|
|
95
|
+
this.selectAndFocus(enabled[prevIdx].id);
|
|
96
|
+
}
|
|
97
|
+
else if (event.key === "Home") {
|
|
98
|
+
event.preventDefault();
|
|
99
|
+
this.selectAndFocus(enabled[0].id);
|
|
100
|
+
}
|
|
101
|
+
else if (event.key === "End") {
|
|
102
|
+
event.preventDefault();
|
|
103
|
+
this.selectAndFocus(enabled[enabled.length - 1].id);
|
|
104
|
+
}
|
|
105
|
+
// Enter / Space intentionally not handled — automatic activation
|
|
106
|
+
// already selected the tab on focus move, and the native button
|
|
107
|
+
// click behavior remains available for consumers who bind to it.
|
|
108
|
+
};
|
|
109
|
+
render() {
|
|
110
|
+
const items = this.parseItems();
|
|
111
|
+
return (h(Host, { key: 'efc6a329ddbc14550f7e186480e41218f52b4865' }, h("div", { key: '4d475ddcb89198d97440e1e807acbef5984f658e', class: `ds-tabs ds-tabs--${this.orientation}`, role: "tablist", "aria-label": this.label, "aria-orientation": this.orientation === "vertical" ? "vertical" : undefined }, items.map((item) => {
|
|
112
|
+
const isActive = item.id === this.active;
|
|
113
|
+
return (h("button", { key: item.id, type: "button", role: "tab", id: item.id, class: `ds-tab${isActive ? " ds-tab--active" : ""}`, "aria-selected": isActive ? "true" : "false", "aria-controls": item.controls ?? item.id, tabindex: isActive ? 0 : -1, disabled: item.disabled, ref: (el) => {
|
|
114
|
+
if (el)
|
|
115
|
+
this.tabRefs.set(item.id, el);
|
|
116
|
+
else
|
|
117
|
+
this.tabRefs.delete(item.id);
|
|
118
|
+
}, onClick: () => this.onClick(item.id), onKeyDown: (e) => this.onKeyDown(e, item.id) }, item.label));
|
|
119
|
+
}))));
|
|
120
|
+
}
|
|
121
|
+
static get is() { return "ds-tabs"; }
|
|
122
|
+
static get originalStyleUrls() {
|
|
123
|
+
return {
|
|
124
|
+
"$": ["ds-tabs.css"]
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
static get styleUrls() {
|
|
128
|
+
return {
|
|
129
|
+
"$": ["ds-tabs.css"]
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
static get properties() {
|
|
133
|
+
return {
|
|
134
|
+
"items": {
|
|
135
|
+
"type": "string",
|
|
136
|
+
"mutable": false,
|
|
137
|
+
"complexType": {
|
|
138
|
+
"original": "string | ReadonlyArray<DsTabItem>",
|
|
139
|
+
"resolved": "readonly DsTabItem[] | string",
|
|
140
|
+
"references": {
|
|
141
|
+
"ReadonlyArray": {
|
|
142
|
+
"location": "global",
|
|
143
|
+
"id": "global::ReadonlyArray"
|
|
144
|
+
},
|
|
145
|
+
"DsTabItem": {
|
|
146
|
+
"location": "local",
|
|
147
|
+
"path": "/Users/alex/projects/MyGitHub/chiralkit/packages/design-system/src/components/ds-tabs/ds-tabs.tsx",
|
|
148
|
+
"id": "src/components/ds-tabs/ds-tabs.tsx::DsTabItem"
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
"required": false,
|
|
153
|
+
"optional": false,
|
|
154
|
+
"docs": {
|
|
155
|
+
"tags": [],
|
|
156
|
+
"text": ""
|
|
157
|
+
},
|
|
158
|
+
"getter": false,
|
|
159
|
+
"setter": false,
|
|
160
|
+
"reflect": false,
|
|
161
|
+
"attribute": "items",
|
|
162
|
+
"defaultValue": "\"[]\""
|
|
163
|
+
},
|
|
164
|
+
"active": {
|
|
165
|
+
"type": "string",
|
|
166
|
+
"mutable": true,
|
|
167
|
+
"complexType": {
|
|
168
|
+
"original": "string",
|
|
169
|
+
"resolved": "string | undefined",
|
|
170
|
+
"references": {}
|
|
171
|
+
},
|
|
172
|
+
"required": false,
|
|
173
|
+
"optional": true,
|
|
174
|
+
"docs": {
|
|
175
|
+
"tags": [],
|
|
176
|
+
"text": ""
|
|
177
|
+
},
|
|
178
|
+
"getter": false,
|
|
179
|
+
"setter": false,
|
|
180
|
+
"reflect": false,
|
|
181
|
+
"attribute": "active"
|
|
182
|
+
},
|
|
183
|
+
"orientation": {
|
|
184
|
+
"type": "string",
|
|
185
|
+
"mutable": false,
|
|
186
|
+
"complexType": {
|
|
187
|
+
"original": "\"horizontal\" | \"vertical\"",
|
|
188
|
+
"resolved": "\"horizontal\" | \"vertical\"",
|
|
189
|
+
"references": {}
|
|
190
|
+
},
|
|
191
|
+
"required": false,
|
|
192
|
+
"optional": false,
|
|
193
|
+
"docs": {
|
|
194
|
+
"tags": [],
|
|
195
|
+
"text": ""
|
|
196
|
+
},
|
|
197
|
+
"getter": false,
|
|
198
|
+
"setter": false,
|
|
199
|
+
"reflect": false,
|
|
200
|
+
"attribute": "orientation",
|
|
201
|
+
"defaultValue": "\"horizontal\""
|
|
202
|
+
},
|
|
203
|
+
"label": {
|
|
204
|
+
"type": "string",
|
|
205
|
+
"mutable": false,
|
|
206
|
+
"complexType": {
|
|
207
|
+
"original": "string",
|
|
208
|
+
"resolved": "string | undefined",
|
|
209
|
+
"references": {}
|
|
210
|
+
},
|
|
211
|
+
"required": false,
|
|
212
|
+
"optional": true,
|
|
213
|
+
"docs": {
|
|
214
|
+
"tags": [],
|
|
215
|
+
"text": ""
|
|
216
|
+
},
|
|
217
|
+
"getter": false,
|
|
218
|
+
"setter": false,
|
|
219
|
+
"reflect": false,
|
|
220
|
+
"attribute": "label"
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
static get events() {
|
|
225
|
+
return [{
|
|
226
|
+
"method": "dsChange",
|
|
227
|
+
"name": "dsChange",
|
|
228
|
+
"bubbles": true,
|
|
229
|
+
"cancelable": true,
|
|
230
|
+
"composed": true,
|
|
231
|
+
"docs": {
|
|
232
|
+
"tags": [],
|
|
233
|
+
"text": ""
|
|
234
|
+
},
|
|
235
|
+
"complexType": {
|
|
236
|
+
"original": "string",
|
|
237
|
+
"resolved": "string",
|
|
238
|
+
"references": {}
|
|
239
|
+
}
|
|
240
|
+
}];
|
|
241
|
+
}
|
|
242
|
+
static get watchers() {
|
|
243
|
+
return [{
|
|
244
|
+
"propName": "items",
|
|
245
|
+
"methodName": "watchItems"
|
|
246
|
+
}];
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: inline-block;
|
|
3
|
+
width: 100%;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.ds-textarea {
|
|
7
|
+
font-family: var(--ds-font-family);
|
|
8
|
+
font-size: var(--ds-font-size-md);
|
|
9
|
+
background-color: transparent;
|
|
10
|
+
color: inherit;
|
|
11
|
+
border: 1px solid color-mix(in oklch, currentColor 22%, transparent);
|
|
12
|
+
-webkit-appearance: none;
|
|
13
|
+
appearance: none;
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
width: 100%;
|
|
16
|
+
resize: vertical;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.ds-textarea::placeholder {
|
|
20
|
+
color: color-mix(in oklch, currentColor 45%, transparent);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.ds-textarea:disabled {
|
|
24
|
+
opacity: 0.5;
|
|
25
|
+
cursor: not-allowed;
|
|
26
|
+
resize: none;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.ds-textarea[aria-invalid="true"] {
|
|
30
|
+
border-color: color-mix(in oklch, currentColor 55%, transparent);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.ds-textarea--md {
|
|
34
|
+
border-radius: var(--ds-radius-sm);
|
|
35
|
+
padding: var(--ds-spacing-sm) var(--ds-spacing-lg);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.ds-textarea--lg {
|
|
39
|
+
border-radius: var(--ds-radius-md);
|
|
40
|
+
padding: var(--ds-spacing-md) var(--ds-spacing-xl);
|
|
41
|
+
}
|