npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@object-ui/plugin-dashboard

v4.6.0

Published

Dashboard plugin for Object UI

Readme

@object-ui/plugin-dashboard

Dashboard plugin for Object UI - Create beautiful dashboards with metrics, charts, and widgets.

Features

  • Dashboard Layouts - Grid-based dashboard layouts
  • Metric Cards - Display KPIs and statistics
  • Widget System - Modular widget components
  • Responsive - Mobile-friendly dashboard grids
  • Customizable - Tailwind CSS styling support

Installation

pnpm add @object-ui/plugin-dashboard

Usage

Automatic Registration (Side-Effect Import)

// In your app entry point (e.g., App.tsx or main.tsx)
import '@object-ui/plugin-dashboard';

// Now you can use dashboard types in your schemas
const schema = {
  type: 'dashboard',
  widgets: [
    {
      type: 'metric-card',
      title: 'Total Sales',
      value: '$123,456',
      trend: 'up',
      trendValue: '+12%'
    }
  ]
};

Manual Registration

import { dashboardComponents } from '@object-ui/plugin-dashboard';
import { ComponentRegistry } from '@object-ui/core';

// Register dashboard components
Object.entries(dashboardComponents).forEach(([type, component]) => {
  ComponentRegistry.register(type, component);
});

Schema API

Dashboard

Container for dashboard widgets:

{
  type: 'dashboard',
  widgets: Widget[],
  columns?: number,               // Grid columns (default: 3)
  gap?: number,                   // Gap between widgets
  className?: string
}

Metric Card

Display a single metric or KPI:

{
  type: 'metric-card',
  title: string,
  value: string | number,
  icon?: string,                  // Lucide icon name
  trend?: 'up' | 'down' | 'neutral',
  trendValue?: string,
  description?: string,
  className?: string
}

Examples

Basic Dashboard

const schema = {
  type: 'dashboard',
  columns: 3,
  gap: 4,
  widgets: [
    {
      type: 'metric-card',
      title: 'Total Users',
      value: '1,234',
      icon: 'users',
      trend: 'up',
      trendValue: '+12%',
      description: 'vs last month'
    },
    {
      type: 'metric-card',
      title: 'Revenue',
      value: '$56,789',
      icon: 'dollar-sign',
      trend: 'up',
      trendValue: '+8.2%',
      description: 'vs last month'
    },
    {
      type: 'metric-card',
      title: 'Active Sessions',
      value: '432',
      icon: 'activity',
      trend: 'down',
      trendValue: '-3%',
      description: 'vs last month'
    }
  ]
};

Dashboard with Charts

const schema = {
  type: 'dashboard',
  widgets: [
    {
      type: 'metric-card',
      title: 'Total Revenue',
      value: '$123,456'
    },
    {
      type: 'card',
      title: 'Sales Trend',
      body: {
        type: 'line-chart',
        data: [/* chart data */],
        height: 300
      }
    },
    {
      type: 'card',
      title: 'Category Distribution',
      body: {
        type: 'pie-chart',
        data: [/* chart data */]
      }
    }
  ]
};

Responsive Dashboard

const schema = {
  type: 'dashboard',
  columns: 4,
  gap: 6,
  className: 'lg:grid-cols-4 md:grid-cols-2 sm:grid-cols-1',
  widgets: [/* widgets */]
};

Integration with Data Sources

Connect dashboard to live data:

import { createObjectStackAdapter } from '@object-ui/data-objectstack';

const dataSource = createObjectStackAdapter({
  baseUrl: 'https://api.example.com',
  token: 'your-auth-token'
});

const schema = {
  type: 'dashboard',
  dataSource,
  widgets: [
    {
      type: 'metric-card',
      title: 'Total Users',
      value: '${data.metrics.totalUsers}',
      trend: '${data.metrics.userTrend}'
    }
  ]
};

TypeScript Support

import type { DashboardSchema, MetricCardSchema } from '@object-ui/plugin-dashboard';

const metricCard: MetricCardSchema = {
  type: 'metric-card',
  title: 'Revenue',
  value: '$123,456',
  trend: 'up',
  trendValue: '+12%'
};

