@stackwright/themes 0.3.1-alpha.5 → 0.3.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @stackwright/themes
2
2
 
3
+ ## 0.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - dc2db25: Adding null checks to core
8
+ - bd7cd6e: Internal packagename refactor.
9
+ - ca71410: Core testing implemented
10
+ - 51dbbc9: Refactor types out of core into own package.
11
+ - f195337: Adding test dependencies to all packages.
12
+ - 5ff20a6: Fixing mixed compilation tooling (tsup/tsc) to only tsup
13
+ - 46df7ac: Documentation updates
14
+ - e4fbf2f: Update all dependencies
15
+ - cc761ce: More version updates
16
+
3
17
  ## 0.3.1-alpha.5
4
18
 
5
19
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -15,12 +15,12 @@ interface ThemeConfig {
15
15
  };
16
16
  backgroundImage?: {
17
17
  url: string;
18
- repeat?: 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat';
19
- size?: 'auto' | 'cover' | 'contain' | string;
18
+ repeat?: "repeat" | "repeat-x" | "repeat-y" | "no-repeat";
19
+ size?: "auto" | "cover" | "contain" | string;
20
20
  position?: string;
21
- attachment?: 'scroll' | 'fixed' | 'local';
21
+ attachment?: "scroll" | "fixed" | "local";
22
22
  scale?: number;
23
- animation?: 'drift' | 'float' | 'shimmer' | 'shimmer-float' | 'none';
23
+ animation?: "drift" | "float" | "shimmer" | "shimmer-float" | "none";
24
24
  customAnimation?: string;
25
25
  };
26
26
  typography: {
@@ -34,8 +34,8 @@ interface ThemeConfig {
34
34
  base: string;
35
35
  lg: string;
36
36
  xl: string;
37
- '2xl': string;
38
- '3xl': string;
37
+ "2xl": string;
38
+ "3xl": string;
39
39
  };
40
40
  };
