@tsiky/components-r19 1.0.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 (287) hide show
  1. package/.prettierignore +4 -0
  2. package/.prettierrc +9 -0
  3. package/.storybook/main.ts +17 -0
  4. package/.storybook/preview.ts +21 -0
  5. package/.storybook/vitest.setup.ts +7 -0
  6. package/README.md +69 -0
  7. package/chart.ts +1 -0
  8. package/eslint.config.js +40 -0
  9. package/index.html +13 -0
  10. package/index.ts +33 -0
  11. package/package.json +63 -0
  12. package/public/vite.svg +1 -0
  13. package/src/App.css +42 -0
  14. package/src/App.tsx +12 -0
  15. package/src/assets/accessibility.png +0 -0
  16. package/src/assets/accessibility.svg +1 -0
  17. package/src/assets/addon-library.png +0 -0
  18. package/src/assets/assets.png +0 -0
  19. package/src/assets/avif-test-image.avif +0 -0
  20. package/src/assets/context.png +0 -0
  21. package/src/assets/discord.svg +1 -0
  22. package/src/assets/docs.png +0 -0
  23. package/src/assets/figma-plugin.png +0 -0
  24. package/src/assets/github.svg +1 -0
  25. package/src/assets/react.svg +1 -0
  26. package/src/assets/share.png +0 -0
  27. package/src/assets/styling.png +0 -0
  28. package/src/assets/testing.png +0 -0
  29. package/src/assets/theming.png +0 -0
  30. package/src/assets/tutorials.svg +1 -0
  31. package/src/assets/youtube.svg +1 -0
  32. package/src/components/AddItemModal/AddItemModal.module.css +72 -0
  33. package/src/components/AddItemModal/AddItemModal.tsx +82 -0
  34. package/src/components/AddItemModal/index.ts +1 -0
  35. package/src/components/Alert/Alert.css +54 -0
  36. package/src/components/Alert/Alert.stories.tsx +82 -0
  37. package/src/components/Alert/Alert.tsx +85 -0
  38. package/src/components/Alert/AlertContext.tsx +200 -0
  39. package/src/components/Alert/AlertModels.ts +34 -0
  40. package/src/components/Alert/index.ts +3 -0
  41. package/src/components/AnnouncementPanel/FlexRowContainer.css +17 -0
  42. package/src/components/AnnouncementPanel/FlexRowContainer.stories.tsx +329 -0
  43. package/src/components/AnnouncementPanel/FlexRowContainer.tsx +24 -0
  44. package/src/components/AnnouncementPanel/ListBox/CounterListBox.css +56 -0
  45. package/src/components/AnnouncementPanel/ListBox/CounterListBox.stories.tsx +292 -0
  46. package/src/components/AnnouncementPanel/ListBox/CounterListBox.tsx +106 -0
  47. package/src/components/AnnouncementPanel/ListBox/SimpleListBox.css +57 -0
  48. package/src/components/AnnouncementPanel/ListBox/SimpleListBox.stories.tsx +189 -0
  49. package/src/components/AnnouncementPanel/ListBox/SimpleListBox.tsx +138 -0
  50. package/src/components/AnnouncementPanel/ListBox/TrendListBox.css +61 -0
  51. package/src/components/AnnouncementPanel/ListBox/TrendListBox.stories.tsx +257 -0
  52. package/src/components/AnnouncementPanel/ListBox/TrendListBox.tsx +90 -0
  53. package/src/components/AnnouncementPanel/ListBox/index.ts +3 -0
  54. package/src/components/AnnouncementPanel/ListContentContainer.css +23 -0
  55. package/src/components/AnnouncementPanel/ListContentContainer.stories.tsx +212 -0
  56. package/src/components/AnnouncementPanel/ListContentContainer.tsx +33 -0
  57. package/src/components/AnnouncementPanel/index.ts +3 -0
  58. package/src/components/BandChart/index.tsx +282 -0
  59. package/src/components/Button/Button.module.css +165 -0
  60. package/src/components/Button/Button.stories.ts +132 -0
  61. package/src/components/Button/Button.tsx +55 -0
  62. package/src/components/Button/button.css +29 -0
  63. package/src/components/Button/index.ts +2 -0
  64. package/src/components/ChartContainer/ChartContainer.css +116 -0
  65. package/src/components/ChartContainer/ChartContainer.stories.tsx +159 -0
  66. package/src/components/ChartContainer/ChartContainer.tsx +155 -0
  67. package/src/components/ChartContainer/index.ts +1 -0
  68. package/src/components/Charts/area-chart-admission/AreaChartAdmission.stories.tsx +65 -0
  69. package/src/components/Charts/area-chart-admission/AreaChartAdmission.tsx +89 -0
  70. package/src/components/Charts/area-chart-admission/content.json +48 -0
  71. package/src/components/Charts/area-chart-hospitalisation/AreaChartHospitalisation.stories.tsx +141 -0
  72. package/src/components/Charts/area-chart-hospitalisation/AreaChartHospitalisation.tsx +262 -0
  73. package/src/components/Charts/area-chart-hospitalisation/content.json +55 -0
  74. package/src/components/Charts/bar-chart/BarChart.stories.tsx +50 -0
  75. package/src/components/Charts/bar-chart/BarChart.tsx +132 -0
  76. package/src/components/Charts/bar-chart/content.json +15 -0
  77. package/src/components/Charts/boxplot-chart/BoxPlotChart.stories.tsx +63 -0
  78. package/src/components/Charts/boxplot-chart/BoxPlotChart.tsx +114 -0
  79. package/src/components/Charts/boxplot-chart/boxUtils.ts +22 -0
  80. package/src/components/Charts/boxplot-chart/content.json +11 -0
  81. package/src/components/Charts/mixed-chart/MixedChart.stories.tsx +83 -0
  82. package/src/components/Charts/mixed-chart/MixedChart.tsx +625 -0
  83. package/src/components/Charts/mixed-chart/content.json +34 -0
  84. package/src/components/Charts/sankey-adaptation/sankey.tsx +70 -0
  85. package/src/components/Charts/sankey-chart/SankeyChart.stories.tsx +69 -0
  86. package/src/components/Charts/sankey-chart/SankeyChart.tsx +155 -0
  87. package/src/components/Charts/sankey-chart/content.json +15 -0
  88. package/src/components/Charts/stacked-column/StackedColumn.stories.tsx +72 -0
  89. package/src/components/Charts/stacked-column/StackedColumn.tsx +406 -0
  90. package/src/components/Charts/stacked-column/content.json +37 -0
  91. package/src/components/Charts/stacked-column-one-hundred-percent/StackedColumnOneHundredPercent.stories.tsx +43 -0
  92. package/src/components/Charts/stacked-column-one-hundred-percent/StackedColumnOneHundredPercent.tsx +75 -0
  93. package/src/components/Charts/stacked-column-one-hundred-percent/content.json +6 -0
  94. package/src/components/CircularProgress/CircularProgress.css +79 -0
  95. package/src/components/CircularProgress/CircularProgress.stories.tsx +251 -0
  96. package/src/components/CircularProgress/CircularProgress.tsx +101 -0
  97. package/src/components/CircularProgress/index.ts +2 -0
  98. package/src/components/Configure.mdx +369 -0
  99. package/src/components/DayStatCard/DayStatCard.css +50 -0
  100. package/src/components/DayStatCard/DayStatCard.stories.tsx +273 -0
  101. package/src/components/DayStatCard/DayStatCard.tsx +69 -0
  102. package/src/components/DayStatCard/index.ts +2 -0
  103. package/src/components/DraggableSwitcher/DraggableSwitcherButton.tsx +58 -0
  104. package/src/components/DraggableSwitcher/context/useDraggableSwitcher.tsx +45 -0
  105. package/src/components/DraggableSwitcher/index.ts +2 -0
  106. package/src/components/DropdownMenu/DropdownMenu.css +100 -0
  107. package/src/components/DropdownMenu/DropdownMenu.stories.tsx +174 -0
  108. package/src/components/DropdownMenu/DropdownMenu.tsx +106 -0
  109. package/src/components/DropdownMenu/index.ts +1 -0
  110. package/src/components/DynamicForm/DynamicFom.stories.ts +773 -0
  111. package/src/components/DynamicForm/DynamicForm.module.css +468 -0
  112. package/src/components/DynamicForm/DynamicForm.tsx +224 -0
  113. package/src/components/DynamicForm/index.ts +3 -0
  114. package/src/components/DynamicForm/tools/form-metadata.ts +82 -0
  115. package/src/components/DynamicForm/tools/validation.ts +168 -0
  116. package/src/components/DynamicInput/DynamicInput.module.css +126 -0
  117. package/src/components/DynamicInput/DynamicInput.stories.ts +350 -0
  118. package/src/components/DynamicInput/DynamicInput.tsx +144 -0
  119. package/src/components/DynamicInput/index.ts +2 -0
  120. package/src/components/DynamicInput/input/CheckboxInput.tsx +41 -0
  121. package/src/components/DynamicInput/input/ColorInput.tsx +46 -0
  122. package/src/components/DynamicInput/input/DateInput.tsx +57 -0
  123. package/src/components/DynamicInput/input/FileInput.tsx +174 -0
  124. package/src/components/DynamicInput/input/InputWrapper.tsx +26 -0
  125. package/src/components/DynamicInput/input/RadioInput.tsx +46 -0
  126. package/src/components/DynamicInput/input/RangeInput.tsx +46 -0
  127. package/src/components/DynamicInput/input/SelectInput.tsx +75 -0
  128. package/src/components/DynamicInput/input/TextInput.tsx +101 -0
  129. package/src/components/DynamicInput/input/TextareaInput.tsx +47 -0
  130. package/src/components/DynamicInput/input/assets/ColorInput.module.css +48 -0
  131. package/src/components/DynamicInput/input/assets/DateInput.module.css +83 -0
  132. package/src/components/DynamicInput/input/assets/FileInput.module.css +133 -0
  133. package/src/components/DynamicInput/input/assets/RangeInput.module.css +169 -0
  134. package/src/components/DynamicInput/input/assets/SelectInput.module.css +95 -0
  135. package/src/components/DynamicInput/input/index.ts +10 -0
  136. package/src/components/DynamicTable/AdvancedFilters.tsx +196 -0
  137. package/src/components/DynamicTable/ColumnSorter.tsx +185 -0
  138. package/src/components/DynamicTable/Pagination.tsx +115 -0
  139. package/src/components/DynamicTable/TableBody.tsx +42 -0
  140. package/src/components/DynamicTable/TableCell.tsx +30 -0
  141. package/src/components/DynamicTable/TableHeader.tsx +34 -0
  142. package/src/components/DynamicTable/TableRow.tsx +56 -0
  143. package/src/components/DynamicTable/TableauDynamic.stories.ts +1014 -0
  144. package/src/components/DynamicTable/TableauDynamique.module.css +1287 -0
  145. package/src/components/DynamicTable/TableauDynamique.tsx +154 -0
  146. package/src/components/DynamicTable/filters/BooleanFilter.tsx +30 -0
  147. package/src/components/DynamicTable/filters/DateFilter.tsx +28 -0
  148. package/src/components/DynamicTable/filters/DateRangeFilter.tsx +51 -0
  149. package/src/components/DynamicTable/filters/FilterRenderer.tsx +117 -0
  150. package/src/components/DynamicTable/filters/MultiSelectFilter.tsx +59 -0
  151. package/src/components/DynamicTable/filters/NumberFilter.tsx +37 -0
  152. package/src/components/DynamicTable/filters/OperatorFilter.tsx +64 -0
  153. package/src/components/DynamicTable/filters/SelectFilter.tsx +69 -0
  154. package/src/components/DynamicTable/filters/TextFilter.tsx +39 -0
  155. package/src/components/DynamicTable/filters/index.ts +9 -0
  156. package/src/components/DynamicTable/hooks/index.ts +2 -0
  157. package/src/components/DynamicTable/hooks/useAsyncActions.ts +36 -0
  158. package/src/components/DynamicTable/hooks/useFilters.ts +142 -0
  159. package/src/components/DynamicTable/hooks/useTableData.ts +216 -0
  160. package/src/components/DynamicTable/index.ts +11 -0
  161. package/src/components/DynamicTable/tools/filterTypes.ts +118 -0
  162. package/src/components/DynamicTable/tools/index.ts +3 -0
  163. package/src/components/DynamicTable/tools/tableConfig.ts +96 -0
  164. package/src/components/DynamicTable/tools/tableTypes.ts +63 -0
  165. package/src/components/EntryControl/EntryControl.module.css +218 -0
  166. package/src/components/EntryControl/EntryControl.stories.tsx +71 -0
  167. package/src/components/EntryControl/EntryControl.tsx +117 -0
  168. package/src/components/EntryControl/index.ts +2 -0
  169. package/src/components/Grid/Grid.stories.tsx +94 -0
  170. package/src/components/Grid/Grid.tsx +214 -0
  171. package/src/components/Grid/grid.css +285 -0
  172. package/src/components/Grid/index.ts +2 -0
  173. package/src/components/Header/Header.stories.tsx +164 -0
  174. package/src/components/Header/Header.tsx +59 -0
  175. package/src/components/Header/header.css +31 -0
  176. package/src/components/Header/index.ts +1 -0
  177. package/src/components/IconText/IconText..stories.tsx +135 -0
  178. package/src/components/IconText/IconText.css +43 -0
  179. package/src/components/IconText/IconText.tsx +43 -0
  180. package/src/components/IconText/index.ts +1 -0
  181. package/src/components/LanguageSelector/LanguageSelector.css +31 -0
  182. package/src/components/LanguageSelector/LanguageSelector.stories.tsx +38 -0
  183. package/src/components/LanguageSelector/LanguageSelector.tsx +37 -0
  184. package/src/components/LanguageSelector/index.ts +1 -0
  185. package/src/components/Logo/Logo.css +89 -0
  186. package/src/components/Logo/Logo.stories.tsx +79 -0
  187. package/src/components/Logo/Logo.tsx +22 -0
  188. package/src/components/Logo/index.ts +2 -0
  189. package/src/components/MetricsPanel/MetricsItem.tsx +128 -0
  190. package/src/components/MetricsPanel/MetricsPanel.module.css +636 -0
  191. package/src/components/MetricsPanel/MetricsPanel.stories.tsx +692 -0
  192. package/src/components/MetricsPanel/MetricsPanel.tsx +282 -0
  193. package/src/components/MetricsPanel/PanelHeader.tsx +19 -0
  194. package/src/components/MetricsPanel/SummaryCard.tsx +61 -0
  195. package/src/components/MetricsPanel/index.ts +4 -0
  196. package/src/components/MetricsPanel/renderers/CompactRenderer.tsx +125 -0
  197. package/src/components/MetricsPanel/renderers/ImageCard.tsx +62 -0
  198. package/src/components/MetricsPanel/renderers/PertinenceCard.tsx +55 -0
  199. package/src/components/MetricsPanel/tools/MetricsPanelTypes.ts +62 -0
  200. package/src/components/MetricsPanel/tools/chooseDefaultRender.ts +50 -0
  201. package/src/components/MetricsPanel/tools/colorUtils.ts +39 -0
  202. package/src/components/MetricsPanel/tools/index.ts +2 -0
  203. package/src/components/ModuleHeader/ModuleHeader.css +37 -0
  204. package/src/components/ModuleHeader/ModuleHeader.stories.tsx +37 -0
  205. package/src/components/ModuleHeader/ModuleHeader.tsx +42 -0
  206. package/src/components/ModuleHeader/index.ts +1 -0
  207. package/src/components/ModuleSideBar/ModuleSideBar.css +227 -0
  208. package/src/components/ModuleSideBar/ModuleSideBar.stories.tsx +40 -0
  209. package/src/components/ModuleSideBar/ModuleSideBar.tsx +155 -0
  210. package/src/components/ModuleSideBar/index.ts +1 -0
  211. package/src/components/NavBar/NavBar.css +58 -0
  212. package/src/components/NavBar/NavBar.stories.tsx +169 -0
  213. package/src/components/NavBar/NavBar.tsx +100 -0
  214. package/src/components/NavBar/NavContext.tsx +30 -0
  215. package/src/components/NavBar/index.ts +2 -0
  216. package/src/components/NavItem/NavItem.css +29 -0
  217. package/src/components/NavItem/NavItem.tsx +58 -0
  218. package/src/components/NavItem/index.ts +1 -0
  219. package/src/components/Page/Dashboard.tsx +93 -0
  220. package/src/components/Page/Page.stories.ts +33 -0
  221. package/src/components/Page/Page.tsx +73 -0
  222. package/src/components/Page/page.css +81 -0
  223. package/src/components/PerformanceCard/PerformanceCard.module.css +232 -0
  224. package/src/components/PerformanceCard/PerformanceCard.stories.tsx +441 -0
  225. package/src/components/PerformanceCard/PerformanceCard.tsx +198 -0
  226. package/src/components/PerformanceCard/defaultHistogramRenderer.tsx +32 -0
  227. package/src/components/PerformanceCard/tools/types.ts +50 -0
  228. package/src/components/PerformanceCard/tools/usePerformanceCard.ts +93 -0
  229. package/src/components/PeriodRange/PeriodRange.module.css +158 -0
  230. package/src/components/PeriodRange/PeriodRange.stories.tsx +66 -0
  231. package/src/components/PeriodRange/PeriodRange.tsx +130 -0
  232. package/src/components/PeriodSelect/PeriodSelect.module.css +65 -0
  233. package/src/components/PeriodSelect/PeriodSelect.stories.tsx +40 -0
  234. package/src/components/PeriodSelect/PeriodSelect.tsx +42 -0
  235. package/src/components/PeriodSelect/index.ts +1 -0
  236. package/src/components/ScrollableHorizontale/ScrollableHorizontale.css +40 -0
  237. package/src/components/ScrollableHorizontale/ScrollableHorizontale.stories.tsx +133 -0
  238. package/src/components/ScrollableHorizontale/ScrollableHorizontale.tsx +29 -0
  239. package/src/components/ScrollableHorizontale/index.ts +1 -0
  240. package/src/components/SearchBar/SearchBar.css +40 -0
  241. package/src/components/SearchBar/SearchBar.stories.tsx +36 -0
  242. package/src/components/SearchBar/SearchBar.tsx +30 -0
  243. package/src/components/SearchBar/index.ts +1 -0
  244. package/src/components/SectionTitle/SectionTitle.css +21 -0
  245. package/src/components/SectionTitle/SectionTitle.stories.tsx +39 -0
  246. package/src/components/SectionTitle/SectionTitle.tsx +18 -0
  247. package/src/components/SideComponent/PatientEditor.tsx +64 -0
  248. package/src/components/SideComponent/SideComponent.css +179 -0
  249. package/src/components/SideComponent/SideComponent.stories.tsx +547 -0
  250. package/src/components/SideComponent/SideComponent.tsx +243 -0
  251. package/src/components/SideComponent/hooks/useBodyScrollLock.ts +15 -0
  252. package/src/components/SideComponent/index.ts +2 -0
  253. package/src/components/SideComponent/portal.ts +11 -0
  254. package/src/components/SubNavBar/SubNavBar.tsx +41 -0
  255. package/src/components/SubNavBar/index.ts +1 -0
  256. package/src/components/Switcher/Switcher.css +65 -0
  257. package/src/components/Switcher/Switcher.stories.tsx +153 -0
  258. package/src/components/Switcher/Switcher.tsx +83 -0
  259. package/src/components/Switcher/index.ts +1 -0
  260. package/src/components/Title/Title.stories.tsx +18 -0
  261. package/src/components/Title/Title.tsx +26 -0
  262. package/src/components/Title/index.ts +1 -0
  263. package/src/components/TranslationKey/TranslationKey.css +272 -0
  264. package/src/components/TranslationKey/TranslationKey.stories.tsx +50 -0
  265. package/src/components/TranslationKey/TranslationKey.tsx +245 -0
  266. package/src/components/TranslationKey/index.ts +1 -0
  267. package/src/components/TrendItem/TrendItem.css +36 -0
  268. package/src/components/TrendItem/TrendItem.stories.tsx +276 -0
  269. package/src/components/TrendItem/TrendItem.tsx +46 -0
  270. package/src/components/TrendItem/index.ts +1 -0
  271. package/src/components/TrendList/TrendList.css +16 -0
  272. package/src/components/TrendList/TrendList.stories.tsx +337 -0
  273. package/src/components/TrendList/TrendList.tsx +45 -0
  274. package/src/components/TrendList/index.ts +1 -0
  275. package/src/components/theme/ThemeSwitcherButton.tsx +64 -0
  276. package/src/components/theme/context/ThemeContext.tsx +61 -0
  277. package/src/components/theme/context/index.ts +2 -0
  278. package/src/components/theme/context/useThemeSwitcher.ts +18 -0
  279. package/src/components/theme/index.ts +1 -0
  280. package/src/index.css +68 -0
  281. package/src/main.tsx +10 -0
  282. package/src/vite-env.d.ts +1 -0
  283. package/tsconfig.app.json +27 -0
  284. package/tsconfig.json +4 -0
  285. package/tsconfig.node.json +25 -0
  286. package/vite.config.ts +43 -0
  287. package/vitest.shims.d.ts +1 -0
