Skip to content

brennerpablo/components-app

Repository files navigation

components-app

Personal component library built with Next.js + React + shadcn/ui. Components are designed to be copied into other projects (shadcn-style copy-paste model — no package to install, no version lock-in).

Stack: Next.js 16 · React 19 · TypeScript · Tailwind CSS v4 · shadcn/ui (New York, neutral) · Radix UI · Lucide React


Agent Skills — Copying Components Efficiently

This section is written for AI coding agents. Follow this protocol to copy or update a component with no wasted steps.

1. Read the component entry first

Each component section contains everything needed. Before touching any files, read the entry for the component you want:

  • Files to copy — exact paths relative to this repo root
  • shadcn dependencies — run these in the target project before pasting files
  • npm dependencies — install these in the target project
  • Internal dependencies — files outside the component folder (e.g. lib/) that must also be copied
  • Type augmentations.d.ts files that extend third-party modules; copy alongside the component files

2. Install dependencies first (order matters)

Run shadcn and npm installs in the target project before copying files. If the target already has shadcn set up, npx shadcn@latest add is safe to re-run — it skips already-present primitives.

1. npx shadcn@latest add <primitives>    # generates shadcn primitives
2. npm install <packages>                # installs npm deps
3. Copy files from this repo             # paste component files

If Atlaskit DnD packages are listed, always use --legacy-peer-deps.

3. Copy files at the exact same paths

Preserve the directory structure. A component at components/ui/data-table/DataTable.tsx here should land at the same path in the target. The barrel index.ts must be included — imports reference it.

4. Check for internal dependencies

Any file listed under Internal dependencies that is not lib/utils.ts must also be copied. lib/utils.ts is assumed present in every shadcn project and can be skipped.

5. Apply type augmentations

Files listed under Type augmentations (e.g. TanstackTable.d.ts) extend third-party module types. Copy them into the same path in the target project. They must be included in tsconfig.json's include glob (the default "**/*.d.ts" covers it).

6. Verify

After copying, confirm:

  • No missing import errors (check @/components/ui/<name> resolves)
  • No missing peer dependency warnings at runtime
  • The component renders correctly against the Usage example in the README entry

Updating an existing component

When pulling in a newer version of a component from this repo:

  1. Diff the component files — look for new or removed props, changed types, new internal deps
  2. Re-check shadcn dependencies and npm dependencies for any additions
  3. Update call sites in the target project if props changed (the Props table in the README entry is the source of truth)
  4. Update any type augmentation files if the .d.ts changed

Copying Components

Each component below lists everything you need to bring it into another project:

  1. Copy the listed files into the same paths in your project
  2. Run the shadcn command to install any required primitives
  3. Run npm install for any additional packages
  4. Copy any listed internal dependencies (shared utilities)
  5. Add any listed type augmentation files

Your target project should already have a shadcn/ui setup with lib/utils.ts (the cn() utility).


Component Template

When adding or updating a component, copy this scaffold and fill it in:

### Component Name

Brief description of what the component does and its main features (2–3 sentences).

**Demo:** `localhost:3000/<route>`

#### Files to copy

