@buillaume.biondo/fab-ui 0.1.0 → 0.1.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 +2149 -0
- package/dist/components/radio/Radio.vue.d.ts +19 -0
- package/dist/components/radio/RadioGroup.vue.d.ts +25 -0
- package/dist/components/radio/index.d.ts +2 -0
- package/dist/components/tabs/Tabs.vue.d.ts +34 -0
- package/dist/components/tabs/TabsContent.vue.d.ts +21 -0
- package/dist/components/tabs/TabsList.vue.d.ts +21 -0
- package/dist/components/tabs/TabsTrigger.vue.d.ts +21 -0
- package/dist/components/tabs/context.d.ts +10 -0
- package/dist/components/tabs/index.d.ts +5 -0
- package/dist/index.cjs +10 -10
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3821 -3533
- package/package.json +1 -1
- package/readme.md +31 -29
package/README.md
ADDED
|
@@ -0,0 +1,2149 @@
|
|
|
1
|
+
# fab-ui
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@buillaume.biondo/fab-ui)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
|
|
6
|
+
A Vue 3 component library built on top of [reka-ui](https://reka-ui.com/) headless primitives, styled with [Tailwind CSS v4](https://tailwindcss.com/) and [class-variance-authority](https://cva.style/). It provides a complete, accessible, and themeable design system — including layout components, form controls, overlays, data display, and navigation — ready to drop into any Vue 3 + Tailwind v4 application.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
|
|
12
|
+
- [Prerequisites](#prerequisites)
|
|
13
|
+
- [Installation](#installation)
|
|
14
|
+
- [Configuration](#configuration)
|
|
15
|
+
- [Design System](#design-system)
|
|
16
|
+
- [Components](#components)
|
|
17
|
+
- [Button](#button)
|
|
18
|
+
- [Badge](#badge)
|
|
19
|
+
- [OverlayBadge](#overlaybadge)
|
|
20
|
+
- [Alert](#alert)
|
|
21
|
+
- [Avatar](#avatar)
|
|
22
|
+
- [Card](#card)
|
|
23
|
+
- [Checkbox](#checkbox)
|
|
24
|
+
- [Radio / RadioGroup](#radio--radiogroup)
|
|
25
|
+
- [Label](#label)
|
|
26
|
+
- [Input](#input)
|
|
27
|
+
- [InputPassword](#inputpassword)
|
|
28
|
+
- [InputNumber](#inputnumber)
|
|
29
|
+
- [InputArea](#inputarea)
|
|
30
|
+
- [InputOTP](#inputotp)
|
|
31
|
+
- [Select](#select)
|
|
32
|
+
- [Slider](#slider)
|
|
33
|
+
- [Toggle](#toggle)
|
|
34
|
+
- [ToggleSwitch](#toggleswitch)
|
|
35
|
+
- [ProgressBar](#progressbar)
|
|
36
|
+
- [Skeleton](#skeleton)
|
|
37
|
+
- [Separator](#separator)
|
|
38
|
+
- [Spinner](#spinner)
|
|
39
|
+
- [Code](#code)
|
|
40
|
+
- [Image](#image)
|
|
41
|
+
- [Carousel](#carousel)
|
|
42
|
+
- [DataTable](#datatable)
|
|
43
|
+
- [Toast / Toaster](#toast--toaster)
|
|
44
|
+
- [SpeedDial](#speeddial)
|
|
45
|
+
- [SplitButton](#splitbutton)
|
|
46
|
+
- [Tooltip](#tooltip)
|
|
47
|
+
- [Collapsible](#collapsible)
|
|
48
|
+
- [DropdownMenu](#dropdownmenu)
|
|
49
|
+
- [ContextMenu](#contextmenu)
|
|
50
|
+
- [Dialog](#dialog)
|
|
51
|
+
- [Sheet](#sheet)
|
|
52
|
+
- [Breadcrumb](#breadcrumb)
|
|
53
|
+
- [NavigationMenu](#navigationmenu)
|
|
54
|
+
- [Sidebar](#sidebar)
|
|
55
|
+
- [Tabs](#tabs)
|
|
56
|
+
- [Composables](#composables)
|
|
57
|
+
- [useToast](#usetoast)
|
|
58
|
+
- [useAppearance](#useappearance)
|
|
59
|
+
- [Roadmap](#roadmap)
|
|
60
|
+
- [License](#license)
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Prerequisites
|
|
65
|
+
|
|
66
|
+
| Dependency | Version |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `vue` | `^3.5` |
|
|
69
|
+
| `tailwindcss` | `^4.0` |
|
|
70
|
+
| `reka-ui` | `^2.0` |
|
|
71
|
+
| `lucide-vue-next` | `>=0.400` |
|
|
72
|
+
| `class-variance-authority` | `^0.7` |
|
|
73
|
+
| `@vueuse/core` | `^12.0` |
|
|
74
|
+
| `vue-input-otp` | `^0.3` (optional, for `InputOTP`) |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Installation
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm install @buillaume.biondo/fab-ui
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Install the required peer dependencies if not already present:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npm install vue reka-ui lucide-vue-next class-variance-authority @vueuse/core tailwindcss
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
For the `InputOTP` component (optional):
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm install vue-input-otp
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Configuration
|
|
99
|
+
|
|
100
|
+
### CSS
|
|
101
|
+
|
|
102
|
+
In your main CSS file (e.g. `src/assets/app.css`), import Tailwind and the library styles:
|
|
103
|
+
|
|
104
|
+
```css
|
|
105
|
+
@import 'tailwindcss';
|
|
106
|
+
@import '@buillaume.biondo/fab-ui/style';
|
|
107
|
+
|
|
108
|
+
/* Optional: Marianne font (French government design system) */
|
|
109
|
+
/* @import '@buillaume.biondo/fab-ui/style/marianne'; */
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Fonts
|
|
113
|
+
|
|
114
|
+
Two fonts are loaded automatically via Google Fonts when you import the library stylesheet:
|
|
115
|
+
|
|
116
|
+
- **DM Sans** — body text and UI
|
|
117
|
+
- **JetBrains Mono** — code blocks and monospaced metrics
|
|
118
|
+
|
|
119
|
+
An optional **Marianne** font (used by the French government design system) is available as local `woff`/`woff2` files in `node_modules/@buillaume.biondo/fab-ui/fonts/marianne/`. Uncomment the import above to activate it.
|
|
120
|
+
|
|
121
|
+
### Toaster
|
|
122
|
+
|
|
123
|
+
Mount the `Toaster` component once in your root layout to enable toast notifications throughout the application:
|
|
124
|
+
|
|
125
|
+
```vue
|
|
126
|
+
<script setup>
|
|
127
|
+
import { Toaster } from '@buillaume.biondo/fab-ui'
|
|
128
|
+
</script>
|
|
129
|
+
|
|
130
|
+
<template>
|
|
131
|
+
<Toaster />
|
|
132
|
+
</template>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Design System
|
|
138
|
+
|
|
139
|
+
### Severity (color variants)
|
|
140
|
+
|
|
141
|
+
All components that accept a `variant` prop use the following semantic severity scale:
|
|
142
|
+
|
|
143
|
+
| Value | Meaning |
|
|
144
|
+
|---|---|
|
|
145
|
+
| `primary` | Brand action color |
|
|
146
|
+
| `secondary` | Neutral / subdued |
|
|
147
|
+
| `success` | Positive feedback |
|
|
148
|
+
| `danger` | Destructive / error |
|
|
149
|
+
| `info` | Informational |
|
|
150
|
+
| `warning` | Caution |
|
|
151
|
+
| `help` | Guidance / purple |
|
|
152
|
+
| `contrast` | High contrast / dark |
|
|
153
|
+
|
|
154
|
+
### Size scale
|
|
155
|
+
|
|
156
|
+
Most components accept a `size` prop with the following values (smallest to largest):
|
|
157
|
+
|
|
158
|
+
`tiny` | `small` | `default` | `large` | `extra`
|
|
159
|
+
|
|
160
|
+
### CSS custom properties
|
|
161
|
+
|
|
162
|
+
The library uses semantic CSS variables. You can override any of them in your CSS to customize the theme:
|
|
163
|
+
|
|
164
|
+
```css
|
|
165
|
+
:root {
|
|
166
|
+
--color-action: #2563eb;
|
|
167
|
+
--color-brand: #1d4ed8;
|
|
168
|
+
--color-bg: #ffffff;
|
|
169
|
+
--color-bg-subtle: #f8fafc;
|
|
170
|
+
--color-bg-raised: #ffffff;
|
|
171
|
+
--color-text: #0f172a;
|
|
172
|
+
--color-text-muted: #64748b;
|
|
173
|
+
--color-text-disabled: #94a3b8;
|
|
174
|
+
--color-border: #e2e8f0;
|
|
175
|
+
--color-border-strong: #cbd5e1;
|
|
176
|
+
--color-success: #16a34a;
|
|
177
|
+
--color-danger: #dc2626;
|
|
178
|
+
--color-warning: #d97706;
|
|
179
|
+
--color-info: #2563eb;
|
|
180
|
+
--color-help: #7c3aed;
|
|
181
|
+
--color-contrast: #1f2937;
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Dark mode
|
|
186
|
+
|
|
187
|
+
Add the `.dark` class to your `<html>` element to activate dark mode:
|
|
188
|
+
|
|
189
|
+
```html
|
|
190
|
+
<html class="dark">
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Square radius mode
|
|
194
|
+
|
|
195
|
+
Add `data-radius="square"` to your `<html>` element to remove all border radii:
|
|
196
|
+
|
|
197
|
+
```html
|
|
198
|
+
<html data-radius="square">
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Components
|
|
204
|
+
|
|
205
|
+
### Button
|
|
206
|
+
|
|
207
|
+
A versatile button component with 8 severity variants, 4 shapes, 5 sizes, and optional loading, icon, and badge states. Renders as a `<button>` by default but can be changed via the `as` prop (e.g. `as="a"` for links).
|
|
208
|
+
|
|
209
|
+
**Props**
|
|
210
|
+
|
|
211
|
+
| Prop | Type | Default | Description |
|
|
212
|
+
|---|---|---|---|
|
|
213
|
+
| `variant` | `Severity` | `'primary'` | Color variant |
|
|
214
|
+
| `shape` | `'plain' \| 'outline' \| 'ghost' \| 'link'` | `'plain'` | Visual style |
|
|
215
|
+
| `size` | `Size` | `'default'` | Button size |
|
|
216
|
+
| `fluid` | `boolean` | `false` | Full-width |
|
|
217
|
+
| `rounded` | `boolean` | `false` | Fully rounded (pill) |
|
|
218
|
+
| `icon` | `boolean` | `false` | Icon-only mode (square / circle) |
|
|
219
|
+
| `loading` | `boolean` | `false` | Shows a spinner, disables interaction |
|
|
220
|
+
| `disabled` | `boolean` | `false` | Disables the button |
|
|
221
|
+
| `badge` | `number \| null` | `null` | Numeric overlay badge (top-right) |
|
|
222
|
+
| `iconLeft` | `Component` | — | Icon component rendered before the label |
|
|
223
|
+
| `iconRight` | `Component` | — | Icon component rendered after the label |
|
|
224
|
+
| `as` | `string \| Component` | `'button'` | Rendered HTML element or component |
|
|
225
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
226
|
+
|
|
227
|
+
```vue
|
|
228
|
+
<script setup>
|
|
229
|
+
import { Button } from '@buillaume.biondo/fab-ui'
|
|
230
|
+
import { PlusIcon, TrashIcon } from 'lucide-vue-next'
|
|
231
|
+
</script>
|
|
232
|
+
|
|
233
|
+
<template>
|
|
234
|
+
<!-- Basic -->
|
|
235
|
+
<Button>Save</Button>
|
|
236
|
+
|
|
237
|
+
<!-- Variants and shapes -->
|
|
238
|
+
<Button variant="danger" shape="outline">Delete</Button>
|
|
239
|
+
<Button variant="success" shape="ghost">Confirm</Button>
|
|
240
|
+
|
|
241
|
+
<!-- With icons -->
|
|
242
|
+
<Button :icon-left="PlusIcon">Add item</Button>
|
|
243
|
+
<Button :icon-right="TrashIcon" variant="danger" shape="outline">Remove</Button>
|
|
244
|
+
|
|
245
|
+
<!-- Icon-only -->
|
|
246
|
+
<Button :icon="true" variant="secondary" shape="ghost">
|
|
247
|
+
<PlusIcon />
|
|
248
|
+
</Button>
|
|
249
|
+
|
|
250
|
+
<!-- Loading state -->
|
|
251
|
+
<Button :loading="isSaving">Saving…</Button>
|
|
252
|
+
|
|
253
|
+
<!-- With badge -->
|
|
254
|
+
<Button :badge="5">Notifications</Button>
|
|
255
|
+
|
|
256
|
+
<!-- As a link -->
|
|
257
|
+
<Button as="a" href="/dashboard" variant="primary" shape="link">Go to dashboard</Button>
|
|
258
|
+
</template>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
### Badge
|
|
264
|
+
|
|
265
|
+
Inline label component for statuses, tags, and counts. Supports 8 severity variants × 3 shapes, with an optional leading dot.
|
|
266
|
+
|
|
267
|
+
**Props**
|
|
268
|
+
|
|
269
|
+
| Prop | Type | Default | Description |
|
|
270
|
+
|---|---|---|---|
|
|
271
|
+
| `variant` | `Severity` | `'primary'` | Color variant |
|
|
272
|
+
| `shape` | `'filled' \| 'outline' \| 'ghost'` | `'filled'` | Visual style |
|
|
273
|
+
| `size` | `Size` | `'default'` | Badge size |
|
|
274
|
+
| `fluid` | `boolean` | `false` | Full-width with centered text |
|
|
275
|
+
| `dot` | `boolean` | `false` | Prepends a colored dot |
|
|
276
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
277
|
+
|
|
278
|
+
```vue
|
|
279
|
+
<script setup>
|
|
280
|
+
import { Badge } from '@buillaume.biondo/fab-ui'
|
|
281
|
+
</script>
|
|
282
|
+
|
|
283
|
+
<template>
|
|
284
|
+
<Badge>Primary</Badge>
|
|
285
|
+
<Badge variant="success">Active</Badge>
|
|
286
|
+
<Badge variant="danger" shape="outline">Error</Badge>
|
|
287
|
+
<Badge variant="warning" shape="ghost" dot>Pending</Badge>
|
|
288
|
+
<Badge variant="info" size="small">3 new</Badge>
|
|
289
|
+
</template>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
### OverlayBadge
|
|
295
|
+
|
|
296
|
+
Wrapper that positions a badge (dot or numeric) as an absolute overlay on top of any element — ideal for notification counts on icons or avatars.
|
|
297
|
+
|
|
298
|
+
**Props**
|
|
299
|
+
|
|
300
|
+
| Prop | Type | Default | Description |
|
|
301
|
+
|---|---|---|---|
|
|
302
|
+
| `value` | `number \| null` | — | Numeric value. `0` or absent renders a dot; `null` hides the badge |
|
|
303
|
+
| `variant` | `Severity` | `'danger'` | Color variant |
|
|
304
|
+
| `position` | `'top-right' \| 'top-left' \| 'bottom-right' \| 'bottom-left'` | `'top-right'` | Badge position |
|
|
305
|
+
| `class` | `string` | — | Additional CSS classes on the wrapper |
|
|
306
|
+
|
|
307
|
+
```vue
|
|
308
|
+
<script setup>
|
|
309
|
+
import { OverlayBadge, Button } from '@buillaume.biondo/fab-ui'
|
|
310
|
+
import { BellIcon } from 'lucide-vue-next'
|
|
311
|
+
</script>
|
|
312
|
+
|
|
313
|
+
<template>
|
|
314
|
+
<!-- Numeric badge -->
|
|
315
|
+
<OverlayBadge :value="12">
|
|
316
|
+
<Button :icon="true" shape="ghost" variant="secondary">
|
|
317
|
+
<BellIcon />
|
|
318
|
+
</Button>
|
|
319
|
+
</OverlayBadge>
|
|
320
|
+
|
|
321
|
+
<!-- Dot badge -->
|
|
322
|
+
<OverlayBadge :value="0" variant="success">
|
|
323
|
+
<Button :icon="true" shape="ghost" variant="secondary">
|
|
324
|
+
<BellIcon />
|
|
325
|
+
</Button>
|
|
326
|
+
</OverlayBadge>
|
|
327
|
+
</template>
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
### Alert
|
|
333
|
+
|
|
334
|
+
Dismissible alert banner with icon, title, body slot, and optional auto-close. Animated with a slide + fade transition.
|
|
335
|
+
|
|
336
|
+
**Props**
|
|
337
|
+
|
|
338
|
+
| Prop | Type | Default | Description |
|
|
339
|
+
|---|---|---|---|
|
|
340
|
+
| `variant` | `Severity` | `'info'` | Color variant |
|
|
341
|
+
| `title` | `string` | — | Bold heading text |
|
|
342
|
+
| `dismissible` | `boolean` | `false` | Shows a close button |
|
|
343
|
+
| `icon` | `boolean` | `true` | Displays the default variant icon |
|
|
344
|
+
| `iconComponent` | `Component` | — | Replaces the default icon |
|
|
345
|
+
| `delay` | `number` | `0` | Auto-close delay in milliseconds (0 = never) |
|
|
346
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
347
|
+
|
|
348
|
+
**Slots**
|
|
349
|
+
|
|
350
|
+
| Slot | Description |
|
|
351
|
+
|---|---|
|
|
352
|
+
| `default` | Alert body content |
|
|
353
|
+
| `#icon` | Custom icon replacing the default one |
|
|
354
|
+
|
|
355
|
+
**Emits**
|
|
356
|
+
|
|
357
|
+
| Event | Description |
|
|
358
|
+
|---|---|
|
|
359
|
+
| `close` | Fired when the alert is dismissed or auto-closes |
|
|
360
|
+
|
|
361
|
+
```vue
|
|
362
|
+
<script setup>
|
|
363
|
+
import { Alert } from '@buillaume.biondo/fab-ui'
|
|
364
|
+
import { RocketIcon } from 'lucide-vue-next'
|
|
365
|
+
</script>
|
|
366
|
+
|
|
367
|
+
<template>
|
|
368
|
+
<Alert title="Heads up!">
|
|
369
|
+
Your trial expires in 3 days.
|
|
370
|
+
</Alert>
|
|
371
|
+
|
|
372
|
+
<Alert variant="success" :dismissible="true" title="Saved!">
|
|
373
|
+
Your changes have been saved successfully.
|
|
374
|
+
</Alert>
|
|
375
|
+
|
|
376
|
+
<Alert variant="danger" :icon-component="RocketIcon">
|
|
377
|
+
Deployment failed. Check the logs.
|
|
378
|
+
</Alert>
|
|
379
|
+
|
|
380
|
+
<!-- Auto-close after 5 seconds -->
|
|
381
|
+
<Alert variant="info" :delay="5000" @close="onClose">
|
|
382
|
+
This message will disappear automatically.
|
|
383
|
+
</Alert>
|
|
384
|
+
</template>
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
### Avatar
|
|
390
|
+
|
|
391
|
+
Circular avatar container wrapping reka-ui's `AvatarRoot`. Use with `AvatarImage` and `AvatarFallback` from `reka-ui` for image with initials fallback.
|
|
392
|
+
|
|
393
|
+
**Props**
|
|
394
|
+
|
|
395
|
+
| Prop | Type | Default | Description |
|
|
396
|
+
|---|---|---|---|
|
|
397
|
+
| `size` | `'tiny' \| 'small' \| 'default' \| 'large' \| 'extra'` | `'default'` | Avatar size |
|
|
398
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
399
|
+
|
|
400
|
+
```vue
|
|
401
|
+
<script setup>
|
|
402
|
+
import { Avatar } from '@buillaume.biondo/fab-ui'
|
|
403
|
+
import { AvatarImage, AvatarFallback } from 'reka-ui'
|
|
404
|
+
</script>
|
|
405
|
+
|
|
406
|
+
<template>
|
|
407
|
+
<Avatar size="large">
|
|
408
|
+
<AvatarImage src="/avatars/john.jpg" alt="John Doe" />
|
|
409
|
+
<AvatarFallback>JD</AvatarFallback>
|
|
410
|
+
</Avatar>
|
|
411
|
+
</template>
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
### Card
|
|
417
|
+
|
|
418
|
+
A flexible card container with optional border color variants, shadow, hover effects, and named slots for header and footer.
|
|
419
|
+
|
|
420
|
+
**Props**
|
|
421
|
+
|
|
422
|
+
| Prop | Type | Default | Description |
|
|
423
|
+
|---|---|---|---|
|
|
424
|
+
| `variant` | `'default' \| Severity` | `'default'` | Border color (9 options including `default`) |
|
|
425
|
+
| `padded` | `boolean` | `true` | Adds vertical padding and inner gap |
|
|
426
|
+
| `bordered` | `boolean` | `true` | Renders a border |
|
|
427
|
+
| `hoverable` | `boolean` | `false` | Elevates shadow on hover |
|
|
428
|
+
| `raised` | `boolean` | `false` | Uses a larger shadow by default |
|
|
429
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
430
|
+
|
|
431
|
+
**Slots**
|
|
432
|
+
|
|
433
|
+
| Slot | Description |
|
|
434
|
+
|---|---|
|
|
435
|
+
| `#header` | Card header area |
|
|
436
|
+
| `default` | Card body |
|
|
437
|
+
| `#footer` | Card footer area |
|
|
438
|
+
|
|
439
|
+
**CardHeader props**
|
|
440
|
+
|
|
441
|
+
| Prop | Type | Default | Description |
|
|
442
|
+
|---|---|---|---|
|
|
443
|
+
| `flush` | `boolean` | `false` | Removes padding; clips content (e.g. cover images) to card corners |
|
|
444
|
+
|
|
445
|
+
```vue
|
|
446
|
+
<script setup>
|
|
447
|
+
import { Card, CardHeader } from '@buillaume.biondo/fab-ui'
|
|
448
|
+
</script>
|
|
449
|
+
|
|
450
|
+
<template>
|
|
451
|
+
<Card variant="primary" :hoverable="true">
|
|
452
|
+
<template #header>
|
|
453
|
+
<CardHeader>
|
|
454
|
+
<h3 class="font-semibold text-lg">Card Title</h3>
|
|
455
|
+
<p class="text-sm text-muted">Card subtitle</p>
|
|
456
|
+
</CardHeader>
|
|
457
|
+
</template>
|
|
458
|
+
|
|
459
|
+
<p>Card body content goes here.</p>
|
|
460
|
+
|
|
461
|
+
<template #footer>
|
|
462
|
+
<div class="flex justify-end gap-2">
|
|
463
|
+
<Button variant="secondary" shape="outline">Cancel</Button>
|
|
464
|
+
<Button>Confirm</Button>
|
|
465
|
+
</div>
|
|
466
|
+
</template>
|
|
467
|
+
</Card>
|
|
468
|
+
</template>
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
---
|
|
472
|
+
|
|
473
|
+
### Checkbox
|
|
474
|
+
|
|
475
|
+
Accessible checkbox built on reka-ui's `CheckboxRoot`. Fully styled with action color when checked and error state support.
|
|
476
|
+
|
|
477
|
+
**Props**
|
|
478
|
+
|
|
479
|
+
Accepts all props from reka-ui's `CheckboxRootProps` plus:
|
|
480
|
+
|
|
481
|
+
| Prop | Type | Description |
|
|
482
|
+
|---|---|---|
|
|
483
|
+
| `class` | `string` | Additional CSS classes |
|
|
484
|
+
|
|
485
|
+
```vue
|
|
486
|
+
<script setup>
|
|
487
|
+
import { Checkbox, Label } from '@buillaume.biondo/fab-ui'
|
|
488
|
+
import { ref } from 'vue'
|
|
489
|
+
|
|
490
|
+
const checked = ref(false)
|
|
491
|
+
</script>
|
|
492
|
+
|
|
493
|
+
<template>
|
|
494
|
+
<div class="flex items-center gap-2">
|
|
495
|
+
<Checkbox id="terms" v-model:checked="checked" />
|
|
496
|
+
<Label for="terms">I agree to the terms</Label>
|
|
497
|
+
</div>
|
|
498
|
+
</template>
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
### Radio / RadioGroup
|
|
504
|
+
|
|
505
|
+
Accessible radio button group built on reka-ui's `RadioGroupRoot` / `RadioGroupItem` primitives. `RadioGroup` is the container that manages the selection state; `Radio` is the individual item with an optional inline label.
|
|
506
|
+
|
|
507
|
+
#### RadioGroup
|
|
508
|
+
|
|
509
|
+
**Props**
|
|
510
|
+
|
|
511
|
+
Accepts all props from reka-ui's `RadioGroupRootProps` plus:
|
|
512
|
+
|
|
513
|
+
| Prop | Type | Default | Description |
|
|
514
|
+
|---|---|---|---|
|
|
515
|
+
| `orientation` | `'horizontal' \| 'vertical'` | `'vertical'` | Layout direction of the items |
|
|
516
|
+
| `modelValue` | `string` | — | Controlled selected value (`v-model`) |
|
|
517
|
+
| `defaultValue` | `string` | — | Initial selected value (uncontrolled) |
|
|
518
|
+
| `disabled` | `boolean` | `false` | Disables the entire group |
|
|
519
|
+
| `name` | `string` | — | Native `name` attribute forwarded to the hidden inputs |
|
|
520
|
+
| `class` | `string` | — | Additional CSS classes on the wrapper |
|
|
521
|
+
|
|
522
|
+
**Emits**
|
|
523
|
+
|
|
524
|
+
| Event | Payload | Description |
|
|
525
|
+
|---|---|---|
|
|
526
|
+
| `update:modelValue` | `string` | Fired when the selected value changes |
|
|
527
|
+
|
|
528
|
+
#### Radio
|
|
529
|
+
|
|
530
|
+
**Props**
|
|
531
|
+
|
|
532
|
+
Accepts all props from reka-ui's `RadioGroupItemProps` plus:
|
|
533
|
+
|
|
534
|
+
| Prop | Type | Default | Description |
|
|
535
|
+
|---|---|---|---|
|
|
536
|
+
| `value` | `string` | **required** | The value this item represents |
|
|
537
|
+
| `variant` | `Severity` | `'primary'` | Color of the checked indicator |
|
|
538
|
+
| `size` | `'small' \| 'default' \| 'large'` | `'default'` | Size of the circle and label text |
|
|
539
|
+
| `label` | `string` | — | Text rendered to the right of the button |
|
|
540
|
+
| `disabled` | `boolean` | `false` | Disables this individual item |
|
|
541
|
+
| `class` | `string` | — | Applied to the wrapper `<label>` |
|
|
542
|
+
|
|
543
|
+
```vue
|
|
544
|
+
<script setup>
|
|
545
|
+
import { RadioGroup, Radio } from '@buillaume.biondo/fab-ui'
|
|
546
|
+
import { ref } from 'vue'
|
|
547
|
+
|
|
548
|
+
const plan = ref('pro')
|
|
549
|
+
</script>
|
|
550
|
+
|
|
551
|
+
<template>
|
|
552
|
+
<!-- Vertical (default) -->
|
|
553
|
+
<RadioGroup v-model="plan">
|
|
554
|
+
<Radio value="free" label="Free" />
|
|
555
|
+
<Radio value="pro" label="Pro" />
|
|
556
|
+
<Radio value="teams" label="Teams" />
|
|
557
|
+
</RadioGroup>
|
|
558
|
+
|
|
559
|
+
<!-- Horizontal -->
|
|
560
|
+
<RadioGroup v-model="plan" orientation="horizontal">
|
|
561
|
+
<Radio value="light" label="Light" />
|
|
562
|
+
<Radio value="dark" label="Dark" />
|
|
563
|
+
</RadioGroup>
|
|
564
|
+
|
|
565
|
+
<!-- Semantic colors -->
|
|
566
|
+
<RadioGroup v-model="plan">
|
|
567
|
+
<Radio value="ok" variant="success" label="Approved" />
|
|
568
|
+
<Radio value="warn" variant="warning" label="Pending" />
|
|
569
|
+
<Radio value="err" variant="danger" label="Rejected" />
|
|
570
|
+
</RadioGroup>
|
|
571
|
+
|
|
572
|
+
<!-- Sizes -->
|
|
573
|
+
<RadioGroup v-model="plan">
|
|
574
|
+
<Radio value="s" size="small" label="Small" />
|
|
575
|
+
<Radio value="m" size="default" label="Default" />
|
|
576
|
+
<Radio value="l" size="large" label="Large" />
|
|
577
|
+
</RadioGroup>
|
|
578
|
+
|
|
579
|
+
<!-- Disabled states -->
|
|
580
|
+
<RadioGroup v-model="plan">
|
|
581
|
+
<Radio value="a" label="Available" />
|
|
582
|
+
<Radio value="b" label="Unavailable" disabled />
|
|
583
|
+
</RadioGroup>
|
|
584
|
+
|
|
585
|
+
<!-- Disabled group -->
|
|
586
|
+
<RadioGroup v-model="plan" disabled>
|
|
587
|
+
<Radio value="x" label="Option X" />
|
|
588
|
+
<Radio value="y" label="Option Y" />
|
|
589
|
+
</RadioGroup>
|
|
590
|
+
</template>
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
---
|
|
594
|
+
|
|
595
|
+
### Label
|
|
596
|
+
|
|
597
|
+
Semantic `<label>` element styled with the design system's text and font styles. Automatically dims when associated with a disabled input.
|
|
598
|
+
|
|
599
|
+
**Props**
|
|
600
|
+
|
|
601
|
+
Accepts all props from reka-ui's `LabelProps` plus:
|
|
602
|
+
|
|
603
|
+
| Prop | Type | Description |
|
|
604
|
+
|---|---|---|
|
|
605
|
+
| `class` | `string` | Additional CSS classes |
|
|
606
|
+
|
|
607
|
+
```vue
|
|
608
|
+
<script setup>
|
|
609
|
+
import { Label, Input } from '@buillaume.biondo/fab-ui'
|
|
610
|
+
</script>
|
|
611
|
+
|
|
612
|
+
<template>
|
|
613
|
+
<div class="flex flex-col gap-1.5">
|
|
614
|
+
<Label for="email">Email address</Label>
|
|
615
|
+
<Input id="email" type="email" placeholder="you@example.com" />
|
|
616
|
+
</div>
|
|
617
|
+
</template>
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
---
|
|
621
|
+
|
|
622
|
+
### Input
|
|
623
|
+
|
|
624
|
+
Standard text input with focus ring, error state, disabled styling, and file input support.
|
|
625
|
+
|
|
626
|
+
**Props**
|
|
627
|
+
|
|
628
|
+
| Prop | Type | Default | Description |
|
|
629
|
+
|---|---|---|---|
|
|
630
|
+
| `modelValue` | `string \| number` | — | Bound value (`v-model`) |
|
|
631
|
+
| `defaultValue` | `string \| number` | — | Uncontrolled default value |
|
|
632
|
+
| `type` | `string` | `'text'` | HTML input type |
|
|
633
|
+
| `placeholder` | `string` | — | Placeholder text |
|
|
634
|
+
| `disabled` | `boolean` | — | Disables the input |
|
|
635
|
+
| `required` | `boolean` | — | Marks the field as required |
|
|
636
|
+
| `error` | `string` | — | Triggers the error visual state |
|
|
637
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
638
|
+
|
|
639
|
+
```vue
|
|
640
|
+
<script setup>
|
|
641
|
+
import { Input } from '@buillaume.biondo/fab-ui'
|
|
642
|
+
import { ref } from 'vue'
|
|
643
|
+
|
|
644
|
+
const email = ref('')
|
|
645
|
+
</script>
|
|
646
|
+
|
|
647
|
+
<template>
|
|
648
|
+
<Input v-model="email" type="email" placeholder="you@example.com" />
|
|
649
|
+
|
|
650
|
+
<!-- With error -->
|
|
651
|
+
<Input v-model="email" error="Invalid email address" />
|
|
652
|
+
</template>
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
---
|
|
656
|
+
|
|
657
|
+
### InputPassword
|
|
658
|
+
|
|
659
|
+
Password input with a toggle button to show or hide the value. Shares the same props as `Input` (minus `type`).
|
|
660
|
+
|
|
661
|
+
**Props**
|
|
662
|
+
|
|
663
|
+
| Prop | Type | Default | Description |
|
|
664
|
+
|---|---|---|---|
|
|
665
|
+
| `modelValue` | `string` | — | Bound value (`v-model`) |
|
|
666
|
+
| `defaultValue` | `string` | — | Uncontrolled default value |
|
|
667
|
+
| `placeholder` | `string` | — | Placeholder text |
|
|
668
|
+
| `disabled` | `boolean` | — | Disables the input |
|
|
669
|
+
| `required` | `boolean` | — | Marks the field as required |
|
|
670
|
+
| `error` | `string` | — | Triggers the error visual state |
|
|
671
|
+
| `class` | `string` | — | Applied to the wrapper div |
|
|
672
|
+
|
|
673
|
+
```vue
|
|
674
|
+
<script setup>
|
|
675
|
+
import { InputPassword } from '@buillaume.biondo/fab-ui'
|
|
676
|
+
import { ref } from 'vue'
|
|
677
|
+
|
|
678
|
+
const password = ref('')
|
|
679
|
+
</script>
|
|
680
|
+
|
|
681
|
+
<template>
|
|
682
|
+
<InputPassword v-model="password" placeholder="Enter your password" />
|
|
683
|
+
</template>
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
---
|
|
687
|
+
|
|
688
|
+
### InputNumber
|
|
689
|
+
|
|
690
|
+
Numeric input with optional `+` / `−` controls on each side. Enforces `min`, `max`, and `step` constraints.
|
|
691
|
+
|
|
692
|
+
**Props**
|
|
693
|
+
|
|
694
|
+
| Prop | Type | Default | Description |
|
|
695
|
+
|---|---|---|---|
|
|
696
|
+
| `modelValue` | `number` | — | Bound value (`v-model`) |
|
|
697
|
+
| `defaultValue` | `number` | — | Uncontrolled default value |
|
|
698
|
+
| `min` | `number` | — | Minimum allowed value |
|
|
699
|
+
| `max` | `number` | — | Maximum allowed value |
|
|
700
|
+
| `step` | `number` | `1` | Increment/decrement step |
|
|
701
|
+
| `controls` | `boolean` | `true` | Show the `+` / `−` buttons |
|
|
702
|
+
| `placeholder` | `string` | — | Placeholder text |
|
|
703
|
+
| `disabled` | `boolean` | — | Disables the input |
|
|
704
|
+
| `required` | `boolean` | — | Marks the field as required |
|
|
705
|
+
| `error` | `string` | — | Triggers the error visual state |
|
|
706
|
+
| `class` | `string` | — | Applied to the wrapper div |
|
|
707
|
+
|
|
708
|
+
```vue
|
|
709
|
+
<script setup>
|
|
710
|
+
import { InputNumber } from '@buillaume.biondo/fab-ui'
|
|
711
|
+
import { ref } from 'vue'
|
|
712
|
+
|
|
713
|
+
const quantity = ref(1)
|
|
714
|
+
</script>
|
|
715
|
+
|
|
716
|
+
<template>
|
|
717
|
+
<InputNumber v-model="quantity" :min="1" :max="99" />
|
|
718
|
+
|
|
719
|
+
<!-- Without stepper controls -->
|
|
720
|
+
<InputNumber v-model="quantity" :controls="false" />
|
|
721
|
+
</template>
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
---
|
|
725
|
+
|
|
726
|
+
### InputArea
|
|
727
|
+
|
|
728
|
+
Multi-line textarea with configurable resize behavior and an optional character counter.
|
|
729
|
+
|
|
730
|
+
**Props**
|
|
731
|
+
|
|
732
|
+
| Prop | Type | Default | Description |
|
|
733
|
+
|---|---|---|---|
|
|
734
|
+
| `modelValue` | `string` | — | Bound value (`v-model`) |
|
|
735
|
+
| `defaultValue` | `string` | — | Uncontrolled default value |
|
|
736
|
+
| `rows` | `number` | `3` | Number of visible rows |
|
|
737
|
+
| `cols` | `number` | — | Fixed column width (makes the wrapper `inline-flex`) |
|
|
738
|
+
| `maxlength` | `number` | — | Max characters; shows a live counter |
|
|
739
|
+
| `resize` | `'none' \| 'vertical' \| 'horizontal' \| 'both'` | `'vertical'` | Resize handle behavior |
|
|
740
|
+
| `placeholder` | `string` | — | Placeholder text |
|
|
741
|
+
| `disabled` | `boolean` | — | Disables the textarea |
|
|
742
|
+
| `required` | `boolean` | — | Marks the field as required |
|
|
743
|
+
| `error` | `string` | — | Triggers the error visual state |
|
|
744
|
+
| `class` | `string` | — | Applied to the wrapper div |
|
|
745
|
+
|
|
746
|
+
```vue
|
|
747
|
+
<script setup>
|
|
748
|
+
import { InputArea } from '@buillaume.biondo/fab-ui'
|
|
749
|
+
import { ref } from 'vue'
|
|
750
|
+
|
|
751
|
+
const bio = ref('')
|
|
752
|
+
</script>
|
|
753
|
+
|
|
754
|
+
<template>
|
|
755
|
+
<InputArea
|
|
756
|
+
v-model="bio"
|
|
757
|
+
placeholder="Tell us about yourself…"
|
|
758
|
+
:rows="5"
|
|
759
|
+
:maxlength="280"
|
|
760
|
+
resize="none"
|
|
761
|
+
/>
|
|
762
|
+
</template>
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
---
|
|
766
|
+
|
|
767
|
+
### InputOTP
|
|
768
|
+
|
|
769
|
+
One-time password input built on [vue-input-otp](https://github.com/wobsoriano/vue-input-otp). Compose `InputOTP`, `InputOTPGroup`, `InputOTPSlot`, and `InputOTPSeparator` to build any OTP layout.
|
|
770
|
+
|
|
771
|
+
> Requires the optional peer dependency `vue-input-otp`.
|
|
772
|
+
|
|
773
|
+
**Exported components**
|
|
774
|
+
|
|
775
|
+
`InputOTP`, `InputOTPGroup`, `InputOTPSlot`, `InputOTPSeparator`
|
|
776
|
+
|
|
777
|
+
```vue
|
|
778
|
+
<script setup>
|
|
779
|
+
import {
|
|
780
|
+
InputOTP,
|
|
781
|
+
InputOTPGroup,
|
|
782
|
+
InputOTPSlot,
|
|
783
|
+
InputOTPSeparator,
|
|
784
|
+
} from '@buillaume.biondo/fab-ui'
|
|
785
|
+
import { ref } from 'vue'
|
|
786
|
+
|
|
787
|
+
const otp = ref('')
|
|
788
|
+
</script>
|
|
789
|
+
|
|
790
|
+
<template>
|
|
791
|
+
<InputOTP v-model="otp" :max-length="6">
|
|
792
|
+
<InputOTPGroup>
|
|
793
|
+
<InputOTPSlot :index="0" />
|
|
794
|
+
<InputOTPSlot :index="1" />
|
|
795
|
+
<InputOTPSlot :index="2" />
|
|
796
|
+
</InputOTPGroup>
|
|
797
|
+
<InputOTPSeparator />
|
|
798
|
+
<InputOTPGroup>
|
|
799
|
+
<InputOTPSlot :index="3" />
|
|
800
|
+
<InputOTPSlot :index="4" />
|
|
801
|
+
<InputOTPSlot :index="5" />
|
|
802
|
+
</InputOTPGroup>
|
|
803
|
+
</InputOTP>
|
|
804
|
+
</template>
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
---
|
|
808
|
+
|
|
809
|
+
### Select
|
|
810
|
+
|
|
811
|
+
Native-feeling select dropdown built on reka-ui. Compose the subcomponents for full control over options, groups, and labels.
|
|
812
|
+
|
|
813
|
+
**Exported components**
|
|
814
|
+
|
|
815
|
+
`Select`, `SelectTrigger`, `SelectValue`, `SelectContent`, `SelectItem`, `SelectGroup`, `SelectLabel`, `SelectSeparator`, `SelectScrollUpButton`, `SelectScrollDownButton`, `SelectItemText`
|
|
816
|
+
|
|
817
|
+
**SelectTrigger props**
|
|
818
|
+
|
|
819
|
+
| Prop | Type | Default | Description |
|
|
820
|
+
|---|---|---|---|
|
|
821
|
+
| `size` | `'sm' \| 'default'` | `'default'` | Trigger height |
|
|
822
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
823
|
+
|
|
824
|
+
```vue
|
|
825
|
+
<script setup>
|
|
826
|
+
import {
|
|
827
|
+
Select,
|
|
828
|
+
SelectTrigger,
|
|
829
|
+
SelectValue,
|
|
830
|
+
SelectContent,
|
|
831
|
+
SelectGroup,
|
|
832
|
+
SelectLabel,
|
|
833
|
+
SelectItem,
|
|
834
|
+
SelectSeparator,
|
|
835
|
+
} from '@buillaume.biondo/fab-ui'
|
|
836
|
+
import { ref } from 'vue'
|
|
837
|
+
|
|
838
|
+
const role = ref('')
|
|
839
|
+
</script>
|
|
840
|
+
|
|
841
|
+
<template>
|
|
842
|
+
<Select v-model="role">
|
|
843
|
+
<SelectTrigger class="w-48">
|
|
844
|
+
<SelectValue placeholder="Select a role" />
|
|
845
|
+
</SelectTrigger>
|
|
846
|
+
<SelectContent>
|
|
847
|
+
<SelectGroup>
|
|
848
|
+
<SelectLabel>Roles</SelectLabel>
|
|
849
|
+
<SelectItem value="admin">Admin</SelectItem>
|
|
850
|
+
<SelectItem value="editor">Editor</SelectItem>
|
|
851
|
+
<SelectSeparator />
|
|
852
|
+
<SelectItem value="viewer">Viewer</SelectItem>
|
|
853
|
+
</SelectGroup>
|
|
854
|
+
</SelectContent>
|
|
855
|
+
</Select>
|
|
856
|
+
</template>
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
---
|
|
860
|
+
|
|
861
|
+
### Slider
|
|
862
|
+
|
|
863
|
+
Range slider built on reka-ui's `SliderRoot`. Supports single value, ranges (multiple thumbs), and all 8 severity variants.
|
|
864
|
+
|
|
865
|
+
**Props**
|
|
866
|
+
|
|
867
|
+
Accepts all props from reka-ui's `SliderRootProps` plus:
|
|
868
|
+
|
|
869
|
+
| Prop | Type | Default | Description |
|
|
870
|
+
|---|---|---|---|
|
|
871
|
+
| `variant` | `Severity` | `'primary'` | Track and thumb color |
|
|
872
|
+
| `size` | `'small' \| 'default' \| 'large'` | `'default'` | Track and thumb dimensions |
|
|
873
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
874
|
+
|
|
875
|
+
```vue
|
|
876
|
+
<script setup>
|
|
877
|
+
import { Slider } from '@buillaume.biondo/fab-ui'
|
|
878
|
+
import { ref } from 'vue'
|
|
879
|
+
|
|
880
|
+
const value = ref([50])
|
|
881
|
+
const range = ref([20, 80])
|
|
882
|
+
</script>
|
|
883
|
+
|
|
884
|
+
<template>
|
|
885
|
+
<!-- Single thumb -->
|
|
886
|
+
<Slider v-model="value" :min="0" :max="100" :step="1" />
|
|
887
|
+
|
|
888
|
+
<!-- Range (two thumbs) -->
|
|
889
|
+
<Slider v-model="range" variant="success" size="large" />
|
|
890
|
+
</template>
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
---
|
|
894
|
+
|
|
895
|
+
### Toggle
|
|
896
|
+
|
|
897
|
+
Toggleable button built on reka-ui's `Toggle` primitive. Useful for toolbar buttons, filter chips, and binary options.
|
|
898
|
+
|
|
899
|
+
**Props**
|
|
900
|
+
|
|
901
|
+
Accepts all props from reka-ui's `ToggleProps` plus:
|
|
902
|
+
|
|
903
|
+
| Prop | Type | Default | Description |
|
|
904
|
+
|---|---|---|---|
|
|
905
|
+
| `variant` | `Severity` | `'primary'` | Active color |
|
|
906
|
+
| `shape` | `'ghost' \| 'outline' \| 'plain'` | `'ghost'` | Visual style |
|
|
907
|
+
| `size` | `Size` | `'default'` | Button size |
|
|
908
|
+
| `onValue` | `string` | — | Label when pressed (overrides slot) |
|
|
909
|
+
| `offValue` | `string` | — | Label when not pressed (overrides slot) |
|
|
910
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
911
|
+
|
|
912
|
+
```vue
|
|
913
|
+
<script setup>
|
|
914
|
+
import { Toggle } from '@buillaume.biondo/fab-ui'
|
|
915
|
+
import { BoldIcon } from 'lucide-vue-next'
|
|
916
|
+
import { ref } from 'vue'
|
|
917
|
+
|
|
918
|
+
const bold = ref(false)
|
|
919
|
+
</script>
|
|
920
|
+
|
|
921
|
+
<template>
|
|
922
|
+
<Toggle v-model:pressed="bold" shape="outline">
|
|
923
|
+
<BoldIcon />
|
|
924
|
+
</Toggle>
|
|
925
|
+
|
|
926
|
+
<!-- With text labels -->
|
|
927
|
+
<Toggle on-value="On" off-value="Off" v-model:pressed="bold" />
|
|
928
|
+
</template>
|
|
929
|
+
```
|
|
930
|
+
|
|
931
|
+
---
|
|
932
|
+
|
|
933
|
+
### ToggleSwitch
|
|
934
|
+
|
|
935
|
+
iOS-style toggle switch built on reka-ui's `SwitchRoot`. Supports an inline label.
|
|
936
|
+
|
|
937
|
+
**Props**
|
|
938
|
+
|
|
939
|
+
Accepts all props from reka-ui's `SwitchRootProps` plus:
|
|
940
|
+
|
|
941
|
+
| Prop | Type | Default | Description |
|
|
942
|
+
|---|---|---|---|
|
|
943
|
+
| `variant` | `Severity` | `'primary'` | Track color when checked |
|
|
944
|
+
| `size` | `'small' \| 'default' \| 'large'` | `'default'` | Switch dimensions |
|
|
945
|
+
| `label` | `string` | — | Label text rendered to the right |
|
|
946
|
+
| `class` | `string` | — | Applied to the wrapper `<label>` |
|
|
947
|
+
|
|
948
|
+
```vue
|
|
949
|
+
<script setup>
|
|
950
|
+
import { ToggleSwitch } from '@buillaume.biondo/fab-ui'
|
|
951
|
+
import { ref } from 'vue'
|
|
952
|
+
|
|
953
|
+
const notifications = ref(true)
|
|
954
|
+
</script>
|
|
955
|
+
|
|
956
|
+
<template>
|
|
957
|
+
<ToggleSwitch v-model:checked="notifications" label="Email notifications" />
|
|
958
|
+
|
|
959
|
+
<ToggleSwitch
|
|
960
|
+
v-model:checked="notifications"
|
|
961
|
+
variant="success"
|
|
962
|
+
size="large"
|
|
963
|
+
label="Enable feature"
|
|
964
|
+
/>
|
|
965
|
+
</template>
|
|
966
|
+
```
|
|
967
|
+
|
|
968
|
+
---
|
|
969
|
+
|
|
970
|
+
### ProgressBar
|
|
971
|
+
|
|
972
|
+
Horizontal progress bar with determinate and indeterminate modes.
|
|
973
|
+
|
|
974
|
+
**Props**
|
|
975
|
+
|
|
976
|
+
| Prop | Type | Default | Description |
|
|
977
|
+
|---|---|---|---|
|
|
978
|
+
| `value` | `number` | — | Progress from 0 to 100. Omit for indeterminate animation |
|
|
979
|
+
| `variant` | `Severity` | `'primary'` | Fill color |
|
|
980
|
+
| `size` | `'tiny' \| 'small' \| 'default' \| 'large'` | `'default'` | Bar height |
|
|
981
|
+
| `label` | `boolean` | `false` | Shows percentage text to the right |
|
|
982
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
983
|
+
|
|
984
|
+
```vue
|
|
985
|
+
<script setup>
|
|
986
|
+
import { ProgressBar } from '@buillaume.biondo/fab-ui'
|
|
987
|
+
</script>
|
|
988
|
+
|
|
989
|
+
<template>
|
|
990
|
+
<!-- Determinate -->
|
|
991
|
+
<ProgressBar :value="72" variant="success" :label="true" />
|
|
992
|
+
|
|
993
|
+
<!-- Indeterminate -->
|
|
994
|
+
<ProgressBar variant="info" />
|
|
995
|
+
|
|
996
|
+
<!-- Sizes -->
|
|
997
|
+
<ProgressBar :value="40" size="tiny" />
|
|
998
|
+
<ProgressBar :value="40" size="large" variant="warning" />
|
|
999
|
+
</template>
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
---
|
|
1003
|
+
|
|
1004
|
+
### Skeleton
|
|
1005
|
+
|
|
1006
|
+
A pulsing placeholder block used to represent loading content. Size and shape are controlled entirely via `class`.
|
|
1007
|
+
|
|
1008
|
+
**Props**
|
|
1009
|
+
|
|
1010
|
+
| Prop | Type | Description |
|
|
1011
|
+
|---|---|---|
|
|
1012
|
+
| `class` | `string` | CSS classes for size and shape (e.g. `h-4 w-32 rounded-full`) |
|
|
1013
|
+
|
|
1014
|
+
```vue
|
|
1015
|
+
<script setup>
|
|
1016
|
+
import { Skeleton } from '@buillaume.biondo/fab-ui'
|
|
1017
|
+
</script>
|
|
1018
|
+
|
|
1019
|
+
<template>
|
|
1020
|
+
<div class="flex items-center gap-3">
|
|
1021
|
+
<Skeleton class="size-10 rounded-full" />
|
|
1022
|
+
<div class="flex flex-col gap-2">
|
|
1023
|
+
<Skeleton class="h-4 w-48" />
|
|
1024
|
+
<Skeleton class="h-3 w-32" />
|
|
1025
|
+
</div>
|
|
1026
|
+
</div>
|
|
1027
|
+
</template>
|
|
1028
|
+
```
|
|
1029
|
+
|
|
1030
|
+
---
|
|
1031
|
+
|
|
1032
|
+
### Separator
|
|
1033
|
+
|
|
1034
|
+
A thin horizontal or vertical divider line built on reka-ui.
|
|
1035
|
+
|
|
1036
|
+
**Props**
|
|
1037
|
+
|
|
1038
|
+
Accepts all props from reka-ui's `SeparatorProps` plus:
|
|
1039
|
+
|
|
1040
|
+
| Prop | Type | Default | Description |
|
|
1041
|
+
|---|---|---|---|
|
|
1042
|
+
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direction |
|
|
1043
|
+
| `decorative` | `boolean` | `true` | Marks the separator as decorative (aria hidden) |
|
|
1044
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
1045
|
+
|
|
1046
|
+
```vue
|
|
1047
|
+
<script setup>
|
|
1048
|
+
import { Separator } from '@buillaume.biondo/fab-ui'
|
|
1049
|
+
</script>
|
|
1050
|
+
|
|
1051
|
+
<template>
|
|
1052
|
+
<Separator />
|
|
1053
|
+
|
|
1054
|
+
<!-- Vertical -->
|
|
1055
|
+
<div class="flex h-8 items-center gap-4">
|
|
1056
|
+
<span>Item A</span>
|
|
1057
|
+
<Separator orientation="vertical" />
|
|
1058
|
+
<span>Item B</span>
|
|
1059
|
+
</div>
|
|
1060
|
+
</template>
|
|
1061
|
+
```
|
|
1062
|
+
|
|
1063
|
+
---
|
|
1064
|
+
|
|
1065
|
+
### Spinner
|
|
1066
|
+
|
|
1067
|
+
A minimal animated loading indicator using a spinning `Loader2` icon.
|
|
1068
|
+
|
|
1069
|
+
**Props**
|
|
1070
|
+
|
|
1071
|
+
| Prop | Type | Description |
|
|
1072
|
+
|---|---|---|
|
|
1073
|
+
| `class` | `string` | CSS classes for size (default `size-4`) and color |
|
|
1074
|
+
|
|
1075
|
+
```vue
|
|
1076
|
+
<script setup>
|
|
1077
|
+
import { Spinner } from '@buillaume.biondo/fab-ui'
|
|
1078
|
+
</script>
|
|
1079
|
+
|
|
1080
|
+
<template>
|
|
1081
|
+
<Spinner />
|
|
1082
|
+
<Spinner class="size-8 text-blue-600" />
|
|
1083
|
+
</template>
|
|
1084
|
+
```
|
|
1085
|
+
|
|
1086
|
+
---
|
|
1087
|
+
|
|
1088
|
+
### Code
|
|
1089
|
+
|
|
1090
|
+
Syntax-highlighted code block powered by [highlight.js](https://highlightjs.org/) with the Atom One Dark theme. Supports automatic language detection, line numbers, a copy-to-clipboard button, and a macOS-style window chrome.
|
|
1091
|
+
|
|
1092
|
+
**Props**
|
|
1093
|
+
|
|
1094
|
+
| Prop | Type | Default | Description |
|
|
1095
|
+
|---|---|---|---|
|
|
1096
|
+
| `code` | `string` | — | Code string to display (or use the default slot) |
|
|
1097
|
+
| `language` | `string` | — | highlight.js language identifier (auto-detected if omitted) |
|
|
1098
|
+
| `filename` | `string` | — | Filename shown in the header bar |
|
|
1099
|
+
| `copyable` | `boolean` | `true` | Shows the copy-to-clipboard button |
|
|
1100
|
+
| `lineNumbers` | `boolean` | `false` | Displays line numbers |
|
|
1101
|
+
| `maxHeight` | `string` | — | CSS max-height for scrollable blocks (e.g. `'400px'`) |
|
|
1102
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
1103
|
+
|
|
1104
|
+
```vue
|
|
1105
|
+
<script setup>
|
|
1106
|
+
import { Code } from '@buillaume.biondo/fab-ui'
|
|
1107
|
+
</script>
|
|
1108
|
+
|
|
1109
|
+
<template>
|
|
1110
|
+
<Code
|
|
1111
|
+
language="javascript"
|
|
1112
|
+
filename="utils.js"
|
|
1113
|
+
:line-numbers="true"
|
|
1114
|
+
max-height="300px"
|
|
1115
|
+
:code="`function greet(name) {\n return 'Hello, ' + name\n}`"
|
|
1116
|
+
/>
|
|
1117
|
+
|
|
1118
|
+
<!-- Via default slot -->
|
|
1119
|
+
<Code language="bash">
|
|
1120
|
+
npm install @buillaume.biondo/fab-ui
|
|
1121
|
+
</Code>
|
|
1122
|
+
</template>
|
|
1123
|
+
```
|
|
1124
|
+
|
|
1125
|
+
---
|
|
1126
|
+
|
|
1127
|
+
### Image
|
|
1128
|
+
|
|
1129
|
+
Smart image container with lazy loading, skeleton placeholder, aspect ratio enforcement, object-fit control, and a fallback for broken images.
|
|
1130
|
+
|
|
1131
|
+
**Props**
|
|
1132
|
+
|
|
1133
|
+
| Prop | Type | Default | Description |
|
|
1134
|
+
|---|---|---|---|
|
|
1135
|
+
| `src` | `string` | — | Image URL (required) |
|
|
1136
|
+
| `alt` | `string` | `''` | Alt text |
|
|
1137
|
+
| `ratio` | `'1/1' \| '4/3' \| '16/9' \| '3/2' \| '2/3' \| '9/16'` | — | Fixed aspect ratio |
|
|
1138
|
+
| `fit` | `'cover' \| 'contain' \| 'fill' \| 'none'` | `'cover'` | CSS `object-fit` value |
|
|
1139
|
+
| `skeleton` | `boolean` | `true` | Shows a pulsing placeholder while loading |
|
|
1140
|
+
| `fallback` | `string` | — | Fallback image URL shown on error |
|
|
1141
|
+
| `rounded` | `boolean \| 'full'` | `false` | Border radius (`true` = card radius, `'full'` = circle) |
|
|
1142
|
+
| `class` | `string` | — | Applied to the container div |
|
|
1143
|
+
|
|
1144
|
+
**Emits**
|
|
1145
|
+
|
|
1146
|
+
| Event | Description |
|
|
1147
|
+
|---|---|
|
|
1148
|
+
| `load` | Native `load` event from `<img>` |
|
|
1149
|
+
| `error` | Native `error` event from `<img>` |
|
|
1150
|
+
|
|
1151
|
+
```vue
|
|
1152
|
+
<script setup>
|
|
1153
|
+
import { Image } from '@buillaume.biondo/fab-ui'
|
|
1154
|
+
</script>
|
|
1155
|
+
|
|
1156
|
+
<template>
|
|
1157
|
+
<Image
|
|
1158
|
+
src="/photos/hero.jpg"
|
|
1159
|
+
alt="Hero image"
|
|
1160
|
+
ratio="16/9"
|
|
1161
|
+
fallback="/photos/placeholder.jpg"
|
|
1162
|
+
:rounded="true"
|
|
1163
|
+
/>
|
|
1164
|
+
|
|
1165
|
+
<!-- Avatar-style -->
|
|
1166
|
+
<Image
|
|
1167
|
+
src="/avatars/user.jpg"
|
|
1168
|
+
alt="User avatar"
|
|
1169
|
+
ratio="1/1"
|
|
1170
|
+
rounded="full"
|
|
1171
|
+
class="w-16"
|
|
1172
|
+
/>
|
|
1173
|
+
</template>
|
|
1174
|
+
```
|
|
1175
|
+
|
|
1176
|
+
---
|
|
1177
|
+
|
|
1178
|
+
### Carousel
|
|
1179
|
+
|
|
1180
|
+
A touch-friendly slideshow with optional navigation arrows, dot indicators, autoplay, loop, and multi-slide view support.
|
|
1181
|
+
|
|
1182
|
+
**Props**
|
|
1183
|
+
|
|
1184
|
+
| Prop | Type | Default | Description |
|
|
1185
|
+
|---|---|---|---|
|
|
1186
|
+
| `arrows` | `boolean` | `true` | Show previous/next arrow buttons |
|
|
1187
|
+
| `dots` | `boolean` | `true` | Show dot indicator buttons |
|
|
1188
|
+
| `autoplay` | `number` | `0` | Autoplay interval in ms (`0` = disabled) |
|
|
1189
|
+
| `loop` | `boolean` | `false` | Wrap around from last to first slide |
|
|
1190
|
+
| `perView` | `number` | `1` | Number of slides visible at once |
|
|
1191
|
+
| `gap` | `string` | `'gap-4'` | Tailwind gap class between slides |
|
|
1192
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
1193
|
+
|
|
1194
|
+
```vue
|
|
1195
|
+
<script setup>
|
|
1196
|
+
import { Carousel, CarouselSlide } from '@buillaume.biondo/fab-ui'
|
|
1197
|
+
</script>
|
|
1198
|
+
|
|
1199
|
+
<template>
|
|
1200
|
+
<Carousel :autoplay="3000" :loop="true" :dots="true">
|
|
1201
|
+
<CarouselSlide>
|
|
1202
|
+
<Image src="/slides/1.jpg" ratio="16/9" />
|
|
1203
|
+
</CarouselSlide>
|
|
1204
|
+
<CarouselSlide>
|
|
1205
|
+
<Image src="/slides/2.jpg" ratio="16/9" />
|
|
1206
|
+
</CarouselSlide>
|
|
1207
|
+
<CarouselSlide>
|
|
1208
|
+
<Image src="/slides/3.jpg" ratio="16/9" />
|
|
1209
|
+
</CarouselSlide>
|
|
1210
|
+
</Carousel>
|
|
1211
|
+
|
|
1212
|
+
<!-- Multi-slide -->
|
|
1213
|
+
<Carousel :per-view="3" gap="gap-6">
|
|
1214
|
+
<CarouselSlide v-for="item in items" :key="item.id">
|
|
1215
|
+
<Card>{{ item.title }}</Card>
|
|
1216
|
+
</CarouselSlide>
|
|
1217
|
+
</Carousel>
|
|
1218
|
+
</template>
|
|
1219
|
+
```
|
|
1220
|
+
|
|
1221
|
+
---
|
|
1222
|
+
|
|
1223
|
+
### DataTable
|
|
1224
|
+
|
|
1225
|
+
A feature-complete data table with client-side sorting, global search with debounce, pagination with ellipsis, row selection, custom cell rendering via named slots, and a loading skeleton.
|
|
1226
|
+
|
|
1227
|
+
**Props**
|
|
1228
|
+
|
|
1229
|
+
| Prop | Type | Default | Description |
|
|
1230
|
+
|---|---|---|---|
|
|
1231
|
+
| `columns` | `DataTableColumn[]` | — | Column definitions (required) |
|
|
1232
|
+
| `data` | `T[]` | — | Row data (required) |
|
|
1233
|
+
| `searchable` | `boolean` | — | Renders a search input above the table |
|
|
1234
|
+
| `selectable` | `boolean` | — | Renders a checkbox column |
|
|
1235
|
+
| `pageSize` | `number` | `15` | Initial rows per page |
|
|
1236
|
+
| `pageSizes` | `number[]` | `[10, 25, 50, 100]` | Page size options in the selector |
|
|
1237
|
+
| `loading` | `boolean` | — | Shows a skeleton instead of data |
|
|
1238
|
+
| `emptyText` | `string` | `'Aucun résultat.'` | Text displayed when there are no rows |
|
|
1239
|
+
| `striped` | `boolean` | — | Alternating row background |
|
|
1240
|
+
| `hoverable` | `boolean` | `true` | Highlights rows on hover |
|
|
1241
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
1242
|
+
|
|
1243
|
+
**`DataTableColumn` definition**
|
|
1244
|
+
|
|
1245
|
+
```ts
|
|
1246
|
+
interface DataTableColumn<Row> {
|
|
1247
|
+
key: string // Row property key
|
|
1248
|
+
label: string // Column header text
|
|
1249
|
+
sortable?: boolean // Enables client-side sorting
|
|
1250
|
+
width?: string // CSS column width
|
|
1251
|
+
align?: 'left' | 'center' | 'right'
|
|
1252
|
+
format?: (value: unknown, row: Row) => string // Custom cell formatter
|
|
1253
|
+
}
|
|
1254
|
+
```
|
|
1255
|
+
|
|
1256
|
+
**Models**
|
|
1257
|
+
|
|
1258
|
+
| Model | Type | Description |
|
|
1259
|
+
|---|---|---|
|
|
1260
|
+
| `v-model:selected` | `T[]` | Two-way binding for selected rows. The checkbox column appears automatically when bound |
|
|
1261
|
+
|
|
1262
|
+
**Emits**
|
|
1263
|
+
|
|
1264
|
+
| Event | Payload | Description |
|
|
1265
|
+
|---|---|---|
|
|
1266
|
+
| `row-click` | `row: T` | Fired when a row is clicked |
|
|
1267
|
+
| `cell-click` | `key: string, row: T` | Fired when a cell is clicked |
|
|
1268
|
+
|
|
1269
|
+
**Slots**
|
|
1270
|
+
|
|
1271
|
+
| Slot | Props | Description |
|
|
1272
|
+
|---|---|---|
|
|
1273
|
+
| `#column-{key}` | `{ row, value }` | Custom cell renderer for the given column key |
|
|
1274
|
+
| `#empty` | — | Custom empty state content |
|
|
1275
|
+
|
|
1276
|
+
```vue
|
|
1277
|
+
<script setup>
|
|
1278
|
+
import { DataTable } from '@buillaume.biondo/fab-ui'
|
|
1279
|
+
import { Badge } from '@buillaume.biondo/fab-ui'
|
|
1280
|
+
import { ref } from 'vue'
|
|
1281
|
+
|
|
1282
|
+
const columns = [
|
|
1283
|
+
{ key: 'name', label: 'Name', sortable: true },
|
|
1284
|
+
{ key: 'email', label: 'Email', sortable: true },
|
|
1285
|
+
{ key: 'role', label: 'Role' },
|
|
1286
|
+
{ key: 'status', label: 'Status' },
|
|
1287
|
+
]
|
|
1288
|
+
|
|
1289
|
+
const users = ref([
|
|
1290
|
+
{ name: 'Alice', email: 'alice@example.com', role: 'Admin', status: 'active' },
|
|
1291
|
+
{ name: 'Bob', email: 'bob@example.com', role: 'Editor', status: 'inactive' },
|
|
1292
|
+
])
|
|
1293
|
+
|
|
1294
|
+
const selected = ref([])
|
|
1295
|
+
</script>
|
|
1296
|
+
|
|
1297
|
+
<template>
|
|
1298
|
+
<DataTable
|
|
1299
|
+
:columns="columns"
|
|
1300
|
+
:data="users"
|
|
1301
|
+
v-model:selected="selected"
|
|
1302
|
+
:searchable="true"
|
|
1303
|
+
:striped="true"
|
|
1304
|
+
@row-click="(row) => console.log(row)"
|
|
1305
|
+
>
|
|
1306
|
+
<!-- Custom status cell -->
|
|
1307
|
+
<template #column-status="{ value }">
|
|
1308
|
+
<Badge :variant="value === 'active' ? 'success' : 'secondary'">
|
|
1309
|
+
{{ value }}
|
|
1310
|
+
</Badge>
|
|
1311
|
+
</template>
|
|
1312
|
+
</DataTable>
|
|
1313
|
+
</template>
|
|
1314
|
+
```
|
|
1315
|
+
|
|
1316
|
+
---
|
|
1317
|
+
|
|
1318
|
+
### Toast / Toaster
|
|
1319
|
+
|
|
1320
|
+
Toast notifications managed through the `useToast` composable. Mount `Toaster` once in your layout — it renders at the bottom-right of the viewport with animated transitions and a progress bar.
|
|
1321
|
+
|
|
1322
|
+
**Toast variants:** `info` | `success` | `warning` | `error`
|
|
1323
|
+
|
|
1324
|
+
**Default durations:**
|
|
1325
|
+
- `info`, `success`: 4 seconds
|
|
1326
|
+
- `warning`: 6 seconds
|
|
1327
|
+
- `error`: persistent (no auto-dismiss)
|
|
1328
|
+
|
|
1329
|
+
See the [useToast](#usetoast) composable section for the full API.
|
|
1330
|
+
|
|
1331
|
+
```vue
|
|
1332
|
+
<!-- Root layout -->
|
|
1333
|
+
<script setup>
|
|
1334
|
+
import { Toaster } from '@buillaume.biondo/fab-ui'
|
|
1335
|
+
</script>
|
|
1336
|
+
|
|
1337
|
+
<template>
|
|
1338
|
+
<slot />
|
|
1339
|
+
<Toaster />
|
|
1340
|
+
</template>
|
|
1341
|
+
```
|
|
1342
|
+
|
|
1343
|
+
```vue
|
|
1344
|
+
<!-- Anywhere in your app -->
|
|
1345
|
+
<script setup>
|
|
1346
|
+
import { useToast } from '@buillaume.biondo/fab-ui'
|
|
1347
|
+
|
|
1348
|
+
const toast = useToast()
|
|
1349
|
+
</script>
|
|
1350
|
+
|
|
1351
|
+
<template>
|
|
1352
|
+
<Button @click="toast.success('Saved successfully!')">Save</Button>
|
|
1353
|
+
<Button @click="toast.error('Something went wrong.')">Fail</Button>
|
|
1354
|
+
</template>
|
|
1355
|
+
```
|
|
1356
|
+
|
|
1357
|
+
---
|
|
1358
|
+
|
|
1359
|
+
### SpeedDial
|
|
1360
|
+
|
|
1361
|
+
A floating action button (FAB) that expands into a list of action buttons in any direction. Actions appear with a staggered animation and display labels as tooltips on hover.
|
|
1362
|
+
|
|
1363
|
+
**`SpeedDialItem` interface**
|
|
1364
|
+
|
|
1365
|
+
```ts
|
|
1366
|
+
interface SpeedDialItem {
|
|
1367
|
+
label: string // Tooltip and accessible label
|
|
1368
|
+
icon: Component // Lucide icon component
|
|
1369
|
+
onClick: () => void // Click handler
|
|
1370
|
+
disabled?: boolean
|
|
1371
|
+
variant?: Severity // Button color (default: 'secondary')
|
|
1372
|
+
}
|
|
1373
|
+
```
|
|
1374
|
+
|
|
1375
|
+
**Props**
|
|
1376
|
+
|
|
1377
|
+
| Prop | Type | Default | Description |
|
|
1378
|
+
|---|---|---|---|
|
|
1379
|
+
| `items` | `SpeedDialItem[]` | — | Action buttons (required) |
|
|
1380
|
+
| `direction` | `'up' \| 'down' \| 'left' \| 'right'` | `'up'` | Direction the actions expand |
|
|
1381
|
+
| `variant` | `Severity` | `'primary'` | Main FAB button color |
|
|
1382
|
+
| `size` | `'small' \| 'default' \| 'large'` | `'default'` | Button size |
|
|
1383
|
+
| `icon` | `Component` | — | Custom icon for the main button (defaults to `+` / `×`) |
|
|
1384
|
+
| `disabled` | `boolean` | — | Disables the FAB |
|
|
1385
|
+
| `class` | `string` | — | Additional CSS classes on the wrapper |
|
|
1386
|
+
|
|
1387
|
+
```vue
|
|
1388
|
+
<script setup>
|
|
1389
|
+
import { SpeedDial } from '@buillaume.biondo/fab-ui'
|
|
1390
|
+
import { PencilIcon, TrashIcon, ShareIcon } from 'lucide-vue-next'
|
|
1391
|
+
|
|
1392
|
+
const actions = [
|
|
1393
|
+
{ label: 'Edit', icon: PencilIcon, onClick: () => edit(), variant: 'primary' },
|
|
1394
|
+
{ label: 'Share', icon: ShareIcon, onClick: () => share(), variant: 'info' },
|
|
1395
|
+
{ label: 'Delete', icon: TrashIcon, onClick: () => remove(), variant: 'danger' },
|
|
1396
|
+
]
|
|
1397
|
+
</script>
|
|
1398
|
+
|
|
1399
|
+
<template>
|
|
1400
|
+
<SpeedDial :items="actions" direction="up" />
|
|
1401
|
+
</template>
|
|
1402
|
+
```
|
|
1403
|
+
|
|
1404
|
+
---
|
|
1405
|
+
|
|
1406
|
+
### SplitButton
|
|
1407
|
+
|
|
1408
|
+
A composite button with a primary action and a dropdown arrow that reveals additional options.
|
|
1409
|
+
|
|
1410
|
+
**Props**
|
|
1411
|
+
|
|
1412
|
+
| Prop | Type | Default | Description |
|
|
1413
|
+
|---|---|---|---|
|
|
1414
|
+
| `variant` | `Severity` | `'primary'` | Color variant |
|
|
1415
|
+
| `shape` | `'plain' \| 'outline' \| 'ghost'` | `'plain'` | Visual style |
|
|
1416
|
+
| `size` | `Size` | `'default'` | Button size |
|
|
1417
|
+
| `fluid` | `boolean` | `false` | Full-width |
|
|
1418
|
+
| `disabled` | `boolean` | `false` | Disables both parts |
|
|
1419
|
+
| `loading` | `boolean` | `false` | Shows spinner on the main button |
|
|
1420
|
+
| `iconLeft` | `Component` | — | Icon component on the main button |
|
|
1421
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
1422
|
+
|
|
1423
|
+
**Slots**
|
|
1424
|
+
|
|
1425
|
+
| Slot | Description |
|
|
1426
|
+
|---|---|
|
|
1427
|
+
| `default` | Label of the main button |
|
|
1428
|
+
| `#dropdown` | `DropdownMenuItem` components for the dropdown |
|
|
1429
|
+
|
|
1430
|
+
**Emits**
|
|
1431
|
+
|
|
1432
|
+
| Event | Description |
|
|
1433
|
+
|---|---|
|
|
1434
|
+
| `click` | Fired when the main button is clicked |
|
|
1435
|
+
|
|
1436
|
+
```vue
|
|
1437
|
+
<script setup>
|
|
1438
|
+
import {
|
|
1439
|
+
SplitButton,
|
|
1440
|
+
DropdownMenuItem,
|
|
1441
|
+
DropdownMenuSeparator,
|
|
1442
|
+
} from '@buillaume.biondo/fab-ui'
|
|
1443
|
+
</script>
|
|
1444
|
+
|
|
1445
|
+
<template>
|
|
1446
|
+
<SplitButton @click="save()">
|
|
1447
|
+
Save
|
|
1448
|
+
|
|
1449
|
+
<template #dropdown>
|
|
1450
|
+
<DropdownMenuItem @click="saveAndPublish()">Save & publish</DropdownMenuItem>
|
|
1451
|
+
<DropdownMenuSeparator />
|
|
1452
|
+
<DropdownMenuItem @click="saveDraft()">Save as draft</DropdownMenuItem>
|
|
1453
|
+
</template>
|
|
1454
|
+
</SplitButton>
|
|
1455
|
+
</template>
|
|
1456
|
+
```
|
|
1457
|
+
|
|
1458
|
+
---
|
|
1459
|
+
|
|
1460
|
+
### Tooltip
|
|
1461
|
+
|
|
1462
|
+
Simple tooltip built on reka-ui. Wrap your trigger with `TooltipProvider`, use `Tooltip` + `TooltipTrigger` + `TooltipContent`.
|
|
1463
|
+
|
|
1464
|
+
**Exported components**
|
|
1465
|
+
|
|
1466
|
+
`TooltipProvider`, `Tooltip`, `TooltipTrigger`, `TooltipContent`
|
|
1467
|
+
|
|
1468
|
+
```vue
|
|
1469
|
+
<script setup>
|
|
1470
|
+
import {
|
|
1471
|
+
Tooltip,
|
|
1472
|
+
TooltipContent,
|
|
1473
|
+
TooltipProvider,
|
|
1474
|
+
TooltipTrigger,
|
|
1475
|
+
Button,
|
|
1476
|
+
} from '@buillaume.biondo/fab-ui'
|
|
1477
|
+
import { SettingsIcon } from 'lucide-vue-next'
|
|
1478
|
+
</script>
|
|
1479
|
+
|
|
1480
|
+
<template>
|
|
1481
|
+
<TooltipProvider>
|
|
1482
|
+
<Tooltip>
|
|
1483
|
+
<TooltipTrigger as-child>
|
|
1484
|
+
<Button :icon="true" shape="ghost" variant="secondary">
|
|
1485
|
+
<SettingsIcon />
|
|
1486
|
+
</Button>
|
|
1487
|
+
</TooltipTrigger>
|
|
1488
|
+
<TooltipContent>Settings</TooltipContent>
|
|
1489
|
+
</Tooltip>
|
|
1490
|
+
</TooltipProvider>
|
|
1491
|
+
</template>
|
|
1492
|
+
```
|
|
1493
|
+
|
|
1494
|
+
---
|
|
1495
|
+
|
|
1496
|
+
### Collapsible
|
|
1497
|
+
|
|
1498
|
+
Expandable / collapsible section built on reka-ui. `CollapsibleContent` supports an `overlay` mode that floats the content above the document flow.
|
|
1499
|
+
|
|
1500
|
+
**Exported components**
|
|
1501
|
+
|
|
1502
|
+
`Collapsible`, `CollapsibleTrigger`, `CollapsibleContent`
|
|
1503
|
+
|
|
1504
|
+
**`CollapsibleContent` props**
|
|
1505
|
+
|
|
1506
|
+
| Prop | Type | Default | Description |
|
|
1507
|
+
|---|---|---|---|
|
|
1508
|
+
| `overlay` | `boolean` | `false` | Positions content as an absolute overlay (`z-20`) |
|
|
1509
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
1510
|
+
|
|
1511
|
+
```vue
|
|
1512
|
+
<script setup>
|
|
1513
|
+
import {
|
|
1514
|
+
Collapsible,
|
|
1515
|
+
CollapsibleTrigger,
|
|
1516
|
+
CollapsibleContent,
|
|
1517
|
+
Button,
|
|
1518
|
+
} from '@buillaume.biondo/fab-ui'
|
|
1519
|
+
import { ref } from 'vue'
|
|
1520
|
+
|
|
1521
|
+
const open = ref(false)
|
|
1522
|
+
</script>
|
|
1523
|
+
|
|
1524
|
+
<template>
|
|
1525
|
+
<Collapsible v-model:open="open">
|
|
1526
|
+
<CollapsibleTrigger as-child>
|
|
1527
|
+
<Button shape="ghost">Toggle section</Button>
|
|
1528
|
+
</CollapsibleTrigger>
|
|
1529
|
+
<CollapsibleContent>
|
|
1530
|
+
<p class="mt-2 text-sm">Hidden content revealed on toggle.</p>
|
|
1531
|
+
</CollapsibleContent>
|
|
1532
|
+
</Collapsible>
|
|
1533
|
+
</template>
|
|
1534
|
+
```
|
|
1535
|
+
|
|
1536
|
+
---
|
|
1537
|
+
|
|
1538
|
+
### DropdownMenu
|
|
1539
|
+
|
|
1540
|
+
Full-featured dropdown menu built on reka-ui with support for items, checkboxes, radio groups, sub-menus, separators, and keyboard shortcuts.
|
|
1541
|
+
|
|
1542
|
+
**Exported components**
|
|
1543
|
+
|
|
1544
|
+
`DropdownMenu`, `DropdownMenuTrigger`, `DropdownMenuContent`, `DropdownMenuItem`, `DropdownMenuLabel`, `DropdownMenuSeparator`, `DropdownMenuShortcut`, `DropdownMenuGroup`, `DropdownMenuSub`, `DropdownMenuSubTrigger`, `DropdownMenuSubContent`, `DropdownMenuCheckboxItem`, `DropdownMenuRadioGroup`, `DropdownMenuRadioItem`, `DropdownMenuPortal`
|
|
1545
|
+
|
|
1546
|
+
```vue
|
|
1547
|
+
<script setup>
|
|
1548
|
+
import {
|
|
1549
|
+
DropdownMenu,
|
|
1550
|
+
DropdownMenuTrigger,
|
|
1551
|
+
DropdownMenuContent,
|
|
1552
|
+
DropdownMenuLabel,
|
|
1553
|
+
DropdownMenuItem,
|
|
1554
|
+
DropdownMenuSeparator,
|
|
1555
|
+
DropdownMenuShortcut,
|
|
1556
|
+
Button,
|
|
1557
|
+
} from '@buillaume.biondo/fab-ui'
|
|
1558
|
+
</script>
|
|
1559
|
+
|
|
1560
|
+
<template>
|
|
1561
|
+
<DropdownMenu>
|
|
1562
|
+
<DropdownMenuTrigger as-child>
|
|
1563
|
+
<Button shape="outline" variant="secondary">Options</Button>
|
|
1564
|
+
</DropdownMenuTrigger>
|
|
1565
|
+
<DropdownMenuContent class="w-48">
|
|
1566
|
+
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
|
1567
|
+
<DropdownMenuSeparator />
|
|
1568
|
+
<DropdownMenuItem>
|
|
1569
|
+
Profile
|
|
1570
|
+
<DropdownMenuShortcut>⌘P</DropdownMenuShortcut>
|
|
1571
|
+
</DropdownMenuItem>
|
|
1572
|
+
<DropdownMenuItem>Settings</DropdownMenuItem>
|
|
1573
|
+
<DropdownMenuSeparator />
|
|
1574
|
+
<DropdownMenuItem class="text-danger">Log out</DropdownMenuItem>
|
|
1575
|
+
</DropdownMenuContent>
|
|
1576
|
+
</DropdownMenu>
|
|
1577
|
+
</template>
|
|
1578
|
+
```
|
|
1579
|
+
|
|
1580
|
+
---
|
|
1581
|
+
|
|
1582
|
+
### ContextMenu
|
|
1583
|
+
|
|
1584
|
+
Right-click context menu with the same feature set as `DropdownMenu`. `ContextMenuItem` accepts a `variant="danger"` prop for destructive actions.
|
|
1585
|
+
|
|
1586
|
+
**Exported components**
|
|
1587
|
+
|
|
1588
|
+
`ContextMenu`, `ContextMenuTrigger`, `ContextMenuContent`, `ContextMenuItem`, `ContextMenuLabel`, `ContextMenuSeparator`, `ContextMenuShortcut`, `ContextMenuGroup`, `ContextMenuSub`, `ContextMenuSubTrigger`, `ContextMenuSubContent`, `ContextMenuCheckboxItem`, `ContextMenuRadioGroup`, `ContextMenuRadioItem`
|
|
1589
|
+
|
|
1590
|
+
**`ContextMenuItem` extra props**
|
|
1591
|
+
|
|
1592
|
+
| Prop | Type | Default | Description |
|
|
1593
|
+
|---|---|---|---|
|
|
1594
|
+
| `variant` | `'default' \| 'danger'` | `'default'` | Renders the item in danger color |
|
|
1595
|
+
| `inset` | `boolean` | — | Adds extra left padding for alignment without an icon |
|
|
1596
|
+
|
|
1597
|
+
```vue
|
|
1598
|
+
<script setup>
|
|
1599
|
+
import {
|
|
1600
|
+
ContextMenu,
|
|
1601
|
+
ContextMenuTrigger,
|
|
1602
|
+
ContextMenuContent,
|
|
1603
|
+
ContextMenuItem,
|
|
1604
|
+
ContextMenuSeparator,
|
|
1605
|
+
} from '@buillaume.biondo/fab-ui'
|
|
1606
|
+
</script>
|
|
1607
|
+
|
|
1608
|
+
<template>
|
|
1609
|
+
<ContextMenu>
|
|
1610
|
+
<ContextMenuTrigger>
|
|
1611
|
+
<div class="p-8 border rounded">Right-click me</div>
|
|
1612
|
+
</ContextMenuTrigger>
|
|
1613
|
+
<ContextMenuContent>
|
|
1614
|
+
<ContextMenuItem>Edit</ContextMenuItem>
|
|
1615
|
+
<ContextMenuItem>Duplicate</ContextMenuItem>
|
|
1616
|
+
<ContextMenuSeparator />
|
|
1617
|
+
<ContextMenuItem variant="danger">Delete</ContextMenuItem>
|
|
1618
|
+
</ContextMenuContent>
|
|
1619
|
+
</ContextMenu>
|
|
1620
|
+
</template>
|
|
1621
|
+
```
|
|
1622
|
+
|
|
1623
|
+
---
|
|
1624
|
+
|
|
1625
|
+
### Dialog
|
|
1626
|
+
|
|
1627
|
+
Modal dialog built on reka-ui with animated overlay, a close button, and a scrollable variant.
|
|
1628
|
+
|
|
1629
|
+
**Exported components**
|
|
1630
|
+
|
|
1631
|
+
`Dialog`, `DialogTrigger`, `DialogContent`, `DialogScrollContent`, `DialogHeader`, `DialogFooter`, `DialogTitle`, `DialogDescription`, `DialogClose`, `DialogOverlay`
|
|
1632
|
+
|
|
1633
|
+
**`DialogContent` extra props**
|
|
1634
|
+
|
|
1635
|
+
| Prop | Type | Default | Description |
|
|
1636
|
+
|---|---|---|---|
|
|
1637
|
+
| `showCloseButton` | `boolean` | `true` | Renders the `×` close button in the top-right corner |
|
|
1638
|
+
|
|
1639
|
+
```vue
|
|
1640
|
+
<script setup>
|
|
1641
|
+
import {
|
|
1642
|
+
Dialog,
|
|
1643
|
+
DialogTrigger,
|
|
1644
|
+
DialogContent,
|
|
1645
|
+
DialogHeader,
|
|
1646
|
+
DialogTitle,
|
|
1647
|
+
DialogDescription,
|
|
1648
|
+
DialogFooter,
|
|
1649
|
+
Button,
|
|
1650
|
+
} from '@buillaume.biondo/fab-ui'
|
|
1651
|
+
</script>
|
|
1652
|
+
|
|
1653
|
+
<template>
|
|
1654
|
+
<Dialog>
|
|
1655
|
+
<DialogTrigger as-child>
|
|
1656
|
+
<Button>Open dialog</Button>
|
|
1657
|
+
</DialogTrigger>
|
|
1658
|
+
<DialogContent>
|
|
1659
|
+
<DialogHeader>
|
|
1660
|
+
<DialogTitle>Confirm deletion</DialogTitle>
|
|
1661
|
+
<DialogDescription>
|
|
1662
|
+
This action cannot be undone. Are you sure?
|
|
1663
|
+
</DialogDescription>
|
|
1664
|
+
</DialogHeader>
|
|
1665
|
+
<DialogFooter>
|
|
1666
|
+
<Button shape="outline" variant="secondary">Cancel</Button>
|
|
1667
|
+
<Button variant="danger">Delete</Button>
|
|
1668
|
+
</DialogFooter>
|
|
1669
|
+
</DialogContent>
|
|
1670
|
+
</Dialog>
|
|
1671
|
+
</template>
|
|
1672
|
+
```
|
|
1673
|
+
|
|
1674
|
+
---
|
|
1675
|
+
|
|
1676
|
+
### Sheet
|
|
1677
|
+
|
|
1678
|
+
Slide-in panel (drawer) that opens from any side of the screen. Built on the same Dialog primitives as the `Dialog` component.
|
|
1679
|
+
|
|
1680
|
+
**Exported components**
|
|
1681
|
+
|
|
1682
|
+
`Sheet`, `SheetTrigger`, `SheetContent`, `SheetHeader`, `SheetFooter`, `SheetTitle`, `SheetDescription`, `SheetClose`, `SheetOverlay`
|
|
1683
|
+
|
|
1684
|
+
**`SheetContent` extra props**
|
|
1685
|
+
|
|
1686
|
+
| Prop | Type | Default | Description |
|
|
1687
|
+
|---|---|---|---|
|
|
1688
|
+
| `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'right'` | The edge the sheet slides in from |
|
|
1689
|
+
|
|
1690
|
+
```vue
|
|
1691
|
+
<script setup>
|
|
1692
|
+
import {
|
|
1693
|
+
Sheet,
|
|
1694
|
+
SheetTrigger,
|
|
1695
|
+
SheetContent,
|
|
1696
|
+
SheetHeader,
|
|
1697
|
+
SheetTitle,
|
|
1698
|
+
SheetDescription,
|
|
1699
|
+
Button,
|
|
1700
|
+
} from '@buillaume.biondo/fab-ui'
|
|
1701
|
+
</script>
|
|
1702
|
+
|
|
1703
|
+
<template>
|
|
1704
|
+
<Sheet>
|
|
1705
|
+
<SheetTrigger as-child>
|
|
1706
|
+
<Button shape="outline">Open panel</Button>
|
|
1707
|
+
</SheetTrigger>
|
|
1708
|
+
<SheetContent side="right">
|
|
1709
|
+
<SheetHeader>
|
|
1710
|
+
<SheetTitle>Settings</SheetTitle>
|
|
1711
|
+
<SheetDescription>Adjust your preferences.</SheetDescription>
|
|
1712
|
+
</SheetHeader>
|
|
1713
|
+
<p class="py-4">Sheet content goes here.</p>
|
|
1714
|
+
</SheetContent>
|
|
1715
|
+
</Sheet>
|
|
1716
|
+
</template>
|
|
1717
|
+
```
|
|
1718
|
+
|
|
1719
|
+
---
|
|
1720
|
+
|
|
1721
|
+
### Breadcrumb
|
|
1722
|
+
|
|
1723
|
+
Semantic breadcrumb navigation with built-in separator, ellipsis, and current page support.
|
|
1724
|
+
|
|
1725
|
+
**Exported components**
|
|
1726
|
+
|
|
1727
|
+
`Breadcrumb`, `BreadcrumbList`, `BreadcrumbItem`, `BreadcrumbLink`, `BreadcrumbPage`, `BreadcrumbSeparator`, `BreadcrumbEllipsis`
|
|
1728
|
+
|
|
1729
|
+
```vue
|
|
1730
|
+
<script setup>
|
|
1731
|
+
import {
|
|
1732
|
+
Breadcrumb,
|
|
1733
|
+
BreadcrumbList,
|
|
1734
|
+
BreadcrumbItem,
|
|
1735
|
+
BreadcrumbLink,
|
|
1736
|
+
BreadcrumbSeparator,
|
|
1737
|
+
BreadcrumbPage,
|
|
1738
|
+
BreadcrumbEllipsis,
|
|
1739
|
+
} from '@buillaume.biondo/fab-ui'
|
|
1740
|
+
</script>
|
|
1741
|
+
|
|
1742
|
+
<template>
|
|
1743
|
+
<Breadcrumb>
|
|
1744
|
+
<BreadcrumbList>
|
|
1745
|
+
<BreadcrumbItem>
|
|
1746
|
+
<BreadcrumbLink href="/">Home</BreadcrumbLink>
|
|
1747
|
+
</BreadcrumbItem>
|
|
1748
|
+
<BreadcrumbSeparator />
|
|
1749
|
+
<BreadcrumbItem>
|
|
1750
|
+
<BreadcrumbEllipsis />
|
|
1751
|
+
</BreadcrumbItem>
|
|
1752
|
+
<BreadcrumbSeparator />
|
|
1753
|
+
<BreadcrumbItem>
|
|
1754
|
+
<BreadcrumbLink href="/docs">Docs</BreadcrumbLink>
|
|
1755
|
+
</BreadcrumbItem>
|
|
1756
|
+
<BreadcrumbSeparator />
|
|
1757
|
+
<BreadcrumbItem>
|
|
1758
|
+
<BreadcrumbPage>Getting started</BreadcrumbPage>
|
|
1759
|
+
</BreadcrumbItem>
|
|
1760
|
+
</BreadcrumbList>
|
|
1761
|
+
</Breadcrumb>
|
|
1762
|
+
</template>
|
|
1763
|
+
```
|
|
1764
|
+
|
|
1765
|
+
---
|
|
1766
|
+
|
|
1767
|
+
### NavigationMenu
|
|
1768
|
+
|
|
1769
|
+
Horizontal navigation menu with animated content panels, built on reka-ui.
|
|
1770
|
+
|
|
1771
|
+
**Exported components**
|
|
1772
|
+
|
|
1773
|
+
`NavigationMenu`, `NavigationMenuList`, `NavigationMenuItem`, `NavigationMenuTrigger`, `NavigationMenuContent`, `NavigationMenuLink`, `NavigationMenuIndicator`, `NavigationMenuViewport`
|
|
1774
|
+
|
|
1775
|
+
Also exports `navigationMenuTriggerStyle` — a CVA function that returns the trigger button classes.
|
|
1776
|
+
|
|
1777
|
+
```vue
|
|
1778
|
+
<script setup>
|
|
1779
|
+
import {
|
|
1780
|
+
NavigationMenu,
|
|
1781
|
+
NavigationMenuList,
|
|
1782
|
+
NavigationMenuItem,
|
|
1783
|
+
NavigationMenuTrigger,
|
|
1784
|
+
NavigationMenuContent,
|
|
1785
|
+
NavigationMenuLink,
|
|
1786
|
+
navigationMenuTriggerStyle,
|
|
1787
|
+
} from '@buillaume.biondo/fab-ui'
|
|
1788
|
+
</script>
|
|
1789
|
+
|
|
1790
|
+
<template>
|
|
1791
|
+
<NavigationMenu>
|
|
1792
|
+
<NavigationMenuList>
|
|
1793
|
+
<NavigationMenuItem>
|
|
1794
|
+
<NavigationMenuTrigger>Products</NavigationMenuTrigger>
|
|
1795
|
+
<NavigationMenuContent>
|
|
1796
|
+
<ul class="grid w-[400px] gap-3 p-4">
|
|
1797
|
+
<li><NavigationMenuLink href="/products/alpha">Alpha</NavigationMenuLink></li>
|
|
1798
|
+
<li><NavigationMenuLink href="/products/beta">Beta</NavigationMenuLink></li>
|
|
1799
|
+
</ul>
|
|
1800
|
+
</NavigationMenuContent>
|
|
1801
|
+
</NavigationMenuItem>
|
|
1802
|
+
<NavigationMenuItem>
|
|
1803
|
+
<NavigationMenuLink :class="navigationMenuTriggerStyle()" href="/about">
|
|
1804
|
+
About
|
|
1805
|
+
</NavigationMenuLink>
|
|
1806
|
+
</NavigationMenuItem>
|
|
1807
|
+
</NavigationMenuList>
|
|
1808
|
+
</NavigationMenu>
|
|
1809
|
+
</template>
|
|
1810
|
+
```
|
|
1811
|
+
|
|
1812
|
+
---
|
|
1813
|
+
|
|
1814
|
+
### Sidebar
|
|
1815
|
+
|
|
1816
|
+
A complete collapsible application sidebar system. It supports three visual variants (`sidebar`, `floating`, `inset`), two collapse modes (`offcanvas`, `icon`), and a full set of composition components for menus, groups, badges, and sub-menus.
|
|
1817
|
+
|
|
1818
|
+
**Exported components**
|
|
1819
|
+
|
|
1820
|
+
`SidebarProvider`, `Sidebar`, `SidebarTrigger`, `SidebarRail`, `SidebarInset`, `SidebarHeader`, `SidebarContent`, `SidebarFooter`, `SidebarSeparator`, `SidebarGroup`, `SidebarGroupLabel`, `SidebarGroupAction`, `SidebarGroupContent`, `SidebarMenu`, `SidebarMenuItem`, `SidebarMenuButton`, `SidebarMenuAction`, `SidebarMenuBadge`, `SidebarMenuSkeleton`, `SidebarMenuSub`, `SidebarMenuSubItem`, `SidebarMenuSubButton`, `SidebarInput`
|
|
1821
|
+
|
|
1822
|
+
Also exports the `useSidebar` composable.
|
|
1823
|
+
|
|
1824
|
+
**`SidebarProvider` / `Sidebar` key props**
|
|
1825
|
+
|
|
1826
|
+
| Prop | Type | Default | Description |
|
|
1827
|
+
|---|---|---|---|
|
|
1828
|
+
| `side` | `'left' \| 'right'` | `'left'` | Sidebar position |
|
|
1829
|
+
| `variant` | `'sidebar' \| 'floating' \| 'inset'` | `'sidebar'` | Visual style |
|
|
1830
|
+
| `collapsible` | `'offcanvas' \| 'icon' \| 'none'` | `'offcanvas'` | Collapse behavior |
|
|
1831
|
+
|
|
1832
|
+
```vue
|
|
1833
|
+
<script setup>
|
|
1834
|
+
import {
|
|
1835
|
+
SidebarProvider,
|
|
1836
|
+
Sidebar,
|
|
1837
|
+
SidebarHeader,
|
|
1838
|
+
SidebarContent,
|
|
1839
|
+
SidebarGroup,
|
|
1840
|
+
SidebarGroupLabel,
|
|
1841
|
+
SidebarGroupContent,
|
|
1842
|
+
SidebarMenu,
|
|
1843
|
+
SidebarMenuItem,
|
|
1844
|
+
SidebarMenuButton,
|
|
1845
|
+
SidebarTrigger,
|
|
1846
|
+
SidebarInset,
|
|
1847
|
+
} from '@buillaume.biondo/fab-ui'
|
|
1848
|
+
import { HomeIcon, SettingsIcon } from 'lucide-vue-next'
|
|
1849
|
+
</script>
|
|
1850
|
+
|
|
1851
|
+
<template>
|
|
1852
|
+
<SidebarProvider>
|
|
1853
|
+
<Sidebar collapsible="icon">
|
|
1854
|
+
<SidebarHeader>
|
|
1855
|
+
<span class="font-semibold">My App</span>
|
|
1856
|
+
</SidebarHeader>
|
|
1857
|
+
<SidebarContent>
|
|
1858
|
+
<SidebarGroup>
|
|
1859
|
+
<SidebarGroupLabel>Navigation</SidebarGroupLabel>
|
|
1860
|
+
<SidebarGroupContent>
|
|
1861
|
+
<SidebarMenu>
|
|
1862
|
+
<SidebarMenuItem>
|
|
1863
|
+
<SidebarMenuButton as-child>
|
|
1864
|
+
<a href="/"><HomeIcon /> Dashboard</a>
|
|
1865
|
+
</SidebarMenuButton>
|
|
1866
|
+
</SidebarMenuItem>
|
|
1867
|
+
<SidebarMenuItem>
|
|
1868
|
+
<SidebarMenuButton as-child>
|
|
1869
|
+
<a href="/settings"><SettingsIcon /> Settings</a>
|
|
1870
|
+
</SidebarMenuButton>
|
|
1871
|
+
</SidebarMenuItem>
|
|
1872
|
+
</SidebarMenu>
|
|
1873
|
+
</SidebarGroupContent>
|
|
1874
|
+
</SidebarGroup>
|
|
1875
|
+
</SidebarContent>
|
|
1876
|
+
</Sidebar>
|
|
1877
|
+
|
|
1878
|
+
<SidebarInset>
|
|
1879
|
+
<header class="flex items-center gap-2 p-4">
|
|
1880
|
+
<SidebarTrigger />
|
|
1881
|
+
<h1>Page title</h1>
|
|
1882
|
+
</header>
|
|
1883
|
+
<main class="p-4">
|
|
1884
|
+
<slot />
|
|
1885
|
+
</main>
|
|
1886
|
+
</SidebarInset>
|
|
1887
|
+
</SidebarProvider>
|
|
1888
|
+
</template>
|
|
1889
|
+
```
|
|
1890
|
+
|
|
1891
|
+
---
|
|
1892
|
+
|
|
1893
|
+
### Tabs
|
|
1894
|
+
|
|
1895
|
+
Accessible tabbed interface built on reka-ui's `TabsRoot` / `TabsList` / `TabsTrigger` / `TabsContent` primitives. The `placement` prop controls whether tabs appear on top, left, or right of the content panel; an animated indicator bar slides to the active tab automatically.
|
|
1896
|
+
|
|
1897
|
+
The component tree is: `Tabs` → `TabsList` → `TabsTrigger` (×n) + `TabsContent` (×n).
|
|
1898
|
+
|
|
1899
|
+
#### Tabs
|
|
1900
|
+
|
|
1901
|
+
Root container. Manages selection state, sets the CSS color variable `--tabs-color`, and provides `placement`, `variant`, and `size` to child components via `provide/inject`.
|
|
1902
|
+
|
|
1903
|
+
**Props**
|
|
1904
|
+
|
|
1905
|
+
Accepts all props from reka-ui's `TabsRootProps` (except `orientation`, derived automatically) plus:
|
|
1906
|
+
|
|
1907
|
+
| Prop | Type | Default | Description |
|
|
1908
|
+
|---|---|---|---|
|
|
1909
|
+
| `modelValue` | `string` | — | Controlled active tab value (`v-model`) |
|
|
1910
|
+
| `defaultValue` | `string` | — | Initial active tab (uncontrolled) |
|
|
1911
|
+
| `placement` | `'top' \| 'left' \| 'right'` | `'top'` | Position of the tab list relative to the panels |
|
|
1912
|
+
| `variant` | `Severity` | `'primary'` | Color of the active indicator and trigger text |
|
|
1913
|
+
| `size` | `'small' \| 'default' \| 'large'` | `'default'` | Size of the trigger buttons |
|
|
1914
|
+
| `activationMode` | `'automatic' \| 'manual'` | `'automatic'` | Whether tabs activate on focus or on click |
|
|
1915
|
+
| `class` | `string` | — | Additional CSS classes on the root element |
|
|
1916
|
+
|
|
1917
|
+
**Emits**
|
|
1918
|
+
|
|
1919
|
+
| Event | Payload | Description |
|
|
1920
|
+
|---|---|---|
|
|
1921
|
+
| `update:modelValue` | `string` | Fired when the active tab changes |
|
|
1922
|
+
|
|
1923
|
+
#### TabsList
|
|
1924
|
+
|
|
1925
|
+
Wrapper for the row or column of `TabsTrigger` buttons. Includes a built-in `TabsIndicator` that slides to the active trigger with a CSS transition.
|
|
1926
|
+
|
|
1927
|
+
**Props**
|
|
1928
|
+
|
|
1929
|
+
Accepts all props from reka-ui's `TabsListProps` plus:
|
|
1930
|
+
|
|
1931
|
+
| Prop | Type | Default | Description |
|
|
1932
|
+
|---|---|---|---|
|
|
1933
|
+
| `loop` | `boolean` | `false` | Keyboard navigation wraps from last to first trigger |
|
|
1934
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
1935
|
+
|
|
1936
|
+
#### TabsTrigger
|
|
1937
|
+
|
|
1938
|
+
Individual tab button. Reads `size` and `placement` from the parent `Tabs` context.
|
|
1939
|
+
|
|
1940
|
+
**Props**
|
|
1941
|
+
|
|
1942
|
+
Accepts all props from reka-ui's `TabsTriggerProps` plus:
|
|
1943
|
+
|
|
1944
|
+
| Prop | Type | Default | Description |
|
|
1945
|
+
|---|---|---|---|
|
|
1946
|
+
| `value` | `string` | **required** | Unique identifier matching a `TabsContent` value |
|
|
1947
|
+
| `disabled` | `boolean` | `false` | Prevents selection and dims the trigger |
|
|
1948
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
1949
|
+
|
|
1950
|
+
#### TabsContent
|
|
1951
|
+
|
|
1952
|
+
Panel revealed when the associated trigger is active. Takes `flex-1` to fill the available space alongside a vertical tab list.
|
|
1953
|
+
|
|
1954
|
+
**Props**
|
|
1955
|
+
|
|
1956
|
+
Accepts all props from reka-ui's `TabsContentProps` plus:
|
|
1957
|
+
|
|
1958
|
+
| Prop | Type | Default | Description |
|
|
1959
|
+
|---|---|---|---|
|
|
1960
|
+
| `value` | `string` | **required** | Must match the corresponding `TabsTrigger` value |
|
|
1961
|
+
| `forceMount` | `boolean` | `false` | Keeps the panel mounted even when inactive (useful for animation libraries) |
|
|
1962
|
+
| `class` | `string` | — | Additional CSS classes |
|
|
1963
|
+
|
|
1964
|
+
```vue
|
|
1965
|
+
<script setup>
|
|
1966
|
+
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@buillaume.biondo/fab-ui'
|
|
1967
|
+
import { ref } from 'vue'
|
|
1968
|
+
|
|
1969
|
+
const active = ref('account')
|
|
1970
|
+
</script>
|
|
1971
|
+
|
|
1972
|
+
<template>
|
|
1973
|
+
<!-- Top (default) -->
|
|
1974
|
+
<Tabs v-model="active" placement="top">
|
|
1975
|
+
<TabsList>
|
|
1976
|
+
<TabsTrigger value="account">Account</TabsTrigger>
|
|
1977
|
+
<TabsTrigger value="security">Security</TabsTrigger>
|
|
1978
|
+
<TabsTrigger value="billing">Billing</TabsTrigger>
|
|
1979
|
+
<TabsTrigger value="disabled" disabled>Disabled</TabsTrigger>
|
|
1980
|
+
</TabsList>
|
|
1981
|
+
<TabsContent value="account" class="p-4">Account settings…</TabsContent>
|
|
1982
|
+
<TabsContent value="security" class="p-4">Security settings…</TabsContent>
|
|
1983
|
+
<TabsContent value="billing" class="p-4">Billing settings…</TabsContent>
|
|
1984
|
+
</Tabs>
|
|
1985
|
+
|
|
1986
|
+
<!-- Left placement -->
|
|
1987
|
+
<Tabs v-model="active" placement="left" variant="success">
|
|
1988
|
+
<TabsList>
|
|
1989
|
+
<TabsTrigger value="profile">Profile</TabsTrigger>
|
|
1990
|
+
<TabsTrigger value="team">Team</TabsTrigger>
|
|
1991
|
+
</TabsList>
|
|
1992
|
+
<TabsContent value="profile" class="p-6">Profile panel…</TabsContent>
|
|
1993
|
+
<TabsContent value="team" class="p-6">Team panel…</TabsContent>
|
|
1994
|
+
</Tabs>
|
|
1995
|
+
|
|
1996
|
+
<!-- Right placement, large size, danger color -->
|
|
1997
|
+
<Tabs v-model="active" placement="right" variant="danger" size="large">
|
|
1998
|
+
<TabsList>
|
|
1999
|
+
<TabsTrigger value="logs">Logs</TabsTrigger>
|
|
2000
|
+
<TabsTrigger value="alerts">Alerts</TabsTrigger>
|
|
2001
|
+
</TabsList>
|
|
2002
|
+
<TabsContent value="logs" class="p-6">Logs panel…</TabsContent>
|
|
2003
|
+
<TabsContent value="alerts" class="p-6">Alerts panel…</TabsContent>
|
|
2004
|
+
</Tabs>
|
|
2005
|
+
|
|
2006
|
+
<!-- Uncontrolled with defaultValue -->
|
|
2007
|
+
<Tabs default-value="tab1">
|
|
2008
|
+
<TabsList>
|
|
2009
|
+
<TabsTrigger value="tab1">Tab 1</TabsTrigger>
|
|
2010
|
+
<TabsTrigger value="tab2">Tab 2</TabsTrigger>
|
|
2011
|
+
</TabsList>
|
|
2012
|
+
<TabsContent value="tab1" class="p-4">Content 1</TabsContent>
|
|
2013
|
+
<TabsContent value="tab2" class="p-4">Content 2</TabsContent>
|
|
2014
|
+
</Tabs>
|
|
2015
|
+
</template>
|
|
2016
|
+
```
|
|
2017
|
+
|
|
2018
|
+
---
|
|
2019
|
+
|
|
2020
|
+
## Composables
|
|
2021
|
+
|
|
2022
|
+
### useToast
|
|
2023
|
+
|
|
2024
|
+
Global toast notification state. The state is shared at the module level — calling `useToast()` anywhere returns the same reactive instance.
|
|
2025
|
+
|
|
2026
|
+
```ts
|
|
2027
|
+
import { useToast } from '@buillaume.biondo/fab-ui'
|
|
2028
|
+
|
|
2029
|
+
const toast = useToast()
|
|
2030
|
+
```
|
|
2031
|
+
|
|
2032
|
+
**Returned methods**
|
|
2033
|
+
|
|
2034
|
+
| Method | Signature | Description |
|
|
2035
|
+
|---|---|---|
|
|
2036
|
+
| `success` | `(message: string, options?: ToastOptions) => string` | Shows a success toast (auto-dismisses after 4s) |
|
|
2037
|
+
| `info` | `(message: string, options?: ToastOptions) => string` | Shows an info toast (auto-dismisses after 4s) |
|
|
2038
|
+
| `warning` | `(message: string, options?: ToastOptions) => string` | Shows a warning toast (auto-dismisses after 6s) |
|
|
2039
|
+
| `error` | `(message: string, options?: ToastOptions) => string` | Shows a persistent error toast |
|
|
2040
|
+
| `dismiss` | `(id: string) => void` | Programmatically removes a toast by its ID |
|
|
2041
|
+
| `toasts` | `Toast[]` (reactive) | The current list of active toasts |
|
|
2042
|
+
|
|
2043
|
+
**`ToastOptions`**
|
|
2044
|
+
|
|
2045
|
+
```ts
|
|
2046
|
+
interface ToastOptions {
|
|
2047
|
+
duration?: number // Override auto-dismiss duration in ms
|
|
2048
|
+
persistent?: boolean // Prevent auto-dismiss
|
|
2049
|
+
}
|
|
2050
|
+
```
|
|
2051
|
+
|
|
2052
|
+
```ts
|
|
2053
|
+
const toast = useToast()
|
|
2054
|
+
|
|
2055
|
+
// Basic usage
|
|
2056
|
+
toast.success('Your profile has been updated.')
|
|
2057
|
+
toast.error('Failed to connect to the server.')
|
|
2058
|
+
|
|
2059
|
+
// Custom duration
|
|
2060
|
+
toast.warning('Session expiring soon.', { duration: 10_000 })
|
|
2061
|
+
|
|
2062
|
+
// Persistent toast with manual dismiss
|
|
2063
|
+
const id = toast.info('Processing your request…', { persistent: true })
|
|
2064
|
+
await doSomething()
|
|
2065
|
+
toast.dismiss(id)
|
|
2066
|
+
```
|
|
2067
|
+
|
|
2068
|
+
---
|
|
2069
|
+
|
|
2070
|
+
### useAppearance
|
|
2071
|
+
|
|
2072
|
+
Manages the application's visual theme (light / dark / system) and border radius mode (default / square). Persists preferences to `localStorage` and a cookie for SSR compatibility.
|
|
2073
|
+
|
|
2074
|
+
```ts
|
|
2075
|
+
import { useAppearance } from '@buillaume.biondo/fab-ui'
|
|
2076
|
+
|
|
2077
|
+
const {
|
|
2078
|
+
appearance,
|
|
2079
|
+
resolvedAppearance,
|
|
2080
|
+
updateAppearance,
|
|
2081
|
+
radiusMode,
|
|
2082
|
+
updateRadiusMode,
|
|
2083
|
+
} = useAppearance()
|
|
2084
|
+
```
|
|
2085
|
+
|
|
2086
|
+
**Returned values**
|
|
2087
|
+
|
|
2088
|
+
| Property | Type | Description |
|
|
2089
|
+
|---|---|---|
|
|
2090
|
+
| `appearance` | `Ref<'light' \| 'dark' \| 'system'>` | Current preference |
|
|
2091
|
+
| `resolvedAppearance` | `ComputedRef<'light' \| 'dark'>` | Resolved value (resolves `'system'` against `prefers-color-scheme`) |
|
|
2092
|
+
| `updateAppearance` | `(value: Appearance) => void` | Updates and persists the theme |
|
|
2093
|
+
| `radiusMode` | `Ref<'default' \| 'square'>` | Current border radius mode |
|
|
2094
|
+
| `updateRadiusMode` | `(value: RadiusMode) => void` | Updates and persists the radius mode |
|
|
2095
|
+
|
|
2096
|
+
Also exports `initializeTheme()` — call it once in your app entry point (before mounting) to apply the persisted theme immediately and avoid a flash of unstyled content.
|
|
2097
|
+
|
|
2098
|
+
```ts
|
|
2099
|
+
// main.ts
|
|
2100
|
+
import { createApp } from 'vue'
|
|
2101
|
+
import { initializeTheme } from '@buillaume.biondo/fab-ui'
|
|
2102
|
+
import App from './App.vue'
|
|
2103
|
+
|
|
2104
|
+
initializeTheme()
|
|
2105
|
+
createApp(App).mount('#app')
|
|
2106
|
+
```
|
|
2107
|
+
|
|
2108
|
+
```vue
|
|
2109
|
+
<script setup>
|
|
2110
|
+
import { useAppearance } from '@buillaume.biondo/fab-ui'
|
|
2111
|
+
|
|
2112
|
+
const { appearance, updateAppearance, radiusMode, updateRadiusMode } = useAppearance()
|
|
2113
|
+
</script>
|
|
2114
|
+
|
|
2115
|
+
<template>
|
|
2116
|
+
<select :value="appearance" @change="updateAppearance($event.target.value)">
|
|
2117
|
+
<option value="light">Light</option>
|
|
2118
|
+
<option value="dark">Dark</option>
|
|
2119
|
+
<option value="system">System</option>
|
|
2120
|
+
</select>
|
|
2121
|
+
|
|
2122
|
+
<label>
|
|
2123
|
+
<input
|
|
2124
|
+
type="checkbox"
|
|
2125
|
+
:checked="radiusMode === 'square'"
|
|
2126
|
+
@change="updateRadiusMode(radiusMode === 'square' ? 'default' : 'square')"
|
|
2127
|
+
/>
|
|
2128
|
+
Square corners
|
|
2129
|
+
</label>
|
|
2130
|
+
</template>
|
|
2131
|
+
```
|
|
2132
|
+
|
|
2133
|
+
---
|
|
2134
|
+
|
|
2135
|
+
## Roadmap
|
|
2136
|
+
|
|
2137
|
+
The following components are planned for upcoming releases:
|
|
2138
|
+
|
|
2139
|
+
- **Radio** — Styled radio buttons with severity/variant support and a radio group wrapper
|
|
2140
|
+
- **Divider** — Horizontal/vertical separator with an optional centered label
|
|
2141
|
+
- **Tabs** — Tab navigation with `Tab`, `TabList`, and `TabPanel` subcomponents and multiple visual variants
|
|
2142
|
+
|
|
2143
|
+
Contributions are welcome. Feel free to open an issue to discuss a feature or submit a pull request.
|
|
2144
|
+
|
|
2145
|
+
---
|
|
2146
|
+
|
|
2147
|
+
## License
|
|
2148
|
+
|
|
2149
|
+
[MIT](./LICENSE) — Guillaume Biondo
|