diff --git a/src/ui/toggle-switch/index.ts b/src/ui/toggle-switch/index.ts new file mode 100644 index 00000000..b9c054e9 --- /dev/null +++ b/src/ui/toggle-switch/index.ts @@ -0,0 +1 @@ +export { ToggleSwitch, type ToggleSwitchProps } from './toggle-switch.tsx'; diff --git a/src/ui/toggle-switch/toggle-switch.stories.tsx b/src/ui/toggle-switch/toggle-switch.stories.tsx new file mode 100644 index 00000000..2dfc54c0 --- /dev/null +++ b/src/ui/toggle-switch/toggle-switch.stories.tsx @@ -0,0 +1,53 @@ +import { useState } from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { ToggleSwitch } from './toggle-switch.tsx'; + +const meta: Meta = { + title: 'ui/ToggleSwitch', + component: ToggleSwitch, + parameters: { + layout: 'centered', + }, + argTypes: { + left: { control: 'text' }, + right: { control: 'text' }, + }, + tags: ['autodocs'], + decorators: [ + (Story, context) => { + const [value, setValue] = useState(context.args.left); + + return ( +
+ +
+ Current state: {value} +
+
+ ); + }, + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const SwitchFirst: Story = { + args: { + left: '증상 AI 검색', + right: '제품 검색', + }, + // render: (args) => { + // const [checked, setChecked] = useState(false); + + // return ; + // }, +}; diff --git a/src/ui/toggle-switch/toggle-switch.styles.css.ts b/src/ui/toggle-switch/toggle-switch.styles.css.ts new file mode 100644 index 00000000..71637827 --- /dev/null +++ b/src/ui/toggle-switch/toggle-switch.styles.css.ts @@ -0,0 +1,58 @@ +import { style } from '@vanilla-extract/css'; +import { globalVars } from '../theme.css.ts'; +import { typography } from '../typography.css.ts'; + +export const toggleGroupRoot = style([ + typography('body_2_14_sb'), + { + all: 'unset', + position: 'relative', + display: 'inline-flex', + alignItems: 'center', + width: '184px', + height: '40px', + backgroundColor: globalVars.color.grey200, + borderRadius: '20px', + cursor: 'pointer', + }, +]); + +export const toggleGroupSlider = style({ + position: 'absolute', + width: '50%', + height: '100%', + borderRadius: '20px', + backgroundColor: globalVars.color.mainblue500, + transition: 'transform 200ms ease', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + selectors: { + ':has(> * + [data-state="on"]) &': { + transform: 'translateX(100%)', + }, + }, +}); + +export const toggleGroupItem = style({ + all: 'unset', + position: 'relative', + zIndex: 1, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + height: '20px', + width: '92px', + borderRadius: '20px', + transition: 'color 200ms ease', + userSelect: 'none', + cursor: 'pointer', + selectors: { + '&[data-state="on"]': { + color: globalVars.color.white, + }, + '&[data-state="off"]': { + color: globalVars.color.grey500, + }, + }, +}); diff --git a/src/ui/toggle-switch/toggle-switch.tsx b/src/ui/toggle-switch/toggle-switch.tsx new file mode 100644 index 00000000..dc40a795 --- /dev/null +++ b/src/ui/toggle-switch/toggle-switch.tsx @@ -0,0 +1,28 @@ +import * as ToggleGroup from '@radix-ui/react-toggle-group'; +import * as styles from './toggle-switch.styles.css.ts'; + +export type ToggleSwitchProps = Pick< + ToggleGroup.ToggleGroupSingleProps, + 'value' | 'onValueChange' +> & { + left: string; + right: string; +}; + +export const ToggleSwitch = ({ left, right, ...props }: ToggleSwitchProps) => { + return ( + + + {left} + + + {right} + +
+ + ); +};