Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 26, 2026

Replaces raw HTML/Tailwind in field renderers with Shadcn UI components and extracts complex visualization components to separate plugin packages for better modularity.

Field Renderer Changes

  • Boolean: Badge with Lucide Check/X icons instead of hardcoded symbols
  • Select: Badge variant="outline" with color mapping
  • User: Avatar/AvatarFallback primitives
  • Email/URL: Button variant="link" asChild wrapping <a> tags
  • Image: Consistent size-* utilities

ObjectGrid Actions

Replaced inline action buttons with DropdownMenu:

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="ghost" size="icon">
      <MoreVertical className="h-4 w-4" />
    </Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem><Edit /> Edit</DropdownMenuItem>
    <DropdownMenuItem variant="destructive"><Trash2 /> Delete</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Plugin Extraction

Created standalone packages for visualization components:

  • @object-ui/plugin-calendar (ObjectCalendar)
  • @object-ui/plugin-gantt (ObjectGantt)
  • @object-ui/plugin-map (ObjectMap)

Each plugin includes component registration and proper externals configuration. Removed from core @object-ui/views package to reduce bundle size.

Original prompt

Role

Frontend Refactoring Specialist (Shadcn UI Expert)

Context

We are refactoring the packages/views package in objectstack-ai/objectui.
The goal is to ensure all "View Components" (which render data from ObjectQL schemas) utilize standard Shadcn UI components instead of raw HTML/Tailwind.

Task 1: Standardize Field Renderers (Read-Only Views)

  1. Read packages/views/src/field-renderers.tsx.
  2. This file currently uses raw <span>, <div>, and <img> tags with hardcoded Tailwind classes.
  3. Refactor this file to use Shadcn atoms imported from @object-ui/components:
    • BooleanCellRenderer: Use a generic <Badge> (Green for true, Gray for false) or an Icon (Check/X).
    • SelectCellRenderer: Replace the hardcoded color map with standard <Badge variant="outline"> or custom badge variants.
    • UserCellRenderer: Replace the <div> circle with <Avatar> and <AvatarFallback>.
    • ImageCellRenderer: Ensure styling is consistent (consider <AspectRatio> or just styled img with rounded-md).
    • UrlCellRenderer / EmailCellRenderer: Use <Button variant="link" className="p-0 h-auto"> instead of raw <a> tags.

Task 2: Polish ObjectGrid Actions

  1. Read packages/views/src/ObjectGrid.tsx.
  2. Locate the "Actions" column generation (around line 300).
  3. Currently, it renders raw <button> elements for Edit/Delete.
  4. Refactor:
    • Use <Button variant="ghost" size="icon"> with Lucid Icons (Edit, Trash2).
    • OR (Better): Wrap them in a <DropdownMenu> (Actions -> Edit, Delete) to save space, standardizing the "Row Actions" pattern.

Task 3: Split Heavy Views to Plugins

Similar to our previous work, the following files represent complex, distinct features that should be plugins:

  • ObjectCalendar.tsx -> packages/plugin-calendar
  • ObjectGantt.tsx -> packages/plugin-gantt
  • ObjectKanban.tsx -> packages/plugin-kanban
  • ObjectMap.tsx -> packages/plugin-map

Execution:

  1. Create the new package directories.
  2. Move the source files.
  3. Create package.json for each (copy from plugin-chatbot template).
  4. Remove the files from packages/views/src.
  5. Update packages/views/src/index.tsx to remove their exports.

Deliverable

  • Updated code for field-renderers.tsx (using Shadcn components).
  • Updated code for ObjectGrid.tsx (using Shadcn Buttons/Dropdowns).
  • Shell commands to execute the plugin extraction (Task 3).

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@vercel
Copy link

vercel bot commented Jan 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
objectui-site Ready Ready Preview, Comment Jan 26, 2026 10:45am

Request Review

Copilot AI and others added 2 commits January 26, 2026 10:34
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor field renderers to use Shadcn UI components Refactor views to Shadcn UI primitives and extract visualization plugins Jan 26, 2026
Copilot AI requested a review from hotlong January 26, 2026 10:47
@github-actions
Copy link

📦 Bundle Size Report

