@soybeanjs/shadcn-theme 0.1.0 → 0.2.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.en_US.md CHANGED
@@ -67,61 +67,115 @@ applyTheme(theme.getCss({ primary: 'emerald' }));
67
67
 
68
68
  ### Custom Preset
69
69
 
70
- `preset` lets you add or override named preset entries on top of the built-in presets. You can extend only one group (e.g. add a custom `primary` preset), or extend `base / primary / feedback / sidebar` together.
70
+ Using the `preset` parameter, you can provide a complete custom color configuration that overrides the built-in base/primary/feedback/sidebar presets. When using a custom preset, you need to provide complete color definitions.
71
71
 
72
- #### 1) Structure and how to reference a preset
72
+ #### 1) When to use custom preset
73
73
 
74
- - `preset` is an object that may contain `base / primary / feedback / sidebar`. Each group is `{ [key: string]: PresetItem }`.
75
- - To use your custom preset, set the corresponding `base` / `primary` / `feedback` / `sidebar` option to the key you defined.
76
- - Example: if you define `preset.primary.brandPrimary`, then pass `primary: 'brandPrimary'`.
74
+ - Use `preset` to provide a complete custom color configuration when built-in preset combinations cannot meet your design requirements.
75
+ - When using a custom preset, all base/primary/feedback/sidebar related parameters will be ignored, only the `preset` configuration is used.
77
76
 
78
- #### 2) Merge/override rules
77
+ #### 2) Color values and `format`
79
78
 
80
- The library shallow-merges your `preset` into the built-ins:
81
-
82
- - Same key is overridden by your `preset` (e.g. defining `primary.indigo` overrides built-in `indigo`).
83
- - New keys are added as extra presets (e.g. `primary.brandPrimary`).
84
-
85
- #### 3) Two sidebar modes
86
-
87
- - `sidebar: 'extended'` (default): ignores `preset.sidebar` and derives sidebar colors from base/primary.
88
- - `sidebar: '<yourKey>'`: uses `preset.sidebar[<yourKey>]` as the sidebar colors.
89
-
90
- #### 4) Color values and `format`
91
-
92
- - Each color value supports: Tailwind palette reference (e.g. `slate.500`), `hsl(...)`, or `oklch(...)`.
79
+ - Each color value supports: Tailwind palette reference (e.g. `slate.500`), `hsl(...)`, `oklch(...)`, or the builtin permitted color names (`inherit`, `currentColor`, `transparent`, `black`, `white`).
93
80
  - `format: 'hsl'`: outputs `h s l [/ alpha]` (no outer `hsl(...)`); `oklch(...)` inputs are converted to HSL.
94
81
  - `format: 'oklch'`: outputs values with the outer `oklch(...)`; `hsl(...)` inputs are converted to OKLCH.
95
82
 
96
- #### Quick example: add a custom primary preset (good starting point)
97
-
98
- `primary` presets only need `primary / ring / chart1~chart5`:
83
+ #### Quick example: Complete custom preset
99
84
 
