@arbor-education/design-system.components 0.15.0 → 0.16.1

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 (304) hide show
  1. package/.gather/skills/write-stories/SKILL.md +207 -271
  2. package/.storybook/preview.ts +5 -0
  3. package/CHANGELOG.md +23 -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/radio/RadioButtonGroup.d.ts +6 -2
  60. package/dist/components/formField/inputs/radio/RadioButtonGroup.d.ts.map +1 -1
  61. package/dist/components/formField/inputs/radio/RadioButtonGroup.js.map +1 -1
  62. package/dist/components/formField/inputs/radio/RadioButtonInput.stories.d.ts.map +1 -1
  63. package/dist/components/formField/inputs/radio/RadioButtonInput.stories.js +61 -49
  64. package/dist/components/formField/inputs/radio/RadioButtonInput.stories.js.map +1 -1
  65. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.stories.d.ts +188 -166
  66. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.stories.d.ts.map +1 -1
  67. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.stories.js +821 -160
  68. package/dist/components/formField/inputs/selectDropdown/SelectDropdown.stories.js.map +1 -1
  69. package/dist/components/formField/inputs/time/TimeInput.stories.d.ts +176 -22
  70. package/dist/components/formField/inputs/time/TimeInput.stories.d.ts.map +1 -1
  71. package/dist/components/formField/inputs/time/TimeInput.stories.js +851 -92
  72. package/dist/components/formField/inputs/time/TimeInput.stories.js.map +1 -1
  73. package/dist/components/formField/label/Label.stories.d.ts +54 -5
  74. package/dist/components/formField/label/Label.stories.d.ts.map +1 -1
  75. package/dist/components/formField/label/Label.stories.js +238 -4
  76. package/dist/components/formField/label/Label.stories.js.map +1 -1
  77. package/dist/components/icoText/IcoText.stories.d.ts +32 -6
  78. package/dist/components/icoText/IcoText.stories.d.ts.map +1 -1
  79. package/dist/components/icoText/IcoText.stories.js +309 -14
  80. package/dist/components/icoText/IcoText.stories.js.map +1 -1
  81. package/dist/components/kpiCard/KPICard.stories.d.ts +100 -2
  82. package/dist/components/kpiCard/KPICard.stories.d.ts.map +1 -1
  83. package/dist/components/kpiCard/KPICard.stories.js +354 -10
  84. package/dist/components/kpiCard/KPICard.stories.js.map +1 -1
  85. package/dist/components/kvpList/KVPList.stories.d.ts +57 -4
  86. package/dist/components/kvpList/KVPList.stories.d.ts.map +1 -1
  87. package/dist/components/kvpList/KVPList.stories.js +403 -10
  88. package/dist/components/kvpList/KVPList.stories.js.map +1 -1
  89. package/dist/components/modal/Modal.stories.d.ts +113 -9
  90. package/dist/components/modal/Modal.stories.d.ts.map +1 -1
  91. package/dist/components/modal/Modal.stories.js +633 -13
  92. package/dist/components/modal/Modal.stories.js.map +1 -1
  93. package/dist/components/modal/modalManager/ModalManager.stories.d.ts +34 -10
  94. package/dist/components/modal/modalManager/ModalManager.stories.d.ts.map +1 -1
  95. package/dist/components/modal/modalManager/ModalManager.stories.js +463 -85
  96. package/dist/components/modal/modalManager/ModalManager.stories.js.map +1 -1
  97. package/dist/components/pill/Pill.d.ts.map +1 -1
  98. package/dist/components/pill/Pill.js +1 -1
  99. package/dist/components/pill/Pill.js.map +1 -1
  100. package/dist/components/pill/Pill.stories.d.ts.map +1 -1
  101. package/dist/components/pill/Pill.stories.js +11 -13
  102. package/dist/components/pill/Pill.stories.js.map +1 -1
  103. package/dist/components/row/Row.stories.d.ts +1 -2
  104. package/dist/components/row/Row.stories.d.ts.map +1 -1
  105. package/dist/components/row/Row.stories.js +360 -50
  106. package/dist/components/row/Row.stories.js.map +1 -1
  107. package/dist/components/searchBar/SearchBar.stories.d.ts +52 -4
  108. package/dist/components/searchBar/SearchBar.stories.d.ts.map +1 -1
  109. package/dist/components/searchBar/SearchBar.stories.js +428 -36
  110. package/dist/components/searchBar/SearchBar.stories.js.map +1 -1
  111. package/dist/components/section/Section.stories.d.ts +11 -41
  112. package/dist/components/section/Section.stories.d.ts.map +1 -1
  113. package/dist/components/section/Section.stories.js +494 -56
  114. package/dist/components/section/Section.stories.js.map +1 -1
  115. package/dist/components/singleUser/SingleUser.stories.d.ts +5 -4
  116. package/dist/components/singleUser/SingleUser.stories.d.ts.map +1 -1
  117. package/dist/components/singleUser/SingleUser.stories.js +303 -31
  118. package/dist/components/singleUser/SingleUser.stories.js.map +1 -1
  119. package/dist/components/slideoverManager/SlideoverManager.stories.d.ts +32 -11
  120. package/dist/components/slideoverManager/SlideoverManager.stories.d.ts.map +1 -1
  121. package/dist/components/slideoverManager/SlideoverManager.stories.js +380 -84
  122. package/dist/components/slideoverManager/SlideoverManager.stories.js.map +1 -1
  123. package/dist/components/table/DSDefaultColDef.d.ts.map +1 -1
  124. package/dist/components/table/DSDefaultColDef.js +4 -3
  125. package/dist/components/table/DSDefaultColDef.js.map +1 -1
  126. package/dist/components/table/Table.d.ts +6 -1
  127. package/dist/components/table/Table.d.ts.map +1 -1
  128. package/dist/components/table/Table.js +8 -3
  129. package/dist/components/table/Table.js.map +1 -1
  130. package/dist/components/table/Table.stories.d.ts +3 -0
  131. package/dist/components/table/Table.stories.d.ts.map +1 -1
  132. package/dist/components/table/Table.stories.js +384 -5
  133. package/dist/components/table/Table.stories.js.map +1 -1
  134. package/dist/components/table/Table.test.js +30 -0
  135. package/dist/components/table/Table.test.js.map +1 -1
  136. package/dist/components/table/TableFooter.stories.d.ts +49 -0
  137. package/dist/components/table/TableFooter.stories.d.ts.map +1 -0
  138. package/dist/components/table/TableFooter.stories.js +137 -0
  139. package/dist/components/table/TableFooter.stories.js.map +1 -0
  140. package/dist/components/table/TableHeader.stories.d.ts +93 -0
  141. package/dist/components/table/TableHeader.stories.d.ts.map +1 -0
  142. package/dist/components/table/TableHeader.stories.js +176 -0
  143. package/dist/components/table/TableHeader.stories.js.map +1 -0
  144. package/dist/components/table/cellEditors/DateCellEditor.stories.d.ts +44 -0
  145. package/dist/components/table/cellEditors/DateCellEditor.stories.d.ts.map +1 -0
  146. package/dist/components/table/cellEditors/DateCellEditor.stories.js +186 -0
  147. package/dist/components/table/cellEditors/DateCellEditor.stories.js.map +1 -0
  148. package/dist/components/table/cellRenderers/BooleanCellRenderer.stories.d.ts +40 -0
  149. package/dist/components/table/cellRenderers/BooleanCellRenderer.stories.d.ts.map +1 -0
  150. package/dist/components/table/cellRenderers/BooleanCellRenderer.stories.js +209 -0
  151. package/dist/components/table/cellRenderers/BooleanCellRenderer.stories.js.map +1 -0
  152. package/dist/components/table/cellRenderers/ButtonCellRenderer.stories.d.ts +48 -0
  153. package/dist/components/table/cellRenderers/ButtonCellRenderer.stories.d.ts.map +1 -0
  154. package/dist/components/table/cellRenderers/ButtonCellRenderer.stories.js +244 -0
  155. package/dist/components/table/cellRenderers/ButtonCellRenderer.stories.js.map +1 -0
  156. package/dist/components/table/cellRenderers/CheckboxCellRenderer.d.ts.map +1 -1
  157. package/dist/components/table/cellRenderers/CheckboxCellRenderer.js +3 -1
  158. package/dist/components/table/cellRenderers/CheckboxCellRenderer.js.map +1 -1
  159. package/dist/components/table/cellRenderers/CheckboxCellRenderer.stories.d.ts +64 -0
  160. package/dist/components/table/cellRenderers/CheckboxCellRenderer.stories.d.ts.map +1 -0
  161. package/dist/components/table/cellRenderers/CheckboxCellRenderer.stories.js +241 -0
  162. package/dist/components/table/cellRenderers/CheckboxCellRenderer.stories.js.map +1 -0
  163. package/dist/components/table/cellRenderers/DefaultCellRenderer.stories.d.ts +55 -0
  164. package/dist/components/table/cellRenderers/DefaultCellRenderer.stories.d.ts.map +1 -0
  165. package/dist/components/table/cellRenderers/DefaultCellRenderer.stories.js +245 -0
  166. package/dist/components/table/cellRenderers/DefaultCellRenderer.stories.js.map +1 -0
  167. package/dist/components/table/cellRenderers/InlineTextCellRenderer.stories.d.ts +67 -0
  168. package/dist/components/table/cellRenderers/InlineTextCellRenderer.stories.d.ts.map +1 -0
  169. package/dist/components/table/cellRenderers/InlineTextCellRenderer.stories.js +221 -0
  170. package/dist/components/table/cellRenderers/InlineTextCellRenderer.stories.js.map +1 -0
  171. package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.d.ts +75 -0
  172. package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.d.ts.map +1 -0
  173. package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.js +270 -0
  174. package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.stories.js.map +1 -0
  175. package/dist/components/table/columnFilters/BooleanFilter.stories.d.ts +57 -0
  176. package/dist/components/table/columnFilters/BooleanFilter.stories.d.ts.map +1 -0
  177. package/dist/components/table/columnFilters/BooleanFilter.stories.js +198 -0
  178. package/dist/components/table/columnFilters/BooleanFilter.stories.js.map +1 -0
  179. package/dist/components/table/columnFilters/TimeFilter.stories.d.ts +58 -0
  180. package/dist/components/table/columnFilters/TimeFilter.stories.d.ts.map +1 -0
  181. package/dist/components/table/columnFilters/TimeFilter.stories.js +207 -0
  182. package/dist/components/table/columnFilters/TimeFilter.stories.js.map +1 -0
  183. package/dist/components/table/pagination/PaginationPanel.stories.d.ts +113 -0
  184. package/dist/components/table/pagination/PaginationPanel.stories.d.ts.map +1 -0
  185. package/dist/components/table/pagination/PaginationPanel.stories.js +272 -0
  186. package/dist/components/table/pagination/PaginationPanel.stories.js.map +1 -0
  187. package/dist/components/table/tableControls/HideColumnsDropdown.d.ts.map +1 -1
  188. package/dist/components/table/tableControls/HideColumnsDropdown.js +9 -3
  189. package/dist/components/table/tableControls/HideColumnsDropdown.js.map +1 -1
  190. package/dist/components/table/tableControls/TableControls.stories.d.ts +151 -0
  191. package/dist/components/table/tableControls/TableControls.stories.d.ts.map +1 -0
  192. package/dist/components/table/tableControls/TableControls.stories.js +356 -0
  193. package/dist/components/table/tableControls/TableControls.stories.js.map +1 -0
  194. package/dist/components/table/tableControls/TableSettingsDropdown.d.ts +27 -1
  195. package/dist/components/table/tableControls/TableSettingsDropdown.d.ts.map +1 -1
  196. package/dist/components/table/tableControls/TableSettingsDropdown.js +53 -26
  197. package/dist/components/table/tableControls/TableSettingsDropdown.js.map +1 -1
  198. package/dist/components/table/tableControls/TableSettingsDropdown.test.d.ts +2 -0
  199. package/dist/components/table/tableControls/TableSettingsDropdown.test.d.ts.map +1 -0
  200. package/dist/components/table/tableControls/TableSettingsDropdown.test.js +178 -0
  201. package/dist/components/table/tableControls/TableSettingsDropdown.test.js.map +1 -0
  202. package/dist/components/tabs/Tabs.stories.d.ts +22 -4
  203. package/dist/components/tabs/Tabs.stories.d.ts.map +1 -1
  204. package/dist/components/tabs/Tabs.stories.js +398 -22
  205. package/dist/components/tabs/Tabs.stories.js.map +1 -1
  206. package/dist/components/tabs/TabsItem.stories.d.ts +54 -1
  207. package/dist/components/tabs/TabsItem.stories.d.ts.map +1 -1
  208. package/dist/components/tabs/TabsItem.stories.js +61 -9
  209. package/dist/components/tabs/TabsItem.stories.js.map +1 -1
  210. package/dist/components/toast/Toast.stories.d.ts +103 -10
  211. package/dist/components/toast/Toast.stories.d.ts.map +1 -1
  212. package/dist/components/toast/Toast.stories.js +409 -47
  213. package/dist/components/toast/Toast.stories.js.map +1 -1
  214. package/dist/components/toggle/Toggle.stories.d.ts +61 -46
  215. package/dist/components/toggle/Toggle.stories.d.ts.map +1 -1
  216. package/dist/components/toggle/Toggle.stories.js +311 -122
  217. package/dist/components/toggle/Toggle.stories.js.map +1 -1
  218. package/dist/components/tooltip/Tooltip.stories.d.ts +78 -6
  219. package/dist/components/tooltip/Tooltip.stories.d.ts.map +1 -1
  220. package/dist/components/tooltip/Tooltip.stories.js +413 -7
  221. package/dist/components/tooltip/Tooltip.stories.js.map +1 -1
  222. package/dist/components/tooltip/TooltipWrapper.stories.d.ts +71 -7
  223. package/dist/components/tooltip/TooltipWrapper.stories.d.ts.map +1 -1
  224. package/dist/components/tooltip/TooltipWrapper.stories.js +238 -10
  225. package/dist/components/tooltip/TooltipWrapper.stories.js.map +1 -1
  226. package/dist/index.css +8 -0
  227. package/dist/index.css.map +1 -1
  228. package/dist/utils/PopupParentContext.stories.d.ts +17 -0
  229. package/dist/utils/PopupParentContext.stories.d.ts.map +1 -0
  230. package/dist/utils/PopupParentContext.stories.js +266 -0
  231. package/dist/utils/PopupParentContext.stories.js.map +1 -0
  232. package/dist/utils/getDefaultPopupParent.d.ts.map +1 -1
  233. package/dist/utils/getDefaultPopupParent.js +6 -0
  234. package/dist/utils/getDefaultPopupParent.js.map +1 -1
  235. package/package.json +1 -1
  236. package/src/components/articleCard/ArticleCard.stories.tsx +524 -111
  237. package/src/components/avatar/Avatar.stories.tsx +504 -59
  238. package/src/components/avatarGroup/AvatarGroup.stories.tsx +977 -175
  239. package/src/components/banner/Banner.stories.tsx +7 -3
  240. package/src/components/card/Card.stories.tsx +466 -36
  241. package/src/components/combobox/Combobox.stories.tsx +867 -260
  242. package/src/components/datePicker/DatePicker.stories.tsx +777 -60
  243. package/src/components/dateTimePicker/DateTimePicker.stories.tsx +910 -132
  244. package/src/components/editableText/EditableText.stories.tsx +567 -91
  245. package/src/components/formField/FormField.test.tsx +6 -0
  246. package/src/components/formField/FormField.tsx +5 -0
  247. package/src/components/formField/fieldset/Fieldset.stories.tsx +761 -51
  248. package/src/components/formField/inputs/checkbox/CheckboxGroup.tsx +1 -1
  249. package/src/components/formField/inputs/checkbox/CheckboxInput.tsx +1 -1
  250. package/src/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.tsx +504 -11
  251. package/src/components/formField/inputs/radio/RadioButtonGroup.tsx +17 -4
  252. package/src/components/formField/inputs/radio/RadioButtonInput.stories.tsx +71 -59
  253. package/src/components/formField/inputs/selectDropdown/SelectDropdown.stories.tsx +1079 -168
  254. package/src/components/formField/inputs/time/TimeInput.stories.tsx +1140 -104
  255. package/src/components/formField/label/Label.stories.tsx +317 -8
  256. package/src/components/icoText/IcoText.stories.tsx +442 -31
  257. package/src/components/kpiCard/KPICard.stories.tsx +475 -30
  258. package/src/components/kvpList/KVPList.stories.tsx +593 -26
  259. package/src/components/modal/Modal.stories.tsx +963 -26
  260. package/src/components/modal/modalManager/ModalManager.stories.tsx +612 -454
  261. package/src/components/pill/Pill.stories.tsx +11 -13
  262. package/src/components/pill/Pill.tsx +1 -0
  263. package/src/components/row/Row.stories.tsx +474 -58
  264. package/src/components/searchBar/SearchBar.stories.tsx +570 -38
  265. package/src/components/section/Section.stories.tsx +723 -70
  266. package/src/components/singleUser/SingleUser.stories.tsx +393 -34
  267. package/src/components/slideoverManager/SlideoverManager.stories.tsx +572 -342
  268. package/src/components/table/DSDefaultColDef.ts +25 -5
  269. package/src/components/table/Table.stories.tsx +460 -5
  270. package/src/components/table/Table.test.tsx +53 -0
  271. package/src/components/table/Table.tsx +9 -2
  272. package/src/components/table/TableFooter.stories.tsx +196 -0
  273. package/src/components/table/TableHeader.stories.tsx +251 -0
  274. package/src/components/table/cellEditors/DateCellEditor.stories.tsx +245 -0
  275. package/src/components/table/cellRenderers/BooleanCellRenderer.stories.tsx +278 -0
  276. package/src/components/table/cellRenderers/ButtonCellRenderer.stories.tsx +333 -0
  277. package/src/components/table/cellRenderers/CheckboxCellRenderer.stories.tsx +337 -0
  278. package/src/components/table/cellRenderers/CheckboxCellRenderer.tsx +5 -1
  279. package/src/components/table/cellRenderers/DefaultCellRenderer.stories.tsx +342 -0
  280. package/src/components/table/cellRenderers/InlineTextCellRenderer.stories.tsx +292 -0
  281. package/src/components/table/cellRenderers/SelectDropdownCellRenderer.stories.tsx +369 -0
  282. package/src/components/table/columnFilters/BooleanFilter.stories.tsx +268 -0
  283. package/src/components/table/columnFilters/TimeFilter.stories.tsx +281 -0
  284. package/src/components/table/pagination/PaginationPanel.stories.tsx +327 -0
  285. package/src/components/table/tableControls/HideColumnsDropdown.tsx +11 -2
  286. package/src/components/table/tableControls/TableControls.stories.tsx +415 -0
  287. package/src/components/table/tableControls/TableSettingsDropdown.test.tsx +207 -0
  288. package/src/components/table/tableControls/TableSettingsDropdown.tsx +103 -39
  289. package/src/components/tabs/Tabs.stories.tsx +540 -60
  290. package/src/components/tabs/TabsItem.stories.tsx +82 -8
  291. package/src/components/toast/Toast.stories.tsx +539 -77
  292. package/src/components/toggle/Toggle.stories.tsx +371 -135
  293. package/src/components/tooltip/Tooltip.stories.tsx +606 -15
  294. package/src/components/tooltip/TooltipWrapper.stories.tsx +348 -12
  295. package/src/docs/Contributing.mdx +241 -0
  296. package/src/docs/UsingComponents.mdx +93 -0
  297. package/src/docs/Welcome.mdx +68 -0
  298. package/src/global.scss +7 -0
  299. package/src/utils/PopupParentContext.stories.tsx +367 -0
  300. package/src/utils/getDefaultPopupParent.ts +6 -0
  301. package/.ralph/storybook-upgrade/knowledge.md +0 -308
  302. package/.ralph/storybook-upgrade/prd.json +0 -777
  303. package/.ralph/storybook-upgrade/progress.md +0 -342
  304. package/src/components/table/TableWIP.mdx +0 -3
