@arbor-education/design-system.components 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/bin/createComponent.sh +2 -2
  3. package/dist/components/avatar/Avatar.d.ts +1 -1
  4. package/dist/components/avatar/Avatar.d.ts.map +1 -1
  5. package/dist/components/avatar/Avatar.js +1 -1
  6. package/dist/components/avatar/Avatar.js.map +1 -1
  7. package/dist/components/avatar/Avatar.stories.d.ts.map +1 -1
  8. package/dist/components/avatar/Avatar.stories.js +7 -0
  9. package/dist/components/avatar/Avatar.stories.js.map +1 -1
  10. package/dist/components/badge/Badge.d.ts +12 -0
  11. package/dist/components/badge/Badge.d.ts.map +1 -0
  12. package/dist/components/badge/Badge.js +6 -0
  13. package/dist/components/badge/Badge.js.map +1 -0
  14. package/dist/components/badge/Badge.stories.d.ts +10 -0
  15. package/dist/components/badge/Badge.stories.d.ts.map +1 -0
  16. package/dist/components/badge/Badge.stories.js +51 -0
  17. package/dist/components/badge/Badge.stories.js.map +1 -0
  18. package/dist/components/badge/Badge.test.d.ts +2 -0
  19. package/dist/components/badge/Badge.test.d.ts.map +1 -0
  20. package/dist/components/badge/Badge.test.js +23 -0
  21. package/dist/components/badge/Badge.test.js.map +1 -0
  22. package/dist/components/card/Card.js +1 -1
  23. package/dist/components/card/Card.js.map +1 -1
  24. package/dist/components/combobox/Combobox.d.ts +16 -0
  25. package/dist/components/combobox/Combobox.d.ts.map +1 -0
  26. package/dist/components/combobox/Combobox.js +195 -0
  27. package/dist/components/combobox/Combobox.js.map +1 -0
  28. package/dist/components/combobox/Combobox.stories.d.ts +24 -0
  29. package/dist/components/combobox/Combobox.stories.d.ts.map +1 -0
  30. package/dist/components/combobox/Combobox.stories.js +246 -0
  31. package/dist/components/combobox/Combobox.stories.js.map +1 -0
  32. package/dist/components/combobox/Combobox.test.d.ts +2 -0
  33. package/dist/components/combobox/Combobox.test.d.ts.map +1 -0
  34. package/dist/components/combobox/Combobox.test.js +798 -0
  35. package/dist/components/combobox/Combobox.test.js.map +1 -0
  36. package/dist/components/combobox/ComboboxButtonTrigger.d.ts +28 -0
  37. package/dist/components/combobox/ComboboxButtonTrigger.d.ts.map +1 -0
  38. package/dist/components/combobox/ComboboxButtonTrigger.js +64 -0
  39. package/dist/components/combobox/ComboboxButtonTrigger.js.map +1 -0
  40. package/dist/components/combobox/ComboboxListbox.d.ts +44 -0
  41. package/dist/components/combobox/ComboboxListbox.d.ts.map +1 -0
  42. package/dist/components/combobox/ComboboxListbox.js +37 -0
  43. package/dist/components/combobox/ComboboxListbox.js.map +1 -0
  44. package/dist/components/combobox/ComboboxOptionRow.d.ts +23 -0
  45. package/dist/components/combobox/ComboboxOptionRow.d.ts.map +1 -0
  46. package/dist/components/combobox/ComboboxOptionRow.js +27 -0
  47. package/dist/components/combobox/ComboboxOptionRow.js.map +1 -0
  48. package/dist/components/combobox/ComboboxTrigger.d.ts +35 -0
  49. package/dist/components/combobox/ComboboxTrigger.d.ts.map +1 -0
  50. package/dist/components/combobox/ComboboxTrigger.js +15 -0
  51. package/dist/components/combobox/ComboboxTrigger.js.map +1 -0
  52. package/dist/components/combobox/buildListboxDisplayOptions.d.ts +3 -0
  53. package/dist/components/combobox/buildListboxDisplayOptions.d.ts.map +1 -0
  54. package/dist/components/combobox/buildListboxDisplayOptions.js +13 -0
  55. package/dist/components/combobox/buildListboxDisplayOptions.js.map +1 -0
  56. package/dist/components/combobox/buildListboxDisplayOptions.test.d.ts +2 -0
  57. package/dist/components/combobox/buildListboxDisplayOptions.test.d.ts.map +1 -0
  58. package/dist/components/combobox/buildListboxDisplayOptions.test.js +22 -0
  59. package/dist/components/combobox/buildListboxDisplayOptions.test.js.map +1 -0
  60. package/dist/components/combobox/comboboxKeyboardTypes.d.ts +41 -0
  61. package/dist/components/combobox/comboboxKeyboardTypes.d.ts.map +1 -0
  62. package/dist/components/combobox/comboboxKeyboardTypes.js +2 -0
  63. package/dist/components/combobox/comboboxKeyboardTypes.js.map +1 -0
  64. package/dist/components/combobox/highlightLabel.d.ts +10 -0
  65. package/dist/components/combobox/highlightLabel.d.ts.map +1 -0
  66. package/dist/components/combobox/highlightLabel.js +18 -0
  67. package/dist/components/combobox/highlightLabel.js.map +1 -0
  68. package/dist/components/combobox/normaliseComboboxQuery.d.ts +2 -0
  69. package/dist/components/combobox/normaliseComboboxQuery.d.ts.map +1 -0
  70. package/dist/components/combobox/normaliseComboboxQuery.js +2 -0
  71. package/dist/components/combobox/normaliseComboboxQuery.js.map +1 -0
  72. package/dist/components/combobox/types.d.ts +46 -0
  73. package/dist/components/combobox/types.d.ts.map +1 -0
  74. package/dist/components/combobox/types.js +2 -0
  75. package/dist/components/combobox/types.js.map +1 -0
  76. package/dist/components/combobox/useChipSelection.d.ts +11 -0
  77. package/dist/components/combobox/useChipSelection.d.ts.map +1 -0
  78. package/dist/components/combobox/useChipSelection.js +35 -0
  79. package/dist/components/combobox/useChipSelection.js.map +1 -0
  80. package/dist/components/combobox/useComboboxChipKeyboard.d.ts +3 -0
  81. package/dist/components/combobox/useComboboxChipKeyboard.d.ts.map +1 -0
  82. package/dist/components/combobox/useComboboxChipKeyboard.js +103 -0
  83. package/dist/components/combobox/useComboboxChipKeyboard.js.map +1 -0
  84. package/dist/components/combobox/useComboboxChipKeyboard.test.d.ts +2 -0
  85. package/dist/components/combobox/useComboboxChipKeyboard.test.d.ts.map +1 -0
  86. package/dist/components/combobox/useComboboxChipKeyboard.test.js +116 -0
  87. package/dist/components/combobox/useComboboxChipKeyboard.test.js.map +1 -0
  88. package/dist/components/combobox/useComboboxKeyboard.d.ts +4 -0
  89. package/dist/components/combobox/useComboboxKeyboard.d.ts.map +1 -0
  90. package/dist/components/combobox/useComboboxKeyboard.js +68 -0
  91. package/dist/components/combobox/useComboboxKeyboard.js.map +1 -0
  92. package/dist/components/combobox/useComboboxListboxDom.d.ts +11 -0
  93. package/dist/components/combobox/useComboboxListboxDom.d.ts.map +1 -0
  94. package/dist/components/combobox/useComboboxListboxDom.js +15 -0
  95. package/dist/components/combobox/useComboboxListboxDom.js.map +1 -0
  96. package/dist/components/combobox/useComboboxListboxKeyboard.d.ts +3 -0
  97. package/dist/components/combobox/useComboboxListboxKeyboard.d.ts.map +1 -0
  98. package/dist/components/combobox/useComboboxListboxKeyboard.js +143 -0
  99. package/dist/components/combobox/useComboboxListboxKeyboard.js.map +1 -0
  100. package/dist/components/combobox/useComboboxListboxKeyboard.test.d.ts +2 -0
  101. package/dist/components/combobox/useComboboxListboxKeyboard.test.d.ts.map +1 -0
  102. package/dist/components/combobox/useComboboxListboxKeyboard.test.js +152 -0
  103. package/dist/components/combobox/useComboboxListboxKeyboard.test.js.map +1 -0
  104. package/dist/components/combobox/useComboboxPopoverBehavior.d.ts +38 -0
  105. package/dist/components/combobox/useComboboxPopoverBehavior.d.ts.map +1 -0
  106. package/dist/components/combobox/useComboboxPopoverBehavior.js +104 -0
  107. package/dist/components/combobox/useComboboxPopoverBehavior.js.map +1 -0
  108. package/dist/components/combobox/useComboboxState.d.ts +27 -0
  109. package/dist/components/combobox/useComboboxState.d.ts.map +1 -0
  110. package/dist/components/combobox/useComboboxState.js +122 -0
  111. package/dist/components/combobox/useComboboxState.js.map +1 -0
  112. package/dist/components/combobox/useElementWidth.d.ts +2 -0
  113. package/dist/components/combobox/useElementWidth.d.ts.map +1 -0
  114. package/dist/components/combobox/useElementWidth.js +31 -0
  115. package/dist/components/combobox/useElementWidth.js.map +1 -0
  116. package/dist/components/combobox/useVisibleChips.d.ts +21 -0
  117. package/dist/components/combobox/useVisibleChips.d.ts.map +1 -0
  118. package/dist/components/combobox/useVisibleChips.js +59 -0
  119. package/dist/components/combobox/useVisibleChips.js.map +1 -0
  120. package/dist/components/combobox/useVisibleChips.test.d.ts +2 -0
  121. package/dist/components/combobox/useVisibleChips.test.d.ts.map +1 -0
  122. package/dist/components/combobox/useVisibleChips.test.js +81 -0
  123. package/dist/components/combobox/useVisibleChips.test.js.map +1 -0
  124. package/dist/components/dot/Dot.d.ts +8 -0
  125. package/dist/components/dot/Dot.d.ts.map +1 -0
  126. package/dist/components/dot/Dot.js +6 -0
  127. package/dist/components/dot/Dot.js.map +1 -0
  128. package/dist/components/dot/Dot.stories.d.ts +15 -0
  129. package/dist/components/dot/Dot.stories.d.ts.map +1 -0
  130. package/dist/components/dot/Dot.stories.js +25 -0
  131. package/dist/components/dot/Dot.stories.js.map +1 -0
  132. package/dist/components/dot/Dot.test.d.ts +2 -0
  133. package/dist/components/dot/Dot.test.d.ts.map +1 -0
  134. package/dist/components/dot/Dot.test.js +19 -0
  135. package/dist/components/dot/Dot.test.js.map +1 -0
  136. package/dist/components/formField/FormField.d.ts +8 -4
  137. package/dist/components/formField/FormField.d.ts.map +1 -1
  138. package/dist/components/formField/FormField.js +7 -6
  139. package/dist/components/formField/FormField.js.map +1 -1
  140. package/dist/components/formField/FormField.stories.d.ts +1 -0
  141. package/dist/components/formField/FormField.stories.d.ts.map +1 -1
  142. package/dist/components/formField/FormField.stories.js +13 -1
  143. package/dist/components/formField/FormField.stories.js.map +1 -1
  144. package/dist/components/formField/FormField.test.js +10 -0
  145. package/dist/components/formField/FormField.test.js.map +1 -1
  146. package/dist/components/icon/allowedIcons.d.ts +1 -0
  147. package/dist/components/icon/allowedIcons.d.ts.map +1 -1
  148. package/dist/components/icon/allowedIcons.js +2 -1
  149. package/dist/components/icon/allowedIcons.js.map +1 -1
  150. package/dist/components/progress/Progress.stories.d.ts +49 -49
  151. package/dist/components/row/Row.d.ts +10 -0
  152. package/dist/components/row/Row.d.ts.map +1 -0
  153. package/dist/components/row/Row.js +17 -0
  154. package/dist/components/row/Row.js.map +1 -0
  155. package/dist/components/row/Row.stories.d.ts +15 -0
  156. package/dist/components/row/Row.stories.d.ts.map +1 -0
  157. package/dist/components/row/Row.stories.js +65 -0
  158. package/dist/components/row/Row.stories.js.map +1 -0
  159. package/dist/components/row/Row.test.d.ts +2 -0
  160. package/dist/components/row/Row.test.d.ts.map +1 -0
  161. package/dist/components/row/Row.test.js +62 -0
  162. package/dist/components/row/Row.test.js.map +1 -0
  163. package/dist/components/section/Section.stories.d.ts +27 -0
  164. package/dist/components/section/Section.stories.d.ts.map +1 -1
  165. package/dist/components/section/Section.stories.js +45 -1
  166. package/dist/components/section/Section.stories.js.map +1 -1
  167. package/dist/components/singleUser/SingleUser.d.ts +15 -0
  168. package/dist/components/singleUser/SingleUser.d.ts.map +1 -0
  169. package/dist/components/singleUser/SingleUser.js +9 -0
  170. package/dist/components/singleUser/SingleUser.js.map +1 -0
  171. package/dist/components/singleUser/SingleUser.stories.d.ts +11 -0
  172. package/dist/components/singleUser/SingleUser.stories.d.ts.map +1 -0
  173. package/dist/components/singleUser/SingleUser.stories.js +52 -0
  174. package/dist/components/singleUser/SingleUser.stories.js.map +1 -0
  175. package/dist/components/singleUser/SingleUser.test.d.ts +2 -0
  176. package/dist/components/singleUser/SingleUser.test.d.ts.map +1 -0
  177. package/dist/components/singleUser/SingleUser.test.js +30 -0
  178. package/dist/components/singleUser/SingleUser.test.js.map +1 -0
  179. package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.d.ts.map +1 -1
  180. package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.js +9 -3
  181. package/dist/components/table/cellRenderers/SelectDropdownCellRenderer.js.map +1 -1
  182. package/dist/components/tabs/TabsItem.stories.d.ts +2 -2
  183. package/dist/components/tag/Tag.d.ts +9 -6
  184. package/dist/components/tag/Tag.d.ts.map +1 -1
  185. package/dist/components/tag/Tag.js +8 -2
  186. package/dist/components/tag/Tag.js.map +1 -1
  187. package/dist/components/tag/Tag.stories.d.ts +11 -6
  188. package/dist/components/tag/Tag.stories.d.ts.map +1 -1
  189. package/dist/components/tag/Tag.stories.js +68 -4
  190. package/dist/components/tag/Tag.stories.js.map +1 -1
  191. package/dist/components/tag/Tag.test.js +86 -50
  192. package/dist/components/tag/Tag.test.js.map +1 -1
  193. package/dist/components/toggle/Toggle.d.ts +3 -0
  194. package/dist/components/toggle/Toggle.d.ts.map +1 -0
  195. package/dist/components/toggle/Toggle.js +8 -0
  196. package/dist/components/toggle/Toggle.js.map +1 -0
  197. package/dist/components/toggle/Toggle.stories.d.ts +97 -0
  198. package/dist/components/toggle/Toggle.stories.d.ts.map +1 -0
  199. package/dist/components/toggle/Toggle.stories.js +186 -0
  200. package/dist/components/toggle/Toggle.stories.js.map +1 -0
  201. package/dist/components/toggle/Toggle.test.d.ts +2 -0
  202. package/dist/components/toggle/Toggle.test.d.ts.map +1 -0
  203. package/dist/components/toggle/Toggle.test.js +58 -0
  204. package/dist/components/toggle/Toggle.test.js.map +1 -0
  205. package/dist/index.css +703 -25
  206. package/dist/index.css.map +1 -1
  207. package/dist/index.d.ts +35 -25
  208. package/dist/index.d.ts.map +1 -1
  209. package/dist/index.js +31 -25
  210. package/dist/index.js.map +1 -1
  211. package/dist/mocks/comboboxStoryOptions.d.ts +5 -0
  212. package/dist/mocks/comboboxStoryOptions.d.ts.map +1 -0
  213. package/dist/mocks/comboboxStoryOptions.js +22 -0
  214. package/dist/mocks/comboboxStoryOptions.js.map +1 -0
  215. package/dist/utils/isSelectAllChord.d.ts +5 -0
  216. package/dist/utils/isSelectAllChord.d.ts.map +1 -0
  217. package/dist/utils/isSelectAllChord.js +7 -0
  218. package/dist/utils/isSelectAllChord.js.map +1 -0
  219. package/dist/utils/isSelectAllChord.test.d.ts +2 -0
  220. package/dist/utils/isSelectAllChord.test.d.ts.map +1 -0
  221. package/dist/utils/isSelectAllChord.test.js +19 -0
  222. package/dist/utils/isSelectAllChord.test.js.map +1 -0
  223. package/dist/utils/nextCircularIndex.d.ts +3 -0
  224. package/dist/utils/nextCircularIndex.d.ts.map +1 -0
  225. package/dist/utils/nextCircularIndex.js +10 -0
  226. package/dist/utils/nextCircularIndex.js.map +1 -0
  227. package/dist/utils/nextCircularIndex.test.d.ts +2 -0
  228. package/dist/utils/nextCircularIndex.test.d.ts.map +1 -0
  229. package/dist/utils/nextCircularIndex.test.js +23 -0
  230. package/dist/utils/nextCircularIndex.test.js.map +1 -0
  231. package/dist/utils/scrollElementIntoViewById.d.ts +2 -0
  232. package/dist/utils/scrollElementIntoViewById.d.ts.map +1 -0
  233. package/dist/utils/scrollElementIntoViewById.js +16 -0
  234. package/dist/utils/scrollElementIntoViewById.js.map +1 -0
  235. package/dist/utils/scrollElementIntoViewById.test.d.ts +2 -0
  236. package/dist/utils/scrollElementIntoViewById.test.d.ts.map +1 -0
  237. package/dist/utils/scrollElementIntoViewById.test.js +31 -0
  238. package/dist/utils/scrollElementIntoViewById.test.js.map +1 -0
  239. package/package.json +1 -1
  240. package/src/components/avatar/Avatar.stories.tsx +8 -0
  241. package/src/components/avatar/Avatar.tsx +3 -3
  242. package/src/components/badge/Badge.stories.tsx +74 -0
  243. package/src/components/badge/Badge.test.tsx +28 -0
  244. package/src/components/badge/Badge.tsx +35 -0
  245. package/src/components/badge/badge.scss +86 -0
  246. package/src/components/card/Card.tsx +1 -1
  247. package/src/components/combobox/Combobox.stories.tsx +340 -0
  248. package/src/components/combobox/Combobox.test.tsx +1160 -0
  249. package/src/components/combobox/Combobox.tsx +434 -0
  250. package/src/components/combobox/ComboboxButtonTrigger.tsx +195 -0
  251. package/src/components/combobox/ComboboxListbox.tsx +224 -0
  252. package/src/components/combobox/ComboboxOptionRow.tsx +128 -0
  253. package/src/components/combobox/ComboboxTrigger.tsx +134 -0
  254. package/src/components/combobox/buildListboxDisplayOptions.test.ts +24 -0
  255. package/src/components/combobox/buildListboxDisplayOptions.ts +12 -0
  256. package/src/components/combobox/combobox.scss +390 -0
  257. package/src/components/combobox/comboboxKeyboardTypes.ts +45 -0
  258. package/src/components/combobox/highlightLabel.tsx +42 -0
  259. package/src/components/combobox/normaliseComboboxQuery.ts +1 -0
  260. package/src/components/combobox/types.ts +53 -0
  261. package/src/components/combobox/useChipSelection.ts +53 -0
  262. package/src/components/combobox/useComboboxChipKeyboard.test.tsx +141 -0
  263. package/src/components/combobox/useComboboxChipKeyboard.ts +121 -0
  264. package/src/components/combobox/useComboboxKeyboard.ts +108 -0
  265. package/src/components/combobox/useComboboxListboxDom.ts +36 -0
  266. package/src/components/combobox/useComboboxListboxKeyboard.test.tsx +186 -0
  267. package/src/components/combobox/useComboboxListboxKeyboard.ts +172 -0
  268. package/src/components/combobox/useComboboxPopoverBehavior.ts +179 -0
  269. package/src/components/combobox/useComboboxState.ts +232 -0
  270. package/src/components/combobox/useElementWidth.ts +40 -0
  271. package/src/components/combobox/useVisibleChips.test.tsx +91 -0
  272. package/src/components/combobox/useVisibleChips.ts +100 -0
  273. package/src/components/dot/Dot.stories.tsx +41 -0
  274. package/src/components/dot/Dot.test.tsx +21 -0
  275. package/src/components/dot/Dot.tsx +18 -0
  276. package/src/components/dot/dot.scss +35 -0
  277. package/src/components/formField/FormField.stories.tsx +30 -1
  278. package/src/components/formField/FormField.test.tsx +20 -0
  279. package/src/components/formField/FormField.tsx +11 -5
  280. package/src/components/formField/inputs/number/numberInput.scss +12 -4
  281. package/src/components/icon/allowedIcons.tsx +2 -0
  282. package/src/components/pill/pill.scss +4 -6
  283. package/src/components/row/Row.stories.tsx +85 -0
  284. package/src/components/row/Row.test.tsx +82 -0
  285. package/src/components/row/Row.tsx +54 -0
  286. package/src/components/row/row.scss +61 -0
  287. package/src/components/section/Section.stories.tsx +56 -0
  288. package/src/components/singleUser/SingleUser.stories.tsx +63 -0
  289. package/src/components/singleUser/SingleUser.test.tsx +61 -0
  290. package/src/components/singleUser/SingleUser.tsx +45 -0
  291. package/src/components/singleUser/singleUser.scss +14 -0
  292. package/src/components/table/cellRenderers/SelectDropdownCellRenderer.tsx +19 -3
  293. package/src/components/tag/Tag.stories.tsx +88 -6
  294. package/src/components/tag/Tag.test.tsx +110 -44
  295. package/src/components/tag/Tag.tsx +38 -14
  296. package/src/components/tag/tag.scss +45 -30
  297. package/src/components/toggle/Toggle.stories.tsx +239 -0
  298. package/src/components/toggle/Toggle.test.tsx +66 -0
  299. package/src/components/toggle/Toggle.tsx +12 -0
  300. package/src/components/toggle/toggle.scss +126 -0
  301. package/src/index.scss +6 -0
  302. package/src/index.ts +48 -31
  303. package/src/mocks/comboboxStoryOptions.ts +25 -0
  304. package/src/tokens.scss +33 -4
  305. package/src/utils/isSelectAllChord.test.ts +24 -0
  306. package/src/utils/isSelectAllChord.ts +8 -0
  307. package/src/utils/nextCircularIndex.test.ts +26 -0
  308. package/src/utils/nextCircularIndex.ts +15 -0
  309. package/src/utils/scrollElementIntoViewById.test.ts +38 -0
  310. package/src/utils/scrollElementIntoViewById.ts +20 -0
  311. package/tokens/json/Arbor.json +3828 -3704
