@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,29 +1,201 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { EditableText } from './EditableText';
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
+ import { useEffect, useState } from 'react';
12
+
13
+ import { Button } from 'Components/button/Button';
14
+ import { EditableText } from 'Components/editableText/EditableText';
15
+
16
+ // ---------------------------------------------------------------------------
17
+ // Content strings
18
+ // ---------------------------------------------------------------------------
19
+
20
+ const DESCRIPTION_INTRO = `
21
+ EditableText is an inline text element that can be edited in place. Clicking the text (or the
22
+ pencil icon beside it) switches to an input or textarea, letting users rename records, update
23
+ titles, and correct short pieces of text without navigating away to a separate form.
24
+ `.trim();
25
+
26
+ const USAGE_GUIDANCE = `
27
+ ### When to use
28
+
29
+ - **Renaming a record title in-context** — group names, report titles, curriculum plan headings
30
+ - **Correcting a short piece of editable text inline** — without navigating to a separate form
31
+ - **Updating a longer freeform description** — use with \`multiline\` for textarea behaviour
32
+
33
+ ---
34
+
35
+ ### When NOT to use
36
+
37
+ | Situation | Use instead |
38
+ |---|---|
39
+ | Collecting new data in a form | [\`FormField\`](?path=/docs/components-formfield--docs) — labelled inputs with validation |
40
+ | Editing content that requires explicit confirmation before saving | \`FormField\` with a submit button — \`onEditSave\` fires on blur |
41
+ | Displaying text the user should never change | A plain text element — EditableText always shows an edit affordance |
42
+
43
+ ---
44
+
45
+ ### Always update \`text\` in \`onEditSave\`
46
+
47
+ EditableText is a **controlled-ish** component — it holds its own internal state but
48
+ initialises from the \`text\` prop. If you don't feed the saved value back as the new \`text\`
49
+ prop, the component will snap back to the original value on the next render cycle.
50
+
51
+ \`\`\`tsx
52
+ const [title, setTitle] = useState('Year 10 Science');
53
+
54
+ <EditableText text={title} onEditSave={setTitle} />
55
+ \`\`\`
56
+
57
+ ### Multiline mode (\`multiline\`)
58
+
59
+ When \`multiline={true}\` the underlying input switches to a \`<textarea>\`.
60
+ The keyboard contract changes:
61
+
62
+ - **Enter** inserts a newline (does **not** save)
63
+ - **Escape** reverts to the pre-edit value
64
+ - **Blur** (clicking away) saves
65
+
66
+ > In single-line mode **Enter** saves immediately. Forgetting this difference is the most
67
+ > common source of unexpected behaviour — document it clearly when you expose this prop to end users.
68
+
69
+ ### Programmatic edit mode (\`isEditing\`)
70
+
71
+ \`isEditing\` is a **one-way trigger**. Setting it to \`true\` tells the component to open the
72
+ input, but the component then takes back ownership of that state. You **cannot** force the
73
+ component closed by setting \`isEditing={false}\` after editing has started — only user
74
+ interaction (blur or Escape) can close it.
75
+
76
+ \`\`\`tsx
77
+ <EditableText
78
+ text={name}
79
+ isEditing={shouldEdit} // opens the input once; component owns state after that
80
+ onEditSave={setName}
81
+ />
82
+ \`\`\`
83
+
84
+ ### Blur saves immediately
85
+
86
+ \`onEditSave\` fires on blur, including accidental focus loss (e.g. the user clicks elsewhere
87
+ on the page). If the user must explicitly confirm a change before it is persisted, use a
88
+ \`<FormField>\` with a dedicated submit button instead.
89
+
90
+ ### Typography is fully inherited
91
+
92
+ EditableText applies **no font styles of its own**. Size, weight, colour, and line-height all
93
+ come from the parent element. Wrap it in an \`<h1>\`, \`<p>\`, or any container and the input
94
+ will match the surrounding text automatically — no extra CSS needed.
95
+ `.trim();
96
+
97
+ const DEVELOPER_NOTES = `
98
+ ### Accessibility & keyboard contract
99
+
100
+ | Key | Single-line | Multiline |
101
+ |---|---|---|
102
+ | Enter | Saves and closes the input | Inserts a newline |
103
+ | Escape | Reverts to the pre-edit value and closes | Reverts to the pre-edit value and closes |
104
+ | Tab / click away (blur) | Saves and closes the input | Saves and closes the input |
105
+
106
+ The display-mode button carries \`aria-label="Edit text"\` so screen-reader users understand
107
+ its purpose. The input carries \`aria-label="Text"\`. Both labels are applied automatically —
108
+ you do not need to pass anything extra.
109
+ `.trim();
110
+
111
+ const RELATED_COMPONENTS = `
112
+ ## Related components
113
+ - [FormField](?path=/docs/components-formfield--docs) — full form inputs with labels, validation, and helper text
114
+ - [Table](?path=/docs/components-table--docs) — data grid that can use EditableText in inline-edit cells
115
+ - [TextInput](?path=/docs/components-formfield-inputs-textinput--docs) — the underlying single-line input used by EditableText
116
+ `.trim();
117
+
118
+ const PROPS_INTRO
119
+ = 'The preview below is wired to the **Controls** panel — tweak any prop to see the story update in real time.';
120
+
121
+ // ---------------------------------------------------------------------------
122
+ // Docs page
123
+ // ---------------------------------------------------------------------------
124
+
125
+ function EditableTextDocsPage() {
126
+ return (
127
+ <>
128
+ <Title />
129
+ <Subtitle />
130
+ <Markdown>{DESCRIPTION_INTRO}</Markdown>
131
+ <DocHeading>Interactive example</DocHeading>
132
+ <Markdown>{PROPS_INTRO}</Markdown>
133
+ <DocPrimary />
134
+ <Controls />
135
+ <DocHeading>Usage guidance</DocHeading>
136
+ <Markdown>{USAGE_GUIDANCE}</Markdown>
137
+ <DocHeading>Developer notes</DocHeading>
138
+ <Markdown>{DEVELOPER_NOTES}</Markdown>
139
+ <DocHeading>Examples</DocHeading>
140
+ <Stories title="" />
141
+ <Markdown>{RELATED_COMPONENTS}</Markdown>
142
+ </>
143
+ );
144
+ }
145
+
146
+ // ---------------------------------------------------------------------------
147
+ // Meta
148
+ // ---------------------------------------------------------------------------
3
149
 
