@object-ui/components 0.3.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/CHANGELOG.md +46 -0
- package/LICENSE +21 -0
- package/README.md +170 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +46186 -0
- package/dist/index.umd.cjs +92 -0
- package/dist/src/hooks/use-mobile.d.ts +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.test.d.ts +1 -0
- package/dist/src/lib/utils.d.ts +4 -0
- package/dist/src/new-components.test.d.ts +1 -0
- package/dist/src/renderers/basic/div.d.ts +1 -0
- package/dist/src/renderers/basic/html.d.ts +1 -0
- package/dist/src/renderers/basic/icon.d.ts +1 -0
- package/dist/src/renderers/basic/image.d.ts +1 -0
- package/dist/src/renderers/basic/index.d.ts +0 -0
- package/dist/src/renderers/basic/separator.d.ts +1 -0
- package/dist/src/renderers/basic/span.d.ts +1 -0
- package/dist/src/renderers/basic/text.d.ts +1 -0
- package/dist/src/renderers/complex/__tests__/data-table.test.d.ts +0 -0
- package/dist/src/renderers/complex/calendar-view.d.ts +1 -0
- package/dist/src/renderers/complex/carousel.d.ts +1 -0
- package/dist/src/renderers/complex/chatbot.d.ts +1 -0
- package/dist/src/renderers/complex/chatbot.test.d.ts +1 -0
- package/dist/src/renderers/complex/data-table.d.ts +1 -0
- package/dist/src/renderers/complex/filter-builder.d.ts +1 -0
- package/dist/src/renderers/complex/index.d.ts +0 -0
- package/dist/src/renderers/complex/resizable.d.ts +1 -0
- package/dist/src/renderers/complex/scroll-area.d.ts +1 -0
- package/dist/src/renderers/complex/table.d.ts +1 -0
- package/dist/src/renderers/complex/timeline.d.ts +1 -0
- package/dist/src/renderers/data-display/alert.d.ts +1 -0
- package/dist/src/renderers/data-display/avatar.d.ts +1 -0
- package/dist/src/renderers/data-display/badge.d.ts +1 -0
- package/dist/src/renderers/data-display/index.d.ts +0 -0
- package/dist/src/renderers/data-display/list.d.ts +1 -0
- package/dist/src/renderers/data-display/statistic.d.ts +1 -0
- package/dist/src/renderers/data-display/tree-view.d.ts +1 -0
- package/dist/src/renderers/disclosure/accordion.d.ts +1 -0
- package/dist/src/renderers/disclosure/collapsible.d.ts +1 -0
- package/dist/src/renderers/disclosure/index.d.ts +0 -0
- package/dist/src/renderers/feedback/index.d.ts +0 -0
- package/dist/src/renderers/feedback/loading.d.ts +1 -0
- package/dist/src/renderers/feedback/progress.d.ts +1 -0
- package/dist/src/renderers/feedback/skeleton.d.ts +1 -0
- package/dist/src/renderers/feedback/toaster.d.ts +1 -0
- package/dist/src/renderers/form/button.d.ts +1 -0
- package/dist/src/renderers/form/calendar.d.ts +1 -0
- package/dist/src/renderers/form/checkbox.d.ts +1 -0
- package/dist/src/renderers/form/date-picker.d.ts +1 -0
- package/dist/src/renderers/form/file-upload.d.ts +1 -0
- package/dist/src/renderers/form/form.d.ts +1 -0
- package/dist/src/renderers/form/index.d.ts +0 -0
- package/dist/src/renderers/form/input-otp.d.ts +1 -0
- package/dist/src/renderers/form/input.d.ts +1 -0
- package/dist/src/renderers/form/label.d.ts +1 -0
- package/dist/src/renderers/form/radio-group.d.ts +1 -0
- package/dist/src/renderers/form/select.d.ts +1 -0
- package/dist/src/renderers/form/slider.d.ts +1 -0
- package/dist/src/renderers/form/switch.d.ts +1 -0
- package/dist/src/renderers/form/textarea.d.ts +1 -0
- package/dist/src/renderers/form/toggle.d.ts +1 -0
- package/dist/src/renderers/index.d.ts +0 -0
- package/dist/src/renderers/layout/card.d.ts +1 -0
- package/dist/src/renderers/layout/container.d.ts +1 -0
- package/dist/src/renderers/layout/flex.d.ts +1 -0
- package/dist/src/renderers/layout/grid.d.ts +1 -0
- package/dist/src/renderers/layout/index.d.ts +0 -0
- package/dist/src/renderers/layout/page.d.ts +7 -0
- package/dist/src/renderers/layout/semantic.d.ts +1 -0
- package/dist/src/renderers/layout/stack.d.ts +1 -0
- package/dist/src/renderers/layout/tabs.d.ts +1 -0
- package/dist/src/renderers/navigation/header-bar.d.ts +1 -0
- package/dist/src/renderers/navigation/index.d.ts +0 -0
- package/dist/src/renderers/navigation/sidebar.d.ts +1 -0
- package/dist/src/renderers/overlay/alert-dialog.d.ts +1 -0
- package/dist/src/renderers/overlay/context-menu.d.ts +1 -0
- package/dist/src/renderers/overlay/dialog.d.ts +1 -0
- package/dist/src/renderers/overlay/drawer.d.ts +1 -0
- package/dist/src/renderers/overlay/dropdown-menu.d.ts +1 -0
- package/dist/src/renderers/overlay/hover-card.d.ts +1 -0
- package/dist/src/renderers/overlay/index.d.ts +0 -0
- package/dist/src/renderers/overlay/popover.d.ts +1 -0
- package/dist/src/renderers/overlay/sheet.d.ts +1 -0
- package/dist/src/renderers/overlay/tooltip.d.ts +1 -0
- package/dist/src/ui/accordion.d.ts +7 -0
- package/dist/src/ui/alert-dialog.d.ts +14 -0
- package/dist/src/ui/alert.d.ts +9 -0
- package/dist/src/ui/aspect-ratio.d.ts +3 -0
- package/dist/src/ui/avatar.d.ts +6 -0
- package/dist/src/ui/badge.d.ts +9 -0
- package/dist/src/ui/breadcrumb.d.ts +11 -0
- package/dist/src/ui/button-group.d.ts +11 -0
- package/dist/src/ui/button.d.ts +13 -0
- package/dist/src/ui/calendar-view.d.ts +21 -0
- package/dist/src/ui/calendar.d.ts +8 -0
- package/dist/src/ui/card.d.ts +9 -0
- package/dist/src/ui/carousel.d.ts +19 -0
- package/dist/src/ui/chatbot.d.ts +36 -0
- package/dist/src/ui/checkbox.d.ts +4 -0
- package/dist/src/ui/collapsible.d.ts +5 -0
- package/dist/src/ui/command.d.ts +18 -0
- package/dist/src/ui/context-menu.d.ts +25 -0
- package/dist/src/ui/dialog.d.ts +15 -0
- package/dist/src/ui/drawer.d.ts +13 -0
- package/dist/src/ui/dropdown-menu.d.ts +25 -0
- package/dist/src/ui/empty.d.ts +11 -0
- package/dist/src/ui/field.d.ts +24 -0
- package/dist/src/ui/filter-builder.d.ts +31 -0
- package/dist/src/ui/form.d.ts +24 -0
- package/dist/src/ui/hover-card.d.ts +6 -0
- package/dist/src/ui/index.d.ts +56 -0
- package/dist/src/ui/input-group.d.ts +16 -0
- package/dist/src/ui/input-otp.d.ts +11 -0
- package/dist/src/ui/input.d.ts +3 -0
- package/dist/src/ui/item.d.ts +23 -0
- package/dist/src/ui/kbd.d.ts +3 -0
- package/dist/src/ui/label.d.ts +4 -0
- package/dist/src/ui/menubar.d.ts +26 -0
- package/dist/src/ui/navigation-menu.d.ts +14 -0
- package/dist/src/ui/pagination.d.ts +13 -0
- package/dist/src/ui/popover.d.ts +7 -0
- package/dist/src/ui/progress.d.ts +4 -0
- package/dist/src/ui/radio-group.d.ts +5 -0
- package/dist/src/ui/resizable.d.ts +10 -0
- package/dist/src/ui/scroll-area.d.ts +5 -0
- package/dist/src/ui/select.d.ts +15 -0
- package/dist/src/ui/separator.d.ts +4 -0
- package/dist/src/ui/sheet.d.ts +13 -0
- package/dist/src/ui/sidebar.d.ts +69 -0
- package/dist/src/ui/skeleton.d.ts +2 -0
- package/dist/src/ui/slider.d.ts +4 -0
- package/dist/src/ui/sonner.d.ts +3 -0
- package/dist/src/ui/spinner.d.ts +3 -0
- package/dist/src/ui/switch.d.ts +4 -0
- package/dist/src/ui/table.d.ts +10 -0
- package/dist/src/ui/tabs.d.ts +7 -0
- package/dist/src/ui/textarea.d.ts +3 -0
- package/dist/src/ui/timeline.d.ts +25 -0
- package/dist/src/ui/toggle-group.d.ts +9 -0
- package/dist/src/ui/toggle.d.ts +9 -0
- package/dist/src/ui/tooltip.d.ts +7 -0
- package/docs/FilterBuilder.md +268 -0
- package/metadata/Chart.component.yml +30 -0
- package/metadata/FilterBuilder.component.yml +39 -0
- package/metadata/GridLayout.component.yml +27 -0
- package/metadata/Menu.component.yml +31 -0
- package/metadata/ObjectForm.component.yml +34 -0
- package/metadata/ObjectTable.component.yml +41 -0
- package/metadata/Page.component.yml +24 -0
- package/package.json +87 -0
- package/postcss.config.js +6 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/index.css +76 -0
- package/src/index.test.ts +7 -0
- package/src/index.ts +10 -0
- package/src/lib/utils.tsx +27 -0
- package/src/new-components.test.ts +74 -0
- package/src/renderers/basic/div.tsx +41 -0
- package/src/renderers/basic/html.tsx +34 -0
- package/src/renderers/basic/icon.tsx +25 -0
- package/src/renderers/basic/image.tsx +37 -0
- package/src/renderers/basic/index.ts +7 -0
- package/src/renderers/basic/separator.tsx +48 -0
- package/src/renderers/basic/span.tsx +44 -0
- package/src/renderers/basic/text.tsx +42 -0
- package/src/renderers/complex/README-KANBAN.md +208 -0
- package/src/renderers/complex/TIMELINE.md +353 -0
- package/src/renderers/complex/__tests__/data-table.test.ts +52 -0
- package/src/renderers/complex/calendar-view.tsx +219 -0
- package/src/renderers/complex/carousel.tsx +60 -0
- package/src/renderers/complex/chatbot.test.ts +44 -0
- package/src/renderers/complex/chatbot.tsx +185 -0
- package/src/renderers/complex/data-table.tsx +650 -0
- package/src/renderers/complex/filter-builder.tsx +68 -0
- package/src/renderers/complex/index.ts +10 -0
- package/src/renderers/complex/resizable.tsx +54 -0
- package/src/renderers/complex/scroll-area.tsx +32 -0
- package/src/renderers/complex/table.tsx +86 -0
- package/src/renderers/complex/timeline.tsx +466 -0
- package/src/renderers/data-display/alert.tsx +37 -0
- package/src/renderers/data-display/avatar.tsx +29 -0
- package/src/renderers/data-display/badge.tsx +46 -0
- package/src/renderers/data-display/index.ts +6 -0
- package/src/renderers/data-display/list.tsx +95 -0
- package/src/renderers/data-display/statistic.tsx +98 -0
- package/src/renderers/data-display/tree-view.tsx +180 -0
- package/src/renderers/disclosure/accordion.tsx +60 -0
- package/src/renderers/disclosure/collapsible.tsx +44 -0
- package/src/renderers/disclosure/index.ts +2 -0
- package/src/renderers/feedback/index.ts +4 -0
- package/src/renderers/feedback/loading.tsx +69 -0
- package/src/renderers/feedback/progress.tsx +20 -0
- package/src/renderers/feedback/skeleton.tsx +22 -0
- package/src/renderers/feedback/toaster.tsx +26 -0
- package/src/renderers/form/button.tsx +61 -0
- package/src/renderers/form/calendar.tsx +25 -0
- package/src/renderers/form/checkbox.tsx +41 -0
- package/src/renderers/form/date-picker.tsx +75 -0
- package/src/renderers/form/file-upload.tsx +175 -0
- package/src/renderers/form/form.tsx +417 -0
- package/src/renderers/form/index.ts +16 -0
- package/src/renderers/form/input-otp.tsx +31 -0
- package/src/renderers/form/input.tsx +79 -0
- package/src/renderers/form/label.tsx +36 -0
- package/src/renderers/form/radio-group.tsx +54 -0
- package/src/renderers/form/select.tsx +66 -0
- package/src/renderers/form/slider.tsx +45 -0
- package/src/renderers/form/switch.tsx +39 -0
- package/src/renderers/form/textarea.tsx +45 -0
- package/src/renderers/form/toggle.tsx +76 -0
- package/src/renderers/index.ts +9 -0
- package/src/renderers/layout/card.tsx +69 -0
- package/src/renderers/layout/container.tsx +113 -0
- package/src/renderers/layout/flex.tsx +123 -0
- package/src/renderers/layout/grid.tsx +155 -0
- package/src/renderers/layout/index.ts +10 -0
- package/src/renderers/layout/page.tsx +82 -0
- package/src/renderers/layout/semantic.tsx +39 -0
- package/src/renderers/layout/stack.tsx +123 -0
- package/src/renderers/layout/tabs.tsx +63 -0
- package/src/renderers/navigation/header-bar.tsx +50 -0
- package/src/renderers/navigation/index.ts +2 -0
- package/src/renderers/navigation/sidebar.tsx +189 -0
- package/src/renderers/overlay/alert-dialog.tsx +63 -0
- package/src/renderers/overlay/context-menu.tsx +91 -0
- package/src/renderers/overlay/dialog.tsx +68 -0
- package/src/renderers/overlay/drawer.tsx +68 -0
- package/src/renderers/overlay/dropdown-menu.tsx +90 -0
- package/src/renderers/overlay/hover-card.tsx +46 -0
- package/src/renderers/overlay/index.ts +9 -0
- package/src/renderers/overlay/popover.tsx +47 -0
- package/src/renderers/overlay/sheet.tsx +68 -0
- package/src/renderers/overlay/tooltip.tsx +58 -0
- package/src/ui/accordion.tsx +64 -0
- package/src/ui/alert-dialog.tsx +155 -0
- package/src/ui/alert.tsx +78 -0
- package/src/ui/aspect-ratio.tsx +11 -0
- package/src/ui/avatar.tsx +51 -0
- package/src/ui/badge.tsx +46 -0
- package/src/ui/breadcrumb.tsx +109 -0
- package/src/ui/button-group.tsx +83 -0
- package/src/ui/button.tsx +65 -0
- package/src/ui/calendar-view.tsx +503 -0
- package/src/ui/calendar.tsx +237 -0
- package/src/ui/card.tsx +138 -0
- package/src/ui/carousel.tsx +239 -0
- package/src/ui/chatbot.tsx +240 -0
- package/src/ui/checkbox.tsx +32 -0
- package/src/ui/collapsible.tsx +31 -0
- package/src/ui/command.tsx +182 -0
- package/src/ui/context-menu.tsx +247 -0
- package/src/ui/dialog.tsx +141 -0
- package/src/ui/drawer.tsx +135 -0
- package/src/ui/dropdown-menu.tsx +254 -0
- package/src/ui/empty.tsx +104 -0
- package/src/ui/field.tsx +246 -0
- package/src/ui/filter-builder.tsx +359 -0
- package/src/ui/form.tsx +167 -0
- package/src/ui/hover-card.tsx +44 -0
- package/src/ui/index.ts +56 -0
- package/src/ui/input-group.tsx +170 -0
- package/src/ui/input-otp.tsx +81 -0
- package/src/ui/input.tsx +24 -0
- package/src/ui/item.tsx +193 -0
- package/src/ui/kbd.tsx +28 -0
- package/src/ui/label.tsx +24 -0
- package/src/ui/menubar.tsx +274 -0
- package/src/ui/navigation-menu.tsx +168 -0
- package/src/ui/pagination.tsx +127 -0
- package/src/ui/popover.tsx +48 -0
- package/src/ui/progress.tsx +41 -0
- package/src/ui/radio-group.tsx +45 -0
- package/src/ui/resizable.tsx +55 -0
- package/src/ui/scroll-area.tsx +58 -0
- package/src/ui/select.tsx +188 -0
- package/src/ui/separator.tsx +31 -0
- package/src/ui/sheet.tsx +137 -0
- package/src/ui/sidebar.tsx +726 -0
- package/src/ui/skeleton.tsx +20 -0
- package/src/ui/slider.tsx +63 -0
- package/src/ui/sonner.tsx +43 -0
- package/src/ui/spinner.tsx +38 -0
- package/src/ui/switch.tsx +31 -0
- package/src/ui/table.tsx +120 -0
- package/src/ui/tabs.tsx +86 -0
- package/src/ui/textarea.tsx +18 -0
- package/src/ui/timeline.tsx +266 -0
- package/src/ui/toggle-group.tsx +87 -0
- package/src/ui/toggle.tsx +50 -0
- package/src/ui/tooltip.tsx +61 -0
- package/tailwind.config.js +75 -0
- package/tsconfig.json +18 -0
- package/vite.config.ts +44 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { clsx, type ClassValue } from "clsx"
|
|
2
|
+
import { twMerge } from "tailwind-merge"
|
|
3
|
+
import { SchemaRenderer } from "@object-ui/react"
|
|
4
|
+
import React from "react"
|
|
5
|
+
|
|
6
|
+
export function cn(...inputs: ClassValue[]) {
|
|
7
|
+
return twMerge(clsx(inputs))
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function renderChildren(children: any): React.ReactNode {
|
|
11
|
+
if (!children) return null;
|
|
12
|
+
if (typeof children === 'string' || typeof children === 'number') {
|
|
13
|
+
return children;
|
|
14
|
+
}
|
|
15
|
+
if (Array.isArray(children)) {
|
|
16
|
+
if (children.length === 0) return null;
|
|
17
|
+
// Unwrap single child to support Radix UI 'asChild' pattern which expects a single ReactElement, not an array
|
|
18
|
+
if (children.length === 1) {
|
|
19
|
+
return <SchemaRenderer schema={children[0]} />;
|
|
20
|
+
}
|
|
21
|
+
return children.map((child, index) => (
|
|
22
|
+
<SchemaRenderer key={child.id || index} schema={child} />
|
|
23
|
+
));
|
|
24
|
+
}
|
|
25
|
+
return <SchemaRenderer schema={children} />;
|
|
26
|
+
}
|
|
27
|
+
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll } from 'vitest';
|
|
2
|
+
import { ComponentRegistry } from '@object-ui/core';
|
|
3
|
+
|
|
4
|
+
describe('New Components Registration', () => {
|
|
5
|
+
// Import all renderers to register them
|
|
6
|
+
beforeAll(async () => {
|
|
7
|
+
await import('./renderers');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
describe('Form Components', () => {
|
|
11
|
+
it('should register date-picker component', () => {
|
|
12
|
+
const component = ComponentRegistry.getConfig('date-picker');
|
|
13
|
+
expect(component).toBeDefined();
|
|
14
|
+
expect(component?.label).toBe('Date Picker');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should register file-upload component', () => {
|
|
18
|
+
const component = ComponentRegistry.getConfig('file-upload');
|
|
19
|
+
expect(component).toBeDefined();
|
|
20
|
+
expect(component?.label).toBe('File Upload');
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('Data Display Components', () => {
|
|
25
|
+
it('should register list component', () => {
|
|
26
|
+
const component = ComponentRegistry.getConfig('list');
|
|
27
|
+
expect(component).toBeDefined();
|
|
28
|
+
expect(component?.label).toBe('List');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should register tree-view component', () => {
|
|
32
|
+
const component = ComponentRegistry.getConfig('tree-view');
|
|
33
|
+
expect(component).toBeDefined();
|
|
34
|
+
expect(component?.label).toBe('Tree View');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('Layout Components', () => {
|
|
39
|
+
it('should register grid component', () => {
|
|
40
|
+
const component = ComponentRegistry.getConfig('grid');
|
|
41
|
+
expect(component).toBeDefined();
|
|
42
|
+
expect(component?.label).toBe('Grid Layout');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should register flex component', () => {
|
|
46
|
+
const component = ComponentRegistry.getConfig('flex');
|
|
47
|
+
expect(component).toBeDefined();
|
|
48
|
+
expect(component?.label).toBe('Flex Layout');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should register container component', () => {
|
|
52
|
+
const component = ComponentRegistry.getConfig('container');
|
|
53
|
+
expect(component).toBeDefined();
|
|
54
|
+
expect(component?.label).toBe('Container');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('Feedback Components', () => {
|
|
59
|
+
it('should register loading component', () => {
|
|
60
|
+
const component = ComponentRegistry.getConfig('loading');
|
|
61
|
+
expect(component).toBeDefined();
|
|
62
|
+
expect(component?.label).toBe('Loading');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('Complex Components', () => {
|
|
67
|
+
it('should register timeline component', () => {
|
|
68
|
+
const component = ComponentRegistry.getConfig('timeline');
|
|
69
|
+
expect(component).toBeDefined();
|
|
70
|
+
expect(component?.label).toBe('Timeline');
|
|
71
|
+
expect(component?.category).toBe('data-display');
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ComponentRegistry } from '@object-ui/core';
|
|
2
|
+
import type { DivSchema } from '@object-ui/types';
|
|
3
|
+
import { renderChildren } from '../../lib/utils';
|
|
4
|
+
import { forwardRef } from 'react';
|
|
5
|
+
|
|
6
|
+
const DivRenderer = forwardRef<HTMLDivElement, { schema: DivSchema; className?: string; [key: string]: any }>(
|
|
7
|
+
({ schema, className, ...props }, ref) => {
|
|
8
|
+
// Extract designer-related props
|
|
9
|
+
const {
|
|
10
|
+
'data-obj-id': dataObjId,
|
|
11
|
+
'data-obj-type': dataObjType,
|
|
12
|
+
style,
|
|
13
|
+
...divProps
|
|
14
|
+
} = props;
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div
|
|
18
|
+
ref={ref}
|
|
19
|
+
className={className}
|
|
20
|
+
{...divProps}
|
|
21
|
+
// Apply designer props
|
|
22
|
+
{...{ 'data-obj-id': dataObjId, 'data-obj-type': dataObjType, style }}
|
|
23
|
+
>
|
|
24
|
+
{renderChildren(schema.children || schema.body)}
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
ComponentRegistry.register('div',
|
|
31
|
+
DivRenderer,
|
|
32
|
+
{
|
|
33
|
+
label: 'Container',
|
|
34
|
+
inputs: [
|
|
35
|
+
{ name: 'className', type: 'string', label: 'CSS Class' }
|
|
36
|
+
],
|
|
37
|
+
defaultProps: {
|
|
38
|
+
className: 'p-4 border border-dashed border-gray-300 rounded min-h-[100px]'
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ComponentRegistry } from '@object-ui/core';
|
|
3
|
+
import type { HtmlSchema } from '@object-ui/types';
|
|
4
|
+
import { cn } from '../../lib/utils';
|
|
5
|
+
|
|
6
|
+
ComponentRegistry.register('html',
|
|
7
|
+
({ schema, className, ...props }: { schema: HtmlSchema; className?: string; [key: string]: any }) => {
|
|
8
|
+
// Extract designer-related props
|
|
9
|
+
const {
|
|
10
|
+
'data-obj-id': dataObjId,
|
|
11
|
+
'data-obj-type': dataObjType,
|
|
12
|
+
style,
|
|
13
|
+
...htmlProps
|
|
14
|
+
} = props;
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div
|
|
18
|
+
className={cn("prose prose-sm max-w-none dark:prose-invert", className)}
|
|
19
|
+
dangerouslySetInnerHTML={{ __html: schema.html }}
|
|
20
|
+
{...htmlProps}
|
|
21
|
+
// Apply designer props
|
|
22
|
+
data-obj-id={dataObjId}
|
|
23
|
+
data-obj-type={dataObjType}
|
|
24
|
+
style={style}
|
|
25
|
+
/>
|
|
26
|
+
);
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
label: 'HTML Content',
|
|
30
|
+
inputs: [
|
|
31
|
+
{ name: 'html', type: 'string', label: 'HTML', description: 'Raw HTML content' }
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ComponentRegistry } from '@object-ui/core';
|
|
2
|
+
import type { IconSchema } from '@object-ui/types';
|
|
3
|
+
import { icons } from 'lucide-react';
|
|
4
|
+
import React, { forwardRef } from 'react';
|
|
5
|
+
|
|
6
|
+
const IconRenderer = forwardRef<SVGSVGElement, { schema: IconSchema; className?: string; [key: string]: any }>(
|
|
7
|
+
({ schema, className, ...props }, ref) => {
|
|
8
|
+
const Icon = (icons as any)[schema.name || schema.icon];
|
|
9
|
+
if (!Icon) return null;
|
|
10
|
+
return <Icon ref={ref} className={className} {...props} />;
|
|
11
|
+
}
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
ComponentRegistry.register('icon',
|
|
15
|
+
IconRenderer,
|
|
16
|
+
{
|
|
17
|
+
label: 'Icon',
|
|
18
|
+
icon: 'smile',
|
|
19
|
+
category: 'basic',
|
|
20
|
+
inputs: [
|
|
21
|
+
{ name: 'name', type: 'string', label: 'Icon Name', defaultValue: 'smile' },
|
|
22
|
+
{ name: 'className', type: 'string', label: 'CSS Class' }
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ComponentRegistry } from '@object-ui/core';
|
|
2
|
+
import type { ImageSchema } from '@object-ui/types';
|
|
3
|
+
|
|
4
|
+
ComponentRegistry.register('image',
|
|
5
|
+
({ schema, className, ...props }: { schema: ImageSchema; className?: string; [key: string]: any }) => {
|
|
6
|
+
// Extract designer-related props
|
|
7
|
+
const {
|
|
8
|
+
'data-obj-id': dataObjId,
|
|
9
|
+
'data-obj-type': dataObjType,
|
|
10
|
+
style,
|
|
11
|
+
...imgProps
|
|
12
|
+
} = props;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<img
|
|
16
|
+
src={schema.src}
|
|
17
|
+
alt={schema.alt || ''}
|
|
18
|
+
className={className}
|
|
19
|
+
{...imgProps}
|
|
20
|
+
// Apply designer props
|
|
21
|
+
data-obj-id={dataObjId}
|
|
22
|
+
data-obj-type={dataObjType}
|
|
23
|
+
style={style}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
label: 'Image',
|
|
29
|
+
icon: 'image',
|
|
30
|
+
category: 'basic',
|
|
31
|
+
inputs: [
|
|
32
|
+
{ name: 'src', type: 'string', label: 'Source URL' },
|
|
33
|
+
{ name: 'alt', type: 'string', label: 'Alt Text' },
|
|
34
|
+
{ name: 'className', type: 'string', label: 'Classes' }
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ComponentRegistry } from '@object-ui/core';
|
|
2
|
+
import type { SeparatorSchema } from '@object-ui/types';
|
|
3
|
+
import { Separator } from '../../ui';
|
|
4
|
+
import { forwardRef } from 'react';
|
|
5
|
+
|
|
6
|
+
const SeparatorRenderer = forwardRef<HTMLDivElement, { schema: SeparatorSchema; className?: string; [key: string]: any }>(
|
|
7
|
+
({ schema, className, ...props }, ref) => {
|
|
8
|
+
// Extract designer-related props
|
|
9
|
+
const {
|
|
10
|
+
'data-obj-id': dataObjId,
|
|
11
|
+
'data-obj-type': dataObjType,
|
|
12
|
+
style,
|
|
13
|
+
...separatorProps
|
|
14
|
+
} = props;
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<Separator
|
|
18
|
+
ref={ref}
|
|
19
|
+
orientation={schema.orientation}
|
|
20
|
+
className={className}
|
|
21
|
+
{...separatorProps}
|
|
22
|
+
// Apply designer props
|
|
23
|
+
{...{ 'data-obj-id': dataObjId, 'data-obj-type': dataObjType, style }}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
ComponentRegistry.register('separator',
|
|
30
|
+
SeparatorRenderer,
|
|
31
|
+
{
|
|
32
|
+
label: 'Separator',
|
|
33
|
+
inputs: [
|
|
34
|
+
{
|
|
35
|
+
name: 'orientation',
|
|
36
|
+
type: 'enum',
|
|
37
|
+
enum: ['horizontal', 'vertical'],
|
|
38
|
+
defaultValue: 'horizontal',
|
|
39
|
+
label: 'Orientation'
|
|
40
|
+
},
|
|
41
|
+
{ name: 'className', type: 'string', label: 'CSS Class' }
|
|
42
|
+
],
|
|
43
|
+
defaultProps: {
|
|
44
|
+
orientation: 'horizontal',
|
|
45
|
+
className: 'my-4'
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ComponentRegistry } from '@object-ui/core';
|
|
2
|
+
import type { SpanSchema } from '@object-ui/types';
|
|
3
|
+
import { renderChildren } from '../../lib/utils';
|
|
4
|
+
import { forwardRef } from 'react';
|
|
5
|
+
|
|
6
|
+
const SpanRenderer = forwardRef<HTMLSpanElement, { schema: SpanSchema; className?: string; [key: string]: any }>(
|
|
7
|
+
({ schema, className, ...props }, ref) => {
|
|
8
|
+
// Extract designer-related props
|
|
9
|
+
const {
|
|
10
|
+
'data-obj-id': dataObjId,
|
|
11
|
+
'data-obj-type': dataObjType,
|
|
12
|
+
style,
|
|
13
|
+
...spanProps
|
|
14
|
+
} = props;
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<span
|
|
18
|
+
ref={ref}
|
|
19
|
+
className={className}
|
|
20
|
+
{...spanProps}
|
|
21
|
+
// Apply designer props
|
|
22
|
+
{...{ 'data-obj-id': dataObjId, 'data-obj-type': dataObjType, style }}
|
|
23
|
+
>
|
|
24
|
+
{renderChildren(schema.body)}
|
|
25
|
+
</span>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
ComponentRegistry.register('span',
|
|
31
|
+
SpanRenderer,
|
|
32
|
+
{
|
|
33
|
+
label: 'Inline Container',
|
|
34
|
+
inputs: [
|
|
35
|
+
{ name: 'className', type: 'string', label: 'CSS Class' }
|
|
36
|
+
],
|
|
37
|
+
defaultProps: {
|
|
38
|
+
className: 'px-2 py-1'
|
|
39
|
+
},
|
|
40
|
+
defaultChildren: [
|
|
41
|
+
{ type: 'text', content: 'Inline text' }
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ComponentRegistry } from '@object-ui/core';
|
|
2
|
+
import type { TextSchema } from '@object-ui/types';
|
|
3
|
+
|
|
4
|
+
ComponentRegistry.register('text',
|
|
5
|
+
({ schema, ...props }: { schema: TextSchema; [key: string]: any }) => {
|
|
6
|
+
// Text is a special case as it might be rendered as a fragment or span depending on usage.
|
|
7
|
+
// However, to support drag and drop in designer, it MUST be wrapped in an element if props are passed.
|
|
8
|
+
|
|
9
|
+
// Extract designer-related props
|
|
10
|
+
const {
|
|
11
|
+
'data-obj-id': dataObjId,
|
|
12
|
+
'data-obj-type': dataObjType,
|
|
13
|
+
style,
|
|
14
|
+
...rest
|
|
15
|
+
} = props;
|
|
16
|
+
|
|
17
|
+
// If we have designer props, we must wrap it to make it selectable
|
|
18
|
+
if (dataObjId) {
|
|
19
|
+
return (
|
|
20
|
+
<span
|
|
21
|
+
data-obj-id={dataObjId}
|
|
22
|
+
data-obj-type={dataObjType}
|
|
23
|
+
style={style}
|
|
24
|
+
{...rest}
|
|
25
|
+
>
|
|
26
|
+
{schema.content || schema.value}
|
|
27
|
+
</span>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return <>{schema.content || schema.value}</>;
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
label: 'Text',
|
|
35
|
+
inputs: [
|
|
36
|
+
{ name: 'content', type: 'string', label: 'Content', required: true }
|
|
37
|
+
],
|
|
38
|
+
defaultProps: {
|
|
39
|
+
content: 'Text content'
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
);
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Kanban Board Component
|
|
2
|
+
|
|
3
|
+
A fully functional, schema-driven Kanban board component for Object UI with drag-and-drop support.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Multiple Columns**: Create unlimited columns with customizable titles
|
|
8
|
+
- **Rich Cards**: Cards support title, description, and multiple badges
|
|
9
|
+
- **Drag & Drop**: Smooth drag-and-drop functionality powered by @dnd-kit
|
|
10
|
+
- **Reordering**: Reorder cards within the same column
|
|
11
|
+
- **Cross-Column Moves**: Move cards between different columns
|
|
12
|
+
- **Column Limits**: Optional capacity limits with visual indicators
|
|
13
|
+
- **Card Counters**: Shows current count and limit per column
|
|
14
|
+
- **Schema-Driven**: Configure entirely through JSON/YAML
|
|
15
|
+
- **Event Callbacks**: Custom event handling for card movements
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### Basic Example
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"type": "kanban",
|
|
24
|
+
"className": "w-full h-[600px]",
|
|
25
|
+
"columns": [
|
|
26
|
+
{
|
|
27
|
+
"id": "todo",
|
|
28
|
+
"title": "To Do",
|
|
29
|
+
"cards": [
|
|
30
|
+
{
|
|
31
|
+
"id": "card-1",
|
|
32
|
+
"title": "Task Title",
|
|
33
|
+
"description": "Task description",
|
|
34
|
+
"badges": [
|
|
35
|
+
{ "label": "High Priority", "variant": "destructive" }
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "in-progress",
|
|
42
|
+
"title": "In Progress",
|
|
43
|
+
"limit": 3,
|
|
44
|
+
"cards": []
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "done",
|
|
48
|
+
"title": "Done",
|
|
49
|
+
"cards": []
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### With Event Handling
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"type": "kanban",
|
|
60
|
+
"columns": [...],
|
|
61
|
+
"onCardMove": "(event) => { console.log('Card moved:', event); }"
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Schema Reference
|
|
66
|
+
|
|
67
|
+
### Kanban Props
|
|
68
|
+
|
|
69
|
+
| Property | Type | Required | Description |
|
|
70
|
+
|----------|------|----------|-------------|
|
|
71
|
+
| `type` | `"kanban"` | Yes | Component type identifier |
|
|
72
|
+
| `columns` | `KanbanColumn[]` | Yes | Array of column configurations |
|
|
73
|
+
| `className` | `string` | No | Custom CSS classes |
|
|
74
|
+
| `onCardMove` | `function` | No | Callback when a card is moved |
|
|
75
|
+
|
|
76
|
+
### KanbanColumn
|
|
77
|
+
|
|
78
|
+
| Property | Type | Required | Description |
|
|
79
|
+
|----------|------|----------|-------------|
|
|
80
|
+
| `id` | `string` | Yes | Unique column identifier |
|
|
81
|
+
| `title` | `string` | Yes | Column header title |
|
|
82
|
+
| `cards` | `KanbanCard[]` | Yes | Array of cards in this column |
|
|
83
|
+
| `limit` | `number` | No | Maximum number of cards allowed |
|
|
84
|
+
| `className` | `string` | No | Custom CSS classes for column |
|
|
85
|
+
|
|
86
|
+
### KanbanCard
|
|
87
|
+
|
|
88
|
+
| Property | Type | Required | Description |
|
|
89
|
+
|----------|------|----------|-------------|
|
|
90
|
+
| `id` | `string` | Yes | Unique card identifier |
|
|
91
|
+
| `title` | `string` | Yes | Card title |
|
|
92
|
+
| `description` | `string` | No | Card description text |
|
|
93
|
+
| `badges` | `Badge[]` | No | Array of badge objects |
|
|
94
|
+
|
|
95
|
+
### Badge
|
|
96
|
+
|
|
97
|
+
| Property | Type | Required | Description |
|
|
98
|
+
|----------|------|----------|-------------|
|
|
99
|
+
| `label` | `string` | Yes | Badge text |
|
|
100
|
+
| `variant` | `"default" \| "secondary" \| "destructive" \| "outline"` | No | Badge color variant |
|
|
101
|
+
|
|
102
|
+
## Examples
|
|
103
|
+
|
|
104
|
+
### Simple Task Board
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"type": "kanban",
|
|
109
|
+
"columns": [
|
|
110
|
+
{
|
|
111
|
+
"id": "backlog",
|
|
112
|
+
"title": "📋 Backlog",
|
|
113
|
+
"cards": [
|
|
114
|
+
{
|
|
115
|
+
"id": "1",
|
|
116
|
+
"title": "Setup project",
|
|
117
|
+
"badges": [{ "label": "Setup" }]
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"id": "doing",
|
|
123
|
+
"title": "🚀 Doing",
|
|
124
|
+
"limit": 2,
|
|
125
|
+
"cards": []
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"id": "done",
|
|
129
|
+
"title": "✅ Done",
|
|
130
|
+
"cards": []
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Issue Tracking Board
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"type": "kanban",
|
|
141
|
+
"columns": [
|
|
142
|
+
{
|
|
143
|
+
"id": "new",
|
|
144
|
+
"title": "New Issues",
|
|
145
|
+
"cards": [
|
|
146
|
+
{
|
|
147
|
+
"id": "issue-1",
|
|
148
|
+
"title": "Bug: Login fails on Safari",
|
|
149
|
+
"description": "Users can't login using Safari browser",
|
|
150
|
+
"badges": [
|
|
151
|
+
{ "label": "Bug", "variant": "destructive" },
|
|
152
|
+
{ "label": "P0", "variant": "destructive" }
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"id": "investigating",
|
|
159
|
+
"title": "Investigating",
|
|
160
|
+
"limit": 3,
|
|
161
|
+
"cards": []
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"id": "fixed",
|
|
165
|
+
"title": "Fixed",
|
|
166
|
+
"cards": []
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Styling
|
|
173
|
+
|
|
174
|
+
The Kanban component uses Tailwind CSS and can be customized using the `className` prop:
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
"type": "kanban",
|
|
179
|
+
"className": "w-full h-[800px] bg-gray-50 p-4 rounded-lg",
|
|
180
|
+
"columns": [...]
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Individual columns can also be styled:
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"id": "urgent",
|
|
189
|
+
"title": "🔥 Urgent",
|
|
190
|
+
"className": "bg-red-50",
|
|
191
|
+
"cards": [...]
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Technical Details
|
|
196
|
+
|
|
197
|
+
- Built with React 18+ and TypeScript
|
|
198
|
+
- Uses @dnd-kit for drag-and-drop functionality
|
|
199
|
+
- Integrates with Shadcn UI components (Card, Badge, ScrollArea)
|
|
200
|
+
- Supports both pointer and touch interactions
|
|
201
|
+
- Accessible keyboard navigation (via @dnd-kit)
|
|
202
|
+
|
|
203
|
+
## Browser Support
|
|
204
|
+
|
|
205
|
+
- Chrome/Edge: Full support
|
|
206
|
+
- Firefox: Full support
|
|
207
|
+
- Safari: Full support
|
|
208
|
+
- Mobile browsers: Full support with touch gestures
|