-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21 from saitamau-maximum/feat/select-box
feat: Select Box
- Loading branch information
Showing
7 changed files
with
586 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
183 changes: 183 additions & 0 deletions
183
packages/components/src/select-box/SelectBox.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
.trigger { | ||
display: flex; | ||
align-items: center; | ||
justify-content: space-between; | ||
height: 100%; | ||
padding: 0.5rem 0.5rem 0.5rem 1rem; | ||
gap: 0.5rem; | ||
border-radius: 0.5rem; | ||
border-width: 2px; | ||
border-style: solid; | ||
font-size: 1rem; | ||
cursor: pointer; | ||
transition: border-color 0.2s ease-in-out; | ||
|
||
:global(.light) & { | ||
border-color: $color-gray-200; | ||
background-color: $color-gray-100; | ||
color: $color-gray-900; | ||
|
||
&:hover { | ||
border-color: $color-gray-400; | ||
} | ||
|
||
&:focus { | ||
outline: none; | ||
} | ||
|
||
&:focus-visible { | ||
outline-offset: -2px; | ||
border-color: $color-green-400; | ||
} | ||
|
||
&[data-placeholder] { | ||
color: $color-gray-500; | ||
} | ||
} | ||
|
||
:global(.dark) & { | ||
border-color: $color-gray-700; | ||
background-color: $color-gray-800; | ||
color: $color-gray-50; | ||
|
||
&:hover { | ||
border-color: $color-gray-500; | ||
} | ||
|
||
&:focus { | ||
outline: none; | ||
} | ||
|
||
&:focus-visible { | ||
outline-offset: -2px; | ||
border-color: $color-green-500; | ||
} | ||
|
||
&[data-placeholder] { | ||
color: $color-gray-400; | ||
} | ||
} | ||
|
||
&.expanded { | ||
width: 100%; | ||
} | ||
} | ||
|
||
.icon { | ||
transition: transform 0.3s ease-in-out; | ||
line-height: 0; | ||
|
||
.trigger[data-state='open'] & { | ||
transform: rotate(-180deg); | ||
} | ||
} | ||
|
||
.content { | ||
display: flex; | ||
align-items: stretch; | ||
justify-content: space-between; | ||
width: 100%; | ||
padding: 0.5rem; | ||
box-sizing: border-box; | ||
border-radius: 0.5rem; | ||
transition: border-color 0.2s ease-in-out; | ||
|
||
:global(.light) &, | ||
&:global(.light) { | ||
background-color: $color-gray-200; | ||
box-shadow: $shadow-light; | ||
} | ||
|
||
:global(.dark) &, | ||
&:global(.dark) { | ||
background-color: $color-gray-700; | ||
box-shadow: $shadow-dark; | ||
} | ||
} | ||
|
||
.item { | ||
display: flex; | ||
align-items: center; | ||
justify-content: space-between; | ||
width: 100%; | ||
padding: 0.5rem 1rem; | ||
box-sizing: border-box; | ||
border-radius: 0.5rem; | ||
transition: background-color 0.2s ease-in-out; | ||
cursor: pointer; | ||
|
||
:global(.light) & { | ||
color: $color-gray-900; | ||
|
||
&:hover { | ||
outline: none; | ||
background-color: $color-gray-100; | ||
} | ||
|
||
&:focus-visible { | ||
outline-offset: -2px; | ||
background-color: $color-gray-100; | ||
} | ||
} | ||
|
||
:global(.dark) & { | ||
color: $color-gray-50; | ||
|
||
&:hover { | ||
outline: none; | ||
background-color: $color-gray-800; | ||
} | ||
|
||
&:focus-visible { | ||
outline-offset: -2px; | ||
background-color: $color-gray-800; | ||
} | ||
} | ||
} | ||
|
||
.groupLabel { | ||
padding: 0.25rem 0.5rem; | ||
font-size: 0.875rem; | ||
|
||
:global(.light) & { | ||
color: $color-gray-500; | ||
} | ||
|
||
:global(.dark) & { | ||
color: $color-gray-400; | ||
} | ||
} | ||
|
||
.separator { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
width: 100%; | ||
height: 2px; | ||
margin: 0.5rem 0; | ||
border-radius: 9999px; | ||
transition: background-color 0.2s ease-in-out; | ||
|
||
:global(.light) & { | ||
background-color: $color-gray-300; | ||
} | ||
|
||
:global(.dark) & { | ||
background-color: $color-gray-600; | ||
} | ||
} | ||
|
||
.scrollButton { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
cursor: default; | ||
|
||
:global(.light) & { | ||
color: $color-gray-600; | ||
} | ||
|
||
:global(.dark) & { | ||
color: $color-gray-300; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { Container } from '../__stories__/containter'; | ||
import { VStack } from '../__stories__/v-stack'; | ||
|
||
import { Props, SelectBox } from './SelectBox'; | ||
|
||
import type { Meta } from '@storybook/react'; | ||
|
||
const meta: Meta<typeof SelectBox> = { | ||
component: SelectBox, | ||
}; | ||
|
||
export default meta; | ||
|
||
const SelectBoxes = (args: Props) => ( | ||
<Container> | ||
<VStack theme="light"> | ||
<SelectBox {...args} _theme="light" /> | ||
</VStack> | ||
<VStack theme="dark"> | ||
<SelectBox {...args} _theme="dark" /> | ||
</VStack> | ||
</Container> | ||
); | ||
|
||
const DUMMY_OPTIONS = [ | ||
{ label: 'Option 1', value: 'option-1' }, | ||
{ label: 'Option Option 2', value: 'option-2' }, | ||
{ label: 'Option Option Option 3', value: 'option-3' }, | ||
]; | ||
|
||
const DUMMY_GROUPED_OPTIONS = [ | ||
{ | ||
label: 'Group 1', | ||
options: [ | ||
{ label: 'Option 1', value: 'option-1' }, | ||
{ label: 'Option Option 2', value: 'option-2' }, | ||
{ label: 'Option Option Option 3', value: 'option-3' }, | ||
], | ||
}, | ||
{ | ||
label: 'Group 2', | ||
options: [ | ||
{ label: 'Option 4', value: 'option-4' }, | ||
{ label: 'Option Option 5', value: 'option-5' }, | ||
{ label: 'Option Option Option 6', value: 'option-6' }, | ||
], | ||
}, | ||
]; | ||
|
||
export const Simple = () => <SelectBoxes options={DUMMY_OPTIONS} />; | ||
|
||
export const Grouped = () => ( | ||
<SelectBoxes groupedOptions={DUMMY_GROUPED_OPTIONS} /> | ||
); | ||
|
||
export const Placeholder = () => ( | ||
<SelectBoxes options={DUMMY_OPTIONS} placeholder="Select an option" /> | ||
); | ||
|
||
export const Expanded = () => <SelectBoxes expanded options={DUMMY_OPTIONS} />; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import * as Select from '@radix-ui/react-select'; | ||
import clsx from 'clsx'; | ||
import { ChevronDown, ChevronUp } from 'react-feather'; | ||
|
||
import styles from './SelectBox.module.scss'; | ||
|
||
type SingleGroupOptions = { | ||
label: string; | ||
value: string; | ||
}[]; | ||
|
||
type GroupedOptions = { | ||
label: string; | ||
options: SingleGroupOptions; | ||
}[]; | ||
|
||
export type Props = { | ||
expanded?: boolean; | ||
placeholder?: string; | ||
/** don't use this prop, it's for storybook only */ | ||
_theme?: 'light' | 'dark'; | ||
} & ( | ||
| { | ||
options: SingleGroupOptions; | ||
groupedOptions?: undefined; | ||
} | ||
| { | ||
options?: undefined; | ||
groupedOptions: GroupedOptions; | ||
} | ||
); | ||
|
||
const SelectBoxItems = ({ options }: { options: SingleGroupOptions }) => { | ||
return options.map((option) => ( | ||
<Select.Item | ||
key={option.value} | ||
value={option.value} | ||
className={styles.item} | ||
> | ||
<Select.ItemText>{option.label}</Select.ItemText> | ||
</Select.Item> | ||
)); | ||
}; | ||
|
||
const SelectBoxGroups = ({ | ||
groupedOptions, | ||
}: { | ||
groupedOptions: GroupedOptions; | ||
}) => { | ||
return groupedOptions.map((group, i) => ( | ||
<> | ||
<Select.Group key={group.label}> | ||
<Select.Label className={styles.groupLabel}>{group.label}</Select.Label> | ||
<SelectBoxItems options={group.options} /> | ||
</Select.Group> | ||
{i < groupedOptions.length - 1 && ( | ||
<Select.Separator className={styles.separator} /> | ||
)} | ||
</> | ||
)); | ||
}; | ||
|
||
export const SelectBox = ({ | ||
expanded = false, | ||
options, | ||
groupedOptions, | ||
placeholder = 'Select an option', | ||
_theme, | ||
}: Props) => { | ||
return ( | ||
<Select.Root> | ||
<Select.Trigger | ||
className={clsx(styles.trigger, expanded && styles.expanded)} | ||
> | ||
<Select.Value placeholder={placeholder} className={styles.value} /> | ||
<Select.Icon className={styles.icon}> | ||
<ChevronDown /> | ||
</Select.Icon> | ||
</Select.Trigger> | ||
|
||
<Select.Portal> | ||
<Select.Content className={clsx(_theme, styles.content)}> | ||
<Select.ScrollUpButton className={styles.scrollButton}> | ||
<ChevronUp /> | ||
</Select.ScrollUpButton> | ||
<Select.Viewport> | ||
{options && <SelectBoxItems options={options} />} | ||
{groupedOptions && ( | ||
<SelectBoxGroups groupedOptions={groupedOptions} /> | ||
)} | ||
</Select.Viewport> | ||
<Select.ScrollDownButton className={styles.scrollButton}> | ||
<ChevronDown /> | ||
</Select.ScrollDownButton> | ||
</Select.Content> | ||
</Select.Portal> | ||
</Select.Root> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './SelectBox'; |
Oops, something went wrong.