@burtson-labs/ui 0.12.4 → 0.13.1

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.
package/README.md CHANGED
@@ -58,7 +58,7 @@ npx shadcn@latest add https://ui.burtson.ai/r/button.json
58
58
 
59
59
  ## <picture><source media="(prefers-color-scheme: dark)" srcset="https://icons.burtson.ai/svg-white/panel-grid.svg"/><img src="https://icons.burtson.ai/svg-black/panel-grid.svg" align="center" alt=""/></picture> Components
60
60
 
61
- Accordion · Alert · Alert Dialog · App Shell · Attachment · Audio Player · Avatar · Badge · Breadcrumb · Button · Card · Chat History · Chat Layout · Checkbox · Collapsible · Combobox · Command · Composer · Connection Status · Context Menu · Conversation · Copy Button · Data Table · Dialog · Dropdown Menu · Editor Tabs · Empty State · Field · Icon Button · Input · Kbd · Label · Markdown · Menubar · Message · Message Actions · Mobile Nav · Navigation Menu · Onboarding Checklist · Page Header · Pagination · Popover · Progress · Radio Group · Reasoning · Resizable · Scroll Area · Secret Input · Select · Separator · Sheet · Skeleton · Slider · Source · Spinner · Stat Card · Status · Steps · Switch · Table · Tabs · Textarea · Toast · Toaster · Tool Call · Toolbar · Tooltip · Tour · Tree View · Voice Recorder
61
+ Accordion · Alert · Alert Dialog · App Shell · Attachment · Audio Player · Avatar · Badge · Breadcrumb · Button · Card · Chat History · Chat Layout · Checkbox · Checkbox Card · Collapsible · Combobox · Command · Composer · Connection Status · Context Menu · Conversation · Copy Button · Data Table · Dialog · Dropdown Menu · Editor Tabs · Empty State · Field · Icon Button · Input · Kbd · Label · Markdown · Menubar · Message · Message Actions · Mobile Nav · Navigation Menu · Onboarding Checklist · Page Header · Pagination · Popover · Progress · Radio Group · Reasoning · Resizable · Scroll Area · Secret Input · Select · Separator · Sheet · Skeleton · Slider · Source · Spinner · Stat Card · Status · Steps · Switch · Table · Tabs · Textarea · Toast · Toaster · Tool Call · Toolbar · Tooltip · Tour · Tree View · Voice Recorder
62
62
 
