@dheme/react 2.2.0 → 2.3.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/README.md +133 -0
- package/dist/index.js +656 -413
- package/dist/index.mjs +657 -413
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -274,6 +274,139 @@ The provider sets 19 CSS variables + `--radius` on `:root`:
|
|
|
274
274
|
|
|
275
275
|
Values are in shadcn/ui format (`h s% l%`), directly compatible with Tailwind CSS `hsl()` usage.
|
|
276
276
|
|
|
277
|
+
## ThemeGenerator
|
|
278
|
+
|
|
279
|
+
A floating FAB (Floating Action Button) that lets users generate and preview themes in real time — directly inside your app. No external dependencies beyond React itself.
|
|
280
|
+
|
|
281
|
+
```tsx
|
|
282
|
+
import { DhemeProvider, ThemeGenerator } from '@dheme/react';
|
|
283
|
+
|
|
284
|
+
function App() {
|
|
285
|
+
return (
|
|
286
|
+
<DhemeProvider apiKey="..." theme="#3b82f6">
|
|
287
|
+
<MyApp />
|
|
288
|
+
<ThemeGenerator />
|
|
289
|
+
</DhemeProvider>
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
The component renders as a pill in the corner of the screen. Clicking it expands a panel with color pickers, sliders, and toggles that call `generateTheme()` in real time with per-parameter debounce.
|
|
295
|
+
|
|
296
|
+
### Props
|
|
297
|
+
|
|
298
|
+
```tsx
|
|
299
|
+
<ThemeGenerator
|
|
300
|
+
defaultTheme="#4332f6" // Initial primary color
|
|
301
|
+
defaultSecondaryColor="#ab67f1" // Initial secondary color
|
|
302
|
+
defaultSaturation={10} // Initial saturation adjust (-100 to 100)
|
|
303
|
+
defaultLightness={2} // Initial lightness adjust (-100 to 100)
|
|
304
|
+
defaultRadius={0} // Initial border radius (0 to 2 rem)
|
|
305
|
+
position="bottom-right" // 'bottom-right' | 'bottom-left'
|
|
306
|
+
open={isOpen} // Controlled open state (optional)
|
|
307
|
+
onOpenChange={setIsOpen} // Controlled open callback (optional)
|
|
308
|
+
labels={{ // i18n overrides (all optional)
|
|
309
|
+
title: 'Theme Generator',
|
|
310
|
+
primary: 'Primary Color',
|
|
311
|
+
secondary: 'Secondary Color',
|
|
312
|
+
saturation: 'Vibrancy',
|
|
313
|
+
lightness: 'Brightness',
|
|
314
|
+
reset: 'Restore defaults',
|
|
315
|
+
}}
|
|
316
|
+
className="my-fab" // Extra class on the container (optional)
|
|
317
|
+
/>
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
| Prop | Type | Default | Description |
|
|
321
|
+
| --- | --- | --- | --- |
|
|
322
|
+
| `defaultTheme` | `string` | `'#4332f6'` | Initial primary HEX color. |
|
|
323
|
+
| `defaultSecondaryColor` | `string` | `'#ab67f1'` | Initial secondary HEX color. |
|
|
324
|
+
| `defaultSaturation` | `number` | `10` | Initial saturation adjust (-100–100). |
|
|
325
|
+
| `defaultLightness` | `number` | `2` | Initial lightness adjust (-100–100). |
|
|
326
|
+
| `defaultRadius` | `number` | `0` | Initial border radius (0–2 rem). |
|
|
327
|
+
| `position` | `'bottom-right' \| 'bottom-left'` | `'bottom-right'` | Corner to anchor the FAB. |
|
|
328
|
+
| `open` | `boolean` | — | Controlled open state. Omit for uncontrolled. |
|
|
329
|
+
| `onOpenChange` | `(open: boolean) => void` | — | Called when open state changes. |
|
|
330
|
+
| `labels` | `ThemeGeneratorLabels` | See below | Override any UI text for i18n. |
|
|
331
|
+
| `className` | `string` | — | Extra CSS class on the fixed container. |
|
|
332
|
+
|
|
333
|
+
#### Default labels
|
|
334
|
+
|
|
335
|
+
| Key | Default |
|
|
336
|
+
| --- | --- |
|
|
337
|
+
| `title` | `'Theme Generator'` |
|
|
338
|
+
| `description` | `'Generate complete themes from a single color. Changes apply in real time.'` |
|
|
339
|
+
| `baseColors` | `'Base Colors'` |
|
|
340
|
+
| `primary` | `'Primary'` |
|
|
341
|
+
| `secondary` | `'Secondary'` |
|
|
342
|
+
| `optional` | `'Optional'` |
|
|
343
|
+
| `fineTuning` | `'Fine Tuning'` |
|
|
344
|
+
| `saturation` | `'Saturation'` |
|
|
345
|
+
| `lightness` | `'Lightness'` |
|
|
346
|
+
| `borderRadius` | `'Border Radius'` |
|
|
347
|
+
| `advancedOptions` | `'Advanced Options'` |
|
|
348
|
+
| `colorfulCard` | `'Colorful Card'` |
|
|
349
|
+
| `colorfulBackground` | `'Colorful Background'` |
|
|
350
|
+
| `colorfulBorder` | `'Colorful Border'` |
|
|
351
|
+
| `reset` | `'Reset'` |
|
|
352
|
+
| `fabPrimaryLabel` | `'Primary'` |
|
|
353
|
+
|
|
354
|
+
### How it works
|
|
355
|
+
|
|
356
|
+
**Real-time generation with debounce**
|
|
357
|
+
|
|
358
|
+
Each parameter has its own debounce timer. Dragging the saturation slider fires an API call 200ms after the user stops — not on every frame. Color pickers debounce at 150ms.
|
|
359
|
+
|
|
360
|
+
| Control | Debounce |
|
|
361
|
+
| --- | --- |
|
|
362
|
+
| Color pickers | 150ms |
|
|
363
|
+
| Sliders (saturation, lightness, radius) | 200ms |
|
|
364
|
+
| Boolean toggles (card, background, border) | None — fires immediately |
|
|
365
|
+
| Secondary color enable/disable | None — fires immediately |
|
|
366
|
+
|
|
367
|
+
**No re-render loops**
|
|
368
|
+
|
|
369
|
+
State local to the component (`localPrimary`, `localSaturation`, …) is the source of truth for the controls. The component does **not** read back from `useTheme()`. This prevents a loop where `generateTheme()` → theme state update → re-render → re-initialize state → `generateTheme()` again.
|
|
370
|
+
|
|
371
|
+
**Zero external dependencies**
|
|
372
|
+
|
|
373
|
+
- Icons: inline SVG (no `lucide-react`)
|
|
374
|
+
- Color picker: built-in gradient + hue slider using pointer events (no `react-colorful`)
|
|
375
|
+
- Styling: inline styles using `hsl(var(--...))` CSS variables — automatically matches the active theme
|
|
376
|
+
|
|
377
|
+
**Controlled vs uncontrolled**
|
|
378
|
+
|
|
379
|
+
Omit `open` / `onOpenChange` for fully uncontrolled behavior. Provide both for external control:
|
|
380
|
+
|
|
381
|
+
```tsx
|
|
382
|
+
const [open, setOpen] = useState(false);
|
|
383
|
+
|
|
384
|
+
<ThemeGenerator open={open} onOpenChange={setOpen} />
|
|
385
|
+
<button onClick={() => setOpen(true)}>Open Theme Editor</button>
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Placement
|
|
389
|
+
|
|
390
|
+
`ThemeGenerator` must be a **descendant** of `<DhemeProvider>` — it consumes `useThemeActions()` internally.
|
|
391
|
+
|
|
392
|
+
```tsx
|
|
393
|
+
// ✅ Correct
|
|
394
|
+
<DhemeProvider ...>
|
|
395
|
+
<App />
|
|
396
|
+
<ThemeGenerator />
|
|
397
|
+
</DhemeProvider>
|
|
398
|
+
|
|
399
|
+
// ❌ Wrong — outside the provider
|
|
400
|
+
<>
|
|
401
|
+
<ThemeGenerator />
|
|
402
|
+
<DhemeProvider ...>
|
|
403
|
+
<App />
|
|
404
|
+
</DhemeProvider>
|
|
405
|
+
</>
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
277
410
|
## Utilities
|
|
278
411
|
|
|
279
412
|
### `themeToCSS(theme, mode)`
|