@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.
@@ -9,7 +9,11 @@ import {
9
9
  registerTheme,
10
10
  applyTheme,
11
11
  themeToCssVariables,
12
- accessiaTheme,
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('accessia').name).toBe('accessia');
27
- expect(getTheme('hangora').name).toBe('hangora');
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(accessiaTheme);
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(accessiaTheme);
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="accessia" mode="dark">
144
+ <DesignSystemProvider theme="midnight" mode="dark">
96
145
  <Consumer />
97
146
  </DesignSystemProvider>
98
147
  );
99
148
 
100
- expect(screen.getByTestId('theme-name').textContent).toBe('accessia');
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,7 +1,7 @@
1
1
  import type { ThemeConfig } from '../../domain/types';
2
2
 
3
- export const hangoraTheme: ThemeConfig = {
4
- name: 'hangora',
3
+ export const editorialTheme: ThemeConfig = {
4
+ name: 'editorial',
5
5
  mode: 'light',
6
6
  colors: {
7
7
  background: '#f4f1e9',
@@ -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';
@@ -1,7 +1,7 @@
1
1
  import type { ThemeConfig } from '../../domain/types';
2
2
 
3
- export const accessiaTheme: ThemeConfig = {
4
- name: 'accessia',
3
+ export const midnightTheme: ThemeConfig = {
4
+ name: 'midnight',
5
5
  mode: 'dark',
6
6
  colors: {
7
7
  background: '#060a12',
@@ -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
- ['accessia', accessiaTheme],
9
- ['hangora', hangoraTheme],
9
+ ['ocean', oceanTheme],
10
+ ['midnight', midnightTheme],
11
+ ['editorial', editorialTheme],
10
12
  ]);
11
13
 
12
14
  export function registerTheme(theme: ThemeConfig): void {
@@ -3,6 +3,7 @@
3
3
  @import "tw-animate-css";
4
4
  @import "./theme.css";
5
5
  @import "./charts.css";
6
+ @import "./console.css";
6
7
  @source "../src";
7
8
 
8
9
  @media (max-width: 767.98px) {