@mindlogic-ai/logician-ui 5.0.0-alpha.3 → 5.0.0-alpha.5

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.
Files changed (242) hide show
  1. package/dist/components/Banner/Banner.types.d.ts +24 -1
  2. package/dist/components/Banner/Banner.types.d.ts.map +1 -1
  3. package/dist/components/Card/Card.types.d.ts +12 -0
  4. package/dist/components/Card/Card.types.d.ts.map +1 -1
  5. package/dist/components/ColorMode/ColorModeToggle.d.ts +7 -2
  6. package/dist/components/ColorMode/ColorModeToggle.d.ts.map +1 -1
  7. package/dist/components/ColorMode/ColorModeToggle.js +8 -3
  8. package/dist/components/ColorMode/ColorModeToggle.js.map +1 -1
  9. package/dist/components/ColorMode/ColorModeToggle.mjs +8 -3
  10. package/dist/components/ColorMode/ColorModeToggle.mjs.map +1 -1
  11. package/dist/components/Confetti/Confetti.types.d.ts +5 -1
  12. package/dist/components/Confetti/Confetti.types.d.ts.map +1 -1
  13. package/dist/components/Confetti/confettiColors.d.ts +5 -5
  14. package/dist/components/Confetti/confettiColors.js +5 -5
  15. package/dist/components/Confetti/confettiColors.mjs +5 -5
  16. package/dist/components/ErrorFallback/ErrorFallback.types.d.ts +6 -0
  17. package/dist/components/ErrorFallback/ErrorFallback.types.d.ts.map +1 -1
  18. package/dist/components/Form/FormModalFooter/FormModalFooter.types.d.ts +4 -1
  19. package/dist/components/Form/FormModalFooter/FormModalFooter.types.d.ts.map +1 -1
  20. package/dist/components/LineGraph/LineGraph.d.ts.map +1 -1
  21. package/dist/components/LineGraph/LineGraph.js +4 -5
  22. package/dist/components/LineGraph/LineGraph.js.map +1 -1
  23. package/dist/components/LineGraph/LineGraph.mjs +5 -6
  24. package/dist/components/LineGraph/LineGraph.mjs.map +1 -1
  25. package/dist/components/LineGraph/LineGraph.types.d.ts +12 -2
  26. package/dist/components/LineGraph/LineGraph.types.d.ts.map +1 -1
  27. package/dist/components/LineGraph/seriesColors.d.ts +12 -8
  28. package/dist/components/LineGraph/seriesColors.d.ts.map +1 -1
  29. package/dist/components/LineGraph/seriesColors.js +8 -7
  30. package/dist/components/LineGraph/seriesColors.js.map +1 -1
  31. package/dist/components/LineGraph/seriesColors.mjs +8 -7
  32. package/dist/components/LineGraph/seriesColors.mjs.map +1 -1
  33. package/dist/components/Masonry/Masonry.types.d.ts +8 -3
  34. package/dist/components/Masonry/Masonry.types.d.ts.map +1 -1
  35. package/dist/components/Menu/MenuItem.types.d.ts +8 -0
  36. package/dist/components/Menu/MenuItem.types.d.ts.map +1 -1
  37. package/dist/components/Modal/ModalCloseButton.d.ts +1 -1
  38. package/dist/components/Modal/ModalCloseButton.js +1 -1
  39. package/dist/components/Modal/ModalCloseButton.mjs +1 -1
  40. package/dist/components/Pagination/Pagination.d.ts +11 -10
  41. package/dist/components/Pagination/Pagination.d.ts.map +1 -1
  42. package/dist/components/Pagination/Pagination.js +11 -10
  43. package/dist/components/Pagination/Pagination.js.map +1 -1
  44. package/dist/components/Pagination/Pagination.mjs +11 -10
  45. package/dist/components/Pagination/Pagination.mjs.map +1 -1
  46. package/dist/components/ProgressBar/ProgressBar.types.d.ts +9 -0
  47. package/dist/components/ProgressBar/ProgressBar.types.d.ts.map +1 -1
  48. package/dist/components/RadialProgress/RadialProgress.types.d.ts +21 -1
  49. package/dist/components/RadialProgress/RadialProgress.types.d.ts.map +1 -1
  50. package/dist/components/SeeMoreButton/SeeMoreButton.types.d.ts +8 -0
  51. package/dist/components/SeeMoreButton/SeeMoreButton.types.d.ts.map +1 -1
  52. package/dist/components/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  53. package/dist/components/SegmentedControl/SegmentedControl.js +6 -7
  54. package/dist/components/SegmentedControl/SegmentedControl.js.map +1 -1
  55. package/dist/components/SegmentedControl/SegmentedControl.mjs +6 -7
  56. package/dist/components/SegmentedControl/SegmentedControl.mjs.map +1 -1
  57. package/dist/components/SegmentedProgressBar/SegmentedProgressBar.types.d.ts +2 -0
  58. package/dist/components/SegmentedProgressBar/SegmentedProgressBar.types.d.ts.map +1 -1
  59. package/dist/components/Toast/Toast.styles.d.ts +6 -2
  60. package/dist/components/Toast/Toast.styles.d.ts.map +1 -1
  61. package/dist/components/Toast/Toast.styles.js +18 -10
  62. package/dist/components/Toast/Toast.styles.js.map +1 -1
  63. package/dist/components/Toast/Toast.styles.mjs +18 -10
  64. package/dist/components/Toast/Toast.styles.mjs.map +1 -1
  65. package/dist/theme/colors.d.ts +2 -2
  66. package/dist/theme/colors.d.ts.map +1 -1
  67. package/dist/theme/colors.js +22 -2
  68. package/dist/theme/colors.js.map +1 -1
  69. package/dist/theme/colors.mjs +23 -3
  70. package/dist/theme/colors.mjs.map +1 -1
  71. package/dist/theme/palette.generated.d.ts +98 -0
  72. package/dist/theme/palette.generated.d.ts.map +1 -1
  73. package/dist/theme/palette.generated.js +99 -0
  74. package/dist/theme/palette.generated.js.map +1 -1
  75. package/dist/theme/palette.generated.mjs +99 -1
  76. package/dist/theme/palette.generated.mjs.map +1 -1
  77. package/dist/theme/paletteSwatches.d.ts +20 -0
  78. package/dist/theme/paletteSwatches.d.ts.map +1 -1
  79. package/package.json +1 -1
  80. package/src/components/Accordion/Accordion.stories.tsx +85 -0
  81. package/src/components/Accordion/Accordion.usage.mdx +200 -0
  82. package/src/components/Appear/Appear.usage.mdx +107 -0
  83. package/src/components/Avatar/Avatar.stories.tsx +71 -1
  84. package/src/components/Avatar/Avatar.usage.mdx +166 -0
  85. package/src/components/Banner/Banner.stories.tsx +152 -2
  86. package/src/components/Banner/Banner.types.ts +30 -1
  87. package/src/components/Banner/Banner.usage.mdx +233 -0
  88. package/src/components/BottomSheet/BottomSheet.stories.tsx +168 -1
  89. package/src/components/BottomSheet/BottomSheet.usage.mdx +216 -0
  90. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +59 -0
  91. package/src/components/Breadcrumb/Breadcrumb.usage.mdx +181 -0
  92. package/src/components/Button/Button.stories.tsx +263 -3
  93. package/src/components/Button/Button.usage.mdx +342 -0
  94. package/src/components/Card/Card.stories.tsx +106 -0
  95. package/src/components/Card/Card.types.ts +12 -0
  96. package/src/components/Card/Card.usage.mdx +216 -0
  97. package/src/components/Checkbox/Checkbox.stories.tsx +140 -13
  98. package/src/components/Checkbox/Checkbox.usage.mdx +214 -0
  99. package/src/components/Chip/Chip.usage.mdx +78 -0
  100. package/src/components/Code/Code.stories.tsx +60 -0
  101. package/src/components/Code/Code.usage.mdx +187 -0
  102. package/src/components/CodeTabs/CodeTabs.stories.tsx +53 -0
  103. package/src/components/CodeTabs/CodeTabs.usage.mdx +176 -0
  104. package/src/components/Collapsible/Collapsible.stories.tsx +58 -0
  105. package/src/components/Collapsible/Collapsible.usage.mdx +173 -0
  106. package/src/components/ColorMode/ColorMode.stories.tsx +50 -0
  107. package/src/components/ColorMode/ColorMode.usage.mdx +135 -0
  108. package/src/components/ColorMode/ColorModeToggle.tsx +10 -3
  109. package/src/components/Confetti/Confetti.types.ts +5 -1
  110. package/src/components/Confetti/Confetti.usage.mdx +111 -0
  111. package/src/components/Confetti/confettiColors.ts +5 -5
  112. package/src/components/Container/Container.stories.tsx +32 -0
  113. package/src/components/Container/Container.usage.mdx +130 -0
  114. package/src/components/CopyableCode/CopyableCode.stories.tsx +62 -0
  115. package/src/components/CopyableCode/CopyableCode.usage.mdx +168 -0
  116. package/src/components/CountBadge/CountBadge.stories.tsx +69 -0
  117. package/src/components/CountBadge/CountBadge.usage.mdx +215 -0
  118. package/src/components/CountUp/CountUp.usage.mdx +107 -0
  119. package/src/components/DatePicker/DatePicker.usage.mdx +177 -0
  120. package/src/components/DatePicker/RangeDatePicker.stories.tsx +87 -3
  121. package/src/components/ErrorFallback/ErrorFallback.types.ts +6 -0
  122. package/src/components/ErrorFallback/ErrorFallback.usage.mdx +127 -0
  123. package/src/components/ExpandableText/ExpandableText.stories.tsx +55 -0
  124. package/src/components/ExpandableText/ExpandableText.usage.mdx +176 -0
  125. package/src/components/FileInput/FileInput.stories.tsx +38 -1
  126. package/src/components/FileInput/FileInput.usage.mdx +178 -0
  127. package/src/components/FileItem/FileItem.stories.tsx +71 -0
  128. package/src/components/FileItem/FileItem.usage.mdx +180 -0
  129. package/src/components/FileList/FileList.stories.tsx +25 -0
  130. package/src/components/FileList/FileList.usage.mdx +165 -0
  131. package/src/components/FlyTo/FlyTo.usage.mdx +99 -0
  132. package/src/components/Form/Form.stories.tsx +149 -0
  133. package/src/components/Form/Form.usage.mdx +201 -0
  134. package/src/components/Form/FormModalFooter/FormModalFooter.types.ts +4 -1
  135. package/src/components/FormControl/FormControl.stories.tsx +35 -0
  136. package/src/components/FormControl/FormControl.usage.mdx +128 -0
  137. package/src/components/FormIntegration/FormIntegration.usage.mdx +158 -0
  138. package/src/components/FormLabel/FormLabel.stories.tsx +71 -0
  139. package/src/components/FormLabel/FormLabel.usage.mdx +125 -0
  140. package/src/components/Icon/Icon.stories.tsx +61 -1
  141. package/src/components/Icon/Icon.usage.mdx +158 -0
  142. package/src/components/IconButton/IconButton.stories.tsx +209 -5
  143. package/src/components/IconButton/IconButton.usage.mdx +273 -0
  144. package/src/components/InfoSprinkle/InfoSprinkle.stories.tsx +77 -1
  145. package/src/components/InfoSprinkle/InfoSprinkle.usage.mdx +189 -0
  146. package/src/components/InlineCode/InlineCode.stories.tsx +75 -0
  147. package/src/components/InlineCode/InlineCode.usage.mdx +142 -0
  148. package/src/components/Input/Input.stories.tsx +180 -0
  149. package/src/components/Input/Input.usage.mdx +278 -0
  150. package/src/components/LineGraph/LineGraph.stories.tsx +112 -0
  151. package/src/components/LineGraph/LineGraph.tsx +4 -5
  152. package/src/components/LineGraph/LineGraph.types.ts +12 -2
  153. package/src/components/LineGraph/LineGraph.usage.mdx +186 -0
  154. package/src/components/LineGraph/seriesColors.test.ts +11 -10
  155. package/src/components/LineGraph/seriesColors.ts +18 -16
  156. package/src/components/Loaders/Loaders.stories.tsx +93 -0
  157. package/src/components/Loaders/Loaders.usage.mdx +180 -0
  158. package/src/components/LogicianProvider/LogicianProvider.usage.mdx +98 -0
  159. package/src/components/Markdown/Markdown.stories.tsx +53 -0
  160. package/src/components/Markdown/Markdown.usage.mdx +182 -0
  161. package/src/components/Masonry/Masonry.stories.tsx +63 -1
  162. package/src/components/Masonry/Masonry.types.ts +8 -3
  163. package/src/components/Masonry/Masonry.usage.mdx +142 -0
  164. package/src/components/MaxLengthIndicator/MaxLengthIndicator.stories.tsx +57 -0
  165. package/src/components/MaxLengthIndicator/MaxLengthIndicator.usage.mdx +125 -0
  166. package/src/components/Menu/Menu.stories.tsx +146 -2
  167. package/src/components/Menu/Menu.usage.mdx +230 -0
  168. package/src/components/Menu/MenuItem.types.ts +8 -0
  169. package/src/components/Modal/Modal.stories.tsx +177 -1
  170. package/src/components/Modal/Modal.usage.mdx +262 -0
  171. package/src/components/Modal/ModalCloseButton.tsx +1 -1
  172. package/src/components/MonthPicker/MonthPicker.stories.tsx +30 -0
  173. package/src/components/MonthPicker/MonthPicker.usage.mdx +191 -0
  174. package/src/components/Pagination/Pagination.stories.tsx +90 -1
  175. package/src/components/Pagination/Pagination.tsx +11 -10
  176. package/src/components/Pagination/Pagination.usage.mdx +186 -0
  177. package/src/components/PasswordInput/PasswordInput.stories.tsx +51 -0
  178. package/src/components/PasswordInput/PasswordInput.usage.mdx +193 -0
  179. package/src/components/PinInput/PinInput.stories.tsx +91 -0
  180. package/src/components/PinInput/PinInput.usage.mdx +194 -0
  181. package/src/components/Popover/Popover.stories.tsx +104 -1
  182. package/src/components/Popover/Popover.usage.mdx +197 -0
  183. package/src/components/ProgressBar/ProgressBar.stories.tsx +92 -1
  184. package/src/components/ProgressBar/ProgressBar.types.ts +9 -0
  185. package/src/components/ProgressBar/ProgressBar.usage.mdx +210 -0
  186. package/src/components/Pulse/Pulse.usage.mdx +102 -0
  187. package/src/components/RadialProgress/RadialProgress.stories.tsx +74 -1
  188. package/src/components/RadialProgress/RadialProgress.types.ts +21 -1
  189. package/src/components/RadialProgress/RadialProgress.usage.mdx +153 -0
  190. package/src/components/Radio/Radio.stories.tsx +119 -0
  191. package/src/components/Radio/Radio.usage.mdx +187 -0
  192. package/src/components/Reveal/Reveal.usage.mdx +105 -0
  193. package/src/components/ScaledContext/ScaledContext.usage.mdx +111 -0
  194. package/src/components/SeeMoreButton/SeeMoreButton.stories.tsx +146 -2
  195. package/src/components/SeeMoreButton/SeeMoreButton.types.ts +8 -0
  196. package/src/components/SeeMoreButton/SeeMoreButton.usage.mdx +213 -0
  197. package/src/components/SegmentedControl/SegmentedControl.stories.tsx +69 -0
  198. package/src/components/SegmentedControl/SegmentedControl.tsx +6 -7
  199. package/src/components/SegmentedControl/SegmentedControl.usage.mdx +209 -0
  200. package/src/components/SegmentedProgressBar/SegmentedProgressBar.stories.tsx +54 -0
  201. package/src/components/SegmentedProgressBar/SegmentedProgressBar.types.ts +2 -0
  202. package/src/components/SegmentedProgressBar/SegmentedProgressBar.usage.mdx +145 -0
  203. package/src/components/Select/Select.stories.tsx +209 -1
  204. package/src/components/Select/Select.usage.mdx +278 -0
  205. package/src/components/Shake/Shake.usage.mdx +107 -0
  206. package/src/components/Slider/Slider.stories.tsx +116 -0
  207. package/src/components/Slider/Slider.usage.mdx +179 -0
  208. package/src/components/Spinner/Spinner.stories.tsx +64 -0
  209. package/src/components/Spinner/Spinner.usage.mdx +136 -0
  210. package/src/components/SwapTransition/SwapTransition.usage.mdx +102 -0
  211. package/src/components/Switch/Switch.stories.tsx +131 -6
  212. package/src/components/Switch/Switch.usage.mdx +199 -0
  213. package/src/components/Table/Table.stories.tsx +159 -1
  214. package/src/components/Table/Table.usage.mdx +235 -0
  215. package/src/components/Tabs/Tabs.stories.tsx +86 -0
  216. package/src/components/Tabs/Tabs.usage.mdx +219 -0
  217. package/src/components/Tag/Tag.stories.tsx +181 -4
  218. package/src/components/Tag/Tag.usage.mdx +257 -0
  219. package/src/components/Textarea/Textarea.stories.tsx +113 -0
  220. package/src/components/Textarea/Textarea.usage.mdx +186 -0
  221. package/src/components/Toast/Toast.stories.tsx +185 -3
  222. package/src/components/Toast/Toast.styles.ts +18 -10
  223. package/src/components/Toast/Toast.usage.mdx +265 -0
  224. package/src/components/Tooltip/Tooltip.stories.tsx +86 -1
  225. package/src/components/Tooltip/Tooltip.usage.mdx +211 -0
  226. package/src/components/Tree/Tree.stories.tsx +89 -0
  227. package/src/components/Tree/Tree.usage.mdx +207 -0
  228. package/src/components/Typography/Typography.stories.tsx +117 -0
  229. package/src/components/Typography/Typography.usage.mdx +251 -0
  230. package/src/components/Workflow/Workflow.usage.mdx +199 -0
  231. package/src/components/noRawScales.test.ts +5 -1
  232. package/src/foundations/BrandAssets.mdx +637 -0
  233. package/src/foundations/BrandAssets.stories.tsx +680 -0
  234. package/src/foundations/BrandColour.mdx +65 -2
  235. package/src/theme/BazePalette.stories.tsx +111 -1
  236. package/src/theme/Palette.stories.tsx +2 -2
  237. package/src/theme/SemanticTokens.mdx +75 -16
  238. package/src/theme/claude.md +15 -9
  239. package/src/theme/colors.ts +33 -3
  240. package/src/theme/contrast.test.ts +32 -0
  241. package/src/theme/palette.generated.ts +99 -0
  242. package/src/theme/paletteSwatches.ts +35 -0
@@ -1,6 +1,11 @@
1
+ import { Flex } from '@chakra-ui/react';
1
2
  import type { Meta, StoryObj } from '@storybook/react';
2
3
 
4
+ import { TokenTable } from '../../guidelines/_components/TokenTable';
5
+ import { Button } from '../Button';
6
+ import { Subtext, Text } from '../Typography';
3
7
  import { Card } from './Card';
8
+ import { clickableStyles, variantStyles } from './Card.styles';
4
9
 
5
10
  const meta = {
6
11
  title: 'Components/Card',
@@ -9,6 +14,15 @@ const meta = {
9
14
  children: 'Default Card',
10
15
  p: 8,
11
16
  },
17
+ argTypes: {
18
+ variant: {
19
+ control: 'select',
20
+ options: ['default', 'wash', 'elevated'],
21
+ description:
22
+ '`default`: `bg.surface` + `border.subtle` hairline. `wash`: `bg.muted`, no border — a block that summarises or concludes. `elevated`: soft `sm` shadow — a standalone raised object.',
23
+ table: { defaultValue: { summary: 'default' } },
24
+ },
25
+ },
12
26
  } satisfies Meta<typeof Card>;
13
27
 
14
28
  export default meta;
@@ -52,3 +66,95 @@ export const AsButton: Story = {
52
66
  <Card {...args} as="button" type="button" textAlign="left" />
53
67
  ),
