@stackframe/stack-ui 2.5.17 → 2.5.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/components/data-table/cells.d.ts +27 -0
  3. package/dist/components/data-table/cells.js +38 -0
  4. package/dist/components/data-table/column-header.d.ts +8 -0
  5. package/dist/components/data-table/column-header.js +10 -0
  6. package/dist/components/data-table/data-table.d.ts +10 -0
  7. package/dist/components/data-table/data-table.js +39 -0
  8. package/dist/components/data-table/faceted-filter.d.ts +15 -0
  9. package/dist/components/data-table/faceted-filter.js +26 -0
  10. package/dist/components/data-table/index.d.ts +9 -0
  11. package/dist/components/data-table/index.js +9 -0
  12. package/dist/components/data-table/pagination.d.ts +6 -0
  13. package/dist/components/data-table/pagination.js +10 -0
  14. package/dist/components/data-table/toolbar-items.d.ts +6 -0
  15. package/dist/components/data-table/toolbar-items.js +5 -0
  16. package/dist/components/data-table/toolbar.d.ts +8 -0
  17. package/dist/components/data-table/toolbar.js +45 -0
  18. package/dist/components/data-table/utils.d.ts +2 -0
  19. package/dist/components/data-table/utils.js +6 -0
  20. package/dist/components/data-table/view-options.d.ts +6 -0
  21. package/dist/components/data-table/view-options.js +12 -0
  22. package/dist/components/editable-text.d.ts +4 -0
  23. package/dist/components/editable-text.js +16 -0
  24. package/dist/components/simple-tooltip.js +1 -1
  25. package/dist/components/ui/card.d.ts +2 -1
  26. package/dist/components/ui/card.js +4 -3
  27. package/dist/components/ui/container.js +4 -15
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.js +2 -0
  30. package/package.json +4 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @stackframe/stack-ui
2
2
 
3
+ ## 2.5.19
4
+
5
+ ### Patch Changes
6
+
7
+ - Team frontend components
8
+ - Updated dependencies
9
+ - @stackframe/stack-shared@2.5.19
10
+
11
+ ## 2.5.18
12
+
13
+ ### Patch Changes
14
+
15
+ - Multi-factor authentication
16
+ - Updated dependencies
17
+ - @stackframe/stack-shared@2.5.18
18
+
3
19
  ## 2.5.17
4
20
 
5
21
  ### Patch Changes
