@fremtind/jokul 0.28.1 → 0.30.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 (279) hide show
  1. package/build/build-stats.html +1 -1
  2. package/build/cjs/components/breadcrumb/index.d.cts +2 -4
  3. package/build/cjs/components/button/index.d.cts +1 -1
  4. package/build/cjs/components/button/types.cjs.map +1 -1
  5. package/build/cjs/components/button/types.d.cts +1 -2
  6. package/build/cjs/components/card/NavCard.cjs.map +1 -1
  7. package/build/cjs/components/card/NavCard.d.cts +1 -10
  8. package/build/cjs/components/card/index.d.cts +2 -2
  9. package/build/cjs/components/card/types.cjs.map +1 -1
  10. package/build/cjs/components/card/types.d.cts +8 -0
  11. package/build/cjs/components/combobox/Combobox.cjs.map +1 -1
  12. package/build/cjs/components/combobox/Combobox.d.cts +6 -7
  13. package/build/cjs/components/combobox/index.d.cts +1 -1
  14. package/build/cjs/components/cookie-consent/index.d.cts +2 -4
  15. package/build/cjs/components/datepicker/index.cjs +1 -1
  16. package/build/cjs/components/datepicker/index.d.cts +3 -3
  17. package/build/cjs/components/datepicker/types.d.cts +7 -0
  18. package/build/cjs/components/datepicker/utils.cjs +1 -1
  19. package/build/cjs/components/datepicker/utils.cjs.map +1 -1
  20. package/build/cjs/components/datepicker/utils.d.cts +0 -1
  21. package/build/cjs/components/datepicker/validation.cjs.map +1 -1
  22. package/build/cjs/components/datepicker/validation.d.cts +1 -8
  23. package/build/cjs/components/description-list/index.d.cts +1 -1
  24. package/build/cjs/components/expander/Expander.cjs.map +1 -1
  25. package/build/cjs/components/expander/Expander.d.cts +1 -2
  26. package/build/cjs/components/expander/index.d.cts +2 -4
  27. package/build/cjs/components/feedback/Feedback.cjs.map +1 -1
  28. package/build/cjs/components/feedback/Feedback.d.cts +4 -9
  29. package/build/cjs/components/feedback/followup/Followup.cjs.map +1 -1
  30. package/build/cjs/components/feedback/followup/Followup.d.cts +3 -14
  31. package/build/cjs/components/feedback/index.d.cts +3 -3
  32. package/build/cjs/components/feedback/presets.cjs.map +1 -1
  33. package/build/cjs/components/feedback/presets.d.cts +2 -5
  34. package/build/cjs/components/feedback/questions/ContactQuestion.cjs.map +1 -1
  35. package/build/cjs/components/feedback/questions/ContactQuestion.d.cts +3 -28
  36. package/build/cjs/components/feedback/types.d.cts +42 -7
  37. package/build/cjs/components/icon-button/index.d.cts +1 -2
  38. package/build/cjs/components/image/index.d.cts +1 -3
  39. package/build/cjs/components/index.cjs +1 -1
  40. package/build/cjs/components/index.d.cts +1 -1
  41. package/build/cjs/components/input-panel/BasePanel.cjs +2 -0
  42. package/build/cjs/components/input-panel/BasePanel.cjs.map +1 -0
  43. package/build/cjs/components/input-panel/BasePanel.d.cts +10 -0
  44. package/build/cjs/components/input-panel/CheckboxPanel.cjs +2 -0
  45. package/build/cjs/components/input-panel/CheckboxPanel.cjs.map +1 -0
  46. package/build/cjs/components/input-panel/CheckboxPanel.d.cts +7 -0
  47. package/build/cjs/components/input-panel/RadioPanel.cjs +2 -0
  48. package/build/cjs/components/input-panel/RadioPanel.cjs.map +1 -0
  49. package/build/cjs/components/{radio-panel → input-panel}/RadioPanel.d.cts +2 -4
  50. package/build/cjs/components/input-panel/RadioPanelGroup.cjs +2 -0
  51. package/build/cjs/components/input-panel/RadioPanelGroup.cjs.map +1 -0
  52. package/build/cjs/components/input-panel/RadioPanelGroup.d.cts +4 -0
  53. package/build/cjs/components/input-panel/documentation/checkbox-panel/ControlledExample.d.cts +4 -0
  54. package/build/cjs/components/input-panel/documentation/checkbox-panel/UncontrolledExample.d.cts +4 -0
  55. package/build/cjs/components/input-panel/documentation/radio-panel/ControlledExample.d.cts +4 -0
  56. package/build/cjs/components/input-panel/documentation/radio-panel/UncontrolledExample.d.cts +4 -0
  57. package/build/cjs/components/input-panel/index.cjs +2 -0
  58. package/build/cjs/components/input-panel/index.d.cts +3 -0
  59. package/build/cjs/components/input-panel/radioPanelContext.cjs +2 -0
  60. package/build/cjs/components/input-panel/radioPanelContext.cjs.map +1 -0
  61. package/build/cjs/components/input-panel/radioPanelContext.d.cts +7 -0
  62. package/build/cjs/components/link-list/LinkList.cjs.map +1 -1
  63. package/build/cjs/components/link-list/LinkList.d.cts +2 -11
  64. package/build/cjs/components/link-list/index.d.cts +1 -0
  65. package/build/cjs/components/link-list/types.cjs +2 -0
  66. package/build/cjs/components/link-list/types.cjs.map +1 -0
  67. package/build/cjs/components/link-list/types.d.cts +11 -0
  68. package/build/cjs/components/list/index.d.cts +2 -3
  69. package/build/cjs/components/loader/index.d.cts +9 -18
  70. package/build/cjs/components/logo/index.d.cts +2 -4
  71. package/build/cjs/components/menu/Menu.cjs +1 -1
  72. package/build/cjs/components/menu/Menu.cjs.map +1 -1
  73. package/build/cjs/components/modal/Modal.cjs.map +1 -1
  74. package/build/cjs/components/modal/Modal.d.cts +8 -2
  75. package/build/cjs/components/modal/index.d.cts +2 -4
  76. package/build/cjs/components/pagination/Pagination.cjs.map +1 -1
  77. package/build/cjs/components/pagination/Pagination.d.cts +2 -1
  78. package/build/cjs/components/pagination/index.d.cts +1 -1
  79. package/build/cjs/components/popover/Popover.cjs.map +1 -1
  80. package/build/cjs/components/popover/Popover.d.cts +6 -6
  81. package/build/cjs/components/popover/index.d.cts +1 -1
  82. package/build/cjs/components/progress-bar/index.d.cts +2 -4
  83. package/build/cjs/components/radio-button/index.d.cts +3 -6
  84. package/build/cjs/components/select/Select.cjs.map +1 -1
  85. package/build/cjs/components/select/Select.d.cts +5 -6
  86. package/build/cjs/components/select/index.d.cts +2 -4
  87. package/build/cjs/components/summary-table/SummaryTable.cjs.map +1 -1
  88. package/build/cjs/components/summary-table/SummaryTable.d.cts +2 -2
  89. package/build/cjs/components/summary-table/index.d.cts +2 -2
  90. package/build/cjs/components/system-message/SystemMessage.cjs.map +1 -1
  91. package/build/cjs/components/system-message/SystemMessage.d.cts +5 -6
  92. package/build/cjs/components/system-message/index.d.cts +1 -1
  93. package/build/cjs/components/tabs/index.d.cts +6 -6
  94. package/build/cjs/components/tag/index.d.cts +1 -3
  95. package/build/cjs/components/text-input/BaseTextArea.cjs.map +1 -1
  96. package/build/cjs/components/text-input/BaseTextArea.d.cts +1 -2
  97. package/build/cjs/components/text-input/index.d.cts +2 -2
  98. package/build/cjs/components/toast/index.d.cts +1 -1
  99. package/build/cjs/components/toast/toastContext.cjs.map +1 -1
  100. package/build/cjs/components/toast/toastContext.d.cts +1 -13
  101. package/build/cjs/components/toast/types.d.cts +11 -0
  102. package/build/cjs/components/toggle-switch/ToggleSlider.cjs.map +1 -1
  103. package/build/cjs/components/toggle-switch/ToggleSlider.d.cts +2 -3
  104. package/build/cjs/components/toggle-switch/ToggleSwitch.cjs.map +1 -1
  105. package/build/cjs/components/toggle-switch/ToggleSwitch.d.cts +1 -1
  106. package/build/cjs/components/toggle-switch/index.d.cts +2 -2
  107. package/build/cjs/components/tooltip/Tooltip.cjs +1 -1
  108. package/build/cjs/components/tooltip/Tooltip.cjs.map +1 -1
  109. package/build/cjs/components/tooltip/Tooltip.d.cts +2 -2
  110. package/build/cjs/components/tooltip/TooltipContent.cjs +1 -1
  111. package/build/cjs/components/tooltip/TooltipContent.cjs.map +1 -1
  112. package/build/cjs/components/tooltip/TooltipTrigger.cjs +1 -1
  113. package/build/cjs/components/tooltip/TooltipTrigger.cjs.map +1 -1
  114. package/build/cjs/index.cjs +1 -1
  115. package/build/es/components/breadcrumb/index.d.ts +2 -4
  116. package/build/es/components/button/index.d.ts +1 -1
  117. package/build/es/components/button/types.d.ts +1 -2
  118. package/build/es/components/button/types.js.map +1 -1
  119. package/build/es/components/card/NavCard.d.ts +1 -10
  120. package/build/es/components/card/NavCard.js.map +1 -1
  121. package/build/es/components/card/index.d.ts +2 -2
  122. package/build/es/components/card/types.d.ts +8 -0
  123. package/build/es/components/card/types.js.map +1 -1
  124. package/build/es/components/combobox/Combobox.d.ts +6 -7
  125. package/build/es/components/combobox/Combobox.js.map +1 -1
  126. package/build/es/components/combobox/index.d.ts +1 -1
  127. package/build/es/components/cookie-consent/index.d.ts +2 -4
  128. package/build/es/components/datepicker/index.d.ts +3 -3
  129. package/build/es/components/datepicker/index.js +1 -1
  130. package/build/es/components/datepicker/types.d.ts +7 -0
  131. package/build/es/components/datepicker/utils.d.ts +0 -1
  132. package/build/es/components/datepicker/utils.js +1 -1
  133. package/build/es/components/datepicker/utils.js.map +1 -1
  134. package/build/es/components/datepicker/validation.d.ts +1 -8
  135. package/build/es/components/datepicker/validation.js.map +1 -1
  136. package/build/es/components/description-list/index.d.ts +1 -1
  137. package/build/es/components/expander/Expander.d.ts +1 -2
  138. package/build/es/components/expander/Expander.js.map +1 -1
  139. package/build/es/components/expander/index.d.ts +2 -4
  140. package/build/es/components/feedback/Feedback.d.ts +4 -9
  141. package/build/es/components/feedback/Feedback.js.map +1 -1
  142. package/build/es/components/feedback/followup/Followup.d.ts +3 -14
  143. package/build/es/components/feedback/followup/Followup.js.map +1 -1
  144. package/build/es/components/feedback/index.d.ts +3 -3
  145. package/build/es/components/feedback/presets.d.ts +2 -5
  146. package/build/es/components/feedback/presets.js.map +1 -1
  147. package/build/es/components/feedback/questions/ContactQuestion.d.ts +3 -28
  148. package/build/es/components/feedback/questions/ContactQuestion.js.map +1 -1
  149. package/build/es/components/feedback/types.d.ts +42 -7
  150. package/build/es/components/icon-button/index.d.ts +1 -2
  151. package/build/es/components/image/index.d.ts +1 -3
  152. package/build/es/components/index.d.ts +1 -1
  153. package/build/es/components/index.js +1 -1
  154. package/build/es/components/input-panel/BasePanel.d.ts +10 -0
  155. package/build/es/components/input-panel/BasePanel.js +2 -0
  156. package/build/es/components/input-panel/BasePanel.js.map +1 -0
  157. package/build/es/components/input-panel/CheckboxPanel.d.ts +7 -0
  158. package/build/es/components/input-panel/CheckboxPanel.js +2 -0
  159. package/build/es/components/input-panel/CheckboxPanel.js.map +1 -0
  160. package/build/es/components/{radio-panel → input-panel}/RadioPanel.d.ts +2 -4
  161. package/build/es/components/input-panel/RadioPanel.js +2 -0
  162. package/build/es/components/input-panel/RadioPanel.js.map +1 -0
  163. package/build/es/components/input-panel/RadioPanelGroup.d.ts +4 -0
  164. package/build/es/components/input-panel/RadioPanelGroup.js +2 -0
  165. package/build/es/components/input-panel/RadioPanelGroup.js.map +1 -0
  166. package/build/es/components/input-panel/documentation/checkbox-panel/ControlledExample.d.ts +4 -0
  167. package/build/es/components/input-panel/documentation/checkbox-panel/UncontrolledExample.d.ts +4 -0
  168. package/build/es/components/input-panel/documentation/radio-panel/ControlledExample.d.ts +4 -0
  169. package/build/es/components/input-panel/documentation/radio-panel/UncontrolledExample.d.ts +4 -0
  170. package/build/es/components/input-panel/index.d.ts +3 -0
  171. package/build/es/components/input-panel/index.js +2 -0
  172. package/build/es/components/input-panel/radioPanelContext.d.ts +7 -0
  173. package/build/es/components/input-panel/radioPanelContext.js +2 -0
  174. package/build/es/components/input-panel/radioPanelContext.js.map +1 -0
  175. package/build/es/components/link-list/LinkList.d.ts +2 -11
  176. package/build/es/components/link-list/LinkList.js.map +1 -1
  177. package/build/es/components/link-list/index.d.ts +1 -0
  178. package/build/es/components/link-list/types.d.ts +11 -0
  179. package/build/es/components/link-list/types.js +2 -0
  180. package/build/es/components/link-list/types.js.map +1 -0
  181. package/build/es/components/list/index.d.ts +2 -3
  182. package/build/es/components/loader/index.d.ts +9 -18
  183. package/build/es/components/logo/index.d.ts +2 -4
  184. package/build/es/components/menu/Menu.js +1 -1
  185. package/build/es/components/menu/Menu.js.map +1 -1
  186. package/build/es/components/modal/Modal.d.ts +8 -2
  187. package/build/es/components/modal/Modal.js.map +1 -1
  188. package/build/es/components/modal/index.d.ts +2 -4
  189. package/build/es/components/pagination/Pagination.d.ts +2 -1
  190. package/build/es/components/pagination/Pagination.js.map +1 -1
  191. package/build/es/components/pagination/index.d.ts +1 -1
  192. package/build/es/components/popover/Popover.d.ts +6 -6
  193. package/build/es/components/popover/Popover.js.map +1 -1
  194. package/build/es/components/popover/index.d.ts +1 -1
  195. package/build/es/components/progress-bar/index.d.ts +2 -4
  196. package/build/es/components/radio-button/index.d.ts +3 -6
  197. package/build/es/components/select/Select.d.ts +5 -6
  198. package/build/es/components/select/Select.js.map +1 -1
  199. package/build/es/components/select/index.d.ts +2 -4
  200. package/build/es/components/summary-table/SummaryTable.d.ts +2 -2
  201. package/build/es/components/summary-table/SummaryTable.js.map +1 -1
  202. package/build/es/components/summary-table/index.d.ts +2 -2
  203. package/build/es/components/system-message/SystemMessage.d.ts +5 -6
  204. package/build/es/components/system-message/SystemMessage.js.map +1 -1
  205. package/build/es/components/system-message/index.d.ts +1 -1
  206. package/build/es/components/tabs/index.d.ts +6 -6
  207. package/build/es/components/tag/index.d.ts +1 -3
  208. package/build/es/components/text-input/BaseTextArea.d.ts +1 -2
  209. package/build/es/components/text-input/BaseTextArea.js.map +1 -1
  210. package/build/es/components/text-input/index.d.ts +2 -2
  211. package/build/es/components/toast/index.d.ts +1 -1
  212. package/build/es/components/toast/toastContext.d.ts +1 -13
  213. package/build/es/components/toast/toastContext.js.map +1 -1
  214. package/build/es/components/toast/types.d.ts +11 -0
  215. package/build/es/components/toggle-switch/ToggleSlider.d.ts +2 -3
  216. package/build/es/components/toggle-switch/ToggleSlider.js.map +1 -1
  217. package/build/es/components/toggle-switch/ToggleSwitch.d.ts +1 -1
  218. package/build/es/components/toggle-switch/ToggleSwitch.js.map +1 -1
  219. package/build/es/components/toggle-switch/index.d.ts +2 -2
  220. package/build/es/components/tooltip/Tooltip.d.ts +2 -2
  221. package/build/es/components/tooltip/Tooltip.js +1 -1
  222. package/build/es/components/tooltip/Tooltip.js.map +1 -1
  223. package/build/es/components/tooltip/TooltipContent.js +1 -1
  224. package/build/es/components/tooltip/TooltipContent.js.map +1 -1
  225. package/build/es/components/tooltip/TooltipTrigger.js +1 -1
  226. package/build/es/components/tooltip/TooltipTrigger.js.map +1 -1
  227. package/build/es/index.js +1 -1
  228. package/package.json +12 -3
  229. package/styles/components/button/button.css +2 -2
  230. package/styles/components/button/button.min.css +1 -1
  231. package/styles/components/checkbox/checkbox.css +4 -4
  232. package/styles/components/checkbox/checkbox.min.css +1 -1
  233. package/styles/components/feedback/feedback.css +2 -2
  234. package/styles/components/feedback/feedback.min.css +1 -1
  235. package/styles/components/input-group/input-group.css +2 -2
  236. package/styles/components/input-group/input-group.min.css +1 -1
  237. package/styles/components/input-panel/_index.scss +2 -0
  238. package/styles/components/input-panel/checkbox-panel.css +132 -0
  239. package/styles/components/input-panel/checkbox-panel.min.css +1 -0
  240. package/styles/components/input-panel/checkbox-panel.scss +88 -0
  241. package/styles/components/{radio-panel → input-panel}/radio-panel.css +67 -56
  242. package/styles/components/input-panel/radio-panel.min.css +1 -0
  243. package/styles/components/input-panel/radio-panel.scss +79 -0
  244. package/styles/components/input-panel/shared.css +61 -0
  245. package/styles/components/input-panel/shared.min.css +1 -0
  246. package/styles/components/input-panel/shared.scss +75 -0
  247. package/styles/components/loader/loader.css +6 -6
  248. package/styles/components/loader/loader.min.css +1 -1
  249. package/styles/components/loader/skeleton-loader.css +5 -5
  250. package/styles/components/loader/skeleton-loader.min.css +1 -1
  251. package/styles/components/message/message.css +2 -2
  252. package/styles/components/message/message.min.css +1 -1
  253. package/styles/components/progress-bar/progress-bar.css +2 -2
  254. package/styles/components/progress-bar/progress-bar.min.css +1 -1
  255. package/styles/components/radio-button/radio-button.css +2 -2
  256. package/styles/components/radio-button/radio-button.min.css +1 -1
  257. package/styles/components/system-message/system-message.css +2 -2
  258. package/styles/components/system-message/system-message.min.css +1 -1
  259. package/styles/components/toast/toast.css +4 -4
  260. package/styles/components/toast/toast.min.css +1 -1
  261. package/styles/components/tooltip/tooltip.css +2 -26
  262. package/styles/components/tooltip/tooltip.min.css +1 -1
  263. package/styles/components/tooltip/tooltip.scss +3 -31
  264. package/styles/styles.css +224 -166
  265. package/styles/styles.min.css +1 -1
  266. package/styles/styles.scss +1 -1
  267. package/build/cjs/components/radio-panel/RadioPanel.cjs +0 -2
  268. package/build/cjs/components/radio-panel/RadioPanel.cjs.map +0 -1
  269. package/build/cjs/components/radio-panel/index.cjs +0 -2
  270. package/build/cjs/components/radio-panel/index.d.cts +0 -1
  271. package/build/es/components/radio-panel/RadioPanel.js +0 -2
  272. package/build/es/components/radio-panel/RadioPanel.js.map +0 -1
  273. package/build/es/components/radio-panel/index.d.ts +0 -1
  274. package/build/es/components/radio-panel/index.js +0 -2
  275. package/styles/components/radio-panel/_index.scss +0 -1
  276. package/styles/components/radio-panel/radio-panel.min.css +0 -1
  277. package/styles/components/radio-panel/radio-panel.scss +0 -140
  278. /package/build/cjs/components/{radio-panel → input-panel}/index.cjs.map +0 -0
  279. /package/build/es/components/{radio-panel → input-panel}/index.js.map +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"Combobox.js","sources":["../../../../src/components/combobox/Combobox.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React, {\n ChangeEvent,\n FC,\n FocusEvent,\n KeyboardEvent,\n MouseEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { Density } from \"../../core/types.js\";\nimport { useAnimatedHeight } from \"../../hooks/useAnimatedHeight/useAnimatedHeight.js\";\nimport { useId } from \"../../hooks/useId/useId.js\";\nimport { useListNavigation } from \"../../hooks/useListNavigation/useListNavigation.js\";\nimport { ValuePair } from \"../../utilities/valuePair.js\";\nimport { ArrowVerticalAnimated } from \"../icon/icons/animated/ArrowVerticalAnimated.js\";\nimport { CheckIcon } from \"../icon/icons/CheckIcon.js\";\nimport { IconButton } from \"../icon-button/IconButton.js\";\nimport { InputGroup, InputGroupProps } from \"../input-group/InputGroup.js\";\nimport { LabelProps } from \"../input-group/Label.js\";\nimport { Tag } from \"../tag/Tag.js\";\nimport { Tooltip } from \"../tooltip/Tooltip.js\";\nimport { TooltipContent } from \"../tooltip/TooltipContent.js\";\nimport { TooltipTrigger } from \"../tooltip/TooltipTrigger.js\";\n\nexport type ComboboxValuePair = ValuePair & {\n tagLabel?: string;\n isMarked?: boolean;\n};\n\nexport function getComboboxValuePair(\n item: string | ComboboxValuePair,\n): ComboboxValuePair {\n return typeof item === \"string\" ? { value: item, label: item } : item;\n}\n\ninterface PartialChangeEvent\n extends Partial<Omit<ChangeEvent<HTMLElement>, \"target\">> {\n type: \"change\" | \"blur\";\n target: {\n name: string;\n value: string;\n selectedOptions: Array<ValuePair>;\n };\n}\n\ntype ChangeEventHandler = (event: PartialChangeEvent) => void;\n\ninterface ComboboxProps extends InputGroupProps {\n id?: string;\n placeholder?: string;\n labelProps?: Omit<\n LabelProps,\n \"children\" | \"density\" | \"htmlFor\" | \"standAlone\"\n >;\n items: Array<ValuePair>;\n noMatchingOption?: string;\n label: string;\n name: string;\n value?: Array<ValuePair>;\n density?: Density;\n width?: string;\n helpLabel?: string;\n errorLabel?: string;\n className?: string;\n invalid?: boolean;\n hasTagHover?: boolean;\n onChange: ChangeEventHandler;\n onBlur?: ChangeEventHandler;\n onFocus?: ChangeEventHandler;\n}\n\nexport const Combobox: FC<ComboboxProps> = ({\n id,\n placeholder,\n items,\n onChange,\n onFocus,\n onBlur,\n value,\n label,\n noMatchingOption,\n labelProps,\n helpLabel,\n errorLabel,\n width,\n density,\n name,\n className,\n invalid,\n hasTagHover,\n}) => {\n const listId = useId(id || \"jkl-combobox\", { generateSuffix: !id });\n const labelId = `${listId}_label`;\n const buttonId = `${listId}_button`;\n const inputId = `${listId}_search-input`;\n\n const [selectedValue, setSelectedValue] = useState<\n Array<ComboboxValuePair>\n >(value || []);\n const [isPointingDown, setIsPointingDown] = useState<boolean>(true);\n const [showMenu, setShowMenu] = useState<boolean>(false);\n const [searchValue, setSearchValue] = useState<string>(\"\");\n const [noResults, setNoResults] = useState(false);\n const [marked, setMarked] = useState<boolean>(false);\n\n const searchRef = useRef<HTMLInputElement>(null);\n const inputRef = useRef<HTMLDivElement>(null);\n const focusInsideRef = useRef(false);\n\n useEffect(() => {\n setSearchValue(\"\");\n if (showMenu && searchRef.current) {\n searchRef.current.focus();\n }\n }, [showMenu]);\n\n useEffect(() => {\n setSelectedValue((prev) => value || prev);\n }, [value]);\n\n // Funksjon for å stile valgt element\n const isSelected = (option: ValuePair) => {\n if (!selectedValue) {\n return false;\n } else {\n return selectedValue.some((value) => value.value === option.value);\n }\n };\n\n // Fjerne ett eller flere valg\n const removeOption = useCallback(\n (option: string) => {\n return selectedValue.filter((value) => value.value !== option);\n },\n [selectedValue],\n );\n\n const onTagRemove = useCallback(\n (\n e:\n | React.MouseEvent<HTMLButtonElement, globalThis.MouseEvent>\n | React.KeyboardEvent<HTMLInputElement>,\n option: string,\n ) => {\n let newValue = removeOption(option);\n setSelectedValue(newValue);\n onChange({\n type: \"change\",\n target: { name, value: option, selectedOptions: newValue },\n });\n e.stopPropagation();\n\n if (newValue.length === 0) {\n setMarked(false);\n }\n },\n [removeOption, setSelectedValue, onChange, name, setMarked],\n );\n\n // Håndtere valgt verdi i listen\n const onItemClick = useCallback(\n (option: string) => {\n let newValue: Array<ValuePair>;\n\n if (selectedValue.some((value) => value.value === option)) {\n newValue = removeOption(option);\n } else {\n const item = items.find((i) => i.value === option);\n newValue = [...selectedValue, item as ValuePair];\n }\n searchRef.current?.focus();\n setSelectedValue(newValue);\n onChange({\n type: \"change\",\n target: { name, value: option, selectedOptions: newValue },\n });\n },\n [selectedValue, setSelectedValue, onChange, name, removeOption, items],\n );\n\n // Funksjon for søk\n const onSearch = (e: {\n target: { value: React.SetStateAction<string> };\n }) => {\n searchRef.current?.focus();\n setShowMenu(true);\n setSearchValue(e.target.value);\n };\n\n const options = useMemo(() => {\n if (!searchValue) {\n return items;\n }\n\n const filteredOptions = items.filter(\n (option) =>\n option.label.toLowerCase().indexOf(searchValue.toLowerCase()) >=\n 0,\n );\n\n setNoResults(filteredOptions.length === 0);\n\n return filteredOptions;\n }, [searchValue, items]);\n\n // Det første elementet i listen skal være aktivt fram til brukeren klikker på noe annet\n const [activeDescendant, setActiveDescendant] = useState<\n string | undefined\n >(options[0]?.value ? `${listId}-${options[0]?.value}` : undefined);\n\n // Håndtere arrow-state\n useEffect(() => {\n if (showMenu) {\n setIsPointingDown(false);\n } else {\n setIsPointingDown(true);\n }\n }, [showMenu]);\n\n // Lukk meny med ESC\n useEffect(() => {\n const handleEscape = (e: globalThis.KeyboardEvent) => {\n if (e.key === \"Escape\" && showMenu) {\n setShowMenu(false);\n }\n };\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"keydown\", handleEscape);\n }\n return () => {\n if (typeof window !== \"undefined\" && showMenu) {\n window.removeEventListener(\"keydown\", handleEscape);\n }\n };\n }, [setShowMenu, showMenu]);\n\n // Fokushåndtering\n const handleFocusPlacement = useCallback((isOpen: boolean) => {\n if (isOpen) {\n if (searchRef.current) {\n searchRef.current.focus();\n }\n } else {\n if (focusInsideRef.current && inputRef.current) {\n inputRef.current.focus();\n }\n }\n }, []);\n\n const handleFocus = useCallback(() => {\n if (!focusInsideRef.current) {\n if (onFocus) {\n onFocus({\n type: \"change\",\n target: {\n name,\n value: selectedValue?.[0].value || \"\",\n selectedOptions: selectedValue,\n },\n });\n }\n focusInsideRef.current = true;\n setShowMenu(true);\n }\n }, [onFocus, selectedValue, name]);\n\n const [dropdownRef] = useAnimatedHeight<HTMLDivElement>(showMenu, {\n onFirstVisible: handleFocusPlacement,\n onTransitionEnd: handleFocusPlacement,\n });\n\n useListNavigation({ ref: dropdownRef });\n\n const componentRootElementRef = useRef<HTMLDivElement>(null);\n\n const handleBlur = useCallback(\n (\n e: FocusEvent<\n HTMLDivElement | HTMLInputElement | HTMLButtonElement\n >,\n ) => {\n const componentRootElement = componentRootElementRef.current;\n const nextFocusIsInsideComponent =\n componentRootElement &&\n componentRootElement.contains(e.relatedTarget as Node);\n if (!nextFocusIsInsideComponent) {\n setSearchValue(\"\");\n\n if (onBlur) {\n onBlur({\n type: \"blur\",\n target: {\n name,\n value: selectedValue?.[0]?.value || \"\",\n selectedOptions: selectedValue,\n },\n });\n inputRef.current?.dispatchEvent(\n new Event(\"focusout\", { bubbles: true }),\n );\n }\n focusInsideRef.current = false;\n setShowMenu(false);\n }\n },\n [onBlur, name, selectedValue],\n );\n\n const handleMouseOver = useCallback((e: MouseEvent<HTMLButtonElement>) => {\n // Ved mouseOver på options flytter vi fokus til dem for å unngå \"dobbel fokus\"\n // der det ser ut som to forskjellige elementer er fokusert/hovered samtidig\n (e.target as HTMLButtonElement).focus({ preventScroll: true });\n }, []);\n\n // Tastaturnavigasjon\n const handleSearchOnKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n e.stopPropagation();\n const listElement = dropdownRef.current;\n if (listElement) {\n listElement\n .querySelector<HTMLButtonElement>('[role=\"option\"]')\n ?.focus();\n }\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n e.stopPropagation();\n setShowMenu(false);\n }\n\n if ((e.metaKey && e.key === \"a\") || (e.ctrlKey && e.key === \"a\")) {\n e.preventDefault();\n e.stopPropagation();\n const updatedSelectedValue = selectedValue.map((item) => ({\n ...item,\n isMarked: true,\n }));\n setMarked(true);\n setSelectedValue(updatedSelectedValue);\n } else if (e.key === \"Backspace\") {\n e.stopPropagation();\n setMarked(false);\n\n // Sjekk om selectedValue er markert\n const selectedValueIsMarked = selectedValue.some(\n (item) => item.isMarked,\n );\n\n if (selectedValueIsMarked) {\n const updatedSelectedValue = selectedValue.filter(\n (item) => !item.isMarked,\n );\n setSelectedValue(updatedSelectedValue);\n setSearchValue(\"\");\n } else if (selectedValue.length > 0 && searchValue === \"\") {\n // Hvis ingen items er markert, fjern siste valgte item\n onTagRemove(\n e,\n selectedValue[selectedValue.length - 1].value,\n );\n }\n }\n },\n [selectedValue, searchValue, dropdownRef, onTagRemove],\n );\n\n const handleOptionOnKeyDown = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === \"Tab\") {\n if (searchRef.current) {\n e.preventDefault();\n e.stopPropagation();\n\n if (e.shiftKey) {\n searchRef.current.focus();\n } else {\n setShowMenu(false);\n searchRef.current.focus();\n }\n }\n } else if (e.key === \"ArrowUp\") {\n if (dropdownRef.current && searchRef.current) {\n // Can't be based on index since the first item might be filtered out\n const firstVisible = dropdownRef.current.querySelector(\n '[role=\"option\"]:not([hidden])',\n );\n if (\n e.currentTarget.id === firstVisible?.id &&\n searchRef.current\n ) {\n searchRef.current.focus();\n }\n }\n }\n },\n [setShowMenu, dropdownRef],\n );\n\n const hasSelection = selectedValue.length >= 1;\n\n return (\n <InputGroup\n label={label}\n id={inputId}\n ref={componentRootElementRef}\n data-testid=\"jkl-combobox\"\n className={clsx(\"jkl-combobox\", className, {\n \"jkl-combobox--invalid\": !!errorLabel || invalid,\n \"jkl-combobox--menu-open\": showMenu,\n \"jkl-combobox--menu-closed\": !showMenu && hasSelection,\n })}\n labelProps={{\n id: labelId,\n ...labelProps,\n }}\n helpLabel={helpLabel}\n errorLabel={errorLabel}\n density={density}\n render={(inputProps) => (\n <div\n className={clsx(\"jkl-combobox__wrapper\", {\n \"jkl-combobox__wrapper--active-value\": hasSelection,\n })}\n style={{ width }}\n tabIndex={-1}\n onFocus={handleFocus}\n onBlur={handleBlur}\n >\n <div\n className=\"jkl-combobox__tags\"\n data-testid=\"jkl-combobox__tags\"\n >\n {selectedValue\n .map(getComboboxValuePair)\n .map((option) => (\n <Tag\n key={option.value}\n className={`jkl-tag ${\n marked && \"jkl-tag__marked\"\n }`}\n data-testid=\"jkl-tag\"\n dismissAction={{\n onClick: (e) => {\n if (searchRef.current) {\n searchRef.current.focus();\n }\n onTagRemove(e, option.value);\n },\n onBlur: handleBlur,\n label: `Fjern ${option.value}`,\n }}\n >\n {hasTagHover ? (\n <Tooltip key={option.value}>\n <TooltipTrigger>\n {\" \"}\n <span\n aria-hidden=\"true\"\n data-testid=\"jkl-tag__content\"\n >\n {option.tagLabel\n ? option.tagLabel\n : option.label}\n </span>\n </TooltipTrigger>\n <TooltipContent>\n {option.label}\n </TooltipContent>\n </Tooltip>\n ) : (\n <span\n aria-hidden=\"true\"\n data-testid=\"jkl-tag__content\"\n >\n {option.tagLabel\n ? option.tagLabel\n : option.label}\n </span>\n )}\n </Tag>\n ))}\n <input\n {...inputProps}\n className=\"jkl-combobox__search-input\"\n onChange={onSearch}\n data-testid=\"jkl-combobox__search-input\"\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={handleSearchOnKeyDown}\n value={searchValue}\n ref={searchRef}\n aria-controls={listId}\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={showMenu}\n placeholder={\n selectedValue.length > 0 ? \"\" : placeholder\n }\n autoComplete=\"off\"\n />\n </div>\n\n <div\n className=\"jkl-combobox__menu\"\n role=\"listbox\"\n ref={dropdownRef}\n id={listId}\n aria-labelledby={labelId}\n aria-multiselectable=\"true\"\n aria-activedescendant={activeDescendant}\n onFocus={handleFocus}\n onBlur={handleBlur}\n tabIndex={-1}\n >\n {options.map((option, i) => (\n <button\n key={`${listId}-${option.value}`}\n type=\"button\"\n id={`${listId}__${option.value}`}\n aria-selected={isSelected(option)}\n role=\"option\"\n value={option.value}\n onBlur={handleBlur}\n className={`jkl-combobox__option ${\n isSelected(option) &&\n \"jkl-combobox__option--selected\"\n }`}\n data-testid=\"jkl-combobox__option\"\n data-testautoid={`jkl-combobox__option-${i}`}\n onFocus={handleFocus}\n onKeyDown={handleOptionOnKeyDown}\n onClick={(e) => {\n setActiveDescendant(\n `${listId}__${option.value}`,\n ); // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/listbox_role#required_javascript_features\n e.stopPropagation();\n onItemClick(option.value);\n setSearchValue(\"\");\n }}\n onMouseOver={handleMouseOver}\n >\n {option.description ? (\n <span>\n {option.label}\n <span className=\"jkl-combobox__option-description\">\n {option.description}\n </span>\n </span>\n ) : (\n option.label\n )}\n {isSelected(option) ? (\n <span>\n <CheckIcon />{\" \"}\n </span>\n ) : null}\n </button>\n ))}\n {noResults && (\n <div className=\"jkl-combobox__no-option\">\n {noMatchingOption}\n </div>\n )}\n </div>\n <div className=\"jkl-combobox__actions\">\n <IconButton\n id={buttonId}\n onFocus={handleFocus}\n onBlur={handleBlur}\n className=\"jkl-combobox__button\"\n data-testid=\"jkl-combobox__button\"\n aria-label={`${\n selectedValue.map((value) => value.label) ||\n \"Velg\"\n },${label}`}\n aria-expanded={showMenu}\n aria-controls={listId}\n role=\"button\"\n onClick={() => setShowMenu(true)}\n onMouseDown={(e) => {\n e.preventDefault();\n inputRef.current?.focus();\n }}\n >\n <ArrowVerticalAnimated\n pointingDown={isPointingDown}\n />\n </IconButton>\n </div>\n </div>\n )}\n />\n );\n};\nCombobox.displayName = \"Combobox\";\n"],"names":["getComboboxValuePair","item","value","label","Combobox","id","placeholder","items","onChange","onFocus","onBlur","noMatchingOption","labelProps","helpLabel","errorLabel","width","density","name","className","invalid","hasTagHover","listId","useId","generateSuffix","labelId","buttonId","inputId","selectedValue","setSelectedValue","useState","isPointingDown","setIsPointingDown","showMenu","setShowMenu","searchValue","setSearchValue","noResults","setNoResults","marked","setMarked","searchRef","useRef","inputRef","focusInsideRef","useEffect","current","focus","prev","isSelected","option","some","removeOption","useCallback","filter","onTagRemove","e","newValue","type","target","selectedOptions","stopPropagation","length","onItemClick","find","i","_a","onSearch","options","useMemo","filteredOptions","toLowerCase","indexOf","activeDescendant","setActiveDescendant","_b","handleEscape","key","window","addEventListener","removeEventListener","handleFocusPlacement","isOpen","handleFocus","dropdownRef","useAnimatedHeight","onFirstVisible","onTransitionEnd","useListNavigation","ref","componentRootElementRef","handleBlur","componentRootElement","contains","relatedTarget","dispatchEvent","Event","bubbles","handleMouseOver","preventScroll","handleSearchOnKeyDown","preventDefault","listElement","querySelector","metaKey","ctrlKey","updatedSelectedValue","map","isMarked","handleOptionOnKeyDown","shiftKey","firstVisible","currentTarget","hasSelection","jsx","InputGroup","clsx","render","inputProps","jsxs","style","tabIndex","children","Tag","dismissAction","onClick","Tooltip","TooltipTrigger","tagLabel","TooltipContent","onKeyDown","role","autoComplete","onMouseOver","description","CheckIcon","IconButton","onMouseDown","ArrowVerticalAnimated","pointingDown","displayName"],"mappings":"82BAiCO,SAASA,EACZC,GAEO,MAAgB,iBAATA,EAAoB,CAAEC,MAAOD,EAAME,MAAOF,GAASA,CACrE,CAsCO,MAAMG,EAA8B,EACvCC,GAAAA,EACAC,YAAAA,EACAC,MAAAA,EACAC,SAAAA,EACAC,QAAAA,EACAC,OAAAA,EACAR,MAAAA,EACAC,MAAAA,EACAQ,iBAAAA,EACAC,WAAAA,EACAC,UAAAA,EACAC,WAAAA,EACAC,MAAAA,EACAC,QAAAA,EACAC,KAAAA,EACAC,UAAAA,EACAC,QAAAA,EACAC,YAAAA,cAEM,MAAAC,EAASC,EAAMjB,GAAM,eAAgB,CAAEkB,gBAAiBlB,IACxDmB,EAAU,GAAGH,UACbI,EAAW,GAAGJ,WACdK,EAAU,GAAGL,kBAEZM,EAAeC,GAAoBC,EAExC3B,GAAS,KACJ4B,EAAgBC,GAAqBF,GAAkB,IACvDG,EAAUC,GAAeJ,GAAkB,IAC3CK,EAAaC,GAAkBN,EAAiB,KAChDO,EAAWC,GAAgBR,GAAS,IACpCS,GAAQC,IAAaV,GAAkB,GAExCW,GAAYC,EAAyB,MACrCC,GAAWD,EAAuB,MAClCE,GAAiBF,GAAO,GAE9BG,GAAU,KACNT,EAAe,IACXH,GAAYQ,GAAUK,SACtBL,GAAUK,QAAQC,UAEvB,CAACd,IAEJY,GAAU,KACWhB,GAACmB,GAAS7C,GAAS6C,GAAI,GACzC,CAAC7C,IAGE,MAAA8C,GAAcC,KACXtB,GAGMA,EAAcuB,MAAMhD,GAAUA,EAAMA,QAAU+C,EAAO/C,QAK9DiD,GAAeC,GAChBH,GACUtB,EAAc0B,QAAQnD,GAAUA,EAAMA,QAAU+C,KAE3D,CAACtB,IAGC2B,GAAcF,GAChB,CACIG,EAGAN,KAEIO,IAAAA,EAAWL,GAAaF,GAC5BrB,EAAiB4B,GACRhD,EAAA,CACLiD,KAAM,SACNC,OAAQ,CAAEzC,KAAAA,EAAMf,MAAO+C,EAAQU,gBAAiBH,KAEpDD,EAAEK,kBAEsB,IAApBJ,EAASK,QACTtB,IAAU,EAAK,GAGvB,CAACY,GAAcvB,EAAkBpB,EAAUS,EAAMsB,KAI/CuB,GAAcV,GACfH,UACOO,IAAAA,EAEJ,GAAI7B,EAAcuB,MAAMhD,GAAUA,EAAMA,QAAU+C,IAC9CO,EAAWL,GAAaF,OACrB,CACH,MAAMhD,EAAOM,EAAMwD,MAAMC,GAAMA,EAAE9D,QAAU+C,IAChCO,EAAA,IAAI7B,EAAe1B,EAClC,CACA,OAAAgE,EAAAzB,GAAUK,UAAVoB,EAAmBnB,QACnBlB,EAAiB4B,GACRhD,EAAA,CACLiD,KAAM,SACNC,OAAQ,CAAEzC,KAAAA,EAAMf,MAAO+C,EAAQU,gBAAiBH,IACnD,GAEL,CAAC7B,EAAeC,EAAkBpB,EAAUS,EAAMkC,GAAc5C,IAI9D2D,GAAYX,UAGd,OAAAU,EAAAzB,GAAUK,UAAVoB,EAAmBnB,QACnBb,GAAY,GACGE,EAAAoB,EAAEG,OAAOxD,MAAK,EAG3BiE,GAAUC,GAAQ,KACpB,IAAKlC,EACM3B,OAAAA,EAGX,MAAM8D,EAAkB9D,EAAM8C,QACzBJ,GACGA,EAAO9C,MAAMmE,cAAcC,QAAQrC,EAAYoC,gBAC/C,IAGK,OAAAjC,EAA2B,IAA3BgC,EAAgBR,QAEtBQ,CAAAA,GACR,CAACnC,EAAa3B,KAGViE,GAAkBC,IAAuB5C,EAE9C,OAAAoC,EAAAE,GAAQ,KAARF,EAAY/D,MAAQ,GAAGmB,KAAU,OAAAqD,EAAAP,GAAQ,SAAR,EAAAO,EAAYxE,aAAU,GAGzD0C,GAAU,KAEFb,GADAC,EACuB,GAI5B,CAACA,IAGJY,GAAU,KACA+B,MAAAA,EAAgBpB,IACJ,WAAVA,EAAEqB,KAAoB5C,GACtBC,GAAY,EAAK,EAGrB,cAAO4C,OAAW,KACXA,OAAAC,iBAAiB,UAAWH,GAEhC,YACQE,OAAW,KAAe7C,GAC1B6C,OAAAE,oBAAoB,UAAWJ,EAAY,CACtD,GAEL,CAAC1C,EAAaD,IAGXgD,MAAAA,GAAuB5B,GAAa6B,IAClCA,EACIzC,GAAUK,SACVL,GAAUK,QAAQC,QAGlBH,GAAeE,SAAWH,GAASG,SACnCH,GAASG,QAAQC,UAG1B,IAEGoC,GAAc9B,GAAY,KACvBT,GAAeE,UACZpC,GACQA,EAAA,CACJgD,KAAM,SACNC,OAAQ,CACJzC,KAAAA,EACAf,OAAO,MAAAyB,OAAAA,EAAAA,EAAgB,GAAGzB,QAAS,GACnCyD,gBAAiBhC,KAI7BgB,GAAeE,SAAU,EACzBZ,GAAY,GAAI,GAErB,CAACxB,EAASkB,EAAeV,KAErBkE,IAAeC,EAAkCpD,EAAU,CAC9DqD,eAAgBL,GAChBM,gBAAiBN,KAGHO,EAAA,CAAEC,IAAKL,KAEnB,MAAAM,GAA0BhD,EAAuB,MAEjDiD,GAAatC,GAEXG,YAIA,MAAMoC,EAAuBF,GAAwB5C,QAEjD8C,GACAA,EAAqBC,SAASrC,EAAEsC,iBAEhC1D,EAAe,IAEXzB,IACOA,EAAA,CACH+C,KAAM,OACNC,OAAQ,CACJzC,KAAAA,EACAf,OAAO,OAAA+D,EAAA,MAAAtC,OAAA,EAAAA,EAAgB,SAAhB,EAAAsC,EAAoB/D,QAAS,GACpCyD,gBAAiBhC,KAGzB,OAAA+C,EAAAhC,GAASG,UAAT6B,EAAkBoB,cACd,IAAIC,MAAM,WAAY,CAAEC,SAAS,MAGzCrD,GAAeE,SAAU,EACzBZ,GAAY,GAAK,GAGzB,CAACvB,EAAQO,EAAMU,IAGbsE,GAAkB7C,GAAaG,IAGhCA,EAAEG,OAA6BZ,MAAM,CAAEoD,eAAe,GAAM,GAC9D,IAGGC,GAAwB/C,GACzBG,UACOA,GAAU,cAAVA,EAAEqB,IAAqB,CACvBrB,EAAE6C,iBACF7C,EAAEK,kBACF,MAAMyC,EAAclB,GAAYtC,QAC5BwD,IAEK,OAAApC,EAAAoC,EAAAC,cAAiC,qBAAjCrC,EACCnB,QACV,KACiB,WAAVS,EAAEqB,MACTrB,EAAE6C,iBACF7C,EAAEK,kBACF3B,GAAY,IAGXsB,GAAAA,EAAEgD,SAAqB,MAAVhD,EAAEqB,KAAiBrB,EAAEiD,SAAqB,MAAVjD,EAAEqB,IAAc,CAC9DrB,EAAE6C,iBACF7C,EAAEK,kBACF,MAAM6C,EAAuB9E,EAAc+E,KAAKzG,IAAU,IACnDA,EACH0G,UAAU,MAEdpE,IAAU,GACVX,EAAiB6E,EAAoB,MAAA,GACpB,cAAVlD,EAAEqB,IAST,GARArB,EAAEK,kBACFrB,IAAU,GAGoBZ,EAAcuB,MACvCjD,GAASA,EAAK0G,WAGQ,CACvB,MAAMF,EAAuB9E,EAAc0B,QACtCpD,IAAUA,EAAK0G,WAEpB/E,EAAiB6E,GACjBtE,EAAe,GACR,MAAAR,EAAckC,OAAS,GAAqB,KAAhB3B,GAEnCoB,GACIC,EACA5B,EAAcA,EAAckC,OAAS,GAAG3D,MAAA,GAKxD,CAACyB,EAAeO,EAAaiD,GAAa7B,KAGxCsD,GAAwBxD,GACzBG,IACO,GAAU,QAAVA,EAAEqB,IACEpC,GAAUK,UACVU,EAAE6C,iBACF7C,EAAEK,kBAEEL,EAAEsD,UAGF5E,GAAY,GACZO,GAAUK,QAAQC,iBAGT,YAAVS,EAAEqB,KACLO,GAAYtC,SAAWL,GAAUK,QAAS,CAEpCiE,MAAAA,EAAe3B,GAAYtC,QAAQyD,cACrC,iCAGA/C,EAAEwD,cAAc1G,MAAO,MAAAyG,OAAA,EAAAA,EAAczG,KACrCmC,GAAUK,SAEVL,GAAUK,QAAQC,OAE1B,IAGR,CAACb,EAAakD,KAGZ6B,GAAerF,EAAckC,QAAU,EAGzC,OAAAoD,EAACC,EAAA,CACG/G,MAAAA,EACAE,GAAIqB,EACJ8D,IAAKC,GACL,cAAY,eACZvE,UAAWiG,EAAK,eAAgBjG,EAAW,CACvC,0BAA2BJ,GAAcK,EACzC,0BAA2Ba,EAC3B,6BAA8BA,GAAYgF,KAE9CpG,WAAY,CACRP,GAAImB,KACDZ,GAEPC,UAAAA,EACAC,WAAAA,EACAE,QAAAA,EACAoG,OAASC,GACLC,EAAC,MAAA,CACGpG,UAAWiG,EAAK,wBAAyB,CACrC,sCAAuCH,KAE3CO,MAAO,CAAExG,MAAAA,GACTyG,UAAU,EACV/G,QAASyE,GACTxE,OAAQgF,GAER+B,SAAA,CAAAH,EAAC,MAAA,CACGpG,UAAU,qBACV,cAAY,qBAEXuG,SAAA,CAAA9F,EACI+E,IAAI1G,GACJ0G,KAAKzD,GACFgE,EAACS,EAAA,CAEGxG,UAAW,WACPoB,IAAU,oBAEd,cAAY,UACZqF,cAAe,CACXC,QAAUrE,IACFf,GAAUK,SACVL,GAAUK,QAAQC,QAEVQ,GAAAC,EAAGN,EAAO/C,MAAK,EAE/BQ,OAAQgF,GACRvF,MAAO,SAAS8C,EAAO/C,SAG1BuH,SAAArG,IACIyG,EACG,CAAAJ,SAAA,CAAAH,EAACQ,EACI,CAAAL,SAAA,CAAA,IACDR,EAAC,OAAA,CACG,cAAY,OACZ,cAAY,mBAEXQ,SAAOxE,EAAA8E,SACF9E,EAAO8E,SACP9E,EAAO9C,WAGrB8G,EAACe,EACI,CAAAP,SAAAxE,EAAO9C,UAbF8C,EAAO/C,OAiBrB+G,EAAC,OAAA,CACG,cAAY,OACZ,cAAY,mBAEXQ,SAAOxE,EAAA8E,SACF9E,EAAO8E,SACP9E,EAAO9C,SAxChB8C,EAAO/C,SA6CxB+G,EAAC,QAAA,IACOI,EACJnG,UAAU,6BACVV,SAAU0D,GACV,cAAY,6BACZzD,QAASyE,GACTxE,OAAQgF,GACRuC,UAAW9B,GACXjG,MAAOgC,EACPsD,IAAKhD,GACL,gBAAenB,EACf6G,KAAK,WACL,oBAAkB,OAClB,gBAAelG,EACf1B,YACIqB,EAAckC,OAAS,EAAI,GAAKvD,EAEpC6H,aAAa,WAIrBb,EAAC,MAAA,CACGpG,UAAU,qBACVgH,KAAK,UACL1C,IAAKL,GACL9E,GAAIgB,EACJ,kBAAiBG,EACjB,uBAAqB,OACrB,wBAAuBgD,GACvB/D,QAASyE,GACTxE,OAAQgF,GACR8B,UAAU,EAETC,SAAA,CAAQtD,GAAAuC,KAAI,CAACzD,EAAQe,IAClBsD,EAAC,SAAA,CAEG7D,KAAK,SACLpD,GAAI,GAAGgB,MAAW4B,EAAO/C,QACzB,gBAAe8C,GAAWC,GAC1BiF,KAAK,SACLhI,MAAO+C,EAAO/C,MACdQ,OAAQgF,GACRxE,UAAW,wBACP8B,GAAWC,IACX,mCAEJ,cAAY,uBACZ,kBAAiB,wBAAwBe,IACzCvD,QAASyE,GACT+C,UAAWrB,GACXgB,QAAUrE,IACNkB,GACI,GAAGpD,MAAW4B,EAAO/C,SAEzBqD,EAAEK,kBACFE,GAAYb,EAAO/C,OACnBiC,EAAe,GAAE,EAErBiG,YAAanC,GAEZwB,SAAA,CAAOxE,EAAAoF,cACH,OACI,CAAAZ,SAAA,CAAOxE,EAAA9C,MACP8G,EAAA,OAAA,CAAK/F,UAAU,mCACXuG,WAAOY,iBAIhBpF,EAAO9C,MAEV6C,GAAWC,GACRqE,EAAC,OACG,CAAAG,SAAA,CAAAR,EAACqB,EAAU,IAAG,OAElB,OAvCC,GAAGjH,KAAU4B,EAAO/C,WA0ChCkC,GACG6E,EAAC,MAAI,CAAA/F,UAAU,0BACVuG,SACL9G,OAGRsG,EAAC,MAAI,CAAA/F,UAAU,wBACXuG,SAAAR,EAACsB,EAAA,CACGlI,GAAIoB,EACJhB,QAASyE,GACTxE,OAAQgF,GACRxE,UAAU,uBACV,cAAY,uBACZ,aAAY,GACRS,EAAc+E,KAAKxG,GAAUA,EAAMC,SACnC,UACAA,IACJ,gBAAe6B,EACf,gBAAeX,EACf6G,KAAK,SACLN,QAAS,IAAM3F,GAAY,GAC3BuG,YAAcjF,UACVA,EAAE6C,iBACF,OAAAnC,EAAAvB,GAASG,UAAToB,EAAkBnB,OAAA,EAGtB2E,SAAAR,EAACwB,EAAA,CACGC,aAAc5G,YAI9B,EAKhB1B,EAASuI,YAAc"}