54
68
  };
69
+
70
+ // ───────────────────────── Usage-page specimens ─────────────────────────
71
+ // Pulled into `Card.usage.mdx` with <Canvas of={…} />. Hidden from the
72
+ // sidebar (`!dev`); `tags` is written out on each story because the indexer
73
+ // reads CSF statically.
74
+
75
+ const CourseBody = () => (
76
+ <>
77
+ <Text fontWeight="bold">AI 글쓰기 기초</Text>
78
+ <Subtext color="fg.muted">수강생 42명 · 6주 과정</Subtext>
79
+ </>
80
+ );
81
+
82
+ export const DoClickableIsTheLink: Story = {
83
+ tags: ['!dev'],
84
+ parameters: { layout: 'padded' },
85
+ name: 'Usage / Do: a clickable card is the link',
86
+ render: () => (
87
+ <Card clickable as="a" href="#course-1" p={5} maxW="320px">
88
+ <CourseBody />
89
+ </Card>
90
+ ),
91
+ };
92
+
93
+ export const DontButtonInClickable: Story = {
94
+ tags: ['!dev'],
95
+ parameters: { layout: 'padded' },
96
+ name: "Usage / Don't: a second control inside a clickable card",
97
+ render: () => (
98
+ <Card clickable onClick={() => {}} p={5} maxW="320px">
99
+ <CourseBody />
100
+ <Flex mt={3}>
101
+ <Button size="sm" variant="secondary">
102
+ 삭제
103
+ </Button>
104
+ </Flex>
105
+ </Card>
106
+ ),
107
+ };
108
+
109
+ export const DoWashForSummary: Story = {
110
+ tags: ['!dev'],
111
+ parameters: { layout: 'padded' },
112
+ name: 'Usage / Do: wash for a summary or result',
113
+ render: () => (
114
+ <Card variant="wash" p={5} maxW="420px">
115
+ <Text fontWeight="bold" mb={1}>
116
+ 요약
117
+ </Text>
118
+ <Text>다음 주까지 요금제 변경안을 정리하고, 금요일에 다시 검토합니다.</Text>
119
+ </Card>
120
+ ),
121
+ };
122
+
123
+ export const DontNestedCards: Story = {
124
+ tags: ['!dev'],
125
+ parameters: { layout: 'padded' },
126
+ name: "Usage / Don't: cards inside cards",
127
+ render: () => (
128
+ <Card p={5} maxW="420px">
129
+ <Text fontWeight="bold" mb={3}>
130
+ 이번 달
131
+ </Text>
132
+ <Card p={4} mb={2}>
133
+ <Text>사용 크레딧 8,489</Text>
134
+ </Card>
135
+ <Card p={4}>
136
+ <Text>남은 크레딧 1,511</Text>
137
+ </Card>
138
+ </Card>
139
+ ),
140
+ };
141
+
142
+ /** Colour tokens from `Card.tsx` (base) and `Card.styles.ts`. */
143
+ const CARD_TOKENS: { token: string; use: string }[] = [
144
+ { token: 'bg.surface', use: 'default · background' },
145
+ { token: 'fg.default', use: 'text' },
146
+ { token: 'border.subtle', use: 'default, elevated · border' },
147
+ { token: variantStyles.wash.bg, use: 'wash · background (no border)' },
148
+ { token: clickableStyles._hover.bg, use: 'clickable · hover background' },
149
+ {
150
+ token: clickableStyles._hover.borderColor,
151
+ use: 'clickable · hover border',
152
+ },
153
+ ];
154
+
155
+ export const UsageTokens: Story = {
156
+ tags: ['!dev'],
157
+ parameters: { layout: 'padded' },
158
+ name: 'Usage / Tokens',
159
+ render: () => <TokenTable rows={CARD_TOKENS} />,
160
+ };
@@ -7,7 +7,19 @@ import type { PolymorphicProps } from '../../types/polymorphic';
7
7
  export type CardVariant = 'default' | 'wash' | 'elevated';
