Skip to content

Commit ce91886

Browse files
Copilothotlong
andcommitted
Add @objectstack/spec package and update @object-ui/types to extend from it
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 565f630 commit ce91886

9 files changed

Lines changed: 914 additions & 13 deletions

File tree

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
# @objectstack/spec
2+
3+
**The Universal UI Component Specification**
4+
5+
*The foundational protocol for the ObjectStack ecosystem*
6+
7+
---
8+
9+
## Overview
10+
11+
`@objectstack/spec` (v0.1.1) defines the **highest law** - the core interfaces and types that all UI components in the ObjectStack ecosystem must follow. This package provides the universal protocol that enables schema-driven UI rendering across different frameworks and implementations.
12+
13+
## Key Concepts
14+
15+
### UIComponent - The Foundation
16+
17+
Every UI component in the ObjectStack ecosystem extends from `UIComponent`:
18+
19+
```typescript
20+
interface UIComponent {
21+
type: string; // Component type discriminator
22+
id?: string; // Unique identifier
23+
props?: Record<string, any>; // Component-specific properties
24+
children?: SchemaNode | SchemaNode[]; // Child content
25+
[key: string]: any; // Extensibility
26+
}
27+
```
28+
29+
### The Inheritance Chain
30+
31+
```
32+
UIComponent (@objectstack/spec) ← The highest law
33+
34+
BaseSchema (@object-ui/types) ← ObjectUI extensions
35+
36+
Specific Schemas (ChartSchema, etc.) ← Component implementations
37+
```
38+
39+
## Installation
40+
41+
```bash
42+
npm install @objectstack/spec
43+
# or
44+
yarn add @objectstack/spec
45+
# or
46+
pnpm add @objectstack/spec
47+
```
48+
49+
## Usage
50+
51+
### Type Definitions
52+
53+
```typescript
54+
import type { UIComponent, SchemaNode, ComponentType } from '@objectstack/spec';
55+
56+
// Define a component
57+
const button: UIComponent = {
58+
type: 'button',
59+
id: 'submit-btn',
60+
props: {
61+
label: 'Submit',
62+
variant: 'primary',
63+
onClick: () => console.log('clicked')
64+
}
65+
};
66+
67+
// Compose components
68+
const form: UIComponent = {
69+
type: 'form',
70+
id: 'user-form',
71+
children: [
72+
{ type: 'input', props: { name: 'email', label: 'Email' } },
73+
{ type: 'input', props: { name: 'password', label: 'Password' } },
74+
button
75+
]
76+
};
77+
```
78+
79+
### Extending UIComponent
80+
81+
```typescript
82+
import type { UIComponent } from '@objectstack/spec';
83+
84+
// Create your own schema
85+
interface CustomButtonSchema extends UIComponent {
86+
type: 'custom-button';
87+
props?: {
88+
label?: string;
89+
variant?: 'primary' | 'secondary';
90+
size?: 'sm' | 'md' | 'lg';
91+
};
92+
}
93+
94+
const myButton: CustomButtonSchema = {
95+
type: 'custom-button',
96+
props: {
97+
label: 'Click Me',
98+
variant: 'primary',
99+
size: 'lg'
100+
}
101+
};
102+
```
103+
104+
## Design Principles
105+
106+
### 1. Type as Discriminator
107+
108+
The `type` field is the **discriminator** that determines which component to render:
109+
110+
```typescript
111+
function resolveComponent(schema: UIComponent) {
112+
switch (schema.type) {
113+
case 'button': return ButtonComponent;
114+
case 'input': return InputComponent;
115+
case 'chart': return ChartComponent;
116+
default: return FallbackComponent;
117+
}
118+
}
119+
```
120+
121+
### 2. Props-Based Configuration
122+
123+
All component-specific properties go in the `props` object:
124+
125+
```typescript
126+
{
127+
type: 'chart',
128+
props: {
129+
chartType: 'bar',
130+
series: [...],
131+
showLegend: true
132+
}
133+
}
134+
```
135+
136+
### 3. Composability via Children
137+
138+
Components can nest indefinitely:
139+
140+
```typescript
141+
{
142+
type: 'card',
143+
children: [
144+
{ type: 'heading', props: { text: 'Title' } },
145+
{ type: 'text', props: { value: 'Content' } },
146+
{ type: 'button', props: { label: 'Action' } }
147+
]
148+
}
149+
```
150+
151+
### 4. Framework Agnostic
152+
153+
The spec is pure TypeScript with **zero dependencies**:
154+
- ✅ Works with React, Vue, Angular, Svelte
155+
- ✅ No runtime overhead
156+
- ✅ Complete type safety
157+
- ✅ Serializable to JSON
158+
159+
## Core Types
160+
161+
### UIComponent
162+
163+
The base interface for all UI components.
164+
165+
### SchemaNode
166+
167+
Union type for component tree nodes:
168+
```typescript
169+
type SchemaNode = UIComponent | string | number | boolean | null | undefined;
170+
```
171+
172+
### ComponentType
173+
174+
Type alias for component type identifiers:
175+
```typescript
176+
type ComponentType = string;
177+
```
178+
179+
### ActionSchema
180+
181+
Interface for event actions:
182+
```typescript
183+
interface ActionSchema {
184+
action: string;
185+
target?: string;
186+
params?: Record<string, any>;
187+
condition?: string;
188+
}
189+
```
190+
191+
### ComponentMetadata
192+
193+
Metadata for designer/editor integration:
194+
```typescript
195+
interface ComponentMetadata {
196+
label?: string;
197+
icon?: string;
198+
category?: string;
199+
description?: string;
200+
tags?: string[];
201+
isContainer?: boolean;
202+
examples?: Record<string, UIComponent>;
203+
}
204+
```
205+
206+
## Compliance Rules
207+
208+
When implementing components for the ObjectStack ecosystem:
209+
210+
1.**MUST** extend from `UIComponent` (directly or indirectly)
211+
2.**MUST** include a `type` field (the discriminator)
212+
3.**MUST** place component-specific props in the `props` object
213+
4.**SHOULD** support `children` for composable components
214+
5.**SHOULD** support `id` for unique identification
215+
216+
## Examples
217+
218+
### Simple Component
219+
220+
```typescript
221+
const text: UIComponent = {
222+
type: 'text',
223+
props: {
224+
value: 'Hello World',
225+
className: 'text-lg font-bold'
226+
}
227+
};
228+
```
229+
230+
### Container Component
231+
232+
```typescript
233+
const grid: UIComponent = {
234+
type: 'grid',
235+
props: {
236+
columns: 3,
237+
gap: 4
238+
},
239+
children: [
240+
{ type: 'card', props: { title: 'Card 1' } },
241+
{ type: 'card', props: { title: 'Card 2' } },
242+
{ type: 'card', props: { title: 'Card 3' } }
243+
]
244+
};
245+
```
246+
247+
### With Actions
248+
249+
```typescript
250+
const button: UIComponent = {
251+
type: 'button',
252+
props: {
253+
label: 'Submit',
254+
events: {
255+
onClick: [
256+
{ action: 'validate', target: 'form-1' },
257+
{ action: 'submit', target: 'form-1' }
258+
]
259+
}
260+
}
261+
};
262+
```
263+
264+
## Version History
265+
266+
### v0.1.1 (Current)
267+
268+
Initial release with core interfaces:
269+
- `UIComponent` - Base component interface
270+
- `SchemaNode` - Union type for tree nodes
271+
- `ActionSchema` - Event action definition
272+
- `ComponentMetadata` - Designer metadata
273+
274+
## Related Packages
275+
276+
- **[@object-ui/types](https://www.npmjs.com/package/@object-ui/types)** - ObjectUI protocol extensions
277+
- **[@object-ui/core](https://www.npmjs.com/package/@object-ui/core)** - Schema validation and expression engine
278+
- **[@object-ui/react](https://www.npmjs.com/package/@object-ui/react)** - React renderer implementation
279+
- **[@object-ui/components](https://www.npmjs.com/package/@object-ui/components)** - Standard UI components
280+
281+
## Philosophy
282+
283+
> **"Protocol First, Implementation Later"**
284+
285+
By defining a universal specification first, we enable:
286+
- 🔄 Multiple UI implementations (Shadcn, Material, Ant Design)
287+
- 🔄 Multiple frameworks (React, Vue, Svelte, Angular)
288+
- 🔄 Multiple backends (REST, GraphQL, ObjectQL)
289+
- 🔄 Static analysis without runtime dependencies
290+
291+
## License
292+
293+
MIT
294+
295+
## Links
296+
297+
- [GitHub](https://github.com/objectstack-ai/objectui)
298+
- [Documentation](https://objectui.org)
299+
- [ObjectStack](https://objectstack.ai)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"name": "@objectstack/spec",
3+
"version": "0.1.1",
4+
"description": "Universal UI Component Specification - The foundational protocol for ObjectStack ecosystem",
5+
"type": "module",
6+
"main": "./dist/index.js",
7+
"module": "./dist/index.js",
8+
"types": "./dist/index.d.ts",
9+
"exports": {
10+
".": {
11+
"types": "./dist/index.d.ts",
12+
"import": "./dist/index.js",
13+
"require": "./dist/index.cjs"
14+
}
15+
},
16+
"files": [
17+
"dist",
18+
"src",
19+
"README.md",
20+
"LICENSE"
21+
],
22+
"scripts": {
23+
"build": "tsc",
24+
"clean": "rm -rf dist",
25+
"type-check": "tsc --noEmit",
26+
"lint": "eslint ."
27+
},
28+
"keywords": [
29+
"objectstack",
30+
"spec",
31+
"protocol",
32+
"ui-component",
33+
"schema",
34+
"typescript",
35+
"json-schema"
36+
],
37+
"author": "ObjectStack Team",
38+
"license": "MIT",
39+
"repository": {
40+
"type": "git",
41+
"url": "https://github.com/objectstack-ai/objectui.git",
42+
"directory": "packages/objectstack-spec"
43+
},
44+
"devDependencies": {
45+
"typescript": "^5.9.3"
46+
}
47+
}

0 commit comments

Comments
 (0)