@navikt/ds-react 6.6.1 → 6.7.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 (258) hide show
  1. package/cjs/chat/Chat.d.ts +2 -1
  2. package/cjs/chat/Chat.js +2 -1
  3. package/cjs/chat/Chat.js.map +1 -1
  4. package/cjs/date/datepicker/parts/DropdownCaption.js +1 -1
  5. package/cjs/date/datepicker/parts/DropdownCaption.js.map +1 -1
  6. package/cjs/date/monthpicker/MonthCaption.js +1 -1
  7. package/cjs/date/utils/labels.d.ts +2 -2
  8. package/cjs/form/ReadOnlyIcon.d.ts +2 -2
  9. package/cjs/form/combobox/Combobox.js +7 -22
  10. package/cjs/form/combobox/Combobox.js.map +1 -1
  11. package/cjs/form/combobox/ComboboxProvider.js +2 -2
  12. package/cjs/form/combobox/ComboboxProvider.js.map +1 -1
  13. package/cjs/form/combobox/ComboboxWrapper.d.ts +1 -2
  14. package/cjs/form/combobox/ComboboxWrapper.js +4 -2
  15. package/cjs/form/combobox/ComboboxWrapper.js.map +1 -1
  16. package/cjs/form/combobox/FilteredOptions/FilteredOptions.js +4 -4
  17. package/cjs/form/combobox/FilteredOptions/FilteredOptions.js.map +1 -1
  18. package/cjs/form/combobox/FilteredOptions/filteredOptionsContext.d.ts +4 -4
  19. package/cjs/form/combobox/FilteredOptions/filteredOptionsContext.js +13 -15
  20. package/cjs/form/combobox/FilteredOptions/filteredOptionsContext.js.map +1 -1
  21. package/cjs/form/combobox/Input/{inputContext.d.ts → Input.context.d.ts} +7 -5
  22. package/cjs/form/combobox/Input/{inputContext.js → Input.context.js} +22 -22
  23. package/cjs/form/combobox/Input/Input.context.js.map +1 -0
  24. package/cjs/form/combobox/Input/Input.js +2 -2
  25. package/cjs/form/combobox/Input/Input.js.map +1 -1
  26. package/cjs/form/combobox/Input/InputController.d.ts +3 -0
  27. package/cjs/form/combobox/Input/InputController.js +70 -0
  28. package/cjs/form/combobox/Input/InputController.js.map +1 -0
  29. package/cjs/form/combobox/{ToggleListButton.js → Input/ToggleListButton.js} +1 -1
  30. package/cjs/form/combobox/Input/ToggleListButton.js.map +1 -0
  31. package/cjs/form/combobox/SelectedOptions/SelectedOptions.js +2 -2
  32. package/cjs/form/combobox/SelectedOptions/SelectedOptions.js.map +1 -1
  33. package/cjs/form/combobox/SelectedOptions/selectedOptionsContext.d.ts +4 -4
  34. package/cjs/form/combobox/SelectedOptions/selectedOptionsContext.js +7 -13
  35. package/cjs/form/combobox/SelectedOptions/selectedOptionsContext.js.map +1 -1
  36. package/cjs/form/combobox/customOptionsContext.d.ts +4 -4
  37. package/cjs/form/combobox/customOptionsContext.js +10 -13
  38. package/cjs/form/combobox/customOptionsContext.js.map +1 -1
  39. package/cjs/form/combobox/types.d.ts +1 -1
  40. package/cjs/help-text/HelpTextIcon.d.ts +1 -1
  41. package/cjs/index.d.ts +1 -0
  42. package/cjs/index.js +4 -2
  43. package/cjs/index.js.map +1 -1
  44. package/cjs/overlay/dismiss/DismissableLayer.d.ts +70 -0
  45. package/cjs/overlay/dismiss/DismissableLayer.js +253 -0
  46. package/cjs/overlay/dismiss/DismissableLayer.js.map +1 -0
  47. package/cjs/overlay/dismiss/util/dispatchCustomEvent.d.ts +50 -0
  48. package/cjs/overlay/dismiss/util/dispatchCustomEvent.js +65 -0
  49. package/cjs/overlay/dismiss/util/dispatchCustomEvent.js.map +1 -0
  50. package/cjs/overlay/dismiss/util/useEscapeKeydown.d.ts +1 -0
  51. package/cjs/overlay/dismiss/util/useEscapeKeydown.js +19 -0
  52. package/cjs/overlay/dismiss/util/useEscapeKeydown.js.map +1 -0
  53. package/cjs/overlay/dismiss/util/useFocusOutside.d.ts +8 -0
  54. package/cjs/overlay/dismiss/util/useFocusOutside.js +42 -0
  55. package/cjs/overlay/dismiss/util/useFocusOutside.js.map +1 -0
  56. package/cjs/overlay/dismiss/util/usePointerDownOutside.d.ts +10 -0
  57. package/cjs/overlay/dismiss/util/usePointerDownOutside.js +84 -0
  58. package/cjs/overlay/dismiss/util/usePointerDownOutside.js.map +1 -0
  59. package/cjs/overlays/floating/Floating.d.ts +53 -0
  60. package/cjs/overlays/floating/Floating.js +215 -0
  61. package/cjs/overlays/floating/Floating.js.map +1 -0
  62. package/cjs/overlays/floating/Floating.utils.d.ts +18 -0
  63. package/cjs/overlays/floating/Floating.utils.js +52 -0
  64. package/cjs/overlays/floating/Floating.utils.js.map +1 -0
  65. package/cjs/popover/Popover.js +13 -28
  66. package/cjs/popover/Popover.js.map +1 -1
  67. package/cjs/progress-bar/ProgressBar.d.ts +72 -0
  68. package/cjs/progress-bar/ProgressBar.js +86 -0
  69. package/cjs/progress-bar/ProgressBar.js.map +1 -0
  70. package/cjs/progress-bar/index.d.ts +1 -0
  71. package/cjs/progress-bar/index.js +10 -0
  72. package/cjs/progress-bar/index.js.map +1 -0
  73. package/cjs/tabs/Tabs.context.d.ts +7 -3
  74. package/cjs/tabs/Tabs.context.js +1 -0
  75. package/cjs/tabs/Tabs.context.js.map +1 -1
  76. package/cjs/timeline/AxisLabels.d.ts +1 -1
  77. package/cjs/toggle-group/ToggleGroup.context.d.ts +7 -3
  78. package/cjs/toggle-group/ToggleGroup.context.js +1 -0
  79. package/cjs/toggle-group/ToggleGroup.context.js.map +1 -1
  80. package/cjs/typography/BodyLong.d.ts +7 -7
  81. package/cjs/typography/BodyLong.js +5 -5
  82. package/cjs/typography/BodyShort.d.ts +5 -5
  83. package/cjs/typography/BodyShort.js +3 -3
  84. package/cjs/typography/Detail.d.ts +5 -5
  85. package/cjs/typography/Detail.js +3 -3
  86. package/cjs/typography/ErrorMessage.d.ts +5 -5
  87. package/cjs/typography/ErrorMessage.js +3 -3
  88. package/cjs/typography/Heading.d.ts +6 -6
  89. package/cjs/typography/Heading.js +3 -3
  90. package/cjs/typography/Label.d.ts +5 -5
  91. package/cjs/typography/Label.js +3 -3
  92. package/cjs/typography/types.d.ts +3 -3
  93. package/cjs/util/hooks/descendants/useDescendant.d.ts +2 -2
  94. package/cjs/util/hooks/descendants/useDescendant.js +49 -52
  95. package/cjs/util/hooks/descendants/useDescendant.js.map +1 -1
  96. package/cjs/util/types/AsChild.d.ts +14 -0
  97. package/cjs/util/types/AsChild.js +3 -0
  98. package/cjs/util/types/AsChild.js.map +1 -0
  99. package/esm/chat/Chat.d.ts +2 -1
  100. package/esm/chat/Chat.js +1 -0
  101. package/esm/chat/Chat.js.map +1 -1
  102. package/esm/date/datepicker/parts/DropdownCaption.js +1 -1
  103. package/esm/date/datepicker/parts/DropdownCaption.js.map +1 -1
  104. package/esm/date/monthpicker/MonthCaption.js +1 -1
  105. package/esm/date/utils/labels.d.ts +2 -2
  106. package/esm/form/ReadOnlyIcon.d.ts +2 -2
  107. package/esm/form/combobox/Combobox.js +8 -23
  108. package/esm/form/combobox/Combobox.js.map +1 -1
  109. package/esm/form/combobox/ComboboxProvider.js +1 -1
  110. package/esm/form/combobox/ComboboxProvider.js.map +1 -1
  111. package/esm/form/combobox/ComboboxWrapper.d.ts +1 -2
  112. package/esm/form/combobox/ComboboxWrapper.js +4 -2
  113. package/esm/form/combobox/ComboboxWrapper.js.map +1 -1
  114. package/esm/form/combobox/FilteredOptions/FilteredOptions.js +3 -3
  115. package/esm/form/combobox/FilteredOptions/FilteredOptions.js.map +1 -1
  116. package/esm/form/combobox/FilteredOptions/filteredOptionsContext.d.ts +4 -4
  117. package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js +15 -16
  118. package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js.map +1 -1
  119. package/esm/form/combobox/Input/{inputContext.d.ts → Input.context.d.ts} +7 -5
  120. package/esm/form/combobox/Input/{inputContext.js → Input.context.js} +22 -21
  121. package/esm/form/combobox/Input/Input.context.js.map +1 -0
  122. package/esm/form/combobox/Input/Input.js +1 -1
  123. package/esm/form/combobox/Input/Input.js.map +1 -1
  124. package/esm/form/combobox/Input/InputController.d.ts +3 -0
  125. package/esm/form/combobox/Input/InputController.js +41 -0
  126. package/esm/form/combobox/Input/InputController.js.map +1 -0
  127. package/esm/form/combobox/{ToggleListButton.js → Input/ToggleListButton.js} +1 -1
  128. package/esm/form/combobox/Input/ToggleListButton.js.map +1 -0
  129. package/esm/form/combobox/SelectedOptions/SelectedOptions.js +1 -1
  130. package/esm/form/combobox/SelectedOptions/SelectedOptions.js.map +1 -1
  131. package/esm/form/combobox/SelectedOptions/selectedOptionsContext.d.ts +4 -4
  132. package/esm/form/combobox/SelectedOptions/selectedOptionsContext.js +9 -14
  133. package/esm/form/combobox/SelectedOptions/selectedOptionsContext.js.map +1 -1
  134. package/esm/form/combobox/customOptionsContext.d.ts +4 -4
  135. package/esm/form/combobox/customOptionsContext.js +10 -12
  136. package/esm/form/combobox/customOptionsContext.js.map +1 -1
  137. package/esm/form/combobox/types.d.ts +1 -1
  138. package/esm/help-text/HelpTextIcon.d.ts +1 -1
  139. package/esm/index.d.ts +1 -0
  140. package/esm/index.js +1 -0
  141. package/esm/index.js.map +1 -1
  142. package/esm/overlay/dismiss/DismissableLayer.d.ts +70 -0
  143. package/esm/overlay/dismiss/DismissableLayer.js +226 -0
  144. package/esm/overlay/dismiss/DismissableLayer.js.map +1 -0
  145. package/esm/overlay/dismiss/util/dispatchCustomEvent.d.ts +50 -0
  146. package/esm/overlay/dismiss/util/dispatchCustomEvent.js +58 -0
  147. package/esm/overlay/dismiss/util/dispatchCustomEvent.js.map +1 -0
  148. package/esm/overlay/dismiss/util/useEscapeKeydown.d.ts +1 -0
  149. package/esm/overlay/dismiss/util/useEscapeKeydown.js +15 -0
  150. package/esm/overlay/dismiss/util/useEscapeKeydown.js.map +1 -0
  151. package/esm/overlay/dismiss/util/useFocusOutside.d.ts +8 -0
  152. package/esm/overlay/dismiss/util/useFocusOutside.js +38 -0
  153. package/esm/overlay/dismiss/util/useFocusOutside.js.map +1 -0
  154. package/esm/overlay/dismiss/util/usePointerDownOutside.d.ts +10 -0
  155. package/esm/overlay/dismiss/util/usePointerDownOutside.js +80 -0
  156. package/esm/overlay/dismiss/util/usePointerDownOutside.js.map +1 -0
  157. package/esm/overlays/floating/Floating.d.ts +53 -0
  158. package/esm/overlays/floating/Floating.js +188 -0
  159. package/esm/overlays/floating/Floating.js.map +1 -0
  160. package/esm/overlays/floating/Floating.utils.d.ts +18 -0
  161. package/esm/overlays/floating/Floating.utils.js +48 -0
  162. package/esm/overlays/floating/Floating.utils.js.map +1 -0
  163. package/esm/popover/Popover.js +16 -31
  164. package/esm/popover/Popover.js.map +1 -1
  165. package/esm/progress-bar/ProgressBar.d.ts +72 -0
  166. package/esm/progress-bar/ProgressBar.js +57 -0
  167. package/esm/progress-bar/ProgressBar.js.map +1 -0
  168. package/esm/progress-bar/index.d.ts +1 -0
  169. package/esm/progress-bar/index.js +3 -0
  170. package/esm/progress-bar/index.js.map +1 -0
  171. package/esm/tabs/Tabs.context.d.ts +7 -3
  172. package/esm/tabs/Tabs.context.js +1 -0
  173. package/esm/tabs/Tabs.context.js.map +1 -1
  174. package/esm/timeline/AxisLabels.d.ts +1 -1
  175. package/esm/toggle-group/ToggleGroup.context.d.ts +7 -3
  176. package/esm/toggle-group/ToggleGroup.context.js +1 -0
  177. package/esm/toggle-group/ToggleGroup.context.js.map +1 -1
  178. package/esm/typography/BodyLong.d.ts +7 -7
  179. package/esm/typography/BodyLong.js +5 -5
  180. package/esm/typography/BodyShort.d.ts +5 -5
  181. package/esm/typography/BodyShort.js +3 -3
  182. package/esm/typography/Detail.d.ts +5 -5
  183. package/esm/typography/Detail.js +3 -3
  184. package/esm/typography/ErrorMessage.d.ts +5 -5
  185. package/esm/typography/ErrorMessage.js +3 -3
  186. package/esm/typography/Heading.d.ts +6 -6
  187. package/esm/typography/Heading.js +3 -3
  188. package/esm/typography/Label.d.ts +5 -5
  189. package/esm/typography/Label.js +3 -3
  190. package/esm/typography/types.d.ts +3 -3
  191. package/esm/util/hooks/descendants/useDescendant.d.ts +2 -2
  192. package/esm/util/hooks/descendants/useDescendant.js +49 -52
  193. package/esm/util/hooks/descendants/useDescendant.js.map +1 -1
  194. package/esm/util/types/AsChild.d.ts +14 -0
  195. package/esm/util/types/AsChild.js +2 -0
  196. package/esm/util/types/AsChild.js.map +1 -0
  197. package/package.json +16 -5
  198. package/src/chat/Chat.tsx +2 -1
  199. package/src/date/datepicker/parts/DropdownCaption.tsx +5 -1
  200. package/src/date/monthpicker/MonthCaption.tsx +1 -1
  201. package/src/form/combobox/Combobox.tsx +6 -76
  202. package/src/form/combobox/ComboboxProvider.tsx +1 -1
  203. package/src/form/combobox/ComboboxWrapper.tsx +4 -3
  204. package/src/form/combobox/FilteredOptions/FilteredOptions.tsx +3 -3
  205. package/src/form/combobox/FilteredOptions/filteredOptionsContext.tsx +19 -29
  206. package/src/form/combobox/Input/{inputContext.tsx → Input.context.tsx} +30 -33
  207. package/src/form/combobox/Input/Input.tsx +1 -1
  208. package/src/form/combobox/Input/InputController.tsx +102 -0
  209. package/src/form/combobox/{ToggleListButton.tsx → Input/ToggleListButton.tsx} +1 -1
  210. package/src/form/combobox/SelectedOptions/SelectedOptions.tsx +1 -1
  211. package/src/form/combobox/SelectedOptions/selectedOptionsContext.tsx +12 -26
  212. package/src/form/combobox/{combobox-utils.test.ts → __tests__/combobox-utils.test.ts} +1 -1
  213. package/src/form/combobox/{combobox.test.tsx → __tests__/combobox.test.tsx} +2 -3
  214. package/src/form/combobox/customOptionsContext.tsx +14 -18
  215. package/src/form/combobox/types.ts +3 -1
  216. package/src/index.ts +1 -0
  217. package/src/overlay/README.md +5 -0
  218. package/src/overlay/dismiss/DismissableLayer.tsx +368 -0
  219. package/src/overlay/dismiss/util/dispatchCustomEvent.ts +77 -0
  220. package/src/overlay/dismiss/util/useEscapeKeydown.ts +21 -0
  221. package/src/overlay/dismiss/util/useFocusOutside.ts +52 -0
  222. package/src/overlay/dismiss/util/usePointerDownOutside.ts +95 -0
  223. package/src/overlays/floating/Floating.tsx +399 -0
  224. package/src/overlays/floating/Floating.utils.ts +63 -0
  225. package/src/popover/Popover.tsx +38 -70
  226. package/src/progress-bar/ProgressBar.tsx +149 -0
  227. package/src/progress-bar/index.ts +2 -0
  228. package/src/tabs/Tabs.context.ts +2 -0
  229. package/src/toggle-group/ToggleGroup.context.ts +1 -0
  230. package/src/typography/BodyLong.tsx +7 -7
  231. package/src/typography/BodyShort.tsx +5 -5
  232. package/src/typography/Detail.tsx +5 -5
  233. package/src/typography/ErrorMessage.tsx +5 -5
  234. package/src/typography/Heading.tsx +6 -6
  235. package/src/typography/Label.tsx +5 -5
  236. package/src/typography/types.ts +3 -3
  237. package/src/util/hooks/descendants/useDescendant.tsx +55 -68
  238. package/src/util/types/AsChild.ts +15 -0
  239. package/cjs/form/combobox/ClearButton.d.ts +0 -7
  240. package/cjs/form/combobox/ClearButton.js +0 -28
  241. package/cjs/form/combobox/ClearButton.js.map +0 -1
  242. package/cjs/form/combobox/FilteredOptions/CheckIcon.d.ts +0 -3
  243. package/cjs/form/combobox/FilteredOptions/CheckIcon.js +0 -12
  244. package/cjs/form/combobox/FilteredOptions/CheckIcon.js.map +0 -1
  245. package/cjs/form/combobox/Input/inputContext.js.map +0 -1
  246. package/cjs/form/combobox/ToggleListButton.js.map +0 -1
  247. package/esm/form/combobox/ClearButton.d.ts +0 -7
  248. package/esm/form/combobox/ClearButton.js +0 -21
  249. package/esm/form/combobox/ClearButton.js.map +0 -1
  250. package/esm/form/combobox/FilteredOptions/CheckIcon.d.ts +0 -3
  251. package/esm/form/combobox/FilteredOptions/CheckIcon.js +0 -7
  252. package/esm/form/combobox/FilteredOptions/CheckIcon.js.map +0 -1
  253. package/esm/form/combobox/Input/inputContext.js.map +0 -1
  254. package/esm/form/combobox/ToggleListButton.js.map +0 -1
  255. package/src/form/combobox/ClearButton.tsx +0 -29
  256. package/src/form/combobox/FilteredOptions/CheckIcon.tsx +0 -23
  257. /package/cjs/form/combobox/{ToggleListButton.d.ts → Input/ToggleListButton.d.ts} +0 -0
  258. /package/esm/form/combobox/{ToggleListButton.d.ts → Input/ToggleListButton.d.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@navikt/ds-react",
3
- "version": "6.6.1",
3
+ "version": "6.7.1",
4
4
  "description": "React components from the Norwegian Labour and Welfare Administration.",
5
5
  "author": "Aksel, a team part of the Norwegian Labour and Welfare Administration.",
6
6
  "license": "MIT",
@@ -310,6 +310,16 @@
310
310
  "default": "./cjs/popover/index.js"
311
311
  }
