@synertech/ui 0.43.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.
@@ -168,6 +168,9 @@ import { cn } from "@synertech/ui";
168
168
  - `BoxPlot` - Médiane, quartiles, moustaches et valeurs aberrantes
169
169
  - `CandlestickChart` - Ouverture, haut, bas, clôture (couleurs de statut)
170
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
171
174
 
172
175
  ### Feedback & Overlays
173
176
 
@@ -552,7 +555,10 @@ Tous les graphiques partagent la même forme de données : un tableau de lignes
552
555
  et des séries qui pointent un champ, exactement comme `DataGrid`.
553
556
 
554
557
  ```tsx
555
- 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";
556
562
 
557
563
  const data = [
558
564
  { month: "Jan", revenue: 18400, cost: 12200 },
@@ -758,6 +764,75 @@ const data = [
758
764
  <Select size="sm" options={regions} value={region} onValueChange={setRegion} />
759
765
  </ChartFilterBar>
760
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
+
761
836
  // Petits multiples — le domaine est calculé sur l'ensemble et imposé à chaque panneau
762
837
  <ChartFacets data={rows} by="region" values={["revenue"]} columns={3}>
763
838
  {({ data, domain, label }) => (
@@ -822,6 +897,33 @@ const data = [
822
897
  - **Les annotations se lisent sur l'axe des catégories.** Un `BarChart`
823
898
  horizontal les ignore, avec un avertissement : un moment placé sur une liste
824
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.
825
927
 
826
928
  ### Cartes KPI
827
929