@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,235 @@
|
|
|
1
|
+
import { ArgTypes, Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import { En, Ko, LangToggle, Verdict } from '../../guidelines/_components/Lang';
|
|
4
|
+
import * as TableStories from './Table.stories';
|
|
5
|
+
import { Tr } from './Tr';
|
|
6
|
+
|
|
7
|
+
<Meta of={TableStories} name="Usage" />
|
|
8
|
+
|
|
9
|
+
<LangToggle />
|
|
10
|
+
|
|
11
|
+
<En>
|
|
12
|
+
|
|
13
|
+
# Table
|
|
14
|
+
|
|
15
|
+
Rows of records that share the same columns, for reading and comparing
|
|
16
|
+
values: members, usage, invoices, API keys.
|
|
17
|
+
|
|
18
|
+
`TableContainer` › `Table` › `Thead` / `Tbody` › `Tr` › `Th` / `Td`. The
|
|
19
|
+
container draws the rounded border, scrolls horizontally, and tracks scroll
|
|
20
|
+
position for sticky columns.
|
|
21
|
+
|
|
22
|
+
## When to use
|
|
23
|
+
|
|
24
|
+
- A list where each item has the same attributes and the reader compares
|
|
25
|
+
across rows: a member list, usage by model, call history.
|
|
26
|
+
- When the reader scans a column (a date, an amount, a status).
|
|
27
|
+
|
|
28
|
+
## When not to use
|
|
29
|
+
|
|
30
|
+
- Items that are read one at a time and have different shapes → `Card` in a
|
|
31
|
+
list or grid.
|
|
32
|
+
- Two to five label–value pairs about one thing → a plain stack of `Text`.
|
|
33
|
+
- A hierarchy (groups inside groups) → `Tree`.
|
|
34
|
+
- Page layout. A table is for data only.
|
|
35
|
+
|
|
36
|
+
## Row states and options
|
|
37
|
+
|
|
38
|
+
</En>
|
|
39
|
+
|
|
40
|
+
<Ko>
|
|
41
|
+
|
|
42
|
+
# Table
|
|
43
|
+
|
|
44
|
+
같은 열을 가진 기록을 행으로 늘어놓고 값을 읽고 비교하게 하는 컴포넌트입니다.
|
|
45
|
+
멤버, 사용량, 청구서, API 키 목록에 씁니다.
|
|
46
|
+
|
|
47
|
+
구조는 `TableContainer` › `Table` › `Thead` / `Tbody` › `Tr` › `Th` / `Td`입니다.
|
|
48
|
+
컨테이너가 둥근 테두리를 그리고, 가로 스크롤을 맡고, 고정 열을 위해 스크롤 위치를
|
|
49
|
+
추적합니다.
|
|
50
|
+
|
|
51
|
+
## 언제 쓰나요
|
|
52
|
+
|
|
53
|
+
- 항목마다 같은 속성이 있고 행끼리 비교해 읽는 목록: 멤버 목록, 모델별 사용량, 호출
|
|
54
|
+
기록.
|
|
55
|
+
- 읽는 사람이 한 열(날짜, 금액, 상태)을 훑어볼 때.
|
|
56
|
+
|
|
57
|
+
## 언제 쓰지 않나요
|
|
58
|
+
|
|
59
|
+
- 하나씩 읽는 항목이고 모양이 서로 다르다면 목록이나 격자 안의 `Card`를 씁니다.
|
|
60
|
+
- 한 대상의 라벨과 값 두세 쌍이라면 `Text`를 쌓아서 보여 줍니다.
|
|
61
|
+
- 그룹 안의 그룹 같은 계층은 `Tree`를 씁니다.
|
|
62
|
+
- 페이지 레이아웃에는 쓰지 않습니다. 표는 데이터에만 씁니다.
|
|
63
|
+
|
|
64
|
+
## 행 상태와 옵션
|
|
65
|
+
|
|
66
|
+
</Ko>
|
|
67
|
+
|
|
68
|
+
<ArgTypes of={Tr} include={['state']} />
|
|
69
|
+
|
|
70
|
+
<En>
|
|
71
|
+
|
|
72
|
+
| Option | Means | Use for |
|
|
73
|
+
| --- | --- | --- |
|
|
74
|
+
| `<Tr state="selected">` | The row is part of the current selection (`primary.selected`) | Rows ticked for a bulk action |
|
|
75
|
+
| `<Tr state="invalid">` | Something in the row is wrong (`bg.invalid.subtle`) | A failed import row |
|
|
76
|
+
| `<Tr state="highlighted">` | Draw the eye to one row (`bg.highlighted`) | The row just added or edited |
|
|
77
|
+
| `onClick` / `tabIndex` / `role="button"` on `Tr` | The row is clickable; it gets the pointer, `primary.wash` hover and a focus outline | Opening a detail drawer |
|
|
78
|
+
| `<Thead sticky>` | The header stays at the top of the scroll area | Long lists in a fixed-height container |
|
|
79
|
+
| `isSticky` + `stickyDirection` + `stickyIndex` on `Th`/`Td` | The column stays put while the table scrolls sideways | A name column on a wide table |
|
|
80
|
+
| `Td wrap` | Long text wraps instead of being cut off | Addresses, descriptions |
|
|
81
|
+
| `ExpandingTr` | A row with a detail row under it, opened by `isExpanded` | Error details for one row |
|
|
82
|
+
|
|
83
|
+
## Do / Don't
|
|
84
|
+
|
|
85
|
+
</En>
|
|
86
|
+
|
|
87
|
+
<Ko>
|
|
88
|
+
|
|
89
|
+
| 옵션 | 뜻 | 쓰는 곳 |
|
|
90
|
+
| --- | --- | --- |
|
|
91
|
+
| `<Tr state="selected">` | 현재 선택에 포함된 행(`primary.selected`) | 일괄 작업을 위해 체크한 행 |
|
|
92
|
+
| `<Tr state="invalid">` | 행 안의 무언가가 잘못됨(`bg.invalid.subtle`) | 가져오기에 실패한 행 |
|
|
93
|
+
| `<Tr state="highlighted">` | 한 행으로 눈길을 끎(`bg.highlighted`) | 방금 추가하거나 고친 행 |
|
|
94
|
+
| `Tr`의 `onClick` / `tabIndex` / `role="button"` | 누를 수 있는 행. 포인터, `primary.wash` 호버, 초점 테두리가 생김 | 상세 서랍 열기 |
|
|
95
|
+
| `<Thead sticky>` | 스크롤해도 머리글이 위에 남음 | 높이가 정해진 영역 안의 긴 목록 |
|
|
96
|
+
| `Th`/`Td`의 `isSticky` + `stickyDirection` + `stickyIndex` | 표를 옆으로 스크롤해도 그 열은 그대로 있음 | 넓은 표의 이름 열 |
|
|
97
|
+
| `Td wrap` | 긴 글을 자르지 않고 줄바꿈함 | 주소, 설명 |
|
|
98
|
+
| `ExpandingTr` | 아래에 상세 행이 붙은 행. `isExpanded`로 엶 | 한 행의 오류 상세 |
|
|
99
|
+
|
|
100
|
+
## 이렇게 하세요 / 이렇게 하지 마세요
|
|
101
|
+
|
|
102
|
+
</Ko>
|
|
103
|
+
|
|
104
|
+
<Canvas of={TableStories.DoNumbersAligned} />
|
|
105
|
+
<Verdict
|
|
106
|
+
kind="do"
|
|
107
|
+
en="Put a real link in the name cell, and align numbers to the end with tabular figures so they line up."
|
|
108
|
+
ko="이름 칸에는 실제 링크를 두고, 숫자는 끝에 맞추고 고정폭 숫자를 써서 자릿수가 맞게 합니다."
|
|
109
|
+
/>
|
|
110
|
+
|
|
111
|
+
<Canvas of={TableStories.DoStateWithWords} />
|
|
112
|
+
<Verdict
|
|
113
|
+
kind="do"
|
|
114
|
+
en="Back a row state with words in a cell. The tint draws the eye; the Badge says what is wrong."
|
|
115
|
+
ko="행 상태는 칸 안의 문구로 함께 알립니다. 배경색은 눈길을 끌고, Badge가 무엇이 잘못됐는지 말합니다."
|
|
116
|
+
/>
|
|
117
|
+
|
|
118
|
+
<Canvas of={TableStories.DontStateColourOnly} />
|
|
119
|
+
<Verdict
|
|
120
|
+
kind="dont"
|
|
121
|
+
en="Rely on the row tint alone. A screen reader does not announce it, and in some modes it is hard to see at all."
|
|
122
|
+
ko="행 배경색만으로 알리지 마세요. 화면 낭독기는 배경색을 읽지 않고, 모드에 따라 거의 보이지 않기도 합니다."
|
|
123
|
+
/>
|
|
124
|
+
|
|
125
|
+
<En>
|
|
126
|
+
|
|
127
|
+
## Content
|
|
128
|
+
|
|
129
|
+
- Column headers are short nouns: 이름, 그룹, 사용 크레딧. Put the unit in
|
|
130
|
+
the header, not in every cell.
|
|
131
|
+
- Numbers and amounts align to the end (`textAlign="end"`); text aligns to the
|
|
132
|
+
start.
|
|
133
|
+
- An empty value is "—", not a blank cell, so the reader knows nothing is
|
|
134
|
+
missing from the page.
|
|
135
|
+
- Keep a status in its own column with a `Badge`, rather than colouring a
|
|
136
|
+
whole row.
|
|
137
|
+
|
|
138
|
+
## Accessibility
|
|
139
|
+
|
|
140
|
+
What Table does for you:
|
|
141
|
+
|
|
142
|
+
- It renders native table elements (`<table>`, `<th>`, `<td>`), so screen
|
|
143
|
+
readers announce row and column positions.
|
|
144
|
+
- A clickable `Tr` gets a pointer, a hover tint and a 2px inset focus
|
|
145
|
+
outline when focused from the keyboard. Static rows never highlight.
|
|
146
|
+
- Sticky header and sticky columns get an opaque background, so text never
|
|
147
|
+
shows through.
|
|
148
|
+
|
|
149
|
+
What you still have to do:
|
|
150
|
+
|
|
151
|
+
- **A clickable row is not a button by itself.** `Tr` only styles it. Give
|
|
152
|
+
it `tabIndex={0}` and handle Enter in `onKeyDown` (WCAG 2.1.1), or better,
|
|
153
|
+
put a real link or button in the row and let that be the target (WCAG
|
|
154
|
+
4.1.2). Never put a button inside a row that is also `role="button"`
|
|
155
|
+
(nested interactive controls, see `ACCESSIBILITY.md` §3).
|
|
156
|
+
- **Row states need words** (WCAG 1.4.1). `state` only tints the row.
|
|
157
|
+
- **Name icon-only buttons in cells**: `aria-label` on the `IconButton`
|
|
158
|
+
(WCAG 4.1.2). For an `ExpandingTr` toggle, also pass `aria-expanded`.
|
|
159
|
+
- Give the table a caption or a heading next to it so it has a name
|
|
160
|
+
(WCAG 1.3.1).
|
|
161
|
+
- A cell cut off with an ellipsis hides content. Use `wrap`, or make the full
|
|
162
|
+
value available another way (WCAG 1.4.10).
|
|
163
|
+
|
|
164
|
+
## Tokens
|
|
165
|
+
|
|
166
|
+
Read from the table slot recipe (`theme/recipes/table.ts`) and the sticky
|
|
167
|
+
styles in `Table.styles.ts`.
|
|
168
|
+
|
|
169
|
+
</En>
|
|
170
|
+
|
|
171
|
+
<Ko>
|
|
172
|
+
|
|
173
|
+
## 문구
|
|
174
|
+
|
|
175
|
+
- 열 머리글은 짧은 명사로 씁니다: 이름, 그룹, 사용 크레딧. 단위는 칸마다 쓰지 않고
|
|
176
|
+
머리글에 씁니다.
|
|
177
|
+
- 숫자와 금액은 끝에 맞추고(`textAlign="end"`), 글은 앞에 맞춥니다.
|
|
178
|
+
- 값이 없으면 빈칸 대신 "—"를 써서, 화면에서 빠진 것이 없다는 것을 알립니다.
|
|
179
|
+
- 상태는 행 전체에 색을 칠하지 않고 `Badge`로 따로 열을 둡니다.
|
|
180
|
+
|
|
181
|
+
## 접근성
|
|
182
|
+
|
|
183
|
+
Table이 알아서 하는 일
|
|
184
|
+
|
|
185
|
+
- 기본 표 요소(`<table>`, `<th>`, `<td>`)로 그리므로 화면 낭독기가 행과 열의 위치를
|
|
186
|
+
읽어 줍니다.
|
|
187
|
+
- 누를 수 있는 `Tr`에는 포인터, 호버 배경, 키보드 초점 시 안쪽 2px 테두리가 생깁니다.
|
|
188
|
+
누를 수 없는 행은 강조되지 않습니다.
|
|
189
|
+
- 고정 머리글과 고정 열은 불투명한 배경을 가지므로 뒤의 글자가 비치지 않습니다.
|
|
190
|
+
|
|
191
|
+
직접 챙겨야 하는 일
|
|
192
|
+
|
|
193
|
+
- **누를 수 있는 행이 저절로 버튼이 되지는 않습니다.** `Tr`은 모양만 바꿉니다.
|
|
194
|
+
`tabIndex={0}`를 주고 `onKeyDown`에서 Enter를 처리하거나(WCAG 2.1.1), 행 안에 실제
|
|
195
|
+
링크나 버튼을 두고 그것을 누르게 하는 편이 낫습니다(WCAG 4.1.2). `role="button"`인
|
|
196
|
+
행 안에 다시 버튼을 넣지 않습니다(상호작용 요소 중첩, `ACCESSIBILITY.md` 3절).
|
|
197
|
+
- **행 상태는 문구로도 알립니다**(WCAG 1.4.1). `state`는 배경색만 바꿉니다.
|
|
198
|
+
- **칸 안의 아이콘 버튼에는 이름을 붙입니다.** `IconButton`에 `aria-label`을 줍니다
|
|
199
|
+
(WCAG 4.1.2). `ExpandingTr`을 여닫는 버튼에는 `aria-expanded`도 줍니다.
|
|
200
|
+
- 표에 캡션을 달거나 옆에 제목을 두어 이름을 붙입니다(WCAG 1.3.1).
|
|
201
|
+
- 말줄임표로 잘린 칸은 내용을 숨깁니다. `wrap`을 쓰거나 전체 값을 다른 방법으로
|
|
202
|
+
볼 수 있게 합니다(WCAG 1.4.10).
|
|
203
|
+
|
|
204
|
+
## 토큰
|
|
205
|
+
|
|
206
|
+
표 슬롯 레시피(`theme/recipes/table.ts`)와 `Table.styles.ts`의 고정 열 스타일에서
|
|
207
|
+
읽습니다.
|
|
208
|
+
|
|
209
|
+
</Ko>
|
|
210
|
+
|
|
211
|
+
<Canvas of={TableStories.UsageTokens} sourceState="none" />
|
|
212
|
+
|
|
213
|
+
<En>
|
|
214
|
+
|
|
215
|
+
## Related
|
|
216
|
+
|
|
217
|
+
- **Badge**: a status in its own column.
|
|
218
|
+
- **Pagination**: long lists split into pages.
|
|
219
|
+
- **Checkbox**: row selection for bulk actions, with `state="selected"`.
|
|
220
|
+
- **Tree**: hierarchical data.
|
|
221
|
+
- **Card**: items with different shapes.
|
|
222
|
+
|
|
223
|
+
</En>
|
|
224
|
+
|
|
225
|
+
<Ko>
|
|
226
|
+
|
|
227
|
+
## 관련 컴포넌트
|
|
228
|
+
|
|
229
|
+
- **Badge**: 따로 둔 열의 상태 표시.
|
|
230
|
+
- **Pagination**: 긴 목록을 쪽으로 나눕니다.
|
|
231
|
+
- **Checkbox**: 일괄 작업을 위한 행 선택. `state="selected"`와 함께 씁니다.
|
|
232
|
+
- **Tree**: 계층이 있는 데이터.
|
|
233
|
+
- **Card**: 모양이 서로 다른 항목.
|
|
234
|
+
|
|
235
|
+
</Ko>
|
|
@@ -2,7 +2,10 @@ import { useState } from 'react';
|
|
|
2
2
|
import { Button, CloseButton, Heading, Text } from '@chakra-ui/react';
|
|
3
3
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
4
4
|
|
|
5
|
+
import { T } from '../../guidelines/_components/Lang';
|
|
6
|
+
import { TokenTable } from '../../guidelines/_components/TokenTable';
|
|
5
7
|
import { Tab } from '@/components/Tabs/Tab/Tab';
|
|
8
|
+
import { TAB_RAMP } from '@/components/Tabs/Tab/Tab.styles';
|
|
6
9
|
import { TabList } from '@/components/Tabs/TabList';
|
|
7
10
|
import { TabPanel } from '@/components/Tabs/TabPanel';
|
|
8
11
|
import { TabPanels } from '@/components/Tabs/TabPanels';
|
|
@@ -260,3 +263,86 @@ export const DynamicTabs: Story = {
|
|
|
260
263
|
);
|
|
261
264
|
},
|
|
262
265
|
};
|
|
266
|
+
|
|
267
|
+
// ───────────────────────── Usage-page specimens ─────────────────────────
|
|
268
|
+
// Pulled into `Tabs.usage.mdx` with <Canvas of={…} />. Hidden from the
|
|
269
|
+
// sidebar (`!dev`).
|
|
270
|
+
|
|
271
|
+
export const DoSectionsOfOnePlace: Story = {
|
|
272
|
+
tags: ['!dev'],
|
|
273
|
+
parameters: { layout: 'padded' },
|
|
274
|
+
name: 'Usage / Do: sections of one place, with a named list',
|
|
275
|
+
render: () => (
|
|
276
|
+
<Tabs defaultValue="credit">
|
|
277
|
+
<TabList aria-label="그룹 설정">
|
|
278
|
+
<Tab value="credit">크레딧</Tab>
|
|
279
|
+
<Tab value="security">보안</Tab>
|
|
280
|
+
<Tab value="notice">공지</Tab>
|
|
281
|
+
</TabList>
|
|
282
|
+
<TabPanel value="credit" pt={4}>
|
|
283
|
+
<Text>이 그룹의 월간 크레딧 한도와 사용량입니다.</Text>
|
|
284
|
+
</TabPanel>
|
|
285
|
+
<TabPanel value="security" pt={4}>
|
|
286
|
+
<Text>로그인과 파일 업로드 정책입니다.</Text>
|
|
287
|
+
</TabPanel>
|
|
288
|
+
<TabPanel value="notice" pt={4}>
|
|
289
|
+
<Text>이 그룹에만 보이는 공지입니다.</Text>
|
|
290
|
+
</TabPanel>
|
|
291
|
+
</Tabs>
|
|
292
|
+
),
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
export const DontTabsAsSteps: Story = {
|
|
296
|
+
tags: ['!dev'],
|
|
297
|
+
parameters: { layout: 'padded' },
|
|
298
|
+
name: "Usage / Don't: tabs as the steps of a flow",
|
|
299
|
+
render: () => (
|
|
300
|
+
<Tabs defaultValue="step1">
|
|
301
|
+
<TabList>
|
|
302
|
+
<Tab value="step1">1. 기본 정보</Tab>
|
|
303
|
+
<Tab value="step2">2. 모델 선택</Tab>
|
|
304
|
+
<Tab value="step3">3. 확인</Tab>
|
|
305
|
+
</TabList>
|
|
306
|
+
<TabPanel value="step1" pt={4}>
|
|
307
|
+
<Text>이름과 설명을 입력하세요.</Text>
|
|
308
|
+
</TabPanel>
|
|
309
|
+
<TabPanel value="step2" pt={4}>
|
|
310
|
+
<Text>모델을 고르세요.</Text>
|
|
311
|
+
</TabPanel>
|
|
312
|
+
<TabPanel value="step3" pt={4}>
|
|
313
|
+
<Text>입력한 내용을 확인하세요.</Text>
|
|
314
|
+
</TabPanel>
|
|
315
|
+
</Tabs>
|
|
316
|
+
),
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
/** Tokens a tab reads: the selected ramp from `TAB_RAMP` in `Tab.styles.ts`, the rest from `Tab.tsx` and `TabList.tsx`. */
|
|
320
|
+
export const UsageTokens: Story = {
|
|
321
|
+
tags: ['!dev'],
|
|
322
|
+
parameters: { layout: 'padded' },
|
|
323
|
+
name: 'Usage / Tokens',
|
|
324
|
+
render: () => (
|
|
325
|
+
<TokenTable
|
|
326
|
+
rows={[
|
|
327
|
+
{
|
|
328
|
+
token: TAB_RAMP.label,
|
|
329
|
+
use: <T en="Selected tab · label" ko="선택된 탭 · 글자" />,
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
token: TAB_RAMP.indicator,
|
|
333
|
+
use: <T en="Selected tab · indicator" ko="선택된 탭 · 표시 막대" />,
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
token: 'fg.muted',
|
|
337
|
+
use: <T en="Other tabs · label" ko="다른 탭 · 글자" />,
|
|
338
|
+
},
|
|
339
|
+
{ token: 'primary.wash', use: <T en="Hover" ko="마우스 올림" /> },
|
|
340
|
+
{
|
|
341
|
+
token: 'bg.muted',
|
|
342
|
+
use: <T en="Vertical · selected fill" ko="세로 탭 · 선택 배경" />,
|
|
343
|
+
},
|
|
344
|
+
{ token: 'border.subtle', use: <T en="List rule" ko="목록 아래 선" /> },
|
|
345
|
+
]}
|
|
346
|
+
/>
|
|
347
|
+
),
|
|
348
|
+
};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { ArgTypes, Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import { En, Ko, LangToggle, Verdict } from '../../guidelines/_components/Lang';
|
|
4
|
+
import * as TabsStories from './Tabs.stories';
|
|
5
|
+
|
|
6
|
+
<Meta of={TabsStories} name="Usage" />
|
|
7
|
+
|
|
8
|
+
<LangToggle />
|
|
9
|
+
|
|
10
|
+
<En>
|
|
11
|
+
|
|
12
|
+
# Tabs
|
|
13
|
+
|
|
14
|
+
A row (or column) of labels that switches between sections of the same place.
|
|
15
|
+
One section shows at a time.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
- To split one object's settings or data into sections: a group's 크레딧,
|
|
20
|
+
보안 and 공지; a chatbot's 설정 and 분석.
|
|
21
|
+
- To switch between dashboards of the same scope, such as usage by model and
|
|
22
|
+
usage by user.
|
|
23
|
+
- For a long settings page in a side panel, with `orientation="vertical"`.
|
|
24
|
+
|
|
25
|
+
## When not to use
|
|
26
|
+
|
|
27
|
+
- To change how the same content is shown, or to filter it (일/주/월, 목록/카드)
|
|
28
|
+
→ `SegmentedControl`. Tabs change *what* you are looking at, not how.
|
|
29
|
+
- For the steps of a flow the user must complete in order → a stepper or a
|
|
30
|
+
sequence of pages. Tabs let the user jump ahead.
|
|
31
|
+
- To move to another page of the app → navigation links or `Breadcrumb`.
|
|
32
|
+
- For two or three short panels the user needs side by side → show them on
|
|
33
|
+
the page.
|
|
34
|
+
|
|
35
|
+
## Variants and what they mean
|
|
36
|
+
|
|
37
|
+
Tabs has one look. A selected tab is a *place*, not a value, so it is marked
|
|
38
|
+
with ink and weight, not with a brand or status colour. `orientation` decides
|
|
39
|
+
the layout:
|
|
40
|
+
|
|
41
|
+
</En>
|
|
42
|
+
|
|
43
|
+
<Ko>
|
|
44
|
+
|
|
45
|
+
# Tabs
|
|
46
|
+
|
|
47
|
+
같은 곳의 여러 구역을 오가게 하는 라벨 한 줄(또는 한 열)입니다. 한 번에 한 구역만
|
|
48
|
+
보입니다.
|
|
49
|
+
|
|
50
|
+
## 언제 쓰나요
|
|
51
|
+
|
|
52
|
+
- 한 대상의 설정이나 데이터를 구역으로 나눌 때: 그룹의 크레딧·보안·공지, 챗봇의 설정·분석.
|
|
53
|
+
- 같은 범위의 대시보드 여러 개를 오갈 때: 모델별 사용량, 사용자별 사용량.
|
|
54
|
+
- 사이드 패널의 긴 설정 화면을 나눌 때는 `orientation="vertical"`을 씁니다.
|
|
55
|
+
|
|
56
|
+
## 언제 쓰지 않나요
|
|
57
|
+
|
|
58
|
+
- 같은 내용을 보는 방식을 바꾸거나 거를 때(일/주/월, 목록/카드)는 `SegmentedControl`을
|
|
59
|
+
씁니다. 탭은 무엇을 보는지를 바꾸고, 어떻게 보는지를 바꾸지 않습니다.
|
|
60
|
+
- 차례대로 끝내야 하는 흐름의 단계에는 단계 표시나 이어지는 페이지를 씁니다. 탭은 사용자가
|
|
61
|
+
단계를 건너뛰게 둡니다.
|
|
62
|
+
- 앱의 다른 페이지로 옮겨 가는 것은 내비게이션 링크나 `Breadcrumb`가 맡습니다.
|
|
63
|
+
- 나란히 봐야 하는 짧은 패널 두세 개는 탭에 숨기지 말고 페이지에 그대로 보입니다.
|
|
64
|
+
|
|
65
|
+
## 변형과 뜻
|
|
66
|
+
|
|
67
|
+
Tabs의 모양은 하나입니다. 선택된 탭은 값이 아니라 지금 있는 곳이므로, 브랜드색이나
|
|
68
|
+
상태색이 아니라 진한 글자와 굵기로 표시합니다. 배치는 `orientation`이 정합니다.
|
|
69
|
+
|
|
70
|
+
</Ko>
|
|
71
|
+
|
|
72
|
+
<ArgTypes of={TabsStories} include={['orientation', 'defaultValue', 'value', 'activationMode']} />
|
|
73
|
+
|
|
74
|
+
<En>
|
|
75
|
+
|
|
76
|
+
| `orientation` | Selected tab | Use for |
|
|
77
|
+
| --- | --- | --- |
|
|
78
|
+
| `horizontal` (default) | `fg.emphasized` label, semibold, with a 2px `primary.main` underline | Sections across the top of a page or panel |
|
|
79
|
+
| `vertical` | `bg.muted` fill, bold, with a 2px `primary.main` bar on the leading edge | A long settings page in a narrow side column |
|
|
80
|
+
|
|
81
|
+
## Do / Don't
|
|
82
|
+
|
|
83
|
+
</En>
|
|
84
|
+
|
|
85
|
+
<Ko>
|
|
86
|
+
|
|
87
|
+
| `orientation` | 선택된 탭 | 쓰는 곳 |
|
|
88
|
+
| --- | --- | --- |
|
|
89
|
+
| `horizontal` (기본) | `fg.emphasized` 글자를 semibold로 쓰고 아래에 2px `primary.main` 밑줄 | 페이지나 패널 위쪽의 구역 |
|
|
90
|
+
| `vertical` | `bg.muted` 배경에 bold, 앞쪽 가장자리에 2px `primary.main` 막대 | 좁은 옆 열에 둔 긴 설정 화면 |
|
|
91
|
+
|
|
92
|
+
## 이렇게 하세요 / 이렇게 하지 마세요
|
|
93
|
+
|
|
94
|
+
</Ko>
|
|
95
|
+
|
|
96
|
+
<Canvas of={TabsStories.DoSectionsOfOnePlace} />
|
|
97
|
+
<Verdict
|
|
98
|
+
kind="do"
|
|
99
|
+
en="Use short nouns for sections of one place, and name the list with aria-label ('그룹 설정')."
|
|
100
|
+
ko="한 곳의 구역에는 짧은 명사를 쓰고, 탭 목록에 aria-label('그룹 설정')로 이름을 붙입니다."
|
|
101
|
+
/>
|
|
102
|
+
|
|
103
|
+
<Canvas of={TabsStories.DontTabsAsSteps} />
|
|
104
|
+
<Verdict
|
|
105
|
+
kind="dont"
|
|
106
|
+
en="Number tabs as the steps of a flow. Nothing stops the user from opening step 3 first."
|
|
107
|
+
ko="탭에 번호를 붙여 흐름의 단계로 쓰지 마세요. 사용자가 3단계를 먼저 열어도 막을 방법이 없습니다."
|
|
108
|
+
/>
|
|
109
|
+
|
|
110
|
+
<En>
|
|
111
|
+
|
|
112
|
+
## Content
|
|
113
|
+
|
|
114
|
+
- One or two words, a noun: "크레딧", "보안", "사용자별". No full stop and no
|
|
115
|
+
icons alone.
|
|
116
|
+
- Keep labels the same length class; one long label next to short ones reads as
|
|
117
|
+
a different kind of tab.
|
|
118
|
+
- Stay under about six horizontal tabs. More than that, use `vertical` or split
|
|
119
|
+
the page.
|
|
120
|
+
- Do not put a count in the label unless it changes what the user does next.
|
|
121
|
+
|
|
122
|
+
## Accessibility
|
|
123
|
+
|
|
124
|
+
What Tabs does for you:
|
|
125
|
+
|
|
126
|
+
- `TabList` is `role="tablist"`, each `Tab` is `role="tab"` with
|
|
127
|
+
`aria-selected`, and each `TabPanel` is `role="tabpanel"` labelled by its tab
|
|
128
|
+
(WCAG 4.1.2).
|
|
129
|
+
- Keyboard (WCAG 2.1.1): `Tab` lands on the selected tab and then moves on; the
|
|
130
|
+
arrow keys move between tabs and wrap at the ends, `Home` / `End` jump to the
|
|
131
|
+
first and last. With the default `activationMode="automatic"` the panel
|
|
132
|
+
changes as focus moves.
|
|
133
|
+
- Each `Tab` is a `Button`, so it shows the focus ring (WCAG 2.4.7). The
|
|
134
|
+
selected label is `fg.emphasized`, at least 13:1 on every surface it can land
|
|
135
|
+
on (WCAG 1.4.3), and the underline is a second cue beside weight (WCAG
|
|
136
|
+
1.4.1).
|
|
137
|
+
|
|
138
|
+
What you still have to do:
|
|
139
|
+
|
|
140
|
+
- **Name the list.** Pass `aria-label` to `TabList` when there is no visible
|
|
141
|
+
heading right above it, or `aria-labelledby` pointing at the heading.
|
|
142
|
+
- Give every `Tab` and `TabPanel` the same `value`. Both throw without one.
|
|
143
|
+
- Put only phrasing content inside a `Tab`: it renders a `<button>`, so no
|
|
144
|
+
`<div>` or `<p>` inside (KWCAG 5.4.1.1, see `ACCESSIBILITY.md`).
|
|
145
|
+
- If switching a panel is slow (it fetches data), use
|
|
146
|
+
`activationMode="manual"` so arrowing across the list does not fire a request
|
|
147
|
+
per tab.
|
|
148
|
+
|
|
149
|
+
## Tokens
|
|
150
|
+
|
|
151
|
+
The selected ramp is `TAB_RAMP` in `Tab.styles.ts`; the other tokens are set in
|
|
152
|
+
`Tab.tsx` and `TabList.tsx`.
|
|
153
|
+
|
|
154
|
+
</En>
|
|
155
|
+
|
|
156
|
+
<Ko>
|
|
157
|
+
|
|
158
|
+
## 문구
|
|
159
|
+
|
|
160
|
+
- 한두 단어의 명사로 씁니다. "크레딧", "보안", "사용자별". 마침표를 찍지 않고, 아이콘만
|
|
161
|
+
두지 않습니다.
|
|
162
|
+
- 라벨 길이를 비슷하게 맞춥니다. 짧은 라벨 사이의 긴 라벨 하나는 다른 종류의 탭처럼
|
|
163
|
+
보입니다.
|
|
164
|
+
- 가로 탭은 여섯 개 안쪽으로 둡니다. 더 많으면 `vertical`을 쓰거나 페이지를 나눕니다.
|
|
165
|
+
- 다음 행동을 바꾸는 경우가 아니면 라벨에 개수를 넣지 않습니다.
|
|
166
|
+
|
|
167
|
+
## 접근성
|
|
168
|
+
|
|
169
|
+
Tabs가 알아서 하는 일
|
|
170
|
+
|
|
171
|
+
- `TabList`는 `role="tablist"`, 각 `Tab`은 `aria-selected`가 붙은 `role="tab"`, 각
|
|
172
|
+
`TabPanel`은 자기 탭으로 이름이 붙는 `role="tabpanel"`입니다(WCAG 4.1.2).
|
|
173
|
+
- 키보드(WCAG 2.1.1): `Tab`을 누르면 선택된 탭에 닿고, 한 번 더 누르면 목록을 벗어납니다. 방향키로 탭 사이를
|
|
174
|
+
옮기고 끝에서는 처음으로 돌아가며, `Home`/`End`로 처음과 끝으로 갑니다. 기본값인
|
|
175
|
+
`activationMode="automatic"`에서는 초점이 옮겨 가면 패널도 바뀝니다.
|
|
176
|
+
- 각 `Tab`은 `Button`이라 초점 테두리가 보입니다(WCAG 2.4.7). 선택된 글자는
|
|
177
|
+
`fg.emphasized`로, 놓일 수 있는 어느 면에서도 13:1 이상입니다(WCAG 1.4.3). 굵기 말고도
|
|
178
|
+
밑줄이 한 번 더 알려 줍니다(WCAG 1.4.1).
|
|
179
|
+
|
|
180
|
+
직접 챙겨야 하는 일
|
|
181
|
+
|
|
182
|
+
- **탭 목록에 이름을 붙입니다.** 바로 위에 보이는 제목이 없다면 `TabList`에
|
|
183
|
+
`aria-label`을, 제목이 있다면 그 제목을 가리키는 `aria-labelledby`를 넘깁니다.
|
|
184
|
+
- 모든 `Tab`과 `TabPanel`에 짝이 맞는 `value`를 줍니다. 없으면 둘 다 오류를 냅니다.
|
|
185
|
+
- `Tab` 안에는 phrasing content만 넣습니다. `<button>`으로 그려지므로 안에 `<div>`나
|
|
186
|
+
`<p>`를 넣지 않습니다(KWCAG 5.4.1.1, `ACCESSIBILITY.md` 참고).
|
|
187
|
+
- 패널을 바꿀 때 데이터를 불러와 느리다면 `activationMode="manual"`을 씁니다. 그래야
|
|
188
|
+
방향키로 탭을 훑을 때마다 요청이 나가지 않습니다.
|
|
189
|
+
|
|
190
|
+
## 토큰
|
|
191
|
+
|
|
192
|
+
선택 상태의 색은 `Tab.styles.ts`의 `TAB_RAMP`에서, 나머지 토큰은 `Tab.tsx`와
|
|
193
|
+
`TabList.tsx`에서 정합니다.
|
|
194
|
+
|
|
195
|
+
</Ko>
|
|
196
|
+
|
|
197
|
+
<Canvas of={TabsStories.UsageTokens} sourceState="none" />
|
|
198
|
+
|
|
199
|
+
<En>
|
|
200
|
+
|
|
201
|
+
## Related
|
|
202
|
+
|
|
203
|
+
- **SegmentedControl**: change how the same content is shown.
|
|
204
|
+
- **Breadcrumb**: where this page sits in a hierarchy.
|
|
205
|
+
- **Foundations/Brand & colour usage**: why a selected place is ink, not
|
|
206
|
+
colour.
|
|
207
|
+
|
|
208
|
+
</En>
|
|
209
|
+
|
|
210
|
+
<Ko>
|
|
211
|
+
|
|
212
|
+
## 관련 컴포넌트
|
|
213
|
+
|
|
214
|
+
- **SegmentedControl**: 같은 내용을 보는 방식 바꾸기.
|
|
215
|
+
- **Breadcrumb**: 이 페이지가 계층의 어디에 있는지.
|
|
216
|
+
- **Foundations/Brand & colour usage**: 선택된 곳을 색이 아니라 진한 글자로 표시하는
|
|
217
|
+
이유.
|
|
218
|
+
|
|
219
|
+
</Ko>
|