@dryui/theme-wizard 3.0.0 → 4.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.
@@ -6,5 +6,5 @@ export { encodeTheme, decodeTheme, encodeRecipe, decodeRecipe } from './url-code
6
6
  export type { DecodedTheme, WizardRecipe } from './url-codec.js';
7
7
  export { generatePalette, textToBrand } from './palette.js';
8
8
  export type { PaletteResult } from './palette.js';
9
- export { PRESETS } from './presets.js';
10
- export type { Preset } from './presets.js';
9
+ export { PRESETS, RECIPE_PRESETS } from './presets.js';
10
+ export type { Preset, RecipePreset } from './presets.js';
@@ -3,4 +3,4 @@ export { hsbToHsl, hslToHsb, hslToRgb, hslToHex, hexToHsl, cssColorToRgb, relati
3
3
  export { generateCss, downloadCss, copyCss, exportJson } from './export-css.js';
4
4
  export { encodeTheme, decodeTheme, encodeRecipe, decodeRecipe } from './url-codec.js';
5
5
  export { generatePalette, textToBrand } from './palette.js';
6
- export { PRESETS } from './presets.js';
6
+ export { PRESETS, RECIPE_PRESETS } from './presets.js';
@@ -1,6 +1,13 @@
1
1
  import type { BrandInput } from './derivation.js';
2
+ import type { WizardRecipe } from './url-codec.js';
2
3
  export interface Preset {
3
4
  name: string;
4
5
  brandInput: BrandInput;
5
6
  }
6
7
  export declare const PRESETS: Preset[];
8
+ export interface RecipePreset {
9
+ name: string;
10
+ description: string;
11
+ recipe: WizardRecipe;
12
+ }
13
+ export declare const RECIPE_PRESETS: RecipePreset[];
@@ -32,3 +32,93 @@ export const PRESETS = [
32
32
  brandInput: { h: 10, s: 85, b: 75 }
33
33
  }
34
34
  ];
35
+ export const RECIPE_PRESETS = [
36
+ {
37
+ name: 'Default',
38
+ description: 'Balanced starting point',
39
+ recipe: {
40
+ brand: { h: 230, s: 65, b: 85 },
41
+ personality: 'structured',
42
+ typography: { fontPreset: 'System', scale: 'default' },
43
+ shape: { radiusPreset: 'soft', radiusScale: 1, density: 'default' },
44
+ shadows: { preset: 'elevated', intensity: 1, tintBrand: true }
45
+ }
46
+ },
47
+ {
48
+ name: 'Dashboard',
49
+ description: 'Dense, data-first interface',
50
+ recipe: {
51
+ brand: { h: 200, s: 80, b: 70 },
52
+ personality: 'structured',
53
+ typography: { fontPreset: 'Geometric', scale: 'compact' },
54
+ shape: { radiusPreset: 'sharp', radiusScale: 1, density: 'compact' },
55
+ shadows: { preset: 'subtle', intensity: 1, tintBrand: false }
56
+ }
57
+ },
58
+ {
59
+ name: 'Editorial',
60
+ description: 'Warm, readable, content-forward',
61
+ recipe: {
62
+ brand: { h: 340, s: 65, b: 85 },
63
+ personality: 'clean',
64
+ typography: { fontPreset: 'Serif', scale: 'spacious' },
65
+ shape: { radiusPreset: 'soft', radiusScale: 1, density: 'spacious' },
66
+ shadows: { preset: 'flat', intensity: 1, tintBrand: true }
67
+ }
68
+ },
69
+ {
70
+ name: 'Terminal',
71
+ description: 'Precise, monospace, technical',
72
+ recipe: {
73
+ brand: { h: 145, s: 60, b: 55 },
74
+ personality: 'minimal',
75
+ typography: { fontPreset: 'Mono', scale: 'compact' },
76
+ shape: { radiusPreset: 'sharp', radiusScale: 1, density: 'compact' },
77
+ shadows: { preset: 'flat', intensity: 1, tintBrand: false }
78
+ }
79
+ },
80
+ {
81
+ name: 'Playful',
82
+ description: 'Warm, rounded, approachable',
83
+ recipe: {
84
+ brand: { h: 25, s: 80, b: 90 },
85
+ personality: 'rich',
86
+ typography: { fontPreset: 'Humanist', scale: 'default' },
87
+ shape: { radiusPreset: 'pill', radiusScale: 1, density: 'default' },
88
+ shadows: { preset: 'deep', intensity: 1, tintBrand: true }
89
+ }
90
+ },
91
+ {
92
+ name: 'Corporate',
93
+ description: 'Professional and measured',
94
+ recipe: {
95
+ brand: { h: 230, s: 65, b: 85 },
96
+ personality: 'structured',
97
+ typography: { fontPreset: 'Classical', scale: 'default' },
98
+ shape: { radiusPreset: 'soft', radiusScale: 1, density: 'default' },
99
+ shadows: { preset: 'elevated', intensity: 1, tintBrand: false }
100
+ }
101
+ },
102
+ {
103
+ name: 'Midnight',
104
+ description: 'Dark, atmospheric, layered',
105
+ recipe: {
106
+ brand: { h: 270, s: 45, b: 80 },
107
+ personality: 'rich',
108
+ typography: { fontPreset: 'System', scale: 'default' },
109
+ shape: { radiusPreset: 'rounded', radiusScale: 1, density: 'default' },
110
+ shadows: { preset: 'deep', intensity: 1, tintBrand: true }
111
+ }
112
+ },
113
+ {
114
+ name: 'Ember',
115
+ description: 'Bold, warm, high contrast',
116
+ recipe: {
117
+ brand: { h: 10, s: 85, b: 75 },
118
+ personality: 'structured',
119
+ typography: { fontPreset: 'Geometric', scale: 'default' },
120
+ shape: { radiusPreset: 'rounded', radiusScale: 1, density: 'default' },
121
+ shadows: { preset: 'elevated', intensity: 1, tintBrand: true }
122
+ }
123
+ }
124
+ ];
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './engine/index.js';
2
+ export { bg } from './actions.js';
2
3
  export { wizardState, getDerivedTheme, setBrandHsb, setStep, goNextStep, goPrevStep, activateFastTrack, applyPreset, getStyleString, setFontPreset, setTypeScale, resetToDefaults, applyRecipe, setRadiusPreset, setRadiusScale, setDensity, getShadowTokens, getShapeTokens, setPersonality, getPersonalityTokens, getAllTokens, getOverrideTokens, RADIUS_PRESETS, FONT_STACKS } from './state.svelte.js';
