@facetui/react 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +60 -0
- package/README.md +509 -0
- package/THEMING.md +168 -0
- package/dist/index.cjs +1220 -0
- package/dist/index.d.cts +367 -0
- package/dist/index.d.ts +367 -0
- package/dist/index.js +1209 -0
- package/package.json +122 -0
package/THEMING.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Theming FacetUI
|
|
2
|
+
|
|
3
|
+
FacetUI ships **one** theme and a fixed token contract. A theme is nothing more
|
|
4
|
+
than an override of ~16 CSS custom properties — there are no per-component theme
|
|
5
|
+
props, no config file, no build step. If your app already uses a
|
|
6
|
+
[shadcn/ui **v4**](https://ui.shadcn.com) theme, FacetUI is themed already; the
|
|
7
|
+
tokens are identical.
|
|
8
|
+
|
|
9
|
+
- [The token contract](#the-token-contract)
|
|
10
|
+
- [Using FacetUI's default theme](#using-facetuis-default-theme)
|
|
11
|
+
- [Dark mode](#dark-mode)
|
|
12
|
+
- [Building your own theme (≈15 min)](#building-your-own-theme-15-min)
|
|
13
|
+
- [Multiple presets](#multiple-presets)
|
|
14
|
+
- [FAQ](#faq)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## The token contract
|
|
19
|
+
|
|
20
|
+
Every FacetUI component is styled exclusively against these semantic tokens.
|
|
21
|
+
Values are [OKLCH](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch).
|
|
22
|
+
Each `--token` is exposed to Tailwind as a `*-token` utility (`bg-primary`,
|
|
23
|
+
`text-muted-foreground`, `border-border`, `ring-ring`, …).
|
|
24
|
+
|
|
25
|
+
| Token | Drives | Notes |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `--background` / `--foreground` | Page + default text | The surface the table sits on |
|
|
28
|
+
| `--primary` / `--primary-foreground` | Selected rows, checked checkboxes, spinner, primary emphasis | |
|
|
29
|
+
| `--muted` / `--muted-foreground` | Header row fill, hover rows, secondary text, result counts | |
|
|
30
|
+
| `--accent` / `--accent-foreground` | Focused / hovered menu & option rows | |
|
|
31
|
+
| `--popover` / `--popover-foreground` | Column-visibility menu, page-size dropdown surface | |
|
|
32
|
+
| `--destructive` / `--destructive-foreground` | Reserved for destructive states in composed layouts | |
|
|
33
|
+
| `--border` | Every divider and cell border | `* { border-color: var(--border) }` is set in base |
|
|
34
|
+
| `--input` | Search field & control borders | Usually equal to `--border` |
|
|
35
|
+
| `--ring` | `focus-visible` ring on every interactive control | Keep it visibly distinct from `--background` |
|
|
36
|
+
|
|
37
|
+
That's the whole surface. Adding a component later means styling it against
|
|
38
|
+
**these** tokens — not introducing new ones unless a genuinely new role appears.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Using FacetUI's default theme
|
|
43
|
+
|
|
44
|
+
Copy the three blocks from [`src/index.css`](./src/index.css) into your global
|
|
45
|
+
stylesheet:
|
|
46
|
+
|
|
47
|
+
1. `@custom-variant dark (&:is(.dark *));`
|
|
48
|
+
2. the `:root { … }` and `.dark { … }` token blocks
|
|
49
|
+
3. the `@theme inline { … }` mapping (this is what makes `bg-primary` etc. resolve)
|
|
50
|
+
|
|
51
|
+
No `tailwind.config` changes are needed on Tailwind v4 — utility classes are
|
|
52
|
+
auto-detected from your source.
|
|
53
|
+
|
|
54
|
+
> **shadcn/ui v4 users:** you already have all of the above. Skip this section.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Dark mode
|
|
59
|
+
|
|
60
|
+
The contract is driven by a `.dark` **class**, matched anywhere up the tree
|
|
61
|
+
(`&:is(.dark *)`). Put the class on `<html>` (or any wrapper) and every FacetUI
|
|
62
|
+
surface below it re-themes instantly — no rebuild, because `@theme inline` keeps
|
|
63
|
+
the utilities pointing at the live custom properties.
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
// e.g. next-themes, or your own toggle
|
|
67
|
+
<html className={isDark ? "dark" : undefined}>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Storybook has a **Theme** toolbar toggle (light / dark) wired to the same class —
|
|
71
|
+
use it to check both halves of the contract while developing.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Building your own theme (≈15 min)
|
|
76
|
+
|
|
77
|
+
A theme override only needs to restate the tokens you want to change. Anything you
|
|
78
|
+
omit falls back to the default.
|
|
79
|
+
|
|
80
|
+
**1. Pick your brand color in OKLCH.** Use any OKLCH picker
|
|
81
|
+
(`oklch(L C H)` — lightness `0–1`, chroma `0–0.4`, hue `0–360`). Say your brand is
|
|
82
|
+
a blue: `oklch(0.55 0.20 255)`.
|
|
83
|
+
|
|
84
|
+
**2. Derive the ramp.** You typically only need the accent pair plus the ring:
|
|
85
|
+
|
|
86
|
+
```css
|
|
87
|
+
/* brand-theme.css — layer this AFTER FacetUI's :root block */
|
|
88
|
+
:root {
|
|
89
|
+
--primary: oklch(0.55 0.20 255);
|
|
90
|
+
--primary-foreground: oklch(0.985 0 0); /* white text on the brand fill */
|
|
91
|
+
--ring: oklch(0.55 0.20 255 / 0.6); /* brand, translucent */
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.dark {
|
|
95
|
+
--primary: oklch(0.72 0.16 255); /* lift L, drop C for dark surfaces */
|
|
96
|
+
--primary-foreground: oklch(0.18 0.02 255);
|
|
97
|
+
--ring: oklch(0.72 0.16 255 / 0.55);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**3. (Optional) shift the neutrals.** The defaults are zinc (hue ≈ 286). To warm
|
|
102
|
+
them, nudge every neutral token's hue toward ~60–90 and add a little chroma:
|
|
103
|
+
|
|
104
|
+
```css
|
|
105
|
+
:root {
|
|
106
|
+
--background: oklch(1 0 0);
|
|
107
|
+
--foreground: oklch(0.14 0.01 75);
|
|
108
|
+
--muted: oklch(0.96 0.008 75);
|
|
109
|
+
--muted-foreground: oklch(0.55 0.02 75);
|
|
110
|
+
--accent: oklch(0.96 0.008 75);
|
|
111
|
+
--accent-foreground: oklch(0.21 0.01 75);
|
|
112
|
+
--border: oklch(0.90 0.01 75);
|
|
113
|
+
--input: oklch(0.90 0.01 75);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**4. Check contrast.** `--foreground` on `--background`, `--primary-foreground` on
|
|
118
|
+
`--primary`, and `--muted-foreground` on `--background` all need to clear WCAG AA
|
|
119
|
+
(4.5:1 for body text). OKLCH lightness (`L`) is close to perceptual — a gap of
|
|
120
|
+
~0.4 between text and its surface is a safe starting point; verify with a
|
|
121
|
+
contrast checker.
|
|
122
|
+
|
|
123
|
+
**5. Load it after the base tokens** so your values win the cascade. Done —
|
|
124
|
+
`<DataTable>` needs no props.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Multiple presets
|
|
129
|
+
|
|
130
|
+
FacetUI intentionally ships a single theme. When you need more than one, make
|
|
131
|
+
each preset a **class** that restates the tokens, mirroring the `.dark` pattern:
|
|
132
|
+
|
|
133
|
+
```css
|
|
134
|
+
.theme-ocean { --primary: oklch(0.55 0.13 220); --ring: oklch(0.55 0.13 220 / .6); /* … */ }
|
|
135
|
+
.theme-ocean.dark,
|
|
136
|
+
.dark .theme-ocean { --primary: oklch(0.72 0.11 220); /* … */ }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
<div className="theme-ocean">
|
|
141
|
+
<DataTable … />
|
|
142
|
+
</div>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Because the tokens are semantic, one class swap re-themes the entire component —
|
|
146
|
+
including its menus and popovers — with no FacetUI API surface involved.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## FAQ
|
|
151
|
+
|
|
152
|
+
**Can I change padding / density / border radius per theme?**
|
|
153
|
+
Density is a runtime prop (`density="compact" | "default" | "comfortable"`), not a
|
|
154
|
+
token. Radius is currently a fixed Tailwind scale (`rounded-xs` / `rounded-sm` /
|
|
155
|
+
`rounded-md`) in the components; if you need it tokenized, that's a component
|
|
156
|
+
change, not a theme override.
|
|
157
|
+
|
|
158
|
+
**Why OKLCH and not HSL / hex?**
|
|
159
|
+
Perceptually uniform lightness makes deriving accessible ramps predictable, and it
|
|
160
|
+
matches shadcn/ui v4 so their themes drop in unchanged. Opacity modifiers
|
|
161
|
+
(`bg-muted/50`) still work — Tailwind compiles them to `color-mix()`.
|
|
162
|
+
|
|
163
|
+
**I'm on Tailwind v3.**
|
|
164
|
+
Add the token `:root` / `.dark` blocks as plain CSS, register the colors in
|
|
165
|
+
`tailwind.config` under `theme.extend.colors` (e.g.
|
|
166
|
+
`primary: "var(--primary)"`), and add
|
|
167
|
+
`"./node_modules/@facetui/react/dist/**/*.js"` (or your copied folder path) to
|
|
168
|
+
`content`.
|