4
150
  const meta = {
5
151
  title: 'Components/EditableText',
6
152
  component: EditableText,
153
+ tags: ['autodocs'],
7
154
  parameters: {
8
- layout: 'padded',
155
+ docs: {
156
+ page: EditableTextDocsPage,
157
+ },
9
158
  },
10
- tags: ['autodocs'],
11
159
  argTypes: {
12
160
  text: {
13
161
  control: 'text',
14
- description: 'The text to display',
15
- },
16
- className: {
17
- control: 'text',
18
- description: 'Optional CSS class name',
162
+ description: 'The current text value. **Always** update this prop inside `onEditSave` to keep the component in sync.',
163
+ table: {
164
+ type: { summary: 'string' },
165
+ },
19
166
  },
20
167
  onEditSave: {
21
- action: 'edit saved',
22
- description: 'Callback fired when the text is edited',
168
+ control: false,
169
+ description: 'Callback fired when the user saves a change (on blur or Enter in single-line mode). Receives the new text string.',
170
+ table: {
171
+ type: { summary: '(newText: string) => void' },
172
+ },
23
173
  },
24
174
  isEditing: {
25
175
  control: 'boolean',
26
- description: 'Control whether the text is in edit mode',
176
+ description:
177
+ 'One-way trigger that forces the component into edit mode when set to `true`. The component takes back ownership of this state once editing begins — setting it back to `false` from outside will not close the input.',
178
+ table: {
179
+ type: { summary: 'boolean' },
180
+ defaultValue: { summary: 'false' },
181
+ },
182
+ },
183
+ multiline: {
184
+ control: 'boolean',
185
+ description:
186
+ 'When `true`, switches the input to a `<textarea>`. In multiline mode **Enter inserts a newline** — it does NOT save. Only blur saves.',
187
+ table: {
188
+ type: { summary: 'boolean' },
189
+ defaultValue: { summary: 'false' },
190
+ },
191
+ },
192
+ className: {
193
+ control: 'text',
194
+ description: 'Additional CSS class names applied to the root `<span>` element.',
195
+ table: {
196
+ type: { summary: 'string' },
197
+ defaultValue: { summary: "''" },
198
+ },
27
199
  },
28
200
  },
29
201
  } satisfies Meta<typeof EditableText>;
