@fremtind/jokul 6.0.0-next.0 → 6.0.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/build/build-stats.html +37 -36
  2. package/build/cjs/components/autosuggest/BaseAutosuggest.cjs +1 -1
  3. package/build/cjs/components/autosuggest/BaseAutosuggest.cjs.map +1 -1
  4. package/build/cjs/components/date-input/DateInput.cjs +2 -0
  5. package/build/cjs/components/date-input/DateInput.cjs.map +1 -0
  6. package/build/cjs/components/date-input/DateInput.d.cts +7 -0
  7. package/build/cjs/components/date-input/calendar/Calendar.cjs +2 -0
  8. package/build/cjs/components/date-input/calendar/Calendar.cjs.map +1 -0
  9. package/build/cjs/components/date-input/calendar/Calendar.d.cts +6 -0
  10. package/build/cjs/components/date-input/calendar/CalendarDay.cjs +2 -0
  11. package/build/cjs/components/date-input/calendar/CalendarDay.cjs.map +1 -0
  12. package/build/cjs/components/date-input/calendar/CalendarDay.d.cts +16 -0
  13. package/build/cjs/components/date-input/calendar/CalendarWeek.cjs +2 -0
  14. package/build/cjs/components/date-input/calendar/CalendarWeek.cjs.map +1 -0
  15. package/build/cjs/components/date-input/calendar/CalendarWeek.d.cts +8 -0
  16. package/build/cjs/components/date-input/calendar/types.d.cts +6 -0
  17. package/build/cjs/components/date-input/calendar/utils.cjs +2 -0
  18. package/build/cjs/components/date-input/calendar/utils.cjs.map +1 -0
  19. package/build/cjs/components/date-input/calendar/utils.d.cts +19 -0
  20. package/build/cjs/components/date-input/index.cjs +2 -0
  21. package/build/cjs/components/date-input/index.d.cts +3 -0
  22. package/build/cjs/components/date-input/types.d.cts +35 -0
  23. package/build/cjs/components/date-input/utils.cjs +2 -0
  24. package/build/cjs/components/date-input/utils.cjs.map +1 -0
  25. package/build/cjs/components/date-input/utils.d.cts +34 -0
  26. package/build/cjs/components/search/Search.cjs +1 -1
  27. package/build/cjs/components/search/Search.cjs.map +1 -1
  28. package/build/cjs/components/select/Option.cjs +2 -0
  29. package/build/cjs/components/select/Option.cjs.map +1 -0
  30. package/build/cjs/components/select/Option.d.cts +12 -0
  31. package/build/cjs/components/select/Select.cjs +1 -1
  32. package/build/cjs/components/select/Select.cjs.map +1 -1
  33. package/build/cjs/components/select/Select.d.cts +18 -3
  34. package/build/cjs/components/select/index.cjs +1 -1
  35. package/build/cjs/components/select/index.d.cts +1 -5
  36. package/build/cjs/components/select/utils.cjs +2 -0
  37. package/build/cjs/components/select/utils.cjs.map +1 -0
  38. package/build/cjs/components/select/utils.d.cts +5 -0
  39. package/build/cjs/components/table/TablePagination.cjs +1 -1
  40. package/build/cjs/components/table/TablePagination.cjs.map +1 -1
  41. package/build/cjs/components/tabs/Tabs.cjs.map +1 -1
  42. package/build/cjs/hooks/useListNavigation/useListNavigation.cjs +1 -1
  43. package/build/cjs/hooks/useListNavigation/useListNavigation.cjs.map +1 -1
  44. package/build/cjs/hooks/useListNavigation/useListNavigation.d.cts +4 -2
  45. package/build/cjs/utilities/valuePair.cjs.map +1 -1
  46. package/build/cjs/utilities/valuePair.d.cts +2 -0
  47. package/build/es/components/autosuggest/BaseAutosuggest.js +1 -1
  48. package/build/es/components/autosuggest/BaseAutosuggest.js.map +1 -1
  49. package/build/es/components/date-input/DateInput.d.ts +7 -0
  50. package/build/es/components/date-input/DateInput.js +2 -0
  51. package/build/es/components/date-input/DateInput.js.map +1 -0
  52. package/build/es/components/date-input/calendar/Calendar.d.ts +6 -0
  53. package/build/es/components/date-input/calendar/Calendar.js +2 -0
  54. package/build/es/components/date-input/calendar/Calendar.js.map +1 -0
  55. package/build/es/components/date-input/calendar/CalendarDay.d.ts +16 -0
  56. package/build/es/components/date-input/calendar/CalendarDay.js +2 -0
  57. package/build/es/components/date-input/calendar/CalendarDay.js.map +1 -0
  58. package/build/es/components/date-input/calendar/CalendarWeek.d.ts +8 -0
  59. package/build/es/components/date-input/calendar/CalendarWeek.js +2 -0
  60. package/build/es/components/date-input/calendar/CalendarWeek.js.map +1 -0
  61. package/build/es/components/date-input/calendar/types.d.ts +6 -0
  62. package/build/es/components/date-input/calendar/utils.d.ts +19 -0
  63. package/build/es/components/date-input/calendar/utils.js +2 -0
  64. package/build/es/components/date-input/calendar/utils.js.map +1 -0
  65. package/build/es/components/date-input/index.d.ts +3 -0
  66. package/build/es/components/date-input/index.js +2 -0
  67. package/build/es/components/date-input/types.d.ts +35 -0
  68. package/build/es/components/date-input/utils.d.ts +34 -0
  69. package/build/es/components/date-input/utils.js +2 -0
  70. package/build/es/components/date-input/utils.js.map +1 -0
  71. package/build/es/components/search/Search.js +1 -1
  72. package/build/es/components/search/Search.js.map +1 -1
  73. package/build/es/components/select/Option.d.ts +12 -0
  74. package/build/es/components/select/Option.js +2 -0
  75. package/build/es/components/select/Option.js.map +1 -0
  76. package/build/es/components/select/Select.d.ts +18 -3
  77. package/build/es/components/select/Select.js +1 -1
  78. package/build/es/components/select/Select.js.map +1 -1
  79. package/build/es/components/select/index.d.ts +1 -5
  80. package/build/es/components/select/index.js +1 -1
  81. package/build/es/components/select/utils.d.ts +5 -0
  82. package/build/es/components/select/utils.js +2 -0
  83. package/build/es/components/select/utils.js.map +1 -0
  84. package/build/es/components/table/TablePagination.js +1 -1
  85. package/build/es/components/table/TablePagination.js.map +1 -1
  86. package/build/es/components/tabs/Tabs.js.map +1 -1
  87. package/build/es/hooks/useListNavigation/useListNavigation.d.ts +4 -2
  88. package/build/es/hooks/useListNavigation/useListNavigation.js +1 -1
  89. package/build/es/hooks/useListNavigation/useListNavigation.js.map +1 -1
  90. package/build/es/utilities/valuePair.d.ts +2 -0
  91. package/build/es/utilities/valuePair.js.map +1 -1
  92. package/codemods/CODEMODS.md +39 -0
  93. package/codemods/__tests__/import-paths.test.mjs +132 -20
  94. package/codemods/import-paths.mjs +8 -6
  95. package/codemods/transforms/date-input.mjs +225 -0
  96. package/codemods/transforms/import-specifiers.mjs +26 -0
  97. package/package.json +14 -13
  98. package/styles/base.css +7 -0
  99. package/styles/base.min.css +1 -1
  100. package/styles/components/autosuggest/autosuggest.min.css +1 -1
  101. package/styles/components/beta/description-list/description-list.min.css +1 -1
  102. package/styles/components/beta/nav-link/navlink.min.css +1 -1
  103. package/styles/components/breadcrumb/breadcrumb.min.css +1 -1
  104. package/styles/components/button/button.min.css +1 -1
  105. package/styles/components/card/card.min.css +1 -1
  106. package/styles/components/checkbox/checkbox.min.css +1 -1
  107. package/styles/components/checkbox-panel/checkbox-panel.min.css +1 -1
  108. package/styles/components/checkbox-panel/development/styles.min.css +1 -1
  109. package/styles/components/chip/chip.min.css +1 -1
  110. package/styles/components/combobox/combobox.min.css +1 -1
  111. package/styles/components/cookie-consent/cookie-consent.min.css +1 -1
  112. package/styles/components/countdown/countdown.css +2 -2
  113. package/styles/components/countdown/countdown.min.css +1 -1
  114. package/styles/components/date-input/_index.scss +8 -0
  115. package/styles/components/date-input/calendar/_index.scss +8 -0
  116. package/styles/components/date-input/calendar/calendar.css +60 -0
  117. package/styles/components/date-input/calendar/calendar.min.css +1 -0
  118. package/styles/components/date-input/calendar/calendar.scss +79 -0
  119. package/styles/components/date-input/date-input.css +187 -0
  120. package/styles/components/date-input/date-input.min.css +1 -0
  121. package/styles/components/date-input/date-input.scss +67 -0
  122. package/styles/components/description-list/description-list.min.css +1 -1
  123. package/styles/components/expander/accordion.min.css +1 -1
  124. package/styles/components/expander/expandable.min.css +1 -1
  125. package/styles/components/feedback/feedback.css +2 -2
  126. package/styles/components/feedback/feedback.min.css +1 -1
  127. package/styles/components/file/file.min.css +1 -1
  128. package/styles/components/file-input/file-input.css +9 -9
  129. package/styles/components/file-input/file-input.min.css +1 -1
  130. package/styles/components/flex/flex.min.css +1 -1
  131. package/styles/components/help/help.min.css +1 -1
  132. package/styles/components/icon/icon.css +1 -1
  133. package/styles/components/icon/icon.min.css +1 -1
  134. package/styles/components/icon/icon.scss +1 -0
  135. package/styles/components/icon-button/icon-button.min.css +1 -1
  136. package/styles/components/image/development/style.min.css +1 -1
  137. package/styles/components/image/image.min.css +1 -1
  138. package/styles/components/input-group/input-group.css +2 -2
  139. package/styles/components/input-group/input-group.min.css +1 -1
  140. package/styles/components/input-panel/input-panel.min.css +1 -1
  141. package/styles/components/link/link.min.css +1 -1
  142. package/styles/components/link-list/link-list.min.css +1 -1
  143. package/styles/components/list/list.min.css +1 -1
  144. package/styles/components/loader/loader.css +6 -6
  145. package/styles/components/loader/loader.min.css +1 -1
  146. package/styles/components/loader/skeleton-loader.css +3 -3
  147. package/styles/components/loader/skeleton-loader.min.css +1 -1
  148. package/styles/components/logo/development/styles.min.css +1 -1
  149. package/styles/components/logo/logo.min.css +1 -1
  150. package/styles/components/menu/menu.min.css +1 -1
  151. package/styles/components/message/message.css +2 -2
  152. package/styles/components/message/message.min.css +1 -1
  153. package/styles/components/modal/modal.min.css +1 -1
  154. package/styles/components/nav-link/nav-link.min.css +1 -1
  155. package/styles/components/number-input/number-input.min.css +1 -1
  156. package/styles/components/pagination/development/styles.min.css +1 -1
  157. package/styles/components/pagination/pagination.min.css +1 -1
  158. package/styles/components/popover/popover.min.css +1 -1
  159. package/styles/components/progress-bar/progress-bar.css +1 -1
  160. package/styles/components/progress-bar/progress-bar.min.css +1 -1
  161. package/styles/components/radio-button/radio-button.min.css +1 -1
  162. package/styles/components/radio-panel/development/styles.min.css +1 -1
  163. package/styles/components/radio-panel/radio-panel.min.css +1 -1
  164. package/styles/components/search/search-with-submit-button.min.css +1 -1
  165. package/styles/components/search/search.min.css +1 -1
  166. package/styles/components/segmented-control/segmented-control.css +3 -3
  167. package/styles/components/segmented-control/segmented-control.min.css +1 -1
  168. package/styles/components/select/_index.scss +5 -0
  169. package/styles/components/select/option.css +73 -0
  170. package/styles/components/select/option.min.css +1 -0
  171. package/styles/components/select/option.scss +74 -0
  172. package/styles/components/select/select.css +84 -264
  173. package/styles/components/select/select.min.css +1 -1
  174. package/styles/components/select/select.scss +79 -328
  175. package/styles/components/summary-table/summary-table.min.css +1 -1
  176. package/styles/components/system-message/system-message.css +2 -2
  177. package/styles/components/system-message/system-message.min.css +1 -1
  178. package/styles/components/table/table.min.css +3 -1
  179. package/styles/components/table-of-contents/table-of-contents.min.css +1 -1
  180. package/styles/components/tabs/tabs.min.css +1 -1
  181. package/styles/components/tag/tag.min.css +1 -1
  182. package/styles/components/text-area/text-area.min.css +1 -1
  183. package/styles/components/text-input/text-input.min.css +1 -1
  184. package/styles/components/toast/toast.css +4 -4
  185. package/styles/components/toast/toast.min.css +1 -1
  186. package/styles/components/toggle-switch/toggle-switch.min.css +1 -1
  187. package/styles/components/tooltip/tooltip.min.css +1 -1
  188. package/styles/components/typography/title.min.css +1 -1
  189. package/styles/components.css +4343 -4553
  190. package/styles/components.min.css +3 -1
  191. package/styles/components.scss +2 -3
  192. package/styles/utility/_index.scss +2 -1
  193. package/styles/utility/_lists.scss +7 -0
  194. package/build/_commonjsHelpers-C37NGDzP.cjs +0 -2
  195. package/build/_commonjsHelpers-C37NGDzP.cjs.map +0 -1
  196. package/build/_commonjsHelpers-CXUWDbkB.js +0 -2
  197. package/build/_commonjsHelpers-CXUWDbkB.js.map +0 -1
  198. package/build/cjs/components/beta/select/Select.cjs +0 -2
  199. package/build/cjs/components/beta/select/Select.cjs.map +0 -1
  200. package/build/cjs/components/beta/select/Select.d.cts +0 -3
  201. package/build/cjs/components/beta/select/index.cjs +0 -2
  202. package/build/cjs/components/beta/select/index.d.cts +0 -2
  203. package/build/cjs/components/beta/select/types.d.cts +0 -10
  204. package/build/cjs/components/datepicker/DatePicker.cjs +0 -2
  205. package/build/cjs/components/datepicker/DatePicker.cjs.map +0 -1
  206. package/build/cjs/components/datepicker/DatePicker.d.cts +0 -3
  207. package/build/cjs/components/datepicker/index.cjs +0 -2
  208. package/build/cjs/components/datepicker/index.cjs.map +0 -1
  209. package/build/cjs/components/datepicker/index.d.cts +0 -4
  210. package/build/cjs/components/datepicker/internal/Calendar.cjs +0 -2
  211. package/build/cjs/components/datepicker/internal/Calendar.cjs.map +0 -1
  212. package/build/cjs/components/datepicker/internal/Calendar.d.cts +0 -15
  213. package/build/cjs/components/datepicker/internal/calendarReducer.cjs +0 -2
  214. package/build/cjs/components/datepicker/internal/calendarReducer.cjs.map +0 -1
  215. package/build/cjs/components/datepicker/internal/calendarReducer.d.cts +0 -18
  216. package/build/cjs/components/datepicker/internal/useCalendar.cjs +0 -2
  217. package/build/cjs/components/datepicker/internal/useCalendar.cjs.map +0 -1
  218. package/build/cjs/components/datepicker/internal/useCalendar.d.cts +0 -59
  219. package/build/cjs/components/datepicker/internal/utils.cjs +0 -2
  220. package/build/cjs/components/datepicker/internal/utils.cjs.map +0 -1
  221. package/build/cjs/components/datepicker/internal/utils.d.cts +0 -167
  222. package/build/cjs/components/datepicker/types.d.cts +0 -280
  223. package/build/cjs/components/datepicker/utils.cjs +0 -2
  224. package/build/cjs/components/datepicker/utils.cjs.map +0 -1
  225. package/build/cjs/components/datepicker/utils.d.cts +0 -22
  226. package/build/cjs/components/datepicker/validation.cjs +0 -2
  227. package/build/cjs/components/datepicker/validation.cjs.map +0 -1
  228. package/build/cjs/components/datepicker/validation.d.cts +0 -4
  229. package/build/cjs/components/select/NativeSelect.cjs +0 -2
  230. package/build/cjs/components/select/NativeSelect.cjs.map +0 -1
  231. package/build/cjs/components/select/NativeSelect.d.cts +0 -3
  232. package/build/cjs/components/select/select-utils.cjs +0 -2
  233. package/build/cjs/components/select/select-utils.cjs.map +0 -1
  234. package/build/cjs/components/select/select-utils.d.cts +0 -2
  235. package/build/cjs/components/select/types.cjs +0 -2
  236. package/build/cjs/components/select/types.cjs.map +0 -1
  237. package/build/cjs/components/select/types.d.cts +0 -66
  238. package/build/es/components/beta/select/Select.d.ts +0 -3
  239. package/build/es/components/beta/select/Select.js +0 -2
  240. package/build/es/components/beta/select/Select.js.map +0 -1
  241. package/build/es/components/beta/select/index.d.ts +0 -2
  242. package/build/es/components/beta/select/index.js +0 -2
  243. package/build/es/components/beta/select/types.d.ts +0 -10
  244. package/build/es/components/datepicker/DatePicker.d.ts +0 -3
  245. package/build/es/components/datepicker/DatePicker.js +0 -2
  246. package/build/es/components/datepicker/DatePicker.js.map +0 -1
  247. package/build/es/components/datepicker/index.d.ts +0 -4
  248. package/build/es/components/datepicker/index.js +0 -2
  249. package/build/es/components/datepicker/index.js.map +0 -1
  250. package/build/es/components/datepicker/internal/Calendar.d.ts +0 -15
  251. package/build/es/components/datepicker/internal/Calendar.js +0 -2
  252. package/build/es/components/datepicker/internal/Calendar.js.map +0 -1
  253. package/build/es/components/datepicker/internal/calendarReducer.d.ts +0 -18
  254. package/build/es/components/datepicker/internal/calendarReducer.js +0 -2
  255. package/build/es/components/datepicker/internal/calendarReducer.js.map +0 -1
  256. package/build/es/components/datepicker/internal/useCalendar.d.ts +0 -59
  257. package/build/es/components/datepicker/internal/useCalendar.js +0 -2
  258. package/build/es/components/datepicker/internal/useCalendar.js.map +0 -1
  259. package/build/es/components/datepicker/internal/utils.d.ts +0 -167
  260. package/build/es/components/datepicker/internal/utils.js +0 -2
  261. package/build/es/components/datepicker/internal/utils.js.map +0 -1
  262. package/build/es/components/datepicker/types.d.ts +0 -280
  263. package/build/es/components/datepicker/utils.d.ts +0 -22
  264. package/build/es/components/datepicker/utils.js +0 -2
  265. package/build/es/components/datepicker/utils.js.map +0 -1
  266. package/build/es/components/datepicker/validation.d.ts +0 -4
  267. package/build/es/components/datepicker/validation.js +0 -2
  268. package/build/es/components/datepicker/validation.js.map +0 -1
  269. package/build/es/components/select/NativeSelect.d.ts +0 -3
  270. package/build/es/components/select/NativeSelect.js +0 -2
  271. package/build/es/components/select/NativeSelect.js.map +0 -1
  272. package/build/es/components/select/select-utils.d.ts +0 -2
  273. package/build/es/components/select/select-utils.js +0 -2
  274. package/build/es/components/select/select-utils.js.map +0 -1
  275. package/build/es/components/select/types.d.ts +0 -66
  276. package/build/es/components/select/types.js +0 -2
  277. package/build/es/components/select/types.js.map +0 -1
  278. package/build/utils-C5AH4j8B.js +0 -2
  279. package/build/utils-C5AH4j8B.js.map +0 -1
  280. package/build/utils-CD_aHC6R.cjs +0 -2
  281. package/build/utils-CD_aHC6R.cjs.map +0 -1
  282. package/styles/components/beta/select/_index.scss +0 -3
  283. package/styles/components/beta/select/select.css +0 -101
  284. package/styles/components/beta/select/select.min.css +0 -1
  285. package/styles/components/beta/select/select.scss +0 -99
  286. package/styles/components/datepicker/_calendar-date-button.scss +0 -72
  287. package/styles/components/datepicker/_calendar-navigation-dropdown.scss +0 -55
  288. package/styles/components/datepicker/_calendar-navigation.scss +0 -14
  289. package/styles/components/datepicker/_calendar-table.scss +0 -29
  290. package/styles/components/datepicker/_calendar.scss +0 -28
  291. package/styles/components/datepicker/_index.scss +0 -6
  292. package/styles/components/datepicker/datepicker.css +0 -246
  293. package/styles/components/datepicker/datepicker.min.css +0 -1
  294. package/styles/components/datepicker/datepicker.scss +0 -49
  295. /package/build/cjs/components/{beta/select → date-input/calendar}/types.cjs +0 -0
  296. /package/build/cjs/components/{beta/select → date-input/calendar}/types.cjs.map +0 -0
  297. /package/build/cjs/components/{beta/select → date-input}/index.cjs.map +0 -0
  298. /package/build/cjs/components/{datepicker → date-input}/types.cjs +0 -0
  299. /package/build/cjs/components/{datepicker → date-input}/types.cjs.map +0 -0
  300. /package/build/es/components/{beta/select → date-input/calendar}/types.js +0 -0
  301. /package/build/es/components/{beta/select → date-input/calendar}/types.js.map +0 -0
  302. /package/build/es/components/{beta/select → date-input}/index.js.map +0 -0
  303. /package/build/es/components/{datepicker → date-input}/types.js +0 -0
  304. /package/build/es/components/{datepicker → date-input}/types.js.map +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"Select.js","sources":["../../../../src/components/select/Select.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React, {\n type CSSProperties,\n type FocusEvent,\n forwardRef,\n type KeyboardEvent,\n type MouseEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { useId } from \"../../hooks/useId/useId.js\";\nimport { useListNavigation } from \"../../hooks/useListNavigation/useListNavigation.js\";\nimport { usePreviousValue } from \"../../hooks/usePreviousValue/usePreviousValue.js\";\nimport { type ValuePair, getValuePair } from \"../../utilities/valuePair.js\";\nimport { ArrowVerticalAnimated } from \"../icon/icons/animated/ArrowVerticalAnimated.js\";\nimport { InputGroup } from \"../input-group/InputGroup.js\";\nimport Popover from \"../popover/Popover.js\";\nimport type { PopupTipProps } from \"../tooltip/types.js\";\nimport { focusSelected, toLower } from \"./select-utils.js\";\nimport type { SelectProps } from \"./types.js\";\n\nconst noop = () => {\n return;\n};\n\ninterface Option extends ValuePair {\n visible: boolean;\n}\n\nexport const Select = forwardRef<HTMLSelectElement, SelectProps>(\n (props, forwardedSelectRef) => {\n const {\n id,\n name,\n items,\n value,\n label,\n labelProps,\n onChange,\n onBlur,\n onFocus,\n className,\n helpLabel,\n errorLabel,\n invalid,\n searchable = false,\n inline = false,\n defaultPrompt = \"Velg\",\n width,\n maxShownOptions = 5,\n style,\n tooltip,\n \"data-testautoid\": dataTestAutoId,\n ...rest\n } = props;\n\n const listId = useId(id || \"jkl-select\", { generateSuffix: !id });\n const labelId = `${listId}_label`;\n const buttonId = `${listId}_button`;\n const searchInputId = `${listId}_search-input`;\n\n const [dropdownIsShown, setShown] = useState(false);\n const toggleListVisibility = useCallback(() => {\n setShown((previousValue) => !previousValue);\n }, []);\n\n // Lagrer faktisk placement etter at floating-ui har kjørt `flip`,\n // slik at vi kan bytte hvilken side av lista og knappen som er\n // flat når lista snus over triggeren.\n const [popoverPlacement, setPopoverPlacement] = useState<\n \"top\" | \"bottom\"\n >(\"bottom\");\n const handlePlacementChange = useCallback((p: string) => {\n setPopoverPlacement(p.startsWith(\"top\") ? \"top\" : \"bottom\");\n }, []);\n\n /// Søk\n\n const isSearchable = Boolean(searchable);\n const showSearchInputField = isSearchable && dropdownIsShown;\n const [searchValue, setSearchValue] = useState(\"\");\n const searchFn = useCallback(\n (item: ValuePair) => {\n if (\n item.label.toLowerCase().includes(searchValue.toLowerCase())\n ) {\n return true;\n }\n\n if (typeof searchable === \"function\") {\n return searchable(searchValue, item);\n }\n\n return false;\n },\n [searchable, searchValue],\n );\n const visibleItems: Option[] = useMemo(\n () =>\n items.map(getValuePair).map((item) => {\n const visible =\n !isSearchable || searchValue === \"\" || searchFn(item);\n return { ...item, visible };\n }),\n [items, isSearchable, searchValue, searchFn],\n );\n const valueIsInItems: boolean = useMemo(() => {\n if (typeof value === \"undefined\") {\n return false;\n }\n return items.some((item) =>\n typeof item === \"string\"\n ? item === value\n : item.value === value,\n );\n }, [value, items]);\n\n /// Valg av <option>\n\n const [selectedValue, setSelectedValue] = useState<string>(\n valueIsInItems && value !== undefined ? value : \"\",\n );\n const hasSelectedValue = selectedValue !== \"\";\n const selectedValueLabel = useMemo(\n () =>\n visibleItems.find((item) => item.value === selectedValue)\n ?.label || defaultPrompt,\n [visibleItems, selectedValue, defaultPrompt],\n );\n\n const selectRef = useRef<HTMLSelectElement | null>(null);\n // Hjelpefunksjon som gjør det enklere å forwarde refen og å bruke den selv internt\n const unifiedSelectRef = useCallback(\n (instance: HTMLSelectElement | null) => {\n selectRef.current = instance;\n if (forwardedSelectRef) {\n if (typeof forwardedSelectRef === \"function\") {\n forwardedSelectRef(instance);\n } else {\n forwardedSelectRef.current = instance;\n }\n }\n if (instance) {\n setSelectedValue(instance.value);\n }\n },\n [forwardedSelectRef],\n );\n\n const previousValue = usePreviousValue(value);\n useEffect(() => {\n if (value === previousValue) {\n return;\n }\n if (typeof value === \"undefined\" || !valueIsInItems) {\n setSelectedValue(\"\");\n } else {\n setSelectedValue(value);\n }\n }, [value, previousValue, valueIsInItems]);\n\n const selectOption = useCallback(\n (item: Option) => {\n const nextValue = item.value;\n setSearchValue(\"\");\n setSelectedValue(nextValue);\n toggleListVisibility();\n buttonRef.current?.focus();\n },\n [toggleListVisibility],\n );\n\n // La komponenten rendre <select> med den valgte verdien før onChange trigges, slik at\n // react-hook-form@>7.41.1 behandler feltet som at det har en verdi.\n const previousSelectedValue = usePreviousValue(selectedValue);\n useEffect(() => {\n // previousSelectedValue er undefined på første render, men da vil vi ikke ha en onChange uansett\n if (\n typeof previousSelectedValue === \"undefined\" ||\n previousSelectedValue === selectedValue ||\n selectedValue === value\n ) {\n return;\n }\n if (onChange) {\n onChange({\n type: \"change\",\n target: { name, value: selectedValue },\n });\n }\n if (selectRef.current) {\n selectRef.current.dispatchEvent(\n new Event(\"change\", { bubbles: true }),\n );\n }\n }, [onChange, name, value, selectedValue, previousSelectedValue]);\n\n /// Fokushåndtering\n\n const componentRootElementRef = useRef<HTMLDivElement>(null);\n const focusInsideRef = useRef(false);\n const searchFieldRef = useRef<HTMLInputElement>(null);\n const buttonRef = useRef<HTMLButtonElement>(null);\n\n const dropdownRef = useRef<HTMLDivElement | null>(null);\n // Lagrer listbox-elementet i state slik at downstream-hooks\n // (f.eks. `useListNavigation`) kan re-feste listeneren idet\n // `FloatingPortal` mounter listen.\n const [listboxEl, setListboxEl] = useState<HTMLDivElement | null>(null);\n\n // Listen rendres i en `FloatingPortal` som monteres via en\n // `useLayoutEffect` + `setState` i floating-ui. Refen er derfor\n // ikke tilgjengelig før i en senere render. Vi bruker en\n // callback-ref for å plassere fokus på valgt option idet listen\n // faktisk er i DOM-en. Refen holdes stabil (tom dependency-list)\n // slik at en endring i `selectedValue`/`isSearchable` ikke får\n // React til å avmontere/remontere refen og dermed flytte fokus\n // mens menyen er åpen — vi leser siste verdier via refs.\n const isSearchableRef = useRef(isSearchable);\n const selectedValueRef = useRef(selectedValue);\n useEffect(() => {\n isSearchableRef.current = isSearchable;\n selectedValueRef.current = selectedValue;\n });\n\n const setDropdownRef = useCallback((node: HTMLDivElement | null) => {\n dropdownRef.current = node;\n setListboxEl(node);\n if (node && !isSearchableRef.current) {\n // Popover skjules med `visibility: hidden` til\n // floating-ui har regnet ut første posisjon. Defer\n // fokus til etter neste paint, slik at vi ikke flytter\n // fokus til et usynlig element (kan gi manglende\n // fokusindikator i enkelte nettlesere).\n requestAnimationFrame(() => {\n if (dropdownRef.current === node) {\n focusSelected(node, selectedValueRef.current);\n }\n });\n }\n }, []);\n\n // Søkbart felt og knappen som får fokus ved lukking lever i hoved-\n // DOM-en, så for de tilfellene holder en useEffect.\n const wasShown = usePreviousValue(dropdownIsShown);\n useEffect(() => {\n if (dropdownIsShown === wasShown) return;\n if (dropdownIsShown && isSearchable) {\n searchFieldRef.current?.focus();\n } else if (\n !dropdownIsShown &&\n focusInsideRef.current &&\n buttonRef.current\n ) {\n buttonRef.current.focus();\n }\n }, [dropdownIsShown, wasShown, isSearchable]);\n\n useListNavigation({ element: listboxEl });\n\n const close = useCallback(() => {\n if (isSearchable) {\n setSearchValue(\"\");\n }\n if (onBlur) {\n onBlur({\n type: \"blur\",\n target: { name, value: selectedValue },\n });\n selectRef.current?.dispatchEvent(\n new Event(\"focusout\", { bubbles: true }),\n );\n }\n focusInsideRef.current = false;\n setShown(false);\n }, [onBlur, isSearchable, name, selectedValue]);\n\n const handleBlur = useCallback(\n (e: FocusEvent<HTMLButtonElement | HTMLInputElement>) => {\n const componentRootElement = componentRootElementRef.current;\n const dropdownElement = dropdownRef.current;\n // There are known issues in Firefox when using \"relatedTarget\" in onBlur events:\n // https://github.com/facebook/react/issues/2011\n // This might be fixed in react 17. Se issue above.\n // Dropdown rendres i en portal, så vi må sjekke begge trærne\n // for å avgjøre om fokus blir værende inne i komponenten.\n const nextFocusIsInsideComponent =\n componentRootElement?.contains(e.relatedTarget as Node) ||\n dropdownElement?.contains(e.relatedTarget as Node);\n if (!nextFocusIsInsideComponent) {\n close();\n }\n },\n [close],\n );\n\n const handleFocus = useCallback(() => {\n if (!focusInsideRef.current) {\n if (onFocus) {\n onFocus({\n type: \"change\",\n target: { name, value: selectedValue },\n });\n }\n focusInsideRef.current = true;\n }\n }, [onFocus, selectedValue, name]);\n\n const handleMouseOver = useCallback(\n (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 );\n\n // Handle focus and blur of hidden select element\n useEffect(() => {\n const select = selectRef.current;\n if (!select) return;\n\n const onSelectFocus = () => {\n if (showSearchInputField) {\n searchFieldRef.current?.focus();\n } else {\n buttonRef.current?.focus();\n }\n };\n const onSelectBlur = (ev: globalThis.FocusEvent) => {\n // Les refs ved hvert kall slik at vi alltid sjekker mot\n // siste listbox-element — den portalerte listen kan ha\n // mountet etter at denne effekten ble satt opp.\n const target = ev.relatedTarget as Node | null;\n const insideComponent =\n componentRootElementRef.current?.contains(target);\n const insideDropdown = dropdownRef.current?.contains(target);\n if (insideComponent || insideDropdown) {\n ev.preventDefault();\n }\n };\n\n select.addEventListener(\"focus\", onSelectFocus);\n select.addEventListener(\"blur\", onSelectBlur);\n return () => {\n select.removeEventListener(\"focus\", onSelectFocus);\n select.removeEventListener(\"blur\", onSelectBlur);\n };\n }, [showSearchInputField]);\n\n /// Tastaturnavigasjon\n\n // Add support for opening dropdown with arrowkey down as expected from native select\n // onKeyDown to stop ArrowDown from scrolling the page\n const handleOnKeyDown = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n if (\n (e.key === \"ArrowDown\" || e.key === \" \") &&\n !dropdownIsShown\n ) {\n e.preventDefault();\n e.stopPropagation();\n setShown(true);\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n e.stopPropagation();\n setShown(false);\n }\n },\n [dropdownIsShown],\n );\n\n // onKeyDown to stop ArrowDown from scrolling the page\n const handleSearchOnKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n e.stopPropagation();\n\n const listElement = dropdownRef.current;\n if (listElement) {\n if (isSearchable) {\n // Flytt fokus til det første elementet i listen, ikke det forrige valgte.\n // Ved endring i filter er det ikke gitt at vi ønsker å ta utgangspunkt i\n // den valgte verdien.\n focusSelected(listElement, undefined);\n } else {\n focusSelected(listElement, selectedValue);\n }\n }\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n e.stopPropagation();\n setShown(false);\n } else if (e.key === \"Tab\" && !e.shiftKey) {\n const listElement = dropdownRef.current;\n if (listElement) {\n e.preventDefault();\n e.stopPropagation();\n focusSelected(listElement, selectedValue);\n }\n } else if (e.key === \"Enter\" && dropdownIsShown) {\n // Should not propagate Enter keyevent because form might submit\n e.preventDefault();\n e.stopPropagation();\n }\n },\n [selectedValue, isSearchable, dropdownIsShown],\n );\n\n // onKeyDown so this Tab listener isn't triggered by tabbing from search field to option\n const handleOptionOnKeyDown = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === \"Tab\") {\n e.preventDefault();\n e.stopPropagation();\n\n if (e.shiftKey && searchFieldRef.current) {\n searchFieldRef.current.focus();\n } else if (buttonRef.current) {\n // Mimic behaviour of Firefox and native select, where Tab selects the current item and closes the menu\n setSelectedValue(e.currentTarget.value);\n setShown(false);\n buttonRef.current.focus();\n }\n } else if (e.key === \"ArrowUp\") {\n if (dropdownRef.current && searchFieldRef.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 searchFieldRef.current\n ) {\n searchFieldRef.current.focus();\n }\n }\n }\n },\n [],\n );\n\n // Add support for closing the dropdown with Escape like native select. Unfortunately, Escape does not trigger the button onKeyDown.\n useEffect(() => {\n const handleEscape = (e: globalThis.KeyboardEvent) => {\n if (e.key === \"Escape\" && dropdownIsShown) {\n setShown(false);\n }\n };\n if (typeof window !== \"undefined\" && dropdownIsShown) {\n window.addEventListener(\"keydown\", handleEscape);\n }\n return () => {\n if (typeof window !== \"undefined\") {\n window.removeEventListener(\"keydown\", handleEscape);\n }\n };\n }, [dropdownIsShown]);\n\n return (\n <>\n <select\n name={name}\n tabIndex={-1}\n data-testid=\"jkl-native-select\"\n className=\"jkl-sr-only\"\n aria-hidden\n ref={unifiedSelectRef}\n value={selectedValue}\n onChange={noop} // React complains unless we give an onChange handler. This is technically a read-only field, but readOnly isn't an option here.\n >\n <option value=\"\" />{\" \"}\n {/* Tom option må være et valg, ellers vil <select> alltid ha en value */}\n {visibleItems.map((item) => (\n <option\n key={`${listId}-opt-${item.value}`}\n hidden={!item.visible}\n value={item.value}\n >\n {item.label}\n </option>\n ))}\n </select>\n <InputGroup\n ref={componentRootElementRef}\n data-testid=\"jkl-select\"\n className={clsx(\"jkl-select\", className, {\n \"jkl-select--inline\": inline,\n \"jkl-select--open\":\n dropdownIsShown &&\n visibleItems.some((item) => item.visible),\n \"jkl-select--no-value\": !hasSelectedValue,\n \"jkl-select--invalid\": !!errorLabel || invalid,\n })}\n data-testautoid={dataTestAutoId}\n tooltip={\n tooltip && React.isValidElement<PopupTipProps>(tooltip)\n ? React.cloneElement(tooltip, {\n triggerProps: {\n ...tooltip.props.triggerProps,\n onFocus: (\n e: FocusEvent<HTMLButtonElement>,\n ) => {\n tooltip.props.triggerProps?.onFocus?.(\n e,\n );\n close();\n },\n },\n })\n : null\n }\n {...rest}\n id={isSearchable ? searchInputId : buttonId}\n style={style}\n label={label}\n labelProps={{\n id: labelId,\n srOnly: inline,\n ...labelProps,\n htmlFor: isSearchable ? searchInputId : buttonId,\n }}\n helpLabel={helpLabel}\n errorLabel={errorLabel}\n render={({\n \"aria-invalid\": ariaInvalid,\n ...inputProps\n }) => {\n // Lista vises kun når dropdown er åpnet *og* det\n // finnes minst ett synlig valg. `aria-expanded` på\n // trigger og combobox må følge samme boolean for\n // ikke å lyve om popoverens tilstand.\n const isPopoverOpen =\n dropdownIsShown &&\n visibleItems.some((item) => item.visible);\n return (\n <Popover\n open={isPopoverOpen}\n placement=\"bottom-start\"\n offset={0}\n modal={false}\n onPlacementChange={handlePlacementChange}\n matchReferenceWidth\n clickOptions={{ enabled: false }}\n dismissOptions={{ enabled: false }}\n roleOptions={{ enabled: false }}\n >\n <Popover.Trigger asChild>\n <div\n className=\"jkl-select__outer-wrapper\"\n data-popover-placement={\n popoverPlacement\n }\n style={{ width }}\n >\n {isSearchable && (\n <input\n {...inputProps}\n aria-invalid={ariaInvalid}\n id={searchInputId}\n hidden={!showSearchInputField}\n ref={searchFieldRef}\n placeholder=\"Søk\"\n value={searchValue}\n onChange={(e) =>\n setSearchValue(\n e.target.value,\n )\n }\n data-testid=\"jkl-select__search-input\"\n className=\"jkl-select__search-input\"\n aria-autocomplete=\"list\"\n aria-activedescendant={\n isPopoverOpen &&\n hasSelectedValue\n ? `${listId}__${toLower(\n selectedValue,\n )}`\n : undefined\n }\n aria-controls={\n isPopoverOpen\n ? listId\n : undefined\n }\n aria-expanded={isPopoverOpen}\n role=\"combobox\"\n onKeyDown={\n handleSearchOnKeyDown\n }\n onBlur={handleBlur}\n onFocus={handleFocus}\n onClick={(e) => {\n e.stopPropagation();\n }}\n />\n )}\n {/* eslint-disable-next-line jsx-a11y/role-supports-aria-props */}\n <button\n // Nei dette er ikke i henhold til speccen, men VoiceOver leser den likevel og det er oppførselen vi ønsker\n aria-invalid={ariaInvalid}\n {...inputProps}\n id={buttonId}\n ref={buttonRef}\n hidden={showSearchInputField}\n type=\"button\"\n name={`${name}-btn`}\n className={clsx(\n \"jkl-select__button\",\n {\n \"jkl-select__button--active-value\":\n !!selectedValue,\n },\n )}\n data-testid=\"jkl-select__button\"\n aria-label={`${\n selectedValueLabel || \"Velg\"\n },${label}`}\n aria-expanded={isPopoverOpen}\n aria-controls={\n isPopoverOpen\n ? listId\n : undefined\n }\n onBlur={handleBlur}\n onFocus={handleFocus}\n onKeyDown={handleOnKeyDown}\n onClick={toggleListVisibility}\n onMouseDown={(e) => {\n // Workaround for en Safari-bug hvor e.relatedTarget er null i onBlur\n // https://twitter.com/MilesSorce/status/1278762360669265925\n e.preventDefault();\n buttonRef.current?.focus();\n }}\n >\n {selectedValueLabel}\n </button>\n <ArrowVerticalAnimated\n variant=\"medium\"\n pointingDown={!isPopoverOpen}\n className=\"jkl-select__arrow\"\n />\n </div>\n </Popover.Trigger>\n <Popover.Content\n initialFocus={-1}\n returnFocus={false}\n className=\"jkl-select__popover\"\n >\n <div\n id={listId}\n ref={setDropdownRef}\n // biome-ignore lint/a11y/useSemanticElements: Vi reimplementerer select\n role=\"listbox\"\n className=\"jkl-select__options-menu\"\n data-popover-placement={\n popoverPlacement\n }\n aria-labelledby={labelId}\n tabIndex={-1}\n data-testid=\"jkl-select__listbox\"\n data-testautoid={\n dataTestAutoId\n ? `${dataTestAutoId}__listbox`\n : \"jkl-select__listbox\"\n }\n data-focus=\"controlled\" // lar oss styre markering av valg vha focus\n style={\n {\n \"--jkl-select-max-shown-options\":\n maxShownOptions,\n } as CSSProperties\n }\n >\n {visibleItems.map((item, i) =>\n // Det er viktig at vi _fjerner_ elementer som ikke er synlige fra DOMen for at tastaturnavigasjon skal fungere.\n // For eksempel, hvis vi har elementene Apple, Samsung og LG i den rekkefølgen og søker etter \"l\"\n // vil Samsung ikke synes. Om vi bare setter hidden-attributtet på Samsung vil ArrowDown fra Apple ikke fungere.\n // Dette lar seg ikke gjenskape i en enhetstest med JSDOM + user-events, og Cypress lukker Select\n // ved første {downArrow} ¯\\_(ツ)_/¯. Så please test scenariet over manuelt om dette skaper trøbbel for deg.\n item.visible ? (\n <button\n key={`${listId}-${item.value}`}\n hidden={!item.visible}\n type=\"button\"\n id={`${listId}__${toLower(\n item.value,\n )}`}\n className=\"jkl-select__option\"\n data-testid=\"jkl-select__option\"\n aria-selected={\n item.value ===\n selectedValue\n }\n // biome-ignore lint/a11y/useSemanticElements: Vi reimplementerer select\n role=\"option\"\n value={item.value}\n data-testautoid={`jkl-select__option-${i}`}\n onBlur={handleBlur}\n onFocus={handleFocus}\n onKeyDown={\n handleOptionOnKeyDown\n }\n onClick={(e) => {\n e.preventDefault();\n selectOption(item);\n }}\n onMouseOver={\n handleMouseOver\n }\n >\n {item.label}\n {item.description ? (\n <span className=\"jkl-select__option-description\">\n {item.description}\n </span>\n ) : null}\n </button>\n ) : null,\n )}\n </div>\n </Popover.Content>\n </Popover>\n );\n }}\n />\n </>\n );\n },\n);\n\nSelect.displayName = \"Select\";\n"],"names":["noop","Select","forwardRef","props","forwardedSelectRef","id","name","items","value","label","labelProps","onChange","onBlur","onFocus","className","helpLabel","errorLabel","invalid","searchable","inline","defaultPrompt","width","maxShownOptions","style","tooltip","dataTestAutoId","rest","listId","useId","generateSuffix","labelId","buttonId","searchInputId","dropdownIsShown","setShown","useState","toggleListVisibility","useCallback","previousValue","popoverPlacement","setPopoverPlacement","handlePlacementChange","p","startsWith","isSearchable","showSearchInputField","searchValue","setSearchValue","searchFn","item","toLowerCase","includes","visibleItems","useMemo","map","getValuePair","visible","valueIsInItems","some","selectedValue","setSelectedValue","hasSelectedValue","selectedValueLabel","find","selectRef","useRef","unifiedSelectRef","instance","current","usePreviousValue","useEffect","selectOption","nextValue","buttonRef","focus","previousSelectedValue","type","target","dispatchEvent","Event","bubbles","componentRootElementRef","focusInsideRef","searchFieldRef","dropdownRef","listboxEl","setListboxEl","isSearchableRef","selectedValueRef","setDropdownRef","node","requestAnimationFrame","focusSelected","wasShown","useListNavigation","element","close","handleBlur","e","componentRootElement","dropdownElement","contains","relatedTarget","handleFocus","handleMouseOver","preventScroll","select","onSelectFocus","onSelectBlur","ev","insideComponent","insideDropdown","preventDefault","addEventListener","removeEventListener","handleOnKeyDown","key","stopPropagation","handleSearchOnKeyDown","listElement","shiftKey","handleOptionOnKeyDown","currentTarget","firstVisible","querySelector","handleEscape","window","jsxs","Fragment","children","tabIndex","ref","jsx","hidden","InputGroup","clsx","React","isValidElement","cloneElement","triggerProps","srOnly","htmlFor","render","ariaInvalid","inputProps","isPopoverOpen","Popover","open","placement","offset","modal","onPlacementChange","matchReferenceWidth","clickOptions","enabled","dismissOptions","roleOptions","Trigger","asChild","placeholder","toLower","role","onKeyDown","onClick","onMouseDown","ArrowVerticalAnimated","variant","pointingDown","Content","initialFocus","returnFocus","i","onMouseOver","description","displayName"],"mappings":"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"}
