@fremtind/jokul 5.0.4 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/build/build-stats.html +1 -1
  2. package/build/cjs/components/combobox/Combobox.cjs +1 -1
  3. package/build/cjs/components/combobox/Combobox.cjs.map +1 -1
  4. package/build/cjs/components/expander/types.d.cts +1 -1
  5. package/build/cjs/components/help/Help.cjs +1 -1
  6. package/build/cjs/components/help/Help.cjs.map +1 -1
  7. package/build/cjs/components/icon/icons/ErrorIcon.cjs +1 -1
  8. package/build/cjs/components/icon/icons/ErrorIcon.cjs.map +1 -1
  9. package/build/cjs/components/menu/Menu.cjs +1 -1
  10. package/build/cjs/components/menu/Menu.cjs.map +1 -1
  11. package/build/cjs/components/popover/Popover.cjs +1 -1
  12. package/build/cjs/components/popover/Popover.cjs.map +1 -1
  13. package/build/cjs/components/popover/types.d.cts +10 -0
  14. package/build/cjs/components/radio-button/RadioButton.cjs.map +1 -1
  15. package/build/cjs/components/select/Select.cjs +1 -1
  16. package/build/cjs/components/select/Select.cjs.map +1 -1
  17. package/build/cjs/components/system-message/SystemMessage.cjs +1 -1
  18. package/build/cjs/components/system-message/SystemMessage.cjs.map +1 -1
  19. package/build/cjs/components/typography/Text.cjs +1 -1
  20. package/build/cjs/components/typography/Text.cjs.map +1 -1
  21. package/build/cjs/components/typography/Title.cjs +1 -1
  22. package/build/cjs/components/typography/Title.cjs.map +1 -1
  23. package/build/cjs/components/typography/types.d.cts +17 -0
  24. package/build/cjs/tokens.cjs +1 -1
  25. package/build/cjs/tokens.cjs.map +1 -1
  26. package/build/cjs/tokens.d.cts +1 -0
  27. package/build/es/components/combobox/Combobox.js +1 -1
  28. package/build/es/components/combobox/Combobox.js.map +1 -1
  29. package/build/es/components/expander/types.d.ts +1 -1
  30. package/build/es/components/help/Help.js +1 -1
  31. package/build/es/components/help/Help.js.map +1 -1
  32. package/build/es/components/icon/icons/ErrorIcon.js +1 -1
  33. package/build/es/components/icon/icons/ErrorIcon.js.map +1 -1
  34. package/build/es/components/menu/Menu.js +1 -1
  35. package/build/es/components/menu/Menu.js.map +1 -1
  36. package/build/es/components/popover/Popover.js +1 -1
  37. package/build/es/components/popover/Popover.js.map +1 -1
  38. package/build/es/components/popover/types.d.ts +10 -0
  39. package/build/es/components/radio-button/RadioButton.js.map +1 -1
  40. package/build/es/components/select/Select.js +1 -1
  41. package/build/es/components/select/Select.js.map +1 -1
  42. package/build/es/components/system-message/SystemMessage.js +1 -1
  43. package/build/es/components/system-message/SystemMessage.js.map +1 -1
  44. package/build/es/components/typography/Text.js +1 -1
  45. package/build/es/components/typography/Text.js.map +1 -1
  46. package/build/es/components/typography/Title.js +1 -1
  47. package/build/es/components/typography/Title.js.map +1 -1
  48. package/build/es/components/typography/types.d.ts +17 -0
  49. package/build/es/tokens.d.ts +1 -0
  50. package/build/es/tokens.js +1 -1
  51. package/build/es/tokens.js.map +1 -1
  52. package/package.json +4 -2
  53. package/src/tokens/metadata/color.metadata.dark.json +165 -0
  54. package/src/tokens/metadata/color.metadata.light.json +165 -0
  55. package/src/tokens/metadata/color.metadata.saturated.dark.json +165 -0
  56. package/src/tokens/metadata/color.metadata.saturated.light.json +165 -0
  57. package/styles/base.css +2 -8
  58. package/styles/base.min.css +1 -1
  59. package/styles/components/beta/nav-link/navlink.css +2 -1
  60. package/styles/components/beta/nav-link/navlink.min.css +1 -1
  61. package/styles/components/checkbox/checkbox.css +9 -5
  62. package/styles/components/checkbox/checkbox.min.css +1 -1
  63. package/styles/components/checkbox/checkbox.scss +7 -4
  64. package/styles/components/checkbox-panel/checkbox-panel.css +27 -5
  65. package/styles/components/checkbox-panel/checkbox-panel.min.css +1 -1
  66. package/styles/components/combobox/combobox.css +4 -7
  67. package/styles/components/combobox/combobox.min.css +1 -1
  68. package/styles/components/combobox/combobox.scss +11 -10
  69. package/styles/components/countdown/countdown.css +2 -2
  70. package/styles/components/countdown/countdown.min.css +1 -1
  71. package/styles/components/feedback/feedback.css +2 -2
  72. package/styles/components/feedback/feedback.min.css +1 -1
  73. package/styles/components/file-input/file-input.css +13 -13
  74. package/styles/components/file-input/file-input.min.css +1 -1
  75. package/styles/components/help/help.css +2 -2
  76. package/styles/components/help/help.min.css +1 -1
  77. package/styles/components/help/help.scss +2 -2
  78. package/styles/components/icon/_base-styles.scss +2 -2
  79. package/styles/components/icon/icon.css +2 -1
  80. package/styles/components/icon/icon.min.css +1 -1
  81. package/styles/components/input-group/_labels.scss +22 -4
  82. package/styles/components/input-group/input-group.css +15 -3
  83. package/styles/components/input-group/input-group.min.css +1 -1
  84. package/styles/components/input-panel/input-panel.css +18 -0
  85. package/styles/components/input-panel/input-panel.min.css +1 -1
  86. package/styles/components/input-panel/input-panel.scss +24 -1
  87. package/styles/components/link/link.css +4 -4
  88. package/styles/components/link/link.min.css +1 -1
  89. package/styles/components/link/link.scss +2 -3
  90. package/styles/components/link-list/link-list.css +2 -1
  91. package/styles/components/link-list/link-list.min.css +1 -1
  92. package/styles/components/list/list.css +2 -1
  93. package/styles/components/list/list.min.css +1 -1
  94. package/styles/components/loader/loader.css +6 -6
  95. package/styles/components/loader/loader.min.css +1 -1
  96. package/styles/components/loader/skeleton-loader.css +3 -3
  97. package/styles/components/loader/skeleton-loader.min.css +1 -1
  98. package/styles/components/menu/_menu-item.scss +1 -1
  99. package/styles/components/menu/menu.css +3 -2
  100. package/styles/components/menu/menu.min.css +1 -1
  101. package/styles/components/menu/menu.scss +2 -1
  102. package/styles/components/message/message.css +2 -2
  103. package/styles/components/message/message.min.css +1 -1
  104. package/styles/components/number-input/number-input.css +2 -2
  105. package/styles/components/number-input/number-input.min.css +1 -1
  106. package/styles/components/progress-bar/progress-bar.css +1 -1
  107. package/styles/components/progress-bar/progress-bar.min.css +1 -1
  108. package/styles/components/radio-button/radio-button.css +8 -3
  109. package/styles/components/radio-button/radio-button.min.css +1 -1
  110. package/styles/components/radio-button/radio-button.scss +7 -3
  111. package/styles/components/radio-panel/radio-panel.css +18 -0
  112. package/styles/components/radio-panel/radio-panel.min.css +1 -1
  113. package/styles/components/search/search.css +3 -2
  114. package/styles/components/search/search.min.css +1 -1
  115. package/styles/components/segmented-control/segmented-control.css +26 -7
  116. package/styles/components/segmented-control/segmented-control.min.css +1 -1
  117. package/styles/components/select/select.css +4 -11
  118. package/styles/components/select/select.min.css +1 -1
  119. package/styles/components/select/select.scss +19 -19
  120. package/styles/components/system-message/system-message.css +2 -2
  121. package/styles/components/system-message/system-message.min.css +1 -1
  122. package/styles/components/text-area/text-area.css +2 -2
  123. package/styles/components/text-area/text-area.min.css +1 -1
  124. package/styles/components/text-input/text-input.css +2 -2
  125. package/styles/components/text-input/text-input.min.css +1 -1
  126. package/styles/components/toast/toast.css +4 -4
  127. package/styles/components/toast/toast.min.css +1 -1
  128. package/styles/components/toggle-switch/toggle-switch.css +3 -0
  129. package/styles/components/toggle-switch/toggle-switch.min.css +1 -1
  130. package/styles/components/toggle-switch/toggle-switch.scss +3 -0
  131. package/styles/components/tooltip/tooltip.css +1 -0
  132. package/styles/components/tooltip/tooltip.min.css +1 -1
  133. package/styles/components/tooltip/tooltip.scss +1 -0
  134. package/styles/components/typography/text.css +6 -0
  135. package/styles/components/typography/text.min.css +1 -1
  136. package/styles/components/typography/text.scss +9 -1
  137. package/styles/components/typography/title.css +3 -0
  138. package/styles/components/typography/title.min.css +1 -1
  139. package/styles/components/typography/title.scss +5 -1
  140. package/styles/components.css +119 -71
  141. package/styles/components.min.css +1 -1
  142. package/styles/jkl/_tokens.scss +3 -1
  143. package/styles/jkl/_typography.scss +1 -3
  144. package/styles/shared/input/shared-input-styles.scss +5 -3
  145. package/styles/theme/_fonts.scss +1 -9
  146. package/styles/theme/_tokens.scss +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Combobox.js","sources":["../../../../src/components/combobox/Combobox.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React, {\n type FC,\n type FocusEvent,\n type KeyboardEvent,\n type MouseEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { useAnimatedHeight } from \"../../hooks/useAnimatedHeight/useAnimatedHeight.js\";\nimport { useId } from \"../../hooks/useId/useId.js\";\nimport { useListNavigation } from \"../../hooks/useListNavigation/useListNavigation.js\";\nimport type { ValuePair } from \"../../utilities/valuePair.js\";\nimport { Chip } from \"../chip/Chip.js\";\nimport { IconButton } from \"../icon-button/IconButton.js\";\nimport { CheckIcon } from \"../icon/icons/CheckIcon.js\";\nimport { ArrowVerticalAnimated } from \"../icon/icons/animated/ArrowVerticalAnimated.js\";\nimport { InputGroup } from \"../input-group/InputGroup.js\";\nimport { Tooltip } from \"../tooltip/Tooltip.js\";\nimport { TooltipContent } from \"../tooltip/TooltipContent.js\";\nimport { TooltipTrigger } from \"../tooltip/TooltipTrigger.js\";\nimport type { ComboboxProps, ComboboxValuePair } from \"./types.js\";\n\nexport function getComboboxValuePair(\n item: string | ComboboxValuePair,\n): ComboboxValuePair {\n return typeof item === \"string\" ? { value: item, label: item } : item;\n}\n\nexport const Combobox: FC<ComboboxProps> = (props) => {\n const {\n \"data-size\": dataSize,\n id,\n placeholder,\n items,\n onChange,\n onFocus,\n onBlur,\n value,\n label,\n noMatchingOption,\n labelProps,\n helpLabel,\n errorLabel,\n width,\n name,\n className,\n invalid,\n description,\n hasTagHover,\n } = props;\n const listId = useId(id || \"jkl-combobox\", { generateSuffix: !id });\n const labelId = `${listId}_label`;\n const buttonId = `${listId}_button`;\n const inputId = `${listId}_search-input`;\n\n const [selectedValue, setSelectedValue] = useState<\n Array<ComboboxValuePair>\n >(value || []);\n const [showMenu, setShowMenu] = useState<boolean>(false);\n const [searchValue, setSearchValue] = useState<string>(\"\");\n const [noResults, setNoResults] = useState(false);\n const [marked, setMarked] = useState<boolean>(false);\n\n const searchRef = useRef<HTMLInputElement>(null);\n const inputRef = useRef<HTMLDivElement>(null);\n const focusInsideRef = useRef(false);\n\n useEffect(() => {\n setSearchValue(\"\");\n if (showMenu && searchRef.current) {\n searchRef.current.focus();\n }\n }, [showMenu]);\n\n useEffect(() => {\n setSelectedValue((prev) => value || prev);\n }, [value]);\n\n // Funksjon for å stile valgt element\n const isSelected = (option: ValuePair) => {\n if (!selectedValue) {\n return false;\n }\n\n return selectedValue.some((value) => value.value === option.value);\n };\n\n // Fjerne ett eller flere valg\n const removeOption = useCallback(\n (option: string) => {\n return selectedValue.filter((value) => value.value !== option);\n },\n [selectedValue],\n );\n\n const onTagRemove = useCallback(\n (\n e:\n | React.MouseEvent<HTMLButtonElement, globalThis.MouseEvent>\n | React.KeyboardEvent<HTMLInputElement>,\n option: string,\n ) => {\n const newValue = removeOption(option);\n setSelectedValue(newValue);\n onChange({\n type: \"change\",\n target: { name, value: option, selectedOptions: newValue },\n });\n e.stopPropagation();\n\n if (newValue.length === 0) {\n setMarked(false);\n }\n },\n [removeOption, onChange, name],\n );\n\n // Håndtere valgt verdi i listen\n const onItemClick = useCallback(\n (option: string) => {\n let newValue: Array<ValuePair>;\n\n if (selectedValue.some((value) => value.value === option)) {\n newValue = removeOption(option);\n } else {\n const item = items.find((i) => i.value === option);\n newValue = [...selectedValue, item as ValuePair];\n }\n searchRef.current?.focus();\n setSelectedValue(newValue);\n onChange({\n type: \"change\",\n target: { name, value: option, selectedOptions: newValue },\n });\n },\n [selectedValue, onChange, name, removeOption, items],\n );\n\n // Funksjon for søk\n const onSearch = (e: {\n target: { value: React.SetStateAction<string> };\n }) => {\n searchRef.current?.focus();\n setShowMenu(true);\n setSearchValue(e.target.value);\n };\n\n const options = useMemo(() => {\n if (!searchValue) {\n return items;\n }\n\n const filteredOptions = items.filter(\n (option) =>\n option.label.toLowerCase().indexOf(searchValue.toLowerCase()) >=\n 0,\n );\n\n setNoResults(filteredOptions.length === 0);\n\n return filteredOptions;\n }, [searchValue, items]);\n\n // Det første elementet i listen skal være aktivt fram til brukeren klikker på noe annet\n const [activeDescendant, setActiveDescendant] = useState<\n string | undefined\n >(options[0]?.value ? `${listId}-${options[0]?.value}` : undefined);\n\n // Håndtere arrow-state\n const isPointingDown = !showMenu;\n\n // Lukk meny med ESC\n useEffect(() => {\n const handleEscape = (e: globalThis.KeyboardEvent) => {\n if (e.key === \"Escape\" && showMenu) {\n setShowMenu(false);\n }\n };\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"keydown\", handleEscape);\n }\n return () => {\n if (typeof window !== \"undefined\" && showMenu) {\n window.removeEventListener(\"keydown\", handleEscape);\n }\n };\n }, [showMenu]);\n\n // Fokushåndtering\n const handleFocusPlacement = useCallback((isOpen: boolean) => {\n if (isOpen) {\n if (searchRef.current) {\n searchRef.current.focus();\n }\n } else {\n if (focusInsideRef.current && inputRef.current) {\n inputRef.current.focus();\n }\n }\n }, []);\n\n const handleFocus = useCallback(() => {\n if (!focusInsideRef.current) {\n if (onFocus) {\n onFocus({\n type: \"change\",\n target: {\n name,\n value: selectedValue?.[0].value || \"\",\n selectedOptions: selectedValue,\n },\n });\n }\n focusInsideRef.current = true;\n setShowMenu(true);\n }\n }, [onFocus, selectedValue, name]);\n\n const [dropdownRef] = useAnimatedHeight<HTMLDivElement>(showMenu, {\n onFirstVisible: handleFocusPlacement,\n onTransitionEnd: handleFocusPlacement,\n });\n\n useListNavigation({ ref: dropdownRef });\n\n const componentRootElementRef = useRef<HTMLDivElement>(null);\n\n const handleBlur = useCallback(\n (\n e: FocusEvent<\n HTMLDivElement | HTMLInputElement | HTMLButtonElement\n >,\n ) => {\n const componentRootElement = componentRootElementRef.current;\n const nextFocusIsInsideComponent = componentRootElement?.contains(\n e.relatedTarget as Node,\n );\n if (!nextFocusIsInsideComponent) {\n setSearchValue(\"\");\n\n if (onBlur) {\n onBlur({\n type: \"blur\",\n target: {\n name,\n value: selectedValue?.[0]?.value || \"\",\n selectedOptions: selectedValue,\n },\n });\n inputRef.current?.dispatchEvent(\n new Event(\"focusout\", { bubbles: true }),\n );\n }\n focusInsideRef.current = false;\n setShowMenu(false);\n }\n },\n [onBlur, name, selectedValue],\n );\n\n const handleMouseOver = useCallback((e: MouseEvent<HTMLButtonElement>) => {\n // Ved mouseOver på options flytter vi fokus til dem for å unngå \"dobbel fokus\"\n // der det ser ut som to forskjellige elementer er fokusert/hovered samtidig\n (e.target as HTMLButtonElement).focus({ preventScroll: true });\n }, []);\n\n // Tastaturnavigasjon\n const handleSearchOnKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n e.stopPropagation();\n const listElement = dropdownRef.current;\n if (listElement) {\n listElement\n .querySelector<HTMLButtonElement>('[role=\"option\"]')\n ?.focus();\n }\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n e.stopPropagation();\n setShowMenu(false);\n }\n\n if ((e.metaKey && e.key === \"a\") || (e.ctrlKey && e.key === \"a\")) {\n e.preventDefault();\n e.stopPropagation();\n const updatedSelectedValue = selectedValue.map((item) => ({\n ...item,\n isMarked: true,\n }));\n setMarked(true);\n setSelectedValue(updatedSelectedValue);\n } else if (e.key === \"Backspace\") {\n e.stopPropagation();\n setMarked(false);\n\n // Sjekk om selectedValue er markert\n const selectedValueIsMarked = selectedValue.some(\n (item) => item.isMarked,\n );\n\n if (selectedValueIsMarked) {\n const updatedSelectedValue = selectedValue.filter(\n (item) => !item.isMarked,\n );\n setSelectedValue(updatedSelectedValue);\n setSearchValue(\"\");\n } else if (selectedValue.length > 0 && searchValue === \"\") {\n // Hvis ingen items er markert, fjern siste valgte item\n onTagRemove(\n e,\n selectedValue[selectedValue.length - 1].value,\n );\n }\n }\n },\n [selectedValue, searchValue, dropdownRef, onTagRemove],\n );\n\n const handleOptionOnKeyDown = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === \"Tab\") {\n if (searchRef.current) {\n e.preventDefault();\n e.stopPropagation();\n\n if (e.shiftKey) {\n searchRef.current.focus();\n } else {\n setShowMenu(false);\n searchRef.current.focus();\n }\n }\n } else if (e.key === \"ArrowUp\") {\n if (dropdownRef.current && searchRef.current) {\n // Can't be based on index since the first item might be filtered out\n const firstVisible = dropdownRef.current.querySelector(\n '[role=\"option\"]:not([hidden])',\n );\n if (\n e.currentTarget.id === firstVisible?.id &&\n searchRef.current\n ) {\n searchRef.current.focus();\n }\n }\n }\n },\n [dropdownRef],\n );\n\n const hasSelection = selectedValue.length >= 1;\n\n const renderSelectedOption = useCallback(\n (option: ComboboxValuePair) => (\n <Chip\n key={option.value}\n data-testid=\"jkl-chip\"\n aria-label={`Fjern ${option.tagLabel}`}\n className={`jkl-combobox__selected-option ${\n marked && \"jkl-combobox__selected-option--marked\"\n }`}\n variant=\"input\"\n onClick={(e) => {\n if (searchRef.current) {\n searchRef.current.focus();\n }\n onTagRemove(e, option.value);\n }}\n onBlur={handleBlur}\n >\n {option.tagLabel ? option.tagLabel : option.label}\n </Chip>\n ),\n [handleBlur, onTagRemove, marked],\n );\n\n return (\n <InputGroup\n label={label}\n id={inputId}\n ref={componentRootElementRef}\n data-testid=\"jkl-combobox\"\n data-size={dataSize}\n className={clsx(\"jkl-combobox\", className, {\n \"jkl-combobox--invalid\": !!errorLabel || invalid,\n \"jkl-combobox--menu-open\": showMenu,\n \"jkl-combobox--menu-closed\": !showMenu && hasSelection,\n })}\n labelProps={{\n id: labelId,\n ...labelProps,\n }}\n helpLabel={helpLabel}\n errorLabel={errorLabel}\n description={description}\n render={(inputProps) => (\n <div\n className={clsx(\"jkl-combobox__wrapper\", {\n \"jkl-combobox__wrapper--active-value\": hasSelection,\n })}\n style={{ width }}\n tabIndex={-1}\n onFocus={handleFocus}\n onBlur={handleBlur}\n >\n <div\n className=\"jkl-combobox__chips\"\n data-testid=\"jkl-combobox__chips\"\n >\n {selectedValue\n .map(getComboboxValuePair)\n .map((option) => {\n return hasTagHover ? (\n <Tooltip key={option.value}>\n <TooltipTrigger>\n {renderSelectedOption(option)}\n </TooltipTrigger>\n <TooltipContent>\n {option.label}\n </TooltipContent>\n </Tooltip>\n ) : (\n renderSelectedOption(option)\n );\n })}\n <input\n {...inputProps}\n className=\"jkl-combobox__search-input\"\n onChange={onSearch}\n data-testid=\"jkl-combobox__search-input\"\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={handleSearchOnKeyDown}\n value={searchValue}\n ref={searchRef}\n aria-controls={listId}\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={showMenu}\n placeholder={\n selectedValue.length > 0 ? \"\" : placeholder\n }\n autoComplete=\"off\"\n />\n </div>\n\n <div\n className=\"jkl-combobox__menu\"\n // biome-ignore lint/a11y/useSemanticElements: Dette er en reimplementering av en liste\n role=\"listbox\"\n ref={dropdownRef}\n id={listId}\n aria-labelledby={labelId}\n aria-multiselectable=\"true\"\n aria-activedescendant={activeDescendant}\n onFocus={handleFocus}\n onBlur={handleBlur}\n tabIndex={-1}\n >\n {options.map((option, i) => (\n <button\n key={`${listId}-${option.value}`}\n type=\"button\"\n id={`${listId}__${option.value}`}\n aria-selected={isSelected(option)}\n // biome-ignore lint/a11y/useSemanticElements: Dette er en reimplementering av en liste\n role=\"option\"\n value={option.value}\n onBlur={handleBlur}\n className={`jkl-combobox__option ${\n isSelected(option) &&\n \"jkl-combobox__option--selected\"\n }`}\n data-testid=\"jkl-combobox__option\"\n data-testautoid={`jkl-combobox__option-${i}`}\n onFocus={handleFocus}\n onKeyDown={handleOptionOnKeyDown}\n onClick={(e) => {\n setActiveDescendant(\n `${listId}__${option.value}`,\n ); // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/listbox_role#required_javascript_features\n e.stopPropagation();\n onItemClick(option.value);\n setSearchValue(\"\");\n }}\n onMouseOver={handleMouseOver}\n >\n {option.description ? (\n <span>\n {option.label}\n <span className=\"jkl-combobox__option-description\">\n {option.description}\n </span>\n </span>\n ) : (\n option.label\n )}\n {isSelected(option) ? (\n <span>\n <CheckIcon />{\" \"}\n </span>\n ) : null}\n </button>\n ))}\n {noResults && (\n <div className=\"jkl-combobox__no-option\">\n {noMatchingOption}\n </div>\n )}\n </div>\n <IconButton\n id={buttonId}\n onFocus={handleFocus}\n onBlur={handleBlur}\n className=\"jkl-text-input-action-button\"\n data-testid=\"jkl-combobox__button\"\n aria-label=\"Åpne meny\"\n aria-expanded={showMenu}\n aria-controls={listId}\n onClick={() => setShowMenu((previous) => !previous)}\n onMouseDown={(e) => {\n e.preventDefault();\n inputRef.current?.focus();\n }}\n >\n <ArrowVerticalAnimated pointingDown={isPointingDown} />\n </IconButton>\n </div>\n )}\n />\n );\n};\nCombobox.displayName = \"Combobox\";\n"],"names":["getComboboxValuePair","item","value","label","Combobox","props","dataSize","id","placeholder","items","onChange","onFocus","onBlur","noMatchingOption","labelProps","helpLabel","errorLabel","width","name","className","invalid","description","hasTagHover","listId","useId","generateSuffix","labelId","buttonId","inputId","selectedValue","setSelectedValue","useState","showMenu","setShowMenu","searchValue","setSearchValue","noResults","setNoResults","marked","setMarked","searchRef","useRef","inputRef","focusInsideRef","useEffect","current","focus","prev","isSelected","option","some","removeOption","useCallback","filter","onTagRemove","e","newValue","type","target","selectedOptions","stopPropagation","length","onItemClick","find","i","onSearch","options","useMemo","filteredOptions","toLowerCase","indexOf","activeDescendant","setActiveDescendant","isPointingDown","handleEscape","key","window","addEventListener","removeEventListener","handleFocusPlacement","isOpen","handleFocus","dropdownRef","useAnimatedHeight","onFirstVisible","onTransitionEnd","useListNavigation","ref","componentRootElementRef","handleBlur","contains","relatedTarget","dispatchEvent","Event","bubbles","handleMouseOver","preventScroll","handleSearchOnKeyDown","preventDefault","listElement","querySelector","metaKey","ctrlKey","updatedSelectedValue","map","isMarked","handleOptionOnKeyDown","shiftKey","firstVisible","currentTarget","hasSelection","renderSelectedOption","jsx","Chip","tagLabel","variant","onClick","children","InputGroup","clsx","render","inputProps","jsxs","style","tabIndex","Tooltip","TooltipTrigger","TooltipContent","onKeyDown","role","autoComplete","onMouseOver","CheckIcon","IconButton","previous","onMouseDown","ArrowVerticalAnimated","pointingDown","displayName"],"mappings":"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"}
