@mindlogic-ai/logician-ui 2.0.0-alpha.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 (432) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +234 -0
  3. package/USAGE.md +299 -0
  4. package/dist/Markdown-2D5K42BY.js +16 -0
  5. package/dist/Markdown-2D5K42BY.js.map +1 -0
  6. package/dist/Markdown-AZBXO5ZP.css +29 -0
  7. package/dist/Markdown-AZBXO5ZP.css.map +1 -0
  8. package/dist/Markdown-RJJEQN4R.mjs +3 -0
  9. package/dist/Markdown-RJJEQN4R.mjs.map +1 -0
  10. package/dist/analytics-GNSHP7X3.svg +1 -0
  11. package/dist/bulb-24SQINQB.svg +1 -0
  12. package/dist/chat-TLRFEUAS.svg +1 -0
  13. package/dist/chunk-5FHXD7KR.js +1735 -0
  14. package/dist/chunk-5FHXD7KR.js.map +1 -0
  15. package/dist/chunk-WSOHBA2C.mjs +1693 -0
  16. package/dist/chunk-WSOHBA2C.mjs.map +1 -0
  17. package/dist/edit-RWL72JNM.svg +1 -0
  18. package/dist/face-55KPDCH4.svg +1 -0
  19. package/dist/filled-analytics-RBC7KWND.svg +1 -0
  20. package/dist/filled-bulb-RC7E2WSM.svg +1 -0
  21. package/dist/filled-chat-A6J44Q7A.svg +1 -0
  22. package/dist/filled-edit-NKKWFSTW.svg +1 -0
  23. package/dist/filled-face-UML5C3LB.svg +1 -0
  24. package/dist/filled-layout-HBVCSDFO.svg +1 -0
  25. package/dist/index.css +51 -0
  26. package/dist/index.css.map +1 -0
  27. package/dist/index.d.mts +964 -0
  28. package/dist/index.d.ts +964 -0
  29. package/dist/index.js +5600 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/index.mjs +5401 -0
  32. package/dist/index.mjs.map +1 -0
  33. package/dist/language-VBJ24OPV.svg +1 -0
  34. package/dist/layout-NDDSWNNV.svg +1 -0
  35. package/dist/pending-NF7NSBYO.svg +1 -0
  36. package/dist/receipt-MNLQIFCO.svg +1 -0
  37. package/dist/sparkles-EOEGVL6G.svg +1 -0
  38. package/dist/store-3RQPBJWG.svg +1 -0
  39. package/dist/store_active-SAOAGVKC.svg +1 -0
  40. package/dist/studio-LYPUIEFA.svg +1 -0
  41. package/dist/studio_active-BC6O66OI.svg +1 -0
  42. package/dist/vertical-ellipsis-3G4WEOCW.svg +1 -0
  43. package/package.json +138 -0
  44. package/src/components/Accordion/Accordion.stories.tsx +41 -0
  45. package/src/components/Accordion/Accordion.tsx +14 -0
  46. package/src/components/Accordion/AccordionButton.tsx +40 -0
  47. package/src/components/Accordion/AccordionItem.tsx +17 -0
  48. package/src/components/Accordion/index.ts +4 -0
  49. package/src/components/Alert/Alert.stories.tsx +38 -0
  50. package/src/components/Alert/Alert.styles.ts +19 -0
  51. package/src/components/Alert/Alert.tsx +41 -0
  52. package/src/components/Alert/Alert.types.ts +5 -0
  53. package/src/components/Alert/index.ts +1 -0
  54. package/src/components/AutowidthInput/AutowidthInput.stories.tsx +23 -0
  55. package/src/components/AutowidthInput/AutowidthInput.tsx +47 -0
  56. package/src/components/AutowidthInput/index.ts +1 -0
  57. package/src/components/Avatar/Avatar.stories.tsx +23 -0
  58. package/src/components/Avatar/Avatar.tsx +19 -0
  59. package/src/components/Avatar/index.tsx +1 -0
  60. package/src/components/Badge/Badge.stories.tsx +23 -0
  61. package/src/components/Badge/Badge.styles.ts +11 -0
  62. package/src/components/Badge/Badge.tsx +26 -0
  63. package/src/components/Badge/index.ts +2 -0
  64. package/src/components/Banner/Banner.stories.tsx +37 -0
  65. package/src/components/Banner/Banner.styles.ts +79 -0
  66. package/src/components/Banner/Banner.tsx +68 -0
  67. package/src/components/Banner/Banner.types.ts +6 -0
  68. package/src/components/Banner/index.ts +2 -0
  69. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +14 -0
  70. package/src/components/Breadcrumb/Breadcrumb.tsx +19 -0
  71. package/src/components/Breadcrumb/Breadcrumb.types.ts +3 -0
  72. package/src/components/Breadcrumb/BreadcrumbItem/BreadcrumbItem.tsx +12 -0
  73. package/src/components/Breadcrumb/BreadcrumbItem/BreadcrumbItem.types.ts +3 -0
  74. package/src/components/Breadcrumb/BreadcrumbItem/index.ts +2 -0
  75. package/src/components/Breadcrumb/BreadcrumbLink/BreadcrumbLink.tsx +30 -0
  76. package/src/components/Breadcrumb/BreadcrumbLink/BreadcrumbLink.types.ts +3 -0
  77. package/src/components/Breadcrumb/BreadcrumbLink/index.ts +2 -0
  78. package/src/components/Breadcrumb/index.ts +3 -0
  79. package/src/components/Button/Button.stories.tsx +52 -0
  80. package/src/components/Button/Button.styles.ts +59 -0
  81. package/src/components/Button/Button.tsx +43 -0
  82. package/src/components/Button/Button.types.ts +13 -0
  83. package/src/components/Button/index.tsx +3 -0
  84. package/src/components/Card/Card.stories.tsx +24 -0
  85. package/src/components/Card/Card.styles.ts +30 -0
  86. package/src/components/Card/Card.tsx +29 -0
  87. package/src/components/Card/Card.types.ts +8 -0
  88. package/src/components/Card/index.ts +2 -0
  89. package/src/components/Carousel/Carousel.stories.tsx +159 -0
  90. package/src/components/Carousel/Carousel.tsx +160 -0
  91. package/src/components/Carousel/Carousel.types.ts +22 -0
  92. package/src/components/Carousel/index.ts +1 -0
  93. package/src/components/CarouselModal/CarouselModal.stories.tsx +53 -0
  94. package/src/components/CarouselModal/CarouselModal.tsx +106 -0
  95. package/src/components/CarouselModal/CarouselModal.types.ts +16 -0
  96. package/src/components/CarouselModal/index.ts +2 -0
  97. package/src/components/Checkbox/Checkbox.stories.tsx +16 -0
  98. package/src/components/Checkbox/Checkbox.tsx +29 -0
  99. package/src/components/Checkbox/Checkbox.types.ts +3 -0
  100. package/src/components/Checkbox/index.ts +2 -0
  101. package/src/components/Chip/Chip.stories.tsx +44 -0
  102. package/src/components/Chip/Chip.styles.ts +114 -0
  103. package/src/components/Chip/Chip.tsx +23 -0
  104. package/src/components/Chip/Chip.types.ts +14 -0
  105. package/src/components/Chip/index.ts +2 -0
  106. package/src/components/ChipButton/Chip.types.ts +4 -0
  107. package/src/components/ChipButton/ChipButton.tsx +25 -0
  108. package/src/components/ChipButton/index.ts +1 -0
  109. package/src/components/Code/Code.stories.tsx +28 -0
  110. package/src/components/Code/Code.tsx +160 -0
  111. package/src/components/Code/Code.types.ts +40 -0
  112. package/src/components/Code/_components/CopyButton.tsx +48 -0
  113. package/src/components/Code/index.ts +1 -0
  114. package/src/components/CodeTabs/CodeTabs.stories.tsx +51 -0
  115. package/src/components/CodeTabs/CodeTabs.tsx +98 -0
  116. package/src/components/CodeTabs/CodeTabs.types.ts +17 -0
  117. package/src/components/CodeTabs/index.ts +1 -0
  118. package/src/components/Container/Container.stories.tsx +28 -0
  119. package/src/components/Container/Container.tsx +21 -0
  120. package/src/components/Container/index.ts +1 -0
  121. package/src/components/Container/useContainerSize.ts +47 -0
  122. package/src/components/CopyableCode/CopyableCode.stories.tsx +26 -0
  123. package/src/components/CopyableCode/CopyableCode.tsx +58 -0
  124. package/src/components/CopyableCode/CopyableCode.types.ts +7 -0
  125. package/src/components/CopyableCode/index.ts +2 -0
  126. package/src/components/CrossPageToasts/CrossPageToasts.tsx +33 -0
  127. package/src/components/CrossPageToasts/index.ts +1 -0
  128. package/src/components/DataField/DataField.stories.tsx +61 -0
  129. package/src/components/DataField/DataField.styles.ts +33 -0
  130. package/src/components/DataField/DataField.tsx +141 -0
  131. package/src/components/DataField/DataField.types.ts +18 -0
  132. package/src/components/DataField/index.ts +1 -0
  133. package/src/components/DatePicker/RangeDatePicker.stories.tsx +45 -0
  134. package/src/components/DatePicker/RangeDatePicker.tsx +74 -0
  135. package/src/components/DatePicker/SingleDatePicker.stories.tsx +31 -0
  136. package/src/components/DatePicker/SingleDatePicker.tsx +72 -0
  137. package/src/components/DatePicker/index.ts +2 -0
  138. package/src/components/FileInput/FileInput.stories.tsx +28 -0
  139. package/src/components/FileInput/FileInput.tsx +117 -0
  140. package/src/components/FileInput/FileInput.types.ts +14 -0
  141. package/src/components/FileInput/index.ts +2 -0
  142. package/src/components/FileItem/FileItem.stories.tsx +27 -0
  143. package/src/components/FileItem/FileItem.tsx +134 -0
  144. package/src/components/FileItem/FileItem.types.ts +11 -0
  145. package/src/components/FileItem/index.ts +1 -0
  146. package/src/components/FileList/FileList.stories.tsx +65 -0
  147. package/src/components/FileList/FileList.tsx +97 -0
  148. package/src/components/FileList/FileList.types.ts +18 -0
  149. package/src/components/FileList/index.tsx +1 -0
  150. package/src/components/FormControl/FormControl.stories.tsx +16 -0
  151. package/src/components/FormControl/FormControl.tsx +12 -0
  152. package/src/components/FormControl/FormControl.types.ts +3 -0
  153. package/src/components/FormControl/index.ts +2 -0
  154. package/src/components/FormLabel/FormLabel.tsx +5 -0
  155. package/src/components/FormLabel/index.ts +1 -0
  156. package/src/components/GuideCue/GuideCue.stories.tsx +57 -0
  157. package/src/components/GuideCue/GuideCue.tsx +231 -0
  158. package/src/components/GuideCue/GuideCueContext.tsx +70 -0
  159. package/src/components/GuideCue/index.ts +2 -0
  160. package/src/components/Icon/Icon.stories.tsx +77 -0
  161. package/src/components/Icon/Icon.styles.ts +6 -0
  162. package/src/components/Icon/Icon.tsx +73 -0
  163. package/src/components/Icon/Icon.types.ts +10 -0
  164. package/src/components/Icon/IconMap.ts +290 -0
  165. package/src/components/Icon/icons/analytics.svg +1 -0
  166. package/src/components/Icon/icons/bulb.svg +1 -0
  167. package/src/components/Icon/icons/chat.svg +1 -0
  168. package/src/components/Icon/icons/edit.svg +1 -0
  169. package/src/components/Icon/icons/face.svg +1 -0
  170. package/src/components/Icon/icons/filled-analytics.svg +1 -0
  171. package/src/components/Icon/icons/filled-bulb.svg +1 -0
  172. package/src/components/Icon/icons/filled-chat.svg +1 -0
  173. package/src/components/Icon/icons/filled-edit.svg +1 -0
  174. package/src/components/Icon/icons/filled-face.svg +1 -0
  175. package/src/components/Icon/icons/filled-layout.svg +1 -0
  176. package/src/components/Icon/icons/language.svg +1 -0
  177. package/src/components/Icon/icons/layout.svg +1 -0
  178. package/src/components/Icon/icons/pending.svg +1 -0
  179. package/src/components/Icon/icons/receipt.svg +1 -0
  180. package/src/components/Icon/icons/sparkles.svg +1 -0
  181. package/src/components/Icon/icons/store.svg +1 -0
  182. package/src/components/Icon/icons/store_active.svg +1 -0
  183. package/src/components/Icon/icons/studio.svg +1 -0
  184. package/src/components/Icon/icons/studio_active.svg +1 -0
  185. package/src/components/Icon/icons/vertical-ellipsis.svg +1 -0
  186. package/src/components/Icon/index.tsx +3 -0
  187. package/src/components/IconButton/IconButton.stories.tsx +51 -0
  188. package/src/components/IconButton/IconButton.styles.ts +52 -0
  189. package/src/components/IconButton/IconButton.tsx +36 -0
  190. package/src/components/IconButton/IconButton.types.ts +12 -0
  191. package/src/components/IconButton/index.tsx +1 -0
  192. package/src/components/InfoSprinkle/InfoSprinkle.stories.tsx +25 -0
  193. package/src/components/InfoSprinkle/InfoSprinkle.tsx +48 -0
  194. package/src/components/InfoSprinkle/index.ts +1 -0
  195. package/src/components/InlineCode/InlineCode.tsx +18 -0
  196. package/src/components/InlineCode/index.ts +1 -0
  197. package/src/components/Input/Input.stories.tsx +55 -0
  198. package/src/components/Input/Input.tsx +358 -0
  199. package/src/components/Input/Input.types.ts +19 -0
  200. package/src/components/Input/index.tsx +2 -0
  201. package/src/components/LineGraph/LineGraph.stories.tsx +98 -0
  202. package/src/components/LineGraph/LineGraph.tsx +88 -0
  203. package/src/components/LineGraph/LineGraph.types.ts +41 -0
  204. package/src/components/LineGraph/index.ts +1 -0
  205. package/src/components/Link/Link.styles.ts +13 -0
  206. package/src/components/Link/Link.tsx +93 -0
  207. package/src/components/Link/index.ts +1 -0
  208. package/src/components/Loaders/PageLoader.stories.tsx +29 -0
  209. package/src/components/Loaders/PageLoader.tsx +30 -0
  210. package/src/components/Loaders/SectionLoader.stories.tsx +26 -0
  211. package/src/components/Loaders/SectionLoader.tsx +30 -0
  212. package/src/components/Loaders/index.ts +1 -0
  213. package/src/components/MDXEditor/MDXEditor.css +21 -0
  214. package/src/components/MDXEditor/MDXEditor.stories.tsx +45 -0
  215. package/src/components/MDXEditor/MDXEditor.tsx +189 -0
  216. package/src/components/MDXEditor/MDXEditor.types.ts +6 -0
  217. package/src/components/MDXEditor/index.ts +1 -0
  218. package/src/components/Markdown/Markdown.module.css +30 -0
  219. package/src/components/Markdown/Markdown.tsx +133 -0
  220. package/src/components/Markdown/Markdown.types.ts +5 -0
  221. package/src/components/Markdown/index.ts +2 -0
  222. package/src/components/Masonry/Masonry.stories.tsx +288 -0
  223. package/src/components/Masonry/Masonry.tsx +187 -0
  224. package/src/components/Masonry/Masonry.types.ts +18 -0
  225. package/src/components/Masonry/index.ts +2 -0
  226. package/src/components/MaxLengthIndicator/MaxLengthIndicator.stories.tsx +26 -0
  227. package/src/components/MaxLengthIndicator/MaxLengthIndicator.tsx +25 -0
  228. package/src/components/MaxLengthIndicator/index.tsx +1 -0
  229. package/src/components/Menu/Menu.stories.tsx +186 -0
  230. package/src/components/Menu/MenuButton.tsx +8 -0
  231. package/src/components/Menu/MenuButton.types.ts +23 -0
  232. package/src/components/Menu/MenuItem.tsx +35 -0
  233. package/src/components/Menu/MenuItem.types.ts +13 -0
  234. package/src/components/Menu/MenuList.tsx +19 -0
  235. package/src/components/Menu/index.ts +7 -0
  236. package/src/components/Modal/Modal.stories.tsx +83 -0
  237. package/src/components/Modal/Modal.styles.ts +14 -0
  238. package/src/components/Modal/Modal.tsx +14 -0
  239. package/src/components/Modal/Modal.types.ts +3 -0
  240. package/src/components/Modal/ModalBody.tsx +9 -0
  241. package/src/components/Modal/ModalCloseButton.tsx +18 -0
  242. package/src/components/Modal/ModalContent/ModalContent.tsx +8 -0
  243. package/src/components/Modal/ModalContent/ModalContent.types.ts +3 -0
  244. package/src/components/Modal/ModalContent/index.ts +1 -0
  245. package/src/components/Modal/ModalFooter/ModalFooter.module.css +3 -0
  246. package/src/components/Modal/ModalFooter/ModalFooter.tsx +20 -0
  247. package/src/components/Modal/ModalFooter/index.ts +1 -0
  248. package/src/components/Modal/ModalHeader.tsx +9 -0
  249. package/src/components/Modal/ModalOverlay.tsx +9 -0
  250. package/src/components/Modal/index.tsx +8 -0
  251. package/src/components/MonthRangePicker/MonthButton/MonthButton.tsx +105 -0
  252. package/src/components/MonthRangePicker/MonthButton/MonthButton.types.ts +42 -0
  253. package/src/components/MonthRangePicker/MonthButton/index.ts +2 -0
  254. package/src/components/MonthRangePicker/MonthRangePicker.stories.tsx +164 -0
  255. package/src/components/MonthRangePicker/MonthRangePicker.tsx +274 -0
  256. package/src/components/MonthRangePicker/MonthRangePicker.types.ts +38 -0
  257. package/src/components/MonthRangePicker/_utils/hasEnabledMonthsInYear.ts +15 -0
  258. package/src/components/MonthRangePicker/_utils/index.ts +6 -0
  259. package/src/components/MonthRangePicker/_utils/isMonthDisabled.ts +20 -0
  260. package/src/components/MonthRangePicker/_utils/isMonthInPreviewRange.ts +32 -0
  261. package/src/components/MonthRangePicker/_utils/isMonthInRange.ts +17 -0
  262. package/src/components/MonthRangePicker/_utils/isMonthSelected.ts +19 -0
  263. package/src/components/MonthRangePicker/_utils/isSelectionStart.ts +12 -0
  264. package/src/components/MonthRangePicker/constants.ts +63 -0
  265. package/src/components/MonthRangePicker/index.ts +2 -0
  266. package/src/components/Pagination/Pagination.stories.tsx +51 -0
  267. package/src/components/Pagination/Pagination.tsx +150 -0
  268. package/src/components/Pagination/Pagination.types.ts +12 -0
  269. package/src/components/Pagination/index.tsx +1 -0
  270. package/src/components/PasswordInput/PasswordInput.stories.tsx +16 -0
  271. package/src/components/PasswordInput/PasswordInput.tsx +42 -0
  272. package/src/components/PasswordInput/PasswordInput.types.ts +11 -0
  273. package/src/components/PasswordInput/index.ts +1 -0
  274. package/src/components/PinInput/PinInput.stories.tsx +26 -0
  275. package/src/components/PinInput/PinInput.tsx +53 -0
  276. package/src/components/PinInput/PinInput.types.ts +27 -0
  277. package/src/components/PinInput/index.tsx +2 -0
  278. package/src/components/ProgressBar/ProgressBar.stories.tsx +18 -0
  279. package/src/components/ProgressBar/ProgressBar.styles.ts +4 -0
  280. package/src/components/ProgressBar/ProgressBar.tsx +27 -0
  281. package/src/components/ProgressBar/ProgressBar.types.ts +4 -0
  282. package/src/components/ProgressBar/index.ts +1 -0
  283. package/src/components/RadialProgress/RadialProgress.stories.tsx +272 -0
  284. package/src/components/RadialProgress/RadialProgress.tsx +232 -0
  285. package/src/components/RadialProgress/RadialProgress.types.ts +27 -0
  286. package/src/components/RadialProgress/index.ts +2 -0
  287. package/src/components/Radio/Radio.stories.tsx +226 -0
  288. package/src/components/Radio/Radio.tsx +35 -0
  289. package/src/components/Radio/Radio.types.ts +21 -0
  290. package/src/components/Radio/RadioGroup.tsx +26 -0
  291. package/src/components/Radio/index.ts +3 -0
  292. package/src/components/SeeMoreButton/SeeMoreButton.stories.tsx +48 -0
  293. package/src/components/SeeMoreButton/SeeMoreButton.styles.ts +11 -0
  294. package/src/components/SeeMoreButton/SeeMoreButton.tsx +34 -0
  295. package/src/components/SeeMoreButton/SeeMoreButton.types.ts +6 -0
  296. package/src/components/SeeMoreButton/index.tsx +1 -0
  297. package/src/components/SegmentedControl/SegmentedControl.stories.tsx +96 -0
  298. package/src/components/SegmentedControl/SegmentedControl.styles.ts +28 -0
  299. package/src/components/SegmentedControl/SegmentedControl.tsx +89 -0
  300. package/src/components/SegmentedControl/SegmentedControl.types.ts +15 -0
  301. package/src/components/SegmentedControl/index.ts +2 -0
  302. package/src/components/SegmentedProgressBar/ProgressSegment.tsx +18 -0
  303. package/src/components/SegmentedProgressBar/SegmentedProgressBar.stories.tsx +228 -0
  304. package/src/components/SegmentedProgressBar/SegmentedProgressBar.tsx +25 -0
  305. package/src/components/SegmentedProgressBar/SegmentedProgressBar.types.ts +11 -0
  306. package/src/components/SegmentedProgressBar/SegmentedProgressBarContext.tsx +24 -0
  307. package/src/components/SegmentedProgressBar/index.ts +3 -0
  308. package/src/components/Select/MenuList/MenuList.tsx +87 -0
  309. package/src/components/Select/MenuList/MenuList.types.ts +21 -0
  310. package/src/components/Select/MenuList/VirtualizedMenuList.tsx +140 -0
  311. package/src/components/Select/MenuList/VirtualizedMenuListContext.tsx +35 -0
  312. package/src/components/Select/MenuList/index.ts +3 -0
  313. package/src/components/Select/Select.stories.tsx +70 -0
  314. package/src/components/Select/Select.styles.ts +102 -0
  315. package/src/components/Select/Select.tsx +204 -0
  316. package/src/components/Select/Select.types.ts +18 -0
  317. package/src/components/Select/_utils/resolveStyle.ts +21 -0
  318. package/src/components/Select/index.ts +1 -0
  319. package/src/components/Slider/Slider.stories.tsx +75 -0
  320. package/src/components/Slider/Slider.tsx +12 -0
  321. package/src/components/Slider/Slider.types.ts +3 -0
  322. package/src/components/Slider/SliderFilledTrack/SliderFilledTrack.tsx +14 -0
  323. package/src/components/Slider/SliderFilledTrack/SliderFilledTrack.types.ts +3 -0
  324. package/src/components/Slider/SliderFilledTrack/index.ts +2 -0
  325. package/src/components/Slider/SliderMark/SliderMark.tsx +12 -0
  326. package/src/components/Slider/SliderMark/SliderMark.types.ts +3 -0
  327. package/src/components/Slider/SliderMark/index.ts +2 -0
  328. package/src/components/Slider/SliderThumb/SliderThumb.tsx +22 -0
  329. package/src/components/Slider/SliderThumb/SliderThumb.types.ts +3 -0
  330. package/src/components/Slider/SliderThumb/index.ts +2 -0
  331. package/src/components/Slider/SliderTrack/SliderTrack.tsx +12 -0
  332. package/src/components/Slider/SliderTrack/SliderTrack.types.ts +3 -0
  333. package/src/components/Slider/SliderTrack/index.ts +2 -0
  334. package/src/components/Slider/index.ts +5 -0
  335. package/src/components/Spinner/Spinner.stories.tsx +16 -0
  336. package/src/components/Spinner/Spinner.tsx +20 -0
  337. package/src/components/Spinner/Spinner.types.ts +3 -0
  338. package/src/components/Spinner/index.ts +2 -0
  339. package/src/components/Switch/Switch.stories.tsx +63 -0
  340. package/src/components/Switch/Switch.tsx +8 -0
  341. package/src/components/Switch/index.ts +1 -0
  342. package/src/components/Table/ExpandingTr/ExpandingTr.tsx +31 -0
  343. package/src/components/Table/ExpandingTr/ExpandingTr.types.ts +9 -0
  344. package/src/components/Table/ExpandingTr/index.ts +2 -0
  345. package/src/components/Table/Table.stories.tsx +326 -0
  346. package/src/components/Table/Table.styles.ts +48 -0
  347. package/src/components/Table/Table.tsx +9 -0
  348. package/src/components/Table/Table.types.ts +16 -0
  349. package/src/components/Table/TableContainer.tsx +55 -0
  350. package/src/components/Table/TableContext.tsx +187 -0
  351. package/src/components/Table/Tbody.tsx +12 -0
  352. package/src/components/Table/Td.tsx +138 -0
  353. package/src/components/Table/Th.tsx +154 -0
  354. package/src/components/Table/Thead.tsx +5 -0
  355. package/src/components/Table/Tr.tsx +5 -0
  356. package/src/components/Table/index.tsx +8 -0
  357. package/src/components/Tabs/Tab/Tab.styles.ts +35 -0
  358. package/src/components/Tabs/Tab/Tab.tsx +67 -0
  359. package/src/components/Tabs/Tab/index.ts +1 -0
  360. package/src/components/Tabs/TabList/TabList.styles.ts +11 -0
  361. package/src/components/Tabs/TabList/TabList.tsx +19 -0
  362. package/src/components/Tabs/TabList/index.ts +1 -0
  363. package/src/components/Tabs/TabPanel.tsx +5 -0
  364. package/src/components/Tabs/TabPanels.tsx +5 -0
  365. package/src/components/Tabs/Tabs.stories.tsx +45 -0
  366. package/src/components/Tabs/Tabs.tsx +65 -0
  367. package/src/components/Tabs/Tabs.types.ts +19 -0
  368. package/src/components/Tabs/TabsContext.tsx +162 -0
  369. package/src/components/Tabs/index.tsx +5 -0
  370. package/src/components/Tag/Tag.stories.tsx +28 -0
  371. package/src/components/Tag/Tag.styles.ts +12 -0
  372. package/src/components/Tag/Tag.tsx +23 -0
  373. package/src/components/Tag/Tag.types.ts +5 -0
  374. package/src/components/Tag/TagCloseButton/TagCloseButton.tsx +12 -0
  375. package/src/components/Tag/TagCloseButton/TagCloseButton.types.ts +3 -0
  376. package/src/components/Tag/TagCloseButton/index.ts +2 -0
  377. package/src/components/Tag/TagLabel/TagLabel.tsx +12 -0
  378. package/src/components/Tag/TagLabel/TagLabel.types.ts +3 -0
  379. package/src/components/Tag/TagLabel/index.ts +2 -0
  380. package/src/components/Tag/TagLeftIcon/TagLeftIcon.tsx +12 -0
  381. package/src/components/Tag/TagLeftIcon/TagLeftIcon.types.ts +3 -0
  382. package/src/components/Tag/TagLeftIcon/index.ts +2 -0
  383. package/src/components/Tag/TagRightIcon/TagRightIcon.tsx +12 -0
  384. package/src/components/Tag/TagRightIcon/TagRightIcon.types.ts +3 -0
  385. package/src/components/Tag/TagRightIcon/index.ts +2 -0
  386. package/src/components/Tag/index.ts +5 -0
  387. package/src/components/Textarea/Textarea.tsx +56 -0
  388. package/src/components/Textarea/adjustHeight.tsx +9 -0
  389. package/src/components/Textarea/index.ts +1 -0
  390. package/src/components/Toast/Toast.stories.tsx +49 -0
  391. package/src/components/Toast/Toast.styles.ts +19 -0
  392. package/src/components/Toast/Toast.tsx +38 -0
  393. package/src/components/Toast/Toast.types.ts +22 -0
  394. package/src/components/Toast/ToastIcon/ToastIcon.tsx +26 -0
  395. package/src/components/Toast/ToastIcon/index.ts +0 -0
  396. package/src/components/Toast/index.ts +2 -0
  397. package/src/components/Toast/useToast.tsx +65 -0
  398. package/src/components/Tooltip/Tooltip.stories.tsx +97 -0
  399. package/src/components/Tooltip/Tooltip.tsx +22 -0
  400. package/src/components/Tooltip/Tooltip.types.ts +3 -0
  401. package/src/components/Tooltip/index.ts +2 -0
  402. package/src/components/Typography/H1.tsx +17 -0
  403. package/src/components/Typography/H2.tsx +17 -0
  404. package/src/components/Typography/H3.tsx +17 -0
  405. package/src/components/Typography/H4.tsx +17 -0
  406. package/src/components/Typography/H5.tsx +17 -0
  407. package/src/components/Typography/Link.tsx +49 -0
  408. package/src/components/Typography/Subtext.tsx +17 -0
  409. package/src/components/Typography/Subtitle.tsx +18 -0
  410. package/src/components/Typography/Text.tsx +22 -0
  411. package/src/components/Typography/Typography.stories.tsx +54 -0
  412. package/src/components/Typography/Typography.types.ts +3 -0
  413. package/src/components/Typography/index.ts +26 -0
  414. package/src/components/UrlInput/UrlInput.stories.tsx +66 -0
  415. package/src/components/UrlInput/UrlInput.tsx +47 -0
  416. package/src/components/UrlInput/index.tsx +1 -0
  417. package/src/hooks/useLocale.ts +11 -0
  418. package/src/hooks/useTranslate.ts +57 -0
  419. package/src/index.ts +96 -0
  420. package/src/theme/Palette.stories.tsx +171 -0
  421. package/src/theme/colors.ts +64 -0
  422. package/src/theme/font.ts +23 -0
  423. package/src/theme/global.ts +30 -0
  424. package/src/theme/index.ts +49 -0
  425. package/src/translations/Defaults.translations.json +100 -0
  426. package/src/types/css-modules.d.ts +0 -0
  427. package/src/types/svg.d.ts +15 -0
  428. package/src/utils/findKeyByValue.ts +17 -0
  429. package/src/utils/formatDateByLocale.ts +36 -0
  430. package/src/utils/formatFileSize.ts +14 -0
  431. package/src/utils/formatNumber.ts +29 -0
  432. package/src/utils/formatTextForMarkdown.ts +3 -0
