Skip to content

Commit

Permalink
refactor: tabs headless, tabs component, segmented-control component (#…
Browse files Browse the repository at this point in the history
…481)

* refactor: tabs

* refactor: option -> trigger로 parts명 변경

* refactor: rootEl가 있을때만 setProperty

* feat: segmented control 변경

* chore: build

* chore: className 변경

* feat: 전부 CSS Variable로 처리

* chore: useTabs에서 layout prop 삭제

* fix: rootEl state

* refactor: 안쓰는 transition 정리

* fix: `--seed-design-segmented-control-tab-count` 계산 전 눈속임

* feat: defaultValue fallback, mount 이전 상태는 slot 대신 inline style로

* chore: generate:all

---------

Co-authored-by: Joo Chanhwi <[email protected]>
  • Loading branch information
junghyeonsu and te6-in authored Nov 29, 2024
1 parent be093ab commit 88cb5d5
Show file tree
Hide file tree
Showing 22 changed files with 256 additions and 207 deletions.
10 changes: 5 additions & 5 deletions docs/components/example/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@
"inline-banner-with-icon": "import { InlineBanner } from \"seed-design/ui/inline-banner\";\nimport { IconILowercaseSerifCircleFill } from \"@daangn/react-monochrome-icon\";\n\nexport default function InlineBannerWithIcon() {\n return (\n <InlineBanner variant=\"informativeWeak\" icon={<IconILowercaseSerifCircleFill />}>\n 다른 사람과 예약된 물품이 있어요.\n </InlineBanner>\n );\n}",
"inline-banner-with-link": "import { InlineBanner } from \"seed-design/ui/inline-banner\";\n\nexport default function InlineBannerWithLink() {\n return (\n <InlineBanner variant=\"informativeWeak\" link={{ label: \"자세히 보기\", onClick: () => {} }}>\n 다른 사람과 예약된 물품이 있어요.\n </InlineBanner>\n );\n}",
"inline-banner-with-title-text": "import { InlineBanner } from \"seed-design/ui/inline-banner\";\n\nexport default function InlineBannerWithTitleText() {\n return (\n <InlineBanner variant=\"informativeWeak\" titleText=\"예약\">\n 다른 사람과 예약된 물품이 있어요.\n </InlineBanner>\n );\n}",
"segmented-control-fixed-width": "import { SegmentedControl, SegmentedControlOption } from \"seed-design/ui/segmented-control\";\n\nexport default function SegmentedControlFixedWidth() {\n return (\n <SegmentedControl style={{ width: \"600px\" }}>\n <SegmentedControlOption value=\"new\">New</SegmentedControlOption>\n <SegmentedControlOption value=\"hot\">Hot</SegmentedControlOption>\n </SegmentedControl>\n );\n}",
"segmented-control-long-label-fixed-width": "import { SegmentedControl, SegmentedControlOption } from \"seed-design/ui/segmented-control\";\n\nexport default function SegmentedControlLongLabelFixedWidth() {\n return (\n <SegmentedControl style={{ width: \"600px\" }}>\n <SegmentedControlOption value=\"price\">가격 높은 순</SegmentedControlOption>\n <SegmentedControlOption value=\"discount\">할인율 높은 순</SegmentedControlOption>\n <SegmentedControlOption value=\"popularity\">인기 많은 순</SegmentedControlOption>\n </SegmentedControl>\n );\n}",
"segmented-control-long-label": "import { SegmentedControl, SegmentedControlOption } from \"seed-design/ui/segmented-control\";\n\nexport default function SegmentedControlLongLabel() {\n return (\n <SegmentedControl>\n <SegmentedControlOption value=\"price\">가격 높은 순</SegmentedControlOption>\n <SegmentedControlOption value=\"discount\">할인율 높은 순</SegmentedControlOption>\n <SegmentedControlOption value=\"popularity\">인기 많은 순</SegmentedControlOption>\n </SegmentedControl>\n );\n}",
"segmented-control-preview": "import { useState } from \"react\";\nimport { SegmentedControl, SegmentedControlOption } from \"seed-design/ui/segmented-control\";\n\nexport default function SegmentedControlPreview() {\n const options = [\"New\", \"Hot\"];\n const [value, setValue] = useState(\"New\");\n\n return (\n <div className=\"flex flex-col gap-3 items-center text-center\">\n <SegmentedControl value={value} defaultValue=\"New\" onValueChange={setValue}>\n {options.map((option) => (\n <SegmentedControlOption key={option} value={option}>\n {option}\n </SegmentedControlOption>\n ))}\n </SegmentedControl>\n <div>Selected value: {value}</div>\n </div>\n );\n}",
"segmented-control-fixed-width": "import { SegmentedControl, SegmentedControlTrigger } from \"seed-design/ui/segmented-control\";\n\nexport default function SegmentedControlFixedWidth() {\n return (\n <SegmentedControl defaultValue=\"new\">\n <SegmentedControlTrigger value=\"new\">New</SegmentedControlTrigger>\n <SegmentedControlTrigger value=\"hot\">Hot</SegmentedControlTrigger>\n </SegmentedControl>\n );\n}",
"segmented-control-long-label-fixed-width": "import { SegmentedControl, SegmentedControlTrigger } from \"seed-design/ui/segmented-control\";\n\nexport default function SegmentedControlLongLabelFixedWidth() {\n return (\n <SegmentedControl defaultValue=\"price\">\n <SegmentedControlTrigger value=\"price\">가격 높은 순</SegmentedControlTrigger>\n <SegmentedControlTrigger value=\"discount\">할인율 높은 순</SegmentedControlTrigger>\n <SegmentedControlTrigger value=\"popularity\">인기 많은 순</SegmentedControlTrigger>\n </SegmentedControl>\n );\n}",
"segmented-control-long-label": "import { SegmentedControl, SegmentedControlTrigger } from \"seed-design/ui/segmented-control\";\n\nexport default function SegmentedControlLongLabel() {\n return (\n <SegmentedControl defaultValue=\"price\">\n <SegmentedControlTrigger value=\"price\">가격 높은 순</SegmentedControlTrigger>\n <SegmentedControlTrigger value=\"discount\">할인율 높은 순</SegmentedControlTrigger>\n <SegmentedControlTrigger value=\"popularity\">인기 많은 순</SegmentedControlTrigger>\n </SegmentedControl>\n );\n}",
"segmented-control-preview": "import { SegmentedControl, SegmentedControlTrigger } from \"seed-design/ui/segmented-control\";\n\nexport default function SegmentedControlPreview() {\n return (\n <SegmentedControl>\n <SegmentedControlTrigger value=\"Hot\">Hot</SegmentedControlTrigger>\n <SegmentedControlTrigger value=\"New\">New</SegmentedControlTrigger>\n </SegmentedControl>\n );\n}",
"skeleton-wave-activity": "import type { ActivityComponentType } from \"@stackflow/react/future\";\nimport type * as React from \"react\";\n\nimport Layout from \"@/components/stackflow/ActivityLayout\";\nimport { Skeleton } from \"seed-design/ui/skeleton\";\nimport {\n useSkeletonDuration,\n useIsRealLoading,\n useSkeletonLoading,\n useSkeletonTimingFunction,\n useSkeletonInitTransitionDuration,\n useSkeletonGradient,\n} from \"@/stores/skeleton\";\n\ndeclare module \"@stackflow/config\" {\n interface Register {\n SkeletonWave: unknown;\n }\n}\n\nconst Fallback = () => {\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"12px\" }}>\n <Skeleton width=\"100%\" height=\"300px\" borderRadius=\"square\" />\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: \"4px\" }}>\n <Skeleton width=\"50px\" height=\"50px\" borderRadius=\"circle\" />\n <Skeleton width=\"100%\" height=\"20px\" borderRadius=\"rounded\" />\n <Skeleton width=\"200px\" height=\"20px\" borderRadius=\"rounded\" />\n </div>\n </div>\n );\n};\n\nconst SkeletonWaveActivity: ActivityComponentType<\"SkeletonWave\"> = () => {\n const isLoading = useSkeletonLoading();\n const isRealLoading = useIsRealLoading();\n const animationDuration = useSkeletonDuration();\n const animationTiming = useSkeletonTimingFunction();\n const initTransitionDuration = useSkeletonInitTransitionDuration();\n const gradient = useSkeletonGradient();\n\n return (\n <Layout>\n <div\n style={\n {\n padding: \"16px\",\n \"--skeleton-gradient\": gradient,\n \"--skeleton-init-transition-duration\": initTransitionDuration,\n \"--skeleton-animation-duration\": animationDuration,\n \"--skeleton-animation-timing-function\": animationTiming,\n } as React.CSSProperties\n }\n >\n {isLoading ? isRealLoading && <Fallback /> : <div>content</div>}\n </div>\n </Layout>\n );\n};\n\nexport default SkeletonWaveActivity;\n\nSkeletonWaveActivity.displayName = \"SkeletonWaveActivity\";",
"switch-disabled": "import { Switch } from \"seed-design/ui/switch\";\n\nexport default function SwitchDisabled() {\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 10 }}>\n <Switch disabled />\n <Switch checked disabled />\n </div>\n );\n}",
"switch-medium": "import { useState } from \"react\";\nimport { Switch } from \"seed-design/ui/switch\";\n\nexport default function SwitchMedium() {\n const [isChecked, setIsChecked] = useState(false);\n\n return (\n <Switch size=\"medium\" checked={isChecked} onCheckedChange={setIsChecked} />\n );\n}",
Expand All @@ -126,7 +126,7 @@
"tabs-size-medium": "import { Tabs, TabContent, TabContentList, TabTrigger, TabTriggerList } from \"seed-design/ui/tabs\";\n\nexport default function TabsSizeMedium() {\n return (\n <div style={{ width: \"360px\" }}>\n <Tabs defaultValue=\"1\" size=\"medium\">\n <TabTriggerList>\n <TabTrigger value=\"1\">라벨1</TabTrigger>\n <TabTrigger value=\"2\">라벨2</TabTrigger>\n <TabTrigger value=\"3\">라벨3</TabTrigger>\n </TabTriggerList>\n <TabContentList>\n <TabContent value=\"1\">\n <Content>Content 1</Content>\n </TabContent>\n <TabContent value=\"2\">\n <Content>Content 2</Content>\n </TabContent>\n <TabContent value=\"3\">\n <Content>Content 3</Content>\n </TabContent>\n </TabContentList>\n </Tabs>\n </div>\n );\n}\n\nconst Content = (props: React.PropsWithChildren) => {\n return (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n height: \"300px\",\n backgroundColor: \"var(--seed-color-bg-layer-default)\",\n }}\n >\n {props.children}\n </div>\n );\n};",
"tabs-size-small": "import { Tabs, TabContent, TabContentList, TabTrigger, TabTriggerList } from \"seed-design/ui/tabs\";\n\nexport default function TabsSizeSmall() {\n return (\n <div style={{ width: \"360px\" }}>\n <Tabs defaultValue=\"1\" size=\"small\">\n <TabTriggerList>\n <TabTrigger value=\"1\">라벨1</TabTrigger>\n <TabTrigger value=\"2\">라벨2</TabTrigger>\n <TabTrigger value=\"3\">라벨3</TabTrigger>\n </TabTriggerList>\n <TabContentList>\n <TabContent value=\"1\">\n <Content>Content 1</Content>\n </TabContent>\n <TabContent value=\"2\">\n <Content>Content 2</Content>\n </TabContent>\n <TabContent value=\"3\">\n <Content>Content 3</Content>\n </TabContent>\n </TabContentList>\n </Tabs>\n </div>\n );\n}\n\nconst Content = (props: React.PropsWithChildren) => {\n return (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n height: \"300px\",\n backgroundColor: \"var(--seed-color-bg-layer-default)\",\n }}\n >\n {props.children}\n </div>\n );\n};",
"tabs-standalone": "import { useState } from \"react\";\nimport { Tabs, TabTrigger, TabTriggerList } from \"seed-design/ui/tabs\";\n\nexport default function TabsStandalone() {\n const [activeTab, setActiveTab] = useState(\"1\");\n\n return (\n <div style={{ width: \"360px\" }}>\n <Tabs defaultValue=\"1\" onValueChange={setActiveTab}>\n <TabTriggerList>\n <TabTrigger value=\"1\">라벨1</TabTrigger>\n <TabTrigger value=\"2\">라벨2</TabTrigger>\n <TabTrigger value=\"3\">라벨3</TabTrigger>\n </TabTriggerList>\n {activeTab === \"1\" && (\n <div>\n <Content>Content 1</Content>\n </div>\n )}\n {activeTab === \"2\" && (\n <div>\n <Content>Content 2</Content>\n </div>\n )}\n {activeTab === \"3\" && (\n <div>\n <Content>Content 3</Content>\n </div>\n )}\n </Tabs>\n </div>\n );\n}\n\nconst Content = (props: React.PropsWithChildren) => {\n return (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n height: \"300px\",\n backgroundColor: \"var(--seed-color-bg-layer-default)\",\n }}\n >\n {props.children}\n </div>\n );\n};",
"tabs-swipeable": "import { Tabs, TabContent, TabContentList, TabTrigger, TabTriggerList } from \"seed-design/ui/tabs\";\n\nexport default function TabsSwipeable() {\n return (\n <div style={{ width: \"360px\" }}>\n <Tabs defaultValue=\"1\" isSwipeable>\n <TabTriggerList>\n <TabTrigger value=\"1\">라벨1</TabTrigger>\n <TabTrigger value=\"2\">라벨2</TabTrigger>\n <TabTrigger value=\"3\">라벨3</TabTrigger>\n </TabTriggerList>\n <TabContentList>\n <TabContent value=\"1\">\n <Content>Content 1</Content>\n </TabContent>\n <TabContent value=\"2\">\n <Content>Content 2</Content>\n </TabContent>\n <TabContent value=\"3\">\n <Content>Content 3</Content>\n </TabContent>\n </TabContentList>\n </Tabs>\n </div>\n );\n}\n\nconst Content = (props: React.PropsWithChildren) => {\n return (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n height: \"300px\",\n backgroundColor: \"var(--seed-color-bg-layer-default)\",\n }}\n >\n {props.children}\n </div>\n );\n};",
"tabs-swipeable": "import { Tabs, TabContent, TabContentList, TabTrigger, TabTriggerList } from \"seed-design/ui/tabs\";\n\nexport default function TabsSwipeable() {\n return (\n <div style={{ width: \"360px\" }}>\n <Tabs defaultValue=\"2\" isSwipeable>\n <TabTriggerList>\n <TabTrigger value=\"1\">라벨1</TabTrigger>\n <TabTrigger value=\"2\">라벨2</TabTrigger>\n <TabTrigger value=\"3\">라벨3</TabTrigger>\n </TabTriggerList>\n <TabContentList>\n <TabContent value=\"1\">\n <Content>Content 1</Content>\n </TabContent>\n <TabContent value=\"2\">\n <Content>Content 2</Content>\n </TabContent>\n <TabContent value=\"3\">\n <Content>Content 3</Content>\n </TabContent>\n </TabContentList>\n </Tabs>\n </div>\n );\n}\n\nconst Content = (props: React.PropsWithChildren) => {\n return (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n height: \"300px\",\n backgroundColor: \"var(--seed-color-bg-layer-default)\",\n }}\n >\n {props.children}\n </div>\n );\n};",
"text-button-brand": "import { IconPlusCircleLine } from \"@daangn/react-monochrome-icon\";\nimport { TextButton } from \"seed-design/ui/text-button\";\n\nexport default function TextButtonBrand() {\n return (\n <TextButton variant=\"brand\" icon={<IconPlusCircleLine />}>\n 추가\n </TextButton>\n );\n}",
"text-button-danger": "import { IconTrashcanLine } from \"@daangn/react-monochrome-icon\";\nimport { TextButton } from \"seed-design/ui/text-button\";\n\nexport default function TextButtonDanger() {\n return (\n <TextButton variant=\"danger\" icon={<IconTrashcanLine />}>\n 삭제\n </TextButton>\n );\n}",
"text-button-disabled": "import { IconPenHorizlineLine } from \"@daangn/react-monochrome-icon\";\nimport { TextButton } from \"seed-design/ui/text-button\";\n\nexport default function TextButtonPreview() {\n return (\n <TextButton disabled icon={<IconPenHorizlineLine />}>\n 새 글\n </TextButton>\n );\n}",
Expand Down
8 changes: 4 additions & 4 deletions docs/components/example/segmented-control-fixed-width.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { SegmentedControl, SegmentedControlOption } from "seed-design/ui/segmented-control";
import { SegmentedControl, SegmentedControlTrigger } from "seed-design/ui/segmented-control";

