@iamfiro/design 0.0.0-stage → 0.1.0

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 (264) hide show
  1. package/AGENTS.md +81 -0
  2. package/README.md +15 -2
  3. package/agents/INDEX.md +156 -0
  4. package/agents/accordion/AGENTS.md +279 -0
  5. package/agents/action-bar/AGENTS.md +90 -0
  6. package/agents/alert/AGENTS.md +212 -0
  7. package/agents/alert-dialog/AGENTS.md +193 -0
  8. package/agents/app-shell/AGENTS.md +409 -0
  9. package/agents/area-chart/AGENTS.md +183 -0
  10. package/agents/aspect-ratio/AGENTS.md +143 -0
  11. package/agents/avatar/AGENTS.md +130 -0
  12. package/agents/badge/AGENTS.md +217 -0
  13. package/agents/bar-chart/AGENTS.md +386 -0
  14. package/agents/bar-list/AGENTS.md +223 -0
  15. package/agents/brand-icon/AGENTS.md +82 -0
  16. package/agents/breadcrumb/AGENTS.md +133 -0
  17. package/agents/button/AGENTS.md +195 -0
  18. package/agents/card/AGENTS.md +141 -0
  19. package/agents/card-frame/AGENTS.md +227 -0
  20. package/agents/chat-bubble/AGENTS.md +266 -0
  21. package/agents/chat-composer/AGENTS.md +251 -0
  22. package/agents/checkbox/AGENTS.md +113 -0
  23. package/agents/code-block/AGENTS.md +144 -0
  24. package/agents/color-dot/AGENTS.md +120 -0
  25. package/agents/color-picker/AGENTS.md +224 -0
  26. package/agents/colors/AGENTS.md +168 -0
  27. package/agents/combobox/AGENTS.md +218 -0
  28. package/agents/command-menu/AGENTS.md +169 -0
  29. package/agents/comment/AGENTS.md +206 -0
  30. package/agents/context-menu/AGENTS.md +303 -0
  31. package/agents/copy-button/AGENTS.md +84 -0
  32. package/agents/count-badge/AGENTS.md +115 -0
  33. package/agents/countdown/AGENTS.md +101 -0
  34. package/agents/data-grid/AGENTS.md +460 -0
  35. package/agents/date-picker/AGENTS.md +197 -0
  36. package/agents/delta/AGENTS.md +114 -0
  37. package/agents/description-list/AGENTS.md +251 -0
  38. package/agents/dialog/AGENTS.md +391 -0
  39. package/agents/drawer/AGENTS.md +471 -0
  40. package/agents/dropdown-menu/AGENTS.md +322 -0
  41. package/agents/dropzone/AGENTS.md +116 -0
  42. package/agents/elapsed/AGENTS.md +160 -0
  43. package/agents/empty-state/AGENTS.md +203 -0
  44. package/agents/file-chip/AGENTS.md +79 -0
  45. package/agents/file-icon/AGENTS.md +66 -0
  46. package/agents/file-upload/AGENTS.md +168 -0
  47. package/agents/filter-chips/AGENTS.md +167 -0
  48. package/agents/flag/AGENTS.md +67 -0
  49. package/agents/funnel-chart/AGENTS.md +131 -0
  50. package/agents/highlight/AGENTS.md +119 -0
  51. package/agents/hover-card/AGENTS.md +271 -0
  52. package/agents/icon-stack/AGENTS.md +120 -0
  53. package/agents/icon-tile/AGENTS.md +94 -0
  54. package/agents/inline-diff/AGENTS.md +211 -0
  55. package/agents/input/AGENTS.md +261 -0
  56. package/agents/kanban/AGENTS.md +352 -0
  57. package/agents/kbd/AGENTS.md +160 -0
  58. package/agents/layout/AGENTS.md +351 -0
  59. package/agents/line-chart/AGENTS.md +393 -0
  60. package/agents/link/AGENTS.md +53 -0
  61. package/agents/list/AGENTS.md +392 -0
  62. package/agents/marker/AGENTS.md +142 -0
  63. package/agents/masked-text/AGENTS.md +127 -0
  64. package/agents/menubar/AGENTS.md +276 -0
  65. package/agents/multi-select/AGENTS.md +159 -0
  66. package/agents/navigation-menu/AGENTS.md +315 -0
  67. package/agents/notice-stack/AGENTS.md +101 -0
  68. package/agents/number-stepper/AGENTS.md +96 -0
  69. package/agents/otp-input/AGENTS.md +162 -0
  70. package/agents/pagination/AGENTS.md +189 -0
  71. package/agents/phone-input/AGENTS.md +131 -0
  72. package/agents/pie-chart/AGENTS.md +243 -0
  73. package/agents/popover/AGENTS.md +190 -0
  74. package/agents/progress/AGENTS.md +273 -0
  75. package/agents/progress-tracker/AGENTS.md +305 -0
  76. package/agents/rating/AGENTS.md +165 -0
  77. package/agents/relative-time/AGENTS.md +103 -0
  78. package/agents/resizable/AGENTS.md +390 -0
  79. package/agents/scaled-preview/AGENTS.md +111 -0
  80. package/agents/scatter-chart/AGENTS.md +160 -0
  81. package/agents/scroll-area/AGENTS.md +271 -0
  82. package/agents/search-input/AGENTS.md +105 -0
  83. package/agents/segmented-control/AGENTS.md +153 -0
  84. package/agents/select/AGENTS.md +159 -0
  85. package/agents/selector-button/AGENTS.md +122 -0
  86. package/agents/sidebar/AGENTS.md +201 -0
  87. package/agents/skeleton/AGENTS.md +166 -0
  88. package/agents/slider/AGENTS.md +181 -0
  89. package/agents/spark-chart/AGENTS.md +257 -0
  90. package/agents/sparkbar/AGENTS.md +92 -0
  91. package/agents/spinner/AGENTS.md +123 -0
  92. package/agents/split-view/AGENTS.md +290 -0
  93. package/agents/stat/AGENTS.md +138 -0
  94. package/agents/status-icon/AGENTS.md +243 -0
  95. package/agents/step-list/AGENTS.md +313 -0
  96. package/agents/table/AGENTS.md +286 -0
  97. package/agents/tabs/AGENTS.md +305 -0
  98. package/agents/tag-input/AGENTS.md +246 -0
  99. package/agents/time-picker/AGENTS.md +228 -0
  100. package/agents/timeline/AGENTS.md +1018 -0
  101. package/agents/toast/AGENTS.md +266 -0
  102. package/agents/toggle-group/AGENTS.md +216 -0
  103. package/agents/toolbar/AGENTS.md +277 -0
  104. package/agents/tooltip/AGENTS.md +154 -0
  105. package/agents/tracker/AGENTS.md +158 -0
  106. package/agents/tree-diagram/AGENTS.md +260 -0
  107. package/agents/tree-view/AGENTS.md +329 -0
  108. package/agents/typography/AGENTS.md +396 -0
  109. package/lib/index.js +17914 -0
  110. package/lib/style.css +2 -0
  111. package/lib/types/components/Accordion/Accordion.d.ts +57 -0
  112. package/lib/types/components/ActionBar/ActionBar.d.ts +24 -0
  113. package/lib/types/components/Alert/Alert.d.ts +36 -0
  114. package/lib/types/components/AppShell/AppShell.d.ts +38 -0
  115. package/lib/types/components/AreaChart/AreaChart.d.ts +17 -0
  116. package/lib/types/components/BarChart/BarChart.d.ts +57 -0
  117. package/lib/types/components/BarList/BarList.d.ts +56 -0
  118. package/lib/types/components/Breadcrumb/Breadcrumb.d.ts +15 -0
  119. package/lib/types/components/Calendar/Calendar.d.ts +34 -0
  120. package/lib/types/components/Calendar/DatePicker.d.ts +45 -0
  121. package/lib/types/components/Calendar/date.d.ts +32 -0
  122. package/lib/types/components/Card/Card.d.ts +64 -0
  123. package/lib/types/components/CardFrame/CardFrame.d.ts +15 -0
  124. package/lib/types/components/Chart/ChartParts.d.ts +38 -0
  125. package/lib/types/components/Chart/chart.d.ts +46 -0
  126. package/lib/types/components/Chart/useChartInteraction.d.ts +39 -0
  127. package/lib/types/components/ChatBubble/ChatBubble.d.ts +61 -0
  128. package/lib/types/components/ChatBubble/formatChatTime.d.ts +2 -0
  129. package/lib/types/components/ChatComposer/ChatComposer.d.ts +42 -0
  130. package/lib/types/components/CodeBlock/CodeBlock.d.ts +18 -0
  131. package/lib/types/components/CodeBlock/highlight.d.ts +10 -0
  132. package/lib/types/components/ColorPicker/ColorPicker.d.ts +61 -0
  133. package/lib/types/components/ColorPicker/color.d.ts +48 -0
  134. package/lib/types/components/ColorPicker/presets.d.ts +7 -0
  135. package/lib/types/components/Combobox/Combobox.d.ts +48 -0
  136. package/lib/types/components/CommandMenu/CommandMenu.d.ts +51 -0
  137. package/lib/types/components/Comment/Comment.d.ts +45 -0
  138. package/lib/types/components/ContextMenu/ContextMenu.d.ts +40 -0
  139. package/lib/types/components/DataGrid/DataGrid.d.ts +43 -0
  140. package/lib/types/components/DataGrid/GridPopover.d.ts +43 -0
  141. package/lib/types/components/DataGrid/anchor.d.ts +5 -0
  142. package/lib/types/components/DataGrid/model.d.ts +61 -0
  143. package/lib/types/components/DataGrid/panels.d.ts +63 -0
  144. package/lib/types/components/DataGrid/typeMeta.d.ts +6 -0
  145. package/lib/types/components/DataGrid/types.d.ts +77 -0
  146. package/lib/types/components/DescriptionList/DescriptionList.d.ts +77 -0
  147. package/lib/types/components/Dialog/AlertDialog.d.ts +26 -0
  148. package/lib/types/components/Dialog/Dialog.d.ts +42 -0
  149. package/lib/types/components/Dialog/modal.d.ts +38 -0
  150. package/lib/types/components/Drawer/Drawer.d.ts +62 -0
  151. package/lib/types/components/DropdownMenu/DropdownMenu.d.ts +97 -0
  152. package/lib/types/components/DropdownMenu/menuCore.d.ts +23 -0
  153. package/lib/types/components/Dropzone/Dropzone.d.ts +30 -0
  154. package/lib/types/components/EmptyState/EmptyState.d.ts +26 -0
  155. package/lib/types/components/FileChip/FileChip.d.ts +32 -0
  156. package/lib/types/components/FileUpload/FileUpload.d.ts +52 -0
  157. package/lib/types/components/FilterChips/FilterChips.d.ts +37 -0
  158. package/lib/types/components/FunnelChart/FunnelChart.d.ts +38 -0
  159. package/lib/types/components/FunnelChart/funnel.d.ts +25 -0
  160. package/lib/types/components/Highlight/Highlight.d.ts +35 -0
  161. package/lib/types/components/HoverCard/HoverCard.d.ts +47 -0
  162. package/lib/types/components/InlineDiff/InlineDiff.d.ts +36 -0
  163. package/lib/types/components/InlineDiff/diff.d.ts +42 -0
  164. package/lib/types/components/InlineDiff/useDiffReview.d.ts +57 -0
  165. package/lib/types/components/Kanban/Kanban.d.ts +64 -0
  166. package/lib/types/components/Kanban/KanbanCard.d.ts +35 -0
  167. package/lib/types/components/Kanban/move.d.ts +25 -0
  168. package/lib/types/components/LineChart/LineChart.d.ts +85 -0
  169. package/lib/types/components/List/List.d.ts +62 -0
  170. package/lib/types/components/Listbox/Listbox.d.ts +60 -0
  171. package/lib/types/components/Marker/Marker.d.ts +28 -0
  172. package/lib/types/components/Menubar/Menubar.d.ts +50 -0
  173. package/lib/types/components/MultiSelect/MultiSelect.d.ts +38 -0
  174. package/lib/types/components/NavigationMenu/NavigationMenu.d.ts +101 -0
  175. package/lib/types/components/NoticeStack/NoticeStack.d.ts +41 -0
  176. package/lib/types/components/NumberStepper/NumberStepper.d.ts +32 -0
  177. package/lib/types/components/OtpInput/OtpInput.d.ts +31 -0
  178. package/lib/types/components/Pagination/Pagination.d.ts +54 -0
  179. package/lib/types/components/Pagination/paginationRange.d.ts +7 -0
  180. package/lib/types/components/PhoneInput/PhoneInput.d.ts +47 -0
  181. package/lib/types/components/PieChart/PieChart.d.ts +67 -0
  182. package/lib/types/components/PieChart/arc.d.ts +26 -0
  183. package/lib/types/components/PieChart/useArcTween.d.ts +15 -0
  184. package/lib/types/components/Popover/Popover.d.ts +28 -0
  185. package/lib/types/components/ProgressTracker/ProgressTracker.d.ts +64 -0
  186. package/lib/types/components/Rating/Rating.d.ts +42 -0
  187. package/lib/types/components/Resizable/Resizable.d.ts +50 -0
  188. package/lib/types/components/Resizable/layout.d.ts +31 -0
  189. package/lib/types/components/ScaledPreview/ScaledPreview.d.ts +38 -0
  190. package/lib/types/components/ScatterChart/ScatterChart.d.ts +81 -0
  191. package/lib/types/components/ScatterChart/scatter.d.ts +14 -0
  192. package/lib/types/components/ScrollArea/ScrollArea.d.ts +34 -0
  193. package/lib/types/components/Select/Select.d.ts +39 -0
  194. package/lib/types/components/Sidebar/Sidebar.d.ts +39 -0
  195. package/lib/types/components/Skeleton/Skeleton.d.ts +47 -0
  196. package/lib/types/components/Slider/Slider.d.ts +36 -0
  197. package/lib/types/components/SparkChart/SparkChart.d.ts +55 -0
  198. package/lib/types/components/SparkChart/spark.d.ts +16 -0
  199. package/lib/types/components/Sparkbar/Sparkbar.d.ts +39 -0
  200. package/lib/types/components/SplitView/SplitView.d.ts +31 -0
  201. package/lib/types/components/Stat/Stat.d.ts +58 -0
  202. package/lib/types/components/StepList/StepList.d.ts +61 -0
  203. package/lib/types/components/Table/Table.d.ts +39 -0
  204. package/lib/types/components/Tabs/Tabs.d.ts +47 -0
  205. package/lib/types/components/TagInput/TagInput.d.ts +46 -0
  206. package/lib/types/components/TimePicker/TimePicker.d.ts +43 -0
  207. package/lib/types/components/TimePicker/time.d.ts +15 -0
  208. package/lib/types/components/Timeline/Timeline.d.ts +154 -0
  209. package/lib/types/components/Timeline/scale.d.ts +22 -0
  210. package/lib/types/components/Toast/Toaster.d.ts +19 -0
  211. package/lib/types/components/Toast/index.d.ts +4 -0
  212. package/lib/types/components/Toast/store.d.ts +75 -0
  213. package/lib/types/components/ToggleGroup/ToggleGroup.d.ts +28 -0
  214. package/lib/types/components/Toolbar/Toolbar.d.ts +70 -0
  215. package/lib/types/components/Tracker/Tracker.d.ts +43 -0
  216. package/lib/types/components/TreeDiagram/TreeDiagram.d.ts +68 -0
  217. package/lib/types/components/TreeView/TreeView.d.ts +107 -0
  218. package/lib/types/components/index.d.ts +186 -0
  219. package/lib/types/hooks/index.d.ts +17 -0
  220. package/lib/types/hooks/timing.d.ts +29 -0
  221. package/lib/types/hooks/useControllableState.d.ts +5 -0
  222. package/lib/types/hooks/useCountdown.d.ts +19 -0
  223. package/lib/types/hooks/useDigitInput.d.ts +24 -0
  224. package/lib/types/hooks/useDismiss.d.ts +3 -0
  225. package/lib/types/hooks/useElapsed.d.ts +28 -0
  226. package/lib/types/hooks/useFloating.d.ts +21 -0
  227. package/lib/types/hooks/useFocusTrap.d.ts +7 -0
  228. package/lib/types/hooks/usePresence.d.ts +8 -0
  229. package/lib/types/hooks/usePressToOpen.d.ts +20 -0
  230. package/lib/types/hooks/useScrollLock.d.ts +2 -0
  231. package/lib/types/hooks/useSelection.d.ts +29 -0
  232. package/lib/types/index.d.ts +5 -0
  233. package/lib/types/primitives/AspectRatio.d.ts +14 -0
  234. package/lib/types/primitives/BrandIcon.d.ts +12 -0
  235. package/lib/types/primitives/ColorDot.d.ts +20 -0
  236. package/lib/types/primitives/CopyButton.d.ts +12 -0
  237. package/lib/types/primitives/CountBadge.d.ts +28 -0
  238. package/lib/types/primitives/Countdown.d.ts +21 -0
  239. package/lib/types/primitives/Delta.d.ts +33 -0
  240. package/lib/types/primitives/Elapsed.d.ts +23 -0
  241. package/lib/types/primitives/FileIcon.d.ts +17 -0
  242. package/lib/types/primitives/Flag.d.ts +15 -0
  243. package/lib/types/primitives/IconStack.d.ts +27 -0
  244. package/lib/types/primitives/IconTile.d.ts +24 -0
  245. package/lib/types/primitives/Kbd.d.ts +19 -0
  246. package/lib/types/primitives/Layout.d.ts +64 -0
  247. package/lib/types/primitives/Link.d.ts +12 -0
  248. package/lib/types/primitives/MaskedText.d.ts +28 -0
  249. package/lib/types/primitives/Progress.d.ts +52 -0
  250. package/lib/types/primitives/RelativeTime.d.ts +22 -0
  251. package/lib/types/primitives/SearchInput.d.ts +8 -0
  252. package/lib/types/primitives/SelectorButton.d.ts +23 -0
  253. package/lib/types/primitives/Spinner.d.ts +15 -0
  254. package/lib/types/primitives/StatusIcon.d.ts +40 -0
  255. package/lib/types/primitives/Swatch.d.ts +11 -0
  256. package/lib/types/primitives/Tooltip.d.ts +17 -0
  257. package/lib/types/primitives/Typography.d.ts +48 -0
  258. package/lib/types/primitives/formatCountdown.d.ts +2 -0
  259. package/lib/types/primitives/formatElapsed.d.ts +8 -0
  260. package/lib/types/primitives/formatRelativeTime.d.ts +16 -0
  261. package/lib/types/primitives/hotkey.d.ts +10 -0
  262. package/lib/types/primitives/index.d.ts +188 -0
  263. package/lib/types/primitives/maskValue.d.ts +24 -0
  264. package/package.json +54 -4