63
63
  Live previews and code for each one are at [ui.burtson.ai](https://ui.burtson.ai/docs/components/button). Building a chat app? The [chat recipe](https://ui.burtson.ai/docs/recipes/chat) puts history, attachments, streaming, voice notes and full screen together, with the complete source.
64
64
 
@@ -0,0 +1,25 @@
1
+ import { Checkbox as CheckboxPrimitive } from 'radix-ui';
2
+ import * as React from 'react';
3
+ export interface CheckboxCardProps extends Omit<React.ComponentProps<typeof CheckboxPrimitive.Root>, 'title' | 'children'> {
4
+ /** The option's name. */
5
+ title: React.ReactNode;
6
+ /** A sentence under the name: what choosing it means. */
7
+ description?: React.ReactNode;
8
+ /** Extra classes for the card (the label); className goes to the checkbox. */
9
+ cardClassName?: string;
10
+ }
11
+ /**
12
+ * A checkbox with a title and a sentence, where the whole card is the hit
13
+ * area (44px or taller). For choices that need explaining: roles,
14
+ * permissions, notification types. One focus ring, on the card.
15
+ */
16
+ declare function CheckboxCard({ title, description, id: idProp, disabled, className, cardClassName, ...props }: CheckboxCardProps): React.JSX.Element;
17
+ export interface CheckboxCardGroupProps extends React.ComponentProps<'fieldset'> {
18
+ /** The group's name, shown as its legend. */
19
+ label: React.ReactNode;
20
+ /** Help under the legend. */
21
+ description?: React.ReactNode;
22
+ }
23
+ /** A fieldset of CheckboxCards with a visible legend. `disabled` disables every card. */
24
+ declare function CheckboxCardGroup({ label, description, className, children, ...props }: CheckboxCardGroupProps): React.JSX.Element;
25
+ export { CheckboxCard, CheckboxCardGroup };
@@ -0,0 +1,65 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { Checkbox as Checkbox$1 } from "./checkbox.js";
3
+ import "radix-ui";
4
+ import * as React from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/components/checkbox-card.tsx
7
+ /**
8
+ * A checkbox with a title and a sentence, where the whole card is the hit
9
+ * area (44px or taller). For choices that need explaining: roles,
10
+ * permissions, notification types. One focus ring, on the card.
11
+ */
12
+ function CheckboxCard({ title, description, id: idProp, disabled, className, cardClassName, ...props }) {
13
+ const auto = React.useId();
14
+ const id = idProp ?? auto;
15
+ return /* @__PURE__ */ jsxs("label", {
16
+ htmlFor: id,
17
+ "data-slot": "checkbox-card",
18
+ className: cn("flex min-h-11 cursor-pointer items-start gap-3 rounded-md border border-border bg-surface px-3 py-2.5 transition-colors hover:border-border-strong", "has-[[data-state=checked]]:border-brand/40 has-[[data-state=checked]]:bg-brand-soft/50", "has-[:focus-visible]:border-ring has-[:focus-visible]:inset-ring-1 has-[:focus-visible]:inset-ring-ring", "has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-60 has-[:disabled]:hover:border-border", cardClassName),
19
+ children: [/* @__PURE__ */ jsx(Checkbox$1, {
20
+ id,
21
+ disabled,
22
+ "aria-labelledby": `${id}-title`,
23
+ "aria-describedby": description ? `${id}-description` : void 0,
24
+ className: cn("mt-0.5 outline-hidden! focus-visible:ring-0 focus-visible:outline-none", className),
25
+ ...props
26
+ }), /* @__PURE__ */ jsxs("span", {
27
+ className: "grid min-w-0 gap-0.5",
28
+ children: [/* @__PURE__ */ jsx("span", {
29
+ id: `${id}-title`,
30
+ className: "text-sm leading-5 font-medium",
31
+ children: title
32
+ }), description && /* @__PURE__ */ jsx("span", {
33
+ id: `${id}-description`,
34
+ className: "text-[13px] leading-5 text-muted-foreground",
35
+ children: description
36
+ })]
37
+ })]
38
+ });
39
+ }
40
+ /** A fieldset of CheckboxCards with a visible legend. `disabled` disables every card. */
41
+ function CheckboxCardGroup({ label, description, className, children, ...props }) {
42
+ const id = React.useId();
43
+ return /* @__PURE__ */ jsxs("fieldset", {
44
+ "data-slot": "checkbox-card-group",
45
+ "aria-describedby": description ? `${id}-description` : void 0,
46
+ className: cn("grid min-w-0 gap-2", className),
47
+ ...props,
48
+ children: [
49
+ /* @__PURE__ */ jsx("legend", {
50
+ className: "mb-1.5 text-sm font-medium",
51
+ children: label
52
+ }),
53
+ description && /* @__PURE__ */ jsx("p", {
54
+ id: `${id}-description`,
55
+ className: "-mt-1.5 text-[13px] text-muted-foreground",
56
+ children: description
57
+ }),
58
+ children
59
+ ]
60
+ });
61
+ }
62
+ //#endregion
63
+ export { CheckboxCard, CheckboxCardGroup };
64
+
65
+ //# sourceMappingURL=checkbox-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkbox-card.js","names":["Checkbox"],"sources":["../../src/components/checkbox-card.tsx"],"sourcesContent":["import { Checkbox as CheckboxPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { Checkbox } from './checkbox';\n\nexport interface CheckboxCardProps extends Omit<\n React.ComponentProps<typeof CheckboxPrimitive.Root>,\n 'title' | 'children'\n> {\n /** The option's name. */\n title: React.ReactNode;\n /** A sentence under the name: what choosing it means. */\n description?: React.ReactNode;\n /** Extra classes for the card (the label); className goes to the checkbox. */\n cardClassName?: string;\n}\n\n/**\n * A checkbox with a title and a sentence, where the whole card is the hit\n * area (44px or taller). For choices that need explaining: roles,\n * permissions, notification types. One focus ring, on the card.\n */\nfunction CheckboxCard({\n title,\n description,\n id: idProp,\n disabled,\n className,\n cardClassName,\n ...props\n}: CheckboxCardProps) {\n const auto = React.useId();\n const id = idProp ?? auto;\n return (\n <label\n htmlFor={id}\n data-slot=\"checkbox-card\"\n className={cn(\n 'flex min-h-11 cursor-pointer items-start gap-3 rounded-md border border-border bg-surface px-3 py-2.5 transition-colors hover:border-border-strong',\n 'has-[[data-state=checked]]:border-brand/40 has-[[data-state=checked]]:bg-brand-soft/50',\n 'has-[:focus-visible]:border-ring has-[:focus-visible]:inset-ring-1 has-[:focus-visible]:inset-ring-ring',\n // :disabled also catches a disabled fieldset around the card.\n 'has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-60 has-[:disabled]:hover:border-border',\n cardClassName,\n )}\n >\n <Checkbox\n id={id}\n disabled={disabled}\n aria-labelledby={`${id}-title`}\n aria-describedby={description ? `${id}-description` : undefined}\n className={cn(\n 'mt-0.5 outline-hidden! focus-visible:ring-0 focus-visible:outline-none',\n className,\n )}\n {...props}\n />\n <span className=\"grid min-w-0 gap-0.5\">\n <span id={`${id}-title`} className=\"text-sm leading-5 font-medium\">\n {title}\n </span>\n {description && (\n <span id={`${id}-description`} className=\"text-[13px] leading-5 text-muted-foreground\">\n {description}\n </span>\n )}\n </span>\n </label>\n );\n}\n\nexport interface CheckboxCardGroupProps extends React.ComponentProps<'fieldset'> {\n /** The group's name, shown as its legend. */\n label: React.ReactNode;\n /** Help under the legend. */\n description?: React.ReactNode;\n}\n\n/** A fieldset of CheckboxCards with a visible legend. `disabled` disables every card. */\nfunction CheckboxCardGroup({\n label,\n description,\n className,\n children,\n ...props\n}: CheckboxCardGroupProps) {\n const id = React.useId();\n return (\n <fieldset\n data-slot=\"checkbox-card-group\"\n aria-describedby={description ? `${id}-description` : undefined}\n className={cn('grid min-w-0 gap-2', className)}\n {...props}\n >\n <legend className=\"mb-1.5 text-sm font-medium\">{label}</legend>\n {description && (\n <p id={`${id}-description`} className=\"-mt-1.5 text-[13px] text-muted-foreground\">\n {description}\n </p>\n )}\n {children}\n </fieldset>\n );\n}\n\nexport { CheckboxCard, CheckboxCardGroup };\n"],"mappings":";;;;;;;;;;;AAwBA,SAAS,aAAa,EACpB,OACA,aACA,IAAI,QACJ,UACA,WACA,eACA,GAAG,SACiB;CACpB,MAAM,OAAO,MAAM,MAAM;CACzB,MAAM,KAAK,UAAU;CACrB,OACE,qBAAC,SAAD;EACE,SAAS;EACT,aAAU;EACV,WAAW,GACT,sJACA,0FACA,2GAEA,qGACA,aACF;EAVF,UAAA,CAYE,oBAACA,YAAD;GACM;GACM;GACV,mBAAiB,GAAG,GAAG;GACvB,oBAAkB,cAAc,GAAG,GAAG,gBAAgB,KAAA;GACtD,WAAW,GACT,0EACA,SACF;GACA,GAAI;EACL,CAAA,GACD,qBAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CACE,oBAAC,QAAD;IAAM,IAAI,GAAG,GAAG;IAAS,WAAU;IAChC,UAAA;GACG,CAAA,GACL,eACC,oBAAC,QAAD;IAAM,IAAI,GAAG,GAAG;IAAe,WAAU;IACtC,UAAA;GACG,CAAA,CAEJ;EACD,CAAA,CAAA;;AAEX;;AAUA,SAAS,kBAAkB,EACzB,OACA,aACA,WACA,UACA,GAAG,SACsB;CACzB,MAAM,KAAK,MAAM,MAAM;CACvB,OACE,qBAAC,YAAD;EACE,aAAU;EACV,oBAAkB,cAAc,GAAG,GAAG,gBAAgB,KAAA;EACtD,WAAW,GAAG,sBAAsB,SAAS;EAC7C,GAAI;EAJN,UAAA;GAME,oBAAC,UAAD;IAAQ,WAAU;IAA8B,UAAA;GAAc,CAAA;GAC7D,eACC,oBAAC,KAAD;IAAG,IAAI,GAAG,GAAG;IAAe,WAAU;IACnC,UAAA;GACA,CAAA;GAEJ;EACO;;AAEd"}
@@ -1,4 +1,12 @@
1
1
  import * as React from 'react';
2
+ /**
3
+ * Where a column goes on a phone card: `title` and `subtitle` head the card,
4
+ * `aside` sits top right (a status badge), `field` is a labelled value in a
5
+ * two-column grid, `footer` is a full-width line at the bottom (links,
6
+ * buttons), `hidden` is left off the card.
7
+ */
8
+ export type DataTableCardSlot = 'title' | 'subtitle' | 'aside' | 'field' | 'footer' | 'hidden';
9
+ export type DataTableBreakpoint = 'sm' | 'md' | 'lg' | 'xl';
2
10
  export interface DataTableColumn<T> {
3
11
  id: string;
4
12
  header: React.ReactNode;
@@ -7,6 +15,27 @@ export interface DataTableColumn<T> {
7
15
  /** Right-aligned tabular figures. */
8
16
  numeric?: boolean;
9
17
  className?: string;
18
+ /**
19
+ * Place on a phone card. With no column marked `title`, the first column
20
+ * is the title; every other column is a `field` unless it says otherwise.
21
+ */
22
+ card?: DataTableCardSlot;
23
+ /** The field's label on a card when `header` is not plain text. */
24
+ cardLabel?: string;
25
+ /** A shorter rendering for the card, e.g. a date without the time. */
26
+ cardCell?: (row: T) => React.ReactNode;
27
+ /** Only on cards, never a table column (e.g. a subtitle the table shows in another cell). */
28
+ cardOnly?: boolean;
29
+ /** Leave the column out of the table below this width (tablets). */
30
+ hideBelow?: DataTableBreakpoint;
31
+ }
32
+ export interface DataTablePaginateOptions {
33
+ /** Starting rows per page; the first option by default. */
34
+ pageSize?: number;
35
+ /** 25, 50 and 100 by default. */
36
+ pageSizeOptions?: readonly number[];
37
+ /** Remembers the chosen page size in localStorage under this key. */
38
+ storageKey?: string;
10
39
  }
11
40
  export type SortDirection = 'asc' | 'desc';
12
41
  export interface DataTableSort {
@@ -40,8 +69,23 @@ export interface DataTableProps<T> extends Omit<React.ComponentProps<'div'>, 'ch
40
69
  page?: number;
41
70
  pageCount?: number;
42
71
  onPageChange?: (page: number) => void;
43
- /** e.g. "1–25 of 312". */
72
+ /** e.g. "1–25 of 312". Worked out from `totalRows` and `pageSize` when left out. */
44
73
  pageSummary?: React.ReactNode;
74
+ /** Rows per page, for the page-size menu and the summary. */
75
+ pageSize?: number;
76
+ pageSizeOptions?: readonly number[];
77
+ /** Adds a rows-per-page menu beside the pages. */
78
+ onPageSizeChange?: (pageSize: number) => void;
79
+ /** Every row on every page (server paging), for the summary. */
80
+ totalRows?: number;
81
+ /**
82
+ * Page in the browser: pass every row in `rows` and the table shows one
83
+ * page, with a rows-per-page menu. It goes back to page 1 when `filter` or
84
+ * `sort` changes. Leave out to page in your app or on the server.
85
+ */
86
+ paginate?: boolean | DataTablePaginateOptions;
87
+ /** Plural noun appended to the built-in summary: "1–25 of 312 members". */
88
+ rowNoun?: string;
45
89
  loading?: boolean;
46
90
  /** A message shown in place of the rows. */
47
91
  error?: React.ReactNode;
@@ -52,11 +96,17 @@ export interface DataTableProps<T> extends Omit<React.ComponentProps<'div'>, 'ch
52
96
  toolbar?: React.ReactNode;
53
97
  density?: 'compact' | 'default';
54
98
  stickyHeader?: boolean;
99
+ /**
100
+ * Below this width the rows become a list of cards (see DataTableColumn
101
+ * `card`). `md` (768px) by default; `false` keeps the table everywhere.
102
+ */
103
+ cardsBelow?: DataTableBreakpoint | false;
55
104
  }
56
105
  /**
57
106
  * A table recipe for records: sort, search, select, page, and row actions,
58
107
  * with loading, empty and error states. Fully controlled, so the data can
59
- * come from a server; the table never reorders rows itself.
108
+ * come from a server; the table never reorders rows itself. On a phone the
109
+ * rows become cards (`cardsBelow`), with the same columns.
60
110
  */
61
- declare function DataTable<T>({ 'aria-label': ariaLabel, columns, rows, getRowId, getRowLabel, sort, onSortChange, filter, onFilterChange, filterPlaceholder, selected, onSelectedChange, onRowAction, rowActions, page, pageCount, onPageChange, pageSummary, loading, error, onRetry, empty, toolbar, density, stickyHeader, className, ...props }: DataTableProps<T>): React.JSX.Element;
111
+ declare function DataTable<T>({ 'aria-label': ariaLabel, columns, rows: rowsProp, getRowId, getRowLabel, sort, onSortChange, filter, onFilterChange, filterPlaceholder, selected, onSelectedChange, onRowAction, rowActions, page, pageCount, onPageChange, pageSummary, pageSize, pageSizeOptions, onPageSizeChange, totalRows, paginate, rowNoun, loading, error, onRetry, empty, toolbar, density, stickyHeader, cardsBelow, className, ...props }: DataTableProps<T>): React.JSX.Element;
62
112
  export { DataTable };