@arbor-education/design-system.components 0.6.0 → 0.7.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 (285) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/components/avatar/Avatar.d.ts +1 -1
  3. package/dist/components/avatar/Avatar.d.ts.map +1 -1
  4. package/dist/components/avatar/Avatar.js +1 -1
  5. package/dist/components/avatar/Avatar.js.map +1 -1
  6. package/dist/components/avatar/Avatar.stories.d.ts.map +1 -1
  7. package/dist/components/avatar/Avatar.stories.js +7 -0
  8. package/dist/components/avatar/Avatar.stories.js.map +1 -1
  9. package/dist/components/badge/Badge.d.ts +12 -0
  10. package/dist/components/badge/Badge.d.ts.map +1 -0
  11. package/dist/components/badge/Badge.js +6 -0
  12. package/dist/components/badge/Badge.js.map +1 -0
  13. package/dist/components/badge/Badge.stories.d.ts +10 -0
  14. package/dist/components/badge/Badge.stories.d.ts.map +1 -0
  15. package/dist/components/badge/Badge.stories.js +51 -0
  16. package/dist/components/badge/Badge.stories.js.map +1 -0
  17. package/dist/components/badge/Badge.test.d.ts +2 -0
  18. package/dist/components/badge/Badge.test.d.ts.map +1 -0
  19. package/dist/components/badge/Badge.test.js +23 -0
  20. package/dist/components/badge/Badge.test.js.map +1 -0
  21. package/dist/components/card/Card.js +1 -1
  22. package/dist/components/card/Card.js.map +1 -1
  23. package/dist/components/combobox/Combobox.d.ts +16 -0
  24. package/dist/components/combobox/Combobox.d.ts.map +1 -0
  25. package/dist/components/combobox/Combobox.js +195 -0
  26. package/dist/components/combobox/Combobox.js.map +1 -0
  27. package/dist/components/combobox/Combobox.stories.d.ts +24 -0
  28. package/dist/components/combobox/Combobox.stories.d.ts.map +1 -0
  29. package/dist/components/combobox/Combobox.stories.js +246 -0
  30. package/dist/components/combobox/Combobox.stories.js.map +1 -0
  31. package/dist/components/combobox/Combobox.test.d.ts +2 -0
  32. package/dist/components/combobox/Combobox.test.d.ts.map +1 -0
  33. package/dist/components/combobox/Combobox.test.js +798 -0
  34. package/dist/components/combobox/Combobox.test.js.map +1 -0
  35. package/dist/components/combobox/ComboboxButtonTrigger.d.ts +28 -0
  36. package/dist/components/combobox/ComboboxButtonTrigger.d.ts.map +1 -0
  37. package/dist/components/combobox/ComboboxButtonTrigger.js +64 -0
  38. package/dist/components/combobox/ComboboxButtonTrigger.js.map +1 -0
  39. package/dist/components/combobox/ComboboxListbox.d.ts +44 -0
  40. package/dist/components/combobox/ComboboxListbox.d.ts.map +1 -0
  41. package/dist/components/combobox/ComboboxListbox.js +37 -0
  42. package/dist/components/combobox/ComboboxListbox.js.map +1 -0
  43. package/dist/components/combobox/ComboboxOptionRow.d.ts +23 -0
  44. package/dist/components/combobox/ComboboxOptionRow.d.ts.map +1 -0
  45. package/dist/components/combobox/ComboboxOptionRow.js +27 -0
  46. package/dist/components/combobox/ComboboxOptionRow.js.map +1 -0
  47. package/dist/components/combobox/ComboboxTrigger.d.ts +35 -0
  48. package/dist/components/combobox/ComboboxTrigger.d.ts.map +1 -0
  49. package/dist/components/combobox/ComboboxTrigger.js +15 -0
  50. package/dist/components/combobox/ComboboxTrigger.js.map +1 -0
  51. package/dist/components/combobox/buildListboxDisplayOptions.d.ts +3 -0
  52. package/dist/components/combobox/buildListboxDisplayOptions.d.ts.map +1 -0
  53. package/dist/components/combobox/buildListboxDisplayOptions.js +13 -0
  54. package/dist/components/combobox/buildListboxDisplayOptions.js.map +1 -0
  55. package/dist/components/combobox/buildListboxDisplayOptions.test.d.ts +2 -0
  56. package/dist/components/combobox/buildListboxDisplayOptions.test.d.ts.map +1 -0
  57. package/dist/components/combobox/buildListboxDisplayOptions.test.js +22 -0
  58. package/dist/components/combobox/buildListboxDisplayOptions.test.js.map +1 -0
  59. package/dist/components/combobox/comboboxKeyboardTypes.d.ts +41 -0
  60. package/dist/components/combobox/comboboxKeyboardTypes.d.ts.map +1 -0
  61. package/dist/components/combobox/comboboxKeyboardTypes.js +2 -0
  62. package/dist/components/combobox/comboboxKeyboardTypes.js.map +1 -0
  63. package/dist/components/combobox/highlightLabel.d.ts +10 -0
  64. package/dist/components/combobox/highlightLabel.d.ts.map +1 -0
  65. package/dist/components/combobox/highlightLabel.js +18 -0
  66. package/dist/components/combobox/highlightLabel.js.map +1 -0
  67. package/dist/components/combobox/normaliseComboboxQuery.d.ts +2 -0
  68. package/dist/components/combobox/normaliseComboboxQuery.d.ts.map +1 -0
  69. package/dist/components/combobox/normaliseComboboxQuery.js +2 -0
  70. package/dist/components/combobox/normaliseComboboxQuery.js.map +1 -0
  71. package/dist/components/combobox/types.d.ts +46 -0
  72. package/dist/components/combobox/types.d.ts.map +1 -0
  73. package/dist/components/combobox/types.js +2 -0
  74. package/dist/components/combobox/types.js.map +1 -0
  75. package/dist/components/combobox/useChipSelection.d.ts +11 -0
  76. package/dist/components/combobox/useChipSelection.d.ts.map +1 -0
  77. package/dist/components/combobox/useChipSelection.js +35 -0
  78. package/dist/components/combobox/useChipSelection.js.map +1 -0
  79. package/dist/components/combobox/useComboboxChipKeyboard.d.ts +3 -0
  80. package/dist/components/combobox/useComboboxChipKeyboard.d.ts.map +1 -0
  81. package/dist/components/combobox/useComboboxChipKeyboard.js +103 -0
  82. package/dist/components/combobox/useComboboxChipKeyboard.js.map +1 -0
  83. package/dist/components/combobox/useComboboxChipKeyboard.test.d.ts +2 -0
  84. package/dist/components/combobox/useComboboxChipKeyboard.test.d.ts.map +1 -0
  85. package/dist/components/combobox/useComboboxChipKeyboard.test.js +116 -0
  86. package/dist/components/combobox/useComboboxChipKeyboard.test.js.map +1 -0
  87. package/dist/components/combobox/useComboboxKeyboard.d.ts +4 -0
  88. package/dist/components/combobox/useComboboxKeyboard.d.ts.map +1 -0
  89. package/dist/components/combobox/useComboboxKeyboard.js +68 -0
  90. package/dist/components/combobox/useComboboxKeyboard.js.map +1 -0
  91. package/dist/components/combobox/useComboboxListboxDom.d.ts +11 -0
  92. package/dist/components/combobox/useComboboxListboxDom.d.ts.map +1 -0
  93. package/dist/components/combobox/useComboboxListboxDom.js +15 -0
  94. package/dist/components/combobox/useComboboxListboxDom.js.map +1 -0
  95. package/dist/components/combobox/useComboboxListboxKeyboard.d.ts +3 -0
  96. package/dist/components/combobox/useComboboxListboxKeyboard.d.ts.map +1 -0
  97. package/dist/components/combobox/useComboboxListboxKeyboard.js +143 -0
  98. package/dist/components/combobox/useComboboxListboxKeyboard.js.map +1 -0
  99. package/dist/components/combobox/useComboboxListboxKeyboard.test.d.ts +2 -0
  100. package/dist/components/combobox/useComboboxListboxKeyboard.test.d.ts.map +1 -0
  101. package/dist/components/combobox/useComboboxListboxKeyboard.test.js +152 -0
  102. package/dist/components/combobox/useComboboxListboxKeyboard.test.js.map +1 -0
  103. package/dist/components/combobox/useComboboxPopoverBehavior.d.ts +38 -0
  104. package/dist/components/combobox/useComboboxPopoverBehavior.d.ts.map +1 -0
  105. package/dist/components/combobox/useComboboxPopoverBehavior.js +104 -0
  106. package/dist/components/combobox/useComboboxPopoverBehavior.js.map +1 -0
  107. package/dist/components/combobox/useComboboxState.d.ts +27 -0
  108. package/dist/components/combobox/useComboboxState.d.ts.map +1 -0
  109. package/dist/components/combobox/useComboboxState.js +122 -0
  110. package/dist/components/combobox/useComboboxState.js.map +1 -0
  111. package/dist/components/combobox/useElementWidth.d.ts +2 -0
  112. package/dist/components/combobox/useElementWidth.d.ts.map +1 -0
  113. package/dist/components/combobox/useElementWidth.js +31 -0
  114. package/dist/components/combobox/useElementWidth.js.map +1 -0
  115. package/dist/components/combobox/useVisibleChips.d.ts +21 -0
  116. package/dist/components/combobox/useVisibleChips.d.ts.map +1 -0
  117. package/dist/components/combobox/useVisibleChips.js +59 -0
  118. package/dist/components/combobox/useVisibleChips.js.map +1 -0
  119. package/dist/components/combobox/useVisibleChips.test.d.ts +2 -0
  120. package/dist/components/combobox/useVisibleChips.test.d.ts.map +1 -0
  121. package/dist/components/combobox/useVisibleChips.test.js +81 -0
  122. package/dist/components/combobox/useVisibleChips.test.js.map +1 -0
  123. package/dist/components/dot/Dot.d.ts +8 -0
  124. package/dist/components/dot/Dot.d.ts.map +1 -0
  125. package/dist/components/dot/Dot.js +6 -0
  126. package/dist/components/dot/Dot.js.map +1 -0
  127. package/dist/components/dot/Dot.stories.d.ts +15 -0
  128. package/dist/components/dot/Dot.stories.d.ts.map +1 -0
  129. package/dist/components/dot/Dot.stories.js +25 -0
  130. package/dist/components/dot/Dot.stories.js.map +1 -0
  131. package/dist/components/dot/Dot.test.d.ts +2 -0
  132. package/dist/components/dot/Dot.test.d.ts.map +1 -0
  133. package/dist/components/dot/Dot.test.js +19 -0
  134. package/dist/components/dot/Dot.test.js.map +1 -0
  135. package/dist/components/formField/FormField.d.ts +8 -4
  136. package/dist/components/formField/FormField.d.ts.map +1 -1
  137. package/dist/components/formField/FormField.js +7 -6
  138. package/dist/components/formField/FormField.js.map +1 -1
  139. package/dist/components/formField/FormField.stories.d.ts +1 -0
  140. package/dist/components/formField/FormField.stories.d.ts.map +1 -1
  141. package/dist/components/formField/FormField.stories.js +13 -1
  142. package/dist/components/formField/FormField.stories.js.map +1 -1
  143. package/dist/components/formField/FormField.test.js +10 -0
  144. package/dist/components/formField/FormField.test.js.map +1 -1
  145. package/dist/components/icon/allowedIcons.d.ts +1 -0
  146. package/dist/components/icon/allowedIcons.d.ts.map +1 -1
  147. package/dist/components/icon/allowedIcons.js +2 -1
  148. package/dist/components/icon/allowedIcons.js.map +1 -1
  149. package/dist/components/progress/Progress.stories.d.ts +49 -49
  150. package/dist/components/singleUser/SingleUser.d.ts +15 -0
  151. package/dist/components/singleUser/SingleUser.d.ts.map +1 -0
  152. package/dist/components/singleUser/SingleUser.js +9 -0
  153. package/dist/components/singleUser/SingleUser.js.map +1 -0
  154. package/dist/components/singleUser/SingleUser.stories.d.ts +11 -0
  155. package/dist/components/singleUser/SingleUser.stories.d.ts.map +1 -0
  156. package/dist/components/singleUser/SingleUser.stories.js +52 -0
  157. package/dist/components/singleUser/SingleUser.stories.js.map +1 -0
  158. package/dist/components/singleUser/SingleUser.test.d.ts +2 -0
  159. package/dist/components/singleUser/SingleUser.test.d.ts.map +1 -0
  160. package/dist/components/singleUser/SingleUser.test.js +30 -0
  161. package/dist/components/singleUser/SingleUser.test.js.map +1 -0
  162. package/dist/components/tabs/TabsItem.stories.d.ts +2 -2
  163. package/dist/components/tag/Tag.d.ts +9 -6
  164. package/dist/components/tag/Tag.d.ts.map +1 -1
  165. package/dist/components/tag/Tag.js +8 -2
  166. package/dist/components/tag/Tag.js.map +1 -1
  167. package/dist/components/tag/Tag.stories.d.ts +11 -6
  168. package/dist/components/tag/Tag.stories.d.ts.map +1 -1
  169. package/dist/components/tag/Tag.stories.js +68 -4
  170. package/dist/components/tag/Tag.stories.js.map +1 -1
  171. package/dist/components/tag/Tag.test.js +86 -50
  172. package/dist/components/tag/Tag.test.js.map +1 -1
  173. package/dist/components/toggle/Toggle.d.ts +3 -0
  174. package/dist/components/toggle/Toggle.d.ts.map +1 -0
  175. package/dist/components/toggle/Toggle.js +8 -0
  176. package/dist/components/toggle/Toggle.js.map +1 -0
  177. package/dist/components/toggle/Toggle.stories.d.ts +97 -0
  178. package/dist/components/toggle/Toggle.stories.d.ts.map +1 -0
  179. package/dist/components/toggle/Toggle.stories.js +186 -0
  180. package/dist/components/toggle/Toggle.stories.js.map +1 -0
  181. package/dist/components/toggle/Toggle.test.d.ts +2 -0
  182. package/dist/components/toggle/Toggle.test.d.ts.map +1 -0
  183. package/dist/components/toggle/Toggle.test.js +58 -0
  184. package/dist/components/toggle/Toggle.test.js.map +1 -0
  185. package/dist/index.css +656 -25
  186. package/dist/index.css.map +1 -1
  187. package/dist/index.d.ts +34 -25
  188. package/dist/index.d.ts.map +1 -1
  189. package/dist/index.js +30 -25
  190. package/dist/index.js.map +1 -1
  191. package/dist/mocks/comboboxStoryOptions.d.ts +5 -0
  192. package/dist/mocks/comboboxStoryOptions.d.ts.map +1 -0
  193. package/dist/mocks/comboboxStoryOptions.js +22 -0
  194. package/dist/mocks/comboboxStoryOptions.js.map +1 -0
  195. package/dist/utils/isSelectAllChord.d.ts +5 -0
  196. package/dist/utils/isSelectAllChord.d.ts.map +1 -0
  197. package/dist/utils/isSelectAllChord.js +7 -0
  198. package/dist/utils/isSelectAllChord.js.map +1 -0
  199. package/dist/utils/isSelectAllChord.test.d.ts +2 -0
  200. package/dist/utils/isSelectAllChord.test.d.ts.map +1 -0
  201. package/dist/utils/isSelectAllChord.test.js +19 -0
  202. package/dist/utils/isSelectAllChord.test.js.map +1 -0
  203. package/dist/utils/nextCircularIndex.d.ts +3 -0
  204. package/dist/utils/nextCircularIndex.d.ts.map +1 -0
  205. package/dist/utils/nextCircularIndex.js +10 -0
  206. package/dist/utils/nextCircularIndex.js.map +1 -0
  207. package/dist/utils/nextCircularIndex.test.d.ts +2 -0
  208. package/dist/utils/nextCircularIndex.test.d.ts.map +1 -0
  209. package/dist/utils/nextCircularIndex.test.js +23 -0
  210. package/dist/utils/nextCircularIndex.test.js.map +1 -0
  211. package/dist/utils/scrollElementIntoViewById.d.ts +2 -0
  212. package/dist/utils/scrollElementIntoViewById.d.ts.map +1 -0
  213. package/dist/utils/scrollElementIntoViewById.js +16 -0
  214. package/dist/utils/scrollElementIntoViewById.js.map +1 -0
  215. package/dist/utils/scrollElementIntoViewById.test.d.ts +2 -0
  216. package/dist/utils/scrollElementIntoViewById.test.d.ts.map +1 -0
  217. package/dist/utils/scrollElementIntoViewById.test.js +31 -0
  218. package/dist/utils/scrollElementIntoViewById.test.js.map +1 -0
  219. package/package.json +1 -1
  220. package/src/components/avatar/Avatar.stories.tsx +8 -0
  221. package/src/components/avatar/Avatar.tsx +3 -3
  222. package/src/components/badge/Badge.stories.tsx +74 -0
  223. package/src/components/badge/Badge.test.tsx +28 -0
  224. package/src/components/badge/Badge.tsx +35 -0
  225. package/src/components/badge/badge.scss +86 -0
  226. package/src/components/card/Card.tsx +1 -1
  227. package/src/components/combobox/Combobox.stories.tsx +340 -0
  228. package/src/components/combobox/Combobox.test.tsx +1160 -0
  229. package/src/components/combobox/Combobox.tsx +434 -0
  230. package/src/components/combobox/ComboboxButtonTrigger.tsx +195 -0
  231. package/src/components/combobox/ComboboxListbox.tsx +224 -0
  232. package/src/components/combobox/ComboboxOptionRow.tsx +128 -0
  233. package/src/components/combobox/ComboboxTrigger.tsx +134 -0
  234. package/src/components/combobox/buildListboxDisplayOptions.test.ts +24 -0
  235. package/src/components/combobox/buildListboxDisplayOptions.ts +12 -0
  236. package/src/components/combobox/combobox.scss +390 -0
  237. package/src/components/combobox/comboboxKeyboardTypes.ts +45 -0
  238. package/src/components/combobox/highlightLabel.tsx +42 -0
  239. package/src/components/combobox/normaliseComboboxQuery.ts +1 -0
  240. package/src/components/combobox/types.ts +53 -0
  241. package/src/components/combobox/useChipSelection.ts +53 -0
  242. package/src/components/combobox/useComboboxChipKeyboard.test.tsx +141 -0
  243. package/src/components/combobox/useComboboxChipKeyboard.ts +121 -0
  244. package/src/components/combobox/useComboboxKeyboard.ts +108 -0
  245. package/src/components/combobox/useComboboxListboxDom.ts +36 -0
  246. package/src/components/combobox/useComboboxListboxKeyboard.test.tsx +186 -0
  247. package/src/components/combobox/useComboboxListboxKeyboard.ts +172 -0
  248. package/src/components/combobox/useComboboxPopoverBehavior.ts +179 -0
  249. package/src/components/combobox/useComboboxState.ts +232 -0
  250. package/src/components/combobox/useElementWidth.ts +40 -0
  251. package/src/components/combobox/useVisibleChips.test.tsx +91 -0
  252. package/src/components/combobox/useVisibleChips.ts +100 -0
  253. package/src/components/dot/Dot.stories.tsx +41 -0
  254. package/src/components/dot/Dot.test.tsx +21 -0
  255. package/src/components/dot/Dot.tsx +18 -0
  256. package/src/components/dot/dot.scss +35 -0
  257. package/src/components/formField/FormField.stories.tsx +30 -1
  258. package/src/components/formField/FormField.test.tsx +20 -0
  259. package/src/components/formField/FormField.tsx +11 -5
  260. package/src/components/formField/inputs/number/numberInput.scss +12 -4
  261. package/src/components/icon/allowedIcons.tsx +2 -0
  262. package/src/components/pill/pill.scss +4 -6
  263. package/src/components/singleUser/SingleUser.stories.tsx +63 -0
  264. package/src/components/singleUser/SingleUser.test.tsx +61 -0
  265. package/src/components/singleUser/SingleUser.tsx +45 -0
  266. package/src/components/singleUser/singleUser.scss +14 -0
  267. package/src/components/tag/Tag.stories.tsx +88 -6
  268. package/src/components/tag/Tag.test.tsx +110 -44
  269. package/src/components/tag/Tag.tsx +38 -14
  270. package/src/components/tag/tag.scss +45 -30
  271. package/src/components/toggle/Toggle.stories.tsx +239 -0
  272. package/src/components/toggle/Toggle.test.tsx +66 -0
  273. package/src/components/toggle/Toggle.tsx +12 -0
  274. package/src/components/toggle/toggle.scss +126 -0
  275. package/src/index.scss +5 -0
  276. package/src/index.ts +47 -31
  277. package/src/mocks/comboboxStoryOptions.ts +25 -0
  278. package/src/tokens.scss +33 -4
  279. package/src/utils/isSelectAllChord.test.ts +24 -0
  280. package/src/utils/isSelectAllChord.ts +8 -0
  281. package/src/utils/nextCircularIndex.test.ts +26 -0
  282. package/src/utils/nextCircularIndex.ts +15 -0
  283. package/src/utils/scrollElementIntoViewById.test.ts +38 -0
  284. package/src/utils/scrollElementIntoViewById.ts +20 -0
  285. package/tokens/json/Arbor.json +3828 -3704