1
+ {"version":3,"file":"Combobox.js","sources":["../../../../src/components/combobox/Combobox.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React, {\n ChangeEvent,\n FC,\n FocusEvent,\n KeyboardEvent,\n MouseEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { Density } from \"../../core/types.js\";\nimport { useAnimatedHeight } from \"../../hooks/useAnimatedHeight/useAnimatedHeight.js\";\nimport { useId } from \"../../hooks/useId/useId.js\";\nimport { useListNavigation } from \"../../hooks/useListNavigation/useListNavigation.js\";\nimport { ValuePair } from \"../../utilities/valuePair.js\";\nimport { ArrowVerticalAnimated } from \"../icon/icons/animated/ArrowVerticalAnimated.js\";\nimport { CheckIcon } from \"../icon/icons/CheckIcon.js\";\nimport { IconButton } from \"../icon-button/IconButton.js\";\nimport { InputGroup, InputGroupProps } from \"../input-group/InputGroup.js\";\nimport { LabelProps } from \"../input-group/Label.js\";\nimport { Tag } from \"../tag/Tag.js\";\nimport { Tooltip } from \"../tooltip/Tooltip.js\";\nimport { TooltipContent } from \"../tooltip/TooltipContent.js\";\nimport { TooltipTrigger } from \"../tooltip/TooltipTrigger.js\";\n\nexport type ComboboxValuePair = ValuePair & {\n tagLabel?: string;\n isMarked?: boolean;\n};\n\nexport function getComboboxValuePair(\n item: string | ComboboxValuePair,\n): ComboboxValuePair {\n return typeof item === \"string\" ? { value: item, label: item } : item;\n}\n\nexport interface ComboboxPartialChangeEvent\n extends Partial<Omit<ChangeEvent<HTMLElement>, \"target\">> {\n type: \"change\" | \"blur\";\n target: {\n name: string;\n value: string;\n selectedOptions: Array<ValuePair>;\n };\n}\n\nexport type ComboboxChangeEventHandler = (\n event: ComboboxPartialChangeEvent,\n) => void;\n\nexport interface ComboboxProps extends InputGroupProps {\n id?: string;\n placeholder?: string;\n labelProps?: Omit<\n LabelProps,\n \"children\" | \"density\" | \"htmlFor\" | \"standAlone\"\n >;\n items: Array<ValuePair>;\n noMatchingOption?: string;\n label: string;\n name: string;\n value?: Array<ValuePair>;\n density?: Density;\n width?: string;\n helpLabel?: string;\n errorLabel?: string;\n className?: string;\n invalid?: boolean;\n hasTagHover?: boolean;\n onChange: ComboboxChangeEventHandler;\n onBlur?: ComboboxChangeEventHandler;\n onFocus?: ComboboxChangeEventHandler;\n}\n\nexport const Combobox: FC<ComboboxProps> = ({\n id,\n placeholder,\n items,\n onChange,\n onFocus,\n onBlur,\n value,\n label,\n noMatchingOption,\n labelProps,\n helpLabel,\n errorLabel,\n width,\n density,\n name,\n className,\n invalid,\n hasTagHover,\n}) => {\n const listId = useId(id || \"jkl-combobox\", { generateSuffix: !id });\n const labelId = `${listId}_label`;\n const buttonId = `${listId}_button`;\n const inputId = `${listId}_search-input`;\n\n const [selectedValue, setSelectedValue] = useState<\n Array<ComboboxValuePair>\n >(value || []);\n const [isPointingDown, setIsPointingDown] = useState<boolean>(true);\n const [showMenu, setShowMenu] = useState<boolean>(false);\n const [searchValue, setSearchValue] = useState<string>(\"\");\n const [noResults, setNoResults] = useState(false);\n const [marked, setMarked] = useState<boolean>(false);\n\n const searchRef = useRef<HTMLInputElement>(null);\n const inputRef = useRef<HTMLDivElement>(null);\n const focusInsideRef = useRef(false);\n\n useEffect(() => {\n setSearchValue(\"\");\n if (showMenu && searchRef.current) {\n searchRef.current.focus();\n }\n }, [showMenu]);\n\n useEffect(() => {\n setSelectedValue((prev) => value || prev);\n }, [value]);\n\n // Funksjon for å stile valgt element\n const isSelected = (option: ValuePair) => {\n if (!selectedValue) {\n return false;\n } else {\n return selectedValue.some((value) => value.value === option.value);\n }\n };\n\n // Fjerne ett eller flere valg\n const removeOption = useCallback(\n (option: string) => {\n return selectedValue.filter((value) => value.value !== option);\n },\n [selectedValue],\n );\n\n const onTagRemove = useCallback(\n (\n e:\n | React.MouseEvent<HTMLButtonElement, globalThis.MouseEvent>\n | React.KeyboardEvent<HTMLInputElement>,\n option: string,\n ) => {\n let newValue = removeOption(option);\n setSelectedValue(newValue);\n onChange({\n type: \"change\",\n target: { name, value: option, selectedOptions: newValue },\n });\n e.stopPropagation();\n\n if (newValue.length === 0) {\n setMarked(false);\n }\n },\n [removeOption, setSelectedValue, onChange, name, setMarked],\n );\n\n // Håndtere valgt verdi i listen\n const onItemClick = useCallback(\n (option: string) => {\n let newValue: Array<ValuePair>;\n\n if (selectedValue.some((value) => value.value === option)) {\n newValue = removeOption(option);\n } else {\n const item = items.find((i) => i.value === option);\n newValue = [...selectedValue, item as ValuePair];\n }\n searchRef.current?.focus();\n setSelectedValue(newValue);\n onChange({\n type: \"change\",\n target: { name, value: option, selectedOptions: newValue },\n });\n },\n [selectedValue, setSelectedValue, onChange, name, removeOption, items],\n );\n\n // Funksjon for søk\n const onSearch = (e: {\n target: { value: React.SetStateAction<string> };\n }) => {\n searchRef.current?.focus();\n setShowMenu(true);\n setSearchValue(e.target.value);\n };\n\n const options = useMemo(() => {\n if (!searchValue) {\n return items;\n }\n\n const filteredOptions = items.filter(\n (option) =>\n option.label.toLowerCase().indexOf(searchValue.toLowerCase()) >=\n 0,\n );\n\n setNoResults(filteredOptions.length === 0);\n\n return filteredOptions;\n }, [searchValue, items]);\n\n // Det første elementet i listen skal være aktivt fram til brukeren klikker på noe annet\n const [activeDescendant, setActiveDescendant] = useState<\n string | undefined\n >(options[0]?.value ? `${listId}-${options[0]?.value}` : undefined);\n\n // Håndtere arrow-state\n useEffect(() => {\n if (showMenu) {\n setIsPointingDown(false);\n } else {\n setIsPointingDown(true);\n }\n }, [showMenu]);\n\n // Lukk meny med ESC\n useEffect(() => {\n const handleEscape = (e: globalThis.KeyboardEvent) => {\n if (e.key === \"Escape\" && showMenu) {\n setShowMenu(false);\n }\n };\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"keydown\", handleEscape);\n }\n return () => {\n if (typeof window !== \"undefined\" && showMenu) {\n window.removeEventListener(\"keydown\", handleEscape);\n }\n };\n }, [setShowMenu, showMenu]);\n\n // Fokushåndtering\n const handleFocusPlacement = useCallback((isOpen: boolean) => {\n if (isOpen) {\n if (searchRef.current) {\n searchRef.current.focus();\n }\n } else {\n if (focusInsideRef.current && inputRef.current) {\n inputRef.current.focus();\n }\n }\n }, []);\n\n const handleFocus = useCallback(() => {\n if (!focusInsideRef.current) {\n if (onFocus) {\n onFocus({\n type: \"change\",\n target: {\n name,\n value: selectedValue?.[0].value || \"\",\n selectedOptions: selectedValue,\n },\n });\n }\n focusInsideRef.current = true;\n setShowMenu(true);\n }\n }, [onFocus, selectedValue, name]);\n\n const [dropdownRef] = useAnimatedHeight<HTMLDivElement>(showMenu, {\n onFirstVisible: handleFocusPlacement,\n onTransitionEnd: handleFocusPlacement,\n });\n\n useListNavigation({ ref: dropdownRef });\n\n const componentRootElementRef = useRef<HTMLDivElement>(null);\n\n const handleBlur = useCallback(\n (\n e: FocusEvent<\n HTMLDivElement | HTMLInputElement | HTMLButtonElement\n >,\n ) => {\n const componentRootElement = componentRootElementRef.current;\n const nextFocusIsInsideComponent =\n componentRootElement &&\n componentRootElement.contains(e.relatedTarget as Node);\n if (!nextFocusIsInsideComponent) {\n setSearchValue(\"\");\n\n if (onBlur) {\n onBlur({\n type: \"blur\",\n target: {\n name,\n value: selectedValue?.[0]?.value || \"\",\n selectedOptions: selectedValue,\n },\n });\n inputRef.current?.dispatchEvent(\n new Event(\"focusout\", { bubbles: true }),\n );\n }\n focusInsideRef.current = false;\n setShowMenu(false);\n }\n },\n [onBlur, name, selectedValue],\n );\n\n const handleMouseOver = useCallback((e: MouseEvent<HTMLButtonElement>) => {\n // Ved mouseOver på options flytter vi fokus til dem for å unngå \"dobbel fokus\"\n // der det ser ut som to forskjellige elementer er fokusert/hovered samtidig\n (e.target as HTMLButtonElement).focus({ preventScroll: true });\n }, []);\n\n // Tastaturnavigasjon\n const handleSearchOnKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n e.stopPropagation();\n const listElement = dropdownRef.current;\n if (listElement) {\n listElement\n .querySelector<HTMLButtonElement>('[role=\"option\"]')\n ?.focus();\n }\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n e.stopPropagation();\n setShowMenu(false);\n }\n\n if ((e.metaKey && e.key === \"a\") || (e.ctrlKey && e.key === \"a\")) {\n e.preventDefault();\n e.stopPropagation();\n const updatedSelectedValue = selectedValue.map((item) => ({\n ...item,\n isMarked: true,\n }));\n setMarked(true);\n setSelectedValue(updatedSelectedValue);\n } else if (e.key === \"Backspace\") {\n e.stopPropagation();\n setMarked(false);\n\n // Sjekk om selectedValue er markert\n const selectedValueIsMarked = selectedValue.some(\n (item) => item.isMarked,\n );\n\n if (selectedValueIsMarked) {\n const updatedSelectedValue = selectedValue.filter(\n (item) => !item.isMarked,\n );\n setSelectedValue(updatedSelectedValue);\n setSearchValue(\"\");\n } else if (selectedValue.length > 0 && searchValue === \"\") {\n // Hvis ingen items er markert, fjern siste valgte item\n onTagRemove(\n e,\n selectedValue[selectedValue.length - 1].value,\n );\n }\n }\n },\n [selectedValue, searchValue, dropdownRef, onTagRemove],\n );\n\n const handleOptionOnKeyDown = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === \"Tab\") {\n if (searchRef.current) {\n e.preventDefault();\n e.stopPropagation();\n\n if (e.shiftKey) {\n searchRef.current.focus();\n } else {\n setShowMenu(false);\n searchRef.current.focus();\n }\n }\n } else if (e.key === \"ArrowUp\") {\n if (dropdownRef.current && searchRef.current) {\n // Can't be based on index since the first item might be filtered out\n const firstVisible = dropdownRef.current.querySelector(\n '[role=\"option\"]:not([hidden])',\n );\n if (\n e.currentTarget.id === firstVisible?.id &&\n searchRef.current\n ) {\n searchRef.current.focus();\n }\n }\n }\n },\n [setShowMenu, dropdownRef],\n );\n\n const hasSelection = selectedValue.length >= 1;\n\n return (\n <InputGroup\n label={label}\n id={inputId}\n ref={componentRootElementRef}\n data-testid=\"jkl-combobox\"\n className={clsx(\"jkl-combobox\", className, {\n \"jkl-combobox--invalid\": !!errorLabel || invalid,\n \"jkl-combobox--menu-open\": showMenu,\n \"jkl-combobox--menu-closed\": !showMenu && hasSelection,\n })}\n labelProps={{\n id: labelId,\n ...labelProps,\n }}\n helpLabel={helpLabel}\n errorLabel={errorLabel}\n density={density}\n render={(inputProps) => (\n <div\n className={clsx(\"jkl-combobox__wrapper\", {\n \"jkl-combobox__wrapper--active-value\": hasSelection,\n })}\n style={{ width }}\n tabIndex={-1}\n onFocus={handleFocus}\n onBlur={handleBlur}\n >\n <div\n className=\"jkl-combobox__tags\"\n data-testid=\"jkl-combobox__tags\"\n >\n {selectedValue\n .map(getComboboxValuePair)\n .map((option) => (\n <Tag\n key={option.value}\n className={`jkl-tag ${\n marked && \"jkl-tag__marked\"\n }`}\n data-testid=\"jkl-tag\"\n dismissAction={{\n onClick: (e) => {\n if (searchRef.current) {\n searchRef.current.focus();\n }\n onTagRemove(e, option.value);\n },\n onBlur: handleBlur,\n label: `Fjern ${option.value}`,\n }}\n >\n {hasTagHover ? (\n <Tooltip key={option.value}>\n <TooltipTrigger>\n {\" \"}\n <span\n aria-hidden=\"true\"\n data-testid=\"jkl-tag__content\"\n >\n {option.tagLabel\n ? option.tagLabel\n : option.label}\n </span>\n </TooltipTrigger>\n <TooltipContent>\n {option.label}\n </TooltipContent>\n </Tooltip>\n ) : (\n <span\n aria-hidden=\"true\"\n data-testid=\"jkl-tag__content\"\n >\n {option.tagLabel\n ? option.tagLabel\n : option.label}\n </span>\n )}\n </Tag>\n ))}\n <input\n {...inputProps}\n className=\"jkl-combobox__search-input\"\n onChange={onSearch}\n data-testid=\"jkl-combobox__search-input\"\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={handleSearchOnKeyDown}\n value={searchValue}\n ref={searchRef}\n aria-controls={listId}\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={showMenu}\n placeholder={\n selectedValue.length > 0 ? \"\" : placeholder\n }\n autoComplete=\"off\"\n />\n </div>\n\n <div\n className=\"jkl-combobox__menu\"\n role=\"listbox\"\n ref={dropdownRef}\n id={listId}\n aria-labelledby={labelId}\n aria-multiselectable=\"true\"\n aria-activedescendant={activeDescendant}\n onFocus={handleFocus}\n onBlur={handleBlur}\n tabIndex={-1}\n >\n {options.map((option, i) => (\n <button\n key={`${listId}-${option.value}`}\n type=\"button\"\n id={`${listId}__${option.value}`}\n aria-selected={isSelected(option)}\n role=\"option\"\n value={option.value}\n onBlur={handleBlur}\n className={`jkl-combobox__option ${\n isSelected(option) &&\n \"jkl-combobox__option--selected\"\n }`}\n data-testid=\"jkl-combobox__option\"\n data-testautoid={`jkl-combobox__option-${i}`}\n onFocus={handleFocus}\n onKeyDown={handleOptionOnKeyDown}\n onClick={(e) => {\n setActiveDescendant(\n `${listId}__${option.value}`,\n ); // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/listbox_role#required_javascript_features\n e.stopPropagation();\n onItemClick(option.value);\n setSearchValue(\"\");\n }}\n onMouseOver={handleMouseOver}\n >\n {option.description ? (\n <span>\n {option.label}\n <span className=\"jkl-combobox__option-description\">\n {option.description}\n </span>\n </span>\n ) : (\n option.label\n )}\n {isSelected(option) ? (\n <span>\n <CheckIcon />{\" \"}\n </span>\n ) : null}\n </button>\n ))}\n {noResults && (\n <div className=\"jkl-combobox__no-option\">\n {noMatchingOption}\n </div>\n )}\n </div>\n <div className=\"jkl-combobox__actions\">\n <IconButton\n id={buttonId}\n onFocus={handleFocus}\n onBlur={handleBlur}\n className=\"jkl-combobox__button\"\n data-testid=\"jkl-combobox__button\"\n aria-label={`${\n selectedValue.map((value) => value.label) ||\n \"Velg\"\n },${label}`}\n aria-expanded={showMenu}\n aria-controls={listId}\n role=\"button\"\n onClick={() => setShowMenu(true)}\n onMouseDown={(e) => {\n e.preventDefault();\n inputRef.current?.focus();\n }}\n >\n <ArrowVerticalAnimated\n pointingDown={isPointingDown}\n />\n </IconButton>\n </div>\n </div>\n )}\n />\n );\n};\nCombobox.displayName = \"Combobox\";\n"],"names":["getComboboxValuePair","item","value","label","Combobox","id","placeholder","items","onChange","onFocus","onBlur","noMatchingOption","labelProps","helpLabel","errorLabel","width","density","name","className","invalid","hasTagHover","listId","useId","generateSuffix","labelId","buttonId","inputId","selectedValue","setSelectedValue","useState","isPointingDown","setIsPointingDown","showMenu","setShowMenu","searchValue","setSearchValue","noResults","setNoResults","marked","setMarked","searchRef","useRef","inputRef","focusInsideRef","useEffect","current","focus","prev","isSelected","option","some","removeOption","useCallback","filter","onTagRemove","e","newValue","type","target","selectedOptions","stopPropagation","length","onItemClick","find","i","_a","onSearch","options","useMemo","filteredOptions","toLowerCase","indexOf","activeDescendant","setActiveDescendant","_b","handleEscape","key","window","addEventListener","removeEventListener","handleFocusPlacement","isOpen","handleFocus","dropdownRef","useAnimatedHeight","onFirstVisible","onTransitionEnd","useListNavigation","ref","componentRootElementRef","handleBlur","componentRootElement","contains","relatedTarget","dispatchEvent","Event","bubbles","handleMouseOver","preventScroll","handleSearchOnKeyDown","preventDefault","listElement","querySelector","metaKey","ctrlKey","updatedSelectedValue","map","isMarked","handleOptionOnKeyDown","shiftKey","firstVisible","currentTarget","hasSelection","jsx","InputGroup","clsx","render","inputProps","jsxs","style","tabIndex","children","Tag","dismissAction","onClick","Tooltip","TooltipTrigger","tagLabel","TooltipContent","onKeyDown","role","autoComplete","onMouseOver","description","CheckIcon","IconButton","onMouseDown","ArrowVerticalAnimated","pointingDown","displayName"],"mappings":"82BAiCO,SAASA,EACZC,GAEO,MAAgB,iBAATA,EAAoB,CAAEC,MAAOD,EAAME,MAAOF,GAASA,CACrE,CAwCO,MAAMG,EAA8B,EACvCC,GAAAA,EACAC,YAAAA,EACAC,MAAAA,EACAC,SAAAA,EACAC,QAAAA,EACAC,OAAAA,EACAR,MAAAA,EACAC,MAAAA,EACAQ,iBAAAA,EACAC,WAAAA,EACAC,UAAAA,EACAC,WAAAA,EACAC,MAAAA,EACAC,QAAAA,EACAC,KAAAA,EACAC,UAAAA,EACAC,QAAAA,EACAC,YAAAA,cAEM,MAAAC,EAASC,EAAMjB,GAAM,eAAgB,CAAEkB,gBAAiBlB,IACxDmB,EAAU,GAAGH,UACbI,EAAW,GAAGJ,WACdK,EAAU,GAAGL,kBAEZM,EAAeC,GAAoBC,EAExC3B,GAAS,KACJ4B,EAAgBC,GAAqBF,GAAkB,IACvDG,EAAUC,GAAeJ,GAAkB,IAC3CK,EAAaC,GAAkBN,EAAiB,KAChDO,EAAWC,GAAgBR,GAAS,IACpCS,GAAQC,IAAaV,GAAkB,GAExCW,GAAYC,EAAyB,MACrCC,GAAWD,EAAuB,MAClCE,GAAiBF,GAAO,GAE9BG,GAAU,KACNT,EAAe,IACXH,GAAYQ,GAAUK,SACtBL,GAAUK,QAAQC,UAEvB,CAACd,IAEJY,GAAU,KACWhB,GAACmB,GAAS7C,GAAS6C,GAAI,GACzC,CAAC7C,IAGE,MAAA8C,GAAcC,KACXtB,GAGMA,EAAcuB,MAAMhD,GAAUA,EAAMA,QAAU+C,EAAO/C,QAK9DiD,GAAeC,GAChBH,GACUtB,EAAc0B,QAAQnD,GAAUA,EAAMA,QAAU+C,KAE3D,CAACtB,IAGC2B,GAAcF,GAChB,CACIG,EAGAN,KAEIO,IAAAA,EAAWL,GAAaF,GAC5BrB,EAAiB4B,GACRhD,EAAA,CACLiD,KAAM,SACNC,OAAQ,CAAEzC,KAAAA,EAAMf,MAAO+C,EAAQU,gBAAiBH,KAEpDD,EAAEK,kBAEsB,IAApBJ,EAASK,QACTtB,IAAU,EAAK,GAGvB,CAACY,GAAcvB,EAAkBpB,EAAUS,EAAMsB,KAI/CuB,GAAcV,GACfH,UACOO,IAAAA,EAEJ,GAAI7B,EAAcuB,MAAMhD,GAAUA,EAAMA,QAAU+C,IAC9CO,EAAWL,GAAaF,OACrB,CACH,MAAMhD,EAAOM,EAAMwD,MAAMC,GAAMA,EAAE9D,QAAU+C,IAChCO,EAAA,IAAI7B,EAAe1B,EAClC,CACA,OAAAgE,EAAAzB,GAAUK,UAAVoB,EAAmBnB,QACnBlB,EAAiB4B,GACRhD,EAAA,CACLiD,KAAM,SACNC,OAAQ,CAAEzC,KAAAA,EAAMf,MAAO+C,EAAQU,gBAAiBH,IACnD,GAEL,CAAC7B,EAAeC,EAAkBpB,EAAUS,EAAMkC,GAAc5C,IAI9D2D,GAAYX,UAGd,OAAAU,EAAAzB,GAAUK,UAAVoB,EAAmBnB,QACnBb,GAAY,GACGE,EAAAoB,EAAEG,OAAOxD,MAAK,EAG3BiE,GAAUC,GAAQ,KACpB,IAAKlC,EACM3B,OAAAA,EAGX,MAAM8D,EAAkB9D,EAAM8C,QACzBJ,GACGA,EAAO9C,MAAMmE,cAAcC,QAAQrC,EAAYoC,gBAC/C,IAGK,OAAAjC,EAA2B,IAA3BgC,EAAgBR,QAEtBQ,CAAAA,GACR,CAACnC,EAAa3B,KAGViE,GAAkBC,IAAuB5C,EAE9C,OAAAoC,EAAAE,GAAQ,KAARF,EAAY/D,MAAQ,GAAGmB,KAAU,OAAAqD,EAAAP,GAAQ,SAAR,EAAAO,EAAYxE,aAAU,GAGzD0C,GAAU,KAEFb,GADAC,EACuB,GAI5B,CAACA,IAGJY,GAAU,KACA+B,MAAAA,EAAgBpB,IACJ,WAAVA,EAAEqB,KAAoB5C,GACtBC,GAAY,EAAK,EAGrB,cAAO4C,OAAW,KACXA,OAAAC,iBAAiB,UAAWH,GAEhC,YACQE,OAAW,KAAe7C,GAC1B6C,OAAAE,oBAAoB,UAAWJ,EAAY,CACtD,GAEL,CAAC1C,EAAaD,IAGXgD,MAAAA,GAAuB5B,GAAa6B,IAClCA,EACIzC,GAAUK,SACVL,GAAUK,QAAQC,QAGlBH,GAAeE,SAAWH,GAASG,SACnCH,GAASG,QAAQC,UAG1B,IAEGoC,GAAc9B,GAAY,KACvBT,GAAeE,UACZpC,GACQA,EAAA,CACJgD,KAAM,SACNC,OAAQ,CACJzC,KAAAA,EACAf,OAAO,MAAAyB,OAAAA,EAAAA,EAAgB,GAAGzB,QAAS,GACnCyD,gBAAiBhC,KAI7BgB,GAAeE,SAAU,EACzBZ,GAAY,GAAI,GAErB,CAACxB,EAASkB,EAAeV,KAErBkE,IAAeC,EAAkCpD,EAAU,CAC9DqD,eAAgBL,GAChBM,gBAAiBN,KAGHO,EAAA,CAAEC,IAAKL,KAEnB,MAAAM,GAA0BhD,EAAuB,MAEjDiD,GAAatC,GAEXG,YAIA,MAAMoC,EAAuBF,GAAwB5C,QAEjD8C,GACAA,EAAqBC,SAASrC,EAAEsC,iBAEhC1D,EAAe,IAEXzB,IACOA,EAAA,CACH+C,KAAM,OACNC,OAAQ,CACJzC,KAAAA,EACAf,OAAO,OAAA+D,EAAA,MAAAtC,OAAA,EAAAA,EAAgB,SAAhB,EAAAsC,EAAoB/D,QAAS,GACpCyD,gBAAiBhC,KAGzB,OAAA+C,EAAAhC,GAASG,UAAT6B,EAAkBoB,cACd,IAAIC,MAAM,WAAY,CAAEC,SAAS,MAGzCrD,GAAeE,SAAU,EACzBZ,GAAY,GAAK,GAGzB,CAACvB,EAAQO,EAAMU,IAGbsE,GAAkB7C,GAAaG,IAGhCA,EAAEG,OAA6BZ,MAAM,CAAEoD,eAAe,GAAM,GAC9D,IAGGC,GAAwB/C,GACzBG,UACOA,GAAU,cAAVA,EAAEqB,IAAqB,CACvBrB,EAAE6C,iBACF7C,EAAEK,kBACF,MAAMyC,EAAclB,GAAYtC,QAC5BwD,IAEK,OAAApC,EAAAoC,EAAAC,cAAiC,qBAAjCrC,EACCnB,QACV,KACiB,WAAVS,EAAEqB,MACTrB,EAAE6C,iBACF7C,EAAEK,kBACF3B,GAAY,IAGXsB,GAAAA,EAAEgD,SAAqB,MAAVhD,EAAEqB,KAAiBrB,EAAEiD,SAAqB,MAAVjD,EAAEqB,IAAc,CAC9DrB,EAAE6C,iBACF7C,EAAEK,kBACF,MAAM6C,EAAuB9E,EAAc+E,KAAKzG,IAAU,IACnDA,EACH0G,UAAU,MAEdpE,IAAU,GACVX,EAAiB6E,EAAoB,MAAA,GACpB,cAAVlD,EAAEqB,IAST,GARArB,EAAEK,kBACFrB,IAAU,GAGoBZ,EAAcuB,MACvCjD,GAASA,EAAK0G,WAGQ,CACvB,MAAMF,EAAuB9E,EAAc0B,QACtCpD,IAAUA,EAAK0G,WAEpB/E,EAAiB6E,GACjBtE,EAAe,GACR,MAAAR,EAAckC,OAAS,GAAqB,KAAhB3B,GAEnCoB,GACIC,EACA5B,EAAcA,EAAckC,OAAS,GAAG3D,MAAA,GAKxD,CAACyB,EAAeO,EAAaiD,GAAa7B,KAGxCsD,GAAwBxD,GACzBG,IACO,GAAU,QAAVA,EAAEqB,IACEpC,GAAUK,UACVU,EAAE6C,iBACF7C,EAAEK,kBAEEL,EAAEsD,UAGF5E,GAAY,GACZO,GAAUK,QAAQC,iBAGT,YAAVS,EAAEqB,KACLO,GAAYtC,SAAWL,GAAUK,QAAS,CAEpCiE,MAAAA,EAAe3B,GAAYtC,QAAQyD,cACrC,iCAGA/C,EAAEwD,cAAc1G,MAAO,MAAAyG,OAAA,EAAAA,EAAczG,KACrCmC,GAAUK,SAEVL,GAAUK,QAAQC,OAE1B,IAGR,CAACb,EAAakD,KAGZ6B,GAAerF,EAAckC,QAAU,EAGzC,OAAAoD,EAACC,EAAA,CACG/G,MAAAA,EACAE,GAAIqB,EACJ8D,IAAKC,GACL,cAAY,eACZvE,UAAWiG,EAAK,eAAgBjG,EAAW,CACvC,0BAA2BJ,GAAcK,EACzC,0BAA2Ba,EAC3B,6BAA8BA,GAAYgF,KAE9CpG,WAAY,CACRP,GAAImB,KACDZ,GAEPC,UAAAA,EACAC,WAAAA,EACAE,QAAAA,EACAoG,OAASC,GACLC,EAAC,MAAA,CACGpG,UAAWiG,EAAK,wBAAyB,CACrC,sCAAuCH,KAE3CO,MAAO,CAAExG,MAAAA,GACTyG,UAAU,EACV/G,QAASyE,GACTxE,OAAQgF,GAER+B,SAAA,CAAAH,EAAC,MAAA,CACGpG,UAAU,qBACV,cAAY,qBAEXuG,SAAA,CAAA9F,EACI+E,IAAI1G,GACJ0G,KAAKzD,GACFgE,EAACS,EAAA,CAEGxG,UAAW,WACPoB,IAAU,oBAEd,cAAY,UACZqF,cAAe,CACXC,QAAUrE,IACFf,GAAUK,SACVL,GAAUK,QAAQC,QAEVQ,GAAAC,EAAGN,EAAO/C,MAAK,EAE/BQ,OAAQgF,GACRvF,MAAO,SAAS8C,EAAO/C,SAG1BuH,SAAArG,IACIyG,EACG,CAAAJ,SAAA,CAAAH,EAACQ,EACI,CAAAL,SAAA,CAAA,IACDR,EAAC,OAAA,CACG,cAAY,OACZ,cAAY,mBAEXQ,SAAOxE,EAAA8E,SACF9E,EAAO8E,SACP9E,EAAO9C,WAGrB8G,EAACe,EACI,CAAAP,SAAAxE,EAAO9C,UAbF8C,EAAO/C,OAiBrB+G,EAAC,OAAA,CACG,cAAY,OACZ,cAAY,mBAEXQ,SAAOxE,EAAA8E,SACF9E,EAAO8E,SACP9E,EAAO9C,SAxChB8C,EAAO/C,SA6CxB+G,EAAC,QAAA,IACOI,EACJnG,UAAU,6BACVV,SAAU0D,GACV,cAAY,6BACZzD,QAASyE,GACTxE,OAAQgF,GACRuC,UAAW9B,GACXjG,MAAOgC,EACPsD,IAAKhD,GACL,gBAAenB,EACf6G,KAAK,WACL,oBAAkB,OAClB,gBAAelG,EACf1B,YACIqB,EAAckC,OAAS,EAAI,GAAKvD,EAEpC6H,aAAa,WAIrBb,EAAC,MAAA,CACGpG,UAAU,qBACVgH,KAAK,UACL1C,IAAKL,GACL9E,GAAIgB,EACJ,kBAAiBG,EACjB,uBAAqB,OACrB,wBAAuBgD,GACvB/D,QAASyE,GACTxE,OAAQgF,GACR8B,UAAU,EAETC,SAAA,CAAQtD,GAAAuC,KAAI,CAACzD,EAAQe,IAClBsD,EAAC,SAAA,CAEG7D,KAAK,SACLpD,GAAI,GAAGgB,MAAW4B,EAAO/C,QACzB,gBAAe8C,GAAWC,GAC1BiF,KAAK,SACLhI,MAAO+C,EAAO/C,MACdQ,OAAQgF,GACRxE,UAAW,wBACP8B,GAAWC,IACX,mCAEJ,cAAY,uBACZ,kBAAiB,wBAAwBe,IACzCvD,QAASyE,GACT+C,UAAWrB,GACXgB,QAAUrE,IACNkB,GACI,GAAGpD,MAAW4B,EAAO/C,SAEzBqD,EAAEK,kBACFE,GAAYb,EAAO/C,OACnBiC,EAAe,GAAE,EAErBiG,YAAanC,GAEZwB,SAAA,CAAOxE,EAAAoF,cACH,OACI,CAAAZ,SAAA,CAAOxE,EAAA9C,MACP8G,EAAA,OAAA,CAAK/F,UAAU,mCACXuG,WAAOY,iBAIhBpF,EAAO9C,MAEV6C,GAAWC,GACRqE,EAAC,OACG,CAAAG,SAAA,CAAAR,EAACqB,EAAU,IAAG,OAElB,OAvCC,GAAGjH,KAAU4B,EAAO/C,WA0ChCkC,GACG6E,EAAC,MAAI,CAAA/F,UAAU,0BACVuG,SACL9G,OAGRsG,EAAC,MAAI,CAAA/F,UAAU,wBACXuG,SAAAR,EAACsB,EAAA,CACGlI,GAAIoB,EACJhB,QAASyE,GACTxE,OAAQgF,GACRxE,UAAU,uBACV,cAAY,uBACZ,aAAY,GACRS,EAAc+E,KAAKxG,GAAUA,EAAMC,SACnC,UACAA,IACJ,gBAAe6B,EACf,gBAAeX,EACf6G,KAAK,SACLN,QAAS,IAAM3F,GAAY,GAC3BuG,YAAcjF,UACVA,EAAE6C,iBACF,OAAAnC,EAAAvB,GAASG,UAAToB,EAAkBnB,OAAA,EAGtB2E,SAAAR,EAACwB,EAAA,CACGC,aAAc5G,YAI9B,EAKhB1B,EAASuI,YAAc"}
@@ -1 +1 @@
1
- export { Combobox, getComboboxValuePair, type ComboboxValuePair, } from './Combobox.js';
1
+ export { Combobox, getComboboxValuePair, type ComboboxValuePair, type ComboboxProps, type ComboboxChangeEventHandler, type ComboboxPartialChangeEvent, } from './Combobox.js';
@@ -1,5 +1,3 @@
1
+ export { CookieConsent, type CookieConsentProps } from './CookieConsent.js';
2
+ export { CookieConsentProvider, useCookieConsent, type CookieConsentProviderProps, } from './CookieConsentContext.js';
1
3
  export type { AcceptConsentCallback, Consent, ConsentState } from './types.js';
