From 1cd315f3f75c9b8d0117eb1e3d276b8689e4a1e3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 09:36:36 +0000 Subject: [PATCH 1/4] Initial plan From c592efe36b71c0c75dce029f6a0bb2a43b279c42 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 09:45:20 +0000 Subject: [PATCH 2/4] feat: create comprehensive @object-ui/types package with all component schemas Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com> --- packages/types/README.md | 304 ++++++++++ packages/types/package.json | 81 +++ packages/types/src/base.ts | 316 ++++++++++ packages/types/src/complex.ts | 465 +++++++++++++++ packages/types/src/data-display.ts | 565 ++++++++++++++++++ packages/types/src/data.ts | 341 +++++++++++ packages/types/src/disclosure.ts | 113 ++++ packages/types/src/feedback.ts | 170 ++++++ packages/types/src/form.ts | 913 +++++++++++++++++++++++++++++ packages/types/src/index.ts | 281 +++++++++ packages/types/src/layout.ts | 387 ++++++++++++ packages/types/src/navigation.ts | 235 ++++++++ packages/types/src/overlay.ts | 408 +++++++++++++ packages/types/tsconfig.json | 13 + 14 files changed, 4592 insertions(+) create mode 100644 packages/types/README.md create mode 100644 packages/types/package.json create mode 100644 packages/types/src/base.ts create mode 100644 packages/types/src/complex.ts create mode 100644 packages/types/src/data-display.ts create mode 100644 packages/types/src/data.ts create mode 100644 packages/types/src/disclosure.ts create mode 100644 packages/types/src/feedback.ts create mode 100644 packages/types/src/form.ts create mode 100644 packages/types/src/index.ts create mode 100644 packages/types/src/layout.ts create mode 100644 packages/types/src/navigation.ts create mode 100644 packages/types/src/overlay.ts create mode 100644 packages/types/tsconfig.json diff --git a/packages/types/README.md b/packages/types/README.md new file mode 100644 index 000000000..f6fd1aaae --- /dev/null +++ b/packages/types/README.md @@ -0,0 +1,304 @@ +# @object-ui/types + +Pure TypeScript type definitions for Object UI - **The Protocol Layer**. + +## Features + +- 🎯 **Complete Type Coverage** - Every component has full TypeScript definitions +- 📦 **Zero Dependencies** - Pure types with no runtime dependencies +- 🔌 **Framework Agnostic** - Use with React, Vue, or any framework +- 🌍 **Backend Agnostic** - Works with REST, GraphQL, ObjectQL, or local data +- 🎨 **Tailwind Native** - Designed for Tailwind CSS styling +- 📚 **Comprehensive JSDoc** - Every type is fully documented + +## Installation + +```bash +npm install @object-ui/types +# or +yarn add @object-ui/types +# or +pnpm add @object-ui/types +``` + +**Important:** This package has **ZERO runtime dependencies**. It's pure TypeScript types. + +## Philosophy + +Object UI follows a **"Protocol First"** approach: + +``` +@object-ui/types (Protocol) + ↓ +@object-ui/core (Engine) + ↓ +@object-ui/react (Framework) + ↓ +@object-ui/components (UI Implementation) +``` + +This separation allows: +- ✅ Multiple UI implementations (Shadcn, Material, Ant Design) +- ✅ Multiple framework bindings (React, Vue, Svelte) +- ✅ Multiple backend adapters (REST, GraphQL, ObjectQL) +- ✅ Static analysis and validation without runtime dependencies + +## Usage + +### Basic Example + +```typescript +import type { FormSchema, InputSchema, ButtonSchema } from '@object-ui/types'; + +const loginForm: FormSchema = { + type: 'form', + fields: [ + { + name: 'email', + type: 'input', + inputType: 'email', + label: 'Email', + required: true, + }, + { + name: 'password', + type: 'input', + inputType: 'password', + label: 'Password', + required: true, + } + ], + submitLabel: 'Sign In' +}; +``` + +### Advanced Example + +```typescript +import type { DataTableSchema, FlexSchema, CardSchema } from '@object-ui/types'; + +const dashboard: CardSchema = { + type: 'card', + title: 'User Management', + content: { + type: 'data-table', + columns: [ + { header: 'Name', accessorKey: 'name' }, + { header: 'Email', accessorKey: 'email' }, + { header: 'Role', accessorKey: 'role' } + ], + data: [], // Connected to data source + pagination: true, + searchable: true, + selectable: true + } +}; +``` + +### Type Narrowing + +```typescript +import type { AnySchema, SchemaByType } from '@object-ui/types'; + +function renderComponent(schema: AnySchema) { + if (schema.type === 'input') { + // TypeScript automatically narrows to InputSchema + console.log(schema.placeholder); + } +} + +// Or use the utility type +type ButtonSchema = SchemaByType<'button'>; +``` + +## Type Categories + +### Base Types + +Foundation types that all components build upon: + +- `BaseSchema` - The base interface for all components +- `SchemaNode` - Union type for schema nodes (objects, strings, numbers, etc.) +- `ComponentMeta` - Metadata for component registration +- `ComponentInput` - Input field definitions for designers/editors + +### Layout Components + +Structure and organization: + +- `ContainerSchema` - Max-width container +- `FlexSchema` - Flexbox layout +- `GridSchema` - CSS Grid layout +- `CardSchema` - Card container +- `TabsSchema` - Tabbed interface + +### Form Components + +User input and interaction: + +- `FormSchema` - Complete form with validation +- `InputSchema` - Text input field +- `SelectSchema` - Dropdown select +- `CheckboxSchema` - Checkbox input +- `RadioGroupSchema` - Radio button group +- `DatePickerSchema` - Date selection +- And 10+ more form components + +### Data Display Components + +Information presentation: + +- `DataTableSchema` - Enterprise data table with sorting, filtering, pagination +- `TableSchema` - Simple table +- `ListSchema` - List with items +- `ChartSchema` - Charts and graphs +- `TreeViewSchema` - Hierarchical tree +- `TimelineSchema` - Timeline visualization + +### Feedback Components + +Status and progress: + +- `LoadingSchema` - Loading spinner +- `ProgressSchema` - Progress bar +- `SkeletonSchema` - Loading placeholder +- `ToastSchema` - Toast notifications + +### Overlay Components + +Modals and popovers: + +- `DialogSchema` - Modal dialog +- `SheetSchema` - Side panel/drawer +- `PopoverSchema` - Popover +- `TooltipSchema` - Tooltip +- `DropdownMenuSchema` - Dropdown menu + +### Navigation Components + +Menus and navigation: + +- `HeaderBarSchema` - Top navigation bar +- `SidebarSchema` - Side navigation +- `BreadcrumbSchema` - Breadcrumb navigation +- `PaginationSchema` - Pagination controls + +### Complex Components + +Advanced composite components: + +- `KanbanSchema` - Kanban board +- `CalendarViewSchema` - Calendar with events +- `FilterBuilderSchema` - Advanced filter builder +- `CarouselSchema` - Image/content carousel +- `ChatbotSchema` - Chat interface + +### Data Management + +Backend integration: + +- `DataSource` - Universal data adapter interface +- `QueryParams` - Query parameters (OData-style) +- `QueryResult` - Paginated query results +- `DataBinding` - Data binding configuration + +## Design Principles + +### 1. Protocol Agnostic + +Types don't assume any specific backend: + +```typescript +interface DataSource { + find(resource: string, params?: QueryParams): Promise>; + create(resource: string, data: Partial): Promise; + // Works with REST, GraphQL, ObjectQL, or anything +} +``` + +### 2. Tailwind Native + +All components support `className` for Tailwind styling: + +```typescript +const button: ButtonSchema = { + type: 'button', + label: 'Click Me', + className: 'bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded' +}; +``` + +### 3. Type Safe + +Full TypeScript support with discriminated unions: + +```typescript +type AnySchema = + | InputSchema + | ButtonSchema + | FormSchema + | /* 50+ more */; + +function render(schema: AnySchema) { + switch (schema.type) { + case 'input': /* schema is InputSchema */ break; + case 'button': /* schema is ButtonSchema */ break; + } +} +``` + +### 4. Composable + +Components can nest indefinitely: + +```typescript +const page: FlexSchema = { + type: 'flex', + direction: 'col', + children: [ + { type: 'header-bar', title: 'My App' }, + { + type: 'flex', + direction: 'row', + children: [ + { type: 'sidebar', nav: [...] }, + { type: 'container', children: [...] } + ] + } + ] +}; +``` + +## Comparison + +### vs Amis Types + +- ✅ **Lighter** - No runtime dependencies +- ✅ **Tailwind Native** - Built for Tailwind CSS +- ✅ **Better TypeScript** - Full type inference +- ✅ **Framework Agnostic** - Not tied to React + +### vs Formily Types + +- ✅ **Full Pages** - Not just forms, entire UIs +- ✅ **Simpler** - More straightforward API +- ✅ **Better Docs** - Comprehensive JSDoc + +## Contributing + +We follow these constraints for this package: + +1. **ZERO runtime dependencies** - Only TypeScript types +2. **No React imports** - Framework agnostic +3. **Comprehensive JSDoc** - Every property documented +4. **Protocol first** - Types define the contract + +## License + +MIT + +## Links + +- [Documentation](https://objectui.org/docs/types) +- [GitHub](https://github.com/objectstack-ai/objectui) +- [NPM](https://www.npmjs.com/package/@object-ui/types) diff --git a/packages/types/package.json b/packages/types/package.json new file mode 100644 index 000000000..f1b241b7b --- /dev/null +++ b/packages/types/package.json @@ -0,0 +1,81 @@ +{ + "name": "@object-ui/types", + "version": "0.1.0", + "description": "Pure TypeScript type definitions for Object UI - The Protocol Layer", + "type": "module", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + }, + "./base": { + "types": "./dist/base.d.ts", + "import": "./dist/base.js" + }, + "./layout": { + "types": "./dist/layout.d.ts", + "import": "./dist/layout.js" + }, + "./form": { + "types": "./dist/form.d.ts", + "import": "./dist/form.js" + }, + "./data-display": { + "types": "./dist/data-display.d.ts", + "import": "./dist/data-display.js" + }, + "./feedback": { + "types": "./dist/feedback.d.ts", + "import": "./dist/feedback.js" + }, + "./overlay": { + "types": "./dist/overlay.d.ts", + "import": "./dist/overlay.js" + }, + "./navigation": { + "types": "./dist/navigation.d.ts", + "import": "./dist/navigation.js" + }, + "./complex": { + "types": "./dist/complex.d.ts", + "import": "./dist/complex.js" + }, + "./data": { + "types": "./dist/data.d.ts", + "import": "./dist/data.js" + } + }, + "files": [ + "dist", + "src", + "README.md", + "LICENSE" + ], + "scripts": { + "build": "tsc", + "clean": "rm -rf dist", + "type-check": "tsc --noEmit" + }, + "keywords": [ + "object-ui", + "types", + "typescript", + "schema", + "json-schema", + "protocol" + ], + "author": "Object UI Team", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/objectstack-ai/objectui.git", + "directory": "packages/types" + }, + "devDependencies": { + "typescript": "^5.0.0" + } +} diff --git a/packages/types/src/base.ts b/packages/types/src/base.ts new file mode 100644 index 000000000..48610a6db --- /dev/null +++ b/packages/types/src/base.ts @@ -0,0 +1,316 @@ +/** + * @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; + + /** + * 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; + + /** + * 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[]; + + /** + * 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; + + /** + * 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/complex.ts b/packages/types/src/complex.ts new file mode 100644 index 000000000..27f92b7d9 --- /dev/null +++ b/packages/types/src/complex.ts @@ -0,0 +1,465 @@ +/** + * @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/data-display.ts b/packages/types/src/data-display.ts new file mode 100644 index 000000000..1911907c6 --- /dev/null +++ b/packages/types/src/data-display.ts @@ -0,0 +1,565 @@ +/** + * @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.ts b/packages/types/src/data.ts new file mode 100644 index 000000000..996837bbf --- /dev/null +++ b/packages/types/src/data.ts @@ -0,0 +1,341 @@ +/** + * @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: any[]): 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/disclosure.ts b/packages/types/src/disclosure.ts new file mode 100644 index 000000000..e6860119c --- /dev/null +++ b/packages/types/src/disclosure.ts @@ -0,0 +1,113 @@ +/** + * @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/feedback.ts b/packages/types/src/feedback.ts new file mode 100644 index 000000000..325dc3bdf --- /dev/null +++ b/packages/types/src/feedback.ts @@ -0,0 +1,170 @@ +/** + * @object-ui/types - Feedback Component Schemas + * + * Type definitions for feedback and status indication components. + * + * @module feedback + * @packageDocumentation + */ + +import type { BaseSchema, SchemaNode } 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/form.ts b/packages/types/src/form.ts new file mode 100644 index 000000000..4ce4f7caf --- /dev/null +++ b/packages/types/src/form.ts @@ -0,0 +1,913 @@ +/** + * @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 + */ + validate?: (value: any) => 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/index.ts b/packages/types/src/index.ts new file mode 100644 index 000000000..3d64823ac --- /dev/null +++ b/packages/types/src/index.ts @@ -0,0 +1,281 @@ +/** + * @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 + */ + +// ============================================================================ +// Base Types - The Foundation +// ============================================================================ +export type { + BaseSchema, + SchemaNode, + ComponentRendererProps, + ComponentInput, + ComponentMeta, + ComponentConfig, + HTMLAttributes, + EventHandlers, + StyleProps, +} from './base'; + +// ============================================================================ +// Layout Components - Structure & Organization +// ============================================================================ +export type { + DivSchema, + SpanSchema, + TextSchema, + ImageSchema, + IconSchema, + SeparatorSchema, + ContainerSchema, + FlexSchema, + GridSchema, + CardSchema, + TabsSchema, + TabItem, + ScrollAreaSchema, + ResizableSchema, + ResizablePanel, + LayoutSchema, +} from './layout'; + +// ============================================================================ +// Form Components - User Input & Interaction +// ============================================================================ +export type { + ButtonSchema, + InputSchema, + TextareaSchema, + SelectSchema, + SelectOption, + CheckboxSchema, + RadioGroupSchema, + RadioOption, + SwitchSchema, + ToggleSchema, + SliderSchema, + FileUploadSchema, + DatePickerSchema, + CalendarSchema, + InputOTPSchema, + ValidationRule, + FieldCondition, + FormField, + FormSchema, + FormComponentSchema, +} from './form'; + +// ============================================================================ +// Data Display Components - Information Presentation +// ============================================================================ +export type { + AlertSchema, + BadgeSchema, + AvatarSchema, + ListSchema, + ListItem, + TableColumn, + TableSchema, + DataTableSchema, + MarkdownSchema, + TreeNode, + TreeViewSchema, + ChartType, + ChartSeries, + ChartSchema, + TimelineEvent, + TimelineSchema, + DataDisplaySchema, +} from './data-display'; + +// ============================================================================ +// Feedback Components - Status & Progress Indication +// ============================================================================ +export type { + LoadingSchema, + ProgressSchema, + SkeletonSchema, + ToastSchema, + ToasterSchema, + FeedbackSchema, +} from './feedback'; + +// ============================================================================ +// Disclosure Components - Collapsible Content +// ============================================================================ +export type { + AccordionItem, + AccordionSchema, + CollapsibleSchema, + DisclosureSchema, +} from './disclosure'; + +// ============================================================================ +// Overlay Components - Modals & Popovers +// ============================================================================ +export type { + DialogSchema, + AlertDialogSchema, + SheetSchema, + DrawerSchema, + PopoverSchema, + TooltipSchema, + HoverCardSchema, + MenuItem, + DropdownMenuSchema, + ContextMenuSchema, + OverlaySchema, +} from './overlay'; + +// ============================================================================ +// Navigation Components - Menus & Navigation +// ============================================================================ +export type { + NavLink, + HeaderBarSchema, + SidebarSchema, + BreadcrumbItem, + BreadcrumbSchema, + PaginationSchema, + NavigationSchema, +} from './navigation'; + +// ============================================================================ +// Complex Components - Advanced/Composite Components +// ============================================================================ +export type { + KanbanColumn, + KanbanCard, + KanbanSchema, + CalendarViewMode, + CalendarEvent, + CalendarViewSchema, + FilterOperator, + FilterCondition, + FilterGroup, + FilterBuilderSchema, + FilterField, + CarouselItem, + CarouselSchema, + ChatMessage, + ChatbotSchema, + ComplexSchema, +} from './complex'; + +// ============================================================================ +// Data Management - Backend Integration +// ============================================================================ +export type { + QueryParams, + QueryResult, + DataSource, + DataScope, + DataContext, + DataBinding, + ValidationError, + APIError, +} from './data'; + +// ============================================================================ +// Union Types - Discriminated Unions for All Schemas +// ============================================================================ + +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'; + +/** + * 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; + +/** + * 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 const VERSION = '0.1.0'; + +/** + * Schema version for compatibility checking + */ +export const SCHEMA_VERSION = '1.0.0'; diff --git a/packages/types/src/layout.ts b/packages/types/src/layout.ts new file mode 100644 index 000000000..5c6248ea7 --- /dev/null +++ b/packages/types/src/layout.ts @@ -0,0 +1,387 @@ +/** + * @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[]; +} + +/** + * Union type of all layout schemas + */ +export type LayoutSchema = + | DivSchema + | SpanSchema + | TextSchema + | ImageSchema + | IconSchema + | SeparatorSchema + | ContainerSchema + | FlexSchema + | GridSchema + | CardSchema + | TabsSchema + | ScrollAreaSchema + | ResizableSchema; diff --git a/packages/types/src/navigation.ts b/packages/types/src/navigation.ts new file mode 100644 index 000000000..cf59a9257 --- /dev/null +++ b/packages/types/src/navigation.ts @@ -0,0 +1,235 @@ +/** + * @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/overlay.ts b/packages/types/src/overlay.ts new file mode 100644 index 000000000..b17658b0e --- /dev/null +++ b/packages/types/src/overlay.ts @@ -0,0 +1,408 @@ +/** + * @object-ui/types - Overlay Component Schemas + * + * Type definitions for modal, dialog, and overlay components. + * + * @module overlay + * @packageDocumentation + */ + +import type { BaseSchema, SchemaNode } from './base'; + +/** + * 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?: 'top' | 'right' | 'bottom' | 'left'; + /** + * 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?: 'top' | 'right' | 'bottom' | 'left'; + /** + * 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?: 'top' | 'right' | 'bottom' | 'left'; + /** + * Popover alignment + * @default 'center' + */ + align?: 'start' | 'center' | 'end'; + /** + * 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?: 'top' | 'right' | 'bottom' | 'left'; + /** + * Tooltip alignment + * @default 'center' + */ + align?: 'start' | 'center' | 'end'; + /** + * 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?: 'top' | 'right' | 'bottom' | 'left'; + /** + * 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?: 'top' | 'right' | 'bottom' | 'left'; + /** + * Menu alignment + * @default 'start' + */ + align?: 'start' | 'center' | 'end'; + /** + * 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/tsconfig.json b/packages/types/tsconfig.json new file mode 100644 index 000000000..633d3f509 --- /dev/null +++ b/packages/types/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "declarationMap": true, + "composite": true, + "noEmit": false + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"] +} From 2c55eb890654c30010a68b0835939e6a03d08375 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 09:48:59 +0000 Subject: [PATCH 3/4] refactor: improve type safety and reduce duplication in types package - Use generics for DataSource.bulk() return type - Improve validation function type safety - Extract OverlayPosition and OverlayAlignment shared types - Add comprehensive usage examples Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com> --- packages/types/.gitignore | 2 + packages/types/examples/dashboard.ts | 88 ++++++++++ packages/types/examples/login-form.ts | 60 +++++++ packages/types/examples/rest-data-source.ts | 169 ++++++++++++++++++++ packages/types/src/data.ts | 2 +- packages/types/src/form.ts | 4 +- packages/types/src/index.ts | 2 + packages/types/src/overlay.ts | 28 ++-- packages/types/tsconfig.json | 5 +- 9 files changed, 347 insertions(+), 13 deletions(-) create mode 100644 packages/types/.gitignore create mode 100644 packages/types/examples/dashboard.ts create mode 100644 packages/types/examples/login-form.ts create mode 100644 packages/types/examples/rest-data-source.ts diff --git a/packages/types/.gitignore b/packages/types/.gitignore new file mode 100644 index 000000000..1eae0cf67 --- /dev/null +++ b/packages/types/.gitignore @@ -0,0 +1,2 @@ +dist/ +node_modules/ diff --git a/packages/types/examples/dashboard.ts b/packages/types/examples/dashboard.ts new file mode 100644 index 000000000..665724677 --- /dev/null +++ b/packages/types/examples/dashboard.ts @@ -0,0 +1,88 @@ +/** + * Example: Dashboard Layout + * + * This example demonstrates a complete dashboard layout with + * sidebar, header, and data table. + */ + +import type { FlexSchema, SidebarSchema, HeaderBarSchema, CardSchema, DataTableSchema } from '../src/index'; + +export const dashboardSchema: FlexSchema = { + type: 'flex', + direction: 'col', + className: 'h-screen', + + children: [ + // Header + { + type: 'header-bar', + title: 'Object UI Dashboard', + logo: '/logo.svg', + sticky: true, + right: [ + { + type: 'button', + label: 'Profile', + variant: 'ghost', + icon: 'User' + } + ] + } as HeaderBarSchema, + + // Main content with sidebar + { + type: 'flex', + direction: 'row', + className: 'flex-1', + children: [ + // Sidebar + { + type: 'sidebar', + collapsible: true, + nav: [ + { label: 'Dashboard', href: '/', icon: 'Home', active: true }, + { label: 'Users', href: '/users', icon: 'Users' }, + { label: 'Settings', href: '/settings', icon: 'Settings' } + ] + } as SidebarSchema, + + // Main content area + { + type: 'container', + className: 'flex-1 p-6', + children: [ + { + type: 'card', + title: 'User Management', + description: 'Manage your users and permissions', + content: { + type: 'data-table', + columns: [ + { header: 'ID', accessorKey: 'id', width: '80px' }, + { header: 'Name', accessorKey: 'name' }, + { header: 'Email', accessorKey: 'email' }, + { header: 'Role', accessorKey: 'role' }, + { header: 'Status', accessorKey: 'status' } + ], + data: [ + { id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin', status: 'Active' }, + { id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User', status: 'Active' }, + { id: 3, name: 'Bob Johnson', email: 'bob@example.com', role: 'User', status: 'Inactive' } + ], + pagination: true, + pageSize: 10, + searchable: true, + selectable: true, + sortable: true, + exportable: true, + rowActions: true, + onRowEdit: (row) => console.log('Edit:', row), + onRowDelete: (row) => console.log('Delete:', row) + } as DataTableSchema + } as CardSchema + ] + } + ] + } + ] +}; diff --git a/packages/types/examples/login-form.ts b/packages/types/examples/login-form.ts new file mode 100644 index 000000000..96a86cb6a --- /dev/null +++ b/packages/types/examples/login-form.ts @@ -0,0 +1,60 @@ +/** + * Example: Simple Login Form + * + * This example demonstrates how to use @object-ui/types to define + * a complete login form with validation. + */ + +import type { FormSchema } from '../src/index'; + +export const loginFormSchema: FormSchema = { + type: 'form', + className: 'max-w-md mx-auto p-6', + + fields: [ + { + name: 'email', + type: 'input', + inputType: 'email', + label: 'Email Address', + placeholder: 'you@example.com', + required: true, + validation: { + required: 'Email is required', + pattern: { + value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, + message: 'Invalid email address' + } + } + }, + { + name: 'password', + type: 'input', + inputType: 'password', + label: 'Password', + placeholder: '••••••••', + required: true, + validation: { + required: 'Password is required', + minLength: { + value: 8, + message: 'Password must be at least 8 characters' + } + } + }, + { + name: 'remember', + type: 'checkbox', + label: 'Remember me', + defaultChecked: false + } + ], + + submitLabel: 'Sign In', + showCancel: false, + + onSubmit: async (data) => { + console.log('Login attempt:', data); + // Handle authentication + } +}; diff --git a/packages/types/examples/rest-data-source.ts b/packages/types/examples/rest-data-source.ts new file mode 100644 index 000000000..e85ef17de --- /dev/null +++ b/packages/types/examples/rest-data-source.ts @@ -0,0 +1,169 @@ +/** + * Example: Data Source Adapter + * + * This example demonstrates implementing a REST API data source adapter + * using the DataSource interface from @object-ui/types. + */ + +import type { DataSource, QueryParams, QueryResult } from '../src/index'; + +/** + * REST API Data Source Implementation + * + * A generic REST API adapter that works with any REST backend. + */ +export class RestDataSource implements DataSource { + constructor(private baseUrl: string) {} + + /** + * Build query string from QueryParams + */ + private buildQueryString(params?: QueryParams): string { + if (!params) return ''; + + const searchParams = new URLSearchParams(); + + if (params.$select) { + searchParams.append('select', params.$select.join(',')); + } + + if (params.$filter) { + searchParams.append('filter', JSON.stringify(params.$filter)); + } + + if (params.$orderby) { + const sort = Object.entries(params.$orderby) + .map(([key, dir]) => `${key}:${dir}`) + .join(','); + searchParams.append('sort', sort); + } + + if (params.$skip !== undefined) { + searchParams.append('skip', params.$skip.toString()); + } + + if (params.$top !== undefined) { + searchParams.append('limit', params.$top.toString()); + } + + if (params.$search) { + searchParams.append('search', params.$search); + } + + return searchParams.toString(); + } + + /** + * Fetch multiple records + */ + async find(resource: string, params?: QueryParams): Promise> { + const queryString = this.buildQueryString(params); + const url = `${this.baseUrl}/${resource}${queryString ? '?' + queryString : ''}`; + + const response = await fetch(url); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + + // Assume API returns { data: [], total: number } + return { + data: data.data || data, + total: data.total, + page: params?.$skip && params?.$top + ? Math.floor(params.$skip / params.$top) + 1 + : 1, + pageSize: params?.$top, + hasMore: data.hasMore + }; + } + + /** + * Fetch a single record by ID + */ + async findOne(resource: string, id: string | number, params?: QueryParams): Promise { + const queryString = this.buildQueryString(params); + const url = `${this.baseUrl}/${resource}/${id}${queryString ? '?' + queryString : ''}`; + + const response = await fetch(url); + + if (response.status === 404) { + return null; + } + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return response.json(); + } + + /** + * Create a new record + */ + async create(resource: string, data: Partial): Promise { + const url = `${this.baseUrl}/${resource}`; + + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return response.json(); + } + + /** + * Update an existing record + */ + async update(resource: string, id: string | number, data: Partial): Promise { + const url = `${this.baseUrl}/${resource}/${id}`; + + const response = await fetch(url, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return response.json(); + } + + /** + * Delete a record + */ + async delete(resource: string, id: string | number): Promise { + const url = `${this.baseUrl}/${resource}/${id}`; + + const response = await fetch(url, { + method: 'DELETE', + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return true; + } +} + +// Usage example: +// const dataSource = new RestDataSource('https://api.example.com'); +// const users = await dataSource.find('users', { +// $filter: { status: 'active' }, +// $orderby: { createdAt: 'desc' }, +// $top: 10 +// }); diff --git a/packages/types/src/data.ts b/packages/types/src/data.ts index 996837bbf..1e84caf03 100644 --- a/packages/types/src/data.ts +++ b/packages/types/src/data.ts @@ -184,7 +184,7 @@ export interface DataSource { * @param data - Bulk data * @returns Promise resolving to operation result */ - bulk?(resource: string, operation: 'create' | 'update' | 'delete', data: any[]): Promise; + bulk?(resource: string, operation: 'create' | 'update' | 'delete', data: Partial[]): Promise; } /** diff --git a/packages/types/src/form.ts b/packages/types/src/form.ts index 4ce4f7caf..ff864f84a 100644 --- a/packages/types/src/form.ts +++ b/packages/types/src/form.ts @@ -726,8 +726,10 @@ export interface ValidationRule { 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: any) => boolean | string | Promise; + validate?: (value: string | number | boolean | null | undefined) => boolean | string | Promise; } /** diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 3d64823ac..440a39c23 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -151,6 +151,8 @@ export type { // Overlay Components - Modals & Popovers // ============================================================================ export type { + OverlayPosition, + OverlayAlignment, DialogSchema, AlertDialogSchema, SheetSchema, diff --git a/packages/types/src/overlay.ts b/packages/types/src/overlay.ts index b17658b0e..b83aeeaa6 100644 --- a/packages/types/src/overlay.ts +++ b/packages/types/src/overlay.ts @@ -9,6 +9,16 @@ 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 */ @@ -143,7 +153,7 @@ export interface SheetSchema extends BaseSchema { * Sheet side * @default 'right' */ - side?: 'top' | 'right' | 'bottom' | 'left'; + side?: OverlayPosition; /** * Sheet footer content */ @@ -188,7 +198,7 @@ export interface DrawerSchema extends BaseSchema { * Drawer direction * @default 'right' */ - direction?: 'top' | 'right' | 'bottom' | 'left'; + direction?: OverlayPosition; /** * Open state change handler */ @@ -221,12 +231,12 @@ export interface PopoverSchema extends BaseSchema { * Popover side * @default 'bottom' */ - side?: 'top' | 'right' | 'bottom' | 'left'; + side?: OverlayPosition; /** * Popover alignment * @default 'center' */ - align?: 'start' | 'center' | 'end'; + align?: OverlayAlignment; /** * Open state change handler */ @@ -250,12 +260,12 @@ export interface TooltipSchema extends BaseSchema { * Tooltip side * @default 'top' */ - side?: 'top' | 'right' | 'bottom' | 'left'; + side?: OverlayPosition; /** * Tooltip alignment * @default 'center' */ - align?: 'start' | 'center' | 'end'; + align?: OverlayAlignment; /** * Delay before showing (ms) * @default 200 @@ -289,7 +299,7 @@ export interface HoverCardSchema extends BaseSchema { * Hover card side * @default 'bottom' */ - side?: 'top' | 'right' | 'bottom' | 'left'; + side?: OverlayPosition; /** * Open delay (ms) * @default 200 @@ -366,12 +376,12 @@ export interface DropdownMenuSchema extends BaseSchema { * Menu side * @default 'bottom' */ - side?: 'top' | 'right' | 'bottom' | 'left'; + side?: OverlayPosition; /** * Menu alignment * @default 'start' */ - align?: 'start' | 'center' | 'end'; + align?: OverlayAlignment; /** * Open state change handler */ diff --git a/packages/types/tsconfig.json b/packages/types/tsconfig.json index 633d3f509..c47684036 100644 --- a/packages/types/tsconfig.json +++ b/packages/types/tsconfig.json @@ -6,8 +6,9 @@ "declaration": true, "declarationMap": true, "composite": true, - "noEmit": false + "noEmit": false, + "lib": ["ES2020", "DOM"] }, "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"] + "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts", "examples"] } From b7346ed48adf52a00f3e88b862e18cdb426d20fd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 09:58:14 +0000 Subject: [PATCH 4/4] fix: update pnpm-lock.yaml for new @object-ui/types package Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com> --- pnpm-lock.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a840a2e92..d1c281bea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -545,6 +545,12 @@ importers: specifier: ^5.0.0 version: 5.9.3 + packages/types: + devDependencies: + typescript: + specifier: ^5.0.0 + version: 5.7.3 + packages: '@acemir/cssom@0.9.31':