3
4
  export type { PreviewMode, NeutralMode, RadiusPreset, Density, ShadowPreset, Personality, TypeScale, FontPreset } from './state.svelte.js';
4
5
  export { default as PersonalityStep } from './steps/Personality.svelte';
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  // Re-export all engine functions and types
2
2
  export * from './engine/index.js';
3
+ // Re-export actions
4
+ export { bg } from './actions.js';
3
5
  // Re-export state (Svelte 5 runes)
4
6
  export { wizardState, getDerivedTheme, setBrandHsb, setStep, goNextStep, goPrevStep, activateFastTrack, applyPreset, getStyleString, setFontPreset, setTypeScale, resetToDefaults, applyRecipe, setRadiusPreset, setRadiusScale, setDensity, getShadowTokens, getShapeTokens, setPersonality, getPersonalityTokens, getAllTokens, getOverrideTokens, RADIUS_PRESETS, FONT_STACKS } from './state.svelte.js';
5
7
  // Step components
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import { Button } from '@dryui/ui';
2
3
  import { ColorPicker } from '@dryui/ui/color-picker';
3
4
  import { Text } from '@dryui/ui/text';
4
5
  import { setBrandHsb, getDerivedTheme, wizardState } from '../state.svelte.js';
@@ -10,17 +11,11 @@
10
11
  hsbToHsl,
11
12
  hslToHex
12
13
  } from '../engine/index.js';
13
- import type { BrandInput } from '../engine/index.js';
14
14
  import { bg } from '../actions';
15
15
 
16
16
  let { mode = 'light' }: { mode?: 'light' | 'dark' } = $props();
17
17
 
18
18
  let isDark = $derived(mode === 'dark');
19
- let brand = $state<BrandInput>({ ...wizardState.brandHsb });
20
-
21
- $effect(() => {
22
- setBrandHsb(brand.h, brand.s, brand.b);
23
- });
24
19
 
25
20
  const SWATCH_TOKENS = [
26
21
  { key: '--dry-color-fill', label: 'Fill' },
@@ -44,32 +39,34 @@
44
39
  );
45
40
 
46
41
  let pickerColor = $derived.by(() => {
47
- const hsl = hsbToHsl(brand.h, brand.s / 100, brand.b / 100);
42
+ const hsl = hsbToHsl(
43
+ wizardState.brandHsb.h,
44
+ wizardState.brandHsb.s / 100,
45
+ wizardState.brandHsb.b / 100
46
+ );
48
47
  return hslToHex(hsl.h, hsl.s, hsl.l);
49
48
  });
