@wakastellar/ui 2.4.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/dist/blocks/antivirus-dashboard/index.d.ts +44 -0
  2. package/dist/blocks/clamav-service-status/index.d.ts +35 -0
  3. package/dist/blocks/file-scan-uploader/index.d.ts +29 -0
  4. package/dist/blocks/index.d.ts +18 -9
  5. package/dist/blocks/quarantine-manager/index.d.ts +27 -0
  6. package/dist/blocks/scan-history-log/index.d.ts +28 -0
  7. package/dist/blocks/scan-policy-editor/index.d.ts +27 -0
  8. package/dist/blocks/scan-report-generator/index.d.ts +47 -0
  9. package/dist/blocks/signature-database-manager/index.d.ts +39 -0
  10. package/dist/blocks/threat-alert-banner/index.d.ts +26 -0
  11. package/dist/components/index.d.ts +4 -4
  12. package/dist/components/waka-signature-pad/index.d.ts +1 -1
  13. package/dist/exceljs.min-BcLLX0PC.js +29 -0
  14. package/dist/exceljs.min-KOayaaQ4.mjs +23013 -0
  15. package/dist/export.cjs.js +1 -1
  16. package/dist/export.d.ts +2 -2
  17. package/dist/export.es.js +1 -1
  18. package/dist/index.cjs.js +136 -136
  19. package/dist/index.es.js +29978 -27215
  20. package/dist/stories/Button.stories.d.ts +1 -1
  21. package/dist/stories/Header.stories.d.ts +1 -1
  22. package/dist/stories/Page.stories.d.ts +1 -1
  23. package/dist/useDataTableImport-COVnvslz.js +9 -0
  24. package/dist/useDataTableImport-DAlxBY8w.mjs +237 -0
  25. package/dist/utils/index.d.ts +1 -0
  26. package/dist/utils/logger.d.ts +9 -0
  27. package/package.json +6 -5
  28. package/src/blocks/antivirus-dashboard/AntivirusDashboard.stories.tsx +291 -0
  29. package/src/blocks/antivirus-dashboard/index.tsx +525 -0
  30. package/src/blocks/clamav-service-status/ClamAVServiceStatus.stories.tsx +195 -0
  31. package/src/blocks/clamav-service-status/index.tsx +370 -0
  32. package/src/blocks/file-scan-uploader/FileScanUploader.stories.tsx +257 -0
  33. package/src/blocks/file-scan-uploader/index.tsx +311 -0
  34. package/src/blocks/index.ts +163 -11
  35. package/src/blocks/quarantine-manager/QuarantineManager.stories.tsx +209 -0
  36. package/src/blocks/quarantine-manager/index.tsx +435 -0
  37. package/src/blocks/scan-history-log/ScanHistoryLog.stories.tsx +231 -0
  38. package/src/blocks/scan-history-log/index.tsx +406 -0
  39. package/src/blocks/scan-policy-editor/ScanPolicyEditor.stories.tsx +106 -0
  40. package/src/blocks/scan-policy-editor/index.tsx +418 -0
  41. package/src/blocks/scan-report-generator/ScanReportGenerator.stories.tsx +232 -0
  42. package/src/blocks/scan-report-generator/index.tsx +612 -0
  43. package/src/blocks/sidebar/index.tsx +2 -1
  44. package/src/blocks/signature-database-manager/SignatureDatabaseManager.stories.tsx +279 -0
  45. package/src/blocks/signature-database-manager/index.tsx +470 -0
  46. package/src/blocks/theme-creator-block/index.tsx +16 -2
  47. package/src/blocks/threat-alert-banner/ThreatAlertBanner.stories.tsx +152 -0
  48. package/src/blocks/threat-alert-banner/index.tsx +320 -0
  49. package/src/components/DataTable/DataTable.stories.tsx +203 -0
  50. package/src/components/DataTable/hooks/useDataTableExport.ts +38 -31
  51. package/src/components/DataTable/hooks/useDataTableImport.ts +31 -20
  52. package/src/components/error-boundary/ErrorBoundary.stories.tsx +125 -0
  53. package/src/components/index.ts +45 -4
  54. package/src/components/language-selector/LanguageSelector.stories.tsx +112 -0
  55. package/src/components/theme-selector/ThemeSelector.stories.tsx +77 -0
  56. package/src/components/toaster/Toaster.stories.tsx +67 -0
  57. package/src/components/waka-activity-feed/WakaActivityFeed.stories.tsx +116 -0
  58. package/src/components/waka-ad-banner/WakaAdBanner.stories.tsx +102 -0
  59. package/src/components/waka-ad-fallback/WakaAdFallback.stories.tsx +117 -0
  60. package/src/components/waka-ad-inline/WakaAdInline.stories.tsx +105 -0
  61. package/src/components/waka-ad-interstitial/WakaAdInterstitial.stories.tsx +92 -0
  62. package/src/components/waka-ad-placeholder/WakaAdPlaceholder.stories.tsx +89 -0
  63. package/src/components/waka-ad-provider/WakaAdProvider.stories.tsx +110 -0
  64. package/src/components/waka-ad-sidebar/WakaAdSidebar.stories.tsx +89 -0
  65. package/src/components/waka-ad-sidebar/index.tsx +3 -2
  66. package/src/components/waka-ad-sticky-footer/WakaAdStickyFooter.stories.tsx +88 -0
  67. package/src/components/waka-address-autocomplete/WakaAddressAutocomplete.stories.tsx +46 -0
  68. package/src/components/waka-admincrumb/WakaAdmincrumb.stories.tsx +166 -0
  69. package/src/components/waka-alert-panel/WakaAlertPanel.stories.tsx +45 -0
  70. package/src/components/waka-alert-stack/WakaAlertStack.stories.tsx +62 -0
  71. package/src/components/waka-allocation-matrix/WakaAllocationMatrix.stories.tsx +68 -0
  72. package/src/components/waka-approval-chain/WakaApprovalChain.stories.tsx +63 -0
  73. package/src/components/waka-audit-log/WakaAuditLog.stories.tsx +73 -0
  74. package/src/components/waka-autocomplete/WakaAutocomplete.stories.tsx +132 -172
  75. package/src/components/waka-biometric-prompt/WakaBiometricPrompt.stories.tsx +48 -0
  76. package/src/components/waka-breadcrumb/WakaBreadcrumb.stories.tsx +74 -191
  77. package/src/components/waka-breadcrumb-path/WakaBreadcrumbPath.stories.tsx +40 -0
  78. package/src/components/waka-budget-burn/WakaBudgetBurn.stories.tsx +86 -0
  79. package/src/components/waka-capacity-planner/WakaCapacityPlanner.stories.tsx +273 -0
  80. package/src/components/waka-cart-summary/WakaCartSummary.stories.tsx +176 -0
  81. package/src/components/waka-cart-summary/index.tsx +19 -10
  82. package/src/components/waka-challenge-timer/WakaChallengeTimer.stories.tsx +98 -0
  83. package/src/components/waka-chat-bubble/WakaChatBubble.stories.tsx +118 -0
  84. package/src/components/waka-checklist/WakaChecklist.stories.tsx +71 -0
  85. package/src/components/waka-checkout-stepper/WakaCheckoutStepper.stories.tsx +102 -0
  86. package/src/components/waka-cohort-table/WakaCohortTable.stories.tsx +56 -0
  87. package/src/components/waka-color-picker/WakaColorPicker.stories.tsx +99 -155
  88. package/src/components/waka-combo-counter/WakaComboCounter.stories.tsx +128 -0
  89. package/src/components/waka-command-bar/WakaCommandBar.stories.tsx +45 -0
  90. package/src/components/waka-compare-period/WakaComparePeriod.stories.tsx +76 -0
  91. package/src/components/waka-config-comparator/WakaConfigComparator.stories.tsx +143 -0
  92. package/src/components/waka-connection-matrix/WakaConnectionMatrix.stories.tsx +52 -0
  93. package/src/components/waka-content-recommendation/WakaContentRecommendation.stories.tsx +41 -0
  94. package/src/components/waka-coupon-input/WakaCouponInput.stories.tsx +126 -0
  95. package/src/components/waka-credit-card-input/WakaCreditCardInput.stories.tsx +120 -0
  96. package/src/components/waka-datetime-picker.form-integration/WakaDateTimePickerForm.stories.tsx +79 -0
  97. package/src/components/waka-dependency-tree/WakaDependencyTree.stories.tsx +72 -0
  98. package/src/components/waka-device-trust/WakaDeviceTrust.stories.tsx +109 -0
  99. package/src/components/waka-empty-state/WakaEmptyState.stories.tsx +87 -0
  100. package/src/components/waka-feature-announcement/WakaFeatureAnnouncement.stories.tsx +47 -0
  101. package/src/components/waka-feature-flag-row/WakaFeatureFlagRow.stories.tsx +188 -0
  102. package/src/components/waka-file-upload/WakaFileUpload.stories.tsx +118 -174
  103. package/src/components/waka-floating-nav/WakaFloatingNav.stories.tsx +53 -0
  104. package/src/components/waka-goal-progress/WakaGoalProgress.stories.tsx +137 -0
  105. package/src/components/waka-hotspot/WakaHotspot.stories.tsx +56 -0
  106. package/src/components/waka-invoice-preview/WakaInvoicePreview.stories.tsx +169 -0
  107. package/src/components/waka-kpi-dashboard/WakaKpiDashboard.stories.tsx +46 -0
  108. package/src/components/waka-level-progress/WakaLevelProgress.stories.tsx +94 -75
  109. package/src/components/waka-liquid-button/WakaLiquidButton.stories.tsx +45 -0
  110. package/src/components/waka-magic-link/WakaMagicLink.stories.tsx +61 -0
  111. package/src/components/waka-magnetic-button/WakaMagneticButton.stories.tsx +40 -0
  112. package/src/components/waka-mention-input/WakaMentionInput.stories.tsx +140 -0
  113. package/src/components/waka-milestone-road/WakaMilestoneRoad.stories.tsx +143 -0
  114. package/src/components/waka-orbital-menu/WakaOrbitalMenu.stories.tsx +54 -0
  115. package/src/components/waka-order-tracker/WakaOrderTracker.stories.tsx +163 -0
  116. package/src/components/waka-outstream-video/WakaOutstreamVideo.stories.tsx +94 -0
  117. package/src/components/waka-pagination/WakaPagination.stories.tsx +110 -280
  118. package/src/components/waka-password-strength/WakaPasswordStrength.stories.tsx +132 -268
  119. package/src/components/waka-payment-method-picker/WakaPaymentMethodPicker.stories.tsx +141 -0
  120. package/src/components/waka-permission-matrix/WakaPermissionMatrix.stories.tsx +124 -0
  121. package/src/components/waka-phone-input/WakaPhoneInput.stories.tsx +56 -0
  122. package/src/components/waka-points-popup/WakaPointsPopup.stories.tsx +96 -0
  123. package/src/components/waka-power-up/WakaPowerUp.stories.tsx +121 -0
  124. package/src/components/waka-presence-indicator/WakaPresenceIndicator.stories.tsx +49 -0
  125. package/src/components/waka-pricing-table/WakaPricingTable.stories.tsx +159 -0
  126. package/src/components/waka-product-card/WakaProductCard.stories.tsx +202 -0
  127. package/src/components/waka-progress-onboarding/WakaProgressOnboarding.stories.tsx +57 -0
  128. package/src/components/waka-pull-to-refresh/WakaPullToRefresh.stories.tsx +51 -0
  129. package/src/components/waka-rank-badge/WakaRankBadge.stories.tsx +108 -0
  130. package/src/components/waka-rating-input/WakaRatingInput.stories.tsx +51 -0
  131. package/src/components/waka-reaction-picker/WakaReactionPicker.stories.tsx +52 -0
  132. package/src/components/waka-region-map/WakaRegionMap.stories.tsx +181 -0
  133. package/src/components/waka-resource-pool/WakaResourcePool.stories.tsx +70 -0
  134. package/src/components/waka-rich-text-editor/WakaRichTextEditor.stories.tsx +108 -197
  135. package/src/components/waka-rollback-slider/WakaRollbackSlider.stories.tsx +41 -0
  136. package/src/components/waka-schedule-picker/WakaSchedulePicker.stories.tsx +64 -0
  137. package/src/components/waka-season-pass/WakaSeasonPass.stories.tsx +107 -0
  138. package/src/components/waka-security-scan-result/WakaSecurityScanResult.stories.tsx +146 -0
  139. package/src/components/waka-security-score/WakaSecurityScore.stories.tsx +63 -0
  140. package/src/components/waka-session-manager/WakaSessionManager.stories.tsx +68 -0
  141. package/src/components/waka-signature-pad/WakaSignaturePad.stories.tsx +159 -0
  142. package/src/components/waka-signature-pad/index.tsx +5 -3
  143. package/src/components/waka-sla-tracker/WakaSlaTracker.stories.tsx +65 -0
  144. package/src/components/waka-slider-range/WakaSliderRange.stories.tsx +66 -0
  145. package/src/components/waka-sponsored-badge/WakaSponsoredBadge.stories.tsx +60 -0
  146. package/src/components/waka-sponsored-card/WakaSponsoredCard.stories.tsx +64 -0
  147. package/src/components/waka-sponsored-feed/WakaSponsoredFeed.stories.tsx +58 -0
  148. package/src/components/waka-spotlight/WakaSpotlight.stories.tsx +53 -0
  149. package/src/components/waka-stats-hexagon/WakaStatsHexagon.stories.tsx +161 -0
  150. package/src/components/waka-stepper/WakaStepper.stories.tsx +137 -410
  151. package/src/components/waka-swipe-card/WakaSwipeCard.stories.tsx +51 -0
  152. package/src/components/waka-tag-input/WakaTagInput.stories.tsx +224 -0
  153. package/src/components/waka-team-banner/WakaTeamBanner.stories.tsx +50 -0
  154. package/src/components/waka-theme-creator/WakaThemeCreator.stories.tsx +58 -0
  155. package/src/components/waka-theme-manager/WakaThemeManager.stories.tsx +298 -0
  156. package/src/components/waka-theme-manager/index.tsx +6 -11
  157. package/src/components/waka-thread-view/WakaThreadView.stories.tsx +143 -0
  158. package/src/components/waka-timeline/WakaTimeline.stories.tsx +171 -324
  159. package/src/components/waka-tooltip-tour/WakaTooltipTour.stories.tsx +92 -0
  160. package/src/components/waka-tour-guide/WakaTourGuide.stories.tsx +89 -0
  161. package/src/components/waka-treemap-chart/WakaTreemapChart.stories.tsx +234 -129
  162. package/src/components/waka-treemap-chart/index.tsx +2 -2
  163. package/src/components/waka-two-factor-setup/WakaTwoFactorSetup.stories.tsx +142 -0
  164. package/src/components/waka-typing-indicator/WakaTypingIndicator.stories.tsx +134 -0
  165. package/src/components/waka-video-ad/WakaVideoAd.stories.tsx +138 -0
  166. package/src/components/waka-video-call/WakaVideoCall.stories.tsx +186 -0
  167. package/src/components/waka-video-overlay/WakaVideoOverlay.stories.tsx +100 -0
  168. package/src/components/waka-voice-message/WakaVoiceMessage.stories.tsx +190 -0
  169. package/src/components/waka-welcome-modal/WakaWelcomeModal.stories.tsx +87 -0
  170. package/src/components/waka-xp-bar/WakaXPBar.stories.tsx +29 -29
  171. package/dist/useDataTableImport-D8R2HQl6.mjs +0 -229
  172. package/dist/useDataTableImport-S_hhA5Wo.js +0 -9
  173. package/src/components/DataTable/README.md +0 -446
