@tsiky/components-r19 1.0.0 → 1.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 (32) hide show
  1. package/index.ts +35 -33
  2. package/package.json +1 -1
  3. package/src/components/Charts/area-chart-admission/AreaChartAdmission.tsx +123 -89
  4. package/src/components/Charts/bar-chart/BarChart.tsx +167 -132
  5. package/src/components/Charts/mixed-chart/MixedChart.tsx +65 -9
  6. package/src/components/Charts/sankey-chart/SankeyChart.tsx +183 -155
  7. package/src/components/Confirmationpopup/ConfirmationPopup.module.css +88 -0
  8. package/src/components/Confirmationpopup/ConfirmationPopup.stories.tsx +94 -0
  9. package/src/components/Confirmationpopup/ConfirmationPopup.tsx +47 -0
  10. package/src/components/Confirmationpopup/index.ts +6 -0
  11. package/src/components/Confirmationpopup/useConfirmationPopup.ts +48 -0
  12. package/src/components/DayStatCard/DayStatCard.tsx +96 -69
  13. package/src/components/DynamicTable/AdvancedFilters.tsx +196 -196
  14. package/src/components/DynamicTable/ColumnSorter.tsx +185 -185
  15. package/src/components/DynamicTable/Pagination.tsx +115 -115
  16. package/src/components/DynamicTable/TableauDynamique.module.css +1287 -1287
  17. package/src/components/DynamicTable/filters/SelectFilter.tsx +69 -69
  18. package/src/components/EntryControl/EntryControl.tsx +117 -117
  19. package/src/components/Grid/Grid.tsx +5 -0
  20. package/src/components/Header/Header.tsx +4 -2
  21. package/src/components/Header/header.css +61 -31
  22. package/src/components/MetricsPanel/MetricsPanel.module.css +688 -636
  23. package/src/components/MetricsPanel/MetricsPanel.tsx +220 -282
  24. package/src/components/MetricsPanel/renderers/CompactRenderer.tsx +148 -125
  25. package/src/components/NavBar/NavBar.tsx +1 -1
  26. package/src/components/SelectFilter/SelectFilter.module.css +249 -0
  27. package/src/components/SelectFilter/SelectFilter.stories.tsx +321 -0
  28. package/src/components/SelectFilter/SelectFilter.tsx +219 -0
  29. package/src/components/SelectFilter/index.ts +2 -0
  30. package/src/components/SelectFilter/types.ts +19 -0
  31. package/src/components/TranslationKey/TranslationKey.tsx +265 -245
  32. package/src/components/TrendList/TrendList.tsx +72 -45
@@ -1,6 +1,7 @@
1
- import React from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import Chart from 'react-apexcharts';
3
3
  import type { ApexOptions } from 'apexcharts';
4
+ import { Move } from 'lucide-react';
4
5
 
5
6
  /* ---------- Types ---------- */