312
312
  },
313
+ "./ProgressBar": {
314
+ "import": {
315
+ "types": "./esm/progress-bar/index.d.ts",
316
+ "default": "./esm/progress-bar/index.js"
317
+ },
318
+ "require": {
319
+ "types": "./cjs/progress-bar/index.d.ts",
320
+ "default": "./cjs/progress-bar/index.js"
321
+ }
322
+ },
313
323
  "./Provider": {
314
324
  "import": {
315
325
  "types": "./esm/provider/index.d.ts",
@@ -573,16 +583,17 @@
573
583
  },
574
584
  "dependencies": {
575
585
  "@floating-ui/react": "0.25.4",
576
- "@navikt/aksel-icons": "^6.6.1",
577
- "@navikt/ds-tokens": "^6.6.1",
586
+ "@floating-ui/react-dom": "^2.0.9",
587
+ "@navikt/aksel-icons": "^6.7.1",
588
+ "@navikt/ds-tokens": "^6.7.1",
578
589
  "clsx": "^2.1.0",
579
590
  "date-fns": "^3.0.0",
580
591
  "react-day-picker": "8.10.0"
581
592
  },
582
593
  "devDependencies": {
583
- "@testing-library/dom": "8.13.0",
594
+ "@testing-library/dom": "9.3.4",
584
595
  "@testing-library/jest-dom": "^5.16.0",
585
- "@testing-library/react": "^13.3.0",
596
+ "@testing-library/react": "^15.0.7",
586
597
  "@testing-library/user-event": "^14.2.0",
587
598
  "@types/faker": "5.5.8",
588
599
  "concurrently": "7.2.1",
package/src/chat/Chat.tsx CHANGED
@@ -3,6 +3,7 @@ import React, { HTMLAttributes, forwardRef } from "react";
3
3
  import { BodyLong } from "../typography";
4
4
  import Bubble from "./Bubble";
5
5
 
6
+ export const VARIANTS = ["subtle", "info", "neutral"] as const;
6
7
  export const POSITIONS = ["left", "right"] as const;
7
8
  export const SIZES = ["medium", "small"] as const;
8
9
 
@@ -28,7 +29,7 @@ export interface ChatProps extends HTMLAttributes<HTMLDivElement> {
28
29
  * Avoid using the same background as the surface behind Chat.
29
30
  * @default "neutral"
30
31
  */
31
- variant?: "subtle" | "info" | "neutral";
32
+ variant?: (typeof VARIANTS)[number];
32
33
  /**
33
34
  * Positions avatar and bubbles.
34
35
  * @default "left"
@@ -37,7 +37,11 @@ export const DropdownCaption = ({ displayMonth, id }: CaptionProps) => {
37
37
  const handleMonthChange: React.ChangeEventHandler<HTMLSelectElement> = (e) =>
38
38
  goToMonth(setMonth(startOfMonth(displayMonth), Number(e.target.value)));
39
39
 
40
- const years = getYears(fromDate, toDate, displayMonth.getFullYear());
40
+ const years = getYears(
41
+ fromDate,
42
+ toDate,
43
+ displayMonth.getFullYear(),
44
+ ).reverse();
41
45
  const months = getMonths(fromDate, toDate, displayMonth);
42
46
 
43
47
  const previousLabel = labelPrevious(previousMonth, { locale });
@@ -35,7 +35,7 @@ export const MonthCaption = () => {
35
35
  if (!years.map((x) => x.getFullYear()).includes(year.getFullYear())) {
36
36
  years.push(setYear(startOfYear(new Date()), year.getFullYear()));
37
37
  }
38
- years.sort((a, b) => a.getFullYear() - b.getFullYear());
38
+ years.sort((a, b) => b.getFullYear() - a.getFullYear());
39
39
  }
40
40
 
41
41
  const handleYearChange = (e) =>
@@ -1,57 +1,31 @@
1
1
  import cl from "clsx";
2
- import React, { forwardRef, useRef } from "react";
2
+ import React, { forwardRef } from "react";
3
3
  import { BodyShort, ErrorMessage, Label } from "../../typography";
4
- import { useMergeRefs } from "../../util/hooks/useMergeRefs";
5
- import ClearButton from "./ClearButton";
6
4
  import ComboboxWrapper from "./ComboboxWrapper";
7
5
  import FilteredOptions from "./FilteredOptions/FilteredOptions";
8
6
  import { useFilteredOptionsContext } from "./FilteredOptions/filteredOptionsContext";
9
- import Input from "./Input/Input";
10
- import { useInputContext } from "./Input/inputContext";
11
- import SelectedOptions from "./SelectedOptions/SelectedOptions";
12
- import { useSelectedOptionsContext } from "./SelectedOptions/selectedOptionsContext";
13
- import ToggleListButton from "./ToggleListButton";
7
+ import { useInputContext } from "./Input/Input.context";
8
+ import { InputController } from "./Input/InputController";
14
9
  import { ComboboxProps } from "./types";
15
10
 
16
11
  export const Combobox = forwardRef<
17
12
  HTMLInputElement,
18
13
  Omit<ComboboxProps, "onChange" | "options" | "size" | "onClear" | "value">
19
14
  >((props, ref) => {
20
- const {
21
- className,
22
- hideLabel = false,
23
- description,
24
- label,
25
- clearButton = true,
26
- clearButtonLabel,
27
- toggleListButton = true,
28
- toggleListButtonLabel,
29
- inputClassName,
30
- shouldShowSelectedOptions = true,
31
- ...rest
32
- } = props;
33
-
34
- const toggleListButtonRef = useRef<HTMLButtonElement>(null);
15
+ const { className, hideLabel = false, description, label, ...rest } = props;
35
16
 
36
- const { activeDecendantId, toggleIsListOpen } = useFilteredOptionsContext();
37
- const { selectedOptions } = useSelectedOptionsContext();
17
+ const { toggleIsListOpen } = useFilteredOptionsContext();
38
18
 
39
19
  const {
40
- clearInput,
41
20
  error,
42
21
  errorId,
43
- focusInput,
44
22
  hasError,
45
23
  inputDescriptionId,
46
24
  inputProps,
47
- inputRef,
48
- value,
49
25
  showErrorMsg,
50
26
  size = "medium",
51
27
  } = useInputContext();
52
28
 
53
- const mergedInputRef = useMergeRefs(inputRef, ref);
54
-
55
29
  return (
56
30
  <ComboboxWrapper
57
31
  className={className}
@@ -59,7 +33,6 @@ export const Combobox = forwardRef<
59
33
  inputProps={inputProps}
60
34
  inputSize={size}
61
35
  toggleIsListOpen={toggleIsListOpen}
62
- toggleListButtonRef={toggleListButtonRef}
63
36
  >
64
37
  <Label
65
38
  htmlFor={inputProps.id}
@@ -83,50 +56,7 @@ export const Combobox = forwardRef<
83
56
  </BodyShort>
84
57
  )}
85
58
  <div className="navds-combobox__wrapper">
86
- {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
87
- <div
88
- className={cl(
89
- "navds-combobox__wrapper-inner navds-text-field__input",
90
- {
91
- "navds-combobox__wrapper-inner--virtually-unfocused":
92
- activeDecendantId !== undefined,
93
- },
94
- )}
95
- onClick={focusInput}
96
- >
97
- {!shouldShowSelectedOptions ? (
98
- <Input
99
- id={inputProps.id}
100
- ref={mergedInputRef}
101
- inputClassName={inputClassName}
102
- {...rest}
103
- />
104
- ) : (
105
- <SelectedOptions selectedOptions={selectedOptions} size={size}>
106
- <Input
107
- id={inputProps.id}
108
- ref={mergedInputRef}
109
- inputClassName={inputClassName}
110
- {...rest}
111
- />
112
- </SelectedOptions>
113
- )}
114
- <div>
115
- {value && clearButton && (
116
- <ClearButton
117
- handleClear={clearInput}
118
- clearButtonLabel={clearButtonLabel}
119
- tabIndex={-1}
120
- />
121
- )}
122
- {toggleListButton && (
123
- <ToggleListButton
124
- toggleListButtonLabel={toggleListButtonLabel}
125
- ref={toggleListButtonRef}
126
- />
127
- )}
128
- </div>
129
- </div>
59
+ <InputController ref={ref} {...rest} />
130
60
  <FilteredOptions />
131
61
  </div>
132
62
  <div
@@ -1,7 +1,7 @@
1
1
  import React, { forwardRef } from "react";
2
2
  import Combobox from "./Combobox";
3
3
  import { FilteredOptionsProvider } from "./FilteredOptions/filteredOptionsContext";
4
- import { InputContextProvider } from "./Input/inputContext";
4
+ import { InputContextProvider } from "./Input/Input.context";
5
5
  import { SelectedOptionsProvider } from "./SelectedOptions/selectedOptionsContext";
6
6
  import { mapToComboboxOptionArray } from "./combobox-utils";
7
7
  import { CustomOptionsProvider } from "./customOptionsContext";
@@ -1,5 +1,6 @@
1
1
  import cl from "clsx";
2
2
  import React, { useRef, useState } from "react";
3
+ import { useInputContext } from "./Input/Input.context";
3
4
 
4
5
  type ComboboxWrapperProps = {
5
6
  children: any;
@@ -10,7 +11,6 @@ type ComboboxWrapperProps = {
10
11
  };
11
12
  inputSize: string;
12
13
  toggleIsListOpen: (isListOpen: boolean) => void;
13
- toggleListButtonRef: React.RefObject<HTMLButtonElement>;
14
14
  };
15
15
 
16
16
  const ComboboxWrapper = ({
@@ -20,15 +20,16 @@ const ComboboxWrapper = ({
20
20
  inputProps,
21
21
  inputSize,
22
22
  toggleIsListOpen,
23
- toggleListButtonRef,
24
23
  }: ComboboxWrapperProps) => {
24
+ const { toggleOpenButtonRef } = useInputContext();
25
+
25
26
  const wrapperRef = useRef<HTMLDivElement | null>(null);
26
27
  const [hasFocusWithin, setHasFocusWithin] = useState(false);
27
28
 
28
29
  function onFocusInsideWrapper(e) {
29
30
  if (
30
31
  !wrapperRef.current?.contains(e.relatedTarget) &&
31
- toggleListButtonRef?.current !== e.target
32
+ toggleOpenButtonRef?.current !== e.target
32
33
  ) {
33
34
  toggleIsListOpen(true);
34
35
  setHasFocusWithin(true);
@@ -3,7 +3,7 @@ import React from "react";
3
3
  import { CheckmarkIcon, PlusIcon } from "@navikt/aksel-icons";
4
4
  import { Loader } from "../../../loader";
5
5
  import { BodyShort, Label } from "../../../typography";
6
- import { useInputContext } from "../Input/inputContext";
6
+ import { useInputContext } from "../Input/Input.context";
7
7
  import { useSelectedOptionsContext } from "../SelectedOptions/selectedOptionsContext";
8
8
  import { isInList, toComboboxOption } from "../combobox-utils";
9
9
  import { ComboboxOption } from "../types";
@@ -38,7 +38,7 @@ const FilteredOptions = () => {
38
38
  const shouldRenderNonSelectables =
39
39
  maxSelected?.isLimitReached || // Render maxSelected message
40
40
  isLoading || // Render loading message
41
- (!isLoading && filteredOptions.length === 0); // Render no hits message
41
+ (!isLoading && filteredOptions.length === 0 && !allowNewValues); // Render no hits message
42
42
 
43
43
  const shouldRenderFilteredOptionsList =
44
44
  (allowNewValues && isValueNew && !maxSelected?.isLimitReached) || // Render add new option
@@ -72,7 +72,7 @@ const FilteredOptions = () => {
72
72
  <Loader title="Søker..." />
73
73
  </div>
74
74
  )}
75
- {!isLoading && filteredOptions.length === 0 && (
75
+ {!isLoading && filteredOptions.length === 0 && !allowNewValues && (
76
76
  <div
77
77
  className="navds-combobox__list-item--no-options"
78
78
  id={filteredOptionsUtil.getNoHitsId(id)}
@@ -1,17 +1,11 @@
1
1
  import cl from "clsx";
2
- import React, {
3
- SetStateAction,
4
- createContext,
5
- useCallback,
6
- useContext,
7
- useMemo,
8
- useState,
9
- } from "react";
2
+ import React, { SetStateAction, useCallback, useMemo, useState } from "react";
3
+ import { createContext } from "../../../util/create-context";
10
4
  import { useClientLayoutEffect, usePrevious } from "../../../util/hooks";
11
- import { useInputContext } from "../Input/inputContext";
5
+ import { useInputContext } from "../Input/Input.context";
12
6
  import { useSelectedOptionsContext } from "../SelectedOptions/selectedOptionsContext";
13
7
  import { toComboboxOption } from "../combobox-utils";
14
- import { useCustomOptionsContext } from "../customOptionsContext";
8
+ import { useComboboxCustomOptions } from "../customOptionsContext";
15
9
  import { ComboboxOption, ComboboxProps } from "../types";
16
10
  import filteredOptionsUtils from "./filtered-options-util";
17
11
  import useVirtualFocus, { VirtualFocusType } from "./useVirtualFocus";
@@ -24,7 +18,7 @@ type FilteredOptionsProps = {
24
18
  };
25
19
  };
26
20
 
27
- type FilteredOptionsContextType = {
21
+ type FilteredOptionsContextValue = {
28
22
  activeDecendantId?: string;
29
23
  allowNewValues?: boolean;
30
24
  ariaDescribedBy?: string;
@@ -42,11 +36,14 @@ type FilteredOptionsContextType = {
42
36
  shouldAutocomplete?: boolean;
43
37
  virtualFocus: VirtualFocusType;
44
38
  };
45
- const FilteredOptionsContext = createContext<FilteredOptionsContextType>(
46
- {} as FilteredOptionsContextType,
47
- );
39
+ const [FilteredOptionsContextProvider, useFilteredOptionsContext] =
40
+ createContext<FilteredOptionsContextValue>({
41
+ name: "FilteredOptionsContext",
42
+ errorMessage:
43
+ "useFilteredOptionsContext must be used within a FilteredOptionsProvider",
44
+ });
48
45
 
49
- export const FilteredOptionsProvider = ({
46
+ const FilteredOptionsProvider = ({
50
47
  children,
51
48
  value: props,
52
49
  }: FilteredOptionsProps) => {
@@ -71,7 +68,7 @@ export const FilteredOptionsProvider = ({
71
68
  const { maxSelected } = useSelectedOptionsContext();
72
69
 
73
70
  const [isInternalListOpen, setInternalListOpen] = useState(false);
74
- const { customOptions } = useCustomOptionsContext();
71
+ const { customOptions } = useComboboxCustomOptions();
75
72
 
76
73
  const filteredOptions = useMemo(() => {
77
74
  if (externalFilteredOptions) {
@@ -152,9 +149,9 @@ export const FilteredOptionsProvider = ({
152
149
 
153
150
  const ariaDescribedBy = useMemo(() => {
154
151
  let activeOption;
155
- if (!isLoading && filteredOptions.length === 0) {
152
+ if (!isLoading && filteredOptions.length === 0 && !allowNewValues) {
156
153
  activeOption = filteredOptionsUtils.getNoHitsId(id);
157
- } else if ((value && value !== "") || isLoading) {
154
+ } else if (value || isLoading) {
158
155
  if (shouldAutocomplete && filteredOptions[0]) {
159
156
  activeOption = filteredOptionsUtils.getOptionId(
160
157
  id,
@@ -180,6 +177,7 @@ export const FilteredOptionsProvider = ({
180
177
  shouldAutocomplete,
181
178
  filteredOptions,
182
179
  id,
180
+ allowNewValues,
183
181
  ]);
184
182
 
185
183
  const currentOption = useMemo(
@@ -211,18 +209,10 @@ export const FilteredOptionsProvider = ({
211
209
  };
212
210
 
213
211
  return (
214
- <FilteredOptionsContext.Provider value={filteredOptionsState}>
212
+ <FilteredOptionsContextProvider {...filteredOptionsState}>
215
213
  {children}
216
- </FilteredOptionsContext.Provider>
214
+ </FilteredOptionsContextProvider>
217
215
  );
218
216
  };
219
217
 
220
- export const useFilteredOptionsContext = () => {
221
- const context = useContext(FilteredOptionsContext);
222
- if (!context) {
223
- throw new Error(
224
- "useFilteredOptionsContext must be used within a FilteredOptionsProvider",
225
- );
226
- }
227
- return context;
228
- };
218
+ export { FilteredOptionsProvider, useFilteredOptionsContext };
@@ -1,18 +1,18 @@
1
1
  import React, {
2
2
  ChangeEvent,
3
3
  ChangeEventHandler,
4
- createContext,
5
4
  useCallback,
6
- useContext,
7
5
  useMemo,
8
6
  useRef,
9
7
  useState,
10
8
  } from "react";
9
+ import { createContext } from "../../../util/create-context";
11
10
  import { useClientLayoutEffect } from "../../../util/hooks";
12
11
  import { FormFieldType, useFormField } from "../../useFormField";
12
+ import { ComboboxProps } from "../types";
13
13
 
14
- interface InputContextType extends FormFieldType {
15
- clearInput: (event: React.PointerEvent | React.KeyboardEvent) => void;
14
+ interface InputContextValue extends FormFieldType {
15
+ clearInput: NonNullable<ComboboxProps["onClear"]>;
16
16
  error?: string;
17
17
  focusInput: () => void;
18
18
  inputRef: React.RefObject<HTMLInputElement>;
@@ -22,11 +22,16 @@ interface InputContextType extends FormFieldType {
22
22
  searchTerm: string;
23
23
  setSearchTerm: React.Dispatch<React.SetStateAction<string>>;
24
24
  shouldAutocomplete?: boolean;
25
+ toggleOpenButtonRef: React.RefObject<HTMLButtonElement>;
25
26
  }
26
27
 
27
- const InputContext = createContext<InputContextType>({} as InputContextType);
28
+ const [InputContextProvider, useInputContext] =
29
+ createContext<InputContextValue>({
30
+ name: "InputContext",
31
+ errorMessage: "useInputContext must be used within an InputContextProvider",
32
+ });
28
33
 
29
- export const InputContextProvider = ({ children, value: props }) => {
34
+ const InputProvider = ({ children, value: props }) => {
30
35
  const {
31
36
  defaultValue = "",
32
37
  description,
@@ -52,6 +57,7 @@ export const InputContextProvider = ({ children, value: props }) => {
52
57
  "comboboxfield",
53
58
  );
54
59
  const inputRef = useRef<HTMLInputElement | null>(null);
60
+ const toggleOpenButtonRef = useRef<HTMLButtonElement>(null);
55
61
  const [internalValue, setInternalValue] = useState<string>(defaultValue);
56
62
 
57
63
  const value = useMemo(
@@ -79,7 +85,7 @@ export const InputContextProvider = ({ children, value: props }) => {
79
85
  );
80
86
 
81
87
  const clearInput = useCallback(
82
- (event: React.PointerEvent | React.KeyboardEvent) => {
88
+ (event: React.PointerEvent | React.KeyboardEvent | React.MouseEvent) => {
83
89
  onClear?.(event);
84
90
  externalOnChange?.(null, "");
85
91
  setValue("");
@@ -98,33 +104,24 @@ export const InputContextProvider = ({ children, value: props }) => {
98
104
  }
99
105
  }, [value, searchTerm, shouldAutocomplete]);
100
106
 
107
+ const contextValue = {
108
+ ...formFieldProps,
109
+ clearInput,
110
+ error,
111
+ focusInput,
112
+ inputRef,
113
+ value,
114
+ setValue,
115
+ onChange,
116
+ searchTerm,
117
+ setSearchTerm,
118
+ shouldAutocomplete,
119
+ toggleOpenButtonRef,
120
+ };
121
+
101
122
  return (
102
- <InputContext.Provider
103
- value={{
104
- ...formFieldProps,
105
- clearInput,
106
- error,
107
- focusInput,
108
- inputRef,
109
- value,
110
- setValue,
111
- onChange,
112
- searchTerm,
113
- setSearchTerm,
114
- shouldAutocomplete,
115
- }}
116
- >
117
- {children}
118
- </InputContext.Provider>
123
+ <InputContextProvider {...contextValue}>{children}</InputContextProvider>
119
124
  );
120
125
  };
121
126
 
122
- export const useInputContext = () => {
123
- const context = useContext(InputContext);
124
- if (!context) {
125
- throw new Error(
126
- "useInputContext must be used within an InputContextProvider",
127
- );
128
- }
129
- return context;
130
- };
127
+ export { InputProvider as InputContextProvider, useInputContext };
@@ -9,7 +9,7 @@ import { omit } from "../../../util";
9
9
  import filteredOptionsUtil from "../FilteredOptions/filtered-options-util";
10
10
  import { useFilteredOptionsContext } from "../FilteredOptions/filteredOptionsContext";
11
11
  import { useSelectedOptionsContext } from "../SelectedOptions/selectedOptionsContext";
12
- import { useInputContext } from "./inputContext";
12
+ import { useInputContext } from "./Input.context";
13
13
 
14
14
  interface InputProps
15
15
  extends Omit<InputHTMLAttributes<HTMLInputElement>, "value"> {
@@ -0,0 +1,102 @@
1
+ /* eslint-disable jsx-a11y/no-static-element-interactions */
2
+ import cl from "clsx";
3
+ import React, { forwardRef } from "react";
4
+ import { XMarkIcon } from "@navikt/aksel-icons";
5
+ import { useMergeRefs } from "../../../util/hooks";
6
+ import { useFilteredOptionsContext } from "../FilteredOptions/filteredOptionsContext";
7
+ import SelectedOptions from "../SelectedOptions/SelectedOptions";
8
+ import { useSelectedOptionsContext } from "../SelectedOptions/selectedOptionsContext";
9
+ import { ComboboxProps } from "../types";
10
+ import Input from "./Input";
11
+ import { useInputContext } from "./Input.context";
12
+ import ToggleListButton from "./ToggleListButton";
13
+
14
+ /* eslint-disable jsx-a11y/click-events-have-key-events */
15
+ export const InputController = forwardRef<
16
+ HTMLInputElement,
17
+ Omit<
18
+ ComboboxProps,
19
+ | "label"
20
+ | "description"
21
+ | "hideLabel"
22
+ | "onChange"
23
+ | "options"
24
+ | "size"
25
+ | "onClear"
26
+ | "value"
27
+ >
28
+ >((props, ref) => {
29
+ const {
30
+ clearButton = true,
31
+ clearButtonLabel,
32
+ toggleListButton = true,
33
+ toggleListButtonLabel,
34
+ inputClassName,
35
+ shouldShowSelectedOptions = true,
36
+ ...rest
37
+ } = props;
38
+
39
+ const {
40
+ clearInput,
41
+ focusInput,
42
+ inputProps,
43
+ value,
44
+ size = "medium",
45
+ inputRef,
46
+ toggleOpenButtonRef,
47
+ } = useInputContext();
48
+
49
+ const { activeDecendantId } = useFilteredOptionsContext();
50
+ const { selectedOptions } = useSelectedOptionsContext();
51
+
52
+ const mergedInputRef = useMergeRefs(inputRef, ref);
53
+
54
+ return (
55
+ <div
56
+ className={cl("navds-combobox__wrapper-inner navds-text-field__input", {
57
+ "navds-combobox__wrapper-inner--virtually-unfocused":
58
+ activeDecendantId !== undefined,
59
+ })}
60
+ onClick={focusInput}
61
+ >
62
+ {!shouldShowSelectedOptions ? (
63
+ <Input
64
+ id={inputProps.id}
65
+ ref={mergedInputRef}
66
+ inputClassName={inputClassName}
67
+ {...rest}
68
+ />
69
+ ) : (
70
+ <SelectedOptions selectedOptions={selectedOptions} size={size}>
71
+ <Input
72
+ id={inputProps.id}
73
+ ref={mergedInputRef}
74
+ inputClassName={inputClassName}
75
+ {...rest}
76
+ />
77
+ </SelectedOptions>
78
+ )}
79
+ <div>
80
+ {value && clearButton && (
81
+ <button
82
+ type="button"
83
+ onClick={clearInput}
84
+ className="navds-combobox__button-clear"
85
+ tabIndex={-1}
86
+ >
87
+ <span className="navds-sr-only">
88
+ {clearButtonLabel ? clearButtonLabel : "Tøm"}
89
+ </span>
90
+ <XMarkIcon aria-hidden />
91
+ </button>
92
+ )}
93
+ {toggleListButton && (
94
+ <ToggleListButton
95
+ toggleListButtonLabel={toggleListButtonLabel}
96
+ ref={toggleOpenButtonRef}
97
+ />
98
+ )}
99
+ </div>
100
+ </div>
101
+ );
102
+ });
@@ -1,6 +1,6 @@
1
1
  import React, { forwardRef } from "react";
2
2
  import { ChevronDownIcon, ChevronUpIcon } from "@navikt/aksel-icons";
3
- import { useFilteredOptionsContext } from "./FilteredOptions/filteredOptionsContext";
3
+ import { useFilteredOptionsContext } from "../FilteredOptions/filteredOptionsContext";
4
4
 
5
5
  interface ToggleListButtonProps {
6
6
  toggleListButtonLabel?: string;
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import { Chips } from "../../../chips";
3
- import { useInputContext } from "../Input/inputContext";
3
+ import { useInputContext } from "../Input/Input.context";
4
4
  import { ComboboxOption } from "../types";
5
5
  import { useSelectedOptionsContext } from "./selectedOptionsContext";
6
6