@@ -0,0 +1,27 @@
1
+ import React from "react";
2
+ export declare function TextCell(props: {
3
+ children: React.ReactNode;
4
+ size?: number;
5
+ icon?: React.ReactNode;
6
+ }): import("react/jsx-runtime").JSX.Element;
7
+ export declare function AvatarCell(props: {
8
+ src?: string;
9
+ }): import("react/jsx-runtime").JSX.Element;
10
+ export declare function DateCell(props: {
11
+ date: Date;
12
+ ignoreAfterYears?: number;
13
+ }): import("react/jsx-runtime").JSX.Element;
14
+ type ActionItem = '-' | {
15
+ item: React.ReactNode;
16
+ onClick: (e: React.MouseEvent) => void | Promise<void>;
17
+ danger?: boolean;
18
+ };
19
+ export declare function ActionCell(props: {
20
+ items?: ActionItem[];
21
+ invisible?: boolean;
22
+ }): import("react/jsx-runtime").JSX.Element;
23
+ export declare function BadgeCell(props: {
24
+ badges: string[];
25
+ size?: number;
26
+ }): import("react/jsx-runtime").JSX.Element;
27
+ export {};
@@ -0,0 +1,38 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { DotsHorizontalIcon } from "@radix-ui/react-icons";
4
+ import { useEffect, useRef, useState } from "react";
5
+ import { SimpleTooltip, cn, Avatar, AvatarImage, Badge, Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "../..";
6
+ export function TextCell(props) {
7
+ const textRef = useRef(null);
8
+ const [isOverflowing, setIsOverflowing] = useState(false);
9
+ const overflowStyle = "text-ellipsis text-nowrap overflow-x-hidden";
10
+ useEffect(() => {
11
+ const checkOverflow = () => {
12
+ if (textRef.current) {
13
+ const isOverflowing = textRef.current.scrollWidth > textRef.current.clientWidth;
14
+ setIsOverflowing(isOverflowing);
15
+ }
16
+ };
17
+ checkOverflow();
18
+ window.addEventListener('resize', checkOverflow);
19
+ return () => {
20
+ window.removeEventListener('resize', checkOverflow);
21
+ };
22
+ }, []);
23
+ return (_jsx("div", { className: "relative", style: { minWidth: props.size }, children: _jsxs("div", { className: "flex items-center gap-2 absolute inset-0", children: [_jsx("div", { className: overflowStyle, ref: textRef, children: isOverflowing ? (_jsx(SimpleTooltip, { tooltip: props.children, children: _jsx("div", { className: overflowStyle, children: props.children }) })) : props.children }), props.icon && _jsx("div", { children: props.icon })] }) }));
24
+ }
25
+ export function AvatarCell(props) {
26
+ return (_jsx(Avatar, { className: "h-6 w-6", children: _jsx(AvatarImage, { src: props.src }) }));
27
+ }
28
+ export function DateCell(props) {
29
+ const ignore = !!props.ignoreAfterYears && new Date(new Date().setFullYear(new Date().getFullYear() + props.ignoreAfterYears)) < props.date;
30
+ const timeString = props.date.toLocaleTimeString([], { year: 'numeric', month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit' });
31
+ return (_jsx(TextCell, { size: 140, children: ignore ? 'Never' : timeString }));
32
+ }
33
+ export function ActionCell(props) {
34
+ return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", className: cn("flex h-8 w-8 p-0 data-[state=open]:bg-muted", props.invisible && "invisible"), children: [_jsx(DotsHorizontalIcon, { className: "h-4 w-4" }), _jsx("span", { className: "sr-only", children: "Open menu" })] }) }), _jsx(DropdownMenuContent, { align: "end", className: "w-[160px]", children: props.items?.map((item, index) => item === '-' ? (_jsx(DropdownMenuSeparator, {}, index)) : (_jsx(DropdownMenuItem, { onClick: item.onClick, className: item.danger ? "text-destructive" : "", children: item.item }, index))) })] }));
35
+ }
36
+ export function BadgeCell(props) {
37
+ return (_jsx("div", { className: "flex items-center gap-1 flex-wrap", children: props.badges.map((badge, index) => (_jsx(Badge, { variant: "secondary", children: badge }, index))) }));
38
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="react" />
2
+ import { Column } from "@tanstack/react-table";
3
+ interface DataTableColumnHeaderProps<TData, TValue> extends React.HTMLAttributes<HTMLDivElement> {
4
+ column: Column<TData, TValue>;
5
+ columnTitle: React.ReactNode;
6
+ }
7
+ export declare function DataTableColumnHeader<TData, TValue>({ column, columnTitle, className, }: DataTableColumnHeaderProps<TData, TValue>): import("react/jsx-runtime").JSX.Element;
8
+ export {};
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { cn } from "../..";
3
+ import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@stackframe/stack-ui";
4
+ import { EyeOff, ArrowUp, ArrowDown } from "lucide-react";
5
+ function Item(props) {
6
+ return (_jsx(DropdownMenuItem, { onClick: props.onClick, children: _jsxs("div", { className: "flex items-center", children: [_jsx(props.icon, { className: "mr-2 h-3.5 w-3.5 text-muted-foreground/70" }), props.children] }) }));
7
+ }
8
+ export function DataTableColumnHeader({ column, columnTitle, className, }) {
9
+ return (_jsx("div", { className: cn("flex items-center space-x-2", className), children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", size: "sm", className: "-ml-3 h-8 data-[state=open]:bg-accent", children: [_jsx("span", { children: columnTitle }), column.getIsSorted() === "desc" ? (_jsx(ArrowDown, { className: "ml-2 h-4 w-4" })) : column.getIsSorted() === "asc" ? (_jsx(ArrowUp, { className: "ml-2 h-4 w-4" })) : null] }) }), _jsxs(DropdownMenuContent, { align: "start", children: [column.getCanSort() && (_jsxs(_Fragment, { children: [_jsx(Item, { icon: ArrowUp, onClick: () => column.toggleSorting(false), children: "Asc" }), _jsx(Item, { icon: ArrowDown, onClick: () => column.toggleSorting(true), children: "Desc" })] })), _jsx(Item, { icon: EyeOff, onClick: () => column.toggleVisibility(false), children: "Hide" })] })] }) }));
10
+ }
@@ -0,0 +1,10 @@
1
+ import { ColumnDef, Table as TableType, VisibilityState } from "@tanstack/react-table";
2
+ import React from "react";
3
+ interface DataTableProps<TData, TValue> {
4
+ columns: ColumnDef<TData, TValue>[];
5
+ data: TData[];
6
+ toolbarRender?: (table: TableType<TData>) => React.ReactNode;
7
+ defaultVisibility?: VisibilityState;
8
+ }
9
+ export declare function DataTable<TData, TValue>({ columns, data, toolbarRender, defaultVisibility, }: DataTableProps<TData, TValue>): import("react/jsx-runtime").JSX.Element;
10
+ export {};
@@ -0,0 +1,39 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@stackframe/stack-ui";
4
+ import { flexRender, getCoreRowModel, getFacetedRowModel, getFacetedUniqueValues, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table";
5
+ import React from "react";
6
+ import { DataTablePagination } from "./pagination";
7
+ import { DataTableToolbar } from "./toolbar";
8
+ export function DataTable({ columns, data, toolbarRender, defaultVisibility, }) {
9
+ const [rowSelection, setRowSelection] = React.useState({});
10
+ const [columnVisibility, setColumnVisibility] = React.useState(defaultVisibility || {});
11
+ const [columnFilters, setColumnFilters] = React.useState([]);
12
+ const [sorting, setSorting] = React.useState([]);
13
+ const table = useReactTable({
14
+ data,
15
+ columns,
16
+ state: {
17
+ sorting,
18
+ columnVisibility,
19
+ rowSelection,
20
+ columnFilters,
21
+ },
22
+ enableRowSelection: true,
23
+ onRowSelectionChange: setRowSelection,
24
+ onSortingChange: setSorting,
25
+ onColumnFiltersChange: setColumnFilters,
26
+ onColumnVisibilityChange: setColumnVisibility,
27
+ getCoreRowModel: getCoreRowModel(),
28
+ getFilteredRowModel: getFilteredRowModel(),
29
+ getPaginationRowModel: getPaginationRowModel(),
30
+ getSortedRowModel: getSortedRowModel(),
31
+ getFacetedRowModel: getFacetedRowModel(),
32
+ getFacetedUniqueValues: getFacetedUniqueValues(),
33
+ });
34
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx(DataTableToolbar, { table: table, toolbarRender: toolbarRender }), _jsx("div", { className: "rounded-md border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => (_jsx(TableRow, { children: headerGroup.headers.map((header) => {
35
+ return (_jsx(TableHead, { colSpan: header.colSpan, children: header.isPlaceholder
36
+ ? null
37
+ : flexRender(header.column.columnDef.header, header.getContext()) }, header.id));
38
+ }) }, headerGroup.id))) }), _jsx(TableBody, { children: table.getRowModel().rows.length ? (table.getRowModel().rows.map((row) => (_jsx(TableRow, { "data-state": row.getIsSelected() && "selected", children: row.getVisibleCells().map((cell) => (_jsx(TableCell, { children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id))) }, row.id)))) : (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: columns.length, className: "h-24 text-center", children: "No results." }) })) })] }) }), _jsx(DataTablePagination, { table: table })] }));
39
+ }
@@ -0,0 +1,15 @@
1
+ import { Column } from "@tanstack/react-table";
2
+ import React from "react";
3
+ interface DataTableFacetedFilterProps<TData, TValue> {
4
+ column?: Column<TData, TValue>;
5
+ title?: string;
6
+ options: {
7
+ label: string;
8
+ value: string;
9
+ icon?: React.ComponentType<{
10
+ className?: string;
11
+ }>;
12
+ }[];
13
+ }
14
+ export declare function DataTableFacetedFilter<TData, TValue>({ column, title, options, }: DataTableFacetedFilterProps<TData, TValue>): import("react/jsx-runtime").JSX.Element;
15
+ export {};
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { cn } from "../..";
3
+ import { CheckIcon } from "@radix-ui/react-icons";
4
+ import { Badge, Button, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, Popover, PopoverContent, PopoverTrigger, Separator } from "@stackframe/stack-ui";
5
+ import { ListFilter } from "lucide-react";
6
+ export function DataTableFacetedFilter({ column, title, options, }) {
7
+ const facets = column?.getFacetedUniqueValues();
8
+ const selectedValues = new Set(column?.getFilterValue());
9
+ return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-8 border", children: [_jsx(ListFilter, { className: "mr-2 h-4 w-4 text-gray-500" }), title, selectedValues.size > 0 && (_jsxs(_Fragment, { children: [_jsx(Separator, { orientation: "vertical", className: "mx-2 h-4" }), _jsx(Badge, { variant: "secondary", className: "rounded-sm px-1 font-normal lg:hidden", children: selectedValues.size }), _jsx("div", { className: "hidden space-x-1 lg:flex", children: selectedValues.size > 2 ? (_jsxs(Badge, { variant: "secondary", className: "rounded-sm px-1 font-normal", children: [selectedValues.size, " selected"] })) : (options
10
+ .filter((option) => selectedValues.has(option.value))
11
+ .map((option) => (_jsx(Badge, { variant: "secondary", className: "rounded-sm px-1 font-normal", children: option.label }, option.value)))) })] }))] }) }), _jsx(PopoverContent, { className: "w-[200px] p-0", align: "start", children: _jsxs(Command, { children: [_jsx(CommandInput, { placeholder: title }), _jsxs(CommandList, { children: [_jsx(CommandEmpty, { children: "No results found." }), _jsx(CommandGroup, { children: options.map((option) => {
12
+ const isSelected = selectedValues.has(option.value);
13
+ return (_jsxs(CommandItem, { onSelect: () => {
14
+ if (isSelected) {
15
+ selectedValues.delete(option.value);
16
+ }
17
+ else {
18
+ selectedValues.add(option.value);
19
+ }
20
+ const filterValues = Array.from(selectedValues);
21
+ column?.setFilterValue(filterValues.length ? filterValues : undefined);
22
+ }, children: [_jsx("div", { className: cn("mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary", isSelected
23
+ ? "bg-primary text-primary-foreground"
24
+ : "opacity-50 [&_svg]:invisible"), children: _jsx(CheckIcon, { className: cn("h-4 w-4") }) }), option.icon && (_jsx(option.icon, { className: "mr-2 h-4 w-4 text-muted-foreground" })), _jsx("span", { children: option.label }), facets?.get(option.value) && (_jsx("span", { className: "ml-auto flex h-4 w-4 items-center justify-center font-mono text-xs", children: facets.get(option.value) }))] }, option.value));
25
+ }) }), selectedValues.size > 0 && (_jsxs(_Fragment, { children: [_jsx(CommandSeparator, {}), _jsx(CommandGroup, { children: _jsx(CommandItem, { onSelect: () => column?.setFilterValue(undefined), className: "justify-center text-center", children: "Clear filters" }) })] }))] })] }) })] }));
26
+ }
@@ -0,0 +1,9 @@
1
+ export * from "./cells";
2
+ export * from "./column-header";
3
+ export * from "./data-table";
4
+ export * from "./faceted-filter";
5
+ export * from "./pagination";
6
+ export * from "./toolbar-items";
7
+ export * from "./toolbar";
8
+ export * from "./utils";
9
+ export * from "./view-options";
@@ -0,0 +1,9 @@
1
+ export * from "./cells";
2
+ export * from "./column-header";
3
+ export * from "./data-table";
4
+ export * from "./faceted-filter";
5
+ export * from "./pagination";
6
+ export * from "./toolbar-items";
7
+ export * from "./toolbar";
8
+ export * from "./utils";
9
+ export * from "./view-options";
@@ -0,0 +1,6 @@
1
+ import { Table } from "@tanstack/react-table";
2
+ interface DataTablePaginationProps<TData> {
3
+ table: Table<TData>;
4
+ }
5
+ export declare function DataTablePagination<TData>({ table, }: DataTablePaginationProps<TData>): import("react/jsx-runtime").JSX.Element;
6
+ export {};
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ChevronLeftIcon, ChevronRightIcon, DoubleArrowLeftIcon, DoubleArrowRightIcon, } from "@radix-ui/react-icons";
3
+ import { Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@stackframe/stack-ui";
4
+ export function DataTablePagination({ table, }) {
5
+ return (_jsxs("div", { className: "flex items-center justify-between px-2 flex-col sm:flex-row gap-y-4 sm:gap-y-0", children: [_jsx("div", { className: "flex-1 text-sm text-muted-foreground", children: table.getFilteredSelectedRowModel().rows.length === 0 ?
6
+ `${table.getFilteredRowModel().rows.length} row(s) found` :
7
+ `${table.getFilteredSelectedRowModel().rows.length} of ${table.getFilteredRowModel().rows.length} row(s) selected` }), _jsxs("div", { className: "flex items-center gap-x-6 lg:gap-x-8 flex-col sm:flex-row gap-y-4 sm:gap-y-0", children: [_jsxs("div", { className: "flex items-center space-x-2", children: [_jsx("p", { className: "text-sm font-medium", children: "Rows per page" }), _jsxs(Select, { value: `${table.getState().pagination.pageSize}`, onValueChange: (value) => {
8
+ table.setPageSize(Number(value));
9
+ }, children: [_jsx(SelectTrigger, { className: "h-8 w-[70px]", children: _jsx(SelectValue, { placeholder: table.getState().pagination.pageSize }) }), _jsx(SelectContent, { side: "top", children: [10, 20, 30, 40, 50].map((pageSize) => (_jsx(SelectItem, { value: `${pageSize}`, children: pageSize }, pageSize))) })] })] }), _jsxs("div", { className: "flex items-center gap-4", children: [_jsxs("div", { className: "flex items-center justify-center text-sm font-medium", children: ["Page ", table.getState().pagination.pageIndex + 1, " of", " ", table.getPageCount()] }), _jsxs("div", { className: "flex items-center space-x-2", children: [_jsxs(Button, { variant: "outline", className: "hidden h-8 w-8 p-0 lg:flex", onClick: () => table.setPageIndex(0), disabled: !table.getCanPreviousPage(), children: [_jsx("span", { className: "sr-only", children: "Go to first page" }), _jsx(DoubleArrowLeftIcon, { className: "h-4 w-4" })] }), _jsxs(Button, { variant: "outline", className: "h-8 w-8 p-0", onClick: () => table.previousPage(), disabled: !table.getCanPreviousPage(), children: [_jsx("span", { className: "sr-only", children: "Go to previous page" }), _jsx(ChevronLeftIcon, { className: "h-4 w-4" })] }), _jsxs(Button, { variant: "outline", className: "h-8 w-8 p-0", onClick: () => table.nextPage(), disabled: !table.getCanNextPage(), children: [_jsx("span", { className: "sr-only", children: "Go to next page" }), _jsx(ChevronRightIcon, { className: "h-4 w-4" })] }), _jsxs(Button, { variant: "outline", className: "hidden h-8 w-8 p-0 lg:flex", onClick: () => table.setPageIndex(table.getPageCount() - 1), disabled: !table.getCanNextPage(), children: [_jsx("span", { className: "sr-only", children: "Go to last page" }), _jsx(DoubleArrowRightIcon, { className: "h-4 w-4" })] })] })] })] })] }));
10
+ }
@@ -0,0 +1,6 @@
1
+ import { Table } from "@tanstack/react-table";
2
+ export declare function SearchToolbarItem<TData>(props: {
3
+ table: Table<TData>;
4
+ keyName: string;
5
+ placeholder: string;
6
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Input } from "../..";
3
+ export function SearchToolbarItem(props) {
4
+ return (_jsx(Input, { placeholder: props.placeholder, value: `${props.table.getColumn(props.keyName)?.getFilterValue() ?? ""}`, onChange: (event) => props.table.getColumn(props.keyName)?.setFilterValue(event.target.value), className: "h-8 w-[150px] lg:w-[250px]" }));
5
+ }
@@ -0,0 +1,8 @@
1
+ /// <reference types="react" />
2
+ import { Table } from "@tanstack/react-table";
3
+ interface DataTableToolbarProps<TData> {
4
+ table: Table<TData>;
5
+ toolbarRender?: (table: Table<TData>) => React.ReactNode;
6
+ }
7
+ export declare function DataTableToolbar<TData>({ table, toolbarRender }: DataTableToolbarProps<TData>): import("react/jsx-runtime").JSX.Element;
8
+ export {};
@@ -0,0 +1,45 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Cross2Icon } from "@radix-ui/react-icons";
4
+ import { Button } from "@stackframe/stack-ui";
5
+ import { DataTableViewOptions } from "./view-options";
6
+ import { DownloadIcon } from "lucide-react";
7
+ import { mkConfig, generateCsv, download } from 'export-to-csv';
8
+ export function DataTableToolbar({ table, toolbarRender }) {
9
+ const isFiltered = table.getState().columnFilters.length > 0;
10
+ const isSorted = table.getState().sorting.length > 0;
11
+ return (_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [toolbarRender?.(table), (isFiltered || isSorted) && (_jsxs(Button, { variant: "ghost", onClick: () => {
12
+ table.resetColumnFilters();
13
+ table.resetSorting();
14
+ }, className: "h-8 px-2 lg:px-3", children: ["Reset", _jsx(Cross2Icon, { className: "ml-2 h-4 w-4" })] }))] }), _jsx("div", { className: "flex-1" }), _jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx(DataTableViewOptions, { table: table }), _jsxs(Button, { variant: "outline", size: "sm", className: "ml-auto hidden h-8 lg:flex", onClick: () => {
15
+ const csvConfig = mkConfig({
16
+ fieldSeparator: ',',
17
+ filename: 'data',
18
+ decimalSeparator: '.',
19
+ useKeysAsHeaders: true,
20
+ });
21
+ const renderCellValue = (cell) => {
22
+ const rendered = cell.renderValue();
23
+ if (rendered === null) {
24
+ return undefined;
25
+ }
26
+ if (['string', 'number', 'boolean', 'undefined'].includes(typeof rendered)) {
27
+ return rendered;
28
+ }
29
+ if (rendered instanceof Date) {
30
+ return rendered.toISOString();
31
+ }
32
+ if (typeof rendered === 'object') {
33
+ return JSON.stringify(rendered);
34
+ }
35
+ };
36
+ const rowModel = table.getCoreRowModel();
37
+ const rows = rowModel.rows.map(row => Object.fromEntries(row.getAllCells().map(c => [c.column.id, renderCellValue(c)]).filter(([_, v]) => v !== undefined)));
38
+ if (rows.length === 0) {
39
+ alert("No data to export");
40
+ return;
41
+ }
42
+ const csv = generateCsv(csvConfig)(rows);
43
+ download(csvConfig)(csv);
44
+ }, children: [_jsx(DownloadIcon, { className: "mr-2 h-4 w-4" }), "Export CSV"] })] })] }));
45
+ }
@@ -0,0 +1,2 @@
1
+ export declare function standardFilterFn(row: any, id: string, value: any): any;
2
+ export declare function arrayFilterFn(row: any, id: string, value: any): any;
@@ -0,0 +1,6 @@
1
+ export function standardFilterFn(row, id, value) {
2
+ return value.includes(row.getValue(id));
3
+ }
4
+ export function arrayFilterFn(row, id, value) {
5
+ return value.some((v) => row.getValue(id).includes(v));
6
+ }
@@ -0,0 +1,6 @@
1
+ import { Table } from "@tanstack/react-table";
2
+ interface DataTableViewOptionsProps<TData> {
3
+ table: Table<TData>;
4
+ }
5
+ export declare function DataTableViewOptions<TData>({ table, }: DataTableViewOptionsProps<TData>): import("react/jsx-runtime").JSX.Element;
6
+ export {};
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { MixerHorizontalIcon } from "@radix-ui/react-icons";
4
+ import { Button, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@stackframe/stack-ui";
5
+ export function DataTableViewOptions({ table, }) {
6
+ return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "ml-auto hidden h-8 lg:flex", children: [_jsx(MixerHorizontalIcon, { className: "mr-2 h-4 w-4" }), "View"] }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsx(DropdownMenuLabel, { children: "Toggle columns" }), _jsx(DropdownMenuSeparator, {}), table
7
+ .getAllColumns()
8
+ .filter((column) => typeof column.accessorFn !== "undefined" && column.getCanHide())
9
+ .map((column) => {
10
+ return (_jsx(DropdownMenuCheckboxItem, { className: "capitalize", checked: column.getIsVisible(), onCheckedChange: (value) => column.toggleVisibility(!!value), children: column.id }, column.id));
11
+ })] })] }));
12
+ }
@@ -0,0 +1,4 @@
1
+ export declare function EditableText(props: {
2
+ value: string;
3
+ onSave?: (value: string) => void | Promise<void>;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,16 @@
1
+ 'use client';
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Edit } from "lucide-react";
4
+ import { useState } from "react";
5
+ import { Button, Input, Typography } from "..";
6
+ export function EditableText(props) {
7
+ const [editing, setEditing] = useState(false);
8
+ const [editingValue, setEditingValue] = useState(props.value);
9
+ return (_jsx("div", { className: 'flex items-center gap-2', children: editing ? (_jsxs(_Fragment, { children: [_jsx(Input, { value: editingValue, onChange: (e) => setEditingValue(e.target.value) }), _jsx(Button, { onClick: async () => {
10
+ await props.onSave?.(editingValue);
11
+ setEditing(false);
12
+ }, children: "Save" }), _jsx(Button, { variant: 'outline', onClick: () => {
13
+ setEditingValue(props.value);
14
+ setEditing(false);
15
+ }, children: "Cancel" })] })) : (_jsxs(_Fragment, { children: [_jsx(Typography, { children: props.value }), _jsx(Button, { onClick: () => setEditing(true), size: 'icon', variant: 'ghost', children: _jsx(Edit, { className: "w-4 h-4" }) })] })) }));
16
+ }
@@ -7,5 +7,5 @@ export function SimpleTooltip(props) {
7
7
  props.type === 'info' ?
8
8
  _jsx(Info, { className: "w-4 h-4 text-zinc-500" }) :
9
9
  null;
10
- return (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex items-center gap-1", children: [props.children, " ", icon] }) }), _jsx(TooltipContent, { children: _jsx("div", { className: "max-w-60 text-center text-wrap", children: props.tooltip }) })] }) }));
10
+ return (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex items-center gap-1", children: [props.children, " ", icon] }) }), _jsx(TooltipContent, { children: _jsx("div", { className: "max-w-60 text-center text-wrap whitespace-pre-wrap", children: props.tooltip }) })] }) }));
11
11
  }
@@ -5,5 +5,6 @@ declare const CardHeader: React.ForwardRefExoticComponent<React.HTMLAttributes<H
5
5
  declare const CardTitle: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLHeadingElement> & React.RefAttributes<HTMLParagraphElement>>;
6
6
  declare const CardDescription: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>>;
7
7
  declare const CardContent: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
8
+ declare const CardSubtitle: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>>;
8
9
  declare const CardFooter: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
9
- export { Card, ClickableCard, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
10
+ export { Card, ClickableCard, CardHeader, CardFooter, CardTitle, CardDescription, CardContent, CardSubtitle };
@@ -5,14 +5,15 @@ const Card = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { r
5
5
  Card.displayName = "Card";
6
6
  const ClickableCard = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("rounded-xl border bg-card text-card-foreground shadow-sm cursor-pointer hover:border-[color:var(--primary)] ease-in-out", className), ...props })));
7
7
  ClickableCard.displayName = "ClickableCard";
8
- const CardHeader = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })));
8
+ const CardHeader = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("flex flex-col space-y-1.5 p-6 pb-0", className), ...props })));
9
9
  CardHeader.displayName = "CardHeader";