2
- export type { CookieConsentProps } from './CookieConsent.js';
3
- export { CookieConsent } from './CookieConsent.js';
4
- export type { CookieConsentProviderProps } from './CookieConsentContext.js';
5
- export { CookieConsentProvider, useCookieConsent, } from './CookieConsentContext.js';
@@ -1,4 +1,4 @@
1
- export * from './types.js';
2
- export * from './validation.js';
3
- export * from './utils.js';
4
1
  export { DatePicker } from './DatePicker.js';
2
+ export { isCorrectFormat, isWithinLowerBound, isWithinUpperBound, } from './validation.js';
3
+ export { formatInput, parseDateString, isBlurTargetOutside } from './utils.js';
4
+ export { type DatePickerProps, type YearsToShow, type DatePickerChangeEventHandler, type DatePickerFocusEventHandler, type DatePickerBlurEventHandler, type DatePickerKeyDownEventHandler, type DatePickerAction, type ComparisonOptions, } from './types.js';
@@ -1,2 +1,2 @@
1
- import{isCorrectFormat as a,isWithinLowerBound as r,isWithinUpperBound as s}from"./validation.js";import{dayMonthYearRegex as t,formatInput as i,isBlurTargetOutside as e,parseDateString as o}from"./utils.js";import{DatePicker as n}from"./DatePicker.js";export{n as DatePicker,t as dayMonthYearRegex,i as formatInput,e as isBlurTargetOutside,a as isCorrectFormat,r as isWithinLowerBound,s as isWithinUpperBound,o as parseDateString};
1
+ import{DatePicker as r}from"./DatePicker.js";import{isCorrectFormat as s,isWithinLowerBound as a,isWithinUpperBound as i}from"./validation.js";import{formatInput as t,isBlurTargetOutside as e,parseDateString as o}from"./utils.js";export{r as DatePicker,t as formatInput,e as isBlurTargetOutside,s as isCorrectFormat,a as isWithinLowerBound,i as isWithinUpperBound,o as parseDateString};
2
2
  //# sourceMappingURL=index.js.map