@@ -0,0 +1,92 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import * as React from "react"
3
+ import { WakaTooltipTour, type TourStep } from "./index"
4
+
5
+ const meta: Meta<typeof WakaTooltipTour> = {
6
+ title: "Navigation/WakaTooltipTour",
7
+ component: WakaTooltipTour,
8
+ parameters: { layout: "padded" },
9
+ tags: ["autodocs"],
10
+ argTypes: {
11
+ isActive: { control: "boolean", description: "Tour actif" },
12
+ showSkip: { control: "boolean", description: "Afficher le bouton skip" },
13
+ showProgress: { control: "boolean", description: "Afficher la progression" },
14
+ showNavigation: { control: "boolean", description: "Afficher la navigation" },
15
+ },
16
+ }
17
+
18
+ export default meta
19
+ type Story = StoryObj<typeof WakaTooltipTour>
20
+
21
+ const steps: TourStep[] = [
22
+ {
23
+ id: "step-1",
24
+ target: "#tour-target-1",
25
+ title: "Navigation principale",
26
+ content: "Accédez rapidement aux sections clés.",
27
+ placement: "bottom",
28
+ highlight: true,
29
+ },
30
+ {
31
+ id: "step-2",
32
+ target: "#tour-target-2",
33
+ title: "Recherche",
34
+ content: "Trouvez des ressources avec la recherche.",
35
+ placement: "bottom",
36
+ highlight: true,
37
+ },
38
+ {
39
+ id: "step-3",
40
+ target: "#tour-target-3",
41
+ title: "Actions rapides",
42
+ content: "Lancez des actions en un clic.",
43
+ placement: "top",
44
+ highlight: true,
45
+ },
46
+ ]
47
+
48
+ const DemoLayout = () => (
49
+ <div className="tw-space-y-4">
50
+ <div className="tw-flex tw-gap-3">
51
+ <button id="tour-target-1" className="tw-px-3 tw-py-2 tw-rounded tw-bg-primary tw-text-primary-foreground">
52
+ Menu
53
+ </button>
54
+ <button id="tour-target-2" className="tw-px-3 tw-py-2 tw-rounded tw-bg-muted">
55
+ Recherche
56
+ </button>
57
+ <button id="tour-target-3" className="tw-px-3 tw-py-2 tw-rounded tw-bg-muted">
58
+ Actions
59
+ </button>
60
+ </div>
61
+ <div className="tw-p-4 tw-border tw-rounded-lg">
62
+ <p className="tw-text-sm tw-text-muted-foreground">Zone de contenu</p>
63
+ </div>
64
+ </div>
65
+ )
66
+
67
+ export const Default: Story = {
68
+ args: {
69
+ tourId: "storybook-tooltip-tour",
70
+ steps,
71
+ isActive: true,
72
+ showSkip: true,
73
+ showProgress: true,
74
+ showNavigation: true,
75
+ closeOnOverlayClick: true,
76
+ },
77
+ render: (args) => {
78
+ const [active, setActive] = React.useState(Boolean(args.isActive))
79
+
80
+ React.useEffect(() => {
81
+ setActive(Boolean(args.isActive))
82
+ }, [args.isActive])
83
+
84
+ return (
85
+ <div>
86
+ <DemoLayout />
87
+ <WakaTooltipTour {...args} isActive={active} onActiveChange={setActive} steps={steps} />
88
+ </div>
89
+ )
90
+ },
91
+ }
92
+
@@ -0,0 +1,89 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import * as React from "react"
3
+ import { WakaTourGuide, type TourStep } from "./index"
4
+
5
+ const meta: Meta<typeof WakaTourGuide> = {
6
+ title: "Navigation/WakaTourGuide",
7
+ component: WakaTourGuide,
8
+ parameters: { layout: "padded" },
9
+ tags: ["autodocs"],
10
+ argTypes: {
11
+ isOpen: { control: "boolean", description: "Tour ouvert" },
12
+ variant: { control: "select", options: ["modal", "tooltip"], description: "Variante" },
13
+ showSkip: { control: "boolean", description: "Afficher le bouton skip" },
14
+ showProgress: { control: "boolean", description: "Afficher la progression" },
15
+ showStepCounter: { control: "boolean", description: "Afficher le compteur" },
16
+ },
17
+ }
18
+
19
+ export default meta
20
+ type Story = StoryObj<typeof WakaTourGuide>
21
+
22
+ const steps: TourStep[] = [
23
+ {
24
+ id: "welcome",
25
+ target: "#guide-target-1",
26
+ title: "Bienvenue",
27
+ content: "Voici un tour rapide des fonctions principales.",
28
+ placement: "bottom",
29
+ },
30
+ {
31
+ id: "profile",
32
+ target: "#guide-target-2",
33
+ title: "Profil",
34
+ content: "Gérez vos préférences et votre compte.",
35
+ placement: "right",
36
+ },
37
+ {
38
+ id: "settings",
39
+ target: "#guide-target-3",
40
+ title: "Paramètres",
41
+ content: "Configurez votre application ici.",
42
+ placement: "left",
43
+ },
44
+ ]
45
+
46
+ const DemoLayout = () => (
47
+ <div className="tw-space-y-4">
48
+ <div className="tw-flex tw-gap-3">
49
+ <button id="guide-target-1" className="tw-px-3 tw-py-2 tw-rounded tw-bg-primary tw-text-primary-foreground">
50
+ Démarrer
51
+ </button>
52
+ <button id="guide-target-2" className="tw-px-3 tw-py-2 tw-rounded tw-bg-muted">
53
+ Profil
54
+ </button>
55
+ <button id="guide-target-3" className="tw-px-3 tw-py-2 tw-rounded tw-bg-muted">
56
+ Paramètres
57
+ </button>
58
+ </div>
59
+ <div className="tw-p-4 tw-border tw-rounded-lg">
60
+ <p className="tw-text-sm tw-text-muted-foreground">Zone de contenu</p>
61
+ </div>
62
+ </div>
63
+ )
64
+
65
+ export const Default: Story = {
66
+ args: {
67
+ steps,
68
+ isOpen: true,
69
+ variant: "modal",
70
+ showSkip: true,
71
+ showProgress: true,
72
+ showStepCounter: true,
73
+ },
74
+ render: (args) => {
75
+ const [open, setOpen] = React.useState(Boolean(args.isOpen))
76
+
77
+ React.useEffect(() => {
78
+ setOpen(Boolean(args.isOpen))
79
+ }, [args.isOpen])
80
+
81
+ return (
82
+ <div>
83
+ <DemoLayout />
84
+ <WakaTourGuide {...args} isOpen={open} onOpenChange={setOpen} steps={steps} />
85
+ </div>
86
+ )
87
+ },
88
+ }
89
+
@@ -3,104 +3,111 @@ import { WakaTreemapChart, useTreemapChart } from './index'
3
3
  import type { TreemapNode } from './index'
