@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,186 @@
|
|
|
1
|
+
import { ArgTypes, Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import { En, Ko, LangToggle, Verdict } from '../../guidelines/_components/Lang';
|
|
4
|
+
import * as PaginationStories from './Pagination.stories';
|
|
5
|
+
|
|
6
|
+
<Meta of={PaginationStories} name="Usage" />
|
|
7
|
+
|
|
8
|
+
<LangToggle />
|
|
9
|
+
|
|
10
|
+
<En>
|
|
11
|
+
|
|
12
|
+
# Pagination
|
|
13
|
+
|
|
14
|
+
Previous and next buttons with a "current / last" page counter, and an
|
|
15
|
+
optional page-size select, for a list or table that is longer than one page.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
- Under a table or list that the server returns one page at a time: members,
|
|
20
|
+
audit logs, API call history, inquiries.
|
|
21
|
+
- When the user needs to come back to a known position, such as page 3 of the
|
|
22
|
+
audit log.
|
|
23
|
+
|
|
24
|
+
## When not to use
|
|
25
|
+
|
|
26
|
+
- The list fits on one page → show it all, without a pagination row.
|
|
27
|
+
- A feed the user scrolls through without looking for a position → load more
|
|
28
|
+
as they scroll.
|
|
29
|
+
- To move between steps or sections → a stepper or `Tabs`.
|
|
30
|
+
|
|
31
|
+
## Variants and what they mean
|
|
32
|
+
|
|
33
|
+
Pagination has no visual variants. The props decide what it shows:
|
|
34
|
+
|
|
35
|
+
</En>
|
|
36
|
+
|
|
37
|
+
<Ko>
|
|
38
|
+
|
|
39
|
+
# Pagination
|
|
40
|
+
|
|
41
|
+
한 페이지보다 긴 목록이나 표에 쓰는 이전·다음 버튼과 "현재 / 마지막" 쪽 번호입니다.
|
|
42
|
+
페이지당 항목 수를 고르는 선택 상자를 함께 둘 수 있습니다.
|
|
43
|
+
|
|
44
|
+
## 언제 쓰나요
|
|
45
|
+
|
|
46
|
+
- 서버가 한 페이지씩 돌려주는 표나 목록 아래: 멤버, 감사 로그, API 호출 기록, 문의.
|
|
47
|
+
- 사용자가 감사 로그 3쪽처럼 알고 있는 위치로 돌아와야 할 때.
|
|
48
|
+
|
|
49
|
+
## 언제 쓰지 않나요
|
|
50
|
+
|
|
51
|
+
- 한 페이지에 다 들어가는 목록은 페이지 줄 없이 모두 보입니다.
|
|
52
|
+
- 위치를 찾지 않고 계속 내려 보는 피드는 스크롤하면 더 불러옵니다.
|
|
53
|
+
- 단계나 구역 사이를 오가는 것은 단계 표시나 `Tabs`가 맡습니다.
|
|
54
|
+
|
|
55
|
+
## 변형과 뜻
|
|
56
|
+
|
|
57
|
+
Pagination에는 모양 변형이 없습니다. 무엇을 보일지는 속성이 정합니다.
|
|
58
|
+
|
|
59
|
+
</Ko>
|
|
60
|
+
|
|
61
|
+
<ArgTypes of={PaginationStories} include={['numTotalItems', 'itemsPerPage', 'itemsPerPageOptions', 'currentPage']} />
|
|
62
|
+
|
|
63
|
+
<En>
|
|
64
|
+
|
|
65
|
+
| Prop | Effect |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| `numTotalItems` + `itemsPerPage` | The last page is `Math.ceil(numTotalItems / itemsPerPage)`. With one page the buttons are hidden and only "1 / 1" remains. |
|
|
68
|
+
| `itemsPerPageOptions` | Adds the page-size select on the left. `itemsPerPage` is always yours to update, from `onItemsPerPageOptionChange`. |
|
|
69
|
+
| `currentPage` | Controlled. Update it from `onBack` / `onNext`, and from `onCurrentPageChange`, which fires when a larger page size puts the current page past the end. Leave it out and the component keeps the page itself. |
|
|
70
|
+
|
|
71
|
+
## Do / Don't
|
|
72
|
+
|
|
73
|
+
</En>
|
|
74
|
+
|
|
75
|
+
<Ko>
|
|
76
|
+
|
|
77
|
+
| 속성 | 효과 |
|
|
78
|
+
| --- | --- |
|
|
79
|
+
| `numTotalItems` + `itemsPerPage` | 마지막 쪽은 `Math.ceil(numTotalItems / itemsPerPage)`입니다. 한 쪽뿐이면 버튼이 사라지고 "1 / 1"만 남습니다. |
|
|
80
|
+
| `itemsPerPageOptions` | 왼쪽에 페이지당 항목 수 선택 상자를 더합니다. `itemsPerPage`는 언제나 호출부가 `onItemsPerPageOptionChange`에서 바꿔 줍니다. |
|
|
81
|
+
| `currentPage` | 제어 모드입니다. `onBack`/`onNext`에서, 그리고 페이지 크기를 키워 현재 쪽이 범위를 벗어날 때 불리는 `onCurrentPageChange`에서 값을 바꿉니다. 넘기지 않으면 컴포넌트가 직접 쪽을 기억합니다. |
|
|
82
|
+
|
|
83
|
+
## 이렇게 하세요 / 이렇게 하지 마세요
|
|
84
|
+
|
|
85
|
+
</Ko>
|
|
86
|
+
|
|
87
|
+
<Canvas of={PaginationStories.DoUnderTheList} />
|
|
88
|
+
<Verdict
|
|
89
|
+
kind="do"
|
|
90
|
+
en="Put it directly under the list it pages, full width, and keep the page when the data refetches so the row does not jump."
|
|
91
|
+
ko="넘기는 목록 바로 아래에 전체 너비로 둡니다. 데이터를 다시 불러오는 동안에도 쪽 번호를 유지해 줄이 들썩이지 않게 합니다."
|
|
92
|
+
/>
|
|
93
|
+
|
|
94
|
+
<Canvas of={PaginationStories.DontOnePage} />
|
|
95
|
+
<Verdict
|
|
96
|
+
kind="dont"
|
|
97
|
+
en="Show a pagination row for a list that fits on one page. '1 / 1' tells the user nothing."
|
|
98
|
+
ko="한 페이지에 다 들어가는 목록에 페이지 줄을 두지 마세요. '1 / 1'은 아무것도 알려 주지 않습니다."
|
|
99
|
+
/>
|
|
100
|
+
|
|
101
|
+
<En>
|
|
102
|
+
|
|
103
|
+
## Content
|
|
104
|
+
|
|
105
|
+
- The counter and the button names come from the library's translations
|
|
106
|
+
(이전 / 다음, 항목 수). Do not add your own labels beside them.
|
|
107
|
+
- If the total matters, say it above the list ("멤버 124명"), not in the
|
|
108
|
+
pagination row.
|
|
109
|
+
|
|
110
|
+
## Accessibility
|
|
111
|
+
|
|
112
|
+
What Pagination does for you:
|
|
113
|
+
|
|
114
|
+
- The previous and next buttons are `IconButton`s with translated names (이전,
|
|
115
|
+
다음), and are disabled on the first and last page (WCAG 4.1.2).
|
|
116
|
+
- The page-size select carries the same words as the visible text beside it
|
|
117
|
+
as its accessible name (WCAG 2.5.3; KWCAG 5.3.4.1).
|
|
118
|
+
- The counter is a paragraph, not a heading, so it stays out of the page
|
|
119
|
+
outline.
|
|
120
|
+
|
|
121
|
+
What you still have to do:
|
|
122
|
+
|
|
123
|
+
- **Look after focus on page change.** The counter is not a live region, and
|
|
124
|
+
on the first or last page the button the user just pressed becomes disabled
|
|
125
|
+
and drops focus. Move focus to the other button or to the top of the list
|
|
126
|
+
when that happens (WCAG 2.4.3).
|
|
127
|
+
- Keep `currentPage` at the page you requested while the data loads, so the
|
|
128
|
+
next button cannot request a page past the end.
|
|
129
|
+
|
|
130
|
+
## Tokens
|
|
131
|
+
|
|
132
|
+
The table lists the tokens set in `Pagination.tsx`.
|
|
133
|
+
|
|
134
|
+
</En>
|
|
135
|
+
|
|
136
|
+
<Ko>
|
|
137
|
+
|
|
138
|
+
## 문구
|
|
139
|
+
|
|
140
|
+
- 쪽 번호와 버튼 이름은 라이브러리 번역(이전 / 다음, 항목 수)에서 옵니다. 옆에 따로 라벨을
|
|
141
|
+
붙이지 않습니다.
|
|
142
|
+
- 전체 개수가 중요하다면 페이지 줄이 아니라 목록 위에 씁니다("멤버 124명").
|
|
143
|
+
|
|
144
|
+
## 접근성
|
|
145
|
+
|
|
146
|
+
Pagination이 알아서 하는 일
|
|
147
|
+
|
|
148
|
+
- 이전·다음 버튼은 번역된 이름(이전, 다음)이 붙은 `IconButton`이며, 첫 쪽과 마지막
|
|
149
|
+
쪽에서는 비활성이 됩니다(WCAG 4.1.2).
|
|
150
|
+
- 페이지당 항목 수 선택 상자는 옆에 보이는 문구와 같은 말을 접근 가능한 이름으로
|
|
151
|
+
갖습니다(WCAG 2.5.3, KWCAG 5.3.4.1).
|
|
152
|
+
- 쪽 번호는 제목이 아니라 문단이라 문서 개요에 끼어들지 않습니다.
|
|
153
|
+
|
|
154
|
+
직접 챙겨야 하는 일
|
|
155
|
+
|
|
156
|
+
- **쪽을 넘길 때 초점을 챙깁니다.** 쪽 번호는 라이브 영역이 아니고, 첫 쪽이나 마지막 쪽에
|
|
157
|
+
닿으면 방금 누른 버튼이 비활성이 되면서 초점을 잃습니다. 그럴 때는 반대쪽 버튼이나 목록
|
|
158
|
+
맨 위로 초점을 옮깁니다(WCAG 2.4.3).
|
|
159
|
+
- 데이터를 불러오는 동안 `currentPage`를 요청한 쪽으로 유지합니다. 그래야 다음 버튼이
|
|
160
|
+
범위 밖의 쪽을 요청하지 않습니다.
|
|
161
|
+
|
|
162
|
+
## 토큰
|
|
163
|
+
|
|
164
|
+
아래 표는 `Pagination.tsx`에서 정한 토큰입니다.
|
|
165
|
+
|
|
166
|
+
</Ko>
|
|
167
|
+
|
|
168
|
+
<Canvas of={PaginationStories.UsageTokens} sourceState="none" />
|
|
169
|
+
|
|
170
|
+
<En>
|
|
171
|
+
|
|
172
|
+
## Related
|
|
173
|
+
|
|
174
|
+
- **Table**: the usual thing Pagination sits under.
|
|
175
|
+
- **Select**: the page-size control inside it.
|
|
176
|
+
|
|
177
|
+
</En>
|
|
178
|
+
|
|
179
|
+
<Ko>
|
|
180
|
+
|
|
181
|
+
## 관련 컴포넌트
|
|
182
|
+
|
|
183
|
+
- **Table**: Pagination이 보통 그 아래에 놓이는 표.
|
|
184
|
+
- **Select**: 안에 들어 있는 페이지 크기 선택 상자.
|
|
185
|
+
|
|
186
|
+
</Ko>
|
|
@@ -2,6 +2,7 @@ import { Meta, StoryObj } from '@storybook/react';
|
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { Stack, Text } from '@chakra-ui/react';
|
|
4
4
|
|
|
5
|
+
import { FieldRow } from '../Form';
|
|
5
6
|
import { PasswordInput } from './PasswordInput';
|
|
6
7
|
|
|
7
8
|
const meta = {
|
|
@@ -54,3 +55,53 @@ export const Disabled: Story = {
|
|
|
54
55
|
defaultValue: 'password123',
|
|
55
56
|
},
|
|
56
57
|
};
|
|
58
|
+
|
|
59
|
+
// ───────────────────────── Usage-page specimens ─────────────────────────
|
|
60
|
+
// Pulled into `PasswordInput.usage.mdx` with <Canvas of={…} />. Hidden (`!dev`).
|
|
61
|
+
|
|
62
|
+
export const DoSignInPassword: Story = {
|
|
63
|
+
tags: ['!dev'],
|
|
64
|
+
parameters: { layout: 'padded' },
|
|
65
|
+
name: 'Usage / Do: labelled, with autocomplete',
|
|
66
|
+
render: () => (
|
|
67
|
+
<Stack maxW="360px">
|
|
68
|
+
<FieldRow label="비밀번호" required>
|
|
69
|
+
<PasswordInput autoComplete="current-password" />
|
|
70
|
+
</FieldRow>
|
|
71
|
+
</Stack>
|
|
72
|
+
),
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const DoRulesBeforeTyping: Story = {
|
|
76
|
+
tags: ['!dev'],
|
|
77
|
+
parameters: { layout: 'padded' },
|
|
78
|
+
name: 'Usage / Do: state the rule before the user types',
|
|
79
|
+
render: () => (
|
|
80
|
+
<Stack maxW="360px">
|
|
81
|
+
<FieldRow
|
|
82
|
+
label="새 비밀번호"
|
|
83
|
+
helperText="영문, 숫자, 특수문자를 섞어 8자 이상 입력합니다."
|
|
84
|
+
required
|
|
85
|
+
>
|
|
86
|
+
<PasswordInput autoComplete="new-password" />
|
|
87
|
+
</FieldRow>
|
|
88
|
+
</Stack>
|
|
89
|
+
),
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export const DontRuleOnlyInError: Story = {
|
|
93
|
+
tags: ['!dev'],
|
|
94
|
+
parameters: { layout: 'padded' },
|
|
95
|
+
name: "Usage / Don't: reveal the rule only as an error",
|
|
96
|
+
render: () => (
|
|
97
|
+
<Stack maxW="360px">
|
|
98
|
+
<FieldRow
|
|
99
|
+
label="새 비밀번호"
|
|
100
|
+
error="비밀번호가 올바르지 않습니다."
|
|
101
|
+
required
|
|
102
|
+
>
|
|
103
|
+
<PasswordInput autoComplete="new-password" defaultValue="abcd" />
|
|
104
|
+
</FieldRow>
|
|
105
|
+
</Stack>
|
|
106
|
+
),
|
|
107
|
+
};
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { ArgTypes, Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import { En, Ko, LangToggle, Verdict } from '../../guidelines/_components/Lang';
|
|
4
|
+
import * as PasswordInputStories from './PasswordInput.stories';
|
|
5
|
+
|
|
6
|
+
<Meta of={PasswordInputStories} name="Usage" />
|
|
7
|
+
|
|
8
|
+
<LangToggle />
|
|
9
|
+
|
|
10
|
+
<En>
|
|
11
|
+
|
|
12
|
+
# PasswordInput
|
|
13
|
+
|
|
14
|
+
An `Input` for passwords and other secrets, with an eye button that shows or
|
|
15
|
+
hides what was typed.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
- Sign-in, sign-up and password reset.
|
|
20
|
+
- A secret the user pastes once, such as an OAuth client secret or an API key.
|
|
21
|
+
|
|
22
|
+
## When not to use
|
|
23
|
+
|
|
24
|
+
- A one-time code sent by email or SMS → `PinInput`.
|
|
25
|
+
- A secret the user only needs to copy, not type → `CopyableCode`.
|
|
26
|
+
- Any value that is not secret → `Input`. Hiding it only makes it harder to
|
|
27
|
+
check.
|
|
28
|
+
|
|
29
|
+
## Props
|
|
30
|
+
|
|
31
|
+
</En>
|
|
32
|
+
|
|
33
|
+
<Ko>
|
|
34
|
+
|
|
35
|
+
# PasswordInput
|
|
36
|
+
|
|
37
|
+
비밀번호 같은 비밀 값을 받는 `Input`입니다. 눈 모양 버튼으로 입력한 내용을 보이거나
|
|
38
|
+
가립니다.
|
|
39
|
+
|
|
40
|
+
## 언제 쓰나요
|
|
41
|
+
|
|
42
|
+
- 로그인, 회원가입, 비밀번호 재설정.
|
|
43
|
+
- OAuth 클라이언트 시크릿이나 API 키처럼 한 번 붙여 넣는 비밀 값.
|
|
44
|
+
|
|
45
|
+
## 언제 쓰지 않나요
|
|
46
|
+
|
|
47
|
+
- 메일이나 문자로 받은 일회용 코드는 `PinInput`을 씁니다.
|
|
48
|
+
- 입력하지 않고 복사만 하면 되는 비밀 값은 `CopyableCode`를 씁니다.
|
|
49
|
+
- 비밀이 아닌 값은 `Input`을 씁니다. 가리면 확인하기만 어려워집니다.
|
|
50
|
+
|
|
51
|
+
## 속성
|
|
52
|
+
|
|
53
|
+
</Ko>
|
|
54
|
+
|
|
55
|
+
<ArgTypes
|
|
56
|
+
of={PasswordInputStories}
|
|
57
|
+
include={[
|
|
58
|
+
'defaultVisible',
|
|
59
|
+
'visible',
|
|
60
|
+
'onVisibleChange',
|
|
61
|
+
'visibilityIcon',
|
|
62
|
+
'rootProps',
|
|
63
|
+
]}
|
|
64
|
+
/>
|
|
65
|
+
|
|
66
|
+
<En>
|
|
67
|
+
|
|
68
|
+
Every other prop goes to the inner `Input`, so `noSpaces`, `invalid`,
|
|
69
|
+
`autoComplete` and `name` work the same way. `type` is not accepted; the
|
|
70
|
+
component sets it from `visible`.
|
|
71
|
+
|
|
72
|
+
## Do / Don't
|
|
73
|
+
|
|
74
|
+
</En>
|
|
75
|
+
|
|
76
|
+
<Ko>
|
|
77
|
+
|
|
78
|
+
나머지 속성은 모두 안쪽 `Input`에 그대로 전달되므로 `noSpaces`, `invalid`,
|
|
79
|
+
`autoComplete`, `name`이 `Input`과 똑같이 동작합니다. `type`은 받지 않으며 `visible`에
|
|
80
|
+
따라 컴포넌트가 정합니다.
|
|
81
|
+
|
|
82
|
+
## 이렇게 하세요 / 이렇게 하지 마세요
|
|
83
|
+
|
|
84
|
+
</Ko>
|
|
85
|
+
|
|
86
|
+
<Canvas of={PasswordInputStories.DoSignInPassword} />
|
|
87
|
+
<Verdict
|
|
88
|
+
kind="do"
|
|
89
|
+
en="Label it and set autoComplete: current-password to sign in, new-password to create one, so password managers fill the right field (WCAG 1.3.5)."
|
|
90
|
+
ko="라벨을 붙이고 autoComplete를 지정합니다. 로그인에는 current-password, 새로 만들 때는 new-password를 써야 비밀번호 관리자가 알맞은 칸을 채웁니다(WCAG 1.3.5)."
|
|
91
|
+
/>
|
|
92
|
+
|
|
93
|
+
<Canvas of={PasswordInputStories.DoRulesBeforeTyping} />
|
|
94
|
+
<Verdict
|
|
95
|
+
kind="do"
|
|
96
|
+
en="State the password rule in helper text before the user types."
|
|
97
|
+
ko="비밀번호 규칙은 입력하기 전에 도움말로 알려 줍니다."
|
|
98
|
+
/>
|
|
99
|
+
|
|
100
|
+
<Canvas of={PasswordInputStories.DontRuleOnlyInError} />
|
|
101
|
+
<Verdict
|
|
102
|
+
kind="dont"
|
|
103
|
+
en="Reveal the rule only after a failed attempt, in an error that does not say what is wrong."
|
|
104
|
+
ko="실패한 뒤에야 규칙을 알려 주거나, 무엇이 틀렸는지 말하지 않는 오류 문구를 쓰지 마세요."
|
|
105
|
+
/>
|
|
106
|
+
|
|
107
|
+
<En>
|
|
108
|
+
|
|
109
|
+
## Content
|
|
110
|
+
|
|
111
|
+
- Label: "Password", "New password", "Client secret". Korean: 비밀번호, 새
|
|
112
|
+
비밀번호.
|
|
113
|
+
- Do not repeat the rule in the placeholder; it disappears on the first
|
|
114
|
+
keystroke.
|
|
115
|
+
- Error text names the rule that failed: 8자 이상 입력해 주세요, not
|
|
116
|
+
비밀번호가 올바르지 않습니다.
|
|
117
|
+
|
|
118
|
+
## Accessibility
|
|
119
|
+
|
|
120
|
+
What PasswordInput does for you:
|
|
121
|
+
|
|
122
|
+
- The field itself is the `Input`: native `<input>`, labelled and wired by
|
|
123
|
+
`FieldRow` / `FormControl`.
|
|
124
|
+
- The eye button has an accessible name ("Toggle password visibility") and
|
|
125
|
+
does nothing while the field is `disabled`.
|
|
126
|
+
|
|
127
|
+
What you still have to do, and known gaps:
|
|
128
|
+
|
|
129
|
+
- **The eye button is mouse and touch only.** It has `tabIndex={-1}` and acts
|
|
130
|
+
on pointer down, so a keyboard user cannot reveal the password (WCAG
|
|
131
|
+
2.1.1). Until the component is fixed, do not make showing the password the
|
|
132
|
+
only way to check it; a confirm field or a clear error works for everyone.
|
|
133
|
+
- **Its name is English and its state is not announced.** The label is fixed
|
|
134
|
+
and there is no `aria-pressed`, so a screen reader does not say whether the
|
|
135
|
+
password is shown (WCAG 4.1.2).
|
|
136
|
+
- Label the field (WCAG 4.1.2; KWCAG 5.3.4.1 레이블 제공) and put errors in
|
|
137
|
+
`FieldRow` `error` (WCAG 3.3.1).
|
|
138
|
+
|
|
139
|
+
## Tokens
|
|
140
|
+
|
|
141
|
+
PasswordInput has no colours of its own. The field reads the `Input` tokens;
|
|
142
|
+
the eye button is a ghost `IconButton`.
|
|
143
|
+
|
|
144
|
+
## Related
|
|
145
|
+
|
|
146
|
+
- **Input**: the field it wraps, and its tokens.
|
|
147
|
+
- **PinInput**: one-time codes.
|
|
148
|
+
- **FieldRow**: label, rule and error.
|
|
149
|
+
|
|
150
|
+
</En>
|
|
151
|
+
|
|
152
|
+
<Ko>
|
|
153
|
+
|
|
154
|
+
## 문구
|
|
155
|
+
|
|
156
|
+
- 라벨: 비밀번호, 새 비밀번호, 클라이언트 시크릿.
|
|
157
|
+
- 규칙을 플레이스홀더에 되풀이하지 않습니다. 첫 글자를 입력하면 사라집니다.
|
|
158
|
+
- 오류 문구는 어긋난 규칙을 말합니다. "비밀번호가 올바르지 않습니다"가 아니라 "8자
|
|
159
|
+
이상 입력해 주세요"라고 씁니다.
|
|
160
|
+
|
|
161
|
+
## 접근성
|
|
162
|
+
|
|
163
|
+
PasswordInput이 알아서 하는 일
|
|
164
|
+
|
|
165
|
+
- 입력란은 `Input` 그대로입니다. 네이티브 `<input>`이고, `FieldRow`나 `FormControl`
|
|
166
|
+
안에서 라벨과 연결됩니다.
|
|
167
|
+
- 눈 모양 버튼에는 접근 가능한 이름("Toggle password visibility")이 있고, 입력란이
|
|
168
|
+
`disabled`이면 동작하지 않습니다.
|
|
169
|
+
|
|
170
|
+
직접 챙겨야 하는 일과 알려진 한계
|
|
171
|
+
|
|
172
|
+
- **눈 모양 버튼은 마우스와 터치로만 동작합니다.** `tabIndex={-1}`이고 포인터를 누를
|
|
173
|
+
때만 반응하므로 키보드 사용자는 비밀번호를 볼 수 없습니다(WCAG 2.1.1). 컴포넌트가
|
|
174
|
+
고쳐지기 전까지는 비밀번호 보기를 유일한 확인 방법으로 두지 마세요. 확인 입력란이나
|
|
175
|
+
분명한 오류 문구는 누구에게나 통합니다.
|
|
176
|
+
- **버튼 이름이 영어이고 상태를 알리지 않습니다.** 라벨이 고정되어 있고
|
|
177
|
+
`aria-pressed`가 없어서, 화면 낭독기는 지금 비밀번호가 보이는지 알려 주지 않습니다
|
|
178
|
+
(WCAG 4.1.2).
|
|
179
|
+
- 입력란에 라벨을 붙이고(WCAG 4.1.2, KWCAG 5.3.4.1 레이블 제공), 오류는 `FieldRow`의
|
|
180
|
+
`error`로 보여 줍니다(WCAG 3.3.1).
|
|
181
|
+
|
|
182
|
+
## 토큰
|
|
183
|
+
|
|
184
|
+
PasswordInput에는 따로 정한 색이 없습니다. 입력란은 `Input`의 토큰을 쓰고, 눈 모양
|
|
185
|
+
버튼은 ghost `IconButton`입니다.
|
|
186
|
+
|
|
187
|
+
## 관련 컴포넌트
|
|
188
|
+
|
|
189
|
+
- **Input**: 감싸고 있는 입력란과 그 토큰.
|
|
190
|
+
- **PinInput**: 일회용 코드.
|
|
191
|
+
- **FieldRow**: 라벨, 규칙, 오류 문구.
|
|
192
|
+
|
|
193
|
+
</Ko>
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react';
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
|
|
4
|
+
import { Stack } from '@chakra-ui/react';
|
|
5
|
+
|
|
6
|
+
import { T } from '../../guidelines/_components/Lang';
|
|
7
|
+
import { TokenTable } from '../../guidelines/_components/TokenTable';
|
|
8
|
+
import { FieldRow } from '../Form';
|
|
9
|
+
import { Subtext } from '../Typography';
|
|
4
10
|
import { PinInput } from '.';
|
|
5
11
|
|
|
6
12
|
const meta = {
|
|
@@ -55,3 +61,88 @@ export const Invalid: Story = {
|
|
|
55
61
|
args: { length: 5, invalid: true },
|
|
56
62
|
render: (args) => <Controlled {...args} />,
|
|
57
63
|
};
|
|
64
|
+
|
|
65
|
+
// ───────────────────────── Usage-page specimens ─────────────────────────
|
|
66
|
+
// Pulled into `PinInput.usage.mdx` with <Canvas of={…} />. Hidden (`!dev`).
|
|
67
|
+
|
|
68
|
+
export const DoSayWhereTheCodeWent: Story = {
|
|
69
|
+
tags: ['!dev'],
|
|
70
|
+
parameters: { layout: 'padded' },
|
|
71
|
+
name: 'Usage / Do: say where the code was sent',
|
|
72
|
+
render: () => {
|
|
73
|
+
const [value, setValue] = useState('');
|
|
74
|
+
return (
|
|
75
|
+
<Stack gap={2} maxW="420px">
|
|
76
|
+
<Subtext color="fg.muted">
|
|
77
|
+
name@company.com 으로 보낸 6자리 코드를 입력하세요.
|
|
78
|
+
</Subtext>
|
|
79
|
+
<PinInput
|
|
80
|
+
length={6}
|
|
81
|
+
type="numeric"
|
|
82
|
+
otp
|
|
83
|
+
value={value}
|
|
84
|
+
onChange={setValue}
|
|
85
|
+
/>
|
|
86
|
+
</Stack>
|
|
87
|
+
);
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const DontCodeWithoutContext: Story = {
|
|
92
|
+
tags: ['!dev'],
|
|
93
|
+
parameters: { layout: 'padded' },
|
|
94
|
+
name: "Usage / Don't: boxes with no context",
|
|
95
|
+
render: () => <PinInput length={6} type="numeric" />,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const DoErrorBelow: Story = {
|
|
99
|
+
tags: ['!dev'],
|
|
100
|
+
parameters: { layout: 'padded' },
|
|
101
|
+
name: 'Usage / Do: a wrong code, in words',
|
|
102
|
+
render: () => (
|
|
103
|
+
<Stack maxW="420px">
|
|
104
|
+
<FieldRow error="코드가 맞지 않습니다. 메일을 다시 확인해 주세요.">
|
|
105
|
+
<PinInput length={6} type="numeric" value="123456" invalid />
|
|
106
|
+
</FieldRow>
|
|
107
|
+
</Stack>
|
|
108
|
+
),
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/** Tokens each box reads, as written in `PinInput.tsx`. */
|
|
112
|
+
export const UsageTokens: Story = {
|
|
113
|
+
tags: ['!dev'],
|
|
114
|
+
parameters: { layout: 'padded' },
|
|
115
|
+
name: 'Usage / Tokens',
|
|
116
|
+
render: () => (
|
|
117
|
+
<TokenTable
|
|
118
|
+
rows={[
|
|
119
|
+
{ token: 'bg.surface', use: <T en="Box background" ko="칸 배경" /> },
|
|
120
|
+
{ token: 'fg.default', use: <T en="Character" ko="글자" /> },
|
|
121
|
+
{
|
|
122
|
+
token: 'border.control',
|
|
123
|
+
use: <T en="Border at rest" ko="평소 테두리" />,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
token: 'fg.icon',
|
|
127
|
+
use: <T en="Border on hover" ko="마우스를 올렸을 때 테두리" />,
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
token: 'primary.main',
|
|
131
|
+
use: <T en="Border and ring on focus" ko="초점 테두리와 링" />,
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
token: 'danger.solid',
|
|
135
|
+
use: <T en="Border when invalid" ko="오류 상태 테두리" />,
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
token: 'disabled.bg',
|
|
139
|
+
use: <T en="Disabled background" ko="비활성 배경" />,
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
token: 'disabled.fg',
|
|
143
|
+
use: <T en="Disabled text" ko="비활성 글자" />,
|
|
144
|
+
},
|
|
145
|
+
]}
|
|
146
|
+
/>
|
|
147
|
+
),
|
|
148
|
+
};
|