export default function SegmentedControlFixedWidth() {
return (
<SegmentedControl style={{ width: "600px" }}>
<SegmentedControlOption value="new">New</SegmentedControlOption>
<SegmentedControlOption value="hot">Hot</SegmentedControlOption>
<SegmentedControl defaultValue="new">
<SegmentedControlTrigger value="new">New</SegmentedControlTrigger>
<SegmentedControlTrigger value="hot">Hot</SegmentedControlTrigger>
</SegmentedControl>
);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { SegmentedControl, SegmentedControlOption } from "seed-design/ui/segmented-control";
import { SegmentedControl, SegmentedControlTrigger } from "seed-design/ui/segmented-control";

export default function SegmentedControlLongLabelFixedWidth() {
return (
<SegmentedControl style={{ width: "600px" }}>
<SegmentedControlOption value="price">가격 높은 순</SegmentedControlOption>
<SegmentedControlOption value="discount">할인율 높은 순</SegmentedControlOption>
<SegmentedControlOption value="popularity">인기 많은 순</SegmentedControlOption>
<SegmentedControl defaultValue="price">
<SegmentedControlTrigger value="price">가격 높은 순</SegmentedControlTrigger>
<SegmentedControlTrigger value="discount">할인율 높은 순</SegmentedControlTrigger>
<SegmentedControlTrigger value="popularity">인기 많은 순</SegmentedControlTrigger>
</SegmentedControl>
);
}
10 changes: 5 additions & 5 deletions docs/components/example/segmented-control-long-label.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { SegmentedControl, SegmentedControlOption } from "seed-design/ui/segmented-control";
import { SegmentedControl, SegmentedControlTrigger } from "seed-design/ui/segmented-control";

export default function SegmentedControlLongLabel() {
return (
<SegmentedControl>
<SegmentedControlOption value="price">가격 높은 순</SegmentedControlOption>
<SegmentedControlOption value="discount">할인율 높은 순</SegmentedControlOption>
<SegmentedControlOption value="popularity">인기 많은 순</SegmentedControlOption>
<SegmentedControl defaultValue="price">
<SegmentedControlTrigger value="price">가격 높은 순</SegmentedControlTrigger>
<SegmentedControlTrigger value="discount">할인율 높은 순</SegmentedControlTrigger>
<SegmentedControlTrigger value="popularity">인기 많은 순</SegmentedControlTrigger>
</SegmentedControl>
);
}
22 changes: 5 additions & 17 deletions docs/components/example/segmented-control-preview.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,10 @@
"use client";

import { useState } from "react";
import { SegmentedControl, SegmentedControlOption } from "seed-design/ui/segmented-control";
import { SegmentedControl, SegmentedControlTrigger } from "seed-design/ui/segmented-control";

export default function SegmentedControlPreview() {
const options = ["New", "Hot"];
const [value, setValue] = useState("New");

return (
<div className="flex flex-col gap-3 items-center text-center">
<SegmentedControl value={value} defaultValue="New" onValueChange={setValue}>
{options.map((option) => (
<SegmentedControlOption key={option} value={option}>
{option}
</SegmentedControlOption>
))}
</SegmentedControl>
<div>Selected value: {value}</div>
</div>
<SegmentedControl>
<SegmentedControlTrigger value="Hot">Hot</SegmentedControlTrigger>
<SegmentedControlTrigger value="New">New</SegmentedControlTrigger>
</SegmentedControl>
);
}
2 changes: 1 addition & 1 deletion docs/components/example/tabs-swipeable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Tabs, TabContent, TabContentList, TabTrigger, TabTriggerList } from "se
export default function TabsSwipeable() {
return (
<div style={{ width: "360px" }}>
<Tabs defaultValue="1" isSwipeable>
<Tabs defaultValue="2" isSwipeable>
<TabTriggerList>
<TabTrigger value="1">라벨1</TabTrigger>
<TabTrigger value="2">라벨2</TabTrigger>
Expand Down
Loading

0 comments on commit 88cb5d5

Please sign in to comment.