@@ -0,0 +1,141 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react-vite';
3
+ import HospitalisationPage, {
4
+ HospitalisationChart,
5
+ type HospitalisationChartProps,
6
+ } from './AreaChartHospitalisation';
7
+
8
+ // importer les données fournies (content.json placé à côté de ce fichier)
9
+ import content from './AreaChartHospitalisation.json';
10
+
11
+ /**
12
+ * Meta (CSF) pour Storybook
13
+ */
14
+ const meta: Meta<typeof HospitalisationChart> = {
15
+ title: 'Charts/AreaChartHospitalisation',
16
+ component: HospitalisationChart,
17
+ tags: ['autodocs'],
18
+ argTypes: {
19
+ height: {
20
+ control: { type: 'number', min: 100, max: 800, step: 10 },
21
+ },
22
+ // Les props labels/series sont complexes : on évite le contrôle direct
23
+ labels: { control: false },
24
+ series: { control: false },
25
+ },
26
+ parameters: {
27
+ // layout responsive par défaut (le composant gère ses breakpoints)
28
+ layout: 'centered',
29
+ },
30
+ };
31
+
32
+ export default meta;
33
+ type Story = StoryObj<typeof HospitalisationChart>;
34
+
35
+ /**
36
+ * Données issues de content.json
37
+ * - content.labels : string[]
38
+ * - content.series : { name: string; data: number[] }[]
39
+ */
40
+ const contentData = content as { labels: string[]; series: HospitalisationChartProps['series'] };
41
+
42
+ const sampleLabels: string[] = contentData.labels;
43
+ const sampleSeries: HospitalisationChartProps['series'] = contentData.series;
44
+
45
+ /**
46
+ * Story principale : le chart seul (avec tes données réelles)
47
+ */
48
+ export const Default: Story = {
49
+ args: {
50
+ labels: sampleLabels,
51
+ series: sampleSeries,
52
+ height: 440,
53
+ } as HospitalisationChartProps,
54
+ };
55
+
56
+ /**
57
+ * Variantes pour vérifier l'adaptation aux différentes tailles d'écran.
58
+ * Ces stories enveloppent le composant dans un conteneur de largeur fixe
59
+ * pour simuler Desktop / Tablet / Mobile.
60
+ */
61
+
62
+ export const Desktop: Story = {
63
+ render: (args) => (
64
+ <div style={{ width: 1200, margin: '0 auto', padding: 24, background: '#f3f4f6' }}>
65
+ <div style={{ maxWidth: '100%', margin: '0 auto' }}>
66
+ <HospitalisationChart {...(args as HospitalisationChartProps)} />
67
+ </div>
68
+ </div>
69
+ ),
70
+ args: {
71
+ labels: sampleLabels,
72
+ series: sampleSeries,
73
+ height: 480,
74
+ } as HospitalisationChartProps,
75
+ parameters: {
76
+ docs: {
77
+ description: { story: 'Vue Desktop (simulée, largeur 1200px).' },
78
+ },
79
+ },
80
+ };
81
+
82
+ export const Tablet: Story = {
83
+ render: (args) => (
84
+ <div style={{ width: 768, margin: '0 auto', padding: 16, background: '#f3f4f6' }}>
85
+ <div style={{ maxWidth: '100%', margin: '0 auto' }}>
86
+ <HospitalisationChart {...(args as HospitalisationChartProps)} />
87
+ </div>
88
+ </div>
89
+ ),
90
+ args: {
91
+ labels: sampleLabels,
92
+ series: sampleSeries,
93
+ height: 420,
94
+ } as HospitalisationChartProps,
95
+ parameters: {
96
+ docs: {
97
+ description: { story: 'Vue Tablet (simulée, largeur 768px).' },
98
+ },
99
+ },
100
+ };
101
+
102
+ export const Mobile: Story = {
103
+ render: (args) => (
104
+ <div style={{ width: 375, margin: '0 auto', padding: 12, background: '#f3f4f6' }}>
105
+ <div style={{ maxWidth: '100%', margin: '0 auto' }}>
106
+ <HospitalisationChart {...(args as HospitalisationChartProps)} />
107
+ </div>
108
+ </div>
109
+ ),
110
+ args: {
111
+ labels: sampleLabels,
112
+ series: sampleSeries,
113
+ height: 320,
114
+ } as HospitalisationChartProps,
115
+ parameters: {
116
+ docs: {
117
+ description: { story: 'Vue Mobile (simulée, largeur 375px).' },
118
+ },
119
+ },
120
+ };
121
+
122
+ /**
123
+ * Story : aperçu de la page complète (dropdown + carte)
124
+ * On continue d'utiliser la page complète qui tente de charger le JSON depuis /hospitalisationData.json
125
+ */
126
+ export const PageView = {
127
+ render: () => (
128
+ <div style={{ background: '#f3f4f6', padding: 24 }}>
129
+ <div style={{ maxWidth: 1200, margin: '0 auto' }}>
130
+ <HospitalisationPage />
131
+ </div>
132
+ </div>
133
+ ),
134
+ parameters: {
135
+ docs: {
136
+ description: {
137
+ story: 'Rendu complet de la page `HospitalisationPage` (titre centré, dropdown, carte).',
138
+ },
139
+ },
140
+ },
141
+ };
@@ -0,0 +1,262 @@
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
+ import Chart from 'react-apexcharts';
3
+ import type { ApexOptions } from 'apexcharts';
4
+
5
+ export type SeriesItem = {
6
+ name: string;
7
+ data: number[];
8
+ };
9
+
10
+ export interface HospitalisationChartProps {
11
+ labels: string[];
12
+ series: SeriesItem[];
13
+ height?: number;
14
+ }
15
+
16
+ const defaultColors = ['#e64a19', '#f0a500', '#66e0f0', '#1e63ff']; // 0-6 / 6-12 / 12-18 / 18-0
17
+
18
+ export const HospitalisationChart: React.FC<HospitalisationChartProps> = ({
19
+ labels,
20
+ series,
21
+ height = 420,
22
+ }) => {
23
+ const options: ApexOptions = {
24
+ chart: {
25
+ type: 'area',
26
+ stacked: true,
27
+ toolbar: { show: false },
28
+ zoom: { enabled: false },
29
+ animations: { enabled: true },
30
+ },
31
+ stroke: {
32
+ curve: 'smooth',
33
+ width: 1.6,
34
+ },
35
+ fill: {
36
+ type: 'solid',
37
+ },
38
+ colors: defaultColors,
39
+ legend: {
40
+ show: true,
41
+ position: 'top',
42
+ horizontalAlign: 'center',
43
+ offsetY: 0,
44
+ labels: {
45
+ useSeriesColors: false,
46
+ },
47
+ markers: {
48
+ /*width: 16,
49
+ height: 12,
50
+ radius: 3,*/
51
+ },
52
+ },
53
+ xaxis: {
54
+ categories: labels,
55
+ labels: {
56
+ rotate: -45,
57
+ rotateAlways: true,
58
+ trim: true,
59
+ style: {
60
+ fontSize: '11px',
61
+ },
62
+ },
63
+ tickPlacement: 'on',
64
+ tooltip: { enabled: false },
65
+ },
66
+ yaxis: {
67
+ min: 0,
68
+ tickAmount: 6,
69
+ labels: {
70
+ // Apex y-axis formatter signature: (val: number) => string
71
+ formatter: (val: number) => `${Math.round(Number(val))}`,
72
+ },
73
+ },
74
+ grid: {
75
+ borderColor: '#e9e9e9',
76
+ row: {
77
+ colors: undefined,
78
+ },
79
+ },
80
+ dataLabels: { enabled: false },
81
+ markers: {
82
+ size: 0,
83
+ },
84
+ tooltip: {
85
+ shared: true,
86
+ intersect: false,
87
+ },
88
+ responsive: [
89
+ {
90
+ breakpoint: 1024,
91
+ options: {
92
+ chart: { height: Math.max(300, Math.round(height * 0.75)) },
93
+ xaxis: { labels: { rotate: -45 } },
94
+ },
95
+ },
96
+ {
97
+ breakpoint: 480,
98
+ options: {
99
+ chart: { height: 300 },
100
+ legend: { position: 'top' },
101
+ xaxis: { labels: { rotate: -45, style: { fontSize: '10px' } } },
102
+ },
103
+ },
104
+ ],
105
+ };
106
+
107
+ return <Chart options={options} series={series} type='area' height={height} width='100%' />;
108
+ };
109
+
110
+ /* ---------- Utils & Page ---------- */
111
+
112
+ function generateWeeklyLabels(start: string, end: string) {
113
+ const s = new Date(start);
114
+ const e = new Date(end);
115
+ const labels: string[] = [];
116
+ for (let d = new Date(s); d <= e; d.setDate(d.getDate() + 7)) {
117
+ labels.push(d.toLocaleDateString('fr-FR', { month: 'short', day: 'numeric' }).replace('.', ''));
118
+ }
119
+ return labels;
120
+ }
121
+
122
+ function randomSeries(length: number, min: number, max: number) {
123
+ return Array.from({ length }, () => Math.max(0, Math.round(min + Math.random() * (max - min))));
124
+ }
125
+
126
+ /** Type guard pour valider le JSON sans utiliser `any` */
127
+ const isSeriesItem = (s: unknown): s is SeriesItem => {
128
+ if (typeof s !== 'object' || s === null) return false;
129
+ const rec = s as Record<string, unknown>;
130
+ return (
131
+ typeof rec.name === 'string' &&
132
+ Array.isArray(rec.data) &&
133
+ rec.data.every((n: unknown) => typeof n === 'number')
134
+ );
135
+ };
136
+
137
+ const isHospitalisationJson = (obj: unknown): obj is { labels: string[]; series: SeriesItem[] } => {
138
+ if (typeof obj !== 'object' || obj === null) return false;
139
+ const rec = obj as Record<string, unknown>;
140
+ return (
141
+ Array.isArray(rec.labels) &&
142
+ rec.labels.every((l: unknown) => typeof l === 'string') &&
143
+ Array.isArray(rec.series) &&
144
+ rec.series.every((s: unknown) => isSeriesItem(s))
145
+ );
146
+ };
147
+
148
+ export const HospitalisationPage: React.FC = () => {
149
+ const [zone, setZone] = useState<string>('inconue');
150
+ const [dataFromJson, setDataFromJson] = useState<{
151
+ labels: string[];
152
+ series: SeriesItem[];
153
+ } | null>(null);
154
+
155
+ // fallback labels (same range que ton exemple)
156
+ const fallbackLabels = useMemo(() => generateWeeklyLabels('2024-02-21', '2024-08-11'), []);
157
+ const fallbackSeries = useMemo(() => {
158
+ const n = fallbackLabels.length;
159
+ return [
160
+ { name: '0h-6h', data: randomSeries(n, 4, 14) },
161
+ { name: '6h-12h', data: randomSeries(n, 6, 14) },
162
+ { name: '12h-18h', data: randomSeries(n, 8, 26) },
163
+ { name: '18h-0h', data: randomSeries(n, 12, 36) },
164
+ ];
165
+ }, [fallbackLabels]);
166
+
167
+ // Essayer de charger /hospitalisationData.json depuis le dossier public
168
+ useEffect(() => {
169
+ let mounted = true;
170
+ fetch('/hospitalisationData.json')
171
+ .then((res) => {
172
+ if (!res.ok) throw new Error('not found');
173
+ return res.json();
174
+ })
175
+ .then((json) => {
176
+ // validation minimale sans any
177
+ if (mounted && isHospitalisationJson(json)) {
178
+ setDataFromJson({ labels: json.labels, series: json.series });
179
+ } else {
180
+ setDataFromJson(null);
181
+ }
182
+ })
183
+ .catch(() => {
184
+ // fichier non trouvé ou invalide -> on reste sur les données de secours
185
+ setDataFromJson(null);
186
+ });
187
+
188
+ return () => {
189
+ mounted = false;
190
+ };
191
+ }, []);
192
+
193
+ const labels = dataFromJson ? dataFromJson.labels : fallbackLabels;
194
+ const series = dataFromJson ? dataFromJson.series : fallbackSeries;
195
+
196
+ return (
197
+ <div style={{ maxWidth: 1200, margin: '0 auto', padding: '24px 12px' }}>
198
+ <h1
199
+ style={{
200
+ textAlign: 'center',
201
+ fontSize: 56,
202
+ margin: '8px 0 18px',
203
+ color: '#5a5a5a',
204
+ fontWeight: 700,
205
+ letterSpacing: -1,
206
+ }}
207
+ >
208
+ Hospitalisations
209
+ </h1>
210
+
211
+ <div style={{ display: 'flex', justifyContent: 'center', marginBottom: 14 }}>
212
+ <div
213
+ style={{
214
+ display: 'inline-flex',
215
+ alignItems: 'center',
216
+ border: '3px solid #3b82f6',
217
+ borderRadius: 10,
218
+ padding: '6px 12px',
219
+ minWidth: 260,
220
+ background: '#fff',
221
+ boxShadow: '0 6px 10px rgba(59,130,246,0.08)',
222
+ }}
223
+ >
224
+ <select
225
+ value={zone}
226
+ onChange={(e) => setZone(e.target.value)}
227
+ style={{
228
+ border: 'none',
229
+ outline: 'none',
230
+ fontSize: 18,
231
+ padding: '6px 8px',
232
+ flex: 1,
233
+ appearance: 'none',
234
+ WebkitAppearance: 'none',
235
+ MozAppearance: 'none',
236
+ background: 'transparent',
237
+ cursor: 'pointer',
238
+ }}
239
+ >
240
+ <option value='inconue'>inconue</option>
241
+ <option value='regionA'>Region A</option>
242
+ <option value='regionB'>Region B</option>
243
+ </select>
244
+ <div style={{ marginLeft: 8, transform: 'scale(1.1)' }}>▾</div>
245
+ </div>
246
+ </div>
247
+
248
+ <div
249
+ style={{
250
+ background: '#fff',
251
+ borderRadius: 14,
252
+ padding: '18px 18px 10px',
253
+ boxShadow: '0 8px 20px rgba(0,0,0,0.06)',
254
+ }}
255
+ >
256
+ <HospitalisationChart labels={labels} series={series} height={440} />
257
+ </div>
258
+ </div>
259
+ );
260
+ };
261
+
262
+ export default HospitalisationPage;
@@ -0,0 +1,55 @@
1
+ {
2
+ "labels": [
3
+ "21 févr",
4
+ "28 févr",
5
+ "6 mars",
6
+ "13 mars",
7
+ "20 mars",
8
+ "27 mars",
9
+ "3 avr",
10
+ "10 avr",
11
+ "17 avr",
12
+ "24 avr",
13
+ "1 mai",
14
+ "8 mai",
15
+ "15 mai",
16
+ "22 mai",
17
+ "29 mai",
18
+ "5 juin",
19
+ "12 juin",
20
+ "19 juin",
21
+ "26 juin",
22
+ "3 juil",
23
+ "10 juil",
24
+ "17 juil",
25
+ "24 juil",
26
+ "31 juil",
27
+ "7 août"
28
+ ],
29
+ "series": [
30
+ {
31
+ "name": "0h-6h",
32
+ "data": [4, 7, 5, 6, 8, 9, 7, 10, 12, 6, 5, 8, 9, 6, 7, 10, 8, 11, 12, 13, 9, 8, 7, 6, 5]
33
+ },
34
+ {
35
+ "name": "6h-12h",
36
+ "data": [
37
+ 6, 8, 10, 7, 9, 12, 11, 10, 14, 13, 12, 10, 11, 12, 13, 10, 11, 12, 13, 14, 12, 11, 9, 10, 8
38
+ ]
39
+ },
40
+ {
41
+ "name": "12h-18h",
42
+ "data": [
43
+ 10, 12, 15, 14, 16, 18, 17, 20, 22, 19, 21, 18, 20, 19, 21, 23, 22, 24, 26, 25, 23, 22, 20,
44
+ 19, 18
45
+ ]
46
+ },
47
+ {
48
+ "name": "18h-0h",
49
+ "data": [
50
+ 15, 18, 20, 19, 22, 24, 23, 26, 28, 25, 29, 26, 28, 30, 27, 28, 32, 30, 31, 34, 32, 30, 28,
51
+ 26, 25
52
+ ]
53
+ }
54
+ ]
55
+ }
@@ -0,0 +1,50 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import HorizontalBarChart, { type HorizontalBarData, type HorizontalBarConfig } from './BarChart';
3
+ import demoContent from './content.json';
4
+
5
+ const demoData: HorizontalBarData = {
6
+ labels: demoContent.labels,
7
+ values: demoContent.values,
8
+ };
9
+
10
+ const defaultCfg: HorizontalBarConfig = {
11
+ color: '#5f9ec4',
12
+ sort: 'desc',
13
+ height: 520,
14
+ showGrid: true,
15
+ showLegend: false,
16
+ };
17
+
18
+ const meta: Meta<typeof HorizontalBarChart> = {
19
+ title: 'Charts/HorizontalBarChart',
20
+ component: HorizontalBarChart,
21
+ tags: ['autodocs'],
22
+ argTypes: {
23
+ data: { control: 'object' },
24
+ config: { control: 'object' },
25
+ },
26
+ };
27
+
28
+ export default meta;
29
+ type Story = StoryObj<typeof HorizontalBarChart>;
30
+
31
+ export const Default: Story = {
32
+ args: {
33
+ data: demoData,
34
+ config: defaultCfg,
35
+ },
36
+ };
37
+
38
+ export const NoGrid: Story = {
39
+ args: {
40
+ data: demoData,
41
+ config: { ...defaultCfg, showGrid: false, color: '#7cb342' },
42
+ },
43
+ };
44
+
45
+ export const Small: Story = {
46
+ args: {
47
+ data: { labels: demoData.labels.slice(0, 6), values: demoData.values.slice(0, 6) },
48
+ config: { ...defaultCfg, height: 360, color: '#ff7043' },
49
+ },
50
+ };
@@ -0,0 +1,132 @@
1
+ import React from 'react';
2
+ import Chart from 'react-apexcharts';
3
+ import type { ApexOptions } from 'apexcharts';
4
+
5
+ export interface HorizontalBarData {
6
+ labels: string[];
7
+ values: number[];
8
+ }
9
+
10
+ export interface HorizontalBarConfig {
11
+ color?: string;
12
+ sort?: 'desc' | 'asc' | null;
13
+ height?: number;
14
+ showGrid?: boolean;
15
+ showLegend?: boolean;
16
+ }
17
+
18
+ interface Props {
19
+ data: HorizontalBarData;
20
+ config?: HorizontalBarConfig;
21
+ }
22
+
23
+ /** Default (local) config */
24
+ const defaultConfig: HorizontalBarConfig = {
25
+ color: '#4f9db5',
26
+ sort: 'desc',
27
+ height: 520,
28
+ showGrid: true,
29
+ showLegend: false,
30
+ };
31
+
32
+ /** Série locale (évite d'importer ApexAxisChartSeries) */
33
+ type HBarSeries = ReadonlyArray<{
34
+ name: string;
35
+ data: ReadonlyArray<number>;
36
+ }>;
37
+
38
+ const HorizontalBarChart: React.FC<Props> = ({ data, config = defaultConfig }) => {
39
+ const cfg: HorizontalBarConfig = { ...defaultConfig, ...config };
40
+
41
+ const labels = data.labels ?? [];
42
+ const values = data.values ?? [];
43
+
44
+ // normalize lengths
45
+ const len = Math.min(labels.length, values.length);
46
+ const pairs: { label: string; value: number }[] = [];
47
+ for (let i = 0; i < len; i++) pairs.push({ label: labels[i], value: values[i] });
48
+
49
+ // optional sorting
50
+ if (cfg.sort === 'desc') pairs.sort((a, b) => b.value - a.value);
51
+ else if (cfg.sort === 'asc') pairs.sort((a, b) => a.value - b.value);
52
+
53
+ const labelsSorted = pairs.map((p) => p.label);
54
+ const valuesSorted = pairs.map((p) => p.value);
55
+
56
+ const series: HBarSeries = [
57
+ {
58
+ name: 'Valeur',
59
+ data: valuesSorted,
60
+ },
61
+ ];
62
+
63
+ const options: ApexOptions = {
64
+ chart: {
65
+ foreColor: 'var(--color-text)',
66
+ type: 'bar',
67
+ toolbar: { show: false },
68
+ height: cfg.height,
69
+ },
70
+ plotOptions: {
71
+ bar: {
72
+ horizontal: true,
73
+ barHeight: '60%',
74
+ distributed: false,
75
+ borderRadius: 6,
76
+ borderRadiusApplication: 'end',
77
+ },
78
+ },
79
+ dataLabels: {
80
+ enabled: false,
81
+ formatter: (val: number) => String(val),
82
+ style: { fontSize: '12px' },
83
+ offsetX: 0,
84
+ },
85
+ yaxis: {
86
+ labels: { style: { fontSize: '12px' } },
87
+ },
88
+ grid: {
89
+ show: !!cfg.showGrid,
90
+ borderColor: '#e6e6e6',
91
+ },
92
+ tooltip: {
93
+ shared: false,
94
+ y: { formatter: (val: number) => String(val) },
95
+ },
96
+ legend: { show: !!cfg.showLegend },
97
+ colors: [cfg.color],
98
+ xaxis: {
99
+ min: 0,
100
+ tickAmount: 5,
101
+ categories: labelsSorted,
102
+ labels: { formatter: (v: string | number) => String(v) },
103
+ },
104
+ responsive: [
105
+ // {
106
+ // breakpoint: 1024,
107
+ // options: {
108
+ // plotOptions: { bar: { barHeight: '52%' } },
109
+ // chart: { height: Math.max(300, Math.round((cfg.height ?? 520) * 0.75)), width: 520 },
110
+ // },
111
+ // },
112
+ // {
113
+ // breakpoint: 768,
114
+ // options: {
115
+ // plotOptions: { bar: { barHeight: '48%' } },
116
+ // chart: { height: Math.max(260, Math.round((cfg.height ?? 520) * 0.6)), width: 360 },
117
+ // },
118
+ // },
119
+ ],
120
+ };
121
+
122
+ return (
123
+ <Chart
124
+ options={options}
125
+ series={series as unknown as ApexOptions['series']}
126
+ type='bar'
127
+ height={cfg.height}
128
+ />
129
+ );
130
+ };
131
+
132
+ export default HorizontalBarChart;
@@ -0,0 +1,15 @@
1
+ {
2
+ "labels": [
3
+ "URGENCES ZSTCD",
4
+ "UNITE DE MEDECINE AIGUE GERIATRIQUE HC",
5
+ "MALADIES APPAREIL DIGESTIF ET NUTRITION HC",
6
+ "CARDIOLOGIE HC",
7
+ "NEUROLOGIE VASCULAIRE HC",
8
+ "CHIRURGIE ORTHOPEDIQUE ET TRAUMATOLOGIE B HC",
9
+ "CHIRURGIE ORTHOPEDIQUE ET TRAUMATOLOGIE A HC",
10
+ "NEUROLOGIE AIGUE HORS VASCULAIRE HC",
11
+ "UNITE DE SOINS ANXIETE DEPRESSION 5A",
12
+ "UNITE DE MALADIES INFECTIEUSES ET TROPICALES HC"
13
+ ],
14
+ "values": [8800, 1200, 1100, 1050, 800, 550, 520, 420, 320, 150]
15
+ }