diff --git a/CLAUDE.md b/CLAUDE.md index e563921..eeed0fe 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -230,7 +230,6 @@ Components are split across two entry points: **Data Display:** -- **DataTable** - Advanced data table with virtualization, sorting, filtering - **Avatar** - User avatar with image/initials fallback **Navigation:** @@ -251,6 +250,25 @@ Components are split across two entry points: - **StatusBar** - VSCode-style status bar - **Hero** - Hero section component +### DataTable (`baukasten-ui/data-table`) + +- **DataTable** - Advanced data table with virtualization, sorting, filtering + +DataTable has its own entry point because it is the only component that needs +`@tanstack/react-table`. Keeping it out of the `extra` and root barrels is what +makes that peer dependency genuinely optional: Rollup resolves re-exported +modules whether or not their exports are used, so a single re-export from a +barrel would force every consumer of that barrel to install the package. + +```tsx +import { DataTable, type ColumnDef } from 'baukasten-ui/data-table'; +``` + +The related helpers and types — `createSelectColumn`, `useDataTable`, +`useDataTableData`, `applyDataTransaction`, `mergeTransactions`, `ColumnDef`, +`SortingState`, `PaginationState`, `RowSelectionState`, `ColumnResizeMode`, +`Row` — are exported from the same entry. + ## Key Technical Details ### Build System @@ -262,28 +280,32 @@ Components are split across two entry points: ### Package Exports -Main package (`baukasten-ui`) provides three entry points: +Main package (`baukasten-ui`) provides four entry points: -- `baukasten-ui` (`.`) — All components and types (re-exports core + extra) +- `baukasten-ui` (`.`) — All components and types (re-exports core + extra; **not** DataTable) - `baukasten-ui/core` (`./core`) — Fundamental primitives (Button, Input, Icon, Typography, etc.) -- `baukasten-ui/extra` (`./extra`) — Higher-level compositions (DataTable, Tabs, Menu, etc.) -- `baukasten-ui/styles` (`./styles`) — Design token utilities +- `baukasten-ui/extra` (`./extra`) — Higher-level compositions (Tabs, Menu, Tree, etc.) +- `baukasten-ui/data-table` (`./data-table`) — DataTable and its helpers/types + +Design tokens and style utilities come from `baukasten-ui/core`, which re-exports all of `src/styles`. There is no separate `./styles` subpath — one was declared for a long time but never built, so it never resolved. **Core components** (23 families): Icon, IconButton, Button, Input, TextArea, Checkbox, Radio/RadioGroup, Select, Slider, Label, FieldLabel, FormGroup, FormHelper, Typography (Heading/Text/Paragraph/Code/Link/Image), Badge, Tag, Table, Alert, Spinner, ProgressBar, Tooltip, Modal, Divider, Dropdown, PortalProvider, Styles, GlobalStyles -**Extra components** (14 families): DataTable, Tabs, Breadcrumbs, Pagination, Menu, ContextMenu, ButtonGroup, FileUpload, Accordion, SplitPane, StatusBar, Hero, Avatar +**Extra components**: Tabs, Breadcrumbs, Pagination, Menu, ContextMenu, ButtonGroup, FileUpload, Combobox, Drawer, Accordion, SplitPane, StatusBar, Hero, Avatar, Tree + +`@tanstack/react-table` is a genuinely **optional peer dependency**, needed only if you import `baukasten-ui/data-table`. Nothing reachable from `.`, `./core` or `./extra` references it, so consumers who do not use DataTable never install it and never bundle it. -`@tanstack/react-table` is an **optional peer dependency** — only needed when importing DataTable from extra. +**Do not re-export DataTable from `extra.ts` or `index.ts`.** Rollup resolves re-exported modules regardless of whether their exports are used, so one re-export makes the peer dependency mandatory for every consumer of that barrel — which is exactly the bug the separate entry point fixes. ### Core / Extra Split Criteria -| Criterion | Core | Extra | -| ------------------------ | ----------------------------------------------------- | -------------------------------------------- | -| **Usage frequency** | Used in 80%+ of UIs | Used in specific scenarios | -| **Complexity** | Atomic / molecular | Composed from multiple core components | -| **External deps** | Only `clsx`, `@floating-ui/react`, `@vscode/codicons` | `@tanstack/react-table` or future heavy deps | -| **Cross-component deps** | May depend on Icon and styles only | May depend on any core component | -| **Self-contained** | Can work alone with just styles | Needs core components at runtime | +| Criterion | Core | Extra | +| ------------------------ | ----------------------------------------------------- | ------------------------------------------------------------------------------------------ | +| **Usage frequency** | Used in 80%+ of UIs | Used in specific scenarios | +| **Complexity** | Atomic / molecular | Composed from multiple core components | +| **External deps** | Only `clsx`, `@floating-ui/react`, `@vscode/codicons` | Same as core — a heavy optional dep earns its own entry point instead (see `./data-table`) | +| **Cross-component deps** | May depend on Icon and styles only | May depend on any core component | +| **Self-contained** | Can work alone with just styles | Needs core components at runtime | **Key rule**: Extra can import from Core. Core **never** imports from Extra. diff --git a/package-lock.json b/package-lock.json index 3d05cce..c1f0045 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18260,6 +18260,7 @@ "name": "@baukasten/vscode-example", "version": "0.3.0", "dependencies": { + "@tanstack/react-table": "^8.21.3", "baukasten-ui": "*", "react": "^19.0.0", "react-dom": "^19.0.0" @@ -18282,6 +18283,7 @@ "name": "@baukasten/vscode-db-explorer-example", "version": "0.3.0", "dependencies": { + "@tanstack/react-table": "^8.21.3", "baukasten-ui": "*", "react": "^19.0.0", "react-dom": "^19.0.0" @@ -20331,6 +20333,7 @@ "name": "@baukasten/website", "version": "0.3.0", "dependencies": { + "@tanstack/react-table": "^8.21.3", "@types/flexsearch": "^0.7.6", "baukasten-ui": "*", "baukasten-ui-web-wrapper": "*", diff --git a/packages/baukasten/package.json b/packages/baukasten/package.json index 19f1311..6fe493c 100644 --- a/packages/baukasten/package.json +++ b/packages/baukasten/package.json @@ -14,28 +14,29 @@ ], "license": "MIT", "type": "module", - "main": "./dist/index.js", + "main": "./dist/index.cjs", "module": "./dist/index.mjs", "types": "./dist/index.d.ts", "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.mjs", - "require": "./dist/index.js" + "require": "./dist/index.cjs" }, "./core": { "types": "./dist/core.d.ts", "import": "./dist/core.mjs", - "require": "./dist/core.js" + "require": "./dist/core.cjs" }, "./extra": { "types": "./dist/extra.d.ts", "import": "./dist/extra.mjs", - "require": "./dist/extra.js" + "require": "./dist/extra.cjs" }, - "./styles": { - "import": "./dist/styles.mjs", - "require": "./dist/styles.js" + "./data-table": { + "types": "./dist/data-table.d.ts", + "import": "./dist/data-table.mjs", + "require": "./dist/data-table.cjs" }, "./dist/baukasten-base.css": "./dist/baukasten-base.css", "./dist/baukasten-vscode.css": "./dist/baukasten-vscode.css", diff --git a/packages/baukasten/src/extra.ts b/packages/baukasten/src/extra.ts index f3181db..d3f5c67 100644 --- a/packages/baukasten/src/extra.ts +++ b/packages/baukasten/src/extra.ts @@ -13,33 +13,13 @@ // ─── Data ─────────────────────────────────────────────────────────────────── -export { - DataTable, - createSelectColumn, - useDataTable, - useDataTableData, - applyDataTransaction, - mergeTransactions, -} from './components/DataTable'; -export type { - AsyncTransactionsFlushedEvent, - DataTableProps, - DataTableVariant, - DataTableColumnAlign, - DataTableRef, - DataTableTransaction, - DataTableTransactionResult, - DataTableTransactionWarning, - UndoableDataTableTransactionResult, - UseDataTableDataOptions, - UseDataTableDataReturn, - ColumnDef, - SortingState, - PaginationState, - RowSelectionState, - ColumnResizeMode, - Row, -} from './components/DataTable'; +// DataTable lives at "baukasten-ui/data-table", not here. It is the only +// component that needs @tanstack/react-table, and a re-export from this barrel +// forces every consumer of `extra` — or of the root entry, which re-exports +// this file — to resolve that package whether or not they use the table. +// Rollup resolves re-exported modules regardless of whether their exports are +// used, so the separate entry point is what makes the peer dependency +// genuinely optional. // ─── Navigation ───────────────────────────────────────────────────────────── diff --git a/packages/baukasten/vite.config.ts b/packages/baukasten/vite.config.ts index 41db3a2..54f8952 100644 --- a/packages/baukasten/vite.config.ts +++ b/packages/baukasten/vite.config.ts @@ -43,10 +43,24 @@ export default defineConfig({ index: resolve(__dirname, 'src/index.ts'), core: resolve(__dirname, 'src/core.ts'), extra: resolve(__dirname, 'src/extra.ts'), + /** + * DataTable is the only code that touches @tanstack/react-table, and is + * deliberately NOT re-exported from `extra` or the root barrel: Rollup + * resolves re-exported modules whether or not their exports are used, so + * a single re-export would force every consumer of those barrels to + * install the package. Keeping it to its own entry is what makes the + * peer dependency genuinely optional. + */ + 'data-table': resolve(__dirname, 'src/components/DataTable/index.ts'), }, name: 'Baukasten', formats: ['es', 'cjs'], - fileName: (format, entryName) => `${entryName}.${format === 'es' ? 'mjs' : 'js'}`, + // `.cjs`, not `.js`: package.json sets "type": "module", so Node parses any + // `.js` file in this package as ESM. Naming the CommonJS build `.js` made + // every require() of the package die with "exports is not defined" on its + // first statement. Vite names the shared chunks `.cjs` itself — only these + // entry files go through this callback, which is why the build looked right. + fileName: (format, entryName) => `${entryName}.${format === 'es' ? 'mjs' : 'cjs'}`, cssFileName: 'baukasten-base', }, rollupOptions: { diff --git a/packages/examples/electron/src/renderer/src/components/LogTable.tsx b/packages/examples/electron/src/renderer/src/components/LogTable.tsx index 6f55a9e..9dc5080 100644 --- a/packages/examples/electron/src/renderer/src/components/LogTable.tsx +++ b/packages/examples/electron/src/renderer/src/components/LogTable.tsx @@ -1,5 +1,6 @@ import type { ColumnDef, Row } from '@tanstack/react-table' -import { Badge, DataTable } from 'baukasten-ui' +import { Badge } from 'baukasten-ui' +import { DataTable } from 'baukasten-ui/data-table' import React, { useMemo } from 'react' import { LOG_LEVEL_COLORS, LogEntry } from '../types/log' diff --git a/packages/examples/vscode-db-explorer/package.json b/packages/examples/vscode-db-explorer/package.json index 68626f5..a353a78 100644 --- a/packages/examples/vscode-db-explorer/package.json +++ b/packages/examples/vscode-db-explorer/package.json @@ -40,6 +40,7 @@ "vite": "^6.0.0" }, "dependencies": { + "@tanstack/react-table": "^8.21.3", "baukasten-ui": "*", "react": "^19.0.0", "react-dom": "^19.0.0" diff --git a/packages/examples/vscode-db-explorer/src/webview/App.tsx b/packages/examples/vscode-db-explorer/src/webview/App.tsx index 5f71455..f4d2fd6 100644 --- a/packages/examples/vscode-db-explorer/src/webview/App.tsx +++ b/packages/examples/vscode-db-explorer/src/webview/App.tsx @@ -14,11 +14,11 @@ import { Badge, Tag, Select, - DataTable, StatusBar, StatusBarSection, StatusBarItem, } from 'baukasten-ui'; +import { DataTable } from 'baukasten-ui/data-table'; import './App.css'; // ─── Mock data ─────────────────────────────────────────────────────────────── diff --git a/packages/examples/vscode/package.json b/packages/examples/vscode/package.json index ed8ff53..607fca9 100644 --- a/packages/examples/vscode/package.json +++ b/packages/examples/vscode/package.json @@ -41,6 +41,7 @@ "vite": "^6.0.0" }, "dependencies": { + "@tanstack/react-table": "^8.21.3", "baukasten-ui": "*", "react": "^19.0.0", "react-dom": "^19.0.0" diff --git a/packages/examples/vscode/src/webview/components/LogTable.tsx b/packages/examples/vscode/src/webview/components/LogTable.tsx index 9f3f186..355f5a6 100644 --- a/packages/examples/vscode/src/webview/components/LogTable.tsx +++ b/packages/examples/vscode/src/webview/components/LogTable.tsx @@ -1,5 +1,6 @@ import type { ColumnDef, Row } from '@tanstack/react-table'; -import { Badge, DataTable } from 'baukasten-ui'; +import { Badge } from 'baukasten-ui'; +import { DataTable } from 'baukasten-ui/data-table'; import React, { useMemo } from 'react'; import { LOG_LEVEL_COLORS, LogEntry } from '../types/log'; diff --git a/packages/website/package.json b/packages/website/package.json index 523be00..ad8de7c 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -10,6 +10,7 @@ "lint": "next lint" }, "dependencies": { + "@tanstack/react-table": "^8.21.3", "@types/flexsearch": "^0.7.6", "baukasten-ui": "*", "baukasten-ui-web-wrapper": "*", diff --git a/packages/website/src/app/components/datatable/page.tsx b/packages/website/src/app/components/datatable/page.tsx index 06c610b..f923ec1 100644 --- a/packages/website/src/app/components/datatable/page.tsx +++ b/packages/website/src/app/components/datatable/page.tsx @@ -4,14 +4,14 @@ import { useState, useMemo, useRef } from 'react'; import PageLayout from '@/components/PageLayout'; import { Showcase, PropDefinition } from '@/components/ComponentShowcase'; import { Badge, Button, Heading } from 'baukasten-ui/core'; -import { DataTable, createSelectColumn, useDataTableData } from 'baukasten-ui/extra'; +import { DataTable, createSelectColumn, useDataTableData } from 'baukasten-ui/data-table'; import type { ColumnDef, SortingState, PaginationState, RowSelectionState, DataTableRef, -} from 'baukasten-ui/extra'; +} from 'baukasten-ui/data-table'; const dataTableProps: PropDefinition[] = [ { @@ -661,8 +661,8 @@ export default function DataTablePage() { title="Basic Usage" description="Define columns using TanStack Table's column definition format, then pass your data and columns to the DataTable component." preview={} - code={`import { DataTable } from 'baukasten-ui/extra'; -import type { ColumnDef } from 'baukasten-ui/extra'; + code={`import { DataTable } from 'baukasten-ui/data-table'; +import type { ColumnDef } from 'baukasten-ui/data-table'; interface User { id: number; @@ -738,8 +738,8 @@ function App() { description="Use createSelectColumn() to add a checkbox column for row selection. Track selected rows with rowSelection state." preview={} code={`import { useState, useMemo } from 'react'; -import { DataTable, createSelectColumn } from 'baukasten-ui/extra'; -import type { RowSelectionState } from 'baukasten-ui/extra'; +import { DataTable, createSelectColumn } from 'baukasten-ui/data-table'; +import type { RowSelectionState } from 'baukasten-ui/data-table'; function App() { const [rowSelection, setRowSelection] = useState({}); @@ -797,8 +797,8 @@ function App() { description="Control sorting state externally for integration with external state management or URL parameters." preview={} code={`import { useState } from 'react'; -import { DataTable } from 'baukasten-ui/extra'; -import type { SortingState } from 'baukasten-ui/extra'; +import { DataTable } from 'baukasten-ui/data-table'; +import type { SortingState } from 'baukasten-ui/data-table'; function App() { const [sorting, setSorting] = useState([]); @@ -1137,8 +1137,8 @@ function App() { description="Use initialData instead of data to enable managed mode. The table manages its own state and exposes a transaction API via ref. Use ref.applyTransaction() to add, update, or remove rows." preview={} code={`import { useRef } from 'react'; -import { DataTable } from 'baukasten-ui/extra'; -import type { DataTableRef } from 'baukasten-ui/extra'; +import { DataTable } from 'baukasten-ui/data-table'; +import type { DataTableRef } from 'baukasten-ui/data-table'; function App() { const tableRef = useRef>(null); @@ -1237,7 +1237,7 @@ tableRef.current?.flushAsyncTransactions(); title="External Hook (useDataTableData)" description="Use the useDataTableData hook externally when you need to share transaction state across multiple components, or prefer lifting state out of the table. Pass data as a prop for controlled mode." preview={} - code={`import { DataTable, useDataTableData } from 'baukasten-ui/extra'; + code={`import { DataTable, useDataTableData } from 'baukasten-ui/data-table'; function App() { const { data, applyTransaction, applyTransactionAsync } = useDataTableData({ diff --git a/skills/write-baukasten/SKILL.md b/skills/write-baukasten/SKILL.md index e39e9de..725f356 100644 --- a/skills/write-baukasten/SKILL.md +++ b/skills/write-baukasten/SKILL.md @@ -30,13 +30,16 @@ npm install @tanstack/react-table ```tsx import { Button, Input, Icon } from 'baukasten-ui/core'; // Core primitives -import { Tabs, Menu, DataTable } from 'baukasten-ui/extra'; // Higher-level compositions +import { Tabs, Menu, Tree } from 'baukasten-ui/extra'; // Higher-level compositions +import { DataTable } from 'baukasten-ui/data-table'; // Needs @tanstack/react-table ``` - `baukasten-ui/core` — fundamental primitives (no heavy deps) - `baukasten-ui/extra` — composed components, may depend on core -- `baukasten-ui/styles` — design token utilities and types -- `baukasten-ui` — re-exports everything from core + extra +- `baukasten-ui/data-table` — DataTable and its helpers/types; the only entry needing `@tanstack/react-table` +- `baukasten-ui` — re-exports core + extra (**not** DataTable) + +Design tokens and style utilities come from `baukasten-ui/core`. There is no `baukasten-ui/styles` subpath — it was declared but never built, and has now been removed. ### CSS Files @@ -199,26 +202,27 @@ Full reference: [references/core-components.md](./references/core-components.md) ### Extra (`baukasten-ui/extra`) -Full reference: [references/extra-components.md](./references/extra-components.md) (DataTable lives in [references/datatable.md](./references/datatable.md) due to its size.) - -| Component | Role | -| --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -| `DataTable` | TanStack-Table-backed grid: sorting, pagination, row selection, column resize, global filter. Peer dep: `@tanstack/react-table`. | -| `Tabs` / `TabList` / `Tab` / `TabPanels` / `TabPanel` | Tabbed interface; variants: `line` \| `lifted` \| `pills`. | -| `Breadcrumbs` | Navigation breadcrumb with optional `pill` variant and `maxItems` collapsing. | -| `Pagination` | Page navigation; API is `totalItems` + `pageSize` (NOT totalPages). | -| `Menu` / `MenuItem` / `MenuDivider` / `SubMenu` | Menu primitives for use inside `Dropdown` or `ContextMenu`. | -| `ContextMenu` | Right-click menu wrapper. Portal-aware. | -| `ButtonGroup` | Connected button group + `ButtonGroup.Dropdown` for split buttons (note: uses `content` prop, not children). | -| `Combobox` | Typeahead select with inline input, single/multi (discriminated union), chips, creatable, clearable, grouping, virtualization. | -| `FileUpload` | Drag-and-drop file picker. Variants: `default` \| `primary` \| `dashed`. | -| `Drawer` / `DrawerHeader` / `DrawerBody` / `DrawerFooter` | Slide-in panel from any edge. | -| `Accordion` / `AccordionItem` | Collapsible panels; optional `exclusive` mode. | -| `Tree` | Hierarchical view with expand/collapse, selection, keyboard nav, edge guides. | -| `SplitPane` / `SplitPane.Pane` | Resizable horizontal or vertical split. | -| `StatusBar` / `StatusBarSection` / `StatusBarItem` | VSCode-style bottom bar (variants live on `StatusBarItem`, not `StatusBar`). | -| `Hero` | Top-of-page banner. | -| `Avatar` | User avatar (`circular` \| `square`) with image or initials fallback. | +Full reference: [references/extra-components.md](./references/extra-components.md) + +> `DataTable` is **not** in `extra`. It has its own entry point, `baukasten-ui/data-table`, so that `@tanstack/react-table` stays an optional peer dependency — see [references/datatable.md](./references/datatable.md). + +| Component | Role | +| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| `Tabs` / `TabList` / `Tab` / `TabPanels` / `TabPanel` | Tabbed interface; variants: `line` \| `lifted` \| `pills`. | +| `Breadcrumbs` | Navigation breadcrumb with optional `pill` variant and `maxItems` collapsing. | +| `Pagination` | Page navigation; API is `totalItems` + `pageSize` (NOT totalPages). | +| `Menu` / `MenuItem` / `MenuDivider` / `SubMenu` | Menu primitives for use inside `Dropdown` or `ContextMenu`. | +| `ContextMenu` | Right-click menu wrapper. Portal-aware. | +| `ButtonGroup` | Connected button group + `ButtonGroup.Dropdown` for split buttons (note: uses `content` prop, not children). | +| `Combobox` | Typeahead select with inline input, single/multi (discriminated union), chips, creatable, clearable, grouping, virtualization. | +| `FileUpload` | Drag-and-drop file picker. Variants: `default` \| `primary` \| `dashed`. | +| `Drawer` / `DrawerHeader` / `DrawerBody` / `DrawerFooter` | Slide-in panel from any edge. | +| `Accordion` / `AccordionItem` | Collapsible panels; optional `exclusive` mode. | +| `Tree` | Hierarchical view with expand/collapse, selection, keyboard nav, edge guides. | +| `SplitPane` / `SplitPane.Pane` | Resizable horizontal or vertical split. | +| `StatusBar` / `StatusBarSection` / `StatusBarItem` | VSCode-style bottom bar (variants live on `StatusBarItem`, not `StatusBar`). | +| `Hero` | Top-of-page banner. | +| `Avatar` | User avatar (`circular` \| `square`) with image or initials fallback. | --- diff --git a/skills/write-baukasten/references/datatable.md b/skills/write-baukasten/references/datatable.md index 744c8af..d8061f4 100644 --- a/skills/write-baukasten/references/datatable.md +++ b/skills/write-baukasten/references/datatable.md @@ -1,8 +1,10 @@ # DataTable Reference -`DataTable` is `baukasten-ui/extra`'s most complex component — built on TanStack Table v8 with ~35 props across sorting, pagination, row selection, column resizing, global filtering, and loading/empty states. It lives in its own reference file because of its size. +`DataTable` is the library's most complex component — built on TanStack Table v8 with ~35 props across sorting, pagination, row selection, column resizing, global filtering, and loading/empty states. It lives in its own reference file because of its size. -**Peer dependency:** requires `@tanstack/react-table` (`npm install @tanstack/react-table`). +**Its own entry point:** `baukasten-ui/data-table`. It is deliberately _not_ exported from `baukasten-ui` or `baukasten-ui/extra` — a re-export from either barrel would force every consumer of that barrel to install `@tanstack/react-table`, because Rollup resolves re-exported modules whether or not their exports are used. + +**Optional peer dependency:** requires `@tanstack/react-table` (`npm install @tanstack/react-table`). Nothing else in the library needs it, so consumers who skip DataTable never install it. > **Always use semantic design tokens** (`var(--bk-*)`). See [./design-tokens.md](./design-tokens.md) for the catalog. @@ -10,10 +12,10 @@ ### DataTable -Advanced data table built on TanStack Table v8 with sorting, pagination, row selection, column resizing, global filtering, and loading/empty states. Requires `@tanstack/react-table` as a peer dependency. +Advanced data table built on TanStack Table v8 with sorting, pagination, row selection, column resizing, global filtering, and loading/empty states. Requires `@tanstack/react-table` as an optional peer dependency. ```tsx -import { DataTable, createSelectColumn, useDataTable } from 'baukasten-ui/extra'; +import { DataTable, createSelectColumn, useDataTable } from 'baukasten-ui/data-table'; import type { DataTableProps, DataTableVariant, @@ -24,7 +26,7 @@ import type { RowSelectionState, ColumnResizeMode, Row, -} from 'baukasten-ui/extra'; +} from 'baukasten-ui/data-table'; // DataTable props (generic over row data type TData) interface DataTableProps {