@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.
- package/dist/blocks/antivirus-dashboard/index.d.ts +44 -0
- package/dist/blocks/clamav-service-status/index.d.ts +35 -0
- package/dist/blocks/file-scan-uploader/index.d.ts +29 -0
- package/dist/blocks/index.d.ts +18 -9
- package/dist/blocks/quarantine-manager/index.d.ts +27 -0
- package/dist/blocks/scan-history-log/index.d.ts +28 -0
- package/dist/blocks/scan-policy-editor/index.d.ts +27 -0
- package/dist/blocks/scan-report-generator/index.d.ts +47 -0
- package/dist/blocks/signature-database-manager/index.d.ts +39 -0
- package/dist/blocks/threat-alert-banner/index.d.ts +26 -0
- package/dist/components/index.d.ts +4 -4
- package/dist/components/waka-signature-pad/index.d.ts +1 -1
- package/dist/exceljs.min-BcLLX0PC.js +29 -0
- package/dist/exceljs.min-KOayaaQ4.mjs +23013 -0
- package/dist/export.cjs.js +1 -1
- package/dist/export.d.ts +2 -2
- package/dist/export.es.js +1 -1
- package/dist/index.cjs.js +136 -136
- package/dist/index.es.js +29978 -27215
- package/dist/stories/Button.stories.d.ts +1 -1
- package/dist/stories/Header.stories.d.ts +1 -1
- package/dist/stories/Page.stories.d.ts +1 -1
- package/dist/useDataTableImport-COVnvslz.js +9 -0
- package/dist/useDataTableImport-DAlxBY8w.mjs +237 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/logger.d.ts +9 -0
- package/package.json +6 -5
- package/src/blocks/antivirus-dashboard/AntivirusDashboard.stories.tsx +291 -0
- package/src/blocks/antivirus-dashboard/index.tsx +525 -0
- package/src/blocks/clamav-service-status/ClamAVServiceStatus.stories.tsx +195 -0
- package/src/blocks/clamav-service-status/index.tsx +370 -0
- package/src/blocks/file-scan-uploader/FileScanUploader.stories.tsx +257 -0
- package/src/blocks/file-scan-uploader/index.tsx +311 -0
- package/src/blocks/index.ts +163 -11
- package/src/blocks/quarantine-manager/QuarantineManager.stories.tsx +209 -0
- package/src/blocks/quarantine-manager/index.tsx +435 -0
- package/src/blocks/scan-history-log/ScanHistoryLog.stories.tsx +231 -0
- package/src/blocks/scan-history-log/index.tsx +406 -0
- package/src/blocks/scan-policy-editor/ScanPolicyEditor.stories.tsx +106 -0
- package/src/blocks/scan-policy-editor/index.tsx +418 -0
- package/src/blocks/scan-report-generator/ScanReportGenerator.stories.tsx +232 -0
- package/src/blocks/scan-report-generator/index.tsx +612 -0
- package/src/blocks/sidebar/index.tsx +2 -1
- package/src/blocks/signature-database-manager/SignatureDatabaseManager.stories.tsx +279 -0
- package/src/blocks/signature-database-manager/index.tsx +470 -0
- package/src/blocks/theme-creator-block/index.tsx +16 -2
- package/src/blocks/threat-alert-banner/ThreatAlertBanner.stories.tsx +152 -0
- package/src/blocks/threat-alert-banner/index.tsx +320 -0
- package/src/components/DataTable/DataTable.stories.tsx +203 -0
- package/src/components/DataTable/hooks/useDataTableExport.ts +38 -31
- package/src/components/DataTable/hooks/useDataTableImport.ts +31 -20
- package/src/components/error-boundary/ErrorBoundary.stories.tsx +125 -0
- package/src/components/index.ts +45 -4
- package/src/components/language-selector/LanguageSelector.stories.tsx +112 -0
- package/src/components/theme-selector/ThemeSelector.stories.tsx +77 -0
- package/src/components/toaster/Toaster.stories.tsx +67 -0
- package/src/components/waka-activity-feed/WakaActivityFeed.stories.tsx +116 -0
- package/src/components/waka-ad-banner/WakaAdBanner.stories.tsx +102 -0
- package/src/components/waka-ad-fallback/WakaAdFallback.stories.tsx +117 -0
- package/src/components/waka-ad-inline/WakaAdInline.stories.tsx +105 -0
- package/src/components/waka-ad-interstitial/WakaAdInterstitial.stories.tsx +92 -0
- package/src/components/waka-ad-placeholder/WakaAdPlaceholder.stories.tsx +89 -0
- package/src/components/waka-ad-provider/WakaAdProvider.stories.tsx +110 -0
- package/src/components/waka-ad-sidebar/WakaAdSidebar.stories.tsx +89 -0
- package/src/components/waka-ad-sidebar/index.tsx +3 -2
- package/src/components/waka-ad-sticky-footer/WakaAdStickyFooter.stories.tsx +88 -0
- package/src/components/waka-address-autocomplete/WakaAddressAutocomplete.stories.tsx +46 -0
- package/src/components/waka-admincrumb/WakaAdmincrumb.stories.tsx +166 -0
- package/src/components/waka-alert-panel/WakaAlertPanel.stories.tsx +45 -0
- package/src/components/waka-alert-stack/WakaAlertStack.stories.tsx +62 -0
- package/src/components/waka-allocation-matrix/WakaAllocationMatrix.stories.tsx +68 -0
- package/src/components/waka-approval-chain/WakaApprovalChain.stories.tsx +63 -0
- package/src/components/waka-audit-log/WakaAuditLog.stories.tsx +73 -0
- package/src/components/waka-autocomplete/WakaAutocomplete.stories.tsx +132 -172
- package/src/components/waka-biometric-prompt/WakaBiometricPrompt.stories.tsx +48 -0
- package/src/components/waka-breadcrumb/WakaBreadcrumb.stories.tsx +74 -191
- package/src/components/waka-breadcrumb-path/WakaBreadcrumbPath.stories.tsx +40 -0
- package/src/components/waka-budget-burn/WakaBudgetBurn.stories.tsx +86 -0
- package/src/components/waka-capacity-planner/WakaCapacityPlanner.stories.tsx +273 -0
- package/src/components/waka-cart-summary/WakaCartSummary.stories.tsx +176 -0
- package/src/components/waka-cart-summary/index.tsx +19 -10
- package/src/components/waka-challenge-timer/WakaChallengeTimer.stories.tsx +98 -0
- package/src/components/waka-chat-bubble/WakaChatBubble.stories.tsx +118 -0
- package/src/components/waka-checklist/WakaChecklist.stories.tsx +71 -0
- package/src/components/waka-checkout-stepper/WakaCheckoutStepper.stories.tsx +102 -0
- package/src/components/waka-cohort-table/WakaCohortTable.stories.tsx +56 -0
- package/src/components/waka-color-picker/WakaColorPicker.stories.tsx +99 -155
- package/src/components/waka-combo-counter/WakaComboCounter.stories.tsx +128 -0
- package/src/components/waka-command-bar/WakaCommandBar.stories.tsx +45 -0
- package/src/components/waka-compare-period/WakaComparePeriod.stories.tsx +76 -0
- package/src/components/waka-config-comparator/WakaConfigComparator.stories.tsx +143 -0
- package/src/components/waka-connection-matrix/WakaConnectionMatrix.stories.tsx +52 -0
- package/src/components/waka-content-recommendation/WakaContentRecommendation.stories.tsx +41 -0
- package/src/components/waka-coupon-input/WakaCouponInput.stories.tsx +126 -0
- package/src/components/waka-credit-card-input/WakaCreditCardInput.stories.tsx +120 -0
- package/src/components/waka-datetime-picker.form-integration/WakaDateTimePickerForm.stories.tsx +79 -0
- package/src/components/waka-dependency-tree/WakaDependencyTree.stories.tsx +72 -0
- package/src/components/waka-device-trust/WakaDeviceTrust.stories.tsx +109 -0
- package/src/components/waka-empty-state/WakaEmptyState.stories.tsx +87 -0
- package/src/components/waka-feature-announcement/WakaFeatureAnnouncement.stories.tsx +47 -0
- package/src/components/waka-feature-flag-row/WakaFeatureFlagRow.stories.tsx +188 -0
- package/src/components/waka-file-upload/WakaFileUpload.stories.tsx +118 -174
- package/src/components/waka-floating-nav/WakaFloatingNav.stories.tsx +53 -0
- package/src/components/waka-goal-progress/WakaGoalProgress.stories.tsx +137 -0
- package/src/components/waka-hotspot/WakaHotspot.stories.tsx +56 -0
- package/src/components/waka-invoice-preview/WakaInvoicePreview.stories.tsx +169 -0
- package/src/components/waka-kpi-dashboard/WakaKpiDashboard.stories.tsx +46 -0
- package/src/components/waka-level-progress/WakaLevelProgress.stories.tsx +94 -75
- package/src/components/waka-liquid-button/WakaLiquidButton.stories.tsx +45 -0
- package/src/components/waka-magic-link/WakaMagicLink.stories.tsx +61 -0
- package/src/components/waka-magnetic-button/WakaMagneticButton.stories.tsx +40 -0
- package/src/components/waka-mention-input/WakaMentionInput.stories.tsx +140 -0
- package/src/components/waka-milestone-road/WakaMilestoneRoad.stories.tsx +143 -0
- package/src/components/waka-orbital-menu/WakaOrbitalMenu.stories.tsx +54 -0
- package/src/components/waka-order-tracker/WakaOrderTracker.stories.tsx +163 -0
- package/src/components/waka-outstream-video/WakaOutstreamVideo.stories.tsx +94 -0
- package/src/components/waka-pagination/WakaPagination.stories.tsx +110 -280
- package/src/components/waka-password-strength/WakaPasswordStrength.stories.tsx +132 -268
- package/src/components/waka-payment-method-picker/WakaPaymentMethodPicker.stories.tsx +141 -0
- package/src/components/waka-permission-matrix/WakaPermissionMatrix.stories.tsx +124 -0
- package/src/components/waka-phone-input/WakaPhoneInput.stories.tsx +56 -0
- package/src/components/waka-points-popup/WakaPointsPopup.stories.tsx +96 -0
- package/src/components/waka-power-up/WakaPowerUp.stories.tsx +121 -0
- package/src/components/waka-presence-indicator/WakaPresenceIndicator.stories.tsx +49 -0
- package/src/components/waka-pricing-table/WakaPricingTable.stories.tsx +159 -0
- package/src/components/waka-product-card/WakaProductCard.stories.tsx +202 -0
- package/src/components/waka-progress-onboarding/WakaProgressOnboarding.stories.tsx +57 -0
- package/src/components/waka-pull-to-refresh/WakaPullToRefresh.stories.tsx +51 -0
- package/src/components/waka-rank-badge/WakaRankBadge.stories.tsx +108 -0
- package/src/components/waka-rating-input/WakaRatingInput.stories.tsx +51 -0
- package/src/components/waka-reaction-picker/WakaReactionPicker.stories.tsx +52 -0
- package/src/components/waka-region-map/WakaRegionMap.stories.tsx +181 -0
- package/src/components/waka-resource-pool/WakaResourcePool.stories.tsx +70 -0
- package/src/components/waka-rich-text-editor/WakaRichTextEditor.stories.tsx +108 -197
- package/src/components/waka-rollback-slider/WakaRollbackSlider.stories.tsx +41 -0
- package/src/components/waka-schedule-picker/WakaSchedulePicker.stories.tsx +64 -0
- package/src/components/waka-season-pass/WakaSeasonPass.stories.tsx +107 -0
- package/src/components/waka-security-scan-result/WakaSecurityScanResult.stories.tsx +146 -0
- package/src/components/waka-security-score/WakaSecurityScore.stories.tsx +63 -0
- package/src/components/waka-session-manager/WakaSessionManager.stories.tsx +68 -0
- package/src/components/waka-signature-pad/WakaSignaturePad.stories.tsx +159 -0
- package/src/components/waka-signature-pad/index.tsx +5 -3
- package/src/components/waka-sla-tracker/WakaSlaTracker.stories.tsx +65 -0
- package/src/components/waka-slider-range/WakaSliderRange.stories.tsx +66 -0
- package/src/components/waka-sponsored-badge/WakaSponsoredBadge.stories.tsx +60 -0
- package/src/components/waka-sponsored-card/WakaSponsoredCard.stories.tsx +64 -0
- package/src/components/waka-sponsored-feed/WakaSponsoredFeed.stories.tsx +58 -0
- package/src/components/waka-spotlight/WakaSpotlight.stories.tsx +53 -0
- package/src/components/waka-stats-hexagon/WakaStatsHexagon.stories.tsx +161 -0
- package/src/components/waka-stepper/WakaStepper.stories.tsx +137 -410
- package/src/components/waka-swipe-card/WakaSwipeCard.stories.tsx +51 -0
- package/src/components/waka-tag-input/WakaTagInput.stories.tsx +224 -0
- package/src/components/waka-team-banner/WakaTeamBanner.stories.tsx +50 -0
- package/src/components/waka-theme-creator/WakaThemeCreator.stories.tsx +58 -0
- package/src/components/waka-theme-manager/WakaThemeManager.stories.tsx +298 -0
- package/src/components/waka-theme-manager/index.tsx +6 -11
- package/src/components/waka-thread-view/WakaThreadView.stories.tsx +143 -0
- package/src/components/waka-timeline/WakaTimeline.stories.tsx +171 -324
- package/src/components/waka-tooltip-tour/WakaTooltipTour.stories.tsx +92 -0
- package/src/components/waka-tour-guide/WakaTourGuide.stories.tsx +89 -0
- package/src/components/waka-treemap-chart/WakaTreemapChart.stories.tsx +234 -129
- package/src/components/waka-treemap-chart/index.tsx +2 -2
- package/src/components/waka-two-factor-setup/WakaTwoFactorSetup.stories.tsx +142 -0
- package/src/components/waka-typing-indicator/WakaTypingIndicator.stories.tsx +134 -0
- package/src/components/waka-video-ad/WakaVideoAd.stories.tsx +138 -0
- package/src/components/waka-video-call/WakaVideoCall.stories.tsx +186 -0
- package/src/components/waka-video-overlay/WakaVideoOverlay.stories.tsx +100 -0
- package/src/components/waka-voice-message/WakaVoiceMessage.stories.tsx +190 -0
- package/src/components/waka-welcome-modal/WakaWelcomeModal.stories.tsx +87 -0
- package/src/components/waka-xp-bar/WakaXPBar.stories.tsx +29 -29
- package/dist/useDataTableImport-D8R2HQl6.mjs +0 -229
- package/dist/useDataTableImport-S_hhA5Wo.js +0 -9
- package/src/components/DataTable/README.md +0 -446
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";var j=Object.create;var C=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var K=Object.getPrototypeOf,F=Object.prototype.hasOwnProperty;var O=(f,n,w,l)=>{if(n&&typeof n=="object"||typeof n=="function")for(let h of X(n))!F.call(f,h)&&h!==w&&C(f,h,{get:()=>n[h],enumerable:!(l=D(n,h))||l.enumerable});return f};var g=(f,n,w)=>(w=f!=null?j(K(f)):{},O(n||!f||!f.__esModule?C(w,"default",{value:f,enumerable:!0}):w,f));const d=require("react");function R({data:f,columns:n,exportConfig:w}){const l=d.useMemo(()=>({formats:["csv","xlsx","json"],filename:"export",includeHeaders:!0,...w}),[w]),h=d.useCallback((e,s)=>{if(!e.length)return;const r=n.filter(a=>a.accessorKey||a.id).map(a=>a.header||a.accessorKey||a.id).join(","),c=e.map(a=>n.filter(o=>o.accessorKey||o.id).map(o=>{const m=o.accessorKey?a[o.accessorKey]:a[o.id],E=o.formatter?o.formatter(m):m,L=String(E||"");return L.includes(",")||L.includes('"')||L.includes(`
|
|
2
|
-
`)?`"${L.replace(/"/g,'""')}"`:L}).join(",")),t=[r,...c].join(`
|
|
3
|
-
`),u=new Blob([t],{type:"text/csv;charset=utf-8;"}),p=document.createElement("a");p.href=URL.createObjectURL(u),p.download=`${s||l.filename}.csv`,p.click(),URL.revokeObjectURL(p.href)},[n,l.filename]),x=d.useCallback((e,s)=>{const r=JSON.stringify(e,null,2),c=new Blob([r],{type:"application/json"}),t=document.createElement("a");t.href=URL.createObjectURL(c),t.download=`${s||l.filename}.json`,t.click(),URL.revokeObjectURL(t.href)},[l.filename]),k=d.useCallback(async(e,s)=>{try{if(typeof window>"u")throw new Error("XLSX export not available in server environment");const r=await import("xlsx"),t=[n.filter(a=>a.accessorKey||a.id).map(a=>a.header||a.accessorKey||a.id),...e.map(a=>n.filter(o=>o.accessorKey||o.id).map(o=>{const m=o.accessorKey?a[o.accessorKey]:a[o.id];return o.formatter?o.formatter(m):m}))],u=r.utils.aoa_to_sheet(t),p=r.utils.book_new();r.utils.book_append_sheet(p,u,"Sheet1"),r.writeFile(p,`${s||l.filename}.xlsx`)}catch(r){throw console.error("Erreur lors de l'export XLSX:",r),new Error("La librairie xlsx n'est pas disponible")}},[n,l.filename]),v=d.useCallback(async(e,s)=>{try{if(typeof window>"u")throw new Error("PDF export not available in server environment");const r=await import("jspdf"),c=await import("jspdf-autotable"),t=new r.default,u=n.filter(a=>a.accessorKey||a.id).map(a=>a.header||a.accessorKey||a.id),p=e.map(a=>n.filter(o=>o.accessorKey||o.id).map(o=>{const m=o.accessorKey?a[o.accessorKey]:a[o.id];return o.formatter?o.formatter(m):m}));t.autoTable({head:[u],body:p,startY:20,styles:{fontSize:8},headStyles:{fillColor:[66,139,202]}}),t.save(`${s||l.filename}.pdf`)}catch(r){throw console.error("Erreur lors de l'export PDF:",r),new Error("Les librairies jsPDF et jspdf-autotable ne sont pas disponibles")}},[n,l.filename]),y=d.useCallback((e,s)=>{const r=n.filter(p=>p.accessorKey||p.id).map(p=>p.accessorKey||p.id);let c=`<?xml version="1.0" encoding="UTF-8"?>
|
|
4
|
-
<data>
|
|
5
|
-
`;e.forEach((p,a)=>{c+=` <row id="${a}">
|
|
6
|
-
`,r.forEach(o=>{const m=p[o],E=String(m||"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");c+=` <${o}>${E}</${o}>
|
|
7
|
-
`}),c+=` </row>
|
|
8
|
-
`}),c+="</data>";const t=new Blob([c],{type:"application/xml"}),u=document.createElement("a");u.href=URL.createObjectURL(t),u.download=`${s||l.filename}.xml`,u.click(),URL.revokeObjectURL(u.href)},[n,l.filename]),b=d.useCallback(async(e,s,r)=>{const c=s||f,t=r||l.filename;if(l.onExport){l.onExport(c,e);return}switch(e.toLowerCase()){case"csv":h(c,t);break;case"json":x(c,t);break;case"xlsx":await k(c,t);break;case"pdf":await v(c,t);break;case"xml":y(c,t);break;default:throw new Error(`Format d'export non supporté: ${e}`)}},[f,l,h,x,k,v,y]),S=d.useCallback(async e=>b(e),[b]),i=d.useCallback(async(e,s)=>b(e,s),[b]);return{exportData:b,exportAll:S,exportSelected:i,supportedFormats:l.formats,isExportSupported:e=>l.formats.includes(e)}}function U({importConfig:f}){const n=d.useMemo(()=>({accept:".csv,.xlsx,.json,.xml",...f}),[f]),w=d.useCallback((i,e=",")=>{const s=i.split(`
|
|
9
|
-
`).filter(t=>t.trim());if(s.length===0)return[];const r=s[0].split(e).map(t=>t.trim().replace(/"/g,""));return s.slice(1).map(t=>{const u=t.split(e).map(a=>a.trim().replace(/"/g,"")),p={};return r.forEach((a,o)=>{p[a]=u[o]||""}),p})},[]),l=d.useCallback(i=>{try{const e=JSON.parse(i);return Array.isArray(e)?e:[e]}catch{throw new Error("Format JSON invalide")}},[]),h=d.useCallback(i=>{try{const r=new DOMParser().parseFromString(i,"text/xml").querySelectorAll("row");return Array.from(r).map(c=>{const t={};return Array.from(c.children).forEach(u=>{t[u.tagName]=u.textContent||""}),t})}catch{throw new Error("Format XML invalide")}},[]),x=d.useCallback(async i=>{try{if(typeof window>"u")throw new Error("XLSX parsing not available in server environment");const e=await import("xlsx"),s=await i.arrayBuffer(),r=e.read(s,{type:"array"}),c=r.SheetNames[0],t=r.Sheets[c],u=e.utils.sheet_to_json(t,{header:1});if(u.length===0)return[];const p=u[0];return u.slice(1).map(a=>{const o={};return p.forEach((m,E)=>{o[m]=a[E]||""}),o})}catch{throw new Error("Erreur lors du parsing du fichier XLSX")}},[]),k=d.useCallback(i=>n.validate?n.validate(i):Array.isArray(i)?i.length===0?{valid:!1,errors:["Aucune donnée trouvée"]}:{valid:!0,errors:[]}:{valid:!1,errors:["Les données doivent être un tableau"]},[n.validate]),v=d.useCallback(i=>n.columnMapping?i.map(e=>{const s={};return Object.entries(n.columnMapping).forEach(([r,c])=>{e[r]!==void 0&&(s[c]=e[r])}),s}):i,[n.columnMapping]),y=d.useCallback(async i=>{const e=i.name.split(".").pop()?.toLowerCase();let s=[];try{const r=await i.text();switch(e){case"csv":s=w(r,n.parseOptions?.csv?.delimiter);break;case"json":s=l(r);break;case"xml":s=h(r);break;case"xlsx":s=await x(i);break;default:throw new Error(`Format de fichier non supporté: ${e}`)}const c=k(s);if(!c.valid)throw new Error(`Données invalides: ${c.errors.join(", ")}`);const t=v(s);return n.onImport&&n.onImport(t),t}catch(r){throw new Error(`Erreur lors de l'import: ${r instanceof Error?r.message:"Erreur inconnue"}`)}},[n,w,l,h,x,k,v]),b=d.useCallback(()=>{const i=document.createElement("input");return i.type="file",i.accept=n.accept,i.multiple=!1,i},[n.accept]),S=d.useCallback(()=>new Promise((i,e)=>{const s=b();s.onchange=async r=>{const c=r.target.files?.[0];if(!c){e(new Error("Aucun fichier sélectionné"));return}try{const t=await y(c);i(t)}catch(t){e(t)}},s.click()}),[b,y]);return{importData:y,importWithUI:S,supportedFormats:n.accept?.split(",")||[],isFormatSupported:i=>{const e=i.split(".").pop()?.toLowerCase();return n.accept?.includes(e||"")||!1}}}exports.useDataTableExport=R;exports.useDataTableImport=U;
|
|
@@ -1,446 +0,0 @@
|
|
|
1
|
-
# 📊 DataTable
|
|
2
|
-
|
|
3
|
-
Composant de table de données ultra-complet basé sur **TanStack Table v8**, totalement configurable et typé.
|
|
4
|
-
|
|
5
|
-
## ✨ Fonctionnalités
|
|
6
|
-
|
|
7
|
-
- ✅ **Tri multi-colonnes** (client & serveur)
|
|
8
|
-
- ✅ **Filtrage global et par colonne**
|
|
9
|
-
- ✅ **Pagination** (client & serveur)
|
|
10
|
-
- ✅ **Sélection multiple** avec checkbox
|
|
11
|
-
- ✅ **Export** (CSV, JSON)
|
|
12
|
-
- ✅ **Import** (CSV)
|
|
13
|
-
- ✅ **Layouts multiples** (standard, card, compact, split, infinite)
|
|
14
|
-
- ✅ **Variants visuels** (bordered, minimal, striped, glass)
|
|
15
|
-
- ✅ **Densité ajustable** (comfortable, compact)
|
|
16
|
-
- ✅ **Toolbar personnalisable** avec actions
|
|
17
|
-
- ✅ **Virtualisation** pour grandes données
|
|
18
|
-
- ✅ **Thème clair/sombre** via TweakCN
|
|
19
|
-
- ✅ **i18n** complet
|
|
20
|
-
- ✅ **Responsive** (mobile-first)
|
|
21
|
-
- ✅ **Accessibilité** (a11y)
|
|
22
|
-
- ✅ **TypeScript** 100%
|
|
23
|
-
|
|
24
|
-
## 📦 Installation
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
pnpm add @wakastart/ui @tanstack/react-table
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## 🚀 Utilisation de base
|
|
31
|
-
|
|
32
|
-
```tsx
|
|
33
|
-
import { DataTable } from "@wakastart/ui"
|
|
34
|
-
import { ColumnDef } from "@tanstack/react-table"
|
|
35
|
-
|
|
36
|
-
interface User {
|
|
37
|
-
id: string
|
|
38
|
-
name: string
|
|
39
|
-
email: string
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const columns: ColumnDef<User>[] = [
|
|
43
|
-
{
|
|
44
|
-
accessorKey: "name",
|
|
45
|
-
header: "Name",
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
accessorKey: "email",
|
|
49
|
-
header: "Email",
|
|
50
|
-
},
|
|
51
|
-
]
|
|
52
|
-
|
|
53
|
-
const data: User[] = [
|
|
54
|
-
{ id: "1", name: "John", email: "john@example.com" },
|
|
55
|
-
{ id: "2", name: "Jane", email: "jane@example.com" },
|
|
56
|
-
]
|
|
57
|
-
|
|
58
|
-
function MyTable() {
|
|
59
|
-
return <DataTable data={data} columns={columns} />
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## 🎨 Exemples avancés
|
|
64
|
-
|
|
65
|
-
### Table avec sélection et actions
|
|
66
|
-
|
|
67
|
-
```tsx
|
|
68
|
-
<DataTable
|
|
69
|
-
data={users}
|
|
70
|
-
columns={columns}
|
|
71
|
-
selection
|
|
72
|
-
toolbar={{
|
|
73
|
-
showSearch: true,
|
|
74
|
-
actions: [
|
|
75
|
-
{
|
|
76
|
-
id: "delete",
|
|
77
|
-
label: "Delete",
|
|
78
|
-
icon: <Trash />,
|
|
79
|
-
onClick: (selectedRows) => console.log(selectedRows),
|
|
80
|
-
requiresSelection: true,
|
|
81
|
-
variant: "destructive",
|
|
82
|
-
},
|
|
83
|
-
],
|
|
84
|
-
}}
|
|
85
|
-
onSelectionChange={(selectedRows) => console.log(selectedRows)}
|
|
86
|
-
/>
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### Pagination serveur
|
|
90
|
-
|
|
91
|
-
```tsx
|
|
92
|
-
<DataTable
|
|
93
|
-
data={users}
|
|
94
|
-
columns={columns}
|
|
95
|
-
pagination={{
|
|
96
|
-
mode: "server",
|
|
97
|
-
currentPage: 0,
|
|
98
|
-
totalItems: 1000,
|
|
99
|
-
pageSize: 10,
|
|
100
|
-
onPageChange: (page) => fetchPage(page),
|
|
101
|
-
onPageSizeChange: (size) => setPageSize(size),
|
|
102
|
-
}}
|
|
103
|
-
/>
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Export et Import
|
|
107
|
-
|
|
108
|
-
```tsx
|
|
109
|
-
<DataTable
|
|
110
|
-
data={users}
|
|
111
|
-
columns={columns}
|
|
112
|
-
enableExport
|
|
113
|
-
enableImport
|
|
114
|
-
/>
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Layouts alternatifs
|
|
118
|
-
|
|
119
|
-
```tsx
|
|
120
|
-
<DataTable
|
|
121
|
-
data={users}
|
|
122
|
-
columns={columns}
|
|
123
|
-
layout="card" // ou "compact", "split", "infinite"
|
|
124
|
-
variant="glass" // ou "bordered", "minimal", "striped"
|
|
125
|
-
density="compact" // ou "comfortable"
|
|
126
|
-
/>
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### Header sticky
|
|
130
|
-
|
|
131
|
-
```tsx
|
|
132
|
-
<DataTable
|
|
133
|
-
data={users}
|
|
134
|
-
columns={columns}
|
|
135
|
-
headerSticky
|
|
136
|
-
virtualizationHeight={600}
|
|
137
|
-
/>
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### Filtres avancés avec autocomplete
|
|
141
|
-
|
|
142
|
-
```tsx
|
|
143
|
-
<DataTable
|
|
144
|
-
data={users}
|
|
145
|
-
columns={columns}
|
|
146
|
-
filterPosition="right" // ou "left", "top", "bottom", "modal"
|
|
147
|
-
filters={[
|
|
148
|
-
{
|
|
149
|
-
id: "name-filter",
|
|
150
|
-
label: "Nom",
|
|
151
|
-
type: "text",
|
|
152
|
-
column: "name",
|
|
153
|
-
placeholder: "Rechercher par nom...",
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
id: "role-filter",
|
|
157
|
-
label: "Rôle",
|
|
158
|
-
type: "multiselect",
|
|
159
|
-
column: "role",
|
|
160
|
-
placeholder: "Sélectionner des rôles...",
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
id: "status-filter",
|
|
164
|
-
label: "Statut",
|
|
165
|
-
type: "select",
|
|
166
|
-
column: "status",
|
|
167
|
-
options: [
|
|
168
|
-
{ label: "Actif", value: "active" },
|
|
169
|
-
{ label: "Inactif", value: "inactive" },
|
|
170
|
-
],
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
id: "date-filter",
|
|
174
|
-
label: "Date de création",
|
|
175
|
-
type: "date",
|
|
176
|
-
column: "createdAt",
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
id: "age-filter",
|
|
180
|
-
label: "Âge",
|
|
181
|
-
type: "range",
|
|
182
|
-
column: "age",
|
|
183
|
-
},
|
|
184
|
-
]}
|
|
185
|
-
onFiltersChange={(activeFilters) => console.log(activeFilters)}
|
|
186
|
-
/>
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
**Caractéristiques des filtres** :
|
|
190
|
-
- 🎯 **Bouton compact** : S'ouvre dans un panneau au clic (ne prend pas de place)
|
|
191
|
-
- 🔍 **Autocomplete intelligent** : Suggestions automatiques basées sur les données de la colonne
|
|
192
|
-
- 📝 **Types multiples** : text, select, multiselect, date, range
|
|
193
|
-
- 📍 **Positions flexibles** :
|
|
194
|
-
- `top`/`bottom` : Popover compact (400px)
|
|
195
|
-
- `left`/`right` : Sheet latéral (400-540px)
|
|
196
|
-
- `modal` : Popover modal
|
|
197
|
-
- ✅ **Gestion des filtres actifs** : Affichage et suppression facile des filtres appliqués
|
|
198
|
-
- 🔧 **Opérateurs multiples** : contains, equals, startsWith, endsWith, in, notIn, between, etc.
|
|
199
|
-
|
|
200
|
-
## 📚 Props
|
|
201
|
-
|
|
202
|
-
### DataTableProps<TData>
|
|
203
|
-
|
|
204
|
-
| Prop | Type | Default | Description |
|
|
205
|
-
|------|------|---------|-------------|
|
|
206
|
-
| `data` | `TData[]` | **required** | Données à afficher |
|
|
207
|
-
| `columns` | `ColumnDef<TData>[]` | **required** | Définition des colonnes |
|
|
208
|
-
| `layout` | `DataTableLayout` | `"standard"` | Layout d'affichage |
|
|
209
|
-
| `variant` | `DataTableVariant` | `"bordered"` | Variant visuel |
|
|
210
|
-
| `density` | `DataTableDensity` | `"comfortable"` | Densité d'affichage |
|
|
211
|
-
| `selection` | `boolean` | `false` | Activer la sélection |
|
|
212
|
-
| `pagination` | `PaginationConfig` | `undefined` | Configuration pagination |
|
|
213
|
-
| `toolbar` | `ToolbarConfig` | `undefined` | Configuration toolbar |
|
|
214
|
-
| `filters` | `FilterConfig[]` | `undefined` | Configuration filtres |
|
|
215
|
-
| `filterPosition` | `FilterPosition` | `"top"` | Position des filtres |
|
|
216
|
-
| `loading` | `boolean` | `false` | État de chargement |
|
|
217
|
-
| `error` | `string \| null` | `null` | Message d'erreur |
|
|
218
|
-
| `emptyState` | `ReactNode` | `undefined` | État vide personnalisé |
|
|
219
|
-
| `headerSticky` | `boolean` | `false` | Header fixe |
|
|
220
|
-
| `enableExport` | `boolean \| ExportConfig` | `false` | Activer l'export |
|
|
221
|
-
| `enableImport` | `boolean \| ImportConfig` | `false` | Activer l'import |
|
|
222
|
-
| `enableVirtualization` | `boolean` | `false` | Activer virtualisation |
|
|
223
|
-
| `onRowClick` | `(row: TData) => void` | `undefined` | Callback clic ligne |
|
|
224
|
-
| `onSelectionChange` | `(rows: TData[]) => void` | `undefined` | Callback sélection |
|
|
225
|
-
| `className` | `string` | `undefined` | Classe CSS |
|
|
226
|
-
| `tableId` | `string` | `undefined` | ID pour persistance |
|
|
227
|
-
|
|
228
|
-
### PaginationConfig
|
|
229
|
-
|
|
230
|
-
```ts
|
|
231
|
-
interface PaginationConfig {
|
|
232
|
-
mode?: "client" | "server"
|
|
233
|
-
pageSize?: number
|
|
234
|
-
pageSizeOptions?: number[]
|
|
235
|
-
currentPage?: number
|
|
236
|
-
totalItems?: number
|
|
237
|
-
onPageChange?: (page: number) => void
|
|
238
|
-
onPageSizeChange?: (size: number) => void
|
|
239
|
-
}
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### ToolbarConfig
|
|
243
|
-
|
|
244
|
-
```ts
|
|
245
|
-
interface ToolbarConfig {
|
|
246
|
-
actions?: TableAction[]
|
|
247
|
-
showSearch?: boolean
|
|
248
|
-
showColumnToggle?: boolean
|
|
249
|
-
showDensity?: boolean
|
|
250
|
-
showRefresh?: boolean
|
|
251
|
-
onRefresh?: () => void
|
|
252
|
-
}
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### TableAction
|
|
256
|
-
|
|
257
|
-
```ts
|
|
258
|
-
interface TableAction {
|
|
259
|
-
id: string
|
|
260
|
-
label: string
|
|
261
|
-
icon?: ReactNode
|
|
262
|
-
onClick: (selectedRows: TData[]) => void
|
|
263
|
-
requiresSelection?: boolean
|
|
264
|
-
variant?: "default" | "destructive" | "outline" | "ghost"
|
|
265
|
-
disabled?: boolean
|
|
266
|
-
}
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### FilterConfig
|
|
270
|
-
|
|
271
|
-
```ts
|
|
272
|
-
interface FilterConfig {
|
|
273
|
-
id: string
|
|
274
|
-
label: string
|
|
275
|
-
type: "text" | "select" | "multiselect" | "date" | "range"
|
|
276
|
-
column?: string
|
|
277
|
-
placeholder?: string
|
|
278
|
-
defaultValue?: any
|
|
279
|
-
options?: Array<{ label: string; value: string | number }>
|
|
280
|
-
}
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
**Types de filtres** :
|
|
284
|
-
- `text` : Champ texte avec autocomplete basé sur les valeurs de la colonne
|
|
285
|
-
- `select` : Liste déroulante simple
|
|
286
|
-
- `multiselect` : Sélection multiple avec checkboxes
|
|
287
|
-
- `date` : Sélecteur de date
|
|
288
|
-
- `range` : Plage numérique (min/max)
|
|
289
|
-
|
|
290
|
-
## 🎛️ Hooks
|
|
291
|
-
|
|
292
|
-
### useDataTable
|
|
293
|
-
|
|
294
|
-
Hook principal pour gérer la logique du DataTable.
|
|
295
|
-
|
|
296
|
-
```tsx
|
|
297
|
-
const {
|
|
298
|
-
table,
|
|
299
|
-
sorting,
|
|
300
|
-
setSorting,
|
|
301
|
-
columnFilters,
|
|
302
|
-
setColumnFilters,
|
|
303
|
-
globalFilter,
|
|
304
|
-
setGlobalFilter,
|
|
305
|
-
selectedRows,
|
|
306
|
-
resetFilters,
|
|
307
|
-
exportData,
|
|
308
|
-
} = useDataTable({
|
|
309
|
-
data,
|
|
310
|
-
columns,
|
|
311
|
-
pagination,
|
|
312
|
-
tableId,
|
|
313
|
-
})
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
### useTableLayout
|
|
317
|
-
|
|
318
|
-
Hook pour gérer le layout et la densité.
|
|
319
|
-
|
|
320
|
-
```tsx
|
|
321
|
-
const {
|
|
322
|
-
layout,
|
|
323
|
-
setLayout,
|
|
324
|
-
density,
|
|
325
|
-
setDensity,
|
|
326
|
-
toggleLayout,
|
|
327
|
-
toggleDensity,
|
|
328
|
-
isMobile,
|
|
329
|
-
densityClasses,
|
|
330
|
-
} = useTableLayout("standard", "comfortable")
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
## 🌍 Internationalisation
|
|
334
|
-
|
|
335
|
-
Le composant supporte l'i18n via `react-i18next`. Toutes les clés sont sous le namespace `datatable` :
|
|
336
|
-
|
|
337
|
-
```json
|
|
338
|
-
{
|
|
339
|
-
"datatable": {
|
|
340
|
-
"loading": "Chargement...",
|
|
341
|
-
"noData": "Aucune donnée",
|
|
342
|
-
"selectAll": "Tout sélectionner",
|
|
343
|
-
"pagination": {
|
|
344
|
-
"showing": "Affichage",
|
|
345
|
-
"to": "à",
|
|
346
|
-
"of": "sur",
|
|
347
|
-
"results": "résultats",
|
|
348
|
-
"rowsPerPage": "Lignes par page"
|
|
349
|
-
},
|
|
350
|
-
"toolbar": {
|
|
351
|
-
"search": "Rechercher...",
|
|
352
|
-
"selected": "sélectionnés",
|
|
353
|
-
"clear": "Effacer",
|
|
354
|
-
"export": "Exporter",
|
|
355
|
-
"columns": "Colonnes"
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
## 🎨 Personnalisation
|
|
362
|
-
|
|
363
|
-
### Styles personnalisés
|
|
364
|
-
|
|
365
|
-
```tsx
|
|
366
|
-
<DataTable
|
|
367
|
-
data={data}
|
|
368
|
-
columns={columns}
|
|
369
|
-
className="custom-table"
|
|
370
|
-
/>
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
### Variant personnalisé
|
|
374
|
-
|
|
375
|
-
Le composant utilise Tailwind CSS. Vous pouvez personnaliser via les variants :
|
|
376
|
-
|
|
377
|
-
- `bordered` : bordures et coins arrondis
|
|
378
|
-
- `minimal` : sans bordures
|
|
379
|
-
- `striped` : lignes alternées
|
|
380
|
-
- `glass` : effet glassmorphism
|
|
381
|
-
|
|
382
|
-
## 🔧 Utilitaires
|
|
383
|
-
|
|
384
|
-
### Export
|
|
385
|
-
|
|
386
|
-
```ts
|
|
387
|
-
import { exportToCSV, exportToJSON } from "@wakastart/ui"
|
|
388
|
-
|
|
389
|
-
exportToCSV(data, "users.csv")
|
|
390
|
-
exportToJSON(data, "users.json")
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
### Import
|
|
394
|
-
|
|
395
|
-
```ts
|
|
396
|
-
import { parseCSV } from "@wakastart/ui"
|
|
397
|
-
|
|
398
|
-
const data = await parseCSV(file)
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
### Persistance
|
|
402
|
-
|
|
403
|
-
```ts
|
|
404
|
-
import { saveTableState, loadTableState } from "@wakastart/ui"
|
|
405
|
-
|
|
406
|
-
saveTableState("my-table", state)
|
|
407
|
-
const state = loadTableState("my-table")
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
## 🧪 Tests
|
|
411
|
-
|
|
412
|
-
```tsx
|
|
413
|
-
import { render, screen } from "@testing-library/react"
|
|
414
|
-
import { DataTable } from "@wakastart/ui"
|
|
415
|
-
|
|
416
|
-
test("renders table with data", () => {
|
|
417
|
-
render(<DataTable data={testData} columns={testColumns} />)
|
|
418
|
-
expect(screen.getByText("John")).toBeInTheDocument()
|
|
419
|
-
})
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
## 📖 Documentation complète
|
|
423
|
-
|
|
424
|
-
- [TanStack Table](https://tanstack.com/table/v8)
|
|
425
|
-
- [WakaStart UI](https://ui.wakastart.com)
|
|
426
|
-
- [Exemples de démo](/demo/app/datatable)
|
|
427
|
-
|
|
428
|
-
## 📝 Changelog
|
|
429
|
-
|
|
430
|
-
### v1.0.0 (2024-10-15)
|
|
431
|
-
|
|
432
|
-
- 🎉 Initial release
|
|
433
|
-
- ✨ Support complet de TanStack Table v8
|
|
434
|
-
- 🎨 Layouts multiples
|
|
435
|
-
- 🌍 i18n complet
|
|
436
|
-
- 📊 Export/Import
|
|
437
|
-
- 🎯 TypeScript strict
|
|
438
|
-
|
|
439
|
-
## 🤝 Contribution
|
|
440
|
-
|
|
441
|
-
Contributions bienvenues ! Voir [CONTRIBUTING.md](../../../CONTRIBUTING.md)
|
|
442
|
-
|
|
443
|
-
## 📄 License
|
|
444
|
-
|
|
445
|
-
MIT © WakaStart
|
|
446
|
-
|