@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,376 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "../../utils/cn"
5
+ import { ChevronRight, Home, MoreHorizontal } from "lucide-react"
6
+ import {
7
+ DropdownMenu,
8
+ DropdownMenuContent,
9
+ DropdownMenuItem,
10
+ DropdownMenuTrigger,
11
+ } from "../dropdown-menu"
12
+
13
+ // ============================================
14
+ // TYPES
15
+ // ============================================
16
+
17
+ export interface BreadcrumbItem {
18
+ /** Libellé de l'élément */
19
+ label: string
20
+ /** URL de destination (optionnel pour le dernier élément) */
21
+ href?: string
22
+ /** Icône personnalisée */
23
+ icon?: React.ReactNode
24
+ /** Désactiver le lien */
25
+ disabled?: boolean
26
+ /** Données additionnelles */
27
+ data?: Record<string, unknown>
28
+ }
29
+
30
+ export interface WakaBreadcrumbProps {
31
+ /** Liste des éléments du fil d'Ariane */
32
+ items: BreadcrumbItem[]
33
+ /** Séparateur entre les éléments */
34
+ separator?: React.ReactNode
35
+ /** Afficher l'icône Home pour le premier élément */
36
+ showHomeIcon?: boolean
37
+ /** Nombre maximum d'éléments visibles (collapse les autres) */
38
+ maxItems?: number
39
+ /** Fonction de rendu personnalisée pour les liens */
40
+ renderLink?: (item: BreadcrumbItem, children: React.ReactNode) => React.ReactNode
41
+ /** Callback lors du clic sur un élément */
42
+ onItemClick?: (item: BreadcrumbItem, index: number) => void
43
+ /** Taille */
44
+ size?: "sm" | "md" | "lg"
45
+ /** Variante visuelle */
46
+ variant?: "default" | "ghost" | "outline"
47
+ /** Classes CSS additionnelles */
48
+ className?: string
49
+ }
50
+
51
+ // ============================================
52
+ // SUB-COMPONENTS
53
+ // ============================================
54
+
55
+ interface BreadcrumbLinkProps {
56
+ item: BreadcrumbItem
57
+ index: number
58
+ isLast: boolean
59
+ size: "sm" | "md" | "lg"
60
+ variant: "default" | "ghost" | "outline"
61
+ showHomeIcon: boolean
62
+ renderLink?: (item: BreadcrumbItem, children: React.ReactNode) => React.ReactNode
63
+ onItemClick?: (item: BreadcrumbItem, index: number) => void
64
+ }
65
+
66
+ function BreadcrumbLink({
67
+ item,
68
+ index,
69
+ isLast,
70
+ size,
71
+ variant,
72
+ showHomeIcon,
73
+ renderLink,
74
+ onItemClick,
75
+ }: BreadcrumbLinkProps) {
76
+ const sizeClasses = {
77
+ sm: "text-xs py-0.5 px-1.5",
78
+ md: "text-sm py-1 px-2",
79
+ lg: "text-base py-1.5 px-3",
80
+ }
81
+
82
+ const iconSizes = {
83
+ sm: "h-3 w-3",
84
+ md: "h-4 w-4",
85
+ lg: "h-5 w-5",
86
+ }
87
+
88
+ const variantClasses = {
89
+ default: isLast
90
+ ? "text-foreground font-medium"
91
+ : "text-muted-foreground hover:text-foreground",
92
+ ghost: isLast
93
+ ? "text-foreground font-medium bg-muted rounded-md"
94
+ : "text-muted-foreground hover:text-foreground hover:bg-muted rounded-md",
95
+ outline: isLast
96
+ ? "text-foreground font-medium border rounded-md"
97
+ : "text-muted-foreground hover:text-foreground hover:border-foreground border border-transparent rounded-md",
98
+ }
99
+
100
+ const content = (
101
+ <span className="flex items-center gap-1.5">
102
+ {index === 0 && showHomeIcon && !item.icon && (
103
+ <Home className={iconSizes[size]} />
104
+ )}
105
+ {item.icon && <span className={iconSizes[size]}>{item.icon}</span>}
106
+ <span className="truncate max-w-[150px]">{item.label}</span>
107
+ </span>
108
+ )
109
+
110
+ const baseClasses = cn(
111
+ "inline-flex items-center transition-colors",
112
+ sizeClasses[size],
113
+ variantClasses[variant],
114
+ item.disabled && "opacity-50 pointer-events-none"
115
+ )
116
+
117
+ const handleClick = (e: React.MouseEvent) => {
118
+ if (onItemClick) {
119
+ e.preventDefault()
120
+ onItemClick(item, index)
121
+ }
122
+ }
123
+
124
+ // Si c'est le dernier élément ou pas de href, on affiche un span
125
+ if (isLast || !item.href) {
126
+ return (
127
+ <span
128
+ className={cn(baseClasses, "cursor-default")}
129
+ aria-current={isLast ? "page" : undefined}
130
+ >
131
+ {content}
132
+ </span>
133
+ )
134
+ }
135
+
136
+ // Si une fonction de rendu personnalisée est fournie
137
+ if (renderLink) {
138
+ return renderLink(item, (
139
+ <span className={baseClasses} onClick={handleClick}>
140
+ {content}
141
+ </span>
142
+ ))
143
+ }
144
+
145
+ // Lien par défaut
146
+ return (
147
+ <a
148
+ href={item.href}
149
+ className={baseClasses}
150
+ onClick={handleClick}
151
+ >
152
+ {content}
153
+ </a>
154
+ )
155
+ }
156
+
157
+ interface CollapsedItemsProps {
158
+ items: BreadcrumbItem[]
159
+ startIndex: number
160
+ size: "sm" | "md" | "lg"
161
+ renderLink?: (item: BreadcrumbItem, children: React.ReactNode) => React.ReactNode
162
+ onItemClick?: (item: BreadcrumbItem, index: number) => void
163
+ }
164
+
165
+ function CollapsedItems({
166
+ items,
167
+ startIndex,
168
+ size,
169
+ renderLink,
170
+ onItemClick,
171
+ }: CollapsedItemsProps) {
172
+ const iconSizes = {
173
+ sm: "h-3 w-3",
174
+ md: "h-4 w-4",
175
+ lg: "h-5 w-5",
176
+ }
177
+
178
+ return (
179
+ <DropdownMenu>
180
+ <DropdownMenuTrigger asChild>
181
+ <button
182
+ type="button"
183
+ className="inline-flex items-center justify-center p-1 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
184
+ aria-label="Afficher les éléments masqués"
185
+ >
186
+ <MoreHorizontal className={iconSizes[size]} />
187
+ </button>
188
+ </DropdownMenuTrigger>
189
+ <DropdownMenuContent align="start">
190
+ {items.map((item, idx) => {
191
+ const actualIndex = startIndex + idx
192
+ const handleClick = () => {
193
+ onItemClick?.(item, actualIndex)
194
+ }
195
+
196
+ if (renderLink && item.href) {
197
+ return (
198
+ <DropdownMenuItem key={actualIndex} asChild>
199
+ {renderLink(item, (
200
+ <span className="flex items-center gap-2 w-full">
201
+ {item.icon}
202
+ {item.label}
203
+ </span>
204
+ ))}
205
+ </DropdownMenuItem>
206
+ )
207
+ }
208
+
209
+ return (
210
+ <DropdownMenuItem
211
+ key={actualIndex}
212
+ onClick={handleClick}
213
+ disabled={item.disabled}
214
+ >
215
+ {item.icon && <span className="mr-2">{item.icon}</span>}
216
+ {item.label}
217
+ </DropdownMenuItem>
218
+ )
219
+ })}
220
+ </DropdownMenuContent>
221
+ </DropdownMenu>
222
+ )
223
+ }
224
+
225
+ // ============================================
226
+ // MAIN COMPONENT
227
+ // ============================================
228
+
229
+ export function WakaBreadcrumb({
230
+ items,
231
+ separator,
232
+ showHomeIcon = false,
233
+ maxItems,
234
+ renderLink,
235
+ onItemClick,
236
+ size = "md",
237
+ variant = "default",
238
+ className,
239
+ }: WakaBreadcrumbProps) {
240
+ const separatorSizes = {
241
+ sm: "h-3 w-3",
242
+ md: "h-4 w-4",
243
+ lg: "h-5 w-5",
244
+ }
245
+
246
+ const defaultSeparator = (
247
+ <ChevronRight className={cn(separatorSizes[size], "text-muted-foreground")} />
248
+ )
249
+
250
+ const renderSeparator = () => separator ?? defaultSeparator
251
+
252
+ // Calculer les éléments à afficher
253
+ const shouldCollapse = maxItems && items.length > maxItems
254
+
255
+ let visibleItems: BreadcrumbItem[]
256
+ let collapsedItems: BreadcrumbItem[] = []
257
+ let collapsedStartIndex = 0
258
+
259
+ if (shouldCollapse && maxItems) {
260
+ // Garder le premier et les (maxItems - 2) derniers éléments
261
+ const keepEnd = Math.max(maxItems - 2, 1)
262
+ visibleItems = [items[0], ...items.slice(-keepEnd)]
263
+ collapsedItems = items.slice(1, -keepEnd)
264
+ collapsedStartIndex = 1
265
+ } else {
266
+ visibleItems = items
267
+ }
268
+
269
+ return (
270
+ <nav aria-label="Fil d'Ariane" className={cn("flex items-center", className)}>
271
+ <ol className="flex items-center flex-wrap gap-1">
272
+ {/* Premier élément */}
273
+ {visibleItems.length > 0 && (
274
+ <li className="flex items-center">
275
+ <BreadcrumbLink
276
+ item={visibleItems[0]}
277
+ index={0}
278
+ isLast={visibleItems.length === 1 && !shouldCollapse}
279
+ size={size}
280
+ variant={variant}
281
+ showHomeIcon={showHomeIcon}
282
+ renderLink={renderLink}
283
+ onItemClick={onItemClick}
284
+ />
285
+ </li>
286
+ )}
287
+
288
+ {/* Éléments collapsés */}
289
+ {shouldCollapse && collapsedItems.length > 0 && (
290
+ <>
291
+ <li className="flex items-center" aria-hidden="true">
292
+ {renderSeparator()}
293
+ </li>
294
+ <li className="flex items-center">
295
+ <CollapsedItems
296
+ items={collapsedItems}
297
+ startIndex={collapsedStartIndex}
298
+ size={size}
299
+ renderLink={renderLink}
300
+ onItemClick={onItemClick}
301
+ />
302
+ </li>
303
+ </>
304
+ )}
305
+
306
+ {/* Éléments restants */}
307
+ {visibleItems.slice(1).map((item, idx) => {
308
+ const actualIndex = shouldCollapse
309
+ ? items.length - (visibleItems.length - 1 - idx)
310
+ : idx + 1
311
+
312
+ return (
313
+ <React.Fragment key={actualIndex}>
314
+ <li className="flex items-center" aria-hidden="true">
315
+ {renderSeparator()}
316
+ </li>
317
+ <li className="flex items-center">
318
+ <BreadcrumbLink
319
+ item={item}
320
+ index={actualIndex}
321
+ isLast={actualIndex === items.length - 1}
322
+ size={size}
323
+ variant={variant}
324
+ showHomeIcon={false}
325
+ renderLink={renderLink}
326
+ onItemClick={onItemClick}
327
+ />
328
+ </li>
329
+ </React.Fragment>
330
+ )
331
+ })}
332
+ </ol>
333
+ </nav>
334
+ )
335
+ }
336
+
337
+ // ============================================
338
+ // UTILITY HOOK
339
+ // ============================================
340
+
341
+ /**
342
+ * Hook pour générer un fil d'Ariane à partir d'un chemin URL
343
+ */
344
+ export function useBreadcrumbFromPath(
345
+ pathname: string,
346
+ options?: {
347
+ homeLabel?: string
348
+ labelMap?: Record<string, string>
349
+ excludePaths?: string[]
350
+ }
351
+ ): BreadcrumbItem[] {
352
+ const { homeLabel = "Accueil", labelMap = {}, excludePaths = [] } = options || {}
353
+
354
+ return React.useMemo(() => {
355
+ const segments = pathname.split("/").filter(Boolean)
356
+ const filteredSegments = segments.filter(seg => !excludePaths.includes(seg))
357
+
358
+ const items: BreadcrumbItem[] = [
359
+ { label: homeLabel, href: "/" }
360
+ ]
361
+
362
+ let currentPath = ""
363
+ filteredSegments.forEach((segment) => {
364
+ currentPath += `/${segment}`
365
+ const label = labelMap[segment] || segment.charAt(0).toUpperCase() + segment.slice(1).replace(/-/g, " ")
366
+ items.push({
367
+ label,
368
+ href: currentPath,
369
+ })
370
+ })
371
+
372
+ return items
373
+ }, [pathname, homeLabel, labelMap, excludePaths])
374
+ }
375
+
376
+ export default WakaBreadcrumb