{"version":3,"file":"renderItems.mjs","names":["common"],"sources":["../../../src/base-ui/ContextMenu/renderItems.tsx"],"sourcesContent":["import { ContextMenu } from '@base-ui/react/context-menu';\nimport { Switch } from 'antd';\nimport { cx } from 'antd-style';\nimport { Check, ChevronRight } from 'lucide-react';\nimport { type MenuInfo } from 'rc-menu/es/interface';\nimport {\n  type KeyboardEvent as ReactKeyboardEvent,\n  type MouseEvent as ReactMouseEvent,\n  type ReactNode,\n} from 'react';\nimport { memo, useCallback, useState } from 'react';\n\nimport common from '@/i18n/resources/en/common';\nimport { useTranslation } from '@/i18n/useTranslation';\nimport Icon from '@/Icon';\nimport {\n  getItemKey,\n  getItemLabel,\n  hasAnyIcon,\n  hasCheckboxAndIcon,\n  type MenuDividerType,\n  type MenuItemGroupType,\n  type MenuItemType,\n  renderIcon,\n  type RenderItemContentOptions,\n  type RenderOptions,\n  type SubMenuType,\n} from '@/Menu';\nimport { styles } from '@/Menu/sharedStyle';\nimport { preventDefaultAndStopPropagation } from '@/utils/dom';\n\nimport {\n  type ContextMenuCheckboxItem,\n  type ContextMenuItem,\n  type ContextMenuSwitchItem,\n} from './type';\n\nexport type { IconAlign, IconSpaceMode } from '@/Menu';\n\nconst EmptyMenuItem = memo(() => {\n  const { t } = useTranslation(common);\n  return (\n    <ContextMenu.Item disabled className={cx(styles.item, styles.empty)}>\n      <div className={styles.itemContent}>\n        <span className={styles.label}>{t('common.empty')}</span>\n      </div>\n    </ContextMenu.Item>\n  );\n});\n\nEmptyMenuItem.displayName = 'EmptyMenuItem';\n\ninterface ContextMenuSwitchItemInternalProps {\n  checked?: boolean;\n  children: ReactNode;\n  closeOnClick?: boolean;\n  danger?: boolean;\n  defaultChecked?: boolean;\n  disabled?: boolean;\n  label?: string;\n  onCheckedChange?: (checked: boolean) => void;\n}\n\nconst ContextMenuSwitchItemInternal = ({\n  checked: checkedProp,\n  children,\n  closeOnClick = false,\n  danger,\n  defaultChecked,\n  disabled,\n  label,\n  onCheckedChange,\n}: ContextMenuSwitchItemInternalProps) => {\n  const [internalChecked, setInternalChecked] = useState(defaultChecked ?? false);\n  const isControlled = checkedProp !== undefined;\n  const checked = isControlled ? checkedProp : internalChecked;\n\n  const handleCheckedChange = useCallback(\n    (newChecked: boolean) => {\n      if (!isControlled) {\n        setInternalChecked(newChecked);\n      }\n      onCheckedChange?.(newChecked);\n    },\n    [isControlled, onCheckedChange],\n  );\n\n  return (\n    <ContextMenu.Item\n      className={cx(styles.item, danger && styles.danger)}\n      closeOnClick={closeOnClick}\n      disabled={disabled}\n      label={label}\n      onClick={(e) => {\n        e.preventDefault();\n        if (!disabled) {\n          handleCheckedChange(!checked);\n        }\n      }}\n    >\n      {children}\n      <Switch\n        checked={checked}\n        disabled={disabled}\n        size=\"small\"\n        style={{ marginInlineStart: 16 }}\n        onChange={handleCheckedChange}\n        onClick={(_, e) => e.stopPropagation()}\n      />\n    </ContextMenu.Item>\n  );\n};\n\nconst renderItemContent = (\n  item: MenuItemType | SubMenuType | ContextMenuCheckboxItem | ContextMenuSwitchItem,\n  options?: RenderItemContentOptions,\n  iconNode?: ReactNode,\n) => {\n  const label = getItemLabel(item);\n  const desc = 'desc' in item ? item.desc : undefined;\n  const extra = 'extra' in item ? item.extra : undefined;\n  const indicatorOnRight = options?.indicatorOnRight;\n  const alignStart = Boolean(desc) && options?.iconAlign === 'start';\n  const hasCustomIcon = iconNode !== undefined && !indicatorOnRight;\n  const hasIcon = hasCustomIcon ? Boolean(iconNode) : Boolean(item.icon);\n  const shouldRenderIcon = hasCustomIcon\n    ? Boolean(options?.reserveIconSpace || iconNode)\n    : Boolean(hasIcon || options?.reserveIconSpace);\n\n  const labelNode = desc ? (\n    <div className={styles.labelGroup}>\n      <span className={styles.label}>{label}</span>\n      <span className={styles.desc}>{desc}</span>\n    </div>\n  ) : (\n    <span className={styles.label}>{label}</span>\n  );\n\n  return (\n    <div className={cx(styles.itemContent, alignStart && styles.itemContentAlignStart)}>\n      {shouldRenderIcon ? (\n        <span\n          aria-hidden={!hasIcon}\n          className={cx(styles.icon, alignStart && styles.iconAlignStart)}\n        >\n          {hasCustomIcon ? iconNode : hasIcon ? renderIcon(item.icon, 'small') : null}\n        </span>\n      ) : null}\n      {labelNode}\n      {extra ? <span className={styles.extra}>{extra}</span> : null}\n      {indicatorOnRight && iconNode ? iconNode : null}\n      {options?.submenu ? (\n        <span className={styles.submenuArrow}>\n          <ChevronRight size={16} />\n        </span>\n      ) : null}\n    </div>\n  );\n};\n\nconst invokeItemClick = (\n  item: MenuItemType,\n  keyPath: string[],\n  event: ReactMouseEvent<HTMLElement> | ReactKeyboardEvent<HTMLElement>,\n) => {\n  if (!item.onClick) return;\n  const key = item.key ?? keyPath.at(-1) ?? '';\n  const info: MenuInfo = {\n    domEvent: event,\n    item: event.currentTarget as MenuInfo['item'],\n    key: String(key),\n    keyPath,\n  };\n  item.onClick(info);\n};\n\nexport const renderContextMenuItems = (\n  items: ContextMenuItem[],\n  keyPath: string[] = [],\n  options?: RenderOptions,\n): ReactNode[] => {\n  const iconAlign = options?.iconAlign;\n  const iconSpaceMode = options?.iconSpaceMode ?? 'global';\n  const reserveIconSpace =\n    options?.reserveIconSpace ?? hasAnyIcon(items, iconSpaceMode === 'global');\n  const indicatorOnRight = options?.indicatorOnRight ?? hasCheckboxAndIcon(items);\n\n  return items.map((item, index) => {\n    if (!item) return null;\n\n    const fallbackKey = `${keyPath.join('-') || 'root'}-${index}`;\n    const itemKey = getItemKey(item, fallbackKey);\n    const nextKeyPath = [...keyPath, String(itemKey)];\n\n    if ((item as ContextMenuCheckboxItem).type === 'checkbox') {\n      const checkboxItem = item as ContextMenuCheckboxItem;\n      const label = getItemLabel(checkboxItem);\n      const labelText = typeof label === 'string' ? label : undefined;\n      const isDanger = Boolean(checkboxItem.danger);\n      const indicator = (\n        <ContextMenu.CheckboxItemIndicator>\n          <Icon icon={Check} size={'small'} />\n        </ContextMenu.CheckboxItemIndicator>\n      );\n\n      return (\n        <ContextMenu.CheckboxItem\n          checked={checkboxItem.checked}\n          className={cx(styles.item, isDanger && styles.danger)}\n          closeOnClick={checkboxItem.closeOnClick}\n          defaultChecked={checkboxItem.defaultChecked}\n          disabled={checkboxItem.disabled}\n          key={itemKey}\n          label={labelText}\n          onCheckedChange={(checked) => checkboxItem.onCheckedChange?.(checked)}\n        >\n          {renderItemContent(\n            checkboxItem,\n            { iconAlign, indicatorOnRight, reserveIconSpace },\n            indicator,\n          )}\n        </ContextMenu.CheckboxItem>\n      );\n    }\n\n    if ((item as ContextMenuSwitchItem).type === 'switch') {\n      const switchItem = item as ContextMenuSwitchItem;\n      const label = getItemLabel(switchItem);\n      const labelText = typeof label === 'string' ? label : undefined;\n      const isDanger = Boolean(switchItem.danger);\n\n      return (\n        <ContextMenuSwitchItemInternal\n          checked={switchItem.checked}\n          closeOnClick={switchItem.closeOnClick}\n          danger={isDanger}\n          defaultChecked={switchItem.defaultChecked}\n          disabled={switchItem.disabled}\n          key={itemKey}\n          label={labelText}\n          onCheckedChange={switchItem.onCheckedChange}\n        >\n          {renderItemContent(switchItem, { iconAlign, reserveIconSpace })}\n        </ContextMenuSwitchItemInternal>\n      );\n    }\n\n    if ((item as MenuDividerType).type === 'divider') {\n      return <ContextMenu.Separator className={styles.separator} key={itemKey} />;\n    }\n\n    if ((item as MenuItemGroupType).type === 'group') {\n      const group = item as MenuItemGroupType;\n      const groupReserveIconSpace =\n        iconSpaceMode === 'group'\n          ? group.children\n            ? hasAnyIcon(group.children)\n            : false\n          : reserveIconSpace;\n      const groupIndicatorOnRight = group.children ? hasCheckboxAndIcon(group.children) : false;\n      return (\n        <ContextMenu.Group key={itemKey}>\n          {group.label ? (\n            <ContextMenu.GroupLabel className={styles.groupLabel}>\n              {group.label}\n            </ContextMenu.GroupLabel>\n          ) : null}\n          {group.children\n            ? renderContextMenuItems(group.children, nextKeyPath, {\n                iconAlign,\n                iconSpaceMode,\n                indicatorOnRight: groupIndicatorOnRight,\n                reserveIconSpace: groupReserveIconSpace,\n              })\n            : null}\n        </ContextMenu.Group>\n      );\n    }\n\n    if (\n      (item as SubMenuType).type === 'submenu' ||\n      ('children' in item && (item as SubMenuType).children)\n    ) {\n      const submenu = item as SubMenuType;\n      const label = getItemLabel(submenu);\n      const labelText = typeof label === 'string' ? label : undefined;\n      const isDanger = 'danger' in submenu && Boolean(submenu.danger);\n\n      return (\n        <ContextMenu.SubmenuRoot key={itemKey}>\n          <ContextMenu.SubmenuTrigger\n            className={cx(styles.item, isDanger && styles.danger)}\n            disabled={submenu.disabled}\n            label={labelText}\n          >\n            {renderItemContent(submenu, {\n              iconAlign,\n              reserveIconSpace,\n              submenu: true,\n            })}\n          </ContextMenu.SubmenuTrigger>\n          <ContextMenu.Portal>\n            <ContextMenu.Positioner\n              alignOffset={-4}\n              className={styles.positioner}\n              data-submenu=\"\"\n              sideOffset={-1}\n              onContextMenu={preventDefaultAndStopPropagation}\n            >\n              <ContextMenu.Popup className={styles.popup}>\n                {submenu.children && submenu.children.length > 0 ? (\n                  renderContextMenuItems(submenu.children, nextKeyPath, {\n                    iconAlign,\n                    iconSpaceMode,\n                  })\n                ) : (\n                  <EmptyMenuItem />\n                )}\n              </ContextMenu.Popup>\n            </ContextMenu.Positioner>\n          </ContextMenu.Portal>\n        </ContextMenu.SubmenuRoot>\n      );\n    }\n\n    const menuItem = item as MenuItemType;\n    const label = getItemLabel(menuItem);\n    const labelText = typeof label === 'string' ? label : undefined;\n    const isDanger = 'danger' in menuItem && Boolean(menuItem.danger);\n\n    return (\n      <ContextMenu.Item\n        className={cx(styles.item, isDanger && styles.danger)}\n        closeOnClick={menuItem.closeOnClick}\n        disabled={menuItem.disabled}\n        key={itemKey}\n        label={labelText}\n        onClick={(event) => invokeItemClick(menuItem, nextKeyPath, event)}\n      >\n        {renderItemContent(menuItem, { iconAlign, reserveIconSpace })}\n      </ContextMenu.Item>\n    );\n  });\n};\n"],"mappings":"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"}