@neuravision/construct 1.1.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 +227 -0
- package/components/README.md +566 -0
- package/components/_keyframes.css +23 -0
- package/components/_shared.css +120 -0
- package/components/accordion.css +124 -0
- package/components/alert.css +67 -0
- package/components/avatar.css +127 -0
- package/components/badge.css +67 -0
- package/components/banner.css +247 -0
- package/components/breadcrumbs.css +152 -0
- package/components/button.css +145 -0
- package/components/card.css +76 -0
- package/components/checkbox.css +120 -0
- package/components/chip.css +361 -0
- package/components/combobox.css +385 -0
- package/components/components.css +2 -0
- package/components/data-table.css +93 -0
- package/components/datepicker.css +268 -0
- package/components/divider.css +73 -0
- package/components/drawer.css +167 -0
- package/components/dropdown.css +401 -0
- package/components/empty-state.css +97 -0
- package/components/field.css +42 -0
- package/components/file-upload.css +111 -0
- package/components/icon.css +31 -0
- package/components/index.css +49 -0
- package/components/input.css +64 -0
- package/components/list.css +474 -0
- package/components/modal.css +164 -0
- package/components/navbar.css +587 -0
- package/components/pagination.css +131 -0
- package/components/popover.css +231 -0
- package/components/progress-bar.css +56 -0
- package/components/select-menu.css +267 -0
- package/components/select.css +30 -0
- package/components/sidebar.css +183 -0
- package/components/skeleton.css +38 -0
- package/components/skip-link.css +38 -0
- package/components/slider.css +305 -0
- package/components/spinner.css +72 -0
- package/components/switch.css +82 -0
- package/components/table.css +139 -0
- package/components/tabs.css +147 -0
- package/components/textarea.css +16 -0
- package/components/toast.css +71 -0
- package/components/toggle-group.css +196 -0
- package/components/toolbar.css +222 -0
- package/components/tooltip.css +124 -0
- package/docs/guidelines.md +141 -0
- package/foundations.css +299 -0
- package/package.json +66 -0
- package/tokens/README.md +179 -0
- package/tokens/tokens.css +434 -0
- package/tokens/tokens.js +1188 -0
- package/tokens/tokens.json +810 -0
- package/tokens/tokens.ts +1188 -0
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
# Construct Components v1
|
|
2
|
+
|
|
3
|
+
Framework-agnostic component styles built on Construct design tokens. Use these styles directly with HTML or wrap them in Angular, React, or Svelte components. Interactive states are controlled via data attributes and ARIA, making them easy to enhance with JavaScript.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
Import order (recommended):
|
|
8
|
+
1. Tokens (automatically included via foundations)
|
|
9
|
+
2. Foundations
|
|
10
|
+
3. Components
|
|
11
|
+
|
|
12
|
+
Example:
|
|
13
|
+
```css
|
|
14
|
+
@import '@neuravision/construct/foundations.css';
|
|
15
|
+
@import '@neuravision/construct/components/components.css';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## State Conventions
|
|
19
|
+
|
|
20
|
+
- `data-state="open"` / `data-state="closed"` for popovers, modals, tooltips
|
|
21
|
+
- `aria-invalid="true"` for form errors
|
|
22
|
+
- `aria-current="page"` for current pagination page
|
|
23
|
+
- `aria-selected="true"` for active tabs and selected datepicker days
|
|
24
|
+
- `aria-disabled="true"` when disabled but not using native `disabled`
|
|
25
|
+
|
|
26
|
+
## Keyboard + ARIA Requirements
|
|
27
|
+
|
|
28
|
+
When building framework wrappers, implement these keyboard patterns:
|
|
29
|
+
|
|
30
|
+
- **Tabs**: Arrow keys move focus between tabs, Home/End jumps to first/last, Enter/Space activates. Use roving tabindex (active tab `tabindex="0"`, others `tabindex="-1"`).
|
|
31
|
+
- **Dropdown (Action-List)**: Trigger uses `aria-expanded` + `aria-controls`. On open, move focus to first item, Esc closes and returns focus to trigger.
|
|
32
|
+
- **Dropdown (Role=menu)**: Only use if implementing arrow-key navigation, Home/End, typeahead, and roving tabindex.
|
|
33
|
+
- **Datepicker**: Arrow keys move by day, PageUp/PageDown switches months, Home/End jumps within week, Enter/Space selects, Esc closes.
|
|
34
|
+
- **Modal**: Focus trap, initial focus inside dialog, Esc closes, focus returns to trigger.
|
|
35
|
+
- **Tooltip**: Opens on hover/focus, closes on blur/Esc, uses `role="tooltip"` with `aria-describedby`.
|
|
36
|
+
|
|
37
|
+
## Components
|
|
38
|
+
|
|
39
|
+
### Button
|
|
40
|
+
|
|
41
|
+
Basic button with variants and sizes:
|
|
42
|
+
|
|
43
|
+
```html
|
|
44
|
+
<button class="ct-button">Primary</button>
|
|
45
|
+
<button class="ct-button ct-button--secondary">Secondary</button>
|
|
46
|
+
<button class="ct-button ct-button--ghost">Ghost</button>
|
|
47
|
+
<button class="ct-button ct-button--outline">Outline</button>
|
|
48
|
+
<button class="ct-button ct-button--danger">Danger</button>
|
|
49
|
+
<button class="ct-button ct-button--accent">Accent</button>
|
|
50
|
+
<button class="ct-button ct-button--link">Link</button>
|
|
51
|
+
|
|
52
|
+
<!-- Sizes -->
|
|
53
|
+
<button class="ct-button ct-button--sm">Small</button>
|
|
54
|
+
<button class="ct-button">Medium</button>
|
|
55
|
+
<button class="ct-button ct-button--lg">Large</button>
|
|
56
|
+
|
|
57
|
+
<!-- With icon -->
|
|
58
|
+
<button class="ct-button">
|
|
59
|
+
<span class="ct-button__icon" aria-hidden="true">+</span>
|
|
60
|
+
Add item
|
|
61
|
+
</button>
|
|
62
|
+
|
|
63
|
+
<!-- Icon only -->
|
|
64
|
+
<button class="ct-button ct-button--icon" aria-label="Settings">
|
|
65
|
+
<span class="ct-button__icon" aria-hidden="true">⚙</span>
|
|
66
|
+
</button>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Field + Input
|
|
70
|
+
|
|
71
|
+
Form field with label, input, hint, and error states:
|
|
72
|
+
|
|
73
|
+
```html
|
|
74
|
+
<div class="ct-field">
|
|
75
|
+
<label class="ct-field__label" for="email">Email</label>
|
|
76
|
+
<input class="ct-input" id="email" type="email" placeholder="name@company.com" />
|
|
77
|
+
<div class="ct-field__hint">We will not share this.</div>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<!-- Error state -->
|
|
81
|
+
<div class="ct-field ct-field--error">
|
|
82
|
+
<label class="ct-field__label" for="name">Name</label>
|
|
83
|
+
<input class="ct-input" id="name" aria-invalid="true" />
|
|
84
|
+
<div class="ct-field__error">Name is required.</div>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<!-- With icon -->
|
|
88
|
+
<div class="ct-field">
|
|
89
|
+
<label class="ct-field__label" for="search">Search</label>
|
|
90
|
+
<div class="ct-input-wrap">
|
|
91
|
+
<span class="ct-input__icon" aria-hidden="true">🔍</span>
|
|
92
|
+
<input class="ct-input ct-input--with-icon" id="search" type="search" />
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Select
|
|
98
|
+
|
|
99
|
+
Native select dropdown:
|
|
100
|
+
|
|
101
|
+
```html
|
|
102
|
+
<div class="ct-field">
|
|
103
|
+
<label class="ct-field__label" for="role">Role</label>
|
|
104
|
+
<select class="ct-select" id="role">
|
|
105
|
+
<option>Designer</option>
|
|
106
|
+
<option>Engineer</option>
|
|
107
|
+
<option>Manager</option>
|
|
108
|
+
</select>
|
|
109
|
+
</div>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Textarea
|
|
113
|
+
|
|
114
|
+
Multi-line text input:
|
|
115
|
+
|
|
116
|
+
```html
|
|
117
|
+
<div class="ct-field">
|
|
118
|
+
<label class="ct-field__label" for="notes">Notes</label>
|
|
119
|
+
<textarea class="ct-textarea" id="notes" placeholder="Add context..."></textarea>
|
|
120
|
+
</div>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Checkbox
|
|
124
|
+
|
|
125
|
+
Single checkbox or checkbox group:
|
|
126
|
+
|
|
127
|
+
```html
|
|
128
|
+
<label class="ct-check">
|
|
129
|
+
<input class="ct-check__input" type="checkbox" />
|
|
130
|
+
<span class="ct-check__label">Remember me</span>
|
|
131
|
+
</label>
|
|
132
|
+
|
|
133
|
+
<label class="ct-check">
|
|
134
|
+
<input class="ct-check__input" type="checkbox" checked />
|
|
135
|
+
<span class="ct-check__label">Send weekly reports</span>
|
|
136
|
+
</label>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Radio
|
|
140
|
+
|
|
141
|
+
Radio button group:
|
|
142
|
+
|
|
143
|
+
```html
|
|
144
|
+
<label class="ct-radio">
|
|
145
|
+
<input class="ct-radio__input" type="radio" name="plan" checked />
|
|
146
|
+
<span class="ct-radio__label">Standard</span>
|
|
147
|
+
</label>
|
|
148
|
+
|
|
149
|
+
<label class="ct-radio">
|
|
150
|
+
<input class="ct-radio__input" type="radio" name="plan" />
|
|
151
|
+
<span class="ct-radio__label">Premium</span>
|
|
152
|
+
</label>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Switch
|
|
156
|
+
|
|
157
|
+
Toggle switch control:
|
|
158
|
+
|
|
159
|
+
```html
|
|
160
|
+
<label class="ct-switch">
|
|
161
|
+
<input class="ct-switch__input" type="checkbox" role="switch" checked />
|
|
162
|
+
<span class="ct-switch__label">Auto renew</span>
|
|
163
|
+
</label>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Card
|
|
167
|
+
|
|
168
|
+
Content card with header, body, and footer:
|
|
169
|
+
|
|
170
|
+
```html
|
|
171
|
+
<section class="ct-card">
|
|
172
|
+
<div class="ct-card__header">
|
|
173
|
+
<h3>Team</h3>
|
|
174
|
+
<button class="ct-button ct-button--ghost">Edit</button>
|
|
175
|
+
</div>
|
|
176
|
+
<div class="ct-card__body">
|
|
177
|
+
<p>Shared ownership and clear permissions.</p>
|
|
178
|
+
<p class="ct-muted">Updated 2 days ago</p>
|
|
179
|
+
</div>
|
|
180
|
+
<div class="ct-card__footer">
|
|
181
|
+
<span class="ct-muted">12 members</span>
|
|
182
|
+
<button class="ct-button ct-button--secondary">Open</button>
|
|
183
|
+
</div>
|
|
184
|
+
</section>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Table
|
|
188
|
+
|
|
189
|
+
Basic data table with variants:
|
|
190
|
+
|
|
191
|
+
```html
|
|
192
|
+
<div class="ct-table-wrap">
|
|
193
|
+
<table class="ct-table ct-table--striped">
|
|
194
|
+
<thead>
|
|
195
|
+
<tr>
|
|
196
|
+
<th scope="col">Name</th>
|
|
197
|
+
<th scope="col">Status</th>
|
|
198
|
+
<th scope="col">Owner</th>
|
|
199
|
+
</tr>
|
|
200
|
+
</thead>
|
|
201
|
+
<tbody>
|
|
202
|
+
<tr>
|
|
203
|
+
<td>Alpha</td>
|
|
204
|
+
<td>Active</td>
|
|
205
|
+
<td>J. Chen</td>
|
|
206
|
+
</tr>
|
|
207
|
+
<tr>
|
|
208
|
+
<td>Beta</td>
|
|
209
|
+
<td>Paused</td>
|
|
210
|
+
<td>L. Hart</td>
|
|
211
|
+
</tr>
|
|
212
|
+
</tbody>
|
|
213
|
+
</table>
|
|
214
|
+
</div>
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Variants:
|
|
218
|
+
- `ct-table--striped` - Alternating row backgrounds
|
|
219
|
+
- `ct-table--compact` - Reduced padding
|
|
220
|
+
- `ct-table--hover` - Row hover effect
|
|
221
|
+
|
|
222
|
+
### Data Table
|
|
223
|
+
|
|
224
|
+
Complex data table with header, toolbar, filters, and actions:
|
|
225
|
+
|
|
226
|
+
```html
|
|
227
|
+
<div class="ct-data-table">
|
|
228
|
+
<div class="ct-data-table__header">
|
|
229
|
+
<div class="ct-data-table__title">
|
|
230
|
+
<h3>Projects</h3>
|
|
231
|
+
<span class="ct-data-table__meta">24 total</span>
|
|
232
|
+
</div>
|
|
233
|
+
<div class="ct-data-table__actions">
|
|
234
|
+
<button class="ct-button ct-button--secondary ct-button--sm">Export</button>
|
|
235
|
+
<button class="ct-button ct-button--sm">New project</button>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
|
|
239
|
+
<div class="ct-data-table__toolbar">
|
|
240
|
+
<div class="ct-data-table__filters">
|
|
241
|
+
<input class="ct-input ct-control--sm" placeholder="Search..." aria-label="Search" />
|
|
242
|
+
<select class="ct-select ct-control--sm" aria-label="Filter by status">
|
|
243
|
+
<option>All Status</option>
|
|
244
|
+
<option>Active</option>
|
|
245
|
+
<option>Paused</option>
|
|
246
|
+
</select>
|
|
247
|
+
</div>
|
|
248
|
+
</div>
|
|
249
|
+
|
|
250
|
+
<div class="ct-data-table__table">
|
|
251
|
+
<table class="ct-table ct-table--striped">
|
|
252
|
+
<!-- table content -->
|
|
253
|
+
</table>
|
|
254
|
+
</div>
|
|
255
|
+
|
|
256
|
+
<div class="ct-data-table__footer">
|
|
257
|
+
<span class="ct-muted">Showing 1-10 of 24</span>
|
|
258
|
+
<!-- pagination component -->
|
|
259
|
+
</div>
|
|
260
|
+
</div>
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Modal
|
|
264
|
+
|
|
265
|
+
Dialog with backdrop:
|
|
266
|
+
|
|
267
|
+
```html
|
|
268
|
+
<div class="ct-modal" data-state="open" role="dialog" aria-modal="true" aria-labelledby="modal-title">
|
|
269
|
+
<div class="ct-modal__dialog">
|
|
270
|
+
<div class="ct-modal__header">
|
|
271
|
+
<h2 id="modal-title">Invite team</h2>
|
|
272
|
+
<button class="ct-button ct-button--ghost" aria-label="Close">×</button>
|
|
273
|
+
</div>
|
|
274
|
+
<div class="ct-modal__body">
|
|
275
|
+
<p>Send an invite to a new team member.</p>
|
|
276
|
+
<!-- form content -->
|
|
277
|
+
</div>
|
|
278
|
+
<div class="ct-modal__footer">
|
|
279
|
+
<button class="ct-button ct-button--secondary">Cancel</button>
|
|
280
|
+
<button class="ct-button">Send</button>
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Toast
|
|
287
|
+
|
|
288
|
+
Notification with variants:
|
|
289
|
+
|
|
290
|
+
```html
|
|
291
|
+
<div class="ct-toast-region" aria-live="polite">
|
|
292
|
+
<div class="ct-toast" data-variant="success" data-state="open">
|
|
293
|
+
<div class="ct-toast__title">Saved</div>
|
|
294
|
+
<div class="ct-toast__description">Your changes were saved.</div>
|
|
295
|
+
<button class="ct-button ct-button--ghost">Undo</button>
|
|
296
|
+
</div>
|
|
297
|
+
</div>
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Variants: `success`, `error`, `info`, `warning`
|
|
301
|
+
|
|
302
|
+
### Alert / Banner
|
|
303
|
+
|
|
304
|
+
Inline feedback message with variants:
|
|
305
|
+
|
|
306
|
+
```html
|
|
307
|
+
<div class="ct-alert" data-variant="warning" role="alert">
|
|
308
|
+
<span class="ct-alert__icon" aria-hidden="true">!</span>
|
|
309
|
+
<div class="ct-alert__content">
|
|
310
|
+
<div class="ct-alert__title">Action required</div>
|
|
311
|
+
<div class="ct-alert__description">Please review the pending changes.</div>
|
|
312
|
+
<div class="ct-alert__actions">
|
|
313
|
+
<button class="ct-button ct-button--secondary ct-button--sm">Review</button>
|
|
314
|
+
</div>
|
|
315
|
+
</div>
|
|
316
|
+
</div>
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Variants: `info`, `success`, `warning`, `danger`
|
|
320
|
+
|
|
321
|
+
### Badge / Status Badge
|
|
322
|
+
|
|
323
|
+
Small status indicators with optional icon or dot:
|
|
324
|
+
|
|
325
|
+
```html
|
|
326
|
+
<span class="ct-badge ct-badge--icon"><span class="ct-badge__dot" aria-hidden="true"></span>Draft</span>
|
|
327
|
+
<span class="ct-badge ct-badge--success ct-badge--icon">
|
|
328
|
+
<span class="ct-badge__icon" aria-hidden="true">+</span>
|
|
329
|
+
Approved
|
|
330
|
+
</span>
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Chip / Tag
|
|
334
|
+
|
|
335
|
+
Compact tags for filters or metadata:
|
|
336
|
+
|
|
337
|
+
```html
|
|
338
|
+
<button class="ct-chip ct-chip--interactive" type="button" aria-pressed="true">
|
|
339
|
+
<span class="ct-chip__icon" aria-hidden="true">#</span>
|
|
340
|
+
Finance
|
|
341
|
+
</button>
|
|
342
|
+
|
|
343
|
+
<span class="ct-chip">
|
|
344
|
+
Uploads
|
|
345
|
+
<button class="ct-chip__remove" type="button" aria-label="Remove tag">x</button>
|
|
346
|
+
</span>
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### File Upload / Drag & Drop
|
|
350
|
+
|
|
351
|
+
Drag area + file list pattern. Use `data-state="dragover"` and `aria-invalid="true"` when needed.
|
|
352
|
+
|
|
353
|
+
```html
|
|
354
|
+
<div class="ct-file-upload">
|
|
355
|
+
<label class="ct-file-upload__dropzone" for="files">
|
|
356
|
+
<input class="ct-file-upload__input" id="files" type="file" multiple />
|
|
357
|
+
<div class="ct-file-upload__title">Drop files here or browse</div>
|
|
358
|
+
<div class="ct-file-upload__hint">PDF, DOCX up to 10MB</div>
|
|
359
|
+
<span class="ct-button ct-button--secondary ct-button--sm">Browse files</span>
|
|
360
|
+
</label>
|
|
361
|
+
|
|
362
|
+
<ul class="ct-file-upload__list">
|
|
363
|
+
<li class="ct-file-upload__item" data-status="success">
|
|
364
|
+
<div class="ct-file-upload__file">
|
|
365
|
+
<div class="ct-file-upload__name">report.pdf</div>
|
|
366
|
+
<div class="ct-file-upload__meta">820 KB</div>
|
|
367
|
+
</div>
|
|
368
|
+
<span class="ct-badge ct-badge--success">Uploaded</span>
|
|
369
|
+
</li>
|
|
370
|
+
</ul>
|
|
371
|
+
<div class="ct-file-upload__error">File is too large.</div>
|
|
372
|
+
</div>
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Loading Spinner + Overlay
|
|
376
|
+
|
|
377
|
+
Spinner for inline loading and overlay for blocking states:
|
|
378
|
+
|
|
379
|
+
```html
|
|
380
|
+
<div class="ct-spinner ct-spinner--sm" role="status" aria-live="polite"></div>
|
|
381
|
+
|
|
382
|
+
<div class="ct-card" style="position: relative; min-height: 180px;">
|
|
383
|
+
<div class="ct-loading-overlay" data-state="active" aria-busy="true">
|
|
384
|
+
<div class="ct-loading-overlay__content">
|
|
385
|
+
<div class="ct-spinner ct-spinner--lg" aria-hidden="true"></div>
|
|
386
|
+
<div class="ct-loading-overlay__label">Uploading files...</div>
|
|
387
|
+
</div>
|
|
388
|
+
</div>
|
|
389
|
+
</div>
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Confirmation Dialog
|
|
393
|
+
|
|
394
|
+
Use the modal base with a confirmation layout:
|
|
395
|
+
|
|
396
|
+
```html
|
|
397
|
+
<div class="ct-modal ct-modal--confirmation" data-state="open" role="dialog" aria-modal="true" aria-labelledby="confirm-title" aria-describedby="confirm-desc">
|
|
398
|
+
<div class="ct-modal__dialog">
|
|
399
|
+
<div class="ct-modal__body">
|
|
400
|
+
<div class="ct-confirmation" data-variant="danger">
|
|
401
|
+
<div class="ct-confirmation__icon" aria-hidden="true">!</div>
|
|
402
|
+
<div class="ct-confirmation__content">
|
|
403
|
+
<h2 class="ct-confirmation__title" id="confirm-title">Delete file?</h2>
|
|
404
|
+
<p class="ct-confirmation__description" id="confirm-desc">This action cannot be undone.</p>
|
|
405
|
+
</div>
|
|
406
|
+
</div>
|
|
407
|
+
</div>
|
|
408
|
+
<div class="ct-modal__footer">
|
|
409
|
+
<button class="ct-button ct-button--secondary">Cancel</button>
|
|
410
|
+
<button class="ct-button ct-button--danger">Delete</button>
|
|
411
|
+
</div>
|
|
412
|
+
</div>
|
|
413
|
+
</div>
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Skeleton / Placeholder
|
|
417
|
+
|
|
418
|
+
Use for loading placeholders:
|
|
419
|
+
|
|
420
|
+
```html
|
|
421
|
+
<div class="ct-stack" style="--ct-stack-space: var(--space-3); max-width: 320px;">
|
|
422
|
+
<span class="ct-skeleton ct-skeleton--title"></span>
|
|
423
|
+
<span class="ct-skeleton ct-skeleton--text"></span>
|
|
424
|
+
<span class="ct-skeleton ct-skeleton--text" style="--ct-skeleton-width: 70%;"></span>
|
|
425
|
+
</div>
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### Tabs
|
|
429
|
+
|
|
430
|
+
Tab navigation with panels:
|
|
431
|
+
|
|
432
|
+
```html
|
|
433
|
+
<div class="ct-tabs">
|
|
434
|
+
<div class="ct-tabs__list" role="tablist">
|
|
435
|
+
<button class="ct-tabs__trigger" role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1" tabindex="0">Overview</button>
|
|
436
|
+
<button class="ct-tabs__trigger" role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2" tabindex="-1">Settings</button>
|
|
437
|
+
</div>
|
|
438
|
+
<div class="ct-tabs__panel" role="tabpanel" id="panel-1" aria-labelledby="tab-1">
|
|
439
|
+
<p>Panel content</p>
|
|
440
|
+
</div>
|
|
441
|
+
</div>
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### Dropdown
|
|
445
|
+
|
|
446
|
+
Action menu:
|
|
447
|
+
|
|
448
|
+
```html
|
|
449
|
+
<div class="ct-dropdown" data-state="open">
|
|
450
|
+
<button class="ct-button ct-button--secondary ct-dropdown__trigger" aria-expanded="true" aria-controls="menu">Actions</button>
|
|
451
|
+
<div class="ct-dropdown__menu" id="menu">
|
|
452
|
+
<button class="ct-dropdown__item" type="button">Edit</button>
|
|
453
|
+
<button class="ct-dropdown__item" type="button">Duplicate</button>
|
|
454
|
+
<div class="ct-dropdown__separator" role="separator"></div>
|
|
455
|
+
<button class="ct-dropdown__item" type="button">Delete</button>
|
|
456
|
+
</div>
|
|
457
|
+
</div>
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### Pagination
|
|
461
|
+
|
|
462
|
+
Page navigation:
|
|
463
|
+
|
|
464
|
+
```html
|
|
465
|
+
<nav class="ct-pagination" aria-label="Pagination">
|
|
466
|
+
<ul class="ct-pagination__list">
|
|
467
|
+
<li><button class="ct-pagination__link" type="button">1</button></li>
|
|
468
|
+
<li><button class="ct-pagination__link" aria-current="page" type="button">2</button></li>
|
|
469
|
+
<li><button class="ct-pagination__link" type="button">3</button></li>
|
|
470
|
+
</ul>
|
|
471
|
+
</nav>
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### Breadcrumbs
|
|
475
|
+
|
|
476
|
+
Path navigation:
|
|
477
|
+
|
|
478
|
+
```html
|
|
479
|
+
<nav class="ct-breadcrumbs" aria-label="Breadcrumb">
|
|
480
|
+
<ol class="ct-breadcrumbs__list">
|
|
481
|
+
<li class="ct-breadcrumbs__item">
|
|
482
|
+
<a class="ct-breadcrumbs__link" href="/">Home</a>
|
|
483
|
+
<span class="ct-breadcrumbs__separator">/</span>
|
|
484
|
+
</li>
|
|
485
|
+
<li class="ct-breadcrumbs__item">
|
|
486
|
+
<a class="ct-breadcrumbs__link" href="/projects">Projects</a>
|
|
487
|
+
<span class="ct-breadcrumbs__separator">/</span>
|
|
488
|
+
</li>
|
|
489
|
+
<li class="ct-breadcrumbs__item">
|
|
490
|
+
<span class="ct-breadcrumbs__current">Alpha</span>
|
|
491
|
+
</li>
|
|
492
|
+
</ol>
|
|
493
|
+
</nav>
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### Datepicker
|
|
497
|
+
|
|
498
|
+
Calendar popup for date selection:
|
|
499
|
+
|
|
500
|
+
```html
|
|
501
|
+
<div class="ct-field">
|
|
502
|
+
<label class="ct-field__label" for="date">Date</label>
|
|
503
|
+
<div class="ct-datepicker" data-state="open">
|
|
504
|
+
<input class="ct-input" id="date" type="text" placeholder="Select date" />
|
|
505
|
+
<div class="ct-datepicker__popover" role="dialog" aria-label="Choose date">
|
|
506
|
+
<div class="ct-datepicker__header">
|
|
507
|
+
<button class="ct-button ct-button--ghost ct-button--icon" aria-label="Previous month">‹</button>
|
|
508
|
+
<div class="ct-datepicker__title">March 2026</div>
|
|
509
|
+
<button class="ct-button ct-button--ghost ct-button--icon" aria-label="Next month">›</button>
|
|
510
|
+
</div>
|
|
511
|
+
<div class="ct-datepicker__grid">
|
|
512
|
+
<div class="ct-datepicker__weekday">Mo</div>
|
|
513
|
+
<!-- ... weekdays ... -->
|
|
514
|
+
<button class="ct-datepicker__day">1</button>
|
|
515
|
+
<button class="ct-datepicker__day" aria-selected="true">15</button>
|
|
516
|
+
<!-- ... days ... -->
|
|
517
|
+
</div>
|
|
518
|
+
</div>
|
|
519
|
+
</div>
|
|
520
|
+
</div>
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Tooltip
|
|
524
|
+
|
|
525
|
+
Hint on hover/focus:
|
|
526
|
+
|
|
527
|
+
```html
|
|
528
|
+
<span class="ct-tooltip" data-state="open" data-side="top">
|
|
529
|
+
<button class="ct-button" aria-describedby="tip-1">Hover me</button>
|
|
530
|
+
<span class="ct-tooltip__content" role="tooltip" id="tip-1">Short hint</span>
|
|
531
|
+
</span>
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
## Layout Utilities
|
|
535
|
+
|
|
536
|
+
### Stack
|
|
537
|
+
|
|
538
|
+
Vertical spacing between children:
|
|
539
|
+
|
|
540
|
+
```html
|
|
541
|
+
<div class="ct-stack" style="--ct-stack-space: var(--space-4);">
|
|
542
|
+
<div>Item 1</div>
|
|
543
|
+
<div>Item 2</div>
|
|
544
|
+
</div>
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### Cluster
|
|
548
|
+
|
|
549
|
+
Horizontal spacing with wrapping:
|
|
550
|
+
|
|
551
|
+
```html
|
|
552
|
+
<div class="ct-cluster" style="--ct-cluster-space: var(--space-3);">
|
|
553
|
+
<button>Button 1</button>
|
|
554
|
+
<button>Button 2</button>
|
|
555
|
+
</div>
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
## Text Utilities
|
|
559
|
+
|
|
560
|
+
- `ct-muted` - Muted text color
|
|
561
|
+
- `ct-truncate` - Truncate with ellipsis
|
|
562
|
+
- `ct-sr-only` - Screen reader only (visually hidden)
|
|
563
|
+
|
|
564
|
+
---
|
|
565
|
+
|
|
566
|
+
**Construct** - Build accessible design constructs
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
@keyframes ct-spin {
|
|
2
|
+
to {
|
|
3
|
+
transform: rotate(360deg);
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
@keyframes ct-skeleton {
|
|
8
|
+
0% {
|
|
9
|
+
background-position: 200% 0;
|
|
10
|
+
}
|
|
11
|
+
100% {
|
|
12
|
+
background-position: -200% 0;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@keyframes ct-progress-indeterminate {
|
|
17
|
+
0% {
|
|
18
|
+
transform: translateX(-100%);
|
|
19
|
+
}
|
|
20
|
+
100% {
|
|
21
|
+
transform: translateX(400%);
|
|
22
|
+
}
|
|
23
|
+
}
|