@@ -0,0 +1,31 @@
1
+ import { Children } from 'react';
2
+ import { Collapse } from '@chakra-ui/react';
3
+
4
+ import { Td } from '../Td';
5
+ import { Tr } from '../Tr';
6
+ import { ExpandingTrProps } from './ExpandingTr.types';
7
+
8
+ export const ExpandingTr: React.FC<ExpandingTrProps> = ({
9
+ children,
10
+ expandedContent,
11
+ isExpanded,
12
+ onExpandChange,
13
+ expandedRowProps,
14
+ ...rest
15
+ }) => {
16
+ const childrenArray = Children.toArray(children);
17
+
18
+ return (
19
+ <>
20
+ {/* Main Row */}
21
+ <Tr {...rest}>{children}</Tr>
22
+
23
+ {/* Expanded Row */}
24
+ <Tr h={isExpanded ? undefined : 0} {...expandedRowProps}>
25
+ <Td colSpan={childrenArray.length} p={0}>
26
+ <Collapse in={isExpanded}>{expandedContent}</Collapse>
27
+ </Td>
28
+ </Tr>
29
+ </>
30
+ );
31
+ };
@@ -0,0 +1,9 @@
1
+ import { TableRowProps } from '@chakra-ui/react';
2
+
3
+ export interface ExpandingTrProps extends TableRowProps {
4
+ children: React.ReactNode;
5
+ isExpanded: boolean; // Controls whether the expanded content is visible
6
+ onExpandChange?: (isExpanded: boolean) => void; // Callback for when expansion state changes
7
+ expandedRowProps?: TableRowProps;
8
+ expandedContent: React.ReactNode;
9
+ }
@@ -0,0 +1,2 @@
1
+ export { ExpandingTr } from './ExpandingTr';
2
+ export { type ExpandingTrProps } from './ExpandingTr.types';
@@ -0,0 +1,326 @@
1
+ import React, { useState } from 'react';
2
+ import { Flex } from '@chakra-ui/react';
3
+ import { Meta, StoryObj } from '@storybook/react';
4
+
5
+ import { Icon } from '../Icon';
6
+ import { IconButton } from '../IconButton';
7
+ import {
8
+ ExpandingTr,
9
+ Table,
10
+ TableContainer,
11
+ Tbody,
12
+ Td,
13
+ Th,
14
+ Thead,
15
+ Tr,
16
+ } from '.';
17
+
18
+ const meta: Meta<typeof Table> = {
19
+ title: 'Components/Table',
20
+ component: Table,
21
+ };
22
+
23
+ export default meta;
24
+
25
+ const columns: {
26
+ key: string;
27
+ label: string;
28
+ }[] = [
29
+ { key: 'unit', label: '헤더1' },
30
+ { key: 'conversion', label: '헤더2' },
31
+ { key: 'factor', label: '헤더3' },
32
+ ];
33
+
34
+ const wideColumns: {
35
+ key: string;
36
+ label: string;
37
+ }[] = [
38
+ { key: 'id', label: 'ID' },
39
+ { key: 'name', label: '이름' },
40
+ { key: 'email', label: '이메일' },
41
+ { key: 'phone', label: '전화번호' },
42
+ { key: 'address', label: '주소' },
43
+ { key: 'company', label: '회사' },
44
+ { key: 'position', label: '직책' },
45
+ { key: 'department', label: '부서' },
46
+ ];
47
+
48
+ const wideData: Record<string, any>[] = [
49
+ {
50
+ id: 1,
51
+ name: '김철수',
52
+ email: 'kim@example.com',
53
+ phone: '010-1234-5678',
54
+ address: '서울특별시 강남구 테헤란로 123',
55
+ company: '테크 주식회사',
56
+ position: '시니어 개발자',
57
+ department: '프론트엔드 팀',
58
+ },
59
+ {
60
+ id: 2,
61
+ name: '이영희',
62
+ email: 'lee@example.com',
63
+ phone: '010-8765-4321',
64
+ address: '서울특별시 서초구 반포대로 456',
65
+ company: '디지털 솔루션즈',
66
+ position: '제품 매니저',
67
+ department: '제품 팀',
68
+ },
69
+ {
70
+ id: 3,
71
+ name: '박지훈',
72
+ email: 'park@example.com',
73
+ phone: '010-2345-6789',
74
+ address: '서울특별시 마포구 양화로 789',
75
+ company: '크리에이티브 랩스',
76
+ position: 'UX 디자이너',
77
+ department: '디자인 팀',
78
+ },
79
+ ];
80
+
81
+ const data: Record<string, any>[] = [
82
+ {
83
+ unit: 'inches',
84
+ conversion: 'millimetres (mm)',
85
+ factor: 25.4,
86
+ expandedText: 'This should only show when expanded.',
87
+ },
88
+ {
89
+ unit: 'feet',
90
+ conversion: 'centimetres (cm)',
91
+ factor: 30.48,
92
+ expandedText: 'This should only show when expanded.',
93
+ },
94
+ ];
95
+
96
+ type Story = StoryObj<typeof Table>;
97
+
98
+ export const Default: Story = {
99
+ render: (args) => (
100
+ <TableContainer>
101
+ <Table {...args}>
102
+ <Thead>
103
+ <Tr>
104
+ {columns.map((column) => (
105
+ <Th key={column.key}>{column.label}</Th>
106
+ ))}
107
+ </Tr>
108
+ </Thead>
109
+ <Tbody>
110
+ {data.map((item) => (
111
+ <Tr>
112
+ {columns.map((column) => (
113
+ <Td key={column.key}>{item[column.key]}</Td>
114
+ ))}
115
+ </Tr>
116
+ ))}
117
+ </Tbody>
118
+ </Table>
119
+ </TableContainer>
120
+ ),
121
+ args: {},
122
+ argTypes: {},
123
+ };
124
+
125
+ export const ExpandedContent: Story = {
126
+ render: (args) => (
127
+ <TableContainer maxW="100%">
128
+ <Table {...args}>
129
+ <Thead>
130
+ <Tr>
131
+ {columns.map((column) => (
132
+ <Th key={column.key}>{column.label}</Th>
133
+ ))}
134
+ </Tr>
135
+ </Thead>
136
+ <Tbody>
137
+ {data.map((item) => {
138
+ const [isExpanded, setIsExpanded] = useState<boolean>(false);
139
+ return (
140
+ <ExpandingTr
141
+ isExpanded={isExpanded}
142
+ onExpandChange={setIsExpanded}
143
+ expandedContent={
144
+ <Flex p={4} align="center" justify="center">
145
+ {item.expandedText}
146
+ </Flex>
147
+ }
148
+ >
149
+ {columns.map((column) => (
150
+ <Td key={column.key}>{item[column.key]}</Td>
151
+ ))}
152
+ <Td w={2}>
153
+ <IconButton
154
+ aria-label="Expand"
155
+ icon={<Icon icon="IoChevronDownOutline" />}
156
+ onClick={() => setIsExpanded((e) => !e)}
157
+ />
158
+ </Td>
159
+ </ExpandingTr>
160
+ );
161
+ })}
162
+ </Tbody>
163
+ </Table>
164
+ </TableContainer>
165
+ ),
166
+ args: {},
167
+ argTypes: {},
168
+ };
169
+
170
+ export const WithLeftStickyColumn: Story = {
171
+ render: (args) => (
172
+ <TableContainer>
173
+ <Table {...args}>
174
+ <Thead>
175
+ <Tr>
176
+ {wideColumns.map((column, index) => (
177
+ <Th
178
+ key={column.key}
179
+ isSticky={index === 0}
180
+ stickyDirection="left"
181
+ >
182
+ {column.label}
183
+ </Th>
184
+ ))}
185
+ </Tr>
186
+ </Thead>
187
+ <Tbody>
188
+ {wideData.map((item) => (
189
+ <Tr key={item.id}>
190
+ {wideColumns.map((column, index) => (
191
+ <Td
192
+ key={column.key}
193
+ isSticky={index === 0}
194
+ stickyDirection="left"
195
+ >
196
+ {item[column.key]}
197
+ </Td>
198
+ ))}
199
+ </Tr>
200
+ ))}
201
+ </Tbody>
202
+ </Table>
203
+ </TableContainer>
204
+ ),
205
+ args: { width: '180%' },
206
+ argTypes: {},
207
+ };
208
+
209
+ export const WithRightStickyColumn: Story = {
210
+ render: (args) => (
211
+ <TableContainer>
212
+ <Table {...args}>
213
+ <Thead>
214
+ <Tr>
215
+ {wideColumns.map((column, index) => (
216
+ <Th
217
+ key={column.key}
218
+ isSticky={index === wideColumns.length - 1}
219
+ stickyDirection="right"
220
+ >
221
+ {column.label}
222
+ </Th>
223
+ ))}
224
+ </Tr>
225
+ </Thead>
226
+ <Tbody>
227
+ {wideData.map((item) => (
228
+ <Tr key={item.id}>
229
+ {wideColumns.map((column, index) => (
230
+ <Td
231
+ key={column.key}
232
+ isSticky={index === wideColumns.length - 1}
233
+ stickyDirection="right"
234
+ >
235
+ {item[column.key]}
236
+ </Td>
237
+ ))}
238
+ </Tr>
239
+ ))}
240
+ </Tbody>
241
+ </Table>
242
+ </TableContainer>
243
+ ),
244
+ args: { width: '180%' },
245
+ argTypes: {},
246
+ };
247
+
248
+ export const WithBothStickyColumns: Story = {
249
+ render: (args) => (
250
+ <TableContainer>
251
+ <Table {...args}>
252
+ <Thead>
253
+ <Tr>
254
+ {wideColumns.map((column, index) => (
255
+ <Th
256
+ key={column.key}
257
+ isSticky={index === 0 || index === wideColumns.length - 1}
258
+ stickyDirection={index === 0 ? 'left' : 'right'}
259
+ >
260
+ {column.label}
261
+ </Th>
262
+ ))}
263
+ </Tr>
264
+ </Thead>
265
+ <Tbody>
266
+ {wideData.map((item) => (
267
+ <Tr key={item.id}>
268
+ {wideColumns.map((column, index) => (
269
+ <Td
270
+ key={column.key}
271
+ isSticky={index === 0 || index === wideColumns.length - 1}
272
+ stickyDirection={index === 0 ? 'left' : 'right'}
273
+ >
274
+ {item[column.key]}
275
+ </Td>
276
+ ))}
277
+ </Tr>
278
+ ))}
279
+ </Tbody>
280
+ </Table>
281
+ </TableContainer>
282
+ ),
283
+ args: { width: '180%' },
284
+ argTypes: {},
285
+ };
286
+
287
+ export const WithTwoLeftStickyColumns: Story = {
288
+ render: (args) => (
289
+ <TableContainer>
290
+ <Table {...args}>
291
+ <Thead>
292
+ <Tr>
293
+ {wideColumns.map((column, index) => (
294
+ <Th
295
+ key={column.key}
296
+ isSticky={index === 0 || index === 1}
297
+ stickyDirection="left"
298
+ stickyIndex={index === 0 || index === 1 ? index : undefined}
299
+ >
300
+ {column.label}
301
+ </Th>
302
+ ))}
303
+ </Tr>
304
+ </Thead>
305
+ <Tbody>
306
+ {wideData.map((item) => (
307
+ <Tr key={item.id}>
308
+ {wideColumns.map((column, index) => (
309
+ <Td
310
+ key={column.key}
311
+ isSticky={index === 0 || index === 1}
312
+ stickyDirection="left"
313
+ stickyIndex={index === 0 || index === 1 ? index : undefined}
314
+ >
315
+ {item[column.key]}
316
+ </Td>
317
+ ))}
318
+ </Tr>
319
+ ))}
320
+ </Tbody>
321
+ </Table>
322
+ </TableContainer>
323
+ ),
324
+ args: { width: '180%' },
325
+ argTypes: {},
326
+ };
@@ -0,0 +1,48 @@
1
+ import { TableScrollState } from './TableContext';
2
+
3
+ export type StickyDirection = 'left' | 'right';
4
+
5
+ export const getStickyStyles = (
6
+ isSticky: boolean,
7
+ stickyDirection: StickyDirection = 'left',
8
+ scrollState: TableScrollState,
9
+ stickyOffset = 0,
10
+ isLastSticky = false
11
+ ) => {
12
+ if (!isSticky || !scrollState) return {};
13
+ const { isScrollStart, isScrollEnd, isScrolling } = scrollState;
14
+
15
+ // 양쪽 sticky 상태
16
+ const isBothSticky =
17
+ (stickyDirection === 'left' && isScrollEnd) ||
18
+ (stickyDirection === 'right' && isScrollStart);
19
+
20
+ // 한쪽 sticky 상태
21
+ const isSingleSticky = isScrolling;
22
+
23
+ // Only show shadow if this is the last sticky column on this side
24
+ const shouldShowShadow = isLastSticky && (isSingleSticky || isBothSticky);
25
+
26
+ return {
27
+ position: 'sticky' as const,
28
+ overflow: 'visible',
29
+ [stickyDirection]: `${stickyOffset}px`,
30
+ zIndex: 2,
31
+ backgroundColor: 'white',
32
+ ...(shouldShowShadow && {
33
+ _after: {
34
+ content: '""',
35
+ position: 'absolute',
36
+ top: 0,
37
+ bottom: '-1px',
38
+ width: '32px',
39
+ insetInlineEnd: stickyDirection === 'left' ? 0 : '100%',
40
+ translate: stickyDirection === 'left' ? '100%' : '-8',
41
+ boxShadow:
42
+ stickyDirection === 'left'
43
+ ? 'rgba(0, 0, 0, 0.16) 8px 0px 8px -8px inset'
44
+ : 'rgba(0, 0, 0, 0.16) -8px 0px 8px -8px inset',
45
+ },
46
+ }),
47
+ };
48
+ };
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import {
3
+ Table as ChakraTable,
4
+ TableProps as ChakraTableProps,
5
+ } from '@chakra-ui/react';
6
+
7
+ export const Table = ({ ...rest }: ChakraTableProps) => {
8
+ return <ChakraTable {...rest} />;
9
+ };
@@ -0,0 +1,16 @@
1
+ import {
2
+ TableCellProps as ChakraTableCellProps,
3
+ TableContainerProps as ChakraTableContainerProps,
4
+ } from '@chakra-ui/react';
5
+
6
+ import { StickyDirection } from './Table.styles';
7
+
8
+ export interface TableContainerProps extends ChakraTableContainerProps {
9
+ children: React.ReactNode;
10
+ }
11
+
12
+ export interface TableCellProps extends ChakraTableCellProps {
13
+ isSticky?: boolean;
14
+ stickyDirection?: StickyDirection;
15
+ stickyIndex?: number;
16
+ }
@@ -0,0 +1,55 @@
1
+ import { forwardRef, useCallback } from 'react';
2
+ import { TableContainer as ChakraTableContainer } from '@chakra-ui/react';
3
+
4
+ import { TableContainerProps } from './Table.types';
5
+ import { TableProvider, useTableContext } from './TableContext';
6
+
7
+ // 실제 테이블 컨테이너 컴포넌트
8
+ const TableContainerInner = forwardRef<HTMLDivElement, TableContainerProps>(
9
+ ({ children, ...rest }, ref) => {
10
+ const { setContainerRef } = useTableContext();
11
+
12
+ // ref 설정 콜백 - 외부 ref와 내부 ref 결합
13
+ const handleRef = useCallback(
14
+ (node: HTMLDivElement | null) => {
15
+ // 외부 ref 설정
16
+ if (typeof ref === 'function') {
17
+ ref(node);
18
+ } else if (ref) {
19
+ ref.current = node;
20
+ }
21
+
22
+ // 내부 컨텍스트 ref 설정
23
+ setContainerRef(node);
24
+ },
25
+ [ref, setContainerRef]
26
+ );
27
+
28
+ return (
29
+ <ChakraTableContainer
30
+ border="1px solid"
31
+ borderRadius="md"
32
+ borderColor="gray.300"
33
+ ref={handleRef}
34
+ {...rest}
35
+ >
36
+ {children}
37
+ </ChakraTableContainer>
38
+ );
39
+ }
40
+ );
41
+
42
+ TableContainerInner.displayName = 'TableContainerInner';
43
+
44
+ // 외부 노출용 컴포넌트
45
+ export const TableContainer = forwardRef<HTMLDivElement, TableContainerProps>(
46
+ (props, ref) => {
47
+ return (
48
+ <TableProvider>
49
+ <TableContainerInner {...props} ref={ref} />
50
+ </TableProvider>
51
+ );
52
+ }
53
+ );
54
+
55
+ TableContainer.displayName = 'TableContainer';
@@ -0,0 +1,187 @@
1
+ import React, {
2
+ createContext,
3
+ ReactNode,
4
+ useCallback,
5
+ useContext,
6
+ useEffect,
7
+ useRef,
8
+ useState,
9
+ } from 'react';
10
+
11
+ export interface TableScrollState {
12
+ isScrollStart: boolean;
13
+ isScrollEnd: boolean;
14
+ isScrolling: boolean;
15
+ }
16
+
17
+ interface StickyColumnInfo {
18
+ leftColumnWidths: Map<number, number>; // Maps index to width
19
+ rightColumnWidths: Map<number, number>; // Maps index to width
20
+ }
21
+
22
+ interface TableContextValue extends TableScrollState {
23
+ setContainerRef: (node: HTMLDivElement | null) => void;
24
+ registerStickyColumn: (
25
+ direction: 'left' | 'right',
26
+ index: number,
27
+ width: number
28
+ ) => void;
29
+ getStickyOffset: (direction: 'left' | 'right', index: number) => number;
30
+ isLastStickyColumn: (direction: 'left' | 'right', index: number) => boolean;
31
+ }
32
+
33
+ const TableContext = createContext<TableContextValue | null>(null);
34
+
35
+ export const useTableContext = () => {
36
+ const context = useContext(TableContext);
37
+ if (!context) {
38
+ console.error('useTableContext must be used within a TableProvider');
39
+ }
40
+ return context;
41
+ };
42
+
43
+ interface TableProviderProps {
44
+ children: ReactNode;
45
+ }
46
+
47
+ export const TableProvider: React.FC<TableProviderProps> = ({ children }) => {
48
+ const containerRef = useRef<HTMLDivElement | null>(null);
49
+ const [scrollState, setScrollState] = useState<TableScrollState>({
50
+ isScrollStart: true,
51
+ isScrollEnd: false,
52
+ isScrolling: false,
53
+ });
54
+
55
+ const stickyColumnsRef = useRef<StickyColumnInfo>({
56
+ leftColumnWidths: new Map(),
57
+ rightColumnWidths: new Map(),
58
+ });
59
+
60
+ // 스크롤 상태 업데이트
61
+ const updateScrollState = useCallback(() => {
62
+ const container = containerRef.current;
63
+ if (!container) return;
64
+
65
+ const { scrollLeft, scrollWidth, clientWidth } = container;
66
+
67
+ const isScrollStart = scrollLeft <= 1;
68
+ const isScrollEnd = Math.abs(scrollWidth - clientWidth - scrollLeft) <= 1;
69
+
70
+ setScrollState((prevState) => {
71
+ // 상태가 변경된 경우에만 업데이트 (불필요한 리렌더링 방지)
72
+ if (
73
+ prevState.isScrollStart !== isScrollStart ||
74
+ prevState.isScrollEnd !== isScrollEnd ||
75
+ prevState.isScrolling !== (!isScrollStart && !isScrollEnd)
76
+ ) {
77
+ return {
78
+ isScrollStart,
79
+ isScrollEnd,
80
+ isScrolling: !isScrollStart && !isScrollEnd,
81
+ };
82
+ }
83
+ return prevState;
84
+ });
85
+ }, []);
86
+
87
+ // 컨테이너 ref 설정 및 상태 업데이트
88
+ const setContainerRef = useCallback(
89
+ (node: HTMLDivElement | null) => {
90
+ containerRef.current = node;
91
+ if (node) {
92
+ updateScrollState();
93
+ }
94
+ },
95
+ [updateScrollState]
96
+ );
97
+
98
+ // Register a sticky column with its width
99
+ const registerStickyColumn = useCallback(
100
+ (direction: 'left' | 'right', index: number, width: number) => {
101
+ if (direction === 'left') {
102
+ stickyColumnsRef.current.leftColumnWidths.set(index, width);
103
+ } else {
104
+ stickyColumnsRef.current.rightColumnWidths.set(index, width);
105
+ }
106
+ },
107
+ []
108
+ );
109
+
110
+ // Get the offset for a sticky column based on its index and direction
111
+ const getStickyOffset = useCallback(
112
+ (direction: 'left' | 'right', index: number) => {
113
+ if (index === 0) return 0;
114
+
115
+ const widthsMap =
116
+ direction === 'left'
117
+ ? stickyColumnsRef.current.leftColumnWidths
118
+ : stickyColumnsRef.current.rightColumnWidths;
119
+
120
+ let offset = 0;
121
+ for (let i = 0; i < index; i++) {
122
+ offset += widthsMap.get(i) || 0;
123
+ }
124
+
125
+ return offset;
126
+ },
127
+ []
128
+ );
129
+
130
+ // Check if a column is the last sticky column on its side
131
+ const isLastStickyColumn = useCallback(
132
+ (direction: 'left' | 'right', index: number) => {
133
+ const widthsMap =
134
+ direction === 'left'
135
+ ? stickyColumnsRef.current.leftColumnWidths
136
+ : stickyColumnsRef.current.rightColumnWidths;
137
+
138
+ // Find the highest index in the map
139
+ let maxIndex = -1;
140
+ for (const idx of widthsMap.keys()) {
141
+ if (idx > maxIndex) maxIndex = idx;
142
+ }
143
+
144
+ return index === maxIndex;
145
+ },
146
+ []
147
+ );
148
+
149
+ // 단일 useEffect에서 모든 이벤트 리스너 관리
150
+ useEffect(() => {
151
+ const container = containerRef.current;
152
+ if (!container) return;
153
+
154
+ // 스크롤 이벤트 핸들러
155
+ const handleScroll = () => updateScrollState();
156
+
157
+ // 리사이즈 이벤트 핸들러
158
+ const handleResize = () => updateScrollState();
159
+
160
+ // 이벤트 리스너 등록
161
+ container.addEventListener('scroll', handleScroll);
162
+ window.addEventListener('resize', handleResize);
163
+
164
+ // 초기 상태 설정
165
+ updateScrollState();
166
+
167
+ // 클린업
168
+ return () => {
169
+ container.removeEventListener('scroll', handleScroll);
170
+ window.removeEventListener('resize', handleResize);
171
+ };
172
+ }, [updateScrollState]);
173
+
174
+ return (
175
+ <TableContext.Provider
176
+ value={{
177
+ ...scrollState,
178
+ setContainerRef,
179
+ registerStickyColumn,
180
+ getStickyOffset,
181
+ isLastStickyColumn,
182
+ }}
183
+ >
184
+ {children}
185
+ </TableContext.Provider>
186
+ );
187
+ };
@@ -0,0 +1,12 @@
1
+ import { forwardRef } from 'react';
2
+ import { TableBodyProps, Tbody as ChakraTbody } from '@chakra-ui/react';
3
+
4
+ export const Tbody = forwardRef<HTMLTableSectionElement, TableBodyProps>(
5
+ (props, ref) => {
6
+ return (
7
+ <ChakraTbody ref={ref} color="gray.1500" fontWeight="medium" {...props} />
8
+ );
9
+ }
10
+ );
11
+
12
+ Tbody.displayName = 'Tbody';