sunkit-ui 0.1.0-alpha.1
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/README.md +463 -0
- package/dist/components/Alert/Alert.d.ts +12 -0
- package/dist/components/Alert/index.d.ts +2 -0
- package/dist/components/Button/Button.d.ts +18 -0
- package/dist/components/Button/index.d.ts +2 -0
- package/dist/components/Card/Card.d.ts +29 -0
- package/dist/components/Card/index.d.ts +2 -0
- package/dist/components/ColorPicker/ColorPicker.d.ts +15 -0
- package/dist/components/ColorPicker/index.d.ts +2 -0
- package/dist/components/DatePicker/DatePicker.d.ts +27 -0
- package/dist/components/DatePicker/index.d.ts +2 -0
- package/dist/components/Input/Input.d.ts +22 -0
- package/dist/components/Input/index.d.ts +2 -0
- package/dist/components/Progress/Progress.d.ts +14 -0
- package/dist/components/Progress/index.d.ts +2 -0
- package/dist/components/Select/Select.d.ts +35 -0
- package/dist/components/Select/index.d.ts +2 -0
- package/dist/components/Slider/Slider.d.ts +27 -0
- package/dist/components/Slider/index.d.ts +2 -0
- package/dist/components/Textarea/Textarea.d.ts +22 -0
- package/dist/components/Textarea/index.d.ts +2 -0
- package/dist/components/Theme/ThemeProvider.d.ts +15 -0
- package/dist/components/Theme/index.d.ts +2 -0
- package/dist/components/Toggle/Toggle.d.ts +23 -0
- package/dist/components/Toggle/index.d.ts +2 -0
- package/dist/hooks/useButtonSound.d.ts +2 -0
- package/dist/hooks/useColorPickerSound.d.ts +4 -0
- package/dist/hooks/useInputSound.d.ts +2 -0
- package/dist/hooks/usePickerSound.d.ts +5 -0
- package/dist/hooks/useSelectSound.d.ts +5 -0
- package/dist/hooks/useSliderSound.d.ts +2 -0
- package/dist/hooks/useToggleSound.d.ts +2 -0
- package/dist/index.d.ts +27 -0
- package/dist/lib/accent.d.ts +17 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/sunkit.cjs +1 -0
- package/dist/sunkit.js +4028 -0
- package/dist/tokens/colors.d.ts +12 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
# sunkit
|
|
2
|
+
|
|
3
|
+
A pastel React component library with soft shadows, spring animations, and Web Audio micro-interactions.
|
|
4
|
+
|
|
5
|
+
Built with **React 19**, **Tailwind CSS v4**, and **class-variance-authority**. Zero runtime dependencies beyond React.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add sunkit
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Peer dependencies (install if not already present):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add react react-dom
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Setup
|
|
24
|
+
|
|
25
|
+
Sunkit ships a CSS file that must be imported once — it registers the Tailwind theme (pastel colour tokens) and the utility classes (`btn-shadow`, keyframe animations, etc.).
|
|
26
|
+
|
|
27
|
+
### With Tailwind CSS v4 (recommended)
|
|
28
|
+
|
|
29
|
+
Add the sunkit CSS layer to your global stylesheet:
|
|
30
|
+
|
|
31
|
+
```css
|
|
32
|
+
/* app/globals.css */
|
|
33
|
+
@import "tailwindcss";
|
|
34
|
+
@import "sunkit/dist/sunkit.css";
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Without Tailwind (standalone)
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
// main.tsx or _app.tsx
|
|
41
|
+
import 'sunkit/dist/sunkit.css'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Components
|
|
47
|
+
|
|
48
|
+
### Button
|
|
49
|
+
|
|
50
|
+
A tactile pastel button with shadow, hover brightness, press scale, and Web Audio click sound.
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { Button } from 'sunkit'
|
|
54
|
+
|
|
55
|
+
<Button color="lavender">Click me</Button>
|
|
56
|
+
<Button color="mint" size="sm" icon="left">With icon</Button>
|
|
57
|
+
<Button color="sky" size="icon-only" icon="only" aria-label="Star" />
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
| Prop | Type | Default |
|
|
61
|
+
|-------------|----------------------------------------------------------------------|--------------|
|
|
62
|
+
| `color` | `'rose'│'peach'│'lemon'│'mint'│'sky'│'lavender'│'lilac'│'neutral'` | `'lavender'` |
|
|
63
|
+
| `size` | `'default'│'sm'│'icon-only'` | `'default'` |
|
|
64
|
+
| `icon` | `'none'│'left'│'right'│'only'` | `'none'` |
|
|
65
|
+
| `iconLeft` | `ReactNode` | — |
|
|
66
|
+
| `iconRight` | `ReactNode` | — |
|
|
67
|
+
| `iconOnly` | `ReactNode` | — |
|
|
68
|
+
| `radius` | `number` (px) | `10` |
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
### Toggle
|
|
73
|
+
|
|
74
|
+
An iOS-style switch with spring knob animation and squish-on-press. Plays distinct snap sounds on/off.
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
import { Toggle } from 'sunkit'
|
|
78
|
+
|
|
79
|
+
<Toggle label="Airplane mode" tone="sky" />
|
|
80
|
+
|
|
81
|
+
// Controlled
|
|
82
|
+
const [on, setOn] = useState(false)
|
|
83
|
+
<Toggle checked={on} onCheckedChange={setOn} tone="mint" label="Notifications" />
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
| Prop | Type | Default |
|
|
87
|
+
|--------------------|-------------------------|-------------|
|
|
88
|
+
| `tone` | pastel tone | `'neutral'` |
|
|
89
|
+
| `size` | `'default'│'sm'` | `'default'` |
|
|
90
|
+
| `checked` | `boolean` | — |
|
|
91
|
+
| `defaultChecked` | `boolean` | `false` |
|
|
92
|
+
| `onCheckedChange` | `(checked: boolean) =>` | — |
|
|
93
|
+
| `label` | `ReactNode` | — |
|
|
94
|
+
| `description` | `ReactNode` | — |
|
|
95
|
+
| `disabled` | `boolean` | `false` |
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
### Input
|
|
100
|
+
|
|
101
|
+
A text input with three visually distinct variants. Plays a gentle focus chime.
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import { Input } from 'sunkit'
|
|
105
|
+
|
|
106
|
+
<Input label="Email" placeholder="you@example.com" tone="lavender" />
|
|
107
|
+
<Input variant="filled" label="Search" placeholder="Search…" />
|
|
108
|
+
<Input variant="ghost" label="Notes" placeholder="Type anything…" />
|
|
109
|
+
|
|
110
|
+
// With adornments
|
|
111
|
+
<Input
|
|
112
|
+
label="Amount"
|
|
113
|
+
leftAdornment={<span>$</span>}
|
|
114
|
+
rightAdornment={<span>USD</span>}
|
|
115
|
+
/>
|
|
116
|
+
|
|
117
|
+
// With error
|
|
118
|
+
<Input label="Email" error="Please enter a valid email." tone="rose" />
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
| Prop | Type | Default |
|
|
122
|
+
|--------------------|-----------------------------------|--------------|
|
|
123
|
+
| `variant` | `'default'│'filled'│'ghost'` | `'default'` |
|
|
124
|
+
| `tone` | pastel tone | `'neutral'` |
|
|
125
|
+
| `size` | `'default'│'sm'` | `'default'` |
|
|
126
|
+
| `label` | `ReactNode` | — |
|
|
127
|
+
| `description` | `ReactNode` | — |
|
|
128
|
+
| `error` | `ReactNode` | — |
|
|
129
|
+
| `leftAdornment` | `ReactNode` | — |
|
|
130
|
+
| `rightAdornment` | `ReactNode` | — |
|
|
131
|
+
| `radius` | `number` (px) | `12` |
|
|
132
|
+
| `invalid` | `boolean` | auto |
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
### Select
|
|
137
|
+
|
|
138
|
+
A custom dropdown (no native `<select>`) with keyboard navigation, optional search, and matching Input variants.
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
import { Select } from 'sunkit'
|
|
142
|
+
|
|
143
|
+
const options = [
|
|
144
|
+
{ value: 'apple', label: 'Apple' },
|
|
145
|
+
{ value: 'mango', label: 'Mango' },
|
|
146
|
+
{ value: 'lemon', label: 'Lemon', disabled: true },
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
<Select options={options} label="Fruit" placeholder="Pick one…" tone="peach" />
|
|
150
|
+
<Select options={options} searchable label="Search & select" />
|
|
151
|
+
|
|
152
|
+
// Controlled
|
|
153
|
+
const [val, setVal] = useState('')
|
|
154
|
+
<Select options={options} value={val} onChange={setVal} />
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
| Prop | Type | Default |
|
|
158
|
+
|---------------|------------------------------|--------------|
|
|
159
|
+
| `options` | `SelectOption[]` (required) | — |
|
|
160
|
+
| `value` | `string` | — |
|
|
161
|
+
| `defaultValue`| `string` | — |
|
|
162
|
+
| `onChange` | `(value: string) => void` | — |
|
|
163
|
+
| `placeholder` | `string` | `'Select…'` |
|
|
164
|
+
| `searchable` | `boolean` | `false` |
|
|
165
|
+
| `variant` | `'default'│'filled'│'ghost'` | `'default'` |
|
|
166
|
+
| `tone` | pastel tone | `'neutral'` |
|
|
167
|
+
| `size` | `'default'│'sm'` | `'default'` |
|
|
168
|
+
| `label` | `ReactNode` | — |
|
|
169
|
+
| `description` | `ReactNode` | — |
|
|
170
|
+
| `error` | `ReactNode` | — |
|
|
171
|
+
| `disabled` | `boolean` | `false` |
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
### Slider
|
|
176
|
+
|
|
177
|
+
A styled range input with a spring-animated thumb that squishes on press. Emits pitched scrub sounds.
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
import { Slider } from 'sunkit'
|
|
181
|
+
|
|
182
|
+
<Slider label="Volume" min={0} max={100} defaultValue={50} tone="lavender" showValue />
|
|
183
|
+
|
|
184
|
+
// With marks
|
|
185
|
+
<Slider
|
|
186
|
+
label="Quality"
|
|
187
|
+
min={0} max={100} step={25}
|
|
188
|
+
marks={[
|
|
189
|
+
{ value: 0, label: 'Low' },
|
|
190
|
+
{ value: 50, label: 'Med' },
|
|
191
|
+
{ value: 100, label: 'High' },
|
|
192
|
+
]}
|
|
193
|
+
/>
|
|
194
|
+
|
|
195
|
+
// Controlled
|
|
196
|
+
const [val, setVal] = useState(40)
|
|
197
|
+
<Slider value={val} onValueChange={setVal} tone="mint" />
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
| Prop | Type | Default |
|
|
201
|
+
|-----------------|------------------------------|--------------|
|
|
202
|
+
| `min` | `number` | `0` |
|
|
203
|
+
| `max` | `number` | `100` |
|
|
204
|
+
| `step` | `number` | `1` |
|
|
205
|
+
| `value` | `number` | — |
|
|
206
|
+
| `defaultValue` | `number` | `0` |
|
|
207
|
+
| `onValueChange` | `(value: number) => void` | — |
|
|
208
|
+
| `tone` | pastel tone | `'lavender'` |
|
|
209
|
+
| `size` | `'default'│'sm'` | `'default'` |
|
|
210
|
+
| `label` | `ReactNode` | — |
|
|
211
|
+
| `description` | `ReactNode` | — |
|
|
212
|
+
| `showValue` | `boolean` | `false` |
|
|
213
|
+
| `marks` | `{ value: number; label?: string }[]` | — |
|
|
214
|
+
| `disabled` | `boolean` | `false` |
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
### Textarea
|
|
219
|
+
|
|
220
|
+
A multi-line text input that matches Input's variants and tones. Supports auto-resize and character count.
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
import { Textarea } from 'sunkit'
|
|
224
|
+
|
|
225
|
+
<Textarea label="Message" rows={4} tone="sky" />
|
|
226
|
+
<Textarea variant="filled" autoResize label="Notes" />
|
|
227
|
+
<Textarea maxLength={200} showCount label="Bio" />
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
| Prop | Type | Default |
|
|
231
|
+
|---------------|------------------------------|-------------|
|
|
232
|
+
| `variant` | `'default'│'filled'│'ghost'` | `'default'` |
|
|
233
|
+
| `tone` | pastel tone | `'neutral'` |
|
|
234
|
+
| `label` | `ReactNode` | — |
|
|
235
|
+
| `description` | `ReactNode` | — |
|
|
236
|
+
| `error` | `ReactNode` | — |
|
|
237
|
+
| `rows` | `number` | `4` |
|
|
238
|
+
| `autoResize` | `boolean` | `false` |
|
|
239
|
+
| `showCount` | `boolean` | `false` |
|
|
240
|
+
| `maxLength` | `number` | — |
|
|
241
|
+
| `radius` | `number` (px) | `12` |
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
### Progress
|
|
246
|
+
|
|
247
|
+
A progress bar with determinate and indeterminate states.
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
import { Progress } from 'sunkit'
|
|
251
|
+
|
|
252
|
+
<Progress value={65} tone="lavender" label="Uploading…" showValue />
|
|
253
|
+
<Progress tone="sky" label="Loading…" /> {/* indeterminate */}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
| Prop | Type | Default |
|
|
257
|
+
|-------------|----------------------------|--------------|
|
|
258
|
+
| `value` | `number` (0–100) | indeterminate if omitted |
|
|
259
|
+
| `tone` | pastel tone | `'lavender'` |
|
|
260
|
+
| `size` | `'sm'│'default'│'lg'` | `'default'` |
|
|
261
|
+
| `label` | `ReactNode` | — |
|
|
262
|
+
| `showValue` | `boolean` | `false` |
|
|
263
|
+
| `animated` | `boolean` | `true` |
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
### Card
|
|
268
|
+
|
|
269
|
+
A versatile container with elevated, filled, and outline variants. Includes `Card.Header`, `Card.Body`, and `Card.Footer`.
|
|
270
|
+
|
|
271
|
+
```tsx
|
|
272
|
+
import { Card } from 'sunkit'
|
|
273
|
+
|
|
274
|
+
<Card tone="lavender" variant="elevated" style={{ maxWidth: 360 }}>
|
|
275
|
+
<Card.Header>
|
|
276
|
+
<h3>Title</h3>
|
|
277
|
+
</Card.Header>
|
|
278
|
+
<Card.Body>
|
|
279
|
+
<p>Body content here.</p>
|
|
280
|
+
</Card.Body>
|
|
281
|
+
<Card.Footer>
|
|
282
|
+
<Button size="sm" color="lavender">Action</Button>
|
|
283
|
+
</Card.Footer>
|
|
284
|
+
</Card>
|
|
285
|
+
|
|
286
|
+
{/* Simple card with inline padding */}
|
|
287
|
+
<Card tone="mint" variant="filled" padding={24}>
|
|
288
|
+
<p>No subcomponents needed.</p>
|
|
289
|
+
</Card>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
| Prop | Type | Default |
|
|
293
|
+
|------------|-----------------------------------|--------------|
|
|
294
|
+
| `variant` | `'elevated'│'filled'│'outline'` | `'elevated'` |
|
|
295
|
+
| `tone` | pastel tone | `'neutral'` |
|
|
296
|
+
| `radius` | `number` (px) | `16` |
|
|
297
|
+
| `padding` | `number│string` | — |
|
|
298
|
+
| `as` | `ElementType` | `'div'` |
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
### ColorPicker
|
|
303
|
+
|
|
304
|
+
A swatch palette for picking one of the 8 pastel tones. Each color plays a unique pitched pluck.
|
|
305
|
+
|
|
306
|
+
```tsx
|
|
307
|
+
import { ColorPicker } from 'sunkit'
|
|
308
|
+
import type { ButtonColor } from 'sunkit'
|
|
309
|
+
|
|
310
|
+
<ColorPicker label="Theme colour" defaultValue="lavender" />
|
|
311
|
+
|
|
312
|
+
// Controlled
|
|
313
|
+
const [color, setColor] = useState<ButtonColor>('sky')
|
|
314
|
+
<ColorPicker value={color} onChange={setColor} />
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
| Prop | Type | Default |
|
|
318
|
+
|----------------|-------------------------------|-------------|
|
|
319
|
+
| `value` | `ButtonColor` | — |
|
|
320
|
+
| `defaultValue` | `ButtonColor` | — |
|
|
321
|
+
| `onChange` | `(value: ButtonColor) => void`| — |
|
|
322
|
+
| `size` | `'default'│'sm'` | `'default'` |
|
|
323
|
+
| `label` | `ReactNode` | — |
|
|
324
|
+
| `description` | `ReactNode` | — |
|
|
325
|
+
| `disabled` | `boolean` | `false` |
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
### DatePicker
|
|
330
|
+
|
|
331
|
+
A fully custom calendar popover — no external dependencies. Full keyboard navigation and min/max date support.
|
|
332
|
+
|
|
333
|
+
```tsx
|
|
334
|
+
import { DatePicker } from 'sunkit'
|
|
335
|
+
|
|
336
|
+
<DatePicker label="Start date" tone="lavender" />
|
|
337
|
+
|
|
338
|
+
// Controlled
|
|
339
|
+
const [date, setDate] = useState<Date | null>(null)
|
|
340
|
+
<DatePicker value={date} onChange={setDate} />
|
|
341
|
+
|
|
342
|
+
// With constraints
|
|
343
|
+
<DatePicker
|
|
344
|
+
minDate={new Date()}
|
|
345
|
+
maxDate={new Date(Date.now() + 30 * 86400000)}
|
|
346
|
+
label="Appointment"
|
|
347
|
+
/>
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
| Prop | Type | Default |
|
|
351
|
+
|----------------|-------------------------------|------------------|
|
|
352
|
+
| `value` | `Date│null` | — |
|
|
353
|
+
| `defaultValue` | `Date│null` | `null` |
|
|
354
|
+
| `onChange` | `(date: Date│null) => void` | — |
|
|
355
|
+
| `minDate` | `Date` | — |
|
|
356
|
+
| `maxDate` | `Date` | — |
|
|
357
|
+
| `tone` | pastel tone | `'lavender'` |
|
|
358
|
+
| `size` | `'default'│'sm'` | `'default'` |
|
|
359
|
+
| `placeholder` | `string` | `'Pick a date…'` |
|
|
360
|
+
| `label` | `ReactNode` | — |
|
|
361
|
+
| `description` | `ReactNode` | — |
|
|
362
|
+
| `disabled` | `boolean` | `false` |
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
### Alert
|
|
367
|
+
|
|
368
|
+
An animated feedback strip for info, success, warning, and error states.
|
|
369
|
+
|
|
370
|
+
```tsx
|
|
371
|
+
import { Alert } from 'sunkit'
|
|
372
|
+
|
|
373
|
+
<Alert variant="success" title="Saved!" dismissable>
|
|
374
|
+
Your changes have been saved.
|
|
375
|
+
</Alert>
|
|
376
|
+
|
|
377
|
+
<Alert variant="error">Something went wrong. Please try again.</Alert>
|
|
378
|
+
|
|
379
|
+
// Custom icon
|
|
380
|
+
<Alert variant="info" icon={<MyIcon />} title="Note">
|
|
381
|
+
Custom icon support.
|
|
382
|
+
</Alert>
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
| Prop | Type | Default |
|
|
386
|
+
|---------------|-----------------------------------------|------------|
|
|
387
|
+
| `variant` | `'info'│'success'│'warning'│'error'` | `'info'` |
|
|
388
|
+
| `title` | `ReactNode` | — |
|
|
389
|
+
| `children` | `ReactNode` | — |
|
|
390
|
+
| `dismissable` | `boolean` | `false` |
|
|
391
|
+
| `onDismiss` | `() => void` | — |
|
|
392
|
+
| `icon` | `ReactNode` | auto |
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## Pastel tones
|
|
397
|
+
|
|
398
|
+
All toned components accept a `tone` prop from this palette:
|
|
399
|
+
|
|
400
|
+
| Token | Light | Dark |
|
|
401
|
+
|-------------|--------------------|--------------------|
|
|
402
|
+
| `rose` | `#F9C5D1` | `#c2607a` |
|
|
403
|
+
| `peach` | `#FDDBB4` | `#b87a3a` |
|
|
404
|
+
| `lemon` | `#FFF1A8` | `#8a7820` |
|
|
405
|
+
| `mint` | `#B8F0D8` | `#2a7a58` |
|
|
406
|
+
| `sky` | `#B8DFFE` | `#2a68a0` |
|
|
407
|
+
| `lavender` | `#D4C5F9` | `#5a3eaa` |
|
|
408
|
+
| `lilac` | `#F0C8F0` | `#8a3a8a` |
|
|
409
|
+
| `neutral` | `#E8E4DC` | `#5a5550` |
|
|
410
|
+
|
|
411
|
+
Import the token list directly:
|
|
412
|
+
|
|
413
|
+
```ts
|
|
414
|
+
import { COLORS, COLOR_MAP } from 'sunkit'
|
|
415
|
+
|
|
416
|
+
COLORS // ColorToken[] — array of all tones
|
|
417
|
+
COLOR_MAP // Record<ButtonColor, { hex, darkHex }>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Sound design
|
|
423
|
+
|
|
424
|
+
Every interactive component has its own sonic identity using the Web Audio API. All sounds are synthesised at runtime — no audio files required, and they respect system `prefers-reduced-motion` preferences in future releases.
|
|
425
|
+
|
|
426
|
+
| Component | Sound |
|
|
427
|
+
|--------------|-------------------------------------------------|
|
|
428
|
+
| Button | Soft sine press + bright triangle release |
|
|
429
|
+
| Toggle | Ascending double-click (on) / descending (off) |
|
|
430
|
+
| Input | Descending sine "ting" on focus |
|
|
431
|
+
| Textarea | Same as Input |
|
|
432
|
+
| Select | Airy pop on open, crisp tick on select |
|
|
433
|
+
| Slider | Pitched scrub — frequency maps to value |
|
|
434
|
+
| ColorPicker | Soft pluck, pitch varies per tone |
|
|
435
|
+
| DatePicker | Whoosh on month nav, ting on date select |
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## Storybook
|
|
440
|
+
|
|
441
|
+
Browse all components interactively:
|
|
442
|
+
|
|
443
|
+
```bash
|
|
444
|
+
pnpm run storybook
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
Opens at [http://localhost:6006](http://localhost:6006).
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## Build
|
|
452
|
+
|
|
453
|
+
```bash
|
|
454
|
+
pnpm run build
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
Outputs to `dist/` — an ES module, CJS bundle, and `.d.ts` type declarations.
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## License
|
|
462
|
+
|
|
463
|
+
MIT
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export type AlertVariant = 'info' | 'success' | 'warning' | 'error';
|
|
3
|
+
export interface AlertProps {
|
|
4
|
+
variant?: AlertVariant;
|
|
5
|
+
title?: ReactNode;
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
dismissable?: boolean;
|
|
8
|
+
onDismiss?: () => void;
|
|
9
|
+
icon?: ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function Alert({ variant, title, children, dismissable, onDismiss, icon, className, }: AlertProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ButtonHTMLAttributes, ReactNode, Ref } from 'react';
|
|
2
|
+
import { ButtonColor } from '../../tokens/colors';
|
|
3
|
+
export type { ButtonColor };
|
|
4
|
+
export type ButtonSize = 'default' | 'sm' | 'icon-only';
|
|
5
|
+
export type ButtonIconPosition = 'none' | 'left' | 'right' | 'only';
|
|
6
|
+
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
7
|
+
ref?: Ref<HTMLButtonElement>;
|
|
8
|
+
color?: ButtonColor;
|
|
9
|
+
accentColor?: string;
|
|
10
|
+
size?: ButtonSize;
|
|
11
|
+
icon?: ButtonIconPosition;
|
|
12
|
+
iconLeft?: ReactNode;
|
|
13
|
+
iconRight?: ReactNode;
|
|
14
|
+
iconOnly?: ReactNode;
|
|
15
|
+
radius?: number;
|
|
16
|
+
children?: ReactNode;
|
|
17
|
+
}
|
|
18
|
+
export declare function Button({ ref: externalRef, color, accentColor: accentColorProp, size, icon, iconLeft, iconRight, iconOnly, radius, children, className, style, ...rest }: ButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ElementType, ReactNode, HTMLAttributes } from 'react';
|
|
2
|
+
import { VariantProps } from 'class-variance-authority';
|
|
3
|
+
declare const cardVariants: (props?: ({
|
|
4
|
+
variant?: "filled" | "elevated" | "outline" | null | undefined;
|
|
5
|
+
tone?: "custom" | "rose" | "peach" | "lemon" | "mint" | "sky" | "lavender" | "lilac" | "neutral" | null | undefined;
|
|
6
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
7
|
+
export type CardTone = NonNullable<VariantProps<typeof cardVariants>['tone']>;
|
|
8
|
+
export type CardVariant = NonNullable<VariantProps<typeof cardVariants>['variant']>;
|
|
9
|
+
export interface CardProps extends HTMLAttributes<HTMLElement>, Omit<VariantProps<typeof cardVariants>, 'tone'> {
|
|
10
|
+
tone?: CardTone | (string & {});
|
|
11
|
+
accentColor?: string;
|
|
12
|
+
as?: ElementType;
|
|
13
|
+
radius?: number;
|
|
14
|
+
padding?: number | string;
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
}
|
|
17
|
+
export declare function Card({ as: As, variant, tone, accentColor: accentColorProp, radius, padding, className, style, children, ...rest }: CardProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export declare namespace Card {
|
|
19
|
+
var Header: typeof CardHeader;
|
|
20
|
+
var Body: typeof CardBody;
|
|
21
|
+
var Footer: typeof CardFooter;
|
|
22
|
+
}
|
|
23
|
+
interface CardSectionProps extends HTMLAttributes<HTMLDivElement> {
|
|
24
|
+
children?: ReactNode;
|
|
25
|
+
}
|
|
26
|
+
declare function CardHeader({ className, children, ...rest }: CardSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
declare function CardBody({ className, children, ...rest }: CardSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
declare function CardFooter({ className, children, ...rest }: CardSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ButtonColor } from '../../tokens/colors';
|
|
3
|
+
export type ColorPickerSize = 'default' | 'sm';
|
|
4
|
+
export interface ColorPickerProps {
|
|
5
|
+
value?: ButtonColor;
|
|
6
|
+
defaultValue?: ButtonColor;
|
|
7
|
+
onChange?: (value: ButtonColor) => void;
|
|
8
|
+
size?: ColorPickerSize;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
label?: ReactNode;
|
|
11
|
+
description?: ReactNode;
|
|
12
|
+
className?: string;
|
|
13
|
+
id?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function ColorPicker({ value: valueProp, defaultValue, onChange, size, disabled, label, description, className, id, }: ColorPickerProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { default as React, ReactNode } from 'react';
|
|
2
|
+
export type DatePickerTone = 'rose' | 'peach' | 'lemon' | 'mint' | 'sky' | 'lavender' | 'lilac' | 'neutral';
|
|
3
|
+
export type DatePickerSize = 'default' | 'sm';
|
|
4
|
+
export type DatePickerMode = 'single' | 'range';
|
|
5
|
+
export type DateRange = [Date | null, Date | null];
|
|
6
|
+
export interface DatePickerProps {
|
|
7
|
+
mode?: DatePickerMode;
|
|
8
|
+
value?: Date | null;
|
|
9
|
+
defaultValue?: Date | null;
|
|
10
|
+
onChange?: (date: Date | null) => void;
|
|
11
|
+
rangeValue?: DateRange;
|
|
12
|
+
defaultRangeValue?: DateRange;
|
|
13
|
+
onRangeChange?: (range: DateRange) => void;
|
|
14
|
+
minDate?: Date;
|
|
15
|
+
maxDate?: Date;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
label?: ReactNode;
|
|
18
|
+
description?: ReactNode;
|
|
19
|
+
tone?: DatePickerTone;
|
|
20
|
+
accentColor?: string;
|
|
21
|
+
size?: DatePickerSize;
|
|
22
|
+
placeholder?: string;
|
|
23
|
+
id?: string;
|
|
24
|
+
className?: string;
|
|
25
|
+
containerClassName?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare const DatePicker: React.ForwardRefExoticComponent<DatePickerProps & React.RefAttributes<HTMLInputElement>>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { default as React, InputHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { VariantProps } from 'class-variance-authority';
|
|
3
|
+
declare const inputVariants: (props?: ({
|
|
4
|
+
variant?: "default" | "filled" | "ghost" | null | undefined;
|
|
5
|
+
tone?: "custom" | "rose" | "peach" | "lemon" | "mint" | "sky" | "lavender" | "lilac" | "neutral" | null | undefined;
|
|
6
|
+
size?: "default" | "sm" | null | undefined;
|
|
7
|
+
invalid?: boolean | null | undefined;
|
|
8
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
9
|
+
export type InputVariantProps = VariantProps<typeof inputVariants>;
|
|
10
|
+
export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'>, Omit<InputVariantProps, 'tone'> {
|
|
11
|
+
tone?: NonNullable<InputVariantProps['tone']> | (string & {});
|
|
12
|
+
accentColor?: string;
|
|
13
|
+
label?: ReactNode;
|
|
14
|
+
description?: ReactNode;
|
|
15
|
+
error?: ReactNode;
|
|
16
|
+
radius?: number;
|
|
17
|
+
leftAdornment?: ReactNode;
|
|
18
|
+
rightAdornment?: ReactNode;
|
|
19
|
+
containerClassName?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export type ProgressTone = 'rose' | 'peach' | 'lemon' | 'mint' | 'sky' | 'lavender' | 'lilac' | 'neutral';
|
|
3
|
+
export type ProgressSize = 'sm' | 'default' | 'lg';
|
|
4
|
+
export interface ProgressProps {
|
|
5
|
+
value?: number;
|
|
6
|
+
tone?: ProgressTone;
|
|
7
|
+
accentColor?: string;
|
|
8
|
+
size?: ProgressSize;
|
|
9
|
+
label?: ReactNode;
|
|
10
|
+
showValue?: boolean;
|
|
11
|
+
animated?: boolean;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function Progress({ value, tone, accentColor: accentColorProp, size, label, showValue, animated, className, }: ProgressProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { default as React, ReactNode } from 'react';
|
|
2
|
+
import { VariantProps } from 'class-variance-authority';
|
|
3
|
+
export interface SelectOption {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
declare const triggerVariants: (props?: ({
|
|
9
|
+
variant?: "default" | "filled" | "ghost" | null | undefined;
|
|
10
|
+
tone?: "custom" | "rose" | "peach" | "lemon" | "mint" | "sky" | "lavender" | "lilac" | "neutral" | null | undefined;
|
|
11
|
+
size?: "default" | "sm" | null | undefined;
|
|
12
|
+
invalid?: boolean | null | undefined;
|
|
13
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
14
|
+
export type SelectVariantProps = VariantProps<typeof triggerVariants>;
|
|
15
|
+
export interface SelectProps extends Omit<SelectVariantProps, 'tone'> {
|
|
16
|
+
tone?: NonNullable<SelectVariantProps['tone']> | (string & {});
|
|
17
|
+
accentColor?: string;
|
|
18
|
+
options: SelectOption[];
|
|
19
|
+
value?: string;
|
|
20
|
+
defaultValue?: string;
|
|
21
|
+
onChange?: (value: string) => void;
|
|
22
|
+
placeholder?: string;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
searchable?: boolean;
|
|
25
|
+
label?: ReactNode;
|
|
26
|
+
description?: ReactNode;
|
|
27
|
+
error?: ReactNode;
|
|
28
|
+
radius?: number;
|
|
29
|
+
id?: string;
|
|
30
|
+
'aria-describedby'?: string;
|
|
31
|
+
containerClassName?: string;
|
|
32
|
+
className?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare const Select: React.ForwardRefExoticComponent<SelectProps & React.RefAttributes<HTMLButtonElement>>;
|
|
35
|
+
export {};
|