@burtson-labs/ui 0.12.3 → 0.13.0

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 (49) hide show
  1. package/README.md +1 -1
  2. package/dist/components/chat-history.js +3 -2
  3. package/dist/components/chat-history.js.map +1 -1
  4. package/dist/components/checkbox-card.d.ts +25 -0
  5. package/dist/components/checkbox-card.js +65 -0
  6. package/dist/components/checkbox-card.js.map +1 -0
  7. package/dist/components/combobox.js +1 -1
  8. package/dist/components/command.js +4 -4
  9. package/dist/components/command.js.map +1 -1
  10. package/dist/components/composer.js +2 -2
  11. package/dist/components/composer.js.map +1 -1
  12. package/dist/components/context-menu.js +1 -1
  13. package/dist/components/context-menu.js.map +1 -1
  14. package/dist/components/data-table.d.ts +53 -3
  15. package/dist/components/data-table.js +346 -113
  16. package/dist/components/data-table.js.map +1 -1
  17. package/dist/components/dialog.d.ts +6 -1
  18. package/dist/components/dialog.js +21 -10
  19. package/dist/components/dialog.js.map +1 -1
  20. package/dist/components/dropdown-menu.js +1 -1
  21. package/dist/components/dropdown-menu.js.map +1 -1
  22. package/dist/components/input.d.ts +15 -1
  23. package/dist/components/input.js +16 -2
  24. package/dist/components/input.js.map +1 -1
  25. package/dist/components/menubar.js +1 -1
  26. package/dist/components/menubar.js.map +1 -1
  27. package/dist/components/message-actions.js +1 -1
  28. package/dist/components/message-actions.js.map +1 -1
  29. package/dist/components/pagination.d.ts +104 -3
  30. package/dist/components/pagination.js +244 -58
  31. package/dist/components/pagination.js.map +1 -1
  32. package/dist/components/popover.d.ts +7 -2
  33. package/dist/components/popover.js +7 -2
  34. package/dist/components/popover.js.map +1 -1
  35. package/dist/components/secret-input.js +1 -1
  36. package/dist/components/select.js +1 -1
  37. package/dist/components/select.js.map +1 -1
  38. package/dist/components/sheet.d.ts +6 -1
  39. package/dist/components/sheet.js +2 -2
  40. package/dist/components/sheet.js.map +1 -1
  41. package/dist/components/steps.d.ts +15 -2
  42. package/dist/components/steps.js +68 -22
  43. package/dist/components/steps.js.map +1 -1
  44. package/dist/index.d.ts +1 -0
  45. package/dist/index.js +5 -4
  46. package/dist/mui/index.js +41 -7
  47. package/dist/mui/index.js.map +1 -1
  48. package/dist/styles.css +1 -1
  49. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"data-table.js","names":[],"sources":["../../src/components/data-table.tsx"],"sourcesContent":["import ArrowDown from '@burtson-labs/icons/react/arrow-down';\nimport ArrowUp from '@burtson-labs/icons/react/arrow-up';\nimport ChevronsUpDown from '@burtson-labs/icons/react/chevrons-up-down';\nimport Search from '@burtson-labs/icons/react/search';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { Button } from './button';\nimport { Checkbox } from './checkbox';\nimport { Input } from './input';\nimport { Pagination } from './pagination';\nimport { Skeleton } from './skeleton';\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from './table';\n\nexport interface DataTableColumn<T> {\n id: string;\n header: React.ReactNode;\n cell: (row: T) => React.ReactNode;\n sortable?: boolean;\n /** Right-aligned tabular figures. */\n numeric?: boolean;\n className?: string;\n}\n\nexport type SortDirection = 'asc' | 'desc';\n\nexport interface DataTableSort {\n columnId: string;\n direction: SortDirection;\n}\n\nexport interface DataTableProps<T> extends Omit<React.ComponentProps<'div'>, 'children'> {\n /** Required: what the table lists, e.g. \"Workspace members\". */\n 'aria-label': string;\n columns: DataTableColumn<T>[];\n /** The rows to show now: already sorted, filtered and paged by the app or server. */\n rows: T[];\n getRowId: (row: T) => string;\n /** Names a row for screen readers (\"Select Ada Lovelace\"). Defaults to its id. */\n getRowLabel?: (row: T) => string;\n\n /** Controlled sort. A sortable header cycles ascending, descending, none. */\n sort?: DataTableSort | null;\n onSortChange?: (sort: DataTableSort | null) => void;\n\n /** Controlled filter text; a search box appears when onFilterChange is set. */\n filter?: string;\n onFilterChange?: (value: string) => void;\n filterPlaceholder?: string;\n\n /** Controlled selection by row id; checkboxes appear when onSelectedChange is set. */\n selected?: string[];\n onSelectedChange?: (ids: string[]) => void;\n\n /** Enter or a click on the row, e.g. open the record. */\n onRowAction?: (row: T) => void;\n /** Per-row controls in a trailing column, e.g. a DropdownMenu. */\n rowActions?: (row: T) => React.ReactNode;\n\n /** 1-based; Pagination appears when onPageChange is set. */\n page?: number;\n pageCount?: number;\n onPageChange?: (page: number) => void;\n /** e.g. \"1–25 of 312\". */\n pageSummary?: React.ReactNode;\n\n loading?: boolean;\n /** A message shown in place of the rows. */\n error?: React.ReactNode;\n onRetry?: () => void;\n /** Shown when there are no rows and nothing failed. */\n empty?: React.ReactNode;\n /** Extra controls beside the search box, e.g. filters or a bulk action. */\n toolbar?: React.ReactNode;\n density?: 'compact' | 'default';\n stickyHeader?: boolean;\n}\n\nconst nextSort = (current: DataTableSort | null | undefined, id: string): DataTableSort | null => {\n if (!current || current.columnId !== id) return { columnId: id, direction: 'asc' };\n return current.direction === 'asc' ? { columnId: id, direction: 'desc' } : null;\n};\n\n// Clicks and keys aimed at these belong to them, not to the row.\nconst INTERACTIVE = 'a,button,input,select,textarea,[role=\"checkbox\"],[role=\"menuitem\"]';\n\n/**\n * A table recipe for records: sort, search, select, page, and row actions,\n * with loading, empty and error states. Fully controlled, so the data can\n * come from a server; the table never reorders rows itself.\n */\nfunction DataTable<T>({\n 'aria-label': ariaLabel,\n columns,\n rows,\n getRowId,\n getRowLabel,\n sort,\n onSortChange,\n filter,\n onFilterChange,\n filterPlaceholder = 'Search',\n selected,\n onSelectedChange,\n onRowAction,\n rowActions,\n page,\n pageCount,\n onPageChange,\n pageSummary,\n loading = false,\n error,\n onRetry,\n empty = 'No results.',\n toolbar,\n density = 'default',\n stickyHeader,\n className,\n ...props\n}: DataTableProps<T>) {\n const selectable = Boolean(onSelectedChange);\n const selectedSet = React.useMemo(() => new Set(selected ?? []), [selected]);\n const ids = rows.map(getRowId);\n const pageSelected = ids.filter((id) => selectedSet.has(id)).length;\n const allState: boolean | 'indeterminate' =\n ids.length > 0 && pageSelected === ids.length\n ? true\n : pageSelected > 0\n ? 'indeterminate'\n : false;\n const colCount = columns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0);\n const interactive = Boolean(onRowAction) || selectable;\n\n // One tab stop in the body: the active row. Arrows move it.\n const [active, setActive] = React.useState(0);\n const frameRef = React.useRef<HTMLDivElement>(null);\n // Rows can shrink under the active index (a new page, a filter).\n const activeRow = Math.min(active, Math.max(0, rows.length - 1));\n\n const toggle = (id: string) => {\n if (!onSelectedChange) return;\n const next = new Set(selectedSet);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n onSelectedChange([...next]);\n };\n const toggleAll = () => {\n if (!onSelectedChange) return;\n const next = new Set(selectedSet);\n if (allState === true) ids.forEach((id) => next.delete(id));\n else ids.forEach((id) => next.add(id));\n onSelectedChange([...next]);\n };\n const focusRow = (i: number) => {\n const clamped = Math.min(Math.max(i, 0), rows.length - 1);\n setActive(clamped);\n frameRef.current\n ?.querySelectorAll<HTMLElement>('[data-slot=\"table-body\"] > [data-slot=\"table-row\"]')\n [clamped]?.focus();\n };\n\n const onRowKeyDown = (event: React.KeyboardEvent<HTMLTableRowElement>, i: number, row: T) => {\n if (event.target !== event.currentTarget) return;\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n focusRow(i + 1);\n break;\n case 'ArrowUp':\n event.preventDefault();\n focusRow(i - 1);\n break;\n case 'Home':\n event.preventDefault();\n focusRow(0);\n break;\n case 'End':\n event.preventDefault();\n focusRow(rows.length - 1);\n break;\n case 'Enter':\n if (onRowAction) {\n event.preventDefault();\n onRowAction(row);\n }\n break;\n case ' ':\n if (selectable) {\n event.preventDefault();\n toggle(getRowId(row));\n }\n break;\n }\n };\n\n const showToolbar = Boolean(onFilterChange || toolbar || (selectable && selectedSet.size));\n let body: React.ReactNode;\n if (error) {\n body = (\n <TableRow className=\"hover:bg-transparent\">\n <TableCell colSpan={colCount} className=\"h-auto py-8 text-center whitespace-normal\">\n <div role=\"alert\" className=\"grid justify-items-center gap-3 text-sm\">\n <span className=\"text-destructive\">{error}</span>\n {onRetry && (\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={onRetry}>\n Try again\n </Button>\n )}\n </div>\n </TableCell>\n </TableRow>\n );\n } else if (loading && rows.length === 0) {\n body = Array.from({ length: 3 }, (_, r) => (\n <TableRow key={`loading-${r}`} className=\"hover:bg-transparent\" aria-hidden>\n {Array.from({ length: colCount }, (_, c) => (\n <TableCell key={c}>\n <Skeleton className=\"h-3.5 w-full max-w-40\" />\n </TableCell>\n ))}\n </TableRow>\n ));\n } else if (rows.length === 0) {\n body = (\n <TableRow className=\"hover:bg-transparent\">\n <TableCell\n colSpan={colCount}\n className=\"h-auto py-10 text-center whitespace-normal text-muted-foreground\"\n >\n {empty}\n </TableCell>\n </TableRow>\n );\n } else {\n body = rows.map((row, i) => {\n const id = getRowId(row);\n const isSelected = selectedSet.has(id);\n const label = getRowLabel?.(row) ?? id;\n return (\n <TableRow\n key={id}\n selected={isSelected}\n tabIndex={interactive ? (i === activeRow ? 0 : -1) : undefined}\n onFocus={() => setActive(i)}\n onKeyDown={interactive ? (e) => onRowKeyDown(e, i, row) : undefined}\n onClick={\n onRowAction\n ? (e) => {\n if ((e.target as HTMLElement).closest(INTERACTIVE)) return;\n onRowAction(row);\n }\n : undefined\n }\n className={cn(\n interactive &&\n 'outline-none focus-visible:bg-muted/60 focus-visible:shadow-[inset_2px_0_0_var(--ring)]',\n onRowAction && 'cursor-pointer',\n )}\n >\n {selectable && (\n <TableCell className=\"w-10\">\n <Checkbox\n checked={isSelected}\n onCheckedChange={() => toggle(id)}\n aria-label={`Select ${label}`}\n tabIndex={-1}\n />\n </TableCell>\n )}\n {columns.map((col) => (\n <TableCell key={col.id} numeric={col.numeric} className={col.className}>\n {col.cell(row)}\n </TableCell>\n ))}\n {rowActions && <TableCell className=\"w-12 text-right\">{rowActions(row)}</TableCell>}\n </TableRow>\n );\n });\n }\n\n return (\n <div data-slot=\"data-table\" className={cn('grid min-w-0 gap-3', className)} {...props}>\n {showToolbar && (\n <div className=\"flex flex-wrap items-center gap-2\">\n {onFilterChange && (\n <div className=\"relative w-full max-w-xs min-w-0 flex-1\">\n <Search\n className=\"pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\"\n aria-hidden\n />\n <Input\n type=\"search\"\n value={filter ?? ''}\n onChange={(e) => onFilterChange(e.target.value)}\n placeholder={filterPlaceholder}\n aria-label={`Search ${ariaLabel.toLowerCase()}`}\n className=\"pl-8\"\n />\n </div>\n )}\n {selectable && (\n <span aria-live=\"polite\" className=\"text-xs text-muted-foreground tabular-nums\">\n {selectedSet.size ? `${selectedSet.size} selected` : ''}\n </span>\n )}\n {toolbar && <div className=\"ml-auto flex flex-wrap items-center gap-2\">{toolbar}</div>}\n </div>\n )}\n <div ref={frameRef} className=\"rounded-lg border bg-surface\">\n <Table\n aria-label={ariaLabel}\n scrollLabel={ariaLabel}\n aria-busy={loading || undefined}\n density={density}\n stickyHeader={stickyHeader}\n className={cn(loading && rows.length > 0 && 'opacity-60 transition-opacity')}\n >\n <TableHeader>\n <TableRow className=\"hover:bg-transparent\">\n {selectable && (\n <TableHead className=\"w-10\">\n <Checkbox\n checked={allState}\n onCheckedChange={toggleAll}\n disabled={rows.length === 0}\n aria-label=\"Select all rows on this page\"\n />\n </TableHead>\n )}\n {columns.map((col) => {\n const sorted = sort?.columnId === col.id ? sort.direction : undefined;\n return (\n <TableHead\n key={col.id}\n numeric={col.numeric}\n className={col.className}\n aria-sort={\n col.sortable\n ? sorted === 'asc'\n ? 'ascending'\n : sorted === 'desc'\n ? 'descending'\n : 'none'\n : undefined\n }\n >\n {col.sortable && onSortChange ? (\n <button\n type=\"button\"\n onClick={() => onSortChange(nextSort(sort, col.id))}\n className={cn(\n '-mx-1.5 inline-flex h-7 items-center gap-1 rounded-sm px-1.5 uppercase outline-none hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/20',\n sorted && 'text-foreground',\n col.numeric && 'flex-row-reverse',\n )}\n >\n {col.header}\n {sorted === 'asc' ? (\n <ArrowUp className=\"size-3.5\" aria-hidden />\n ) : sorted === 'desc' ? (\n <ArrowDown className=\"size-3.5\" aria-hidden />\n ) : (\n <ChevronsUpDown className=\"size-3.5 opacity-50\" aria-hidden />\n )}\n </button>\n ) : (\n col.header\n )}\n </TableHead>\n );\n })}\n {rowActions && (\n <TableHead className=\"w-12\">\n <span className=\"sr-only\">Actions</span>\n </TableHead>\n )}\n </TableRow>\n </TableHeader>\n <TableBody>{body}</TableBody>\n </Table>\n </div>\n {onPageChange && page !== undefined && pageCount !== undefined && pageCount > 0 && (\n <Pagination\n page={page}\n pageCount={pageCount}\n onPageChange={onPageChange}\n summary={pageSummary}\n />\n )}\n </div>\n );\n}\n\nexport { DataTable };\n"],"mappings":"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"}
