{"version":3,"file":"Menu.cjs","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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"}