fix(SW-1509): removed support for plain array items in order to handle proper props extending
various fixes for supporting default selected
This commit is contained in:
@@ -14,9 +14,15 @@ export default meta
|
|||||||
|
|
||||||
type Story = StoryObj<typeof Select>
|
type Story = StoryObj<typeof Select>
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{ label: 'Foo', value: 'foo' },
|
||||||
|
{ label: 'Bar', value: 'bar' },
|
||||||
|
{ label: 'Baz', value: 'baz' },
|
||||||
|
]
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
items: ['Foo', 'Bar', 'Baz'],
|
items,
|
||||||
label: 'Select an item',
|
label: 'Select an item',
|
||||||
name: 'foo',
|
name: 'foo',
|
||||||
},
|
},
|
||||||
@@ -24,40 +30,38 @@ export const Default: Story = {
|
|||||||
|
|
||||||
export const DefaultSelected: Story = {
|
export const DefaultSelected: Story = {
|
||||||
args: {
|
args: {
|
||||||
items: ['Foo', 'Bar', 'Baz'],
|
items,
|
||||||
label: 'Select an item',
|
|
||||||
name: 'foo',
|
|
||||||
defaultSelectedKey: 'Foo',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ObjectItem: Story = {
|
|
||||||
args: {
|
|
||||||
items: [
|
|
||||||
{ label: 'Foo', value: 'foo' },
|
|
||||||
{ label: 'Bar', value: 'bar' },
|
|
||||||
{ label: 'Baz', value: 'baz' },
|
|
||||||
],
|
|
||||||
label: 'Select an item',
|
label: 'Select an item',
|
||||||
name: 'foo',
|
name: 'foo',
|
||||||
|
defaultSelectedKey: 'foo',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Icons: Story = {
|
export const Icons: Story = {
|
||||||
args: {
|
args: {
|
||||||
icon: 'star',
|
items,
|
||||||
itemIcon: 'check',
|
|
||||||
items: ['Foo', 'Bar', 'Baz'],
|
|
||||||
label: 'Select an item',
|
label: 'Select an item',
|
||||||
name: 'foo',
|
name: 'foo',
|
||||||
|
icon: 'star',
|
||||||
|
itemIcon: 'check',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Filtering: Story = {
|
export const Filtering: Story = {
|
||||||
args: {
|
args: {
|
||||||
items: ['Foo', 'Bar', 'Baz'],
|
items,
|
||||||
label: 'Select an item',
|
label: 'Select an item',
|
||||||
name: 'foo',
|
name: 'foo',
|
||||||
enableFiltering: true,
|
enableFiltering: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const FilteringSelected: Story = {
|
||||||
|
args: {
|
||||||
|
items,
|
||||||
|
label: 'Select an item',
|
||||||
|
name: 'foo',
|
||||||
|
enableFiltering: true,
|
||||||
|
defaultSelectedKey: 'foo',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { Typography } from '../Typography'
|
|||||||
import { SelectItem } from './SelectItem'
|
import { SelectItem } from './SelectItem'
|
||||||
import { SelectFilter } from './SelectFilter'
|
import { SelectFilter } from './SelectFilter'
|
||||||
|
|
||||||
import type { SelectProps } from './types'
|
import type { SelectProps, SelectFilterProps } from './types'
|
||||||
|
|
||||||
import styles from './select.module.css'
|
import styles from './select.module.css'
|
||||||
|
|
||||||
@@ -23,10 +23,9 @@ export function Select({
|
|||||||
isDisabled,
|
isDisabled,
|
||||||
icon,
|
icon,
|
||||||
itemIcon,
|
itemIcon,
|
||||||
enableFiltering,
|
|
||||||
...props
|
...props
|
||||||
}: SelectProps) {
|
}: SelectProps | SelectFilterProps) {
|
||||||
if (enableFiltering) {
|
if ('enableFiltering' in props) {
|
||||||
return (
|
return (
|
||||||
<SelectFilter
|
<SelectFilter
|
||||||
name={name}
|
name={name}
|
||||||
@@ -34,7 +33,6 @@ export function Select({
|
|||||||
items={items}
|
items={items}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
itemIcon={itemIcon}
|
itemIcon={itemIcon}
|
||||||
isDisabled={isDisabled}
|
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@@ -59,22 +57,26 @@ export function Select({
|
|||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<SelectValue className={cx(styles.displayText, styles.selectValue)}>
|
<SelectValue className={cx(styles.displayText, styles.selectValue)}>
|
||||||
{({ isPlaceholder, selectedText }) => (
|
{({ selectedText }) => {
|
||||||
<>
|
return (
|
||||||
<Typography
|
<>
|
||||||
variant={
|
<Typography
|
||||||
isPlaceholder ? 'Body/Paragraph/mdRegular' : 'Label/xsRegular'
|
variant={
|
||||||
}
|
selectedText
|
||||||
>
|
? 'Label/xsRegular'
|
||||||
<span className={styles.label}>{label}</span>
|
: 'Body/Paragraph/mdRegular'
|
||||||
</Typography>
|
}
|
||||||
{selectedText ? (
|
>
|
||||||
<Typography variant="Body/Paragraph/mdRegular">
|
<span className={styles.label}>{label}</span>
|
||||||
<span>{selectedText}</span>
|
|
||||||
</Typography>
|
</Typography>
|
||||||
) : null}
|
{selectedText ? (
|
||||||
</>
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
)}
|
<span>{selectedText}</span>
|
||||||
|
</Typography>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}}
|
||||||
</SelectValue>
|
</SelectValue>
|
||||||
|
|
||||||
<MaterialIcon
|
<MaterialIcon
|
||||||
@@ -88,27 +90,16 @@ export function Select({
|
|||||||
|
|
||||||
<Popover className={styles.popover} shouldFlip={false}>
|
<Popover className={styles.popover} shouldFlip={false}>
|
||||||
<ListBox className={styles.listBox}>
|
<ListBox className={styles.listBox}>
|
||||||
{items.map((item) =>
|
{items.map((item) => (
|
||||||
typeof item === 'object' ? (
|
<SelectItem
|
||||||
<SelectItem
|
key={item.value}
|
||||||
key={item.label}
|
id={item.value}
|
||||||
id={item.label}
|
icon={item.icon || itemIcon}
|
||||||
icon={item.icon || itemIcon}
|
isDisabled={item.isDisabled}
|
||||||
isDisabled={item.isDisabled}
|
>
|
||||||
>
|
{item.label}
|
||||||
{item.label}
|
</SelectItem>
|
||||||
</SelectItem>
|
))}
|
||||||
) : (
|
|
||||||
<SelectItem
|
|
||||||
key={item}
|
|
||||||
id={item}
|
|
||||||
icon={itemIcon}
|
|
||||||
isDisabled={isDisabled}
|
|
||||||
>
|
|
||||||
{item.toString()}
|
|
||||||
</SelectItem>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</ListBox>
|
</ListBox>
|
||||||
</Popover>
|
</Popover>
|
||||||
</AriaSelect>
|
</AriaSelect>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
ListBox,
|
ListBox,
|
||||||
Popover,
|
Popover,
|
||||||
} from 'react-aria-components'
|
} from 'react-aria-components'
|
||||||
import { cx } from 'class-variance-authority'
|
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
import { MaterialIcon } from '../Icons/MaterialIcon'
|
import { MaterialIcon } from '../Icons/MaterialIcon'
|
||||||
@@ -21,13 +20,14 @@ export function SelectFilter({
|
|||||||
name,
|
name,
|
||||||
label,
|
label,
|
||||||
items,
|
items,
|
||||||
isRequired,
|
|
||||||
isDisabled,
|
isDisabled,
|
||||||
icon,
|
icon,
|
||||||
itemIcon,
|
itemIcon,
|
||||||
|
defaultSelectedKey,
|
||||||
|
...props
|
||||||
}: SelectFilterProps) {
|
}: SelectFilterProps) {
|
||||||
const [focus, setFocus] = useState(false)
|
const [focus, setFocus] = useState(false)
|
||||||
const [value, setValue] = useState<Key | null>(null)
|
const [value, setValue] = useState<Key | null>(defaultSelectedKey ?? null)
|
||||||
const iconColor = isDisabled ? 'Icon/Interactive/Disabled' : 'Icon/Default'
|
const iconColor = isDisabled ? 'Icon/Interactive/Disabled' : 'Icon/Default'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -35,11 +35,12 @@ export function SelectFilter({
|
|||||||
className={styles.select}
|
className={styles.select}
|
||||||
name={name}
|
name={name}
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
isRequired={isRequired}
|
|
||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
onSelectionChange={(val) => setValue(val)}
|
onSelectionChange={setValue}
|
||||||
onFocus={() => setFocus(true)}
|
onFocus={() => setFocus(true)}
|
||||||
onBlur={() => setFocus(false)}
|
onBlur={() => setFocus(false)}
|
||||||
|
defaultSelectedKey={defaultSelectedKey}
|
||||||
|
{...props}
|
||||||
>
|
>
|
||||||
<label className={styles.inner}>
|
<label className={styles.inner}>
|
||||||
{icon ? (
|
{icon ? (
|
||||||
@@ -60,7 +61,7 @@ export function SelectFilter({
|
|||||||
<span className={styles.label}>{label}</span>
|
<span className={styles.label}>{label}</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="Body/Paragraph/mdRegular">
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
<Input className={cx(styles.input, { [styles.hasValue]: value })} />
|
<Input className={styles.input} />
|
||||||
</Typography>
|
</Typography>
|
||||||
</span>
|
</span>
|
||||||
<Button className={styles.button}>
|
<Button className={styles.button}>
|
||||||
@@ -81,27 +82,16 @@ export function SelectFilter({
|
|||||||
offset={22}
|
offset={22}
|
||||||
>
|
>
|
||||||
<ListBox className={styles.listBox}>
|
<ListBox className={styles.listBox}>
|
||||||
{items.map((item) =>
|
{items.map((item) => (
|
||||||
typeof item === 'object' ? (
|
<SelectItem
|
||||||
<SelectItem
|
key={item.value}
|
||||||
key={item.label}
|
id={item.value}
|
||||||
id={item.label}
|
icon={item.icon || itemIcon}
|
||||||
icon={item.icon || itemIcon}
|
isDisabled={item.isDisabled}
|
||||||
isDisabled={item.isDisabled}
|
>
|
||||||
>
|
{item.label}
|
||||||
{item.label}
|
</SelectItem>
|
||||||
</SelectItem>
|
))}
|
||||||
) : (
|
|
||||||
<SelectItem
|
|
||||||
key={item}
|
|
||||||
id={item}
|
|
||||||
icon={itemIcon}
|
|
||||||
isDisabled={isDisabled}
|
|
||||||
>
|
|
||||||
{item.toString()}
|
|
||||||
</SelectItem>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</ListBox>
|
</ListBox>
|
||||||
</Popover>
|
</Popover>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
&.hasValue {
|
&[value]:not([value='']) {
|
||||||
position: unset;
|
position: unset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ComponentProps } from 'react'
|
import { ComponentProps } from 'react'
|
||||||
import { Key, ListBoxItem, Select } from 'react-aria-components'
|
import { ComboBox, Key, ListBoxItem, Select } from 'react-aria-components'
|
||||||
import { MaterialIconProps } from '../Icons/MaterialIcon'
|
import { MaterialIconProps } from '../Icons/MaterialIcon'
|
||||||
|
|
||||||
interface Item extends Record<string, unknown> {
|
interface Item extends Record<string, unknown> {
|
||||||
@@ -12,10 +12,9 @@ interface Item extends Record<string, unknown> {
|
|||||||
export interface SelectProps extends ComponentProps<typeof Select> {
|
export interface SelectProps extends ComponentProps<typeof Select> {
|
||||||
icon?: MaterialIconProps['icon']
|
icon?: MaterialIconProps['icon']
|
||||||
itemIcon?: MaterialIconProps['icon']
|
itemIcon?: MaterialIconProps['icon']
|
||||||
items: (Key | Item)[]
|
items: Item[]
|
||||||
name: string
|
name: string
|
||||||
label: string
|
label: string
|
||||||
enableFiltering?: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectItemProps extends ComponentProps<typeof ListBoxItem> {
|
export interface SelectItemProps extends ComponentProps<typeof ListBoxItem> {
|
||||||
@@ -23,7 +22,11 @@ export interface SelectItemProps extends ComponentProps<typeof ListBoxItem> {
|
|||||||
children: string
|
children: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disabling rule because we're just omitting one prop while keeping interface
|
export interface SelectFilterProps extends ComponentProps<typeof ComboBox> {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
icon?: MaterialIconProps['icon']
|
||||||
export interface SelectFilterProps
|
itemIcon?: MaterialIconProps['icon']
|
||||||
extends Omit<SelectProps, 'enableFiltering'> {}
|
items: Item[]
|
||||||
|
name: string
|
||||||
|
label: string
|
||||||
|
enableFiltering: boolean
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user