Updated various components to replace traditional select implementations with the new SelectField component. This change enhances the user interface by providing a more consistent layout and improved accessibility. Additionally, refactored the dashboard and operations pages to utilize DataGridCard for better organization of content, streamlining the overall user experience.
101 lines
2.6 KiB
TypeScript
101 lines
2.6 KiB
TypeScript
import type { ComponentProps, ReactNode } from 'react'
|
|
|
|
import { Field, FieldDescription, FieldLabel } from '@evobgp/ui/components/field'
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectGroup,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from '@evobgp/ui/components/select'
|
|
import { cn } from '@evobgp/ui/lib/utils'
|
|
|
|
export type SelectMenuItem<T extends string = string> = {
|
|
value: T
|
|
label: ReactNode
|
|
disabled?: boolean
|
|
}
|
|
|
|
type SelectRootProps = ComponentProps<typeof Select>
|
|
|
|
export interface SelectMenuProps<T extends string = string>
|
|
extends Omit<SelectRootProps, 'children' | 'onValueChange' | 'value' | 'defaultValue'> {
|
|
items: ReadonlyArray<SelectMenuItem<T>>
|
|
value?: T | null
|
|
defaultValue?: T | null
|
|
onValueChange?: (value: T | null) => void
|
|
placeholder?: string
|
|
id?: string
|
|
triggerClassName?: string
|
|
contentClassName?: string
|
|
size?: 'sm' | 'default'
|
|
side?: ComponentProps<typeof SelectContent>['side']
|
|
}
|
|
|
|
/** ReUI c-select-4: `items` на Root, опции в `SelectGroup`. */
|
|
export function SelectMenu<T extends string = string>({
|
|
items,
|
|
placeholder,
|
|
id,
|
|
triggerClassName,
|
|
contentClassName,
|
|
size = 'default',
|
|
side,
|
|
value,
|
|
defaultValue,
|
|
onValueChange,
|
|
...selectProps
|
|
}: SelectMenuProps<T>) {
|
|
return (
|
|
<Select
|
|
items={items}
|
|
value={value}
|
|
defaultValue={defaultValue}
|
|
onValueChange={(next) => onValueChange?.(next as T | null)}
|
|
{...selectProps}
|
|
>
|
|
<SelectTrigger id={id} className={cn('w-full', triggerClassName)} size={size}>
|
|
<SelectValue placeholder={placeholder} />
|
|
</SelectTrigger>
|
|
<SelectContent side={side} className={contentClassName}>
|
|
<SelectGroup>
|
|
{items.map((item) => (
|
|
<SelectItem key={item.value} value={item.value} disabled={item.disabled}>
|
|
{item.label}
|
|
</SelectItem>
|
|
))}
|
|
</SelectGroup>
|
|
</SelectContent>
|
|
</Select>
|
|
)
|
|
}
|
|
|
|
export interface SelectFieldProps<T extends string = string> extends SelectMenuProps<T> {
|
|
label?: ReactNode
|
|
description?: ReactNode
|
|
fieldClassName?: string
|
|
}
|
|
|
|
export function SelectField<T extends string = string>({
|
|
label,
|
|
description,
|
|
fieldClassName,
|
|
id,
|
|
...menuProps
|
|
}: SelectFieldProps<T>) {
|
|
return (
|
|
<Field className={fieldClassName}>
|
|
{label ? <FieldLabel htmlFor={id}>{label}</FieldLabel> : null}
|
|
<SelectMenu id={id} {...menuProps} />
|
|
{description ? (
|
|
typeof description === 'string' ? (
|
|
<FieldDescription className="font-mono text-xs">{description}</FieldDescription>
|
|
) : (
|
|
description
|
|
)
|
|
) : null}
|
|
</Field>
|
|
)
|
|
}
|