6
7
  export interface BandChartData {
@@ -59,6 +60,9 @@ interface Props {
59
60
  config?: BandChartConfig;
60
61
  height?: number;
61
62
  useOnGoing?: boolean;
63
+ draggable?: boolean;
64
+ tooltipEnabled?: boolean;
65
+ // zoomEnabled removed as separate prop — zoom/pan follow tooltipEnabled
62
66
  }
63
67
 
64
68
  /* ---------- Local series item types (compat Apex) ---------- */
@@ -140,7 +144,24 @@ const MixedChart: React.FC<Props> = ({
140
144
  config = defaultConfig,
141
145
  height = 350,
142
146
  useOnGoing,
147
+ draggable = false,
148
+ tooltipEnabled = true,
143
149
  }) => {
150
+ const [renderKey, setRenderKey] = useState(0);
151
+ const [loading, setLoading] = useState(false);
152
+
153
+ // Lorsque draggable passe de true → false, on force remount
154
+ useEffect(() => {
155
+ if (!draggable) {
156
+ setLoading(true);
157
+ const timeout = setTimeout(() => {
158
+ setRenderKey((k) => k + 1); // nouvelle key → remount Chart
159
+ setLoading(false);
160
+ }, 10); // très court délai pour permettre le placeholder
161
+ return () => clearTimeout(timeout);
162
+ }
163
+ }, [draggable]);
164
+
144
165
  // merge defaults and provided config
145
166
  const merged = { ...defaultConfig, ...config };
146
167
  // minimal override: if caller provided useOnGoing boolean, it forces merged.showOnGoing
@@ -480,9 +501,26 @@ const MixedChart: React.FC<Props> = ({
480
501
  chart: {
481
502
  foreColor: 'var(--color-text)',
482
503
  type: 'line',
483
- toolbar: { show: false, offsetY: -20 },
504
+ toolbar: {
505
+ show: false,
506
+ offsetY: -20,
507
+ autoSelected: 'pan',
508
+ tools: {
509
+ download: false,
510
+ selection: true,
511
+ zoom: true,
512
+ zoomin: true,
513
+ zoomout: true,
514
+ pan: true,
515
+ reset: true,
516
+ },
517
+ },
484
518
  width: '100%',
485
- zoom: { enabled: false, type: 'x', autoScaleYaxis: true },
519
+ zoom: {
520
+ enabled: tooltipEnabled,
521
+ type: 'x',
522
+ autoScaleYaxis: true,
523
+ },
486
524
  animations: {
487
525
  enabled: true,
488
526
  animateGradually: { enabled: true, delay: 80 },
@@ -525,6 +563,7 @@ const MixedChart: React.FC<Props> = ({
525
563
  // CUSTOM TOOLTIP: show only defined values, keep Real and OnGoing separate,
526
564
  // skip outlier points flagged _outside, skip column placeholder zeros
527
565
  tooltip: {
566
+ enabled: tooltipEnabled,
528
567
  shared: true,
529
568
  intersect: false,
530
569
  followCursor: true,
@@ -613,12 +652,29 @@ const MixedChart: React.FC<Props> = ({
613
652
  };
614
653
 
615
654
  return (
616
- <Chart
617
- options={options}
618
- series={series as unknown as ApexOptions['series']}
619
- type='line'
620
- height={height}
621
- />
655
+ <div style={{ position: 'relative', width: '100%', height }}>
656
+ {draggable && !loading ? (
657
+ <div
658
+ style={{
659
+ width: '100%',
660
+ height: '100%',
661
+ display: 'flex',
662
+ alignItems: 'center',
663
+ justifyContent: 'center',
664
+ }}
665
+ >
666
+ <Move size={48} strokeWidth={1.5} style={{ opacity: 0.8 }} />
667
+ </div>
668
+ ) : (
669
+ <Chart
670
+ key={renderKey} // force remount si besoin
671
+ options={options}
672
+ series={series as unknown as ApexOptions['series']}
673
+ type="line"
674
+ height={height}
675
+ />
676
+ )}
677
+ </div>
622
678
  );
623
679
  };
624
680
 
@@ -1,155 +1,183 @@
1
- import React, { useEffect, useRef } from 'react';
2
- import { color } from 'storybook/internal/theming';
3
-
4
- export type SankeyLink = { source: string; target: string; value: number; color?: string };
5
-
6
- interface Props {
7
- links?: SankeyLink[];
8
- height?: number;
9
- nodeWidth?: number;
10
- enableToolbar?: boolean;
11
- annotatePercent?: boolean;
12
- maxLeftFraction?: number;
13
- className?: string;
14
- }
15
-
16
- const SankeyChart: React.FC<Props> = ({
17
- links,
18
- height = 480,
19
- nodeWidth = 5,
20
- enableToolbar = false,
21
- annotatePercent = true,
22
- maxLeftFraction = 0.45,
23
- className,
24
- }) => {
25
- const containerRef = useRef<HTMLDivElement | null>(null);
26
-
27
- useEffect(() => {
28
- let sInstance: { render: (d: unknown) => void; destroy?: () => void } | null = null;
29
- let mounted = true;
30
-
31
- (async () => {
32
- try {
33
- const mod = await import('apexsankey');
34
- const ApexSankey = mod?.default as unknown;
35
-
36
- if (!mounted) return;
37
- const mountEl = containerRef.current;
38
- if (!mountEl) return;
39
-
40
- const defaultLinks: SankeyLink[] = [
41
- { source: 'non-seniors', target: 'retour', value: 73.9 },
42
- { source: 'non-seniors', target: 'hospitalisations', value: 23.9 },
43
- { source: 'non-seniors', target: 'transfert', value: 2.1 },
44
- { source: 'non-seniors', target: 'maison_medicale_de_garde', value: 0.1 },
45
- { source: 'non-seniors', target: 'deces', value: 0.1 },
46
- { source: 'seniors', target: 'retour', value: 75.6 },
47
- { source: 'seniors', target: 'hospitalisations', value: 20.4 },
48
- { source: 'seniors', target: 'transfert', value: 3.1 },
49
- { source: 'seniors', target: 'maison_medicale_de_garde', value: 0.1 },
50
- { source: 'seniors', target: 'deces', value: 0.8 },
51
- ];
52
- const usedLinks = links && links.length ? links : defaultLinks;
53
-
54
- const nodeSet = new Set<string>();
55
- usedLinks.forEach((l) => {
56
- nodeSet.add(l.source);
57
- nodeSet.add(l.target);
58
- });
59
-
60
- const orderedNodes = [
61
- 'non-seniors',
62
- 'seniors',
63
- 'retour',
64
- 'hospitalisations',
65
- 'transfert',
66
- 'maison_medicale_de_garde',
67
- 'deces',
68
- ].filter((id) => nodeSet.has(id));
69
- for (const id of nodeSet) if (!orderedNodes.includes(id)) orderedNodes.push(id);
70
-
71
- const totalsBySource: Record<string, number> = {};
72
- const totalsByTarget: Record<string, number> = {};
73
- let overall = 0;
74
- usedLinks.forEach((l) => {
75
- totalsBySource[l.source] = (totalsBySource[l.source] || 0) + (l.value ?? 0);
76
- totalsByTarget[l.target] = (totalsByTarget[l.target] || 0) + (l.value ?? 0);
77
- overall += l.value ?? 0;
78
- });
79
-
80
- const nodes = orderedNodes.map((id) => {
81
- let title = id;
82
- if (annotatePercent) {
83
- const srcVal = totalsBySource[id];
84
- if (typeof srcVal === 'number' && overall > 0) {
85
- const pct = Math.round((srcVal / overall) * 1000) / 10;
86
- title = `${id} (${pct}%)`;
87
- } else {
88
- const t = totalsByTarget[id];
89
- if (typeof t === 'number' && overall > 0) {
90
- const pct = Math.round((t / overall) * 1000) / 10;
91
- title = `${id} (${pct}%)`;
92
- }
93
- }
94
- }
95
- return { id, title };
96
- });
97
-
98
- const edges = usedLinks.map((l) => ({
99
- source: l.source,
100
- target: l.target,
101
- value: l.value,
102
- }));
103
- const data = { nodes, edges };
104
-
105
- const parent = mountEl?.parentElement;
106
- const containerWidth = parent ? parent.clientWidth || 420 : mountEl?.clientWidth || 420;
107
-
108
- const graphOptions = {
109
- nodeWidth,
110
- fontFamily:
111
- "Inter, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial",
112
- fontWeight: '600',
113
- fontColor: 'var(--color-text)',
114
- height,
115
- enableToolbar,
116
- viewPortWidth: containerWidth,
117
- viewPortHeight: height,
118
- width: containerWidth,
119
- nodeAlignment: 'top',
120
- colors: {
121
- text: 'var(--color-text)',
122
- background: '#fff',
123
- },
124
- linkOpacity: 0.6,
125
- canvasStyle: {},
126
- };
127
-
128
- // constructor type
129
- const SankeyCtor = ApexSankey as unknown as new (
130
- el: Element,
131
- opts: unknown
132
- ) => { render: (d: unknown) => void; destroy?: () => void };
133
- sInstance = new SankeyCtor(mountEl as Element, graphOptions as unknown);
134
- sInstance.render(data as unknown);
135
- } catch (err) {
136
- console.error('Erreur lors du rendu ApexSankey :', err);
137
- }
138
- })();
139
-
140
- return () => {
141
- mounted = false;
142
- try {
143
- if (sInstance && typeof sInstance.destroy === 'function') sInstance.destroy();
144
- } catch {
145
- /* noop */
146
- }
147
- };
148
- }, [links, height, nodeWidth, enableToolbar, annotatePercent, maxLeftFraction]);
149
-
150
- return (
151
- <div ref={containerRef} className={className} style={{ height: height, overflow: 'hidden' }} />
152
- );
153
- };
154
-
155
- export default SankeyChart;
1
+ import { Move } from 'lucide-react';
2
+ import React, { useEffect, useRef } from 'react';
3
+
4
+ export type SankeyLink = { source: string; target: string; value: number; color?: string };
5
+
6
+ interface Props {
7
+ links?: SankeyLink[];
8
+ height?: number;
9
+ nodeWidth?: number;
10
+ enableToolbar?: boolean;
11
+ annotatePercent?: boolean;
12
+ maxLeftFraction?: number;
13
+ className?: string;
14
+ draggable?: boolean;
15
+ }
16
+
17
+ const SankeyChart: React.FC<Props> = ({
18
+ links,
19
+ height = 480,
20
+ nodeWidth = 5,
21
+ enableToolbar = false,
22
+ annotatePercent = true,
23
+ maxLeftFraction = 0.45,
24
+ className,
25
+ draggable = false,
26
+ }) => {
27
+ const containerRef = useRef<HTMLDivElement | null>(null);
28
+
29
+ useEffect(() => {
30
+ let sInstance: { render: (d: unknown) => void; destroy?: () => void } | null = null;
31
+ let mounted = true;
32
+
33
+ (async () => {
34
+ try {
35
+ const mod = await import('apexsankey');
36
+ const ApexSankey = mod?.default as unknown;
37
+
38
+ if (!mounted) return;
39
+ const mountEl = containerRef.current;
40
+ if (!mountEl) return;
41
+
42
+ const defaultLinks: SankeyLink[] = [
43
+ { source: 'non-seniors', target: 'retour', value: 73.9 },
44
+ { source: 'non-seniors', target: 'hospitalisations', value: 23.9 },
45
+ { source: 'non-seniors', target: 'transfert', value: 2.1 },
46
+ { source: 'non-seniors', target: 'maison_medicale_de_garde', value: 0.1 },
47
+ { source: 'non-seniors', target: 'deces', value: 0.1 },
48
+ { source: 'seniors', target: 'retour', value: 75.6 },
49
+ { source: 'seniors', target: 'hospitalisations', value: 20.4 },
50
+ { source: 'seniors', target: 'transfert', value: 3.1 },
51
+ { source: 'seniors', target: 'maison_medicale_de_garde', value: 0.1 },
52
+ { source: 'seniors', target: 'deces', value: 0.8 },
53
+ ];
54
+ const usedLinks = links && links.length ? links : defaultLinks;
55
+
56
+ const nodeSet = new Set<string>();
57
+ usedLinks.forEach((l) => {
58
+ nodeSet.add(l.source);
59
+ nodeSet.add(l.target);
60
+ });
61
+
62
+ const orderedNodes = [
63
+ 'non-seniors',
64
+ 'seniors',
65
+ 'retour',
66
+ 'hospitalisations',
67
+ 'transfert',
68
+ 'maison_medicale_de_garde',
69
+ 'deces',
70
+ ].filter((id) => nodeSet.has(id));
71
+ for (const id of nodeSet) if (!orderedNodes.includes(id)) orderedNodes.push(id);
72
+
73
+ const totalsBySource: Record<string, number> = {};
74
+ const totalsByTarget: Record<string, number> = {};
75
+ let overall = 0;
76
+ usedLinks.forEach((l) => {
77
+ totalsBySource[l.source] = (totalsBySource[l.source] || 0) + (l.value ?? 0);
78
+ totalsByTarget[l.target] = (totalsByTarget[l.target] || 0) + (l.value ?? 0);
79
+ overall += l.value ?? 0;
80
+ });
81
+
82
+ const nodes = orderedNodes.map((id) => {
83
+ let title = id;
84
+ if (annotatePercent) {
85
+ const srcVal = totalsBySource[id];
86
+ if (typeof srcVal === 'number' && overall > 0) {
87
+ const pct = Math.round((srcVal / overall) * 1000) / 10;
88
+ title = `${id} (${pct}%)`;
89
+ } else {
90
+ const t = totalsByTarget[id];
91
+ if (typeof t === 'number' && overall > 0) {
92
+ const pct = Math.round((t / overall) * 1000) / 10;
93
+ title = `${id} (${pct}%)`;
94
+ }
95
+ }
96
+ }
97
+ return { id, title };
98
+ });
99
+
100
+ const edges = usedLinks.map((l) => ({
101
+ source: l.source,
102
+ target: l.target,
103
+ value: l.value,
104
+ }));
105
+ const data = { nodes, edges };
106
+
107
+ const parent = mountEl?.parentElement;
108
+ const containerWidth = parent ? parent.clientWidth || 420 : mountEl?.clientWidth || 420;
109
+
110
+ const graphOptions = {
111
+ nodeWidth,
112
+ fontFamily:
113
+ "Inter, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial",
114
+ fontWeight: '600',
115
+ fontColor: 'var(--color-text)',
116
+ height,
117
+ enableToolbar,
118
+ viewPortWidth: containerWidth,
119
+ viewPortHeight: height,
120
+ width: containerWidth,
121
+ nodeAlignment: 'top',
122
+ colors: {
123
+ text: 'var(--color-text)',
124
+ background: '#fff',
125
+ },
126
+ linkOpacity: 0.6,
127
+ canvasStyle: {},
128
+ };
129
+
130
+ // constructor type
131
+ const SankeyCtor = ApexSankey as unknown as new (
132
+ el: Element,
133
+ opts: unknown
134
+ ) => { render: (d: unknown) => void; destroy?: () => void };
135
+ sInstance = new SankeyCtor(mountEl as Element, graphOptions as unknown);
136
+ sInstance.render(data as unknown);
137
+ } catch (err) {
138
+ console.error('Erreur lors du rendu ApexSankey :', err);
139
+ }
140
+ })();
141
+
142
+ return () => {
143
+ mounted = false;
144
+ try {
145
+ if (sInstance && typeof sInstance.destroy === 'function') sInstance.destroy();
146
+ } catch {
147
+ /* noop */
148
+ }
149
+ };
150
+ }, [links, height, nodeWidth, enableToolbar, annotatePercent, maxLeftFraction]);
151
+
152
+ return (
153
+ <div style={{ position: 'relative', height }}>
154
+ {/* Chart container, masqué si draggable */}
155
+ <div
156
+ ref={containerRef}
157
+ className={className}
158
+ style={{ height, overflow: 'hidden', opacity: draggable ? 0 : 1 }}
159
+ />
160
+
161
+ {/* Overlay Move */}
162
+ {draggable && (
163
+ <div
164
+ style={{
165
+ position: 'absolute',
166
+ top: 0,
167
+ left: 0,
168
+ width: '100%',
169
+ height: '100%',
170
+ display: 'flex',
171
+ alignItems: 'center',
172
+ justifyContent: 'center',
173
+ pointerEvents: 'none',
174
+ }}
175
+ >
176
+ <Move size={32} strokeWidth={1.5} style={{ opacity: 0.8 }} />
177
+ </div>
178
+ )}
179
+ </div>
180
+ );
181
+ };
182
+
183
+ export default SankeyChart;
@@ -0,0 +1,88 @@
1
+ .overlay {
2
+ position: fixed;
3
+ top: 0;
4
+ left: 0;
5
+ right: 0;
6
+ bottom: 0;
7
+ background-color: rgba(0, 0, 0, 0.5);
8
+ display: flex;
9
+ justify-content: center;
10
+ align-items: center;
11
+ z-index: 1000;
12
+ }
13
+
14
+ .popup {
15
+ background: white;
16
+ border-radius: 8px;
17
+ min-width: 400px;
18
+ max-width: 500px;
19
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
20
+ }
21
+
22
+ .header {
23
+ padding: 1rem;
24
+ border-bottom: 1px solid #e5e5e5;
25
+ }
26
+
27
+ .header h3 {
28
+ margin: 0;
29
+ font-size: 1.25rem;
30
+ }
31
+
32
+ .body {
33
+ padding: 1.5rem;
34
+ }
35
+
36
+ .body p {
37
+ margin: 0;
38
+ line-height: 1.5;
39
+ }
40
+
41
+ .footer {
42
+ padding: 1rem;
43
+ border-top: 1px solid #e5e5e5;
44
+ display: flex;
45
+ justify-content: flex-end;
46
+ gap: 0.5rem;
47
+ }
48
+
49
+ .confirmButton,
50
+ .cancelButton {
51
+ padding: 0.5rem 1rem;
52
+ border: none;
53
+ border-radius: 4px;
54
+ cursor: pointer;
55
+ font-size: 0.875rem;
56
+ transition: all 0.2s;
57
+ }
58
+
59
+ .confirmButton {
60
+ background-color: #dc3545;
61
+ color: white;
62
+ }
63
+
64
+ .confirmButton:hover {
65
+ background-color: #c82333;
66
+ }
67
+
68
+ .cancelButton {
69
+ background-color: #6c757d;
70
+ color: white;
71
+ }
72
+
73
+ .cancelButton:hover {
74
+ background-color: #5a6268;
75
+ }
76
+
77
+ /* Types variants */
78
+ .warning .header {
79
+ border-left: 4px solid #ffc107;
80
+ }
81
+
82
+ .danger .header {
83
+ border-left: 4px solid #dc3545;
84
+ }
85
+
86
+ .info .header {
87
+ border-left: 4px solid #17a2b8;
88
+ }
@@ -0,0 +1,94 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { ConfirmationPopup } from './ConfirmationPopup';
3
+ import { useConfirmationPopup } from './useConfirmationPopup';
4
+
5
+ const meta: Meta<typeof ConfirmationPopup> = {
6
+ title: 'Components/ConfirmationPopup',
7
+ component: ConfirmationPopup,
8
+ tags: ['autodocs'],
9
+ args: {
10
+ title: 'Supprimer cet élément ?',
11
+ message: 'Cette action est irréversible. Voulez-vous vraiment supprimer cet élément ?',
12
+ confirmText: 'Oui, supprimer',
13
+ cancelText: 'Annuler',
14
+ type: 'warning',
15
+ },
16
+ };
17
+
18
+ export default meta;
19
+ type Story = StoryObj<typeof ConfirmationPopup>;
20
+
21
+ export const Default: Story = {
22
+ args: {
23
+ isOpen: true,
24
+ onConfirm: () => console.log('Confirmé!'),
25
+ onCancel: () => console.log('Annulé!'),
26
+ },
27
+ };
28
+
29
+ export const ControlledExample = () => {
30
+ const { isOpen, title, message, showConfirmation, hideConfirmation, handleConfirm } =
31
+ useConfirmationPopup();
32
+
33
+ const handleDelete = () => {
34
+ console.log('Element supprimé!');
35
+ };
36
+
37
+ return (
38
+ <div>
39
+ <button
40
+ onClick={() =>
41
+ showConfirmation(
42
+ 'Supprimer cet élément ?',
43
+ 'Cette action est irréversible.',
44
+ handleDelete
45
+ )
46
+ }
47
+ >
48
+ Supprimer un élément
49
+ </button>
50
+
51
+ <ConfirmationPopup
52
+ isOpen={isOpen}
53
+ title={title}
54
+ message={message}
55
+ onConfirm={handleConfirm}
56
+ onCancel={hideConfirmation}
57
+ confirmText='Confirmer'
58
+ cancelText='Annuler'
59
+ type='danger'
60
+ />
61
+ </div>
62
+ );
63
+ };
64
+
65
+ export const DifferentTypes: Story = {
66
+ render: () => (
67
+ <div style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap' }}>
68
+ <ConfirmationPopup
69
+ isOpen={true}
70
+ title='Information'
71
+ message='Ceci est une information'
72
+ onConfirm={() => {}}
73
+ onCancel={() => {}}
74
+ type='info'
75
+ />
76
+ <ConfirmationPopup
77
+ isOpen={true}
78
+ title='Attention'
79
+ message='Ceci est un avertissement'
80
+ onConfirm={() => {}}
81
+ onCancel={() => {}}
82
+ type='warning'
83
+ />
84
+ <ConfirmationPopup
85
+ isOpen={true}
86
+ title='Danger'
87
+ message='Ceci est une action dangereuse'
88
+ onConfirm={() => {}}
89
+ onCancel={() => {}}
90
+ type='danger'
91
+ />
92
+ </div>
93
+ ),
94
+ };