4
4
  import * as React from 'react'
5
5
 
6
- const diskUsageData: TreemapNode = {
7
- id: 'root',
8
- name: 'Disk Usage',
9
- children: [
10
- {
11
- id: 'documents',
12
- name: 'Documents',
13
- children: [
14
- { id: 'pdf', name: 'PDFs', value: 2500 },
15
- { id: 'word', name: 'Word Docs', value: 1800 },
16
- { id: 'spreadsheets', name: 'Spreadsheets', value: 1200 },
17
- ],
18
- },
19
- {
20
- id: 'media',
21
- name: 'Media',
22
- children: [
23
- { id: 'photos', name: 'Photos', value: 8000 },
24
- { id: 'videos', name: 'Videos', value: 15000 },
25
- { id: 'music', name: 'Music', value: 3500 },
26
- ],
27
- },
28
- {
29
- id: 'apps',
30
- name: 'Applications',
31
- children: [
32
- { id: 'system', name: 'System', value: 5000 },
33
- { id: 'user', name: 'User Apps', value: 7000 },
34
- ],
35
- },
36
- { id: 'other', name: 'Other', value: 2000 },
37
- ],
38
- }
6
+ // Données pour l'utilisation du disque - format tableau
7
+ const diskUsageData: TreemapNode[] = [
8
+ {
9
+ id: 'documents',
10
+ label: 'Documents',
11
+ value: 5500,
12
+ category: 'files',
13
+ children: [
14
+ { id: 'pdf', label: 'PDFs', value: 2500, category: 'files' },
15
+ { id: 'word', label: 'Word Docs', value: 1800, category: 'files' },
16
+ { id: 'spreadsheets', label: 'Spreadsheets', value: 1200, category: 'files' },
17
+ ],
18
+ },
19
+ {
20
+ id: 'media',
21
+ label: 'Media',
22
+ value: 26500,
23
+ category: 'media',
24
+ children: [
25
+ { id: 'photos', label: 'Photos', value: 8000, category: 'media' },
26
+ { id: 'videos', label: 'Videos', value: 15000, category: 'media' },
27
+ { id: 'music', label: 'Music', value: 3500, category: 'media' },
28
+ ],
29
+ },
30
+ {
31
+ id: 'apps',
32
+ label: 'Applications',
33
+ value: 12000,
34
+ category: 'apps',
35
+ children: [
36
+ { id: 'system', label: 'System', value: 5000, category: 'apps' },
37
+ { id: 'user', label: 'User Apps', value: 7000, category: 'apps' },
38
+ ],
39
+ },
40
+ { id: 'other', label: 'Other', value: 2000, category: 'other' },
41
+ ]
39
42
 