@@ -1,4 +1,5 @@
1
1
  import classNames from 'classnames';
2
+ import { Icon } from 'Components/icon/Icon';
2
3
 
3
4
  export type TagColor = 'neutral'
4
5
  | 'orange'
@@ -9,26 +10,49 @@ export type TagColor = 'neutral'
9
10
  | 'salmon'
10
11
  | 'yellow';
11
12
 
12
- export type DotColour = 'purple' | 'salmon' | 'teal' | 'yellow' | 'green' | 'orange' | 'blue';
13
-
14
- type TagProps = {
15
- text: string;
13
+ export type TagProps = {
14
+ children: React.ReactNode;
16
15
  color?: TagColor;
17
- dotColour?: DotColour;
16
+ selected?: boolean;
17
+ slotStart?: React.ReactNode;
18
+ slotEnd?: React.ReactNode;
19
+ onRemove?: () => void;
20
+ removeLabel?: string;
21
+ removeButtonTabIndex?: 0 | -1;
18
22
  };
19
23
 
20
- export const Tag = ({ text, color = 'neutral', dotColour }: TagProps) => {
24
+ export const Tag = ({
25
+ children,
26
+ color = 'neutral',
27
+ selected = false,
28
+ slotStart,
29
+ slotEnd,
30
+ onRemove,
31
+ removeLabel = 'Remove',
32
+ removeButtonTabIndex = 0,
33
+ }: TagProps): React.JSX.Element => {
21
34
  return (
22
- <span
23
- className={classNames('ds-tag', `ds-tag--${color}`)}
35
+ <span className={classNames('ds-tag', `ds-tag--${color}`, {
36
+ 'ds-tag--selected': selected,
37
+ })}
24
38
  >
25
- {dotColour && (
26
- <span
27
- aria-label={`${dotColour} dot`}
28
- className={classNames('ds-tag__dot', `ds-tag__dot--${dotColour}`)}
29
- />
39
+ {slotStart && <span className="ds-tag__slot-start">{slotStart}</span>}
40
+ <span className="ds-tag__label">{children}</span>
41
+ {slotEnd && <span className="ds-tag__slot-end">{slotEnd}</span>}
42
+ {onRemove && (
43
+ <button
44
+ type="button"
45
+ className="ds-tag__remove"
46
+ aria-label={removeLabel}
47
+ onClick={(e) => {
48
+ e.stopPropagation();
49
+ onRemove();
50
+ }}
51
+ tabIndex={removeButtonTabIndex}
52
+ >
53
+ <Icon name="x" size={12} />
54
+ </button>
30
55
  )}
31
- {text}
32
56
  </span>
33
57
  );
34
58
  };
@@ -1,21 +1,24 @@
1
1
  .ds-tag {
2
- display: flex;
3
- padding: var(--tag-spacing-vertical) var(--tag-spacing-horizontal);
2
+ display: inline-flex;
3
+ padding: 0 var(--tag-spacing-horizontal);
4
4
  align-items: center;
5
5
  gap: var(--tag-spacing-gap-horizontal);
6
6
  border-radius: var(--tag-radius);
7
+ border: var(--border-weight) solid transparent;
8
+ box-sizing: border-box;
7
9
  flex-grow: 0;
8
10
  width: fit-content;
9
-
10
- /* typography/body/p1-reg */
11
+ white-space: nowrap;
12
+ max-width: 100%;
13
+ height: var(--tag-height);
11
14
  font-style: normal;
12
- line-height: 150%; /* 19.5px */
15
+ line-height: 150%;
13
16
 
14
17
  &--neutral {
15
18
  color: var(--tag-neutral-color-text);
16
19
  background: var(--tag-neutral-color-background);
17
20
  }
18
-
21
+
19
22
  &--orange {
20
23
  color: var(--tag-category-orange-color-text);
21
24
  background: var(--tag-category-orange-color-background);
@@ -50,38 +53,50 @@
50
53
  color: var(--tag-category-yellow-color-text);
51
54
  background: var(--tag-category-yellow-color-background);
52
55
  }
53
- }
54
56
 
55
- .ds-tag__dot {
56
- width: 10px;
57
- height: 10px;
58
- border-radius: 50%;
59
-
60
- &--purple {
61
- background-color: var(--color-extended-colours-purple-500);
57
+ &--selected {
58
+ background: var(--tag-selected-color-background);
59
+ color: var(--tag-neutral-color-text);
60
+ border-color: var(--tag-selected-color-border);
62
61
  }
63
62
 
64
- &--salmon {
65
- background-color: var(--color-extended-colours-salmon-500);
66
- }
63
+ }
67
64
 
68
- &--teal {
69
- background-color: var(--color-extended-colours-teal-500);
70
- }
65
+ .ds-tag__slot-start {
66
+ display: flex;
67
+ align-items: center;
68
+ flex-shrink: 0;
69
+ }
71
70
 
72
- &--yellow {
73
- background-color: var(--color-extended-colours-yellow-500);
74
- }
71
+ .ds-tag__label {
72
+ overflow: hidden;
73
+ text-overflow: ellipsis;
74
+ }
75
75
 
76
- &--green {
77
- background-color: var(--color-extended-colours-green-500);
78
- }
76
+ .ds-tag__slot-end {
77
+ display: flex;
78
+ align-items: center;
79
+ flex-shrink: 0;
80
+ }
79
81
 
80
- &--orange {
81
- background-color: var(--color-extended-colours-orange-500);
82
+ .ds-tag__remove {
83
+ display: flex;
84
+ align-items: center;
85
+ justify-content: center;
86
+ border: none;
87
+ background: transparent;
88
+ padding: 0;
89
+ cursor: pointer;
90
+ color: inherit;
91
+ border-radius: 50%;
92
+ flex-shrink: 0;
93
+
94
+ &:hover {
95
+ background-color: var(--color-grey-200);
82
96
  }
83
97
 
84
- &--blue {
85
- background-color: var(--color-extended-colours-blue-500);
98
+ &:disabled {
99
+ cursor: not-allowed;
100
+ opacity: 0.5;
86
101
  }
87
102
  }
@@ -0,0 +1,239 @@
1
+ import { useState } from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react-vite';
3
+ import { fn } from 'storybook/test';
4
+ import { Toggle } from './Toggle';
5
+
6
+ /**
7
+ * The Toggle component is a binary on/off switch, built on top of Radix UI's
8
+ * Switch primitive. Think of it like the light switch in the St. Olaf town
9
+ * hall — everyone in town knows exactly whether the lights are on or off,
10
+ * and there is never any confusion about which state you are in.
11
+ *
12
+ * Toggling is the right choice when you need an immediate, binary setting
13
+ * change — "dark mode on", "notifications off", "feature enabled". Unlike a
14
+ * checkbox, a toggle implies the change takes effect right away, without
15
+ * needing a form submission.
16
+ *
17
+ * **Accessibility**
18
+ * - Rendered as a `<button role="switch">` — screen readers announce the
19
+ * current state ("checked" / "not checked") automatically.
20
+ * - Fully keyboard accessible: `Space` or `Enter` toggles the state.
21
+ * - Associate a visible label with the toggle using a `<label htmlFor={id}>`
22
+ * so users of all abilities know what they are toggling.
23
+ * - The `disabled` prop renders the element as non-interactive and applies
24
+ * correct ARIA semantics.
25
+ *
26
+ * **CSS classes**
27
+ * - Root element: `ds-toggle`
28
+ * - Thumb (the sliding dot): `ds-toggle__thumb`
29
+ * - Checked state is driven by Radix's `data-state="checked"` attribute,
30
+ * which the SCSS uses to apply brand colours and shift the thumb position.
31
+ */
32
+ const meta = {
33
+ title: 'Components/Toggle',
34
+ component: Toggle,
35
+ parameters: {
36
+ layout: 'centered',
37
+ },
38
+ tags: ['autodocs'],
39
+ args: {
40
+ onCheckedChange: fn(),
41
+ },
42
+ argTypes: {
43
+ checked: {
44
+ control: 'boolean',
45
+ description:
46
+ 'Controls the checked state when used as a controlled component. '
47
+ + 'Pair with `onCheckedChange` to keep your state in sync.',
48
+ },
49
+ defaultChecked: {
50
+ control: 'boolean',
51
+ description:
52
+ 'Sets the initial checked state for an uncontrolled toggle. '
53
+ + 'The component manages its own state after mount.',
54
+ },
55
+ disabled: {
56
+ control: 'boolean',
57
+ description:
58
+ 'Disables the toggle. The toggle becomes non-interactive and is '
59
+ + 'visually dimmed. Useful for read-only settings or permission-gated features.',
60
+ },
61
+ required: {
62
+ control: 'boolean',
63
+ description:
64
+ 'Marks the toggle as required when used inside a `<form>`. '
65
+ + 'Prevents form submission if the toggle is unchecked.',
66
+ },
67
+ name: {
68
+ control: 'text',
69
+ description:
70
+ 'The name of the toggle as submitted with form data. '
71
+ + 'Works the same as the `name` attribute on a native `<input>`.',
72
+ },
73
+ value: {
74
+ control: 'text',
75
+ description:
76
+ 'The value submitted with form data when the toggle is checked. '
77
+ + 'Defaults to `"on"` (matching native checkbox behaviour).',
78
+ },
79
+ onCheckedChange: {
80
+ action: 'checkedChange',
81
+ description:
82
+ 'Callback fired whenever the checked state changes. '
83
+ + 'Receives the new boolean value: `(checked: boolean) => void`.',
84
+ },
85
+ },
86
+ } satisfies Meta<typeof Toggle>;
87
+
88
+ export default meta;
89
+ type Story = StoryObj<typeof meta>;
90
+
91
+ // ---------------------------------------------------------------------------
92
+ // Basic states
93
+ // ---------------------------------------------------------------------------
94
+
95
+ /** The toggle in its default, unchecked (off) state. */
96
+ export const Default: Story = {};
97
+
98
+ /**
99
+ * The toggle in its checked (on) state.
100
+ *
101
+ * Uses `defaultChecked` so the component manages its own state — perfect for
102
+ * uncontrolled usage where you just need a sensible starting position.
103
+ */
104
+ export const Checked: Story = {
105
+ args: {
106
+ defaultChecked: true,
107
+ },
108
+ };
109
+
110
+ // ---------------------------------------------------------------------------
111
+ // Disabled states
112
+ // ---------------------------------------------------------------------------
113
+
114
+ /**
115
+ * A disabled toggle that is currently off.
116
+ *
117
+ * Use this when a setting exists but cannot be changed in the current context
118
+ * — for example, a feature that requires a higher subscription tier.
119
+ */
120
+ export const Disabled: Story = {
121
+ args: {
122
+ disabled: true,
123
+ },
124
+ };
125
+
126
+ /**
127
+ * A disabled toggle that is currently on.
128
+ *
129
+ * This communicates "this setting is enabled, but you cannot change it right
130
+ * now." Always pair a disabled toggle with a tooltip or helper text that
131
+ * explains why it cannot be interacted with.
132
+ */
133
+ export const DisabledChecked: Story = {
134
+ args: {
135
+ defaultChecked: true,
136
+ disabled: true,
137
+ },
138
+ };
139
+
140
+ // ---------------------------------------------------------------------------
141
+ // Controlled usage
142
+ // ---------------------------------------------------------------------------
143
+
144
+ /**
145
+ * A fully controlled toggle backed by React state.
146
+ *
147
+ * Back in St. Olaf, my neighbour Hildegard Bjornsson kept a hand-written
148
+ * ledger of every switch in her house — she never trusted a switch to remember
149
+ * its own state! A controlled toggle is just like that ledger: your component
150
+ * owns the truth, and the toggle simply displays what you tell it to.
151
+ *
152
+ * Use the controlled pattern when:
153
+ * - You need to read the toggle state elsewhere in the UI.
154
+ * - You want to conditionally show/hide other elements based on the state.
155
+ * - You are submitting state as part of a larger form payload.
156
+ */
157
+ const ControlledTemplate = (args: React.ComponentProps<typeof Toggle>) => {
158
+ const [enabled, setEnabled] = useState(false);
159
+
160
+ return (
161
+ <div
162
+ style={{
163
+ display: 'flex',
164
+ flexDirection: 'column',
165
+ alignItems: 'center',
166
+ gap: '12px',
167
+ }}
168
+ >
169
+ <Toggle
170
+ {...args}
171
+ checked={enabled}
172
+ onCheckedChange={(checked) => {
173
+ setEnabled(checked);
174
+ args.onCheckedChange?.(checked);
175
+ }}
176
+ />
177
+ <p
178
+ style={{
179
+ margin: 0,
180
+ fontSize: '14px',
181
+ color: enabled ? 'var(--color-brand-700)' : 'var(--color-grey-500)',
182
+ }}
183
+ >
184
+ {enabled ? 'Feature enabled' : 'Feature disabled'}
185
+ </p>
186
+ </div>
187
+ );
188
+ };
189
+
190
+ export const Controlled: Story = {
191
+ render: ControlledTemplate,
192
+ };
193
+
194
+ // ---------------------------------------------------------------------------
195
+ // With label (accessible usage)
196
+ // ---------------------------------------------------------------------------
197
+
198
+ /**
199
+ * A toggle paired with a visible `<label>` element for full accessibility.
200
+ *
201
+ * This is the pattern you should reach for in almost every real-world use
202
+ * case. By wiring the label's `htmlFor` to the toggle's `id`, you get:
203
+ *
204
+ * - Screen readers announce both the label text and the toggle state.
205
+ * - Clicking the label text also toggles the switch (larger click target).
206
+ * - Visual users see a clear description of what the toggle controls.
207
+ *
208
+ * You know, this is a lot like what we learned in St. Olaf Home Economics
209
+ * class — always label your preserves. An unlabelled jar of lingonberry jam
210
+ * looks just like an unlabelled jar of beet relish, and nobody wants that
211
+ * confusion at the dinner table. Or on a settings page!
212
+ */
213
+ const WithLabelTemplate = (args: React.ComponentProps<typeof Toggle>) => {
214
+ const [enabled, setEnabled] = useState(false);
215
+
216
+ return (
217
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
218
+ <Toggle
219
+ {...args}
220
+ id="email-notifications-toggle"
221
+ checked={enabled}
222
+ onCheckedChange={(checked) => {
223
+ setEnabled(checked);
224
+ args.onCheckedChange?.(checked);
225
+ }}
226
+ />
227
+ <label
228
+ htmlFor="email-notifications-toggle"
229
+ style={{ fontSize: '14px', cursor: 'pointer', userSelect: 'none' }}
230
+ >
231
+ Email notifications
232
+ </label>
233
+ </div>
234
+ );
235
+ };
236
+
237
+ export const WithLabel: Story = {
238
+ render: WithLabelTemplate,
239
+ };
@@ -0,0 +1,66 @@
1
+ import { describe, expect, test, vi } from 'vitest';
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import '@testing-library/jest-dom/vitest';
4
+ import { Toggle } from './Toggle';
5
+
6
+ describe('Toggle component', () => {
7
+ test('renders a switch element', () => {
8
+ render(<Toggle />);
9
+ expect(screen.getByRole('switch')).toBeInTheDocument();
10
+ });
11
+
12
+ test('is unchecked by default', () => {
13
+ render(<Toggle />);
14
+ expect(screen.getByRole('switch')).not.toBeChecked();
15
+ });
16
+
17
+ test('is checked when defaultChecked is true', () => {
18
+ render(<Toggle defaultChecked />);
19
+ expect(screen.getByRole('switch')).toBeChecked();
20
+ });
21
+
22
+ test('is checked when controlled checked prop is true', () => {
23
+ render(<Toggle checked onCheckedChange={vi.fn()} />);
24
+ expect(screen.getByRole('switch')).toBeChecked();
25
+ });
26
+
27
+ test('calls onCheckedChange with true when toggled on', () => {
28
+ const handleChange = vi.fn();
29
+ render(<Toggle onCheckedChange={handleChange} />);
30
+ fireEvent.click(screen.getByRole('switch'));
31
+ expect(handleChange).toHaveBeenCalledTimes(1);
32
+ expect(handleChange).toHaveBeenCalledWith(true);
33
+ });
34
+
35
+ test('calls onCheckedChange with false when toggled off', () => {
36
+ const handleChange = vi.fn();
37
+ render(<Toggle defaultChecked onCheckedChange={handleChange} />);
38
+ fireEvent.click(screen.getByRole('switch'));
39
+ expect(handleChange).toHaveBeenCalledTimes(1);
40
+ expect(handleChange).toHaveBeenCalledWith(false);
41
+ });
42
+
43
+ test('is disabled when disabled prop is set', () => {
44
+ render(<Toggle disabled />);
45
+ expect(screen.getByRole('switch')).toBeDisabled();
46
+ });
47
+
48
+ test('does not call onCheckedChange when disabled', () => {
49
+ const handleChange = vi.fn();
50
+ render(<Toggle disabled onCheckedChange={handleChange} />);
51
+ fireEvent.click(screen.getByRole('switch'));
52
+ expect(handleChange).not.toHaveBeenCalled();
53
+ });
54
+
55
+ test('applies the ds-toggle base class', () => {
56
+ render(<Toggle />);
57
+ expect(screen.getByRole('switch')).toHaveClass('ds-toggle');
58
+ });
59
+
60
+ test('applies additional className alongside base class', () => {
61
+ render(<Toggle className="custom-class" />);
62
+ const toggle = screen.getByRole('switch');
63
+ expect(toggle).toHaveClass('ds-toggle');
64
+ expect(toggle).toHaveClass('custom-class');
65
+ });
66
+ });
@@ -0,0 +1,12 @@
1
+ import classNames from 'classnames';
2
+ import { Switch } from 'radix-ui';
3
+
4
+ export const Toggle = (props: Switch.SwitchProps) => {
5
+ const { className, ...rest } = props;
6
+
7
+ return (
8
+ <Switch.Root className={classNames('ds-toggle', className)} {...rest}>
9
+ <Switch.Thumb className="ds-toggle__thumb" />
10
+ </Switch.Root>
11
+ );
12
+ };
@@ -0,0 +1,126 @@
1
+ .ds-toggle {
2
+ all: unset;
3
+ width: 40px;
4
+ height: 24px;
5
+ background-color: var(--toggle-off-default-color-background);
6
+ border-radius: var(--toggle-radius);
7
+ border: var(--toggle-weight-border) solid var(--toggle-off-default-color-border);
8
+ position: relative;
9
+ cursor: pointer;
10
+
11
+ &:focus {
12
+ background-color: var(--toggle-off-focus-color-background);
13
+ border-color: var(--toggle-off-focus-color-border);
14
+ outline: var(--focus-border) solid var(--color-brand-300);
15
+ }
16
+
17
+ &:hover {
18
+ background-color: var(--toggle-off-hover-color-background);
19
+ border-color: var(--toggle-off-hover-color-border);
20
+ }
21
+
22
+ &:active {
23
+ background-color: var(--toggle-off-active-color-background);
24
+ border-color: var(--toggle-off-active-color-border);
25
+ }
26
+
27
+ &:disabled {
28
+ background-color: var(--toggle-off-disabled-color-background);
29
+ border-color: var(--toggle-off-disabled-color-border);
30
+ cursor: default;
31
+
32
+ &:focus, &:hover, &:active {
33
+ background-color: var(--toggle-off-disabled-color-background);
34
+ border-color: var(--toggle-off-disabled-color-border);
35
+ outline: none;
36
+ }
37
+ }
38
+
39
+ &[data-state="checked"] {
40
+ background-color: var(--toggle-on-default-color-background);
41
+ border-color: var(--toggle-on-default-color-border);
42
+
43
+ &:focus {
44
+ background-color: var(--toggle-on-focus-color-background);
45
+ border-color: var(--toggle-on-focus-color-border);
46
+ }
47
+
48
+ &:hover {
49
+ background-color: var(--toggle-on-hover-color-background);
50
+ border-color: var(--toggle-on-hover-color-border);
51
+ }
52
+
53
+ &:active {
54
+ background-color: var(--toggle-on-active-color-background);
55
+ border-color: var(--toggle-on-active-color-border);
56
+ }
57
+
58
+ &:disabled {
59
+ background-color: var(--toggle-on-disabled-color-background);
60
+ border-color: var(--toggle-on-disabled-color-border);
61
+ cursor: default;
62
+
63
+ &:focus, &:hover, &:active {
64
+ background-color: var(--toggle-on-disabled-color-background);
65
+ border-color: var(--toggle-on-disabled-color-border);
66
+ outline: none;
67
+ }
68
+ }
69
+ }
70
+
71
+ &__thumb {
72
+ display: block;
73
+ width: 18px;
74
+ height: 18px;
75
+ background-color: var(--toggle-off-default-color-dot);
76
+ border-radius: var(--border-radius-round);
77
+ transition: transform .1s;
78
+ transform: translateX(2px);
79
+ will-change: transform;
80
+
81
+ &:focus {
82
+ background-color: var(--toggle-off-focus-color-dot);
83
+ }
84
+
85
+ &:hover {
86
+ background-color: var(--toggle-off-hover-color-dot);
87
+ }
88
+
89
+ &:active {
90
+ background-color: var(--toggle-off-active-color-dot);
91
+ }
92
+
93
+ &[data-disabled] {
94
+ background-color: var(--toggle-off-disabled-color-dot);
95
+
96
+ &:focus, &:hover, &:active {
97
+ background-color: var(--toggle-off-disabled-color-dot);
98
+ }
99
+ }
100
+
101
+ &[data-state="checked"] {
102
+ transform: translateX(20px);
103
+ background-color: var(--toggle-on-default-color-dot);
104
+
105
+ &:focus {
106
+ background-color: var(--toggle-on-focus-color-dot);
107
+ }
108
+
109
+ &:hover {
110
+ background-color: var(--toggle-on-hover-color-dot);
111
+ }
112
+
113
+ &:active {
114
+ background-color: var(--toggle-on-active-color-dot);
115
+ }
116
+
117
+ &[data-disabled] {
118
+ background-color: var(--toggle-on-disabled-color-dot);
119
+
120
+ &:focus, &:hover, &:active {
121
+ background-color: var(--toggle-on-disabled-color-dot);
122
+ }
123
+ }
124
+ }
125
+ }
126
+ }
package/src/index.scss CHANGED
@@ -16,6 +16,8 @@
16
16
  @use "components/formField/inputs/selectDropdown/selectDropdown";
17
17
  @use "components/formField/inputs/colourPickerDropdown/colourPickerDropdown.scss";
18
18
  @use "components/tag/tag.scss";
19
+ @use "components/dot/dot.scss";
20
+ @use "components/badge/badge.scss";
19
21
  @use "components/pill/pill.scss";
20
22
  @use "components/section/section.scss";
21
23
  @use "components/tabs/tabs.scss";
@@ -35,6 +37,10 @@
35
37
  @use "components/toast/toast.scss";
36
38
  @use "components/datePicker/datePicker.scss";
37
39
  @use "components/avatar/avatar.scss";
40
+ @use "components/singleUser/singleUser.scss";
38
41
  @use "components/avatarGroup/avatarGroup.scss";
39
42
  @use "components/userDropdown/userDropdown.scss";
43
+ @use "components/row/row.scss";
44
+ @use "components/combobox/combobox.scss";
45
+ @use "components/toggle/toggle.scss";
40
46
  @import "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap";