diff --git a/docs/architecture/objectstack-spec-integration.md b/docs/architecture/objectstack-spec-integration.md new file mode 100644 index 00000000..5775dac5 --- /dev/null +++ b/docs/architecture/objectstack-spec-integration.md @@ -0,0 +1,245 @@ +# Architecture: ObjectStack Spec Integration + +## Overview + +This document explains how ObjectUI integrates with `@objectstack/spec` (v0.1.1) as the foundational protocol for all UI components. + +## The Inheritance Chain + +``` +@objectstack/spec (v0.1.1) ← The "Highest Law" - Universal Protocol + ↓ +UIComponent ← Base interface for all UI components + ↓ +BaseSchema (@object-ui/types) ← ObjectUI-specific extensions + ↓ +Specific Schemas ← Component implementations + ↓ +Component Renderers ← UI implementations +``` + +### 1. UIComponent (@objectstack/spec) + +The foundational interface that defines the core protocol for schema-driven UI: + +```typescript +interface UIComponent { + type: string; // Component type discriminator + id?: string; // Unique identifier + props?: Record; // Component-specific properties + children?: SchemaNode | SchemaNode[]; // Child content + [key: string]: any; // Extensibility +} +``` + +**Why this is the "highest law":** +- Defines the universal contract for all UI components +- Ensures interoperability across the ObjectStack ecosystem +- Provides the type discriminator pattern +- Enables JSON serialization + +### 2. BaseSchema (@object-ui/types) + +Extends `UIComponent` with ObjectUI-specific rendering logic: + +```typescript +interface BaseSchema extends UIComponent { + // Inherited from UIComponent + type: string; + id?: string; + children?: SchemaNode | SchemaNode[]; + + // ObjectUI extensions + className?: string; // Tailwind CSS classes + visible?: boolean; // Static visibility + visibleOn?: string; // Dynamic visibility (expression) + hidden?: boolean; // Static hiding + hiddenOn?: string; // Dynamic hiding (expression) + disabled?: boolean; // Static disabled state + disabledOn?: string; // Dynamic disabled state (expression) + + // Additional ObjectUI properties + name?: string; + label?: string; + description?: string; + placeholder?: string; + style?: Record; + data?: any; + body?: SchemaNode | SchemaNode[]; + testId?: string; + ariaLabel?: string; +} +``` + +### 3. Specific Schemas (e.g., ChartSchema) + +Component-specific interfaces that extend `BaseSchema`: + +```typescript +interface ChartSchema extends BaseSchema { + type: 'chart'; // Type discriminator + chartType: ChartType; // Chart-specific property + title?: string; + description?: string; + categories?: string[]; + series: ChartSeries[]; + height?: string | number; + showLegend?: boolean; + showGrid?: boolean; + animate?: boolean; + config?: Record; +} +``` + +## Data Display Components + +The following components are defined in `@object-ui/types/data-display`: + +| Type | Component | Schema Interface | Key Properties | +|------|-----------|-----------------|----------------| +| `alert` | Alert | `AlertSchema` | title, description, variant, icon, dismissible | +| `statistic` | Metric Card | `StatisticSchema` | label, value, trend, description, icon | +| `badge` | Badge | `BadgeSchema` | label, variant, icon | +| `avatar` | Avatar | `AvatarSchema` | src, alt, fallback, size, shape | +| `list` | List | `ListSchema` | items, ordered, dividers | +| `table` | Basic Table | `TableSchema` | columns, data, caption, hoverable | +| `data-table` | Data Grid | `DataTableSchema` | pagination, searchable, rowActions, selectable | +| `chart` | Chart | `ChartSchema` | chartType, series, categories, showLegend | +| `timeline` | Timeline | `TimelineSchema` | events, orientation, position | +| `tree-view` | Tree View | `TreeViewSchema` | data, multiSelect, showLines | +| `markdown` | Markdown | `MarkdownSchema` | content, sanitize | +| `html` | Raw HTML | `HtmlSchema` | html | + +## Usage Examples + +### 1. Simple Component (Compliant with UIComponent) + +```json +{ + "type": "badge", + "id": "status-badge", + "label": "New", + "variant": "default" +} +``` + +### 2. Component with ObjectUI Extensions + +```json +{ + "type": "alert", + "id": "welcome-alert", + "title": "Welcome!", + "description": "Thank you for using ObjectUI", + "variant": "default", + "icon": "info", + "dismissible": true, + "visibleOn": "${user.isNewUser}", + "className": "mb-4" +} +``` + +### 3. Complex Component with Children + +```json +{ + "type": "flex", + "id": "user-profile", + "props": { + "direction": "col", + "gap": 4 + }, + "children": [ + { + "type": "avatar", + "src": "https://github.com/shadcn.png", + "fallback": "JD", + "size": "lg" + }, + { + "type": "statistic", + "label": "Followers", + "value": "1,234", + "trend": "up" + }, + { + "type": "badge", + "label": "Pro Member", + "variant": "default" + } + ] +} +``` + +### 4. Data Display with Chart + +```json +{ + "type": "chart", + "id": "sales-chart", + "chartType": "bar", + "title": "Monthly Sales", + "categories": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"], + "series": [ + { + "name": "Revenue", + "data": [12000, 15000, 18000, 14000, 22000, 25000], + "color": "#3b82f6" + } + ], + "showLegend": true, + "height": 400 +} +``` + +## Protocol Compliance Rules + +When creating or using components: + +1. ✅ **MUST** extend from `UIComponent` (directly or indirectly via `BaseSchema`) +2. ✅ **MUST** include a `type` field (the discriminator) +3. ✅ **MUST** use the correct type value from the component registry +4. ✅ **SHOULD** place component-specific properties at the top level (not in props) +5. ✅ **SHOULD** use `props` for standard HTML attributes (role, aria-*, data-*) +6. ✅ **SHOULD** support `children` for composable components +7. ✅ **SHOULD** support `id` for unique identification +8. ✅ **MAY** use ObjectUI extensions (className, visibleOn, etc.) + +### Property Placement Guide + +**Component-specific properties** → Top level: +```json +{ + "type": "alert", + "title": "Welcome", // ✅ Component-specific + "variant": "default", // ✅ Component-specific + "dismissible": true // ✅ Component-specific +} +``` + +**Standard HTML/ARIA attributes** → props object: +```json +{ + "type": "alert", + "title": "Welcome", + "props": { + "role": "alert", // ✅ HTML attribute + "aria-live": "polite", // ✅ ARIA attribute + "data-testid": "alert" // ✅ Data attribute + } +} +``` + +## Related Packages + +- **[@objectstack/spec](../../packages/objectstack-spec)** - Universal UI component specification +- **[@object-ui/types](../../packages/types)** - ObjectUI protocol extensions +- **[@object-ui/core](../../packages/core)** - Schema validation and expression engine +- **[@object-ui/react](../../packages/react)** - React renderer +- **[@object-ui/components](../../packages/components)** - Shadcn/Tailwind implementation + +## References + +- [ObjectStack Spec README](../../packages/objectstack-spec/README.md) +- [Object UI Types README](../../packages/types/README.md) +- [Data Display Examples](../../packages/types/examples/data-display-examples.json) diff --git a/package.json b/package.json index fd9c8516..0ac18afa 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "showcase": "node packages/cli/dist/cli.js showcase", "start": "pnpm dev", "build": "pnpm --filter './packages/*' -r build && pnpm --filter './examples/*' -r build", - "pretest": "pnpm --filter @object-ui/types build && pnpm --filter @object-ui/core build && pnpm --filter @object-ui/react build && pnpm --filter @object-ui/components build && pnpm --filter @object-ui/plugin-kanban build && pnpm --filter @object-ui/plugin-charts build", + "pretest": "pnpm --filter @objectstack/spec build && pnpm --filter @object-ui/types build && pnpm --filter @object-ui/core build && pnpm --filter @object-ui/react build && pnpm --filter @object-ui/components build && pnpm --filter @object-ui/plugin-kanban build && pnpm --filter @object-ui/plugin-charts build", "test": "vitest run", "docs:dev": "pnpm --filter object-ui-docs dev", "docs:build": "pnpm --filter object-ui-docs build", diff --git a/packages/types/README.md b/packages/types/README.md index f6fd1aaa..0f5b0ef8 100644 --- a/packages/types/README.md +++ b/packages/types/README.md @@ -5,7 +5,8 @@ Pure TypeScript type definitions for Object UI - **The Protocol Layer**. ## Features - 🎯 **Complete Type Coverage** - Every component has full TypeScript definitions -- 📦 **Zero Dependencies** - Pure types with no runtime dependencies +- 🏛️ **Built on @objectstack/spec** - Extends the universal UI component specification +- 📦 **Minimal Dependencies** - Only depends on @objectstack/spec (pure types) - 🔌 **Framework Agnostic** - Use with React, Vue, or any framework - 🌍 **Backend Agnostic** - Works with REST, GraphQL, ObjectQL, or local data - 🎨 **Tailwind Native** - Designed for Tailwind CSS styling @@ -21,20 +22,26 @@ yarn add @object-ui/types pnpm add @object-ui/types ``` -**Important:** This package has **ZERO runtime dependencies**. It's pure TypeScript types. +**Important:** This package depends on `@objectstack/spec` which provides the foundational protocol. -## Philosophy +## Architecture: The Inheritance Chain -Object UI follows a **"Protocol First"** approach: +Object UI follows a strict **"Protocol First"** approach with a clear inheritance hierarchy: ``` -@object-ui/types (Protocol) - ↓ -@object-ui/core (Engine) - ↓ -@object-ui/react (Framework) - ↓ -@object-ui/components (UI Implementation) +@objectstack/spec (v0.1.1) ← The "Highest Law" - Universal protocol + ↓ +UIComponent ← Base interface for all UI components + ↓ +BaseSchema (@object-ui/types) ← ObjectUI extensions (visibleOn, hiddenOn, etc.) + ↓ +Specific Schemas ← Component implementations (ChartSchema, etc.) + ↓ +@object-ui/core (Engine) ← Schema validation and expression evaluation + ↓ +@object-ui/react (Framework) ← React renderer + ↓ +@object-ui/components (UI) ← Shadcn/Tailwind implementation ``` This separation allows: @@ -42,6 +49,7 @@ This separation allows: - ✅ Multiple framework bindings (React, Vue, Svelte) - ✅ Multiple backend adapters (REST, GraphQL, ObjectQL) - ✅ Static analysis and validation without runtime dependencies +- ✅ Compliance with the ObjectStack ecosystem standards ## Usage diff --git a/packages/types/examples/data-display-examples.json b/packages/types/examples/data-display-examples.json new file mode 100644 index 00000000..3c09efab --- /dev/null +++ b/packages/types/examples/data-display-examples.json @@ -0,0 +1,288 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Data Display Components - Protocol Compliance Examples", + "description": "Examples demonstrating compliance with @objectstack/spec (v0.1.1)", + "examples": { + "alert": { + "type": "alert", + "id": "welcome-alert", + "title": "Welcome!", + "description": "Thank you for using ObjectUI", + "variant": "default", + "icon": "info", + "dismissible": true + }, + "statistic": { + "type": "statistic", + "id": "revenue-metric", + "label": "Total Revenue", + "value": "$45,231.89", + "trend": "up", + "description": "+20.1% from last month", + "icon": "dollar-sign" + }, + "badge": { + "type": "badge", + "id": "status-badge", + "label": "New", + "variant": "default", + "icon": "star" + }, + "avatar": { + "type": "avatar", + "id": "user-avatar", + "src": "https://github.com/shadcn.png", + "alt": "User profile picture", + "fallback": "CN", + "size": "default", + "shape": "circle" + }, + "list": { + "type": "list", + "id": "user-list", + "items": [ + { + "id": "item-1", + "label": "User Profile", + "description": "View and edit your profile", + "icon": "user" + }, + { + "id": "item-2", + "label": "Settings", + "description": "Manage your preferences", + "icon": "settings" + }, + { + "id": "item-3", + "label": "Logout", + "description": "Sign out of your account", + "icon": "log-out" + } + ], + "ordered": false, + "dividers": true + }, + "table": { + "type": "table", + "id": "users-table", + "caption": "User Management", + "columns": [ + { + "header": "Name", + "accessorKey": "name", + "sortable": true + }, + { + "header": "Email", + "accessorKey": "email", + "type": "text" + }, + { + "header": "Role", + "accessorKey": "role", + "type": "text" + } + ], + "data": [ + { "id": 1, "name": "John Doe", "email": "john@example.com", "role": "Admin" }, + { "id": 2, "name": "Jane Smith", "email": "jane@example.com", "role": "User" } + ], + "hoverable": true, + "striped": false + }, + "data-table": { + "type": "data-table", + "id": "enterprise-table", + "caption": "Customer Database", + "columns": [ + { + "header": "ID", + "accessorKey": "id", + "type": "number", + "width": 80 + }, + { + "header": "Company", + "accessorKey": "company", + "sortable": true, + "filterable": true + }, + { + "header": "Status", + "accessorKey": "status", + "type": "text" + }, + { + "header": "Revenue", + "accessorKey": "revenue", + "type": "currency", + "align": "right" + } + ], + "data": [], + "pagination": true, + "pageSize": 10, + "searchable": true, + "selectable": true, + "sortable": true, + "exportable": true, + "rowActions": true + }, + "chart": { + "type": "chart", + "id": "sales-chart", + "chartType": "bar", + "title": "Monthly Sales", + "description": "Revenue breakdown by month", + "categories": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"], + "series": [ + { + "name": "Revenue", + "data": [12000, 15000, 18000, 14000, 22000, 25000], + "color": "#3b82f6" + }, + { + "name": "Expenses", + "data": [8000, 9000, 11000, 10000, 13000, 14000], + "color": "#ef4444" + } + ], + "showLegend": true, + "showGrid": true, + "animate": true, + "height": 400 + }, + "timeline": { + "type": "timeline", + "id": "project-timeline", + "events": [ + { + "id": "event-1", + "title": "Project Started", + "description": "Initial project kickoff meeting", + "date": "2024-01-15", + "icon": "flag", + "color": "blue" + }, + { + "id": "event-2", + "title": "First Milestone", + "description": "Completed Phase 1 deliverables", + "date": "2024-02-20", + "icon": "check", + "color": "green" + }, + { + "id": "event-3", + "title": "Beta Release", + "description": "Released beta version to testers", + "date": "2024-03-10", + "icon": "rocket", + "color": "purple" + } + ], + "orientation": "vertical", + "position": "left" + }, + "tree-view": { + "type": "tree-view", + "id": "file-explorer", + "data": [ + { + "id": "root", + "label": "Project", + "icon": "folder", + "defaultExpanded": true, + "children": [ + { + "id": "src", + "label": "src", + "icon": "folder", + "children": [ + { + "id": "index", + "label": "index.ts", + "icon": "file" + }, + { + "id": "app", + "label": "app.tsx", + "icon": "file" + } + ] + }, + { + "id": "public", + "label": "public", + "icon": "folder", + "children": [ + { + "id": "index-html", + "label": "index.html", + "icon": "file" + } + ] + } + ] + } + ], + "multiSelect": false, + "showLines": true + }, + "markdown": { + "type": "markdown", + "id": "readme", + "content": "# Welcome\n\nThis is a **markdown** component.\n\n- Feature 1\n- Feature 2\n- Feature 3", + "sanitize": true + }, + "html": { + "type": "html", + "id": "custom-html", + "html": "