8
8
 
9
9
  export type CardOwnProps = Omit<ChakraCardRootProps, 'as'> & {
10
+ /**
11
+ * The whole card is one target: pointer cursor, and on hover the ground
12
+ * steps to `bg.subtle` and the border to `border.strong`. Styling only —
13
+ * render it as the control with `as` (`as={NextLink}`, `as="button"`).
14
+ */
10
15
  clickable?: boolean;
16
+ /**
17
+ * `default`: `bg.surface` with a `border.subtle` hairline — most content.
18
+ * `wash`: `bg.muted`, no border — a block that summarises or concludes (an
19
+ * AI summary, a purchase total). `elevated`: a soft `sm` shadow — a
20
+ * standalone card that should read as a raised object.
21
+ * @default 'default'
22
+ */
11
23
  variant?: CardVariant;
12
24
  };
13
25
 
@@ -0,0 +1,216 @@
1
+ import { ArgTypes, Canvas, Meta } from '@storybook/blocks';
2
+
3
+ import { En, Ko, LangToggle, Verdict } from '../../guidelines/_components/Lang';
4
+ import * as CardStories from './Card.stories';
5
+
6
+ <Meta of={CardStories} name="Usage" />
7
+
8
+ <LangToggle />
9
+
10
+ <En>
11
+
12
+ # Card
13
+
14
+ A bordered surface that groups content about one thing: a course, a meeting,
15
+ a plan, a setting. Default padding is `8`; most call sites set their own.
16
+
17
+ ## When to use
18
+
19
+ - To group the content and actions of one item, especially in a list or grid
20
+ of similar items.
21
+ - To set a summary or result apart from the page (`variant="wash"`).
22
+ - As a single click target for the whole item (`clickable` with `as`).
23
+
24
+ ## When not to use
25
+
26
+ - Records with the same columns → `Table`.
27
+ - A message about the page or a task → `Banner`.
28
+ - Sections that open and close → `Accordion` or `Collapsible`.
29
+ - Just to add space or a border around a form. Use layout (`Stack`, padding).
30
+
31
+ ## Variants and what they mean
32
+
33
+ </En>
34
+
35
+ <Ko>
36
+
37
+ # Card
38
+
39
+ 한 대상(강좌, 회의, 요금제, 설정)에 관한 내용을 테두리 있는 면으로 묶는 컴포넌트입니다.
40
+ 기본 안쪽 여백은 `8`이며, 대부분의 호출부에서 직접 정합니다.
41
+
42
+ ## 언제 쓰나요
43
+
44
+ - 한 항목의 내용과 동작을 묶을 때. 특히 비슷한 항목이 목록이나 격자로 늘어설 때.
45
+ - 요약이나 결과를 페이지와 구분할 때(`variant="wash"`).
46
+ - 항목 전체를 한 번에 누르는 대상으로 만들 때(`clickable`과 `as`).
47
+
48
+ ## 언제 쓰지 않나요
49
+
50
+ - 같은 열을 가진 기록은 `Table`을 씁니다.
51
+ - 페이지나 작업에 관한 안내는 `Banner`를 씁니다.
52
+ - 여닫는 섹션은 `Accordion`이나 `Collapsible`을 씁니다.
53
+ - 폼 둘레에 여백이나 테두리를 두려는 목적만으로 쓰지 않습니다. 레이아웃(`Stack`, 여백)을
54
+ 씁니다.
55
+
56
+ ## 변형과 뜻
57
+
58
+ </Ko>
59
+
60
+ <ArgTypes of={CardStories} include={['variant', 'clickable']} />
61
+
62
+ <En>
63
+
64
+ | Variant | Means | Use for |
65
+ | --- | --- | --- |
66
+ | `default` | A framed item on the page: `bg.surface` and a `border.subtle` hairline | List items, settings groups |
67
+ | `wash` | A block that summarises or concludes: `bg.muted`, no border | An AI summary, a purchase total, an accepted invitation |
68
+ | `elevated` | A standalone object that sits above the page: soft `sm` shadow | A recording or processing panel |
69
+ | `clickable` | The whole card is one target: hover steps to `bg.subtle` and `border.strong`, nothing lifts | Course cards, chatbot cards |
70
+
71
+ ## Do / Don't
72
+
73
+ </En>
74
+
75
+ <Ko>
76
+
77
+ | 변형 | 뜻 | 쓰는 곳 |
78
+ | --- | --- | --- |
79
+ | `default` | 페이지 위의 테두리 있는 항목. `bg.surface`와 `border.subtle` 선 | 목록 항목, 설정 묶음 |
80
+ | `wash` | 요약하거나 마무리하는 블록. `bg.muted`, 테두리 없음 | AI 요약, 결제 합계, 수락한 초대 |
81
+ | `elevated` | 페이지 위에 떠 있는 독립된 대상. 부드러운 `sm` 그림자 | 녹음 패널, 처리 중 패널 |
82
+ | `clickable` | 카드 전체가 누르는 대상. 호버하면 `bg.subtle`과 `border.strong`으로 바뀌고 떠오르지 않음 | 강좌 카드, 챗봇 카드 |
83
+
84
+ ## 이렇게 하세요 / 이렇게 하지 마세요
85
+
86
+ </Ko>
87
+
88
+ <Canvas of={CardStories.DoClickableIsTheLink} />
89
+ <Verdict
90
+ kind="do"
91
+ en="Make a clickable card the link itself (as='a' or as={NextLink}), so it is focusable and announced as a link."
92
+ ko="누를 수 있는 카드는 카드 자체를 링크로 만듭니다(as='a' 또는 as={NextLink}). 그래야 초점을 받고 링크로 읽힙니다."
93
+ />
94
+
95
+ <Canvas of={CardStories.DontButtonInClickable} />
96
+ <Verdict
97
+ kind="dont"
98
+ en="Put a second control inside a clickable card. A click on 삭제 also opens the card, and as a link or button the card cannot contain another control. Move the action out, or make only the title the link."
99
+ ko="누를 수 있는 카드 안에 다른 컨트롤을 넣지 마세요. '삭제'를 눌러도 카드가 열리고, 카드가 링크나 버튼이면 안에 다른 컨트롤을 둘 수 없습니다. 동작을 밖으로 빼거나 제목만 링크로 만듭니다."
100
+ />
101
+
102
+ <Canvas of={CardStories.DoWashForSummary} />
103
+ <Verdict
104
+ kind="do"
105
+ en="Use wash for a summary or a result. The fill sets it apart, so it needs no border."
106
+ ko="요약이나 결과에는 wash를 씁니다. 배경색이 구분해 주므로 테두리가 필요 없습니다."
107
+ />
108
+
109
+ <Canvas of={CardStories.DontNestedCards} />
110
+ <Verdict
111
+ kind="dont"
112
+ en="Nest cards. Borders inside borders add weight without adding structure; use dividers or a Stack inside one card."
113
+ ko="카드 안에 카드를 넣지 마세요. 테두리 안의 테두리는 구조 없이 무게만 더합니다. 한 카드 안에서 구분선이나 Stack을 씁니다."
114
+ />
115
+
116
+ <En>
117
+
118
+ ## Content
119
+
120
+ - Lead with what identifies the item (its name), then the details.
121
+ - Keep actions for the item at the bottom or top-right, in the same place on
122
+ every card in a list.
123
+
124
+ ## Accessibility
125
+
126
+ What Card does for you:
127
+
128
+ - `as` changes the element and its props, so a clickable card can be a real
129
+ `<a>` or `<button>` and get focus, Enter (and Space for a button) and the
130
+ right role without extra code.
131
+ - The hover state uses a border and a tier step, not a shadow, so it also
132
+ reads in dark mode.
133
+
134
+ What you still have to do:
135
+
136
+ - **A clickable card must be a control** (WCAG 2.1.1, 4.1.2). `clickable` is
137
+ styling only. A `<div>` with `onClick` is not focusable. With
138
+ `as="button"`, also pass `type="button"`.
139
+ - **Nothing interactive inside a clickable card** (nested interactive
140
+ controls, `ACCESSIBILITY.md` §3). If a card needs its own actions, make only
141
+ the title the link.
142
+ - **Inside a `<button>`, only phrasing content.** A card rendered as a button
143
+ must not contain `<div>` or `<p>` children (`ACCESSIBILITY.md` §5, KWCAG
144
+ 5.4.1.1). Use `as="span"` with `display="block"` on the text inside, or use
145
+ a link.
146
+ - Card has no visible focus style of its own. Check the focus indicator of a
147
+ clickable card in your app (WCAG 2.4.7).
148
+
149
+ ## Tokens
150
+
151
+ Read from `Card.tsx` and `clickableStyles` / `variantStyles` in
152
+ `Card.styles.ts`.
153
+
154
+ </En>
155
+
156
+ <Ko>
157
+
158
+ ## 문구
159
+
160
+ - 항목을 알아볼 수 있는 것(이름)을 먼저 쓰고, 세부 내용을 뒤에 씁니다.
161
+ - 항목의 동작은 목록 안의 모든 카드에서 같은 자리(아래쪽이나 오른쪽 위)에 둡니다.
162
+
163
+ ## 접근성
164
+
165
+ Card가 알아서 하는 일
166
+
167
+ - `as`가 요소와 그 속성을 함께 바꾸므로, 누를 수 있는 카드를 실제 `<a>`나
168
+ `<button>`으로 만들 수 있습니다. 그러면 따로 코드를 쓰지 않아도 초점, Enter(버튼이면
169
+ Space도), 알맞은 역할이 생깁니다.
170
+ - 호버 상태는 그림자가 아니라 테두리와 바탕 단계로 표현하므로 다크 모드에서도
171
+ 보입니다.
172
+
173
+ 직접 챙겨야 하는 일
174
+
175
+ - **누를 수 있는 카드는 컨트롤이어야 합니다**(WCAG 2.1.1, 4.1.2). `clickable`은
176
+ 모양만 바꿉니다. `onClick`만 단 `<div>`는 초점을 받지 못합니다. `as="button"`을 쓸
177
+ 때는 `type="button"`도 넘깁니다.
178
+ - **누를 수 있는 카드 안에는 상호작용 요소를 넣지 않습니다**(상호작용 요소 중첩,
179
+ `ACCESSIBILITY.md` 3절). 카드에 따로 동작이 필요하다면 제목만 링크로 만듭니다.
180
+ - **`<button>` 안에는 phrasing content만 넣습니다.** 버튼으로 그린 카드에는 `<div>`나
181
+ `<p>` 자식을 넣지 않습니다(`ACCESSIBILITY.md` 5절, KWCAG 5.4.1.1). 안의 글자에는
182
+ `as="span"`과 `display="block"`을 쓰거나 링크를 씁니다.
183
+ - Card에는 자체 초점 스타일이 없습니다. 앱에서 누를 수 있는 카드의 초점 표시를
184
+ 확인합니다(WCAG 2.4.7).
185
+
186
+ ## 토큰
187
+
188
+ `Card.tsx`와 `Card.styles.ts`의 `clickableStyles` / `variantStyles`에서 읽습니다.
189
+
190
+ </Ko>
191
+
192
+ <Canvas of={CardStories.UsageTokens} sourceState="none" />
193
+
194
+ <En>
195
+
196
+ ## Related
197
+
198
+ - **Table**: records with the same columns.
199
+ - **Banner**: a message about the page.
200
+ - **Accordion** / **Collapsible**: sections that open.
201
+ - **Masonry**: a grid of cards with different heights.
202
+ - **Foundations/Brand & colour usage**: surfaces and layers.
203
+
204
+ </En>
205
+
206
+ <Ko>
207
+
208
+ ## 관련 컴포넌트
209
+
210
+ - **Table**: 같은 열을 가진 기록.
211
+ - **Banner**: 페이지에 관한 안내.
212
+ - **Accordion** / **Collapsible**: 여닫는 섹션.
213
+ - **Masonry**: 높이가 서로 다른 카드의 격자.
214
+ - **Foundations/Brand & colour usage**: 면과 레이어.
215
+
216
+ </Ko>
@@ -2,6 +2,9 @@ import React, { useState } from 'react';
2
2
  import { HStack, Stack, VStack } from '@chakra-ui/react';