@@ -1,28 +1,289 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { Fieldset } from './Fieldset';
3
- import { FormField } from '../FormField';
4
- import { CheckboxInput } from '../inputs/checkbox/CheckboxInput';
5
- import { RadioButtonInput } from '../inputs/radio/RadioButtonInput';
2
+ import {
3
+ Controls,
4
+ Heading as DocHeading,
5
+ Markdown,
6
+ Primary as DocPrimary,
7
+ Stories,
8
+ Subtitle,
9
+ Title,
10
+ } from '@storybook/addon-docs/blocks';
11
+
12
+ import { CheckboxInput } from 'Components/formField/inputs/checkbox/CheckboxInput';
13
+ import { Fieldset } from 'Components/formField/fieldset/Fieldset';
14
+ import { RadioButtonInput } from 'Components/formField/inputs/radio/RadioButtonInput';
15
+ import { FormField } from 'Components/formField/FormField';
16
+
17
+ // ─────────────────────────────────────────────
18
+ // Content strings
19
+ // ─────────────────────────────────────────────
20
+
21
+ const DESCRIPTION_INTRO = `
22
+ The **Fieldset** component is the semantic wrapper for grouping related form controls in the Arbor
23
+ design system. It renders a native HTML \`<fieldset>\` with an optional \`<legend>\`, giving a
24
+ grouped set of inputs a shared label that assistive technology can announce before each control.
25
+
26
+ Under the hood it resets all browser user-agent styles (border, margin, padding) and uses flexbox
27
+ to stack children with consistent spacing via the design-system token
28
+ \`--checkbox-or-radio-button-group-spacing-gap-vertical\`.
29
+
30
+ Use **Fieldset** when the higher-level \`CheckboxGroup\` or \`RadioButtonGroup\` components do not
31
+ cover your layout needs — for example, mixed control types, custom grid arrangements, or consent
32
+ blocks that combine checkboxes with rich text.
33
+
34
+ ---
35
+
36
+ ### When to use
37
+
38
+ | Scenario | Notes |
39
+ |---|---|
40
+ | Custom group of checkboxes | Primary use case — wrap \`CheckboxInput\` components |
41
+ | Custom group of radio buttons | Enforces mutual exclusivity via shared \`name\` attribute |
42
+ | Mixed control group | Combine different control types under one accessible label |
43
+ | Section of a larger form | Groups FormField components under a shared named section |
44
+ | Consent and permissions blocks | Parent consent forms with multiple independent options |
45
+
46
+ ---
47
+
48
+ ### When NOT to use
49
+
50
+ | Scenario | Alternative |
51
+ |---|---|
52
+ | Single labelled input | Use \`FormField\` with \`label\` + \`labelFor\` |
53
+ | Standard checkbox list | Consider \`CheckboxGroup\` if it covers the layout |
54
+ | Standard radio button list | Consider \`RadioButtonGroup\` if it covers the layout |
55
+ | Visual card grouping (non-form) | Use layout primitives — \`<fieldset>\` is for form controls only |
56
+ | Unknown-length async option list | Compose dynamically, but always keep Fieldset + legend |
57
+
58
+ ---
59
+
60
+ ### Component API
61
+
62
+ \`\`\`tsx
63
+ import { Fieldset } from '@arbor-education/design-system.components';
64
+
65
+ // With legend
66
+ <Fieldset legend="Notification preferences">
67
+ <CheckboxInput id="email" name="notifications" label="Email" />
68
+ <CheckboxInput id="sms" name="notifications" label="SMS" />
69
+ </Fieldset>
70
+
71
+ // Without legend (requires aria-label or aria-labelledby for accessibility)
72
+ <h2 id="prefs-heading">Notification preferences</h2>
73
+ <Fieldset aria-labelledby="prefs-heading">
74
+ <CheckboxInput id="email" name="notifications" label="Email" />
75
+ <CheckboxInput id="sms" name="notifications" label="SMS" />
76
+ </Fieldset>
77
+
78
+ // Disable all children at once
79
+ <Fieldset legend="Trip consent" disabled>
80
+ <CheckboxInput id="trip-1" name="consent" label="Year 7 Geography trip" />
81
+ <CheckboxInput id="trip-2" name="consent" label="Year 8 Science museum" />
82
+ </Fieldset>
83
+ \`\`\`
84
+ `.trim();
85
+
86
+ const USAGE_GUIDANCE = `
87
+ ### When to use
88
+
89
+ Fieldset is the right choice when you need to group two or more related form controls and give that
90
+ group an accessible label. The most common patterns in Arbor are:
91
+
92
+ - **Consent blocks** — a set of independent checkboxes that each require explicit opt-in
93
+ - **Preference groups** — a set of radio buttons where only one option is valid
94
+ - **Form sections** — a logical sub-section of a larger form, named with a visible legend
95
+
96
+ ---
97
+
98
+ ### When NOT to use
99
+
100
+ | Anti-pattern | Why it is wrong | What to do instead |
101
+ |---|---|---|
102
+ | Adding a visible border | The UA border is intentionally removed. Adding it back makes fieldset look like a card | Use a \`<div>\` with a border if you need a visual card |
103
+ | Grouping non-form content | Fieldset is a form landmark — assistive technology announces it as such | Use \`<section>\` or \`<div>\` for non-form groupings |
104
+ | Omitting legend with no ARIA fallback | Screen readers have no group label to announce | Always provide \`legend\`, \`aria-label\`, or \`aria-labelledby\` |
105
+ | Nesting fieldsets deeply | Legal HTML but confusing for AT users | Flatten or split into separate form sections |
106
+
107
+ ---
108
+
109
+ ### The \`disabled\` prop — one prop to rule them all
110
+
111
+ Setting \`disabled\` on the Fieldset element is the correct, semantic way to disable an entire group
112
+ of controls. The browser propagates the disabled state to **all descendant form controls**
113
+ automatically — no JavaScript, no CSS hacks, no prop-drilling needed.
114
+
115
+ \`\`\`tsx
116
+ // This ONE prop disables every checkbox/radio/input inside:
117
+ <Fieldset legend="Trip consent" disabled>
118
+ <CheckboxInput id="trip-1" label="Year 7 Geography trip" />
119
+ <CheckboxInput id="trip-2" label="Year 8 Science museum" />
120
+ <CheckboxInput id="trip-3" label="Year 9 Drama workshop" />
121
+ </Fieldset>
122
+ \`\`\`
123
+
124
+ Do **not** pass \`disabled\` to each child individually when you want to disable the whole group —
125
+ that is more code, more error-prone, and is not semantically equivalent.
126
+
127
+ ---
128
+
129
+ ### Legend visibility
130
+
131
+ The \`legend\` prop renders a \`<legend>\` element as the **first child** of the fieldset. This is
132
+ enforced by the component. Do not try to move it via CSS positioning — the browser ignores
133
+ \`position: absolute\` on \`<legend>\` in many layouts and the AT reading order depends on it being
134
+ first in the DOM.
135
+ `.trim();
136
+
137
+ const DEVELOPER_NOTES = `
138
+ ### Critical usage patterns
139
+
140
+ #### Always label your fieldset
141
+
142
+ A fieldset without any group label fails WCAG 1.3.1 (Info and Relationships). Use one of:
143
+
144
+ 1. **\`legend\` prop** (preferred) — renders a visible \`<legend>\` element
145
+ 2. **\`aria-label\`** — invisible label string (use when design requires no visible heading)
146
+ 3. **\`aria-labelledby\`** — points to an existing heading element by \`id\`
147
+
148
+ #### Radio button mutual exclusivity
149
+
150
+ For radio buttons, share the same \`name\` attribute across all \`RadioButtonInput\` children.
151
+ The \`<fieldset>\` provides the group semantics; the shared \`name\` enforces single-selection.
152
+
153
+ \`\`\`tsx
154
+ <Fieldset legend="Report access level">
155
+ <RadioButtonInput name="access" id="access-view" label="View only" value="view" />
156
+ <RadioButtonInput name="access" id="access-edit" label="View and edit" value="edit" />
157
+ <RadioButtonInput name="access" id="access-admin" label="Full admin" value="admin" />
158
+ </Fieldset>
159
+ \`\`\`
160
+
161
+ #### Do not add extra wrapper divs around children
162
+
163
+ The Fieldset already applies \`display: flex; flex-direction: column; gap: var(--checkbox-or-radio-button-group-spacing-gap-vertical)\`.
164
+ Adding extra \`<div>\` wrappers around each child will break the spacing rhythm.
165
+
166
+ ---
167
+
168
+ ### Accessibility
169
+
170
+ | Concern | How it is addressed |
171
+ |---|---|
172
+ | Group label | \`<legend>\` is the first child — screen readers announce it before each control in the group |
173
+ | Disabled state | Native \`disabled\` on \`<fieldset>\` propagates to all descendants — no JS needed |
174
+ | No visible legend | Use \`aria-label\` or \`aria-labelledby\` — never leave the group unlabelled |
175
+ | Keyboard navigation | All standard browser keyboard behaviour is preserved — no custom handlers needed |
176
+ | WCAG 1.3.1 | Grouping via fieldset+legend satisfies Info and Relationships at level A |
177
+
178
+ ---
179
+
180
+ ### TypeScript types
181
+
182
+ \`\`\`ts
183
+ import type { FieldsetProps } from '@arbor-education/design-system.components';
184
+ \`\`\`
185
+
186
+ | Prop | Type | Default | Description |
187
+ |---|---|---|
188
+ | \`legend\` | \`string\` | — | Renders a \`<legend>\` element as the first child. Omit only when using \`aria-label\` or \`aria-labelledby\` |
189
+ | \`disabled\` | \`boolean\` | \`false\` | Disables all descendant form controls via native HTML propagation |
190
+ | \`children\` | \`ReactNode\` | — | Form controls to group. Typically \`CheckboxInput\` or \`RadioButtonInput\` |
191
+ | \`className\` | \`string\` | — | Additional CSS classes for the \`<fieldset>\` element |
192
+ | \`aria-label\` | \`string\` | — | Invisible accessible label — use when there is no visible legend |
193
+ | \`aria-labelledby\` | \`string\` | — | \`id\` of an existing heading element — alternative to \`legend\` |
194
+ `.trim();
195
+
196
+ const RELATED_COMPONENTS = `
197
+ ---
198
+
199
+ ### Related components
200
+
201
+ | Component | Storybook link |
202
+ |---|---|
203
+ | FormField | [View FormField](?path=/docs/components-formfield-formfield--docs) |
204
+ | CheckboxInput | [View CheckboxInput](?path=/docs/components-formfield-inputs-checkboxinput--docs) |
205
+ | RadioButtonInput | [View RadioButtonInput](?path=/docs/components-formfield-inputs-radiobuttoninput--docs) |
206
+ `.trim();
207
+
208
+ const PROPS_INTRO = `
209
+ Use the controls below to toggle \`legend\` and \`disabled\` and see how Fieldset responds in real
210
+ time. The \`children\` prop cannot be set via the controls panel directly — the Default story
211
+ renders \`CheckboxInput\` components as the primary use case.
212
+ `.trim();
213
+
214
+ // ─────────────────────────────────────────────
215
+ // Custom docs page
216
+ // ─────────────────────────────────────────────
217
+
218
+ function FieldsetDocsPage() {
219
+ return (
220
+ <>
221
+ <Title />
222
+ <Subtitle />
223
+ <Markdown>{DESCRIPTION_INTRO}</Markdown>
224
+ <DocHeading>Interactive example</DocHeading>
225
+ <Markdown>{PROPS_INTRO}</Markdown>
226
+ <DocPrimary />
227
+ <Controls />
228
+ <DocHeading>Usage guidance</DocHeading>
229
+ <Markdown>{USAGE_GUIDANCE}</Markdown>
230
+ <DocHeading>Developer notes</DocHeading>
231
+ <Markdown>{DEVELOPER_NOTES}</Markdown>
232
+ <DocHeading>Examples</DocHeading>
233
+ <Stories title="" />
234
+ <Markdown>{RELATED_COMPONENTS}</Markdown>
235
+ </>
236
+ );
237
+ }
238
+
239
+ // ─────────────────────────────────────────────
240
+ // Meta
241
+ // ─────────────────────────────────────────────
6
242
 
7
243
  const meta = {
8
244
  title: 'Components/FormField/Fieldset',
9
245
  component: Fieldset,
246
+ tags: ['autodocs'],
10
247
  parameters: {
11
248
  layout: 'padded',
249
+ docs: { page: FieldsetDocsPage },
12
250
  },
13
- tags: ['autodocs'],
14
251
  argTypes: {
15
252
  legend: {
16
- control: 'text',
17
- description: 'The legend text for the fieldset',
253
+ description:
254
+ 'Renders a `<legend>` element as the first child of the fieldset. Provides the accessible group label announced by screen readers before each control in the group. Omit only when using `aria-label` or `aria-labelledby`.',
255
+ control: { type: 'text' },
256
+ table: {
257
+ type: { summary: 'string' },
258
+ defaultValue: { summary: '—' },
259
+ },
18
260
  },
19
261
  disabled: {
20
- control: 'boolean',
21
- description: 'Disable all form controls within the fieldset',
262
+ description:
263
+ 'Disables all descendant form controls via native HTML propagation. **One prop disables everything** — no need to pass `disabled` to each child individually.',
264
+ control: { type: 'boolean' },
265
+ table: {
266
+ type: { summary: 'boolean' },
267
+ defaultValue: { summary: 'false' },
268
+ },
22
269
  },
23
270
  children: {
271
+ description:
272
+ 'Form controls to group. Typically `CheckboxInput` or `RadioButtonInput` components. Do not wrap children in extra `<div>` elements — the fieldset already applies flex + gap spacing.',
24
273
  control: false,
25
- description: 'Form controls and other content to display within the fieldset',
274
+ table: {
275
+ type: { summary: 'ReactNode' },
276
+ defaultValue: { summary: '—' },
277
+ },
278
+ },
279
+ className: {
280
+ description:
281
+ 'Additional CSS class(es) applied to the `<fieldset>` element. Use design-token values for any layout overrides.',
282
+ control: { type: 'text' },
283
+ table: {
284
+ type: { summary: 'string' },
285
+ defaultValue: { summary: '—' },
286
+ },
26
287
  },
27
288
  },
28
289
  } satisfies Meta<typeof Fieldset>;
@@ -30,60 +291,509 @@ const meta = {
30
291
  export default meta;
31
292
  type Story = StoryObj<typeof meta>;
32
293
 
33
- // Default fieldset with simple content
294
+ // ─────────────────────────────────────────────
295
+ // Helpers
296
+ // ─────────────────────────────────────────────
297
+
298
+ /** Wraps a story with a consistent description below the rendered example. */
299
+ function withDescription(description: string, story: Story): Story {
300
+ return {
301
+ ...story,
302
+ parameters: {
303
+ ...story.parameters,
304
+ docs: {
305
+ ...story.parameters?.docs,
306
+ description: { story: description },
307
+ },
308
+ },
309
+ };
310
+ }
311
+
312
+ // ─────────────────────────────────────────────
313
+ // Stories
314
+ // ─────────────────────────────────────────────
315
+
34
316
  export const Default: Story = {
35
317
  args: {
36
- legend: 'Personal Information',
37
- children: (
38
- <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
318
+ legend: 'Consent and Permissions',
319
+ disabled: false,
320
+ },
321
+ render: args => (
322
+ <Fieldset {...args}>
323
+ <CheckboxInput id="consent-trips" name="consent" label="Consent for school trips" onChange={() => {}} />
324
+ <CheckboxInput id="consent-photos" name="consent" label="Consent for photographs" onChange={() => {}} />
325
+ <CheckboxInput id="consent-data" name="consent" label="Consent for data sharing with partner schools" onChange={() => {}} />
326
+ </Fieldset>
327
+ ),
328
+ };
329
+
330
+ export const WithRadioButtons: Story = withDescription(
331
+ 'Radio buttons inside a fieldset enforce single-selection. Share the same `name` attribute across all `RadioButtonInput` children — the fieldset provides the group semantics, the shared `name` enforces mutual exclusivity.',
332
+ {
333
+ parameters: {
334
+ controls: { disable: true },
335
+ docs: {
336
+ source: {
337
+ code: `
338
+ import { Fieldset, RadioButtonInput } from '@arbor-education/design-system.components';
339
+
340
+ export default function ReportAccessFieldset() {
341
+ return (
342
+ <Fieldset legend="Report access level">
343
+ <RadioButtonInput
344
+ id="access-view"
345
+ name="access"
346
+ value="view"
347
+ label="View only — can read reports but not download"
348
+ />
349
+ <RadioButtonInput
350
+ id="access-download"
351
+ name="access"
352
+ value="download"
353
+ label="View and download — can export to PDF"
354
+ />
355
+ <RadioButtonInput
356
+ id="access-admin"
357
+ name="access"
358
+ value="admin"
359
+ label="Full admin — can view, download, and share with parents"
360
+ />
361
+ </Fieldset>
362
+ );
363
+ }
364
+ `.trim(),
365
+ },
366
+ },
367
+ },
368
+ render: () => (
369
+ <Fieldset legend="Report access level">
370
+ <RadioButtonInput
371
+ id="access-view"
372
+ name="access"
373
+ value="view"
374
+ label="View only — can read reports but not download"
375
+ />
376
+ <RadioButtonInput
377
+ id="access-download"
378
+ name="access"
379
+ value="download"
380
+ label="View and download — can export to PDF"
381
+ />
382
+ <RadioButtonInput
383
+ id="access-admin"
384
+ name="access"
385
+ value="admin"
386
+ label="Full admin — can view, download, and share with parents"
387
+ />
388
+ </Fieldset>
389
+ ),
390
+ },
391
+ );
392
+
393
+ export const WithFormFields: Story = withDescription(
394
+ 'Fieldset can wrap `FormField` components to create a named section within a larger form. This is useful for logical groupings like an address block or emergency contact details where each field has its own label.',
395
+ {
396
+ parameters: {
397
+ controls: { disable: true },
398
+ docs: {
399
+ source: {
400
+ code: `
401
+ import { Fieldset, FormField } from '@arbor-education/design-system.components';
402
+
403
+ export default function DietaryRequirementsFieldset() {
404
+ return (
405
+ <Fieldset legend="Dietary requirements">
406
+ <FormField
407
+ id="diet-primary"
408
+ label="Primary dietary requirement"
409
+ inputProps={{ placeholder: 'e.g. Halal, Vegetarian, Vegan' }}
410
+ />
411
+ <FormField
412
+ id="diet-allergies"
413
+ label="Allergies and intolerances"
414
+ fieldDescription="List all known allergens — this information is shared with the school kitchen"
415
+ inputProps={{ placeholder: 'e.g. Peanuts, Gluten, Dairy' }}
416
+ />
417
+ </Fieldset>
418
+ );
419
+ }
420
+ `.trim(),
421
+ },
422
+ },
423
+ },
424
+ render: () => (
425
+ <Fieldset legend="Dietary requirements">
39
426
  <FormField
40
- id="first-name"
41
- label="First Name"
42
- inputProps={{
43
- placeholder: 'Enter your first name',
44
- }}
427
+ id="diet-primary"
428
+ label="Primary dietary requirement"
429
+ inputProps={{ placeholder: 'e.g. Halal, Vegetarian, Vegan' }}
45
430
  />
46
431
  <FormField
47
- id="last-name"
48
- label="Last Name"
49
- inputProps={{
50
- placeholder: 'Enter your last name',
51
- }}
432
+ id="diet-allergies"
433
+ label="Allergies and intolerances"
434
+ fieldDescription="List all known allergens — this information is shared with the school kitchen"
435
+ inputProps={{ placeholder: 'e.g. Peanuts, Gluten, Dairy' }}
52
436
  />
53
- </div>
437
+ </Fieldset>
54
438
  ),
55
439
  },
56
- };
57
- // Disabled fieldset
58
- export const Disabled: Story = {
59
- args: {
60
- legend: 'Disabled Fieldset',
61
- disabled: true,
62
- children: (
63
- <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
64
- <FormField
65
- id="disabled-input"
66
- label="Disabled Input"
67
- inputProps={{
68
- placeholder: 'This input is disabled',
69
- disabled: true,
440
+ );
441
+
442
+ export const WithoutLegend: Story = withDescription(
443
+ 'The `legend` prop is optional. When omitted the fieldset still provides semantic grouping, but you **must** supply either `aria-label` or `aria-labelledby` to satisfy WCAG 1.3.1. This is useful when the group label already exists as a visible heading in the page.',
444
+ {
445
+ parameters: {
446
+ controls: { disable: true },
447
+ docs: {
448
+ source: {
449
+ code: `
450
+ import { Fieldset, CheckboxInput } from '@arbor-education/design-system.components';
451
+
452
+ export default function WithoutLegendFieldset() {
453
+ return (
454
+ // No legend prop — aria-labelledby points to the heading above
455
+ <div>
456
+ <h2 id="notif-heading">Notification preferences</h2>
457
+ <Fieldset aria-labelledby="notif-heading">
458
+ <CheckboxInput
459
+ id="notif-email"
460
+ name="notifications"
461
+ label="Email — weekly summary and urgent alerts"
462
+ />
463
+ <CheckboxInput
464
+ id="notif-sms"
465
+ name="notifications"
466
+ label="SMS — urgent alerts only"
467
+ />
468
+ <CheckboxInput
469
+ id="notif-app"
470
+ name="notifications"
471
+ label="In-app — all updates in the Arbor dashboard"
472
+ />
473
+ </Fieldset>
474
+ </div>
475
+ );
476
+ }
477
+ `.trim(),
478
+ },
479
+ },
480
+ },
481
+ render: () => (
482
+ <div>
483
+ <h2
484
+ id="notif-heading"
485
+ style={{
486
+ fontFamily: 'var(--type-body-font-family)',
487
+ fontWeight: 'var(--type-body-bold-weight)' as React.CSSProperties['fontWeight'],
488
+ color: 'var(--form-field-label-color-text)',
489
+ marginBottom: 'var(--form-field-spacing-vertical)',
490
+ marginTop: 0,
491
+ fontSize: '1rem',
70
492
  }}
493
+ >
494
+ Notification preferences
495
+ </h2>
496
+ <Fieldset aria-labelledby="notif-heading">
497
+ <CheckboxInput
498
+ id="notif-email"
499
+ name="notifications"
500
+ label="Email — weekly summary and urgent alerts"
501
+ onChange={() => {}}
502
+ />
503
+ <CheckboxInput
504
+ id="notif-sms"
505
+ name="notifications"
506
+ label="SMS — urgent alerts only"
507
+ onChange={() => {}}
508
+ />
509
+ <CheckboxInput
510
+ id="notif-app"
511
+ name="notifications"
512
+ label="In-app — all updates in the Arbor dashboard"
513
+ onChange={() => {}}
514
+ />
515
+ </Fieldset>
516
+ </div>
517
+ ),
518
+ },
519
+ );
520
+
521
+ export const WithAriaLabel: Story = withDescription(
522
+ 'Use `aria-label` when no visible heading exists to reference via `aria-labelledby` and design requirements prevent showing a `<legend>`. The label is invisible to sighted users but fully accessible to screen readers.',
523
+ {
524
+ parameters: {
525
+ controls: { disable: true },
526
+ docs: {
527
+ source: {
528
+ code: `
529
+ import { Fieldset, CheckboxInput } from '@arbor-education/design-system.components';
530
+
531
+ export default function AriaLabelFieldset() {
532
+ return (
533
+ <Fieldset aria-label="Trip consent options">
534
+ <CheckboxInput
535
+ id="trip-geography"
536
+ name="trip-consent"
537
+ label="Year 7 Geography field trip — 14 March"
538
+ />
539
+ <CheckboxInput
540
+ id="trip-science"
541
+ name="trip-consent"
542
+ label="Year 7 Science museum visit — 28 March"
543
+ />
544
+ <CheckboxInput
545
+ id="trip-drama"
546
+ name="trip-consent"
547
+ label="Year 7 Drama workshop — 4 April"
548
+ />
549
+ </Fieldset>
550
+ );
551
+ }
552
+ `.trim(),
553
+ },
554
+ },
555
+ },
556
+ render: () => (
557
+ <Fieldset aria-label="Trip consent options">
558
+ <CheckboxInput
559
+ id="trip-geography"
560
+ name="trip-consent"
561
+ label="Year 7 Geography field trip — 14 March"
562
+ onChange={() => {}}
563
+ />
564
+ <CheckboxInput
565
+ id="trip-science"
566
+ name="trip-consent"
567
+ label="Year 7 Science museum visit — 28 March"
568
+ onChange={() => {}}
71
569
  />
72
570
  <CheckboxInput
73
- id="disabled-checkbox"
74
- name="disabled"
75
- value="disabled"
76
- label="Disabled checkbox"
77
- disabled={true}
571
+ id="trip-drama"
572
+ name="trip-consent"
573
+ label="Year 7 Drama workshop — 4 April"
574
+ onChange={() => {}}
78
575
  />
576
+ </Fieldset>
577
+ ),
578
+ },
579
+ );
580
+
581
+ export const Disabled: Story = withDescription(
582
+ 'Setting `disabled` on the Fieldset is the correct semantic approach to disabling an entire group. The browser propagates the disabled state to **all descendant form controls** automatically — no need to pass `disabled` to each child individually.',
583
+ {
584
+ parameters: {
585
+ controls: { disable: true },
586
+ docs: {
587
+ source: {
588
+ code: `
589
+ import { Fieldset, RadioButtonInput } from '@arbor-education/design-system.components';
590
+
591
+ export default function DisabledFieldset() {
592
+ return (
593
+ // ONE disabled prop disables all three radio buttons:
594
+ <Fieldset legend="Notification preferences" disabled>
595
+ <RadioButtonInput
596
+ id="notif-all"
597
+ name="notif-freq"
598
+ value="all"
599
+ label="All notifications"
600
+ />
601
+ <RadioButtonInput
602
+ id="notif-urgent"
603
+ name="notif-freq"
604
+ value="urgent"
605
+ label="Urgent alerts only"
606
+ />
607
+ <RadioButtonInput
608
+ id="notif-none"
609
+ name="notif-freq"
610
+ value="none"
611
+ label="No notifications"
612
+ />
613
+ </Fieldset>
614
+ );
615
+ }
616
+ `.trim(),
617
+ },
618
+ },
619
+ },
620
+ render: () => (
621
+ <Fieldset legend="Notification preferences" disabled>
79
622
  <RadioButtonInput
80
- id="disabled-radio"
81
- name="disabled"
82
- value="disabled"
83
- label="Disabled radio"
84
- disabled={true}
623
+ id="notif-all"
624
+ name="notif-freq"
625
+ value="all"
626
+ label="All notifications"
85
627
  />
86
- </div>
628
+ <RadioButtonInput
629
+ id="notif-urgent"
630
+ name="notif-freq"
631
+ value="urgent"
632
+ label="Urgent alerts only"
633
+ />
634
+ <RadioButtonInput
635
+ id="notif-none"
636
+ name="notif-freq"
637
+ value="none"
638
+ label="No notifications"
639
+ />
640
+ </Fieldset>
87
641
  ),
88
642
  },
89
- };
643
+ );
644
+
645
+ export const DisabledWithCheckboxes: Story = withDescription(
646
+ 'The most visually compelling demonstration of the `disabled` prop — all checkboxes are greyed out and non-interactive with a single `disabled` on the fieldset. This is how Arbor locks consent forms during a pending approval workflow.',
647
+ {
648
+ parameters: {
649
+ controls: { disable: true },
650
+ docs: {
651
+ source: {
652
+ code: `
653
+ import { Fieldset, CheckboxInput } from '@arbor-education/design-system.components';
654
+
655
+ export default function DisabledCheckboxesFieldset() {
656
+ return (
657
+ <Fieldset legend="Consent and permissions" disabled>
658
+ <CheckboxInput
659
+ id="consent-trips-dis"
660
+ name="consent"
661
+ label="Consent for school trips"
662
+ checked
663
+ onChange={() => {}}
664
+ />
665
+ <CheckboxInput
666
+ id="consent-photos-dis"
667
+ name="consent"
668
+ label="Consent for photographs"
669
+ checked
670
+ onChange={() => {}}
671
+ />
672
+ <CheckboxInput
673
+ id="consent-data-dis"
674
+ name="consent"
675
+ label="Consent for data sharing with partner schools"
676
+ onChange={() => {}}
677
+ />
678
+ <CheckboxInput
679
+ id="consent-medical-dis"
680
+ name="consent"
681
+ label="Consent to share medical information with trip supervisors"
682
+ onChange={() => {}}
683
+ />
684
+ </Fieldset>
685
+ );
686
+ }
687
+ `.trim(),
688
+ },
689
+ },
690
+ },
691
+ render: () => (
692
+ <Fieldset legend="Consent and permissions" disabled>
693
+ <CheckboxInput
694
+ id="consent-trips-dis"
695
+ name="consent"
696
+ label="Consent for school trips"
697
+ checked
698
+ onChange={() => {}}
699
+ />
700
+ <CheckboxInput
701
+ id="consent-photos-dis"
702
+ name="consent"
703
+ label="Consent for photographs"
704
+ checked
705
+ onChange={() => {}}
706
+ />
707
+ <CheckboxInput
708
+ id="consent-data-dis"
709
+ name="consent"
710
+ label="Consent for data sharing with partner schools"
711
+ onChange={() => {}}
712
+ />
713
+ <CheckboxInput
714
+ id="consent-medical-dis"
715
+ name="consent"
716
+ label="Consent to share medical information with trip supervisors"
717
+ onChange={() => {}}
718
+ />
719
+ </Fieldset>
720
+ ),
721
+ },
722
+ );
723
+
724
+ export const DisabledWithRadioButtons: Story = withDescription(
725
+ 'Radio buttons inside a disabled fieldset are also non-interactive. Use this pattern when the selection has been locked — for example, after a parent has submitted a form that is now awaiting school staff approval.',
726
+ {
727
+ parameters: {
728
+ controls: { disable: true },
729
+ docs: {
730
+ source: {
731
+ code: `
732
+ import { Fieldset, RadioButtonInput } from '@arbor-education/design-system.components';
733
+
734
+ export default function DisabledRadioFieldset() {
735
+ return (
736
+ <Fieldset legend="Dietary requirements" disabled>
737
+ <RadioButtonInput
738
+ id="diet-halal-dis"
739
+ name="diet"
740
+ value="halal"
741
+ label="Halal"
742
+ defaultChecked
743
+ />
744
+ <RadioButtonInput
745
+ id="diet-vegetarian-dis"
746
+ name="diet"
747
+ value="vegetarian"
748
+ label="Vegetarian"
749
+ />
750
+ <RadioButtonInput
751
+ id="diet-vegan-dis"
752
+ name="diet"
753
+ value="vegan"
754
+ label="Vegan"
755
+ />
756
+ <RadioButtonInput
757
+ id="diet-none-dis"
758
+ name="diet"
759
+ value="none"
760
+ label="No specific requirement"
761
+ />
762
+ </Fieldset>
763
+ );
764
+ }
765
+ `.trim(),
766
+ },
767
+ },
768
+ },
769
+ render: () => (
770
+ <Fieldset legend="Dietary requirements" disabled>
771
+ <RadioButtonInput
772
+ id="diet-halal-dis"
773
+ name="diet"
774
+ value="halal"
775
+ label="Halal"
776
+ defaultChecked
777
+ />
778
+ <RadioButtonInput
779
+ id="diet-vegetarian-dis"
780
+ name="diet"
781
+ value="vegetarian"
782
+ label="Vegetarian"
783
+ />
784
+ <RadioButtonInput
785
+ id="diet-vegan-dis"
786
+ name="diet"
787
+ value="vegan"
788
+ label="Vegan"
789
+ />
790
+ <RadioButtonInput
791
+ id="diet-none-dis"
792
+ name="diet"
793
+ value="none"
794
+ label="No specific requirement"
795
+ />
796
+ </Fieldset>
797
+ ),
798
+ },
799
+ );