-
Notifications
You must be signed in to change notification settings - Fork 0
feat(web): migrate BottomSheet (#55) #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| import type { Meta, StoryObj } from "@storybook/nextjs-vite"; | ||
| import { OverlayProvider, overlay } from "overlay-kit"; | ||
| import { BottomSheet } from "./BottomSheet"; | ||
|
|
||
| /** | ||
| * **vaul docs** | ||
| * https://vaul.emilkowal.ski/api | ||
| */ | ||
| const meta: Meta<typeof BottomSheet> = { | ||
| title: "V2/Components/BottomSheet", | ||
| component: BottomSheet, | ||
| parameters: { | ||
| layout: "centered", | ||
| }, | ||
| tags: ["autodocs"], | ||
| argTypes: { | ||
| locked: { | ||
| control: "boolean", | ||
| description: "์ธ๋ถ ์์์์ ์ํธ์์ฉ์ ์ค์ ํฉ๋๋ค.", | ||
| }, | ||
| radius: { | ||
| control: "select", | ||
| options: ["none", "small", "medium", "large"], | ||
| }, | ||
| theme: { | ||
| control: "select", | ||
| options: ["light", "dark"], | ||
| }, | ||
| }, | ||
| decorators: [ | ||
| Story => ( | ||
| <OverlayProvider> | ||
| <Story /> | ||
| </OverlayProvider> | ||
| ), | ||
| ], | ||
| } satisfies Meta<typeof BottomSheet>; | ||
|
|
||
| export default meta; | ||
| type Story = StoryObj<typeof meta>; | ||
|
|
||
| const BottomSheetNoScroll = () => { | ||
| return ( | ||
| <div style={{ height: 240, padding: 24, display: "flex", alignItems: "center", justifyContent: "center" }}> | ||
| BottomSheet | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| const BottomSheetScroll = () => { | ||
| return ( | ||
| <div style={{ height: 2000, padding: 24, display: "flex", alignItems: "center", justifyContent: "center" }}> | ||
| BottomSheet | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export const BottomSheets: Story = { | ||
| args: { | ||
| showHandle: true, | ||
| radius: "medium", | ||
| }, | ||
| render: args => { | ||
| const openNoScrollBottomSheet = () => { | ||
| overlay.open(({ isOpen, close }) => ( | ||
| <BottomSheet | ||
| {...args} | ||
| open={isOpen} | ||
| onClose={() => { | ||
| close(); | ||
| }} | ||
| content={<BottomSheetNoScroll />} | ||
| /> | ||
| )); | ||
| }; | ||
|
|
||
| const openScrollBottomSheet = () => { | ||
| overlay.open(({ isOpen, close }) => ( | ||
| <BottomSheet | ||
| {...args} | ||
| open={isOpen} | ||
| onClose={() => { | ||
| close(); | ||
| }} | ||
| content={<BottomSheetScroll />} | ||
| /> | ||
| )); | ||
| }; | ||
|
|
||
| return ( | ||
| <div | ||
| style={{ | ||
| display: "flex", | ||
| flexDirection: "column", | ||
| gap: 16, | ||
| alignItems: "center", | ||
| }} | ||
| > | ||
| <button type="button" onClick={openNoScrollBottomSheet}> | ||
| Open(No Scroll) | ||
| </button> | ||
| <button type="button" onClick={openScrollBottomSheet}> | ||
| Open(Scroll) | ||
| </button> | ||
| </div> | ||
| ); | ||
| }, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,71 @@ | ||||||||||
| import { css, cva } from "../../../../styled-system/css"; | ||||||||||
|
|
||||||||||
| /* Color tokens */ | ||||||||||
| const SEED_PALETTE_COLOR_BASE_100 = "#ffffff"; | ||||||||||
| const SEED_PALETTE_COLOR_BASE_800 = "#494f54"; | ||||||||||
|
|
||||||||||
| /* Radius tokens */ | ||||||||||
| const SEED_SPACING_100 = "0px"; | ||||||||||
| const SEED_SPACING_300 = "8px"; | ||||||||||
| const SEED_SPACING_600 = "20px"; | ||||||||||
| const SEED_SPACING_900 = "32px"; | ||||||||||
|
|
||||||||||
| export const overlay = css({ | ||||||||||
| position: "fixed", | ||||||||||
| inset: 0, | ||||||||||
| backgroundColor: "rgba(0, 0, 0, 0.4)", | ||||||||||
| }); | ||||||||||
|
|
||||||||||
| export const drawerContent = cva({ | ||||||||||
| base: { | ||||||||||
| position: "fixed", | ||||||||||
| bottom: 0, | ||||||||||
| left: 0, | ||||||||||
| right: 0, | ||||||||||
| height: "fit-content", | ||||||||||
| backgroundColor: "#fff", | ||||||||||
| outline: "none", | ||||||||||
| maxHeight: "calc(100dvh - 32px)", | ||||||||||
| borderBottomLeftRadius: "0 !important", | ||||||||||
| borderBottomRightRadius: "0 !important", | ||||||||||
| overflowY: "hidden", | ||||||||||
| }, | ||||||||||
| variants: { | ||||||||||
| radius: { | ||||||||||
| none: { | ||||||||||
| borderTop: SEED_SPACING_100, | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CSS ์์ฑ ์ค๋ฅ
๋ค์๊ณผ ๊ฐ์ด ์์ ํ์ธ์: none: {
- borderTop: SEED_SPACING_100,
+ borderRadius: SEED_SPACING_100,
},๐ Committable suggestion
Suggested change
๐ค Prompt for AI Agents |
||||||||||
| }, | ||||||||||
| small: { | ||||||||||
| borderRadius: SEED_SPACING_300, | ||||||||||
| }, | ||||||||||
| medium: { | ||||||||||
| borderRadius: SEED_SPACING_600, | ||||||||||
| }, | ||||||||||
| large: { | ||||||||||
| borderRadius: SEED_SPACING_900, | ||||||||||
| }, | ||||||||||
| }, | ||||||||||
| theme: { | ||||||||||
| light: { | ||||||||||
| backgroundColor: SEED_PALETTE_COLOR_BASE_100, | ||||||||||
| }, | ||||||||||
| dark: { | ||||||||||
| backgroundColor: SEED_PALETTE_COLOR_BASE_800, | ||||||||||
| }, | ||||||||||
| }, | ||||||||||
| }, | ||||||||||
| }); | ||||||||||
|
|
||||||||||
| export const drawerContentInner = css({ | ||||||||||
| maxHeight: "calc(100dvh - 68px)", | ||||||||||
| overflowY: "auto", | ||||||||||
| WebkitOverflowScrolling: "touch", | ||||||||||
| }); | ||||||||||
|
|
||||||||||
| export const drawerHandle = css({ | ||||||||||
| height: "36px", | ||||||||||
| width: "100%", | ||||||||||
| display: "flex", | ||||||||||
| alignItems: "center", | ||||||||||
| justifyContent: "center", | ||||||||||
| }); | ||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,44 @@ | ||||||
| "use client"; | ||||||
|
|
||||||
| import { SwitchCase } from "@/shared/utils/SwitchCase"; | ||||||
| import { Drawer } from "vaul"; | ||||||
| import * as styles from "./BottomSheet.style"; | ||||||
| import type { BottomSheetProps } from "./BottomSheet.type"; | ||||||
|
|
||||||
| export const BottomSheet = ({ | ||||||
| open, | ||||||
| onClose, | ||||||
| locked = true, | ||||||
| showHandle = true, | ||||||
| handleOnly = false, | ||||||
| radius, | ||||||
| theme = "light", | ||||||
| zIndex = 1, | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. zIndex ๊ธฐ๋ณธ๊ฐ์ด ๋ฎ์ ์ ์์ ์ค๋ฒ๋ ์ด ์ปดํฌ๋ํธ์ zIndex ๊ธฐ๋ณธ๊ฐ์ด 1๋ก ์ค์ ๋์ด ์๋๋ฐ, ์ผ๋ฐ์ ์ผ๋ก ๋ชจ๋ฌ/๋ฐํ ์ํธ๋ 1000 ์ด์์ ๋์ z-index๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ค๋ฅธ UI ์์์ ๊ฐ๋ ค์ง ์ํ์ด ์์ต๋๋ค. ๋ค์๊ณผ ๊ฐ์ด ์์ ์ ๊ถ์ฅํฉ๋๋ค: - zIndex = 1,
+ zIndex = 1000,๐ Committable suggestion
Suggested change
๐ค Prompt for AI Agents |
||||||
| className, | ||||||
| content, | ||||||
| }: BottomSheetProps) => { | ||||||
| return ( | ||||||
| <Drawer.Root open={open} onClose={onClose} modal={locked} handleOnly={handleOnly}> | ||||||
| <Drawer.Portal> | ||||||
| <Drawer.Overlay className={styles.overlay} data-frieeren-component="BottomSheetOverlay" style={{ zIndex }} /> | ||||||
| <Drawer.Content | ||||||
| className={`${styles.drawerContent({ radius, theme })} ${className || ""}`} | ||||||
| data-frieeren-component="BottomSheet" | ||||||
| style={{ zIndex }} | ||||||
| > | ||||||
| <SwitchCase | ||||||
| value={String(showHandle)} | ||||||
| caseBy={{ | ||||||
| true: ( | ||||||
| <div className={styles.drawerHandle}> | ||||||
| <Drawer.Handle style={{ width: 36 }} /> | ||||||
| </div> | ||||||
| ), | ||||||
| }} | ||||||
| /> | ||||||
| <div className={styles.drawerContentInner}>{content}</div> | ||||||
| </Drawer.Content> | ||||||
| </Drawer.Portal> | ||||||
| </Drawer.Root> | ||||||
| ); | ||||||
| }; | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| export const BottomSheetRadius = { | ||
| NONE: "none", | ||
| SMALL: "small", | ||
| MEDIUM: "medium", | ||
| LARGE: "large", | ||
| } as const; | ||
|
|
||
| export const BottomSheetTheme = { | ||
| light: "light", | ||
| dark: "dark", | ||
| } as const; | ||
|
|
||
| type ValueOf<T> = T[keyof T]; | ||
|
|
||
| export type BottomSheetRadius = ValueOf<typeof BottomSheetRadius>; | ||
| export type BottomSheetTheme = ValueOf<typeof BottomSheetTheme>; | ||
| export interface BottomSheetProps { | ||
| /** ๋ฐํ ์ํธ์ ์ด๋ฆผ/๋ซํ ์ํ๋ฅผ ์ ์ดํฉ๋๋ค. */ | ||
| open?: boolean; | ||
| /** ๋ฐํ ์ํธ๊ฐ ๋ซํ ๋ ํธ์ถ๋๋ ์ฝ๋ฐฑ ํจ์์ ๋๋ค. */ | ||
| onClose?: () => void; | ||
| /** ๋ฐํ ์ํธ์ ๋ชจ๋ฌ๋ฆฌํฐ๋ฅผ ์ ์ดํฉ๋๋ค. true์ผ ๊ฒฝ์ฐ ์ธ๋ถ ์์์์ ์ํธ์์ฉ์ ๋นํ์ฑํํ๊ณ ์คํฌ๋ฆฐ ๋ฆฌ๋์๋ ๋ฐํ ์ํธ ์ฝํ ์ธ ๋ง ๋ณด์ ๋๋ค. */ | ||
| locked?: boolean; | ||
| /** ๋ฐํ ์ํธ ์๋จ์ ๋๋๊ทธ ํธ๋ค์ ํ์ํ ์ง ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํฉ๋๋ค. */ | ||
| showHandle?: boolean; | ||
| /** true์ผ ๊ฒฝ์ฐ ํธ๋ค์ ํตํด์๋ง ๋๋๊ทธ๊ฐ ๊ฐ๋ฅํฉ๋๋ค. */ | ||
| handleOnly?: boolean; | ||
| /** ๋ฐํ ์ํธ์ z-index ๊ฐ์ ์ค์ ํฉ๋๋ค. */ | ||
| zIndex?: number; | ||
| /** ๋ฐํ ์ํธ์ ๋ชจ์๋ฆฌ ๋ฅ๊ธ๊ธฐ ์ ๋๋ฅผ ์ค์ ํฉ๋๋ค. */ | ||
| radius?: BottomSheetRadius; | ||
| /** ๋ฐํ ์ํธ์ ํ ๋ง๋ฅผ ์ค์ ํฉ๋๋ค. */ | ||
| theme?: BottomSheetTheme; | ||
| /** ์ถ๊ฐ CSS ํด๋์ค๋ช ์ ์ ์ฉํฉ๋๋ค. */ | ||
| className?: string; | ||
| /** ๋ฐํ ์ํธ ๋ด๋ถ์ ํ์ํ ์ฝํ ์ธ ์ ๋๋ค. */ | ||
| content?: React.ReactNode; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export { BottomSheet } from "./BottomSheet"; | ||
| export type { BottomSheetProps } from "./BottomSheet.type"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
overlay ์ ๋ฆฌ ์ฝ๋ฐฑ ๋๋ฝ์ผ๋ก ์ธํ ์ ์ฌ์ ๋ฉ๋ชจ๋ฆฌ ๋์
overlay.open์ฝ๋ฐฑ์์unmountํ๋ผ๋ฏธํฐ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์์ต๋๋ค. learnings์ ๋ฐ๋ฅด๋ฉด, overlay-kit์ ์ฝ๋ฐฑ์{ isOpen, close, unmount }๋ฅผ ์ ๊ณตํ๋ฉฐ,unmount๋ ์ค๋ฒ๋ ์ด๊ฐ ์์ ํ ์ข ๋ฃ/์ธ๋ง์ดํธ๋ ๋ ํธ์ถ๋์ด์ผ ํฉ๋๋ค. ์ด๋ฅผ ๋๋ฝํ๋ฉด ์ค๋ฒ๋ ์ด ์ธ์คํด์ค๊ฐ ๋ฉ๋ชจ๋ฆฌ์์ ์ ๋๋ก ์ ๋ฆฌ๋์ง ์์ ์ ์์ต๋๋ค.Based on learnings.
๋ค์ diff๋ฅผ ์ ์ฉํ์ฌ
unmount์ฝ๋ฐฑ์ ์ถ๊ฐํ์ธ์:const openNoScrollBottomSheet = () => { - overlay.open(({ isOpen, close }) => ( + overlay.open(({ isOpen, close, unmount }) => ( <BottomSheet {...args} open={isOpen} onClose={() => { close(); + unmount(); }} content={<BottomSheetNoScroll />} /> )); }; const openScrollBottomSheet = () => { - overlay.open(({ isOpen, close }) => ( + overlay.open(({ isOpen, close, unmount }) => ( <BottomSheet {...args} open={isOpen} onClose={() => { close(); + unmount(); }} content={<BottomSheetScroll />} /> )); };์ฐธ๊ณ :
BottomSheet์ปดํฌ๋ํธ์onCloseprop์ดDrawer.Root์onClose์ ์ด๋ป๊ฒ ์ฐ๊ฒฐ๋๋์ง ํ์ธํ๊ณ ,Drawer๊ฐ ์์ ํ ์ธ๋ง์ดํธ๋ ํunmount๊ฐ ํธ์ถ๋๋๋ก ํ์ด๋ฐ์ ์กฐ์ ํด์ผ ํ ์ ์์ต๋๋ค.Also applies to: 78-87
๐ค Prompt for AI Agents