@julien-wiegandt/open-ui 0.3.0 → 0.3.2
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 +514 -0
- package/dist/components/button/index.d.ts +1 -1
- package/dist/components/utils/use-auto-contrast-color.d.ts +2 -0
- package/dist/open-ui.js +3225 -3327
- package/dist/open-ui.umd.cjs +74 -74
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
# open-ui
|
|
2
|
+
|
|
3
|
+
Simple lightweight UI components for React.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @julien-wiegandt/open-ui
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Wrap your app with the `OpenUIProvider` and pass at least one theme:
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { OpenUIProvider, createTheme } from "@julien-wiegandt/open-ui";
|
|
15
|
+
|
|
16
|
+
const theme = createTheme({
|
|
17
|
+
radius: "md",
|
|
18
|
+
primary: "#6090fa",
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
function App() {
|
|
22
|
+
return (
|
|
23
|
+
<OpenUIProvider themes={[theme]}>
|
|
24
|
+
<MyApp />
|
|
25
|
+
</OpenUIProvider>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Components
|
|
31
|
+
|
|
32
|
+
### Button
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
<Button variant="contained" color="primary" label="Click me" />
|
|
36
|
+
|
|
37
|
+
<Button variant="outlined" color="secondary" label="Outlined" />
|
|
38
|
+
|
|
39
|
+
<Button
|
|
40
|
+
variant="contained"
|
|
41
|
+
color="primary"
|
|
42
|
+
label="Submit"
|
|
43
|
+
starticon="sparkles"
|
|
44
|
+
size="lg"
|
|
45
|
+
onClick={async () => { await submitForm(); }}
|
|
46
|
+
/>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
| Prop | Type | Default | Description |
|
|
50
|
+
| -------------- | ------------------------------------------------------------ | ------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
51
|
+
| `label` | `string` | — | Button text |
|
|
52
|
+
| `variant` | `"contained" \| "outlined" \| "text"` | theme default | Visual style |
|
|
53
|
+
| `color` | `"default" \| "primary" \| "secondary" \| "error" \| string` | theme default | Color token or hex |
|
|
54
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Button size |
|
|
55
|
+
| `starticon` | `ReactNode \| Icon` | — | Icon before label (`"bell"`, `"check"`, `"heart"`, `"sync"`, `"sparkles"`, `"dots"`, `"send"`, `"copy"`, `"hamburger"`) |
|
|
56
|
+
| `endicon` | `ReactNode \| Icon` | — | Icon after label |
|
|
57
|
+
| `loading` | `boolean` | — | Show loading state |
|
|
58
|
+
| `endanimation` | `boolean` | — | Show check icon on completion |
|
|
59
|
+
| `radius` | `Radius` | theme default | Border radius |
|
|
60
|
+
| `disabled` | `boolean` | `false` | Disable button |
|
|
61
|
+
| `w` | `string` | — | Width |
|
|
62
|
+
| `h` | `string` | — | Height |
|
|
63
|
+
| `align` | `"left" \| "center" \| "right"` | — | Text alignment |
|
|
64
|
+
|
|
65
|
+
### Checkbox
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
<Checkbox label="Accept terms" color="primary" />
|
|
69
|
+
|
|
70
|
+
<Checkbox
|
|
71
|
+
checked={isChecked}
|
|
72
|
+
onChange={(checked) => setIsChecked(checked)}
|
|
73
|
+
label="Remember me"
|
|
74
|
+
labelPosition="right"
|
|
75
|
+
size="lg"
|
|
76
|
+
/>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
| Prop | Type | Default | Description |
|
|
80
|
+
| ---------------- | ---------------------------- | --------- | ---------------------------- |
|
|
81
|
+
| `checked` | `boolean` | — | Controlled state |
|
|
82
|
+
| `defaultChecked` | `boolean` | `false` | Initial state (uncontrolled) |
|
|
83
|
+
| `onChange` | `(checked: boolean) => void` | — | Change handler |
|
|
84
|
+
| `label` | `string` | — | Label text |
|
|
85
|
+
| `labelPosition` | `"left" \| "right"` | `"right"` | Label placement |
|
|
86
|
+
| `color` | `Color \| string` | — | Check color |
|
|
87
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Checkbox size |
|
|
88
|
+
| `disabled` | `boolean` | `false` | Disable checkbox |
|
|
89
|
+
|
|
90
|
+
### Chip
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<Chip label="Tag" color="primary" variant="contained" />
|
|
94
|
+
|
|
95
|
+
<Chip label="Status" color="secondary" variant="outlined" startIcon={<MyIcon />} />
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
| Prop | Type | Default | Description |
|
|
99
|
+
| ----------- | ------------------------------------- | ------------- | ------------------ |
|
|
100
|
+
| `label` | `string` | — | Chip text |
|
|
101
|
+
| `variant` | `"contained" \| "outlined" \| "text"` | theme default | Visual style |
|
|
102
|
+
| `color` | `Color \| string` | — | Color token or hex |
|
|
103
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Chip size |
|
|
104
|
+
| `startIcon` | `ReactNode` | — | Icon before label |
|
|
105
|
+
| `endIcon` | `ReactNode` | — | Icon after label |
|
|
106
|
+
| `radius` | `Radius` | theme default | Border radius |
|
|
107
|
+
|
|
108
|
+
### Divider
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
<Divider />
|
|
112
|
+
|
|
113
|
+
<Divider orientation="vertical" color="#ccc" type="dashed" size="md" />
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
| Prop | Type | Default | Description |
|
|
117
|
+
| ------------- | --------------------------------------------- | -------------- | --------------------------- |
|
|
118
|
+
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Divider direction |
|
|
119
|
+
| `color` | `string` | `"black"` | Line color |
|
|
120
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"sm"` | Thickness (1px / 2px / 3px) |
|
|
121
|
+
| `type` | `"solid" \| "dotted" \| "dashed" \| "double"` | `"solid"` | Line style |
|
|
122
|
+
|
|
123
|
+
### Flex
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
<Flex direction="row" align="center" justify="between" gap={16}>
|
|
127
|
+
<Text>Left</Text>
|
|
128
|
+
<Text>Right</Text>
|
|
129
|
+
</Flex>
|
|
130
|
+
|
|
131
|
+
<Flex direction="column" gap={8} elevation={2} p={16}>
|
|
132
|
+
<Text>Card content</Text>
|
|
133
|
+
</Flex>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
| Prop | Type | Default | Description |
|
|
137
|
+
| ----------- | ------------------------------------------------------------------- | ---------- | -------------------- |
|
|
138
|
+
| `direction` | `"row" \| "column" \| "row-reverse" \| "column-reverse"` | `"column"` | Flex direction |
|
|
139
|
+
| `align` | `"normal" \| "center" \| "start" \| "end" \| "stretch"` | — | Align items |
|
|
140
|
+
| `justify` | `"center" \| "start" \| "end" \| "between" \| "around" \| "evenly"` | — | Justify content |
|
|
141
|
+
| `gap` | `string \| number` | — | Gap between children |
|
|
142
|
+
| `wrap` | `"nowrap" \| "wrap" \| "wrap-reverse"` | — | Flex wrap |
|
|
143
|
+
| `width` | `string` | — | Container width |
|
|
144
|
+
| `height` | `string` | — | Container height |
|
|
145
|
+
| `elevation` | `number` | — | Box shadow depth |
|
|
146
|
+
|
|
147
|
+
### Image
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
<Image src="/photo.jpg" alt="Photo" hoverstyle={{ transform: "scale(1.05)" }} />
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
| Prop | Type | Default | Description |
|
|
154
|
+
| ------------ | --------------- | ------- | --------------- |
|
|
155
|
+
| `hoverstyle` | `CSSProperties` | — | Styles on hover |
|
|
156
|
+
| `pressstyle` | `CSSProperties` | — | Styles on press |
|
|
157
|
+
|
|
158
|
+
Extends all standard `<img>` attributes.
|
|
159
|
+
|
|
160
|
+
### Input
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
<Input label="Email" placeholder="you@example.com" color="primary" required />
|
|
164
|
+
|
|
165
|
+
<Input label="Password" type="password" error="Password is required" />
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
| Prop | Type | Default | Description |
|
|
169
|
+
| ---------- | ----------------- | ----------- | ------------------------- |
|
|
170
|
+
| `label` | `string` | — | Label text |
|
|
171
|
+
| `color` | `Color \| string` | `"default"` | Focus/border color |
|
|
172
|
+
| `error` | `string` | — | Error message below input |
|
|
173
|
+
| `required` | `boolean` | — | Shows required asterisk |
|
|
174
|
+
| `w` | `string` | — | Width |
|
|
175
|
+
| `h` | `string` | — | Height |
|
|
176
|
+
|
|
177
|
+
Extends all standard `<input>` attributes.
|
|
178
|
+
|
|
179
|
+
### Modal
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
183
|
+
|
|
184
|
+
<Button label="Open modal" onClick={() => setIsOpen(true)} />
|
|
185
|
+
|
|
186
|
+
<Modal
|
|
187
|
+
isOpen={isOpen}
|
|
188
|
+
onClose={() => setIsOpen(false)}
|
|
189
|
+
title="Confirmation"
|
|
190
|
+
size="m"
|
|
191
|
+
footer={<Button label="Confirm" color="primary" variant="contained" />}
|
|
192
|
+
>
|
|
193
|
+
<Text>Are you sure you want to proceed?</Text>
|
|
194
|
+
</Modal>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
| Prop | Type | Default | Description |
|
|
198
|
+
| --------------------- | ----------------------------------- | ------- | --------------------------------- |
|
|
199
|
+
| `isOpen` | `boolean` | — | **Required.** Controls visibility |
|
|
200
|
+
| `onClose` | `() => void` | — | Close callback |
|
|
201
|
+
| `title` | `ReactNode` | — | Modal title |
|
|
202
|
+
| `size` | `"xs" \| "s" \| "m" \| "l" \| "xl"` | `"m"` | Modal width (30vw–70vw) |
|
|
203
|
+
| `fullScreen` | `boolean` | — | Full screen mode |
|
|
204
|
+
| `footer` | `ReactNode` | — | Footer content |
|
|
205
|
+
| `close` | `ReactNode` | — | Custom close button |
|
|
206
|
+
| `closeOnClickOutside` | `boolean` | `true` | Close on backdrop click |
|
|
207
|
+
|
|
208
|
+
### Popover
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
<Popover
|
|
212
|
+
content={<Text>Popover content</Text>}
|
|
213
|
+
color="primary"
|
|
214
|
+
placement="bottom"
|
|
215
|
+
>
|
|
216
|
+
<Button label="Hover me" />
|
|
217
|
+
</Popover>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
| Prop | Type | Default | Description |
|
|
221
|
+
| ------------ | ---------------------------------------- | ------------- | ------------------------------ |
|
|
222
|
+
| `content` | `ReactNode` | — | **Required.** Popover content |
|
|
223
|
+
| `color` | `Color \| string` | — | **Required.** Background color |
|
|
224
|
+
| `placement` | `"top" \| "bottom" \| "left" \| "right"` | `"top"` | Position relative to trigger |
|
|
225
|
+
| `visible` | `boolean` | — | Controlled visibility |
|
|
226
|
+
| `gap` | `number` | `8` | Distance from trigger (px) |
|
|
227
|
+
| `radius` | `Radius` | theme default | Border radius |
|
|
228
|
+
| `arrowcolor` | `string` | — | Arrow color override |
|
|
229
|
+
|
|
230
|
+
### ProgressBar
|
|
231
|
+
|
|
232
|
+
```tsx
|
|
233
|
+
<ProgressBar color="primary" value={75} />
|
|
234
|
+
|
|
235
|
+
<ProgressBar color="#22c55e" value={100} h="12px" animationDurationInSeconds={2} />
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
| Prop | Type | Default | Description |
|
|
239
|
+
| ---------------------------- | ----------------- | -------- | ---------------------------- |
|
|
240
|
+
| `color` | `Color \| string` | — | **Required.** Bar color |
|
|
241
|
+
| `value` | `number` | — | **Required.** Progress 0–100 |
|
|
242
|
+
| `h` | `string` | `"8px"` | Bar height |
|
|
243
|
+
| `w` | `string` | `"100%"` | Bar width |
|
|
244
|
+
| `animationDurationInSeconds` | `number` | `1` | Animation duration |
|
|
245
|
+
|
|
246
|
+
### Select
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
const options = [
|
|
250
|
+
{ key: "react", label: "React" },
|
|
251
|
+
{ key: "vue", label: "Vue" },
|
|
252
|
+
{ key: "svelte", label: "Svelte" },
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
<Select
|
|
256
|
+
options={options}
|
|
257
|
+
label="Framework"
|
|
258
|
+
placeholder="Pick one"
|
|
259
|
+
onChange={(option) => console.log(option)}
|
|
260
|
+
required
|
|
261
|
+
/>;
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
| Prop | Type | Default | Description |
|
|
265
|
+
| --------------- | ---------------------------------------------- | -------- | ---------------------------- |
|
|
266
|
+
| `options` | `{ key: string; label: string; data?: any }[]` | — | **Required.** Options list |
|
|
267
|
+
| `value` | `SelectOption` | — | Controlled value |
|
|
268
|
+
| `initialValue` | `SelectOption` | — | Initial value (uncontrolled) |
|
|
269
|
+
| `onChange` | `(value: SelectOption) => void` | — | Change handler |
|
|
270
|
+
| `placeholder` | `string` | — | Placeholder text |
|
|
271
|
+
| `label` | `string` | — | Label text |
|
|
272
|
+
| `required` | `boolean` | — | Shows required asterisk |
|
|
273
|
+
| `orientation` | `"up" \| "down"` | `"down"` | Dropdown direction |
|
|
274
|
+
| `CustomOption` | `(props) => ReactNode` | — | Custom option renderer |
|
|
275
|
+
| `hideScrollbar` | `boolean` | — | Hide dropdown scrollbar |
|
|
276
|
+
|
|
277
|
+
### Skeleton
|
|
278
|
+
|
|
279
|
+
```tsx
|
|
280
|
+
<Skeleton width="200px" height="20px" color="primary" />
|
|
281
|
+
|
|
282
|
+
<Skeleton width="48px" height="48px" radius="50%" />
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
| Prop | Type | Default | Description |
|
|
286
|
+
| -------- | ----------------- | ------- | --------------- |
|
|
287
|
+
| `width` | `string` | `auto` | Skeleton width |
|
|
288
|
+
| `height` | `string` | `auto` | Skeleton height |
|
|
289
|
+
| `radius` | `string` | — | Border radius |
|
|
290
|
+
| `color` | `Color \| string` | — | Shimmer color |
|
|
291
|
+
|
|
292
|
+
### Switch
|
|
293
|
+
|
|
294
|
+
```tsx
|
|
295
|
+
<Switch value={isOn} onChange={(on) => setIsOn(on)} color="primary" />
|
|
296
|
+
|
|
297
|
+
<Switch color="secondary" size={32} />
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
| Prop | Type | Default | Description |
|
|
301
|
+
| ---------- | ------------------------- | ------- | ---------------------------------- |
|
|
302
|
+
| `value` | `boolean` | `false` | On/off state |
|
|
303
|
+
| `onChange` | `(isOn: boolean) => void` | — | Change handler |
|
|
304
|
+
| `color` | `Color \| string` | — | Active color |
|
|
305
|
+
| `size` | `number` | `48` | Width in px (height = size / 1.75) |
|
|
306
|
+
|
|
307
|
+
### Text
|
|
308
|
+
|
|
309
|
+
```tsx
|
|
310
|
+
<Text size="16" weight="medium" color="primary">Hello world</Text>
|
|
311
|
+
|
|
312
|
+
<Text size="14" color="#666" align="center">Centered subtitle</Text>
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
| Prop | Type | Default | Description |
|
|
316
|
+
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | --------------- |
|
|
317
|
+
| `size` | `"8" \| "10" \| "12" \| "14" \| "15" \| "16" \| "18" \| "20" \| "24" \| "28" \| "32" \| "36" \| "40" \| "44" \| "48" \| "52" \| "56" \| "60" \| "64" \| "72" \| "80" \| "96"` | — | Font size |
|
|
318
|
+
| `weight` | `"regular" \| "medium" \| "semibold" \| "bold"` | — | Font weight |
|
|
319
|
+
| `color` | `Color \| string` | — | Text color |
|
|
320
|
+
| `align` | `"left" \| "center" \| "right" \| "justify"` | — | Text alignment |
|
|
321
|
+
| `width` | `string` | — | Container width |
|
|
322
|
+
|
|
323
|
+
### TextArea
|
|
324
|
+
|
|
325
|
+
```tsx
|
|
326
|
+
<TextArea label="Message" placeholder="Type here..." color="primary" rows={4} />
|
|
327
|
+
|
|
328
|
+
<TextArea label="Bio" required error="This field is required" />
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
| Prop | Type | Default | Description |
|
|
332
|
+
| ---------- | ----------------- | ----------- | ---------------------------- |
|
|
333
|
+
| `label` | `string` | — | Label text |
|
|
334
|
+
| `color` | `Color \| string` | `"default"` | Focus/border color |
|
|
335
|
+
| `error` | `string` | — | Error message below textarea |
|
|
336
|
+
| `required` | `boolean` | — | Shows required asterisk |
|
|
337
|
+
| `w` | `string` | — | Width |
|
|
338
|
+
| `h` | `string` | — | Height |
|
|
339
|
+
|
|
340
|
+
Extends all standard `<textarea>` attributes.
|
|
341
|
+
|
|
342
|
+
### Title
|
|
343
|
+
|
|
344
|
+
```tsx
|
|
345
|
+
<Title level={1} weight="bold" color="primary">Page Title</Title>
|
|
346
|
+
|
|
347
|
+
<Title level={3}>Section Heading</Title>
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
| Prop | Type | Default | Description |
|
|
351
|
+
| -------- | ----------------------------------------------- | ------- | -------------------------------------------- |
|
|
352
|
+
| `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | — | **Required.** HTML heading level (`h1`–`h6`) |
|
|
353
|
+
| `weight` | `"regular" \| "medium" \| "semibold" \| "bold"` | — | Font weight |
|
|
354
|
+
| `color` | `Color \| string` | — | Title color |
|
|
355
|
+
|
|
356
|
+
### Toast
|
|
357
|
+
|
|
358
|
+
Toasts are rendered via context. Use the `useToast` hook:
|
|
359
|
+
|
|
360
|
+
```tsx
|
|
361
|
+
const { addToast } = useToast();
|
|
362
|
+
|
|
363
|
+
addToast({ title: "Saved!", color: "primary", icon: <CheckIcon /> });
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
| Prop | Type | Default | Description |
|
|
367
|
+
| ------- | ----------------- | ------- | ------------- |
|
|
368
|
+
| `title` | `string` | — | Toast message |
|
|
369
|
+
| `color` | `Color \| string` | — | Accent color |
|
|
370
|
+
| `icon` | `ReactNode` | — | Leading icon |
|
|
371
|
+
|
|
372
|
+
### Tooltip
|
|
373
|
+
|
|
374
|
+
```tsx
|
|
375
|
+
<Tooltip label="Copy to clipboard" color="primary" placement="top">
|
|
376
|
+
<Button starticon="copy" variant="text" />
|
|
377
|
+
</Tooltip>
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
| Prop | Type | Default | Description |
|
|
381
|
+
| ----------- | ---------------------------------------- | ------------- | ----------------------------- |
|
|
382
|
+
| `label` | `ReactNode` | — | **Required.** Tooltip content |
|
|
383
|
+
| `color` | `Color \| string` | `"primary"` | Background color |
|
|
384
|
+
| `variant` | `"contained" \| "outlined" \| "text"` | theme default | Visual style |
|
|
385
|
+
| `placement` | `"top" \| "bottom" \| "left" \| "right"` | `"top"` | Position |
|
|
386
|
+
| `gap` | `number` | `8` | Distance from trigger (px) |
|
|
387
|
+
| `radius` | `Radius` | theme default | Border radius |
|
|
388
|
+
|
|
389
|
+
### Icons
|
|
390
|
+
|
|
391
|
+
All icons accept `size`, `color`, `strokeWidth`, and `animated` props.
|
|
392
|
+
|
|
393
|
+
```tsx
|
|
394
|
+
<BellIcon size={24} hasNotification={true} />
|
|
395
|
+
<HeartIcon size={24} isLiked={liked} />
|
|
396
|
+
<CheckIcon size={24} isVisible={done} />
|
|
397
|
+
<SyncIcon size={24} isSyncing={loading} />
|
|
398
|
+
<HamburgerIcon size={24} isOpen={menuOpen} />
|
|
399
|
+
<CopyIcon size={24} isCopied={copied} />
|
|
400
|
+
<SparklesIcon size={24} animated />
|
|
401
|
+
<DotsIcon size={24} animated />
|
|
402
|
+
<SendHorizontalIcon size={24} animated />
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Icons can also be referenced by name in `Button` via `starticon` / `endicon`:
|
|
406
|
+
|
|
407
|
+
```tsx
|
|
408
|
+
<Button starticon="bell" label="Notifications" />
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## Spacing
|
|
412
|
+
|
|
413
|
+
All components (except a few like Select, Image) support margin and padding shorthand props:
|
|
414
|
+
|
|
415
|
+
```tsx
|
|
416
|
+
<Button label="Spaced" mt={16} mx={8} p={12} />
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
| Prop | Description |
|
|
420
|
+
| ---------------------- | ----------------------------------- |
|
|
421
|
+
| `m` | Margin all sides |
|
|
422
|
+
| `mt`, `mr`, `mb`, `ml` | Margin top / right / bottom / left |
|
|
423
|
+
| `mx`, `my` | Margin horizontal / vertical |
|
|
424
|
+
| `p` | Padding all sides |
|
|
425
|
+
| `pt`, `pr`, `pb`, `pl` | Padding top / right / bottom / left |
|
|
426
|
+
| `px`, `py` | Padding horizontal / vertical |
|
|
427
|
+
|
|
428
|
+
## Theme
|
|
429
|
+
|
|
430
|
+
### Creating a theme
|
|
431
|
+
|
|
432
|
+
Use `createTheme` to build a theme object. Pass a color string and the palette (5 shades) is generated automatically:
|
|
433
|
+
|
|
434
|
+
```tsx
|
|
435
|
+
import { createTheme } from "@julien-wiegandt/open-ui";
|
|
436
|
+
|
|
437
|
+
const theme = createTheme({
|
|
438
|
+
radius: "md",
|
|
439
|
+
primary: "#6090fa",
|
|
440
|
+
secondary: "#8b5cf6",
|
|
441
|
+
error: "#e74c3c",
|
|
442
|
+
titleFontFamily: "Inter Variable",
|
|
443
|
+
textFontFamily: "Space Mono",
|
|
444
|
+
});
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
| Param | Type | Default | Description |
|
|
448
|
+
| ----------------- | ------------------------------------------ | ----------------------- | ----------------------------------------------------------------------------- |
|
|
449
|
+
| `radius` | `"none" \| "sm" \| "md" \| "lg" \| "full"` | — | **Required.** Global border radius (`0px` / `8px` / `12px` / `14px` / `42px`) |
|
|
450
|
+
| `primary` | `string \| ColorPalette` | — | **Required.** Primary color hex or custom palette |
|
|
451
|
+
| `secondary` | `string \| ColorPalette` | `"#000000"` | Secondary color |
|
|
452
|
+
| `default` | `string \| ColorPalette` | `"#000000"` | Default color |
|
|
453
|
+
| `error` | `string \| ColorPalette` | `"#e74c3c"` | Error color |
|
|
454
|
+
| `titleFontFamily` | `string` | `"Poppins"` | Heading font family |
|
|
455
|
+
| `textFontFamily` | `string` | `"Poppins, sans-serif"` | Body text font family |
|
|
456
|
+
| `components` | `object` | — | Per-component style overrides |
|
|
457
|
+
|
|
458
|
+
### Custom color palette
|
|
459
|
+
|
|
460
|
+
Instead of a hex string, pass a full palette object for precise control:
|
|
461
|
+
|
|
462
|
+
```tsx
|
|
463
|
+
const theme = createTheme({
|
|
464
|
+
radius: "lg",
|
|
465
|
+
primary: {
|
|
466
|
+
darker: "#162a55",
|
|
467
|
+
dark: "#1c448c",
|
|
468
|
+
main: "#6090fa",
|
|
469
|
+
light: "#daeeff",
|
|
470
|
+
lighter: "#eff8ff",
|
|
471
|
+
},
|
|
472
|
+
});
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### Multiple themes
|
|
476
|
+
|
|
477
|
+
Pass multiple themes and switch at runtime:
|
|
478
|
+
|
|
479
|
+
```tsx
|
|
480
|
+
import { OpenUIProvider, createTheme } from "@julien-wiegandt/open-ui";
|
|
481
|
+
|
|
482
|
+
const light = createTheme({ radius: "md", primary: "#6090fa" });
|
|
483
|
+
const dark = createTheme({ radius: "md", primary: "#818cf8" });
|
|
484
|
+
|
|
485
|
+
<OpenUIProvider themes={[light, dark]}>
|
|
486
|
+
<App />
|
|
487
|
+
</OpenUIProvider>;
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
Switch themes from any child component:
|
|
491
|
+
|
|
492
|
+
```tsx
|
|
493
|
+
import { ThemeContext } from "@julien-wiegandt/open-ui";
|
|
494
|
+
|
|
495
|
+
const { setTheme } = useContext(ThemeContext);
|
|
496
|
+
|
|
497
|
+
// Switch by index
|
|
498
|
+
setTheme({ index: 1 });
|
|
499
|
+
|
|
500
|
+
// Or pass a new theme object
|
|
501
|
+
setTheme({ theme: myCustomTheme });
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
### Provider settings
|
|
505
|
+
|
|
506
|
+
```tsx
|
|
507
|
+
<OpenUIProvider
|
|
508
|
+
themes={[theme]}
|
|
509
|
+
settings={{
|
|
510
|
+
autoContrast: true, // auto-adjust text color for readability (default: true)
|
|
511
|
+
toasts: { ... }, // toast notification settings
|
|
512
|
+
}}
|
|
513
|
+
>
|
|
514
|
+
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Color, Radius, Variant } from '../../theme/types';
|
|
2
1
|
import { default as React } from 'react';
|
|
2
|
+
import { Color, Radius, Variant } from '../../theme/types';
|
|
3
3
|
import { MarginProps, PaddingProps } from '../common/types';
|
|
4
4
|
import { TextProps } from '../text';
|
|
5
5
|
export type Icon = "bell" | "check" | "hamburger" | "heart" | "sync" | "sparkles" | "dots" | "send" | "copy";
|