From d07416d7186a2589b0fce39f2e5c2c74c2da7e02 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 04:52:18 +0000 Subject: [PATCH 1/9] Initial plan From 91c498c6604240266f20f9bd5439b34e1e547b91 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 04:59:28 +0000 Subject: [PATCH 2/9] feat(types): Enhance base schema and add CRUD/API types - Add comprehensive properties to BaseSchema (visible, hidden, disabled, name, label, description, etc.) - Create new crud.ts with CRUD operation schemas (CRUDSchema, DetailSchema, ActionSchema) - Create new api.ts with API integration and event handling schemas - Support complete CRUD interfaces with filters, pagination, toolbar - Add event handler configuration for API calls, navigation, dialogs - Add data fetching configuration for dynamic data loading - Export all new types from index.ts Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com> --- packages/types/src/api.ts | 464 +++++++++++++++++++++++++++++++++++ packages/types/src/base.ts | 83 +++++++ packages/types/src/crud.ts | 467 ++++++++++++++++++++++++++++++++++++ packages/types/src/index.ts | 35 ++- 4 files changed, 1048 insertions(+), 1 deletion(-) create mode 100644 packages/types/src/api.ts create mode 100644 packages/types/src/crud.ts diff --git a/packages/types/src/api.ts b/packages/types/src/api.ts new file mode 100644 index 000000000..03556e462 --- /dev/null +++ b/packages/types/src/api.ts @@ -0,0 +1,464 @@ +/** + * @object-ui/types - API and Event Schemas + * + * Type definitions for API integration and event handling. + * These schemas enable dynamic API calls and event-driven interactions. + * + * @module api + * @packageDocumentation + */ + +import type { BaseSchema } from './base'; + +/** + * HTTP Method types + */ +export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'; + +/** + * API request configuration + */ +export interface APIRequest { + /** + * API endpoint URL + * Supports variable substitution: "/api/users/${userId}" + */ + url: string; + /** + * HTTP method + * @default 'GET' + */ + method?: HTTPMethod; + /** + * Request headers + */ + headers?: Record; + /** + * Request body data + * For POST, PUT, PATCH requests + */ + data?: any; + /** + * Query parameters + */ + params?: Record; + /** + * Request timeout in milliseconds + */ + timeout?: number; + /** + * Whether to send credentials (cookies) + * @default false + */ + withCredentials?: boolean; + /** + * Data transformation function + * Transform request data before sending + */ + transformRequest?: string; + /** + * Response transformation function + * Transform response data after receiving + */ + transformResponse?: string; +} + +/** + * API configuration for components + */ +export interface APIConfig { + /** + * API request configuration + */ + request?: APIRequest; + /** + * Success handler + * JavaScript expression or function name + */ + onSuccess?: string; + /** + * Error handler + * JavaScript expression or function name + */ + onError?: string; + /** + * Loading indicator + * Whether to show loading state during request + * @default true + */ + showLoading?: boolean; + /** + * Success message to display + */ + successMessage?: string; + /** + * Error message to display + */ + errorMessage?: string; + /** + * Whether to reload data after success + * @default false + */ + reload?: boolean; + /** + * Whether to redirect after success + */ + redirect?: string; + /** + * Whether to close dialog/modal after success + * @default false + */ + close?: boolean; + /** + * Retry configuration + */ + retry?: { + /** + * Maximum retry attempts + */ + maxAttempts?: number; + /** + * Delay between retries in milliseconds + */ + delay?: number; + /** + * HTTP status codes to retry + */ + retryOn?: number[]; + }; + /** + * Cache configuration + */ + cache?: { + /** + * Cache key + */ + key?: string; + /** + * Cache duration in milliseconds + */ + duration?: number; + /** + * Whether to use stale cache while revalidating + */ + staleWhileRevalidate?: boolean; + }; +} + +/** + * Event handler configuration + */ +export interface EventHandler { + /** + * Event type + */ + event: string; + /** + * Handler type + */ + type: 'action' | 'api' | 'script' | 'navigation' | 'dialog' | 'toast' | 'custom'; + /** + * Action configuration (for type: 'action') + */ + action?: { + /** + * Action name/identifier + */ + name: string; + /** + * Action parameters + */ + params?: Record; + }; + /** + * API configuration (for type: 'api') + */ + api?: APIConfig; + /** + * Script to execute (for type: 'script') + * JavaScript code as string + */ + script?: string; + /** + * Navigation target (for type: 'navigation') + */ + navigate?: { + /** + * Target URL or route + */ + to: string; + /** + * Navigation type + */ + type?: 'push' | 'replace' | 'reload'; + /** + * Query parameters + */ + params?: Record; + /** + * Open in new window/tab + */ + external?: boolean; + }; + /** + * Dialog configuration (for type: 'dialog') + */ + dialog?: { + /** + * Dialog type + */ + type: 'alert' | 'confirm' | 'prompt' | 'modal'; + /** + * Dialog title + */ + title?: string; + /** + * Dialog content + */ + content?: string | BaseSchema; + /** + * Dialog actions + */ + actions?: Array<{ + label: string; + handler?: EventHandler; + }>; + }; + /** + * Toast configuration (for type: 'toast') + */ + toast?: { + /** + * Toast type + */ + type: 'success' | 'error' | 'warning' | 'info'; + /** + * Toast message + */ + message: string; + /** + * Toast duration in milliseconds + */ + duration?: number; + }; + /** + * Condition for executing handler + * JavaScript expression + */ + condition?: string; + /** + * Whether to prevent default event behavior + */ + preventDefault?: boolean; + /** + * Whether to stop event propagation + */ + stopPropagation?: boolean; + /** + * Debounce delay in milliseconds + */ + debounce?: number; + /** + * Throttle delay in milliseconds + */ + throttle?: number; +} + +/** + * Component with event handlers + */ +export interface EventableSchema extends BaseSchema { + /** + * Event handlers configuration + */ + events?: EventHandler[]; + /** + * Click handler + */ + onClick?: EventHandler | string; + /** + * Change handler + */ + onChange?: EventHandler | string; + /** + * Submit handler + */ + onSubmit?: EventHandler | string; + /** + * Focus handler + */ + onFocus?: EventHandler | string; + /** + * Blur handler + */ + onBlur?: EventHandler | string; + /** + * Mouse enter handler + */ + onMouseEnter?: EventHandler | string; + /** + * Mouse leave handler + */ + onMouseLeave?: EventHandler | string; + /** + * Key down handler + */ + onKeyDown?: EventHandler | string; + /** + * Key up handler + */ + onKeyUp?: EventHandler | string; +} + +/** + * Data fetching configuration + */ +export interface DataFetchConfig { + /** + * Data source API + */ + api: string | APIRequest; + /** + * Whether to fetch on mount + * @default true + */ + fetchOnMount?: boolean; + /** + * Polling interval in milliseconds + * If set, data will be refetched at this interval + */ + pollInterval?: number; + /** + * Dependencies for refetching + * Array of variable names to watch + */ + dependencies?: string[]; + /** + * Default data before fetch completes + */ + defaultData?: any; + /** + * Transform function for fetched data + * JavaScript expression or function name + */ + transform?: string; + /** + * Filter function for data + * JavaScript expression or function name + */ + filter?: string; + /** + * Sort configuration + */ + sort?: { + /** + * Field to sort by + */ + field: string; + /** + * Sort order + */ + order: 'asc' | 'desc'; + }; + /** + * Pagination configuration + */ + pagination?: { + /** + * Current page + */ + page?: number; + /** + * Page size + */ + pageSize?: number; + /** + * Whether pagination is enabled + */ + enabled?: boolean; + }; +} + +/** + * Component with data fetching + */ +export interface DataFetchableSchema extends BaseSchema { + /** + * Data fetching configuration + */ + dataSource?: DataFetchConfig; + /** + * Loading state + */ + loading?: boolean; + /** + * Error state + */ + error?: string | null; + /** + * Fetched data + */ + data?: any; +} + +/** + * Expression evaluation context + */ +export interface ExpressionContext { + /** + * Current component data + */ + data?: any; + /** + * Global application state + */ + state?: any; + /** + * Form values (when in form context) + */ + form?: any; + /** + * Current user information + */ + user?: any; + /** + * Environment variables + */ + env?: Record; + /** + * Utility functions + */ + utils?: Record; +} + +/** + * Expression schema for dynamic values + */ +export interface ExpressionSchema { + /** + * Expression type + */ + type: 'expression'; + /** + * Expression string + * Supports ${} syntax for variable interpolation + */ + value: string; + /** + * Default value if expression fails + */ + defaultValue?: any; + /** + * Whether to watch and re-evaluate on context changes + * @default true + */ + reactive?: boolean; +} + +/** + * Union type of all API schemas + */ +export type APISchema = + | EventableSchema + | DataFetchableSchema + | ExpressionSchema; diff --git a/packages/types/src/base.ts b/packages/types/src/base.ts index c0b48cf6b..20be91e67 100644 --- a/packages/types/src/base.ts +++ b/packages/types/src/base.ts @@ -35,6 +35,30 @@ export interface BaseSchema { */ id?: string; + /** + * Human-readable name for the component. + * Used for form field names, labels, and debugging. + */ + name?: string; + + /** + * Display label for the component. + * Often used in forms, cards, and other UI elements. + */ + label?: string; + + /** + * Descriptive text providing additional context. + * Typically rendered as help text below the component. + */ + description?: string; + + /** + * Placeholder text for input components. + * Provides hints about expected input format or content. + */ + placeholder?: string; + /** * Tailwind CSS classes to apply to the component. * This is the primary styling mechanism in Object UI. @@ -42,6 +66,13 @@ export interface BaseSchema { */ className?: string; + /** + * Inline CSS styles as a JavaScript object. + * Use sparingly - prefer className with Tailwind. + * @example { backgroundColor: '#fff', padding: '16px' } + */ + style?: Record; + /** * Arbitrary data attached to the component. * Can be used for custom properties, state, or context. @@ -60,6 +91,58 @@ export interface BaseSchema { */ children?: SchemaNode | SchemaNode[]; + /** + * Controls whether the component is visible. + * When false, component is not rendered (display: none). + * @default true + */ + visible?: boolean; + + /** + * Expression for conditional visibility. + * Evaluated against the current data context. + * @example "${data.role === 'admin'}" + */ + visibleOn?: string; + + /** + * Controls whether the component is hidden (but still rendered). + * When true, component is rendered but not visible (visibility: hidden). + * @default false + */ + hidden?: boolean; + + /** + * Expression for conditional hiding. + * @example "${!data.isActive}" + */ + hiddenOn?: string; + + /** + * Controls whether the component is disabled. + * Applies to interactive components like buttons and inputs. + * @default false + */ + disabled?: boolean; + + /** + * Expression for conditional disabling. + * @example "${data.status === 'locked'}" + */ + disabledOn?: string; + + /** + * Test ID for automated testing. + * Rendered as data-testid attribute. + */ + testId?: string; + + /** + * Accessibility label for screen readers. + * Rendered as aria-label attribute. + */ + ariaLabel?: string; + /** * Additional properties specific to the component type. * This index signature allows type-specific extensions. diff --git a/packages/types/src/crud.ts b/packages/types/src/crud.ts new file mode 100644 index 000000000..8da971f48 --- /dev/null +++ b/packages/types/src/crud.ts @@ -0,0 +1,467 @@ +/** + * @object-ui/types - CRUD Component Schemas + * + * Type definitions for Create, Read, Update, Delete operations. + * These schemas enable building complete data management interfaces. + * + * @module crud + * @packageDocumentation + */ + +import type { BaseSchema, SchemaNode } from './base'; +import type { FormField } from './form'; +import type { TableColumn } from './data-display'; + +/** + * Action button configuration for CRUD operations + */ +export interface ActionSchema extends BaseSchema { + type: 'action'; + /** + * Action label + */ + label: string; + /** + * Action type/level + * @default 'default' + */ + level?: 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'default'; + /** + * Icon to display (lucide-react icon name) + */ + icon?: string; + /** + * Action variant + */ + variant?: 'default' | 'outline' | 'ghost' | 'link'; + /** + * Whether action is disabled + */ + disabled?: boolean; + /** + * Action type + */ + actionType?: 'button' | 'link' | 'dropdown'; + /** + * API endpoint to call + */ + api?: string; + /** + * HTTP method + * @default 'POST' + */ + method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; + /** + * Confirmation message before execution + */ + confirmText?: string; + /** + * Success message after execution + */ + successMessage?: string; + /** + * Whether to reload data after action + * @default true + */ + reload?: boolean; + /** + * Whether to close dialog/modal after action + * @default true + */ + close?: boolean; + /** + * Custom click handler + */ + onClick?: () => void | Promise; + /** + * Redirect URL after success + */ + redirect?: string; +} + +/** + * CRUD operation configuration + */ +export interface CRUDOperation { + /** + * Operation type + */ + type: 'create' | 'read' | 'update' | 'delete' | 'export' | 'import' | 'custom'; + /** + * Operation label + */ + label?: string; + /** + * Operation icon + */ + icon?: string; + /** + * Whether operation is enabled + * @default true + */ + enabled?: boolean; + /** + * API endpoint for this operation + */ + api?: string; + /** + * HTTP method + */ + method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; + /** + * Confirmation message + */ + confirmText?: string; + /** + * Success message + */ + successMessage?: string; + /** + * Visibility condition + */ + visibleOn?: string; + /** + * Disabled condition + */ + disabledOn?: string; +} + +/** + * Filter configuration for CRUD components + */ +export interface CRUDFilter { + /** + * Filter name (field name) + */ + name: string; + /** + * Filter label + */ + label?: string; + /** + * Filter type + */ + type?: 'input' | 'select' | 'date-picker' | 'date-range' | 'number-range'; + /** + * Filter operator + * @default 'equals' + */ + operator?: 'equals' | 'contains' | 'startsWith' | 'endsWith' | 'gt' | 'gte' | 'lt' | 'lte' | 'between' | 'in'; + /** + * Options for select filter + */ + options?: Array<{ label: string; value: string | number }>; + /** + * Placeholder text + */ + placeholder?: string; + /** + * Default value + */ + defaultValue?: any; +} + +/** + * Toolbar configuration for CRUD components + */ +export interface CRUDToolbar { + /** + * Show create button + * @default true + */ + showCreate?: boolean; + /** + * Show refresh button + * @default true + */ + showRefresh?: boolean; + /** + * Show export button + * @default false + */ + showExport?: boolean; + /** + * Show import button + * @default false + */ + showImport?: boolean; + /** + * Show filter toggle + * @default true + */ + showFilter?: boolean; + /** + * Show search box + * @default true + */ + showSearch?: boolean; + /** + * Custom actions + */ + actions?: ActionSchema[]; +} + +/** + * CRUD pagination configuration + */ +export interface CRUDPagination { + /** + * Whether pagination is enabled + * @default true + */ + enabled?: boolean; + /** + * Default page size + * @default 10 + */ + pageSize?: number; + /** + * Page size options + * @default [10, 20, 50, 100] + */ + pageSizeOptions?: number[]; + /** + * Show total count + * @default true + */ + showTotal?: boolean; + /** + * Show page size selector + * @default true + */ + showSizeChanger?: boolean; +} + +/** + * Complete CRUD component + * Provides full Create, Read, Update, Delete functionality + */ +export interface CRUDSchema extends BaseSchema { + type: 'crud'; + /** + * CRUD title + */ + title?: string; + /** + * Resource name (singular) + * @example 'user', 'product', 'order' + */ + resource?: string; + /** + * API endpoint for list/search + */ + api?: string; + /** + * Table columns configuration + */ + columns: TableColumn[]; + /** + * Form fields for create/edit + */ + fields?: FormField[]; + /** + * Enabled operations + */ + operations?: { + create?: boolean | CRUDOperation; + read?: boolean | CRUDOperation; + update?: boolean | CRUDOperation; + delete?: boolean | CRUDOperation; + export?: boolean | CRUDOperation; + import?: boolean | CRUDOperation; + [key: string]: boolean | CRUDOperation | undefined; + }; + /** + * Toolbar configuration + */ + toolbar?: CRUDToolbar; + /** + * Filter configuration + */ + filters?: CRUDFilter[]; + /** + * Pagination configuration + */ + pagination?: CRUDPagination; + /** + * Default sort field + */ + defaultSort?: string; + /** + * Default sort order + * @default 'asc' + */ + defaultSortOrder?: 'asc' | 'desc'; + /** + * Row selection mode + */ + selectable?: boolean | 'single' | 'multiple'; + /** + * Batch actions for selected rows + */ + batchActions?: ActionSchema[]; + /** + * Row actions (displayed in each row) + */ + rowActions?: ActionSchema[]; + /** + * Custom empty state + */ + emptyState?: SchemaNode; + /** + * Whether to show loading state + * @default true + */ + loading?: boolean; + /** + * Custom loading component + */ + loadingComponent?: SchemaNode; + /** + * Table layout mode + * @default 'table' + */ + mode?: 'table' | 'grid' | 'list' | 'kanban'; + /** + * Grid columns (for grid mode) + * @default 3 + */ + gridColumns?: number; + /** + * Card template (for grid/list mode) + */ + cardTemplate?: SchemaNode; + /** + * Kanban columns (for kanban mode) + */ + kanbanColumns?: Array<{ + id: string; + title: string; + color?: string; + }>; + /** + * Kanban group field + */ + kanbanGroupField?: string; +} + +/** + * Detail view component + * Displays detailed information about a single record + */ +export interface DetailSchema extends BaseSchema { + type: 'detail'; + /** + * Detail title + */ + title?: string; + /** + * API endpoint to fetch detail data + */ + api?: string; + /** + * Resource ID to display + */ + resourceId?: string | number; + /** + * Field groups for organized display + */ + groups?: Array<{ + title?: string; + description?: string; + fields: Array<{ + name: string; + label?: string; + type?: 'text' | 'image' | 'link' | 'badge' | 'date' | 'datetime' | 'json' | 'html' | 'custom'; + format?: string; + render?: SchemaNode; + }>; + }>; + /** + * Actions available in detail view + */ + actions?: ActionSchema[]; + /** + * Tabs for additional content + */ + tabs?: Array<{ + key: string; + label: string; + content: SchemaNode | SchemaNode[]; + }>; + /** + * Show back button + * @default true + */ + showBack?: boolean; + /** + * Custom back action + */ + onBack?: () => void; + /** + * Whether to show loading state + * @default true + */ + loading?: boolean; +} + +/** + * CRUD Dialog/Modal component for CRUD operations + * Note: For general dialog usage, use DialogSchema from overlay module + */ +export interface CRUDDialogSchema extends BaseSchema { + type: 'crud-dialog'; + /** + * Dialog title + */ + title?: string; + /** + * Dialog description + */ + description?: string; + /** + * Dialog content + */ + content?: SchemaNode | SchemaNode[]; + /** + * Dialog size + * @default 'default' + */ + size?: 'sm' | 'default' | 'lg' | 'xl' | 'full'; + /** + * Dialog actions/buttons + */ + actions?: ActionSchema[]; + /** + * Whether dialog is open + */ + open?: boolean; + /** + * Close handler + */ + onClose?: () => void; + /** + * Whether clicking outside closes dialog + * @default true + */ + closeOnOutsideClick?: boolean; + /** + * Whether pressing Escape closes dialog + * @default true + */ + closeOnEscape?: boolean; + /** + * Show close button + * @default true + */ + showClose?: boolean; +} + +/** + * Union type of all CRUD schemas + */ +export type CRUDComponentSchema = + | ActionSchema + | CRUDSchema + | DetailSchema + | CRUDDialogSchema; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 34221c441..6306d2318 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -216,6 +216,37 @@ export type { APIError, } from './data'; +// ============================================================================ +// CRUD Components - Create, Read, Update, Delete Operations +// ============================================================================ +export type { + ActionSchema, + CRUDOperation, + CRUDFilter, + CRUDToolbar, + CRUDPagination, + CRUDSchema, + DetailSchema, + CRUDDialogSchema, + CRUDComponentSchema, +} from './crud'; + +// ============================================================================ +// API and Events - API Integration and Event Handling +// ============================================================================ +export type { + HTTPMethod, + APIRequest, + APIConfig, + EventHandler, + EventableSchema, + DataFetchConfig, + DataFetchableSchema, + ExpressionContext, + ExpressionSchema, + APISchema, +} from './api'; + // ============================================================================ // Union Types - Discriminated Unions for All Schemas // ============================================================================ @@ -229,6 +260,7 @@ import type { DisclosureSchema } from './disclosure'; import type { OverlaySchema } from './overlay'; import type { NavigationSchema } from './navigation'; import type { ComplexSchema } from './complex'; +import type { CRUDComponentSchema } from './crud'; /** * Union of all component schemas. @@ -243,7 +275,8 @@ export type AnySchema = | DisclosureSchema | OverlaySchema | NavigationSchema - | ComplexSchema; + | ComplexSchema + | CRUDComponentSchema; /** * Utility type to extract the schema type from a type string. From 53c8e5479df7aa0752cba67d7dfa96c9ad06d362 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 05:03:27 +0000 Subject: [PATCH 3/9] Changes before error encountered Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com> --- docs/integration/api.md | 484 ++++++++++++++++++++++++++++ docs/protocol/crud.md | 499 +++++++++++++++++++++++++++++ examples/README.md | 2 + examples/api-integration/app.json | 366 +++++++++++++++++++++ examples/user-management/README.md | 185 +++++++++++ examples/user-management/app.json | 322 +++++++++++++++++++ 6 files changed, 1858 insertions(+) create mode 100644 docs/integration/api.md create mode 100644 docs/protocol/crud.md create mode 100644 examples/api-integration/app.json create mode 100644 examples/user-management/README.md create mode 100644 examples/user-management/app.json diff --git a/docs/integration/api.md b/docs/integration/api.md new file mode 100644 index 000000000..4d2bd6738 --- /dev/null +++ b/docs/integration/api.md @@ -0,0 +1,484 @@ +# API Integration Guide + +Object UI provides powerful API integration capabilities, allowing components to fetch data, submit forms, and trigger actions through REST APIs. + +## Overview + +API integration in Object UI supports: + +- 🔄 **Automatic Data Fetching** - Components fetch data on mount or on demand +- 🔃 **Real-time Updates** - Polling for live data updates +- 📤 **Form Submission** - Submit forms to APIs with validation +- ⚡ **Event-Driven Actions** - Trigger API calls from user interactions +- 🔁 **Request/Response Transformation** - Transform data before sending or after receiving +- 🔒 **Authentication** - Send credentials and custom headers +- ⏱️ **Retry & Timeout** - Configure retry logic and timeouts +- 💾 **Caching** - Cache responses for better performance + +## Data Fetching + +### Basic Data Fetching + +Use `dataSource` to fetch data automatically: + +```json +{ + "type": "div", + "dataSource": { + "api": "https://api.example.com/users" + }, + "body": { + "type": "list", + "items": "${data}" + } +} +``` + +### Advanced Data Fetching + +```json +{ + "type": "div", + "dataSource": { + "api": { + "url": "https://api.example.com/users", + "method": "GET", + "headers": { + "Authorization": "Bearer ${env.token}" + }, + "params": { + "page": 1, + "limit": 10 + } + }, + "fetchOnMount": true, + "pollInterval": 30000, + "transform": "data => data.users", + "filter": "user => user.active", + "sort": { + "field": "name", + "order": "asc" + }, + "pagination": { + "page": 1, + "pageSize": 10, + "enabled": true + } + } +} +``` + +### Configuration Options + +| Property | Type | Description | +|----------|------|-------------| +| `api` | `string \| APIRequest` | API endpoint or full request config | +| `fetchOnMount` | `boolean` | Fetch data when component mounts (default: true) | +| `pollInterval` | `number` | Polling interval in milliseconds | +| `dependencies` | `string[]` | Variables to watch for refetching | +| `defaultData` | `any` | Default data before fetch completes | +| `transform` | `string` | Transform function for response data | +| `filter` | `string` | Filter function for data | +| `sort` | `object` | Sort configuration | +| `pagination` | `object` | Pagination configuration | + +## API Requests + +### Request Configuration + +```typescript +interface APIRequest { + url: string; // API endpoint (supports ${} variables) + method?: HTTPMethod; // GET, POST, PUT, DELETE, PATCH + headers?: object; // Request headers + data?: any; // Request body (for POST/PUT/PATCH) + params?: object; // Query parameters + timeout?: number; // Request timeout in ms + withCredentials?: boolean; // Send cookies + transformRequest?: string; // Transform before sending + transformResponse?: string; // Transform after receiving +} +``` + +### Example Requests + +**Simple GET:** +```json +{ + "api": { + "url": "/api/users", + "method": "GET" + } +} +``` + +**POST with Data:** +```json +{ + "api": { + "url": "/api/users", + "method": "POST", + "data": { + "name": "${form.name}", + "email": "${form.email}" + } + } +} +``` + +**With Headers:** +```json +{ + "api": { + "url": "/api/users", + "method": "GET", + "headers": { + "Authorization": "Bearer ${env.token}", + "X-Custom-Header": "value" + } + } +} +``` + +**With Query Parameters:** +```json +{ + "api": { + "url": "/api/users", + "method": "GET", + "params": { + "page": "${state.page}", + "limit": 10, + "search": "${state.search}" + } + } +} +``` + +## Event Handlers + +### API Event Handler + +Trigger API calls from user interactions: + +```json +{ + "type": "button", + "label": "Save", + "onClick": { + "type": "api", + "api": { + "request": { + "url": "/api/save", + "method": "POST", + "data": "${form}" + }, + "successMessage": "Saved successfully!", + "errorMessage": "Save failed", + "showLoading": true, + "reload": true, + "redirect": "/success" + } + } +} +``` + +### API Configuration + +```typescript +interface APIConfig { + request?: APIRequest; + onSuccess?: string; // Success handler expression + onError?: string; // Error handler expression + showLoading?: boolean; // Show loading indicator + successMessage?: string; // Success toast message + errorMessage?: string; // Error toast message + reload?: boolean; // Reload data after success + redirect?: string; // Redirect after success + close?: boolean; // Close dialog after success + retry?: { + maxAttempts?: number; + delay?: number; + retryOn?: number[]; // HTTP status codes to retry + }; + cache?: { + key?: string; + duration?: number; + staleWhileRevalidate?: boolean; + }; +} +``` + +## Form Submission + +### Basic Form Submission + +```json +{ + "type": "form", + "fields": [...], + "onSubmit": { + "type": "api", + "api": { + "request": { + "url": "/api/contact", + "method": "POST" + }, + "successMessage": "Message sent!", + "showLoading": true + } + } +} +``` + +### Form with Validation + +```json +{ + "type": "form", + "fields": [ + { + "name": "email", + "type": "input", + "inputType": "email", + "required": true, + "validation": { + "pattern": { + "value": "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$", + "message": "Invalid email format" + } + } + } + ], + "onSubmit": { + "type": "api", + "api": { + "request": { + "url": "/api/register", + "method": "POST" + }, + "successMessage": "Registration successful!", + "redirect": "/login" + } + } +} +``` + +## Variable Substitution + +Use `${}` syntax to reference variables in URLs, data, and messages: + +### Available Variables + +- `${data}` - Component data +- `${form}` - Form values +- `${state}` - Global application state +- `${user}` - Current user information +- `${env}` - Environment variables +- `${utils}` - Utility functions + +### Examples + +```json +{ + "url": "/api/users/${user.id}", + "data": { + "name": "${form.name}", + "email": "${form.email}", + "createdBy": "${user.id}" + }, + "successMessage": "Welcome, ${form.name}!" +} +``` + +## Response Transformation + +Transform API responses using JavaScript expressions: + +```json +{ + "dataSource": { + "api": "/api/github/repos/objectstack-ai/objectui", + "transform": "data => ({ stars: data.stargazers_count, forks: data.forks_count })" + } +} +``` + +Multiple transformations: + +```json +{ + "dataSource": { + "api": "/api/users", + "transform": "data => data.users", + "filter": "user => user.active && user.role === 'admin'", + "sort": { + "field": "createdAt", + "order": "desc" + } + } +} +``` + +## Error Handling + +### Basic Error Handling + +```json +{ + "onClick": { + "type": "api", + "api": { + "request": { + "url": "/api/action", + "method": "POST" + }, + "successMessage": "Success!", + "errorMessage": "Operation failed. Please try again." + } + } +} +``` + +### Custom Error Handler + +```json +{ + "onClick": { + "type": "api", + "api": { + "request": { + "url": "/api/action", + "method": "POST" + }, + "onError": "error => { console.error(error); showNotification(error.message); }" + } + } +} +``` + +### Retry Configuration + +```json +{ + "api": { + "request": { + "url": "/api/action", + "method": "POST" + }, + "retry": { + "maxAttempts": 3, + "delay": 1000, + "retryOn": [500, 502, 503, 504] + } + } +} +``` + +## Caching + +Cache API responses to improve performance: + +```json +{ + "dataSource": { + "api": "/api/users", + "cache": { + "key": "users-list", + "duration": 300000, + "staleWhileRevalidate": true + } + } +} +``` + +### Cache Options + +- `key` - Unique cache key +- `duration` - Cache duration in milliseconds +- `staleWhileRevalidate` - Return stale data while fetching fresh data + +## Polling + +Automatically refetch data at regular intervals: + +```json +{ + "dataSource": { + "api": "/api/dashboard/stats", + "pollInterval": 30000, + "fetchOnMount": true + } +} +``` + +## Authentication + +### Bearer Token + +```json +{ + "api": { + "url": "/api/protected", + "method": "GET", + "headers": { + "Authorization": "Bearer ${env.API_TOKEN}" + } + } +} +``` + +### Cookies + +```json +{ + "api": { + "url": "/api/protected", + "method": "GET", + "withCredentials": true + } +} +``` + +### Custom Headers + +```json +{ + "api": { + "url": "/api/protected", + "method": "GET", + "headers": { + "X-API-Key": "${env.API_KEY}", + "X-User-Id": "${user.id}" + } + } +} +``` + +## Best Practices + +1. **Use Environment Variables** - Store API keys and tokens in environment variables +2. **Handle Errors Gracefully** - Always provide error messages +3. **Show Loading States** - Use `showLoading: true` for better UX +4. **Cache When Appropriate** - Cache static or slow-changing data +5. **Use Transformations** - Transform data at the source, not in templates +6. **Validate Input** - Use form validation before submitting +7. **Provide Feedback** - Show success/error messages to users +8. **Use Retry Logic** - Retry transient failures automatically +9. **Optimize Polling** - Use reasonable polling intervals +10. **Secure APIs** - Always use HTTPS and authentication + +## Examples + +See these examples for complete implementations: + +- [User Management](../../examples/user-management) - Full CRUD with API integration +- [API Integration Demo](../../examples/api-integration) - Various API patterns +- [Dashboard](../../examples/dashboard) - Real-time data fetching + +## Related Documentation + +- [CRUD Protocol](./crud.md) +- [Event Handling](./events.md) +- [Expression System](./expressions.md) +- [Data Sources](../integration/data-sources.md) diff --git a/docs/protocol/crud.md b/docs/protocol/crud.md new file mode 100644 index 000000000..81f98012b --- /dev/null +++ b/docs/protocol/crud.md @@ -0,0 +1,499 @@ +# CRUD Protocol Specification + +The CRUD (Create, Read, Update, Delete) protocol provides a complete data management interface through JSON schema. + +## Overview + +The CRUD protocol simplifies building data management interfaces by providing a declarative way to define tables, forms, filters, and operations. Instead of writing hundreds of lines of React code, you can define a complete CRUD interface in a single JSON schema. + +## Basic Structure + +```json +{ + "type": "crud", + "resource": "user", + "api": "/api/users", + "columns": [...], + "fields": [...], + "operations": {...}, + "toolbar": {...}, + "filters": [...], + "pagination": {...} +} +``` + +## Schema Properties + +### Core Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `type` | `string` | ✅ | Must be `"crud"` | +| `resource` | `string` | ❌ | Resource name (e.g., "user", "product") | +| `api` | `string` | ✅ | Base API endpoint | +| `title` | `string` | ❌ | Table title | +| `description` | `string` | ❌ | Table description | + +### Columns Configuration + +Defines how data is displayed in the table: + +```typescript +interface TableColumn { + name: string; // Field name + label?: string; // Display label + type?: string; // Column type (text, badge, date, image, etc.) + width?: number; // Column width in pixels + sortable?: boolean; // Enable sorting + searchable?: boolean; // Include in search + format?: string; // Format string (for dates, numbers) + render?: SchemaNode; // Custom render schema +} +``` + +**Example:** + +```json +{ + "columns": [ + { + "name": "id", + "label": "ID", + "type": "text", + "width": 80, + "sortable": true + }, + { + "name": "avatar", + "label": "Avatar", + "type": "image", + "width": 60 + }, + { + "name": "name", + "label": "Name", + "type": "text", + "sortable": true, + "searchable": true + }, + { + "name": "status", + "label": "Status", + "type": "badge", + "sortable": true + }, + { + "name": "createdAt", + "label": "Created", + "type": "date", + "format": "YYYY-MM-DD HH:mm", + "sortable": true + } + ] +} +``` + +### Fields Configuration + +Defines form fields for create/edit operations: + +```json +{ + "fields": [ + { + "name": "name", + "label": "Full Name", + "type": "input", + "required": true, + "placeholder": "Enter name" + }, + { + "name": "email", + "label": "Email", + "type": "input", + "inputType": "email", + "required": true + }, + { + "name": "role", + "label": "Role", + "type": "select", + "options": [ + { "label": "Admin", "value": "admin" }, + { "label": "User", "value": "user" } + ] + } + ] +} +``` + +### Operations Configuration + +Controls which CRUD operations are enabled: + +```typescript +interface CRUDOperation { + enabled?: boolean; + label?: string; + icon?: string; + api?: string; + method?: HTTPMethod; + confirmText?: string; + successMessage?: string; +} +``` + +**Example:** + +```json +{ + "operations": { + "create": { + "enabled": true, + "label": "Add User", + "icon": "plus", + "api": "/api/users", + "method": "POST", + "successMessage": "User created successfully!" + }, + "update": { + "enabled": true, + "label": "Edit", + "api": "/api/users/${id}", + "method": "PUT", + "successMessage": "User updated!" + }, + "delete": { + "enabled": true, + "label": "Delete", + "api": "/api/users/${id}", + "method": "DELETE", + "confirmText": "Delete this user?", + "successMessage": "User deleted!" + }, + "export": { + "enabled": true, + "label": "Export", + "api": "/api/users/export" + } + } +} +``` + +### Toolbar Configuration + +Customizes the toolbar appearance and actions: + +```json +{ + "toolbar": { + "showCreate": true, + "showRefresh": true, + "showExport": true, + "showImport": false, + "showFilter": true, + "showSearch": true, + "actions": [ + { + "type": "action", + "label": "Import CSV", + "icon": "upload", + "variant": "outline" + } + ] + } +} +``` + +### Filters Configuration + +Defines available filters: + +```json +{ + "filters": [ + { + "name": "role", + "label": "Role", + "type": "select", + "operator": "equals", + "options": [ + { "label": "All", "value": "" }, + { "label": "Admin", "value": "admin" }, + { "label": "User", "value": "user" } + ] + }, + { + "name": "status", + "label": "Status", + "type": "select", + "operator": "equals", + "options": [...] + }, + { + "name": "createdAt", + "label": "Created Date", + "type": "date-range", + "operator": "between" + } + ] +} +``` + +### Pagination Configuration + +Controls pagination behavior: + +```json +{ + "pagination": { + "enabled": true, + "pageSize": 20, + "pageSizeOptions": [10, 20, 50, 100], + "showTotal": true, + "showSizeChanger": true + } +} +``` + +### Batch Actions + +Actions that can be performed on multiple selected rows: + +```json +{ + "selectable": "multiple", + "batchActions": [ + { + "type": "action", + "label": "Activate Selected", + "icon": "check", + "level": "success", + "api": "/api/users/batch/activate", + "method": "POST", + "confirmText": "Activate ${count} users?", + "successMessage": "${count} users activated!" + }, + { + "type": "action", + "label": "Delete Selected", + "icon": "trash", + "level": "danger", + "api": "/api/users/batch/delete", + "method": "DELETE", + "confirmText": "Delete ${count} users?" + } + ] +} +``` + +### Row Actions + +Actions available for individual rows: + +```json +{ + "rowActions": [ + { + "type": "action", + "label": "View", + "icon": "eye", + "redirect": "/users/${id}" + }, + { + "type": "action", + "label": "Edit", + "icon": "edit" + }, + { + "type": "action", + "label": "Delete", + "icon": "trash", + "level": "danger", + "confirmText": "Delete this user?" + } + ] +} +``` + +## Display Modes + +The CRUD component supports multiple display modes: + +### Table Mode (Default) + +```json +{ + "mode": "table" +} +``` + +Traditional table view with columns and rows. + +### Grid Mode + +```json +{ + "mode": "grid", + "gridColumns": 3, + "cardTemplate": { + "type": "card", + "body": [ + { "type": "text", "content": "${item.name}" }, + { "type": "text", "content": "${item.email}" } + ] + } +} +``` + +Card-based grid layout. + +### List Mode + +```json +{ + "mode": "list", + "cardTemplate": { + "type": "div", + "className": "p-4 border-b", + "body": [...] + } +} +``` + +Vertical list layout. + +### Kanban Mode + +```json +{ + "mode": "kanban", + "kanbanGroupField": "status", + "kanbanColumns": [ + { "id": "todo", "title": "To Do", "color": "gray" }, + { "id": "in_progress", "title": "In Progress", "color": "blue" }, + { "id": "done", "title": "Done", "color": "green" } + ] +} +``` + +Kanban board layout with draggable cards. + +## API Contract + +The CRUD component expects specific API endpoints and response formats: + +### List Endpoint + +**Request:** `GET /api/users?page=1&pageSize=20&search=john&sort=name&order=asc` + +**Response:** +```json +{ + "data": [ + { + "id": 1, + "name": "John Doe", + "email": "john@example.com", + ... + } + ], + "total": 100, + "page": 1, + "pageSize": 20 +} +``` + +### Create Endpoint + +**Request:** `POST /api/users` +```json +{ + "name": "John Doe", + "email": "john@example.com", + ... +} +``` + +**Response:** +```json +{ + "id": 1, + "name": "John Doe", + "email": "john@example.com", + ... +} +``` + +### Read Endpoint + +**Request:** `GET /api/users/1` + +**Response:** +```json +{ + "id": 1, + "name": "John Doe", + "email": "john@example.com", + ... +} +``` + +### Update Endpoint + +**Request:** `PUT /api/users/1` +```json +{ + "name": "John Smith", + ... +} +``` + +**Response:** +```json +{ + "id": 1, + "name": "John Smith", + ... +} +``` + +### Delete Endpoint + +**Request:** `DELETE /api/users/1` + +**Response:** +```json +{ + "success": true +} +``` + +## Variable Substitution + +URLs and messages support variable substitution using `${}` syntax: + +- `${id}` - Current record ID +- `${count}` - Selected items count (for batch actions) +- `${item.field}` - Field value from current record + +**Examples:** + +```json +{ + "api": "/api/users/${id}", + "confirmText": "Delete ${item.name}?", + "successMessage": "${count} users activated!" +} +``` + +## Complete Example + +See [examples/user-management](../../examples/user-management) for a complete working example. + +## Related + +- [Action Schema](./action.md) +- [Detail Schema](./detail.md) +- [API Integration](../integration/api.md) +- [Event Handling](./events.md) diff --git a/examples/README.md b/examples/README.md index f773c96d0..8b87d5307 100644 --- a/examples/README.md +++ b/examples/README.md @@ -14,6 +14,8 @@ These examples demonstrate the new JSON project specification - pure JSON schema | [**dashboard**](./dashboard) | Analytics dashboard | ⭐⭐ Intermediate | Metrics, activity feeds, grids | | [**data-display**](./data-display) | Data visualization patterns | ⭐⭐ Intermediate | Lists, profiles, badges, progress | | [**landing-page**](./landing-page) | Marketing landing page | ⭐⭐⭐ Advanced | Hero sections, CTAs, full layouts | +| [**user-management**](./user-management) | Complete CRUD interface | ⭐⭐⭐ Advanced | Full CRUD, filters, pagination, batch actions | +| [**api-integration**](./api-integration) | API integration patterns | ⭐⭐⭐ Advanced | Data fetching, events, dynamic data | | [**cli-demo**](./cli-demo) | CLI demonstration | ⭐ Beginner | Bilingual form, gradient backgrounds | ### 🔧 Integration Examples diff --git a/examples/api-integration/app.json b/examples/api-integration/app.json new file mode 100644 index 000000000..1bb647fc1 --- /dev/null +++ b/examples/api-integration/app.json @@ -0,0 +1,366 @@ +{ + "$schema": "https://objectui.org/schema/v1", + "type": "page", + "title": "API Integration Demo", + "description": "Demonstrating dynamic data fetching, API calls, and event handling", + "body": [ + { + "type": "card", + "title": "🔄 Real-time Data Fetching", + "description": "Components that automatically fetch and display data from APIs", + "className": "mb-6", + "body": { + "type": "div", + "className": "p-6 space-y-4", + "dataSource": { + "api": "https://api.github.com/repos/objectstack-ai/objectui", + "fetchOnMount": true, + "pollInterval": 30000, + "transform": "data => ({ stars: data.stargazers_count, forks: data.forks_count, issues: data.open_issues_count })" + }, + "body": [ + { + "type": "div", + "className": "grid grid-cols-3 gap-4", + "body": [ + { + "type": "card", + "className": "text-center", + "body": [ + { + "type": "text", + "content": "${data.stars}", + "className": "text-3xl font-bold text-yellow-600" + }, + { + "type": "text", + "content": "⭐ Stars", + "className": "text-sm text-muted-foreground" + } + ] + }, + { + "type": "card", + "className": "text-center", + "body": [ + { + "type": "text", + "content": "${data.forks}", + "className": "text-3xl font-bold text-blue-600" + }, + { + "type": "text", + "content": "🔱 Forks", + "className": "text-sm text-muted-foreground" + } + ] + }, + { + "type": "card", + "className": "text-center", + "body": [ + { + "type": "text", + "content": "${data.issues}", + "className": "text-3xl font-bold text-red-600" + }, + { + "type": "text", + "content": "🐛 Issues", + "className": "text-sm text-muted-foreground" + } + ] + } + ] + }, + { + "type": "text", + "content": "Data updates every 30 seconds automatically", + "className": "text-xs text-muted-foreground text-center" + } + ] + } + }, + { + "type": "card", + "title": "🎯 Interactive Actions", + "description": "Buttons with API calls and event handlers", + "className": "mb-6", + "body": { + "type": "div", + "className": "p-6 space-y-4", + "body": [ + { + "type": "div", + "className": "flex gap-3", + "body": [ + { + "type": "button", + "label": "API Call", + "icon": "zap", + "onClick": { + "type": "api", + "api": { + "request": { + "url": "/api/test", + "method": "POST", + "data": { + "message": "Hello from Object UI!" + } + }, + "successMessage": "API call successful!", + "errorMessage": "API call failed", + "showLoading": true + } + } + }, + { + "type": "button", + "label": "Show Dialog", + "icon": "message-square", + "variant": "outline", + "onClick": { + "type": "dialog", + "dialog": { + "type": "alert", + "title": "Hello!", + "content": "This dialog was triggered by a button click event" + } + } + }, + { + "type": "button", + "label": "Show Toast", + "icon": "bell", + "variant": "outline", + "onClick": { + "type": "toast", + "toast": { + "type": "success", + "message": "Toast notification triggered!", + "duration": 3000 + } + } + }, + { + "type": "button", + "label": "Navigate", + "icon": "external-link", + "variant": "outline", + "onClick": { + "type": "navigation", + "navigate": { + "to": "/users", + "type": "push" + } + } + } + ] + } + ] + } + }, + { + "type": "card", + "title": "📝 Form with API Submission", + "description": "Forms that submit data to APIs with validation", + "className": "mb-6", + "body": { + "type": "div", + "className": "p-6", + "body": { + "type": "form", + "fields": [ + { + "name": "name", + "label": "Your Name", + "type": "input", + "placeholder": "Enter your name", + "required": true + }, + { + "name": "email", + "label": "Email Address", + "type": "input", + "inputType": "email", + "placeholder": "your@email.com", + "required": true + }, + { + "name": "message", + "label": "Message", + "type": "textarea", + "placeholder": "What would you like to tell us?", + "rows": 4, + "required": true + } + ], + "submitLabel": "Send Message", + "onSubmit": { + "type": "api", + "api": { + "request": { + "url": "/api/contact", + "method": "POST" + }, + "successMessage": "Message sent successfully!", + "errorMessage": "Failed to send message", + "showLoading": true, + "reload": false, + "close": false + } + } + } + } + }, + { + "type": "card", + "title": "🔀 Conditional Rendering", + "description": "Components that show/hide based on data conditions", + "className": "mb-6", + "body": { + "type": "div", + "className": "p-6 space-y-4", + "body": [ + { + "type": "select", + "name": "userType", + "label": "User Type", + "options": [ + { "label": "Select a type", "value": "" }, + { "label": "Admin", "value": "admin" }, + { "label": "User", "value": "user" }, + { "label": "Guest", "value": "guest" } + ] + }, + { + "type": "alert", + "variant": "default", + "title": "Admin Access", + "description": "You have full administrative privileges", + "visibleOn": "${form.userType === 'admin'}" + }, + { + "type": "alert", + "variant": "default", + "title": "Standard User", + "description": "You have standard user access", + "visibleOn": "${form.userType === 'user'}" + }, + { + "type": "alert", + "variant": "destructive", + "title": "Guest Access", + "description": "You have limited guest access", + "visibleOn": "${form.userType === 'guest'}" + }, + { + "type": "button", + "label": "Delete Account", + "variant": "destructive", + "visibleOn": "${form.userType === 'admin'}", + "onClick": { + "type": "dialog", + "dialog": { + "type": "confirm", + "title": "Confirm Deletion", + "content": "Are you sure you want to delete this account?", + "actions": [ + { + "label": "Cancel" + }, + { + "label": "Delete", + "handler": { + "type": "api", + "api": { + "request": { + "url": "/api/account", + "method": "DELETE" + }, + "successMessage": "Account deleted", + "close": true + } + } + } + ] + } + } + } + ] + } + }, + { + "type": "card", + "title": "⚡ Event Chaining", + "description": "Multiple actions triggered in sequence", + "className": "mb-6", + "body": { + "type": "div", + "className": "p-6", + "body": { + "type": "button", + "label": "Run Multi-Step Process", + "icon": "play", + "events": [ + { + "event": "click", + "type": "toast", + "toast": { + "type": "info", + "message": "Step 1: Starting process..." + } + }, + { + "event": "click", + "type": "api", + "api": { + "request": { + "url": "/api/step1", + "method": "POST" + }, + "showLoading": true + }, + "debounce": 1000 + }, + { + "event": "click", + "type": "toast", + "toast": { + "type": "success", + "message": "Process completed successfully!" + }, + "debounce": 2000 + } + ] + } + } + }, + { + "type": "card", + "title": "💡 Expression System", + "description": "Dynamic values using expressions", + "body": { + "type": "div", + "className": "p-6 space-y-3", + "body": [ + { + "type": "text", + "content": "Current time: ${new Date().toLocaleString()}", + "className": "text-sm" + }, + { + "type": "text", + "content": "User Agent: ${navigator.userAgent}", + "className": "text-xs text-muted-foreground" + }, + { + "type": "text", + "content": "Window Size: ${window.innerWidth}x${window.innerHeight}", + "className": "text-xs text-muted-foreground" + } + ] + } + } + ] +} diff --git a/examples/user-management/README.md b/examples/user-management/README.md new file mode 100644 index 000000000..3f1413b60 --- /dev/null +++ b/examples/user-management/README.md @@ -0,0 +1,185 @@ +# User Management Example + +A complete CRUD (Create, Read, Update, Delete) interface for managing users, built entirely with JSON schema. + +## Features + +This example demonstrates: + +- ✅ **Complete CRUD Operations** - Create, read, update, and delete users +- ✅ **Advanced Filtering** - Filter by role, status, and date range +- ✅ **Search & Sort** - Search across multiple fields with sortable columns +- ✅ **Pagination** - Configurable page sizes with total count display +- ✅ **Batch Operations** - Activate, deactivate, or delete multiple users at once +- ✅ **Row Actions** - View details, edit, reset password, or delete individual users +- ✅ **Form Validation** - Required fields, email validation, and file upload constraints +- ✅ **Confirmation Dialogs** - Safety prompts before destructive actions +- ✅ **Success Messages** - User feedback after successful operations +- ✅ **Custom Toolbar** - Additional actions like import CSV and bulk invite +- ✅ **Empty State** - Friendly message when no users exist + +## Schema Structure + +The example uses the new `CRUDSchema` type which provides a complete data management interface: + +```json +{ + "type": "crud", + "resource": "user", + "api": "/api/users", + "columns": [...], // Table columns configuration + "fields": [...], // Form fields for create/edit + "operations": {...}, // CRUD operation settings + "toolbar": {...}, // Toolbar configuration + "filters": [...], // Filter options + "pagination": {...}, // Pagination settings + "batchActions": [...], // Bulk operations + "rowActions": [...] // Per-row actions +} +``` + +## Running the Example + +### Using Object UI CLI + +```bash +# Install the CLI globally +npm install -g @object-ui/cli + +# Serve the example +cd examples/user-management +objectui serve app.json +``` + +Visit http://localhost:3000 to see the user management interface. + +### Using as a Template + +You can use this as a starting point for your own CRUD interfaces: + +1. Copy `app.json` to your project +2. Modify the `api` endpoints to match your backend +3. Customize the `columns` and `fields` for your data model +4. Adjust `operations`, `filters`, and `actions` as needed + +## Customization + +### Changing the Data Model + +Edit the `columns` array to define what fields are displayed: + +```json +{ + "columns": [ + { + "name": "fieldName", + "label": "Display Label", + "type": "text|badge|date|image", + "sortable": true, + "searchable": true + } + ] +} +``` + +### Modifying Operations + +Enable/disable operations or customize their behavior: + +```json +{ + "operations": { + "create": { + "enabled": true, + "label": "Add User", + "api": "/api/users", + "method": "POST", + "successMessage": "User created!" + }, + "delete": { + "enabled": true, + "confirmText": "Delete this user?", + "successMessage": "User deleted!" + } + } +} +``` + +### Adding Custom Actions + +Add custom toolbar or row actions: + +```json +{ + "toolbar": { + "actions": [ + { + "type": "action", + "label": "Custom Action", + "icon": "star", + "api": "/api/custom-endpoint", + "method": "POST" + } + ] + } +} +``` + +## API Integration + +This example expects a REST API with the following endpoints: + +- `GET /api/users` - List users (with pagination, filtering, sorting) +- `POST /api/users` - Create a new user +- `GET /api/users/:id` - Get user details +- `PUT /api/users/:id` - Update a user +- `DELETE /api/users/:id` - Delete a user +- `GET /api/users/export` - Export users +- `POST /api/users/batch/activate` - Batch activate users +- `POST /api/users/batch/deactivate` - Batch deactivate users +- `DELETE /api/users/batch/delete` - Batch delete users +- `POST /api/users/:id/reset-password` - Reset user password + +### Request/Response Format + +**List Users (GET /api/users)** + +Query Parameters: +- `page` - Page number (default: 1) +- `pageSize` - Results per page (default: 20) +- `search` - Search query +- `sort` - Sort field +- `order` - Sort order (asc/desc) +- `role` - Filter by role +- `status` - Filter by status + +Response: +```json +{ + "data": [ + { + "id": 1, + "name": "John Doe", + "email": "john@example.com", + "role": "admin", + "status": "active", + "avatar": "https://...", + "createdAt": "2024-01-15T10:00:00Z" + } + ], + "total": 100, + "page": 1, + "pageSize": 20 +} +``` + +## Learn More + +- [Object UI Documentation](https://www.objectui.org) +- [CRUD Schema Reference](../../docs/protocol/crud.md) +- [API Integration Guide](../../docs/integration/api.md) +- [More Examples](../) + +## License + +MIT diff --git a/examples/user-management/app.json b/examples/user-management/app.json new file mode 100644 index 000000000..a5a23a91b --- /dev/null +++ b/examples/user-management/app.json @@ -0,0 +1,322 @@ +{ + "$schema": "https://objectui.org/schema/v1", + "type": "page", + "title": "User Management", + "description": "Complete CRUD interface for managing users", + "body": [ + { + "type": "crud", + "resource": "user", + "api": "/api/users", + "title": "Users", + "description": "Manage system users and their permissions", + "columns": [ + { + "name": "id", + "label": "ID", + "type": "text", + "width": 80, + "sortable": true + }, + { + "name": "avatar", + "label": "Avatar", + "type": "image", + "width": 60 + }, + { + "name": "name", + "label": "Name", + "type": "text", + "sortable": true, + "searchable": true + }, + { + "name": "email", + "label": "Email", + "type": "text", + "sortable": true, + "searchable": true + }, + { + "name": "role", + "label": "Role", + "type": "badge", + "sortable": true + }, + { + "name": "status", + "label": "Status", + "type": "badge", + "sortable": true + }, + { + "name": "createdAt", + "label": "Created At", + "type": "date", + "format": "YYYY-MM-DD HH:mm", + "sortable": true + } + ], + "fields": [ + { + "name": "name", + "label": "Full Name", + "type": "input", + "required": true, + "placeholder": "Enter full name" + }, + { + "name": "email", + "label": "Email Address", + "type": "input", + "inputType": "email", + "required": true, + "placeholder": "user@example.com" + }, + { + "name": "password", + "label": "Password", + "type": "input", + "inputType": "password", + "required": true, + "placeholder": "Enter password", + "description": "Minimum 8 characters with letters and numbers" + }, + { + "name": "role", + "label": "Role", + "type": "select", + "required": true, + "options": [ + { "label": "Admin", "value": "admin" }, + { "label": "Editor", "value": "editor" }, + { "label": "Viewer", "value": "viewer" } + ] + }, + { + "name": "status", + "label": "Status", + "type": "radio-group", + "required": true, + "defaultValue": "active", + "options": [ + { "label": "Active", "value": "active" }, + { "label": "Inactive", "value": "inactive" }, + { "label": "Suspended", "value": "suspended" } + ] + }, + { + "name": "bio", + "label": "Biography", + "type": "textarea", + "placeholder": "Brief description about the user", + "rows": 4 + }, + { + "name": "avatar", + "label": "Avatar", + "type": "file-upload", + "accept": "image/*", + "maxSize": 2097152, + "description": "Upload a profile picture (max 2MB)" + } + ], + "operations": { + "create": { + "enabled": true, + "label": "Add User", + "icon": "plus", + "api": "/api/users", + "method": "POST", + "successMessage": "User created successfully!" + }, + "read": { + "enabled": true, + "api": "/api/users/${id}", + "method": "GET" + }, + "update": { + "enabled": true, + "label": "Edit", + "icon": "edit", + "api": "/api/users/${id}", + "method": "PUT", + "successMessage": "User updated successfully!" + }, + "delete": { + "enabled": true, + "label": "Delete", + "icon": "trash", + "api": "/api/users/${id}", + "method": "DELETE", + "confirmText": "Are you sure you want to delete this user?", + "successMessage": "User deleted successfully!" + }, + "export": { + "enabled": true, + "label": "Export Users", + "icon": "download", + "api": "/api/users/export", + "method": "GET" + } + }, + "toolbar": { + "showCreate": true, + "showRefresh": true, + "showExport": true, + "showImport": false, + "showFilter": true, + "showSearch": true, + "actions": [ + { + "type": "action", + "label": "Import CSV", + "icon": "upload", + "variant": "outline" + }, + { + "type": "action", + "label": "Bulk Invite", + "icon": "mail", + "variant": "outline" + } + ] + }, + "filters": [ + { + "name": "role", + "label": "Role", + "type": "select", + "operator": "equals", + "options": [ + { "label": "All Roles", "value": "" }, + { "label": "Admin", "value": "admin" }, + { "label": "Editor", "value": "editor" }, + { "label": "Viewer", "value": "viewer" } + ] + }, + { + "name": "status", + "label": "Status", + "type": "select", + "operator": "equals", + "options": [ + { "label": "All Status", "value": "" }, + { "label": "Active", "value": "active" }, + { "label": "Inactive", "value": "inactive" }, + { "label": "Suspended", "value": "suspended" } + ] + }, + { + "name": "createdAt", + "label": "Created Date", + "type": "date-range", + "operator": "between" + } + ], + "pagination": { + "enabled": true, + "pageSize": 20, + "pageSizeOptions": [10, 20, 50, 100], + "showTotal": true, + "showSizeChanger": true + }, + "defaultSort": "createdAt", + "defaultSortOrder": "desc", + "selectable": "multiple", + "batchActions": [ + { + "type": "action", + "label": "Activate Selected", + "icon": "check", + "level": "success", + "api": "/api/users/batch/activate", + "method": "POST", + "confirmText": "Activate ${count} selected users?", + "successMessage": "${count} users activated successfully!" + }, + { + "type": "action", + "label": "Deactivate Selected", + "icon": "x", + "level": "warning", + "api": "/api/users/batch/deactivate", + "method": "POST", + "confirmText": "Deactivate ${count} selected users?", + "successMessage": "${count} users deactivated successfully!" + }, + { + "type": "action", + "label": "Delete Selected", + "icon": "trash", + "level": "danger", + "api": "/api/users/batch/delete", + "method": "DELETE", + "confirmText": "Are you sure you want to delete ${count} selected users? This action cannot be undone.", + "successMessage": "${count} users deleted successfully!" + } + ], + "rowActions": [ + { + "type": "action", + "label": "View Details", + "icon": "eye", + "variant": "ghost", + "redirect": "/users/${id}" + }, + { + "type": "action", + "label": "Edit", + "icon": "edit", + "variant": "ghost" + }, + { + "type": "action", + "label": "Reset Password", + "icon": "key", + "variant": "ghost", + "api": "/api/users/${id}/reset-password", + "method": "POST", + "confirmText": "Send password reset email to this user?", + "successMessage": "Password reset email sent!" + }, + { + "type": "action", + "label": "Delete", + "icon": "trash", + "variant": "ghost", + "level": "danger", + "confirmText": "Are you sure you want to delete this user?" + } + ], + "mode": "table", + "emptyState": { + "type": "div", + "className": "text-center py-12", + "body": [ + { + "type": "text", + "content": "👤", + "className": "text-6xl mb-4" + }, + { + "type": "text", + "content": "No users found", + "className": "text-xl font-semibold mb-2" + }, + { + "type": "text", + "content": "Get started by creating your first user", + "className": "text-muted-foreground mb-4" + }, + { + "type": "button", + "label": "Add First User", + "icon": "plus" + } + ] + } + } + ] +} From 4f68e0e452ec633015769e73bd08d8c50260bdff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 05:14:42 +0000 Subject: [PATCH 4/9] feat(core): Add schema validation and builder utilities - Add schema-validator.ts with validateSchema, assertValidSchema, isValidSchema functions - Add schema-builder.ts with fluent builders for Form, CRUD, Button, Input, Card, Grid, Flex - Export validation and builder utilities from core package - Add @object-ui/types dependency to core package - Update tsconfig with composite projects and path mappings - Create comprehensive BEST_PRACTICES.md guide - Create user-management and api-integration example apps - Create CRUD protocol documentation - Create API integration guide - Update examples README with new examples Co-authored-by: xuyushun441-sys <255036401+xuyushun441-sys@users.noreply.github.com> --- docs/BEST_PRACTICES.md | 636 +++++++++++++ packages/core/package.json | 1 + packages/core/src/builder/schema-builder.ts | 576 +++++++++++ packages/core/src/index.ts | 2 + .../core/src/validation/schema-validator.ts | 336 +++++++ packages/core/tsconfig.json | 9 +- packages/types/src/api.d.ts | 450 +++++++++ packages/types/src/api.js | 10 + packages/types/src/base.d.ts | 359 +++++++ packages/types/src/base.js | 10 + packages/types/src/complex.d.ts | 432 +++++++++ packages/types/src/complex.js | 9 + packages/types/src/crud.d.ts | 456 +++++++++ packages/types/src/crud.js | 10 + packages/types/src/data-display.d.ts | 537 +++++++++++ packages/types/src/data-display.js | 9 + packages/types/src/data.d.ts | 294 ++++++ packages/types/src/data.js | 10 + packages/types/src/disclosure.d.ts | 106 +++ packages/types/src/disclosure.js | 9 + packages/types/src/feedback.d.ts | 158 ++++ packages/types/src/feedback.js | 9 + packages/types/src/form.d.ts | 895 ++++++++++++++++++ packages/types/src/form.js | 9 + packages/types/src/index.d.ts | 102 ++ packages/types/src/index.js | 48 + packages/types/src/layout.d.ts | 380 ++++++++ packages/types/src/layout.js | 10 + packages/types/src/navigation.d.ts | 223 +++++ packages/types/src/navigation.js | 9 + packages/types/src/overlay.d.ts | 395 ++++++++ packages/types/src/overlay.js | 9 + tsconfig.json | 4 + 33 files changed, 6510 insertions(+), 2 deletions(-) create mode 100644 docs/BEST_PRACTICES.md create mode 100644 packages/core/src/builder/schema-builder.ts create mode 100644 packages/core/src/validation/schema-validator.ts create mode 100644 packages/types/src/api.d.ts create mode 100644 packages/types/src/api.js create mode 100644 packages/types/src/base.d.ts create mode 100644 packages/types/src/base.js create mode 100644 packages/types/src/complex.d.ts create mode 100644 packages/types/src/complex.js create mode 100644 packages/types/src/crud.d.ts create mode 100644 packages/types/src/crud.js create mode 100644 packages/types/src/data-display.d.ts create mode 100644 packages/types/src/data-display.js create mode 100644 packages/types/src/data.d.ts create mode 100644 packages/types/src/data.js create mode 100644 packages/types/src/disclosure.d.ts create mode 100644 packages/types/src/disclosure.js create mode 100644 packages/types/src/feedback.d.ts create mode 100644 packages/types/src/feedback.js create mode 100644 packages/types/src/form.d.ts create mode 100644 packages/types/src/form.js create mode 100644 packages/types/src/index.d.ts create mode 100644 packages/types/src/index.js create mode 100644 packages/types/src/layout.d.ts create mode 100644 packages/types/src/layout.js create mode 100644 packages/types/src/navigation.d.ts create mode 100644 packages/types/src/navigation.js create mode 100644 packages/types/src/overlay.d.ts create mode 100644 packages/types/src/overlay.js diff --git a/docs/BEST_PRACTICES.md b/docs/BEST_PRACTICES.md new file mode 100644 index 000000000..ceac0d36b --- /dev/null +++ b/docs/BEST_PRACTICES.md @@ -0,0 +1,636 @@ +# Object UI Best Practices + +This guide covers best practices for building applications with Object UI's JSON-driven approach. + +## Table of Contents + +- [Schema Design](#schema-design) +- [Performance](#performance) +- [Type Safety](#type-safety) +- [Maintainability](#maintainability) +- [API Integration](#api-integration) +- [Security](#security) +- [Testing](#testing) +- [Accessibility](#accessibility) + +## Schema Design + +### 1. Keep Schemas Modular and Reusable + +**❌ Bad:** +```json +{ + "type": "div", + "body": [ + { + "type": "card", + "title": "User 1", + "body": [ + { "type": "text", "content": "Name: John" }, + { "type": "text", "content": "Email: john@example.com" } + ] + }, + { + "type": "card", + "title": "User 2", + "body": [ + { "type": "text", "content": "Name: Jane" }, + { "type": "text", "content": "Email": "jane@example.com" } + ] + } + ] +} +``` + +**✅ Good:** +```json +{ + "type": "div", + "dataSource": { + "api": "/api/users" + }, + "body": { + "type": "grid", + "columns": 2, + "children": "${data.map(user => ({ type: 'card', title: user.name, body: [{ type: 'text', content: user.email }] }))}" + } +} +``` + +### 2. Use Semantic Types + +Choose the most appropriate component type for your content. + +**❌ Bad:** +```json +{ + "type": "div", + "className": "border p-4", + "body": "This is a warning" +} +``` + +**✅ Good:** +```json +{ + "type": "alert", + "variant": "warning", + "description": "This is a warning" +} +``` + +### 3. Leverage Conditional Rendering + +Use `visibleOn`, `hiddenOn`, and `disabledOn` for dynamic UIs. + +**✅ Good:** +```json +{ + "type": "button", + "label": "Delete", + "variant": "destructive", + "visibleOn": "${user.role === 'admin'}", + "disabledOn": "${item.status === 'locked'}" +} +``` + +### 4. Structure Complex Forms Logically + +Group related fields and use clear labels. + +**✅ Good:** +```json +{ + "type": "form", + "fields": [ + { + "name": "personalInfo", + "type": "group", + "label": "Personal Information", + "fields": [ + { "name": "firstName", "type": "input", "label": "First Name" }, + { "name": "lastName", "type": "input", "label": "Last Name" } + ] + }, + { + "name": "contactInfo", + "type": "group", + "label": "Contact Information", + "fields": [ + { "name": "email", "type": "input", "inputType": "email", "label": "Email" }, + { "name": "phone", "type": "input", "inputType": "tel", "label": "Phone" } + ] + } + ] +} +``` + +## Performance + +### 1. Use Data Fetching Wisely + +**❌ Bad** - Fetch data in every component: +```json +{ + "type": "div", + "body": [ + { + "type": "card", + "dataSource": { "api": "/api/stats" }, + "body": "..." + }, + { + "type": "card", + "dataSource": { "api": "/api/stats" }, + "body": "..." + } + ] +} +``` + +**✅ Good** - Fetch once at parent level: +```json +{ + "type": "div", + "dataSource": { "api": "/api/stats" }, + "body": [ + { + "type": "card", + "body": "${data.users}" + }, + { + "type": "card", + "body": "${data.orders}" + } + ] +} +``` + +### 2. Enable Caching for Static Data + +```json +{ + "dataSource": { + "api": "/api/countries", + "cache": { + "key": "countries-list", + "duration": 3600000, + "staleWhileRevalidate": true + } + } +} +``` + +### 3. Use Pagination for Large Lists + +```json +{ + "type": "crud", + "api": "/api/users", + "pagination": { + "enabled": true, + "pageSize": 20, + "pageSizeOptions": [10, 20, 50] + } +} +``` + +### 4. Optimize Polling Intervals + +```json +{ + "dataSource": { + "api": "/api/dashboard/stats", + "pollInterval": 30000, + "fetchOnMount": true + } +} +``` + +## Type Safety + +### 1. Use TypeScript for Schema Generation + +**✅ Good:** +```typescript +import { FormBuilder, input } from '@object-ui/core/builder'; + +const loginForm = new FormBuilder() + .field({ + name: 'email', + type: 'input', + inputType: 'email', + required: true + }) + .field({ + name: 'password', + type: 'input', + inputType: 'password', + required: true + }) + .submitLabel('Login') + .build(); +``` + +### 2. Validate Schemas Before Runtime + +```typescript +import { validateSchema, assertValidSchema } from '@object-ui/core/validation'; + +// Validate and get detailed errors +const result = validateSchema(schema); +if (!result.valid) { + console.error('Schema errors:', result.errors); +} + +// Or assert and throw on error +assertValidSchema(schema); +``` + +### 3. Use Schema Version for Compatibility + +```json +{ + "$schema": "https://objectui.org/schema/v1", + "type": "page", + "body": [...] +} +``` + +## Maintainability + +### 1. Use Descriptive IDs and Test IDs + +**✅ Good:** +```json +{ + "type": "button", + "id": "submit-login-button", + "testId": "login-submit", + "label": "Login" +} +``` + +### 2. Document Complex Expressions + +```json +{ + "type": "text", + "content": "${data.users.filter(u => u.active && u.verified).length}", + "description": "Count of active and verified users" +} +``` + +### 3. Use Constants for Repeated Values + +Instead of: +```json +{ + "api": "/api/v1/users", + "operations": { + "create": { "api": "/api/v1/users" }, + "update": { "api": "/api/v1/users/${id}" } + } +} +``` + +Use environment variables or configuration: +```json +{ + "api": "${env.API_BASE}/users", + "operations": { + "create": { "api": "${env.API_BASE}/users" }, + "update": { "api": "${env.API_BASE}/users/${id}" } + } +} +``` + +### 4. Organize Large Schemas + +Split large schemas into multiple files: + +```typescript +// schemas/users/list.json +// schemas/users/form.json +// schemas/users/detail.json + +import userList from './schemas/users/list.json'; +import userForm from './schemas/users/form.json'; +``` + +## API Integration + +### 1. Always Handle Errors + +**✅ Good:** +```json +{ + "onClick": { + "type": "api", + "api": { + "request": { + "url": "/api/action", + "method": "POST" + }, + "successMessage": "Action completed successfully!", + "errorMessage": "Failed to complete action. Please try again.", + "showLoading": true + } + } +} +``` + +### 2. Use Confirmation for Destructive Actions + +**✅ Good:** +```json +{ + "type": "action", + "label": "Delete", + "level": "danger", + "confirmText": "Are you sure you want to delete this item? This action cannot be undone.", + "api": "/api/items/${id}", + "method": "DELETE" +} +``` + +### 3. Provide User Feedback + +```json +{ + "api": { + "request": { + "url": "/api/save", + "method": "POST" + }, + "showLoading": true, + "successMessage": "Changes saved successfully!", + "errorMessage": "Failed to save changes", + "reload": true + } +} +``` + +### 4. Transform Data at the Source + +**✅ Good:** +```json +{ + "dataSource": { + "api": "/api/products", + "transform": "data => data.products.map(p => ({ ...p, displayName: `${p.name} (${p.sku})` }))" + } +} +``` + +## Security + +### 1. Never Expose Sensitive Data in Schemas + +**❌ Bad:** +```json +{ + "api": { + "url": "/api/users", + "headers": { + "Authorization": "******" + } + } +} +``` + +**✅ Good:** +```json +{ + "api": { + "url": "/api/users", + "headers": { + "Authorization": "${env.API_TOKEN}" + } + } +} +``` + +### 2. Validate User Input + +```json +{ + "name": "email", + "type": "input", + "inputType": "email", + "required": true, + "validation": { + "pattern": { + "value": "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$", + "message": "Please enter a valid email address" + } + } +} +``` + +### 3. Use HTTPS for APIs + +```json +{ + "api": "https://api.example.com/data" +} +``` + +### 4. Sanitize Dynamic Content + +When displaying user-generated content, use appropriate sanitization. + +## Testing + +### 1. Use Test IDs for E2E Tests + +```json +{ + "type": "button", + "testId": "submit-form", + "label": "Submit" +} +``` + +Then in tests: +```typescript +await page.getByTestId('submit-form').click(); +``` + +### 2. Validate Schemas in Tests + +```typescript +import { validateSchema } from '@object-ui/core/validation'; + +test('schema is valid', () => { + const result = validateSchema(mySchema); + expect(result.valid).toBe(true); + expect(result.errors).toHaveLength(0); +}); +``` + +### 3. Test Dynamic Expressions + +```typescript +test('expression evaluates correctly', () => { + const schema = { + type: 'text', + content: '${user.name}' + }; + + const context = { user: { name: 'John' } }; + const result = evaluateExpression(schema.content, context); + expect(result).toBe('John'); +}); +``` + +## Accessibility + +### 1. Use Semantic HTML and ARIA Labels + +**✅ Good:** +```json +{ + "type": "button", + "label": "Close", + "ariaLabel": "Close dialog", + "icon": "x" +} +``` + +### 2. Provide Alternative Text for Images + +```json +{ + "type": "image", + "src": "/logo.png", + "alt": "Company Logo" +} +``` + +### 3. Ensure Keyboard Navigation + +```json +{ + "type": "dialog", + "closeOnEscape": true, + "showClose": true +} +``` + +### 4. Use Appropriate Color Contrast + +Use Tailwind's semantic color classes for proper contrast: + +```json +{ + "type": "button", + "className": "bg-primary text-primary-foreground" +} +``` + +## Common Patterns + +### Dashboard Card + +```json +{ + "type": "card", + "className": "shadow-lg", + "body": [ + { + "type": "flex", + "justify": "between", + "align": "start", + "body": [ + { + "type": "div", + "body": [ + { + "type": "text", + "content": "Total Users", + "className": "text-sm font-medium text-muted-foreground" + }, + { + "type": "text", + "content": "${data.userCount}", + "className": "text-3xl font-bold" + } + ] + }, + { + "type": "icon", + "name": "users", + "className": "text-muted-foreground" + } + ] + } + ] +} +``` + +### Data Table with Actions + +```json +{ + "type": "crud", + "resource": "user", + "api": "/api/users", + "columns": [...], + "rowActions": [ + { + "type": "action", + "label": "Edit", + "icon": "edit" + }, + { + "type": "action", + "label": "Delete", + "icon": "trash", + "level": "danger", + "confirmText": "Delete this user?" + } + ] +} +``` + +### Multi-Step Form + +```json +{ + "type": "tabs", + "items": [ + { + "value": "step1", + "label": "Personal Info", + "content": { + "type": "form", + "fields": [...] + } + }, + { + "value": "step2", + "label": "Contact Info", + "content": { + "type": "form", + "fields": [...] + } + } + ] +} +``` + +## Summary + +- ✅ Keep schemas modular and reusable +- ✅ Use semantic component types +- ✅ Leverage conditional rendering +- ✅ Optimize data fetching and caching +- ✅ Use TypeScript for type safety +- ✅ Validate schemas before runtime +- ✅ Handle errors gracefully +- ✅ Never expose sensitive data +- ✅ Add test IDs for testing +- ✅ Follow accessibility guidelines + +Following these best practices will help you build maintainable, performant, and accessible applications with Object UI. diff --git a/packages/core/package.json b/packages/core/package.json index 015c68ff4..310b6adc1 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -11,6 +11,7 @@ "lint": "eslint ." }, "dependencies": { + "@object-ui/types": "workspace:*", "lodash": "^4.17.21", "zod": "^3.22.4" }, diff --git a/packages/core/src/builder/schema-builder.ts b/packages/core/src/builder/schema-builder.ts new file mode 100644 index 000000000..788546949 --- /dev/null +++ b/packages/core/src/builder/schema-builder.ts @@ -0,0 +1,576 @@ +/** + * @object-ui/core - Schema Builder + * + * Fluent API for building schemas programmatically. + * Provides type-safe builder functions for common schema patterns. + * + * @module builder + * @packageDocumentation + */ + +import type { + BaseSchema, + FormSchema, + FormField, + CRUDSchema, + TableColumn, + ActionSchema, + ButtonSchema, + InputSchema, + CardSchema, + GridSchema, + FlexSchema +} from '@object-ui/types'; + +/** + * Base builder class + */ +class SchemaBuilder { + protected schema: any; + + constructor(type: string) { + this.schema = { type }; + } + + /** + * Set the ID + */ + id(id: string): this { + this.schema.id = id; + return this; + } + + /** + * Set the className + */ + className(className: string): this { + this.schema.className = className; + return this; + } + + /** + * Set visibility + */ + visible(visible: boolean): this { + this.schema.visible = visible; + return this; + } + + /** + * Set conditional visibility + */ + visibleOn(expression: string): this { + this.schema.visibleOn = expression; + return this; + } + + /** + * Set disabled state + */ + disabled(disabled: boolean): this { + this.schema.disabled = disabled; + return this; + } + + /** + * Set test ID + */ + testId(testId: string): this { + this.schema.testId = testId; + return this; + } + + /** + * Build the final schema + */ + build(): T { + return this.schema as T; + } +} + +/** + * Form builder + */ +export class FormBuilder extends SchemaBuilder { + constructor() { + super('form'); + this.schema.fields = []; + } + + /** + * Add a field to the form + */ + field(field: FormField): this { + this.schema.fields = [...(this.schema.fields || []), field]; + return this; + } + + /** + * Add multiple fields + */ + fields(fields: FormField[]): this { + this.schema.fields = fields; + return this; + } + + /** + * Set default values + */ + defaultValues(values: Record): this { + this.schema.defaultValues = values; + return this; + } + + /** + * Set submit label + */ + submitLabel(label: string): this { + this.schema.submitLabel = label; + return this; + } + + /** + * Set form layout + */ + layout(layout: 'vertical' | 'horizontal'): this { + this.schema.layout = layout; + return this; + } + + /** + * Set number of columns + */ + columns(columns: number): this { + this.schema.columns = columns; + return this; + } + + /** + * Set submit handler + */ + onSubmit(handler: (data: Record) => void | Promise): this { + this.schema.onSubmit = handler; + return this; + } +} + +/** + * CRUD builder + */ +export class CRUDBuilder extends SchemaBuilder { + constructor() { + super('crud'); + this.schema.columns = []; + } + + /** + * Set resource name + */ + resource(resource: string): this { + this.schema.resource = resource; + return this; + } + + /** + * Set API endpoint + */ + api(api: string): this { + this.schema.api = api; + return this; + } + + /** + * Set title + */ + title(title: string): this { + this.schema.title = title; + return this; + } + + /** + * Set description + */ + description(description: string): this { + this.schema.description = description; + return this; + } + + /** + * Add a column + */ + column(column: TableColumn): this { + this.schema.columns = [...(this.schema.columns || []), column]; + return this; + } + + /** + * Set all columns + */ + columns(columns: TableColumn[]): this { + this.schema.columns = columns; + return this; + } + + /** + * Set form fields + */ + fields(fields: FormField[]): this { + this.schema.fields = fields; + return this; + } + + /** + * Enable create operation + */ + enableCreate(label?: string): this { + if (!this.schema.operations) this.schema.operations = {}; + this.schema.operations.create = { + enabled: true, + label: label || 'Create', + api: this.schema.api, + method: 'POST' + }; + return this; + } + + /** + * Enable update operation + */ + enableUpdate(label?: string): this { + if (!this.schema.operations) this.schema.operations = {}; + this.schema.operations.update = { + enabled: true, + label: label || 'Update', + api: `${this.schema.api}/\${id}`, + method: 'PUT' + }; + return this; + } + + /** + * Enable delete operation + */ + enableDelete(label?: string, confirmText?: string): this { + if (!this.schema.operations) this.schema.operations = {}; + this.schema.operations.delete = { + enabled: true, + label: label || 'Delete', + api: `${this.schema.api}/\${id}`, + method: 'DELETE', + confirmText: confirmText || 'Are you sure?' + }; + return this; + } + + /** + * Set pagination + */ + pagination(pageSize: number = 20): this { + this.schema.pagination = { + enabled: true, + pageSize, + pageSizeOptions: [10, 20, 50, 100], + showTotal: true, + showSizeChanger: true + }; + return this; + } + + /** + * Enable row selection + */ + selectable(mode: 'single' | 'multiple' = 'multiple'): this { + this.schema.selectable = mode; + return this; + } + + /** + * Add a batch action + */ + batchAction(action: ActionSchema): this { + this.schema.batchActions = [...(this.schema.batchActions || []), action]; + return this; + } + + /** + * Add a row action + */ + rowAction(action: ActionSchema): this { + this.schema.rowActions = [...(this.schema.rowActions || []), action]; + return this; + } +} + +/** + * Button builder + */ +export class ButtonBuilder extends SchemaBuilder { + constructor() { + super('button'); + } + + /** + * Set button label + */ + label(label: string): this { + this.schema.label = label; + return this; + } + + /** + * Set button variant + */ + variant(variant: 'default' | 'secondary' | 'destructive' | 'outline' | 'ghost' | 'link'): this { + this.schema.variant = variant; + return this; + } + + /** + * Set button size + */ + size(size: 'default' | 'sm' | 'lg' | 'icon'): this { + this.schema.size = size; + return this; + } + + /** + * Set button icon + */ + icon(icon: string): this { + this.schema.icon = icon; + return this; + } + + /** + * Set click handler + */ + onClick(handler: () => void | Promise): this { + this.schema.onClick = handler; + return this; + } + + /** + * Set loading state + */ + loading(loading: boolean): this { + this.schema.loading = loading; + return this; + } +} + +/** + * Input builder + */ +export class InputBuilder extends SchemaBuilder { + constructor() { + super('input'); + } + + /** + * Set field name + */ + name(name: string): this { + this.schema.name = name; + return this; + } + + /** + * Set label + */ + label(label: string): this { + this.schema.label = label; + return this; + } + + /** + * Set placeholder + */ + placeholder(placeholder: string): this { + this.schema.placeholder = placeholder; + return this; + } + + /** + * Set input type + */ + inputType(type: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url'): this { + this.schema.inputType = type; + return this; + } + + /** + * Mark as required + */ + required(required: boolean = true): this { + this.schema.required = required; + return this; + } + + /** + * Set default value + */ + defaultValue(value: string | number): this { + this.schema.defaultValue = value; + return this; + } +} + +/** + * Card builder + */ +export class CardBuilder extends SchemaBuilder { + constructor() { + super('card'); + } + + /** + * Set card title + */ + title(title: string): this { + this.schema.title = title; + return this; + } + + /** + * Set card description + */ + description(description: string): this { + this.schema.description = description; + return this; + } + + /** + * Set card content + */ + content(content: BaseSchema | BaseSchema[]): this { + this.schema.content = content; + return this; + } + + /** + * Set card variant + */ + variant(variant: 'default' | 'outline' | 'ghost'): this { + this.schema.variant = variant; + return this; + } + + /** + * Make card hoverable + */ + hoverable(hoverable: boolean = true): this { + this.schema.hoverable = hoverable; + return this; + } +} + +/** + * Grid builder + */ +export class GridBuilder extends SchemaBuilder { + constructor() { + super('grid'); + this.schema.children = []; + } + + /** + * Set number of columns + */ + columns(columns: number): this { + this.schema.columns = columns; + return this; + } + + /** + * Set gap + */ + gap(gap: number): this { + this.schema.gap = gap; + return this; + } + + /** + * Add a child + */ + child(child: BaseSchema): this { + const children = Array.isArray(this.schema.children) ? this.schema.children : []; + this.schema.children = [...children, child]; + return this; + } + + /** + * Set all children + */ + children(children: BaseSchema[]): this { + this.schema.children = children; + return this; + } +} + +/** + * Flex builder + */ +export class FlexBuilder extends SchemaBuilder { + constructor() { + super('flex'); + this.schema.children = []; + } + + /** + * Set flex direction + */ + direction(direction: 'row' | 'col' | 'row-reverse' | 'col-reverse'): this { + this.schema.direction = direction; + return this; + } + + /** + * Set justify content + */ + justify(justify: 'start' | 'end' | 'center' | 'between' | 'around' | 'evenly'): this { + this.schema.justify = justify; + return this; + } + + /** + * Set align items + */ + align(align: 'start' | 'end' | 'center' | 'baseline' | 'stretch'): this { + this.schema.align = align; + return this; + } + + /** + * Set gap + */ + gap(gap: number): this { + this.schema.gap = gap; + return this; + } + + /** + * Add a child + */ + child(child: BaseSchema): this { + const children = Array.isArray(this.schema.children) ? this.schema.children : []; + this.schema.children = [...children, child]; + return this; + } + + /** + * Set all children + */ + children(children: BaseSchema[]): this { + this.schema.children = children; + return this; + } +} + +// Export factory functions +export const form = () => new FormBuilder(); +export const crud = () => new CRUDBuilder(); +export const button = () => new ButtonBuilder(); +export const input = () => new InputBuilder(); +export const card = () => new CardBuilder(); +export const grid = () => new GridBuilder(); +export const flex = () => new FlexBuilder(); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 065f30e10..6a96f8063 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,5 +1,7 @@ export * from './types'; export * from './registry/Registry'; +export * from './validation/schema-validator'; +export * from './builder/schema-builder'; // export * from './data-scope'; // TODO // export * from './evaluator'; // TODO // export * from './validators'; // TODO diff --git a/packages/core/src/validation/schema-validator.ts b/packages/core/src/validation/schema-validator.ts new file mode 100644 index 000000000..36af90a2d --- /dev/null +++ b/packages/core/src/validation/schema-validator.ts @@ -0,0 +1,336 @@ +/** + * @object-ui/core - Schema Validation + * + * Runtime validation utilities for Object UI schemas. + * These utilities help ensure schemas are valid before rendering. + * + * @module validation + * @packageDocumentation + */ + +import type { BaseSchema } from '@object-ui/types'; + +/** + * Validation error details + */ +export interface ValidationError { + path: string; + message: string; + type: 'error' | 'warning'; + code?: string; +} + +/** + * Validation result + */ +export interface ValidationResult { + valid: boolean; + errors: ValidationError[]; + warnings: ValidationError[]; +} + +/** + * Validation rules for base schema + */ +const BASE_SCHEMA_RULES = { + type: { + required: true, + validate: (value: any) => typeof value === 'string' && value.length > 0, + message: 'type must be a non-empty string' + }, + id: { + required: false, + validate: (value: any) => typeof value === 'string', + message: 'id must be a string' + }, + className: { + required: false, + validate: (value: any) => typeof value === 'string', + message: 'className must be a string' + }, + visible: { + required: false, + validate: (value: any) => typeof value === 'boolean', + message: 'visible must be a boolean' + }, + disabled: { + required: false, + validate: (value: any) => typeof value === 'boolean', + message: 'disabled must be a boolean' + } +}; + +/** + * Validate a schema against base rules + */ +function validateBaseSchema(schema: any, path: string = 'schema'): ValidationError[] { + const errors: ValidationError[] = []; + + if (!schema || typeof schema !== 'object') { + errors.push({ + path, + message: 'Schema must be an object', + type: 'error', + code: 'INVALID_SCHEMA' + }); + return errors; + } + + // Validate required and optional properties + Object.entries(BASE_SCHEMA_RULES).forEach(([key, rule]) => { + const value = schema[key]; + + if (rule.required && value === undefined) { + errors.push({ + path: `${path}.${key}`, + message: `${key} is required`, + type: 'error', + code: 'MISSING_REQUIRED' + }); + } + + if (value !== undefined && !rule.validate(value)) { + errors.push({ + path: `${path}.${key}`, + message: rule.message, + type: 'error', + code: 'INVALID_TYPE' + }); + } + }); + + return errors; +} + +/** + * Validate CRUD schema specific properties + */ +function validateCRUDSchema(schema: any, path: string = 'schema'): ValidationError[] { + const errors: ValidationError[] = []; + + if (schema.type === 'crud') { + // Check required properties for CRUD + if (!schema.columns || !Array.isArray(schema.columns)) { + errors.push({ + path: `${path}.columns`, + message: 'CRUD schema requires columns array', + type: 'error', + code: 'MISSING_COLUMNS' + }); + } + + if (!schema.api && !schema.dataSource) { + errors.push({ + path: `${path}.api`, + message: 'CRUD schema requires api or dataSource', + type: 'warning', + code: 'MISSING_DATA_SOURCE' + }); + } + + // Validate columns + if (schema.columns && Array.isArray(schema.columns)) { + schema.columns.forEach((column: any, index: number) => { + if (!column.name) { + errors.push({ + path: `${path}.columns[${index}]`, + message: 'Column requires name property', + type: 'error', + code: 'MISSING_COLUMN_NAME' + }); + } + }); + } + + // Validate fields if present + if (schema.fields && Array.isArray(schema.fields)) { + schema.fields.forEach((field: any, index: number) => { + if (!field.name) { + errors.push({ + path: `${path}.fields[${index}]`, + message: 'Field requires name property', + type: 'error', + code: 'MISSING_FIELD_NAME' + }); + } + }); + } + } + + return errors; +} + +/** + * Validate form schema specific properties + */ +function validateFormSchema(schema: any, path: string = 'schema'): ValidationError[] { + const errors: ValidationError[] = []; + + if (schema.type === 'form') { + if (schema.fields && Array.isArray(schema.fields)) { + schema.fields.forEach((field: any, index: number) => { + if (!field.name) { + errors.push({ + path: `${path}.fields[${index}]`, + message: 'Form field requires name property', + type: 'error', + code: 'MISSING_FIELD_NAME' + }); + } + + // Check for duplicate field names + const duplicates = schema.fields.filter((f: any) => f.name === field.name); + if (duplicates.length > 1) { + errors.push({ + path: `${path}.fields[${index}]`, + message: `Duplicate field name: ${field.name}`, + type: 'warning', + code: 'DUPLICATE_FIELD_NAME' + }); + } + }); + } + } + + return errors; +} + +/** + * Validate child schemas recursively + */ +function validateChildren(schema: any, path: string = 'schema'): ValidationError[] { + const errors: ValidationError[] = []; + + const children = schema.children || schema.body; + if (children) { + if (Array.isArray(children)) { + children.forEach((child: any, index: number) => { + if (typeof child === 'object' && child !== null) { + const childResult = validateSchema(child, `${path}.children[${index}]`); + errors.push(...childResult.errors, ...childResult.warnings); + } + }); + } else if (typeof children === 'object' && children !== null) { + const childResult = validateSchema(children, `${path}.children`); + errors.push(...childResult.errors, ...childResult.warnings); + } + } + + return errors; +} + +/** + * Validate a complete schema + * + * @param schema - The schema to validate + * @param options - Validation options + * @returns Validation result with errors and warnings + * + * @example + * ```typescript + * const result = validateSchema({ + * type: 'form', + * fields: [ + * { name: 'email', type: 'input' } + * ] + * }); + * + * if (!result.valid) { + * console.error('Validation errors:', result.errors); + * } + * ``` + */ +export function validateSchema( + schema: any, + path: string = 'schema' +): ValidationResult { + const allErrors: ValidationError[] = []; + + // Validate base schema + allErrors.push(...validateBaseSchema(schema, path)); + + // Validate type-specific schemas + allErrors.push(...validateCRUDSchema(schema, path)); + allErrors.push(...validateFormSchema(schema, path)); + + // Validate children recursively + allErrors.push(...validateChildren(schema, path)); + + const errors = allErrors.filter(e => e.type === 'error'); + const warnings = allErrors.filter(e => e.type === 'warning'); + + return { + valid: errors.length === 0, + errors, + warnings + }; +} + +/** + * Assert that a schema is valid, throwing an error if not + * + * @param schema - The schema to validate + * @throws Error if schema is invalid + * + * @example + * ```typescript + * try { + * assertValidSchema(schema); + * // Schema is valid, continue rendering + * } catch (error) { + * console.error('Invalid schema:', error.message); + * } + * ``` + */ +export function assertValidSchema(schema: any): asserts schema is BaseSchema { + const result = validateSchema(schema); + + if (!result.valid) { + const errorMessages = result.errors.map(e => `${e.path}: ${e.message}`).join('\n'); + throw new Error(`Schema validation failed:\n${errorMessages}`); + } +} + +/** + * Check if a value is a valid schema + * + * @param value - The value to check + * @returns True if the value is a valid schema + * + * @example + * ```typescript + * if (isValidSchema(data)) { + * renderSchema(data); + * } + * ``` + */ +export function isValidSchema(value: any): value is BaseSchema { + const result = validateSchema(value); + return result.valid; +} + +/** + * Get a human-readable error summary + * + * @param result - The validation result + * @returns Formatted error summary + */ +export function formatValidationErrors(result: ValidationResult): string { + const parts: string[] = []; + + if (result.errors.length > 0) { + parts.push('Errors:'); + result.errors.forEach(error => { + parts.push(` - ${error.path}: ${error.message}`); + }); + } + + if (result.warnings.length > 0) { + parts.push('Warnings:'); + result.warnings.forEach(warning => { + parts.push(` - ${warning.path}: ${warning.message}`); + }); + } + + return parts.join('\n'); +} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index b596ae672..1081aa700 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -4,7 +4,12 @@ "outDir": "dist", "rootDir": "src", "noEmit": false, - "declaration": true + "declaration": true, + "composite": true }, - "include": ["src"] + "include": ["src"], + "exclude": ["src/**/*.test.ts"], + "references": [ + { "path": "../types" } + ] } diff --git a/packages/types/src/api.d.ts b/packages/types/src/api.d.ts new file mode 100644 index 000000000..1b609192c --- /dev/null +++ b/packages/types/src/api.d.ts @@ -0,0 +1,450 @@ +/** + * @object-ui/types - API and Event Schemas + * + * Type definitions for API integration and event handling. + * These schemas enable dynamic API calls and event-driven interactions. + * + * @module api + * @packageDocumentation + */ +import type { BaseSchema } from './base'; +/** + * HTTP Method types + */ +export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'; +/** + * API request configuration + */ +export interface APIRequest { + /** + * API endpoint URL + * Supports variable substitution: "/api/users/${userId}" + */ + url: string; + /** + * HTTP method + * @default 'GET' + */ + method?: HTTPMethod; + /** + * Request headers + */ + headers?: Record; + /** + * Request body data + * For POST, PUT, PATCH requests + */ + data?: any; + /** + * Query parameters + */ + params?: Record; + /** + * Request timeout in milliseconds + */ + timeout?: number; + /** + * Whether to send credentials (cookies) + * @default false + */ + withCredentials?: boolean; + /** + * Data transformation function + * Transform request data before sending + */ + transformRequest?: string; + /** + * Response transformation function + * Transform response data after receiving + */ + transformResponse?: string; +} +/** + * API configuration for components + */ +export interface APIConfig { + /** + * API request configuration + */ + request?: APIRequest; + /** + * Success handler + * JavaScript expression or function name + */ + onSuccess?: string; + /** + * Error handler + * JavaScript expression or function name + */ + onError?: string; + /** + * Loading indicator + * Whether to show loading state during request + * @default true + */ + showLoading?: boolean; + /** + * Success message to display + */ + successMessage?: string; + /** + * Error message to display + */ + errorMessage?: string; + /** + * Whether to reload data after success + * @default false + */ + reload?: boolean; + /** + * Whether to redirect after success + */ + redirect?: string; + /** + * Whether to close dialog/modal after success + * @default false + */ + close?: boolean; + /** + * Retry configuration + */ + retry?: { + /** + * Maximum retry attempts + */ + maxAttempts?: number; + /** + * Delay between retries in milliseconds + */ + delay?: number; + /** + * HTTP status codes to retry + */ + retryOn?: number[]; + }; + /** + * Cache configuration + */ + cache?: { + /** + * Cache key + */ + key?: string; + /** + * Cache duration in milliseconds + */ + duration?: number; + /** + * Whether to use stale cache while revalidating + */ + staleWhileRevalidate?: boolean; + }; +} +/** + * Event handler configuration + */ +export interface EventHandler { + /** + * Event type + */ + event: string; + /** + * Handler type + */ + type: 'action' | 'api' | 'script' | 'navigation' | 'dialog' | 'toast' | 'custom'; + /** + * Action configuration (for type: 'action') + */ + action?: { + /** + * Action name/identifier + */ + name: string; + /** + * Action parameters + */ + params?: Record; + }; + /** + * API configuration (for type: 'api') + */ + api?: APIConfig; + /** + * Script to execute (for type: 'script') + * JavaScript code as string + */ + script?: string; + /** + * Navigation target (for type: 'navigation') + */ + navigate?: { + /** + * Target URL or route + */ + to: string; + /** + * Navigation type + */ + type?: 'push' | 'replace' | 'reload'; + /** + * Query parameters + */ + params?: Record; + /** + * Open in new window/tab + */ + external?: boolean; + }; + /** + * Dialog configuration (for type: 'dialog') + */ + dialog?: { + /** + * Dialog type + */ + type: 'alert' | 'confirm' | 'prompt' | 'modal'; + /** + * Dialog title + */ + title?: string; + /** + * Dialog content + */ + content?: string | BaseSchema; + /** + * Dialog actions + */ + actions?: Array<{ + label: string; + handler?: EventHandler; + }>; + }; + /** + * Toast configuration (for type: 'toast') + */ + toast?: { + /** + * Toast type + */ + type: 'success' | 'error' | 'warning' | 'info'; + /** + * Toast message + */ + message: string; + /** + * Toast duration in milliseconds + */ + duration?: number; + }; + /** + * Condition for executing handler + * JavaScript expression + */ + condition?: string; + /** + * Whether to prevent default event behavior + */ + preventDefault?: boolean; + /** + * Whether to stop event propagation + */ + stopPropagation?: boolean; + /** + * Debounce delay in milliseconds + */ + debounce?: number; + /** + * Throttle delay in milliseconds + */ + throttle?: number; +} +/** + * Component with event handlers + */ +export interface EventableSchema extends BaseSchema { + /** + * Event handlers configuration + */ + events?: EventHandler[]; + /** + * Click handler + */ + onClick?: EventHandler | string; + /** + * Change handler + */ + onChange?: EventHandler | string; + /** + * Submit handler + */ + onSubmit?: EventHandler | string; + /** + * Focus handler + */ + onFocus?: EventHandler | string; + /** + * Blur handler + */ + onBlur?: EventHandler | string; + /** + * Mouse enter handler + */ + onMouseEnter?: EventHandler | string; + /** + * Mouse leave handler + */ + onMouseLeave?: EventHandler | string; + /** + * Key down handler + */ + onKeyDown?: EventHandler | string; + /** + * Key up handler + */ + onKeyUp?: EventHandler | string; +} +/** + * Data fetching configuration + */ +export interface DataFetchConfig { + /** + * Data source API + */ + api: string | APIRequest; + /** + * Whether to fetch on mount + * @default true + */ + fetchOnMount?: boolean; + /** + * Polling interval in milliseconds + * If set, data will be refetched at this interval + */ + pollInterval?: number; + /** + * Dependencies for refetching + * Array of variable names to watch + */ + dependencies?: string[]; + /** + * Default data before fetch completes + */ + defaultData?: any; + /** + * Transform function for fetched data + * JavaScript expression or function name + */ + transform?: string; + /** + * Filter function for data + * JavaScript expression or function name + */ + filter?: string; + /** + * Sort configuration + */ + sort?: { + /** + * Field to sort by + */ + field: string; + /** + * Sort order + */ + order: 'asc' | 'desc'; + }; + /** + * Pagination configuration + */ + pagination?: { + /** + * Current page + */ + page?: number; + /** + * Page size + */ + pageSize?: number; + /** + * Whether pagination is enabled + */ + enabled?: boolean; + }; +} +/** + * Component with data fetching + */ +export interface DataFetchableSchema extends BaseSchema { + /** + * Data fetching configuration + */ + dataSource?: DataFetchConfig; + /** + * Loading state + */ + loading?: boolean; + /** + * Error state + */ + error?: string | null; + /** + * Fetched data + */ + data?: any; +} +/** + * Expression evaluation context + */ +export interface ExpressionContext { + /** + * Current component data + */ + data?: any; + /** + * Global application state + */ + state?: any; + /** + * Form values (when in form context) + */ + form?: any; + /** + * Current user information + */ + user?: any; + /** + * Environment variables + */ + env?: Record; + /** + * Utility functions + */ + utils?: Record; +} +/** + * Expression schema for dynamic values + */ +export interface ExpressionSchema { + /** + * Expression type + */ + type: 'expression'; + /** + * Expression string + * Supports ${} syntax for variable interpolation + */ + value: string; + /** + * Default value if expression fails + */ + defaultValue?: any; + /** + * Whether to watch and re-evaluate on context changes + * @default true + */ + reactive?: boolean; +} +/** + * Union type of all API schemas + */ +export type APISchema = EventableSchema | DataFetchableSchema | ExpressionSchema; diff --git a/packages/types/src/api.js b/packages/types/src/api.js new file mode 100644 index 000000000..8905abc7d --- /dev/null +++ b/packages/types/src/api.js @@ -0,0 +1,10 @@ +/** + * @object-ui/types - API and Event Schemas + * + * Type definitions for API integration and event handling. + * These schemas enable dynamic API calls and event-driven interactions. + * + * @module api + * @packageDocumentation + */ +export {}; diff --git a/packages/types/src/base.d.ts b/packages/types/src/base.d.ts new file mode 100644 index 000000000..a42e7a244 --- /dev/null +++ b/packages/types/src/base.d.ts @@ -0,0 +1,359 @@ +/** + * @object-ui/types - Base Schema Types + * + * The foundational type definitions for the Object UI schema protocol. + * These types define the universal interface for all UI components. + * + * @module base + * @packageDocumentation + */ +/** + * Base schema interface that all component schemas extend. + * This is the fundamental building block of the Object UI protocol. + * + * @example + * ```typescript + * const schema: BaseSchema = { + * type: 'text', + * id: 'greeting', + * className: 'text-lg font-bold', + * data: { message: 'Hello World' } + * } + * ``` + */ +export interface BaseSchema { + /** + * Component type identifier. Determines which renderer to use. + * @example 'input', 'button', 'form', 'grid' + */ + type: string; + /** + * Unique identifier for the component instance. + * Used for state management, event handling, and React keys. + */ + id?: string; + /** + * Human-readable name for the component. + * Used for form field names, labels, and debugging. + */ + name?: string; + /** + * Display label for the component. + * Often used in forms, cards, and other UI elements. + */ + label?: string; + /** + * Descriptive text providing additional context. + * Typically rendered as help text below the component. + */ + description?: string; + /** + * Placeholder text for input components. + * Provides hints about expected input format or content. + */ + placeholder?: string; + /** + * Tailwind CSS classes to apply to the component. + * This is the primary styling mechanism in Object UI. + * @example 'bg-blue-500 text-white p-4 rounded-lg' + */ + className?: string; + /** + * Inline CSS styles as a JavaScript object. + * Use sparingly - prefer className with Tailwind. + * @example { backgroundColor: '#fff', padding: '16px' } + */ + style?: Record; + /** + * Arbitrary data attached to the component. + * Can be used for custom properties, state, or context. + */ + data?: any; + /** + * Child components or content. + * Can be a single component, array of components, or primitive values. + */ + body?: SchemaNode | SchemaNode[]; + /** + * Alternative name for children (React-style). + * Some components use 'children' instead of 'body'. + */ + children?: SchemaNode | SchemaNode[]; + /** + * Controls whether the component is visible. + * When false, component is not rendered (display: none). + * @default true + */ + visible?: boolean; + /** + * Expression for conditional visibility. + * Evaluated against the current data context. + * @example "${data.role === 'admin'}" + */ + visibleOn?: string; + /** + * Controls whether the component is hidden (but still rendered). + * When true, component is rendered but not visible (visibility: hidden). + * @default false + */ + hidden?: boolean; + /** + * Expression for conditional hiding. + * @example "${!data.isActive}" + */ + hiddenOn?: string; + /** + * Controls whether the component is disabled. + * Applies to interactive components like buttons and inputs. + * @default false + */ + disabled?: boolean; + /** + * Expression for conditional disabling. + * @example "${data.status === 'locked'}" + */ + disabledOn?: string; + /** + * Test ID for automated testing. + * Rendered as data-testid attribute. + */ + testId?: string; + /** + * Accessibility label for screen readers. + * Rendered as aria-label attribute. + */ + ariaLabel?: string; + /** + * Additional properties specific to the component type. + * This index signature allows type-specific extensions. + */ + [key: string]: any; +} +/** + * A schema node can be a full schema object or a primitive value. + * This union type supports both structured components and simple content. + * + * @example + * ```typescript + * const nodes: SchemaNode[] = [ + * { type: 'text', value: 'Hello' }, + * 'Plain string', + * { type: 'button', label: 'Click' } + * ] + * ``` + */ +export type SchemaNode = BaseSchema | string | number | boolean | null | undefined; +/** + * Component renderer function type. + * Accepts a schema and returns a rendered component. + * Framework-agnostic - can be React, Vue, or any other renderer. + */ +export interface ComponentRendererProps { + /** + * The schema object to render + */ + schema: TSchema; + /** + * Additional properties passed to the renderer + */ + [key: string]: any; +} +/** + * Input field configuration for component metadata. + * Describes what properties a component accepts in the designer/editor. + */ +export interface ComponentInput { + /** + * Property name (must match schema property) + */ + name: string; + /** + * Input control type + */ + type: 'string' | 'number' | 'boolean' | 'enum' | 'array' | 'object' | 'color' | 'date' | 'code' | 'file' | 'slot'; + /** + * Display label in the editor + */ + label?: string; + /** + * Default value for new instances + */ + defaultValue?: any; + /** + * Whether this property is required + */ + required?: boolean; + /** + * Enum options (for type='enum') + */ + enum?: string[] | { + label: string; + value: any; + }[]; + /** + * Help text or description + */ + description?: string; + /** + * Whether this is an advanced/expert option + */ + advanced?: boolean; + /** + * Specific input type (e.g., 'email', 'password' for string) + */ + inputType?: string; + /** + * Minimum value (for number/date) + */ + min?: number; + /** + * Maximum value (for number/date) + */ + max?: number; + /** + * Step value (for number) + */ + step?: number; + /** + * Placeholder text + */ + placeholder?: string; +} +/** + * Component metadata for registration and designer integration. + * Describes the component's capabilities, defaults, and documentation. + */ +export interface ComponentMeta { + /** + * Display name in designer/palette + */ + label?: string; + /** + * Icon name or SVG string + */ + icon?: string; + /** + * Category for grouping (e.g., 'Layout', 'Form', 'Data Display') + */ + category?: string; + /** + * Configurable properties + */ + inputs?: ComponentInput[]; + /** + * Default property values for new instances + */ + defaultProps?: Record; + /** + * Default children for container components + */ + defaultChildren?: SchemaNode[]; + /** + * Example configurations for documentation + */ + examples?: Record; + /** + * Whether the component can have children + */ + isContainer?: boolean; + /** + * Whether the component can be resized in the designer + */ + resizable?: boolean; + /** + * Resize constraints (which dimensions can be resized) + */ + resizeConstraints?: { + width?: boolean; + height?: boolean; + minWidth?: number; + maxWidth?: number; + minHeight?: number; + maxHeight?: number; + }; + /** + * Tags for search/filtering + */ + tags?: string[]; + /** + * Description for documentation + */ + description?: string; +} +/** + * Complete component configuration combining renderer and metadata. + */ +export interface ComponentConfig extends ComponentMeta { + /** + * Unique component type identifier + */ + type: string; + /** + * The component renderer (framework-specific) + */ + component: any; +} +/** + * Common HTML attributes that can be applied to components + */ +export interface HTMLAttributes { + id?: string; + className?: string; + style?: Record; + title?: string; + role?: string; + 'aria-label'?: string; + 'aria-describedby'?: string; + 'data-testid'?: string; +} +/** + * Event handler types + */ +export interface EventHandlers { + onClick?: (event?: any) => void | Promise; + onChange?: (value: any, event?: any) => void | Promise; + onSubmit?: (data: any, event?: any) => void | Promise; + onFocus?: (event?: any) => void; + onBlur?: (event?: any) => void; + onKeyDown?: (event?: any) => void; + onKeyUp?: (event?: any) => void; + onMouseEnter?: (event?: any) => void; + onMouseLeave?: (event?: any) => void; +} +/** + * Common style properties using Tailwind's semantic naming + */ +export interface StyleProps { + /** + * Padding (Tailwind scale: 0-96) + */ + padding?: number | string; + /** + * Margin (Tailwind scale: 0-96) + */ + margin?: number | string; + /** + * Gap between flex/grid items (Tailwind scale: 0-96) + */ + gap?: number | string; + /** + * Background color + */ + backgroundColor?: string; + /** + * Text color + */ + textColor?: string; + /** + * Border width + */ + borderWidth?: number | string; + /** + * Border color + */ + borderColor?: string; + /** + * Border radius + */ + borderRadius?: number | string; +} diff --git a/packages/types/src/base.js b/packages/types/src/base.js new file mode 100644 index 000000000..5c3d37ef7 --- /dev/null +++ b/packages/types/src/base.js @@ -0,0 +1,10 @@ +/** + * @object-ui/types - Base Schema Types + * + * The foundational type definitions for the Object UI schema protocol. + * These types define the universal interface for all UI components. + * + * @module base + * @packageDocumentation + */ +export {}; diff --git a/packages/types/src/complex.d.ts b/packages/types/src/complex.d.ts new file mode 100644 index 000000000..894ef589a --- /dev/null +++ b/packages/types/src/complex.d.ts @@ -0,0 +1,432 @@ +/** + * @object-ui/types - Complex Component Schemas + * + * Type definitions for advanced/composite components. + * + * @module complex + * @packageDocumentation + */ +import type { BaseSchema, SchemaNode } from './base'; +/** + * Kanban column + */ +export interface KanbanColumn { + /** + * Unique column identifier + */ + id: string; + /** + * Column title + */ + title: string; + /** + * Column cards/items + */ + items: KanbanCard[]; + /** + * Column color/variant + */ + color?: string; + /** + * Maximum number of cards allowed + */ + limit?: number; + /** + * Whether column is collapsed + */ + collapsed?: boolean; +} +/** + * Kanban card + */ +export interface KanbanCard { + /** + * Unique card identifier + */ + id: string; + /** + * Card title + */ + title: string; + /** + * Card description + */ + description?: string; + /** + * Card labels/tags + */ + labels?: string[]; + /** + * Card assignees + */ + assignees?: string[]; + /** + * Card due date + */ + dueDate?: string | Date; + /** + * Card priority + */ + priority?: 'low' | 'medium' | 'high' | 'critical'; + /** + * Custom card content + */ + content?: SchemaNode | SchemaNode[]; + /** + * Additional card data + */ + data?: any; +} +/** + * Kanban board component + */ +export interface KanbanSchema extends BaseSchema { + type: 'kanban'; + /** + * Kanban columns + */ + columns: KanbanColumn[]; + /** + * Enable drag and drop + * @default true + */ + draggable?: boolean; + /** + * Card move handler + */ + onCardMove?: (cardId: string, fromColumn: string, toColumn: string, position: number) => void; + /** + * Card click handler + */ + onCardClick?: (card: KanbanCard) => void; + /** + * Column add handler + */ + onColumnAdd?: (column: KanbanColumn) => void; + /** + * Card add handler + */ + onCardAdd?: (columnId: string, card: KanbanCard) => void; +} +/** + * Calendar view mode + */ +export type CalendarViewMode = 'month' | 'week' | 'day' | 'agenda'; +/** + * Calendar event + */ +export interface CalendarEvent { + /** + * Unique event identifier + */ + id: string; + /** + * Event title + */ + title: string; + /** + * Event description + */ + description?: string; + /** + * Event start date/time + */ + start: string | Date; + /** + * Event end date/time + */ + end: string | Date; + /** + * Whether event is all day + */ + allDay?: boolean; + /** + * Event color + */ + color?: string; + /** + * Additional event data + */ + data?: any; +} +/** + * Calendar view component + */ +export interface CalendarViewSchema extends BaseSchema { + type: 'calendar-view'; + /** + * Calendar events + */ + events: CalendarEvent[]; + /** + * Default view mode + * @default 'month' + */ + defaultView?: CalendarViewMode; + /** + * Controlled view mode + */ + view?: CalendarViewMode; + /** + * Default date + */ + defaultDate?: string | Date; + /** + * Controlled date + */ + date?: string | Date; + /** + * Available views + * @default ['month', 'week', 'day'] + */ + views?: CalendarViewMode[]; + /** + * Enable event creation + * @default false + */ + editable?: boolean; + /** + * Event click handler + */ + onEventClick?: (event: CalendarEvent) => void; + /** + * Event create handler + */ + onEventCreate?: (start: Date, end: Date) => void; + /** + * Event update handler + */ + onEventUpdate?: (event: CalendarEvent) => void; + /** + * Date change handler + */ + onDateChange?: (date: Date) => void; + /** + * View change handler + */ + onViewChange?: (view: CalendarViewMode) => void; +} +/** + * Filter operator + */ +export type FilterOperator = 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'starts_with' | 'ends_with' | 'greater_than' | 'less_than' | 'greater_than_or_equal' | 'less_than_or_equal' | 'is_empty' | 'is_not_empty' | 'in' | 'not_in'; +/** + * Filter condition + */ +export interface FilterCondition { + /** + * Field to filter + */ + field: string; + /** + * Filter operator + */ + operator: FilterOperator; + /** + * Filter value + */ + value?: any; +} +/** + * Filter group + */ +export interface FilterGroup { + /** + * Logical operator (AND/OR) + * @default 'and' + */ + operator: 'and' | 'or'; + /** + * Filter conditions or nested groups + */ + conditions: (FilterCondition | FilterGroup)[]; +} +/** + * Filter builder component + */ +export interface FilterBuilderSchema extends BaseSchema { + type: 'filter-builder'; + /** + * Available fields for filtering + */ + fields: FilterField[]; + /** + * Default filter configuration + */ + defaultValue?: FilterGroup; + /** + * Controlled filter value + */ + value?: FilterGroup; + /** + * Change handler + */ + onChange?: (filter: FilterGroup) => void; + /** + * Allow nested groups + * @default true + */ + allowGroups?: boolean; + /** + * Maximum nesting depth + * @default 3 + */ + maxDepth?: number; +} +/** + * Filter field definition + */ +export interface FilterField { + /** + * Field name/key + */ + name: string; + /** + * Field label + */ + label: string; + /** + * Field type + */ + type: 'string' | 'number' | 'date' | 'boolean' | 'select'; + /** + * Available operators for this field + */ + operators?: FilterOperator[]; + /** + * Options (for select type) + */ + options?: { + label: string; + value: any; + }[]; +} +/** + * Carousel item + */ +export interface CarouselItem { + /** + * Unique item identifier + */ + id?: string; + /** + * Item content + */ + content: SchemaNode | SchemaNode[]; +} +/** + * Carousel component + */ +export interface CarouselSchema extends BaseSchema { + type: 'carousel'; + /** + * Carousel items + */ + items: CarouselItem[]; + /** + * Auto-play interval (ms) + */ + autoPlay?: number; + /** + * Show navigation arrows + * @default true + */ + showArrows?: boolean; + /** + * Show pagination dots + * @default true + */ + showDots?: boolean; + /** + * Enable infinite loop + * @default true + */ + loop?: boolean; + /** + * Items visible at once + * @default 1 + */ + itemsPerView?: number; + /** + * Gap between items + */ + gap?: number; + /** + * Slide change handler + */ + onSlideChange?: (index: number) => void; +} +/** + * Chatbot message + */ +export interface ChatMessage { + /** + * Unique message identifier + */ + id: string; + /** + * Message role + */ + role: 'user' | 'assistant' | 'system'; + /** + * Message content + */ + content: string; + /** + * Message timestamp + */ + timestamp?: string | Date; + /** + * Message metadata + */ + metadata?: any; +} +/** + * Chatbot component + */ +export interface ChatbotSchema extends BaseSchema { + type: 'chatbot'; + /** + * Chat messages + */ + messages: ChatMessage[]; + /** + * Input placeholder + * @default 'Type a message...' + */ + placeholder?: string; + /** + * Whether chat is loading (thinking) + */ + loading?: boolean; + /** + * Message send handler + */ + onSendMessage?: (message: string) => void | Promise; + /** + * Show avatars + * @default true + */ + showAvatars?: boolean; + /** + * User avatar + */ + userAvatar?: string; + /** + * Assistant avatar + */ + assistantAvatar?: string; + /** + * Enable markdown rendering + * @default true + */ + markdown?: boolean; + /** + * Chat height + */ + height?: string | number; +} +/** + * Union type of all complex schemas + */ +export type ComplexSchema = KanbanSchema | CalendarViewSchema | FilterBuilderSchema | CarouselSchema | ChatbotSchema; diff --git a/packages/types/src/complex.js b/packages/types/src/complex.js new file mode 100644 index 000000000..08e9e16ea --- /dev/null +++ b/packages/types/src/complex.js @@ -0,0 +1,9 @@ +/** + * @object-ui/types - Complex Component Schemas + * + * Type definitions for advanced/composite components. + * + * @module complex + * @packageDocumentation + */ +export {}; diff --git a/packages/types/src/crud.d.ts b/packages/types/src/crud.d.ts new file mode 100644 index 000000000..c7d61e9b2 --- /dev/null +++ b/packages/types/src/crud.d.ts @@ -0,0 +1,456 @@ +/** + * @object-ui/types - CRUD Component Schemas + * + * Type definitions for Create, Read, Update, Delete operations. + * These schemas enable building complete data management interfaces. + * + * @module crud + * @packageDocumentation + */ +import type { BaseSchema, SchemaNode } from './base'; +import type { FormField } from './form'; +import type { TableColumn } from './data-display'; +/** + * Action button configuration for CRUD operations + */ +export interface ActionSchema extends BaseSchema { + type: 'action'; + /** + * Action label + */ + label: string; + /** + * Action type/level + * @default 'default' + */ + level?: 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'default'; + /** + * Icon to display (lucide-react icon name) + */ + icon?: string; + /** + * Action variant + */ + variant?: 'default' | 'outline' | 'ghost' | 'link'; + /** + * Whether action is disabled + */ + disabled?: boolean; + /** + * Action type + */ + actionType?: 'button' | 'link' | 'dropdown'; + /** + * API endpoint to call + */ + api?: string; + /** + * HTTP method + * @default 'POST' + */ + method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; + /** + * Confirmation message before execution + */ + confirmText?: string; + /** + * Success message after execution + */ + successMessage?: string; + /** + * Whether to reload data after action + * @default true + */ + reload?: boolean; + /** + * Whether to close dialog/modal after action + * @default true + */ + close?: boolean; + /** + * Custom click handler + */ + onClick?: () => void | Promise; + /** + * Redirect URL after success + */ + redirect?: string; +} +/** + * CRUD operation configuration + */ +export interface CRUDOperation { + /** + * Operation type + */ + type: 'create' | 'read' | 'update' | 'delete' | 'export' | 'import' | 'custom'; + /** + * Operation label + */ + label?: string; + /** + * Operation icon + */ + icon?: string; + /** + * Whether operation is enabled + * @default true + */ + enabled?: boolean; + /** + * API endpoint for this operation + */ + api?: string; + /** + * HTTP method + */ + method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; + /** + * Confirmation message + */ + confirmText?: string; + /** + * Success message + */ + successMessage?: string; + /** + * Visibility condition + */ + visibleOn?: string; + /** + * Disabled condition + */ + disabledOn?: string; +} +/** + * Filter configuration for CRUD components + */ +export interface CRUDFilter { + /** + * Filter name (field name) + */ + name: string; + /** + * Filter label + */ + label?: string; + /** + * Filter type + */ + type?: 'input' | 'select' | 'date-picker' | 'date-range' | 'number-range'; + /** + * Filter operator + * @default 'equals' + */ + operator?: 'equals' | 'contains' | 'startsWith' | 'endsWith' | 'gt' | 'gte' | 'lt' | 'lte' | 'between' | 'in'; + /** + * Options for select filter + */ + options?: Array<{ + label: string; + value: string | number; + }>; + /** + * Placeholder text + */ + placeholder?: string; + /** + * Default value + */ + defaultValue?: any; +} +/** + * Toolbar configuration for CRUD components + */ +export interface CRUDToolbar { + /** + * Show create button + * @default true + */ + showCreate?: boolean; + /** + * Show refresh button + * @default true + */ + showRefresh?: boolean; + /** + * Show export button + * @default false + */ + showExport?: boolean; + /** + * Show import button + * @default false + */ + showImport?: boolean; + /** + * Show filter toggle + * @default true + */ + showFilter?: boolean; + /** + * Show search box + * @default true + */ + showSearch?: boolean; + /** + * Custom actions + */ + actions?: ActionSchema[]; +} +/** + * CRUD pagination configuration + */ +export interface CRUDPagination { + /** + * Whether pagination is enabled + * @default true + */ + enabled?: boolean; + /** + * Default page size + * @default 10 + */ + pageSize?: number; + /** + * Page size options + * @default [10, 20, 50, 100] + */ + pageSizeOptions?: number[]; + /** + * Show total count + * @default true + */ + showTotal?: boolean; + /** + * Show page size selector + * @default true + */ + showSizeChanger?: boolean; +} +/** + * Complete CRUD component + * Provides full Create, Read, Update, Delete functionality + */ +export interface CRUDSchema extends BaseSchema { + type: 'crud'; + /** + * CRUD title + */ + title?: string; + /** + * Resource name (singular) + * @example 'user', 'product', 'order' + */ + resource?: string; + /** + * API endpoint for list/search + */ + api?: string; + /** + * Table columns configuration + */ + columns: TableColumn[]; + /** + * Form fields for create/edit + */ + fields?: FormField[]; + /** + * Enabled operations + */ + operations?: { + create?: boolean | CRUDOperation; + read?: boolean | CRUDOperation; + update?: boolean | CRUDOperation; + delete?: boolean | CRUDOperation; + export?: boolean | CRUDOperation; + import?: boolean | CRUDOperation; + [key: string]: boolean | CRUDOperation | undefined; + }; + /** + * Toolbar configuration + */ + toolbar?: CRUDToolbar; + /** + * Filter configuration + */ + filters?: CRUDFilter[]; + /** + * Pagination configuration + */ + pagination?: CRUDPagination; + /** + * Default sort field + */ + defaultSort?: string; + /** + * Default sort order + * @default 'asc' + */ + defaultSortOrder?: 'asc' | 'desc'; + /** + * Row selection mode + */ + selectable?: boolean | 'single' | 'multiple'; + /** + * Batch actions for selected rows + */ + batchActions?: ActionSchema[]; + /** + * Row actions (displayed in each row) + */ + rowActions?: ActionSchema[]; + /** + * Custom empty state + */ + emptyState?: SchemaNode; + /** + * Whether to show loading state + * @default true + */ + loading?: boolean; + /** + * Custom loading component + */ + loadingComponent?: SchemaNode; + /** + * Table layout mode + * @default 'table' + */ + mode?: 'table' | 'grid' | 'list' | 'kanban'; + /** + * Grid columns (for grid mode) + * @default 3 + */ + gridColumns?: number; + /** + * Card template (for grid/list mode) + */ + cardTemplate?: SchemaNode; + /** + * Kanban columns (for kanban mode) + */ + kanbanColumns?: Array<{ + id: string; + title: string; + color?: string; + }>; + /** + * Kanban group field + */ + kanbanGroupField?: string; +} +/** + * Detail view component + * Displays detailed information about a single record + */ +export interface DetailSchema extends BaseSchema { + type: 'detail'; + /** + * Detail title + */ + title?: string; + /** + * API endpoint to fetch detail data + */ + api?: string; + /** + * Resource ID to display + */ + resourceId?: string | number; + /** + * Field groups for organized display + */ + groups?: Array<{ + title?: string; + description?: string; + fields: Array<{ + name: string; + label?: string; + type?: 'text' | 'image' | 'link' | 'badge' | 'date' | 'datetime' | 'json' | 'html' | 'custom'; + format?: string; + render?: SchemaNode; + }>; + }>; + /** + * Actions available in detail view + */ + actions?: ActionSchema[]; + /** + * Tabs for additional content + */ + tabs?: Array<{ + key: string; + label: string; + content: SchemaNode | SchemaNode[]; + }>; + /** + * Show back button + * @default true + */ + showBack?: boolean; + /** + * Custom back action + */ + onBack?: () => void; + /** + * Whether to show loading state + * @default true + */ + loading?: boolean; +} +/** + * CRUD Dialog/Modal component for CRUD operations + * Note: For general dialog usage, use DialogSchema from overlay module + */ +export interface CRUDDialogSchema extends BaseSchema { + type: 'crud-dialog'; + /** + * Dialog title + */ + title?: string; + /** + * Dialog description + */ + description?: string; + /** + * Dialog content + */ + content?: SchemaNode | SchemaNode[]; + /** + * Dialog size + * @default 'default' + */ + size?: 'sm' | 'default' | 'lg' | 'xl' | 'full'; + /** + * Dialog actions/buttons + */ + actions?: ActionSchema[]; + /** + * Whether dialog is open + */ + open?: boolean; + /** + * Close handler + */ + onClose?: () => void; + /** + * Whether clicking outside closes dialog + * @default true + */ + closeOnOutsideClick?: boolean; + /** + * Whether pressing Escape closes dialog + * @default true + */ + closeOnEscape?: boolean; + /** + * Show close button + * @default true + */ + showClose?: boolean; +} +/** + * Union type of all CRUD schemas + */ +export type CRUDComponentSchema = ActionSchema | CRUDSchema | DetailSchema | CRUDDialogSchema; diff --git a/packages/types/src/crud.js b/packages/types/src/crud.js new file mode 100644 index 000000000..13cd7f442 --- /dev/null +++ b/packages/types/src/crud.js @@ -0,0 +1,10 @@ +/** + * @object-ui/types - CRUD Component Schemas + * + * Type definitions for Create, Read, Update, Delete operations. + * These schemas enable building complete data management interfaces. + * + * @module crud + * @packageDocumentation + */ +export {}; diff --git a/packages/types/src/data-display.d.ts b/packages/types/src/data-display.d.ts new file mode 100644 index 000000000..47f3a927a --- /dev/null +++ b/packages/types/src/data-display.d.ts @@ -0,0 +1,537 @@ +/** + * @object-ui/types - Data Display Component Schemas + * + * Type definitions for components that display data and information. + * + * @module data-display + * @packageDocumentation + */ +import type { BaseSchema, SchemaNode } from './base'; +/** + * Alert component + */ +export interface AlertSchema extends BaseSchema { + type: 'alert'; + /** + * Alert title + */ + title?: string; + /** + * Alert description/message + */ + description?: string; + /** + * Alert variant + * @default 'default' + */ + variant?: 'default' | 'destructive'; + /** + * Alert icon + */ + icon?: string; + /** + * Whether alert is dismissible + */ + dismissible?: boolean; + /** + * Dismiss handler + */ + onDismiss?: () => void; + /** + * Child content + */ + children?: SchemaNode | SchemaNode[]; +} +/** + * Badge component + */ +export interface BadgeSchema extends BaseSchema { + type: 'badge'; + /** + * Badge text + */ + label?: string; + /** + * Badge variant + * @default 'default' + */ + variant?: 'default' | 'secondary' | 'destructive' | 'outline'; + /** + * Badge icon + */ + icon?: string; + /** + * Child content + */ + children?: SchemaNode | SchemaNode[]; +} +/** + * Avatar component + */ +export interface AvatarSchema extends BaseSchema { + type: 'avatar'; + /** + * Image source URL + */ + src?: string; + /** + * Alt text + */ + alt?: string; + /** + * Fallback text (initials) + */ + fallback?: string; + /** + * Avatar size + * @default 'default' + */ + size?: 'sm' | 'default' | 'lg' | 'xl'; + /** + * Avatar shape + * @default 'circle' + */ + shape?: 'circle' | 'square'; +} +/** + * List component + */ +export interface ListSchema extends BaseSchema { + type: 'list'; + /** + * List items + */ + items: ListItem[]; + /** + * Whether list is ordered + * @default false + */ + ordered?: boolean; + /** + * List item dividers + * @default false + */ + dividers?: boolean; + /** + * Dense/compact layout + * @default false + */ + dense?: boolean; +} +/** + * List item + */ +export interface ListItem { + /** + * Unique item identifier + */ + id?: string; + /** + * Item label/title + */ + label?: string; + /** + * Item description + */ + description?: string; + /** + * Item icon + */ + icon?: string; + /** + * Item avatar image + */ + avatar?: string; + /** + * Whether item is disabled + */ + disabled?: boolean; + /** + * Click handler + */ + onClick?: () => void; + /** + * Item content (schema nodes) + */ + content?: SchemaNode | SchemaNode[]; +} +/** + * Table column definition + */ +export interface TableColumn { + /** + * Column header text + */ + header: string; + /** + * Key to access data in row object + */ + accessorKey: string; + /** + * Header CSS class + */ + className?: string; + /** + * Cell CSS class + */ + cellClassName?: string; + /** + * Column width + */ + width?: string | number; + /** + * Whether column is sortable + * @default true + */ + sortable?: boolean; + /** + * Whether column is filterable + * @default true + */ + filterable?: boolean; + /** + * Whether column is resizable + * @default true + */ + resizable?: boolean; + /** + * Custom cell renderer function + */ + cell?: (value: any, row: any) => any; +} +/** + * Simple table component + */ +export interface TableSchema extends BaseSchema { + type: 'table'; + /** + * Table caption + */ + caption?: string; + /** + * Table columns + */ + columns: TableColumn[]; + /** + * Table data rows + */ + data: any[]; + /** + * Whether table has hover effect + * @default true + */ + hoverable?: boolean; + /** + * Whether table has striped rows + * @default false + */ + striped?: boolean; +} +/** + * Enterprise data table with advanced features + */ +export interface DataTableSchema extends BaseSchema { + type: 'data-table'; + /** + * Table caption + */ + caption?: string; + /** + * Table columns + */ + columns: TableColumn[]; + /** + * Table data rows + */ + data: any[]; + /** + * Enable pagination + * @default true + */ + pagination?: boolean; + /** + * Rows per page + * @default 10 + */ + pageSize?: number; + /** + * Enable search + * @default true + */ + searchable?: boolean; + /** + * Enable row selection + * @default false + */ + selectable?: boolean; + /** + * Enable column sorting + * @default true + */ + sortable?: boolean; + /** + * Enable CSV export + * @default false + */ + exportable?: boolean; + /** + * Show row actions (edit/delete) + * @default false + */ + rowActions?: boolean; + /** + * Enable column resizing + * @default true + */ + resizableColumns?: boolean; + /** + * Enable column reordering + * @default true + */ + reorderableColumns?: boolean; + /** + * Row edit handler + */ + onRowEdit?: (row: any) => void; + /** + * Row delete handler + */ + onRowDelete?: (row: any) => void; + /** + * Selection change handler + */ + onSelectionChange?: (selectedRows: any[]) => void; + /** + * Columns reorder handler + */ + onColumnsReorder?: (columns: TableColumn[]) => void; +} +/** + * Markdown renderer component + */ +export interface MarkdownSchema extends BaseSchema { + type: 'markdown'; + /** + * Markdown content + */ + content: string; + /** + * Whether to sanitize HTML + * @default true + */ + sanitize?: boolean; + /** + * Custom components for markdown elements + */ + components?: Record; +} +/** + * Tree view node + */ +export interface TreeNode { + /** + * Unique node identifier + */ + id: string; + /** + * Node label + */ + label: string; + /** + * Node icon + */ + icon?: string; + /** + * Whether node is expanded by default + * @default false + */ + defaultExpanded?: boolean; + /** + * Whether node is selectable + * @default true + */ + selectable?: boolean; + /** + * Child nodes + */ + children?: TreeNode[]; + /** + * Additional data + */ + data?: any; +} +/** + * Tree view component + */ +export interface TreeViewSchema extends BaseSchema { + type: 'tree-view'; + /** + * Tree data + */ + data: TreeNode[]; + /** + * Default expanded node IDs + */ + defaultExpandedIds?: string[]; + /** + * Default selected node IDs + */ + defaultSelectedIds?: string[]; + /** + * Controlled expanded node IDs + */ + expandedIds?: string[]; + /** + * Controlled selected node IDs + */ + selectedIds?: string[]; + /** + * Enable multi-selection + * @default false + */ + multiSelect?: boolean; + /** + * Show lines connecting nodes + * @default true + */ + showLines?: boolean; + /** + * Node select handler + */ + onSelectChange?: (selectedIds: string[]) => void; + /** + * Node expand handler + */ + onExpandChange?: (expandedIds: string[]) => void; +} +/** + * Chart type + */ +export type ChartType = 'line' | 'bar' | 'area' | 'pie' | 'donut' | 'radar' | 'scatter'; +/** + * Chart data series + */ +export interface ChartSeries { + /** + * Series name + */ + name: string; + /** + * Series data points + */ + data: number[]; + /** + * Series color + */ + color?: string; +} +/** + * Chart component + */ +export interface ChartSchema extends BaseSchema { + type: 'chart'; + /** + * Chart type + */ + chartType: ChartType; + /** + * Chart title + */ + title?: string; + /** + * Chart description + */ + description?: string; + /** + * X-axis labels/categories + */ + categories?: string[]; + /** + * Data series + */ + series: ChartSeries[]; + /** + * Chart height + */ + height?: string | number; + /** + * Chart width + */ + width?: string | number; + /** + * Show legend + * @default true + */ + showLegend?: boolean; + /** + * Show grid + * @default true + */ + showGrid?: boolean; + /** + * Enable animations + * @default true + */ + animate?: boolean; + /** + * Chart configuration (library-specific) + */ + config?: Record; +} +/** + * Timeline event + */ +export interface TimelineEvent { + /** + * Event unique identifier + */ + id?: string; + /** + * Event title + */ + title: string; + /** + * Event description + */ + description?: string; + /** + * Event date/time + */ + date: string | Date; + /** + * Event icon + */ + icon?: string; + /** + * Event color + */ + color?: string; + /** + * Event content + */ + content?: SchemaNode | SchemaNode[]; +} +/** + * Timeline component + */ +export interface TimelineSchema extends BaseSchema { + type: 'timeline'; + /** + * Timeline events + */ + events: TimelineEvent[]; + /** + * Timeline orientation + * @default 'vertical' + */ + orientation?: 'vertical' | 'horizontal'; + /** + * Timeline position (for vertical) + * @default 'left' + */ + position?: 'left' | 'right' | 'alternate'; +} +/** + * Union type of all data display schemas + */ +export type DataDisplaySchema = AlertSchema | BadgeSchema | AvatarSchema | ListSchema | TableSchema | DataTableSchema | MarkdownSchema | TreeViewSchema | ChartSchema | TimelineSchema; diff --git a/packages/types/src/data-display.js b/packages/types/src/data-display.js new file mode 100644 index 000000000..62d32f97b --- /dev/null +++ b/packages/types/src/data-display.js @@ -0,0 +1,9 @@ +/** + * @object-ui/types - Data Display Component Schemas + * + * Type definitions for components that display data and information. + * + * @module data-display + * @packageDocumentation + */ +export {}; diff --git a/packages/types/src/data.d.ts b/packages/types/src/data.d.ts new file mode 100644 index 000000000..a4ef6ea45 --- /dev/null +++ b/packages/types/src/data.d.ts @@ -0,0 +1,294 @@ +/** + * @object-ui/types - Data Source Types + * + * Type definitions for data fetching and management. + * These interfaces define the universal adapter pattern for data access. + * + * @module data + * @packageDocumentation + */ +/** + * Query parameters for data fetching. + * Follows OData/REST conventions for universal compatibility. + */ +export interface QueryParams { + /** + * Fields to select (projection) + * @example ['id', 'name', 'email'] + */ + $select?: string[]; + /** + * Filter expression + * @example { age: { $gt: 18 }, status: 'active' } + */ + $filter?: Record; + /** + * Sort order + * @example { createdAt: 'desc', name: 'asc' } + */ + $orderby?: Record; + /** + * Number of records to skip (for pagination) + */ + $skip?: number; + /** + * Maximum number of records to return + */ + $top?: number; + /** + * Related entities to expand/include + * @example ['author', 'comments'] + */ + $expand?: string[]; + /** + * Search query (full-text search) + */ + $search?: string; + /** + * Total count of records (for pagination) + */ + $count?: boolean; + /** + * Additional custom parameters + */ + [key: string]: any; +} +/** + * Query result with pagination metadata + */ +export interface QueryResult { + /** + * Result data array + */ + data: T[]; + /** + * Total number of records (if requested) + */ + total?: number; + /** + * Current page number (1-indexed) + */ + page?: number; + /** + * Page size + */ + pageSize?: number; + /** + * Whether there are more records + */ + hasMore?: boolean; + /** + * Cursor for cursor-based pagination + */ + cursor?: string; + /** + * Additional metadata + */ + metadata?: Record; +} +/** + * Universal data source interface. + * This is the core abstraction that makes Object UI backend-agnostic. + * + * Implementations can connect to: + * - REST APIs + * - GraphQL endpoints + * - ObjectQL servers + * - Firebase/Supabase + * - Local arrays/JSON + * - Any data source + * + * @template T - The data type + * + * @example + * ```typescript + * class RestDataSource implements DataSource { + * async find(resource, params) { + * const response = await fetch(`/api/${resource}?${buildQuery(params)}`); + * return response.json(); + * } + * // ... other methods + * } + * ``` + */ +export interface DataSource { + /** + * Fetch multiple records. + * + * @param resource - Resource name (e.g., 'users', 'posts') + * @param params - Query parameters + * @returns Promise resolving to query result + */ + find(resource: string, params?: QueryParams): Promise>; + /** + * Fetch a single record by ID. + * + * @param resource - Resource name + * @param id - Record identifier + * @param params - Additional query parameters + * @returns Promise resolving to the record or null + */ + findOne(resource: string, id: string | number, params?: QueryParams): Promise; + /** + * Create a new record. + * + * @param resource - Resource name + * @param data - Record data + * @returns Promise resolving to the created record + */ + create(resource: string, data: Partial): Promise; + /** + * Update an existing record. + * + * @param resource - Resource name + * @param id - Record identifier + * @param data - Updated data (partial) + * @returns Promise resolving to the updated record + */ + update(resource: string, id: string | number, data: Partial): Promise; + /** + * Delete a record. + * + * @param resource - Resource name + * @param id - Record identifier + * @returns Promise resolving to true if successful + */ + delete(resource: string, id: string | number): Promise; + /** + * Execute a bulk operation (optional). + * + * @param resource - Resource name + * @param operation - Operation type + * @param data - Bulk data + * @returns Promise resolving to operation result + */ + bulk?(resource: string, operation: 'create' | 'update' | 'delete', data: Partial[]): Promise; +} +/** + * Data scope context for managing data state. + * Provides reactive data management within the UI. + */ +export interface DataScope { + /** + * Data source instance + */ + dataSource?: DataSource; + /** + * Current data + */ + data?: any; + /** + * Loading state + */ + loading?: boolean; + /** + * Error state + */ + error?: Error | string | null; + /** + * Refresh data + */ + refresh?: () => Promise; + /** + * Set data + */ + setData?: (data: any) => void; +} +/** + * Data context for component trees. + * Allows components to access and share data. + */ +export interface DataContext { + /** + * Named data scopes + */ + scopes: Record; + /** + * Register a data scope + */ + registerScope: (name: string, scope: DataScope) => void; + /** + * Get a data scope by name + */ + getScope: (name: string) => DataScope | undefined; + /** + * Remove a data scope + */ + removeScope: (name: string) => void; +} +/** + * Data binding configuration. + * Defines how a component's data is sourced and updated. + */ +export interface DataBinding { + /** + * Data source name + */ + source?: string; + /** + * Resource name + */ + resource?: string; + /** + * Query parameters + */ + params?: QueryParams; + /** + * Transform function for data + */ + transform?: (data: any) => any; + /** + * Auto-refresh interval (ms) + */ + refreshInterval?: number; + /** + * Cache data + */ + cache?: boolean; + /** + * Cache TTL (ms) + */ + cacheTTL?: number; +} +/** + * Validation error + */ +export interface ValidationError { + /** + * Field name + */ + field: string; + /** + * Error message + */ + message: string; + /** + * Error code + */ + code?: string; +} +/** + * API error response + */ +export interface APIError { + /** + * Error message + */ + message: string; + /** + * HTTP status code + */ + status?: number; + /** + * Error code + */ + code?: string; + /** + * Validation errors + */ + errors?: ValidationError[]; + /** + * Additional error data + */ + data?: any; +} diff --git a/packages/types/src/data.js b/packages/types/src/data.js new file mode 100644 index 000000000..17efeea15 --- /dev/null +++ b/packages/types/src/data.js @@ -0,0 +1,10 @@ +/** + * @object-ui/types - Data Source Types + * + * Type definitions for data fetching and management. + * These interfaces define the universal adapter pattern for data access. + * + * @module data + * @packageDocumentation + */ +export {}; diff --git a/packages/types/src/disclosure.d.ts b/packages/types/src/disclosure.d.ts new file mode 100644 index 000000000..5670f3379 --- /dev/null +++ b/packages/types/src/disclosure.d.ts @@ -0,0 +1,106 @@ +/** + * @object-ui/types - Disclosure Component Schemas + * + * Type definitions for collapsible and expandable components. + * + * @module disclosure + * @packageDocumentation + */ +import type { BaseSchema, SchemaNode } from './base'; +/** + * Accordion item + */ +export interface AccordionItem { + /** + * Unique item identifier + */ + value: string; + /** + * Item title/trigger + */ + title: string; + /** + * Item content + */ + content: SchemaNode | SchemaNode[]; + /** + * Whether item is disabled + */ + disabled?: boolean; + /** + * Item icon + */ + icon?: string; +} +/** + * Accordion component + */ +export interface AccordionSchema extends BaseSchema { + type: 'accordion'; + /** + * Accordion items + */ + items: AccordionItem[]; + /** + * Accordion type + * @default 'single' + */ + accordionType?: 'single' | 'multiple'; + /** + * Whether items are collapsible + * @default true + */ + collapsible?: boolean; + /** + * Default expanded item values + */ + defaultValue?: string | string[]; + /** + * Controlled expanded item values + */ + value?: string | string[]; + /** + * Change handler + */ + onValueChange?: (value: string | string[]) => void; + /** + * Accordion variant + * @default 'default' + */ + variant?: 'default' | 'bordered' | 'separated'; +} +/** + * Collapsible component + */ +export interface CollapsibleSchema extends BaseSchema { + type: 'collapsible'; + /** + * Trigger content/label + */ + trigger: string | SchemaNode; + /** + * Collapsible content + */ + content: SchemaNode | SchemaNode[]; + /** + * Default open state + * @default false + */ + defaultOpen?: boolean; + /** + * Controlled open state + */ + open?: boolean; + /** + * Whether collapsible is disabled + */ + disabled?: boolean; + /** + * Open state change handler + */ + onOpenChange?: (open: boolean) => void; +} +/** + * Union type of all disclosure schemas + */ +export type DisclosureSchema = AccordionSchema | CollapsibleSchema; diff --git a/packages/types/src/disclosure.js b/packages/types/src/disclosure.js new file mode 100644 index 000000000..b9bda76b7 --- /dev/null +++ b/packages/types/src/disclosure.js @@ -0,0 +1,9 @@ +/** + * @object-ui/types - Disclosure Component Schemas + * + * Type definitions for collapsible and expandable components. + * + * @module disclosure + * @packageDocumentation + */ +export {}; diff --git a/packages/types/src/feedback.d.ts b/packages/types/src/feedback.d.ts new file mode 100644 index 000000000..fff61755d --- /dev/null +++ b/packages/types/src/feedback.d.ts @@ -0,0 +1,158 @@ +/** + * @object-ui/types - Feedback Component Schemas + * + * Type definitions for feedback and status indication components. + * + * @module feedback + * @packageDocumentation + */ +import type { BaseSchema } from './base'; +/** + * Loading/Spinner component + */ +export interface LoadingSchema extends BaseSchema { + type: 'loading'; + /** + * Loading text/message + */ + label?: string; + /** + * Spinner size + * @default 'default' + */ + size?: 'sm' | 'default' | 'lg'; + /** + * Spinner variant + * @default 'spinner' + */ + variant?: 'spinner' | 'dots' | 'pulse'; + /** + * Whether to show fullscreen overlay + * @default false + */ + fullscreen?: boolean; +} +/** + * Progress bar component + */ +export interface ProgressSchema extends BaseSchema { + type: 'progress'; + /** + * Progress value (0-100) + */ + value?: number; + /** + * Maximum value + * @default 100 + */ + max?: number; + /** + * Progress bar variant + * @default 'default' + */ + variant?: 'default' | 'success' | 'warning' | 'error'; + /** + * Show percentage label + * @default false + */ + showLabel?: boolean; + /** + * Progress bar size + * @default 'default' + */ + size?: 'sm' | 'default' | 'lg'; + /** + * Indeterminate/loading state + * @default false + */ + indeterminate?: boolean; +} +/** + * Skeleton loading placeholder + */ +export interface SkeletonSchema extends BaseSchema { + type: 'skeleton'; + /** + * Skeleton variant + * @default 'text' + */ + variant?: 'text' | 'circular' | 'rectangular'; + /** + * Width + */ + width?: string | number; + /** + * Height + */ + height?: string | number; + /** + * Number of lines (for text variant) + * @default 1 + */ + lines?: number; + /** + * Enable animation + * @default true + */ + animate?: boolean; +} +/** + * Toast notification (declarative schema) + */ +export interface ToastSchema extends BaseSchema { + type: 'toast'; + /** + * Toast title + */ + title?: string; + /** + * Toast description + */ + description?: string; + /** + * Toast variant + * @default 'default' + */ + variant?: 'default' | 'success' | 'warning' | 'error' | 'info'; + /** + * Auto-dismiss duration in milliseconds + * @default 5000 + */ + duration?: number; + /** + * Toast position + * @default 'bottom-right' + */ + position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'; + /** + * Action button + */ + action?: { + label: string; + onClick: () => void; + }; + /** + * Dismiss handler + */ + onDismiss?: () => void; +} +/** + * Toaster container (for toast management) + */ +export interface ToasterSchema extends BaseSchema { + type: 'toaster'; + /** + * Toast position + * @default 'bottom-right' + */ + position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'; + /** + * Maximum number of toasts to show + * @default 5 + */ + limit?: number; +} +/** + * Union type of all feedback schemas + */ +export type FeedbackSchema = LoadingSchema | ProgressSchema | SkeletonSchema | ToastSchema | ToasterSchema; diff --git a/packages/types/src/feedback.js b/packages/types/src/feedback.js new file mode 100644 index 000000000..7fdc3a2fd --- /dev/null +++ b/packages/types/src/feedback.js @@ -0,0 +1,9 @@ +/** + * @object-ui/types - Feedback Component Schemas + * + * Type definitions for feedback and status indication components. + * + * @module feedback + * @packageDocumentation + */ +export {}; diff --git a/packages/types/src/form.d.ts b/packages/types/src/form.d.ts new file mode 100644 index 000000000..038871615 --- /dev/null +++ b/packages/types/src/form.d.ts @@ -0,0 +1,895 @@ +/** + * @object-ui/types - Form Component Schemas + * + * Type definitions for form input and interactive components. + * + * @module form + * @packageDocumentation + */ +import type { BaseSchema, SchemaNode } from './base'; +/** + * Button component + */ +export interface ButtonSchema extends BaseSchema { + type: 'button'; + /** + * Button text label + */ + label?: string; + /** + * Button variant/style + * @default 'default' + */ + variant?: 'default' | 'secondary' | 'destructive' | 'outline' | 'ghost' | 'link'; + /** + * Button size + * @default 'default' + */ + size?: 'default' | 'sm' | 'lg' | 'icon'; + /** + * Whether button is disabled + */ + disabled?: boolean; + /** + * Whether button is in loading state + */ + loading?: boolean; + /** + * Icon to display (lucide-react icon name) + */ + icon?: string; + /** + * Icon position + * @default 'left' + */ + iconPosition?: 'left' | 'right'; + /** + * Click handler + */ + onClick?: () => void | Promise; + /** + * Button type + * @default 'button' + */ + buttonType?: 'button' | 'submit' | 'reset'; + /** + * Child components (for custom content) + */ + children?: SchemaNode | SchemaNode[]; +} +/** + * Text input component + */ +export interface InputSchema extends BaseSchema { + type: 'input'; + /** + * Field name for form submission + */ + name?: string; + /** + * Input label + */ + label?: string; + /** + * Placeholder text + */ + placeholder?: string; + /** + * Input type + * @default 'text' + */ + inputType?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search' | 'date' | 'time' | 'datetime-local'; + /** + * Default value + */ + defaultValue?: string | number; + /** + * Controlled value + */ + value?: string | number; + /** + * Whether field is required + */ + required?: boolean; + /** + * Whether field is disabled + */ + disabled?: boolean; + /** + * Whether field is readonly + */ + readOnly?: boolean; + /** + * Help text or description + */ + description?: string; + /** + * Error message + */ + error?: string; + /** + * Change handler + */ + onChange?: (value: string | number) => void; + /** + * Input wrapper CSS class + */ + wrapperClass?: string; + /** + * Minimum value (for number type) + */ + min?: number; + /** + * Maximum value (for number type) + */ + max?: number; + /** + * Step value (for number type) + */ + step?: number; + /** + * Maximum length + */ + maxLength?: number; + /** + * Pattern for validation + */ + pattern?: string; +} +/** + * Textarea component + */ +export interface TextareaSchema extends BaseSchema { + type: 'textarea'; + /** + * Field name for form submission + */ + name?: string; + /** + * Textarea label + */ + label?: string; + /** + * Placeholder text + */ + placeholder?: string; + /** + * Default value + */ + defaultValue?: string; + /** + * Controlled value + */ + value?: string; + /** + * Number of visible rows + */ + rows?: number; + /** + * Whether field is required + */ + required?: boolean; + /** + * Whether field is disabled + */ + disabled?: boolean; + /** + * Whether field is readonly + */ + readOnly?: boolean; + /** + * Help text or description + */ + description?: string; + /** + * Error message + */ + error?: string; + /** + * Change handler + */ + onChange?: (value: string) => void; + /** + * Maximum length + */ + maxLength?: number; +} +/** + * Select dropdown component + */ +export interface SelectSchema extends BaseSchema { + type: 'select'; + /** + * Field name for form submission + */ + name?: string; + /** + * Select label + */ + label?: string; + /** + * Placeholder text + */ + placeholder?: string; + /** + * Default selected value + */ + defaultValue?: string; + /** + * Controlled value + */ + value?: string; + /** + * Select options + */ + options: SelectOption[]; + /** + * Whether field is required + */ + required?: boolean; + /** + * Whether field is disabled + */ + disabled?: boolean; + /** + * Help text or description + */ + description?: string; + /** + * Error message + */ + error?: string; + /** + * Change handler + */ + onChange?: (value: string) => void; +} +/** + * Select option + */ +export interface SelectOption { + /** + * Option label (displayed to user) + */ + label: string; + /** + * Option value (submitted in form) + */ + value: string; + /** + * Whether option is disabled + */ + disabled?: boolean; + /** + * Option icon + */ + icon?: string; +} +/** + * Checkbox component + */ +export interface CheckboxSchema extends BaseSchema { + type: 'checkbox'; + /** + * Field name for form submission + */ + name?: string; + /** + * Checkbox label + */ + label?: string; + /** + * Default checked state + */ + defaultChecked?: boolean; + /** + * Controlled checked state + */ + checked?: boolean; + /** + * Whether checkbox is disabled + */ + disabled?: boolean; + /** + * Help text or description + */ + description?: string; + /** + * Error message + */ + error?: string; + /** + * Change handler + */ + onChange?: (checked: boolean) => void; +} +/** + * Radio group component + */ +export interface RadioGroupSchema extends BaseSchema { + type: 'radio-group'; + /** + * Field name for form submission + */ + name?: string; + /** + * Radio group label + */ + label?: string; + /** + * Default selected value + */ + defaultValue?: string; + /** + * Controlled value + */ + value?: string; + /** + * Radio options + */ + options: RadioOption[]; + /** + * Radio group orientation + * @default 'vertical' + */ + orientation?: 'horizontal' | 'vertical'; + /** + * Whether field is disabled + */ + disabled?: boolean; + /** + * Help text or description + */ + description?: string; + /** + * Error message + */ + error?: string; + /** + * Change handler + */ + onChange?: (value: string) => void; +} +/** + * Radio option + */ +export interface RadioOption { + /** + * Option label + */ + label: string; + /** + * Option value + */ + value: string; + /** + * Whether option is disabled + */ + disabled?: boolean; + /** + * Option description + */ + description?: string; +} +/** + * Switch/Toggle component + */ +export interface SwitchSchema extends BaseSchema { + type: 'switch'; + /** + * Field name for form submission + */ + name?: string; + /** + * Switch label + */ + label?: string; + /** + * Default checked state + */ + defaultChecked?: boolean; + /** + * Controlled checked state + */ + checked?: boolean; + /** + * Whether switch is disabled + */ + disabled?: boolean; + /** + * Help text or description + */ + description?: string; + /** + * Change handler + */ + onChange?: (checked: boolean) => void; +} +/** + * Toggle button component + */ +export interface ToggleSchema extends BaseSchema { + type: 'toggle'; + /** + * Toggle label + */ + label?: string; + /** + * Default pressed state + */ + defaultPressed?: boolean; + /** + * Controlled pressed state + */ + pressed?: boolean; + /** + * Whether toggle is disabled + */ + disabled?: boolean; + /** + * Toggle variant + * @default 'default' + */ + variant?: 'default' | 'outline'; + /** + * Toggle size + * @default 'default' + */ + size?: 'default' | 'sm' | 'lg'; + /** + * Change handler + */ + onChange?: (pressed: boolean) => void; + /** + * Child content + */ + children?: SchemaNode | SchemaNode[]; +} +/** + * Slider component + */ +export interface SliderSchema extends BaseSchema { + type: 'slider'; + /** + * Field name for form submission + */ + name?: string; + /** + * Slider label + */ + label?: string; + /** + * Default value + */ + defaultValue?: number[]; + /** + * Controlled value + */ + value?: number[]; + /** + * Minimum value + * @default 0 + */ + min?: number; + /** + * Maximum value + * @default 100 + */ + max?: number; + /** + * Step increment + * @default 1 + */ + step?: number; + /** + * Whether slider is disabled + */ + disabled?: boolean; + /** + * Help text or description + */ + description?: string; + /** + * Change handler + */ + onChange?: (value: number[]) => void; +} +/** + * File upload component + */ +export interface FileUploadSchema extends BaseSchema { + type: 'file-upload'; + /** + * Field name for form submission + */ + name?: string; + /** + * Upload label + */ + label?: string; + /** + * Accepted file types + * @example 'image/*', '.pdf,.doc' + */ + accept?: string; + /** + * Allow multiple files + * @default false + */ + multiple?: boolean; + /** + * Maximum file size in bytes + */ + maxSize?: number; + /** + * Maximum number of files (for multiple) + */ + maxFiles?: number; + /** + * Whether field is disabled + */ + disabled?: boolean; + /** + * Help text or description + */ + description?: string; + /** + * Error message + */ + error?: string; + /** + * Change handler (receives FileList or File[]) + */ + onChange?: (files: FileList | File[]) => void; +} +/** + * Date picker component + */ +export interface DatePickerSchema extends BaseSchema { + type: 'date-picker'; + /** + * Field name for form submission + */ + name?: string; + /** + * Date picker label + */ + label?: string; + /** + * Placeholder text + */ + placeholder?: string; + /** + * Default value (Date object or ISO string) + */ + defaultValue?: Date | string; + /** + * Controlled value + */ + value?: Date | string; + /** + * Minimum selectable date + */ + minDate?: Date | string; + /** + * Maximum selectable date + */ + maxDate?: Date | string; + /** + * Date format + * @default 'PPP' + */ + format?: string; + /** + * Whether field is disabled + */ + disabled?: boolean; + /** + * Help text or description + */ + description?: string; + /** + * Error message + */ + error?: string; + /** + * Change handler + */ + onChange?: (date: Date | undefined) => void; +} +/** + * Calendar component + */ +export interface CalendarSchema extends BaseSchema { + type: 'calendar'; + /** + * Default selected date(s) + */ + defaultValue?: Date | Date[]; + /** + * Controlled selected date(s) + */ + value?: Date | Date[]; + /** + * Selection mode + * @default 'single' + */ + mode?: 'single' | 'multiple' | 'range'; + /** + * Minimum selectable date + */ + minDate?: Date | string; + /** + * Maximum selectable date + */ + maxDate?: Date | string; + /** + * Whether calendar is disabled + */ + disabled?: boolean; + /** + * Change handler + */ + onChange?: (date: Date | Date[] | undefined) => void; +} +/** + * Input OTP component + */ +export interface InputOTPSchema extends BaseSchema { + type: 'input-otp'; + /** + * Field name for form submission + */ + name?: string; + /** + * OTP input label + */ + label?: string; + /** + * Number of OTP digits + * @default 6 + */ + length?: number; + /** + * Default value + */ + defaultValue?: string; + /** + * Controlled value + */ + value?: string; + /** + * Whether field is disabled + */ + disabled?: boolean; + /** + * Help text or description + */ + description?: string; + /** + * Error message + */ + error?: string; + /** + * Change handler + */ + onChange?: (value: string) => void; + /** + * Complete handler (called when all digits filled) + */ + onComplete?: (value: string) => void; +} +/** + * Form validation rule + */ +export interface ValidationRule { + /** + * Required field validation + */ + required?: string | boolean; + /** + * Minimum length validation + */ + minLength?: { + value: number; + message: string; + }; + /** + * Maximum length validation + */ + maxLength?: { + value: number; + message: string; + }; + /** + * Minimum value validation (for numbers) + */ + min?: { + value: number; + message: string; + }; + /** + * Maximum value validation (for numbers) + */ + max?: { + value: number; + message: string; + }; + /** + * Pattern validation (regex) + */ + pattern?: { + value: string | RegExp; + message: string; + }; + /** + * Custom validation function + * @param value - The field value to validate + * @returns true if valid, false or error message if invalid + */ + validate?: (value: string | number | boolean | null | undefined) => boolean | string | Promise; +} +/** + * Form field condition for conditional rendering + */ +export interface FieldCondition { + /** + * Field to watch + */ + field: string; + /** + * Show when field equals this value + */ + equals?: any; + /** + * Show when field does not equal this value + */ + notEquals?: any; + /** + * Show when field value is in this array + */ + in?: any[]; + /** + * Custom condition function + */ + custom?: (formData: any) => boolean; +} +/** + * Form field configuration + */ +export interface FormField { + /** + * Unique field identifier + */ + id?: string; + /** + * Field name for form submission + */ + name: string; + /** + * Field label + */ + label?: string; + /** + * Field description + */ + description?: string; + /** + * Field type/component + */ + type?: string; + /** + * Input type (for input fields) + */ + inputType?: string; + /** + * Whether field is required + */ + required?: boolean; + /** + * Whether field is disabled + */ + disabled?: boolean; + /** + * Placeholder text + */ + placeholder?: string; + /** + * Select options (for select/radio) + */ + options?: SelectOption[] | RadioOption[]; + /** + * Validation rules + */ + validation?: ValidationRule; + /** + * Conditional rendering + */ + condition?: FieldCondition; + /** + * Additional field-specific props + */ + [key: string]: any; +} +/** + * Complete form component + */ +export interface FormSchema extends BaseSchema { + type: 'form'; + /** + * Form fields configuration + */ + fields?: FormField[]; + /** + * Default form values + */ + defaultValues?: Record; + /** + * Submit button label + * @default 'Submit' + */ + submitLabel?: string; + /** + * Cancel button label + * @default 'Cancel' + */ + cancelLabel?: string; + /** + * Show cancel button + * @default false + */ + showCancel?: boolean; + /** + * Form layout + * @default 'vertical' + */ + layout?: 'vertical' | 'horizontal'; + /** + * Number of columns for multi-column layout + * @default 1 + */ + columns?: number; + /** + * Validation mode + * @default 'onSubmit' + */ + validationMode?: 'onSubmit' | 'onBlur' | 'onChange' | 'onTouched' | 'all'; + /** + * Reset form after successful submission + * @default false + */ + resetOnSubmit?: boolean; + /** + * Whether form is disabled + */ + disabled?: boolean; + /** + * Submit handler + */ + onSubmit?: (data: Record) => void | Promise; + /** + * Change handler (called on any field change) + */ + onChange?: (data: Record) => void; + /** + * Cancel handler + */ + onCancel?: () => void; + /** + * Show form action buttons + * @default true + */ + showActions?: boolean; + /** + * Field container CSS class + */ + fieldContainerClass?: string; + /** + * Child components (alternative to fields array) + */ + children?: SchemaNode | SchemaNode[]; +} +/** + * Union type of all form schemas + */ +export type FormComponentSchema = ButtonSchema | InputSchema | TextareaSchema | SelectSchema | CheckboxSchema | RadioGroupSchema | SwitchSchema | ToggleSchema | SliderSchema | FileUploadSchema | DatePickerSchema | CalendarSchema | InputOTPSchema | FormSchema; diff --git a/packages/types/src/form.js b/packages/types/src/form.js new file mode 100644 index 000000000..781ba3054 --- /dev/null +++ b/packages/types/src/form.js @@ -0,0 +1,9 @@ +/** + * @object-ui/types - Form Component Schemas + * + * Type definitions for form input and interactive components. + * + * @module form + * @packageDocumentation + */ +export {}; diff --git a/packages/types/src/index.d.ts b/packages/types/src/index.d.ts new file mode 100644 index 000000000..cf10619e6 --- /dev/null +++ b/packages/types/src/index.d.ts @@ -0,0 +1,102 @@ +/** + * @object-ui/types + * + * Pure TypeScript type definitions for Object UI - The Protocol Layer. + * + * This package contains ZERO runtime dependencies and defines the complete + * JSON schema protocol for the Object UI ecosystem. + * + * ## Philosophy + * + * Object UI follows a "Schema First" approach where: + * 1. Types define the protocol (this package) + * 2. Core implements the engine (@object-ui/core) + * 3. React provides the framework bindings (@object-ui/react) + * 4. Components provide the UI implementation (@object-ui/components) + * + * ## Design Principles + * + * - **Protocol Agnostic**: Works with any backend (REST, GraphQL, ObjectQL) + * - **Framework Agnostic**: Types can be used with React, Vue, or vanilla JS + * - **Zero Dependencies**: Pure TypeScript with no runtime dependencies + * - **Tailwind Native**: Designed for Tailwind CSS styling via className + * - **Type Safe**: Full TypeScript support with strict typing + * + * ## Usage + * + * ```typescript + * import type { InputSchema, FormSchema, ButtonSchema } from '@object-ui/types'; + * + * const loginForm: FormSchema = { + * type: 'form', + * fields: [ + * { name: 'email', type: 'input', inputType: 'email', required: true }, + * { name: 'password', type: 'input', inputType: 'password', required: true } + * ] + * }; + * ``` + * + * @packageDocumentation + */ +export type { BaseSchema, SchemaNode, ComponentRendererProps, ComponentInput, ComponentMeta, ComponentConfig, HTMLAttributes, EventHandlers, StyleProps, } from './base'; +export type { DivSchema, SpanSchema, TextSchema, ImageSchema, IconSchema, SeparatorSchema, ContainerSchema, FlexSchema, GridSchema, CardSchema, TabsSchema, TabItem, ScrollAreaSchema, ResizableSchema, ResizablePanel, LayoutSchema, PageSchema, } from './layout'; +export type { ButtonSchema, InputSchema, TextareaSchema, SelectSchema, SelectOption, CheckboxSchema, RadioGroupSchema, RadioOption, SwitchSchema, ToggleSchema, SliderSchema, FileUploadSchema, DatePickerSchema, CalendarSchema, InputOTPSchema, ValidationRule, FieldCondition, FormField, FormSchema, FormComponentSchema, } from './form'; +export type { AlertSchema, BadgeSchema, AvatarSchema, ListSchema, ListItem, TableColumn, TableSchema, DataTableSchema, MarkdownSchema, TreeNode, TreeViewSchema, ChartType, ChartSeries, ChartSchema, TimelineEvent, TimelineSchema, DataDisplaySchema, } from './data-display'; +export type { LoadingSchema, ProgressSchema, SkeletonSchema, ToastSchema, ToasterSchema, FeedbackSchema, } from './feedback'; +export type { AccordionItem, AccordionSchema, CollapsibleSchema, DisclosureSchema, } from './disclosure'; +export type { OverlayPosition, OverlayAlignment, DialogSchema, AlertDialogSchema, SheetSchema, DrawerSchema, PopoverSchema, TooltipSchema, HoverCardSchema, MenuItem, DropdownMenuSchema, ContextMenuSchema, OverlaySchema, } from './overlay'; +export type { NavLink, HeaderBarSchema, SidebarSchema, BreadcrumbItem, BreadcrumbSchema, PaginationSchema, NavigationSchema, } from './navigation'; +export type { KanbanColumn, KanbanCard, KanbanSchema, CalendarViewMode, CalendarEvent, CalendarViewSchema, FilterOperator, FilterCondition, FilterGroup, FilterBuilderSchema, FilterField, CarouselItem, CarouselSchema, ChatMessage, ChatbotSchema, ComplexSchema, } from './complex'; +export type { QueryParams, QueryResult, DataSource, DataScope, DataContext, DataBinding, ValidationError, APIError, } from './data'; +export type { ActionSchema, CRUDOperation, CRUDFilter, CRUDToolbar, CRUDPagination, CRUDSchema, DetailSchema, CRUDDialogSchema, CRUDComponentSchema, } from './crud'; +export type { HTTPMethod, APIRequest, APIConfig, EventHandler, EventableSchema, DataFetchConfig, DataFetchableSchema, ExpressionContext, ExpressionSchema, APISchema, } from './api'; +import type { BaseSchema, SchemaNode } from './base'; +import type { LayoutSchema } from './layout'; +import type { FormComponentSchema } from './form'; +import type { DataDisplaySchema } from './data-display'; +import type { FeedbackSchema } from './feedback'; +import type { DisclosureSchema } from './disclosure'; +import type { OverlaySchema } from './overlay'; +import type { NavigationSchema } from './navigation'; +import type { ComplexSchema } from './complex'; +import type { CRUDComponentSchema } from './crud'; +/** + * Union of all component schemas. + * Use this for generic component rendering where the type is determined at runtime. + */ +export type AnySchema = BaseSchema | LayoutSchema | FormComponentSchema | DataDisplaySchema | FeedbackSchema | DisclosureSchema | OverlaySchema | NavigationSchema | ComplexSchema | CRUDComponentSchema; +/** + * Utility type to extract the schema type from a type string. + * Useful for type narrowing in renderers. + * + * @example + * ```typescript + * function renderComponent(schema: SchemaByType) { + * // schema is now typed based on the type string + * } + * ``` + */ +export type SchemaByType = Extract; +/** + * Utility type to make all properties optional except the type. + * Useful for partial schema definitions in editors. + */ +export type PartialSchema = { + type: T['type']; +} & Partial>; +/** + * Schema with required children (for container components). + */ +export type ContainerSchemaWithChildren = BaseSchema & { + children: SchemaNode | SchemaNode[]; +}; +/** + * Version information + */ +export declare const VERSION = "0.1.0"; +/** + * Schema version for compatibility checking + */ +export declare const SCHEMA_VERSION = "1.0.0"; diff --git a/packages/types/src/index.js b/packages/types/src/index.js new file mode 100644 index 000000000..7c33b7ae7 --- /dev/null +++ b/packages/types/src/index.js @@ -0,0 +1,48 @@ +/** + * @object-ui/types + * + * Pure TypeScript type definitions for Object UI - The Protocol Layer. + * + * This package contains ZERO runtime dependencies and defines the complete + * JSON schema protocol for the Object UI ecosystem. + * + * ## Philosophy + * + * Object UI follows a "Schema First" approach where: + * 1. Types define the protocol (this package) + * 2. Core implements the engine (@object-ui/core) + * 3. React provides the framework bindings (@object-ui/react) + * 4. Components provide the UI implementation (@object-ui/components) + * + * ## Design Principles + * + * - **Protocol Agnostic**: Works with any backend (REST, GraphQL, ObjectQL) + * - **Framework Agnostic**: Types can be used with React, Vue, or vanilla JS + * - **Zero Dependencies**: Pure TypeScript with no runtime dependencies + * - **Tailwind Native**: Designed for Tailwind CSS styling via className + * - **Type Safe**: Full TypeScript support with strict typing + * + * ## Usage + * + * ```typescript + * import type { InputSchema, FormSchema, ButtonSchema } from '@object-ui/types'; + * + * const loginForm: FormSchema = { + * type: 'form', + * fields: [ + * { name: 'email', type: 'input', inputType: 'email', required: true }, + * { name: 'password', type: 'input', inputType: 'password', required: true } + * ] + * }; + * ``` + * + * @packageDocumentation + */ +/** + * Version information + */ +export const VERSION = '0.1.0'; +/** + * Schema version for compatibility checking + */ +export const SCHEMA_VERSION = '1.0.0'; diff --git a/packages/types/src/layout.d.ts b/packages/types/src/layout.d.ts new file mode 100644 index 000000000..7f99e063d --- /dev/null +++ b/packages/types/src/layout.d.ts @@ -0,0 +1,380 @@ +/** + * @object-ui/types - Layout Component Schemas + * + * Type definitions for layout and container components. + * These components organize and structure other components. + * + * @module layout + * @packageDocumentation + */ +import type { BaseSchema, SchemaNode } from './base'; +/** + * Basic HTML div container + */ +export interface DivSchema extends BaseSchema { + type: 'div'; + /** + * Child components + */ + children?: SchemaNode | SchemaNode[]; +} +/** + * Text span component for inline text + */ +export interface SpanSchema extends BaseSchema { + type: 'span'; + /** + * Text content + */ + value?: string; + /** + * Child components + */ + children?: SchemaNode | SchemaNode[]; +} +/** + * Text display component + */ +export interface TextSchema extends BaseSchema { + type: 'text'; + /** + * Text content to display + */ + value?: string; + /** + * Text variant/style + * @default 'body' + */ + variant?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'body' | 'caption' | 'overline'; + /** + * Text alignment + */ + align?: 'left' | 'center' | 'right' | 'justify'; +} +/** + * Image component + */ +export interface ImageSchema extends BaseSchema { + type: 'image'; + /** + * Image source URL + */ + src: string; + /** + * Alt text for accessibility + */ + alt?: string; + /** + * Image width + */ + width?: string | number; + /** + * Image height + */ + height?: string | number; + /** + * Object fit property + */ + objectFit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down'; +} +/** + * Icon component + */ +export interface IconSchema extends BaseSchema { + type: 'icon'; + /** + * Icon name (lucide-react icon name) + */ + name: string; + /** + * Icon size in pixels + * @default 24 + */ + size?: number; + /** + * Icon color + */ + color?: string; +} +/** + * Separator/Divider component + */ +export interface SeparatorSchema extends BaseSchema { + type: 'separator'; + /** + * Orientation of the separator + * @default 'horizontal' + */ + orientation?: 'horizontal' | 'vertical'; + /** + * Whether to add decorative content + */ + decorative?: boolean; +} +/** + * Generic container component + */ +export interface ContainerSchema extends BaseSchema { + type: 'container'; + /** + * Max width constraint + * @default 'lg' + */ + maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full' | false; + /** + * Center the container + * @default true + */ + centered?: boolean; + /** + * Padding + */ + padding?: number; + /** + * Child components + */ + children?: SchemaNode | SchemaNode[]; +} +/** + * Flexbox layout component + */ +export interface FlexSchema extends BaseSchema { + type: 'flex'; + /** + * Flex direction + * @default 'row' + */ + direction?: 'row' | 'col' | 'row-reverse' | 'col-reverse'; + /** + * Justify content alignment + * @default 'start' + */ + justify?: 'start' | 'end' | 'center' | 'between' | 'around' | 'evenly'; + /** + * Align items + * @default 'center' + */ + align?: 'start' | 'end' | 'center' | 'baseline' | 'stretch'; + /** + * Gap between items (Tailwind scale 0-8) + * @default 2 + */ + gap?: number; + /** + * Allow items to wrap + * @default false + */ + wrap?: boolean; + /** + * Child components + */ + children?: SchemaNode | SchemaNode[]; +} +/** + * CSS Grid layout component + */ +export interface GridSchema extends BaseSchema { + type: 'grid'; + /** + * Number of columns (responsive) + * Can be number or object: { xs: 1, sm: 2, md: 3, lg: 4 } + * @default 3 + */ + columns?: number | Record; + /** + * Gap between items (Tailwind scale 0-8) + * @default 4 + */ + gap?: number; + /** + * Child components + */ + children?: SchemaNode | SchemaNode[]; +} +/** + * Card component + */ +export interface CardSchema extends BaseSchema { + type: 'card'; + /** + * Card title + */ + title?: string; + /** + * Card description + */ + description?: string; + /** + * Card header content + */ + header?: SchemaNode | SchemaNode[]; + /** + * Card body/content + */ + content?: SchemaNode | SchemaNode[]; + /** + * Card footer content + */ + footer?: SchemaNode | SchemaNode[]; + /** + * Variant style + * @default 'default' + */ + variant?: 'default' | 'outline' | 'ghost'; + /** + * Whether the card is hoverable + * @default false + */ + hoverable?: boolean; + /** + * Whether the card is clickable + * @default false + */ + clickable?: boolean; + /** + * Click handler + */ + onClick?: () => void; +} +/** + * Tabs component + */ +export interface TabsSchema extends BaseSchema { + type: 'tabs'; + /** + * Default active tab value + */ + defaultValue?: string; + /** + * Controlled active tab value + */ + value?: string; + /** + * Tabs orientation + * @default 'horizontal' + */ + orientation?: 'horizontal' | 'vertical'; + /** + * Tab items configuration + */ + items: TabItem[]; + /** + * Change handler + */ + onValueChange?: (value: string) => void; +} +/** + * Individual tab item + */ +export interface TabItem { + /** + * Unique tab identifier + */ + value: string; + /** + * Tab label + */ + label: string; + /** + * Tab icon + */ + icon?: string; + /** + * Whether tab is disabled + */ + disabled?: boolean; + /** + * Tab content + */ + content: SchemaNode | SchemaNode[]; +} +/** + * Scroll area component + */ +export interface ScrollAreaSchema extends BaseSchema { + type: 'scroll-area'; + /** + * Height of the scroll container + */ + height?: string | number; + /** + * Width of the scroll container + */ + width?: string | number; + /** + * Scrollbar orientation + * @default 'vertical' + */ + orientation?: 'vertical' | 'horizontal' | 'both'; + /** + * Child components + */ + children?: SchemaNode | SchemaNode[]; +} +/** + * Resizable panels component + */ +export interface ResizableSchema extends BaseSchema { + type: 'resizable'; + /** + * Direction of resizable panels + * @default 'horizontal' + */ + direction?: 'horizontal' | 'vertical'; + /** + * Resizable panels + */ + panels: ResizablePanel[]; +} +/** + * Individual resizable panel + */ +export interface ResizablePanel { + /** + * Unique panel identifier + */ + id: string; + /** + * Default size (percentage 0-100) + */ + defaultSize?: number; + /** + * Minimum size (percentage 0-100) + */ + minSize?: number; + /** + * Maximum size (percentage 0-100) + */ + maxSize?: number; + /** + * Panel content + */ + content: SchemaNode | SchemaNode[]; +} +/** + * Page layout component + * Top-level container for a page route + */ +export interface PageSchema extends BaseSchema { + type: 'page'; + /** + * Page title + */ + title?: string; + /** + * Page description + */ + description?: string; + /** + * Main content array + */ + body?: SchemaNode[]; + /** + * Alternative content prop + */ + children?: SchemaNode | SchemaNode[]; +} +/** + * Union type of all layout schemas + */ +export type LayoutSchema = DivSchema | SpanSchema | TextSchema | ImageSchema | IconSchema | SeparatorSchema | ContainerSchema | FlexSchema | GridSchema | CardSchema | TabsSchema | ScrollAreaSchema | ResizableSchema | PageSchema; diff --git a/packages/types/src/layout.js b/packages/types/src/layout.js new file mode 100644 index 000000000..1bb63acdc --- /dev/null +++ b/packages/types/src/layout.js @@ -0,0 +1,10 @@ +/** + * @object-ui/types - Layout Component Schemas + * + * Type definitions for layout and container components. + * These components organize and structure other components. + * + * @module layout + * @packageDocumentation + */ +export {}; diff --git a/packages/types/src/navigation.d.ts b/packages/types/src/navigation.d.ts new file mode 100644 index 000000000..6440a1741 --- /dev/null +++ b/packages/types/src/navigation.d.ts @@ -0,0 +1,223 @@ +/** + * @object-ui/types - Navigation Component Schemas + * + * Type definitions for navigation and menu components. + * + * @module navigation + * @packageDocumentation + */ +import type { BaseSchema, SchemaNode } from './base'; +/** + * Navigation link + */ +export interface NavLink { + /** + * Link label + */ + label: string; + /** + * Link URL/href + */ + href: string; + /** + * Link icon + */ + icon?: string; + /** + * Whether link is active + */ + active?: boolean; + /** + * Whether link is disabled + */ + disabled?: boolean; + /** + * Submenu links + */ + children?: NavLink[]; + /** + * Badge content + */ + badge?: string | number; +} +/** + * Header bar component + */ +export interface HeaderBarSchema extends BaseSchema { + type: 'header-bar'; + /** + * Header title/brand + */ + title?: string; + /** + * Brand logo image URL + */ + logo?: string; + /** + * Navigation links + */ + nav?: NavLink[]; + /** + * Left side content + */ + left?: SchemaNode | SchemaNode[]; + /** + * Center content + */ + center?: SchemaNode | SchemaNode[]; + /** + * Right side content + */ + right?: SchemaNode | SchemaNode[]; + /** + * Whether header is sticky + * @default true + */ + sticky?: boolean; + /** + * Header height + */ + height?: string | number; + /** + * Header variant + * @default 'default' + */ + variant?: 'default' | 'bordered' | 'floating'; +} +/** + * Sidebar component + */ +export interface SidebarSchema extends BaseSchema { + type: 'sidebar'; + /** + * Sidebar title + */ + title?: string; + /** + * Navigation links + */ + nav?: NavLink[]; + /** + * Sidebar content (alternative to nav) + */ + content?: SchemaNode | SchemaNode[]; + /** + * Footer content + */ + footer?: SchemaNode | SchemaNode[]; + /** + * Sidebar position + * @default 'left' + */ + position?: 'left' | 'right'; + /** + * Whether sidebar is collapsible + * @default true + */ + collapsible?: boolean; + /** + * Default collapsed state + * @default false + */ + defaultCollapsed?: boolean; + /** + * Controlled collapsed state + */ + collapsed?: boolean; + /** + * Sidebar width when expanded + * @default '16rem' + */ + width?: string | number; + /** + * Sidebar width when collapsed + * @default '4rem' + */ + collapsedWidth?: string | number; + /** + * Collapsed state change handler + */ + onCollapsedChange?: (collapsed: boolean) => void; + /** + * Sidebar variant + * @default 'default' + */ + variant?: 'default' | 'bordered' | 'floating'; +} +/** + * Breadcrumb item + */ +export interface BreadcrumbItem { + /** + * Item label + */ + label: string; + /** + * Item URL/href + */ + href?: string; + /** + * Item icon + */ + icon?: string; + /** + * Click handler (if not using href) + */ + onClick?: () => void; +} +/** + * Breadcrumb component + */ +export interface BreadcrumbSchema extends BaseSchema { + type: 'breadcrumb'; + /** + * Breadcrumb items + */ + items: BreadcrumbItem[]; + /** + * Separator character/icon + * @default '/' + */ + separator?: string; + /** + * Maximum items to display before collapsing + */ + maxItems?: number; +} +/** + * Pagination component + */ +export interface PaginationSchema extends BaseSchema { + type: 'pagination'; + /** + * Current page (1-indexed) + */ + page: number; + /** + * Total number of pages + */ + totalPages: number; + /** + * Number of sibling pages to show + * @default 1 + */ + siblings?: number; + /** + * Show first/last buttons + * @default true + */ + showFirstLast?: boolean; + /** + * Show previous/next buttons + * @default true + */ + showPrevNext?: boolean; + /** + * Page change handler + */ + onPageChange?: (page: number) => void; +} +/** + * Union type of all navigation schemas + */ +export type NavigationSchema = HeaderBarSchema | SidebarSchema | BreadcrumbSchema | PaginationSchema; diff --git a/packages/types/src/navigation.js b/packages/types/src/navigation.js new file mode 100644 index 000000000..8c3914d0c --- /dev/null +++ b/packages/types/src/navigation.js @@ -0,0 +1,9 @@ +/** + * @object-ui/types - Navigation Component Schemas + * + * Type definitions for navigation and menu components. + * + * @module navigation + * @packageDocumentation + */ +export {}; diff --git a/packages/types/src/overlay.d.ts b/packages/types/src/overlay.d.ts new file mode 100644 index 000000000..a3ba97104 --- /dev/null +++ b/packages/types/src/overlay.d.ts @@ -0,0 +1,395 @@ +/** + * @object-ui/types - Overlay Component Schemas + * + * Type definitions for modal, dialog, and overlay components. + * + * @module overlay + * @packageDocumentation + */ +import type { BaseSchema, SchemaNode } from './base'; +/** + * Position type for overlays + */ +export type OverlayPosition = 'top' | 'right' | 'bottom' | 'left'; +/** + * Alignment type for overlays + */ +export type OverlayAlignment = 'start' | 'center' | 'end'; +/** + * Dialog component + */ +export interface DialogSchema extends BaseSchema { + type: 'dialog'; + /** + * Dialog title + */ + title?: string; + /** + * Dialog description + */ + description?: string; + /** + * Dialog content + */ + content?: SchemaNode | SchemaNode[]; + /** + * Dialog trigger (button or element that opens the dialog) + */ + trigger?: SchemaNode; + /** + * Default open state + * @default false + */ + defaultOpen?: boolean; + /** + * Controlled open state + */ + open?: boolean; + /** + * Dialog footer content + */ + footer?: SchemaNode | SchemaNode[]; + /** + * Whether dialog is modal (prevents interaction with background) + * @default true + */ + modal?: boolean; + /** + * Open state change handler + */ + onOpenChange?: (open: boolean) => void; +} +/** + * Alert dialog (confirmation dialog) + */ +export interface AlertDialogSchema extends BaseSchema { + type: 'alert-dialog'; + /** + * Dialog title + */ + title?: string; + /** + * Dialog description + */ + description?: string; + /** + * Dialog trigger + */ + trigger?: SchemaNode; + /** + * Default open state + * @default false + */ + defaultOpen?: boolean; + /** + * Controlled open state + */ + open?: boolean; + /** + * Cancel button label + * @default 'Cancel' + */ + cancelLabel?: string; + /** + * Confirm button label + * @default 'Confirm' + */ + confirmLabel?: string; + /** + * Confirm button variant + * @default 'default' + */ + confirmVariant?: 'default' | 'destructive'; + /** + * Confirm handler + */ + onConfirm?: () => void | Promise; + /** + * Cancel handler + */ + onCancel?: () => void; + /** + * Open state change handler + */ + onOpenChange?: (open: boolean) => void; +} +/** + * Sheet/Drawer side panel + */ +export interface SheetSchema extends BaseSchema { + type: 'sheet'; + /** + * Sheet title + */ + title?: string; + /** + * Sheet description + */ + description?: string; + /** + * Sheet content + */ + content?: SchemaNode | SchemaNode[]; + /** + * Sheet trigger + */ + trigger?: SchemaNode; + /** + * Default open state + * @default false + */ + defaultOpen?: boolean; + /** + * Controlled open state + */ + open?: boolean; + /** + * Sheet side + * @default 'right' + */ + side?: OverlayPosition; + /** + * Sheet footer content + */ + footer?: SchemaNode | SchemaNode[]; + /** + * Open state change handler + */ + onOpenChange?: (open: boolean) => void; +} +/** + * Drawer component (alternative name for Sheet) + */ +export interface DrawerSchema extends BaseSchema { + type: 'drawer'; + /** + * Drawer title + */ + title?: string; + /** + * Drawer description + */ + description?: string; + /** + * Drawer content + */ + content?: SchemaNode | SchemaNode[]; + /** + * Drawer trigger + */ + trigger?: SchemaNode; + /** + * Default open state + * @default false + */ + defaultOpen?: boolean; + /** + * Controlled open state + */ + open?: boolean; + /** + * Drawer direction + * @default 'right' + */ + direction?: OverlayPosition; + /** + * Open state change handler + */ + onOpenChange?: (open: boolean) => void; +} +/** + * Popover component + */ +export interface PopoverSchema extends BaseSchema { + type: 'popover'; + /** + * Popover content + */ + content: SchemaNode | SchemaNode[]; + /** + * Popover trigger + */ + trigger: SchemaNode; + /** + * Default open state + * @default false + */ + defaultOpen?: boolean; + /** + * Controlled open state + */ + open?: boolean; + /** + * Popover side + * @default 'bottom' + */ + side?: OverlayPosition; + /** + * Popover alignment + * @default 'center' + */ + align?: OverlayAlignment; + /** + * Open state change handler + */ + onOpenChange?: (open: boolean) => void; +} +/** + * Tooltip component + */ +export interface TooltipSchema extends BaseSchema { + type: 'tooltip'; + /** + * Tooltip content/text + */ + content: string | SchemaNode; + /** + * Element to attach tooltip to + */ + children: SchemaNode; + /** + * Tooltip side + * @default 'top' + */ + side?: OverlayPosition; + /** + * Tooltip alignment + * @default 'center' + */ + align?: OverlayAlignment; + /** + * Delay before showing (ms) + * @default 200 + */ + delayDuration?: number; +} +/** + * Hover card component + */ +export interface HoverCardSchema extends BaseSchema { + type: 'hover-card'; + /** + * Hover card content + */ + content: SchemaNode | SchemaNode[]; + /** + * Hover trigger element + */ + trigger: SchemaNode; + /** + * Default open state + * @default false + */ + defaultOpen?: boolean; + /** + * Controlled open state + */ + open?: boolean; + /** + * Hover card side + * @default 'bottom' + */ + side?: OverlayPosition; + /** + * Open delay (ms) + * @default 200 + */ + openDelay?: number; + /** + * Close delay (ms) + * @default 300 + */ + closeDelay?: number; + /** + * Open state change handler + */ + onOpenChange?: (open: boolean) => void; +} +/** + * Menu item + */ +export interface MenuItem { + /** + * Menu item label + */ + label: string; + /** + * Menu item icon + */ + icon?: string; + /** + * Whether item is disabled + */ + disabled?: boolean; + /** + * Click handler + */ + onClick?: () => void; + /** + * Keyboard shortcut + */ + shortcut?: string; + /** + * Submenu items + */ + children?: MenuItem[]; + /** + * Separator (renders as divider) + */ + separator?: boolean; +} +/** + * Dropdown menu component + */ +export interface DropdownMenuSchema extends BaseSchema { + type: 'dropdown-menu'; + /** + * Menu items + */ + items: MenuItem[]; + /** + * Menu trigger + */ + trigger: SchemaNode; + /** + * Default open state + * @default false + */ + defaultOpen?: boolean; + /** + * Controlled open state + */ + open?: boolean; + /** + * Menu side + * @default 'bottom' + */ + side?: OverlayPosition; + /** + * Menu alignment + * @default 'start' + */ + align?: OverlayAlignment; + /** + * Open state change handler + */ + onOpenChange?: (open: boolean) => void; +} +/** + * Context menu component + */ +export interface ContextMenuSchema extends BaseSchema { + type: 'context-menu'; + /** + * Menu items + */ + items: MenuItem[]; + /** + * Element to attach context menu to + */ + children: SchemaNode | SchemaNode[]; +} +/** + * Union type of all overlay schemas + */ +export type OverlaySchema = DialogSchema | AlertDialogSchema | SheetSchema | DrawerSchema | PopoverSchema | TooltipSchema | HoverCardSchema | DropdownMenuSchema | ContextMenuSchema; diff --git a/packages/types/src/overlay.js b/packages/types/src/overlay.js new file mode 100644 index 000000000..4854aa329 --- /dev/null +++ b/packages/types/src/overlay.js @@ -0,0 +1,9 @@ +/** + * @object-ui/types - Overlay Component Schemas + * + * Type definitions for modal, dialog, and overlay components. + * + * @module overlay + * @packageDocumentation + */ +export {}; diff --git a/tsconfig.json b/tsconfig.json index bdb2861db..9d7db4c39 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,6 +21,10 @@ "baseUrl": ".", "paths": { + "@object-ui/types": ["packages/types/src"], + "@object-ui/types/*": ["packages/types/src/*"], + "@object-ui/core": ["packages/core/src"], + "@object-ui/core/*": ["packages/core/src/*"], "@object-ui/protocol": ["packages/core/src"], "@object-ui/protocol/*": ["packages/core/src/*"], "@object-ui/engine": ["packages/engine/src"], From 03834b615e9156c0857a5b25703a7d640b3b189c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 05:16:15 +0000 Subject: [PATCH 5/9] docs: Add enhancement summary and finalize PR - Add ENHANCEMENT_SUMMARY.md documenting all completed work - Complete all 5 phases of the enhancement plan - Added 2 new comprehensive examples (user-management, api-integration) - Added 3 new documentation guides (CRUD, API, Best Practices) - Added schema validation and builder utilities - All changes are backward compatible Co-authored-by: xuyushun441-sys <255036401+xuyushun441-sys@users.noreply.github.com> --- ENHANCEMENT_SUMMARY.md | 146 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 ENHANCEMENT_SUMMARY.md diff --git a/ENHANCEMENT_SUMMARY.md b/ENHANCEMENT_SUMMARY.md new file mode 100644 index 000000000..9c0a7d188 --- /dev/null +++ b/ENHANCEMENT_SUMMARY.md @@ -0,0 +1,146 @@ +# Metadata Specifications and Component System Enhancement - Summary + +## Overview + +This PR successfully enhances the Object UI metadata specifications and component system to support building complete applications using pure JSON schemas. + +## What Was Accomplished + +### Phase 1: Enhanced Type Definitions ✅ + +**Commit: 91c498c** + +1. **Extended BaseSchema** with essential properties: + - Conditional rendering: `visibleOn`, `hiddenOn`, `disabledOn` + - Semantic properties: `name`, `label`, `description`, `placeholder` + - Accessibility: `ariaLabel`, `testId` + - Styling: `style` object for inline styles + +2. **Created CRUD Schemas** (`packages/types/src/crud.ts`): + - `CRUDSchema`: Complete CRUD interface with columns, fields, operations, filters, pagination + - `ActionSchema`: Button actions with API integration + - `DetailSchema`: Record detail views + - Supporting types: `CRUDOperation`, `CRUDFilter`, `CRUDToolbar`, `CRUDPagination` + +3. **Created API Integration Schemas** (`packages/types/src/api.ts`): + - `APIRequest`: HTTP request configuration + - `APIConfig`: Success/error handling, loading states, redirects + - `EventHandler`: Dynamic event handling (API calls, navigation, dialogs, toasts) + - `DataFetchConfig`: Automatic data fetching with polling, caching, transformation + - `ExpressionSchema`: Dynamic value expressions + +### Phase 2: Developer Experience Tools ✅ + +**Commit: 4f68e0e** + +1. **Schema Validation** (`packages/core/src/validation/schema-validator.ts`): + ```typescript + validateSchema(schema) // Returns ValidationResult with errors/warnings + assertValidSchema(schema) // Throws on invalid schema + isValidSchema(value) // Type guard + formatValidationErrors() // Human-readable errors + ``` + +2. **Schema Builders** (`packages/core/src/builder/schema-builder.ts`): + - Fluent API for type-safe schema construction + - Builders: `FormBuilder`, `CRUDBuilder`, `ButtonBuilder`, `InputBuilder`, `CardBuilder`, `GridBuilder`, `FlexBuilder` + - Factory functions: `form()`, `crud()`, `button()`, etc. + +3. **TypeScript Configuration**: + - Added composite project references + - Updated path mappings for `@object-ui/types` and `@object-ui/core` + - Improved type inference and IDE support + +### Phase 3: Examples & Documentation ✅ + +**Commit: 4f68e0e** + +1. **Real-World Examples**: + - `examples/user-management/`: Complete CRUD interface (8.9KB JSON) + - Full CRUD operations + - Filters, pagination, sorting + - Batch actions for multiple selections + - Row actions with confirmations + - Empty state handling + + - `examples/api-integration/`: API patterns showcase (11KB JSON) + - Real-time data fetching with polling + - Interactive actions (API calls, dialogs, toasts, navigation) + - Form submission with validation + - Conditional rendering + - Event chaining + - Expression system demo + +2. **Protocol Documentation**: + - `docs/protocol/crud.md` (8.8KB): Complete CRUD protocol specification + - Schema properties reference + - Display modes (table, grid, list, kanban) + - API contract specification + - Variable substitution patterns + + - `docs/integration/api.md` (9.8KB): API integration guide + - Data fetching patterns + - Request/response handling + - Event handlers + - Form submission + - Error handling + - Caching and polling + - Authentication patterns + +3. **Best Practices Guide** (`docs/BEST_PRACTICES.md`, 11KB): + - Schema design patterns + - Performance optimization + - Type safety recommendations + - Maintainability guidelines + - API integration best practices + - Security considerations + - Testing strategies + - Accessibility standards + +## Key Achievements + +1. **Complete JSON-Driven Development**: Applications can now be built entirely from JSON schemas +2. **Type Safety**: Full TypeScript support with validation and builders +3. **Developer Experience**: Fluent APIs and comprehensive validation +4. **Production Ready**: Real-world examples and best practices +5. **Documentation**: Complete protocol specs and integration guides + +## File Statistics + +- **New Type Files**: 2 (crud.ts, api.ts) +- **New Core Files**: 2 (schema-validator.ts, schema-builder.ts) +- **New Examples**: 2 complete applications +- **New Documentation**: 3 comprehensive guides +- **Total Lines Added**: ~6,500+ + +## Next Steps (Future Enhancements) + +While all planned phases are complete, potential future enhancements could include: + +1. **Runtime Schema Migration**: Tools to migrate schemas between versions +2. **Visual Schema Editor**: GUI for building schemas +3. **Additional Builders**: More builder classes for complex components +4. **Extended Validation**: Custom validation rules +5. **Schema Templates**: Pre-built templates for common patterns + +## Testing + +All TypeScript builds pass successfully: +- `packages/types`: ✅ Build successful +- `packages/core`: ✅ Build successful with validation and builders + +## Breaking Changes + +**None**. All changes are additive and backward compatible. + +## Migration Guide + +No migration needed. Existing schemas continue to work as before. New features are opt-in: + +- To use new properties: Add them to existing schemas +- To use validation: Import from `@object-ui/core` +- To use builders: Import from `@object-ui/core/builder` + +## Conclusion + +This PR successfully delivers a comprehensive enhancement to Object UI's metadata specifications and component system, enabling developers to build complete, production-ready applications using pure JSON schemas with full type safety and excellent developer experience. From e0df38a77fc69bb0507ff8ebe13ec99739eb139e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 05:32:44 +0000 Subject: [PATCH 6/9] Changes before error encountered Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com> --- pnpm-lock.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d298982ba..f30fe179c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -475,6 +475,9 @@ importers: packages/core: dependencies: + '@object-ui/types': + specifier: workspace:* + version: link:../types lodash: specifier: ^4.17.21 version: 4.17.21 From e86606a345a3fe0ba2d9469c69c8dfb2ecc4dca7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 06:27:08 +0000 Subject: [PATCH 7/9] fix: Add composite project references for data-objectql and react packages - Configure data-objectql tsconfig with composite: true and types reference - Configure react tsconfig with composite: true and references to types and core - Fixes TypeScript build errors about files not being under rootDir - All packages now build successfully with pnpm build Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com> --- packages/core/src/builder/schema-builder.d.ts | 287 ++++++++++ packages/core/src/builder/schema-builder.js | 505 ++++++++++++++++++ packages/core/src/index.d.ts | 2 + packages/core/src/index.js | 2 + packages/core/src/registry/Registry.d.ts | 13 + .../core/src/validation/schema-validator.d.ts | 87 +++ .../core/src/validation/schema-validator.js | 280 ++++++++++ packages/data-objectql/tsconfig.json | 9 +- packages/react/tsconfig.json | 9 +- 9 files changed, 1190 insertions(+), 4 deletions(-) create mode 100644 packages/core/src/builder/schema-builder.d.ts create mode 100644 packages/core/src/builder/schema-builder.js create mode 100644 packages/core/src/validation/schema-validator.d.ts create mode 100644 packages/core/src/validation/schema-validator.js diff --git a/packages/core/src/builder/schema-builder.d.ts b/packages/core/src/builder/schema-builder.d.ts new file mode 100644 index 000000000..1cdb7fe3f --- /dev/null +++ b/packages/core/src/builder/schema-builder.d.ts @@ -0,0 +1,287 @@ +/** + * @object-ui/core - Schema Builder + * + * Fluent API for building schemas programmatically. + * Provides type-safe builder functions for common schema patterns. + * + * @module builder + * @packageDocumentation + */ +import type { BaseSchema, FormSchema, FormField, CRUDSchema, TableColumn, ActionSchema, ButtonSchema, InputSchema, CardSchema, GridSchema, FlexSchema } from '@object-ui/types'; +/** + * Base builder class + */ +declare class SchemaBuilder { + protected schema: any; + constructor(type: string); + /** + * Set the ID + */ + id(id: string): this; + /** + * Set the className + */ + className(className: string): this; + /** + * Set visibility + */ + visible(visible: boolean): this; + /** + * Set conditional visibility + */ + visibleOn(expression: string): this; + /** + * Set disabled state + */ + disabled(disabled: boolean): this; + /** + * Set test ID + */ + testId(testId: string): this; + /** + * Build the final schema + */ + build(): T; +} +/** + * Form builder + */ +export declare class FormBuilder extends SchemaBuilder { + constructor(); + /** + * Add a field to the form + */ + field(field: FormField): this; + /** + * Add multiple fields + */ + fields(fields: FormField[]): this; + /** + * Set default values + */ + defaultValues(values: Record): this; + /** + * Set submit label + */ + submitLabel(label: string): this; + /** + * Set form layout + */ + layout(layout: 'vertical' | 'horizontal'): this; + /** + * Set number of columns + */ + columns(columns: number): this; + /** + * Set submit handler + */ + onSubmit(handler: (data: Record) => void | Promise): this; +} +/** + * CRUD builder + */ +export declare class CRUDBuilder extends SchemaBuilder { + constructor(); + /** + * Set resource name + */ + resource(resource: string): this; + /** + * Set API endpoint + */ + api(api: string): this; + /** + * Set title + */ + title(title: string): this; + /** + * Set description + */ + description(description: string): this; + /** + * Add a column + */ + column(column: TableColumn): this; + /** + * Set all columns + */ + columns(columns: TableColumn[]): this; + /** + * Set form fields + */ + fields(fields: FormField[]): this; + /** + * Enable create operation + */ + enableCreate(label?: string): this; + /** + * Enable update operation + */ + enableUpdate(label?: string): this; + /** + * Enable delete operation + */ + enableDelete(label?: string, confirmText?: string): this; + /** + * Set pagination + */ + pagination(pageSize?: number): this; + /** + * Enable row selection + */ + selectable(mode?: 'single' | 'multiple'): this; + /** + * Add a batch action + */ + batchAction(action: ActionSchema): this; + /** + * Add a row action + */ + rowAction(action: ActionSchema): this; +} +/** + * Button builder + */ +export declare class ButtonBuilder extends SchemaBuilder { + constructor(); + /** + * Set button label + */ + label(label: string): this; + /** + * Set button variant + */ + variant(variant: 'default' | 'secondary' | 'destructive' | 'outline' | 'ghost' | 'link'): this; + /** + * Set button size + */ + size(size: 'default' | 'sm' | 'lg' | 'icon'): this; + /** + * Set button icon + */ + icon(icon: string): this; + /** + * Set click handler + */ + onClick(handler: () => void | Promise): this; + /** + * Set loading state + */ + loading(loading: boolean): this; +} +/** + * Input builder + */ +export declare class InputBuilder extends SchemaBuilder { + constructor(); + /** + * Set field name + */ + name(name: string): this; + /** + * Set label + */ + label(label: string): this; + /** + * Set placeholder + */ + placeholder(placeholder: string): this; + /** + * Set input type + */ + inputType(type: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url'): this; + /** + * Mark as required + */ + required(required?: boolean): this; + /** + * Set default value + */ + defaultValue(value: string | number): this; +} +/** + * Card builder + */ +export declare class CardBuilder extends SchemaBuilder { + constructor(); + /** + * Set card title + */ + title(title: string): this; + /** + * Set card description + */ + description(description: string): this; + /** + * Set card content + */ + content(content: BaseSchema | BaseSchema[]): this; + /** + * Set card variant + */ + variant(variant: 'default' | 'outline' | 'ghost'): this; + /** + * Make card hoverable + */ + hoverable(hoverable?: boolean): this; +} +/** + * Grid builder + */ +export declare class GridBuilder extends SchemaBuilder { + constructor(); + /** + * Set number of columns + */ + columns(columns: number): this; + /** + * Set gap + */ + gap(gap: number): this; + /** + * Add a child + */ + child(child: BaseSchema): this; + /** + * Set all children + */ + children(children: BaseSchema[]): this; +} +/** + * Flex builder + */ +export declare class FlexBuilder extends SchemaBuilder { + constructor(); + /** + * Set flex direction + */ + direction(direction: 'row' | 'col' | 'row-reverse' | 'col-reverse'): this; + /** + * Set justify content + */ + justify(justify: 'start' | 'end' | 'center' | 'between' | 'around' | 'evenly'): this; + /** + * Set align items + */ + align(align: 'start' | 'end' | 'center' | 'baseline' | 'stretch'): this; + /** + * Set gap + */ + gap(gap: number): this; + /** + * Add a child + */ + child(child: BaseSchema): this; + /** + * Set all children + */ + children(children: BaseSchema[]): this; +} +export declare const form: () => FormBuilder; +export declare const crud: () => CRUDBuilder; +export declare const button: () => ButtonBuilder; +export declare const input: () => InputBuilder; +export declare const card: () => CardBuilder; +export declare const grid: () => GridBuilder; +export declare const flex: () => FlexBuilder; +export {}; diff --git a/packages/core/src/builder/schema-builder.js b/packages/core/src/builder/schema-builder.js new file mode 100644 index 000000000..e16686125 --- /dev/null +++ b/packages/core/src/builder/schema-builder.js @@ -0,0 +1,505 @@ +/** + * @object-ui/core - Schema Builder + * + * Fluent API for building schemas programmatically. + * Provides type-safe builder functions for common schema patterns. + * + * @module builder + * @packageDocumentation + */ +/** + * Base builder class + */ +class SchemaBuilder { + constructor(type) { + Object.defineProperty(this, "schema", { + enumerable: true, + configurable: true, + writable: true, + value: void 0 + }); + this.schema = { type }; + } + /** + * Set the ID + */ + id(id) { + this.schema.id = id; + return this; + } + /** + * Set the className + */ + className(className) { + this.schema.className = className; + return this; + } + /** + * Set visibility + */ + visible(visible) { + this.schema.visible = visible; + return this; + } + /** + * Set conditional visibility + */ + visibleOn(expression) { + this.schema.visibleOn = expression; + return this; + } + /** + * Set disabled state + */ + disabled(disabled) { + this.schema.disabled = disabled; + return this; + } + /** + * Set test ID + */ + testId(testId) { + this.schema.testId = testId; + return this; + } + /** + * Build the final schema + */ + build() { + return this.schema; + } +} +/** + * Form builder + */ +export class FormBuilder extends SchemaBuilder { + constructor() { + super('form'); + this.schema.fields = []; + } + /** + * Add a field to the form + */ + field(field) { + this.schema.fields = [...(this.schema.fields || []), field]; + return this; + } + /** + * Add multiple fields + */ + fields(fields) { + this.schema.fields = fields; + return this; + } + /** + * Set default values + */ + defaultValues(values) { + this.schema.defaultValues = values; + return this; + } + /** + * Set submit label + */ + submitLabel(label) { + this.schema.submitLabel = label; + return this; + } + /** + * Set form layout + */ + layout(layout) { + this.schema.layout = layout; + return this; + } + /** + * Set number of columns + */ + columns(columns) { + this.schema.columns = columns; + return this; + } + /** + * Set submit handler + */ + onSubmit(handler) { + this.schema.onSubmit = handler; + return this; + } +} +/** + * CRUD builder + */ +export class CRUDBuilder extends SchemaBuilder { + constructor() { + super('crud'); + this.schema.columns = []; + } + /** + * Set resource name + */ + resource(resource) { + this.schema.resource = resource; + return this; + } + /** + * Set API endpoint + */ + api(api) { + this.schema.api = api; + return this; + } + /** + * Set title + */ + title(title) { + this.schema.title = title; + return this; + } + /** + * Set description + */ + description(description) { + this.schema.description = description; + return this; + } + /** + * Add a column + */ + column(column) { + this.schema.columns = [...(this.schema.columns || []), column]; + return this; + } + /** + * Set all columns + */ + columns(columns) { + this.schema.columns = columns; + return this; + } + /** + * Set form fields + */ + fields(fields) { + this.schema.fields = fields; + return this; + } + /** + * Enable create operation + */ + enableCreate(label) { + if (!this.schema.operations) + this.schema.operations = {}; + this.schema.operations.create = { + enabled: true, + label: label || 'Create', + api: this.schema.api, + method: 'POST' + }; + return this; + } + /** + * Enable update operation + */ + enableUpdate(label) { + if (!this.schema.operations) + this.schema.operations = {}; + this.schema.operations.update = { + enabled: true, + label: label || 'Update', + api: `${this.schema.api}/\${id}`, + method: 'PUT' + }; + return this; + } + /** + * Enable delete operation + */ + enableDelete(label, confirmText) { + if (!this.schema.operations) + this.schema.operations = {}; + this.schema.operations.delete = { + enabled: true, + label: label || 'Delete', + api: `${this.schema.api}/\${id}`, + method: 'DELETE', + confirmText: confirmText || 'Are you sure?' + }; + return this; + } + /** + * Set pagination + */ + pagination(pageSize = 20) { + this.schema.pagination = { + enabled: true, + pageSize, + pageSizeOptions: [10, 20, 50, 100], + showTotal: true, + showSizeChanger: true + }; + return this; + } + /** + * Enable row selection + */ + selectable(mode = 'multiple') { + this.schema.selectable = mode; + return this; + } + /** + * Add a batch action + */ + batchAction(action) { + this.schema.batchActions = [...(this.schema.batchActions || []), action]; + return this; + } + /** + * Add a row action + */ + rowAction(action) { + this.schema.rowActions = [...(this.schema.rowActions || []), action]; + return this; + } +} +/** + * Button builder + */ +export class ButtonBuilder extends SchemaBuilder { + constructor() { + super('button'); + } + /** + * Set button label + */ + label(label) { + this.schema.label = label; + return this; + } + /** + * Set button variant + */ + variant(variant) { + this.schema.variant = variant; + return this; + } + /** + * Set button size + */ + size(size) { + this.schema.size = size; + return this; + } + /** + * Set button icon + */ + icon(icon) { + this.schema.icon = icon; + return this; + } + /** + * Set click handler + */ + onClick(handler) { + this.schema.onClick = handler; + return this; + } + /** + * Set loading state + */ + loading(loading) { + this.schema.loading = loading; + return this; + } +} +/** + * Input builder + */ +export class InputBuilder extends SchemaBuilder { + constructor() { + super('input'); + } + /** + * Set field name + */ + name(name) { + this.schema.name = name; + return this; + } + /** + * Set label + */ + label(label) { + this.schema.label = label; + return this; + } + /** + * Set placeholder + */ + placeholder(placeholder) { + this.schema.placeholder = placeholder; + return this; + } + /** + * Set input type + */ + inputType(type) { + this.schema.inputType = type; + return this; + } + /** + * Mark as required + */ + required(required = true) { + this.schema.required = required; + return this; + } + /** + * Set default value + */ + defaultValue(value) { + this.schema.defaultValue = value; + return this; + } +} +/** + * Card builder + */ +export class CardBuilder extends SchemaBuilder { + constructor() { + super('card'); + } + /** + * Set card title + */ + title(title) { + this.schema.title = title; + return this; + } + /** + * Set card description + */ + description(description) { + this.schema.description = description; + return this; + } + /** + * Set card content + */ + content(content) { + this.schema.content = content; + return this; + } + /** + * Set card variant + */ + variant(variant) { + this.schema.variant = variant; + return this; + } + /** + * Make card hoverable + */ + hoverable(hoverable = true) { + this.schema.hoverable = hoverable; + return this; + } +} +/** + * Grid builder + */ +export class GridBuilder extends SchemaBuilder { + constructor() { + super('grid'); + this.schema.children = []; + } + /** + * Set number of columns + */ + columns(columns) { + this.schema.columns = columns; + return this; + } + /** + * Set gap + */ + gap(gap) { + this.schema.gap = gap; + return this; + } + /** + * Add a child + */ + child(child) { + const children = Array.isArray(this.schema.children) ? this.schema.children : []; + this.schema.children = [...children, child]; + return this; + } + /** + * Set all children + */ + children(children) { + this.schema.children = children; + return this; + } +} +/** + * Flex builder + */ +export class FlexBuilder extends SchemaBuilder { + constructor() { + super('flex'); + this.schema.children = []; + } + /** + * Set flex direction + */ + direction(direction) { + this.schema.direction = direction; + return this; + } + /** + * Set justify content + */ + justify(justify) { + this.schema.justify = justify; + return this; + } + /** + * Set align items + */ + align(align) { + this.schema.align = align; + return this; + } + /** + * Set gap + */ + gap(gap) { + this.schema.gap = gap; + return this; + } + /** + * Add a child + */ + child(child) { + const children = Array.isArray(this.schema.children) ? this.schema.children : []; + this.schema.children = [...children, child]; + return this; + } + /** + * Set all children + */ + children(children) { + this.schema.children = children; + return this; + } +} +// Export factory functions +export const form = () => new FormBuilder(); +export const crud = () => new CRUDBuilder(); +export const button = () => new ButtonBuilder(); +export const input = () => new InputBuilder(); +export const card = () => new CardBuilder(); +export const grid = () => new GridBuilder(); +export const flex = () => new FlexBuilder(); diff --git a/packages/core/src/index.d.ts b/packages/core/src/index.d.ts index 3e73ea163..b3b222bcb 100644 --- a/packages/core/src/index.d.ts +++ b/packages/core/src/index.d.ts @@ -1,2 +1,4 @@ export * from './types'; export * from './registry/Registry'; +export * from './validation/schema-validator'; +export * from './builder/schema-builder'; diff --git a/packages/core/src/index.js b/packages/core/src/index.js index 301d3a241..2651ed50d 100644 --- a/packages/core/src/index.js +++ b/packages/core/src/index.js @@ -1,5 +1,7 @@ export * from './types'; export * from './registry/Registry'; +export * from './validation/schema-validator'; +export * from './builder/schema-builder'; // export * from './data-scope'; // TODO // export * from './evaluator'; // TODO // export * from './validators'; // TODO diff --git a/packages/core/src/registry/Registry.d.ts b/packages/core/src/registry/Registry.d.ts index f2b2dd0f7..0053d24f3 100644 --- a/packages/core/src/registry/Registry.d.ts +++ b/packages/core/src/registry/Registry.d.ts @@ -12,13 +12,26 @@ export type ComponentInput = { }[]; description?: string; advanced?: boolean; + inputType?: string; }; export type ComponentMeta = { label?: string; icon?: string; + category?: string; inputs?: ComponentInput[]; defaultProps?: Record; defaultChildren?: SchemaNode[]; + examples?: Record; + isContainer?: boolean; + resizable?: boolean; + resizeConstraints?: { + width?: boolean; + height?: boolean; + minWidth?: number; + maxWidth?: number; + minHeight?: number; + maxHeight?: number; + }; }; export type ComponentConfig = ComponentMeta & { type: string; diff --git a/packages/core/src/validation/schema-validator.d.ts b/packages/core/src/validation/schema-validator.d.ts new file mode 100644 index 000000000..de426df23 --- /dev/null +++ b/packages/core/src/validation/schema-validator.d.ts @@ -0,0 +1,87 @@ +/** + * @object-ui/core - Schema Validation + * + * Runtime validation utilities for Object UI schemas. + * These utilities help ensure schemas are valid before rendering. + * + * @module validation + * @packageDocumentation + */ +import type { BaseSchema } from '@object-ui/types'; +/** + * Validation error details + */ +export interface ValidationError { + path: string; + message: string; + type: 'error' | 'warning'; + code?: string; +} +/** + * Validation result + */ +export interface ValidationResult { + valid: boolean; + errors: ValidationError[]; + warnings: ValidationError[]; +} +/** + * Validate a complete schema + * + * @param schema - The schema to validate + * @param options - Validation options + * @returns Validation result with errors and warnings + * + * @example + * ```typescript + * const result = validateSchema({ + * type: 'form', + * fields: [ + * { name: 'email', type: 'input' } + * ] + * }); + * + * if (!result.valid) { + * console.error('Validation errors:', result.errors); + * } + * ``` + */ +export declare function validateSchema(schema: any, path?: string): ValidationResult; +/** + * Assert that a schema is valid, throwing an error if not + * + * @param schema - The schema to validate + * @throws Error if schema is invalid + * + * @example + * ```typescript + * try { + * assertValidSchema(schema); + * // Schema is valid, continue rendering + * } catch (error) { + * console.error('Invalid schema:', error.message); + * } + * ``` + */ +export declare function assertValidSchema(schema: any): asserts schema is BaseSchema; +/** + * Check if a value is a valid schema + * + * @param value - The value to check + * @returns True if the value is a valid schema + * + * @example + * ```typescript + * if (isValidSchema(data)) { + * renderSchema(data); + * } + * ``` + */ +export declare function isValidSchema(value: any): value is BaseSchema; +/** + * Get a human-readable error summary + * + * @param result - The validation result + * @returns Formatted error summary + */ +export declare function formatValidationErrors(result: ValidationResult): string; diff --git a/packages/core/src/validation/schema-validator.js b/packages/core/src/validation/schema-validator.js new file mode 100644 index 000000000..611e116b7 --- /dev/null +++ b/packages/core/src/validation/schema-validator.js @@ -0,0 +1,280 @@ +/** + * @object-ui/core - Schema Validation + * + * Runtime validation utilities for Object UI schemas. + * These utilities help ensure schemas are valid before rendering. + * + * @module validation + * @packageDocumentation + */ +/** + * Validation rules for base schema + */ +const BASE_SCHEMA_RULES = { + type: { + required: true, + validate: (value) => typeof value === 'string' && value.length > 0, + message: 'type must be a non-empty string' + }, + id: { + required: false, + validate: (value) => typeof value === 'string', + message: 'id must be a string' + }, + className: { + required: false, + validate: (value) => typeof value === 'string', + message: 'className must be a string' + }, + visible: { + required: false, + validate: (value) => typeof value === 'boolean', + message: 'visible must be a boolean' + }, + disabled: { + required: false, + validate: (value) => typeof value === 'boolean', + message: 'disabled must be a boolean' + } +}; +/** + * Validate a schema against base rules + */ +function validateBaseSchema(schema, path = 'schema') { + const errors = []; + if (!schema || typeof schema !== 'object') { + errors.push({ + path, + message: 'Schema must be an object', + type: 'error', + code: 'INVALID_SCHEMA' + }); + return errors; + } + // Validate required and optional properties + Object.entries(BASE_SCHEMA_RULES).forEach(([key, rule]) => { + const value = schema[key]; + if (rule.required && value === undefined) { + errors.push({ + path: `${path}.${key}`, + message: `${key} is required`, + type: 'error', + code: 'MISSING_REQUIRED' + }); + } + if (value !== undefined && !rule.validate(value)) { + errors.push({ + path: `${path}.${key}`, + message: rule.message, + type: 'error', + code: 'INVALID_TYPE' + }); + } + }); + return errors; +} +/** + * Validate CRUD schema specific properties + */ +function validateCRUDSchema(schema, path = 'schema') { + const errors = []; + if (schema.type === 'crud') { + // Check required properties for CRUD + if (!schema.columns || !Array.isArray(schema.columns)) { + errors.push({ + path: `${path}.columns`, + message: 'CRUD schema requires columns array', + type: 'error', + code: 'MISSING_COLUMNS' + }); + } + if (!schema.api && !schema.dataSource) { + errors.push({ + path: `${path}.api`, + message: 'CRUD schema requires api or dataSource', + type: 'warning', + code: 'MISSING_DATA_SOURCE' + }); + } + // Validate columns + if (schema.columns && Array.isArray(schema.columns)) { + schema.columns.forEach((column, index) => { + if (!column.name) { + errors.push({ + path: `${path}.columns[${index}]`, + message: 'Column requires name property', + type: 'error', + code: 'MISSING_COLUMN_NAME' + }); + } + }); + } + // Validate fields if present + if (schema.fields && Array.isArray(schema.fields)) { + schema.fields.forEach((field, index) => { + if (!field.name) { + errors.push({ + path: `${path}.fields[${index}]`, + message: 'Field requires name property', + type: 'error', + code: 'MISSING_FIELD_NAME' + }); + } + }); + } + } + return errors; +} +/** + * Validate form schema specific properties + */ +function validateFormSchema(schema, path = 'schema') { + const errors = []; + if (schema.type === 'form') { + if (schema.fields && Array.isArray(schema.fields)) { + schema.fields.forEach((field, index) => { + if (!field.name) { + errors.push({ + path: `${path}.fields[${index}]`, + message: 'Form field requires name property', + type: 'error', + code: 'MISSING_FIELD_NAME' + }); + } + // Check for duplicate field names + const duplicates = schema.fields.filter((f) => f.name === field.name); + if (duplicates.length > 1) { + errors.push({ + path: `${path}.fields[${index}]`, + message: `Duplicate field name: ${field.name}`, + type: 'warning', + code: 'DUPLICATE_FIELD_NAME' + }); + } + }); + } + } + return errors; +} +/** + * Validate child schemas recursively + */ +function validateChildren(schema, path = 'schema') { + const errors = []; + const children = schema.children || schema.body; + if (children) { + if (Array.isArray(children)) { + children.forEach((child, index) => { + if (typeof child === 'object' && child !== null) { + const childResult = validateSchema(child, `${path}.children[${index}]`); + errors.push(...childResult.errors, ...childResult.warnings); + } + }); + } + else if (typeof children === 'object' && children !== null) { + const childResult = validateSchema(children, `${path}.children`); + errors.push(...childResult.errors, ...childResult.warnings); + } + } + return errors; +} +/** + * Validate a complete schema + * + * @param schema - The schema to validate + * @param options - Validation options + * @returns Validation result with errors and warnings + * + * @example + * ```typescript + * const result = validateSchema({ + * type: 'form', + * fields: [ + * { name: 'email', type: 'input' } + * ] + * }); + * + * if (!result.valid) { + * console.error('Validation errors:', result.errors); + * } + * ``` + */ +export function validateSchema(schema, path = 'schema') { + const allErrors = []; + // Validate base schema + allErrors.push(...validateBaseSchema(schema, path)); + // Validate type-specific schemas + allErrors.push(...validateCRUDSchema(schema, path)); + allErrors.push(...validateFormSchema(schema, path)); + // Validate children recursively + allErrors.push(...validateChildren(schema, path)); + const errors = allErrors.filter(e => e.type === 'error'); + const warnings = allErrors.filter(e => e.type === 'warning'); + return { + valid: errors.length === 0, + errors, + warnings + }; +} +/** + * Assert that a schema is valid, throwing an error if not + * + * @param schema - The schema to validate + * @throws Error if schema is invalid + * + * @example + * ```typescript + * try { + * assertValidSchema(schema); + * // Schema is valid, continue rendering + * } catch (error) { + * console.error('Invalid schema:', error.message); + * } + * ``` + */ +export function assertValidSchema(schema) { + const result = validateSchema(schema); + if (!result.valid) { + const errorMessages = result.errors.map(e => `${e.path}: ${e.message}`).join('\n'); + throw new Error(`Schema validation failed:\n${errorMessages}`); + } +} +/** + * Check if a value is a valid schema + * + * @param value - The value to check + * @returns True if the value is a valid schema + * + * @example + * ```typescript + * if (isValidSchema(data)) { + * renderSchema(data); + * } + * ``` + */ +export function isValidSchema(value) { + const result = validateSchema(value); + return result.valid; +} +/** + * Get a human-readable error summary + * + * @param result - The validation result + * @returns Formatted error summary + */ +export function formatValidationErrors(result) { + const parts = []; + if (result.errors.length > 0) { + parts.push('Errors:'); + result.errors.forEach(error => { + parts.push(` - ${error.path}: ${error.message}`); + }); + } + if (result.warnings.length > 0) { + parts.push('Warnings:'); + result.warnings.forEach(warning => { + parts.push(` - ${warning.path}: ${warning.message}`); + }); + } + return parts.join('\n'); +} diff --git a/packages/data-objectql/tsconfig.json b/packages/data-objectql/tsconfig.json index 516a2824e..48103b0db 100644 --- a/packages/data-objectql/tsconfig.json +++ b/packages/data-objectql/tsconfig.json @@ -4,8 +4,13 @@ "outDir": "./dist", "rootDir": "./src", "declaration": true, - "declarationDir": "./dist" + "declarationDir": "./dist", + "composite": true, + "noEmit": false }, "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.test.tsx"] + "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.test.tsx"], + "references": [ + { "path": "../types" } + ] } diff --git a/packages/react/tsconfig.json b/packages/react/tsconfig.json index 24a7ca4af..19bd07b2c 100644 --- a/packages/react/tsconfig.json +++ b/packages/react/tsconfig.json @@ -5,7 +5,12 @@ "rootDir": "src", "jsx": "react-jsx", "noEmit": false, - "declaration": true + "declaration": true, + "composite": true }, - "include": ["src"] + "include": ["src"], + "references": [ + { "path": "../types" }, + { "path": "../core" } + ] } From 629f6e704dea2d27ea8ee2b1430fe874d4259e47 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 15 Jan 2026 06:51:15 +0000 Subject: [PATCH 8/9] fix: Fix eslint errors in types package - Replace Function type with proper function signature in api.ts - Remove generated .d.ts and .js files from src directory - Update .gitignore to prevent generated files in src - All packages now pass lint with 0 errors (only warnings remain) - Fixes: utils?: Record -> utils?: Record any> Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- packages/types/.gitignore | 5 + packages/types/src/api.d.ts | 450 -------------- packages/types/src/api.js | 10 - packages/types/src/api.ts | 2 +- packages/types/src/base.d.ts | 359 ----------- packages/types/src/base.js | 10 - packages/types/src/complex.d.ts | 432 ------------- packages/types/src/complex.js | 9 - packages/types/src/crud.d.ts | 456 -------------- packages/types/src/crud.js | 10 - packages/types/src/data-display.d.ts | 537 ---------------- packages/types/src/data-display.js | 9 - packages/types/src/data.d.ts | 294 --------- packages/types/src/data.js | 10 - packages/types/src/disclosure.d.ts | 106 ---- packages/types/src/disclosure.js | 9 - packages/types/src/feedback.d.ts | 158 ----- packages/types/src/feedback.js | 9 - packages/types/src/form.d.ts | 895 --------------------------- packages/types/src/form.js | 9 - packages/types/src/index.d.ts | 102 --- packages/types/src/index.js | 48 -- packages/types/src/layout.d.ts | 380 ------------ packages/types/src/layout.js | 10 - packages/types/src/navigation.d.ts | 223 ------- packages/types/src/navigation.js | 9 - packages/types/src/overlay.d.ts | 395 ------------ packages/types/src/overlay.js | 9 - 28 files changed, 6 insertions(+), 4949 deletions(-) delete mode 100644 packages/types/src/api.d.ts delete mode 100644 packages/types/src/api.js delete mode 100644 packages/types/src/base.d.ts delete mode 100644 packages/types/src/base.js delete mode 100644 packages/types/src/complex.d.ts delete mode 100644 packages/types/src/complex.js delete mode 100644 packages/types/src/crud.d.ts delete mode 100644 packages/types/src/crud.js delete mode 100644 packages/types/src/data-display.d.ts delete mode 100644 packages/types/src/data-display.js delete mode 100644 packages/types/src/data.d.ts delete mode 100644 packages/types/src/data.js delete mode 100644 packages/types/src/disclosure.d.ts delete mode 100644 packages/types/src/disclosure.js delete mode 100644 packages/types/src/feedback.d.ts delete mode 100644 packages/types/src/feedback.js delete mode 100644 packages/types/src/form.d.ts delete mode 100644 packages/types/src/form.js delete mode 100644 packages/types/src/index.d.ts delete mode 100644 packages/types/src/index.js delete mode 100644 packages/types/src/layout.d.ts delete mode 100644 packages/types/src/layout.js delete mode 100644 packages/types/src/navigation.d.ts delete mode 100644 packages/types/src/navigation.js delete mode 100644 packages/types/src/overlay.d.ts delete mode 100644 packages/types/src/overlay.js diff --git a/packages/types/.gitignore b/packages/types/.gitignore index 1eae0cf67..8ace31571 100644 --- a/packages/types/.gitignore +++ b/packages/types/.gitignore @@ -1,2 +1,7 @@ dist/ node_modules/ +# Ignore generated files in src (should only be in dist) +src/**/*.d.ts +src/**/*.js +!src/**/*.test.ts +!src/**/*.test.js diff --git a/packages/types/src/api.d.ts b/packages/types/src/api.d.ts deleted file mode 100644 index 1b609192c..000000000 --- a/packages/types/src/api.d.ts +++ /dev/null @@ -1,450 +0,0 @@ -/** - * @object-ui/types - API and Event Schemas - * - * Type definitions for API integration and event handling. - * These schemas enable dynamic API calls and event-driven interactions. - * - * @module api - * @packageDocumentation - */ -import type { BaseSchema } from './base'; -/** - * HTTP Method types - */ -export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'; -/** - * API request configuration - */ -export interface APIRequest { - /** - * API endpoint URL - * Supports variable substitution: "/api/users/${userId}" - */ - url: string; - /** - * HTTP method - * @default 'GET' - */ - method?: HTTPMethod; - /** - * Request headers - */ - headers?: Record; - /** - * Request body data - * For POST, PUT, PATCH requests - */ - data?: any; - /** - * Query parameters - */ - params?: Record; - /** - * Request timeout in milliseconds - */ - timeout?: number; - /** - * Whether to send credentials (cookies) - * @default false - */ - withCredentials?: boolean; - /** - * Data transformation function - * Transform request data before sending - */ - transformRequest?: string; - /** - * Response transformation function - * Transform response data after receiving - */ - transformResponse?: string; -} -/** - * API configuration for components - */ -export interface APIConfig { - /** - * API request configuration - */ - request?: APIRequest; - /** - * Success handler - * JavaScript expression or function name - */ - onSuccess?: string; - /** - * Error handler - * JavaScript expression or function name - */ - onError?: string; - /** - * Loading indicator - * Whether to show loading state during request - * @default true - */ - showLoading?: boolean; - /** - * Success message to display - */ - successMessage?: string; - /** - * Error message to display - */ - errorMessage?: string; - /** - * Whether to reload data after success - * @default false - */ - reload?: boolean; - /** - * Whether to redirect after success - */ - redirect?: string; - /** - * Whether to close dialog/modal after success - * @default false - */ - close?: boolean; - /** - * Retry configuration - */ - retry?: { - /** - * Maximum retry attempts - */ - maxAttempts?: number; - /** - * Delay between retries in milliseconds - */ - delay?: number; - /** - * HTTP status codes to retry - */ - retryOn?: number[]; - }; - /** - * Cache configuration - */ - cache?: { - /** - * Cache key - */ - key?: string; - /** - * Cache duration in milliseconds - */ - duration?: number; - /** - * Whether to use stale cache while revalidating - */ - staleWhileRevalidate?: boolean; - }; -} -/** - * Event handler configuration - */ -export interface EventHandler { - /** - * Event type - */ - event: string; - /** - * Handler type - */ - type: 'action' | 'api' | 'script' | 'navigation' | 'dialog' | 'toast' | 'custom'; - /** - * Action configuration (for type: 'action') - */ - action?: { - /** - * Action name/identifier - */ - name: string; - /** - * Action parameters - */ - params?: Record; - }; - /** - * API configuration (for type: 'api') - */ - api?: APIConfig; - /** - * Script to execute (for type: 'script') - * JavaScript code as string - */ - script?: string; - /** - * Navigation target (for type: 'navigation') - */ - navigate?: { - /** - * Target URL or route - */ - to: string; - /** - * Navigation type - */ - type?: 'push' | 'replace' | 'reload'; - /** - * Query parameters - */ - params?: Record; - /** - * Open in new window/tab - */ - external?: boolean; - }; - /** - * Dialog configuration (for type: 'dialog') - */ - dialog?: { - /** - * Dialog type - */ - type: 'alert' | 'confirm' | 'prompt' | 'modal'; - /** - * Dialog title - */ - title?: string; - /** - * Dialog content - */ - content?: string | BaseSchema; - /** - * Dialog actions - */ - actions?: Array<{ - label: string; - handler?: EventHandler; - }>; - }; - /** - * Toast configuration (for type: 'toast') - */ - toast?: { - /** - * Toast type - */ - type: 'success' | 'error' | 'warning' | 'info'; - /** - * Toast message - */ - message: string; - /** - * Toast duration in milliseconds - */ - duration?: number; - }; - /** - * Condition for executing handler - * JavaScript expression - */ - condition?: string; - /** - * Whether to prevent default event behavior - */ - preventDefault?: boolean; - /** - * Whether to stop event propagation - */ - stopPropagation?: boolean; - /** - * Debounce delay in milliseconds - */ - debounce?: number; - /** - * Throttle delay in milliseconds - */ - throttle?: number; -} -/** - * Component with event handlers - */ -export interface EventableSchema extends BaseSchema { - /** - * Event handlers configuration - */ - events?: EventHandler[]; - /** - * Click handler - */ - onClick?: EventHandler | string; - /** - * Change handler - */ - onChange?: EventHandler | string; - /** - * Submit handler - */ - onSubmit?: EventHandler | string; - /** - * Focus handler - */ - onFocus?: EventHandler | string; - /** - * Blur handler - */ - onBlur?: EventHandler | string; - /** - * Mouse enter handler - */ - onMouseEnter?: EventHandler | string; - /** - * Mouse leave handler - */ - onMouseLeave?: EventHandler | string; - /** - * Key down handler - */ - onKeyDown?: EventHandler | string; - /** - * Key up handler - */ - onKeyUp?: EventHandler | string; -} -/** - * Data fetching configuration - */ -export interface DataFetchConfig { - /** - * Data source API - */ - api: string | APIRequest; - /** - * Whether to fetch on mount - * @default true - */ - fetchOnMount?: boolean; - /** - * Polling interval in milliseconds - * If set, data will be refetched at this interval - */ - pollInterval?: number; - /** - * Dependencies for refetching - * Array of variable names to watch - */ - dependencies?: string[]; - /** - * Default data before fetch completes - */ - defaultData?: any; - /** - * Transform function for fetched data - * JavaScript expression or function name - */ - transform?: string; - /** - * Filter function for data - * JavaScript expression or function name - */ - filter?: string; - /** - * Sort configuration - */ - sort?: { - /** - * Field to sort by - */ - field: string; - /** - * Sort order - */ - order: 'asc' | 'desc'; - }; - /** - * Pagination configuration - */ - pagination?: { - /** - * Current page - */ - page?: number; - /** - * Page size - */ - pageSize?: number; - /** - * Whether pagination is enabled - */ - enabled?: boolean; - }; -} -/** - * Component with data fetching - */ -export interface DataFetchableSchema extends BaseSchema { - /** - * Data fetching configuration - */ - dataSource?: DataFetchConfig; - /** - * Loading state - */ - loading?: boolean; - /** - * Error state - */ - error?: string | null; - /** - * Fetched data - */ - data?: any; -} -/** - * Expression evaluation context - */ -export interface ExpressionContext { - /** - * Current component data - */ - data?: any; - /** - * Global application state - */ - state?: any; - /** - * Form values (when in form context) - */ - form?: any; - /** - * Current user information - */ - user?: any; - /** - * Environment variables - */ - env?: Record; - /** - * Utility functions - */ - utils?: Record; -} -/** - * Expression schema for dynamic values - */ -export interface ExpressionSchema { - /** - * Expression type - */ - type: 'expression'; - /** - * Expression string - * Supports ${} syntax for variable interpolation - */ - value: string; - /** - * Default value if expression fails - */ - defaultValue?: any; - /** - * Whether to watch and re-evaluate on context changes - * @default true - */ - reactive?: boolean; -} -/** - * Union type of all API schemas - */ -export type APISchema = EventableSchema | DataFetchableSchema | ExpressionSchema; diff --git a/packages/types/src/api.js b/packages/types/src/api.js deleted file mode 100644 index 8905abc7d..000000000 --- a/packages/types/src/api.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @object-ui/types - API and Event Schemas - * - * Type definitions for API integration and event handling. - * These schemas enable dynamic API calls and event-driven interactions. - * - * @module api - * @packageDocumentation - */ -export {}; diff --git a/packages/types/src/api.ts b/packages/types/src/api.ts index 03556e462..4e27964fd 100644 --- a/packages/types/src/api.ts +++ b/packages/types/src/api.ts @@ -428,7 +428,7 @@ export interface ExpressionContext { /** * Utility functions */ - utils?: Record; + utils?: Record any>; } /** diff --git a/packages/types/src/base.d.ts b/packages/types/src/base.d.ts deleted file mode 100644 index a42e7a244..000000000 --- a/packages/types/src/base.d.ts +++ /dev/null @@ -1,359 +0,0 @@ -/** - * @object-ui/types - Base Schema Types - * - * The foundational type definitions for the Object UI schema protocol. - * These types define the universal interface for all UI components. - * - * @module base - * @packageDocumentation - */ -/** - * Base schema interface that all component schemas extend. - * This is the fundamental building block of the Object UI protocol. - * - * @example - * ```typescript - * const schema: BaseSchema = { - * type: 'text', - * id: 'greeting', - * className: 'text-lg font-bold', - * data: { message: 'Hello World' } - * } - * ``` - */ -export interface BaseSchema { - /** - * Component type identifier. Determines which renderer to use. - * @example 'input', 'button', 'form', 'grid' - */ - type: string; - /** - * Unique identifier for the component instance. - * Used for state management, event handling, and React keys. - */ - id?: string; - /** - * Human-readable name for the component. - * Used for form field names, labels, and debugging. - */ - name?: string; - /** - * Display label for the component. - * Often used in forms, cards, and other UI elements. - */ - label?: string; - /** - * Descriptive text providing additional context. - * Typically rendered as help text below the component. - */ - description?: string; - /** - * Placeholder text for input components. - * Provides hints about expected input format or content. - */ - placeholder?: string; - /** - * Tailwind CSS classes to apply to the component. - * This is the primary styling mechanism in Object UI. - * @example 'bg-blue-500 text-white p-4 rounded-lg' - */ - className?: string; - /** - * Inline CSS styles as a JavaScript object. - * Use sparingly - prefer className with Tailwind. - * @example { backgroundColor: '#fff', padding: '16px' } - */ - style?: Record; - /** - * Arbitrary data attached to the component. - * Can be used for custom properties, state, or context. - */ - data?: any; - /** - * Child components or content. - * Can be a single component, array of components, or primitive values. - */ - body?: SchemaNode | SchemaNode[]; - /** - * Alternative name for children (React-style). - * Some components use 'children' instead of 'body'. - */ - children?: SchemaNode | SchemaNode[]; - /** - * Controls whether the component is visible. - * When false, component is not rendered (display: none). - * @default true - */ - visible?: boolean; - /** - * Expression for conditional visibility. - * Evaluated against the current data context. - * @example "${data.role === 'admin'}" - */ - visibleOn?: string; - /** - * Controls whether the component is hidden (but still rendered). - * When true, component is rendered but not visible (visibility: hidden). - * @default false - */ - hidden?: boolean; - /** - * Expression for conditional hiding. - * @example "${!data.isActive}" - */ - hiddenOn?: string; - /** - * Controls whether the component is disabled. - * Applies to interactive components like buttons and inputs. - * @default false - */ - disabled?: boolean; - /** - * Expression for conditional disabling. - * @example "${data.status === 'locked'}" - */ - disabledOn?: string; - /** - * Test ID for automated testing. - * Rendered as data-testid attribute. - */ - testId?: string; - /** - * Accessibility label for screen readers. - * Rendered as aria-label attribute. - */ - ariaLabel?: string; - /** - * Additional properties specific to the component type. - * This index signature allows type-specific extensions. - */ - [key: string]: any; -} -/** - * A schema node can be a full schema object or a primitive value. - * This union type supports both structured components and simple content. - * - * @example - * ```typescript - * const nodes: SchemaNode[] = [ - * { type: 'text', value: 'Hello' }, - * 'Plain string', - * { type: 'button', label: 'Click' } - * ] - * ``` - */ -export type SchemaNode = BaseSchema | string | number | boolean | null | undefined; -/** - * Component renderer function type. - * Accepts a schema and returns a rendered component. - * Framework-agnostic - can be React, Vue, or any other renderer. - */ -export interface ComponentRendererProps { - /** - * The schema object to render - */ - schema: TSchema; - /** - * Additional properties passed to the renderer - */ - [key: string]: any; -} -/** - * Input field configuration for component metadata. - * Describes what properties a component accepts in the designer/editor. - */ -export interface ComponentInput { - /** - * Property name (must match schema property) - */ - name: string; - /** - * Input control type - */ - type: 'string' | 'number' | 'boolean' | 'enum' | 'array' | 'object' | 'color' | 'date' | 'code' | 'file' | 'slot'; - /** - * Display label in the editor - */ - label?: string; - /** - * Default value for new instances - */ - defaultValue?: any; - /** - * Whether this property is required - */ - required?: boolean; - /** - * Enum options (for type='enum') - */ - enum?: string[] | { - label: string; - value: any; - }[]; - /** - * Help text or description - */ - description?: string; - /** - * Whether this is an advanced/expert option - */ - advanced?: boolean; - /** - * Specific input type (e.g., 'email', 'password' for string) - */ - inputType?: string; - /** - * Minimum value (for number/date) - */ - min?: number; - /** - * Maximum value (for number/date) - */ - max?: number; - /** - * Step value (for number) - */ - step?: number; - /** - * Placeholder text - */ - placeholder?: string; -} -/** - * Component metadata for registration and designer integration. - * Describes the component's capabilities, defaults, and documentation. - */ -export interface ComponentMeta { - /** - * Display name in designer/palette - */ - label?: string; - /** - * Icon name or SVG string - */ - icon?: string; - /** - * Category for grouping (e.g., 'Layout', 'Form', 'Data Display') - */ - category?: string; - /** - * Configurable properties - */ - inputs?: ComponentInput[]; - /** - * Default property values for new instances - */ - defaultProps?: Record; - /** - * Default children for container components - */ - defaultChildren?: SchemaNode[]; - /** - * Example configurations for documentation - */ - examples?: Record; - /** - * Whether the component can have children - */ - isContainer?: boolean; - /** - * Whether the component can be resized in the designer - */ - resizable?: boolean; - /** - * Resize constraints (which dimensions can be resized) - */ - resizeConstraints?: { - width?: boolean; - height?: boolean; - minWidth?: number; - maxWidth?: number; - minHeight?: number; - maxHeight?: number; - }; - /** - * Tags for search/filtering - */ - tags?: string[]; - /** - * Description for documentation - */ - description?: string; -} -/** - * Complete component configuration combining renderer and metadata. - */ -export interface ComponentConfig extends ComponentMeta { - /** - * Unique component type identifier - */ - type: string; - /** - * The component renderer (framework-specific) - */ - component: any; -} -/** - * Common HTML attributes that can be applied to components - */ -export interface HTMLAttributes { - id?: string; - className?: string; - style?: Record; - title?: string; - role?: string; - 'aria-label'?: string; - 'aria-describedby'?: string; - 'data-testid'?: string; -} -/** - * Event handler types - */ -export interface EventHandlers { - onClick?: (event?: any) => void | Promise; - onChange?: (value: any, event?: any) => void | Promise; - onSubmit?: (data: any, event?: any) => void | Promise; - onFocus?: (event?: any) => void; - onBlur?: (event?: any) => void; - onKeyDown?: (event?: any) => void; - onKeyUp?: (event?: any) => void; - onMouseEnter?: (event?: any) => void; - onMouseLeave?: (event?: any) => void; -} -/** - * Common style properties using Tailwind's semantic naming - */ -export interface StyleProps { - /** - * Padding (Tailwind scale: 0-96) - */ - padding?: number | string; - /** - * Margin (Tailwind scale: 0-96) - */ - margin?: number | string; - /** - * Gap between flex/grid items (Tailwind scale: 0-96) - */ - gap?: number | string; - /** - * Background color - */ - backgroundColor?: string; - /** - * Text color - */ - textColor?: string; - /** - * Border width - */ - borderWidth?: number | string; - /** - * Border color - */ - borderColor?: string; - /** - * Border radius - */ - borderRadius?: number | string; -} diff --git a/packages/types/src/base.js b/packages/types/src/base.js deleted file mode 100644 index 5c3d37ef7..000000000 --- a/packages/types/src/base.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @object-ui/types - Base Schema Types - * - * The foundational type definitions for the Object UI schema protocol. - * These types define the universal interface for all UI components. - * - * @module base - * @packageDocumentation - */ -export {}; diff --git a/packages/types/src/complex.d.ts b/packages/types/src/complex.d.ts deleted file mode 100644 index 894ef589a..000000000 --- a/packages/types/src/complex.d.ts +++ /dev/null @@ -1,432 +0,0 @@ -/** - * @object-ui/types - Complex Component Schemas - * - * Type definitions for advanced/composite components. - * - * @module complex - * @packageDocumentation - */ -import type { BaseSchema, SchemaNode } from './base'; -/** - * Kanban column - */ -export interface KanbanColumn { - /** - * Unique column identifier - */ - id: string; - /** - * Column title - */ - title: string; - /** - * Column cards/items - */ - items: KanbanCard[]; - /** - * Column color/variant - */ - color?: string; - /** - * Maximum number of cards allowed - */ - limit?: number; - /** - * Whether column is collapsed - */ - collapsed?: boolean; -} -/** - * Kanban card - */ -export interface KanbanCard { - /** - * Unique card identifier - */ - id: string; - /** - * Card title - */ - title: string; - /** - * Card description - */ - description?: string; - /** - * Card labels/tags - */ - labels?: string[]; - /** - * Card assignees - */ - assignees?: string[]; - /** - * Card due date - */ - dueDate?: string | Date; - /** - * Card priority - */ - priority?: 'low' | 'medium' | 'high' | 'critical'; - /** - * Custom card content - */ - content?: SchemaNode | SchemaNode[]; - /** - * Additional card data - */ - data?: any; -} -/** - * Kanban board component - */ -export interface KanbanSchema extends BaseSchema { - type: 'kanban'; - /** - * Kanban columns - */ - columns: KanbanColumn[]; - /** - * Enable drag and drop - * @default true - */ - draggable?: boolean; - /** - * Card move handler - */ - onCardMove?: (cardId: string, fromColumn: string, toColumn: string, position: number) => void; - /** - * Card click handler - */ - onCardClick?: (card: KanbanCard) => void; - /** - * Column add handler - */ - onColumnAdd?: (column: KanbanColumn) => void; - /** - * Card add handler - */ - onCardAdd?: (columnId: string, card: KanbanCard) => void; -} -/** - * Calendar view mode - */ -export type CalendarViewMode = 'month' | 'week' | 'day' | 'agenda'; -/** - * Calendar event - */ -export interface CalendarEvent { - /** - * Unique event identifier - */ - id: string; - /** - * Event title - */ - title: string; - /** - * Event description - */ - description?: string; - /** - * Event start date/time - */ - start: string | Date; - /** - * Event end date/time - */ - end: string | Date; - /** - * Whether event is all day - */ - allDay?: boolean; - /** - * Event color - */ - color?: string; - /** - * Additional event data - */ - data?: any; -} -/** - * Calendar view component - */ -export interface CalendarViewSchema extends BaseSchema { - type: 'calendar-view'; - /** - * Calendar events - */ - events: CalendarEvent[]; - /** - * Default view mode - * @default 'month' - */ - defaultView?: CalendarViewMode; - /** - * Controlled view mode - */ - view?: CalendarViewMode; - /** - * Default date - */ - defaultDate?: string | Date; - /** - * Controlled date - */ - date?: string | Date; - /** - * Available views - * @default ['month', 'week', 'day'] - */ - views?: CalendarViewMode[]; - /** - * Enable event creation - * @default false - */ - editable?: boolean; - /** - * Event click handler - */ - onEventClick?: (event: CalendarEvent) => void; - /** - * Event create handler - */ - onEventCreate?: (start: Date, end: Date) => void; - /** - * Event update handler - */ - onEventUpdate?: (event: CalendarEvent) => void; - /** - * Date change handler - */ - onDateChange?: (date: Date) => void; - /** - * View change handler - */ - onViewChange?: (view: CalendarViewMode) => void; -} -/** - * Filter operator - */ -export type FilterOperator = 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'starts_with' | 'ends_with' | 'greater_than' | 'less_than' | 'greater_than_or_equal' | 'less_than_or_equal' | 'is_empty' | 'is_not_empty' | 'in' | 'not_in'; -/** - * Filter condition - */ -export interface FilterCondition { - /** - * Field to filter - */ - field: string; - /** - * Filter operator - */ - operator: FilterOperator; - /** - * Filter value - */ - value?: any; -} -/** - * Filter group - */ -export interface FilterGroup { - /** - * Logical operator (AND/OR) - * @default 'and' - */ - operator: 'and' | 'or'; - /** - * Filter conditions or nested groups - */ - conditions: (FilterCondition | FilterGroup)[]; -} -/** - * Filter builder component - */ -export interface FilterBuilderSchema extends BaseSchema { - type: 'filter-builder'; - /** - * Available fields for filtering - */ - fields: FilterField[]; - /** - * Default filter configuration - */ - defaultValue?: FilterGroup; - /** - * Controlled filter value - */ - value?: FilterGroup; - /** - * Change handler - */ - onChange?: (filter: FilterGroup) => void; - /** - * Allow nested groups - * @default true - */ - allowGroups?: boolean; - /** - * Maximum nesting depth - * @default 3 - */ - maxDepth?: number; -} -/** - * Filter field definition - */ -export interface FilterField { - /** - * Field name/key - */ - name: string; - /** - * Field label - */ - label: string; - /** - * Field type - */ - type: 'string' | 'number' | 'date' | 'boolean' | 'select'; - /** - * Available operators for this field - */ - operators?: FilterOperator[]; - /** - * Options (for select type) - */ - options?: { - label: string; - value: any; - }[]; -} -/** - * Carousel item - */ -export interface CarouselItem { - /** - * Unique item identifier - */ - id?: string; - /** - * Item content - */ - content: SchemaNode | SchemaNode[]; -} -/** - * Carousel component - */ -export interface CarouselSchema extends BaseSchema { - type: 'carousel'; - /** - * Carousel items - */ - items: CarouselItem[]; - /** - * Auto-play interval (ms) - */ - autoPlay?: number; - /** - * Show navigation arrows - * @default true - */ - showArrows?: boolean; - /** - * Show pagination dots - * @default true - */ - showDots?: boolean; - /** - * Enable infinite loop - * @default true - */ - loop?: boolean; - /** - * Items visible at once - * @default 1 - */ - itemsPerView?: number; - /** - * Gap between items - */ - gap?: number; - /** - * Slide change handler - */ - onSlideChange?: (index: number) => void; -} -/** - * Chatbot message - */ -export interface ChatMessage { - /** - * Unique message identifier - */ - id: string; - /** - * Message role - */ - role: 'user' | 'assistant' | 'system'; - /** - * Message content - */ - content: string; - /** - * Message timestamp - */ - timestamp?: string | Date; - /** - * Message metadata - */ - metadata?: any; -} -/** - * Chatbot component - */ -export interface ChatbotSchema extends BaseSchema { - type: 'chatbot'; - /** - * Chat messages - */ - messages: ChatMessage[]; - /** - * Input placeholder - * @default 'Type a message...' - */ - placeholder?: string; - /** - * Whether chat is loading (thinking) - */ - loading?: boolean; - /** - * Message send handler - */ - onSendMessage?: (message: string) => void | Promise; - /** - * Show avatars - * @default true - */ - showAvatars?: boolean; - /** - * User avatar - */ - userAvatar?: string; - /** - * Assistant avatar - */ - assistantAvatar?: string; - /** - * Enable markdown rendering - * @default true - */ - markdown?: boolean; - /** - * Chat height - */ - height?: string | number; -} -/** - * Union type of all complex schemas - */ -export type ComplexSchema = KanbanSchema | CalendarViewSchema | FilterBuilderSchema | CarouselSchema | ChatbotSchema; diff --git a/packages/types/src/complex.js b/packages/types/src/complex.js deleted file mode 100644 index 08e9e16ea..000000000 --- a/packages/types/src/complex.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @object-ui/types - Complex Component Schemas - * - * Type definitions for advanced/composite components. - * - * @module complex - * @packageDocumentation - */ -export {}; diff --git a/packages/types/src/crud.d.ts b/packages/types/src/crud.d.ts deleted file mode 100644 index c7d61e9b2..000000000 --- a/packages/types/src/crud.d.ts +++ /dev/null @@ -1,456 +0,0 @@ -/** - * @object-ui/types - CRUD Component Schemas - * - * Type definitions for Create, Read, Update, Delete operations. - * These schemas enable building complete data management interfaces. - * - * @module crud - * @packageDocumentation - */ -import type { BaseSchema, SchemaNode } from './base'; -import type { FormField } from './form'; -import type { TableColumn } from './data-display'; -/** - * Action button configuration for CRUD operations - */ -export interface ActionSchema extends BaseSchema { - type: 'action'; - /** - * Action label - */ - label: string; - /** - * Action type/level - * @default 'default' - */ - level?: 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'default'; - /** - * Icon to display (lucide-react icon name) - */ - icon?: string; - /** - * Action variant - */ - variant?: 'default' | 'outline' | 'ghost' | 'link'; - /** - * Whether action is disabled - */ - disabled?: boolean; - /** - * Action type - */ - actionType?: 'button' | 'link' | 'dropdown'; - /** - * API endpoint to call - */ - api?: string; - /** - * HTTP method - * @default 'POST' - */ - method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; - /** - * Confirmation message before execution - */ - confirmText?: string; - /** - * Success message after execution - */ - successMessage?: string; - /** - * Whether to reload data after action - * @default true - */ - reload?: boolean; - /** - * Whether to close dialog/modal after action - * @default true - */ - close?: boolean; - /** - * Custom click handler - */ - onClick?: () => void | Promise; - /** - * Redirect URL after success - */ - redirect?: string; -} -/** - * CRUD operation configuration - */ -export interface CRUDOperation { - /** - * Operation type - */ - type: 'create' | 'read' | 'update' | 'delete' | 'export' | 'import' | 'custom'; - /** - * Operation label - */ - label?: string; - /** - * Operation icon - */ - icon?: string; - /** - * Whether operation is enabled - * @default true - */ - enabled?: boolean; - /** - * API endpoint for this operation - */ - api?: string; - /** - * HTTP method - */ - method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; - /** - * Confirmation message - */ - confirmText?: string; - /** - * Success message - */ - successMessage?: string; - /** - * Visibility condition - */ - visibleOn?: string; - /** - * Disabled condition - */ - disabledOn?: string; -} -/** - * Filter configuration for CRUD components - */ -export interface CRUDFilter { - /** - * Filter name (field name) - */ - name: string; - /** - * Filter label - */ - label?: string; - /** - * Filter type - */ - type?: 'input' | 'select' | 'date-picker' | 'date-range' | 'number-range'; - /** - * Filter operator - * @default 'equals' - */ - operator?: 'equals' | 'contains' | 'startsWith' | 'endsWith' | 'gt' | 'gte' | 'lt' | 'lte' | 'between' | 'in'; - /** - * Options for select filter - */ - options?: Array<{ - label: string; - value: string | number; - }>; - /** - * Placeholder text - */ - placeholder?: string; - /** - * Default value - */ - defaultValue?: any; -} -/** - * Toolbar configuration for CRUD components - */ -export interface CRUDToolbar { - /** - * Show create button - * @default true - */ - showCreate?: boolean; - /** - * Show refresh button - * @default true - */ - showRefresh?: boolean; - /** - * Show export button - * @default false - */ - showExport?: boolean; - /** - * Show import button - * @default false - */ - showImport?: boolean; - /** - * Show filter toggle - * @default true - */ - showFilter?: boolean; - /** - * Show search box - * @default true - */ - showSearch?: boolean; - /** - * Custom actions - */ - actions?: ActionSchema[]; -} -/** - * CRUD pagination configuration - */ -export interface CRUDPagination { - /** - * Whether pagination is enabled - * @default true - */ - enabled?: boolean; - /** - * Default page size - * @default 10 - */ - pageSize?: number; - /** - * Page size options - * @default [10, 20, 50, 100] - */ - pageSizeOptions?: number[]; - /** - * Show total count - * @default true - */ - showTotal?: boolean; - /** - * Show page size selector - * @default true - */ - showSizeChanger?: boolean; -} -/** - * Complete CRUD component - * Provides full Create, Read, Update, Delete functionality - */ -export interface CRUDSchema extends BaseSchema { - type: 'crud'; - /** - * CRUD title - */ - title?: string; - /** - * Resource name (singular) - * @example 'user', 'product', 'order' - */ - resource?: string; - /** - * API endpoint for list/search - */ - api?: string; - /** - * Table columns configuration - */ - columns: TableColumn[]; - /** - * Form fields for create/edit - */ - fields?: FormField[]; - /** - * Enabled operations - */ - operations?: { - create?: boolean | CRUDOperation; - read?: boolean | CRUDOperation; - update?: boolean | CRUDOperation; - delete?: boolean | CRUDOperation; - export?: boolean | CRUDOperation; - import?: boolean | CRUDOperation; - [key: string]: boolean | CRUDOperation | undefined; - }; - /** - * Toolbar configuration - */ - toolbar?: CRUDToolbar; - /** - * Filter configuration - */ - filters?: CRUDFilter[]; - /** - * Pagination configuration - */ - pagination?: CRUDPagination; - /** - * Default sort field - */ - defaultSort?: string; - /** - * Default sort order - * @default 'asc' - */ - defaultSortOrder?: 'asc' | 'desc'; - /** - * Row selection mode - */ - selectable?: boolean | 'single' | 'multiple'; - /** - * Batch actions for selected rows - */ - batchActions?: ActionSchema[]; - /** - * Row actions (displayed in each row) - */ - rowActions?: ActionSchema[]; - /** - * Custom empty state - */ - emptyState?: SchemaNode; - /** - * Whether to show loading state - * @default true - */ - loading?: boolean; - /** - * Custom loading component - */ - loadingComponent?: SchemaNode; - /** - * Table layout mode - * @default 'table' - */ - mode?: 'table' | 'grid' | 'list' | 'kanban'; - /** - * Grid columns (for grid mode) - * @default 3 - */ - gridColumns?: number; - /** - * Card template (for grid/list mode) - */ - cardTemplate?: SchemaNode; - /** - * Kanban columns (for kanban mode) - */ - kanbanColumns?: Array<{ - id: string; - title: string; - color?: string; - }>; - /** - * Kanban group field - */ - kanbanGroupField?: string; -} -/** - * Detail view component - * Displays detailed information about a single record - */ -export interface DetailSchema extends BaseSchema { - type: 'detail'; - /** - * Detail title - */ - title?: string; - /** - * API endpoint to fetch detail data - */ - api?: string; - /** - * Resource ID to display - */ - resourceId?: string | number; - /** - * Field groups for organized display - */ - groups?: Array<{ - title?: string; - description?: string; - fields: Array<{ - name: string; - label?: string; - type?: 'text' | 'image' | 'link' | 'badge' | 'date' | 'datetime' | 'json' | 'html' | 'custom'; - format?: string; - render?: SchemaNode; - }>; - }>; - /** - * Actions available in detail view - */ - actions?: ActionSchema[]; - /** - * Tabs for additional content - */ - tabs?: Array<{ - key: string; - label: string; - content: SchemaNode | SchemaNode[]; - }>; - /** - * Show back button - * @default true - */ - showBack?: boolean; - /** - * Custom back action - */ - onBack?: () => void; - /** - * Whether to show loading state - * @default true - */ - loading?: boolean; -} -/** - * CRUD Dialog/Modal component for CRUD operations - * Note: For general dialog usage, use DialogSchema from overlay module - */ -export interface CRUDDialogSchema extends BaseSchema { - type: 'crud-dialog'; - /** - * Dialog title - */ - title?: string; - /** - * Dialog description - */ - description?: string; - /** - * Dialog content - */ - content?: SchemaNode | SchemaNode[]; - /** - * Dialog size - * @default 'default' - */ - size?: 'sm' | 'default' | 'lg' | 'xl' | 'full'; - /** - * Dialog actions/buttons - */ - actions?: ActionSchema[]; - /** - * Whether dialog is open - */ - open?: boolean; - /** - * Close handler - */ - onClose?: () => void; - /** - * Whether clicking outside closes dialog - * @default true - */ - closeOnOutsideClick?: boolean; - /** - * Whether pressing Escape closes dialog - * @default true - */ - closeOnEscape?: boolean; - /** - * Show close button - * @default true - */ - showClose?: boolean; -} -/** - * Union type of all CRUD schemas - */ -export type CRUDComponentSchema = ActionSchema | CRUDSchema | DetailSchema | CRUDDialogSchema; diff --git a/packages/types/src/crud.js b/packages/types/src/crud.js deleted file mode 100644 index 13cd7f442..000000000 --- a/packages/types/src/crud.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @object-ui/types - CRUD Component Schemas - * - * Type definitions for Create, Read, Update, Delete operations. - * These schemas enable building complete data management interfaces. - * - * @module crud - * @packageDocumentation - */ -export {}; diff --git a/packages/types/src/data-display.d.ts b/packages/types/src/data-display.d.ts deleted file mode 100644 index 47f3a927a..000000000 --- a/packages/types/src/data-display.d.ts +++ /dev/null @@ -1,537 +0,0 @@ -/** - * @object-ui/types - Data Display Component Schemas - * - * Type definitions for components that display data and information. - * - * @module data-display - * @packageDocumentation - */ -import type { BaseSchema, SchemaNode } from './base'; -/** - * Alert component - */ -export interface AlertSchema extends BaseSchema { - type: 'alert'; - /** - * Alert title - */ - title?: string; - /** - * Alert description/message - */ - description?: string; - /** - * Alert variant - * @default 'default' - */ - variant?: 'default' | 'destructive'; - /** - * Alert icon - */ - icon?: string; - /** - * Whether alert is dismissible - */ - dismissible?: boolean; - /** - * Dismiss handler - */ - onDismiss?: () => void; - /** - * Child content - */ - children?: SchemaNode | SchemaNode[]; -} -/** - * Badge component - */ -export interface BadgeSchema extends BaseSchema { - type: 'badge'; - /** - * Badge text - */ - label?: string; - /** - * Badge variant - * @default 'default' - */ - variant?: 'default' | 'secondary' | 'destructive' | 'outline'; - /** - * Badge icon - */ - icon?: string; - /** - * Child content - */ - children?: SchemaNode | SchemaNode[]; -} -/** - * Avatar component - */ -export interface AvatarSchema extends BaseSchema { - type: 'avatar'; - /** - * Image source URL - */ - src?: string; - /** - * Alt text - */ - alt?: string; - /** - * Fallback text (initials) - */ - fallback?: string; - /** - * Avatar size - * @default 'default' - */ - size?: 'sm' | 'default' | 'lg' | 'xl'; - /** - * Avatar shape - * @default 'circle' - */ - shape?: 'circle' | 'square'; -} -/** - * List component - */ -export interface ListSchema extends BaseSchema { - type: 'list'; - /** - * List items - */ - items: ListItem[]; - /** - * Whether list is ordered - * @default false - */ - ordered?: boolean; - /** - * List item dividers - * @default false - */ - dividers?: boolean; - /** - * Dense/compact layout - * @default false - */ - dense?: boolean; -} -/** - * List item - */ -export interface ListItem { - /** - * Unique item identifier - */ - id?: string; - /** - * Item label/title - */ - label?: string; - /** - * Item description - */ - description?: string; - /** - * Item icon - */ - icon?: string; - /** - * Item avatar image - */ - avatar?: string; - /** - * Whether item is disabled - */ - disabled?: boolean; - /** - * Click handler - */ - onClick?: () => void; - /** - * Item content (schema nodes) - */ - content?: SchemaNode | SchemaNode[]; -} -/** - * Table column definition - */ -export interface TableColumn { - /** - * Column header text - */ - header: string; - /** - * Key to access data in row object - */ - accessorKey: string; - /** - * Header CSS class - */ - className?: string; - /** - * Cell CSS class - */ - cellClassName?: string; - /** - * Column width - */ - width?: string | number; - /** - * Whether column is sortable - * @default true - */ - sortable?: boolean; - /** - * Whether column is filterable - * @default true - */ - filterable?: boolean; - /** - * Whether column is resizable - * @default true - */ - resizable?: boolean; - /** - * Custom cell renderer function - */ - cell?: (value: any, row: any) => any; -} -/** - * Simple table component - */ -export interface TableSchema extends BaseSchema { - type: 'table'; - /** - * Table caption - */ - caption?: string; - /** - * Table columns - */ - columns: TableColumn[]; - /** - * Table data rows - */ - data: any[]; - /** - * Whether table has hover effect - * @default true - */ - hoverable?: boolean; - /** - * Whether table has striped rows - * @default false - */ - striped?: boolean; -} -/** - * Enterprise data table with advanced features - */ -export interface DataTableSchema extends BaseSchema { - type: 'data-table'; - /** - * Table caption - */ - caption?: string; - /** - * Table columns - */ - columns: TableColumn[]; - /** - * Table data rows - */ - data: any[]; - /** - * Enable pagination - * @default true - */ - pagination?: boolean; - /** - * Rows per page - * @default 10 - */ - pageSize?: number; - /** - * Enable search - * @default true - */ - searchable?: boolean; - /** - * Enable row selection - * @default false - */ - selectable?: boolean; - /** - * Enable column sorting - * @default true - */ - sortable?: boolean; - /** - * Enable CSV export - * @default false - */ - exportable?: boolean; - /** - * Show row actions (edit/delete) - * @default false - */ - rowActions?: boolean; - /** - * Enable column resizing - * @default true - */ - resizableColumns?: boolean; - /** - * Enable column reordering - * @default true - */ - reorderableColumns?: boolean; - /** - * Row edit handler - */ - onRowEdit?: (row: any) => void; - /** - * Row delete handler - */ - onRowDelete?: (row: any) => void; - /** - * Selection change handler - */ - onSelectionChange?: (selectedRows: any[]) => void; - /** - * Columns reorder handler - */ - onColumnsReorder?: (columns: TableColumn[]) => void; -} -/** - * Markdown renderer component - */ -export interface MarkdownSchema extends BaseSchema { - type: 'markdown'; - /** - * Markdown content - */ - content: string; - /** - * Whether to sanitize HTML - * @default true - */ - sanitize?: boolean; - /** - * Custom components for markdown elements - */ - components?: Record; -} -/** - * Tree view node - */ -export interface TreeNode { - /** - * Unique node identifier - */ - id: string; - /** - * Node label - */ - label: string; - /** - * Node icon - */ - icon?: string; - /** - * Whether node is expanded by default - * @default false - */ - defaultExpanded?: boolean; - /** - * Whether node is selectable - * @default true - */ - selectable?: boolean; - /** - * Child nodes - */ - children?: TreeNode[]; - /** - * Additional data - */ - data?: any; -} -/** - * Tree view component - */ -export interface TreeViewSchema extends BaseSchema { - type: 'tree-view'; - /** - * Tree data - */ - data: TreeNode[]; - /** - * Default expanded node IDs - */ - defaultExpandedIds?: string[]; - /** - * Default selected node IDs - */ - defaultSelectedIds?: string[]; - /** - * Controlled expanded node IDs - */ - expandedIds?: string[]; - /** - * Controlled selected node IDs - */ - selectedIds?: string[]; - /** - * Enable multi-selection - * @default false - */ - multiSelect?: boolean; - /** - * Show lines connecting nodes - * @default true - */ - showLines?: boolean; - /** - * Node select handler - */ - onSelectChange?: (selectedIds: string[]) => void; - /** - * Node expand handler - */ - onExpandChange?: (expandedIds: string[]) => void; -} -/** - * Chart type - */ -export type ChartType = 'line' | 'bar' | 'area' | 'pie' | 'donut' | 'radar' | 'scatter'; -/** - * Chart data series - */ -export interface ChartSeries { - /** - * Series name - */ - name: string; - /** - * Series data points - */ - data: number[]; - /** - * Series color - */ - color?: string; -} -/** - * Chart component - */ -export interface ChartSchema extends BaseSchema { - type: 'chart'; - /** - * Chart type - */ - chartType: ChartType; - /** - * Chart title - */ - title?: string; - /** - * Chart description - */ - description?: string; - /** - * X-axis labels/categories - */ - categories?: string[]; - /** - * Data series - */ - series: ChartSeries[]; - /** - * Chart height - */ - height?: string | number; - /** - * Chart width - */ - width?: string | number; - /** - * Show legend - * @default true - */ - showLegend?: boolean; - /** - * Show grid - * @default true - */ - showGrid?: boolean; - /** - * Enable animations - * @default true - */ - animate?: boolean; - /** - * Chart configuration (library-specific) - */ - config?: Record; -} -/** - * Timeline event - */ -export interface TimelineEvent { - /** - * Event unique identifier - */ - id?: string; - /** - * Event title - */ - title: string; - /** - * Event description - */ - description?: string; - /** - * Event date/time - */ - date: string | Date; - /** - * Event icon - */ - icon?: string; - /** - * Event color - */ - color?: string; - /** - * Event content - */ - content?: SchemaNode | SchemaNode[]; -} -/** - * Timeline component - */ -export interface TimelineSchema extends BaseSchema { - type: 'timeline'; - /** - * Timeline events - */ - events: TimelineEvent[]; - /** - * Timeline orientation - * @default 'vertical' - */ - orientation?: 'vertical' | 'horizontal'; - /** - * Timeline position (for vertical) - * @default 'left' - */ - position?: 'left' | 'right' | 'alternate'; -} -/** - * Union type of all data display schemas - */ -export type DataDisplaySchema = AlertSchema | BadgeSchema | AvatarSchema | ListSchema | TableSchema | DataTableSchema | MarkdownSchema | TreeViewSchema | ChartSchema | TimelineSchema; diff --git a/packages/types/src/data-display.js b/packages/types/src/data-display.js deleted file mode 100644 index 62d32f97b..000000000 --- a/packages/types/src/data-display.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @object-ui/types - Data Display Component Schemas - * - * Type definitions for components that display data and information. - * - * @module data-display - * @packageDocumentation - */ -export {}; diff --git a/packages/types/src/data.d.ts b/packages/types/src/data.d.ts deleted file mode 100644 index a4ef6ea45..000000000 --- a/packages/types/src/data.d.ts +++ /dev/null @@ -1,294 +0,0 @@ -/** - * @object-ui/types - Data Source Types - * - * Type definitions for data fetching and management. - * These interfaces define the universal adapter pattern for data access. - * - * @module data - * @packageDocumentation - */ -/** - * Query parameters for data fetching. - * Follows OData/REST conventions for universal compatibility. - */ -export interface QueryParams { - /** - * Fields to select (projection) - * @example ['id', 'name', 'email'] - */ - $select?: string[]; - /** - * Filter expression - * @example { age: { $gt: 18 }, status: 'active' } - */ - $filter?: Record; - /** - * Sort order - * @example { createdAt: 'desc', name: 'asc' } - */ - $orderby?: Record; - /** - * Number of records to skip (for pagination) - */ - $skip?: number; - /** - * Maximum number of records to return - */ - $top?: number; - /** - * Related entities to expand/include - * @example ['author', 'comments'] - */ - $expand?: string[]; - /** - * Search query (full-text search) - */ - $search?: string; - /** - * Total count of records (for pagination) - */ - $count?: boolean; - /** - * Additional custom parameters - */ - [key: string]: any; -} -/** - * Query result with pagination metadata - */ -export interface QueryResult { - /** - * Result data array - */ - data: T[]; - /** - * Total number of records (if requested) - */ - total?: number; - /** - * Current page number (1-indexed) - */ - page?: number; - /** - * Page size - */ - pageSize?: number; - /** - * Whether there are more records - */ - hasMore?: boolean; - /** - * Cursor for cursor-based pagination - */ - cursor?: string; - /** - * Additional metadata - */ - metadata?: Record; -} -/** - * Universal data source interface. - * This is the core abstraction that makes Object UI backend-agnostic. - * - * Implementations can connect to: - * - REST APIs - * - GraphQL endpoints - * - ObjectQL servers - * - Firebase/Supabase - * - Local arrays/JSON - * - Any data source - * - * @template T - The data type - * - * @example - * ```typescript - * class RestDataSource implements DataSource { - * async find(resource, params) { - * const response = await fetch(`/api/${resource}?${buildQuery(params)}`); - * return response.json(); - * } - * // ... other methods - * } - * ``` - */ -export interface DataSource { - /** - * Fetch multiple records. - * - * @param resource - Resource name (e.g., 'users', 'posts') - * @param params - Query parameters - * @returns Promise resolving to query result - */ - find(resource: string, params?: QueryParams): Promise>; - /** - * Fetch a single record by ID. - * - * @param resource - Resource name - * @param id - Record identifier - * @param params - Additional query parameters - * @returns Promise resolving to the record or null - */ - findOne(resource: string, id: string | number, params?: QueryParams): Promise; - /** - * Create a new record. - * - * @param resource - Resource name - * @param data - Record data - * @returns Promise resolving to the created record - */ - create(resource: string, data: Partial): Promise; - /** - * Update an existing record. - * - * @param resource - Resource name - * @param id - Record identifier - * @param data - Updated data (partial) - * @returns Promise resolving to the updated record - */ - update(resource: string, id: string | number, data: Partial): Promise; - /** - * Delete a record. - * - * @param resource - Resource name - * @param id - Record identifier - * @returns Promise resolving to true if successful - */ - delete(resource: string, id: string | number): Promise; - /** - * Execute a bulk operation (optional). - * - * @param resource - Resource name - * @param operation - Operation type - * @param data - Bulk data - * @returns Promise resolving to operation result - */ - bulk?(resource: string, operation: 'create' | 'update' | 'delete', data: Partial[]): Promise; -} -/** - * Data scope context for managing data state. - * Provides reactive data management within the UI. - */ -export interface DataScope { - /** - * Data source instance - */ - dataSource?: DataSource; - /** - * Current data - */ - data?: any; - /** - * Loading state - */ - loading?: boolean; - /** - * Error state - */ - error?: Error | string | null; - /** - * Refresh data - */ - refresh?: () => Promise; - /** - * Set data - */ - setData?: (data: any) => void; -} -/** - * Data context for component trees. - * Allows components to access and share data. - */ -export interface DataContext { - /** - * Named data scopes - */ - scopes: Record; - /** - * Register a data scope - */ - registerScope: (name: string, scope: DataScope) => void; - /** - * Get a data scope by name - */ - getScope: (name: string) => DataScope | undefined; - /** - * Remove a data scope - */ - removeScope: (name: string) => void; -} -/** - * Data binding configuration. - * Defines how a component's data is sourced and updated. - */ -export interface DataBinding { - /** - * Data source name - */ - source?: string; - /** - * Resource name - */ - resource?: string; - /** - * Query parameters - */ - params?: QueryParams; - /** - * Transform function for data - */ - transform?: (data: any) => any; - /** - * Auto-refresh interval (ms) - */ - refreshInterval?: number; - /** - * Cache data - */ - cache?: boolean; - /** - * Cache TTL (ms) - */ - cacheTTL?: number; -} -/** - * Validation error - */ -export interface ValidationError { - /** - * Field name - */ - field: string; - /** - * Error message - */ - message: string; - /** - * Error code - */ - code?: string; -} -/** - * API error response - */ -export interface APIError { - /** - * Error message - */ - message: string; - /** - * HTTP status code - */ - status?: number; - /** - * Error code - */ - code?: string; - /** - * Validation errors - */ - errors?: ValidationError[]; - /** - * Additional error data - */ - data?: any; -} diff --git a/packages/types/src/data.js b/packages/types/src/data.js deleted file mode 100644 index 17efeea15..000000000 --- a/packages/types/src/data.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @object-ui/types - Data Source Types - * - * Type definitions for data fetching and management. - * These interfaces define the universal adapter pattern for data access. - * - * @module data - * @packageDocumentation - */ -export {}; diff --git a/packages/types/src/disclosure.d.ts b/packages/types/src/disclosure.d.ts deleted file mode 100644 index 5670f3379..000000000 --- a/packages/types/src/disclosure.d.ts +++ /dev/null @@ -1,106 +0,0 @@ -/** - * @object-ui/types - Disclosure Component Schemas - * - * Type definitions for collapsible and expandable components. - * - * @module disclosure - * @packageDocumentation - */ -import type { BaseSchema, SchemaNode } from './base'; -/** - * Accordion item - */ -export interface AccordionItem { - /** - * Unique item identifier - */ - value: string; - /** - * Item title/trigger - */ - title: string; - /** - * Item content - */ - content: SchemaNode | SchemaNode[]; - /** - * Whether item is disabled - */ - disabled?: boolean; - /** - * Item icon - */ - icon?: string; -} -/** - * Accordion component - */ -export interface AccordionSchema extends BaseSchema { - type: 'accordion'; - /** - * Accordion items - */ - items: AccordionItem[]; - /** - * Accordion type - * @default 'single' - */ - accordionType?: 'single' | 'multiple'; - /** - * Whether items are collapsible - * @default true - */ - collapsible?: boolean; - /** - * Default expanded item values - */ - defaultValue?: string | string[]; - /** - * Controlled expanded item values - */ - value?: string | string[]; - /** - * Change handler - */ - onValueChange?: (value: string | string[]) => void; - /** - * Accordion variant - * @default 'default' - */ - variant?: 'default' | 'bordered' | 'separated'; -} -/** - * Collapsible component - */ -export interface CollapsibleSchema extends BaseSchema { - type: 'collapsible'; - /** - * Trigger content/label - */ - trigger: string | SchemaNode; - /** - * Collapsible content - */ - content: SchemaNode | SchemaNode[]; - /** - * Default open state - * @default false - */ - defaultOpen?: boolean; - /** - * Controlled open state - */ - open?: boolean; - /** - * Whether collapsible is disabled - */ - disabled?: boolean; - /** - * Open state change handler - */ - onOpenChange?: (open: boolean) => void; -} -/** - * Union type of all disclosure schemas - */ -export type DisclosureSchema = AccordionSchema | CollapsibleSchema; diff --git a/packages/types/src/disclosure.js b/packages/types/src/disclosure.js deleted file mode 100644 index b9bda76b7..000000000 --- a/packages/types/src/disclosure.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @object-ui/types - Disclosure Component Schemas - * - * Type definitions for collapsible and expandable components. - * - * @module disclosure - * @packageDocumentation - */ -export {}; diff --git a/packages/types/src/feedback.d.ts b/packages/types/src/feedback.d.ts deleted file mode 100644 index fff61755d..000000000 --- a/packages/types/src/feedback.d.ts +++ /dev/null @@ -1,158 +0,0 @@ -/** - * @object-ui/types - Feedback Component Schemas - * - * Type definitions for feedback and status indication components. - * - * @module feedback - * @packageDocumentation - */ -import type { BaseSchema } from './base'; -/** - * Loading/Spinner component - */ -export interface LoadingSchema extends BaseSchema { - type: 'loading'; - /** - * Loading text/message - */ - label?: string; - /** - * Spinner size - * @default 'default' - */ - size?: 'sm' | 'default' | 'lg'; - /** - * Spinner variant - * @default 'spinner' - */ - variant?: 'spinner' | 'dots' | 'pulse'; - /** - * Whether to show fullscreen overlay - * @default false - */ - fullscreen?: boolean; -} -/** - * Progress bar component - */ -export interface ProgressSchema extends BaseSchema { - type: 'progress'; - /** - * Progress value (0-100) - */ - value?: number; - /** - * Maximum value - * @default 100 - */ - max?: number; - /** - * Progress bar variant - * @default 'default' - */ - variant?: 'default' | 'success' | 'warning' | 'error'; - /** - * Show percentage label - * @default false - */ - showLabel?: boolean; - /** - * Progress bar size - * @default 'default' - */ - size?: 'sm' | 'default' | 'lg'; - /** - * Indeterminate/loading state - * @default false - */ - indeterminate?: boolean; -} -/** - * Skeleton loading placeholder - */ -export interface SkeletonSchema extends BaseSchema { - type: 'skeleton'; - /** - * Skeleton variant - * @default 'text' - */ - variant?: 'text' | 'circular' | 'rectangular'; - /** - * Width - */ - width?: string | number; - /** - * Height - */ - height?: string | number; - /** - * Number of lines (for text variant) - * @default 1 - */ - lines?: number; - /** - * Enable animation - * @default true - */ - animate?: boolean; -} -/** - * Toast notification (declarative schema) - */ -export interface ToastSchema extends BaseSchema { - type: 'toast'; - /** - * Toast title - */ - title?: string; - /** - * Toast description - */ - description?: string; - /** - * Toast variant - * @default 'default' - */ - variant?: 'default' | 'success' | 'warning' | 'error' | 'info'; - /** - * Auto-dismiss duration in milliseconds - * @default 5000 - */ - duration?: number; - /** - * Toast position - * @default 'bottom-right' - */ - position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'; - /** - * Action button - */ - action?: { - label: string; - onClick: () => void; - }; - /** - * Dismiss handler - */ - onDismiss?: () => void; -} -/** - * Toaster container (for toast management) - */ -export interface ToasterSchema extends BaseSchema { - type: 'toaster'; - /** - * Toast position - * @default 'bottom-right' - */ - position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'; - /** - * Maximum number of toasts to show - * @default 5 - */ - limit?: number; -} -/** - * Union type of all feedback schemas - */ -export type FeedbackSchema = LoadingSchema | ProgressSchema | SkeletonSchema | ToastSchema | ToasterSchema; diff --git a/packages/types/src/feedback.js b/packages/types/src/feedback.js deleted file mode 100644 index 7fdc3a2fd..000000000 --- a/packages/types/src/feedback.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @object-ui/types - Feedback Component Schemas - * - * Type definitions for feedback and status indication components. - * - * @module feedback - * @packageDocumentation - */ -export {}; diff --git a/packages/types/src/form.d.ts b/packages/types/src/form.d.ts deleted file mode 100644 index 038871615..000000000 --- a/packages/types/src/form.d.ts +++ /dev/null @@ -1,895 +0,0 @@ -/** - * @object-ui/types - Form Component Schemas - * - * Type definitions for form input and interactive components. - * - * @module form - * @packageDocumentation - */ -import type { BaseSchema, SchemaNode } from './base'; -/** - * Button component - */ -export interface ButtonSchema extends BaseSchema { - type: 'button'; - /** - * Button text label - */ - label?: string; - /** - * Button variant/style - * @default 'default' - */ - variant?: 'default' | 'secondary' | 'destructive' | 'outline' | 'ghost' | 'link'; - /** - * Button size - * @default 'default' - */ - size?: 'default' | 'sm' | 'lg' | 'icon'; - /** - * Whether button is disabled - */ - disabled?: boolean; - /** - * Whether button is in loading state - */ - loading?: boolean; - /** - * Icon to display (lucide-react icon name) - */ - icon?: string; - /** - * Icon position - * @default 'left' - */ - iconPosition?: 'left' | 'right'; - /** - * Click handler - */ - onClick?: () => void | Promise; - /** - * Button type - * @default 'button' - */ - buttonType?: 'button' | 'submit' | 'reset'; - /** - * Child components (for custom content) - */ - children?: SchemaNode | SchemaNode[]; -} -/** - * Text input component - */ -export interface InputSchema extends BaseSchema { - type: 'input'; - /** - * Field name for form submission - */ - name?: string; - /** - * Input label - */ - label?: string; - /** - * Placeholder text - */ - placeholder?: string; - /** - * Input type - * @default 'text' - */ - inputType?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search' | 'date' | 'time' | 'datetime-local'; - /** - * Default value - */ - defaultValue?: string | number; - /** - * Controlled value - */ - value?: string | number; - /** - * Whether field is required - */ - required?: boolean; - /** - * Whether field is disabled - */ - disabled?: boolean; - /** - * Whether field is readonly - */ - readOnly?: boolean; - /** - * Help text or description - */ - description?: string; - /** - * Error message - */ - error?: string; - /** - * Change handler - */ - onChange?: (value: string | number) => void; - /** - * Input wrapper CSS class - */ - wrapperClass?: string; - /** - * Minimum value (for number type) - */ - min?: number; - /** - * Maximum value (for number type) - */ - max?: number; - /** - * Step value (for number type) - */ - step?: number; - /** - * Maximum length - */ - maxLength?: number; - /** - * Pattern for validation - */ - pattern?: string; -} -/** - * Textarea component - */ -export interface TextareaSchema extends BaseSchema { - type: 'textarea'; - /** - * Field name for form submission - */ - name?: string; - /** - * Textarea label - */ - label?: string; - /** - * Placeholder text - */ - placeholder?: string; - /** - * Default value - */ - defaultValue?: string; - /** - * Controlled value - */ - value?: string; - /** - * Number of visible rows - */ - rows?: number; - /** - * Whether field is required - */ - required?: boolean; - /** - * Whether field is disabled - */ - disabled?: boolean; - /** - * Whether field is readonly - */ - readOnly?: boolean; - /** - * Help text or description - */ - description?: string; - /** - * Error message - */ - error?: string; - /** - * Change handler - */ - onChange?: (value: string) => void; - /** - * Maximum length - */ - maxLength?: number; -} -/** - * Select dropdown component - */ -export interface SelectSchema extends BaseSchema { - type: 'select'; - /** - * Field name for form submission - */ - name?: string; - /** - * Select label - */ - label?: string; - /** - * Placeholder text - */ - placeholder?: string; - /** - * Default selected value - */ - defaultValue?: string; - /** - * Controlled value - */ - value?: string; - /** - * Select options - */ - options: SelectOption[]; - /** - * Whether field is required - */ - required?: boolean; - /** - * Whether field is disabled - */ - disabled?: boolean; - /** - * Help text or description - */ - description?: string; - /** - * Error message - */ - error?: string; - /** - * Change handler - */ - onChange?: (value: string) => void; -} -/** - * Select option - */ -export interface SelectOption { - /** - * Option label (displayed to user) - */ - label: string; - /** - * Option value (submitted in form) - */ - value: string; - /** - * Whether option is disabled - */ - disabled?: boolean; - /** - * Option icon - */ - icon?: string; -} -/** - * Checkbox component - */ -export interface CheckboxSchema extends BaseSchema { - type: 'checkbox'; - /** - * Field name for form submission - */ - name?: string; - /** - * Checkbox label - */ - label?: string; - /** - * Default checked state - */ - defaultChecked?: boolean; - /** - * Controlled checked state - */ - checked?: boolean; - /** - * Whether checkbox is disabled - */ - disabled?: boolean; - /** - * Help text or description - */ - description?: string; - /** - * Error message - */ - error?: string; - /** - * Change handler - */ - onChange?: (checked: boolean) => void; -} -/** - * Radio group component - */ -export interface RadioGroupSchema extends BaseSchema { - type: 'radio-group'; - /** - * Field name for form submission - */ - name?: string; - /** - * Radio group label - */ - label?: string; - /** - * Default selected value - */ - defaultValue?: string; - /** - * Controlled value - */ - value?: string; - /** - * Radio options - */ - options: RadioOption[]; - /** - * Radio group orientation - * @default 'vertical' - */ - orientation?: 'horizontal' | 'vertical'; - /** - * Whether field is disabled - */ - disabled?: boolean; - /** - * Help text or description - */ - description?: string; - /** - * Error message - */ - error?: string; - /** - * Change handler - */ - onChange?: (value: string) => void; -} -/** - * Radio option - */ -export interface RadioOption { - /** - * Option label - */ - label: string; - /** - * Option value - */ - value: string; - /** - * Whether option is disabled - */ - disabled?: boolean; - /** - * Option description - */ - description?: string; -} -/** - * Switch/Toggle component - */ -export interface SwitchSchema extends BaseSchema { - type: 'switch'; - /** - * Field name for form submission - */ - name?: string; - /** - * Switch label - */ - label?: string; - /** - * Default checked state - */ - defaultChecked?: boolean; - /** - * Controlled checked state - */ - checked?: boolean; - /** - * Whether switch is disabled - */ - disabled?: boolean; - /** - * Help text or description - */ - description?: string; - /** - * Change handler - */ - onChange?: (checked: boolean) => void; -} -/** - * Toggle button component - */ -export interface ToggleSchema extends BaseSchema { - type: 'toggle'; - /** - * Toggle label - */ - label?: string; - /** - * Default pressed state - */ - defaultPressed?: boolean; - /** - * Controlled pressed state - */ - pressed?: boolean; - /** - * Whether toggle is disabled - */ - disabled?: boolean; - /** - * Toggle variant - * @default 'default' - */ - variant?: 'default' | 'outline'; - /** - * Toggle size - * @default 'default' - */ - size?: 'default' | 'sm' | 'lg'; - /** - * Change handler - */ - onChange?: (pressed: boolean) => void; - /** - * Child content - */ - children?: SchemaNode | SchemaNode[]; -} -/** - * Slider component - */ -export interface SliderSchema extends BaseSchema { - type: 'slider'; - /** - * Field name for form submission - */ - name?: string; - /** - * Slider label - */ - label?: string; - /** - * Default value - */ - defaultValue?: number[]; - /** - * Controlled value - */ - value?: number[]; - /** - * Minimum value - * @default 0 - */ - min?: number; - /** - * Maximum value - * @default 100 - */ - max?: number; - /** - * Step increment - * @default 1 - */ - step?: number; - /** - * Whether slider is disabled - */ - disabled?: boolean; - /** - * Help text or description - */ - description?: string; - /** - * Change handler - */ - onChange?: (value: number[]) => void; -} -/** - * File upload component - */ -export interface FileUploadSchema extends BaseSchema { - type: 'file-upload'; - /** - * Field name for form submission - */ - name?: string; - /** - * Upload label - */ - label?: string; - /** - * Accepted file types - * @example 'image/*', '.pdf,.doc' - */ - accept?: string; - /** - * Allow multiple files - * @default false - */ - multiple?: boolean; - /** - * Maximum file size in bytes - */ - maxSize?: number; - /** - * Maximum number of files (for multiple) - */ - maxFiles?: number; - /** - * Whether field is disabled - */ - disabled?: boolean; - /** - * Help text or description - */ - description?: string; - /** - * Error message - */ - error?: string; - /** - * Change handler (receives FileList or File[]) - */ - onChange?: (files: FileList | File[]) => void; -} -/** - * Date picker component - */ -export interface DatePickerSchema extends BaseSchema { - type: 'date-picker'; - /** - * Field name for form submission - */ - name?: string; - /** - * Date picker label - */ - label?: string; - /** - * Placeholder text - */ - placeholder?: string; - /** - * Default value (Date object or ISO string) - */ - defaultValue?: Date | string; - /** - * Controlled value - */ - value?: Date | string; - /** - * Minimum selectable date - */ - minDate?: Date | string; - /** - * Maximum selectable date - */ - maxDate?: Date | string; - /** - * Date format - * @default 'PPP' - */ - format?: string; - /** - * Whether field is disabled - */ - disabled?: boolean; - /** - * Help text or description - */ - description?: string; - /** - * Error message - */ - error?: string; - /** - * Change handler - */ - onChange?: (date: Date | undefined) => void; -} -/** - * Calendar component - */ -export interface CalendarSchema extends BaseSchema { - type: 'calendar'; - /** - * Default selected date(s) - */ - defaultValue?: Date | Date[]; - /** - * Controlled selected date(s) - */ - value?: Date | Date[]; - /** - * Selection mode - * @default 'single' - */ - mode?: 'single' | 'multiple' | 'range'; - /** - * Minimum selectable date - */ - minDate?: Date | string; - /** - * Maximum selectable date - */ - maxDate?: Date | string; - /** - * Whether calendar is disabled - */ - disabled?: boolean; - /** - * Change handler - */ - onChange?: (date: Date | Date[] | undefined) => void; -} -/** - * Input OTP component - */ -export interface InputOTPSchema extends BaseSchema { - type: 'input-otp'; - /** - * Field name for form submission - */ - name?: string; - /** - * OTP input label - */ - label?: string; - /** - * Number of OTP digits - * @default 6 - */ - length?: number; - /** - * Default value - */ - defaultValue?: string; - /** - * Controlled value - */ - value?: string; - /** - * Whether field is disabled - */ - disabled?: boolean; - /** - * Help text or description - */ - description?: string; - /** - * Error message - */ - error?: string; - /** - * Change handler - */ - onChange?: (value: string) => void; - /** - * Complete handler (called when all digits filled) - */ - onComplete?: (value: string) => void; -} -/** - * Form validation rule - */ -export interface ValidationRule { - /** - * Required field validation - */ - required?: string | boolean; - /** - * Minimum length validation - */ - minLength?: { - value: number; - message: string; - }; - /** - * Maximum length validation - */ - maxLength?: { - value: number; - message: string; - }; - /** - * Minimum value validation (for numbers) - */ - min?: { - value: number; - message: string; - }; - /** - * Maximum value validation (for numbers) - */ - max?: { - value: number; - message: string; - }; - /** - * Pattern validation (regex) - */ - pattern?: { - value: string | RegExp; - message: string; - }; - /** - * Custom validation function - * @param value - The field value to validate - * @returns true if valid, false or error message if invalid - */ - validate?: (value: string | number | boolean | null | undefined) => boolean | string | Promise; -} -/** - * Form field condition for conditional rendering - */ -export interface FieldCondition { - /** - * Field to watch - */ - field: string; - /** - * Show when field equals this value - */ - equals?: any; - /** - * Show when field does not equal this value - */ - notEquals?: any; - /** - * Show when field value is in this array - */ - in?: any[]; - /** - * Custom condition function - */ - custom?: (formData: any) => boolean; -} -/** - * Form field configuration - */ -export interface FormField { - /** - * Unique field identifier - */ - id?: string; - /** - * Field name for form submission - */ - name: string; - /** - * Field label - */ - label?: string; - /** - * Field description - */ - description?: string; - /** - * Field type/component - */ - type?: string; - /** - * Input type (for input fields) - */ - inputType?: string; - /** - * Whether field is required - */ - required?: boolean; - /** - * Whether field is disabled - */ - disabled?: boolean; - /** - * Placeholder text - */ - placeholder?: string; - /** - * Select options (for select/radio) - */ - options?: SelectOption[] | RadioOption[]; - /** - * Validation rules - */ - validation?: ValidationRule; - /** - * Conditional rendering - */ - condition?: FieldCondition; - /** - * Additional field-specific props - */ - [key: string]: any; -} -/** - * Complete form component - */ -export interface FormSchema extends BaseSchema { - type: 'form'; - /** - * Form fields configuration - */ - fields?: FormField[]; - /** - * Default form values - */ - defaultValues?: Record; - /** - * Submit button label - * @default 'Submit' - */ - submitLabel?: string; - /** - * Cancel button label - * @default 'Cancel' - */ - cancelLabel?: string; - /** - * Show cancel button - * @default false - */ - showCancel?: boolean; - /** - * Form layout - * @default 'vertical' - */ - layout?: 'vertical' | 'horizontal'; - /** - * Number of columns for multi-column layout - * @default 1 - */ - columns?: number; - /** - * Validation mode - * @default 'onSubmit' - */ - validationMode?: 'onSubmit' | 'onBlur' | 'onChange' | 'onTouched' | 'all'; - /** - * Reset form after successful submission - * @default false - */ - resetOnSubmit?: boolean; - /** - * Whether form is disabled - */ - disabled?: boolean; - /** - * Submit handler - */ - onSubmit?: (data: Record) => void | Promise; - /** - * Change handler (called on any field change) - */ - onChange?: (data: Record) => void; - /** - * Cancel handler - */ - onCancel?: () => void; - /** - * Show form action buttons - * @default true - */ - showActions?: boolean; - /** - * Field container CSS class - */ - fieldContainerClass?: string; - /** - * Child components (alternative to fields array) - */ - children?: SchemaNode | SchemaNode[]; -} -/** - * Union type of all form schemas - */ -export type FormComponentSchema = ButtonSchema | InputSchema | TextareaSchema | SelectSchema | CheckboxSchema | RadioGroupSchema | SwitchSchema | ToggleSchema | SliderSchema | FileUploadSchema | DatePickerSchema | CalendarSchema | InputOTPSchema | FormSchema; diff --git a/packages/types/src/form.js b/packages/types/src/form.js deleted file mode 100644 index 781ba3054..000000000 --- a/packages/types/src/form.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @object-ui/types - Form Component Schemas - * - * Type definitions for form input and interactive components. - * - * @module form - * @packageDocumentation - */ -export {}; diff --git a/packages/types/src/index.d.ts b/packages/types/src/index.d.ts deleted file mode 100644 index cf10619e6..000000000 --- a/packages/types/src/index.d.ts +++ /dev/null @@ -1,102 +0,0 @@ -/** - * @object-ui/types - * - * Pure TypeScript type definitions for Object UI - The Protocol Layer. - * - * This package contains ZERO runtime dependencies and defines the complete - * JSON schema protocol for the Object UI ecosystem. - * - * ## Philosophy - * - * Object UI follows a "Schema First" approach where: - * 1. Types define the protocol (this package) - * 2. Core implements the engine (@object-ui/core) - * 3. React provides the framework bindings (@object-ui/react) - * 4. Components provide the UI implementation (@object-ui/components) - * - * ## Design Principles - * - * - **Protocol Agnostic**: Works with any backend (REST, GraphQL, ObjectQL) - * - **Framework Agnostic**: Types can be used with React, Vue, or vanilla JS - * - **Zero Dependencies**: Pure TypeScript with no runtime dependencies - * - **Tailwind Native**: Designed for Tailwind CSS styling via className - * - **Type Safe**: Full TypeScript support with strict typing - * - * ## Usage - * - * ```typescript - * import type { InputSchema, FormSchema, ButtonSchema } from '@object-ui/types'; - * - * const loginForm: FormSchema = { - * type: 'form', - * fields: [ - * { name: 'email', type: 'input', inputType: 'email', required: true }, - * { name: 'password', type: 'input', inputType: 'password', required: true } - * ] - * }; - * ``` - * - * @packageDocumentation - */ -export type { BaseSchema, SchemaNode, ComponentRendererProps, ComponentInput, ComponentMeta, ComponentConfig, HTMLAttributes, EventHandlers, StyleProps, } from './base'; -export type { DivSchema, SpanSchema, TextSchema, ImageSchema, IconSchema, SeparatorSchema, ContainerSchema, FlexSchema, GridSchema, CardSchema, TabsSchema, TabItem, ScrollAreaSchema, ResizableSchema, ResizablePanel, LayoutSchema, PageSchema, } from './layout'; -export type { ButtonSchema, InputSchema, TextareaSchema, SelectSchema, SelectOption, CheckboxSchema, RadioGroupSchema, RadioOption, SwitchSchema, ToggleSchema, SliderSchema, FileUploadSchema, DatePickerSchema, CalendarSchema, InputOTPSchema, ValidationRule, FieldCondition, FormField, FormSchema, FormComponentSchema, } from './form'; -export type { AlertSchema, BadgeSchema, AvatarSchema, ListSchema, ListItem, TableColumn, TableSchema, DataTableSchema, MarkdownSchema, TreeNode, TreeViewSchema, ChartType, ChartSeries, ChartSchema, TimelineEvent, TimelineSchema, DataDisplaySchema, } from './data-display'; -export type { LoadingSchema, ProgressSchema, SkeletonSchema, ToastSchema, ToasterSchema, FeedbackSchema, } from './feedback'; -export type { AccordionItem, AccordionSchema, CollapsibleSchema, DisclosureSchema, } from './disclosure'; -export type { OverlayPosition, OverlayAlignment, DialogSchema, AlertDialogSchema, SheetSchema, DrawerSchema, PopoverSchema, TooltipSchema, HoverCardSchema, MenuItem, DropdownMenuSchema, ContextMenuSchema, OverlaySchema, } from './overlay'; -export type { NavLink, HeaderBarSchema, SidebarSchema, BreadcrumbItem, BreadcrumbSchema, PaginationSchema, NavigationSchema, } from './navigation'; -export type { KanbanColumn, KanbanCard, KanbanSchema, CalendarViewMode, CalendarEvent, CalendarViewSchema, FilterOperator, FilterCondition, FilterGroup, FilterBuilderSchema, FilterField, CarouselItem, CarouselSchema, ChatMessage, ChatbotSchema, ComplexSchema, } from './complex'; -export type { QueryParams, QueryResult, DataSource, DataScope, DataContext, DataBinding, ValidationError, APIError, } from './data'; -export type { ActionSchema, CRUDOperation, CRUDFilter, CRUDToolbar, CRUDPagination, CRUDSchema, DetailSchema, CRUDDialogSchema, CRUDComponentSchema, } from './crud'; -export type { HTTPMethod, APIRequest, APIConfig, EventHandler, EventableSchema, DataFetchConfig, DataFetchableSchema, ExpressionContext, ExpressionSchema, APISchema, } from './api'; -import type { BaseSchema, SchemaNode } from './base'; -import type { LayoutSchema } from './layout'; -import type { FormComponentSchema } from './form'; -import type { DataDisplaySchema } from './data-display'; -import type { FeedbackSchema } from './feedback'; -import type { DisclosureSchema } from './disclosure'; -import type { OverlaySchema } from './overlay'; -import type { NavigationSchema } from './navigation'; -import type { ComplexSchema } from './complex'; -import type { CRUDComponentSchema } from './crud'; -/** - * Union of all component schemas. - * Use this for generic component rendering where the type is determined at runtime. - */ -export type AnySchema = BaseSchema | LayoutSchema | FormComponentSchema | DataDisplaySchema | FeedbackSchema | DisclosureSchema | OverlaySchema | NavigationSchema | ComplexSchema | CRUDComponentSchema; -/** - * Utility type to extract the schema type from a type string. - * Useful for type narrowing in renderers. - * - * @example - * ```typescript - * function renderComponent(schema: SchemaByType) { - * // schema is now typed based on the type string - * } - * ``` - */ -export type SchemaByType = Extract; -/** - * Utility type to make all properties optional except the type. - * Useful for partial schema definitions in editors. - */ -export type PartialSchema = { - type: T['type']; -} & Partial>; -/** - * Schema with required children (for container components). - */ -export type ContainerSchemaWithChildren = BaseSchema & { - children: SchemaNode | SchemaNode[]; -}; -/** - * Version information - */ -export declare const VERSION = "0.1.0"; -/** - * Schema version for compatibility checking - */ -export declare const SCHEMA_VERSION = "1.0.0"; diff --git a/packages/types/src/index.js b/packages/types/src/index.js deleted file mode 100644 index 7c33b7ae7..000000000 --- a/packages/types/src/index.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @object-ui/types - * - * Pure TypeScript type definitions for Object UI - The Protocol Layer. - * - * This package contains ZERO runtime dependencies and defines the complete - * JSON schema protocol for the Object UI ecosystem. - * - * ## Philosophy - * - * Object UI follows a "Schema First" approach where: - * 1. Types define the protocol (this package) - * 2. Core implements the engine (@object-ui/core) - * 3. React provides the framework bindings (@object-ui/react) - * 4. Components provide the UI implementation (@object-ui/components) - * - * ## Design Principles - * - * - **Protocol Agnostic**: Works with any backend (REST, GraphQL, ObjectQL) - * - **Framework Agnostic**: Types can be used with React, Vue, or vanilla JS - * - **Zero Dependencies**: Pure TypeScript with no runtime dependencies - * - **Tailwind Native**: Designed for Tailwind CSS styling via className - * - **Type Safe**: Full TypeScript support with strict typing - * - * ## Usage - * - * ```typescript - * import type { InputSchema, FormSchema, ButtonSchema } from '@object-ui/types'; - * - * const loginForm: FormSchema = { - * type: 'form', - * fields: [ - * { name: 'email', type: 'input', inputType: 'email', required: true }, - * { name: 'password', type: 'input', inputType: 'password', required: true } - * ] - * }; - * ``` - * - * @packageDocumentation - */ -/** - * Version information - */ -export const VERSION = '0.1.0'; -/** - * Schema version for compatibility checking - */ -export const SCHEMA_VERSION = '1.0.0'; diff --git a/packages/types/src/layout.d.ts b/packages/types/src/layout.d.ts deleted file mode 100644 index 7f99e063d..000000000 --- a/packages/types/src/layout.d.ts +++ /dev/null @@ -1,380 +0,0 @@ -/** - * @object-ui/types - Layout Component Schemas - * - * Type definitions for layout and container components. - * These components organize and structure other components. - * - * @module layout - * @packageDocumentation - */ -import type { BaseSchema, SchemaNode } from './base'; -/** - * Basic HTML div container - */ -export interface DivSchema extends BaseSchema { - type: 'div'; - /** - * Child components - */ - children?: SchemaNode | SchemaNode[]; -} -/** - * Text span component for inline text - */ -export interface SpanSchema extends BaseSchema { - type: 'span'; - /** - * Text content - */ - value?: string; - /** - * Child components - */ - children?: SchemaNode | SchemaNode[]; -} -/** - * Text display component - */ -export interface TextSchema extends BaseSchema { - type: 'text'; - /** - * Text content to display - */ - value?: string; - /** - * Text variant/style - * @default 'body' - */ - variant?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'body' | 'caption' | 'overline'; - /** - * Text alignment - */ - align?: 'left' | 'center' | 'right' | 'justify'; -} -/** - * Image component - */ -export interface ImageSchema extends BaseSchema { - type: 'image'; - /** - * Image source URL - */ - src: string; - /** - * Alt text for accessibility - */ - alt?: string; - /** - * Image width - */ - width?: string | number; - /** - * Image height - */ - height?: string | number; - /** - * Object fit property - */ - objectFit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down'; -} -/** - * Icon component - */ -export interface IconSchema extends BaseSchema { - type: 'icon'; - /** - * Icon name (lucide-react icon name) - */ - name: string; - /** - * Icon size in pixels - * @default 24 - */ - size?: number; - /** - * Icon color - */ - color?: string; -} -/** - * Separator/Divider component - */ -export interface SeparatorSchema extends BaseSchema { - type: 'separator'; - /** - * Orientation of the separator - * @default 'horizontal' - */ - orientation?: 'horizontal' | 'vertical'; - /** - * Whether to add decorative content - */ - decorative?: boolean; -} -/** - * Generic container component - */ -export interface ContainerSchema extends BaseSchema { - type: 'container'; - /** - * Max width constraint - * @default 'lg' - */ - maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full' | false; - /** - * Center the container - * @default true - */ - centered?: boolean; - /** - * Padding - */ - padding?: number; - /** - * Child components - */ - children?: SchemaNode | SchemaNode[]; -} -/** - * Flexbox layout component - */ -export interface FlexSchema extends BaseSchema { - type: 'flex'; - /** - * Flex direction - * @default 'row' - */ - direction?: 'row' | 'col' | 'row-reverse' | 'col-reverse'; - /** - * Justify content alignment - * @default 'start' - */ - justify?: 'start' | 'end' | 'center' | 'between' | 'around' | 'evenly'; - /** - * Align items - * @default 'center' - */ - align?: 'start' | 'end' | 'center' | 'baseline' | 'stretch'; - /** - * Gap between items (Tailwind scale 0-8) - * @default 2 - */ - gap?: number; - /** - * Allow items to wrap - * @default false - */ - wrap?: boolean; - /** - * Child components - */ - children?: SchemaNode | SchemaNode[]; -} -/** - * CSS Grid layout component - */ -export interface GridSchema extends BaseSchema { - type: 'grid'; - /** - * Number of columns (responsive) - * Can be number or object: { xs: 1, sm: 2, md: 3, lg: 4 } - * @default 3 - */ - columns?: number | Record; - /** - * Gap between items (Tailwind scale 0-8) - * @default 4 - */ - gap?: number; - /** - * Child components - */ - children?: SchemaNode | SchemaNode[]; -} -/** - * Card component - */ -export interface CardSchema extends BaseSchema { - type: 'card'; - /** - * Card title - */ - title?: string; - /** - * Card description - */ - description?: string; - /** - * Card header content - */ - header?: SchemaNode | SchemaNode[]; - /** - * Card body/content - */ - content?: SchemaNode | SchemaNode[]; - /** - * Card footer content - */ - footer?: SchemaNode | SchemaNode[]; - /** - * Variant style - * @default 'default' - */ - variant?: 'default' | 'outline' | 'ghost'; - /** - * Whether the card is hoverable - * @default false - */ - hoverable?: boolean; - /** - * Whether the card is clickable - * @default false - */ - clickable?: boolean; - /** - * Click handler - */ - onClick?: () => void; -} -/** - * Tabs component - */ -export interface TabsSchema extends BaseSchema { - type: 'tabs'; - /** - * Default active tab value - */ - defaultValue?: string; - /** - * Controlled active tab value - */ - value?: string; - /** - * Tabs orientation - * @default 'horizontal' - */ - orientation?: 'horizontal' | 'vertical'; - /** - * Tab items configuration - */ - items: TabItem[]; - /** - * Change handler - */ - onValueChange?: (value: string) => void; -} -/** - * Individual tab item - */ -export interface TabItem { - /** - * Unique tab identifier - */ - value: string; - /** - * Tab label - */ - label: string; - /** - * Tab icon - */ - icon?: string; - /** - * Whether tab is disabled - */ - disabled?: boolean; - /** - * Tab content - */ - content: SchemaNode | SchemaNode[]; -} -/** - * Scroll area component - */ -export interface ScrollAreaSchema extends BaseSchema { - type: 'scroll-area'; - /** - * Height of the scroll container - */ - height?: string | number; - /** - * Width of the scroll container - */ - width?: string | number; - /** - * Scrollbar orientation - * @default 'vertical' - */ - orientation?: 'vertical' | 'horizontal' | 'both'; - /** - * Child components - */ - children?: SchemaNode | SchemaNode[]; -} -/** - * Resizable panels component - */ -export interface ResizableSchema extends BaseSchema { - type: 'resizable'; - /** - * Direction of resizable panels - * @default 'horizontal' - */ - direction?: 'horizontal' | 'vertical'; - /** - * Resizable panels - */ - panels: ResizablePanel[]; -} -/** - * Individual resizable panel - */ -export interface ResizablePanel { - /** - * Unique panel identifier - */ - id: string; - /** - * Default size (percentage 0-100) - */ - defaultSize?: number; - /** - * Minimum size (percentage 0-100) - */ - minSize?: number; - /** - * Maximum size (percentage 0-100) - */ - maxSize?: number; - /** - * Panel content - */ - content: SchemaNode | SchemaNode[]; -} -/** - * Page layout component - * Top-level container for a page route - */ -export interface PageSchema extends BaseSchema { - type: 'page'; - /** - * Page title - */ - title?: string; - /** - * Page description - */ - description?: string; - /** - * Main content array - */ - body?: SchemaNode[]; - /** - * Alternative content prop - */ - children?: SchemaNode | SchemaNode[]; -} -/** - * Union type of all layout schemas - */ -export type LayoutSchema = DivSchema | SpanSchema | TextSchema | ImageSchema | IconSchema | SeparatorSchema | ContainerSchema | FlexSchema | GridSchema | CardSchema | TabsSchema | ScrollAreaSchema | ResizableSchema | PageSchema; diff --git a/packages/types/src/layout.js b/packages/types/src/layout.js deleted file mode 100644 index 1bb63acdc..000000000 --- a/packages/types/src/layout.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @object-ui/types - Layout Component Schemas - * - * Type definitions for layout and container components. - * These components organize and structure other components. - * - * @module layout - * @packageDocumentation - */ -export {}; diff --git a/packages/types/src/navigation.d.ts b/packages/types/src/navigation.d.ts deleted file mode 100644 index 6440a1741..000000000 --- a/packages/types/src/navigation.d.ts +++ /dev/null @@ -1,223 +0,0 @@ -/** - * @object-ui/types - Navigation Component Schemas - * - * Type definitions for navigation and menu components. - * - * @module navigation - * @packageDocumentation - */ -import type { BaseSchema, SchemaNode } from './base'; -/** - * Navigation link - */ -export interface NavLink { - /** - * Link label - */ - label: string; - /** - * Link URL/href - */ - href: string; - /** - * Link icon - */ - icon?: string; - /** - * Whether link is active - */ - active?: boolean; - /** - * Whether link is disabled - */ - disabled?: boolean; - /** - * Submenu links - */ - children?: NavLink[]; - /** - * Badge content - */ - badge?: string | number; -} -/** - * Header bar component - */ -export interface HeaderBarSchema extends BaseSchema { - type: 'header-bar'; - /** - * Header title/brand - */ - title?: string; - /** - * Brand logo image URL - */ - logo?: string; - /** - * Navigation links - */ - nav?: NavLink[]; - /** - * Left side content - */ - left?: SchemaNode | SchemaNode[]; - /** - * Center content - */ - center?: SchemaNode | SchemaNode[]; - /** - * Right side content - */ - right?: SchemaNode | SchemaNode[]; - /** - * Whether header is sticky - * @default true - */ - sticky?: boolean; - /** - * Header height - */ - height?: string | number; - /** - * Header variant - * @default 'default' - */ - variant?: 'default' | 'bordered' | 'floating'; -} -/** - * Sidebar component - */ -export interface SidebarSchema extends BaseSchema { - type: 'sidebar'; - /** - * Sidebar title - */ - title?: string; - /** - * Navigation links - */ - nav?: NavLink[]; - /** - * Sidebar content (alternative to nav) - */ - content?: SchemaNode | SchemaNode[]; - /** - * Footer content - */ - footer?: SchemaNode | SchemaNode[]; - /** - * Sidebar position - * @default 'left' - */ - position?: 'left' | 'right'; - /** - * Whether sidebar is collapsible - * @default true - */ - collapsible?: boolean; - /** - * Default collapsed state - * @default false - */ - defaultCollapsed?: boolean; - /** - * Controlled collapsed state - */ - collapsed?: boolean; - /** - * Sidebar width when expanded - * @default '16rem' - */ - width?: string | number; - /** - * Sidebar width when collapsed - * @default '4rem' - */ - collapsedWidth?: string | number; - /** - * Collapsed state change handler - */ - onCollapsedChange?: (collapsed: boolean) => void; - /** - * Sidebar variant - * @default 'default' - */ - variant?: 'default' | 'bordered' | 'floating'; -} -/** - * Breadcrumb item - */ -export interface BreadcrumbItem { - /** - * Item label - */ - label: string; - /** - * Item URL/href - */ - href?: string; - /** - * Item icon - */ - icon?: string; - /** - * Click handler (if not using href) - */ - onClick?: () => void; -} -/** - * Breadcrumb component - */ -export interface BreadcrumbSchema extends BaseSchema { - type: 'breadcrumb'; - /** - * Breadcrumb items - */ - items: BreadcrumbItem[]; - /** - * Separator character/icon - * @default '/' - */ - separator?: string; - /** - * Maximum items to display before collapsing - */ - maxItems?: number; -} -/** - * Pagination component - */ -export interface PaginationSchema extends BaseSchema { - type: 'pagination'; - /** - * Current page (1-indexed) - */ - page: number; - /** - * Total number of pages - */ - totalPages: number; - /** - * Number of sibling pages to show - * @default 1 - */ - siblings?: number; - /** - * Show first/last buttons - * @default true - */ - showFirstLast?: boolean; - /** - * Show previous/next buttons - * @default true - */ - showPrevNext?: boolean; - /** - * Page change handler - */ - onPageChange?: (page: number) => void; -} -/** - * Union type of all navigation schemas - */ -export type NavigationSchema = HeaderBarSchema | SidebarSchema | BreadcrumbSchema | PaginationSchema; diff --git a/packages/types/src/navigation.js b/packages/types/src/navigation.js deleted file mode 100644 index 8c3914d0c..000000000 --- a/packages/types/src/navigation.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @object-ui/types - Navigation Component Schemas - * - * Type definitions for navigation and menu components. - * - * @module navigation - * @packageDocumentation - */ -export {}; diff --git a/packages/types/src/overlay.d.ts b/packages/types/src/overlay.d.ts deleted file mode 100644 index a3ba97104..000000000 --- a/packages/types/src/overlay.d.ts +++ /dev/null @@ -1,395 +0,0 @@ -/** - * @object-ui/types - Overlay Component Schemas - * - * Type definitions for modal, dialog, and overlay components. - * - * @module overlay - * @packageDocumentation - */ -import type { BaseSchema, SchemaNode } from './base'; -/** - * Position type for overlays - */ -export type OverlayPosition = 'top' | 'right' | 'bottom' | 'left'; -/** - * Alignment type for overlays - */ -export type OverlayAlignment = 'start' | 'center' | 'end'; -/** - * Dialog component - */ -export interface DialogSchema extends BaseSchema { - type: 'dialog'; - /** - * Dialog title - */ - title?: string; - /** - * Dialog description - */ - description?: string; - /** - * Dialog content - */ - content?: SchemaNode | SchemaNode[]; - /** - * Dialog trigger (button or element that opens the dialog) - */ - trigger?: SchemaNode; - /** - * Default open state - * @default false - */ - defaultOpen?: boolean; - /** - * Controlled open state - */ - open?: boolean; - /** - * Dialog footer content - */ - footer?: SchemaNode | SchemaNode[]; - /** - * Whether dialog is modal (prevents interaction with background) - * @default true - */ - modal?: boolean; - /** - * Open state change handler - */ - onOpenChange?: (open: boolean) => void; -} -/** - * Alert dialog (confirmation dialog) - */ -export interface AlertDialogSchema extends BaseSchema { - type: 'alert-dialog'; - /** - * Dialog title - */ - title?: string; - /** - * Dialog description - */ - description?: string; - /** - * Dialog trigger - */ - trigger?: SchemaNode; - /** - * Default open state - * @default false - */ - defaultOpen?: boolean; - /** - * Controlled open state - */ - open?: boolean; - /** - * Cancel button label - * @default 'Cancel' - */ - cancelLabel?: string; - /** - * Confirm button label - * @default 'Confirm' - */ - confirmLabel?: string; - /** - * Confirm button variant - * @default 'default' - */ - confirmVariant?: 'default' | 'destructive'; - /** - * Confirm handler - */ - onConfirm?: () => void | Promise; - /** - * Cancel handler - */ - onCancel?: () => void; - /** - * Open state change handler - */ - onOpenChange?: (open: boolean) => void; -} -/** - * Sheet/Drawer side panel - */ -export interface SheetSchema extends BaseSchema { - type: 'sheet'; - /** - * Sheet title - */ - title?: string; - /** - * Sheet description - */ - description?: string; - /** - * Sheet content - */ - content?: SchemaNode | SchemaNode[]; - /** - * Sheet trigger - */ - trigger?: SchemaNode; - /** - * Default open state - * @default false - */ - defaultOpen?: boolean; - /** - * Controlled open state - */ - open?: boolean; - /** - * Sheet side - * @default 'right' - */ - side?: OverlayPosition; - /** - * Sheet footer content - */ - footer?: SchemaNode | SchemaNode[]; - /** - * Open state change handler - */ - onOpenChange?: (open: boolean) => void; -} -/** - * Drawer component (alternative name for Sheet) - */ -export interface DrawerSchema extends BaseSchema { - type: 'drawer'; - /** - * Drawer title - */ - title?: string; - /** - * Drawer description - */ - description?: string; - /** - * Drawer content - */ - content?: SchemaNode | SchemaNode[]; - /** - * Drawer trigger - */ - trigger?: SchemaNode; - /** - * Default open state - * @default false - */ - defaultOpen?: boolean; - /** - * Controlled open state - */ - open?: boolean; - /** - * Drawer direction - * @default 'right' - */ - direction?: OverlayPosition; - /** - * Open state change handler - */ - onOpenChange?: (open: boolean) => void; -} -/** - * Popover component - */ -export interface PopoverSchema extends BaseSchema { - type: 'popover'; - /** - * Popover content - */ - content: SchemaNode | SchemaNode[]; - /** - * Popover trigger - */ - trigger: SchemaNode; - /** - * Default open state - * @default false - */ - defaultOpen?: boolean; - /** - * Controlled open state - */ - open?: boolean; - /** - * Popover side - * @default 'bottom' - */ - side?: OverlayPosition; - /** - * Popover alignment - * @default 'center' - */ - align?: OverlayAlignment; - /** - * Open state change handler - */ - onOpenChange?: (open: boolean) => void; -} -/** - * Tooltip component - */ -export interface TooltipSchema extends BaseSchema { - type: 'tooltip'; - /** - * Tooltip content/text - */ - content: string | SchemaNode; - /** - * Element to attach tooltip to - */ - children: SchemaNode; - /** - * Tooltip side - * @default 'top' - */ - side?: OverlayPosition; - /** - * Tooltip alignment - * @default 'center' - */ - align?: OverlayAlignment; - /** - * Delay before showing (ms) - * @default 200 - */ - delayDuration?: number; -} -/** - * Hover card component - */ -export interface HoverCardSchema extends BaseSchema { - type: 'hover-card'; - /** - * Hover card content - */ - content: SchemaNode | SchemaNode[]; - /** - * Hover trigger element - */ - trigger: SchemaNode; - /** - * Default open state - * @default false - */ - defaultOpen?: boolean; - /** - * Controlled open state - */ - open?: boolean; - /** - * Hover card side - * @default 'bottom' - */ - side?: OverlayPosition; - /** - * Open delay (ms) - * @default 200 - */ - openDelay?: number; - /** - * Close delay (ms) - * @default 300 - */ - closeDelay?: number; - /** - * Open state change handler - */ - onOpenChange?: (open: boolean) => void; -} -/** - * Menu item - */ -export interface MenuItem { - /** - * Menu item label - */ - label: string; - /** - * Menu item icon - */ - icon?: string; - /** - * Whether item is disabled - */ - disabled?: boolean; - /** - * Click handler - */ - onClick?: () => void; - /** - * Keyboard shortcut - */ - shortcut?: string; - /** - * Submenu items - */ - children?: MenuItem[]; - /** - * Separator (renders as divider) - */ - separator?: boolean; -} -/** - * Dropdown menu component - */ -export interface DropdownMenuSchema extends BaseSchema { - type: 'dropdown-menu'; - /** - * Menu items - */ - items: MenuItem[]; - /** - * Menu trigger - */ - trigger: SchemaNode; - /** - * Default open state - * @default false - */ - defaultOpen?: boolean; - /** - * Controlled open state - */ - open?: boolean; - /** - * Menu side - * @default 'bottom' - */ - side?: OverlayPosition; - /** - * Menu alignment - * @default 'start' - */ - align?: OverlayAlignment; - /** - * Open state change handler - */ - onOpenChange?: (open: boolean) => void; -} -/** - * Context menu component - */ -export interface ContextMenuSchema extends BaseSchema { - type: 'context-menu'; - /** - * Menu items - */ - items: MenuItem[]; - /** - * Element to attach context menu to - */ - children: SchemaNode | SchemaNode[]; -} -/** - * Union type of all overlay schemas - */ -export type OverlaySchema = DialogSchema | AlertDialogSchema | SheetSchema | DrawerSchema | PopoverSchema | TooltipSchema | HoverCardSchema | DropdownMenuSchema | ContextMenuSchema; diff --git a/packages/types/src/overlay.js b/packages/types/src/overlay.js deleted file mode 100644 index 4854aa329..000000000 --- a/packages/types/src/overlay.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @object-ui/types - Overlay Component Schemas - * - * Type definitions for modal, dialog, and overlay components. - * - * @module overlay - * @packageDocumentation - */ -export {}; From 464b1015e903e9a92e09e7b19c55827024d15006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=80=A1?= Date: Thu, 15 Jan 2026 14:58:23 +0800 Subject: [PATCH 9/9] =?UTF-8?q?=E5=88=A0=E9=99=A4=20ENHANCEMENT=5FSUMMARY.?= =?UTF-8?q?md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ENHANCEMENT_SUMMARY.md | 146 ----------------------------------------- 1 file changed, 146 deletions(-) delete mode 100644 ENHANCEMENT_SUMMARY.md diff --git a/ENHANCEMENT_SUMMARY.md b/ENHANCEMENT_SUMMARY.md deleted file mode 100644 index 9c0a7d188..000000000 --- a/ENHANCEMENT_SUMMARY.md +++ /dev/null @@ -1,146 +0,0 @@ -# Metadata Specifications and Component System Enhancement - Summary - -## Overview - -This PR successfully enhances the Object UI metadata specifications and component system to support building complete applications using pure JSON schemas. - -## What Was Accomplished - -### Phase 1: Enhanced Type Definitions ✅ - -**Commit: 91c498c** - -1. **Extended BaseSchema** with essential properties: - - Conditional rendering: `visibleOn`, `hiddenOn`, `disabledOn` - - Semantic properties: `name`, `label`, `description`, `placeholder` - - Accessibility: `ariaLabel`, `testId` - - Styling: `style` object for inline styles - -2. **Created CRUD Schemas** (`packages/types/src/crud.ts`): - - `CRUDSchema`: Complete CRUD interface with columns, fields, operations, filters, pagination - - `ActionSchema`: Button actions with API integration - - `DetailSchema`: Record detail views - - Supporting types: `CRUDOperation`, `CRUDFilter`, `CRUDToolbar`, `CRUDPagination` - -3. **Created API Integration Schemas** (`packages/types/src/api.ts`): - - `APIRequest`: HTTP request configuration - - `APIConfig`: Success/error handling, loading states, redirects - - `EventHandler`: Dynamic event handling (API calls, navigation, dialogs, toasts) - - `DataFetchConfig`: Automatic data fetching with polling, caching, transformation - - `ExpressionSchema`: Dynamic value expressions - -### Phase 2: Developer Experience Tools ✅ - -**Commit: 4f68e0e** - -1. **Schema Validation** (`packages/core/src/validation/schema-validator.ts`): - ```typescript - validateSchema(schema) // Returns ValidationResult with errors/warnings - assertValidSchema(schema) // Throws on invalid schema - isValidSchema(value) // Type guard - formatValidationErrors() // Human-readable errors - ``` - -2. **Schema Builders** (`packages/core/src/builder/schema-builder.ts`): - - Fluent API for type-safe schema construction - - Builders: `FormBuilder`, `CRUDBuilder`, `ButtonBuilder`, `InputBuilder`, `CardBuilder`, `GridBuilder`, `FlexBuilder` - - Factory functions: `form()`, `crud()`, `button()`, etc. - -3. **TypeScript Configuration**: - - Added composite project references - - Updated path mappings for `@object-ui/types` and `@object-ui/core` - - Improved type inference and IDE support - -### Phase 3: Examples & Documentation ✅ - -**Commit: 4f68e0e** - -1. **Real-World Examples**: - - `examples/user-management/`: Complete CRUD interface (8.9KB JSON) - - Full CRUD operations - - Filters, pagination, sorting - - Batch actions for multiple selections - - Row actions with confirmations - - Empty state handling - - - `examples/api-integration/`: API patterns showcase (11KB JSON) - - Real-time data fetching with polling - - Interactive actions (API calls, dialogs, toasts, navigation) - - Form submission with validation - - Conditional rendering - - Event chaining - - Expression system demo - -2. **Protocol Documentation**: - - `docs/protocol/crud.md` (8.8KB): Complete CRUD protocol specification - - Schema properties reference - - Display modes (table, grid, list, kanban) - - API contract specification - - Variable substitution patterns - - - `docs/integration/api.md` (9.8KB): API integration guide - - Data fetching patterns - - Request/response handling - - Event handlers - - Form submission - - Error handling - - Caching and polling - - Authentication patterns - -3. **Best Practices Guide** (`docs/BEST_PRACTICES.md`, 11KB): - - Schema design patterns - - Performance optimization - - Type safety recommendations - - Maintainability guidelines - - API integration best practices - - Security considerations - - Testing strategies - - Accessibility standards - -## Key Achievements - -1. **Complete JSON-Driven Development**: Applications can now be built entirely from JSON schemas -2. **Type Safety**: Full TypeScript support with validation and builders -3. **Developer Experience**: Fluent APIs and comprehensive validation -4. **Production Ready**: Real-world examples and best practices -5. **Documentation**: Complete protocol specs and integration guides - -## File Statistics - -- **New Type Files**: 2 (crud.ts, api.ts) -- **New Core Files**: 2 (schema-validator.ts, schema-builder.ts) -- **New Examples**: 2 complete applications -- **New Documentation**: 3 comprehensive guides -- **Total Lines Added**: ~6,500+ - -## Next Steps (Future Enhancements) - -While all planned phases are complete, potential future enhancements could include: - -1. **Runtime Schema Migration**: Tools to migrate schemas between versions -2. **Visual Schema Editor**: GUI for building schemas -3. **Additional Builders**: More builder classes for complex components -4. **Extended Validation**: Custom validation rules -5. **Schema Templates**: Pre-built templates for common patterns - -## Testing - -All TypeScript builds pass successfully: -- `packages/types`: ✅ Build successful -- `packages/core`: ✅ Build successful with validation and builders - -## Breaking Changes - -**None**. All changes are additive and backward compatible. - -## Migration Guide - -No migration needed. Existing schemas continue to work as before. New features are opt-in: - -- To use new properties: Add them to existing schemas -- To use validation: Import from `@object-ui/core` -- To use builders: Import from `@object-ui/core/builder` - -## Conclusion - -This PR successfully delivers a comprehensive enhancement to Object UI's metadata specifications and component system, enabling developers to build complete, production-ready applications using pure JSON schemas with full type safety and excellent developer experience.