@mindlogic-ai/logician-ui 5.0.0-alpha.3 → 5.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Banner/Banner.types.d.ts +24 -1
- package/dist/components/Banner/Banner.types.d.ts.map +1 -1
- package/dist/components/Card/Card.types.d.ts +12 -0
- package/dist/components/Card/Card.types.d.ts.map +1 -1
- package/dist/components/ColorMode/ColorModeToggle.d.ts +7 -2
- package/dist/components/ColorMode/ColorModeToggle.d.ts.map +1 -1
- package/dist/components/ColorMode/ColorModeToggle.js +8 -3
- package/dist/components/ColorMode/ColorModeToggle.js.map +1 -1
- package/dist/components/ColorMode/ColorModeToggle.mjs +8 -3
- package/dist/components/ColorMode/ColorModeToggle.mjs.map +1 -1
- package/dist/components/Confetti/Confetti.types.d.ts +5 -1
- package/dist/components/Confetti/Confetti.types.d.ts.map +1 -1
- package/dist/components/Confetti/confettiColors.d.ts +5 -5
- package/dist/components/Confetti/confettiColors.js +5 -5
- package/dist/components/Confetti/confettiColors.mjs +5 -5
- package/dist/components/ErrorFallback/ErrorFallback.types.d.ts +6 -0
- package/dist/components/ErrorFallback/ErrorFallback.types.d.ts.map +1 -1
- package/dist/components/Form/FormModalFooter/FormModalFooter.types.d.ts +4 -1
- package/dist/components/Form/FormModalFooter/FormModalFooter.types.d.ts.map +1 -1
- package/dist/components/LineGraph/LineGraph.d.ts.map +1 -1
- package/dist/components/LineGraph/LineGraph.js +4 -5
- package/dist/components/LineGraph/LineGraph.js.map +1 -1
- package/dist/components/LineGraph/LineGraph.mjs +5 -6
- package/dist/components/LineGraph/LineGraph.mjs.map +1 -1
- package/dist/components/LineGraph/LineGraph.types.d.ts +12 -2
- package/dist/components/LineGraph/LineGraph.types.d.ts.map +1 -1
- package/dist/components/LineGraph/seriesColors.d.ts +12 -8
- package/dist/components/LineGraph/seriesColors.d.ts.map +1 -1
- package/dist/components/LineGraph/seriesColors.js +8 -7
- package/dist/components/LineGraph/seriesColors.js.map +1 -1
- package/dist/components/LineGraph/seriesColors.mjs +8 -7
- package/dist/components/LineGraph/seriesColors.mjs.map +1 -1
- package/dist/components/Masonry/Masonry.types.d.ts +8 -3
- package/dist/components/Masonry/Masonry.types.d.ts.map +1 -1
- package/dist/components/Menu/MenuItem.types.d.ts +8 -0
- package/dist/components/Menu/MenuItem.types.d.ts.map +1 -1
- package/dist/components/Modal/ModalCloseButton.d.ts +1 -1
- package/dist/components/Modal/ModalCloseButton.js +1 -1
- package/dist/components/Modal/ModalCloseButton.mjs +1 -1
- package/dist/components/Pagination/Pagination.d.ts +11 -10
- package/dist/components/Pagination/Pagination.d.ts.map +1 -1
- package/dist/components/Pagination/Pagination.js +11 -10
- package/dist/components/Pagination/Pagination.js.map +1 -1
- package/dist/components/Pagination/Pagination.mjs +11 -10
- package/dist/components/Pagination/Pagination.mjs.map +1 -1
- package/dist/components/ProgressBar/ProgressBar.types.d.ts +9 -0
- package/dist/components/ProgressBar/ProgressBar.types.d.ts.map +1 -1
- package/dist/components/RadialProgress/RadialProgress.types.d.ts +21 -1
- package/dist/components/RadialProgress/RadialProgress.types.d.ts.map +1 -1
- package/dist/components/SeeMoreButton/SeeMoreButton.types.d.ts +8 -0
- package/dist/components/SeeMoreButton/SeeMoreButton.types.d.ts.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.js +6 -7
- package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
- package/dist/components/SegmentedControl/SegmentedControl.mjs +6 -7
- package/dist/components/SegmentedControl/SegmentedControl.mjs.map +1 -1
- package/dist/components/SegmentedProgressBar/SegmentedProgressBar.types.d.ts +2 -0
- package/dist/components/SegmentedProgressBar/SegmentedProgressBar.types.d.ts.map +1 -1
- package/dist/components/Toast/Toast.styles.d.ts +6 -2
- package/dist/components/Toast/Toast.styles.d.ts.map +1 -1
- package/dist/components/Toast/Toast.styles.js +18 -10
- package/dist/components/Toast/Toast.styles.js.map +1 -1
- package/dist/components/Toast/Toast.styles.mjs +18 -10
- package/dist/components/Toast/Toast.styles.mjs.map +1 -1
- package/dist/theme/colors.d.ts +2 -2
- package/dist/theme/colors.d.ts.map +1 -1
- package/dist/theme/colors.js +22 -2
- package/dist/theme/colors.js.map +1 -1
- package/dist/theme/colors.mjs +23 -3
- package/dist/theme/colors.mjs.map +1 -1
- package/dist/theme/palette.generated.d.ts +98 -0
- package/dist/theme/palette.generated.d.ts.map +1 -1
- package/dist/theme/palette.generated.js +99 -0
- package/dist/theme/palette.generated.js.map +1 -1
- package/dist/theme/palette.generated.mjs +99 -1
- package/dist/theme/palette.generated.mjs.map +1 -1
- package/dist/theme/paletteSwatches.d.ts +20 -0
- package/dist/theme/paletteSwatches.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/Accordion/Accordion.stories.tsx +85 -0
- package/src/components/Accordion/Accordion.usage.mdx +200 -0
- package/src/components/Appear/Appear.usage.mdx +107 -0
- package/src/components/Avatar/Avatar.stories.tsx +71 -1
- package/src/components/Avatar/Avatar.usage.mdx +166 -0
- package/src/components/Banner/Banner.stories.tsx +152 -2
- package/src/components/Banner/Banner.types.ts +30 -1
- package/src/components/Banner/Banner.usage.mdx +233 -0
- package/src/components/BottomSheet/BottomSheet.stories.tsx +168 -1
- package/src/components/BottomSheet/BottomSheet.usage.mdx +216 -0
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +59 -0
- package/src/components/Breadcrumb/Breadcrumb.usage.mdx +181 -0
- package/src/components/Button/Button.stories.tsx +263 -3
- package/src/components/Button/Button.usage.mdx +342 -0
- package/src/components/Card/Card.stories.tsx +106 -0
- package/src/components/Card/Card.types.ts +12 -0
- package/src/components/Card/Card.usage.mdx +216 -0
- package/src/components/Checkbox/Checkbox.stories.tsx +140 -13
- package/src/components/Checkbox/Checkbox.usage.mdx +214 -0
- package/src/components/Chip/Chip.usage.mdx +78 -0
- package/src/components/Code/Code.stories.tsx +60 -0
- package/src/components/Code/Code.usage.mdx +187 -0
- package/src/components/CodeTabs/CodeTabs.stories.tsx +53 -0
- package/src/components/CodeTabs/CodeTabs.usage.mdx +176 -0
- package/src/components/Collapsible/Collapsible.stories.tsx +58 -0
- package/src/components/Collapsible/Collapsible.usage.mdx +173 -0
- package/src/components/ColorMode/ColorMode.stories.tsx +50 -0
- package/src/components/ColorMode/ColorMode.usage.mdx +135 -0
- package/src/components/ColorMode/ColorModeToggle.tsx +10 -3
- package/src/components/Confetti/Confetti.types.ts +5 -1
- package/src/components/Confetti/Confetti.usage.mdx +111 -0
- package/src/components/Confetti/confettiColors.ts +5 -5
- package/src/components/Container/Container.stories.tsx +32 -0
- package/src/components/Container/Container.usage.mdx +130 -0
- package/src/components/CopyableCode/CopyableCode.stories.tsx +62 -0
- package/src/components/CopyableCode/CopyableCode.usage.mdx +168 -0
- package/src/components/CountBadge/CountBadge.stories.tsx +69 -0
- package/src/components/CountBadge/CountBadge.usage.mdx +215 -0
- package/src/components/CountUp/CountUp.usage.mdx +107 -0
- package/src/components/DatePicker/DatePicker.usage.mdx +177 -0
- package/src/components/DatePicker/RangeDatePicker.stories.tsx +87 -3
- package/src/components/ErrorFallback/ErrorFallback.types.ts +6 -0
- package/src/components/ErrorFallback/ErrorFallback.usage.mdx +127 -0
- package/src/components/ExpandableText/ExpandableText.stories.tsx +55 -0
- package/src/components/ExpandableText/ExpandableText.usage.mdx +176 -0
- package/src/components/FileInput/FileInput.stories.tsx +38 -1
- package/src/components/FileInput/FileInput.usage.mdx +178 -0
- package/src/components/FileItem/FileItem.stories.tsx +71 -0
- package/src/components/FileItem/FileItem.usage.mdx +180 -0
- package/src/components/FileList/FileList.stories.tsx +25 -0
- package/src/components/FileList/FileList.usage.mdx +165 -0
- package/src/components/FlyTo/FlyTo.usage.mdx +99 -0
- package/src/components/Form/Form.stories.tsx +149 -0
- package/src/components/Form/Form.usage.mdx +201 -0
- package/src/components/Form/FormModalFooter/FormModalFooter.types.ts +4 -1
- package/src/components/FormControl/FormControl.stories.tsx +35 -0
- package/src/components/FormControl/FormControl.usage.mdx +128 -0
- package/src/components/FormIntegration/FormIntegration.usage.mdx +158 -0
- package/src/components/FormLabel/FormLabel.stories.tsx +71 -0
- package/src/components/FormLabel/FormLabel.usage.mdx +125 -0
- package/src/components/Icon/Icon.stories.tsx +61 -1
- package/src/components/Icon/Icon.usage.mdx +158 -0
- package/src/components/IconButton/IconButton.stories.tsx +209 -5
- package/src/components/IconButton/IconButton.usage.mdx +273 -0
- package/src/components/InfoSprinkle/InfoSprinkle.stories.tsx +77 -1
- package/src/components/InfoSprinkle/InfoSprinkle.usage.mdx +189 -0
- package/src/components/InlineCode/InlineCode.stories.tsx +75 -0
- package/src/components/InlineCode/InlineCode.usage.mdx +142 -0
- package/src/components/Input/Input.stories.tsx +180 -0
- package/src/components/Input/Input.usage.mdx +278 -0
- package/src/components/LineGraph/LineGraph.stories.tsx +112 -0
- package/src/components/LineGraph/LineGraph.tsx +4 -5
- package/src/components/LineGraph/LineGraph.types.ts +12 -2
- package/src/components/LineGraph/LineGraph.usage.mdx +186 -0
- package/src/components/LineGraph/seriesColors.test.ts +11 -10
- package/src/components/LineGraph/seriesColors.ts +18 -16
- package/src/components/Loaders/Loaders.stories.tsx +93 -0
- package/src/components/Loaders/Loaders.usage.mdx +180 -0
- package/src/components/LogicianProvider/LogicianProvider.usage.mdx +98 -0
- package/src/components/Markdown/Markdown.stories.tsx +53 -0
- package/src/components/Markdown/Markdown.usage.mdx +182 -0
- package/src/components/Masonry/Masonry.stories.tsx +63 -1
- package/src/components/Masonry/Masonry.types.ts +8 -3
- package/src/components/Masonry/Masonry.usage.mdx +142 -0
- package/src/components/MaxLengthIndicator/MaxLengthIndicator.stories.tsx +57 -0
- package/src/components/MaxLengthIndicator/MaxLengthIndicator.usage.mdx +125 -0
- package/src/components/Menu/Menu.stories.tsx +146 -2
- package/src/components/Menu/Menu.usage.mdx +230 -0
- package/src/components/Menu/MenuItem.types.ts +8 -0
- package/src/components/Modal/Modal.stories.tsx +177 -1
- package/src/components/Modal/Modal.usage.mdx +262 -0
- package/src/components/Modal/ModalCloseButton.tsx +1 -1
- package/src/components/MonthPicker/MonthPicker.stories.tsx +30 -0
- package/src/components/MonthPicker/MonthPicker.usage.mdx +191 -0
- package/src/components/Pagination/Pagination.stories.tsx +90 -1
- package/src/components/Pagination/Pagination.tsx +11 -10
- package/src/components/Pagination/Pagination.usage.mdx +186 -0
- package/src/components/PasswordInput/PasswordInput.stories.tsx +51 -0
- package/src/components/PasswordInput/PasswordInput.usage.mdx +193 -0
- package/src/components/PinInput/PinInput.stories.tsx +91 -0
- package/src/components/PinInput/PinInput.usage.mdx +194 -0
- package/src/components/Popover/Popover.stories.tsx +104 -1
- package/src/components/Popover/Popover.usage.mdx +197 -0
- package/src/components/ProgressBar/ProgressBar.stories.tsx +92 -1
- package/src/components/ProgressBar/ProgressBar.types.ts +9 -0
- package/src/components/ProgressBar/ProgressBar.usage.mdx +210 -0
- package/src/components/Pulse/Pulse.usage.mdx +102 -0
- package/src/components/RadialProgress/RadialProgress.stories.tsx +74 -1
- package/src/components/RadialProgress/RadialProgress.types.ts +21 -1
- package/src/components/RadialProgress/RadialProgress.usage.mdx +153 -0
- package/src/components/Radio/Radio.stories.tsx +119 -0
- package/src/components/Radio/Radio.usage.mdx +187 -0
- package/src/components/Reveal/Reveal.usage.mdx +105 -0
- package/src/components/ScaledContext/ScaledContext.usage.mdx +111 -0
- package/src/components/SeeMoreButton/SeeMoreButton.stories.tsx +146 -2
- package/src/components/SeeMoreButton/SeeMoreButton.types.ts +8 -0
- package/src/components/SeeMoreButton/SeeMoreButton.usage.mdx +213 -0
- package/src/components/SegmentedControl/SegmentedControl.stories.tsx +69 -0
- package/src/components/SegmentedControl/SegmentedControl.tsx +6 -7
- package/src/components/SegmentedControl/SegmentedControl.usage.mdx +209 -0
- package/src/components/SegmentedProgressBar/SegmentedProgressBar.stories.tsx +54 -0
- package/src/components/SegmentedProgressBar/SegmentedProgressBar.types.ts +2 -0
- package/src/components/SegmentedProgressBar/SegmentedProgressBar.usage.mdx +145 -0
- package/src/components/Select/Select.stories.tsx +209 -1
- package/src/components/Select/Select.usage.mdx +278 -0
- package/src/components/Shake/Shake.usage.mdx +107 -0
- package/src/components/Slider/Slider.stories.tsx +116 -0
- package/src/components/Slider/Slider.usage.mdx +179 -0
- package/src/components/Spinner/Spinner.stories.tsx +64 -0
- package/src/components/Spinner/Spinner.usage.mdx +136 -0
- package/src/components/SwapTransition/SwapTransition.usage.mdx +102 -0
- package/src/components/Switch/Switch.stories.tsx +131 -6
- package/src/components/Switch/Switch.usage.mdx +199 -0
- package/src/components/Table/Table.stories.tsx +159 -1
- package/src/components/Table/Table.usage.mdx +235 -0
- package/src/components/Tabs/Tabs.stories.tsx +86 -0
- package/src/components/Tabs/Tabs.usage.mdx +219 -0
- package/src/components/Tag/Tag.stories.tsx +181 -4
- package/src/components/Tag/Tag.usage.mdx +257 -0
- package/src/components/Textarea/Textarea.stories.tsx +113 -0
- package/src/components/Textarea/Textarea.usage.mdx +186 -0
- package/src/components/Toast/Toast.stories.tsx +185 -3
- package/src/components/Toast/Toast.styles.ts +18 -10
- package/src/components/Toast/Toast.usage.mdx +265 -0
- package/src/components/Tooltip/Tooltip.stories.tsx +86 -1
- package/src/components/Tooltip/Tooltip.usage.mdx +211 -0
- package/src/components/Tree/Tree.stories.tsx +89 -0
- package/src/components/Tree/Tree.usage.mdx +207 -0
- package/src/components/Typography/Typography.stories.tsx +117 -0
- package/src/components/Typography/Typography.usage.mdx +251 -0
- package/src/components/Workflow/Workflow.usage.mdx +199 -0
- package/src/components/noRawScales.test.ts +5 -1
- package/src/foundations/BrandColour.mdx +65 -2
- package/src/theme/BazePalette.stories.tsx +111 -1
- package/src/theme/Palette.stories.tsx +2 -2
- package/src/theme/SemanticTokens.mdx +75 -16
- package/src/theme/claude.md +15 -9
- package/src/theme/colors.ts +33 -3
- package/src/theme/contrast.test.ts +32 -0
- package/src/theme/palette.generated.ts +99 -0
- package/src/theme/paletteSwatches.ts +35 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { ArgTypes, Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import { En, Ko, LangToggle } from '../../guidelines/_components/Lang';
|
|
4
|
+
import * as SwapTransitionStories from './SwapTransition.stories';
|
|
5
|
+
|
|
6
|
+
<Meta of={SwapTransitionStories} name="Usage" />
|
|
7
|
+
|
|
8
|
+
<LangToggle />
|
|
9
|
+
|
|
10
|
+
<En>
|
|
11
|
+
|
|
12
|
+
# SwapTransition
|
|
13
|
+
|
|
14
|
+
Swaps one piece of content for another with a short directional slide, for
|
|
15
|
+
moving between steps of a sequence or between records in the same frame.
|
|
16
|
+
|
|
17
|
+
</En>
|
|
18
|
+
|
|
19
|
+
<Ko>
|
|
20
|
+
|
|
21
|
+
# SwapTransition
|
|
22
|
+
|
|
23
|
+
한 내용을 다른 내용으로 바꿀 때 짧게 옆으로 밀어 넘깁니다. 순서가 있는 단계 사이를
|
|
24
|
+
오가거나, 같은 틀 안에서 다른 항목으로 넘어갈 때 씁니다.
|
|
25
|
+
|
|
26
|
+
</Ko>
|
|
27
|
+
|
|
28
|
+
<Canvas of={SwapTransitionStories.Default} />
|
|
29
|
+
|
|
30
|
+
<En>
|
|
31
|
+
|
|
32
|
+
## When to use
|
|
33
|
+
|
|
34
|
+
- Question 1 → question 2 in a quiz or a multi-step flow, keyed on the step
|
|
35
|
+
index.
|
|
36
|
+
- Moving from an overview screen to the step runner, or between items under
|
|
37
|
+
review, keyed on the record id.
|
|
38
|
+
- Going back: pass a negative `distance` so the content travels the other way.
|
|
39
|
+
|
|
40
|
+
## When not to use
|
|
41
|
+
|
|
42
|
+
- New content is added under existing content rather than replacing it →
|
|
43
|
+
`Reveal`, or `Appear` if nothing is pushed.
|
|
44
|
+
- A value changes in place → `CountUp` or `Pulse`.
|
|
45
|
+
- The key would change on unrelated re-renders → pick a key that identifies the
|
|
46
|
+
content (a step index, a record id), or the content swaps with itself.
|
|
47
|
+
|
|
48
|
+
## Reduced motion and accessibility
|
|
49
|
+
|
|
50
|
+
- With `prefers-reduced-motion: reduce` both halves take no time and nothing
|
|
51
|
+
slides. The outgoing content is hidden at once, and the new content appears
|
|
52
|
+
when the 150ms exit timer ends.
|
|
53
|
+
- While the old content leaves it gets `aria-hidden` and ignores the pointer,
|
|
54
|
+
so it cannot be read or clicked on its way out.
|
|
55
|
+
- SwapTransition does not move focus. After a step change, move focus to the
|
|
56
|
+
new step (its heading, or its first field) yourself, so keyboard and
|
|
57
|
+
screen reader users start in the right place (WCAG 2.4.3).
|
|
58
|
+
- It renders one `div`, and every prop lands on that element, so a wrapper
|
|
59
|
+
told to fill (`display="flex" flex={1} minH={0}`) still fills.
|
|
60
|
+
|
|
61
|
+
## Props
|
|
62
|
+
|
|
63
|
+
</En>
|
|
64
|
+
|
|
65
|
+
<Ko>
|
|
66
|
+
|
|
67
|
+
## 언제 쓰나요
|
|
68
|
+
|
|
69
|
+
- 퀴즈나 여러 단계로 된 흐름에서 1번 문항에서 2번 문항으로 넘어갈 때. 단계 번호를
|
|
70
|
+
key로 씁니다.
|
|
71
|
+
- 개요 화면에서 단계 진행 화면으로, 또는 검토 중인 항목 사이를 오갈 때. 항목 id를
|
|
72
|
+
key로 씁니다.
|
|
73
|
+
- 뒤로 갈 때는 `distance`에 음수를 넘겨 반대 방향으로 움직입니다.
|
|
74
|
+
|
|
75
|
+
## 언제 쓰지 않나요
|
|
76
|
+
|
|
77
|
+
- 새 내용이 기존 내용을 바꾸지 않고 그 아래에 더해진다면 `Reveal`을 씁니다. 아무것도
|
|
78
|
+
밀어내지 않는다면 `Appear`를 씁니다.
|
|
79
|
+
- 값이 제자리에서 바뀐다면 `CountUp`이나 `Pulse`를 씁니다.
|
|
80
|
+
- 상관없는 렌더에서도 key가 바뀐다면, 내용을 식별하는 값(단계 번호, 항목 id)으로 key를
|
|
81
|
+
바꿉니다. 그러지 않으면 같은 내용끼리 서로 바뀌는 애니메이션이 재생됩니다.
|
|
82
|
+
|
|
83
|
+
## 동작 줄이기와 접근성
|
|
84
|
+
|
|
85
|
+
- `prefers-reduced-motion: reduce`에서는 나가고 들어오는 동작 모두 시간이 0이라
|
|
86
|
+
밀리는 움직임이 없습니다. 나가는 내용은 바로 사라지고, 새 내용은 150ms의 퇴장
|
|
87
|
+
타이머가 끝나면 나타납니다.
|
|
88
|
+
- 나가는 동안 이전 내용에는 `aria-hidden`이 붙고 포인터도 받지 않으므로, 사라지는 중에
|
|
89
|
+
읽히거나 눌리지 않습니다.
|
|
90
|
+
- SwapTransition은 초점을 옮기지 않습니다. 단계가 바뀌면 새 단계(제목이나 첫 입력란)로
|
|
91
|
+
직접 초점을 옮겨, 키보드와 화면 낭독기 사용자가 제자리에서 시작하게 합니다(WCAG 2.4.3).
|
|
92
|
+
- `div` 하나만 그리고 모든 속성이 그 요소에 적용됩니다. 그래서 채우도록 지정한 감싸는
|
|
93
|
+
요소(`display="flex" flex={1} minH={0}`)도 그대로 채웁니다.
|
|
94
|
+
|
|
95
|
+
## 속성
|
|
96
|
+
|
|
97
|
+
</Ko>
|
|
98
|
+
|
|
99
|
+
<ArgTypes
|
|
100
|
+
of={SwapTransitionStories}
|
|
101
|
+
include={['transitionKey', 'distance', 'animateInitial']}
|
|
102
|
+
/>
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { Stack, Text } from '@chakra-ui/react';
|
|
2
|
+
import { Box, Stack, Text } from '@chakra-ui/react';
|
|
3
3
|
import { Meta, StoryObj } from '@storybook/react';
|
|
4
4
|
|
|
5
|
+
import { T } from '../../guidelines/_components/Lang';
|
|
6
|
+
import { TokenTable } from '../../guidelines/_components/TokenTable';
|
|
7
|
+
import { Checkbox } from '../Checkbox';
|
|
5
8
|
import { Switch } from './Switch';
|
|
6
9
|
|
|
7
10
|
const meta = {
|
|
@@ -22,7 +25,7 @@ export default meta;
|
|
|
22
25
|
type Story = StoryObj<typeof meta>;
|
|
23
26
|
|
|
24
27
|
export const Uncontrolled: Story = {
|
|
25
|
-
render: args => (
|
|
28
|
+
render: (args) => (
|
|
26
29
|
<Switch {...args}>
|
|
27
30
|
<Switch.Control />
|
|
28
31
|
</Switch>
|
|
@@ -34,12 +37,16 @@ export const Uncontrolled: Story = {
|
|
|
34
37
|
};
|
|
35
38
|
|
|
36
39
|
export const Controlled: Story = {
|
|
37
|
-
render: args => {
|
|
40
|
+
render: (args) => {
|
|
38
41
|
const [checked, setChecked] = useState(false);
|
|
39
42
|
|
|
40
43
|
return (
|
|
41
44
|
<Stack direction="row" align="center" gap={4}>
|
|
42
|
-
<Switch
|
|
45
|
+
<Switch
|
|
46
|
+
{...args}
|
|
47
|
+
checked={checked}
|
|
48
|
+
onCheckedChange={(e) => setChecked(e.checked)}
|
|
49
|
+
>
|
|
43
50
|
<Switch.Control />
|
|
44
51
|
</Switch>
|
|
45
52
|
<Text>{checked ? 'On' : 'Off'}</Text>
|
|
@@ -53,7 +60,7 @@ export const Controlled: Story = {
|
|
|
53
60
|
};
|
|
54
61
|
|
|
55
62
|
export const Disabled: Story = {
|
|
56
|
-
render: args => (
|
|
63
|
+
render: (args) => (
|
|
57
64
|
<Switch {...args}>
|
|
58
65
|
<Switch.Control />
|
|
59
66
|
</Switch>
|
|
@@ -66,7 +73,7 @@ export const Disabled: Story = {
|
|
|
66
73
|
};
|
|
67
74
|
|
|
68
75
|
export const WithLabel: Story = {
|
|
69
|
-
render: args => (
|
|
76
|
+
render: (args) => (
|
|
70
77
|
<Switch {...args}>
|
|
71
78
|
<Switch.Control />
|
|
72
79
|
<Switch.Label>Enable notifications</Switch.Label>
|
|
@@ -76,3 +83,121 @@ export const WithLabel: Story = {
|
|
|
76
83
|
size: 'md',
|
|
77
84
|
},
|
|
78
85
|
};
|
|
86
|
+
|
|
87
|
+
// ───────────────────────── Usage-page specimens ─────────────────────────
|
|
88
|
+
// Pulled into `Switch.usage.mdx` with <Canvas of={…} />. Hidden (`!dev`); `tags`
|
|
89
|
+
// is written out on each story because the indexer reads CSF statically.
|
|
90
|
+
|
|
91
|
+
export const DoSettingRow: Story = {
|
|
92
|
+
tags: ['!dev'],
|
|
93
|
+
parameters: { layout: 'padded' },
|
|
94
|
+
name: 'Usage / Do: one setting, label first',
|
|
95
|
+
render: () => {
|
|
96
|
+
const [checked, setChecked] = useState(true);
|
|
97
|
+
return (
|
|
98
|
+
<Box
|
|
99
|
+
maxW="480px"
|
|
100
|
+
borderWidth="1px"
|
|
101
|
+
borderColor="border.subtle"
|
|
102
|
+
borderRadius="12px"
|
|
103
|
+
p={4}
|
|
104
|
+
>
|
|
105
|
+
<Switch
|
|
106
|
+
checked={checked}
|
|
107
|
+
onCheckedChange={(e) => setChecked(e.checked)}
|
|
108
|
+
display="flex"
|
|
109
|
+
justifyContent="space-between"
|
|
110
|
+
w="100%"
|
|
111
|
+
>
|
|
112
|
+
<Switch.Label>
|
|
113
|
+
<Text as="span" display="block" fontWeight="semibold">
|
|
114
|
+
상단에 고정
|
|
115
|
+
</Text>
|
|
116
|
+
<Text as="span" display="block" color="fg.muted" fontSize="sm">
|
|
117
|
+
공지 목록 맨 위에 항상 보입니다.
|
|
118
|
+
</Text>
|
|
119
|
+
</Switch.Label>
|
|
120
|
+
<Switch.Control />
|
|
121
|
+
</Switch>
|
|
122
|
+
</Box>
|
|
123
|
+
);
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export const DontStateInLabel: Story = {
|
|
128
|
+
tags: ['!dev'],
|
|
129
|
+
parameters: { layout: 'padded' },
|
|
130
|
+
name: "Usage / Don't: put the state in the label",
|
|
131
|
+
render: () => {
|
|
132
|
+
const [checked, setChecked] = useState(true);
|
|
133
|
+
return (
|
|
134
|
+
<Switch checked={checked} onCheckedChange={(e) => setChecked(e.checked)}>
|
|
135
|
+
<Switch.Control />
|
|
136
|
+
<Switch.Label>{checked ? '켜짐' : '꺼짐'}</Switch.Label>
|
|
137
|
+
</Switch>
|
|
138
|
+
);
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export const DontSwitchList: Story = {
|
|
143
|
+
tags: ['!dev'],
|
|
144
|
+
parameters: { layout: 'padded' },
|
|
145
|
+
name: "Usage / Don't: switches to pick items from a list",
|
|
146
|
+
render: () => (
|
|
147
|
+
<Stack gap={2}>
|
|
148
|
+
{['마케팅팀', '영업팀', '개발팀'].map((team) => (
|
|
149
|
+
<Switch key={team}>
|
|
150
|
+
<Switch.Control />
|
|
151
|
+
<Switch.Label>{team}</Switch.Label>
|
|
152
|
+
</Switch>
|
|
153
|
+
))}
|
|
154
|
+
</Stack>
|
|
155
|
+
),
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export const DoCheckboxList: Story = {
|
|
159
|
+
tags: ['!dev'],
|
|
160
|
+
parameters: { layout: 'padded' },
|
|
161
|
+
name: 'Usage / Do: checkboxes to pick items',
|
|
162
|
+
render: () => (
|
|
163
|
+
<Stack gap={2}>
|
|
164
|
+
{['마케팅팀', '영업팀', '개발팀'].map((team) => (
|
|
165
|
+
<Checkbox key={team}>
|
|
166
|
+
<Checkbox.Control />
|
|
167
|
+
<Checkbox.Label>{team}</Checkbox.Label>
|
|
168
|
+
</Checkbox>
|
|
169
|
+
))}
|
|
170
|
+
</Stack>
|
|
171
|
+
),
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/** Tokens `SwitchControl` reads, as written in `SwitchControl.tsx`. */
|
|
175
|
+
export const UsageTokens: Story = {
|
|
176
|
+
tags: ['!dev'],
|
|
177
|
+
parameters: { layout: 'padded' },
|
|
178
|
+
name: 'Usage / Tokens',
|
|
179
|
+
render: () => (
|
|
180
|
+
<TokenTable
|
|
181
|
+
rows={[
|
|
182
|
+
{ token: 'bg.track', use: <T en="Track when off" ko="꺼짐 트랙" /> },
|
|
183
|
+
{ token: 'primary.main', use: <T en="Track when on" ko="켜짐 트랙" /> },
|
|
184
|
+
{
|
|
185
|
+
token: 'bg.surface',
|
|
186
|
+
use: <T en="Thumb when off" ko="꺼짐 손잡이" />,
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
token: 'fg.onPrimary',
|
|
190
|
+
use: <T en="Thumb when on" ko="켜짐 손잡이" />,
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
token: 'disabled.bg',
|
|
194
|
+
use: <T en="Disabled track" ko="비활성 트랙" />,
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
token: 'focus.ring',
|
|
198
|
+
use: <T en="Keyboard focus ring" ko="키보드 초점 링" />,
|
|
199
|
+
},
|
|
200
|
+
]}
|
|
201
|
+
/>
|
|
202
|
+
),
|
|
203
|
+
};
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { ArgTypes, Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import { En, Ko, LangToggle, Verdict } from '../../guidelines/_components/Lang';
|
|
4
|
+
import * as SwitchStories from './Switch.stories';
|
|
5
|
+
|
|
6
|
+
<Meta of={SwitchStories} name="Usage" />
|
|
7
|
+
|
|
8
|
+
<LangToggle />
|
|
9
|
+
|
|
10
|
+
<En>
|
|
11
|
+
|
|
12
|
+
# Switch
|
|
13
|
+
|
|
14
|
+
A toggle for one setting that is either on or off.
|
|
15
|
+
|
|
16
|
+
## When to use
|
|
17
|
+
|
|
18
|
+
- A single feature or setting the user turns on or off: pin an announcement,
|
|
19
|
+
show it as a pop-up, enable a connector.
|
|
20
|
+
- A row in a settings list, with the label on the left and the switch at the
|
|
21
|
+
end.
|
|
22
|
+
|
|
23
|
+
## When not to use
|
|
24
|
+
|
|
25
|
+
- Picking items from a list, or several choices that belong together →
|
|
26
|
+
`Checkbox`.
|
|
27
|
+
- Agreeing to something → `Checkbox`. "On" is not the same as "I agree".
|
|
28
|
+
- One of more than two states → `Radio` or `SelectField`.
|
|
29
|
+
|
|
30
|
+
## Props
|
|
31
|
+
|
|
32
|
+
</En>
|
|
33
|
+
|
|
34
|
+
<Ko>
|
|
35
|
+
|
|
36
|
+
# Switch
|
|
37
|
+
|
|
38
|
+
켜거나 끄는 설정 하나를 바꾸는 토글입니다.
|
|
39
|
+
|
|
40
|
+
## 언제 쓰나요
|
|
41
|
+
|
|
42
|
+
- 사용자가 켜거나 끄는 기능이나 설정 하나: 공지 상단 고정, 팝업으로 보여 주기, 커넥터
|
|
43
|
+
사용.
|
|
44
|
+
- 설정 목록의 한 행. 라벨은 왼쪽에, 스위치는 행 끝에 둡니다.
|
|
45
|
+
|
|
46
|
+
## 언제 쓰지 않나요
|
|
47
|
+
|
|
48
|
+
- 목록에서 항목을 고르거나, 함께 묶이는 여러 선택은 `Checkbox`를 씁니다.
|
|
49
|
+
- 동의를 받을 때는 `Checkbox`를 씁니다. "켜짐"은 "동의합니다"와 다릅니다.
|
|
50
|
+
- 상태가 셋 이상이라면 `Radio`나 `SelectField`를 씁니다.
|
|
51
|
+
|
|
52
|
+
## 속성
|
|
53
|
+
|
|
54
|
+
</Ko>
|
|
55
|
+
|
|
56
|
+
<ArgTypes
|
|
57
|
+
of={SwitchStories}
|
|
58
|
+
include={['checked', 'defaultChecked', 'onCheckedChange', 'disabled', 'size']}
|
|
59
|
+
/>
|
|
60
|
+
|
|
61
|
+
<En>
|
|
62
|
+
|
|
63
|
+
Compose it from `<Switch>`, `<Switch.Control />` and `<Switch.Label>`. The
|
|
64
|
+
root is the click target, so the label toggles it too. The thumb settles with
|
|
65
|
+
a small overshoot; under reduced motion it moves without it.
|
|
66
|
+
|
|
67
|
+
If the change is saved the moment the switch flips, say so on the screen (a
|
|
68
|
+
toast, or a "saved" line). If it is saved with the rest of the form, keep it
|
|
69
|
+
in the form and save on submit, the same as every other field.
|
|
70
|
+
|
|
71
|
+
## Do / Don't
|
|
72
|
+
|
|
73
|
+
</En>
|
|
74
|
+
|
|
75
|
+
<Ko>
|
|
76
|
+
|
|
77
|
+
`<Switch>`, `<Switch.Control />`, `<Switch.Label>`을 조합해서 씁니다. 루트 전체를 눌러도
|
|
78
|
+
되므로 라벨을 눌러도 바뀝니다. 손잡이는 살짝 지나쳤다가 제자리에 멈추고, 동작 줄이기
|
|
79
|
+
설정에서는 그 움직임 없이 옮겨 갑니다.
|
|
80
|
+
|
|
81
|
+
스위치를 바꾸는 순간 저장된다면 화면에서 그렇게 알려 줍니다(토스트나 "저장됨" 문구).
|
|
82
|
+
폼의 다른 값과 함께 저장된다면 다른 필드처럼 폼 안에 두고 제출할 때 저장합니다.
|
|
83
|
+
|
|
84
|
+
## 이렇게 하세요 / 이렇게 하지 마세요
|
|
85
|
+
|
|
86
|
+
</Ko>
|
|
87
|
+
|
|
88
|
+
<Canvas of={SwitchStories.DoSettingRow} />
|
|
89
|
+
<Verdict
|
|
90
|
+
kind="do"
|
|
91
|
+
en="Name the setting in the label, describe its effect in a muted line, and put the switch at the end of the row."
|
|
92
|
+
ko="라벨에 설정 이름을 쓰고, 효과는 흐린 글자로 한 줄 덧붙이며, 스위치는 행 끝에 둡니다."
|
|
93
|
+
/>
|
|
94
|
+
|
|
95
|
+
<Canvas of={SwitchStories.DontStateInLabel} />
|
|
96
|
+
<Verdict
|
|
97
|
+
kind="dont"
|
|
98
|
+
en="Make the label say the current state. The label should name the setting; the switch already shows the state, and a screen reader announces it."
|
|
99
|
+
ko="라벨에 현재 상태를 쓰지 마세요. 라벨은 설정의 이름이어야 합니다. 상태는 스위치가 이미 보여 주고, 화면 낭독기도 읽어 줍니다."
|
|
100
|
+
/>
|
|
101
|
+
|
|
102
|
+
<Canvas of={SwitchStories.DontSwitchList} />
|
|
103
|
+
<Verdict
|
|
104
|
+
kind="dont"
|
|
105
|
+
en="Use switches to pick items from a list. Teams are not settings that are on or off."
|
|
106
|
+
ko="목록에서 항목을 고르는 데 스위치를 쓰지 마세요. 팀은 켜고 끄는 설정이 아닙니다."
|
|
107
|
+
/>
|
|
108
|
+
|
|
109
|
+
<Canvas of={SwitchStories.DoCheckboxList} />
|
|
110
|
+
<Verdict
|
|
111
|
+
kind="do"
|
|
112
|
+
en="Use checkboxes to pick items."
|
|
113
|
+
ko="항목을 고를 때는 체크박스를 씁니다."
|
|
114
|
+
/>
|
|
115
|
+
|
|
116
|
+
<En>
|
|
117
|
+
|
|
118
|
+
## Content
|
|
119
|
+
|
|
120
|
+
- The label names the setting or feature (상단에 고정), not the action (고정하기)
|
|
121
|
+
and not the state (켜짐).
|
|
122
|
+
- One muted line under the label says what changes when it is on.
|
|
123
|
+
- No question marks.
|
|
124
|
+
|
|
125
|
+
## Accessibility
|
|
126
|
+
|
|
127
|
+
What Switch does for you:
|
|
128
|
+
|
|
129
|
+
- A native checkbox input carries the state, so Tab focuses it and Space
|
|
130
|
+
toggles it.
|
|
131
|
+
- The keyboard focus ring shows on the track (WCAG 2.4.7). The off track is
|
|
132
|
+
`bg.track`, a filled track that stays visible on any surface (WCAG 1.4.11).
|
|
133
|
+
|
|
134
|
+
What you still have to do:
|
|
135
|
+
|
|
136
|
+
- **Always render `Switch.Label`** (with `srOnly` if the row's title is
|
|
137
|
+
elsewhere). Without it the switch has no name (WCAG 4.1.2; KWCAG 5.3.4.1
|
|
138
|
+
레이블 제공).
|
|
139
|
+
- Position, not colour, shows the state; keep the default thumb so it stays
|
|
140
|
+
that way (WCAG 1.4.1).
|
|
141
|
+
- If flipping it saves immediately, announce the result (a toast), so the
|
|
142
|
+
user knows the change was not lost (WCAG 4.1.3).
|
|
143
|
+
|
|
144
|
+
## Tokens
|
|
145
|
+
|
|
146
|
+
</En>
|
|
147
|
+
|
|
148
|
+
<Ko>
|
|
149
|
+
|
|
150
|
+
## 문구
|
|
151
|
+
|
|
152
|
+
- 라벨에는 설정이나 기능의 이름을 씁니다(상단에 고정). 동작(고정하기)이나 상태(켜짐)는
|
|
153
|
+
쓰지 않습니다.
|
|
154
|
+
- 라벨 아래 흐린 글자 한 줄로 켜면 무엇이 달라지는지 씁니다.
|
|
155
|
+
- 물음표를 쓰지 않습니다.
|
|
156
|
+
|
|
157
|
+
## 접근성
|
|
158
|
+
|
|
159
|
+
Switch가 알아서 하는 일
|
|
160
|
+
|
|
161
|
+
- 상태는 네이티브 체크박스 입력이 가지고 있어서 Tab으로 초점을 옮기고 Space로 바꿀 수
|
|
162
|
+
있습니다.
|
|
163
|
+
- 키보드 초점 링이 트랙에 보입니다(WCAG 2.4.7). 꺼짐 트랙은 어떤 면 위에서도 보이도록
|
|
164
|
+
채워진 `bg.track`을 씁니다(WCAG 1.4.11).
|
|
165
|
+
|
|
166
|
+
직접 챙겨야 하는 일
|
|
167
|
+
|
|
168
|
+
- **`Switch.Label`을 항상 그립니다.** 행 제목이 다른 곳에 있다면 `srOnly`를 줍니다.
|
|
169
|
+
라벨이 없으면 스위치에 이름이 없습니다(WCAG 4.1.2, KWCAG 5.3.4.1 레이블 제공).
|
|
170
|
+
- 상태는 색이 아니라 손잡이 위치로 드러납니다. 기본 손잡이를 그대로 두어 이 점을
|
|
171
|
+
지킵니다(WCAG 1.4.1).
|
|
172
|
+
- 바꾸는 즉시 저장된다면 토스트 등으로 결과를 알려, 바뀐 내용이 사라지지 않았다는 것을
|
|
173
|
+
알 수 있게 합니다(WCAG 4.1.3).
|
|
174
|
+
|
|
175
|
+
## 토큰
|
|
176
|
+
|
|
177
|
+
</Ko>
|
|
178
|
+
|
|
179
|
+
<Canvas of={SwitchStories.UsageTokens} sourceState="none" />
|
|
180
|
+
|
|
181
|
+
<En>
|
|
182
|
+
|
|
183
|
+
## Related
|
|
184
|
+
|
|
185
|
+
- **Checkbox**: picking items, agreeing.
|
|
186
|
+
- **Radio** / **SelectField**: more than two states.
|
|
187
|
+
- **Toast**: confirming a change that saved immediately.
|
|
188
|
+
|
|
189
|
+
</En>
|
|
190
|
+
|
|
191
|
+
<Ko>
|
|
192
|
+
|
|
193
|
+
## 관련 컴포넌트
|
|
194
|
+
|
|
195
|
+
- **Checkbox**: 항목 고르기, 동의.
|
|
196
|
+
- **Radio** / **SelectField**: 상태가 셋 이상일 때.
|
|
197
|
+
- **Toast**: 바로 저장된 변경 알림.
|
|
198
|
+
|
|
199
|
+
</Ko>
|
|
@@ -2,9 +2,13 @@ import { useState } from 'react';
|
|
|
2
2
|
import { Flex } from '@chakra-ui/react';
|
|
3
3
|
import { Meta, StoryObj } from '@storybook/react';
|
|
4
4
|
|
|
5
|
+
import { TokenTable } from '../../guidelines/_components/TokenTable';
|
|
6
|
+
import { tableSlotRecipe } from '../../theme/recipes/table';
|
|
7
|
+
import { Badge } from '../Badge';
|
|
5
8
|
import { Button } from '../Button';
|
|
6
9
|
import { IoChevronDownOutline } from '../Icon';
|
|
7
10
|
import { IconButton } from '../IconButton';
|
|
11
|
+
import { Link } from '../Typography';
|
|
8
12
|
import {
|
|
9
13
|
ExpandingTr,
|
|
10
14
|
Table,
|
|
@@ -126,7 +130,7 @@ export const Default: Story = {
|
|
|
126
130
|
/**
|
|
127
131
|
* Rows that receive `onClick` (or `role="button"` / `tabIndex`) automatically
|
|
128
132
|
* get the interactive treatment from the table recipe: pointer cursor,
|
|
129
|
-
* `
|
|
133
|
+
* `primary.wash` hover, and a focus-visible outline. Static rows never highlight.
|
|
130
134
|
*/
|
|
131
135
|
export const InteractiveRows: Story = {
|
|
132
136
|
render: (args) => (
|
|
@@ -699,3 +703,157 @@ export const StickyOffsetsSurvivePagination: Story = {
|
|
|
699
703
|
args: { width: '220%' },
|
|
700
704
|
argTypes: {},
|
|
701
705
|
};
|
|
706
|
+
|
|
707
|
+
// ───────────────────────── Usage-page specimens ─────────────────────────
|
|
708
|
+
// Pulled into `Table.usage.mdx` with <Canvas of={…} />. Hidden from the
|
|
709
|
+
// sidebar (`!dev`); `tags` is written out on each story because the indexer
|
|
710
|
+
// reads CSF statically.
|
|
711
|
+
|
|
712
|
+
const USAGE_ROWS = [
|
|
713
|
+
{ name: '김지민', group: '마케팅', credits: 12480, status: 'ok' },
|
|
714
|
+
{ name: '이서준', group: '영업', credits: 830, status: 'ok' },
|
|
715
|
+
{ name: '박하은', group: '개발', credits: 0, status: 'invalid' },
|
|
716
|
+
] as const;
|
|
717
|
+
|
|
718
|
+
export const DoNumbersAligned: Story = {
|
|
719
|
+
tags: ['!dev'],
|
|
720
|
+
parameters: { layout: 'padded' },
|
|
721
|
+
name: 'Usage / Do: a link in the name cell, numbers aligned to the end',
|
|
722
|
+
render: () => (
|
|
723
|
+
<TableContainer maxW="520px">
|
|
724
|
+
<Table>
|
|
725
|
+
<Thead>
|
|
726
|
+
<Tr>
|
|
727
|
+
<Th>이름</Th>
|
|
728
|
+
<Th>그룹</Th>
|
|
729
|
+
<Th textAlign="end">사용 크레딧</Th>
|
|
730
|
+
</Tr>
|
|
731
|
+
</Thead>
|
|
732
|
+
<Tbody>
|
|
733
|
+
{USAGE_ROWS.map((row) => (
|
|
734
|
+
<Tr key={row.name}>
|
|
735
|
+
<Td>
|
|
736
|
+
<Link href={`#member-${row.name}`}>{row.name}</Link>
|
|
737
|
+
</Td>
|
|
738
|
+
<Td>{row.group}</Td>
|
|
739
|
+
<Td textAlign="end" fontVariantNumeric="tabular-nums">
|
|
740
|
+
{row.credits.toLocaleString('ko-KR')}
|
|
741
|
+
</Td>
|
|
742
|
+
</Tr>
|
|
743
|
+
))}
|
|
744
|
+
</Tbody>
|
|
745
|
+
</Table>
|
|
746
|
+
</TableContainer>
|
|
747
|
+
),
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
export const DoStateWithWords: Story = {
|
|
751
|
+
tags: ['!dev'],
|
|
752
|
+
parameters: { layout: 'padded' },
|
|
753
|
+
name: 'Usage / Do: a row state backed by words',
|
|
754
|
+
render: () => (
|
|
755
|
+
<TableContainer maxW="520px">
|
|
756
|
+
<Table>
|
|
757
|
+
<Thead>
|
|
758
|
+
<Tr>
|
|
759
|
+
<Th>이름</Th>
|
|
760
|
+
<Th>상태</Th>
|
|
761
|
+
</Tr>
|
|
762
|
+
</Thead>
|
|
763
|
+
<Tbody>
|
|
764
|
+
{USAGE_ROWS.map((row) => (
|
|
765
|
+
<Tr
|
|
766
|
+
key={row.name}
|
|
767
|
+
state={row.status === 'invalid' ? 'invalid' : undefined}
|
|
768
|
+
>
|
|
769
|
+
<Td>{row.name}</Td>
|
|
770
|
+
<Td>
|
|
771
|
+
{row.status === 'invalid' ? (
|
|
772
|
+
<Badge variant="danger">이메일 오류</Badge>
|
|
773
|
+
) : (
|
|
774
|
+
<Badge variant="success">정상</Badge>
|
|
775
|
+
)}
|
|
776
|
+
</Td>
|
|
777
|
+
</Tr>
|
|
778
|
+
))}
|
|
779
|
+
</Tbody>
|
|
780
|
+
</Table>
|
|
781
|
+
</TableContainer>
|
|
782
|
+
),
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
export const DontStateColourOnly: Story = {
|
|
786
|
+
tags: ['!dev'],
|
|
787
|
+
parameters: { layout: 'padded' },
|
|
788
|
+
name: "Usage / Don't: a tinted row with no words",
|
|
789
|
+
render: () => (
|
|
790
|
+
<TableContainer maxW="520px">
|
|
791
|
+
<Table>
|
|
792
|
+
<Thead>
|
|
793
|
+
<Tr>
|
|
794
|
+
<Th>이름</Th>
|
|
795
|
+
<Th>그룹</Th>
|
|
796
|
+
</Tr>
|
|
797
|
+
</Thead>
|
|
798
|
+
<Tbody>
|
|
799
|
+
{USAGE_ROWS.map((row) => (
|
|
800
|
+
<Tr
|
|
801
|
+
key={row.name}
|
|
802
|
+
state={row.status === 'invalid' ? 'invalid' : undefined}
|
|
803
|
+
>
|
|
804
|
+
<Td>{row.name}</Td>
|
|
805
|
+
<Td>{row.group}</Td>
|
|
806
|
+
</Tr>
|
|
807
|
+
))}
|
|
808
|
+
</Tbody>
|
|
809
|
+
</Table>
|
|
810
|
+
</TableContainer>
|
|
811
|
+
),
|
|
812
|
+
};
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Every colour token in the table slot recipe (`theme/recipes/table.ts`),
|
|
816
|
+
* collected by walking the recipe, so a recipe change shows up here.
|
|
817
|
+
*/
|
|
818
|
+
const recipeTokens = (
|
|
819
|
+
node: unknown,
|
|
820
|
+
path: string[] = []
|
|
821
|
+
): { token: string; use: string }[] => {
|
|
822
|
+
if (typeof node === 'string') {
|
|
823
|
+
return /^[a-z]+(\.[a-zA-Z0-9]+)+$/.test(node)
|
|
824
|
+
? [{ token: node, use: path.join(' › ') }]
|
|
825
|
+
: [];
|
|
826
|
+
}
|
|
827
|
+
if (node && typeof node === 'object') {
|
|
828
|
+
return Object.entries(node).flatMap(([key, value]) =>
|
|
829
|
+
recipeTokens(value, [...path, key])
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
return [];
|
|
833
|
+
};
|
|
834
|
+
|
|
835
|
+
/** One row per token; the places it is read from are listed together. */
|
|
836
|
+
const mergeByToken = (rows: { token: string; use: string }[]) =>
|
|
837
|
+
[...new Set(rows.map((row) => row.token))].map((token) => ({
|
|
838
|
+
token,
|
|
839
|
+
use: rows
|
|
840
|
+
.filter((row) => row.token === token)
|
|
841
|
+
.map((row) => row.use)
|
|
842
|
+
.join(', '),
|
|
843
|
+
}));
|
|
844
|
+
|
|
845
|
+
export const UsageTokens: Story = {
|
|
846
|
+
tags: ['!dev'],
|
|
847
|
+
parameters: { layout: 'padded' },
|
|
848
|
+
name: 'Usage / Tokens',
|
|
849
|
+
render: () => (
|
|
850
|
+
<TokenTable
|
|
851
|
+
rows={mergeByToken([
|
|
852
|
+
...recipeTokens(tableSlotRecipe.base),
|
|
853
|
+
{ token: 'border.subtle', use: 'TableContainer › border' },
|
|
854
|
+
{ token: 'bg.subtle', use: 'Th isSticky › background' },
|
|
855
|
+
{ token: 'bg.surface', use: 'Td isSticky › background' },
|
|
856
|
+
])}
|
|
857
|
+
/>
|
|
858
|
+
),
|
|
859
|
+
};
|