-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat-fe: Switch Toggle 컴포넌트 구현 (#230)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Jeongwoo Park <[email protected]>
- Loading branch information
1 parent
a311c59
commit d9a13a1
Showing
5 changed files
with
165 additions
and
2 deletions.
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
82 changes: 82 additions & 0 deletions
82
frontend/src/components/common/ToggleSwitch/ToggleSwitch.stories.tsx
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,82 @@ | ||
import { useArgs } from '@storybook/preview-api'; | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
import ToggleSwitch from './index'; | ||
|
||
const meta: Meta<typeof ToggleSwitch> = { | ||
title: 'Common/ToggleSwitch', | ||
component: ToggleSwitch, | ||
parameters: { | ||
layout: 'centered', | ||
docs: { | ||
description: { | ||
component: 'ToggleSwitch 컴포넌트는 스위치를 토글할 수 있는 기능을 제공합니다.', | ||
}, | ||
}, | ||
}, | ||
tags: ['autodocs'], | ||
argTypes: { | ||
isChecked: { | ||
description: '스위치의 체크 상태를 나타냅니다.', | ||
control: { type: 'boolean' }, | ||
table: { | ||
type: { summary: 'boolean' }, | ||
}, | ||
}, | ||
isDisabled: { | ||
description: '스위치의 활성화 상태를 나타냅니다.', | ||
control: { type: 'boolean' }, | ||
table: { | ||
type: { summary: 'boolean' }, | ||
}, | ||
}, | ||
onChange: { | ||
description: '스위치 상태 변경 시 호출되는 콜백 함수입니다.', | ||
action: 'changed', | ||
table: { | ||
type: { summary: '() => void' }, | ||
}, | ||
}, | ||
}, | ||
decorators: [ | ||
(Child, context) => { | ||
const [args, updateArgs] = useArgs(); | ||
|
||
const handleChange = () => { | ||
updateArgs({ isChecked: !context.args.isChecked }); | ||
}; | ||
|
||
return ( | ||
<Child | ||
args={{ | ||
...args, | ||
onChange: handleChange, | ||
}} | ||
/> | ||
); | ||
}, | ||
], | ||
}; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof meta>; | ||
|
||
export const Default: Story = { | ||
args: { | ||
isChecked: false, | ||
}, | ||
}; | ||
|
||
export const Disabled: Story = { | ||
args: { | ||
isChecked: false, | ||
isDisabled: true, | ||
}, | ||
}; | ||
|
||
Default.parameters = { | ||
docs: { | ||
description: { | ||
story: 'ToggleSwitch 컴포넌트의 기본 상태입니다.', | ||
}, | ||
}, | ||
}; |
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,20 @@ | ||
import S, { StyleProps } from './style'; | ||
|
||
interface ToggleSwitchProps extends StyleProps { | ||
onChange: () => void; | ||
} | ||
|
||
export default function ToggleSwitch({ isChecked, isDisabled, onChange }: ToggleSwitchProps) { | ||
return ( | ||
<S.Switch | ||
isChecked={isChecked} | ||
isDisabled={isDisabled} | ||
onClick={onChange} | ||
> | ||
<S.Knob | ||
isChecked={isChecked} | ||
isDisabled={isDisabled} | ||
/> | ||
</S.Switch> | ||
); | ||
} |
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,61 @@ | ||
import { css } from '@emotion/react'; | ||
import styled from '@emotion/styled'; | ||
|
||
export interface StyleProps { | ||
isChecked: boolean; | ||
isDisabled: boolean; | ||
} | ||
|
||
const Switch = styled.div<StyleProps>` | ||
--parent-width: 5rem; | ||
--parent-padding: 0.3rem; | ||
width: var(--parent-width); | ||
aspect-ratio: 5/3; | ||
background-color: ${({ isChecked, theme }) => | ||
isChecked ? theme.baseColors.purplescale[600] : theme.baseColors.grayscale[100]}; | ||
outline: 0.2rem solid | ||
${({ isChecked, theme }) => (isChecked ? theme.baseColors.purplescale[600] : theme.baseColors.grayscale[700])}; | ||
border-radius: 99rem; | ||
display: flex; | ||
align-items: center; | ||
padding: var(--parent-padding); | ||
cursor: pointer; | ||
transition: background-color 0.3s; | ||
outline-offset: -0.1rem; | ||
${({ isDisabled, theme }) => | ||
isDisabled && | ||
css({ | ||
backgroundColor: theme.baseColors.grayscale[400], | ||
outline: `0.2rem solid ${theme.baseColors.grayscale[500]}`, | ||
})} | ||
`; | ||
|
||
const Knob = styled.div<StyleProps>` | ||
height: 100%; | ||
aspect-ratio: 1/1; | ||
background-color: ${({ isChecked, theme }) => | ||
isChecked ? theme.baseColors.grayscale[200] : theme.baseColors.grayscale[700]}; | ||
border-radius: 50%; | ||
transform: ${({ isChecked }) => | ||
isChecked ? 'translate(calc(var(--parent-width) - var(--parent-padding)*2 - 100%))' : 'translate(0)'}; | ||
transition: transform 0.2s; | ||
${({ isDisabled, theme }) => | ||
isDisabled && | ||
css({ | ||
backgroundColor: theme.baseColors.grayscale[700], | ||
})} | ||
`; | ||
|
||
const S = { | ||
Switch, | ||
Knob, | ||
}; | ||
|
||
export default S; |