@veltra/styles 1.0.9 → 1.0.11
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.js +5 -5
- package/dist/theme/ui-theme.d.ts +1 -4
- package/dist/theme/ui-theme.js +2 -30
- package/dist/theme/ui-theme.js.map +1 -1
- package/package.json +5 -5
- package/src/theme/ui-theme.ts +2 -42
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import "./normalize.css";
|
|
2
|
+
import "./anime/fade.css";
|
|
3
|
+
import "./anime/slide.css";
|
|
4
|
+
import "./anime/spring.css";
|
|
5
|
+
import "./anime/zoom-in.css";
|
package/dist/theme/ui-theme.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { Theme } from "./type.js";
|
|
|
4
4
|
type RecursivePartial<T> = { [P in keyof T]?: T[P] extends object ? RecursivePartial<T[P]> : T[P] };
|
|
5
5
|
declare class UITheme {
|
|
6
6
|
static themeID: string;
|
|
7
|
-
private static legacyDeprecationWarned;
|
|
8
7
|
private static adoptedSheet;
|
|
9
8
|
readonly theme: Theme;
|
|
10
9
|
private readonly reactiveEnabled;
|
|
@@ -18,10 +17,8 @@ declare class UITheme {
|
|
|
18
17
|
private renderShadow;
|
|
19
18
|
private renderBGColorAlpha;
|
|
20
19
|
private renderBGFilter;
|
|
21
|
-
/**
|
|
20
|
+
/** 主题变量声明列表,均为 `--u-` 前缀的 CSS 自定义属性 */
|
|
22
21
|
themeToDeclarationList(theme: Theme): string[];
|
|
23
|
-
private static withLegacyDuplicates;
|
|
24
|
-
private static warnLegacyOnce;
|
|
25
22
|
private static declarationBlock;
|
|
26
23
|
private static removeExistingStyleTag;
|
|
27
24
|
private static applyGlobalCSS;
|
package/dist/theme/ui-theme.js
CHANGED
|
@@ -4,18 +4,8 @@ import { isObj, o, str } from "@cat-kit/core";
|
|
|
4
4
|
import { withUnit } from "@veltra/utils";
|
|
5
5
|
import { reactive, toRaw, watch } from "vue";
|
|
6
6
|
//#region src/theme/ui-theme.ts
|
|
7
|
-
function isDevEnv() {
|
|
8
|
-
try {
|
|
9
|
-
if (typeof import.meta !== "undefined") {
|
|
10
|
-
if (import.meta.env?.DEV === true) return true;
|
|
11
|
-
}
|
|
12
|
-
} catch {}
|
|
13
|
-
const proc = globalThis.process;
|
|
14
|
-
return typeof proc !== "undefined" && proc.env?.NODE_ENV !== "production";
|
|
15
|
-
}
|
|
16
7
|
var UITheme = class UITheme {
|
|
17
8
|
static themeID = "ultra-ui-theme";
|
|
18
|
-
static legacyDeprecationWarned = false;
|
|
19
9
|
static adoptedSheet = null;
|
|
20
10
|
theme;
|
|
21
11
|
reactiveEnabled;
|
|
@@ -79,7 +69,7 @@ var UITheme = class UITheme {
|
|
|
79
69
|
const { filter } = theme.bg;
|
|
80
70
|
return `--u-bg-filter: ${filter.blur} ${filter.saturate}`;
|
|
81
71
|
}
|
|
82
|
-
/**
|
|
72
|
+
/** 主题变量声明列表,均为 `--u-` 前缀的 CSS 自定义属性 */
|
|
83
73
|
themeToDeclarationList(theme) {
|
|
84
74
|
const raw = theme;
|
|
85
75
|
const lines = [...this.renderBase(raw)];
|
|
@@ -93,26 +83,8 @@ var UITheme = class UITheme {
|
|
|
93
83
|
for (const c of chunks) lines.push(...c.split(";").map((s) => s.trim()).filter(Boolean));
|
|
94
84
|
return lines;
|
|
95
85
|
}
|
|
96
|
-
static withLegacyDuplicates(decls) {
|
|
97
|
-
const legacy = [];
|
|
98
|
-
for (const decl of decls) {
|
|
99
|
-
const idx = decl.indexOf(":");
|
|
100
|
-
if (idx === -1) continue;
|
|
101
|
-
const name = decl.slice(0, idx).trim();
|
|
102
|
-
const value = decl.slice(idx + 1).trim();
|
|
103
|
-
if (name.startsWith("--u-")) legacy.push(`--${name.slice(4)}: ${value}`);
|
|
104
|
-
}
|
|
105
|
-
return [...decls, ...legacy].join(";");
|
|
106
|
-
}
|
|
107
|
-
static warnLegacyOnce() {
|
|
108
|
-
if (!isDevEnv() || UITheme.legacyDeprecationWarned) return;
|
|
109
|
-
UITheme.legacyDeprecationWarned = true;
|
|
110
|
-
console.warn("[@veltra/styles] Theme CSS variables now prefer the `--u-` namespace. Unprefixed aliases (e.g. `--color-primary`) are deprecated and will be removed in a future major version.");
|
|
111
|
-
}
|
|
112
86
|
static declarationBlock(decls) {
|
|
113
|
-
|
|
114
|
-
UITheme.warnLegacyOnce();
|
|
115
|
-
return merged;
|
|
87
|
+
return decls.join(";");
|
|
116
88
|
}
|
|
117
89
|
static removeExistingStyleTag(doc) {
|
|
118
90
|
const el = doc.getElementById(UITheme.themeID);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui-theme.js","names":[],"sources":["../../src/theme/ui-theme.ts"],"sourcesContent":["import { isObj, o, str } from '@cat-kit/core'\nimport { withUnit } from '@veltra/utils'\nimport { reactive, toRaw, watch } from 'vue'\n\nimport { componentCssVarsDarkDecls, componentCssVarsLightDecls } from './component-css-vars'\nimport { mixColor } from './helper'\nimport type { Theme } from './type'\n\ntype RecursivePartial<T> = {\n [P in keyof T]?: T[P] extends object ? RecursivePartial<T[P]> : T[P]\n}\n\nfunction isDevEnv(): boolean {\n try {\n if (typeof import.meta !== 'undefined') {\n const env = (import.meta as { env?: { DEV?: boolean } }).env\n if (env?.DEV === true) return true\n }\n } catch {\n /* ignore */\n }\n const proc = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process\n return typeof proc !== 'undefined' && proc.env?.NODE_ENV !== 'production'\n}\n\nexport class UITheme {\n static themeID = 'ultra-ui-theme'\n\n private static legacyDeprecationWarned = false\n\n private static adoptedSheet: CSSStyleSheet | null = null\n\n readonly theme: Theme\n\n private readonly reactiveEnabled: boolean\n\n constructor(theme: Theme, options?: { reactive?: boolean }) {\n this.reactiveEnabled = options?.reactive !== false\n this.theme = reactive(theme) as Theme\n if (this.reactiveEnabled) {\n watch(this.theme, () => this.render(), { deep: true })\n }\n }\n\n static setTheme(mode: 'light' | 'dark' | 'auto'): void {\n if (typeof document === 'undefined') return\n const el = document.documentElement\n if (mode === 'auto') {\n delete el.dataset.theme\n } else {\n el.dataset.theme = mode\n }\n }\n\n private renderBase(\n theme: Record<string, unknown>,\n themeRules: string[] = [],\n parentKey = '--u'\n ): string[] {\n Object.keys(theme).forEach((key) => {\n const value = theme[key]\n const varKey = `${parentKey.startsWith('-') ? parentKey : str(parentKey).kebabCase()}-${str(key).kebabCase()}`\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n this.renderBase(value as Record<string, unknown>, themeRules, varKey)\n } else {\n if (value || value === 0) {\n const v = withUnit(value as number | string, 'px')\n if (v !== undefined) {\n themeRules.push(`${varKey}: ${v}`)\n }\n }\n }\n })\n\n return themeRules\n }\n\n private renderBorder(theme: Theme): string {\n const border = Object.keys(theme.border)\n .map((key) => `var(--u-border-${key})`)\n .join(' ')\n\n return `--u-border: ${border}`\n }\n\n private renderTypeColor(theme: Theme): string {\n const { color } = theme\n\n const types = Object.keys(color)\n const rates = [1, 3, 5, 7, 9]\n\n return types\n .map((type) => {\n const colorValue = color[type as keyof typeof color]! as `#${string}`\n\n return rates\n .map((rate) => {\n const light = `--u-color-${type}-light-${rate}: ${mixColor(\n colorValue,\n '#fff',\n rate / 10\n )}`\n const dark = `--u-color-${type}-dark-${rate}: ${mixColor(\n colorValue,\n '#000',\n rate / 10\n )}`\n return `${light};${dark}`\n })\n .join(';')\n })\n .join(';')\n }\n\n private renderShadow(_theme: Theme): string {\n const shadow = ['x', 'y', 'blur', 'spread', 'color']\n .map((k) => `var(--u-shadow-${k})`)\n .join(' ')\n\n return `--u-shadow: ${shadow}`\n }\n\n private renderBGColorAlpha(theme: Theme): string {\n const { color } = theme.bg\n return Object.keys(color)\n .map((type) => `--u-bg-color-${type}-alpha: ${color[type as keyof typeof color]}aa`)\n .join(';')\n }\n\n private renderBGFilter(theme: Theme): string {\n const { filter } = theme.bg\n return `--u-bg-filter: ${filter.blur} ${filter.saturate}`\n }\n\n /** 主题变量声明(不含 legacy 副本) */\n themeToDeclarationList(theme: Theme): string[] {\n const raw = theme as unknown as Record<string, unknown>\n const lines: string[] = [...this.renderBase(raw)]\n const chunks = [\n this.renderTypeColor(theme),\n this.renderShadow(theme),\n this.renderBGColorAlpha(theme),\n this.renderBGFilter(theme),\n this.renderBorder(theme)\n ]\n for (const c of chunks) {\n lines.push(\n ...c\n .split(';')\n .map((s) => s.trim())\n .filter(Boolean)\n )\n }\n return lines\n }\n\n private static withLegacyDuplicates(decls: string[]): string {\n const legacy: string[] = []\n for (const decl of decls) {\n const idx = decl.indexOf(':')\n if (idx === -1) continue\n const name = decl.slice(0, idx).trim()\n const value = decl.slice(idx + 1).trim()\n if (name.startsWith('--u-')) {\n legacy.push(`--${name.slice(4)}: ${value}`)\n }\n }\n return [...decls, ...legacy].join(';')\n }\n\n private static warnLegacyOnce(): void {\n if (!isDevEnv() || UITheme.legacyDeprecationWarned) return\n UITheme.legacyDeprecationWarned = true\n console.warn(\n '[@veltra/styles] Theme CSS variables now prefer the `--u-` namespace. ' +\n 'Unprefixed aliases (e.g. `--color-primary`) are deprecated and will be removed in a future major version.'\n )\n }\n\n private static declarationBlock(decls: string[]): string {\n const merged = UITheme.withLegacyDuplicates(decls)\n UITheme.warnLegacyOnce()\n return merged\n }\n\n private static removeExistingStyleTag(doc: Document): void {\n const el = doc.getElementById(UITheme.themeID)\n if (el?.parentNode) {\n el.parentNode.removeChild(el)\n }\n }\n\n private static applyGlobalCSS(css: string): void {\n const doc = typeof document !== 'undefined' ? document : undefined\n if (!doc) return\n\n const canAdopt =\n typeof CSSStyleSheet !== 'undefined' && 'adoptedStyleSheets' in Document.prototype\n\n if (canAdopt) {\n UITheme.removeExistingStyleTag(doc)\n if (!UITheme.adoptedSheet) {\n UITheme.adoptedSheet = new CSSStyleSheet()\n doc.adoptedStyleSheets = [...doc.adoptedStyleSheets, UITheme.adoptedSheet]\n }\n UITheme.adoptedSheet.replaceSync(css)\n } else {\n if (UITheme.adoptedSheet) {\n UITheme.adoptedSheet = null\n }\n let style = doc.getElementById(UITheme.themeID)\n if (!style) {\n style = doc.createElement('style')\n style.id = UITheme.themeID\n doc.head.appendChild(style)\n }\n style.textContent = css\n }\n }\n\n /** 内置 light/dark:支持 data-theme 与 prefers-color-scheme */\n static injectBuiltInThemes(light: UITheme, dark: UITheme): void {\n const lightDecls = [\n ...light.themeToDeclarationList(toRaw(light.theme)),\n ...componentCssVarsLightDecls\n ]\n const darkDecls = [\n ...dark.themeToDeclarationList(toRaw(dark.theme)),\n ...componentCssVarsDarkDecls\n ]\n const lightBlock = UITheme.declarationBlock(lightDecls)\n const darkBlock = UITheme.declarationBlock(darkDecls)\n\n const css = [\n `html { ${lightBlock} }`,\n `@media (prefers-color-scheme: dark) {`,\n ` html:not([data-theme=\"light\"]) { ${darkBlock} }`,\n `}`,\n `html[data-theme=\"light\"] { ${lightBlock} }`,\n `html[data-theme=\"dark\"] { ${darkBlock} }`\n ].join('\\n')\n\n UITheme.applyGlobalCSS(css)\n }\n\n render(): void {\n const decls = [...this.themeToDeclarationList(toRaw(this.theme)), ...componentCssVarsLightDecls]\n const block = UITheme.declarationBlock(decls)\n const css = `html { ${block} }`\n UITheme.applyGlobalCSS(css)\n }\n\n new(customTheme: RecursivePartial<Theme> = {}): UITheme {\n function delEmpty(obj: Record<string, unknown>) {\n Object.keys(obj).forEach((key) => {\n const value = obj[key]\n if (isObj(value)) {\n return delEmpty(value as Record<string, unknown>)\n }\n if (!value && value !== 0) {\n delete obj[key]\n }\n })\n }\n\n delEmpty(customTheme as Record<string, unknown>)\n\n const base = JSON.parse(JSON.stringify(toRaw(this.theme))) as Record<string, any>\n o(base).deepExtend(customTheme as Record<string, any>)\n return new UITheme(base as Theme, { reactive: this.reactiveEnabled })\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ui-theme.js","names":[],"sources":["../../src/theme/ui-theme.ts"],"sourcesContent":["import { isObj, o, str } from '@cat-kit/core'\nimport { withUnit } from '@veltra/utils'\nimport { reactive, toRaw, watch } from 'vue'\n\nimport { componentCssVarsDarkDecls, componentCssVarsLightDecls } from './component-css-vars'\nimport { mixColor } from './helper'\nimport type { Theme } from './type'\n\ntype RecursivePartial<T> = {\n [P in keyof T]?: T[P] extends object ? RecursivePartial<T[P]> : T[P]\n}\n\nexport class UITheme {\n static themeID = 'ultra-ui-theme'\n\n private static adoptedSheet: CSSStyleSheet | null = null\n\n readonly theme: Theme\n\n private readonly reactiveEnabled: boolean\n\n constructor(theme: Theme, options?: { reactive?: boolean }) {\n this.reactiveEnabled = options?.reactive !== false\n this.theme = reactive(theme) as Theme\n if (this.reactiveEnabled) {\n watch(this.theme, () => this.render(), { deep: true })\n }\n }\n\n static setTheme(mode: 'light' | 'dark' | 'auto'): void {\n if (typeof document === 'undefined') return\n const el = document.documentElement\n if (mode === 'auto') {\n delete el.dataset.theme\n } else {\n el.dataset.theme = mode\n }\n }\n\n private renderBase(\n theme: Record<string, unknown>,\n themeRules: string[] = [],\n parentKey = '--u'\n ): string[] {\n Object.keys(theme).forEach((key) => {\n const value = theme[key]\n const varKey = `${parentKey.startsWith('-') ? parentKey : str(parentKey).kebabCase()}-${str(key).kebabCase()}`\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n this.renderBase(value as Record<string, unknown>, themeRules, varKey)\n } else {\n if (value || value === 0) {\n const v = withUnit(value as number | string, 'px')\n if (v !== undefined) {\n themeRules.push(`${varKey}: ${v}`)\n }\n }\n }\n })\n\n return themeRules\n }\n\n private renderBorder(theme: Theme): string {\n const border = Object.keys(theme.border)\n .map((key) => `var(--u-border-${key})`)\n .join(' ')\n\n return `--u-border: ${border}`\n }\n\n private renderTypeColor(theme: Theme): string {\n const { color } = theme\n\n const types = Object.keys(color)\n const rates = [1, 3, 5, 7, 9]\n\n return types\n .map((type) => {\n const colorValue = color[type as keyof typeof color]! as `#${string}`\n\n return rates\n .map((rate) => {\n const light = `--u-color-${type}-light-${rate}: ${mixColor(\n colorValue,\n '#fff',\n rate / 10\n )}`\n const dark = `--u-color-${type}-dark-${rate}: ${mixColor(\n colorValue,\n '#000',\n rate / 10\n )}`\n return `${light};${dark}`\n })\n .join(';')\n })\n .join(';')\n }\n\n private renderShadow(_theme: Theme): string {\n const shadow = ['x', 'y', 'blur', 'spread', 'color']\n .map((k) => `var(--u-shadow-${k})`)\n .join(' ')\n\n return `--u-shadow: ${shadow}`\n }\n\n private renderBGColorAlpha(theme: Theme): string {\n const { color } = theme.bg\n return Object.keys(color)\n .map((type) => `--u-bg-color-${type}-alpha: ${color[type as keyof typeof color]}aa`)\n .join(';')\n }\n\n private renderBGFilter(theme: Theme): string {\n const { filter } = theme.bg\n return `--u-bg-filter: ${filter.blur} ${filter.saturate}`\n }\n\n /** 主题变量声明列表,均为 `--u-` 前缀的 CSS 自定义属性 */\n themeToDeclarationList(theme: Theme): string[] {\n const raw = theme as unknown as Record<string, unknown>\n const lines: string[] = [...this.renderBase(raw)]\n const chunks = [\n this.renderTypeColor(theme),\n this.renderShadow(theme),\n this.renderBGColorAlpha(theme),\n this.renderBGFilter(theme),\n this.renderBorder(theme)\n ]\n for (const c of chunks) {\n lines.push(\n ...c\n .split(';')\n .map((s) => s.trim())\n .filter(Boolean)\n )\n }\n return lines\n }\n\n private static declarationBlock(decls: string[]): string {\n return decls.join(';')\n }\n\n private static removeExistingStyleTag(doc: Document): void {\n const el = doc.getElementById(UITheme.themeID)\n if (el?.parentNode) {\n el.parentNode.removeChild(el)\n }\n }\n\n private static applyGlobalCSS(css: string): void {\n const doc = typeof document !== 'undefined' ? document : undefined\n if (!doc) return\n\n const canAdopt =\n typeof CSSStyleSheet !== 'undefined' && 'adoptedStyleSheets' in Document.prototype\n\n if (canAdopt) {\n UITheme.removeExistingStyleTag(doc)\n if (!UITheme.adoptedSheet) {\n UITheme.adoptedSheet = new CSSStyleSheet()\n doc.adoptedStyleSheets = [...doc.adoptedStyleSheets, UITheme.adoptedSheet]\n }\n UITheme.adoptedSheet.replaceSync(css)\n } else {\n if (UITheme.adoptedSheet) {\n UITheme.adoptedSheet = null\n }\n let style = doc.getElementById(UITheme.themeID)\n if (!style) {\n style = doc.createElement('style')\n style.id = UITheme.themeID\n doc.head.appendChild(style)\n }\n style.textContent = css\n }\n }\n\n /** 内置 light/dark:支持 data-theme 与 prefers-color-scheme */\n static injectBuiltInThemes(light: UITheme, dark: UITheme): void {\n const lightDecls = [\n ...light.themeToDeclarationList(toRaw(light.theme)),\n ...componentCssVarsLightDecls\n ]\n const darkDecls = [\n ...dark.themeToDeclarationList(toRaw(dark.theme)),\n ...componentCssVarsDarkDecls\n ]\n const lightBlock = UITheme.declarationBlock(lightDecls)\n const darkBlock = UITheme.declarationBlock(darkDecls)\n\n const css = [\n `html { ${lightBlock} }`,\n `@media (prefers-color-scheme: dark) {`,\n ` html:not([data-theme=\"light\"]) { ${darkBlock} }`,\n `}`,\n `html[data-theme=\"light\"] { ${lightBlock} }`,\n `html[data-theme=\"dark\"] { ${darkBlock} }`\n ].join('\\n')\n\n UITheme.applyGlobalCSS(css)\n }\n\n render(): void {\n const decls = [...this.themeToDeclarationList(toRaw(this.theme)), ...componentCssVarsLightDecls]\n const block = UITheme.declarationBlock(decls)\n const css = `html { ${block} }`\n UITheme.applyGlobalCSS(css)\n }\n\n new(customTheme: RecursivePartial<Theme> = {}): UITheme {\n function delEmpty(obj: Record<string, unknown>) {\n Object.keys(obj).forEach((key) => {\n const value = obj[key]\n if (isObj(value)) {\n return delEmpty(value as Record<string, unknown>)\n }\n if (!value && value !== 0) {\n delete obj[key]\n }\n })\n }\n\n delEmpty(customTheme as Record<string, unknown>)\n\n const base = JSON.parse(JSON.stringify(toRaw(this.theme))) as Record<string, any>\n o(base).deepExtend(customTheme as Record<string, any>)\n return new UITheme(base as Theme, { reactive: this.reactiveEnabled })\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veltra/styles",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist",
|
|
6
6
|
"src"
|
|
@@ -55,13 +55,13 @@
|
|
|
55
55
|
}
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
|
-
"build": "tsdown
|
|
58
|
+
"build": "tsdown",
|
|
59
59
|
"check-types": "tsc -p tsconfig.json --noEmit"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@cat-kit/core": "^1.1.
|
|
63
|
-
"@veltra/compositions": "1.0.
|
|
64
|
-
"@veltra/utils": "1.0.
|
|
62
|
+
"@cat-kit/core": "^1.1.3",
|
|
63
|
+
"@veltra/compositions": "1.0.11",
|
|
64
|
+
"@veltra/utils": "1.0.11"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"vue": "^3.5.33"
|
package/src/theme/ui-theme.ts
CHANGED
|
@@ -10,24 +10,9 @@ type RecursivePartial<T> = {
|
|
|
10
10
|
[P in keyof T]?: T[P] extends object ? RecursivePartial<T[P]> : T[P]
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
function isDevEnv(): boolean {
|
|
14
|
-
try {
|
|
15
|
-
if (typeof import.meta !== 'undefined') {
|
|
16
|
-
const env = (import.meta as { env?: { DEV?: boolean } }).env
|
|
17
|
-
if (env?.DEV === true) return true
|
|
18
|
-
}
|
|
19
|
-
} catch {
|
|
20
|
-
/* ignore */
|
|
21
|
-
}
|
|
22
|
-
const proc = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process
|
|
23
|
-
return typeof proc !== 'undefined' && proc.env?.NODE_ENV !== 'production'
|
|
24
|
-
}
|
|
25
|
-
|
|
26
13
|
export class UITheme {
|
|
27
14
|
static themeID = 'ultra-ui-theme'
|
|
28
15
|
|
|
29
|
-
private static legacyDeprecationWarned = false
|
|
30
|
-
|
|
31
16
|
private static adoptedSheet: CSSStyleSheet | null = null
|
|
32
17
|
|
|
33
18
|
readonly theme: Theme
|
|
@@ -132,7 +117,7 @@ export class UITheme {
|
|
|
132
117
|
return `--u-bg-filter: ${filter.blur} ${filter.saturate}`
|
|
133
118
|
}
|
|
134
119
|
|
|
135
|
-
/**
|
|
120
|
+
/** 主题变量声明列表,均为 `--u-` 前缀的 CSS 自定义属性 */
|
|
136
121
|
themeToDeclarationList(theme: Theme): string[] {
|
|
137
122
|
const raw = theme as unknown as Record<string, unknown>
|
|
138
123
|
const lines: string[] = [...this.renderBase(raw)]
|
|
@@ -154,33 +139,8 @@ export class UITheme {
|
|
|
154
139
|
return lines
|
|
155
140
|
}
|
|
156
141
|
|
|
157
|
-
private static withLegacyDuplicates(decls: string[]): string {
|
|
158
|
-
const legacy: string[] = []
|
|
159
|
-
for (const decl of decls) {
|
|
160
|
-
const idx = decl.indexOf(':')
|
|
161
|
-
if (idx === -1) continue
|
|
162
|
-
const name = decl.slice(0, idx).trim()
|
|
163
|
-
const value = decl.slice(idx + 1).trim()
|
|
164
|
-
if (name.startsWith('--u-')) {
|
|
165
|
-
legacy.push(`--${name.slice(4)}: ${value}`)
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return [...decls, ...legacy].join(';')
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
private static warnLegacyOnce(): void {
|
|
172
|
-
if (!isDevEnv() || UITheme.legacyDeprecationWarned) return
|
|
173
|
-
UITheme.legacyDeprecationWarned = true
|
|
174
|
-
console.warn(
|
|
175
|
-
'[@veltra/styles] Theme CSS variables now prefer the `--u-` namespace. ' +
|
|
176
|
-
'Unprefixed aliases (e.g. `--color-primary`) are deprecated and will be removed in a future major version.'
|
|
177
|
-
)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
142
|
private static declarationBlock(decls: string[]): string {
|
|
181
|
-
|
|
182
|
-
UITheme.warnLegacyOnce()
|
|
183
|
-
return merged
|
|
143
|
+
return decls.join(';')
|
|
184
144
|
}
|
|
185
145
|
|
|
186
146
|
private static removeExistingStyleTag(doc: Document): void {
|