3
3
  import type { Meta, StoryObj } from '@storybook/react';
4
4
 
5
+ import { T } from '../../guidelines/_components/Lang';
6
+ import { TokenTable } from '../../guidelines/_components/TokenTable';
7
+ import { Text } from '../Typography';
5
8
  import { Checkbox } from './Checkbox';
6
9
 
7
10
  const meta = {
@@ -28,7 +31,7 @@ export default meta;
28
31
  type Story = StoryObj<typeof meta>;
29
32
 
30
33
  export const Default: Story = {
31
- render: args => (
34
+ render: (args) => (
32
35
  <Checkbox {...args}>
33
36
  <Checkbox.Control />
34
37
  </Checkbox>
@@ -36,7 +39,7 @@ export const Default: Story = {
36
39
  };
37
40
 
38
41
  export const Checked: Story = {
39
- render: args => (
42
+ render: (args) => (
40
43
  <Checkbox {...args}>
41
44
  <Checkbox.Control />
42
45
  </Checkbox>
@@ -45,7 +48,7 @@ export const Checked: Story = {
45
48
  };
46
49
 
47
50
  export const Indeterminate: Story = {
48
- render: args => (
51
+ render: (args) => (
49
52
  <Checkbox {...args}>
50
53
  <Checkbox.Control />
51
54
  </Checkbox>
@@ -54,7 +57,7 @@ export const Indeterminate: Story = {
54
57
  };
55
58
 
56
59
  export const Disabled: Story = {
57
- render: args => (
60
+ render: (args) => (
58
61
  <Checkbox {...args}>
59
62
  <Checkbox.Control />
60
63
  </Checkbox>
@@ -63,7 +66,7 @@ export const Disabled: Story = {
63
66
  };
64
67
 
65
68
  export const DisabledChecked: Story = {
66
- render: args => (
69
+ render: (args) => (
67
70
  <Checkbox {...args}>
68
71
  <Checkbox.Control />
69
72
  </Checkbox>
@@ -72,7 +75,7 @@ export const DisabledChecked: Story = {
72
75
  };
73
76
 
74
77
  export const DisabledIndeterminate: Story = {
75
- render: args => (
78
+ render: (args) => (
76
79
  <Checkbox {...args}>
77
80
  <Checkbox.Control />
78
81
  </Checkbox>
@@ -81,7 +84,7 @@ export const DisabledIndeterminate: Story = {
81
84
  };
82
85
 
83
86
  export const WithLabel: Story = {
84
- render: args => (
87
+ render: (args) => (
85
88
  <Checkbox {...args}>
86
89
  <Checkbox.Control />
87
90
  <Checkbox.Label>Accept terms and conditions</Checkbox.Label>
@@ -92,7 +95,7 @@ export const WithLabel: Story = {
92
95
  export const Sizes: Story = {
93
96
  render: () => (
94
97
  <HStack gap={6} align="center">
95
- {(['xs', 'sm', 'md', 'lg'] as const).map(size => (
98
+ {(['xs', 'sm', 'md', 'lg'] as const).map((size) => (
96
99
  <VStack key={size} gap={2}>
97
100
  <Checkbox size={size} checked={true}>
98
101
  <Checkbox.Control />
@@ -105,7 +108,7 @@ export const Sizes: Story = {
105
108
  };
106
109
 
107
110
  export const LeftLabel: Story = {
108
- render: args => (
111
+ render: (args) => (
109
112
  <Checkbox {...args}>
110
113
  <Checkbox.Label>Label on the left</Checkbox.Label>
111
114
  <Checkbox.Control />
@@ -115,7 +118,7 @@ export const LeftLabel: Story = {
115
118
  };
116
119
 
117
120
  export const RichLabel: Story = {
118
- render: args => (
121
+ render: (args) => (
119
122
  <Checkbox {...args}>
120
123
  <Checkbox.Control />
121
124
  <Checkbox.Label>
@@ -143,8 +146,8 @@ export const Group: Story = {
143
146
  };
144
147
 
145
148
  const handleToggle = (item: string) => {
146
- setSelected(prev =>
147
- prev.includes(item) ? prev.filter(i => i !== item) : [...prev, item]
149
+ setSelected((prev) =>
150
+ prev.includes(item) ? prev.filter((i) => i !== item) : [...prev, item]
148
151
  );
149
152
  };
150
153
 
@@ -158,7 +161,7 @@ export const Group: Story = {
158
161
  <Checkbox.Label>Select All</Checkbox.Label>
159
162
  </Checkbox>
160
163
  <Stack gap={2} pl={6}>
161
- {items.map(item => (
164
+ {items.map((item) => (
162
165
  <Checkbox
163
166
  key={item}
164
167
  checked={selected.includes(item)}
@@ -173,3 +176,127 @@ export const Group: Story = {
173
176
  );
174
177
  },
175
178
  };
179
+
180
+ // ───────────────────────── Usage-page specimens ─────────────────────────
181
+ // Pulled into `Checkbox.usage.mdx` with <Canvas of={…} />. Hidden (`!dev`); `tags`
182
+ // is written out on each story because the indexer reads CSF statically.
183
+
184
+ const CHANNELS = ['이메일', '앱 알림', '문자'];
185
+
186
+ export const DoLabelledList: Story = {
187
+ tags: ['!dev'],
188
+ parameters: { layout: 'padded' },
189
+ name: 'Usage / Do: several independent choices',
190
+ render: () => (
191
+ <Stack gap={2}>
192
+ <Text fontWeight="semibold">알림 받을 곳</Text>
193
+ {CHANNELS.map((channel, i) => (
194
+ <Checkbox key={channel} defaultChecked={i === 0}>
195
+ <Checkbox.Control />
196
+ <Checkbox.Label>{channel}</Checkbox.Label>
197
+ </Checkbox>
198
+ ))}
199
+ </Stack>
200
+ ),
201
+ };
202
+
203
+ export const DoSelectAll: Story = {
204
+ tags: ['!dev'],
205
+ parameters: { layout: 'padded' },
206
+ name: 'Usage / Do: indeterminate for a partial select-all',
207
+ render: () => {
208
+ const [checked, setChecked] = useState([true, false, true]);
209
+ const all = checked.every(Boolean);
210
+ const some = checked.some(Boolean);
211
+ return (
212
+ <Stack gap={2}>
213
+ <Checkbox
214
+ checked={all ? true : some ? 'indeterminate' : false}
215
+ onCheckedChange={() => setChecked(checked.map(() => !all))}
216
+ >
217
+ <Checkbox.Control />
218
+ <Checkbox.Label>전체 선택</Checkbox.Label>
219
+ </Checkbox>
220
+ <Stack gap={2} pl={6}>
221
+ {CHANNELS.map((channel, i) => (
222
+ <Checkbox
223
+ key={channel}
224
+ checked={checked[i]}
225
+ onCheckedChange={(e) =>
226
+ setChecked(checked.map((v, j) => (j === i ? !!e.checked : v)))
227
+ }
228
+ >
229
+ <Checkbox.Control />
230
+ <Checkbox.Label>{channel}</Checkbox.Label>
231
+ </Checkbox>
232
+ ))}
233
+ </Stack>
234
+ </Stack>
235
+ );
236
+ },
237
+ };
238
+
239
+ export const DontNegativeLabel: Story = {
240
+ tags: ['!dev'],
241
+ parameters: { layout: 'padded' },
242
+ name: "Usage / Don't: a negative label",
243
+ render: () => (
244
+ <Checkbox>
245
+ <Checkbox.Control />
246
+ <Checkbox.Label>마케팅 메일 받지 않기</Checkbox.Label>
247
+ </Checkbox>
248
+ ),
249
+ };
250
+
251
+ export const DoHiddenLabelInTable: Story = {
252
+ tags: ['!dev'],
253
+ parameters: { layout: 'padded' },
254
+ name: 'Usage / Do: a hidden label when the row names it',
255
+ render: () => (
256
+ <HStack gap={3}>
257
+ <Checkbox>
258
+ <Checkbox.Control />
259
+ <Checkbox.Label srOnly>김민지 선택</Checkbox.Label>
260
+ </Checkbox>
261
+ <Text>김민지</Text>
262
+ <Text color="fg.muted">minji@company.com</Text>
263
+ </HStack>
264
+ ),
265
+ };
266
+
267
+ /** Tokens `CheckboxControl` reads, as written in `CheckboxControl.tsx`. */
268
+ export const UsageTokens: Story = {
269
+ tags: ['!dev'],
270
+ parameters: { layout: 'padded' },
271
+ name: 'Usage / Tokens',
272
+ render: () => (
273
+ <TokenTable
274
+ rows={[
275
+ {
276
+ token: 'bg.surface',
277
+ use: <T en="Unchecked box" ko="선택 전 상자" />,
278
+ },
279
+ {
280
+ token: 'border.control',
281
+ use: <T en="Unchecked border (3:1)" ko="선택 전 테두리(3:1)" />,
282
+ },
283
+ {
284
+ token: 'primary.main',
285
+ use: (
286
+ <T en="Checked and indeterminate fill" ko="선택·일부 선택 채움" />
287
+ ),
288
+ },
289
+ { token: 'fg.onPrimary', use: <T en="Check mark" ko="체크 표시" /> },
290
+ { token: 'disabled.bg', use: <T en="Disabled box" ko="비활성 상자" /> },
291
+ {
292
+ token: 'disabled.fg',
293
+ use: <T en="Disabled mark" ko="비활성 표시" />,
294
+ },
295
+ {
296
+ token: 'focus.ring',
297
+ use: <T en="Keyboard focus ring" ko="키보드 초점 링" />,
298
+ },
299
+ ]}
300
+ />
301
+ ),
302
+ };