@object-ui/components 0.5.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/.turbo/turbo-build.log +12 -25
  2. package/CHANGELOG.md +32 -0
  3. package/dist/index.css +1 -1
  4. package/dist/index.js +23987 -22576
  5. package/dist/index.umd.cjs +30 -30
  6. package/dist/src/custom/action-param-dialog.d.ts +21 -0
  7. package/dist/src/custom/index.d.ts +4 -0
  8. package/dist/src/custom/navigation-overlay.d.ts +50 -0
  9. package/dist/src/custom/view-skeleton.d.ts +37 -0
  10. package/dist/src/custom/view-states.d.ts +33 -0
  11. package/dist/src/index.d.ts +1 -0
  12. package/dist/src/renderers/action/action-button.d.ts +11 -0
  13. package/dist/src/renderers/action/action-group.d.ts +25 -0
  14. package/dist/src/renderers/action/action-icon.d.ts +10 -0
  15. package/dist/src/renderers/action/action-menu.d.ts +19 -0
  16. package/dist/src/renderers/action/index.d.ts +0 -0
  17. package/dist/src/renderers/action/resolve-icon.d.ts +6 -0
  18. package/package.json +20 -19
  19. package/src/__tests__/PageRendererRegions.test.tsx +664 -55
  20. package/src/__tests__/__snapshots__/snapshot-critical.test.tsx.snap +811 -0
  21. package/src/__tests__/__snapshots__/snapshot.test.tsx.snap +327 -0
  22. package/src/__tests__/accessibility.test.tsx +137 -0
  23. package/src/__tests__/api-consistency.test.tsx +596 -0
  24. package/src/__tests__/color-contrast.test.tsx +212 -0
  25. package/src/__tests__/compliance.test.tsx +72 -0
  26. package/src/__tests__/edge-cases.test.tsx +285 -0
  27. package/src/__tests__/navigation-overlay.test.tsx +273 -0
  28. package/src/__tests__/snapshot-critical.test.tsx +317 -0
  29. package/src/__tests__/snapshot.test.tsx +205 -0
  30. package/src/__tests__/view-compliance.test.tsx +153 -0
  31. package/src/__tests__/wcag-audit.test.tsx +493 -0
  32. package/src/custom/action-param-dialog.tsx +264 -0
  33. package/src/custom/index.ts +4 -0
  34. package/src/custom/navigation-overlay.tsx +296 -0
  35. package/src/custom/view-skeleton.tsx +243 -0
  36. package/src/custom/view-states.tsx +153 -0
  37. package/src/index.ts +1 -0
  38. package/src/renderers/action/action-button.tsx +147 -0
  39. package/src/renderers/action/action-group.tsx +270 -0
  40. package/src/renderers/action/action-icon.tsx +150 -0
  41. package/src/renderers/action/action-menu.tsx +203 -0
  42. package/src/renderers/action/index.ts +18 -0
  43. package/src/renderers/action/resolve-icon.ts +35 -0
  44. package/src/renderers/complex/__tests__/data-table-batch-editing.test.tsx +275 -0
  45. package/src/renderers/complex/__tests__/data-table-cell-renderer.test.tsx +120 -0
  46. package/src/renderers/complex/__tests__/data-table-editing.test.tsx +221 -0
  47. package/src/renderers/complex/data-table.tsx +269 -33
  48. package/src/renderers/complex/resizable.tsx +20 -17
  49. package/src/renderers/data-display/list.tsx +1 -1
  50. package/src/renderers/data-display/table.tsx +1 -1
  51. package/src/renderers/data-display/tree-view.tsx +2 -1
  52. package/src/renderers/form/form.tsx +33 -10
  53. package/src/renderers/index.ts +1 -0
  54. package/src/renderers/layout/aspect-ratio.tsx +1 -1
  55. package/src/renderers/layout/page.tsx +416 -52
  56. package/src/renderers/navigation/sidebar.tsx +6 -0
  57. package/src/renderers/placeholders.tsx +2 -2
  58. package/src/stories/MockedData.stories.tsx +87 -37
  59. package/src/stories-json/Accessibility.mdx +297 -0
  60. package/src/stories-json/EdgeCases.stories.tsx +160 -0
  61. package/src/stories-json/GettingStarted.mdx +89 -0
  62. package/src/stories-json/Introduction.mdx +127 -0
  63. package/src/stories-json/accordion.stories.tsx +1 -1
  64. package/src/stories-json/aggrid.stories.tsx +1 -1
  65. package/src/stories-json/alert.stories.tsx +1 -1
  66. package/src/stories-json/aspect-ratio.stories.tsx +1 -1
  67. package/src/stories-json/avatar.stories.tsx +1 -1
  68. package/src/stories-json/badge.stories.tsx +1 -1
  69. package/src/stories-json/breadcrumb.stories.tsx +1 -1
  70. package/src/stories-json/button-group.stories.tsx +1 -1
  71. package/src/stories-json/button.stories.tsx +1 -1
  72. package/src/stories-json/calendar.stories.tsx +1 -1
  73. package/src/stories-json/card.stories.tsx +1 -1
  74. package/src/stories-json/carousel.stories.tsx +1 -1
  75. package/src/stories-json/charts.stories.tsx +1 -1
  76. package/src/stories-json/chatbot.stories.tsx +1 -1
  77. package/src/stories-json/code-editor.stories.tsx +1 -1
  78. package/src/stories-json/collapsible.stories.tsx +1 -1
  79. package/src/stories-json/controls.stories.tsx +1 -1
  80. package/src/stories-json/crm-live-data.stories.tsx +154 -0
  81. package/src/stories-json/data-table.stories.tsx +80 -4
  82. package/src/stories-json/data_display_extras.stories.tsx +1 -1
  83. package/src/stories-json/date-picker.stories.tsx +1 -1
  84. package/src/stories-json/detail-view.stories.tsx +1 -1
  85. package/src/stories-json/dialog.stories.tsx +1 -1
  86. package/src/stories-json/feedback_extras.stories.tsx +1 -1
  87. package/src/stories-json/feedback_others.stories.tsx +1 -1
  88. package/src/stories-json/form-variants.stories.tsx +210 -0
  89. package/src/stories-json/form_advanced.stories.tsx +1 -1
  90. package/src/stories-json/form_extras.stories.tsx +1 -1
  91. package/src/stories-json/grid.stories.tsx +1 -1
  92. package/src/stories-json/icon.stories.tsx +1 -1
  93. package/src/stories-json/input.stories.tsx +1 -1
  94. package/src/stories-json/kanban.stories.tsx +1 -1
  95. package/src/stories-json/layout_extended.stories.tsx +1 -1
  96. package/src/stories-json/layout_flex.stories.tsx +1 -1
  97. package/src/stories-json/list-view.stories.tsx +1 -1
  98. package/src/stories-json/markdown.stories.tsx +1 -1
  99. package/src/stories-json/menus.stories.tsx +1 -1
  100. package/src/stories-json/metric-card.stories.tsx +1 -1
  101. package/src/stories-json/navigation-menu.stories.tsx +1 -1
  102. package/src/stories-json/object-aggrid-advanced.stories.tsx +389 -0
  103. package/src/stories-json/object-aggrid.stories.tsx +1 -1
  104. package/src/stories-json/object-form.stories.tsx +1 -1
  105. package/src/stories-json/object-gantt.stories.tsx +1 -1
  106. package/src/stories-json/object-grid.stories.tsx +159 -1
  107. package/src/stories-json/object-map.stories.tsx +1 -1
  108. package/src/stories-json/object-view.stories.tsx +1 -1
  109. package/src/stories-json/overlay_extras.stories.tsx +1 -1
  110. package/src/stories-json/overlay_others.stories.tsx +1 -1
  111. package/src/stories-json/resizable.stories.tsx +1 -1
  112. package/src/stories-json/select.stories.tsx +1 -1
  113. package/src/stories-json/separator.stories.tsx +1 -1
  114. package/src/stories-json/statistic.stories.tsx +1 -1
  115. package/src/stories-json/tabs.stories.tsx +1 -1
  116. package/src/stories-json/timeline.stories.tsx +1 -1
  117. package/src/stories-json/typography.stories.tsx +1 -1
  118. package/src/ui/slider.tsx +6 -2
  119. package/src/stories/Introduction.mdx +0 -34
