@navikt/ds-react 6.7.0 → 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 (211) 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/overlay/dismiss/DismissableLayer.d.ts +70 -0
  42. package/cjs/overlay/dismiss/DismissableLayer.js +253 -0
  43. package/cjs/overlay/dismiss/DismissableLayer.js.map +1 -0
  44. package/cjs/overlay/dismiss/util/dispatchCustomEvent.d.ts +50 -0
  45. package/cjs/overlay/dismiss/util/dispatchCustomEvent.js +65 -0
  46. package/cjs/overlay/dismiss/util/dispatchCustomEvent.js.map +1 -0
  47. package/cjs/overlay/dismiss/util/useEscapeKeydown.d.ts +1 -0
  48. package/cjs/overlay/dismiss/util/useEscapeKeydown.js +19 -0
  49. package/cjs/overlay/dismiss/util/useEscapeKeydown.js.map +1 -0
  50. package/cjs/overlay/dismiss/util/useFocusOutside.d.ts +8 -0
  51. package/cjs/overlay/dismiss/util/useFocusOutside.js +42 -0
  52. package/cjs/overlay/dismiss/util/useFocusOutside.js.map +1 -0
  53. package/cjs/overlay/dismiss/util/usePointerDownOutside.d.ts +10 -0
  54. package/cjs/overlay/dismiss/util/usePointerDownOutside.js +84 -0
  55. package/cjs/overlay/dismiss/util/usePointerDownOutside.js.map +1 -0
  56. package/cjs/overlays/floating/Floating.d.ts +53 -0
  57. package/cjs/overlays/floating/Floating.js +215 -0
  58. package/cjs/overlays/floating/Floating.js.map +1 -0
  59. package/cjs/overlays/floating/Floating.utils.d.ts +18 -0
  60. package/cjs/overlays/floating/Floating.utils.js +52 -0
  61. package/cjs/overlays/floating/Floating.utils.js.map +1 -0
  62. package/cjs/popover/Popover.js +13 -28
  63. package/cjs/popover/Popover.js.map +1 -1
  64. package/cjs/progress-bar/ProgressBar.d.ts +20 -8
  65. package/cjs/progress-bar/ProgressBar.js +19 -9
  66. package/cjs/progress-bar/ProgressBar.js.map +1 -1
  67. package/cjs/tabs/Tabs.context.d.ts +7 -3
  68. package/cjs/tabs/Tabs.context.js +1 -0
  69. package/cjs/tabs/Tabs.context.js.map +1 -1
  70. package/cjs/timeline/AxisLabels.d.ts +1 -1
  71. package/cjs/toggle-group/ToggleGroup.context.d.ts +7 -3
  72. package/cjs/toggle-group/ToggleGroup.context.js +1 -0
  73. package/cjs/toggle-group/ToggleGroup.context.js.map +1 -1
  74. package/cjs/util/hooks/descendants/useDescendant.d.ts +2 -2
  75. package/cjs/util/hooks/descendants/useDescendant.js +49 -52
  76. package/cjs/util/hooks/descendants/useDescendant.js.map +1 -1
  77. package/cjs/util/types/AsChild.d.ts +14 -0
  78. package/cjs/util/types/AsChild.js +3 -0
  79. package/cjs/util/types/AsChild.js.map +1 -0
  80. package/esm/chat/Chat.d.ts +2 -1
  81. package/esm/chat/Chat.js +1 -0
  82. package/esm/chat/Chat.js.map +1 -1
  83. package/esm/date/datepicker/parts/DropdownCaption.js +1 -1
  84. package/esm/date/datepicker/parts/DropdownCaption.js.map +1 -1
  85. package/esm/date/monthpicker/MonthCaption.js +1 -1
  86. package/esm/date/utils/labels.d.ts +2 -2
  87. package/esm/form/ReadOnlyIcon.d.ts +2 -2
  88. package/esm/form/combobox/Combobox.js +8 -23
  89. package/esm/form/combobox/Combobox.js.map +1 -1
  90. package/esm/form/combobox/ComboboxProvider.js +1 -1
  91. package/esm/form/combobox/ComboboxProvider.js.map +1 -1
  92. package/esm/form/combobox/ComboboxWrapper.d.ts +1 -2
  93. package/esm/form/combobox/ComboboxWrapper.js +4 -2
  94. package/esm/form/combobox/ComboboxWrapper.js.map +1 -1
  95. package/esm/form/combobox/FilteredOptions/FilteredOptions.js +3 -3
  96. package/esm/form/combobox/FilteredOptions/FilteredOptions.js.map +1 -1
  97. package/esm/form/combobox/FilteredOptions/filteredOptionsContext.d.ts +4 -4
  98. package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js +15 -16
  99. package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js.map +1 -1
  100. package/esm/form/combobox/Input/{inputContext.d.ts → Input.context.d.ts} +7 -5
  101. package/esm/form/combobox/Input/{inputContext.js → Input.context.js} +22 -21
  102. package/esm/form/combobox/Input/Input.context.js.map +1 -0
  103. package/esm/form/combobox/Input/Input.js +1 -1
  104. package/esm/form/combobox/Input/Input.js.map +1 -1
  105. package/esm/form/combobox/Input/InputController.d.ts +3 -0
  106. package/esm/form/combobox/Input/InputController.js +41 -0
  107. package/esm/form/combobox/Input/InputController.js.map +1 -0
  108. package/esm/form/combobox/{ToggleListButton.js → Input/ToggleListButton.js} +1 -1
  109. package/esm/form/combobox/Input/ToggleListButton.js.map +1 -0
  110. package/esm/form/combobox/SelectedOptions/SelectedOptions.js +1 -1
  111. package/esm/form/combobox/SelectedOptions/SelectedOptions.js.map +1 -1
  112. package/esm/form/combobox/SelectedOptions/selectedOptionsContext.d.ts +4 -4
  113. package/esm/form/combobox/SelectedOptions/selectedOptionsContext.js +9 -14
  114. package/esm/form/combobox/SelectedOptions/selectedOptionsContext.js.map +1 -1
  115. package/esm/form/combobox/customOptionsContext.d.ts +4 -4
  116. package/esm/form/combobox/customOptionsContext.js +10 -12
  117. package/esm/form/combobox/customOptionsContext.js.map +1 -1
  118. package/esm/form/combobox/types.d.ts +1 -1
  119. package/esm/help-text/HelpTextIcon.d.ts +1 -1
  120. package/esm/overlay/dismiss/DismissableLayer.d.ts +70 -0
  121. package/esm/overlay/dismiss/DismissableLayer.js +226 -0
  122. package/esm/overlay/dismiss/DismissableLayer.js.map +1 -0
  123. package/esm/overlay/dismiss/util/dispatchCustomEvent.d.ts +50 -0
  124. package/esm/overlay/dismiss/util/dispatchCustomEvent.js +58 -0
  125. package/esm/overlay/dismiss/util/dispatchCustomEvent.js.map +1 -0
  126. package/esm/overlay/dismiss/util/useEscapeKeydown.d.ts +1 -0
  127. package/esm/overlay/dismiss/util/useEscapeKeydown.js +15 -0
  128. package/esm/overlay/dismiss/util/useEscapeKeydown.js.map +1 -0
  129. package/esm/overlay/dismiss/util/useFocusOutside.d.ts +8 -0
  130. package/esm/overlay/dismiss/util/useFocusOutside.js +38 -0
  131. package/esm/overlay/dismiss/util/useFocusOutside.js.map +1 -0
  132. package/esm/overlay/dismiss/util/usePointerDownOutside.d.ts +10 -0
  133. package/esm/overlay/dismiss/util/usePointerDownOutside.js +80 -0
  134. package/esm/overlay/dismiss/util/usePointerDownOutside.js.map +1 -0
  135. package/esm/overlays/floating/Floating.d.ts +53 -0
  136. package/esm/overlays/floating/Floating.js +188 -0
  137. package/esm/overlays/floating/Floating.js.map +1 -0
  138. package/esm/overlays/floating/Floating.utils.d.ts +18 -0
  139. package/esm/overlays/floating/Floating.utils.js +48 -0
  140. package/esm/overlays/floating/Floating.utils.js.map +1 -0
  141. package/esm/popover/Popover.js +16 -31
  142. package/esm/popover/Popover.js.map +1 -1
  143. package/esm/progress-bar/ProgressBar.d.ts +20 -8
  144. package/esm/progress-bar/ProgressBar.js +20 -10
  145. package/esm/progress-bar/ProgressBar.js.map +1 -1
  146. package/esm/tabs/Tabs.context.d.ts +7 -3
  147. package/esm/tabs/Tabs.context.js +1 -0
  148. package/esm/tabs/Tabs.context.js.map +1 -1
  149. package/esm/timeline/AxisLabels.d.ts +1 -1
  150. package/esm/toggle-group/ToggleGroup.context.d.ts +7 -3
  151. package/esm/toggle-group/ToggleGroup.context.js +1 -0
  152. package/esm/toggle-group/ToggleGroup.context.js.map +1 -1
  153. package/esm/util/hooks/descendants/useDescendant.d.ts +2 -2
  154. package/esm/util/hooks/descendants/useDescendant.js +49 -52
  155. package/esm/util/hooks/descendants/useDescendant.js.map +1 -1
  156. package/esm/util/types/AsChild.d.ts +14 -0
  157. package/esm/util/types/AsChild.js +2 -0
  158. package/esm/util/types/AsChild.js.map +1 -0
  159. package/package.json +6 -5
  160. package/src/chat/Chat.tsx +2 -1
  161. package/src/date/datepicker/parts/DropdownCaption.tsx +5 -1
  162. package/src/date/monthpicker/MonthCaption.tsx +1 -1
  163. package/src/form/combobox/Combobox.tsx +6 -76
  164. package/src/form/combobox/ComboboxProvider.tsx +1 -1
  165. package/src/form/combobox/ComboboxWrapper.tsx +4 -3
  166. package/src/form/combobox/FilteredOptions/FilteredOptions.tsx +3 -3
  167. package/src/form/combobox/FilteredOptions/filteredOptionsContext.tsx +19 -29
  168. package/src/form/combobox/Input/{inputContext.tsx → Input.context.tsx} +30 -33
  169. package/src/form/combobox/Input/Input.tsx +1 -1
  170. package/src/form/combobox/Input/InputController.tsx +102 -0
  171. package/src/form/combobox/{ToggleListButton.tsx → Input/ToggleListButton.tsx} +1 -1
  172. package/src/form/combobox/SelectedOptions/SelectedOptions.tsx +1 -1
  173. package/src/form/combobox/SelectedOptions/selectedOptionsContext.tsx +12 -26
  174. package/src/form/combobox/{combobox-utils.test.ts → __tests__/combobox-utils.test.ts} +1 -1
  175. package/src/form/combobox/{combobox.test.tsx → __tests__/combobox.test.tsx} +2 -3
  176. package/src/form/combobox/customOptionsContext.tsx +14 -18
  177. package/src/form/combobox/types.ts +3 -1
  178. package/src/overlay/README.md +5 -0
  179. package/src/overlay/dismiss/DismissableLayer.tsx +368 -0
  180. package/src/overlay/dismiss/util/dispatchCustomEvent.ts +77 -0
  181. package/src/overlay/dismiss/util/useEscapeKeydown.ts +21 -0
  182. package/src/overlay/dismiss/util/useFocusOutside.ts +52 -0
  183. package/src/overlay/dismiss/util/usePointerDownOutside.ts +95 -0
  184. package/src/overlays/floating/Floating.tsx +399 -0
  185. package/src/overlays/floating/Floating.utils.ts +63 -0
  186. package/src/popover/Popover.tsx +38 -70
  187. package/src/progress-bar/ProgressBar.tsx +45 -20
  188. package/src/tabs/Tabs.context.ts +2 -0
  189. package/src/toggle-group/ToggleGroup.context.ts +1 -0
  190. package/src/util/hooks/descendants/useDescendant.tsx +55 -68
  191. package/src/util/types/AsChild.ts +15 -0
  192. package/cjs/form/combobox/ClearButton.d.ts +0 -7
  193. package/cjs/form/combobox/ClearButton.js +0 -28
  194. package/cjs/form/combobox/ClearButton.js.map +0 -1
  195. package/cjs/form/combobox/FilteredOptions/CheckIcon.d.ts +0 -3
  196. package/cjs/form/combobox/FilteredOptions/CheckIcon.js +0 -12
  197. package/cjs/form/combobox/FilteredOptions/CheckIcon.js.map +0 -1
  198. package/cjs/form/combobox/Input/inputContext.js.map +0 -1
  199. package/cjs/form/combobox/ToggleListButton.js.map +0 -1
  200. package/esm/form/combobox/ClearButton.d.ts +0 -7
  201. package/esm/form/combobox/ClearButton.js +0 -21
  202. package/esm/form/combobox/ClearButton.js.map +0 -1
  203. package/esm/form/combobox/FilteredOptions/CheckIcon.d.ts +0 -3
  204. package/esm/form/combobox/FilteredOptions/CheckIcon.js +0 -7
  205. package/esm/form/combobox/FilteredOptions/CheckIcon.js.map +0 -1
  206. package/esm/form/combobox/Input/inputContext.js.map +0 -1
  207. package/esm/form/combobox/ToggleListButton.js.map +0 -1
  208. package/src/form/combobox/ClearButton.tsx +0 -29
  209. package/src/form/combobox/FilteredOptions/CheckIcon.tsx +0 -23
  210. /package/cjs/form/combobox/{ToggleListButton.d.ts → Input/ToggleListButton.d.ts} +0 -0
  211. /package/esm/form/combobox/{ToggleListButton.d.ts → Input/ToggleListButton.d.ts} +0 -0