40
- const salesByCategoryData: TreemapNode = {
41
- id: 'sales',
42
- name: 'Sales',
43
- children: [
44
- {
45
- id: 'electronics',
46
- name: 'Electronics',
47
- color: '#3b82f6',
48
- children: [
49
- { id: 'phones', name: 'Phones', value: 45000 },
50
- { id: 'laptops', name: 'Laptops', value: 38000 },
51
- { id: 'tablets', name: 'Tablets', value: 22000 },
52
- { id: 'accessories', name: 'Accessories', value: 15000 },
53
- ],
54
- },
55
- {
56
- id: 'clothing',
57
- name: 'Clothing',
58
- color: '#22c55e',
59
- children: [
60
- { id: 'mens', name: "Men's", value: 28000 },
61
- { id: 'womens', name: "Women's", value: 35000 },
62
- { id: 'kids', name: 'Kids', value: 18000 },
63
- ],
64
- },
65
- {
66
- id: 'home',
67
- name: 'Home & Garden',
68
- color: '#f59e0b',
69
- children: [
70
- { id: 'furniture', name: 'Furniture', value: 32000 },
71
- { id: 'decor', name: 'Decor', value: 12000 },
72
- { id: 'garden', name: 'Garden', value: 8000 },
73
- ],
74
- },
75
- ],
76
- }
43
+ // Données de ventes par catégorie
44
+ const salesByCategoryData: TreemapNode[] = [
45
+ {
46
+ id: 'electronics',
47
+ label: 'Electronics',
48
+ value: 120000,
49
+ color: '#3b82f6',
50
+ category: 'electronics',
51
+ children: [
52
+ { id: 'phones', label: 'Phones', value: 45000, category: 'electronics' },
53
+ { id: 'laptops', label: 'Laptops', value: 38000, category: 'electronics' },
54
+ { id: 'tablets', label: 'Tablets', value: 22000, category: 'electronics' },
55
+ { id: 'accessories', label: 'Accessories', value: 15000, category: 'electronics' },
56
+ ],
57
+ },
58
+ {
59
+ id: 'clothing',
60
+ label: 'Clothing',
61
+ value: 81000,
62
+ color: '#22c55e',
63
+ category: 'clothing',
64
+ children: [
65
+ { id: 'mens', label: "Men's", value: 28000, category: 'clothing' },
66
+ { id: 'womens', label: "Women's", value: 35000, category: 'clothing' },
67
+ { id: 'kids', label: 'Kids', value: 18000, category: 'clothing' },
68
+ ],
69
+ },
70
+ {
71
+ id: 'home',
72
+ label: 'Home & Garden',
73
+ value: 52000,
74
+ color: '#f59e0b',
75
+ category: 'home',
76
+ children: [
77
+ { id: 'furniture', label: 'Furniture', value: 32000, category: 'home' },
78
+ { id: 'decor', label: 'Decor', value: 12000, category: 'home' },
79
+ { id: 'garden', label: 'Garden', value: 8000, category: 'home' },
80
+ ],
81
+ },
82
+ ]
77
83
 
