@boyernick/standard-ui-react 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/package.json +46 -0
- package/src/accordion.tsx +84 -0
- package/src/alert-dialog.tsx +101 -0
- package/src/attachment.tsx +138 -0
- package/src/autocomplete.tsx +281 -0
- package/src/avatar.tsx +56 -0
- package/src/badge.tsx +28 -0
- package/src/brand.tsx +70 -0
- package/src/breadcrumb.tsx +81 -0
- package/src/button.tsx +129 -0
- package/src/calendar.tsx +84 -0
- package/src/card.tsx +54 -0
- package/src/carousel.tsx +253 -0
- package/src/chart.tsx +185 -0
- package/src/checkbox-group.tsx +14 -0
- package/src/checkbox.tsx +31 -0
- package/src/code-block.tsx +124 -0
- package/src/collapsible.tsx +61 -0
- package/src/combobox.tsx +324 -0
- package/src/command.tsx +377 -0
- package/src/context-menu.tsx +250 -0
- package/src/dialog.tsx +78 -0
- package/src/drawer.tsx +156 -0
- package/src/empty.tsx +52 -0
- package/src/field.tsx +75 -0
- package/src/fieldset.tsx +25 -0
- package/src/form.tsx +14 -0
- package/src/icons.tsx +91 -0
- package/src/illustrations.tsx +167 -0
- package/src/image-modal.tsx +110 -0
- package/src/index.ts +833 -0
- package/src/input.tsx +68 -0
- package/src/lib/cn.ts +3 -0
- package/src/lib/motion.ts +23 -0
- package/src/markdown-editor.tsx +302 -0
- package/src/menu.tsx +205 -0
- package/src/menubar.tsx +22 -0
- package/src/meter.tsx +61 -0
- package/src/navigation-menu.tsx +217 -0
- package/src/number-field.tsx +119 -0
- package/src/orb.tsx +33 -0
- package/src/otp-field.tsx +45 -0
- package/src/pagination.tsx +91 -0
- package/src/popover.tsx +92 -0
- package/src/preview-card.tsx +103 -0
- package/src/progress.tsx +60 -0
- package/src/radio.tsx +43 -0
- package/src/scroll-area.tsx +67 -0
- package/src/select.tsx +161 -0
- package/src/separator.tsx +17 -0
- package/src/sidebar.tsx +82 -0
- package/src/skeleton.tsx +32 -0
- package/src/slider.tsx +56 -0
- package/src/sounds.tsx +270 -0
- package/src/spinner.tsx +45 -0
- package/src/switch.tsx +19 -0
- package/src/table.tsx +81 -0
- package/src/tabs.tsx +62 -0
- package/src/text-animate.tsx +155 -0
- package/src/textarea.tsx +58 -0
- package/src/ticker.tsx +74 -0
- package/src/toast.tsx +142 -0
- package/src/toggle.tsx +32 -0
- package/src/toolbar.tsx +75 -0
- package/src/tooltip.tsx +55 -0
- package/src/video-player.tsx +241 -0
package/README.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @boyernick/standard-ui-react
|
|
2
|
+
|
|
3
|
+
Styled React components for StandardUI. Interactive controls wrap [Base UI](https://base-ui.com); atoms (Button, Input, Badge) are token-styled DOM.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Button, Input, Badge, Switch, Checkbox } from "@boyernick/standard-ui-react"
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Requires `@boyernick/standard-ui-tokens` CSS, Tailwind v4 `@source` for this package’s `src`, and a Central Icons license (`CENTRAL_LICENSE_KEY`) to install `@central-icons-react/round-outlined-radius-2-stroke-2`. See the repo root README.
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@boyernick/standard-ui-react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React components for StandardUI",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"files": [
|
|
9
|
+
"src"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./src/index.ts",
|
|
14
|
+
"default": "./src/index.ts"
|
|
15
|
+
},
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
20
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@base-ui/react": "^1.7.0",
|
|
24
|
+
"@central-icons-react/round-outlined-radius-2-stroke-2": "^1.1.312",
|
|
25
|
+
"class-variance-authority": "^0.7.1",
|
|
26
|
+
"clsx": "^2.1.1",
|
|
27
|
+
"date-fns": "^4.4.0",
|
|
28
|
+
"embla-carousel-react": "^8.6.0",
|
|
29
|
+
"react-day-picker": "^10.0.1",
|
|
30
|
+
"recharts": "^3.10.1",
|
|
31
|
+
"sugar-high": "^2.0.1"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/react": "^19",
|
|
35
|
+
"@types/react-dom": "^19",
|
|
36
|
+
"typescript": "^5"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/boyernick/standard-ui.git",
|
|
44
|
+
"directory": "packages/react"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { Accordion as BaseAccordion } from "@base-ui/react/accordion"
|
|
4
|
+
import type { ComponentProps } from "react"
|
|
5
|
+
import { IconChevronBottom } from "./icons"
|
|
6
|
+
import { cn } from "./lib/cn"
|
|
7
|
+
import { motion } from "./lib/motion"
|
|
8
|
+
|
|
9
|
+
export type AccordionProps = ComponentProps<typeof BaseAccordion.Root>
|
|
10
|
+
export type AccordionItemProps = ComponentProps<typeof BaseAccordion.Item>
|
|
11
|
+
export type AccordionHeaderProps = ComponentProps<typeof BaseAccordion.Header>
|
|
12
|
+
export type AccordionTriggerProps = ComponentProps<typeof BaseAccordion.Trigger>
|
|
13
|
+
export type AccordionPanelProps = ComponentProps<typeof BaseAccordion.Panel>
|
|
14
|
+
|
|
15
|
+
export const Accordion = ({ className, ...props }: AccordionProps) => (
|
|
16
|
+
<BaseAccordion.Root
|
|
17
|
+
className={cn(
|
|
18
|
+
"flex w-full flex-col overflow-hidden rounded-xl border border-border-primary bg-surface",
|
|
19
|
+
className,
|
|
20
|
+
)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
export const AccordionItem = ({ className, ...props }: AccordionItemProps) => (
|
|
26
|
+
<BaseAccordion.Item
|
|
27
|
+
className={cn(
|
|
28
|
+
"flex flex-col border-b border-border-primary last:border-b-0",
|
|
29
|
+
className,
|
|
30
|
+
)}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
export const AccordionHeader = ({
|
|
36
|
+
className,
|
|
37
|
+
...props
|
|
38
|
+
}: AccordionHeaderProps) => (
|
|
39
|
+
<BaseAccordion.Header className={cn("m-0", className)} {...props} />
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
export const AccordionTrigger = ({
|
|
43
|
+
className,
|
|
44
|
+
children,
|
|
45
|
+
...props
|
|
46
|
+
}: AccordionTriggerProps) => (
|
|
47
|
+
<BaseAccordion.Trigger
|
|
48
|
+
className={cn(
|
|
49
|
+
"group flex w-full cursor-pointer items-center justify-between gap-3 px-4 py-3.5 text-left text-sm text-fg-primary outline-none",
|
|
50
|
+
motion.colors,
|
|
51
|
+
"hover:bg-background-tertiary focus-visible:relative focus-visible:z-10 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-offset-1 focus-visible:ring-offset-background-primary focus-visible:ring-ring/20 data-disabled:cursor-not-allowed data-disabled:opacity-50",
|
|
52
|
+
className,
|
|
53
|
+
)}
|
|
54
|
+
{...props}
|
|
55
|
+
>
|
|
56
|
+
<span className="min-w-0 flex-1">{children}</span>
|
|
57
|
+
<IconChevronBottom
|
|
58
|
+
size={16}
|
|
59
|
+
className={cn(
|
|
60
|
+
"size-4 shrink-0 text-fg-tertiary",
|
|
61
|
+
motion.transform,
|
|
62
|
+
"group-data-panel-open:rotate-180",
|
|
63
|
+
)}
|
|
64
|
+
aria-hidden
|
|
65
|
+
/>
|
|
66
|
+
</BaseAccordion.Trigger>
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
export const AccordionPanel = ({
|
|
70
|
+
className,
|
|
71
|
+
children,
|
|
72
|
+
...props
|
|
73
|
+
}: AccordionPanelProps) => (
|
|
74
|
+
<BaseAccordion.Panel
|
|
75
|
+
className={cn(
|
|
76
|
+
"h-[var(--accordion-panel-height)] overflow-hidden text-sm text-fg-secondary",
|
|
77
|
+
motion.accordionPanel,
|
|
78
|
+
className,
|
|
79
|
+
)}
|
|
80
|
+
{...props}
|
|
81
|
+
>
|
|
82
|
+
<div className="px-4 pt-0 pb-4 leading-relaxed">{children}</div>
|
|
83
|
+
</BaseAccordion.Panel>
|
|
84
|
+
)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { AlertDialog as BaseAlertDialog } from "@base-ui/react/alert-dialog"
|
|
4
|
+
import type { ComponentProps, HTMLAttributes } from "react"
|
|
5
|
+
import { cn } from "./lib/cn"
|
|
6
|
+
import { motion } from "./lib/motion"
|
|
7
|
+
|
|
8
|
+
export type AlertDialogProps = ComponentProps<typeof BaseAlertDialog.Root>
|
|
9
|
+
export type AlertDialogTriggerProps = ComponentProps<
|
|
10
|
+
typeof BaseAlertDialog.Trigger
|
|
11
|
+
>
|
|
12
|
+
export type AlertDialogPortalProps = ComponentProps<
|
|
13
|
+
typeof BaseAlertDialog.Portal
|
|
14
|
+
>
|
|
15
|
+
export type AlertDialogBackdropProps = ComponentProps<
|
|
16
|
+
typeof BaseAlertDialog.Backdrop
|
|
17
|
+
>
|
|
18
|
+
export type AlertDialogPopupProps = ComponentProps<typeof BaseAlertDialog.Popup>
|
|
19
|
+
export type AlertDialogTitleProps = ComponentProps<typeof BaseAlertDialog.Title>
|
|
20
|
+
export type AlertDialogDescriptionProps = ComponentProps<
|
|
21
|
+
typeof BaseAlertDialog.Description
|
|
22
|
+
>
|
|
23
|
+
export type AlertDialogCloseProps = ComponentProps<typeof BaseAlertDialog.Close>
|
|
24
|
+
export type AlertDialogHeaderProps = HTMLAttributes<HTMLDivElement>
|
|
25
|
+
|
|
26
|
+
export const AlertDialog = (props: AlertDialogProps) => (
|
|
27
|
+
<BaseAlertDialog.Root {...props} />
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
export const AlertDialogTrigger = ({
|
|
31
|
+
className,
|
|
32
|
+
...props
|
|
33
|
+
}: AlertDialogTriggerProps) => (
|
|
34
|
+
<BaseAlertDialog.Trigger className={cn(className)} {...props} />
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
export const AlertDialogPortal = (props: AlertDialogPortalProps) => (
|
|
38
|
+
<BaseAlertDialog.Portal {...props} />
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
export const AlertDialogBackdrop = ({
|
|
42
|
+
className,
|
|
43
|
+
...props
|
|
44
|
+
}: AlertDialogBackdropProps) => (
|
|
45
|
+
<BaseAlertDialog.Backdrop
|
|
46
|
+
className={cn(
|
|
47
|
+
"fixed inset-0 z-50 bg-black/40 dark:bg-black/60",
|
|
48
|
+
motion.backdrop,
|
|
49
|
+
className,
|
|
50
|
+
)}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
export const AlertDialogPopup = ({
|
|
56
|
+
className,
|
|
57
|
+
...props
|
|
58
|
+
}: AlertDialogPopupProps) => (
|
|
59
|
+
<BaseAlertDialog.Popup
|
|
60
|
+
className={cn(
|
|
61
|
+
"fixed top-1/2 left-1/2 z-50 flex w-full max-w-md -translate-x-1/2 -translate-y-1/2 flex-col gap-6 rounded-xl border border-border-primary bg-surface p-5 shadow-md outline-none max-sm:max-w-[calc(100vw-2rem)]",
|
|
62
|
+
motion.popupCenter,
|
|
63
|
+
className,
|
|
64
|
+
)}
|
|
65
|
+
{...props}
|
|
66
|
+
/>
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
export const AlertDialogTitle = ({
|
|
70
|
+
className,
|
|
71
|
+
...props
|
|
72
|
+
}: AlertDialogTitleProps) => (
|
|
73
|
+
<BaseAlertDialog.Title
|
|
74
|
+
className={cn("text-sm-strong text-fg-primary", className)}
|
|
75
|
+
{...props}
|
|
76
|
+
/>
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
export const AlertDialogDescription = ({
|
|
80
|
+
className,
|
|
81
|
+
...props
|
|
82
|
+
}: AlertDialogDescriptionProps) => (
|
|
83
|
+
<BaseAlertDialog.Description
|
|
84
|
+
className={cn("text-sm leading-relaxed text-fg-secondary", className)}
|
|
85
|
+
{...props}
|
|
86
|
+
/>
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
export const AlertDialogClose = ({
|
|
90
|
+
className,
|
|
91
|
+
...props
|
|
92
|
+
}: AlertDialogCloseProps) => (
|
|
93
|
+
<BaseAlertDialog.Close className={cn(className)} {...props} />
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
export const AlertDialogHeader = ({
|
|
97
|
+
className,
|
|
98
|
+
...props
|
|
99
|
+
}: AlertDialogHeaderProps) => (
|
|
100
|
+
<div className={cn("flex flex-col gap-1", className)} {...props} />
|
|
101
|
+
)
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
ChangeEvent,
|
|
5
|
+
ComponentProps,
|
|
6
|
+
DragEvent,
|
|
7
|
+
InputHTMLAttributes,
|
|
8
|
+
} from "react";
|
|
9
|
+
import { IconCrossSmall } from "./icons";
|
|
10
|
+
import { cn } from "./lib/cn";
|
|
11
|
+
import { motion } from "./lib/motion";
|
|
12
|
+
|
|
13
|
+
export type AttachmentProps = Omit<ComponentProps<"label">, "onDrop"> & {
|
|
14
|
+
accept?: InputHTMLAttributes<HTMLInputElement>["accept"];
|
|
15
|
+
multiple?: boolean;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
onFiles?: (files: File[]) => void;
|
|
18
|
+
};
|
|
19
|
+
export type AttachmentListProps = ComponentProps<"ul">;
|
|
20
|
+
export type AttachmentItemProps = ComponentProps<"li">;
|
|
21
|
+
export type AttachmentPreviewProps = ComponentProps<"div">;
|
|
22
|
+
export type AttachmentNameProps = ComponentProps<"span">;
|
|
23
|
+
export type AttachmentRemoveProps = ComponentProps<"button">;
|
|
24
|
+
|
|
25
|
+
export const Attachment = ({
|
|
26
|
+
className,
|
|
27
|
+
children,
|
|
28
|
+
accept,
|
|
29
|
+
multiple,
|
|
30
|
+
disabled,
|
|
31
|
+
onFiles,
|
|
32
|
+
...props
|
|
33
|
+
}: AttachmentProps) => {
|
|
34
|
+
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
35
|
+
const files = Array.from(event.currentTarget.files ?? []);
|
|
36
|
+
if (files.length > 0) onFiles?.(files);
|
|
37
|
+
event.currentTarget.value = "";
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const handleDrop = (event: DragEvent<HTMLLabelElement>) => {
|
|
41
|
+
event.preventDefault();
|
|
42
|
+
if (disabled) return;
|
|
43
|
+
|
|
44
|
+
const files = Array.from(event.dataTransfer.files);
|
|
45
|
+
if (files.length > 0) onFiles?.(multiple ? files : files.slice(0, 1));
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const handleDragOver = (event: DragEvent<HTMLLabelElement>) => {
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<label
|
|
54
|
+
data-disabled={disabled || undefined}
|
|
55
|
+
className={cn(
|
|
56
|
+
"flex min-h-32 cursor-pointer flex-col items-center justify-center gap-2 rounded-xl border border-dashed border-border-primary bg-surface p-6 text-center text-sm text-fg-secondary outline-none hover:bg-background-secondary focus-within:border-ring focus-within:ring-[3px] focus-within:ring-offset-1 focus-within:ring-offset-background-primary focus-within:ring-ring/20 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
|
|
57
|
+
motion.colors,
|
|
58
|
+
className,
|
|
59
|
+
)}
|
|
60
|
+
onDrop={handleDrop}
|
|
61
|
+
onDragOver={handleDragOver}
|
|
62
|
+
{...props}
|
|
63
|
+
>
|
|
64
|
+
<input
|
|
65
|
+
type="file"
|
|
66
|
+
className="sr-only"
|
|
67
|
+
accept={accept}
|
|
68
|
+
multiple={multiple}
|
|
69
|
+
disabled={disabled}
|
|
70
|
+
onChange={handleChange}
|
|
71
|
+
/>
|
|
72
|
+
{children}
|
|
73
|
+
</label>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const AttachmentList = ({
|
|
78
|
+
className,
|
|
79
|
+
...props
|
|
80
|
+
}: AttachmentListProps) => (
|
|
81
|
+
<ul className={cn("flex flex-col gap-2", className)} {...props} />
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
export const AttachmentItem = ({
|
|
85
|
+
className,
|
|
86
|
+
...props
|
|
87
|
+
}: AttachmentItemProps) => (
|
|
88
|
+
<li
|
|
89
|
+
className={cn(
|
|
90
|
+
"flex items-center gap-3 rounded-lg border border-border-primary bg-surface p-2",
|
|
91
|
+
className,
|
|
92
|
+
)}
|
|
93
|
+
{...props}
|
|
94
|
+
/>
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
export const AttachmentPreview = ({
|
|
98
|
+
className,
|
|
99
|
+
...props
|
|
100
|
+
}: AttachmentPreviewProps) => (
|
|
101
|
+
<div
|
|
102
|
+
className={cn(
|
|
103
|
+
"flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-md bg-background-tertiary text-fg-secondary [&_img]:size-full [&_img]:object-cover [&_svg]:size-5",
|
|
104
|
+
className,
|
|
105
|
+
)}
|
|
106
|
+
{...props}
|
|
107
|
+
/>
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
export const AttachmentName = ({
|
|
111
|
+
className,
|
|
112
|
+
...props
|
|
113
|
+
}: AttachmentNameProps) => (
|
|
114
|
+
<span
|
|
115
|
+
className={cn("min-w-0 flex-1 truncate text-sm text-fg-primary", className)}
|
|
116
|
+
{...props}
|
|
117
|
+
/>
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
export const AttachmentRemove = ({
|
|
121
|
+
className,
|
|
122
|
+
children,
|
|
123
|
+
type = "button",
|
|
124
|
+
...props
|
|
125
|
+
}: AttachmentRemoveProps) => (
|
|
126
|
+
<button
|
|
127
|
+
type={type}
|
|
128
|
+
aria-label="Remove attachment"
|
|
129
|
+
className={cn(
|
|
130
|
+
"flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-md border border-transparent text-fg-tertiary outline-none hover:bg-background-tertiary hover:text-fg-primary focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-offset-1 focus-visible:ring-offset-background-primary focus-visible:ring-ring/20 disabled:cursor-not-allowed disabled:opacity-50",
|
|
131
|
+
motion.colors,
|
|
132
|
+
className,
|
|
133
|
+
)}
|
|
134
|
+
{...props}
|
|
135
|
+
>
|
|
136
|
+
{children ?? <IconCrossSmall />}
|
|
137
|
+
</button>
|
|
138
|
+
);
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { Autocomplete as BaseAutocomplete } from "@base-ui/react/autocomplete"
|
|
4
|
+
import type { ComponentProps, ReactElement } from "react"
|
|
5
|
+
import { IconChevronDownSmall, IconCrossSmall } from "./icons"
|
|
6
|
+
import { cn } from "./lib/cn"
|
|
7
|
+
import { motion } from "./lib/motion"
|
|
8
|
+
|
|
9
|
+
export type AutocompleteProps = ComponentProps<typeof BaseAutocomplete.Root>
|
|
10
|
+
export type AutocompleteValueProps = ComponentProps<typeof BaseAutocomplete.Value>
|
|
11
|
+
export type AutocompleteTriggerProps = ComponentProps<
|
|
12
|
+
typeof BaseAutocomplete.Trigger
|
|
13
|
+
>
|
|
14
|
+
export type AutocompleteInputProps = ComponentProps<typeof BaseAutocomplete.Input>
|
|
15
|
+
export type AutocompleteInputGroupProps = ComponentProps<
|
|
16
|
+
typeof BaseAutocomplete.InputGroup
|
|
17
|
+
>
|
|
18
|
+
export type AutocompleteIconProps = ComponentProps<typeof BaseAutocomplete.Icon>
|
|
19
|
+
export type AutocompleteClearProps = ComponentProps<typeof BaseAutocomplete.Clear>
|
|
20
|
+
export type AutocompleteListProps = ComponentProps<typeof BaseAutocomplete.List>
|
|
21
|
+
export type AutocompleteStatusProps = ComponentProps<
|
|
22
|
+
typeof BaseAutocomplete.Status
|
|
23
|
+
>
|
|
24
|
+
export type AutocompletePortalProps = ComponentProps<
|
|
25
|
+
typeof BaseAutocomplete.Portal
|
|
26
|
+
>
|
|
27
|
+
export type AutocompleteBackdropProps = ComponentProps<
|
|
28
|
+
typeof BaseAutocomplete.Backdrop
|
|
29
|
+
>
|
|
30
|
+
export type AutocompletePositionerProps = ComponentProps<
|
|
31
|
+
typeof BaseAutocomplete.Positioner
|
|
32
|
+
>
|
|
33
|
+
export type AutocompletePopupProps = ComponentProps<typeof BaseAutocomplete.Popup>
|
|
34
|
+
export type AutocompleteArrowProps = ComponentProps<typeof BaseAutocomplete.Arrow>
|
|
35
|
+
export type AutocompleteGroupProps = ComponentProps<typeof BaseAutocomplete.Group>
|
|
36
|
+
export type AutocompleteGroupLabelProps = ComponentProps<
|
|
37
|
+
typeof BaseAutocomplete.GroupLabel
|
|
38
|
+
>
|
|
39
|
+
export type AutocompleteItemProps = ComponentProps<typeof BaseAutocomplete.Item>
|
|
40
|
+
export type AutocompleteRowProps = ComponentProps<typeof BaseAutocomplete.Row>
|
|
41
|
+
export type AutocompleteCollectionProps = ComponentProps<
|
|
42
|
+
typeof BaseAutocomplete.Collection
|
|
43
|
+
>
|
|
44
|
+
export type AutocompleteEmptyProps = ComponentProps<typeof BaseAutocomplete.Empty>
|
|
45
|
+
export type AutocompleteSeparatorProps = ComponentProps<
|
|
46
|
+
typeof BaseAutocomplete.Separator
|
|
47
|
+
>
|
|
48
|
+
|
|
49
|
+
export const Autocomplete = (props: AutocompleteProps): ReactElement => (
|
|
50
|
+
<BaseAutocomplete.Root {...props} />
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
export const AutocompleteValue = (props: AutocompleteValueProps) => (
|
|
54
|
+
<BaseAutocomplete.Value {...props} />
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
const inputGroupAccessoryClassName = cn(
|
|
58
|
+
"inline-flex size-9 shrink-0 cursor-pointer items-center justify-center text-fg-tertiary outline-none",
|
|
59
|
+
motion.colors,
|
|
60
|
+
"hover:text-fg-primary focus-visible:bg-background-tertiary focus-visible:text-fg-primary focus-visible:outline-none data-disabled:cursor-not-allowed",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
export const AutocompleteInputGroup = ({
|
|
64
|
+
className,
|
|
65
|
+
...props
|
|
66
|
+
}: AutocompleteInputGroupProps) => (
|
|
67
|
+
<BaseAutocomplete.InputGroup
|
|
68
|
+
className={cn(
|
|
69
|
+
"relative flex min-h-9 w-full items-center rounded-md border border-border-secondary bg-surface inset-shadow-outline-top outline-none transition-[color,box-shadow]",
|
|
70
|
+
"has-[[data-popup-open]]:bg-background-tertiary/60",
|
|
71
|
+
"focus-within:border-ring focus-within:ring-[3px] focus-within:ring-offset-1 focus-within:ring-offset-background-primary focus-within:ring-ring/20",
|
|
72
|
+
"aria-invalid:border-destructive aria-invalid:focus-within:border-destructive aria-invalid:focus-within:ring-destructive/20",
|
|
73
|
+
"has-[[aria-invalid=true]]:border-destructive has-[[aria-invalid=true]]:focus-within:border-destructive has-[[aria-invalid=true]]:focus-within:ring-destructive/20",
|
|
74
|
+
"has-[:disabled]:opacity-50",
|
|
75
|
+
className,
|
|
76
|
+
)}
|
|
77
|
+
{...props}
|
|
78
|
+
/>
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
export const AutocompleteInput = ({
|
|
82
|
+
className,
|
|
83
|
+
...props
|
|
84
|
+
}: AutocompleteInputProps) => (
|
|
85
|
+
<BaseAutocomplete.Input
|
|
86
|
+
className={cn(
|
|
87
|
+
"h-9 min-w-0 flex-1 cursor-text rounded-md bg-transparent px-3 text-sm text-fg-primary outline-none placeholder:text-fg-quaternary focus-visible:ring-0",
|
|
88
|
+
className,
|
|
89
|
+
)}
|
|
90
|
+
{...props}
|
|
91
|
+
/>
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
export const AutocompleteTrigger = ({
|
|
95
|
+
className,
|
|
96
|
+
children,
|
|
97
|
+
...props
|
|
98
|
+
}: AutocompleteTriggerProps) => (
|
|
99
|
+
<BaseAutocomplete.Trigger
|
|
100
|
+
className={cn(inputGroupAccessoryClassName, className)}
|
|
101
|
+
{...props}
|
|
102
|
+
>
|
|
103
|
+
{children ?? <AutocompleteIcon />}
|
|
104
|
+
</BaseAutocomplete.Trigger>
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
export const AutocompleteIcon = ({
|
|
108
|
+
className,
|
|
109
|
+
children,
|
|
110
|
+
...props
|
|
111
|
+
}: AutocompleteIconProps) => (
|
|
112
|
+
<BaseAutocomplete.Icon
|
|
113
|
+
className={cn(
|
|
114
|
+
"flex shrink-0 text-fg-tertiary",
|
|
115
|
+
motion.transform,
|
|
116
|
+
"data-popup-open:rotate-180",
|
|
117
|
+
className,
|
|
118
|
+
)}
|
|
119
|
+
{...props}
|
|
120
|
+
>
|
|
121
|
+
{children ?? (
|
|
122
|
+
<IconChevronDownSmall size={16} className="size-4" aria-hidden />
|
|
123
|
+
)}
|
|
124
|
+
</BaseAutocomplete.Icon>
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
export const AutocompleteClear = ({
|
|
128
|
+
className,
|
|
129
|
+
children,
|
|
130
|
+
...props
|
|
131
|
+
}: AutocompleteClearProps) => (
|
|
132
|
+
<BaseAutocomplete.Clear
|
|
133
|
+
className={cn(inputGroupAccessoryClassName, className)}
|
|
134
|
+
{...props}
|
|
135
|
+
>
|
|
136
|
+
{children ?? (
|
|
137
|
+
<IconCrossSmall size={14} className="size-3.5" aria-hidden />
|
|
138
|
+
)}
|
|
139
|
+
</BaseAutocomplete.Clear>
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
export const AutocompletePortal = (props: AutocompletePortalProps) => (
|
|
143
|
+
<BaseAutocomplete.Portal {...props} />
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
export const AutocompleteBackdrop = ({
|
|
147
|
+
className,
|
|
148
|
+
...props
|
|
149
|
+
}: AutocompleteBackdropProps) => (
|
|
150
|
+
<BaseAutocomplete.Backdrop className={cn(className)} {...props} />
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
export const AutocompletePositioner = ({
|
|
154
|
+
sideOffset = 4,
|
|
155
|
+
className,
|
|
156
|
+
...props
|
|
157
|
+
}: AutocompletePositionerProps) => (
|
|
158
|
+
<BaseAutocomplete.Positioner
|
|
159
|
+
sideOffset={sideOffset}
|
|
160
|
+
className={cn("z-50 outline-none", className)}
|
|
161
|
+
{...props}
|
|
162
|
+
/>
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
export const AutocompletePopup = ({
|
|
166
|
+
className,
|
|
167
|
+
...props
|
|
168
|
+
}: AutocompletePopupProps) => (
|
|
169
|
+
<BaseAutocomplete.Popup
|
|
170
|
+
className={cn(
|
|
171
|
+
"z-50 max-h-[min(24rem,var(--available-height))] w-[var(--anchor-width)] overflow-hidden rounded-md border border-border-primary bg-surface shadow-md outline-none",
|
|
172
|
+
motion.popupAnchor,
|
|
173
|
+
className,
|
|
174
|
+
)}
|
|
175
|
+
{...props}
|
|
176
|
+
/>
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
export const AutocompleteArrow = ({
|
|
180
|
+
className,
|
|
181
|
+
...props
|
|
182
|
+
}: AutocompleteArrowProps) => (
|
|
183
|
+
<BaseAutocomplete.Arrow
|
|
184
|
+
className={cn(
|
|
185
|
+
"data-[side=bottom]:top-[-6px] data-[side=left]:right-[-6px] data-[side=right]:left-[-6px] data-[side=top]:bottom-[-6px]",
|
|
186
|
+
"size-2.5 rotate-45 border border-border-primary bg-surface",
|
|
187
|
+
"data-[side=bottom]:border-r-0 data-[side=bottom]:border-b-0",
|
|
188
|
+
"data-[side=top]:border-t-0 data-[side=top]:border-l-0",
|
|
189
|
+
"data-[side=left]:border-b-0 data-[side=left]:border-l-0",
|
|
190
|
+
"data-[side=right]:border-t-0 data-[side=right]:border-r-0",
|
|
191
|
+
className,
|
|
192
|
+
)}
|
|
193
|
+
{...props}
|
|
194
|
+
/>
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
export const AutocompleteList = ({
|
|
198
|
+
className,
|
|
199
|
+
...props
|
|
200
|
+
}: AutocompleteListProps) => (
|
|
201
|
+
<BaseAutocomplete.List
|
|
202
|
+
className={cn("max-h-[inherit] overflow-y-auto p-1 outline-none", className)}
|
|
203
|
+
{...props}
|
|
204
|
+
/>
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
export const AutocompleteItem = ({
|
|
208
|
+
className,
|
|
209
|
+
...props
|
|
210
|
+
}: AutocompleteItemProps) => (
|
|
211
|
+
<BaseAutocomplete.Item
|
|
212
|
+
className={cn(
|
|
213
|
+
"flex min-h-8 cursor-default items-center gap-2 rounded-xs px-2.5 py-1.5 text-sm text-fg-primary outline-none select-none",
|
|
214
|
+
motion.colors,
|
|
215
|
+
"data-disabled:cursor-not-allowed data-disabled:opacity-50 data-highlighted:bg-background-tertiary data-highlighted:text-fg-primary",
|
|
216
|
+
className,
|
|
217
|
+
)}
|
|
218
|
+
{...props}
|
|
219
|
+
/>
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
export const AutocompleteEmpty = ({
|
|
223
|
+
className,
|
|
224
|
+
...props
|
|
225
|
+
}: AutocompleteEmptyProps) => (
|
|
226
|
+
<BaseAutocomplete.Empty
|
|
227
|
+
className={cn("px-2.5 py-2 text-sm text-fg-tertiary empty:hidden", className)}
|
|
228
|
+
{...props}
|
|
229
|
+
/>
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
export const AutocompleteStatus = ({
|
|
233
|
+
className,
|
|
234
|
+
...props
|
|
235
|
+
}: AutocompleteStatusProps) => (
|
|
236
|
+
<BaseAutocomplete.Status
|
|
237
|
+
className={cn("px-2.5 py-2 text-sm text-fg-tertiary", className)}
|
|
238
|
+
{...props}
|
|
239
|
+
/>
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
export const AutocompleteGroup = ({
|
|
243
|
+
className,
|
|
244
|
+
...props
|
|
245
|
+
}: AutocompleteGroupProps) => (
|
|
246
|
+
<BaseAutocomplete.Group className={cn(className)} {...props} />
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
export const AutocompleteGroupLabel = ({
|
|
250
|
+
className,
|
|
251
|
+
...props
|
|
252
|
+
}: AutocompleteGroupLabelProps) => (
|
|
253
|
+
<BaseAutocomplete.GroupLabel
|
|
254
|
+
className={cn("px-2.5 py-1.5 text-xs text-fg-tertiary", className)}
|
|
255
|
+
{...props}
|
|
256
|
+
/>
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
export const AutocompleteSeparator = ({
|
|
260
|
+
className,
|
|
261
|
+
...props
|
|
262
|
+
}: AutocompleteSeparatorProps) => (
|
|
263
|
+
<BaseAutocomplete.Separator
|
|
264
|
+
className={cn("my-1 h-px bg-border-primary", className)}
|
|
265
|
+
{...props}
|
|
266
|
+
/>
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
export const AutocompleteCollection = (props: AutocompleteCollectionProps) => (
|
|
270
|
+
<BaseAutocomplete.Collection {...props} />
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
export const AutocompleteRow = ({
|
|
274
|
+
className,
|
|
275
|
+
...props
|
|
276
|
+
}: AutocompleteRowProps) => (
|
|
277
|
+
<BaseAutocomplete.Row className={cn(className)} {...props} />
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
export const useAutocompleteFilter = BaseAutocomplete.useFilter
|
|
281
|
+
export const useAutocompleteFilteredItems = BaseAutocomplete.useFilteredItems
|