@zen-ui-capri/system 1.1.0 → 1.1.4

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.
@@ -0,0 +1,186 @@
1
+ export type ZenThemeId =
2
+ | 'obsidian-gold'
3
+ | 'blackwall-crimson'
4
+ | 'neon-emerald'
5
+ | 'midnight-cobalt'
6
+ | 'atelier-paper'
7
+ | 'nordic-snow'
8
+ | 'kyoto-matcha'
9
+ | 'cyber-daylight';
10
+
11
+ export type ZenThemeMode = ZenThemeId | 'obsidian' | 'paper';
12
+ export type ZenDensityMode = 'comfortable' | 'compact';
13
+ export type ZenRadiusMode = 'sharp' | 'architectural' | 'soft';
14
+
15
+ export interface ZenThemeMetadata {
16
+ readonly id: ZenThemeId;
17
+ readonly name: string;
18
+ readonly polarity: 'dark' | 'light';
19
+ readonly tagline: string;
20
+ readonly canvasHex: string;
21
+ readonly accentHex: string;
22
+ readonly secondaryHex: string;
23
+ readonly inkHex: string;
24
+ }
25
+
26
+ export const ZEN_THEMES: readonly ZenThemeMetadata[] = [
27
+ {
28
+ id: 'obsidian-gold',
29
+ name: 'Obsidian Gold',
30
+ polarity: 'dark',
31
+ tagline: 'Warm alabaster & solar gold on deep mineral void',
32
+ canvasHex: '#070709',
33
+ accentHex: '#F5B841',
34
+ secondaryHex: '#FB923C',
35
+ inkHex: '#F6F2E9',
36
+ },
37
+ {
38
+ id: 'blackwall-crimson',
39
+ name: 'Capri // Capricorn',
40
+ polarity: 'dark',
41
+ tagline: 'Edgerunners S2 mixed-construct hot pink & acid neon green on void',
42
+ canvasHex: '#050508',
43
+ accentHex: '#FF2E93',
44
+ secondaryHex: '#00FF66',
45
+ inkHex: '#F4F7FA',
46
+ },
47
+ {
48
+ id: 'neon-emerald',
49
+ name: 'Bio-Emerald Terminal',
50
+ polarity: 'dark',
51
+ tagline: 'High-frequency financial & telemetry phosphor emerald',
52
+ canvasHex: '#040807',
53
+ accentHex: '#10B981',
54
+ secondaryHex: '#2DD4BF',
55
+ inkHex: '#ECFDF5',
56
+ },
57
+ {
58
+ id: 'midnight-cobalt',
59
+ name: 'Midnight Cobalt',
60
+ polarity: 'dark',
61
+ tagline: 'Cloud infrastructure & distributed systems deep slate',
62
+ canvasHex: '#060911',
63
+ accentHex: '#38BDF8',
64
+ secondaryHex: '#818CF8',
65
+ inkHex: '#F1F5F9',
66
+ },
67
+ {
68
+ id: 'atelier-paper',
69
+ name: 'Atelier Paper',
70
+ polarity: 'light',
71
+ tagline: 'Swiss archival cotton stock with burnished bronze ink',
72
+ canvasHex: '#F6F2E9',
73
+ accentHex: '#B45309',
74
+ secondaryHex: '#C2410C',
75
+ inkHex: '#121216',
76
+ },
77
+ {
78
+ id: 'nordic-snow',
79
+ name: 'Nordic Snow',
80
+ polarity: 'light',
81
+ tagline: 'Crisp daylight SaaS alabaster with royal cobalt precision',
82
+ canvasHex: '#F8FAFC',
83
+ accentHex: '#2563EB',
84
+ secondaryHex: '#0891B2',
85
+ inkHex: '#0F172A',
86
+ },
87
+ {
88
+ id: 'kyoto-matcha',
89
+ name: 'Kyoto Matcha',
90
+ polarity: 'light',
91
+ tagline: 'Raw botanical stone & forest ink for calm workspaces',
92
+ canvasHex: '#F3F5F0',
93
+ accentHex: '#15803D',
94
+ secondaryHex: '#0F766E',
95
+ inkHex: '#142018',
96
+ },
97
+ {
98
+ id: 'cyber-daylight',
99
+ name: 'Arasaka Daylight',
100
+ polarity: 'light',
101
+ tagline: 'High-contrast titanium white with razor crimson signal',
102
+ canvasHex: '#F2F2F5',
103
+ accentHex: '#E11D48',
104
+ secondaryHex: '#0284C7',
105
+ inkHex: '#09090D',
106
+ },
107
+ ];
108
+
109
+ export interface ZenThemeTokenOverrides {
110
+ readonly accentPrimary?: string;
111
+ readonly bgCanvas?: string;
112
+ readonly surface1?: string;
113
+ readonly inkPrimary?: string;
114
+ }
115
+
116
+ export function syncZenScrollbarStyles(
117
+ themeMeta: ZenThemeMetadata,
118
+ overrides?: ZenThemeTokenOverrides
119
+ ): void {
120
+ if (typeof document === 'undefined') return;
121
+ const accent = overrides?.accentPrimary ?? themeMeta.accentHex;
122
+ const track = overrides?.bgCanvas ?? themeMeta.canvasHex;
123
+ const borderSubtle =
124
+ themeMeta.polarity === 'dark'
125
+ ? 'rgba(255, 255, 255, 0.12)'
126
+ : 'rgba(15, 23, 42, 0.14)';
127
+
128
+ const styleId = 'zen-theme-scrollbar';
129
+ let styleEl = document.getElementById(styleId) as HTMLStyleElement | null;
130
+ if (!styleEl) {
131
+ styleEl = document.createElement('style');
132
+ styleEl.id = styleId;
133
+ document.head.appendChild(styleEl);
134
+ }
135
+
136
+ styleEl.textContent = `
137
+ @supports (-moz-appearance: none) {
138
+ html, body, * {
139
+ scrollbar-width: thin;
140
+ scrollbar-color: ${accent} ${track};
141
+ }
142
+ }
143
+ ::-webkit-scrollbar,
144
+ html::-webkit-scrollbar,
145
+ body::-webkit-scrollbar,
146
+ *::-webkit-scrollbar {
147
+ width: 10px;
148
+ height: 10px;
149
+ }
150
+ ::-webkit-scrollbar-track,
151
+ html::-webkit-scrollbar-track,
152
+ body::-webkit-scrollbar-track,
153
+ *::-webkit-scrollbar-track {
154
+ background-color: ${track};
155
+ border-left: 1px solid ${borderSubtle};
156
+ }
157
+ ::-webkit-scrollbar-thumb,
158
+ html::-webkit-scrollbar-thumb,
159
+ body::-webkit-scrollbar-thumb,
160
+ *::-webkit-scrollbar-thumb {
161
+ background-color: color-mix(in srgb, ${accent} 68%, ${track});
162
+ border: 2px solid ${track};
163
+ border-radius: 9999px;
164
+ }
165
+ ::-webkit-scrollbar-thumb:hover,
166
+ html::-webkit-scrollbar-thumb:hover,
167
+ body::-webkit-scrollbar-thumb:hover,
168
+ *::-webkit-scrollbar-thumb:hover {
169
+ background-color: ${accent};
170
+ border: 2px solid ${track};
171
+ }
172
+ ::-webkit-scrollbar-thumb:active,
173
+ html::-webkit-scrollbar-thumb:active,
174
+ body::-webkit-scrollbar-thumb:active,
175
+ *::-webkit-scrollbar-thumb:active {
176
+ background-color: ${themeMeta.secondaryHex};
177
+ border: 2px solid ${track};
178
+ }
179
+ ::-webkit-scrollbar-corner,
180
+ html::-webkit-scrollbar-corner,
181
+ body::-webkit-scrollbar-corner,
182
+ *::-webkit-scrollbar-corner {
183
+ background-color: ${track};
184
+ }
185
+ `.trim();
186
+ }
@@ -4,20 +4,107 @@ import {
4
4
  type ZenRadiusMode,
5
5
  type ZenThemeId,
6
6
  type ZenThemeMetadata,
7
- } from '../theme/ZenThemeProvider';
7
+ } from '../theme/zen-theme-core';
8
8
  import type {
9
9
  ZenAICameraFraming,
10
10
  ZenAIDirective,
11
11
  ZenAIPersonaMode,
12
12
  } from '../components/ZenAIConstruct';
