diff --git a/apps/www/app/layout.config.tsx b/apps/www/app/layout.config.tsx index bde44dc..cb3ebc8 100644 --- a/apps/www/app/layout.config.tsx +++ b/apps/www/app/layout.config.tsx @@ -27,14 +27,6 @@ export const baseOptions: BaseLayoutProps = { > ), }, - githubUrl: "https://github.com/ruru-m07/ruru-ui/", - // links: [ - // { - // text: 'Documentation', - // url: '/docs', - // active: 'nested-url', - // }, - // ], }; // docs layout configuration diff --git a/apps/www/components/preview/index.tsx b/apps/www/components/preview/index.tsx index 0479e94..599844e 100644 --- a/apps/www/components/preview/index.tsx +++ b/apps/www/components/preview/index.tsx @@ -14,6 +14,15 @@ import { TooltipProvider, TooltipTrigger, } from "ruru-ui/components/tooltip"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectTrigger, + SelectValue, +} from "ruru-ui/components/select"; import { BadgePreview } from "../badgePreview"; import Tabspreview from "../tabs"; @@ -127,4 +136,29 @@ export default { ), + select: ( + + + + + + + + + Fruits + C + C++ + Java + Python + Rust + Golang + Scala + Ruby + C# + + + + + + ), } as Record; diff --git a/apps/www/content/docs/components/select.mdx b/apps/www/content/docs/components/select.mdx new file mode 100644 index 0000000..9c9394b --- /dev/null +++ b/apps/www/content/docs/components/select.mdx @@ -0,0 +1,312 @@ +--- +title: Select +description: The Select component is used to get user input. +preview: select +--- + +import { Tab, Tabs } from "fumadocs-ui/components/tabs"; + +import { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton, +} from "ruru-ui/components/select"; + +## Usage + +--- + + + + + + + + + + + Fruits + Apple + Banana + Blueberry + Grapes + Pineapple + + + + + + +```tsx +import { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton, +} from "ruru-ui/components/select"; + +export function SelectDemo() { + return ( + + + + + + + + Fruits + Apple + Banana + Blueberry + Grapes + Pineapple + + + + + ) +} +``` + + + + +## Examples + +--- + +### Basic Usage + +The `Select` component can be used to create a basic dropdown menu. + + + + + + + + + + Fruits + Apple + Banana + Blueberry + Grapes + Pineapple + + + + + + ```tsx + import { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + } from "ruru-ui/components/select"; + + export function BasicSelect() { + return ( + + + + + + + Fruits + Apple + Banana + Blueberry + Grapes + Pineapple + + + + ); + } + ``` + + + + +### Disabled Select + +You can disable the `Select` component by passing the `disabled` prop to the `SelectTrigger`. + + + + + + + + + + Fruits + Apple + Banana + Blueberry + Grapes + Pineapple + + + + + + ```tsx + import { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + } from "ruru-ui/components/select"; + + export function DisabledSelect() { + return ( + + + + + + + Fruits + Apple + Banana + Blueberry + Grapes + Pineapple + + + + ); + } + ``` + + + + + +### Default Value + +You can set a default value for the `Select` component by passing the `defaultValue` prop to the `Select` component. + + + + + + + + + + Fruits + Apple + Banana + Blueberry + Grapes + Pineapple + + + + + +```tsx + import { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + } from "ruru-ui/components/select"; + +export function DefaultValueSelect() { + return ( + + + + + + + Fruits + Apple + Banana + Blueberry + Grapes + Pineapple + + + + ); +} +``` + + + +## Props + +| Name | Type | Default | Description | +| ----------------- | ------------------------ | --------- | ------------------------------------------ | +| **children** | ReactNode | - | The content of the select component. | +| **defaultValue** | string | - | The default value of the select component. | +| **disabled** | boolean | false | If `true`, the select will be disabled. | +| **value** | string | - | The value of the select component. | +| **onValueChange** | (value: string) => void | - | Function to call when the value changes. | +| **placeholder** | string | - | Placeholder text for the select component. | +| **variant** | 'primary' \| 'secondary' | 'primary' | The variant of the select component. | + +--- + +The `Select` component is a powerful and flexible dropdown menu that can be used in a variety of scenarios. It supports customization through its various props and can be integrated seamlessly into your application. + +## Importing Components + +The `Select` component is built using several subcomponents that you can import individually: + +- `Select` +- `SelectGroup` +- `SelectValue` +- `SelectTrigger` +- `SelectContent` +- `SelectLabel` +- `SelectItem` +- `SelectSeparator` +- `SelectScrollUpButton` +- `SelectScrollDownButton` + +This allows for fine-grained control and customization over the appearance and behavior of the select dropdown. + +For more detailed information on each subcomponent and additional examples, please refer to the documentation for each individual component. + +--- + +## Conclusion + +The `Select` component in the `ruru-ui` library offers a robust solution for creating dropdown menus in your application. By leveraging its flexible API and various customization options, you can create user-friendly and accessible dropdown menus that fit seamlessly into your application's design. + +Feel free to experiment with the examples provided and explore the various props to see how you can best utilize the `Select` component in your projects. + +--- + +This documentation provides a comprehensive overview of the `Select` component, including usage examples, prop descriptions, and subcomponent details. By following this structure, you ensure that users can easily understand how to use and customize the component in their projects. + +Would you like to add more specific examples or cover additional subcomponents in this documentation? diff --git a/packages/ui/package.json b/packages/ui/package.json index 0305b17..c17a434 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -87,6 +87,7 @@ "dependencies": { "@radix-ui/react-checkbox": "^1.1.1", "@radix-ui/react-direction": "^1.1.0", + "@radix-ui/react-select": "^2.1.1", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-switch": "^1.1.0", "@radix-ui/react-tabs": "^1.1.0", diff --git a/packages/ui/src/components/select.tsx b/packages/ui/src/components/select.tsx new file mode 100644 index 0000000..ccd84f5 --- /dev/null +++ b/packages/ui/src/components/select.tsx @@ -0,0 +1,164 @@ +"use client"; + +import * as React from "react"; +import { + CaretSortIcon, + CheckIcon, + ChevronDownIcon, + ChevronUpIcon, +} from "@/icons"; +import * as SelectPrimitive from "@radix-ui/react-select"; + +import { cn } from "@/utils/cn"; + +const Select = SelectPrimitive.Root; + +const SelectGroup = SelectPrimitive.Group; + +const SelectValue = SelectPrimitive.Value; + +const SelectTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + span]:line-clamp-1", + className, + )} + {...props} + > + {children} + + + + +)); +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName; + +const SelectScrollUpButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)); +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName; + +const SelectScrollDownButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)); +SelectScrollDownButton.displayName = + SelectPrimitive.ScrollDownButton.displayName; + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = "popper", ...props }, ref) => ( + + + + + {children} + + + + +)); +SelectContent.displayName = SelectPrimitive.Content.displayName; + +const SelectLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +SelectLabel.displayName = SelectPrimitive.Label.displayName; + +const SelectItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)); +SelectItem.displayName = SelectPrimitive.Item.displayName; + +const SelectSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +SelectSeparator.displayName = SelectPrimitive.Separator.displayName; + +export { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton, +}; diff --git a/packages/ui/src/icons/CaretSortIcon.tsx b/packages/ui/src/icons/CaretSortIcon.tsx new file mode 100644 index 0000000..7d9a23e --- /dev/null +++ b/packages/ui/src/icons/CaretSortIcon.tsx @@ -0,0 +1,17 @@ +export const CaretSortIcon = ({ className }: { className?: string }) => ( + + + +); diff --git a/packages/ui/src/icons/CheckIcon.tsx b/packages/ui/src/icons/CheckIcon.tsx new file mode 100644 index 0000000..13ba11d --- /dev/null +++ b/packages/ui/src/icons/CheckIcon.tsx @@ -0,0 +1,17 @@ +export const CheckIcon = ({ className }: { className?: string }) => ( + + + +); diff --git a/packages/ui/src/icons/ChevronDownIcon.tsx b/packages/ui/src/icons/ChevronDownIcon.tsx new file mode 100644 index 0000000..3a2ee3f --- /dev/null +++ b/packages/ui/src/icons/ChevronDownIcon.tsx @@ -0,0 +1,17 @@ +export const ChevronDownIcon = ({ className }: { className?: string }) => ( + + + +); diff --git a/packages/ui/src/icons/ChevronUpIcon.tsx b/packages/ui/src/icons/ChevronUpIcon.tsx new file mode 100644 index 0000000..d8dd285 --- /dev/null +++ b/packages/ui/src/icons/ChevronUpIcon.tsx @@ -0,0 +1,17 @@ +export const ChevronUpIcon = ({ className }: { className?: string }) => ( + + + +); diff --git a/packages/ui/src/icons/index.ts b/packages/ui/src/icons/index.ts new file mode 100644 index 0000000..e7afda1 --- /dev/null +++ b/packages/ui/src/icons/index.ts @@ -0,0 +1,4 @@ +export { CaretSortIcon } from "./CaretSortIcon"; +export { CheckIcon } from "./CheckIcon"; +export { ChevronDownIcon } from "./ChevronDownIcon"; +export { ChevronUpIcon } from "./ChevronUpIcon"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bd1960b..bb01fc5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -184,6 +184,9 @@ importers: '@radix-ui/react-direction': specifier: ^1.1.0 version: 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-select': + specifier: ^2.1.1 + version: 2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-slot': specifier: ^1.1.0 version: 1.1.0(@types/react@18.3.3)(react@18.3.1) @@ -2110,6 +2113,46 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /@radix-ui/react-select@2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-8iRDfyLtzxlprOo9IicnzvpsO1wNCkuwzzCM+Z5Rb5tNOpCdMvcc2AkzX0Fz+Tz9v6NJ5B/7EEgyZveo4FBRfQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/number': 1.1.0 + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.3 + '@types/react-dom': 18.3.0 + aria-hidden: 1.2.4 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.5.7(@types/react@18.3.3)(react@18.3.1) + dev: false + /@radix-ui/react-slot@1.0.2(@types/react@18.3.3)(react@18.3.1): resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} peerDependencies: