Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/app/(auth)/login/_styles/Login.css.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { style } from "@vanilla-extract/css";

import { semantic, typography } from "@/styles";
import { colors, semantic, typography } from "@/styles";

export const wrapper = style({
width: "100%",
height: "100vh",
height: "100dvh",
overflow: "hidden",
});

Expand Down Expand Up @@ -39,6 +39,7 @@ export const logoWrapper = style({
export const logoIcon = style({
width: "7.7rem",
height: "4rem",
color: colors.redOrange[50],
});

export const gradientOverlay = style({
Expand Down
2 changes: 1 addition & 1 deletion src/app/member/onboarding/layout.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { style } from "@vanilla-extract/css";
export const wrapper = style({
width: "100%",
maxWidth: "480px",
height: "100vh",
height: "100dvh",
display: "flex",
flexDirection: "column",
});
Expand Down
2 changes: 1 addition & 1 deletion src/app/member/profile/_components/Banner/Banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const Banner = () => {
</Text>
{/* TODO: [가게 등록하기] url로 변경 */}
<Link href='/' className={styles.linkWrapper}>
<Text typo='label2' color='neutral.10'>
<Text typo='label2Sb' color='neutral.10'>
가게 등록하기
</Text>
<ChevronRightIcon width={16} height={16} className={styles.icon} />
Expand Down
8 changes: 4 additions & 4 deletions src/assets/logo-wordmark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 10 additions & 27 deletions src/components/ui/BottomSheet/BottomSheet.css.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { style } from "@vanilla-extract/css";

import { colors, radius, semantic, typography } from "@/styles";
import { colors, semantic } from "@/styles";
import { zIndex } from "@/styles/zIndex.css";

export const overlay = style({
position: "fixed",
inset: 0,
backgroundColor: semantic.background.dim,
zIndex: zIndex.overlay,
});

export const content = style({
Expand All @@ -15,25 +17,19 @@ export const content = style({
right: 0,
maxWidth: "48rem",
margin: "0 auto",
display: "flex",
justifyContent: "center",
backgroundColor: colors.common[100],
borderTopLeftRadius: radius[120],
borderTopRightRadius: radius[120],
borderRadius: "2.8rem 2.8rem 0 0",
zIndex: zIndex.modal,
});

export const innerContent = style({
width: "100%",
minHeight: "32.6rem",
maxHeight: "100vh",
minHeight: "37.5rem",
maxHeight: "calc(100dvh - 52px)",
display: "flex",
flexDirection: "column",
});

export const handleContainer = style({
padding: "1.2rem 16.2rem 1rem",
});

export const handle = style({
width: "5.1rem",
height: "0.4rem",
Expand All @@ -43,29 +39,16 @@ export const handle = style({
});

export const title = style({
display: "flex",
gap: "1rem",
width: "100%",
padding: "1.4rem 2rem",
...typography.title2Sb,
color: semantic.text.normal,
});

export const sheetBody = style({
display: "flex",
flex: 1,
flexDirection: "column",
gap: "0.8rem",
padding: "1.4rem 2rem 6rem",
overflowY: "auto",
});

export const sheetBodyTitle = style({
...typography.title3Sb,
color: semantic.text.normal,
});

export const sheetBodyDescription = style({
...typography.body2Rg,
color: semantic.text.alternative,
padding: "2rem",
});

export const buttonContainer = style({
Expand Down
139 changes: 49 additions & 90 deletions src/components/ui/BottomSheet/BottomSheet.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,137 +2,96 @@ import type { Meta, StoryObj } from "@storybook/nextjs";
import { useState } from "react";

import { Button } from "../Button";
import { Text } from "../Text";
import { BottomSheet } from "./BottomSheet";
import * as styles from "./BottomSheet.css";

const meta: Meta<typeof BottomSheet> = {
const meta: Meta<typeof BottomSheet.Root> = {
title: "Components/BottomSheet",
component: BottomSheet,
component: BottomSheet.Root,
tags: ["autodocs"],
argTypes: {
open: { table: { disable: true } },
title: { control: "text" },
trigger: { control: false },
footer: { control: false },
content: { control: false },
},
};
export default meta;

type Story = StoryObj<typeof BottomSheet>;
type Story = StoryObj<typeof BottomSheet.Root>;

const BottomSheetWrapper = (
args: React.ComponentProps<typeof BottomSheet> & {
content?: React.ReactNode;
footer?: React.ReactNode;
}
) => {
const [isOpen, setIsOpen] = useState(args.open || false);
const BottomSheetWrapper = ({
defaultOpen = false,
title = "서비스 필수 이용 약관",
bodyText = "회원님의 개인정보 보호를 위해 장기간 비밀번호를 유지 중인 경우 비밀번호 변경을 안내해 드리고 있습니다.",
confirmText = "동의하고 계속하기",
}: {
defaultOpen?: boolean;
title?: string;
bodyText?: string;
confirmText?: string;
}) => {
const [isOpen, setIsOpen] = useState(defaultOpen);

return (
<BottomSheet
{...args}
open={isOpen}
onOpenChange={setIsOpen}
trigger={
<BottomSheet.Root open={isOpen} onOpenChange={setIsOpen}>
<BottomSheet.Trigger>
<Button variant='primary' onClick={() => setIsOpen(true)}>
바텀시트 열기
</Button>
}
content={args.content}
/>
</BottomSheet.Trigger>

Comment on lines +31 to +37
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

중첩 button 발생 가능성

<BottomSheet.Trigger>asChild를 주지 않으면 내부에서 <button>이 생성되어 <Button>(또는 <button>)을 감싸게 됩니다. 이는 불법 중첩 HTML이며 접근성 오류를 유발합니다.

-<BottomSheet.Trigger>
+<BottomSheet.Trigger asChild>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<BottomSheet.Root open={isOpen} onOpenChange={setIsOpen}>
<BottomSheet.Trigger>
<Button variant='primary' onClick={() => setIsOpen(true)}>
바텀시트 열기
</Button>
}
content={args.content}
/>
</BottomSheet.Trigger>
<BottomSheet.Root open={isOpen} onOpenChange={setIsOpen}>
<BottomSheet.Trigger asChild>
<Button variant='primary' onClick={() => setIsOpen(true)}>
바텀시트 열기
</Button>
</BottomSheet.Trigger>
🤖 Prompt for AI Agents
In src/components/ui/BottomSheet/BottomSheet.stories.tsx around lines 31 to 37,
the BottomSheet.Trigger component wraps a Button without using the asChild prop,
causing nested button elements which is invalid HTML and harms accessibility. To
fix this, add the asChild prop to BottomSheet.Trigger so it forwards its
behavior to the child Button without creating an extra button element.

<BottomSheet.Content>
<BottomSheet.Title>
<Text typo='title3Sb'>{title}</Text>
</BottomSheet.Title>

<BottomSheet.Body>
<Text>{bodyText}</Text>
</BottomSheet.Body>

<BottomSheet.Footer>
<Button size='fullWidth' onClick={() => setIsOpen(false)}>
{confirmText}
</Button>
</BottomSheet.Footer>
</BottomSheet.Content>
</BottomSheet.Root>
);
};

export const Default: Story = {
render: args => (
render: () => (
<BottomSheetWrapper
{...args}
title='서비스 필수 이용약관'
footer={
<Button size='fullWidth' onClick={() => alert("동의합니다")}>
동의하고 계속하기
</Button>
}
content={
<>
<h2 className={styles.sheetBodyTitle}>비밀번호를 변경해 안내 설명</h2>
<p className={styles.sheetBodyDescription}>
회원님의 개인정보 보호를 위해 장기간 비밀번호를 유지 중인 경우
비밀번호 변경을 안내해 드리고 있습니다. 회원님의 개인정보 보호를
위해 장기간 비밀번호를 유지 중인 경우 비밀번호 변경을 안내해 드리고
있습니다.회원님의 개인정보 보호를 위해 장기간 비밀번호를 유지 중인
경우 비밀번호 변경을 안내해 드리고 있습니다.회원님의 개인정보 보호를
위해 장기간 비밀번호를 유지 중인 경우 비밀번호 변경을 안내해 드리고
있습니다.회원님의 개인정보 보호를 위해 장기간 비밀번호를 유지 중인
경우 비밀번호 변경을 안내해 드리고 있습니다.회원님의 개인정보 보호를
위해 장기간 비밀번호를 유지 중인 경우 비밀번호 변경을 안내해 드리고
있습니다.회원님의 개인정보 보호를 위해 장기간 비밀번호를 유지 중인
경우 비밀번호 변경을 안내해 드리고 있습니다.회원님의 개인정보 보호를
위해 장기간 비밀번호를 유지 중인 경우 비밀번호 변경을 안내해 드리고
있습니다.회원님의 개인정보 보호를 위해 장기간 비밀번호를 유지 중인
경우 비밀번호 변경을 안내해 드리고 있습니다.회원님의 개인정보 보호를
위해 장기간 비밀번호를 유지 중인 경우 비밀번호 변경을 안내해 드리고
있습니다.회원님의 개인정보 보호를 위해 장기간 비밀번호를 유지 중인
경우 비밀번호 변경을 안내해 드리고 있습니다.회원님의 개인정보 보호를
위해 장기간 비밀번호를 유지 중인 경우 비밀번호 변경을 안내해 드리고
있습니다.회원님의 개인정보 보호를 위해 장기간 비밀번호를 유지 중인
경우 비밀번호 변경을 안내해 드리고 있습니다.회원님의 개인정보 보호를
위해 장기간 비밀번호를 유지 중인 경우 비밀번호 변경을 안내해 드리고
있습니다.회원님의 개인정보 보호를 위해 장기간 비밀번호를 유지 중인
경우 비밀번호 변경을 안내해 드리고 있습니다.회원님의 개인정보 보호를
위해 장기간 비밀번호를 유지 중인 경우 비밀번호 변경을 안내해 드리고
있습니다.
</p>
</>
}
defaultOpen={false}
title='서비스 필수 이용 약관'
bodyText={`회원님의 개인정보 보호를 위해 장기간 비밀번호를 유지 중인 경우 비밀번호 변경을 안내해 드리고 있습니다.
동일한 설명이 반복되어 내용이 길어지면, Body 영역에 scroll이 적용됩니다.`}
confirmText='동의하고 계속하기'
/>
),
parameters: {
docs: {
description: {
story:
"버튼을 클릭하면 바텀시트가 열리고, 하단에 footer 버튼이 렌더링됩니다.",
"Trigger 버튼을 클릭하면 BottomSheet가 열리고 Title/Body/Footer가 표시됩니다.",
},
},
},
};

export const Opened: Story = {
render: (args, { viewMode }) => {
render: (_, { viewMode }) => {
const forceClosedInDocs = viewMode === "docs";

return (
<BottomSheetWrapper
{...args}
open={forceClosedInDocs ? false : args.open}
defaultOpen={!forceClosedInDocs}
title='즉시 열리는 바텀시트'
footer={
<Button size='fullWidth' onClick={() => alert("닫기")}>
확인
</Button>
}
content={
<>
<h2 className={styles.sheetBodyTitle}>
비밀번호를 변경해 안내 설명
</h2>
<p className={styles.sheetBodyDescription}>
회원님의 개인정보 보호를 위해 장기간 비밀번호를 유지 중인 경우
비밀번호 변경을 안내해 드리고 있습니다.
</p>
</>
}
bodyText='회원님의 개인정보 보호를 위해 장기간 비밀번호를 유지 중인 경우 비밀번호 변경을 안내해 드리고 있습니다.'
confirmText='확인'
/>
);
},
args: {
open: true,
},
parameters: {
docs: {
description: {
story:
"Canvas에선 열린 상태로 시작되며, 하단에 버튼이 함께 표시됩니다.",
"Canvas에선 열린 상태로 시작되며, 닫기 버튼을 통해 닫을 수 있습니다.",
},
},
},
Expand Down
Loading