@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,142 @@
|
|
|
1
|
+
import { ArgTypes, Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import { En, Ko, LangToggle, Verdict } from '../../guidelines/_components/Lang';
|
|
4
|
+
import * as MasonryStories from './Masonry.stories';
|
|
5
|
+
|
|
6
|
+
<Meta of={MasonryStories} name="Usage" />
|
|
7
|
+
|
|
8
|
+
<LangToggle />
|
|
9
|
+
|
|
10
|
+
<En>
|
|
11
|
+
|
|
12
|
+
# Masonry
|
|
13
|
+
|
|
14
|
+
Equal-width columns that pack items of different heights without gaps,
|
|
15
|
+
re-measuring as items resize. FactChat uses it for the model and voice menus.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
- Unordered groups or cards whose heights differ a lot, where a grid would
|
|
20
|
+
leave holes.
|
|
21
|
+
|
|
22
|
+
## When not to use
|
|
23
|
+
|
|
24
|
+
- Items with similar heights → `SimpleGrid` / `Grid`, which keeps row order.
|
|
25
|
+
- Anything with an order (steps, a ranking, a timeline, search results) →
|
|
26
|
+
a list or a grid. Masonry's reading order is column by column.
|
|
27
|
+
- A data list → `Table`.
|
|
28
|
+
|
|
29
|
+
## Props
|
|
30
|
+
|
|
31
|
+
</En>
|
|
32
|
+
|
|
33
|
+
<Ko>
|
|
34
|
+
|
|
35
|
+
# Masonry
|
|
36
|
+
|
|
37
|
+
너비가 같은 열에 높이가 다른 항목을 빈틈없이 채우고, 항목 크기가 바뀌면 다시 재는
|
|
38
|
+
레이아웃입니다. FactChat은 모델 메뉴와 음성 메뉴에 씁니다.
|
|
39
|
+
|
|
40
|
+
## 언제 쓰나요
|
|
41
|
+
|
|
42
|
+
- 순서가 없고 높이 차이가 커서 격자로 놓으면 빈칸이 생기는 묶음이나 카드.
|
|
43
|
+
|
|
44
|
+
## 언제 쓰지 않나요
|
|
45
|
+
|
|
46
|
+
- 높이가 비슷한 항목은 행 순서를 지키는 `SimpleGrid` / `Grid`를 씁니다.
|
|
47
|
+
- 순서가 있는 것(단계, 순위, 타임라인, 검색 결과)은 목록이나 격자를 씁니다.
|
|
48
|
+
Masonry의 읽기 순서는 열 단위입니다.
|
|
49
|
+
- 데이터 목록은 `Table`을 씁니다.
|
|
50
|
+
|
|
51
|
+
## 속성
|
|
52
|
+
|
|
53
|
+
</Ko>
|
|
54
|
+
|
|
55
|
+
<ArgTypes of={MasonryStories} include={['numCols', 'gap', 'horizontalArrangement']} />
|
|
56
|
+
|
|
57
|
+
<En>
|
|
58
|
+
|
|
59
|
+
## Do / Don't
|
|
60
|
+
|
|
61
|
+
</En>
|
|
62
|
+
|
|
63
|
+
<Ko>
|
|
64
|
+
|
|
65
|
+
## 이렇게 하세요 / 이렇게 하지 마세요
|
|
66
|
+
|
|
67
|
+
</Ko>
|
|
68
|
+
|
|
69
|
+
<Canvas of={MasonryStories.DoUnorderedGroups} />
|
|
70
|
+
<Verdict
|
|
71
|
+
kind="do"
|
|
72
|
+
en="Pack unordered groups of different heights. Nothing depends on which comes first."
|
|
73
|
+
ko="높이가 다르고 순서가 없는 묶음을 빈틈없이 채웁니다. 어느 것이 먼저 오든 상관없습니다."
|
|
74
|
+
/>
|
|
75
|
+
|
|
76
|
+
<Canvas of={MasonryStories.DontOrderedContent} />
|
|
77
|
+
<Verdict
|
|
78
|
+
kind="dont"
|
|
79
|
+
en="Lay out steps in it. Placement follows height, so the visual order scrambles, and keyboard and screen-reader order runs down each column."
|
|
80
|
+
ko="단계를 Masonry로 늘어놓지 마세요. 높이에 따라 자리가 정해져 눈에 보이는 순서가 뒤섞이고, 키보드와 화면 낭독기는 열마다 위에서 아래로 읽습니다."
|
|
81
|
+
/>
|
|
82
|
+
|
|
83
|
+
<En>
|
|
84
|
+
|
|
85
|
+
## Accessibility
|
|
86
|
+
|
|
87
|
+
What Masonry does for you:
|
|
88
|
+
|
|
89
|
+
- Nothing beyond layout. It renders plain boxes, one column after another.
|
|
90
|
+
|
|
91
|
+
What you still have to do:
|
|
92
|
+
|
|
93
|
+
- **Keep the content order-free** (WCAG 1.3.2, 2.4.3). The DOM order is
|
|
94
|
+
column 1 top to bottom, then column 2, so Tab and a screen reader follow
|
|
95
|
+
columns, not the rows a sighted reader sees.
|
|
96
|
+
- **Set `numCols` for the viewport** with `useBreakpointValue`; at 320px wide
|
|
97
|
+
one column avoids sideways scrolling (WCAG 1.4.10).
|
|
98
|
+
|
|
99
|
+
## Tokens
|
|
100
|
+
|
|
101
|
+
Masonry sets no colour tokens.
|
|
102
|
+
|
|
103
|
+
</En>
|
|
104
|
+
|
|
105
|
+
<Ko>
|
|
106
|
+
|
|
107
|
+
## 접근성
|
|
108
|
+
|
|
109
|
+
Masonry가 알아서 하는 일
|
|
110
|
+
|
|
111
|
+
- 레이아웃 말고는 없습니다. 열을 하나씩 차례로 그리는 일반 상자입니다.
|
|
112
|
+
|
|
113
|
+
직접 챙겨야 하는 일
|
|
114
|
+
|
|
115
|
+
- **순서가 없는 내용에만 씁니다**(WCAG 1.3.2, 2.4.3). DOM 순서가 1열 위에서 아래, 그다음
|
|
116
|
+
2열이라, Tab과 화면 낭독기는 눈에 보이는 행이 아니라 열을 따라갑니다.
|
|
117
|
+
- **화면 너비에 맞게 `numCols`를 정합니다.** `useBreakpointValue`를 쓰고, 폭 320px에서는
|
|
118
|
+
한 열로 두어 가로 스크롤을 막습니다(WCAG 1.4.10).
|
|
119
|
+
|
|
120
|
+
## 토큰
|
|
121
|
+
|
|
122
|
+
Masonry는 색 토큰을 쓰지 않습니다.
|
|
123
|
+
|
|
124
|
+
</Ko>
|
|
125
|
+
|
|
126
|
+
<En>
|
|
127
|
+
|
|
128
|
+
## Related
|
|
129
|
+
|
|
130
|
+
- **Card**: what usually goes in each cell.
|
|
131
|
+
- **Container**: page width.
|
|
132
|
+
|
|
133
|
+
</En>
|
|
134
|
+
|
|
135
|
+
<Ko>
|
|
136
|
+
|
|
137
|
+
## 관련 컴포넌트
|
|
138
|
+
|
|
139
|
+
- **Card**: 칸마다 주로 들어가는 것.
|
|
140
|
+
- **Container**: 페이지 너비.
|
|
141
|
+
|
|
142
|
+
</Ko>
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { Box, chakra, Flex } from '@chakra-ui/react';
|
|
1
3
|
import { Meta, StoryObj } from '@storybook/react';
|
|
2
4
|
|
|
5
|
+
import { T } from '../../guidelines/_components/Lang';
|
|
6
|
+
import { TokenTable } from '../../guidelines/_components/TokenTable';
|
|
7
|
+
import { Textarea } from '../Textarea';
|
|
3
8
|
import { MaxLengthIndicator } from '.';
|
|
4
9
|
|
|
5
10
|
const meta = {
|
|
@@ -24,3 +29,55 @@ export default meta;
|
|
|
24
29
|
type Story = StoryObj<typeof MaxLengthIndicator>;
|
|
25
30
|
|
|
26
31
|
export const Basic: Story = {};
|
|
32
|
+
|
|
33
|
+
// ───────────────────────── Usage-page specimens ─────────────────────────
|
|
34
|
+
// Pulled into `MaxLengthIndicator.usage.mdx` with <Canvas of={…} />. Hidden
|
|
35
|
+
// from the sidebar (`!dev`).
|
|
36
|
+
|
|
37
|
+
const LIMIT = 200;
|
|
38
|
+
|
|
39
|
+
export const DoUnderField: Story = {
|
|
40
|
+
tags: ['!dev'],
|
|
41
|
+
parameters: { layout: 'padded' },
|
|
42
|
+
name: 'Usage / Do: under the field, tied to it, with the real limit',
|
|
43
|
+
render: function DoUnderFieldStory() {
|
|
44
|
+
const [text, setText] = useState('신입 사원을 위한 사내 규정 안내 챗봇입니다.');
|
|
45
|
+
return (
|
|
46
|
+
<Box w="360px">
|
|
47
|
+
<chakra.label
|
|
48
|
+
display="block"
|
|
49
|
+
htmlFor="bot-description"
|
|
50
|
+
fontSize="sm"
|
|
51
|
+
fontWeight="semibold"
|
|
52
|
+
mb={1}
|
|
53
|
+
>
|
|
54
|
+
설명
|
|
55
|
+
</chakra.label>
|
|
56
|
+
<Textarea
|
|
57
|
+
id="bot-description"
|
|
58
|
+
value={text}
|
|
59
|
+
maxLength={LIMIT}
|
|
60
|
+
aria-describedby="bot-description-count"
|
|
61
|
+
onChange={(event) => setText(event.target.value)}
|
|
62
|
+
/>
|
|
63
|
+
<Flex justify="flex-end" mt={1}>
|
|
64
|
+
<MaxLengthIndicator
|
|
65
|
+
id="bot-description-count"
|
|
66
|
+
value={text.length}
|
|
67
|
+
maxLength={LIMIT}
|
|
68
|
+
/>
|
|
69
|
+
</Flex>
|
|
70
|
+
</Box>
|
|
71
|
+
);
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/** Tokens the indicator reads, from `MaxLengthIndicator.tsx`. */
|
|
76
|
+
export const UsageTokens: Story = {
|
|
77
|
+
tags: ['!dev'],
|
|
78
|
+
parameters: { layout: 'padded' },
|
|
79
|
+
name: 'Usage / Tokens',
|
|
80
|
+
render: () => (
|
|
81
|
+
<TokenTable rows={[{ token: 'fg.subtle', use: <T en="count text" ko="개수 글자" /> }]} />
|
|
82
|
+
),
|
|
83
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import { En, Ko, LangToggle, Verdict } from '../../guidelines/_components/Lang';
|
|
4
|
+
import * as MaxLengthIndicatorStories from './MaxLengthIndicator.stories';
|
|
5
|
+
|
|
6
|
+
<Meta of={MaxLengthIndicatorStories} name="Usage" />
|
|
7
|
+
|
|
8
|
+
<LangToggle />
|
|
9
|
+
|
|
10
|
+
<En>
|
|
11
|
+
|
|
12
|
+
# MaxLengthIndicator
|
|
13
|
+
|
|
14
|
+
A small `value/maxLength` counter under a text field that has a length limit.
|
|
15
|
+
|
|
16
|
+
## When to use
|
|
17
|
+
|
|
18
|
+
- Under an `Input` or `Textarea` with a hard character limit the reader is
|
|
19
|
+
likely to reach: a description, a prompt, a name with a short limit.
|
|
20
|
+
|
|
21
|
+
## When not to use
|
|
22
|
+
|
|
23
|
+
- No limit, or one nobody comes near → leave it out.
|
|
24
|
+
- A count of items, not characters → plain text or `CountBadge`.
|
|
25
|
+
|
|
26
|
+
## How it works
|
|
27
|
+
|
|
28
|
+
- It only displays the two numbers, in `subtext` style and `fg.subtle`. It does
|
|
29
|
+
not count, enforce the limit, change colour near the limit or announce
|
|
30
|
+
anything.
|
|
31
|
+
- Pass the field's current length as `value` and the same limit you set on the
|
|
32
|
+
field's `maxLength`, which is what actually stops input.
|
|
33
|
+
- Other `Text` props (`id`, `textAlign`, …) pass through.
|
|
34
|
+
|
|
35
|
+
## Do
|
|
36
|
+
|
|
37
|
+
</En>
|
|
38
|
+
|
|
39
|
+
<Ko>
|
|
40
|
+
|
|
41
|
+
# MaxLengthIndicator
|
|
42
|
+
|
|
43
|
+
글자 수 제한이 있는 입력란 아래에 `value/maxLength`를 보여 주는 작은 숫자입니다.
|
|
44
|
+
|
|
45
|
+
## 언제 쓰나요
|
|
46
|
+
|
|
47
|
+
- 설명, 프롬프트, 짧은 이름처럼 사용자가 닿을 만한 글자 수 제한이 있는 `Input`이나
|
|
48
|
+
`Textarea` 아래에 둡니다.
|
|
49
|
+
|
|
50
|
+
## 언제 쓰지 않나요
|
|
51
|
+
|
|
52
|
+
- 제한이 없거나 아무도 닿지 않을 제한이라면 두지 않습니다.
|
|
53
|
+
- 글자가 아니라 항목의 개수라면 일반 글자나 `CountBadge`를 씁니다.
|
|
54
|
+
|
|
55
|
+
## 동작 방식
|
|
56
|
+
|
|
57
|
+
- 숫자 두 개를 `subtext` 스타일과 `fg.subtle` 색으로 보여 주기만 합니다. 글자를
|
|
58
|
+
세거나, 제한을 지키게 하거나, 제한에 가까워질 때 색을 바꾸거나, 무언가를 알려 주지
|
|
59
|
+
않습니다.
|
|
60
|
+
- 입력란의 현재 길이를 `value`로, 입력란의 `maxLength`와 같은 제한 값을 `maxLength`로
|
|
61
|
+
넘깁니다. 입력을 실제로 막는 것은 입력란의 `maxLength`입니다.
|
|
62
|
+
- `id`, `textAlign` 같은 다른 `Text` 속성은 그대로 전달됩니다.
|
|
63
|
+
|
|
64
|
+
## 이렇게 하세요
|
|
65
|
+
|
|
66
|
+
</Ko>
|
|
67
|
+
|
|
68
|
+
<Canvas of={MaxLengthIndicatorStories.DoUnderField} />
|
|
69
|
+
<Verdict
|
|
70
|
+
kind="do"
|
|
71
|
+
en="Put it under the field, set the same limit as the field's maxLength, and point the field's aria-describedby at the counter's id so the limit is read with the field."
|
|
72
|
+
ko="입력란 아래에 두고, 입력란의 maxLength와 같은 제한 값을 쓰며, 입력란의 aria-describedby가 카운터의 id를 가리키게 해서 제한이 입력란과 함께 읽히게 합니다."
|
|
73
|
+
/>
|
|
74
|
+
|
|
75
|
+
<En>
|
|
76
|
+
|
|
77
|
+
## Accessibility
|
|
78
|
+
|
|
79
|
+
- Tie the counter to the field with `aria-describedby`, so the limit is
|
|
80
|
+
announced when the field gets focus (WCAG 1.3.1).
|
|
81
|
+
- It does not announce changes while typing, which is usually right: a
|
|
82
|
+
number read out on every keystroke is noise. If reaching the limit matters,
|
|
83
|
+
say so once in a `role="status"` region (WCAG 4.1.3).
|
|
84
|
+
- `fg.subtle` is for secondary text. If the counter is the only place the
|
|
85
|
+
limit is stated, check its contrast on the field's background (WCAG 1.4.3).
|
|
86
|
+
|
|
87
|
+
## Tokens
|
|
88
|
+
|
|
89
|
+
</En>
|
|
90
|
+
|
|
91
|
+
<Ko>
|
|
92
|
+
|
|
93
|
+
## 접근성
|
|
94
|
+
|
|
95
|
+
- `aria-describedby`로 카운터를 입력란에 연결해서, 입력란에 초점이 오면 제한이 함께
|
|
96
|
+
읽히게 합니다(WCAG 1.3.1).
|
|
97
|
+
- 입력하는 동안 바뀐 숫자를 알려 주지 않습니다. 대개는 이것이 맞습니다. 글자를 칠 때마다
|
|
98
|
+
숫자를 읽으면 소음이 됩니다. 제한에 닿았다는 사실이 중요하다면 `role="status"`
|
|
99
|
+
영역으로 한 번만 알립니다(WCAG 4.1.3).
|
|
100
|
+
- `fg.subtle`은 보조 글자용 색입니다. 카운터가 제한을 알리는 유일한 곳이라면 입력란
|
|
101
|
+
배경 위에서 대비를 확인합니다(WCAG 1.4.3).
|
|
102
|
+
|
|
103
|
+
## 토큰
|
|
104
|
+
|
|
105
|
+
</Ko>
|
|
106
|
+
|
|
107
|
+
<Canvas of={MaxLengthIndicatorStories.UsageTokens} sourceState="none" />
|
|
108
|
+
|
|
109
|
+
<En>
|
|
110
|
+
|
|
111
|
+
## Related
|
|
112
|
+
|
|
113
|
+
- **Input** / **Textarea**: the field and its `maxLength`.
|
|
114
|
+
- **FormControl**: label, help and error text for the field.
|
|
115
|
+
|
|
116
|
+
</En>
|
|
117
|
+
|
|
118
|
+
<Ko>
|
|
119
|
+
|
|
120
|
+
## 관련 컴포넌트
|
|
121
|
+
|
|
122
|
+
- **Input** / **Textarea**: 입력란과 그 `maxLength`.
|
|
123
|
+
- **FormControl**: 입력란의 라벨, 도움말, 오류 문구.
|
|
124
|
+
|
|
125
|
+
</Ko>
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
1
|
+
import { type ReactNode, useState } from 'react';
|
|
2
|
+
import { Box } from '@chakra-ui/react';
|
|
2
3
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
4
|
|
|
5
|
+
import { T } from '../../guidelines/_components/Lang';
|
|
6
|
+
import { TokenTable } from '../../guidelines/_components/TokenTable';
|
|
4
7
|
import { Button } from '../Button/Button';
|
|
5
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
CopyIcon,
|
|
10
|
+
EditIcon,
|
|
11
|
+
IoChevronDownOutline,
|
|
12
|
+
SlSettings,
|
|
13
|
+
TrashIcon,
|
|
14
|
+
VerticalEllipsisIcon,
|
|
15
|
+
} from '../Icon';
|
|
6
16
|
import { IconButton } from '../IconButton';
|
|
7
17
|
import { Menu } from './Menu';
|
|
8
18
|
import { MenuItemProps } from './MenuItem.types';
|
|
@@ -223,3 +233,137 @@ export const SelectiveIcon: Story = {
|
|
|
223
233
|
);
|
|
224
234
|
},
|
|
225
235
|
};
|
|
236
|
+
|
|
237
|
+
// ───────────────────────── Usage-page specimens ─────────────────────────
|
|
238
|
+
// Pulled into `Menu.usage.mdx` with <Canvas of={…} />. Hidden from the
|
|
239
|
+
// sidebar (`!dev`). Each menu is held open and rendered in place
|
|
240
|
+
// (`portalled={false}`) so it sits inside its canvas.
|
|
241
|
+
|
|
242
|
+
const OpenMenu = ({
|
|
243
|
+
trigger,
|
|
244
|
+
children,
|
|
245
|
+
}: {
|
|
246
|
+
trigger: ReactNode;
|
|
247
|
+
children: ReactNode;
|
|
248
|
+
}) => (
|
|
249
|
+
<Box h="200px">
|
|
250
|
+
<Menu
|
|
251
|
+
open
|
|
252
|
+
closeOnSelect={false}
|
|
253
|
+
positioning={{ placement: 'bottom-start', flip: false }}
|
|
254
|
+
>
|
|
255
|
+
<Menu.Trigger asChild>{trigger}</Menu.Trigger>
|
|
256
|
+
{/* The list caps itself at the viewport space left below the
|
|
257
|
+
trigger; a canvas near the fold would clip the last row. */}
|
|
258
|
+
<Menu.List portalled={false} maxH="none">
|
|
259
|
+
{children}
|
|
260
|
+
</Menu.List>
|
|
261
|
+
</Menu>
|
|
262
|
+
</Box>
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
// An element, not a component: `Menu.Trigger asChild` passes its ref and
|
|
266
|
+
// props to its direct child, which must be the button itself.
|
|
267
|
+
const rowTrigger = (
|
|
268
|
+
<IconButton aria-label="김민지 님 작업 메뉴" variant="ghost">
|
|
269
|
+
<VerticalEllipsisIcon aria-hidden />
|
|
270
|
+
</IconButton>
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
export const DoRowActions: Story = {
|
|
274
|
+
tags: ['!dev'],
|
|
275
|
+
parameters: { layout: 'padded' },
|
|
276
|
+
name: 'Usage / Do: actions on one row, danger last',
|
|
277
|
+
render: () => (
|
|
278
|
+
<OpenMenu trigger={rowTrigger}>
|
|
279
|
+
<Menu.Item value="rename" icon={<EditIcon aria-hidden />}>
|
|
280
|
+
이름 변경
|
|
281
|
+
</Menu.Item>
|
|
282
|
+
<Menu.Item value="duplicate" icon={<CopyIcon aria-hidden />}>
|
|
283
|
+
복제
|
|
284
|
+
</Menu.Item>
|
|
285
|
+
<Menu.Separator />
|
|
286
|
+
<Menu.Item
|
|
287
|
+
value="delete"
|
|
288
|
+
variant="danger"
|
|
289
|
+
icon={<TrashIcon aria-hidden />}
|
|
290
|
+
>
|
|
291
|
+
삭제
|
|
292
|
+
</Menu.Item>
|
|
293
|
+
</OpenMenu>
|
|
294
|
+
),
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
export const DontDangerEverywhere: Story = {
|
|
298
|
+
tags: ['!dev'],
|
|
299
|
+
parameters: { layout: 'padded' },
|
|
300
|
+
name: "Usage / Don't: danger on actions that are not destructive",
|
|
301
|
+
render: () => (
|
|
302
|
+
<OpenMenu trigger={rowTrigger}>
|
|
303
|
+
<Menu.Item value="rename" variant="danger">
|
|
304
|
+
이름 변경
|
|
305
|
+
</Menu.Item>
|
|
306
|
+
<Menu.Item value="archive" variant="danger">
|
|
307
|
+
보관
|
|
308
|
+
</Menu.Item>
|
|
309
|
+
<Menu.Item value="delete" variant="danger">
|
|
310
|
+
삭제
|
|
311
|
+
</Menu.Item>
|
|
312
|
+
</OpenMenu>
|
|
313
|
+
),
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
export const DontUnnamedTrigger: Story = {
|
|
317
|
+
tags: ['!dev'],
|
|
318
|
+
parameters: { layout: 'padded' },
|
|
319
|
+
name: "Usage / Don't: the same unnamed trigger on every row",
|
|
320
|
+
render: () => (
|
|
321
|
+
<OpenMenu
|
|
322
|
+
trigger={
|
|
323
|
+
<IconButton aria-label="메뉴" variant="ghost">
|
|
324
|
+
<VerticalEllipsisIcon aria-hidden />
|
|
325
|
+
</IconButton>
|
|
326
|
+
}
|
|
327
|
+
>
|
|
328
|
+
<Menu.Item value="rename">이름 변경</Menu.Item>
|
|
329
|
+
<Menu.Item value="delete" variant="danger">
|
|
330
|
+
삭제
|
|
331
|
+
</Menu.Item>
|
|
332
|
+
</OpenMenu>
|
|
333
|
+
),
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
/** Tokens a menu row reads, as set in `MenuItem.tsx` and `MenuList.tsx`. */
|
|
337
|
+
export const UsageTokens: Story = {
|
|
338
|
+
tags: ['!dev'],
|
|
339
|
+
parameters: { layout: 'padded' },
|
|
340
|
+
name: 'Usage / Tokens',
|
|
341
|
+
render: () => (
|
|
342
|
+
<TokenTable
|
|
343
|
+
rows={[
|
|
344
|
+
{ token: 'bg.panel', use: <T en="List" ko="목록" /> },
|
|
345
|
+
{
|
|
346
|
+
token: 'border.subtle',
|
|
347
|
+
use: <T en="List border" ko="목록 테두리" />,
|
|
348
|
+
},
|
|
349
|
+
{ token: 'fg.muted', use: <T en="Row · text" ko="줄 · 글자" /> },
|
|
350
|
+
{
|
|
351
|
+
token: 'fg.default',
|
|
352
|
+
use: <T en="Row · highlighted text" ko="줄 · 강조된 글자" />,
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
token: 'primary.wash',
|
|
356
|
+
use: <T en="Row · highlighted" ko="줄 · 강조 배경" />,
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
token: 'danger.fg',
|
|
360
|
+
use: <T en="Danger row · text" ko="위험 줄 · 글자" />,
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
token: 'danger.bg',
|
|
364
|
+
use: <T en="Danger row · highlighted" ko="위험 줄 · 강조 배경" />,
|
|
365
|
+
},
|
|
366
|
+
]}
|
|
367
|
+
/>
|
|
368
|
+
),
|
|
369
|
+
};
|