1
+ {"version":3,"file":"Combobox.js","sources":["../../../../src/components/combobox/Combobox.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React, {\n type FC,\n type FocusEvent,\n type KeyboardEvent,\n type MouseEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { useAnimatedHeight } from \"../../hooks/useAnimatedHeight/useAnimatedHeight.js\";\nimport { useId } from \"../../hooks/useId/useId.js\";\nimport { useListNavigation } from \"../../hooks/useListNavigation/useListNavigation.js\";\nimport type { ValuePair } from \"../../utilities/valuePair.js\";\nimport { Chip } from \"../chip/Chip.js\";\nimport { IconButton } from \"../icon-button/IconButton.js\";\nimport { CheckIcon } from \"../icon/icons/CheckIcon.js\";\nimport { ArrowVerticalAnimated } from \"../icon/icons/animated/ArrowVerticalAnimated.js\";\nimport { InputGroup } from \"../input-group/InputGroup.js\";\nimport { Tooltip } from \"../tooltip/Tooltip.js\";\nimport { TooltipContent } from \"../tooltip/TooltipContent.js\";\nimport { TooltipTrigger } from \"../tooltip/TooltipTrigger.js\";\nimport type { ComboboxProps, ComboboxValuePair } from \"./types.js\";\n\nexport function getComboboxValuePair(\n item: string | ComboboxValuePair,\n): ComboboxValuePair {\n return typeof item === \"string\" ? { value: item, label: item } : item;\n}\n\nexport const Combobox: FC<ComboboxProps> = (props) => {\n const {\n \"data-size\": dataSize,\n id,\n placeholder,\n items,\n onChange,\n onFocus,\n onBlur,\n value,\n label,\n noMatchingOption,\n labelProps,\n helpLabel,\n errorLabel,\n width,\n name,\n className,\n invalid,\n description,\n hasTagHover,\n } = props;\n const listId = useId(id || \"jkl-combobox\", { generateSuffix: !id });\n const labelId = `${listId}_label`;\n const buttonId = `${listId}_button`;\n const inputId = `${listId}_search-input`;\n\n const [selectedValue, setSelectedValue] = useState<\n Array<ComboboxValuePair>\n >(value || []);\n const [showMenu, setShowMenu] = useState<boolean>(false);\n const [searchValue, setSearchValue] = useState<string>(\"\");\n const [noResults, setNoResults] = useState(false);\n const [marked, setMarked] = useState<boolean>(false);\n\n const searchRef = useRef<HTMLInputElement>(null);\n const inputRef = useRef<HTMLDivElement>(null);\n const focusInsideRef = useRef(false);\n\n useEffect(() => {\n setSearchValue(\"\");\n if (showMenu && searchRef.current) {\n searchRef.current.focus();\n }\n }, [showMenu]);\n\n useEffect(() => {\n setSelectedValue((prev) => value || prev);\n }, [value]);\n\n // Funksjon for å stile valgt element\n const isSelected = (option: ValuePair) => {\n if (!selectedValue) {\n return false;\n }\n\n return selectedValue.some((value) => value.value === option.value);\n };\n\n // Fjerne ett eller flere valg\n const removeOption = useCallback(\n (option: string) => {\n return selectedValue.filter((value) => value.value !== option);\n },\n [selectedValue],\n );\n\n const onTagRemove = useCallback(\n (\n e:\n | React.MouseEvent<HTMLButtonElement, globalThis.MouseEvent>\n | React.KeyboardEvent<HTMLInputElement>,\n option: string,\n ) => {\n const newValue = removeOption(option);\n setSelectedValue(newValue);\n onChange({\n type: \"change\",\n target: { name, value: option, selectedOptions: newValue },\n });\n e.stopPropagation();\n\n if (newValue.length === 0) {\n setMarked(false);\n }\n },\n [removeOption, onChange, name],\n );\n\n // Håndtere valgt verdi i listen\n const onItemClick = useCallback(\n (option: string) => {\n let newValue: Array<ValuePair>;\n\n if (selectedValue.some((value) => value.value === option)) {\n newValue = removeOption(option);\n } else {\n const item = items.find((i) => i.value === option);\n newValue = [...selectedValue, item as ValuePair];\n }\n searchRef.current?.focus();\n setSelectedValue(newValue);\n onChange({\n type: \"change\",\n target: { name, value: option, selectedOptions: newValue },\n });\n },\n [selectedValue, onChange, name, removeOption, items],\n );\n\n // Funksjon for søk\n const onSearch = (e: {\n target: { value: React.SetStateAction<string> };\n }) => {\n searchRef.current?.focus();\n setShowMenu(true);\n setSearchValue(e.target.value);\n };\n\n const options = useMemo(() => {\n if (!searchValue) {\n return items;\n }\n\n const filteredOptions = items.filter(\n (option) =>\n option.label.toLowerCase().indexOf(searchValue.toLowerCase()) >=\n 0,\n );\n\n setNoResults(filteredOptions.length === 0);\n\n return filteredOptions;\n }, [searchValue, items]);\n\n // Det første elementet i listen skal være aktivt fram til brukeren klikker på noe annet\n const [activeDescendant, setActiveDescendant] = useState<\n string | undefined\n >(options[0]?.value ? `${listId}-${options[0]?.value}` : undefined);\n\n // Håndtere arrow-state\n const isPointingDown = !showMenu;\n\n // Lukk meny med ESC\n useEffect(() => {\n const handleEscape = (e: globalThis.KeyboardEvent) => {\n if (e.key === \"Escape\" && showMenu) {\n setShowMenu(false);\n }\n };\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"keydown\", handleEscape);\n }\n return () => {\n if (typeof window !== \"undefined\" && showMenu) {\n window.removeEventListener(\"keydown\", handleEscape);\n }\n };\n }, [showMenu]);\n\n // Fokushåndtering\n const handleFocusPlacement = useCallback((isOpen: boolean) => {\n if (isOpen) {\n if (searchRef.current) {\n searchRef.current.focus();\n }\n } else {\n if (focusInsideRef.current && inputRef.current) {\n inputRef.current.focus();\n }\n }\n }, []);\n\n const handleFocus = useCallback(() => {\n if (!focusInsideRef.current) {\n if (onFocus) {\n onFocus({\n type: \"change\",\n target: {\n name,\n value: selectedValue?.[0].value || \"\",\n selectedOptions: selectedValue,\n },\n });\n }\n focusInsideRef.current = true;\n setShowMenu(true);\n }\n }, [onFocus, selectedValue, name]);\n\n const [dropdownRef] = useAnimatedHeight<HTMLDivElement>(showMenu, {\n onFirstVisible: handleFocusPlacement,\n onTransitionEnd: handleFocusPlacement,\n });\n\n useListNavigation({ ref: dropdownRef });\n\n const componentRootElementRef = useRef<HTMLDivElement>(null);\n\n const handleBlur = useCallback(\n (\n e: FocusEvent<\n HTMLDivElement | HTMLInputElement | HTMLButtonElement\n >,\n ) => {\n const componentRootElement = componentRootElementRef.current;\n const nextFocusIsInsideComponent = componentRootElement?.contains(\n e.relatedTarget as Node,\n );\n if (!nextFocusIsInsideComponent) {\n setSearchValue(\"\");\n\n if (onBlur) {\n onBlur({\n type: \"blur\",\n target: {\n name,\n value: selectedValue?.[0]?.value || \"\",\n selectedOptions: selectedValue,\n },\n });\n inputRef.current?.dispatchEvent(\n new Event(\"focusout\", { bubbles: true }),\n );\n }\n focusInsideRef.current = false;\n setShowMenu(false);\n }\n },\n [onBlur, name, selectedValue],\n );\n\n const handleMouseOver = useCallback((e: MouseEvent<HTMLButtonElement>) => {\n // Ved mouseOver på options flytter vi fokus til dem for å unngå \"dobbel fokus\"\n // der det ser ut som to forskjellige elementer er fokusert/hovered samtidig\n (e.target as HTMLButtonElement).focus({ preventScroll: true });\n }, []);\n\n // Tastaturnavigasjon\n const handleSearchOnKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n e.stopPropagation();\n const listElement = dropdownRef.current;\n if (listElement) {\n listElement\n .querySelector<HTMLButtonElement>('[role=\"option\"]')\n ?.focus();\n }\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n e.stopPropagation();\n setShowMenu(false);\n }\n\n if ((e.metaKey && e.key === \"a\") || (e.ctrlKey && e.key === \"a\")) {\n e.preventDefault();\n e.stopPropagation();\n const updatedSelectedValue = selectedValue.map((item) => ({\n ...item,\n isMarked: true,\n }));\n setMarked(true);\n setSelectedValue(updatedSelectedValue);\n } else if (e.key === \"Backspace\") {\n e.stopPropagation();\n setMarked(false);\n\n // Sjekk om selectedValue er markert\n const selectedValueIsMarked = selectedValue.some(\n (item) => item.isMarked,\n );\n\n if (selectedValueIsMarked) {\n const updatedSelectedValue = selectedValue.filter(\n (item) => !item.isMarked,\n );\n setSelectedValue(updatedSelectedValue);\n setSearchValue(\"\");\n } else if (selectedValue.length > 0 && searchValue === \"\") {\n // Hvis ingen items er markert, fjern siste valgte item\n onTagRemove(\n e,\n selectedValue[selectedValue.length - 1].value,\n );\n }\n }\n },\n [selectedValue, searchValue, dropdownRef, onTagRemove],\n );\n\n const handleOptionOnKeyDown = useCallback(\n (e: KeyboardEvent<HTMLButtonElement>) => {\n if (e.key === \"Tab\") {\n if (searchRef.current) {\n e.preventDefault();\n e.stopPropagation();\n\n if (e.shiftKey) {\n searchRef.current.focus();\n } else {\n setShowMenu(false);\n searchRef.current.focus();\n }\n }\n } else if (e.key === \"ArrowUp\") {\n if (dropdownRef.current && searchRef.current) {\n // Can't be based on index since the first item might be filtered out\n const firstVisible = dropdownRef.current.querySelector(\n '[role=\"option\"]:not([hidden])',\n );\n if (\n e.currentTarget.id === firstVisible?.id &&\n searchRef.current\n ) {\n searchRef.current.focus();\n }\n }\n }\n },\n [dropdownRef],\n );\n\n const hasSelection = selectedValue.length >= 1;\n\n const renderSelectedOption = useCallback(\n (option: ComboboxValuePair) => (\n <Chip\n key={option.value}\n data-testid=\"jkl-chip\"\n aria-label={`Fjern ${option.tagLabel}`}\n className={`jkl-combobox__selected-option ${\n marked && \"jkl-combobox__selected-option--marked\"\n }`}\n variant=\"input\"\n onClick={(e) => {\n if (searchRef.current) {\n searchRef.current.focus();\n }\n onTagRemove(e, option.value);\n }}\n onBlur={handleBlur}\n >\n {option.tagLabel ? option.tagLabel : option.label}\n </Chip>\n ),\n [handleBlur, onTagRemove, marked],\n );\n\n return (\n <InputGroup\n label={label}\n id={inputId}\n ref={componentRootElementRef}\n data-testid=\"jkl-combobox\"\n data-size={dataSize}\n className={clsx(\"jkl-combobox\", className, {\n \"jkl-combobox--invalid\": !!errorLabel || invalid,\n \"jkl-combobox--menu-open\": showMenu,\n \"jkl-combobox--menu-closed\": !showMenu && hasSelection,\n })}\n labelProps={{\n id: labelId,\n ...labelProps,\n }}\n helpLabel={helpLabel}\n errorLabel={errorLabel}\n description={description}\n render={(inputProps) => (\n <div\n className={clsx(\"jkl-combobox__wrapper\", {\n \"jkl-combobox__wrapper--active-value\": hasSelection,\n })}\n style={{ width }}\n tabIndex={-1}\n onFocus={handleFocus}\n onBlur={handleBlur}\n data-invalid={!!errorLabel || invalid}\n >\n <div\n className=\"jkl-combobox__chips\"\n data-testid=\"jkl-combobox__chips\"\n >\n {selectedValue\n .map(getComboboxValuePair)\n .map((option) => {\n return hasTagHover ? (\n <Tooltip key={option.value}>\n <TooltipTrigger>\n {renderSelectedOption(option)}\n </TooltipTrigger>\n <TooltipContent>\n {option.label}\n </TooltipContent>\n </Tooltip>\n ) : (\n renderSelectedOption(option)\n );\n })}\n <input\n {...inputProps}\n className=\"jkl-combobox__search-input\"\n onChange={onSearch}\n data-testid=\"jkl-combobox__search-input\"\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={handleSearchOnKeyDown}\n value={searchValue}\n ref={searchRef}\n aria-controls={listId}\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={showMenu}\n placeholder={\n selectedValue.length > 0 ? \"\" : placeholder\n }\n autoComplete=\"off\"\n />\n </div>\n\n <div\n className=\"jkl-combobox__menu\"\n // biome-ignore lint/a11y/useSemanticElements: Dette er en reimplementering av en liste\n role=\"listbox\"\n ref={dropdownRef}\n id={listId}\n aria-labelledby={labelId}\n aria-multiselectable=\"true\"\n aria-activedescendant={activeDescendant}\n onFocus={handleFocus}\n onBlur={handleBlur}\n tabIndex={-1}\n >\n {options.map((option, i) => (\n <button\n key={`${listId}-${option.value}`}\n type=\"button\"\n id={`${listId}__${option.value}`}\n aria-selected={isSelected(option)}\n // biome-ignore lint/a11y/useSemanticElements: Dette er en reimplementering av en liste\n role=\"option\"\n value={option.value}\n onBlur={handleBlur}\n className={`jkl-combobox__option ${\n isSelected(option) &&\n \"jkl-combobox__option--selected\"\n }`}\n data-testid=\"jkl-combobox__option\"\n data-testautoid={`jkl-combobox__option-${i}`}\n onFocus={handleFocus}\n onKeyDown={handleOptionOnKeyDown}\n onClick={(e) => {\n setActiveDescendant(\n `${listId}__${option.value}`,\n ); // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/listbox_role#required_javascript_features\n e.stopPropagation();\n onItemClick(option.value);\n setSearchValue(\"\");\n }}\n onMouseOver={handleMouseOver}\n >\n {option.description ? (\n <span>\n {option.label}\n <span className=\"jkl-combobox__option-description\">\n {option.description}\n </span>\n </span>\n ) : (\n option.label\n )}\n {isSelected(option) ? (\n <span>\n <CheckIcon />{\" \"}\n </span>\n ) : null}\n </button>\n ))}\n {noResults && (\n <div className=\"jkl-combobox__no-option\">\n {noMatchingOption}\n </div>\n )}\n </div>\n <IconButton\n id={buttonId}\n onFocus={handleFocus}\n onBlur={handleBlur}\n className=\"jkl-text-input-action-button\"\n data-testid=\"jkl-combobox__button\"\n aria-label=\"Åpne meny\"\n aria-expanded={showMenu}\n aria-controls={listId}\n onClick={() => setShowMenu((previous) => !previous)}\n onMouseDown={(e) => {\n e.preventDefault();\n inputRef.current?.focus();\n }}\n >\n <ArrowVerticalAnimated pointingDown={isPointingDown} />\n </IconButton>\n </div>\n )}\n />\n );\n};\nCombobox.displayName = \"Combobox\";\n"],"names":["getComboboxValuePair","item","value","label","Combobox","props","dataSize","id","placeholder","items","onChange","onFocus","onBlur","noMatchingOption","labelProps","helpLabel","errorLabel","width","name","className","invalid","description","hasTagHover","listId","useId","generateSuffix","labelId","buttonId","inputId","selectedValue","setSelectedValue","useState","showMenu","setShowMenu","searchValue","setSearchValue","noResults","setNoResults","marked","setMarked","searchRef","useRef","inputRef","focusInsideRef","useEffect","current","focus","prev","isSelected","option","some","removeOption","useCallback","filter","onTagRemove","e","newValue","type","target","selectedOptions","stopPropagation","length","onItemClick","find","i","onSearch","options","useMemo","filteredOptions","toLowerCase","indexOf","activeDescendant","setActiveDescendant","isPointingDown","handleEscape","key","window","addEventListener","removeEventListener","handleFocusPlacement","isOpen","handleFocus","dropdownRef","useAnimatedHeight","onFirstVisible","onTransitionEnd","useListNavigation","ref","componentRootElementRef","handleBlur","contains","relatedTarget","dispatchEvent","Event","bubbles","handleMouseOver","preventScroll","handleSearchOnKeyDown","preventDefault","listElement","querySelector","metaKey","ctrlKey","updatedSelectedValue","map","isMarked","handleOptionOnKeyDown","shiftKey","firstVisible","currentTarget","hasSelection","renderSelectedOption","jsx","Chip","tagLabel","variant","onClick","children","InputGroup","clsx","render","inputProps","jsxs","style","tabIndex","Tooltip","TooltipTrigger","TooltipContent","onKeyDown","role","autoComplete","onMouseOver","CheckIcon","IconButton","previous","onMouseDown","ArrowVerticalAnimated","pointingDown","displayName"],"mappings":"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"}
@@ -10,7 +10,7 @@ export type ExpandablePanelProps<ElementType extends React.ElementType> = Polymo
10
10
  export type ExpandablePanelComponent = {
11
11
  Content: ExpandablePanelContentComponent;
12
12
  Header: ExpanderComponent;
13
- } & (<ElementType extends React.ElementType = "div">(props: ExpandablePanelProps<ElementType>) => React.ReactElement | null);
13
+ } & (<ElementType extends React.ElementType = "details">(props: ExpandablePanelProps<ElementType>) => React.ReactElement | null);
14
14
  export type ExpanderProps<ElementType extends React.ElementType> = PolymorphicPropsWithRef<ElementType, {
15
15
  icon?: React.ReactNode;
16
16
  open?: boolean;
@@ -1,2 +1,2 @@
1
- import{jsxs as o,jsx as t}from"react/jsx-runtime";import{c as e}from"../../../clsx-BeLtu-UY.js";import"react";import{Button as i}from"../button/Button.js";import{Icon as r}from"../icon/Icon.js";const s=({position:s="top",buttonText:a="Hjelp",showButtonText:p=!1,iconPosition:l="left",className:n,children:c,...h})=>o("div",{className:e("jkl-help",n),children:[t(i,{...h,title:a||h.title,iconPosition:l,variant:"ghost",className:"jkl-help-trigger",icon:t(r,{"aria-hidden":"true",children:"help"}),"data-testid":"jkl-help-trigger",popovertarget:`${a}-popover`,style:{anchorName:`${a}-popover`},children:p&&a}),t("output",{"aria-live":"assertive",children:t("div",{"data-position":s,popover:"auto",id:`${a}-popover`,className:"jkl-help-popover",children:c})})]});export{s as Help};
1
+ import{jsxs as t,jsx as o}from"react/jsx-runtime";import{c as e}from"../../../clsx-BeLtu-UY.js";import{useId as i}from"react";import{Button as r}from"../button/Button.js";import{Icon as s}from"../icon/Icon.js";const a=({position:a="top",buttonText:n="Hjelp",showButtonText:p=!1,iconPosition:l="left",className:c,children:d,...m})=>{const h=i();return t("div",{className:e("jkl-help",c),children:[o(r,{...m,title:n||m.title,iconPosition:l,variant:"ghost",className:"jkl-help-trigger",icon:o(s,{"aria-hidden":"true",children:"help"}),"data-testid":"jkl-help-trigger",popovertarget:`${h}-popover`,children:p&&n}),o("output",{"aria-live":"assertive",children:o("div",{"data-position":a,popover:"auto",id:`${h}-popover`,className:"jkl-help-popover",children:d})})]})};export{a as Help};
2
2
  //# sourceMappingURL=Help.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Help.js","sources":["../../../../src/components/help/Help.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React from \"react\";\nimport { Button } from \"../button/index.js\";\nimport { Icon } from \"../icon/Icon.js\";\nimport type { HelpProps } from \"./types.js\";\n\nexport const Help = ({\n position = \"top\",\n buttonText = \"Hjelp\",\n showButtonText = false,\n iconPosition = \"left\",\n className,\n children,\n ...rest\n}: HelpProps) => {\n return (\n <div className={clsx(\"jkl-help\", className)}>\n <Button\n {...rest}\n title={buttonText || rest.title}\n iconPosition={iconPosition}\n variant=\"ghost\"\n className={\"jkl-help-trigger\"}\n icon={<Icon aria-hidden=\"true\">help</Icon>}\n data-testid=\"jkl-help-trigger\"\n // @ts-ignore\n popovertarget={`${buttonText}-popover`}\n style={{ anchorName: `${buttonText}-popover` }}\n >\n {showButtonText && buttonText}\n </Button>\n\n <output aria-live=\"assertive\">\n <div\n data-position={position}\n // @ts-ignore\n popover=\"auto\"\n id={`${buttonText}-popover`}\n className=\"jkl-help-popover\"\n >\n {children}\n </div>\n </output>\n </div>\n );\n};\n"],"names":["Help","position","buttonText","showButtonText","iconPosition","className","children","rest","clsx","jsx","Button","title","variant","icon","Icon","popovertarget","style","anchorName","popover","id"],"mappings":"kMAMO,MAAMA,EAAO,EAChBC,SAAAA,EAAW,MACXC,WAAAA,EAAa,QACbC,eAAAA,GAAiB,EACjBC,aAAAA,EAAe,OACfC,UAAAA,EACAC,SAAAA,KACGC,OAGE,MAAA,CAAIF,UAAWG,EAAK,WAAYH,GAC7BC,SAAA,CAAAG,EAACC,EAAA,IACOH,EACJI,MAAOT,GAAcK,EAAKI,MAC1BP,aAAAA,EACAQ,QAAQ,QACRP,UAAW,mBACXQ,KAAMJ,EAACK,EAAA,CAAK,cAAY,OAAOR,SAAA,SAC/B,cAAY,mBAEZS,cAAe,GAAGb,YAClBc,MAAO,CAAEC,WAAY,GAAGf,aAEvBI,SAAAH,GAAkBD,IAGvBO,EAAC,SAAA,CAAO,YAAU,YACdH,SAAAG,EAAC,MAAA,CACG,gBAAeR,EAEfiB,QAAQ,OACRC,GAAI,GAAGjB,YACPG,UAAU,mBAETC,SAAAA"}
1
+ {"version":3,"file":"Help.js","sources":["../../../../src/components/help/Help.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport React, { useId } from \"react\";\nimport { Button } from \"../button/index.js\";\nimport { Icon } from \"../icon/Icon.js\";\nimport type { HelpProps } from \"./types.js\";\n\nexport const Help = ({\n position = \"top\",\n buttonText = \"Hjelp\",\n showButtonText = false,\n iconPosition = \"left\",\n className,\n children,\n ...rest\n}: HelpProps) => {\n const helpId = useId();\n\n return (\n <div className={clsx(\"jkl-help\", className)}>\n <Button\n {...rest}\n title={buttonText || rest.title}\n iconPosition={iconPosition}\n variant=\"ghost\"\n className={\"jkl-help-trigger\"}\n icon={<Icon aria-hidden=\"true\">help</Icon>}\n data-testid=\"jkl-help-trigger\"\n // @ts-ignore\n popovertarget={`${helpId}-popover`}\n >\n {showButtonText && buttonText}\n </Button>\n\n <output aria-live=\"assertive\">\n <div\n data-position={position}\n // @ts-ignore\n popover=\"auto\"\n id={`${helpId}-popover`}\n className=\"jkl-help-popover\"\n >\n {children}\n </div>\n </output>\n </div>\n );\n};\n"],"names":["Help","position","buttonText","showButtonText","iconPosition","className","children","rest","helpId","useId","clsx","jsx","Button","title","variant","icon","Icon","popovertarget","popover","id"],"mappings":"kNAMO,MAAMA,EAAO,EAChBC,SAAAA,EAAW,MACXC,WAAAA,EAAa,QACbC,eAAAA,GAAiB,EACjBC,aAAAA,EAAe,OACfC,UAAAA,EACAC,SAAAA,KACGC,MAEH,MAAMC,EAASC,IAEf,SACK,MAAA,CAAIJ,UAAWK,EAAK,WAAYL,GAC7BC,SAAA,CAAAK,EAACC,EAAA,IACOL,EACJM,MAAOX,GAAcK,EAAKM,MAC1BT,aAAAA,EACAU,QAAQ,QACRT,UAAW,mBACXU,KAAMJ,EAACK,EAAA,CAAK,cAAY,OAAOV,SAAA,SAC/B,cAAY,mBAEZW,cAAe,GAAGT,YAEjBF,SAAAH,GAAkBD,IAGvBS,EAAC,SAAA,CAAO,YAAU,YACdL,SAAAK,EAAC,MAAA,CACG,gBAAeV,EAEfiB,QAAQ,OACRC,GAAI,GAAGX,YACPH,UAAU,mBAETC,SAAAA"}
@@ -1,2 +1,2 @@
1
- import{jsx as r}from"react/jsx-runtime";import"react";import{Icon as o}from"../Icon.js";const c=c=>r(o,{bold:!0,filled:!0,...c,children:""});c.displayName="ErrorIcon";export{c as ErrorIcon};
1
+ import{jsx as r}from"react/jsx-runtime";import"react";import{Icon as o}from"../Icon.js";const c=c=>r(o,{bold:!0,filled:!0,...c,children:""});c.displayName="ErrorIcon";export{c as ErrorIcon};
2
2
  //# sourceMappingURL=ErrorIcon.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorIcon.js","sources":["../../../../../src/components/icon/icons/ErrorIcon.tsx"],"sourcesContent":["import React from \"react\";\nimport { Icon, type IconComponent } from \"../Icon.js\";\nimport type { IconProps } from \"../types.js\";\n\nexport const ErrorIcon: IconComponent = (props: IconProps) => (\n <Icon bold filled {...props}>\n {\"\\uf8b6\"}\n </Icon>\n);\nErrorIcon.displayName = \"ErrorIcon\";\n"],"names":["ErrorIcon","props","jsx","Icon","bold","filled","children","displayName"],"mappings":"wFAIO,MAAMA,EAA4BC,GACrCC,EAACC,EAAA,CAAKC,MAAI,EAACC,QAAM,KAAKJ,EACjBK,SAAA,MAGTN,EAAUO,YAAc"}
1
+ {"version":3,"file":"ErrorIcon.js","sources":["../../../../../src/components/icon/icons/ErrorIcon.tsx"],"sourcesContent":["import React from \"react\";\nimport { Icon, type IconComponent } from \"../Icon.js\";\nimport type { IconProps } from \"../types.js\";\n\nexport const ErrorIcon: IconComponent = (props: IconProps) => (\n <Icon bold filled {...props}>\n {\"\\ue82a\"}\n </Icon>\n);\nErrorIcon.displayName = \"ErrorIcon\";\n"],"names":["ErrorIcon","props","jsx","Icon","bold","filled","children","displayName"],"mappings":"wFAIO,MAAMA,EAA4BC,GACrCC,EAACC,EAAA,CAAKC,MAAI,EAACC,QAAM,KAAKJ,EACjBK,SAAA,MAGTN,EAAUO,YAAc"}
@@ -1,2 +1,2 @@
1
- import{jsxs as e,jsx as s}from"react/jsx-runtime";import{useFloatingTree as t,useFloatingNodeId as n,useFloatingParentNodeId as o,useFloating as a,autoUpdate as r,offset as i,flip as l,shift as u,useInteractions as d,useHover as c,safePolygon as m,useClick as p,useDismiss as f,useRole as g,useListNavigation as h,useMergeRefs as v,useTransitionStyles as k,FloatingNode as x,FloatingPortal as y,FloatingFocusManager as P,FloatingTree as j}from"@floating-ui/react";import{c as F}from"../../../clsx-BeLtu-UY.js";import w,{forwardRef as I,useId as M,useRef as C,useState as E,useEffect as S}from"react";import{useBrowserPreferences as N}from"../../hooks/useBrowserPreferences/useBrowserPreferences.js";import"../../hooks/useScreen/useScreen.js";import"../../hooks/useId/useId.js";import{getThemeAndSize as O}from"../../utilities/getThemeAndSize.js";import{SlotComponent as R}from"../../utilities/polymorphism/SlotComponent.js";import{useMenuWideEvents as b}from"./useMenuWideEvents.js";function T(e,s=0){switch(e){case"top":default:return`0 ${s}px`;case"left":return`${s}px 0`;case"bottom":return`0 ${-s}px`;case"right":return-s+"px 0"}}const z=I((j,I)=>{const{children:z,className:A,initialPlacement:D,openOnHover:$=!1,keepOpenOnClickOutside:B=!1,triggerElement:H,isOpen:K,onToggle:V,...W}=j,q=`"jkl-menu"${M()}`,{prefersReducedMotion:L}=N(),U=t(),G=n(),J=o(),Q=null!=J,X=C([]),[Y,Z]=E(null),{allowHover:_,isOpen:ee,setIsOpen:se}=b(U,G,J),te=void 0!==K?K:ee;S(()=>V?.(te),[te,V]);const{refs:ne,placement:oe,context:ae,floatingStyles:re}=a({nodeId:G,open:te,onOpenChange:se,placement:D||(Q?"right-start":"bottom-start"),middleware:[i(2),l({fallbackAxisSideDirection:"end",crossAxis:!1}),u({padding:8})],whileElementsMounted:r}),{getReferenceProps:ie,getFloatingProps:le,getItemProps:ue}=d([c(ae,{enabled:$&&_,delay:{open:75},handleClose:m({requireIntent:!0,blockPointerEvents:!0})}),p(ae,{event:"mousedown"}),f(ae,{outsidePress:!B}),g(ae,{role:"menu"}),h(ae,{listRef:X,activeIndex:Y,nested:Q,onNavigate:Z})]),de=v([ne.setReference,I]),{theme:ce,size:me}=O(ne.reference.current),{isMounted:pe,styles:fe}=k(ae,{duration:{open:L?0:250,close:L?0:150},initial:({side:e})=>({opacity:0,translate:T(e,5)}),open:({side:e})=>({opacity:1,translate:T(e,0)}),close:({side:e})=>({opacity:0,translate:T(e,5)})});return e(x,{id:G,children:[w.isValidElement(H)&&s(R,{...ie({...W,ref:de,role:Q?"menuitem":void 0,"aria-controls":q,onClick(e){e.stopPropagation()}}),children:H}),pe&&s(y,{children:s(P,{context:ae,modal:!1,initialFocus:Q?-1:0,returnFocus:!Q,children:s("div",{className:F("jkl jkl-menu",A),"data-theme":ce,"data-size":me,role:"menu","data-placement":oe,"aria-live":"assertive","aria-hidden":!te,ref:ne.setFloating,...le({id:q,style:{...re,...fe}}),children:w.Children.map(z,(e,t)=>w.isValidElement(e)?s(R,{...ue({...e.props,tabIndex:Y===t?0:-1,role:"menuitem",ref(e){X.current[t]=e},onClick(e){e.defaultPrevented||U?.events.emit("click")},onKeyDown(s){e.props.onKeyDown?.(s),!s.defaultPrevented&&(U?.events.emit("keydown"),"menuitemcheckbox"===s.currentTarget.role&&"Enter"===s.key&&se(!1))},onMouseEnter(){_&&te&&Z(t)}}),children:e}):e)})})})]})});z.displayName="MenuComponent";const A=I((e,t)=>null===o()?s(j,{children:s(z,{ref:t,...e})}):s(z,{ref:t,...e}));A.displayName="Menu";export{A as Menu};
1
+ import{jsxs as e,jsx as s}from"react/jsx-runtime";import{useFloatingTree as t,useFloatingNodeId as n,useFloatingParentNodeId as o,useFloating as a,autoUpdate as r,offset as i,flip as l,shift as u,useInteractions as d,useHover as c,safePolygon as m,useClick as p,useDismiss as f,useRole as g,useListNavigation as h,useMergeRefs as v,useTransitionStyles as k,FloatingNode as x,FloatingPortal as y,FloatingFocusManager as P,FloatingTree as j}from"@floating-ui/react";import{c as F}from"../../../clsx-BeLtu-UY.js";import w,{forwardRef as I,useId as M,useRef as C,useState as E,useEffect as S}from"react";import{useBrowserPreferences as N}from"../../hooks/useBrowserPreferences/useBrowserPreferences.js";import"../../hooks/useScreen/useScreen.js";import"../../hooks/useId/useId.js";import{getThemeAndSize as O}from"../../utilities/getThemeAndSize.js";import{SlotComponent as R}from"../../utilities/polymorphism/SlotComponent.js";import{useMenuWideEvents as b}from"./useMenuWideEvents.js";function T(e,s=0){switch(e){case"top":default:return`0 ${s}px`;case"left":return`${s}px 0`;case"bottom":return`0 ${-s}px`;case"right":return-s+"px 0"}}const z=I((j,I)=>{const{children:z,className:A,initialPlacement:D,openOnHover:$=!1,keepOpenOnClickOutside:B=!1,triggerElement:H,isOpen:K,onToggle:V,...W}=j,q=`"jkl-menu"${M()}`,{prefersReducedMotion:L}=N(),U=t(),G=n(),J=o(),Q=null!=J,X=C([]),[Y,Z]=E(null),{allowHover:_,isOpen:ee,setIsOpen:se}=b(U,G,J),te=void 0!==K?K:ee;S(()=>V?.(te),[te,V]);const{refs:ne,placement:oe,context:ae,floatingStyles:re}=a({nodeId:G,open:te,onOpenChange:se,placement:D||(Q?"right-start":"bottom-start"),middleware:[i(5),l({fallbackAxisSideDirection:"end",crossAxis:!1}),u({padding:8})],whileElementsMounted:r}),{getReferenceProps:ie,getFloatingProps:le,getItemProps:ue}=d([c(ae,{enabled:$&&_,delay:{open:75},handleClose:m({requireIntent:!0,blockPointerEvents:!0})}),p(ae,{event:"mousedown"}),f(ae,{outsidePress:!B}),g(ae,{role:"menu"}),h(ae,{listRef:X,activeIndex:Y,nested:Q,onNavigate:Z})]),de=v([ne.setReference,I]),{theme:ce,size:me}=O(ne.reference.current),{isMounted:pe,styles:fe}=k(ae,{duration:{open:L?0:250,close:L?0:150},initial:({side:e})=>({opacity:0,translate:T(e,5)}),open:({side:e})=>({opacity:1,translate:T(e,0)}),close:({side:e})=>({opacity:0,translate:T(e,5)})});return e(x,{id:G,children:[w.isValidElement(H)&&s(R,{...ie({...W,ref:de,role:Q?"menuitem":void 0,"aria-controls":q,onClick(e){e.stopPropagation()}}),children:H}),pe&&s(y,{children:s(P,{context:ae,modal:!1,initialFocus:Q?-1:0,returnFocus:!Q,children:s("div",{className:F("jkl jkl-menu",A),"data-theme":ce,"data-size":me,role:"menu","data-placement":oe,"aria-live":"assertive","aria-hidden":!te,ref:ne.setFloating,...le({id:q,style:{...re,...fe}}),children:w.Children.map(z,(e,t)=>w.isValidElement(e)?s(R,{...ue({...e.props,tabIndex:Y===t?0:-1,role:"menuitem",ref(e){X.current[t]=e},onClick(e){e.defaultPrevented||U?.events.emit("click")},onKeyDown(s){e.props.onKeyDown?.(s),!s.defaultPrevented&&(U?.events.emit("keydown"),"menuitemcheckbox"===s.currentTarget.role&&"Enter"===s.key&&se(!1))},onMouseEnter(){_&&te&&Z(t)}}),children:e}):e)})})})]})});z.displayName="MenuComponent";const A=I((e,t)=>null===o()?s(j,{children:s(z,{ref:t,...e})}):s(z,{ref:t,...e}));A.displayName="Menu";export{A as Menu};
2
2
  //# sourceMappingURL=Menu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Menu.js","sources":["../../../../src/components/menu/Menu.tsx"],"sourcesContent":["import {\n FloatingFocusManager,\n FloatingNode,\n FloatingPortal,\n FloatingTree,\n type Side,\n autoUpdate,\n flip,\n offset,\n safePolygon,\n shift,\n useClick,\n useDismiss,\n useFloating,\n useFloatingNodeId,\n useFloatingParentNodeId,\n useFloatingTree,\n useHover,\n useInteractions,\n useListNavigation,\n useMergeRefs,\n useRole,\n useTransitionStyles,\n} from \"@floating-ui/react\";\nimport clsx from \"clsx\";\nimport React, { forwardRef, useEffect, useRef, useState, useId } from \"react\";\nimport { useBrowserPreferences } from \"../../hooks/index.js\";\nimport { getThemeAndSize } from \"../../utilities/getThemeAndSize.js\";\nimport { SlotComponent } from \"../../utilities/index.js\";\nimport type { MenuProps } from \"./types.js\";\nimport { useMenuWideEvents } from \"./useMenuWideEvents.js\";\n\nfunction getTranslation(side: Side, value = 0) {\n switch (side) {\n case \"top\":\n return `0 ${value}px`;\n case \"left\":\n return `${value}px 0`;\n case \"bottom\":\n return `0 ${-value}px`;\n case \"right\":\n return `${-value}px 0`;\n\n default:\n return `0 ${value}px`;\n }\n}\n\nconst MenuComponent = forwardRef<HTMLButtonElement, MenuProps>(\n (props, forwardedRef) => {\n const {\n children,\n className,\n initialPlacement,\n openOnHover = false,\n keepOpenOnClickOutside = false,\n triggerElement,\n isOpen: isOpenOverride,\n onToggle,\n ...triggerProps\n } = props;\n\n const MenuId = `\"jkl-menu\"${useId()}`;\n\n const { prefersReducedMotion } = useBrowserPreferences();\n\n const tree = useFloatingTree();\n const nodeId = useFloatingNodeId();\n const parentId = useFloatingParentNodeId();\n const isNested = parentId != null;\n\n const listItemsRef = useRef<Array<HTMLButtonElement | null>>([]);\n const [activeIndex, setActiveIndex] = useState<number | null>(null);\n const {\n allowHover,\n isOpen: isOpenDefault,\n setIsOpen,\n } = useMenuWideEvents(tree, nodeId, parentId);\n\n const isOpen =\n isOpenOverride !== undefined ? isOpenOverride : isOpenDefault;\n\n useEffect(() => onToggle?.(isOpen), [isOpen, onToggle]);\n\n const { refs, placement, context, floatingStyles } = useFloating({\n nodeId,\n open: isOpen,\n onOpenChange: setIsOpen,\n placement:\n initialPlacement || (isNested ? \"right-start\" : \"bottom-start\"),\n middleware: [\n offset(2),\n flip({\n fallbackAxisSideDirection: \"end\", // Allow bottom placement in narrow viewports (https://floating-ui.com/docs/flip#fallbackaxissidedirection)\n crossAxis: false, // See https://floating-ui.com/docs/flip#combining-with-shift\n }),\n shift({ padding: 8 }),\n ],\n whileElementsMounted: autoUpdate,\n });\n\n const { getReferenceProps, getFloatingProps, getItemProps } =\n useInteractions([\n useHover(context, {\n enabled: openOnHover && allowHover,\n delay: { open: 75 },\n handleClose: safePolygon({\n requireIntent: true,\n blockPointerEvents: true,\n }),\n }),\n useClick(context, {\n event: \"mousedown\",\n }),\n useDismiss(context, { outsidePress: !keepOpenOnClickOutside }),\n useRole(context, { role: \"menu\" }),\n useListNavigation(context, {\n listRef: listItemsRef,\n activeIndex,\n nested: isNested,\n onNavigate: setActiveIndex,\n }),\n ]);\n\n const referenceRef = useMergeRefs([refs.setReference, forwardedRef]);\n\n // Siden menyen rendres på rot må vi hente lokal dark/light-verdi fra triggeren\n // Vi må gjøre dette for å ta hensyn til at tema kan styres lokalt for deler av UIet\n const { theme, size } = getThemeAndSize(\n refs.reference.current as HTMLElement,\n );\n\n const { isMounted, styles: animationStyles } = useTransitionStyles(\n context,\n {\n duration: {\n open: prefersReducedMotion ? 0 : 250,\n close: prefersReducedMotion ? 0 : 150,\n },\n initial: ({ side }) => ({\n opacity: 0,\n translate: getTranslation(side, 5),\n }),\n open: ({ side }) => ({\n opacity: 1,\n translate: getTranslation(side, 0),\n }),\n close: ({ side }) => ({\n opacity: 0,\n translate: getTranslation(side, 5),\n }),\n },\n );\n\n return (\n <FloatingNode id={nodeId}>\n {React.isValidElement(triggerElement) && (\n <SlotComponent\n {...getReferenceProps({\n ...triggerProps,\n ref: referenceRef,\n role: isNested ? \"menuitem\" : undefined,\n \"aria-controls\": MenuId,\n onClick(event) {\n event.stopPropagation();\n },\n })}\n >\n {triggerElement}\n </SlotComponent>\n )}\n {isMounted && (\n <FloatingPortal>\n <FloatingFocusManager\n context={context}\n // Prevent outside content interference.\n modal={false}\n // Only initially focus the root floating menu.\n initialFocus={isNested ? -1 : 0}\n // Only return focus to the root menu's reference when menus close.\n returnFocus={!isNested}\n >\n <div\n className={clsx(\"jkl jkl-menu\", className)}\n data-theme={theme}\n data-size={size}\n role=\"menu\"\n data-placement={placement}\n aria-live=\"assertive\"\n aria-hidden={!isOpen}\n ref={refs.setFloating}\n {...getFloatingProps({\n id: MenuId,\n style: {\n ...floatingStyles,\n ...animationStyles,\n },\n })}\n >\n {React.Children.map(\n children,\n (child, index) => {\n if (React.isValidElement(child)) {\n return (\n <SlotComponent\n {...getItemProps({\n ...child.props,\n tabIndex:\n activeIndex ===\n index\n ? 0\n : -1,\n role: \"menuitem\",\n ref(\n node: HTMLButtonElement,\n ) {\n listItemsRef.current[\n index\n ] = node;\n },\n onClick(event) {\n if (\n event.defaultPrevented\n ) {\n return;\n }\n tree?.events.emit(\n \"click\",\n );\n },\n onKeyDown(event) {\n child.props.onKeyDown?.(\n event,\n );\n if (\n event.defaultPrevented\n ) {\n return;\n }\n tree?.events.emit(\n \"keydown\",\n );\n if (\n event\n .currentTarget\n .role ===\n \"menuitemcheckbox\" &&\n event.key ===\n \"Enter\"\n ) {\n // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/menuitemcheckbox_role#keyboard_interactions\n setIsOpen(\n false,\n );\n }\n },\n onMouseEnter() {\n if (\n allowHover &&\n isOpen\n ) {\n setActiveIndex(\n index,\n );\n }\n },\n })}\n >\n {child}\n </SlotComponent>\n );\n }\n\n return child;\n },\n )}\n </div>\n </FloatingFocusManager>\n </FloatingPortal>\n )}\n </FloatingNode>\n );\n },\n);\nMenuComponent.displayName = \"MenuComponent\";\n\nexport const Menu = forwardRef<HTMLButtonElement, MenuProps>((props, ref) => {\n const parentId = useFloatingParentNodeId();\n\n if (parentId === null) {\n return (\n <FloatingTree>\n <MenuComponent ref={ref} {...props} />\n </FloatingTree>\n );\n }\n\n return <MenuComponent ref={ref} {...props} />;\n});\n\nMenu.displayName = \"Menu\";\n"],"names":["getTranslation","side","value","MenuComponent","forwardRef","props","forwardedRef","children","className","initialPlacement","openOnHover","keepOpenOnClickOutside","triggerElement","isOpen","isOpenOverride","onToggle","triggerProps","MenuId","useId","prefersReducedMotion","useBrowserPreferences","tree","useFloatingTree","nodeId","useFloatingNodeId","parentId","useFloatingParentNodeId","isNested","listItemsRef","useRef","activeIndex","setActiveIndex","useState","allowHover","isOpenDefault","setIsOpen","useMenuWideEvents","useEffect","refs","placement","context","floatingStyles","useFloating","open","onOpenChange","middleware","offset","flip","fallbackAxisSideDirection","crossAxis","shift","padding","whileElementsMounted","autoUpdate","getReferenceProps","getFloatingProps","getItemProps","useInteractions","useHover","enabled","delay","handleClose","safePolygon","requireIntent","blockPointerEvents","useClick","event","useDismiss","outsidePress","useRole","role","useListNavigation","listRef","nested","onNavigate","referenceRef","useMergeRefs","setReference","theme","size","getThemeAndSize","reference","current","isMounted","styles","animationStyles","useTransitionStyles","duration","close","initial","opacity","translate","jsxs","FloatingNode","id","React","isValidElement","jsx","SlotComponent","ref","onClick","stopPropagation","FloatingPortal","FloatingFocusManager","modal","initialFocus","returnFocus","clsx","setFloating","style","Children","map","child","index","tabIndex","node","defaultPrevented","events","emit","onKeyDown","currentTarget","key","onMouseEnter","displayName","Menu","FloatingTree"],"mappings":"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"}
1
+ {"version":3,"file":"Menu.js","sources":["../../../../src/components/menu/Menu.tsx"],"sourcesContent":["import {\n FloatingFocusManager,\n FloatingNode,\n FloatingPortal,\n FloatingTree,\n type Side,\n autoUpdate,\n flip,\n offset,\n safePolygon,\n shift,\n useClick,\n useDismiss,\n useFloating,\n useFloatingNodeId,\n useFloatingParentNodeId,\n useFloatingTree,\n useHover,\n useInteractions,\n useListNavigation,\n useMergeRefs,\n useRole,\n useTransitionStyles,\n} from \"@floating-ui/react\";\nimport clsx from \"clsx\";\nimport React, { forwardRef, useEffect, useRef, useState, useId } from \"react\";\nimport { useBrowserPreferences } from \"../../hooks/index.js\";\nimport { getThemeAndSize } from \"../../utilities/getThemeAndSize.js\";\nimport { SlotComponent } from \"../../utilities/index.js\";\nimport type { MenuProps } from \"./types.js\";\nimport { useMenuWideEvents } from \"./useMenuWideEvents.js\";\n\nfunction getTranslation(side: Side, value = 0) {\n switch (side) {\n case \"top\":\n return `0 ${value}px`;\n case \"left\":\n return `${value}px 0`;\n case \"bottom\":\n return `0 ${-value}px`;\n case \"right\":\n return `${-value}px 0`;\n\n default:\n return `0 ${value}px`;\n }\n}\n\nconst MenuComponent = forwardRef<HTMLButtonElement, MenuProps>(\n (props, forwardedRef) => {\n const {\n children,\n className,\n initialPlacement,\n openOnHover = false,\n keepOpenOnClickOutside = false,\n triggerElement,\n isOpen: isOpenOverride,\n onToggle,\n ...triggerProps\n } = props;\n\n const MenuId = `\"jkl-menu\"${useId()}`;\n\n const { prefersReducedMotion } = useBrowserPreferences();\n\n const tree = useFloatingTree();\n const nodeId = useFloatingNodeId();\n const parentId = useFloatingParentNodeId();\n const isNested = parentId != null;\n\n const listItemsRef = useRef<Array<HTMLButtonElement | null>>([]);\n const [activeIndex, setActiveIndex] = useState<number | null>(null);\n const {\n allowHover,\n isOpen: isOpenDefault,\n setIsOpen,\n } = useMenuWideEvents(tree, nodeId, parentId);\n\n const isOpen =\n isOpenOverride !== undefined ? isOpenOverride : isOpenDefault;\n\n useEffect(() => onToggle?.(isOpen), [isOpen, onToggle]);\n\n const { refs, placement, context, floatingStyles } = useFloating({\n nodeId,\n open: isOpen,\n onOpenChange: setIsOpen,\n placement:\n initialPlacement || (isNested ? \"right-start\" : \"bottom-start\"),\n middleware: [\n offset(5),\n flip({\n fallbackAxisSideDirection: \"end\", // Allow bottom placement in narrow viewports (https://floating-ui.com/docs/flip#fallbackaxissidedirection)\n crossAxis: false, // See https://floating-ui.com/docs/flip#combining-with-shift\n }),\n shift({ padding: 8 }),\n ],\n whileElementsMounted: autoUpdate,\n });\n\n const { getReferenceProps, getFloatingProps, getItemProps } =\n useInteractions([\n useHover(context, {\n enabled: openOnHover && allowHover,\n delay: { open: 75 },\n handleClose: safePolygon({\n requireIntent: true,\n blockPointerEvents: true,\n }),\n }),\n useClick(context, {\n event: \"mousedown\",\n }),\n useDismiss(context, { outsidePress: !keepOpenOnClickOutside }),\n useRole(context, { role: \"menu\" }),\n useListNavigation(context, {\n listRef: listItemsRef,\n activeIndex,\n nested: isNested,\n onNavigate: setActiveIndex,\n }),\n ]);\n\n const referenceRef = useMergeRefs([refs.setReference, forwardedRef]);\n\n // Siden menyen rendres på rot må vi hente lokal dark/light-verdi fra triggeren\n // Vi må gjøre dette for å ta hensyn til at tema kan styres lokalt for deler av UIet\n const { theme, size } = getThemeAndSize(\n refs.reference.current as HTMLElement,\n );\n\n const { isMounted, styles: animationStyles } = useTransitionStyles(\n context,\n {\n duration: {\n open: prefersReducedMotion ? 0 : 250,\n close: prefersReducedMotion ? 0 : 150,\n },\n initial: ({ side }) => ({\n opacity: 0,\n translate: getTranslation(side, 5),\n }),\n open: ({ side }) => ({\n opacity: 1,\n translate: getTranslation(side, 0),\n }),\n close: ({ side }) => ({\n opacity: 0,\n translate: getTranslation(side, 5),\n }),\n },\n );\n\n return (\n <FloatingNode id={nodeId}>\n {React.isValidElement(triggerElement) && (\n <SlotComponent\n {...getReferenceProps({\n ...triggerProps,\n ref: referenceRef,\n role: isNested ? \"menuitem\" : undefined,\n \"aria-controls\": MenuId,\n onClick(event) {\n event.stopPropagation();\n },\n })}\n >\n {triggerElement}\n </SlotComponent>\n )}\n {isMounted && (\n <FloatingPortal>\n <FloatingFocusManager\n context={context}\n // Prevent outside content interference.\n modal={false}\n // Only initially focus the root floating menu.\n initialFocus={isNested ? -1 : 0}\n // Only return focus to the root menu's reference when menus close.\n returnFocus={!isNested}\n >\n <div\n className={clsx(\"jkl jkl-menu\", className)}\n data-theme={theme}\n data-size={size}\n role=\"menu\"\n data-placement={placement}\n aria-live=\"assertive\"\n aria-hidden={!isOpen}\n ref={refs.setFloating}\n {...getFloatingProps({\n id: MenuId,\n style: {\n ...floatingStyles,\n ...animationStyles,\n },\n })}\n >\n {React.Children.map(\n children,\n (child, index) => {\n if (React.isValidElement(child)) {\n return (\n <SlotComponent\n {...getItemProps({\n ...child.props,\n tabIndex:\n activeIndex ===\n index\n ? 0\n : -1,\n role: \"menuitem\",\n ref(\n node: HTMLButtonElement,\n ) {\n listItemsRef.current[\n index\n ] = node;\n },\n onClick(event) {\n if (\n event.defaultPrevented\n ) {\n return;\n }\n tree?.events.emit(\n \"click\",\n );\n },\n onKeyDown(event) {\n child.props.onKeyDown?.(\n event,\n );\n if (\n event.defaultPrevented\n ) {\n return;\n }\n tree?.events.emit(\n \"keydown\",\n );\n if (\n event\n .currentTarget\n .role ===\n \"menuitemcheckbox\" &&\n event.key ===\n \"Enter\"\n ) {\n // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/menuitemcheckbox_role#keyboard_interactions\n setIsOpen(\n false,\n );\n }\n },\n onMouseEnter() {\n if (\n allowHover &&\n isOpen\n ) {\n setActiveIndex(\n index,\n );\n }\n },\n })}\n >\n {child}\n </SlotComponent>\n );\n }\n\n return child;\n },\n )}\n </div>\n </FloatingFocusManager>\n </FloatingPortal>\n )}\n </FloatingNode>\n );\n },\n);\nMenuComponent.displayName = \"MenuComponent\";\n\nexport const Menu = forwardRef<HTMLButtonElement, MenuProps>((props, ref) => {\n const parentId = useFloatingParentNodeId();\n\n if (parentId === null) {\n return (\n <FloatingTree>\n <MenuComponent ref={ref} {...props} />\n </FloatingTree>\n );\n }\n\n return <MenuComponent ref={ref} {...props} />;\n});\n\nMenu.displayName = \"Menu\";\n"],"names":["getTranslation","side","value","MenuComponent","forwardRef","props","forwardedRef","children","className","initialPlacement","openOnHover","keepOpenOnClickOutside","triggerElement","isOpen","isOpenOverride","onToggle","triggerProps","MenuId","useId","prefersReducedMotion","useBrowserPreferences","tree","useFloatingTree","nodeId","useFloatingNodeId","parentId","useFloatingParentNodeId","isNested","listItemsRef","useRef","activeIndex","setActiveIndex","useState","allowHover","isOpenDefault","setIsOpen","useMenuWideEvents","useEffect","refs","placement","context","floatingStyles","useFloating","open","onOpenChange","middleware","offset","flip","fallbackAxisSideDirection","crossAxis","shift","padding","whileElementsMounted","autoUpdate","getReferenceProps","getFloatingProps","getItemProps","useInteractions","useHover","enabled","delay","handleClose","safePolygon","requireIntent","blockPointerEvents","useClick","event","useDismiss","outsidePress","useRole","role","useListNavigation","listRef","nested","onNavigate","referenceRef","useMergeRefs","setReference","theme","size","getThemeAndSize","reference","current","isMounted","styles","animationStyles","useTransitionStyles","duration","close","initial","opacity","translate","jsxs","FloatingNode","id","React","isValidElement","jsx","SlotComponent","ref","onClick","stopPropagation","FloatingPortal","FloatingFocusManager","modal","initialFocus","returnFocus","clsx","setFloating","style","Children","map","child","index","tabIndex","node","defaultPrevented","events","emit","onKeyDown","currentTarget","key","onMouseEnter","displayName","Menu","FloatingTree"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{jsx as e}from"react/jsx-runtime";import{useMergeRefs as t,FloatingPortal as n,FloatingFocusManager as o,useFloating as s,autoUpdate as r,offset as a,flip as i,shift as l,useClick as c,useHover as u,useFocus as p,useDismiss as d,useRole as m,useInteractions as f}from"@floating-ui/react";import{c as g}from"../../../clsx-BeLtu-UY.js";import*as h from"react";import{getThemeAndSize as v}from"../../utilities/getThemeAndSize.js";const b=h.createContext(null),x=()=>{const e=h.useContext(b);if(null==e)throw new Error("Popover komponenter må brukes innenfor en <Popover /> komponent");return e},k=({children:t,...n})=>{const o=(({open:e,onOpenChange:t,placement:n="bottom-start",strategy:o="absolute",modal:g=!0,offset:v=4,positionReference:b,onPlacementChange:x,hoverOptions:k,focusOptions:C,clickOptions:F,roleOptions:P,dismissOptions:R})=>{const[y,E]=h.useState(e),O=e??y,j=t??E,w=s({open:O,onOpenChange:j,placement:n,strategy:o,middleware:[a(v),i({padding:5,fallbackPlacements:["bottom","top"]}),l({padding:12})],whileElementsMounted:r}),z=w.context,M=c(z,{enabled:!1,...F}),N=u(z,{enabled:!1,...k}),S=p(z,{enabled:!1,...C}),T=d(z,R),A=m(z,P),L=f([M,T,S,N,A]);return h.useLayoutEffect(()=>{b&&w.refs.setPositionReference(b?.current)},[b,w.refs]),h.useLayoutEffect(()=>{O&&x?.(w.placement)},[O,w.placement,x]),h.useMemo(()=>({open:O,onOpenChange:j,modal:g,...L,...w}),[O,j,g,L,w])})({...n});return e(b.Provider,{value:o,children:t})},C=h.forwardRef(function({children:n,asChild:o=!1,...s},r){const{refs:a,getReferenceProps:i,open:l,onOpenChange:c}=x(),u=n.ref,p=t([a.setReference,r,u]);return o&&h.isValidElement(n)?h.cloneElement(n,i({ref:p,...s,...n.props})):e("button",{ref:p,onClick:()=>c?.(!l),"aria-expanded":l,...i({...s,className:g("jkl-popover-trigger",s.className)}),children:n})}),F=h.forwardRef(function({style:s,className:r,padding:a=0,initialFocus:i=0,returnFocus:l=!0,...c},u){const{context:p,modal:d,refs:m,open:f,floatingStyles:b,getFloatingProps:k,isPositioned:C}=x(),F=t([m.setFloating,u]),P=m.reference.current,{theme:R,size:y}=v((O=P)&&"contextElement"in O?P.contextElement:P),E=h.useRef(null);var O;return h.useEffect(()=>{E.current=p.elements.domReference?.closest("[data-portal]")||document.body},[p.elements.domReference]),f?e(n,{root:E.current,children:e(o,{context:p,modal:d,initialFocus:i,returnFocus:l,children:e("div",{"data-theme":R,"data-size":y,className:g("jkl jkl-popover",r),ref:F,style:{...s,...b,"--popover-padding":`var(--jkl-spacing-${a})`,visibility:d||C?"visible":"hidden"},...k(c),children:c.children})})}):null});k.Trigger=C,k.Content=F;export{k as Popover,k as default};
1
+ import{jsx as e}from"react/jsx-runtime";import{useMergeRefs as t,FloatingPortal as n,FloatingFocusManager as o,useFloating as s,autoUpdate as r,offset as a,flip as i,shift as l,size as c,useClick as p,useHover as d,useFocus as u,useDismiss as f,useRole as m,useInteractions as g}from"@floating-ui/react";import{c as h}from"../../../clsx-BeLtu-UY.js";import*as v from"react";import{getThemeAndSize as x}from"../../utilities/getThemeAndSize.js";const b=v.createContext(null),R=()=>{const e=v.useContext(b);if(null==e)throw new Error("Popover komponenter må brukes innenfor en <Popover /> komponent");return e},k=({children:t,...n})=>{const o=(({open:e,onOpenChange:t,placement:n="bottom-start",strategy:o="absolute",modal:h=!0,offset:x=4,positionReference:b,onPlacementChange:R,matchReferenceWidth:k=!1,hoverOptions:y,focusOptions:C,clickOptions:F,roleOptions:P,dismissOptions:E})=>{const[O,j]=v.useState(e),w=e??O,z=t??j,M=s({open:w,onOpenChange:z,placement:n,strategy:o,middleware:[a(x),i({padding:5,fallbackPlacements:["bottom","top"]}),l({padding:12}),...k?[c({apply({rects:e,elements:t}){t.floating.style.width=`${e.reference.width}px`}})]:[]],whileElementsMounted:r}),N=M.context,S=p(N,{enabled:!1,...F}),T=d(N,{enabled:!1,...y}),A=u(N,{enabled:!1,...C}),L=f(N,E),$=m(N,P),D=g([S,L,A,T,$]);return v.useLayoutEffect(()=>{b&&M.refs.setPositionReference(b?.current)},[b,M.refs]),v.useLayoutEffect(()=>{w&&R?.(M.placement)},[w,M.placement,R]),v.useMemo(()=>({open:w,onOpenChange:z,modal:h,...D,...M}),[w,z,h,D,M])})({...n});return e(b.Provider,{value:o,children:t})},y=v.forwardRef(function({children:n,asChild:o=!1,...s},r){const{refs:a,getReferenceProps:i,open:l,onOpenChange:c}=R(),p=n.ref,d=t([a.setReference,r,p]);return o&&v.isValidElement(n)?v.cloneElement(n,i({ref:d,...s,...n.props})):e("button",{ref:d,onClick:()=>c?.(!l),"aria-expanded":l,...i({...s,className:h("jkl-popover-trigger",s.className)}),children:n})}),C=v.forwardRef(function({style:s,className:r,padding:a=0,initialFocus:i=0,returnFocus:l=!0,...c},p){const{context:d,modal:u,refs:f,open:m,floatingStyles:g,getFloatingProps:b,isPositioned:k}=R(),y=t([f.setFloating,p]),C=f.reference.current,{theme:F,size:P}=x((O=C)&&"contextElement"in O?C.contextElement:C),E=v.useRef(null);var O;return v.useEffect(()=>{E.current=d.elements.domReference?.closest("[data-portal]")||document.body},[d.elements.domReference]),m?e(n,{root:E.current,children:e(o,{context:d,modal:u,initialFocus:i,returnFocus:l,children:e("div",{"data-theme":F,"data-size":P,className:h("jkl jkl-popover",r),ref:y,style:{...s,...g,"--popover-padding":`var(--jkl-spacing-${a})`,visibility:u||k?"visible":"hidden"},...b(c),children:c.children})})}):null});k.Trigger=y,k.Content=C;export{k as Popover,k as default};
2
2
  //# sourceMappingURL=Popover.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Popover.js","sources":["../../../../src/components/popover/Popover.tsx"],"sourcesContent":["import {\n FloatingFocusManager,\n FloatingPortal,\n type ReferenceElement,\n type VirtualElement,\n autoUpdate,\n flip,\n offset,\n shift,\n useClick,\n useDismiss,\n useFloating,\n useFocus,\n useHover,\n useInteractions,\n useMergeRefs,\n useRole,\n} from \"@floating-ui/react\";\nimport clsx from \"clsx\";\nimport * as React from \"react\";\nimport { getThemeAndSize } from \"../../utilities/getThemeAndSize.js\";\nimport type { PopoverOptions } from \"./types.js\";\n\nconst usePopover = ({\n open: _open,\n onOpenChange: _onOpenChange,\n placement = \"bottom-start\",\n strategy = \"absolute\",\n modal = true,\n offset: _offset = 4,\n positionReference,\n onPlacementChange,\n hoverOptions,\n focusOptions,\n clickOptions,\n roleOptions,\n dismissOptions,\n}: PopoverOptions) => {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(_open);\n\n const open = _open ?? uncontrolledOpen;\n const onOpenChange = _onOpenChange ?? setUncontrolledOpen;\n\n const data = useFloating({\n open,\n onOpenChange,\n placement,\n strategy,\n middleware: [\n offset(_offset),\n flip({ padding: 5, fallbackPlacements: [\"bottom\", \"top\"] }),\n shift({ padding: 12 }),\n ],\n whileElementsMounted: autoUpdate,\n });\n\n const context = data.context;\n\n const click = useClick(context, {\n enabled: false,\n ...clickOptions,\n });\n const hover = useHover(context, { enabled: false, ...hoverOptions });\n const focus = useFocus(context, { enabled: false, ...focusOptions });\n const dismiss = useDismiss(context, dismissOptions);\n const role = useRole(context, roleOptions);\n\n const interactions = useInteractions([click, dismiss, focus, hover, role]);\n\n React.useLayoutEffect(() => {\n if (positionReference) {\n data.refs.setPositionReference(positionReference?.current);\n }\n }, [positionReference, data.refs]);\n\n // useLayoutEffect (i stedet for useEffect) sikrer at konsumenter får\n // riktig placement før paint — ellers ville første frame bruke default\n // placement og deretter snappe over til den faktiske, noe som gir et\n // synlig \"glitch\" på styling som er placement-avhengig (f.eks. flat side\n // / border-radius på Select-listboxen ved flip).\n React.useLayoutEffect(() => {\n if (!open) return;\n onPlacementChange?.(data.placement);\n }, [open, data.placement, onPlacementChange]);\n\n return React.useMemo(\n () => ({\n open,\n onOpenChange,\n modal,\n ...interactions,\n ...data,\n }),\n [open, onOpenChange, modal, interactions, data],\n );\n};\n\ntype PopoverContextType = ReturnType<typeof usePopover> | null;\n\nconst PopoverContext = React.createContext<PopoverContextType>(null);\n\nconst usePopoverContext = () => {\n const context = React.useContext(PopoverContext);\n\n if (context == null) {\n throw new Error(\n \"Popover komponenter må brukes innenfor en <Popover /> komponent\",\n );\n }\n\n return context;\n};\n\nexport const Popover = ({\n children,\n ...restOptions\n}: {\n children: React.ReactNode;\n} & PopoverOptions) => {\n const popover = usePopover({ ...restOptions });\n return (\n <PopoverContext.Provider value={popover}>\n {children}\n </PopoverContext.Provider>\n );\n};\n\ninterface PopoverTriggerProps {\n children: React.ReactNode;\n /**\n * Rendrer komponenten som child-elementet sitt, og slår sammen egenskaper og props.\n *\n * Default er `false`.\n *\n * @example\n * ```tsx\n * <Component asChild foo=\"bar\">\n * <Child baz=\"qux\" />\n * </Component>\n *\n * // Rendrer følgende:\n * <Child foo=\"bar\" baz=\"qux\" />\n * ```\n */\n asChild?: boolean;\n}\n\nconst PopoverTrigger = React.forwardRef<\n HTMLElement,\n React.HTMLProps<HTMLElement> & PopoverTriggerProps\n>(function PopoverTrigger({ children, asChild = false, ...props }, propRef) {\n const { refs, getReferenceProps, open, onOpenChange } = usePopoverContext();\n const childrenRef = (children as any).ref;\n const ref = useMergeRefs([refs.setReference, propRef, childrenRef]);\n\n if (asChild && React.isValidElement(children)) {\n return React.cloneElement(\n children,\n getReferenceProps({\n ref,\n ...props,\n ...children.props,\n }),\n );\n }\n\n return (\n <button\n ref={ref}\n onClick={() => onOpenChange?.(!open)}\n aria-expanded={open}\n {...getReferenceProps({\n ...props,\n className: clsx(\"jkl-popover-trigger\", props.className),\n })}\n >\n {children}\n </button>\n );\n});\n\ninterface PopoverContentProps {\n /**\n * Padding rundt innholdet i popoveren.\n *\n * Default er `0`.\n */\n padding?: 0 | 8 | 16 | 24;\n /**\n *\n * Angir hvilket element som skal motta fokus ved åpning.\n * Kan være en tabbar index eller en referanse til et element.\"\n *\n * Default er `0`, som betyr at det første fokuserbare elementet i popoveren får fokus.\n * @see https://floating-ui.com/docs/FloatingFocusManager#initialfocus\n */\n initialFocus?: number | React.RefObject<HTMLElement>;\n /**\n * Angir om fokus skal returneres til triggeren når popoveren lukkes.\n *\n * Default er `true`.\n * @see https://floating-ui.com/docs/FloatingFocusManager#returnfocus\n */\n returnFocus?: boolean;\n}\n\n// Er popover-elementet posisjonert i forhold til et annet element enn triggeren?\nconst isCustomPositioned = (\n referenceElement: ReferenceElement,\n): referenceElement is VirtualElement => {\n if (!referenceElement) return false;\n\n return \"contextElement\" in referenceElement;\n};\n\nconst PopoverContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLProps<HTMLDivElement> & PopoverContentProps\n>(function PopoverContent(\n {\n style,\n className,\n padding = 0,\n initialFocus = 0,\n returnFocus = true,\n ...props\n },\n propRef,\n) {\n const {\n context,\n modal,\n refs,\n open,\n floatingStyles,\n getFloatingProps,\n isPositioned,\n } = usePopoverContext();\n const ref = useMergeRefs([refs.setFloating, propRef]);\n\n const referenceElement = refs.reference.current as ReferenceElement;\n\n const { theme, size } = isCustomPositioned(referenceElement)\n ? getThemeAndSize(referenceElement.contextElement)\n : getThemeAndSize(referenceElement);\n\n const floatingPortalRef = React.useRef<HTMLElement | null>(null);\n\n // TODO: Løser et problem hvor nestede portaler ikke \"fester\" seg til det nærmeste portal-elementet. Fjernes når alle komponenter som rendres i en portal tar i bruk popover komponenten da den håndterer dette internt. Issue: https://github.com/fremtind/jokul/issues/4356\n React.useEffect(() => {\n floatingPortalRef.current =\n context.elements.domReference?.closest<HTMLElement>(\n \"[data-portal]\",\n ) || document.body;\n }, [context.elements.domReference]);\n\n if (!open) return null;\n\n return (\n <FloatingPortal root={floatingPortalRef.current}>\n <FloatingFocusManager\n context={context}\n modal={modal}\n initialFocus={initialFocus}\n returnFocus={returnFocus}\n >\n <div\n data-theme={theme}\n data-size={size}\n className={clsx(\"jkl jkl-popover\", className)}\n ref={ref}\n style={\n {\n ...style,\n ...floatingStyles,\n \"--popover-padding\": `var(--jkl-spacing-${padding})`,\n // Skjul popoveren inntil floating-ui har regnet\n // ut første posisjon — ellers blinker den\n // kort i (0,0) før den hopper på plass.\n // Bare for ikke-modale popovere; modale bruker\n // umiddelbar fokus-trap som forutsetter at\n // innholdet er fokuserbart fra første render.\n visibility:\n modal || isPositioned ? \"visible\" : \"hidden\",\n } as React.CSSProperties\n }\n {...getFloatingProps(props)}\n >\n {props.children}\n </div>\n </FloatingFocusManager>\n </FloatingPortal>\n );\n});\n\nPopover.Trigger = PopoverTrigger;\nPopover.Content = PopoverContent;\n\nexport default Popover;\n"],"names":["PopoverContext","React","createContext","usePopoverContext","context","useContext","Error","Popover","children","restOptions","popover","open","_open","onOpenChange","_onOpenChange","placement","strategy","modal","offset","_offset","positionReference","onPlacementChange","hoverOptions","focusOptions","clickOptions","roleOptions","dismissOptions","uncontrolledOpen","setUncontrolledOpen","useState","data","useFloating","middleware","flip","padding","fallbackPlacements","shift","whileElementsMounted","autoUpdate","click","useClick","enabled","hover","useHover","focus","useFocus","dismiss","useDismiss","role","useRole","interactions","useInteractions","useLayoutEffect","refs","setPositionReference","current","useMemo","usePopover","Provider","value","PopoverTrigger","forwardRef","asChild","props","propRef","getReferenceProps","childrenRef","ref","useMergeRefs","setReference","isValidElement","cloneElement","jsx","onClick","className","clsx","PopoverContent","style","initialFocus","returnFocus","floatingStyles","getFloatingProps","isPositioned","setFloating","referenceElement","reference","theme","size","getThemeAndSize","contextElement","floatingPortalRef","useRef","useEffect","elements","domReference","closest","document","body","FloatingPortal","root","FloatingFocusManager","visibility","Trigger","Content"],"mappings":"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"}
1
+ {"version":3,"file":"Popover.js","sources":["../../../../src/components/popover/Popover.tsx"],"sourcesContent":["import {\n FloatingFocusManager,\n FloatingPortal,\n type ReferenceElement,\n type VirtualElement,\n autoUpdate,\n flip,\n offset,\n shift,\n size,\n useClick,\n useDismiss,\n useFloating,\n useFocus,\n useHover,\n useInteractions,\n useMergeRefs,\n useRole,\n} from \"@floating-ui/react\";\nimport clsx from \"clsx\";\nimport * as React from \"react\";\nimport { getThemeAndSize } from \"../../utilities/getThemeAndSize.js\";\nimport type { PopoverOptions } from \"./types.js\";\n\nconst usePopover = ({\n open: _open,\n onOpenChange: _onOpenChange,\n placement = \"bottom-start\",\n strategy = \"absolute\",\n modal = true,\n offset: _offset = 4,\n positionReference,\n onPlacementChange,\n matchReferenceWidth = false,\n hoverOptions,\n focusOptions,\n clickOptions,\n roleOptions,\n dismissOptions,\n}: PopoverOptions) => {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(_open);\n\n const open = _open ?? uncontrolledOpen;\n const onOpenChange = _onOpenChange ?? setUncontrolledOpen;\n\n const data = useFloating({\n open,\n onOpenChange,\n placement,\n strategy,\n middleware: [\n offset(_offset),\n flip({ padding: 5, fallbackPlacements: [\"bottom\", \"top\"] }),\n shift({ padding: 12 }),\n ...(matchReferenceWidth\n ? [\n size({\n apply({ rects, elements }) {\n elements.floating.style.width = `${rects.reference.width}px`;\n },\n }),\n ]\n : []),\n ],\n whileElementsMounted: autoUpdate,\n });\n\n const context = data.context;\n\n const click = useClick(context, {\n enabled: false,\n ...clickOptions,\n });\n const hover = useHover(context, { enabled: false, ...hoverOptions });\n const focus = useFocus(context, { enabled: false, ...focusOptions });\n const dismiss = useDismiss(context, dismissOptions);\n const role = useRole(context, roleOptions);\n\n const interactions = useInteractions([click, dismiss, focus, hover, role]);\n\n React.useLayoutEffect(() => {\n if (positionReference) {\n data.refs.setPositionReference(positionReference?.current);\n }\n }, [positionReference, data.refs]);\n\n // useLayoutEffect (i stedet for useEffect) sikrer at konsumenter får\n // riktig placement før paint — ellers ville første frame bruke default\n // placement og deretter snappe over til den faktiske, noe som gir et\n // synlig \"glitch\" på styling som er placement-avhengig (f.eks. flat side\n // / border-radius på Select-listboxen ved flip).\n React.useLayoutEffect(() => {\n if (!open) return;\n onPlacementChange?.(data.placement);\n }, [open, data.placement, onPlacementChange]);\n\n return React.useMemo(\n () => ({\n open,\n onOpenChange,\n modal,\n ...interactions,\n ...data,\n }),\n [open, onOpenChange, modal, interactions, data],\n );\n};\n\ntype PopoverContextType = ReturnType<typeof usePopover> | null;\n\nconst PopoverContext = React.createContext<PopoverContextType>(null);\n\nconst usePopoverContext = () => {\n const context = React.useContext(PopoverContext);\n\n if (context == null) {\n throw new Error(\n \"Popover komponenter må brukes innenfor en <Popover /> komponent\",\n );\n }\n\n return context;\n};\n\nexport const Popover = ({\n children,\n ...restOptions\n}: {\n children: React.ReactNode;\n} & PopoverOptions) => {\n const popover = usePopover({ ...restOptions });\n return (\n <PopoverContext.Provider value={popover}>\n {children}\n </PopoverContext.Provider>\n );\n};\n\ninterface PopoverTriggerProps {\n children: React.ReactNode;\n /**\n * Rendrer komponenten som child-elementet sitt, og slår sammen egenskaper og props.\n *\n * Default er `false`.\n *\n * @example\n * ```tsx\n * <Component asChild foo=\"bar\">\n * <Child baz=\"qux\" />\n * </Component>\n *\n * // Rendrer følgende:\n * <Child foo=\"bar\" baz=\"qux\" />\n * ```\n */\n asChild?: boolean;\n}\n\nconst PopoverTrigger = React.forwardRef<\n HTMLElement,\n React.HTMLProps<HTMLElement> & PopoverTriggerProps\n>(function PopoverTrigger({ children, asChild = false, ...props }, propRef) {\n const { refs, getReferenceProps, open, onOpenChange } = usePopoverContext();\n const childrenRef = (children as any).ref;\n const ref = useMergeRefs([refs.setReference, propRef, childrenRef]);\n\n if (asChild && React.isValidElement(children)) {\n return React.cloneElement(\n children,\n getReferenceProps({\n ref,\n ...props,\n ...children.props,\n }),\n );\n }\n\n return (\n <button\n ref={ref}\n onClick={() => onOpenChange?.(!open)}\n aria-expanded={open}\n {...getReferenceProps({\n ...props,\n className: clsx(\"jkl-popover-trigger\", props.className),\n })}\n >\n {children}\n </button>\n );\n});\n\ninterface PopoverContentProps {\n /**\n * Padding rundt innholdet i popoveren.\n *\n * Default er `0`.\n */\n padding?: 0 | 8 | 16 | 24;\n /**\n *\n * Angir hvilket element som skal motta fokus ved åpning.\n * Kan være en tabbar index eller en referanse til et element.\"\n *\n * Default er `0`, som betyr at det første fokuserbare elementet i popoveren får fokus.\n * @see https://floating-ui.com/docs/FloatingFocusManager#initialfocus\n */\n initialFocus?: number | React.RefObject<HTMLElement>;\n /**\n * Angir om fokus skal returneres til triggeren når popoveren lukkes.\n *\n * Default er `true`.\n * @see https://floating-ui.com/docs/FloatingFocusManager#returnfocus\n */\n returnFocus?: boolean;\n}\n\n// Er popover-elementet posisjonert i forhold til et annet element enn triggeren?\nconst isCustomPositioned = (\n referenceElement: ReferenceElement,\n): referenceElement is VirtualElement => {\n if (!referenceElement) return false;\n\n return \"contextElement\" in referenceElement;\n};\n\nconst PopoverContent = React.forwardRef<\n HTMLDivElement,\n React.HTMLProps<HTMLDivElement> & PopoverContentProps\n>(function PopoverContent(\n {\n style,\n className,\n padding = 0,\n initialFocus = 0,\n returnFocus = true,\n ...props\n },\n propRef,\n) {\n const {\n context,\n modal,\n refs,\n open,\n floatingStyles,\n getFloatingProps,\n isPositioned,\n } = usePopoverContext();\n const ref = useMergeRefs([refs.setFloating, propRef]);\n\n const referenceElement = refs.reference.current as ReferenceElement;\n\n const { theme, size } = isCustomPositioned(referenceElement)\n ? getThemeAndSize(referenceElement.contextElement)\n : getThemeAndSize(referenceElement);\n\n const floatingPortalRef = React.useRef<HTMLElement | null>(null);\n\n // TODO: Løser et problem hvor nestede portaler ikke \"fester\" seg til det nærmeste portal-elementet. Fjernes når alle komponenter som rendres i en portal tar i bruk popover komponenten da den håndterer dette internt. Issue: https://github.com/fremtind/jokul/issues/4356\n React.useEffect(() => {\n floatingPortalRef.current =\n context.elements.domReference?.closest<HTMLElement>(\n \"[data-portal]\",\n ) || document.body;\n }, [context.elements.domReference]);\n\n if (!open) return null;\n\n return (\n <FloatingPortal root={floatingPortalRef.current}>\n <FloatingFocusManager\n context={context}\n modal={modal}\n initialFocus={initialFocus}\n returnFocus={returnFocus}\n >\n <div\n data-theme={theme}\n data-size={size}\n className={clsx(\"jkl jkl-popover\", className)}\n ref={ref}\n style={\n {\n ...style,\n ...floatingStyles,\n \"--popover-padding\": `var(--jkl-spacing-${padding})`,\n // Skjul popoveren inntil floating-ui har regnet\n // ut første posisjon — ellers blinker den\n // kort i (0,0) før den hopper på plass.\n // Bare for ikke-modale popovere; modale bruker\n // umiddelbar fokus-trap som forutsetter at\n // innholdet er fokuserbart fra første render.\n visibility:\n modal || isPositioned ? \"visible\" : \"hidden\",\n } as React.CSSProperties\n }\n {...getFloatingProps(props)}\n >\n {props.children}\n </div>\n </FloatingFocusManager>\n </FloatingPortal>\n );\n});\n\nPopover.Trigger = PopoverTrigger;\nPopover.Content = PopoverContent;\n\nexport default Popover;\n"],"names":["PopoverContext","React","createContext","usePopoverContext","context","useContext","Error","Popover","children","restOptions","popover","open","_open","onOpenChange","_onOpenChange","placement","strategy","modal","offset","_offset","positionReference","onPlacementChange","matchReferenceWidth","hoverOptions","focusOptions","clickOptions","roleOptions","dismissOptions","uncontrolledOpen","setUncontrolledOpen","useState","data","useFloating","middleware","flip","padding","fallbackPlacements","shift","size","apply","rects","elements","floating","style","width","reference","whileElementsMounted","autoUpdate","click","useClick","enabled","hover","useHover","focus","useFocus","dismiss","useDismiss","role","useRole","interactions","useInteractions","useLayoutEffect","refs","setPositionReference","current","useMemo","usePopover","Provider","value","PopoverTrigger","forwardRef","asChild","props","propRef","getReferenceProps","childrenRef","ref","useMergeRefs","setReference","isValidElement","cloneElement","jsx","onClick","className","clsx","PopoverContent","initialFocus","returnFocus","floatingStyles","getFloatingProps","isPositioned","setFloating","referenceElement","theme","getThemeAndSize","contextElement","floatingPortalRef","useRef","useEffect","domReference","closest","document","body","FloatingPortal","root","FloatingFocusManager","visibility","Trigger","Content"],"mappings":"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"}
@@ -65,6 +65,16 @@ export interface PopoverOptions {
65
65
  * popoveren ligger over eller under referansen.
66
66
  */
67
67
  onPlacementChange?: (placement: Placement) => void;
68
+ /**
69
+ * Setter bredden på popoveren lik bredden på referanse-elementet.
70
+ * Referanse-elementet er vanligvis `Popover.Trigger`, men kan overstyres
71
+ * med `positionReference`.
72
+ *
73
+ * @see https://floating-ui.com/docs/size#match-reference-width
74
+ *
75
+ * @default false
76
+ */
77
+ matchReferenceWidth?: boolean;
68
78
  /**
69
79
  * Options for hover-interaksjoner.
70
80
  *
@@ -1 +1 @@
1
- {"version":3,"file":"RadioButton.js","sources":["../../../../src/components/radio-button/RadioButton.tsx"],"sourcesContent":["import React, { forwardRef } from \"react\";\nimport { useId } from \"../../hooks/useId/useId.js\";\nimport { SupportLabel } from \"../input-group/SupportLabel.js\";\nimport { BaseRadioButton } from \"./BaseRadioButton.js\";\nimport { useRadioGroupContext } from \"./radioGroupContext.js\";\nimport type { RadioButtonProps } from \"./types.js\";\n\nexport const RadioButton = forwardRef<HTMLInputElement, RadioButtonProps>(\n (props, ref) => {\n const { checked, value, supportLabelProps, helpLabel, ...rest } = props;\n const { value: selectedValue, ...context } = useRadioGroupContext();\n const supportId = useId(\"jkl-support-label\");\n\n return (\n <>\n <BaseRadioButton\n {...context}\n {...rest}\n ref={ref}\n checked={\n typeof checked !== \"undefined\"\n ? checked\n : typeof selectedValue !== \"undefined\"\n ? value === selectedValue\n : undefined\n }\n value={value}\n aria-describedby={helpLabel ? supportId : undefined}\n />\n <SupportLabel\n {...supportLabelProps}\n label={helpLabel}\n labelType={\"help\"}\n id={supportId}\n />\n </>\n );\n },\n);\n\nRadioButton.displayName = \"RadioButton\";\n"],"names":["RadioButton","forwardRef","props","ref","checked","value","supportLabelProps","helpLabel","rest","selectedValue","context","useRadioGroupContext","supportId","useId","jsxs","Fragment","children","jsx","BaseRadioButton","SupportLabel","label","labelType","id","displayName"],"mappings":"yUAOO,MAAMA,EAAcC,EACvB,CAACC,EAAOC,KACJ,MAAQC,QAAAA,EAASC,MAAAA,EAAOC,kBAAAA,EAAmBC,UAAAA,KAAcC,GAASN,GAC1DG,MAAOI,KAAkBC,GAAYC,IACvCC,EAAYC,EAAM,qBAExB,OACIC,EAAAC,EAAA,CACIC,SAAA,CAAAC,EAACC,EAAA,IACOR,KACAF,EACJL,IAAAA,EACAC,eACWA,EAAY,IACbA,SACOK,EAAkB,IACvBJ,IAAUI,OACV,EAEZJ,MAAAA,EACA,mBAAkBE,EAAYK,OAAY,IAE9CK,EAACE,EAAA,IACOb,EACJc,MAAOb,EACPc,UAAW,OACXC,GAAIV,SAOxBZ,EAAYuB,YAAc"}
1
+ {"version":3,"file":"RadioButton.js","sources":["../../../../src/components/radio-button/RadioButton.tsx"],"sourcesContent":["import React, { forwardRef } from \"react\";\nimport { useId } from \"../../hooks/useId/useId.js\";\nimport { SupportLabel } from \"../input-group/SupportLabel.js\";\nimport { BaseRadioButton } from \"./BaseRadioButton.js\";\nimport { useRadioGroupContext } from \"./radioGroupContext.js\";\nimport type { RadioButtonProps } from \"./types.js\";\n\nexport const RadioButton = forwardRef<HTMLInputElement, RadioButtonProps>(\n (props, ref) => {\n const { checked, value, supportLabelProps, helpLabel, ...rest } = props;\n const { value: selectedValue, ...context } = useRadioGroupContext();\n\n const supportId = useId(\"jkl-support-label\");\n\n return (\n <>\n <BaseRadioButton\n {...context}\n {...rest}\n ref={ref}\n checked={\n typeof checked !== \"undefined\"\n ? checked\n : typeof selectedValue !== \"undefined\"\n ? value === selectedValue\n : undefined\n }\n value={value}\n aria-describedby={helpLabel ? supportId : undefined}\n />\n <SupportLabel\n {...supportLabelProps}\n label={helpLabel}\n labelType={\"help\"}\n id={supportId}\n />\n </>\n );\n },\n);\n\nRadioButton.displayName = \"RadioButton\";\n"],"names":["RadioButton","forwardRef","props","ref","checked","value","supportLabelProps","helpLabel","rest","selectedValue","context","useRadioGroupContext","supportId","useId","jsxs","Fragment","children","jsx","BaseRadioButton","SupportLabel","label","labelType","id","displayName"],"mappings":"yUAOO,MAAMA,EAAcC,EACvB,CAACC,EAAOC,KACJ,MAAQC,QAAAA,EAASC,MAAAA,EAAOC,kBAAAA,EAAmBC,UAAAA,KAAcC,GAASN,GAC1DG,MAAOI,KAAkBC,GAAYC,IAEvCC,EAAYC,EAAM,qBAExB,OACIC,EAAAC,EAAA,CACIC,SAAA,CAAAC,EAACC,EAAA,IACOR,KACAF,EACJL,IAAAA,EACAC,eACWA,EAAY,IACbA,SACOK,EAAkB,IACvBJ,IAAUI,OACV,EAEZJ,MAAAA,EACA,mBAAkBE,EAAYK,OAAY,IAE9CK,EAACE,EAAA,IACOb,EACJc,MAAOb,EACPc,UAAW,OACXC,GAAIV,SAOxBZ,EAAYuB,YAAc"}
@@ -1,2 +1,2 @@
1
- import{jsxs as e,Fragment as t,jsx as o}from"react/jsx-runtime";import{c as r}from"../../../clsx-BeLtu-UY.js";import n,{forwardRef as a,useState as s,useCallback as l,useMemo as i,useRef as c,useEffect as u}from"react";import{useId as p}from"../../hooks/useId/useId.js";import{useListNavigation as d}from"../../hooks/useListNavigation/useListNavigation.js";import{usePreviousValue as v}from"../../hooks/usePreviousValue/usePreviousValue.js";import{getValuePair as m}from"../../utilities/valuePair.js";import{ArrowVerticalAnimated as f}from"../icon/icons/animated/ArrowVerticalAnimated.js";import{InputGroup as b}from"../input-group/InputGroup.js";import{Popover as h}from"../popover/Popover.js";import{focusSelected as k,toLower as g}from"./select-utils.js";const y=()=>{},_=a((a,_)=>{const{id:j,name:w,items:P,value:$,label:x,labelProps:D,onChange:E,onBlur:L,onFocus:N,className:C,helpLabel:F,errorLabel:A,invalid:S,searchable:V=!1,inline:T=!1,defaultPrompt:I="Velg",width:O,maxShownOptions:K=5,style:B,tooltip:M,"data-testautoid":q,...z}=a,G=p(j||"jkl-select",{generateSuffix:!j}),R=`${G}_label`,U=`${G}_button`,W=`${G}_search-input`,Z=`--${G.replace(/[^a-zA-Z0-9-]/g,"-")}-anchor`,[H,J]=s(!1),Q=l(()=>{J(e=>!e)},[]),[X,Y]=s("bottom"),ee=l(e=>{Y(e.startsWith("top")?"top":"bottom")},[]),te=!!V,oe=te&&H,[re,ne]=s(""),ae=l(e=>!!e.label.toLowerCase().includes(re.toLowerCase())||"function"==typeof V&&V(re,e),[V,re]),se=i(()=>P.map(m).map(e=>{const t=!te||""===re||ae(e);return{...e,visible:t}}),[P,te,re,ae]),le=i(()=>!(typeof $>"u")&&P.some(e=>"string"==typeof e?e===$:e.value===$),[$,P]),[ie,ce]=s(le&&void 0!==$?$:""),ue=""!==ie,pe=i(()=>se.find(e=>e.value===ie)?.label||I,[se,ie,I]),de=c(null),ve=l(e=>{de.current=e,_&&("function"==typeof _?_(e):_.current=e),e&&ce(e.value)},[_]),me=v($);u(()=>{$!==me&&ce(typeof $>"u"||!le?"":$)},[$,me,le]);const fe=l(e=>{const t=e.value;ne(""),ce(t),Q(),ye.current?.focus()},[Q]),be=v(ie);u(()=>{typeof be>"u"||be===ie||ie===$||(E&&E({type:"change",target:{name:w,value:ie}}),de.current&&de.current.dispatchEvent(new Event("change",{bubbles:!0})))},[E,w,$,ie,be]);const he=c(null),ke=c(!1),ge=c(null),ye=c(null),_e=c(null),[je,we]=s(null),Pe=c(te),$e=c(ie);u(()=>{Pe.current=te,$e.current=ie});const xe=l(e=>{_e.current=e,we(e),e&&!Pe.current&&requestAnimationFrame(()=>{_e.current===e&&k(e,$e.current)})},[]),De=v(H);u(()=>{H!==De&&(H&&te?ge.current?.focus():!H&&ke.current&&ye.current&&ye.current.focus())},[H,De,te]),d({element:je});const Ee=l(()=>{te&&ne(""),L&&(L({type:"blur",target:{name:w,value:ie}}),de.current?.dispatchEvent(new Event("focusout",{bubbles:!0}))),ke.current=!1,J(!1)},[L,te,w,ie]),Le=l(e=>{const t=he.current,o=_e.current;t?.contains(e.relatedTarget)||o?.contains(e.relatedTarget)||Ee()},[Ee]),Ne=l(()=>{ke.current||(N&&N({type:"change",target:{name:w,value:ie}}),ke.current=!0)},[N,ie,w]),Ce=l(e=>{e.target.focus({preventScroll:!0})},[]);u(()=>{const e=de.current;if(!e)return;const t=()=>{oe?ge.current?.focus():ye.current?.focus()},o=e=>{const t=e.relatedTarget,o=he.current?.contains(t),r=_e.current?.contains(t);(o||r)&&e.preventDefault()};return e.addEventListener("focus",t),e.addEventListener("blur",o),()=>{e.removeEventListener("focus",t),e.removeEventListener("blur",o)}},[oe]);const Fe=l(e=>{"ArrowDown"!==e.key&&" "!==e.key||H?"Escape"===e.key&&(e.preventDefault(),e.stopPropagation(),J(!1)):(e.preventDefault(),e.stopPropagation(),J(!0))},[H]),Ae=l(e=>{if("ArrowDown"===e.key){e.preventDefault(),e.stopPropagation();const t=_e.current;t&&k(t,te?void 0:ie)}else if("Escape"===e.key)e.preventDefault(),e.stopPropagation(),J(!1);else if("Tab"!==e.key||e.shiftKey)"Enter"===e.key&&H&&(e.preventDefault(),e.stopPropagation());else{const t=_e.current;t&&(e.preventDefault(),e.stopPropagation(),k(t,ie))}},[ie,te,H]),Se=l(e=>{if("Tab"===e.key)e.preventDefault(),e.stopPropagation(),e.shiftKey&&ge.current?ge.current.focus():ye.current&&(ce(e.currentTarget.value),J(!1),ye.current.focus());else if("ArrowUp"===e.key&&_e.current&&ge.current){const t=_e.current.querySelector('[role="option"]:not([hidden])');e.currentTarget.id===t?.id&&ge.current&&ge.current.focus()}},[]);return u(()=>{const e=e=>{"Escape"===e.key&&H&&J(!1)};return typeof window<"u"&&H&&window.addEventListener("keydown",e),()=>{typeof window<"u"&&window.removeEventListener("keydown",e)}},[H]),e(t,{children:[e("select",{name:w,tabIndex:-1,"data-testid":"jkl-native-select",className:"jkl-sr-only","aria-hidden":!0,ref:ve,value:ie,onChange:y,children:[o("option",{value:""})," ",se.map(e=>o("option",{hidden:!e.visible,value:e.value,children:e.label},`${G}-opt-${e.value}`))]}),o(b,{ref:he,"data-testid":"jkl-select",className:r("jkl-select",C,{"jkl-select--inline":T,"jkl-select--open":H&&se.some(e=>e.visible),"jkl-select--no-value":!ue,"jkl-select--invalid":!!A||S}),"data-testautoid":q,tooltip:M&&n.isValidElement(M)?n.cloneElement(M,{triggerProps:{...M.props.triggerProps,onFocus:e=>{M.props.triggerProps?.onFocus?.(e),Ee()}}}):null,...z,id:te?W:U,style:B,label:x,labelProps:{id:R,srOnly:T,...D,htmlFor:te?W:U},helpLabel:F,errorLabel:A,render:({"aria-invalid":t,...n})=>{const a=H&&se.some(e=>e.visible);return e(h,{open:a,placement:"bottom-start",offset:0,modal:!1,onPlacementChange:ee,clickOptions:{enabled:!1},dismissOptions:{enabled:!1},roleOptions:{enabled:!1},children:[o(h.Trigger,{asChild:!0,children:e("div",{className:"jkl-select__outer-wrapper","data-popover-placement":X,style:{width:O,anchorName:Z},children:[te&&o("input",{...n,"aria-invalid":t,id:W,hidden:!oe,ref:ge,placeholder:"Søk",value:re,onChange:e=>ne(e.target.value),"data-testid":"jkl-select__search-input",className:"jkl-select__search-input","aria-autocomplete":"list","aria-activedescendant":a&&ue?`${G}__${g(ie)}`:void 0,"aria-controls":a?G:void 0,"aria-expanded":a,role:"combobox",onKeyDown:Ae,onBlur:Le,onFocus:Ne,onClick:e=>{e.stopPropagation()}}),o("button",{"aria-invalid":t,...n,id:U,ref:ye,hidden:oe,type:"button",name:`${w}-btn`,className:r("jkl-select__button",{"jkl-select__button--active-value":!!ie}),"data-testid":"jkl-select__button","aria-label":`${pe||"Velg"},${x}`,"aria-expanded":a,"aria-controls":a?G:void 0,onBlur:Le,onFocus:Ne,onKeyDown:Fe,onClick:Q,onMouseDown:e=>{e.preventDefault(),ye.current?.focus()},children:pe}),o(f,{variant:"medium",pointingDown:!a,className:"jkl-select__arrow"})]})}),o(h.Content,{initialFocus:-1,returnFocus:!1,className:"jkl-select__popover",style:{width:`anchor-size(${Z} width)`},children:o("div",{id:G,ref:xe,role:"listbox",className:"jkl-select__options-menu","data-popover-placement":X,"aria-labelledby":R,tabIndex:-1,"data-testid":"jkl-select__listbox","data-testautoid":q?`${q}__listbox`:"jkl-select__listbox","data-focus":"controlled",style:{"--jkl-select-max-shown-options":K},children:se.map((t,r)=>t.visible?e("button",{hidden:!t.visible,type:"button",id:`${G}__${g(t.value)}`,className:"jkl-select__option","data-testid":"jkl-select__option","aria-selected":t.value===ie,role:"option",value:t.value,"data-testautoid":`jkl-select__option-${r}`,onBlur:Le,onFocus:Ne,onKeyDown:Se,onClick:e=>{e.preventDefault(),fe(t)},onMouseOver:Ce,children:[t.label,t.description?o("span",{className:"jkl-select__option-description",children:t.description}):null]},`${G}-${t.value}`):null)})})]})}})]})});_.displayName="Select";export{_ as Select};
1
+ import{jsxs as e,Fragment as t,jsx as o}from"react/jsx-runtime";import{c as r}from"../../../clsx-BeLtu-UY.js";import n,{forwardRef as a,useState as s,useCallback as l,useMemo as i,useRef as c,useEffect as u}from"react";import{useId as p}from"../../hooks/useId/useId.js";import{useListNavigation as d}from"../../hooks/useListNavigation/useListNavigation.js";import{usePreviousValue as v}from"../../hooks/usePreviousValue/usePreviousValue.js";import{getValuePair as m}from"../../utilities/valuePair.js";import{ArrowVerticalAnimated as f}from"../icon/icons/animated/ArrowVerticalAnimated.js";import{InputGroup as b}from"../input-group/InputGroup.js";import{Popover as h}from"../popover/Popover.js";import{focusSelected as k,toLower as g}from"./select-utils.js";const y=()=>{},_=a((a,_)=>{const{id:j,name:w,items:P,value:x,label:D,labelProps:E,onChange:L,onBlur:$,onFocus:N,className:C,helpLabel:F,errorLabel:S,invalid:V,searchable:A=!1,inline:T=!1,defaultPrompt:I="Velg",width:O,maxShownOptions:K=5,style:B,tooltip:M,"data-testautoid":R,...q}=a,G=p(j||"jkl-select",{generateSuffix:!j}),W=`${G}_label`,U=`${G}_button`,z=`${G}_search-input`,[H,J]=s(!1),Q=l(()=>{J(e=>!e)},[]),[X,Y]=s("bottom"),Z=l(e=>{Y(e.startsWith("top")?"top":"bottom")},[]),ee=!!A,te=ee&&H,[oe,re]=s(""),ne=l(e=>!!e.label.toLowerCase().includes(oe.toLowerCase())||"function"==typeof A&&A(oe,e),[A,oe]),ae=i(()=>P.map(m).map(e=>{const t=!ee||""===oe||ne(e);return{...e,visible:t}}),[P,ee,oe,ne]),se=i(()=>!(typeof x>"u")&&P.some(e=>"string"==typeof e?e===x:e.value===x),[x,P]),[le,ie]=s(se&&void 0!==x?x:""),ce=""!==le,ue=i(()=>ae.find(e=>e.value===le)?.label||I,[ae,le,I]),pe=c(null),de=l(e=>{pe.current=e,_&&("function"==typeof _?_(e):_.current=e),e&&ie(e.value)},[_]),ve=v(x);u(()=>{x!==ve&&ie(typeof x>"u"||!se?"":x)},[x,ve,se]);const me=l(e=>{const t=e.value;re(""),ie(t),Q(),ge.current?.focus()},[Q]),fe=v(le);u(()=>{typeof fe>"u"||fe===le||le===x||(L&&L({type:"change",target:{name:w,value:le}}),pe.current&&pe.current.dispatchEvent(new Event("change",{bubbles:!0})))},[L,w,x,le,fe]);const be=c(null),he=c(!1),ke=c(null),ge=c(null),ye=c(null),[_e,je]=s(null),we=c(ee),Pe=c(le);u(()=>{we.current=ee,Pe.current=le});const xe=l(e=>{ye.current=e,je(e),e&&!we.current&&requestAnimationFrame(()=>{ye.current===e&&k(e,Pe.current)})},[]),De=v(H);u(()=>{H!==De&&(H&&ee?ke.current?.focus():!H&&he.current&&ge.current&&ge.current.focus())},[H,De,ee]),d({element:_e});const Ee=l(()=>{ee&&re(""),$&&($({type:"blur",target:{name:w,value:le}}),pe.current?.dispatchEvent(new Event("focusout",{bubbles:!0}))),he.current=!1,J(!1)},[$,ee,w,le]),Le=l(e=>{const t=be.current,o=ye.current;t?.contains(e.relatedTarget)||o?.contains(e.relatedTarget)||Ee()},[Ee]),$e=l(()=>{he.current||(N&&N({type:"change",target:{name:w,value:le}}),he.current=!0)},[N,le,w]),Ne=l(e=>{e.target.focus({preventScroll:!0})},[]);u(()=>{const e=pe.current;if(!e)return;const t=()=>{te?ke.current?.focus():ge.current?.focus()},o=e=>{const t=e.relatedTarget,o=be.current?.contains(t),r=ye.current?.contains(t);(o||r)&&e.preventDefault()};return e.addEventListener("focus",t),e.addEventListener("blur",o),()=>{e.removeEventListener("focus",t),e.removeEventListener("blur",o)}},[te]);const Ce=l(e=>{"ArrowDown"!==e.key&&" "!==e.key||H?"Escape"===e.key&&(e.preventDefault(),e.stopPropagation(),J(!1)):(e.preventDefault(),e.stopPropagation(),J(!0))},[H]),Fe=l(e=>{if("ArrowDown"===e.key){e.preventDefault(),e.stopPropagation();const t=ye.current;t&&k(t,ee?void 0:le)}else if("Escape"===e.key)e.preventDefault(),e.stopPropagation(),J(!1);else if("Tab"!==e.key||e.shiftKey)"Enter"===e.key&&H&&(e.preventDefault(),e.stopPropagation());else{const t=ye.current;t&&(e.preventDefault(),e.stopPropagation(),k(t,le))}},[le,ee,H]),Se=l(e=>{if("Tab"===e.key)e.preventDefault(),e.stopPropagation(),e.shiftKey&&ke.current?ke.current.focus():ge.current&&(ie(e.currentTarget.value),J(!1),ge.current.focus());else if("ArrowUp"===e.key&&ye.current&&ke.current){const t=ye.current.querySelector('[role="option"]:not([hidden])');e.currentTarget.id===t?.id&&ke.current&&ke.current.focus()}},[]);return u(()=>{const e=e=>{"Escape"===e.key&&H&&J(!1)};return typeof window<"u"&&H&&window.addEventListener("keydown",e),()=>{typeof window<"u"&&window.removeEventListener("keydown",e)}},[H]),e(t,{children:[e("select",{name:w,tabIndex:-1,"data-testid":"jkl-native-select",className:"jkl-sr-only","aria-hidden":!0,ref:de,value:le,onChange:y,children:[o("option",{value:""})," ",ae.map(e=>o("option",{hidden:!e.visible,value:e.value,children:e.label},`${G}-opt-${e.value}`))]}),o(b,{ref:be,"data-testid":"jkl-select",className:r("jkl-select",C,{"jkl-select--inline":T,"jkl-select--open":H&&ae.some(e=>e.visible),"jkl-select--no-value":!ce,"jkl-select--invalid":!!S||V}),"data-testautoid":R,tooltip:M&&n.isValidElement(M)?n.cloneElement(M,{triggerProps:{...M.props.triggerProps,onFocus:e=>{M.props.triggerProps?.onFocus?.(e),Ee()}}}):null,...q,id:ee?z:U,style:B,label:D,labelProps:{id:W,srOnly:T,...E,htmlFor:ee?z:U},helpLabel:F,errorLabel:S,render:({"aria-invalid":t,...n})=>{const a=H&&ae.some(e=>e.visible);return e(h,{open:a,placement:"bottom-start",offset:0,modal:!1,onPlacementChange:Z,matchReferenceWidth:!0,clickOptions:{enabled:!1},dismissOptions:{enabled:!1},roleOptions:{enabled:!1},children:[o(h.Trigger,{asChild:!0,children:e("div",{className:"jkl-select__outer-wrapper","data-popover-placement":X,style:{width:O},children:[ee&&o("input",{...n,"aria-invalid":t,id:z,hidden:!te,ref:ke,placeholder:"Søk",value:oe,onChange:e=>re(e.target.value),"data-testid":"jkl-select__search-input",className:"jkl-select__search-input","aria-autocomplete":"list","aria-activedescendant":a&&ce?`${G}__${g(le)}`:void 0,"aria-controls":a?G:void 0,"aria-expanded":a,role:"combobox",onKeyDown:Fe,onBlur:Le,onFocus:$e,onClick:e=>{e.stopPropagation()}}),o("button",{"aria-invalid":t,...n,id:U,ref:ge,hidden:te,type:"button",name:`${w}-btn`,className:r("jkl-select__button",{"jkl-select__button--active-value":!!le}),"data-testid":"jkl-select__button","aria-label":`${ue||"Velg"},${D}`,"aria-expanded":a,"aria-controls":a?G:void 0,onBlur:Le,onFocus:$e,onKeyDown:Ce,onClick:Q,onMouseDown:e=>{e.preventDefault(),ge.current?.focus()},children:ue}),o(f,{variant:"medium",pointingDown:!a,className:"jkl-select__arrow"})]})}),o(h.Content,{initialFocus:-1,returnFocus:!1,className:"jkl-select__popover",children:o("div",{id:G,ref:xe,role:"listbox",className:"jkl-select__options-menu","data-popover-placement":X,"aria-labelledby":W,tabIndex:-1,"data-testid":"jkl-select__listbox","data-testautoid":R?`${R}__listbox`:"jkl-select__listbox","data-focus":"controlled",style:{"--jkl-select-max-shown-options":K},children:ae.map((t,r)=>t.visible?e("button",{hidden:!t.visible,type:"button",id:`${G}__${g(t.value)}`,className:"jkl-select__option","data-testid":"jkl-select__option","aria-selected":t.value===le,role:"option",value:t.value,"data-testautoid":`jkl-select__option-${r}`,onBlur:Le,onFocus:$e,onKeyDown:Se,onClick:e=>{e.preventDefault(),me(t)},onMouseOver:Ne,children:[t.label,t.description?o("span",{className:"jkl-select__option-description",children:t.description}):null]},`${G}-${t.value}`):null)})})]})}})]})});_.displayName="Select";export{_ as Select};
2
2
  //# sourceMappingURL=Select.js.map