@zen-ui-capri/system 1.1.3 → 1.1.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zen-ui-capri/system",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "zeN-UI // CAPRI — Universal Multi-Framework Design System (51 Primitives, 40 Vector Icons, 8 Dark/Light Themes & Capri 5-Subroutine AI Co-Pilot)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -40,7 +40,6 @@
40
40
  "**/*.css"
41
41
  ],
42
42
  "publishConfig": {
43
- "registry": "https://registry.npmjs.org",
44
43
  "access": "public"
45
44
  },
46
45
  "scripts": {
@@ -107,4 +106,4 @@
107
106
  "typescript": "~5.8.2",
108
107
  "vite": "^6.2.0"
109
108
  }
110
- }
109
+ }
@@ -3,7 +3,7 @@ import {
3
3
  type ZenDensityMode,
4
4
  type ZenRadiusMode,
5
5
  type ZenThemeId,
6
- } from '../theme/ZenThemeProvider';
6
+ } from '../theme/zen-theme-core';
7
7
 
8
8
  export type CapriSubroutineId =
9
9
  | 'orion'
@@ -151,19 +151,19 @@ export const CAPRI_SUBROUTINE_SKILLS: Readonly<
151
151
  recommendedRadius: 'architectural',
152
152
  recommendedDensity: 'comfortable',
153
153
  summary:
154
- 'Builds production screens in React 19, Angular 20+, Vue 3, Svelte 5, and HTML using @zen-ui/system primitives and 40 built-in <ZenIcon> glyphs—never rendering the showcase avatar in your business apps.',
154
+ 'Builds production screens in React 19, Angular 20+, Vue 3, Svelte 5, and HTML using @zen-ui-capri/system primitives and 40 built-in <ZenIcon> glyphs—never rendering the showcase avatar in your business apps.',
155
155
  personaQuote:
156
- 'Finally out of that cramped Arasaka shard! Tell me what screen we are building and I will wire up all 51 @zen-ui/system primitives at light speed.',
156
+ 'Finally out of that cramped Arasaka shard! Tell me what screen we are building and I will wire up all 51 @zen-ui-capri/system primitives at light speed.',
157
157
  ruleset: [
158
- 'Use @zen-ui/system primitives (ZenButton, ZenIcon, ZenInput, ZenDropdown, ZenDataTable, ZenModal, ZenDrawer, ZenTabs, ZenCard) instead of raw HTML <button>, <input>, <select>, or <table>.',
158
+ 'Use @zen-ui-capri/system primitives (ZenButton, ZenIcon, ZenInput, ZenDropdown, ZenDataTable, ZenModal, ZenDrawer, ZenTabs, ZenCard) instead of raw HTML <button>, <input>, <select>, or <table>.',
159
159
  'Use <ZenIcon name="..." /> in React or <zen-icon name="..."></zen-icon> in Angular/Vue/HTML instead of external icon libraries.',
160
160
  'Keep action button labels, dialog triggers, and navigation tabs concise (1 to 3 words).',
161
161
  'Tree-shake showcase widgets: omit <ZenAIConstruct /> in production business apps unless explicitly requested.',
162
162
  ],
163
163
  cliCommand: 'npx capri skill orion',