78
- const portfolioData: TreemapNode = {
79
- id: 'portfolio',
80
- name: 'Investment Portfolio',
81
- children: [
82
- {
83
- id: 'stocks',
84
- name: 'Stocks',
85
- children: [
86
- { id: 'tech', name: 'Tech', value: 45000, color: '#3b82f6' },
87
- { id: 'healthcare', name: 'Healthcare', value: 25000, color: '#22c55e' },
88
- { id: 'finance', name: 'Finance', value: 20000, color: '#f59e0b' },
89
- { id: 'energy', name: 'Energy', value: 10000, color: '#ef4444' },
90
- ],
91
- },
92
- {
93
- id: 'bonds',
94
- name: 'Bonds',
95
- children: [
96
- { id: 'gov', name: 'Government', value: 30000, color: '#8b5cf6' },
97
- { id: 'corp', name: 'Corporate', value: 15000, color: '#ec4899' },
98
- ],
99
- },
100
- { id: 'cash', name: 'Cash', value: 20000, color: '#6b7280' },
101
- { id: 'crypto', name: 'Crypto', value: 5000, color: '#06b6d4' },
102
- ],
103
- }
84
+ // Données de portefeuille d'investissement
85
+ const portfolioData: TreemapNode[] = [
86
+ {
87
+ id: 'stocks',
88
+ label: 'Stocks',
89
+ value: 100000,
90
+ category: 'stocks',
91
+ children: [
92
+ { id: 'tech', label: 'Tech', value: 45000, color: '#3b82f6', category: 'stocks' },
93
+ { id: 'healthcare', label: 'Healthcare', value: 25000, color: '#22c55e', category: 'stocks' },
94
+ { id: 'finance', label: 'Finance', value: 20000, color: '#f59e0b', category: 'stocks' },
95
+ { id: 'energy', label: 'Energy', value: 10000, color: '#ef4444', category: 'stocks' },
96
+ ],
97
+ },
98
+ {
99
+ id: 'bonds',
100
+ label: 'Bonds',
101
+ value: 45000,
102
+ category: 'bonds',
103
+ children: [
104
+ { id: 'gov', label: 'Government', value: 30000, color: '#8b5cf6', category: 'bonds' },
105
+ { id: 'corp', label: 'Corporate', value: 15000, color: '#ec4899', category: 'bonds' },
106
+ ],
107
+ },
108
+ { id: 'cash', label: 'Cash', value: 20000, color: '#6b7280', category: 'cash' },
109
+ { id: 'crypto', label: 'Crypto', value: 5000, color: '#06b6d4', category: 'crypto' },
110
+ ]
104
111
 