@@ -268,3 +268,10 @@ export interface DatePickerProps extends Omit<InputGroupProps, "label" | "childr
268
268
  }
269
269
  export interface DatePickerAction extends Exclude<ButtonHTMLAttributes<HTMLButtonElement>, "disabled"> {
270
270
  }
271
+ export type ComparisonOptions = {
272
+ /**
273
+ * Kontroller om testen skal godkjennes om verdien er lik
274
+ * @default false
275
+ */
276
+ inclusive: boolean;
277
+ };
@@ -1,5 +1,4 @@
1
1
  import { default as React } from 'react';
2
- export declare const dayMonthYearRegex: RegExp;
3
2
  /**
4
3
  * Format a Date object as a string in the format DatePicker expects.
5
4
  *
@@ -1,2 +1,2 @@
1
- const e=/^(\d\d?)[\W](\d\d?)[\W](\d{4}|\d{2})$/,t=/^(\d{4}|\d{2})[\W](\d\d?)[\W](\d\d?)$/;function r(e){return`${`${e.getDate()}`.padStart(2,"0")}.${`${e.getMonth()+1}`.padStart(2,"0")}.${e.getFullYear()}`}function n(r){if(!r)return;const n=(r=>{const n=e.exec(r);if(n)return n.slice(1,4);const a=t.exec(r);if(!a)return;const s=a.slice(1,4);return s.reverse(),s})(r);if(!n)return;const a=parseInt((new Date).toLocaleString("no-NB",{year:"2-digit"})),s=parseInt(n[0],10),d=parseInt(n[1],10)-1,i=parseInt(n[2],10),o=i>99?i:(u=i)>a?u+1900:u+2e3,c=new Date(o,d,s,0,0,0);var u;return c.getMonth()===d&&c.getFullYear()===o?c:void 0}function a(e){if(!e.relatedTarget)return!0;const t=e.target.closest(".jkl-datepicker__input-wrapper");return e.relatedTarget.closest(".jkl-datepicker__input-wrapper")!==t}export{e as dayMonthYearRegex,r as formatInput,a as isBlurTargetOutside,n as parseDateString};
1
+ const t=/^(\d\d?)[\W](\d\d?)[\W](\d{4}|\d{2})$/,e=/^(\d{4}|\d{2})[\W](\d\d?)[\W](\d\d?)$/;function r(t){return`${`${t.getDate()}`.padStart(2,"0")}.${`${t.getMonth()+1}`.padStart(2,"0")}.${t.getFullYear()}`}function n(r){if(!r)return;const n=(r=>{const n=t.exec(r);if(n)return n.slice(1,4);const a=e.exec(r);if(!a)return;const s=a.slice(1,4);return s.reverse(),s})(r);if(!n)return;const a=parseInt((new Date).toLocaleString("no-NB",{year:"2-digit"})),s=parseInt(n[0],10),d=parseInt(n[1],10)-1,i=parseInt(n[2],10),o=i>99?i:(u=i)>a?u+1900:u+2e3,c=new Date(o,d,s,0,0,0);var u;return c.getMonth()===d&&c.getFullYear()===o?c:void 0}function a(t){if(!t.relatedTarget)return!0;const e=t.target.closest(".jkl-datepicker__input-wrapper");return t.relatedTarget.closest(".jkl-datepicker__input-wrapper")!==e}export{r as formatInput,a as isBlurTargetOutside,n as parseDateString};
2
2
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../../../src/components/datepicker/utils.ts"],"sourcesContent":["import React from \"react\";\n\nexport const dayMonthYearRegex = /^(\\d\\d?)[\\W](\\d\\d?)[\\W](\\d{4}|\\d{2})$/;\nconst yearMonthDayRegex = /^(\\d{4}|\\d{2})[\\W](\\d\\d?)[\\W](\\d\\d?)$/;\n\n/**\n * Format a Date object as a string in the format DatePicker expects.\n *\n * @param date the Date object to format\n * @return returns a date string with \"dd.mm.yyyy\"-format\n */\nexport function formatInput(date: Date): string {\n const day = `${date.getDate()}`.padStart(2, \"0\");\n const month = `${date.getMonth() + 1}`.padStart(2, \"0\");\n return `${day}.${month}.${date.getFullYear()}`;\n}\n\n/**\n * Get the date segments from a string of unknown format\n *\n * @param input date as a string with unknown format\n * @returns an array of string elements [day, month, year]\n */\nconst getDateSegmentsFromString = (input: string): string[] | undefined => {\n const dayMonthYear = dayMonthYearRegex.exec(input);\n\n if (dayMonthYear) {\n return dayMonthYear.slice(1, 4);\n }\n\n const yearMonthDay = yearMonthDayRegex.exec(input);\n\n if (!yearMonthDay) {\n return undefined;\n }\n\n // reverse to get the correct ordering\n const slicedDateSegments = yearMonthDay.slice(1, 4);\n slicedDateSegments.reverse();\n\n return slicedDateSegments;\n};\n\n/**\n * Convert a date string to a Date object\n *\n * @param dateString date as string with format dd.mm.yyyy\n * @return a Date object representing the given date\n */\nexport function parseDateString(dateString?: string): Date | undefined {\n if (!dateString) {\n return undefined;\n }\n\n const inputDateSegments = getDateSegmentsFromString(dateString);\n\n if (!inputDateSegments) {\n return undefined;\n }\n\n const currentTwoDigitYear = parseInt(\n new Date().toLocaleString(\"no-NB\", { year: \"2-digit\" }),\n );\n const parseTwoDigitYear = (year: number) =>\n year > currentTwoDigitYear ? year + 1900 : year + 2000;\n\n const day = parseInt(inputDateSegments[0], 10);\n const month = parseInt(inputDateSegments[1], 10) - 1;\n const yearIn = parseInt(inputDateSegments[2], 10);\n const year = yearIn > 99 ? yearIn : parseTwoDigitYear(yearIn);\n\n const generatedDate = new Date(year, month, day, 0, 0, 0);\n // Days can \"overflow\" to next month/year in Date(). Return undefined if it does:\n return generatedDate.getMonth() === month &&\n generatedDate.getFullYear() === year\n ? generatedDate\n : undefined;\n}\n\n/**\n * Hjelpefunksjon for å se om en onBlur går utenfor DatePicker,\n * eller om den går til et interaktivt element inni DatePickeren.\n * @param {React.FocusEvent<HTMLButtonElement | HTMLInputElement>} e - Eventet fra onBlur og action.onBlur\n * @returns {boolean} true hvis e.relatedTarget er utenfor DatePicker\n */\nexport function isBlurTargetOutside(\n e: React.FocusEvent<HTMLButtonElement | HTMLInputElement>,\n): boolean {\n if (!e.relatedTarget) {\n return true;\n }\n\n const targetRoot = e.target.closest(\".jkl-datepicker__input-wrapper\");\n const relatedTargetRoot = e.relatedTarget.closest(\n \".jkl-datepicker__input-wrapper\",\n );\n\n return relatedTargetRoot !== targetRoot;\n}\n"],"names":["dayMonthYearRegex","yearMonthDayRegex","formatInput","date","getDate","padStart","getMonth","getFullYear","parseDateString","dateString","inputDateSegments","input","dayMonthYear","exec","slice","yearMonthDay","slicedDateSegments","reverse","getDateSegmentsFromString","currentTwoDigitYear","parseInt","Date","toLocaleString","year","day","month","yearIn","generatedDate","isBlurTargetOutside","e","relatedTarget","targetRoot","target","closest"],"mappings":"AAEO,MAAMA,EAAoB,wCAC3BC,EAAoB,wCAQnB,SAASC,EAAYC,GAGxB,MAAO,GAFK,GAAGA,EAAKC,YAAYC,SAAS,EAAG,QAC9B,GAAGF,EAAKG,WAAa,IAAID,SAAS,EAAG,QACzBF,EAAKI,eACnC,CAkCO,SAASC,EAAgBC,GAC5B,IAAKA,EACM,OAGLC,MAAAA,EA/BwB,CAACC,IACzBC,MAAAA,EAAeZ,EAAkBa,KAAKF,GAExCC,GAAAA,EACOA,OAAAA,EAAaE,MAAM,EAAG,GAG3BC,MAAAA,EAAed,EAAkBY,KAAKF,GAE5C,IAAKI,EACM,OAIX,MAAMC,EAAqBD,EAAaD,MAAM,EAAG,GACjDE,OAAAA,EAAmBC,UAEZD,CAAAA,EAcmBE,CAA0BT,GAEpD,IAAKC,EACM,OAGX,MAAMS,EAAsBC,UACxB,IAAIC,MAAOC,eAAe,QAAS,CAAEC,KAAM,aAKzCC,EAAMJ,SAASV,EAAkB,GAAI,IACrCe,EAAQL,SAASV,EAAkB,GAAI,IAAM,EAC7CgB,EAASN,SAASV,EAAkB,GAAI,IACxCa,EAAOG,EAAS,GAAKA,GANAH,EAM2BG,GAL3CP,EAAsBI,EAAO,KAAOA,EAAO,IAOhDI,EAAgB,IAAIN,KAAKE,EAAME,EAAOD,EAAK,EAAG,EAAG,GAR7B,IAACD,EAUpBI,OAAAA,EAAcrB,aAAemB,GAChCE,EAAcpB,gBAAkBgB,EAC9BI,OACA,CACV,CAQO,SAASC,EACZC,GAEI,IAACA,EAAEC,cACI,OAAA,EAGX,MAAMC,EAAaF,EAAEG,OAAOC,QAAQ,kCAKpC,OAJ0BJ,EAAEC,cAAcG,QACtC,oCAGyBF,CACjC"}
1
+ {"version":3,"file":"utils.js","sources":["../../../../src/components/datepicker/utils.ts"],"sourcesContent":["import React from \"react\";\n\nconst dayMonthYearRegex = /^(\\d\\d?)[\\W](\\d\\d?)[\\W](\\d{4}|\\d{2})$/;\nconst yearMonthDayRegex = /^(\\d{4}|\\d{2})[\\W](\\d\\d?)[\\W](\\d\\d?)$/;\n\n/**\n * Format a Date object as a string in the format DatePicker expects.\n *\n * @param date the Date object to format\n * @return returns a date string with \"dd.mm.yyyy\"-format\n */\nexport function formatInput(date: Date): string {\n const day = `${date.getDate()}`.padStart(2, \"0\");\n const month = `${date.getMonth() + 1}`.padStart(2, \"0\");\n return `${day}.${month}.${date.getFullYear()}`;\n}\n\n/**\n * Get the date segments from a string of unknown format\n *\n * @param input date as a string with unknown format\n * @returns an array of string elements [day, month, year]\n */\nconst getDateSegmentsFromString = (input: string): string[] | undefined => {\n const dayMonthYear = dayMonthYearRegex.exec(input);\n\n if (dayMonthYear) {\n return dayMonthYear.slice(1, 4);\n }\n\n const yearMonthDay = yearMonthDayRegex.exec(input);\n\n if (!yearMonthDay) {\n return undefined;\n }\n\n // reverse to get the correct ordering\n const slicedDateSegments = yearMonthDay.slice(1, 4);\n slicedDateSegments.reverse();\n\n return slicedDateSegments;\n};\n\n/**\n * Convert a date string to a Date object\n *\n * @param dateString date as string with format dd.mm.yyyy\n * @return a Date object representing the given date\n */\nexport function parseDateString(dateString?: string): Date | undefined {\n if (!dateString) {\n return undefined;\n }\n\n const inputDateSegments = getDateSegmentsFromString(dateString);\n\n if (!inputDateSegments) {\n return undefined;\n }\n\n const currentTwoDigitYear = parseInt(\n new Date().toLocaleString(\"no-NB\", { year: \"2-digit\" }),\n );\n const parseTwoDigitYear = (year: number) =>\n year > currentTwoDigitYear ? year + 1900 : year + 2000;\n\n const day = parseInt(inputDateSegments[0], 10);\n const month = parseInt(inputDateSegments[1], 10) - 1;\n const yearIn = parseInt(inputDateSegments[2], 10);\n const year = yearIn > 99 ? yearIn : parseTwoDigitYear(yearIn);\n\n const generatedDate = new Date(year, month, day, 0, 0, 0);\n // Days can \"overflow\" to next month/year in Date(). Return undefined if it does:\n return generatedDate.getMonth() === month &&\n generatedDate.getFullYear() === year\n ? generatedDate\n : undefined;\n}\n\n/**\n * Hjelpefunksjon for å se om en onBlur går utenfor DatePicker,\n * eller om den går til et interaktivt element inni DatePickeren.\n * @param {React.FocusEvent<HTMLButtonElement | HTMLInputElement>} e - Eventet fra onBlur og action.onBlur\n * @returns {boolean} true hvis e.relatedTarget er utenfor DatePicker\n */\nexport function isBlurTargetOutside(\n e: React.FocusEvent<HTMLButtonElement | HTMLInputElement>,\n): boolean {\n if (!e.relatedTarget) {\n return true;\n }\n\n const targetRoot = e.target.closest(\".jkl-datepicker__input-wrapper\");\n const relatedTargetRoot = e.relatedTarget.closest(\n \".jkl-datepicker__input-wrapper\",\n );\n\n return relatedTargetRoot !== targetRoot;\n}\n"],"names":["dayMonthYearRegex","yearMonthDayRegex","formatInput","date","getDate","padStart","getMonth","getFullYear","parseDateString","dateString","inputDateSegments","input","dayMonthYear","exec","slice","yearMonthDay","slicedDateSegments","reverse","getDateSegmentsFromString","currentTwoDigitYear","parseInt","Date","toLocaleString","year","day","month","yearIn","generatedDate","isBlurTargetOutside","e","relatedTarget","targetRoot","target","closest"],"mappings":"AAEA,MAAMA,EAAoB,wCACpBC,EAAoB,wCAQnB,SAASC,EAAYC,GAGxB,MAAO,GAFK,GAAGA,EAAKC,YAAYC,SAAS,EAAG,QAC9B,GAAGF,EAAKG,WAAa,IAAID,SAAS,EAAG,QACzBF,EAAKI,eACnC,CAkCO,SAASC,EAAgBC,GAC5B,IAAKA,EACM,OAGLC,MAAAA,EA/BwB,CAACC,IACzBC,MAAAA,EAAeZ,EAAkBa,KAAKF,GAExCC,GAAAA,EACOA,OAAAA,EAAaE,MAAM,EAAG,GAG3BC,MAAAA,EAAed,EAAkBY,KAAKF,GAE5C,IAAKI,EACM,OAIX,MAAMC,EAAqBD,EAAaD,MAAM,EAAG,GACjDE,OAAAA,EAAmBC,UAEZD,CAAAA,EAcmBE,CAA0BT,GAEpD,IAAKC,EACM,OAGX,MAAMS,EAAsBC,UACxB,IAAIC,MAAOC,eAAe,QAAS,CAAEC,KAAM,aAKzCC,EAAMJ,SAASV,EAAkB,GAAI,IACrCe,EAAQL,SAASV,EAAkB,GAAI,IAAM,EAC7CgB,EAASN,SAASV,EAAkB,GAAI,IACxCa,EAAOG,EAAS,GAAKA,GANAH,EAM2BG,GAL3CP,EAAsBI,EAAO,KAAOA,EAAO,IAOhDI,EAAgB,IAAIN,KAAKE,EAAME,EAAOD,EAAK,EAAG,EAAG,GAR7B,IAACD,EAUpBI,OAAAA,EAAcrB,aAAemB,GAChCE,EAAcpB,gBAAkBgB,EAC9BI,OACA,CACV,CAQO,SAASC,EACZC,GAEI,IAACA,EAAEC,cACI,OAAA,EAGX,MAAMC,EAAaF,EAAEG,OAAOC,QAAQ,kCAKpC,OAJ0BJ,EAAEC,cAAcG,QACtC,oCAGyBF,CACjC"}
@@ -1,11 +1,4 @@
1
+ import { ComparisonOptions } from './types.js';
1
2
  export declare function isCorrectFormat(value: string | undefined): boolean;