Package Size Gzipped
components (index.js) 1520.38KB 358.07KB
core (index.js) 0.53KB 0.28KB
plugin-aggrid (AgGridImpl-DKkq6v1B.js) 5.09KB 1.84KB
plugin-aggrid (index-B6NPAFZx.js) 15.66KB 4.51KB
plugin-aggrid (index.js) 0.18KB 0.15KB
plugin-calendar-view (index.js) 25.13KB 6.40KB
plugin-calendar (index.js) 16.68KB 5.10KB
plugin-charts (AdvancedChartImpl-DazADGz5.js) 74.89KB 15.82KB
plugin-charts (BarChart-CRc8MAtI.js) 551.60KB 127.51KB
plugin-charts (ChartImpl-DVw_7KEd.js) 3.17KB 1.10KB
plugin-charts (index-CdgY2AuM.js) 12.39KB 3.83KB
plugin-charts (index.js) 0.21KB 0.16KB
plugin-chatbot (index.js) 18.36KB 5.21KB
plugin-editor (MonacoImpl-B7ZgZJJG.js) 18.15KB 5.59KB
plugin-editor (index-Dl3HAAqu.js) 10.07KB 3.31KB
plugin-editor (index.js) 0.19KB 0.15KB
plugin-gantt (index.js) 17.97KB 5.24KB
plugin-kanban (KanbanImpl-CUWM-JC-.js) 76.50KB 20.46KB
plugin-kanban (index-BV3FWhCb.js) 11.86KB 3.67KB
plugin-kanban (index.js) 0.18KB 0.15KB
plugin-map (index.js) 16.72KB 5.09KB
plugin-markdown (MarkdownImpl-BRkYjVWf.js) 256.79KB 64.50KB
plugin-markdown (index-D_CdfEXQ.js) 9.59KB 3.16KB
plugin-markdown (index.js) 0.19KB 0.15KB
plugin-timeline (index.js) 23.90KB 5.95KB
react (SchemaRenderer.js) 1.44KB 0.73KB
react (index.js) 0.36KB 0.23KB
react (index.test.js) 0.34KB 0.26KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 0.20KB 0.18KB
types (base.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (data-display.js) 0.20KB 0.18KB
types (data.js) 0.20KB 0.18KB
types (disclosure.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (index.js) 0.34KB 0.25KB
types (layout.js) 0.20KB 0.18KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (registry.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@hotlong hotlong marked this pull request as ready for review January 26, 2026 11:12
Copilot AI review requested due to automatic review settings January 26, 2026 11:12
@github-actions
Copy link

✅ All checks passed!

  • ✅ Type check passed
  • ✅ Tests passed
  • ✅ Lint check completed

@hotlong hotlong merged commit 3f78e5e into main Jan 26, 2026
16 checks passed
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors view components in the ObjectUI library to adopt Shadcn UI primitives and extracts three visualization components (ObjectCalendar, ObjectGantt, ObjectMap) into separate plugin packages for better modularity and reduced bundle size.

Changes:

  • Replaced raw HTML elements in field renderers with Shadcn UI components (Badge with icons for Boolean, Avatar for User, Button with asChild for links)
  • Refactored ObjectGrid action buttons to use DropdownMenu with icons, improving UI consistency and saving space
  • Extracted ObjectCalendar, ObjectGantt, and ObjectMap from @object-ui/views to dedicated plugin packages with proper component registration

Reviewed changes

Copilot reviewed 21 out of 25 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/views/src/field-renderers.tsx Refactored to use Shadcn primitives: Badge with Check/X icons for Boolean, Avatar/AvatarFallback for User, Button variant="link" asChild for Email/URL, consistent size-* utilities for images
packages/views/src/ObjectGrid.tsx Replaced inline action buttons with DropdownMenu containing Edit/Delete menu items with proper icons and destructive variant
packages/views/src/index.tsx Removed exports and registrations for extracted visualization components (ObjectKanban, ObjectCalendar, ObjectGantt, ObjectMap)
packages/views/src/tests/field-renderers.test.tsx Updated test assertions to match new Badge text ("True"/"False") and Avatar data-slot selector
packages/views/src/tests/Object*.test.tsx Removed test files for extracted components
packages/plugin-calendar/* New plugin package with ObjectCalendar component, proper package.json, vite config, and component registration
packages/plugin-gantt/* New plugin package with ObjectGantt component, proper package.json, vite config, and component registration
packages/plugin-map/* New plugin package with ObjectMap component, proper package.json, vite config, and component registration
pnpm-lock.yaml Added dependency entries for three new plugin packages
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

export type { ObjectCalendarProps };

// Register component
const ObjectCalendarRenderer: React.FC<{ schema: any }> = ({ schema }) => {
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.

The plugin renderers (ObjectCalendarRenderer, ObjectGanttRenderer, ObjectMapRenderer) pass dataSource={null as any} to their components without checking if the schema has inline data first. This differs from the pattern used in the views package where ObjectGridRenderer, ObjectFormRenderer, and ObjectViewRenderer check for inline data before rendering.

If these components are rendered without inline data (i.e., when schema.data.provider is not 'value'), they will throw an error "DataSource required for object/api providers" which will be displayed as an error state. While this is handled gracefully, it would be more consistent to add the same inline data guards that exist in the views package renderers.

Consider adding the same pattern used in packages/views/src/index.tsx lines 68-84 to provide a clearer error message upfront.

Suggested change
const ObjectCalendarRenderer: React.FC<{ schema: any }> = ({ schema }) => {
const ObjectCalendarRenderer: React.FC<{ schema: any }> = ({ schema }) => {
const provider = schema?.data?.provider;
if (provider && provider !== 'value') {
return (
<div className="text-sm text-destructive">
object-calendar plugin renderer requires inline data (schema.data.provider = &apos;value&apos;) when no dataSource is provided.
</div>
);
}

Copilot uses AI. Check for mistakes.
export type { ObjectGanttProps };

// Register component
const ObjectGanttRenderer: React.FC<{ schema: any }> = ({ schema }) => {
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.

The plugin renderers (ObjectCalendarRenderer, ObjectGanttRenderer, ObjectMapRenderer) pass dataSource={null as any} to their components without checking if the schema has inline data first. This differs from the pattern used in the views package where ObjectGridRenderer, ObjectFormRenderer, and ObjectViewRenderer check for inline data before rendering.

If these components are rendered without inline data (i.e., when schema.data.provider is not 'value'), they will throw an error "DataSource required for object/api providers" which will be displayed as an error state. While this is handled gracefully, it would be more consistent to add the same inline data guards that exist in the views package renderers.

Consider adding the same pattern used in packages/views/src/index.tsx lines 68-84 to provide a clearer error message upfront.

Suggested change
const ObjectGanttRenderer: React.FC<{ schema: any }> = ({ schema }) => {
const ObjectGanttRenderer: React.FC<{ schema: any }> = ({ schema }) => {
const provider = schema?.data?.provider;
// When used as a standalone plugin renderer, we only support inline data (provider: 'value')
// because no external DataSource is injected here. This mirrors the guard logic used in
// the views package to fail fast with a clearer error message.
if (provider && provider !== 'value') {
return (
<div className="text-sm text-destructive">
ObjectGantt plugin requires inline data (schema.data.provider === &quot;value&quot;) when no
DataSource is provided. Use a views renderer or supply inline data for this plugin.
</div>
);
}

Copilot uses AI. Check for mistakes.

// Register component
const ObjectMapRenderer: React.FC<{ schema: any }> = ({ schema }) => {
return <ObjectMap schema={schema} dataSource={null as any} />;
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.

The plugin renderers (ObjectCalendarRenderer, ObjectGanttRenderer, ObjectMapRenderer) pass dataSource={null as any} to their components without checking if the schema has inline data first. This differs from the pattern used in the views package where ObjectGridRenderer, ObjectFormRenderer, and ObjectViewRenderer check for inline data before rendering.

If these components are rendered without inline data (i.e., when schema.data.provider is not 'value'), they will throw an error "DataSource required for object/api providers" which will be displayed as an error state. While this is handled gracefully, it would be more consistent to add the same inline data guards that exist in the views package renderers.

Consider adding the same pattern used in packages/views/src/index.tsx lines 68-84 to provide a clearer error message upfront.

Suggested change
return <ObjectMap schema={schema} dataSource={null as any} />;
const provider = schema?.data?.provider;
const hasInlineData = provider === 'value';
const inlineData = hasInlineData ? schema?.data?.value : undefined;
if (!hasInlineData) {
return (
<div className="text-sm text-red-500">
Object Map plugin requires inline data. Set <code>schema.data.provider = &quot;value&quot;</code> and provide
inline data to use this renderer.
</div>
);
}
return <ObjectMap schema={schema} dataSource={inlineData} />;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants