@arbor-education/design-system.components 0.14.0 → 0.16.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 (320) hide show
  1. package/.gather/skills/write-stories/SKILL.md +207 -271
  2. package/.storybook/preview.ts +5 -0
  3. package/CHANGELOG.md +27 -0
  4. package/README.md +8 -0
  5. package/component-library.md +144 -13
  6. package/dist/components/articleCard/ArticleCard.stories.d.ts +137 -11
  7. package/dist/components/articleCard/ArticleCard.stories.d.ts.map +1 -1
  8. package/dist/components/articleCard/ArticleCard.stories.js +358 -91
  9. package/dist/components/articleCard/ArticleCard.stories.js.map +1 -1
  10. package/dist/components/avatar/Avatar.stories.d.ts +6 -6
  11. package/dist/components/avatar/Avatar.stories.d.ts.map +1 -1
  12. package/dist/components/avatar/Avatar.stories.js +393 -49
  13. package/dist/components/avatar/Avatar.stories.js.map +1 -1
  14. package/dist/components/avatarGroup/AvatarGroup.stories.d.ts +9 -7
  15. package/dist/components/avatarGroup/AvatarGroup.stories.d.ts.map +1 -1
  16. package/dist/components/avatarGroup/AvatarGroup.stories.js +688 -65
  17. package/dist/components/avatarGroup/AvatarGroup.stories.js.map +1 -1
  18. package/dist/components/banner/Banner.stories.d.ts.map +1 -1
  19. package/dist/components/banner/Banner.stories.js +7 -3
  20. package/dist/components/banner/Banner.stories.js.map +1 -1
  21. package/dist/components/card/Card.stories.d.ts +105 -4
  22. package/dist/components/card/Card.stories.d.ts.map +1 -1
  23. package/dist/components/card/Card.stories.js +336 -18
  24. package/dist/components/card/Card.stories.js.map +1 -1
  25. package/dist/components/combobox/Combobox.stories.d.ts +134 -21
  26. package/dist/components/combobox/Combobox.stories.d.ts.map +1 -1
  27. package/dist/components/combobox/Combobox.stories.js +676 -175
  28. package/dist/components/combobox/Combobox.stories.js.map +1 -1
  29. package/dist/components/datePicker/DatePicker.stories.d.ts +119 -27
  30. package/dist/components/datePicker/DatePicker.stories.d.ts.map +1 -1
  31. package/dist/components/datePicker/DatePicker.stories.js +575 -47
  32. package/dist/components/datePicker/DatePicker.stories.js.map +1 -1
  33. package/dist/components/dateTimePicker/DateTimePicker.stories.d.ts +155 -39
  34. package/dist/components/dateTimePicker/DateTimePicker.stories.d.ts.map +1 -1
  35. package/dist/components/dateTimePicker/DateTimePicker.stories.js +674 -103
  36. package/dist/components/dateTimePicker/DateTimePicker.stories.js.map +1 -1
  37. package/dist/components/editableText/EditableText.stories.d.ts +53 -12
  38. package/dist/components/editableText/EditableText.stories.d.ts.map +1 -1
  39. package/dist/components/editableText/EditableText.stories.js +401 -64
  40. package/dist/components/editableText/EditableText.stories.js.map +1 -1
  41. package/dist/components/formField/FormField.d.ts +4 -0
  42. package/dist/components/formField/FormField.d.ts.map +1 -1
  43. package/dist/components/formField/FormField.js +2 -1
  44. package/dist/components/formField/FormField.js.map +1 -1
  45. package/dist/components/formField/FormField.test.js +5 -0
  46. package/dist/components/formField/FormField.test.js.map +1 -1
  47. package/dist/components/formField/fieldset/Fieldset.stories.d.ts +56 -4
  48. package/dist/components/formField/fieldset/Fieldset.stories.d.ts.map +1 -1
  49. package/dist/components/formField/fieldset/Fieldset.stories.js +534 -28
  50. package/dist/components/formField/fieldset/Fieldset.stories.js.map +1 -1
  51. package/dist/components/formField/inputs/checkbox/CheckboxGroup.d.ts +3 -1
  52. package/dist/components/formField/inputs/checkbox/CheckboxGroup.d.ts.map +1 -1
  53. package/dist/components/formField/inputs/checkbox/CheckboxInput.js +1 -1
  54. package/dist/components/formField/inputs/checkbox/CheckboxInput.js.map +1 -1
  55. package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.d.ts +95 -1
  56. package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.d.ts.map +1 -1
  57. package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.js +386 -9
  58. package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.js.map +1 -1
  59. package/dist/components/formField/inputs/number/NumberInput.d.ts.map +1 -1
  60. package/dist/components/formField/inputs/number/NumberInput.js +14 -2
  61. package/dist/components/formField/inputs/number/NumberInput.js.map +1 -1
  62. package/dist/components/formField/inputs/number/NumberInput.test.js +21 -0
  63. package/dist/components/formField/inputs/number/NumberInput.test.js.map +1 -1
  64. package/dist/components/formField/inputs/radio/RadioButtonGroup.d.ts +6 -2
  65. package/dist/components/formField/inputs/radio/RadioButtonGroup.d.ts.map +1 -1
  66. package/dist/components/formField/inputs/radio/RadioButtonGroup.js.map +1 -1
  67. package/dist/components/formField/inputs/radio/RadioButtonInput.stories.d.ts.map +1 -1
  68. package/dist/components/formField/inputs/radio/RadioButtonInput.stories.js +61 -49
  69. package/dist/components/formField/inputs/radio/RadioButtonInput.stories.js.map +1 -1
  70. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.stories.d.ts +188 -166
  71. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.stories.d.ts.map +1 -1
  72. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.stories.js +821 -160
  73. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.stories.js.map +1 -1
  74. package/dist/components/formField/inputs/time/TimeInput.stories.d.ts +176 -22
  75. package/dist/components/formField/inputs/time/TimeInput.stories.d.ts.map +1 -1
  76. package/dist/components/formField/inputs/time/TimeInput.stories.js +851 -92
  77. package/dist/components/formField/inputs/time/TimeInput.stories.js.map +1 -1
  78. package/dist/components/formField/label/Label.stories.d.ts +54 -5
  79. package/dist/components/formField/label/Label.stories.d.ts.map +1 -1
  80. package/dist/components/formField/label/Label.stories.js +238 -4
  81. package/dist/components/formField/label/Label.stories.js.map +1 -1
  82. package/dist/components/icoText/IcoText.stories.d.ts +32 -6
  83. package/dist/components/icoText/IcoText.stories.d.ts.map +1 -1
  84. package/dist/components/icoText/IcoText.stories.js +309 -14
  85. package/dist/components/icoText/IcoText.stories.js.map +1 -1
  86. package/dist/components/kpiCard/KPICard.stories.d.ts +100 -2
  87. package/dist/components/kpiCard/KPICard.stories.d.ts.map +1 -1
  88. package/dist/components/kpiCard/KPICard.stories.js +354 -10
  89. package/dist/components/kpiCard/KPICard.stories.js.map +1 -1
  90. package/dist/components/kvpList/KVPList.stories.d.ts +57 -4
  91. package/dist/components/kvpList/KVPList.stories.d.ts.map +1 -1
  92. package/dist/components/kvpList/KVPList.stories.js +403 -10
  93. package/dist/components/kvpList/KVPList.stories.js.map +1 -1
  94. package/dist/components/modal/Modal.stories.d.ts +113 -9
  95. package/dist/components/modal/Modal.stories.d.ts.map +1 -1
  96. package/dist/components/modal/Modal.stories.js +633 -13
  97. package/dist/components/modal/Modal.stories.js.map +1 -1
  98. package/dist/components/modal/modalManager/ModalManager.stories.d.ts +34 -10
  99. package/dist/components/modal/modalManager/ModalManager.stories.d.ts.map +1 -1
  100. package/dist/components/modal/modalManager/ModalManager.stories.js +463 -85
  101. package/dist/components/modal/modalManager/ModalManager.stories.js.map +1 -1
  102. package/dist/components/pill/Pill.d.ts.map +1 -1
  103. package/dist/components/pill/Pill.js +1 -1
  104. package/dist/components/pill/Pill.js.map +1 -1
  105. package/dist/components/pill/Pill.stories.d.ts.map +1 -1
  106. package/dist/components/pill/Pill.stories.js +11 -13
  107. package/dist/components/pill/Pill.stories.js.map +1 -1
  108. package/dist/components/row/Row.stories.d.ts +1 -2
  109. package/dist/components/row/Row.stories.d.ts.map +1 -1
  110. package/dist/components/row/Row.stories.js +360 -50
  111. package/dist/components/row/Row.stories.js.map +1 -1
  112. package/dist/components/searchBar/SearchBar.stories.d.ts +52 -4
  113. package/dist/components/searchBar/SearchBar.stories.d.ts.map +1 -1
  114. package/dist/components/searchBar/SearchBar.stories.js +428 -36
  115. package/dist/components/searchBar/SearchBar.stories.js.map +1 -1
  116. package/dist/components/section/Section.stories.d.ts +11 -41
  117. package/dist/components/section/Section.stories.d.ts.map +1 -1
  118. package/dist/components/section/Section.stories.js +494 -56
  119. package/dist/components/section/Section.stories.js.map +1 -1
  120. package/dist/components/singleUser/SingleUser.stories.d.ts +5 -4
  121. package/dist/components/singleUser/SingleUser.stories.d.ts.map +1 -1
  122. package/dist/components/singleUser/SingleUser.stories.js +303 -31
  123. package/dist/components/singleUser/SingleUser.stories.js.map +1 -1
  124. package/dist/components/slideoverManager/SlideoverManager.stories.d.ts +32 -11
  125. package/dist/components/slideoverManager/SlideoverManager.stories.d.ts.map +1 -1
  126. package/dist/components/slideoverManager/SlideoverManager.stories.js +380 -84
  127. package/dist/components/slideoverManager/SlideoverManager.stories.js.map +1 -1
  128. package/dist/components/table/DSDefaultColDef.d.ts.map +1 -1
  129. package/dist/components/table/DSDefaultColDef.js +4 -3
  130. package/dist/components/table/DSDefaultColDef.js.map +1 -1
  131. package/dist/components/table/Table.d.ts +7 -1
  132. package/dist/components/table/Table.d.ts.map +1 -1
  133. package/dist/components/table/Table.js +12 -5
  134. package/dist/components/table/Table.js.map +1 -1
  135. package/dist/components/table/Table.stories.d.ts +3 -0
  136. package/dist/components/table/Table.stories.d.ts.map +1 -1
  137. package/dist/components/table/Table.stories.js +445 -3
  138. package/dist/components/table/Table.stories.js.map +1 -1
  139. package/dist/components/table/Table.test.js +184 -0
  140. package/dist/components/table/Table.test.js.map +1 -1
  141. package/dist/components/table/TableFooter.stories.d.ts +49 -0
  142. package/dist/components/table/TableFooter.stories.d.ts.map +1 -0
  143. package/dist/components/table/TableFooter.stories.js +137 -0
  144. package/dist/components/table/TableFooter.stories.js.map +1 -0
  145. package/dist/components/table/TableHeader.stories.d.ts +93 -0
  146. package/dist/components/table/TableHeader.stories.d.ts.map +1 -0
  147. package/dist/components/table/TableHeader.stories.js +176 -0
  148. package/dist/components/table/TableHeader.stories.js.map +1 -0
  149. package/dist/components/table/cellEditors/DateCellEditor.stories.d.ts +44 -0
  150. package/dist/components/table/cellEditors/DateCellEditor.stories.d.ts.map +1 -0
  151. package/dist/components/table/cellEditors/DateCellEditor.stories.js +186 -0
  152. package/dist/components/table/cellEditors/DateCellEditor.stories.js.map +1 -0
  153. package/dist/components/table/cellEditors/NumberCellEditor.d.ts +13 -0
  154. package/dist/components/table/cellEditors/NumberCellEditor.d.ts.map +1 -0
  155. package/dist/components/table/cellEditors/NumberCellEditor.js +35 -0
  156. package/dist/components/table/cellEditors/NumberCellEditor.js.map +1 -0
  157. package/dist/components/table/cellRenderers/BooleanCellRenderer.stories.d.ts +40 -0
  158. package/dist/components/table/cellRenderers/BooleanCellRenderer.stories.d.ts.map +1 -0
  159. package/dist/components/table/cellRenderers/BooleanCellRenderer.stories.js +209 -0
  160. package/dist/components/table/cellRenderers/BooleanCellRenderer.stories.js.map +1 -0
  161. package/dist/components/table/cellRenderers/ButtonCellRenderer.stories.d.ts +48 -0
  162. package/dist/components/table/cellRenderers/ButtonCellRenderer.stories.d.ts.map +1 -0
  163. package/dist/components/table/cellRenderers/ButtonCellRenderer.stories.js +244 -0
  164. package/dist/components/table/cellRenderers/ButtonCellRenderer.stories.js.map +1 -0
  165. package/dist/components/table/cellRenderers/CheckboxCellRenderer.d.ts.map +1 -1
  166. package/dist/components/table/cellRenderers/CheckboxCellRenderer.js +3 -1
  167. package/dist/components/table/cellRenderers/CheckboxCellRenderer.js.map +1 -1
  168. package/dist/components/table/cellRenderers/CheckboxCellRenderer.stories.d.ts +64 -0
  169. package/dist/components/table/cellRenderers/CheckboxCellRenderer.stories.d.ts.map +1 -0
  170. package/dist/components/table/cellRenderers/CheckboxCellRenderer.stories.js +241 -0
  171. package/dist/components/table/cellRenderers/CheckboxCellRenderer.stories.js.map +1 -0
  172. package/dist/components/table/cellRenderers/DefaultCellRenderer.stories.d.ts +55 -0
  173. package/dist/components/table/cellRenderers/DefaultCellRenderer.stories.d.ts.map +1 -0
  174. package/dist/components/table/cellRenderers/DefaultCellRenderer.stories.js +245 -0
  175. package/dist/components/table/cellRenderers/DefaultCellRenderer.stories.js.map +1 -0
  176. package/dist/components/table/cellRenderers/InlineTextCellRenderer.stories.d.ts +67 -0
  177. package/dist/components/table/cellRenderers/InlineTextCellRenderer.stories.d.ts.map +1 -0
  178. package/dist/components/table/cellRenderers/InlineTextCellRenderer.stories.js +221 -0
  179. package/dist/components/table/cellRenderers/InlineTextCellRenderer.stories.js.map +1 -0
  180. package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.d.ts +75 -0
  181. package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.d.ts.map +1 -0
  182. package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.js +270 -0
  183. package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.js.map +1 -0
  184. package/dist/components/table/columnFilters/BooleanFilter.stories.d.ts +57 -0
  185. package/dist/components/table/columnFilters/BooleanFilter.stories.d.ts.map +1 -0
  186. package/dist/components/table/columnFilters/BooleanFilter.stories.js +198 -0
  187. package/dist/components/table/columnFilters/BooleanFilter.stories.js.map +1 -0
  188. package/dist/components/table/columnFilters/TimeFilter.stories.d.ts +58 -0
  189. package/dist/components/table/columnFilters/TimeFilter.stories.d.ts.map +1 -0
  190. package/dist/components/table/columnFilters/TimeFilter.stories.js +207 -0
  191. package/dist/components/table/columnFilters/TimeFilter.stories.js.map +1 -0
  192. package/dist/components/table/pagination/PaginationPanel.stories.d.ts +113 -0
  193. package/dist/components/table/pagination/PaginationPanel.stories.d.ts.map +1 -0
  194. package/dist/components/table/pagination/PaginationPanel.stories.js +272 -0
  195. package/dist/components/table/pagination/PaginationPanel.stories.js.map +1 -0
  196. package/dist/components/table/tableControls/TableControls.stories.d.ts +151 -0
  197. package/dist/components/table/tableControls/TableControls.stories.d.ts.map +1 -0
  198. package/dist/components/table/tableControls/TableControls.stories.js +356 -0
  199. package/dist/components/table/tableControls/TableControls.stories.js.map +1 -0
  200. package/dist/components/table/tableControls/TableSettingsDropdown.d.ts +27 -1
  201. package/dist/components/table/tableControls/TableSettingsDropdown.d.ts.map +1 -1
  202. package/dist/components/table/tableControls/TableSettingsDropdown.js +53 -26
  203. package/dist/components/table/tableControls/TableSettingsDropdown.js.map +1 -1
  204. package/dist/components/table/tableControls/TableSettingsDropdown.test.d.ts +2 -0
  205. package/dist/components/table/tableControls/TableSettingsDropdown.test.d.ts.map +1 -0
  206. package/dist/components/table/tableControls/TableSettingsDropdown.test.js +178 -0
  207. package/dist/components/table/tableControls/TableSettingsDropdown.test.js.map +1 -0
  208. package/dist/components/tabs/Tabs.stories.d.ts +22 -4
  209. package/dist/components/tabs/Tabs.stories.d.ts.map +1 -1
  210. package/dist/components/tabs/Tabs.stories.js +398 -22
  211. package/dist/components/tabs/Tabs.stories.js.map +1 -1
  212. package/dist/components/tabs/TabsItem.stories.d.ts +54 -1
  213. package/dist/components/tabs/TabsItem.stories.d.ts.map +1 -1
  214. package/dist/components/tabs/TabsItem.stories.js +61 -9
  215. package/dist/components/tabs/TabsItem.stories.js.map +1 -1
  216. package/dist/components/toast/Toast.stories.d.ts +103 -10
  217. package/dist/components/toast/Toast.stories.d.ts.map +1 -1
  218. package/dist/components/toast/Toast.stories.js +409 -47
  219. package/dist/components/toast/Toast.stories.js.map +1 -1
  220. package/dist/components/toggle/Toggle.stories.d.ts +61 -46
  221. package/dist/components/toggle/Toggle.stories.d.ts.map +1 -1
  222. package/dist/components/toggle/Toggle.stories.js +311 -122
  223. package/dist/components/toggle/Toggle.stories.js.map +1 -1
  224. package/dist/components/tooltip/Tooltip.stories.d.ts +78 -6
  225. package/dist/components/tooltip/Tooltip.stories.d.ts.map +1 -1
  226. package/dist/components/tooltip/Tooltip.stories.js +413 -7
  227. package/dist/components/tooltip/Tooltip.stories.js.map +1 -1
  228. package/dist/components/tooltip/TooltipWrapper.stories.d.ts +71 -7
  229. package/dist/components/tooltip/TooltipWrapper.stories.d.ts.map +1 -1
  230. package/dist/components/tooltip/TooltipWrapper.stories.js +238 -10
  231. package/dist/components/tooltip/TooltipWrapper.stories.js.map +1 -1
  232. package/dist/index.css +27 -0
  233. package/dist/index.css.map +1 -1
  234. package/dist/index.d.ts +3 -2
  235. package/dist/index.d.ts.map +1 -1
  236. package/dist/index.js +3 -2
  237. package/dist/index.js.map +1 -1
  238. package/dist/utils/PopupParentContext.stories.d.ts +17 -0
  239. package/dist/utils/PopupParentContext.stories.d.ts.map +1 -0
  240. package/dist/utils/PopupParentContext.stories.js +266 -0
  241. package/dist/utils/PopupParentContext.stories.js.map +1 -0
  242. package/dist/utils/getDefaultPopupParent.d.ts.map +1 -1
  243. package/dist/utils/getDefaultPopupParent.js +6 -0
  244. package/dist/utils/getDefaultPopupParent.js.map +1 -1
  245. package/package.json +1 -1
  246. package/src/components/articleCard/ArticleCard.stories.tsx +524 -111
  247. package/src/components/avatar/Avatar.stories.tsx +504 -59
  248. package/src/components/avatarGroup/AvatarGroup.stories.tsx +977 -175
  249. package/src/components/banner/Banner.stories.tsx +7 -3
  250. package/src/components/card/Card.stories.tsx +466 -36
  251. package/src/components/combobox/Combobox.stories.tsx +867 -260
  252. package/src/components/datePicker/DatePicker.stories.tsx +777 -60
  253. package/src/components/dateTimePicker/DateTimePicker.stories.tsx +910 -132
  254. package/src/components/editableText/EditableText.stories.tsx +567 -91
  255. package/src/components/formField/FormField.test.tsx +6 -0
  256. package/src/components/formField/FormField.tsx +5 -0
  257. package/src/components/formField/fieldset/Fieldset.stories.tsx +761 -51
  258. package/src/components/formField/inputs/checkbox/CheckboxGroup.tsx +1 -1
  259. package/src/components/formField/inputs/checkbox/CheckboxInput.tsx +1 -1
  260. package/src/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.tsx +504 -11
  261. package/src/components/formField/inputs/number/NumberInput.test.tsx +28 -0
  262. package/src/components/formField/inputs/number/NumberInput.tsx +15 -0
  263. package/src/components/formField/inputs/radio/RadioButtonGroup.tsx +17 -4
  264. package/src/components/formField/inputs/radio/RadioButtonInput.stories.tsx +71 -59
  265. package/src/components/formField/inputs/selectDropdown/SelectDropdown.stories.tsx +1079 -168
  266. package/src/components/formField/inputs/time/TimeInput.stories.tsx +1140 -104
  267. package/src/components/formField/label/Label.stories.tsx +317 -8
  268. package/src/components/icoText/IcoText.stories.tsx +442 -31
  269. package/src/components/kpiCard/KPICard.stories.tsx +475 -30
  270. package/src/components/kvpList/KVPList.stories.tsx +593 -26
  271. package/src/components/modal/Modal.stories.tsx +963 -26
  272. package/src/components/modal/modalManager/ModalManager.stories.tsx +612 -454
  273. package/src/components/pill/Pill.stories.tsx +11 -13
  274. package/src/components/pill/Pill.tsx +1 -0
  275. package/src/components/row/Row.stories.tsx +474 -58
  276. package/src/components/searchBar/SearchBar.stories.tsx +570 -38
  277. package/src/components/section/Section.stories.tsx +723 -70
  278. package/src/components/singleUser/SingleUser.stories.tsx +393 -34
  279. package/src/components/slideoverManager/SlideoverManager.stories.tsx +572 -342
  280. package/src/components/table/DSDefaultColDef.ts +25 -5
  281. package/src/components/table/Table.stories.tsx +504 -3
  282. package/src/components/table/Table.test.tsx +255 -0
  283. package/src/components/table/Table.tsx +15 -2
  284. package/src/components/table/TableFooter.stories.tsx +196 -0
  285. package/src/components/table/TableHeader.stories.tsx +251 -0
  286. package/src/components/table/cellEditors/DateCellEditor.stories.tsx +245 -0
  287. package/src/components/table/cellEditors/NumberCellEditor.tsx +83 -0
  288. package/src/components/table/cellEditors/numberCellEditor.scss +11 -0
  289. package/src/components/table/cellRenderers/BooleanCellRenderer.stories.tsx +278 -0
  290. package/src/components/table/cellRenderers/ButtonCellRenderer.stories.tsx +333 -0
  291. package/src/components/table/cellRenderers/CheckboxCellRenderer.stories.tsx +337 -0
  292. package/src/components/table/cellRenderers/CheckboxCellRenderer.tsx +5 -1
  293. package/src/components/table/cellRenderers/DefaultCellRenderer.stories.tsx +342 -0
  294. package/src/components/table/cellRenderers/InlineTextCellRenderer.stories.tsx +292 -0
  295. package/src/components/table/cellRenderers/SelectDropdownCellRenderer.stories.tsx +369 -0
  296. package/src/components/table/columnFilters/BooleanFilter.stories.tsx +268 -0
  297. package/src/components/table/columnFilters/TimeFilter.stories.tsx +281 -0
  298. package/src/components/table/pagination/PaginationPanel.stories.tsx +327 -0
  299. package/src/components/table/table.scss +11 -0
  300. package/src/components/table/tableControls/TableControls.stories.tsx +415 -0
  301. package/src/components/table/tableControls/TableSettingsDropdown.test.tsx +207 -0
  302. package/src/components/table/tableControls/TableSettingsDropdown.tsx +103 -39
  303. package/src/components/tabs/Tabs.stories.tsx +540 -60
  304. package/src/components/tabs/TabsItem.stories.tsx +82 -8
  305. package/src/components/toast/Toast.stories.tsx +539 -77
  306. package/src/components/toggle/Toggle.stories.tsx +371 -135
  307. package/src/components/tooltip/Tooltip.stories.tsx +606 -15
  308. package/src/components/tooltip/TooltipWrapper.stories.tsx +348 -12
  309. package/src/docs/Contributing.mdx +241 -0
  310. package/src/docs/UsingComponents.mdx +93 -0
  311. package/src/docs/Welcome.mdx +68 -0
  312. package/src/global.scss +7 -0
  313. package/src/index.scss +1 -0
  314. package/src/index.ts +3 -2
  315. package/src/utils/PopupParentContext.stories.tsx +367 -0
  316. package/src/utils/getDefaultPopupParent.ts +6 -0
  317. package/.ralph/storybook-upgrade/knowledge.md +0 -308
  318. package/.ralph/storybook-upgrade/prd.json +0 -777
  319. package/.ralph/storybook-upgrade/progress.md +0 -342
  320. package/src/components/table/TableWIP.mdx +0 -3
