From dcee552d8bc7b6f9bff49d7b04a864b3be385146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malcolm=20Nihl=C3=A9n?= Date: Sat, 28 Jun 2025 11:26:50 +0200 Subject: [PATCH 1/9] feat: first take on table component --- packages/ui-react/package.json | 1 + .../src/components/card/card.stories.tsx | 13 ++ .../ui-react/src/components/card/card.tsx | 41 ++++ .../src/components/table/table.stories.tsx | 9 + .../ui-react/src/components/table/table.tsx | 199 ++++++++++++++++++ pnpm-lock.yaml | 22 ++ 6 files changed, 285 insertions(+) create mode 100644 packages/ui-react/src/components/card/card.stories.tsx create mode 100644 packages/ui-react/src/components/card/card.tsx create mode 100644 packages/ui-react/src/components/table/table.stories.tsx create mode 100644 packages/ui-react/src/components/table/table.tsx diff --git a/packages/ui-react/package.json b/packages/ui-react/package.json index cf0d071..dde31cc 100644 --- a/packages/ui-react/package.json +++ b/packages/ui-react/package.json @@ -32,6 +32,7 @@ "dependencies": { "@base-ui-components/react": "1.0.0-beta.0", "@tailwindcss/vite": "^4.1.7", + "@tanstack/react-table": "^8.21.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.511.0", diff --git a/packages/ui-react/src/components/card/card.stories.tsx b/packages/ui-react/src/components/card/card.stories.tsx new file mode 100644 index 0000000..5962560 --- /dev/null +++ b/packages/ui-react/src/components/card/card.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, Preview } from "@storybook/react"; +import { Card } from "./card.js"; + +export default { + title: "Components/Card", + component: Card, +} satisfies Meta; + +export const Simple = { + args: { + children: "Card Content", + }, +} satisfies Preview; diff --git a/packages/ui-react/src/components/card/card.tsx b/packages/ui-react/src/components/card/card.tsx new file mode 100644 index 0000000..3596053 --- /dev/null +++ b/packages/ui-react/src/components/card/card.tsx @@ -0,0 +1,41 @@ +import { mergeProps, useRender } from "@base-ui-components/react"; +import { cva, type VariantProps } from "class-variance-authority"; +import { cn } from "../../lib/utils.js"; + +const cardVariants = cva( + ` + p-4 + border + rounded-lg + text-gray-dark + `, + { + variants: { + variant: { + light: "bg-gray-100 border-gray-300", + medium: "bg-gray-200 border-gray-300", + }, + }, + defaultVariants: { + variant: "light", + }, + }, +); + +export type Props = useRender.ComponentProps<"div"> & + VariantProps; + +function Card(props: Props) { + const { render =
, className, variant, ...otherProps } = props; + + const defaultProps: useRender.ElementProps<"div"> = { + className: cn(cardVariants({ variant }), className), + }; + + return useRender({ + render, + props: mergeProps(defaultProps, otherProps), + }); +} + +export { Card }; diff --git a/packages/ui-react/src/components/table/table.stories.tsx b/packages/ui-react/src/components/table/table.stories.tsx new file mode 100644 index 0000000..b30a285 --- /dev/null +++ b/packages/ui-react/src/components/table/table.stories.tsx @@ -0,0 +1,9 @@ +import type { Meta, Preview } from "@storybook/react"; +import { TableTest } from "./table.js"; + +export default { + title: "Components/Table", + component: TableTest, +} satisfies Meta; + +export const Simple = {} satisfies Preview; diff --git a/packages/ui-react/src/components/table/table.tsx b/packages/ui-react/src/components/table/table.tsx new file mode 100644 index 0000000..b9a8f35 --- /dev/null +++ b/packages/ui-react/src/components/table/table.tsx @@ -0,0 +1,199 @@ +import { + createColumnHelper, + flexRender, + getCoreRowModel, + type Table as TanstackTable, + useReactTable, +} from "@tanstack/react-table"; +import { type ComponentProps, memo, useMemo, useState } from "react"; +import { cn } from "../../lib/utils.js"; +import { Card } from "../card/card.js"; + +type Attendee = { + firstName: string; + lastName: string; + role: "scout" | "leader" | "volunteer"; +}; + +const defaultData: Attendee[] = [ + { firstName: "Alice", lastName: "Smith", role: "scout" }, + { firstName: "Bob", lastName: "Johnson", role: "leader" }, + { firstName: "Charlie", lastName: "Brown", role: "volunteer" }, +]; + +const columnHelper = createColumnHelper(); + +const columns = [ + columnHelper.accessor("firstName", { + header: () => "Förnamn", + }), + columnHelper.accessor("lastName", { + header: () => "Efternamn", + }), + columnHelper.accessor("role", { + header: () => "Roll", + cell: (info) => { + const role = info.getValue(); + return role.charAt(0).toUpperCase() + role.slice(1); + }, + }), +]; + +function TableTest() { + const [data, _setData] = useState(() => [...defaultData]); + + const table = useReactTable({ + data, + columns, + columnResizeMode: "onChange", + getCoreRowModel: getCoreRowModel(), + }); + + return ; +} + +export type Props = ComponentProps<"table"> & { + table: TanstackTable; +}; + +function Table(props: Props) { + const { table, className, ...otherProps } = props; + + /** + * Instead of calling `column.getSize()` on every render for every header + * and especially every data cell (very expensive), + * we will calculate all column sizes at once at the root table level in a useMemo + * and pass the column sizes down as CSS variables to the
element. + */ + // biome-ignore lint/correctness/useExhaustiveDependencies: This is carefully optimized to avoid unnecessary recalculations + const columnSizeVars = useMemo(() => { + const headers = table.getFlatHeaders(); + const colSizes: { [key: string]: number } = {}; + for (const header of headers) { + colSizes[`--header-${header.id}-size`] = header.getSize(); + colSizes[`--col-${header.column.id}-size`] = header.column.getSize(); + } + return colSizes; + }, [table.getState().columnSizingInfo, table.getState().columnSizing]); + + return ( + <> +
+        {JSON.stringify(
+          {
+            columnSizing: table.getState().columnSizing,
+          },
+          null,
+          2,
+        )}
+      
+ + +
+ + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + ))} + + ))} + + {table.getState().columnSizingInfo.isResizingColumn ? ( + + ) : ( + + )} + + {table.getFooterGroups().map((footerGroup) => ( + + {footerGroup.headers.map((header) => ( + + ))} + + ))} + +
+ {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext(), + )} + + {header.column.getCanResize() && ( +
header.column.resetSize()} + onMouseDown={header.getResizeHandler()} + onTouchStart={header.getResizeHandler()} + className={cn( + "absolute flex justify-center items-center py-2 top-0 right-0 h-full w-2 cursor-col-resize touch-none select-none", + "after:w-0.5 after:h-full after:bg-gray-300", + header.column.getIsResizing() && + "bg-blue-100 after:invisible", + )} + style={{ + transform: + table.options.columnResizeMode === "onEnd" && + header.column.getIsResizing() + ? `translateX(${table.getState().columnSizingInfo.deltaOffset}px)` + : "", + }} + >
+ )} +
+ {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.footer, + header.getContext(), + )} +
+ + + ); +} + +function TableBody({ table }: { table: TanstackTable }) { + return ( + + {table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + ))} + + ); +} + +//special memoized wrapper for our table body that we will use during column resizing +export const MemoizedTableBody = memo( + TableBody, + (prev, next) => prev.table.options.data === next.table.options.data, +) as typeof TableBody; + +export { TableTest, Table }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 58e71e1..bc36464 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: '@tailwindcss/vite': specifier: ^4.1.7 version: 4.1.7(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)) + '@tanstack/react-table': + specifier: ^8.21.3 + version: 8.21.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -931,6 +934,17 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 + '@tanstack/react-table@8.21.3': + resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} + engines: {node: '>=12'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + + '@tanstack/table-core@8.21.3': + resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} + engines: {node: '>=12'} + '@testing-library/dom@10.4.0': resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} engines: {node: '>=18'} @@ -2962,6 +2976,14 @@ snapshots: tailwindcss: 4.1.7 vite: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1) + '@tanstack/react-table@8.21.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@tanstack/table-core': 8.21.3 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + '@tanstack/table-core@8.21.3': {} + '@testing-library/dom@10.4.0': dependencies: '@babel/code-frame': 7.27.1 From 864976e3d60a617533ea5e92c8158aeeff605495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malcolm=20Nihl=C3=A9n?= Date: Sun, 29 Jun 2025 18:42:49 +0200 Subject: [PATCH 2/9] feat: add column header buttons --- .../ui-react/src/components/button/button.tsx | 35 ++++++++++++++----- .../ui-react/src/components/table/table.tsx | 29 +++++++++++---- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/packages/ui-react/src/components/button/button.tsx b/packages/ui-react/src/components/button/button.tsx index a8623d7..81f175c 100644 --- a/packages/ui-react/src/components/button/button.tsx +++ b/packages/ui-react/src/components/button/button.tsx @@ -14,6 +14,16 @@ const buttonVariants = cva( { variants: { color: { + gray: ` + [--btn-text:var(--color-gray-800)] + [--btn-border:var(--color-gray-400)] + [--btn-bg:var(--color-gray-200)] + [--btn-bg-hover:var(--color-gray-4300)] + [--btn-bg-active:var(--color-gray-400)] + + [--btn-bg-text-hover:var(--color-gray-200)] + [--btn-bg-text-active:var(--color-gray-300)] + `, blue: ` [--btn-text:var(--color-white)] [--btn-border:var(--color-blue)] @@ -21,7 +31,6 @@ const buttonVariants = cva( [--btn-bg-hover:var(--color-blue-hover)] [--btn-bg-active:var(--color-blue-active)] - [--btn-text-border:var(--color-blue-600)] [--btn-bg-text-hover:var(--color-bluegray-100)] [--btn-bg-text-active:var(--color-bluegray-200)] `, @@ -32,7 +41,6 @@ const buttonVariants = cva( [--btn-bg-hover:var(--color-orange-hover)] [--btn-bg-active:var(--color-orange-active)] - [--btn-text-border:var(--color-orange)] [--btn-bg-text-hover:var(--color-orange-100)] [--btn-bg-text-active:var(--color-orange-200)] `, @@ -43,7 +51,6 @@ const buttonVariants = cva( [--btn-bg-hover:var(--color-red-hover)] [--btn-bg-active:var(--color-red-active)] - [--btn-text-border:var(--color-red)] [--btn-bg-text-hover:var(--color-red-100)] [--btn-bg-text-active:var(--color-red-200)] `, @@ -54,7 +61,6 @@ const buttonVariants = cva( [--btn-bg-hover:var(--color-trackergreen-hover)] [--btn-bg-active:var(--color-trackergreen-active)] - [--btn-text-border:var(--color-trackergreen)] [--btn-bg-text-hover:var(--color-trackergreen-100)] [--btn-bg-text-active:var(--color-trackergreen-200)] `, @@ -65,7 +71,6 @@ const buttonVariants = cva( [--btn-bg-hover:var(--color-discovererblue-hover)] [--btn-bg-active:var(--color-discovererblue-active)] - [--btn-text-border:var(--color-discovererblue)] [--btn-bg-text-hover:var(--color-discovererblue-100)] [--btn-bg-text-active:var(--color-discovererblue-200)] `, @@ -76,7 +81,6 @@ const buttonVariants = cva( [--btn-bg-hover:var(--color-adventurerorange-hover)] [--btn-bg-active:var(--color-adventurerorange-active)] - [--btn-text-border:var(--color-adventurerorange)] [--btn-bg-text-hover:var(--color-adventurerorange-100)] [--btn-bg-text-active:var(--color-adventurerorange-200)] `, @@ -87,7 +91,6 @@ const buttonVariants = cva( [--btn-bg-hover:var(--color-challengerpink-hover)] [--btn-bg-active:var(--color-challengerpink-active)] - [--btn-text-border:var(--color-challengerpink)] [--btn-bg-text-hover:var(--color-challengerpink-100)] [--btn-bg-text-active:var(--color-challengerpink-200)] `, @@ -98,7 +101,6 @@ const buttonVariants = cva( [--btn-bg-hover:var(--color-roveryellow-hover)] [--btn-bg-active:var(--color-roveryellow-active)] - [--btn-text-border:var(--color-roveryellow)] [--btn-bg-text-hover:var(--color-roveryellow-100)] [--btn-bg-text-active:var(--color-roveryellow-200)] `, @@ -129,6 +131,7 @@ const buttonVariants = cva( size: { medium: "text-base px-4 h-10 rounded-lg", small: "text-sm px-3 h-8 rounded-md", + "tiny-icon": "text-sm p-1 size-6 rounded-md", }, }, defaultVariants: { @@ -136,6 +139,22 @@ const buttonVariants = cva( variant: "contained", size: "medium", }, + compoundVariants: [ + { + color: "gray", + variant: "text", + class: ` + text-(--btn-text) + `, + }, + { + color: "gray", + variant: "outlined", + class: ` + text-(--btn-text) + `, + }, + ], }, ); diff --git a/packages/ui-react/src/components/table/table.tsx b/packages/ui-react/src/components/table/table.tsx index b9a8f35..06ce7c4 100644 --- a/packages/ui-react/src/components/table/table.tsx +++ b/packages/ui-react/src/components/table/table.tsx @@ -2,11 +2,14 @@ import { createColumnHelper, flexRender, getCoreRowModel, + getFilteredRowModel, type Table as TanstackTable, useReactTable, } from "@tanstack/react-table"; +import { EllipsisVerticalIcon, ListFilterIcon } from "lucide-react"; import { type ComponentProps, memo, useMemo, useState } from "react"; import { cn } from "../../lib/utils.js"; +import { Button } from "../button/button.js"; import { Card } from "../card/card.js"; type Attendee = { @@ -47,6 +50,7 @@ function TableTest() { columns, columnResizeMode: "onChange", getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), }); return ; @@ -110,12 +114,23 @@ function Table(props: Props) { width: `calc(var(--header-${header?.id}-size) * 1px)`, }} > - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef.header, - header.getContext(), - )} +
+ {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext(), + )} + +
+ + +
+
{header.column.getCanResize() && (
prev.table.options.data === next.table.options.data, ) as typeof TableBody; -export { TableTest, Table }; +export { Table, TableTest }; From 0f92bb207dcd45489ccfcf5d0327db713412447f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malcolm=20Nihl=C3=A9n?= Date: Sun, 6 Jul 2025 13:34:36 +0200 Subject: [PATCH 3/9] fix: full width when no resize --- packages/ui-react/src/components/table/table.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/ui-react/src/components/table/table.tsx b/packages/ui-react/src/components/table/table.tsx index 06ce7c4..dcc401e 100644 --- a/packages/ui-react/src/components/table/table.tsx +++ b/packages/ui-react/src/components/table/table.tsx @@ -82,10 +82,11 @@ function Table(props: Props) { return ( <> -
+      
         {JSON.stringify(
           {
-            columnSizing: table.getState().columnSizing,
+            // columnSizing: table.getState().columnSizing,
+            // columnSizeVars,
           },
           null,
           2,
@@ -93,14 +94,17 @@ function Table(props: Props) {
       
From d4d773713db468bed67b3b4fed33f4f45c5a22cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malcolm=20Nihl=C3=A9n?= Date: Sun, 6 Jul 2025 21:17:40 +0200 Subject: [PATCH 4/9] feat: add menu component --- packages/ui-react/package.json | 24 +- .../ui-react/src/components/menu/Docs.mdx | 14 + .../src/components/menu/menu.stories.tsx | 59 ++ .../ui-react/src/components/menu/menu.tsx | 181 +++++++ pnpm-lock.yaml | 506 ++++++++++-------- 5 files changed, 543 insertions(+), 241 deletions(-) create mode 100644 packages/ui-react/src/components/menu/Docs.mdx create mode 100644 packages/ui-react/src/components/menu/menu.stories.tsx create mode 100644 packages/ui-react/src/components/menu/menu.tsx diff --git a/packages/ui-react/package.json b/packages/ui-react/package.json index dde31cc..bf208c9 100644 --- a/packages/ui-react/package.json +++ b/packages/ui-react/package.json @@ -30,16 +30,16 @@ "author": "", "license": "MIT", "dependencies": { - "@base-ui-components/react": "1.0.0-beta.0", - "@tailwindcss/vite": "^4.1.7", + "@base-ui-components/react": "1.0.0-beta.1", + "@tailwindcss/vite": "^4.1.11", "@tanstack/react-table": "^8.21.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^0.511.0", + "lucide-react": "^0.525.0", "react": "^19.1.0", - "sonner": "^2.0.3", - "tailwind-merge": "^3.3.0", - "tailwindcss": "^4.1.7" + "sonner": "^2.0.6", + "tailwind-merge": "^3.3.1", + "tailwindcss": "^4.1.11" }, "devDependencies": { "@storybook/addon-a11y": "^8.6.14", @@ -50,16 +50,16 @@ "@storybook/react": "8.6.14", "@storybook/react-vite": "8.6.14", "@storybook/test": "8.6.14", - "@tailwindcss/cli": "^4.1.7", - "@types/react": "^19.1.4", - "@vitest/browser": "^3.1.3", - "@vitest/coverage-v8": "^3.1.3", + "@tailwindcss/cli": "^4.1.11", + "@types/react": "^19.1.8", + "@vitest/browser": "^3.2.4", + "@vitest/coverage-v8": "^3.2.4", "copyfiles": "^2.4.1", - "playwright": "^1.52.0", + "playwright": "^1.53.2", "prop-types": "15.8.1", "storybook": "8.6.14", "typescript": "^5.8.3", "vite": "^6.3.5", - "vitest": "^3.1.3" + "vitest": "^3.2.4" } } \ No newline at end of file diff --git a/packages/ui-react/src/components/menu/Docs.mdx b/packages/ui-react/src/components/menu/Docs.mdx new file mode 100644 index 0000000..cb1b05a --- /dev/null +++ b/packages/ui-react/src/components/menu/Docs.mdx @@ -0,0 +1,14 @@ +import { Meta, Primary, Controls } from '@storybook/addon-docs'; +import stories from './menu.stories' + + + +# Menu + +The Menu component is used to display a list of options when a button or other +trigger element is clicked. It extends the [Base UI Menu +component](https://base-ui.com/react/components/menu). + + + + diff --git a/packages/ui-react/src/components/menu/menu.stories.tsx b/packages/ui-react/src/components/menu/menu.stories.tsx new file mode 100644 index 0000000..cf79dfa --- /dev/null +++ b/packages/ui-react/src/components/menu/menu.stories.tsx @@ -0,0 +1,59 @@ +import type { Meta, Preview } from "@storybook/react"; +import { Button } from "../button/button.js"; +import * as Menu from "./menu.js"; + +export default { + title: "Components/Menu", + component: Menu.Root, + argTypes: { + children: { + control: false, + }, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export const Simple = { + args: { + children: ( + <> + Open Menu} /> + + Option 1 + Option 2 + + Option 3 + + + ), + }, +} satisfies Preview; + +export const Nested = { + args: { + children: ( + <> + Open Menu} /> + + Option 1 + Option 2 + + + + Submenu} /> + + Option 1 + Option 2 + + + + + ), + }, +} satisfies Preview; diff --git a/packages/ui-react/src/components/menu/menu.tsx b/packages/ui-react/src/components/menu/menu.tsx new file mode 100644 index 0000000..22b45ac --- /dev/null +++ b/packages/ui-react/src/components/menu/menu.tsx @@ -0,0 +1,181 @@ +import { Menu as MenuPrimitive } from "@base-ui-components/react/menu"; +import { ChevronRightIcon, ChevronsRightIcon } from "lucide-react"; +import { createContext, useContext } from "react"; +import { cn } from "../../lib/utils.js"; + +const Root = MenuPrimitive.Root; +const Trigger = MenuPrimitive.Trigger; +const Group = MenuPrimitive.Group; +const SubmenuRoot = MenuPrimitive.SubmenuRoot; +const SubmenuTrigger = MenuPrimitive.SubmenuTrigger; + +function ArrowSvg(props: React.ComponentProps<"svg">) { + return ( + // biome-ignore lint/a11y/noSvgWithoutTitle: This is only for display + + {/* Border */} + + + {/* Background */} + + + {/* Border with same background color to create rounded edges */} + + + ); +} + +function Arrow() { + return ( + + + + ); +} + +const SubmenuContext = createContext<{ + isNested: boolean; +}>({ + isNested: false, +}); + +const Positioner = ({ + className, + children, + ...props +}: MenuPrimitive.Positioner.Props) => { + const submenuContext = useContext(SubmenuContext); + + return ( + + + + + + {children} + + + + + ); +}; + +const GroupLabel = ({ + className, + ...props +}: MenuPrimitive.GroupLabel.Props) => ( + +); + +const Item = ({ className, children, ...props }: MenuPrimitive.Item.Props) => ( + + {children} + + + +); + +const Separator = ({ className, ...props }: MenuPrimitive.Separator.Props) => ( + +); + +export { + Group, + GroupLabel, + Item, + Root, + Trigger, + SubmenuRoot, + SubmenuTrigger, + Positioner, + Separator, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bc36464..55e1360 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,11 +18,11 @@ importers: packages/ui-react: dependencies: '@base-ui-components/react': - specifier: 1.0.0-beta.0 - version: 1.0.0-beta.0(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: 1.0.0-beta.1 + version: 1.0.0-beta.1(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@tailwindcss/vite': - specifier: ^4.1.7 - version: 4.1.7(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)) + specifier: ^4.1.11 + version: 4.1.11(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)) '@tanstack/react-table': specifier: ^8.21.3 version: 8.21.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -33,36 +33,36 @@ importers: specifier: ^2.1.1 version: 2.1.1 lucide-react: - specifier: ^0.511.0 - version: 0.511.0(react@19.1.0) + specifier: ^0.525.0 + version: 0.525.0(react@19.1.0) react: specifier: ^19.1.0 version: 19.1.0 sonner: - specifier: ^2.0.3 - version: 2.0.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^2.0.6 + version: 2.0.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) tailwind-merge: - specifier: ^3.3.0 - version: 3.3.0 + specifier: ^3.3.1 + version: 3.3.1 tailwindcss: - specifier: ^4.1.7 - version: 4.1.7 + specifier: ^4.1.11 + version: 4.1.11 devDependencies: '@storybook/addon-a11y': specifier: ^8.6.14 version: 8.6.14(storybook@8.6.14) '@storybook/addon-docs': specifier: 8.6.14 - version: 8.6.14(@types/react@19.1.4)(storybook@8.6.14) + version: 8.6.14(@types/react@19.1.8)(storybook@8.6.14) '@storybook/addon-essentials': specifier: 8.6.14 - version: 8.6.14(@types/react@19.1.4)(storybook@8.6.14) + version: 8.6.14(@types/react@19.1.8)(storybook@8.6.14) '@storybook/blocks': specifier: 8.6.14 version: 8.6.14(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@8.6.14) '@storybook/experimental-addon-test': specifier: 8.6.14 - version: 8.6.14(@vitest/browser@3.1.3)(@vitest/runner@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@8.6.14)(vitest@3.1.3) + version: 8.6.14(@vitest/browser@3.2.4)(@vitest/runner@3.2.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@8.6.14)(vitest@3.2.4) '@storybook/react': specifier: 8.6.14 version: 8.6.14(@storybook/test@8.6.14(storybook@8.6.14))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@8.6.14)(typescript@5.8.3) @@ -73,23 +73,23 @@ importers: specifier: 8.6.14 version: 8.6.14(storybook@8.6.14) '@tailwindcss/cli': - specifier: ^4.1.7 - version: 4.1.7 + specifier: ^4.1.11 + version: 4.1.11 '@types/react': - specifier: ^19.1.4 - version: 19.1.4 + specifier: ^19.1.8 + version: 19.1.8 '@vitest/browser': - specifier: ^3.1.3 - version: 3.1.3(playwright@1.52.0)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))(vitest@3.1.3) + specifier: ^3.2.4 + version: 3.2.4(playwright@1.53.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))(vitest@3.2.4) '@vitest/coverage-v8': - specifier: ^3.1.3 - version: 3.1.3(@vitest/browser@3.1.3)(vitest@3.1.3) + specifier: ^3.2.4 + version: 3.2.4(@vitest/browser@3.2.4)(vitest@3.2.4) copyfiles: specifier: ^2.4.1 version: 2.4.1 playwright: - specifier: ^1.52.0 - version: 1.52.0 + specifier: ^1.53.2 + version: 1.53.2 prop-types: specifier: 15.8.1 version: 15.8.1 @@ -103,8 +103,8 @@ importers: specifier: ^6.3.5 version: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1) vitest: - specifier: ^3.1.3 - version: 3.1.3(@vitest/browser@3.1.3)(jiti@2.4.2)(lightningcss@1.30.1) + specifier: ^3.2.4 + version: 3.2.4(@vitest/browser@3.2.4)(jiti@2.4.2)(lightningcss@1.30.1) packages: @@ -170,6 +170,10 @@ packages: resolution: {integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.27.6': + resolution: {integrity: sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==} + engines: {node: '>=6.9.0'} + '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} @@ -182,8 +186,8 @@ packages: resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==} engines: {node: '>=6.9.0'} - '@base-ui-components/react@1.0.0-beta.0': - resolution: {integrity: sha512-lPw5/40g/TbpSG1e1g4drl10kaSY2VBOFFQ9axmGhwPGqrQmTuW42jcUq/7OPdXQAyMakfWMWLSXyk3NXbRk+Q==} + '@base-ui-components/react@1.0.0-beta.1': + resolution: {integrity: sha512-7zmGiz4/+HKnv99lWftItoSMqnj2PdSvt2krh0/GP+Rj0xK0NMnFI/gIVvP7CB2G+k0JPUrRWXjXa3y08oiakg==} engines: {node: '>=14.0.0'} peerDependencies: '@types/react': ^17 || ^18 || ^19 @@ -412,12 +416,6 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - '@floating-ui/react@0.27.12': - resolution: {integrity: sha512-kKlWNrpIQxF1B/a2MZvE0/uyKby4960yjO91W7nVyNKmmfNi62xU9HCjL1M1eWzx/LFj/VPSwJVbwQk9Pq/68A==} - peerDependencies: - react: '>=17.0.0' - react-dom: '>=17.0.0' - '@floating-ui/utils@0.2.9': resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} @@ -840,69 +838,69 @@ packages: peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@tailwindcss/cli@4.1.7': - resolution: {integrity: sha512-hJNjpov/UiJc9ZWH4j/eEQxqklADrD/71s+t8Y0wbyQVAwtLkSp+MeC/sHTb03X+28rfbe0fRXkiBsf73/IwPg==} + '@tailwindcss/cli@4.1.11': + resolution: {integrity: sha512-7RAFOrVaXCFz5ooEG36Kbh+sMJiI2j4+Ozp71smgjnLfBRu7DTfoq8DsTvzse2/6nDeo2M3vS/FGaxfDgr3rtQ==} hasBin: true - '@tailwindcss/node@4.1.7': - resolution: {integrity: sha512-9rsOpdY9idRI2NH6CL4wORFY0+Q6fnx9XP9Ju+iq/0wJwGD5IByIgFmwVbyy4ymuyprj8Qh4ErxMKTUL4uNh3g==} + '@tailwindcss/node@4.1.11': + resolution: {integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==} - '@tailwindcss/oxide-android-arm64@4.1.7': - resolution: {integrity: sha512-IWA410JZ8fF7kACus6BrUwY2Z1t1hm0+ZWNEzykKmMNM09wQooOcN/VXr0p/WJdtHZ90PvJf2AIBS/Ceqx1emg==} + '@tailwindcss/oxide-android-arm64@4.1.11': + resolution: {integrity: sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.1.7': - resolution: {integrity: sha512-81jUw9To7fimGGkuJ2W5h3/oGonTOZKZ8C2ghm/TTxbwvfSiFSDPd6/A/KE2N7Jp4mv3Ps9OFqg2fEKgZFfsvg==} + '@tailwindcss/oxide-darwin-arm64@4.1.11': + resolution: {integrity: sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.1.7': - resolution: {integrity: sha512-q77rWjEyGHV4PdDBtrzO0tgBBPlQWKY7wZK0cUok/HaGgbNKecegNxCGikuPJn5wFAlIywC3v+WMBt0PEBtwGw==} + '@tailwindcss/oxide-darwin-x64@4.1.11': + resolution: {integrity: sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.1.7': - resolution: {integrity: sha512-RfmdbbK6G6ptgF4qqbzoxmH+PKfP4KSVs7SRlTwcbRgBwezJkAO3Qta/7gDy10Q2DcUVkKxFLXUQO6J3CRvBGw==} + '@tailwindcss/oxide-freebsd-x64@4.1.11': + resolution: {integrity: sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.7': - resolution: {integrity: sha512-OZqsGvpwOa13lVd1z6JVwQXadEobmesxQ4AxhrwRiPuE04quvZHWn/LnihMg7/XkN+dTioXp/VMu/p6A5eZP3g==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11': + resolution: {integrity: sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.1.7': - resolution: {integrity: sha512-voMvBTnJSfKecJxGkoeAyW/2XRToLZ227LxswLAwKY7YslG/Xkw9/tJNH+3IVh5bdYzYE7DfiaPbRkSHFxY1xA==} + '@tailwindcss/oxide-linux-arm64-gnu@4.1.11': + resolution: {integrity: sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-arm64-musl@4.1.7': - resolution: {integrity: sha512-PjGuNNmJeKHnP58M7XyjJyla8LPo+RmwHQpBI+W/OxqrwojyuCQ+GUtygu7jUqTEexejZHr/z3nBc/gTiXBj4A==} + '@tailwindcss/oxide-linux-arm64-musl@4.1.11': + resolution: {integrity: sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-x64-gnu@4.1.7': - resolution: {integrity: sha512-HMs+Va+ZR3gC3mLZE00gXxtBo3JoSQxtu9lobbZd+DmfkIxR54NO7Z+UQNPsa0P/ITn1TevtFxXTpsRU7qEvWg==} + '@tailwindcss/oxide-linux-x64-gnu@4.1.11': + resolution: {integrity: sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-linux-x64-musl@4.1.7': - resolution: {integrity: sha512-MHZ6jyNlutdHH8rd+YTdr3QbXrHXqwIhHw9e7yXEBcQdluGwhpQY2Eku8UZK6ReLaWtQ4gijIv5QoM5eE+qlsA==} + '@tailwindcss/oxide-linux-x64-musl@4.1.11': + resolution: {integrity: sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-wasm32-wasi@4.1.7': - resolution: {integrity: sha512-ANaSKt74ZRzE2TvJmUcbFQ8zS201cIPxUDm5qez5rLEwWkie2SkGtA4P+GPTj+u8N6JbPrC8MtY8RmJA35Oo+A==} + '@tailwindcss/oxide-wasm32-wasi@4.1.11': + resolution: {integrity: sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -913,26 +911,26 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.1.7': - resolution: {integrity: sha512-HUiSiXQ9gLJBAPCMVRk2RT1ZrBjto7WvqsPBwUrNK2BcdSxMnk19h4pjZjI7zgPhDxlAbJSumTC4ljeA9y0tEw==} + '@tailwindcss/oxide-win32-arm64-msvc@4.1.11': + resolution: {integrity: sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.1.7': - resolution: {integrity: sha512-rYHGmvoHiLJ8hWucSfSOEmdCBIGZIq7SpkPRSqLsH2Ab2YUNgKeAPT1Fi2cx3+hnYOrAb0jp9cRyode3bBW4mQ==} + '@tailwindcss/oxide-win32-x64-msvc@4.1.11': + resolution: {integrity: sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.1.7': - resolution: {integrity: sha512-5SF95Ctm9DFiUyjUPnDGkoKItPX/k+xifcQhcqX5RA85m50jw1pT/KzjdvlqxRja45Y52nR4MR9fD1JYd7f8NQ==} + '@tailwindcss/oxide@4.1.11': + resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==} engines: {node: '>= 10'} - '@tailwindcss/vite@4.1.7': - resolution: {integrity: sha512-tYa2fO3zDe41I7WqijyVbRd8oWT0aEID1Eokz5hMT6wShLIHj3yvwj9XbfuloHP9glZ6H+aG2AN/+ZrxJ1Y5RQ==} + '@tailwindcss/vite@4.1.11': + resolution: {integrity: sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==} peerDependencies: - vite: ^5.2.0 || ^6 + vite: ^5.2.0 || ^6 || ^7 '@tanstack/react-table@8.21.3': resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} @@ -980,6 +978,12 @@ packages: '@types/babel__traverse@7.20.7': resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} + '@types/chai@5.2.2': + resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/doctrine@0.0.9': resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==} @@ -989,8 +993,8 @@ packages: '@types/mdx@2.0.13': resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} - '@types/react@19.1.4': - resolution: {integrity: sha512-EB1yiiYdvySuIITtD5lhW4yPyJ31RkJkkDw794LaQYrxCSaQV/47y5o1FMC4zF9ZyjUjzJMZwbovEnT5yHTW6g==} + '@types/react@19.1.8': + resolution: {integrity: sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==} '@types/resolve@1.20.6': resolution: {integrity: sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==} @@ -998,12 +1002,12 @@ packages: '@types/uuid@9.0.8': resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} - '@vitest/browser@3.1.3': - resolution: {integrity: sha512-Dgyez9LbHJHl9ObZPo5mu4zohWLo7SMv8zRWclMF+dxhQjmOtEP0raEX13ac5ygcvihNoQPBZXdya5LMSbcCDQ==} + '@vitest/browser@3.2.4': + resolution: {integrity: sha512-tJxiPrWmzH8a+w9nLKlQMzAKX/7VjFs50MWgcAj7p9XQ7AQ9/35fByFYptgPELyLw+0aixTnC4pUWV+APcZ/kw==} peerDependencies: playwright: '*' safaridriver: '*' - vitest: 3.1.3 + vitest: 3.2.4 webdriverio: ^7.0.0 || ^8.0.0 || ^9.0.0 peerDependenciesMeta: playwright: @@ -1013,11 +1017,11 @@ packages: webdriverio: optional: true - '@vitest/coverage-v8@3.1.3': - resolution: {integrity: sha512-cj76U5gXCl3g88KSnf80kof6+6w+K4BjOflCl7t6yRJPDuCrHtVu0SgNYOUARJOL5TI8RScDbm5x4s1/P9bvpw==} + '@vitest/coverage-v8@3.2.4': + resolution: {integrity: sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==} peerDependencies: - '@vitest/browser': 3.1.3 - vitest: 3.1.3 + '@vitest/browser': 3.2.4 + vitest: 3.2.4 peerDependenciesMeta: '@vitest/browser': optional: true @@ -1025,14 +1029,14 @@ packages: '@vitest/expect@2.0.5': resolution: {integrity: sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==} - '@vitest/expect@3.1.3': - resolution: {integrity: sha512-7FTQQuuLKmN1Ig/h+h/GO+44Q1IlglPlR2es4ab7Yvfx+Uk5xsv+Ykk+MEt/M2Yn/xGmzaLKxGw2lgy2bwuYqg==} + '@vitest/expect@3.2.4': + resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - '@vitest/mocker@3.1.3': - resolution: {integrity: sha512-PJbLjonJK82uCWHjzgBJZuR7zmAOrSvKk1QBxrennDIgtH4uK0TB1PvYmc0XBCigxxtiAVPfWtAdy4lpz8SQGQ==} + '@vitest/mocker@3.2.4': + resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} peerDependencies: msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 peerDependenciesMeta: msw: optional: true @@ -1045,20 +1049,20 @@ packages: '@vitest/pretty-format@2.1.9': resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==} - '@vitest/pretty-format@3.1.3': - resolution: {integrity: sha512-i6FDiBeJUGLDKADw2Gb01UtUNb12yyXAqC/mmRWuYl+m/U9GS7s8us5ONmGkGpUUo7/iAYzI2ePVfOZTYvUifA==} + '@vitest/pretty-format@3.2.4': + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/runner@3.1.3': - resolution: {integrity: sha512-Tae+ogtlNfFei5DggOsSUvkIaSuVywujMj6HzR97AHK6XK8i3BuVyIifWAm/sE3a15lF5RH9yQIrbXYuo0IFyA==} + '@vitest/runner@3.2.4': + resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} - '@vitest/snapshot@3.1.3': - resolution: {integrity: sha512-XVa5OPNTYUsyqG9skuUkFzAeFnEzDp8hQu7kZ0N25B1+6KjGm4hWLtURyBbsIAOekfWQ7Wuz/N/XXzgYO3deWQ==} + '@vitest/snapshot@3.2.4': + resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} '@vitest/spy@2.0.5': resolution: {integrity: sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==} - '@vitest/spy@3.1.3': - resolution: {integrity: sha512-x6w+ctOEmEXdWaa6TO4ilb7l9DxPR5bwEb6hILKuxfU1NqWT2mpJD9NJN7t3OTfxmVlOMrvtoFJGdgyzZ605lQ==} + '@vitest/spy@3.2.4': + resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} '@vitest/utils@2.0.5': resolution: {integrity: sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==} @@ -1066,8 +1070,8 @@ packages: '@vitest/utils@2.1.9': resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==} - '@vitest/utils@3.1.3': - resolution: {integrity: sha512-2Ltrpht4OmHO9+c/nmHtF09HWiyWdworqnHIwjfvDyWjuwKbdkcS9AnhsDn+8E2RM4x++foD1/tNuLPVvWG1Rg==} + '@vitest/utils@3.2.4': + resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} acorn@8.14.1: resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} @@ -1109,6 +1113,9 @@ packages: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} + ast-v8-to-istanbul@0.3.3: + resolution: {integrity: sha512-MuXMrSLVVoA6sYN/6Hke18vMzrT4TZNbZIj/hvh0fnYFpO+/kFXcLIaiPwXXWaQUPg4yJD8fj+lfJ7/1EBconw==} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -1333,8 +1340,8 @@ packages: resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} engines: {node: '>=12.0.0'} - fdir@6.4.4: - resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} + fdir@6.4.6: + resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: @@ -1525,6 +1532,9 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + jsdoc-type-pratt-parser@4.1.0: resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==} engines: {node: '>=12.0.0'} @@ -1621,14 +1631,17 @@ packages: loupe@3.1.3: resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} + loupe@3.1.4: + resolution: {integrity: sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lucide-react@0.511.0: - resolution: {integrity: sha512-VK5a2ydJ7xm8GvBeKLS9mu1pVK6ucef9780JVUjw6bAjJL/QXnd4Y0p7SPeOUMC27YhzNCZvm5d/QX0Tp3rc0w==} + lucide-react@0.525.0: + resolution: {integrity: sha512-Tm1txJ2OkymCGkvwoHt33Y2JpN5xucVq1slHcgE6Lk0WjDfjgKWor5CdVER8U6DvcfMwh4M8XxmpTiyzfmfDYQ==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -1776,13 +1789,13 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} - playwright-core@1.52.0: - resolution: {integrity: sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==} + playwright-core@1.53.2: + resolution: {integrity: sha512-ox/OytMy+2w1jcYEYlOo1Hhp8hZkLCximMTUTMBXjGUA1KoFfiSZ+DU+3a739jsPY0yoKH2TFy9S2fsJas8yAw==} engines: {node: '>=18'} hasBin: true - playwright@1.52.0: - resolution: {integrity: sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==} + playwright@1.53.2: + resolution: {integrity: sha512-6K/qQxVFuVQhRQhFsVZ9fGeatxirtrpPgxzBYWyZLEXJzqYwuL4fuNmfOfD5et1tJE4GScKyPNeLhZeRwuTU3A==} engines: {node: '>=18'} hasBin: true @@ -1794,8 +1807,8 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} - postcss@8.5.3: - resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} pretty-format@27.5.1: @@ -1858,6 +1871,9 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + reselect@5.1.1: + resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + resolve@1.22.10: resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} engines: {node: '>= 0.4'} @@ -1913,8 +1929,8 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - sonner@2.0.3: - resolution: {integrity: sha512-njQ4Hht92m0sMqqHVDL32V2Oun9W1+PHO9NDv9FHfJjT3JT22IG4Jpo3FPQy+mouRKCXFWO+r67v6MrHX2zeIA==} + sonner@2.0.6: + resolution: {integrity: sha512-yHFhk8T/DK3YxjFQXIrcHT1rGEeTLliVzWbO0xN8GberVun2RiBnxAjXAYpZrqwEVHBG9asI/Li8TAAhN9m59Q==} peerDependencies: react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc @@ -1976,6 +1992,9 @@ packages: resolution: {integrity: sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==} engines: {node: '>=12'} + strip-literal@3.0.0: + resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -1987,11 +2006,11 @@ packages: tabbable@6.2.0: resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} - tailwind-merge@3.3.0: - resolution: {integrity: sha512-fyW/pEfcQSiigd5SNn0nApUOxx0zB/dm6UDU/rEwc2c3sX2smWUNbapHv+QRqLGVp9GWX3THIa7MUGPo+YkDzQ==} + tailwind-merge@3.3.1: + resolution: {integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==} - tailwindcss@4.1.7: - resolution: {integrity: sha512-kr1o/ErIdNhTz8uzAYL7TpaUuzKIE6QPQ4qmSdxnoX/lo+5wmUHQA6h3L5yIqEImSRnAAURDirLu/BgiXGPAhg==} + tailwindcss@4.1.11: + resolution: {integrity: sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==} tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} @@ -2017,12 +2036,12 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyglobby@0.2.13: - resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} + tinyglobby@0.2.14: + resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} - tinypool@1.0.2: - resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} engines: {node: ^18.0.0 || >=20.0.0} tinyrainbow@1.2.0: @@ -2037,6 +2056,10 @@ packages: resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} + tinyspy@4.0.3: + resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} + engines: {node: '>=14.0.0'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -2090,8 +2113,8 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true - vite-node@3.1.3: - resolution: {integrity: sha512-uHV4plJ2IxCl4u1up1FQRrqclylKAogbtBfOTwcuJ28xFi+89PZ57BRh+naIRvH70HPwxy5QHYzg1OrEaC7AbA==} + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true @@ -2135,16 +2158,16 @@ packages: yaml: optional: true - vitest@3.1.3: - resolution: {integrity: sha512-188iM4hAHQ0km23TN/adso1q5hhwKqUpv+Sd6p5sOuh6FhQnRNW3IsiIpvxqahtBabsJ2SLZgmGSpcYK4wQYJw==} + vitest@3.2.4: + resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/debug': ^4.1.12 '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.1.3 - '@vitest/ui': 3.1.3 + '@vitest/browser': 3.2.4 + '@vitest/ui': 3.2.4 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -2316,6 +2339,8 @@ snapshots: '@babel/runtime@7.27.1': {} + '@babel/runtime@7.27.6': {} + '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 @@ -2339,16 +2364,18 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@base-ui-components/react@1.0.0-beta.0(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@base-ui-components/react@1.0.0-beta.1(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@babel/runtime': 7.27.1 - '@floating-ui/react': 0.27.12(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@babel/runtime': 7.27.6 + '@floating-ui/react-dom': 2.1.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@floating-ui/utils': 0.2.9 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) + reselect: 5.1.1 + tabbable: 6.2.0 use-sync-external-store: 1.5.0(react@19.1.0) optionalDependencies: - '@types/react': 19.1.4 + '@types/react': 19.1.8 '@bcoe/v8-coverage@1.0.2': {} @@ -2477,14 +2504,6 @@ snapshots: react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - '@floating-ui/react@0.27.12(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@floating-ui/react-dom': 2.1.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@floating-ui/utils': 0.2.9 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - tabbable: 6.2.0 - '@floating-ui/utils@0.2.9': {} '@isaacs/cliui@8.0.2': @@ -2528,10 +2547,10 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - '@mdx-js/react@3.1.0(@types/react@19.1.4)(react@19.1.0)': + '@mdx-js/react@3.1.0(@types/react@19.1.8)(react@19.1.0)': dependencies: '@types/mdx': 2.0.13 - '@types/react': 19.1.4 + '@types/react': 19.1.8 react: 19.1.0 '@parcel/watcher-android-arm64@2.5.1': @@ -2698,9 +2717,9 @@ snapshots: storybook: 8.6.14 ts-dedent: 2.2.0 - '@storybook/addon-docs@8.6.14(@types/react@19.1.4)(storybook@8.6.14)': + '@storybook/addon-docs@8.6.14(@types/react@19.1.8)(storybook@8.6.14)': dependencies: - '@mdx-js/react': 3.1.0(@types/react@19.1.4)(react@19.1.0) + '@mdx-js/react': 3.1.0(@types/react@19.1.8)(react@19.1.0) '@storybook/blocks': 8.6.14(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@8.6.14) '@storybook/csf-plugin': 8.6.14(storybook@8.6.14) '@storybook/react-dom-shim': 8.6.14(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@8.6.14) @@ -2711,12 +2730,12 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@storybook/addon-essentials@8.6.14(@types/react@19.1.4)(storybook@8.6.14)': + '@storybook/addon-essentials@8.6.14(@types/react@19.1.8)(storybook@8.6.14)': dependencies: '@storybook/addon-actions': 8.6.14(storybook@8.6.14) '@storybook/addon-backgrounds': 8.6.14(storybook@8.6.14) '@storybook/addon-controls': 8.6.14(storybook@8.6.14) - '@storybook/addon-docs': 8.6.14(@types/react@19.1.4)(storybook@8.6.14) + '@storybook/addon-docs': 8.6.14(@types/react@19.1.8)(storybook@8.6.14) '@storybook/addon-highlight': 8.6.14(storybook@8.6.14) '@storybook/addon-measure': 8.6.14(storybook@8.6.14) '@storybook/addon-outline': 8.6.14(storybook@8.6.14) @@ -2798,7 +2817,7 @@ snapshots: storybook: 8.6.14 unplugin: 1.16.1 - '@storybook/experimental-addon-test@8.6.14(@vitest/browser@3.1.3)(@vitest/runner@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@8.6.14)(vitest@3.1.3)': + '@storybook/experimental-addon-test@8.6.14(@vitest/browser@3.2.4)(@vitest/runner@3.2.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(storybook@8.6.14)(vitest@3.2.4)': dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 1.4.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -2809,9 +2828,9 @@ snapshots: storybook: 8.6.14 ts-dedent: 2.2.0 optionalDependencies: - '@vitest/browser': 3.1.3(playwright@1.52.0)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))(vitest@3.1.3) - '@vitest/runner': 3.1.3 - vitest: 3.1.3(@vitest/browser@3.1.3)(jiti@2.4.2)(lightningcss@1.30.1) + '@vitest/browser': 3.2.4(playwright@1.53.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))(vitest@3.2.4) + '@vitest/runner': 3.2.4 + vitest: 3.2.4(@vitest/browser@3.2.4)(jiti@2.4.2)(lightningcss@1.30.1) transitivePeerDependencies: - react - react-dom @@ -2895,17 +2914,17 @@ snapshots: dependencies: storybook: 8.6.14 - '@tailwindcss/cli@4.1.7': + '@tailwindcss/cli@4.1.11': dependencies: '@parcel/watcher': 2.5.1 - '@tailwindcss/node': 4.1.7 - '@tailwindcss/oxide': 4.1.7 + '@tailwindcss/node': 4.1.11 + '@tailwindcss/oxide': 4.1.11 enhanced-resolve: 5.18.1 mri: 1.2.0 picocolors: 1.1.1 - tailwindcss: 4.1.7 + tailwindcss: 4.1.11 - '@tailwindcss/node@4.1.7': + '@tailwindcss/node@4.1.11': dependencies: '@ampproject/remapping': 2.3.0 enhanced-resolve: 5.18.1 @@ -2913,67 +2932,67 @@ snapshots: lightningcss: 1.30.1 magic-string: 0.30.17 source-map-js: 1.2.1 - tailwindcss: 4.1.7 + tailwindcss: 4.1.11 - '@tailwindcss/oxide-android-arm64@4.1.7': + '@tailwindcss/oxide-android-arm64@4.1.11': optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.7': + '@tailwindcss/oxide-darwin-arm64@4.1.11': optional: true - '@tailwindcss/oxide-darwin-x64@4.1.7': + '@tailwindcss/oxide-darwin-x64@4.1.11': optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.7': + '@tailwindcss/oxide-freebsd-x64@4.1.11': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.7': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.7': + '@tailwindcss/oxide-linux-arm64-gnu@4.1.11': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.7': + '@tailwindcss/oxide-linux-arm64-musl@4.1.11': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.1.7': + '@tailwindcss/oxide-linux-x64-gnu@4.1.11': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.1.7': + '@tailwindcss/oxide-linux-x64-musl@4.1.11': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.1.7': + '@tailwindcss/oxide-wasm32-wasi@4.1.11': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.1.7': + '@tailwindcss/oxide-win32-arm64-msvc@4.1.11': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.1.7': + '@tailwindcss/oxide-win32-x64-msvc@4.1.11': optional: true - '@tailwindcss/oxide@4.1.7': + '@tailwindcss/oxide@4.1.11': dependencies: detect-libc: 2.0.4 tar: 7.4.3 optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.7 - '@tailwindcss/oxide-darwin-arm64': 4.1.7 - '@tailwindcss/oxide-darwin-x64': 4.1.7 - '@tailwindcss/oxide-freebsd-x64': 4.1.7 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.7 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.7 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.7 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.7 - '@tailwindcss/oxide-linux-x64-musl': 4.1.7 - '@tailwindcss/oxide-wasm32-wasi': 4.1.7 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.7 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.7 - - '@tailwindcss/vite@4.1.7(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))': - dependencies: - '@tailwindcss/node': 4.1.7 - '@tailwindcss/oxide': 4.1.7 - tailwindcss: 4.1.7 + '@tailwindcss/oxide-android-arm64': 4.1.11 + '@tailwindcss/oxide-darwin-arm64': 4.1.11 + '@tailwindcss/oxide-darwin-x64': 4.1.11 + '@tailwindcss/oxide-freebsd-x64': 4.1.11 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.11 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.11 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.11 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.11 + '@tailwindcss/oxide-linux-x64-musl': 4.1.11 + '@tailwindcss/oxide-wasm32-wasi': 4.1.11 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.11 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.11 + + '@tailwindcss/vite@4.1.11(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))': + dependencies: + '@tailwindcss/node': 4.1.11 + '@tailwindcss/oxide': 4.1.11 + tailwindcss: 4.1.11 vite: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1) '@tanstack/react-table@8.21.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': @@ -3036,13 +3055,19 @@ snapshots: dependencies: '@babel/types': 7.27.1 + '@types/chai@5.2.2': + dependencies: + '@types/deep-eql': 4.0.2 + + '@types/deep-eql@4.0.2': {} + '@types/doctrine@0.0.9': {} '@types/estree@1.0.7': {} '@types/mdx@2.0.13': {} - '@types/react@19.1.4': + '@types/react@19.1.8': dependencies: csstype: 3.1.3 @@ -3050,29 +3075,30 @@ snapshots: '@types/uuid@9.0.8': {} - '@vitest/browser@3.1.3(playwright@1.52.0)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))(vitest@3.1.3)': + '@vitest/browser@3.2.4(playwright@1.53.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))(vitest@3.2.4)': dependencies: '@testing-library/dom': 10.4.0 '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0) - '@vitest/mocker': 3.1.3(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)) - '@vitest/utils': 3.1.3 + '@vitest/mocker': 3.2.4(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)) + '@vitest/utils': 3.2.4 magic-string: 0.30.17 sirv: 3.0.1 tinyrainbow: 2.0.0 - vitest: 3.1.3(@vitest/browser@3.1.3)(jiti@2.4.2)(lightningcss@1.30.1) + vitest: 3.2.4(@vitest/browser@3.2.4)(jiti@2.4.2)(lightningcss@1.30.1) ws: 8.18.2 optionalDependencies: - playwright: 1.52.0 + playwright: 1.53.2 transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/coverage-v8@3.1.3(@vitest/browser@3.1.3)(vitest@3.1.3)': + '@vitest/coverage-v8@3.2.4(@vitest/browser@3.2.4)(vitest@3.2.4)': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 + ast-v8-to-istanbul: 0.3.3 debug: 4.4.1 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 @@ -3083,9 +3109,9 @@ snapshots: std-env: 3.9.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.1.3(@vitest/browser@3.1.3)(jiti@2.4.2)(lightningcss@1.30.1) + vitest: 3.2.4(@vitest/browser@3.2.4)(jiti@2.4.2)(lightningcss@1.30.1) optionalDependencies: - '@vitest/browser': 3.1.3(playwright@1.52.0)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))(vitest@3.1.3) + '@vitest/browser': 3.2.4(playwright@1.53.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))(vitest@3.2.4) transitivePeerDependencies: - supports-color @@ -3096,16 +3122,17 @@ snapshots: chai: 5.2.0 tinyrainbow: 1.2.0 - '@vitest/expect@3.1.3': + '@vitest/expect@3.2.4': dependencies: - '@vitest/spy': 3.1.3 - '@vitest/utils': 3.1.3 + '@types/chai': 5.2.2 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.1.3(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))': + '@vitest/mocker@3.2.4(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))': dependencies: - '@vitest/spy': 3.1.3 + '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: @@ -3119,18 +3146,19 @@ snapshots: dependencies: tinyrainbow: 1.2.0 - '@vitest/pretty-format@3.1.3': + '@vitest/pretty-format@3.2.4': dependencies: tinyrainbow: 2.0.0 - '@vitest/runner@3.1.3': + '@vitest/runner@3.2.4': dependencies: - '@vitest/utils': 3.1.3 + '@vitest/utils': 3.2.4 pathe: 2.0.3 + strip-literal: 3.0.0 - '@vitest/snapshot@3.1.3': + '@vitest/snapshot@3.2.4': dependencies: - '@vitest/pretty-format': 3.1.3 + '@vitest/pretty-format': 3.2.4 magic-string: 0.30.17 pathe: 2.0.3 @@ -3138,9 +3166,9 @@ snapshots: dependencies: tinyspy: 3.0.2 - '@vitest/spy@3.1.3': + '@vitest/spy@3.2.4': dependencies: - tinyspy: 3.0.2 + tinyspy: 4.0.3 '@vitest/utils@2.0.5': dependencies: @@ -3155,10 +3183,10 @@ snapshots: loupe: 3.1.3 tinyrainbow: 1.2.0 - '@vitest/utils@3.1.3': + '@vitest/utils@3.2.4': dependencies: - '@vitest/pretty-format': 3.1.3 - loupe: 3.1.3 + '@vitest/pretty-format': 3.2.4 + loupe: 3.1.4 tinyrainbow: 2.0.0 acorn@8.14.1: {} @@ -3187,6 +3215,12 @@ snapshots: dependencies: tslib: 2.8.1 + ast-v8-to-istanbul@0.3.3: + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + estree-walker: 3.0.3 + js-tokens: 9.0.1 + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 @@ -3414,7 +3448,7 @@ snapshots: expect-type@1.2.1: {} - fdir@6.4.4(picomatch@4.0.2): + fdir@6.4.6(picomatch@4.0.2): optionalDependencies: picomatch: 4.0.2 @@ -3601,6 +3635,8 @@ snapshots: js-tokens@4.0.0: {} + js-tokens@9.0.1: {} + jsdoc-type-pratt-parser@4.1.0: {} jsesc@3.1.0: {} @@ -3666,13 +3702,15 @@ snapshots: loupe@3.1.3: {} + loupe@3.1.4: {} + lru-cache@10.4.3: {} lru-cache@5.1.1: dependencies: yallist: 3.1.1 - lucide-react@0.511.0(react@19.1.0): + lucide-react@0.525.0(react@19.1.0): dependencies: react: 19.1.0 @@ -3789,11 +3827,11 @@ snapshots: picomatch@4.0.2: {} - playwright-core@1.52.0: {} + playwright-core@1.53.2: {} - playwright@1.52.0: + playwright@1.53.2: dependencies: - playwright-core: 1.52.0 + playwright-core: 1.53.2 optionalDependencies: fsevents: 2.3.2 @@ -3803,7 +3841,7 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss@8.5.3: + postcss@8.5.6: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -3892,6 +3930,8 @@ snapshots: require-directory@2.1.1: {} + reselect@5.1.1: {} + resolve@1.22.10: dependencies: is-core-module: 2.16.1 @@ -3965,7 +4005,7 @@ snapshots: sisteransi@1.0.5: {} - sonner@2.0.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + sonner@2.0.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: react: 19.1.0 react-dom: 19.1.0(react@19.1.0) @@ -4022,6 +4062,10 @@ snapshots: dependencies: min-indent: 1.0.1 + strip-literal@3.0.0: + dependencies: + js-tokens: 9.0.1 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -4030,9 +4074,9 @@ snapshots: tabbable@6.2.0: {} - tailwind-merge@3.3.0: {} + tailwind-merge@3.3.1: {} - tailwindcss@4.1.7: {} + tailwindcss@4.1.11: {} tapable@2.2.1: {} @@ -4062,12 +4106,12 @@ snapshots: tinyexec@0.3.2: {} - tinyglobby@0.2.13: + tinyglobby@0.2.14: dependencies: - fdir: 6.4.4(picomatch@4.0.2) + fdir: 6.4.6(picomatch@4.0.2) picomatch: 4.0.2 - tinypool@1.0.2: {} + tinypool@1.1.1: {} tinyrainbow@1.2.0: {} @@ -4075,6 +4119,8 @@ snapshots: tinyspy@3.0.2: {} + tinyspy@4.0.3: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -4122,7 +4168,7 @@ snapshots: uuid@9.0.1: {} - vite-node@3.1.3(jiti@2.4.2)(lightningcss@1.30.1): + vite-node@3.2.4(jiti@2.4.2)(lightningcss@1.30.1): dependencies: cac: 6.7.14 debug: 4.4.1 @@ -4146,41 +4192,43 @@ snapshots: vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1): dependencies: esbuild: 0.25.4 - fdir: 6.4.4(picomatch@4.0.2) + fdir: 6.4.6(picomatch@4.0.2) picomatch: 4.0.2 - postcss: 8.5.3 + postcss: 8.5.6 rollup: 4.40.2 - tinyglobby: 0.2.13 + tinyglobby: 0.2.14 optionalDependencies: fsevents: 2.3.3 jiti: 2.4.2 lightningcss: 1.30.1 - vitest@3.1.3(@vitest/browser@3.1.3)(jiti@2.4.2)(lightningcss@1.30.1): + vitest@3.2.4(@vitest/browser@3.2.4)(jiti@2.4.2)(lightningcss@1.30.1): dependencies: - '@vitest/expect': 3.1.3 - '@vitest/mocker': 3.1.3(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)) - '@vitest/pretty-format': 3.1.3 - '@vitest/runner': 3.1.3 - '@vitest/snapshot': 3.1.3 - '@vitest/spy': 3.1.3 - '@vitest/utils': 3.1.3 + '@types/chai': 5.2.2 + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1)) + '@vitest/pretty-format': 3.2.4 + '@vitest/runner': 3.2.4 + '@vitest/snapshot': 3.2.4 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 chai: 5.2.0 debug: 4.4.1 expect-type: 1.2.1 magic-string: 0.30.17 pathe: 2.0.3 + picomatch: 4.0.2 std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.13 - tinypool: 1.0.2 + tinyglobby: 0.2.14 + tinypool: 1.1.1 tinyrainbow: 2.0.0 vite: 6.3.5(jiti@2.4.2)(lightningcss@1.30.1) - vite-node: 3.1.3(jiti@2.4.2)(lightningcss@1.30.1) + vite-node: 3.2.4(jiti@2.4.2)(lightningcss@1.30.1) why-is-node-running: 2.3.0 optionalDependencies: - '@vitest/browser': 3.1.3(playwright@1.52.0)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))(vitest@3.1.3) + '@vitest/browser': 3.2.4(playwright@1.53.2)(vite@6.3.5(jiti@2.4.2)(lightningcss@1.30.1))(vitest@3.2.4) transitivePeerDependencies: - jiti - less From 113b34ebd9a5d851be930d45ec84708c0a3e2166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malcolm=20Nihl=C3=A9n?= Date: Sun, 6 Jul 2025 23:25:47 +0200 Subject: [PATCH 5/9] feat: add sorting menu to table --- .../src/components/menu/menu.stories.tsx | 5 +- .../ui-react/src/components/menu/menu.tsx | 71 ++-- .../src/components/table/table-test.tsx | 71 ++++ .../src/components/table/table.stories.tsx | 9 +- .../ui-react/src/components/table/table.tsx | 332 ++++++++++-------- 5 files changed, 300 insertions(+), 188 deletions(-) create mode 100644 packages/ui-react/src/components/table/table-test.tsx diff --git a/packages/ui-react/src/components/menu/menu.stories.tsx b/packages/ui-react/src/components/menu/menu.stories.tsx index cf79dfa..93fcb5a 100644 --- a/packages/ui-react/src/components/menu/menu.stories.tsx +++ b/packages/ui-react/src/components/menu/menu.stories.tsx @@ -1,4 +1,5 @@ import type { Meta, Preview } from "@storybook/react"; +import { InfoIcon } from "lucide-react"; import { Button } from "../button/button.js"; import * as Menu from "./menu.js"; @@ -46,7 +47,9 @@ export const Nested = { - Submenu} /> + }>Submenu} + /> Option 1 Option 2 diff --git a/packages/ui-react/src/components/menu/menu.tsx b/packages/ui-react/src/components/menu/menu.tsx index 22b45ac..58f6486 100644 --- a/packages/ui-react/src/components/menu/menu.tsx +++ b/packages/ui-react/src/components/menu/menu.tsx @@ -129,37 +129,52 @@ const GroupLabel = ({ /> ); -const Item = ({ className, children, ...props }: MenuPrimitive.Item.Props) => ( - { + const { icon, ...otherProps } = props; - data-[disabled]:pointer-events-none - data-[disabled]:opacity-50 + return ( + + {icon && {icon}} - group/item - `, - className, - )} - {...props} - > - {children} + {/* This 2px padding is there to fix some issues with the font not being correctly centered. */} + {children} - - -); + + + ); +}; const Separator = ({ className, ...props }: MenuPrimitive.Separator.Props) => ( (); + +const columns = [ + columnHelper.accessor("firstName", { + header: () => "Förnamn", + }), + columnHelper.accessor("lastName", { + header: () => "Efternamn", + enableSorting: false, + }), + columnHelper.accessor("role", { + header: () => "Roll", + cell: (info) => { + const role = info.getValue(); + return role.charAt(0).toUpperCase() + role.slice(1); + }, + }), +]; + +function TableTest() { + const [data, _setData] = useState(() => [...defaultData]); + + const table = useReactTable({ + data, + columns, + columnResizeMode: "onChange", + getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getSortedRowModel: getSortedRowModel(), + }); + + return ( + <> +
+        {JSON.stringify(
+          {
+            // columnSizing: table.getState().columnSizing,
+            // columnSizeVars,
+          },
+          null,
+          2,
+        )}
+      
+
+ + ); +} + +export { TableTest }; diff --git a/packages/ui-react/src/components/table/table.stories.tsx b/packages/ui-react/src/components/table/table.stories.tsx index b30a285..3a6becb 100644 --- a/packages/ui-react/src/components/table/table.stories.tsx +++ b/packages/ui-react/src/components/table/table.stories.tsx @@ -1,9 +1,12 @@ import type { Meta, Preview } from "@storybook/react"; -import { TableTest } from "./table.js"; +import { Table } from "./table.js"; +import { TableTest } from "./table-test.js"; export default { title: "Components/Table", - component: TableTest, + component: Table, } satisfies Meta; -export const Simple = {} satisfies Preview; +export const Simple = { + render: () => , +} satisfies Preview; diff --git a/packages/ui-react/src/components/table/table.tsx b/packages/ui-react/src/components/table/table.tsx index dcc401e..178a68b 100644 --- a/packages/ui-react/src/components/table/table.tsx +++ b/packages/ui-react/src/components/table/table.tsx @@ -1,62 +1,23 @@ import { - createColumnHelper, flexRender, - getCoreRowModel, - getFilteredRowModel, + type Header, type Table as TanstackTable, - useReactTable, } from "@tanstack/react-table"; -import { EllipsisVerticalIcon, ListFilterIcon } from "lucide-react"; -import { type ComponentProps, memo, useMemo, useState } from "react"; +import { + ArrowDownIcon, + ArrowUpIcon, + ChevronsUpDownIcon, + EllipsisVerticalIcon, + ListFilterIcon, +} from "lucide-react"; +import { memo, useMemo } from "react"; +import { Fragment } from "react/jsx-runtime"; import { cn } from "../../lib/utils.js"; import { Button } from "../button/button.js"; import { Card } from "../card/card.js"; +import * as Menu from "../menu/menu.js"; -type Attendee = { - firstName: string; - lastName: string; - role: "scout" | "leader" | "volunteer"; -}; - -const defaultData: Attendee[] = [ - { firstName: "Alice", lastName: "Smith", role: "scout" }, - { firstName: "Bob", lastName: "Johnson", role: "leader" }, - { firstName: "Charlie", lastName: "Brown", role: "volunteer" }, -]; - -const columnHelper = createColumnHelper(); - -const columns = [ - columnHelper.accessor("firstName", { - header: () => "Förnamn", - }), - columnHelper.accessor("lastName", { - header: () => "Efternamn", - }), - columnHelper.accessor("role", { - header: () => "Roll", - cell: (info) => { - const role = info.getValue(); - return role.charAt(0).toUpperCase() + role.slice(1); - }, - }), -]; - -function TableTest() { - const [data, _setData] = useState(() => [...defaultData]); - - const table = useReactTable({ - data, - columns, - columnResizeMode: "onChange", - getCoreRowModel: getCoreRowModel(), - getFilteredRowModel: getFilteredRowModel(), - }); - - return
; -} - -export type Props = ComponentProps<"table"> & { +export type Props = Parameters[0] & { table: TanstackTable; }; @@ -81,115 +42,80 @@ function Table(props: Props) { }, [table.getState().columnSizingInfo, table.getState().columnSizing]); return ( - <> -
-        {JSON.stringify(
-          {
-            // columnSizing: table.getState().columnSizing,
-            // columnSizeVars,
-          },
-          null,
-          2,
-        )}
-      
- - +
-
- - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - - ))} - - ))} - - {table.getState().columnSizingInfo.isResizingColumn ? ( - - ) : ( - - )} - - {table.getFooterGroups().map((footerGroup) => ( - - {footerGroup.headers.map((header) => ( - + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + - ))} - - ))} - -
-
- {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef.header, - header.getContext(), - )} - -
- - -
-
- - {header.column.getCanResize() && ( -
header.column.resetSize()} - onMouseDown={header.getResizeHandler()} - onTouchStart={header.getResizeHandler()} - className={cn( - "absolute flex justify-center items-center py-2 top-0 right-0 h-full w-2 cursor-col-resize touch-none select-none", - "after:w-0.5 after:h-full after:bg-gray-300", - header.column.getIsResizing() && - "bg-blue-100 after:invisible", - )} - style={{ - transform: - table.options.columnResizeMode === "onEnd" && - header.column.getIsResizing() - ? `translateX(${table.getState().columnSizingInfo.deltaOffset}px)` - : "", - }} - >
- )} -
+
+
{header.isPlaceholder ? null : flexRender( - header.column.columnDef.footer, + header.column.columnDef.header, header.getContext(), )} -
- - + +
+ + +
+
+ + {header.column.getCanResize() && ( + + )} + + ))} + + ))} + + + {table.getState().columnSizingInfo.isResizingColumn ? ( + + ) : ( + + )} + + + {table.getFooterGroups().map((footerGroup) => ( + + {footerGroup.headers.map((header) => ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.footer, + header.getContext(), + )} + + ))} + + ))} + + + ); } @@ -209,10 +135,104 @@ function TableBody({ table }: { table: TanstackTable }) { ); } -//special memoized wrapper for our table body that we will use during column resizing +function ResizeHandle({ + table, + header, +}: { + // biome-ignore lint/suspicious/noExplicitAny: We don't care about the type here + table: TanstackTable; + // biome-ignore lint/suspicious/noExplicitAny: We don't care about the type here + header: Header; +}) { + return ( +
header.column.resetSize()} + onMouseDown={header.getResizeHandler()} + onTouchStart={header.getResizeHandler()} + className={cn( + "absolute flex justify-center items-center py-2 top-0 right-0 h-full w-2 cursor-col-resize touch-none select-none", + "after:w-0.5 after:h-full after:bg-gray-300", + header.column.getIsResizing() && "bg-blue-100 after:invisible", + )} + style={{ + transform: + table.options.columnResizeMode === "onEnd" && + header.column.getIsResizing() + ? `translateX(${table.getState().columnSizingInfo.deltaOffset}px)` + : "", + }} + /> + ); +} + +// biome-ignore lint/suspicious/noExplicitAny: We don't care about the type here +function HeaderMenu({ header }: { header: Header }) { + const menuSections = [ + header.column.getCanSort() && ( + + {header.column.getIsSorted() !== "asc" && ( + } + onClick={() => header.column.toggleSorting(false)} + > + Sort Ascending + + )} + {header.column.getIsSorted() !== "desc" && ( + } + onClick={() => header.column.toggleSorting(true)} + > + Sort Descending + + )} + {header.column.getIsSorted() && ( + } + onClick={() => header.column.clearSorting()} + > + Clear Sorting + + )} + + ), + ].filter((section) => section !== false); + + if (menuSections.length === 0) { + return null; + } + + return ( + + + + + } + /> + + + {menuSections.map((section, index) => ( + <> + {section} + {index < menuSections.length - 1 && } + + ))} + + + ); +} + +// Special memoized wrapper for our table body that we will use during column resizing export const MemoizedTableBody = memo( TableBody, (prev, next) => prev.table.options.data === next.table.options.data, ) as typeof TableBody; -export { Table, TableTest }; +export { Table }; From ee68a4eed0974da5aa228a1a313d69a7b1b14529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malcolm=20Nihl=C3=A9n?= Date: Mon, 7 Jul 2025 16:24:34 +0200 Subject: [PATCH 6/9] fix: use correct font --- packages/ui-react/.storybook/style.css | 2 ++ packages/ui-react/src/components/menu/menu.tsx | 2 +- packages/ui-react/src/overview.mdx | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/ui-react/.storybook/style.css b/packages/ui-react/.storybook/style.css index f95f59f..bb5c1bb 100644 --- a/packages/ui-react/.storybook/style.css +++ b/packages/ui-react/.storybook/style.css @@ -5,5 +5,7 @@ html { /* Use a bold color to clearly show cases where we've forgotten to set text color. */ color: #ff00ff; + + @apply font-sans; } } diff --git a/packages/ui-react/src/components/menu/menu.tsx b/packages/ui-react/src/components/menu/menu.tsx index 58f6486..edb6ffc 100644 --- a/packages/ui-react/src/components/menu/menu.tsx +++ b/packages/ui-react/src/components/menu/menu.tsx @@ -169,7 +169,7 @@ const Item = ({ {icon && {icon}} {/* This 2px padding is there to fix some issues with the font not being correctly centered. */} - {children} + {children} diff --git a/packages/ui-react/src/overview.mdx b/packages/ui-react/src/overview.mdx index 82d4769..aacc202 100644 --- a/packages/ui-react/src/overview.mdx +++ b/packages/ui-react/src/overview.mdx @@ -24,10 +24,10 @@ To use the provided styles yourself, setup your Tailwind CSS like this: // Import the Scouterna UI theme @import "@scouterna/ui-react/theme.css"; -// Set base text color to make your own text coherent with the theme +// Set base font-family and text color to make your own text coherent with the theme @layer base { html { - @apply text-gray-dark; + @apply font-sans text-gray-dark; } } ``` From 601e58d0ac5d72a5738a8513b394d2e83c79d296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malcolm=20Nihl=C3=A9n?= Date: Mon, 7 Jul 2025 16:52:33 +0200 Subject: [PATCH 7/9] fix: remove font hack because of fixed fonts --- packages/ui-react/src/components/menu/menu.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/ui-react/src/components/menu/menu.tsx b/packages/ui-react/src/components/menu/menu.tsx index edb6ffc..a059d8c 100644 --- a/packages/ui-react/src/components/menu/menu.tsx +++ b/packages/ui-react/src/components/menu/menu.tsx @@ -168,8 +168,7 @@ const Item = ({ > {icon && {icon}} - {/* This 2px padding is there to fix some issues with the font not being correctly centered. */} - {children} + {children} From 84da5cc4969bcc6bdb64e7fb086c43197733f498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malcolm=20Nihl=C3=A9n?= Date: Tue, 8 Jul 2025 12:06:34 +0200 Subject: [PATCH 8/9] feat: make header titles toggle sort --- .../src/components/table/table-test.tsx | 7 ++- .../ui-react/src/components/table/table.tsx | 53 ++++++++++++++++--- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/packages/ui-react/src/components/table/table-test.tsx b/packages/ui-react/src/components/table/table-test.tsx index d42fdcb..92df16b 100644 --- a/packages/ui-react/src/components/table/table-test.tsx +++ b/packages/ui-react/src/components/table/table-test.tsx @@ -16,7 +16,7 @@ type Attendee = { const defaultData: Attendee[] = [ { firstName: "Alice", lastName: "Smith", role: "scout" }, - { firstName: "Bob", lastName: "Johnson", role: "leader" }, + { firstName: "Bob", lastName: "Abraham", role: "leader" }, { firstName: "Charlie", lastName: "Brown", role: "volunteer" }, ]; @@ -25,13 +25,15 @@ const columnHelper = createColumnHelper(); const columns = [ columnHelper.accessor("firstName", { header: () => "Förnamn", + size: 200, }), columnHelper.accessor("lastName", { header: () => "Efternamn", - enableSorting: false, + size: 200, }), columnHelper.accessor("role", { header: () => "Roll", + enableSorting: false, cell: (info) => { const role = info.getValue(); return role.charAt(0).toUpperCase() + role.slice(1); @@ -58,6 +60,7 @@ function TableTest() { { // columnSizing: table.getState().columnSizing, // columnSizeVars, + sort: table.getState().sorting, }, null, 2, diff --git a/packages/ui-react/src/components/table/table.tsx b/packages/ui-react/src/components/table/table.tsx index 178a68b..93dda68 100644 --- a/packages/ui-react/src/components/table/table.tsx +++ b/packages/ui-react/src/components/table/table.tsx @@ -10,7 +10,7 @@ import { EllipsisVerticalIcon, ListFilterIcon, } from "lucide-react"; -import { memo, useMemo } from "react"; +import { memo, useId, useMemo } from "react"; import { Fragment } from "react/jsx-runtime"; import { cn } from "../../lib/utils.js"; import { Button } from "../button/button.js"; @@ -62,18 +62,13 @@ function Table(props: Props) { {headerGroup.headers.map((header) => (
- {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef.header, - header.getContext(), - )} +
+ + + + ); +} + // biome-ignore lint/suspicious/noExplicitAny: We don't care about the type here function HeaderMenu({ header }: { header: Header }) { const menuSections = [ From 7ae8861f6225c557463071918894a91b563138db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malcolm=20Nihl=C3=A9n?= Date: Tue, 8 Jul 2025 23:47:37 +0200 Subject: [PATCH 9/9] tmp --- .../src/components/button/button.stories.tsx | 6 ++++++ .../src/components/table/table-test.tsx | 20 ++++++++++++++++++- .../ui-react/src/components/table/table.tsx | 13 ++++++++---- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/packages/ui-react/src/components/button/button.stories.tsx b/packages/ui-react/src/components/button/button.stories.tsx index e25b5b7..f9b02c6 100644 --- a/packages/ui-react/src/components/button/button.stories.tsx +++ b/packages/ui-react/src/components/button/button.stories.tsx @@ -22,6 +22,12 @@ export const Contained = { }, }; +// + export const Text = { args: { variant: "text", diff --git a/packages/ui-react/src/components/table/table-test.tsx b/packages/ui-react/src/components/table/table-test.tsx index 92df16b..75d251d 100644 --- a/packages/ui-react/src/components/table/table-test.tsx +++ b/packages/ui-react/src/components/table/table-test.tsx @@ -18,6 +18,24 @@ const defaultData: Attendee[] = [ { firstName: "Alice", lastName: "Smith", role: "scout" }, { firstName: "Bob", lastName: "Abraham", role: "leader" }, { firstName: "Charlie", lastName: "Brown", role: "volunteer" }, + { firstName: "Diana", lastName: "Prince", role: "scout" }, + { firstName: "Ethan", lastName: "Hunt", role: "leader" }, + { firstName: "Fiona", lastName: "Apple", role: "volunteer" }, + { firstName: "George", lastName: "Washington", role: "scout" }, + { firstName: "Hannah", lastName: "Montana", role: "leader" }, + { firstName: "Ian", lastName: "Fleming", role: "volunteer" }, + { firstName: "Julia", lastName: "Roberts", role: "scout" }, + { firstName: "Kevin", lastName: "Spacey", role: "leader" }, + { firstName: "Laura", lastName: "Croft", role: "volunteer" }, + { firstName: "Mike", lastName: "Tyson", role: "scout" }, + { firstName: "Nina", lastName: "Simone", role: "leader" }, + { firstName: "Oscar", lastName: "Wilde", role: "volunteer" }, + { firstName: "Paula", lastName: "Patton", role: "scout" }, + { firstName: "Quentin", lastName: "Tarantino", role: "leader" }, + { firstName: "Rachel", lastName: "Green", role: "volunteer" }, + { firstName: "Sam", lastName: "Smith", role: "scout" }, + { firstName: "Tina", lastName: "Turner", role: "leader" }, + { firstName: "Ursula", lastName: "K. Le Guin", role: "volunteer" }, ]; const columnHelper = createColumnHelper(); @@ -66,7 +84,7 @@ function TableTest() { 2, )} - +
); } diff --git a/packages/ui-react/src/components/table/table.tsx b/packages/ui-react/src/components/table/table.tsx index 93dda68..2d2b260 100644 --- a/packages/ui-react/src/components/table/table.tsx +++ b/packages/ui-react/src/components/table/table.tsx @@ -1,3 +1,4 @@ +import { ScrollArea } from "@base-ui-components/react"; import { flexRender, type Header, @@ -48,6 +49,7 @@ function Table(props: Props) { variant="light" >
(props: Props) { : "100%", }} > - + {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( {table.getRowModel().rows.map((row) => ( - + {row.getVisibleCells().map((cell) => ( - ))}
({ table }: { table: TanstackTable }) { return (
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}