2
- type ComparisonOptions = {
3
- /**
4
- * Kontroller om testen skal godkjennes om verdien er lik
5
- * @default false
6
- */
7
- inclusive: boolean;
8
- };
9
3
  export declare function isWithinLowerBound(value: Date | string | undefined, minDate: Date, options?: ComparisonOptions): boolean;
10
4
  export declare function isWithinUpperBound(value: Date | string | undefined, maxDate: Date, options?: ComparisonOptions): boolean;
11
- export {};
@@ -1 +1 @@
1
- {"version":3,"file":"validation.js","sources":["../../../../src/components/datepicker/validation.ts"],"sourcesContent":["import { parseDateString } from \"./utils.js\";\n\nexport function isCorrectFormat(value: string | undefined): boolean {\n if (!value) {\n return false;\n }\n const val = parseDateString(value);\n return Boolean(val);\n}\n\ntype ComparisonOptions = {\n /**\n * Kontroller om testen skal godkjennes om verdien er lik\n * @default false\n */\n inclusive: boolean;\n};\n\nexport function isWithinLowerBound(\n value: Date | string | undefined,\n minDate: Date,\n options: ComparisonOptions = { inclusive: false },\n): boolean {\n const val = typeof value === \"string\" ? parseDateString(value) : value;\n\n if (!val) {\n return false;\n }\n\n if (options.inclusive) {\n return val >= minDate;\n }\n\n return val > minDate;\n}\n\nexport function isWithinUpperBound(\n value: Date | string | undefined,\n maxDate: Date,\n options: ComparisonOptions = { inclusive: false },\n): boolean {\n const val = typeof value === \"string\" ? parseDateString(value) : value;\n\n if (!val) {\n return false;\n }\n\n if (options.inclusive) {\n return val <= maxDate;\n }\n\n return val < maxDate;\n}\n"],"names":["isCorrectFormat","value","parseDateString","isWithinLowerBound","minDate","options","inclusive","val","isWithinUpperBound","maxDate"],"mappings":"6CAEO,SAASA,EAAgBC,GAC5B,QAAKA,KAGOC,EAAgBD,EAEhC,CAUO,SAASE,EACZF,EACAG,EACAC,EAA6B,CAAEC,WAAW,IAE1C,MAAMC,EAAuB,iBAAVN,EAAqBC,EAAgBD,GAASA,EAEjE,QAAKM,IAIDF,EAAQC,UACDC,GAAOH,EAGXG,EAAMH,EACjB,CAEO,SAASI,EACZP,EACAQ,EACAJ,EAA6B,CAAEC,WAAW,IAE1C,MAAMC,EAAuB,iBAAVN,EAAqBC,EAAgBD,GAASA,EAEjE,QAAKM,IAIDF,EAAQC,UACDC,GAAOE,EAGXF,EAAME,EACjB"}
1
+ {"version":3,"file":"validation.js","sources":["../../../../src/components/datepicker/validation.ts"],"sourcesContent":["import { ComparisonOptions } from \"./types.js\";\nimport { parseDateString } from \"./utils.js\";\n\nexport function isCorrectFormat(value: string | undefined): boolean {\n if (!value) {\n return false;\n }\n const val = parseDateString(value);\n return Boolean(val);\n}\n\nexport function isWithinLowerBound(\n value: Date | string | undefined,\n minDate: Date,\n options: ComparisonOptions = { inclusive: false },\n): boolean {\n const val = typeof value === \"string\" ? parseDateString(value) : value;\n\n if (!val) {\n return false;\n }\n\n if (options.inclusive) {\n return val >= minDate;\n }\n\n return val > minDate;\n}\n\nexport function isWithinUpperBound(\n value: Date | string | undefined,\n maxDate: Date,\n options: ComparisonOptions = { inclusive: false },\n): boolean {\n const val = typeof value === \"string\" ? parseDateString(value) : value;\n\n if (!val) {\n return false;\n }\n\n if (options.inclusive) {\n return val <= maxDate;\n }\n\n return val < maxDate;\n}\n"],"names":["isCorrectFormat","value","parseDateString","isWithinLowerBound","minDate","options","inclusive","val","isWithinUpperBound","maxDate"],"mappings":"6CAGO,SAASA,EAAgBC,GAC5B,QAAKA,KAGOC,EAAgBD,EAEhC,CAEO,SAASE,EACZF,EACAG,EACAC,EAA6B,CAAEC,WAAW,IAE1C,MAAMC,EAAuB,iBAAVN,EAAqBC,EAAgBD,GAASA,EAEjE,QAAKM,IAIDF,EAAQC,UACDC,GAAOH,EAGXG,EAAMH,EACjB,CAEO,SAASI,EACZP,EACAQ,EACAJ,EAA6B,CAAEC,WAAW,IAE1C,MAAMC,EAAuB,iBAAVN,EAAqBC,EAAgBD,GAASA,EAEjE,QAAKM,IAIDF,EAAQC,UACDC,GAAOE,EAGXF,EAAME,EACjB"}
@@ -1 +1 @@
1
- export * from './DescriptionList.js';
1
+ export { DescriptionList, DescriptionTerm, DescriptionDetail, type DescriptionListProps, type DescriptionTermProps, type DescriptionDetailProps, } from './DescriptionList.js';
@@ -1,6 +1,5 @@
1
1
  import { default as React } from 'react';
2
2
  import { Density, WithChildren } from '../../core/types.js';