\```
components/ui/<name>/ComponentName.tsx
components/ui/<name>/index.ts
\```

#### shadcn dependencies

\```bash
npx shadcn@latest add button input # ...
\```

#### npm dependencies

\```bash
npm install package-a package-b
\```

#### Internal dependencies

| File               | Purpose                     |
| ------------------ | --------------------------- |
| `lib/some-util.ts` | Description of what it does |

#### Type augmentations

| File           | What it augments                                 |
| -------------- | ------------------------------------------------ |
| `SomeLib.d.ts` | Extends `some-package` module with custom fields |

#### Usage

\```tsx
import { ComponentName } from "@/components/ui/<name>"

export default function Page() {
return <ComponentName prop="value" />
}
\```

#### Notes

- Any special flags, caveats, or known issues.

Components

ProgressBar

A Tremor-style horizontal progress bar with semantic color variants (default, neutral, success, warning, error), optional animation, and an optional label. Adapted from Tremor — no external dependencies beyond cn().

Demo: localhost:3000/charts/progress-bar

Files to copy

components/charts/progress-bar/ProgressBar.tsx
components/charts/progress-bar/index.ts

shadcn dependencies

None.

npm dependencies

None.

Internal dependencies

File Purpose
lib/utils.ts cn() class utility

Usage

import { ProgressBar } from "@/components/ui/progress-bar"

<ProgressBar value={60} variant="default" label="60%" />
<ProgressBar value={3} max={5} showAnimation label="3/5" />

Props

Prop Type Default Description
value number 0 Current progress value.
max number 100 Upper boundary value.
variant "default" | "neutral" | "success" | "warning" | "error" "default" Color scheme of the bar.
showAnimation boolean false Enables a CSS transition when the value changes.
label string Optional text displayed to the right of the bar.
className string Extra classes applied to the outer wrapper div.

Notes

  • Inherits all HTMLDivElement props (forwarded to the outer wrapper).
  • Value is clamped between 0 and max internally — no need to guard at call sites.

DataTable

A fully-featured data table with sorting, filtering, pagination, row selection, column management, and CSV export. Built on TanStack Table with drag-and-drop column reordering powered by Atlaskit Pragmatic DnD.

Demo: localhost:3000/data-table

Files to copy

components/ui/data-table/DataTable.tsx
components/ui/data-table/DataTableBulkEditor.tsx
components/ui/data-table/DataTableColumnHeader.tsx
components/ui/data-table/DataTableFilter.tsx
components/ui/data-table/DataTableFilterbar.tsx
components/ui/data-table/DataTableLocaleContext.tsx
components/ui/data-table/DataTablePagination.tsx
components/ui/data-table/DataTableRowActions.tsx
components/ui/data-table/DataTableViewOptions.tsx
components/ui/data-table/TanstackTable.d.ts
components/ui/data-table/columnBuilder.tsx
components/ui/data-table/i18n.ts
components/ui/data-table/types.ts
components/ui/data-table/index.ts
lib/exportTableToCSV.ts
lib/exportTableToXLSX.ts

shadcn dependencies

npx shadcn@latest add button checkbox dropdown-menu input label popover select table

npm dependencies

npm install @tanstack/react-table papaparse xlsx use-debounce tiny-invariant
npm install --legacy-peer-deps @atlaskit/pragmatic-drag-and-drop @atlaskit/pragmatic-drag-and-drop-flourish @atlaskit/pragmatic-drag-and-drop-hitbox @atlaskit/pragmatic-drag-and-drop-live-region @atlaskit/pragmatic-drag-and-drop-react-drop-indicator

Internal dependencies

File Purpose
lib/utils.ts cn() utility — already present in any shadcn project
lib/exportTableToCSV.ts CSV export helper using PapaParse
lib/exportTableToXLSX.ts XLSX export helper using SheetJS

Type augmentations

File What it augments
TanstackTable.d.ts Extends @tanstack/react-table ColumnMeta with className?: string and displayName: string

Usage

// columns.tsx — generic factory for static utility columns (select checkbox + row actions)
import { DataTableRowActions } from "@/components/ui/data-table";
import { ColumnDef, createColumnHelper } from "@tanstack/react-table";

export function createColumns<TData>(): ColumnDef<TData>[] {
  const helper = createColumnHelper<TData>();
  return [
    helper.display({ id: "select" /* checkbox header/cell */ }),
    helper.display({
      id: "edit",
      cell: ({ row }) => <DataTableRowActions row={row} />,
    }),
  ];
}

// page.tsx — simple pattern (no custom cell/header)
// Use InferRowType to derive the row type automatically from the metadata
import { DataTable, ColumnMetadata, InferRowType } from "@/components/ui/data-table";
import { createColumns } from "./columns";
import { data } from "./data";

const columnsMetadata = [
  {
    columnId: "name",
    title: "Name",
    type: "text",
    sortable: true,
    filters: { text: true },
  },
  {
    columnId: "amount",
    title: "Amount",
    type: "number",
    sortable: true,
    aligned: "right",
    filters: { number: true },
    formatter: (value) => `$${value}`,
    filterValueFormatter: (value) => `$${value}`,
  },
] as const satisfies ColumnMetadata[];

type Row = InferRowType<typeof columnsMetadata>;

export default function Page() {
  return (
    <DataTable<Row>
      columns={createColumns<Row>()}
      columnsMetadata={columnsMetadata}
      data={data}
      tableName="fund_assets"
      language="en"
    />
  );
}

Custom cell and header renderers

When a column needs JSX beyond what formatter covers (icons, badges, data from multiple fields), use the cell field. Similarly, header fully replaces the default DataTableColumnHeader when you need a non-standard header.

Note on typing: InferRowType creates a circular reference when the metadata array references Row inside a cell/header callback. In this case, define Row manually and annotate with ColumnMetadata<Row>[] instead.

import {
  DataTable,
  DataTableColumnHeader,
  ColumnMetadata,
} from "@/components/ui/data-table";
import { CheckCircle2, AlertTriangle, User } from "lucide-react";

// Define Row manually when using cell/header overrides
type Row = {
  owner: string
  status: "live" | "inactive" | "archived"
  pl: number
  plMin: number
  enquadrado: string
}

const columnsMetadata = [
  {
    columnId: "owner",
    title: "Owner",
    type: "text",
    sortable: true,
    filters: { text: true },
    // custom header — wraps DataTableColumnHeader to keep sort button
    header: ({ column }) => (
      <div className="flex items-center gap-1.5">
        <User className="h-3.5 w-3.5 text-muted-foreground" />
        <DataTableColumnHeader column={column} title="Owner" />
      </div>
    ),
  },
  {
    columnId: "status",
    title: "Status",
    type: "text",
    sortable: true,
    inferOptions: true,
    filters: { checkbox: true },
    // custom cell — badge with conditional colour
    cell: ({ row }) => {
      const s = row.original.status;
      const styles = { live: "bg-emerald-100 text-emerald-700", inactive: "bg-muted text-muted-foreground", archived: "bg-amber-100 text-amber-700" };
      return <span className={`rounded-full px-2 py-0.5 text-xs font-medium ${styles[s]}`}>{s}</span>;
    },
  },
  {
    columnId: "pl",
    title: "PL",
    subtitle: "(Min)",           // rendered below the title by DataTableColumnHeader
    type: "number",
    sortable: true,
    aligned: "right",
    filters: { number: true },
    // custom cell — icon + value from multiple fields via row.original
    cell: ({ row }) => (
      <div className="flex items-center gap-1.5">
        {row.original.enquadrado === "True"
          ? <CheckCircle2 className="h-3 w-3 text-emerald-600" />
          : <AlertTriangle className="h-3 w-3 text-orange-400" />}
        <span className="text-xs">{row.original.pl}</span>
        <span className="text-[9px]">({row.original.plMin})</span>
      </div>
    ),
  },
] as const satisfies ColumnMetadata<Row>[];

export default function Page() {
  return (
    <DataTable<Row>
      columns={createColumns<Row>()}
      columnsMetadata={columnsMetadata}
      data={data}
      tableName="fund_assets"
      language="pt"
    />
  );
}

DataTable props:

Prop Type Required Description
columns ColumnDef<TData>[] Yes Static display columns — first element is the select column, last is the row-actions column
data TData[] Yes Row data
columnsMetadata ColumnMetadata<TData>[] No Declarative descriptors that auto-build the data columns and filter controls
persistColumnOrder boolean No Saves column order to a cookie (data-table-column-order) and restores it on mount. Defaults to false.
tableName string No Base filename for CSV/XLSX exports. Produces {tableName}-{YYYY-MM-DD}.csv / .xlsx. Also used as localStorage key when persistColumnOrder is true. Defaults to "export".
enableRowSelection boolean No Enables row checkboxes and click-to-select. Shows an accent-colored left-border on selected rows and reveals the BulkEditor bar. Defaults to false.
enableRowActions boolean No Appends the per-row actions column (ellipsis menu via DataTableRowActions). Defaults to false.
enablePagination boolean No Shows pagination controls and slices rows into pages. Defaults to true. Set to false to render all rows at once.
pageSize number No Number of rows per page when pagination is enabled. Defaults to 20.
paginationDisplayTop boolean No When true, renders the pagination row between the filterbar and the table instead of below it. Defaults to false.
language DataTableLanguage No UI language for built-in labels. "en" (default) or "pt". Import DataTableLanguage from @/components/ui/data-table.
enableTextSelection boolean No Allows users to select and copy text from table cells. Defaults to true. Set to false to disable selection (e.g. when click interactions conflict).
enableFullscreen boolean No Adds a fullscreen toggle button to the toolbar (right of the View button). Opens the table in a fixed overlay covering the entire viewport via a React portal. Press Escape or click the button again to exit. Defaults to false.
enableDownload boolean No Shows or hides the Export dropdown button (CSV / XLSX) in the toolbar. Defaults to true.
enableColumnOptions boolean No Shows or hides the View (column visibility/reorder) button in the toolbar. Defaults to true.
toolbarIconsOnly boolean No When true, toolbar buttons (Export, View, Fullscreen) render only their icon without a text label. Defaults to false.
accentColor string No Accent color for active filter button backgrounds, filter value labels, the row-selection indicator bar, and the clear-filters button. Accepts a Tailwind color token ("blue-600") or any CSS color value ("#3b82f6"). Defaults to zinc-800.
onRowAction { onAdd?, onEdit?, onDelete? } No Callbacks for the per-row action dropdown (requires enableRowActions). Each receives row.original as TData. Only items with a provided callback are rendered in the menu.
onBulkAction { onEdit?, onDelete? } No Callbacks for the bulk editor toolbar (requires enableRowSelection). Each receives TData[] for all selected rows. Commands are disabled when no callback is provided.

ColumnMetadata fields:

Field Type Description
columnId keyof TData & string Accessor key matching the data property
title string Column header label
subtitle string Optional secondary label shown below the title in the header
description string Tooltip text shown on hover of an info icon in the header
type "text" | "number" Data type — controls available filter types
sortable boolean Enable column sorting. Default false
hideable boolean Show in view options toggle. Default true
options OptionItem[] Options array for select / checkbox / checkboxSearch filters
filters.text boolean Debounced text search input
filters.textColumns string[] Additional column IDs searched alongside the primary text column. Placeholder auto-updates to list all column titles.
filters.select boolean Single-value dropdown filter
filters.checkbox boolean Multi-value checkbox filter (arrIncludesSome)
filters.checkboxSearch boolean | { multiple?: boolean } Checkbox list with search box. multiple: false for single-select (radio-style). Default: true
filters.number boolean Condition + value filter (only for type: "number")
aligned "left" | "center" | "right" Cell text alignment
formatter (value: unknown) => ReactNode Simple cell renderer — receives the column's value only
filterValueFormatter (value: number | string) => string Formats values displayed inside the number filter popover
cell (props: CellContext<TData, unknown>) => ReactNode Full cell renderer override — receives the complete TanStack CellContext (use row.original to access other fields). Takes precedence over formatter.
header (props: HeaderContext<TData, unknown>) => ReactNode Full header renderer override — replaces the default DataTableColumnHeader. Wrap DataTableColumnHeader inside it to keep the sort button.

Features:

  • Metadata-driven column and filter construction — add a column by adding one object to columnsMetadata
  • cell and header overrides on any ColumnMetadata entry — full TanStack CellContext/HeaderContext access, including row.original for multi-field cells
  • InferRowType<typeof columnsMetadata> utility — derive a fully-typed row type automatically from a const metadata array; when cell/header overrides are used, define Row manually and annotate with ColumnMetadata<Row>[] instead
  • Filter types: single select, multi-checkbox, numeric condition (built-in conditions: is equal to, is between, is greater than, is less than), debounced text search
  • Row selection with emerald left-border indicator
  • Bulk action command bar (keyboard shortcuts: e edit · d delete · Escape clear)
  • Column visibility toggle + drag-and-drop reordering with accessibility live region announcements
  • Persistent column order via cookie (persistColumnOrder prop)
  • Pagination (20 rows/page) with responsive first/last buttons
  • CSV and XLSX export via the Export dropdown (visible, filtered rows only) — filename controlled via tableName prop
  • Fullscreen overlay mode via React portal (ESC to dismiss)

Notes

  • Atlaskit DnD packages require --legacy-peer-deps due to a React 19 peer dependency conflict

StatusMap

A grid-based status heatmap that renders rows × dates cells, each colored by a status key. Useful for operational dashboards (machine status, service health, etc.). Fully driven by props — pass data, a label config, and display options.

Demo: localhost:3000/status-map

Files to copy

components/ui/status-map/StatusHeatmap.tsx
components/ui/status-map/types.ts
components/ui/status-map/index.ts

shadcn dependencies

None required.

npm dependencies

npm install date-fns

Internal dependencies

File Purpose
lib/utils.ts cn() utility — already in any shadcn project

Type augmentations

None.

Usage

import { StatusMap } from "@/components/ui/status-map"
import type { StatusMapEntry } from "@/components/ui/status-map"

const data: StatusMapEntry[] = [
  { row: "Machine A", date: "2025-03-01", status: "green" },
  { row: "Machine A", date: "2025-03-02", status: "red" },
  { row: "Machine B", date: "2025-03-01", status: "orange" },
]

export default function Page() {
  return (
    <StatusMap
      data={data}
      labelConfig={{
        green:  { color: "bg-emerald-500", label: "Operational" },
        orange: { color: "bg-orange-400",  label: "Warning" },
        red:    { color: "bg-red-500",     label: "Fault" },
        grey:   { color: "bg-muted",       label: "No data" },
      }}
      label
      labelAlign="right"
      labelTop={false}
      style="rounded"
      onCellClick={(row, date, status) => console.log(row, date, status)}
    />
  )
}

Props:

Prop Type Default Description
data StatusMapEntry[] Array of { row, date, status }. Missing row/date combinations fall back to the last key in labelConfig.
labelConfig Record<string, StatusItemConfig> Maps status keys to { color: string, label: string }. color is a Tailwind bg class (e.g. "bg-emerald-500").
style "rounded" | "squared" | "tight" "rounded" Cell shape. tight collapses padding for dense grids.
bordered boolean true Wraps the grid in a rounded border.
label boolean false Shows a color legend.
labelAlign "left" | "center" | "right" "left" Horizontal alignment of the legend.
labelTop boolean false Renders the legend above the grid instead of below.
className string Additional class names on the root element.
onCellClick (row, date, status) => void Callback fired when a cell is clicked.

StatusMapEntry fields:

Field Type Description
row string Row label (e.g. machine name)
date string ISO "YYYY-MM-DD" date
status string Key into labelConfig

Features:

  • Derives unique rows and dates automatically from data — no manual axis config
  • Missing cells fall back to the last key in labelConfig (intended as a "no data" state)
  • Legend shows count of cells per status in parentheses
  • Horizontally scrollable for wide date ranges
  • onCellClick for interactive dashboards

Notes

  • Rows appear in insertion order from data; dates are sorted ascending
  • The date field must be "YYYY-MM-DD"; the component appends T00:00:00 to avoid timezone off-by-one errors

Badge

A small label component for displaying status, categories, or counts. Inspired by Tremor's Badge. Supports five semantic color variants (default, neutral, success, warning, error) with automatic light and dark mode styling.

Demo: localhost:3000/ui/badge

Files to copy

components/ui/badge.tsx

shadcn dependencies

None required.

npm dependencies

npm install class-variance-authority

Internal dependencies

File Purpose
lib/utils.ts cn() utility — already in any shadcn project

Type augmentations

None.

Usage

import { Badge } from "@/components/ui/badge"

<Badge variant="default">Default</Badge>
<Badge variant="neutral">Neutral</Badge>
<Badge variant="success">Success</Badge>
<Badge variant="warning">Warning</Badge>
<Badge variant="error">Error</Badge>

Props:

Prop Type Default Description
variant "default" | "neutral" | "success" | "error" | "warning" "default" Color scheme of the badge
className string Additional CSS classes
children React.ReactNode Badge content — text and/or Lucide icons

Features:

  • Five semantic variants: default (blue), neutral (gray), success (emerald), warning (yellow), error (red)
  • Icon support — place any lucide-react icon as a direct child, auto-sized to 12 px
  • Full light and dark mode support via Tailwind color classes
  • Spreads all native span props for aria attributes, event handlers, etc.
  • Exports badgeVariants CVA function for reuse on other elements

Notes

  • Replaces the default shadcn badge.tsx — the variant names differ from shadcn's (default/secondary/destructive/outline)
  • cva is already installed via shadcn's class-variance-authority dependency

Tabs

Accessible tabbed navigation built on Radix UI Tabs primitives. Supports line (underline indicator) and solid (pill with background) variants, icon support inside triggers, disabled states, and full keyboard navigation.

Demo: localhost:3000/tabs

Files to copy

components/ui/tabs.tsx

shadcn dependencies

None required.

npm dependencies

None — uses radix-ui (unified package), which is a peer dependency of any shadcn/ui setup.

Internal dependencies

File Purpose
lib/utils.ts cn() utility — already in any shadcn project

Type augmentations

None.

Usage

import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"

<Tabs defaultValue="overview">
  <TabsList variant="line">
    <TabsTrigger value="overview">Overview</TabsTrigger>
    <TabsTrigger value="settings">Settings</TabsTrigger>
    <TabsTrigger value="billing" disabled>Billing</TabsTrigger>
  </TabsList>
  <TabsContent value="overview">Overview content</TabsContent>
  <TabsContent value="settings">Settings content</TabsContent>
  <TabsContent value="billing">Billing content</TabsContent>
</Tabs>

Props:

Tabs (root):

Prop Type Default Description
defaultValue string Initially active tab value (uncontrolled)
value string Controlled active tab value
onValueChange (value: string) => void Callback fired when the active tab changes
className string Additional CSS classes on the root element

TabsList:

Prop Type Default Description
variant "line" | "solid" "line" "line" uses a border-bottom underline; "solid" uses a pill container with background
className string Additional CSS classes

TabsTrigger:

Prop Type Default Description
value string Identifier for this tab (required)
disabled boolean false Disables interaction with the trigger
className string Additional CSS classes

TabsContent:

Prop Type Default Description
value string Must match the corresponding TabsTrigger value (required)
className string Additional CSS classes

Features:

  • Two visual variants: line (underline indicator) and solid (pill/card active state)
  • Icon support — place any lucide-react icon as a child of TabsTrigger
  • Disabled triggers via the disabled prop
  • Full keyboard navigation (arrow keys, Home/End) inherited from Radix UI
  • Variant context passed automatically from TabsList to TabsTrigger — no extra prop threading needed
  • All sub-components accept className for full styling override

Notes

  • Import as named exports: Tabs, TabsList, TabsTrigger, TabsContent
  • radix-ui must be installed (npm install radix-ui)

ComponentDoc

An in-page documentation block rendered at the bottom of demo pages. Shows a usage code snippet with a copy button and a props table. Follows the component's own props-driven API standard.

Demo: Visible at the bottom of every component demo page (e.g. localhost:3000/data-table, localhost:3000/status-map).

Files to copy

components/ui/component-doc/ComponentDoc.tsx
components/ui/component-doc/index.ts

shadcn dependencies

None required.

npm dependencies

None.

Internal dependencies

File Purpose
lib/utils.ts cn() utility — already in any shadcn project

Type augmentations

None.

Usage

import { ComponentDoc } from "@/components/ui/component-doc"

// Single flat props list:
<ComponentDoc
  title="MyComponent"
  description="Short description of what it does."
  usage={`import { MyComponent } from "@/components/ui/my-component"

