@wakastellar/ui 2.0.0 → 2.1.1

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 (291) hide show
  1. package/README.md +71 -8
  2. package/dist/cli/commands/add.d.ts +7 -0
  3. package/dist/cli/commands/init.d.ts +6 -0
  4. package/dist/cli/commands/list.d.ts +5 -0
  5. package/dist/cli/commands/search.d.ts +1 -0
  6. package/dist/cli/index.cjs +6014 -0
  7. package/dist/cli/index.d.ts +1 -0
  8. package/dist/cli/utils/config.d.ts +29 -0
  9. package/dist/cli/utils/logger.d.ts +20 -0
  10. package/dist/cli/utils/registry.d.ts +23 -0
  11. package/package.json +14 -3
  12. package/src/blocks/activity-timeline/index.tsx +586 -0
  13. package/src/blocks/calendar-view/index.tsx +756 -0
  14. package/src/blocks/chat/index.tsx +1018 -0
  15. package/src/blocks/chat/widget.tsx +504 -0
  16. package/src/blocks/dashboard/index.tsx +522 -0
  17. package/src/blocks/empty-states/index.tsx +452 -0
  18. package/src/blocks/error-pages/index.tsx +426 -0
  19. package/src/blocks/faq/index.tsx +479 -0
  20. package/src/blocks/file-manager/index.tsx +890 -0
  21. package/src/blocks/footer/index.tsx +133 -0
  22. package/src/blocks/header/index.tsx +357 -0
  23. package/src/blocks/headtab/index.tsx +139 -0
  24. package/src/blocks/i18n-editor/index.tsx +1016 -0
  25. package/src/blocks/index.ts +80 -0
  26. package/src/blocks/kanban-board/index.tsx +779 -0
  27. package/src/blocks/landing/index.tsx +677 -0
  28. package/src/blocks/language-selector/index.tsx +88 -0
  29. package/src/blocks/layout/index.tsx +159 -0
  30. package/src/blocks/login/index.tsx +339 -0
  31. package/src/blocks/login/types.ts +131 -0
  32. package/src/blocks/pricing/index.tsx +564 -0
  33. package/src/blocks/profile/index.tsx +746 -0
  34. package/src/blocks/settings/index.tsx +558 -0
  35. package/src/blocks/sidebar/index.tsx +713 -0
  36. package/src/blocks/theme-creator-block/index.tsx +835 -0
  37. package/src/blocks/user-management/index.tsx +1037 -0
  38. package/src/blocks/wizard/index.tsx +719 -0
  39. package/src/components/DataTable/DataTable.tsx +406 -0
  40. package/src/components/DataTable/DataTableAdvanced.tsx +720 -0
  41. package/src/components/DataTable/DataTableBody.tsx +216 -0
  42. package/src/components/DataTable/DataTableCell.tsx +172 -0
  43. package/src/components/DataTable/DataTableColumnResizer.tsx +62 -0
  44. package/src/components/DataTable/DataTableConflictResolver.tsx +478 -0
  45. package/src/components/DataTable/DataTableContextMenu.tsx +219 -0
  46. package/src/components/DataTable/DataTableEditCell.tsx +279 -0
  47. package/src/components/DataTable/DataTableFilterBuilder.tsx +519 -0
  48. package/src/components/DataTable/DataTableFilters.tsx +535 -0
  49. package/src/components/DataTable/DataTableGrouping.tsx +147 -0
  50. package/src/components/DataTable/DataTableHeader.tsx +172 -0
  51. package/src/components/DataTable/DataTablePagination.tsx +125 -0
  52. package/src/components/DataTable/DataTableSelection.tsx +269 -0
  53. package/src/components/DataTable/DataTableSyncStatus.tsx +281 -0
  54. package/src/components/DataTable/DataTableToolbar.tsx +262 -0
  55. package/src/components/DataTable/README.md +446 -0
  56. package/src/components/DataTable/__tests__/DataTableAdvanced.test.tsx +426 -0
  57. package/src/components/DataTable/__tests__/DataTableEdit.test.tsx +329 -0
  58. package/src/components/DataTable/__tests__/useDataTableAdvanced.test.ts +455 -0
  59. package/src/components/DataTable/examples/EditExample.tsx +166 -0
  60. package/src/components/DataTable/formatters/index.ts +335 -0
  61. package/src/components/DataTable/hooks/__tests__/useDataTableEdit.test.ts +239 -0
  62. package/src/components/DataTable/hooks/useDataTable.ts +145 -0
  63. package/src/components/DataTable/hooks/useDataTableAdvanced.ts +342 -0
  64. package/src/components/DataTable/hooks/useDataTableAdvancedFilters.ts +637 -0
  65. package/src/components/DataTable/hooks/useDataTableColumnTemplates.ts +186 -0
  66. package/src/components/DataTable/hooks/useDataTableEdit.ts +167 -0
  67. package/src/components/DataTable/hooks/useDataTableExport.ts +227 -0
  68. package/src/components/DataTable/hooks/useDataTableImport.ts +216 -0
  69. package/src/components/DataTable/hooks/useDataTableOffline.ts +481 -0
  70. package/src/components/DataTable/hooks/useDataTableTheme.ts +213 -0
  71. package/src/components/DataTable/hooks/useDataTableVirtualization.ts +99 -0
  72. package/src/components/DataTable/hooks/useTableLayout.ts +85 -0
  73. package/src/components/DataTable/index.ts +81 -0
  74. package/src/components/DataTable/services/IndexedDBService.ts +504 -0
  75. package/src/components/DataTable/templates/index.tsx +803 -0
  76. package/src/components/DataTable/types.ts +504 -0
  77. package/src/components/DataTable/utils.ts +164 -0
  78. package/src/components/DataTable/workers/exportWorker.ts +213 -0
  79. package/src/components/accordion/index.tsx +61 -0
  80. package/src/components/alert/index.tsx +61 -0
  81. package/src/components/alert-dialog/index.tsx +146 -0
  82. package/src/components/aspect-ratio/index.tsx +12 -0
  83. package/src/components/avatar/index.tsx +54 -0
  84. package/src/components/badge/Badge.stories.tsx +64 -0
  85. package/src/components/badge/index.tsx +38 -0
  86. package/src/components/button/Button.stories.tsx +173 -0
  87. package/src/components/button/index.tsx +56 -0
  88. package/src/components/calendar/index.tsx +73 -0
  89. package/src/components/card/index.tsx +78 -0
  90. package/src/components/checkbox/index.tsx +34 -0
  91. package/src/components/code/index.tsx +229 -0
  92. package/src/components/collapsible/index.tsx +16 -0
  93. package/src/components/command/index.tsx +162 -0
  94. package/src/components/context-menu/index.tsx +204 -0
  95. package/src/components/dialog/index.tsx +126 -0
  96. package/src/components/dropdown-menu/index.tsx +204 -0
  97. package/src/components/error-boundary/ErrorBoundary.tsx +281 -0
  98. package/src/components/error-boundary/index.ts +7 -0
  99. package/src/components/form/index.tsx +183 -0
  100. package/src/components/hover-card/index.tsx +33 -0
  101. package/src/components/index.ts +368 -0
  102. package/src/components/input/Input.stories.tsx +100 -0
  103. package/src/components/input/index.tsx +27 -0
  104. package/src/components/input-otp/index.tsx +277 -0
  105. package/src/components/label/index.tsx +30 -0
  106. package/src/components/language-selector/index.tsx +341 -0
  107. package/src/components/menubar/index.tsx +240 -0
  108. package/src/components/navigation-menu/index.tsx +134 -0
  109. package/src/components/popover/index.tsx +35 -0
  110. package/src/components/progress/index.tsx +32 -0
  111. package/src/components/radio-group/index.tsx +48 -0
  112. package/src/components/scroll-area/index.tsx +52 -0
  113. package/src/components/select/index.tsx +164 -0
  114. package/src/components/separator/index.tsx +35 -0
  115. package/src/components/sheet/index.tsx +147 -0
  116. package/src/components/skeleton/index.tsx +22 -0
  117. package/src/components/slider/index.tsx +32 -0
  118. package/src/components/switch/index.tsx +33 -0
  119. package/src/components/table/index.tsx +117 -0
  120. package/src/components/tabs/index.tsx +59 -0
  121. package/src/components/textarea/index.tsx +30 -0
  122. package/src/components/theme-selector/index.tsx +327 -0
  123. package/src/components/toast/index.tsx +133 -0
  124. package/src/components/toaster/index.tsx +34 -0
  125. package/src/components/toggle/index.tsx +49 -0
  126. package/src/components/tooltip/index.tsx +34 -0
  127. package/src/components/typography/index.tsx +276 -0
  128. package/src/components/waka-3d-pie-chart/index.tsx +486 -0
  129. package/src/components/waka-achievement-unlock/index.tsx +716 -0
  130. package/src/components/waka-activity-feed/index.tsx +686 -0
  131. package/src/components/waka-address-autocomplete/index.tsx +1202 -0
  132. package/src/components/waka-admincrumb/index.tsx +349 -0
  133. package/src/components/waka-alert-stack/index.tsx +827 -0
  134. package/src/components/waka-allocation-matrix/index.tsx +1278 -0
  135. package/src/components/waka-approval-chain/index.tsx +766 -0
  136. package/src/components/waka-audit-log/index.tsx +1475 -0
  137. package/src/components/waka-autocomplete/index.tsx +358 -0
  138. package/src/components/waka-badge-showcase/index.tsx +704 -0
  139. package/src/components/waka-barcode/index.tsx +260 -0
  140. package/src/components/waka-biometric-prompt/index.tsx +765 -0
  141. package/src/components/waka-bottom-sheet/index.tsx +495 -0
  142. package/src/components/waka-breadcrumb/index.tsx +376 -0
  143. package/src/components/waka-breadcrumb-path/index.tsx +513 -0
  144. package/src/components/waka-budget-burn/index.tsx +1234 -0
  145. package/src/components/waka-capacity-planner/index.tsx +1107 -0
  146. package/src/components/waka-carousel/index.tsx +893 -0
  147. package/src/components/waka-cart-summary/index.tsx +1055 -0
  148. package/src/components/waka-challenge-timer/index.tsx +1044 -0
  149. package/src/components/waka-charts/WakaAreaChart.tsx +251 -0
  150. package/src/components/waka-charts/WakaBarChart.tsx +222 -0
  151. package/src/components/waka-charts/WakaChart.tsx +124 -0
  152. package/src/components/waka-charts/WakaLineChart.tsx +219 -0
  153. package/src/components/waka-charts/WakaMiniChart.tsx +133 -0
  154. package/src/components/waka-charts/WakaPieChart.tsx +214 -0
  155. package/src/components/waka-charts/WakaSparkline.tsx +229 -0
  156. package/src/components/waka-charts/dataTableHelpers.ts +109 -0
  157. package/src/components/waka-charts/hooks/useChartTheme.ts +123 -0
  158. package/src/components/waka-charts/hooks/useRechartsLoader.ts +234 -0
  159. package/src/components/waka-charts/index.ts +90 -0
  160. package/src/components/waka-charts/types.ts +330 -0
  161. package/src/components/waka-chat-bubble/index.tsx +1060 -0
  162. package/src/components/waka-checklist/index.tsx +1067 -0
  163. package/src/components/waka-checkout-stepper/index.tsx +976 -0
  164. package/src/components/waka-cohort-table/index.tsx +1011 -0
  165. package/src/components/waka-color-picker/index.tsx +447 -0
  166. package/src/components/waka-combo-counter/index.tsx +864 -0
  167. package/src/components/waka-combobox/index.tsx +497 -0
  168. package/src/components/waka-command-bar/index.tsx +403 -0
  169. package/src/components/waka-compare-period/index.tsx +1230 -0
  170. package/src/components/waka-connection-matrix/index.tsx +1053 -0
  171. package/src/components/waka-contribution-graph/index.tsx +552 -0
  172. package/src/components/waka-cost-breakdown/index.tsx +1065 -0
  173. package/src/components/waka-coupon-input/index.tsx +592 -0
  174. package/src/components/waka-credit-card-input/index.tsx +982 -0
  175. package/src/components/waka-daily-reward/index.tsx +762 -0
  176. package/src/components/waka-date-range-picker/index.tsx +378 -0
  177. package/src/components/waka-datetime-picker/index.tsx +793 -0
  178. package/src/components/waka-datetime-picker.form-integration/index.tsx +402 -0
  179. package/src/components/waka-deployment-lane/index.tsx +673 -0
  180. package/src/components/waka-device-trust/index.tsx +1259 -0
  181. package/src/components/waka-dock/index.tsx +285 -0
  182. package/src/components/waka-drawer/index.tsx +319 -0
  183. package/src/components/waka-empty-state/index.tsx +545 -0
  184. package/src/components/waka-error-shake/index.tsx +398 -0
  185. package/src/components/waka-feature-announcement/index.tsx +991 -0
  186. package/src/components/waka-file-upload/index.tsx +437 -0
  187. package/src/components/waka-floating-nav/index.tsx +413 -0
  188. package/src/components/waka-flow-diagram/index.tsx +508 -0
  189. package/src/components/waka-funnel-chart/index.tsx +823 -0
  190. package/src/components/waka-glow-card/index.tsx +246 -0
  191. package/src/components/waka-goal-progress/index.tsx +1025 -0
  192. package/src/components/waka-haptic-button/index.tsx +388 -0
  193. package/src/components/waka-health-pulse/index.tsx +451 -0
  194. package/src/components/waka-heatmap/index.tsx +1026 -0
  195. package/src/components/waka-hotspot/index.tsx +682 -0
  196. package/src/components/waka-image/index.tsx +373 -0
  197. package/src/components/waka-incident-timeline/index.tsx +686 -0
  198. package/src/components/waka-invoice-preview/index.tsx +829 -0
  199. package/src/components/waka-kanban/index.tsx +646 -0
  200. package/src/components/waka-kpi-dashboard/index.tsx +755 -0
  201. package/src/components/waka-leaderboard/index.tsx +746 -0
  202. package/src/components/waka-level-progress/index.tsx +665 -0
  203. package/src/components/waka-liquid-button/index.tsx +520 -0
  204. package/src/components/waka-loading-orbit/index.tsx +478 -0
  205. package/src/components/waka-loot-box/index.tsx +1091 -0
  206. package/src/components/waka-magic-link/index.tsx +321 -0
  207. package/src/components/waka-magnetic-button/index.tsx +567 -0
  208. package/src/components/waka-mention-input/index.tsx +953 -0
  209. package/src/components/waka-metric-sparkline/index.tsx +627 -0
  210. package/src/components/waka-milestone-road/index.tsx +1064 -0
  211. package/src/components/waka-modal/index.tsx +374 -0
  212. package/src/components/waka-morph-button/index.tsx +495 -0
  213. package/src/components/waka-network-topology/index.tsx +801 -0
  214. package/src/components/waka-notifications/index.tsx +414 -0
  215. package/src/components/waka-number-input/index.tsx +373 -0
  216. package/src/components/waka-orbital-menu/index.tsx +445 -0
  217. package/src/components/waka-order-tracker/index.tsx +1041 -0
  218. package/src/components/waka-pagination/index.tsx +393 -0
  219. package/src/components/waka-password-strength/index.tsx +824 -0
  220. package/src/components/waka-payment-method-picker/index.tsx +715 -0
  221. package/src/components/waka-permission-matrix/index.tsx +1302 -0
  222. package/src/components/waka-phone-input/index.tsx +801 -0
  223. package/src/components/waka-pipeline-view/index.tsx +604 -0
  224. package/src/components/waka-player-card/index.tsx +691 -0
  225. package/src/components/waka-points-popup/index.tsx +366 -0
  226. package/src/components/waka-power-up/index.tsx +1155 -0
  227. package/src/components/waka-presence-indicator/index.tsx +1181 -0
  228. package/src/components/waka-pricing-table/index.tsx +755 -0
  229. package/src/components/waka-product-card/index.tsx +786 -0
  230. package/src/components/waka-progress-onboarding/index.tsx +878 -0
  231. package/src/components/waka-pull-to-refresh/index.tsx +451 -0
  232. package/src/components/waka-qrcode/index.tsx +232 -0
  233. package/src/components/waka-quest-card/index.tsx +1275 -0
  234. package/src/components/waka-quota-bar/index.tsx +693 -0
  235. package/src/components/waka-radar-score/index.tsx +512 -0
  236. package/src/components/waka-rank-badge/index.tsx +813 -0
  237. package/src/components/waka-rating-input/index.tsx +560 -0
  238. package/src/components/waka-reaction-picker/index.tsx +1062 -0
  239. package/src/components/waka-region-map/index.tsx +730 -0
  240. package/src/components/waka-resource-gauge/index.tsx +654 -0
  241. package/src/components/waka-resource-pool/index.tsx +1035 -0
  242. package/src/components/waka-rich-text-editor/index.tsx +594 -0
  243. package/src/components/waka-rollback-slider/index.tsx +891 -0
  244. package/src/components/waka-sankey-diagram/index.tsx +1032 -0
  245. package/src/components/waka-schedule-picker/index.tsx +1060 -0
  246. package/src/components/waka-scratch-card/index.tsx +914 -0
  247. package/src/components/waka-season-pass/index.tsx +886 -0
  248. package/src/components/waka-security-score/index.tsx +1126 -0
  249. package/src/components/waka-segmented-control/index.tsx +238 -0
  250. package/src/components/waka-server-rack/index.tsx +764 -0
  251. package/src/components/waka-session-manager/index.tsx +815 -0
  252. package/src/components/waka-signature-pad/index.tsx +744 -0
  253. package/src/components/waka-skeleton-wave/index.tsx +454 -0
  254. package/src/components/waka-skill-tree/index.tsx +1031 -0
  255. package/src/components/waka-sla-tracker/index.tsx +798 -0
  256. package/src/components/waka-slider-range/index.tsx +765 -0
  257. package/src/components/waka-spin-wheel/index.tsx +671 -0
  258. package/src/components/waka-spinner/index.tsx +284 -0
  259. package/src/components/waka-spotlight/index.tsx +410 -0
  260. package/src/components/waka-stat/index.tsx +428 -0
  261. package/src/components/waka-stats-hexagon/index.tsx +824 -0
  262. package/src/components/waka-status-matrix/index.tsx +565 -0
  263. package/src/components/waka-stepper/index.tsx +489 -0
  264. package/src/components/waka-streak-counter/index.tsx +334 -0
  265. package/src/components/waka-success-explosion/index.tsx +453 -0
  266. package/src/components/waka-swipe-card/index.tsx +574 -0
  267. package/src/components/waka-tabs-morph/index.tsx +509 -0
  268. package/src/components/waka-tag-input/index.tsx +877 -0
  269. package/src/components/waka-team-banner/index.tsx +1183 -0
  270. package/src/components/waka-terminal-output/index.tsx +836 -0
  271. package/src/components/waka-theme-creator/index.tsx +762 -0
  272. package/src/components/waka-theme-manager/index.tsx +654 -0
  273. package/src/components/waka-thread-view/index.tsx +874 -0
  274. package/src/components/waka-tilt-card/index.tsx +250 -0
  275. package/src/components/waka-time-picker/index.tsx +479 -0
  276. package/src/components/waka-timeline/index.tsx +385 -0
  277. package/src/components/waka-tooltip-tour/index.tsx +855 -0
  278. package/src/components/waka-tour-guide/index.tsx +920 -0
  279. package/src/components/waka-tournament-bracket/index.tsx +1276 -0
  280. package/src/components/waka-tree/index.tsx +557 -0
  281. package/src/components/waka-treemap-chart/index.tsx +1031 -0
  282. package/src/components/waka-two-factor-setup/index.tsx +995 -0
  283. package/src/components/waka-typewriter/index.tsx +566 -0
  284. package/src/components/waka-typing-indicator/index.tsx +649 -0
  285. package/src/components/waka-versus-card/index.tsx +1026 -0
  286. package/src/components/waka-video/index.tsx +557 -0
  287. package/src/components/waka-video-call/index.tsx +1087 -0
  288. package/src/components/waka-virtual-list/index.tsx +327 -0
  289. package/src/components/waka-voice-message/index.tsx +1019 -0
  290. package/src/components/waka-welcome-modal/index.tsx +790 -0
  291. package/src/components/waka-xp-bar/index.tsx +799 -0
