@tailwind-styled/theme 2.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.
package/dist/index.cjs ADDED
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ThemeRegistry: () => ThemeRegistry,
24
+ compileDesignTokens: () => compileDesignTokens,
25
+ createMultiTheme: () => createMultiTheme,
26
+ createTheme: () => createTheme,
27
+ defineThemeContract: () => defineThemeContract
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+ function defineThemeContract(shape) {
31
+ const vars = {};
32
+ for (const group in shape) {
33
+ ;
34
+ vars[group] = {};
35
+ for (const token in shape[group]) {
36
+ ;
37
+ vars[group][token] = `var(--${group}-${token})`;
38
+ }
39
+ }
40
+ return { _contract: shape, _vars: vars };
41
+ }
42
+ function createTheme(contract, name, values, asRoot = false) {
43
+ const flatVars = {};
44
+ const cssLines = [];
45
+ for (const group in values) {
46
+ for (const token in values[group]) {
47
+ const varName = `--${group}-${token}`;
48
+ const value = values[group][token];
49
+ flatVars[varName] = value;
50
+ cssLines.push(` ${varName}: ${value};`);
51
+ }
52
+ }
53
+ const selector = asRoot ? ":root" : `[data-theme="${name}"]`;
54
+ const css = `${selector} {
55
+ ${cssLines.join("\n")}
56
+ }`;
57
+ return {
58
+ name,
59
+ contract,
60
+ values,
61
+ css,
62
+ vars: flatVars,
63
+ selector
64
+ };
65
+ }
66
+ var ThemeRegistry = class {
67
+ constructor() {
68
+ this.themes = /* @__PURE__ */ new Map();
69
+ this.defaultTheme = null;
70
+ }
71
+ /** Register a theme */
72
+ register(theme, isDefault = false) {
73
+ this.themes.set(theme.name, theme);
74
+ if (isDefault || !this.defaultTheme) {
75
+ this.defaultTheme = theme.name;
76
+ }
77
+ return this;
78
+ }
79
+ /** Get a theme by name */
80
+ get(name) {
81
+ return this.themes.get(name);
82
+ }
83
+ /** Get all theme names */
84
+ names() {
85
+ return Array.from(this.themes.keys());
86
+ }
87
+ /**
88
+ * Generate combined CSS for all themes.
89
+ * Inject into <head> or a .css file.
90
+ *
91
+ * @example
92
+ * // In globals.css or layout.tsx
93
+ * const css = registry.generateCss()
94
+ */
95
+ generateCss() {
96
+ return Array.from(this.themes.values()).map((t) => t.css).join("\n\n");
97
+ }
98
+ /**
99
+ * Get the CSS for a specific theme only.
100
+ */
101
+ getThemeCss(name) {
102
+ var _a, _b;
103
+ return (_b = (_a = this.themes.get(name)) == null ? void 0 : _a.css) != null ? _b : null;
104
+ }
105
+ /**
106
+ * Inject all theme CSS into document <head> (browser only).
107
+ * Call once on app init.
108
+ */
109
+ inject(styleId = "__tw_themes") {
110
+ if (typeof document === "undefined") return;
111
+ let style = document.getElementById(styleId);
112
+ if (!style) {
113
+ style = document.createElement("style");
114
+ style.id = styleId;
115
+ document.head.appendChild(style);
116
+ }
117
+ style.textContent = this.generateCss();
118
+ }
119
+ /**
120
+ * Switch active theme by setting data-theme on <html>.
121
+ */
122
+ apply(name, target = document.documentElement) {
123
+ if (typeof document === "undefined") return;
124
+ if (!this.themes.has(name)) {
125
+ console.warn(`[tailwind-styled-v4] Theme "${name}" not registered.`);
126
+ return;
127
+ }
128
+ target.dataset.theme = name;
129
+ }
130
+ /**
131
+ * Get current active theme name from data-theme attribute.
132
+ */
133
+ current(target = document.documentElement) {
134
+ var _a;
135
+ if (typeof document === "undefined") return this.defaultTheme;
136
+ return (_a = target.dataset.theme) != null ? _a : this.defaultTheme;
137
+ }
138
+ };
139
+ function createMultiTheme(config) {
140
+ var _a;
141
+ const registry = new ThemeRegistry();
142
+ const light = createTheme(config.contract, "light", config.light, true);
143
+ const dark = createTheme(config.contract, "dark", config.dark, false);
144
+ registry.register(light, true);
145
+ registry.register(dark);
146
+ for (const [name, values] of Object.entries((_a = config.extras) != null ? _a : {})) {
147
+ registry.register(createTheme(config.contract, name, values));
148
+ }
149
+ return {
150
+ registry,
151
+ vars: config.contract._vars,
152
+ light,
153
+ dark
154
+ };
155
+ }
156
+ function compileDesignTokens(tokens, prefix = "") {
157
+ const vars = [];
158
+ function flatten(obj, path) {
159
+ for (const [key, value] of Object.entries(obj)) {
160
+ const varPath = path ? `${path}-${key}` : key;
161
+ if (typeof value === "string") {
162
+ vars.push(` --${varPath}: ${value};`);
163
+ } else {
164
+ flatten(value, varPath);
165
+ }
166
+ }
167
+ }
168
+ flatten(tokens, prefix);
169
+ return `:root {
170
+ ${vars.join("\n")}
171
+ }`;
172
+ }
173
+ // Annotate the CommonJS export names for ESM import in node:
174
+ 0 && (module.exports = {
175
+ ThemeRegistry,
176
+ compileDesignTokens,
177
+ createMultiTheme,
178
+ createTheme,
179
+ defineThemeContract
180
+ });
@@ -0,0 +1,181 @@
1
+ /**
2
+ * tailwind-styled-v4 — Multi-Theme Engine
3
+ *
4
+ * Enterprise-grade theming. Support light/dark/brand themes dengan
5
+ * CSS variables. Zero runtime overhead — themes di-resolve via CSS.
6
+ *
7
+ * Fitur:
8
+ * - Multiple named themes (light, dark, brand, high-contrast)
9
+ * - CSS variable output (Tailwind v4 compatible)
10
+ * - Theme contract (TypeScript-safe — missing tokens = TS error)
11
+ * - Per-component theme override
12
+ * - White-label ready
13
+ *
14
+ * @example
15
+ * // 1. Define contract
16
+ * const contract = defineThemeContract({
17
+ * colors: { bg: "", fg: "", primary: "", muted: "" },
18
+ * font: { sans: "", mono: "" },
19
+ * })
20
+ *
21
+ * // 2. Create themes
22
+ * const lightTheme = createTheme(contract, "light", {
23
+ * colors: { bg: "#ffffff", fg: "#09090b", primary: "#3b82f6", muted: "#71717a" },
24
+ * font: { sans: "InterVariable, sans-serif", mono: "JetBrains Mono, monospace" },
25
+ * })
26
+ *
27
+ * const darkTheme = createTheme(contract, "dark", {
28
+ * colors: { bg: "#09090b", fg: "#fafafa", primary: "#60a5fa", muted: "#a1a1aa" },
29
+ * font: { sans: "InterVariable, sans-serif", mono: "JetBrains Mono, monospace" },
30
+ * })
31
+ *
32
+ * // 3. Use tokens in components
33
+ * const Card = tw.div`bg-[var(--colors-bg)] text-[var(--colors-fg)] p-6`
34
+ *
35
+ * // 4. Apply in layout
36
+ * // <html data-theme="dark"> or inject CSS
37
+ */
38
+ type TokenMap = Record<string, Record<string, string>>;
39
+ interface ThemeContract<T extends TokenMap> {
40
+ _contract: T;
41
+ _vars: ThemeVars<T>;
42
+ }
43
+ type ThemeVars<T extends TokenMap> = {
44
+ [Group in keyof T]: {
45
+ [Token in keyof T[Group]]: string;
46
+ };
47
+ };
48
+ interface Theme<T extends TokenMap> {
49
+ name: string;
50
+ contract: ThemeContract<T>;
51
+ values: T;
52
+ /** CSS string to inject (`:root` or `[data-theme="name"]`) */
53
+ css: string;
54
+ /** CSS variables as a flat record */
55
+ vars: Record<string, string>;
56
+ /** Apply this theme to an element via data attribute */
57
+ selector: string;
58
+ }
59
+ /**
60
+ * Define the shape of your theme. All themes must satisfy this contract.
61
+ * Returns typed CSS variable references for use in tw components.
62
+ *
63
+ * @example
64
+ * const contract = defineThemeContract({
65
+ * colors: { bg: "", fg: "", primary: "" },
66
+ * font: { sans: "" },
67
+ * })
68
+ *
69
+ * // Use in components:
70
+ * const Card = tw.div`bg-[${contract._vars.colors.bg}]`
71
+ * // → tw.div`bg-[var(--colors-bg)]`
72
+ */
73
+ declare function defineThemeContract<T extends TokenMap>(shape: T): ThemeContract<T>;
74
+ /**
75
+ * Create a typed theme that satisfies a contract.
76
+ *
77
+ * @param contract - Theme contract from defineThemeContract()
78
+ * @param name - Theme name ("light", "dark", "brand", etc.)
79
+ * @param values - Token values (TypeScript enforces completeness)
80
+ * @param asRoot - If true, use :root selector. Default: false (uses [data-theme])
81
+ */
82
+ declare function createTheme<T extends TokenMap>(contract: ThemeContract<T>, name: string, values: T, asRoot?: boolean): Theme<T>;
83
+ declare class ThemeRegistry {
84
+ private themes;
85
+ private defaultTheme;
86
+ /** Register a theme */
87
+ register<T extends TokenMap>(theme: Theme<T>, isDefault?: boolean): this;
88
+ /** Get a theme by name */
89
+ get(name: string): Theme<any> | undefined;
90
+ /** Get all theme names */
91
+ names(): string[];
92
+ /**
93
+ * Generate combined CSS for all themes.
94
+ * Inject into <head> or a .css file.
95
+ *
96
+ * @example
97
+ * // In globals.css or layout.tsx
98
+ * const css = registry.generateCss()
99
+ */
100
+ generateCss(): string;
101
+ /**
102
+ * Get the CSS for a specific theme only.
103
+ */
104
+ getThemeCss(name: string): string | null;
105
+ /**
106
+ * Inject all theme CSS into document <head> (browser only).
107
+ * Call once on app init.
108
+ */
109
+ inject(styleId?: string): void;
110
+ /**
111
+ * Switch active theme by setting data-theme on <html>.
112
+ */
113
+ apply(name: string, target?: HTMLElement): void;
114
+ /**
115
+ * Get current active theme name from data-theme attribute.
116
+ */
117
+ current(target?: HTMLElement): string | null;
118
+ }
119
+ interface MultiThemeConfig<T extends TokenMap> {
120
+ contract: ThemeContract<T>;
121
+ light: T;
122
+ dark: T;
123
+ /** Additional named themes (brand, high-contrast, etc.) */
124
+ extras?: Record<string, T>;
125
+ }
126
+ /**
127
+ * Create a ThemeRegistry with light/dark + optional extras in one call.
128
+ *
129
+ * @example
130
+ * const { registry, vars } = createMultiTheme({
131
+ * contract: defineThemeContract({
132
+ * colors: { bg: "", fg: "", primary: "", border: "" }
133
+ * }),
134
+ * light: {
135
+ * colors: { bg: "#fff", fg: "#09090b", primary: "#3b82f6", border: "#e5e7eb" }
136
+ * },
137
+ * dark: {
138
+ * colors: { bg: "#09090b", fg: "#fafafa", primary: "#60a5fa", border: "#27272a" }
139
+ * },
140
+ * })
141
+ *
142
+ * // Inject CSS:
143
+ * registry.inject()
144
+ *
145
+ * // Use tokens in components:
146
+ * const Card = tw.div`bg-[${vars.colors.bg}] text-[${vars.colors.fg}]`
147
+ */
148
+ declare function createMultiTheme<T extends TokenMap>(config: MultiThemeConfig<T>): {
149
+ registry: ThemeRegistry;
150
+ vars: ThemeVars<T>;
151
+ light: Theme<T>;
152
+ dark: Theme<T>;
153
+ };
154
+ interface DesignTokens {
155
+ [path: string]: string | DesignTokens;
156
+ }
157
+ /**
158
+ * Flatten nested design token object into CSS variables.
159
+ * Supports Figma-style nested tokens.
160
+ *
161
+ * @example
162
+ * compileDesignTokens({
163
+ * color: {
164
+ * brand: { primary: "#3b82f6", secondary: "#6366f1" },
165
+ * neutral: { 50: "#fafafa", 900: "#09090b" }
166
+ * },
167
+ * spacing: { base: "4px", lg: "16px" }
168
+ * })
169
+ * →
170
+ * :root {
171
+ * --color-brand-primary: #3b82f6;
172
+ * --color-brand-secondary: #6366f1;
173
+ * --color-neutral-50: #fafafa;
174
+ * --color-neutral-900: #09090b;
175
+ * --spacing-base: 4px;
176
+ * --spacing-lg: 16px;
177
+ * }
178
+ */
179
+ declare function compileDesignTokens(tokens: DesignTokens, prefix?: string): string;
180
+
181
+ export { type DesignTokens, type MultiThemeConfig, type Theme, type ThemeContract, ThemeRegistry, type ThemeVars, type TokenMap, compileDesignTokens, createMultiTheme, createTheme, defineThemeContract };
@@ -0,0 +1,181 @@
1
+ /**
2
+ * tailwind-styled-v4 — Multi-Theme Engine
3
+ *
4
+ * Enterprise-grade theming. Support light/dark/brand themes dengan
5
+ * CSS variables. Zero runtime overhead — themes di-resolve via CSS.
6
+ *
7
+ * Fitur:
8
+ * - Multiple named themes (light, dark, brand, high-contrast)
9
+ * - CSS variable output (Tailwind v4 compatible)
10
+ * - Theme contract (TypeScript-safe — missing tokens = TS error)
11
+ * - Per-component theme override
12
+ * - White-label ready
13
+ *
14
+ * @example
15
+ * // 1. Define contract
16
+ * const contract = defineThemeContract({
17
+ * colors: { bg: "", fg: "", primary: "", muted: "" },
18
+ * font: { sans: "", mono: "" },
19
+ * })
20
+ *
21
+ * // 2. Create themes
22
+ * const lightTheme = createTheme(contract, "light", {
23
+ * colors: { bg: "#ffffff", fg: "#09090b", primary: "#3b82f6", muted: "#71717a" },
24
+ * font: { sans: "InterVariable, sans-serif", mono: "JetBrains Mono, monospace" },
25
+ * })
26
+ *
27
+ * const darkTheme = createTheme(contract, "dark", {
28
+ * colors: { bg: "#09090b", fg: "#fafafa", primary: "#60a5fa", muted: "#a1a1aa" },
29
+ * font: { sans: "InterVariable, sans-serif", mono: "JetBrains Mono, monospace" },
30
+ * })
31
+ *
32
+ * // 3. Use tokens in components
33
+ * const Card = tw.div`bg-[var(--colors-bg)] text-[var(--colors-fg)] p-6`
34
+ *
35
+ * // 4. Apply in layout
36
+ * // <html data-theme="dark"> or inject CSS
37
+ */
38
+ type TokenMap = Record<string, Record<string, string>>;
39
+ interface ThemeContract<T extends TokenMap> {
40
+ _contract: T;
41
+ _vars: ThemeVars<T>;
42
+ }
43
+ type ThemeVars<T extends TokenMap> = {
44
+ [Group in keyof T]: {
45
+ [Token in keyof T[Group]]: string;
46
+ };
47
+ };
48
+ interface Theme<T extends TokenMap> {
49
+ name: string;
50
+ contract: ThemeContract<T>;
51
+ values: T;
52
+ /** CSS string to inject (`:root` or `[data-theme="name"]`) */
53
+ css: string;
54
+ /** CSS variables as a flat record */
55
+ vars: Record<string, string>;
56
+ /** Apply this theme to an element via data attribute */
57
+ selector: string;
58
+ }
59
+ /**
60
+ * Define the shape of your theme. All themes must satisfy this contract.
61
+ * Returns typed CSS variable references for use in tw components.
62
+ *
63
+ * @example
64
+ * const contract = defineThemeContract({
65
+ * colors: { bg: "", fg: "", primary: "" },
66
+ * font: { sans: "" },
67
+ * })
68
+ *
69
+ * // Use in components:
70
+ * const Card = tw.div`bg-[${contract._vars.colors.bg}]`
71
+ * // → tw.div`bg-[var(--colors-bg)]`
72
+ */
73
+ declare function defineThemeContract<T extends TokenMap>(shape: T): ThemeContract<T>;
74
+ /**
75
+ * Create a typed theme that satisfies a contract.
76
+ *
77
+ * @param contract - Theme contract from defineThemeContract()
78
+ * @param name - Theme name ("light", "dark", "brand", etc.)
79
+ * @param values - Token values (TypeScript enforces completeness)
80
+ * @param asRoot - If true, use :root selector. Default: false (uses [data-theme])
81
+ */
82
+ declare function createTheme<T extends TokenMap>(contract: ThemeContract<T>, name: string, values: T, asRoot?: boolean): Theme<T>;
83
+ declare class ThemeRegistry {
84
+ private themes;
85
+ private defaultTheme;
86
+ /** Register a theme */
87
+ register<T extends TokenMap>(theme: Theme<T>, isDefault?: boolean): this;
88
+ /** Get a theme by name */
89
+ get(name: string): Theme<any> | undefined;
90
+ /** Get all theme names */
91
+ names(): string[];
92
+ /**
93
+ * Generate combined CSS for all themes.
94
+ * Inject into <head> or a .css file.
95
+ *
96
+ * @example
97
+ * // In globals.css or layout.tsx
98
+ * const css = registry.generateCss()
99
+ */
100
+ generateCss(): string;
101
+ /**
102
+ * Get the CSS for a specific theme only.
103
+ */
104
+ getThemeCss(name: string): string | null;
105
+ /**
106
+ * Inject all theme CSS into document <head> (browser only).
107
+ * Call once on app init.
108
+ */
109
+ inject(styleId?: string): void;
110
+ /**
111
+ * Switch active theme by setting data-theme on <html>.
112
+ */
113
+ apply(name: string, target?: HTMLElement): void;
114
+ /**
115
+ * Get current active theme name from data-theme attribute.
116
+ */
117
+ current(target?: HTMLElement): string | null;
118
+ }
119
+ interface MultiThemeConfig<T extends TokenMap> {
120
+ contract: ThemeContract<T>;
121
+ light: T;
122
+ dark: T;
123
+ /** Additional named themes (brand, high-contrast, etc.) */
124
+ extras?: Record<string, T>;
125
+ }
126
+ /**
127
+ * Create a ThemeRegistry with light/dark + optional extras in one call.
128
+ *
129
+ * @example
130
+ * const { registry, vars } = createMultiTheme({
131
+ * contract: defineThemeContract({
132
+ * colors: { bg: "", fg: "", primary: "", border: "" }
133
+ * }),
134
+ * light: {
135
+ * colors: { bg: "#fff", fg: "#09090b", primary: "#3b82f6", border: "#e5e7eb" }
136
+ * },
137
+ * dark: {
138
+ * colors: { bg: "#09090b", fg: "#fafafa", primary: "#60a5fa", border: "#27272a" }
139
+ * },
140
+ * })
141
+ *
142
+ * // Inject CSS:
143
+ * registry.inject()
144
+ *
145
+ * // Use tokens in components:
146
+ * const Card = tw.div`bg-[${vars.colors.bg}] text-[${vars.colors.fg}]`
147
+ */
148
+ declare function createMultiTheme<T extends TokenMap>(config: MultiThemeConfig<T>): {
149
+ registry: ThemeRegistry;
150
+ vars: ThemeVars<T>;
151
+ light: Theme<T>;
152
+ dark: Theme<T>;
153
+ };
154
+ interface DesignTokens {
155
+ [path: string]: string | DesignTokens;
156
+ }
157
+ /**
158
+ * Flatten nested design token object into CSS variables.
159
+ * Supports Figma-style nested tokens.
160
+ *
161
+ * @example
162
+ * compileDesignTokens({
163
+ * color: {
164
+ * brand: { primary: "#3b82f6", secondary: "#6366f1" },
165
+ * neutral: { 50: "#fafafa", 900: "#09090b" }
166
+ * },
167
+ * spacing: { base: "4px", lg: "16px" }
168
+ * })
169
+ * →
170
+ * :root {
171
+ * --color-brand-primary: #3b82f6;
172
+ * --color-brand-secondary: #6366f1;
173
+ * --color-neutral-50: #fafafa;
174
+ * --color-neutral-900: #09090b;
175
+ * --spacing-base: 4px;
176
+ * --spacing-lg: 16px;
177
+ * }
178
+ */
179
+ declare function compileDesignTokens(tokens: DesignTokens, prefix?: string): string;
180
+
181
+ export { type DesignTokens, type MultiThemeConfig, type Theme, type ThemeContract, ThemeRegistry, type ThemeVars, type TokenMap, compileDesignTokens, createMultiTheme, createTheme, defineThemeContract };
package/dist/index.js ADDED
@@ -0,0 +1,151 @@
1
+ // src/index.ts
2
+ function defineThemeContract(shape) {
3
+ const vars = {};
4
+ for (const group in shape) {
5
+ ;
6
+ vars[group] = {};
7
+ for (const token in shape[group]) {
8
+ ;
9
+ vars[group][token] = `var(--${group}-${token})`;
10
+ }
11
+ }
12
+ return { _contract: shape, _vars: vars };
13
+ }
14
+ function createTheme(contract, name, values, asRoot = false) {
15
+ const flatVars = {};
16
+ const cssLines = [];
17
+ for (const group in values) {
18
+ for (const token in values[group]) {
19
+ const varName = `--${group}-${token}`;
20
+ const value = values[group][token];
21
+ flatVars[varName] = value;
22
+ cssLines.push(` ${varName}: ${value};`);
23
+ }
24
+ }
25
+ const selector = asRoot ? ":root" : `[data-theme="${name}"]`;
26
+ const css = `${selector} {
27
+ ${cssLines.join("\n")}
28
+ }`;
29
+ return {
30
+ name,
31
+ contract,
32
+ values,
33
+ css,
34
+ vars: flatVars,
35
+ selector
36
+ };
37
+ }
38
+ var ThemeRegistry = class {
39
+ constructor() {
40
+ this.themes = /* @__PURE__ */ new Map();
41
+ this.defaultTheme = null;
42
+ }
43
+ /** Register a theme */
44
+ register(theme, isDefault = false) {
45
+ this.themes.set(theme.name, theme);
46
+ if (isDefault || !this.defaultTheme) {
47
+ this.defaultTheme = theme.name;
48
+ }
49
+ return this;
50
+ }
51
+ /** Get a theme by name */
52
+ get(name) {
53
+ return this.themes.get(name);
54
+ }
55
+ /** Get all theme names */
56
+ names() {
57
+ return Array.from(this.themes.keys());
58
+ }
59
+ /**
60
+ * Generate combined CSS for all themes.
61
+ * Inject into <head> or a .css file.
62
+ *
63
+ * @example
64
+ * // In globals.css or layout.tsx
65
+ * const css = registry.generateCss()
66
+ */
67
+ generateCss() {
68
+ return Array.from(this.themes.values()).map((t) => t.css).join("\n\n");
69
+ }
70
+ /**
71
+ * Get the CSS for a specific theme only.
72
+ */
73
+ getThemeCss(name) {
74
+ var _a, _b;
75
+ return (_b = (_a = this.themes.get(name)) == null ? void 0 : _a.css) != null ? _b : null;
76
+ }
77
+ /**
78
+ * Inject all theme CSS into document <head> (browser only).
79
+ * Call once on app init.
80
+ */
81
+ inject(styleId = "__tw_themes") {
82
+ if (typeof document === "undefined") return;
83
+ let style = document.getElementById(styleId);
84
+ if (!style) {
85
+ style = document.createElement("style");
86
+ style.id = styleId;
87
+ document.head.appendChild(style);
88
+ }
89
+ style.textContent = this.generateCss();
90
+ }
91
+ /**
92
+ * Switch active theme by setting data-theme on <html>.
93
+ */
94
+ apply(name, target = document.documentElement) {
95
+ if (typeof document === "undefined") return;
96
+ if (!this.themes.has(name)) {
97
+ console.warn(`[tailwind-styled-v4] Theme "${name}" not registered.`);
98
+ return;
99
+ }
100
+ target.dataset.theme = name;
101
+ }
102
+ /**
103
+ * Get current active theme name from data-theme attribute.
104
+ */
105
+ current(target = document.documentElement) {
106
+ var _a;
107
+ if (typeof document === "undefined") return this.defaultTheme;
108
+ return (_a = target.dataset.theme) != null ? _a : this.defaultTheme;
109
+ }
110
+ };
111
+ function createMultiTheme(config) {
112
+ var _a;
113
+ const registry = new ThemeRegistry();
114
+ const light = createTheme(config.contract, "light", config.light, true);
115
+ const dark = createTheme(config.contract, "dark", config.dark, false);
116
+ registry.register(light, true);
117
+ registry.register(dark);
118
+ for (const [name, values] of Object.entries((_a = config.extras) != null ? _a : {})) {
119
+ registry.register(createTheme(config.contract, name, values));
120
+ }
121
+ return {
122
+ registry,
123
+ vars: config.contract._vars,
124
+ light,
125
+ dark
126
+ };
127
+ }
128
+ function compileDesignTokens(tokens, prefix = "") {
129
+ const vars = [];
130
+ function flatten(obj, path) {
131
+ for (const [key, value] of Object.entries(obj)) {
132
+ const varPath = path ? `${path}-${key}` : key;
133
+ if (typeof value === "string") {
134
+ vars.push(` --${varPath}: ${value};`);
135
+ } else {
136
+ flatten(value, varPath);
137
+ }
138
+ }
139
+ }
140
+ flatten(tokens, prefix);
141
+ return `:root {
142
+ ${vars.join("\n")}
143
+ }`;
144
+ }
145
+ export {
146
+ ThemeRegistry,
147
+ compileDesignTokens,
148
+ createMultiTheme,
149
+ createTheme,
150
+ defineThemeContract
151
+ };
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@tailwind-styled/theme",
3
+ "version": "2.0.0",
4
+ "description": "Enterprise multi-theme engine for tailwind-styled-v4 — CSS variable output, TypeScript-safe contracts",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.cjs"
15
+ }
16
+ },
17
+ "files": ["dist"],
18
+ "sideEffects": false,
19
+ "scripts": {
20
+ "build": "tsup src/index.ts --format cjs,esm --dts --out-dir dist --clean",
21
+ "dev": "tsup src/index.ts --format cjs,esm --dts --out-dir dist --watch"
22
+ },
23
+ "devDependencies": {
24
+ "tsup": "^8",
25
+ "typescript": "^5"
26
+ }
27
+ }