<MyComponent requiredProp="value" optionalProp />`}
  props={[
    { name: "requiredProp", type: "string", required: true, description: "..." },
    { name: "optionalProp", type: "boolean", default: "false", description: "..." },
  ]}
/>

// Multiple named prop sections (e.g. component props + sub-type fields):
<ComponentDoc
  title="MyComponent"
  usage={`...`}
  propSections={[
    {
      title: "MyComponent props",
      props: [{ name: "data", type: "Row[]", required: true, description: "..." }],
    },
    {
      title: "Row fields",
      props: [{ name: "id", type: "string", required: true, description: "..." }],
    },
  ]}
/>

Props:

Prop Type Description
title string Component name shown as the section heading.
description string Optional subtitle below the heading.
usage string Raw code string rendered in a syntax-highlighted block with a copy button.
props PropDef[] Flat list of prop definitions. Renders under a single "Props" heading.
propSections PropSection[] Multiple named prop groups, each with its own sub-heading. Use instead of props when there are multiple distinct types to document.
className string Additional class names on the root <section>.

PropDef fields:

Field Type Description
name string Prop name (rendered in monospace)
type string Type string (rendered in a muted code badge)
default string Default value, if any
required boolean Adds a red * next to the prop name
description string Human-readable description

Notes

  • Place <ComponentDoc> at the bottom of every demo page, after the live component demo
  • Update it whenever props are added, removed, or changed

AreaChart

A Tremor-inspired responsive area chart built on Recharts. Supports single and multi-series data, gradient/solid/no-fill modes, stacked and percentage layouts, an interactive legend with optional horizontal slider, custom tooltips, and click events on dots and legend categories.

Demo: localhost:3000/charts/area-chart

Files to copy

components/charts/area-chart/AreaChart.tsx
components/charts/area-chart/index.ts
components/charts/utils/chartColors.ts
components/charts/utils/chartHelpers.ts
components/charts/utils/useOnWindowResize.ts

shadcn dependencies

None.

npm dependencies

npm install recharts

Internal dependencies

File Purpose
lib/utils.ts cn() utility — already present in any shadcn project
components/charts/utils/chartColors.ts Color palette, getColorClass(), constructCategoryColors()
components/charts/utils/chartHelpers.ts getYAxisDomain(), hasOnlyOneValueForKey()
components/charts/utils/useOnWindowResize.ts Window resize hook used to recalculate legend height

Type augmentations

None.

Usage

import { AreaChart } from "@/components/charts/area-chart"

// Single series with value formatter
<AreaChart
  data={revenueData}
  index="month"
  categories={["Revenue"]}
  valueFormatter={(v) => `$${v.toLocaleString()}`}
/>

// Multi-series stacked with solid fill
<AreaChart
  data={trafficData}
  index="month"
  categories={["Organic", "Direct", "Referral"]}
  type="stacked"
  fill="solid"
/>

// Interactive with event callback
<AreaChart
  data={trafficData}
  index="month"
  categories={["Organic", "Direct", "Referral"]}
  onValueChange={(event) => console.log(event)}
/>

Props

Prop Type Default Description
data Record<string, any>[] Required. Array of data objects with the index key and one key per category.
index string Required. Key used as the X-axis label (e.g. "month").
categories string[] Required. Keys from data objects to render as area series.
colors ChartColor[] CHART_COLORS Color names for each category, in order.
valueFormatter (value: number) => string v => v.toString() Formats Y-axis ticks and tooltip values.
type "default" | "stacked" | "percent" "default" Layout mode — default overlapping, stacked cumulative, or normalized to 100%.
fill "gradient" | "solid" | "none" "gradient" Fill style for the area under each line.
axisTextSize "xs" | "sm" | "md" | "lg" | number "xs" Font size for axis tick labels. Named sizes: xs=12, sm=14, md=16, lg=18px.
legendTextSize "xs" | "sm" | "md" | "lg" | number "xs" Font size for legend item labels.
dataPointTextSize "xs" | "sm" | "md" | "lg" | number "xs" Font size for data point labels (requires showDataPointLabels).
showDataPointLabels boolean false When true, renders the formatted value as a label above each data point.
showDataPointLabelBackground boolean false When true, each label gets a rounded background tinted with the series color. Requires showDataPointLabels.
dataPointLabelFormatter (value: number) => string Custom formatter for data point labels. Falls back to valueFormatter when omitted. Useful for compact notation (e.g. 1500000 → "1.5M").
showXAxis boolean true Show the X-axis with tick labels.
showYAxis boolean true Show the Y-axis with tick labels.
showGridLines boolean true Show horizontal grid lines.
showLegend boolean true Show the legend above the chart.
showTooltip boolean true Show the tooltip on hover.
legendPosition "left" | "center" | "right" "right" Horizontal alignment of the legend.
enableLegendSlider boolean false Make the legend horizontally scrollable with arrow buttons.
yAxisWidth number auto Width in pixels reserved for the Y-axis. Defaults to auto-inferred from the largest formatted value in the dataset.
autoMinValue boolean false Set Y-axis minimum to "auto" instead of 0.
minValue number Explicit Y-axis domain minimum.
maxValue number Explicit Y-axis domain maximum.
allowDecimals boolean true Allow decimal Y-axis tick values.
startEndOnly boolean false Show only the first and last X-axis tick labels.
intervalType "preserveStartEnd" | "equidistantPreserveStart" "equidistantPreserveStart" Recharts X-axis tick interval strategy.
tickGap number 5 Minimum gap in pixels between X-axis tick labels.
connectNulls boolean false Bridge null data points instead of creating gaps.
xAxisLabel string Optional label rendered below the X-axis.
yAxisLabel string Optional label rendered to the left of the Y-axis (rotated).
onValueChange (value: AreaChartEventProps) => void Fired when a dot or legend item is clicked; null on deselect.
tooltipCallback (content: TooltipProps) => void Side-effect callback when tooltip active state or label changes.
customTooltip React.ComponentType<TooltipProps> Custom component rendered in place of the default tooltip.
className string Additional classes on the outer wrapper (default height h-80).

Notes

  • The ChartColor type and CHART_COLORS constant are exported from the barrel for external use.
  • The three utility files in components/charts/utils/ are shared across chart components — copy them once and reuse.
  • Recharts requires a fixed height on the container; override with className="h-96" or similar.

BarChart

A Tremor-inspired responsive bar chart built on Recharts. Supports vertical and horizontal bar orientations, multi-category side-by-side and stacked layouts, percent-normalized stacking, an interactive legend with optional slider, custom tooltips, and click events on bars and legend categories.

Demo: localhost:3000/charts/bar-chart

Files to copy

components/charts/bar-chart/BarChart.tsx
components/charts/bar-chart/index.ts
components/charts/utils/chartColors.ts
components/charts/utils/chartHelpers.ts
components/charts/utils/useOnWindowResize.ts

shadcn dependencies

None.

npm dependencies

npm install recharts

Internal dependencies

File Purpose
lib/utils.ts cn() utility — already present in any shadcn project
components/charts/utils/chartColors.ts Color palette, getColorClass(), constructCategoryColors()
components/charts/utils/chartHelpers.ts getYAxisDomain(), inferYAxisWidth(), measureTextWidth()
components/charts/utils/useOnWindowResize.ts Window resize hook used to recalculate legend height

Type augmentations

None.

Usage

import { BarChart } from "@/components/charts/bar-chart"

// Basic single series
<BarChart
  data={salesData}
  index="month"
  categories={["Sales"]}
  valueFormatter={(v) => `$${v.toLocaleString()}`}
/>

// Stacked multi-category
<BarChart
  data={departmentData}
  index="month"
  categories={["Engineering", "Marketing", "Support"]}
  type="stacked"
/>

// Vertical (horizontal bars) with interactive events
<BarChart
  data={regionData}
  index="region"
  categories={["Revenue"]}
  layout="vertical"
  valueFormatter={(v) => `$${v.toLocaleString()}`}
  onValueChange={(event) => console.log(event)}
/>

Props

Prop Type Default Description
data Record<string, any>[] Required. Array of data objects with the index key and one key per category.
index string Required. Key used as the category-axis label (e.g. "month", "region").
categories string[] Required. Keys from data objects to render as bar series.
colors ChartColor[] CHART_COLORS Color names for each category, in order.
valueFormatter (value: number) => string v => v.toString() Formats numeric axis ticks and tooltip values.
layout "vertical" | "horizontal" "horizontal" Orientation — "horizontal" renders vertical bars, "vertical" renders horizontal bars.
type "default" | "stacked" | "percent" "default" Bar display mode — side-by-side, stacked cumulative, or normalized to 100%.
barCategoryGap string | number Gap between bar groups. Accepts a percentage string (e.g. "20%") or pixel value.
axisTextSize "xs" | "sm" | "md" | "lg" | number "xs" Font size for axis tick labels. Named sizes: xs=12, sm=14, md=16, lg=18px.
autoScaleLabels boolean false Automatically shrinks axis tick font size as entry count grows, preventing label overlap on large datasets without scroll.
legendTextSize "xs" | "sm" | "md" | "lg" | number "xs" Font size for legend item labels.
showXAxis boolean true Show the X-axis with tick labels.
showYAxis boolean true Show the Y-axis with tick labels.
showGridLines boolean true Show grid lines (horizontal for default layout, vertical for layout="vertical").
showLegend boolean true Show the legend above the chart.
showTooltip boolean true Show the tooltip on hover.
legendPosition "left" | "center" | "right" "right" Horizontal alignment of the legend.
enableLegendSlider boolean false Make the legend horizontally scrollable with arrow buttons.
yAxisWidth number auto Width in pixels reserved for the Y-axis. Defaults to auto-inferred from labels.
autoMinValue boolean false Set numeric axis minimum to "auto" instead of 0.
minValue number Explicit numeric axis domain minimum.
maxValue number Explicit numeric axis domain maximum.
allowDecimals boolean true Allow decimal tick values on the numeric axis.
startEndOnly boolean false Show only the first and last tick labels on the category axis.
intervalType "preserveStartEnd" | "equidistantPreserveStart" "equidistantPreserveStart" Recharts tick interval strategy for the category axis.
tickGap number 5 Minimum gap in pixels between category-axis tick labels.
xAxisLabel string Optional label rendered below the X-axis.
yAxisLabel string Optional label rendered to the left of the Y-axis (rotated).
onValueChange (value: BarChartEventProps) => void Fired when a bar or legend item is clicked; null on deselect. eventType is "bar" or "category".
tooltipCallback (content: TooltipProps) => void Side-effect callback when tooltip active state or label changes.
customTooltip React.ComponentType<TooltipProps> Custom component rendered in place of the default tooltip.
className string Additional classes on the outer wrapper (default height h-80).

Notes

  • The ChartColor type and CHART_COLORS constant are exported from the barrel for external use.
  • The three utility files in components/charts/utils/ are shared with AreaChart — copy them once and reuse.
  • For type="percent", pass a percent formatter: valueFormatter={(v) => \${(v * 100).toFixed(0)}%`}`.
  • Recharts requires a fixed height on the container; override with className="h-96" or similar.

DonutChart

A Tremor-inspired donut and pie chart for visualizing part-to-whole relationships. Supports an optional center label (auto-total or custom text), click interactions with active segment highlighting, custom tooltip, and tooltip callbacks. Powered by Recharts.

Demo: localhost:3000/charts/donut-chart

Files to copy

components/charts/donut-chart/DonutChart.tsx
components/charts/donut-chart/index.ts
components/charts/utils/chartColors.ts

shadcn dependencies

None.

npm dependencies

npm install recharts

Internal dependencies

File Purpose
lib/utils.ts cn() utility — already present in any shadcn project
components/charts/utils/chartColors.ts Color palette, getColorClass(), constructCategoryColors()

Type augmentations

None.

Usage

import { DonutChart } from "@/components/charts/donut-chart"

// Basic donut
<DonutChart
  data={data}
  category="browser"
  value="share"
  valueFormatter={(v) => `${v}%`}
/>

// With center label (shows sum of all values)
<DonutChart
  data={data}
  category="browser"
  value="share"
  showLabel
  valueFormatter={(v) => `${v}%`}
/>

// Pie variant
<DonutChart
  data={data}
  category="region"
  value="revenue"
  variant="pie"
  valueFormatter={(v) => `$${v.toLocaleString()}`}
/>

// Interactive
<DonutChart
  data={data}
  category="browser"
  value="share"
  onValueChange={(event) => console.log(event)}
/>

Props

Prop Type Default Description
data Record<string, any>[] Required. Array of data objects with keys for category labels and numeric values.
category string Required. Key in each data object used as the segment label (e.g. "browser", "region").
value string Required. Key in each data object used as the segment's numeric value.
colors ChartColor[] CHART_COLORS Color palette for each segment. Cycles if fewer colors than segments.
variant "donut" | "pie" "donut" Shape variant — "donut" renders a ring, "pie" fills the center.
valueFormatter (value: number) => string v => v.toString() Formats tooltip values and the center label total.
label string Custom text shown in the center (donut only). When omitted, the sum of all values is shown.
showLabel boolean false Show a label in the center of the donut. Has no effect on the pie variant.
showTooltip boolean true Show or hide the tooltip on hover.
onValueChange (value: DonutChartEventProps) => void Fired when a segment is clicked. Returns { eventType: "sector", categoryClicked, ...dataRow } or null on deselect.
tooltipCallback (content: TooltipProps) => void Side-effect callback fired when tooltip active state or hovered category changes.
customTooltip React.ComponentType<TooltipProps> Custom component rendered in place of the default tooltip. Receives active and payload.
className string Additional classes on the outer wrapper. The chart has min-h-40 and aspect-square by default — it fills the parent height while staying circular.

Notes

  • Default size is h-40 w-40 — override with className="h-48 w-48" or any size.
  • Center label is only rendered when variant="donut" and showLabel={true}.
  • Clicking an active segment deselects it and fires onValueChange(null).
  • Only chartColors.ts is required from the utils directory (no axis helpers needed).

Card

A fundamental layout primitive for grouping content — KPI cards, forms, or sections. Adapts Tremor's Card design using project CSS variable tokens. Supports asChild for rendering as any semantic element.

Demo: localhost:3000/ui/card

Files to copy

components/ui/card/Card.tsx
components/ui/card/index.ts

shadcn dependencies

None.

npm dependencies

None (radix-ui unified package already required by other components).

Internal dependencies

File Purpose
lib/utils.ts cn() utility

Type augmentations

None.

Usage

import { Card } from "@/components/ui/card"

// Basic
<Card className="max-w-sm">
  <p className="text-sm text-muted-foreground">Card content</p>
</Card>

// Semantic HTML via asChild
<ul>
  <Card asChild>
    <li>List item styled as a card</li>
  </Card>
</ul>

Props

Prop Type Default Description
enableFullscreen boolean false When true, shows a fullscreen toggle button in the top-right corner. Expands via portal; Escape to exit.
hoverShadow boolean false When true, applies a subtle shadow on hover with a smooth fade-in transition.
asChild boolean false When true, merges Card props onto its first child element instead of rendering a <div>.
className string Additional Tailwind classes to customize the card.
...props React.HTMLAttributes<HTMLDivElement> All standard div props are forwarded.

Notes

  • Default styles: rounded-lg border border-border bg-card p-6 shadow-xs.
  • Override padding with className="p-4" or any Tailwind spacing class.
  • asChild uses Radix UI's Slot.Root from the radix-ui unified package.

DatePicker

A date picker input that opens a popover calendar. Supports single date, date range, and date + time selection modes with i18n (en/pt).

Demo: localhost:3000/date-picker

Files to copy

components/ui/date-picker/date-picker.tsx
components/ui/date-picker/index.ts

shadcn dependencies

npx shadcn@latest add button popover calendar

npm dependencies

npm install date-fns react-day-picker

Internal dependencies

File Purpose
lib/utils.ts cn() utility

Usage

import { DatePicker } from "@/components/ui/date-picker"

// Single date
<DatePicker value={date} onChange={setDate} />

// Date range
<DatePicker mode="range" value={range} onChange={setRange} />

// Date + time
<DatePicker mode="datetime" value={dateTime} onChange={setDateTime} />

// With constraints and i18n
<DatePicker
  value={date}
  onChange={setDate}
  minDate={new Date()}
  maxDate={addDays(new Date(), 30)}
  language="pt"
/>

Props

Prop Type Default Description
mode "single" | "range" | "datetime" "single" Selection mode
value Date | DateRange | undefined Selected value (type depends on mode)
onChange (value) => void Called when selection changes
displayFormat "long" | "short" "long" "long" = full date (March 21, 2026), "short" = dd/MM/yyyy
enableDayNavigation boolean false Single mode only. Adds chevron buttons to step one day forward/backward
placeholder string Localized default Custom placeholder text
disabled boolean false Disables the trigger
disableWeekends boolean false Prevents selection of Saturdays and Sundays
disabledDates string[] Array of dates in "yyyy-MM-dd" format to disable
enableYearMonthSelect boolean false Shows dropdown selects for year and month in the calendar header
language "en" | "pt" "en" Locale for labels and formatting
format string Per-mode default Custom date-fns format string
minDate Date Earliest selectable date
maxDate Date Latest selectable date
triggerClassName string Additional classes for the trigger button
className string Additional classes for the popover content

Features

  • Three modes — single date, date range (from/to), date + time (24h)
  • Auto-close — popover closes on single select, stays open for datetime
  • i18n — English and Portuguese labels, month names, and date formatting
  • Min/max constraints — disable dates outside a range
  • Controlled — fully controlled via value/onChange

Notes

  • Uses react-day-picker v9 and date-fns v4 (both already in this repo).
  • Time input uses 24-hour format.
  • The DateRange type is { from?: Date; to?: Date } from react-day-picker.
  • The discriminated union on mode makes value and onChange type-safe per mode.

MonthPicker

A year/month picker with popover. The user selects a year from a dropdown and a month from a 3-column button grid.

Demo: localhost:3000/month-picker

Files to copy

  • components/ui/month-picker/month-picker.tsx
  • components/ui/month-picker/index.ts

Dependencies

shadcn: button, popover npm: date-fns, lucide-react

Usage

import { MonthPicker } from "@/components/ui/month-picker"

const [value, setValue] = useState<{ year: number; month: number }>()

<MonthPicker value={value} onChange={setValue} />

// With month navigation arrows
<MonthPicker value={value} onChange={setValue} enableMonthNavigation />

// Constrained range
<MonthPicker
  value={value}
  onChange={setValue}
  minDate={{ year: 2020, month: 0 }}
  maxDate={{ year: 2030, month: 11 }}
/>

Props

Prop Type Default Description
value { year: number; month: number } | undefined Selected value. month is 0-indexed (0 = Jan, 11 = Dec)
onChange (value) => void Called when a month is selected
enableMonthNavigation boolean false Adds < > buttons to step one month forward/backward
placeholder string Localized default Custom placeholder text
disabled boolean false Disables the trigger
language "en" | "pt" "en" Locale for labels and month names
size "default" | "sm" "default" Trigger size variant
shadow "none" | "xs" | "sm" "xs" Trigger shadow
minDate { year: number; month: number } Earliest selectable year/month (defaults to 100 years back)
maxDate { year: number; month: number } Latest selectable year/month (defaults to 10 years forward)
triggerClassName string Additional classes for the trigger button
className string Additional classes for the popover content

Features

  • Year dropdown + month grid — select year from dropdown, then pick month from a 3-column button grid
  • Month navigation — optional < > arrows to step month-by-month
  • Constrained rangeminDate/maxDate limit selectable months and filter the grid
  • i18n — English and Portuguese month names and labels
  • Consistent styling — matches DatePicker trigger appearance (size, shadow, icons)

Select

A props-driven select dropdown built on Radix UI Select. Supports groups, labels, separators, searchable filtering, custom item rendering, a "last selected" cookie-based memory feature, loading skeleton state, and i18n (en/pt).

Demo: localhost:3000/ui/select

Files to copy

components/ui/select/select.tsx
components/ui/select/index.ts

shadcn dependencies

None.

npm dependencies

None (radix-ui unified package and lucide-react already required by other components).

Internal dependencies

File Purpose
lib/utils.ts cn() utility

Type augmentations

None.

Usage

import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"

<Select value={value} onValueChange={setValue}>
  <SelectTrigger className="w-50">
    <SelectValue placeholder="Pick one" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="apple">Apple</SelectItem>
    <SelectItem value="banana">Banana</SelectItem>
  </SelectContent>
</Select>

{/* Loading state */}
<Select>
  <SelectTrigger className="w-50" loading>
    <SelectValue placeholder="Loading..." />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="x">Option</SelectItem>
  </SelectContent>
</Select>

Props

Select (root)

Prop Type Default Description
value string Controlled selected value.
defaultValue string Uncontrolled default value.
onValueChange (value: string) => void Callback when the selected value changes.
disabled boolean false Disables the entire select.
open boolean Controlled open state of the dropdown.
onOpenChange (open: boolean) => void Callback when the open state changes.
renderItem (entry: { value: string; label: string }) => ReactNode Custom render for each SelectItem's content.
language "en" | "pt" "en" UI language for built-in strings.
selectId string Unique ID used as the cookie key for last-selected persistence.
enableLastSelected boolean false Persists last selection in a cookie and shows a footer suggestion (requires selectId).
renderLastSelected (entry: { value: string; label: string }) => ReactNode Custom render for the last-selected footer content.

SelectTrigger

Prop Type Default Description
size "sm" | "default" "default" Trigger height. sm = 32 px, default = 36 px.
loading boolean false Shows a pulsing skeleton bar inside the trigger and disables it.
className string Additional CSS classes.

SelectContent

Prop Type Default Description
searchable boolean false Renders a search input to filter items. Forces popper positioning.
searchPlaceholder string "Search..." Placeholder for the search input.
position "item-aligned" | "popper" "item-aligned" Positioning strategy. Forced to popper when searchable.
align "start" | "center" | "end" "center" Alignment relative to the trigger.

SelectItem

Prop Type Default Description
value string Required. The value for this option.
searchValue string Custom string to match against when filtering.
disabled boolean false Disables this individual item.

Notes

  • The loading prop on SelectTrigger replaces children with a pulsing skeleton bar and disables the trigger. Requires the skeleton-pulse keyframe in your global CSS.
  • enableLastSelected stores a 90-day cookie keyed by selectId.
  • When searchable is true, the position is forced to "popper" because item-aligned mode doesn't work well with the search input.

MultiSelect

A multi-item select with checkboxes, search input, and chip display for selected values. Consumers render MultiSelectItem children; the component manages selection state internally and reports changes via onValueChange.

Demo: localhost:3000/multi-select

Files to copy

components/ui/multi-select/MultiSelect.tsx
components/ui/multi-select/index.ts

shadcn dependencies

npx shadcn@latest add button command popover

npm dependencies

None.

Internal dependencies

File Purpose
lib/utils.ts cn() class utility

Usage

import { MultiSelect, MultiSelectItem } from "@/components/ui/multi-select"

const options = [
  { value: "a", label: "Option A" },
  { value: "b", label: "Option B" },
]

<MultiSelect
  placeholder="Select..."
  placeholderSearch="Search..."
  onValueChange={(values) => console.log(values)}
>
  {options.map((o) => (
    <MultiSelectItem key={o.value} value={o.value}>
      {o.label}
    </MultiSelectItem>
  ))}
</MultiSelect>

Props — MultiSelect

Prop Type Default Description
onValueChange (value: string[]) => void Called with the updated selected values array on each change.
placeholder string "Select..." Trigger button text when nothing is selected.
placeholderSearch string "Search..." Search input placeholder inside the popover.
disabled boolean false Disables the trigger and prevents the popover from opening.
className string Extra classes applied to the trigger button.
children React.ReactNode MultiSelectItem elements to render as options.

Props — MultiSelectItem

Prop Type Default Description
value string Unique identifier returned in the onValueChange array.
children React.ReactNode Label shown in the list and in the selected chip.
className string Extra classes applied to the command item.

Notes

  • Selected values are displayed as removable chips inside the trigger button.
  • The popover width matches the trigger width via w-(--radix-popover-trigger-width).
  • Relies on cmdk (bundled with the shadcn command primitive) for filtering — no additional search logic needed.

FormulaBuilder

A drag-and-drop formula builder that lets users compose expressions from variable blocks and math operators. Supports controlled value, click-to-add, canvas reordering, token removal, and optional formula validation.

Demo: localhost:3000/formula-builder

Files to copy

components/ui/formula-builder/formula-builder.tsx
components/ui/formula-builder/types.ts
components/ui/formula-builder/index.ts

shadcn dependencies

None.

npm dependencies

npm install --legacy-peer-deps @atlaskit/pragmatic-drag-and-drop @atlaskit/pragmatic-drag-and-drop-flourish @atlaskit/pragmatic-drag-and-drop-hitbox @atlaskit/pragmatic-drag-and-drop-react-drop-indicator tiny-invariant lucide-react

Internal dependencies

File Purpose
lib/utils.ts cn() class utility

Usage

import { FormulaBuilder } from "@/components/ui/formula-builder"

const variables = {
  height: "Person height",
  weight: "Person weight",
  age: "Person age",
}

<FormulaBuilder
  variables={variables}
  value={formula}
  onChange={setFormula}
/>

Props

Prop Type Default Description
variables Record<string, string> Required. Dictionary of variable keys to display labels.
value string Controlled formula string, space-separated.
onChange (formula: string) => void Callback fired when the formula changes.
operators string[] ["+", "-", "*", "/", "(", ")"] Operators available in the palette.
placeholder string "Drag variables and operators here…" Placeholder text for the empty canvas.
disabled boolean false Disables all interaction.
showValidation boolean false Shows validation errors for malformed expressions.
className string Additional className on the root container.

Features

  • Drag variables and operators from palette to canvas
  • Click palette items to append (alternative to drag)
  • Reorder tokens by dragging within the canvas
  • Remove tokens with X button
  • Visual drop indicators for insertion position
  • Optional validation (consecutive operators, unbalanced parentheses)
  • Controlled value/onChange API
  • Custom drag previews
  • Instance isolation (multiple builders on one page)

Notes

  • Atlaskit DnD packages require --legacy-peer-deps due to React 19 peer dep conflict.
  • The formula is stored as a space-separated string of variable keys and operators.
  • Unknown tokens in the value string are treated as variables with the raw key as the label.

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages