@synertech/ui 0.42.0 → 0.44.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.
@@ -160,12 +160,17 @@ import { cn } from "@synertech/ui";
160
160
  - `BulletChart` - Réalisé, objectif et plages qualitatives sur une seule ligne
161
161
  - `ChartFacets` - Petits multiples : un même graphique répété, à échelle partagée
162
162
  - `ChartScaleLegend` - La légende d'une rampe de couleur
163
+ - `ChartFilterBar` - Les filtres en une rangée au-dessus des graphiques qu'ils cadrent
164
+ - `ChartPeriodPicker` - La fenêtre d'un tableau de bord : préréglages nommés + calendrier
163
165
  - `WaterfallChart` - Comment on passe de A à B : chaque contribution, positive ou négative
164
166
  - `FunnelChart` - Des étapes ordonnées et leur déperdition (rampe ordinale)
165
167
  - `DumbbellChart` - Avant → après par élément, ou une plage min–max
166
168
  - `BoxPlot` - Médiane, quartiles, moustaches et valeurs aberrantes
167
169
  - `CandlestickChart` - Ouverture, haut, bas, clôture (couleurs de statut)
168
170
  - `GanttChart` - Des tâches dans le temps, avec dépendances et jalons
171
+ - `ChartSyncProvider` - Plusieurs panneaux qui se lisent comme un seul objet :
172
+ survol partagé et fenêtre brossée en commun
173
+ - `ChartExportButton` - Le tableau du graphique en CSV ou JSON
169
174
 
170
175
  ### Feedback & Overlays
171
176
 
@@ -550,7 +555,10 @@ Tous les graphiques partagent la même forme de données : un tableau de lignes
550
555
  et des séries qui pointent un champ, exactement comme `DataGrid`.
551
556
 
