From 83616fa6eb53b8f49c69c772abe8f416641b284f Mon Sep 17 00:00:00 2001 From: Dani Moreno <96433370+dani-moreno@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:28:36 +0100 Subject: [PATCH] Support separators in `Select` and `Dropdown` (#992) * Support separators in Select and Dropdown * fix breadcrumbs * colors --- .../Forms/Fields/Select/index.stories.tsx | 1 + .../Forms/Fields/Select/index.tsx | 24 ++++++++++----- .../Navigation/Dropdown/index.stories.tsx | 1 + .../Navigation/Dropdown/index.tsx | 29 ++++++++++++------- .../Navigation/Header/Breadcrumbs/index.tsx | 7 +++-- lib/ui/dropdown-menu.tsx | 2 +- lib/ui/select.tsx | 2 +- 7 files changed, 44 insertions(+), 22 deletions(-) diff --git a/lib/experimental/Forms/Fields/Select/index.stories.tsx b/lib/experimental/Forms/Fields/Select/index.stories.tsx index 6ef5ec6db..5c714ecd4 100644 --- a/lib/experimental/Forms/Fields/Select/index.stories.tsx +++ b/lib/experimental/Forms/Fields/Select/index.stories.tsx @@ -54,6 +54,7 @@ export const WithCustomTrigger: Story = { options: [ { value: "red", label: "Red" }, { value: "green", label: "Green" }, + "separator", { value: "blue", label: "Blue" }, ], }, diff --git a/lib/experimental/Forms/Fields/Select/index.tsx b/lib/experimental/Forms/Fields/Select/index.tsx index 9b43c0568..270fe2ef5 100644 --- a/lib/experimental/Forms/Fields/Select/index.tsx +++ b/lib/experimental/Forms/Fields/Select/index.tsx @@ -9,12 +9,13 @@ import { SelectContent, SelectItem as SelectItemPrimitive, Select as SelectPrimitive, + SelectSeparator, SelectTrigger, SelectValue as SelectValuePrimitive, } from "@/ui/select" import { forwardRef } from "react" -type SelectItemProps = { +type SelectItemObject = { value: T label: string icon?: IconType @@ -22,6 +23,8 @@ type SelectItemProps = { avatar?: AvatarVariant } +type SelectItemProps = SelectItemObject | "separator" + type SelectProps = { placeholder: string onChange: (value: T) => void @@ -33,7 +36,7 @@ type SelectProps = { onOpenChange?: (open: boolean) => void } -const SelectItem = ({ item }: { item: SelectItemProps }) => { +const SelectItem = ({ item }: { item: SelectItemObject }) => { return (
@@ -56,7 +59,7 @@ const SelectItem = ({ item }: { item: SelectItemProps }) => { ) } -const SelectValue = ({ item }: { item: SelectItemProps }) => { +const SelectValue = ({ item }: { item: SelectItemObject }) => { return (
{item.icon && ( @@ -87,7 +90,10 @@ export const Select = forwardRef>( }, ref ) { - const selectedOption = options.find((option) => option.value === value) + const selectedOption = options.find( + (option): option is Exclude => + option !== "separator" && option.value === value + ) return ( >( )} - {options.map((option) => ( - - ))} + {options.map((option, index) => + option === "separator" ? ( + + ) : ( + + ) + )} ) diff --git a/lib/experimental/Navigation/Dropdown/index.stories.tsx b/lib/experimental/Navigation/Dropdown/index.stories.tsx index f085838f5..a04505186 100644 --- a/lib/experimental/Navigation/Dropdown/index.stories.tsx +++ b/lib/experimental/Navigation/Dropdown/index.stories.tsx @@ -33,6 +33,7 @@ export const Default: Story = { icon: Icons.Save, description: "Preserve changes", }, + "separator", { label: "Delete", onClick: () => console.log("Delete clicked"), diff --git a/lib/experimental/Navigation/Dropdown/index.tsx b/lib/experimental/Navigation/Dropdown/index.tsx index 374c46fc4..2e043523e 100644 --- a/lib/experimental/Navigation/Dropdown/index.tsx +++ b/lib/experimental/Navigation/Dropdown/index.tsx @@ -11,11 +11,12 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, + DropdownMenuSeparator, DropdownMenuTrigger, } from "@/ui/dropdown-menu" import { NavigationItem } from "../utils" -export type DropdownItem = NavigationItem & { +export type DropdownItemObject = NavigationItem & { onClick?: () => void icon?: IconType description?: string @@ -23,12 +24,14 @@ export type DropdownItem = NavigationItem & { avatar?: AvatarVariant } +export type DropdownItem = DropdownItemObject | "separator" + type DropdownProps = { items: DropdownItem[] children?: React.ReactNode } -const DropdownItem = ({ item }: { item: DropdownItem }) => { +const DropdownItem = ({ item }: { item: DropdownItemObject }) => { const { label, ...props } = item const content = ( @@ -101,15 +104,19 @@ export function Dropdown({ items, children }: DropdownProps) {
- {items.map((item, index) => ( - - ))} + {items.map((item, index) => + item === "separator" ? ( + + ) : ( + + ) + )}
diff --git a/lib/experimental/Navigation/Header/Breadcrumbs/index.tsx b/lib/experimental/Navigation/Header/Breadcrumbs/index.tsx index 6be8a3994..73793d357 100644 --- a/lib/experimental/Navigation/Header/Breadcrumbs/index.tsx +++ b/lib/experimental/Navigation/Header/Breadcrumbs/index.tsx @@ -9,7 +9,10 @@ import { import { ModuleAvatar } from "@/experimental/Information/ModuleAvatar" -import { Dropdown, type DropdownItem } from "@/experimental/Navigation/Dropdown" +import { + Dropdown, + type DropdownItemObject, +} from "@/experimental/Navigation/Dropdown" import { ChevronRight } from "@/icons/app" import { Link } from "@/lib/linkHandler" @@ -28,7 +31,7 @@ interface BreadcrumbItemProps { isLast: boolean } -type DropdownItemWithoutIcon = Omit +type DropdownItemWithoutIcon = Omit function BreadcrumbItem({ item, isLast }: BreadcrumbItemProps) { // eslint-disable-next-line @typescript-eslint/no-unused-vars diff --git a/lib/ui/dropdown-menu.tsx b/lib/ui/dropdown-menu.tsx index 5f25ca1b4..d60359cfd 100644 --- a/lib/ui/dropdown-menu.tsx +++ b/lib/ui/dropdown-menu.tsx @@ -162,7 +162,7 @@ const DropdownMenuSeparator = React.forwardRef< >(({ className, ...props }, ref) => ( )) diff --git a/lib/ui/select.tsx b/lib/ui/select.tsx index a31c4c20e..d35d65425 100644 --- a/lib/ui/select.tsx +++ b/lib/ui/select.tsx @@ -128,7 +128,7 @@ const SelectSeparator = React.forwardRef< >(({ className, ...props }, ref) => ( ))