diff --git a/packages/design-system/packages/core/src/components/select/Select.stories.tsx b/packages/design-system/packages/core/src/components/select/Select.stories.tsx index 5641cc2..dec2336 100644 --- a/packages/design-system/packages/core/src/components/select/Select.stories.tsx +++ b/packages/design-system/packages/core/src/components/select/Select.stories.tsx @@ -25,9 +25,9 @@ const meta: Meta = { size: { description: '셀렉트 박스의 크기를 지정합니다.', control: 'select', - options: ['md', 'lg'], + options: ['xs', 'sm', 'md', 'lg'], table: { - type: { summary: ['md', 'lg'].join(' | ') }, + type: { summary: ['xs', 'sm', 'md', 'lg'].join(' | ') }, defaultValue: { summary: 'md' }, }, }, @@ -40,6 +40,24 @@ const meta: Meta = { defaultValue: { summary: 'sm' }, }, }, + border: { + description: '셀렉트 박스의 테두리 지정 여부를 지정합니다.', + control: 'select', + options: ['default', 'none'], + table: { + type: { summary: ['default', 'none'].join(' | ') }, + defaultValue: { summary: 'sm' }, + }, + }, + deselect: { + description: + 'true로 지정 시 같은 옵션을 다시 선택하면 선택이 취소됩니다.', + control: 'boolean', + table: { + type: { summary: 'boolean' }, + defaultValue: { summary: 'false' }, + }, + }, disabled: { description: '셀렉트 박스의 비활성화 상태를 지정합니다.', control: 'boolean', diff --git a/packages/design-system/packages/core/src/components/select/Select.style.ts b/packages/design-system/packages/core/src/components/select/Select.style.ts index 8802bbb..65964aa 100644 --- a/packages/design-system/packages/core/src/components/select/Select.style.ts +++ b/packages/design-system/packages/core/src/components/select/Select.style.ts @@ -16,6 +16,8 @@ export const variants = { info: getSelectModifier('info'), }, size: { + xs: getSelectModifier('size-xs'), + sm: getSelectModifier('size-sm'), md: '', lg: getSelectModifier('size-lg'), }, @@ -28,6 +30,10 @@ export const variants = { none: '', with: getSelectModifier('background'), }, + border: { + default: '', + none: getSelectModifier('border-none'), + }, } export const selectVariants = cva(selectClassName, { @@ -37,5 +43,6 @@ export const selectVariants = cva(selectClassName, { size: 'md', round: 'sm', background: 'none', + border: 'default', }, }) diff --git a/packages/design-system/packages/core/src/components/select/Select.tsx b/packages/design-system/packages/core/src/components/select/Select.tsx index 4101b45..4c78a7d 100644 --- a/packages/design-system/packages/core/src/components/select/Select.tsx +++ b/packages/design-system/packages/core/src/components/select/Select.tsx @@ -51,7 +51,8 @@ function Option({ round={round === 'md' ? 'sm' : 'xs'} title={title || `선택: ${label || value}`} disabled={disabled} - onClick={select}> + onClick={select} + withoutClickInteraction> {label || value} {isSelected && } @@ -66,6 +67,7 @@ function Select( size, round, mobile: isMobile = false, + deselect: isDeselect = false, value: valueProps, defaultValue = '', onChange, @@ -109,20 +111,23 @@ function Select( const [label, setLabel] = React.useState(options[defaultValue] ?? '') - const setValue = React.useCallback((v: string) => { - setValueState((prev: string) => { - if (prev === v) { - setLabel(options[defaultValue] ?? '') - return defaultValue - } - setLabel(options[v] ?? '') - return v - }) - closeAndFocusToSelectInput() - }, []) + const setValue = React.useCallback( + (v: string) => { + setValueState((prev: string) => { + if (isDeselect && prev === v) { + setLabel(options[defaultValue] ?? '') + return defaultValue + } + setLabel(options[v] ?? '') + return v + }) + closeAndFocusToSelectInput() + }, + [isDeselect], + ) - const inputBox = useElementRect(containerRef) - const optionBox = useElementRect(optionRef, [isOpen]) + const inputBox = useElementRect(containerRef, [size]) + const optionBox = useElementRect(optionRef, [isOpen, size]) useIsomorphicLayoutEffect(() => { if (isOpen) { @@ -205,6 +210,7 @@ function SelectContainer( label, description, state, + border, withBackground, ...props }: SelectContainerProps, @@ -218,6 +224,7 @@ function SelectContainer( size: props.size, round: props.round, background: withBackground ? 'with' : null, + border, }), className, )} diff --git a/packages/design-system/packages/core/src/components/select/Select.type.ts b/packages/design-system/packages/core/src/components/select/Select.type.ts index 4683319..e9a21ec 100644 --- a/packages/design-system/packages/core/src/components/select/Select.type.ts +++ b/packages/design-system/packages/core/src/components/select/Select.type.ts @@ -25,7 +25,9 @@ export interface SelectContainerProps state?: keyof SelectVariants['state'] size?: keyof SelectVariants['size'] round?: keyof SelectVariants['round'] + border?: keyof SelectVariants['border'] withBackground?: boolean + deselect?: boolean mobile?: boolean label?: React.ReactNode description?: React.ReactNode @@ -34,7 +36,13 @@ export interface SelectContainerProps export type SelectProps = React.PropsWithChildren & Omit< SelectContainerProps, - 'className' | 'style' | 'label' | 'description' | 'state' | 'withBackground' + | 'className' + | 'style' + | 'label' + | 'description' + | 'state' + | 'withBackground' + | 'border' > export type SelectOption = Record diff --git a/packages/design-system/packages/core/src/components/select/_index.scss b/packages/design-system/packages/core/src/components/select/_index.scss index edb52c9..715135f 100644 --- a/packages/design-system/packages/core/src/components/select/_index.scss +++ b/packages/design-system/packages/core/src/components/select/_index.scss @@ -78,6 +78,26 @@ } } + &--border-none { + & .ds-select__input > input { + border: none; + &:focus, + &:hover, + &:active { + background-color: variable.$ds-gray-050; + } + .dark &:focus, + .dark &:hover, + .dark &:active { + background-color: variable.$ds-gray-700; + } + &:disabled, + .dark &:disabled { + background-color: inherit; + } + } + } + &--background { & .ds-select__input > input { background-color: variable.$ds-gray-050; @@ -91,6 +111,14 @@ } } } + &.ds-select--border-none .ds-select__input > input { + &:focus { + background-color: variable.$ds-gray-050; + .dark & { + background-color: variable.$ds-gray-700; + } + } + } } &__option { @@ -207,6 +235,34 @@ } } + &--size-xs { + & .ds-select__input { + & > input { + height: 2rem; + padding: 0.25rem 0.75rem; + padding-right: 2rem; + font-size: variable.$ds-font-size-200; + } + & > svg { + width: 2rem; + font-size: variable.$ds-font-size-300; + } + } + } + &--size-sm { + & .ds-select__input { + & > input { + height: 2.25rem; + padding: 0.25rem 0.75rem; + padding-right: 2.25rem; + font-size: variable.$ds-font-size-200; + } + & > svg { + width: 2.25rem; + font-size: variable.$ds-font-size-300; + } + } + } &--size-lg { & .ds-select__input { & > input {