const dashboard: DashboardSchema = {
  type: 'dashboard',
  columns: 3,
  widgets: [metricCard]
};

Customization

All components support Tailwind CSS classes:

const schema = {
  type: 'metric-card',
  title: 'Custom Metric',
  value: '100',
  className: 'bg-gradient-to-r from-blue-500 to-purple-600 text-white'
};

Type-aware list/table widget cells

Dashboard type: 'table' widgets bound to an objectName automatically render each cell using the appropriate component for the field's type — the same cell renderers used by ObjectGrid (the list view) and reports (@object-ui/plugin-report).

You don't need to declare type on each column. The widget fetches the object schema once and infers the renderer from the bound field:

| Field type | Cell rendering | |---|---| | select / picklist / status | Translated label inside a colored Badge | | lookup / reference / master_detail / user / owner | Display name (FK is auto-expanded server-side via $expand) | | boolean | Checkbox | | email | mailto: link | | url | Clickable link | | phone | Phone link with copy button | | date / datetime | Locale-formatted date | | currency | Locale currency (or honour format: '$0,0') | | percent | 0% / 0.0% formatted (honour format) |

Author overrides always win — pass type, format, options, referenceTo, or your own cell function on a column to bypass auto-detection.

{
  "type": "table",
  "objectName": "opportunity",
  "columns": [
    { "accessorKey": "name",        "header": "Opportunity" },
    { "accessorKey": "account",     "header": "Account" },
    { "accessorKey": "amount",      "header": "Amount",      "format": "$0,0" },
    { "accessorKey": "stage",       "header": "Stage" },
    { "accessorKey": "probability", "header": "Probability", "format": "0%" },
    { "accessorKey": "close_date",  "header": "Close Date",  "format": "YYYY-MM-DD" },
    { "accessorKey": "owner",       "header": "Owner" }
  ]
}

DashboardGridLayout — persisting drag / resize edits

DashboardRenderer — design-mode widget reorder

When DashboardRenderer is used in design mode (designMode={true} plus an onWidgetsReorder callback), widgets become sortable via @dnd-kit. Dragging a widget over another inserts it at that index (insertion semantics, not swap) — the array order is the visual order because widgets render with gridColumn: span W. The renderer calls onWidgetsReorder(nextWidgets) with the reordered array; the host (e.g. DashboardView) is responsible for persisting the change via its DataSource.

A 5px pointer-activation distance keeps click-to-select working on the same widget surface.

DashboardGridLayout — persisting drag / resize edits

DashboardGridLayout (registered as schema type: 'dashboard-grid') has an inline "Edit Layout" mode that lets users drag and resize widgets via react-grid-layout. When the user clicks Save Layout, the new grid coordinates are merged back into schema.widgets[].layout and handed off through the onSchemaChange callback.

<DashboardGridLayout
  schema={dashboard}
  // ✅ Preferred — write the updated schema through your data adapter.
  onSchemaChange={(next) => client.meta.saveItem('dashboard', next.name, next)}
/>

If onSchemaChange is not provided, layout edits stay in component state and are lost on refresh — a console.warn is emitted in development to flag the missing wiring. The component never writes to localStorage or any other storage on its own: persistence is the parent's concern, delegated to whatever data adapter you have injected (REST, ObjectQL, file system, …) per the protocol-agnostic architecture rule.

⚠️ Removed in 3.4: the legacy persistLayoutKey prop and its built-in localStorage fallback have been removed. Previously a shared default key 'dashboard-layout' caused layouts to bleed across dashboards. If you still want a browser-local cache for a demo, do it in the parent inside onSchemaChange.

Compatibility

  • React: 18.x or 19.x
  • Node.js: ≥ 18
  • TypeScript: ≥ 5.0 (strict mode)
  • @objectstack/spec: ^3.3.0
  • @objectstack/client: ^3.3.0
  • Tailwind CSS: ≥ 3.4 (for packages with UI)

Links

License

MIT — see LICENSE.