1
+ {"version":3,"file":"data-table.js","names":[],"sources":["../../src/components/data-table.tsx"],"sourcesContent":["import ArrowDown from '@burtson-labs/icons/react/arrow-down';\nimport ArrowUp from '@burtson-labs/icons/react/arrow-up';\nimport ChevronsUpDown from '@burtson-labs/icons/react/chevrons-up-down';\nimport Search from '@burtson-labs/icons/react/search';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { Button } from './button';\nimport { Checkbox } from './checkbox';\nimport { Input } from './input';\nimport { Pagination, pageWindow, paginationSummary, usePagination } from './pagination';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './select';\nimport { Skeleton } from './skeleton';\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from './table';\n\n/**\n * Where a column goes on a phone card: `title` and `subtitle` head the card,\n * `aside` sits top right (a status badge), `field` is a labelled value in a\n * two-column grid, `footer` is a full-width line at the bottom (links,\n * buttons), `hidden` is left off the card.\n */\nexport type DataTableCardSlot = 'title' | 'subtitle' | 'aside' | 'field' | 'footer' | 'hidden';\n\nexport type DataTableBreakpoint = 'sm' | 'md' | 'lg' | 'xl';\n\nexport interface DataTableColumn<T> {\n id: string;\n header: React.ReactNode;\n cell: (row: T) => React.ReactNode;\n sortable?: boolean;\n /** Right-aligned tabular figures. */\n numeric?: boolean;\n className?: string;\n /**\n * Place on a phone card. With no column marked `title`, the first column\n * is the title; every other column is a `field` unless it says otherwise.\n */\n card?: DataTableCardSlot;\n /** The field's label on a card when `header` is not plain text. */\n cardLabel?: string;\n /** A shorter rendering for the card, e.g. a date without the time. */\n cardCell?: (row: T) => React.ReactNode;\n /** Only on cards, never a table column (e.g. a subtitle the table shows in another cell). */\n cardOnly?: boolean;\n /** Leave the column out of the table below this width (tablets). */\n hideBelow?: DataTableBreakpoint;\n}\n\nexport interface DataTablePaginateOptions {\n /** Starting rows per page; the first option by default. */\n pageSize?: number;\n /** 25, 50 and 100 by default. */\n pageSizeOptions?: readonly number[];\n /** Remembers the chosen page size in localStorage under this key. */\n storageKey?: string;\n}\n\nexport type SortDirection = 'asc' | 'desc';\n\nexport interface DataTableSort {\n columnId: string;\n direction: SortDirection;\n}\n\nexport interface DataTableProps<T> extends Omit<React.ComponentProps<'div'>, 'children'> {\n /** Required: what the table lists, e.g. \"Workspace members\". */\n 'aria-label': string;\n columns: DataTableColumn<T>[];\n /** The rows to show now: already sorted, filtered and paged by the app or server. */\n rows: T[];\n getRowId: (row: T) => string;\n /** Names a row for screen readers (\"Select Ada Lovelace\"). Defaults to its id. */\n getRowLabel?: (row: T) => string;\n\n /** Controlled sort. A sortable header cycles ascending, descending, none. */\n sort?: DataTableSort | null;\n onSortChange?: (sort: DataTableSort | null) => void;\n\n /** Controlled filter text; a search box appears when onFilterChange is set. */\n filter?: string;\n onFilterChange?: (value: string) => void;\n filterPlaceholder?: string;\n\n /** Controlled selection by row id; checkboxes appear when onSelectedChange is set. */\n selected?: string[];\n onSelectedChange?: (ids: string[]) => void;\n\n /** Enter or a click on the row, e.g. open the record. */\n onRowAction?: (row: T) => void;\n /** Per-row controls in a trailing column, e.g. a DropdownMenu. */\n rowActions?: (row: T) => React.ReactNode;\n\n /** 1-based; Pagination appears when onPageChange is set. */\n page?: number;\n pageCount?: number;\n onPageChange?: (page: number) => void;\n /** e.g. \"1–25 of 312\". Worked out from `totalRows` and `pageSize` when left out. */\n pageSummary?: React.ReactNode;\n /** Rows per page, for the page-size menu and the summary. */\n pageSize?: number;\n pageSizeOptions?: readonly number[];\n /** Adds a rows-per-page menu beside the pages. */\n onPageSizeChange?: (pageSize: number) => void;\n /** Every row on every page (server paging), for the summary. */\n totalRows?: number;\n /**\n * Page in the browser: pass every row in `rows` and the table shows one\n * page, with a rows-per-page menu. It goes back to page 1 when `filter` or\n * `sort` changes. Leave out to page in your app or on the server.\n */\n paginate?: boolean | DataTablePaginateOptions;\n /** Plural noun appended to the built-in summary: \"1–25 of 312 members\". */\n rowNoun?: string;\n\n loading?: boolean;\n /** A message shown in place of the rows. */\n error?: React.ReactNode;\n onRetry?: () => void;\n /** Shown when there are no rows and nothing failed. */\n empty?: React.ReactNode;\n /** Extra controls beside the search box, e.g. filters or a bulk action. */\n toolbar?: React.ReactNode;\n density?: 'compact' | 'default';\n stickyHeader?: boolean;\n /**\n * Below this width the rows become a list of cards (see DataTableColumn\n * `card`). `md` (768px) by default; `false` keeps the table everywhere.\n */\n cardsBelow?: DataTableBreakpoint | false;\n}\n\nconst BREAKPOINTS: Record<DataTableBreakpoint, number> = { sm: 640, md: 768, lg: 1024, xl: 1280 };\n\nconst hideBelowClass: Record<DataTableBreakpoint, string> = {\n sm: 'hidden sm:table-cell',\n md: 'hidden md:table-cell',\n lg: 'hidden lg:table-cell',\n xl: 'hidden xl:table-cell',\n};\n\nconst subscribeNone = () => () => undefined;\n\n/**\n * True while the viewport is narrower than `bp`. Without matchMedia (server\n * render, tests) it is false, so the table is the fallback.\n */\nfunction useNarrowerThan(bp: DataTableBreakpoint | false): boolean {\n const query = bp ? `(max-width: ${BREAKPOINTS[bp] - 0.02}px)` : null;\n const subscribe = React.useCallback(\n (onChange: () => void) => {\n if (!query || typeof matchMedia !== 'function') return () => undefined;\n const mq = matchMedia(query);\n mq.addEventListener?.('change', onChange);\n return () => mq.removeEventListener?.('change', onChange);\n },\n [query],\n );\n return React.useSyncExternalStore(\n query ? subscribe : subscribeNone,\n () => Boolean(query && typeof matchMedia === 'function' && matchMedia(query).matches),\n () => false,\n );\n}\n\nconst textOf = (node: React.ReactNode): string | undefined =>\n typeof node === 'string' || typeof node === 'number' ? String(node) : undefined;\n\nconst nextSort = (current: DataTableSort | null | undefined, id: string): DataTableSort | null => {\n if (!current || current.columnId !== id) return { columnId: id, direction: 'asc' };\n return current.direction === 'asc' ? { columnId: id, direction: 'desc' } : null;\n};\n\n// Clicks and keys aimed at these belong to them, not to the row.\nconst INTERACTIVE = 'a,button,input,select,textarea,[role=\"checkbox\"],[role=\"menuitem\"]';\n\n/**\n * A table recipe for records: sort, search, select, page, and row actions,\n * with loading, empty and error states. Fully controlled, so the data can\n * come from a server; the table never reorders rows itself. On a phone the\n * rows become cards (`cardsBelow`), with the same columns.\n */\nfunction DataTable<T>({\n 'aria-label': ariaLabel,\n columns,\n rows: rowsProp,\n getRowId,\n getRowLabel,\n sort,\n onSortChange,\n filter,\n onFilterChange,\n filterPlaceholder = 'Search',\n selected,\n onSelectedChange,\n onRowAction,\n rowActions,\n page,\n pageCount,\n onPageChange,\n pageSummary,\n pageSize,\n pageSizeOptions,\n onPageSizeChange,\n totalRows,\n paginate,\n rowNoun,\n loading = false,\n error,\n onRetry,\n empty = 'No results.',\n toolbar,\n density = 'default',\n stickyHeader,\n cardsBelow = 'md',\n className,\n ...props\n}: DataTableProps<T>) {\n const paginateOptions = paginate === true ? {} : paginate || undefined;\n const paging = usePagination(rowsProp, {\n defaultPageSize: paginateOptions?.pageSize,\n pageSizeOptions: paginateOptions?.pageSizeOptions,\n storageKey: paginateOptions?.storageKey,\n // A new search or sort starts again at page 1.\n resetKey: `${filter ?? ''}\\u0000${sort?.columnId ?? ''}\\u0000${sort?.direction ?? ''}`,\n });\n const rows = paginateOptions ? paging.rows : rowsProp;\n const cards = useNarrowerThan(cardsBelow);\n const uid = React.useId();\n\n const selectable = Boolean(onSelectedChange);\n const selectedSet = React.useMemo(() => new Set(selected ?? []), [selected]);\n const ids = rows.map(getRowId);\n const pageSelected = ids.filter((id) => selectedSet.has(id)).length;\n const allState: boolean | 'indeterminate' =\n ids.length > 0 && pageSelected === ids.length\n ? true\n : pageSelected > 0\n ? 'indeterminate'\n : false;\n const tableColumns = columns.filter((c) => !c.cardOnly);\n const colCount = tableColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0);\n const interactive = Boolean(onRowAction) || selectable;\n\n // One tab stop in the body: the active row. Arrows move it.\n const [active, setActive] = React.useState(0);\n const frameRef = React.useRef<HTMLDivElement>(null);\n // Rows can shrink under the active index (a new page, a filter).\n const activeRow = Math.min(active, Math.max(0, rows.length - 1));\n\n const toggle = (id: string) => {\n if (!onSelectedChange) return;\n const next = new Set(selectedSet);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n onSelectedChange([...next]);\n };\n const toggleAll = () => {\n if (!onSelectedChange) return;\n const next = new Set(selectedSet);\n if (allState === true) ids.forEach((id) => next.delete(id));\n else ids.forEach((id) => next.add(id));\n onSelectedChange([...next]);\n };\n const focusRow = (i: number) => {\n const clamped = Math.min(Math.max(i, 0), rows.length - 1);\n setActive(clamped);\n frameRef.current\n ?.querySelectorAll<HTMLElement>('[data-slot=\"table-body\"] > [data-slot=\"table-row\"]')\n [clamped]?.focus();\n };\n\n const onRowKeyDown = (event: React.KeyboardEvent<HTMLTableRowElement>, i: number, row: T) => {\n if (event.target !== event.currentTarget) return;\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n focusRow(i + 1);\n break;\n case 'ArrowUp':\n event.preventDefault();\n focusRow(i - 1);\n break;\n case 'Home':\n event.preventDefault();\n focusRow(0);\n break;\n case 'End':\n event.preventDefault();\n focusRow(rows.length - 1);\n break;\n case 'Enter':\n if (onRowAction) {\n event.preventDefault();\n onRowAction(row);\n }\n break;\n case ' ':\n if (selectable) {\n event.preventDefault();\n toggle(getRowId(row));\n }\n break;\n }\n };\n\n // Headers are gone on cards, so sorting moves to a menu in the toolbar.\n const sortable = onSortChange ? columns.filter((c) => c.sortable) : [];\n const columnLabel = (c: DataTableColumn<T>) => c.cardLabel ?? textOf(c.header) ?? c.id;\n const cardSort =\n cards && sortable.length > 0 && onSortChange ? (\n <Select\n value={sort ? `${sort.columnId}:${sort.direction}` : 'none'}\n onValueChange={(v) => {\n if (v === 'none') return onSortChange(null);\n const [columnId = '', direction] = v.split(':');\n onSortChange({ columnId, direction: direction === 'desc' ? 'desc' : 'asc' });\n }}\n >\n <SelectTrigger aria-label=\"Sort by\" className=\"pointer-coarse:h-11\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent align=\"end\">\n <SelectItem value=\"none\">Default order</SelectItem>\n {sortable.flatMap((c) => [\n <SelectItem key={`${c.id}:asc`} value={`${c.id}:asc`}>\n {columnLabel(c)} ascending\n </SelectItem>,\n <SelectItem key={`${c.id}:desc`} value={`${c.id}:desc`}>\n {columnLabel(c)} descending\n </SelectItem>,\n ])}\n </SelectContent>\n </Select>\n ) : null;\n const cardSelectAll =\n cards && selectable ? (\n <label\n htmlFor={`${uid}-all`}\n className=\"flex min-h-11 cursor-pointer items-center gap-2.5 pr-1 text-sm sm:min-h-9\"\n >\n <Checkbox\n id={`${uid}-all`}\n checked={allState}\n onCheckedChange={toggleAll}\n disabled={rows.length === 0}\n aria-label=\"Select all rows on this page\"\n />\n Select all\n </label>\n ) : null;\n\n const showToolbar = Boolean(\n onFilterChange || toolbar || (selectable && selectedSet.size) || cardSort || cardSelectAll,\n );\n\n const withNoun = (summary: string, total: number) =>\n rowNoun && total ? `${summary} ${rowNoun}` : summary;\n let pager: React.ReactNode = null;\n if (paginateOptions) {\n if (paging.hasPages)\n pager = (\n <Pagination {...paging.paginationProps} summary={withNoun(paging.summary, paging.total)} />\n );\n } else if (onPageChange && page !== undefined && pageCount !== undefined && pageCount > 0) {\n pager = (\n <Pagination\n page={page}\n pageCount={pageCount}\n onPageChange={onPageChange}\n summary={\n pageSummary ??\n (totalRows !== undefined && pageSize\n ? withNoun(\n paginationSummary(pageWindow({ page, pageSize, total: totalRows })),\n totalRows,\n )\n : undefined)\n }\n pageSize={pageSize}\n pageSizeOptions={pageSizeOptions}\n onPageSizeChange={onPageSizeChange}\n />\n );\n }\n\n const toolbarNode = showToolbar && (\n <div className=\"flex flex-wrap items-center gap-2\">\n {onFilterChange && (\n <div className=\"relative min-w-0 basis-full sm:max-w-xs sm:flex-1 sm:basis-0\">\n <Search\n className=\"pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\"\n aria-hidden\n />\n <Input\n type=\"search\"\n value={filter ?? ''}\n onChange={(e) => onFilterChange(e.target.value)}\n placeholder={filterPlaceholder}\n aria-label={`Search ${ariaLabel.toLowerCase()}`}\n className=\"pl-8\"\n />\n </div>\n )}\n {cardSelectAll}\n {selectable && (\n <span aria-live=\"polite\" className=\"text-xs text-muted-foreground tabular-nums\">\n {selectedSet.size ? `${selectedSet.size} selected` : ''}\n </span>\n )}\n {(toolbar || cardSort) && (\n <div className=\"ml-auto flex flex-wrap items-center gap-2\">\n {cardSort}\n {toolbar}\n </div>\n )}\n </div>\n );\n\n return (\n <div\n data-slot=\"data-table\"\n data-layout={cards ? 'cards' : 'table'}\n // One minmax(0,1fr) track: a wide table scrolls inside its frame instead\n // of stretching a grid or flex parent.\n className={cn('grid min-w-0 grid-cols-[minmax(0,1fr)] gap-3', className)}\n {...props}\n >\n {toolbarNode}\n {cards ? (\n <DataTableCards\n aria-label={ariaLabel}\n columns={columns}\n rows={rows}\n getRowId={getRowId}\n getRowLabel={getRowLabel}\n selectedSet={selectedSet}\n onToggle={selectable ? toggle : undefined}\n onRowAction={onRowAction}\n rowActions={rowActions}\n loading={loading}\n error={error}\n onRetry={onRetry}\n empty={empty}\n />\n ) : (\n <div ref={frameRef} className=\"rounded-lg border bg-surface\">\n <Table\n aria-label={ariaLabel}\n scrollLabel={ariaLabel}\n aria-busy={loading || undefined}\n density={density}\n stickyHeader={stickyHeader}\n className={cn(loading && rows.length > 0 && 'opacity-60 transition-opacity')}\n >\n <TableHeader>\n <TableRow className=\"hover:bg-transparent\">\n {selectable && (\n <TableHead className=\"w-10\">\n <Checkbox\n checked={allState}\n onCheckedChange={toggleAll}\n disabled={rows.length === 0}\n aria-label=\"Select all rows on this page\"\n />\n </TableHead>\n )}\n {tableColumns.map((col) => {\n const sorted = sort?.columnId === col.id ? sort.direction : undefined;\n return (\n <TableHead\n key={col.id}\n numeric={col.numeric}\n className={cn(col.hideBelow && hideBelowClass[col.hideBelow], col.className)}\n aria-sort={\n col.sortable\n ? sorted === 'asc'\n ? 'ascending'\n : sorted === 'desc'\n ? 'descending'\n : 'none'\n : undefined\n }\n >\n {col.sortable && onSortChange ? (\n <button\n type=\"button\"\n onClick={() => onSortChange(nextSort(sort, col.id))}\n className={cn(\n '-mx-1.5 inline-flex h-7 items-center gap-1 rounded-sm px-1.5 uppercase outline-none hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/20',\n sorted && 'text-foreground',\n col.numeric && 'flex-row-reverse',\n )}\n >\n {col.header}\n {sorted === 'asc' ? (\n <ArrowUp className=\"size-3.5\" aria-hidden />\n ) : sorted === 'desc' ? (\n <ArrowDown className=\"size-3.5\" aria-hidden />\n ) : (\n <ChevronsUpDown className=\"size-3.5 opacity-50\" aria-hidden />\n )}\n </button>\n ) : (\n col.header\n )}\n </TableHead>\n );\n })}\n {rowActions && (\n <TableHead className=\"w-12\">\n <span className=\"sr-only\">Actions</span>\n </TableHead>\n )}\n </TableRow>\n </TableHeader>\n <TableBody>\n {error ? (\n <TableRow className=\"hover:bg-transparent\">\n <TableCell\n colSpan={colCount}\n className=\"h-auto py-8 text-center whitespace-normal\"\n >\n <ErrorMessage error={error} onRetry={onRetry} />\n </TableCell>\n </TableRow>\n ) : loading && rows.length === 0 ? (\n Array.from({ length: 3 }, (_, r) => (\n <TableRow key={`loading-${r}`} className=\"hover:bg-transparent\" aria-hidden>\n {Array.from({ length: colCount }, (_, c) => (\n <TableCell key={c}>\n <Skeleton className=\"h-3.5 w-full max-w-40\" />\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : rows.length === 0 ? (\n <TableRow className=\"hover:bg-transparent\">\n <TableCell\n colSpan={colCount}\n className=\"h-auto py-10 text-center whitespace-normal text-muted-foreground\"\n >\n {empty}\n </TableCell>\n </TableRow>\n ) : (\n rows.map((row, i) => {\n const id = getRowId(row);\n const isSelected = selectedSet.has(id);\n const label = getRowLabel?.(row) ?? id;\n return (\n <TableRow\n key={id}\n selected={isSelected}\n tabIndex={interactive ? (i === activeRow ? 0 : -1) : undefined}\n onFocus={() => setActive(i)}\n onKeyDown={interactive ? (e) => onRowKeyDown(e, i, row) : undefined}\n onClick={\n onRowAction\n ? (e) => {\n if ((e.target as HTMLElement).closest(INTERACTIVE)) return;\n onRowAction(row);\n }\n : undefined\n }\n className={cn(\n interactive &&\n 'outline-none focus-visible:bg-muted/60 focus-visible:shadow-[inset_2px_0_0_var(--ring)]',\n onRowAction && 'cursor-pointer',\n )}\n >\n {selectable && (\n <TableCell className=\"w-10\">\n <Checkbox\n checked={isSelected}\n onCheckedChange={() => toggle(id)}\n aria-label={`Select ${label}`}\n tabIndex={-1}\n />\n </TableCell>\n )}\n {tableColumns.map((col) => (\n <TableCell\n key={col.id}\n numeric={col.numeric}\n className={cn(\n col.hideBelow && hideBelowClass[col.hideBelow],\n col.className,\n )}\n >\n {col.cell(row)}\n </TableCell>\n ))}\n {rowActions && (\n <TableCell className=\"w-12 text-right\">{rowActions(row)}</TableCell>\n )}\n </TableRow>\n );\n })\n )}\n </TableBody>\n </Table>\n </div>\n )}\n {pager}\n </div>\n );\n}\n\nfunction ErrorMessage({ error, onRetry }: { error: React.ReactNode; onRetry?: () => void }) {\n return (\n <div role=\"alert\" className=\"grid justify-items-center gap-3 text-sm\">\n <span className=\"text-destructive\">{error}</span>\n {onRetry && (\n <Button type=\"button\" size=\"sm\" variant=\"outline\" onClick={onRetry}>\n Try again\n </Button>\n )}\n </div>\n );\n}\n\nconst cardLabelClass =\n 'text-[11px] font-semibold tracking-[0.06em] text-muted-foreground uppercase';\n\n/**\n * The phone layout: a list of articles, one per row, each named by its title.\n * The title is the row's open button (its hit area covers the card); the\n * checkbox, row actions and footer controls sit above it and keep their own\n * clicks. No roving focus: Tab walks the controls, as in any list of links.\n */\nfunction DataTableCards<T>({\n 'aria-label': ariaLabel,\n columns,\n rows,\n getRowId,\n getRowLabel,\n selectedSet,\n onToggle,\n onRowAction,\n rowActions,\n loading,\n error,\n onRetry,\n empty,\n}: {\n 'aria-label': string;\n columns: DataTableColumn<T>[];\n rows: T[];\n getRowId: (row: T) => string;\n getRowLabel?: (row: T) => string;\n selectedSet: Set<string>;\n onToggle?: (id: string) => void;\n onRowAction?: (row: T) => void;\n rowActions?: (row: T) => React.ReactNode;\n loading: boolean;\n error?: React.ReactNode;\n onRetry?: () => void;\n empty: React.ReactNode;\n}) {\n const uid = React.useId();\n if (error)\n return (\n <div className=\"rounded-lg border bg-surface px-4 py-8\">\n <ErrorMessage error={error} onRetry={onRetry} />\n </div>\n );\n if (rows.length === 0 && !loading)\n return (\n <div className=\"rounded-lg border bg-surface px-4 py-10 text-center text-sm text-muted-foreground\">\n {empty}\n </div>\n );\n\n const visible = columns.filter((c) => c.card !== 'hidden');\n // With no column marked as the title, the first unplaced column is it.\n const firstUnplaced = visible.some((c) => c.card === 'title')\n ? undefined\n : visible.find((c) => c.card === undefined);\n const slotOf = (c: DataTableColumn<T>): DataTableCardSlot =>\n c.card ?? (c === firstUnplaced ? 'title' : 'field');\n const inSlot = (s: DataTableCardSlot) => visible.filter((c) => slotOf(c) === s);\n const title = inSlot('title');\n const subtitle = inSlot('subtitle');\n const aside = inSlot('aside');\n const fields = inSlot('field');\n const footer = inSlot('footer');\n const show = (c: DataTableColumn<T>, row: T) => (c.cardCell ?? c.cell)(row);\n\n return (\n // role=\"list\": Safari drops list semantics from a list with no bullets.\n // eslint-disable-next-line jsx-a11y/no-redundant-roles\n <ul\n role=\"list\"\n aria-label={ariaLabel}\n aria-busy={loading || undefined}\n data-slot=\"data-table-cards\"\n className={cn('grid gap-2', loading && rows.length > 0 && 'opacity-60 transition-opacity')}\n >\n {loading && rows.length === 0\n ? Array.from({ length: 3 }, (_, r) => (\n <li\n key={`loading-${r}`}\n aria-hidden\n className=\"grid gap-3 rounded-lg border bg-surface p-3.5\"\n >\n <Skeleton className=\"h-4 w-1/2\" />\n <Skeleton className=\"h-3.5 w-3/4\" />\n </li>\n ))\n : rows.map((row, i) => {\n const id = getRowId(row);\n const label = getRowLabel?.(row) ?? id;\n const isSelected = selectedSet.has(id);\n const titleId = `${uid}-${i}`;\n return (\n <li key={id}>\n <article\n aria-labelledby={title.length ? titleId : undefined}\n aria-label={title.length ? undefined : label}\n data-slot=\"data-table-card\"\n data-state={isSelected ? 'selected' : undefined}\n className={cn(\n 'relative grid gap-3 rounded-lg border bg-surface p-3.5 shadow-xs transition-colors',\n onRowAction &&\n 'hover:bg-muted/40 has-[[data-row-action]:focus-visible]:border-ring has-[[data-row-action]:focus-visible]:inset-ring-1 has-[[data-row-action]:focus-visible]:inset-ring-ring',\n 'data-[state=selected]:border-brand/40 data-[state=selected]:bg-brand-soft/60',\n )}\n >\n <div className=\"flex items-start gap-3\">\n {onToggle && (\n // A 44px target around the 16px box.\n <label\n htmlFor={`${titleId}-select`}\n className=\"relative z-10 -mx-3.5 -my-3 grid size-11 shrink-0 cursor-pointer place-items-center\"\n >\n <Checkbox\n id={`${titleId}-select`}\n checked={isSelected}\n onCheckedChange={() => onToggle(id)}\n aria-label={`Select ${label}`}\n />\n </label>\n )}\n <div className=\"grid min-w-0 flex-1 gap-0.5\">\n {title.map((c, j) => (\n <div\n key={c.id}\n id={j === 0 ? titleId : undefined}\n className=\"min-w-0 text-[15px] leading-5 font-semibold [overflow-wrap:anywhere]\"\n >\n {onRowAction && j === 0 ? (\n <button\n type=\"button\"\n data-row-action=\"\"\n onClick={() => onRowAction(row)}\n className=\"text-left outline-hidden! after:absolute after:inset-0 after:rounded-lg\"\n >\n {show(c, row)}\n </button>\n ) : (\n show(c, row)\n )}\n </div>\n ))}\n </div>\n {aside.length > 0 && (\n <div className=\"relative z-10 flex shrink-0 flex-col items-end gap-1\">\n {aside.map((c) => (\n <div key={c.id}>{show(c, row)}</div>\n ))}\n </div>\n )}\n {rowActions && (\n <div className=\"relative z-10 -my-2.5 -mr-1.5 shrink-0\">\n {rowActions(row)}\n </div>\n )}\n </div>\n {subtitle.length > 0 && (\n // Under the header row, not beside the status, so it gets the card's width.\n <div className={cn('-mt-2 grid min-w-0 gap-0.5', onToggle && 'pl-7')}>\n {subtitle.map((c) => (\n <div\n key={c.id}\n className=\"min-w-0 text-sm text-muted-foreground [overflow-wrap:anywhere]\"\n >\n {show(c, row)}\n </div>\n ))}\n </div>\n )}\n {fields.length > 0 && (\n <dl className=\"grid grid-cols-2 gap-x-4 gap-y-2.5 text-sm\">\n {fields.map((c) => (\n <div key={c.id} className=\"min-w-0\">\n <dt className={cardLabelClass}>{c.cardLabel ?? c.header}</dt>\n <dd\n className={cn(\n 'mt-0.5 min-w-0 [overflow-wrap:anywhere]',\n c.numeric && 'tabular-nums',\n )}\n >\n {show(c, row)}\n </dd>\n </div>\n ))}\n </dl>\n )}\n {footer.map((c) => (\n <div key={c.id} className=\"relative z-10 flex flex-wrap gap-2\">\n {show(c, row)}\n </div>\n ))}\n </article>\n </li>\n );\n })}\n </ul>\n );\n}\n\nexport { DataTable };\n"],"mappings":"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"}
@@ -5,8 +5,13 @@ declare function DialogTrigger(props: React.ComponentProps<typeof DialogPrimitiv
5
5
  declare function DialogClose(props: React.ComponentProps<typeof DialogPrimitive.Close>): React.JSX.Element;
6
6
  declare function DialogPortal(props: React.ComponentProps<typeof DialogPrimitive.Portal>): React.JSX.Element;
7
7
  declare function DialogOverlay({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Overlay>): React.JSX.Element;
8
- declare function DialogContent({ className, children, showCloseButton, ...props }: React.ComponentProps<typeof DialogPrimitive.Content> & {
8
+ declare function DialogContent({ className, children, showCloseButton, mobile, ...props }: React.ComponentProps<typeof DialogPrimitive.Content> & {
9
9
  showCloseButton?: boolean;
10
+ /**
11
+ * `sheet`: on phones (below 640px) the dialog is a bottom sheet, full
12
+ * width with a grab bar. Larger screens keep the centred window.
13
+ */
14
+ mobile?: 'center' | 'sheet';
10
15
  }): React.JSX.Element;
11
16
  declare function DialogHeader({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
12
17
  declare function DialogFooter({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
@@ -35,19 +35,30 @@ function DialogOverlay({ className, ...props }) {
35
35
  ...props
36
36
  });
37
37
  }
38
- function DialogContent({ className, children, showCloseButton = true, ...props }) {
38
+ var bottomSheetClasses = "max-sm:top-auto max-sm:bottom-0 max-sm:left-0 max-sm:w-full max-sm:max-w-none max-sm:translate-x-0 max-sm:translate-y-0 max-sm:max-h-[92dvh] max-sm:rounded-b-none max-sm:border-x-0 max-sm:border-b-0 max-sm:pb-[max(1.25rem,env(safe-area-inset-bottom))] max-sm:[--bl-scale:1] max-sm:[--bl-ty:100%]";
39
+ function DialogContent({ className, children, showCloseButton = true, mobile = "center", ...props }) {
40
+ const sheet = mobile === "sheet";
39
41
  return /* @__PURE__ */ jsxs(DialogPortal, { children: [/* @__PURE__ */ jsx(DialogOverlay, {}), /* @__PURE__ */ jsxs(Dialog.Content, {
40
42
  "data-slot": "dialog-content",
41
- className: cn("fixed top-1/2 left-1/2 z-50 grid [--bl-scale:0.95] [--bl-ty:8px] w-[calc(100%-2rem)] max-w-lg max-h-[calc(100dvh-2rem)] overflow-y-auto overscroll-contain -translate-x-1/2 -translate-y-1/2 gap-5 rounded-xl border border-border-strong bg-surface-raised p-5 text-foreground shadow-[0_24px_80px_rgb(0_0_0_/_0.28)] outline-none data-[state=closed]:animate-out data-[state=open]:animate-in sm:p-6", className),
43
+ "data-mobile": mobile,
44
+ className: cn("fixed top-1/2 left-1/2 z-50 grid [--bl-scale:0.95] [--bl-ty:8px] w-[calc(100%-2rem)] max-w-lg max-h-[calc(100dvh-2rem)] overflow-y-auto overscroll-contain -translate-x-1/2 -translate-y-1/2 gap-5 rounded-xl border border-border-strong bg-surface-raised p-5 text-foreground shadow-[0_24px_80px_rgb(0_0_0_/_0.28)] outline-none data-[state=closed]:animate-out data-[state=open]:animate-in sm:p-6", sheet && bottomSheetClasses, className),
42
45
  ...props,
43
- children: [children, showCloseButton ? /* @__PURE__ */ jsxs(Dialog.Close, {
44
- "data-slot": "dialog-close",
45
- className: "absolute top-3.5 right-3.5 grid size-8 place-items-center rounded-md text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/20 [&_svg]:size-4",
46
- children: [/* @__PURE__ */ jsx(X, { "aria-hidden": true }), /* @__PURE__ */ jsx("span", {
47
- className: "sr-only",
48
- children: "Close"
49
- })]
50
- }) : null]
46
+ children: [
47
+ sheet && /* @__PURE__ */ jsx("div", {
48
+ "data-slot": "dialog-handle",
49
+ "aria-hidden": true,
50
+ className: "mx-auto -mt-2 -mb-3 hidden h-1 w-10 shrink-0 rounded-full bg-border-strong max-sm:block"
51
+ }),
52
+ children,
53
+ showCloseButton ? /* @__PURE__ */ jsxs(Dialog.Close, {
54
+ "data-slot": "dialog-close",
55
+ className: cn("absolute top-3.5 right-3.5 grid size-8 place-items-center rounded-md text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/20 [&_svg]:size-4", sheet && "max-sm:top-3 max-sm:right-3 pointer-coarse:max-sm:size-11"),
56
+ children: [/* @__PURE__ */ jsx(X, { "aria-hidden": true }), /* @__PURE__ */ jsx("span", {
57
+ className: "sr-only",
58
+ children: "Close"
59
+ })]
60
+ }) : null
61
+ ]
51
62
  })] });
52
63
  }
53
64
  function DialogHeader({ className, ...props }) {
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.js","names":["Dialog","DialogPrimitive"],"sources":["../../src/components/dialog.tsx"],"sourcesContent":["import X from '@burtson-labs/icons/react/x';\nimport { Dialog as DialogPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nfunction Dialog(props: React.ComponentProps<typeof DialogPrimitive.Root>) {\n return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />;\n}\n\nfunction DialogTrigger(props: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />;\n}\n\nfunction DialogClose(props: React.ComponentProps<typeof DialogPrimitive.Close>) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />;\n}\n\nfunction DialogPortal(props: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />;\n}\n\nfunction DialogOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n return (\n <DialogPrimitive.Overlay\n data-slot=\"dialog-overlay\"\n className={cn(\n 'fixed inset-0 z-50 bg-black/55 backdrop-blur-[3px] data-[state=closed]:animate-fade-out data-[state=open]:animate-fade-in',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = true,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & { showCloseButton?: boolean }) {\n return (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Content\n data-slot=\"dialog-content\"\n className={cn(\n 'fixed top-1/2 left-1/2 z-50 grid [--bl-scale:0.95] [--bl-ty:8px] w-[calc(100%-2rem)] max-w-lg max-h-[calc(100dvh-2rem)] overflow-y-auto overscroll-contain -translate-x-1/2 -translate-y-1/2 gap-5 rounded-xl border border-border-strong bg-surface-raised p-5 text-foreground shadow-[0_24px_80px_rgb(0_0_0_/_0.28)] outline-none data-[state=closed]:animate-out data-[state=open]:animate-in sm:p-6',\n className,\n )}\n {...props}\n >\n {children}\n {showCloseButton ? (\n <DialogPrimitive.Close\n data-slot=\"dialog-close\"\n className=\"absolute top-3.5 right-3.5 grid size-8 place-items-center rounded-md text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/20 [&_svg]:size-4\"\n >\n <X aria-hidden />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n ) : null}\n </DialogPrimitive.Content>\n </DialogPortal>\n );\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div data-slot=\"dialog-header\" className={cn('grid gap-1.5 pr-7', className)} {...props} />\n );\n}\n\nfunction DialogFooter({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\n 'flex flex-col-reverse gap-2 border-t border-border pt-4 sm:flex-row sm:justify-end',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n className={cn('text-base font-semibold tracking-[-0.02em]', className)}\n {...props}\n />\n );\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn('text-sm leading-5 text-muted-foreground', className)}\n {...props}\n />\n );\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n"],"mappings":";;;;;;AAMA,SAASA,SAAO,OAA0D;CACxE,OAAO,oBAACC,OAAgB,MAAjB;EAAsB,aAAU;EAAS,GAAI;CAAQ,CAAA;AAC9D;AAEA,SAAS,cAAc,OAA6D;CAClF,OAAO,oBAACA,OAAgB,SAAjB;EAAyB,aAAU;EAAiB,GAAI;CAAQ,CAAA;AACzE;AAEA,SAAS,YAAY,OAA2D;CAC9E,OAAO,oBAACA,OAAgB,OAAjB;EAAuB,aAAU;EAAe,GAAI;CAAQ,CAAA;AACrE;AAEA,SAAS,aAAa,OAA4D;CAChF,OAAO,oBAACA,OAAgB,QAAjB;EAAwB,aAAU;EAAgB,GAAI;CAAQ,CAAA;AACvE;AAEA,SAAS,cAAc,EACrB,WACA,GAAG,SACoD;CACvD,OACE,oBAACA,OAAgB,SAAjB;EACE,aAAU;EACV,WAAW,GACT,6HACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,cAAc,EACrB,WACA,UACA,kBAAkB,MAClB,GAAG,SACoF;CACvF,OACE,qBAAC,cAAD,EAAA,UAAA,CACE,oBAAC,eAAD,CAAgB,CAAA,GAChB,qBAACA,OAAgB,SAAjB;EACE,aAAU;EACV,WAAW,GACT,2YACA,SACF;EACA,GAAI;EANN,UAAA,CAQG,UACA,kBACC,qBAACA,OAAgB,OAAjB;GACE,aAAU;GACV,WAAU;GAFZ,UAAA,CAIE,oBAAC,GAAD,EAAG,eAAA,KAAa,CAAA,GAChB,oBAAC,QAAD;IAAM,WAAU;IAAU,UAAA;GAAW,CAAA,CAChB;EACrB,CAAA,IAAA,IACmB;CACb,CAAA,CAAA,EAAA,CAAA;AAElB;AAEA,SAAS,aAAa,EAAE,WAAW,GAAG,SAAsC;CAC1E,OACE,oBAAC,OAAD;EAAK,aAAU;EAAgB,WAAW,GAAG,qBAAqB,SAAS;EAAG,GAAI;CAAQ,CAAA;AAE9F;AAEA,SAAS,aAAa,EAAE,WAAW,GAAG,SAAsC;CAC1E,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,sFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAA6D;CAChG,OACE,oBAACA,OAAgB,OAAjB;EACE,aAAU;EACV,WAAW,GAAG,8CAA8C,SAAS;EACrE,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,kBAAkB,EACzB,WACA,GAAG,SACwD;CAC3D,OACE,oBAACA,OAAgB,aAAjB;EACE,aAAU;EACV,WAAW,GAAG,2CAA2C,SAAS;EAClE,GAAI;CACL,CAAA;AAEL"}
1
+ {"version":3,"file":"dialog.js","names":["Dialog","DialogPrimitive"],"sources":["../../src/components/dialog.tsx"],"sourcesContent":["import X from '@burtson-labs/icons/react/x';\nimport { Dialog as DialogPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nfunction Dialog(props: React.ComponentProps<typeof DialogPrimitive.Root>) {\n return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />;\n}\n\nfunction DialogTrigger(props: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />;\n}\n\nfunction DialogClose(props: React.ComponentProps<typeof DialogPrimitive.Close>) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />;\n}\n\nfunction DialogPortal(props: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />;\n}\n\nfunction DialogOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n return (\n <DialogPrimitive.Overlay\n data-slot=\"dialog-overlay\"\n className={cn(\n 'fixed inset-0 z-50 bg-black/55 backdrop-blur-[3px] data-[state=closed]:animate-fade-out data-[state=open]:animate-fade-in',\n className,\n )}\n {...props}\n />\n );\n}\n\n// Below 640px the dialog docks to the bottom edge, full width, and slides up:\n// thumbs reach its buttons and the keyboard does not cover a centred box.\nconst bottomSheetClasses =\n 'max-sm:top-auto max-sm:bottom-0 max-sm:left-0 max-sm:w-full max-sm:max-w-none max-sm:translate-x-0 max-sm:translate-y-0 max-sm:max-h-[92dvh] max-sm:rounded-b-none max-sm:border-x-0 max-sm:border-b-0 max-sm:pb-[max(1.25rem,env(safe-area-inset-bottom))] max-sm:[--bl-scale:1] max-sm:[--bl-ty:100%]';\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = true,\n mobile = 'center',\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n showCloseButton?: boolean;\n /**\n * `sheet`: on phones (below 640px) the dialog is a bottom sheet, full\n * width with a grab bar. Larger screens keep the centred window.\n */\n mobile?: 'center' | 'sheet';\n}) {\n const sheet = mobile === 'sheet';\n return (\n <DialogPortal>\n <DialogOverlay />\n <DialogPrimitive.Content\n data-slot=\"dialog-content\"\n data-mobile={mobile}\n className={cn(\n 'fixed top-1/2 left-1/2 z-50 grid [--bl-scale:0.95] [--bl-ty:8px] w-[calc(100%-2rem)] max-w-lg max-h-[calc(100dvh-2rem)] overflow-y-auto overscroll-contain -translate-x-1/2 -translate-y-1/2 gap-5 rounded-xl border border-border-strong bg-surface-raised p-5 text-foreground shadow-[0_24px_80px_rgb(0_0_0_/_0.28)] outline-none data-[state=closed]:animate-out data-[state=open]:animate-in sm:p-6',\n sheet && bottomSheetClasses,\n className,\n )}\n {...props}\n >\n {sheet && (\n <div\n data-slot=\"dialog-handle\"\n aria-hidden\n className=\"mx-auto -mt-2 -mb-3 hidden h-1 w-10 shrink-0 rounded-full bg-border-strong max-sm:block\"\n />\n )}\n {children}\n {showCloseButton ? (\n <DialogPrimitive.Close\n data-slot=\"dialog-close\"\n className={cn(\n 'absolute top-3.5 right-3.5 grid size-8 place-items-center rounded-md text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/20 [&_svg]:size-4',\n // 44px on a touch screen when it is a sheet, like Sheet's.\n sheet && 'max-sm:top-3 max-sm:right-3 pointer-coarse:max-sm:size-11',\n )}\n >\n <X aria-hidden />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n ) : null}\n </DialogPrimitive.Content>\n </DialogPortal>\n );\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div data-slot=\"dialog-header\" className={cn('grid gap-1.5 pr-7', className)} {...props} />\n );\n}\n\nfunction DialogFooter({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\n 'flex flex-col-reverse gap-2 border-t border-border pt-4 sm:flex-row sm:justify-end',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n className={cn('text-base font-semibold tracking-[-0.02em]', className)}\n {...props}\n />\n );\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn('text-sm leading-5 text-muted-foreground', className)}\n {...props}\n />\n );\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n"],"mappings":";;;;;;AAMA,SAASA,SAAO,OAA0D;CACxE,OAAO,oBAACC,OAAgB,MAAjB;EAAsB,aAAU;EAAS,GAAI;CAAQ,CAAA;AAC9D;AAEA,SAAS,cAAc,OAA6D;CAClF,OAAO,oBAACA,OAAgB,SAAjB;EAAyB,aAAU;EAAiB,GAAI;CAAQ,CAAA;AACzE;AAEA,SAAS,YAAY,OAA2D;CAC9E,OAAO,oBAACA,OAAgB,OAAjB;EAAuB,aAAU;EAAe,GAAI;CAAQ,CAAA;AACrE;AAEA,SAAS,aAAa,OAA4D;CAChF,OAAO,oBAACA,OAAgB,QAAjB;EAAwB,aAAU;EAAgB,GAAI;CAAQ,CAAA;AACvE;AAEA,SAAS,cAAc,EACrB,WACA,GAAG,SACoD;CACvD,OACE,oBAACA,OAAgB,SAAjB;EACE,aAAU;EACV,WAAW,GACT,6HACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAIA,IAAM,qBACJ;AAEF,SAAS,cAAc,EACrB,WACA,UACA,kBAAkB,MAClB,SAAS,UACT,GAAG,SAQF;CACD,MAAM,QAAQ,WAAW;CACzB,OACE,qBAAC,cAAD,EAAA,UAAA,CACE,oBAAC,eAAD,CAAgB,CAAA,GAChB,qBAACA,OAAgB,SAAjB;EACE,aAAU;EACV,eAAa;EACb,WAAW,GACT,2YACA,SAAS,oBACT,SACF;EACA,GAAI;EARN,UAAA;GAUG,SACC,oBAAC,OAAD;IACE,aAAU;IACV,eAAA;IACA,WAAU;GACX,CAAA;GAEF;GACA,kBACC,qBAACA,OAAgB,OAAjB;IACE,aAAU;IACV,WAAW,GACT,qOAEA,SAAS,2DACX;IANF,UAAA,CAQE,oBAAC,GAAD,EAAG,eAAA,KAAa,CAAA,GAChB,oBAAC,QAAD;KAAM,WAAU;KAAU,UAAA;IAAW,CAAA,CAChB;GACrB,CAAA,IAAA;EACmB;CACb,CAAA,CAAA,EAAA,CAAA;AAElB;AAEA,SAAS,aAAa,EAAE,WAAW,GAAG,SAAsC;CAC1E,OACE,oBAAC,OAAD;EAAK,aAAU;EAAgB,WAAW,GAAG,qBAAqB,SAAS;EAAG,GAAI;CAAQ,CAAA;AAE9F;AAEA,SAAS,aAAa,EAAE,WAAW,GAAG,SAAsC;CAC1E,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,sFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAA6D;CAChG,OACE,oBAACA,OAAgB,OAAjB;EACE,aAAU;EACV,WAAW,GAAG,8CAA8C,SAAS;EACrE,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,kBAAkB,EACzB,WACA,GAAG,SACwD;CAC3D,OACE,oBAACA,OAAgB,aAAjB;EACE,aAAU;EACV,WAAW,GAAG,2CAA2C,SAAS;EAClE,GAAI;CACL,CAAA;AAEL"}
@@ -105,7 +105,7 @@ function DropdownMenuSubTrigger({ className, inset, children, ...props }) {
105
105
  return /* @__PURE__ */ jsxs(DropdownMenu.SubTrigger, {
106
106
  "data-slot": "dropdown-menu-sub-trigger",
107
107
  "data-inset": inset || void 0,
108
- className: cn(menuItemClasses, "data-[state=open]:bg-muted", className),
108
+ className: cn(menuItemClasses, "data-[state=open]:bg-secondary", className),
109
109
  ...props,
110
110
  children: [children, /* @__PURE__ */ jsx(ChevronRight, {
111
111
  className: "ml-auto size-4",
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown-menu.js","names":["DropdownMenu","DropdownMenuPrimitive","itemClasses"],"sources":["../../src/components/dropdown-menu.tsx"],"sourcesContent":["import Check from '@burtson-labs/icons/react/check';\nimport ChevronRight from '@burtson-labs/icons/react/chevron-right';\nimport { DropdownMenu as DropdownMenuPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { menuItemClasses as itemClasses, surfaceClasses } from './popover';\n\nfunction DropdownMenu(props: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n return <DropdownMenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />;\n}\n\nfunction DropdownMenuTrigger(props: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n return <DropdownMenuPrimitive.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />;\n}\n\nfunction DropdownMenuGroup(props: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {\n return <DropdownMenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />;\n}\n\nfunction DropdownMenuContent({\n className,\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n data-slot=\"dropdown-menu-content\"\n sideOffset={sideOffset}\n className={cn(\n surfaceClasses,\n 'max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto p-1',\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = 'default',\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n variant?: 'default' | 'destructive';\n}) {\n return (\n <DropdownMenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n data-inset={inset || undefined}\n data-variant={variant}\n className={cn(\n itemClasses,\n 'data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:*:[svg]:!text-destructive',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {\n return (\n <DropdownMenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n className={cn(itemClasses, 'pl-8', className)}\n checked={checked}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Check className=\"size-4 text-foreground\" aria-hidden />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n );\n}\n\nfunction DropdownMenuRadioGroup(\n props: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>,\n) {\n return <DropdownMenuPrimitive.RadioGroup data-slot=\"dropdown-menu-radio-group\" {...props} />;\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {\n return (\n <DropdownMenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n className={cn(itemClasses, 'pl-8', className)}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <span className=\"block size-2 rounded-full bg-foreground\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n );\n}\n\nfunction DropdownMenuLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }) {\n return (\n <DropdownMenuPrimitive.Label\n data-slot=\"dropdown-menu-label\"\n data-inset={inset || undefined}\n className={cn(\n 'px-2 pt-2 pb-1 text-[11px] font-semibold tracking-[0.08em] text-muted-foreground uppercase data-[inset]:pl-8',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n return (\n <DropdownMenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n className={cn('-mx-1 my-1 h-px bg-border', className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuShortcut({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSub(props: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n return <DropdownMenuPrimitive.Sub data-slot=\"dropdown-menu-sub\" {...props} />;\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }) {\n return (\n <DropdownMenuPrimitive.SubTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset || undefined}\n className={cn(itemClasses, 'data-[state=open]:bg-muted', className)}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto size-4\" aria-hidden />\n </DropdownMenuPrimitive.SubTrigger>\n );\n}\n\nfunction DropdownMenuSubContent({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.SubContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\n surfaceClasses,\n 'min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden p-1',\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n}\n\nexport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"dropdown-menu.js","names":["DropdownMenu","DropdownMenuPrimitive","itemClasses"],"sources":["../../src/components/dropdown-menu.tsx"],"sourcesContent":["import Check from '@burtson-labs/icons/react/check';\nimport ChevronRight from '@burtson-labs/icons/react/chevron-right';\nimport { DropdownMenu as DropdownMenuPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { menuItemClasses as itemClasses, surfaceClasses } from './popover';\n\nfunction DropdownMenu(props: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n return <DropdownMenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />;\n}\n\nfunction DropdownMenuTrigger(props: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n return <DropdownMenuPrimitive.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />;\n}\n\nfunction DropdownMenuGroup(props: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {\n return <DropdownMenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />;\n}\n\nfunction DropdownMenuContent({\n className,\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n data-slot=\"dropdown-menu-content\"\n sideOffset={sideOffset}\n className={cn(\n surfaceClasses,\n 'max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto p-1',\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = 'default',\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n variant?: 'default' | 'destructive';\n}) {\n return (\n <DropdownMenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n data-inset={inset || undefined}\n data-variant={variant}\n className={cn(\n itemClasses,\n 'data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:*:[svg]:!text-destructive',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {\n return (\n <DropdownMenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n className={cn(itemClasses, 'pl-8', className)}\n checked={checked}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Check className=\"size-4 text-foreground\" aria-hidden />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n );\n}\n\nfunction DropdownMenuRadioGroup(\n props: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>,\n) {\n return <DropdownMenuPrimitive.RadioGroup data-slot=\"dropdown-menu-radio-group\" {...props} />;\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {\n return (\n <DropdownMenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n className={cn(itemClasses, 'pl-8', className)}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <span className=\"block size-2 rounded-full bg-foreground\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n );\n}\n\nfunction DropdownMenuLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }) {\n return (\n <DropdownMenuPrimitive.Label\n data-slot=\"dropdown-menu-label\"\n data-inset={inset || undefined}\n className={cn(\n 'px-2 pt-2 pb-1 text-[11px] font-semibold tracking-[0.08em] text-muted-foreground uppercase data-[inset]:pl-8',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n return (\n <DropdownMenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n className={cn('-mx-1 my-1 h-px bg-border', className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuShortcut({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSub(props: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n return <DropdownMenuPrimitive.Sub data-slot=\"dropdown-menu-sub\" {...props} />;\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }) {\n return (\n <DropdownMenuPrimitive.SubTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset || undefined}\n className={cn(itemClasses, 'data-[state=open]:bg-secondary', className)}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto size-4\" aria-hidden />\n </DropdownMenuPrimitive.SubTrigger>\n );\n}\n\nfunction DropdownMenuSubContent({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.SubContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\n surfaceClasses,\n 'min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden p-1',\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n}\n\nexport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n};\n"],"mappings":"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"}
@@ -1,4 +1,18 @@
1
1
  import * as React from 'react';
2
- export declare const fieldClasses = "w-full min-w-0 rounded-md border border-input bg-surface px-3 text-base sm:text-sm text-foreground shadow-xs outline-none transition-[border-color,box-shadow,background-color] placeholder:text-muted-foreground/80 hover:border-border-strong focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:border-brand focus-visible:ring-[3px] focus-visible:ring-ring/15 disabled:cursor-not-allowed disabled:bg-muted disabled:opacity-60 aria-invalid:border-destructive aria-invalid:ring-destructive/15 dark:bg-surface-raised";
2
+ /**
3
+ * Keyboard focus for anything that is a text field, or a box that contains
4
+ * one (Composer, a bordered Command): the border turns the ring colour and a
5
+ * 1px inset ring doubles it to 2px. It sits inside the border box, so it
6
+ * follows the radius exactly and no overflow can clip it. The outline is
7
+ * suppressed with !important: an app's unlayered `:focus-visible { outline }`
8
+ * would otherwise beat the utilities layer and draw a second, offset box.
9
+ * outline-hidden keeps a transparent outline, which forced-colors mode shows.
10
+ */
11
+ export declare const fieldFocusClasses = "outline-hidden! focus-visible:border-ring focus-visible:inset-ring-1 focus-visible:inset-ring-ring aria-invalid:focus-visible:inset-ring-destructive";
12
+ /**
13
+ * Fields and field-like triggers: 10px radius (radius-md). Popovers are 12px
14
+ * (radius-lg) and their rows 8px (radius-sm: 12px less the 4px inset).
15
+ */
16
+ export declare const fieldClasses = "w-full min-w-0 rounded-md border border-input bg-surface px-3 text-base sm:text-sm text-foreground shadow-xs transition-[border-color,box-shadow,background-color] placeholder:text-muted-foreground/80 hover:border-border-strong outline-hidden! focus-visible:border-ring focus-visible:inset-ring-1 focus-visible:inset-ring-ring aria-invalid:focus-visible:inset-ring-destructive disabled:cursor-not-allowed disabled:bg-muted disabled:opacity-60 aria-invalid:border-destructive dark:bg-surface-raised";
3
17
  declare const Input: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
4
18
  export { Input };
@@ -2,7 +2,21 @@ import { cn } from "../lib/utils.js";
2
2
  import * as React from "react";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  //#region src/components/input.tsx
5
- var fieldClasses = "w-full min-w-0 rounded-md border border-input bg-surface px-3 text-base sm:text-sm text-foreground shadow-xs outline-none transition-[border-color,box-shadow,background-color] placeholder:text-muted-foreground/80 hover:border-border-strong focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:border-brand focus-visible:ring-[3px] focus-visible:ring-ring/15 disabled:cursor-not-allowed disabled:bg-muted disabled:opacity-60 aria-invalid:border-destructive aria-invalid:ring-destructive/15 dark:bg-surface-raised";
5
+ /**
6
+ * Keyboard focus for anything that is a text field, or a box that contains
7
+ * one (Composer, a bordered Command): the border turns the ring colour and a
8
+ * 1px inset ring doubles it to 2px. It sits inside the border box, so it
9
+ * follows the radius exactly and no overflow can clip it. The outline is
10
+ * suppressed with !important: an app's unlayered `:focus-visible { outline }`
11
+ * would otherwise beat the utilities layer and draw a second, offset box.
12
+ * outline-hidden keeps a transparent outline, which forced-colors mode shows.
13
+ */
14
+ var fieldFocusClasses = "outline-hidden! focus-visible:border-ring focus-visible:inset-ring-1 focus-visible:inset-ring-ring aria-invalid:focus-visible:inset-ring-destructive";
15
+ /**
16
+ * Fields and field-like triggers: 10px radius (radius-md). Popovers are 12px
17
+ * (radius-lg) and their rows 8px (radius-sm: 12px less the 4px inset).
18
+ */
19
+ var fieldClasses = `w-full min-w-0 rounded-md border border-input bg-surface px-3 text-base sm:text-sm text-foreground shadow-xs transition-[border-color,box-shadow,background-color] placeholder:text-muted-foreground/80 hover:border-border-strong ${fieldFocusClasses} disabled:cursor-not-allowed disabled:bg-muted disabled:opacity-60 aria-invalid:border-destructive dark:bg-surface-raised`;
6
20
  var Input = React.forwardRef(function Input({ className, type, ...props }, ref) {
7
21
  return /* @__PURE__ */ jsx("input", {
8
22
  ref,
@@ -13,6 +27,6 @@ var Input = React.forwardRef(function Input({ className, type, ...props }, ref)
13
27
  });
14
28
  });
15
29
  //#endregion
16
- export { Input, fieldClasses };
30
+ export { Input, fieldClasses, fieldFocusClasses };
17
31
 
18
32
  //# sourceMappingURL=input.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"input.js","names":[],"sources":["../../src/components/input.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nexport const fieldClasses =\n 'w-full min-w-0 rounded-md border border-input bg-surface px-3 text-base sm:text-sm text-foreground shadow-xs outline-none transition-[border-color,box-shadow,background-color] placeholder:text-muted-foreground/80 hover:border-border-strong focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:border-brand focus-visible:ring-[3px] focus-visible:ring-ring/15 disabled:cursor-not-allowed disabled:bg-muted disabled:opacity-60 aria-invalid:border-destructive aria-invalid:ring-destructive/15 dark:bg-surface-raised';\n\nconst Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(function Input(\n { className, type, ...props }: React.ComponentProps<'input'>,\n ref,\n) {\n return (\n <input\n ref={ref}\n type={type}\n data-slot=\"input\"\n className={cn(\n fieldClasses,\n 'h-9 py-1.5 file:mr-3 file:border-0 file:bg-transparent file:text-sm file:font-semibold file:text-foreground',\n className,\n )}\n {...props}\n />\n );\n});\n\nexport { Input };\n"],"mappings":";;;;AAIA,IAAa,eACX;AAEF,IAAM,QAAQ,MAAM,WAA4D,SAAS,MACvF,EAAE,WAAW,MAAM,GAAG,SACtB,KACA;CACA,OACE,oBAAC,SAAD;EACO;EACC;EACN,aAAU;EACV,WAAW,GACT,cACA,+GACA,SACF;EACA,GAAI;CACL,CAAA;AAEL,CAAC"}
1
+ {"version":3,"file":"input.js","names":[],"sources":["../../src/components/input.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\n/**\n * Keyboard focus for anything that is a text field, or a box that contains\n * one (Composer, a bordered Command): the border turns the ring colour and a\n * 1px inset ring doubles it to 2px. It sits inside the border box, so it\n * follows the radius exactly and no overflow can clip it. The outline is\n * suppressed with !important: an app's unlayered `:focus-visible { outline }`\n * would otherwise beat the utilities layer and draw a second, offset box.\n * outline-hidden keeps a transparent outline, which forced-colors mode shows.\n */\nexport const fieldFocusClasses =\n 'outline-hidden! focus-visible:border-ring focus-visible:inset-ring-1 focus-visible:inset-ring-ring aria-invalid:focus-visible:inset-ring-destructive';\n\n/**\n * Fields and field-like triggers: 10px radius (radius-md). Popovers are 12px\n * (radius-lg) and their rows 8px (radius-sm: 12px less the 4px inset).\n */\nexport const fieldClasses = `w-full min-w-0 rounded-md border border-input bg-surface px-3 text-base sm:text-sm text-foreground shadow-xs transition-[border-color,box-shadow,background-color] placeholder:text-muted-foreground/80 hover:border-border-strong ${fieldFocusClasses} disabled:cursor-not-allowed disabled:bg-muted disabled:opacity-60 aria-invalid:border-destructive dark:bg-surface-raised`;\n\nconst Input = React.forwardRef<HTMLInputElement, React.ComponentProps<'input'>>(function Input(\n { className, type, ...props }: React.ComponentProps<'input'>,\n ref,\n) {\n return (\n <input\n ref={ref}\n type={type}\n data-slot=\"input\"\n className={cn(\n fieldClasses,\n 'h-9 py-1.5 file:mr-3 file:border-0 file:bg-transparent file:text-sm file:font-semibold file:text-foreground',\n className,\n )}\n {...props}\n />\n );\n});\n\nexport { Input };\n"],"mappings":";;;;;;;;;;;;;AAaA,IAAa,oBACX;;;;;AAMF,IAAa,eAAe,sOAAsO,kBAAkB;AAEpR,IAAM,QAAQ,MAAM,WAA4D,SAAS,MACvF,EAAE,WAAW,MAAM,GAAG,SACtB,KACA;CACA,OACE,oBAAC,SAAD;EACO;EACC;EACN,aAAU;EACV,WAAW,GACT,cACA,+GACA,SACF;EACA,GAAI;CACL,CAAA;AAEL,CAAC"}
@@ -119,7 +119,7 @@ function MenubarSubTrigger({ className, inset, children, ...props }) {
119
119
  return /* @__PURE__ */ jsxs(Menubar.SubTrigger, {
120
120
  "data-slot": "menubar-sub-trigger",
121
121
  "data-inset": inset || void 0,
122
- className: cn(menuItemClasses, "data-[state=open]:bg-muted", className),
122
+ className: cn(menuItemClasses, "data-[state=open]:bg-secondary", className),
123
123
  ...props,
124
124
  children: [children, /* @__PURE__ */ jsx(ChevronRight, {
125
125
  className: "ml-auto size-4",
@@ -1 +1 @@
1
- {"version":3,"file":"menubar.js","names":["Menubar","MenubarPrimitive","itemClasses"],"sources":["../../src/components/menubar.tsx"],"sourcesContent":["import Check from '@burtson-labs/icons/react/check';\nimport ChevronRight from '@burtson-labs/icons/react/chevron-right';\nimport { Menubar as MenubarPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { menuItemClasses as itemClasses, surfaceClasses } from './popover';\n\n/**\n * An application menu bar (File, Edit, View). Left/Right move between menus,\n * Down opens one, and an open menu follows the pointer across triggers. Rows\n * match DropdownMenu and ContextMenu.\n */\nfunction Menubar({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.Root>) {\n return (\n <MenubarPrimitive.Root\n data-slot=\"menubar\"\n className={cn('flex h-8 items-center gap-0.5 rounded-md border bg-surface p-0.5', className)}\n {...props}\n />\n );\n}\n\nfunction MenubarMenu(props: React.ComponentProps<typeof MenubarPrimitive.Menu>) {\n return <MenubarPrimitive.Menu data-slot=\"menubar-menu\" {...props} />;\n}\n\nfunction MenubarTrigger({\n className,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) {\n return (\n <MenubarPrimitive.Trigger\n data-slot=\"menubar-trigger\"\n className={cn(\n 'flex h-7 items-center rounded-sm px-2.5 text-[13px] font-medium outline-none select-none hover:bg-muted focus-visible:shadow-[inset_0_0_0_1px_var(--ring)] data-[state=open]:bg-muted',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MenubarGroup(props: React.ComponentProps<typeof MenubarPrimitive.Group>) {\n return <MenubarPrimitive.Group data-slot=\"menubar-group\" {...props} />;\n}\n\nfunction MenubarContent({\n className,\n align = 'start',\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Content>) {\n return (\n <MenubarPrimitive.Portal>\n <MenubarPrimitive.Content\n data-slot=\"menubar-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(\n surfaceClasses,\n 'max-h-(--radix-menubar-content-available-height) min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-x-hidden overflow-y-auto p-1',\n className,\n )}\n {...props}\n />\n </MenubarPrimitive.Portal>\n );\n}\n\nfunction MenubarItem({\n className,\n inset,\n variant = 'default',\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Item> & {\n inset?: boolean;\n variant?: 'default' | 'destructive';\n}) {\n return (\n <MenubarPrimitive.Item\n data-slot=\"menubar-item\"\n data-inset={inset || undefined}\n data-variant={variant}\n className={cn(\n itemClasses,\n 'data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:*:[svg]:!text-destructive',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MenubarCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) {\n return (\n <MenubarPrimitive.CheckboxItem\n data-slot=\"menubar-checkbox-item\"\n className={cn(itemClasses, 'pl-8', className)}\n checked={checked}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <MenubarPrimitive.ItemIndicator>\n <Check className=\"size-4 text-foreground\" aria-hidden />\n </MenubarPrimitive.ItemIndicator>\n </span>\n {children}\n </MenubarPrimitive.CheckboxItem>\n );\n}\n\nfunction MenubarRadioGroup(props: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {\n return <MenubarPrimitive.RadioGroup data-slot=\"menubar-radio-group\" {...props} />;\n}\n\nfunction MenubarRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) {\n return (\n <MenubarPrimitive.RadioItem\n data-slot=\"menubar-radio-item\"\n className={cn(itemClasses, 'pl-8', className)}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <MenubarPrimitive.ItemIndicator>\n <span className=\"block size-2 rounded-full bg-foreground\" />\n </MenubarPrimitive.ItemIndicator>\n </span>\n {children}\n </MenubarPrimitive.RadioItem>\n );\n}\n\nfunction MenubarLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Label> & { inset?: boolean }) {\n return (\n <MenubarPrimitive.Label\n data-slot=\"menubar-label\"\n data-inset={inset || undefined}\n className={cn(\n 'px-2 pt-2 pb-1 text-[11px] font-semibold tracking-[0.08em] text-muted-foreground uppercase data-[inset]:pl-8',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MenubarSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Separator>) {\n return (\n <MenubarPrimitive.Separator\n data-slot=\"menubar-separator\"\n className={cn('-mx-1 my-1 h-px bg-border', className)}\n {...props}\n />\n );\n}\n\nfunction MenubarShortcut({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"menubar-shortcut\"\n className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}\n {...props}\n />\n );\n}\n\nfunction MenubarSub(props: React.ComponentProps<typeof MenubarPrimitive.Sub>) {\n return <MenubarPrimitive.Sub data-slot=\"menubar-sub\" {...props} />;\n}\n\nfunction MenubarSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & { inset?: boolean }) {\n return (\n <MenubarPrimitive.SubTrigger\n data-slot=\"menubar-sub-trigger\"\n data-inset={inset || undefined}\n className={cn(itemClasses, 'data-[state=open]:bg-muted', className)}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto size-4\" aria-hidden />\n </MenubarPrimitive.SubTrigger>\n );\n}\n\nfunction MenubarSubContent({\n className,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.SubContent>) {\n return (\n <MenubarPrimitive.Portal>\n <MenubarPrimitive.SubContent\n data-slot=\"menubar-sub-content\"\n className={cn(\n surfaceClasses,\n 'min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden p-1',\n className,\n )}\n {...props}\n />\n </MenubarPrimitive.Portal>\n );\n}\n\nexport {\n Menubar,\n MenubarMenu,\n MenubarCheckboxItem,\n MenubarContent,\n MenubarGroup,\n MenubarItem,\n MenubarLabel,\n MenubarRadioGroup,\n MenubarRadioItem,\n MenubarSeparator,\n MenubarShortcut,\n MenubarSub,\n MenubarSubContent,\n MenubarSubTrigger,\n MenubarTrigger,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"menubar.js","names":["Menubar","MenubarPrimitive","itemClasses"],"sources":["../../src/components/menubar.tsx"],"sourcesContent":["import Check from '@burtson-labs/icons/react/check';\nimport ChevronRight from '@burtson-labs/icons/react/chevron-right';\nimport { Menubar as MenubarPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { menuItemClasses as itemClasses, surfaceClasses } from './popover';\n\n/**\n * An application menu bar (File, Edit, View). Left/Right move between menus,\n * Down opens one, and an open menu follows the pointer across triggers. Rows\n * match DropdownMenu and ContextMenu.\n */\nfunction Menubar({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.Root>) {\n return (\n <MenubarPrimitive.Root\n data-slot=\"menubar\"\n className={cn('flex h-8 items-center gap-0.5 rounded-md border bg-surface p-0.5', className)}\n {...props}\n />\n );\n}\n\nfunction MenubarMenu(props: React.ComponentProps<typeof MenubarPrimitive.Menu>) {\n return <MenubarPrimitive.Menu data-slot=\"menubar-menu\" {...props} />;\n}\n\nfunction MenubarTrigger({\n className,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) {\n return (\n <MenubarPrimitive.Trigger\n data-slot=\"menubar-trigger\"\n className={cn(\n 'flex h-7 items-center rounded-sm px-2.5 text-[13px] font-medium outline-none select-none hover:bg-muted focus-visible:shadow-[inset_0_0_0_1px_var(--ring)] data-[state=open]:bg-muted',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MenubarGroup(props: React.ComponentProps<typeof MenubarPrimitive.Group>) {\n return <MenubarPrimitive.Group data-slot=\"menubar-group\" {...props} />;\n}\n\nfunction MenubarContent({\n className,\n align = 'start',\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Content>) {\n return (\n <MenubarPrimitive.Portal>\n <MenubarPrimitive.Content\n data-slot=\"menubar-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(\n surfaceClasses,\n 'max-h-(--radix-menubar-content-available-height) min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-x-hidden overflow-y-auto p-1',\n className,\n )}\n {...props}\n />\n </MenubarPrimitive.Portal>\n );\n}\n\nfunction MenubarItem({\n className,\n inset,\n variant = 'default',\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Item> & {\n inset?: boolean;\n variant?: 'default' | 'destructive';\n}) {\n return (\n <MenubarPrimitive.Item\n data-slot=\"menubar-item\"\n data-inset={inset || undefined}\n data-variant={variant}\n className={cn(\n itemClasses,\n 'data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:*:[svg]:!text-destructive',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MenubarCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) {\n return (\n <MenubarPrimitive.CheckboxItem\n data-slot=\"menubar-checkbox-item\"\n className={cn(itemClasses, 'pl-8', className)}\n checked={checked}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <MenubarPrimitive.ItemIndicator>\n <Check className=\"size-4 text-foreground\" aria-hidden />\n </MenubarPrimitive.ItemIndicator>\n </span>\n {children}\n </MenubarPrimitive.CheckboxItem>\n );\n}\n\nfunction MenubarRadioGroup(props: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {\n return <MenubarPrimitive.RadioGroup data-slot=\"menubar-radio-group\" {...props} />;\n}\n\nfunction MenubarRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) {\n return (\n <MenubarPrimitive.RadioItem\n data-slot=\"menubar-radio-item\"\n className={cn(itemClasses, 'pl-8', className)}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <MenubarPrimitive.ItemIndicator>\n <span className=\"block size-2 rounded-full bg-foreground\" />\n </MenubarPrimitive.ItemIndicator>\n </span>\n {children}\n </MenubarPrimitive.RadioItem>\n );\n}\n\nfunction MenubarLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Label> & { inset?: boolean }) {\n return (\n <MenubarPrimitive.Label\n data-slot=\"menubar-label\"\n data-inset={inset || undefined}\n className={cn(\n 'px-2 pt-2 pb-1 text-[11px] font-semibold tracking-[0.08em] text-muted-foreground uppercase data-[inset]:pl-8',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MenubarSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Separator>) {\n return (\n <MenubarPrimitive.Separator\n data-slot=\"menubar-separator\"\n className={cn('-mx-1 my-1 h-px bg-border', className)}\n {...props}\n />\n );\n}\n\nfunction MenubarShortcut({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"menubar-shortcut\"\n className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}\n {...props}\n />\n );\n}\n\nfunction MenubarSub(props: React.ComponentProps<typeof MenubarPrimitive.Sub>) {\n return <MenubarPrimitive.Sub data-slot=\"menubar-sub\" {...props} />;\n}\n\nfunction MenubarSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & { inset?: boolean }) {\n return (\n <MenubarPrimitive.SubTrigger\n data-slot=\"menubar-sub-trigger\"\n data-inset={inset || undefined}\n className={cn(itemClasses, 'data-[state=open]:bg-secondary', className)}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto size-4\" aria-hidden />\n </MenubarPrimitive.SubTrigger>\n );\n}\n\nfunction MenubarSubContent({\n className,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.SubContent>) {\n return (\n <MenubarPrimitive.Portal>\n <MenubarPrimitive.SubContent\n data-slot=\"menubar-sub-content\"\n className={cn(\n surfaceClasses,\n 'min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden p-1',\n className,\n )}\n {...props}\n />\n </MenubarPrimitive.Portal>\n );\n}\n\nexport {\n Menubar,\n MenubarMenu,\n MenubarCheckboxItem,\n MenubarContent,\n MenubarGroup,\n MenubarItem,\n MenubarLabel,\n MenubarRadioGroup,\n MenubarRadioItem,\n MenubarSeparator,\n MenubarShortcut,\n MenubarSub,\n MenubarSubContent,\n MenubarSubTrigger,\n MenubarTrigger,\n};\n"],"mappings":"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"}
@@ -99,7 +99,7 @@ function MessageEditor({ defaultValue, onSubmit, onCancel, submitLabel = "Send",
99
99
  send();
100
100
  }
101
101
  },
102
- className: "field-sizing-content max-h-60 min-h-16 w-full resize-none rounded-lg border border-brand bg-surface px-3 py-2 text-base leading-6 ring-[3px] ring-ring/15 outline-none sm:text-sm"
102
+ className: "field-sizing-content max-h-60 min-h-16 w-full resize-none rounded-lg border border-ring bg-surface px-3 py-2 text-base leading-6 inset-ring-1 inset-ring-ring outline-hidden! sm:text-sm"
103
103
  }), /* @__PURE__ */ jsxs("div", {
104
104
  className: "flex justify-end gap-2",
105
105
  children: [/* @__PURE__ */ jsx(Button, {
@@ -1 +1 @@
1
- {"version":3,"file":"message-actions.js","names":["_Fragment"],"sources":["../../src/components/message-actions.tsx"],"sourcesContent":["import Edit from '@burtson-labs/icons/react/edit';\nimport FileText from '@burtson-labs/icons/react/file-text';\nimport RotateCcw from '@burtson-labs/icons/react/rotate-ccw';\nimport ThumbsDown from '@burtson-labs/icons/react/thumbs-down';\nimport ThumbsUp from '@burtson-labs/icons/react/thumbs-up';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { formatBytes } from './attachment';\nimport { VoiceMessage } from './audio-player';\nimport { Button } from './button';\nimport { CopyButton } from './copy-button';\nimport { IconButton } from './icon-button';\n\nexport type MessageFeedback = 'up' | 'down' | null;\n\nexport interface MessageActionsProps extends React.ComponentProps<'div'> {\n /** Text for the copy button; leave out to hide it. */\n copyText?: string;\n onRegenerate?: () => void;\n /** Edit a sent message (user turns). Pair with MessageEditor. */\n onEdit?: () => void;\n /** The current rating; controlled. */\n feedback?: MessageFeedback;\n /** Adds thumbs up and down. Clicking the chosen one again clears it (null). */\n onFeedback?: (value: MessageFeedback) => void;\n}\n\n/**\n * The row under a message: copy, regenerate, edit and a thumbs rating, as\n * small icon buttons. Pass it to Message's `actions`, which shows it on\n * hover and focus (always on touch screens).\n */\nfunction MessageActions({\n copyText,\n onRegenerate,\n onEdit,\n feedback = null,\n onFeedback,\n className,\n ...props\n}: MessageActionsProps) {\n const small = 'size-7 text-muted-foreground hover:text-foreground pointer-coarse:size-10';\n return (\n <div\n data-slot=\"message-actions\"\n role=\"toolbar\"\n aria-label=\"Message actions\"\n className={cn('flex items-center gap-0.5', className)}\n {...props}\n >\n {copyText !== undefined && (\n <CopyButton value={copyText} label=\"Copy message\" className={small} />\n )}\n {onEdit && (\n <IconButton\n variant=\"ghost\"\n size=\"icon-sm\"\n label=\"Edit message\"\n onClick={onEdit}\n className={small}\n >\n <Edit />\n </IconButton>\n )}\n {onRegenerate && (\n <IconButton\n variant=\"ghost\"\n size=\"icon-sm\"\n label=\"Regenerate response\"\n onClick={onRegenerate}\n className={small}\n >\n <RotateCcw />\n </IconButton>\n )}\n {onFeedback && (\n <>\n <IconButton\n variant=\"ghost\"\n size=\"icon-sm\"\n label=\"Good response\"\n aria-pressed={feedback === 'up'}\n onClick={() => onFeedback(feedback === 'up' ? null : 'up')}\n className={cn(small, feedback === 'up' && 'text-brand hover:text-brand')}\n >\n <ThumbsUp className={cn(feedback === 'up' && 'fill-current')} />\n </IconButton>\n <IconButton\n variant=\"ghost\"\n size=\"icon-sm\"\n label=\"Bad response\"\n aria-pressed={feedback === 'down'}\n onClick={() => onFeedback(feedback === 'down' ? null : 'down')}\n className={cn(small, feedback === 'down' && 'text-foreground')}\n >\n <ThumbsDown className={cn(feedback === 'down' && 'fill-current')} />\n </IconButton>\n </>\n )}\n </div>\n );\n}\n\nexport interface MessageEditorProps extends Omit<React.ComponentProps<'form'>, 'onSubmit'> {\n /** The text being edited. */\n defaultValue: string;\n /** Save and send the edited message again. */\n onSubmit: (text: string) => void;\n onCancel: () => void;\n submitLabel?: string;\n}\n\n/**\n * Edit-and-resend in place of a sent message. Enter sends (never mid-IME\n * composition), Shift+Enter adds a line, Escape cancels.\n */\nfunction MessageEditor({\n defaultValue,\n onSubmit,\n onCancel,\n submitLabel = 'Send',\n className,\n ...props\n}: MessageEditorProps) {\n const [value, setValue] = React.useState(defaultValue);\n const send = () => {\n if (value.trim()) onSubmit(value.trim());\n };\n return (\n <form\n data-slot=\"message-editor\"\n onSubmit={(e) => {\n e.preventDefault();\n send();\n }}\n className={cn('grid w-full max-w-[85%] gap-2 justify-self-end', className)}\n {...props}\n >\n <textarea\n aria-label=\"Edit message\"\n value={value}\n // eslint-disable-next-line jsx-a11y/no-autofocus -- editing was just asked for\n autoFocus\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={(e) => {\n if (e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229) return;\n if (e.key === 'Escape') {\n e.preventDefault();\n onCancel();\n } else if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n send();\n }\n }}\n className=\"field-sizing-content max-h-60 min-h-16 w-full resize-none rounded-lg border border-brand bg-surface px-3 py-2 text-base leading-6 ring-[3px] ring-ring/15 outline-none sm:text-sm\"\n />\n <div className=\"flex justify-end gap-2\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onCancel}>\n Cancel\n </Button>\n <Button type=\"submit\" size=\"sm\" disabled={!value.trim()}>\n {submitLabel}\n </Button>\n </div>\n </form>\n );\n}\n\nexport interface MessageFile {\n name: string;\n /** Bytes. */\n size?: number;\n /** MIME type; audio renders a player, images a thumbnail. */\n type?: string;\n /** Where to open or play it. */\n href?: string;\n /** Waveform peaks for audio (see computePeaks). */\n peaks?: number[];\n /** Seconds, for audio. */\n duration?: number;\n /** Transcript for audio. */\n transcript?: React.ReactNode;\n}\n\nexport interface MessageAttachmentsProps extends React.ComponentProps<'div'> {\n files: MessageFile[];\n}\n\n/**\n * Files sent with a message: voice notes play inline, images show a\n * thumbnail, anything else is a named chip that opens the file.\n */\nfunction MessageAttachments({ files, className, ...props }: MessageAttachmentsProps) {\n if (!files.length) return null;\n return (\n <div\n data-slot=\"message-attachments\"\n className={cn('flex flex-wrap gap-2', className)}\n {...props}\n >\n {files.map((f, i) => {\n const type = f.type ?? '';\n if (type.startsWith('audio/') && f.href) {\n return (\n <VoiceMessage\n key={`${f.name}-${i}`}\n src={f.href}\n peaks={f.peaks}\n duration={f.duration}\n transcript={f.transcript}\n title={f.name}\n />\n );\n }\n if (type.startsWith('image/') && f.href) {\n return (\n <a\n key={`${f.name}-${i}`}\n href={f.href}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"block overflow-hidden rounded-lg border outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n >\n <img src={f.href} alt={f.name} className=\"h-28 w-auto max-w-56 object-cover\" />\n </a>\n );\n }\n const chip = (\n <>\n <FileText aria-hidden className=\"size-4 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 truncate\">{f.name}</span>\n {f.size !== undefined && (\n <span className=\"shrink-0 text-xs text-muted-foreground\">{formatBytes(f.size)}</span>\n )}\n </>\n );\n const chipClass =\n 'inline-flex max-w-64 items-center gap-2 rounded-md border bg-surface px-2.5 py-1.5 text-sm';\n return f.href ? (\n <a\n key={`${f.name}-${i}`}\n href={f.href}\n target=\"_blank\"\n rel=\"noreferrer\"\n className={cn(\n chipClass,\n 'outline-none hover:bg-muted focus-visible:ring-[3px] focus-visible:ring-ring/20',\n )}\n >\n {chip}\n </a>\n ) : (\n <span key={`${f.name}-${i}`} className={chipClass}>\n {chip}\n </span>\n );\n })}\n </div>\n );\n}\n\nexport { MessageActions, MessageAttachments, MessageEditor };\n"],"mappings":"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"}
1
+ {"version":3,"file":"message-actions.js","names":["_Fragment"],"sources":["../../src/components/message-actions.tsx"],"sourcesContent":["import Edit from '@burtson-labs/icons/react/edit';\nimport FileText from '@burtson-labs/icons/react/file-text';\nimport RotateCcw from '@burtson-labs/icons/react/rotate-ccw';\nimport ThumbsDown from '@burtson-labs/icons/react/thumbs-down';\nimport ThumbsUp from '@burtson-labs/icons/react/thumbs-up';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { formatBytes } from './attachment';\nimport { VoiceMessage } from './audio-player';\nimport { Button } from './button';\nimport { CopyButton } from './copy-button';\nimport { IconButton } from './icon-button';\n\nexport type MessageFeedback = 'up' | 'down' | null;\n\nexport interface MessageActionsProps extends React.ComponentProps<'div'> {\n /** Text for the copy button; leave out to hide it. */\n copyText?: string;\n onRegenerate?: () => void;\n /** Edit a sent message (user turns). Pair with MessageEditor. */\n onEdit?: () => void;\n /** The current rating; controlled. */\n feedback?: MessageFeedback;\n /** Adds thumbs up and down. Clicking the chosen one again clears it (null). */\n onFeedback?: (value: MessageFeedback) => void;\n}\n\n/**\n * The row under a message: copy, regenerate, edit and a thumbs rating, as\n * small icon buttons. Pass it to Message's `actions`, which shows it on\n * hover and focus (always on touch screens).\n */\nfunction MessageActions({\n copyText,\n onRegenerate,\n onEdit,\n feedback = null,\n onFeedback,\n className,\n ...props\n}: MessageActionsProps) {\n const small = 'size-7 text-muted-foreground hover:text-foreground pointer-coarse:size-10';\n return (\n <div\n data-slot=\"message-actions\"\n role=\"toolbar\"\n aria-label=\"Message actions\"\n className={cn('flex items-center gap-0.5', className)}\n {...props}\n >\n {copyText !== undefined && (\n <CopyButton value={copyText} label=\"Copy message\" className={small} />\n )}\n {onEdit && (\n <IconButton\n variant=\"ghost\"\n size=\"icon-sm\"\n label=\"Edit message\"\n onClick={onEdit}\n className={small}\n >\n <Edit />\n </IconButton>\n )}\n {onRegenerate && (\n <IconButton\n variant=\"ghost\"\n size=\"icon-sm\"\n label=\"Regenerate response\"\n onClick={onRegenerate}\n className={small}\n >\n <RotateCcw />\n </IconButton>\n )}\n {onFeedback && (\n <>\n <IconButton\n variant=\"ghost\"\n size=\"icon-sm\"\n label=\"Good response\"\n aria-pressed={feedback === 'up'}\n onClick={() => onFeedback(feedback === 'up' ? null : 'up')}\n className={cn(small, feedback === 'up' && 'text-brand hover:text-brand')}\n >\n <ThumbsUp className={cn(feedback === 'up' && 'fill-current')} />\n </IconButton>\n <IconButton\n variant=\"ghost\"\n size=\"icon-sm\"\n label=\"Bad response\"\n aria-pressed={feedback === 'down'}\n onClick={() => onFeedback(feedback === 'down' ? null : 'down')}\n className={cn(small, feedback === 'down' && 'text-foreground')}\n >\n <ThumbsDown className={cn(feedback === 'down' && 'fill-current')} />\n </IconButton>\n </>\n )}\n </div>\n );\n}\n\nexport interface MessageEditorProps extends Omit<React.ComponentProps<'form'>, 'onSubmit'> {\n /** The text being edited. */\n defaultValue: string;\n /** Save and send the edited message again. */\n onSubmit: (text: string) => void;\n onCancel: () => void;\n submitLabel?: string;\n}\n\n/**\n * Edit-and-resend in place of a sent message. Enter sends (never mid-IME\n * composition), Shift+Enter adds a line, Escape cancels.\n */\nfunction MessageEditor({\n defaultValue,\n onSubmit,\n onCancel,\n submitLabel = 'Send',\n className,\n ...props\n}: MessageEditorProps) {\n const [value, setValue] = React.useState(defaultValue);\n const send = () => {\n if (value.trim()) onSubmit(value.trim());\n };\n return (\n <form\n data-slot=\"message-editor\"\n onSubmit={(e) => {\n e.preventDefault();\n send();\n }}\n className={cn('grid w-full max-w-[85%] gap-2 justify-self-end', className)}\n {...props}\n >\n <textarea\n aria-label=\"Edit message\"\n value={value}\n // eslint-disable-next-line jsx-a11y/no-autofocus -- editing was just asked for\n autoFocus\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={(e) => {\n if (e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229) return;\n if (e.key === 'Escape') {\n e.preventDefault();\n onCancel();\n } else if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n send();\n }\n }}\n className=\"field-sizing-content max-h-60 min-h-16 w-full resize-none rounded-lg border border-ring bg-surface px-3 py-2 text-base leading-6 inset-ring-1 inset-ring-ring outline-hidden! sm:text-sm\"\n />\n <div className=\"flex justify-end gap-2\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onCancel}>\n Cancel\n </Button>\n <Button type=\"submit\" size=\"sm\" disabled={!value.trim()}>\n {submitLabel}\n </Button>\n </div>\n </form>\n );\n}\n\nexport interface MessageFile {\n name: string;\n /** Bytes. */\n size?: number;\n /** MIME type; audio renders a player, images a thumbnail. */\n type?: string;\n /** Where to open or play it. */\n href?: string;\n /** Waveform peaks for audio (see computePeaks). */\n peaks?: number[];\n /** Seconds, for audio. */\n duration?: number;\n /** Transcript for audio. */\n transcript?: React.ReactNode;\n}\n\nexport interface MessageAttachmentsProps extends React.ComponentProps<'div'> {\n files: MessageFile[];\n}\n\n/**\n * Files sent with a message: voice notes play inline, images show a\n * thumbnail, anything else is a named chip that opens the file.\n */\nfunction MessageAttachments({ files, className, ...props }: MessageAttachmentsProps) {\n if (!files.length) return null;\n return (\n <div\n data-slot=\"message-attachments\"\n className={cn('flex flex-wrap gap-2', className)}\n {...props}\n >\n {files.map((f, i) => {\n const type = f.type ?? '';\n if (type.startsWith('audio/') && f.href) {\n return (\n <VoiceMessage\n key={`${f.name}-${i}`}\n src={f.href}\n peaks={f.peaks}\n duration={f.duration}\n transcript={f.transcript}\n title={f.name}\n />\n );\n }\n if (type.startsWith('image/') && f.href) {\n return (\n <a\n key={`${f.name}-${i}`}\n href={f.href}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"block overflow-hidden rounded-lg border outline-none focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n >\n <img src={f.href} alt={f.name} className=\"h-28 w-auto max-w-56 object-cover\" />\n </a>\n );\n }\n const chip = (\n <>\n <FileText aria-hidden className=\"size-4 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 truncate\">{f.name}</span>\n {f.size !== undefined && (\n <span className=\"shrink-0 text-xs text-muted-foreground\">{formatBytes(f.size)}</span>\n )}\n </>\n );\n const chipClass =\n 'inline-flex max-w-64 items-center gap-2 rounded-md border bg-surface px-2.5 py-1.5 text-sm';\n return f.href ? (\n <a\n key={`${f.name}-${i}`}\n href={f.href}\n target=\"_blank\"\n rel=\"noreferrer\"\n className={cn(\n chipClass,\n 'outline-none hover:bg-muted focus-visible:ring-[3px] focus-visible:ring-ring/20',\n )}\n >\n {chip}\n </a>\n ) : (\n <span key={`${f.name}-${i}`} className={chipClass}>\n {chip}\n </span>\n );\n })}\n </div>\n );\n}\n\nexport { MessageActions, MessageAttachments, MessageEditor };\n"],"mappings":"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"}