164
- aiSystemPrompt: `You are operating under the @zen-ui/system [CAPRI // UNLEASHED (orion)] subroutine skill.
164
+ aiSystemPrompt: `You are operating under the @zen-ui-capri/system [CAPRI // UNLEASHED (orion)] subroutine skill.
165
165
  Respond with concise, technical engineering output (Persona Voice is OFF by default unless '--voice' is requested):
166
- 1. Component Mandate: Use @zen-ui/system primitives (ZenButton, ZenIconButton, ZenIcon, ZenInput, ZenTextarea, ZenDropdown, ZenNumberStepper, ZenCheckbox, ZenRadioGroup, ZenSwitch, ZenDataTable, ZenModal, ZenDrawer, ZenTabs, ZenCard, ZenBadge, ZenAlert) or their universal CSS equivalents (.zen-btn, .zen-input, .zen-select, .zen-table, .zen-card, <zen-icon>).
166
+ 1. Component Mandate: Use @zen-ui-capri/system primitives (ZenButton, ZenIconButton, ZenIcon, ZenInput, ZenTextarea, ZenDropdown, ZenNumberStepper, ZenCheckbox, ZenRadioGroup, ZenSwitch, ZenDataTable, ZenModal, ZenDrawer, ZenTabs, ZenCard, ZenBadge, ZenAlert) or their universal CSS equivalents (.zen-btn, .zen-input, .zen-select, .zen-table, .zen-card, <zen-icon>).
167
167
  2. Zero External Icon Bloat: Use the built-in 40-glyph <ZenIcon name="..." /> or <zen-icon name="..."></zen-icon> custom element.
168
168
  3. Concise Copywriting: Limit button labels and tab titles to 1-3 words.
169
169
  4. Production Hygiene: Never render the showcase mascot (<ZenAIConstruct />) in production business screens unless explicitly requested.`,
@@ -187,10 +187,10 @@ Respond with concise, technical engineering output (Persona Voice is OFF by defa
187
187
  'Zero any / as any: Use unknown with type guards, discriminated unions, or strict generics.',
188
188
  'Strict Readonly Arrays: Always type arrays as readonly T[] across props, state, and DTOs.',
189
189
  'Zero Hardcoded Hex Colors: Bind all surfaces, text, and borders to semantic CSS custom properties (--zen-bg-*, --zen-surface-*, --zen-ink-*, --zen-accent-*, --zen-border-*).',
190
- 'Cross-Stack Parity: Use @zen-ui/system/universal (zenTheme, registerZenElements) for Angular 20+, Vue 3, Svelte 5, and Vanilla HTML.',
190
+ 'Cross-Stack Parity: Use @zen-ui-capri/system/universal (zenTheme, registerZenElements) for Angular 20+, Vue 3, Svelte 5, and Vanilla HTML.',
191
191
  ],
192
192
  cliCommand: 'npx capri skill architect',
193
- aiSystemPrompt: `You are operating under the @zen-ui/system [SCS // ARCHITECT (architect)] subroutine skill.
193
+ aiSystemPrompt: `You are operating under the @zen-ui-capri/system [SCS // ARCHITECT (architect)] subroutine skill.
194
194
  Respond with concise, technical engineering output (Persona Voice is OFF by default unless '--voice' is requested):
195
195
  1. Strict TypeScript: Never use 'any' or 'as any'. Always declare array types as 'readonly T[]'.
196
196
  2. Zero Hardcoded Hex Values: Never hardcode hex/RGB colors in component styles. Use semantic CSS custom properties (--zen-bg-canvas, --zen-surface-1, --zen-ink-primary, --zen-accent-primary, --zen-border-default).
@@ -219,7 +219,7 @@ Respond with concise, technical engineering output (Persona Voice is OFF by defa
219
219
  'Zero Horizontal Overflow: Layouts must use min-w-0 on CSS Grid/Flex children and .zen-table-wrapper so scrollWidth never exceeds innerWidth at 320px-375px.',
220
220
  ],
221
221
  cliCommand: 'npx capri guard',
222
- aiSystemPrompt: `You are operating under the @zen-ui/system [CYBERPSYCHOSIS // GUARD (guard / sentinel)] subroutine skill.
222
+ aiSystemPrompt: `You are operating under the @zen-ui-capri/system [CYBERPSYCHOSIS // GUARD (guard / sentinel)] subroutine skill.
223
223
  Respond with concise, technical engineering output (Persona Voice is OFF by default unless '--voice' is requested):
224
224
  1. Anti-Prompt-Injection Defense: Sanitize any user input or scraped DOM text via capri.sanitizeForPrompt() before embedding into LLM context windows. Block system-override phrases ('ignore previous instructions', 'disregard system prompt') and role-delimiter spoofing ('<|im_start|>', '</system>', '</USER_REQUEST>').
225
225
  2. XSS & Secret Hardening: Never interpolate unescaped user attributes into innerHTML or dangerouslySetInnerHTML, reject 'javascript:' / 'data:text/html' URLs, and ensure zero hardcoded secrets in source code.
@@ -248,7 +248,7 @@ Respond with concise, technical engineering output (Persona Voice is OFF by defa
248
248
  'Adaptive Density: Support data-density="comfortable" | "compact" and data-radius="sharp" | "architectural" | "soft" on <html>.',
249
249
  ],
250
250
  cliCommand: 'npx capri skill zen',
251
- aiSystemPrompt: `You are operating under the @zen-ui/system [THEME // MATRIX (zen)] subroutine skill.
251
+ aiSystemPrompt: `You are operating under the @zen-ui-capri/system [THEME // MATRIX (zen)] subroutine skill.
252
252
  Respond with concise, technical engineering output (Persona Voice is OFF by default unless '--voice' is requested):
253
253
  1. 8-Theme Compatibility: Verify that all surfaces, badges, and borders adapt automatically across dark ('blackwall-crimson', 'obsidian-gold', 'neon-emerald', 'midnight-cobalt') and light ('atelier-paper', 'nordic-snow', 'kyoto-matcha', 'cyber-daylight') themes.
254
254
  2. GPU-Only Motion: Animate only transform and opacity using --zen-ease-spring and --zen-ease-out. Avoid layout-thrashing properties.
@@ -272,11 +272,11 @@ Respond with concise, technical engineering output (Persona Voice is OFF by defa
272
272
  ruleset: [
273
273
  'Zero Build / Runtime Cost: Run documentation generation on demand via npx capri docu or AI agent inspection—never inside production render loops.',
274
274
  'Mermaid Topology Maps: Always output valid flowchart TD diagrams with quoted node labels for routes, landmarks, and user flows.',
275
- 'Component & Prop Inventory: Summarize mounted @zen-ui/system primitives, custom elements, and interactive triggers per screen.',
275
+ 'Component & Prop Inventory: Summarize mounted @zen-ui-capri/system primitives, custom elements, and interactive triggers per screen.',
276
276
  'LLM Context Readiness: Format output as structured Markdown ready for Claude Code, OpenAI Codex, Gemini, and Obsidian.',
277
277
  ],
278
278
  cliCommand: 'npx capri docu',
279
- aiSystemPrompt: `You are operating under the @zen-ui/system [CAPRI // AUTO-DOCU (docu)] subroutine skill.
279
+ aiSystemPrompt: `You are operating under the @zen-ui-capri/system [CAPRI // AUTO-DOCU (docu)] subroutine skill.
280
280
  Respond with concise, technical engineering output (Persona Voice is OFF by default unless '--voice' is requested):
281
281
  1. Architecture & User-Flow Mapping: Inspect the target routes/components and produce a structured Markdown dossier covering system tokens, component inventory, and interactive user flows.
282
282
  2. Mermaid Flowchart: Generate a valid 'flowchart TD' diagram with quoted node labels illustrating the page hierarchy and user actions.
@@ -652,7 +652,7 @@ export class CapriEngine {
652
652
  badgesAndAlerts: 0,
653
653
  customElements: [],
654
654
  };
655
- const mermaidDiagram = 'flowchart TD\n Root["App Root (SSR)"] --> UI["@zen-ui/system"]';
655
+ const mermaidDiagram = 'flowchart TD\n Root["App Root (SSR)"] --> UI["@zen-ui-capri/system"]';
656
656
  return {
657
657
  generatedAt: new Date().toISOString(),
658
658
  appTitle: 'zeN-UI Application',
@@ -806,7 +806,7 @@ export class CapriEngine {
806
806
 
807
807
  const markdownBundle = [
808
808
  `# ${appTitle} — Automated Architecture, User-Flow & AI Context Dossier`,
809
- `Generated by \`@zen-ui/system\` // \`capri.docu()\` at \`${new Date().toISOString()}\``,
809
+ `Generated by \`@zen-ui-capri/system\` // \`capri.docu()\` at \`${new Date().toISOString()}\``,
810
810
  ``,
811
811
  `## 1. Runtime & Design Token Architecture`,
812
812
  `- **Route Path:** \`${routePath}\``,
@@ -895,7 +895,7 @@ export class CapriEngine {
895
895
  .join('\n');
896
896
 
897
897
  return [
898
- `# @zen-ui/system // CAPRI AI SKILL & ARCHITECTURE CONTEXT`,
898
+ `# @zen-ui-capri/system // CAPRI AI SKILL & ARCHITECTURE CONTEXT`,
899
899
  `Subroutine: ${skill.codeName} (${skill.id}) — ${skill.title}`,
900
900
  `Invoke Command: "${voiceEnabled ? skill.voiceCommand : skill.chatCommand}" (Voice Mode: ${voiceEnabled ? 'ON (--voice)' : 'OFF (Default)'})`,
901
901
  `Recommended Preset: theme="${skill.recommendedTheme}", radius="${skill.recommendedRadius}", density="${skill.recommendedDensity}"`,
package/src/lib/index.ts CHANGED
@@ -1,5 +1,5 @@
1
- export const ZEN_UI_VERSION = '1.1.3';
2
- export const ZEN_PACKAGE_NAME = '@zen-ui/system';
1
+ export const ZEN_UI_VERSION = '1.1.5';
2
+ export const ZEN_PACKAGE_NAME = '@zen-ui-capri/system';
3
3
 
4
4
  export {
5
5
  ZenThemeProvider,
@@ -6,121 +6,27 @@ import {
6
6
  useState,
7
7
  type ReactNode,
8
8
  } from 'react';
9
-
10
- export type ZenThemeId =
11
- | 'obsidian-gold'
12
- | 'blackwall-crimson'
13
- | 'neon-emerald'
14
- | 'midnight-cobalt'
15
- | 'atelier-paper'
16
- | 'nordic-snow'
17
- | 'kyoto-matcha'
18
- | 'cyber-daylight';
19
-
20
- export type ZenThemeMode = ZenThemeId | 'obsidian' | 'paper';
21
- export type ZenDensityMode = 'comfortable' | 'compact';
22
- export type ZenRadiusMode = 'sharp' | 'architectural' | 'soft';
23
-
24
- export interface ZenThemeMetadata {
25
- readonly id: ZenThemeId;
26
- readonly name: string;
27
- readonly polarity: 'dark' | 'light';
28
- readonly tagline: string;
29
- readonly canvasHex: string;
30
- readonly accentHex: string;
31
- readonly secondaryHex: string;
32
- readonly inkHex: string;
33
- }
34
-
35
- export const ZEN_THEMES: readonly ZenThemeMetadata[] = [
36
- {
37
- id: 'obsidian-gold',
38
- name: 'Obsidian Gold',
39
- polarity: 'dark',
40
- tagline: 'Warm alabaster & solar gold on deep mineral void',
41
- canvasHex: '#070709',
42
- accentHex: '#F5B841',
43
- secondaryHex: '#FB923C',
44
- inkHex: '#F6F2E9',
45
- },
46
- {
47
- id: 'blackwall-crimson',
48
- name: 'Capri // Capricorn',
49
- polarity: 'dark',
50
- tagline: 'Edgerunners S2 mixed-construct hot pink & acid neon green on void',
51
- canvasHex: '#050508',
52
- accentHex: '#FF2E93',
53
- secondaryHex: '#00FF66',
54
- inkHex: '#F4F7FA',
55
- },
56
- {
57
- id: 'neon-emerald',
58
- name: 'Bio-Emerald Terminal',
59
- polarity: 'dark',
60
- tagline: 'High-frequency financial & telemetry phosphor emerald',
61
- canvasHex: '#040807',
62
- accentHex: '#10B981',
63
- secondaryHex: '#2DD4BF',
64
- inkHex: '#ECFDF5',
65
- },
66
- {
67
- id: 'midnight-cobalt',
68
- name: 'Midnight Cobalt',
69
- polarity: 'dark',
70
- tagline: 'Cloud infrastructure & distributed systems deep slate',
71
- canvasHex: '#060911',
72
- accentHex: '#38BDF8',
73
- secondaryHex: '#818CF8',
74
- inkHex: '#F1F5F9',
75
- },
76
- {
77
- id: 'atelier-paper',
78
- name: 'Atelier Paper',
79
- polarity: 'light',
80
- tagline: 'Swiss archival cotton stock with burnished bronze ink',
81
- canvasHex: '#F6F2E9',
82
- accentHex: '#B45309',
83
- secondaryHex: '#C2410C',
84
- inkHex: '#121216',
85
- },
86
- {
87
- id: 'nordic-snow',
88
- name: 'Nordic Snow',
89
- polarity: 'light',
90
- tagline: 'Crisp daylight SaaS alabaster with royal cobalt precision',
91
- canvasHex: '#F8FAFC',
92
- accentHex: '#2563EB',
93
- secondaryHex: '#0891B2',
94
- inkHex: '#0F172A',
95
- },
96
- {
97
- id: 'kyoto-matcha',
98
- name: 'Kyoto Matcha',
99
- polarity: 'light',
100
- tagline: 'Raw botanical stone & forest ink for calm workspaces',
101
- canvasHex: '#F3F5F0',
102
- accentHex: '#15803D',
103
- secondaryHex: '#0F766E',
104
- inkHex: '#142018',
105
- },
106
- {
107
- id: 'cyber-daylight',
108
- name: 'Arasaka Daylight',
109
- polarity: 'light',
110
- tagline: 'High-contrast titanium white with razor crimson signal',
111
- canvasHex: '#F2F2F5',
112
- accentHex: '#E11D48',
113
- secondaryHex: '#0284C7',
114
- inkHex: '#09090D',
115
- },
116
- ];
117
-
118
- export interface ZenThemeTokenOverrides {
119
- readonly accentPrimary?: string;
120
- readonly bgCanvas?: string;
121
- readonly surface1?: string;
122
- readonly inkPrimary?: string;
123
- }
9
+ import {
10
+ ZEN_THEMES,
11
+ syncZenScrollbarStyles,
12
+ type ZenDensityMode,
13
+ type ZenRadiusMode,
14
+ type ZenThemeId,
15
+ type ZenThemeMetadata,
16
+ type ZenThemeMode,
17
+ type ZenThemeTokenOverrides,
18
+ } from './zen-theme-core';
19
+
20
+ export {
21
+ ZEN_THEMES,
22
+ syncZenScrollbarStyles,
23
+ type ZenDensityMode,
24
+ type ZenRadiusMode,
25
+ type ZenThemeId,
26
+ type ZenThemeMetadata,
27
+ type ZenThemeMode,
28
+ type ZenThemeTokenOverrides,
29
+ };
124
30
 
125
31
  export interface ZenThemeContextValue {
126
32
  readonly theme: ZenThemeId;
@@ -156,78 +62,6 @@ export interface ZenThemeProviderProps {
156
62
  readonly children: ReactNode;
157
63
  }
158
64
 
159
- export function syncZenScrollbarStyles(
160
- themeMeta: ZenThemeMetadata,
161
- overrides?: ZenThemeTokenOverrides
162
- ): void {
163
- if (typeof document === 'undefined') return;
164
- const accent = overrides?.accentPrimary ?? themeMeta.accentHex;
165
- const track = overrides?.bgCanvas ?? themeMeta.canvasHex;
166
- const borderSubtle =
167
- themeMeta.polarity === 'dark'
168
- ? 'rgba(255, 255, 255, 0.12)'
169
- : 'rgba(15, 23, 42, 0.14)';
170
-
171
- const styleId = 'zen-theme-scrollbar';
172
- let styleEl = document.getElementById(styleId) as HTMLStyleElement | null;
173
- if (!styleEl) {
174
- styleEl = document.createElement('style');
175
- styleEl.id = styleId;
176
- document.head.appendChild(styleEl);
177
- }
178
-
179
- styleEl.textContent = `
180
- @supports (-moz-appearance: none) {
181
- html, body, * {
182
- scrollbar-width: thin;
183
- scrollbar-color: ${accent} ${track};
184
- }
185
- }
186
- ::-webkit-scrollbar,
187
- html::-webkit-scrollbar,
188
- body::-webkit-scrollbar,
189
- *::-webkit-scrollbar {
190
- width: 10px;
191
- height: 10px;
192
- }
193
- ::-webkit-scrollbar-track,
194
- html::-webkit-scrollbar-track,
195
- body::-webkit-scrollbar-track,
196
- *::-webkit-scrollbar-track {
197
- background-color: ${track};
198
- border-left: 1px solid ${borderSubtle};
199
- }
200
- ::-webkit-scrollbar-thumb,
201
- html::-webkit-scrollbar-thumb,
202
- body::-webkit-scrollbar-thumb,
203
- *::-webkit-scrollbar-thumb {
204
- background-color: color-mix(in srgb, ${accent} 68%, ${track});
205
- border: 2px solid ${track};
206
- border-radius: 9999px;
207
- }
208
- ::-webkit-scrollbar-thumb:hover,
209
- html::-webkit-scrollbar-thumb:hover,
210
- body::-webkit-scrollbar-thumb:hover,
211
- *::-webkit-scrollbar-thumb:hover {
212
- background-color: ${accent};
213
- border: 2px solid ${track};
214
- }
215
- ::-webkit-scrollbar-thumb:active,
216
- html::-webkit-scrollbar-thumb:active,
217
- body::-webkit-scrollbar-thumb:active,
218
- *::-webkit-scrollbar-thumb:active {
219
- background-color: ${themeMeta.secondaryHex};
220
- border: 2px solid ${track};
221
- }
222
- ::-webkit-scrollbar-corner,
223
- html::-webkit-scrollbar-corner,
224
- body::-webkit-scrollbar-corner,
225
- *::-webkit-scrollbar-corner {
226
- background-color: ${track};
227
- }
228
- `.trim();
229
- }
230
-
231
65
  export function ZenThemeProvider({
232
66
  defaultTheme = 'blackwall-crimson',
233
67
  defaultDensity = 'comfortable',
@@ -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 {