@@ -1,94 +1,622 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { fn } from 'storybook/test';
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { Controls, Heading as DocHeading, Markdown, Primary as DocPrimary, Stories, Subtitle, Title, } from '@storybook/addon-docs/blocks';
4
+ import { FormField } from '../formField/FormField';
3
5
  import { DatePicker } from './DatePicker';
6
+ // ---------------------------------------------------------------------------
7
+ // Docs page content
8
+ // ---------------------------------------------------------------------------
9
+ const DESCRIPTION_INTRO = [
10
+ 'DatePicker combines a native `<input type="date">` with a calendar popover for date selection.',
11
+ 'Built on [Radix UI Popover](https://www.radix-ui.com/primitives/docs/components/popover) and',
12
+ '[react-day-picker](https://daypicker.dev/).',
13
+ '',
14
+ '> **Portal rendering.** The calendar panel renders via a Radix portal — do **not** place inside',
15
+ '> a container with `overflow: hidden` or the calendar will be clipped.',
16
+ '',
17
+ 'When empty, a decorative span overlays the hint text (`DD/MM/YYYY` or `Pick a date`) because',
18
+ 'browsers do not reliably show `placeholder` on native date inputs. When a custom `placeholder` is',
19
+ 'provided and the field is empty, the input becomes read-only and the calendar opens on click only',
20
+ '— Tab focus does not trigger it.',
21
+ ].join('\n');
22
+ const USAGE_GUIDANCE = [
23
+ '### When to use',
24
+ '',
25
+ '- **Single date selection** — enrollment dates, event dates, term start/end dates',
26
+ '- **Date of birth entry** — with a clear format hint so users know the expected format',
27
+ '- **Booking and scheduling** — parent evenings, appointment slots, report deadlines',
28
+ '',
29
+ '---',
30
+ '',
31
+ '### When NOT to use',
32
+ '',
33
+ '| Situation | Use instead |',
34
+ '|---|---|',
35
+ '| Date ranges (from/to) | Two separate `DatePicker` fields |',
36
+ '| Date + time combined | `DatePicker` paired with `TimeInput` |',
37
+ '| Year-only or month-only selection | `SelectDropdown` with year/month options |',
38
+ '| Relative dates ("next week", "in 30 days") | `SelectDropdown` with relative option labels |',
39
+ ].join('\n');
40
+ const DEVELOPER_NOTES = [
41
+ '### Critical usage patterns',
42
+ '',
43
+ '**`onChange` receives a `Date` object — never a string.** Format for display with',
44
+ '`date?.toLocaleDateString(\'en-GB\')`. Do not call `date.toString()` or assume ISO format.',
45
+ '',
46
+ '**`value` and `defaultValue` are `Date` objects — not strings.** Month is zero-indexed:',
47
+ '`new Date(2024, 8, 1)` = 1 September 2024. Passing a string is a type error.',
48
+ '',
49
+ '```tsx',
50
+ '// ✅ Correct',
51
+ 'defaultValue={new Date(2024, 8, 1)}',
52
+ '',
53
+ '// ❌ Wrong — type error',
54
+ 'defaultValue="2024-09-01"',
55
+ '```',
56
+ '',
57
+ '**`hasError` is visual-only when used standalone.** It applies the red border but does NOT',
58
+ 'set `aria-invalid`. Always pair both when outside `<FormField>`:',
59
+ '',
60
+ '```tsx',
61
+ '<DatePicker hasError aria-invalid={true} aria-describedby="error-id" />',
62
+ '```',
63
+ '',
64
+ '**Controlled vs uncontrolled.** Pass `value` + `onChange` for controlled mode.',
65
+ 'Pass only `defaultValue` for uncontrolled. Do not pass both `value` and `defaultValue`.',
66
+ '',
67
+ '**Time preservation.** DatePicker preserves any time component from the previous value when the',
68
+ 'date changes — this enables clean DateTimePicker composition.',
69
+ '',
70
+ '---',
71
+ '',
72
+ '### Accessibility',
73
+ '',
74
+ '- Always label via `<FormField>` or `aria-label` / `aria-labelledby`',
75
+ '- Pair `hasError` with `aria-invalid={true}` when used standalone — `<FormField>` handles both',
76
+ '- `aria-describedby` should point to the error element ID for screen-reader coverage',
77
+ '- The calendar icon button has built-in screen reader text ("Open date picker")',
78
+ '- The calendar closes and returns focus to the input on date selection or Escape',
79
+ '',
80
+ '---',
81
+ '',
82
+ '### TypeScript types',
83
+ '',
84
+ '```ts',
85
+ "import { DatePicker } from '@arbor-education/design-system.components';",
86
+ '',
87
+ 'function MyDateField(props: DatePicker.Props) { ... }',
88
+ '```',
89
+ '',
90
+ '| Type | Description |',
91
+ '|---|---|',
92
+ '| `DatePicker.Props` | Full props interface |',
93
+ ].join('\n');
94
+ const RELATED_COMPONENTS = [
95
+ '## Related components',
96
+ '',
97
+ '[FormField](?path=/docs/components-formfield--docs) · [TimeInput](?path=/docs/components-formfield-inputs-timeinput--docs)',
98
+ ].join('\n');
99
+ const PROPS_INTRO = 'The preview below is wired to the **Controls** panel — tweak any prop to see the story update in real time.';
100
+ // ---------------------------------------------------------------------------
101
+ // Docs page component
102
+ // ---------------------------------------------------------------------------
103
+ function DatePickerDocsPage() {
104
+ return (_jsxs(_Fragment, { children: [_jsx(Title, {}), _jsx(Subtitle, {}), _jsx(Markdown, { children: DESCRIPTION_INTRO }), _jsx(DocHeading, { children: "Interactive example" }), _jsx(Markdown, { children: PROPS_INTRO }), _jsx(DocPrimary, {}), _jsx(Controls, {}), _jsx(DocHeading, { children: "Usage guidance" }), _jsx(Markdown, { children: USAGE_GUIDANCE }), _jsx(DocHeading, { children: "Developer notes" }), _jsx(Markdown, { children: DEVELOPER_NOTES }), _jsx(DocHeading, { children: "Examples" }), _jsx(Stories, { title: "" }), _jsx(Markdown, { children: RELATED_COMPONENTS })] }));
105
+ }
106
+ // ---------------------------------------------------------------------------
107
+ // Meta
108
+ // ---------------------------------------------------------------------------
4
109
  const meta = {
5
110
  title: 'Components/DatePicker',
6
111
  component: DatePicker,
7
- decorators: [
8
- Story => (_jsx("div", { style: { maxWidth: '220px', width: '100%' }, children: _jsx(Story, {}) })),
9
- ],
112
+ tags: ['autodocs'],
10
113
  parameters: {
11
- layout: 'centered',
114
+ layout: 'padded',
12
115
  docs: {
13
- description: {
14
- component: '`DatePicker` uses a native `type="date"` input (`yyyy-MM-dd`) with a synced calendar popover. When empty, hint copy uses a decorative span (browsers do not reliably show `placeholder` on native date fields). `displayFormat` controls that hint (`DD/MM/YYYY` vs `Pick a date`). The custom month/year header uses the design-system select control.',
15
- },
116
+ page: DatePickerDocsPage,
16
117
  },
17
118
  },
18
- tags: ['autodocs'],
19
- args: {
20
- onChange: fn(),
21
- },
22
119
  argTypes: {
23
- displayFormat: {
24
- control: 'inline-radio',
120
+ 'displayFormat': {
121
+ control: { type: 'inline-radio' },
25
122
  options: ['default', 'friendly'],
26
- description: 'Controls the empty-state hint text (`DD/MM/YYYY` vs `Pick a date`). The field value is always native ISO `yyyy-MM-dd`.',
123
+ description: [
124
+ 'Controls the empty-state hint overlay.',
125
+ '`"default"` shows `DD/MM/YYYY`; `"friendly"` shows `Pick a date`.',
126
+ 'Overridden by `placeholder` when that prop is provided.',
127
+ ].join(' '),
128
+ table: {
129
+ type: { summary: "'default' | 'friendly'" },
130
+ defaultValue: { summary: "'default'" },
131
+ },
132
+ },
133
+ 'placeholder': {
134
+ control: 'text',
135
+ description: [
136
+ 'Custom text for the empty-state overlay.',
137
+ 'Overrides the `displayFormat` hint.',
138
+ 'When set and the field is empty, the input becomes read-only — the calendar opens on click only, not Tab focus.',
139
+ ].join(' '),
140
+ table: {
141
+ type: { summary: 'string' },
142
+ defaultValue: { summary: 'undefined' },
143
+ },
144
+ },
145
+ 'onChange': {
146
+ control: false,
147
+ action: 'onChange',
148
+ description: [
149
+ 'Callback fired when the selected date changes.',
150
+ 'Receives a `Date` object, or `undefined` when the field is cleared.',
151
+ 'Never receives a string — format with `date?.toLocaleDateString(\'en-GB\')`.',
152
+ ].join(' '),
153
+ table: {
154
+ type: { summary: '(newDate?: Date) => void' },
155
+ },
156
+ },
157
+ 'hasError': {
158
+ control: 'boolean',
159
+ description: [
160
+ 'Applies error-state visual styling (red border).',
161
+ 'Does **not** set `aria-invalid` automatically when used standalone.',
162
+ 'Always pair with `aria-invalid={true}` for screen-reader coverage.',
163
+ '`<FormField>` handles both automatically when `errorText` is set.',
164
+ ].join(' '),
165
+ table: {
166
+ type: { summary: 'boolean' },
167
+ defaultValue: { summary: 'false' },
168
+ },
169
+ },
170
+ 'value': {
171
+ control: false,
172
+ description: [
173
+ 'Controlled selected date.',
174
+ 'Must be a `Date` object — not a string.',
175
+ 'Pair with `onChange` to keep state in sync.',
176
+ ].join(' '),
177
+ table: {
178
+ type: { summary: 'Date' },
179
+ defaultValue: { summary: 'undefined' },
180
+ },
27
181
  },
28
- placeholder: {
182
+ 'defaultValue': {
183
+ control: false,
184
+ description: [
185
+ 'Uncontrolled initial date.',
186
+ 'Must be a `Date` object (month is zero-indexed: `new Date(2024, 8, 1)` = 1 Sep 2024).',
187
+ 'Use when you only need the value on form submit.',
188
+ ].join(' '),
189
+ table: {
190
+ type: { summary: 'Date' },
191
+ defaultValue: { summary: 'undefined' },
192
+ },
193
+ },
194
+ 'id': {
29
195
  control: 'text',
30
- description: 'Optional override for the empty-state hint (defaults from `displayFormat`).',
196
+ description: 'HTML `id` for the input element. Required when inside `<FormField>` so the label `htmlFor` can be linked.',
197
+ table: {
198
+ type: { summary: 'string' },
199
+ },
31
200
  },
32
- className: {
201
+ 'className': {
33
202
  control: 'text',
34
- description: 'Additional CSS class names',
203
+ description: 'Additional CSS class names on the root wrapper element.',
204
+ table: {
205
+ type: { summary: 'string' },
206
+ },
207
+ },
208
+ 'autoFocus': {
209
+ control: 'boolean',
210
+ description: 'Autofocuses the date input on mount. Use sparingly — unexpected focus shifts can disorient screen-reader users.',
211
+ table: {
212
+ type: { summary: 'boolean' },
213
+ defaultValue: { summary: 'false' },
214
+ },
215
+ },
216
+ 'aria-invalid': {
217
+ control: 'boolean',
218
+ description: [
219
+ 'Marks the input as invalid for screen readers.',
220
+ 'Must be set manually when used standalone — `<FormField>` sets this automatically when `errorText` is provided.',
221
+ ].join(' '),
222
+ table: {
223
+ type: { summary: 'boolean | "true" | "false"' },
224
+ },
35
225
  },
36
- onChange: {
37
- description: 'Callback fired when the selected date changes. Receives the selected Date, or undefined when cleared.',
226
+ 'aria-describedby': {
227
+ control: 'text',
228
+ description: 'ID of the element describing the field (e.g. an error message). Links the input to the error for screen readers.',
229
+ table: {
230
+ type: { summary: 'string' },
231
+ },
38
232
  },
39
233
  },
40
234
  };
41
235
  export default meta;
42
- export const Default = {
236
+ // ---------------------------------------------------------------------------
237
+ // Helper: attach a per-story description
238
+ // ---------------------------------------------------------------------------
239
+ const withDescription = (story, description) => ({
240
+ ...story,
43
241
  parameters: {
242
+ ...story.parameters,
44
243
  docs: {
244
+ ...story.parameters?.docs,
45
245
  description: {
46
- story: 'Empty field shows hint **DD/MM/YYYY** (`displayFormat="default"`).',
246
+ story: description,
47
247
  },
48
248
  },
49
249
  },
250
+ });
251
+ // ---------------------------------------------------------------------------
252
+ // Named template components for stateful stories
253
+ // ---------------------------------------------------------------------------
254
+ const ControlledWithDisplayTemplate = () => {
255
+ const [selectedDate, setSelectedDate] = useState(undefined);
256
+ return (_jsxs("div", { style: { maxWidth: '280px' }, children: [_jsx(DatePicker, { id: "controlled-display", onChange: setSelectedDate }), _jsxs("p", { style: { margin: 'var(--spacing-small) 0 0', color: 'var(--color-grey-600)' }, children: ["Selected:", ' ', _jsx("code", { children: selectedDate ? selectedDate.toLocaleDateString('en-GB') : '(none)' })] })] }));
257
+ };
258
+ const ControlledWithValidationTemplate = () => {
259
+ const [selectedDate, setSelectedDate] = useState(undefined);
260
+ const [error, setError] = useState(undefined);
261
+ const today = new Date();
262
+ today.setHours(0, 0, 0, 0);
263
+ const handleChange = (date) => {
264
+ setSelectedDate(date);
265
+ if (!date) {
266
+ setError(undefined);
267
+ return;
268
+ }
269
+ const picked = new Date(date);
270
+ picked.setHours(0, 0, 0, 0);
271
+ if (picked <= today) {
272
+ setError('The event date must be in the future. Please pick a later date.');
273
+ }
274
+ else {
275
+ setError(undefined);
276
+ }
277
+ };
278
+ return (_jsxs("div", { style: { maxWidth: '280px' }, children: [_jsx(DatePicker, { id: "validated-date", onChange: handleChange, hasError: !!error, "aria-invalid": error ? true : undefined, "aria-describedby": error ? 'validated-date-error' : undefined }), error && (_jsx("p", { id: "validated-date-error", role: "alert", style: { margin: 'var(--spacing-small) 0 0', color: 'var(--color-semantic-destructive-600)', fontSize: '0.875rem' }, children: error })), !error && selectedDate && (_jsxs("p", { style: { margin: 'var(--spacing-small) 0 0', color: 'var(--color-semantic-success-600)', fontSize: '0.875rem' }, children: ["Event date set:", ' ', selectedDate.toLocaleDateString('en-GB')] }))] }));
279
+ };
280
+ const WithFormFieldTemplate = () => (_jsx("div", { style: { maxWidth: '320px' }, children: _jsx(FormField, { label: "Pupil enrollment date", id: "ff-enrollment-date", inputType: "datePicker", fieldDescription: "Select the date the pupil will join the school.", inputProps: {} }) }));
281
+ const WithFormFieldAndErrorTemplate = () => {
282
+ const [submitted, setSubmitted] = useState(false);
283
+ const [selectedDate, setSelectedDate] = useState(undefined);
284
+ const hasError = submitted && !selectedDate;
285
+ return (_jsxs("div", { style: { maxWidth: '320px', display: 'flex', flexDirection: 'column', gap: 'var(--spacing-large)' }, children: [_jsx(FormField, { label: "Parent evening appointment", id: "ff-parent-evening", inputType: "datePicker", errorText: hasError ? 'Please select an appointment date before submitting.' : undefined, inputProps: {
286
+ 'onChange': setSelectedDate,
287
+ hasError,
288
+ 'aria-invalid': hasError ? true : undefined,
289
+ } }), _jsx("div", { children: _jsx("button", { type: "button", onClick: () => setSubmitted(true), style: { padding: 'var(--spacing-small) var(--spacing-medium)' }, children: "Submit" }) }), submitted && selectedDate && (_jsxs("p", { style: { margin: 0, color: 'var(--color-semantic-success-600)', fontSize: '0.875rem' }, children: ["Appointment booked for", ' ', selectedDate.toLocaleDateString('en-GB'), "."] }))] }));
50
290
  };
51
- export const FriendlyFormat = {
52
- name: 'Friendly Format',
291
+ // ---------------------------------------------------------------------------
292
+ // Stories
293
+ // ---------------------------------------------------------------------------
294
+ export const Default = withDescription({
295
+ args: {
296
+ id: 'default-date',
297
+ },
298
+ render: args => (_jsx("div", { style: { maxWidth: '280px' }, children: _jsx(DatePicker, { ...args }) })),
299
+ }, [
300
+ 'The interactive canvas — every prop is wired to the Controls panel.',
301
+ 'Empty field shows the **DD/MM/YYYY** hint overlay (`displayFormat="default"`).',
302
+ 'Click the calendar icon or type directly into the field to select a date.',
303
+ ].join(' '));
304
+ export const FriendlyFormat = withDescription({
53
305
  args: {
54
306
  displayFormat: 'friendly',
307
+ id: 'friendly-date',
55
308
  },
309
+ render: args => (_jsx("div", { style: { maxWidth: '280px' }, children: _jsx(DatePicker, { ...args }) })),
56
310
  parameters: {
311
+ controls: { disable: true },
57
312
  docs: {
58
- description: {
59
- story: 'Empty field shows hint **Pick a date**.',
313
+ source: {
314
+ language: 'tsx',
315
+ code: `
316
+ import { DatePicker } from '@arbor-education/design-system.components';
317
+
318
+ function FriendlyFormatExample() {
319
+ return (
320
+ <DatePicker
321
+ id="event-date"
322
+ displayFormat="friendly"
323
+ onChange={(date) => {
324
+ // date is Date | undefined — not a string
325
+ console.log('Event date:', date?.toLocaleDateString('en-GB'));
326
+ }}
327
+ />
328
+ );
329
+ }
330
+ export default FriendlyFormatExample;
331
+ `.trim(),
60
332
  },
61
333
  },
62
334
  },
63
- };
64
- /** `placeholder` overrides the default empty-state hint. */
65
- export const PlaceholderCustomOverride = {
66
- name: 'Placeholder · custom copy',
67
- args: {
68
- displayFormat: 'default',
69
- placeholder: 'e.g. 25/12/2024',
335
+ }, '`displayFormat="friendly"` shows **Pick a date** instead of the `DD/MM/YYYY` format hint. Use for contexts where a conversational label reads better than a technical format string.');
336
+ export const WithDefaultValue = withDescription({
337
+ render: () => (_jsx("div", { style: { maxWidth: '280px' }, children: _jsx(DatePicker, { id: "default-value-date", defaultValue: new Date(2024, 8, 1) }) })),
338
+ parameters: {
339
+ controls: { disable: true },
340
+ docs: {
341
+ source: {
342
+ language: 'tsx',
343
+ code: `
344
+ import { DatePicker } from '@arbor-education/design-system.components';
345
+
346
+ function EditEnrollmentDate() {
347
+ // Month is zero-indexed: 8 = September
348
+ const currentEnrollmentDate = new Date(2024, 8, 1);
349
+
350
+ return (
351
+ <DatePicker
352
+ id="enrollment-date"
353
+ defaultValue={currentEnrollmentDate}
354
+ onChange={(date) => {
355
+ // date is Date | undefined — not a string
356
+ console.log('Updated to:', date?.toLocaleDateString('en-GB'));
357
+ }}
358
+ />
359
+ );
360
+ }
361
+ export default EditEnrollmentDate;
362
+ `.trim(),
363
+ },
364
+ },
70
365
  },
366
+ }, [
367
+ 'Use `defaultValue` to pre-populate an uncontrolled DatePicker — for example when an admin opens a',
368
+ 'pupil\'s enrollment record to edit it. The prop must be a `Date` object (month is zero-indexed:',
369
+ '`new Date(2024, 8, 1)` = 1 September 2024). Passing a string is a type error.',
370
+ ].join(' '));
371
+ export const WithPlaceholder = withDescription({
372
+ render: () => (_jsx("div", { style: { maxWidth: '280px' }, children: _jsx(DatePicker, { id: "placeholder-date", placeholder: "Choose term start date" }) })),
71
373
  parameters: {
374
+ controls: { disable: true },
72
375
  docs: {
73
- description: {
74
- story: 'The optional `placeholder` prop replaces the default hint.',
376
+ source: {
377
+ language: 'tsx',
378
+ code: `
379
+ import { DatePicker } from '@arbor-education/design-system.components';
380
+
381
+ function TermStartDatePicker() {
382
+ return (
383
+ <DatePicker
384
+ id="term-start-date"
385
+ placeholder="Choose term start date"
386
+ onChange={(date) => {
387
+ console.log('Term start:', date?.toLocaleDateString('en-GB'));
388
+ }}
389
+ />
390
+ );
391
+ }
392
+ export default TermStartDatePicker;
393
+ `.trim(),
75
394
  },
76
395
  },
77
396
  },
78
- };
79
- /** Friendly format with custom hint copy. */
80
- export const PlaceholderFriendlyWithCustomCopy = {
81
- name: 'Placeholder · friendly format, custom hint',
82
- args: {
83
- displayFormat: 'friendly',
84
- placeholder: 'Choose a date',
397
+ }, [
398
+ 'When `placeholder` is set and the field is empty, the input becomes **read-only** and the',
399
+ 'calendar opens on **click only** — Tab focus does not trigger it. This prevents the popup',
400
+ 'from unexpectedly opening as keyboard users navigate through a form.',
401
+ ].join(' '));
402
+ export const ErrorState = withDescription({
403
+ render: () => (_jsxs("div", { style: { maxWidth: '280px' }, children: [_jsx(DatePicker, { id: "error-state-date", hasError: true, "aria-invalid": true, "aria-describedby": "error-state-msg" }), _jsx("p", { id: "error-state-msg", role: "alert", style: { margin: 'var(--spacing-xsmall) 0 0', color: 'var(--color-semantic-destructive-600)', fontSize: '0.875rem' }, children: "Please select a valid enrollment date." })] })),
404
+ parameters: {
405
+ controls: { disable: true },
406
+ docs: {
407
+ source: {
408
+ language: 'tsx',
409
+ code: `
410
+ import { DatePicker } from '@arbor-education/design-system.components';
411
+
412
+ // Standalone — set both hasError (visual) and aria-invalid (screen reader) yourself.
413
+ // Inside <FormField> both are handled automatically when errorText is set.
414
+ function EnrollmentDateWithError() {
415
+ return (
416
+ <>
417
+ <DatePicker
418
+ id="enrollment-date"
419
+ hasError
420
+ aria-invalid={true}
421
+ aria-describedby="enrollment-date-error"
422
+ />
423
+ <p id="enrollment-date-error" role="alert">
424
+ Please select a valid enrollment date.
425
+ </p>
426
+ </>
427
+ );
428
+ }
429
+ export default EnrollmentDateWithError;
430
+ `.trim(),
431
+ },
432
+ },
85
433
  },
434
+ }, [
435
+ 'The error state requires **both** `hasError` (visual red border) and `aria-invalid={true}`',
436
+ '(screen-reader signal). Use `aria-describedby` to link the input to the error message element.',
437
+ 'When using `<FormField>`, set `errorText` and the component handles all three automatically.',
438
+ ].join(' '));
439
+ export const ControlledWithDisplay = withDescription({
440
+ render: () => _jsx(ControlledWithDisplayTemplate, {}),
86
441
  parameters: {
442
+ controls: { disable: true },
87
443
  docs: {
88
- description: {
89
- story: '`displayFormat="friendly"` with a custom hint instead of **Pick a date**.',
444
+ source: {
445
+ language: 'tsx',
446
+ code: `
447
+ import { useState } from 'react';
448
+ import { DatePicker } from '@arbor-education/design-system.components';
449
+
450
+ function ControlledDatePickerExample() {
451
+ const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined);
452
+
453
+ return (
454
+ <div>
455
+ <DatePicker
456
+ id="event-date"
457
+ onChange={setSelectedDate}
458
+ />
459
+ <p>
460
+ Selected:{' '}
461
+ <code>
462
+ {selectedDate
463
+ ? selectedDate.toLocaleDateString('en-GB')
464
+ : '(none)'}
465
+ </code>
466
+ </p>
467
+ </div>
468
+ );
469
+ }
470
+ export default ControlledDatePickerExample;
471
+ `.trim(),
90
472
  },
91
473
  },
92
474
  },
93
- };
475
+ }, [
476
+ '`onChange` receives a `Date` object (or `undefined`) — never a string. Use',
477
+ '`date.toLocaleDateString(\'en-GB\')` for human-readable display.',
478
+ 'This controlled example stores the value in state and renders it below the field.',
479
+ ].join(' '));
480
+ export const ControlledWithValidation = withDescription({
481
+ render: () => _jsx(ControlledWithValidationTemplate, {}),
482
+ parameters: {
483
+ controls: { disable: true },
484
+ docs: {
485
+ source: {
486
+ language: 'tsx',
487
+ code: `
488
+ import { useState } from 'react';
489
+ import { DatePicker } from '@arbor-education/design-system.components';
490
+
491
+ function FutureDatePicker() {
492
+ const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined);
493
+ const [error, setError] = useState<string | undefined>(undefined);
494
+
495
+ const today = new Date();
496
+ today.setHours(0, 0, 0, 0);
497
+
498
+ function handleChange(date: Date | undefined) {
499
+ setSelectedDate(date);
500
+ if (!date) { setError(undefined); return; }
501
+ const picked = new Date(date);
502
+ picked.setHours(0, 0, 0, 0);
503
+ if (picked <= today) {
504
+ setError('The event date must be in the future. Please pick a later date.');
505
+ } else {
506
+ setError(undefined);
507
+ }
508
+ }
509
+
510
+ return (
511
+ <div>
512
+ <DatePicker
513
+ id="event-date"
514
+ onChange={handleChange}
515
+ hasError={!!error}
516
+ aria-invalid={error ? true : undefined}
517
+ aria-describedby={error ? 'event-date-error' : undefined}
518
+ />
519
+ {error && (
520
+ <p id="event-date-error" role="alert">
521
+ {error}
522
+ </p>
523
+ )}
524
+ </div>
525
+ );
526
+ }
527
+ export default FutureDatePicker;
528
+ `.trim(),
529
+ },
530
+ },
531
+ },
532
+ }, [
533
+ 'Real-time validation: only future dates are accepted. Selecting today or a past date triggers',
534
+ 'error styling (`hasError` + `aria-invalid` + `aria-describedby`). Clearing the date removes the error.',
535
+ 'The accessible `role="alert"` paragraph announces the error to screen readers immediately.',
536
+ ].join(' '));
537
+ export const WithFormField = withDescription({
538
+ render: () => _jsx(WithFormFieldTemplate, {}),
539
+ parameters: {
540
+ controls: { disable: true },
541
+ docs: {
542
+ source: {
543
+ language: 'tsx',
544
+ code: `
545
+ import { FormField } from '@arbor-education/design-system.components';
546
+
547
+ function EnrollmentDateField() {
548
+ return (
549
+ <FormField
550
+ label="Pupil enrollment date"
551
+ id="enrollment-date"
552
+ inputType="datePicker"
553
+ fieldDescription="Select the date the pupil will join the school."
554
+ inputProps={{
555
+ onChange: (date) => {
556
+ // date is Date | undefined
557
+ console.log('Enrollment date:', date?.toLocaleDateString('en-GB'));
558
+ },
559
+ }}
560
+ />
561
+ );
562
+ }
563
+ export default EnrollmentDateField;
564
+ `.trim(),
565
+ },
566
+ },
567
+ },
568
+ }, [
569
+ 'The recommended form usage: `<FormField inputType="datePicker">` provides the accessible',
570
+ 'label, description, and error layout. Pass DatePicker-specific props through `inputProps`.',
571
+ 'The `label`, `fieldDescription`, and `errorText` props belong on `<FormField>` itself.',
572
+ ].join(' '));
573
+ export const WithFormFieldAndError = withDescription({
574
+ render: () => _jsx(WithFormFieldAndErrorTemplate, {}),
575
+ parameters: {
576
+ controls: { disable: true },
577
+ docs: {
578
+ source: {
579
+ language: 'tsx',
580
+ code: `
581
+ import { useState } from 'react';
582
+ import { FormField } from '@arbor-education/design-system.components';
583
+
584
+ function ParentEveningForm() {
585
+ const [submitted, setSubmitted] = useState(false);
586
+ const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined);
587
+ const hasError = submitted && !selectedDate;
588
+
589
+ return (
590
+ <div>
591
+ <FormField
592
+ label="Parent evening appointment"
593
+ id="parent-evening-date"
594
+ inputType="datePicker"
595
+ errorText={
596
+ hasError
597
+ ? 'Please select an appointment date before submitting.'
598
+ : undefined
599
+ }
600
+ inputProps={{
601
+ onChange: setSelectedDate,
602
+ hasError,
603
+ 'aria-invalid': hasError ? true : undefined,
604
+ }}
605
+ />
606
+ <button type="button" onClick={() => setSubmitted(true)}>
607
+ Submit
608
+ </button>
609
+ </div>
610
+ );
611
+ }
612
+ export default ParentEveningForm;
613
+ `.trim(),
614
+ },
615
+ },
616
+ },
617
+ }, [
618
+ 'A submit-gated form: clicking Submit without a date triggers the full error pattern.',
619
+ '`errorText` on `<FormField>` renders the message in the correct accessible layout below the input,',
620
+ 'linked via `aria-describedby` automatically. Once a date is chosen, the error clears.',
621
+ ].join(' '));
94
622
  //# sourceMappingURL=DatePicker.stories.js.map