105
112
  const meta: Meta<typeof WakaTreemapChart> = {
106
113
  title: 'Components/Charts/WakaTreemapChart',
@@ -117,9 +124,14 @@ const meta: Meta<typeof WakaTreemapChart> = {
117
124
  argTypes: {
118
125
  colorScheme: {
119
126
  control: 'select',
120
- options: ['blues', 'greens', 'purples', 'oranges', 'category'],
127
+ options: ['default', 'cool', 'warm', 'neon', 'pastel'],
121
128
  description: 'Color scheme for nodes',
122
129
  },
130
+ colorBy: {
131
+ control: 'select',
132
+ options: ['category', 'value'],
133
+ description: 'How to assign colors',
134
+ },
123
135
  showLabels: {
124
136
  control: 'boolean',
125
137
  description: 'Show node labels',
@@ -132,9 +144,13 @@ const meta: Meta<typeof WakaTreemapChart> = {
132
144
  control: 'boolean',
133
145
  description: 'Enable drill-down on click',
134
146
  },
135
- animated: {
147
+ showLegend: {
136
148
  control: 'boolean',
137
- description: 'Enable animations',
149
+ description: 'Show legend',
150
+ },
151
+ animationDuration: {
152
+ control: { type: 'range', min: 0, max: 1000, step: 50 },
153
+ description: 'Animation duration in ms',
138
154
  },
139
155
  padding: {
140
156
  control: { type: 'range', min: 0, max: 8, step: 1 },
@@ -156,24 +172,41 @@ export const Default: Story = {
156
172
  }
157
173
 
158
174
  export const WithCustomColors: Story = {
159
- render: () => <WakaTreemapChart data={salesByCategoryData} width={600} height={400} colorScheme="category" />,
175
+ render: () => <WakaTreemapChart data={salesByCategoryData} width={600} height={400} colorBy="category" />,
160
176
  }
161
177
 
162
178
  export const ColorSchemes: Story = {
163
179
  render: () => (
164
180
  <div className="space-y-6">
165
181
  <div>
166
- <p className="text-sm text-muted-foreground mb-2">Blues</p>
167
- <WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="blues" />
182
+ <p className="text-sm text-muted-foreground mb-2">Default</p>
183
+ <WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="default" />
184
+ </div>
185
+ <div>
186
+ <p className="text-sm text-muted-foreground mb-2">Cool</p>
187
+ <WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="cool" />
168
188
  </div>
169
189
  <div>
170
- <p className="text-sm text-muted-foreground mb-2">Greens</p>
171
- <WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="greens" />
190
+ <p className="text-sm text-muted-foreground mb-2">Warm</p>
191
+ <WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="warm" />
172
192
  </div>
173
193
  <div>
174
- <p className="text-sm text-muted-foreground mb-2">Purples</p>
175
- <WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="purples" />
194
+ <p className="text-sm text-muted-foreground mb-2">Neon</p>
195
+ <WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="neon" />
176
196
  </div>
197
+ <div>
198
+ <p className="text-sm text-muted-foreground mb-2">Pastel</p>
199
+ <WakaTreemapChart data={diskUsageData} width={500} height={250} colorScheme="pastel" />
200
+ </div>
201
+ </div>
202
+ ),
203
+ }
204
+
205
+ export const ColorByValue: Story = {
206
+ render: () => (
207
+ <div className="space-y-4">
208
+ <p className="text-sm text-muted-foreground">Colors are based on value (gradient from blue to red)</p>
209
+ <WakaTreemapChart data={portfolioData} width={600} height={350} colorBy="value" showLegend={false} />
177
210
  </div>
178
211
  ),
179
212
  }
@@ -187,7 +220,8 @@ export const DrillDown: Story = {
187
220
  width={650}
188
221
  height={400}
189
222
  enableDrillDown
190
- colorScheme="category"
223
+ showBreadcrumb
224
+ colorScheme="default"
191
225
  />
192
226
  </div>
193
227
  ),
@@ -252,12 +286,12 @@ export const Interactive: Story = {
252
286
  data={portfolioData}
253
287
  width={600}
254
288
  height={350}
255
- colorScheme="category"
289
+ colorScheme="default"
256
290
  onNodeClick={(node) => setSelected(node)}
257
291
  />
258
292
  {selected && (
259
293
  <div className="p-4 border rounded-lg bg-muted/50">
260
- <h4 className="font-semibold">{selected.name}</h4>
294
+ <h4 className="font-semibold">{selected.label}</h4>
261
295
  {selected.value && (
262
296
  <p className="text-2xl font-bold text-primary">
263
297
  ${selected.value.toLocaleString()}
@@ -277,47 +311,79 @@ export const Interactive: Story = {
277
311
 
278
312
  export const WithHook: Story = {
279
313
  render: () => {
280
- const { currentNode, breadcrumbs, drillDown, drillUp, reset, getTotalValue } = useTreemapChart(diskUsageData)
314
+ const [rootId, setRootId] = React.useState<string | null>(null)
315
+ const [path, setPath] = React.useState<TreemapNode[]>([])
316
+
317
+ const { computeLayout, getTotalValue, findNode, getPathToNode } = useTreemapChart({
318
+ width: 600,
319
+ height: 350,
320
+ })
321
+
322
+ const handleNodeClick = (node: TreemapNode) => {
323
+ if (node.children && node.children.length > 0) {
324
+ setRootId(node.id)
325
+ const newPath = getPathToNode(diskUsageData, node.id)
326
+ setPath(newPath)
327
+ }
328
+ }
329
+
330
+ const handleReset = () => {
331
+ setRootId(null)
332
+ setPath([])
333
+ }
334
+
335
+ const handleBack = () => {
336
+ if (path.length > 1) {
337
+ const parentId = path[path.length - 2].id
338
+ setRootId(parentId)
339
+ setPath(path.slice(0, -1))
340
+ } else {
341
+ handleReset()
342
+ }
343
+ }
344
+
345
+ const currentData = rootId ? (findNode(diskUsageData, rootId)?.children || diskUsageData) : diskUsageData
281
346
 
282
347
  return (
283
348
  <div className="space-y-4">
284
349
  <div className="flex items-center gap-2">
285
- {breadcrumbs.map((crumb, index) => (
350
+ <button
351
+ onClick={handleReset}
352
+ className="text-sm hover:underline"
353
+ >
354
+ Root
355
+ </button>
356
+ {path.map((crumb, index) => (
286
357
  <React.Fragment key={crumb.id}>
287
- {index > 0 && <span className="text-muted-foreground">/</span>}
288
- <button
289
- onClick={() => drillDown(crumb)}
290
- className="text-sm hover:underline"
291
- >
292
- {crumb.name}
293
- </button>
358
+ <span className="text-muted-foreground">/</span>
359
+ <span className="text-sm">{crumb.label}</span>
294
360
  </React.Fragment>
295
361
  ))}
296
362
  </div>
297
363
  <div className="flex gap-2">
298
364
  <button
299
- onClick={drillUp}
300
- disabled={breadcrumbs.length <= 1}
365
+ onClick={handleBack}
366
+ disabled={path.length === 0}
301
367
  className="px-3 py-1 text-sm border rounded hover:bg-muted disabled:opacity-50"
302
368
  >
303
369
  Back
304
370
  </button>
305
371
  <button
306
- onClick={reset}
372
+ onClick={handleReset}
307
373
  className="px-3 py-1 text-sm border rounded hover:bg-muted"
308
374
  >
309
375
  Reset
310
376
  </button>
311
377
  <span className="px-3 py-1 text-sm bg-muted rounded">
312
- Total: {getTotalValue(currentNode).toLocaleString()} MB
378
+ Total: {getTotalValue(currentData).toLocaleString()} MB
313
379
  </span>
314
380
  </div>
315
381
  <WakaTreemapChart
316
- data={currentNode}
382
+ data={currentData}
317
383
  width={600}
318
384
  height={350}
319
385
  enableDrillDown={false}
320
- onNodeClick={(node) => node.children && drillDown(node)}
386
+ onNodeClick={handleNodeClick}
321
387
  />
322
388
  </div>
323
389
  )
@@ -341,9 +407,9 @@ export const PortfolioDashboard: Story = {
341
407
  data={portfolioData}
342
408
  width={650}
343
409
  height={400}
344
- colorScheme="category"
410
+ colorScheme="default"
345
411
  enableDrillDown
346
- valueFormatter={(v) => `$${(v / 1000).toFixed(0)}K`}
412
+ showBreadcrumb
347
413
  />
348
414
  </div>
349
415
  ),
@@ -365,14 +431,53 @@ export const DiskUsageDashboard: Story = {
365
431
  data={diskUsageData}
366
432
  width={650}
367
433
  height={380}
368
- colorScheme="blues"
434
+ colorScheme="cool"
369
435
  enableDrillDown
370
- valueFormatter={(v) => `${(v / 1000).toFixed(1)} GB`}
436
+ showBreadcrumb
371
437
  />
372
438
  </div>
373
439
  ),
374
440
  }
375
441
 
376
442
  export const NoAnimation: Story = {
377
- render: () => <WakaTreemapChart data={diskUsageData} width={500} height={300} animated={false} />,
443
+ render: () => <WakaTreemapChart data={diskUsageData} width={500} height={300} animationDuration={0} />,
444
+ }
445
+
446
+ export const WithLegend: Story = {
447
+ render: () => (
448
+ <div className="space-y-6">
449
+ <div>
450
+ <p className="text-sm text-muted-foreground mb-2">Legend on the right</p>
451
+ <WakaTreemapChart
452
+ data={salesByCategoryData}
453
+ width={600}
454
+ height={350}
455
+ showLegend
456
+ legendPosition="right"
457
+ />
458
+ </div>
459
+ <div>
460
+ <p className="text-sm text-muted-foreground mb-2">Legend at the bottom</p>
461
+ <WakaTreemapChart
462
+ data={salesByCategoryData}
463
+ width={600}
464
+ height={350}
465
+ showLegend
466
+ legendPosition="bottom"
467
+ />
468
+ </div>
469
+ </div>
470
+ ),
471
+ }
472
+
473
+ export const WithZoomControls: Story = {
474
+ render: () => (
475
+ <WakaTreemapChart
476
+ data={portfolioData}
477
+ width={600}
478
+ height={400}
479
+ showZoomControls
480
+ enableZoomToFit
481
+ />
482
+ ),
378
483
  }
@@ -663,7 +663,7 @@ interface TreemapRectangleProps {
663
663
  minLabelSize: number
664
664
  animationDuration: number
665
665
  onClick: () => void
666
- onMouseEnter: () => void
666
+ onMouseEnter: (e: React.MouseEvent<SVGGElement>) => void
667
667
  onMouseLeave: () => void
668
668
  }
669
669
 
@@ -989,7 +989,7 @@ export function WakaTreemapChart({
989
989
  minLabelSize={minLabelSize}
990
990
  animationDuration={animationDuration}
991
991
  onClick={() => handleNodeClick(node)}
992
- onMouseEnter={(e: any) => handleMouseEnter(node, e)}
992
+ onMouseEnter={(e: React.MouseEvent<SVGGElement>) => handleMouseEnter(node, e)}
993
993
  onMouseLeave={handleMouseLeave}
994
994
  />
995
995
  )