1
+ {"version":3,"file":"Select.js","sources":["../../../../src/components/select/Select.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport {\n type CSSProperties,\n type ComponentPropsWithoutRef,\n type KeyboardEvent,\n type FocusEvent,\n forwardRef,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport { useListNavigation } from \"../../hooks/index.js\";\nimport { mergeRefs } from \"../../utilities/mergeRefs.js\";\nimport { type ValuePair, getValuePair } from \"../../utilities/valuePair.js\";\nimport { Button } from \"../button/Button.js\";\nimport { Flex } from \"../flex/Flex.js\";\nimport { ArrowDownIcon, CloseIcon } from \"../icon/index.js\";\nimport { InputGroup } from \"../input-group/InputGroup.js\";\nimport type { InputGroupProps } from \"../input-group/types.js\";\nimport { Search } from \"../search/Search.js\";\nimport { Text } from \"../typography/Text.js\";\nimport { Title } from \"../typography/Title.js\";\nimport { Option } from \"./Option.js\";\nimport { autofocus, getButtonText, getReactNodeText } from \"./utils.js\";\nimport type { DataTestAutoId } from \"../../utilities/types.js\";\n\nexport type SelectProps = Omit<InputGroupProps, \"children\" | \"inline\"> &\n DataTestAutoId &\n Omit<ComponentPropsWithoutRef<\"select\">, \"size\" | \"children\"> & {\n width?: string;\n items: (string | ValuePair)[];\n placeholder?: string;\n } & (\n | {\n searchable: true;\n onSearch?: (searchTerm: string) => void;\n filterFunction?: (item: ValuePair, searchTerm: string) => boolean;\n }\n | {\n searchable?: false;\n onSearch?: never;\n filterFunction?: never;\n }\n );\n\nexport const Select = forwardRef<HTMLSelectElement, SelectProps>(\n function Select(props, externalRef) {\n const {\n label,\n errorLabel,\n helpLabel,\n labelProps,\n supportLabelProps,\n tooltip,\n description,\n style,\n className,\n id: idProp,\n items: rawItems,\n multiple = false,\n searchable = false,\n onSearch,\n filterFunction,\n placeholder,\n width,\n value,\n \"data-testautoid\": dataTestautoid,\n \"data-size\": size,\n ...elementProps\n } = props;\n\n const popoverRef = useRef<HTMLDivElement>(null);\n const selectRef = useRef<HTMLSelectElement>(null);\n const unifiedRef = mergeRefs(externalRef, selectRef);\n\n const baseId = `jkl-select-${useId()}`;\n const selectId = idProp ?? baseId;\n const popoverId = `${selectId}-popover`;\n\n const [filter, setFilter] = useState(\"\");\n const [selected, setSelected] = useState(() => new Set<string>());\n\n useListNavigation({ ref: popoverRef, disableTypeahead: searchable });\n\n const items = rawItems.map(getValuePair);\n const filteredItems =\n searchable && filter\n ? items.filter((item) =>\n filterFunction\n ? filterFunction(item, filter)\n : item.label\n .toLowerCase()\n .includes(filter.toLowerCase()),\n )\n : items;\n\n const showPlaceholder =\n selected.size === 0 || (selected.size === 1 && placeholder && selected.has(\"\"));\n const placeholderText = placeholder || \"Ingen valgt\";\n const buttonText = getButtonText(selected, items, placeholderText);\n\n /**\n * Setter event-lyttere for å synkronisere verdier i det skjulte select-elementet med\n * visningen i vår komponent, samt nullstilling av filter når menyen lukkes.\n */\n // biome-ignore lint/correctness/useExhaustiveDependencies:\n useLayoutEffect(() => {\n const select = selectRef.current;\n const popover = popoverRef.current;\n if (!select) return;\n\n const syncSelected = () => {\n setSelected(\n new Set(Array.from(select.selectedOptions, (o) => o.value)),\n );\n };\n\n const resetFilterOnClose = (event: ToggleEvent) => {\n if (event.newState === \"closed\") setFilter(\"\");\n };\n\n syncSelected();\n popover?.addEventListener(\"toggle\", resetFilterOnClose);\n select.addEventListener(\"change\", syncSelected);\n\n return () => {\n select.removeEventListener(\"change\", syncSelected);\n popover?.removeEventListener(\"toggle\", resetFilterOnClose);\n };\n }, [multiple, rawItems]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Oppdaterer visning når value settes\n useLayoutEffect(() => {\n setSelected(\n new Set(\n Array.from(\n selectRef.current?.selectedOptions ?? [],\n (o) => o.value,\n ),\n ),\n );\n }, [value, elementProps.defaultValue]);\n\n /**\n * Sørger for at menyen kan åpnes med piltastene slik som i native select\n */\n const openWithArrows = (event: KeyboardEvent) => {\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n popoverRef.current?.showPopover?.();\n }\n };\n\n /**\n * Fyrer av focus- eller blur-event på det skjulte select-elementet når\n * fokus går inn eller ut av komponenten, slik at f.eks. react-hook-form\n * oppdaterer sin state riktig.\n */\n const syncFocus = (event: FocusEvent) => {\n const sel = selectRef.current;\n if (!popoverRef.current?.contains(event.relatedTarget)) {\n if (!sel) return;\n if ([\"focus\", \"focusin\"].includes(event.type)) {\n sel.dispatchEvent(new Event(\"focusin\", { bubbles: true }));\n sel.dispatchEvent(new Event(\"focus\", { bubbles: true }));\n } else if ([\"blur\", \"focusout\"].includes(event.type)) {\n sel.dispatchEvent(new Event(\"focusout\", { bubbles: true }));\n sel.dispatchEvent(new Event(\"blur\", { bubbles: true }));\n }\n }\n };\n\n return (\n <InputGroup\n id={selectId}\n label={label}\n errorLabel={errorLabel}\n helpLabel={helpLabel}\n labelProps={labelProps}\n supportLabelProps={supportLabelProps}\n tooltip={tooltip}\n description={description}\n style={style}\n data-testautoid={dataTestautoid}\n data-size={size}\n className={clsx(\"jkl-select\", className)}\n render={(inputProps) => (\n <>\n <button\n aria-label={`${showPlaceholder ? placeholderText : buttonText}, ${getReactNodeText(label)}`}\n className=\"jkl-select__button\"\n data-testid=\"jkl-select__button\"\n disabled={elementProps.disabled}\n type=\"button\"\n // @ts-ignore\n popovertarget={popoverId}\n style={{ \"--width\": width } as CSSProperties}\n onKeyDown={openWithArrows}\n onFocus={syncFocus}\n onBlur={syncFocus}\n {...inputProps}\n >\n {showPlaceholder ? placeholderText : buttonText}\n <ArrowDownIcon />\n </button>\n <Flex\n direction=\"column\"\n gap=\"16\"\n ref={popoverRef}\n // @ts-ignore\n popover=\"auto\"\n id={popoverId}\n className=\"jkl-select__popover\"\n aria-label={getReactNodeText(label)}\n >\n <Flex\n as=\"header\"\n alignItems=\"start\"\n justifyContent=\"space-between\"\n gap=\"8\"\n >\n <Title\n size=\"m\"\n as=\"h3\"\n id={`${selectId}-title`}\n >\n {label}\n </Title>\n <Button\n type=\"button\"\n variant=\"ghost\"\n icon={<CloseIcon />}\n aria-label=\"Lukk\"\n // @ts-ignore\n popovertarget={popoverId}\n popovertargetaction=\"hide\"\n />\n </Flex>\n {searchable && (\n <Search\n value={filter}\n onChange={(e) => {\n setFilter(e.target.value);\n onSearch?.(e.target.value);\n }}\n ref={autofocus(searchable)}\n autoComplete=\"off\"\n labelProps={{ srOnly: true }}\n label=\"Søk\"\n placeholder=\"Søk...\"\n width=\"100%\"\n className=\"jkl-spacing-8--bottom\"\n />\n )}\n <Flex\n direction=\"column\"\n gap=\"8\"\n // biome-ignore lint/a11y/useSemanticElements: Vi reimplementerer select\n role=\"listbox\"\n aria-multiselectable={multiple}\n aria-labelledby={`${selectId}-title`}\n >\n {filteredItems.map((pair, index) => (\n <Option\n {...pair}\n key={pair.value}\n selected={selected.has(pair.value)}\n multiple={multiple}\n selectRef={selectRef}\n // @ts-ignore\n popovertarget={\n multiple ? undefined : popoverId\n }\n popovertargetaction={\n multiple ? undefined : \"hide\"\n }\n ref={autofocus(() => {\n if (searchable) return false;\n if (showPlaceholder)\n return index === 0;\n return (\n selected.has(pair.value) &&\n filteredItems.findIndex((p) =>\n selected.has(p.value),\n ) === index\n );\n })}\n />\n ))}\n {searchable && !filteredItems.length && (\n <Text short>Ingen treff</Text>\n )}\n </Flex>\n {multiple && (\n <Button\n type=\"button\"\n variant=\"primary\"\n // @ts-ignore\n popovertarget={popoverId}\n popovertargetaction=\"hide\"\n >\n Bekreft\n </Button>\n )}\n </Flex>\n <select\n defaultValue={\n !multiple && value === undefined && placeholder\n ? \"\"\n : undefined\n }\n {...elementProps}\n tabIndex={-1}\n value={value}\n multiple={multiple}\n ref={unifiedRef}\n aria-labelledby={inputProps.id}\n >\n {!multiple && placeholder && (\n <option value=\"\" disabled>\n {placeholder}\n </option>\n )}\n {items.map((item) => (\n <option key={item.value} value={item.value}>\n {item.label}\n </option>\n ))}\n </select>\n </>\n )}\n />\n );\n },\n);\n\nSelect.displayName = \"Select\";\n"],"names":["Select","forwardRef","props","externalRef","label","errorLabel","helpLabel","labelProps","supportLabelProps","tooltip","description","style","className","id","idProp","items","rawItems","multiple","searchable","onSearch","filterFunction","placeholder","width","value","dataTestautoid","size","elementProps","popoverRef","useRef","selectRef","unifiedRef","mergeRefs","baseId","useId","selectId","popoverId","filter","setFilter","useState","selected","setSelected","Set","useListNavigation","ref","disableTypeahead","map","getValuePair","filteredItems","item","toLowerCase","includes","showPlaceholder","has","placeholderText","buttonText","getButtonText","useLayoutEffect","select","current","popover","syncSelected","Array","from","selectedOptions","o","resetFilterOnClose","event","newState","addEventListener","removeEventListener","defaultValue","openWithArrows","key","preventDefault","showPopover","syncFocus","sel","contains","relatedTarget","type","dispatchEvent","Event","bubbles","jsx","InputGroup","clsx","render","inputProps","jsxs","Fragment","children","getReactNodeText","disabled","popovertarget","onKeyDown","onFocus","onBlur","ArrowDownIcon","Flex","direction","gap","as","alignItems","justifyContent","Title","Button","variant","icon","CloseIcon","popovertargetaction","Search","onChange","e","target","autofocus","autoComplete","srOnly","role","pair","index","createElement","Option","findIndex","p","length","Text","short","tabIndex","displayName"],"mappings":"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"}
@@ -1,5 +1 @@
1
- export { Select } from './Select.js';
2
- export { NativeSelect } from './NativeSelect.js';
3
- export type { SelectProps, SelectChangeEventHandler, SelectPartialChangeEvent, NativeSelectProps, } from './types.js';
4
- export { Select as BETA_Select } from '../beta/select/Select.jsx';
5
- export type { SelectProps as BETA_SelectProps } from '../beta/select/types.js';
1
+ export { Select, type SelectProps } from './Select.js';
@@ -1,2 +1,2 @@
1
- import{Select as e}from"./Select.js";import{NativeSelect as t}from"./NativeSelect.js";import{Select as a}from"../beta/select/Select.js";export{a as BETA_Select,t as NativeSelect,e as Select};
1
+ import{Select as e}from"./Select.js";export{e as Select};
2
2
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,5 @@
1
+ import { ReactNode } from 'react';
2
+ import { ValuePair } from '../../utilities/valuePair.js';
3
+ export declare function getReactNodeText(node: ReactNode): string;
4
+ export declare const getButtonText: (selected: Set<string>, valuePairs: ValuePair[], placeholderText: string) => string;
5
+ export declare const autofocus: (active: boolean | (() => boolean)) => (el: HTMLElement | null) => void;
@@ -0,0 +1,2 @@
1
+ import{isValidElement as t}from"react";function e(o){return"string"==typeof o||"number"==typeof o?String(o):Array.isArray(o)?o.map(e).join(""):t(o)?e(o.props.children):""}const o=(t,e,o)=>1===t.size?e.find(e=>t.has(e.value))?.label??o:`${t.size} valgt`,a=t=>e=>{e&&(e.autofocus="boolean"==typeof t?t:t())};export{a as autofocus,o as getButtonText,e as getReactNodeText};
2
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sources":["../../../../src/components/select/utils.ts"],"sourcesContent":["import { type ReactNode, isValidElement } from \"react\";\nimport type { ValuePair } from \"../../utilities/valuePair.js\";\n\nexport function getReactNodeText(node: ReactNode): string {\n if (typeof node === \"string\" || typeof node === \"number\") return String(node);\n if (Array.isArray(node)) return node.map(getReactNodeText).join(\"\");\n if (isValidElement(node)) return getReactNodeText(node.props.children);\n return \"\";\n}\n\nexport const getButtonText = (\n selected: Set<string>,\n valuePairs: ValuePair[],\n placeholderText: string,\n): string => {\n if (selected.size === 1) {\n return (\n valuePairs.find((p) => selected.has(p.value))?.label ??\n placeholderText\n );\n }\n return `${selected.size} valgt`;\n};\n\nexport const autofocus =\n (active: boolean | (() => boolean)) => (el: HTMLElement | null) => {\n if (el) el.autofocus = typeof active === \"boolean\" ? active : active();\n };\n"],"names":["getReactNodeText","node","String","Array","isArray","map","join","isValidElement","props","children","getButtonText","selected","valuePairs","placeholderText","size","find","p","has","value","label","autofocus","active","el"],"mappings":"uCAGO,SAASA,EAAiBC,GAC7B,MAAoB,iBAATA,GAAqC,iBAATA,EAA0BC,OAAOD,GACpEE,MAAMC,QAAQH,GAAcA,EAAKI,IAAIL,GAAkBM,KAAK,IAC5DC,EAAeN,GAAcD,EAAiBC,EAAKO,MAAMC,UACtD,EACX,CAEO,MAAMC,EAAgB,CACzBC,EACAC,EACAC,IAEsB,IAAlBF,EAASG,KAELF,EAAWG,KAAMC,GAAML,EAASM,IAAID,EAAEE,SAASC,OAC/CN,EAGD,GAAGF,EAASG,aAGVM,EACRC,GAAuCC,IAChCA,IAAIA,EAAGF,UAA8B,kBAAXC,EAAuBA,EAASA"}
@@ -1,2 +1,2 @@
1
- import{jsxs as e,jsx as a,Fragment as i}from"react/jsx-runtime";import{c as n}from"../../../clsx-BeLtu-UY.js";import{forwardRef as t,useState as l,useCallback as r}from"react";import{useId as o}from"../../hooks/useId/useId.js";import{IconButton as s}from"../icon-button/IconButton.js";import{ChevronLeftIcon as c}from"../icon/icons/ChevronLeftIcon.js";import{ChevronRightIcon as p}from"../icon/icons/ChevronRightIcon.js";import{NativeSelect as m}from"../select/NativeSelect.js";import{TextInput as g}from"../text-input/TextInput.js";const d=t((i,t)=>{const{activePage:d=0,totalNumberOfRows:u,rowsPerPage:h,rowsPerPageItems:k,className:_,id:v,withGoToPage:j=!1,onChange:f,onChangeRowsPerPage:N,labels:P={rowsPerPage:"Rader per side",previous:"Forrige",next:"Neste"},...C}=i,w=o(v||"jkl-table-pagination",{generateSuffix:!v}),I=h<=0?1:Math.ceil(u/h),[x,S]=l(function(e,a,i){return a<e?e:a>i?i:a}(0,d,I-1)),y=r(e=>{const a=Number.parseInt(e.currentTarget.dataset.number);f(e,a,x),S(a),M(String(a+1))},[f,x]),[A,M]=l(String(x+1)),T=r(e=>{M(e.target.value);try{const a=Number.parseInt(e.target.value)-1;if(Number.isNaN(a))return;a>=0&&a<I&&(f(e,a,x),S(a))}catch{return}},[f,x,I]),R=r(e=>{if(0===x)return void f(e,x,x);const a=x-1;f(e,a,x),S(a),M(String(a+1))},[f,x]),O=r(e=>{if(x===I-1)return void f(e,x,x);const a=x+1;f(e,a,x),S(a),M(String(a+1))},[f,I,x]);return e("div",{className:n("jkl-table-pagination",_),...C,id:w,ref:t,children:[a("div",{className:"jkl-table-pagination__left",children:e("div",{className:"jkl-table-pagination__picker jkl-table-pagination__picker--rows",children:[e("span",{className:"jkl-table-pagination__picker-label","aria-hidden":"true",children:[P.rowsPerPage,":"]}),a(m,{className:"jkl-table-pagination__picker-input",label:P.rowsPerPage,labelProps:{srOnly:!0},name:`${w}-rows-per-page`,items:k.map(e=>"number"==typeof e?String(e):{label:e.label,value:String(e.value)}),value:String(h),onChange:N,width:"min(8rem, 100%)",inline:!0})]})}),e("span",{className:"jkl-table-pagination__total-rows",children:["Treff: ",u]}),a("div",{className:"jkl-table-pagination__right",children:1!==I&&e("nav",{className:"jkl-table-pagination__nav",children:[j&&e("div",{className:"jkl-table-pagination__picker jkl-table-pagination__picker--page",children:[e("span",{className:"jkl-table-pagination__picker-label","aria-hidden":"true",children:["object"==typeof j?j.gotoLabel:"Gå til side",":"]}),a(g,{className:"jkl-table-pagination__picker-input",label:"object"==typeof j?j.gotoLabel:"Gå til side",labelProps:{srOnly:!0},name:`${w}-go-to-page`,value:A,width:"min(4rem, 100%)",onChange:T,"aria-invalid":A&&A!==String(x+1)?"true":void 0})]}),e("ul",{children:[a("li",{children:a(s,{className:"jkl-table-pagination__previous",title:P.previous,onClick:R,children:a(c,{})})}),a(b,{id:w,activePage:d,numberOfPages:I,onPageClick:y}),a("li",{children:a(s,{className:"jkl-table-pagination__next",title:P.next,onClick:O,children:a(p,{})})})]})]})})]})}),b=({id:t,activePage:l,numberOfPages:r,onPageClick:o})=>{if(r<=7)return a(i,{children:Array.from({length:r}).map((e,i)=>a("li",{children:a("button",{className:n("jkl-table-pagination__page",{"jkl-table-pagination__page--active":l===i}),type:"button","data-number":i,onClick:o,children:i+1})},`${t}-page-${i}`))});const s=l>3&&r>7,c=l<r-4&&r>7,p=Math.min(Math.max(l-2,1),r-6),m=Math.min(p+1,r-5),g=Math.min(m+1,r-4),d=Math.min(m+2,r-3),b=Math.min(m+3,r-2);return e(i,{children:[a("li",{children:a(u,{isActive:0===l,number:0,onClick:o})}),a("li",{children:s?a("span",{className:"jkl-table-pagination__ellipsis","aria-hidden":!0,children:"..."}):a(u,{isActive:l===p,number:p,onClick:o})}),a("li",{children:a(u,{isActive:l===m,number:m,onClick:o})}),a("li",{children:a(u,{isActive:l===g,number:g,onClick:o})}),a("li",{children:a(u,{isActive:l===d,number:d,onClick:o})}),a("li",{children:c?a("span",{className:"jkl-table-pagination__ellipsis","aria-hidden":!0,children:"..."}):a(u,{isActive:l===b,number:b,onClick:o})}),a("li",{children:a(u,{isActive:l===r-1,number:r-1,onClick:o})})]})},u=({isActive:e,number:i,onClick:t,...l})=>a("button",{className:n("jkl-table-pagination__page",{"jkl-table-pagination__page--active":e}),type:"button","data-number":i,onClick:t,...l,children:i+1});d.displayName="TablePagination";export{d as TablePagination};
1
+ import{jsxs as e,jsx as a,Fragment as i}from"react/jsx-runtime";import{c as n}from"../../../clsx-BeLtu-UY.js";import{forwardRef as t,useState as l,useCallback as r}from"react";import{useId as o}from"../../hooks/useId/useId.js";import{IconButton as s}from"../icon-button/IconButton.js";import{ChevronLeftIcon as c}from"../icon/icons/ChevronLeftIcon.js";import{ChevronRightIcon as p}from"../icon/icons/ChevronRightIcon.js";import{Select as m}from"../select/Select.js";import{TextInput as g}from"../text-input/TextInput.js";const d=t((i,t)=>{const{activePage:d=0,totalNumberOfRows:u,rowsPerPage:h,rowsPerPageItems:k,className:_,id:v,withGoToPage:j=!1,onChange:f,onChangeRowsPerPage:N,labels:P={rowsPerPage:"Rader per side",previous:"Forrige",next:"Neste"},...C}=i,w=o(v||"jkl-table-pagination",{generateSuffix:!v}),I=h<=0?1:Math.ceil(u/h),[x,S]=l(function(e,a,i){return a<e?e:a>i?i:a}(0,d,I-1)),y=r(e=>{const a=Number.parseInt(e.currentTarget.dataset.number);f(e,a,x),S(a),M(String(a+1))},[f,x]),[A,M]=l(String(x+1)),T=r(e=>{M(e.target.value);try{const a=Number.parseInt(e.target.value)-1;if(Number.isNaN(a))return;a>=0&&a<I&&(f(e,a,x),S(a))}catch{return}},[f,x,I]),R=r(e=>{if(0===x)return void f(e,x,x);const a=x-1;f(e,a,x),S(a),M(String(a+1))},[f,x]),O=r(e=>{if(x===I-1)return void f(e,x,x);const a=x+1;f(e,a,x),S(a),M(String(a+1))},[f,I,x]);return e("div",{className:n("jkl-table-pagination",_),...C,id:w,ref:t,children:[a("div",{className:"jkl-table-pagination__left",children:e("div",{className:"jkl-table-pagination__picker jkl-table-pagination__picker--rows",children:[e("span",{className:"jkl-table-pagination__picker-label","aria-hidden":"true",children:[P.rowsPerPage,":"]}),a(m,{className:"jkl-table-pagination__picker-input",label:P.rowsPerPage,labelProps:{srOnly:!0},name:`${w}-rows-per-page`,items:k.map(e=>"number"==typeof e?String(e):{label:e.label,value:String(e.value)}),value:String(h),onChange:N,width:"min(8rem, 100%)"})]})}),e("span",{className:"jkl-table-pagination__total-rows",children:["Treff: ",u]}),a("div",{className:"jkl-table-pagination__right",children:1!==I&&e("nav",{className:"jkl-table-pagination__nav",children:[j&&e("div",{className:"jkl-table-pagination__picker jkl-table-pagination__picker--page",children:[e("span",{className:"jkl-table-pagination__picker-label","aria-hidden":"true",children:["object"==typeof j?j.gotoLabel:"Gå til side",":"]}),a(g,{className:"jkl-table-pagination__picker-input",label:"object"==typeof j?j.gotoLabel:"Gå til side",labelProps:{srOnly:!0},name:`${w}-go-to-page`,value:A,width:"min(4rem, 100%)",onChange:T,"aria-invalid":A&&A!==String(x+1)?"true":void 0})]}),e("ul",{children:[a("li",{children:a(s,{className:"jkl-table-pagination__previous",title:P.previous,onClick:R,children:a(c,{})})}),a(b,{id:w,activePage:d,numberOfPages:I,onPageClick:y}),a("li",{children:a(s,{className:"jkl-table-pagination__next",title:P.next,onClick:O,children:a(p,{})})})]})]})})]})}),b=({id:t,activePage:l,numberOfPages:r,onPageClick:o})=>{if(r<=7)return a(i,{children:Array.from({length:r}).map((e,i)=>a("li",{children:a("button",{className:n("jkl-table-pagination__page",{"jkl-table-pagination__page--active":l===i}),type:"button","data-number":i,onClick:o,children:i+1})},`${t}-page-${i}`))});const s=l>3&&r>7,c=l<r-4&&r>7,p=Math.min(Math.max(l-2,1),r-6),m=Math.min(p+1,r-5),g=Math.min(m+1,r-4),d=Math.min(m+2,r-3),b=Math.min(m+3,r-2);return e(i,{children:[a("li",{children:a(u,{isActive:0===l,number:0,onClick:o})}),a("li",{children:s?a("span",{className:"jkl-table-pagination__ellipsis","aria-hidden":!0,children:"..."}):a(u,{isActive:l===p,number:p,onClick:o})}),a("li",{children:a(u,{isActive:l===m,number:m,onClick:o})}),a("li",{children:a(u,{isActive:l===g,number:g,onClick:o})}),a("li",{children:a(u,{isActive:l===d,number:d,onClick:o})}),a("li",{children:c?a("span",{className:"jkl-table-pagination__ellipsis","aria-hidden":!0,children:"..."}):a(u,{isActive:l===b,number:b,onClick:o})}),a("li",{children:a(u,{isActive:l===r-1,number:r-1,onClick:o})})]})},u=({isActive:e,number:i,onClick:t,...l})=>a("button",{className:n("jkl-table-pagination__page",{"jkl-table-pagination__page--active":e}),type:"button","data-number":i,onClick:t,...l,children:i+1});d.displayName="TablePagination";export{d as TablePagination};
2
2
  //# sourceMappingURL=TablePagination.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TablePagination.js","sources":["../../../../src/components/table/TablePagination.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React, {\n forwardRef,\n useCallback,\n useState,\n type ChangeEventHandler,\n type FC,\n type MouseEventHandler,\n} from \"react\";\nimport { useId } from \"../../hooks/useId/useId.js\";\nimport { IconButton } from \"../icon-button/IconButton.js\";\nimport { ChevronLeftIcon } from \"../icon/icons/ChevronLeftIcon.js\";\nimport { ChevronRightIcon } from \"../icon/icons/ChevronRightIcon.js\";\nimport { NativeSelect } from \"../select/NativeSelect.js\";\nimport { TextInput } from \"../text-input/TextInput.js\";\nimport type { TablePaginationProps } from \"./types.js\";\n\nfunction clamp(min: number, num: number, max: number): number {\n if (num < min) {\n return min;\n }\n\n if (num > max) {\n return max;\n }\n\n return num;\n}\n\nexport const TablePagination = forwardRef<HTMLDivElement, TablePaginationProps>(\n (props, ref) => {\n const {\n activePage = 0,\n totalNumberOfRows,\n rowsPerPage,\n rowsPerPageItems,\n className,\n id: idProp,\n withGoToPage = false,\n onChange,\n onChangeRowsPerPage,\n labels = {\n rowsPerPage: \"Rader per side\",\n previous: \"Forrige\",\n next: \"Neste\",\n },\n ...rest\n } = props;\n\n const id = useId(idProp || \"jkl-table-pagination\", {\n generateSuffix: !idProp,\n });\n\n const showAll = rowsPerPage <= 0;\n const numberOfPages = showAll\n ? 1\n : Math.ceil(totalNumberOfRows / rowsPerPage);\n\n const [currentPage, setCurrentPage] = useState(\n clamp(0, activePage, numberOfPages - 1),\n );\n\n const onPageClick: MouseEventHandler<HTMLButtonElement> = useCallback(\n (e) => {\n const toPage = Number.parseInt(\n e.currentTarget.dataset.number as string,\n );\n onChange(e, toPage, currentPage);\n setCurrentPage(toPage);\n setPagePickerValue(String(toPage + 1));\n },\n [onChange, currentPage],\n );\n\n const [pagePickerValue, setPagePickerValue] = useState(\n String(currentPage + 1),\n );\n const onPageChange: ChangeEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n setPagePickerValue(e.target.value);\n try {\n const toPage = Number.parseInt(e.target.value) - 1;\n if (Number.isNaN(toPage)) {\n return;\n }\n\n if (toPage >= 0 && toPage < numberOfPages) {\n onChange(e, toPage, currentPage);\n setCurrentPage(toPage);\n }\n } catch {\n return;\n }\n },\n [onChange, currentPage, numberOfPages],\n );\n\n const onPrevious: MouseEventHandler<HTMLButtonElement> = useCallback(\n (e) => {\n if (currentPage === 0) {\n // TODO: skal dette være en no-op i stedet?\n onChange(e, currentPage, currentPage);\n return;\n }\n const toPage = currentPage - 1;\n onChange(e, toPage, currentPage);\n setCurrentPage(toPage);\n setPagePickerValue(String(toPage + 1));\n },\n [onChange, currentPage],\n );\n\n const onNext: MouseEventHandler<HTMLButtonElement> = useCallback(\n (e) => {\n if (currentPage === numberOfPages - 1) {\n // TODO: skal dette være en no-op i stedet?\n onChange(e, currentPage, currentPage);\n return;\n }\n const toPage = currentPage + 1;\n onChange(e, toPage, currentPage);\n setCurrentPage(toPage);\n setPagePickerValue(String(toPage + 1));\n },\n [onChange, numberOfPages, currentPage],\n );\n\n return (\n <div\n className={clsx(\"jkl-table-pagination\", className)}\n {...rest}\n id={id}\n ref={ref}\n >\n <div className=\"jkl-table-pagination__left\">\n <div className=\"jkl-table-pagination__picker jkl-table-pagination__picker--rows\">\n <span\n className=\"jkl-table-pagination__picker-label\"\n aria-hidden=\"true\"\n >\n {labels.rowsPerPage}:\n </span>\n <NativeSelect\n className=\"jkl-table-pagination__picker-input\"\n label={labels.rowsPerPage}\n labelProps={{ srOnly: true }}\n name={`${id}-rows-per-page`}\n items={rowsPerPageItems.map((i) =>\n typeof i === \"number\"\n ? String(i)\n : {\n label: i.label,\n value: String(i.value),\n },\n )}\n value={String(rowsPerPage)}\n onChange={onChangeRowsPerPage}\n width=\"min(8rem, 100%)\"\n inline\n />\n </div>\n </div>\n <span className=\"jkl-table-pagination__total-rows\">\n Treff: {totalNumberOfRows}\n </span>\n <div className=\"jkl-table-pagination__right\">\n {numberOfPages !== 1 && (\n <nav className=\"jkl-table-pagination__nav\">\n {withGoToPage && (\n <div className=\"jkl-table-pagination__picker jkl-table-pagination__picker--page\">\n <span\n className=\"jkl-table-pagination__picker-label\"\n aria-hidden=\"true\"\n >\n {typeof withGoToPage === \"object\"\n ? withGoToPage.gotoLabel\n : \"Gå til side\"}\n :\n </span>\n {/* onChange først ved enter/submit */}\n <TextInput\n className=\"jkl-table-pagination__picker-input\"\n label={\n typeof withGoToPage === \"object\"\n ? withGoToPage.gotoLabel\n : \"Gå til side\"\n }\n labelProps={{ srOnly: true }}\n name={`${id}-go-to-page`}\n value={pagePickerValue}\n width=\"min(4rem, 100%)\"\n onChange={onPageChange}\n aria-invalid={\n pagePickerValue &&\n pagePickerValue !==\n String(currentPage + 1)\n ? \"true\"\n : undefined\n }\n />\n </div>\n )}\n <ul>\n <li>\n <IconButton\n className=\"jkl-table-pagination__previous\"\n title={labels.previous}\n onClick={onPrevious}\n >\n <ChevronLeftIcon />\n </IconButton>\n </li>\n <PaginationPages\n id={id}\n activePage={activePage}\n numberOfPages={numberOfPages}\n onPageClick={onPageClick}\n />\n <li>\n <IconButton\n className=\"jkl-table-pagination__next\"\n title={labels.next}\n onClick={onNext}\n >\n <ChevronRightIcon />\n </IconButton>\n </li>\n </ul>\n </nav>\n )}\n </div>\n </div>\n );\n },\n);\n\nconst PaginationPages: FC<{\n id: string;\n activePage: number;\n numberOfPages: number;\n onPageClick: MouseEventHandler;\n}> = ({ id, activePage, numberOfPages, onPageClick }) => {\n if (numberOfPages <= 7) {\n return (\n <>\n {Array.from({ length: numberOfPages }).map((_, i) => (\n <li key={`${id}-page-${i}`}>\n <button\n className={clsx(\"jkl-table-pagination__page\", {\n \"jkl-table-pagination__page--active\":\n activePage === i,\n })}\n type=\"button\"\n data-number={i}\n onClick={onPageClick}\n >\n {i + 1}\n </button>\n </li>\n ))}\n </>\n );\n }\n\n const showStartEllipsis = activePage > 3 && numberOfPages > 7;\n const showEndEllipsis = activePage < numberOfPages - 4 && numberOfPages > 7;\n\n const startEllipsis = Math.min(\n Math.max(activePage - 2, 1),\n numberOfPages - 6,\n );\n const centerPageNumberStart = Math.min(\n startEllipsis + 1,\n numberOfPages - 5,\n );\n const centerPageNumber = Math.min(\n centerPageNumberStart + 1,\n numberOfPages - 4,\n );\n const centerPageNumberEnd = Math.min(\n centerPageNumberStart + 2,\n numberOfPages - 3,\n );\n const endEllipsis = Math.min(centerPageNumberStart + 3, numberOfPages - 2);\n\n return (\n <>\n <li>\n <PaginationPageButton\n isActive={activePage === 0}\n number={0}\n onClick={onPageClick}\n />\n </li>\n <li>\n {showStartEllipsis ? (\n <span\n className=\"jkl-table-pagination__ellipsis\"\n aria-hidden\n >\n {\"...\"}\n </span>\n ) : (\n <PaginationPageButton\n isActive={activePage === startEllipsis}\n number={startEllipsis}\n onClick={onPageClick}\n />\n )}\n </li>\n <li>\n <PaginationPageButton\n isActive={activePage === centerPageNumberStart}\n number={centerPageNumberStart}\n onClick={onPageClick}\n />\n </li>\n <li>\n <PaginationPageButton\n isActive={activePage === centerPageNumber}\n number={centerPageNumber}\n onClick={onPageClick}\n />\n </li>\n <li>\n <PaginationPageButton\n isActive={activePage === centerPageNumberEnd}\n number={centerPageNumberEnd}\n onClick={onPageClick}\n />\n </li>\n <li>\n {showEndEllipsis ? (\n <span\n className=\"jkl-table-pagination__ellipsis\"\n aria-hidden\n >\n {\"...\"}\n </span>\n ) : (\n <PaginationPageButton\n isActive={activePage === endEllipsis}\n number={endEllipsis}\n onClick={onPageClick}\n />\n )}\n </li>\n <li>\n <PaginationPageButton\n isActive={activePage === numberOfPages - 1}\n number={numberOfPages - 1}\n onClick={onPageClick}\n />\n </li>\n </>\n );\n};\n\nconst PaginationPageButton: FC<{\n isActive: boolean;\n number: number;\n onClick: MouseEventHandler;\n}> = ({ isActive, number, onClick, ...rest }) => (\n <button\n className={clsx(\"jkl-table-pagination__page\", {\n \"jkl-table-pagination__page--active\": isActive,\n })}\n type=\"button\"\n data-number={number}\n onClick={onClick}\n {...rest}\n >\n {number + 1}\n </button>\n);\n\nTablePagination.displayName = \"TablePagination\";\n"],"names":["TablePagination","forwardRef","props","ref","activePage","totalNumberOfRows","rowsPerPage","rowsPerPageItems","className","id","idProp","withGoToPage","onChange","onChangeRowsPerPage","labels","previous","next","rest","useId","generateSuffix","numberOfPages","Math","ceil","currentPage","setCurrentPage","useState","min","num","max","clamp","onPageClick","useCallback","e","toPage","Number","parseInt","currentTarget","dataset","number","setPagePickerValue","String","pagePickerValue","onPageChange","target","value","isNaN","onPrevious","onNext","jsxs","clsx","children","jsx","NativeSelect","label","labelProps","srOnly","name","items","map","i","width","inline","gotoLabel","TextInput","IconButton","title","onClick","ChevronLeftIcon","PaginationPages","ChevronRightIcon","Fragment","Array","from","length","_","type","showStartEllipsis","showEndEllipsis","startEllipsis","centerPageNumberStart","centerPageNumber","centerPageNumberEnd","endEllipsis","PaginationPageButton","isActive","displayName"],"mappings":"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"}