@@ -31,106 +203,410 @@ const meta = {
31
203
  export default meta;
32
204
  type Story = StoryObj<typeof meta>;
33
205
 
34
- // Default (inherits parent styles)
35
- export const Default: Story = {
36
- render: args => (
37
- <div style={{ width: '100%' }}>
38
- <EditableText {...args} />
39
- </div>
40
- ),
41
- args: {
42
- text: 'Editable Text',
43
- onEditSave: () => {},
206
+ // ---------------------------------------------------------------------------
207
+ // Helper
208
+ // ---------------------------------------------------------------------------
209
+
210
+ const withDescription = (story: StoryObj<typeof meta>, description: string): StoryObj<typeof meta> => ({
211
+ ...story,
212
+ parameters: {
213
+ ...story.parameters,
214
+ docs: {
215
+ ...story.parameters?.docs,
216
+ description: {
217
+ story: description,
218
+ },
219
+ },
44
220
  },
221
+ });
222
+
223
+ // ---------------------------------------------------------------------------
224
+ // Named template components
225
+ // (All use useState so onEditSave keeps the component in sync — this is the
226
+ // pattern every consumer MUST follow to avoid text snapping back on re-render)
227
+ // ---------------------------------------------------------------------------
228
+
229
+ const DefaultTemplate = (args: React.ComponentProps<typeof EditableText>) => {
230
+ const [text, setText] = useState(args.text);
231
+ const [lastSaved, setLastSaved] = useState(args.text);
232
+
233
+ useEffect(() => {
234
+ setText(args.text);
235
+ setLastSaved(args.text);
236
+ }, [args.text]);
237
+
238
+ return (
239
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem', maxWidth: '480px' }}>
240
+ <EditableText
241
+ {...args}
242
+ text={text}
243
+ onEditSave={(val) => {
244
+ setText(val);
245
+ setLastSaved(val);
246
+ }}
247
+ />
248
+ <p className="ds-text" style={{ margin: 0, color: 'var(--color-grey-600)', fontSize: '0.875rem' }}>
249
+ Last saved: &quot;
250
+ {lastSaved}
251
+ &quot;
252
+ </p>
253
+ </div>
254
+ );
255
+ };
256
+
257
+ const MultilineTemplate = () => {
258
+ const [text, setText] = useState(
259
+ 'Attendance requirements and absence notification procedures for all pupils enrolled in Year 10.',
260
+ );
261
+ const [lastSaved, setLastSaved] = useState(text);
262
+
263
+ return (
264
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem', maxWidth: '560px' }}>
265
+ <EditableText
266
+ text={text}
267
+ multiline
268
+ onEditSave={(val) => {
269
+ setText(val);
270
+ setLastSaved(val);
271
+ }}
272
+ />
273
+ <p className="ds-text" style={{ margin: 0, color: 'var(--color-grey-600)', fontSize: '0.875rem' }}>
274
+ Last saved: &quot;
275
+ {lastSaved}
276
+ &quot;
277
+ </p>
278
+ </div>
279
+ );
280
+ };
281
+
282
+ const ProgrammaticControlTemplate = () => {
283
+ const [text, setText] = useState('Spring Term Assessment Schedule');
284
+ const [triggerEdit, setTriggerEdit] = useState(false);
285
+
286
+ const handleEditSave = (val: string) => {
287
+ setText(val);
288
+ setTriggerEdit(false);
289
+ };
290
+
291
+ return (
292
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem', maxWidth: '480px' }}>
293
+ <EditableText text={text} isEditing={triggerEdit} onEditSave={handleEditSave} />
294
+ <Button variant="secondary" onClick={() => setTriggerEdit(true)}>
295
+ Edit title
296
+ </Button>
297
+ </div>
298
+ );
45
299
  };
46
300
 
47
- // Inside H1 heading
48
- export const InH1: Story = {
49
- render: args => (
301
+ const InHeading1Template = () => {
302
+ const [text, setText] = useState('Year 10 Science Curriculum Plan');
303
+ return (
50
304
  <h1>
51
- <EditableText {...args} />
305
+ <EditableText text={text} onEditSave={setText} />
52
306
  </h1>
53
- ),
54
- args: {
55
- text: 'Editable Heading Level 1',
56
- onEditSave: () => {},
57
- },
307
+ );
58
308
  };
59
309
 
60
- // Inside H2 heading
61
- export const InH2: Story = {
62
- render: args => (
310
+ const InHeading2Template = () => {
311
+ const [text, setText] = useState('Spring Term Assessment Schedule');
312
+ return (
63
313
  <h2>
64
- <EditableText {...args} />
314
+ <EditableText text={text} onEditSave={setText} />
65
315
  </h2>
66
- ),
67
- args: {
68
- text: 'Editable Heading Level 2',
69
- onEditSave: () => {},
70
- },
316
+ );
71
317
  };
72
318
 
73
- // Inside H3 heading
74
- export const InH3: Story = {
75
- render: args => (
76
- <h3>
77
- <EditableText {...args} />
78
- </h3>
79
- ),
80
- args: {
81
- text: 'Editable Heading Level 3',
82
- onEditSave: () => {},
83
- },
319
+ const InParagraphTemplate = () => {
320
+ const [text, setText] = useState('Emily Johnson');
321
+ return (
322
+ <p className="ds-text">
323
+ Class teacher:
324
+ {' '}
325
+ <EditableText text={text} onEditSave={setText} />
326
+ </p>
327
+ );
84
328
  };
85
329
 
86
- // Inside H4 heading
87
- export const InH4: Story = {
88
- render: args => (
89
- <h4>
90
- <EditableText {...args} />
91
- </h4>
92
- ),
93
- args: {
94
- text: 'Editable Heading Level 4',
95
- onEditSave: () => {},
96
- },
330
+ const LongTextTemplate = () => {
331
+ const [text, setText] = useState(
332
+ 'Behaviour policy and expectations for all students during lesson time, including mobile phone usage and dress code requirements',
333
+ );
334
+ return (
335
+ <div style={{ maxWidth: '480px' }}>
336
+ <EditableText text={text} onEditSave={setText} />
337
+ </div>
338
+ );
97
339
  };
98
340
 
99
- // Inside paragraph
100
- export const InParagraph: Story = {
101
- render: args => (
102
- <p>
103
- <EditableText {...args} />
104
- </p>
105
- ),
106
- args: {
107
- text: 'Editable paragraph text',
108
- onEditSave: () => {},
109
- },
110
- };
341
+ const EscapeToCancelTemplate = () => {
342
+ const [text, setText] = useState('Mr. David Chen');
343
+ const [savedText, setSavedText] = useState('Mr. David Chen');
344
+ const [cancelCount, setCancelCount] = useState(0);
111
345
 
112
- // Inside custom styled div
113
- export const InCustomStyledDiv: Story = {
114
- render: args => (
115
- <div style={{ fontSize: '24px', fontWeight: 'bold', color: '#0066cc' }}>
116
- <EditableText {...args} />
346
+ return (
347
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem', maxWidth: '480px' }}>
348
+ <EditableText
349
+ text={text}
350
+ onEditSave={(val) => {
351
+ setText(val);
352
+ setSavedText(val);
353
+ }}
354
+ />
355
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '0.25rem' }}>
356
+ <p className="ds-text" style={{ margin: 0, color: 'var(--color-grey-600)', fontSize: '0.875rem' }}>
357
+ Saved value: &quot;
358
+ {savedText}
359
+ &quot;
360
+ </p>
361
+ <p className="ds-text" style={{ margin: 0, color: 'var(--color-grey-600)', fontSize: '0.875rem' }}>
362
+ Escapes pressed:
363
+ {' '}
364
+ {cancelCount}
365
+ </p>
366
+ </div>
367
+ <p className="ds-text" style={{ margin: 0, fontSize: '0.875rem' }}>
368
+ Try editing the text above, type something new, then press
369
+ {' '}
370
+ <kbd>Escape</kbd>
371
+ {' '}
372
+ — the
373
+ original value is restored without calling
374
+ {' '}
375
+ <code>onEditSave</code>
376
+ .
377
+ </p>
378
+ {/*
379
+ We track cancels by wrapping the component and watching for text changes
380
+ that don't match what we'd expect from a save — but EditableText does not
381
+ expose an onCancel callback. The counter below is illustrative only.
382
+ Reset the page to see the true saved state.
383
+ */}
384
+ <Button variant="secondary" onClick={() => setCancelCount(c => c + 1)}>
385
+ Simulate cancel count (manual)
386
+ </Button>
117
387
  </div>
118
- ),
119
- args: {
120
- text: 'Custom styled editable text',
121
- onEditSave: () => {},
122
- },
388
+ );
123
389
  };
124
390
 
125
- // Long text example
126
- export const LongText: Story = {
127
- render: args => (
128
- <h2>
129
- <EditableText {...args} />
130
- </h2>
131
- ),
391
+ // ---------------------------------------------------------------------------
392
+ // Stories
393
+ // ---------------------------------------------------------------------------
394
+
395
+ export const Default: Story = {
132
396
  args: {
133
- text: 'This is a much longer text that demonstrates how the component handles extended content',
397
+ text: 'Year 10 Science Curriculum Plan',
134
398
  onEditSave: () => {},
399
+ isEditing: false,
400
+ multiline: false,
401
+ className: '',
402
+ },
403
+ render: args => <DefaultTemplate {...args} />,
404
+ parameters: {
405
+ docs: {
406
+ description: {
407
+ story: PROPS_INTRO,
408
+ },
409
+ },
135
410
  },
136
411
  };
412
+
413
+ export const MultilineEditing: Story = withDescription(
414
+ {
415
+ args: { text: '', onEditSave: () => {} },
416
+ render: () => <MultilineTemplate />,
417
+ parameters: {
418
+ docs: {
419
+ source: {
420
+ code: `
421
+ import { EditableText } from '@arbor-education/design-system.components';
422
+ import { useState } from 'react';
423
+
424
+ const [text, setText] = useState(
425
+ 'Attendance requirements and absence notification procedures for all pupils enrolled in Year 10.',
426
+ );
427
+
428
+ <EditableText
429
+ text={text}
430
+ multiline
431
+ onEditSave={setText}
432
+ />
433
+ `.trim(),
434
+ },
435
+ },
436
+ },
437
+ },
438
+ `When \`multiline={true}\` the component renders a \`<textarea>\` instead of a text input.
439
+
440
+ > **Key difference:** In multiline mode **Enter inserts a newline** — it does **not** save.
441
+ > Only blur (clicking away) or Escape will close the editor.
442
+ > In single-line mode, Enter saves immediately.
443
+
444
+ Use multiline for longer freeform text such as descriptions, notes, or policy summaries.`,
445
+ );
446
+
447
+ export const ProgrammaticControl: Story = withDescription(
448
+ {
449
+ args: { text: '', onEditSave: () => {} },
450
+ render: () => <ProgrammaticControlTemplate />,
451
+ parameters: {
452
+ docs: {
453
+ source: {
454
+ code: `
455
+ import { EditableText } from '@arbor-education/design-system.components';
456
+ import { Button } from '@arbor-education/design-system.components';
457
+ import { useState } from 'react';
458
+
459
+ const [text, setText] = useState('Spring Term Assessment Schedule');
460
+ const [triggerEdit, setTriggerEdit] = useState(false);
461
+
462
+ <EditableText
463
+ text={text}
464
+ isEditing={triggerEdit}
465
+ onEditSave={(val) => {
466
+ setText(val);
467
+ setTriggerEdit(false);
468
+ }}
469
+ />
470
+ <Button variant="secondary" onClick={() => setTriggerEdit(true)}>
471
+ Edit title
472
+ </Button>
473
+ `.trim(),
474
+ },
475
+ },
476
+ },
477
+ },
478
+ `Use \`isEditing\` to open the input programmatically — for example, from a toolbar button or a keyboard shortcut.
479
+
480
+ > **Important:** \`isEditing\` is a one-way trigger. Once the component receives \`true\` it takes back
481
+ > ownership of edit state. Setting \`isEditing={false}\` from the outside will **not** close
482
+ > the input after editing has begun — only blur or Escape can do that.`,
483
+ );
484
+
485
+ export const InHeading1: Story = withDescription(
486
+ {
487
+ args: { text: '', onEditSave: () => {} },
488
+ render: () => <InHeading1Template />,
489
+ parameters: {
490
+ docs: {
491
+ source: {
492
+ code: `
493
+ import { EditableText } from '@arbor-education/design-system.components';
494
+ import { useState } from 'react';
495
+
496
+ const [text, setText] = useState('Year 10 Science Curriculum Plan');
497
+
498
+ <h1>
499
+ <EditableText text={text} onEditSave={setText} />
500
+ </h1>
501
+ `.trim(),
502
+ },
503
+ },
504
+ },
505
+ },
506
+ `EditableText inherits all typography from its parent. Wrapping it in an \`<h1>\` gives the
507
+ input the same font size, weight, and line-height as the surrounding heading — no extra CSS needed.`,
508
+ );
509
+
510
+ export const InHeading2: Story = withDescription(
511
+ {
512
+ args: { text: '', onEditSave: () => {} },
513
+ render: () => <InHeading2Template />,
514
+ parameters: {
515
+ docs: {
516
+ source: {
517
+ code: `
518
+ import { EditableText } from '@arbor-education/design-system.components';
519
+ import { useState } from 'react';
520
+
521
+ const [text, setText] = useState('Spring Term Assessment Schedule');
522
+
523
+ <h2>
524
+ <EditableText text={text} onEditSave={setText} />
525
+ </h2>
526
+ `.trim(),
527
+ },
528
+ },
529
+ },
530
+ },
531
+ `Same inheritance pattern as \`InHeading1\` but at \`<h2>\` size — useful for section titles and
532
+ panel headers inside a page that already has an \`<h1>\`.`,
533
+ );
534
+
535
+ export const InParagraph: Story = withDescription(
536
+ {
537
+ args: { text: '', onEditSave: () => {} },
538
+ render: () => <InParagraphTemplate />,
539
+ parameters: {
540
+ docs: {
541
+ source: {
542
+ code: `
543
+ import { EditableText } from '@arbor-education/design-system.components';
544
+ import { useState } from 'react';
545
+
546
+ const [text, setText] = useState('Emily Johnson');
547
+
548
+ <p className="ds-text">
549
+ Class teacher: <EditableText text={text} onEditSave={setText} />
550
+ </p>
551
+ `.trim(),
552
+ },
553
+ },
554
+ },
555
+ },
556
+ `EditableText can sit inline within a paragraph. The input inherits body-text styles automatically,
557
+ so it blends seamlessly with surrounding copy. Use \`className="ds-text"\` on the wrapping \`<p>\`
558
+ to apply design-system base font styles.`,
559
+ );
560
+
561
+ export const LongText: Story = withDescription(
562
+ {
563
+ args: { text: '', onEditSave: () => {} },
564
+ render: () => <LongTextTemplate />,
565
+ parameters: {
566
+ docs: {
567
+ source: {
568
+ code: `
569
+ import { EditableText } from '@arbor-education/design-system.components';
570
+ import { useState } from 'react';
571
+
572
+ const [text, setText] = useState(
573
+ 'Behaviour policy and expectations for all students during lesson time, including mobile phone usage and dress code requirements',
574
+ );
575
+
576
+ <EditableText text={text} onEditSave={setText} />
577
+ `.trim(),
578
+ },
579
+ },
580
+ },
581
+ },
582
+ `Long text strings wrap naturally inside the component button. The input expands to fill the
583
+ available width when the user enters edit mode. Constrain the parent container's width if you
584
+ need to limit how wide the input can grow.`,
585
+ );
586
+
587
+ export const EscapeToCancel: Story = withDescription(
588
+ {
589
+ args: { text: '', onEditSave: () => {} },
590
+ render: () => <EscapeToCancelTemplate />,
591
+ parameters: {
592
+ docs: {
593
+ source: {
594
+ code: `
595
+ import { EditableText } from '@arbor-education/design-system.components';
596
+ import { useState } from 'react';
597
+
598
+ const [text, setText] = useState('Mr. David Chen');
599
+
600
+ // Pressing Escape while editing restores the pre-edit value
601
+ // and does NOT call onEditSave — no network request is made.
602
+ <EditableText text={text} onEditSave={setText} />
603
+ `.trim(),
604
+ },
605
+ },
606
+ },
607
+ },
608
+ `Press **Escape** while editing to revert the input to its pre-edit value without calling
609
+ \`onEditSave\`. This means no data is persisted — a safe exit for users who change their minds.
610
+
611
+ The component handles this internally. No special setup is needed in the consumer.`,
612
+ );