@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,127 @@
|
|
|
1
|
+
import { ArgTypes, Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import { En, Ko, LangToggle } from '../../guidelines/_components/Lang';
|
|
4
|
+
import * as ErrorFallbackStories from './ErrorFallback.stories';
|
|
5
|
+
|
|
6
|
+
<Meta of={ErrorFallbackStories} name="Usage" />
|
|
7
|
+
|
|
8
|
+
<LangToggle />
|
|
9
|
+
|
|
10
|
+
<En>
|
|
11
|
+
|
|
12
|
+
# ErrorFallback
|
|
13
|
+
|
|
14
|
+
The full-height card an error boundary renders when a page or a large section
|
|
15
|
+
fails to render: what happened, details for support, and a way to try again.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
- As the `fallback` of a React error boundary or a route-level error page
|
|
20
|
+
(FactChat uses it in its `ErrorBoundary` and route error screens).
|
|
21
|
+
|
|
22
|
+
## When not to use
|
|
23
|
+
|
|
24
|
+
- A request failed but the page still works → `Banner` (`danger`) in place, or
|
|
25
|
+
a `Toast`.
|
|
26
|
+
- One block inside a page, such as a code block or a table in a chat message,
|
|
27
|
+
failed → a small inline fallback. ErrorFallback is at least one screen tall
|
|
28
|
+
(`100svh`).
|
|
29
|
+
|
|
30
|
+
## Props
|
|
31
|
+
|
|
32
|
+
</En>
|
|
33
|
+
|
|
34
|
+
<Ko>
|
|
35
|
+
|
|
36
|
+
# ErrorFallback
|
|
37
|
+
|
|
38
|
+
페이지나 큰 영역을 그리지 못했을 때 에러 바운더리가 대신 그리는 전체 높이의
|
|
39
|
+
카드입니다. 무슨 일이 있었는지, 지원팀에 전할 정보, 다시 시도하는 방법을 보여 줍니다.
|
|
40
|
+
|
|
41
|
+
## 언제 쓰나요
|
|
42
|
+
|
|
43
|
+
- React 에러 바운더리의 `fallback`이나 라우트 단위 오류 화면으로 씁니다(FactChat은
|
|
44
|
+
`ErrorBoundary`와 라우트 오류 화면에서 씁니다).
|
|
45
|
+
|
|
46
|
+
## 언제 쓰지 않나요
|
|
47
|
+
|
|
48
|
+
- 요청은 실패했지만 페이지는 쓸 수 있다면, 그 자리에 `Banner`(`danger`)를 두거나
|
|
49
|
+
`Toast`를 씁니다.
|
|
50
|
+
- 채팅 메시지 안의 코드 블록이나 표처럼 페이지 안의 한 덩어리만 실패했다면 작은 인라인
|
|
51
|
+
대체 화면을 씁니다. ErrorFallback은 높이가 화면 하나(`100svh`) 이상입니다.
|
|
52
|
+
|
|
53
|
+
## 속성
|
|
54
|
+
|
|
55
|
+
</Ko>
|
|
56
|
+
|
|
57
|
+
<ArgTypes of={ErrorFallbackStories} />
|
|
58
|
+
|
|
59
|
+
<En>
|
|
60
|
+
|
|
61
|
+
What it shows and does:
|
|
62
|
+
|
|
63
|
+
- Title, subtitle, help text and button labels come from the library's
|
|
64
|
+
translations, in the app's language.
|
|
65
|
+
- `error.message` is shown to the reader as is, in a `danger.bg` box. Throw
|
|
66
|
+
errors whose message a person can read, or pass an `Error` with a
|
|
67
|
+
user-facing message.
|
|
68
|
+
- The support block lists the error ID (generated when `errorId` is missing),
|
|
69
|
+
the time, `componentName`, `userId` and the page path.
|
|
70
|
+
- **Copy error details** copies a report with the ID, `timestamp`, component,
|
|
71
|
+
message, full URL, user ID and user agent, then confirms with a toast. The
|
|
72
|
+
app must mount `<Toaster />` for that toast to appear.
|
|
73
|
+
- **Try again** calls `onErrorReset`; **Refresh page** reloads the window.
|
|
74
|
+
- The time on screen is when the card rendered; the `timestamp` prop goes only
|
|
75
|
+
into the copied report.
|
|
76
|
+
|
|
77
|
+
<Canvas of={ErrorFallbackStories.Default} />
|
|
78
|
+
|
|
79
|
+
## Accessibility
|
|
80
|
+
|
|
81
|
+
- The card is a `<section>` named by its title, so it is a landmark even when
|
|
82
|
+
the page's `<main>` failed with it (WCAG 1.3.1).
|
|
83
|
+
- The title is an `<h1>` and the support block an `<h2>`, so the outline does
|
|
84
|
+
not skip levels (`ACCESSIBILITY.md` §2, KWCAG 5.2.4.2).
|
|
85
|
+
- Move focus to the card's heading when it replaces content the reader was
|
|
86
|
+
using, so a screen reader user learns that the page changed (WCAG 2.4.3).
|
|
87
|
+
|
|
88
|
+
## Related
|
|
89
|
+
|
|
90
|
+
- **Banner**: a failure the page survives.
|
|
91
|
+
- **Toast**: a failed background action.
|
|
92
|
+
|
|
93
|
+
</En>
|
|
94
|
+
|
|
95
|
+
<Ko>
|
|
96
|
+
|
|
97
|
+
보여 주는 것과 하는 일
|
|
98
|
+
|
|
99
|
+
- 제목, 부제, 도움말, 버튼 라벨은 라이브러리 번역에서 앱의 언어로 가져옵니다.
|
|
100
|
+
- `error.message`는 `danger.bg` 상자 안에 그대로 보입니다. 사람이 읽을 수 있는
|
|
101
|
+
메시지로 오류를 던지거나, 사용자에게 보여 줄 메시지를 담은 `Error`를 넘깁니다.
|
|
102
|
+
- 지원 정보에는 오류 ID(`errorId`가 없으면 새로 만듦), 시간, `componentName`,
|
|
103
|
+
`userId`, 페이지 경로가 나옵니다.
|
|
104
|
+
- **오류 정보 복사**는 ID, `timestamp`, 컴포넌트, 메시지, 전체 URL, 사용자 ID,
|
|
105
|
+
사용자 에이전트를 담은 보고서를 복사하고 토스트로 알립니다. 그 토스트가 보이려면 앱에
|
|
106
|
+
`<Toaster />`가 있어야 합니다.
|
|
107
|
+
- **다시 시도**는 `onErrorReset`을 부르고, **페이지 새로고침**은 창을 다시 엽니다.
|
|
108
|
+
- 화면의 시간은 카드를 그린 시각입니다. `timestamp` 속성은 복사되는 보고서에만
|
|
109
|
+
들어갑니다.
|
|
110
|
+
|
|
111
|
+
<Canvas of={ErrorFallbackStories.Default} />
|
|
112
|
+
|
|
113
|
+
## 접근성
|
|
114
|
+
|
|
115
|
+
- 카드는 제목으로 이름을 붙인 `<section>`이라서, 페이지의 `<main>`이 함께 사라져도
|
|
116
|
+
랜드마크가 남습니다(WCAG 1.3.1).
|
|
117
|
+
- 제목은 `<h1>`, 지원 정보는 `<h2>`라서 제목 수준을 건너뛰지 않습니다
|
|
118
|
+
(`ACCESSIBILITY.md` §2, KWCAG 5.2.4.2).
|
|
119
|
+
- 사용자가 쓰던 내용을 이 카드가 대신한다면 카드 제목으로 초점을 옮깁니다. 그래야 화면
|
|
120
|
+
낭독기 사용자가 페이지가 바뀐 것을 압니다(WCAG 2.4.3).
|
|
121
|
+
|
|
122
|
+
## 관련 컴포넌트
|
|
123
|
+
|
|
124
|
+
- **Banner**: 페이지는 살아 있는 실패.
|
|
125
|
+
- **Toast**: 백그라운드 작업의 실패.
|
|
126
|
+
|
|
127
|
+
</Ko>
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react';
|
|
2
2
|
|
|
3
|
+
import { TokenTable } from '../../guidelines/_components/TokenTable';
|
|
4
|
+
import { Card } from '../Card';
|
|
5
|
+
import { LINK_RAMP, Text } from '../Typography';
|
|
3
6
|
import { ExpandableText } from './ExpandableText';
|
|
4
7
|
|
|
5
8
|
const meta = {
|
|
@@ -163,3 +166,55 @@ export const ComponentComparison: Story = {
|
|
|
163
166
|
);
|
|
164
167
|
},
|
|
165
168
|
};
|
|
169
|
+
|
|
170
|
+
// ───────────────────────── Usage-page specimens ─────────────────────────
|
|
171
|
+
// Pulled into `ExpandableText.usage.mdx` with <Canvas of={…} />. Hidden from
|
|
172
|
+
// the sidebar (`!dev`); `tags` is written out on each story because the
|
|
173
|
+
// indexer reads CSF statically.
|
|
174
|
+
|
|
175
|
+
const DESCRIPTION =
|
|
176
|
+
'회의 내용을 바탕으로 요약, 결정 사항, 할 일을 정리해 주는 챗봇입니다. 녹음 파일이나 회의록을 올리면 참석자별 발언을 나눠 보여 주고, 다음 회의 전에 확인할 항목을 골라 줍니다. 팀 공용 챗봇으로 공유해 같은 형식의 회의록을 쓸 수 있습니다.';
|
|
177
|
+
|
|
178
|
+
export const DoSecondaryDescription: Story = {
|
|
179
|
+
tags: ['!dev'],
|
|
180
|
+
parameters: { layout: 'padded' },
|
|
181
|
+
name: 'Usage / Do: a long secondary description in a card',
|
|
182
|
+
render: () => (
|
|
183
|
+
<Card p={5} maxW="360px">
|
|
184
|
+
<Text fontWeight="bold" mb={1}>
|
|
185
|
+
회의록 도우미
|
|
186
|
+
</Text>
|
|
187
|
+
<ExpandableText lineClamp={2} component="Subtext">
|
|
188
|
+
{DESCRIPTION}
|
|
189
|
+
</ExpandableText>
|
|
190
|
+
</Card>
|
|
191
|
+
),
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export const DontClipTheMessage: Story = {
|
|
195
|
+
tags: ['!dev'],
|
|
196
|
+
parameters: { layout: 'padded' },
|
|
197
|
+
name: "Usage / Don't: clip what the reader must not miss",
|
|
198
|
+
render: () => (
|
|
199
|
+
<Card p={5} maxW="360px">
|
|
200
|
+
<ExpandableText lineClamp={1}>
|
|
201
|
+
이 작업은 되돌릴 수 없습니다. 그룹을 삭제하면 그룹에 속한 멤버 42명의
|
|
202
|
+
크레딧 한도와 챗봇 공유 설정이 함께 지워집니다.
|
|
203
|
+
</ExpandableText>
|
|
204
|
+
</Card>
|
|
205
|
+
),
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
export const UsageTokens: Story = {
|
|
209
|
+
tags: ['!dev'],
|
|
210
|
+
parameters: { layout: 'padded' },
|
|
211
|
+
name: 'Usage / Tokens',
|
|
212
|
+
render: () => (
|
|
213
|
+
<TokenTable
|
|
214
|
+
rows={[
|
|
215
|
+
{ token: LINK_RAMP.default, use: '더보기 / 접기 (Link)' },
|
|
216
|
+
{ token: 'fg.default', use: '더보기 / 접기 · hover' },
|
|
217
|
+
]}
|
|
218
|
+
/>
|
|
219
|
+
),
|
|
220
|
+
};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import { En, Ko, LangToggle, Verdict } from '../../guidelines/_components/Lang';
|
|
4
|
+
import * as ExpandableTextStories from './ExpandableText.stories';
|
|
5
|
+
|
|
6
|
+
<Meta of={ExpandableTextStories} name="Usage" />
|
|
7
|
+
|
|
8
|
+
<LangToggle />
|
|
9
|
+
|
|
10
|
+
<En>
|
|
11
|
+
|
|
12
|
+
# ExpandableText
|
|
13
|
+
|
|
14
|
+
Text clipped to a number of lines, with a 더보기 / 접기 link that opens it.
|
|
15
|
+
Opening animates the height, so the content below slides down rather than
|
|
16
|
+
jumping. The link appears only when the text actually overflows.
|
|
17
|
+
|
|
18
|
+
## When to use
|
|
19
|
+
|
|
20
|
+
- A long secondary description in a card or a header: a chatbot's
|
|
21
|
+
description, an announcement preview, an image prompt in a history list.
|
|
22
|
+
|
|
23
|
+
## When not to use
|
|
24
|
+
|
|
25
|
+
- The main content the reader came for → show it in full.
|
|
26
|
+
- Warnings, prices, terms, or anything the reader must not miss → show it in
|
|
27
|
+
full.
|
|
28
|
+
- A section with a heading and structure → `Collapsible`.
|
|
29
|
+
|
|
30
|
+
## Props
|
|
31
|
+
|
|
32
|
+
| Prop | Means |
|
|
33
|
+
| --- | --- |
|
|
34
|
+
| `lineClamp` | Lines shown while closed. Default `3`. |
|
|
35
|
+
| `component` | The typography tier that wraps it: `Text` (default), `Subtitle`, `Subtext`, `H1`–`H5`. Other props go to that component. |
|
|
36
|
+
| `charLimit` | Deprecated and ignored. Truncation is by line. |
|
|
37
|
+
|
|
38
|
+
## Do / Don't
|
|
39
|
+
|
|
40
|
+
</En>
|
|
41
|
+
|
|
42
|
+
<Ko>
|
|
43
|
+
|
|
44
|
+
# ExpandableText
|
|
45
|
+
|
|
46
|
+
정해진 줄 수만큼만 보여 주고, '더보기' / '접기' 링크로 펼치는 글입니다. 펼칠 때 높이가
|
|
47
|
+
움직이므로 아래 내용이 갑자기 튀지 않고 밀려 내려갑니다. 링크는 글이 실제로 넘칠 때만
|
|
48
|
+
나타납니다.
|
|
49
|
+
|
|
50
|
+
## 언제 쓰나요
|
|
51
|
+
|
|
52
|
+
- 카드나 머리 영역의 긴 보조 설명: 챗봇 설명, 공지 미리보기, 이미지 기록 목록의
|
|
53
|
+
프롬프트.
|
|
54
|
+
|
|
55
|
+
## 언제 쓰지 않나요
|
|
56
|
+
|
|
57
|
+
- 읽는 사람이 보러 온 본 내용은 전부 보여 줍니다.
|
|
58
|
+
- 경고, 가격, 약관처럼 놓치면 안 되는 내용은 전부 보여 줍니다.
|
|
59
|
+
- 제목과 구조가 있는 섹션은 `Collapsible`을 씁니다.
|
|
60
|
+
|
|
61
|
+
## 속성
|
|
62
|
+
|
|
63
|
+
| 속성 | 뜻 |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| `lineClamp` | 접혀 있을 때 보여 줄 줄 수. 기본값 `3`. |
|
|
66
|
+
| `component` | 감싸는 글자 단계: `Text`(기본값), `Subtitle`, `Subtext`, `H1`–`H5`. 나머지 속성은 이 컴포넌트로 넘어갑니다. |
|
|
67
|
+
| `charLimit` | deprecated이며 무시됩니다. 글은 줄 단위로 자릅니다. |
|
|
68
|
+
|
|
69
|
+
## 이렇게 하세요 / 이렇게 하지 마세요
|
|
70
|
+
|
|
71
|
+
</Ko>
|
|
72
|
+
|
|
73
|
+
<Canvas of={ExpandableTextStories.DoSecondaryDescription} />
|
|
74
|
+
<Verdict
|
|
75
|
+
kind="do"
|
|
76
|
+
en="Clip a long secondary description so the cards in a row stay the same height."
|
|
77
|
+
ko="긴 보조 설명을 접어서, 한 줄에 놓인 카드들의 높이를 맞춥니다."
|
|
78
|
+
/>
|
|
79
|
+
|
|
80
|
+
<Canvas of={ExpandableTextStories.DontClipTheMessage} />
|
|
81
|
+
<Verdict
|
|
82
|
+
kind="dont"
|
|
83
|
+
en="Clip a warning. The consequence sits behind 더보기, where most people never look."
|
|
84
|
+
ko="경고를 접지 마세요. 결과가 '더보기' 뒤에 숨어 대부분의 사람이 보지 못합니다."
|
|
85
|
+
/>
|
|
86
|
+
|
|
87
|
+
<En>
|
|
88
|
+
|
|
89
|
+
## Content
|
|
90
|
+
|
|
91
|
+
- Put the most important sentence first, so the clipped lines still say what
|
|
92
|
+
the text is about.
|
|
93
|
+
- Keep `lineClamp` the same for every item in a list.
|
|
94
|
+
|
|
95
|
+
## Accessibility
|
|
96
|
+
|
|
97
|
+
What ExpandableText does for you:
|
|
98
|
+
|
|
99
|
+
- The toggle is a `<button>` styled as a link, with `aria-expanded`, and a
|
|
100
|
+
translated label (더보기 / 접기) (WCAG 2.1.1, 4.1.2).
|
|
101
|
+
- The full text is in the DOM while closed; only its height is clipped, so
|
|
102
|
+
find-in-page and text selection reach it.
|
|
103
|
+
|
|
104
|
+
What you still have to do:
|
|
105
|
+
|
|
106
|
+
- While closed, the hidden lines are still read by a screen reader (they are
|
|
107
|
+
only clipped visually). Do not rely on the clamp to shorten what is
|
|
108
|
+
announced.
|
|
109
|
+
- Do not use a heading tier (`H1`–`H5`) for a long paragraph only to get its
|
|
110
|
+
size; the whole paragraph becomes a heading (`ACCESSIBILITY.md` §2).
|
|
111
|
+
- Known markup issue: the clipping box is a `<div>` inside the `<p>` (or
|
|
112
|
+
heading) that `component` renders, which a markup validator reports as a
|
|
113
|
+
nesting error (KWCAG 5.4.1.1). Tracked in the PR that added this page.
|
|
114
|
+
|
|
115
|
+
## Tokens
|
|
116
|
+
|
|
117
|
+
The toggle is a `Link`; on hover it turns `fg.default` instead of
|
|
118
|
+
`fg.linkHover`, and it has no underline.
|
|
119
|
+
|
|
120
|
+
</En>
|
|
121
|
+
|
|
122
|
+
<Ko>
|
|
123
|
+
|
|
124
|
+
## 문구
|
|
125
|
+
|
|
126
|
+
- 가장 중요한 문장을 앞에 둡니다. 그래야 접힌 상태에서도 무엇에 관한 글인지 알 수
|
|
127
|
+
있습니다.
|
|
128
|
+
- 한 목록 안의 항목은 모두 같은 `lineClamp`를 씁니다.
|
|
129
|
+
|
|
130
|
+
## 접근성
|
|
131
|
+
|
|
132
|
+
ExpandableText가 알아서 하는 일
|
|
133
|
+
|
|
134
|
+
- 펼침 버튼은 링크 모양의 `<button>`이고, `aria-expanded`와 번역된 이름('더보기' /
|
|
135
|
+
'접기')이 있습니다(WCAG 2.1.1, 4.1.2).
|
|
136
|
+
- 접혀 있어도 전체 글이 DOM에 있고 높이만 잘립니다. 그래서 페이지 내 검색과 글 선택이
|
|
137
|
+
닿습니다.
|
|
138
|
+
|
|
139
|
+
직접 챙겨야 하는 일
|
|
140
|
+
|
|
141
|
+
- 접혀 있어도 화면 낭독기는 숨은 줄까지 읽습니다(화면에서만 잘립니다). 읽히는 양을
|
|
142
|
+
줄이는 용도로 쓰지 않습니다.
|
|
143
|
+
- 크기만 보고 긴 문단에 제목 단계(`H1`–`H5`)를 쓰지 않습니다. 문단 전체가 제목이
|
|
144
|
+
됩니다(`ACCESSIBILITY.md` 2절).
|
|
145
|
+
- 알려진 마크업 문제: 자르는 상자가 `component`가 그리는 `<p>`(또는 제목) 안의
|
|
146
|
+
`<div>`라서, 마크업 검사기가 중첩 오류로 봅니다(KWCAG 5.4.1.1). 이 페이지를 추가한
|
|
147
|
+
PR에 기록해 두었습니다.
|
|
148
|
+
|
|
149
|
+
## 토큰
|
|
150
|
+
|
|
151
|
+
펼침 버튼은 `Link`입니다. 호버하면 `fg.linkHover`가 아니라 `fg.default`로 바뀌고,
|
|
152
|
+
밑줄이 없습니다.
|
|
153
|
+
|
|
154
|
+
</Ko>
|
|
155
|
+
|
|
156
|
+
<Canvas of={ExpandableTextStories.UsageTokens} sourceState="none" />
|
|
157
|
+
|
|
158
|
+
<En>
|
|
159
|
+
|
|
160
|
+
## Related
|
|
161
|
+
|
|
162
|
+
- **Collapsible**: a section with a trigger.
|
|
163
|
+
- **Typography**: the tiers `component` can use.
|
|
164
|
+
- **Markdown**: formatted long text.
|
|
165
|
+
|
|
166
|
+
</En>
|
|
167
|
+
|
|
168
|
+
<Ko>
|
|
169
|
+
|
|
170
|
+
## 관련 컴포넌트
|
|
171
|
+
|
|
172
|
+
- **Collapsible**: 트리거가 있는 섹션.
|
|
173
|
+
- **Typography**: `component`로 고를 수 있는 글자 단계.
|
|
174
|
+
- **Markdown**: 서식 있는 긴 글.
|
|
175
|
+
|
|
176
|
+
</Ko>
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
|
|
4
|
+
import { Stack } from '@chakra-ui/react';
|
|
5
|
+
|
|
6
|
+
import { FieldRow } from '../Form';
|
|
4
7
|
import { FileInput } from '.';
|
|
5
8
|
|
|
6
|
-
|
|
9
|
+
const meta = {
|
|
7
10
|
title: 'Components/FileInput',
|
|
8
11
|
component: FileInput,
|
|
9
12
|
args: {
|
|
@@ -36,3 +39,37 @@ export const Basic: Story = {
|
|
|
36
39
|
return <FileInput onChange={handleChange} bgImage={bgImage} />;
|
|
37
40
|
},
|
|
38
41
|
};
|
|
42
|
+
|
|
43
|
+
// ───────────────────────── Usage-page specimens ─────────────────────────
|
|
44
|
+
// Pulled into `FileInput.usage.mdx` with <Canvas of={…} />. Hidden (`!dev`).
|
|
45
|
+
|
|
46
|
+
export const DoSayWhatFits: Story = {
|
|
47
|
+
tags: ['!dev'],
|
|
48
|
+
parameters: { layout: 'padded' },
|
|
49
|
+
name: 'Usage / Do: say which files fit',
|
|
50
|
+
render: () => (
|
|
51
|
+
<Stack maxW="420px">
|
|
52
|
+
<FieldRow
|
|
53
|
+
label="멤버 목록 파일"
|
|
54
|
+
helperText="CSV 또는 XLSX, 최대 5MB. 첫 줄은 이메일, 이름 순서입니다."
|
|
55
|
+
>
|
|
56
|
+
<FileInput
|
|
57
|
+
accept=".csv,.xlsx"
|
|
58
|
+
fileInputLabel="파일을 눌러서 고르기"
|
|
59
|
+
onChange={() => {}}
|
|
60
|
+
/>
|
|
61
|
+
</FieldRow>
|
|
62
|
+
</Stack>
|
|
63
|
+
),
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const DontUnexplained: Story = {
|
|
67
|
+
tags: ['!dev'],
|
|
68
|
+
parameters: { layout: 'padded' },
|
|
69
|
+
name: "Usage / Don't: no type, size or purpose",
|
|
70
|
+
render: () => (
|
|
71
|
+
<Stack maxW="420px">
|
|
72
|
+
<FileInput onChange={() => {}} />
|
|
73
|
+
</Stack>
|
|
74
|
+
),
|
|
75
|
+
};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { ArgTypes, Canvas, Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
import { En, Ko, LangToggle, Verdict } from '../../guidelines/_components/Lang';
|
|
4
|
+
import * as FileInputStories from './FileInput.stories';
|
|
5
|
+
|
|
6
|
+
<Meta of={FileInputStories} name="Usage" />
|
|
7
|
+
|
|
8
|
+
<LangToggle />
|
|
9
|
+
|
|
10
|
+
<En>
|
|
11
|
+
|
|
12
|
+
# FileInput
|
|
13
|
+
|
|
14
|
+
A dashed area that opens the system file picker when clicked, with an
|
|
15
|
+
optional image preview behind it.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
- Uploading a file into a form: a member list CSV, a policy document,
|
|
20
|
+
reference images, a project file.
|
|
21
|
+
- Replacing an image, with the current one shown through `bgImage`.
|
|
22
|
+
|
|
23
|
+
## When not to use
|
|
24
|
+
|
|
25
|
+
- Attaching files to a chat message → the chat composer's attach button.
|
|
26
|
+
- Showing files already uploaded → `FileList` or `FileItem` (put them under
|
|
27
|
+
the FileInput).
|
|
28
|
+
|
|
29
|
+
## Props
|
|
30
|
+
|
|
31
|
+
</En>
|
|
32
|
+
|
|
33
|
+
<Ko>
|
|
34
|
+
|
|
35
|
+
# FileInput
|
|
36
|
+
|
|
37
|
+
누르면 시스템 파일 선택 창이 열리는 점선 영역입니다. 뒤에 이미지 미리보기를 깔 수
|
|
38
|
+
있습니다.
|
|
39
|
+
|
|
40
|
+
## 언제 쓰나요
|
|
41
|
+
|
|
42
|
+
- 폼에 파일을 올릴 때: 멤버 목록 CSV, 정책 문서, 참고 이미지, 프로젝트 파일.
|
|
43
|
+
- 이미지를 바꿀 때. 지금 이미지는 `bgImage`로 보여 줍니다.
|
|
44
|
+
|
|
45
|
+
## 언제 쓰지 않나요
|
|
46
|
+
|
|
47
|
+
- 채팅 메시지에 파일을 붙일 때는 채팅 입력창의 첨부 버튼을 씁니다.
|
|
48
|
+
- 이미 올린 파일을 보여 줄 때는 `FileList`나 `FileItem`을 씁니다(FileInput 아래에
|
|
49
|
+
둡니다).
|
|
50
|
+
|
|
51
|
+
## 속성
|
|
52
|
+
|
|
53
|
+
</Ko>
|
|
54
|
+
|
|
55
|
+
<ArgTypes
|
|
56
|
+
of={FileInputStories}
|
|
57
|
+
include={[
|
|
58
|
+
'onChange',
|
|
59
|
+
'fileInputLabel',
|
|
60
|
+
'bgImage',
|
|
61
|
+
'isLoading',
|
|
62
|
+
'containerStyle',
|
|
63
|
+
]}
|
|
64
|
+
/>
|
|
65
|
+
|
|
66
|
+
<En>
|
|
67
|
+
|
|
68
|
+
`onChange` receives the browser's `FileList` (or `null`). Native input props
|
|
69
|
+
such as `accept`, `multiple` and `name` pass through to the hidden
|
|
70
|
+
`<input type="file">`, and the forwarded ref points at it. `isLoading`
|
|
71
|
+
replaces the prompt with a spinner. The default prompt is translated
|
|
72
|
+
(`upload_your_file`). The area does not handle drag and drop.
|
|
73
|
+
|
|
74
|
+
## Do / Don't
|
|
75
|
+
|
|
76
|
+
</En>
|
|
77
|
+
|
|
78
|
+
<Ko>
|
|
79
|
+
|
|
80
|
+
`onChange`는 브라우저의 `FileList`(또는 `null`)를 받습니다. `accept`, `multiple`,
|
|
81
|
+
`name` 같은 네이티브 속성은 숨은 `<input type="file">`에 그대로 전달되고, 넘긴 ref도 이
|
|
82
|
+
입력을 가리킵니다. `isLoading`이면 안내 문구 대신 스피너를 보여 줍니다. 기본 안내
|
|
83
|
+
문구는 번역됩니다(`upload_your_file`). 끌어다 놓기는 처리하지 않습니다.
|
|
84
|
+
|
|
85
|
+
## 이렇게 하세요 / 이렇게 하지 마세요
|
|
86
|
+
|
|
87
|
+
</Ko>
|
|
88
|
+
|
|
89
|
+
<Canvas of={FileInputStories.DoSayWhatFits} />
|
|
90
|
+
<Verdict
|
|
91
|
+
kind="do"
|
|
92
|
+
en="Label it, set accept, and say the allowed types, size limit and expected layout in helper text."
|
|
93
|
+
ko="라벨을 붙이고 accept를 지정하며, 받는 형식, 최대 크기, 내용 형식을 도움말로 알려 줍니다."
|
|
94
|
+
/>
|
|
95
|
+
|
|
96
|
+
<Canvas of={FileInputStories.DontUnexplained} />
|
|
97
|
+
<Verdict
|
|
98
|
+
kind="dont"
|
|
99
|
+
en="Show the drop area with only the default prompt. The user finds out the rules by failing."
|
|
100
|
+
ko="기본 안내 문구만 있는 영역을 두지 마세요. 사용자는 실패하고 나서야 조건을 압니다."
|
|
101
|
+
/>
|
|
102
|
+
|
|
103
|
+
<En>
|
|
104
|
+
|
|
105
|
+
## Content
|
|
106
|
+
|
|
107
|
+
- The prompt says what to do with the pointer (파일을 눌러서 고르기). Do not
|
|
108
|
+
promise dragging; it is not supported.
|
|
109
|
+
- Types and size limit go in `FieldRow` `helperText`, the same words the
|
|
110
|
+
error will use.
|
|
111
|
+
|
|
112
|
+
## Accessibility
|
|
113
|
+
|
|
114
|
+
What FileInput does for you:
|
|
115
|
+
|
|
116
|
+
- The prompt sits inside a `<label>` around the file input, so clicking
|
|
117
|
+
anywhere in it opens the picker. There is no extra role on the wrapper
|
|
118
|
+
(`ACCESSIBILITY.md` §3).
|
|
119
|
+
|
|
120
|
+
Known gap, and what to do:
|
|
121
|
+
|
|
122
|
+
- **It cannot be reached by keyboard.** The file input is `hidden`, so it is
|
|
123
|
+
out of the tab order and the label is not focusable (WCAG 2.1.1). Until the
|
|
124
|
+
component is fixed, add a visible `Button` next to it that calls
|
|
125
|
+
`ref.current?.click()`.
|
|
126
|
+
- Wrap it in `FieldRow` with a label so the purpose is in text (WCAG 3.3.2),
|
|
127
|
+
and report rejected files in words, not only with the red row in
|
|
128
|
+
`FileItem` (WCAG 3.3.1).
|
|
129
|
+
|
|
130
|
+
## Tokens
|
|
131
|
+
|
|
132
|
+
The dashed border is `border.default`; the prompt and icon are `fg.subtle` on
|
|
133
|
+
a `bg.muted` tile, over an 85% `bg.surface` wash. With `bgImage` the prompt
|
|
134
|
+
turns `fg.default` and appears on hover.
|
|
135
|
+
|
|
136
|
+
## Related
|
|
137
|
+
|
|
138
|
+
- **FileList** / **FileItem**: what was uploaded.
|
|
139
|
+
- **FieldRow**: label, rules and error.
|
|
140
|
+
|
|
141
|
+
</En>
|
|
142
|
+
|
|
143
|
+
<Ko>
|
|
144
|
+
|
|
145
|
+
## 문구
|
|
146
|
+
|
|
147
|
+
- 안내 문구에는 포인터로 할 일을 씁니다(파일을 눌러서 고르기). 끌어다 놓기는 지원하지
|
|
148
|
+
않으므로 약속하지 않습니다.
|
|
149
|
+
- 형식과 최대 크기는 `FieldRow`의 `helperText`에 쓰고, 오류 문구에서도 같은 표현을
|
|
150
|
+
씁니다.
|
|
151
|
+
|
|
152
|
+
## 접근성
|
|
153
|
+
|
|
154
|
+
FileInput이 알아서 하는 일
|
|
155
|
+
|
|
156
|
+
- 안내 문구가 파일 입력을 감싼 `<label>` 안에 있어서 영역 어디를 눌러도 선택 창이
|
|
157
|
+
열립니다. 감싸는 요소에 불필요한 역할을 주지 않습니다(`ACCESSIBILITY.md` 3절).
|
|
158
|
+
|
|
159
|
+
알려진 한계와 대처
|
|
160
|
+
|
|
161
|
+
- **키보드로 닿을 수 없습니다.** 파일 입력이 `hidden`이라 Tab 순서에서 빠지고, 라벨도
|
|
162
|
+
초점을 받지 않습니다(WCAG 2.1.1). 고쳐지기 전까지는 옆에 `ref.current?.click()`을
|
|
163
|
+
호출하는 보이는 `Button`을 둡니다.
|
|
164
|
+
- 라벨이 있는 `FieldRow`로 감싸 용도를 글자로 알리고(WCAG 3.3.2), 받지 못한 파일은
|
|
165
|
+
`FileItem`의 빨간 행만이 아니라 문구로 알립니다(WCAG 3.3.1).
|
|
166
|
+
|
|
167
|
+
## 토큰
|
|
168
|
+
|
|
169
|
+
점선 테두리는 `border.default`, 안내 문구와 아이콘은 `bg.muted` 타일 위의
|
|
170
|
+
`fg.subtle`이며, 바탕은 85% `bg.surface`입니다. `bgImage`가 있으면 안내 문구가
|
|
171
|
+
`fg.default`로 바뀌고 마우스를 올렸을 때 나타납니다.
|
|
172
|
+
|
|
173
|
+
## 관련 컴포넌트
|
|
174
|
+
|
|
175
|
+
- **FileList** / **FileItem**: 올린 파일.
|
|
176
|
+
- **FieldRow**: 라벨, 조건, 오류 문구.
|
|
177
|
+
|
|
178
|
+
</Ko>
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react';
|
|
2
2
|
|
|
3
|
+
import { Stack } from '@chakra-ui/react';
|
|
4
|
+
|
|
5
|
+
import { T } from '../../guidelines/_components/Lang';
|
|
6
|
+
import { TokenTable } from '../../guidelines/_components/TokenTable';
|
|
7
|
+
import { FieldRow } from '../Form';
|
|
3
8
|
import { FileItem } from './FileItem';
|
|
4
9
|
|
|
5
10
|
const meta = {
|
|
@@ -53,3 +58,69 @@ export const Deleting: Story = {
|
|
|
53
58
|
isDeleting: true,
|
|
54
59
|
},
|
|
55
60
|
};
|
|
61
|
+
|
|
62
|
+
// ───────────────────────── Usage-page specimens ─────────────────────────
|
|
63
|
+
// Pulled into `FileItem.usage.mdx` with <Canvas of={…} />. Hidden (`!dev`).
|
|
64
|
+
|
|
65
|
+
export const DoErrorInText: Story = {
|
|
66
|
+
tags: ['!dev'],
|
|
67
|
+
parameters: { layout: 'padded' },
|
|
68
|
+
name: 'Usage / Do: repeat the error in text',
|
|
69
|
+
render: () => (
|
|
70
|
+
<Stack maxW="480px">
|
|
71
|
+
<FieldRow error="members.xlsx: 파일이 5MB를 넘습니다. 나눠서 올려 주세요.">
|
|
72
|
+
<FileItem
|
|
73
|
+
fileName="members.xlsx"
|
|
74
|
+
error="파일이 5MB를 넘습니다."
|
|
75
|
+
onFileDelete={() => {}}
|
|
76
|
+
/>
|
|
77
|
+
</FieldRow>
|
|
78
|
+
</Stack>
|
|
79
|
+
),
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const DontErrorInTooltipOnly: Story = {
|
|
83
|
+
tags: ['!dev'],
|
|
84
|
+
parameters: { layout: 'padded' },
|
|
85
|
+
name: "Usage / Don't: the reason only in a tooltip",
|
|
86
|
+
render: () => (
|
|
87
|
+
<Stack maxW="480px">
|
|
88
|
+
<FileItem
|
|
89
|
+
fileName="members.xlsx"
|
|
90
|
+
error="파일이 5MB를 넘습니다."
|
|
91
|
+
onFileDelete={() => {}}
|
|
92
|
+
/>
|
|
93
|
+
</Stack>
|
|
94
|
+
),
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/** Tokens `FileItem.tsx` reads. */
|
|
98
|
+
export const UsageTokens: Story = {
|
|
99
|
+
tags: ['!dev'],
|
|
100
|
+
parameters: { layout: 'padded' },
|
|
101
|
+
name: 'Usage / Tokens',
|
|
102
|
+
render: () => (
|
|
103
|
+
<TokenTable
|
|
104
|
+
rows={[
|
|
105
|
+
{ token: 'border.subtle', use: <T en="Row border" ko="행 테두리" /> },
|
|
106
|
+
{
|
|
107
|
+
token: 'fg.muted',
|
|
108
|
+
use: <T en="File icon, action icons" ko="파일 아이콘, 동작 아이콘" />,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
token: 'fg.subtle',
|
|
112
|
+
use: <T en="Cancel-upload icon" ko="업로드 취소 아이콘" />,
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
token: 'danger.fg',
|
|
116
|
+
use: (
|
|
117
|
+
<T
|
|
118
|
+
en="Error: left bar, icon, file name"
|
|
119
|
+
ko="오류: 왼쪽 막대, 아이콘, 파일 이름"
|
|
120
|
+
/>
|
|
121
|
+
),
|
|
122
|
+
},
|
|
123
|
+
]}
|
|
124
|
+
/>
|
|
125
|
+
),
|
|
126
|
+
};
|