@@ -0,0 +1,390 @@
1
+ .ds-combobox {
2
+ position: relative;
3
+ width: 100%;
4
+ }
5
+
6
+ // Trigger area
7
+ .ds-combobox__trigger {
8
+ display: flex;
9
+ align-items: center;
10
+ gap: var(--spacing-small);
11
+ min-height: var(--form-field-text-medium-height);
12
+ padding: var(--spacing-xsmall) var(--spacing-small);
13
+ border: var(--border-weight) solid var(--form-field-combobox-default-color-border);
14
+ border-radius: var(--form-field-radius);
15
+ background-color: var(--form-field-combobox-default-color-background);
16
+ color: var(--form-field-combobox-default-color-text);
17
+ cursor: text;
18
+ transition: border-color 0.2s, box-shadow 0.2s, background-color 0.2s;
19
+ box-sizing: border-box;
20
+ font-style: normal;
21
+ line-height: 150%;
22
+
23
+ &:hover:not(.ds-combobox__trigger--disabled) {
24
+ border-color: var(--form-field-combobox-hover-color-border);
25
+ background-color: var(--form-field-combobox-hover-color-background);
26
+ }
27
+
28
+ &:focus-within:not(.ds-combobox__trigger--disabled) {
29
+ border-color: var(--form-field-combobox-focus-color-border);
30
+ background-color: var(--form-field-combobox-focus-color-background);
31
+ outline: var(--focus-border) solid var(--form-field-combobox-focus-color-border);
32
+ }
33
+
34
+ &--error {
35
+ border-color: var(--form-field-combobox-error-color-border);
36
+
37
+ &:focus-within {
38
+ border-color: var(--form-field-combobox-error-color-border);
39
+ box-shadow: 0 0 0 var(--focus-border) var(--form-field-combobox-error-color-border);
40
+ }
41
+ }
42
+
43
+ &--disabled {
44
+ background-color: var(--form-field-combobox-disabled-color-background);
45
+ border-color: var(--form-field-combobox-disabled-color-border);
46
+ color: var(--form-field-combobox-disabled-color-text);
47
+ cursor: not-allowed;
48
+ }
49
+
50
+ &--button {
51
+ cursor: pointer;
52
+ }
53
+ }
54
+
55
+ .ds-combobox__chips-and-input {
56
+ display: flex;
57
+ flex-wrap: wrap;
58
+ align-items: center;
59
+ gap: var(--spacing-xsmall);
60
+ flex: 1;
61
+ min-width: 0;
62
+ }
63
+
64
+ .ds-combobox__button-content {
65
+ display: flex;
66
+ align-items: center;
67
+ gap: var(--spacing-xsmall);
68
+ flex: 1;
69
+ min-width: 0;
70
+ }
71
+
72
+ .ds-combobox__button-tags-viewport {
73
+ flex: 1;
74
+ min-width: 0;
75
+ overflow: hidden;
76
+ }
77
+
78
+ .ds-combobox__button-tags-track {
79
+ display: inline-flex;
80
+ width: auto;
81
+ flex-wrap: nowrap;
82
+ align-items: center;
83
+ gap: var(--spacing-xsmall);
84
+ }
85
+
86
+ .ds-combobox__button-placeholder {
87
+ color: var(--form-field-combobox-placeholder-color-text);
88
+ white-space: nowrap;
89
+ }
90
+
91
+ .ds-combobox__button-ellipsis {
92
+ flex-shrink: 0;
93
+ font-size: var(--font-size-medium);
94
+ margin-left: var(--spacing-xsmall);
95
+ }
96
+
97
+ .ds-combobox__measure {
98
+ position: absolute;
99
+ visibility: hidden;
100
+ pointer-events: none;
101
+ left: -9999px;
102
+ top: -9999px;
103
+ white-space: nowrap;
104
+ width: max-content;
105
+ height: 0;
106
+ overflow: hidden;
107
+ }
108
+
109
+ // Input
110
+ .ds-combobox__input {
111
+ flex: 1;
112
+ min-width: 80px;
113
+ border: none;
114
+ outline: none;
115
+ background: transparent;
116
+ color: inherit;
117
+ font: inherit;
118
+ padding: 0;
119
+ line-height: var(--line-height-default);
120
+
121
+ &::placeholder {
122
+ color: var(--form-field-combobox-placeholder-color-text);
123
+ }
124
+
125
+ .ds-combobox__trigger--disabled & {
126
+ cursor: not-allowed;
127
+ }
128
+ }
129
+
130
+ // Chevron
131
+ .ds-combobox__chevron {
132
+ flex-shrink: 0;
133
+ display: flex;
134
+ align-items: center;
135
+ justify-content: center;
136
+ border: none;
137
+ background: transparent;
138
+ padding: 0;
139
+ color: inherit;
140
+ cursor: pointer;
141
+
142
+ .ds-combobox__trigger--disabled & {
143
+ cursor: not-allowed;
144
+ }
145
+ }
146
+
147
+ // Popover
148
+ .ds-combobox__popover {
149
+ min-width: var(--radix-popper-anchor-width);
150
+
151
+ &:focus {
152
+ outline: none;
153
+ }
154
+ }
155
+
156
+ // Listbox
157
+ .ds-combobox__listbox {
158
+ list-style: none;
159
+ margin: 0;
160
+ padding: 0;
161
+ max-height: min(
162
+ var(--form-field-combobox-listbox-max-height),
163
+ var(--radix-popper-available-height, 150px)
164
+ );
165
+ overflow-y: auto;
166
+ }
167
+
168
+ .ds-combobox__listbox-search-row {
169
+ list-style: none;
170
+ background: var(--form-dropdown-color-background);
171
+ margin-bottom: var(--spacing-small);
172
+ }
173
+
174
+ .ds-combobox__listbox-search-input-wrap {
175
+ display: flex;
176
+ align-items: center;
177
+ gap: var(--spacing-xsmall);
178
+ width: 100%;
179
+ border: var(--border-weight) solid var(--form-field-combobox-default-color-border);
180
+ border-radius: var(--border-radius-round);
181
+ padding: var(--spacing-xsmall) var(--spacing-small);
182
+ box-sizing: border-box;
183
+ }
184
+
185
+ .ds-combobox__input--in-listbox {
186
+ min-width: 0;
187
+ width: 100%;
188
+ }
189
+
190
+ // Loading row uses the same spacing as one option row.
191
+ .ds-combobox__loading-row {
192
+ list-style: none;
193
+ display: flex;
194
+ align-items: center;
195
+ justify-content: center;
196
+ min-height: calc(2 * var(--form-dropdown-form-drop-item-spacing-vertical) + 1.5em);
197
+ padding: var(--form-dropdown-form-drop-item-spacing-vertical) var(--form-dropdown-form-drop-item-spacing-horizontal);
198
+ }
199
+
200
+ .ds-combobox__loading-status {
201
+ display: flex;
202
+ align-items: center;
203
+ justify-content: center;
204
+ color: var(--form-dropdown-form-drop-item-default-color-text);
205
+ }
206
+
207
+ .ds-combobox__loading-spinner {
208
+ display: inline-flex;
209
+ animation: ds-combobox-loader-spin 0.8s linear infinite;
210
+ }
211
+
212
+ @keyframes ds-combobox-loader-spin {
213
+ from {
214
+ transform: rotate(0deg);
215
+ }
216
+
217
+ to {
218
+ transform: rotate(360deg);
219
+ }
220
+ }
221
+
222
+ @mixin ds-combobox-option-surface {
223
+ display: flex;
224
+ align-items: center;
225
+ gap: var(--form-dropdown-form-drop-item-spacing-gap-horizontal);
226
+ padding: var(--form-dropdown-form-drop-item-spacing-vertical) var(--form-dropdown-form-drop-item-spacing-horizontal);
227
+ border-radius: var(--form-dropdown-form-drop-item-radius, 8px);
228
+ background: var(--form-dropdown-form-drop-item-default-color-background);
229
+ color: var(--form-dropdown-form-drop-item-default-color-text);
230
+ cursor: pointer;
231
+ }
232
+
233
+ .ds-combobox__option-row {
234
+ display: flex;
235
+ align-items: center;
236
+ gap: var(--spacing-xsmall);
237
+ list-style: none;
238
+
239
+ > .ds-combobox__option {
240
+ @include ds-combobox-option-surface;
241
+
242
+ flex: 1;
243
+ min-width: 0;
244
+ }
245
+
246
+ &--highlighted > .ds-combobox__option {
247
+ background: var(--form-dropdown-form-drop-item-hover-color-background);
248
+ outline: none;
249
+ }
250
+
251
+ &--selected > .ds-combobox__option {
252
+ background: var(--form-dropdown-form-drop-item-active-color-background);
253
+ color: var(--form-dropdown-form-drop-item-active-color-text);
254
+ }
255
+
256
+ &--disabled > .ds-combobox__option {
257
+ pointer-events: none;
258
+ opacity: 0.5;
259
+ }
260
+ }
261
+
262
+ // Ensures selected options are distinguishable when 'focused'.
263
+ .ds-combobox__option-row--selected.ds-combobox__option-row--highlighted > .ds-combobox__option {
264
+ background: var(--form-dropdown-form-drop-item-hover-color-background);
265
+ color: var(--form-dropdown-form-drop-item-default-color-text);
266
+ }
267
+
268
+ // Standalone option (e.g. create row) — full width on the <li>
269
+ li.ds-combobox__option {
270
+ @include ds-combobox-option-surface;
271
+
272
+ list-style: none;
273
+
274
+ &--highlighted {
275
+ background: var(--form-dropdown-form-drop-item-hover-color-background);
276
+ outline: none;
277
+ }
278
+
279
+ &--selected {
280
+ background: var(--form-dropdown-form-drop-item-active-color-background);
281
+ color: var(--form-dropdown-form-drop-item-active-color-text);
282
+ }
283
+
284
+ &--disabled {
285
+ pointer-events: none;
286
+ opacity: 0.5;
287
+ }
288
+ }
289
+
290
+ .ds-combobox__option--selected.ds-combobox__option--highlighted {
291
+ background: var(--form-dropdown-form-drop-item-hover-color-background);
292
+ color: var(--form-dropdown-form-drop-item-default-color-text);
293
+ }
294
+
295
+
296
+ .ds-combobox__option-label {
297
+ flex: 1;
298
+ min-width: 0;
299
+ }
300
+
301
+ .ds-combobox__option-match {
302
+ background: var(--color-semantic-caution-100);
303
+ color: inherit;
304
+ font-weight: var(--font-weight-semi-bold);
305
+ padding: 0;
306
+ }
307
+
308
+ .ds-combobox__option-check {
309
+ margin-left: auto;
310
+ display: flex;
311
+ align-items: center;
312
+ }
313
+
314
+ .ds-combobox__option-delete {
315
+ flex-shrink: 0;
316
+ display: flex;
317
+ align-items: center;
318
+ justify-content: center;
319
+ border: none;
320
+ background: transparent;
321
+ padding: var(--spacing-xsmall);
322
+ cursor: pointer;
323
+ color: var(--form-dropdown-form-drop-item-default-color-text);
324
+ opacity: 0.75;
325
+ border-radius: var(--form-dropdown-form-drop-item-radius, 8px);
326
+ transition: opacity 0.15s;
327
+ }
328
+
329
+ .ds-combobox__option-delete:hover {
330
+ opacity: 1;
331
+ outline: none;
332
+
333
+ }
334
+
335
+ .ds-combobox__option-delete:focus-visible {
336
+ opacity: 1;
337
+ outline: var(--focus-border) solid var(--form-field-combobox-focus-color-border);
338
+ }
339
+
340
+
341
+ // Create row
342
+ .ds-combobox__create-row {
343
+ font-style: italic;
344
+ }
345
+
346
+ // Groups
347
+ .ds-combobox__group {
348
+ list-style: none;
349
+ }
350
+
351
+ .ds-combobox__group-header {
352
+ padding: var(--form-dropdown-form-drop-item-spacing-vertical) var(--form-dropdown-form-drop-item-spacing-horizontal);
353
+ font-weight: var(--font-weight-semi-bold);
354
+ font-size: var(--font-size-xs);
355
+ color: var(--search-list-color-header);
356
+ text-transform: uppercase;
357
+ letter-spacing: 0.04em;
358
+ }
359
+
360
+ .ds-combobox__group-list {
361
+ list-style: none;
362
+ margin: 0;
363
+ padding: 0;
364
+ }
365
+
366
+ // Clear all
367
+ .ds-combobox__clear-all-wrapper {
368
+ display: flex;
369
+ justify-content: flex-end;
370
+ margin-top: var(--spacing-xsmall);
371
+ }
372
+
373
+ .ds-combobox__clear-all {
374
+ border: none;
375
+ background: transparent;
376
+ color: var(--form-field-combobox-help-text-default-color-text);
377
+ cursor: pointer;
378
+ font-size: var(--font-size-sm);
379
+ text-decoration: underline;
380
+ padding: 0;
381
+
382
+ &:hover {
383
+ color: var(--form-field-combobox-help-text-hover-color-text);
384
+ }
385
+
386
+ &:disabled {
387
+ cursor: not-allowed;
388
+ opacity: 0.5;
389
+ }
390
+ }
@@ -0,0 +1,45 @@
1
+ import type { ComboboxOption } from './types';
2
+
3
+ export type UseComboboxChipKeyboardParams = {
4
+ inputRef: React.RefObject<HTMLInputElement | null>;
5
+ clearAll: () => void;
6
+ clearChipSelection: () => void;
7
+ exitChipNav: () => void;
8
+ focusedChipIndex: number | null;
9
+ removeValue: (optionValue: string) => void;
10
+ selectedChipValues: string[];
11
+ selectedValues: string[];
12
+ setFocusedChipIndex: React.Dispatch<React.SetStateAction<number | null>>;
13
+ };
14
+
15
+ export type UseComboboxListboxKeyboardParams = {
16
+ allowCreate: boolean;
17
+ clearChipSelection: () => void;
18
+ exitChipNav: () => void;
19
+ focusDeleteButtonForHighlighted?: () => boolean;
20
+ listboxOptions: ComboboxOption[];
21
+ focusedChipIndex: number | null;
22
+ handleCreate: () => void;
23
+ highlightIndex: number;
24
+ isOpen: boolean;
25
+ mergedOptions: ComboboxOption[];
26
+ openPopover: () => void;
27
+ query: string;
28
+ removeValue: (optionValue: string) => void;
29
+ scrollHighlightedIntoView: (index: number) => void;
30
+ selectOption: (optionValue: string) => void;
31
+ selectedChipValues: string[];
32
+ selectedValues: string[];
33
+ setHighlightIndex: React.Dispatch<React.SetStateAction<number>>;
34
+ setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
35
+ setQuery: React.Dispatch<React.SetStateAction<string>>;
36
+ showCreateRow: boolean;
37
+ showListboxLoading: boolean;
38
+ totalItems: number;
39
+ };
40
+
41
+ export type UseComboboxKeyboardParams = UseComboboxChipKeyboardParams
42
+ & UseComboboxListboxKeyboardParams
43
+ & {
44
+ setSelectedChipValues: React.Dispatch<React.SetStateAction<string[]>>;
45
+ };
@@ -0,0 +1,42 @@
1
+ import type { ComboboxSearchType } from './types';
2
+
3
+ type HighlightLabelOptions = {
4
+ label: string;
5
+ query: string;
6
+ searchType: ComboboxSearchType;
7
+ highlightStringMatches: boolean;
8
+ };
9
+
10
+ export const highlightLabel = ({
11
+ label,
12
+ query,
13
+ searchType,
14
+ highlightStringMatches,
15
+ }: HighlightLabelOptions): React.ReactNode => {
16
+ const trimmedQuery = query.trim();
17
+ if (!highlightStringMatches || !trimmedQuery || typeof searchType === 'function') {
18
+ return label;
19
+ }
20
+
21
+ const lowerLabel = label.toLowerCase();
22
+ const lowerQuery = trimmedQuery.toLowerCase();
23
+ const matchStart
24
+ = searchType === 'prefix'
25
+ ? (lowerLabel.startsWith(lowerQuery) ? 0 : -1)
26
+ : lowerLabel.indexOf(lowerQuery);
27
+
28
+ if (matchStart === -1) {
29
+ return label;
30
+ }
31
+
32
+ const matchEnd = matchStart + trimmedQuery.length;
33
+ return (
34
+ <>
35
+ {matchStart > 0 && label.slice(0, matchStart)}
36
+ <mark className="ds-combobox__option-match">
37
+ {label.slice(matchStart, matchEnd)}
38
+ </mark>
39
+ {matchEnd < label.length && label.slice(matchEnd)}
40
+ </>
41
+ );
42
+ };
@@ -0,0 +1 @@
1
+ export const normaliseComboboxQuery = (value: string) => value.trim().toLowerCase();
@@ -0,0 +1,53 @@
1
+ import type { IconName } from 'Components/icon/allowedIcons';
2
+ import type React from 'react';
3
+
4
+ /** Matches DOM / ARIA `aria-invalid` (boolean and grammar/spelling, etc.). */
5
+ export type ComboboxAriaInvalid = React.AriaAttributes['aria-invalid'];
6
+
7
+ export type ComboboxOption = {
8
+ value: string;
9
+ label: string;
10
+ tagLabel?: string;
11
+ iconName?: IconName;
12
+ disabled?: boolean;
13
+ group?: string;
14
+ };
15
+
16
+ export type ComboboxCreateResult = string | ComboboxOption | void;
17
+ export type ComboboxSearchFn = (option: ComboboxOption, query: string) => boolean;
18
+ export type ComboboxSearchType = 'prefix' | 'substring' | ComboboxSearchFn;
19
+
20
+ export type ComboboxProps = {
21
+ 'options': ComboboxOption[];
22
+ 'multiple'?: boolean;
23
+ 'value'?: string[];
24
+ 'defaultValue'?: string[];
25
+ 'onValueChange'?: (values: string[]) => void;
26
+
27
+ 'onSearch'?: (query: string) => void;
28
+ 'searchType'?: ComboboxSearchType;
29
+ 'highlightStringMatches'?: boolean;
30
+
31
+ 'allowCreate'?: boolean;
32
+ 'onCreateNew'?: (inputValue: string) => ComboboxCreateResult;
33
+ 'onDeleteCreated'?: (value: string) => void;
34
+
35
+ 'placeholder'?: string;
36
+ 'disabled'?: boolean;
37
+ 'dropdownOnFocus'?: boolean;
38
+ 'triggerVariant'?: 'input' | 'button';
39
+ 'showDropdownTrigger'?: boolean;
40
+ 'showSelectionCountBadge'?: boolean;
41
+ 'selectionCountA11yLabel'?: string | ((count: number) => string);
42
+ 'loading'?: boolean;
43
+ 'hasError'?: boolean;
44
+ 'showClearAll'?: boolean;
45
+ 'clearAllLabel'?: string;
46
+ 'renderOption'?: (option: ComboboxOption, selected: boolean) => React.ReactNode;
47
+ 'getTagLabel'?: (option: ComboboxOption) => string;
48
+
49
+ 'id'?: string;
50
+ 'aria-describedby'?: string;
51
+ 'aria-invalid'?: ComboboxAriaInvalid;
52
+ 'aria-label'?: string;
53
+ };
@@ -0,0 +1,53 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react';
2
+
3
+ export type UseChipSelectionReturn = {
4
+ selectedChipValues: string[];
5
+ selectedChipValuesSet: Set<string>;
6
+ setSelectedChipValues: React.Dispatch<React.SetStateAction<string[]>>;
7
+ clearChipSelection: () => void;
8
+ focusedChipIndex: number | null;
9
+ setFocusedChipIndex: React.Dispatch<React.SetStateAction<number | null>>;
10
+ exitChipNav: () => void;
11
+ };
12
+
13
+ export const useChipSelection = (selectedValues: string[]): UseChipSelectionReturn => {
14
+ const [selectedChipValues, setSelectedChipValues] = useState<string[]>([]);
15
+ const [focusedChipIndex, setFocusedChipIndex] = useState<number | null>(null);
16
+
17
+ const selectedChipValuesSet = useMemo(
18
+ () => new Set(selectedChipValues),
19
+ [selectedChipValues],
20
+ );
21
+
22
+ const clearChipSelection = useCallback(() => {
23
+ setSelectedChipValues([]);
24
+ setFocusedChipIndex(null);
25
+ }, []);
26
+
27
+ const exitChipNav = useCallback(() => {
28
+ setFocusedChipIndex(null);
29
+ }, []);
30
+
31
+ useEffect(() => {
32
+ setSelectedChipValues((prev) => {
33
+ if (prev.length === 0) return prev;
34
+ return prev.filter(value => selectedValues.includes(value));
35
+ });
36
+ }, [selectedValues]);
37
+
38
+ useEffect(() => {
39
+ if (focusedChipIndex !== null && focusedChipIndex >= selectedValues.length) {
40
+ setFocusedChipIndex(selectedValues.length > 0 ? selectedValues.length - 1 : null);
41
+ }
42
+ }, [selectedValues.length, focusedChipIndex]);
43
+
44
+ return {
45
+ selectedChipValues,
46
+ selectedChipValuesSet,
47
+ setSelectedChipValues,
48
+ clearChipSelection,
49
+ focusedChipIndex,
50
+ setFocusedChipIndex,
51
+ exitChipNav,
52
+ };
53
+ };