@qlover/tailwind-theme 0.2.1 → 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,23 @@
1
1
  # @qlover/tailwind-theme
2
2
 
3
+ ## 0.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ ## 0.3.0
8
+
9
+ ### Minor Changes
10
+
11
+ #### ✨ Features
12
+
13
+ - **tailwind-theme:** Introduce 'generater' module for theme generation ([24e2345](https://github.com/qlover/fe-base/commit/24e2345d7cc1162702362ea3c29b61b6788d7861)) ([#658](https://github.com/qlover/fe-base/pull/658))
14
+
15
+ - **next-oauth:** enhance styling and theme generation for improved UI consistency ([c225d16](https://github.com/qlover/fe-base/commit/c225d164d09c5c71070c309022203295a840c024)) ([#657](https://github.com/qlover/fe-base/pull/657))
16
+
17
+ #### ♻️ Refactors
18
+
19
+ - **UserService, UserStore:** Simplify session persistence logic ([5de703d](https://github.com/qlover/fe-base/commit/5de703daf5a0b96e269a46e4b9360401da657d6d)) ([#669](https://github.com/qlover/fe-base/pull/669))
20
+
3
21
  ## 0.2.1
4
22
 
5
23
  ### Patch Changes
@@ -0,0 +1,383 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/generater.ts
31
+ var generater_exports = {};
32
+ __export(generater_exports, {
33
+ generateThemeFile: () => generateThemeFile,
34
+ generateThemeFiles: () => generateThemeFiles
35
+ });
36
+ module.exports = __toCommonJS(generater_exports);
37
+ var import_fs = __toESM(require("fs"), 1);
38
+ var import_path = __toESM(require("path"), 1);
39
+
40
+ // src/utils.ts
41
+ function resolveTokenValue(value, prefix) {
42
+ return value.replace(/\$\{prefix\}/g, prefix);
43
+ }
44
+ function deepMerge(target, source) {
45
+ const result = { ...target };
46
+ for (const key in source) {
47
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
48
+ const sourceVal = source[key];
49
+ const targetVal = result[key];
50
+ if (sourceVal && typeof sourceVal === "object" && !Array.isArray(sourceVal) && targetVal && typeof targetVal === "object") {
51
+ result[key] = deepMerge(
52
+ targetVal,
53
+ sourceVal
54
+ );
55
+ } else {
56
+ result[key] = sourceVal;
57
+ }
58
+ }
59
+ }
60
+ return result;
61
+ }
62
+
63
+ // src/config.ts
64
+ var themePrimaryBgOpacity = {
65
+ light: "0.08",
66
+ dark: "0.12",
67
+ pink: "0.12",
68
+ amber: "0.12",
69
+ forest: "0.1",
70
+ ocean: "0.1"
71
+ };
72
+ var builtinThemes = {
73
+ light: {
74
+ "color-primary": "246 248 250",
75
+ "color-secondary": "255 255 255",
76
+ "color-elevated": "240 242 244",
77
+ "color-primary-text": "31 35 40",
78
+ "color-primary-text-hover": "101 109 118",
79
+ "color-secondary-text": "101 109 118",
80
+ "color-tertiary-text": "140 149 159",
81
+ "color-primary-border": "208 215 222",
82
+ "color-brand": "124 58 237",
83
+ "color-brand-hover": "109 40 217",
84
+ "color-brand-active": "91 33 182",
85
+ "color-success": "#1a7f37",
86
+ "color-warning": "#faad14",
87
+ "color-error": "#cf222e",
88
+ "border-radius": "6px"
89
+ },
90
+ dark: {
91
+ "color-primary": "15 17 21",
92
+ "color-secondary": "22 27 34",
93
+ "color-elevated": "33 38 45",
94
+ "color-primary-text": "230 237 243",
95
+ "color-primary-text-hover": "139 148 158",
96
+ "color-secondary-text": "139 148 158",
97
+ "color-tertiary-text": "110 118 129",
98
+ "color-primary-border": "48 54 61",
99
+ "color-brand": "139 92 246",
100
+ "color-brand-hover": "124 58 237",
101
+ "color-brand-active": "109 40 217",
102
+ "color-success": "#3fb950",
103
+ "color-warning": "#faad14",
104
+ "color-error": "#f85149",
105
+ "border-radius": "6px"
106
+ },
107
+ pink: {
108
+ "color-primary": "26 13 20",
109
+ "color-secondary": "37 16 27",
110
+ "color-elevated": "48 21 34",
111
+ "color-primary-text": "252 232 240",
112
+ "color-primary-text-hover": "196 144 168",
113
+ "color-secondary-text": "196 144 168",
114
+ "color-tertiary-text": "138 88 112",
115
+ "color-primary-border": "92 45 66",
116
+ "color-brand": "244 114 182",
117
+ "color-brand-hover": "236 72 153",
118
+ "color-brand-active": "219 39 119",
119
+ "color-success": "#34d399",
120
+ "color-warning": "#faad14",
121
+ "color-error": "#fb7185",
122
+ "border-radius": "8px"
123
+ },
124
+ amber: {
125
+ "color-primary": "30 18 0",
126
+ "color-secondary": "40 26 0",
127
+ "color-elevated": "50 31 0",
128
+ "color-primary-text": "242 232 213",
129
+ "color-primary-text-hover": "184 166 138",
130
+ "color-secondary-text": "184 166 138",
131
+ "color-tertiary-text": "122 106 86",
132
+ "color-primary-border": "74 56 0",
133
+ "color-brand": "232 148 58",
134
+ "color-brand-hover": "208 120 40",
135
+ "color-brand-active": "180 100 30",
136
+ "color-success": "#5aad6e",
137
+ "color-warning": "#faad14",
138
+ "color-error": "#c85a4a",
139
+ "border-radius": "6px"
140
+ },
141
+ forest: {
142
+ "color-primary": "6 21 8",
143
+ "color-secondary": "12 31 14",
144
+ "color-elevated": "19 39 22",
145
+ "color-primary-text": "216 240 220",
146
+ "color-primary-text-hover": "136 173 142",
147
+ "color-secondary-text": "136 173 142",
148
+ "color-tertiary-text": "90 122 94",
149
+ "color-primary-border": "44 66 48",
150
+ "color-brand": "74 222 128",
151
+ "color-brand-hover": "34 197 94",
152
+ "color-brand-active": "22 163 74",
153
+ "color-success": "#86efac",
154
+ "color-warning": "#faad14",
155
+ "color-error": "#f87171",
156
+ "border-radius": "6px"
157
+ },
158
+ ocean: {
159
+ "color-primary": "6 14 26",
160
+ "color-secondary": "13 26 46",
161
+ "color-elevated": "18 36 62",
162
+ "color-primary-text": "218 238 255",
163
+ "color-primary-text-hover": "122 181 212",
164
+ "color-secondary-text": "122 181 212",
165
+ "color-tertiary-text": "74 126 154",
166
+ "color-primary-border": "30 58 92",
167
+ "color-brand": "56 189 248",
168
+ "color-brand-hover": "14 165 233",
169
+ "color-brand-active": "2 132 199",
170
+ "color-success": "#34d399",
171
+ "color-warning": "#faad14",
172
+ "color-error": "#f87171",
173
+ "border-radius": "6px"
174
+ }
175
+ };
176
+ var getDerivedTokens = (prefix, themeName) => {
177
+ const opacity = themeName ? themePrimaryBgOpacity[themeName] ?? "0.1" : "0.1";
178
+ return {
179
+ "color-bg-container": `rgb(var(--${prefix}-color-secondary))`,
180
+ "color-text": `rgb(var(--${prefix}-color-primary-text) / 0.85)`,
181
+ "color-text-heading": `rgb(var(--${prefix}-color-primary-text))`,
182
+ "color-text-disabled": `rgb(var(--${prefix}-color-primary-text) / 0.25)`,
183
+ "color-primary-hover": `rgb(var(--${prefix}-color-brand-hover))`,
184
+ "color-primary-active": `rgb(var(--${prefix}-color-brand-active))`,
185
+ "color-primary-bg": `rgb(var(--${prefix}-color-brand) / ${opacity})`,
186
+ "line-height": "1.5715"
187
+ };
188
+ };
189
+ var defaultTokenMapping = {
190
+ "color-primary": "rgb(var(--${prefix}-color-primary))",
191
+ "color-primary-active": "rgb(var(--${prefix}-color-primary-active))",
192
+ "color-primary-hover": "rgb(var(--${prefix}-color-primary-hover))",
193
+ "color-primary-bg": "rgb(var(--${prefix}-color-primary-bg))",
194
+ "color-secondary": "rgb(var(--${prefix}-color-secondary))",
195
+ "color-elevated": "rgb(var(--${prefix}-color-elevated))",
196
+ "color-primary-text": "rgb(var(--${prefix}-color-primary-text))",
197
+ "color-primary-text-hover": "rgb(var(--${prefix}-color-primary-text-hover))",
198
+ "color-secondary-text": "rgb(var(--${prefix}-color-secondary-text))",
199
+ "color-tertiary-text": "rgb(var(--${prefix}-color-tertiary-text))",
200
+ "color-primary-border": "rgb(var(--${prefix}-color-primary-border))",
201
+ "color-brand": "rgb(var(--${prefix}-color-brand))",
202
+ "color-brand-hover": "rgb(var(--${prefix}-color-brand-hover))",
203
+ "color-brand-active": "rgb(var(--${prefix}-color-brand-active))",
204
+ /** Text/icons on brand-colored surfaces (buttons, badges) */
205
+ "color-on-brand": "#ffffff",
206
+ "color-progress-track": "rgb(var(--${prefix}-color-primary-border) / 0.5)",
207
+ "color-bg-container": "rgb(var(--${prefix}-color-bg-container))",
208
+ "font-sans": 'var(--font-inter), ui-sans-serif, system-ui, "PingFang SC", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans SC", sans-serif',
209
+ "animate-dashboard-skeleton-shimmer": "dashboard-skeleton-shimmer 1.6s ease-in-out infinite"
210
+ };
211
+ function getDefaultSelector(themeName, root) {
212
+ if (root) {
213
+ return `:root, html[data-theme="${themeName}"], [data-theme="${themeName}"]`;
214
+ }
215
+ return `html[data-theme="${themeName}"], [data-theme="${themeName}"]`;
216
+ }
217
+ var defaultConfig = {
218
+ prefix: "fe",
219
+ themes: {},
220
+ tokenMapping: defaultTokenMapping,
221
+ cssSelector: getDefaultSelector
222
+ };
223
+ function getConfig(options) {
224
+ let allThemes = deepMerge(builtinThemes, options?.themes || {});
225
+ const includeThemes = options?.includeThemes;
226
+ if (includeThemes?.length) {
227
+ const filtered = {};
228
+ for (const name of includeThemes) {
229
+ if (allThemes[name]) {
230
+ filtered[name] = allThemes[name];
231
+ }
232
+ }
233
+ allThemes = filtered;
234
+ }
235
+ const allMappings = deepMerge(
236
+ defaultTokenMapping,
237
+ options?.tokenMapping || {}
238
+ );
239
+ const config = Object.assign(
240
+ {},
241
+ defaultConfig,
242
+ options,
243
+ {
244
+ themes: allThemes,
245
+ tokenMapping: allMappings,
246
+ includeThemes: includeThemes ?? []
247
+ }
248
+ );
249
+ if (!config.defaultTheme || !config.themes[config.defaultTheme]) {
250
+ config.defaultTheme = Object.keys(config.themes)[0];
251
+ }
252
+ return config;
253
+ }
254
+
255
+ // src/core.ts
256
+ function generateLayerBaseCSS(options = {}) {
257
+ const config = getConfig(options);
258
+ const { prefix, themes, cssSelector, defaultTheme } = config;
259
+ let css = "";
260
+ for (const [themeName, vars] of Object.entries(themes)) {
261
+ const isDefault = themeName === defaultTheme;
262
+ const selector = cssSelector(themeName, isDefault);
263
+ const themeDerived = getDerivedTokens(prefix, themeName);
264
+ const merged = {
265
+ ...vars,
266
+ ...themeDerived
267
+ };
268
+ css += `${selector} {
269
+ `;
270
+ for (const [varName, value] of Object.entries(merged)) {
271
+ css += ` --${prefix}-${varName}: ${value};
272
+ `;
273
+ }
274
+ css += "}\n\n";
275
+ }
276
+ return css;
277
+ }
278
+ function generateThemeBlockCSS(options = {}) {
279
+ const config = getConfig(options);
280
+ const { prefix, tokenMapping = defaultTokenMapping } = config;
281
+ let css = "@theme {\n";
282
+ for (const [tokenName, tokenValue] of Object.entries(tokenMapping)) {
283
+ const finalValue = resolveTokenValue(tokenValue, prefix);
284
+ css += ` --${tokenName}: ${finalValue};
285
+ `;
286
+ }
287
+ css += "}\n";
288
+ return css;
289
+ }
290
+ function generateThemeCSS(options = {}) {
291
+ let css = "";
292
+ const layerBaseContent = generateLayerBaseCSS(options);
293
+ if (layerBaseContent) {
294
+ css += "@layer base {\n" + layerBaseContent + "}\n\n";
295
+ }
296
+ css += generateThemeBlockCSS(options);
297
+ return css;
298
+ }
299
+
300
+ // src/generater.ts
301
+ var DEFAULT_OUTPUT_PATHS = {
302
+ "layer-base": "theme-layer-base.css",
303
+ "theme-block": "theme-block.css",
304
+ full: "theme.css"
305
+ };
306
+ function resolveCssContent(variant, options) {
307
+ switch (variant) {
308
+ case "layer-base": {
309
+ const layerBaseContent = generateLayerBaseCSS(options);
310
+ return layerBaseContent ? `@layer base {
311
+ ${layerBaseContent}}
312
+ ` : "";
313
+ }
314
+ case "theme-block":
315
+ return generateThemeBlockCSS(options);
316
+ case "full":
317
+ return generateThemeCSS(options);
318
+ default: {
319
+ const _exhaustive = variant;
320
+ return _exhaustive;
321
+ }
322
+ }
323
+ }
324
+ async function writeCssFile(absolutePath, css, overwrite) {
325
+ if (import_fs.default.existsSync(absolutePath)) {
326
+ if (overwrite) {
327
+ console.warn(
328
+ `\u26A0\uFE0F Warning: File already exists at ${absolutePath}. It will be overwritten.`
329
+ );
330
+ } else {
331
+ throw new Error(
332
+ `File already exists at ${absolutePath} and overwrite is set to false.`
333
+ );
334
+ }
335
+ }
336
+ const dir = import_path.default.dirname(absolutePath);
337
+ if (!import_fs.default.existsSync(dir)) {
338
+ import_fs.default.mkdirSync(dir, { recursive: true });
339
+ }
340
+ await import_fs.default.promises.writeFile(absolutePath, css, "utf-8");
341
+ console.log(`\u2705 Theme CSS generated at ${absolutePath}`);
342
+ }
343
+ function resolveOutputPath(variant, options) {
344
+ if (options.outputPath) {
345
+ return import_path.default.resolve(process.cwd(), options.outputPath);
346
+ }
347
+ return import_path.default.resolve(process.cwd(), DEFAULT_OUTPUT_PATHS[variant]);
348
+ }
349
+ async function generateThemeFile(options = {}) {
350
+ const {
351
+ variant = "full",
352
+ overwrite = true,
353
+ outputPath,
354
+ ...restOptions
355
+ } = options;
356
+ const absolutePath = outputPath ? import_path.default.resolve(process.cwd(), outputPath) : resolveOutputPath(variant, options);
357
+ const css = resolveCssContent(variant, restOptions);
358
+ await writeCssFile(absolutePath, css, overwrite);
359
+ return absolutePath;
360
+ }
361
+ async function generateThemeFiles(options = {}) {
362
+ const {
363
+ outputDir = ".",
364
+ outputPaths = {},
365
+ overwrite = true,
366
+ ...restOptions
367
+ } = options;
368
+ const variants = Object.keys(DEFAULT_OUTPUT_PATHS);
369
+ const result = {};
370
+ for (const variant of variants) {
371
+ const relativePath = outputPaths[variant] ?? import_path.default.join(outputDir, DEFAULT_OUTPUT_PATHS[variant]);
372
+ const absolutePath = import_path.default.resolve(process.cwd(), relativePath);
373
+ const css = resolveCssContent(variant, restOptions);
374
+ await writeCssFile(absolutePath, css, overwrite);
375
+ result[variant] = absolutePath;
376
+ }
377
+ return result;
378
+ }
379
+ // Annotate the CommonJS export names for ESM import in node:
380
+ 0 && (module.exports = {
381
+ generateThemeFile,
382
+ generateThemeFiles
383
+ });
@@ -0,0 +1,68 @@
1
+ type RGBChannels = string;
2
+ type ColorValue = string;
3
+ type ThemeTokens = Record<string, ColorValue | RGBChannels>;
4
+ /** Named themes → token sets (avoids index-signature confusion with `Record<string, ThemeTokens>`) */
5
+ type ThemesMap = Record<string, ThemeTokens>;
6
+ /**
7
+ * Token mapping for the theme.
8
+ *
9
+ * @example
10
+ * {
11
+ * 'color-primary': 'rgb(var(--${prefix}-color-primary))',
12
+ * 'color-secondary': 'rgb(var(--${prefix}-color-secondary))',
13
+ * 'color-elevated': 'rgb(var(--${prefix}-color-elevated))',
14
+ * 'color-primary-text': 'rgb(var(--${prefix}-color-primary-text))',
15
+ * 'color-primary-text-hover': 'rgb(var(--${prefix}-color-primary-text-hover))',
16
+ * 'color-secondary-text': 'rgb(var(--${prefix}-color-secondary-text))',
17
+ * 'color-tertiary-text': 'rgb(var(--${prefix}-color-tertiary-text))',
18
+ * }
19
+ *
20
+ * 最后结果可能=>
21
+ * {
22
+ * '--color-primary': 'rgb(var(--fe-color-primary))',
23
+ * '--color-secondary': 'rgb(var(--fe-color-secondary))',
24
+ * '--color-elevated': 'rgb(var(--fe-color-elevated))',
25
+ * '--color-primary-text': 'rgb(var(--fe-color-primary-text))',
26
+ * '--color-primary-text-hover': 'rgb(var(--fe-color-primary-text-hover))',
27
+ * '--color-secondary-text': 'rgb(var(--fe-color-secondary-text))',
28
+ * '--color-tertiary-text': 'rgb(var(--fe-color-tertiary-text))',
29
+ * }
30
+ */
31
+ type TokenMapping = Record<string, string>;
32
+ interface UiThemeOptions {
33
+ prefix?: string;
34
+ defaultTheme?: string;
35
+ themes?: ThemesMap;
36
+ /**
37
+ * When set, only these theme names are emitted (after merging builtins).
38
+ * Use to keep app CSS small when the package ships extra demo themes.
39
+ */
40
+ includeThemes?: string[];
41
+ tokenMapping?: TokenMapping;
42
+ cssSelector?: (themeName: string, root: boolean) => string;
43
+ outputPath?: string;
44
+ overwrite?: boolean;
45
+ }
46
+
47
+ /** CSS variant aligned with {@link core.ts} generators */
48
+ type ThemeCssVariant = 'layer-base' | 'theme-block' | 'full';
49
+ interface GenerateThemeFileOptions extends UiThemeOptions {
50
+ /** Which CSS generator to use. Default: `full` */
51
+ variant?: ThemeCssVariant;
52
+ }
53
+ interface GenerateThemeFilesOptions extends UiThemeOptions {
54
+ /** Directory for default output file names. Default: `.` (cwd) */
55
+ outputDir?: string;
56
+ /** Override output path per variant (relative to cwd unless absolute) */
57
+ outputPaths?: Partial<Record<ThemeCssVariant, string>>;
58
+ }
59
+ /**
60
+ * Write theme CSS to a file using the selected core generator variant.
61
+ */
62
+ declare function generateThemeFile(options?: GenerateThemeFileOptions): Promise<string>;
63
+ /**
64
+ * Write all three theme CSS variants (layer-base, theme-block, full) to files.
65
+ */
66
+ declare function generateThemeFiles(options?: GenerateThemeFilesOptions): Promise<Record<ThemeCssVariant, string>>;
67
+
68
+ export { type GenerateThemeFileOptions, type GenerateThemeFilesOptions, type ThemeCssVariant, generateThemeFile, generateThemeFiles };
@@ -0,0 +1,68 @@
1
+ type RGBChannels = string;
2
+ type ColorValue = string;
3
+ type ThemeTokens = Record<string, ColorValue | RGBChannels>;
4
+ /** Named themes → token sets (avoids index-signature confusion with `Record<string, ThemeTokens>`) */
5
+ type ThemesMap = Record<string, ThemeTokens>;
6
+ /**
7
+ * Token mapping for the theme.
8
+ *
9
+ * @example
10
+ * {
11
+ * 'color-primary': 'rgb(var(--${prefix}-color-primary))',
12
+ * 'color-secondary': 'rgb(var(--${prefix}-color-secondary))',
13
+ * 'color-elevated': 'rgb(var(--${prefix}-color-elevated))',
14
+ * 'color-primary-text': 'rgb(var(--${prefix}-color-primary-text))',
15
+ * 'color-primary-text-hover': 'rgb(var(--${prefix}-color-primary-text-hover))',
16
+ * 'color-secondary-text': 'rgb(var(--${prefix}-color-secondary-text))',
17
+ * 'color-tertiary-text': 'rgb(var(--${prefix}-color-tertiary-text))',
18
+ * }
19
+ *
20
+ * 最后结果可能=>
21
+ * {
22
+ * '--color-primary': 'rgb(var(--fe-color-primary))',
23
+ * '--color-secondary': 'rgb(var(--fe-color-secondary))',
24
+ * '--color-elevated': 'rgb(var(--fe-color-elevated))',
25
+ * '--color-primary-text': 'rgb(var(--fe-color-primary-text))',
26
+ * '--color-primary-text-hover': 'rgb(var(--fe-color-primary-text-hover))',
27
+ * '--color-secondary-text': 'rgb(var(--fe-color-secondary-text))',
28
+ * '--color-tertiary-text': 'rgb(var(--fe-color-tertiary-text))',
29
+ * }
30
+ */
31
+ type TokenMapping = Record<string, string>;
32
+ interface UiThemeOptions {
33
+ prefix?: string;
34
+ defaultTheme?: string;
35
+ themes?: ThemesMap;
36
+ /**
37
+ * When set, only these theme names are emitted (after merging builtins).
38
+ * Use to keep app CSS small when the package ships extra demo themes.
39
+ */
40
+ includeThemes?: string[];
41
+ tokenMapping?: TokenMapping;
42
+ cssSelector?: (themeName: string, root: boolean) => string;
43
+ outputPath?: string;
44
+ overwrite?: boolean;
45
+ }
46
+
47
+ /** CSS variant aligned with {@link core.ts} generators */
48
+ type ThemeCssVariant = 'layer-base' | 'theme-block' | 'full';
49
+ interface GenerateThemeFileOptions extends UiThemeOptions {
50
+ /** Which CSS generator to use. Default: `full` */
51
+ variant?: ThemeCssVariant;
52
+ }
53
+ interface GenerateThemeFilesOptions extends UiThemeOptions {
54
+ /** Directory for default output file names. Default: `.` (cwd) */
55
+ outputDir?: string;
56
+ /** Override output path per variant (relative to cwd unless absolute) */
57
+ outputPaths?: Partial<Record<ThemeCssVariant, string>>;
58
+ }
59
+ /**
60
+ * Write theme CSS to a file using the selected core generator variant.
61
+ */
62
+ declare function generateThemeFile(options?: GenerateThemeFileOptions): Promise<string>;
63
+ /**
64
+ * Write all three theme CSS variants (layer-base, theme-block, full) to files.
65
+ */
66
+ declare function generateThemeFiles(options?: GenerateThemeFilesOptions): Promise<Record<ThemeCssVariant, string>>;
67
+
68
+ export { type GenerateThemeFileOptions, type GenerateThemeFilesOptions, type ThemeCssVariant, generateThemeFile, generateThemeFiles };
@@ -0,0 +1,347 @@
1
+ // src/generater.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+
5
+ // src/utils.ts
6
+ function resolveTokenValue(value, prefix) {
7
+ return value.replace(/\$\{prefix\}/g, prefix);
8
+ }
9
+ function deepMerge(target, source) {
10
+ const result = { ...target };
11
+ for (const key in source) {
12
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
13
+ const sourceVal = source[key];
14
+ const targetVal = result[key];
15
+ if (sourceVal && typeof sourceVal === "object" && !Array.isArray(sourceVal) && targetVal && typeof targetVal === "object") {
16
+ result[key] = deepMerge(
17
+ targetVal,
18
+ sourceVal
19
+ );
20
+ } else {
21
+ result[key] = sourceVal;
22
+ }
23
+ }
24
+ }
25
+ return result;
26
+ }
27
+
28
+ // src/config.ts
29
+ var themePrimaryBgOpacity = {
30
+ light: "0.08",
31
+ dark: "0.12",
32
+ pink: "0.12",
33
+ amber: "0.12",
34
+ forest: "0.1",
35
+ ocean: "0.1"
36
+ };
37
+ var builtinThemes = {
38
+ light: {
39
+ "color-primary": "246 248 250",
40
+ "color-secondary": "255 255 255",
41
+ "color-elevated": "240 242 244",
42
+ "color-primary-text": "31 35 40",
43
+ "color-primary-text-hover": "101 109 118",
44
+ "color-secondary-text": "101 109 118",
45
+ "color-tertiary-text": "140 149 159",
46
+ "color-primary-border": "208 215 222",
47
+ "color-brand": "124 58 237",
48
+ "color-brand-hover": "109 40 217",
49
+ "color-brand-active": "91 33 182",
50
+ "color-success": "#1a7f37",
51
+ "color-warning": "#faad14",
52
+ "color-error": "#cf222e",
53
+ "border-radius": "6px"
54
+ },
55
+ dark: {
56
+ "color-primary": "15 17 21",
57
+ "color-secondary": "22 27 34",
58
+ "color-elevated": "33 38 45",
59
+ "color-primary-text": "230 237 243",
60
+ "color-primary-text-hover": "139 148 158",
61
+ "color-secondary-text": "139 148 158",
62
+ "color-tertiary-text": "110 118 129",
63
+ "color-primary-border": "48 54 61",
64
+ "color-brand": "139 92 246",
65
+ "color-brand-hover": "124 58 237",
66
+ "color-brand-active": "109 40 217",
67
+ "color-success": "#3fb950",
68
+ "color-warning": "#faad14",
69
+ "color-error": "#f85149",
70
+ "border-radius": "6px"
71
+ },
72
+ pink: {
73
+ "color-primary": "26 13 20",
74
+ "color-secondary": "37 16 27",
75
+ "color-elevated": "48 21 34",
76
+ "color-primary-text": "252 232 240",
77
+ "color-primary-text-hover": "196 144 168",
78
+ "color-secondary-text": "196 144 168",
79
+ "color-tertiary-text": "138 88 112",
80
+ "color-primary-border": "92 45 66",
81
+ "color-brand": "244 114 182",
82
+ "color-brand-hover": "236 72 153",
83
+ "color-brand-active": "219 39 119",
84
+ "color-success": "#34d399",
85
+ "color-warning": "#faad14",
86
+ "color-error": "#fb7185",
87
+ "border-radius": "8px"
88
+ },
89
+ amber: {
90
+ "color-primary": "30 18 0",
91
+ "color-secondary": "40 26 0",
92
+ "color-elevated": "50 31 0",
93
+ "color-primary-text": "242 232 213",
94
+ "color-primary-text-hover": "184 166 138",
95
+ "color-secondary-text": "184 166 138",
96
+ "color-tertiary-text": "122 106 86",
97
+ "color-primary-border": "74 56 0",
98
+ "color-brand": "232 148 58",
99
+ "color-brand-hover": "208 120 40",
100
+ "color-brand-active": "180 100 30",
101
+ "color-success": "#5aad6e",
102
+ "color-warning": "#faad14",
103
+ "color-error": "#c85a4a",
104
+ "border-radius": "6px"
105
+ },
106
+ forest: {
107
+ "color-primary": "6 21 8",
108
+ "color-secondary": "12 31 14",
109
+ "color-elevated": "19 39 22",
110
+ "color-primary-text": "216 240 220",
111
+ "color-primary-text-hover": "136 173 142",
112
+ "color-secondary-text": "136 173 142",
113
+ "color-tertiary-text": "90 122 94",
114
+ "color-primary-border": "44 66 48",
115
+ "color-brand": "74 222 128",
116
+ "color-brand-hover": "34 197 94",
117
+ "color-brand-active": "22 163 74",
118
+ "color-success": "#86efac",
119
+ "color-warning": "#faad14",
120
+ "color-error": "#f87171",
121
+ "border-radius": "6px"
122
+ },
123
+ ocean: {
124
+ "color-primary": "6 14 26",
125
+ "color-secondary": "13 26 46",
126
+ "color-elevated": "18 36 62",
127
+ "color-primary-text": "218 238 255",
128
+ "color-primary-text-hover": "122 181 212",
129
+ "color-secondary-text": "122 181 212",
130
+ "color-tertiary-text": "74 126 154",
131
+ "color-primary-border": "30 58 92",
132
+ "color-brand": "56 189 248",
133
+ "color-brand-hover": "14 165 233",
134
+ "color-brand-active": "2 132 199",
135
+ "color-success": "#34d399",
136
+ "color-warning": "#faad14",
137
+ "color-error": "#f87171",
138
+ "border-radius": "6px"
139
+ }
140
+ };
141
+ var getDerivedTokens = (prefix, themeName) => {
142
+ const opacity = themeName ? themePrimaryBgOpacity[themeName] ?? "0.1" : "0.1";
143
+ return {
144
+ "color-bg-container": `rgb(var(--${prefix}-color-secondary))`,
145
+ "color-text": `rgb(var(--${prefix}-color-primary-text) / 0.85)`,
146
+ "color-text-heading": `rgb(var(--${prefix}-color-primary-text))`,
147
+ "color-text-disabled": `rgb(var(--${prefix}-color-primary-text) / 0.25)`,
148
+ "color-primary-hover": `rgb(var(--${prefix}-color-brand-hover))`,
149
+ "color-primary-active": `rgb(var(--${prefix}-color-brand-active))`,
150
+ "color-primary-bg": `rgb(var(--${prefix}-color-brand) / ${opacity})`,
151
+ "line-height": "1.5715"
152
+ };
153
+ };
154
+ var defaultTokenMapping = {
155
+ "color-primary": "rgb(var(--${prefix}-color-primary))",
156
+ "color-primary-active": "rgb(var(--${prefix}-color-primary-active))",
157
+ "color-primary-hover": "rgb(var(--${prefix}-color-primary-hover))",
158
+ "color-primary-bg": "rgb(var(--${prefix}-color-primary-bg))",
159
+ "color-secondary": "rgb(var(--${prefix}-color-secondary))",
160
+ "color-elevated": "rgb(var(--${prefix}-color-elevated))",
161
+ "color-primary-text": "rgb(var(--${prefix}-color-primary-text))",
162
+ "color-primary-text-hover": "rgb(var(--${prefix}-color-primary-text-hover))",
163
+ "color-secondary-text": "rgb(var(--${prefix}-color-secondary-text))",
164
+ "color-tertiary-text": "rgb(var(--${prefix}-color-tertiary-text))",
165
+ "color-primary-border": "rgb(var(--${prefix}-color-primary-border))",
166
+ "color-brand": "rgb(var(--${prefix}-color-brand))",
167
+ "color-brand-hover": "rgb(var(--${prefix}-color-brand-hover))",
168
+ "color-brand-active": "rgb(var(--${prefix}-color-brand-active))",
169
+ /** Text/icons on brand-colored surfaces (buttons, badges) */
170
+ "color-on-brand": "#ffffff",
171
+ "color-progress-track": "rgb(var(--${prefix}-color-primary-border) / 0.5)",
172
+ "color-bg-container": "rgb(var(--${prefix}-color-bg-container))",
173
+ "font-sans": 'var(--font-inter), ui-sans-serif, system-ui, "PingFang SC", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans SC", sans-serif',
174
+ "animate-dashboard-skeleton-shimmer": "dashboard-skeleton-shimmer 1.6s ease-in-out infinite"
175
+ };
176
+ function getDefaultSelector(themeName, root) {
177
+ if (root) {
178
+ return `:root, html[data-theme="${themeName}"], [data-theme="${themeName}"]`;
179
+ }
180
+ return `html[data-theme="${themeName}"], [data-theme="${themeName}"]`;
181
+ }
182
+ var defaultConfig = {
183
+ prefix: "fe",
184
+ themes: {},
185
+ tokenMapping: defaultTokenMapping,
186
+ cssSelector: getDefaultSelector
187
+ };
188
+ function getConfig(options) {
189
+ let allThemes = deepMerge(builtinThemes, options?.themes || {});
190
+ const includeThemes = options?.includeThemes;
191
+ if (includeThemes?.length) {
192
+ const filtered = {};
193
+ for (const name of includeThemes) {
194
+ if (allThemes[name]) {
195
+ filtered[name] = allThemes[name];
196
+ }
197
+ }
198
+ allThemes = filtered;
199
+ }
200
+ const allMappings = deepMerge(
201
+ defaultTokenMapping,
202
+ options?.tokenMapping || {}
203
+ );
204
+ const config = Object.assign(
205
+ {},
206
+ defaultConfig,
207
+ options,
208
+ {
209
+ themes: allThemes,
210
+ tokenMapping: allMappings,
211
+ includeThemes: includeThemes ?? []
212
+ }
213
+ );
214
+ if (!config.defaultTheme || !config.themes[config.defaultTheme]) {
215
+ config.defaultTheme = Object.keys(config.themes)[0];
216
+ }
217
+ return config;
218
+ }
219
+
220
+ // src/core.ts
221
+ function generateLayerBaseCSS(options = {}) {
222
+ const config = getConfig(options);
223
+ const { prefix, themes, cssSelector, defaultTheme } = config;
224
+ let css = "";
225
+ for (const [themeName, vars] of Object.entries(themes)) {
226
+ const isDefault = themeName === defaultTheme;
227
+ const selector = cssSelector(themeName, isDefault);
228
+ const themeDerived = getDerivedTokens(prefix, themeName);
229
+ const merged = {
230
+ ...vars,
231
+ ...themeDerived
232
+ };
233
+ css += `${selector} {
234
+ `;
235
+ for (const [varName, value] of Object.entries(merged)) {
236
+ css += ` --${prefix}-${varName}: ${value};
237
+ `;
238
+ }
239
+ css += "}\n\n";
240
+ }
241
+ return css;
242
+ }
243
+ function generateThemeBlockCSS(options = {}) {
244
+ const config = getConfig(options);
245
+ const { prefix, tokenMapping = defaultTokenMapping } = config;
246
+ let css = "@theme {\n";
247
+ for (const [tokenName, tokenValue] of Object.entries(tokenMapping)) {
248
+ const finalValue = resolveTokenValue(tokenValue, prefix);
249
+ css += ` --${tokenName}: ${finalValue};
250
+ `;
251
+ }
252
+ css += "}\n";
253
+ return css;
254
+ }
255
+ function generateThemeCSS(options = {}) {
256
+ let css = "";
257
+ const layerBaseContent = generateLayerBaseCSS(options);
258
+ if (layerBaseContent) {
259
+ css += "@layer base {\n" + layerBaseContent + "}\n\n";
260
+ }
261
+ css += generateThemeBlockCSS(options);
262
+ return css;
263
+ }
264
+
265
+ // src/generater.ts
266
+ var DEFAULT_OUTPUT_PATHS = {
267
+ "layer-base": "theme-layer-base.css",
268
+ "theme-block": "theme-block.css",
269
+ full: "theme.css"
270
+ };
271
+ function resolveCssContent(variant, options) {
272
+ switch (variant) {
273
+ case "layer-base": {
274
+ const layerBaseContent = generateLayerBaseCSS(options);
275
+ return layerBaseContent ? `@layer base {
276
+ ${layerBaseContent}}
277
+ ` : "";
278
+ }
279
+ case "theme-block":
280
+ return generateThemeBlockCSS(options);
281
+ case "full":
282
+ return generateThemeCSS(options);
283
+ default: {
284
+ const _exhaustive = variant;
285
+ return _exhaustive;
286
+ }
287
+ }
288
+ }
289
+ async function writeCssFile(absolutePath, css, overwrite) {
290
+ if (fs.existsSync(absolutePath)) {
291
+ if (overwrite) {
292
+ console.warn(
293
+ `\u26A0\uFE0F Warning: File already exists at ${absolutePath}. It will be overwritten.`
294
+ );
295
+ } else {
296
+ throw new Error(
297
+ `File already exists at ${absolutePath} and overwrite is set to false.`
298
+ );
299
+ }
300
+ }
301
+ const dir = path.dirname(absolutePath);
302
+ if (!fs.existsSync(dir)) {
303
+ fs.mkdirSync(dir, { recursive: true });
304
+ }
305
+ await fs.promises.writeFile(absolutePath, css, "utf-8");
306
+ console.log(`\u2705 Theme CSS generated at ${absolutePath}`);
307
+ }
308
+ function resolveOutputPath(variant, options) {
309
+ if (options.outputPath) {
310
+ return path.resolve(process.cwd(), options.outputPath);
311
+ }
312
+ return path.resolve(process.cwd(), DEFAULT_OUTPUT_PATHS[variant]);
313
+ }
314
+ async function generateThemeFile(options = {}) {
315
+ const {
316
+ variant = "full",
317
+ overwrite = true,
318
+ outputPath,
319
+ ...restOptions
320
+ } = options;
321
+ const absolutePath = outputPath ? path.resolve(process.cwd(), outputPath) : resolveOutputPath(variant, options);
322
+ const css = resolveCssContent(variant, restOptions);
323
+ await writeCssFile(absolutePath, css, overwrite);
324
+ return absolutePath;
325
+ }
326
+ async function generateThemeFiles(options = {}) {
327
+ const {
328
+ outputDir = ".",
329
+ outputPaths = {},
330
+ overwrite = true,
331
+ ...restOptions
332
+ } = options;
333
+ const variants = Object.keys(DEFAULT_OUTPUT_PATHS);
334
+ const result = {};
335
+ for (const variant of variants) {
336
+ const relativePath = outputPaths[variant] ?? path.join(outputDir, DEFAULT_OUTPUT_PATHS[variant]);
337
+ const absolutePath = path.resolve(process.cwd(), relativePath);
338
+ const css = resolveCssContent(variant, restOptions);
339
+ await writeCssFile(absolutePath, css, overwrite);
340
+ result[variant] = absolutePath;
341
+ }
342
+ return result;
343
+ }
344
+ export {
345
+ generateThemeFile,
346
+ generateThemeFiles
347
+ };
package/dist/index.cjs CHANGED
@@ -1,13 +1,11 @@
1
- "use strict";var j=Object.create;var m=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var G=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var E=(r,e)=>{for(var o in e)m(r,o,{get:e[o],enumerable:!0})},k=(r,e,o,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of D(e))!A.call(r,a)&&a!==o&&m(r,a,{get:()=>e[a],enumerable:!(t=B(e,a))||t.enumerable});return r};var $=(r,e,o)=>(o=r!=null?j(G(r)):{},k(e||!r||!r.__esModule?m(o,"default",{value:r,enumerable:!0}):o,r)),_=r=>k(m({},"__esModule",{value:!0}),r);var Y={};E(Y,{builtinThemes:()=>C,defaultConfig:()=>S,defaultTokenMapping:()=>l,generateLayerBaseCSS:()=>f,generateThemeBlockCSS:()=>y,generateThemeCSS:()=>v,generateThemeFile:()=>q,generateThemeFiles:()=>I,getConfig:()=>g,getDefaultSelector:()=>w,getDerivedTokens:()=>x});module.exports=_(Y);function O(r,e){return r.replace(/\$\{prefix\}/g,e)}function d(r,e){let o={...r};for(let t in e)if(Object.prototype.hasOwnProperty.call(e,t)){let a=e[t],n=o[t];a&&typeof a=="object"&&!Array.isArray(a)&&n&&typeof n=="object"?o[t]=d(n,a):o[t]=a}return o}var H={light:"0.08",dark:"0.12",pink:"0.12",amber:"0.12",forest:"0.1",ocean:"0.1"},C={light:{"color-primary":"246 248 250","color-secondary":"255 255 255","color-elevated":"240 242 244","color-primary-text":"31 35 40","color-primary-text-hover":"101 109 118","color-secondary-text":"101 109 118","color-tertiary-text":"140 149 159","color-primary-border":"208 215 222","color-brand":"124 58 237","color-brand-hover":"109 40 217","color-brand-active":"91 33 182","color-success":"#1a7f37","color-warning":"#faad14","color-error":"#cf222e","border-radius":"6px"},dark:{"color-primary":"15 17 21","color-secondary":"22 27 34","color-elevated":"33 38 45","color-primary-text":"230 237 243","color-primary-text-hover":"139 148 158","color-secondary-text":"139 148 158","color-tertiary-text":"110 118 129","color-primary-border":"48 54 61","color-brand":"139 92 246","color-brand-hover":"124 58 237","color-brand-active":"109 40 217","color-success":"#3fb950","color-warning":"#faad14","color-error":"#f85149","border-radius":"6px"},pink:{"color-primary":"26 13 20","color-secondary":"37 16 27","color-elevated":"48 21 34","color-primary-text":"252 232 240","color-primary-text-hover":"196 144 168","color-secondary-text":"196 144 168","color-tertiary-text":"138 88 112","color-primary-border":"92 45 66","color-brand":"244 114 182","color-brand-hover":"236 72 153","color-brand-active":"219 39 119","color-success":"#34d399","color-warning":"#faad14","color-error":"#fb7185","border-radius":"8px"},amber:{"color-primary":"30 18 0","color-secondary":"40 26 0","color-elevated":"50 31 0","color-primary-text":"242 232 213","color-primary-text-hover":"184 166 138","color-secondary-text":"184 166 138","color-tertiary-text":"122 106 86","color-primary-border":"74 56 0","color-brand":"232 148 58","color-brand-hover":"208 120 40","color-brand-active":"180 100 30","color-success":"#5aad6e","color-warning":"#faad14","color-error":"#c85a4a","border-radius":"6px"},forest:{"color-primary":"6 21 8","color-secondary":"12 31 14","color-elevated":"19 39 22","color-primary-text":"216 240 220","color-primary-text-hover":"136 173 142","color-secondary-text":"136 173 142","color-tertiary-text":"90 122 94","color-primary-border":"44 66 48","color-brand":"74 222 128","color-brand-hover":"34 197 94","color-brand-active":"22 163 74","color-success":"#86efac","color-warning":"#faad14","color-error":"#f87171","border-radius":"6px"},ocean:{"color-primary":"6 14 26","color-secondary":"13 26 46","color-elevated":"18 36 62","color-primary-text":"218 238 255","color-primary-text-hover":"122 181 212","color-secondary-text":"122 181 212","color-tertiary-text":"74 126 154","color-primary-border":"30 58 92","color-brand":"56 189 248","color-brand-hover":"14 165 233","color-brand-active":"2 132 199","color-success":"#34d399","color-warning":"#faad14","color-error":"#f87171","border-radius":"6px"}},x=(r,e)=>{let o=e?H[e]??"0.1":"0.1";return{"color-bg-container":`rgb(var(--${r}-color-secondary))`,"color-text":`rgb(var(--${r}-color-primary-text) / 0.85)`,"color-text-heading":`rgb(var(--${r}-color-primary-text))`,"color-text-disabled":`rgb(var(--${r}-color-primary-text) / 0.25)`,"color-primary-hover":`rgb(var(--${r}-color-brand-hover))`,"color-primary-active":`rgb(var(--${r}-color-brand-active))`,"color-primary-bg":`rgb(var(--${r}-color-brand) / ${o})`,"line-height":"1.5715"}},l={"color-primary":"rgb(var(--${prefix}-color-primary))","color-primary-active":"rgb(var(--${prefix}-color-primary-active))","color-primary-hover":"rgb(var(--${prefix}-color-primary-hover))","color-primary-bg":"rgb(var(--${prefix}-color-primary-bg))","color-secondary":"rgb(var(--${prefix}-color-secondary))","color-elevated":"rgb(var(--${prefix}-color-elevated))","color-primary-text":"rgb(var(--${prefix}-color-primary-text))","color-primary-text-hover":"rgb(var(--${prefix}-color-primary-text-hover))","color-secondary-text":"rgb(var(--${prefix}-color-secondary-text))","color-tertiary-text":"rgb(var(--${prefix}-color-tertiary-text))","color-primary-border":"rgb(var(--${prefix}-color-primary-border))","color-brand":"rgb(var(--${prefix}-color-brand))","color-brand-hover":"rgb(var(--${prefix}-color-brand-hover))","color-brand-active":"rgb(var(--${prefix}-color-brand-active))","color-on-brand":"#ffffff","color-progress-track":"rgb(var(--${prefix}-color-primary-border) / 0.5)","color-bg-container":"rgb(var(--${prefix}-color-bg-container))","font-sans":'var(--font-inter), ui-sans-serif, system-ui, "PingFang SC", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans SC", sans-serif',"animate-dashboard-skeleton-shimmer":"dashboard-skeleton-shimmer 1.6s ease-in-out infinite"};function w(r,e){return e?`:root, html[data-theme="${r}"], [data-theme="${r}"]`:`html[data-theme="${r}"], [data-theme="${r}"]`}var S={prefix:"fe",themes:{},tokenMapping:l,cssSelector:w};function g(r){let e=d(C,r?.themes||{}),o=d(l,r?.tokenMapping||{}),t=Object.assign({},S,r,{themes:e,tokenMapping:o});return!t.defaultTheme&&t.themes&&(t.defaultTheme=Object.keys(t.themes)[0]),t}function f(r={}){let e=g(r),{prefix:o,themes:t,cssSelector:a,defaultTheme:n}=e,c="";for(let[i,h]of Object.entries(t)){let u=a(i,i===n),V=x(o,i),P={...h,...V};c+=`${u} {
2
- `;for(let[R,F]of Object.entries(P))c+=` --${o}-${R}: ${F};
3
- `;c+=`}
1
+ "use strict";var d=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var S=Object.prototype.hasOwnProperty;var w=(r,o)=>{for(var t in o)d(r,t,{get:o[t],enumerable:!0})},R=(r,o,t,a)=>{if(o&&typeof o=="object"||typeof o=="function")for(let e of C(o))!S.call(r,e)&&e!==t&&d(r,e,{get:()=>o[e],enumerable:!(a=O(o,e))||a.enumerable});return r};var U=r=>R(d({},"__esModule",{value:!0}),r);var B={};w(B,{builtinThemes:()=>f,defaultConfig:()=>b,defaultTokenMapping:()=>l,generateLayerBaseCSS:()=>x,generateThemeBlockCSS:()=>h,generateThemeCSS:()=>V,getConfig:()=>p,getDefaultSelector:()=>y,getDerivedTokens:()=>m});module.exports=U(B);function g(r,o){return r.replace(/\$\{prefix\}/g,o)}function s(r,o){let t={...r};for(let a in o)if(Object.prototype.hasOwnProperty.call(o,a)){let e=o[a],c=t[a];e&&typeof e=="object"&&!Array.isArray(e)&&c&&typeof c=="object"?t[a]=s(c,e):t[a]=e}return t}var j={light:"0.08",dark:"0.12",pink:"0.12",amber:"0.12",forest:"0.1",ocean:"0.1"},f={light:{"color-primary":"246 248 250","color-secondary":"255 255 255","color-elevated":"240 242 244","color-primary-text":"31 35 40","color-primary-text-hover":"101 109 118","color-secondary-text":"101 109 118","color-tertiary-text":"140 149 159","color-primary-border":"208 215 222","color-brand":"124 58 237","color-brand-hover":"109 40 217","color-brand-active":"91 33 182","color-success":"#1a7f37","color-warning":"#faad14","color-error":"#cf222e","border-radius":"6px"},dark:{"color-primary":"15 17 21","color-secondary":"22 27 34","color-elevated":"33 38 45","color-primary-text":"230 237 243","color-primary-text-hover":"139 148 158","color-secondary-text":"139 148 158","color-tertiary-text":"110 118 129","color-primary-border":"48 54 61","color-brand":"139 92 246","color-brand-hover":"124 58 237","color-brand-active":"109 40 217","color-success":"#3fb950","color-warning":"#faad14","color-error":"#f85149","border-radius":"6px"},pink:{"color-primary":"26 13 20","color-secondary":"37 16 27","color-elevated":"48 21 34","color-primary-text":"252 232 240","color-primary-text-hover":"196 144 168","color-secondary-text":"196 144 168","color-tertiary-text":"138 88 112","color-primary-border":"92 45 66","color-brand":"244 114 182","color-brand-hover":"236 72 153","color-brand-active":"219 39 119","color-success":"#34d399","color-warning":"#faad14","color-error":"#fb7185","border-radius":"8px"},amber:{"color-primary":"30 18 0","color-secondary":"40 26 0","color-elevated":"50 31 0","color-primary-text":"242 232 213","color-primary-text-hover":"184 166 138","color-secondary-text":"184 166 138","color-tertiary-text":"122 106 86","color-primary-border":"74 56 0","color-brand":"232 148 58","color-brand-hover":"208 120 40","color-brand-active":"180 100 30","color-success":"#5aad6e","color-warning":"#faad14","color-error":"#c85a4a","border-radius":"6px"},forest:{"color-primary":"6 21 8","color-secondary":"12 31 14","color-elevated":"19 39 22","color-primary-text":"216 240 220","color-primary-text-hover":"136 173 142","color-secondary-text":"136 173 142","color-tertiary-text":"90 122 94","color-primary-border":"44 66 48","color-brand":"74 222 128","color-brand-hover":"34 197 94","color-brand-active":"22 163 74","color-success":"#86efac","color-warning":"#faad14","color-error":"#f87171","border-radius":"6px"},ocean:{"color-primary":"6 14 26","color-secondary":"13 26 46","color-elevated":"18 36 62","color-primary-text":"218 238 255","color-primary-text-hover":"122 181 212","color-secondary-text":"122 181 212","color-tertiary-text":"74 126 154","color-primary-border":"30 58 92","color-brand":"56 189 248","color-brand-hover":"14 165 233","color-brand-active":"2 132 199","color-success":"#34d399","color-warning":"#faad14","color-error":"#f87171","border-radius":"6px"}},m=(r,o)=>{let t=o?j[o]??"0.1":"0.1";return{"color-bg-container":`rgb(var(--${r}-color-secondary))`,"color-text":`rgb(var(--${r}-color-primary-text) / 0.85)`,"color-text-heading":`rgb(var(--${r}-color-primary-text))`,"color-text-disabled":`rgb(var(--${r}-color-primary-text) / 0.25)`,"color-primary-hover":`rgb(var(--${r}-color-brand-hover))`,"color-primary-active":`rgb(var(--${r}-color-brand-active))`,"color-primary-bg":`rgb(var(--${r}-color-brand) / ${t})`,"line-height":"1.5715"}},l={"color-primary":"rgb(var(--${prefix}-color-primary))","color-primary-active":"rgb(var(--${prefix}-color-primary-active))","color-primary-hover":"rgb(var(--${prefix}-color-primary-hover))","color-primary-bg":"rgb(var(--${prefix}-color-primary-bg))","color-secondary":"rgb(var(--${prefix}-color-secondary))","color-elevated":"rgb(var(--${prefix}-color-elevated))","color-primary-text":"rgb(var(--${prefix}-color-primary-text))","color-primary-text-hover":"rgb(var(--${prefix}-color-primary-text-hover))","color-secondary-text":"rgb(var(--${prefix}-color-secondary-text))","color-tertiary-text":"rgb(var(--${prefix}-color-tertiary-text))","color-primary-border":"rgb(var(--${prefix}-color-primary-border))","color-brand":"rgb(var(--${prefix}-color-brand))","color-brand-hover":"rgb(var(--${prefix}-color-brand-hover))","color-brand-active":"rgb(var(--${prefix}-color-brand-active))","color-on-brand":"#ffffff","color-progress-track":"rgb(var(--${prefix}-color-primary-border) / 0.5)","color-bg-container":"rgb(var(--${prefix}-color-bg-container))","font-sans":'var(--font-inter), ui-sans-serif, system-ui, "PingFang SC", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans SC", sans-serif',"animate-dashboard-skeleton-shimmer":"dashboard-skeleton-shimmer 1.6s ease-in-out infinite"};function y(r,o){return o?`:root, html[data-theme="${r}"], [data-theme="${r}"]`:`html[data-theme="${r}"], [data-theme="${r}"]`}var b={prefix:"fe",themes:{},tokenMapping:l,cssSelector:y};function p(r){let o=s(f,r?.themes||{}),t=r?.includeThemes;if(t?.length){let c={};for(let n of t)o[n]&&(c[n]=o[n]);o=c}let a=s(l,r?.tokenMapping||{}),e=Object.assign({},b,r,{themes:o,tokenMapping:a,includeThemes:t??[]});return(!e.defaultTheme||!e.themes[e.defaultTheme])&&(e.defaultTheme=Object.keys(e.themes)[0]),e}function x(r={}){let o=p(r),{prefix:t,themes:a,cssSelector:e,defaultTheme:c}=o,n="";for(let[i,v]of Object.entries(a)){let u=e(i,i===c),T=m(t,i),$={...v,...T};n+=`${u} {
2
+ `;for(let[k,M]of Object.entries($))n+=` --${t}-${k}: ${M};
3
+ `;n+=`}
4
4
 
5
- `}return c}function y(r={}){let e=g(r),{prefix:o,tokenMapping:t=l}=e,a=`@theme {
6
- `;for(let[n,c]of Object.entries(t)){let i=O(c,o);a+=` --${n}: ${i};
7
- `}return a+=`}
8
- `,a}function v(r={}){let e="",o=f(r);return o&&(e+=`@layer base {
9
- `+o+`}
5
+ `}return n}function h(r={}){let o=p(r),{prefix:t,tokenMapping:a=l}=o,e=`@theme {
6
+ `;for(let[c,n]of Object.entries(a)){let i=g(n,t);e+=` --${c}: ${i};
7
+ `}return e+=`}
8
+ `,e}function V(r={}){let o="",t=x(r);return t&&(o+=`@layer base {
9
+ `+t+`}
10
10
 
11
- `),e+=y(r),e}var p=$(require("fs"),1),s=$(require("path"),1);var T={"layer-base":"theme-layer-base.css","theme-block":"theme-block.css",full:"theme.css"};function M(r,e){switch(r){case"layer-base":{let o=f(e);return o?`@layer base {
12
- ${o}}
13
- `:""}case"theme-block":return y(e);case"full":return v(e);default:return r}}async function U(r,e,o){if(p.default.existsSync(r))if(o)console.warn(`\u26A0\uFE0F Warning: File already exists at ${r}. It will be overwritten.`);else throw new Error(`File already exists at ${r} and overwrite is set to false.`);let t=s.default.dirname(r);p.default.existsSync(t)||p.default.mkdirSync(t,{recursive:!0}),await p.default.promises.writeFile(r,e,"utf-8"),console.log(`\u2705 Theme CSS generated at ${r}`)}function L(r,e){return e.outputPath?s.default.resolve(process.cwd(),e.outputPath):s.default.resolve(process.cwd(),T[r])}async function q(r={}){let{variant:e="full",overwrite:o=!0,outputPath:t,...a}=r,n=t?s.default.resolve(process.cwd(),t):L(e,r),c=M(e,a);return await U(n,c,o),n}async function I(r={}){let{outputDir:e=".",outputPaths:o={},overwrite:t=!0,...a}=r,n=Object.keys(T),c={};for(let i of n){let h=o[i]??s.default.join(e,T[i]),b=s.default.resolve(process.cwd(),h),u=M(i,a);await U(b,u,t),c[i]=b}return c}0&&(module.exports={builtinThemes,defaultConfig,defaultTokenMapping,generateLayerBaseCSS,generateThemeBlockCSS,generateThemeCSS,generateThemeFile,generateThemeFiles,getConfig,getDefaultSelector,getDerivedTokens});
11
+ `),o+=h(r),o}0&&(module.exports={builtinThemes,defaultConfig,defaultTokenMapping,generateLayerBaseCSS,generateThemeBlockCSS,generateThemeCSS,getConfig,getDefaultSelector,getDerivedTokens});
package/dist/index.d.ts CHANGED
@@ -33,6 +33,11 @@ interface UiThemeOptions {
33
33
  prefix?: string;
34
34
  defaultTheme?: string;
35
35
  themes?: ThemesMap;
36
+ /**
37
+ * When set, only these theme names are emitted (after merging builtins).
38
+ * Use to keep app CSS small when the package ships extra demo themes.
39
+ */
40
+ includeThemes?: string[];
36
41
  tokenMapping?: TokenMapping;
37
42
  cssSelector?: (themeName: string, root: boolean) => string;
38
43
  outputPath?: string;
@@ -64,25 +69,4 @@ declare function generateThemeBlockCSS(options?: UiThemeOptions): string;
64
69
  */
65
70
  declare function generateThemeCSS(options?: UiThemeOptions): string;
66
71
 
67
- /** CSS variant aligned with {@link core.ts} generators */
68
- type ThemeCssVariant = 'layer-base' | 'theme-block' | 'full';
69
- interface GenerateThemeFileOptions extends UiThemeOptions {
70
- /** Which CSS generator to use. Default: `full` */
71
- variant?: ThemeCssVariant;
72
- }
73
- interface GenerateThemeFilesOptions extends UiThemeOptions {
74
- /** Directory for default output file names. Default: `.` (cwd) */
75
- outputDir?: string;
76
- /** Override output path per variant (relative to cwd unless absolute) */
77
- outputPaths?: Partial<Record<ThemeCssVariant, string>>;
78
- }
79
- /**
80
- * Write theme CSS to a file using the selected core generator variant.
81
- */
82
- declare function generateThemeFile(options?: GenerateThemeFileOptions): Promise<string>;
83
- /**
84
- * Write all three theme CSS variants (layer-base, theme-block, full) to files.
85
- */
86
- declare function generateThemeFiles(options?: GenerateThemeFilesOptions): Promise<Record<ThemeCssVariant, string>>;
87
-
88
- export { type ColorValue, type GenerateThemeFileOptions, type GenerateThemeFilesOptions, type RGBChannels, type ThemeCssVariant, type ThemeTokens, type ThemesMap, type TokenMapping, type UiThemeOptions, builtinThemes, defaultConfig, defaultTokenMapping, generateLayerBaseCSS, generateThemeBlockCSS, generateThemeCSS, generateThemeFile, generateThemeFiles, getConfig, getDefaultSelector, getDerivedTokens };
72
+ export { type ColorValue, type RGBChannels, type ThemeTokens, type ThemesMap, type TokenMapping, type UiThemeOptions, builtinThemes, defaultConfig, defaultTokenMapping, generateLayerBaseCSS, generateThemeBlockCSS, generateThemeCSS, getConfig, getDefaultSelector, getDerivedTokens };
package/dist/index.js CHANGED
@@ -182,7 +182,17 @@ var defaultConfig = {
182
182
  cssSelector: getDefaultSelector
183
183
  };
184
184
  function getConfig(options) {
185
- const allThemes = deepMerge(builtinThemes, options?.themes || {});
185
+ let allThemes = deepMerge(builtinThemes, options?.themes || {});
186
+ const includeThemes = options?.includeThemes;
187
+ if (includeThemes?.length) {
188
+ const filtered = {};
189
+ for (const name of includeThemes) {
190
+ if (allThemes[name]) {
191
+ filtered[name] = allThemes[name];
192
+ }
193
+ }
194
+ allThemes = filtered;
195
+ }
186
196
  const allMappings = deepMerge(
187
197
  defaultTokenMapping,
188
198
  options?.tokenMapping || {}
@@ -193,10 +203,11 @@ function getConfig(options) {
193
203
  options,
194
204
  {
195
205
  themes: allThemes,
196
- tokenMapping: allMappings
206
+ tokenMapping: allMappings,
207
+ includeThemes: includeThemes ?? []
197
208
  }
198
209
  );
199
- if (!config.defaultTheme && config.themes) {
210
+ if (!config.defaultTheme || !config.themes[config.defaultTheme]) {
200
211
  config.defaultTheme = Object.keys(config.themes)[0];
201
212
  }
202
213
  return config;
@@ -246,88 +257,6 @@ function generateThemeCSS(options = {}) {
246
257
  css += generateThemeBlockCSS(options);
247
258
  return css;
248
259
  }
249
-
250
- // src/generater.ts
251
- import fs from "fs";
252
- import path from "path";
253
- var DEFAULT_OUTPUT_PATHS = {
254
- "layer-base": "theme-layer-base.css",
255
- "theme-block": "theme-block.css",
256
- full: "theme.css"
257
- };
258
- function resolveCssContent(variant, options) {
259
- switch (variant) {
260
- case "layer-base": {
261
- const layerBaseContent = generateLayerBaseCSS(options);
262
- return layerBaseContent ? `@layer base {
263
- ${layerBaseContent}}
264
- ` : "";
265
- }
266
- case "theme-block":
267
- return generateThemeBlockCSS(options);
268
- case "full":
269
- return generateThemeCSS(options);
270
- default: {
271
- const _exhaustive = variant;
272
- return _exhaustive;
273
- }
274
- }
275
- }
276
- async function writeCssFile(absolutePath, css, overwrite) {
277
- if (fs.existsSync(absolutePath)) {
278
- if (overwrite) {
279
- console.warn(
280
- `\u26A0\uFE0F Warning: File already exists at ${absolutePath}. It will be overwritten.`
281
- );
282
- } else {
283
- throw new Error(
284
- `File already exists at ${absolutePath} and overwrite is set to false.`
285
- );
286
- }
287
- }
288
- const dir = path.dirname(absolutePath);
289
- if (!fs.existsSync(dir)) {
290
- fs.mkdirSync(dir, { recursive: true });
291
- }
292
- await fs.promises.writeFile(absolutePath, css, "utf-8");
293
- console.log(`\u2705 Theme CSS generated at ${absolutePath}`);
294
- }
295
- function resolveOutputPath(variant, options) {
296
- if (options.outputPath) {
297
- return path.resolve(process.cwd(), options.outputPath);
298
- }
299
- return path.resolve(process.cwd(), DEFAULT_OUTPUT_PATHS[variant]);
300
- }
301
- async function generateThemeFile(options = {}) {
302
- const {
303
- variant = "full",
304
- overwrite = true,
305
- outputPath,
306
- ...restOptions
307
- } = options;
308
- const absolutePath = outputPath ? path.resolve(process.cwd(), outputPath) : resolveOutputPath(variant, options);
309
- const css = resolveCssContent(variant, restOptions);
310
- await writeCssFile(absolutePath, css, overwrite);
311
- return absolutePath;
312
- }
313
- async function generateThemeFiles(options = {}) {
314
- const {
315
- outputDir = ".",
316
- outputPaths = {},
317
- overwrite = true,
318
- ...restOptions
319
- } = options;
320
- const variants = Object.keys(DEFAULT_OUTPUT_PATHS);
321
- const result = {};
322
- for (const variant of variants) {
323
- const relativePath = outputPaths[variant] ?? path.join(outputDir, DEFAULT_OUTPUT_PATHS[variant]);
324
- const absolutePath = path.resolve(process.cwd(), relativePath);
325
- const css = resolveCssContent(variant, restOptions);
326
- await writeCssFile(absolutePath, css, overwrite);
327
- result[variant] = absolutePath;
328
- }
329
- return result;
330
- }
331
260
  export {
332
261
  builtinThemes,
333
262
  defaultConfig,
@@ -335,8 +264,6 @@ export {
335
264
  generateLayerBaseCSS,
336
265
  generateThemeBlockCSS,
337
266
  generateThemeCSS,
338
- generateThemeFile,
339
- generateThemeFiles,
340
267
  getConfig,
341
268
  getDefaultSelector,
342
269
  getDerivedTokens
package/dist/plugin.cjs CHANGED
@@ -208,7 +208,17 @@ var defaultConfig = {
208
208
  cssSelector: getDefaultSelector
209
209
  };
210
210
  function getConfig(options) {
211
- const allThemes = deepMerge(builtinThemes, options?.themes || {});
211
+ let allThemes = deepMerge(builtinThemes, options?.themes || {});
212
+ const includeThemes = options?.includeThemes;
213
+ if (includeThemes?.length) {
214
+ const filtered = {};
215
+ for (const name of includeThemes) {
216
+ if (allThemes[name]) {
217
+ filtered[name] = allThemes[name];
218
+ }
219
+ }
220
+ allThemes = filtered;
221
+ }
212
222
  const allMappings = deepMerge(
213
223
  defaultTokenMapping,
214
224
  options?.tokenMapping || {}
@@ -219,10 +229,11 @@ function getConfig(options) {
219
229
  options,
220
230
  {
221
231
  themes: allThemes,
222
- tokenMapping: allMappings
232
+ tokenMapping: allMappings,
233
+ includeThemes: includeThemes ?? []
223
234
  }
224
235
  );
225
- if (!config.defaultTheme && config.themes) {
236
+ if (!config.defaultTheme || !config.themes[config.defaultTheme]) {
226
237
  config.defaultTheme = Object.keys(config.themes)[0];
227
238
  }
228
239
  return config;
package/dist/plugin.d.cts CHANGED
@@ -35,6 +35,11 @@ interface UiThemeOptions {
35
35
  prefix?: string;
36
36
  defaultTheme?: string;
37
37
  themes?: ThemesMap;
38
+ /**
39
+ * When set, only these theme names are emitted (after merging builtins).
40
+ * Use to keep app CSS small when the package ships extra demo themes.
41
+ */
42
+ includeThemes?: string[];
38
43
  tokenMapping?: TokenMapping;
39
44
  cssSelector?: (themeName: string, root: boolean) => string;
40
45
  outputPath?: string;
package/dist/plugin.d.ts CHANGED
@@ -35,6 +35,11 @@ interface UiThemeOptions {
35
35
  prefix?: string;
36
36
  defaultTheme?: string;
37
37
  themes?: ThemesMap;
38
+ /**
39
+ * When set, only these theme names are emitted (after merging builtins).
40
+ * Use to keep app CSS small when the package ships extra demo themes.
41
+ */
42
+ includeThemes?: string[];
38
43
  tokenMapping?: TokenMapping;
39
44
  cssSelector?: (themeName: string, root: boolean) => string;
40
45
  outputPath?: string;
package/dist/plugin.js CHANGED
@@ -182,7 +182,17 @@ var defaultConfig = {
182
182
  cssSelector: getDefaultSelector
183
183
  };
184
184
  function getConfig(options) {
185
- const allThemes = deepMerge(builtinThemes, options?.themes || {});
185
+ let allThemes = deepMerge(builtinThemes, options?.themes || {});
186
+ const includeThemes = options?.includeThemes;
187
+ if (includeThemes?.length) {
188
+ const filtered = {};
189
+ for (const name of includeThemes) {
190
+ if (allThemes[name]) {
191
+ filtered[name] = allThemes[name];
192
+ }
193
+ }
194
+ allThemes = filtered;
195
+ }
186
196
  const allMappings = deepMerge(
187
197
  defaultTokenMapping,
188
198
  options?.tokenMapping || {}
@@ -193,10 +203,11 @@ function getConfig(options) {
193
203
  options,
194
204
  {
195
205
  themes: allThemes,
196
- tokenMapping: allMappings
206
+ tokenMapping: allMappings,
207
+ includeThemes: includeThemes ?? []
197
208
  }
198
209
  );
199
- if (!config.defaultTheme && config.themes) {
210
+ if (!config.defaultTheme || !config.themes[config.defaultTheme]) {
200
211
  config.defaultTheme = Object.keys(config.themes)[0];
201
212
  }
202
213
  return config;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qlover/tailwind-theme",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "main": "./dist/index.js",
@@ -18,6 +18,11 @@
18
18
  "import": "./dist/plugin.js",
19
19
  "require": "./dist/plugin.cjs"
20
20
  },
21
+ "./generater": {
22
+ "types": "./dist/generater.d.ts",
23
+ "import": "./dist/generater.js",
24
+ "require": "./dist/generater.cjs"
25
+ },
21
26
  "./theme.css": "./dist/theme.css",
22
27
  "./theme-layer-base.css": "./dist/theme-layer-base.css",
23
28
  "./theme-block.css": "./dist/theme-block.css"
@@ -47,7 +52,7 @@
47
52
  "access": "public"
48
53
  },
49
54
  "dependencies": {
50
- "postcss": "^8.5.14"
55
+ "postcss": "^8.5.28"
51
56
  },
52
57
  "scripts": {
53
58
  "lint": "eslint src --fix",