50
49
 
51
- let pickerHex = $state('');
52
-
53
- $effect(() => {
54
- pickerHex = pickerColor;
55
- });
56
-
57
- $effect(() => {
58
- if (pickerHex && pickerHex !== pickerColor) {
59
- const hsl = hexToHsl(pickerHex);
50
+ const pickerModel = {
51
+ get hex() {
52
+ return pickerColor;
53
+ },
54
+ set hex(value: string) {
55
+ if (!value || value === pickerColor) return;
56
+ const hsl = hexToHsl(value);
60
57
  const hsb = hslToHsb(hsl.h, hsl.s, hsl.l);
61
- brand = { h: hsb.h, s: Math.round(hsb.s * 100), b: Math.round(hsb.b * 100) };
58
+ setBrandHsb(hsb.h, Math.round(hsb.s * 100), Math.round(hsb.b * 100));
62
59
  }
63
- });
60
+ };
64
61
 
65
62
  function selectPreset(preset: (typeof PRESETS)[number]) {
66
- brand = preset.brandInput;
63
+ setBrandHsb(preset.brandInput.h, preset.brandInput.s, preset.brandInput.b);
67
64
  }
68
65
  </script>
69
66
 
70
67
  <section class="brand-section">
71
68
  <div class="picker-wrap">
72
- <ColorPicker.Root bind:value={pickerHex} areaHeight={160}>
69
+ <ColorPicker.Root bind:value={pickerModel.hex} areaHeight={160}>
73
70
  <ColorPicker.Area />
74
71
  <ColorPicker.HueSlider />
75
72
  <ColorPicker.Input format="hex" />
@@ -90,22 +87,23 @@
90
87
  {#each PRESETS as preset, i (preset.name)}
91
88
  {@const presetTheme = PRESET_THEMES[i] ?? PRESET_THEMES[0]!}
92
89
  {@const presetTokens = isDark ? presetTheme.dark : presetTheme.light}
93
- <button
94
- class="preset-btn"
95
- data-selected={brand.h === preset.brandInput.h &&
96
- brand.s === preset.brandInput.s &&
97
- brand.b === preset.brandInput.b
98
- ? ''
99
- : undefined}
100
- onclick={() => selectPreset(preset)}
101
- >
102
- <div class="preset-thumb">
103
- {#each SWATCH_TOKENS as { key } (key)}
104
- <div class="preset-swatch" use:bg={presetTokens[key] ?? ''}></div>
105
- {/each}
90
+ <Button type="button" variant="bare" onclick={() => selectPreset(preset)}>
91
+ <div
92
+ class="preset-btn"
93
+ data-selected={wizardState.brandHsb.h === preset.brandInput.h &&
94
+ wizardState.brandHsb.s === preset.brandInput.s &&
95
+ wizardState.brandHsb.b === preset.brandInput.b
96
+ ? ''
97
+ : undefined}
98
+ >
99
+ <div class="preset-thumb">
100
+ {#each SWATCH_TOKENS as { key } (key)}
101
+ <div class="preset-swatch" use:bg={presetTokens[key] ?? ''}></div>
102
+ {/each}
103
+ </div>
104
+ <Text as="span" size="xs" color="muted">{preset.name.toLowerCase()}</Text>
106
105
  </div>
107
- <Text as="span" size="xs" color="muted">{preset.name.toLowerCase()}</Text>
108
- </button>
106
+ </Button>
109
107
  {/each}
110
108
  </div>
111
109
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dryui/theme-wizard",
3
- "version": "3.0.0",
3
+ "version": "4.0.0",
4
4
  "author": "Rob Balfre",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -37,15 +37,15 @@
37
37
  "check": "svelte-check --tsconfig ./tsconfig.json"
38
38
  },
39
39
  "peerDependencies": {
40
- "@dryui/primitives": "^0.3.0",
41
- "@dryui/ui": "^0.3.0",
40
+ "@dryui/primitives": "^0.4.0",
41
+ "@dryui/ui": "^0.4.0",
42
42
  "lucide-svelte": ">=1.0.1",
43
43
  "svelte": "^5.55.1"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@dryui/lint": "^0.2.0",
47
- "@dryui/primitives": "^0.3.0",
48
- "@dryui/ui": "^0.3.0",
47
+ "@dryui/primitives": "^0.4.0",
48
+ "@dryui/ui": "^0.4.0",
49
49
  "lucide-svelte": "^1.0.1",
50
50
  "svelte": "^5.55.3",
51
51
  "@sveltejs/package": "^2.5.7",