@shohojdhara/atomix 0.3.14 → 0.4.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 (343) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/build-tools/EXAMPLES.md +372 -0
  3. package/build-tools/README.md +242 -0
  4. package/build-tools/__tests__/error-handler.test.js +230 -0
  5. package/build-tools/__tests__/index.test.js +141 -0
  6. package/build-tools/__tests__/rollup-plugin.test.js +194 -0
  7. package/build-tools/__tests__/utils.test.js +161 -0
  8. package/build-tools/__tests__/vite-plugin.test.js +129 -0
  9. package/build-tools/__tests__/webpack-loader.test.js +190 -0
  10. package/build-tools/error-handler.js +308 -0
  11. package/build-tools/index.d.ts +44 -0
  12. package/build-tools/index.js +88 -0
  13. package/build-tools/package.json +50 -0
  14. package/build-tools/rollup-plugin.js +236 -0
  15. package/build-tools/types.d.ts +163 -0
  16. package/build-tools/utils.js +203 -0
  17. package/build-tools/vite-plugin.js +161 -0
  18. package/build-tools/webpack-loader.js +123 -0
  19. package/dist/atomix.css +21044 -2618
  20. package/dist/atomix.css.map +1 -1
  21. package/dist/atomix.min.css +77 -3
  22. package/dist/atomix.min.css.map +1 -1
  23. package/dist/build-tools/EXAMPLES.md +372 -0
  24. package/dist/build-tools/README.md +242 -0
  25. package/dist/build-tools/__tests__/error-handler.test.js +230 -0
  26. package/dist/build-tools/__tests__/index.test.js +141 -0
  27. package/dist/build-tools/__tests__/rollup-plugin.test.js +194 -0
  28. package/dist/build-tools/__tests__/utils.test.js +161 -0
  29. package/dist/build-tools/__tests__/vite-plugin.test.js +129 -0
  30. package/dist/build-tools/__tests__/webpack-loader.test.js +190 -0
  31. package/dist/build-tools/error-handler.js +308 -0
  32. package/dist/build-tools/index.d.ts +44 -0
  33. package/dist/build-tools/index.js +88 -0
  34. package/dist/build-tools/package.json +50 -0
  35. package/dist/build-tools/rollup-plugin.js +236 -0
  36. package/dist/build-tools/types.d.ts +163 -0
  37. package/dist/build-tools/utils.js +203 -0
  38. package/dist/build-tools/vite-plugin.js +161 -0
  39. package/dist/build-tools/webpack-loader.js +123 -0
  40. package/dist/charts.d.ts +1 -1
  41. package/dist/charts.js +86 -57
  42. package/dist/charts.js.map +1 -1
  43. package/dist/core.d.ts +1 -1
  44. package/dist/core.js +136 -112
  45. package/dist/core.js.map +1 -1
  46. package/dist/forms.d.ts +2 -5
  47. package/dist/forms.js +140 -128
  48. package/dist/forms.js.map +1 -1
  49. package/dist/heavy.d.ts +1 -1
  50. package/dist/heavy.js +136 -112
  51. package/dist/heavy.js.map +1 -1
  52. package/dist/index.d.ts +152 -78
  53. package/dist/index.esm.js +346 -340
  54. package/dist/index.esm.js.map +1 -1
  55. package/dist/index.js +359 -353
  56. package/dist/index.js.map +1 -1
  57. package/dist/index.min.js +1 -1
  58. package/dist/index.min.js.map +1 -1
  59. package/dist/layout.js.map +1 -1
  60. package/dist/theme.d.ts +9 -9
  61. package/dist/theme.js.map +1 -1
  62. package/package.json +23 -8
  63. package/scripts/atomix-cli.js +170 -73
  64. package/scripts/cli/__tests__/README.md +81 -0
  65. package/scripts/cli/__tests__/basic.test.js +115 -0
  66. package/scripts/cli/__tests__/component-generator.test.js +332 -0
  67. package/scripts/cli/__tests__/integration.test.js +327 -0
  68. package/scripts/cli/__tests__/test-setup.js +133 -0
  69. package/scripts/cli/__tests__/token-manager.test.js +251 -0
  70. package/scripts/cli/__tests__/utils.test.js +161 -0
  71. package/scripts/cli/component-generator.js +253 -299
  72. package/scripts/cli/dependency-checker.js +355 -0
  73. package/scripts/cli/interactive-init.js +46 -5
  74. package/scripts/cli/template-manager.js +0 -2
  75. package/scripts/cli/templates/common-templates.js +636 -0
  76. package/scripts/cli/templates/composable-templates.js +148 -126
  77. package/scripts/cli/templates/index.js +23 -16
  78. package/scripts/cli/templates/project-templates.js +151 -23
  79. package/scripts/cli/templates/react-templates.js +280 -210
  80. package/scripts/cli/templates/scss-templates.js +90 -91
  81. package/scripts/cli/templates/testing-templates.js +206 -27
  82. package/scripts/cli/templates/testing-utils.js +278 -0
  83. package/scripts/cli/templates/types-templates.js +70 -56
  84. package/scripts/cli/theme-bridge.js +8 -2
  85. package/scripts/cli/token-manager.js +318 -206
  86. package/scripts/cli/utils.js +0 -1
  87. package/src/components/Accordion/Accordion.stories.tsx +358 -850
  88. package/src/components/Accordion/Accordion.test.tsx +70 -50
  89. package/src/components/Accordion/Accordion.tsx +99 -94
  90. package/src/components/AtomixGlass/AtomixGlass.test.tsx +1 -1
  91. package/src/components/AtomixGlass/AtomixGlass.tsx +80 -39
  92. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +103 -81
  93. package/src/components/AtomixGlass/GlassFilter.tsx +9 -16
  94. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +8 -7
  95. package/src/components/AtomixGlass/glass-utils.ts +6 -5
  96. package/src/components/AtomixGlass/shader-utils.ts +133 -52
  97. package/src/components/AtomixGlass/stories/Customization.stories.tsx +131 -0
  98. package/src/components/AtomixGlass/stories/Examples.stories.tsx +2957 -2853
  99. package/src/components/AtomixGlass/stories/Modes.stories.tsx +1 -1
  100. package/src/components/AtomixGlass/stories/Overview.stories.tsx +348 -0
  101. package/src/components/AtomixGlass/stories/Performance.stories.tsx +103 -0
  102. package/src/components/AtomixGlass/stories/Playground.stories.tsx +51 -36
  103. package/src/components/AtomixGlass/stories/{ShaderVariants.stories.tsx → Shaders.stories.tsx} +2 -2
  104. package/src/components/AtomixGlass/stories/shared-components.tsx +90 -190
  105. package/src/components/Avatar/Avatar.stories.tsx +195 -0
  106. package/src/components/Avatar/Avatar.tsx +58 -56
  107. package/src/components/Badge/Badge.stories.tsx +122 -352
  108. package/src/components/Badge/Badge.test.tsx +41 -41
  109. package/src/components/Badge/Badge.tsx +64 -62
  110. package/src/components/Block/Block.stories.tsx +30 -11
  111. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +142 -23
  112. package/src/components/Breadcrumb/Breadcrumb.tsx +62 -60
  113. package/src/components/Button/Button.stories.tsx +454 -1126
  114. package/src/components/Button/Button.test.tsx +123 -0
  115. package/src/components/Button/Button.tsx +88 -60
  116. package/src/components/Button/ButtonGroup.stories.tsx +376 -215
  117. package/src/components/Button/ButtonGroup.tsx +4 -15
  118. package/src/components/Callout/Callout.stories.tsx +316 -568
  119. package/src/components/Card/Card.stories.tsx +292 -81
  120. package/src/components/Card/Card.tsx +30 -14
  121. package/src/components/Chart/AreaChart.tsx +1 -1
  122. package/src/components/Chart/CandlestickChart.tsx +23 -16
  123. package/src/components/Chart/Chart.stories.tsx +153 -16
  124. package/src/components/Chart/Chart.tsx +40 -44
  125. package/src/components/Chart/ChartRenderer.tsx +39 -12
  126. package/src/components/Chart/ChartToolbar.tsx +21 -5
  127. package/src/components/Chart/DonutChart.tsx +1 -1
  128. package/src/components/Chart/FunnelChart.tsx +4 -1
  129. package/src/components/Chart/GaugeChart.tsx +3 -1
  130. package/src/components/Chart/HeatmapChart.tsx +50 -37
  131. package/src/components/Chart/LineChart.tsx +3 -2
  132. package/src/components/Chart/MultiAxisChart.tsx +24 -16
  133. package/src/components/Chart/RadarChart.tsx +19 -17
  134. package/src/components/Chart/ScatterChart.tsx +29 -21
  135. package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +152 -66
  136. package/src/components/ColorModeToggle/ColorModeToggle.tsx +15 -3
  137. package/src/components/Countdown/Countdown.stories.tsx +114 -7
  138. package/src/components/DataTable/DataTable.stories.tsx +349 -144
  139. package/src/components/DataTable/DataTable.test.tsx +26 -148
  140. package/src/components/DataTable/DataTable.tsx +485 -456
  141. package/src/components/DatePicker/DatePicker.stories.tsx +310 -1066
  142. package/src/components/DatePicker/DatePicker.tsx +31 -26
  143. package/src/components/Dropdown/Dropdown.stories.tsx +153 -36
  144. package/src/components/Dropdown/Dropdown.tsx +313 -299
  145. package/src/components/EdgePanel/EdgePanel.stories.tsx +221 -25
  146. package/src/components/EdgePanel/EdgePanel.tsx +1 -3
  147. package/src/components/Footer/Footer.stories.tsx +396 -327
  148. package/src/components/Footer/Footer.tsx +130 -128
  149. package/src/components/Footer/FooterLink.tsx +2 -2
  150. package/src/components/Form/Checkbox.stories.tsx +140 -6
  151. package/src/components/Form/Checkbox.test.tsx +63 -0
  152. package/src/components/Form/Checkbox.tsx +122 -78
  153. package/src/components/Form/Form.stories.tsx +110 -19
  154. package/src/components/Form/FormGroup.stories.tsx +127 -4
  155. package/src/components/Form/Input.stories.tsx +22 -39
  156. package/src/components/Form/Input.test.tsx +38 -44
  157. package/src/components/Form/Radio.stories.tsx +146 -17
  158. package/src/components/Form/Radio.tsx +68 -66
  159. package/src/components/Form/Select.stories.tsx +140 -8
  160. package/src/components/Form/Select.tsx +184 -182
  161. package/src/components/Form/Textarea.stories.tsx +149 -6
  162. package/src/components/Form/Textarea.test.tsx +27 -32
  163. package/src/components/Hero/Hero.stories.tsx +372 -38
  164. package/src/components/Hero/Hero.tsx +201 -55
  165. package/src/components/Icon/index.ts +7 -1
  166. package/src/components/List/List.stories.tsx +141 -3
  167. package/src/components/List/List.tsx +19 -23
  168. package/src/components/Modal/Modal.stories.tsx +183 -43
  169. package/src/components/Modal/Modal.tsx +130 -127
  170. package/src/components/Navigation/Menu/MegaMenu.tsx +70 -70
  171. package/src/components/Navigation/Nav/NavDropdown.tsx +1 -5
  172. package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +128 -28
  173. package/src/components/Navigation/SideMenu/SideMenu.tsx +5 -7
  174. package/src/components/Navigation/SideMenu/SideMenuItem.tsx +4 -5
  175. package/src/components/Pagination/Pagination.stories.tsx +7 -4
  176. package/src/components/Pagination/Pagination.tsx +199 -202
  177. package/src/components/PhotoViewer/PhotoViewer.tsx +4 -1
  178. package/src/components/Popover/Popover.stories.tsx +354 -97
  179. package/src/components/Popover/Popover.tsx +41 -37
  180. package/src/components/Progress/Progress.stories.tsx +160 -7
  181. package/src/components/River/River.stories.tsx +3 -2
  182. package/src/components/SectionIntro/SectionIntro.stories.tsx +239 -47
  183. package/src/components/Slider/Slider.stories.tsx +12 -4
  184. package/src/components/Spinner/Spinner.stories.tsx +104 -8
  185. package/src/components/Spinner/Spinner.test.tsx +23 -23
  186. package/src/components/Spinner/Spinner.tsx +43 -46
  187. package/src/components/Steps/Steps.stories.tsx +173 -42
  188. package/src/components/Tabs/Tabs.stories.tsx +141 -12
  189. package/src/components/Tabs/Tabs.tsx +74 -72
  190. package/src/components/Testimonial/Testimonial.stories.tsx +120 -3
  191. package/src/components/Todo/Todo.stories.tsx +198 -9
  192. package/src/components/Toggle/Toggle.stories.tsx +137 -36
  193. package/src/components/Toggle/Toggle.test.tsx +65 -70
  194. package/src/components/Toggle/Toggle.tsx +4 -1
  195. package/src/components/Tooltip/Tooltip.stories.tsx +194 -100
  196. package/src/components/Tooltip/Tooltip.tsx +104 -106
  197. package/src/components/Upload/Upload.stories.tsx +241 -150
  198. package/src/components/Upload/Upload.tsx +287 -283
  199. package/src/components/VideoPlayer/VideoPlayer.tsx +6 -1
  200. package/src/components/index.ts +13 -2
  201. package/src/layouts/Grid/Grid.stories.tsx +9 -3
  202. package/src/layouts/MasonryGrid/MasonryGrid.tsx +5 -1
  203. package/src/lib/README.md +2 -2
  204. package/src/lib/__tests__/theme-tools.test.ts +219 -0
  205. package/src/lib/composables/index.ts +2 -2
  206. package/src/lib/composables/shared-mouse-tracker.ts +13 -14
  207. package/src/lib/composables/useAtomixGlass.ts +126 -97
  208. package/src/lib/composables/useChartExport.ts +3 -8
  209. package/src/lib/composables/useDataTable.ts +72 -43
  210. package/src/lib/composables/useHero.ts +58 -14
  211. package/src/lib/composables/useHeroBackgroundSlider.ts +2 -9
  212. package/src/lib/composables/useInput.ts +10 -8
  213. package/src/lib/composables/useSideMenu.ts +6 -5
  214. package/src/lib/composables/useTooltip.ts +1 -2
  215. package/src/lib/composables/useVideoPlayer.ts +44 -35
  216. package/src/lib/config/index.ts +154 -154
  217. package/src/lib/constants/components.ts +9 -32
  218. package/src/lib/constants/cssVariables.ts +29 -29
  219. package/src/lib/hooks/__tests__/useComponentCustomization.test.ts +2 -6
  220. package/src/lib/hooks/index.ts +1 -1
  221. package/src/lib/hooks/useComponentCustomization.ts +11 -17
  222. package/src/lib/hooks/usePerformanceMonitor.ts +6 -7
  223. package/src/lib/patterns/__tests__/slots.test.ts +1 -1
  224. package/src/lib/patterns/index.ts +1 -1
  225. package/src/lib/patterns/slots.tsx +8 -13
  226. package/src/lib/storybook/InteractiveDemo.tsx +13 -18
  227. package/src/lib/storybook/PreviewContainer.tsx +1 -1
  228. package/src/lib/storybook/VariantsGrid.tsx +3 -7
  229. package/src/lib/storybook/index.ts +1 -1
  230. package/src/lib/theme/adapters/cssVariableMapper.ts +47 -74
  231. package/src/lib/theme/adapters/index.ts +3 -9
  232. package/src/lib/theme/adapters/themeAdapter.ts +41 -26
  233. package/src/lib/theme/config/index.ts +1 -1
  234. package/src/lib/theme/config/types.ts +2 -2
  235. package/src/lib/theme/config/validator.ts +10 -5
  236. package/src/lib/theme/constants/constants.ts +2 -2
  237. package/src/lib/theme/constants/index.ts +1 -2
  238. package/src/lib/theme/core/__tests__/createTheme.test.ts +20 -22
  239. package/src/lib/theme/core/composeTheme.ts +32 -26
  240. package/src/lib/theme/core/createTheme.ts +1 -1
  241. package/src/lib/theme/core/createThemeObject.ts +308 -301
  242. package/src/lib/theme/core/index.ts +3 -3
  243. package/src/lib/theme/devtools/CLI.ts +107 -105
  244. package/src/lib/theme/devtools/Comparator.tsx +50 -32
  245. package/src/lib/theme/devtools/DesignTokensCustomizer.stories.tsx +50 -48
  246. package/src/lib/theme/devtools/DesignTokensCustomizer.tsx +257 -63
  247. package/src/lib/theme/devtools/Inspector.tsx +75 -60
  248. package/src/lib/theme/devtools/LiveEditor.tsx +97 -76
  249. package/src/lib/theme/devtools/Preview.tsx +150 -106
  250. package/src/lib/theme/devtools/ThemeValidator.ts +29 -21
  251. package/src/lib/theme/devtools/index.ts +3 -9
  252. package/src/lib/theme/devtools/useHistory.ts +23 -21
  253. package/src/lib/theme/errors/errors.ts +12 -11
  254. package/src/lib/theme/errors/index.ts +2 -7
  255. package/src/lib/theme/generators/generateCSS.ts +9 -13
  256. package/src/lib/theme/generators/generateCSSNested.ts +1 -6
  257. package/src/lib/theme/generators/generateCSSVariables.ts +673 -630
  258. package/src/lib/theme/generators/index.ts +1 -4
  259. package/src/lib/theme/i18n/index.ts +1 -1
  260. package/src/lib/theme/i18n/rtl.ts +13 -13
  261. package/src/lib/theme/index.ts +7 -16
  262. package/src/lib/theme/runtime/ThemeApplicator.ts +4 -4
  263. package/src/lib/theme/runtime/ThemeContext.tsx +1 -1
  264. package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +19 -23
  265. package/src/lib/theme/runtime/ThemeProvider.tsx +230 -239
  266. package/src/lib/theme/runtime/__tests__/ThemeProvider.integration.test.tsx +1 -1
  267. package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +24 -29
  268. package/src/lib/theme/runtime/index.ts +2 -5
  269. package/src/lib/theme/runtime/useTheme.ts +18 -18
  270. package/src/lib/theme/runtime/useThemeTokens.ts +22 -22
  271. package/src/lib/theme/test/testTheme.ts +15 -16
  272. package/src/lib/theme/tokens/index.ts +2 -7
  273. package/src/lib/theme/tokens/tokens.ts +25 -24
  274. package/src/lib/theme/types.ts +428 -411
  275. package/src/lib/theme/utils/__tests__/themeValidation.test.ts +3 -3
  276. package/src/lib/theme/utils/componentTheming.ts +18 -18
  277. package/src/lib/theme/utils/domUtils.ts +277 -289
  278. package/src/lib/theme/utils/index.ts +1 -2
  279. package/src/lib/theme/utils/injectCSS.ts +10 -14
  280. package/src/lib/theme/utils/naming.ts +20 -16
  281. package/src/lib/theme/utils/themeHelpers.ts +10 -12
  282. package/src/lib/theme/utils/themeUtils.ts +85 -86
  283. package/src/lib/theme/utils/themeValidation.ts +82 -33
  284. package/src/lib/theme-tools.ts +8 -6
  285. package/src/lib/types/components.ts +172 -71
  286. package/src/lib/types/partProps.ts +1 -1
  287. package/src/lib/utils/__tests__/csv.test.ts +45 -0
  288. package/src/lib/utils/componentUtils.ts +8 -12
  289. package/src/lib/utils/csv.ts +19 -0
  290. package/src/lib/utils/dataTableExport.ts +2 -15
  291. package/src/lib/utils/fontPreloader.ts +10 -19
  292. package/src/lib/utils/icons.ts +4 -1
  293. package/src/lib/utils/index.ts +2 -6
  294. package/src/lib/utils/memoryMonitor.ts +10 -8
  295. package/src/lib/utils/themeNaming.ts +2 -2
  296. package/src/styles/01-settings/_index.scss +1 -1
  297. package/src/styles/01-settings/_settings.accordion.scss +28 -7
  298. package/src/styles/01-settings/_settings.colors.scss +11 -11
  299. package/src/styles/01-settings/_settings.design-tokens.scss +61 -50
  300. package/src/styles/01-settings/_settings.navbar.scss +1 -1
  301. package/src/styles/01-settings/_settings.spacing.scss +3 -4
  302. package/src/styles/01-settings/_settings.tooltip.scss +1 -1
  303. package/src/styles/01-settings/_settings.typography.scss +4 -4
  304. package/src/styles/02-tools/_tools.button.scss +51 -21
  305. package/src/styles/02-tools/_tools.utility-api.scss +38 -12
  306. package/src/styles/03-generic/_generic.root.scss +4 -3
  307. package/src/styles/06-components/_components.accordion.scss +56 -14
  308. package/src/styles/06-components/_components.atomix-glass.scss +13 -9
  309. package/src/styles/06-components/_components.button.scss +16 -4
  310. package/src/styles/06-components/_components.callout.scss +27 -21
  311. package/src/styles/06-components/_components.card.scss +5 -14
  312. package/src/styles/06-components/_components.chart.scss +22 -19
  313. package/src/styles/06-components/_components.checkbox.scss +25 -17
  314. package/src/styles/06-components/_components.color-mode-toggle.scss +3 -1
  315. package/src/styles/06-components/_components.edge-panel.scss +9 -2
  316. package/src/styles/06-components/_components.footer.scss +1 -1
  317. package/src/styles/06-components/_components.side-menu.scss +5 -5
  318. package/src/styles/06-components/_components.toggle.scss +18 -0
  319. package/src/styles/06-components/_index.scss +1 -1
  320. package/src/styles/06-components/old.chart.styles.scss +0 -2
  321. package/src/styles/99-utilities/_index.scss +2 -0
  322. package/src/styles/99-utilities/_utilities.border.scss +69 -27
  323. package/src/styles/99-utilities/_utilities.display.scss +1 -1
  324. package/src/styles/99-utilities/_utilities.opacity.scss +10 -0
  325. package/src/styles/99-utilities/_utilities.position.scss +16 -9
  326. package/src/styles/99-utilities/_utilities.scss +2 -0
  327. package/src/styles/99-utilities/_utilities.sizes.scss +47 -18
  328. package/src/styles/99-utilities/_utilities.spacing.scss +118 -66
  329. package/src/styles/99-utilities/_utilities.text-gradient.scss +45 -0
  330. package/src/styles/99-utilities/_utilities.text.scss +67 -46
  331. package/themes/dark-complementary/README.md +98 -0
  332. package/themes/dark-complementary/index.scss +158 -0
  333. package/themes/default-light/README.md +81 -0
  334. package/themes/default-light/index.scss +154 -0
  335. package/themes/high-contrast/README.md +105 -0
  336. package/themes/high-contrast/index.scss +172 -0
  337. package/themes/test-theme/README.md +38 -0
  338. package/themes/test-theme/index.scss +47 -0
  339. package/scripts/cli/templates-original-backup.js +0 -1655
  340. package/scripts/cli/templates_backup.js +0 -684
  341. package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +0 -1438
  342. package/src/lib/composables/useButton.ts +0 -93
  343. package/src/lib/composables/useCheckbox.ts +0 -70
