@veltra/styles 1.6.6 → 1.7.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.
Files changed (54) hide show
  1. package/README.md +22 -0
  2. package/dist/_mixins.scss +1 -7
  3. package/dist/theme/component-css-vars.js +1 -1
  4. package/dist/theme/component-css-vars.js.map +1 -1
  5. package/dist/theme/index.d.ts +10 -7
  6. package/dist/theme/index.js +9 -6
  7. package/dist/theme/load-theme.d.ts +3 -4
  8. package/dist/theme/load-theme.js +15 -22
  9. package/dist/theme/load-theme.js.map +1 -1
  10. package/dist/theme/presets/ancient.d.ts +3 -2
  11. package/dist/theme/presets/ancient.js +3 -2
  12. package/dist/theme/presets/ancient.js.map +1 -1
  13. package/dist/theme/presets/dark.js +1 -1
  14. package/dist/theme/presets/dark.js.map +1 -1
  15. package/dist/theme/presets/glass.d.ts +7 -3
  16. package/dist/theme/presets/glass.js +18 -47
  17. package/dist/theme/presets/glass.js.map +1 -1
  18. package/dist/theme/presets/hero.d.ts +3 -3
  19. package/dist/theme/presets/hero.js +3 -40
  20. package/dist/theme/presets/hero.js.map +1 -1
  21. package/dist/theme/presets/midnight.d.ts +8 -0
  22. package/dist/theme/presets/midnight.js +55 -0
  23. package/dist/theme/presets/midnight.js.map +1 -0
  24. package/dist/theme/presets/neon.d.ts +8 -0
  25. package/dist/theme/presets/neon.js +55 -0
  26. package/dist/theme/presets/neon.js.map +1 -0
  27. package/dist/theme/presets/ocean.d.ts +8 -0
  28. package/dist/theme/presets/ocean.js +55 -0
  29. package/dist/theme/presets/ocean.js.map +1 -0
  30. package/dist/theme/presets/sakura.d.ts +8 -0
  31. package/dist/theme/presets/sakura.js +57 -0
  32. package/dist/theme/presets/sakura.js.map +1 -0
  33. package/dist/theme/ui-theme.d.ts +16 -8
  34. package/dist/theme/ui-theme.js +11 -25
  35. package/dist/theme/ui-theme.js.map +1 -1
  36. package/package.json +3 -3
  37. package/src/_mixins.scss +1 -7
  38. package/src/theme/__test__/ui-theme.test.ts +42 -9
  39. package/src/theme/component-css-vars.ts +1 -1
  40. package/src/theme/load-theme.ts +12 -27
  41. package/src/theme/presets/ancient.ts +3 -1
  42. package/src/theme/presets/dark.ts +43 -40
  43. package/src/theme/presets/glass.ts +56 -67
  44. package/src/theme/presets/hero.ts +2 -35
  45. package/src/theme/presets/index.ts +7 -4
  46. package/src/theme/presets/midnight.ts +45 -0
  47. package/src/theme/presets/neon.ts +45 -0
  48. package/src/theme/presets/ocean.ts +35 -0
  49. package/src/theme/presets/sakura.ts +37 -0
  50. package/src/theme/ui-theme.ts +26 -41
  51. package/dist/theme/presets/shadcn.d.ts +0 -8
  52. package/dist/theme/presets/shadcn.js +0 -100
  53. package/dist/theme/presets/shadcn.js.map +0 -1
  54. package/src/theme/presets/shadcn.ts +0 -84
@@ -1,47 +1,50 @@
1
1
  import { lightTheme } from './light'
2
2
 
