Skip to content

Commit

Permalink
fix(select): dynamic items collection type (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
PHILLIPS71 authored Apr 15, 2024
1 parent 44a390d commit 7cebc28
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 22 deletions.
37 changes: 26 additions & 11 deletions packages/react/src/components/select/Select.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
import type { UseSelectProps } from '@/components/select/use-select.hook'
import type { ButtonProps, SelectProps as ComponentProps, ListBoxProps, PopoverProps } from 'react-aria-components'
import type { Override } from '@/utilities/types'
import type { ButtonProps, ListBoxProps, PopoverProps, SelectProps } from 'react-aria-components'

import React from 'react'
import { Button, Select as Component, ListBox, Popover } from 'react-aria-components'
import { Button, ListBox, Popover, Select } from 'react-aria-components'

import { useFormGroupContext } from '@/components/form/use-form-group.hook'
import SelectOption from '@/components/select/SelectOption'
import SelectValue from '@/components/select/SelectValue'
import { SelectContext, useSelect } from '@/components/select/use-select.hook'

export type SelectProps<T extends object> = ComponentProps<T> &
Omit<UseSelectProps<T>, 'ref'> &
ListBoxProps<T> & {
items?: Pick<ListBoxProps<T>, 'items'> | null
type OveriddenSelectProps<T extends object> = Override<
SelectProps<T>,
{
children?: React.ReactNode | ((item: T) => React.ReactNode)
}
>

type OveriddenListBoxProps<T extends object> = Override<
ListBoxProps<T>,
{
items?: Iterable<T> | null
}
>

type ComponentProps<T extends object> = UseSelectProps<T> &
OveriddenSelectProps<T> &
OveriddenListBoxProps<T> & {
placement?: 'top' | 'bottom'
}

const Select: <T extends object>(props: SelectProps<T>) => React.ReactNode = (() =>
const Component: <T extends object>(props: ComponentProps<T>) => React.ReactNode = (() =>
React.forwardRef((props, ref: React.ForwardedRef<HTMLDivElement>) => {
const {
children,
Expand Down Expand Up @@ -44,7 +58,7 @@ const Select: <T extends object>(props: SelectProps<T>) => React.ReactNode = (()
onChange: group?.onChange ?? onChange,
})

const component = React.useMemo<ComponentProps<any>>(
const select = React.useMemo<SelectProps<any>>(
() => ({
ref: group?.ref ?? ref,
name: group?.name,
Expand Down Expand Up @@ -97,7 +111,7 @@ const Select: <T extends object>(props: SelectProps<T>) => React.ReactNode = (()

return (
<SelectContext.Provider value={context}>
<Component {...component}>
<Select {...select}>
<Button {...button}>
<SelectValue />

Expand All @@ -122,11 +136,12 @@ const Select: <T extends object>(props: SelectProps<T>) => React.ReactNode = (()
<Popover {...popover}>
<ListBox {...listbox}>{children}</ListBox>
</Popover>
</Component>
</Select>
</SelectContext.Provider>
)
}))()

export default Object.assign(Select, {
export { ComponentProps as SelectProps }
export default Object.assign(Component, {
Option: SelectOption,
})
15 changes: 8 additions & 7 deletions packages/react/src/components/select/SelectOption.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import type { ListBoxItemProps as ComponentProps } from 'react-aria-components'
import type { ListBoxItemProps } from 'react-aria-components'

import React from 'react'
import { ListBoxItem as Component } from 'react-aria-components'
import { ListBoxItem } from 'react-aria-components'

import { useSelectContext } from '@/components/select/use-select.hook'

type SelectOptionProps = ComponentProps
type ComponentProps = ListBoxItemProps

const SelectOption = React.forwardRef<HTMLDivElement, SelectOptionProps>((props, ref) => {
const Component = React.forwardRef<HTMLDivElement, ComponentProps>((props, ref) => {
const { children, className, ...rest } = props

const { slots } = useSelectContext()

const component = React.useMemo<ComponentProps>(
const item = React.useMemo<ListBoxItemProps>(
() => ({
ref,
className: slots.option(),
Expand All @@ -21,7 +21,8 @@ const SelectOption = React.forwardRef<HTMLDivElement, SelectOptionProps>((props,
[ref, rest, slots]
)

return <Component {...component}>{children}</Component>
return <ListBoxItem {...item}>{children}</ListBoxItem>
})

export default SelectOption
export { ComponentProps as SelectOptionProps }
export default Component
8 changes: 4 additions & 4 deletions packages/react/src/components/select/SelectValue.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import React from 'react'
import { SelectValue as Component, SelectStateContext } from 'react-aria-components'
import { SelectStateContext, SelectValue } from 'react-aria-components'

import { useSelectContext } from '@/components/select/use-select.hook'

const SelectValue: React.FC = () => {
const Component: React.FC = () => {
const { selectedItem } = React.useContext(SelectStateContext)
const { slots } = useSelectContext()

const render = React.useMemo(() => {
if (selectedItem?.textValue) return selectedItem.textValue

return <Component className={slots.placeholder()} />
return <SelectValue className={slots.placeholder()} />
}, [selectedItem?.textValue, slots])

return render
}

export default SelectValue
export default Component
1 change: 1 addition & 0 deletions packages/react/src/components/select/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export type { SelectProps } from '@/components/select/Select'
export type { SelectOptionProps } from '@/components/select/SelectOption'

export { default as Select } from '@/components/select/Select'
2 changes: 2 additions & 0 deletions packages/react/src/utilities/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export type Component<
as?: React.ElementType<TProps>
}

export type Override<T, R> = Omit<T, keyof R> & R

export type ComponentWithoutAs<T extends React.ElementType> = Omit<Component<T>, 'as'>

export type Selection = 'all' | Set<string | number>
Expand Down

0 comments on commit 7cebc28

Please sign in to comment.