@@ -319,336 +319,342 @@ export const Upload: React.FC<UploadProps> = ({
319
319
  // Calculate time remaining based on upload speed
320
320
  const calculateTimeRemaining = useCallback((progress: number, elapsedTime: number): string => {
321
321
  if (progress <= 0 || elapsedTime <= 0) return '';
322
-
322
+
323
323
  const estimatedTotalTime = (elapsedTime / progress) * 100;
324
324
  const remainingTime = estimatedTotalTime - elapsedTime;
325
-
325
+
326
326
  if (remainingTime <= 0) return 'Almost done...';
327
-
327
+
328
328
  const seconds = Math.ceil(remainingTime / 1000);
329
329
  if (seconds < 60) {
330
330
  return `${seconds} second${seconds !== 1 ? 's' : ''} left`;
331
331
  }
332
-
332
+
333
333
  const minutes = Math.floor(seconds / 60);
334
334
  const remainingSeconds = seconds % 60;
335
335
  return `${minutes}m ${remainingSeconds}s left`;
336
336
  }, []);
337
337
 
338
338
  // Upload file chunk
339
- const uploadChunk = useCallback((
340
- file: File,
341
- chunkIndex: number,
342
- totalChunks: number,
343
- chunkSize: number,
344
- chunkXhrs: XMLHttpRequest[]
345
- ): Promise<any> => {
346
- return new Promise((resolve, reject) => {
347
- const start = chunkIndex * chunkSize;
348
- const end = Math.min(start + chunkSize, file.size);
349
- const chunk = file.slice(start, end);
350
-
351
- const formData = new FormData();
352
- formData.append('file', chunk, file.name);
353
- formData.append('chunkIndex', chunkIndex.toString());
354
- formData.append('totalChunks', totalChunks.toString());
355
- formData.append('fileName', file.name);
356
- formData.append('fileSize', file.size.toString());
357
-
358
- // Add additional form data
359
- Object.entries(uploadData).forEach(([key, value]) => {
360
- formData.append(key, value);
361
- });
339
+ const uploadChunk = useCallback(
340
+ (
341
+ file: File,
342
+ chunkIndex: number,
343
+ totalChunks: number,
344
+ chunkSize: number,
345
+ chunkXhrs: XMLHttpRequest[]
346
+ ): Promise<any> => {
347
+ return new Promise((resolve, reject) => {
348
+ const start = chunkIndex * chunkSize;
349
+ const end = Math.min(start + chunkSize, file.size);
350
+ const chunk = file.slice(start, end);
351
+
352
+ const formData = new FormData();
353
+ formData.append('file', chunk, file.name);
354
+ formData.append('chunkIndex', chunkIndex.toString());
355
+ formData.append('totalChunks', totalChunks.toString());
356
+ formData.append('fileName', file.name);
357
+ formData.append('fileSize', file.size.toString());
358
+
359
+ // Add additional form data
360
+ Object.entries(uploadData).forEach(([key, value]) => {
361
+ formData.append(key, value);
362
+ });
363
+
364
+ const xhr = new XMLHttpRequest();
365
+
366
+ // Store XHR for cancellation
367
+ chunkXhrs[chunkIndex] = xhr;
368
+
369
+ // Set up progress tracking for this chunk
370
+ xhr.upload.addEventListener('progress', e => {
371
+ if (e.lengthComputable && uploadRequestRef.current) {
372
+ const chunkProgress = (e.loaded / e.total) * 100;
373
+ const overallProgress = ((chunkIndex * chunkSize + e.loaded) / file.size) * 100;
362
374
 
363
- const xhr = new XMLHttpRequest();
364
-
365
- // Store XHR for cancellation
366
- chunkXhrs[chunkIndex] = xhr;
367
-
368
- // Set up progress tracking for this chunk
369
- xhr.upload.addEventListener('progress', (e) => {
370
- if (e.lengthComputable && uploadRequestRef.current) {
371
- const chunkProgress = (e.loaded / e.total) * 100;
372
- const overallProgress = ((chunkIndex * chunkSize + e.loaded) / file.size) * 100;
373
-
374
- setUploadProgress(Math.min(overallProgress, 100));
375
-
376
- const elapsedTime = startTimeRef.current ? Date.now() - startTimeRef.current : 0;
377
- const timeRemaining = calculateTimeRemaining(overallProgress, elapsedTime);
378
- setTimeLeft(timeRemaining);
379
-
380
- if (onFileUpload) {
381
- onFileUpload(file, overallProgress);
375
+ setUploadProgress(Math.min(overallProgress, 100));
376
+
377
+ const elapsedTime = startTimeRef.current ? Date.now() - startTimeRef.current : 0;
378
+ const timeRemaining = calculateTimeRemaining(overallProgress, elapsedTime);
379
+ setTimeLeft(timeRemaining);
380
+
381
+ if (onFileUpload) {
382
+ onFileUpload(file, overallProgress);
383
+ }
382
384
  }
383
- }
384
- });
385
+ });
385
386
 
386
- xhr.addEventListener('load', () => {
387
- if (xhr.status >= 200 && xhr.status < 300) {
388
- try {
389
- const response = xhr.responseText ? JSON.parse(xhr.responseText) : {};
390
- resolve(response);
391
- } catch {
392
- resolve({});
387
+ xhr.addEventListener('load', () => {
388
+ if (xhr.status >= 200 && xhr.status < 300) {
389
+ try {
390
+ const response = xhr.responseText ? JSON.parse(xhr.responseText) : {};
391
+ resolve(response);
392
+ } catch {
393
+ resolve({});
394
+ }
395
+ } else {
396
+ reject(new Error(`Upload failed with status ${xhr.status}: ${xhr.statusText}`));
393
397
  }
394
- } else {
395
- reject(new Error(`Upload failed with status ${xhr.status}: ${xhr.statusText}`));
396
- }
397
- });
398
+ });
398
399
 
399
- xhr.addEventListener('error', () => {
400
- reject(new Error('Network error occurred during upload'));
401
- });
400
+ xhr.addEventListener('error', () => {
401
+ reject(new Error('Network error occurred during upload'));
402
+ });
402
403
 
403
- xhr.addEventListener('abort', () => {
404
- reject(new Error('Upload was cancelled'));
405
- });
404
+ xhr.addEventListener('abort', () => {
405
+ reject(new Error('Upload was cancelled'));
406
+ });
406
407
 
407
- xhr.open(uploadMethod, uploadEndpoint!);
408
+ xhr.open(uploadMethod, uploadEndpoint!);
408
409
 
409
- // Set headers
410
- Object.entries(uploadHeaders).forEach(([key, value]) => {
411
- xhr.setRequestHeader(key, value);
412
- });
410
+ // Set headers
411
+ Object.entries(uploadHeaders).forEach(([key, value]) => {
412
+ xhr.setRequestHeader(key, value);
413
+ });
413
414
 
414
- xhr.send(formData);
415
- });
416
- }, [uploadEndpoint, uploadMethod, uploadHeaders, uploadData, onFileUpload, calculateTimeRemaining]);
415
+ xhr.send(formData);
416
+ });
417
+ },
418
+ [uploadEndpoint, uploadMethod, uploadHeaders, uploadData, onFileUpload, calculateTimeRemaining]
419
+ );
417
420
 
418
421
  // Upload file (with chunking support)
419
- const uploadFile = useCallback(async (file: File, retryCount: number = 0) => {
420
- // If no endpoint is provided, simulate upload for backward compatibility
421
- if (!uploadEndpoint) {
422
- setStatus('loading');
423
- setUploadProgress(0);
424
- startTimeRef.current = Date.now();
425
-
426
- // Simulate progress updates
427
- let progress = 0;
428
- const interval = setInterval(() => {
429
- progress += 5;
422
+ const uploadFile = useCallback(
423
+ async (file: File, retryCount: number = 0) => {
424
+ // If no endpoint is provided, simulate upload for backward compatibility
425
+ if (!uploadEndpoint) {
426
+ setStatus('loading');
427
+ setUploadProgress(0);
428
+ startTimeRef.current = Date.now();
430
429
 
431
- if (progress < 100) {
432
- setUploadProgress(progress);
433
- const elapsedTime = Date.now() - (startTimeRef.current || Date.now());
434
- const timeRemaining = calculateTimeRemaining(progress, elapsedTime);
435
- setTimeLeft(timeRemaining);
430
+ // Simulate progress updates
431
+ let progress = 0;
432
+ const interval = setInterval(() => {
433
+ progress += 5;
436
434
 
437
- if (onFileUpload) {
438
- onFileUpload(file, progress);
439
- }
440
- } else {
441
- clearInterval(interval);
442
- setStatus('success');
443
- setSuccessMessage('Upload successful');
444
- startTimeRef.current = null;
435
+ if (progress < 100) {
436
+ setUploadProgress(progress);
437
+ const elapsedTime = Date.now() - (startTimeRef.current || Date.now());
438
+ const timeRemaining = calculateTimeRemaining(progress, elapsedTime);
439
+ setTimeLeft(timeRemaining);
445
440
 
446
- if (onFileUploadComplete) {
447
- onFileUploadComplete(file);
448
- }
449
-
450
- uploadRequestRef.current = null;
451
- }
452
- }, 500);
453
-
454
- // Store interval for cleanup
455
- uploadRequestRef.current = {
456
- xhr: null,
457
- abortController: new AbortController(),
458
- file,
459
- retryCount,
460
- intervalId: interval,
461
- };
462
-
463
- return;
464
- }
441
+ if (onFileUpload) {
442
+ onFileUpload(file, progress);
443
+ }
444
+ } else {
445
+ clearInterval(interval);
446
+ setStatus('success');
447
+ setSuccessMessage('Upload successful');
448
+ startTimeRef.current = null;
465
449
 
466
- setStatus('loading');
467
- setUploadProgress(0);
468
- setErrorMessage(null);
469
- setSuccessMessage(null);
470
- startTimeRef.current = Date.now();
450
+ if (onFileUploadComplete) {
451
+ onFileUploadComplete(file);
452
+ }
471
453
 
472
- try {
473
- const chunkSize = chunkSizeInMB > 0 ? chunkSizeInMB * 1024 * 1024 : file.size;
474
- const totalChunks = chunkSizeInMB > 0 ? Math.ceil(file.size / chunkSize) : 1;
454
+ uploadRequestRef.current = null;
455
+ }
456
+ }, 500);
475
457
 
476
- if (totalChunks > 1) {
477
- // Chunked upload
478
- const chunkXhrs: XMLHttpRequest[] = [];
479
-
480
- // Initialize upload request with chunk array
458
+ // Store interval for cleanup
481
459
  uploadRequestRef.current = {
482
460
  xhr: null,
483
461
  abortController: new AbortController(),
484
462
  file,
485
463
  retryCount,
486
- chunkXhrs,
464
+ intervalId: interval,
487
465
  };
488
466
 
489
- try {
490
- const chunkResults = [];
491
- for (let i = 0; i < totalChunks; i++) {
492
- // Check if upload was cancelled
493
- if (!uploadRequestRef.current) {
494
- throw new Error('Upload was cancelled');
495
- }
496
-
497
- const result = await uploadChunk(file, i, totalChunks, chunkSize, chunkXhrs);
498
- chunkResults.push(result);
499
- }
500
-
501
- setStatus('success');
502
- setSuccessMessage('Upload successful');
503
- setUploadProgress(100);
504
- setTimeLeft(null);
505
- startTimeRef.current = null;
506
-
507
- if (onFileUploadComplete) {
508
- onFileUploadComplete(file, chunkResults);
509
- }
467
+ return;
468
+ }
510
469
 
511
- uploadRequestRef.current = null;
512
- } catch (error) {
513
- // Abort all remaining chunks
514
- chunkXhrs.forEach(xhr => {
515
- if (xhr && xhr.readyState !== XMLHttpRequest.DONE) {
516
- xhr.abort();
517
- }
518
- });
519
- throw error;
520
- }
521
- } else {
522
- // Single upload - wrap in Promise for proper error handling
523
- await new Promise<void>((resolve, reject) => {
524
- const formData = new FormData();
525
- formData.append('file', file);
526
-
527
- // Add additional form data
528
- Object.entries(uploadData).forEach(([key, value]) => {
529
- formData.append(key, value);
530
- });
470
+ setStatus('loading');
471
+ setUploadProgress(0);
472
+ setErrorMessage(null);
473
+ setSuccessMessage(null);
474
+ startTimeRef.current = Date.now();
531
475
 
532
- const xhr = new XMLHttpRequest();
533
- const abortController = new AbortController();
476
+ try {
477
+ const chunkSize = chunkSizeInMB > 0 ? chunkSizeInMB * 1024 * 1024 : file.size;
478
+ const totalChunks = chunkSizeInMB > 0 ? Math.ceil(file.size / chunkSize) : 1;
534
479
 
535
- // Set up progress tracking
536
- xhr.upload.addEventListener('progress', (e) => {
537
- if (e.lengthComputable) {
538
- const progress = (e.loaded / e.total) * 100;
539
- setUploadProgress(progress);
480
+ if (totalChunks > 1) {
481
+ // Chunked upload
482
+ const chunkXhrs: XMLHttpRequest[] = [];
540
483
 
541
- const elapsedTime = startTimeRef.current ? Date.now() - startTimeRef.current : 0;
542
- const timeRemaining = calculateTimeRemaining(progress, elapsedTime);
543
- setTimeLeft(timeRemaining);
484
+ // Initialize upload request with chunk array
485
+ uploadRequestRef.current = {
486
+ xhr: null,
487
+ abortController: new AbortController(),
488
+ file,
489
+ retryCount,
490
+ chunkXhrs,
491
+ };
544
492
 
545
- if (onFileUpload) {
546
- onFileUpload(file, progress);
493
+ try {
494
+ const chunkResults = [];
495
+ for (let i = 0; i < totalChunks; i++) {
496
+ // Check if upload was cancelled
497
+ if (!uploadRequestRef.current) {
498
+ throw new Error('Upload was cancelled');
547
499
  }
500
+
501
+ const result = await uploadChunk(file, i, totalChunks, chunkSize, chunkXhrs);
502
+ chunkResults.push(result);
548
503
  }
549
- });
550
504
 
551
- xhr.addEventListener('load', () => {
552
- if (xhr.status >= 200 && xhr.status < 300) {
553
- setStatus('success');
554
- setSuccessMessage('Upload successful');
555
- setUploadProgress(100);
556
- setTimeLeft(null);
557
- startTimeRef.current = null;
505
+ setStatus('success');
506
+ setSuccessMessage('Upload successful');
507
+ setUploadProgress(100);
508
+ setTimeLeft(null);
509
+ startTimeRef.current = null;
510
+
511
+ if (onFileUploadComplete) {
512
+ onFileUploadComplete(file, chunkResults);
513
+ }
558
514
 
559
- try {
560
- const response = xhr.responseText ? JSON.parse(xhr.responseText) : {};
561
- if (onFileUploadComplete) {
562
- onFileUploadComplete(file, response);
515
+ uploadRequestRef.current = null;
516
+ } catch (error) {
517
+ // Abort all remaining chunks
518
+ chunkXhrs.forEach(xhr => {
519
+ if (xhr && xhr.readyState !== XMLHttpRequest.DONE) {
520
+ xhr.abort();
521
+ }
522
+ });
523
+ throw error;
524
+ }
525
+ } else {
526
+ // Single upload - wrap in Promise for proper error handling
527
+ await new Promise<void>((resolve, reject) => {
528
+ const formData = new FormData();
529
+ formData.append('file', file);
530
+
531
+ // Add additional form data
532
+ Object.entries(uploadData).forEach(([key, value]) => {
533
+ formData.append(key, value);
534
+ });
535
+
536
+ const xhr = new XMLHttpRequest();
537
+ const abortController = new AbortController();
538
+
539
+ // Set up progress tracking
540
+ xhr.upload.addEventListener('progress', e => {
541
+ if (e.lengthComputable) {
542
+ const progress = (e.loaded / e.total) * 100;
543
+ setUploadProgress(progress);
544
+
545
+ const elapsedTime = startTimeRef.current ? Date.now() - startTimeRef.current : 0;
546
+ const timeRemaining = calculateTimeRemaining(progress, elapsedTime);
547
+ setTimeLeft(timeRemaining);
548
+
549
+ if (onFileUpload) {
550
+ onFileUpload(file, progress);
563
551
  }
564
- } catch {
565
- if (onFileUploadComplete) {
566
- onFileUploadComplete(file);
552
+ }
553
+ });
554
+
555
+ xhr.addEventListener('load', () => {
556
+ if (xhr.status >= 200 && xhr.status < 300) {
557
+ setStatus('success');
558
+ setSuccessMessage('Upload successful');
559
+ setUploadProgress(100);
560
+ setTimeLeft(null);
561
+ startTimeRef.current = null;
562
+
563
+ try {
564
+ const response = xhr.responseText ? JSON.parse(xhr.responseText) : {};
565
+ if (onFileUploadComplete) {
566
+ onFileUploadComplete(file, response);
567
+ }
568
+ } catch {
569
+ if (onFileUploadComplete) {
570
+ onFileUploadComplete(file);
571
+ }
567
572
  }
573
+
574
+ uploadRequestRef.current = null;
575
+ resolve();
576
+ } else {
577
+ reject(new Error(`Upload failed with status ${xhr.status}: ${xhr.statusText}`));
568
578
  }
579
+ });
580
+
581
+ xhr.addEventListener('error', () => {
582
+ reject(new Error('Network error occurred during upload'));
583
+ });
569
584
 
585
+ xhr.addEventListener('abort', () => {
586
+ setStatus('idle');
587
+ setUploadProgress(0);
588
+ setTimeLeft(null);
589
+ startTimeRef.current = null;
570
590
  uploadRequestRef.current = null;
571
- resolve();
572
- } else {
573
- reject(new Error(`Upload failed with status ${xhr.status}: ${xhr.statusText}`));
574
- }
575
- });
576
591
 
577
- xhr.addEventListener('error', () => {
578
- reject(new Error('Network error occurred during upload'));
579
- });
592
+ if (onUploadCancel) {
593
+ onUploadCancel(file);
594
+ }
580
595
 
581
- xhr.addEventListener('abort', () => {
582
- setStatus('idle');
583
- setUploadProgress(0);
584
- setTimeLeft(null);
585
- startTimeRef.current = null;
586
- uploadRequestRef.current = null;
596
+ reject(new Error('Upload was cancelled'));
597
+ });
587
598
 
588
- if (onUploadCancel) {
589
- onUploadCancel(file);
590
- }
591
-
592
- reject(new Error('Upload was cancelled'));
593
- });
599
+ xhr.open(uploadMethod, uploadEndpoint);
600
+
601
+ // Set headers
602
+ Object.entries(uploadHeaders).forEach(([key, value]) => {
603
+ xhr.setRequestHeader(key, value);
604
+ });
594
605
 
595
- xhr.open(uploadMethod, uploadEndpoint);
606
+ // Store request for cancellation
607
+ uploadRequestRef.current = {
608
+ xhr,
609
+ abortController,
610
+ file,
611
+ retryCount,
612
+ };
596
613
 
597
- // Set headers
598
- Object.entries(uploadHeaders).forEach(([key, value]) => {
599
- xhr.setRequestHeader(key, value);
614
+ xhr.send(formData);
600
615
  });
616
+ }
617
+ } catch (error) {
618
+ const errorMessage = error instanceof Error ? error.message : 'Upload failed';
601
619
 
602
- // Store request for cancellation
603
- uploadRequestRef.current = {
604
- xhr,
605
- abortController,
606
- file,
607
- retryCount,
608
- };
620
+ // Retry logic
621
+ if (retryCount < maxRetries && !errorMessage.includes('cancelled')) {
622
+ setStatus('loading');
623
+ setErrorMessage(`Upload failed. Retrying... (${retryCount + 1}/${maxRetries})`);
609
624
 
610
- xhr.send(formData);
611
- });
612
- }
613
- } catch (error) {
614
- const errorMessage = error instanceof Error ? error.message : 'Upload failed';
615
-
616
- // Retry logic
617
- if (retryCount < maxRetries && !errorMessage.includes('cancelled')) {
618
- setStatus('loading');
619
- setErrorMessage(`Upload failed. Retrying... (${retryCount + 1}/${maxRetries})`);
620
-
621
- setTimeout(() => {
622
- uploadFile(file, retryCount + 1);
623
- }, retryDelay);
624
- } else {
625
- setStatus('error');
626
- setErrorMessage(errorMessage);
627
- setUploadProgress(0);
628
- setTimeLeft(null);
629
- startTimeRef.current = null;
630
- uploadRequestRef.current = null;
625
+ setTimeout(() => {
626
+ uploadFile(file, retryCount + 1);
627
+ }, retryDelay);
628
+ } else {
629
+ setStatus('error');
630
+ setErrorMessage(errorMessage);
631
+ setUploadProgress(0);
632
+ setTimeLeft(null);
633
+ startTimeRef.current = null;
634
+ uploadRequestRef.current = null;
631
635
 
632
- if (onFileUploadError) {
633
- onFileUploadError(file, errorMessage);
636
+ if (onFileUploadError) {
637
+ onFileUploadError(file, errorMessage);
638
+ }
634
639
  }
635
640
  }
636
- }
637
- }, [
638
- uploadEndpoint,
639
- uploadMethod,
640
- uploadHeaders,
641
- uploadData,
642
- chunkSizeInMB,
643
- maxRetries,
644
- retryDelay,
645
- onFileUpload,
646
- onFileUploadComplete,
647
- onFileUploadError,
648
- onUploadCancel,
649
- uploadChunk,
650
- calculateTimeRemaining,
651
- ]);
641
+ },
642
+ [
643
+ uploadEndpoint,
644
+ uploadMethod,
645
+ uploadHeaders,
646
+ uploadData,
647
+ chunkSizeInMB,
648
+ maxRetries,
649
+ retryDelay,
650
+ onFileUpload,
651
+ onFileUploadComplete,
652
+ onFileUploadError,
653
+ onUploadCancel,
654
+ uploadChunk,
655
+ calculateTimeRemaining,
656
+ ]
657
+ );
652
658
 
653
659
  // Reset upload
654
660
  const resetUpload = useCallback(() => {
@@ -658,7 +664,7 @@ export const Upload: React.FC<UploadProps> = ({
658
664
  if (uploadRequestRef.current.xhr) {
659
665
  uploadRequestRef.current.xhr.abort();
660
666
  }
661
-
667
+
662
668
  // Cancel all chunk XHR requests
663
669
  if (uploadRequestRef.current.chunkXhrs) {
664
670
  uploadRequestRef.current.chunkXhrs.forEach(xhr => {
@@ -667,12 +673,12 @@ export const Upload: React.FC<UploadProps> = ({
667
673
  }
668
674
  });
669
675
  }
670
-
676
+
671
677
  // Clear interval if it exists
672
678
  if (uploadRequestRef.current.intervalId) {
673
679
  clearInterval(uploadRequestRef.current.intervalId);
674
680
  }
675
-
681
+
676
682
  uploadRequestRef.current = null;
677
683
  }
678
684
 
@@ -692,7 +698,7 @@ export const Upload: React.FC<UploadProps> = ({
692
698
  if (uploadRequestRef.current.xhr) {
693
699
  uploadRequestRef.current.xhr.abort();
694
700
  }
695
-
701
+
696
702
  // Cancel all chunk XHR requests
697
703
  if (uploadRequestRef.current.chunkXhrs) {
698
704
  uploadRequestRef.current.chunkXhrs.forEach(xhr => {
@@ -701,19 +707,19 @@ export const Upload: React.FC<UploadProps> = ({
701
707
  }
702
708
  });
703
709
  }
704
-
710
+
705
711
  // Clear interval if it exists (for simulated uploads)
706
712
  if (uploadRequestRef.current.intervalId) {
707
713
  clearInterval(uploadRequestRef.current.intervalId);
708
714
  }
709
-
715
+
710
716
  uploadRequestRef.current.abortController.abort();
711
-
717
+
712
718
  if (onUploadCancel && uploadRequestRef.current.file) {
713
719
  onUploadCancel(uploadRequestRef.current.file);
714
720
  }
715
721
  }
716
-
722
+
717
723
  uploadRequestRef.current = null;
718
724
  resetUpload();
719
725
  }, [onUploadCancel, resetUpload]);
@@ -726,7 +732,7 @@ export const Upload: React.FC<UploadProps> = ({
726
732
  if (uploadRequestRef.current.xhr) {
727
733
  uploadRequestRef.current.xhr.abort();
728
734
  }
729
-
735
+
730
736
  // Cancel all chunk XHR requests
731
737
  if (uploadRequestRef.current.chunkXhrs) {
732
738
  uploadRequestRef.current.chunkXhrs.forEach(xhr => {
@@ -735,7 +741,7 @@ export const Upload: React.FC<UploadProps> = ({
735
741
  }
736
742
  });
737
743
  }
738
-
744
+
739
745
  // Clear interval if it exists
740
746
  if (uploadRequestRef.current.intervalId) {
741
747
  clearInterval(uploadRequestRef.current.intervalId);
@@ -857,7 +863,7 @@ export const Upload: React.FC<UploadProps> = ({
857
863
  )}
858
864
  </div>
859
865
  )}
860
-
866
+
861
867
  {errorMessage && status === 'error' && (
862
868
  <div className="c-upload__error-message">
863
869
  {errorMessage}
@@ -876,11 +882,9 @@ export const Upload: React.FC<UploadProps> = ({
876
882
  )}
877
883
  </div>
878
884
  )}
879
-
885
+
880
886
  {successMessage && status === 'success' && (
881
- <div className="c-upload__success-message">
882
- {successMessage}
883
- </div>
887
+ <div className="c-upload__success-message">{successMessage}</div>
884
888
  )}
885
889
  </div>
886
890
  )}