UNPKG

@navikt/ds-react

Version:

React components from the Norwegian Labour and Welfare Administration.

228 lines 16.6 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import React, { forwardRef, useRef } from "react"; import { ChevronRightIcon } from "@navikt/aksel-icons"; import { useModalContext } from "../../modal/Modal.context.js"; import { Slot } from "../../slot/Slot.js"; import { useRenameCSS, useThemeInternal } from "../../theme/Theme.js"; import { useId } from "../../util/index.js"; import { composeEventHandlers } from "../../util/composeEventHandlers.js"; import { createContext } from "../../util/create-context.js"; import { useMergeRefs } from "../../util/hooks/index.js"; import { useControllableState } from "../../util/hooks/useControllableState.js"; import { requireReactElement } from "../../util/requireReactElement.js"; import { Menu } from "../floating-menu/Menu.js"; const [ActionMenuProvider, useActionMenuContext] = createContext({ name: "ActionMenuContext", errorMessage: "ActionMenu sub-components cannot be rendered outside the ActionMenu component.", }); const ActionMenuRoot = ({ children, open: openProp, onOpenChange, rootElement: rootElementProp, }) => { const triggerRef = useRef(null); const modalContext = useModalContext(false); const rootElement = modalContext ? modalContext.ref.current : rootElementProp; const [open = false, setOpen] = useControllableState({ value: openProp, defaultValue: false, onChange: onOpenChange, }); return (React.createElement(ActionMenuProvider, { triggerId: useId(), triggerRef: triggerRef, contentId: useId(), open: open, onOpenChange: setOpen, onOpenToggle: () => setOpen((prevOpen) => !prevOpen), rootElement: rootElement }, React.createElement(Menu, { open: open, onOpenChange: setOpen, modal: true }, children))); }; /** * ActionMenu is a dropdown menu for actions and navigation. * * @example * ```jsx * <ActionMenu> * <ActionMenu.Trigger> * <button>Open Menu</button> * </ActionMenu.Trigger> * <ActionMenu.Content> * <ActionMenu.Item onSelect={() => alert("Item 1 selected")}> * Item 1 * </ActionMenu.Item> * <ActionMenu.Item onSelect={() => alert("Item 2 selected")}> * Item 2 * </ActionMenu.Item> * </ActionMenu.Content> * <ActionMenu> * ``` */ export const ActionMenu = ActionMenuRoot; export const ActionMenuTrigger = forwardRef((_a, ref) => { var { children, onKeyDown, style, onClick } = _a, rest = __rest(_a, ["children", "onKeyDown", "style", "onClick"]); const context = useActionMenuContext(); const mergedRefs = useMergeRefs(ref, context.triggerRef); return (React.createElement(Menu.Anchor, { asChild: true }, React.createElement(Slot, Object.assign({ type: "button", id: context.triggerId, "aria-haspopup": "menu", "aria-expanded": context.open, "aria-controls": context.open ? context.contentId : undefined, "data-state": context.open ? "open" : "closed", ref: mergedRefs }, rest, { style: Object.assign(Object.assign({}, style), { pointerEvents: context.open ? "auto" : undefined }), onClick: composeEventHandlers(onClick, context.onOpenToggle), onKeyDown: composeEventHandlers(onKeyDown, (event) => { if (event.key === "ArrowDown") { context.onOpenChange(true); /* Stop keydown from scrolling window */ event.preventDefault(); } }) }), requireReactElement(children)))); }); export const ActionMenuContent = forwardRef((_a, ref) => { var { children, className, style, align = "start" } = _a, rest = __rest(_a, ["children", "className", "style", "align"]); const context = useActionMenuContext(); const { cn } = useRenameCSS(); return (React.createElement(Menu.Portal, { rootElement: context.rootElement }, React.createElement(Menu.Content, Object.assign({ ref: ref, id: context.contentId, "aria-labelledby": context.triggerId, className: cn("navds-action-menu__content", className) }, rest, { align: align, sideOffset: 4, collisionPadding: 10, returnFocus: context.triggerRef, safeZone: { anchor: context.triggerRef.current }, style: Object.assign(Object.assign({}, style), { "--__ac-action-menu-content-transform-origin": "var(--ac-floating-transform-origin)", "--__ac-action-menu-content-available-height": "var(--ac-floating-available-height)", }) }), React.createElement("div", { className: cn("navds-action-menu__content-inner") }, children)))); }); export const ActionMenuLabel = forwardRef((_a, ref) => { var { children, className } = _a, rest = __rest(_a, ["children", "className"]); const { cn } = useRenameCSS(); return (React.createElement("div", Object.assign({ ref: ref }, rest, { className: cn("navds-action-menu__label", className) }), children)); }); export const ActionMenuGroup = forwardRef((_a, ref) => { var { children, className, label } = _a, rest = __rest(_a, ["children", "className", "label"]); const labelId = useId(); const { cn } = useRenameCSS(); return (React.createElement(Menu.Group, Object.assign({ ref: ref }, rest, { className: cn("navds-action-menu__group", className), asChild: false, "aria-labelledby": label ? labelId : undefined }), label && (React.createElement(ActionMenu.Label, { id: labelId, "aria-hidden": true }, label)), children)); }); const Marker = ({ children, className, placement }) => { const { cn } = useRenameCSS(); return (React.createElement("div", { "aria-hidden": true, className: cn(className, "navds-action-menu__marker", `navds-action-menu__marker--${placement}`) }, children)); }; const Shortcut = ({ children }) => { const { cn } = useRenameCSS(); /** * Assumes the user will input either a single keyboard key * or keys separated by "+" */ const parsed = children.split("+").filter((str) => str !== ""); return (React.createElement(Marker, { placement: "right" }, parsed.map((char, index) => (React.createElement("span", { key: char + index, className: cn("navds-action-menu__shortcut") }, char))))); }; export const ActionMenuItem = forwardRef((_a, ref) => { var { children, as: Component = "div", className, icon, shortcut, variant } = _a, rest = __rest(_a, ["children", "as", "className", "icon", "shortcut", "variant"]); const { cn } = useRenameCSS(); return (React.createElement(Menu.Item, Object.assign({}, rest, { className: cn("navds-action-menu__item", className, { "navds-action-menu__item--danger": variant === "danger", "navds-action-menu__item--has-icon": icon, }), "aria-keyshortcuts": shortcut !== null && shortcut !== void 0 ? shortcut : undefined, asChild: true }), React.createElement(Component, { ref: ref }, children, icon && (React.createElement(Marker, { placement: "left", className: cn("navds-action-menu__marker-icon") }, icon)), shortcut && React.createElement(Shortcut, null, shortcut)))); }); export const ActionMenuCheckboxItem = forwardRef((_a, ref) => { var { children, className, shortcut, onSelect } = _a, rest = __rest(_a, ["children", "className", "shortcut", "onSelect"]); const { cn } = useRenameCSS(); return (React.createElement(Menu.CheckboxItem, Object.assign({ ref: ref }, rest, { onSelect: composeEventHandlers(onSelect, (event) => { /** * Prevent default to avoid the menu from closing when clicking the checkbox */ event.preventDefault(); }), asChild: false, className: cn("navds-action-menu__item navds-action-menu__item--has-icon", className), "aria-keyshortcuts": shortcut }), children, React.createElement(Marker, { placement: "left" }, React.createElement(Menu.ItemIndicator, { className: cn("navds-action-menu__indicator") }, React.createElement("svg", { width: "1em", height: "1em", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: cn("navds-action-menu__indicator-icon"), "aria-hidden": true }, React.createElement("g", { className: cn("navds-action-menu__indicator-icon--unchecked") }, React.createElement("rect", { width: "24", height: "24", rx: "4", fill: "var(--ax-border-neutral, var(--a-border-default))" }), React.createElement("rect", { x: "1", y: "1", width: "22", height: "22", rx: "3", fill: "var(--ax-bg-default, var(--a-surface-default))", strokeWidth: "2" })), React.createElement("g", { className: cn("navds-action-menu__indicator-icon--indeterminate") }, React.createElement("rect", { width: "24", height: "24", rx: "4", fill: "var(--ax-bg-strong-pressed, var(--a-surface-action-selected))" }), React.createElement("rect", { x: "6", y: "10", width: "12", height: "4", rx: "1", fill: "var(--ax-bg-default, var(--a-surface-default))" })), React.createElement("g", { className: cn("navds-action-menu__indicator-icon--checked") }, React.createElement("rect", { width: "24", height: "24", rx: "4", fill: "var(--ax-bg-strong-pressed, var(--a-surface-action-selected))" }), React.createElement("path", { d: "M10.0352 13.4148L16.4752 7.40467C17.0792 6.83965 18.029 6.86933 18.5955 7.47478C19.162 8.08027 19.1296 9.03007 18.5245 9.59621L11.0211 16.5993C10.741 16.859 10.3756 17 10.0002 17C9.60651 17 9.22717 16.8462 8.93914 16.5611L6.43914 14.0611C5.85362 13.4756 5.85362 12.5254 6.43914 11.9399C7.02467 11.3544 7.97483 11.3544 8.56036 11.9399L10.0352 13.4148Z", fill: "var(--ax-bg-default, var(--a-surface-default))" }))))), shortcut && React.createElement(Shortcut, null, shortcut))); }); export const ActionMenuRadioGroup = forwardRef((_a, ref) => { var { children, label } = _a, rest = __rest(_a, ["children", "label"]); const labelId = useId(); return (React.createElement(Menu.RadioGroup, Object.assign({ ref: ref }, rest, { asChild: false, "aria-labelledby": label ? labelId : undefined }), label && (React.createElement(ActionMenu.Label, { id: labelId, "aria-hidden": true }, label)), children)); }); export const ActionMenuRadioItem = forwardRef((_a, ref) => { var { children, className, onSelect } = _a, rest = __rest(_a, ["children", "className", "onSelect"]); const { cn } = useRenameCSS(); const themeContext = useThemeInternal(false); return (React.createElement(Menu.RadioItem, Object.assign({ ref: ref }, rest, { onSelect: composeEventHandlers(onSelect, (event) => { /** * Prevent default to avoid the menu from closing when clicking the radio */ event.preventDefault(); }), asChild: false, className: cn("navds-action-menu__item navds-action-menu__item--has-icon", className) }), children, React.createElement(Marker, { placement: "left" }, React.createElement(Menu.ItemIndicator, { className: cn("navds-action-menu__indicator") }, React.createElement("svg", { width: "1em", height: "1em", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: cn("navds-action-menu__indicator-icon"), "aria-hidden": true }, React.createElement("g", { className: cn("navds-action-menu__indicator-icon--unchecked") }, React.createElement("rect", { width: "24", height: "24", rx: "12", fill: "var(--ax-border-neutral, var(--a-border-default))" }), React.createElement("rect", { x: "1", y: "1", width: "22", height: "22", rx: "11", strokeWidth: "2", fill: "var(--ax-bg-default, var(--a-surface-default))" })), (themeContext === null || themeContext === void 0 ? void 0 : themeContext.isDarkside) ? (React.createElement("g", { className: cn("navds-action-menu__indicator-icon--checked") }, React.createElement("rect", { width: "24", height: "24", rx: "12", fill: "var(--ax-bg-strong-pressed)" }), React.createElement("rect", { x: "8", y: "8", width: "8", height: "8", rx: "4", fill: "var(--ax-bg-default, var(--a-surface-default))" }))) : (React.createElement("g", { className: cn("navds-action-menu__indicator-icon--checked") }, React.createElement("rect", { x: "1", y: "1", width: "22", height: "22", rx: "11", fill: "var(--ax-bg-default, var(--a-surface-default))" }), React.createElement("rect", { x: "1", y: "1", width: "22", height: "22", rx: "11", stroke: "var(--ax-bg-strong-pressed, var(--a-surface-action-selected))", strokeWidth: "2" }), React.createElement("path", { d: "M20 12C20 16.4178 16.4178 20 12 20C7.58222 20 4 16.4178 4 12C4 7.58222 7.58222 4 12 4C16.4178 4 20 7.58222 20 12Z", fill: "var(--ax-bg-strong-pressed, var(--a-surface-action-selected))" })))))))); }); export const ActionMenuDivider = forwardRef((_a, ref) => { var { className } = _a, rest = __rest(_a, ["className"]); const { cn } = useRenameCSS(); return (React.createElement(Menu.Divider, Object.assign({ ref: ref, asChild: false }, rest, { className: cn("navds-action-menu__divider", className) }))); }); export const ActionMenuSub = (props) => { const { children, open: openProp, onOpenChange } = props; const [open = false, setOpen] = useControllableState({ value: openProp, defaultValue: false, onChange: onOpenChange, }); return (React.createElement(Menu.Sub, { open: open, onOpenChange: setOpen }, children)); }; export const ActionMenuSubTrigger = forwardRef((_a, ref) => { var { children, className, icon } = _a, rest = __rest(_a, ["children", "className", "icon"]); const { cn } = useRenameCSS(); return (React.createElement(Menu.SubTrigger, Object.assign({ ref: ref }, rest, { asChild: false, className: cn("navds-action-menu__item navds-action-menu__sub-trigger", className, { "navds-action-menu__item--has-icon": icon }) }), children, icon && (React.createElement(Marker, { placement: "left", className: cn("navds-action-menu__marker-icon") }, icon)), React.createElement(Marker, { placement: "right", className: cn("navds-action-menu__marker-icon") }, React.createElement(ChevronRightIcon, { "aria-hidden": true })))); }); export const ActionMenuSubContent = forwardRef((_a, ref) => { var { children, className, style } = _a, rest = __rest(_a, ["children", "className", "style"]); const { cn } = useRenameCSS(); const context = useActionMenuContext(); return (React.createElement(Menu.Portal, { rootElement: context.rootElement }, React.createElement(Menu.SubContent, Object.assign({ ref: ref, alignOffset: -4, sideOffset: 1, collisionPadding: 10 }, rest, { className: cn("navds-action-menu__content navds-action-menu__sub-content", className), style: Object.assign(Object.assign({}, style), { "--ac-action-menu-content-transform-origin": "var(--ac-floating-transform-origin)", "--ac-action-menu-content-available-width": "var(--ac-floating-available-width)", "--ac-action-menu-content-available-height": "var(--ac-floating-available-height)", "--ac-action-menu-trigger-width": "var(--ac-floating-anchor-width)", "--ac-action-menu-trigger-height": "var(--ac-floating-anchor-height)", }) }), React.createElement("div", { className: cn("navds-action-menu__content-inner") }, children)))); }); /* -------------------------------------------------------------------------- */ ActionMenu.Trigger = ActionMenuTrigger; ActionMenu.Content = ActionMenuContent; ActionMenu.Group = ActionMenuGroup; ActionMenu.Label = ActionMenuLabel; ActionMenu.Item = ActionMenuItem; ActionMenu.CheckboxItem = ActionMenuCheckboxItem; ActionMenu.RadioGroup = ActionMenuRadioGroup; ActionMenu.RadioItem = ActionMenuRadioItem; ActionMenu.Divider = ActionMenuDivider; ActionMenu.Sub = ActionMenuSub; ActionMenu.SubTrigger = ActionMenuSubTrigger; ActionMenu.SubContent = ActionMenuSubContent; //# sourceMappingURL=ActionMenu.js.map