3
- export type ExpandDirection = "up" | "down";
4
3
  export interface ExpanderProps extends WithChildren {
5
4
  as?: "summary" | "button";
6
5
  /** Må settes dersom du ikke bruker CoreToggle. Verdien skal være IDen til innholdet du ekspanderer. */
@@ -16,7 +15,7 @@ export interface ExpanderProps extends WithChildren {
16
15
  */
17
16
  isExpanded?: boolean;
18
17
  /** @default "down" */
19
- expandDirection?: ExpandDirection;
18
+ expandDirection?: "up" | "down";
20
19
  density?: Density;
21
20
  /**
22
21
  * Skjul knappeteksten visuelt.
@@ -1 +1 @@
1
- {"version":3,"file":"Expander.js","sources":["../../../../src/components/expander/Expander.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React, { ForwardedRef } from \"react\";\nimport { Density, WithChildren } from \"../../core/types.js\";\nimport { ArrowVerticalAnimated } from \"../icon/icons/animated/ArrowVerticalAnimated.js\";\nimport { ScreenReaderOnly } from \"../ScreenReaderOnly.js\";\n\nexport type ExpandDirection = \"up\" | \"down\";\n\nexport interface ExpanderProps extends WithChildren {\n as?: \"summary\" | \"button\";\n /** Må settes dersom du ikke bruker CoreToggle. Verdien skal være IDen til innholdet du ekspanderer. */\n \"aria-controls\"?: string;\n /** Må settes dersom du ikke bruker CoreToggle. IDen her skal brukes som verdien til aria-labelledby på innholdet du ekspanderer. */\n id?: string;\n className?: string;\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;\n /**\n * Styrer retningen til pila, som animeres ved endring. Styrer også aria-expanded.\n * @default false\n */\n isExpanded?: boolean;\n /** @default \"down\" */\n expandDirection?: ExpandDirection;\n density?: Density;\n /**\n * Skjul knappeteksten visuelt.\n *\n * @default false\n */\n hideLabel?: boolean;\n}\n\nexport const Expander = React.forwardRef(\n (\n {\n as = \"button\",\n className,\n children,\n density,\n expandDirection = \"down\",\n isExpanded = false,\n hideLabel = false,\n ...rest\n }: ExpanderProps,\n ref: ForwardedRef<HTMLButtonElement>,\n ): JSX.Element => {\n const ContentWrapper = hideLabel ? ScreenReaderOnly : React.Fragment;\n const pointingDown =\n expandDirection === \"down\" ? !isExpanded : isExpanded;\n\n const El = as;\n const type = El === \"button\" ? \"button\" : undefined;\n\n return (\n <El\n aria-expanded={isExpanded}\n data-testid=\"jkl-expander\"\n type={type}\n className={clsx(\"jkl-expander\", className, {\n \"jkl-expander--expanded\": isExpanded,\n \"jkl-expander--icon-only\": !children,\n })}\n {...rest}\n data-density={density}\n ref={ref}\n >\n {children && (\n <ContentWrapper>\n <span className=\"jkl-expander__text\">{children}</span>\n </ContentWrapper>\n )}\n <ArrowVerticalAnimated\n className=\"jkl-expander__arrow\"\n pointingDown={pointingDown}\n bold={isExpanded}\n />\n </El>\n );\n },\n);\n\nExpander.displayName = \"Expander\";\n"],"names":["Expander","React","forwardRef","as","className","children","density","expandDirection","isExpanded","hideLabel","rest","ref","ContentWrapper","ScreenReaderOnly","Fragment","pointingDown","jsxs","type","clsx","jsx","ArrowVerticalAnimated","bold","displayName"],"mappings":"uQAiCO,MAAMA,EAAWC,EAAMC,YAC1B,EAEQC,GAAAA,EAAK,SACLC,UAAAA,EACAC,SAAAA,EACAC,QAAAA,EACAC,gBAAAA,EAAkB,OAClBC,WAAAA,GAAa,EACbC,UAAAA,GAAY,KACTC,GAEPC,KAEMC,MAAAA,EAAiBH,EAAYI,EAAmBZ,EAAMa,SACtDC,EACkB,SAApBR,GAA8BC,EAAaA,EAM3C,OAAAQ,EAJOb,EAIN,CACG,gBAAeK,EACf,cAAY,eACZS,KANY,WADTd,EACoB,cAAW,EAOlCC,UAAWc,EAAK,eAAgBd,EAAW,CACvC,yBAA0BI,EAC1B,2BAA4BH,OAE5BK,EACJ,eAAcJ,EACdK,IAAAA,EAECN,SAAA,CAAAA,KACIO,EACG,CAAAP,SAAAc,EAAC,QAAKf,UAAU,qBAAsBC,SAAAA,MAG9Cc,EAACC,EAAA,CACGhB,UAAU,sBACVW,aAAAA,EACAM,KAAMb,MACV,IAMhBR,EAASsB,YAAc"}
1
+ {"version":3,"file":"Expander.js","sources":["../../../../src/components/expander/Expander.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React, { ForwardedRef } from \"react\";\nimport { Density, WithChildren } from \"../../core/types.js\";\nimport { ArrowVerticalAnimated } from \"../icon/icons/animated/ArrowVerticalAnimated.js\";\nimport { ScreenReaderOnly } from \"../ScreenReaderOnly.js\";\n\nexport interface ExpanderProps extends WithChildren {\n as?: \"summary\" | \"button\";\n /** Må settes dersom du ikke bruker CoreToggle. Verdien skal være IDen til innholdet du ekspanderer. */\n \"aria-controls\"?: string;\n /** Må settes dersom du ikke bruker CoreToggle. IDen her skal brukes som verdien til aria-labelledby på innholdet du ekspanderer. */\n id?: string;\n className?: string;\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;\n /**\n * Styrer retningen til pila, som animeres ved endring. Styrer også aria-expanded.\n * @default false\n */\n isExpanded?: boolean;\n /** @default \"down\" */\n expandDirection?: \"up\" | \"down\";\n density?: Density;\n /**\n * Skjul knappeteksten visuelt.\n *\n * @default false\n */\n hideLabel?: boolean;\n}\n\nexport const Expander = React.forwardRef(\n (\n {\n as = \"button\",\n className,\n children,\n density,\n expandDirection = \"down\",\n isExpanded = false,\n hideLabel = false,\n ...rest\n }: ExpanderProps,\n ref: ForwardedRef<HTMLButtonElement>,\n ): JSX.Element => {\n const ContentWrapper = hideLabel ? ScreenReaderOnly : React.Fragment;\n const pointingDown =\n expandDirection === \"down\" ? !isExpanded : isExpanded;\n\n const El = as;\n const type = El === \"button\" ? \"button\" : undefined;\n\n return (\n <El\n aria-expanded={isExpanded}\n data-testid=\"jkl-expander\"\n type={type}\n className={clsx(\"jkl-expander\", className, {\n \"jkl-expander--expanded\": isExpanded,\n \"jkl-expander--icon-only\": !children,\n })}\n {...rest}\n data-density={density}\n ref={ref}\n >\n {children && (\n <ContentWrapper>\n <span className=\"jkl-expander__text\">{children}</span>\n </ContentWrapper>\n )}\n <ArrowVerticalAnimated\n className=\"jkl-expander__arrow\"\n pointingDown={pointingDown}\n bold={isExpanded}\n />\n </El>\n );\n },\n);\n\nExpander.displayName = \"Expander\";\n"],"names":["Expander","React","forwardRef","as","className","children","density","expandDirection","isExpanded","hideLabel","rest","ref","ContentWrapper","ScreenReaderOnly","Fragment","pointingDown","jsxs","type","clsx","jsx","ArrowVerticalAnimated","bold","displayName"],"mappings":"uQA+BO,MAAMA,EAAWC,EAAMC,YAC1B,EAEQC,GAAAA,EAAK,SACLC,UAAAA,EACAC,SAAAA,EACAC,QAAAA,EACAC,gBAAAA,EAAkB,OAClBC,WAAAA,GAAa,EACbC,UAAAA,GAAY,KACTC,GAEPC,KAEMC,MAAAA,EAAiBH,EAAYI,EAAmBZ,EAAMa,SACtDC,EACkB,SAApBR,GAA8BC,EAAaA,EAM3C,OAAAQ,EAJOb,EAIN,CACG,gBAAeK,EACf,cAAY,eACZS,KANY,WADTd,EACoB,cAAW,EAOlCC,UAAWc,EAAK,eAAgBd,EAAW,CACvC,yBAA0BI,EAC1B,2BAA4BH,OAE5BK,EACJ,eAAcJ,EACdK,IAAAA,EAECN,SAAA,CAAAA,KACIO,EACG,CAAAP,SAAAc,EAAC,QAAKf,UAAU,qBAAsBC,SAAAA,MAG9Cc,EAACC,EAAA,CACGhB,UAAU,sBACVW,aAAAA,EACAM,KAAMb,MACV,IAMhBR,EAASsB,YAAc"}
@@ -1,4 +1,2 @@
1
- export type { ExpanderProps as ExpandButtonProps } from './Expander.js';
2
- export { Expander } from './Expander.js';
3
- export type { ExpandSectionProps } from './ExpandSection.js';
4
- export { ExpandSection } from './ExpandSection.js';
1
+ export { Expander, type ExpanderProps } from './Expander.js';
2
+ export { ExpandSection, type ExpandSectionProps } from './ExpandSection.js';
@@ -1,11 +1,7 @@
1
- import { ComponentProps, ReactElement, ReactNode } from 'react';
1
+ import { ReactElement, ReactNode } from 'react';
2
2
  import { BaseTextAreaProps } from '../text-input/BaseTextArea.js';