@@ -0,0 +1,89 @@
1
+ import { Meta } from '@storybook/blocks';
2
+
3
+ <Meta title="Getting Started" />
4
+
5
+ # ObjectUI Component Library
6
+
7
+ ObjectUI is a **server-driven UI engine** that renders enterprise interfaces from JSON metadata.
8
+ Built on **React**, **Tailwind CSS**, and **Shadcn UI (Radix)**, it bridges the speed of
9
+ low-code with the design quality of hand-crafted components.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ # Core packages
15
+ pnpm add @object-ui/types @object-ui/core @object-ui/react
16
+
17
+ # UI layer
18
+ pnpm add @object-ui/components @object-ui/fields @object-ui/layout
19
+ ```
20
+
21
+ Peer dependencies — make sure these are in your project:
22
+
23
+ ```bash
24
+ pnpm add react react-dom tailwindcss
25
+ ```
26
+
27
+ ## Quick Usage
28
+
29
+ ```tsx
30
+ import { ObjectRenderer } from '@object-ui/react';
31
+
32
+ const schema = {
33
+ type: 'Card',
34
+ props: { title: 'Hello' },
35
+ children: [
36
+ {
37
+ type: 'Text',
38
+ props: { content: 'Rendered from JSON!' },
39
+ },
40
+ ],
41
+ };
42
+
43
+ export default function App() {
44
+ return <ObjectRenderer schema={schema} />;
45
+ }
46
+ ```
47
+
48
+ The `ObjectRenderer` resolves each node in the schema tree against the **Component Registry**,
49
+ producing a fully interactive React tree.
50
+
51
+ ## Accessibility
52
+
53
+ Every component in ObjectUI follows the **WAI-ARIA** authoring practices provided by
54
+ [Radix UI](https://www.radix-ui.com/). This means:
55
+
56
+ - Correct ARIA roles and attributes out of the box
57
+ - Full keyboard navigation support
58
+ - Focus management for overlays, dialogs, and menus
59
+ - Screen-reader-friendly labels and live regions
60
+
61
+ Run the Storybook accessibility addon (included) to audit any story for violations.
62
+
63
+ ## Theme Configuration
64
+
65
+ ObjectUI uses Tailwind CSS for styling. Customise the design tokens through your
66
+ `tailwind.config` and CSS variables:
67
+
68
+ ```css
69
+ @layer base {
70
+ :root {
71
+ --background: 0 0% 100%;
72
+ --foreground: 222 84% 5%;
73
+ --primary: 222 47% 11%;
74
+ --primary-foreground: 210 40% 98%;
75
+ /* ...other tokens */
76
+ }
77
+ }
78
+ ```
79
+
80
+ All Shadcn-based components pick up these tokens automatically — no prop drilling required.
81
+
82
+ ## Explore
83
+
84
+ Use the sidebar to browse every component. Each story shows:
85
+
86
+ - **Live preview** — interact directly in the canvas
87
+ - **Controls** — tweak props in real time
88
+ - **Docs** — auto-generated API tables (when tagged with `autodocs`)
89
+ - **Accessibility** — axe audit panel
@@ -0,0 +1,127 @@
1
+ import { Meta } from '@storybook/blocks';
2
+
3
+ <Meta title="Getting Started/Introduction" />
4
+
5
+ # ObjectUI — Universal Server-Driven UI Engine
6
+
7
+ ObjectUI is a **JSON-to-UI rendering engine** for React that transforms declarative schemas
8
+ into fully interactive enterprise interfaces. Built on **Shadcn UI**, **Radix Primitives**,
9
+ and **Tailwind CSS**, it bridges the speed of low-code platforms with the design quality of
10
+ hand-crafted components.
11
+
12
+ ---
13
+
14
+ ## Why ObjectUI?
15
+
16
+ | Benefit | Description |
17
+ |---|---|
18
+ | **Schema-Driven** | Define your UI as JSON — render it anywhere with zero custom JSX. |
19
+ | **Enterprise-Ready** | Dashboards, data grids, Kanbans, forms, and CRUDs out of the box. |
20
+ | **Accessible by Default** | Every component inherits WAI-ARIA patterns from Radix UI. |
21
+ | **Themeable** | Tailwind CSS design tokens + CSS variables — no prop drilling required. |
22
+ | **Backend Agnostic** | Works with any API or data source; no server lock-in. |
23
+
24
+ ---
25
+
26
+ ## Architecture Overview
27
+
28
+ ObjectUI follows a layered architecture where each layer has a single responsibility:
29
+
30
+ ```
31
+ ┌─────────────────────────────────────────────────────┐
32
+ │ Your Application │
33
+ ├─────────────────────────────────────────────────────┤
34
+ │ @object-ui/react (Runtime) │
35
+ │ ObjectRenderer · SchemaRenderer · Hooks │
36
+ ├──────────┬──────────────────────────┬───────────────┤
37
+ │ Plugins │ @object-ui/fields │ @object-ui/ │
38
+ │ Grid, │ Text, Number, Select, │ layout │
39
+ │ Kanban, │ Date, Checkbox, … │ AppShell, │
40
+ │ Charts, │ │ Sidebar, │
41
+ │ Form, … │ │ Header │
42
+ ├──────────┴──────────────────────────┴───────────────┤
43
+ │ @object-ui/components (Atoms) │
44
+ │ Button · Card · Badge · Dialog · Tabs · … │
45
+ ├─────────────────────────────────────────────────────┤
46
+ │ @object-ui/core (Engine) │
47
+ │ Component Registry · Schema Validation · │
48
+ │ Expression Evaluation · Data Binding │
49
+ ├─────────────────────────────────────────────────────┤
50
+ │ @object-ui/types (Protocol) │
51
+ │ ComponentSchema · ActionSchema · FieldSchema │
52
+ │ Pure TypeScript — 0 deps │
53
+ └─────────────────────────────────────────────────────┘
54
+ ```
55
+
56
+ ### Layer Breakdown
57
+
58
+ 1. **`@object-ui/types`** — Pure TypeScript interfaces that define the JSON protocol.
59
+ Zero runtime dependencies.
60
+ 2. **`@object-ui/core`** — The rendering engine: component registry, schema validation,
61
+ expression evaluation (`visible: "${data.age > 18}"`), and data binding. No UI code.
62
+ 3. **`@object-ui/components`** — Shadcn-based UI atoms (Button, Card, Badge, Dialog, etc.).
63
+ Pure presentation — no business logic.
64
+ 4. **`@object-ui/fields`** — Standard field renderers for form inputs (Text, Number,
65
+ Select, Date). Each field implements the `FieldWidgetProps` contract.
66
+ 5. **`@object-ui/layout`** — Page-level structure components (AppShell, Header, Sidebar).
67
+ Routing-aware composition.
68
+ 6. **`@object-ui/plugin-*`** — Complex view widgets (Grid, Kanban, Charts, Map, Gantt,
69
+ Form, Timeline). Heavy third-party dependencies are isolated here.
70
+ 7. **`@object-ui/react`** — The public runtime entry point that ties everything together.
71
+ Provides `ObjectRenderer`, hooks, and provider components.
72
+
73
+ ---
74
+
75
+ ## Quick Start
76
+
77
+ ```tsx
78
+ import { ObjectRenderer } from '@object-ui/react';
79
+
80
+ const schema = {
81
+ type: 'Card',
82
+ props: { title: 'Welcome' },
83
+ children: [
84
+ { type: 'Text', props: { content: 'Rendered from JSON!' } },
85
+ { type: 'Button', props: { label: 'Click me', variant: 'default' } },
86
+ ],
87
+ };
88
+
89
+ export default function App() {
90
+ return <ObjectRenderer schema={schema} />;
91
+ }
92
+ ```
93
+
94
+ The `ObjectRenderer` walks the schema tree, resolves each node against the **Component
95
+ Registry**, and produces a fully interactive React component tree.
96
+
97
+ ---
98
+
99
+ ## Browsing This Storybook
100
+
101
+ Use the **sidebar** on the left to explore every component. Stories are organised into:
102
+
103
+ | Section | What You'll Find |
104
+ |---|---|
105
+ | **Getting Started** | Introduction, data binding guides, and setup instructions. |
106
+ | **Primitives** | Base Shadcn atoms — Buttons, Cards, Badges, Inputs, Dialogs, and more. |
107
+ | **Fields** | Form field renderers — text, number, select, date, checkbox, etc. |
108
+ | **Plugins** | Complex view widgets — Data Grid, Kanban, Charts, Map, Gantt, Timeline. |
109
+ | **Templates** | Pre-built page layouts — Dashboards, Reports, Sidebar navigation. |
110
+ | **Apps** | Full application demos (e.g. CRM) composed from multiple plugins. |
111
+
112
+ Each story provides:
113
+
114
+ - **Canvas** — Live interactive preview.
115
+ - **Controls** — Tweak JSON props in real time via the controls panel.
116
+ - **Docs** — Auto-generated API reference (for stories tagged `autodocs`).
117
+ - **Accessibility** — axe-core audit panel to check WCAG compliance.
118
+
119
+ ---
120
+
121
+ ## Documentation
122
+
123
+ Full documentation, migration guides, and API references are available at the
124
+ [ObjectUI docs site](https://objectui.dev).
125
+
126
+ For source code and contribution guidelines, visit the
127
+ [GitHub repository](https://github.com/objectstack-ai/objectui).
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Components/Accordion',
6
+ title: 'Primitives/Data Display/Accordion',
7
7
  component: SchemaRenderer,
8
8
  parameters: { layout: 'padded' },
9
9
  tags: ['autodocs'],
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Views/Data Grid (AgGrid)',
6
+ title: 'Plugins/Data Views/AgGrid',
7
7
  component: SchemaRenderer,
8
8
  parameters: {
9
9
  layout: 'padded',
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Components/Alert',
6
+ title: 'Primitives/Feedback/Alert',
7
7
  component: SchemaRenderer,
8
8
  parameters: { layout: 'padded' },
9
9
  tags: ['autodocs'],
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Components/Aspect Ratio',
6
+ title: 'Primitives/Data Display/Aspect Ratio',
7
7
  component: SchemaRenderer,
8
8
  parameters: { layout: 'centered' },
9
9
  tags: ['autodocs'],
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Components/Avatar',
6
+ title: 'Primitives/Data Display/Avatar',
7
7
  component: SchemaRenderer,
8
8
  parameters: { layout: 'centered' },
9
9
  tags: ['autodocs'],
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Components/Badge',
6
+ title: 'Primitives/Data Display/Badge',
7
7
  component: SchemaRenderer,
8
8
  parameters: { layout: 'centered' },
9
9
  tags: ['autodocs'],
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Components/Breadcrumb',
6
+ title: 'Primitives/Navigation/Breadcrumb',
7
7
  component: SchemaRenderer,
8
8
  parameters: { layout: 'centered' },
9
9
  tags: ['autodocs'],
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Components/Button Group',
6
+ title: 'Primitives/General/Button Group',
7
7
  component: SchemaRenderer,
8
8
  parameters: { layout: 'centered' },
9
9
  tags: ['autodocs'],
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Components/Button',
6
+ title: 'Primitives/General/Button',
7
7
  component: SchemaRenderer,
8
8
  parameters: {
9
9
  layout: 'centered',
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Components/Calendar',
6
+ title: 'Plugins/Scheduling/Calendar',
7
7
  component: SchemaRenderer,
8
8
  parameters: {
9
9
  layout: 'padded',
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Components/Card',
6
+ title: 'Primitives/Data Display/Card',
7
7
  component: SchemaRenderer,
8
8
  parameters: {
9
9
  layout: 'padded',
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Components/Carousel',
6
+ title: 'Primitives/Data Display/Carousel',
7
7
  component: SchemaRenderer,
8
8
  parameters: { layout: 'centered' },
9
9
  tags: ['autodocs'],
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Views/Charts',
6
+ title: 'Plugins/Rich Content/Charts',
7
7
  component: SchemaRenderer,
8
8
  parameters: {
9
9
  layout: 'padded',
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Views/Chatbot',
6
+ title: 'Plugins/Rich Content/Chatbot',
7
7
  component: SchemaRenderer,
8
8
  parameters: {
9
9
  layout: 'centered',
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Views/Code Editor',
6
+ title: 'Plugins/Rich Content/Code Editor',
7
7
  component: SchemaRenderer,
8
8
  parameters: {
9
9
  layout: 'padded',
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Components/Collapsible',
6
+ title: 'Primitives/Data Display/Collapsible',
7
7
  component: SchemaRenderer,
8
8
  parameters: { layout: 'centered' },
9
9
  tags: ['autodocs'],
@@ -3,7 +3,7 @@ import { SchemaRenderer } from '../SchemaRenderer';
3
3
  import type { BaseSchema } from '@object-ui/types';
4
4
 
5
5
  const meta = {
6
- title: 'Components/Controls',
6
+ title: 'Primitives/Data Entry/Controls',
7
7
  component: SchemaRenderer,
8
8
  parameters: { layout: 'centered' },
9
9
  tags: ['autodocs'],
@@ -0,0 +1,154 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import React, { useEffect, useState, useCallback } from 'react';
3
+ import { SchemaRenderer, SchemaRendererProvider } from '@object-ui/react';
4
+ import type { BaseSchema } from '@object-ui/types';
5
+ import { createStorybookDataSource } from '@storybook-config/datasource';
6
+
7
+ const meta: Meta = {
8
+ title: 'Plugins/Data Views/CRM Live Data',
9
+ parameters: {
10
+ layout: 'padded',
11
+ },
12
+ };
13
+
14
+ export default meta;
15
+
16
+ const dataSource = createStorybookDataSource();
17
+
18
+ // ==========================================
19
+ // Helper: Fetches data from MSW and renders a schema
20
+ // ==========================================
21
+ const LiveDataView = ({
22
+ objectName,
23
+ schema,
24
+ title
25
+ }: {
26
+ objectName: string;
27
+ schema: (data: any[]) => BaseSchema;
28
+ title: string;
29
+ }) => {
30
+ const [data, setData] = useState<any[]>([]);
31
+ const [loading, setLoading] = useState(true);
32
+ const [error, setError] = useState<string | null>(null);
33
+
34
+ const fetchData = useCallback(async () => {
35
+ setLoading(true);
36
+ setError(null);
37
+ try {
38
+ const result = await dataSource.find(objectName, { $top: 50 });
39
+ setData(result.data as any[]);
40
+ } catch (err: any) {
41
+ console.error(`[CRM Live] Failed to fetch ${objectName}:`, err);
42
+ setError(err?.message || `Failed to fetch ${objectName}`);
43
+ } finally {
44
+ setLoading(false);
45
+ }
46
+ }, [objectName]);
47
+
48
+ useEffect(() => {
49
+ fetchData();
50
+ }, [fetchData]);
51
+
52
+ if (loading) return <div className="p-8 text-muted-foreground">Loading {title} from MSW API...</div>;
53
+ if (error) return (
54
+ <div className="p-8 space-y-2">
55
+ <div className="text-destructive font-medium">API Error: {error}</div>
56
+ <div className="text-sm text-muted-foreground">
57
+ Ensure the ObjectStack MSW runtime is running. Check browser console for logs.
58
+ </div>
59
+ </div>
60
+ );
61
+
62
+ return (
63
+ <SchemaRendererProvider dataSource={dataSource}>
64
+ <div className="space-y-4">
65
+ <h2 className="text-lg font-semibold">{title} ({data.length} records)</h2>
66
+ <SchemaRenderer schema={schema(data)} />
67
+ </div>
68
+ </SchemaRendererProvider>
69
+ );
70
+ };
71
+
72
+ // ==========================================
73
+ // Contact Grid from MSW
74
+ // ==========================================
75
+ export const ContactGrid: StoryObj = {
76
+ name: 'Contact Grid (Live)',
77
+ render: () => (
78
+ <LiveDataView
79
+ objectName="contact"
80
+ title="Contacts"
81
+ schema={(data) => ({
82
+ type: 'object-grid',
83
+ objectName: 'contact',
84
+ columns: [
85
+ { field: 'name', header: 'Name', sortable: true, filterable: true },
86
+ { field: 'email', header: 'Email', sortable: true },
87
+ { field: 'title', header: 'Title' },
88
+ { field: 'department', header: 'Department' },
89
+ { field: 'status', header: 'Status', sortable: true },
90
+ ],
91
+ data,
92
+ pagination: true,
93
+ pageSize: 10,
94
+ className: 'w-full',
95
+ } as any)}
96
+ />
97
+ ),
98
+ };
99
+
100
+ // ==========================================
101
+ // Account Grid from MSW
102
+ // ==========================================
103
+ export const AccountGrid: StoryObj = {
104
+ name: 'Account Grid (Live)',
105
+ render: () => (
106
+ <LiveDataView
107
+ objectName="account"
108
+ title="Accounts"
109
+ schema={(data) => ({
110
+ type: 'object-grid',
111
+ objectName: 'account',
112
+ columns: [
113
+ { field: 'name', header: 'Company', sortable: true, filterable: true },
114
+ { field: 'industry', header: 'Industry', sortable: true },
115
+ { field: 'type', header: 'Type' },
116
+ { field: 'employees', header: 'Employees', type: 'number' },
117
+ { field: 'phone', header: 'Phone' },
118
+ ],
119
+ data,
120
+ pagination: true,
121
+ pageSize: 10,
122
+ className: 'w-full',
123
+ } as any)}
124
+ />
125
+ ),
126
+ };
127
+
128
+ // ==========================================
129
+ // Opportunity Grid from MSW
130
+ // ==========================================
131
+ export const OpportunityGrid: StoryObj = {
132
+ name: 'Opportunity Grid (Live)',
133
+ render: () => (
134
+ <LiveDataView
135
+ objectName="opportunity"
136
+ title="Opportunities"
137
+ schema={(data) => ({
138
+ type: 'object-grid',
139
+ objectName: 'opportunity',
140
+ columns: [
141
+ { field: 'name', header: 'Opportunity', sortable: true },
142
+ { field: 'amount', header: 'Amount', type: 'currency', sortable: true },
143
+ { field: 'stage', header: 'Stage', sortable: true },
144
+ { field: 'probability', header: 'Probability' },
145
+ { field: 'close_date', header: 'Close Date', type: 'date' },
146
+ ],
147
+ data,
148
+ pagination: true,
149
+ pageSize: 10,
150
+ className: 'w-full',
151
+ } as any)}
152
+ />
153
+ ),
154
+ };
@@ -1,8 +1,10 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react';
2
- import { SchemaRenderer } from '../SchemaRenderer';
2
+ import { SchemaRenderer, SchemaRendererProvider } from '@object-ui/react';
3
+ import type { BaseSchema } from '@object-ui/types';
4
+ import { createStorybookDataSource } from '@storybook-config/datasource';
3
5
 
4
6
  const meta: Meta = {
5
- title: 'Components/Table',
7
+ title: 'Primitives/Data Display/Table',
6
8
  component: SchemaRenderer,
7
9
  tags: ['autodocs'],
8
10
  argTypes: {
@@ -13,6 +15,15 @@ const meta: Meta = {
13
15
  export default meta;
14
16
  type Story = StoryObj<typeof meta>;
15
17
 
18
+ // Create a DataSource instance that connects to MSW
19
+ const dataSource = createStorybookDataSource();
20
+
21
+ const renderStory = (args: any) => (
22
+ <SchemaRendererProvider dataSource={dataSource}>
23
+ <SchemaRenderer schema={args as unknown as BaseSchema} />
24
+ </SchemaRendererProvider>
25
+ );
26
+
16
27
  export const DataTable: Story = {
17
28
  args: {
18
29
  type: 'data-table',
@@ -29,7 +40,7 @@ export const DataTable: Story = {
29
40
  { id: 3, name: 'Bob Johnson', email: 'bob@example.com', role: 'User' }
30
41
  ]
31
42
  },
32
- render: (args) => <SchemaRenderer schema={args} />
43
+ render: renderStory
33
44
  };
34
45
 
35
46
  export const FullFeatures: Story = {
@@ -56,5 +67,70 @@ export const FullFeatures: Story = {
56
67
  method: i % 2 === 0 ? 'Credit Card' : 'PayPal'
57
68
  }))
58
69
  },
59
- render: (args) => <SchemaRenderer schema={args} />
70
+ render: renderStory
71
+ };
72
+
73
+ export const EditableTable: Story = {
74
+ args: {
75
+ type: 'data-table',
76
+ caption: 'Editable Product Inventory - Simple Cell Editing',
77
+ searchable: false,
78
+ pagination: false,
79
+ editable: true,
80
+ columns: [
81
+ { header: 'SKU', accessorKey: 'sku', width: '100px', editable: false },
82
+ { header: 'Product Name', accessorKey: 'name' },
83
+ { header: 'Price', accessorKey: 'price' },
84
+ { header: 'Stock', accessorKey: 'stock' }
85
+ ],
86
+ data: [
87
+ { sku: 'PROD-001', name: 'Laptop', price: '$1299.99', stock: 15 },
88
+ { sku: 'PROD-002', name: 'Mouse', price: '$29.99', stock: 120 },
89
+ { sku: 'PROD-003', name: 'Keyboard', price: '$79.99', stock: 45 },
90
+ { sku: 'PROD-004', name: 'Monitor', price: '$399.99', stock: 22 }
91
+ ],
92
+ onCellChange: (rowIndex: number, columnKey: string, newValue: any, row: any) => {
93
+ console.log('Cell edited:', { rowIndex, columnKey, newValue, row });
94
+ alert(`Updated ${columnKey} to "${newValue}" for ${row.name}`);
95
+ }
96
+ },
97
+ render: renderStory
60
98
  };
99
+
100
+ export const BatchEditTable: Story = {
101
+ args: {
102
+ type: 'data-table',
103
+ caption: 'Batch Edit Mode - Edit Multiple Rows & Save Together (💡 Double-click cells to edit, then see save buttons appear)',
104
+ searchable: false,
105
+ pagination: false,
106
+ editable: true,
107
+ rowActions: true,
108
+ columns: [
109
+ { header: 'ID', accessorKey: 'id', width: '60px', editable: false },
110
+ { header: 'Product Name', accessorKey: 'name' },
111
+ { header: 'Category', accessorKey: 'category' },
112
+ { header: 'Price', accessorKey: 'price' },
113
+ { header: 'Stock', accessorKey: 'stock' }
114
+ ],
115
+ data: [
116
+ { id: 1, name: 'Wireless Mouse', category: 'Electronics', price: '$29.99', stock: 50 },
117
+ { id: 2, name: 'USB-C Cable', category: 'Accessories', price: '$12.99', stock: 100 },
118
+ { id: 3, name: 'Laptop Stand', category: 'Accessories', price: '$45.99', stock: 25 },
119
+ { id: 4, name: 'Webcam HD', category: 'Electronics', price: '$79.99', stock: 15 },
120
+ { id: 5, name: 'Desk Lamp', category: 'Furniture', price: '$34.99', stock: 30 }
121
+ ],
122
+ onRowSave: async (rowIndex: number, changes: Record<string, any>, row: any) => {
123
+ console.log('Saving single row:', { rowIndex, changes, row });
124
+ await new Promise(resolve => setTimeout(resolve, 500));
125
+ alert(`✓ Saved changes for "${row.name}":\n${JSON.stringify(changes, null, 2)}`);
126
+ },
127
+ onBatchSave: async (allChanges: Array<{ rowIndex: number; changes: Record<string, any>; row: any }>) => {
128
+ console.log('Batch saving all rows:', allChanges);
129
+ await new Promise(resolve => setTimeout(resolve, 800));
130
+ const summary = allChanges.map(c => `${c.row.name}: ${Object.keys(c.changes).length} field(s)`).join('\n');
131
+ alert(`✓ Batch saved ${allChanges.length} rows:\n\n${summary}`);
132
+ }
133
+ },
134
+ render: renderStory
135
+ };
136
+
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { SchemaRenderer } from '../SchemaRenderer';
3
3
 
4
4
  const meta: Meta = {
5
- title: 'Components/Data Display Extras',
5
+ title: 'Primitives/Data Display/Extras',
6
6
  component: SchemaRenderer,
7
7
  tags: ['autodocs'],
8
8
  argTypes: {