@@ -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
 
@@ -1,17 +1,12 @@
1
- import React, {
2
- createContext,
3
- useCallback,
4
- useContext,
5
- useMemo,
6
- useState,
7
- } from "react";
1
+ import React, { useCallback, useMemo, useState } from "react";
2
+ import { createContext } from "../../../util/create-context";
8
3
  import { usePrevious } from "../../../util/hooks";
9
- import { useInputContext } from "../Input/inputContext";
4
+ import { useInputContext } from "../Input/Input.context";
10
5
  import { isInList } from "../combobox-utils";
11
- import { useCustomOptionsContext } from "../customOptionsContext";
6
+ import { useComboboxCustomOptions } from "../customOptionsContext";
12
7
  import { ComboboxOption, ComboboxProps, MaxSelected } from "../types";
13
8
 
14
- type SelectedOptionsContextType = {
9
+ type SelectedOptionsContextValue = {
15
10
  addSelectedOption: (option: ComboboxOption) => void;
16
11
  isMultiSelect?: boolean;
17
12
  removeSelectedOption: (option: ComboboxOption) => void;
@@ -25,11 +20,10 @@ type SelectedOptionsContextType = {
25
20
  ) => void;
26
21
  };
27
22
 
28
- const SelectedOptionsContext = createContext<SelectedOptionsContextType>(
29
- {} as SelectedOptionsContextType,
30
- );
23
+ const [SelectedOptionsContextProvider, useSelectedOptionsContext] =
24
+ createContext<SelectedOptionsContextValue>();
31
25
 
32
- export const SelectedOptionsProvider = ({
26
+ const SelectedOptionsProvider = ({
33
27
  children,
34
28
  value,
35
29
  }: {
@@ -45,7 +39,7 @@ export const SelectedOptionsProvider = ({
45
39
  removeCustomOption,
46
40
  addCustomOption,
47
41
  setCustomOptions,
48
- } = useCustomOptionsContext();
42
+ } = useComboboxCustomOptions();
49
43
  const {
50
44
  allowNewValues,
51
45
  isMultiSelect,
@@ -149,18 +143,10 @@ export const SelectedOptionsProvider = ({
149
143
  };
150
144
 
151
145
  return (
152
- <SelectedOptionsContext.Provider value={selectedOptionsState}>
146
+ <SelectedOptionsContextProvider {...selectedOptionsState}>
153
147
  {children}
154
- </SelectedOptionsContext.Provider>
148
+ </SelectedOptionsContextProvider>
155
149
  );
156
150
  };
157
151
 
158
- export const useSelectedOptionsContext = () => {
159
- const context = useContext(SelectedOptionsContext);
160
- if (!context) {
161
- throw new Error(
162
- "useSelectedOptionsContext must be used within a SelectedOptionsProvider",
163
- );
164
- }
165
- return context;
166
- };
152
+ export { SelectedOptionsProvider, useSelectedOptionsContext };
@@ -2,7 +2,7 @@ import {
2
2
  isInList,
3
3
  mapToComboboxOptionArray,
4
4
  toComboboxOption,
5
- } from "./combobox-utils";
5
+ } from "../combobox-utils";
6
6
 
7
7
  const list = [
8
8
  { label: "Hjelpemidler", value: "HJE" },
@@ -1,10 +1,9 @@
1
1
  /* eslint-disable testing-library/no-unnecessary-act -- https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning */
2
- import { render, screen } from "@testing-library/react";
2
+ import { act, render, screen } from "@testing-library/react";
3
3
  import userEvent from "@testing-library/user-event";
4
4
  import React, { useId } from "react";
5
- import { act } from "react-dom/test-utils";
6
5
  import { describe, expect, test, vi } from "vitest";
7
- import { UNSAFE_Combobox } from "./index";
6
+ import { UNSAFE_Combobox } from "../index";
8
7
 
9
8
  const options = [
10
9
  "banana",
@@ -1,19 +1,23 @@
1
- import React, { createContext, useCallback, useContext, useState } from "react";
2
- import { useInputContext } from "./Input/inputContext";
1
+ import React, { useCallback, useState } from "react";
2
+ import { createContext } from "../../util/create-context";
3
+ import { useInputContext } from "./Input/Input.context";
3
4
  import { ComboboxOption } from "./types";
4
5
 
5
- type CustomOptionsContextType = {
6
+ type CustomOptionsContextValue = {
6
7
  customOptions: ComboboxOption[];
7
8
  removeCustomOption: (option: ComboboxOption) => void;
8
9
  addCustomOption: (option: ComboboxOption) => void;
9
10
  setCustomOptions: React.Dispatch<React.SetStateAction<ComboboxOption[]>>;
10
11
  };
11
12
 
12
- const CustomOptionsContext = createContext<CustomOptionsContextType>(
13
- {} as CustomOptionsContextType,
14
- );
13
+ const [ComboboxCustomOptionsProvider, useComboboxCustomOptions] =
14
+ createContext<CustomOptionsContextValue>({
15
+ name: "ComboboxCustomOptions",
16
+ errorMessage:
17
+ "useComboboxCustomOptions must be used within a ComboboxCustomOptionsProvider",
18
+ });
15
19
 
16
- export const CustomOptionsProvider = ({
20
+ const CustomOptionsProvider = ({
17
21
  children,
18
22
  value,
19
23
  }: {
@@ -54,18 +58,10 @@ export const CustomOptionsProvider = ({
54
58
  };
55
59
 
56
60
  return (
57
- <CustomOptionsContext.Provider value={customOptionsState}>
61
+ <ComboboxCustomOptionsProvider {...customOptionsState}>
58
62
  {children}
59
- </CustomOptionsContext.Provider>
63
+ </ComboboxCustomOptionsProvider>
60
64
  );
61
65
  };
62
66
 
63
- export const useCustomOptionsContext = () => {
64
- const context = useContext(CustomOptionsContext);
65
- if (!context) {
66
- throw new Error(
67
- "useCustomOptionsContext must be used within a CustomOptionsProvider",
68
- );
69
- }
70
- return context;
71
- };
67
+ export { CustomOptionsProvider, useComboboxCustomOptions };
@@ -100,7 +100,9 @@ export interface ComboboxProps
100
100
  *
101
101
  * @param event
102
102
  */
103
- onClear?: (event: React.PointerEvent | React.KeyboardEvent) => void;
103
+ onClear?: (
104
+ event: React.PointerEvent | React.KeyboardEvent | React.MouseEvent,
105
+ ) => void;
104
106
  /**
105
107
  * Callback function triggered whenever an option is selected or de-selected.
106
108
  *
@@ -0,0 +1,5 @@
1
+ # DismissableLayer API
2
+
3
+ `DismissableLayer`-API provides a robust handler for layers that can be dismissed by interacting outside of it.
4
+
5
+ One of the benefits is its ability to handle nested elements, relevant when creating nested dropdowns and similar solutions.