3
- export const darkTheme = lightTheme.new({
4
- color: {
5
- primary: '#3b82f6',
6
- success: '#22c55e',
7
- warning: '#f59e0b',
8
- danger: '#ef4444',
9
- info: '#06b6d4',
10
- disabled: '#27272a',
11
- default: '#27272a'
12
- },
13
-
14
- bg: {
3
+ export const darkTheme = lightTheme.new(
4
+ {
15
5
  color: {
16
- bottom: '#0c0c0e',
17
- middle: '#141417',
18
- top: '#1c1c21',
19
- hover: '#26262c',
20
- black: '#000000'
6
+ primary: '#3b82f6',
7
+ success: '#22c55e',
8
+ warning: '#f59e0b',
9
+ danger: '#ef4444',
10
+ info: '#06b6d4',
11
+ disabled: '#27272a',
12
+ default: '#27272a'
21
13
  },
22
- filter: { blur: 'none', saturate: 'none' }
23
- },
24
14
 
25
- 'text-color': {
26
- title: '#f4f4f5',
27
- main: '#d4d4d8',
28
- second: '#a1a1aa',
29
- placeholder: '#71717a',
30
- assist: '#52525b',
31
- disabled: '#3f3f46',
32
- white: '#ffffff'
33
- },
15
+ bg: {
16
+ color: {
17
+ bottom: '#0c0c0e',
18
+ middle: '#141417',
19
+ top: '#1c1c21',
20
+ hover: '#26262c',
21
+ black: '#000000'
22
+ },
23
+ filter: { blur: 'none', saturate: 'none' }
24
+ },
25
+
26
+ 'text-color': {
27
+ title: '#f4f4f5',
28
+ main: '#d4d4d8',
29
+ second: '#a1a1aa',
30
+ placeholder: '#71717a',
31
+ assist: '#52525b',
32
+ disabled: '#3f3f46',
33
+ white: '#ffffff'
34
+ },
34
35
 
35
- border: { color: '#37373f', mutedColor: '#42424c' },
36
+ border: { color: '#37373f', mutedColor: '#42424c' },
36
37
 
37
- shadow: {
38
- color: '#00000066',
39
- x: 0,
40
- y: 1,
41
- blur: 3,
42
- spread: 0,
43
- emboss: 'none',
44
- sm: '0 1px 2px 0 rgba(0, 0, 0, 0.4)',
45
- lg: '0 8px 24px 0 rgba(0, 0, 0, 0.5), 0 2px 6px 0 rgba(0, 0, 0, 0.35)'
46
- }
47
- })
38
+ shadow: {
39
+ color: '#00000066',
40
+ x: 0,
41
+ y: 1,
42
+ blur: 3,
43
+ spread: 0,
44
+ emboss: 'none',
45
+ sm: '0 1px 2px 0 rgba(0, 0, 0, 0.4)',
46
+ lg: '0 8px 24px 0 rgba(0, 0, 0, 0.5), 0 2px 6px 0 rgba(0, 0, 0, 0.35)'
47
+ }
48
+ },
49
+ { series: 'dark' }
50
+ )
@@ -1,73 +1,62 @@
1
1
  import { lightTheme } from './light'
2
2
 
