@dynamic-labs-sdk/droplet 0.27.2 → 0.27.3
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 +116 -20
- package/package.json +11 -2
- package/src/styles/globals.css +16 -12
package/README.md
CHANGED
|
@@ -1,38 +1,30 @@
|
|
|
1
1
|
# `@dynamic-labs-sdk/droplet`
|
|
2
2
|
|
|
3
|
-
Dynamic Labs'
|
|
3
|
+
Dynamic Labs' React component library. Built on Radix UI primitives, Tailwind CSS v4, and an OKLCH-based design token system. Ships with 35+ components, animated icons, dark mode, and a live Storybook.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
}
|
|
9
|
+
```bash
|
|
10
|
+
npm install @dynamic-labs-sdk/droplet
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @dynamic-labs-sdk/droplet
|
|
13
|
+
# or
|
|
14
|
+
yarn add @dynamic-labs-sdk/droplet
|
|
17
15
|
```
|
|
18
16
|
|
|
17
|
+
**Peer dependencies:** `react >= 18`, `react-dom >= 18`, `tailwindcss >= 4`. Next.js (`>= 14`) is optional.
|
|
18
|
+
|
|
19
19
|
---
|
|
20
20
|
|
|
21
21
|
## Setup
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Droplet ships Tailwind CSS v4 utility classes baked into its compiled output. You must (1) have Tailwind v4 configured in your app, (2) import the design tokens stylesheet, and (3) tell Tailwind to scan droplet's `dist/` so its utility classes are emitted into your stylesheet.
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
import '@dynamic-labs-sdk/droplet/styles/globals.css';
|
|
27
|
-
```
|
|
25
|
+
### 1. Install and configure Tailwind v4
|
|
28
26
|
|
|
29
|
-
If you'
|
|
30
|
-
|
|
31
|
-
```ts
|
|
32
|
-
import '../../packages/droplet/src/styles/globals.css';
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Your bundler must support Tailwind CSS v4 via the `@tailwindcss/vite` plugin:
|
|
27
|
+
If you don't already have Tailwind v4, follow [the Tailwind v4 install guide](https://tailwindcss.com/docs/installation). The `@tailwindcss/vite` plugin is the simplest path for Vite/Next:
|
|
36
28
|
|
|
37
29
|
```ts
|
|
38
30
|
// vite.config.ts
|
|
@@ -44,6 +36,26 @@ export default defineConfig({
|
|
|
44
36
|
});
|
|
45
37
|
```
|
|
46
38
|
|
|
39
|
+
### 2. Import the design tokens stylesheet
|
|
40
|
+
|
|
41
|
+
Import once at your app root. This provides the full color, shadow, radius, and typography token system and is required for all components to render correctly.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import '@dynamic-labs-sdk/droplet/styles/globals.css';
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 3. Add droplet to Tailwind's `@source` paths
|
|
48
|
+
|
|
49
|
+
Tailwind v4 only scans the consuming project by default, so it will miss the utility classes inside droplet's compiled JS. Add an `@source` directive to your app's main stylesheet:
|
|
50
|
+
|
|
51
|
+
```css
|
|
52
|
+
/* app.css */
|
|
53
|
+
@import 'tailwindcss';
|
|
54
|
+
@source "../node_modules/@dynamic-labs-sdk/droplet/dist";
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Adjust the relative path to match where your stylesheet lives. Without this step, components will render unstyled.
|
|
58
|
+
|
|
47
59
|
---
|
|
48
60
|
|
|
49
61
|
## Usage
|
|
@@ -194,6 +206,90 @@ import {
|
|
|
194
206
|
|
|
195
207
|
---
|
|
196
208
|
|
|
209
|
+
## Theming
|
|
210
|
+
|
|
211
|
+
Droplet's theme is a layer of CSS custom properties. Tailwind utility classes resolve through them (`bg-brand-default` → `var(--brand-default)`), and every component reads from the same vars — so you can fully rebrand by **redefining the vars in your own stylesheet**. No Tailwind config changes, no rebuild, no fork.
|
|
212
|
+
|
|
213
|
+
### Quick start: change the brand color
|
|
214
|
+
|
|
215
|
+
```css
|
|
216
|
+
/* your-theme.css — imported AFTER @dynamic-labs-sdk/droplet/styles/globals.css */
|
|
217
|
+
|
|
218
|
+
:root {
|
|
219
|
+
--brand-default: oklch(0.67 0.21 30); /* your light-mode brand */
|
|
220
|
+
--brand-hover: oklch(0.72 0.19 30);
|
|
221
|
+
--brand-accented: oklch(0.58 0.22 30);
|
|
222
|
+
--brand-light: oklch(0.97 0.03 30);
|
|
223
|
+
--ring: oklch(0.67 0.21 30);
|
|
224
|
+
--action: oklch(0.67 0.21 30);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.dark {
|
|
228
|
+
--brand-default: oklch(0.6 0.22 30); /* your dark-mode brand */
|
|
229
|
+
--brand-hover: oklch(0.68 0.19 30);
|
|
230
|
+
--brand-accented: oklch(0.52 0.23 30);
|
|
231
|
+
--brand-light: oklch(0.27 0.07 30);
|
|
232
|
+
--ring: oklch(0.6 0.22 30);
|
|
233
|
+
--action: oklch(0.6 0.22 30);
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
// in your app entry, AFTER the droplet import
|
|
239
|
+
import '@dynamic-labs-sdk/droplet/styles/globals.css';
|
|
240
|
+
import './your-theme.css';
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
That's it. Buttons, links, focus rings, text-selection highlights, sidebars — all switch to the new brand.
|
|
244
|
+
|
|
245
|
+
### Cascade order matters
|
|
246
|
+
|
|
247
|
+
Your theme stylesheet **must load after** `@dynamic-labs-sdk/droplet/styles/globals.css`, or the same selectors (`:root`, `.dark`) in droplet's stylesheet will win and your overrides will silently do nothing. If you `@import` in a single CSS file, put droplet's import **first**:
|
|
248
|
+
|
|
249
|
+
```css
|
|
250
|
+
@import '@dynamic-labs-sdk/droplet/styles/globals.css';
|
|
251
|
+
@import './your-theme.css';
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### What's themeable
|
|
255
|
+
|
|
256
|
+
Anything in the [Design tokens](#design-tokens) table below — colors, shadows, radii. The most common things to override:
|
|
257
|
+
|
|
258
|
+
| What you want to change | Tokens |
|
|
259
|
+
| ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
|
|
260
|
+
| Brand color (buttons, focus rings, links, selection) | `--brand-default`, `--brand-hover`, `--brand-accented`, `--brand-light`, `--ring`, `--action` |
|
|
261
|
+
| Surfaces (page bg, cards, sidebar) | `--background`, `--card`, `--bg-bottom`, `--bg-default`, `--sidebar` |
|
|
262
|
+
| Text colors | `--foreground`, `--muted-foreground`, `--text-link` |
|
|
263
|
+
| Radius scale | `--radius-sm` through `--radius-4xl` |
|
|
264
|
+
| Selection highlight | `--selection-bg` |
|
|
265
|
+
| Solid button top-highlight | `--button-highlight` |
|
|
266
|
+
| Checkbox / radio hover fills | `--checkbox-hover-fill`, `--radio-hover-fill` |
|
|
267
|
+
|
|
268
|
+
For semantic colors (success/danger/warning/process), override the matching `--<state>-default`, `--<state>-light`, `--text-<state>` triplet.
|
|
269
|
+
|
|
270
|
+
### Scoping a theme to part of your app
|
|
271
|
+
|
|
272
|
+
If you only want droplet themed inside a subtree (e.g., a marketing site reusing one component), put the overrides on a wrapper class instead of `:root`:
|
|
273
|
+
|
|
274
|
+
```css
|
|
275
|
+
.my-theme {
|
|
276
|
+
--brand-default: oklch(0.67 0.21 30);
|
|
277
|
+
/* ... */
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
```tsx
|
|
282
|
+
<div className="my-theme">
|
|
283
|
+
<Button>Themed</Button>
|
|
284
|
+
</div>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Color space
|
|
288
|
+
|
|
289
|
+
Droplet uses [OKLCH](https://oklch.com/) throughout. If your design system is in hex/rgb, tools like [oklch.com](https://oklch.com) or [oklch.fyi](https://oklch.fyi) will convert. You don't *have* to use OKLCH in your overrides — `oklch()`, `hex`, `rgb()`, and `hsl()` all interoperate fine — but staying in OKLCH gives you perceptually uniform lightness ramps when you tune hover/accented variants.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
197
293
|
## Design tokens
|
|
198
294
|
|
|
199
295
|
All tokens are CSS custom properties defined in `globals.css`. Tailwind utility classes map directly to them — `bg-brand-default` resolves to `var(--brand-default)`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynamic-labs-sdk/droplet",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.esm.js",
|
|
@@ -23,6 +23,9 @@
|
|
|
23
23
|
"dist",
|
|
24
24
|
"src/styles"
|
|
25
25
|
],
|
|
26
|
+
"sideEffects": [
|
|
27
|
+
"**/*.css"
|
|
28
|
+
],
|
|
26
29
|
"dependencies": {
|
|
27
30
|
"@hugeicons/core-free-icons": "4.1.1",
|
|
28
31
|
"@hugeicons/react": "1.1.6",
|
|
@@ -76,7 +79,13 @@
|
|
|
76
79
|
"peerDependencies": {
|
|
77
80
|
"next": ">=14",
|
|
78
81
|
"react": ">=18",
|
|
79
|
-
"react-dom": ">=18"
|
|
82
|
+
"react-dom": ">=18",
|
|
83
|
+
"tailwindcss": ">=4"
|
|
84
|
+
},
|
|
85
|
+
"peerDependenciesMeta": {
|
|
86
|
+
"next": {
|
|
87
|
+
"optional": true
|
|
88
|
+
}
|
|
80
89
|
},
|
|
81
90
|
"scripts": {
|
|
82
91
|
"build": "rm -rf dist && tsdown && pnpm exec tsc --emitDeclarationOnly -p ./tsconfig.lib.json",
|
package/src/styles/globals.css
CHANGED
|
@@ -227,6 +227,12 @@
|
|
|
227
227
|
--shadow-field-hover: 0 0 0 1px oklch(0.278 0.03 256.85 / 0.18), 0px 0px 1px 0px oklch(0.278 0.03 256.85 / 0.10);
|
|
228
228
|
--shadow-elevated: 0 0 0 1px oklch(0.278 0.03 256.85 / 0.10), 0px 5px 15px 0px oklch(0.278 0.03 256.85 / 0.08), 0px 15px 35px -5px oklch(0.278 0.03 256.85 / 0.20);
|
|
229
229
|
--shadow-card-content: 0px 0px 2px 0px oklch(0.278 0.03 256.85 / 0.08), 0px 1px 2px 0px oklch(0.278 0.03 256.85 / 0.06);
|
|
230
|
+
|
|
231
|
+
/* ——— Component-specific overlays (themeable) ——— */
|
|
232
|
+
--selection-bg: oklch(0.574 0.207 257.4 / 0.15);
|
|
233
|
+
--checkbox-hover-fill: oklch(0.278 0.03 256.85 / 0.08);
|
|
234
|
+
--radio-hover-fill: oklch(0.278 0.03 256.85 / 0.12);
|
|
235
|
+
--button-highlight: oklch(1 0 0);
|
|
230
236
|
}
|
|
231
237
|
|
|
232
238
|
/* ═══════════════════════════════════════════════════════════
|
|
@@ -354,6 +360,12 @@
|
|
|
354
360
|
--shadow-field-hover: 0 0 0 1px oklch(1 0 0 / 0.18), 0px 0px 1px 0px oklch(0 0 0 / 0.10);
|
|
355
361
|
--shadow-elevated: 0 0 0 1px oklch(1 0 0 / 0.06), 0px 5px 15px 0px oklch(0 0 0 / 0.25), 0px 15px 35px -5px oklch(0 0 0 / 0.45);
|
|
356
362
|
--shadow-card-content: 0px 0px 2px 0px oklch(0 0 0 / 0.08), 0px 1px 2px 0px oklch(0 0 0 / 0.06);
|
|
363
|
+
|
|
364
|
+
/* ——— Component-specific overlays (themeable) ——— */
|
|
365
|
+
--selection-bg: oklch(0.510 0.205 257 / 0.18);
|
|
366
|
+
--checkbox-hover-fill: oklch(1 0 0 / 0.10);
|
|
367
|
+
--radio-hover-fill: oklch(1 0 0 / 0.15);
|
|
368
|
+
--button-highlight: oklch(1 0 0);
|
|
357
369
|
}
|
|
358
370
|
|
|
359
371
|
@layer base {
|
|
@@ -384,7 +396,7 @@
|
|
|
384
396
|
}
|
|
385
397
|
/* Branded text selection */
|
|
386
398
|
::selection {
|
|
387
|
-
background-color:
|
|
399
|
+
background-color: var(--selection-bg);
|
|
388
400
|
color: inherit;
|
|
389
401
|
}
|
|
390
402
|
/* Slashed zero + tabular nums for monospace contexts */
|
|
@@ -448,16 +460,12 @@
|
|
|
448
460
|
position: absolute;
|
|
449
461
|
inset: 2px;
|
|
450
462
|
border-radius: 2px;
|
|
451
|
-
background:
|
|
463
|
+
background: var(--checkbox-hover-fill);
|
|
452
464
|
opacity: 0;
|
|
453
465
|
transition: opacity 150ms ease-out;
|
|
454
466
|
pointer-events: none;
|
|
455
467
|
}
|
|
456
468
|
|
|
457
|
-
.dark [data-slot='checkbox'][data-state='unchecked']::before {
|
|
458
|
-
background: oklch(1 0 0 / 0.10);
|
|
459
|
-
}
|
|
460
|
-
|
|
461
469
|
[data-slot='checkbox'][data-state='unchecked']:not(:disabled):hover::before {
|
|
462
470
|
opacity: 1;
|
|
463
471
|
}
|
|
@@ -477,16 +485,12 @@
|
|
|
477
485
|
top: 50%;
|
|
478
486
|
left: 50%;
|
|
479
487
|
transform: translate(-50%, -50%);
|
|
480
|
-
background:
|
|
488
|
+
background: var(--radio-hover-fill);
|
|
481
489
|
opacity: 0;
|
|
482
490
|
transition: opacity 150ms ease-out;
|
|
483
491
|
pointer-events: none;
|
|
484
492
|
}
|
|
485
493
|
|
|
486
|
-
.dark [data-slot='radio-group-item'][data-state='unchecked']::before {
|
|
487
|
-
background: oklch(1 0 0 / 0.15);
|
|
488
|
-
}
|
|
489
|
-
|
|
490
494
|
[data-slot='radio-group-item'][data-state='unchecked']:not(:disabled):hover::before {
|
|
491
495
|
opacity: 1;
|
|
492
496
|
}
|
|
@@ -524,7 +528,7 @@
|
|
|
524
528
|
position: absolute;
|
|
525
529
|
inset: 0;
|
|
526
530
|
border-radius: inherit;
|
|
527
|
-
background: linear-gradient(180deg,
|
|
531
|
+
background: linear-gradient(180deg, var(--button-highlight), transparent);
|
|
528
532
|
opacity: 0.1;
|
|
529
533
|
transition: opacity 0.5s;
|
|
530
534
|
pointer-events: none;
|