@@ -0,0 +1,172 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { flexRender, Table, HeaderGroup } from "@tanstack/react-table"
5
+ import { cn } from "./utils"
6
+
7
+ /**
8
+ * Props pour le composant DataTableHeader
9
+ */
10
+ export interface DataTableHeaderProps<TData> {
11
+ /** Instance de la table TanStack */
12
+ table: Table<TData>
13
+ /** Header sticky */
14
+ headerSticky?: boolean
15
+ /** Classes CSS pour la densité */
16
+ densityClasses?: {
17
+ header?: string
18
+ table?: string
19
+ cell?: string
20
+ }
21
+ /** Activer le redimensionnement des colonnes */
22
+ enableColumnResize?: boolean
23
+ /** Mode de redimensionnement */
24
+ columnResizeMode?: "onChange" | "onEnd"
25
+ }
26
+
27
+ /**
28
+ * Composant Header réutilisable pour DataTable
29
+ *
30
+ * Gère :
31
+ * - Le tri des colonnes
32
+ * - Le redimensionnement
33
+ * - Le sticky header
34
+ */
35
+ export function DataTableHeader<TData>({
36
+ table,
37
+ headerSticky = false,
38
+ densityClasses = {},
39
+ enableColumnResize = false,
40
+ columnResizeMode = "onEnd",
41
+ }: DataTableHeaderProps<TData>) {
42
+ return (
43
+ <thead className={cn(headerSticky && "sticky top-0 bg-background z-10")}>
44
+ {table.getHeaderGroups().map((headerGroup) => (
45
+ <DataTableHeaderRow
46
+ key={headerGroup.id}
47
+ headerGroup={headerGroup}
48
+ densityClasses={densityClasses}
49
+ enableColumnResize={enableColumnResize}
50
+ columnResizeMode={columnResizeMode}
51
+ table={table}
52
+ />
53
+ ))}
54
+ </thead>
55
+ )
56
+ }
57
+
58
+ /**
59
+ * Props pour DataTableHeaderRow
60
+ */
61
+ interface DataTableHeaderRowProps<TData> {
62
+ headerGroup: HeaderGroup<TData>
63
+ densityClasses: {
64
+ header?: string
65
+ table?: string
66
+ cell?: string
67
+ }
68
+ enableColumnResize: boolean
69
+ columnResizeMode: "onChange" | "onEnd"
70
+ table: Table<TData>
71
+ }
72
+
73
+ /**
74
+ * Ligne d'en-tête individuelle
75
+ * Optimisé avec React.memo pour éviter les re-renders inutiles
76
+ */
77
+ function DataTableHeaderRowInner<TData>({
78
+ headerGroup,
79
+ densityClasses,
80
+ enableColumnResize,
81
+ columnResizeMode,
82
+ table,
83
+ }: DataTableHeaderRowProps<TData>) {
84
+ return (
85
+ <tr className="border-b">
86
+ {headerGroup.headers.map((header) => {
87
+ const canSort = header.column.getCanSort()
88
+ const isSorted = header.column.getIsSorted()
89
+ const canResize = enableColumnResize && header.column.getCanResize()
90
+
91
+ return (
92
+ <th
93
+ key={header.id}
94
+ className={cn(
95
+ "text-left font-medium text-muted-foreground relative",
96
+ densityClasses.header,
97
+ canSort && "cursor-pointer select-none hover:text-foreground"
98
+ )}
99
+ onClick={header.column.getToggleSortingHandler()}
100
+ style={{
101
+ width: header.getSize(),
102
+ minWidth: header.column.columnDef.minSize,
103
+ maxWidth: header.column.columnDef.maxSize,
104
+ }}
105
+ >
106
+ <div className="flex items-center">
107
+ {header.isPlaceholder
108
+ ? null
109
+ : flexRender(header.column.columnDef.header, header.getContext())}
110
+
111
+ {/* Indicateur de tri */}
112
+ {isSorted && (
113
+ <span className="ml-2">
114
+ {isSorted === "asc" ? "↑" : "↓"}
115
+ </span>
116
+ )}
117
+ </div>
118
+
119
+ {/* Handle de redimensionnement */}
120
+ {canResize && (
121
+ <div
122
+ onMouseDown={header.getResizeHandler()}
123
+ onTouchStart={header.getResizeHandler()}
124
+ className={cn(
125
+ "absolute right-0 top-0 h-full w-1 cursor-col-resize select-none touch-none",
126
+ "hover:bg-primary/50",
127
+ header.column.getIsResizing() && "bg-primary"
128
+ )}
129
+ />
130
+ )}
131
+ </th>
132
+ )
133
+ })}
134
+ </tr>
135
+ )
136
+ }
137
+
138
+ /**
139
+ * Fonction de comparaison personnalisée pour React.memo
140
+ */
141
+ function areHeaderRowPropsEqual<TData>(
142
+ prevProps: DataTableHeaderRowProps<TData>,
143
+ nextProps: DataTableHeaderRowProps<TData>
144
+ ): boolean {
145
+ // Comparer l'ID du groupe de headers
146
+ if (prevProps.headerGroup.id !== nextProps.headerGroup.id) return false
147
+
148
+ // Comparer les classes de densité
149
+ if (prevProps.densityClasses.header !== nextProps.densityClasses.header) return false
150
+
151
+ // Comparer les options de redimensionnement
152
+ if (prevProps.enableColumnResize !== nextProps.enableColumnResize) return false
153
+ if (prevProps.columnResizeMode !== nextProps.columnResizeMode) return false
154
+
155
+ // Vérifier si le tri a changé sur une colonne
156
+ const prevHeaders = prevProps.headerGroup.headers
157
+ const nextHeaders = nextProps.headerGroup.headers
158
+ if (prevHeaders.length !== nextHeaders.length) return false
159
+
160
+ for (let i = 0; i < prevHeaders.length; i++) {
161
+ if (prevHeaders[i].column.getIsSorted() !== nextHeaders[i].column.getIsSorted()) return false
162
+ if (prevHeaders[i].column.getIsResizing() !== nextHeaders[i].column.getIsResizing()) return false
163
+ if (prevHeaders[i].getSize() !== nextHeaders[i].getSize()) return false
164
+ }
165
+
166
+ return true
167
+ }
168
+
169
+ // Export avec React.memo pour optimiser les re-renders
170
+ const DataTableHeaderRow = React.memo(DataTableHeaderRowInner, areHeaderRowPropsEqual) as typeof DataTableHeaderRowInner
171
+
172
+ export { DataTableHeaderRow }
@@ -0,0 +1,125 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Table } from "@tanstack/react-table"
5
+ import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from "lucide-react"
6
+ import { Button } from "../button"
7
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../select"
8
+ import { useTranslation } from "react-i18next"
9
+
10
+ interface DataTablePaginationProps<TData> {
11
+ table: Table<TData>
12
+ pageSizeOptions?: number[]
13
+ showInfo?: boolean
14
+ }
15
+
16
+ export function DataTablePagination<TData>({
17
+ table,
18
+ pageSizeOptions = [25, 50, 100, 500],
19
+ showInfo = true,
20
+ }: DataTablePaginationProps<TData>) {
21
+ const { t } = useTranslation()
22
+
23
+ const pageIndex = table.getState().pagination.pageIndex
24
+ const pageSize = table.getState().pagination.pageSize
25
+ const pageCount = table.getPageCount()
26
+ const totalRows = table.getFilteredRowModel().rows.length
27
+
28
+ const startRow = pageIndex * pageSize + 1
29
+ const endRow = Math.min((pageIndex + 1) * pageSize, totalRows)
30
+
31
+ return (
32
+ <div className="flex flex-col sm:flex-row items-center justify-between gap-4 px-4 py-3 border-t">
33
+ {/* Info de pagination */}
34
+ {showInfo && (
35
+ <div className="text-sm text-muted-foreground">
36
+ {totalRows > 0 ? (
37
+ <>
38
+ {t("datatable.pagination.showing", { defaultValue: "Showing" })} {startRow} {t("datatable.pagination.to", { defaultValue: "to" })} {endRow} {t("datatable.pagination.of", { defaultValue: "of" })} {totalRows} {t("datatable.pagination.results", { defaultValue: "results" })}
39
+ </>
40
+ ) : (
41
+ t("datatable.pagination.noResults", { defaultValue: "No results" })
42
+ )}
43
+ </div>
44
+ )}
45
+
46
+ <div className="flex items-center gap-6">
47
+ {/* Taille de page */}
48
+ <div className="flex items-center gap-2">
49
+ <span className="text-sm text-muted-foreground whitespace-nowrap">
50
+ {t("datatable.pagination.rowsPerPage", { defaultValue: "Rows per page" })}
51
+ </span>
52
+ <Select
53
+ value={`${pageSize}`}
54
+ onValueChange={(value) => {
55
+ table.setPageSize(Number(value))
56
+ }}
57
+ >
58
+ <SelectTrigger className="h-8 w-[70px]">
59
+ <SelectValue placeholder={pageSize} />
60
+ </SelectTrigger>
61
+ <SelectContent side="top">
62
+ {pageSizeOptions.map((size) => (
63
+ <SelectItem key={size} value={`${size}`}>
64
+ {size}
65
+ </SelectItem>
66
+ ))}
67
+ </SelectContent>
68
+ </Select>
69
+ </div>
70
+
71
+ {/* Navigation */}
72
+ <div className="flex items-center gap-1">
73
+ <span className="text-sm text-muted-foreground mr-2">
74
+ {t("datatable.pagination.page", { defaultValue: "Page" })} {pageIndex + 1} {t("datatable.pagination.of", { defaultValue: "of" })} {pageCount}
75
+ </span>
76
+
77
+ <Button
78
+ variant="outline"
79
+ size="icon"
80
+ className="h-8 w-8"
81
+ onClick={() => table.setPageIndex(0)}
82
+ disabled={!table.getCanPreviousPage()}
83
+ >
84
+ <ChevronsLeft className="h-4 w-4" />
85
+ <span className="sr-only">{t("datatable.pagination.firstPage", { defaultValue: "First page" })}</span>
86
+ </Button>
87
+
88
+ <Button
89
+ variant="outline"
90
+ size="icon"
91
+ className="h-8 w-8"
92
+ onClick={() => table.previousPage()}
93
+ disabled={!table.getCanPreviousPage()}
94
+ >
95
+ <ChevronLeft className="h-4 w-4" />
96
+ <span className="sr-only">{t("datatable.pagination.previousPage", { defaultValue: "Previous page" })}</span>
97
+ </Button>
98
+
99
+ <Button
100
+ variant="outline"
101
+ size="icon"
102
+ className="h-8 w-8"
103
+ onClick={() => table.nextPage()}
104
+ disabled={!table.getCanNextPage()}
105
+ >
106
+ <ChevronRight className="h-4 w-4" />
107
+ <span className="sr-only">{t("datatable.pagination.nextPage", { defaultValue: "Next page" })}</span>
108
+ </Button>
109
+
110
+ <Button
111
+ variant="outline"
112
+ size="icon"
113
+ className="h-8 w-8"
114
+ onClick={() => table.setPageIndex(pageCount - 1)}
115
+ disabled={!table.getCanNextPage()}
116
+ >
117
+ <ChevronsRight className="h-4 w-4" />
118
+ <span className="sr-only">{t("datatable.pagination.lastPage", { defaultValue: "Last page" })}</span>
119
+ </Button>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ )
124
+ }
125
+
@@ -0,0 +1,269 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Checkbox } from "../checkbox"
5
+ import { Button } from "../button"
6
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../select"
7
+ import { cn } from "./utils"
8
+
9
+ /**
10
+ * Props pour la sélection avancée du DataTable
11
+ */
12
+ export interface DataTableSelectionProps<TData> {
13
+ /** Table instance */
14
+ table: any
15
+ /** Mode de sélection */
16
+ selectionMode?: "single" | "multiple" | "range"
17
+ /** Données sélectionnées */
18
+ selectedRows: TData[]
19
+ /** Callback de changement de sélection */
20
+ onSelectionChange?: (selectedRows: TData[]) => void
21
+ /** Actions sur la sélection */
22
+ selectionActions?: Array<{
23
+ id: string
24
+ label: string
25
+ icon?: React.ReactNode
26
+ onClick: (selectedRows: TData[]) => void
27
+ disabled?: boolean
28
+ destructive?: boolean
29
+ }>
30
+ /** Classe CSS personnalisée */
31
+ className?: string
32
+ }
33
+
34
+ /**
35
+ * Composant pour la sélection avancée du DataTable
36
+ */
37
+ export function DataTableSelection<TData>({
38
+ table,
39
+ selectionMode = "multiple",
40
+ selectedRows,
41
+ onSelectionChange,
42
+ selectionActions = [],
43
+ className,
44
+ }: DataTableSelectionProps<TData>) {
45
+ const [lastSelectedIndex, setLastSelectedIndex] = React.useState<number | null>(null)
46
+
47
+ // Gestion de la sélection par plage (Shift+Click)
48
+ const handleRowSelection = React.useCallback((rowIndex: number, checked: boolean) => {
49
+ if (selectionMode === "single") {
50
+ table.setRowSelection({ [rowIndex]: checked })
51
+ return
52
+ }
53
+
54
+ if (selectionMode === "range" && lastSelectedIndex !== null) {
55
+ const start = Math.min(lastSelectedIndex, rowIndex)
56
+ const end = Math.max(lastSelectedIndex, rowIndex)
57
+ const newSelection = { ...table.getState().rowSelection }
58
+
59
+ for (let i = start; i <= end; i++) {
60
+ newSelection[i] = checked
61
+ }
62
+
63
+ table.setRowSelection(newSelection)
64
+ } else {
65
+ table.setRowSelection((prev: any) => ({
66
+ ...prev,
67
+ [rowIndex]: checked
68
+ }))
69
+ }
70
+
71
+ setLastSelectedIndex(rowIndex)
72
+ }, [table, selectionMode, lastSelectedIndex])
73
+
74
+ // Sélection de toutes les lignes
75
+ const handleSelectAll = React.useCallback((checked: boolean) => {
76
+ if (checked) {
77
+ const allRowIds = table.getRowModel().rows.reduce((acc: any, row: any, index: number) => {
78
+ acc[index] = true
79
+ return acc
80
+ }, {})
81
+ table.setRowSelection(allRowIds)
82
+ } else {
83
+ table.setRowSelection({})
84
+ }
85
+ }, [table])
86
+
87
+ // Sélection par plage
88
+ const handleRangeSelection = React.useCallback((start: number, end: number, checked: boolean) => {
89
+ const newSelection = { ...table.getState().rowSelection }
90
+
91
+ for (let i = start; i <= end; i++) {
92
+ newSelection[i] = checked
93
+ }
94
+
95
+ table.setRowSelection(newSelection)
96
+ }, [table])
97
+
98
+ // Sélection par critères
99
+ const handleSelectByCriteria = React.useCallback((criteria: (row: TData) => boolean) => {
100
+ const newSelection = { ...table.getState().rowSelection }
101
+
102
+ table.getRowModel().rows.forEach((row: any, index: number) => {
103
+ if (criteria(row.original)) {
104
+ newSelection[index] = true
105
+ }
106
+ })
107
+
108
+ table.setRowSelection(newSelection)
109
+ }, [table])
110
+
111
+ // Actions de sélection
112
+ const handleSelectionAction = React.useCallback((action: any) => {
113
+ action.onClick(selectedRows)
114
+ }, [selectedRows])
115
+
116
+ const isAllSelected = table.getIsAllPageRowsSelected()
117
+ const isSomeSelected = table.getIsSomePageRowsSelected()
118
+
119
+ return (
120
+ <div className={cn("flex items-center gap-2", className)}>
121
+ {/* Checkbox principal */}
122
+ <Checkbox
123
+ checked={isAllSelected}
124
+ onCheckedChange={handleSelectAll}
125
+ ref={(el) => {
126
+ if (el && 'indeterminate' in el) {
127
+ (el as any).indeterminate = isSomeSelected && !isAllSelected
128
+ }
129
+ }}
130
+ aria-label="Select all rows"
131
+ />
132
+
133
+ {/* Informations de sélection */}
134
+ {selectedRows.length > 0 && (
135
+ <div className="flex items-center gap-2 text-sm text-muted-foreground">
136
+ <span>{selectedRows.length} selected</span>
137
+
138
+ {/* Actions rapides */}
139
+ <div className="flex items-center gap-1">
140
+ {selectionActions.map((action) => (
141
+ <Button
142
+ key={action.id}
143
+ variant="ghost"
144
+ size="sm"
145
+ onClick={() => handleSelectionAction(action)}
146
+ disabled={action.disabled}
147
+ className={cn(
148
+ action.destructive && "text-destructive hover:text-destructive"
149
+ )}
150
+ >
151
+ {action.icon && <span className="mr-1">{action.icon}</span>}
152
+ {action.label}
153
+ </Button>
154
+ ))}
155
+ </div>
156
+ </div>
157
+ )}
158
+
159
+ {/* Sélection par critères */}
160
+ <Select onValueChange={(value) => {
161
+ switch (value) {
162
+ case "all":
163
+ handleSelectAll(true)
164
+ break
165
+ case "none":
166
+ handleSelectAll(false)
167
+ break
168
+ case "invert":
169
+ table.getRowModel().rows.forEach((row: any, index: number) => {
170
+ const isSelected = table.getState().rowSelection[index]
171
+ table.setRowSelection((prev: any) => ({
172
+ ...prev,
173
+ [index]: !isSelected
174
+ }))
175
+ })
176
+ break
177
+ }
178
+ }}>
179
+ <SelectTrigger className="w-32">
180
+ <SelectValue placeholder="Select" />
181
+ </SelectTrigger>
182
+ <SelectContent>
183
+ <SelectItem value="all">Select All</SelectItem>
184
+ <SelectItem value="none">Select None</SelectItem>
185
+ <SelectItem value="invert">Invert Selection</SelectItem>
186
+ </SelectContent>
187
+ </Select>
188
+ </div>
189
+ )
190
+ }
191
+
192
+ /**
193
+ * Hook pour la sélection avancée
194
+ */
195
+ export function useDataTableSelection<TData>({
196
+ table,
197
+ selectionMode = "multiple",
198
+ onSelectionChange,
199
+ }: {
200
+ table: any
201
+ selectionMode?: "single" | "multiple" | "range"
202
+ onSelectionChange?: (selectedRows: TData[]) => void
203
+ }) {
204
+ const [selectedRows, setSelectedRows] = React.useState<TData[]>([])
205
+
206
+ // Mise à jour des lignes sélectionnées
207
+ React.useEffect(() => {
208
+ const selected = table.getFilteredSelectedRowModel().rows.map((row: any) => row.original)
209
+ setSelectedRows(selected)
210
+ onSelectionChange?.(selected)
211
+ }, [table, onSelectionChange])
212
+
213
+ // Fonctions utilitaires
214
+ const selectRow = React.useCallback((rowIndex: number, selected: boolean = true) => {
215
+ table.setRowSelection((prev: any) => ({
216
+ ...prev,
217
+ [rowIndex]: selected
218
+ }))
219
+ }, [table])
220
+
221
+ const selectAll = React.useCallback((selected: boolean = true) => {
222
+ if (selected) {
223
+ const allRowIds = table.getRowModel().rows.reduce((acc: any, row: any, index: number) => {
224
+ acc[index] = true
225
+ return acc
226
+ }, {})
227
+ table.setRowSelection(allRowIds)
228
+ } else {
229
+ table.setRowSelection({})
230
+ }
231
+ }, [table])
232
+
233
+ const selectRange = React.useCallback((start: number, end: number, selected: boolean = true) => {
234
+ const newSelection = { ...table.getState().rowSelection }
235
+
236
+ for (let i = start; i <= end; i++) {
237
+ newSelection[i] = selected
238
+ }
239
+
240
+ table.setRowSelection(newSelection)
241
+ }, [table])
242
+
243
+ const selectByCriteria = React.useCallback((criteria: (row: TData) => boolean) => {
244
+ const newSelection = { ...table.getState().rowSelection }
245
+
246
+ table.getRowModel().rows.forEach((row: any, index: number) => {
247
+ if (criteria(row.original)) {
248
+ newSelection[index] = true
249
+ }
250
+ })
251
+
252
+ table.setRowSelection(newSelection)
253
+ }, [table])
254
+
255
+ const clearSelection = React.useCallback(() => {
256
+ table.setRowSelection({})
257
+ }, [table])
258
+
259
+ return {
260
+ selectedRows,
261
+ selectRow,
262
+ selectAll,
263
+ selectRange,
264
+ selectByCriteria,
265
+ clearSelection,
266
+ isAllSelected: table.getIsAllPageRowsSelected(),
267
+ isSomeSelected: table.getIsSomePageRowsSelected(),
268
+ }
269
+ }