@@ -0,0 +1,393 @@
1
+ # LineChart
2
+
3
+ > 차트 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
4
+
5
+ 여러 시리즈의 추이를 비교하는 선 차트. 마우스·터치·화살표 키로 안내선을 옮기면 그날의 값이 Card 툴팁으로 따라오고, 오른쪽 끝에선 반대편으로 넘어가요. 툴팁은 ColorDot · Text · Separator로만 조립했고, 색은 --chart-* 토큰을 순서대로 써요.
6
+
7
+ ```tsx
8
+ import { LineChart, type LineSeries } from '@iamfiro/design'
9
+ ```
10
+
11
+ ## 디자인 규칙
12
+
13
+ - 차트: 시리즈 색은 `--chart-1…6`을 순서대로, 그리드는 `--chart-grid`로 아주 옅게(세로선·축선 없음). 범례·툴팁의 색 표시는 `ColorDot`, 툴팁은 `Card raised` + `Separator`로 조립. 축·툴팁·범례·호버/키보드는 `components/Chart/`의 공용 조각(`ChartTooltip`, `ChartLegend`, `useChartInteraction`)을 쓴다. → `LineChart` · `BarChart` · `PieChart` · `Sparkbar`
14
+ - 차트에서 한 칸을 고르는 화면(피벗)은 `BarChart selected` + `Table selectedKey`를 같은 상태로 묶는다. 고르지 않은 칸은 옅은 색, 고른 칸의 x축 아이콘(`xIcon`)은 흰 칩으로 펼친다. 임계치·이상 구간은 `LineChart referenceLines` · `bands`, 실시간 데이터는 `streaming`(모양 변형 대신 한 칸 미끄러짐) + `endDot="pulse"`.
15
+
16
+ ## API
17
+
18
+ ### LineChart
19
+
20
+ | prop | 타입 | 기본값 | 설명 |
21
+ | --- | --- | --- | --- |
22
+ | `data` (필수) | `LineChartRow[]` | | 행 목록. 한 행 = x축 한 칸. |
23
+ | `xKey` (필수) | `string` | | x축 라벨이 든 필드. |
24
+ | `series` (필수) | `LineSeries[]` | | 그릴 시리즈. color를 생략하면 --chart-1부터 순서대로. |
25
+ | `height` | `number` | `240` | 축 라벨을 포함한 높이(px). 너비는 부모를 채워요. |
26
+ | `curve` | `'linear' \| 'smooth'` | `'linear'` | 직선 또는 단조 곡선. |
27
+ | `area` | `boolean \| 'gradient' \| 'solid'` | `false` | 선 아래 채움. true·'gradient'는 아래로 옅어지고, 'solid'는 한 겹의 옅은 색이에요. |
28
+ | `stack` | `'stacked' \| 'percent'` | | 시리즈를 위로 쌓아요(percent = 행마다 100%). 보통은 AreaChart type으로 써요. |
29
+ | `connectNulls` | `boolean` | | null에서 끊지 않고 건너 이어 그려요. |
30
+ | `showTotal` | `boolean` | `stack이면 true` | 툴팁 마지막 줄에 합계. |
31
+ | `yTickCount` | `number` | `3` | y축 라벨 개수(0 포함). 간격은 1·2·2.5·3·5 단위로 반올림해요. |
32
+ | `yMax` | `number` | | y축 위 끝을 고정. |
33
+ | `yTicks` | `number[]` | | y축 값을 직접 지정(예: [0, 12, 24]). yTickCount · yMax보다 우선해요. |
34
+ | `xTicks` | `'auto' \| 'edges'` | `'auto'` | x축 라벨. edges는 첫 행과 마지막 행만('96초 전' … '지금'). |
35
+ | `bands` | `LineChartBand[]` | | 플롯 뒤에 칠하는 x 구간. |
36
+ | `referenceLines` | `LineChartReferenceLine[]` | | 가로 점선 기준선(임계치·목표). |
37
+ | `endDot` | `boolean \| 'pulse'` | | 각 선의 마지막 점에 점을 찍어요. 'pulse'면 퍼지는 링이 반복돼요. |
38
+ | `streaming` | `boolean \| number` | | 갱신마다 행이 하나 추가되고 가장 오래된 행이 빠지는 데이터. 모양 변형 대신 한 칸 왼쪽으로 미끄러져요. 숫자는 이동 시간(ms, 선형). |
39
+ | `formatValue` | `(value, series) => string` | `'1,234'` | 툴팁 값 형식. |
40
+ | `formatAxisValue` | `(value) => string` | `'6천'` | y축 라벨 형식(한국어 축약). |
41
+ | `formatX` | `(row, index) => string` | | x축 라벨 형식. 기본은 xKey 값 그대로. |
42
+ | `formatTitle` | `(row, index) => ReactNode` | | 툴팁 제목. 기본은 formatX. |
43
+ | `tooltipSort` | `'value' \| 'series' \| 'reverse'` | `'value' (stack이면 'reverse')` | 툴팁 행 순서. reverse = 위에 쌓인 시리즈부터. |
44
+ | `legend` | `boolean` | `true` | 아래 범례. 마우스를 올리면 해당 선을 강조해요. |
45
+ | `activeIndex` | `number \| null` | | 하이라이트한 행(제어). null이면 없음. |
46
+ | `defaultActiveIndex` | `number \| null` | `null` | 처음 하이라이트(비제어). |
47
+ | `onActiveIndexChange` | `(index: number \| null) => void` | | 하이라이트가 바뀔 때. |
48
+ | `aria-label` | `string` | `'선 차트'` | 차트 이름. 하이라이트한 값은 aria-live로 읽어 줘요. |
49
+
50
+ ### LineSeries
51
+
52
+ | prop | 타입 | 기본값 | 설명 |
53
+ | --- | --- | --- | --- |
54
+ | `key` (필수) | `string` | | 행에서 값을 읽을 필드. |
55
+ | `label` (필수) | `string` | | 범례·툴팁 이름. |
56
+ | `color` | `string` | | CSS 변수('--chart-2') 또는 색. |
57
+
58
+ ### LineChartBand
59
+
60
+ | prop | 타입 | 기본값 | 설명 |
61
+ | --- | --- | --- | --- |
62
+ | `from / to` (필수) | `number` | | 구간의 시작 · 끝 행 index. |
63
+ | `tone` | `'neutral' \| 'accent' \| 'warning' \| 'danger'` | `'warning'` | 옅은 채움 색(--*-soft). |
64
+
65
+ ### LineChartReferenceLine
66
+
67
+ | prop | 타입 | 기본값 | 설명 |
68
+ | --- | --- | --- | --- |
69
+ | `value` (필수) | `number` | | 선을 그을 y 값. |
70
+ | `label` | `string` | | 오른쪽 끝, 선 위의 작은 라벨. |
71
+ | `tone` | `'neutral' \| 'accent' \| 'warning' \| 'danger'` | `'neutral'` | 선과 라벨 색. |
72
+
73
+ ## 예제
74
+
75
+ 예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
76
+
77
+ ### 기본
78
+
79
+ 툴팁엔 값이 큰 순서로 나와요. 범례에 마우스를 올리면 그 선만 강조돼요. 차트에 포커스하고 ←/→, Home/End, Esc로도 움직여요.
80
+
81
+ ```tsx
82
+ import { LineChart, type LineSeries } from '@iamfiro/design'
83
+
84
+ const SERIES: LineSeries[] = [
85
+ { key: 'paid', label: '유료 광고' },
86
+ { key: 'organic', label: '검색 유입' },
87
+ { key: 'email', label: '이메일' },
88
+ { key: 'referral', label: '추천' },
89
+ { key: 'direct', label: '직접 방문' },
90
+ ]
91
+
92
+ const DATA = [
93
+ { date: '3월 3일', day: '월', paid: 3600, organic: 4200, email: 1200, referral: 1800, direct: 600 },
94
+ { date: '3월 4일', day: '화', paid: 3350, organic: 4700, email: 1100, referral: 2300, direct: 900 },
95
+ { date: '3월 5일', day: '수', paid: 4400, organic: 3900, email: 1700, referral: 2000, direct: 700 },
96
+ { date: '3월 6일', day: '목', paid: 4800, organic: 4600, email: 2100, referral: 1500, direct: 800 },
97
+ { date: '3월 7일', day: '금', paid: 4500, organic: 5300, email: 1800, referral: 1900, direct: 1000 },
98
+ { date: '3월 8일', day: '토', paid: 4300, organic: 5600, email: 1450, referral: 2400, direct: 1200 },
99
+ { date: '3월 9일', day: '일', paid: 4200, organic: 6000, email: 1500, referral: 2700, direct: 1100 },
100
+ ]
101
+
102
+ export default function Example() {
103
+ return (
104
+ <LineChart
105
+ data={DATA}
106
+ xKey="date"
107
+ series={SERIES}
108
+ formatValue={(v) => `${v.toLocaleString('ko-KR')}만 원`}
109
+ formatTitle={(row) => `${row.date} (${row.day})`}
110
+ aria-label="유입 경로별 매출"
111
+ style={{ width: '100%', maxWidth: 560 }}
112
+ />
113
+ )
114
+ }
115
+ ```
116
+
117
+ ### 부드러운 곡선
118
+
119
+ curve="smooth"는 단조 보간이라 실제 값보다 튀어 오르지 않아요. 값이 빠진 날(null)은 선이 끊겨요.
120
+
121
+ ```tsx
122
+ import { LineChart, type LineSeries } from '@iamfiro/design'
123
+
124
+ const SERIES: LineSeries[] = [
125
+ { key: 'web', label: '웹', color: '--chart-2' },
126
+ { key: 'app', label: '앱', color: '--chart-3' },
127
+ ]
128
+
129
+ const DATA = [
130
+ { week: '1주', web: 820, app: 410 },
131
+ { week: '2주', web: 940, app: 520 },
132
+ { week: '3주', web: 910, app: null },
133
+ { week: '4주', web: 1180, app: 690 },
134
+ { week: '5주', web: 1260, app: 760 },
135
+ { week: '6주', web: 1210, app: 880 },
136
+ { week: '7주', web: 1420, app: 1010 },
137
+ { week: '8주', web: 1530, app: 1120 },
138
+ ]
139
+
140
+ export default function Example() {
141
+ return (
142
+ <LineChart
143
+ data={DATA}
144
+ xKey="week"
145
+ series={SERIES}
146
+ curve="smooth"
147
+ height={200}
148
+ yTickCount={4}
149
+ formatValue={(v) => `${v.toLocaleString('ko-KR')}명`}
150
+ aria-label="주간 활성 사용자"
151
+ style={{ width: '100%', maxWidth: 560 }}
152
+ />
153
+ )
154
+ }
155
+ ```
156
+
157
+ ### 영역 (area)
158
+
159
+ area를 켜면 선 아래를 옅은 그라데이션으로 채워 양의 크기를 강조해요.
160
+
161
+ ```tsx
162
+ import { LineChart, type LineSeries } from '@iamfiro/design'
163
+
164
+ const SERIES: LineSeries[] = [
165
+ { key: 'pro', label: '프로', color: '--chart-2' },
166
+ { key: 'team', label: '팀', color: '--chart-4' },
167
+ ]
168
+
169
+ const DATA = [
170
+ { month: '5월', pro: 1200, team: 400 },
171
+ { month: '6월', pro: 1450, team: 520 },
172
+ { month: '7월', pro: 1380, team: 610 },
173
+ { month: '8월', pro: 1720, team: 790 },
174
+ { month: '9월', pro: 1950, team: 880 },
175
+ { month: '10월', pro: 2240, team: 1130 },
176
+ ]
177
+
178
+ export default function Example() {
179
+ return (
180
+ <LineChart
181
+ data={DATA}
182
+ xKey="month"
183
+ series={SERIES}
184
+ area
185
+ curve="smooth"
186
+ height={220}
187
+ formatValue={(v) => `${v.toLocaleString('ko-KR')}명`}
188
+ aria-label="요금제별 구독자"
189
+ style={{ width: '100%', maxWidth: 560 }}
190
+ />
191
+ )
192
+ }
193
+ ```
194
+
195
+ ### 선택 연동 (activeIndex)
196
+
197
+ 하이라이트한 날을 앱 상태로 들고 있어 다른 UI와 맞물려요. 데이터를 바꾸면 선이 새 모양으로 미끄러져요.
198
+
199
+ ```tsx
200
+ import { useState } from 'react'
201
+ import { LineChart, type LineSeries, Inline, SegmentedControl, Stack, Text } from '@iamfiro/design'
202
+
203
+ const SERIES: LineSeries[] = [
204
+ { key: 'signup', label: '가입' },
205
+ { key: 'paid', label: '결제' },
206
+ ]
207
+
208
+ const RANGES = {
209
+ week: [
210
+ { x: '월', signup: 120, paid: 32 },
211
+ { x: '화', signup: 180, paid: 41 },
212
+ { x: '수', signup: 150, paid: 38 },
213
+ { x: '목', signup: 210, paid: 55 },
214
+ { x: '금', signup: 260, paid: 61 },
215
+ { x: '토', signup: 190, paid: 44 },
216
+ { x: '일', signup: 170, paid: 40 },
217
+ ],
218
+ lastWeek: [
219
+ { x: '월', signup: 90, paid: 20 },
220
+ { x: '화', signup: 110, paid: 28 },
221
+ { x: '수', signup: 160, paid: 35 },
222
+ { x: '목', signup: 140, paid: 30 },
223
+ { x: '금', signup: 200, paid: 47 },
224
+ { x: '토', signup: 230, paid: 52 },
225
+ { x: '일', signup: 150, paid: 33 },
226
+ ],
227
+ }
228
+
229
+ export default function Example() {
230
+ const [range, setRange] = useState<keyof typeof RANGES>('week')
231
+ const [active, setActive] = useState<number | null>(4)
232
+ const data = RANGES[range]
233
+ const row = active === null ? null : data[active]
234
+
235
+ return (
236
+ <Stack gap={4} style={{ width: '100%', maxWidth: 560 }}>
237
+ <Inline>
238
+ <SegmentedControl
239
+ value={range}
240
+ onChange={setRange}
241
+ ariaLabel="기간"
242
+ options={[
243
+ { value: 'week', label: '이번 주' },
244
+ { value: 'lastWeek', label: '지난주' },
245
+ ]}
246
+ />
247
+ </Inline>
248
+ <LineChart data={data} xKey="x" series={SERIES} activeIndex={active} onActiveIndexChange={setActive} formatTitle={(r) => `${r.x}요일`} />
249
+ <Text variant="body-sm" tone="secondary">
250
+ {row ? `${row.x}요일 결제 전환율 ${Math.round((row.paid / row.signup) * 100)}%` : '차트에서 요일을 골라 보세요.'}
251
+ </Text>
252
+ </Stack>
253
+ )
254
+ }
255
+ ```
256
+
257
+ ### 구간 · 기준선
258
+
259
+ bands는 x 구간(행 index from → to)을 옅은 tone 색으로 칠하고, referenceLines는 값 위치에 점선과 라벨을 그려요. 기준선 값은 y축 범위에 포함돼요.
260
+
261
+ ```tsx
262
+ import { ChartLegend, LineChart, type LineChartBand, type LineChartReferenceLine, Stack } from '@iamfiro/design'
263
+
264
+ const TRAFFIC = [820, 610, 450, 380, 360, 520, 1100, 2300, 3600, 4100, 4300, 4500, 4800, 4600, 4400, 4700, 5200, 5900, 6800, 7100, 6200, 4300, 2600, 1400]
265
+ const DATA = TRAFFIC.map((rps, h) => ({ hour: `${h}시`, rps }))
266
+
267
+ const BANDS: LineChartBand[] = [
268
+ { from: 2, to: 5, tone: 'neutral' },
269
+ { from: 18, to: 20, tone: 'danger' },
270
+ ]
271
+
272
+ const LINES: LineChartReferenceLine[] = [
273
+ { value: 4000, label: '평시 4,000', tone: 'neutral' },
274
+ { value: 6500, label: '한도 6,500', tone: 'danger' },
275
+ ]
276
+
277
+ export default function Example() {
278
+ return (
279
+ <Stack gap={3} style={{ width: '100%', maxWidth: 560 }}>
280
+ <LineChart
281
+ data={DATA}
282
+ xKey="hour"
283
+ series={[{ key: 'rps', label: '초당 요청', color: '--chart-2' }]}
284
+ curve="smooth"
285
+ area
286
+ height={220}
287
+ bands={BANDS}
288
+ referenceLines={LINES}
289
+ formatValue={(v) => `${v.toLocaleString('ko-KR')}건/초`}
290
+ legend={false}
291
+ aria-label="시간대별 초당 요청 수"
292
+ />
293
+ <ChartLegend
294
+ items={[
295
+ { key: 'maintenance', label: '정기 점검', color: '--surface-active' },
296
+ { key: 'over', label: '한도 초과', color: '--danger-soft' },
297
+ ]}
298
+ />
299
+ </Stack>
300
+ )
301
+ }
302
+ ```
303
+
304
+ ### 실시간 스트리밍
305
+
306
+ streaming은 데이터가 한 칸씩 밀릴 때 모양을 바꾸지 않고 플롯 전체를 왼쪽으로 미끄러뜨려요(숫자 = 이동 ms, 갱신 주기와 맞추면 끊김 없이 흘러요). 작고 낮은 높이에 yTicks={[0, 12, 24]}, xTicks="edges"로 양 끝 라벨만, endDot="pulse"로 마지막 점에 맥박을 둬요.
307
+
308
+ ```tsx
309
+ import { useEffect, useState } from 'react'
310
+ import { Pause, Play } from 'lucide-react'
311
+ import { LineChart, type LineChartBand, Button, Inline, Stack, Text } from '@iamfiro/design'
312
+
313
+ const POINTS = 97 // one per second → "96초 전" … "지금"
314
+ const LIMIT = 12
315
+
316
+ /** Next queue depth: small drift pulled back toward ~6, an occasional burst or drain. */
317
+ const step = (prev: number, r: number) => {
318
+ const drift = (r < 0.06 ? 8 : r > 0.94 ? -6 : (r - 0.5) * 3) + (6 - prev) * 0.12
319
+ return Math.max(0, Math.min(23, Math.round(prev + drift)))
320
+ }
321
+
322
+ // A fixed seed keeps the first picture the same on every load.
323
+ const INITIAL = (() => {
324
+ let seed = 11
325
+ const rand = () => (seed = (seed * 16807) % 2147483647) / 2147483647
326
+ const rows: Array<{ id: number; depth: number }> = []
327
+ let depth = 4
328
+ for (let i = 0; i < POINTS; i++) {
329
+ depth = step(depth, rand())
330
+ rows.push({ id: i, depth })
331
+ }
332
+ return rows
333
+ })()
334
+
335
+ /** Runs of rows at or over the limit become warning bands. */
336
+ function overLimit(rows: Array<{ depth: number }>): LineChartBand[] {
337
+ const bands: LineChartBand[] = []
338
+ rows.forEach((r, i) => {
339
+ if (r.depth < LIMIT) return
340
+ const last = bands[bands.length - 1]
341
+ if (last && last.to === i - 1) last.to = i
342
+ else bands.push({ from: Math.max(0, i - 1), to: i, tone: 'warning' })
343
+ })
344
+ return bands
345
+ }
346
+
347
+ const ago = (i: number) => (i === POINTS - 1 ? '지금' : `${POINTS - 1 - i}초 전`)
348
+
349
+ export default function Example() {
350
+ const [rows, setRows] = useState(INITIAL)
351
+ const [running, setRunning] = useState(true)
352
+
353
+ useEffect(() => {
354
+ if (!running) return
355
+ const id = window.setInterval(() => {
356
+ setRows((prev) => {
357
+ const last = prev[prev.length - 1]
358
+ return [...prev.slice(1), { id: last.id + 1, depth: step(last.depth, Math.random()) }]
359
+ })
360
+ }, 1000)
361
+ return () => window.clearInterval(id)
362
+ }, [running])
363
+
364
+ return (
365
+ <Stack gap={2} style={{ width: '100%', maxWidth: 560 }}>
366
+ <Inline justify="between">
367
+ <Text variant="overline">배포 대기열</Text>
368
+ <Button size="sm" variant="ghost" icon={running ? <Pause /> : <Play />} onClick={() => setRunning((r) => !r)}>
369
+ {running ? '일시정지' : '재개'}
370
+ </Button>
371
+ </Inline>
372
+ <LineChart
373
+ data={rows}
374
+ xKey="id"
375
+ series={[{ key: 'depth', label: '대기 작업', color: '--chart-4' }]}
376
+ area="solid"
377
+ height={140}
378
+ yTicks={[0, 12, 24]}
379
+ xTicks="edges"
380
+ formatX={(_, i) => ago(i)}
381
+ formatTitle={(_, i) => ago(i)}
382
+ formatValue={(v) => `${v}개`}
383
+ bands={overLimit(rows)}
384
+ referenceLines={[{ value: LIMIT }]}
385
+ endDot={running ? 'pulse' : true}
386
+ streaming={1000}
387
+ legend={false}
388
+ aria-label="최근 96초 배포 대기열 길이"
389
+ />
390
+ </Stack>
391
+ )
392
+ }
393
+ ```
@@ -0,0 +1,53 @@
1
+ # Link
2
+
3
+ > 버튼 & 링크 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
4
+
5
+ 글 속 링크. 옅은 밑줄이 있고 마우스를 올리면 밑줄이 진해져요. 본문에선 파란 accent, 회색 설명 줄 · 이벤트 줄(Marker) 안에선 주변 글자색을 그대로 쓰는 inherit을 써요. 버튼처럼 동작하는 것은 Button variant="ghost"로 만들어요.
6
+
7
+ ```tsx
8
+ import { Link } from '@iamfiro/design'
9
+ ```
10
+
11
+ ## 디자인 규칙
12
+
13
+ - 대화 사이의 이벤트 줄(초대 · 병합 · 고정)은 `Marker`: 16px 아이콘 + 회색 한 줄, 배경 · 테두리 없음. 아이콘은 기본 회색, 결과에 상태가 담긴 이벤트만 `tone`(병합 = success). 스레드 안에선 `gutter={avatarSize}`로 아바타 열에 맞춘다. 글 속 참조(#482)는 `Link variant="inherit"`(주변 색 + 밑줄).
14
+
15
+ ## API
16
+
17
+ ### Link
18
+
19
+ <a>의 모든 속성(href, target, onClick…)을 그대로 받아요.
20
+
21
+ | prop | 타입 | 기본값 | 설명 |
22
+ | --- | --- | --- | --- |
23
+ | `variant` | `'accent' \| 'inherit'` | `'accent'` | accent: 파란 글자 · inherit: 주변 글자색 + 밑줄, hover에 진한 글자. |
24
+ | `href` | `string` | | 이동할 주소. |
25
+ | `className` | `string` | | 추가 클래스. |
26
+
27
+ ## 예제
28
+
29
+ 예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
30
+
31
+ ### accent · inherit
32
+
33
+ accent는 본문 속 링크, inherit은 회색 글 안에서 밑줄로만 링크임을 알려요. 키보드로 포커스하면 파란 링이 생겨요.
34
+
35
+ ```tsx
36
+ import { Link, Stack, Text } from '@iamfiro/design'
37
+
38
+ export default function Example() {
39
+ return (
40
+ <Stack gap={3} style={{ maxWidth: 420 }}>
41
+ <Text variant="body-md">
42
+ 자세한 설정은 <Link href="#">워크스페이스 설정</Link>에서 바꿀 수 있어요.
43
+ </Text>
44
+ <Text variant="body-md" tone="secondary">
45
+ 박솔 님이 <Link variant="inherit" href="#">#482</Link>를 main에 병합했어요.
46
+ </Text>
47
+ <Text variant="caption" tone="tertiary">
48
+ 마지막 배포 <Link variant="inherit" href="#">v2.14.0</Link> · 10월 25일
49
+ </Text>
50
+ </Stack>
51
+ )
52
+ }
53
+ ```