100
- ```ts
85
+ ```typescript
101
86
  const theme = createShadcnTheme({
102
- primary: 'brandPrimary',
103
87
  preset: {
104
- primary: {
105
- brandPrimary: {
106
- light: {
107
- primary: 'blue.600',
108
- ring: 'blue.400',
109
- chart1: 'orange.600',
110
- chart2: 'teal.600',
111
- chart3: 'cyan.900',
112
- chart4: 'amber.400',
113
- chart5: 'amber.500'
114
- },
115
- dark: {
116
- primary: 'blue.400',
117
- ring: 'blue.500',
118
- chart1: 'orange.500',
119
- chart2: 'teal.500',
120
- chart3: 'cyan.400',
121
- chart4: 'amber.500',
122
- chart5: 'amber.600'
123
- }
124
- }
88
+ light: {
89
+ // Base colors
90
+ background: 'white',
91
+ foreground: 'slate.950',
92
+ card: 'white',
93
+ cardForeground: 'slate.950',
94
+ popover: 'white',
95
+ popoverForeground: 'slate.950',
96
+ primaryForeground: 'slate.50',
97
+ secondary: 'slate.100',
98
+ secondaryForeground: 'slate.900',
99
+ muted: 'slate.100',
100
+ mutedForeground: 'slate.500',
101
+ accent: 'slate.100',
102
+ accentForeground: 'slate.900',
103
+ destructiveForeground: 'slate.50',
104
+ successForeground: 'slate.50',
105
+ warningForeground: 'slate.50',
106
+ infoForeground: 'slate.50',
107
+ carbon: 'slate.800',
108
+ carbonForeground: 'slate.50',
109
+ border: 'slate.200',
110
+ input: 'slate.200',
111
+ // Theme colors
112
+ primary: 'blue.600',
113
+ destructive: 'red.500',
114
+ success: 'green.500',
115
+ warning: 'amber.500',
116
+ info: 'blue.500',
117
+ ring: 'blue.400',
118
+ // Chart colors
119
+ chart1: 'orange.600',
120
+ chart2: 'teal.600',
121
+ chart3: 'cyan.900',
122
+ chart4: 'amber.400',
123
+ chart5: 'amber.500',
124
+ // Sidebar colors
125
+ sidebar: 'slate.50',
126
+ sidebarForeground: 'slate.900',
127
+ sidebarPrimary: 'blue.600',
128
+ sidebarPrimaryForeground: 'slate.50',
129
+ sidebarAccent: 'slate.100',
130
+ sidebarAccentForeground: 'slate.900',
131
+ sidebarBorder: 'slate.200',
132
+ sidebarRing: 'blue.400'
133
+ },
134
+ dark: {
135
+ // Base colors
136
+ background: 'slate.950',
137
+ foreground: 'slate.50',
138
+ card: 'slate.900',
139
+ cardForeground: 'slate.50',
140
+ popover: 'slate.900',
141
+ popoverForeground: 'slate.50',
142
+ primaryForeground: 'slate.900',
143
+ secondary: 'slate.800',
144
+ secondaryForeground: 'slate.50',
145
+ muted: 'slate.800',
146
+ mutedForeground: 'slate.400',
147
+ accent: 'slate.800',
148
+ accentForeground: 'slate.50',
149
+ destructiveForeground: 'slate.900',
150
+ successForeground: 'slate.900',
151
+ warningForeground: 'slate.900',
152
+ infoForeground: 'slate.900',
153
+ carbon: 'slate.100',
154
+ carbonForeground: 'slate.900',
155
+ border: 'oklch(100% 0 0 / 0.1)',
156
+ input: 'oklch(100% 0 0 / 0.15)',
157
+ // Theme colors
158
+ primary: 'blue.400',
159
+ destructive: 'red.400',
160
+ success: 'green.400',
161
+ warning: 'amber.400',
162
+ info: 'blue.400',
163
+ ring: 'blue.500',
164
+ // Chart colors
165
+ chart1: 'orange.500',
166
+ chart2: 'teal.500',
167
+ chart3: 'cyan.400',
168
+ chart4: 'amber.500',
169
+ chart5: 'amber.600',
170
+ // Sidebar colors
171
+ sidebar: 'slate.950',
172
+ sidebarForeground: 'slate.50',
173
+ sidebarPrimary: 'blue.400',
174
+ sidebarPrimaryForeground: 'slate.950',
175
+ sidebarAccent: 'slate.900',
176
+ sidebarAccentForeground: 'slate.50',
177
+ sidebarBorder: 'slate.800',
178
+ sidebarRing: 'blue.500'
125
179
  }
126
180
  }
127
181
  });
@@ -129,127 +183,11 @@ const theme = createShadcnTheme({
129
183
  const css = theme.getCss();
130
184
  ```
131
185
 
132
- #### Quick example: add a custom feedback preset
133
-
134
- ```ts
135
- const theme = createShadcnTheme({
136
- feedback: 'brandFeedback',
137
- preset: {
138
- feedback: {
139
- brandFeedback: {
140
- light: {
141
- destructive: 'red.500',
142
- success: 'emerald.500',
143
- warning: 'amber.500',
144
- info: 'sky.500'
145
- },
146
- dark: {
147
- destructive: 'red.400',
148
- success: 'emerald.400',
149
- warning: 'amber.400',
150
- info: 'sky.400'
151
- }
152
- }
153
- }
154
- }
155
- });
156
- ```
157
-
158
- #### Quick example: custom sidebar (non-extended)
159
-
160
- ```ts
161
- const theme = createShadcnTheme({
162
- sidebar: 'brandSidebar',
163
- preset: {
164
- sidebar: {
165
- brandSidebar: {
166
- light: {
167
- sidebar: 'slate.50',
168
- sidebarForeground: 'slate.900',
169
- sidebarPrimary: 'blue.600',
170
- sidebarPrimaryForeground: 'slate.50',
171
- sidebarAccent: 'slate.100',
172
- sidebarAccentForeground: 'slate.900',
173
- sidebarBorder: 'slate.200',
174
- sidebarRing: 'blue.400'
175
- },
176
- dark: {
177
- sidebar: 'slate.950',
178
- sidebarForeground: 'slate.50',
179
- sidebarPrimary: 'blue.400',
180
- sidebarPrimaryForeground: 'slate.950',
181
- sidebarAccent: 'slate.900',
182
- sidebarAccentForeground: 'slate.50',
183
- sidebarBorder: 'slate.800',
184
- sidebarRing: 'blue.500'
185
- }
186
- }
187
- }
188
- }
189
- });
190
- ```
191
-
192
- #### Full example (custom base + primary + feedback)
186
+ #### Notes
193
187
 
194
- ```typescript
195
- createShadcnTheme({
196
- base: 'demoBase',
197
- primary: 'demoPrimary',
198
- feedback: 'demoFeedback',
199
- preset: {
200
- base: {
201
- demoBase: {
202
- light: {
203
- background: 'oklch(100% 0 0)',
204
- foreground: 'stone.950',
205
- card: 'oklch(100% 0 0)',
206
- cardForeground: 'stone.950',
207
- popover: 'oklch(100% 0 0)',
208
- popoverForeground: 'stone.950',
209
- primaryForeground: 'stone.50',
210
- secondary: 'stone.100',
211
- secondaryForeground: 'stone.900',
212
- muted: 'stone.100',
213
- mutedForeground: 'stone.500',
214
- accent: 'stone.100',
215
- accentForeground: 'stone.900',
216
- destructiveForeground: 'stone.50',
217
- successForeground: 'stone.50',
218
- warningForeground: 'stone.50',
219
- infoForeground: 'stone.50',
220
- carbon: 'stone.800',
221
- carbonForeground: 'stone.50',
222
- border: 'stone.200',
223
- input: 'stone.200'
224
- },
225
- dark: {
226
- background: 'stone.950',
227
- foreground: 'stone.50',
228
- card: 'stone.900',
229
- cardForeground: 'stone.50',
230
- popover: 'stone.900',
231
- popoverForeground: 'stone.50',
232
- primaryForeground: 'stone.900',
233
- secondary: 'stone.800',
234
- secondaryForeground: 'stone.50',
235
- muted: 'stone.800',
236
- mutedForeground: 'stone.400',
237
- accent: 'stone.800',
238
- accentForeground: 'stone.50',
239
- destructiveForeground: 'stone.900',
240
- successForeground: 'stone.900',
241
- warningForeground: 'stone.900',
242
- infoForeground: 'stone.900',
243
- carbon: 'stone.100',
244
- carbonForeground: 'stone.900',
245
- border: 'oklch(100% 0 0 / 0.1)',
246
- input: 'oklch(100% 0 0 / 0.15)'
247
- }
248
- }
249
- }
250
- }
251
- });
252
- ```
188
+ - When providing the `preset` parameter, the `base`, `primary`, `feedback`, and `sidebar` parameters will be ignored.
189
+ - The preset must include complete color definitions for both `light` and `dark` modes.
190
+ - It is recommended to start from the structure of built-in presets and modify according to your design needs.
253
191
 
254
192
  ## 📖 API Documentation
255
193
 
@@ -269,54 +207,58 @@ theme.getRadiusCss(radius?: string): string
269
207
 
270
208
  #### ThemeOptions
271
209
 
272
- | Parameter | Type | Default | Description |
273
- |------|------|--------|------|
274
- | `base` | `BuiltinBasePresetKey \| string` | `'gray'` | Base preset key |
275
- | `primary` | `BuiltinPrimaryPresetKey \| string` | `'indigo'` | Primary preset key |
276
- | `feedback` | `BuiltinFeedbackPresetKey \| string` | `'classic'` | Feedback preset key |
277
- | `sidebar` | `'extended' \| string` | `'extended'` | Sidebar mode; `extended` derives from base/primary |
278
- | `preset` | `CustomPreset` | - | Custom preset collection (extends base/primary/feedback/sidebar) |
279
- | `radius` | `string` | `'0.625rem'` | Global border radius |
280
- | `styleTarget` | `'html' \| ':root'` | `':root'` | CSS variables mount selector |
281
- | `darkSelector` | `'class' \| 'media' \| string` | `'class'` | Dark mode selector (custom string supported) |
282
- | `format` | `'hsl' \| 'oklch'` | `'hsl'` | Output color format |
210
+ | Parameter | Type | Default | Description |
211
+ | -------------- | ------------------------------ | ------------ | --------------------------------------------------------------------------------------- |
212
+ | `base` | `BuiltinBasePresetKey` | `'neutral'` | Base preset key |
213
+ | `primary` | `BuiltinPrimaryPresetKey` | `'indigo'` | Primary preset key |
214
+ | `feedback` | `BuiltinFeedbackPresetKey` | `'classic'` | Feedback preset key |
215
+ | `sidebar` | `'extended'` | `'extended'` | Sidebar mode; `extended` derives from base/primary |
216
+ | `preset` | `ThemeColorPresetItem` | - | Complete custom color preset (when provided, base/primary/feedback/sidebar are ignored) |
217
+ | `radius` | `string` | `'0.625rem'` | Global border radius |
218
+ | `styleTarget` | `'html' \| ':root'` | `':root'` | CSS variables mount selector |
219
+ | `darkSelector` | `'class' \| 'media' \| string` | `'class'` | Dark mode selector (custom string supported) |
220
+ | `format` | `'hsl' \| 'oklch'` | `'hsl'` | Output color format |
283
221
 
284
222
  ### Preset Configuration (PresetConfig)
285
223
 
286
224
  ```typescript
287
225
  interface PresetConfig {
288
- base?: string;
289
- primary?: string;
290
- feedback?: string;
291
- sidebar?: 'extended' | string;
226
+ base?: BuiltinBasePresetKey | 'custom';
227
+ primary?: BuiltinPrimaryPresetKey | 'custom';
228
+ feedback?: BuiltinFeedbackPresetKey | 'custom';
229
+ sidebar?: 'extended' | 'custom';
230
+ preset?: ThemeColorPresetItem;
292
231
  }
293
232
  ```
294
233
 
234
+ When using the `preset` parameter, other configuration parameters (base/primary/feedback/sidebar) will be ignored.
235
+
295
236
  #### Feedback Palette Key (FeedbackPaletteKey)
296
237
 
297
- | Style | Description | Use Cases |
298
- |------|------|----------|
299
- | `classic` | Classic Standard | Most common combination, suitable for most scenarios |
300
- | `vivid` | Vivid & Energetic | High saturation, suitable for youth-oriented products and creative applications |
301
- | `subtle` | Soft & Elegant | Low contrast, suitable for premium brands and elegant interfaces |
302
- | `warm` | Warm & Welcoming | Warm color tones, creates a friendly and warm atmosphere |
303
- | `cool` | Cool & Professional | Cool color tones, suitable for tech and professional applications |
304
- | `nature` | Natural & Fresh | Natural colors, suitable for eco-friendly and health products |
305
- | `modern` | Modern & Minimalist | Strong modern feel, suitable for tech products and SaaS applications |
306
- | `vibrant` | Vibrant & Dynamic | High-energy colors, suitable for sports and gaming applications |
307
- | `professional` | Business Professional | Stable and dignified, suitable for enterprise applications and B2B products |
308
- | `soft` | Dreamy & Soft | Soft tones, suitable for design tools and creative platforms |
309
- | `bold` | Bold & Eye-catching | High contrast, suitable for scenarios requiring strong visual impact |
310
- | `calm` | Calm & Soothing | Low saturation, suitable for long-term use applications |
311
- | `candy` | Candy Colors | Bright and cute, suitable for children's products and fun applications |
312
- | `deep` | Deep & Mysterious | Deep tones, suitable for dark themes and mysterious styles |
313
- | `light` | Fresh & Light | Light tones, suitable for clean and refreshing interfaces |
238
+ | Style | Description | Use Cases |
239
+ | -------------- | --------------------- | ------------------------------------------------------------------------------- |
240
+ | `classic` | Classic Standard | Most common combination, suitable for most scenarios |
241
+ | `vivid` | Vivid & Energetic | High saturation, suitable for youth-oriented products and creative applications |
242
+ | `subtle` | Soft & Elegant | Low contrast, suitable for premium brands and elegant interfaces |
243
+ | `warm` | Warm & Welcoming | Warm color tones, creates a friendly and warm atmosphere |
244
+ | `cool` | Cool & Professional | Cool color tones, suitable for tech and professional applications |
245
+ | `nature` | Natural & Fresh | Natural colors, suitable for eco-friendly and health products |
246
+ | `modern` | Modern & Minimalist | Strong modern feel, suitable for tech products and SaaS applications |
247
+ | `vibrant` | Vibrant & Dynamic | High-energy colors, suitable for sports and gaming applications |
248
+ | `professional` | Business Professional | Stable and dignified, suitable for enterprise applications and B2B products |
249
+ | `soft` | Dreamy & Soft | Soft tones, suitable for design tools and creative platforms |
250
+ | `bold` | Bold & Eye-catching | High contrast, suitable for scenarios requiring strong visual impact |
251
+ | `calm` | Calm & Soothing | Low saturation, suitable for long-term use applications |
252
+ | `candy` | Candy Colors | Bright and cute, suitable for children's products and fun applications |
253
+ | `deep` | Deep & Mysterious | Deep tones, suitable for dark themes and mysterious styles |
254
+ | `light` | Fresh & Light | Light tones, suitable for clean and refreshing interfaces |
314
255
 
315
256
  ### Theme Color Configuration (ThemeColors)
316
257
 
317
258
  Supports configuration of the following color variables:
318
259
 
319
260
  #### Base Colors
261
+
320
262
  - `background` - Background color
321
263
  - `foreground` - Foreground color (text)
322
264
  - `card` - Card background
@@ -338,12 +280,14 @@ Supports configuration of the following color variables:
338
280
  - `ring` - Focus ring color
339
281
 
340
282
  #### Extended Colors
283
+
341
284
  - `success` / `successForeground` - Success state
342
285
  - `warning` / `warningForeground` - Warning state
343
286
  - `info` / `infoForeground` - Info state
344
287
  - `carbon` / `carbonForeground` - Carbon color (additional dark scheme)
345
288
 
346
289
  #### Sidebar Colors
290
+
347
291
  - `sidebar` - Sidebar background
348
292
  - `sidebarForeground` - Sidebar foreground
349
293
  - `sidebarPrimary` - Sidebar primary color
@@ -354,6 +298,7 @@ Supports configuration of the following color variables:
354
298
  - `sidebarRing` - Sidebar focus ring
355
299
 
356
300
  #### Chart Colors
301
+
357
302
  - `chart1` ~ `chart5` - Chart colors
358
303
 
359
304
  ### Color Value Format (ColorValue)
@@ -361,22 +306,25 @@ Supports configuration of the following color variables:
361
306
  Supports three color value formats:
362
307
 
363
308
  1. **HSL Format**
309
+
364
310
  ```typescript
365
- 'hsl(0 0% 100%)'
366
- 'hsl(0 0% 100% / 0.5)' // with opacity
311
+ 'hsl(0 0% 100%)';
312
+ 'hsl(0 0% 100% / 0.5)'; // with opacity
367
313
  ```
368
314
 
369
315
  2. **OKLCH Format**
316
+
370
317
  ```typescript
371
- 'oklch(100% 0 0)'
372
- 'oklch(100% 0 0 / 0.5)' // with opacity
318
+ 'oklch(100% 0 0)';
319
+ 'oklch(100% 0 0 / 0.5)'; // with opacity
373
320
  ```
374
321
 
375
322
  3. **Tailwind Palette Reference**
323
+
376
324
  ```typescript
377
- 'slate.500'
378
- 'blue.600'
379
- 'red.50'
325
+ 'slate.500';
326
+ 'blue.600';
327
+ 'red.50';
380
328
  ```
381
329
 
382
330
  ## 🎨 Usage Examples
@@ -533,19 +481,19 @@ module.exports = {
533
481
  DEFAULT: 'hsl(var(--primary))',
534
482
  foreground: 'hsl(var(--primary-foreground))',
535
483
  50: 'hsl(var(--primary-50))',
536
- 100: 'hsl(var(--primary-100))',
484
+ 100: 'hsl(var(--primary-100))'
537
485
  // ... more shades
538
- },
486
+ }
539
487
  // ... other colors
540
488
  },
541
489
  borderRadius: {
542
490
  lg: 'var(--radius)',
543
491
  md: 'calc(var(--radius) - 2px)',
544
- sm: 'calc(var(--radius) - 4px)',
492
+ sm: 'calc(var(--radius) - 4px)'
545
493
  }
546
494
  }
547
495
  }
548
- }
496
+ };
549
497
  ```
550
498
 
551
499
  When you use `format: 'hsl'`, opacity must be handled separately, especially for `border` / `input` / `sidebarBorder`:
@@ -555,20 +503,20 @@ When you use `format: 'hsl'`, opacity must be handled separately, especially for
555
503
 
556
504
  ```js
557
505
  // Use the generated alpha value
558
- border: 'hsl(var(--border) / var(--border-alpha))'
506
+ border: 'hsl(var(--border) / var(--border-alpha))';
559
507
  ```
560
508
 
561
509
  If you want Tailwind opacity modifiers to work (e.g. `border-border/50`), use the `<alpha-value>` placeholder (in this case you typically don't use `--border-alpha`):
562
510
 
563
511
  ```js
564
512
  // Let Tailwind inject opacity
565
- border: 'hsl(var(--border) / <alpha-value>)'
513
+ border: 'hsl(var(--border) / <alpha-value>)';
566
514
  ```
567
515
 
568
516
  If you use `format: 'oklch'`, since the variable value already contains `oklch(...)`, use `var(--xxx)` directly in Tailwind (no extra `oklch(...)` wrapper needed):
569
517
 
570
518
  ```js
571
- background: 'var(--background)'
519
+ background: 'var(--background)';
572
520
  ```
573
521
 
574
522
  ### Using in CSS