3
- export const glassLightTheme = lightTheme.new({
4
- color: {
5
- primary: '#3B82F6',
6
- success: '#10B981',
7
- warning: '#F59E0B',
8
- danger: '#EF4444',
9
- info: '#06B6D4',
10
- disabled: '#E5E7EB',
11
- default: '#F3F4F6'
12
- },
13
- bg: {
3
+ /**
4
+ * 玻璃拟态,天生适合深色(半透明背景 + 背景模糊在深色下层次最好)。
5
+ * 背景为 rgba() 时派生 token(kbd / batch-edit 混合色)无法自动推导,
6
+ * 需通过组件级扩展键显式声明。
7
+ */
8
+ export const glassTheme = lightTheme.new(
9
+ {
14
10
  color: {
15
- bottom: 'rgba(255, 255, 255, 0.45)',
16
- middle: 'rgba(255, 255, 255, 0.55)',
17
- top: 'rgba(255, 255, 255, 0.6)',
18
- hover: 'rgba(255, 255, 255, 0.75)',
19
- black: '#000000'
11
+ primary: '#3B82F6',
12
+ success: '#10B981',
13
+ warning: '#F59E0B',
14
+ danger: '#EF4444',
15
+ info: '#06B6D4',
16
+ disabled: '#374151',
17
+ default: '#1E293B'
20
18
  },
21
- filter: { blur: 'blur(24px)', saturate: 'saturate(180%)' }
22
- },
23
- border: {
24
- color: 'rgba(15, 23, 42, 0.14)',
25
- mutedColor: 'rgba(15, 23, 42, 0.08)',
26
- width: 1,
27
- style: 'solid'
28
- },
29
- 'text-color': {
30
- title: '#1E293B',
31
- main: '#334155',
32
- placeholder: '#94A3B8',
33
- second: '#64748B',
34
- assist: '#CBD5E1',
35
- disabled: '#94A3B8',
36
- white: '#FFFFFF'
37
- },
38
- shadow: { color: '#00000014', x: 0, y: 4, blur: 24, spread: 0, emboss: 'none' }
39
- })
40
-
41
- export const glassDarkTheme = glassLightTheme.new({
42
- color: { disabled: '#374151', default: '#1E293B' },
43
- bg: {
44
- color: {
45
- bottom: 'rgba(15, 23, 42, 0.6)',
46
- middle: 'rgba(15, 23, 42, 0.7)',
47
- top: 'rgba(15, 23, 42, 0.75)',
48
- hover: 'rgba(30, 41, 59, 0.85)',
49
- black: '#000000'
19
+ bg: {
20
+ color: {
21
+ bottom: 'rgba(15, 23, 42, 0.6)',
22
+ middle: 'rgba(15, 23, 42, 0.7)',
23
+ top: 'rgba(15, 23, 42, 0.75)',
24
+ hover: 'rgba(30, 41, 59, 0.85)',
25
+ black: '#000000'
26
+ },
27
+ filter: { blur: 'blur(20px)', saturate: 'saturate(200%)' }
50
28
  },
51
- filter: { blur: 'blur(20px)', saturate: 'saturate(200%)' }
52
- },
53
- border: { color: 'rgba(255, 255, 255, 0.18)', mutedColor: 'rgba(255, 255, 255, 0.1)' },
54
- 'text-color': {
55
- title: '#F8FAFC',
56
- main: '#F1F5F9',
57
- second: '#94A3B8',
58
- placeholder: '#64748B',
59
- assist: '#64748B',
60
- disabled: '#475569',
61
- white: '#ffffff'
29
+ border: {
30
+ color: 'rgba(255, 255, 255, 0.18)',
31
+ mutedColor: 'rgba(255, 255, 255, 0.1)',
32
+ width: 1,
33
+ style: 'solid'
34
+ },
35
+ 'text-color': {
36
+ title: '#F8FAFC',
37
+ main: '#F1F5F9',
38
+ second: '#94A3B8',
39
+ placeholder: '#64748B',
40
+ assist: '#64748B',
41
+ disabled: '#475569',
42
+ white: '#ffffff'
43
+ },
44
+ shadow: {
45
+ color: '#00000059',
46
+ x: 0,
47
+ y: 4,
48
+ blur: 32,
49
+ spread: 0,
50
+ emboss: 'none',
51
+ sm: '0 1px 2px 0 rgba(0, 0, 0, 0.4)',
52
+ lg: '0 8px 24px 0 rgba(0, 0, 0, 0.55), 0 2px 6px 0 rgba(0, 0, 0, 0.35)'
53
+ },
54
+ kbd: {
55
+ 'inset-shadow': 'rgba(0, 0, 0, 0.5)',
56
+ 'border-shadow': 'rgba(255, 255, 255, 0.09)',
57
+ 'drop-shadow': 'rgba(0, 0, 0, 0.6)'
58
+ },
59
+ 'batch-edit': { 'form-header-bg': 'rgba(15, 23, 42, 0.8)' }
62
60
  },
63
- shadow: {
64
- color: '#00000059',
65
- x: 0,
66
- y: 4,
67
- blur: 32,
68
- spread: 0,
69
- emboss: 'none',
70
- sm: '0 1px 2px 0 rgba(0, 0, 0, 0.4)',
71
- lg: '0 8px 24px 0 rgba(0, 0, 0, 0.55), 0 2px 6px 0 rgba(0, 0, 0, 0.35)'
72
- }
73
- })
61
+ { series: 'dark' }
62
+ )
@@ -1,6 +1,7 @@
1
1
  import { lightTheme } from './light'
2
2
 
3
- export const heroLightTheme = lightTheme.new({
3
+ /** HeroUI 风格,天生适合浅色 */
4
+ export const heroTheme = lightTheme.new({
4
5
  color: {
5
6
  primary: '#7828c8', // purple
6
7
  success: '#17c964',
@@ -31,37 +32,3 @@ export const heroLightTheme = lightTheme.new({
31
32
  },
32
33
  button: { 'default-bg': '#ebebec' }
33
34
  })
34
-
35
- export const heroDarkTheme = heroLightTheme.new({
36
- color: { primary: '#9353d3', disabled: '#27272a', default: '#27272a' },
37
- bg: {
38
- color: {
39
- bottom: '#000000',
40
- middle: '#18181b',
41
- top: '#27272a',
42
- hover: '#3f3f46',
43
- black: '#000000'
44
- }
45
- },
46
- border: { color: '#3f3f46', mutedColor: '#3f3f46' },
47
- 'text-color': {
48
- title: '#ECEDEE',
49
- main: '#ECEDEE',
50
- second: '#A1A1AA',
51
- placeholder: '#71717A',
52
- assist: '#71717A',
53
- disabled: '#71717A',
54
- white: '#FFFFFF'
55
- },
56
- shadow: {
57
- color: '#00000033',
58
- x: 0,
59
- y: 4,
60
- blur: 14,
61
- spread: 0,
62
- emboss: '0 2px 4px 0 #0000000a,0 1px 2px 0 #0000000f,0 0 1px 0 #0000000f',
63
- sm: '0 1px 2px 0 rgba(0, 0, 0, 0.4)',
64
- lg: '0 8px 24px 0 rgba(0, 0, 0, 0.5), 0 2px 6px 0 rgba(0, 0, 0, 0.35)'
65
- },
66
- button: { 'default-bg': 'var(--u-bg-color-top)' }
67
- })
@@ -1,6 +1,9 @@
1
1
  export { lightTheme } from './light'
2
2
  export { darkTheme } from './dark'
3
- export { heroDarkTheme, heroLightTheme } from './hero'
4
- export { shadcnLightTheme, shadcnDarkTheme } from './shadcn'
5
- export { glassDarkTheme, glassLightTheme } from './glass'
6
- export { ancientLightTheme } from './ancient'
3
+ export { heroTheme } from './hero'
4
+ export { glassTheme } from './glass'
5
+ export { ancientTheme } from './ancient'
6
+ export { sakuraTheme } from './sakura'
7
+ export { oceanTheme } from './ocean'
8
+ export { midnightTheme } from './midnight'
9
+ export { neonTheme } from './neon'
@@ -0,0 +1,45 @@
1
+ import { darkTheme } from './dark'
2
+
3
+ /** 午夜(靛蓝 + 深空底,宽松间距、舒缓缓动),天生适合深色 */
4
+ export const midnightTheme = darkTheme.new({
5
+ color: {
6
+ primary: '#6f78ee', // 星靛(白字对比 3.75:1)
7
+ success: '#34d399',
8
+ warning: '#fbbf24',
9
+ danger: '#f87171',
10
+ info: '#38bdf8',
11
+ disabled: '#232d4a',
12
+ default: '#232d4a'
13
+ },
14
+ bg: {
15
+ color: {
16
+ bottom: '#0a0f1e', // 深空
17
+ middle: '#101731',
18
+ top: '#182242',
19
+ hover: '#212d54'
20
+ }
21
+ },
22
+ 'text-color': {
23
+ title: '#e8ecff', // 月光
24
+ main: '#c3cbf0',
25
+ second: '#8d97c6',
26
+ placeholder: '#7d8ab8',
27
+ assist: '#5b6895',
28
+ disabled: '#576493'
29
+ },
30
+ // mutedColor 与卡片底对比 2.6:1,保证输入控件清晰可见
31
+ border: { color: '#36457a', mutedColor: '#52619a' },
32
+ // 更宽松的间距,配合深空的呼吸感
33
+ gap: { small: 8, default: 10, large: 14 },
34
+ shadow: {
35
+ color: '#00000080',
36
+ x: 0,
37
+ y: 2,
38
+ blur: 8,
39
+ spread: 0,
40
+ emboss: 'none',
41
+ sm: '0 1px 2px 0 rgba(0, 0, 0, 0.5)',
42
+ lg: '0 8px 24px 0 rgba(0, 0, 0, 0.6), 0 2px 6px 0 rgba(0, 0, 0, 0.4)'
43
+ },
44
+ transition: { slow: '0.4s', ease: 'cubic-bezier(0.33, 1, 0.68, 1)' }
45
+ })
@@ -0,0 +1,45 @@
1
+ import { darkTheme } from './dark'
2
+
3
+ /** 霓虹(品红 + 夜紫底 + 辉光阴影,小圆角、急速缓动),天生适合深色 */
4
+ export const neonTheme = darkTheme.new({
5
+ color: {
6
+ primary: '#c026d3', // 霓红
7
+ success: '#4ade80',
8
+ warning: '#facc15',
9
+ danger: '#fb7185',
10
+ info: '#22d3ee',
11
+ disabled: '#241532',
12
+ default: '#241532'
13
+ },
14
+ bg: {
15
+ color: {
16
+ bottom: '#0c0612', // 夜紫
17
+ middle: '#130a1d',
18
+ top: '#1c102a',
19
+ hover: '#28163d'
20
+ }
21
+ },
22
+ 'text-color': {
23
+ title: '#f6efff',
24
+ main: '#d9cdee',
25
+ second: '#a08bc4',
26
+ placeholder: '#8f74b8',
27
+ assist: '#6b4f94',
28
+ disabled: '#63498a'
29
+ },
30
+ // mutedColor 与卡片底对比 2.65:1,输入控件带清晰的紫色描边
31
+ border: { color: '#503480', mutedColor: '#684a9e' },
32
+ // 赛博感:小圆角 + 品红辉光
33
+ radius: { small: 2, default: 4, large: 8 },
34
+ shadow: {
35
+ color: 'rgba(192, 38, 211, 0.3)',
36
+ x: 0,
37
+ y: 0,
38
+ blur: 12,
39
+ spread: 0,
40
+ emboss: 'none',
41
+ sm: '0 1px 2px 0 rgba(0, 0, 0, 0.5)',
42
+ lg: '0 0 24px 0 rgba(192, 38, 211, 0.25), 0 8px 24px 0 rgba(0, 0, 0, 0.5)'
43
+ },
44
+ transition: { fast: '0.1s', ease: 'cubic-bezier(0.85, 0, 0.15, 1)' }
45
+ })
@@ -0,0 +1,35 @@
1
+ import { lightTheme } from './light'
2
+
3
+ /** 海盐(松石青 + 冷白底,利落的快缓动),天生适合浅色 */
4
+ export const oceanTheme = lightTheme.new({
5
+ color: {
6
+ primary: '#0d9488', // 松石青
7
+ success: '#16a34a',
8
+ warning: '#d97706',
9
+ danger: '#dc2626',
10
+ info: '#0284c7',
11
+ disabled: '#eff6f5',
12
+ default: '#eff6f5'
13
+ },
14
+ bg: { color: { bottom: '#eef6f5', middle: '#f5fafa', top: '#ffffff', hover: '#e0efee' } },
15
+ 'text-color': {
16
+ title: '#16302e', // 深礁
17
+ main: '#2f4a48',
18
+ second: '#5b7875',
19
+ assist: '#c3d6d4',
20
+ placeholder: '#7fa19e',
21
+ disabled: '#a3bab7'
22
+ },
23
+ border: { width: 1, color: '#c2dedb', mutedColor: '#8fbcb7' },
24
+ radius: { small: 6, default: 10, large: 14 },
25
+ shadow: {
26
+ color: 'rgba(21, 94, 89, 0.12)',
27
+ x: 0,
28
+ y: 2,
29
+ blur: 10,
30
+ spread: -1,
31
+ sm: '0 1px 2px 0 rgba(21, 94, 89, 0.08)',
32
+ lg: '0 8px 24px 0 rgba(21, 94, 89, 0.12), 0 2px 6px 0 rgba(21, 94, 89, 0.06)'
33
+ },
34
+ transition: { fast: '0.12s', ease: 'cubic-bezier(0.22, 1, 0.36, 1)' }
35
+ })
@@ -0,0 +1,37 @@
1
+ import { lightTheme } from './light'
2
+
3
+ /** 樱花(柔粉 + 花瓣底,大圆角、弹性缓动),天生适合浅色 */
4
+ export const sakuraTheme = lightTheme.new({
5
+ color: {
6
+ primary: '#e64980', // 樱粉
7
+ success: '#2f9e6e',
8
+ warning: '#e8890c',
9
+ danger: '#e03131',
10
+ info: '#7c6cf0',
11
+ disabled: '#faf0f3',
12
+ default: '#faf0f3'
13
+ },
14
+ bg: { color: { bottom: '#fdf1f5', middle: '#fef6f9', top: '#ffffff', hover: '#fbe4ec' } },
15
+ 'text-color': {
16
+ title: '#43272f', // 樱墨
17
+ main: '#5f3d46',
18
+ second: '#92616d',
19
+ assist: '#dcc0c7',
20
+ placeholder: '#b58694',
21
+ disabled: '#c4a0aa'
22
+ },
23
+ border: { width: 1, color: '#f0c3d4', mutedColor: '#e09db6' },
24
+ radius: { small: 8, default: 12, large: 16 },
25
+ // 更宽松的表单控件,配合大圆角的柔和感
26
+ 'form-component-height': { small: 26, default: 34, large: 42 },
27
+ shadow: {
28
+ color: 'rgba(173, 58, 105, 0.12)',
29
+ x: 0,
30
+ y: 4,
31
+ blur: 14,
32
+ spread: -2,
33
+ sm: '0 1px 2px 0 rgba(173, 58, 105, 0.08)',
34
+ lg: '0 8px 24px 0 rgba(173, 58, 105, 0.14), 0 2px 6px 0 rgba(173, 58, 105, 0.08)'
35
+ },
36
+ transition: { easeOut: 'cubic-bezier(0.34, 1.56, 0.64, 1)' }
37
+ })
@@ -10,6 +10,16 @@ type RecursivePartial<T> = {
10
10
  [P in keyof T]?: T[P] extends object ? RecursivePartial<T[P]> : T[P]
11
11
  }
12
12
 
13
+ /** 主题系列:浅色或深色。决定组件级 token 与 html[data-theme] */
14
+ export type ThemeSeries = 'light' | 'dark'
15
+
16
+ export interface UIThemeOptions {
17
+ /** 主题变更时是否自动重渲染,默认 true */
18
+ reactive?: boolean
19
+ /** 主题所属系列,默认 'light' */
20
+ series?: ThemeSeries
21
+ }
22
+
13
23
  export class UITheme {
14
24
  static themeID = 'ultra-ui-theme'
15
25
 
@@ -17,26 +27,20 @@ export class UITheme {
17
27
 
18
28
  readonly theme: Theme
19
29
 
30
+ /** 主题所属系列:浅色 / 深色 */
31
+ series: ThemeSeries
32
+
20
33
  private readonly reactiveEnabled: boolean
21
34
 
22
- constructor(theme: Theme, options?: { reactive?: boolean }) {
35
+ constructor(theme: Theme, options?: UIThemeOptions) {
23
36
  this.reactiveEnabled = options?.reactive !== false
37
+ this.series = options?.series ?? 'light'
24
38
  this.theme = reactive(theme) as Theme
25
39
  if (this.reactiveEnabled) {
26
40
  watch(this.theme, () => this.render(), { deep: true })
27
41
  }
28
42
  }
29
43
 
30
- static setTheme(mode: 'light' | 'dark' | 'auto'): void {
31
- if (typeof document === 'undefined') return
32
- const el = document.documentElement
33
- if (mode === 'auto') {
34
- delete el.dataset.theme
35
- } else {
36
- el.dataset.theme = mode
37
- }
38
- }
39
-
40
44
  private renderBase(
41
45
  theme: Record<string, unknown>,
42
46
  themeRules: string[] = [],
@@ -267,42 +271,20 @@ export class UITheme {
267
271
  }
268
272
  }
269
273
 
270
- /** 内置 light/dark:支持 data-theme 与 prefers-color-scheme */
271
- static injectBuiltInThemes(light: UITheme, dark: UITheme): void {
272
- const lightDecls = [
273
- ...light.themeToDeclarationList(toRaw(light.theme)),
274
- ...componentCssVarsLightDecls
275
- ]
276
- const darkDecls = [
277
- ...dark.themeToDeclarationList(toRaw(dark.theme)),
278
- ...componentCssVarsDarkDecls
279
- ]
280
- const lightBlock = UITheme.declarationBlock(lightDecls)
281
- const darkBlock = UITheme.declarationBlock(darkDecls)
282
-
283
- const css = [
284
- `html { ${lightBlock} }`,
285
- `@media (prefers-color-scheme: dark) {`,
286
- ` html:not([data-theme="light"]) { ${darkBlock} }`,
287
- `}`,
288
- `html[data-theme="light"] { ${lightBlock} }`,
289
- `html[data-theme="dark"] { ${darkBlock} }`
290
- ].join('\n')
291
-
292
- UITheme.applyGlobalCSS(css)
293
- }
294
-
274
+ /** 注入主题:全局 token + 与主题系列匹配的组件级 token,并写入 html[data-theme] */
295
275
  render(): void {
296
- const isDark =
297
- typeof document !== 'undefined' && document.documentElement.dataset.theme === 'dark'
298
- const componentDecls = isDark ? componentCssVarsDarkDecls : componentCssVarsLightDecls
276
+ const componentDecls =
277
+ this.series === 'dark' ? componentCssVarsDarkDecls : componentCssVarsLightDecls
299
278
  const decls = [...this.themeToDeclarationList(toRaw(this.theme)), ...componentDecls]
300
279
  const block = UITheme.declarationBlock(decls)
301
280
  const css = `html { ${block} }`
302
281
  UITheme.applyGlobalCSS(css)
282
+ if (typeof document !== 'undefined') {
283
+ document.documentElement.dataset.theme = this.series
284
+ }
303
285
  }
304
286
 
305
- new(customTheme: RecursivePartial<Theme> = {}): UITheme {
287
+ new(customTheme: RecursivePartial<Theme> = {}, options?: { series?: ThemeSeries }): UITheme {
306
288
  function delEmpty(obj: Record<string, unknown>) {
307
289
  Object.keys(obj).forEach((key) => {
308
290
  const value = obj[key]
@@ -335,6 +317,9 @@ export class UITheme {
335
317
  }
336
318
 
337
319
  deepMerge(base, customTheme)
338
- return new UITheme(base as Theme, { reactive: this.reactiveEnabled })
320
+ return new UITheme(base as Theme, {
321
+ reactive: this.reactiveEnabled,
322
+ series: options?.series ?? this.series
323
+ })
339
324
  }
340
325
  }
@@ -1,8 +0,0 @@
1
- import { UITheme } from "../ui-theme.js";
2
- import "../index.js";
3
- //#region src/theme/presets/shadcn.d.ts
4
- declare const shadcnLightTheme: UITheme;
5
- declare const shadcnDarkTheme: UITheme;
6
- //#endregion
7
- export { shadcnDarkTheme, shadcnLightTheme };
8
- //# sourceMappingURL=shadcn.d.ts.map
@@ -1,100 +0,0 @@
1
- import { lightTheme } from "./light.js";
2
- //#region src/theme/presets/shadcn.ts
3
- const shadcnLightTheme = lightTheme.new({
4
- color: {
5
- primary: "#18181b",
6
- success: "#22c55e",
7
- warning: "#f59e0b",
8
- danger: "#ef4444",
9
- info: "#3b82f6",
10
- disabled: "#f4f4f5",
11
- default: "#fafafa"
12
- },
13
- bg: { color: {
14
- bottom: "#f4f4f5",
15
- middle: "#fafafa",
16
- top: "#ffffff",
17
- hover: "#f4f4f5",
18
- black: "#000000"
19
- } },
20
- border: {
21
- color: "#e4e4e7",
22
- mutedColor: "#e4e4e7"
23
- },
24
- "text-color": {
25
- title: "#09090b",
26
- main: "#09090b",
27
- second: "#71717a",
28
- placeholder: "#a1a1aa",
29
- assist: "#a1a1aa",
30
- disabled: "#a1a1aa",
31
- white: "#ffffff"
32
- },
33
- radius: {
34
- small: 4,
35
- default: 6,
36
- large: 8
37
- },
38
- shadow: {
39
- color: "#0000000d",
40
- x: 0,
41
- y: 1,
42
- blur: 2,
43
- spread: 0,
44
- emboss: "none"
45
- },
46
- button: {
47
- "primary-text-color": "#ffffff",
48
- "primary-hover-bg": "#27272a",
49
- "primary-hover-color": "#ffffff"
50
- }
51
- });
52
- const shadcnDarkTheme = shadcnLightTheme.new({
53
- color: {
54
- primary: "#fafafa",
55
- disabled: "#27272a",
56
- default: "#18181b"
57
- },
58
- bg: { color: {
59
- bottom: "#09090b",
60
- middle: "#18181b",
61
- top: "#27272a",
62
- hover: "#27272a",
63
- black: "#000000"
64
- } },
65
- border: {
66
- color: "#3f3f46",
67
- mutedColor: "#27272a"
68
- },
69
- "text-color": {
70
- title: "#fafafa",
71
- main: "#fafafa",
72
- second: "#a1a1aa",
73
- placeholder: "#71717a",
74
- assist: "#71717a",
75
- disabled: "#71717a",
76
- white: "#ffffff"
77
- },
78
- shadow: {
79
- color: "#00000066",
80
- x: 0,
81
- y: 1,
82
- blur: 2,
83
- spread: 0,
84
- emboss: "none",
85
- sm: "0 1px 2px 0 rgba(0, 0, 0, 0.4)",
86
- lg: "0 8px 24px 0 rgba(0, 0, 0, 0.5), 0 2px 6px 0 rgba(0, 0, 0, 0.35)"
87
- },
88
- button: {
89
- "primary-text-color": "#000000",
90
- "primary-hover-bg": "#e4e4e7",
91
- "primary-hover-color": "#000000",
92
- "primary-plain-color": "#fafafa"
93
- },
94
- checkbox: { color: "#000000" },
95
- tag: { "primary-dark-color": "#000000" }
96
- });
97
- //#endregion
98
- export { shadcnDarkTheme, shadcnLightTheme };
99
-
100
- //# sourceMappingURL=shadcn.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"shadcn.js","names":[],"sources":["../../../src/theme/presets/shadcn.ts"],"sourcesContent":["import { lightTheme } from './light'\n\nexport const shadcnLightTheme = lightTheme.new({\n color: {\n primary: '#18181b', // zinc-900\n success: '#22c55e',\n warning: '#f59e0b',\n danger: '#ef4444',\n info: '#3b82f6',\n disabled: '#f4f4f5',\n default: '#fafafa'\n },\n bg: {\n color: {\n bottom: '#f4f4f5',\n middle: '#fafafa',\n top: '#ffffff',\n hover: '#f4f4f5',\n black: '#000000'\n }\n },\n border: { color: '#e4e4e7', mutedColor: '#e4e4e7' },\n 'text-color': {\n title: '#09090b',\n main: '#09090b',\n second: '#71717a',\n placeholder: '#a1a1aa',\n assist: '#a1a1aa',\n disabled: '#a1a1aa',\n white: '#ffffff'\n },\n radius: { small: 4, default: 6, large: 8 },\n shadow: { color: '#0000000d', x: 0, y: 1, blur: 2, spread: 0, emboss: 'none' },\n button: {\n 'primary-text-color': '#ffffff',\n 'primary-hover-bg': '#27272a',\n 'primary-hover-color': '#ffffff'\n }\n})\n\nexport const shadcnDarkTheme = shadcnLightTheme.new({\n color: {\n primary: '#fafafa', // zinc-50\n disabled: '#27272a',\n default: '#18181b'\n },\n bg: {\n color: {\n bottom: '#09090b',\n middle: '#18181b',\n top: '#27272a',\n hover: '#27272a',\n black: '#000000'\n }\n },\n border: { color: '#3f3f46', mutedColor: '#27272a' },\n 'text-color': {\n title: '#fafafa',\n main: '#fafafa',\n second: '#a1a1aa',\n placeholder: '#71717a',\n assist: '#71717a',\n disabled: '#71717a',\n white: '#ffffff'\n },\n shadow: {\n color: '#00000066',\n x: 0,\n y: 1,\n blur: 2,\n spread: 0,\n emboss: 'none',\n sm: '0 1px 2px 0 rgba(0, 0, 0, 0.4)',\n lg: '0 8px 24px 0 rgba(0, 0, 0, 0.5), 0 2px 6px 0 rgba(0, 0, 0, 0.35)'\n },\n button: {\n 'primary-text-color': '#000000',\n 'primary-hover-bg': '#e4e4e7',\n 'primary-hover-color': '#000000',\n 'primary-plain-color': '#fafafa'\n },\n checkbox: { color: '#000000' },\n tag: { 'primary-dark-color': '#000000' }\n})\n"],"mappings":";;AAEA,MAAa,mBAAmB,WAAW,IAAI;CAC7C,OAAO;EACL,SAAS;EACT,SAAS;EACT,SAAS;EACT,QAAQ;EACR,MAAM;EACN,UAAU;EACV,SAAS;CACX;CACA,IAAI,EACF,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,KAAK;EACL,OAAO;EACP,OAAO;CACT,EACF;CACA,QAAQ;EAAE,OAAO;EAAW,YAAY;CAAU;CAClD,cAAc;EACZ,OAAO;EACP,MAAM;EACN,QAAQ;EACR,aAAa;EACb,QAAQ;EACR,UAAU;EACV,OAAO;CACT;CACA,QAAQ;EAAE,OAAO;EAAG,SAAS;EAAG,OAAO;CAAE;CACzC,QAAQ;EAAE,OAAO;EAAa,GAAG;EAAG,GAAG;EAAG,MAAM;EAAG,QAAQ;EAAG,QAAQ;CAAO;CAC7E,QAAQ;EACN,sBAAsB;EACtB,oBAAoB;EACpB,uBAAuB;CACzB;AACF,CAAC;AAED,MAAa,kBAAkB,iBAAiB,IAAI;CAClD,OAAO;EACL,SAAS;EACT,UAAU;EACV,SAAS;CACX;CACA,IAAI,EACF,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,KAAK;EACL,OAAO;EACP,OAAO;CACT,EACF;CACA,QAAQ;EAAE,OAAO;EAAW,YAAY;CAAU;CAClD,cAAc;EACZ,OAAO;EACP,MAAM;EACN,QAAQ;EACR,aAAa;EACb,QAAQ;EACR,UAAU;EACV,OAAO;CACT;CACA,QAAQ;EACN,OAAO;EACP,GAAG;EACH,GAAG;EACH,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,IAAI;EACJ,IAAI;CACN;CACA,QAAQ;EACN,sBAAsB;EACtB,oBAAoB;EACpB,uBAAuB;EACvB,uBAAuB;CACzB;CACA,UAAU,EAAE,OAAO,UAAU;CAC7B,KAAK,EAAE,sBAAsB,UAAU;AACzC,CAAC"}