@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,547 @@
1
+ /**
2
+ * Notes:
3
+ * - SideComponent is inline-only and covers its parent. Parent MUST have `position: relative`.
4
+ * - No external focus-trap used here. If you install `focus-trap-react`, you can
5
+ * integrate it inside the component and add a story for it.
6
+ */
7
+ import type { Meta, StoryObj } from '@storybook/react-vite';
8
+ import React, { useRef, useEffect, useState } from 'react';
9
+ import SideComponent, { type SideComponentRef, type SideComponentProps } from './SideComponent';
10
+ import './SideComponent.css';
11
+
12
+ const meta: Meta<typeof SideComponent> = {
13
+ title: 'Components/SideComponent',
14
+ component: SideComponent,
15
+ parameters: { layout: 'padded' },
16
+ tags: ['autodocs'],
17
+ argTypes: {
18
+ title: { control: 'text' },
19
+ subtitle: { control: 'text' },
20
+ size: { control: 'text' },
21
+ closeOnOverlayClick: { control: 'boolean' },
22
+ showCloseButton: { control: 'boolean' },
23
+ },
24
+ };
25
+ export default meta;
26
+ type Story = StoryObj<typeof SideComponent>;
27
+
28
+ /* Shared example content used by many stories */
29
+ const ExampleContent = (
30
+ <div style={{ padding: 16, minHeight: 480 }}>
31
+ <div style={{ background: '#eef6fb', padding: 12, borderRadius: 6, marginBottom: 12 }}>
32
+ <strong>GENDER : M</strong> <span style={{ marginLeft: 18 }} /> <strong>AGE : 42</strong>
33
+ </div>
34
+
35
+ <div style={{ marginBottom: 12 }}>
36
+ <label style={{ display: 'block', marginBottom: 6 }}>Destination*</label>
37
+ <div className='select-wrapper'>
38
+ <select>
39
+ <option>Select a destination</option>
40
+ <option>Cardiology</option>
41
+ <option>Geriatrics</option>
42
+ </select>
43
+ </div>
44
+ </div>
45
+
46
+ <div style={{ marginTop: 8 }}>
47
+ <div style={{ marginBottom: 6, fontWeight: 600 }}>Stretchering</div>
48
+ <label style={{ display: 'block', marginBottom: 6 }}>
49
+ <input type='radio' name='s' defaultChecked /> No
50
+ </label>
51
+ <label style={{ display: 'block', marginBottom: 6 }}>
52
+ <input type='radio' name='s' /> By Saniia
53
+ </label>
54
+ <label style={{ display: 'block' }}>
55
+ <input type='radio' name='s' /> Yes
56
+ </label>
57
+ </div>
58
+ </div>
59
+ );
60
+
61
+ /** 1) DefaultOpen — opens on mount for quick visual check */
62
+ export const DefaultOpen: Story = {
63
+ render: (args) => {
64
+ const ref = React.createRef<SideComponentRef>();
65
+ useEffect(() => {
66
+ ref.current?.open();
67
+ // eslint-disable-next-line react-hooks/exhaustive-deps
68
+ }, []);
69
+ return (
70
+ <div
71
+ style={{
72
+ width: 700,
73
+ margin: '24px auto',
74
+ position: 'relative',
75
+ border: '1px solid #e6e6e6',
76
+ padding: 16,
77
+ minHeight: 480,
78
+ }}
79
+ >
80
+ <p style={{ marginTop: 0 }}>
81
+ Parent container — SideComponent will cover only this parent.
82
+ </p>
83
+ <SideComponent ref={ref} {...(args as SideComponentProps)}>
84
+ {ExampleContent}
85
+ </SideComponent>
86
+ </div>
87
+ );
88
+ },
89
+ args: {
90
+ title: 'Edit Patient',
91
+ subtitle: 'John WICK - IEP: 26',
92
+ size: '420px',
93
+ },
94
+ tags: ['autodocs'],
95
+ };
96
+
97
+ /** 2) WithButton — open/close using an external button (typical usage) */
98
+ export const WithButton: Story = {
99
+ render: () => {
100
+ const ref = useRef<SideComponentRef | null>(null);
101
+ return (
102
+ <div
103
+ style={{
104
+ width: 700,
105
+ margin: '24px auto',
106
+ position: 'relative',
107
+ border: '1px solid #e6e6e6',
108
+ padding: 16,
109
+ minHeight: 480,
110
+ }}
111
+ >
112
+ <p style={{ marginTop: 0 }}>Click the button to open the inline drawer:</p>
113
+ <button
114
+ onClick={() => ref.current?.open()}
115
+ style={{
116
+ padding: '8px 12px',
117
+ borderRadius: 6,
118
+ background: '#0b84ff',
119
+ color: '#fff',
120
+ border: 'none',
121
+ cursor: 'pointer',
122
+ }}
123
+ >
124
+ Open editor
125
+ </button>
126
+
127
+ <SideComponent ref={ref} title='Edit Patient' subtitle='John WICK - IEP: 26' size='420px'>
128
+ {ExampleContent}
129
+ </SideComponent>
130
+ </div>
131
+ );
132
+ },
133
+ tags: ['autodocs'],
134
+ };
135
+
136
+ /** 3) WithFooter — sticky footer for actions (save/cancel) */
137
+ export const WithFooter: Story = {
138
+ render: () => {
139
+ const ref = useRef<SideComponentRef | null>(null);
140
+ return (
141
+ <div
142
+ style={{
143
+ width: 700,
144
+ margin: '24px auto',
145
+ position: 'relative',
146
+ border: '1px solid #e6e6e6',
147
+ padding: 16,
148
+ minHeight: 480,
149
+ }}
150
+ >
151
+ <p style={{ marginTop: 0 }}>Long content + sticky footer demonstration.</p>
152
+ <button onClick={() => ref.current?.open()}>Open (with footer)</button>
153
+
154
+ <SideComponent ref={ref} title='Edit Patient' subtitle='John WICK - IEP: 26' size='420px'>
155
+ <div style={{ padding: 16 }}>
156
+ <p>Scrollable content area (to demonstrate footer stickiness):</p>
157
+ <div style={{ height: 380, background: '#fff', marginBottom: 12 }} />
158
+ <div style={{ height: 200, background: '#f9fafb' }} />
159
+ </div>
160
+
161
+ <div className='scp-footer'>
162
+ <button onClick={() => ref.current?.close()}>Cancel</button>
163
+ <button
164
+ style={{
165
+ background: '#0b84ff',
166
+ color: '#fff',
167
+ border: 'none',
168
+ padding: '8px 12px',
169
+ borderRadius: 6,
170
+ }}
171
+ >
172
+ Save
173
+ </button>
174
+ </div>
175
+ </SideComponent>
176
+ </div>
177
+ );
178
+ },
179
+ tags: ['autodocs'],
180
+ };
181
+
182
+ /** 4) SizeVariants — show small/medium/percentage sizes */
183
+ export const SizeVariants: Story = {
184
+ render: () => {
185
+ const refSmall = useRef<SideComponentRef | null>(null);
186
+ const refPercent = useRef<SideComponentRef | null>(null);
187
+ return (
188
+ <div style={{ display: 'flex', gap: 16, width: '100%', justifyContent: 'center' }}>
189
+ <div
190
+ style={{
191
+ width: 380,
192
+ position: 'relative',
193
+ border: '1px solid #e6e6e6',
194
+ padding: 12,
195
+ minHeight: 480,
196
+ }}
197
+ >
198
+ <button onClick={() => refSmall.current?.open()}>Open 300px</button>
199
+ <SideComponent ref={refSmall} title='Small' size='300px'>
200
+ <div style={{ padding: 12 }}>Small panel (300px)</div>
201
+ </SideComponent>
202
+ </div>
203
+
204
+ <div
205
+ style={{
206
+ width: 700,
207
+ position: 'relative',
208
+ border: '1px solid #e6e6e6',
209
+ padding: 12,
210
+ minHeight: 480,
211
+ }}
212
+ >
213
+ <button onClick={() => refPercent.current?.open()}>Open 60%</button>
214
+ <SideComponent ref={refPercent} title='60%' size='60%'>
215
+ <div style={{ padding: 12 }}>60% width of parent</div>
216
+ </SideComponent>
217
+ </div>
218
+ </div>
219
+ );
220
+ },
221
+ tags: ['autodocs'],
222
+ };
223
+
224
+ /** 5) MultipleInstances — independent drawers in the same page */
225
+ export const MultipleInstances: Story = {
226
+ render: () => {
227
+ const refA = useRef<SideComponentRef | null>(null);
228
+ const refB = useRef<SideComponentRef | null>(null);
229
+ return (
230
+ <div style={{ display: 'flex', gap: 24, padding: 24 }}>
231
+ <div
232
+ style={{
233
+ width: 360,
234
+ position: 'relative',
235
+ border: '1px solid #e6e6e6',
236
+ padding: 12,
237
+ minHeight: 480,
238
+ }}
239
+ >
240
+ <p>Box A</p>
241
+ <button onClick={() => refA.current?.open()}>Open A</button>
242
+ <SideComponent ref={refA} title='Panel A' size='320px'>
243
+ <div style={{ padding: 12 }}>Content A</div>
244
+ </SideComponent>
245
+ </div>
246
+
247
+ <div
248
+ style={{
249
+ width: 420,
250
+ position: 'relative',
251
+ border: '1px solid #e6e6e6',
252
+ padding: 12,
253
+ minHeight: 480,
254
+ }}
255
+ >
256
+ <p>Box B</p>
257
+ <button onClick={() => refB.current?.open()}>Open B</button>
258
+ <SideComponent ref={refB} title='Panel B' size='360px'>
259
+ <div style={{ padding: 12 }}>Content B</div>
260
+ </SideComponent>
261
+ </div>
262
+ </div>
263
+ );
264
+ },
265
+ tags: ['autodocs'],
266
+ };
267
+
268
+ /** 6) FormWithValidation — form inside the drawer with simple validation */
269
+ export const FormWithValidation: Story = {
270
+ render: () => {
271
+ const ref = useRef<SideComponentRef | null>(null);
272
+ const [name, setName] = useState('');
273
+ const [error, setError] = useState<string | null>(null);
274
+
275
+ const onSave = () => {
276
+ if (name.trim().length < 3) {
277
+ setError('Name must be at least 3 characters');
278
+ return;
279
+ }
280
+ setError(null);
281
+ // simulate save and close
282
+ setTimeout(() => ref.current?.close(), 300);
283
+ };
284
+
285
+ return (
286
+ <div
287
+ style={{
288
+ width: 700,
289
+ margin: 24,
290
+ position: 'relative',
291
+ border: '1px solid #e6e6e6',
292
+ padding: 12,
293
+ minHeight: 480,
294
+ }}
295
+ >
296
+ <button onClick={() => ref.current?.open()}>Open form</button>
297
+ <SideComponent ref={ref} title='Edit Patient' size='420px'>
298
+ <div style={{ padding: 16 }}>
299
+ <label style={{ display: 'block', marginBottom: 6 }}>Full name</label>
300
+ <input
301
+ value={name}
302
+ onChange={(e) => setName(e.target.value)}
303
+ style={{ width: '100%', padding: 8, marginBottom: 8 }}
304
+ />
305
+ {error && <div style={{ color: 'crimson', marginBottom: 8 }}>{error}</div>}
306
+ <div style={{ display: 'flex', gap: 8 }}>
307
+ <button onClick={() => ref.current?.close()}>Cancel</button>
308
+ <button
309
+ onClick={onSave}
310
+ style={{
311
+ background: '#0b84ff',
312
+ color: '#fff',
313
+ border: 'none',
314
+ padding: '8px 12px',
315
+ borderRadius: 6,
316
+ }}
317
+ >
318
+ Save
319
+ </button>
320
+ </div>
321
+ </div>
322
+ </SideComponent>
323
+ </div>
324
+ );
325
+ },
326
+ tags: ['autodocs'],
327
+ };
328
+
329
+ /** 7) AsyncContent — show loader then content (simulate remote data) */
330
+ export const AsyncContent: Story = {
331
+ render: () => {
332
+ const ref = useRef<SideComponentRef | null>(null);
333
+ const [loading, setLoading] = useState(false);
334
+ const [data, setData] = useState<string | null>(null);
335
+
336
+ const openAndLoad = () => {
337
+ ref.current?.open();
338
+ setLoading(true);
339
+ setData(null);
340
+ setTimeout(() => {
341
+ setData('Loaded patient data from server (simulated).');
342
+ setLoading(false);
343
+ }, 1000);
344
+ };
345
+
346
+ return (
347
+ <div
348
+ style={{
349
+ width: 700,
350
+ margin: 24,
351
+ position: 'relative',
352
+ border: '1px solid #e6e6e6',
353
+ padding: 12,
354
+ minHeight: 480,
355
+ }}
356
+ >
357
+ <button onClick={openAndLoad}>Open (async)</button>
358
+ <SideComponent ref={ref} title='Edit Patient (async)' size='420px'>
359
+ <div style={{ padding: 16 }}>
360
+ {loading ? (
361
+ <div>Loading…</div>
362
+ ) : (
363
+ <div>{data ?? 'No data yet. Click open to load.'}</div>
364
+ )}
365
+ </div>
366
+ </SideComponent>
367
+ </div>
368
+ );
369
+ },
370
+ tags: ['autodocs'],
371
+ };
372
+
373
+ /** 8) Themed — pass custom inline style and className to customize look */
374
+ export const Themed: Story = {
375
+ render: () => {
376
+ const ref = useRef<SideComponentRef | null>(null);
377
+ return (
378
+ <div
379
+ style={{
380
+ width: 700,
381
+ margin: 24,
382
+ position: 'relative',
383
+ border: '1px solid #e6e6e6',
384
+ padding: 12,
385
+ minHeight: 480,
386
+ }}
387
+ >
388
+ <button onClick={() => ref.current?.open()}>Open themed</button>
389
+ <SideComponent
390
+ ref={ref}
391
+ title='Custom Theme'
392
+ size='420px'
393
+ style={{ background: '#fffaf0' }}
394
+ className='my-custom-side'
395
+ >
396
+ <div style={{ padding: 16 }}>
397
+ This panel uses inline style and a custom class (declare .my-custom-side in your CSS).
398
+ </div>
399
+ </SideComponent>
400
+ </div>
401
+ );
402
+ },
403
+ tags: ['autodocs'],
404
+ };
405
+
406
+ /** 9) RTL — show the drawer in a right-to-left context (wrap parent with dir="rtl") */
407
+ export const RTLExample: Story = {
408
+ render: () => {
409
+ const ref = useRef<SideComponentRef | null>(null);
410
+ return (
411
+ <div
412
+ dir='rtl'
413
+ style={{
414
+ width: 700,
415
+ margin: 24,
416
+ position: 'relative',
417
+ border: '1px solid #e6e6e6',
418
+ padding: 12,
419
+ minHeight: 480,
420
+ }}
421
+ >
422
+ <p>
423
+ Parent with dir="rtl" — note how content direction changes. The drawer still anchors to
424
+ parent right edge (logical start/end may differ).
425
+ </p>
426
+ <button onClick={() => ref.current?.open()}>Open (RTL)</button>
427
+ <SideComponent ref={ref} title='RTL Example' size='360px'>
428
+ <div style={{ padding: 16 }}>RTL content</div>
429
+ </SideComponent>
430
+ </div>
431
+ );
432
+ },
433
+ tags: ['autodocs'],
434
+ };
435
+
436
+ /** 10) KeyboardNavigation — show tabbable controls inside and test keyboard focus */
437
+ export const KeyboardNavigation: Story = {
438
+ render: () => {
439
+ const ref = useRef<SideComponentRef | null>(null);
440
+ return (
441
+ <div
442
+ style={{
443
+ width: 700,
444
+ margin: 24,
445
+ position: 'relative',
446
+ border: '1px solid #e6e6e6',
447
+ padding: 12,
448
+ minHeight: 480,
449
+ }}
450
+ >
451
+ <p>Open the drawer and use Tab to move through focusable elements.</p>
452
+ <button onClick={() => ref.current?.open()}>Open (Keyboard)</button>
453
+ <SideComponent ref={ref} title='Keyboard Nav' size='420px'>
454
+ <div style={{ padding: 16 }}>
455
+ <input
456
+ placeholder='First name'
457
+ style={{ display: 'block', marginBottom: 8, width: '100%' }}
458
+ />
459
+ <input
460
+ placeholder='Last name'
461
+ style={{ display: 'block', marginBottom: 8, width: '100%' }}
462
+ />
463
+ <select style={{ display: 'block', marginBottom: 8, width: '100%' }}>
464
+ <option>Option A</option>
465
+ <option>Option B</option>
466
+ </select>
467
+ <button style={{ marginRight: 8 }}>Action</button>
468
+ <a href='#' onClick={(e) => e.preventDefault()} style={{ marginLeft: 8 }}>
469
+ Link
470
+ </a>
471
+ </div>
472
+ </SideComponent>
473
+ </div>
474
+ );
475
+ },
476
+ tags: ['autodocs'],
477
+ };
478
+
479
+ /** 11) NestedTrigger — open drawer from inside the parent (e.g. inline contextual action) */
480
+ export const NestedTrigger: Story = {
481
+ render: () => {
482
+ const ref = useRef<SideComponentRef | null>(null);
483
+ return (
484
+ <div
485
+ style={{
486
+ width: 700,
487
+ margin: 24,
488
+ position: 'relative',
489
+ border: '1px solid #e6e6e6',
490
+ padding: 12,
491
+ minHeight: 480,
492
+ }}
493
+ >
494
+ <div style={{ display: 'flex', gap: 12 }}>
495
+ <div style={{ flex: 1 }}>
496
+ <p>Parent content</p>
497
+ <div style={{ marginTop: 8 }}>
498
+ <button onClick={() => ref.current?.open()}>Open inline (nested)</button>
499
+ </div>
500
+ </div>
501
+ </div>
502
+
503
+ <SideComponent ref={ref} title='Nested trigger' size='360px'>
504
+ <div style={{ padding: 16 }}>
505
+ <p>Opened from a trigger inside the parent. Good for contextual editors.</p>
506
+ </div>
507
+ </SideComponent>
508
+ </div>
509
+ );
510
+ },
511
+ tags: ['autodocs'],
512
+ };
513
+
514
+ /** 12) Playground — modify args in Controls, then click Open */
515
+ export const Playground: Story = {
516
+ render: (args) => {
517
+ const ref = useRef<SideComponentRef | null>(null);
518
+ return (
519
+ <div
520
+ style={{
521
+ width: 700,
522
+ margin: 24,
523
+ position: 'relative',
524
+ border: '1px solid #e6e6e6',
525
+ padding: 12,
526
+ minHeight: 480,
527
+ }}
528
+ >
529
+ <div style={{ marginBottom: 12 }}>
530
+ <small>Change the controls (title/size/etc.) in the panel then click Open.</small>
531
+ </div>
532
+ <button onClick={() => ref.current?.open()}>Open (Playground)</button>
533
+ <SideComponent ref={ref} {...(args as SideComponentProps)}>
534
+ {ExampleContent}
535
+ </SideComponent>
536
+ </div>
537
+ );
538
+ },
539
+ args: {
540
+ title: 'Edit Patient (Playground)',
541
+ subtitle: 'John WICK - IEP: 26',
542
+ size: '420px',
543
+ closeOnOverlayClick: true,
544
+ showCloseButton: true,
545
+ },
546
+ tags: ['autodocs'],
547
+ };