41
41
  spacing: {
@@ -44,13 +44,13 @@ interface ThemeConfig {
44
44
  md: string;
45
45
  lg: string;
46
46
  xl: string;
47
- '2xl': string;
47
+ "2xl": string;
48
48
  };
49
- components: {
50
- button: ComponentStyle;
51
- card: ComponentStyle;
52
- header: ComponentStyle;
53
- footer: ComponentStyle;
49
+ components?: {
50
+ button?: ComponentStyle;
51
+ card?: ComponentStyle;
52
+ header?: ComponentStyle;
53
+ footer?: ComponentStyle;
54
54
  };
55
55
  }
56
56
  interface ComponentStyle {
@@ -68,7 +68,7 @@ interface Theme extends ThemeConfig {
68
68
 
69
69
  interface ThemeContextType {
70
70
  theme: Theme;
71
- setTheme?: (theme: Theme) => void;
71
+ setTheme: (theme: Theme) => void;
72
72
  }
73
73
  interface ThemeProviderProps {
74
74
  theme: Theme;
package/dist/index.d.ts CHANGED
@@ -15,12 +15,12 @@ interface ThemeConfig {
15
15
  };
16
16
  backgroundImage?: {
17
17
  url: string;
18
- repeat?: 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat';
19
- size?: 'auto' | 'cover' | 'contain' | string;
18
+ repeat?: "repeat" | "repeat-x" | "repeat-y" | "no-repeat";
19
+ size?: "auto" | "cover" | "contain" | string;
20
20
  position?: string;
21
- attachment?: 'scroll' | 'fixed' | 'local';
21
+ attachment?: "scroll" | "fixed" | "local";
22
22
  scale?: number;
23
- animation?: 'drift' | 'float' | 'shimmer' | 'shimmer-float' | 'none';
23
+ animation?: "drift" | "float" | "shimmer" | "shimmer-float" | "none";
24
24
  customAnimation?: string;
25
25
  };
26
26
  typography: {
@@ -34,8 +34,8 @@ interface ThemeConfig {
34
34
  base: string;
35
35
  lg: string;
36
36
  xl: string;
37
- '2xl': string;
38
- '3xl': string;
37
+ "2xl": string;
38
+ "3xl": string;
39
39
  };
40
40
  };
41
41
  spacing: {
@@ -44,13 +44,13 @@ interface ThemeConfig {
44
44
  md: string;
45
45
  lg: string;
46
46
  xl: string;
47
- '2xl': string;
47
+ "2xl": string;
48
48
  };
49
- components: {
50
- button: ComponentStyle;
51
- card: ComponentStyle;
52
- header: ComponentStyle;
53
- footer: ComponentStyle;
49
+ components?: {
50
+ button?: ComponentStyle;
51
+ card?: ComponentStyle;
52
+ header?: ComponentStyle;
53
+ footer?: ComponentStyle;
54
54
  };
55
55
  }
56
56
  interface ComponentStyle {
@@ -68,7 +68,7 @@ interface Theme extends ThemeConfig {
68
68
 
69
69
  interface ThemeContextType {
70
70
  theme: Theme;
71
- setTheme?: (theme: Theme) => void;
71
+ setTheme: (theme: Theme) => void;
72
72
  }
73
73
  interface ThemeProviderProps {
74
74
  theme: Theme;
package/dist/index.js CHANGED
@@ -40,8 +40,9 @@ module.exports = __toCommonJS(index_exports);
40
40
  var import_react = require("react");
41
41
  var import_jsx_runtime = require("react/jsx-runtime");
42
42
  var ThemeContext = (0, import_react.createContext)(void 0);
43
- var ThemeProvider = ({ theme, children }) => {
44
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeContext.Provider, { value: { theme }, children });
43
+ var ThemeProvider = ({ theme: initialTheme, children }) => {
44
+ const [theme, setTheme] = (0, import_react.useState)(initialTheme);
45
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeContext.Provider, { value: { theme, setTheme }, children });
45
46
  };
46
47
  var useTheme = () => {
47
48
  const context = (0, import_react.useContext)(ThemeContext);
@@ -85,80 +86,68 @@ var ThemeLoader = class {
85
86
  static getEmbeddedTheme(name) {
86
87
  const themes = {
87
88
  corporate: `
89
+ id: "corporate"
88
90
  name: "Corporate"
91
+ description: "A professional amber-toned corporate theme"
89
92
  colors:
90
- primary:
91
- 50: "#fef7ee"
92
- 100: "#fdedd3"
93
- 500: "#f59e0b"
94
- 600: "#d97706"
95
- 700: "#b45309"
96
- neutral:
97
- 50: "#f8fafc"
98
- 100: "#f1f5f9"
99
- 700: "#334155"
100
- 800: "#1e293b"
101
- 900: "#0f172a"
102
- text:
103
- primary: "#1f2937"
104
- secondary: "#6b7280"
105
- inverse: "#ffffff"
106
-
107
- spacing:
108
- section: "py-20"
109
- container: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"
110
-
93
+ primary: "#f59e0b"
94
+ secondary: "#334155"
95
+ accent: "#d97706"
96
+ background: "#f8fafc"
97
+ surface: "#ffffff"
98
+ text: "#1f2937"
99
+ textSecondary: "#6b7280"
111
100
  typography:
112
- hero: "text-4xl md:text-6xl font-bold"
113
- subtitle: "text-xl md:text-2xl"
114
-
115
- components:
116
- button:
117
- primary: "bg-amber-600 text-white hover:bg-amber-700 px-8 py-3 rounded-lg font-semibold"
118
- secondary: "text-amber-600 border border-amber-600 hover:bg-amber-50 px-8 py-3 rounded-lg font-semibold"
119
- header:
120
- background: "bg-white shadow-sm"
121
- border: "border-b border-gray-200"
122
- hero:
123
- background: "bg-gradient-to-br from-slate-900 to-slate-800"
101
+ fontFamily:
102
+ primary: "Roboto, sans-serif"
103
+ secondary: "Roboto, sans-serif"
104
+ scale:
105
+ xs: "0.75rem"
106
+ sm: "0.875rem"
107
+ base: "1rem"
108
+ lg: "1.125rem"
109
+ xl: "1.25rem"
110
+ 2xl: "1.5rem"
111
+ 3xl: "1.875rem"
112
+ spacing:
113
+ xs: "0.5rem"
114
+ sm: "0.75rem"
115
+ md: "1rem"
116
+ lg: "1.5rem"
117
+ xl: "2rem"
118
+ 2xl: "3rem"
124
119
  `,
125
120
  soft: `
121
+ id: "soft"
126
122
  name: "Soft"
123
+ description: "A gentle pink-toned soft theme"
127
124
  colors:
128
- primary:
129
- 50: "#fdf2f8"
130
- 100: "#fce7f3"
131
- 500: "#ec4899"
132
- 600: "#db2777"
133
- 700: "#be185d"
134
- neutral:
135
- 50: "#fefefe"
136
- 100: "#f9fafb"
137
- 700: "#6b7280"
138
- 800: "#4b5563"
139
- 900: "#374151"
140
- text:
141
- primary: "#374151"
142
- secondary: "#9ca3af"
143
- inverse: "#ffffff"
144
-
145
- spacing:
146
- section: "py-16"
147
- container: "max-w-6xl mx-auto px-6 sm:px-8 lg:px-10"
148
-
125
+ primary: "#ec4899"
126
+ secondary: "#6b7280"
127
+ accent: "#db2777"
128
+ background: "#f9fafb"
129
+ surface: "#ffffff"
130
+ text: "#374151"
131
+ textSecondary: "#9ca3af"
149
132
  typography:
150
- hero: "text-3xl md:text-5xl font-semibold"
151
- subtitle: "text-lg md:text-xl"
152
-
153
- components:
154
- button:
155
- primary: "bg-pink-600 text-white hover:bg-pink-700 px-6 py-2 rounded-full font-medium"
156
- secondary: "text-pink-600 border border-pink-600 hover:bg-pink-50 px-6 py-2 rounded-full font-medium"
157
- header:
158
- background: "bg-neutral-50 shadow-none"
159
- border: "border-b border-neutral-200"
160
- hero:
161
- background: "bg-gradient-to-br from-neutral-100 to-neutral-200"
133
+ fontFamily:
134
+ primary: "Roboto, sans-serif"
135
+ secondary: "Roboto, sans-serif"
136
+ scale:
137
+ xs: "0.75rem"
138
+ sm: "0.875rem"
139
+ base: "1rem"
140
+ lg: "1.125rem"
141
+ xl: "1.25rem"
142
+ 2xl: "1.5rem"
143
+ 3xl: "1.875rem"
144
+ spacing:
145
+ xs: "0.5rem"
146
+ sm: "0.75rem"
147
+ md: "1rem"
148
+ lg: "1.5rem"
149
+ xl: "2rem"
150
+ 2xl: "3rem"
162
151
  `
163
152
  };
164
153
  if (!themes[name]) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/ThemeProvider.tsx","../src/themeLoader.ts"],"sourcesContent":["export * from './types';\nexport * from './ThemeProvider';\nexport * from './themeLoader';\nexport type { ThemeConfig, Theme, ComponentStyle } from './types';","import React, { createContext, useContext, ReactNode } from 'react';\nimport { Theme } from './types';\n\ninterface ThemeContextType {\n theme: Theme;\n setTheme?: (theme: Theme) => void;\n}\n\nconst ThemeContext = createContext<ThemeContextType | undefined>(undefined);\n\ninterface ThemeProviderProps {\n theme: Theme;\n children: ReactNode;\n}\n\nexport const ThemeProvider: React.FC<ThemeProviderProps> = ({ theme, children }) => {\n return (\n <ThemeContext.Provider value={{ theme }}>\n {children}\n </ThemeContext.Provider>\n );\n};\n\nexport const useTheme = (): ThemeContextType => {\n const context = useContext(ThemeContext);\n if (!context) {\n throw new Error('useTheme must be used within a ThemeProvider');\n }\n return context;\n};","import * as yaml from 'js-yaml';\nimport { Theme } from './types';\n\nexport class ThemeLoader {\n private static themes: Map<string, Theme> = new Map();\n\n static loadThemeFromYaml(yamlContent: string): Theme {\n try {\n const theme = yaml.load(yamlContent) as Theme;\n this.themes.set(theme.name, theme);\n return theme;\n } catch (error) {\n throw new Error(`Failed to parse theme YAML: ${error}`);\n }\n }\n\n static loadThemeFromFile(themeName: string): Theme {\n // In a real implementation, this would load from the file system\n // For now, we'll embed the themes\n const themeData = this.getEmbeddedTheme(themeName);\n return this.loadThemeFromYaml(themeData);\n }\n\n static getTheme(name: string): Theme | undefined {\n return this.themes.get(name);\n }\n\n static getAllThemes(): Theme[] {\n return Array.from(this.themes.values());\n }\n\n static registerCustomTheme(theme: Theme): void {\n this.themes.set(theme.name, theme);\n console.log(`🎨 Registered custom theme: ${theme.name}`);\n }\n\n static loadCustomTheme(theme: Theme): Theme {\n this.registerCustomTheme(theme);\n return theme;\n }\n\n private static getEmbeddedTheme(name: string): string {\n const themes: Record<string, string> = {\n corporate: `\nname: \"Corporate\"\ncolors:\n primary:\n 50: \"#fef7ee\"\n 100: \"#fdedd3\"\n 500: \"#f59e0b\"\n 600: \"#d97706\"\n 700: \"#b45309\"\n neutral:\n 50: \"#f8fafc\"\n 100: \"#f1f5f9\"\n 700: \"#334155\"\n 800: \"#1e293b\"\n 900: \"#0f172a\"\n text:\n primary: \"#1f2937\"\n secondary: \"#6b7280\"\n inverse: \"#ffffff\"\n\nspacing:\n section: \"py-20\"\n container: \"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8\"\n\ntypography:\n hero: \"text-4xl md:text-6xl font-bold\"\n subtitle: \"text-xl md:text-2xl\"\n\ncomponents:\n button:\n primary: \"bg-amber-600 text-white hover:bg-amber-700 px-8 py-3 rounded-lg font-semibold\"\n secondary: \"text-amber-600 border border-amber-600 hover:bg-amber-50 px-8 py-3 rounded-lg font-semibold\"\n header:\n background: \"bg-white shadow-sm\"\n border: \"border-b border-gray-200\"\n hero:\n background: \"bg-gradient-to-br from-slate-900 to-slate-800\"\n`,\n soft: `\nname: \"Soft\"\ncolors:\n primary:\n 50: \"#fdf2f8\"\n 100: \"#fce7f3\"\n 500: \"#ec4899\"\n 600: \"#db2777\"\n 700: \"#be185d\"\n neutral:\n 50: \"#fefefe\"\n 100: \"#f9fafb\"\n 700: \"#6b7280\"\n 800: \"#4b5563\"\n 900: \"#374151\"\n text:\n primary: \"#374151\"\n secondary: \"#9ca3af\"\n inverse: \"#ffffff\"\n\nspacing:\n section: \"py-16\"\n container: \"max-w-6xl mx-auto px-6 sm:px-8 lg:px-10\"\n\ntypography:\n hero: \"text-3xl md:text-5xl font-semibold\"\n subtitle: \"text-lg md:text-xl\"\n\ncomponents:\n button:\n primary: \"bg-pink-600 text-white hover:bg-pink-700 px-6 py-2 rounded-full font-medium\"\n secondary: \"text-pink-600 border border-pink-600 hover:bg-pink-50 px-6 py-2 rounded-full font-medium\"\n header:\n background: \"bg-neutral-50 shadow-none\"\n border: \"border-b border-neutral-200\"\n hero:\n background: \"bg-gradient-to-br from-neutral-100 to-neutral-200\"\n`\n };\n\n if (!themes[name]) {\n throw new Error(`Theme '${name}' not found`);\n }\n\n return themes[name];\n }\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAA4D;AAiBxD;AATJ,IAAM,mBAAe,4BAA4C,MAAS;AAOnE,IAAM,gBAA8C,CAAC,EAAE,OAAO,SAAS,MAAM;AAClF,SACE,4CAAC,aAAa,UAAb,EAAsB,OAAO,EAAE,MAAM,GACnC,UACH;AAEJ;AAEO,IAAM,WAAW,MAAwB;AAC9C,QAAM,cAAU,yBAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,SAAO;AACT;;;AC7BA,WAAsB;AAGf,IAAM,cAAN,MAAkB;AAAA,EACvB,OAAe,SAA6B,oBAAI,IAAI;AAAA,EAEpD,OAAO,kBAAkB,aAA4B;AACnD,QAAI;AACF,YAAM,QAAa,UAAK,WAAW;AACnC,WAAK,OAAO,IAAI,MAAM,MAAM,KAAK;AACjC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,IAAI,MAAM,+BAA+B,KAAK,EAAE;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,OAAO,kBAAkB,WAA0B;AAGjD,UAAM,YAAY,KAAK,iBAAiB,SAAS;AACjD,WAAO,KAAK,kBAAkB,SAAS;AAAA,EACzC;AAAA,EAEA,OAAO,SAAS,MAAiC;AAC/C,WAAO,KAAK,OAAO,IAAI,IAAI;AAAA,EAC7B;AAAA,EAEA,OAAO,eAAwB;AAC7B,WAAO,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;AAAA,EACxC;AAAA,EAEA,OAAO,oBAAoB,OAAoB;AAC7C,SAAK,OAAO,IAAI,MAAM,MAAM,KAAK;AACjC,YAAQ,IAAI,sCAA+B,MAAM,IAAI,EAAE;AAAA,EACzD;AAAA,EAEA,OAAO,gBAAgB,OAAqB;AAC1C,SAAK,oBAAoB,KAAK;AAC9B,WAAO;AAAA,EACT;AAAA,EAEA,OAAe,iBAAiB,MAAsB;AACpD,UAAM,SAAiC;AAAA,MACrC,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAsCX,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAsCR;AAEA,QAAI,CAAC,OAAO,IAAI,GAAG;AACjB,YAAM,IAAI,MAAM,UAAU,IAAI,aAAa;AAAA,IAC7C;AAEA,WAAO,OAAO,IAAI;AAAA,EACpB;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/ThemeProvider.tsx","../src/themeLoader.ts"],"sourcesContent":["export * from './types';\nexport * from './ThemeProvider';\nexport * from './themeLoader';\nexport type { ThemeConfig, Theme, ComponentStyle } from './types';","import React, { createContext, useContext, useState, ReactNode } from 'react';\nimport { Theme } from './types';\n\ninterface ThemeContextType {\n theme: Theme;\n setTheme: (theme: Theme) => void;\n}\n\nconst ThemeContext = createContext<ThemeContextType | undefined>(undefined);\n\ninterface ThemeProviderProps {\n theme: Theme;\n children: ReactNode;\n}\n\nexport const ThemeProvider: React.FC<ThemeProviderProps> = ({ theme: initialTheme, children }) => {\n const [theme, setTheme] = useState<Theme>(initialTheme);\n return (\n <ThemeContext.Provider value={{ theme, setTheme }}>\n {children}\n </ThemeContext.Provider>\n );\n};\n\nexport const useTheme = (): ThemeContextType => {\n const context = useContext(ThemeContext);\n if (!context) {\n throw new Error('useTheme must be used within a ThemeProvider');\n }\n return context;\n};","import * as yaml from 'js-yaml';\nimport { Theme } from './types';\n\nexport class ThemeLoader {\n private static themes: Map<string, Theme> = new Map();\n\n static loadThemeFromYaml(yamlContent: string): Theme {\n try {\n const theme = yaml.load(yamlContent) as Theme;\n this.themes.set(theme.name, theme);\n return theme;\n } catch (error) {\n throw new Error(`Failed to parse theme YAML: ${error}`);\n }\n }\n\n static loadThemeFromFile(themeName: string): Theme {\n // In a real implementation, this would load from the file system\n // For now, we'll embed the themes\n const themeData = this.getEmbeddedTheme(themeName);\n return this.loadThemeFromYaml(themeData);\n }\n\n static getTheme(name: string): Theme | undefined {\n return this.themes.get(name);\n }\n\n static getAllThemes(): Theme[] {\n return Array.from(this.themes.values());\n }\n\n static registerCustomTheme(theme: Theme): void {\n this.themes.set(theme.name, theme);\n console.log(`🎨 Registered custom theme: ${theme.name}`);\n }\n\n static loadCustomTheme(theme: Theme): Theme {\n this.registerCustomTheme(theme);\n return theme;\n }\n\n private static getEmbeddedTheme(name: string): string {\n const themes: Record<string, string> = {\n corporate: `\nid: \"corporate\"\nname: \"Corporate\"\ndescription: \"A professional amber-toned corporate theme\"\ncolors:\n primary: \"#f59e0b\"\n secondary: \"#334155\"\n accent: \"#d97706\"\n background: \"#f8fafc\"\n surface: \"#ffffff\"\n text: \"#1f2937\"\n textSecondary: \"#6b7280\"\ntypography:\n fontFamily:\n primary: \"Roboto, sans-serif\"\n secondary: \"Roboto, sans-serif\"\n scale:\n xs: \"0.75rem\"\n sm: \"0.875rem\"\n base: \"1rem\"\n lg: \"1.125rem\"\n xl: \"1.25rem\"\n 2xl: \"1.5rem\"\n 3xl: \"1.875rem\"\nspacing:\n xs: \"0.5rem\"\n sm: \"0.75rem\"\n md: \"1rem\"\n lg: \"1.5rem\"\n xl: \"2rem\"\n 2xl: \"3rem\"\n`,\n soft: `\nid: \"soft\"\nname: \"Soft\"\ndescription: \"A gentle pink-toned soft theme\"\ncolors:\n primary: \"#ec4899\"\n secondary: \"#6b7280\"\n accent: \"#db2777\"\n background: \"#f9fafb\"\n surface: \"#ffffff\"\n text: \"#374151\"\n textSecondary: \"#9ca3af\"\ntypography:\n fontFamily:\n primary: \"Roboto, sans-serif\"\n secondary: \"Roboto, sans-serif\"\n scale:\n xs: \"0.75rem\"\n sm: \"0.875rem\"\n base: \"1rem\"\n lg: \"1.125rem\"\n xl: \"1.25rem\"\n 2xl: \"1.5rem\"\n 3xl: \"1.875rem\"\nspacing:\n xs: \"0.5rem\"\n sm: \"0.75rem\"\n md: \"1rem\"\n lg: \"1.5rem\"\n xl: \"2rem\"\n 2xl: \"3rem\"\n`\n };\n\n if (!themes[name]) {\n throw new Error(`Theme '${name}' not found`);\n }\n\n return themes[name];\n }\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAsE;AAkBlE;AAVJ,IAAM,mBAAe,4BAA4C,MAAS;AAOnE,IAAM,gBAA8C,CAAC,EAAE,OAAO,cAAc,SAAS,MAAM;AAChG,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAgB,YAAY;AACtD,SACE,4CAAC,aAAa,UAAb,EAAsB,OAAO,EAAE,OAAO,SAAS,GAC7C,UACH;AAEJ;AAEO,IAAM,WAAW,MAAwB;AAC9C,QAAM,cAAU,yBAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,SAAO;AACT;;;AC9BA,WAAsB;AAGf,IAAM,cAAN,MAAkB;AAAA,EACvB,OAAe,SAA6B,oBAAI,IAAI;AAAA,EAEpD,OAAO,kBAAkB,aAA4B;AACnD,QAAI;AACF,YAAM,QAAa,UAAK,WAAW;AACnC,WAAK,OAAO,IAAI,MAAM,MAAM,KAAK;AACjC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,IAAI,MAAM,+BAA+B,KAAK,EAAE;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,OAAO,kBAAkB,WAA0B;AAGjD,UAAM,YAAY,KAAK,iBAAiB,SAAS;AACjD,WAAO,KAAK,kBAAkB,SAAS;AAAA,EACzC;AAAA,EAEA,OAAO,SAAS,MAAiC;AAC/C,WAAO,KAAK,OAAO,IAAI,IAAI;AAAA,EAC7B;AAAA,EAEA,OAAO,eAAwB;AAC7B,WAAO,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;AAAA,EACxC;AAAA,EAEA,OAAO,oBAAoB,OAAoB;AAC7C,SAAK,OAAO,IAAI,MAAM,MAAM,KAAK;AACjC,YAAQ,IAAI,sCAA+B,MAAM,IAAI,EAAE;AAAA,EACzD;AAAA,EAEA,OAAO,gBAAgB,OAAqB;AAC1C,SAAK,oBAAoB,KAAK;AAC9B,WAAO;AAAA,EACT;AAAA,EAEA,OAAe,iBAAiB,MAAsB;AACpD,UAAM,SAAiC;AAAA,MACrC,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAgCX,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgCR;AAEA,QAAI,CAAC,OAAO,IAAI,GAAG;AACjB,YAAM,IAAI,MAAM,UAAU,IAAI,aAAa;AAAA,IAC7C;AAEA,WAAO,OAAO,IAAI;AAAA,EACpB;AACF;","names":[]}
package/dist/index.mjs CHANGED
@@ -1,9 +1,10 @@
1
1
  // src/ThemeProvider.tsx
2
- import { createContext, useContext } from "react";
2
+ import { createContext, useContext, useState } from "react";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  var ThemeContext = createContext(void 0);
5
- var ThemeProvider = ({ theme, children }) => {
6
- return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: { theme }, children });
5
+ var ThemeProvider = ({ theme: initialTheme, children }) => {
6
+ const [theme, setTheme] = useState(initialTheme);
7
+ return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: { theme, setTheme }, children });
7
8
  };
8
9
  var useTheme = () => {
9
10
  const context = useContext(ThemeContext);
@@ -47,80 +48,68 @@ var ThemeLoader = class {
47
48
  static getEmbeddedTheme(name) {
48
49
  const themes = {
49
50
  corporate: `
51
+ id: "corporate"
50
52
  name: "Corporate"
53
+ description: "A professional amber-toned corporate theme"
51
54
  colors:
52
- primary:
53
- 50: "#fef7ee"
54
- 100: "#fdedd3"
55
- 500: "#f59e0b"
56
- 600: "#d97706"
57
- 700: "#b45309"
58
- neutral:
59
- 50: "#f8fafc"
60
- 100: "#f1f5f9"
61
- 700: "#334155"
62
- 800: "#1e293b"
63
- 900: "#0f172a"
64
- text:
65
- primary: "#1f2937"
66
- secondary: "#6b7280"
67
- inverse: "#ffffff"
68
-
69
- spacing:
70
- section: "py-20"
71
- container: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"
72
-
55
+ primary: "#f59e0b"
56
+ secondary: "#334155"
57
+ accent: "#d97706"
58
+ background: "#f8fafc"
59
+ surface: "#ffffff"
60
+ text: "#1f2937"
61
+ textSecondary: "#6b7280"
73
62
  typography:
74
- hero: "text-4xl md:text-6xl font-bold"
75
- subtitle: "text-xl md:text-2xl"
76
-
77
- components:
78
- button:
79
- primary: "bg-amber-600 text-white hover:bg-amber-700 px-8 py-3 rounded-lg font-semibold"
80
- secondary: "text-amber-600 border border-amber-600 hover:bg-amber-50 px-8 py-3 rounded-lg font-semibold"
81
- header:
82
- background: "bg-white shadow-sm"
83
- border: "border-b border-gray-200"
84
- hero:
85
- background: "bg-gradient-to-br from-slate-900 to-slate-800"
63
+ fontFamily:
64
+ primary: "Roboto, sans-serif"
65
+ secondary: "Roboto, sans-serif"
66
+ scale:
67
+ xs: "0.75rem"
68
+ sm: "0.875rem"
69
+ base: "1rem"
70
+ lg: "1.125rem"
71
+ xl: "1.25rem"
72
+ 2xl: "1.5rem"
73
+ 3xl: "1.875rem"
74
+ spacing:
75
+ xs: "0.5rem"
76
+ sm: "0.75rem"
77
+ md: "1rem"
78
+ lg: "1.5rem"
79
+ xl: "2rem"
80
+ 2xl: "3rem"
86
81
  `,
87
82
  soft: `
83
+ id: "soft"
88
84
  name: "Soft"
85
+ description: "A gentle pink-toned soft theme"
89
86
  colors:
90
- primary:
91
- 50: "#fdf2f8"
92
- 100: "#fce7f3"
93
- 500: "#ec4899"
94
- 600: "#db2777"
95
- 700: "#be185d"
96
- neutral:
97
- 50: "#fefefe"
98
- 100: "#f9fafb"
99
- 700: "#6b7280"
100
- 800: "#4b5563"
101
- 900: "#374151"
102
- text:
103
- primary: "#374151"
104
- secondary: "#9ca3af"
105
- inverse: "#ffffff"
106
-
107
- spacing:
108
- section: "py-16"
109
- container: "max-w-6xl mx-auto px-6 sm:px-8 lg:px-10"
110
-
87
+ primary: "#ec4899"
88
+ secondary: "#6b7280"
89
+ accent: "#db2777"
90
+ background: "#f9fafb"
91
+ surface: "#ffffff"
92
+ text: "#374151"
93
+ textSecondary: "#9ca3af"
111
94
  typography:
112
- hero: "text-3xl md:text-5xl font-semibold"
113
- subtitle: "text-lg md:text-xl"
114
-
115
- components:
116
- button:
117
- primary: "bg-pink-600 text-white hover:bg-pink-700 px-6 py-2 rounded-full font-medium"
118
- secondary: "text-pink-600 border border-pink-600 hover:bg-pink-50 px-6 py-2 rounded-full font-medium"
119
- header:
120
- background: "bg-neutral-50 shadow-none"
121
- border: "border-b border-neutral-200"
122
- hero:
123
- background: "bg-gradient-to-br from-neutral-100 to-neutral-200"
95
+ fontFamily:
96
+ primary: "Roboto, sans-serif"
97
+ secondary: "Roboto, sans-serif"
98
+ scale:
99
+ xs: "0.75rem"
100
+ sm: "0.875rem"
101
+ base: "1rem"
102
+ lg: "1.125rem"
103
+ xl: "1.25rem"
104
+ 2xl: "1.5rem"
105
+ 3xl: "1.875rem"
106
+ spacing:
107
+ xs: "0.5rem"
108
+ sm: "0.75rem"
109
+ md: "1rem"
110
+ lg: "1.5rem"
111
+ xl: "2rem"
112
+ 2xl: "3rem"
124
113
  `
125
114
  };
126
115
  if (!themes[name]) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ThemeProvider.tsx","../src/themeLoader.ts"],"sourcesContent":["import React, { createContext, useContext, ReactNode } from 'react';\nimport { Theme } from './types';\n\ninterface ThemeContextType {\n theme: Theme;\n setTheme?: (theme: Theme) => void;\n}\n\nconst ThemeContext = createContext<ThemeContextType | undefined>(undefined);\n\ninterface ThemeProviderProps {\n theme: Theme;\n children: ReactNode;\n}\n\nexport const ThemeProvider: React.FC<ThemeProviderProps> = ({ theme, children }) => {\n return (\n <ThemeContext.Provider value={{ theme }}>\n {children}\n </ThemeContext.Provider>\n );\n};\n\nexport const useTheme = (): ThemeContextType => {\n const context = useContext(ThemeContext);\n if (!context) {\n throw new Error('useTheme must be used within a ThemeProvider');\n }\n return context;\n};","import * as yaml from 'js-yaml';\nimport { Theme } from './types';\n\nexport class ThemeLoader {\n private static themes: Map<string, Theme> = new Map();\n\n static loadThemeFromYaml(yamlContent: string): Theme {\n try {\n const theme = yaml.load(yamlContent) as Theme;\n this.themes.set(theme.name, theme);\n return theme;\n } catch (error) {\n throw new Error(`Failed to parse theme YAML: ${error}`);\n }\n }\n\n static loadThemeFromFile(themeName: string): Theme {\n // In a real implementation, this would load from the file system\n // For now, we'll embed the themes\n const themeData = this.getEmbeddedTheme(themeName);\n return this.loadThemeFromYaml(themeData);\n }\n\n static getTheme(name: string): Theme | undefined {\n return this.themes.get(name);\n }\n\n static getAllThemes(): Theme[] {\n return Array.from(this.themes.values());\n }\n\n static registerCustomTheme(theme: Theme): void {\n this.themes.set(theme.name, theme);\n console.log(`🎨 Registered custom theme: ${theme.name}`);\n }\n\n static loadCustomTheme(theme: Theme): Theme {\n this.registerCustomTheme(theme);\n return theme;\n }\n\n private static getEmbeddedTheme(name: string): string {\n const themes: Record<string, string> = {\n corporate: `\nname: \"Corporate\"\ncolors:\n primary:\n 50: \"#fef7ee\"\n 100: \"#fdedd3\"\n 500: \"#f59e0b\"\n 600: \"#d97706\"\n 700: \"#b45309\"\n neutral:\n 50: \"#f8fafc\"\n 100: \"#f1f5f9\"\n 700: \"#334155\"\n 800: \"#1e293b\"\n 900: \"#0f172a\"\n text:\n primary: \"#1f2937\"\n secondary: \"#6b7280\"\n inverse: \"#ffffff\"\n\nspacing:\n section: \"py-20\"\n container: \"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8\"\n\ntypography:\n hero: \"text-4xl md:text-6xl font-bold\"\n subtitle: \"text-xl md:text-2xl\"\n\ncomponents:\n button:\n primary: \"bg-amber-600 text-white hover:bg-amber-700 px-8 py-3 rounded-lg font-semibold\"\n secondary: \"text-amber-600 border border-amber-600 hover:bg-amber-50 px-8 py-3 rounded-lg font-semibold\"\n header:\n background: \"bg-white shadow-sm\"\n border: \"border-b border-gray-200\"\n hero:\n background: \"bg-gradient-to-br from-slate-900 to-slate-800\"\n`,\n soft: `\nname: \"Soft\"\ncolors:\n primary:\n 50: \"#fdf2f8\"\n 100: \"#fce7f3\"\n 500: \"#ec4899\"\n 600: \"#db2777\"\n 700: \"#be185d\"\n neutral:\n 50: \"#fefefe\"\n 100: \"#f9fafb\"\n 700: \"#6b7280\"\n 800: \"#4b5563\"\n 900: \"#374151\"\n text:\n primary: \"#374151\"\n secondary: \"#9ca3af\"\n inverse: \"#ffffff\"\n\nspacing:\n section: \"py-16\"\n container: \"max-w-6xl mx-auto px-6 sm:px-8 lg:px-10\"\n\ntypography:\n hero: \"text-3xl md:text-5xl font-semibold\"\n subtitle: \"text-lg md:text-xl\"\n\ncomponents:\n button:\n primary: \"bg-pink-600 text-white hover:bg-pink-700 px-6 py-2 rounded-full font-medium\"\n secondary: \"text-pink-600 border border-pink-600 hover:bg-pink-50 px-6 py-2 rounded-full font-medium\"\n header:\n background: \"bg-neutral-50 shadow-none\"\n border: \"border-b border-neutral-200\"\n hero:\n background: \"bg-gradient-to-br from-neutral-100 to-neutral-200\"\n`\n };\n\n if (!themes[name]) {\n throw new Error(`Theme '${name}' not found`);\n }\n\n return themes[name];\n }\n}"],"mappings":";AAAA,SAAgB,eAAe,kBAA6B;AAiBxD;AATJ,IAAM,eAAe,cAA4C,MAAS;AAOnE,IAAM,gBAA8C,CAAC,EAAE,OAAO,SAAS,MAAM;AAClF,SACE,oBAAC,aAAa,UAAb,EAAsB,OAAO,EAAE,MAAM,GACnC,UACH;AAEJ;AAEO,IAAM,WAAW,MAAwB;AAC9C,QAAM,UAAU,WAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,SAAO;AACT;;;AC7BA,YAAY,UAAU;AAGf,IAAM,cAAN,MAAkB;AAAA,EACvB,OAAe,SAA6B,oBAAI,IAAI;AAAA,EAEpD,OAAO,kBAAkB,aAA4B;AACnD,QAAI;AACF,YAAM,QAAa,UAAK,WAAW;AACnC,WAAK,OAAO,IAAI,MAAM,MAAM,KAAK;AACjC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,IAAI,MAAM,+BAA+B,KAAK,EAAE;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,OAAO,kBAAkB,WAA0B;AAGjD,UAAM,YAAY,KAAK,iBAAiB,SAAS;AACjD,WAAO,KAAK,kBAAkB,SAAS;AAAA,EACzC;AAAA,EAEA,OAAO,SAAS,MAAiC;AAC/C,WAAO,KAAK,OAAO,IAAI,IAAI;AAAA,EAC7B;AAAA,EAEA,OAAO,eAAwB;AAC7B,WAAO,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;AAAA,EACxC;AAAA,EAEA,OAAO,oBAAoB,OAAoB;AAC7C,SAAK,OAAO,IAAI,MAAM,MAAM,KAAK;AACjC,YAAQ,IAAI,sCAA+B,MAAM,IAAI,EAAE;AAAA,EACzD;AAAA,EAEA,OAAO,gBAAgB,OAAqB;AAC1C,SAAK,oBAAoB,KAAK;AAC9B,WAAO;AAAA,EACT;AAAA,EAEA,OAAe,iBAAiB,MAAsB;AACpD,UAAM,SAAiC;AAAA,MACrC,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAsCX,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAsCR;AAEA,QAAI,CAAC,OAAO,IAAI,GAAG;AACjB,YAAM,IAAI,MAAM,UAAU,IAAI,aAAa;AAAA,IAC7C;AAEA,WAAO,OAAO,IAAI;AAAA,EACpB;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/ThemeProvider.tsx","../src/themeLoader.ts"],"sourcesContent":["import React, { createContext, useContext, useState, ReactNode } from 'react';\nimport { Theme } from './types';\n\ninterface ThemeContextType {\n theme: Theme;\n setTheme: (theme: Theme) => void;\n}\n\nconst ThemeContext = createContext<ThemeContextType | undefined>(undefined);\n\ninterface ThemeProviderProps {\n theme: Theme;\n children: ReactNode;\n}\n\nexport const ThemeProvider: React.FC<ThemeProviderProps> = ({ theme: initialTheme, children }) => {\n const [theme, setTheme] = useState<Theme>(initialTheme);\n return (\n <ThemeContext.Provider value={{ theme, setTheme }}>\n {children}\n </ThemeContext.Provider>\n );\n};\n\nexport const useTheme = (): ThemeContextType => {\n const context = useContext(ThemeContext);\n if (!context) {\n throw new Error('useTheme must be used within a ThemeProvider');\n }\n return context;\n};","import * as yaml from 'js-yaml';\nimport { Theme } from './types';\n\nexport class ThemeLoader {\n private static themes: Map<string, Theme> = new Map();\n\n static loadThemeFromYaml(yamlContent: string): Theme {\n try {\n const theme = yaml.load(yamlContent) as Theme;\n this.themes.set(theme.name, theme);\n return theme;\n } catch (error) {\n throw new Error(`Failed to parse theme YAML: ${error}`);\n }\n }\n\n static loadThemeFromFile(themeName: string): Theme {\n // In a real implementation, this would load from the file system\n // For now, we'll embed the themes\n const themeData = this.getEmbeddedTheme(themeName);\n return this.loadThemeFromYaml(themeData);\n }\n\n static getTheme(name: string): Theme | undefined {\n return this.themes.get(name);\n }\n\n static getAllThemes(): Theme[] {\n return Array.from(this.themes.values());\n }\n\n static registerCustomTheme(theme: Theme): void {\n this.themes.set(theme.name, theme);\n console.log(`🎨 Registered custom theme: ${theme.name}`);\n }\n\n static loadCustomTheme(theme: Theme): Theme {\n this.registerCustomTheme(theme);\n return theme;\n }\n\n private static getEmbeddedTheme(name: string): string {\n const themes: Record<string, string> = {\n corporate: `\nid: \"corporate\"\nname: \"Corporate\"\ndescription: \"A professional amber-toned corporate theme\"\ncolors:\n primary: \"#f59e0b\"\n secondary: \"#334155\"\n accent: \"#d97706\"\n background: \"#f8fafc\"\n surface: \"#ffffff\"\n text: \"#1f2937\"\n textSecondary: \"#6b7280\"\ntypography:\n fontFamily:\n primary: \"Roboto, sans-serif\"\n secondary: \"Roboto, sans-serif\"\n scale:\n xs: \"0.75rem\"\n sm: \"0.875rem\"\n base: \"1rem\"\n lg: \"1.125rem\"\n xl: \"1.25rem\"\n 2xl: \"1.5rem\"\n 3xl: \"1.875rem\"\nspacing:\n xs: \"0.5rem\"\n sm: \"0.75rem\"\n md: \"1rem\"\n lg: \"1.5rem\"\n xl: \"2rem\"\n 2xl: \"3rem\"\n`,\n soft: `\nid: \"soft\"\nname: \"Soft\"\ndescription: \"A gentle pink-toned soft theme\"\ncolors:\n primary: \"#ec4899\"\n secondary: \"#6b7280\"\n accent: \"#db2777\"\n background: \"#f9fafb\"\n surface: \"#ffffff\"\n text: \"#374151\"\n textSecondary: \"#9ca3af\"\ntypography:\n fontFamily:\n primary: \"Roboto, sans-serif\"\n secondary: \"Roboto, sans-serif\"\n scale:\n xs: \"0.75rem\"\n sm: \"0.875rem\"\n base: \"1rem\"\n lg: \"1.125rem\"\n xl: \"1.25rem\"\n 2xl: \"1.5rem\"\n 3xl: \"1.875rem\"\nspacing:\n xs: \"0.5rem\"\n sm: \"0.75rem\"\n md: \"1rem\"\n lg: \"1.5rem\"\n xl: \"2rem\"\n 2xl: \"3rem\"\n`\n };\n\n if (!themes[name]) {\n throw new Error(`Theme '${name}' not found`);\n }\n\n return themes[name];\n }\n}"],"mappings":";AAAA,SAAgB,eAAe,YAAY,gBAA2B;AAkBlE;AAVJ,IAAM,eAAe,cAA4C,MAAS;AAOnE,IAAM,gBAA8C,CAAC,EAAE,OAAO,cAAc,SAAS,MAAM;AAChG,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAgB,YAAY;AACtD,SACE,oBAAC,aAAa,UAAb,EAAsB,OAAO,EAAE,OAAO,SAAS,GAC7C,UACH;AAEJ;AAEO,IAAM,WAAW,MAAwB;AAC9C,QAAM,UAAU,WAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACA,SAAO;AACT;;;AC9BA,YAAY,UAAU;AAGf,IAAM,cAAN,MAAkB;AAAA,EACvB,OAAe,SAA6B,oBAAI,IAAI;AAAA,EAEpD,OAAO,kBAAkB,aAA4B;AACnD,QAAI;AACF,YAAM,QAAa,UAAK,WAAW;AACnC,WAAK,OAAO,IAAI,MAAM,MAAM,KAAK;AACjC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,IAAI,MAAM,+BAA+B,KAAK,EAAE;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,OAAO,kBAAkB,WAA0B;AAGjD,UAAM,YAAY,KAAK,iBAAiB,SAAS;AACjD,WAAO,KAAK,kBAAkB,SAAS;AAAA,EACzC;AAAA,EAEA,OAAO,SAAS,MAAiC;AAC/C,WAAO,KAAK,OAAO,IAAI,IAAI;AAAA,EAC7B;AAAA,EAEA,OAAO,eAAwB;AAC7B,WAAO,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;AAAA,EACxC;AAAA,EAEA,OAAO,oBAAoB,OAAoB;AAC7C,SAAK,OAAO,IAAI,MAAM,MAAM,KAAK;AACjC,YAAQ,IAAI,sCAA+B,MAAM,IAAI,EAAE;AAAA,EACzD;AAAA,EAEA,OAAO,gBAAgB,OAAqB;AAC1C,SAAK,oBAAoB,KAAK;AAC9B,WAAO;AAAA,EACT;AAAA,EAEA,OAAe,iBAAiB,MAAsB;AACpD,UAAM,SAAiC;AAAA,MACrC,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAgCX,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgCR;AAEA,QAAI,CAAC,OAAO,IAAI,GAAG;AACjB,YAAM,IAAI,MAAM,UAAU,IAAI,aAAa;AAAA,IAC7C;AAEA,WAAO,OAAO,IAAI;AAAA,EACpB;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackwright/themes",
3
- "version": "0.3.1-alpha.5",
3
+ "version": "0.3.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -16,6 +16,8 @@
16
16
  },
17
17
  "scripts": {
18
18
  "build": "tsup",
19
- "dev": "tsup --watch"
19
+ "dev": "tsup --watch",
20
+ "test": "vitest",
21
+ "test:run": "vitest run"
20
22
  }
21
23
  }
@@ -1,9 +1,9 @@
1
- import React, { createContext, useContext, ReactNode } from 'react';
1
+ import React, { createContext, useContext, useState, ReactNode } from 'react';
2
2
  import { Theme } from './types';
3
3
 
4
4
  interface ThemeContextType {
5
5
  theme: Theme;
6
- setTheme?: (theme: Theme) => void;
6
+ setTheme: (theme: Theme) => void;
7
7
  }
8
8
 
9
9
  const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
@@ -13,9 +13,10 @@ interface ThemeProviderProps {
13
13
  children: ReactNode;
14
14
  }
15
15
 
16
- export const ThemeProvider: React.FC<ThemeProviderProps> = ({ theme, children }) => {
16
+ export const ThemeProvider: React.FC<ThemeProviderProps> = ({ theme: initialTheme, children }) => {
17
+ const [theme, setTheme] = useState<Theme>(initialTheme);
17
18
  return (
18
- <ThemeContext.Provider value={{ theme }}>
19
+ <ThemeContext.Provider value={{ theme, setTheme }}>
19
20
  {children}
20
21
  </ThemeContext.Provider>
21
22
  );
@@ -42,80 +42,68 @@ export class ThemeLoader {
42
42
  private static getEmbeddedTheme(name: string): string {
43
43
  const themes: Record<string, string> = {
44
44
  corporate: `
45
+ id: "corporate"
45
46
  name: "Corporate"
47
+ description: "A professional amber-toned corporate theme"
46
48
  colors:
47
- primary:
48
- 50: "#fef7ee"
49
- 100: "#fdedd3"
50
- 500: "#f59e0b"
51
- 600: "#d97706"
52
- 700: "#b45309"
53
- neutral:
54
- 50: "#f8fafc"
55
- 100: "#f1f5f9"
56
- 700: "#334155"
57
- 800: "#1e293b"
58
- 900: "#0f172a"
59
- text:
60
- primary: "#1f2937"
61
- secondary: "#6b7280"
62
- inverse: "#ffffff"
63
-
64
- spacing:
65
- section: "py-20"
66
- container: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"
67
-
49
+ primary: "#f59e0b"
50
+ secondary: "#334155"
51
+ accent: "#d97706"
52
+ background: "#f8fafc"
53
+ surface: "#ffffff"
54
+ text: "#1f2937"
55
+ textSecondary: "#6b7280"
68
56
  typography:
69
- hero: "text-4xl md:text-6xl font-bold"
70
- subtitle: "text-xl md:text-2xl"
71
-
72
- components:
73
- button:
74
- primary: "bg-amber-600 text-white hover:bg-amber-700 px-8 py-3 rounded-lg font-semibold"
75
- secondary: "text-amber-600 border border-amber-600 hover:bg-amber-50 px-8 py-3 rounded-lg font-semibold"
76
- header:
77
- background: "bg-white shadow-sm"
78
- border: "border-b border-gray-200"
79
- hero:
80
- background: "bg-gradient-to-br from-slate-900 to-slate-800"
57
+ fontFamily:
58
+ primary: "Roboto, sans-serif"
59
+ secondary: "Roboto, sans-serif"
60
+ scale:
61
+ xs: "0.75rem"
62
+ sm: "0.875rem"
63
+ base: "1rem"
64
+ lg: "1.125rem"
65
+ xl: "1.25rem"
66
+ 2xl: "1.5rem"
67
+ 3xl: "1.875rem"
68
+ spacing:
69
+ xs: "0.5rem"
70
+ sm: "0.75rem"
71
+ md: "1rem"
72
+ lg: "1.5rem"
73
+ xl: "2rem"
74
+ 2xl: "3rem"
81
75
  `,
82
76
  soft: `
77
+ id: "soft"
83
78
  name: "Soft"
79
+ description: "A gentle pink-toned soft theme"
84
80
  colors:
85
- primary:
86
- 50: "#fdf2f8"
87
- 100: "#fce7f3"
88
- 500: "#ec4899"
89
- 600: "#db2777"
90
- 700: "#be185d"
91
- neutral:
92
- 50: "#fefefe"
93
- 100: "#f9fafb"
94
- 700: "#6b7280"
95
- 800: "#4b5563"
96
- 900: "#374151"
97
- text:
98
- primary: "#374151"
99
- secondary: "#9ca3af"
100
- inverse: "#ffffff"
101
-
102
- spacing:
103
- section: "py-16"
104
- container: "max-w-6xl mx-auto px-6 sm:px-8 lg:px-10"
105
-
81
+ primary: "#ec4899"
82
+ secondary: "#6b7280"
83
+ accent: "#db2777"
84
+ background: "#f9fafb"
85
+ surface: "#ffffff"
86
+ text: "#374151"
87
+ textSecondary: "#9ca3af"
106
88
  typography:
107
- hero: "text-3xl md:text-5xl font-semibold"
108
- subtitle: "text-lg md:text-xl"
109
-
110
- components:
111
- button:
112
- primary: "bg-pink-600 text-white hover:bg-pink-700 px-6 py-2 rounded-full font-medium"
113
- secondary: "text-pink-600 border border-pink-600 hover:bg-pink-50 px-6 py-2 rounded-full font-medium"
114
- header:
115
- background: "bg-neutral-50 shadow-none"
116
- border: "border-b border-neutral-200"
117
- hero:
118
- background: "bg-gradient-to-br from-neutral-100 to-neutral-200"
89
+ fontFamily:
90
+ primary: "Roboto, sans-serif"
91
+ secondary: "Roboto, sans-serif"
92
+ scale:
93
+ xs: "0.75rem"
94
+ sm: "0.875rem"
95
+ base: "1rem"
96
+ lg: "1.125rem"
97
+ xl: "1.25rem"
98
+ 2xl: "1.5rem"
99
+ 3xl: "1.875rem"
100
+ spacing:
101
+ xs: "0.5rem"
102
+ sm: "0.75rem"
103
+ md: "1rem"
104
+ lg: "1.5rem"
105
+ xl: "2rem"
106
+ 2xl: "3rem"
119
107
  `
120
108
  };
121
109
 
package/src/types.ts CHANGED
@@ -1,66 +1,66 @@
1
1
  export interface ThemeConfig {
2
- id: string;
3
- name: string;
4
- description: string;
5
- colors: {
6
- primary: string;
7
- secondary: string;
8
- accent: string;
9
- background: string;
10
- surface: string;
11
- text: string;
12
- textSecondary: string;
13
- };
14
- backgroundImage?: {
15
- url: string;
16
- repeat?: 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat';
17
- size?: 'auto' | 'cover' | 'contain' | string;
18
- position?: string;
19
- attachment?: 'scroll' | 'fixed' | 'local';
20
- scale?: number;
21
- animation?: 'drift' | 'float' | 'shimmer' | 'shimmer-float' | 'none';
22
- customAnimation?: string;
23
- };
24
- typography: {
25
- fontFamily: {
26
- primary: string;
27
- secondary: string;
2
+ id: string;
3
+ name: string;
4
+ description: string;
5
+ colors: {
6
+ primary: string;
7
+ secondary: string;
8
+ accent: string;
9
+ background: string;
10
+ surface: string;
11
+ text: string;
12
+ textSecondary: string;
28
13
  };
29
- scale: {
30
- xs: string;
31
- sm: string;
32
- base: string;
33
- lg: string;
34
- xl: string;
35
- '2xl': string;
36
- '3xl': string;
14
+ backgroundImage?: {
15
+ url: string;
16
+ repeat?: "repeat" | "repeat-x" | "repeat-y" | "no-repeat";
17
+ size?: "auto" | "cover" | "contain" | string;
18
+ position?: string;
19
+ attachment?: "scroll" | "fixed" | "local";
20
+ scale?: number;
21
+ animation?: "drift" | "float" | "shimmer" | "shimmer-float" | "none";
22
+ customAnimation?: string;
23
+ };
24
+ typography: {
25
+ fontFamily: {
26
+ primary: string;
27
+ secondary: string;
28
+ };
29
+ scale: {
30
+ xs: string;
31
+ sm: string;
32
+ base: string;
33
+ lg: string;
34
+ xl: string;
35
+ "2xl": string;
36
+ "3xl": string;
37
+ };
38
+ };
39
+ spacing: {
40
+ xs: string;
41
+ sm: string;
42
+ md: string;
43
+ lg: string;
44
+ xl: string;
45
+ "2xl": string;
46
+ };
47
+ components?: {
48
+ button?: ComponentStyle;
49
+ card?: ComponentStyle;
50
+ header?: ComponentStyle;
51
+ footer?: ComponentStyle;
37
52
  };
38
- };
39
- spacing: {
40
- xs: string;
41
- sm: string;
42
- md: string;
43
- lg: string;
44
- xl: string;
45
- '2xl': string;
46
- };
47
- components: {
48
- button: ComponentStyle;
49
- card: ComponentStyle;
50
- header: ComponentStyle;
51
- footer: ComponentStyle;
52
- };
53
53
  }
54
54
 
55
55
  export interface ComponentStyle {
56
- base?: string;
57
- primary?: string;
58
- secondary?: string;
59
- outline?: string;
60
- shadow?: string;
61
- nav?: string;
62
- text?: string;
63
- [key: string]: string | undefined;
56
+ base?: string;
57
+ primary?: string;
58
+ secondary?: string;
59
+ outline?: string;
60
+ shadow?: string;
61
+ nav?: string;
62
+ text?: string;
63
+ [key: string]: string | undefined;
64
64
  }
65
65
 
66
- export interface Theme extends ThemeConfig {}
66
+ export interface Theme extends ThemeConfig {}
package/test/setup.ts ADDED
@@ -0,0 +1 @@
1
+ // Vitest setup for @stackwright/themes
@@ -0,0 +1,174 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { ThemeLoader } from '../src/themeLoader';
3
+ import type { Theme } from '../src/types';
4
+
5
+ // The ThemeLoader uses a static Map, so we need to be careful about state
6
+ // leaking between tests. We work around this by using unique theme names.
7
+
8
+ const makeCustomTheme = (overrides: Partial<Theme> = {}): Theme => ({
9
+ id: 'test-theme',
10
+ name: 'Test Theme',
11
+ description: 'A theme for testing',
12
+ colors: {
13
+ primary: '#aabbcc',
14
+ secondary: '#112233',
15
+ accent: '#ccbbaa',
16
+ background: '#ffffff',
17
+ surface: '#f0f0f0',
18
+ text: '#000000',
19
+ textSecondary: '#666666',
20
+ },
21
+ typography: {
22
+ fontFamily: { primary: 'Arial, sans-serif', secondary: 'Georgia, serif' },
23
+ scale: {
24
+ xs: '0.75rem', sm: '0.875rem', base: '1rem',
25
+ lg: '1.125rem', xl: '1.25rem', '2xl': '1.5rem', '3xl': '1.875rem',
26
+ },
27
+ },
28
+ spacing: {
29
+ xs: '0.5rem', sm: '0.75rem', md: '1rem',
30
+ lg: '1.5rem', xl: '2rem', '2xl': '3rem',
31
+ },
32
+ ...overrides,
33
+ });
34
+
35
+ describe('ThemeLoader.loadThemeFromFile', () => {
36
+ it('loads the corporate theme and returns a valid ThemeConfig', () => {
37
+ const theme = ThemeLoader.loadThemeFromFile('corporate');
38
+ expect(theme).toBeDefined();
39
+ expect(theme.name).toBe('Corporate');
40
+ expect(theme.id).toBe('corporate');
41
+ });
42
+
43
+ it('corporate theme has flat hex string colors (not nested objects)', () => {
44
+ const theme = ThemeLoader.loadThemeFromFile('corporate');
45
+ expect(typeof theme.colors.primary).toBe('string');
46
+ expect(theme.colors.primary).toMatch(/^#[0-9a-fA-F]{6}$/);
47
+ expect(typeof theme.colors.secondary).toBe('string');
48
+ expect(typeof theme.colors.background).toBe('string');
49
+ expect(typeof theme.colors.surface).toBe('string');
50
+ expect(typeof theme.colors.text).toBe('string');
51
+ expect(typeof theme.colors.textSecondary).toBe('string');
52
+ });
53
+
54
+ it('loads the soft theme and returns a valid ThemeConfig', () => {
55
+ const theme = ThemeLoader.loadThemeFromFile('soft');
56
+ expect(theme).toBeDefined();
57
+ expect(theme.name).toBe('Soft');
58
+ expect(theme.id).toBe('soft');
59
+ });
60
+
61
+ it('soft theme has flat hex string colors', () => {
62
+ const theme = ThemeLoader.loadThemeFromFile('soft');
63
+ expect(typeof theme.colors.primary).toBe('string');
64
+ expect(theme.colors.primary).toMatch(/^#[0-9a-fA-F]{6}$/);
65
+ });
66
+
67
+ it('throws for an unknown theme name', () => {
68
+ expect(() => ThemeLoader.loadThemeFromFile('nonexistent')).toThrow(
69
+ "Theme 'nonexistent' not found"
70
+ );
71
+ });
72
+
73
+ it('loaded themes have required typography and spacing fields', () => {
74
+ const theme = ThemeLoader.loadThemeFromFile('corporate');
75
+ expect(theme.typography).toBeDefined();
76
+ expect(theme.typography.fontFamily.primary).toBeTruthy();
77
+ expect(theme.spacing).toBeDefined();
78
+ expect(theme.spacing.md).toBeTruthy();
79
+ });
80
+ });
81
+
82
+ describe('ThemeLoader.loadThemeFromYaml', () => {
83
+ it('parses valid YAML and returns a theme', () => {
84
+ const yaml = `
85
+ id: "yaml-test"
86
+ name: "YAML Test"
87
+ description: "Parsed from YAML"
88
+ colors:
89
+ primary: "#ff0000"
90
+ secondary: "#00ff00"
91
+ accent: "#0000ff"
92
+ background: "#ffffff"
93
+ surface: "#eeeeee"
94
+ text: "#111111"
95
+ textSecondary: "#555555"
96
+ typography:
97
+ fontFamily:
98
+ primary: "Roboto, sans-serif"
99
+ secondary: "Roboto, sans-serif"
100
+ scale:
101
+ xs: "0.75rem"
102
+ sm: "0.875rem"
103
+ base: "1rem"
104
+ lg: "1.125rem"
105
+ xl: "1.25rem"
106
+ 2xl: "1.5rem"
107
+ 3xl: "1.875rem"
108
+ spacing:
109
+ xs: "0.5rem"
110
+ sm: "0.75rem"
111
+ md: "1rem"
112
+ lg: "1.5rem"
113
+ xl: "2rem"
114
+ 2xl: "3rem"
115
+ `;
116
+ const theme = ThemeLoader.loadThemeFromYaml(yaml);
117
+ expect(theme.name).toBe('YAML Test');
118
+ expect(theme.colors.primary).toBe('#ff0000');
119
+ });
120
+
121
+ it('throws for invalid YAML syntax', () => {
122
+ expect(() =>
123
+ ThemeLoader.loadThemeFromYaml('{ invalid: yaml: content: :')
124
+ ).toThrow('Failed to parse theme YAML');
125
+ });
126
+ });
127
+
128
+ describe('ThemeLoader.registerCustomTheme / getTheme', () => {
129
+ it('registers a custom theme and retrieves it by name', () => {
130
+ const custom = makeCustomTheme({ name: 'My Custom Theme A' });
131
+ ThemeLoader.registerCustomTheme(custom);
132
+ const retrieved = ThemeLoader.getTheme('My Custom Theme A');
133
+ expect(retrieved).toBeDefined();
134
+ expect(retrieved?.colors.primary).toBe('#aabbcc');
135
+ });
136
+
137
+ it('getTheme returns undefined for an unregistered name', () => {
138
+ expect(ThemeLoader.getTheme('__does_not_exist__')).toBeUndefined();
139
+ });
140
+
141
+ it('overwriting a theme by name replaces it', () => {
142
+ const v1 = makeCustomTheme({ name: 'Overwrite Test', colors: { ...makeCustomTheme().colors, primary: '#111111' } });
143
+ const v2 = makeCustomTheme({ name: 'Overwrite Test', colors: { ...makeCustomTheme().colors, primary: '#222222' } });
144
+ ThemeLoader.registerCustomTheme(v1);
145
+ ThemeLoader.registerCustomTheme(v2);
146
+ expect(ThemeLoader.getTheme('Overwrite Test')?.colors.primary).toBe('#222222');
147
+ });
148
+ });
149
+
150
+ describe('ThemeLoader.loadCustomTheme', () => {
151
+ it('registers the theme and returns it', () => {
152
+ const custom = makeCustomTheme({ name: 'LoadCustom Test' });
153
+ const returned = ThemeLoader.loadCustomTheme(custom);
154
+ expect(returned).toBe(custom);
155
+ expect(ThemeLoader.getTheme('LoadCustom Test')).toBeDefined();
156
+ });
157
+ });
158
+
159
+ describe('ThemeLoader.getAllThemes', () => {
160
+ it('returns an array (may include themes registered by other tests)', () => {
161
+ // Load a known theme to ensure at least one is present
162
+ ThemeLoader.loadThemeFromFile('corporate');
163
+ const all = ThemeLoader.getAllThemes();
164
+ expect(Array.isArray(all)).toBe(true);
165
+ expect(all.length).toBeGreaterThan(0);
166
+ });
167
+
168
+ it('includes a custom theme after registration', () => {
169
+ const uniqueName = `AllThemes-${Date.now()}`;
170
+ ThemeLoader.registerCustomTheme(makeCustomTheme({ name: uniqueName }));
171
+ const names = ThemeLoader.getAllThemes().map(t => t.name);
172
+ expect(names).toContain(uniqueName);
173
+ });
174
+ });
package/tsconfig.json CHANGED
@@ -1,23 +1,8 @@
1
1
  {
2
+ "extends": "../tsconfig.base.json",
2
3
  "compilerOptions": {
3
- "target": "es2022",
4
- "lib": ["dom", "dom.iterable", "es6"],
5
- "allowJs": true,
6
- "skipLibCheck": true,
7
- "esModuleInterop": true,
8
- "allowSyntheticDefaultImports": true,
9
- "strict": true,
10
- "forceConsistentCasingInFileNames": true,
11
- "moduleResolution": "node",
12
- "resolveJsonModule": true,
13
- "isolatedModules": true,
14
- "noEmit": false,
15
- "jsx": "react-jsx",
16
- "module": "commonjs",
17
4
  "outDir": "./dist",
18
- "rootDir": "./src",
19
- "declaration": true,
20
- "declarationMap": true
5
+ "rootDir": "./src"
21
6
  },
22
7
  "include": [
23
8
  "src/**/*"
File without changes