Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -101,45 +101,6 @@ describe('Disclosure Renderers - Display Issue Detection', () => {
* Comprehensive tests for complex renderer components
*/
describe('Complex Renderers - Display Issue Detection', () => {
describe('Timeline Renderer', () => {
it('should be properly registered', () => {
const validation = validateComponentRegistration('timeline');
expect(validation.isRegistered).toBe(true);
});

it('should render timeline with events', () => {
const { container } = renderComponent({
type: 'timeline',
items: [
{
title: 'Event 1',
description: 'Description 1',
time: '2024-01-01',
},
{
title: 'Event 2',
description: 'Description 2',
time: '2024-01-02',
},
],
});

expect(container.textContent).toContain('Event 1');
expect(container.textContent).toContain('Event 2');
});

it('should handle empty timeline', () => {
const { container } = renderComponent({
type: 'timeline',
items: [],
});

const domCheck = checkDOMStructure(container);
// Empty timeline is acceptable
expect(domCheck).toBeDefined();
});
});

describe('Data Table Renderer', () => {
it('should be properly registered', () => {
const validation = validateComponentRegistration('data-table');
Expand Down Expand Up @@ -188,36 +149,6 @@ describe('Complex Renderers - Display Issue Detection', () => {
});
});

describe('Chatbot Renderer', () => {
it('should be properly registered', () => {
const validation = validateComponentRegistration('chatbot');
expect(validation.isRegistered).toBe(true);
});

it('should render chatbot interface', () => {
const { container } = renderComponent({
type: 'chatbot',
messages: [
{ role: 'user', content: 'Hello' },
{ role: 'assistant', content: 'Hi there!' },
],
});

expect(container.textContent).toContain('Hello');
expect(container.textContent).toContain('Hi there!');
});

it('should handle empty messages', () => {
const { container } = renderComponent({
type: 'chatbot',
messages: [],
});

const domCheck = checkDOMStructure(container);
expect(domCheck).toBeDefined();
});
});

describe('Carousel Renderer', () => {
it('should be properly registered', () => {
const validation = validateComponentRegistration('carousel');
Expand Down
9 changes: 0 additions & 9 deletions packages/components/src/new-components.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,4 @@ describe('New Components Registration', () => {
expect(component?.label).toBe('Loading');
});
});

describe('Complex Components', () => {
it('should register timeline component', () => {
const component = ComponentRegistry.getConfig('timeline');
expect(component).toBeDefined();
expect(component?.label).toBe('Timeline');
expect(component?.category).toBe('data-display');
});
});
});
52 changes: 0 additions & 52 deletions packages/components/src/renderers/complex/chatbot.test.ts

This file was deleted.

3 changes: 1 addition & 2 deletions packages/components/src/renderers/complex/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import './filter-builder';
import './scroll-area';
import './resizable';
import './table';
import './chatbot';
import './data-table';
import './timeline';


2 changes: 0 additions & 2 deletions packages/components/src/ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export * from './calendar';
export * from './calendar-view';
export * from './card';
export * from './carousel';
export * from './chatbot';
export * from './checkbox';
export * from './collapsible';
export * from './combobox';
Expand Down Expand Up @@ -60,7 +59,6 @@ export * from './switch';
export * from './table';
export * from './tabs';
export * from './textarea';
export * from './timeline';
export * from './toast';
export { Toaster as ToastNotifier } from './toaster';
export * from './toggle-group';
Expand Down
63 changes: 63 additions & 0 deletions packages/plugin-chatbot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# @object-ui/plugin-chatbot

Chatbot interface plugin for Object UI.

## Installation

```bash
npm install @object-ui/plugin-chatbot
```

## Usage

```tsx
import { Chatbot } from '@object-ui/plugin-chatbot';

function App() {
const [messages, setMessages] = useState([
{
id: '1',
role: 'assistant',
content: 'Hello! How can I help you today?'
}
]);

const handleSend = (content: string) => {
const newMessage = {
id: Date.now().toString(),
role: 'user',
content
};
setMessages([...messages, newMessage]);
};

return (
<Chatbot
messages={messages}
onSendMessage={handleSend}
placeholder="Type your message..."
/>
);
}
```

## Schema-Driven Usage

This plugin automatically registers with ObjectUI's component registry when imported:

```tsx
import '@object-ui/plugin-chatbot';

const schema = {
component: 'chatbot',
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the schema-driven usage example, the key is component: 'chatbot' but the rest of the ObjectUI schema types (e.g. ChatbotSchema in packages/types/src/complex.ts) and other docs use type: 'chatbot'. To avoid confusing users and to provide a working example, this snippet should use type: 'chatbot' instead of component.

Suggested change
component: 'chatbot',
type: 'chatbot',

Copilot uses AI. Check for mistakes.
messages: [
{ id: '1', role: 'assistant', content: 'Hello!' }
],
placeholder: 'Type your message...',
autoResponse: true
};
```

## License

MIT © ObjectStack Inc.
52 changes: 52 additions & 0 deletions packages/plugin-chatbot/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "@object-ui/plugin-chatbot",
"version": "0.3.0",
"type": "module",
"license": "MIT",
"description": "Chatbot interface plugin for Object UI",
"homepage": "https://www.objectui.org",
"repository": {
"type": "git",
"url": "https://github.com/objectstack-ai/objectui.git",
"directory": "packages/plugin-chatbot"
},
"bugs": {
"url": "https://github.com/objectstack-ai/objectui/issues"
},
"main": "dist/index.umd.cjs",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.umd.cjs"
}
},
"scripts": {
"build": "vite build",
"test": "vitest run",
"test:watch": "vitest",
"type-check": "tsc --noEmit",
"lint": "eslint ."
},
"dependencies": {
"@object-ui/components": "workspace:*",
"@object-ui/core": "workspace:*",
"@object-ui/react": "workspace:*",
"@object-ui/types": "workspace:*",
"lucide-react": "^0.468.0"
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This package pins lucide-react to ^0.468.0 while other packages in the monorepo (e.g. @object-ui/components, @object-ui/runner, @object-ui/views) use ^0.562.0, which will cause pnpm to install multiple lucide-react versions. For consistency and to avoid duplicate copies of the icon library in consumer bundles, consider aligning this dependency version with the one used elsewhere in the workspace unless there is a specific need for the older release.

Suggested change
"lucide-react": "^0.468.0"
"lucide-react": "^0.562.0"

Copilot uses AI. Check for mistakes.
},
"peerDependencies": {
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"devDependencies": {
"@types/react": "^19.0.6",
"@types/react-dom": "^19.0.3",
"@vitejs/plugin-react": "^4.2.1",
"typescript": "^5.9.3",
"vite": "^7.3.1",
"vite-plugin-dts": "^4.5.4"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@
*/

import * as React from "react"
import { cn } from "../lib/utils"
import { Button } from "./button"
import { Input } from "./input"
import { ScrollArea } from "./scroll-area"
import { Avatar, AvatarFallback, AvatarImage } from "./avatar"
import { cn } from "@object-ui/components"
import { Button, Input, ScrollArea, Avatar, AvatarFallback, AvatarImage } from "@object-ui/components"
import { Send } from "lucide-react"

// Message type definition
Expand Down Expand Up @@ -246,3 +243,6 @@ const TypingIndicator = React.forwardRef<HTMLDivElement, TypingIndicatorProps>(
TypingIndicator.displayName = "TypingIndicator"

export { Chatbot, TypingIndicator }

// Export renderer to register the component with ObjectUI
export * from './renderer';
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import { ComponentRegistry } from '@object-ui/core';
import type { ChatbotSchema, ChatMessage } from '@object-ui/types';
import { Chatbot } from '../../ui';
import { Chatbot } from './index';
import { useState } from 'react';

/**
Expand Down Expand Up @@ -41,7 +41,7 @@ ComponentRegistry.register('chatbot',
const handleSendMessage = (content: string) => {
// Create user message with robust ID generation
const userMessage: ChatMessage = {
id: crypto.randomUUID(),
id: crypto?.randomUUID?.() || `msg-${Date.now()}-${Math.random().toString(36).slice(2)}`,
role: 'user',
content,
timestamp: schema.showTimestamp ? new Date().toLocaleTimeString() : undefined,
Expand All @@ -59,7 +59,7 @@ ComponentRegistry.register('chatbot',
if (schema.autoResponse) {
setTimeout(() => {
const assistantMessage: ChatMessage = {
id: crypto.randomUUID(),
id: crypto?.randomUUID?.() || `msg-${Date.now()}-${Math.random().toString(36).slice(2)}`,
role: 'assistant',
content: schema.autoResponseText || 'Thank you for your message!',
timestamp: schema.showTimestamp ? new Date().toLocaleTimeString() : undefined,
Expand Down
18 changes: 18 additions & 0 deletions packages/plugin-chatbot/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
"noEmit": false,
"declaration": true,
"composite": true,
"declarationMap": true,
"skipLibCheck": true
},
"include": ["src"],
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.test.tsx"]
}
Loading
Loading