@miozu/jera 0.4.4 → 0.5.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/ARCHITECTURE.md +657 -0
- package/CLAUDE.md +24 -1
- package/llms.txt +69 -57
- package/package.json +5 -6
- package/src/components/navigation/DropdownContainer.svelte +575 -0
- package/src/components/navigation/LeftBar.svelte +179 -0
- package/src/components/navigation/LeftBarItem.svelte +267 -0
- package/src/components/navigation/LeftBarPopover.svelte +121 -0
- package/src/components/navigation/LeftBarSection.svelte +63 -0
- package/src/components/navigation/LeftBarToggle.svelte +87 -0
- package/src/components/primitives/Button.svelte +147 -94
- package/src/index.js +8 -0
package/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,657 @@
|
|
|
1
|
+
# @miozu/jera - Architecture Documentation
|
|
2
|
+
|
|
3
|
+
**Last Updated:** February 2026
|
|
4
|
+
**Version:** 0.5.0+
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
jera is a **zero-dependency, AI-first component library** for Svelte 5. It follows a layered architecture that separates design tokens, CSS, and framework-specific code.
|
|
11
|
+
|
|
12
|
+
### Design Philosophy
|
|
13
|
+
|
|
14
|
+
1. **CSS is the library** - Pure modern CSS is 100% portable
|
|
15
|
+
2. **Framework wrappers are thin** - Svelte components are ~50-100 lines
|
|
16
|
+
3. **Zero dependencies** - No external runtime dependencies
|
|
17
|
+
4. **AI-first documentation** - llms.txt standard for AI assistants
|
|
18
|
+
5. **Browser-native** - Modern CSS features over JS polyfills
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Architecture Layers
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
26
|
+
│ Layer 5: AI Documentation │
|
|
27
|
+
│ llms.txt, llms-full.txt, CLAUDE.md │
|
|
28
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
29
|
+
│
|
|
30
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
31
|
+
│ Layer 4: Framework Wrappers │
|
|
32
|
+
│ Svelte 5 Components │
|
|
33
|
+
│ (Native runes: $state, $derived, $props) │
|
|
34
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
35
|
+
│
|
|
36
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
37
|
+
│ Layer 3: Pure CSS │
|
|
38
|
+
│ Component styles using CSS custom properties │
|
|
39
|
+
│ (nesting, :has(), container queries, color-mix()) │
|
|
40
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
41
|
+
│
|
|
42
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
43
|
+
│ Layer 2: CSS Custom Properties │
|
|
44
|
+
│ Generated from tokens.json │
|
|
45
|
+
│ (--color-*, --space-*, --font-*) │
|
|
46
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
47
|
+
│
|
|
48
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
49
|
+
│ Layer 1: W3C Design Tokens (DTCG) │
|
|
50
|
+
│ tokens.json │
|
|
51
|
+
│ (Single source of truth for all values) │
|
|
52
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Layer 1: W3C Design Tokens (DTCG)
|
|
58
|
+
|
|
59
|
+
Design tokens are defined following the [W3C Design Tokens Community Group](https://design-tokens.github.io/community-group/format/) specification (stable October 2025).
|
|
60
|
+
|
|
61
|
+
### Token Structure
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"$type": "color",
|
|
66
|
+
"color": {
|
|
67
|
+
"base": {
|
|
68
|
+
"00": { "$value": "#0f1419", "$description": "Primary background (dark)" },
|
|
69
|
+
"01": { "$value": "#1a1f26", "$description": "Surface/card" },
|
|
70
|
+
"0D": { "$value": "#61afef", "$description": "Primary/blue" }
|
|
71
|
+
},
|
|
72
|
+
"semantic": {
|
|
73
|
+
"bg": { "$value": "{color.base.00}" },
|
|
74
|
+
"surface": { "$value": "{color.base.01}" },
|
|
75
|
+
"primary": { "$value": "{color.base.0D}" }
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"space": {
|
|
79
|
+
"1": { "$value": "4px", "$type": "dimension" },
|
|
80
|
+
"2": { "$value": "8px", "$type": "dimension" },
|
|
81
|
+
"4": { "$value": "16px", "$type": "dimension" }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Base16 Color System (CRITICAL)
|
|
87
|
+
|
|
88
|
+
jera uses the **Miozu Base16 color system** as its foundation. All 16 colors follow the standard Base16 naming convention.
|
|
89
|
+
|
|
90
|
+
**Token Naming (hex digits, NOT decimal):**
|
|
91
|
+
```
|
|
92
|
+
base00, base01, base02, base03, base04, base05, base06, base07
|
|
93
|
+
base08, base09, base0A, base0B, base0C, base0D, base0E, base0F
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**NEVER use:** `base0`, `base1`, `base10`, `base15` (these are incorrect)
|
|
97
|
+
|
|
98
|
+
**Color Responsibilities:**
|
|
99
|
+
|
|
100
|
+
| Token | Dark Theme | Light Theme | Usage |
|
|
101
|
+
|-------|------------|-------------|-------|
|
|
102
|
+
| base00 | #0f1419 | #ffffff | Primary background |
|
|
103
|
+
| base01 | #1a1f26 | #f8f9fa | Surface/card |
|
|
104
|
+
| base02 | #242a33 | #f1f3f5 | Selection/hover |
|
|
105
|
+
| base03 | #4a5568 | #adb5bd | Muted/disabled |
|
|
106
|
+
| base04 | #a0aec0 | #6c757d | Secondary text |
|
|
107
|
+
| base05 | #e2e8f0 | #212529 | Primary text |
|
|
108
|
+
| base06 | #f7fafc | #1a1d20 | High emphasis |
|
|
109
|
+
| base07 | #ffffff | #0d0f10 | Maximum contrast |
|
|
110
|
+
| base08 | #e06c75 | #dc3545 | Error/red |
|
|
111
|
+
| base09 | #d19a66 | #fd7e14 | Warning/orange |
|
|
112
|
+
| base0A | #e5c07b | #ffc107 | Highlight/yellow |
|
|
113
|
+
| base0B | #98c379 | #28a745 | Success/green |
|
|
114
|
+
| base0C | #56b6c2 | #17a2b8 | Info/cyan |
|
|
115
|
+
| base0D | #61afef | #007bff | Primary/blue |
|
|
116
|
+
| base0E | #c678dd | #6f42c1 | Accent/purple |
|
|
117
|
+
| base0F | #be5046 | #e83e8c | Secondary accent |
|
|
118
|
+
|
|
119
|
+
### Token Build Process
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# tokens.json → CSS custom properties
|
|
123
|
+
node tokens/build.js
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The build script generates `tokens.css` with all CSS custom properties:
|
|
127
|
+
|
|
128
|
+
```css
|
|
129
|
+
:root {
|
|
130
|
+
--color-base00: #0f1419;
|
|
131
|
+
--color-base01: #1a1f26;
|
|
132
|
+
/* ... */
|
|
133
|
+
--space-1: 4px;
|
|
134
|
+
--space-2: 8px;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
[data-theme='miozu-light'] {
|
|
138
|
+
--color-base00: #ffffff;
|
|
139
|
+
--color-base01: #f8f9fa;
|
|
140
|
+
/* ... grayscale inverts, accents adjust */
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Layer 2: CSS Custom Properties
|
|
147
|
+
|
|
148
|
+
Generated CSS custom properties serve as the interface between tokens and component styles.
|
|
149
|
+
|
|
150
|
+
### Naming Conventions
|
|
151
|
+
|
|
152
|
+
| Prefix | Purpose | Example |
|
|
153
|
+
|--------|---------|---------|
|
|
154
|
+
| `--color-` | Colors | `--color-base0D`, `--color-primary` |
|
|
155
|
+
| `--space-` | Spacing | `--space-1`, `--space-4` |
|
|
156
|
+
| `--font-` | Typography | `--font-size-sm`, `--font-weight-bold` |
|
|
157
|
+
| `--radius-` | Border radius | `--radius-sm`, `--radius-full` |
|
|
158
|
+
| `--shadow-` | Box shadows | `--shadow-sm`, `--shadow-lg` |
|
|
159
|
+
| `--z-` | Z-index layers | `--z-modal`, `--z-toast` |
|
|
160
|
+
|
|
161
|
+
### Semantic Color Aliases
|
|
162
|
+
|
|
163
|
+
Components use semantic aliases that map to Base16:
|
|
164
|
+
|
|
165
|
+
```css
|
|
166
|
+
/* In tokens.css */
|
|
167
|
+
:root {
|
|
168
|
+
--color-bg: var(--color-base00);
|
|
169
|
+
--color-surface: var(--color-base01);
|
|
170
|
+
--color-surface-alt: var(--color-base02);
|
|
171
|
+
--color-text: var(--color-base05);
|
|
172
|
+
--color-text-strong: var(--color-base07);
|
|
173
|
+
--color-text-muted: var(--color-base04);
|
|
174
|
+
--color-primary: var(--color-base0D);
|
|
175
|
+
--color-success: var(--color-base0B);
|
|
176
|
+
--color-warning: var(--color-base0A);
|
|
177
|
+
--color-error: var(--color-base08);
|
|
178
|
+
--color-info: var(--color-base0C);
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Layer 3: Pure CSS Components
|
|
185
|
+
|
|
186
|
+
Component styles use modern CSS features and are framework-agnostic.
|
|
187
|
+
|
|
188
|
+
### Modern CSS Features Used
|
|
189
|
+
|
|
190
|
+
| Feature | Usage | Browser Support |
|
|
191
|
+
|---------|-------|-----------------|
|
|
192
|
+
| CSS Nesting | Scoped styles | 2024+ |
|
|
193
|
+
| `:has()` | Parent selection | 2024+ |
|
|
194
|
+
| Container Queries | Responsive components | 2023+ |
|
|
195
|
+
| `color-mix()` | Dynamic color variants | 2023+ |
|
|
196
|
+
| CSS Layers | Specificity management | 2023+ |
|
|
197
|
+
| Custom Properties | Design tokens | 2017+ |
|
|
198
|
+
|
|
199
|
+
### CSS Component Pattern
|
|
200
|
+
|
|
201
|
+
```css
|
|
202
|
+
/* button.css - Pure CSS, no framework */
|
|
203
|
+
|
|
204
|
+
.jera-button {
|
|
205
|
+
/* Base styles using tokens */
|
|
206
|
+
display: inline-flex;
|
|
207
|
+
align-items: center;
|
|
208
|
+
justify-content: center;
|
|
209
|
+
gap: var(--space-2);
|
|
210
|
+
padding: var(--space-2) var(--space-4);
|
|
211
|
+
font-size: var(--font-size-sm);
|
|
212
|
+
font-weight: var(--font-weight-medium);
|
|
213
|
+
border-radius: var(--radius-md);
|
|
214
|
+
transition: all 150ms ease;
|
|
215
|
+
cursor: pointer;
|
|
216
|
+
border: none;
|
|
217
|
+
|
|
218
|
+
/* Variants using CSS nesting */
|
|
219
|
+
&[data-variant="primary"] {
|
|
220
|
+
background: var(--color-primary);
|
|
221
|
+
color: var(--color-base07);
|
|
222
|
+
|
|
223
|
+
&:hover {
|
|
224
|
+
background: color-mix(in srgb, var(--color-primary) 85%, black);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
&[data-variant="secondary"] {
|
|
229
|
+
background: var(--color-surface);
|
|
230
|
+
color: var(--color-text);
|
|
231
|
+
border: 1px solid var(--color-base03);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* Size variants */
|
|
235
|
+
&[data-size="sm"] {
|
|
236
|
+
padding: var(--space-1) var(--space-2);
|
|
237
|
+
font-size: var(--font-size-xs);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
&[data-size="lg"] {
|
|
241
|
+
padding: var(--space-3) var(--space-6);
|
|
242
|
+
font-size: var(--font-size-base);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/* State variants */
|
|
246
|
+
&:disabled {
|
|
247
|
+
opacity: 0.5;
|
|
248
|
+
cursor: not-allowed;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
&[data-loading] {
|
|
252
|
+
position: relative;
|
|
253
|
+
color: transparent;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Container Queries for Responsive Components
|
|
259
|
+
|
|
260
|
+
```css
|
|
261
|
+
.jera-sidebar {
|
|
262
|
+
container-type: inline-size;
|
|
263
|
+
container-name: sidebar;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
@container sidebar (max-width: 200px) {
|
|
267
|
+
.jera-sidebar-label {
|
|
268
|
+
display: none;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.jera-sidebar-icon {
|
|
272
|
+
margin: 0 auto;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Layer 4: Svelte 5 Framework Wrapper
|
|
280
|
+
|
|
281
|
+
Svelte components are thin wrappers around the CSS. They handle:
|
|
282
|
+
- Props and reactivity via native runes
|
|
283
|
+
- Event handling
|
|
284
|
+
- Accessibility attributes
|
|
285
|
+
- State management
|
|
286
|
+
|
|
287
|
+
### Svelte 5 Runes (Required)
|
|
288
|
+
|
|
289
|
+
| Rune | Usage |
|
|
290
|
+
|------|-------|
|
|
291
|
+
| `$props()` | Declare component props (single call only) |
|
|
292
|
+
| `$state()` | Reactive local state |
|
|
293
|
+
| `$derived()` | Computed values |
|
|
294
|
+
| `$bindable()` | Two-way binding props |
|
|
295
|
+
| `$effect()` | Side effects (use sparingly) |
|
|
296
|
+
|
|
297
|
+
### Component Template
|
|
298
|
+
|
|
299
|
+
```svelte
|
|
300
|
+
<!-- Button.svelte -->
|
|
301
|
+
<script>
|
|
302
|
+
let {
|
|
303
|
+
variant = 'primary',
|
|
304
|
+
size = 'md',
|
|
305
|
+
disabled = false,
|
|
306
|
+
loading = false,
|
|
307
|
+
href = null,
|
|
308
|
+
class: className = '',
|
|
309
|
+
children,
|
|
310
|
+
onclick,
|
|
311
|
+
...rest
|
|
312
|
+
} = $props();
|
|
313
|
+
|
|
314
|
+
// Derived class string
|
|
315
|
+
const classes = $derived(
|
|
316
|
+
['jera-button', className].filter(Boolean).join(' ')
|
|
317
|
+
);
|
|
318
|
+
</script>
|
|
319
|
+
|
|
320
|
+
{#if href && !disabled}
|
|
321
|
+
<a
|
|
322
|
+
{href}
|
|
323
|
+
class={classes}
|
|
324
|
+
data-variant={variant}
|
|
325
|
+
data-size={size}
|
|
326
|
+
data-loading={loading || undefined}
|
|
327
|
+
{...rest}
|
|
328
|
+
>
|
|
329
|
+
{@render children?.()}
|
|
330
|
+
</a>
|
|
331
|
+
{:else}
|
|
332
|
+
<button
|
|
333
|
+
type="button"
|
|
334
|
+
class={classes}
|
|
335
|
+
data-variant={variant}
|
|
336
|
+
data-size={size}
|
|
337
|
+
data-loading={loading || undefined}
|
|
338
|
+
{disabled}
|
|
339
|
+
{onclick}
|
|
340
|
+
{...rest}
|
|
341
|
+
>
|
|
342
|
+
{@render children?.()}
|
|
343
|
+
</button>
|
|
344
|
+
{/if}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Reactive Singleton Pattern (ThemeState)
|
|
348
|
+
|
|
349
|
+
For global state like theme management, jera uses a **reactive singleton class pattern**:
|
|
350
|
+
|
|
351
|
+
```javascript
|
|
352
|
+
// reactive.svelte.js
|
|
353
|
+
|
|
354
|
+
export class ThemeState {
|
|
355
|
+
// Reactive state using runes
|
|
356
|
+
current = $state('system');
|
|
357
|
+
|
|
358
|
+
// Derived values
|
|
359
|
+
resolved = $derived.by(() => this.#resolveTheme());
|
|
360
|
+
dataTheme = $derived.by(() =>
|
|
361
|
+
this.resolved === 'dark' ? 'miozu-dark' : 'miozu-light'
|
|
362
|
+
);
|
|
363
|
+
isDark = $derived.by(() => this.resolved === 'dark');
|
|
364
|
+
isLight = $derived.by(() => this.resolved === 'light');
|
|
365
|
+
|
|
366
|
+
// Private state
|
|
367
|
+
#initialized = false;
|
|
368
|
+
#mediaQuery = null;
|
|
369
|
+
|
|
370
|
+
constructor(initial = 'system') {
|
|
371
|
+
this.current = initial;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
#resolveTheme() {
|
|
375
|
+
if (this.current === 'system') {
|
|
376
|
+
if (typeof window === 'undefined') return 'dark';
|
|
377
|
+
return this.#mediaQuery?.matches ? 'dark' : 'light';
|
|
378
|
+
}
|
|
379
|
+
return this.current;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
init() { /* ... */ }
|
|
383
|
+
sync() { /* ... */ }
|
|
384
|
+
toggle() { /* ... */ }
|
|
385
|
+
set(theme) { /* ... */ }
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Singleton instance
|
|
389
|
+
let themeInstance = null;
|
|
390
|
+
|
|
391
|
+
export function getTheme(initial = 'system') {
|
|
392
|
+
if (!themeInstance) {
|
|
393
|
+
themeInstance = new ThemeState(initial);
|
|
394
|
+
}
|
|
395
|
+
return themeInstance;
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
**Usage in SvelteKit:**
|
|
400
|
+
|
|
401
|
+
```svelte
|
|
402
|
+
<!-- +layout.svelte (root) -->
|
|
403
|
+
<script>
|
|
404
|
+
import { getTheme } from '@miozu/jera';
|
|
405
|
+
import { onMount } from 'svelte';
|
|
406
|
+
|
|
407
|
+
// Get singleton once
|
|
408
|
+
const themeState = getTheme();
|
|
409
|
+
|
|
410
|
+
onMount(() => {
|
|
411
|
+
themeState.sync(); // Hydrate from DOM
|
|
412
|
+
themeState.init(); // Setup listeners
|
|
413
|
+
});
|
|
414
|
+
</script>
|
|
415
|
+
|
|
416
|
+
<!-- Pass to children as props -->
|
|
417
|
+
<Sidebar {themeState} />
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
```svelte
|
|
421
|
+
<!-- Child component -->
|
|
422
|
+
<script>
|
|
423
|
+
// Receive as prop, DON'T call getTheme()
|
|
424
|
+
let { themeState } = $props();
|
|
425
|
+
|
|
426
|
+
function handleToggle() {
|
|
427
|
+
themeState.toggle();
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Reactive access
|
|
431
|
+
let isDark = $derived(themeState.isDark);
|
|
432
|
+
</script>
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## Layer 5: AI Documentation
|
|
438
|
+
|
|
439
|
+
### llms.txt Standard
|
|
440
|
+
|
|
441
|
+
Following the [llms.txt specification](https://llmstxt.org/), jera provides:
|
|
442
|
+
|
|
443
|
+
| File | Purpose |
|
|
444
|
+
|------|---------|
|
|
445
|
+
| `llms.txt` | Quick reference index |
|
|
446
|
+
| `llms-full.txt` | Complete documentation |
|
|
447
|
+
| `CLAUDE.md` | Detailed AI context |
|
|
448
|
+
|
|
449
|
+
### llms.txt Structure
|
|
450
|
+
|
|
451
|
+
```markdown
|
|
452
|
+
# @miozu/jera
|
|
453
|
+
|
|
454
|
+
> Description of the library
|
|
455
|
+
|
|
456
|
+
## Quick Start
|
|
457
|
+
- Installation
|
|
458
|
+
- Basic usage
|
|
459
|
+
|
|
460
|
+
## Components
|
|
461
|
+
- [Button](/src/components/Button.svelte): Description
|
|
462
|
+
- [Input](/src/components/Input.svelte): Description
|
|
463
|
+
|
|
464
|
+
## Patterns
|
|
465
|
+
- Theme management
|
|
466
|
+
- Class variants
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Directory Structure
|
|
472
|
+
|
|
473
|
+
```
|
|
474
|
+
jera/
|
|
475
|
+
├── tokens/
|
|
476
|
+
│ ├── tokens.json # W3C DTCG source of truth
|
|
477
|
+
│ ├── tokens.dark.json # Dark theme overrides
|
|
478
|
+
│ ├── tokens.light.json # Light theme overrides
|
|
479
|
+
│ └── build.js # Token → CSS generator
|
|
480
|
+
├── src/
|
|
481
|
+
│ ├── tokens/ # Generated CSS
|
|
482
|
+
│ │ ├── index.css # All tokens bundled
|
|
483
|
+
│ │ ├── colors.css # Base16 palette
|
|
484
|
+
│ │ ├── spacing.css # 4px-based scale
|
|
485
|
+
│ │ ├── typography.css # Font system
|
|
486
|
+
│ │ └── effects.css # Shadows, radius, transitions
|
|
487
|
+
│ ├── css/ # Pure CSS components (future)
|
|
488
|
+
│ │ ├── button.css
|
|
489
|
+
│ │ ├── input.css
|
|
490
|
+
│ │ └── modal.css
|
|
491
|
+
│ ├── components/
|
|
492
|
+
│ │ ├── primitives/ # Button, Badge, Avatar, etc.
|
|
493
|
+
│ │ ├── forms/ # Input, Select, Checkbox, etc.
|
|
494
|
+
│ │ ├── feedback/ # Toast, Spinner, Alert, etc.
|
|
495
|
+
│ │ ├── overlays/ # Modal, Popover, Dropdown
|
|
496
|
+
│ │ ├── navigation/ # Tabs, Sidebar, Accordion
|
|
497
|
+
│ │ └── docs/ # CodeBlock, PropsTable
|
|
498
|
+
│ ├── utils/
|
|
499
|
+
│ │ ├── cn.svelte.js # Class utilities (cn, cv)
|
|
500
|
+
│ │ ├── reactive.svelte.js # ThemeState, createReactive
|
|
501
|
+
│ │ └── sidebar.svelte.js # Sidebar state management
|
|
502
|
+
│ ├── actions/
|
|
503
|
+
│ │ └── index.js # Svelte actions
|
|
504
|
+
│ └── index.js # Main exports
|
|
505
|
+
├── llms.txt # AI quick reference
|
|
506
|
+
├── llms-full.txt # AI complete docs
|
|
507
|
+
├── CLAUDE.md # AI detailed context
|
|
508
|
+
├── ARCHITECTURE.md # This file
|
|
509
|
+
└── package.json
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
## Theming
|
|
515
|
+
|
|
516
|
+
### Theme Attribute
|
|
517
|
+
|
|
518
|
+
Themes are applied via `data-theme` attribute on `<html>`:
|
|
519
|
+
|
|
520
|
+
```html
|
|
521
|
+
<html data-theme="miozu-dark">
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
Supported values:
|
|
525
|
+
- `miozu-dark` - Dark theme (default)
|
|
526
|
+
- `miozu-light` - Light theme
|
|
527
|
+
|
|
528
|
+
### Theme-Agnostic Components
|
|
529
|
+
|
|
530
|
+
Components **NEVER** check theme directly. They use semantic tokens:
|
|
531
|
+
|
|
532
|
+
```svelte
|
|
533
|
+
<!-- CORRECT: Works in both themes -->
|
|
534
|
+
<div class="bg-base00 text-base05 border-base03">
|
|
535
|
+
<h1 class="text-base07">Title</h1>
|
|
536
|
+
<button class="bg-base0D text-base07">Action</button>
|
|
537
|
+
</div>
|
|
538
|
+
|
|
539
|
+
<!-- WRONG: Don't use theme-specific logic in components -->
|
|
540
|
+
{#if theme.isDark}
|
|
541
|
+
<div class="dark-styles">...</div>
|
|
542
|
+
{/if}
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
### CSS Theme Switching
|
|
546
|
+
|
|
547
|
+
Theme switching is handled entirely via CSS custom property values:
|
|
548
|
+
|
|
549
|
+
```css
|
|
550
|
+
/* Dark theme (default) */
|
|
551
|
+
:root {
|
|
552
|
+
--color-base00: #0f1419;
|
|
553
|
+
--color-base05: #e2e8f0;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/* Light theme - only values change, not usage */
|
|
557
|
+
[data-theme='miozu-light'] {
|
|
558
|
+
--color-base00: #ffffff;
|
|
559
|
+
--color-base05: #212529;
|
|
560
|
+
}
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
## Integration with Tailwind (Consumer Apps)
|
|
566
|
+
|
|
567
|
+
While jera itself uses pure CSS, consumer apps can use Tailwind alongside jera:
|
|
568
|
+
|
|
569
|
+
### Tailwind 4 Configuration
|
|
570
|
+
|
|
571
|
+
```css
|
|
572
|
+
/* app.css in consumer app */
|
|
573
|
+
@import '@miozu/jera/tokens';
|
|
574
|
+
|
|
575
|
+
@theme {
|
|
576
|
+
/* Extend Tailwind with jera tokens */
|
|
577
|
+
--color-base00: var(--color-base00);
|
|
578
|
+
--color-base01: var(--color-base01);
|
|
579
|
+
/* ... */
|
|
580
|
+
}
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
### Using jera Components with Tailwind
|
|
584
|
+
|
|
585
|
+
```svelte
|
|
586
|
+
<script>
|
|
587
|
+
import { Button } from '@miozu/jera';
|
|
588
|
+
</script>
|
|
589
|
+
|
|
590
|
+
<!-- jera component with Tailwind utility classes -->
|
|
591
|
+
<Button variant="primary" class="mt-4 shadow-lg">
|
|
592
|
+
Click me
|
|
593
|
+
</Button>
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
---
|
|
597
|
+
|
|
598
|
+
## Performance Considerations
|
|
599
|
+
|
|
600
|
+
1. **CSS-first** - Styles load before JS, preventing FOUC
|
|
601
|
+
2. **Tree-shakeable** - Import only what you use
|
|
602
|
+
3. **No runtime CSS-in-JS** - Zero overhead
|
|
603
|
+
4. **Lazy loading** - Components can be dynamically imported
|
|
604
|
+
5. **SSR-safe** - All components work with SvelteKit SSR
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
## Browser Support
|
|
609
|
+
|
|
610
|
+
jera targets modern browsers (2024+):
|
|
611
|
+
|
|
612
|
+
| Browser | Minimum Version |
|
|
613
|
+
|---------|-----------------|
|
|
614
|
+
| Chrome | 120+ |
|
|
615
|
+
| Firefox | 118+ |
|
|
616
|
+
| Safari | 17+ |
|
|
617
|
+
| Edge | 120+ |
|
|
618
|
+
|
|
619
|
+
For older browser support, consider using CSS polyfills or fallbacks.
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
## Migration Guide
|
|
624
|
+
|
|
625
|
+
### From Tailwind-Only Components
|
|
626
|
+
|
|
627
|
+
1. Extract design tokens to `tokens.json`
|
|
628
|
+
2. Generate CSS custom properties
|
|
629
|
+
3. Replace Tailwind classes with semantic tokens
|
|
630
|
+
4. Keep Tailwind for utility classes in consumer apps
|
|
631
|
+
|
|
632
|
+
### From CSS-in-JS
|
|
633
|
+
|
|
634
|
+
1. Extract styles to pure CSS files
|
|
635
|
+
2. Use CSS custom properties for theming
|
|
636
|
+
3. Replace dynamic style props with data attributes
|
|
637
|
+
|
|
638
|
+
---
|
|
639
|
+
|
|
640
|
+
## Rules for AI Assistants
|
|
641
|
+
|
|
642
|
+
1. **Use Svelte 5 runes** - No legacy `$:`, `export let`, stores
|
|
643
|
+
2. **Single $props() call** - Destructure all props in one call
|
|
644
|
+
3. **Use cv() for variants** - Don't hardcode conditional classes
|
|
645
|
+
4. **Semantic colors** - Use `--color-*` tokens, not raw hex values
|
|
646
|
+
5. **Pure JavaScript** - No TypeScript
|
|
647
|
+
6. **Zero dependencies** - Don't add external packages
|
|
648
|
+
7. **Theme-agnostic** - Components work in both themes automatically
|
|
649
|
+
8. **Accessibility first** - Include ARIA attributes, keyboard support
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
## Related Documentation
|
|
654
|
+
|
|
655
|
+
- [CLAUDE.md](./CLAUDE.md) - AI context file with API reference
|
|
656
|
+
- [llms.txt](./llms.txt) - Quick AI reference
|
|
657
|
+
- [README.md](./README.md) - Getting started guide
|
package/CLAUDE.md
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
1
|
# @miozu/jera - AI Context File
|
|
2
2
|
|
|
3
3
|
**Package:** @miozu/jera
|
|
4
|
-
**Purpose:**
|
|
4
|
+
**Purpose:** Zero-dependency, AI-first component library for Svelte 5
|
|
5
5
|
**Author:** Nicholas Glazer <glazer.nicholas@gmail.com>
|
|
6
|
+
**Last Updated:** February 2026
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Architecture Overview
|
|
11
|
+
|
|
12
|
+
jera follows a **5-layer architecture** designed for portability and AI-assisted development:
|
|
13
|
+
|
|
14
|
+
1. **W3C Design Tokens (DTCG)** - `tokens.json` as single source of truth
|
|
15
|
+
2. **CSS Custom Properties** - Generated from tokens, used by all styles
|
|
16
|
+
3. **Pure Modern CSS** - Framework-agnostic component styles
|
|
17
|
+
4. **Svelte 5 Wrappers** - Thin components using native runes
|
|
18
|
+
5. **AI Documentation** - llms.txt standard for AI assistants
|
|
19
|
+
|
|
20
|
+
**Full architecture documentation:** [ARCHITECTURE.md](./ARCHITECTURE.md)
|
|
21
|
+
|
|
22
|
+
### Key Design Principles
|
|
23
|
+
|
|
24
|
+
- **CSS is the library** - Pure CSS is 100% portable across frameworks
|
|
25
|
+
- **Zero dependencies** - No runtime external dependencies
|
|
26
|
+
- **Browser-native** - Modern CSS features over JS polyfills
|
|
27
|
+
- **Theme-agnostic** - Components work in both themes automatically
|
|
28
|
+
- **AI-first** - Documentation optimized for AI assistants
|
|
6
29
|
|
|
7
30
|
---
|
|
8
31
|
|