Custom HTML

This is raw HTML content.

" + } + }, + "compositeExample": { + "type": "flex", + "id": "user-profile-card", + "props": { + "direction": "col", + "gap": 4 + }, + "children": [ + { + "type": "avatar", + "src": "https://github.com/shadcn.png", + "alt": "User Avatar", + "fallback": "JD", + "size": "lg" + }, + { + "type": "statistic", + "label": "Followers", + "value": "1,234", + "trend": "up", + "icon": "users" + }, + { + "type": "badge", + "label": "Pro Member", + "variant": "default" + }, + { + "type": "list", + "items": [ + { + "label": "Posts", + "description": "42 articles" + }, + { + "label": "Achievements", + "description": "15 badges earned" + } + ], + "dividers": true + } + ] + } +} diff --git a/packages/types/tsconfig.json b/packages/types/tsconfig.json index c4768403..baba4bc5 100644 --- a/packages/types/tsconfig.json +++ b/packages/types/tsconfig.json @@ -7,7 +7,10 @@ "declarationMap": true, "composite": true, "noEmit": false, - "lib": ["ES2020", "DOM"] + "lib": ["ES2020", "DOM"], + // Override paths from root tsconfig to use node_modules resolution + // This ensures @objectstack/spec is resolved from workspace dependency + "paths": {} }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts", "examples"]