@burtson-labs/ui 0.4.0 → 0.5.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 +3 -3
- package/dist/components/alert-dialog.d.ts +20 -0
- package/dist/components/alert-dialog.js +80 -0
- package/dist/components/alert-dialog.js.map +1 -0
- package/dist/components/button.d.ts +1 -1
- package/dist/components/combobox.d.ts +32 -0
- package/dist/components/combobox.js +79 -0
- package/dist/components/combobox.js.map +1 -0
- package/dist/components/dialog.js +2 -2
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/navigation-menu.js +2 -2
- package/dist/components/navigation-menu.js.map +1 -1
- package/dist/components/pagination.d.ts +18 -0
- package/dist/components/pagination.js +92 -0
- package/dist/components/pagination.js.map +1 -0
- package/dist/components/popover.d.ts +1 -1
- package/dist/components/popover.js +1 -1
- package/dist/components/popover.js.map +1 -1
- package/dist/components/select.js +1 -1
- package/dist/components/sheet.d.ts +4 -2
- package/dist/components/sheet.js +5 -3
- package/dist/components/sheet.js.map +1 -1
- package/dist/components/steps.d.ts +14 -0
- package/dist/components/steps.js +45 -0
- package/dist/components/steps.js.map +1 -0
- package/dist/components/tabs.js +1 -1
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/toast.js +1 -1
- package/dist/components/toast.js.map +1 -1
- package/dist/components/tooltip.js +1 -1
- package/dist/components/tooltip.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +9 -5
- package/dist/styles.css +1 -1
- package/dist/theme.css +22 -11
- package/dist/tokens.d.ts +167 -0
- package/dist/tokens.js +53 -1
- package/dist/tokens.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
# Burtson UI
|
|
9
9
|
|
|
10
|
-
**
|
|
10
|
+
**React components for Burtson Labs products.**
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Used in Bandit Stealth, Sentinel, our cluster tools and client apps. Radix primitives handle focus and keyboard behaviour, Tailwind v4 handles styling, and the icons are [Burtson Icons](https://icons.burtson.ai). No runtime provider. Install the package, or copy a component's source and change it.
|
|
13
13
|
|
|
14
14
|
[](https://ui.burtson.ai)
|
|
15
15
|
[](https://www.npmjs.com/package/@burtson-labs/ui)
|
|
@@ -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 · App Shell · Avatar · Badge · Breadcrumb · Button · Card · Checkbox · Collapsible · Command · Dialog · Dropdown Menu · Empty State · Field · Icon Button · Input · Kbd · Label · Navigation Menu · Page Header · Popover · Progress · Radio Group · Scroll Area · Select · Separator · Sheet · Skeleton · Spinner · Stat Card · Status · Switch · Table · Tabs · Textarea · Toast · Toolbar · Tooltip
|
|
61
|
+
Accordion · Alert · Alert Dialog · App Shell · Avatar · Badge · Breadcrumb · Button · Card · Checkbox · Collapsible · Combobox · Command · Dialog · Dropdown Menu · Empty State · Field · Icon Button · Input · Kbd · Label · Navigation Menu · Page Header · Pagination · Popover · Progress · Radio Group · Scroll Area · Select · Separator · Sheet · Skeleton · Spinner · Stat Card · Status · Steps · Switch · Table · Tabs · Textarea · Toast · Toolbar · Tooltip
|
|
62
62
|
|
|
63
63
|
Live previews and code for each one are at [ui.burtson.ai](https://ui.burtson.ai/docs/components/button).
|
|
64
64
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AlertDialog as AlertDialogPrimitive } from 'radix-ui';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* A confirmation that interrupts: "Delete 3 keys?", "Revoke access?". Unlike
|
|
5
|
+
* Dialog it has no close button and ignores outside clicks, so the person
|
|
6
|
+
* answers it; Escape still cancels. Focus starts on Cancel.
|
|
7
|
+
*/
|
|
8
|
+
declare function AlertDialog(props: React.ComponentProps<typeof AlertDialogPrimitive.Root>): React.JSX.Element;
|
|
9
|
+
declare function AlertDialogTrigger(props: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>): React.JSX.Element;
|
|
10
|
+
declare function AlertDialogContent({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Content>): React.JSX.Element;
|
|
11
|
+
declare function AlertDialogHeader({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
|
|
12
|
+
declare function AlertDialogFooter({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
|
|
13
|
+
declare function AlertDialogTitle({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Title>): React.JSX.Element;
|
|
14
|
+
declare function AlertDialogDescription({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Description>): React.JSX.Element;
|
|
15
|
+
/** The confirming button. `destructive` paints it as a danger action. */
|
|
16
|
+
declare function AlertDialogAction({ className, destructive, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Action> & {
|
|
17
|
+
destructive?: boolean;
|
|
18
|
+
}): React.JSX.Element;
|
|
19
|
+
declare function AlertDialogCancel({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>): React.JSX.Element;
|
|
20
|
+
export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { buttonVariants } from "./button.js";
|
|
3
|
+
import { AlertDialog } from "radix-ui";
|
|
4
|
+
import "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/components/alert-dialog.tsx
|
|
7
|
+
/**
|
|
8
|
+
* A confirmation that interrupts: "Delete 3 keys?", "Revoke access?". Unlike
|
|
9
|
+
* Dialog it has no close button and ignores outside clicks, so the person
|
|
10
|
+
* answers it; Escape still cancels. Focus starts on Cancel.
|
|
11
|
+
*/
|
|
12
|
+
function AlertDialog$1(props) {
|
|
13
|
+
return /* @__PURE__ */ jsx(AlertDialog.Root, {
|
|
14
|
+
"data-slot": "alert-dialog",
|
|
15
|
+
...props
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function AlertDialogTrigger(props) {
|
|
19
|
+
return /* @__PURE__ */ jsx(AlertDialog.Trigger, {
|
|
20
|
+
"data-slot": "alert-dialog-trigger",
|
|
21
|
+
...props
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function AlertDialogContent({ className, ...props }) {
|
|
25
|
+
return /* @__PURE__ */ jsxs(AlertDialog.Portal, { children: [/* @__PURE__ */ jsx(AlertDialog.Overlay, {
|
|
26
|
+
"data-slot": "alert-dialog-overlay",
|
|
27
|
+
className: "fixed inset-0 z-50 bg-black/55 backdrop-blur-[3px] data-[state=closed]:animate-fade-out data-[state=open]:animate-fade-in"
|
|
28
|
+
}), /* @__PURE__ */ jsx(AlertDialog.Content, {
|
|
29
|
+
"data-slot": "alert-dialog-content",
|
|
30
|
+
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-md -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),
|
|
31
|
+
...props
|
|
32
|
+
})] });
|
|
33
|
+
}
|
|
34
|
+
function AlertDialogHeader({ className, ...props }) {
|
|
35
|
+
return /* @__PURE__ */ jsx("div", {
|
|
36
|
+
"data-slot": "alert-dialog-header",
|
|
37
|
+
className: cn("grid gap-1.5", className),
|
|
38
|
+
...props
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function AlertDialogFooter({ className, ...props }) {
|
|
42
|
+
return /* @__PURE__ */ jsx("div", {
|
|
43
|
+
"data-slot": "alert-dialog-footer",
|
|
44
|
+
className: cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className),
|
|
45
|
+
...props
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function AlertDialogTitle({ className, ...props }) {
|
|
49
|
+
return /* @__PURE__ */ jsx(AlertDialog.Title, {
|
|
50
|
+
"data-slot": "alert-dialog-title",
|
|
51
|
+
className: cn("text-base font-semibold tracking-[-0.02em]", className),
|
|
52
|
+
...props
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function AlertDialogDescription({ className, ...props }) {
|
|
56
|
+
return /* @__PURE__ */ jsx(AlertDialog.Description, {
|
|
57
|
+
"data-slot": "alert-dialog-description",
|
|
58
|
+
className: cn("text-sm leading-5 text-muted-foreground", className),
|
|
59
|
+
...props
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/** The confirming button. `destructive` paints it as a danger action. */
|
|
63
|
+
function AlertDialogAction({ className, destructive = false, ...props }) {
|
|
64
|
+
return /* @__PURE__ */ jsx(AlertDialog.Action, {
|
|
65
|
+
"data-slot": "alert-dialog-action",
|
|
66
|
+
className: cn(buttonVariants({ variant: destructive ? "destructive" : "default" }), className),
|
|
67
|
+
...props
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function AlertDialogCancel({ className, ...props }) {
|
|
71
|
+
return /* @__PURE__ */ jsx(AlertDialog.Cancel, {
|
|
72
|
+
"data-slot": "alert-dialog-cancel",
|
|
73
|
+
className: cn(buttonVariants({ variant: "outline" }), className),
|
|
74
|
+
...props
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
export { AlertDialog$1 as AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger };
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=alert-dialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-dialog.js","names":["AlertDialog","AlertDialogPrimitive"],"sources":["../../src/components/alert-dialog.tsx"],"sourcesContent":["import { AlertDialog as AlertDialogPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { buttonVariants } from './button';\n\n/**\n * A confirmation that interrupts: \"Delete 3 keys?\", \"Revoke access?\". Unlike\n * Dialog it has no close button and ignores outside clicks, so the person\n * answers it; Escape still cancels. Focus starts on Cancel.\n */\nfunction AlertDialog(props: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {\n return <AlertDialogPrimitive.Root data-slot=\"alert-dialog\" {...props} />;\n}\n\nfunction AlertDialogTrigger(props: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {\n return <AlertDialogPrimitive.Trigger data-slot=\"alert-dialog-trigger\" {...props} />;\n}\n\nfunction AlertDialogContent({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {\n return (\n <AlertDialogPrimitive.Portal>\n <AlertDialogPrimitive.Overlay\n data-slot=\"alert-dialog-overlay\"\n className=\"fixed inset-0 z-50 bg-black/55 backdrop-blur-[3px] data-[state=closed]:animate-fade-out data-[state=open]:animate-fade-in\"\n />\n <AlertDialogPrimitive.Content\n data-slot=\"alert-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-md -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 </AlertDialogPrimitive.Portal>\n );\n}\n\nfunction AlertDialogHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div data-slot=\"alert-dialog-header\" className={cn('grid gap-1.5', className)} {...props} />\n );\n}\n\nfunction AlertDialogFooter({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"alert-dialog-footer\"\n className={cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className)}\n {...props}\n />\n );\n}\n\nfunction AlertDialogTitle({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {\n return (\n <AlertDialogPrimitive.Title\n data-slot=\"alert-dialog-title\"\n className={cn('text-base font-semibold tracking-[-0.02em]', className)}\n {...props}\n />\n );\n}\n\nfunction AlertDialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {\n return (\n <AlertDialogPrimitive.Description\n data-slot=\"alert-dialog-description\"\n className={cn('text-sm leading-5 text-muted-foreground', className)}\n {...props}\n />\n );\n}\n\n/** The confirming button. `destructive` paints it as a danger action. */\nfunction AlertDialogAction({\n className,\n destructive = false,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Action> & { destructive?: boolean }) {\n return (\n <AlertDialogPrimitive.Action\n data-slot=\"alert-dialog-action\"\n className={cn(\n buttonVariants({ variant: destructive ? 'destructive' : 'default' }),\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogCancel({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {\n return (\n <AlertDialogPrimitive.Cancel\n data-slot=\"alert-dialog-cancel\"\n className={cn(buttonVariants({ variant: 'outline' }), className)}\n {...props}\n />\n );\n}\n\nexport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n};\n"],"mappings":";;;;;;;;;;;AAYA,SAASA,cAAY,OAA+D;CAClF,OAAO,oBAACC,YAAqB,MAAtB;EAA2B,aAAU;EAAe,GAAI;CAAQ,CAAA;AACzE;AAEA,SAAS,mBAAmB,OAAkE;CAC5F,OAAO,oBAACA,YAAqB,SAAtB;EAA8B,aAAU;EAAuB,GAAI;CAAQ,CAAA;AACpF;AAEA,SAAS,mBAAmB,EAC1B,WACA,GAAG,SACyD;CAC5D,OACE,qBAACA,YAAqB,QAAtB,EAAA,UAAA,CACE,oBAACA,YAAqB,SAAtB;EACE,aAAU;EACV,WAAU;CACX,CAAA,GACD,oBAACA,YAAqB,SAAtB;EACE,aAAU;EACV,WAAW,GACT,8UACA,SACF;EACA,GAAI;CACL,CAAA,CAC0B,EAAA,CAAA;AAEjC;AAEA,SAAS,kBAAkB,EAAE,WAAW,GAAG,SAAsC;CAC/E,OACE,oBAAC,OAAD;EAAK,aAAU;EAAsB,WAAW,GAAG,gBAAgB,SAAS;EAAG,GAAI;CAAQ,CAAA;AAE/F;AAEA,SAAS,kBAAkB,EAAE,WAAW,GAAG,SAAsC;CAC/E,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,0DAA0D,SAAS;EACjF,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,iBAAiB,EACxB,WACA,GAAG,SACuD;CAC1D,OACE,oBAACA,YAAqB,OAAtB;EACE,aAAU;EACV,WAAW,GAAG,8CAA8C,SAAS;EACrE,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,uBAAuB,EAC9B,WACA,GAAG,SAC6D;CAChE,OACE,oBAACA,YAAqB,aAAtB;EACE,aAAU;EACV,WAAW,GAAG,2CAA2C,SAAS;EAClE,GAAI;CACL,CAAA;AAEL;;AAGA,SAAS,kBAAkB,EACzB,WACA,cAAc,OACd,GAAG,SACoF;CACvF,OACE,oBAACA,YAAqB,QAAtB;EACE,aAAU;EACV,WAAW,GACT,eAAe,EAAE,SAAS,cAAc,gBAAgB,UAAU,CAAC,GACnE,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,kBAAkB,EACzB,WACA,GAAG,SACwD;CAC3D,OACE,oBAACA,YAAqB,QAAtB;EACE,aAAU;EACV,WAAW,GAAG,eAAe,EAAE,SAAS,UAAU,CAAC,GAAG,SAAS;EAC/D,GAAI;CACL,CAAA;AAEL"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type VariantProps } from 'class-variance-authority';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
declare const buttonVariants: (props?: ({
|
|
4
|
-
variant?: "secondary" | "destructive" | "brand" | "link" | "default" | "
|
|
4
|
+
variant?: "secondary" | "destructive" | "brand" | "link" | "default" | "soft" | "outline" | "ghost" | null | undefined;
|
|
5
5
|
size?: "default" | "xs" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg" | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
7
|
export interface ButtonProps extends React.ComponentProps<'button'>, VariantProps<typeof buttonVariants> {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface ComboboxOption {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
/** Second line, e.g. an email under a name. Also searched. */
|
|
6
|
+
description?: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface ComboboxProps {
|
|
10
|
+
options: ComboboxOption[];
|
|
11
|
+
value: string | null;
|
|
12
|
+
onValueChange: (value: string | null) => void;
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
searchPlaceholder?: string;
|
|
15
|
+
emptyText?: string;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
/** Show a spinner in the list, e.g. while `onSearchChange` fetches. */
|
|
18
|
+
loading?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Called as the person types. Pass it to search on a server; the options
|
|
21
|
+
* you pass back are shown as-is (no client filtering).
|
|
22
|
+
*/
|
|
23
|
+
onSearchChange?: (search: string) => void;
|
|
24
|
+
/** Let the person clear the selection by picking it again. */
|
|
25
|
+
clearable?: boolean;
|
|
26
|
+
id?: string;
|
|
27
|
+
className?: string;
|
|
28
|
+
'aria-invalid'?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** Pick one value from a long or remote list by typing. */
|
|
31
|
+
declare function Combobox({ options, value, onValueChange, placeholder, searchPlaceholder, emptyText, disabled, loading, onSearchChange, clearable, id, className, ...aria }: ComboboxProps): React.JSX.Element;
|
|
32
|
+
export { Combobox };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "./command.js";
|
|
3
|
+
import { fieldClasses } from "./input.js";
|
|
4
|
+
import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
|
|
5
|
+
import { Spinner } from "./spinner.js";
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import Check from "@burtson-labs/icons/react/check";
|
|
9
|
+
import ChevronsUpDown from "@burtson-labs/icons/react/chevrons-up-down";
|
|
10
|
+
//#region src/components/combobox.tsx
|
|
11
|
+
/** Pick one value from a long or remote list by typing. */
|
|
12
|
+
function Combobox({ options, value, onValueChange, placeholder = "Select…", searchPlaceholder = "Search…", emptyText = "No matches.", disabled, loading, onSearchChange, clearable = true, id, className, ...aria }) {
|
|
13
|
+
const [open, setOpen] = React.useState(false);
|
|
14
|
+
const listId = React.useId();
|
|
15
|
+
const selected = options.find((o) => o.value === value);
|
|
16
|
+
return /* @__PURE__ */ jsxs(Popover, {
|
|
17
|
+
open,
|
|
18
|
+
onOpenChange: setOpen,
|
|
19
|
+
children: [/* @__PURE__ */ jsx(PopoverTrigger, {
|
|
20
|
+
asChild: true,
|
|
21
|
+
children: /* @__PURE__ */ jsxs("button", {
|
|
22
|
+
type: "button",
|
|
23
|
+
id,
|
|
24
|
+
role: "combobox",
|
|
25
|
+
"aria-expanded": open,
|
|
26
|
+
"aria-controls": listId,
|
|
27
|
+
"aria-invalid": aria["aria-invalid"],
|
|
28
|
+
disabled,
|
|
29
|
+
"data-slot": "combobox-trigger",
|
|
30
|
+
className: cn(fieldClasses, "flex h-9 items-center justify-between gap-2 text-left", !selected && "text-muted-foreground", className),
|
|
31
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
32
|
+
className: "truncate",
|
|
33
|
+
children: selected?.label ?? value ?? placeholder
|
|
34
|
+
}), /* @__PURE__ */ jsx(ChevronsUpDown, {
|
|
35
|
+
className: "size-4 shrink-0 opacity-60",
|
|
36
|
+
"aria-hidden": true
|
|
37
|
+
})]
|
|
38
|
+
})
|
|
39
|
+
}), /* @__PURE__ */ jsx(PopoverContent, {
|
|
40
|
+
id: listId,
|
|
41
|
+
className: "w-(--radix-popover-trigger-width) min-w-64 p-0",
|
|
42
|
+
align: "start",
|
|
43
|
+
children: /* @__PURE__ */ jsxs(Command, {
|
|
44
|
+
shouldFilter: !onSearchChange,
|
|
45
|
+
children: [/* @__PURE__ */ jsx(CommandInput, {
|
|
46
|
+
placeholder: searchPlaceholder,
|
|
47
|
+
onValueChange: onSearchChange
|
|
48
|
+
}), /* @__PURE__ */ jsxs(CommandList, { children: [loading ? /* @__PURE__ */ jsxs("div", {
|
|
49
|
+
className: "flex items-center justify-center gap-2 py-6 text-sm text-muted-foreground",
|
|
50
|
+
children: [/* @__PURE__ */ jsx(Spinner, {}), " Searching…"]
|
|
51
|
+
}) : /* @__PURE__ */ jsx(CommandEmpty, { children: emptyText }), !loading && /* @__PURE__ */ jsx(CommandGroup, { children: options.map((o) => /* @__PURE__ */ jsxs(CommandItem, {
|
|
52
|
+
value: `${o.label} ${o.description ?? ""} ${o.value}`,
|
|
53
|
+
disabled: o.disabled,
|
|
54
|
+
onSelect: () => {
|
|
55
|
+
onValueChange(clearable && o.value === value ? null : o.value);
|
|
56
|
+
setOpen(false);
|
|
57
|
+
},
|
|
58
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
59
|
+
className: "grid min-w-0 flex-1",
|
|
60
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
61
|
+
className: "truncate",
|
|
62
|
+
children: o.label
|
|
63
|
+
}), o.description && /* @__PURE__ */ jsx("span", {
|
|
64
|
+
className: "truncate text-xs text-muted-foreground",
|
|
65
|
+
children: o.description
|
|
66
|
+
})]
|
|
67
|
+
}), /* @__PURE__ */ jsx(Check, {
|
|
68
|
+
"aria-hidden": true,
|
|
69
|
+
className: cn("ml-auto size-4 text-brand", o.value === value ? "opacity-100" : "opacity-0")
|
|
70
|
+
})]
|
|
71
|
+
}, o.value)) })] })]
|
|
72
|
+
})
|
|
73
|
+
})]
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
77
|
+
export { Combobox };
|
|
78
|
+
|
|
79
|
+
//# sourceMappingURL=combobox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combobox.js","names":[],"sources":["../../src/components/combobox.tsx"],"sourcesContent":["import Check from '@burtson-labs/icons/react/check';\nimport ChevronsUpDown from '@burtson-labs/icons/react/chevrons-up-down';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from './command';\nimport { fieldClasses } from './input';\nimport { Popover, PopoverContent, PopoverTrigger } from './popover';\nimport { Spinner } from './spinner';\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n /** Second line, e.g. an email under a name. Also searched. */\n description?: string;\n disabled?: boolean;\n}\n\nexport interface ComboboxProps {\n options: ComboboxOption[];\n value: string | null;\n onValueChange: (value: string | null) => void;\n placeholder?: string;\n searchPlaceholder?: string;\n emptyText?: string;\n disabled?: boolean;\n /** Show a spinner in the list, e.g. while `onSearchChange` fetches. */\n loading?: boolean;\n /**\n * Called as the person types. Pass it to search on a server; the options\n * you pass back are shown as-is (no client filtering).\n */\n onSearchChange?: (search: string) => void;\n /** Let the person clear the selection by picking it again. */\n clearable?: boolean;\n id?: string;\n className?: string;\n 'aria-invalid'?: boolean;\n}\n\n/** Pick one value from a long or remote list by typing. */\nfunction Combobox({\n options,\n value,\n onValueChange,\n placeholder = 'Select…',\n searchPlaceholder = 'Search…',\n emptyText = 'No matches.',\n disabled,\n loading,\n onSearchChange,\n clearable = true,\n id,\n className,\n ...aria\n}: ComboboxProps) {\n const [open, setOpen] = React.useState(false);\n const listId = React.useId();\n const selected = options.find((o) => o.value === value);\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n id={id}\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={listId}\n aria-invalid={aria['aria-invalid']}\n disabled={disabled}\n data-slot=\"combobox-trigger\"\n className={cn(\n fieldClasses,\n 'flex h-9 items-center justify-between gap-2 text-left',\n !selected && 'text-muted-foreground',\n className,\n )}\n >\n <span className=\"truncate\">{selected?.label ?? value ?? placeholder}</span>\n <ChevronsUpDown className=\"size-4 shrink-0 opacity-60\" aria-hidden />\n </button>\n </PopoverTrigger>\n <PopoverContent\n id={listId}\n className=\"w-(--radix-popover-trigger-width) min-w-64 p-0\"\n align=\"start\"\n >\n <Command shouldFilter={!onSearchChange}>\n <CommandInput placeholder={searchPlaceholder} onValueChange={onSearchChange} />\n <CommandList>\n {loading ? (\n <div className=\"flex items-center justify-center gap-2 py-6 text-sm text-muted-foreground\">\n <Spinner /> Searching…\n </div>\n ) : (\n <CommandEmpty>{emptyText}</CommandEmpty>\n )}\n {!loading && (\n <CommandGroup>\n {options.map((o) => (\n <CommandItem\n key={o.value}\n value={`${o.label} ${o.description ?? ''} ${o.value}`}\n disabled={o.disabled}\n onSelect={() => {\n onValueChange(clearable && o.value === value ? null : o.value);\n setOpen(false);\n }}\n >\n <span className=\"grid min-w-0 flex-1\">\n <span className=\"truncate\">{o.label}</span>\n {o.description && (\n <span className=\"truncate text-xs text-muted-foreground\">\n {o.description}\n </span>\n )}\n </span>\n <Check\n aria-hidden\n className={cn(\n 'ml-auto size-4 text-brand',\n o.value === value ? 'opacity-100' : 'opacity-0',\n )}\n />\n </CommandItem>\n ))}\n </CommandGroup>\n )}\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n );\n}\n\nexport { Combobox };\n"],"mappings":";;;;;;;;;;;AAiDA,SAAS,SAAS,EAChB,SACA,OACA,eACA,cAAc,WACd,oBAAoB,WACpB,YAAY,eACZ,UACA,SACA,gBACA,YAAY,MACZ,IACA,WACA,GAAG,QACa;CAChB,MAAM,CAAC,MAAM,WAAW,MAAM,SAAS,KAAK;CAC5C,MAAM,SAAS,MAAM,MAAM;CAC3B,MAAM,WAAW,QAAQ,MAAM,MAAM,EAAE,UAAU,KAAK;CACtD,OACE,qBAAC,SAAD;EAAe;EAAM,cAAc;EAAnC,UAAA,CACE,oBAAC,gBAAD;GAAgB,SAAA;GACd,UAAA,qBAAC,UAAD;IACE,MAAK;IACD;IACJ,MAAK;IACL,iBAAe;IACf,iBAAe;IACf,gBAAc,KAAK;IACT;IACV,aAAU;IACV,WAAW,GACT,cACA,yDACA,CAAC,YAAY,yBACb,SACF;IAdF,UAAA,CAgBE,oBAAC,QAAD;KAAM,WAAU;KAAY,UAAA,UAAU,SAAS,SAAS;IAAkB,CAAA,GAC1E,oBAAC,gBAAD;KAAgB,WAAU;KAA6B,eAAA;IAAa,CAAA,CAC9D;;EACM,CAAA,GAChB,oBAAC,gBAAD;GACE,IAAI;GACJ,WAAU;GACV,OAAM;GAEN,UAAA,qBAAC,SAAD;IAAS,cAAc,CAAC;IAAxB,UAAA,CACE,oBAAC,cAAD;KAAc,aAAa;KAAmB,eAAe;IAAiB,CAAA,GAC9E,qBAAC,aAAD,EAAA,UAAA,CACG,UACC,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACE,oBAAC,SAAD,CAAU,CAAA,GAAC,aACR;IAEL,CAAA,IAAA,oBAAC,cAAD,EAAA,UAAe,UAAwB,CAAA,GAExC,CAAC,WACA,oBAAC,cAAD,EAAA,UACG,QAAQ,KAAK,MACZ,qBAAC,aAAD;KAEE,OAAO,GAAG,EAAE,MAAM,GAAG,EAAE,eAAe,GAAG,GAAG,EAAE;KAC9C,UAAU,EAAE;KACZ,gBAAgB;MACd,cAAc,aAAa,EAAE,UAAU,QAAQ,OAAO,EAAE,KAAK;MAC7D,QAAQ,KAAK;KACf;KAPF,UAAA,CASE,qBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA,CACE,oBAAC,QAAD;OAAM,WAAU;OAAY,UAAA,EAAE;MAAY,CAAA,GACzC,EAAE,eACD,oBAAC,QAAD;OAAM,WAAU;OACb,UAAA,EAAE;MACC,CAAA,CAEJ;KACN,CAAA,GAAA,oBAAC,OAAD;MACE,eAAA;MACA,WAAW,GACT,6BACA,EAAE,UAAU,QAAQ,gBAAgB,WACtC;KACD,CAAA,CACU;IAvBN,GAAA,EAAE,KAuBI,CACd,EACW,CAAA,CAEL,EAAA,CAAA,CACN;;EACK,CAAA,CACT;;AAEb"}
|
|
@@ -31,14 +31,14 @@ function DialogPortal(props) {
|
|
|
31
31
|
function DialogOverlay({ className, ...props }) {
|
|
32
32
|
return /* @__PURE__ */ jsx(Dialog.Overlay, {
|
|
33
33
|
"data-slot": "dialog-overlay",
|
|
34
|
-
className: cn("fixed inset-0 z-50 bg-black/55 backdrop-blur-[3px] data-[state=closed]:animate-out data-[state=open]:animate-in", className),
|
|
34
|
+
className: cn("fixed inset-0 z-50 bg-black/55 backdrop-blur-[3px] data-[state=closed]:animate-fade-out data-[state=open]:animate-fade-in", className),
|
|
35
35
|
...props
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
38
|
function DialogContent({ className, children, showCloseButton = true, ...props }) {
|
|
39
39
|
return /* @__PURE__ */ jsxs(DialogPortal, { children: [/* @__PURE__ */ jsx(DialogOverlay, {}), /* @__PURE__ */ jsxs(Dialog.Content, {
|
|
40
40
|
"data-slot": "dialog-content",
|
|
41
|
-
className: cn("fixed top-1/2 left-1/2 z-50 grid w-[calc(100%-2rem)] max-w-lg -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),
|
|
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 -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),
|
|
42
42
|
...props,
|
|
43
43
|
children: [children, showCloseButton ? /* @__PURE__ */ jsxs(Dialog.Close, {
|
|
44
44
|
"data-slot": "dialog-close",
|
|
@@ -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-out data-[state=open]:animate-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 w-[calc(100%-2rem)] max-w-lg -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,
|
|
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 -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,8UACA,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"}
|
|
@@ -48,7 +48,7 @@ function NavigationMenuTrigger({ className, children, ...props }) {
|
|
|
48
48
|
function NavigationMenuContent({ className, ...props }) {
|
|
49
49
|
return /* @__PURE__ */ jsx(NavigationMenu.Content, {
|
|
50
50
|
"data-slot": "navigation-menu-content",
|
|
51
|
-
className: cn("top-0 left-0 w-full p-2 md:absolute md:w-auto data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out", className),
|
|
51
|
+
className: cn("top-0 left-0 w-full p-2 md:absolute md:w-auto data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion=from-end]:[--bl-tx:24px] data-[motion=from-start]:[--bl-tx:-24px] data-[motion=to-end]:[--bl-tx:24px] data-[motion=to-start]:[--bl-tx:-24px] [--bl-scale:1]", className),
|
|
52
52
|
...props
|
|
53
53
|
});
|
|
54
54
|
}
|
|
@@ -57,7 +57,7 @@ function NavigationMenuViewport({ className, ...props }) {
|
|
|
57
57
|
className: "absolute top-full left-0 z-50 flex justify-center",
|
|
58
58
|
children: /* @__PURE__ */ jsx(NavigationMenu.Viewport, {
|
|
59
59
|
"data-slot": "navigation-menu-viewport",
|
|
60
|
-
className: cn("relative mt-2 h-(--radix-navigation-menu-viewport-height) w-full origin-top overflow-hidden rounded-lg border border-border-strong bg-surface-raised text-popover-foreground shadow-[0_16px_48px_rgb(0_0_0_/_0.18)] data-[state=closed]:animate-out data-[state=open]:animate-in md:w-(--radix-navigation-menu-viewport-width)", className),
|
|
60
|
+
className: cn("relative mt-2 h-(--radix-navigation-menu-viewport-height) w-full origin-top overflow-hidden rounded-lg border border-border-strong bg-surface-raised text-popover-foreground shadow-[0_16px_48px_rgb(0_0_0_/_0.18)] transition-[width,height] duration-200 [--bl-ty:-6px] data-[state=closed]:animate-out data-[state=open]:animate-in md:w-(--radix-navigation-menu-viewport-width)", className),
|
|
61
61
|
...props
|
|
62
62
|
})
|
|
63
63
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation-menu.js","names":["NavigationMenu","NavigationMenuPrimitive"],"sources":["../../src/components/navigation-menu.tsx"],"sourcesContent":["import ChevronDown from '@burtson-labs/icons/react/chevron-down';\nimport { NavigationMenu as NavigationMenuPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\n/**\n * Site navigation with dropdown panels (a products menu, docs sections).\n * Keyboard and screen-reader behaviour come from Radix; the panel renders in\n * a shared viewport under the bar, sized to its content.\n */\nfunction NavigationMenu({\n className,\n children,\n viewport = true,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & { viewport?: boolean }) {\n return (\n <NavigationMenuPrimitive.Root\n data-slot=\"navigation-menu\"\n data-viewport={viewport}\n className={cn(\n 'group/navigation-menu relative flex max-w-max flex-1 items-center justify-center',\n className,\n )}\n {...props}\n >\n {children}\n {viewport && <NavigationMenuViewport />}\n </NavigationMenuPrimitive.Root>\n );\n}\n\nfunction NavigationMenuList({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {\n return (\n <NavigationMenuPrimitive.List\n data-slot=\"navigation-menu-list\"\n className={cn('group flex flex-1 list-none items-center justify-center gap-1', className)}\n {...props}\n />\n );\n}\n\nfunction NavigationMenuItem({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {\n return (\n <NavigationMenuPrimitive.Item\n data-slot=\"navigation-menu-item\"\n className={cn('relative', className)}\n {...props}\n />\n );\n}\n\n/** The look of a top-level entry, for links that sit beside triggers. */\nconst navigationMenuTriggerStyle =\n 'group inline-flex h-9 w-max items-center justify-center gap-1 rounded-md px-3 text-sm font-semibold text-foreground/80 outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/20 disabled:pointer-events-none disabled:opacity-50 data-[active]:text-foreground data-[state=open]:bg-muted data-[state=open]:text-foreground';\n\nfunction NavigationMenuTrigger({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {\n return (\n <NavigationMenuPrimitive.Trigger\n data-slot=\"navigation-menu-trigger\"\n className={cn(navigationMenuTriggerStyle, className)}\n {...props}\n >\n {children}\n <ChevronDown\n aria-hidden\n className=\"relative top-px size-3.5 transition-transform duration-200 group-data-[state=open]:rotate-180\"\n />\n </NavigationMenuPrimitive.Trigger>\n );\n}\n\nfunction NavigationMenuContent({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {\n return (\n <NavigationMenuPrimitive.Content\n data-slot=\"navigation-menu-content\"\n className={cn(\n 'top-0 left-0 w-full p-2 md:absolute md:w-auto data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction NavigationMenuViewport({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {\n return (\n <div className=\"absolute top-full left-0 z-50 flex justify-center\">\n <NavigationMenuPrimitive.Viewport\n data-slot=\"navigation-menu-viewport\"\n className={cn(\n 'relative mt-2 h-(--radix-navigation-menu-viewport-height) w-full origin-top overflow-hidden rounded-lg border border-border-strong bg-surface-raised text-popover-foreground shadow-[0_16px_48px_rgb(0_0_0_/_0.18)] data-[state=closed]:animate-out data-[state=open]:animate-in md:w-(--radix-navigation-menu-viewport-width)',\n className,\n )}\n {...props}\n />\n </div>\n );\n}\n\nfunction NavigationMenuLink({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {\n return (\n <NavigationMenuPrimitive.Link\n data-slot=\"navigation-menu-link\"\n className={cn(\n \"flex flex-col gap-1 rounded-sm p-2 text-sm outline-none transition-colors hover:bg-muted focus-visible:ring-[3px] focus-visible:ring-ring/20 data-[active=true]:bg-muted data-[active=true]:shadow-[inset_2px_0_0_var(--color-brand)] [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction NavigationMenuIndicator({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {\n return (\n <NavigationMenuPrimitive.Indicator\n data-slot=\"navigation-menu-indicator\"\n className={cn(\n 'top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=hidden]:animate-out data-[state=visible]:animate-in',\n className,\n )}\n {...props}\n >\n <div className=\"relative top-[60%] size-2 rotate-45 rounded-tl-sm bg-border-strong\" />\n </NavigationMenuPrimitive.Indicator>\n );\n}\n\nexport {\n NavigationMenu,\n NavigationMenuContent,\n NavigationMenuIndicator,\n NavigationMenuItem,\n NavigationMenuLink,\n NavigationMenuList,\n NavigationMenuTrigger,\n navigationMenuTriggerStyle,\n NavigationMenuViewport,\n};\n"],"mappings":";;;;;;;;;;;AAWA,SAASA,iBAAe,EACtB,WACA,UACA,WAAW,MACX,GAAG,SACkF;CACrF,OACE,qBAACC,eAAwB,MAAzB;EACE,aAAU;EACV,iBAAe;EACf,WAAW,GACT,oFACA,SACF;EACA,GAAI;EAPN,UAAA,CASG,UACA,YAAY,oBAAC,wBAAD,CAAyB,CAAA,CACV;;AAElC;AAEA,SAAS,mBAAmB,EAC1B,WACA,GAAG,SACyD;CAC5D,OACE,oBAACA,eAAwB,MAAzB;EACE,aAAU;EACV,WAAW,GAAG,iEAAiE,SAAS;EACxF,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,mBAAmB,EAC1B,WACA,GAAG,SACyD;CAC5D,OACE,oBAACA,eAAwB,MAAzB;EACE,aAAU;EACV,WAAW,GAAG,YAAY,SAAS;EACnC,GAAI;CACL,CAAA;AAEL;;AAGA,IAAM,6BACJ;AAEF,SAAS,sBAAsB,EAC7B,WACA,UACA,GAAG,SAC4D;CAC/D,OACE,qBAACA,eAAwB,SAAzB;EACE,aAAU;EACV,WAAW,GAAG,4BAA4B,SAAS;EACnD,GAAI;EAHN,UAAA,CAKG,UACD,oBAAC,aAAD;GACE,eAAA;GACA,WAAU;EACX,CAAA,CAC8B;;AAErC;AAEA,SAAS,sBAAsB,EAC7B,WACA,GAAG,SAC4D;CAC/D,OACE,oBAACA,eAAwB,SAAzB;EACE,aAAU;EACV,WAAW,GACT,
|
|
1
|
+
{"version":3,"file":"navigation-menu.js","names":["NavigationMenu","NavigationMenuPrimitive"],"sources":["../../src/components/navigation-menu.tsx"],"sourcesContent":["import ChevronDown from '@burtson-labs/icons/react/chevron-down';\nimport { NavigationMenu as NavigationMenuPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\n/**\n * Site navigation with dropdown panels (a products menu, docs sections).\n * Keyboard and screen-reader behaviour come from Radix; the panel renders in\n * a shared viewport under the bar, sized to its content.\n */\nfunction NavigationMenu({\n className,\n children,\n viewport = true,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & { viewport?: boolean }) {\n return (\n <NavigationMenuPrimitive.Root\n data-slot=\"navigation-menu\"\n data-viewport={viewport}\n className={cn(\n 'group/navigation-menu relative flex max-w-max flex-1 items-center justify-center',\n className,\n )}\n {...props}\n >\n {children}\n {viewport && <NavigationMenuViewport />}\n </NavigationMenuPrimitive.Root>\n );\n}\n\nfunction NavigationMenuList({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {\n return (\n <NavigationMenuPrimitive.List\n data-slot=\"navigation-menu-list\"\n className={cn('group flex flex-1 list-none items-center justify-center gap-1', className)}\n {...props}\n />\n );\n}\n\nfunction NavigationMenuItem({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {\n return (\n <NavigationMenuPrimitive.Item\n data-slot=\"navigation-menu-item\"\n className={cn('relative', className)}\n {...props}\n />\n );\n}\n\n/** The look of a top-level entry, for links that sit beside triggers. */\nconst navigationMenuTriggerStyle =\n 'group inline-flex h-9 w-max items-center justify-center gap-1 rounded-md px-3 text-sm font-semibold text-foreground/80 outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/20 disabled:pointer-events-none disabled:opacity-50 data-[active]:text-foreground data-[state=open]:bg-muted data-[state=open]:text-foreground';\n\nfunction NavigationMenuTrigger({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {\n return (\n <NavigationMenuPrimitive.Trigger\n data-slot=\"navigation-menu-trigger\"\n className={cn(navigationMenuTriggerStyle, className)}\n {...props}\n >\n {children}\n <ChevronDown\n aria-hidden\n className=\"relative top-px size-3.5 transition-transform duration-200 group-data-[state=open]:rotate-180\"\n />\n </NavigationMenuPrimitive.Trigger>\n );\n}\n\nfunction NavigationMenuContent({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {\n return (\n <NavigationMenuPrimitive.Content\n data-slot=\"navigation-menu-content\"\n className={cn(\n 'top-0 left-0 w-full p-2 md:absolute md:w-auto data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion=from-end]:[--bl-tx:24px] data-[motion=from-start]:[--bl-tx:-24px] data-[motion=to-end]:[--bl-tx:24px] data-[motion=to-start]:[--bl-tx:-24px] [--bl-scale:1]',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction NavigationMenuViewport({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {\n return (\n <div className=\"absolute top-full left-0 z-50 flex justify-center\">\n <NavigationMenuPrimitive.Viewport\n data-slot=\"navigation-menu-viewport\"\n className={cn(\n 'relative mt-2 h-(--radix-navigation-menu-viewport-height) w-full origin-top overflow-hidden rounded-lg border border-border-strong bg-surface-raised text-popover-foreground shadow-[0_16px_48px_rgb(0_0_0_/_0.18)] transition-[width,height] duration-200 [--bl-ty:-6px] data-[state=closed]:animate-out data-[state=open]:animate-in md:w-(--radix-navigation-menu-viewport-width)',\n className,\n )}\n {...props}\n />\n </div>\n );\n}\n\nfunction NavigationMenuLink({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {\n return (\n <NavigationMenuPrimitive.Link\n data-slot=\"navigation-menu-link\"\n className={cn(\n \"flex flex-col gap-1 rounded-sm p-2 text-sm outline-none transition-colors hover:bg-muted focus-visible:ring-[3px] focus-visible:ring-ring/20 data-[active=true]:bg-muted data-[active=true]:shadow-[inset_2px_0_0_var(--color-brand)] [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction NavigationMenuIndicator({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {\n return (\n <NavigationMenuPrimitive.Indicator\n data-slot=\"navigation-menu-indicator\"\n className={cn(\n 'top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=hidden]:animate-out data-[state=visible]:animate-in',\n className,\n )}\n {...props}\n >\n <div className=\"relative top-[60%] size-2 rotate-45 rounded-tl-sm bg-border-strong\" />\n </NavigationMenuPrimitive.Indicator>\n );\n}\n\nexport {\n NavigationMenu,\n NavigationMenuContent,\n NavigationMenuIndicator,\n NavigationMenuItem,\n NavigationMenuLink,\n NavigationMenuList,\n NavigationMenuTrigger,\n navigationMenuTriggerStyle,\n NavigationMenuViewport,\n};\n"],"mappings":";;;;;;;;;;;AAWA,SAASA,iBAAe,EACtB,WACA,UACA,WAAW,MACX,GAAG,SACkF;CACrF,OACE,qBAACC,eAAwB,MAAzB;EACE,aAAU;EACV,iBAAe;EACf,WAAW,GACT,oFACA,SACF;EACA,GAAI;EAPN,UAAA,CASG,UACA,YAAY,oBAAC,wBAAD,CAAyB,CAAA,CACV;;AAElC;AAEA,SAAS,mBAAmB,EAC1B,WACA,GAAG,SACyD;CAC5D,OACE,oBAACA,eAAwB,MAAzB;EACE,aAAU;EACV,WAAW,GAAG,iEAAiE,SAAS;EACxF,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,mBAAmB,EAC1B,WACA,GAAG,SACyD;CAC5D,OACE,oBAACA,eAAwB,MAAzB;EACE,aAAU;EACV,WAAW,GAAG,YAAY,SAAS;EACnC,GAAI;CACL,CAAA;AAEL;;AAGA,IAAM,6BACJ;AAEF,SAAS,sBAAsB,EAC7B,WACA,UACA,GAAG,SAC4D;CAC/D,OACE,qBAACA,eAAwB,SAAzB;EACE,aAAU;EACV,WAAW,GAAG,4BAA4B,SAAS;EACnD,GAAI;EAHN,UAAA,CAKG,UACD,oBAAC,aAAD;GACE,eAAA;GACA,WAAU;EACX,CAAA,CAC8B;;AAErC;AAEA,SAAS,sBAAsB,EAC7B,WACA,GAAG,SAC4D;CAC/D,OACE,oBAACA,eAAwB,SAAzB;EACE,aAAU;EACV,WAAW,GACT,yRACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,uBAAuB,EAC9B,WACA,GAAG,SAC6D;CAChE,OACE,oBAAC,OAAD;EAAK,WAAU;EACb,UAAA,oBAACA,eAAwB,UAAzB;GACE,aAAU;GACV,WAAW,GACT,wXACA,SACF;GACA,GAAI;EACL,CAAA;CACE,CAAA;AAET;AAEA,SAAS,mBAAmB,EAC1B,WACA,GAAG,SACyD;CAC5D,OACE,oBAACA,eAAwB,MAAzB;EACE,aAAU;EACV,WAAW,GACT,kUACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,wBAAwB,EAC/B,WACA,GAAG,SAC8D;CACjE,OACE,oBAACA,eAAwB,WAAzB;EACE,aAAU;EACV,WAAW,GACT,sIACA,SACF;EACA,GAAI;EAEJ,UAAA,oBAAC,OAAD,EAAK,WAAU,qEAAsE,CAAA;CACpD,CAAA;AAEvC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The page numbers to show: always the first and last page, `siblings` pages
|
|
4
|
+
* either side of the current one, and 'ellipsis' for the gaps.
|
|
5
|
+
*/
|
|
6
|
+
export declare function paginationRange(page: number, pageCount: number, siblings?: number): (number | 'ellipsis')[];
|
|
7
|
+
export interface PaginationProps extends Omit<React.ComponentProps<'nav'>, 'onChange'> {
|
|
8
|
+
/** 1-based current page. */
|
|
9
|
+
page: number;
|
|
10
|
+
pageCount: number;
|
|
11
|
+
onPageChange: (page: number) => void;
|
|
12
|
+
siblings?: number;
|
|
13
|
+
/** Optional summary on the left, e.g. "1–25 of 312". */
|
|
14
|
+
summary?: React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
/** Page controls for a table or list. Buttons are real buttons, keyboard-reachable. */
|
|
17
|
+
declare function Pagination({ page, pageCount, onPageChange, siblings, summary, className, ...props }: PaginationProps): React.JSX.Element;
|
|
18
|
+
export { Pagination };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Button } from "./button.js";
|
|
3
|
+
import "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import ChevronRight from "@burtson-labs/icons/react/chevron-right";
|
|
6
|
+
import ChevronLeft from "@burtson-labs/icons/react/chevron-left";
|
|
7
|
+
//#region src/components/pagination.tsx
|
|
8
|
+
/**
|
|
9
|
+
* The page numbers to show: always the first and last page, `siblings` pages
|
|
10
|
+
* either side of the current one, and 'ellipsis' for the gaps.
|
|
11
|
+
*/
|
|
12
|
+
function paginationRange(page, pageCount, siblings = 1) {
|
|
13
|
+
if (pageCount <= 0) return [];
|
|
14
|
+
if (pageCount <= siblings * 2 + 5) return Array.from({ length: pageCount }, (_, i) => i + 1);
|
|
15
|
+
const start = Math.max(2, page - siblings);
|
|
16
|
+
const end = Math.min(pageCount - 1, page + siblings);
|
|
17
|
+
const out = [1];
|
|
18
|
+
if (start > 2) out.push("ellipsis");
|
|
19
|
+
for (let p = start; p <= end; p += 1) out.push(p);
|
|
20
|
+
if (end < pageCount - 1) out.push("ellipsis");
|
|
21
|
+
out.push(pageCount);
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
/** Page controls for a table or list. Buttons are real buttons, keyboard-reachable. */
|
|
25
|
+
function Pagination({ page, pageCount, onPageChange, siblings = 1, summary, className, ...props }) {
|
|
26
|
+
const pages = paginationRange(page, pageCount, siblings);
|
|
27
|
+
const go = (p) => onPageChange(Math.min(Math.max(1, p), Math.max(1, pageCount)));
|
|
28
|
+
return /* @__PURE__ */ jsxs("nav", {
|
|
29
|
+
"aria-label": "Pagination",
|
|
30
|
+
"data-slot": "pagination",
|
|
31
|
+
className: cn("flex flex-wrap items-center justify-between gap-3", className),
|
|
32
|
+
...props,
|
|
33
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
34
|
+
className: "text-xs text-muted-foreground tabular-nums",
|
|
35
|
+
children: summary
|
|
36
|
+
}), /* @__PURE__ */ jsxs("ul", {
|
|
37
|
+
className: "flex items-center gap-1",
|
|
38
|
+
children: [
|
|
39
|
+
/* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Button, {
|
|
40
|
+
variant: "ghost",
|
|
41
|
+
size: "sm",
|
|
42
|
+
onClick: () => go(page - 1),
|
|
43
|
+
disabled: page <= 1,
|
|
44
|
+
"aria-label": "Previous page",
|
|
45
|
+
children: [/* @__PURE__ */ jsx(ChevronLeft, { "aria-hidden": true }), /* @__PURE__ */ jsx("span", {
|
|
46
|
+
className: "hidden sm:inline",
|
|
47
|
+
children: "Previous"
|
|
48
|
+
})]
|
|
49
|
+
}) }),
|
|
50
|
+
pages.map((p, i) => p === "ellipsis" ? /* @__PURE__ */ jsx("li", {
|
|
51
|
+
"aria-hidden": true,
|
|
52
|
+
className: "px-1 text-muted-foreground",
|
|
53
|
+
children: "…"
|
|
54
|
+
}, `e${i}`) : /* @__PURE__ */ jsx("li", {
|
|
55
|
+
className: "hidden sm:block",
|
|
56
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
57
|
+
variant: p === page ? "outline" : "ghost",
|
|
58
|
+
size: "icon-sm",
|
|
59
|
+
onClick: () => go(p),
|
|
60
|
+
"aria-current": p === page ? "page" : void 0,
|
|
61
|
+
"aria-label": `Page ${p}`,
|
|
62
|
+
className: cn("tabular-nums", p === page && "border-brand/40 text-brand"),
|
|
63
|
+
children: p
|
|
64
|
+
})
|
|
65
|
+
}, p)),
|
|
66
|
+
/* @__PURE__ */ jsxs("li", {
|
|
67
|
+
className: "px-2 text-xs text-muted-foreground tabular-nums sm:hidden",
|
|
68
|
+
children: [
|
|
69
|
+
page,
|
|
70
|
+
" / ",
|
|
71
|
+
pageCount
|
|
72
|
+
]
|
|
73
|
+
}),
|
|
74
|
+
/* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Button, {
|
|
75
|
+
variant: "ghost",
|
|
76
|
+
size: "sm",
|
|
77
|
+
onClick: () => go(page + 1),
|
|
78
|
+
disabled: page >= pageCount,
|
|
79
|
+
"aria-label": "Next page",
|
|
80
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
81
|
+
className: "hidden sm:inline",
|
|
82
|
+
children: "Next"
|
|
83
|
+
}), /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": true })]
|
|
84
|
+
}) })
|
|
85
|
+
]
|
|
86
|
+
})]
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
export { Pagination, paginationRange };
|
|
91
|
+
|
|
92
|
+
//# sourceMappingURL=pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.js","names":[],"sources":["../../src/components/pagination.tsx"],"sourcesContent":["import ChevronLeft from '@burtson-labs/icons/react/chevron-left';\nimport ChevronRight from '@burtson-labs/icons/react/chevron-right';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { Button } from './button';\n\n/**\n * The page numbers to show: always the first and last page, `siblings` pages\n * either side of the current one, and 'ellipsis' for the gaps.\n */\nexport function paginationRange(\n page: number,\n pageCount: number,\n siblings = 1,\n): (number | 'ellipsis')[] {\n if (pageCount <= 0) return [];\n const window = siblings * 2 + 5; // first, last, current, siblings, two gaps\n if (pageCount <= window) return Array.from({ length: pageCount }, (_, i) => i + 1);\n const start = Math.max(2, page - siblings);\n const end = Math.min(pageCount - 1, page + siblings);\n const out: (number | 'ellipsis')[] = [1];\n if (start > 2) out.push('ellipsis');\n for (let p = start; p <= end; p += 1) out.push(p);\n if (end < pageCount - 1) out.push('ellipsis');\n out.push(pageCount);\n return out;\n}\n\nexport interface PaginationProps extends Omit<React.ComponentProps<'nav'>, 'onChange'> {\n /** 1-based current page. */\n page: number;\n pageCount: number;\n onPageChange: (page: number) => void;\n siblings?: number;\n /** Optional summary on the left, e.g. \"1–25 of 312\". */\n summary?: React.ReactNode;\n}\n\n/** Page controls for a table or list. Buttons are real buttons, keyboard-reachable. */\nfunction Pagination({\n page,\n pageCount,\n onPageChange,\n siblings = 1,\n summary,\n className,\n ...props\n}: PaginationProps) {\n const pages = paginationRange(page, pageCount, siblings);\n const go = (p: number) => onPageChange(Math.min(Math.max(1, p), Math.max(1, pageCount)));\n return (\n <nav\n aria-label=\"Pagination\"\n data-slot=\"pagination\"\n className={cn('flex flex-wrap items-center justify-between gap-3', className)}\n {...props}\n >\n <div className=\"text-xs text-muted-foreground tabular-nums\">{summary}</div>\n <ul className=\"flex items-center gap-1\">\n <li>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => go(page - 1)}\n disabled={page <= 1}\n aria-label=\"Previous page\"\n >\n <ChevronLeft aria-hidden />\n <span className=\"hidden sm:inline\">Previous</span>\n </Button>\n </li>\n {pages.map((p, i) =>\n p === 'ellipsis' ? (\n <li key={`e${i}`} aria-hidden className=\"px-1 text-muted-foreground\">\n …\n </li>\n ) : (\n <li key={p} className=\"hidden sm:block\">\n <Button\n variant={p === page ? 'outline' : 'ghost'}\n size=\"icon-sm\"\n onClick={() => go(p)}\n aria-current={p === page ? 'page' : undefined}\n aria-label={`Page ${p}`}\n className={cn('tabular-nums', p === page && 'border-brand/40 text-brand')}\n >\n {p}\n </Button>\n </li>\n ),\n )}\n <li className=\"px-2 text-xs text-muted-foreground tabular-nums sm:hidden\">\n {page} / {pageCount}\n </li>\n <li>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => go(page + 1)}\n disabled={page >= pageCount}\n aria-label=\"Next page\"\n >\n <span className=\"hidden sm:inline\">Next</span>\n <ChevronRight aria-hidden />\n </Button>\n </li>\n </ul>\n </nav>\n );\n}\n\nexport { Pagination };\n"],"mappings":";;;;;;;;;;;AAYA,SAAgB,gBACd,MACA,WACA,WAAW,GACc;CACzB,IAAI,aAAa,GAAG,OAAO,CAAC;CAE5B,IAAI,aADW,WAAW,IAAI,GACL,OAAO,MAAM,KAAK,EAAE,QAAQ,UAAU,IAAI,GAAG,MAAM,IAAI,CAAC;CACjF,MAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,QAAQ;CACzC,MAAM,MAAM,KAAK,IAAI,YAAY,GAAG,OAAO,QAAQ;CACnD,MAAM,MAA+B,CAAC,CAAC;CACvC,IAAI,QAAQ,GAAG,IAAI,KAAK,UAAU;CAClC,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,KAAK,GAAG,IAAI,KAAK,CAAC;CAChD,IAAI,MAAM,YAAY,GAAG,IAAI,KAAK,UAAU;CAC5C,IAAI,KAAK,SAAS;CAClB,OAAO;AACT;;AAaA,SAAS,WAAW,EAClB,MACA,WACA,cACA,WAAW,GACX,SACA,WACA,GAAG,SACe;CAClB,MAAM,QAAQ,gBAAgB,MAAM,WAAW,QAAQ;CACvD,MAAM,MAAM,MAAc,aAAa,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI,GAAG,SAAS,CAAC,CAAC;CACvF,OACE,qBAAC,OAAD;EACE,cAAW;EACX,aAAU;EACV,WAAW,GAAG,qDAAqD,SAAS;EAC5E,GAAI;EAJN,UAAA,CAME,oBAAC,OAAD;GAAK,WAAU;GAA8C,UAAA;EAAa,CAAA,GAC1E,qBAAC,MAAD;GAAI,WAAU;GAAd,UAAA;IACE,oBAAC,MAAD,EAAA,UACE,qBAAC,QAAD;KACE,SAAQ;KACR,MAAK;KACL,eAAe,GAAG,OAAO,CAAC;KAC1B,UAAU,QAAQ;KAClB,cAAW;KALb,UAAA,CAOE,oBAAC,aAAD,EAAa,eAAA,KAAa,CAAA,GAC1B,oBAAC,QAAD;MAAM,WAAU;MAAmB,UAAA;KAAc,CAAA,CAC3C;IACN,CAAA,EAAA,CAAA;IACH,MAAM,KAAK,GAAG,MACb,MAAM,aACJ,oBAAC,MAAD;KAAkB,eAAA;KAAY,WAAU;KAA6B,UAAA;IAEjE,GAFK,IAAI,GAET,IAEJ,oBAAC,MAAD;KAAY,WAAU;KACpB,UAAA,oBAAC,QAAD;MACE,SAAS,MAAM,OAAO,YAAY;MAClC,MAAK;MACL,eAAe,GAAG,CAAC;MACnB,gBAAc,MAAM,OAAO,SAAS,KAAA;MACpC,cAAY,QAAQ;MACpB,WAAW,GAAG,gBAAgB,MAAM,QAAQ,4BAA4B;MAEvE,UAAA;KACK,CAAA;IACN,GAXK,CAWL,CAER;IACA,qBAAC,MAAD;KAAI,WAAU;KAAd,UAAA;MACG;MAAK;MAAI;KACR;;IACJ,oBAAC,MAAD,EAAA,UACE,qBAAC,QAAD;KACE,SAAQ;KACR,MAAK;KACL,eAAe,GAAG,OAAO,CAAC;KAC1B,UAAU,QAAQ;KAClB,cAAW;KALb,UAAA,CAOE,oBAAC,QAAD;MAAM,WAAU;MAAmB,UAAA;KAAU,CAAA,GAC7C,oBAAC,cAAD,EAAc,eAAA,KAAa,CAAA,CACrB;IACN,CAAA,EAAA,CAAA;GACF;EACD,CAAA,CAAA;;AAET"}
|
|
@@ -4,7 +4,7 @@ import * as React from 'react';
|
|
|
4
4
|
* The floating surface shared by popovers, menus and select lists: raised,
|
|
5
5
|
* with a strong border, and the one place a heavy shadow is allowed.
|
|
6
6
|
*/
|
|
7
|
-
export declare const surfaceClasses = "z-50 animate-in rounded-lg border border-border-strong bg-surface-raised text-popover-foreground shadow-[0_16px_48px_rgb(0_0_0_/_0.18)] data-[state=closed]:animate-out";
|
|
7
|
+
export declare const surfaceClasses = "z-50 animate-in rounded-lg border border-border-strong bg-surface-raised text-popover-foreground shadow-[0_16px_48px_rgb(0_0_0_/_0.18)] data-[state=closed]:animate-out data-[side=bottom]:[--bl-ty:-6px] data-[side=top]:[--bl-ty:6px] data-[side=left]:[--bl-tx:6px] data-[side=right]:[--bl-tx:-6px]";
|
|
8
8
|
declare function Popover(props: React.ComponentProps<typeof PopoverPrimitive.Root>): React.JSX.Element;
|
|
9
9
|
declare function PopoverTrigger(props: React.ComponentProps<typeof PopoverPrimitive.Trigger>): React.JSX.Element;
|
|
10
10
|
declare function PopoverAnchor(props: React.ComponentProps<typeof PopoverPrimitive.Anchor>): React.JSX.Element;
|
|
@@ -7,7 +7,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
7
7
|
* The floating surface shared by popovers, menus and select lists: raised,
|
|
8
8
|
* with a strong border, and the one place a heavy shadow is allowed.
|
|
9
9
|
*/
|
|
10
|
-
var surfaceClasses = "z-50 animate-in rounded-lg border border-border-strong bg-surface-raised text-popover-foreground shadow-[0_16px_48px_rgb(0_0_0_/_0.18)] data-[state=closed]:animate-out";
|
|
10
|
+
var surfaceClasses = "z-50 animate-in rounded-lg border border-border-strong bg-surface-raised text-popover-foreground shadow-[0_16px_48px_rgb(0_0_0_/_0.18)] data-[state=closed]:animate-out data-[side=bottom]:[--bl-ty:-6px] data-[side=top]:[--bl-ty:6px] data-[side=left]:[--bl-tx:6px] data-[side=right]:[--bl-tx:-6px]";
|
|
11
11
|
function Popover$1(props) {
|
|
12
12
|
return /* @__PURE__ */ jsx(Popover.Root, {
|
|
13
13
|
"data-slot": "popover",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popover.js","names":["Popover","PopoverPrimitive"],"sources":["../../src/components/popover.tsx"],"sourcesContent":["import { Popover as PopoverPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\n/**\n * The floating surface shared by popovers, menus and select lists: raised,\n * with a strong border, and the one place a heavy shadow is allowed.\n */\nexport const surfaceClasses =\n 'z-50 animate-in rounded-lg border border-border-strong bg-surface-raised text-popover-foreground shadow-[0_16px_48px_rgb(0_0_0_/_0.18)] data-[state=closed]:animate-out';\n\nfunction Popover(props: React.ComponentProps<typeof PopoverPrimitive.Root>) {\n return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />;\n}\n\nfunction PopoverTrigger(props: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {\n return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />;\n}\n\nfunction PopoverAnchor(props: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {\n return <PopoverPrimitive.Anchor data-slot=\"popover-anchor\" {...props} />;\n}\n\nfunction PopoverContent({\n className,\n align = 'center',\n sideOffset = 6,\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Content>) {\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n data-slot=\"popover-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(\n surfaceClasses,\n 'w-72 origin-(--radix-popover-content-transform-origin) p-4 outline-hidden',\n className,\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n );\n}\n\nexport { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };\n"],"mappings":";;;;;;;;;AASA,IAAa,iBACX;AAEF,SAASA,UAAQ,OAA2D;CAC1E,OAAO,oBAACC,QAAiB,MAAlB;EAAuB,aAAU;EAAU,GAAI;CAAQ,CAAA;AAChE;AAEA,SAAS,eAAe,OAA8D;CACpF,OAAO,oBAACA,QAAiB,SAAlB;EAA0B,aAAU;EAAkB,GAAI;CAAQ,CAAA;AAC3E;AAEA,SAAS,cAAc,OAA6D;CAClF,OAAO,oBAACA,QAAiB,QAAlB;EAAyB,aAAU;EAAiB,GAAI;CAAQ,CAAA;AACzE;AAEA,SAAS,eAAe,EACtB,WACA,QAAQ,UACR,aAAa,GACb,GAAG,SACqD;CACxD,OACE,oBAACA,QAAiB,QAAlB,EAAA,UACE,oBAACA,QAAiB,SAAlB;EACE,aAAU;EACH;EACK;EACZ,WAAW,GACT,gBACA,6EACA,SACF;EACA,GAAI;CACL,CAAA,EACsB,CAAA;AAE7B"}
|
|
1
|
+
{"version":3,"file":"popover.js","names":["Popover","PopoverPrimitive"],"sources":["../../src/components/popover.tsx"],"sourcesContent":["import { Popover as PopoverPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\n/**\n * The floating surface shared by popovers, menus and select lists: raised,\n * with a strong border, and the one place a heavy shadow is allowed.\n */\nexport const surfaceClasses =\n 'z-50 animate-in rounded-lg border border-border-strong bg-surface-raised text-popover-foreground shadow-[0_16px_48px_rgb(0_0_0_/_0.18)] data-[state=closed]:animate-out data-[side=bottom]:[--bl-ty:-6px] data-[side=top]:[--bl-ty:6px] data-[side=left]:[--bl-tx:6px] data-[side=right]:[--bl-tx:-6px]';\n\nfunction Popover(props: React.ComponentProps<typeof PopoverPrimitive.Root>) {\n return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />;\n}\n\nfunction PopoverTrigger(props: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {\n return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />;\n}\n\nfunction PopoverAnchor(props: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {\n return <PopoverPrimitive.Anchor data-slot=\"popover-anchor\" {...props} />;\n}\n\nfunction PopoverContent({\n className,\n align = 'center',\n sideOffset = 6,\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Content>) {\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n data-slot=\"popover-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(\n surfaceClasses,\n 'w-72 origin-(--radix-popover-content-transform-origin) p-4 outline-hidden',\n className,\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n );\n}\n\nexport { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };\n"],"mappings":";;;;;;;;;AASA,IAAa,iBACX;AAEF,SAASA,UAAQ,OAA2D;CAC1E,OAAO,oBAACC,QAAiB,MAAlB;EAAuB,aAAU;EAAU,GAAI;CAAQ,CAAA;AAChE;AAEA,SAAS,eAAe,OAA8D;CACpF,OAAO,oBAACA,QAAiB,SAAlB;EAA0B,aAAU;EAAkB,GAAI;CAAQ,CAAA;AAC3E;AAEA,SAAS,cAAc,OAA6D;CAClF,OAAO,oBAACA,QAAiB,QAAlB;EAAyB,aAAU;EAAiB,GAAI;CAAQ,CAAA;AACzE;AAEA,SAAS,eAAe,EACtB,WACA,QAAQ,UACR,aAAa,GACb,GAAG,SACqD;CACxD,OACE,oBAACA,QAAiB,QAAlB,EAAA,UACE,oBAACA,QAAiB,SAAlB;EACE,aAAU;EACH;EACK;EACZ,WAAW,GACT,gBACA,6EACA,SACF;EACA,GAAI;CACL,CAAA,EACsB,CAAA;AAE7B"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { cn } from "../lib/utils.js";
|
|
2
|
-
import { surfaceClasses } from "./popover.js";
|
|
3
2
|
import { fieldClasses } from "./input.js";
|
|
3
|
+
import { surfaceClasses } from "./popover.js";
|
|
4
4
|
import ChevronDown from "@burtson-labs/icons/react/chevron-down";
|
|
5
5
|
import { Select } from "radix-ui";
|
|
6
6
|
import "react";
|
|
@@ -4,8 +4,10 @@ declare function Sheet(props: React.ComponentProps<typeof SheetPrimitive.Root>):
|
|
|
4
4
|
declare function SheetTrigger(props: React.ComponentProps<typeof SheetPrimitive.Trigger>): React.JSX.Element;
|
|
5
5
|
declare function SheetClose(props: React.ComponentProps<typeof SheetPrimitive.Close>): React.JSX.Element;
|
|
6
6
|
declare const sideClasses: {
|
|
7
|
-
readonly right: "inset-y-0 right-0 h-full w-3/4 border-l [--bl-sheet-
|
|
8
|
-
readonly left: "inset-y-0 left-0 h-full w-3/4 border-r [--bl-sheet-
|
|
7
|
+
readonly right: "inset-y-0 right-0 h-full w-3/4 border-l [--bl-sheet-x:100%] sm:max-w-sm";
|
|
8
|
+
readonly left: "inset-y-0 left-0 h-full w-3/4 border-r [--bl-sheet-x:-100%] sm:max-w-sm";
|
|
9
|
+
readonly top: "inset-x-0 top-0 max-h-[85dvh] rounded-b-xl border-b [--bl-sheet-x:0] [--bl-sheet-y:-100%]";
|
|
10
|
+
readonly bottom: "inset-x-0 bottom-0 max-h-[85dvh] rounded-t-xl border-t [--bl-sheet-x:0] [--bl-sheet-y:100%]";
|
|
9
11
|
};
|
|
10
12
|
declare function SheetContent({ className, children, side, ...props }: React.ComponentProps<typeof SheetPrimitive.Content> & {
|
|
11
13
|
side?: keyof typeof sideClasses;
|
package/dist/components/sheet.js
CHANGED
|
@@ -23,13 +23,15 @@ function SheetClose(props) {
|
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
25
|
var sideClasses = {
|
|
26
|
-
right: "inset-y-0 right-0 h-full w-3/4 border-l [--bl-sheet-
|
|
27
|
-
left: "inset-y-0 left-0 h-full w-3/4 border-r [--bl-sheet-
|
|
26
|
+
right: "inset-y-0 right-0 h-full w-3/4 border-l [--bl-sheet-x:100%] sm:max-w-sm",
|
|
27
|
+
left: "inset-y-0 left-0 h-full w-3/4 border-r [--bl-sheet-x:-100%] sm:max-w-sm",
|
|
28
|
+
top: "inset-x-0 top-0 max-h-[85dvh] rounded-b-xl border-b [--bl-sheet-x:0] [--bl-sheet-y:-100%]",
|
|
29
|
+
bottom: "inset-x-0 bottom-0 max-h-[85dvh] rounded-t-xl border-t [--bl-sheet-x:0] [--bl-sheet-y:100%]"
|
|
28
30
|
};
|
|
29
31
|
function SheetContent({ className, children, side = "right", ...props }) {
|
|
30
32
|
return /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(Dialog.Overlay, {
|
|
31
33
|
"data-slot": "sheet-overlay",
|
|
32
|
-
className: "fixed inset-0 z-50 bg-black/55 backdrop-blur-[3px] data-[state=closed]:animate-out data-[state=open]:animate-in"
|
|
34
|
+
className: "fixed inset-0 z-50 bg-black/55 backdrop-blur-[3px] data-[state=closed]:animate-fade-out data-[state=open]:animate-fade-in"
|
|
33
35
|
}), /* @__PURE__ */ jsxs(Dialog.Content, {
|
|
34
36
|
"data-slot": "sheet-content",
|
|
35
37
|
className: cn("fixed z-50 flex flex-col gap-4 border-border-strong bg-surface-raised text-foreground shadow-[0_24px_80px_rgb(0_0_0_/_0.28)] outline-none data-[state=closed]:animate-sheet-out data-[state=open]:animate-sheet-in", sideClasses[side], className),
|