@lexibase/rdx-ui 1.0.0-beta.0 → 1.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # RDX UI
2
2
 
3
3
  The shared theme used by the RDX development website and generated documentation
4
- sites. The source of truth is `packages/rdx-ui/src`: Radix dropdowns, buttons,
4
+ sites. The source of truth is `packages/rdx-ui/src`: Base UI dropdowns, buttons,
5
5
  logo, theme provider, navbar, sidebar, landing page and MDX components.
6
6
 
7
7
  Published as `@lexibase/rdx-ui`. React/Next.js source is intentionally shipped
@@ -20,3 +20,93 @@ export default function MyHome() {
20
20
  Configure project-owned components via `homepage.component` and `navbar.logo`.
21
21
  Do not edit generated `.rdx/` files. Installing the versioning plugin does not
22
22
  change this theme: it contributes data to the shared version dropdown.
23
+
24
+ ## Documentation components
25
+
26
+ `Callout` is registered automatically in MDX, with optional `title` and variants
27
+ `note` (default), `tip`, `success`, `warning`, `danger`:
28
+
29
+ ```mdx
30
+ <Callout variant="warning" title="Before updating">
31
+
32
+ Read **release notes** before deploying.
33
+
34
+ </Callout>
35
+ ```
36
+
37
+ In React, import it from `@lexibase/rdx-ui/components/callout`. It renders a static
38
+ note, not an automatic live alert. The Markdown map also styles all six heading
39
+ levels, responsive images, GFM tables and keyboard-scrollable code blocks.
40
+ Fenced code blocks include a language label and copy button automatically;
41
+ inline code remains unchanged. Copy failures leave the code selectable and show
42
+ manual-copy guidance instead of a false success message.
43
+
44
+ ## Base UI composition
45
+
46
+ The shared components use `@base-ui/react`. Existing RDX colors, variants,
47
+ dimensions and layout are preserved; `components.json` selects `base-nova` for
48
+ future shadcn additions, without regenerating the existing theme.
49
+
50
+ This beta changes the composition API: `asChild` is no longer supported.
51
+ Use `render` for interactive composition and `ButtonLink` for navigation:
52
+
53
+ ```tsx
54
+ import { Button } from '@lexibase/rdx-ui/components/button'
55
+ import { ButtonLink } from '@lexibase/rdx-ui/components/button-link'
56
+ import {
57
+ DropdownMenu, DropdownMenuTrigger, DropdownMenuContent,
58
+ DropdownMenuGroup, DropdownMenuLabel, DropdownMenuItem,
59
+ DropdownMenuLinkItem,
60
+ } from '@lexibase/rdx-ui/components/dropdown-menu'
61
+ import Link from 'next/link'
62
+
63
+ <ButtonLink href="/docs" variant="outline">Documentation</ButtonLink>
64
+
65
+ <DropdownMenu>
66
+ <DropdownMenuTrigger render={<Button variant="outline" />}>
67
+ Actions
68
+ </DropdownMenuTrigger>
69
+ <DropdownMenuContent align="start">
70
+ <DropdownMenuGroup>
71
+ <DropdownMenuLabel>Project</DropdownMenuLabel>
72
+ <DropdownMenuItem onClick={() => console.log('Action')}>Run action</DropdownMenuItem>
73
+ <DropdownMenuLinkItem closeOnClick render={<Link href="/docs" />}>
74
+ Documentation
75
+ </DropdownMenuLinkItem>
76
+ </DropdownMenuGroup>
77
+ </DropdownMenuContent>
78
+ </DropdownMenu>
79
+ ```
80
+
81
+ `ButtonLink` renders a Next.js link with button styling, not `role="button"`.
82
+ `Button` renders a native button; use `type="submit"` explicitly for form submission.
83
+ Menu actions use `onClick` instead of Radix's `onSelect`. Labels must be inside
84
+ `DropdownMenuGroup`. Checkbox values are boolean, not the Radix `indeterminate`
85
+ string; checkbox/radio items remain open unless `closeOnClick` is enabled.
86
+ Navigation items use `DropdownMenuLinkItem` (with `closeOnClick` when desired).
87
+ Components accept Base UI state-aware `className` callbacks and `render` props.
88
+ For custom CSS, replace Radix state selectors/variables with Base UI's
89
+ `data-open`, `data-closed`, `data-highlighted`, `data-popup-open`,
90
+ `--available-height` and `--transform-origin`. `Separator` remains decorative by
91
+ default; set `decorative={false}` for an accessible separator role.
92
+
93
+ See [Base UI Menu](https://base-ui.com/react/components/menu) and
94
+ [shadcn Base UI](https://ui.shadcn.com/docs/components/base/button).
95
+
96
+ ## Documentation tabs
97
+
98
+ `Tabs`, `TabsList`, `TabsTrigger` and `TabsContent` wrap Base UI Tabs and are
99
+ automatically registered in MDX. Import them from
100
+ `@lexibase/rdx-ui/components/tabs` in React files. Use an explicit `defaultValue`,
101
+ matching string values and an `aria-label` on each list. Arrow keys move focus;
102
+ Enter or Space activates a tab. The list scrolls on small screens. See
103
+ the repository's `MDX.md` and `docs/examples/tabs.mdx` for complete examples.
104
+
105
+ ## Documentation accordion
106
+
107
+ `Accordion`, `AccordionItem`, `AccordionTrigger` and `AccordionContent` wrap
108
+ Base UI Accordion and are registered in MDX. Import them from
109
+ `@lexibase/rdx-ui/components/accordion` in React files. One item opens at a time
110
+ by default; `multiple` allows independent expansion. Triggers use native buttons
111
+ inside `h3` headings with normal Tab navigation and Enter/Space activation.
112
+ See `MDX.md` and `docs/examples/accordion.mdx` for examples and React options.
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@lexibase/rdx-ui",
3
- "version": "1.0.0-beta.0",
3
+ "version": "1.0.0-beta.2",
4
4
  "type": "module",
5
+ "engines": {
6
+ "node": ">=20.9"
7
+ },
5
8
  "description": "The shared RDX documentation theme and UI components.",
6
9
  "license": "MIT",
7
10
  "files": [
8
11
  "src",
9
12
  "postcss.config.mjs",
13
+ "postcss-plugin.cjs",
10
14
  "README.md"
11
15
  ],
12
16
  "publishConfig": {
@@ -18,42 +22,46 @@
18
22
  "directory": "packages/rdx-ui"
19
23
  },
20
24
  "dependencies": {
21
- "@tailwindcss/postcss": "^4.1.13",
22
- "postcss": "^8.5.6",
23
- "tailwindcss": "^4.1.13",
24
- "@radix-ui/react-dropdown-menu": "^2.1.16",
25
- "@radix-ui/react-separator": "^1.1.7",
26
- "@radix-ui/react-slot": "^1.2.3",
25
+ "cmdk": "^1.1.1",
26
+ "@base-ui/react": "^1.9.0",
27
+ "@tailwindcss/postcss": "^4.3.3",
27
28
  "class-variance-authority": "^0.7.1",
28
29
  "clsx": "^2.1.1",
29
- "lucide-react": "^0.542.0",
30
+ "lucide-react": "^0.577.0",
30
31
  "next-themes": "^0.4.6",
31
- "tailwind-merge": "^3.3.1",
32
- "tw-animate-css": "^1.3.8"
32
+ "postcss": "^8.5.31",
33
+ "tailwind-merge": "^3.7.0",
34
+ "tailwindcss": "^4.3.3",
35
+ "tw-animate-css": "^1.4.0",
36
+ "@lexibase/rdx-types": "1.0.0-beta.5"
33
37
  },
34
38
  "peerDependencies": {
35
- "next": "^15.5.0",
36
- "react": "^19.1.0",
37
- "react-dom": "^19.1.0"
39
+ "next": "^16.4.2",
40
+ "react": "^19.3.1",
41
+ "react-dom": "^19.3.1"
38
42
  },
39
43
  "devDependencies": {
40
- "@tailwindcss/postcss": "^4.1.13",
44
+ "@tailwindcss/postcss": "^4.3.3",
41
45
  "@types/node": "^22.15.3",
42
- "@types/react": "19.1.0",
43
- "@types/react-dom": "19.1.1",
44
- "eslint": "^9.34.0",
45
- "postcss": "^8.5.6",
46
- "next": "^15.5.0",
47
- "react": "19.1.0",
48
- "react-dom": "19.1.0",
49
- "tailwindcss": "^4.1.13",
50
- "typescript": "5.9.2",
46
+ "@types/react": "19.3.0",
47
+ "@types/react-dom": "19.3.0",
48
+ "eslint": "^9.39.5",
49
+ "next": "^16.4.2",
50
+ "postcss": "^8.5.31",
51
+ "react": "19.3.1",
52
+ "react-dom": "19.3.1",
53
+ "tailwindcss": "^4.3.3",
54
+ "typescript": "6.0.3",
51
55
  "@rdx/typescript-config": "1.0.0",
52
56
  "@rdx/eslint-config": "1.0.0"
53
57
  },
54
58
  "exports": {
55
- "./globals.css": "./src/styles/globals.css",
59
+ "./globals.css": {
60
+ "types": "./src/styles/globals.d.css.ts",
61
+ "default": "./src/styles/globals.css"
62
+ },
56
63
  "./postcss.config": "./postcss.config.mjs",
64
+ "./postcss-plugin": "./postcss-plugin.cjs",
57
65
  "./lib/*": "./src/lib/*.ts",
58
66
  "./components/*": "./src/components/*.tsx",
59
67
  "./hooks/*": "./src/hooks/*.ts",
@@ -0,0 +1,2 @@
1
+ // Keep Tailwind's native dependencies in the PostCSS worker, not the app bundle.
2
+ module.exports = require('@tailwindcss/postcss')
@@ -1,11 +1,7 @@
1
- import { createRequire } from 'node:module'
2
-
3
- const require = createRequire(import.meta.url)
4
-
5
1
  /** @type {import('postcss-load-config').Config} */
6
2
  const config = {
7
3
  plugins: {
8
- [require.resolve('@tailwindcss/postcss')]: {},
4
+ '@lexibase/rdx-ui/postcss-plugin': {},
9
5
  },
10
6
  }
11
7
 
@@ -0,0 +1,91 @@
1
+ 'use client'
2
+
3
+ import { Accordion as AccordionPrimitive } from '@base-ui/react/accordion'
4
+ import { ChevronDown, ChevronUp } from 'lucide-react'
5
+
6
+ import { mergeStateClassName } from '../lib/utils'
7
+
8
+ function Accordion({
9
+ className,
10
+ multiple = false,
11
+ ...props
12
+ }: AccordionPrimitive.Root.Props<string>) {
13
+ return (
14
+ <AccordionPrimitive.Root
15
+ data-slot="accordion"
16
+ multiple={multiple}
17
+ className={mergeStateClassName(
18
+ 'my-4 flex w-full min-w-0 flex-col',
19
+ className
20
+ )}
21
+ {...props}
22
+ />
23
+ )
24
+ }
25
+
26
+ function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
27
+ return (
28
+ <AccordionPrimitive.Item
29
+ data-slot="accordion-item"
30
+ className={mergeStateClassName(
31
+ 'min-w-0 border-b border-border last:border-b-0',
32
+ className
33
+ )}
34
+ {...props}
35
+ />
36
+ )
37
+ }
38
+
39
+ function AccordionTrigger({
40
+ className,
41
+ children,
42
+ ...props
43
+ }: AccordionPrimitive.Trigger.Props) {
44
+ return (
45
+ <AccordionPrimitive.Header className="m-0 flex text-sm font-medium">
46
+ <AccordionPrimitive.Trigger
47
+ data-slot="accordion-trigger"
48
+ className={mergeStateClassName(
49
+ 'group/accordion-trigger relative flex flex-1 min-w-0 items-start justify-between gap-3 rounded-lg border border-transparent py-2.5 text-left text-sm font-medium text-foreground transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 data-disabled:pointer-events-none data-disabled:opacity-50 motion-reduce:transition-none',
50
+ className
51
+ )}
52
+ {...props}
53
+ >
54
+ <span className="min-w-0 [overflow-wrap:anywhere]">{children}</span>
55
+ <ChevronDown
56
+ aria-hidden="true"
57
+ data-slot="accordion-trigger-icon"
58
+ className="pointer-events-none ml-auto size-4 shrink-0 text-muted-foreground group-aria-expanded/accordion-trigger:hidden"
59
+ />
60
+ <ChevronUp
61
+ aria-hidden="true"
62
+ data-slot="accordion-trigger-icon"
63
+ className="pointer-events-none ml-auto hidden size-4 shrink-0 text-muted-foreground group-aria-expanded/accordion-trigger:inline"
64
+ />
65
+ </AccordionPrimitive.Trigger>
66
+ </AccordionPrimitive.Header>
67
+ )
68
+ }
69
+
70
+ function AccordionContent({
71
+ className,
72
+ children,
73
+ ...props
74
+ }: AccordionPrimitive.Panel.Props) {
75
+ return (
76
+ <AccordionPrimitive.Panel
77
+ data-slot="accordion-content"
78
+ className={mergeStateClassName(
79
+ 'min-w-0 overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up motion-reduce:data-open:animate-none motion-reduce:data-closed:animate-none',
80
+ className
81
+ )}
82
+ {...props}
83
+ >
84
+ <div className="pt-0 pb-2.5 leading-6 text-foreground/85 [overflow-wrap:anywhere] [&>:first-child]:mt-0 [&>:last-child]:mb-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground">
85
+ {children}
86
+ </div>
87
+ </AccordionPrimitive.Panel>
88
+ )
89
+ }
90
+
91
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
@@ -0,0 +1,33 @@
1
+ import type { ComponentProps } from 'react'
2
+ import { Quote } from 'lucide-react'
3
+
4
+ import { cn } from '../lib/utils'
5
+
6
+ /** A quotation keeps native semantics, without the heading or tone of a Callout. */
7
+ export function Blockquote({
8
+ children,
9
+ className,
10
+ ...props
11
+ }: ComponentProps<'blockquote'>) {
12
+ return (
13
+ <blockquote
14
+ data-rdx-blockquote
15
+ className={cn(
16
+ 'my-6 flex min-w-0 gap-3 rounded-lg border border-border border-l-2 border-l-ring/50 bg-muted/25 p-4 text-foreground/85 sm:p-5',
17
+ className
18
+ )}
19
+ {...props}
20
+ >
21
+ <Quote
22
+ aria-hidden="true"
23
+ className="mt-1 size-4 shrink-0 text-muted-foreground/70"
24
+ />
25
+ <div
26
+ data-slot="blockquote-content"
27
+ className="min-w-0 flex-1 leading-7 [overflow-wrap:anywhere] [&>:first-child]:mt-0 [&>:last-child]:mb-0"
28
+ >
29
+ {children}
30
+ </div>
31
+ </blockquote>
32
+ )
33
+ }
@@ -0,0 +1,27 @@
1
+ 'use client'
2
+
3
+ import Link from 'next/link'
4
+ import type { ComponentProps } from 'react'
5
+ import type { VariantProps } from 'class-variance-authority'
6
+
7
+ import { buttonVariants } from './button'
8
+ import { cn } from '../lib/utils'
9
+
10
+ /** Navigation keeps native anchor semantics, independent of button behavior. */
11
+ function ButtonLink({
12
+ className,
13
+ variant,
14
+ size,
15
+ active,
16
+ ...props
17
+ }: ComponentProps<typeof Link> & VariantProps<typeof buttonVariants>) {
18
+ return (
19
+ <Link
20
+ data-slot="button"
21
+ className={cn(buttonVariants({ variant, size, active }), className)}
22
+ {...props}
23
+ />
24
+ )
25
+ }
26
+
27
+ export { ButtonLink }
@@ -1,7 +1,6 @@
1
1
  'use client'
2
2
 
3
- import * as React from 'react'
4
- import { Slot } from '@radix-ui/react-slot'
3
+ import { Button as ButtonPrimitive } from '@base-ui/react/button'
5
4
  import { cva, type VariantProps } from 'class-variance-authority'
6
5
 
7
6
  import { cn } from '@lexibase/rdx-ui/lib/utils'
@@ -49,19 +48,17 @@ function Button({
49
48
  variant,
50
49
  size,
51
50
  active,
52
- asChild = false,
53
51
  ...props
54
- }: React.ComponentProps<'button'> &
55
- VariantProps<typeof buttonVariants> & {
56
- asChild?: boolean
57
- active?: boolean
58
- }) {
59
- const Comp = asChild ? Slot : 'button'
60
-
52
+ }: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
61
53
  return (
62
- <Comp
54
+ <ButtonPrimitive
63
55
  data-slot="button"
64
- className={cn(buttonVariants({ variant, size, active, className }))}
56
+ className={(state) =>
57
+ cn(
58
+ buttonVariants({ variant, size, active }),
59
+ typeof className === 'function' ? className(state) : className
60
+ )
61
+ }
65
62
  {...props}
66
63
  />
67
64
  )
@@ -0,0 +1,96 @@
1
+ import type { ComponentProps } from 'react'
2
+ import {
3
+ CircleAlert,
4
+ CircleCheck,
5
+ Info,
6
+ Lightbulb,
7
+ TriangleAlert,
8
+ } from 'lucide-react'
9
+
10
+ import { cn } from '../lib/utils'
11
+
12
+ const variants = {
13
+ note: {
14
+ icon: Info,
15
+ label: 'Note',
16
+ classes: 'border-border bg-muted/40',
17
+ iconClass: 'text-muted-foreground',
18
+ },
19
+ tip: {
20
+ icon: Lightbulb,
21
+ label: 'Tip',
22
+ classes: 'border-blue-500/30 bg-blue-500/5',
23
+ iconClass: 'text-blue-700 dark:text-blue-400',
24
+ },
25
+ success: {
26
+ icon: CircleCheck,
27
+ label: 'Success',
28
+ classes: 'border-emerald-500/30 bg-emerald-500/5',
29
+ iconClass: 'text-emerald-700 dark:text-emerald-400',
30
+ },
31
+ warning: {
32
+ icon: TriangleAlert,
33
+ label: 'Warning',
34
+ classes: 'border-amber-500/30 bg-amber-500/5',
35
+ iconClass: 'text-amber-700 dark:text-amber-400',
36
+ },
37
+ danger: {
38
+ icon: CircleAlert,
39
+ label: 'Danger',
40
+ classes: 'border-red-500/30 bg-red-500/5',
41
+ iconClass: 'text-red-700 dark:text-red-400',
42
+ },
43
+ } as const
44
+
45
+ export type CalloutVariant = keyof typeof variants
46
+ export type CalloutProps = Omit<ComponentProps<'aside'>, 'title'> & {
47
+ variant?: CalloutVariant
48
+ title?: string
49
+ }
50
+
51
+ /** Static documentation content, deliberately not a live alert region. */
52
+ export function Callout({
53
+ variant = 'note',
54
+ title,
55
+ className,
56
+ children,
57
+ ...props
58
+ }: CalloutProps) {
59
+ if (!Object.hasOwn(variants, variant)) {
60
+ throw new Error(
61
+ `[RDX] Invalid Callout variant "${variant}". Use note, tip, success, warning or danger.`
62
+ )
63
+ }
64
+ const { icon: Icon, label, classes, iconClass } = variants[variant]
65
+ return (
66
+ <aside
67
+ role="note"
68
+ aria-label={title || label}
69
+ data-rdx-callout={variant}
70
+ className={cn(
71
+ 'my-6 flex min-w-0 gap-3 rounded-md border p-4 text-sm text-foreground',
72
+ classes,
73
+ className
74
+ )}
75
+ {...props}
76
+ >
77
+ <Icon
78
+ aria-hidden="true"
79
+ className={cn('mt-0.5 size-4 shrink-0', iconClass)}
80
+ />
81
+ <div className="min-w-0 flex-1">
82
+ {title && (
83
+ <p data-slot="callout-title" className="mb-2 font-semibold leading-5">
84
+ {title}
85
+ </p>
86
+ )}
87
+ <div
88
+ data-slot="callout-content"
89
+ className="leading-6 break-words [&>:first-child]:mt-0 [&>:last-child]:mb-0"
90
+ >
91
+ {children}
92
+ </div>
93
+ </div>
94
+ </aside>
95
+ )
96
+ }
@@ -0,0 +1,55 @@
1
+ import { Children, isValidElement, type ComponentProps } from 'react'
2
+ import { CodeXml } from 'lucide-react'
3
+
4
+ import { cn } from '../lib/utils'
5
+ import { CopyCodeButton } from './copy-code-button'
6
+
7
+ /** Keep the code server-rendered; only clipboard interaction needs JavaScript. */
8
+ export function CodeBlock({
9
+ children,
10
+ className,
11
+ ...props
12
+ }: ComponentProps<'pre'>) {
13
+ const code = Children.toArray(children).find(
14
+ (child) =>
15
+ isValidElement<{ className?: string }>(child) &&
16
+ child.props.className?.includes('language-')
17
+ )
18
+ const language = isValidElement<{ className?: string }>(code)
19
+ ? code.props.className?.match(/(?:^|\s)language-([^\s]+)/)?.[1]
20
+ : undefined
21
+ return (
22
+ <div
23
+ data-rdx-code-block
24
+ className="my-4 min-w-0 max-w-full overflow-hidden rounded-lg border border-border bg-muted/30 text-foreground"
25
+ >
26
+ <div className="flex flex-wrap items-center justify-between gap-x-3 gap-y-1.5 border-b border-border/70 bg-muted/30 px-3 py-1.5">
27
+ <div className="flex min-w-0 items-center gap-2">
28
+ <span
29
+ aria-hidden="true"
30
+ className="flex size-6 shrink-0 items-center justify-center rounded-md border border-blue-500/20 bg-blue-500/10 text-blue-700 dark:text-blue-400"
31
+ >
32
+ <CodeXml className="size-3.5" />
33
+ </span>
34
+ <span
35
+ className="min-w-0 truncate font-mono text-xs font-medium text-muted-foreground"
36
+ title={language}
37
+ >
38
+ {language ?? 'Code'}
39
+ </span>
40
+ </div>
41
+ <CopyCodeButton />
42
+ </div>
43
+ <pre
44
+ tabIndex={0}
45
+ className={cn(
46
+ 'm-0 max-w-full overflow-x-auto p-3 font-mono text-[13px] leading-6 text-foreground/90 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring [&>code]:bg-transparent [&>code]:rounded-none [&>code]:p-0 [&>code]:[font-family:inherit] [&>code]:text-inherit',
47
+ className
48
+ )}
49
+ {...props}
50
+ >
51
+ {children}
52
+ </pre>
53
+ </div>
54
+ )
55
+ }
@@ -0,0 +1,90 @@
1
+ 'use client'
2
+
3
+ // shadcn/ui Base Nova Command (cmdk), composed with the Base UI Dialog.
4
+ import * as React from 'react'
5
+ import { Command as CommandPrimitive } from 'cmdk'
6
+ import { Search } from 'lucide-react'
7
+ import { cn } from '../lib/utils'
8
+
9
+ function Command({
10
+ className,
11
+ ...props
12
+ }: React.ComponentProps<typeof CommandPrimitive>) {
13
+ return (
14
+ <CommandPrimitive
15
+ data-slot="command"
16
+ className={cn(
17
+ 'flex size-full flex-col overflow-hidden rounded-xl bg-popover p-1 text-popover-foreground',
18
+ className
19
+ )}
20
+ {...props}
21
+ />
22
+ )
23
+ }
24
+ function CommandInput({
25
+ className,
26
+ ...props
27
+ }: React.ComponentProps<typeof CommandPrimitive.Input>) {
28
+ return (
29
+ <div
30
+ data-slot="command-input-wrapper"
31
+ className="flex items-center gap-2 border-b px-2 py-2 pr-9"
32
+ >
33
+ <Search className="size-4 shrink-0 text-muted-foreground" />
34
+ <CommandPrimitive.Input
35
+ data-slot="command-input"
36
+ className={cn(
37
+ 'h-8 min-w-0 w-full bg-transparent text-sm outline-none placeholder:text-muted-foreground disabled:opacity-50',
38
+ className
39
+ )}
40
+ {...props}
41
+ />
42
+ </div>
43
+ )
44
+ }
45
+ function CommandList({
46
+ className,
47
+ ...props
48
+ }: React.ComponentProps<typeof CommandPrimitive.List>) {
49
+ return (
50
+ <CommandPrimitive.List
51
+ data-slot="command-list"
52
+ className={cn(
53
+ 'max-h-[min(50dvh,24rem)] scroll-py-1 overflow-x-hidden overflow-y-auto outline-none',
54
+ className
55
+ )}
56
+ {...props}
57
+ />
58
+ )
59
+ }
60
+ function CommandEmpty({
61
+ className,
62
+ ...props
63
+ }: React.ComponentProps<typeof CommandPrimitive.Empty>) {
64
+ return (
65
+ <CommandPrimitive.Empty
66
+ data-slot="command-empty"
67
+ className={cn(
68
+ 'px-4 py-6 text-center text-sm text-muted-foreground',
69
+ className
70
+ )}
71
+ {...props}
72
+ />
73
+ )
74
+ }
75
+ function CommandItem({
76
+ className,
77
+ ...props
78
+ }: React.ComponentProps<typeof CommandPrimitive.Item>) {
79
+ return (
80
+ <CommandPrimitive.Item
81
+ data-slot="command-item"
82
+ className={cn(
83
+ 'relative flex cursor-default items-center gap-2 rounded-lg px-2 py-2 text-sm outline-none select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-[selected=true]:bg-muted data-[selected=true]:text-foreground',
84
+ className
85
+ )}
86
+ {...props}
87
+ />
88
+ )
89
+ }
90
+ export { Command, CommandInput, CommandList, CommandEmpty, CommandItem }