1
+ {"version":3,"file":"TablePagination.js","sources":["../../../../src/components/table/TablePagination.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React, {\n forwardRef,\n useCallback,\n useState,\n type ChangeEventHandler,\n type FC,\n type MouseEventHandler,\n} from \"react\";\nimport { useId } from \"../../hooks/useId/useId.js\";\nimport { IconButton } from \"../icon-button/IconButton.js\";\nimport { ChevronLeftIcon } from \"../icon/icons/ChevronLeftIcon.js\";\nimport { ChevronRightIcon } from \"../icon/icons/ChevronRightIcon.js\";\nimport { Select } from \"../select/Select.js\";\nimport { TextInput } from \"../text-input/TextInput.js\";\nimport type { TablePaginationProps } from \"./types.js\";\n\nfunction clamp(min: number, num: number, max: number): number {\n if (num < min) {\n return min;\n }\n\n if (num > max) {\n return max;\n }\n\n return num;\n}\n\nexport const TablePagination = forwardRef<HTMLDivElement, TablePaginationProps>(\n (props, ref) => {\n const {\n activePage = 0,\n totalNumberOfRows,\n rowsPerPage,\n rowsPerPageItems,\n className,\n id: idProp,\n withGoToPage = false,\n onChange,\n onChangeRowsPerPage,\n labels = {\n rowsPerPage: \"Rader per side\",\n previous: \"Forrige\",\n next: \"Neste\",\n },\n ...rest\n } = props;\n\n const id = useId(idProp || \"jkl-table-pagination\", {\n generateSuffix: !idProp,\n });\n\n const showAll = rowsPerPage <= 0;\n const numberOfPages = showAll\n ? 1\n : Math.ceil(totalNumberOfRows / rowsPerPage);\n\n const [currentPage, setCurrentPage] = useState(\n clamp(0, activePage, numberOfPages - 1),\n );\n\n const onPageClick: MouseEventHandler<HTMLButtonElement> = useCallback(\n (e) => {\n const toPage = Number.parseInt(\n e.currentTarget.dataset.number as string,\n );\n onChange(e, toPage, currentPage);\n setCurrentPage(toPage);\n setPagePickerValue(String(toPage + 1));\n },\n [onChange, currentPage],\n );\n\n const [pagePickerValue, setPagePickerValue] = useState(\n String(currentPage + 1),\n );\n const onPageChange: ChangeEventHandler<HTMLInputElement> = useCallback(\n (e) => {\n setPagePickerValue(e.target.value);\n try {\n const toPage = Number.parseInt(e.target.value) - 1;\n if (Number.isNaN(toPage)) {\n return;\n }\n\n if (toPage >= 0 && toPage < numberOfPages) {\n onChange(e, toPage, currentPage);\n setCurrentPage(toPage);\n }\n } catch {\n return;\n }\n },\n [onChange, currentPage, numberOfPages],\n );\n\n const onPrevious: MouseEventHandler<HTMLButtonElement> = useCallback(\n (e) => {\n if (currentPage === 0) {\n // TODO: skal dette være en no-op i stedet?\n onChange(e, currentPage, currentPage);\n return;\n }\n const toPage = currentPage - 1;\n onChange(e, toPage, currentPage);\n setCurrentPage(toPage);\n setPagePickerValue(String(toPage + 1));\n },\n [onChange, currentPage],\n );\n\n const onNext: MouseEventHandler<HTMLButtonElement> = useCallback(\n (e) => {\n if (currentPage === numberOfPages - 1) {\n // TODO: skal dette være en no-op i stedet?\n onChange(e, currentPage, currentPage);\n return;\n }\n const toPage = currentPage + 1;\n onChange(e, toPage, currentPage);\n setCurrentPage(toPage);\n setPagePickerValue(String(toPage + 1));\n },\n [onChange, numberOfPages, currentPage],\n );\n\n return (\n <div\n className={clsx(\"jkl-table-pagination\", className)}\n {...rest}\n id={id}\n ref={ref}\n >\n <div className=\"jkl-table-pagination__left\">\n <div className=\"jkl-table-pagination__picker jkl-table-pagination__picker--rows\">\n <span\n className=\"jkl-table-pagination__picker-label\"\n aria-hidden=\"true\"\n >\n {labels.rowsPerPage}:\n </span>\n <Select\n className=\"jkl-table-pagination__picker-input\"\n label={labels.rowsPerPage}\n labelProps={{ srOnly: true }}\n name={`${id}-rows-per-page`}\n items={rowsPerPageItems.map((i) =>\n typeof i === \"number\"\n ? String(i)\n : {\n label: i.label,\n value: String(i.value),\n },\n )}\n value={String(rowsPerPage)}\n onChange={onChangeRowsPerPage}\n width=\"min(8rem, 100%)\"\n />\n </div>\n </div>\n <span className=\"jkl-table-pagination__total-rows\">\n Treff: {totalNumberOfRows}\n </span>\n <div className=\"jkl-table-pagination__right\">\n {numberOfPages !== 1 && (\n <nav className=\"jkl-table-pagination__nav\">\n {withGoToPage && (\n <div className=\"jkl-table-pagination__picker jkl-table-pagination__picker--page\">\n <span\n className=\"jkl-table-pagination__picker-label\"\n aria-hidden=\"true\"\n >\n {typeof withGoToPage === \"object\"\n ? withGoToPage.gotoLabel\n : \"Gå til side\"}\n :\n </span>\n {/* onChange først ved enter/submit */}\n <TextInput\n className=\"jkl-table-pagination__picker-input\"\n label={\n typeof withGoToPage === \"object\"\n ? withGoToPage.gotoLabel\n : \"Gå til side\"\n }\n labelProps={{ srOnly: true }}\n name={`${id}-go-to-page`}\n value={pagePickerValue}\n width=\"min(4rem, 100%)\"\n onChange={onPageChange}\n aria-invalid={\n pagePickerValue &&\n pagePickerValue !==\n String(currentPage + 1)\n ? \"true\"\n : undefined\n }\n />\n </div>\n )}\n <ul>\n <li>\n <IconButton\n className=\"jkl-table-pagination__previous\"\n title={labels.previous}\n onClick={onPrevious}\n >\n <ChevronLeftIcon />\n </IconButton>\n </li>\n <PaginationPages\n id={id}\n activePage={activePage}\n numberOfPages={numberOfPages}\n onPageClick={onPageClick}\n />\n <li>\n <IconButton\n className=\"jkl-table-pagination__next\"\n title={labels.next}\n onClick={onNext}\n >\n <ChevronRightIcon />\n </IconButton>\n </li>\n </ul>\n </nav>\n )}\n </div>\n </div>\n );\n },\n);\n\nconst PaginationPages: FC<{\n id: string;\n activePage: number;\n numberOfPages: number;\n onPageClick: MouseEventHandler;\n}> = ({ id, activePage, numberOfPages, onPageClick }) => {\n if (numberOfPages <= 7) {\n return (\n <>\n {Array.from({ length: numberOfPages }).map((_, i) => (\n <li key={`${id}-page-${i}`}>\n <button\n className={clsx(\"jkl-table-pagination__page\", {\n \"jkl-table-pagination__page--active\":\n activePage === i,\n })}\n type=\"button\"\n data-number={i}\n onClick={onPageClick}\n >\n {i + 1}\n </button>\n </li>\n ))}\n </>\n );\n }\n\n const showStartEllipsis = activePage > 3 && numberOfPages > 7;\n const showEndEllipsis = activePage < numberOfPages - 4 && numberOfPages > 7;\n\n const startEllipsis = Math.min(\n Math.max(activePage - 2, 1),\n numberOfPages - 6,\n );\n const centerPageNumberStart = Math.min(\n startEllipsis + 1,\n numberOfPages - 5,\n );\n const centerPageNumber = Math.min(\n centerPageNumberStart + 1,\n numberOfPages - 4,\n );\n const centerPageNumberEnd = Math.min(\n centerPageNumberStart + 2,\n numberOfPages - 3,\n );\n const endEllipsis = Math.min(centerPageNumberStart + 3, numberOfPages - 2);\n\n return (\n <>\n <li>\n <PaginationPageButton\n isActive={activePage === 0}\n number={0}\n onClick={onPageClick}\n />\n </li>\n <li>\n {showStartEllipsis ? (\n <span\n className=\"jkl-table-pagination__ellipsis\"\n aria-hidden\n >\n {\"...\"}\n </span>\n ) : (\n <PaginationPageButton\n isActive={activePage === startEllipsis}\n number={startEllipsis}\n onClick={onPageClick}\n />\n )}\n </li>\n <li>\n <PaginationPageButton\n isActive={activePage === centerPageNumberStart}\n number={centerPageNumberStart}\n onClick={onPageClick}\n />\n </li>\n <li>\n <PaginationPageButton\n isActive={activePage === centerPageNumber}\n number={centerPageNumber}\n onClick={onPageClick}\n />\n </li>\n <li>\n <PaginationPageButton\n isActive={activePage === centerPageNumberEnd}\n number={centerPageNumberEnd}\n onClick={onPageClick}\n />\n </li>\n <li>\n {showEndEllipsis ? (\n <span\n className=\"jkl-table-pagination__ellipsis\"\n aria-hidden\n >\n {\"...\"}\n </span>\n ) : (\n <PaginationPageButton\n isActive={activePage === endEllipsis}\n number={endEllipsis}\n onClick={onPageClick}\n />\n )}\n </li>\n <li>\n <PaginationPageButton\n isActive={activePage === numberOfPages - 1}\n number={numberOfPages - 1}\n onClick={onPageClick}\n />\n </li>\n </>\n );\n};\n\nconst PaginationPageButton: FC<{\n isActive: boolean;\n number: number;\n onClick: MouseEventHandler;\n}> = ({ isActive, number, onClick, ...rest }) => (\n <button\n className={clsx(\"jkl-table-pagination__page\", {\n \"jkl-table-pagination__page--active\": isActive,\n })}\n type=\"button\"\n data-number={number}\n onClick={onClick}\n {...rest}\n >\n {number + 1}\n </button>\n);\n\nTablePagination.displayName = \"TablePagination\";\n"],"names":["TablePagination","forwardRef","props","ref","activePage","totalNumberOfRows","rowsPerPage","rowsPerPageItems","className","id","idProp","withGoToPage","onChange","onChangeRowsPerPage","labels","previous","next","rest","useId","generateSuffix","numberOfPages","Math","ceil","currentPage","setCurrentPage","useState","min","num","max","clamp","onPageClick","useCallback","e","toPage","Number","parseInt","currentTarget","dataset","number","setPagePickerValue","String","pagePickerValue","onPageChange","target","value","isNaN","onPrevious","onNext","jsxs","clsx","children","jsx","Select","label","labelProps","srOnly","name","items","map","i","width","gotoLabel","TextInput","IconButton","title","onClick","ChevronLeftIcon","PaginationPages","ChevronRightIcon","Fragment","Array","from","length","_","type","showStartEllipsis","showEndEllipsis","startEllipsis","centerPageNumberStart","centerPageNumber","centerPageNumberEnd","endEllipsis","PaginationPageButton","isActive","displayName"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Tabs.js","sources":["../../../../../../node_modules/.pnpm/nanoid@5.1.16/node_modules/nanoid/url-alphabet/index.js","../../../../../../node_modules/.pnpm/nanoid@5.1.16/node_modules/nanoid/index.browser.js","../../../../src/components/tabs/Tabs.tsx"],"sourcesContent":["export let urlAlphabet =\n 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'\n","\n\nimport { urlAlphabet as scopedUrlAlphabet } from './url-alphabet/index.js'\n\nexport { urlAlphabet } from './url-alphabet/index.js'\n\nexport let random = bytes => crypto.getRandomValues(new Uint8Array(bytes))\n\nexport let customRandom = (alphabet, defaultSize, getRandom) => {\n let safeByteCutoff = 256 - (256 % alphabet.length)\n\n if (safeByteCutoff === 256) {\n let mask = alphabet.length - 1\n\n return (size = defaultSize) => {\n if (!size) return ''\n let id = ''\n while (true) {\n let bytes = getRandom(size)\n let j = size\n while (j--) {\n id += alphabet[bytes[j] & mask]\n if (id.length >= size) return id\n }\n }\n }\n }\n\n let step = Math.ceil((1.6 * 256 * defaultSize) / safeByteCutoff)\n\n return (size = defaultSize) => {\n if (!size) return ''\n let id = ''\n while (true) {\n let bytes = getRandom(step)\n let j = step\n while (j--) {\n if (bytes[j] < safeByteCutoff) {\n id += alphabet[bytes[j] % alphabet.length]\n if (id.length >= size) return id\n }\n }\n }\n }\n}\n\nexport let customAlphabet = (alphabet, size = 21) =>\n customRandom(alphabet, size | 0, random)\n\nexport let nanoid = (size = 21) => {\n let id = ''\n let bytes = crypto.getRandomValues(new Uint8Array((size |= 0)))\n while (size--) {\n id += scopedUrlAlphabet[bytes[size] & 63]\n }\n return id\n}\n","import clsx from \"clsx\";\nimport { nanoid } from \"nanoid\";\nimport React, { useCallback, useEffect, useState } from \"react\";\nimport { usePreviousValue } from \"../../hooks/usePreviousValue/usePreviousValue.js\";\nimport type { InjectedProps } from \"./TabList.js\";\nimport type { TabListProps, TabPanelProps, TabsProps } from \"./types.js\";\n\n/**\n * Konteiner for et grensesnitt hvor man kan tabbe mellom innhold.\n * Må inneholde en TabList etterfulgt av en eller flere TabPanel.\n *\n * Docs: https://jokul.fremtind.no/komponenter/tabs\n */\nexport const Tabs = ({ onChange, defaultTab, ...props }: TabsProps) => {\n const [activeIndex, setActiveIndex] = useState(defaultTab ?? 0);\n\n const previousTabIndex = usePreviousValue(activeIndex);\n\n useEffect(() => {\n if (\n previousTabIndex !== undefined &&\n previousTabIndex !== activeIndex &&\n onChange\n ) {\n onChange(activeIndex);\n }\n }, [onChange, previousTabIndex, activeIndex]);\n\n const [tabIDs, setTabIDs] = useState<string[]>([]);\n const [tabPanelIDs, setTabPanelIds] = useState<string[]>([]);\n\n const resolveIDs = useCallback(() => {\n const tabList = React.Children.toArray(props.children)[0];\n\n if (!React.isValidElement(tabList)) return;\n\n React.Children.forEach(tabList.props.children, (tab) => {\n if (!React.isValidElement(tab)) return;\n\n setTabIDs((prev) => [...prev, `jkl-tab-${nanoid(8)}`]);\n setTabPanelIds((prev) => [...prev, `jkl-tabpanel-${nanoid(8)}`]);\n });\n }, [props.children]);\n\n const renderTabList = () => {\n const tabList = React.Children.toArray(props.children)[0];\n\n if (!React.isValidElement<TabListProps & InjectedProps>(tabList))\n return;\n\n return React.cloneElement<TabListProps & InjectedProps>(tabList, {\n activeIndex,\n setActiveIndex,\n tabIDs,\n tabPanelIDs,\n });\n };\n\n const renderTabPanels = () => {\n return React.Children.map(props.children, (child, childIndex) => {\n if (\n !React.isValidElement<\n TabPanelProps & React.HTMLAttributes<HTMLDivElement>\n >(child) ||\n childIndex === 0\n )\n return;\n\n const tabPanelIndex = childIndex - 1;\n\n return tabPanelIndex === activeIndex\n ? React.cloneElement<\n TabPanelProps & React.HTMLAttributes<HTMLDivElement>\n >(child, {\n \"aria-labelledby\": tabIDs[tabPanelIndex],\n id: tabPanelIDs[tabPanelIndex],\n })\n : null;\n });\n };\n\n useEffect(() => {\n resolveIDs();\n }, [resolveIDs]);\n\n return (\n <div {...props} className={clsx(\"jkl-tabs\", props.className)}>\n {renderTabList()}\n {renderTabPanels()}\n </div>\n );\n};\n"],"names":["nanoid","size","id","bytes","crypto","getRandomValues","Uint8Array","Tabs","onChange","defaultTab","props","activeIndex","setActiveIndex","useState","previousTabIndex","usePreviousValue","useEffect","tabIDs","setTabIDs","tabPanelIDs","setTabPanelIds","resolveIDs","useCallback","tabList","React","Children","toArray","children","isValidElement","forEach","tab","prev","jsxs","className","clsx","cloneElement","renderTabList","map","child","childIndex","tabPanelIndex"],"mappings":"+OAAO,ICiDIA,EAAS,CAACC,EAAO,MAC1B,IAAIC,EAAK,GACLC,EAAQC,OAAOC,gBAAgB,IAAIC,WAAYL,GAAQ,IAC3D,KAAOA,KACLC,GDpDF,mECoDwC,GAAdC,EAAMF,IAEhC,OAAOC,GC1CF,MAAMK,EAAO,EAAGC,SAAAA,EAAUC,WAAAA,KAAeC,MAC5C,MAAOC,EAAaC,GAAkBC,EAASJ,GAAc,GAEvDK,EAAmBC,EAAiBJ,GAE1CK,EAAU,UAEmB,IAArBF,GACAA,IAAqBH,GACrBH,GAEAA,EAASG,IAEd,CAACH,EAAUM,EAAkBH,IAEhC,MAAOM,EAAQC,GAAaL,EAAmB,KACxCM,EAAaC,GAAkBP,EAAmB,IAEnDQ,EAAaC,EAAY,KAC3B,MAAMC,EAAUC,EAAMC,SAASC,QAAQhB,EAAMiB,UAAU,GAElDH,EAAMI,eAAeL,IAE1BC,EAAMC,SAASI,QAAQN,EAAQb,MAAMiB,SAAWG,IACvCN,EAAMI,eAAeE,KAE1BZ,EAAWa,GAAS,IAAIA,EAAM,WAAW/B,EAAO,OAChDoB,EAAgBW,GAAS,IAAIA,EAAM,gBAAgB/B,EAAO,WAE/D,CAACU,EAAMiB,WAuCV,OAAAX,EAAU,KACNK,KACD,CAACA,IAGAW,EAAC,UAAQtB,EAAOuB,UAAWC,EAAK,WAAYxB,EAAMuB,WAC7CN,SAAA,CA3Ca,MAClB,MAAMJ,EAAUC,EAAMC,SAASC,QAAQhB,EAAMiB,UAAU,GAEvD,GAAKH,EAAMI,eAA6CL,GAGxD,OAAOC,EAAMW,aAA2CZ,EAAS,CAC7DZ,YAAAA,EACAC,eAAAA,EACAK,OAAAA,EACAE,YAAAA,KAiCCiB,GA5BEZ,EAAMC,SAASY,IAAI3B,EAAMiB,SAAU,CAACW,EAAOC,KAC9C,IACKf,EAAMI,eAELU,IACa,IAAfC,EAEA,OAEJ,MAAMC,EAAgBD,EAAa,EAEnC,OAAOC,IAAkB7B,EACnBa,EAAMW,aAEJG,EAAO,CACL,kBAAmBrB,EAAOuB,GAC1BtC,GAAIiB,EAAYqB,KAEpB","x_google_ignoreList":[0,1]}
1
+ {"version":3,"file":"Tabs.js","sources":["../../../../../../node_modules/.pnpm/nanoid@6.0.1/node_modules/nanoid/url-alphabet/index.js","../../../../../../node_modules/.pnpm/nanoid@6.0.1/node_modules/nanoid/index.browser.js","../../../../src/components/tabs/Tabs.tsx"],"sourcesContent":["export let urlAlphabet =\n 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'\n","\n\nimport { urlAlphabet } from './url-alphabet/index.js'\n\nexport { urlAlphabet }\n\nexport let random = bytes => crypto.getRandomValues(new Uint8Array(bytes))\n\nexport let customRandom = (alphabet, defaultSize, getRandom) => {\n let safeByteCutoff = 256 - (256 % alphabet.length)\n\n if (safeByteCutoff === 256) {\n let mask = alphabet.length - 1\n\n return (size = defaultSize) => {\n if (!size) return ''\n let id = ''\n while (true) {\n let bytes = getRandom(size)\n let j = size\n while (j--) {\n id += alphabet[bytes[j] & mask]\n if (id.length >= size) return id\n }\n }\n }\n }\n\n let step = Math.ceil((1.6 * 256 * defaultSize) / safeByteCutoff)\n\n return (size = defaultSize) => {\n if (!size) return ''\n let id = ''\n while (true) {\n let bytes = getRandom(step)\n let j = step\n while (j--) {\n if (bytes[j] < safeByteCutoff) {\n id += alphabet[bytes[j] % alphabet.length]\n if (id.length >= size) return id\n }\n }\n }\n }\n}\n\nexport let customAlphabet = (alphabet, size = 21) =>\n customRandom(alphabet, size | 0, random)\n\nexport let nanoid = (size = 21) => {\n let id = ''\n let bytes = crypto.getRandomValues(new Uint8Array((size |= 0)))\n while (size--) {\n id += urlAlphabet[bytes[size] & 63]\n }\n return id\n}\n","import clsx from \"clsx\";\nimport { nanoid } from \"nanoid\";\nimport React, { useCallback, useEffect, useState } from \"react\";\nimport { usePreviousValue } from \"../../hooks/usePreviousValue/usePreviousValue.js\";\nimport type { InjectedProps } from \"./TabList.js\";\nimport type { TabListProps, TabPanelProps, TabsProps } from \"./types.js\";\n\n/**\n * Konteiner for et grensesnitt hvor man kan tabbe mellom innhold.\n * Må inneholde en TabList etterfulgt av en eller flere TabPanel.\n *\n * Docs: https://jokul.fremtind.no/komponenter/tabs\n */\nexport const Tabs = ({ onChange, defaultTab, ...props }: TabsProps) => {\n const [activeIndex, setActiveIndex] = useState(defaultTab ?? 0);\n\n const previousTabIndex = usePreviousValue(activeIndex);\n\n useEffect(() => {\n if (\n previousTabIndex !== undefined &&\n previousTabIndex !== activeIndex &&\n onChange\n ) {\n onChange(activeIndex);\n }\n }, [onChange, previousTabIndex, activeIndex]);\n\n const [tabIDs, setTabIDs] = useState<string[]>([]);\n const [tabPanelIDs, setTabPanelIds] = useState<string[]>([]);\n\n const resolveIDs = useCallback(() => {\n const tabList = React.Children.toArray(props.children)[0];\n\n if (!React.isValidElement(tabList)) return;\n\n React.Children.forEach(tabList.props.children, (tab) => {\n if (!React.isValidElement(tab)) return;\n\n setTabIDs((prev) => [...prev, `jkl-tab-${nanoid(8)}`]);\n setTabPanelIds((prev) => [...prev, `jkl-tabpanel-${nanoid(8)}`]);\n });\n }, [props.children]);\n\n const renderTabList = () => {\n const tabList = React.Children.toArray(props.children)[0];\n\n if (!React.isValidElement<TabListProps & InjectedProps>(tabList))\n return;\n\n return React.cloneElement<TabListProps & InjectedProps>(tabList, {\n activeIndex,\n setActiveIndex,\n tabIDs,\n tabPanelIDs,\n });\n };\n\n const renderTabPanels = () => {\n return React.Children.map(props.children, (child, childIndex) => {\n if (\n !React.isValidElement<\n TabPanelProps & React.HTMLAttributes<HTMLDivElement>\n >(child) ||\n childIndex === 0\n )\n return;\n\n const tabPanelIndex = childIndex - 1;\n\n return tabPanelIndex === activeIndex\n ? React.cloneElement<\n TabPanelProps & React.HTMLAttributes<HTMLDivElement>\n >(child, {\n \"aria-labelledby\": tabIDs[tabPanelIndex],\n id: tabPanelIDs[tabPanelIndex],\n })\n : null;\n });\n };\n\n useEffect(() => {\n resolveIDs();\n }, [resolveIDs]);\n\n return (\n <div {...props} className={clsx(\"jkl-tabs\", props.className)}>\n {renderTabList()}\n {renderTabPanels()}\n </div>\n );\n};\n"],"names":["nanoid","size","id","bytes","crypto","getRandomValues","Uint8Array","Tabs","onChange","defaultTab","props","activeIndex","setActiveIndex","useState","previousTabIndex","usePreviousValue","useEffect","tabIDs","setTabIDs","tabPanelIDs","setTabPanelIds","resolveIDs","useCallback","tabList","React","Children","toArray","children","isValidElement","forEach","tab","prev","jsxs","className","clsx","cloneElement","renderTabList","map","child","childIndex","tabPanelIndex"],"mappings":"+OAAO,ICiDIA,EAAS,CAACC,EAAO,MAC1B,IAAIC,EAAK,GACLC,EAAQC,OAAOC,gBAAgB,IAAIC,WAAYL,GAAQ,IAC3D,KAAOA,KACLC,GDpDF,mECoDkC,GAAdC,EAAMF,IAE1B,OAAOC,GC1CF,MAAMK,EAAO,EAAGC,SAAAA,EAAUC,WAAAA,KAAeC,MAC5C,MAAOC,EAAaC,GAAkBC,EAASJ,GAAc,GAEvDK,EAAmBC,EAAiBJ,GAE1CK,EAAU,UAEmB,IAArBF,GACAA,IAAqBH,GACrBH,GAEAA,EAASG,IAEd,CAACH,EAAUM,EAAkBH,IAEhC,MAAOM,EAAQC,GAAaL,EAAmB,KACxCM,EAAaC,GAAkBP,EAAmB,IAEnDQ,EAAaC,EAAY,KAC3B,MAAMC,EAAUC,EAAMC,SAASC,QAAQhB,EAAMiB,UAAU,GAElDH,EAAMI,eAAeL,IAE1BC,EAAMC,SAASI,QAAQN,EAAQb,MAAMiB,SAAWG,IACvCN,EAAMI,eAAeE,KAE1BZ,EAAWa,GAAS,IAAIA,EAAM,WAAW/B,EAAO,OAChDoB,EAAgBW,GAAS,IAAIA,EAAM,gBAAgB/B,EAAO,WAE/D,CAACU,EAAMiB,WAuCV,OAAAX,EAAU,KACNK,KACD,CAACA,IAGAW,EAAC,UAAQtB,EAAOuB,UAAWC,EAAK,WAAYxB,EAAMuB,WAC7CN,SAAA,CA3Ca,MAClB,MAAMJ,EAAUC,EAAMC,SAASC,QAAQhB,EAAMiB,UAAU,GAEvD,GAAKH,EAAMI,eAA6CL,GAGxD,OAAOC,EAAMW,aAA2CZ,EAAS,CAC7DZ,YAAAA,EACAC,eAAAA,EACAK,OAAAA,EACAE,YAAAA,KAiCCiB,GA5BEZ,EAAMC,SAASY,IAAI3B,EAAMiB,SAAU,CAACW,EAAOC,KAC9C,IACKf,EAAMI,eAELU,IACa,IAAfC,EAEA,OAEJ,MAAMC,EAAgBD,EAAa,EAEnC,OAAOC,IAAkB7B,EACnBa,EAAMW,aAEJG,EAAO,CACL,kBAAmBrB,EAAOuB,GAC1BtC,GAAIiB,EAAYqB,KAEpB","x_google_ignoreList":[0,1]}
@@ -6,11 +6,13 @@ import { RefObject } from 'react';
6
6
  * re-festes når elementet faktisk er tilgjengelig.
7
7
  */
8
8
  type UseListNavigationProps<T> = {
9
+ disableTypeahead?: boolean;
10
+ } & ({
9
11
  ref: RefObject<T | null>;
10
12
  element?: never;
11
13
  } | {
12
14
  ref?: never;
13
15
  element: T | null;
14
- };
15
- export declare function useListNavigation<T extends HTMLElement>({ ref, element, }: UseListNavigationProps<T>): void;
16
+ });
17
+ export declare function useListNavigation<T extends HTMLElement>({ ref, element, disableTypeahead, }: UseListNavigationProps<T>): void;
16
18
  export {};
@@ -1,2 +1,2 @@
1
- import{useLayoutEffect as e}from"react";function t({ref:t,element:n}){e(()=>{const e=n??t?.current??null;if(!e)return;const s={id:void 0},o={keys:""},c=t=>{!function({list:e,event:t,search:n,searchResetTimer:s}){const{key:o,target:c}=t,i={event:t,list:e,currentFocus:c};switch(o){case"ArrowUp":case"PageUp":r("prev",i);break;case"ArrowDown":case"PageDown":r("next",i);break;case"Home":r("first",i);break;case"End":r("last",i);break;case"Tab":t.preventDefault();break;case"Enter":case" ":break;default:if(void 0!==n){const t=function({list:e,key:t,search:r,searchResetTimer:n}){const s=e.querySelectorAll('[role="option"]');if(!s.length)return null;if(r){r.keys=r.keys.concat(t),function(e,t){void 0!==t.id&&(clearTimeout(t.id),t.id=void 0),t.id=window.setTimeout(()=>{e&&(e.keys=""),t.id=void 0},500)}(r,n);for(let e=0;e<s.length;e++){const t=s[e].innerText;if(t&&0===t.toLowerCase().indexOf(r.keys))return s[e]}}return null}({list:e,key:o,search:n,searchResetTimer:s});t&&t.focus()}}}({list:e,event:t,search:o,searchResetTimer:s})};return e.addEventListener("keydown",c),()=>{e.removeEventListener("keydown",c),void 0!==s.id&&clearTimeout(s.id)}},[n,t])}function r(e,{event:t,list:r,currentFocus:n}){t.preventDefault(),function(e,t,r){const n=r;switch(e){case"prev":{const e=n&&n.previousElementSibling;e&&e.focus();break}case"next":{const e=n&&n.nextElementSibling;e&&e.focus();break}case"first":{const e=t.querySelector('[role="option"]');e&&e.focus();break}case"last":{const e=t.querySelectorAll('[role="option"]');e.length&&e[e.length-1].focus();break}}}(e,r,n)}export{t as useListNavigation};
1
+ import{useRef as e,useCallback as t,useEffect as r}from"react";const n=["Control","Alt","Shift","Meta"],o="[role='option'][class~='jkl-select__option'],[class~='jkl-combobox__option'],[class~='jkl-option'],[class~='jkl-search']";function c({ref:c,element:s,disableTypeahead:l=!1}){const u=e(void 0),i=e(""),f=t(e=>{if(l||n.includes(e))return;const t=s??c?.current??null;if(i.current=i.current.concat(e),clearTimeout(u.current),u.current=setTimeout(()=>{i.current="",u.current=void 0},500),!i.current.length)return;const r=t?.querySelectorAll(o);if(r&&r.length)for(const e of r)if(0===e.innerText?.toLowerCase().indexOf(i.current.toLowerCase()))return void a(e)},[s,c,l]),d=t(e=>{const t=s??c?.current??null;if(!t)return;const{key:r,target:n}=e,l=n,u=Array.from(t.querySelectorAll(o));switch(r){case"ArrowUp":{e.preventDefault();const t=u.indexOf(l.closest(o));a(u[t-1]);break}case"ArrowDown":{e.preventDefault();const t=u.indexOf(l.closest(o));a(u[t+1]);break}case"PageUp":case"Home":e.preventDefault(),a(u[0]);break;case"PageDown":case"End":e.preventDefault(),a(u[u.length-1]);break;case"Shift":case"Control":case"Alt":case"Meta":case"Enter":case"Escape":case" ":break;case"Tab":e.preventDefault();break;default:f(r)}},[s,c,f]);r(()=>{const e=s??c?.current??null;if(e)return e.addEventListener("keydown",d),()=>{e.removeEventListener("keydown",d),clearTimeout(u.current)}},[s,c,d])}function a(e){e&&("BUTTON"===e.nodeName||"INPUT"===e.nodeName?e.focus():e.querySelector("input,button")?.focus())}export{c as useListNavigation};
2
2
  //# sourceMappingURL=useListNavigation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useListNavigation.js","sources":["../../../../src/hooks/useListNavigation/useListNavigation.ts"],"sourcesContent":["import { type RefObject, useLayoutEffect } from \"react\";\n\ntype TimerHandle = { id: number | undefined };\ntype KeyBuffer = { keys: string } | undefined;\ntype Direction = \"prev\" | \"next\" | \"first\" | \"last\";\ninterface MoveDetails {\n event: KeyboardEvent;\n list: HTMLElement;\n currentFocus: HTMLButtonElement;\n}\ninterface ListDetails {\n list: HTMLElement;\n search: KeyBuffer;\n searchResetTimer: TimerHandle;\n}\ninterface SearchDetails extends ListDetails {\n key: string;\n}\ninterface EventDetails extends ListDetails {\n event: KeyboardEvent;\n}\n/**\n * Enten `ref` eller `element` må gis. `ref` brukes når listen alltid\n * er i DOM-en; `element` foretrekkes når elementet mountes/unmountes\n * dynamisk (f.eks. portalert via floating-ui), slik at listeneren\n * re-festes når elementet faktisk er tilgjengelig.\n */\ntype UseListNavigationProps<T> =\n | {\n ref: RefObject<T | null>;\n element?: never;\n }\n | {\n ref?: never;\n element: T | null;\n };\n\nexport function useListNavigation<T extends HTMLElement>({\n ref,\n element,\n}: UseListNavigationProps<T>): void {\n // Bruker `useLayoutEffect` slik at keydown-listeneren er på plass før\n // browseren maler neste frame. Det er viktig for konsumenter som\n // flytter fokus inn i lista i en `requestAnimationFrame`-callback\n // (som Select), ellers kan første tastetrykk gå tapt.\n useLayoutEffect(() => {\n // `ref?.current` leses inne i effekten — refen er fylt i commit-\n // fasen, og var `null` i render-tid for callere som passerer\n // `ref` (som Combobox).\n const list = element ?? ref?.current ?? null;\n if (!list) return;\n\n // `TimerHandle` er et muterbart objekt slik at `resetWhenIdle`\n // kan oppdatere `id` på samme referanse — `setTimeout`-handlen må\n // være delt på tvers av tastetrykk for at `clearTimeout` skal\n // kunne avbryte forrige timeout.\n const searchResetTimer: TimerHandle = { id: undefined };\n const search: KeyBuffer = { keys: \"\" }; // keypress buffer is an object to preserve state\n const handler = (event: KeyboardEvent) => {\n handleListKeyNav({ list, event, search, searchResetTimer });\n };\n\n list.addEventListener(\"keydown\", handler);\n return () => {\n list.removeEventListener(\"keydown\", handler);\n if (searchResetTimer.id !== undefined) {\n clearTimeout(searchResetTimer.id);\n }\n };\n }, [element, ref]);\n}\n\nfunction handleMoveTo(\n direction: Direction,\n { event, list, currentFocus }: MoveDetails,\n) {\n event.preventDefault();\n moveFocusTo(direction, list, currentFocus);\n}\n\nfunction handleListKeyNav({\n list,\n event,\n search,\n searchResetTimer,\n}: EventDetails) {\n const { key, target } = event;\n const currentFocus = target as HTMLButtonElement;\n\n const moveDetails = {\n event,\n list,\n currentFocus,\n };\n\n switch (key) {\n case \"ArrowUp\":\n case \"PageUp\":\n handleMoveTo(\"prev\", moveDetails);\n break;\n case \"ArrowDown\":\n case \"PageDown\":\n handleMoveTo(\"next\", moveDetails);\n break;\n case \"Home\":\n handleMoveTo(\"first\", moveDetails);\n break;\n case \"End\":\n handleMoveTo(\"last\", moveDetails);\n break;\n case \"Tab\":\n // in a standard select, tab does nothing in-menu\n event.preventDefault();\n break;\n case \"Enter\":\n case \" \":\n break;\n\n default:\n if (search !== undefined) {\n const searchResult = findItem({\n list,\n key,\n search,\n searchResetTimer,\n });\n if (searchResult) {\n searchResult.focus();\n }\n }\n break;\n }\n}\n\nfunction moveFocusTo(\n direction: Direction,\n list: HTMLElement,\n current: HTMLButtonElement,\n) {\n const thisOption = current;\n switch (direction) {\n case \"prev\": {\n const prevOption: HTMLButtonElement | null =\n thisOption &&\n (thisOption.previousElementSibling as HTMLButtonElement);\n if (prevOption) {\n prevOption.focus();\n }\n break;\n }\n case \"next\": {\n const nextOption: HTMLButtonElement | null =\n thisOption &&\n (thisOption.nextElementSibling as HTMLButtonElement);\n if (nextOption) {\n nextOption.focus();\n }\n break;\n }\n case \"first\": {\n const firstItem =\n list.querySelector<HTMLButtonElement>(`[role=\"option\"]`);\n if (firstItem) {\n firstItem.focus();\n }\n break;\n }\n case \"last\": {\n const listItems =\n list.querySelectorAll<HTMLButtonElement>(`[role=\"option\"]`);\n if (listItems.length) {\n listItems[listItems.length - 1].focus();\n }\n break;\n }\n }\n}\n\nfunction findItem({\n list,\n key,\n search,\n searchResetTimer,\n}: SearchDetails): HTMLButtonElement | null {\n const listItems = list.querySelectorAll(`[role=\"option\"]`);\n if (!listItems.length) return null;\n\n if (search) {\n search.keys = search.keys.concat(key);\n resetWhenIdle(search, searchResetTimer);\n\n for (let n = 0; n < listItems.length; n++) {\n const label = (listItems[n] as HTMLButtonElement).innerText;\n if (label && label.toLowerCase().indexOf(search.keys) === 0) {\n return listItems[n] as HTMLButtonElement;\n }\n }\n }\n\n return null;\n}\n\nfunction resetWhenIdle(search: KeyBuffer, timer: TimerHandle) {\n if (timer.id !== undefined) {\n clearTimeout(timer.id);\n timer.id = undefined;\n }\n timer.id = window.setTimeout(() => {\n if (search) {\n search.keys = \"\";\n }\n timer.id = undefined;\n }, 500);\n}\n"],"names":["useListNavigation","ref","element","useLayoutEffect","list","current","searchResetTimer","id","search","keys","handler","event","key","target","moveDetails","currentFocus","handleMoveTo","preventDefault","searchResult","listItems","querySelectorAll","length","concat","timer","clearTimeout","window","setTimeout","resetWhenIdle","n","label","innerText","toLowerCase","indexOf","findItem","focus","handleListKeyNav","addEventListener","removeEventListener","direction","thisOption","prevOption","previousElementSibling","nextOption","nextElementSibling","firstItem","querySelector","moveFocusTo"],"mappings":"wCAqCO,SAASA,GACZC,IAAAA,EACAC,QAAAA,IAMAC,EAAgB,KAIZ,MAAMC,EAAOF,GAAWD,GAAKI,SAAW,KACxC,IAAKD,EAAM,OAMX,MAAME,EAAgC,CAAEC,QAAI,GACtCC,EAAoB,CAAEC,KAAM,IAC5BC,EAAWC,KAsBzB,UACIP,KAAAA,EACAO,MAAAA,EACAH,OAAAA,EACAF,iBAAAA,IAEA,MAAQM,IAAAA,EAAKC,OAAAA,GAAWF,EAGlBG,EAAc,CAChBH,MAAAA,EACAP,KAAAA,EACAW,aALiBF,GAQrB,OAAQD,GACJ,IAAK,UACL,IAAK,SACDI,EAAa,OAAQF,GACrB,MACJ,IAAK,YACL,IAAK,WACDE,EAAa,OAAQF,GACrB,MACJ,IAAK,OACDE,EAAa,QAASF,GACtB,MACJ,IAAK,MACDE,EAAa,OAAQF,GACrB,MACJ,IAAK,MAEDH,EAAMM,iBACN,MACJ,IAAK,QACL,IAAK,IACD,MAEJ,QACI,QAAe,IAAXT,EAAsB,CACtB,MAAMU,EA0DtB,UACId,KAAAA,EACAQ,IAAAA,EACAJ,OAAAA,EACAF,iBAAAA,IAEA,MAAMa,EAAYf,EAAKgB,iBAAiB,mBACxC,IAAKD,EAAUE,OAAQ,OAAO,KAE9B,GAAIb,EAAQ,CACRA,EAAOC,KAAOD,EAAOC,KAAKa,OAAOV,GAczC,SAAuBJ,EAAmBe,QACrB,IAAbA,EAAMhB,KACNiB,aAAaD,EAAMhB,IACnBgB,EAAMhB,QAAK,GAEfgB,EAAMhB,GAAKkB,OAAOC,WAAW,KACrBlB,IACAA,EAAOC,KAAO,IAElBc,EAAMhB,QAAK,GACZ,IACP,CAxBQoB,CAAcnB,EAAQF,GAEtB,IAAA,IAASsB,EAAI,EAAGA,EAAIT,EAAUE,OAAQO,IAAK,CACvC,MAAMC,EAASV,EAAUS,GAAyBE,UAClD,GAAID,GAAsD,IAA7CA,EAAME,cAAcC,QAAQxB,EAAOC,MAC5C,OAAOU,EAAUS,EAEzB,CACJ,CAEA,OAAO,IACX,CAhFqCK,CAAS,CAC1B7B,KAAAA,EACAQ,IAAAA,EACAJ,OAAAA,EACAF,iBAAAA,IAEAY,GACAA,EAAagB,OAErB,EAGZ,CAzEYC,CAAiB,CAAE/B,KAAAA,EAAMO,MAAAA,EAAOH,OAAAA,EAAQF,iBAAAA,KAG5C,OAAAF,EAAKgC,iBAAiB,UAAW1B,GAC1B,KACHN,EAAKiC,oBAAoB,UAAW3B,QACR,IAAxBJ,EAAiBC,IACjBiB,aAAalB,EAAiBC,MAGvC,CAACL,EAASD,GACjB,CAEA,SAASe,EACLsB,GACE3B,MAAAA,EAAOP,KAAAA,EAAMW,aAAAA,IAEfJ,EAAMM,iBA0DV,SACIqB,EACAlC,EACAC,GAEA,MAAMkC,EAAalC,EACnB,OAAQiC,GACJ,IAAK,OAAQ,CACT,MAAME,EACFD,GACCA,EAAWE,uBACZD,GACAA,EAAWN,QAEf,KACJ,CACA,IAAK,OAAQ,CACT,MAAMQ,EACFH,GACCA,EAAWI,mBACZD,GACAA,EAAWR,QAEf,KACJ,CACA,IAAK,QAAS,CACV,MAAMU,EACFxC,EAAKyC,cAAiC,mBACtCD,GACAA,EAAUV,QAEd,KACJ,CACA,IAAK,OAAQ,CACT,MAAMf,EACFf,EAAKgB,iBAAoC,mBACzCD,EAAUE,QACVF,EAAUA,EAAUE,OAAS,GAAGa,QAEpC,KACJ,EAER,CAnGIY,CAAYR,EAAWlC,EAAMW,EACjC"}
1
+ {"version":3,"file":"useListNavigation.js","sources":["../../../../src/hooks/useListNavigation/useListNavigation.ts"],"sourcesContent":["import { type RefObject, useCallback, useEffect, useRef } from \"react\";\n\n/**\n * Enten `ref` eller `element` må gis. `ref` brukes når listen alltid\n * er i DOM-en; `element` foretrekkes når elementet mountes/unmountes\n * dynamisk (f.eks. portalert via floating-ui), slik at listeneren\n * re-festes når elementet faktisk er tilgjengelig.\n */\ntype UseListNavigationProps<T> = {\n disableTypeahead?: boolean;\n} & (\n | {\n ref: RefObject<T | null>;\n element?: never;\n }\n | {\n ref?: never;\n element: T | null;\n }\n);\n\nconst TYPEAHEAD_SEARCH_TIMEOUT = 500;\nconst MODIFIERS = [\"Control\", \"Alt\", \"Shift\", \"Meta\"];\nconst LIST_ITEM_SELECTOR =\n \"[role='option'][class~='jkl-select__option'],[class~='jkl-combobox__option'],[class~='jkl-option'],[class~='jkl-search']\";\n\nexport function useListNavigation<T extends HTMLElement>({\n ref,\n element,\n disableTypeahead = false,\n}: UseListNavigationProps<T>): void {\n const searchResetTimer = useRef<ReturnType<typeof setTimeout> | undefined>(\n undefined,\n );\n const searchTerm = useRef<string>(\"\");\n\n const typeahead = useCallback(\n (key: string): void => {\n if (disableTypeahead || MODIFIERS.includes(key)) return;\n const list = element ?? ref?.current ?? null;\n\n searchTerm.current = searchTerm.current.concat(key);\n clearTimeout(searchResetTimer.current);\n searchResetTimer.current = setTimeout(() => {\n searchTerm.current = \"\";\n searchResetTimer.current = undefined;\n }, TYPEAHEAD_SEARCH_TIMEOUT);\n\n if (!searchTerm.current.length) return;\n\n const listItems =\n list?.querySelectorAll<HTMLElement>(LIST_ITEM_SELECTOR);\n if (!listItems || !listItems.length) return;\n\n for (const item of listItems) {\n if (\n item.innerText\n ?.toLowerCase()\n .indexOf(searchTerm.current.toLowerCase()) === 0\n ) {\n focusButtonOrInput(item);\n return;\n }\n }\n },\n [element, ref, disableTypeahead],\n );\n\n const handleKeyNavigation = useCallback(\n (event: KeyboardEvent): void => {\n const list = element ?? ref?.current ?? null;\n if (!list) return;\n\n const { key, target } = event;\n const current = target as HTMLElement;\n const allItems = Array.from(\n list.querySelectorAll<HTMLElement>(LIST_ITEM_SELECTOR),\n );\n\n switch (key) {\n case \"ArrowUp\": {\n event.preventDefault();\n const index = allItems.indexOf(\n current.closest(LIST_ITEM_SELECTOR) as HTMLElement,\n );\n focusButtonOrInput(allItems[index - 1]);\n break;\n }\n case \"ArrowDown\": {\n event.preventDefault();\n const index = allItems.indexOf(\n current.closest(LIST_ITEM_SELECTOR) as HTMLElement,\n );\n focusButtonOrInput(allItems[index + 1]);\n break;\n }\n case \"PageUp\":\n case \"Home\": {\n event.preventDefault();\n focusButtonOrInput(allItems[0]);\n break;\n }\n case \"PageDown\":\n case \"End\": {\n event.preventDefault();\n focusButtonOrInput(allItems[allItems.length - 1]);\n break;\n }\n // Vi gjør ingenting for modifiers eller mellomrom\n case \"Shift\":\n case \"Control\":\n case \"Alt\":\n case \"Meta\":\n case \"Enter\":\n case \"Escape\":\n case \" \":\n break;\n\n case \"Tab\":\n event.preventDefault();\n break;\n\n // Alle andre taster trigger typeahead\n default:\n typeahead(key);\n break;\n }\n },\n [element, ref, typeahead],\n );\n\n useEffect(() => {\n const list = element ?? ref?.current ?? null;\n if (!list) return;\n\n list.addEventListener(\"keydown\", handleKeyNavigation);\n\n return () => {\n list.removeEventListener(\"keydown\", handleKeyNavigation);\n clearTimeout(searchResetTimer.current);\n };\n }, [element, ref, handleKeyNavigation]);\n}\n\nfunction focusButtonOrInput(element?: Element | null): void {\n if (!element) return;\n\n if (element.nodeName === \"BUTTON\" || element.nodeName === \"INPUT\") {\n (element as HTMLElement).focus();\n } else {\n element\n .querySelector<HTMLInputElement | HTMLButtonElement>(\"input,button\")\n ?.focus();\n }\n}\n"],"names":["MODIFIERS","LIST_ITEM_SELECTOR","useListNavigation","ref","element","disableTypeahead","searchResetTimer","useRef","searchTerm","typeahead","useCallback","key","includes","list","current","concat","clearTimeout","setTimeout","length","listItems","querySelectorAll","item","innerText","toLowerCase","indexOf","focusButtonOrInput","handleKeyNavigation","event","target","allItems","Array","from","preventDefault","index","closest","useEffect","addEventListener","removeEventListener","nodeName","focus","querySelector"],"mappings":"+DAqBA,MACMA,EAAY,CAAC,UAAW,MAAO,QAAS,QACxCC,EACF,2HAEG,SAASC,GACZC,IAAAA,EACAC,QAAAA,EACAC,iBAAAA,GAAmB,IAEnB,MAAMC,EAAmBC,OACrB,GAEEC,EAAaD,EAAe,IAE5BE,EAAYC,EACbC,IACG,GAAIN,GAAoBL,EAAUY,SAASD,GAAM,OACjD,MAAME,EAAOT,GAAWD,GAAKW,SAAW,KASxC,GAPAN,EAAWM,QAAUN,EAAWM,QAAQC,OAAOJ,GAC/CK,aAAaV,EAAiBQ,SAC9BR,EAAiBQ,QAAUG,WAAW,KAClCT,EAAWM,QAAU,GACrBR,EAAiBQ,aAAU,GAxBV,MA2BhBN,EAAWM,QAAQI,OAAQ,OAEhC,MAAMC,EACFN,GAAMO,iBAA8BnB,GACxC,GAAKkB,GAAcA,EAAUD,OAE7B,IAAA,MAAWG,KAAQF,EACf,GAGuD,IAFnDE,EAAKC,WACCC,cACDC,QAAQhB,EAAWM,QAAQS,eAGhC,YADAE,EAAmBJ,IAK/B,CAACjB,EAASD,EAAKE,IAGbqB,EAAsBhB,EACvBiB,IACG,MAAMd,EAAOT,GAAWD,GAAKW,SAAW,KACxC,IAAKD,EAAM,OAEX,MAAQF,IAAAA,EAAKiB,OAAAA,GAAWD,EAClBb,EAAUc,EACVC,EAAWC,MAAMC,KACnBlB,EAAKO,iBAA8BnB,IAGvC,OAAQU,GACJ,IAAK,UAAW,CACZgB,EAAMK,iBACN,MAAMC,EAAQJ,EAASL,QACnBV,EAAQoB,QAAQjC,IAEpBwB,EAAmBI,EAASI,EAAQ,IACpC,KACJ,CACA,IAAK,YAAa,CACdN,EAAMK,iBACN,MAAMC,EAAQJ,EAASL,QACnBV,EAAQoB,QAAQjC,IAEpBwB,EAAmBI,EAASI,EAAQ,IACpC,KACJ,CACA,IAAK,SACL,IAAK,OACDN,EAAMK,iBACNP,EAAmBI,EAAS,IAC5B,MAEJ,IAAK,WACL,IAAK,MACDF,EAAMK,iBACNP,EAAmBI,EAASA,EAASX,OAAS,IAC9C,MAGJ,IAAK,QACL,IAAK,UACL,IAAK,MACL,IAAK,OACL,IAAK,QACL,IAAK,SACL,IAAK,IACD,MAEJ,IAAK,MACDS,EAAMK,iBACN,MAGJ,QACIvB,EAAUE,KAItB,CAACP,EAASD,EAAKM,IAGnB0B,EAAU,KACN,MAAMtB,EAAOT,GAAWD,GAAKW,SAAW,KACxC,GAAKD,EAEL,OAAAA,EAAKuB,iBAAiB,UAAWV,GAE1B,KACHb,EAAKwB,oBAAoB,UAAWX,GACpCV,aAAaV,EAAiBQ,WAEnC,CAACV,EAASD,EAAKuB,GACtB,CAEA,SAASD,EAAmBrB,GACnBA,IAEoB,WAArBA,EAAQkC,UAA8C,UAArBlC,EAAQkC,SACxClC,EAAwBmC,QAEzBnC,EACKoC,cAAoD,iBACnDD,QAEd"}
@@ -1,6 +1,8 @@
1
+ import { ReactNode } from 'react';
1
2
  export type ValuePair = {
2
3
  value: string;
3
4
  label: string;
4
5
  description?: string;
6
+ media?: ReactNode;
5
7
  };
6
8
  export declare function getValuePair(item: string | ValuePair): ValuePair;
@@ -1 +1 @@
1
- {"version":3,"file":"valuePair.js","sources":["../../../src/utilities/valuePair.ts"],"sourcesContent":["export type ValuePair = {\n value: string;\n label: string;\n description?: string;\n};\n\nexport function getValuePair(item: string | ValuePair): ValuePair {\n return typeof item === \"string\" ? { value: item, label: item } : item;\n}\n"],"names":["getValuePair","item","value","label"],"mappings":"AAMO,SAASA,EAAaC,GACzB,MAAuB,iBAATA,EAAoB,CAAEC,MAAOD,EAAME,MAAOF,GAASA,CACrE"}
1
+ {"version":3,"file":"valuePair.js","sources":["../../../src/utilities/valuePair.ts"],"sourcesContent":["import type { ReactNode } from \"react\";\n\nexport type ValuePair = {\n value: string;\n label: string;\n description?: string;\n media?: ReactNode;\n};\n\nexport function getValuePair(item: string | ValuePair): ValuePair {\n return typeof item === \"string\" ? { value: item, label: item } : item;\n}\n"],"names":["getValuePair","item","value","label"],"mappings":"AASO,SAASA,EAAaC,GACzB,MAAuB,iBAATA,EAAoB,CAAEC,MAAOD,EAAME,MAAOF,GAASA,CACrE"}
@@ -118,6 +118,41 @@ Tilsvarende omdøping for alle Tailwind v4-fargeklasser generert fra `--color-*`
118
118
 
119
119
  Tailwind-modifikatorer (`hover:`, `dark:`, `md:`, `focus:` o.l.), opacity-modifikatorer (`/50`) og viktig-prefiks (`!`) håndteres korrekt.
120
120
 
121
+ #### DateInput (Jøkul 6)
122
+
123
+ Import path, stilimporter og komponentnavn omdøpes automatisk:
124
+
125
+ | Gammel import | Ny import |
126
+ |---|---|
127
+ | `@fremtind/jokul/datepicker` | `@fremtind/jokul/date-input` |
128
+ | `@fremtind/jokul/date-inputs` | `@fremtind/jokul/date-input` |
129
+ | `@fremtind/jokul/date-picker` | `@fremtind/jokul/date-input` |
130
+
131
+ Stilmappa følger komponentmappa, så både mappe- og filnavn skrives om. Gjelder både `import "..."` og Sass `@use`/`@forward`:
132
+
133
+ | Gammel stilimport | Ny stilimport |
134
+ |---|---|
135
+ | `@fremtind/jokul/styles/components/datepicker` | `@fremtind/jokul/styles/components/date-input` |
136
+ | `@fremtind/jokul/styles/components/datepicker/_index.scss` | `@fremtind/jokul/styles/components/date-input/_index.scss` |
137
+ | `@fremtind/jokul/styles/components/datepicker/datepicker.scss` | `@fremtind/jokul/styles/components/date-input/date-input.scss` |
138
+ | `@fremtind/jokul/styles/components/datepicker/datepicker.css` | `@fremtind/jokul/styles/components/date-input/date-input.css` |
139
+ | `@fremtind/jokul/styles/components/datepicker/datepicker.min.css` | `@fremtind/jokul/styles/components/date-input/date-input.min.css` |
140
+
141
+ De samme variantene håndteres for de eldre mappenavnene `date-picker` og `date-inputs`.
142
+
143
+ | Gammel komponent | Ny komponent |
144
+ |---|---|
145
+ | `DatePicker` | `DateInput` |
146
+
147
+ Prop-navnene som begrenser datovalg omdøpes automatisk:
148
+
149
+ | Gammel prop | Ny prop |
150
+ |---|---|
151
+ | `disableBeforeDate` | `min` |
152
+ | `disableAfterDate` | `max` |
153
+
154
+ Fjernede props endres ikke automatisk, men gir varsel når de finnes i en fil som bruker `DateInput`/`DatePicker`: `defaultShow`, `initialShow`, `extended`, `invalid`, `yearsToShow`, `days`, `months`, `monthLabel`, `yearLabel`, `action`, `showCalendarLabel`, `hideCalendarLabel` og `textInputProps`. Se [MIGRATION.md](../MIGRATION.md#fjernede-props-og-hjelpefunksjoner) for erstatninger.
155
+
121
156
  ---
122
157
 
123
158
  #### Fjernede maskefunksjoner
@@ -147,3 +182,7 @@ Disse mønstrene kan ikke omdøpes automatisk. Codemoden skriver ut ett varsel p
147
182
  | `variant="outlined\|high\|low"` (på `Card`) | `variant`-prop er fjernet. Bruk `outlined` (boolean) for ramme, fjern `high`/`low`. |
148
183
  | `bg-background-interactive` o.l. (Tailwind) | Fjernede Tailwind-klasser basert på `background-interactive`/`text-interactive`. |
149
184
  | `border-border-separator` o.l. (Tailwind) | Fjernede Tailwind-kantklasser. Bruk `border-border-default`, `-subdued` eller `-strong`. |
185
+ | `<DateInput>` | Datoverdier bruker nå ISO-format (`yyyy-mm-dd`), ikke `dd.mm.yyyy`. |
186
+ | `<DateInput>` `onChange` | Gir nå et standard React change-event. Les datoen fra `event.target.value`. |
187
+ | `defaultShow` | Fjernet fra DateInput. Kalenderen åpnes via kalenderknappen. |
188
+ | `extended`, `invalid`, `yearsToShow`, `days`, `months`, `monthLabel`, `yearLabel`, `action`, `showCalendarLabel`, `hideCalendarLabel`, `textInputProps` | Fjernet fra DateInput. Se migrasjonsguiden for erstatninger. |