@florianke/components 0.0.2 → 0.0.6
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 +467 -31
- package/dist/alert-dialog.d.mts +13 -0
- package/dist/alert-dialog.d.mts.map +1 -0
- package/dist/alert-dialog.mjs +13 -0
- package/dist/alert-dialog.mjs.map +1 -0
- package/dist/avatar.mjs +2 -2
- package/dist/button.d.mts +1 -1
- package/dist/button.d.mts.map +1 -1
- package/dist/button.mjs +4 -3
- package/dist/button.mjs.map +1 -1
- package/dist/card.mjs +1 -1
- package/dist/components/alert-dialog/alert-dialog.d.mts +35 -0
- package/dist/components/alert-dialog/alert-dialog.d.mts.map +1 -0
- package/dist/components/alert-dialog/alert-dialog.mjs +50 -0
- package/dist/components/alert-dialog/alert-dialog.mjs.map +1 -0
- package/dist/components/select/select.d.mts +42 -0
- package/dist/components/select/select.d.mts.map +1 -0
- package/dist/components/select/select.mjs +102 -0
- package/dist/components/select/select.mjs.map +1 -0
- package/dist/components/toast/toast.d.mts +45 -0
- package/dist/components/toast/toast.d.mts.map +1 -0
- package/dist/components/toast/toast.mjs +156 -0
- package/dist/components/toast/toast.mjs.map +1 -0
- package/dist/components/tooltip/tooltip.d.mts +30 -0
- package/dist/components/tooltip/tooltip.d.mts.map +1 -0
- package/dist/components/tooltip/tooltip.mjs +40 -0
- package/dist/components/tooltip/tooltip.mjs.map +1 -0
- package/dist/dropdown-menu.mjs +1 -1
- package/dist/field.d.mts +11 -0
- package/dist/field.d.mts.map +1 -0
- package/dist/field.mjs +14 -0
- package/dist/field.mjs.map +1 -0
- package/dist/heading.d.mts +17 -0
- package/dist/heading.d.mts.map +1 -0
- package/dist/heading.mjs +20 -0
- package/dist/heading.mjs.map +1 -0
- package/dist/hint.d.mts +17 -0
- package/dist/hint.d.mts.map +1 -0
- package/dist/hint.mjs +22 -0
- package/dist/hint.mjs.map +1 -0
- package/dist/hooks/use-confirm.d.mts +23 -0
- package/dist/hooks/use-confirm.d.mts.map +1 -0
- package/dist/hooks/use-confirm.mjs +97 -0
- package/dist/hooks/use-confirm.mjs.map +1 -0
- package/dist/index.d.mts +11 -1
- package/dist/index.mjs +12 -2
- package/dist/input.d.mts +1 -0
- package/dist/input.d.mts.map +1 -1
- package/dist/input.mjs +74 -7
- package/dist/input.mjs.map +1 -1
- package/dist/label.d.mts +20 -0
- package/dist/label.d.mts.map +1 -0
- package/dist/label.mjs +19 -0
- package/dist/label.mjs.map +1 -0
- package/dist/{cn-BpvCVwZv.mjs → lib/cn.mjs} +2 -2
- package/dist/lib/cn.mjs.map +1 -0
- package/dist/providers.d.mts +12 -0
- package/dist/providers.d.mts.map +1 -0
- package/dist/providers.mjs +14 -0
- package/dist/providers.mjs.map +1 -0
- package/dist/select.d.mts +2 -38
- package/dist/select.d.mts.map +1 -1
- package/dist/select.mjs +2 -98
- package/dist/select.mjs.map +1 -1
- package/dist/text.d.mts +30 -0
- package/dist/text.d.mts.map +1 -0
- package/dist/text.mjs +37 -0
- package/dist/text.mjs.map +1 -0
- package/dist/toast.d.mts +18 -0
- package/dist/toast.d.mts.map +1 -0
- package/dist/toast.mjs +17 -0
- package/dist/toast.mjs.map +1 -0
- package/dist/tooltip.d.mts +11 -0
- package/dist/tooltip.d.mts.map +1 -0
- package/dist/tooltip.mjs +11 -0
- package/dist/tooltip.mjs.map +1 -0
- package/package.json +41 -1
- package/src/styles.css +13 -1
- package/dist/cn-BpvCVwZv.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ A small, opinionated React component library built on top of [Base UI](https://b
|
|
|
5
5
|
- **Headless-first** — behavior, accessibility, and keyboard interaction are handled by Base UI; this library only adds opinionated styling and a few ergonomic defaults.
|
|
6
6
|
- **Themeable** — all colors are CSS variables (`--background`, `--foreground`, `--ring`, ...), so you can restyle the whole library by overriding a handful of custom properties.
|
|
7
7
|
- **Tree-shakeable** — every component ships as its own entry point, so bundlers only include what you actually import.
|
|
8
|
-
- **Client-ready** — every interactive component is already marked with `"use client"`, so it works out of the box inside a Next.js App Router Server Component tree.
|
|
8
|
+
- **Client-ready** — every interactive component is already marked with `"use client"`, so it works out of the box inside a Next.js App Router Server Component tree — including dot-notation access like `<Select.Trigger>` directly from a Server Component page (no `"use client"` needed in your own file just to reference it).
|
|
9
9
|
|
|
10
10
|
## Table of Contents
|
|
11
11
|
|
|
@@ -14,14 +14,24 @@ A small, opinionated React component library built on top of [Base UI](https://b
|
|
|
14
14
|
- [Setup](#setup)
|
|
15
15
|
- [Quick Start](#quick-start)
|
|
16
16
|
- [Theming](#theming)
|
|
17
|
+
- [Providers](#providers)
|
|
17
18
|
- [Components](#components)
|
|
19
|
+
- [AlertDialog](#alertdialog)
|
|
18
20
|
- [Avatar](#avatar)
|
|
19
21
|
- [Button](#button)
|
|
20
22
|
- [Card](#card)
|
|
21
23
|
- [DropdownMenu](#dropdownmenu)
|
|
24
|
+
- [Field](#field)
|
|
25
|
+
- [Heading](#heading)
|
|
26
|
+
- [Hint](#hint)
|
|
22
27
|
- [Input](#input)
|
|
28
|
+
- [Label](#label)
|
|
23
29
|
- [Select](#select)
|
|
30
|
+
- [Text](#text)
|
|
31
|
+
- [Toast](#toast)
|
|
32
|
+
- [Tooltip](#tooltip)
|
|
24
33
|
- [Hooks](#hooks)
|
|
34
|
+
- [useConfirm](#useconfirm)
|
|
25
35
|
- [useInitials](#useinitials)
|
|
26
36
|
- [Package Exports](#package-exports)
|
|
27
37
|
- [License](#license)
|
|
@@ -81,11 +91,27 @@ Dark mode is automatic via `prefers-color-scheme`, and can be forced by toggling
|
|
|
81
91
|
<html className="dark">
|
|
82
92
|
```
|
|
83
93
|
|
|
84
|
-
|
|
94
|
+
### 4. Wrap your app in `Providers`
|
|
95
|
+
|
|
96
|
+
`Toast`, `Tooltip`, and `useConfirm` all need a bit of context set up somewhere above where you use them. Wrap your root layout once with [`Providers`](#providers) and you're done.
|
|
85
97
|
|
|
86
98
|
```tsx
|
|
87
|
-
|
|
99
|
+
import { Providers } from "@florianke/components";
|
|
100
|
+
|
|
101
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
102
|
+
return (
|
|
103
|
+
<html>
|
|
104
|
+
<body>
|
|
105
|
+
<Providers>{children}</Providers>
|
|
106
|
+
</body>
|
|
107
|
+
</html>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Quick Start
|
|
88
113
|
|
|
114
|
+
```tsx
|
|
89
115
|
import { Avatar, Button, Card, Input } from "@florianke/components";
|
|
90
116
|
|
|
91
117
|
export default function Example() {
|
|
@@ -108,17 +134,21 @@ export default function Example() {
|
|
|
108
134
|
|
|
109
135
|
Every component reads its colors from CSS custom properties, defined once in `styles.css` and re-defined inside `.dark`:
|
|
110
136
|
|
|
111
|
-
| Token
|
|
112
|
-
|
|
|
113
|
-
| `--background`
|
|
114
|
-
| `--foreground`
|
|
115
|
-
| `--card` / `--card-foreground`
|
|
116
|
-
| `--popover` / `--popover-foreground`
|
|
117
|
-
| `--border`
|
|
118
|
-
| `--input` / `--input-border`
|
|
119
|
-
| `--muted` / `--muted-foreground`
|
|
120
|
-
| `--accent` / `--accent-foreground`
|
|
121
|
-
| `--ring`
|
|
137
|
+
| Token | Used for |
|
|
138
|
+
| -------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
139
|
+
| `--background` | Page background |
|
|
140
|
+
| `--foreground` | Primary text |
|
|
141
|
+
| `--card` / `--card-foreground` | `Card` surface and its text |
|
|
142
|
+
| `--popover` / `--popover-foreground` | Floating surfaces (`DropdownMenu`, `Select`, `Toast`, `Tooltip`, `AlertDialog`) |
|
|
143
|
+
| `--border` | Hairline borders and dividers |
|
|
144
|
+
| `--input` / `--input-border` | Form control backgrounds and borders |
|
|
145
|
+
| `--muted` / `--muted-foreground` | Recessed surfaces and secondary text |
|
|
146
|
+
| `--accent` / `--accent-foreground` | Hover/highlighted state on menu and select items |
|
|
147
|
+
| `--ring` | Focus rings |
|
|
148
|
+
| `--success` | Success state (`Toast` type `"success"`) |
|
|
149
|
+
| `--warning` | Warning state (`Toast` type `"warning"`) |
|
|
150
|
+
| `--destructive` | Error/destructive state (`Toast` type `"error"`, `Button` variant `"destructive"`, invalid `Input`, `Hint` variant `"error"`) |
|
|
151
|
+
| `--info` | Info state (`Toast` type `"info"`) |
|
|
122
152
|
|
|
123
153
|
Override any of these in your own CSS (after importing the package's stylesheet) to reskin the whole library:
|
|
124
154
|
|
|
@@ -128,8 +158,89 @@ Override any of these in your own CSS (after importing the package's stylesheet)
|
|
|
128
158
|
}
|
|
129
159
|
```
|
|
130
160
|
|
|
161
|
+
## Providers
|
|
162
|
+
|
|
163
|
+
A single wrapper component that bundles everything the library needs context for: toast notifications, tooltip delay grouping, and the [`useConfirm`](#useconfirm) dialog. Add it once, near the root of your app, and every `Toast`, `Tooltip`, and `useConfirm()` call anywhere below it will just work — no further setup required.
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
import { Providers } from "@florianke/components";
|
|
167
|
+
|
|
168
|
+
<Providers>{children}</Providers>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Internally, it's equivalent to:
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
<Toast.Provider>
|
|
175
|
+
<Tooltip.Provider>
|
|
176
|
+
<ConfirmProvider>
|
|
177
|
+
{children}
|
|
178
|
+
<Toast.Viewport>
|
|
179
|
+
<Toast.List />
|
|
180
|
+
</Toast.Viewport>
|
|
181
|
+
</ConfirmProvider>
|
|
182
|
+
</Tooltip.Provider>
|
|
183
|
+
</Toast.Provider>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
If you need to configure something the bundled version doesn't expose (e.g. a custom tooltip delay), compose the pieces yourself instead of using `Providers` — see [Toast](#toast), [Tooltip](#tooltip), and [useConfirm](#useconfirm).
|
|
187
|
+
|
|
188
|
+
| Prop | Type | Default | Description |
|
|
189
|
+
| ---------- | ------------------- | ------- | -------------- |
|
|
190
|
+
| `children` | `React.ReactNode` | — | Your app. |
|
|
191
|
+
|
|
131
192
|
## Components
|
|
132
193
|
|
|
194
|
+
### AlertDialog
|
|
195
|
+
|
|
196
|
+
A modal confirmation dialog built on Base UI's `AlertDialog`.
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
import { AlertDialog, Button } from "@florianke/components";
|
|
200
|
+
|
|
201
|
+
<AlertDialog>
|
|
202
|
+
<AlertDialog.Trigger render={<Button variant="destructive" size="sm" />}>
|
|
203
|
+
Discard draft
|
|
204
|
+
</AlertDialog.Trigger>
|
|
205
|
+
<AlertDialog.Content>
|
|
206
|
+
<div className="flex flex-col gap-1">
|
|
207
|
+
<AlertDialog.Title>Discard draft?</AlertDialog.Title>
|
|
208
|
+
<AlertDialog.Description>
|
|
209
|
+
You can’t undo this action.
|
|
210
|
+
</AlertDialog.Description>
|
|
211
|
+
</div>
|
|
212
|
+
<div className="flex justify-end gap-2">
|
|
213
|
+
<AlertDialog.Close>Cancel</AlertDialog.Close>
|
|
214
|
+
<AlertDialog.Close render={<Button variant="destructive" />}>
|
|
215
|
+
Discard
|
|
216
|
+
</AlertDialog.Close>
|
|
217
|
+
</div>
|
|
218
|
+
</AlertDialog.Content>
|
|
219
|
+
</AlertDialog>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
For the common "confirm before doing something destructive" flow, prefer the imperative [`useConfirm`](#useconfirm) hook instead of building the dialog by hand — it already includes this exact structure, plus an optional type-to-confirm verification step.
|
|
223
|
+
|
|
224
|
+
#### `AlertDialog` (root)
|
|
225
|
+
|
|
226
|
+
Forwards all props to Base UI's `AlertDialog.Root` — e.g. `open`, `defaultOpen`, `onOpenChange`.
|
|
227
|
+
|
|
228
|
+
#### `AlertDialog.Trigger`
|
|
229
|
+
|
|
230
|
+
Forwards all props to Base UI's `AlertDialog.Trigger` — most commonly `render` (to swap the rendered element/component, e.g. our own `Button`).
|
|
231
|
+
|
|
232
|
+
#### `AlertDialog.Content`
|
|
233
|
+
|
|
234
|
+
Renders the backdrop, positions the popup at the center of the screen, and handles the open/close transition. Accepts standard `<div>` props plus everything Base UI's `AlertDialog.Popup` accepts.
|
|
235
|
+
|
|
236
|
+
#### `AlertDialog.Title` / `AlertDialog.Description`
|
|
237
|
+
|
|
238
|
+
Forward all props to Base UI's `AlertDialog.Title` / `AlertDialog.Description` (which wire up the `aria-labelledby`/`aria-describedby` linking automatically).
|
|
239
|
+
|
|
240
|
+
#### `AlertDialog.Close`
|
|
241
|
+
|
|
242
|
+
Forwards all props to Base UI's `AlertDialog.Close`. Defaults to rendering as our own `Button` with `variant="outline"` — pass `render={<Button variant="destructive" />}` for the confirming action.
|
|
243
|
+
|
|
133
244
|
### Avatar
|
|
134
245
|
|
|
135
246
|
Renders an image, and automatically falls back to the person's initials — shown immediately, with the image swapping in as soon as it finishes loading (no flash, no artificial delay).
|
|
@@ -143,8 +254,8 @@ import { Avatar } from "@florianke/components";
|
|
|
143
254
|
```
|
|
144
255
|
|
|
145
256
|
| Prop | Type | Default | Description |
|
|
146
|
-
| ----------- |
|
|
147
|
-
| `name` | `string` |
|
|
257
|
+
| ----------- | ---------------------------------- | ----------- | ---------------------------------------------------------------------------- |
|
|
258
|
+
| `name` | `string` | — (required) | Full name. Used for the `alt` text and to derive the fallback initials via [`useInitials`](#useinitials). |
|
|
148
259
|
| `src` | `string` | `undefined` | Image URL. When omitted, the initials fallback is shown. |
|
|
149
260
|
| `variant` | `"rounded" \| "squared"` | `"rounded"` | Shape of the avatar. |
|
|
150
261
|
| `size` | `"small" \| "base" \| "large"` | `"base"` | Size of the avatar. |
|
|
@@ -162,6 +273,7 @@ import { Button } from "@florianke/components";
|
|
|
162
273
|
<Button variant="outline">Outline</Button>
|
|
163
274
|
<Button variant="ghost">Ghost</Button>
|
|
164
275
|
<Button variant="link">Link</Button>
|
|
276
|
+
<Button variant="destructive">Delete</Button>
|
|
165
277
|
|
|
166
278
|
<Button size="sm">Small</Button>
|
|
167
279
|
<Button size="md">Medium</Button>
|
|
@@ -175,12 +287,12 @@ import { Button } from "@florianke/components";
|
|
|
175
287
|
</Button>
|
|
176
288
|
```
|
|
177
289
|
|
|
178
|
-
| Prop | Type
|
|
179
|
-
| ----------- |
|
|
180
|
-
| `variant` | `"primary" \| "secondary" \| "outline" \| "ghost" \| "link"`
|
|
181
|
-
| `size` | `"sm" \| "md"`
|
|
182
|
-
| `disabled` | `boolean`
|
|
183
|
-
| `className` | `string`
|
|
290
|
+
| Prop | Type | Default | Description |
|
|
291
|
+
| ----------- | --------------------------------------------------------------------------------------- | ----------- | ---------------------------------------------------------- |
|
|
292
|
+
| `variant` | `"primary" \| "secondary" \| "outline" \| "ghost" \| "link" \| "destructive"` | `"primary"` | Visual style. Use `"destructive"` for irreversible actions (delete, discard). |
|
|
293
|
+
| `size` | `"sm" \| "md"` | `"md"` | Height/padding/type scale. Ignored when `variant="link"`. |
|
|
294
|
+
| `disabled` | `boolean` | `false` | Disables the button (via the native `disabled` attribute). |
|
|
295
|
+
| `className` | `string` | `undefined` | Extra classes, merged with the defaults. |
|
|
184
296
|
|
|
185
297
|
Also accepts every other native `<button>` prop (`onClick`, `type`, `ref`, ...), since it's built on Base UI's `Button`.
|
|
186
298
|
|
|
@@ -246,6 +358,70 @@ Forwards all props to Base UI's `Menu.Trigger` — most commonly `render` (to sw
|
|
|
246
358
|
|
|
247
359
|
Forwards all props to Base UI's `Menu.Item` — most commonly `disabled` and `onClick`.
|
|
248
360
|
|
|
361
|
+
### Field
|
|
362
|
+
|
|
363
|
+
A layout primitive for building form fields: just a `<div>` with `flex flex-col gap-y-1.5`. Compose it with [`Label`](#label), [`Input`](#input), and [`Hint`](#hint).
|
|
364
|
+
|
|
365
|
+
```tsx
|
|
366
|
+
import { Field, Hint, Input, Label } from "@florianke/components";
|
|
367
|
+
|
|
368
|
+
<Field className="w-64">
|
|
369
|
+
<Label htmlFor="email">Email</Label>
|
|
370
|
+
<Input id="email" placeholder="you@example.com" />
|
|
371
|
+
<Hint>We’ll never share your email.</Hint>
|
|
372
|
+
</Field>
|
|
373
|
+
|
|
374
|
+
{/* Error state */}
|
|
375
|
+
<Field className="w-64">
|
|
376
|
+
<Label htmlFor="email">Email</Label>
|
|
377
|
+
<Input id="email" aria-invalid="true" defaultValue="not-an-email" />
|
|
378
|
+
<Hint variant="error">Please enter a valid email address.</Hint>
|
|
379
|
+
</Field>
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
| Prop | Type | Default | Description |
|
|
383
|
+
| ----------- | ----------- | ----------- | --------------------------------------------- |
|
|
384
|
+
| `className` | `string` | `undefined` | Extra classes, merged with the defaults. |
|
|
385
|
+
|
|
386
|
+
Accepts every other standard `<div>` prop.
|
|
387
|
+
|
|
388
|
+
### Heading
|
|
389
|
+
|
|
390
|
+
A page/section heading with three preset sizes. Renders the actual matching HTML tag (`<h1>`, `<h2>`, or `<h3>`) for correct document outline/accessibility.
|
|
391
|
+
|
|
392
|
+
```tsx
|
|
393
|
+
import { Heading } from "@florianke/components";
|
|
394
|
+
|
|
395
|
+
<Heading level="h1">Page title</Heading>
|
|
396
|
+
<Heading level="h2">Section title</Heading>
|
|
397
|
+
<Heading level="h3">Subsection title</Heading>
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
| Prop | Type | Default | Description |
|
|
401
|
+
| ----------- | ------------------------- | ------- | --------------------------------------------- |
|
|
402
|
+
| `level` | `"h1" \| "h2" \| "h3"` | `"h1"` | Determines both the rendered tag and the type scale. |
|
|
403
|
+
| `className` | `string` | `undefined` | Extra classes, merged with the defaults. |
|
|
404
|
+
|
|
405
|
+
Accepts every other standard heading (`<h1>`/`<h2>`/`<h3>`) prop.
|
|
406
|
+
|
|
407
|
+
### Hint
|
|
408
|
+
|
|
409
|
+
Small helper/status text for form fields — e.g. under an [`Input`](#input) inside a [`Field`](#field). The `"error"` variant only changes the text color to `--destructive`; it doesn't add an icon or change the layout.
|
|
410
|
+
|
|
411
|
+
```tsx
|
|
412
|
+
import { Hint } from "@florianke/components";
|
|
413
|
+
|
|
414
|
+
<Hint>Must be at least 8 characters long.</Hint>
|
|
415
|
+
<Hint variant="error">Password must be at least 8 characters long.</Hint>
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
| Prop | Type | Default | Description |
|
|
419
|
+
| ----------- | ----------------------- | -------- | --------------------------------------------- |
|
|
420
|
+
| `variant` | `"info" \| "error"` | `"info"` | `"error"` renders the text in `--destructive`. |
|
|
421
|
+
| `className` | `string` | `undefined` | Extra classes, merged with the defaults. |
|
|
422
|
+
|
|
423
|
+
Accepts every other standard `<span>` prop.
|
|
424
|
+
|
|
249
425
|
### Input
|
|
250
426
|
|
|
251
427
|
```tsx
|
|
@@ -255,16 +431,47 @@ import { Input } from "@florianke/components";
|
|
|
255
431
|
<Input size="sm" placeholder="Small" />
|
|
256
432
|
<Input disabled placeholder="Can't edit this" />
|
|
257
433
|
<Input defaultValue="1920" />
|
|
434
|
+
|
|
435
|
+
{/* Invalid state — red border + ring, works with any input */}
|
|
436
|
+
<Input aria-invalid="true" defaultValue="not-an-email" />
|
|
437
|
+
|
|
438
|
+
{/* Password: renders a show/hide toggle button automatically */}
|
|
439
|
+
<Input type="password" defaultValue="hunter2" />
|
|
440
|
+
<Input type="password" aria-invalid="true" defaultValue="short" />
|
|
258
441
|
```
|
|
259
442
|
|
|
260
|
-
| Prop
|
|
261
|
-
|
|
|
262
|
-
| `size`
|
|
263
|
-
| `disabled`
|
|
264
|
-
| `
|
|
443
|
+
| Prop | Type | Default | Description |
|
|
444
|
+
| ------------- | ------------------- | ------- | --------------------------------------------- |
|
|
445
|
+
| `size` | `"sm" \| "md"` | `"md"` | Height/padding/type scale. |
|
|
446
|
+
| `disabled` | `boolean` | `false` | Disables the input. |
|
|
447
|
+
| `type` | `string` | `"text"` | Standard HTML input type. `"password"` gets special treatment (see below). |
|
|
448
|
+
| `aria-invalid` | `boolean \| "true" \| "false"` | `undefined` | When truthy, the border and focus ring turn `--destructive` red. |
|
|
449
|
+
| `className` | `string` | `undefined` | Extra classes, merged with the defaults. |
|
|
265
450
|
|
|
266
451
|
Also accepts every other native `<input>` prop (`value`, `onChange`, `placeholder`, `ref`, ...), except `size` which is overridden by the prop above.
|
|
267
452
|
|
|
453
|
+
When `type="password"`, `Input` renders a bordered group with the text field on the left and a show/hide toggle button (eye icon) on the right, instead of a plain `<input type="password">`. All other props (`aria-invalid`, `disabled`, `value`, `onChange`, ...) still apply to the underlying field as usual.
|
|
454
|
+
|
|
455
|
+
### Label
|
|
456
|
+
|
|
457
|
+
A form field label. Built on top of [`Text`](#text) (`as="label"`), defaulting to a slightly bolder weight than body text.
|
|
458
|
+
|
|
459
|
+
```tsx
|
|
460
|
+
import { Label } from "@florianke/components";
|
|
461
|
+
|
|
462
|
+
<Label htmlFor="name">Name</Label>
|
|
463
|
+
<Label size="small" htmlFor="name">Name</Label>
|
|
464
|
+
<Label weight="regular" htmlFor="name">Name</Label>
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
| Prop | Type | Default | Description |
|
|
468
|
+
| ----------- | ------------------------------- | -------- | ---------------------------- |
|
|
469
|
+
| `size` | `"small" \| "base" \| "large"` | `"base"` | Type scale. |
|
|
470
|
+
| `weight` | `"regular" \| "plus"` | `"plus"` | Font weight. |
|
|
471
|
+
| `className` | `string` | `undefined` | Extra classes, merged with the defaults. |
|
|
472
|
+
|
|
473
|
+
Accepts every other standard `<label>` prop (`htmlFor`, `ref`, ...).
|
|
474
|
+
|
|
268
475
|
### Select
|
|
269
476
|
|
|
270
477
|
A native-select replacement built on Base UI's `Select`, styled to always drop down below the trigger (never flips above it) and to show the selected item's **label** in the trigger — not its raw `value`.
|
|
@@ -335,7 +542,7 @@ Also accepts every other Base UI `Select.Trigger` prop (`disabled`, `ref`, ...).
|
|
|
335
542
|
|
|
336
543
|
| Prop | Type | Default | Description |
|
|
337
544
|
| ----------- | ------------ | ------------ | --------------------------------------- |
|
|
338
|
-
| `value` | `any` |
|
|
545
|
+
| `value` | `any` | — (required) | The value submitted/selected. |
|
|
339
546
|
| `disabled` | `boolean` | `false` | Disables this option. |
|
|
340
547
|
|
|
341
548
|
`children` is used both as the visible label and (automatically) as the text shown in the trigger once selected.
|
|
@@ -350,8 +557,208 @@ A thin horizontal divider between groups of items. No special props beyond stand
|
|
|
350
557
|
<Select.Item value="orange">Orange</Select.Item>
|
|
351
558
|
```
|
|
352
559
|
|
|
560
|
+
### Text
|
|
561
|
+
|
|
562
|
+
The base typography primitive for body copy — small/base/large sizes, two weights, two font families, and two line-height densities. [`Label`](#label) and [`Hint`](#hint) are both built on top of it.
|
|
563
|
+
|
|
564
|
+
```tsx
|
|
565
|
+
import { Text } from "@florianke/components";
|
|
566
|
+
|
|
567
|
+
<Text>Base text</Text>
|
|
568
|
+
<Text size="small">Small text</Text>
|
|
569
|
+
<Text size="large">Large text</Text>
|
|
570
|
+
|
|
571
|
+
<Text weight="plus">Slightly bolder</Text>
|
|
572
|
+
<Text family="mono">Monospaced</Text>
|
|
573
|
+
<Text leading="compact">Tighter line height</Text>
|
|
574
|
+
|
|
575
|
+
{/* Render as a different element */}
|
|
576
|
+
<Text as="span">Inline text</Text>
|
|
577
|
+
<Text as="div">Block text</Text>
|
|
578
|
+
<Text as="label" htmlFor="name">A label</Text>
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
| Prop | Type | Default | Description |
|
|
582
|
+
| ----------- | --------------------------------------------- | --------- | --------------------------------------------- |
|
|
583
|
+
| `as` | `"p" \| "span" \| "div" \| "label"` | `"p"` | The rendered HTML element. |
|
|
584
|
+
| `size` | `"small" \| "base" \| "large"` | `"base"` | Type scale. |
|
|
585
|
+
| `weight` | `"regular" \| "plus"` | `"regular"` | Font weight. |
|
|
586
|
+
| `family` | `"sans" \| "mono"` | `"sans"` | Font family. |
|
|
587
|
+
| `leading` | `"normal" \| "compact"` | `"normal"` | Line-height density. |
|
|
588
|
+
| `className` | `string` | `undefined` | Extra classes, merged with the defaults. |
|
|
589
|
+
|
|
590
|
+
Accepts every other standard HTML attribute for whichever element `as` renders.
|
|
591
|
+
|
|
592
|
+
### Toast
|
|
593
|
+
|
|
594
|
+
Transient notifications, built on Base UI's `Toast`. Needs a `Toast.Provider` (already included if you use [`Providers`](#providers)) and a rendered `Toast.Viewport` + `Toast.List` somewhere in the tree (also already included in `Providers`).
|
|
595
|
+
|
|
596
|
+
```tsx
|
|
597
|
+
"use client";
|
|
598
|
+
|
|
599
|
+
import { Button, Toast } from "@florianke/components";
|
|
600
|
+
|
|
601
|
+
function CreateToastButton() {
|
|
602
|
+
const toastManager = Toast.useToastManager();
|
|
603
|
+
|
|
604
|
+
return (
|
|
605
|
+
<Button
|
|
606
|
+
onClick={() =>
|
|
607
|
+
toastManager.add({
|
|
608
|
+
type: "success", // "success" | "error" | "warning" | "info" | undefined
|
|
609
|
+
title: "Changes saved",
|
|
610
|
+
description: "Your changes have been saved successfully.",
|
|
611
|
+
})
|
|
612
|
+
}
|
|
613
|
+
>
|
|
614
|
+
Save
|
|
615
|
+
</Button>
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
If you're not using [`Providers`](#providers), set it up manually once near the root of your app:
|
|
621
|
+
|
|
622
|
+
```tsx
|
|
623
|
+
<Toast.Provider>
|
|
624
|
+
{children}
|
|
625
|
+
<Toast.Viewport>
|
|
626
|
+
<Toast.List />
|
|
627
|
+
</Toast.Viewport>
|
|
628
|
+
</Toast.Provider>
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
- `Toast.List` renders every active toast, automatically stacked/peeking, with the correct icon and color for `type`.
|
|
632
|
+
- The four `type` variants (`success`, `error`, `warning`, `info`) each get a distinct icon shape (not just a color), so they stay distinguishable for colorblind users too.
|
|
633
|
+
- `Toast.useToastManager()` (also exported standalone as `useToastManager`) returns `{ toasts, add, close, update, promise }` — see [Base UI's Toast docs](https://base-ui.com/react/components/toast) for the full manager API.
|
|
634
|
+
|
|
635
|
+
#### `Toast.Provider`
|
|
636
|
+
|
|
637
|
+
Forwards all props to Base UI's `Toast.Provider`.
|
|
638
|
+
|
|
639
|
+
#### `Toast.Viewport`
|
|
640
|
+
|
|
641
|
+
The fixed-position container toasts are portaled into (bottom-right corner by default). Forwards all props to Base UI's `Toast.Viewport`.
|
|
642
|
+
|
|
643
|
+
#### `Toast.List`
|
|
644
|
+
|
|
645
|
+
No props — renders the current toasts from `useToastManager()`. Use this unless you need full manual control over each toast's markup (in which case, compose `Toast.Root` / `Toast.Content` / `Toast.Icon` / `Toast.Title` / `Toast.Description` / `Toast.Close` yourself).
|
|
646
|
+
|
|
647
|
+
#### `Toast.Close`
|
|
648
|
+
|
|
649
|
+
Forwards all props to Base UI's `Toast.Close`. Defaults to rendering as our own `Button` with `variant="outline" size="sm"`.
|
|
650
|
+
|
|
651
|
+
### Tooltip
|
|
652
|
+
|
|
653
|
+
A short, single-line (up to `max-w-64`, then wraps) hint shown on hover/focus, built on Base UI's `Tooltip`. Needs a `Tooltip.Provider` (already included if you use [`Providers`](#providers)) as an ancestor.
|
|
654
|
+
|
|
655
|
+
```tsx
|
|
656
|
+
import { Button, Tooltip } from "@florianke/components";
|
|
657
|
+
|
|
658
|
+
<Tooltip.Provider>
|
|
659
|
+
<Tooltip>
|
|
660
|
+
<Tooltip.Trigger render={<Button variant="ghost" size="sm" />}>
|
|
661
|
+
<BoldIcon />
|
|
662
|
+
</Tooltip.Trigger>
|
|
663
|
+
<Tooltip.Content>Bold</Tooltip.Content>
|
|
664
|
+
</Tooltip>
|
|
665
|
+
</Tooltip.Provider>
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
#### `Tooltip.Provider`
|
|
669
|
+
|
|
670
|
+
| Prop | Type | Default | Description |
|
|
671
|
+
| ------------ | ----------- | ------- | ---------------------------------------------------------------------- |
|
|
672
|
+
| `delay` | `number` | `150` | Milliseconds before a tooltip opens (Base UI's own default is `600`). |
|
|
673
|
+
| `closeDelay` | `number` | `0` | Milliseconds before a tooltip closes. |
|
|
674
|
+
|
|
675
|
+
Groups all tooltips underneath it so that once one is open, adjacent ones open instantly (Base UI's built-in behavior).
|
|
676
|
+
|
|
677
|
+
#### `Tooltip` (root)
|
|
678
|
+
|
|
679
|
+
Forwards all props to Base UI's `Tooltip.Root`.
|
|
680
|
+
|
|
681
|
+
#### `Tooltip.Trigger`
|
|
682
|
+
|
|
683
|
+
Forwards all props to Base UI's `Tooltip.Trigger` — most commonly `render`.
|
|
684
|
+
|
|
685
|
+
#### `Tooltip.Content`
|
|
686
|
+
|
|
687
|
+
| Prop | Type | Default | Description |
|
|
688
|
+
| ------------- | --------------------------------------------------- | --------- | ---------------------------------------------------- |
|
|
689
|
+
| `side` | `"top" \| "bottom" \| "left" \| "right"` | `undefined` (Base UI default: `"top"`) | Preferred side relative to the trigger. |
|
|
690
|
+
| `align` | `"start" \| "center" \| "end"` | `"center"` | Alignment along that side. |
|
|
691
|
+
| `sideOffset` | `number` | `8` | Gap (px) between the trigger and the tooltip. |
|
|
692
|
+
| `alignOffset` | `number` | `undefined` | Extra offset along the alignment axis. |
|
|
693
|
+
|
|
353
694
|
## Hooks
|
|
354
695
|
|
|
696
|
+
### useConfirm
|
|
697
|
+
|
|
698
|
+
An imperative confirmation dialog — `await` a promise instead of managing dialog open state yourself. Needs a `ConfirmProvider` as an ancestor (already included if you use [`Providers`](#providers)).
|
|
699
|
+
|
|
700
|
+
```tsx
|
|
701
|
+
"use client";
|
|
702
|
+
|
|
703
|
+
import { Button, useConfirm } from "@florianke/components";
|
|
704
|
+
|
|
705
|
+
function DiscardButton() {
|
|
706
|
+
const confirm = useConfirm();
|
|
707
|
+
|
|
708
|
+
async function handleClick() {
|
|
709
|
+
const confirmed = await confirm({
|
|
710
|
+
title: "Discard draft?",
|
|
711
|
+
description: "You can't undo this action.",
|
|
712
|
+
confirmText: "Discard",
|
|
713
|
+
variant: "danger",
|
|
714
|
+
});
|
|
715
|
+
if (confirmed) {
|
|
716
|
+
// ...discard
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
return (
|
|
721
|
+
<Button variant="destructive" onClick={handleClick}>
|
|
722
|
+
Discard draft
|
|
723
|
+
</Button>
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
For anything more sensitive than a plain yes/no (e.g. deleting an account or a production resource), require the user to type a matching string before the confirm button enables, via `verificationText`:
|
|
729
|
+
|
|
730
|
+
```tsx
|
|
731
|
+
const confirmed = await confirm({
|
|
732
|
+
title: "Delete account",
|
|
733
|
+
description: `Type "${entityName}" to confirm.`,
|
|
734
|
+
confirmText: "Delete",
|
|
735
|
+
variant: "danger",
|
|
736
|
+
verificationText: entityName,
|
|
737
|
+
});
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
If you're not using [`Providers`](#providers), set it up manually once near the root of your app:
|
|
741
|
+
|
|
742
|
+
```tsx
|
|
743
|
+
import { ConfirmProvider } from "@florianke/components";
|
|
744
|
+
|
|
745
|
+
<ConfirmProvider>{children}</ConfirmProvider>
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
`useConfirm(): (options?: ConfirmOptions) => Promise<boolean>` — resolves `true` when confirmed, `false` when cancelled (Escape, backdrop click, or the Cancel button).
|
|
749
|
+
|
|
750
|
+
`ConfirmOptions`:
|
|
751
|
+
|
|
752
|
+
| Option | Type | Default | Description |
|
|
753
|
+
| --------------------------- | ------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------- |
|
|
754
|
+
| `title` | `React.ReactNode` | `"Are you sure?"` | Dialog title. |
|
|
755
|
+
| `description` | `React.ReactNode` | `undefined` | Dialog description. |
|
|
756
|
+
| `confirmText` | `string` | `"Confirm"` | Label of the confirming button. |
|
|
757
|
+
| `cancelText` | `string` | `"Cancel"` | Label of the cancelling button. |
|
|
758
|
+
| `variant` | `"default" \| "danger"` | `"default"` | `"danger"` renders the confirm button with `Button`'s `destructive` variant. |
|
|
759
|
+
| `verificationText` | `string` | `undefined` | When set, requires the user to type this exact text before confirming. |
|
|
760
|
+
| `verificationInstruction` | `React.ReactNode` | `Type <b>{verificationText}</b> to confirm.` | Custom label shown above the verification input. |
|
|
761
|
+
|
|
355
762
|
### useInitials
|
|
356
763
|
|
|
357
764
|
Derives up to two initials from a full name — the first letter of the first word and the first letter of the last word (falls back to a single letter for one-word names). This is what powers `Avatar`'s fallback, and is exported standalone in case you need initials somewhere else in your app (e.g. a table row, a comment list).
|
|
@@ -373,19 +780,48 @@ useInitials("Max Peter Mustermann"); // "MM" (first + last word)
|
|
|
373
780
|
|
|
374
781
|
## Package Exports
|
|
375
782
|
|
|
376
|
-
Every component (and
|
|
783
|
+
Every component (and hook) is available from the main entry point, and also as its own subpath for more granular imports/bundling:
|
|
377
784
|
|
|
378
785
|
```tsx
|
|
379
786
|
// Everything, from the main entry
|
|
380
|
-
import {
|
|
787
|
+
import {
|
|
788
|
+
AlertDialog,
|
|
789
|
+
Avatar,
|
|
790
|
+
Button,
|
|
791
|
+
Card,
|
|
792
|
+
ConfirmProvider,
|
|
793
|
+
DropdownMenu,
|
|
794
|
+
Field,
|
|
795
|
+
Heading,
|
|
796
|
+
Hint,
|
|
797
|
+
Input,
|
|
798
|
+
Label,
|
|
799
|
+
Providers,
|
|
800
|
+
Select,
|
|
801
|
+
Text,
|
|
802
|
+
Toast,
|
|
803
|
+
Tooltip,
|
|
804
|
+
useConfirm,
|
|
805
|
+
useInitials,
|
|
806
|
+
} from "@florianke/components";
|
|
381
807
|
|
|
382
808
|
// Or, individually
|
|
809
|
+
import { AlertDialog } from "@florianke/components/alert-dialog";
|
|
383
810
|
import { Avatar } from "@florianke/components/avatar";
|
|
384
811
|
import { Button } from "@florianke/components/button";
|
|
385
812
|
import { Card } from "@florianke/components/card";
|
|
386
813
|
import { DropdownMenu } from "@florianke/components/dropdown-menu";
|
|
814
|
+
import { Field } from "@florianke/components/field";
|
|
815
|
+
import { Heading } from "@florianke/components/heading";
|
|
816
|
+
import { Hint } from "@florianke/components/hint";
|
|
387
817
|
import { Input } from "@florianke/components/input";
|
|
818
|
+
import { Label } from "@florianke/components/label";
|
|
819
|
+
import { Providers } from "@florianke/components/providers";
|
|
388
820
|
import { Select } from "@florianke/components/select";
|
|
821
|
+
import { Text } from "@florianke/components/text";
|
|
822
|
+
import { Toast } from "@florianke/components/toast";
|
|
823
|
+
import { Tooltip } from "@florianke/components/tooltip";
|
|
824
|
+
import { ConfirmProvider, useConfirm } from "@florianke/components/hooks/use-confirm";
|
|
389
825
|
import { useInitials } from "@florianke/components/hooks/use-initials";
|
|
390
826
|
|
|
391
827
|
import "@florianke/components/styles.css";
|
|
@@ -393,4 +829,4 @@ import "@florianke/components/styles.css";
|
|
|
393
829
|
|
|
394
830
|
## License
|
|
395
831
|
|
|
396
|
-
|
|
832
|
+
MIT
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogRoot, AlertDialogTitle, AlertDialogTrigger } from "./components/alert-dialog/alert-dialog.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/components/alert-dialog/index.d.ts
|
|
4
|
+
declare const AlertDialog: typeof AlertDialogRoot & {
|
|
5
|
+
Trigger: typeof AlertDialogTrigger;
|
|
6
|
+
Content: typeof AlertDialogContent;
|
|
7
|
+
Title: typeof AlertDialogTitle;
|
|
8
|
+
Description: typeof AlertDialogDescription;
|
|
9
|
+
Close: typeof AlertDialogClose;
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
export { AlertDialog };
|
|
13
|
+
//# sourceMappingURL=alert-dialog.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-dialog.d.mts","names":[],"sources":["../src/components/alert-dialog/index.ts"],"mappings":";;;cAea,WAAA,SAAW,eAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogRoot, AlertDialogTitle, AlertDialogTrigger } from "./components/alert-dialog/alert-dialog.mjs";
|
|
2
|
+
//#region src/components/alert-dialog/index.ts
|
|
3
|
+
const AlertDialog = Object.assign(AlertDialogRoot, {
|
|
4
|
+
Trigger: AlertDialogTrigger,
|
|
5
|
+
Content: AlertDialogContent,
|
|
6
|
+
Title: AlertDialogTitle,
|
|
7
|
+
Description: AlertDialogDescription,
|
|
8
|
+
Close: AlertDialogClose
|
|
9
|
+
});
|
|
10
|
+
//#endregion
|
|
11
|
+
export { AlertDialog };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=alert-dialog.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-dialog.mjs","names":[],"sources":["../src/components/alert-dialog/index.ts"],"sourcesContent":["import {\n AlertDialogClose,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogRoot,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from \"./alert-dialog\";\n\n// Composed in a module without \"use client\" on purpose: Next.js/Turbopack\n// generates a client-reference proxy for each export of a \"use client\"\n// module, and that proxy does not forward extra static properties attached\n// via Object.assign. Doing the composition here (a plain module that just\n// re-imports the already-resolved client references) keeps\n// `AlertDialog.Content` etc. working when consumed from a Server Component.\nexport const AlertDialog = Object.assign(AlertDialogRoot, {\n Trigger: AlertDialogTrigger,\n Content: AlertDialogContent,\n Title: AlertDialogTitle,\n Description: AlertDialogDescription,\n Close: AlertDialogClose,\n});\n"],"mappings":";;AAeA,MAAa,cAAc,OAAO,OAAO,iBAAiB;CACxD,SAAS;CACT,SAAS;CACT,OAAO;CACP,aAAa;CACb,OAAO;CACR,CAAC"}
|