@umituz/web-design-system 6.12.0 → 6.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/styles.css +1 -1
- package/package.json +2 -1
- package/src/__tests__/theme-provider.test.tsx +58 -9
- package/src/infrastructure/themes/create-theme.ts +49 -0
- package/src/infrastructure/themes/{hangora.theme.ts → editorial.theme.ts} +2 -2
- package/src/infrastructure/themes/index.ts +5 -2
- package/src/infrastructure/themes/{accessia.theme.ts → midnight.theme.ts} +2 -2
- package/src/infrastructure/themes/ocean.theme.ts +71 -0
- package/src/infrastructure/themes/registry.ts +6 -4
- package/src/styles/compile.css +1 -0
- package/src/styles/console.css +2481 -0
|
@@ -9,7 +9,11 @@ import {
|
|
|
9
9
|
registerTheme,
|
|
10
10
|
applyTheme,
|
|
11
11
|
themeToCssVariables,
|
|
12
|
-
|
|
12
|
+
createTheme,
|
|
13
|
+
midnightTheme,
|
|
14
|
+
editorialTheme,
|
|
15
|
+
oceanTheme,
|
|
16
|
+
defaultTheme,
|
|
13
17
|
} from '../infrastructure/themes';
|
|
14
18
|
import type { ThemeConfig } from '../domain/types';
|
|
15
19
|
|
|
@@ -22,13 +26,50 @@ describe('Theme System and Provider', () => {
|
|
|
22
26
|
if (existing) existing.remove();
|
|
23
27
|
});
|
|
24
28
|
|
|
25
|
-
it('retrieves default and built-in themes by name', () => {
|
|
26
|
-
expect(getTheme('
|
|
27
|
-
expect(getTheme('
|
|
29
|
+
it('retrieves default and built-in themes by generic archetype name', () => {
|
|
30
|
+
expect(getTheme('midnight').name).toBe('midnight');
|
|
31
|
+
expect(getTheme('editorial').name).toBe('editorial');
|
|
32
|
+
expect(getTheme('ocean').name).toBe('ocean');
|
|
28
33
|
expect(getTheme('default').name).toBe('default');
|
|
29
34
|
expect(getTheme('non-existent').name).toBe('default');
|
|
30
35
|
});
|
|
31
36
|
|
|
37
|
+
it('allows createTheme to customize an existing preset or define from scratch', () => {
|
|
38
|
+
const customized = createTheme('midnight', {
|
|
39
|
+
name: 'midnight-custom',
|
|
40
|
+
colors: { primary: '#10b981' },
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
expect(customized.name).toBe('midnight-custom');
|
|
44
|
+
expect(customized.colors.primary).toBe('#10b981');
|
|
45
|
+
expect(customized.colors.background).toBe(midnightTheme.colors.background);
|
|
46
|
+
|
|
47
|
+
const fromScratch = createTheme({
|
|
48
|
+
name: 'standalone',
|
|
49
|
+
colors: {
|
|
50
|
+
background: '#000',
|
|
51
|
+
foreground: '#fff',
|
|
52
|
+
card: '#111',
|
|
53
|
+
cardForeground: '#fff',
|
|
54
|
+
popover: '#111',
|
|
55
|
+
popoverForeground: '#fff',
|
|
56
|
+
primary: '#f00',
|
|
57
|
+
primaryForeground: '#fff',
|
|
58
|
+
secondary: '#222',
|
|
59
|
+
secondaryForeground: '#fff',
|
|
60
|
+
muted: '#222',
|
|
61
|
+
mutedForeground: '#888',
|
|
62
|
+
accent: '#333',
|
|
63
|
+
accentForeground: '#fff',
|
|
64
|
+
border: '#444',
|
|
65
|
+
input: '#444',
|
|
66
|
+
destructive: '#f00',
|
|
67
|
+
destructiveForeground: '#fff',
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
expect(fromScratch.name).toBe('standalone');
|
|
71
|
+
});
|
|
72
|
+
|
|
32
73
|
it('registers and retrieves custom themes', () => {
|
|
33
74
|
const custom: ThemeConfig = {
|
|
34
75
|
name: 'custom-corp',
|
|
@@ -59,16 +100,24 @@ describe('Theme System and Provider', () => {
|
|
|
59
100
|
});
|
|
60
101
|
|
|
61
102
|
it('converts theme config to CSS variables string', () => {
|
|
62
|
-
const css = themeToCssVariables(
|
|
103
|
+
const css = themeToCssVariables(midnightTheme);
|
|
63
104
|
expect(css).toContain('--color-primary: #4e8cff;');
|
|
64
105
|
expect(css).toContain('--app-primary: #4e8cff;');
|
|
65
106
|
expect(css).toContain('--color-background: #060a12;');
|
|
66
|
-
expect(css).toContain('--bg-0: #060a12;');
|
|
67
107
|
expect(css).toContain('--font-sans:');
|
|
108
|
+
|
|
109
|
+
const editorialCss = themeToCssVariables(editorialTheme);
|
|
110
|
+
expect(editorialCss).toContain('--color-primary: #33406b;');
|
|
111
|
+
|
|
112
|
+
const oceanCss = themeToCssVariables(oceanTheme);
|
|
113
|
+
expect(oceanCss).toContain('--color-primary: #0284c7;');
|
|
114
|
+
|
|
115
|
+
const defaultCss = themeToCssVariables(defaultTheme);
|
|
116
|
+
expect(defaultCss).toContain('--color-primary: #2563eb;');
|
|
68
117
|
});
|
|
69
118
|
|
|
70
119
|
it('applies theme variables to document head', () => {
|
|
71
|
-
applyTheme(
|
|
120
|
+
applyTheme(midnightTheme);
|
|
72
121
|
const styleEl = document.getElementById('umituz-theme-vars');
|
|
73
122
|
expect(styleEl).toBeTruthy();
|
|
74
123
|
expect(styleEl?.textContent).toContain('--color-primary: #4e8cff;');
|
|
@@ -92,12 +141,12 @@ describe('Theme System and Provider', () => {
|
|
|
92
141
|
}
|
|
93
142
|
|
|
94
143
|
render(
|
|
95
|
-
<DesignSystemProvider theme="
|
|
144
|
+
<DesignSystemProvider theme="midnight" mode="dark">
|
|
96
145
|
<Consumer />
|
|
97
146
|
</DesignSystemProvider>
|
|
98
147
|
);
|
|
99
148
|
|
|
100
|
-
expect(screen.getByTestId('theme-name').textContent).toBe('
|
|
149
|
+
expect(screen.getByTestId('theme-name').textContent).toBe('midnight');
|
|
101
150
|
expect(screen.getByTestId('theme-mode').textContent).toBe('dark');
|
|
102
151
|
expect(document.documentElement.classList.contains('dark')).toBe(true);
|
|
103
152
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { ThemeConfig, ThemeColors, ThemeTypography, ThemeRadii } from '../../domain/types';
|
|
2
|
+
import { getTheme } from './registry';
|
|
3
|
+
|
|
4
|
+
export interface ThemeOverrides {
|
|
5
|
+
name?: string;
|
|
6
|
+
mode?: 'light' | 'dark';
|
|
7
|
+
colors?: Partial<ThemeColors>;
|
|
8
|
+
darkColors?: Partial<ThemeColors>;
|
|
9
|
+
typography?: Partial<ThemeTypography>;
|
|
10
|
+
radii?: Partial<ThemeRadii>;
|
|
11
|
+
customVars?: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function createTheme(
|
|
15
|
+
baseOrConfig: string | ThemeConfig,
|
|
16
|
+
overrides?: ThemeOverrides
|
|
17
|
+
): ThemeConfig {
|
|
18
|
+
if (typeof baseOrConfig === 'object' && !overrides) {
|
|
19
|
+
return baseOrConfig;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const base = typeof baseOrConfig === 'string' ? getTheme(baseOrConfig) : baseOrConfig;
|
|
23
|
+
if (!overrides) return base;
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
name: overrides.name ?? base.name,
|
|
27
|
+
mode: overrides.mode ?? base.mode,
|
|
28
|
+
colors: {
|
|
29
|
+
...base.colors,
|
|
30
|
+
...(overrides.colors ?? {}),
|
|
31
|
+
},
|
|
32
|
+
darkColors: {
|
|
33
|
+
...(base.darkColors ?? {}),
|
|
34
|
+
...(overrides.darkColors ?? {}),
|
|
35
|
+
},
|
|
36
|
+
typography: {
|
|
37
|
+
...(base.typography ?? {}),
|
|
38
|
+
...(overrides.typography ?? {}),
|
|
39
|
+
},
|
|
40
|
+
radii: {
|
|
41
|
+
...(base.radii ?? {}),
|
|
42
|
+
...(overrides.radii ?? {}),
|
|
43
|
+
},
|
|
44
|
+
customVars: {
|
|
45
|
+
...(base.customVars ?? {}),
|
|
46
|
+
...(overrides.customVars ?? {}),
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
export { accessiaTheme } from './accessia.theme';
|
|
2
|
-
export { hangoraTheme } from './hangora.theme';
|
|
3
1
|
export { defaultTheme } from './default.theme';
|
|
2
|
+
export { oceanTheme } from './ocean.theme';
|
|
3
|
+
export { midnightTheme } from './midnight.theme';
|
|
4
|
+
export { editorialTheme } from './editorial.theme';
|
|
5
|
+
export { createTheme } from './create-theme';
|
|
6
|
+
export type { ThemeOverrides } from './create-theme';
|
|
4
7
|
export { registerTheme, getTheme, hasTheme, listThemes } from './registry';
|
|
5
8
|
export { themeToCssVariables, applyTheme } from './apply-theme';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { ThemeConfig } from '../../domain/types';
|
|
2
|
+
|
|
3
|
+
export const oceanTheme: ThemeConfig = {
|
|
4
|
+
name: 'ocean',
|
|
5
|
+
mode: 'light',
|
|
6
|
+
colors: {
|
|
7
|
+
background: '#f8fafc',
|
|
8
|
+
foreground: '#0f172a',
|
|
9
|
+
card: '#ffffff',
|
|
10
|
+
cardForeground: '#0f172a',
|
|
11
|
+
popover: '#ffffff',
|
|
12
|
+
popoverForeground: '#0f172a',
|
|
13
|
+
primary: '#0284c7',
|
|
14
|
+
primaryForeground: '#ffffff',
|
|
15
|
+
primarySoft: 'rgba(2, 132, 199, 0.1)',
|
|
16
|
+
secondary: '#0ea5e9',
|
|
17
|
+
secondaryForeground: '#ffffff',
|
|
18
|
+
muted: '#f0f9ff',
|
|
19
|
+
mutedForeground: '#64748b',
|
|
20
|
+
accent: '#e0f2fe',
|
|
21
|
+
accentForeground: '#0369a1',
|
|
22
|
+
border: '#e2e8f0',
|
|
23
|
+
input: '#e2e8f0',
|
|
24
|
+
destructive: '#ef4444',
|
|
25
|
+
destructiveForeground: '#ffffff',
|
|
26
|
+
ring: 'rgba(2, 132, 199, 0.45)',
|
|
27
|
+
success: '#10b981',
|
|
28
|
+
successForeground: '#ffffff',
|
|
29
|
+
warning: '#f59e0b',
|
|
30
|
+
warningForeground: '#ffffff',
|
|
31
|
+
info: '#0284c7',
|
|
32
|
+
infoForeground: '#ffffff',
|
|
33
|
+
},
|
|
34
|
+
darkColors: {
|
|
35
|
+
background: '#08111e',
|
|
36
|
+
foreground: '#f0f9ff',
|
|
37
|
+
card: '#0c1a2e',
|
|
38
|
+
cardForeground: '#f0f9ff',
|
|
39
|
+
popover: '#0c1a2e',
|
|
40
|
+
popoverForeground: '#f0f9ff',
|
|
41
|
+
primary: '#38bdf8',
|
|
42
|
+
primaryForeground: '#08111e',
|
|
43
|
+
secondary: '#0284c7',
|
|
44
|
+
secondaryForeground: '#ffffff',
|
|
45
|
+
muted: '#13233b',
|
|
46
|
+
mutedForeground: '#94a3b8',
|
|
47
|
+
accent: '#183052',
|
|
48
|
+
accentForeground: '#7dd3fc',
|
|
49
|
+
border: '#1b3252',
|
|
50
|
+
input: '#1b3252',
|
|
51
|
+
destructive: '#f87171',
|
|
52
|
+
destructiveForeground: '#ffffff',
|
|
53
|
+
ring: 'rgba(56, 189, 248, 0.5)',
|
|
54
|
+
success: '#34d399',
|
|
55
|
+
successForeground: '#ffffff',
|
|
56
|
+
warning: '#fbbf24',
|
|
57
|
+
warningForeground: '#ffffff',
|
|
58
|
+
info: '#38bdf8',
|
|
59
|
+
infoForeground: '#ffffff',
|
|
60
|
+
},
|
|
61
|
+
typography: {
|
|
62
|
+
fontSans: 'ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif',
|
|
63
|
+
fontMono: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
|
|
64
|
+
},
|
|
65
|
+
radii: {
|
|
66
|
+
sm: '6px',
|
|
67
|
+
md: '8px',
|
|
68
|
+
lg: '12px',
|
|
69
|
+
xl: '16px',
|
|
70
|
+
},
|
|
71
|
+
};
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { ThemeConfig } from '../../domain/types';
|
|
2
|
-
import { accessiaTheme } from './accessia.theme';
|
|
3
|
-
import { hangoraTheme } from './hangora.theme';
|
|
4
2
|
import { defaultTheme } from './default.theme';
|
|
3
|
+
import { oceanTheme } from './ocean.theme';
|
|
4
|
+
import { midnightTheme } from './midnight.theme';
|
|
5
|
+
import { editorialTheme } from './editorial.theme';
|
|
5
6
|
|
|
6
7
|
const themeRegistry = new Map<string, ThemeConfig>([
|
|
7
8
|
['default', defaultTheme],
|
|
8
|
-
['
|
|
9
|
-
['
|
|
9
|
+
['ocean', oceanTheme],
|
|
10
|
+
['midnight', midnightTheme],
|
|
11
|
+
['editorial', editorialTheme],
|
|
10
12
|
]);
|
|
11
13
|
|
|
12
14
|
export function registerTheme(theme: ThemeConfig): void {
|