3
- import { Followup } from './followup/Followup.js';
4
- import { ContactQuestion } from './questions/ContactQuestion.js';
5
- import { FeedbackOption, FeedbackType } from './types.js';
6
- type FollowupProps = ComponentProps<typeof Followup>;
7
- type ContactQuestionProps = ComponentProps<typeof ContactQuestion>;
8
- type Props = {
3
+ import { ContactQuestionProps, FeedbackOption, FeedbackType, FollowupProps } from './types.js';
4
+ export type FeedbackProps = {
9
5
  className?: string;
10
6
  /** Velg typen alternativer, Smiley eller RadioButtons. */
11
7
  type: "radio" | "smiley";
@@ -46,5 +42,4 @@ type Props = {
46
42
  */
47
43
  landmarkLabel?: string;
48
44
  } & Pick<BaseTextAreaProps, "counter">;
49
- export declare const Feedback: ({ className, followup, contactQuestion, counter, landmarkLabel, ...mainQuestionProps }: Props) => ReactElement;
50
- export {};
45
+ export declare const Feedback: ({ className, followup, contactQuestion, counter, landmarkLabel, ...mainQuestionProps }: FeedbackProps) => ReactElement;
@@ -1 +1 @@
1
- {"version":3,"file":"Feedback.js","sources":["../../../../src/components/feedback/Feedback.tsx"],"sourcesContent":["import React, {\n ComponentProps,\n ReactElement,\n ReactNode,\n useState,\n} from \"react\";\nimport { BaseTextAreaProps } from \"../text-input/BaseTextArea.js\";\nimport { FeedbackContextProvider } from \"./feedbackContext.js\";\nimport { Followup } from \"./followup/Followup.js\";\nimport { MainQuestion } from \"./main-question/MainQuestion.js\";\nimport { ContactQuestion } from \"./questions/ContactQuestion.js\";\nimport { FeedbackOption, FeedbackType } from \"./types.js\";\n\ntype FollowupProps = ComponentProps<typeof Followup>;\ntype ContactQuestionProps = ComponentProps<typeof ContactQuestion>;\n\ntype Props = {\n className?: string;\n /** Velg typen alternativer, Smiley eller RadioButtons. */\n type: \"radio\" | \"smiley\";\n /** Spørsmålet som stilles til brukeren */\n label: string;\n /** Hjelpetekst til hovedspørsmålet */\n helpLabel?: string;\n /** Svaralternativer til spørsmålet */\n options: FeedbackOption[];\n /** Dersom du vil stille et åpent spørsmål i tillegg kan du sette denne til en truthy verdi */\n addOnQuestion?:\n | {\n /** Spørsmålet du vil stille */\n label?: string;\n /** Eventuell hjelpetekst. Om du ikke spesifiserer en vil det vises en påminnelse om å ikke skrive inn personling informasjon. */\n helpLabel?: string;\n }\n | boolean;\n /** Lar deg tilpasse meldingen som kommer når brukeren sender inn tilbakemeldingen. */\n successMessage?: {\n title: string;\n children: ReactNode;\n };\n /**\n * Funksjon for å håndtere innsending av tilbakemelding\n * @param value Verdien av tilbakemeldingen. Dette er et objekt med følgende egenskaper:\n * - `feedbackValue`: Selve verdien av tilbakemeldingen (format varierer etter spørsmålstype)\n * - `intentionalSubmit`: Er `true` hvis brukeren aktivt sendte inn skjemaet, `false` hvis skjemaet ble sendt inn automatisk\n * - `message`: Eventuell utfyllende melding fra bruker. Blir kun sendt inn ved aktiv innsending\n */\n onSubmit: (value: FeedbackType) => void;\n followup?: FollowupProps;\n contactQuestion?: ContactQuestionProps;\n /**\n * Hvis du ønsker at Feedback formen skal eksponeres som et landmark kan du sende inn\n * hva du ønsker at en skjermleser skal kalle den her. Bare eksponer Feedback som et\n * landmark på sider der den er en viktig del av innholdet, feks en kvitteringsside\n * eller et annet sted det å kunne gi tilbakemelding vil føles naturlig eller forventet\n * for brukeren.\n */\n landmarkLabel?: string;\n} & Pick<BaseTextAreaProps, \"counter\">;\n\nexport const Feedback = ({\n className,\n followup,\n contactQuestion,\n counter,\n landmarkLabel,\n ...mainQuestionProps\n}: Props): ReactElement => {\n const [feedbackSubmitted, setFeedbackSubmitted] = useState(false);\n const [followupStarted, setFollowupStarted] = useState(false);\n const [followupSubmitted, setFollowupSubmitted] = useState(false);\n const [contactSubmitted, setContactSubmitted] = useState(false);\n\n return (\n <div\n className={`jkl-feedback ${className || \"\"}`}\n data-testid=\"feedback\"\n >\n <FeedbackContextProvider\n value={{\n feedbackSubmitted,\n followupStarted,\n followupSubmitted,\n contactSubmitted,\n counter,\n landmarkLabel,\n setFeedbackSubmitted,\n setFollowupStarted,\n setFollowupSubmitted,\n setContactSubmitted,\n }}\n >\n {!followupStarted && <MainQuestion {...mainQuestionProps} />}\n {feedbackSubmitted && !contactSubmitted && followup && (\n <Followup {...followup} />\n )}\n {contactQuestion && (\n <div aria-live=\"polite\">\n {/* Show contact question after followup, or after feedback if no followup */}\n {((!followup && feedbackSubmitted) ||\n followupSubmitted) && (\n <ContactQuestion {...contactQuestion} />\n )}\n </div>\n )}\n </FeedbackContextProvider>\n </div>\n );\n};\n"],"names":["Feedback","className","followup","contactQuestion","counter","landmarkLabel","mainQuestionProps","feedbackSubmitted","setFeedbackSubmitted","useState","followupStarted","setFollowupStarted","followupSubmitted","setFollowupSubmitted","contactSubmitted","setContactSubmitted","jsx","children","jsxs","FeedbackContextProvider","value","MainQuestion","Followup","ContactQuestion"],"mappings":"oUA4DO,MAAMA,EAAW,EACpBC,UAAAA,EACAC,SAAAA,EACAC,gBAAAA,EACAC,QAAAA,EACAC,cAAAA,KACGC,MAEG,MAACC,EAAmBC,GAAwBC,GAAS,IACpDC,EAAiBC,GAAsBF,GAAS,IAChDG,EAAmBC,GAAwBJ,GAAS,IACpDK,EAAkBC,GAAuBN,GAAS,GAGrD,OAAAO,EAAC,MAAA,CACGf,UAAW,gBAAgBA,GAAa,KACxC,cAAY,WAEZgB,SAAAC,EAACC,EAAA,CACGC,MAAO,CACHb,kBAAAA,EACAG,gBAAAA,EACAE,kBAAAA,EACAE,iBAAAA,EACAV,QAAAA,EACAC,cAAAA,EACAG,qBAAAA,EACAG,mBAAAA,EACAE,qBAAAA,EACAE,oBAAAA,GAGHE,SAAA,EAACP,GAAmBM,EAACK,EAAc,IAAGf,IACtCC,IAAsBO,GAAoBZ,GACtCc,EAAAM,EAAA,IAAapB,IAEjBC,GACGa,EAAC,MAAI,CAAA,YAAU,SAERC,WAACf,GAAYK,GACZK,IACAI,EAACO,EAAiB,IAAGpB,UAIrC"}
1
+ {"version":3,"file":"Feedback.js","sources":["../../../../src/components/feedback/Feedback.tsx"],"sourcesContent":["import React, { ReactElement, ReactNode, useState } from \"react\";\nimport { BaseTextAreaProps } from \"../text-input/BaseTextArea.js\";\nimport { FeedbackContextProvider } from \"./feedbackContext.js\";\nimport { Followup } from \"./followup/Followup.js\";\nimport { MainQuestion } from \"./main-question/MainQuestion.js\";\nimport { ContactQuestion } from \"./questions/ContactQuestion.js\";\nimport {\n ContactQuestionProps,\n FeedbackOption,\n FeedbackType,\n FollowupProps,\n} from \"./types.js\";\n\nexport type FeedbackProps = {\n className?: string;\n /** Velg typen alternativer, Smiley eller RadioButtons. */\n type: \"radio\" | \"smiley\";\n /** Spørsmålet som stilles til brukeren */\n label: string;\n /** Hjelpetekst til hovedspørsmålet */\n helpLabel?: string;\n /** Svaralternativer til spørsmålet */\n options: FeedbackOption[];\n /** Dersom du vil stille et åpent spørsmål i tillegg kan du sette denne til en truthy verdi */\n addOnQuestion?:\n | {\n /** Spørsmålet du vil stille */\n label?: string;\n /** Eventuell hjelpetekst. Om du ikke spesifiserer en vil det vises en påminnelse om å ikke skrive inn personling informasjon. */\n helpLabel?: string;\n }\n | boolean;\n /** Lar deg tilpasse meldingen som kommer når brukeren sender inn tilbakemeldingen. */\n successMessage?: {\n title: string;\n children: ReactNode;\n };\n /**\n * Funksjon for å håndtere innsending av tilbakemelding\n * @param value Verdien av tilbakemeldingen. Dette er et objekt med følgende egenskaper:\n * - `feedbackValue`: Selve verdien av tilbakemeldingen (format varierer etter spørsmålstype)\n * - `intentionalSubmit`: Er `true` hvis brukeren aktivt sendte inn skjemaet, `false` hvis skjemaet ble sendt inn automatisk\n * - `message`: Eventuell utfyllende melding fra bruker. Blir kun sendt inn ved aktiv innsending\n */\n onSubmit: (value: FeedbackType) => void;\n followup?: FollowupProps;\n contactQuestion?: ContactQuestionProps;\n /**\n * Hvis du ønsker at Feedback formen skal eksponeres som et landmark kan du sende inn\n * hva du ønsker at en skjermleser skal kalle den her. Bare eksponer Feedback som et\n * landmark på sider der den er en viktig del av innholdet, feks en kvitteringsside\n * eller et annet sted det å kunne gi tilbakemelding vil føles naturlig eller forventet\n * for brukeren.\n */\n landmarkLabel?: string;\n} & Pick<BaseTextAreaProps, \"counter\">;\n\nexport const Feedback = ({\n className,\n followup,\n contactQuestion,\n counter,\n landmarkLabel,\n ...mainQuestionProps\n}: FeedbackProps): ReactElement => {\n const [feedbackSubmitted, setFeedbackSubmitted] = useState(false);\n const [followupStarted, setFollowupStarted] = useState(false);\n const [followupSubmitted, setFollowupSubmitted] = useState(false);\n const [contactSubmitted, setContactSubmitted] = useState(false);\n\n return (\n <div\n className={`jkl-feedback ${className || \"\"}`}\n data-testid=\"feedback\"\n >\n <FeedbackContextProvider\n value={{\n feedbackSubmitted,\n followupStarted,\n followupSubmitted,\n contactSubmitted,\n counter,\n landmarkLabel,\n setFeedbackSubmitted,\n setFollowupStarted,\n setFollowupSubmitted,\n setContactSubmitted,\n }}\n >\n {!followupStarted && <MainQuestion {...mainQuestionProps} />}\n {feedbackSubmitted && !contactSubmitted && followup && (\n <Followup {...followup} />\n )}\n {contactQuestion && (\n <div aria-live=\"polite\">\n {/* Show contact question after followup, or after feedback if no followup */}\n {((!followup && feedbackSubmitted) ||\n followupSubmitted) && (\n <ContactQuestion {...contactQuestion} />\n )}\n </div>\n )}\n </FeedbackContextProvider>\n </div>\n );\n};\n"],"names":["Feedback","className","followup","contactQuestion","counter","landmarkLabel","mainQuestionProps","feedbackSubmitted","setFeedbackSubmitted","useState","followupStarted","setFollowupStarted","followupSubmitted","setFollowupSubmitted","contactSubmitted","setContactSubmitted","jsx","children","jsxs","FeedbackContextProvider","value","MainQuestion","Followup","ContactQuestion"],"mappings":"oUAyDO,MAAMA,EAAW,EACpBC,UAAAA,EACAC,SAAAA,EACAC,gBAAAA,EACAC,QAAAA,EACAC,cAAAA,KACGC,MAEG,MAACC,EAAmBC,GAAwBC,GAAS,IACpDC,EAAiBC,GAAsBF,GAAS,IAChDG,EAAmBC,GAAwBJ,GAAS,IACpDK,EAAkBC,GAAuBN,GAAS,GAGrD,OAAAO,EAAC,MAAA,CACGf,UAAW,gBAAgBA,GAAa,KACxC,cAAY,WAEZgB,SAAAC,EAACC,EAAA,CACGC,MAAO,CACHb,kBAAAA,EACAG,gBAAAA,EACAE,kBAAAA,EACAE,iBAAAA,EACAV,QAAAA,EACAC,cAAAA,EACAG,qBAAAA,EACAG,mBAAAA,EACAE,qBAAAA,EACAE,oBAAAA,GAGHE,SAAA,EAACP,GAAmBM,EAACK,EAAc,IAAGf,IACtCC,IAAsBO,GAAoBZ,GACtCc,EAAAM,EAAA,IAAapB,IAEjBC,GACGa,EAAC,MAAI,CAAA,YAAU,SAERC,WAACf,GAAYK,GACZK,IACAI,EAACO,EAAiB,IAAGpB,UAIrC"}
@@ -1,14 +1,3 @@
1
- import { FC, ReactNode } from 'react';
2
- import { FeedbackAnswer, FollowupQuestion } from '../types.js';
3
- interface Props {
4
- /** Spørsmålet/ene som skal stilles. Kan være av typen radio, checkbox eller text */
5
- questions: FollowupQuestion[];
6
- /** Lar deg tilpasse meldingen som kommer når brukeren har svart på spørsmålene. */
7
- successMessage?: {
8
- title: string;
9
- children: ReactNode;
10
- };
11
- onSubmit: (values: FeedbackAnswer[]) => void;
12
- }
13
- export declare const Followup: FC<Props>;
14
- export {};
1
+ import { FC } from 'react';
2
+ import { FollowupProps } from '../types.js';
3
+ export declare const Followup: FC<FollowupProps>;
@@ -1 +1 @@
1
- {"version":3,"file":"Followup.js","sources":["../../../../../src/components/feedback/followup/Followup.tsx"],"sourcesContent":["import React, { FC, ReactNode, useEffect, useRef, useState } from \"react\";\nimport {\n PrimaryButton,\n SecondaryButton,\n TertiaryButton,\n} from \"../../button/Button.js\";\nimport { useFeedbackContext } from \"../feedbackContext.js\";\nimport { FeedbackSuccess } from \"../FeedbackSuccess.js\";\nimport { FeedbackAnswer, FollowupQuestion } from \"../types.js\";\nimport { getQuestionFromType } from \"../utils.js\";\nimport { FollowUpProvider } from \"./followupContext.js\";\nimport { useFollowup } from \"./useFollowup.js\";\n\nconst defaultSuccessMessage = {\n title: \"Takk, igjen!\",\n children:\n \"Vi setter pris på at du tok deg tid til å svare på flere spørsmål. Det hjelper oss med å gjøre nettsidene bedre for deg og alle andre som bruker dem.\",\n};\n\ninterface Props {\n /** Spørsmålet/ene som skal stilles. Kan være av typen radio, checkbox eller text */\n questions: FollowupQuestion[];\n /** Lar deg tilpasse meldingen som kommer når brukeren har svart på spørsmålene. */\n successMessage?: {\n title: string;\n children: ReactNode;\n };\n onSubmit: (values: FeedbackAnswer[]) => void;\n}\n\nexport const Followup: FC<Props> = ({\n questions,\n successMessage = defaultSuccessMessage,\n onSubmit,\n}) => {\n const [noThanks, setNoThanks] = useState(false);\n const focusRef = useRef<HTMLParagraphElement>(null);\n const followupState = useFollowup(questions, onSubmit);\n const { handleAbort, handleNext, step, submitted } = followupState;\n const {\n followupStarted,\n setFollowupStarted,\n setFollowupSubmitted,\n contactSubmitted,\n landmarkLabel,\n } = useFeedbackContext();\n\n useEffect(() => {\n if (step.number === 0) {\n return;\n }\n focusRef.current && focusRef.current.focus();\n }, [step]);\n\n useEffect(() => {\n setFollowupSubmitted(submitted);\n }, [submitted, setFollowupSubmitted]);\n\n const QuestionComponent = getQuestionFromType(questions[step.number].type);\n const Button = step.isLast ? PrimaryButton : SecondaryButton;\n\n if (noThanks) {\n return null;\n }\n\n return (\n <div aria-live=\"polite\">\n <FollowUpProvider state={followupState}>\n {!followupStarted && (\n <div className=\"jkl-feedback__fade-in\">\n <p className=\"jkl-heading-4 jkl-spacing-xl--top jkl-spacing-xs--bottom\">\n Har du tid til å svare på noen flere spørsmål?\n </p>\n <p className=\"jkl-body jkl-spacing-xl--bottom\">\n Det tar kun et minutt, og hjelper oss å lage bedre\n løsninger for deg.\n </p>\n <PrimaryButton\n onClick={() => setFollowupStarted(true)}\n className=\"jkl-spacing-xl--right\"\n >\n Jeg har tid!\n </PrimaryButton>\n <TertiaryButton onClick={() => setNoThanks(true)}>\n Nei takk\n </TertiaryButton>\n </div>\n )}\n {!submitted && followupStarted && (\n <form\n onSubmit={handleNext}\n className=\"jkl-feedback__fade-in\"\n aria-label={landmarkLabel}\n >\n <p\n className=\"jkl-feedback__step-counter\"\n ref={focusRef}\n >\n Steg {step.number + 1} av {questions.length}\n </p>\n <QuestionComponent\n {...questions[step.number]}\n // eslint-disable-next-line jsx-a11y/no-autofocus\n autoFocus\n key={step.number}\n />\n <div className=\"jkl-spacing-xl--top\" aria-live=\"off\">\n <Button type=\"submit\">\n {step.isLast ? \"Send inn\" : \"Neste\"}\n </Button>\n <TertiaryButton\n onClick={handleAbort}\n className=\"jkl-spacing-xl--left\"\n >\n Avbryt\n </TertiaryButton>\n </div>\n </form>\n )}\n {submitted && !contactSubmitted && (\n <FeedbackSuccess {...successMessage} />\n )}\n </FollowUpProvider>\n </div>\n );\n};\n"],"names":["defaultSuccessMessage","title","children","Followup","questions","successMessage","onSubmit","noThanks","setNoThanks","useState","focusRef","useRef","followupState","useFollowup","handleAbort","handleNext","step","submitted","followupStarted","setFollowupStarted","setFollowupSubmitted","contactSubmitted","landmarkLabel","useFeedbackContext","useEffect","number","current","focus","QuestionComponent","getQuestionFromType","type","Button","isLast","PrimaryButton","SecondaryButton","jsxs","FollowUpProvider","state","className","jsx","onClick","TertiaryButton","ref","length","createElement","autoFocus","key","FeedbackSuccess"],"mappings":"6eAaA,MAAMA,EAAwB,CAC1BC,MAAO,eACPC,SACI,yJAcKC,EAAsB,EAC/BC,UAAAA,EACAC,eAAAA,EAAiBL,EACjBM,SAAAA,MAEM,MAACC,EAAUC,GAAeC,GAAS,GACnCC,EAAWC,EAA6B,MACxCC,EAAgBC,EAAYT,EAAWE,IACrCQ,YAAAA,EAAaC,WAAAA,EAAYC,KAAAA,EAAMC,UAAAA,GAAcL,GAEjDM,gBAAAA,EACAC,mBAAAA,EACAC,qBAAAA,EACAC,iBAAAA,EACAC,cAAAA,GACAC,IAEJC,GAAU,KACc,IAAhBR,EAAKS,QAGAf,EAAAgB,SAAWhB,EAASgB,QAAQC,OAAM,GAC5C,CAACX,IAEJQ,GAAU,KACNJ,EAAqBH,EAAS,GAC/B,CAACA,EAAWG,IAETQ,MAAAA,EAAoBC,EAAoBzB,EAAUY,EAAKS,QAAQK,MAC/DC,EAASf,EAAKgB,OAASC,EAAgBC,EAE7C,OAAI3B,EACO,OAIN,MAAI,CAAA,YAAU,SACXL,SAACiC,EAAAC,EAAA,CAAiBC,MAAOzB,EACpBV,SAAA,EAACgB,GACEiB,EAAC,MAAI,CAAAG,UAAU,wBACXpC,SAAA,CAACqC,EAAA,IAAA,CAAED,UAAU,2DAA2DpC,SAExE,mDACCqC,EAAA,IAAA,CAAED,UAAU,kCAAkCpC,SAG/C,0EACAqC,EAACN,EAAA,CACGO,QAAS,IAAMrB,GAAmB,GAClCmB,UAAU,wBACbpC,SAAA,mBAGAuC,EAAe,CAAAD,QAAS,IAAMhC,GAAY,GAAON,SAElD,iBAGNe,GAAaC,GACXiB,EAAC,OAAA,CACG7B,SAAUS,EACVuB,UAAU,wBACV,aAAYhB,EAEZpB,SAAA,CAAAiC,EAAC,IAAA,CACGG,UAAU,6BACVI,IAAKhC,EACRR,SAAA,CAAA,QACSc,EAAKS,OAAS,EAAE,OAAKrB,EAAUuC,UAEzCC,EAAChB,EAAA,IACOxB,EAAUY,EAAKS,QAEnBoB,WAAS,EACTC,IAAK9B,EAAKS,SAEbU,EAAA,MAAA,CAAIG,UAAU,sBAAsB,YAAU,MAC3CpC,SAAA,CAAAqC,EAACR,GAAOD,KAAK,SACR5B,SAAKc,EAAAgB,OAAS,WAAa,UAEhCO,EAACE,EAAA,CACGD,QAAS1B,EACTwB,UAAU,uBACbpC,SAAA,iBAMZe,IAAcI,GACVkB,EAAAQ,EAAA,IAAoB1C,QAGjC"}
1
+ {"version":3,"file":"Followup.js","sources":["../../../../../src/components/feedback/followup/Followup.tsx"],"sourcesContent":["import React, { FC, useEffect, useRef, useState } from \"react\";\nimport {\n PrimaryButton,\n SecondaryButton,\n TertiaryButton,\n} from \"../../button/Button.js\";\nimport { useFeedbackContext } from \"../feedbackContext.js\";\nimport { FeedbackSuccess } from \"../FeedbackSuccess.js\";\nimport { FollowupProps } from \"../types.js\";\nimport { getQuestionFromType } from \"../utils.js\";\nimport { FollowUpProvider } from \"./followupContext.js\";\nimport { useFollowup } from \"./useFollowup.js\";\n\nconst defaultSuccessMessage = {\n title: \"Takk, igjen!\",\n children:\n \"Vi setter pris på at du tok deg tid til å svare på flere spørsmål. Det hjelper oss med å gjøre nettsidene bedre for deg og alle andre som bruker dem.\",\n};\n\nexport const Followup: FC<FollowupProps> = ({\n questions,\n successMessage = defaultSuccessMessage,\n onSubmit,\n}) => {\n const [noThanks, setNoThanks] = useState(false);\n const focusRef = useRef<HTMLParagraphElement>(null);\n const followupState = useFollowup(questions, onSubmit);\n const { handleAbort, handleNext, step, submitted } = followupState;\n const {\n followupStarted,\n setFollowupStarted,\n setFollowupSubmitted,\n contactSubmitted,\n landmarkLabel,\n } = useFeedbackContext();\n\n useEffect(() => {\n if (step.number === 0) {\n return;\n }\n focusRef.current && focusRef.current.focus();\n }, [step]);\n\n useEffect(() => {\n setFollowupSubmitted(submitted);\n }, [submitted, setFollowupSubmitted]);\n\n const QuestionComponent = getQuestionFromType(questions[step.number].type);\n const Button = step.isLast ? PrimaryButton : SecondaryButton;\n\n if (noThanks) {\n return null;\n }\n\n return (\n <div aria-live=\"polite\">\n <FollowUpProvider state={followupState}>\n {!followupStarted && (\n <div className=\"jkl-feedback__fade-in\">\n <p className=\"jkl-heading-4 jkl-spacing-xl--top jkl-spacing-xs--bottom\">\n Har du tid til å svare på noen flere spørsmål?\n </p>\n <p className=\"jkl-body jkl-spacing-xl--bottom\">\n Det tar kun et minutt, og hjelper oss å lage bedre\n løsninger for deg.\n </p>\n <PrimaryButton\n onClick={() => setFollowupStarted(true)}\n className=\"jkl-spacing-xl--right\"\n >\n Jeg har tid!\n </PrimaryButton>\n <TertiaryButton onClick={() => setNoThanks(true)}>\n Nei takk\n </TertiaryButton>\n </div>\n )}\n {!submitted && followupStarted && (\n <form\n onSubmit={handleNext}\n className=\"jkl-feedback__fade-in\"\n aria-label={landmarkLabel}\n >\n <p\n className=\"jkl-feedback__step-counter\"\n ref={focusRef}\n >\n Steg {step.number + 1} av {questions.length}\n </p>\n <QuestionComponent\n {...questions[step.number]}\n // eslint-disable-next-line jsx-a11y/no-autofocus\n autoFocus\n key={step.number}\n />\n <div className=\"jkl-spacing-xl--top\" aria-live=\"off\">\n <Button type=\"submit\">\n {step.isLast ? \"Send inn\" : \"Neste\"}\n </Button>\n <TertiaryButton\n onClick={handleAbort}\n className=\"jkl-spacing-xl--left\"\n >\n Avbryt\n </TertiaryButton>\n </div>\n </form>\n )}\n {submitted && !contactSubmitted && (\n <FeedbackSuccess {...successMessage} />\n )}\n </FollowUpProvider>\n </div>\n );\n};\n"],"names":["defaultSuccessMessage","title","children","Followup","questions","successMessage","onSubmit","noThanks","setNoThanks","useState","focusRef","useRef","followupState","useFollowup","handleAbort","handleNext","step","submitted","followupStarted","setFollowupStarted","setFollowupSubmitted","contactSubmitted","landmarkLabel","useFeedbackContext","useEffect","number","current","focus","QuestionComponent","getQuestionFromType","type","Button","isLast","PrimaryButton","SecondaryButton","jsxs","FollowUpProvider","state","className","jsx","onClick","TertiaryButton","ref","length","createElement","autoFocus","key","FeedbackSuccess"],"mappings":"6eAaA,MAAMA,EAAwB,CAC1BC,MAAO,eACPC,SACI,yJAGKC,EAA8B,EACvCC,UAAAA,EACAC,eAAAA,EAAiBL,EACjBM,SAAAA,MAEM,MAACC,EAAUC,GAAeC,GAAS,GACnCC,EAAWC,EAA6B,MACxCC,EAAgBC,EAAYT,EAAWE,IACrCQ,YAAAA,EAAaC,WAAAA,EAAYC,KAAAA,EAAMC,UAAAA,GAAcL,GAEjDM,gBAAAA,EACAC,mBAAAA,EACAC,qBAAAA,EACAC,iBAAAA,EACAC,cAAAA,GACAC,IAEJC,GAAU,KACc,IAAhBR,EAAKS,QAGAf,EAAAgB,SAAWhB,EAASgB,QAAQC,OAAM,GAC5C,CAACX,IAEJQ,GAAU,KACNJ,EAAqBH,EAAS,GAC/B,CAACA,EAAWG,IAETQ,MAAAA,EAAoBC,EAAoBzB,EAAUY,EAAKS,QAAQK,MAC/DC,EAASf,EAAKgB,OAASC,EAAgBC,EAE7C,OAAI3B,EACO,OAIN,MAAI,CAAA,YAAU,SACXL,SAACiC,EAAAC,EAAA,CAAiBC,MAAOzB,EACpBV,SAAA,EAACgB,GACEiB,EAAC,MAAI,CAAAG,UAAU,wBACXpC,SAAA,CAACqC,EAAA,IAAA,CAAED,UAAU,2DAA2DpC,SAExE,mDACCqC,EAAA,IAAA,CAAED,UAAU,kCAAkCpC,SAG/C,0EACAqC,EAACN,EAAA,CACGO,QAAS,IAAMrB,GAAmB,GAClCmB,UAAU,wBACbpC,SAAA,mBAGAuC,EAAe,CAAAD,QAAS,IAAMhC,GAAY,GAAON,SAElD,iBAGNe,GAAaC,GACXiB,EAAC,OAAA,CACG7B,SAAUS,EACVuB,UAAU,wBACV,aAAYhB,EAEZpB,SAAA,CAAAiC,EAAC,IAAA,CACGG,UAAU,6BACVI,IAAKhC,EACRR,SAAA,CAAA,QACSc,EAAKS,OAAS,EAAE,OAAKrB,EAAUuC,UAEzCC,EAAChB,EAAA,IACOxB,EAAUY,EAAKS,QAEnBoB,WAAS,EACTC,IAAK9B,EAAKS,SAEbU,EAAA,MAAA,CAAIG,UAAU,sBAAsB,YAAU,MAC3CpC,SAAA,CAAAqC,EAACR,GAAOD,KAAK,SACR5B,SAAKc,EAAAgB,OAAS,WAAa,UAEhCO,EAACE,EAAA,CACGD,QAAS1B,EACTwB,UAAU,uBACbpC,SAAA,iBAMZe,IAAcI,GACVkB,EAAAQ,EAAA,IAAoB1C,QAGjC"}
@@ -1,3 +1,3 @@
1
- import { Feedback } from './Feedback.js';
2
- import { PRESETS } from './presets.js';
3
- export { Feedback, PRESETS };
1
+ export { Feedback, type FeedbackProps } from './Feedback.js';
2
+ export { PRESETS, type PresetProperties } from './presets.js';
3
+ export { type FeedbackOption, type FeedbackType, type FollowupProps, type FollowupQuestion, type MainQuestion, type RadioQuestion, type SmileyQuestion, type CheckboxQuestion, type TextQuestion, type ContactQuestionProps, type FeedbackAnswer, type SingleFeedbackAnswer, type MultiFeedbackAnswer, } from './types.js';
@@ -1,6 +1,3 @@
1
- import { ComponentProps } from 'react';
2
- import { Feedback } from './Feedback.js';
3
- type FeedbackProps = ComponentProps<typeof Feedback>;
4
- type PresetProperties = Pick<FeedbackProps, "label" | "type" | "options" | "addOnQuestion">;
1
+ import { FeedbackProps } from './Feedback.js';
2
+ export type PresetProperties = Pick<FeedbackProps, "label" | "type" | "options" | "addOnQuestion">;
5
3
  export declare const PRESETS: Record<string, PresetProperties>;
6
- export {};
@@ -1 +1 @@
1
- {"version":3,"file":"presets.js","sources":["../../../../src/components/feedback/presets.tsx"],"sourcesContent":["import { ComponentProps } from \"react\";\nimport { Feedback } from \"./Feedback.js\";\nimport { defaultOptions as smileyOptions } from \"./questions/smileyUtils.js\";\n\ntype FeedbackProps = ComponentProps<typeof Feedback>;\ntype PresetProperties = Pick<\n FeedbackProps,\n \"label\" | \"type\" | \"options\" | \"addOnQuestion\"\n>;\n\nconst smileyQuestion: PresetProperties = {\n type: \"smiley\",\n label: \"Hvor fornøyd er du med denne nettsiden?\",\n options: smileyOptions,\n addOnQuestion: true,\n};\n\nexport const PRESETS: Record<string, PresetProperties> = {\n \"Fant du\": {\n type: \"radio\",\n label: \"Fant du det du lette etter?\",\n options: [\n {\n label: \"Ja\",\n value: \"ja\",\n textAreaLabel:\n \"Så bra! Har du noen tilbakemeldinger kan du skrive dem her.\",\n },\n {\n label: \"Nei\",\n value: \"nei\",\n textAreaLabel:\n \"Det var leit! Fortell oss gjerne hva du savner, så kan vi gjøre sidene våre bedre.\",\n },\n ],\n addOnQuestion: true,\n },\n \"Fikk du gjort\": {\n type: \"radio\",\n label: \"Fikk du gjort det du skulle?\",\n options: [\n {\n label: \"Ja\",\n value: \"ja\",\n textAreaLabel:\n \"Så bra! Har du noen tilbakemeldinger kan du skrive dem her.\",\n },\n {\n label: \"Nei\",\n value: \"nei\",\n textAreaLabel:\n \"Det var leit! Fortell oss gjerne hva du savner, så kan vi gjøre sidene våre bedre.\",\n },\n ],\n addOnQuestion: true,\n },\n \"Hvor fornøyd 5\": smileyQuestion,\n Smileys: smileyQuestion,\n};\n"],"names":["smileyQuestion","type","label","options","smileyOptions","addOnQuestion","PRESETS","value","textAreaLabel","Smileys"],"mappings":"4DAUA,MAAMA,EAAmC,CACrCC,KAAM,SACNC,MAAO,0CACPC,QAASC,EACTC,eAAe,GAGNC,EAA4C,CACrD,UAAW,CACPL,KAAM,QACNC,MAAO,8BACPC,QAAS,CACL,CACID,MAAO,KACPK,MAAO,KACPC,cACI,+DAER,CACIN,MAAO,MACPK,MAAO,MACPC,cACI,uFAGZH,eAAe,GAEnB,gBAAiB,CACbJ,KAAM,QACNC,MAAO,+BACPC,QAAS,CACL,CACID,MAAO,KACPK,MAAO,KACPC,cACI,+DAER,CACIN,MAAO,MACPK,MAAO,MACPC,cACI,uFAGZH,eAAe,GAEnB,iBAAkBL,EAClBS,QAAST"}
1
+ {"version":3,"file":"presets.js","sources":["../../../../src/components/feedback/presets.tsx"],"sourcesContent":["import { FeedbackProps } from \"./Feedback.js\";\nimport { defaultOptions as smileyOptions } from \"./questions/smileyUtils.js\";\n\nexport type PresetProperties = Pick<\n FeedbackProps,\n \"label\" | \"type\" | \"options\" | \"addOnQuestion\"\n>;\n\nconst smileyQuestion: PresetProperties = {\n type: \"smiley\",\n label: \"Hvor fornøyd er du med denne nettsiden?\",\n options: smileyOptions,\n addOnQuestion: true,\n};\n\nexport const PRESETS: Record<string, PresetProperties> = {\n \"Fant du\": {\n type: \"radio\",\n label: \"Fant du det du lette etter?\",\n options: [\n {\n label: \"Ja\",\n value: \"ja\",\n textAreaLabel:\n \"Så bra! Har du noen tilbakemeldinger kan du skrive dem her.\",\n },\n {\n label: \"Nei\",\n value: \"nei\",\n textAreaLabel:\n \"Det var leit! Fortell oss gjerne hva du savner, så kan vi gjøre sidene våre bedre.\",\n },\n ],\n addOnQuestion: true,\n },\n \"Fikk du gjort\": {\n type: \"radio\",\n label: \"Fikk du gjort det du skulle?\",\n options: [\n {\n label: \"Ja\",\n value: \"ja\",\n textAreaLabel:\n \"Så bra! Har du noen tilbakemeldinger kan du skrive dem her.\",\n },\n {\n label: \"Nei\",\n value: \"nei\",\n textAreaLabel:\n \"Det var leit! Fortell oss gjerne hva du savner, så kan vi gjøre sidene våre bedre.\",\n },\n ],\n addOnQuestion: true,\n },\n \"Hvor fornøyd 5\": smileyQuestion,\n Smileys: smileyQuestion,\n};\n"],"names":["smileyQuestion","type","label","options","smileyOptions","addOnQuestion","PRESETS","value","textAreaLabel","Smileys"],"mappings":"4DAQA,MAAMA,EAAmC,CACrCC,KAAM,SACNC,MAAO,0CACPC,QAASC,EACTC,eAAe,GAGNC,EAA4C,CACrD,UAAW,CACPL,KAAM,QACNC,MAAO,8BACPC,QAAS,CACL,CACID,MAAO,KACPK,MAAO,KACPC,cACI,+DAER,CACIN,MAAO,MACPK,MAAO,MACPC,cACI,uFAGZH,eAAe,GAEnB,gBAAiB,CACbJ,KAAM,QACNC,MAAO,+BACPC,QAAS,CACL,CACID,MAAO,KACPK,MAAO,KACPC,cACI,+DAER,CACIN,MAAO,MACPK,MAAO,MACPC,cACI,uFAGZH,eAAe,GAEnB,iBAAkBL,EAClBS,QAAST"}
@@ -1,28 +1,3 @@
1
- import { FC, ReactNode } from 'react';
2
- interface Props {
3
- /**
4
- * Lar deg tilpasse spørsmålsteksten.
5
- * @default "Kan vi kontakte deg for flere innspill?"
6
- * */
7
- label?: string;
8
- /**
9
- * Lar deg tilpasse teksten på knappen for innsending.
10
- * @default "Sett meg på lista!"
11
- * */
12
- sendButtonLabel?: string;
13
- /** Sett til true om du også vil spørre om brukjerens telefonnummer i tillegg til epost */
14
- withPhone?: boolean;
15
- /** Her kan du legge inn eventuelt annet innhold du vil ha med. Kommer mellom overskriften og feltene for utfylling */
16
- children?: ReactNode;
17
- onSubmit: (values: {
18
- email: string;
19
- phone?: string;
20
- }) => void;
21
- /** Lar deg tilpasse meldingen som kommer når brukeren sender inn skjemaet. */
22
- successMessage?: {
23
- title: string;
24
- children: ReactNode;
25
- };
26
- }
27
- export declare const ContactQuestion: FC<Props>;
28
- export {};
1
+ import { FC } from 'react';
2
+ import { ContactQuestionProps } from '../types.js';
3
+ export declare const ContactQuestion: FC<ContactQuestionProps>;
@@ -1 +1 @@
1
- {"version":3,"file":"ContactQuestion.js","sources":["../../../../../src/components/feedback/questions/ContactQuestion.tsx"],"sourcesContent":["import React, {\n ChangeEvent,\n FC,\n ReactNode,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { isValidEpost } from \"../../../utilities/validators/isValidEpost/isValidEpost.js\";\nimport { isValidTelefonnummer } from \"../../../utilities/validators/isValidTelefonnummer/isValidTelefonnummer.js\";\nimport { PrimaryButton, TertiaryButton } from \"../../button/Button.js\";\nimport { TextInput } from \"../../text-input/TextInput.js\";\nimport { useFeedbackContext } from \"../feedbackContext.js\";\nimport { FeedbackSuccess } from \"../FeedbackSuccess.js\";\n\nconst validateEmail = (email?: string) => {\n if (!email || email === \"\") {\n return \"Du må oppgi e-postadresse for at vi kan kontakte deg\";\n }\n if (!isValidEpost(email)) {\n return \"Skriv inn en gyldig e-postadresse\";\n }\n return;\n};\n\nconst validatePhone = (phone?: string) => {\n if (!phone || phone === \"\") {\n return \"Du må oppgi telefonnummer for at vi kan kontakte deg\";\n }\n if (!isValidTelefonnummer(phone)) {\n return \"Skriv inn et gyldig telefonnummer\";\n }\n return;\n};\n\nconst defaultSuccessMessage = {\n title: \"Takk for tiden din!\",\n children:\n \"Neste gang vi gjennomfører intervjuer og tester kan det hende vi tar kontakt med deg. Dine innspill hjelper oss med å gjøre nettsidene bedre for deg og alle andre som bruker dem.\",\n};\n\ninterface Props {\n /**\n * Lar deg tilpasse spørsmålsteksten.\n * @default \"Kan vi kontakte deg for flere innspill?\"\n * */\n label?: string;\n /**\n * Lar deg tilpasse teksten på knappen for innsending.\n * @default \"Sett meg på lista!\"\n * */\n sendButtonLabel?: string;\n /** Sett til true om du også vil spørre om brukjerens telefonnummer i tillegg til epost */\n withPhone?: boolean;\n /** Her kan du legge inn eventuelt annet innhold du vil ha med. Kommer mellom overskriften og feltene for utfylling */\n children?: ReactNode;\n onSubmit: (values: { email: string; phone?: string }) => void;\n /** Lar deg tilpasse meldingen som kommer når brukeren sender inn skjemaet. */\n successMessage?: {\n title: string;\n children: ReactNode;\n };\n}\n\nexport const ContactQuestion: FC<Props> = ({\n label = \"Kan vi kontakte deg for flere innspill?\",\n sendButtonLabel = \"Sett meg på lista!\",\n withPhone = false,\n onSubmit,\n successMessage = defaultSuccessMessage,\n children,\n}) => {\n const [email, setEmail] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [errors, setErrors] = useState<{ email?: string; phone?: string }>(\n {},\n );\n const emailRef = useRef<HTMLInputElement>(null);\n const phoneRef = useRef<HTMLInputElement>(null);\n const [shouldValidate, setShouldValidate] = useState(false);\n\n const [noThanks, setNoThanks] = useState(false);\n const { contactSubmitted, setContactSubmitted, landmarkLabel } =\n useFeedbackContext();\n\n const ChildrenWrapper = typeof children === \"string\" ? \"p\" : \"div\";\n\n const validate = (email: string, phone: string) => {\n const emailError = validateEmail(email);\n const phoneError = validatePhone(phone);\n setErrors({ email: emailError, phone: phoneError });\n return { emailError, phoneError };\n };\n\n useEffect(() => {\n if (shouldValidate) {\n const { emailError, phoneError } = validate(email, phone);\n\n if (!emailError && (!withPhone || !phoneError)) {\n setShouldValidate(false);\n }\n }\n }, [email, phone, shouldValidate, withPhone]);\n\n const handleChange =\n (consumer: (value: string) => void) =>\n (e: ChangeEvent<HTMLInputElement>) =>\n consumer(e.target.value);\n\n const handleSubmit: React.FormEventHandler = (e) => {\n e.preventDefault();\n\n const { emailError, phoneError } = validate(email, phone);\n if (emailError) {\n setShouldValidate(true);\n emailRef.current?.focus();\n return;\n }\n if (withPhone && phoneError) {\n setShouldValidate(true);\n phoneRef.current?.focus();\n return;\n }\n\n onSubmit({ email, phone: withPhone ? phone : undefined });\n setContactSubmitted(true);\n };\n\n if (noThanks) {\n return null;\n }\n\n if (contactSubmitted) {\n return <FeedbackSuccess {...successMessage} />;\n }\n\n return (\n <form\n className=\"jkl-spacing-xl--top\"\n onSubmit={handleSubmit}\n aria-label={landmarkLabel}\n >\n <p className=\"jkl-heading-4 jkl-spacing-xs--bottom\">{label}</p>\n {children && (\n <ChildrenWrapper className=\"jkl-body\">\n {children}\n </ChildrenWrapper>\n )}\n\n <TextInput\n ref={emailRef}\n className=\"jkl-spacing-l--top\"\n label=\"E-post\"\n labelProps={{ variant: \"small\" }}\n autoComplete=\"email\"\n name=\"email\"\n value={email}\n onChange={handleChange(setEmail)}\n errorLabel={errors.email}\n />\n {withPhone && (\n <TextInput\n ref={phoneRef}\n className=\"jkl-spacing-l--top\"\n label=\"Telefonnummer\"\n labelProps={{ variant: \"small\" }}\n autoComplete=\"tel\"\n name=\"phone\"\n value={phone}\n onChange={handleChange(setPhone)}\n errorLabel={errors.phone}\n />\n )}\n\n <div className=\"jkl-spacing-xl--top\">\n <PrimaryButton type=\"submit\" className=\"jkl-spacing-xl--right\">\n {sendButtonLabel}\n </PrimaryButton>\n <TertiaryButton onClick={() => setNoThanks(true)}>\n Nei takk\n </TertiaryButton>\n </div>\n </form>\n );\n};\n"],"names":["defaultSuccessMessage","title","children","ContactQuestion","label","sendButtonLabel","withPhone","onSubmit","successMessage","email","setEmail","useState","phone","setPhone","errors","setErrors","emailRef","useRef","phoneRef","shouldValidate","setShouldValidate","noThanks","setNoThanks","contactSubmitted","setContactSubmitted","landmarkLabel","useFeedbackContext","ChildrenWrapper","validate","emailError","isValidEpost","validateEmail","phoneError","isValidTelefonnummer","validatePhone","useEffect","handleChange","consumer","e","target","value","jsx","FeedbackSuccess","jsxs","className","preventDefault","_a","current","focus","_b","TextInput","ref","labelProps","variant","autoComplete","name","onChange","errorLabel","PrimaryButton","type","TertiaryButton","onClick"],"mappings":"kjBAeA,MAoBMA,EAAwB,CAC1BC,MAAO,sBACPC,SACI,sLA0BKC,EAA6B,EACtCC,MAAAA,EAAQ,0CACRC,gBAAAA,EAAkB,qBAClBC,UAAAA,GAAY,EACZC,SAAAA,EACAC,eAAAA,EAAiBR,EACjBE,SAAAA,MAEA,MAAOO,EAAOC,GAAYC,EAAS,KAC5BC,EAAOC,GAAYF,EAAS,KAC5BG,EAAQC,GAAaJ,EACxB,CAAC,GAECK,EAAWC,EAAyB,MACpCC,EAAWD,EAAyB,OACnCE,EAAgBC,GAAqBT,GAAS,IAE9CU,EAAUC,GAAeX,GAAS,IACjCY,iBAAAA,EAAkBC,oBAAAA,EAAqBC,cAAAA,GAC3CC,IAEEC,EAAsC,iBAAbzB,EAAwB,IAAM,MAEvD0B,EAAW,CAACnB,EAAeG,KACvB,MAAAiB,EAzEQ,CAACpB,GACdA,GAAmB,KAAVA,EAGTqB,EAAarB,QAAd,EACO,oCAHA,uDAuEYsB,CAActB,GAC3BuB,EAhEQ,CAACpB,GACdA,GAAmB,KAAVA,EAGTqB,EAAqBrB,QAAtB,EACO,oCAHA,uDA8DYsB,CAActB,GACjC,OAAAG,EAAU,CAAEN,MAAOoB,EAAYjB,MAAOoB,IAC/B,CAAEH,WAAAA,EAAYG,WAAAA,IAGzBG,GAAU,KACN,GAAIhB,EAAgB,CACV,MAAEU,WAAAA,EAAYG,WAAAA,GAAeJ,EAASnB,EAAOG,IAE9CiB,KAAgBvB,IAAc0B,IAC/BZ,GAAkB,EAE1B,IACD,CAACX,EAAOG,EAAOO,EAAgBb,IAE5B,MAAA8B,EACDC,GACAC,GACGD,EAASC,EAAEC,OAAOC,OAqBtBnB,OAAAA,EACO,KAGPE,EACOkB,EAACC,EAAiB,IAAGlC,IAI5BmC,EAAC,OAAA,CACGC,UAAU,sBACVrC,SA9BsC+B,YAC1CA,EAAEO,iBAEI,MAAEhB,WAAAA,EAAYG,WAAAA,GAAeJ,EAASnB,EAAOG,GACnD,OAAIiB,GACAT,GAAkB,QAClB,OAAA0B,EAAA9B,EAAS+B,UAATD,EAAkBE,UAGlB1C,GAAa0B,GACbZ,GAAkB,QAClB,OAAA6B,EAAA/B,EAAS6B,UAATE,EAAkBD,WAItBzC,EAAS,CAAEE,MAAAA,EAAOG,MAAON,EAAYM,OAAQ,SAC7CY,GAAoB,GAAI,EAepB,aAAYC,EAEZvB,SAAA,CAACuC,EAAA,IAAA,CAAEG,UAAU,uCAAwC1C,SAAME,IAC1DF,GACGuC,EAACd,EAAgB,CAAAiB,UAAU,WACtB1C,SAAAA,IAITuC,EAACS,EAAA,CACGC,IAAKnC,EACL4B,UAAU,qBACVxC,MAAM,SACNgD,WAAY,CAAEC,QAAS,SACvBC,aAAa,QACbC,KAAK,QACLf,MAAO/B,EACP+C,SAAUpB,EAAa1B,GACvB+C,WAAY3C,EAAOL,QAEtBH,GACGmC,EAACS,EAAA,CACGC,IAAKjC,EACL0B,UAAU,qBACVxC,MAAM,gBACNgD,WAAY,CAAEC,QAAS,SACvBC,aAAa,MACbC,KAAK,QACLf,MAAO5B,EACP4C,SAAUpB,EAAavB,GACvB4C,WAAY3C,EAAOF,QAI3B+B,EAAC,MAAI,CAAAC,UAAU,sBACX1C,SAAA,CAAAuC,EAACiB,EAAc,CAAAC,KAAK,SAASf,UAAU,wBAClC1C,SACLG,MACCuD,EAAe,CAAAC,QAAS,IAAMvC,GAAY,GAAOpB,SAElD,kBACJ"}
1
+ {"version":3,"file":"ContactQuestion.js","sources":["../../../../../src/components/feedback/questions/ContactQuestion.tsx"],"sourcesContent":["import React, { ChangeEvent, FC, useEffect, useRef, useState } from \"react\";\nimport { isValidEpost } from \"../../../utilities/validators/isValidEpost/isValidEpost.js\";\nimport { isValidTelefonnummer } from \"../../../utilities/validators/isValidTelefonnummer/isValidTelefonnummer.js\";\nimport { PrimaryButton, TertiaryButton } from \"../../button/Button.js\";\nimport { TextInput } from \"../../text-input/TextInput.js\";\nimport { useFeedbackContext } from \"../feedbackContext.js\";\nimport { FeedbackSuccess } from \"../FeedbackSuccess.js\";\nimport { ContactQuestionProps } from \"../types.js\";\n\nconst validateEmail = (email?: string) => {\n if (!email || email === \"\") {\n return \"Du må oppgi e-postadresse for at vi kan kontakte deg\";\n }\n if (!isValidEpost(email)) {\n return \"Skriv inn en gyldig e-postadresse\";\n }\n return;\n};\n\nconst validatePhone = (phone?: string) => {\n if (!phone || phone === \"\") {\n return \"Du må oppgi telefonnummer for at vi kan kontakte deg\";\n }\n if (!isValidTelefonnummer(phone)) {\n return \"Skriv inn et gyldig telefonnummer\";\n }\n return;\n};\n\nconst defaultSuccessMessage = {\n title: \"Takk for tiden din!\",\n children:\n \"Neste gang vi gjennomfører intervjuer og tester kan det hende vi tar kontakt med deg. Dine innspill hjelper oss med å gjøre nettsidene bedre for deg og alle andre som bruker dem.\",\n};\n\nexport const ContactQuestion: FC<ContactQuestionProps> = ({\n label = \"Kan vi kontakte deg for flere innspill?\",\n sendButtonLabel = \"Sett meg på lista!\",\n withPhone = false,\n onSubmit,\n successMessage = defaultSuccessMessage,\n children,\n}) => {\n const [email, setEmail] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [errors, setErrors] = useState<{ email?: string; phone?: string }>(\n {},\n );\n const emailRef = useRef<HTMLInputElement>(null);\n const phoneRef = useRef<HTMLInputElement>(null);\n const [shouldValidate, setShouldValidate] = useState(false);\n\n const [noThanks, setNoThanks] = useState(false);\n const { contactSubmitted, setContactSubmitted, landmarkLabel } =\n useFeedbackContext();\n\n const ChildrenWrapper = typeof children === \"string\" ? \"p\" : \"div\";\n\n const validate = (email: string, phone: string) => {\n const emailError = validateEmail(email);\n const phoneError = validatePhone(phone);\n setErrors({ email: emailError, phone: phoneError });\n return { emailError, phoneError };\n };\n\n useEffect(() => {\n if (shouldValidate) {\n const { emailError, phoneError } = validate(email, phone);\n\n if (!emailError && (!withPhone || !phoneError)) {\n setShouldValidate(false);\n }\n }\n }, [email, phone, shouldValidate, withPhone]);\n\n const handleChange =\n (consumer: (value: string) => void) =>\n (e: ChangeEvent<HTMLInputElement>) =>\n consumer(e.target.value);\n\n const handleSubmit: React.FormEventHandler = (e) => {\n e.preventDefault();\n\n const { emailError, phoneError } = validate(email, phone);\n if (emailError) {\n setShouldValidate(true);\n emailRef.current?.focus();\n return;\n }\n if (withPhone && phoneError) {\n setShouldValidate(true);\n phoneRef.current?.focus();\n return;\n }\n\n onSubmit({ email, phone: withPhone ? phone : undefined });\n setContactSubmitted(true);\n };\n\n if (noThanks) {\n return null;\n }\n\n if (contactSubmitted) {\n return <FeedbackSuccess {...successMessage} />;\n }\n\n return (\n <form\n className=\"jkl-spacing-xl--top\"\n onSubmit={handleSubmit}\n aria-label={landmarkLabel}\n >\n <p className=\"jkl-heading-4 jkl-spacing-xs--bottom\">{label}</p>\n {children && (\n <ChildrenWrapper className=\"jkl-body\">\n {children}\n </ChildrenWrapper>\n )}\n\n <TextInput\n ref={emailRef}\n className=\"jkl-spacing-l--top\"\n label=\"E-post\"\n labelProps={{ variant: \"small\" }}\n autoComplete=\"email\"\n name=\"email\"\n value={email}\n onChange={handleChange(setEmail)}\n errorLabel={errors.email}\n />\n {withPhone && (\n <TextInput\n ref={phoneRef}\n className=\"jkl-spacing-l--top\"\n label=\"Telefonnummer\"\n labelProps={{ variant: \"small\" }}\n autoComplete=\"tel\"\n name=\"phone\"\n value={phone}\n onChange={handleChange(setPhone)}\n errorLabel={errors.phone}\n />\n )}\n\n <div className=\"jkl-spacing-xl--top\">\n <PrimaryButton type=\"submit\" className=\"jkl-spacing-xl--right\">\n {sendButtonLabel}\n </PrimaryButton>\n <TertiaryButton onClick={() => setNoThanks(true)}>\n Nei takk\n </TertiaryButton>\n </div>\n </form>\n );\n};\n"],"names":["defaultSuccessMessage","title","children","ContactQuestion","label","sendButtonLabel","withPhone","onSubmit","successMessage","email","setEmail","useState","phone","setPhone","errors","setErrors","emailRef","useRef","phoneRef","shouldValidate","setShouldValidate","noThanks","setNoThanks","contactSubmitted","setContactSubmitted","landmarkLabel","useFeedbackContext","ChildrenWrapper","validate","emailError","isValidEpost","validateEmail","phoneError","isValidTelefonnummer","validatePhone","useEffect","handleChange","consumer","e","target","value","jsx","FeedbackSuccess","jsxs","className","preventDefault","_a","current","focus","_b","TextInput","ref","labelProps","variant","autoComplete","name","onChange","errorLabel","PrimaryButton","type","TertiaryButton","onClick"],"mappings":"kjBASA,MAoBMA,EAAwB,CAC1BC,MAAO,sBACPC,SACI,sLAGKC,EAA4C,EACrDC,MAAAA,EAAQ,0CACRC,gBAAAA,EAAkB,qBAClBC,UAAAA,GAAY,EACZC,SAAAA,EACAC,eAAAA,EAAiBR,EACjBE,SAAAA,MAEA,MAAOO,EAAOC,GAAYC,EAAS,KAC5BC,EAAOC,GAAYF,EAAS,KAC5BG,EAAQC,GAAaJ,EACxB,CAAC,GAECK,EAAWC,EAAyB,MACpCC,EAAWD,EAAyB,OACnCE,EAAgBC,GAAqBT,GAAS,IAE9CU,EAAUC,GAAeX,GAAS,IACjCY,iBAAAA,EAAkBC,oBAAAA,EAAqBC,cAAAA,GAC3CC,IAEEC,EAAsC,iBAAbzB,EAAwB,IAAM,MAEvD0B,EAAW,CAACnB,EAAeG,KACvB,MAAAiB,EAlDQ,CAACpB,GACdA,GAAmB,KAAVA,EAGTqB,EAAarB,QAAd,EACO,oCAHA,uDAgDYsB,CAActB,GAC3BuB,EAzCQ,CAACpB,GACdA,GAAmB,KAAVA,EAGTqB,EAAqBrB,QAAtB,EACO,oCAHA,uDAuCYsB,CAActB,GACjC,OAAAG,EAAU,CAAEN,MAAOoB,EAAYjB,MAAOoB,IAC/B,CAAEH,WAAAA,EAAYG,WAAAA,IAGzBG,GAAU,KACN,GAAIhB,EAAgB,CACV,MAAEU,WAAAA,EAAYG,WAAAA,GAAeJ,EAASnB,EAAOG,IAE9CiB,KAAgBvB,IAAc0B,IAC/BZ,GAAkB,EAE1B,IACD,CAACX,EAAOG,EAAOO,EAAgBb,IAE5B,MAAA8B,EACDC,GACAC,GACGD,EAASC,EAAEC,OAAOC,OAqBtBnB,OAAAA,EACO,KAGPE,EACOkB,EAACC,EAAiB,IAAGlC,IAI5BmC,EAAC,OAAA,CACGC,UAAU,sBACVrC,SA9BsC+B,YAC1CA,EAAEO,iBAEI,MAAEhB,WAAAA,EAAYG,WAAAA,GAAeJ,EAASnB,EAAOG,GACnD,OAAIiB,GACAT,GAAkB,QAClB,OAAA0B,EAAA9B,EAAS+B,UAATD,EAAkBE,UAGlB1C,GAAa0B,GACbZ,GAAkB,QAClB,OAAA6B,EAAA/B,EAAS6B,UAATE,EAAkBD,WAItBzC,EAAS,CAAEE,MAAAA,EAAOG,MAAON,EAAYM,OAAQ,SAC7CY,GAAoB,GAAI,EAepB,aAAYC,EAEZvB,SAAA,CAACuC,EAAA,IAAA,CAAEG,UAAU,uCAAwC1C,SAAME,IAC1DF,GACGuC,EAACd,EAAgB,CAAAiB,UAAU,WACtB1C,SAAAA,IAITuC,EAACS,EAAA,CACGC,IAAKnC,EACL4B,UAAU,qBACVxC,MAAM,SACNgD,WAAY,CAAEC,QAAS,SACvBC,aAAa,QACbC,KAAK,QACLf,MAAO/B,EACP+C,SAAUpB,EAAa1B,GACvB+C,WAAY3C,EAAOL,QAEtBH,GACGmC,EAACS,EAAA,CACGC,IAAKjC,EACL0B,UAAU,qBACVxC,MAAM,gBACNgD,WAAY,CAAEC,QAAS,SACvBC,aAAa,MACbC,KAAK,QACLf,MAAO5B,EACP4C,SAAUpB,EAAavB,GACvB4C,WAAY3C,EAAOF,QAI3B+B,EAAC,MAAI,CAAAC,UAAU,sBACX1C,SAAA,CAAAuC,EAACiB,EAAc,CAAAC,KAAK,SAASf,UAAU,wBAClC1C,SACLG,MACCuD,EAAe,CAAAC,QAAS,IAAMvC,GAAY,GAAOpB,SAElD,kBACJ"}