@mindlogic-ai/logician-ui 5.0.0-alpha.2 → 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/Badge/Badge.d.ts.map +1 -1
- package/dist/components/Badge/Badge.js +5 -3
- package/dist/components/Badge/Badge.js.map +1 -1
- package/dist/components/Badge/Badge.mjs +5 -3
- package/dist/components/Badge/Badge.mjs.map +1 -1
- package/dist/components/Badge/Badge.types.d.ts +7 -5
- package/dist/components/Badge/Badge.types.d.ts.map +1 -1
- 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/Badge/Badge.stories.tsx +193 -3
- package/src/components/Badge/Badge.tsx +5 -3
- package/src/components/Badge/Badge.types.ts +7 -5
- package/src/components/Badge/Badge.usage.mdx +265 -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 +364 -0
- package/src/foundations/BrandColour.stories.tsx +334 -0
- package/src/guidelines/ComponentPageTemplate.mdx +84 -0
- package/src/guidelines/FeedbackActions.mdx +162 -23
- package/src/guidelines/_components/Lang.tsx +175 -0
- package/src/guidelines/_components/TokenTable.tsx +136 -0
- 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,145 @@
|
|
|
1
|
+
import { ArgTypes, Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import { En, Ko, LangToggle, Verdict } from '../../guidelines/_components/Lang';
|
|
4
|
+
import * as SegmentedProgressBarStories from './SegmentedProgressBar.stories';
|
|
5
|
+
|
|
6
|
+
<Meta of={SegmentedProgressBarStories} name="Usage" />
|
|
7
|
+
|
|
8
|
+
<LangToggle />
|
|
9
|
+
|
|
10
|
+
<En>
|
|
11
|
+
|
|
12
|
+
# SegmentedProgressBar
|
|
13
|
+
|
|
14
|
+
One bar split into parts of a single whole, such as messages sent, failed and
|
|
15
|
+
still to go.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
- A batch job with more than one outcome: sent and failed, accepted and
|
|
20
|
+
rejected.
|
|
21
|
+
- A total split into two or three parts the reader compares at a glance.
|
|
22
|
+
|
|
23
|
+
## When not to use
|
|
24
|
+
|
|
25
|
+
- A single value against a limit → `ProgressBar`.
|
|
26
|
+
- Many categories, or a share of storage or budget → `RadialProgress` with a
|
|
27
|
+
legend, or a table.
|
|
28
|
+
|
|
29
|
+
## How it works
|
|
30
|
+
|
|
31
|
+
- `<SegmentedProgressBar max={total}>` draws the `bg.track` remainder; each
|
|
32
|
+
`<ProgressSegment value={n} filledTrackColor="…" />` inside it takes
|
|
33
|
+
`n / max` of the width, in order.
|
|
34
|
+
- `height` defaults to 16px; pass `height` for a slimmer bar.
|
|
35
|
+
|
|
36
|
+
</En>
|
|
37
|
+
|
|
38
|
+
<Ko>
|
|
39
|
+
|
|
40
|
+
# SegmentedProgressBar
|
|
41
|
+
|
|
42
|
+
보낸 메시지, 실패한 메시지, 남은 메시지처럼 하나의 전체를 이루는 부분을 막대 하나에
|
|
43
|
+
나눠 보여 줍니다.
|
|
44
|
+
|
|
45
|
+
## 언제 쓰나요
|
|
46
|
+
|
|
47
|
+
- 결과가 둘 이상인 일괄 작업: 보냄과 실패, 승인과 거절.
|
|
48
|
+
- 전체를 두세 부분으로 나눠 한눈에 비교할 때.
|
|
49
|
+
|
|
50
|
+
## 언제 쓰지 않나요
|
|
51
|
+
|
|
52
|
+
- 한도에 대한 값 하나는 `ProgressBar`를 씁니다.
|
|
53
|
+
- 분류가 많거나 저장 공간, 예산의 비율이라면 범례를 붙인 `RadialProgress`나 표를
|
|
54
|
+
씁니다.
|
|
55
|
+
|
|
56
|
+
## 동작 방식
|
|
57
|
+
|
|
58
|
+
- `<SegmentedProgressBar max={total}>`이 `bg.track` 바탕을 그리고, 그 안의
|
|
59
|
+
`<ProgressSegment value={n} filledTrackColor="…" />`가 차례대로 폭의 `n / max`만큼
|
|
60
|
+
차지합니다.
|
|
61
|
+
- 높이 기본값은 16px입니다. 더 얇게 하려면 `height`를 넘깁니다.
|
|
62
|
+
|
|
63
|
+
</Ko>
|
|
64
|
+
|
|
65
|
+
<ArgTypes of={SegmentedProgressBarStories} include={['max', 'height']} />
|
|
66
|
+
|
|
67
|
+
<En>
|
|
68
|
+
|
|
69
|
+
## Do / Don't
|
|
70
|
+
|
|
71
|
+
</En>
|
|
72
|
+
|
|
73
|
+
<Ko>
|
|
74
|
+
|
|
75
|
+
## 이렇게 하세요 / 이렇게 하지 마세요
|
|
76
|
+
|
|
77
|
+
</Ko>
|
|
78
|
+
|
|
79
|
+
<Canvas of={SegmentedProgressBarStories.DoCountsInText} />
|
|
80
|
+
<Verdict
|
|
81
|
+
kind="do"
|
|
82
|
+
en="Write each count next to the bar and colour the failure count's text too. Hide the bar itself from screen readers (aria-hidden) when the text says everything."
|
|
83
|
+
ko="부분별 개수를 막대 옆에 글자로 쓰고, 실패 개수는 글자에도 색을 입힙니다. 글자가 모든 정보를 전한다면 막대는 화면 낭독기에서 숨깁니다(aria-hidden)."
|
|
84
|
+
/>
|
|
85
|
+
|
|
86
|
+
<Canvas of={SegmentedProgressBarStories.DontColourOnly} />
|
|
87
|
+
<Verdict
|
|
88
|
+
kind="dont"
|
|
89
|
+
en="Show the segments with no words. Green and red are the only way to tell them apart, and each segment is announced as a full progress bar."
|
|
90
|
+
ko="글자 없이 세그먼트만 보여 주지 마세요. 초록과 빨강 말고는 구분할 방법이 없고, 세그먼트마다 꽉 찬 진행 막대로 읽힙니다."
|
|
91
|
+
/>
|
|
92
|
+
|
|
93
|
+
<En>
|
|
94
|
+
|
|
95
|
+
## Accessibility
|
|
96
|
+
|
|
97
|
+
- **Each segment is announced as a separate, full progress bar.**
|
|
98
|
+
`ProgressSegment` is a `ProgressBar` with `max` set to its own `value`, so a
|
|
99
|
+
screen reader hears "100%" once per segment, and the container has no role
|
|
100
|
+
or name. Until that changes, put the counts in text and set `aria-hidden` on
|
|
101
|
+
the bar (WCAG 1.3.1, 4.1.2).
|
|
102
|
+
- **Words, not colour alone** (WCAG 1.4.1).
|
|
103
|
+
- Status colours (`success.solid`, `danger.solid`) only when the parts are
|
|
104
|
+
outcomes; other parts take `primary.main` or category tokens. Use tokens,
|
|
105
|
+
not hex.
|
|
106
|
+
|
|
107
|
+
## Tokens
|
|
108
|
+
|
|
109
|
+
</En>
|
|
110
|
+
|
|
111
|
+
<Ko>
|
|
112
|
+
|
|
113
|
+
## 접근성
|
|
114
|
+
|
|
115
|
+
- **세그먼트마다 따로, 꽉 찬 진행 막대로 읽힙니다.** `ProgressSegment`는 `max`를 자기
|
|
116
|
+
`value`로 정한 `ProgressBar`라서, 화면 낭독기는 세그먼트마다 "100%"라고 읽습니다.
|
|
117
|
+
바깥 요소에는 역할도 이름도 없습니다. 이 문제가 고쳐질 때까지는 개수를 글자로 쓰고
|
|
118
|
+
막대에 `aria-hidden`을 붙입니다(WCAG 1.3.1, 4.1.2).
|
|
119
|
+
- **색만으로 알리지 않습니다**(WCAG 1.4.1).
|
|
120
|
+
- 부분이 작업 결과일 때만 상태색(`success.solid`, `danger.solid`)을 씁니다. 그 밖의
|
|
121
|
+
부분은 `primary.main`이나 category 토큰을 씁니다. 16진수가 아니라 토큰을 씁니다.
|
|
122
|
+
|
|
123
|
+
## 토큰
|
|
124
|
+
|
|
125
|
+
</Ko>
|
|
126
|
+
|
|
127
|
+
<Canvas of={SegmentedProgressBarStories.UsageTokens} sourceState="none" />
|
|
128
|
+
|
|
129
|
+
<En>
|
|
130
|
+
|
|
131
|
+
## Related
|
|
132
|
+
|
|
133
|
+
- **ProgressBar**: one value against a limit.
|
|
134
|
+
- **RadialProgress**: a share split into categories.
|
|
135
|
+
|
|
136
|
+
</En>
|
|
137
|
+
|
|
138
|
+
<Ko>
|
|
139
|
+
|
|
140
|
+
## 관련 컴포넌트
|
|
141
|
+
|
|
142
|
+
- **ProgressBar**: 한도에 대한 값 하나.
|
|
143
|
+
- **RadialProgress**: 분류별로 나눈 비율.
|
|
144
|
+
|
|
145
|
+
</Ko>
|
|
@@ -9,11 +9,21 @@ import {
|
|
|
9
9
|
Stack,
|
|
10
10
|
Text,
|
|
11
11
|
} from '@chakra-ui/react';
|
|
12
|
-
import { Meta } from '@storybook/react';
|
|
12
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
13
13
|
|
|
14
|
+
import { T } from '../../guidelines/_components/Lang';
|
|
15
|
+
import { TokenTable } from '../../guidelines/_components/TokenTable';
|
|
14
16
|
import { Badge } from '../Badge';
|
|
17
|
+
import { Radio, RadioGroup } from '../Radio';
|
|
15
18
|
import { IoCall, IoChatbubbleEllipses, IoIosMail } from '../Icon';
|
|
19
|
+
import { ComboboxField } from './ComboboxField';
|
|
16
20
|
import { Select } from './Select';
|
|
21
|
+
import {
|
|
22
|
+
contentStyles,
|
|
23
|
+
indicatorStyles,
|
|
24
|
+
itemStyles,
|
|
25
|
+
triggerStyles,
|
|
26
|
+
} from './Select.styles';
|
|
17
27
|
import { SelectField } from './SelectField';
|
|
18
28
|
|
|
19
29
|
const meta = {
|
|
@@ -771,3 +781,201 @@ export const WithOpenChange = () => {
|
|
|
771
781
|
</HStack>
|
|
772
782
|
);
|
|
773
783
|
};
|
|
784
|
+
|
|
785
|
+
// ───────────────────────── Usage-page specimens ─────────────────────────
|
|
786
|
+
// Pulled into `Select.usage.mdx` with <Canvas of={…} />. Hidden from the
|
|
787
|
+
// sidebar (`!dev`); `tags` is written out on each story because the indexer
|
|
788
|
+
// reads CSF statically.
|
|
789
|
+
|
|
790
|
+
type UsageStory = StoryObj;
|
|
791
|
+
|
|
792
|
+
const LANGUAGES = [
|
|
793
|
+
{ label: '한국어', value: 'ko' },
|
|
794
|
+
{ label: 'English', value: 'en' },
|
|
795
|
+
{ label: '日本語', value: 'ja' },
|
|
796
|
+
];
|
|
797
|
+
|
|
798
|
+
const GROUPS = [
|
|
799
|
+
'경영지원팀',
|
|
800
|
+
'고객성공팀',
|
|
801
|
+
'데이터팀',
|
|
802
|
+
'디자인팀',
|
|
803
|
+
'마케팅팀',
|
|
804
|
+
'백엔드팀',
|
|
805
|
+
'법무팀',
|
|
806
|
+
'보안팀',
|
|
807
|
+
'사업개발팀',
|
|
808
|
+
'세일즈팀',
|
|
809
|
+
'인사팀',
|
|
810
|
+
'재무팀',
|
|
811
|
+
'프론트엔드팀',
|
|
812
|
+
].map((name) => ({ label: name, value: name }));
|
|
813
|
+
|
|
814
|
+
export const DoLabelled: UsageStory = {
|
|
815
|
+
tags: ['!dev'],
|
|
816
|
+
parameters: { layout: 'padded' },
|
|
817
|
+
name: 'Usage / Do: a visible label',
|
|
818
|
+
render: () => (
|
|
819
|
+
<Box maxW="320px">
|
|
820
|
+
<SelectField label="답변 언어" options={LANGUAGES} defaultValue="ko" />
|
|
821
|
+
</Box>
|
|
822
|
+
),
|
|
823
|
+
};
|
|
824
|
+
|
|
825
|
+
export const DontNameless: UsageStory = {
|
|
826
|
+
tags: ['!dev'],
|
|
827
|
+
parameters: { layout: 'padded' },
|
|
828
|
+
name: "Usage / Don't: no label, ariaLabel or placeholder",
|
|
829
|
+
render: () => (
|
|
830
|
+
<Flex maxW="480px" align="center" justify="space-between" gap={4}>
|
|
831
|
+
<Text fontWeight="semibold">답변 언어</Text>
|
|
832
|
+
<Box w="180px">
|
|
833
|
+
<SelectField options={LANGUAGES} defaultValue="ko" />
|
|
834
|
+
</Box>
|
|
835
|
+
</Flex>
|
|
836
|
+
),
|
|
837
|
+
};
|
|
838
|
+
|
|
839
|
+
export const DoComboboxForLongList: UsageStory = {
|
|
840
|
+
tags: ['!dev'],
|
|
841
|
+
parameters: { layout: 'padded' },
|
|
842
|
+
name: 'Usage / Do: ComboboxField for a long list',
|
|
843
|
+
render: () => (
|
|
844
|
+
<Box maxW="320px">
|
|
845
|
+
<ComboboxField
|
|
846
|
+
label="그룹"
|
|
847
|
+
placeholder="그룹 이름으로 찾기"
|
|
848
|
+
options={GROUPS}
|
|
849
|
+
emptyText="일치하는 그룹이 없습니다"
|
|
850
|
+
/>
|
|
851
|
+
</Box>
|
|
852
|
+
),
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
export const DontSelectForTwo: UsageStory = {
|
|
856
|
+
tags: ['!dev'],
|
|
857
|
+
parameters: { layout: 'padded' },
|
|
858
|
+
name: "Usage / Don't: a dropdown for two options",
|
|
859
|
+
render: () => (
|
|
860
|
+
<Box maxW="320px">
|
|
861
|
+
<SelectField
|
|
862
|
+
label="공개 범위"
|
|
863
|
+
options={[
|
|
864
|
+
{ label: '전체 공개', value: 'public' },
|
|
865
|
+
{ label: '그룹만', value: 'group' },
|
|
866
|
+
]}
|
|
867
|
+
defaultValue="public"
|
|
868
|
+
/>
|
|
869
|
+
</Box>
|
|
870
|
+
),
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
export const DoRadioForTwo: UsageStory = {
|
|
874
|
+
tags: ['!dev'],
|
|
875
|
+
parameters: { layout: 'padded' },
|
|
876
|
+
name: 'Usage / Do: Radio for two visible options',
|
|
877
|
+
render: () => (
|
|
878
|
+
<Stack gap={2} maxW="320px">
|
|
879
|
+
<Text id="usage-visibility" fontWeight="semibold">
|
|
880
|
+
공개 범위
|
|
881
|
+
</Text>
|
|
882
|
+
<RadioGroup
|
|
883
|
+
defaultValue="public"
|
|
884
|
+
aria-labelledby="usage-visibility"
|
|
885
|
+
display="flex"
|
|
886
|
+
gap={4}
|
|
887
|
+
>
|
|
888
|
+
<Radio value="public">
|
|
889
|
+
<Radio.Control />
|
|
890
|
+
<Radio.Text>전체 공개</Radio.Text>
|
|
891
|
+
</Radio>
|
|
892
|
+
<Radio value="group">
|
|
893
|
+
<Radio.Control />
|
|
894
|
+
<Radio.Text>그룹만</Radio.Text>
|
|
895
|
+
</Radio>
|
|
896
|
+
</RadioGroup>
|
|
897
|
+
</Stack>
|
|
898
|
+
),
|
|
899
|
+
};
|
|
900
|
+
|
|
901
|
+
/**
|
|
902
|
+
* Tokens the trigger, list and options read, taken from the style objects in
|
|
903
|
+
* `Select.styles.ts` (shared by Select and Combobox).
|
|
904
|
+
*/
|
|
905
|
+
export const UsageTokens: UsageStory = {
|
|
906
|
+
tags: ['!dev'],
|
|
907
|
+
parameters: { layout: 'padded' },
|
|
908
|
+
name: 'Usage / Tokens',
|
|
909
|
+
render: () => (
|
|
910
|
+
<TokenTable
|
|
911
|
+
rows={[
|
|
912
|
+
{
|
|
913
|
+
token: triggerStyles.bg,
|
|
914
|
+
use: <T en="Trigger background" ko="트리거 배경" />,
|
|
915
|
+
},
|
|
916
|
+
{
|
|
917
|
+
token: triggerStyles.color,
|
|
918
|
+
use: <T en="Selected value" ko="선택한 값" />,
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
token: triggerStyles.borderColor,
|
|
922
|
+
use: <T en="Trigger border at rest" ko="트리거 평소 테두리" />,
|
|
923
|
+
},
|
|
924
|
+
{
|
|
925
|
+
token: triggerStyles._hover.borderColor,
|
|
926
|
+
use: <T en="Border on hover" ko="마우스를 올렸을 때 테두리" />,
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
token: triggerStyles._focus.borderColor,
|
|
930
|
+
use: (
|
|
931
|
+
<T
|
|
932
|
+
en="Border and ring on focus or open"
|
|
933
|
+
ko="초점을 받거나 열렸을 때 테두리와 링"
|
|
934
|
+
/>
|
|
935
|
+
),
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
token: triggerStyles._invalid.borderColor,
|
|
939
|
+
use: <T en="Border when invalid" ko="오류 상태 테두리" />,
|
|
940
|
+
},
|
|
941
|
+
{
|
|
942
|
+
token: triggerStyles._disabled.bg,
|
|
943
|
+
use: <T en="Disabled background" ko="비활성 배경" />,
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
token: triggerStyles._disabled.color,
|
|
947
|
+
use: <T en="Disabled text" ko="비활성 글자" />,
|
|
948
|
+
},
|
|
949
|
+
{
|
|
950
|
+
token: indicatorStyles.color,
|
|
951
|
+
use: <T en="Chevron" ko="펼침 화살표" />,
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
token: contentStyles.bg,
|
|
955
|
+
use: <T en="List background" ko="목록 배경" />,
|
|
956
|
+
},
|
|
957
|
+
{
|
|
958
|
+
token: contentStyles.borderColor,
|
|
959
|
+
use: <T en="List border" ko="목록 테두리" />,
|
|
960
|
+
},
|
|
961
|
+
{
|
|
962
|
+
token: itemStyles._highlighted.bg,
|
|
963
|
+
use: (
|
|
964
|
+
<T
|
|
965
|
+
en="Option under the pointer or keyboard"
|
|
966
|
+
ko="포인터나 키보드가 가리키는 항목"
|
|
967
|
+
/>
|
|
968
|
+
),
|
|
969
|
+
},
|
|
970
|
+
{
|
|
971
|
+
token: itemStyles._checked.bg,
|
|
972
|
+
use: <T en="Selected option" ko="선택된 항목" />,
|
|
973
|
+
},
|
|
974
|
+
{
|
|
975
|
+
token: itemStyles._disabled.color,
|
|
976
|
+
use: <T en="Disabled option" ko="선택할 수 없는 항목" />,
|
|
977
|
+
},
|
|
978
|
+
]}
|
|
979
|
+
/>
|
|
980
|
+
),
|
|
981
|
+
};
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { ArgTypes, Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import { En, Ko, LangToggle, Verdict } from '../../guidelines/_components/Lang';
|
|
4
|
+
import * as SelectStories from './Select.stories';
|
|
5
|
+
import { SelectField } from './SelectField';
|
|
6
|
+
|
|
7
|
+
<Meta of={SelectStories} name="Usage" />
|
|
8
|
+
|
|
9
|
+
<LangToggle />
|
|
10
|
+
|
|
11
|
+
<En>
|
|
12
|
+
|
|
13
|
+
# Select, SelectField, Combobox, ComboboxField
|
|
14
|
+
|
|
15
|
+
Pick one value from a list that is too long to show in full. `SelectField` and
|
|
16
|
+
`ComboboxField` are ready-made fields; `Select` and `Combobox` are the styled
|
|
17
|
+
parts for building your own.
|
|
18
|
+
|
|
19
|
+
| Component | Use it for |
|
|
20
|
+
| --------------- | ------------------------------------------------------------------------------------ |
|
|
21
|
+
| `SelectField` | One value from a short, fixed list. Pass `options`, `value`, `onChange`. |
|
|
22
|
+
| `ComboboxField` | One value from a long list the user would rather search than scroll. |
|
|
23
|
+
| `Select.*` | Multi-select, grouped options, options with icons or descriptions, a custom trigger. |
|
|
24
|
+
| `Combobox.*` | A searchable list with groups or custom rows. |
|
|
25
|
+
|
|
26
|
+
## When to use
|
|
27
|
+
|
|
28
|
+
- Five or more options, or options that would crowd the page if shown at once:
|
|
29
|
+
a language, a model, a role.
|
|
30
|
+
- A setting in a dense list where each row ends in a choice: `SelectField`
|
|
31
|
+
with `variant="ghost"`.
|
|
32
|
+
- A list the user searches by name, such as groups or members:
|
|
33
|
+
`ComboboxField`.
|
|
34
|
+
|
|
35
|
+
## When not to use
|
|
36
|
+
|
|
37
|
+
- Two to four options that fit on screen → `Radio`, so the user sees every
|
|
38
|
+
option without opening anything. A single on/off → `Switch` or `Checkbox`.
|
|
39
|
+
- Switching the view of the same content → `SegmentedControl` or `Tabs`.
|
|
40
|
+
- Running an action (Rename, Delete) → `Menu`. A select holds a value; a menu
|
|
41
|
+
does something.
|
|
42
|
+
- Free text with suggestions the user may ignore → `Input`.
|
|
43
|
+
|
|
44
|
+
## Variants and props
|
|
45
|
+
|
|
46
|
+
</En>
|
|
47
|
+
|
|
48
|
+
<Ko>
|
|
49
|
+
|
|
50
|
+
# Select, SelectField, Combobox, ComboboxField
|
|
51
|
+
|
|
52
|
+
다 펼쳐 보이기에는 긴 목록에서 값 하나를 고르게 합니다. `SelectField`와
|
|
53
|
+
`ComboboxField`는 바로 쓰는 필드이고, `Select`와 `Combobox`는 직접 조합할 때 쓰는
|
|
54
|
+
스타일이 입혀진 부품입니다.
|
|
55
|
+
|
|
56
|
+
| 컴포넌트 | 쓰는 곳 |
|
|
57
|
+
| --------------- | ------------------------------------------------------------------------ |
|
|
58
|
+
| `SelectField` | 짧고 정해진 목록에서 값 하나. `options`, `value`, `onChange`를 넘깁니다. |
|
|
59
|
+
| `ComboboxField` | 스크롤보다 검색이 편한 긴 목록에서 값 하나. |
|
|
60
|
+
| `Select.*` | 여러 개 선택, 묶은 항목, 아이콘이나 설명이 붙은 항목, 직접 만든 트리거. |
|
|
61
|
+
| `Combobox.*` | 묶음이나 직접 만든 행이 있는 검색 목록. |
|
|
62
|
+
|
|
63
|
+
## 언제 쓰나요
|
|
64
|
+
|
|
65
|
+
- 선택지가 다섯 개 이상이거나, 한꺼번에 보이면 화면이 복잡해질 때: 언어, 모델, 역할.
|
|
66
|
+
- 행마다 끝에 선택이 하나씩 있는 촘촘한 설정 목록: `variant="ghost"`인 `SelectField`.
|
|
67
|
+
- 이름으로 찾는 목록(그룹, 멤버): `ComboboxField`.
|
|
68
|
+
|
|
69
|
+
## 언제 쓰지 않나요
|
|
70
|
+
|
|
71
|
+
- 화면에 다 들어가는 두세 개의 선택지는 `Radio`를 씁니다. 아무것도 열지 않고 모든
|
|
72
|
+
선택지를 볼 수 있습니다. 켜고 끄는 값 하나는 `Switch`나 `Checkbox`를 씁니다.
|
|
73
|
+
- 같은 내용의 보기 방식을 바꿀 때는 `SegmentedControl`이나 `Tabs`를 씁니다.
|
|
74
|
+
- 이름 바꾸기, 삭제 같은 동작은 `Menu`를 씁니다. 셀렉트는 값을 담고, 메뉴는 일을
|
|
75
|
+
합니다.
|
|
76
|
+
- 제안을 무시하고 자유롭게 써도 되는 텍스트는 `Input`을 씁니다.
|
|
77
|
+
|
|
78
|
+
## 변형과 속성
|
|
79
|
+
|
|
80
|
+
</Ko>
|
|
81
|
+
|
|
82
|
+
<ArgTypes
|
|
83
|
+
of={SelectField}
|
|
84
|
+
include={['variant', 'label', 'ariaLabel', 'placeholder', 'stagger']}
|
|
85
|
+
/>
|
|
86
|
+
|
|
87
|
+
<En>
|
|
88
|
+
|
|
89
|
+
| Variant | Means | Use for |
|
|
90
|
+
| ------------------- | ------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
|
|
91
|
+
| `outline` (default) | A bordered field, the same as `Input`. Width defaults to `full`. | Forms, modals, filters |
|
|
92
|
+
| `ghost` | No border until hover or focus; sized to its value. An invalid field keeps its red border. | The trailing choice in a settings row, where a column of bordered triggers would outweigh the card |
|
|
93
|
+
|
|
94
|
+
Other props: `size` (`xs`–`lg`, default `md`), `invalid`, `disabled`,
|
|
95
|
+
`readOnly`, `required`, `name`, `width`. `onChange` receives the value, or
|
|
96
|
+
`null` when the selection is cleared. `ComboboxField` adds `emptyText`; it has
|
|
97
|
+
no `variant` or `stagger`.
|
|
98
|
+
|
|
99
|
+
## Do / Don't
|
|
100
|
+
|
|
101
|
+
</En>
|
|
102
|
+
|
|
103
|
+
<Ko>
|
|
104
|
+
|
|
105
|
+
| 변형 | 뜻 | 쓰는 곳 |
|
|
106
|
+
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
107
|
+
| `outline` (기본) | `Input`과 같은 테두리가 있는 필드. 너비 기본값은 `full`입니다. | 폼, 모달, 필터 |
|
|
108
|
+
| `ghost` | 마우스를 올리거나 초점을 받기 전에는 테두리가 없고, 값 길이에 맞춰 너비가 정해집니다. 오류 상태에서는 빨간 테두리가 남습니다. | 설정 목록의 행 끝 선택. 테두리 있는 트리거가 줄지어 있으면 카드보다 무거워 보이는 곳 |
|
|
109
|
+
|
|
110
|
+
그 밖의 속성: `size`(`xs`~`lg`, 기본 `md`), `invalid`, `disabled`, `readOnly`,
|
|
111
|
+
`required`, `name`, `width`. `onChange`는 고른 값을 받고, 선택을 지우면 `null`을
|
|
112
|
+
받습니다. `ComboboxField`에는 `emptyText`가 더 있고, `variant`와 `stagger`는
|
|
113
|
+
없습니다.
|
|
114
|
+
|
|
115
|
+
## 이렇게 하세요 / 이렇게 하지 마세요
|
|
116
|
+
|
|
117
|
+
</Ko>
|
|
118
|
+
|
|
119
|
+
<Canvas of={SelectStories.DoLabelled} />
|
|
120
|
+
<Verdict
|
|
121
|
+
kind="do"
|
|
122
|
+
en="Give the field a visible label with the label prop. It is rendered as the part the trigger is named by."
|
|
123
|
+
ko="label 속성으로 보이는 라벨을 붙입니다. 라벨은 트리거의 이름이 되는 부품으로 그려집니다."
|
|
124
|
+
/>
|
|
125
|
+
|
|
126
|
+
<Canvas of={SelectStories.DontNameless} />
|
|
127
|
+
<Verdict
|
|
128
|
+
kind="dont"
|
|
129
|
+
en="Leave out label, ariaLabel and placeholder. The text next to it is not connected, so a screen reader announces a bare 'button', whatever the value says (KWCAG 5.3.4.1)."
|
|
130
|
+
ko="label, ariaLabel, placeholder를 모두 빼지 마세요. 옆에 있는 글자는 연결되지 않으므로, 화면 낭독기는 값이 무엇이든 그냥 '버튼'이라고만 읽습니다(KWCAG 5.3.4.1)."
|
|
131
|
+
/>
|
|
132
|
+
|
|
133
|
+
<Canvas of={SelectStories.Ghost} />
|
|
134
|
+
<Verdict
|
|
135
|
+
kind="do"
|
|
136
|
+
en="In a settings list, use the ghost variant and pass the row title as ariaLabel."
|
|
137
|
+
ko="설정 목록에서는 ghost 변형을 쓰고, 행 제목을 ariaLabel로 넘깁니다."
|
|
138
|
+
/>
|
|
139
|
+
|
|
140
|
+
<Canvas of={SelectStories.DoComboboxForLongList} />
|
|
141
|
+
<Verdict
|
|
142
|
+
kind="do"
|
|
143
|
+
en="Use ComboboxField when the user knows the name and the list is long. Translate emptyText; the default is English."
|
|
144
|
+
ko="사용자가 이름을 알고 목록이 길다면 ComboboxField를 씁니다. emptyText의 기본값은 영어이므로 번역해서 넘깁니다."
|
|
145
|
+
/>
|
|
146
|
+
|
|
147
|
+
<Canvas of={SelectStories.DontSelectForTwo} />
|
|
148
|
+
<Verdict
|
|
149
|
+
kind="dont"
|
|
150
|
+
en="Hide two options behind a dropdown. The user has to open it to learn there is only one alternative."
|
|
151
|
+
ko="선택지 두 개를 드롭다운 안에 숨기지 마세요. 다른 선택지가 하나뿐이라는 것을 열어 봐야 압니다."
|
|
152
|
+
/>
|
|
153
|
+
|
|
154
|
+
<Canvas of={SelectStories.DoRadioForTwo} />
|
|
155
|
+
<Verdict
|
|
156
|
+
kind="do"
|
|
157
|
+
en="Show a few options as Radio, so the choice is visible at a glance."
|
|
158
|
+
ko="선택지가 몇 개뿐이면 Radio로 펼쳐서 한눈에 보이게 합니다."
|
|
159
|
+
/>
|
|
160
|
+
|
|
161
|
+
<En>
|
|
162
|
+
|
|
163
|
+
## Content
|
|
164
|
+
|
|
165
|
+
- Label: a noun for what is chosen (답변 언어, 역할), not an instruction (언어를
|
|
166
|
+
선택하세요).
|
|
167
|
+
- Placeholder: only when "nothing chosen yet" is a real state. It also becomes
|
|
168
|
+
the hidden name if there is no label, so make it meaningful, but prefer
|
|
169
|
+
`label` or `ariaLabel`.
|
|
170
|
+
- Options: short, parallel, sentence case, sorted in a predictable order
|
|
171
|
+
(frequency, size, or alphabetical). Do not repeat the label in each option.
|
|
172
|
+
- `emptyText` on `ComboboxField`: say what was not found (일치하는 그룹이
|
|
173
|
+
없습니다).
|
|
174
|
+
|
|
175
|
+
## Accessibility
|
|
176
|
+
|
|
177
|
+
What these components do for you:
|
|
178
|
+
|
|
179
|
+
- **A name, if you give one.** `SelectField` and `ComboboxField` always render
|
|
180
|
+
the label part the trigger points at: visibly for `label`, visually hidden
|
|
181
|
+
for `ariaLabel` (or `placeholder` as a fallback). The name is in the server
|
|
182
|
+
markup, not added after hydration (KWCAG 5.3.4.1 레이블 제공).
|
|
183
|
+
- **Keyboard.** The Chakra / Zag listbox handles it: Enter, Space or the arrow
|
|
184
|
+
keys open the list; arrows move; Enter selects; Escape closes and returns
|
|
185
|
+
focus to the trigger. In `ComboboxField` typing filters the list.
|
|
186
|
+
- **Focus and states.** The trigger shows a `primary.main` border and ring on
|
|
187
|
+
focus and while open (WCAG 2.4.7). The selected option is bold on
|
|
188
|
+
`primary.selected` and carries a check mark, so it does not rely on colour
|
|
189
|
+
alone (WCAG 1.4.1).
|
|
190
|
+
|
|
191
|
+
What you still have to do:
|
|
192
|
+
|
|
193
|
+
- **Always pass `label` or `ariaLabel`.** Inside `FieldRow`, the row's label
|
|
194
|
+
does not reach the trigger: pass the same text as `ariaLabel`. The type does
|
|
195
|
+
not stop you from leaving all three out.
|
|
196
|
+
- **Compose `Select.*` / `Combobox.*` with a `Label` part.** Leave it out and
|
|
197
|
+
the trigger has no name. When the label is elsewhere on screen, render
|
|
198
|
+
`<Select.Label srOnly>`.
|
|
199
|
+
- Put errors in words (`FieldRow` `error`) as well as `invalid` (WCAG 3.3.1).
|
|
200
|
+
|
|
201
|
+
## Tokens
|
|
202
|
+
|
|
203
|
+
Generated from `Select.styles.ts`. Select and Combobox share these.
|
|
204
|
+
|
|
205
|
+
</En>
|
|
206
|
+
|
|
207
|
+
<Ko>
|
|
208
|
+
|
|
209
|
+
## 문구
|
|
210
|
+
|
|
211
|
+
- 라벨: 고르는 대상을 명사로 씁니다(답변 언어, 역할). "언어를 선택하세요" 같은 지시문은
|
|
212
|
+
쓰지 않습니다.
|
|
213
|
+
- 플레이스홀더: "아직 고르지 않음"이 실제로 있는 상태일 때만 씁니다. 라벨이 없으면
|
|
214
|
+
숨은 이름으로도 쓰이므로 뜻이 통하게 쓰되, 되도록 `label`이나 `ariaLabel`을 씁니다.
|
|
215
|
+
- 선택지: 짧고 같은 형식으로 쓰며, 자주 쓰는 순, 크기순, 가나다순처럼 예측할 수 있는
|
|
216
|
+
순서로 둡니다. 선택지마다 라벨을 되풀이하지 않습니다.
|
|
217
|
+
- `ComboboxField`의 `emptyText`: 무엇을 찾지 못했는지 씁니다(일치하는 그룹이
|
|
218
|
+
없습니다).
|
|
219
|
+
|
|
220
|
+
## 접근성
|
|
221
|
+
|
|
222
|
+
이 컴포넌트들이 알아서 하는 일
|
|
223
|
+
|
|
224
|
+
- **이름을 주면 그대로 씁니다.** `SelectField`와 `ComboboxField`는 트리거가 가리키는
|
|
225
|
+
라벨 부품을 항상 그립니다. `label`이면 보이게, `ariaLabel`(없으면 `placeholder`)이면
|
|
226
|
+
시각적으로 숨겨서 그립니다. 이름은 하이드레이션 뒤에 붙는 것이 아니라 서버가 보낸
|
|
227
|
+
마크업 안에 있습니다(KWCAG 5.3.4.1 레이블 제공).
|
|
228
|
+
- **키보드.** Chakra와 Zag의 목록 상자가 처리합니다. Enter, Space, 방향키로 목록을
|
|
229
|
+
열고, 방향키로 옮기고, Enter로 고르며, Escape로 닫으면 초점이 트리거로 돌아갑니다.
|
|
230
|
+
`ComboboxField`에서는 입력하면 목록이 걸러집니다.
|
|
231
|
+
- **초점과 상태.** 트리거는 초점을 받거나 열려 있는 동안 `primary.main` 테두리와 링을
|
|
232
|
+
보여 줍니다(WCAG 2.4.7). 선택된 항목은 `primary.selected` 위에 굵은 글자와 체크
|
|
233
|
+
표시로 나타나므로 색에만 기대지 않습니다(WCAG 1.4.1).
|
|
234
|
+
|
|
235
|
+
직접 챙겨야 하는 일
|
|
236
|
+
|
|
237
|
+
- **`label`이나 `ariaLabel`을 반드시 넘깁니다.** `FieldRow` 안에서는 행의 라벨이
|
|
238
|
+
트리거까지 닿지 않으므로 같은 글자를 `ariaLabel`로 넘깁니다. 셋 다 빠뜨려도 타입
|
|
239
|
+
검사에서 걸리지 않습니다.
|
|
240
|
+
- **`Select.*`나 `Combobox.*`로 조합할 때는 `Label` 부품을 넣습니다.** 빼면 트리거에
|
|
241
|
+
이름이 없습니다. 라벨이 화면의 다른 곳에 있다면 `<Select.Label srOnly>`를 씁니다.
|
|
242
|
+
- 오류는 `invalid`와 함께 `FieldRow`의 `error`로 문구를 보여 줍니다(WCAG 3.3.1).
|
|
243
|
+
|
|
244
|
+
## 토큰
|
|
245
|
+
|
|
246
|
+
`Select.styles.ts`에서 자동으로 만듭니다. Select와 Combobox가 함께 씁니다.
|
|
247
|
+
|
|
248
|
+
</Ko>
|
|
249
|
+
|
|
250
|
+
<Canvas of={SelectStories.UsageTokens} sourceState="none" />
|
|
251
|
+
|
|
252
|
+
<En>
|
|
253
|
+
|
|
254
|
+
## Related
|
|
255
|
+
|
|
256
|
+
- **Radio**: a few options, all visible.
|
|
257
|
+
- **Switch** / **Checkbox**: on or off.
|
|
258
|
+
- **SegmentedControl** / **Tabs**: switching views.
|
|
259
|
+
- **Menu**: actions, not values.
|
|
260
|
+
- **FieldRow**: label, helper and error around the field.
|
|
261
|
+
- More compositions: the _Multi Select_, _Grouped Options_ and _Custom Items_
|
|
262
|
+
stories under Components/Select and Components/Combobox.
|
|
263
|
+
|
|
264
|
+
</En>
|
|
265
|
+
|
|
266
|
+
<Ko>
|
|
267
|
+
|
|
268
|
+
## 관련 컴포넌트
|
|
269
|
+
|
|
270
|
+
- **Radio**: 몇 개 안 되는 선택지를 모두 보여 줄 때.
|
|
271
|
+
- **Switch** / **Checkbox**: 켜고 끄는 값.
|
|
272
|
+
- **SegmentedControl** / **Tabs**: 보기 전환.
|
|
273
|
+
- **Menu**: 값이 아니라 동작.
|
|
274
|
+
- **FieldRow**: 필드를 둘러싼 라벨, 도움말, 오류 문구.
|
|
275
|
+
- 조합 예시: Components/Select와 Components/Combobox 아래의 _Multi Select_,
|
|
276
|
+
_Grouped Options_, _Custom Items_ 스토리.
|
|
277
|
+
|
|
278
|
+
</Ko>
|