@burtson-labs/ui 0.7.0 → 0.8.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/dist/components/alert-dialog.js +1 -1
- package/dist/components/alert-dialog.js.map +1 -1
- package/dist/components/alert.js +2 -2
- package/dist/components/alert.js.map +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/button.js +26 -6
- package/dist/components/button.js.map +1 -1
- package/dist/components/checkbox.js +11 -6
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/combobox.d.ts +6 -1
- package/dist/components/combobox.js +25 -6
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/composer.d.ts +5 -3
- package/dist/components/composer.js +46 -9
- package/dist/components/composer.js.map +1 -1
- package/dist/components/conversation.js +2 -2
- package/dist/components/conversation.js.map +1 -1
- package/dist/components/copy-button.d.ts +3 -1
- package/dist/components/copy-button.js +14 -5
- package/dist/components/copy-button.js.map +1 -1
- package/dist/components/dialog.js +1 -1
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/input.d.ts +2 -2
- package/dist/components/input.js +5 -4
- package/dist/components/input.js.map +1 -1
- package/dist/components/markdown.js +5 -14
- package/dist/components/markdown.js.map +1 -1
- package/dist/components/message.js +1 -1
- package/dist/components/message.js.map +1 -1
- package/dist/components/pagination.d.ts +1 -1
- package/dist/components/pagination.js +8 -2
- package/dist/components/pagination.js.map +1 -1
- package/dist/components/popover.js +1 -1
- package/dist/components/popover.js.map +1 -1
- package/dist/components/progress.d.ts +1 -1
- package/dist/components/progress.js +7 -4
- package/dist/components/progress.js.map +1 -1
- package/dist/components/sheet.js +1 -1
- package/dist/components/sheet.js.map +1 -1
- package/dist/components/slider.js +1 -1
- package/dist/components/slider.js.map +1 -1
- package/dist/components/steps.js +2 -2
- package/dist/components/steps.js.map +1 -1
- package/dist/components/textarea.d.ts +1 -1
- package/dist/components/textarea.js +4 -3
- package/dist/components/textarea.js.map +1 -1
- package/dist/components/tool-call.d.ts +3 -1
- package/dist/components/tool-call.js +20 -2
- package/dist/components/tool-call.js.map +1 -1
- package/dist/components/toolbar.js +1 -1
- package/dist/components/toolbar.js.map +1 -1
- package/dist/components/tooltip.js +13 -5
- package/dist/components/tooltip.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -1
- package/dist/lib/platform.d.ts +10 -0
- package/dist/lib/platform.js +24 -0
- package/dist/lib/platform.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/theme.css +28 -1
- package/dist/tokens.js +1 -1
- package/dist/tokens.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IconButton } from "./icon-button.js";
|
|
2
2
|
import { toast } from "./toaster.js";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import Check from "@burtson-labs/icons/react/check";
|
|
6
6
|
import Copy from "@burtson-labs/icons/react/copy";
|
|
7
7
|
//#region src/components/copy-button.tsx
|
|
@@ -10,7 +10,8 @@ import Copy from "@burtson-labs/icons/react/copy";
|
|
|
10
10
|
* browser blocks the clipboard it raises a toast (needs a mounted Toaster)
|
|
11
11
|
* asking the person to copy by hand.
|
|
12
12
|
*/
|
|
13
|
-
function CopyButton({ value, label = "Copy", variant = "ghost", size = "icon-sm", ...props }) {
|
|
13
|
+
function CopyButton({ value, label = "Copy", variant = "ghost", size = "icon-sm", onCopySuccess, onCopyError, ...props }) {
|
|
14
|
+
const [message, setMessage] = React.useState("");
|
|
14
15
|
const [copied, setCopied] = React.useState(false);
|
|
15
16
|
const timer = React.useRef(void 0);
|
|
16
17
|
React.useEffect(() => () => clearTimeout(timer.current), []);
|
|
@@ -18,9 +19,13 @@ function CopyButton({ value, label = "Copy", variant = "ghost", size = "icon-sm"
|
|
|
18
19
|
try {
|
|
19
20
|
await navigator.clipboard.writeText(value);
|
|
20
21
|
setCopied(true);
|
|
22
|
+
setMessage("Copied to clipboard.");
|
|
23
|
+
onCopySuccess?.();
|
|
21
24
|
clearTimeout(timer.current);
|
|
22
25
|
timer.current = setTimeout(() => setCopied(false), 1600);
|
|
23
|
-
} catch {
|
|
26
|
+
} catch (error) {
|
|
27
|
+
setMessage("Copy blocked. Select the text and copy it manually.");
|
|
28
|
+
onCopyError?.(error);
|
|
24
29
|
toast({
|
|
25
30
|
title: "Copy blocked by the browser",
|
|
26
31
|
description: "Select the text and copy it by hand.",
|
|
@@ -28,7 +33,7 @@ function CopyButton({ value, label = "Copy", variant = "ghost", size = "icon-sm"
|
|
|
28
33
|
});
|
|
29
34
|
}
|
|
30
35
|
};
|
|
31
|
-
return /* @__PURE__ */ jsx(IconButton, {
|
|
36
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(IconButton, {
|
|
32
37
|
"data-slot": "copy-button",
|
|
33
38
|
label: copied ? "Copied" : label,
|
|
34
39
|
variant,
|
|
@@ -39,7 +44,11 @@ function CopyButton({ value, label = "Copy", variant = "ghost", size = "icon-sm"
|
|
|
39
44
|
"aria-hidden": true,
|
|
40
45
|
className: "text-success"
|
|
41
46
|
}) : /* @__PURE__ */ jsx(Copy, { "aria-hidden": true })
|
|
42
|
-
})
|
|
47
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
48
|
+
role: "status",
|
|
49
|
+
className: "sr-only",
|
|
50
|
+
children: message
|
|
51
|
+
})] });
|
|
43
52
|
}
|
|
44
53
|
//#endregion
|
|
45
54
|
export { CopyButton };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy-button.js","names":[],"sources":["../../src/components/copy-button.tsx"],"sourcesContent":["import Check from '@burtson-labs/icons/react/check';\nimport Copy from '@burtson-labs/icons/react/copy';\nimport * as React from 'react';\n\nimport { IconButton, type IconButtonProps } from './icon-button';\nimport { toast } from './toaster';\n\nexport interface CopyButtonProps extends Omit<IconButtonProps, 'label' | 'children' | 'onClick'> {\n /** The text to put on the clipboard. */\n value: string;\n /** Accessible name, e.g. \"Copy API key\". */\n label?: string;\n}\n\n/**\n * Icon button that copies `value` and shows a check for a moment. When the\n * browser blocks the clipboard it raises a toast (needs a mounted Toaster)\n * asking the person to copy by hand.\n */\nfunction CopyButton({\n value,\n label = 'Copy',\n variant = 'ghost',\n size = 'icon-sm',\n ...props\n}: CopyButtonProps) {\n const [copied, setCopied] = React.useState(false);\n const timer = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n React.useEffect(() => () => clearTimeout(timer.current), []);\n\n const copy = async () => {\n try {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n clearTimeout(timer.current);\n timer.current = setTimeout(() => setCopied(false), 1600);\n } catch {\n toast({\n title: 'Copy blocked by the browser',\n description: 'Select the text and copy it by hand.',\n variant: 'destructive',\n });\n }\n };\n\n return (\n <IconButton\n
|
|
1
|
+
{"version":3,"file":"copy-button.js","names":["_Fragment"],"sources":["../../src/components/copy-button.tsx"],"sourcesContent":["import Check from '@burtson-labs/icons/react/check';\nimport Copy from '@burtson-labs/icons/react/copy';\nimport * as React from 'react';\n\nimport { IconButton, type IconButtonProps } from './icon-button';\nimport { toast } from './toaster';\n\nexport interface CopyButtonProps extends Omit<IconButtonProps, 'label' | 'children' | 'onClick'> {\n /** The text to put on the clipboard. */\n value: string;\n /** Accessible name, e.g. \"Copy API key\". */\n label?: string;\n onCopySuccess?: () => void;\n onCopyError?: (error: unknown) => void;\n}\n\n/**\n * Icon button that copies `value` and shows a check for a moment. When the\n * browser blocks the clipboard it raises a toast (needs a mounted Toaster)\n * asking the person to copy by hand.\n */\nfunction CopyButton({\n value,\n label = 'Copy',\n variant = 'ghost',\n size = 'icon-sm',\n onCopySuccess,\n onCopyError,\n ...props\n}: CopyButtonProps) {\n const [message, setMessage] = React.useState('');\n const [copied, setCopied] = React.useState(false);\n const timer = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n React.useEffect(() => () => clearTimeout(timer.current), []);\n\n const copy = async () => {\n try {\n await navigator.clipboard.writeText(value);\n setCopied(true);\n setMessage('Copied to clipboard.');\n onCopySuccess?.();\n clearTimeout(timer.current);\n timer.current = setTimeout(() => setCopied(false), 1600);\n } catch (error) {\n setMessage('Copy blocked. Select the text and copy it manually.');\n onCopyError?.(error);\n toast({\n title: 'Copy blocked by the browser',\n description: 'Select the text and copy it by hand.',\n variant: 'destructive',\n });\n }\n };\n\n return (\n <>\n <IconButton\n data-slot=\"copy-button\"\n label={copied ? 'Copied' : label}\n variant={variant}\n size={size}\n onClick={() => void copy()}\n {...props}\n >\n {copied ? <Check aria-hidden className=\"text-success\" /> : <Copy aria-hidden />}\n </IconButton>\n <span role=\"status\" className=\"sr-only\">\n {message}\n </span>\n </>\n );\n}\n\nexport { CopyButton };\n"],"mappings":";;;;;;;;;;;;AAqBA,SAAS,WAAW,EAClB,OACA,QAAQ,QACR,UAAU,SACV,OAAO,WACP,eACA,aACA,GAAG,SACe;CAClB,MAAM,CAAC,SAAS,cAAc,MAAM,SAAS,EAAE;CAC/C,MAAM,CAAC,QAAQ,aAAa,MAAM,SAAS,KAAK;CAChD,MAAM,QAAQ,MAAM,OAAkD,KAAA,CAAS;CAC/E,MAAM,sBAAsB,aAAa,MAAM,OAAO,GAAG,CAAC,CAAC;CAE3D,MAAM,OAAO,YAAY;EACvB,IAAI;GACF,MAAM,UAAU,UAAU,UAAU,KAAK;GACzC,UAAU,IAAI;GACd,WAAW,sBAAsB;GACjC,gBAAgB;GAChB,aAAa,MAAM,OAAO;GAC1B,MAAM,UAAU,iBAAiB,UAAU,KAAK,GAAG,IAAI;EACzD,SAAS,OAAO;GACd,WAAW,qDAAqD;GAChE,cAAc,KAAK;GACnB,MAAM;IACJ,OAAO;IACP,aAAa;IACb,SAAS;GACX,CAAC;EACH;CACF;CAEA,OACE,qBAAAA,UAAA,EAAA,UAAA,CACE,oBAAC,YAAD;EACE,aAAU;EACV,OAAO,SAAS,WAAW;EAClB;EACH;EACN,eAAe,KAAK,KAAK;EACzB,GAAI;EAEH,UAAA,SAAS,oBAAC,OAAD;GAAO,eAAA;GAAY,WAAU;EAAgB,CAAA,IAAI,oBAAC,MAAD,EAAM,eAAA,KAAa,CAAA;CACpE,CAAA,GACZ,oBAAC,QAAD;EAAM,MAAK;EAAS,WAAU;EAC3B,UAAA;CACG,CAAA,CACN,EAAA,CAAA;AAEN"}
|
|
@@ -38,7 +38,7 @@ function DialogOverlay({ className, ...props }) {
|
|
|
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 [--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),
|
|
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),
|
|
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-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,
|
|
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,4 +1,4 @@
|
|
|
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-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: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";
|
|
3
|
-
declare
|
|
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";
|
|
3
|
+
declare const Input: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
4
4
|
export { Input };
|
package/dist/components/input.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { cn } from "../lib/utils.js";
|
|
2
|
-
import "react";
|
|
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-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: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";
|
|
6
|
-
function Input({ className, type, ...props }) {
|
|
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";
|
|
6
|
+
var Input = React.forwardRef(function Input({ className, type, ...props }, ref) {
|
|
7
7
|
return /* @__PURE__ */ jsx("input", {
|
|
8
|
+
ref,
|
|
8
9
|
type,
|
|
9
10
|
"data-slot": "input",
|
|
10
11
|
className: cn(fieldClasses, "h-9 py-1.5 file:mr-3 file:border-0 file:bg-transparent file:text-sm file:font-semibold file:text-foreground", className),
|
|
11
12
|
...props
|
|
12
13
|
});
|
|
13
|
-
}
|
|
14
|
+
});
|
|
14
15
|
//#endregion
|
|
15
16
|
export { Input, fieldClasses };
|
|
16
17
|
|
|
@@ -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-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: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\
|
|
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,8 +1,7 @@
|
|
|
1
1
|
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { CopyButton } from "./copy-button.js";
|
|
2
3
|
import * as React from "react";
|
|
3
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
-
import Check from "@burtson-labs/icons/react/check";
|
|
5
|
-
import Copy from "@burtson-labs/icons/react/copy";
|
|
6
5
|
//#region src/components/markdown.tsx
|
|
7
6
|
var SAFE_HREF = /^(https?:\/\/|mailto:)/i;
|
|
8
7
|
function inline(text, key) {
|
|
@@ -38,7 +37,6 @@ function inline(text, key) {
|
|
|
38
37
|
}
|
|
39
38
|
/** A fenced code block with a language label and a copy button. */
|
|
40
39
|
function CodeBlock({ code, lang, className }) {
|
|
41
|
-
const [copied, setCopied] = React.useState(false);
|
|
42
40
|
return /* @__PURE__ */ jsxs("div", {
|
|
43
41
|
"data-slot": "code-block",
|
|
44
42
|
className: cn("overflow-hidden rounded-md border bg-code text-code-foreground", className),
|
|
@@ -47,17 +45,10 @@ function CodeBlock({ code, lang, className }) {
|
|
|
47
45
|
children: [/* @__PURE__ */ jsx("span", {
|
|
48
46
|
className: "font-mono",
|
|
49
47
|
children: lang || "text"
|
|
50
|
-
}), /* @__PURE__ */ jsx(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
className: "
|
|
54
|
-
onClick: () => {
|
|
55
|
-
navigator.clipboard?.writeText(code).then(() => {
|
|
56
|
-
setCopied(true);
|
|
57
|
-
setTimeout(() => setCopied(false), 1400);
|
|
58
|
-
});
|
|
59
|
-
},
|
|
60
|
-
children: copied ? /* @__PURE__ */ jsx(Check, { "aria-hidden": true }) : /* @__PURE__ */ jsx(Copy, { "aria-hidden": true })
|
|
48
|
+
}), /* @__PURE__ */ jsx(CopyButton, {
|
|
49
|
+
value: code,
|
|
50
|
+
label: "Copy code",
|
|
51
|
+
className: "size-7 text-code-foreground hover:bg-white/10 hover:text-code-foreground"
|
|
61
52
|
})]
|
|
62
53
|
}), /* @__PURE__ */ jsx("pre", {
|
|
63
54
|
className: "overflow-x-auto p-3 font-mono text-[12.5px] leading-5",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.js","names":[],"sources":["../../src/components/markdown.tsx"],"sourcesContent":["import Check from '@burtson-labs/icons/react/check';\nimport Copy from '@burtson-labs/icons/react/copy';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\n/*\n * A small, safe Markdown renderer for chat: paragraphs, headings, bullet and\n * numbered lists, block quotes, fenced code, inline code, bold, italic and\n * links. Everything becomes React elements (never HTML strings), and links\n * only keep http(s) and mailto targets, so model output cannot inject markup\n * or script.\n */\n\nconst SAFE_HREF = /^(https?:\\/\\/|mailto:)/i;\n\nfunction inline(text: string, key: string): React.ReactNode[] {\n const out: React.ReactNode[] = [];\n const pattern =\n /(`[^`]+`)|(\\*\\*[^*]+\\*\\*|__[^_]+__)|(\\*[^*\\s][^*]*\\*|_[^_\\s][^_]*_)|(\\[[^\\]]+\\]\\([^)\\s]+\\))/g;\n let last = 0;\n let n = 0;\n for (const m of text.matchAll(pattern)) {\n const i = m.index;\n if (i > last) out.push(text.slice(last, i));\n const token = m[0];\n const k = `${key}-${n++}`;\n if (m[1]) {\n out.push(\n <code key={k} className=\"rounded-xs bg-muted px-1 py-0.5 font-mono text-[0.85em]\">\n {token.slice(1, -1)}\n </code>,\n );\n } else if (m[2]) {\n out.push(<strong key={k}>{inline(token.slice(2, -2), k)}</strong>);\n } else if (m[3]) {\n out.push(<em key={k}>{inline(token.slice(1, -1), k)}</em>);\n } else {\n const [, label = '', href = ''] = /^\\[([^\\]]+)\\]\\(([^)\\s]+)\\)$/.exec(token) ?? [];\n out.push(\n SAFE_HREF.test(href) ? (\n <a\n key={k}\n href={href}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n className=\"text-brand underline underline-offset-2 hover:text-brand-hover\"\n >\n {label}\n </a>\n ) : (\n label\n ),\n );\n }\n last = i + token.length;\n }\n if (last < text.length) out.push(text.slice(last));\n return out;\n}\n\n/** A fenced code block with a language label and a copy button. */\nfunction CodeBlock({ code, lang, className }: { code: string; lang?: string; className?: string }) {\n const [copied, setCopied] = React.useState(false);\n return (\n <div\n data-slot=\"code-block\"\n className={cn('overflow-hidden rounded-md border bg-code text-code-foreground', className)}\n >\n <div className=\"flex h-8 items-center justify-between border-b border-white/10 px-3 text-[11px] text-code-foreground/60\">\n <span className=\"font-mono\">{lang || 'text'}</span>\n <button\n type=\"button\"\n aria-label={copied ? 'Copied' : 'Copy code'}\n className=\"grid size-6 place-items-center rounded-xs outline-none hover:bg-white/10 focus-visible:ring-[3px] focus-visible:ring-ring/30 [&_svg]:size-3.5\"\n onClick={() => {\n void navigator.clipboard?.writeText(code).then(() => {\n setCopied(true);\n setTimeout(() => setCopied(false), 1400);\n });\n }}\n >\n {copied ? <Check aria-hidden /> : <Copy aria-hidden />}\n </button>\n </div>\n <pre className=\"overflow-x-auto p-3 font-mono text-[12.5px] leading-5\">\n <code>{code}</code>\n </pre>\n </div>\n );\n}\n\ntype Block =\n | { type: 'p'; text: string }\n | { type: 'h'; level: 1 | 2 | 3; text: string }\n | { type: 'ul' | 'ol'; items: string[] }\n | { type: 'quote'; text: string }\n | { type: 'code'; lang: string; code: string };\n\n/** Split Markdown into blocks. Exported for tests. */\nexport function parseMarkdown(source: string): Block[] {\n const lines = source.replace(/\\r\\n?/g, '\\n').split('\\n');\n const blocks: Block[] = [];\n let para: string[] = [];\n const flush = () => {\n if (para.length) blocks.push({ type: 'p', text: para.join(' ') });\n para = [];\n };\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? '';\n const fence = /^```\\s*([\\w+-]*)\\s*$/.exec(line);\n if (fence) {\n flush();\n const code: string[] = [];\n i++;\n while (i < lines.length && !/^```\\s*$/.test(lines[i] ?? '')) code.push(lines[i++] ?? '');\n blocks.push({ type: 'code', lang: fence[1] ?? '', code: code.join('\\n') });\n continue;\n }\n const heading = /^(#{1,3})\\s+(.*)$/.exec(line);\n if (heading) {\n flush();\n blocks.push({\n type: 'h',\n level: (heading[1]?.length ?? 1) as 1 | 2 | 3,\n text: heading[2] ?? '',\n });\n continue;\n }\n const list = /^\\s*([-*]|\\d+[.)])\\s+(.*)$/.exec(line);\n if (list) {\n flush();\n const type = /\\d/.test(list[1] ?? '') ? 'ol' : 'ul';\n const prev = blocks.at(-1);\n if (prev && prev.type === type) prev.items.push(list[2] ?? '');\n else blocks.push({ type, items: [list[2] ?? ''] });\n continue;\n }\n const quote = /^>\\s?(.*)$/.exec(line);\n if (quote) {\n flush();\n blocks.push({ type: 'quote', text: quote[1] ?? '' });\n continue;\n }\n if (!line.trim()) flush();\n else para.push(line.trim());\n }\n flush();\n return blocks;\n}\n\nexport interface MarkdownProps extends Omit<React.ComponentProps<'div'>, 'children'> {\n children: string;\n}\n\n/** Renders a Markdown string safely, for assistant messages. */\nfunction Markdown({ children, className, ...props }: MarkdownProps) {\n const blocks = React.useMemo(() => parseMarkdown(children), [children]);\n return (\n <div\n data-slot=\"markdown\"\n className={cn('grid gap-3 text-sm leading-6 [&_li]:leading-6', className)}\n {...props}\n >\n {blocks.map((b, i) => {\n const k = `b${i}`;\n switch (b.type) {\n case 'h': {\n const Tag = (['h3', 'h4', 'h5'] as const)[b.level - 1] ?? 'h5';\n return (\n <Tag key={k} className=\"font-semibold tracking-[-0.01em]\">\n {inline(b.text, k)}\n </Tag>\n );\n }\n case 'ul':\n case 'ol': {\n const Tag = b.type;\n return (\n <Tag\n key={k}\n className={cn('grid gap-1 pl-5', b.type === 'ul' ? 'list-disc' : 'list-decimal')}\n >\n {b.items.map((item, j) => (\n <li key={`${k}-${j}`}>{inline(item, `${k}-${j}`)}</li>\n ))}\n </Tag>\n );\n }\n case 'quote':\n return (\n <blockquote\n key={k}\n className=\"border-l-2 border-border-strong pl-3 text-muted-foreground\"\n >\n {inline(b.text, k)}\n </blockquote>\n );\n case 'code':\n return <CodeBlock key={k} code={b.code} lang={b.lang} />;\n default:\n return <p key={k}>{inline(b.text, k)}</p>;\n }\n })}\n </div>\n );\n}\n\nexport { CodeBlock, Markdown };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"markdown.js","names":[],"sources":["../../src/components/markdown.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { CopyButton } from './copy-button';\n\n/*\n * A small, safe Markdown renderer for chat: paragraphs, headings, bullet and\n * numbered lists, block quotes, fenced code, inline code, bold, italic and\n * links. Everything becomes React elements (never HTML strings), and links\n * only keep http(s) and mailto targets, so model output cannot inject markup\n * or script.\n */\n\nconst SAFE_HREF = /^(https?:\\/\\/|mailto:)/i;\n\nfunction inline(text: string, key: string): React.ReactNode[] {\n const out: React.ReactNode[] = [];\n const pattern =\n /(`[^`]+`)|(\\*\\*[^*]+\\*\\*|__[^_]+__)|(\\*[^*\\s][^*]*\\*|_[^_\\s][^_]*_)|(\\[[^\\]]+\\]\\([^)\\s]+\\))/g;\n let last = 0;\n let n = 0;\n for (const m of text.matchAll(pattern)) {\n const i = m.index;\n if (i > last) out.push(text.slice(last, i));\n const token = m[0];\n const k = `${key}-${n++}`;\n if (m[1]) {\n out.push(\n <code key={k} className=\"rounded-xs bg-muted px-1 py-0.5 font-mono text-[0.85em]\">\n {token.slice(1, -1)}\n </code>,\n );\n } else if (m[2]) {\n out.push(<strong key={k}>{inline(token.slice(2, -2), k)}</strong>);\n } else if (m[3]) {\n out.push(<em key={k}>{inline(token.slice(1, -1), k)}</em>);\n } else {\n const [, label = '', href = ''] = /^\\[([^\\]]+)\\]\\(([^)\\s]+)\\)$/.exec(token) ?? [];\n out.push(\n SAFE_HREF.test(href) ? (\n <a\n key={k}\n href={href}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n className=\"text-brand underline underline-offset-2 hover:text-brand-hover\"\n >\n {label}\n </a>\n ) : (\n label\n ),\n );\n }\n last = i + token.length;\n }\n if (last < text.length) out.push(text.slice(last));\n return out;\n}\n\n/** A fenced code block with a language label and a copy button. */\nfunction CodeBlock({ code, lang, className }: { code: string; lang?: string; className?: string }) {\n return (\n <div\n data-slot=\"code-block\"\n className={cn('overflow-hidden rounded-md border bg-code text-code-foreground', className)}\n >\n <div className=\"flex h-8 items-center justify-between border-b border-white/10 px-3 text-[11px] text-code-foreground/60\">\n <span className=\"font-mono\">{lang || 'text'}</span>\n <CopyButton\n value={code}\n label=\"Copy code\"\n className=\"size-7 text-code-foreground hover:bg-white/10 hover:text-code-foreground\"\n />\n </div>\n <pre className=\"overflow-x-auto p-3 font-mono text-[12.5px] leading-5\">\n <code>{code}</code>\n </pre>\n </div>\n );\n}\n\ntype Block =\n | { type: 'p'; text: string }\n | { type: 'h'; level: 1 | 2 | 3; text: string }\n | { type: 'ul' | 'ol'; items: string[] }\n | { type: 'quote'; text: string }\n | { type: 'code'; lang: string; code: string };\n\n/** Split Markdown into blocks. Exported for tests. */\nexport function parseMarkdown(source: string): Block[] {\n const lines = source.replace(/\\r\\n?/g, '\\n').split('\\n');\n const blocks: Block[] = [];\n let para: string[] = [];\n const flush = () => {\n if (para.length) blocks.push({ type: 'p', text: para.join(' ') });\n para = [];\n };\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? '';\n const fence = /^```\\s*([\\w+-]*)\\s*$/.exec(line);\n if (fence) {\n flush();\n const code: string[] = [];\n i++;\n while (i < lines.length && !/^```\\s*$/.test(lines[i] ?? '')) code.push(lines[i++] ?? '');\n blocks.push({ type: 'code', lang: fence[1] ?? '', code: code.join('\\n') });\n continue;\n }\n const heading = /^(#{1,3})\\s+(.*)$/.exec(line);\n if (heading) {\n flush();\n blocks.push({\n type: 'h',\n level: (heading[1]?.length ?? 1) as 1 | 2 | 3,\n text: heading[2] ?? '',\n });\n continue;\n }\n const list = /^\\s*([-*]|\\d+[.)])\\s+(.*)$/.exec(line);\n if (list) {\n flush();\n const type = /\\d/.test(list[1] ?? '') ? 'ol' : 'ul';\n const prev = blocks.at(-1);\n if (prev && prev.type === type) prev.items.push(list[2] ?? '');\n else blocks.push({ type, items: [list[2] ?? ''] });\n continue;\n }\n const quote = /^>\\s?(.*)$/.exec(line);\n if (quote) {\n flush();\n blocks.push({ type: 'quote', text: quote[1] ?? '' });\n continue;\n }\n if (!line.trim()) flush();\n else para.push(line.trim());\n }\n flush();\n return blocks;\n}\n\nexport interface MarkdownProps extends Omit<React.ComponentProps<'div'>, 'children'> {\n children: string;\n}\n\n/** Renders a Markdown string safely, for assistant messages. */\nfunction Markdown({ children, className, ...props }: MarkdownProps) {\n const blocks = React.useMemo(() => parseMarkdown(children), [children]);\n return (\n <div\n data-slot=\"markdown\"\n className={cn('grid gap-3 text-sm leading-6 [&_li]:leading-6', className)}\n {...props}\n >\n {blocks.map((b, i) => {\n const k = `b${i}`;\n switch (b.type) {\n case 'h': {\n const Tag = (['h3', 'h4', 'h5'] as const)[b.level - 1] ?? 'h5';\n return (\n <Tag key={k} className=\"font-semibold tracking-[-0.01em]\">\n {inline(b.text, k)}\n </Tag>\n );\n }\n case 'ul':\n case 'ol': {\n const Tag = b.type;\n return (\n <Tag\n key={k}\n className={cn('grid gap-1 pl-5', b.type === 'ul' ? 'list-disc' : 'list-decimal')}\n >\n {b.items.map((item, j) => (\n <li key={`${k}-${j}`}>{inline(item, `${k}-${j}`)}</li>\n ))}\n </Tag>\n );\n }\n case 'quote':\n return (\n <blockquote\n key={k}\n className=\"border-l-2 border-border-strong pl-3 text-muted-foreground\"\n >\n {inline(b.text, k)}\n </blockquote>\n );\n case 'code':\n return <CodeBlock key={k} code={b.code} lang={b.lang} />;\n default:\n return <p key={k}>{inline(b.text, k)}</p>;\n }\n })}\n </div>\n );\n}\n\nexport { CodeBlock, Markdown };\n"],"mappings":"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"}
|
|
@@ -39,7 +39,7 @@ function Message({ from, avatar, name, meta, actions, children, className, ...pr
|
|
|
39
39
|
}),
|
|
40
40
|
/* @__PURE__ */ jsx("div", {
|
|
41
41
|
"data-slot": "message-body",
|
|
42
|
-
className: cn("min-w-0 text-sm leading-6", user && "rounded-lg rounded-tr-xs bg-secondary px-3.5 py-2 text-secondary-foreground"),
|
|
42
|
+
className: cn("min-w-0 break-words text-sm leading-6", user && "rounded-lg rounded-tr-xs bg-secondary px-3.5 py-2 text-secondary-foreground"),
|
|
43
43
|
children
|
|
44
44
|
}),
|
|
45
45
|
actions && /* @__PURE__ */ jsx("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.js","names":[],"sources":["../../src/components/message.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nexport type MessageRole = 'user' | 'assistant' | 'system';\n\nexport interface MessageProps extends React.ComponentProps<'div'> {\n /** Who wrote it. (Not `role`, which is the ARIA attribute.) */\n from: MessageRole;\n /** Avatar or agent mark beside assistant messages. */\n avatar?: React.ReactNode;\n /** Sender name shown above the message, e.g. the agent's name. */\n name?: React.ReactNode;\n /** Timestamp or status text. */\n meta?: React.ReactNode;\n /** Actions such as copy and retry, shown on hover and focus. */\n actions?: React.ReactNode;\n}\n\n/**\n * One turn in a conversation. User turns sit on the right in a quiet bubble,\n * assistant turns read full width with an optional avatar, and system notes\n * are centred and small.\n */\nfunction Message({\n from,\n avatar,\n name,\n meta,\n actions,\n children,\n className,\n ...props\n}: MessageProps) {\n if (from === 'system') {\n return (\n <div\n data-slot=\"message\"\n data-role=\"system\"\n className={cn('mx-auto max-w-prose text-center text-xs text-muted-foreground', className)}\n {...props}\n >\n {children}\n </div>\n );\n }\n const user = from === 'user';\n return (\n <div\n data-slot=\"message\"\n data-role={from}\n className={cn(\n 'group/message flex animate-in gap-3',\n user ? 'justify-end' : 'justify-start',\n className,\n )}\n {...props}\n >\n {!user && avatar && (\n <div className=\"mt-0.5 grid size-7 shrink-0 place-items-center overflow-hidden rounded-md border border-brand/15 bg-brand-soft text-brand [&_svg]:size-4\">\n {avatar}\n </div>\n )}\n <div\n className={cn('grid min-w-0 gap-1.5', user ? 'max-w-[85%] justify-items-end' : 'flex-1')}\n >\n {(name || meta) && (\n <div className=\"flex items-baseline gap-2 text-xs\">\n {name && <span className=\"font-semibold text-foreground\">{name}</span>}\n {meta && <span className=\"text-muted-foreground\">{meta}</span>}\n </div>\n )}\n <div\n data-slot=\"message-body\"\n className={cn(\n 'min-w-0 text-sm leading-6',\n user && 'rounded-lg rounded-tr-xs bg-secondary px-3.5 py-2 text-secondary-foreground',\n )}\n >\n {children}\n </div>\n {actions && (\n <div className=\"flex gap-1 opacity-0 transition-opacity group-focus-within/message:opacity-100 group-hover/message:opacity-100 max-md:opacity-100\">\n {actions}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nexport { Message };\n"],"mappings":";;;;;;;;;AAwBA,SAAS,QAAQ,EACf,MACA,QACA,MACA,MACA,SACA,UACA,WACA,GAAG,SACY;CACf,IAAI,SAAS,UACX,OACE,oBAAC,OAAD;EACE,aAAU;EACV,aAAU;EACV,WAAW,GAAG,iEAAiE,SAAS;EACxF,GAAI;EAEH;CACE,CAAA;CAGT,MAAM,OAAO,SAAS;CACtB,OACE,qBAAC,OAAD;EACE,aAAU;EACV,aAAW;EACX,WAAW,GACT,uCACA,OAAO,gBAAgB,iBACvB,SACF;EACA,GAAI;EARN,UAAA,CAUG,CAAC,QAAQ,UACR,oBAAC,OAAD;GAAK,WAAU;GACZ,UAAA;EACE,CAAA,GAEP,qBAAC,OAAD;GACE,WAAW,GAAG,wBAAwB,OAAO,kCAAkC,QAAQ;GADzF,UAAA;KAGI,QAAQ,SACR,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACG,QAAQ,oBAAC,QAAD;MAAM,WAAU;MAAiC,UAAA;KAAW,CAAA,GACpE,QAAQ,oBAAC,QAAD;MAAM,WAAU;MAAyB,UAAA;KAAW,CAAA,CAC1D;;IAEP,oBAAC,OAAD;KACE,aAAU;KACV,WAAW,GACT,
|
|
1
|
+
{"version":3,"file":"message.js","names":[],"sources":["../../src/components/message.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nexport type MessageRole = 'user' | 'assistant' | 'system';\n\nexport interface MessageProps extends React.ComponentProps<'div'> {\n /** Who wrote it. (Not `role`, which is the ARIA attribute.) */\n from: MessageRole;\n /** Avatar or agent mark beside assistant messages. */\n avatar?: React.ReactNode;\n /** Sender name shown above the message, e.g. the agent's name. */\n name?: React.ReactNode;\n /** Timestamp or status text. */\n meta?: React.ReactNode;\n /** Actions such as copy and retry, shown on hover and focus. */\n actions?: React.ReactNode;\n}\n\n/**\n * One turn in a conversation. User turns sit on the right in a quiet bubble,\n * assistant turns read full width with an optional avatar, and system notes\n * are centred and small.\n */\nfunction Message({\n from,\n avatar,\n name,\n meta,\n actions,\n children,\n className,\n ...props\n}: MessageProps) {\n if (from === 'system') {\n return (\n <div\n data-slot=\"message\"\n data-role=\"system\"\n className={cn('mx-auto max-w-prose text-center text-xs text-muted-foreground', className)}\n {...props}\n >\n {children}\n </div>\n );\n }\n const user = from === 'user';\n return (\n <div\n data-slot=\"message\"\n data-role={from}\n className={cn(\n 'group/message flex animate-in gap-3',\n user ? 'justify-end' : 'justify-start',\n className,\n )}\n {...props}\n >\n {!user && avatar && (\n <div className=\"mt-0.5 grid size-7 shrink-0 place-items-center overflow-hidden rounded-md border border-brand/15 bg-brand-soft text-brand [&_svg]:size-4\">\n {avatar}\n </div>\n )}\n <div\n className={cn('grid min-w-0 gap-1.5', user ? 'max-w-[85%] justify-items-end' : 'flex-1')}\n >\n {(name || meta) && (\n <div className=\"flex items-baseline gap-2 text-xs\">\n {name && <span className=\"font-semibold text-foreground\">{name}</span>}\n {meta && <span className=\"text-muted-foreground\">{meta}</span>}\n </div>\n )}\n <div\n data-slot=\"message-body\"\n className={cn(\n 'min-w-0 break-words text-sm leading-6',\n user && 'rounded-lg rounded-tr-xs bg-secondary px-3.5 py-2 text-secondary-foreground',\n )}\n >\n {children}\n </div>\n {actions && (\n <div className=\"flex gap-1 opacity-0 transition-opacity group-focus-within/message:opacity-100 group-hover/message:opacity-100 max-md:opacity-100\">\n {actions}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nexport { Message };\n"],"mappings":";;;;;;;;;AAwBA,SAAS,QAAQ,EACf,MACA,QACA,MACA,MACA,SACA,UACA,WACA,GAAG,SACY;CACf,IAAI,SAAS,UACX,OACE,oBAAC,OAAD;EACE,aAAU;EACV,aAAU;EACV,WAAW,GAAG,iEAAiE,SAAS;EACxF,GAAI;EAEH;CACE,CAAA;CAGT,MAAM,OAAO,SAAS;CACtB,OACE,qBAAC,OAAD;EACE,aAAU;EACV,aAAW;EACX,WAAW,GACT,uCACA,OAAO,gBAAgB,iBACvB,SACF;EACA,GAAI;EARN,UAAA,CAUG,CAAC,QAAQ,UACR,oBAAC,OAAD;GAAK,WAAU;GACZ,UAAA;EACE,CAAA,GAEP,qBAAC,OAAD;GACE,WAAW,GAAG,wBAAwB,OAAO,kCAAkC,QAAQ;GADzF,UAAA;KAGI,QAAQ,SACR,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACG,QAAQ,oBAAC,QAAD;MAAM,WAAU;MAAiC,UAAA;KAAW,CAAA,GACpE,QAAQ,oBAAC,QAAD;MAAM,WAAU;MAAyB,UAAA;KAAW,CAAA,CAC1D;;IAEP,oBAAC,OAAD;KACE,aAAU;KACV,WAAW,GACT,yCACA,QAAQ,6EACV;KAEC;IACE,CAAA;IACJ,WACC,oBAAC,OAAD;KAAK,WAAU;KACZ,UAAA;IACE,CAAA;GAEJ;EACF,CAAA,CAAA;;AAET"}
|
|
@@ -14,5 +14,5 @@ export interface PaginationProps extends Omit<React.ComponentProps<'nav'>, 'onCh
|
|
|
14
14
|
summary?: React.ReactNode;
|
|
15
15
|
}
|
|
16
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;
|
|
17
|
+
declare function Pagination({ page: requestedPage, pageCount: requestedCount, onPageChange, siblings, summary, className, ...props }: PaginationProps): React.JSX.Element;
|
|
18
18
|
export { Pagination };
|
|
@@ -10,8 +10,12 @@ import ChevronLeft from "@burtson-labs/icons/react/chevron-left";
|
|
|
10
10
|
* either side of the current one, and 'ellipsis' for the gaps.
|
|
11
11
|
*/
|
|
12
12
|
function paginationRange(page, pageCount, siblings = 1) {
|
|
13
|
+
pageCount = Number.isFinite(pageCount) ? Math.max(0, Math.floor(pageCount)) : 0;
|
|
14
|
+
siblings = Number.isFinite(siblings) ? Math.min(5, Math.max(0, Math.floor(siblings))) : 1;
|
|
15
|
+
page = Number.isFinite(page) ? Math.max(1, Math.min(pageCount, Math.floor(page))) : 1;
|
|
13
16
|
if (pageCount <= 0) return [];
|
|
14
|
-
|
|
17
|
+
const window = siblings * 2 + 5;
|
|
18
|
+
if (pageCount <= window) return Array.from({ length: pageCount }, (_, i) => i + 1);
|
|
15
19
|
const start = Math.max(2, page - siblings);
|
|
16
20
|
const end = Math.min(pageCount - 1, page + siblings);
|
|
17
21
|
const out = [1];
|
|
@@ -22,7 +26,9 @@ function paginationRange(page, pageCount, siblings = 1) {
|
|
|
22
26
|
return out;
|
|
23
27
|
}
|
|
24
28
|
/** Page controls for a table or list. Buttons are real buttons, keyboard-reachable. */
|
|
25
|
-
function Pagination({ page, pageCount, onPageChange, siblings = 1, summary, className, ...props }) {
|
|
29
|
+
function Pagination({ page: requestedPage, pageCount: requestedCount, onPageChange, siblings = 1, summary, className, ...props }) {
|
|
30
|
+
const pageCount = Number.isFinite(requestedCount) ? Math.max(0, Math.floor(requestedCount)) : 0;
|
|
31
|
+
const page = pageCount === 0 ? 0 : Number.isFinite(requestedPage) ? Math.max(1, Math.min(pageCount, Math.floor(requestedPage))) : 1;
|
|
26
32
|
const pages = paginationRange(page, pageCount, siblings);
|
|
27
33
|
const go = (p) => onPageChange(Math.min(Math.max(1, p), Math.max(1, pageCount)));
|
|
28
34
|
return /* @__PURE__ */ jsxs("nav", {
|
|
@@ -1 +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,
|
|
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 pageCount = Number.isFinite(pageCount) ? Math.max(0, Math.floor(pageCount)) : 0;\n siblings = Number.isFinite(siblings) ? Math.min(5, Math.max(0, Math.floor(siblings))) : 1;\n page = Number.isFinite(page) ? Math.max(1, Math.min(pageCount, Math.floor(page))) : 1;\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: requestedPage,\n pageCount: requestedCount,\n onPageChange,\n siblings = 1,\n summary,\n className,\n ...props\n}: PaginationProps) {\n const pageCount = Number.isFinite(requestedCount) ? Math.max(0, Math.floor(requestedCount)) : 0;\n const page =\n pageCount === 0\n ? 0\n : Number.isFinite(requestedPage)\n ? Math.max(1, Math.min(pageCount, Math.floor(requestedPage)))\n : 1;\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":"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"}
|
|
@@ -31,7 +31,7 @@ function PopoverContent({ className, align = "center", sideOffset = 6, ...props
|
|
|
31
31
|
"data-slot": "popover-content",
|
|
32
32
|
align,
|
|
33
33
|
sideOffset,
|
|
34
|
-
className: cn(surfaceClasses, "w-72 origin-(--radix-popover-content-transform-origin) p-4 outline-hidden", className),
|
|
34
|
+
className: cn(surfaceClasses, "w-72 max-w-[calc(100vw-2rem)] max-h-(--radix-popover-content-available-height) overflow-y-auto origin-(--radix-popover-content-transform-origin) p-4 outline-hidden", className),
|
|
35
35
|
...props
|
|
36
36
|
}) });
|
|
37
37
|
}
|
|
@@ -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 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,
|
|
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 max-w-[calc(100vw-2rem)] max-h-(--radix-popover-content-available-height) overflow-y-auto 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,uKACA,SACF;EACA,GAAI;CACL,CAAA,EACsB,CAAA;AAE7B"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Progress as ProgressPrimitive } from 'radix-ui';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
declare function Progress({ className, value, ...props }: React.ComponentProps<typeof ProgressPrimitive.Root>): React.JSX.Element;
|
|
3
|
+
declare function Progress({ className, value, max, ...props }: React.ComponentProps<typeof ProgressPrimitive.Root>): React.JSX.Element;
|
|
4
4
|
export { Progress };
|
|
@@ -3,16 +3,19 @@ import { Progress } from "radix-ui";
|
|
|
3
3
|
import "react";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/progress.tsx
|
|
6
|
-
function Progress$1({ className, value, ...props }) {
|
|
6
|
+
function Progress$1({ className, value, max = 100, ...props }) {
|
|
7
|
+
const maximum = Number.isFinite(max) && max > 0 ? max : 100;
|
|
8
|
+
const progress = typeof value === "number" && Number.isFinite(value) ? Math.min(maximum, Math.max(0, value)) : null;
|
|
7
9
|
return /* @__PURE__ */ jsx(Progress.Root, {
|
|
8
10
|
"data-slot": "progress",
|
|
9
|
-
value,
|
|
11
|
+
value: progress,
|
|
12
|
+
max: maximum,
|
|
10
13
|
className: cn("relative h-1.5 w-full overflow-hidden rounded-full bg-muted", className),
|
|
11
14
|
...props,
|
|
12
15
|
children: /* @__PURE__ */ jsx(Progress.Indicator, {
|
|
13
16
|
"data-slot": "progress-indicator",
|
|
14
|
-
className: "h-full
|
|
15
|
-
style: { transform: `translateX(-${100 -
|
|
17
|
+
className: cn("h-full bg-brand transition-transform", progress === null ? "w-1/3 animate-pulse" : "w-full"),
|
|
18
|
+
style: progress === null ? void 0 : { transform: `translateX(-${100 - progress / maximum * 100}%)` }
|
|
16
19
|
})
|
|
17
20
|
});
|
|
18
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"progress.js","names":["Progress","ProgressPrimitive"],"sources":["../../src/components/progress.tsx"],"sourcesContent":["import { Progress as ProgressPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nfunction Progress({\n className,\n value,\n ...props\n}: React.ComponentProps<typeof ProgressPrimitive.Root>) {\n return (\n <ProgressPrimitive.Root\n data-slot=\"progress\"\n value={
|
|
1
|
+
{"version":3,"file":"progress.js","names":["Progress","ProgressPrimitive"],"sources":["../../src/components/progress.tsx"],"sourcesContent":["import { Progress as ProgressPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nfunction Progress({\n className,\n value,\n max = 100,\n ...props\n}: React.ComponentProps<typeof ProgressPrimitive.Root>) {\n const maximum = Number.isFinite(max) && max > 0 ? max : 100;\n const progress =\n typeof value === 'number' && Number.isFinite(value)\n ? Math.min(maximum, Math.max(0, value))\n : null;\n return (\n <ProgressPrimitive.Root\n data-slot=\"progress\"\n value={progress}\n max={maximum}\n className={cn('relative h-1.5 w-full overflow-hidden rounded-full bg-muted', className)}\n {...props}\n >\n <ProgressPrimitive.Indicator\n data-slot=\"progress-indicator\"\n className={cn(\n 'h-full bg-brand transition-transform',\n progress === null ? 'w-1/3 animate-pulse' : 'w-full',\n )}\n style={\n progress === null\n ? undefined\n : { transform: `translateX(-${100 - (progress / maximum) * 100}%)` }\n }\n />\n </ProgressPrimitive.Root>\n );\n}\n\nexport { Progress };\n"],"mappings":";;;;;AAKA,SAASA,WAAS,EAChB,WACA,OACA,MAAM,KACN,GAAG,SACmD;CACtD,MAAM,UAAU,OAAO,SAAS,GAAG,KAAK,MAAM,IAAI,MAAM;CACxD,MAAM,WACJ,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAC9C,KAAK,IAAI,SAAS,KAAK,IAAI,GAAG,KAAK,CAAC,IACpC;CACN,OACE,oBAACC,SAAkB,MAAnB;EACE,aAAU;EACV,OAAO;EACP,KAAK;EACL,WAAW,GAAG,+DAA+D,SAAS;EACtF,GAAI;EAEJ,UAAA,oBAACA,SAAkB,WAAnB;GACE,aAAU;GACV,WAAW,GACT,wCACA,aAAa,OAAO,wBAAwB,QAC9C;GACA,OACE,aAAa,OACT,KAAA,IACA,EAAE,WAAW,eAAe,MAAO,WAAW,UAAW,IAAI,IAAI;EAExE,CAAA;CACqB,CAAA;AAE5B"}
|
package/dist/components/sheet.js
CHANGED
|
@@ -34,7 +34,7 @@ function SheetContent({ className, children, side = "right", ...props }) {
|
|
|
34
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"
|
|
35
35
|
}), /* @__PURE__ */ jsxs(Dialog.Content, {
|
|
36
36
|
"data-slot": "sheet-content",
|
|
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),
|
|
37
|
+
className: cn("fixed z-50 max-h-dvh overflow-y-auto overscroll-contain 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),
|
|
38
38
|
...props,
|
|
39
39
|
children: [children, /* @__PURE__ */ jsxs(Dialog.Close, {
|
|
40
40
|
className: "absolute top-3.5 right-3.5 grid size-8 place-items-center rounded-md text-muted-foreground transition-colors outline-none hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/20 [&_svg]:size-4",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sheet.js","names":["SheetPrimitive"],"sources":["../../src/components/sheet.tsx"],"sourcesContent":["import X from '@burtson-labs/icons/react/x';\nimport { Dialog as SheetPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nfunction Sheet(props: React.ComponentProps<typeof SheetPrimitive.Root>) {\n return <SheetPrimitive.Root data-slot=\"sheet\" {...props} />;\n}\n\nfunction SheetTrigger(props: React.ComponentProps<typeof SheetPrimitive.Trigger>) {\n return <SheetPrimitive.Trigger data-slot=\"sheet-trigger\" {...props} />;\n}\n\nfunction SheetClose(props: React.ComponentProps<typeof SheetPrimitive.Close>) {\n return <SheetPrimitive.Close data-slot=\"sheet-close\" {...props} />;\n}\n\nconst sideClasses = {\n right: 'inset-y-0 right-0 h-full w-3/4 border-l [--bl-sheet-x:100%] sm:max-w-sm',\n left: 'inset-y-0 left-0 h-full w-3/4 border-r [--bl-sheet-x:-100%] sm:max-w-sm',\n // Top and bottom sheets are the mobile drawers.\n top: 'inset-x-0 top-0 max-h-[85dvh] rounded-b-xl border-b [--bl-sheet-x:0] [--bl-sheet-y:-100%]',\n bottom:\n 'inset-x-0 bottom-0 max-h-[85dvh] rounded-t-xl border-t [--bl-sheet-x:0] [--bl-sheet-y:100%]',\n} as const;\n\nfunction SheetContent({\n className,\n children,\n side = 'right',\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Content> & { side?: keyof typeof sideClasses }) {\n return (\n <SheetPrimitive.Portal>\n <SheetPrimitive.Overlay\n data-slot=\"sheet-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 <SheetPrimitive.Content\n data-slot=\"sheet-content\"\n className={cn(\n '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',\n sideClasses[side],\n className,\n )}\n {...props}\n >\n {children}\n <SheetPrimitive.Close className=\"absolute top-3.5 right-3.5 grid size-8 place-items-center rounded-md text-muted-foreground transition-colors outline-none hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/20 [&_svg]:size-4\">\n <X aria-hidden />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n </SheetPrimitive.Content>\n </SheetPrimitive.Portal>\n );\n}\n\nfunction SheetHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"sheet-header\"\n className={cn('flex flex-col gap-1.5 p-4', className)}\n {...props}\n />\n );\n}\n\nfunction SheetFooter({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"sheet-footer\"\n className={cn('mt-auto flex flex-col gap-2 p-4', className)}\n {...props}\n />\n );\n}\n\nfunction SheetTitle({ className, ...props }: React.ComponentProps<typeof SheetPrimitive.Title>) {\n return (\n <SheetPrimitive.Title\n data-slot=\"sheet-title\"\n className={cn('text-base font-semibold tracking-[-0.02em] text-foreground', className)}\n {...props}\n />\n );\n}\n\nfunction SheetDescription({\n className,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Description>) {\n return (\n <SheetPrimitive.Description\n data-slot=\"sheet-description\"\n className={cn('text-sm text-muted-foreground', className)}\n {...props}\n />\n );\n}\n\nexport {\n Sheet,\n SheetClose,\n SheetContent,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetTitle,\n SheetTrigger,\n};\n"],"mappings":";;;;;;AAMA,SAAS,MAAM,OAAyD;CACtE,OAAO,oBAACA,OAAe,MAAhB;EAAqB,aAAU;EAAQ,GAAI;CAAQ,CAAA;AAC5D;AAEA,SAAS,aAAa,OAA4D;CAChF,OAAO,oBAACA,OAAe,SAAhB;EAAwB,aAAU;EAAgB,GAAI;CAAQ,CAAA;AACvE;AAEA,SAAS,WAAW,OAA0D;CAC5E,OAAO,oBAACA,OAAe,OAAhB;EAAsB,aAAU;EAAc,GAAI;CAAQ,CAAA;AACnE;AAEA,IAAM,cAAc;CAClB,OAAO;CACP,MAAM;CAEN,KAAK;CACL,QACE;AACJ;AAEA,SAAS,aAAa,EACpB,WACA,UACA,OAAO,SACP,GAAG,SACyF;CAC5F,OACE,qBAACA,OAAe,QAAhB,EAAA,UAAA,CACE,oBAACA,OAAe,SAAhB;EACE,aAAU;EACV,WAAU;CACX,CAAA,GACD,qBAACA,OAAe,SAAhB;EACE,aAAU;EACV,WAAW,GACT,
|
|
1
|
+
{"version":3,"file":"sheet.js","names":["SheetPrimitive"],"sources":["../../src/components/sheet.tsx"],"sourcesContent":["import X from '@burtson-labs/icons/react/x';\nimport { Dialog as SheetPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nfunction Sheet(props: React.ComponentProps<typeof SheetPrimitive.Root>) {\n return <SheetPrimitive.Root data-slot=\"sheet\" {...props} />;\n}\n\nfunction SheetTrigger(props: React.ComponentProps<typeof SheetPrimitive.Trigger>) {\n return <SheetPrimitive.Trigger data-slot=\"sheet-trigger\" {...props} />;\n}\n\nfunction SheetClose(props: React.ComponentProps<typeof SheetPrimitive.Close>) {\n return <SheetPrimitive.Close data-slot=\"sheet-close\" {...props} />;\n}\n\nconst sideClasses = {\n right: 'inset-y-0 right-0 h-full w-3/4 border-l [--bl-sheet-x:100%] sm:max-w-sm',\n left: 'inset-y-0 left-0 h-full w-3/4 border-r [--bl-sheet-x:-100%] sm:max-w-sm',\n // Top and bottom sheets are the mobile drawers.\n top: 'inset-x-0 top-0 max-h-[85dvh] rounded-b-xl border-b [--bl-sheet-x:0] [--bl-sheet-y:-100%]',\n bottom:\n 'inset-x-0 bottom-0 max-h-[85dvh] rounded-t-xl border-t [--bl-sheet-x:0] [--bl-sheet-y:100%]',\n} as const;\n\nfunction SheetContent({\n className,\n children,\n side = 'right',\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Content> & { side?: keyof typeof sideClasses }) {\n return (\n <SheetPrimitive.Portal>\n <SheetPrimitive.Overlay\n data-slot=\"sheet-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 <SheetPrimitive.Content\n data-slot=\"sheet-content\"\n className={cn(\n 'fixed z-50 max-h-dvh overflow-y-auto overscroll-contain 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',\n sideClasses[side],\n className,\n )}\n {...props}\n >\n {children}\n <SheetPrimitive.Close className=\"absolute top-3.5 right-3.5 grid size-8 place-items-center rounded-md text-muted-foreground transition-colors outline-none hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/20 [&_svg]:size-4\">\n <X aria-hidden />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n </SheetPrimitive.Content>\n </SheetPrimitive.Portal>\n );\n}\n\nfunction SheetHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"sheet-header\"\n className={cn('flex flex-col gap-1.5 p-4', className)}\n {...props}\n />\n );\n}\n\nfunction SheetFooter({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"sheet-footer\"\n className={cn('mt-auto flex flex-col gap-2 p-4', className)}\n {...props}\n />\n );\n}\n\nfunction SheetTitle({ className, ...props }: React.ComponentProps<typeof SheetPrimitive.Title>) {\n return (\n <SheetPrimitive.Title\n data-slot=\"sheet-title\"\n className={cn('text-base font-semibold tracking-[-0.02em] text-foreground', className)}\n {...props}\n />\n );\n}\n\nfunction SheetDescription({\n className,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Description>) {\n return (\n <SheetPrimitive.Description\n data-slot=\"sheet-description\"\n className={cn('text-sm text-muted-foreground', className)}\n {...props}\n />\n );\n}\n\nexport {\n Sheet,\n SheetClose,\n SheetContent,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetTitle,\n SheetTrigger,\n};\n"],"mappings":";;;;;;AAMA,SAAS,MAAM,OAAyD;CACtE,OAAO,oBAACA,OAAe,MAAhB;EAAqB,aAAU;EAAQ,GAAI;CAAQ,CAAA;AAC5D;AAEA,SAAS,aAAa,OAA4D;CAChF,OAAO,oBAACA,OAAe,SAAhB;EAAwB,aAAU;EAAgB,GAAI;CAAQ,CAAA;AACvE;AAEA,SAAS,WAAW,OAA0D;CAC5E,OAAO,oBAACA,OAAe,OAAhB;EAAsB,aAAU;EAAc,GAAI;CAAQ,CAAA;AACnE;AAEA,IAAM,cAAc;CAClB,OAAO;CACP,MAAM;CAEN,KAAK;CACL,QACE;AACJ;AAEA,SAAS,aAAa,EACpB,WACA,UACA,OAAO,SACP,GAAG,SACyF;CAC5F,OACE,qBAACA,OAAe,QAAhB,EAAA,UAAA,CACE,oBAACA,OAAe,SAAhB;EACE,aAAU;EACV,WAAU;CACX,CAAA,GACD,qBAACA,OAAe,SAAhB;EACE,aAAU;EACV,WAAW,GACT,mQACA,YAAY,OACZ,SACF;EACA,GAAI;EAPN,UAAA,CASG,UACD,qBAACA,OAAe,OAAhB;GAAsB,WAAU;GAAhC,UAAA,CACE,oBAAC,GAAD,EAAG,eAAA,KAAa,CAAA,GAChB,oBAAC,QAAD;IAAM,WAAU;IAAU,UAAA;GAAW,CAAA,CACjB;EACA,CAAA,CAAA;CACH,CAAA,CAAA,EAAA,CAAA;AAE3B;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAAsC;CACzE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,6BAA6B,SAAS;EACpD,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAAsC;CACzE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,mCAAmC,SAAS;EAC1D,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,WAAW,EAAE,WAAW,GAAG,SAA4D;CAC9F,OACE,oBAACA,OAAe,OAAhB;EACE,aAAU;EACV,WAAW,GAAG,8DAA8D,SAAS;EACrF,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,iBAAiB,EACxB,WACA,GAAG,SACuD;CAC1D,OACE,oBAACA,OAAe,aAAhB;EACE,aAAU;EACV,WAAW,GAAG,iCAAiC,SAAS;EACxD,GAAI;CACL,CAAA;AAEL"}
|
|
@@ -8,7 +8,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
8
8
|
* number isn't meaningful ("45% change").
|
|
9
9
|
*/
|
|
10
10
|
function Slider({ className, value, onValueChange, min = 0, max = 100, step = 1, style, ...props }) {
|
|
11
|
-
const percent = max > min ? (value - min) / (max - min) * 100 : 0;
|
|
11
|
+
const percent = max > min ? Math.min(100, Math.max(0, (value - min) / (max - min) * 100)) : 0;
|
|
12
12
|
return /* @__PURE__ */ jsx("input", {
|
|
13
13
|
type: "range",
|
|
14
14
|
"data-slot": "slider",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slider.js","names":[],"sources":["../../src/components/slider.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nexport interface SliderProps extends Omit<\n React.ComponentProps<'input'>,\n 'type' | 'value' | 'onChange'\n> {\n value: number;\n onValueChange: (value: number) => void;\n min?: number;\n max?: number;\n step?: number;\n}\n\n/**\n * A single-value range slider on the native input, so keyboard, touch and\n * screen readers work without extra code. Pass `aria-valuetext` when the raw\n * number isn't meaningful (\"45% change\").\n */\nfunction Slider({\n className,\n value,\n onValueChange,\n min = 0,\n max = 100,\n step = 1,\n style,\n ...props\n}: SliderProps) {\n const percent = max > min ? ((value - min) / (max - min)) * 100 : 0;\n return (\n <input\n type=\"range\"\n data-slot=\"slider\"\n min={min}\n max={max}\n step={step}\n value={value}\n onChange={(event) => onValueChange(Number(event.target.value))}\n style={{ ...style, ['--bl-slider-fill' as string]: `${percent}%` }}\n className={cn(\n 'h-5 w-full min-w-0 cursor-pointer appearance-none bg-transparent outline-none disabled:cursor-not-allowed disabled:opacity-60',\n // Track: brand up to the thumb, muted after it.\n '[&::-webkit-slider-runnable-track]:h-1.5 [&::-webkit-slider-runnable-track]:rounded-full',\n '[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_right,var(--color-brand)_var(--bl-slider-fill),var(--color-muted)_var(--bl-slider-fill))]',\n '[&::-moz-range-track]:h-1.5 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-muted',\n '[&::-moz-range-progress]:h-1.5 [&::-moz-range-progress]:rounded-full [&::-moz-range-progress]:bg-brand',\n '[&::-webkit-slider-thumb]:-mt-[5px] [&::-webkit-slider-thumb]:size-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-brand [&::-webkit-slider-thumb]:bg-background [&::-webkit-slider-thumb]:shadow-sm',\n '[&::-moz-range-thumb]:size-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-brand [&::-moz-range-thumb]:bg-background',\n 'focus-visible:[&::-webkit-slider-thumb]:ring-[3px] focus-visible:[&::-webkit-slider-thumb]:ring-ring/30',\n 'focus-visible:[&::-moz-range-thumb]:ring-[3px] focus-visible:[&::-moz-range-thumb]:ring-ring/30',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport { Slider };\n"],"mappings":";;;;;;;;;AAoBA,SAAS,OAAO,EACd,WACA,OACA,eACA,MAAM,GACN,MAAM,KACN,OAAO,GACP,OACA,GAAG,SACW;CACd,MAAM,UAAU,MAAM,
|
|
1
|
+
{"version":3,"file":"slider.js","names":[],"sources":["../../src/components/slider.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nexport interface SliderProps extends Omit<\n React.ComponentProps<'input'>,\n 'type' | 'value' | 'onChange'\n> {\n value: number;\n onValueChange: (value: number) => void;\n min?: number;\n max?: number;\n step?: number;\n}\n\n/**\n * A single-value range slider on the native input, so keyboard, touch and\n * screen readers work without extra code. Pass `aria-valuetext` when the raw\n * number isn't meaningful (\"45% change\").\n */\nfunction Slider({\n className,\n value,\n onValueChange,\n min = 0,\n max = 100,\n step = 1,\n style,\n ...props\n}: SliderProps) {\n const percent = max > min ? Math.min(100, Math.max(0, ((value - min) / (max - min)) * 100)) : 0;\n return (\n <input\n type=\"range\"\n data-slot=\"slider\"\n min={min}\n max={max}\n step={step}\n value={value}\n onChange={(event) => onValueChange(Number(event.target.value))}\n style={{ ...style, ['--bl-slider-fill' as string]: `${percent}%` }}\n className={cn(\n 'h-5 w-full min-w-0 cursor-pointer appearance-none bg-transparent outline-none disabled:cursor-not-allowed disabled:opacity-60',\n // Track: brand up to the thumb, muted after it.\n '[&::-webkit-slider-runnable-track]:h-1.5 [&::-webkit-slider-runnable-track]:rounded-full',\n '[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_right,var(--color-brand)_var(--bl-slider-fill),var(--color-muted)_var(--bl-slider-fill))]',\n '[&::-moz-range-track]:h-1.5 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-muted',\n '[&::-moz-range-progress]:h-1.5 [&::-moz-range-progress]:rounded-full [&::-moz-range-progress]:bg-brand',\n '[&::-webkit-slider-thumb]:-mt-[5px] [&::-webkit-slider-thumb]:size-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-brand [&::-webkit-slider-thumb]:bg-background [&::-webkit-slider-thumb]:shadow-sm',\n '[&::-moz-range-thumb]:size-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-brand [&::-moz-range-thumb]:bg-background',\n 'focus-visible:[&::-webkit-slider-thumb]:ring-[3px] focus-visible:[&::-webkit-slider-thumb]:ring-ring/30',\n 'focus-visible:[&::-moz-range-thumb]:ring-[3px] focus-visible:[&::-moz-range-thumb]:ring-ring/30',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport { Slider };\n"],"mappings":";;;;;;;;;AAoBA,SAAS,OAAO,EACd,WACA,OACA,eACA,MAAM,GACN,MAAM,KACN,OAAO,GACP,OACA,GAAG,SACW;CACd,MAAM,UAAU,MAAM,MAAM,KAAK,IAAI,KAAK,KAAK,IAAI,IAAK,QAAQ,QAAQ,MAAM,OAAQ,GAAG,CAAC,IAAI;CAC9F,OACE,oBAAC,SAAD;EACE,MAAK;EACL,aAAU;EACL;EACA;EACC;EACC;EACP,WAAW,UAAU,cAAc,OAAO,MAAM,OAAO,KAAK,CAAC;EAC7D,OAAO;GAAE,GAAG;IAAQ,qBAA+B,GAAG,QAAQ;EAAG;EACjE,WAAW,GACT,iIAEA,4FACA,uJACA,iGACA,0GACA,+SACA,yKACA,2GACA,mGACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
|
package/dist/components/steps.js
CHANGED
|
@@ -17,7 +17,7 @@ function Steps({ items, current, orientation = "horizontal", className, ...props
|
|
|
17
17
|
"aria-current": state === "current" ? "step" : void 0,
|
|
18
18
|
className: cn("flex min-w-0 items-start gap-2.5", orientation === "horizontal" && "flex-1"),
|
|
19
19
|
children: [/* @__PURE__ */ jsx("span", {
|
|
20
|
-
className: cn("grid size-6 shrink-0 place-items-center rounded-full border text-xs font-semibold tabular-nums", state === "complete" && "border-
|
|
20
|
+
className: cn("grid size-6 shrink-0 place-items-center rounded-full border text-xs font-semibold tabular-nums", state === "complete" && "border-primary bg-primary text-primary-foreground", state === "current" && "border-brand bg-brand-soft text-brand", state === "upcoming" && "border-border-strong text-muted-foreground"),
|
|
21
21
|
children: state === "complete" ? /* @__PURE__ */ jsx(Check, {
|
|
22
22
|
className: "size-3.5",
|
|
23
23
|
"aria-hidden": true
|
|
@@ -25,7 +25,7 @@ function Steps({ items, current, orientation = "horizontal", className, ...props
|
|
|
25
25
|
}), /* @__PURE__ */ jsxs("span", {
|
|
26
26
|
className: "grid min-w-0 gap-0.5 pt-0.5",
|
|
27
27
|
children: [/* @__PURE__ */ jsxs("span", {
|
|
28
|
-
className: cn("
|
|
28
|
+
className: cn("break-words text-[13px] font-semibold", state === "upcoming" && "text-muted-foreground"),
|
|
29
29
|
children: [item.title, /* @__PURE__ */ jsx("span", {
|
|
30
30
|
className: "sr-only",
|
|
31
31
|
children: state === "complete" ? " (done)" : state === "current" ? " (current)" : ""
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"steps.js","names":[],"sources":["../../src/components/steps.tsx"],"sourcesContent":["import Check from '@burtson-labs/icons/react/check';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nexport interface StepItem {\n title: React.ReactNode;\n description?: React.ReactNode;\n}\n\nexport interface StepsProps extends React.ComponentProps<'ol'> {\n items: StepItem[];\n /** 0-based index of the step in progress; earlier steps show as done. */\n current: number;\n orientation?: 'horizontal' | 'vertical';\n}\n\n/** Progress through a short multi-step flow (a wizard, an onboarding). */\nfunction Steps({ items, current, orientation = 'horizontal', className, ...props }: StepsProps) {\n return (\n <ol\n data-slot=\"steps\"\n data-orientation={orientation}\n className={cn(\n 'flex gap-3',\n orientation === 'horizontal' ? 'flex-row items-start' : 'flex-col',\n className,\n )}\n {...props}\n >\n {items.map((item, i) => {\n const state = i < current ? 'complete' : i === current ? 'current' : 'upcoming';\n return (\n <li\n key={i}\n data-state={state}\n aria-current={state === 'current' ? 'step' : undefined}\n className={cn(\n 'flex min-w-0 items-start gap-2.5',\n orientation === 'horizontal' && 'flex-1',\n )}\n >\n <span\n className={cn(\n 'grid size-6 shrink-0 place-items-center rounded-full border text-xs font-semibold tabular-nums',\n state === 'complete' && 'border-
|
|
1
|
+
{"version":3,"file":"steps.js","names":[],"sources":["../../src/components/steps.tsx"],"sourcesContent":["import Check from '@burtson-labs/icons/react/check';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nexport interface StepItem {\n title: React.ReactNode;\n description?: React.ReactNode;\n}\n\nexport interface StepsProps extends React.ComponentProps<'ol'> {\n items: StepItem[];\n /** 0-based index of the step in progress; earlier steps show as done. */\n current: number;\n orientation?: 'horizontal' | 'vertical';\n}\n\n/** Progress through a short multi-step flow (a wizard, an onboarding). */\nfunction Steps({ items, current, orientation = 'horizontal', className, ...props }: StepsProps) {\n return (\n <ol\n data-slot=\"steps\"\n data-orientation={orientation}\n className={cn(\n 'flex gap-3',\n orientation === 'horizontal' ? 'flex-row items-start' : 'flex-col',\n className,\n )}\n {...props}\n >\n {items.map((item, i) => {\n const state = i < current ? 'complete' : i === current ? 'current' : 'upcoming';\n return (\n <li\n key={i}\n data-state={state}\n aria-current={state === 'current' ? 'step' : undefined}\n className={cn(\n 'flex min-w-0 items-start gap-2.5',\n orientation === 'horizontal' && 'flex-1',\n )}\n >\n <span\n className={cn(\n 'grid size-6 shrink-0 place-items-center rounded-full border text-xs font-semibold tabular-nums',\n state === 'complete' && 'border-primary bg-primary text-primary-foreground',\n state === 'current' && 'border-brand bg-brand-soft text-brand',\n state === 'upcoming' && 'border-border-strong text-muted-foreground',\n )}\n >\n {state === 'complete' ? <Check className=\"size-3.5\" aria-hidden /> : i + 1}\n </span>\n <span className=\"grid min-w-0 gap-0.5 pt-0.5\">\n <span\n className={cn(\n 'break-words text-[13px] font-semibold',\n state === 'upcoming' && 'text-muted-foreground',\n )}\n >\n {item.title}\n <span className=\"sr-only\">\n {state === 'complete' ? ' (done)' : state === 'current' ? ' (current)' : ''}\n </span>\n </span>\n {item.description && (\n <span className=\"text-xs text-muted-foreground\">{item.description}</span>\n )}\n </span>\n </li>\n );\n })}\n </ol>\n );\n}\n\nexport { Steps };\n"],"mappings":";;;;;;AAkBA,SAAS,MAAM,EAAE,OAAO,SAAS,cAAc,cAAc,WAAW,GAAG,SAAqB;CAC9F,OACE,oBAAC,MAAD;EACE,aAAU;EACV,oBAAkB;EAClB,WAAW,GACT,cACA,gBAAgB,eAAe,yBAAyB,YACxD,SACF;EACA,GAAI;EAEH,UAAA,MAAM,KAAK,MAAM,MAAM;GACtB,MAAM,QAAQ,IAAI,UAAU,aAAa,MAAM,UAAU,YAAY;GACrE,OACE,qBAAC,MAAD;IAEE,cAAY;IACZ,gBAAc,UAAU,YAAY,SAAS,KAAA;IAC7C,WAAW,GACT,oCACA,gBAAgB,gBAAgB,QAClC;IAPF,UAAA,CASE,oBAAC,QAAD;KACE,WAAW,GACT,kGACA,UAAU,cAAc,qDACxB,UAAU,aAAa,yCACvB,UAAU,cAAc,4CAC1B;KAEC,UAAA,UAAU,aAAa,oBAAC,OAAD;MAAO,WAAU;MAAW,eAAA;KAAa,CAAA,IAAI,IAAI;IACrE,CAAA,GACN,qBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CACE,qBAAC,QAAD;MACE,WAAW,GACT,yCACA,UAAU,cAAc,uBAC1B;MAJF,UAAA,CAMG,KAAK,OACN,oBAAC,QAAD;OAAM,WAAU;OACb,UAAA,UAAU,aAAa,YAAY,UAAU,YAAY,eAAe;MACrE,CAAA,CACF;KACL,CAAA,GAAA,KAAK,eACJ,oBAAC,QAAD;MAAM,WAAU;MAAiC,UAAA,KAAK;KAAkB,CAAA,CAEtE;IACJ,CAAA,CAAA;GAlCG,GAAA,CAkCH;EAER,CAAC;CACC,CAAA;AAER"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
declare
|
|
2
|
+
declare const Textarea: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, "ref"> & React.RefAttributes<HTMLTextAreaElement>>;
|
|
3
3
|
export { Textarea };
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { cn } from "../lib/utils.js";
|
|
2
2
|
import { fieldClasses } from "./input.js";
|
|
3
|
-
import "react";
|
|
3
|
+
import * as React from "react";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/textarea.tsx
|
|
6
|
-
function Textarea({ className, ...props }) {
|
|
6
|
+
var Textarea = React.forwardRef(function Textarea({ className, ...props }, ref) {
|
|
7
7
|
return /* @__PURE__ */ jsx("textarea", {
|
|
8
|
+
ref,
|
|
8
9
|
"data-slot": "textarea",
|
|
9
10
|
className: cn(fieldClasses, "min-h-24 resize-y py-2.5 leading-5", className),
|
|
10
11
|
...props
|
|
11
12
|
});
|
|
12
|
-
}
|
|
13
|
+
});
|
|
13
14
|
//#endregion
|
|
14
15
|
export { Textarea };
|
|
15
16
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textarea.js","names":[],"sources":["../../src/components/textarea.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { fieldClasses } from './input';\n\
|
|
1
|
+
{"version":3,"file":"textarea.js","names":[],"sources":["../../src/components/textarea.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { fieldClasses } from './input';\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, React.ComponentProps<'textarea'>>(\n function Textarea({ className, ...props }: React.ComponentProps<'textarea'>, ref) {\n return (\n <textarea\n ref={ref}\n data-slot=\"textarea\"\n className={cn(fieldClasses, 'min-h-24 resize-y py-2.5 leading-5', className)}\n {...props}\n />\n );\n },\n);\n\nexport { Textarea };\n"],"mappings":";;;;;AAMA,IAAM,WAAW,MAAM,WACrB,SAAS,SAAS,EAAE,WAAW,GAAG,SAA2C,KAAK;CAChF,OACE,oBAAC,YAAD;EACO;EACL,aAAU;EACV,WAAW,GAAG,cAAc,sCAAsC,SAAS;EAC3E,GAAI;CACL,CAAA;AAEL,CACF"}
|