@duongthiu/onex-core 0.1.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/README.md +428 -0
- package/THEME_API.md +681 -0
- package/dist/api-vuL1Eg5L.d.mts +2961 -0
- package/dist/api-vuL1Eg5L.d.ts +2961 -0
- package/dist/chunk-3SZX6LHT.js +244 -0
- package/dist/chunk-3SZX6LHT.js.map +1 -0
- package/dist/chunk-7EON6Q4L.mjs +8149 -0
- package/dist/chunk-7EON6Q4L.mjs.map +1 -0
- package/dist/chunk-WDY773GJ.js +8308 -0
- package/dist/chunk-WDY773GJ.js.map +1 -0
- package/dist/chunk-XE4EOKS4.mjs +239 -0
- package/dist/chunk-XE4EOKS4.mjs.map +1 -0
- package/dist/client.d.mts +1461 -0
- package/dist/client.d.ts +1461 -0
- package/dist/client.js +542 -0
- package/dist/client.js.map +1 -0
- package/dist/client.mjs +5 -0
- package/dist/client.mjs.map +1 -0
- package/dist/index.d.mts +125 -0
- package/dist/index.d.ts +125 -0
- package/dist/index.js +601 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +61 -0
- package/dist/index.mjs.map +1 -0
- package/dist/server.d.mts +70 -0
- package/dist/server.d.ts +70 -0
- package/dist/server.js +196 -0
- package/dist/server.js.map +1 -0
- package/dist/server.mjs +188 -0
- package/dist/server.mjs.map +1 -0
- package/package.json +113 -0
package/THEME_API.md
ADDED
|
@@ -0,0 +1,681 @@
|
|
|
1
|
+
# OneX Theme API Reference
|
|
2
|
+
|
|
3
|
+
**Version**: 1.0.0
|
|
4
|
+
**Package**: `@onex/core`
|
|
5
|
+
**Status**: Public API
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
This document defines the **public API contract** for OneX theme developers. All types and interfaces marked with `@public` are stable and follow semantic versioning.
|
|
12
|
+
|
|
13
|
+
### Stability Guarantee
|
|
14
|
+
|
|
15
|
+
- ✅ **Public API** (`@public` tag): Stable, semantic versioning applies
|
|
16
|
+
- ⚠️ **Internal API** (no tag): May change without notice, do not use
|
|
17
|
+
|
|
18
|
+
### Breaking Change Policy
|
|
19
|
+
|
|
20
|
+
- **Major version** (2.0.0): Breaking changes to public API
|
|
21
|
+
- **Minor version** (1.1.0): New features, backward compatible
|
|
22
|
+
- **Patch version** (1.0.1): Bug fixes, backward compatible
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Public API
|
|
27
|
+
|
|
28
|
+
### Core Types
|
|
29
|
+
|
|
30
|
+
All types are imported from `@onex/core`:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import type {
|
|
34
|
+
// Theme Contract
|
|
35
|
+
ThemeManifest,
|
|
36
|
+
ThemeModule,
|
|
37
|
+
ThemeConfig,
|
|
38
|
+
|
|
39
|
+
// Section Types
|
|
40
|
+
SectionComponentProps,
|
|
41
|
+
SectionInstance,
|
|
42
|
+
SectionSchema,
|
|
43
|
+
TemplateDefinition,
|
|
44
|
+
|
|
45
|
+
// Component Types
|
|
46
|
+
ComponentInstance,
|
|
47
|
+
|
|
48
|
+
// Block Types
|
|
49
|
+
BlockInstance,
|
|
50
|
+
|
|
51
|
+
// Validation
|
|
52
|
+
ValidationResult,
|
|
53
|
+
ValidationError,
|
|
54
|
+
ValidationWarning,
|
|
55
|
+
} from "@onex/core"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Theme Manifest
|
|
61
|
+
|
|
62
|
+
**Location**: `packages/core/src/types/theme.ts`
|
|
63
|
+
**Tag**: `@public`
|
|
64
|
+
|
|
65
|
+
The manifest is the primary contract between your theme and the OneX platform.
|
|
66
|
+
|
|
67
|
+
### Interface
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
interface ThemeManifest {
|
|
71
|
+
/** Unique theme identifier (lowercase, kebab-case) */
|
|
72
|
+
id: string;
|
|
73
|
+
|
|
74
|
+
/** Human-readable theme name */
|
|
75
|
+
name: string;
|
|
76
|
+
|
|
77
|
+
/** Semantic version (e.g., "1.0.0") */
|
|
78
|
+
version: string;
|
|
79
|
+
|
|
80
|
+
/** Theme description */
|
|
81
|
+
description?: string;
|
|
82
|
+
|
|
83
|
+
/** Theme author information */
|
|
84
|
+
author: {
|
|
85
|
+
name: string;
|
|
86
|
+
email?: string;
|
|
87
|
+
url?: string;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/** OneX engine version compatibility (e.g., "^1.0.0") */
|
|
91
|
+
engine: string;
|
|
92
|
+
|
|
93
|
+
/** Required peer dependencies */
|
|
94
|
+
peerDependencies: {
|
|
95
|
+
react: string;
|
|
96
|
+
"react-dom": string;
|
|
97
|
+
"@onex/core"?: string;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/** Available sections in this theme */
|
|
101
|
+
sections: string[];
|
|
102
|
+
|
|
103
|
+
/** Theme configuration (colors, typography, etc.) */
|
|
104
|
+
config: ThemeConfig;
|
|
105
|
+
|
|
106
|
+
/** Entry points for the theme bundle */
|
|
107
|
+
exports: {
|
|
108
|
+
main: string;
|
|
109
|
+
types?: string;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/** Optional theme preview/screenshot */
|
|
113
|
+
preview?: {
|
|
114
|
+
thumbnail?: string;
|
|
115
|
+
screenshots?: string[];
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/** Optional license information */
|
|
119
|
+
license?: string;
|
|
120
|
+
|
|
121
|
+
/** Optional homepage/repository */
|
|
122
|
+
repository?: string;
|
|
123
|
+
|
|
124
|
+
/** Optional tags for categorization */
|
|
125
|
+
tags?: string[];
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Example
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
export const manifest: ThemeManifest = {
|
|
133
|
+
id: "my-awesome-theme",
|
|
134
|
+
name: "My Awesome Theme",
|
|
135
|
+
version: "1.0.0",
|
|
136
|
+
description: "A beautiful, modern theme for e-commerce",
|
|
137
|
+
author: {
|
|
138
|
+
name: "Your Name",
|
|
139
|
+
email: "you@example.com",
|
|
140
|
+
url: "https://yoursite.com"
|
|
141
|
+
},
|
|
142
|
+
engine: "^1.0.0",
|
|
143
|
+
peerDependencies: {
|
|
144
|
+
react: "^19.0.0",
|
|
145
|
+
"react-dom": "^19.0.0",
|
|
146
|
+
"@onex/core": "^1.0.0"
|
|
147
|
+
},
|
|
148
|
+
sections: ["hero-default", "hero-minimal", "footer-default"],
|
|
149
|
+
config: themeConfig,
|
|
150
|
+
exports: {
|
|
151
|
+
main: "./dist/index.mjs",
|
|
152
|
+
types: "./dist/index.d.ts"
|
|
153
|
+
},
|
|
154
|
+
tags: ["e-commerce", "minimal", "modern"],
|
|
155
|
+
license: "MIT"
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Validation Rules
|
|
160
|
+
|
|
161
|
+
- `id`: Must be lowercase, kebab-case, 3-50 characters
|
|
162
|
+
- `version`: Must follow semver (e.g., "1.0.0")
|
|
163
|
+
- `engine`: Must be valid semver range (e.g., "^1.0.0", ">=1.0.0 <2.0.0")
|
|
164
|
+
- `sections`: Must match exported section component keys
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Theme Module
|
|
169
|
+
|
|
170
|
+
**Tag**: `@public`
|
|
171
|
+
|
|
172
|
+
The structure your theme bundle must export.
|
|
173
|
+
|
|
174
|
+
### Interface
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
interface ThemeModule {
|
|
178
|
+
/** Theme manifest */
|
|
179
|
+
manifest: ThemeManifest;
|
|
180
|
+
|
|
181
|
+
/** Section components registry */
|
|
182
|
+
sections: Record<string, React.ComponentType<SectionComponentProps>>;
|
|
183
|
+
|
|
184
|
+
/** Theme configuration */
|
|
185
|
+
config: ThemeConfig;
|
|
186
|
+
|
|
187
|
+
/** Optional theme initialization function */
|
|
188
|
+
init?: () => void | Promise<void>;
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Example
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
import type { ThemeModule } from "@onex/core"
|
|
196
|
+
import { HeroDefault, HeroMinimal } from "./sections/hero"
|
|
197
|
+
import { FooterDefault } from "./sections/footer"
|
|
198
|
+
|
|
199
|
+
export const theme: ThemeModule = {
|
|
200
|
+
manifest,
|
|
201
|
+
config,
|
|
202
|
+
sections: {
|
|
203
|
+
"hero-default": HeroDefault,
|
|
204
|
+
"hero-minimal": HeroMinimal,
|
|
205
|
+
"footer-default": FooterDefault,
|
|
206
|
+
},
|
|
207
|
+
init: async () => {
|
|
208
|
+
console.log("Theme initialized")
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export default theme
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Section Component Props
|
|
218
|
+
|
|
219
|
+
**Location**: `packages/core/src/types/section.ts`
|
|
220
|
+
**Tag**: `@public`
|
|
221
|
+
|
|
222
|
+
Props passed to every section component.
|
|
223
|
+
|
|
224
|
+
### Interface
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
interface SectionComponentProps {
|
|
228
|
+
/** Section instance data */
|
|
229
|
+
section: SectionInstance;
|
|
230
|
+
|
|
231
|
+
/** Section schema */
|
|
232
|
+
schema: SectionSchema;
|
|
233
|
+
|
|
234
|
+
/** Selected template definition */
|
|
235
|
+
template: TemplateDefinition;
|
|
236
|
+
|
|
237
|
+
/** Whether in edit mode */
|
|
238
|
+
isEditing?: boolean;
|
|
239
|
+
|
|
240
|
+
/** Optional data for sections (e.g., products, blog posts) */
|
|
241
|
+
data?: Record<string, unknown>;
|
|
242
|
+
|
|
243
|
+
/** Callback when settings change */
|
|
244
|
+
onSettingsChange?: (settings: Settings) => void;
|
|
245
|
+
|
|
246
|
+
/** Component management callbacks */
|
|
247
|
+
onComponentAdd?: (componentType: string) => void;
|
|
248
|
+
onComponentUpdate?: (componentId: string, updates: Partial<ComponentInstance>) => void;
|
|
249
|
+
onComponentRemove?: (componentId: string) => void;
|
|
250
|
+
onComponentReorder?: (componentIds: string[]) => void;
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Example Section Component
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import type { SectionComponentProps } from "@onex/core"
|
|
258
|
+
import { ButtonComponent, Heading } from "@onex/core/client"
|
|
259
|
+
|
|
260
|
+
export function HeroMinimal({ section, isEditing }: SectionComponentProps) {
|
|
261
|
+
const { title, subtitle, ctaText, ctaUrl } = section.settings
|
|
262
|
+
|
|
263
|
+
return (
|
|
264
|
+
<section className="hero">
|
|
265
|
+
<Heading level={1}>{title}</Heading>
|
|
266
|
+
<p>{subtitle}</p>
|
|
267
|
+
<ButtonComponent href={ctaUrl}>{ctaText}</ButtonComponent>
|
|
268
|
+
</section>
|
|
269
|
+
)
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Theme Configuration
|
|
276
|
+
|
|
277
|
+
**Location**: `packages/core/src/types/theme.ts`
|
|
278
|
+
**Tag**: `@public`
|
|
279
|
+
|
|
280
|
+
Design tokens for your theme.
|
|
281
|
+
|
|
282
|
+
### Interface
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
interface ThemeConfig {
|
|
286
|
+
id: string;
|
|
287
|
+
name: string;
|
|
288
|
+
version: string;
|
|
289
|
+
|
|
290
|
+
colors: {
|
|
291
|
+
light: ColorPalette;
|
|
292
|
+
dark?: ColorPalette;
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
typography: Typography;
|
|
296
|
+
spacing: Spacing;
|
|
297
|
+
borderRadius: BorderRadius;
|
|
298
|
+
breakpoints: Breakpoints;
|
|
299
|
+
|
|
300
|
+
tokens?: DesignToken[];
|
|
301
|
+
customCss?: string;
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Example
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
export const config: ThemeConfig = {
|
|
309
|
+
id: "my-theme",
|
|
310
|
+
name: "My Theme",
|
|
311
|
+
version: "1.0.0",
|
|
312
|
+
colors: {
|
|
313
|
+
light: {
|
|
314
|
+
primary: "#3b82f6",
|
|
315
|
+
secondary: "#8b5cf6",
|
|
316
|
+
background: "#ffffff",
|
|
317
|
+
foreground: "#000000",
|
|
318
|
+
// ... other colors
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
typography: {
|
|
322
|
+
fontFamily: {
|
|
323
|
+
heading: "Inter, sans-serif",
|
|
324
|
+
body: "Inter, sans-serif",
|
|
325
|
+
mono: "Fira Code, monospace"
|
|
326
|
+
},
|
|
327
|
+
fontSize: {
|
|
328
|
+
xs: "0.75rem",
|
|
329
|
+
sm: "0.875rem",
|
|
330
|
+
base: "1rem",
|
|
331
|
+
lg: "1.125rem",
|
|
332
|
+
xl: "1.25rem",
|
|
333
|
+
"2xl": "1.5rem",
|
|
334
|
+
"3xl": "1.875rem",
|
|
335
|
+
"4xl": "2.25rem",
|
|
336
|
+
"5xl": "3rem"
|
|
337
|
+
},
|
|
338
|
+
// ... other typography settings
|
|
339
|
+
},
|
|
340
|
+
spacing: {
|
|
341
|
+
xs: "0.25rem",
|
|
342
|
+
sm: "0.5rem",
|
|
343
|
+
md: "1rem",
|
|
344
|
+
lg: "1.5rem",
|
|
345
|
+
xl: "2rem",
|
|
346
|
+
"2xl": "3rem",
|
|
347
|
+
"3xl": "4rem",
|
|
348
|
+
"4xl": "6rem"
|
|
349
|
+
},
|
|
350
|
+
borderRadius: {
|
|
351
|
+
none: "0",
|
|
352
|
+
sm: "0.125rem",
|
|
353
|
+
md: "0.375rem",
|
|
354
|
+
lg: "0.5rem",
|
|
355
|
+
xl: "0.75rem",
|
|
356
|
+
"2xl": "1rem",
|
|
357
|
+
full: "9999px"
|
|
358
|
+
},
|
|
359
|
+
breakpoints: {
|
|
360
|
+
sm: "640px",
|
|
361
|
+
md: "768px",
|
|
362
|
+
lg: "1024px",
|
|
363
|
+
xl: "1280px",
|
|
364
|
+
"2xl": "1536px"
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## UI Components
|
|
372
|
+
|
|
373
|
+
**Location**: `packages/core/src/components/`
|
|
374
|
+
**Tag**: `@public`
|
|
375
|
+
|
|
376
|
+
Pre-built UI components available for use in your sections.
|
|
377
|
+
|
|
378
|
+
### Available Components
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
import {
|
|
382
|
+
// Layout
|
|
383
|
+
GridContainer,
|
|
384
|
+
FullWidthSection,
|
|
385
|
+
Container,
|
|
386
|
+
Grid,
|
|
387
|
+
Columns,
|
|
388
|
+
|
|
389
|
+
// Text
|
|
390
|
+
Heading,
|
|
391
|
+
Paragraph,
|
|
392
|
+
Quote,
|
|
393
|
+
Badge,
|
|
394
|
+
|
|
395
|
+
// Interactive
|
|
396
|
+
ButtonComponent,
|
|
397
|
+
Link,
|
|
398
|
+
Divider,
|
|
399
|
+
Spacer,
|
|
400
|
+
|
|
401
|
+
// Media
|
|
402
|
+
Image,
|
|
403
|
+
Icon,
|
|
404
|
+
Video,
|
|
405
|
+
Gallery,
|
|
406
|
+
Map,
|
|
407
|
+
|
|
408
|
+
// Forms
|
|
409
|
+
Input,
|
|
410
|
+
Textarea,
|
|
411
|
+
Checkbox,
|
|
412
|
+
Select,
|
|
413
|
+
|
|
414
|
+
// Advanced
|
|
415
|
+
Card,
|
|
416
|
+
Alert,
|
|
417
|
+
Accordion,
|
|
418
|
+
Tabs,
|
|
419
|
+
Rating,
|
|
420
|
+
Progress,
|
|
421
|
+
Timer,
|
|
422
|
+
Table,
|
|
423
|
+
Code
|
|
424
|
+
} from "@onex/core/client"
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Example Usage
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
import { Heading, ButtonComponent, Card } from "@onex/core/client"
|
|
431
|
+
|
|
432
|
+
export function MySection({ section }: SectionComponentProps) {
|
|
433
|
+
return (
|
|
434
|
+
<Card>
|
|
435
|
+
<Heading level={2}>Section Title</Heading>
|
|
436
|
+
<ButtonComponent href="/learn-more">Learn More</ButtonComponent>
|
|
437
|
+
</Card>
|
|
438
|
+
)
|
|
439
|
+
}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## Utilities
|
|
445
|
+
|
|
446
|
+
**Location**: `packages/core/src/utils/`
|
|
447
|
+
**Tag**: `@public`
|
|
448
|
+
|
|
449
|
+
Utility functions for common tasks.
|
|
450
|
+
|
|
451
|
+
### cn() - Class Name Merger
|
|
452
|
+
|
|
453
|
+
Combines Tailwind classes with proper precedence.
|
|
454
|
+
|
|
455
|
+
```typescript
|
|
456
|
+
import { cn } from "@onex/core/client"
|
|
457
|
+
|
|
458
|
+
const className = cn(
|
|
459
|
+
"text-base",
|
|
460
|
+
"text-lg", // This wins (last one)
|
|
461
|
+
section.settings.customClass
|
|
462
|
+
)
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### generateId() - UUID Generator
|
|
466
|
+
|
|
467
|
+
```typescript
|
|
468
|
+
import { generateId } from "@onex/core/client"
|
|
469
|
+
|
|
470
|
+
const id = generateId() // "abc123-def456-..."
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Validation
|
|
476
|
+
|
|
477
|
+
**Location**: `packages/core/src/types/theme.ts`
|
|
478
|
+
**Tag**: `@public`
|
|
479
|
+
|
|
480
|
+
Types for theme validation results.
|
|
481
|
+
|
|
482
|
+
### Interface
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
interface ValidationResult {
|
|
486
|
+
valid: boolean;
|
|
487
|
+
errors?: ValidationError[];
|
|
488
|
+
warnings?: ValidationWarning[];
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
interface ValidationError {
|
|
492
|
+
code: string;
|
|
493
|
+
message: string;
|
|
494
|
+
path?: string;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
interface ValidationWarning {
|
|
498
|
+
code: string;
|
|
499
|
+
message: string;
|
|
500
|
+
path?: string;
|
|
501
|
+
}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
### Common Error Codes
|
|
505
|
+
|
|
506
|
+
- `MISSING_MANIFEST`: manifest.json not found
|
|
507
|
+
- `INVALID_MANIFEST`: Manifest schema validation failed
|
|
508
|
+
- `BUNDLE_TOO_LARGE`: ZIP exceeds size limit (10MB)
|
|
509
|
+
- `UNSAFE_EVAL`: eval() detected
|
|
510
|
+
- `UNSAFE_FUNCTION`: Function constructor detected
|
|
511
|
+
- `NODE_API`: Node.js API usage detected
|
|
512
|
+
- `INCOMPATIBLE_ENGINE`: Engine version mismatch
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
## Security Constraints
|
|
517
|
+
|
|
518
|
+
**v1.0.0**: Static validation + runtime error boundaries
|
|
519
|
+
|
|
520
|
+
### Allowed
|
|
521
|
+
|
|
522
|
+
- ✅ Import from `@onex/core`, `@onex/core/client`
|
|
523
|
+
- ✅ Import from `react`, `react-dom`
|
|
524
|
+
- ✅ Standard JavaScript/TypeScript
|
|
525
|
+
- ✅ Tailwind CSS classes
|
|
526
|
+
- ✅ Fetch API for CDN resources only
|
|
527
|
+
|
|
528
|
+
### Blocked
|
|
529
|
+
|
|
530
|
+
- ❌ `eval()` or `new Function()`
|
|
531
|
+
- ❌ Node.js APIs (`fs`, `path`, `child_process`, etc.)
|
|
532
|
+
- ❌ Dynamic imports except from CDN
|
|
533
|
+
- ❌ Inline `<script>` tags
|
|
534
|
+
- ❌ Bundle size > 1MB
|
|
535
|
+
|
|
536
|
+
### Runtime Constraints
|
|
537
|
+
|
|
538
|
+
- ✅ Error boundaries catch render crashes
|
|
539
|
+
- ⚠️ No protection against: infinite loops, memory leaks, network abuse
|
|
540
|
+
- ⚠️ v2.0.0 will add iframe sandbox for stronger isolation
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
## Engine Version Compatibility
|
|
545
|
+
|
|
546
|
+
Themes must specify compatible `@onex/core` versions using semver ranges.
|
|
547
|
+
|
|
548
|
+
### Examples
|
|
549
|
+
|
|
550
|
+
```typescript
|
|
551
|
+
// Exact version
|
|
552
|
+
"engine": "1.0.0"
|
|
553
|
+
|
|
554
|
+
// Compatible with 1.x
|
|
555
|
+
"engine": "^1.0.0"
|
|
556
|
+
|
|
557
|
+
// Compatible with 1.2.0 or higher
|
|
558
|
+
"engine": ">=1.2.0"
|
|
559
|
+
|
|
560
|
+
// Compatible with 1.x but not 2.x
|
|
561
|
+
"engine": ">=1.0.0 <2.0.0"
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
### Runtime Enforcement
|
|
565
|
+
|
|
566
|
+
The platform will check compatibility before loading your theme:
|
|
567
|
+
|
|
568
|
+
```typescript
|
|
569
|
+
if (!semver.satisfies(platformVersion, theme.manifest.engine)) {
|
|
570
|
+
throw new Error("Incompatible theme version")
|
|
571
|
+
}
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
## Versioning Strategy
|
|
577
|
+
|
|
578
|
+
Follow semantic versioning for your theme:
|
|
579
|
+
|
|
580
|
+
- **Major** (2.0.0): Breaking changes to section APIs
|
|
581
|
+
- **Minor** (1.1.0): New sections or features
|
|
582
|
+
- **Patch** (1.0.1): Bug fixes
|
|
583
|
+
|
|
584
|
+
### Example Changelog
|
|
585
|
+
|
|
586
|
+
```
|
|
587
|
+
## 1.1.0 (2026-02-01)
|
|
588
|
+
- Added: hero-split section variant
|
|
589
|
+
- Improved: footer responsive layout
|
|
590
|
+
|
|
591
|
+
## 1.0.1 (2026-01-25)
|
|
592
|
+
- Fixed: button hover state
|
|
593
|
+
- Fixed: mobile menu alignment
|
|
594
|
+
|
|
595
|
+
## 1.0.0 (2026-01-20)
|
|
596
|
+
- Initial release
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
---
|
|
600
|
+
|
|
601
|
+
## Best Practices
|
|
602
|
+
|
|
603
|
+
### 1. Use TypeScript
|
|
604
|
+
|
|
605
|
+
```typescript
|
|
606
|
+
import type { SectionComponentProps, ThemeManifest } from "@onex/core"
|
|
607
|
+
|
|
608
|
+
export const manifest: ThemeManifest = { ... }
|
|
609
|
+
export function HeroSection(props: SectionComponentProps) { ... }
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
### 2. Export Named and Default
|
|
613
|
+
|
|
614
|
+
```typescript
|
|
615
|
+
export const theme: ThemeModule = { ... }
|
|
616
|
+
export { manifest, config }
|
|
617
|
+
export default theme
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
### 3. Handle Edit Mode
|
|
621
|
+
|
|
622
|
+
```typescript
|
|
623
|
+
export function MySection({ section, isEditing }: SectionComponentProps) {
|
|
624
|
+
return (
|
|
625
|
+
<div>
|
|
626
|
+
{isEditing && <div className="edit-overlay">Edit Mode</div>}
|
|
627
|
+
{/* Your content */}
|
|
628
|
+
</div>
|
|
629
|
+
)
|
|
630
|
+
}
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### 4. Use Theme Config
|
|
634
|
+
|
|
635
|
+
```typescript
|
|
636
|
+
export function MySection({ section }: SectionComponentProps) {
|
|
637
|
+
const bgColor = section.settings.backgroundColor || config.colors.light.primary
|
|
638
|
+
|
|
639
|
+
return <section style={{ backgroundColor: bgColor }}>...</section>
|
|
640
|
+
}
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
### 5. Bundle Optimization
|
|
644
|
+
|
|
645
|
+
```javascript
|
|
646
|
+
// esbuild.config.js
|
|
647
|
+
module.exports = {
|
|
648
|
+
external: ["@onex/core", "@onex/core/client", "react", "react-dom"],
|
|
649
|
+
minify: true,
|
|
650
|
+
treeShaking: true
|
|
651
|
+
}
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
---
|
|
655
|
+
|
|
656
|
+
## Migration Guide
|
|
657
|
+
|
|
658
|
+
### From Internal Themes to Marketplace
|
|
659
|
+
|
|
660
|
+
If migrating an existing internal theme:
|
|
661
|
+
|
|
662
|
+
1. **Create manifest.json** with theme metadata
|
|
663
|
+
2. **Externalize @onex/core** in build config
|
|
664
|
+
3. **Export ThemeModule** structure
|
|
665
|
+
4. **Test engine compatibility** with platform
|
|
666
|
+
5. **Validate with CLI**: `onex theme validate`
|
|
667
|
+
6. **Upload**: `onex theme publish`
|
|
668
|
+
|
|
669
|
+
---
|
|
670
|
+
|
|
671
|
+
## Support
|
|
672
|
+
|
|
673
|
+
- **Documentation**: https://docs.onex.dev/themes
|
|
674
|
+
- **API Reference**: This document
|
|
675
|
+
- **CLI Help**: `onex theme --help`
|
|
676
|
+
- **Issues**: https://github.com/onex/themes/issues
|
|
677
|
+
|
|
678
|
+
---
|
|
679
|
+
|
|
680
|
+
*Last Updated: 2026-01-23*
|
|
681
|
+
*API Version: 1.0.0*
|