diff --git a/.changeset/loose-grapes-bake.md b/.changeset/loose-grapes-bake.md new file mode 100644 index 00000000..1b302227 --- /dev/null +++ b/.changeset/loose-grapes-bake.md @@ -0,0 +1,5 @@ +--- +'@example/ui-playground': patch +--- + +feat: add separator variant & examples. diff --git a/.changeset/wicked-frogs-live.md b/.changeset/wicked-frogs-live.md new file mode 100644 index 00000000..b763eb75 --- /dev/null +++ b/.changeset/wicked-frogs-live.md @@ -0,0 +1,5 @@ +--- +'@example/ui-playground': patch +--- + +feat: add new tanstack table component examples. diff --git a/.vscode/settings.json b/.vscode/settings.json index 29d9fb3a..6c06dac8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -56,5 +56,6 @@ ], "[sql]": { "editor.defaultFormatter": "adpyke.vscode-sql-formatter" - } + }, + "typescript.experimental.useTsgo": false } diff --git a/examples/ui-playground/package.json b/examples/ui-playground/package.json index bf8c343c..5a889ef5 100644 --- a/examples/ui-playground/package.json +++ b/examples/ui-playground/package.json @@ -3,7 +3,7 @@ "version": "0.1.0-alpha.78", "private": true, "scripts": { - "dev": "NODE_OPTIONS='--inspect' next dev --port 3003 --turbopack", + "dev": "NODE_OPTIONS='--inspect' next dev --port 3004 --turbopack", "build": "next build", "start": "next start", "lint": "eslint .", @@ -20,6 +20,7 @@ "@phosphor-icons/react": "^2.1.8", "@tailwindcss/postcss": "^4.1.7", "@tanstack/react-query": "^5.71.5", + "@tanstack/react-table": "^8.21.3", "@tiptap/extension-color": "^2.26.3", "@tiptap/extension-link": "2.26.3", "@tiptap/extension-text-align": "^2.26.3", diff --git a/examples/ui-playground/src/app/playground/shadcn/page-sidebar.tsx b/examples/ui-playground/src/app/playground/shadcn/page-sidebar.tsx index 59264dde..26c5c825 100644 --- a/examples/ui-playground/src/app/playground/shadcn/page-sidebar.tsx +++ b/examples/ui-playground/src/app/playground/shadcn/page-sidebar.tsx @@ -27,9 +27,11 @@ const navigationItems = [ { href: '#link', label: 'Link' }, { href: '#pagination', label: 'Pagination' }, { href: '#progress', label: 'Progress' }, + { href: '#separator', label: 'Separator' }, { href: '#select', label: 'Select' }, { href: '#slider', label: 'Slider' }, { href: '#switch', label: 'Switch' }, + { href: '#table', label: 'Table' }, { href: '#tabs', label: 'Tabs' }, { href: '#tooltip', label: 'Tooltip' }, { href: '#dropdown-menu', label: 'Dropdown Menu' }, diff --git a/examples/ui-playground/src/app/playground/shadcn/page.tsx b/examples/ui-playground/src/app/playground/shadcn/page.tsx index 86a0c896..b2e6bf54 100644 --- a/examples/ui-playground/src/app/playground/shadcn/page.tsx +++ b/examples/ui-playground/src/app/playground/shadcn/page.tsx @@ -20,8 +20,10 @@ import { PaginationSection } from './pagination-section' import { ProgressSection } from './progress-section' import { RichTextSection } from './rich-text-section' import { SelectSection } from './select-section' +import { SeparatorSection } from './separator-section' import { SliderSection } from './slider-section' import { SwitchSection } from './switch-section' +import { TableSection } from './table-section' import { TabsSection } from './tabs-section' import { TextareaSection } from './textarea-section' import { ToastSection } from './toast-section' @@ -72,7 +74,7 @@ export default function ComboboxPage() { Input OTP - A + Link @@ -93,10 +95,18 @@ export default function ComboboxPage() { Slider + + Separator + + Switch + + Table + + Tabs diff --git a/examples/ui-playground/src/app/playground/shadcn/separator-section.tsx b/examples/ui-playground/src/app/playground/shadcn/separator-section.tsx new file mode 100644 index 00000000..c3515f37 --- /dev/null +++ b/examples/ui-playground/src/app/playground/shadcn/separator-section.tsx @@ -0,0 +1,47 @@ +import React from 'react' + +import { Separator, Typography } from '@genseki/react/v2' + +import { PlaygroundCard } from '~/src/components/card' + +function BasicSeparatorExamples() { + return ( +
+
+ Left content + + Right content +
+
+ Top + + Bottom +
+
+ Left content + + Right content +
+
+ Top + + Bottom +
+
+ ) +} + +export function SeparatorSection() { + return ( +
+ + + Visual dividers for grouping content horizontally or vertically. + +
+ +
+
+
+ ) +} diff --git a/examples/ui-playground/src/app/playground/shadcn/table-section.tsx b/examples/ui-playground/src/app/playground/shadcn/table-section.tsx new file mode 100644 index 00000000..7daa3ec3 --- /dev/null +++ b/examples/ui-playground/src/app/playground/shadcn/table-section.tsx @@ -0,0 +1,241 @@ +import React from 'react' + +import { createColumnHelper, getCoreRowModel, useReactTable } from '@tanstack/react-table' + +import { TanstackTable } from '@genseki/react' +import { Typography } from '@genseki/react/v2' + +import { PlaygroundCard } from '../../../components/card' + +type User = { + id: number + fname: string + lname: string + food: string +} + +const columnHelper = createColumnHelper() + +const columns = [ + columnHelper.accessor('id', { + header: 'ID', + cell: (props) =>

{props.getValue()}

, + }), + columnHelper.accessor('fname', { + header: 'First Name', + cell: (props) =>

{props.getValue()}

, + }), + columnHelper.accessor('lname', { + header: 'Last Name', + cell: (props) =>

{props.getValue()}

, + }), + columnHelper.accessor('food', { + header: 'Favorite Food', + cell: (props) =>

{props.getValue()}

, + }), +] + +function BasicTable() { + const users: User[] = [ + { + id: 1, + fname: 'Supakorn', + lname: 'Netsuwan', + food: 'Hamburger', + }, + { + id: 2, + fname: 'Jane', + lname: 'Doe', + food: 'Pizza', + }, + { + id: 3, + fname: 'John', + lname: 'Smith', + food: 'Sushi', + }, + { + id: 4, + fname: 'Emily', + lname: 'Johnson', + food: 'Tacos', + }, + { + id: 5, + fname: 'Michael', + lname: 'Brown', + food: 'Pasta', + }, + ] + + const table = useReactTable({ + getCoreRowModel: getCoreRowModel(), + data: users, + columns, + }) + + return ( +
+ +
+ ) +} + +function SortableTable() { + const users: User[] = [ + { + id: 1, + fname: 'Supakorn', + lname: 'Netsuwan', + food: 'Hamburger', + }, + { + id: 2, + fname: 'Jane', + lname: 'Doe', + food: 'Pizza', + }, + { + id: 3, + fname: 'John', + lname: 'Smith', + food: 'Sushi', + }, + { + id: 4, + fname: 'Emily', + lname: 'Johnson', + food: 'Tacos', + }, + { + id: 5, + fname: 'Michael', + lname: 'Brown', + food: 'Pasta', + }, + ] + + const table = useReactTable({ + getCoreRowModel: getCoreRowModel(), + data: users, + columns, + }) + + return ( +
+ +
+ ) +} + +function LoadingTable() { + const users: User[] = [] + + const table = useReactTable({ + getCoreRowModel: getCoreRowModel(), + data: users, + columns, + }) + + return ( +
+ +
+ ) +} + +function EmptyTable() { + const users: User[] = [] + + const table = useReactTable({ + getCoreRowModel: getCoreRowModel(), + data: users, + columns, + }) + + return ( +
+ +
+ ) +} + +function ErrorTable() { + const users: User[] = [] + + const table = useReactTable({ + getCoreRowModel: getCoreRowModel(), + data: users, + columns, + }) + + return ( +
+ +
+ ) +} + +export const TableSection = React.memo(function () { + return ( +
+ + + A simple table with basic data display functionality. + + +
+ +
+
+ + + + Table with sortable columns. Click on column headers to sort. + +
+ +
+
+ + + + Table displaying a loading state while data is being fetched. + +
+ +
+
+ + + + Table displaying an empty state when no data is available. + +
+ +
+
+ + + + Table displaying an error state when data fetching fails. + +
+ +
+
+
+ ) +}) + +TableSection.displayName = 'TableSection' diff --git a/packages/react/src/react/components/primitives/tanstack-table.tsx b/packages/react/src/react/components/primitives/tanstack-table.tsx index a7ca1e7f..b2f8c2ff 100644 --- a/packages/react/src/react/components/primitives/tanstack-table.tsx +++ b/packages/react/src/react/components/primitives/tanstack-table.tsx @@ -14,6 +14,7 @@ import { import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from './table' +import { Typography } from '../../../../v2' import { cn } from '../../utils/cn' type RowClickHandler = (row: Row, e: React.MouseEvent) => void @@ -133,15 +134,22 @@ export function TanstackTable({ role={canSort ? 'button' : undefined} tabIndex={canSort ? 0 : -1} > - 1 && 'justify-center' )} > - {children} + + {children} + {canSort && children && getSortIcon(header.column.getIsSorted())} - + ) })} @@ -230,14 +238,12 @@ export const TableEmpty = (props: { {props.emptyFallback ?? ( -
+
-

- {props.emptyMessage ?? 'No data'} -

+ {props.emptyMessage ?? 'No data'}
)} diff --git a/packages/react/v2/components/primitives/separator.tsx b/packages/react/v2/components/primitives/separator.tsx index 1d9ec5a7..4a6237cf 100644 --- a/packages/react/v2/components/primitives/separator.tsx +++ b/packages/react/v2/components/primitives/separator.tsx @@ -2,28 +2,44 @@ import React from 'react' import * as SeparatorPrimitive from '@radix-ui/react-separator' - -import { cn } from '../../../src/react/utils/cn' +import { cva, type VariantProps } from 'class-variance-authority' /** * Shadcn component */ +const separator = cva('shrink-0', { + variants: { + variant: { + solid: + 'bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px', + dashed: `bg-size-[12px_12px] bg-repeat + data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=horizontal]:bg-[linear-gradient(to_right,var(--color-border-primary)_50%,transparent_50%)] + data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px data-[orientation=vertical]:bg-[linear-gradient(to_bottom,var(--color-border-primary)_50%,transparent_50%)] + `, + }, + }, + defaultVariants: { + variant: 'solid', + }, +}) + +type SeparatorProps = React.ComponentProps & + VariantProps + function Separator({ className, orientation = 'horizontal', + variant, decorative = true, ...props -}: React.ComponentProps) { +}: SeparatorProps) { return ( ) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a1434d2..48f99003 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -171,6 +171,9 @@ importers: '@tanstack/react-query': specifier: ^5.71.5 version: 5.76.1(react@19.1.0) + '@tanstack/react-table': + specifier: ^8.21.3 + version: 8.21.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@tiptap/extension-color': specifier: ^2.26.3 version: 2.26.3(@tiptap/core@2.26.3(@tiptap/pm@2.26.3))(@tiptap/extension-text-style@2.26.3(@tiptap/core@2.26.3(@tiptap/pm@2.26.3)))