13
13
  import type { ZenBackgroundVariant } from '../components/ZenAmbientBackground';
14
- import {
15
- renderZenIconSvgMarkup,
16
- type ZenIconName,
17
- type ZenIconSize,
18
- type ZenIconTone,
14
+ import type {
15
+ ZenIconName,
16
+ ZenIconSize,
17
+ ZenIconTone,
19
18
  } from '../components/ZenIcon';
20
19
 
20
+ const UNIVERSAL_ICON_SIZE_PX: Record<ZenIconSize, number> = {
21
+ xs: 12,
22
+ sm: 14,
23
+ md: 16,
24
+ lg: 20,
25
+ xl: 24,
26
+ };
27
+
28
+ const UNIVERSAL_TONE_COLOR_MAP: Record<ZenIconTone, string> = {
29
+ inherit: 'currentColor',
30
+ primary: 'var(--zen-ink-primary)',
31
+ secondary: 'var(--zen-ink-secondary)',
32
+ muted: 'var(--zen-ink-muted)',
33
+ accent: 'var(--zen-accent-primary)',
34
+ success: 'var(--zen-status-success)',
35
+ warning: 'var(--zen-status-warning)',
36
+ danger: 'var(--zen-status-danger)',
37
+ };
38
+
39
+ const UNIVERSAL_ICON_SVG_INNER: Record<ZenIconName, string> = {
40
+ search: '<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>',
41
+ plus: '<path d="M5 12h14"/><path d="M12 5v14"/>',
42
+ minus: '<path d="M5 12h14"/>',
43
+ close: '<path d="M18 6 6 18"/><path d="m6 6 12 12"/>',
44
+ check: '<path d="M20 6 9 17l-5-5"/>',
45
+ copy: '<rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>',
46
+ 'chevron-down': '<path d="m6 9 6 6 6-6"/>',
47
+ 'chevron-right': '<path d="m9 18 6-6-6-6"/>',
48
+ 'chevron-left': '<path d="m15 18-6-6 6-6"/>',
49
+ 'external-link': '<path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>',
50
+ bolt: '<path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z"/>',
51
+ sparkles: '<path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"/><path d="M20 3v4"/><path d="M22 5h-4"/>',
52
+ terminal: '<polyline points="4 17 10 11 4 5"/><line x1="12" x2="20" y1="19" y2="19"/>',
53
+ cpu: '<rect width="16" height="16" x="4" y="4" rx="2"/><rect width="6" height="6" x="9" y="9" rx="1"/><path d="M15 2v2"/><path d="M15 20v2"/><path d="M2 15h2"/><path d="M2 9h2"/><path d="M20 15h2"/><path d="M20 9h2"/><path d="M9 2v2"/><path d="M9 20v2"/>',
54
+ database: '<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14a9 3 0 0 0 18 0V5"/><path d="M3 12a9 3 0 0 0 18 0"/>',
55
+ layers: '<path d="m12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83Z"/><path d="m22 17.65-9.17 4.16a2 2 0 0 1-1.66 0L2 17.65"/><path d="m22 12.65-9.17 4.16a2 2 0 0 1-1.66 0L2 12.65"/>',
56
+ shield: '<path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/>',
57
+ sliders: '<line x1="4" x2="4" y1="21" y2="14"/><line x1="4" x2="4" y1="10" y2="3"/><line x1="12" x2="12" y1="21" y2="12"/><line x1="12" x2="12" y1="8" y2="3"/><line x1="20" x2="20" y1="21" y2="16"/><line x1="20" x2="20" y1="12" y2="3"/><line x1="2" x2="6" y1="14" y2="14"/><line x1="10" x2="14" y1="8" y2="8"/><line x1="18" x2="22" y1="16" y2="16"/>',
58
+ command: '<path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3"/>',
59
+ code: '<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>',
60
+ activity: '<path d="M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2"/>',
61
+ info: '<circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/>',
62
+ success: '<circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/>',
63
+ warning: '<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/>',
64
+ danger: '<path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/><path d="M12 8v4"/><path d="M12 16h.01"/>',
65
+ 'trend-up': '<polyline points="22 7 13.5 15.5 8.5 10.5 2 17"/><polyline points="16 7 22 7 22 13"/>',
66
+ 'trend-down': '<polyline points="22 17 13.5 8.5 8.5 13.5 2 7"/><polyline points="16 17 22 17 22 11"/>',
67
+ radio: '<path d="M4.9 19.1C1 15.2 1 8.8 4.9 4.9"/><path d="M7.8 16.2c-2.3-2.3-2.3-6.1 0-8.5"/><circle cx="12" cy="12" r="2"/><path d="M16.2 7.8c2.3 2.3 2.3 6.1 0 8.5"/><path d="M19.1 4.9C23 8.8 23 15.1 19.1 19"/>',
68
+ sun: '<circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/>',
69
+ moon: '<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>',
70
+ eye: '<path d="M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0"/><circle cx="12" cy="12" r="3"/>',
71
+ upload: '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" x2="12" y1="3" y2="15"/>',
72
+ trash: '<path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/>',
73
+ refresh: '<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M8 16H3v5"/>',
74
+ menu: '<line x1="4" x2="20" y1="12" y2="12"/><line x1="4" x2="20" y1="6" y2="6"/><line x1="4" x2="20" y1="18" y2="18"/>',
75
+ 'panel-right': '<rect width="18" height="18" x="3" y="3" rx="2"/><path d="M15 3v18"/>',
76
+ user: '<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>',
77
+ lock: '<rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>',
78
+ globe: '<circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/>',
79
+ folder: '<path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/>',
80
+ };
81
+
82
+ function renderZenIconSvgMarkup(options: {
83
+ readonly name: ZenIconName;
84
+ readonly size?: ZenIconSize;
85
+ readonly tone?: ZenIconTone;
86
+ readonly strokeWidth?: number;
87
+ readonly spin?: boolean;
88
+ }): string {
89
+ const sizeKey = options.size ?? 'md';
90
+ const px = Object.prototype.hasOwnProperty.call(UNIVERSAL_ICON_SIZE_PX, sizeKey)
91
+ ? UNIVERSAL_ICON_SIZE_PX[sizeKey]
92
+ : UNIVERSAL_ICON_SIZE_PX.md;
93
+ const toneKey = options.tone ?? 'inherit';
94
+ const color = Object.prototype.hasOwnProperty.call(UNIVERSAL_TONE_COLOR_MAP, toneKey)
95
+ ? UNIVERSAL_TONE_COLOR_MAP[toneKey]
96
+ : UNIVERSAL_TONE_COLOR_MAP.inherit;
97
+ const sw =
98
+ typeof options.strokeWidth === 'number' && Number.isFinite(options.strokeWidth)
99
+ ? Math.min(Math.max(options.strokeWidth, 0.5), 4)
100
+ : 2;
101
+ const inner = Object.prototype.hasOwnProperty.call(UNIVERSAL_ICON_SVG_INNER, options.name)
102
+ ? UNIVERSAL_ICON_SVG_INNER[options.name]
103
+ : UNIVERSAL_ICON_SVG_INNER.sparkles;
104
+ const spinStyle = options.spin ? 'animation: spin 1s linear infinite;' : '';
105
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${px}" height="${px}" viewBox="0 0 24 24" fill="none" stroke="${color}" stroke-width="${sw}" stroke-linecap="round" stroke-linejoin="round" style="display:inline-block;vertical-align:middle;flex-shrink:0;${spinStyle}">${inner}</svg>`;
106
+ }
107
+
21
108
  export type ZenUniversalPolarity = 'dark' | 'light';
22
109
 
23
110
  export interface ZenUniversalThemeState {
@@ -696,7 +783,8 @@ export function escapeZenHtml(raw: string): string {
696
783
 
697
784
  export function sanitizeZenAssetUrl(raw: string): string {
698
785
  const trimmed = raw.trim();
699
- if (/^(?:javascript|data|vbscript)\s*:/i.test(trimmed)) {
786
+ const normalizedSchemeCheck = trimmed.replace(/[\u0000-\u0020]+/g, '');
787
+ if (/^(?:javascript|data|vbscript|file):/i.test(normalizedSchemeCheck)) {
700
788
  return '/capri-construct-base.png';
701
789
  }
702
790
  return escapeZenHtml(trimmed);