@object-ui/components 0.5.0 → 2.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.
- package/.turbo/turbo-build.log +12 -25
- package/CHANGELOG.md +13 -0
- package/dist/index.css +1 -1
- package/dist/index.js +23366 -22221
- package/dist/index.umd.cjs +30 -30
- package/dist/src/custom/action-param-dialog.d.ts +21 -0
- package/dist/src/custom/index.d.ts +2 -0
- package/dist/src/custom/navigation-overlay.d.ts +50 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/renderers/action/action-button.d.ts +11 -0
- package/dist/src/renderers/action/action-group.d.ts +25 -0
- package/dist/src/renderers/action/action-icon.d.ts +10 -0
- package/dist/src/renderers/action/action-menu.d.ts +19 -0
- package/dist/src/renderers/action/index.d.ts +0 -0
- package/dist/src/renderers/action/resolve-icon.d.ts +6 -0
- package/package.json +9 -8
- package/src/__tests__/PageRendererRegions.test.tsx +664 -55
- package/src/__tests__/compliance.test.tsx +72 -0
- package/src/__tests__/navigation-overlay.test.tsx +273 -0
- package/src/__tests__/view-compliance.test.tsx +153 -0
- package/src/custom/action-param-dialog.tsx +264 -0
- package/src/custom/index.ts +2 -0
- package/src/custom/navigation-overlay.tsx +296 -0
- package/src/index.ts +1 -0
- package/src/renderers/action/action-button.tsx +147 -0
- package/src/renderers/action/action-group.tsx +270 -0
- package/src/renderers/action/action-icon.tsx +150 -0
- package/src/renderers/action/action-menu.tsx +203 -0
- package/src/renderers/action/index.ts +18 -0
- package/src/renderers/action/resolve-icon.ts +35 -0
- package/src/renderers/complex/__tests__/data-table-batch-editing.test.tsx +275 -0
- package/src/renderers/complex/__tests__/data-table-cell-renderer.test.tsx +120 -0
- package/src/renderers/complex/__tests__/data-table-editing.test.tsx +221 -0
- package/src/renderers/complex/data-table.tsx +242 -21
- package/src/renderers/form/form.tsx +23 -4
- package/src/renderers/index.ts +1 -0
- package/src/renderers/layout/page.tsx +416 -52
- package/src/renderers/navigation/sidebar.tsx +6 -0
- package/src/renderers/placeholders.tsx +2 -2
- package/src/stories/Introduction.mdx +54 -27
- package/src/stories/MockedData.stories.tsx +87 -37
- package/src/stories-json/accordion.stories.tsx +1 -1
- package/src/stories-json/aggrid.stories.tsx +1 -1
- package/src/stories-json/alert.stories.tsx +1 -1
- package/src/stories-json/aspect-ratio.stories.tsx +1 -1
- package/src/stories-json/avatar.stories.tsx +1 -1
- package/src/stories-json/badge.stories.tsx +1 -1
- package/src/stories-json/breadcrumb.stories.tsx +1 -1
- package/src/stories-json/button-group.stories.tsx +1 -1
- package/src/stories-json/button.stories.tsx +1 -1
- package/src/stories-json/calendar.stories.tsx +1 -1
- package/src/stories-json/card.stories.tsx +1 -1
- package/src/stories-json/carousel.stories.tsx +1 -1
- package/src/stories-json/charts.stories.tsx +1 -1
- package/src/stories-json/chatbot.stories.tsx +1 -1
- package/src/stories-json/code-editor.stories.tsx +1 -1
- package/src/stories-json/collapsible.stories.tsx +1 -1
- package/src/stories-json/controls.stories.tsx +1 -1
- package/src/stories-json/crm-live-data.stories.tsx +154 -0
- package/src/stories-json/data-table.stories.tsx +80 -4
- package/src/stories-json/data_display_extras.stories.tsx +1 -1
- package/src/stories-json/date-picker.stories.tsx +1 -1
- package/src/stories-json/detail-view.stories.tsx +1 -1
- package/src/stories-json/dialog.stories.tsx +1 -1
- package/src/stories-json/feedback_extras.stories.tsx +1 -1
- package/src/stories-json/feedback_others.stories.tsx +1 -1
- package/src/stories-json/form-variants.stories.tsx +210 -0
- package/src/stories-json/form_advanced.stories.tsx +1 -1
- package/src/stories-json/form_extras.stories.tsx +1 -1
- package/src/stories-json/grid.stories.tsx +1 -1
- package/src/stories-json/icon.stories.tsx +1 -1
- package/src/stories-json/input.stories.tsx +1 -1
- package/src/stories-json/kanban.stories.tsx +1 -1
- package/src/stories-json/layout_extended.stories.tsx +1 -1
- package/src/stories-json/layout_flex.stories.tsx +1 -1
- package/src/stories-json/list-view.stories.tsx +1 -1
- package/src/stories-json/markdown.stories.tsx +1 -1
- package/src/stories-json/menus.stories.tsx +1 -1
- package/src/stories-json/metric-card.stories.tsx +1 -1
- package/src/stories-json/navigation-menu.stories.tsx +1 -1
- package/src/stories-json/object-aggrid-advanced.stories.tsx +389 -0
- package/src/stories-json/object-aggrid.stories.tsx +1 -1
- package/src/stories-json/object-form.stories.tsx +1 -1
- package/src/stories-json/object-gantt.stories.tsx +1 -1
- package/src/stories-json/object-grid.stories.tsx +159 -1
- package/src/stories-json/object-map.stories.tsx +1 -1
- package/src/stories-json/object-view.stories.tsx +1 -1
- package/src/stories-json/overlay_extras.stories.tsx +1 -1
- package/src/stories-json/overlay_others.stories.tsx +1 -1
- package/src/stories-json/resizable.stories.tsx +1 -1
- package/src/stories-json/select.stories.tsx +1 -1
- package/src/stories-json/separator.stories.tsx +1 -1
- package/src/stories-json/statistic.stories.tsx +1 -1
- package/src/stories-json/tabs.stories.tsx +1 -1
- package/src/stories-json/timeline.stories.tsx +1 -1
- package/src/stories-json/typography.stories.tsx +1 -1
|
@@ -1,71 +1,121 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import React, { useEffect, useState, useCallback } from 'react';
|
|
3
3
|
import { SchemaRenderer, SchemaRendererProvider } from '@object-ui/react';
|
|
4
|
-
import {
|
|
4
|
+
import type { BaseSchema } from '@object-ui/types';
|
|
5
|
+
import { createStorybookDataSource } from '@storybook-config/datasource';
|
|
5
6
|
|
|
6
|
-
//
|
|
7
|
-
|
|
7
|
+
// ==========================================
|
|
8
|
+
// Story 1: Static Data Binding
|
|
9
|
+
// ==========================================
|
|
10
|
+
// Demonstrates how JSON schemas can reference data via expressions like ${data.field}
|
|
11
|
+
|
|
12
|
+
const staticDataSchema: BaseSchema = {
|
|
8
13
|
type: "page",
|
|
9
|
-
props: { title: "
|
|
14
|
+
props: { title: "Static Data Binding" },
|
|
10
15
|
children: [
|
|
11
16
|
{
|
|
12
17
|
type: "page:header",
|
|
13
18
|
props: {
|
|
14
|
-
title: "
|
|
15
|
-
description: "
|
|
19
|
+
title: "Sarah Connors",
|
|
20
|
+
description: "Lead Engineer at Cyberdyne Systems"
|
|
16
21
|
}
|
|
17
22
|
},
|
|
18
23
|
{
|
|
19
|
-
type: "
|
|
20
|
-
props: {
|
|
24
|
+
type: "grid",
|
|
25
|
+
props: { cols: 2, gap: 4, className: "mt-4" },
|
|
21
26
|
children: [
|
|
22
|
-
{ type: "
|
|
23
|
-
{ type: "
|
|
24
|
-
{ type: "
|
|
27
|
+
{ type: "card", title: "Full Name", children: [{ type: "text", content: "Sarah Connors" }] },
|
|
28
|
+
{ type: "card", title: "Email", children: [{ type: "text", content: "sarah@cyberdyne.com" }] },
|
|
29
|
+
{ type: "card", title: "Status", children: [{ type: "badge", props: { variant: "default", children: "Active" } }] },
|
|
30
|
+
{ type: "card", title: "Department", children: [{ type: "text", content: "Engineering" }] },
|
|
25
31
|
]
|
|
26
32
|
}
|
|
27
33
|
]
|
|
28
34
|
};
|
|
29
35
|
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
// ==========================================
|
|
37
|
+
// Story 2: MSW-Backed Data (Live API)
|
|
38
|
+
// ==========================================
|
|
39
|
+
// The ObjectStack kernel seeds CRM data via MSW. This story fetches contacts from /api/v1.
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
// Simulate a fetch call locally since MSW might not be configured in this environment
|
|
36
|
-
const mockData = {
|
|
37
|
-
name: "Sarah Connors",
|
|
38
|
-
title: "Lead Engineer",
|
|
39
|
-
company: "Cyberdyne Systems",
|
|
40
|
-
email: "sarah@cyberdyne.com",
|
|
41
|
-
status: "Active"
|
|
42
|
-
};
|
|
41
|
+
const dataSource = createStorybookDataSource();
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
const ContactListFromAPI = () => {
|
|
44
|
+
const [contacts, setContacts] = useState<any[]>([]);
|
|
45
|
+
const [loading, setLoading] = useState(true);
|
|
46
|
+
const [error, setError] = useState<string | null>(null);
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
const fetchContacts = useCallback(async () => {
|
|
49
|
+
setLoading(true);
|
|
50
|
+
setError(null);
|
|
51
|
+
try {
|
|
52
|
+
const result = await dataSource.find('contact', { $top: 10 });
|
|
53
|
+
setContacts(result.data as any[]);
|
|
54
|
+
} catch (err: any) {
|
|
55
|
+
console.error('[Data Binding] Failed to fetch contacts:', err);
|
|
56
|
+
setError(err?.message || 'Failed to fetch data from MSW API');
|
|
57
|
+
} finally {
|
|
58
|
+
setLoading(false);
|
|
59
|
+
}
|
|
49
60
|
}, []);
|
|
50
61
|
|
|
51
|
-
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
fetchContacts();
|
|
64
|
+
}, [fetchContacts]);
|
|
65
|
+
|
|
66
|
+
if (loading) return <div className="p-8 text-muted-foreground">Loading contacts from MSW API...</div>;
|
|
67
|
+
if (error) return (
|
|
68
|
+
<div className="p-8 space-y-2">
|
|
69
|
+
<div className="text-destructive font-medium">API Error: {error}</div>
|
|
70
|
+
<div className="text-sm text-muted-foreground">
|
|
71
|
+
This story requires the ObjectStack MSW runtime to be running.
|
|
72
|
+
Check the browser console for [Storybook MSW] logs.
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const gridSchema: BaseSchema = {
|
|
78
|
+
type: 'object-grid',
|
|
79
|
+
objectName: 'contact',
|
|
80
|
+
columns: [
|
|
81
|
+
{ field: 'name', header: 'Name', sortable: true },
|
|
82
|
+
{ field: 'email', header: 'Email', sortable: true },
|
|
83
|
+
{ field: 'title', header: 'Title' },
|
|
84
|
+
{ field: 'status', header: 'Status' },
|
|
85
|
+
],
|
|
86
|
+
data: contacts,
|
|
87
|
+
className: 'w-full'
|
|
88
|
+
} as any;
|
|
52
89
|
|
|
53
90
|
return (
|
|
54
|
-
<SchemaRendererProvider dataSource={
|
|
55
|
-
<
|
|
91
|
+
<SchemaRendererProvider dataSource={dataSource}>
|
|
92
|
+
<div className="space-y-4">
|
|
93
|
+
<div className="flex items-center justify-between">
|
|
94
|
+
<h2 className="text-lg font-semibold">Contacts from MSW ({contacts.length} records)</h2>
|
|
95
|
+
</div>
|
|
96
|
+
<SchemaRenderer schema={gridSchema} />
|
|
97
|
+
</div>
|
|
56
98
|
</SchemaRendererProvider>
|
|
57
99
|
);
|
|
58
100
|
};
|
|
59
101
|
|
|
102
|
+
// ==========================================
|
|
103
|
+
// Meta
|
|
104
|
+
// ==========================================
|
|
105
|
+
|
|
60
106
|
const meta: Meta = {
|
|
61
|
-
title: '
|
|
62
|
-
component: DataFetcher,
|
|
107
|
+
title: 'Getting Started/Data Binding',
|
|
63
108
|
parameters: {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
109
|
+
layout: 'padded',
|
|
110
|
+
},
|
|
67
111
|
};
|
|
68
112
|
|
|
69
113
|
export default meta;
|
|
70
114
|
|
|
71
|
-
export const
|
|
115
|
+
export const StaticData: StoryObj = {
|
|
116
|
+
render: () => <SchemaRenderer schema={staticDataSchema} />,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export const LiveAPI: StoryObj = {
|
|
120
|
+
render: () => <ContactListFromAPI />,
|
|
121
|
+
};
|
|
@@ -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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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 '
|
|
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: '
|
|
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:
|
|
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:
|
|
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: '
|
|
5
|
+
title: 'Primitives/Data Display/Extras',
|
|
6
6
|
component: SchemaRenderer,
|
|
7
7
|
tags: ['autodocs'],
|
|
8
8
|
argTypes: {
|
|
@@ -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: '
|
|
6
|
+
title: 'Primitives/Data Entry/Date Picker',
|
|
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: '
|
|
6
|
+
title: 'Primitives/Feedback/Dialog',
|
|
7
7
|
component: SchemaRenderer,
|
|
8
8
|
parameters: { layout: 'centered' },
|
|
9
9
|
tags: ['autodocs'],
|
|
@@ -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: '
|
|
5
|
+
title: 'Primitives/Feedback/Extras',
|
|
6
6
|
component: SchemaRenderer,
|
|
7
7
|
tags: ['autodocs'],
|
|
8
8
|
};
|
|
@@ -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: '
|
|
6
|
+
title: 'Primitives/Feedback/Others',
|
|
7
7
|
component: SchemaRenderer,
|
|
8
8
|
parameters: { layout: 'centered' },
|
|
9
9
|
tags: ['autodocs'],
|