552
557
  ```tsx
553
- import { LineChart, AreaChart, BarChart, PieChart, ScatterChart } from "@synertech/ui";
558
+ import {
559
+ LineChart, AreaChart, BarChart, PieChart, ScatterChart,
560
+ ChartSyncProvider, ChartExportButton, brushToPeriod,
561
+ } from "@synertech/ui";
554
562
 
555
563
  const data = [
556
564
  { month: "Jan", revenue: 18400, cost: 12200 },
@@ -732,6 +740,99 @@ const data = [
732
740
  today="2026-04-14"
733
741
  />
734
742
 
743
+ // Annotations — ce qui s'est passé, dessiné là où ça s'est passé
744
+ // (`referenceLines` = un seuil sur l'axe des valeurs ; les annotations = un
745
+ // moment sur l'axe des catégories. Lisible sur LineChart, AreaChart, BarChart)
746
+ <LineChart
747
+ data={monthly}
748
+ series={[{ key: "revenue" }]}
749
+ x={{ key: "month" }}
750
+ annotations={[
751
+ { type: "band", from: "Fév", to: "Mar", label: "Campagne" },
752
+ { type: "line", x: "Mai", label: "Refonte du tunnel" },
753
+ { type: "point", x: "Août", y: 39900, label: "Record" },
754
+ ]}
755
+ />
756
+
757
+ // Trames — le canal de secours quand la teinte échoue (CVD sévère, impression
758
+ // en niveaux de gris, forced-colors). Jamais par défaut : c'est de l'a11y
759
+ <BarChart data={channels} series={channelSeries} x={{ key: "quarter" }} stack="stacked" patterns />
760
+
761
+ // La rangée de filtres — une seule, au-dessus de TOUS les graphiques
762
+ <ChartFilterBar actions={<Button size="sm">Exporter</Button>}>
763
+ <ChartPeriodPicker size="sm" value={period} onChange={setPeriod} />
764
+ <Select size="sm" options={regions} value={region} onValueChange={setRegion} />
765
+ </ChartFilterBar>
766
+
767
+ // L'état d'erreur — distinct de l'état vide, sur TOUS les graphiques du kit
768
+ // (« il n'y a rien » et « on n'a pas réussi à charger » sont deux affirmations
769
+ // différentes ; seule la seconde appelle une reprise)
770
+ <LineChart
771
+ data={rows}
772
+ series={series}
773
+ x={{ key: "month" }}
774
+ loading={query.isFetching}
775
+ error={query.isError}
776
+ onRetry={() => query.refetch()}
777
+ />
778
+
779
+ // L'export — le tableau exact du graphique, dans la fente `actions`
780
+ <LineChart
781
+ data={rows}
782
+ series={series}
783
+ x={{ key: "month", label: "Mois" }}
784
+ actions={
785
+ <ChartExportButton
786
+ data={rows}
787
+ series={series}
788
+ xKey="month"
789
+ xLabel="Mois"
790
+ filename="revenus"
791
+ size="sm"
792
+ />
793
+ }
794
+ />
795
+
796
+ // La trappe d'évasion — dessiner DANS le tracé, avec les échelles du graphique
797
+ // (Line, Area, Bar, Scatter. Une fonction dessine par-dessus les marques ;
798
+ // `{ under, over }` atteint aussi le dessous. Coordonnées relatives à la zone
799
+ // de dessin, et sans clip : la marge est à la charge de l'appelant)
800
+ <LineChart
801
+ data={rows}
802
+ series={series}
803
+ x={{ key: "month" }}
804
+ y={{ domain: [100, 230] }} // ← réserver la place de l'annotation
805
+ overlay={({ xAt, yAt, dimensions }) => (
806
+ <rect
807
+ x={0}
808
+ y={yAt(200)}
809
+ width={dimensions.innerWidth}
810
+ height={Math.abs(yAt(160) - yAt(200))}
811
+ className="fill-green-500"
812
+ opacity={0.1}
813
+ />
814
+ )}
815
+ />
816
+
817
+ // La volumétrie — allège le TRACÉ, jamais les données
818
+ // (LTTB sur Line/Area, échantillon régulier sur Scatter. Le tableau, l'infobulle
819
+ // et la droite de tendance continuent de lire chaque ligne)
820
+ <LineChart data={fiftyThousandRows} series={series} x={{ key: "t", scale: "linear" }} maxPoints={400} />
821
+
822
+ // Le tableau de bord synchronisé — un pointeur, une infobulle ; une plage, toutes
823
+ // les cartes. `brushToPeriod` rend la fenêtre au `ChartPeriodPicker`
824
+ <ChartSyncProvider brush={null} onBrushChange={(range) => {
825
+ const next = range && brushToPeriod(range);
826
+ if (next) setPeriod(next);
827
+ }}>
828
+ <ChartFilterBar>
829
+ <ChartPeriodPicker size="sm" value={period} onChange={setPeriod} />
830
+ </ChartFilterBar>
831
+
832
+ <LineChart data={rows} series={series} x={xAxis} brush />
833
+ <BarChart data={rows} series={series} x={{ key: "day" }} />
834
+ </ChartSyncProvider>
835
+
735
836
  // Petits multiples — le domaine est calculé sur l'ensemble et imposé à chaque panneau
736
837
  <ChartFacets data={rows} by="region" values={["revenue"]} columns={3}>
737
838
  {({ data, domain, label }) => (
@@ -786,6 +887,43 @@ const data = [
786
887
  sous déficience de vision des couleurs.
787
888
  - **`GanttChart` n'est pas un `Calendar`.** Le calendrier sélectionne une date
788
889
  et la renvoie ; le planning se lit. Une ligne sans largeur est un jalon.
890
+ - **Les filtres vivent dans UNE rangée, au-dessus des graphiques.** Jamais dans
891
+ une carte, jamais par graphique : deux panneaux filtrés séparément répondent à
892
+ deux questions et rien à l'écran ne le dit.
893
+ - **Les trames ne sont jamais activées par défaut.** C'est une option
894
+ d'accessibilité, pas une décoration — et elles ne peignent que des identités :
895
+ une rampe (Heatmap, `diverging`, tunnel) encode une grandeur, ce qu'aucune
896
+ trame ne sait dire.
897
+ - **Les annotations se lisent sur l'axe des catégories.** Un `BarChart`
898
+ horizontal les ignore, avec un avertissement : un moment placé sur une liste
899
+ de noms n'en est plus un.
900
+ - **`error` n'est jamais `empty`.** Un panneau qui affiche « Aucune donnée »
901
+ après une requête échouée affirme quelque chose de faux, et ne propose aucune
902
+ sortie. `loading` l'emporte sur les deux : une reprise remplace le message par
903
+ le voyant.
904
+ - **Rien n'est décimé tout seul.** Un graphique qui dessinerait en douce une
905
+ autre forme que celle qu'on lui a remise serait pire qu'un graphique lent :
906
+ au-delà de 2 000 points il avertit, et `maxPoints` est à vous. Il n'allège
907
+ que le tracé — le tableau garde chaque ligne.
908
+ - **`BarChart` n'a pas de `maxPoints`.** Décimer des barres, c'est supprimer des
909
+ catégories : `bins` est la réponse là-bas.
910
+ - **`ScatterChart` échantillonne régulièrement, pas en LTTB.** Un nuage se lit à
911
+ sa densité ; garder les plus grands triangles en découperait l'enveloppe et
912
+ jetterait précisément ce qu'on regarde.
913
+ - **`overlay` n'est pas `children`.** Les graphiques restent des objets fermés ;
914
+ la trappe remet la géométrie résolue et rien d'autre. C'est elle qui rend
915
+ défendable chaque refus de cette liste — « prenez un `BarChart` groupé » ne
916
+ tient que si l'application peut dessiner ce qu'elle n'obtiendra jamais du kit.
917
+ - **Un `ScatterChart` ne se brosse pas.** Ses deux axes sont des mesures, et une
918
+ fenêtre sur l'une d'elles n'est pas le geste qu'un nuage appelle.
919
+ - **Une plage se pose aussi au clavier.** Maj + flèches l'étend, Échap la retire :
920
+ un filtre qui ne s'atteint qu'à la souris est inaccessible à la moitié des
921
+ lecteurs.
922
+ - **Une fenêtre qui a déjà recadré le tableau de bord n'a plus à être teintée.**
923
+ Les panneaux SONT la fenêtre ; la bande lave alors chaque tracé de bord à bord
924
+ et n'énonce rien. Repassez `brush={null}` après l'avoir appliquée.
925
+ - **L'export écrit les mesures brutes.** Ce qui ouvre le fichier va calculer
926
+ dessus, et `1 234,5 $` est une chaîne. Seule la catégorie est formatée.
789
927
 
790
928
  ### Cartes KPI
791
929