10
10
  const CardTitle = React.forwardRef(({ className, ...props }, ref) => (_jsx("h3", { ref: ref, className: cn("font-semibold leading-none tracking-tight capitalize", className), ...props })));
11
11
  CardTitle.displayName = "CardTitle";
12
12
  const CardDescription = React.forwardRef(({ className, ...props }, ref) => (_jsx("p", { ref: ref, className: cn("text-sm text-muted-foreground", className), ...props })));
13
13
  CardDescription.displayName = "CardDescription";
14
- const CardContent = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("p-6 pt-0", className), ...props })));
14
+ const CardContent = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("p-6", className), ...props })));
15
15
  CardContent.displayName = "CardContent";
16
+ const CardSubtitle = React.forwardRef(({ className, ...props }, ref) => (_jsx("h4", { ref: ref, className: cn("text-sm text-muted-foreground font-bold", className), ...props })));
16
17
  const CardFooter = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("flex items-center p-6 pt-0", className), ...props })));
17
18
  CardFooter.displayName = "CardFooter";
18
- export { Card, ClickableCard, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
19
+ export { Card, ClickableCard, CardHeader, CardFooter, CardTitle, CardDescription, CardContent, CardSubtitle };
@@ -1,19 +1,8 @@
1
1
  'use client';
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
- import React, { useId } from 'react';
4
- import { cn } from '../..';
2
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { filterUndefined } from '@stackframe/stack-shared/dist/utils/objects';
4
+ import React from 'react';
5
5
  const Container = React.forwardRef(({ size, ...props }, ref) => {
6
- const styleId = useId().replaceAll(':', '-');
7
- const styleSheet = `
8
- .stack-inner-container-${styleId} {
9
- max-width: 100%;
10
- }
11
- @media (min-width: ${size}px) {
12
- .stack-inner-container-${styleId} {
13
- width: ${size}px;
14
- }
15
- }
16
- `;
17
- return (_jsxs(_Fragment, { children: [_jsx("style", { children: styleSheet }), _jsx("div", { className: "flex justify-center w-full", children: _jsx("div", { ...props, ref: ref, className: cn(props.className, `stack-inner-container-${styleId}`), children: props.children }) })] }));
6
+ return (_jsx(_Fragment, { children: _jsx("div", { className: "flex justify-center w-full", children: _jsx("div", { ...props, ref: ref, style: { width: '100%', maxWidth: size, ...props.style ? filterUndefined(props.style) : {} }, children: props.children }) }) }));
18
7
  });
19
8
  export { Container };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ export * from "./components/action-dialog";
2
2
  export * from "./components/browser-frame";
3
3
  export * from "./components/copy-button";
4
4
  export * from "./components/copy-field";
5
+ export * from "./components/data-table";
6
+ export * from "./components/editable-text";
5
7
  export * from "./components/simple-tooltip";
6
8
  export * from "./components/ui/accordion";
7
9
  export * from "./components/ui/alert";
package/dist/index.js CHANGED
@@ -2,6 +2,8 @@ export * from "./components/action-dialog";
2
2
  export * from "./components/browser-frame";
3
3
  export * from "./components/copy-button";
4
4
  export * from "./components/copy-field";
5
+ export * from "./components/data-table";
6
+ export * from "./components/editable-text";
5
7
  export * from "./components/simple-tooltip";
6
8
  export * from "./components/ui/accordion";
7
9
  export * from "./components/ui/alert";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackframe/stack-ui",
3
- "version": "2.5.17",
3
+ "version": "2.5.19",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [
@@ -57,6 +57,8 @@
57
57
  "@radix-ui/react-toggle-group": "^1.0.4",
58
58
  "@radix-ui/react-tooltip": "^1.0.7",
59
59
  "class-variance-authority": "^0.7.0",
60
+ "@tanstack/react-table": "^8.17.0",
61
+ "export-to-csv": "^1.3.0",
60
62
  "clsx": "^2.0.0",
61
63
  "cmdk": "^1.0.0",
62
64
  "input-otp": "^1.2.4",
@@ -66,7 +68,7 @@
66
68
  "react-hook-form": "^7.51.4",
67
69
  "react-resizable-panels": "^2.0.19",
68
70
  "tailwind-merge": "^2.3.0",
69
- "@stackframe/stack-shared": "2.5.17"
71
+ "@stackframe/stack-shared": "2.5.19"
70
72
  },
71
73
  "devDependencies": {
72
74
  "@types/react": "^18.2.66",