@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.
Files changed (67) hide show
  1. package/README.md +9 -0
  2. package/package.json +46 -0
  3. package/src/accordion.tsx +84 -0
  4. package/src/alert-dialog.tsx +101 -0
  5. package/src/attachment.tsx +138 -0
  6. package/src/autocomplete.tsx +281 -0
  7. package/src/avatar.tsx +56 -0
  8. package/src/badge.tsx +28 -0
  9. package/src/brand.tsx +70 -0
  10. package/src/breadcrumb.tsx +81 -0
  11. package/src/button.tsx +129 -0
  12. package/src/calendar.tsx +84 -0
  13. package/src/card.tsx +54 -0
  14. package/src/carousel.tsx +253 -0
  15. package/src/chart.tsx +185 -0
  16. package/src/checkbox-group.tsx +14 -0
  17. package/src/checkbox.tsx +31 -0
  18. package/src/code-block.tsx +124 -0
  19. package/src/collapsible.tsx +61 -0
  20. package/src/combobox.tsx +324 -0
  21. package/src/command.tsx +377 -0
  22. package/src/context-menu.tsx +250 -0
  23. package/src/dialog.tsx +78 -0
  24. package/src/drawer.tsx +156 -0
  25. package/src/empty.tsx +52 -0
  26. package/src/field.tsx +75 -0
  27. package/src/fieldset.tsx +25 -0
  28. package/src/form.tsx +14 -0
  29. package/src/icons.tsx +91 -0
  30. package/src/illustrations.tsx +167 -0
  31. package/src/image-modal.tsx +110 -0
  32. package/src/index.ts +833 -0
  33. package/src/input.tsx +68 -0
  34. package/src/lib/cn.ts +3 -0
  35. package/src/lib/motion.ts +23 -0
  36. package/src/markdown-editor.tsx +302 -0
  37. package/src/menu.tsx +205 -0
  38. package/src/menubar.tsx +22 -0
  39. package/src/meter.tsx +61 -0
  40. package/src/navigation-menu.tsx +217 -0
  41. package/src/number-field.tsx +119 -0
  42. package/src/orb.tsx +33 -0
  43. package/src/otp-field.tsx +45 -0
  44. package/src/pagination.tsx +91 -0
  45. package/src/popover.tsx +92 -0
  46. package/src/preview-card.tsx +103 -0
  47. package/src/progress.tsx +60 -0
  48. package/src/radio.tsx +43 -0
  49. package/src/scroll-area.tsx +67 -0
  50. package/src/select.tsx +161 -0
  51. package/src/separator.tsx +17 -0
  52. package/src/sidebar.tsx +82 -0
  53. package/src/skeleton.tsx +32 -0
  54. package/src/slider.tsx +56 -0
  55. package/src/sounds.tsx +270 -0
  56. package/src/spinner.tsx +45 -0
  57. package/src/switch.tsx +19 -0
  58. package/src/table.tsx +81 -0
  59. package/src/tabs.tsx +62 -0
  60. package/src/text-animate.tsx +155 -0
  61. package/src/textarea.tsx +58 -0
  62. package/src/ticker.tsx +74 -0
  63. package/src/toast.tsx +142 -0
  64. package/src/toggle.tsx +32 -0
  65. package/src/toolbar.tsx +75 -0
  66. package/src/tooltip.tsx +55 -0
  67. 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