{"version":3,"file":"MenuItem.cjs","names":[],"sources":["../../../src/components/Menu/MenuItem.tsx"],"sourcesContent":["/*\nCopyright 2023 New Vector Ltd.\n\nSPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial\nPlease see LICENSE files in the repository root for full details.\n*/\n\nimport classnames from \"classnames\";\nimport React, {\n  type ComponentPropsWithoutRef,\n  type ComponentType,\n  type ElementType,\n  isValidElement,\n  type ReactElement,\n  type SVGAttributes,\n  useCallback,\n  useContext,\n  type MouseEventHandler,\n} from \"react\";\nimport styles from \"./MenuItem.module.css\";\nimport { Text } from \"../Typography/Text\";\nimport ChevronRightIcon from \"@vector-im/compound-design-tokens/assets/web/icons/chevron-right\";\nimport { MenuContext } from \"./MenuContext\";\nimport { Slot } from \"@radix-ui/react-slot\";\n\ntype MenuItemElement = \"button\" | \"a\" | \"div\";\n\ntype Props<C extends MenuItemElement> = {\n  /**\n   * The element type of this menu item.\n   * @default button\n   */\n  as?: C;\n  /**\n   * The CSS class name.\n   */\n  className?: string;\n  /**\n   * The icon to show on this menu item.\n   * When `Icon` is a ReactElement, it should spread the props\n   */\n  Icon?: ComponentType<SVGAttributes<SVGElement>> | ReactElement;\n  /**\n   * The label to show on this menu item.\n   */\n  // This prop is required because it's rare to not want a label\n  label: string | null;\n  /**\n   * Additional properties to pass to the Text label component.\n   */\n  labelProps?: ComponentPropsWithoutRef<typeof Text>;\n  /**\n   * Event callback for when the item is selected via mouse, touch, or keyboard.\n   * Calling event.preventDefault in this handler will prevent the menu from\n   * being dismissed.\n   */\n  // This prop is required because it's rare to not want a selection handler\n  onSelect: ((e: Event) => void) | null;\n  /**\n   * Event callback for when the item is clicked.\n   * @param e\n   */\n  onClick?: MouseEventHandler<HTMLElementTagNameMap[C]>;\n  /**\n   * The color variant of the menu item.\n   * @default primary\n   */\n  kind?: \"primary\" | \"critical\";\n  disabled?: boolean;\n  /**\n   * Whether to hide the chevron navigation hint.\n   */\n  hideChevron?: boolean;\n} & Omit<ComponentPropsWithoutRef<C>, \"onSelect\" | \"onClick\">;\n\n/**\n * An item within a menu, acting either as a navigation button, or simply a\n * container for other interactive elements.\n * Must be used within a compound Menu or other `menu` or `menubar` aria role subtree.\n */\nexport const MenuItem = <C extends MenuItemElement = \"button\">({\n  as,\n  className,\n  Icon,\n  label,\n  labelProps,\n  onSelect,\n  kind = \"primary\",\n  children,\n  onClick: onClickProp,\n  disabled,\n  hideChevron,\n  ...props\n}: Props<C>): React.ReactElement => {\n  const Component = as ?? (\"button\" as ElementType);\n  const context = useContext(MenuContext);\n\n  const onClick = useCallback(\n    (e: Parameters<Exclude<typeof onClickProp, undefined>>[0]) => {\n      (onClickProp as ((e_: typeof e) => void) | undefined)?.(e);\n      // If there is no wrapper component to automatically handle onSelect, we\n      // need to handle it manually, dismissing the menu as the default action\n      if (onSelect !== null && context?.MenuItemWrapper == null) {\n        const selectEvent = new CustomEvent(\"menu.itemSelect\", {\n          bubbles: true,\n          cancelable: true,\n        });\n        onSelect(selectEvent);\n        if (!selectEvent.defaultPrevented) context?.onOpenChange(false);\n      }\n    },\n    [context, onSelect],\n  );\n\n  const iconIsReactElement = isValidElement(Icon);\n  const componentIcon = Icon as ReactElement;\n  const SvgIcon = Icon as ComponentType<SVGAttributes<SVGElement>>;\n\n  const content = (\n    <Component\n      role=\"menuitem\"\n      {...props}\n      className={classnames(className, styles.item, {\n        [styles.interactive]: onSelect !== null,\n        [styles[\"no-label\"]]: label === null,\n        [styles[\"no-icon\"]]: !Icon,\n        [styles[\"disabled\"]]: disabled,\n      })}\n      data-kind={kind}\n      onClick={onClick}\n      disabled={Component === \"button\" ? disabled : undefined}\n      aria-disabled={Component === \"button\" ? undefined : disabled}\n    >\n      {Icon &&\n        (iconIsReactElement ? (\n          <Slot className={styles.icon}>{componentIcon}</Slot>\n        ) : (\n          <SvgIcon\n            width={24}\n            height={24}\n            className={styles.icon}\n            aria-hidden={true}\n          />\n        ))}\n\n      {label !== null && (\n        <Text\n          className={styles.label}\n          size=\"md\"\n          weight=\"medium\"\n          as=\"span\"\n          {...labelProps}\n        >\n          {label}\n        </Text>\n      )}\n      {/* We use CSS to swap between this navigation hint and the provided\n      children on hover - see the styles module. */}\n      {!hideChevron && (Component === \"button\" || Component === \"a\") && (\n        <ChevronRightIcon\n          width={8}\n          height={24}\n          className={styles[\"nav-hint\"]}\n          aria-hidden={true}\n          /* The SVG is a small icon in a large canvas. It probably ought to be\n             cropped, but we can adjust the viewBox here to chop off the horizontal\n             space to get it closer to the right hand edge.\n           */\n          viewBox=\"8 0 8 24\"\n        />\n      )}\n      {children}\n    </Component>\n  );\n\n  return context?.MenuItemWrapper == null || onSelect === null ? (\n    content\n  ) : (\n    <context.MenuItemWrapper onSelect={onSelect}>\n      {content}\n    </context.MenuItemWrapper>\n  );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAgFA,IAAa,YAAkD,EAC7D,IACA,WACA,MACA,OACA,YACA,UACA,OAAO,WACP,UACA,SAAS,aACT,UACA,aACA,GAAG,YAC+B;CAClC,MAAM,YAAY,MAAO;CACzB,MAAM,WAAA,GAAA,MAAA,YAAqB,oBAAA,YAAY;CAEvC,MAAM,WAAA,GAAA,MAAA,cACH,MAA6D;AAC3D,gBAAuD,EAAE;AAG1D,MAAI,aAAa,QAAQ,SAAS,mBAAmB,MAAM;GACzD,MAAM,cAAc,IAAI,YAAY,mBAAmB;IACrD,SAAS;IACT,YAAY;IACb,CAAC;AACF,YAAS,YAAY;AACrB,OAAI,CAAC,YAAY,iBAAkB,UAAS,aAAa,MAAM;;IAGnE,CAAC,SAAS,SAAS,CACpB;CAED,MAAM,sBAAA,GAAA,MAAA,gBAAoC,KAAK;CAC/C,MAAM,gBAAgB;CACtB,MAAM,UAAU;CAEhB,MAAM,UACJ,iBAAA,GAAA,kBAAA,MAAC,WAAD;EACE,MAAK;EACL,GAAI;EACJ,YAAA,GAAA,WAAA,SAAsB,WAAW,wBAAA,QAAO,MAAM;IAC3C,wBAAA,QAAO,cAAc,aAAa;IAClC,wBAAA,QAAO,cAAc,UAAU;IAC/B,wBAAA,QAAO,aAAa,CAAC;IACrB,wBAAA,QAAO,cAAc;GACvB,CAAC;EACF,aAAW;EACF;EACT,UAAU,cAAc,WAAW,WAAW,KAAA;EAC9C,iBAAe,cAAc,WAAW,KAAA,IAAY;YAZtD;GAcG,SACE,qBACC,iBAAA,GAAA,kBAAA,KAAC,qBAAA,MAAD;IAAM,WAAW,wBAAA,QAAO;cAAO;IAAqB,CAAA,GAEpD,iBAAA,GAAA,kBAAA,KAAC,SAAD;IACE,OAAO;IACP,QAAQ;IACR,WAAW,wBAAA,QAAO;IAClB,eAAa;IACb,CAAA;GAGL,UAAU,QACT,iBAAA,GAAA,kBAAA,KAAC,aAAA,MAAD;IACE,WAAW,wBAAA,QAAO;IAClB,MAAK;IACL,QAAO;IACP,IAAG;IACH,GAAI;cAEH;IACI,CAAA;GAIR,CAAC,gBAAgB,cAAc,YAAY,cAAc,QACxD,iBAAA,GAAA,kBAAA,KAAC,iEAAA,SAAD;IACE,OAAO;IACP,QAAQ;IACR,WAAW,wBAAA,QAAO;IAClB,eAAa;IAKb,SAAQ;IACR,CAAA;GAEH;GACS;;AAGd,QAAO,SAAS,mBAAmB,QAAQ,aAAa,OACtD,UAEA,iBAAA,GAAA,kBAAA,KAAC,QAAQ,iBAAT;EAAmC;YAChC;EACuB,CAAA"}