@lobehub/ui 5.13.0 → 5.14.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.
package/es/Menu/baseItem.d.mts
CHANGED
|
@@ -31,6 +31,10 @@ interface BaseSubMenuType {
|
|
|
31
31
|
delay?: number;
|
|
32
32
|
desc?: ReactNode;
|
|
33
33
|
disabled?: boolean;
|
|
34
|
+
/** Pinned footer slot, rendered below the scrollable submenu items with a divider border. */
|
|
35
|
+
footer?: ReactNode;
|
|
36
|
+
/** Pinned header slot, rendered above the scrollable submenu items with a divider border. */
|
|
37
|
+
header?: ReactNode;
|
|
34
38
|
icon?: IconProps['icon'];
|
|
35
39
|
key?: Key;
|
|
36
40
|
label?: ReactNode;
|
|
@@ -186,6 +186,11 @@ const renderContextMenuItems = (items, keyPath = [], options) => {
|
|
|
186
186
|
const label = getItemLabel(submenu);
|
|
187
187
|
const labelText = typeof label === "string" ? label : void 0;
|
|
188
188
|
const isDanger = "danger" in submenu && Boolean(submenu.danger);
|
|
189
|
+
const submenuHasSlots = submenu.header != null || submenu.footer != null;
|
|
190
|
+
const submenuBody = submenu.children && submenu.children.length > 0 ? renderContextMenuItems(submenu.children, nextKeyPath, {
|
|
191
|
+
iconAlign,
|
|
192
|
+
iconSpaceMode
|
|
193
|
+
}) : /* @__PURE__ */ jsx(EmptyMenuItem, {});
|
|
189
194
|
return /* @__PURE__ */ jsxs(ContextMenu.SubmenuRoot, {
|
|
190
195
|
defaultOpen: submenu.defaultOpen,
|
|
191
196
|
open: submenu.open,
|
|
@@ -210,12 +215,22 @@ const renderContextMenuItems = (items, keyPath = [], options) => {
|
|
|
210
215
|
"data-submenu": "",
|
|
211
216
|
sideOffset: -1,
|
|
212
217
|
onContextMenu: preventDefaultAndStopPropagation,
|
|
213
|
-
children: /* @__PURE__ */
|
|
214
|
-
className: styles.popup,
|
|
215
|
-
children:
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
218
|
+
children: /* @__PURE__ */ jsxs(ContextMenu.Popup, {
|
|
219
|
+
className: submenuHasSlots ? cx(styles.popup, styles.popupWithSlots) : styles.popup,
|
|
220
|
+
children: [
|
|
221
|
+
submenu.header == null ? null : /* @__PURE__ */ jsx("div", {
|
|
222
|
+
className: styles.header,
|
|
223
|
+
children: submenu.header
|
|
224
|
+
}),
|
|
225
|
+
submenuHasSlots ? /* @__PURE__ */ jsx("div", {
|
|
226
|
+
className: styles.slotViewport,
|
|
227
|
+
children: submenuBody
|
|
228
|
+
}) : submenuBody,
|
|
229
|
+
submenu.footer == null ? null : /* @__PURE__ */ jsx("div", {
|
|
230
|
+
className: styles.footer,
|
|
231
|
+
children: submenu.footer
|
|
232
|
+
})
|
|
233
|
+
]
|
|
219
234
|
})
|
|
220
235
|
}) })]
|
|
221
236
|
}, itemKey);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"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 type BaseMenuItemGroupType,\n type BaseSubMenuType,\n getItemKey,\n getItemLabel,\n hasAnyIcon,\n hasCheckboxAndIcon,\n type MenuDividerType,\n type MenuItemType,\n renderIcon,\n type RenderItemContentOptions,\n type RenderOptions,\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 <span\n style={{ display: 'inline-flex', marginInlineStart: 16 }}\n onFocus={(e) => e.stopPropagation()}\n >\n <Switch\n checked={checked}\n disabled={disabled}\n size=\"small\"\n tabIndex={-1}\n onChange={handleCheckedChange}\n onClick={(_, e) => e.stopPropagation()}\n />\n </span>\n </ContextMenu.Item>\n );\n};\n\nconst renderItemContent = (\n item: MenuItemType | BaseSubMenuType | 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 BaseMenuItemGroupType).type === 'group') {\n const group = item as BaseMenuItemGroupType;\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 BaseSubMenuType).type === 'submenu' ||\n ('children' in item && (item as BaseSubMenuType).children)\n ) {\n const submenu = item as BaseSubMenuType;\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\n defaultOpen={submenu.defaultOpen}\n key={itemKey}\n open={submenu.open}\n onOpenChange={submenu.onOpenChange}\n >\n <ContextMenu.SubmenuTrigger\n {...submenu.triggerProps}\n className={cx(styles.item, isDanger && styles.danger)}\n closeDelay={submenu.closeDelay}\n delay={submenu.delay}\n disabled={submenu.disabled}\n label={labelText}\n openOnHover={submenu.openOnHover}\n onClick={submenu.onClick}\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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"}
|
|
1
|
+
{"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 type BaseMenuItemGroupType,\n type BaseSubMenuType,\n getItemKey,\n getItemLabel,\n hasAnyIcon,\n hasCheckboxAndIcon,\n type MenuDividerType,\n type MenuItemType,\n renderIcon,\n type RenderItemContentOptions,\n type RenderOptions,\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 <span\n style={{ display: 'inline-flex', marginInlineStart: 16 }}\n onFocus={(e) => e.stopPropagation()}\n >\n <Switch\n checked={checked}\n disabled={disabled}\n size=\"small\"\n tabIndex={-1}\n onChange={handleCheckedChange}\n onClick={(_, e) => e.stopPropagation()}\n />\n </span>\n </ContextMenu.Item>\n );\n};\n\nconst renderItemContent = (\n item: MenuItemType | BaseSubMenuType | 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 BaseMenuItemGroupType).type === 'group') {\n const group = item as BaseMenuItemGroupType;\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 BaseSubMenuType).type === 'submenu' ||\n ('children' in item && (item as BaseSubMenuType).children)\n ) {\n const submenu = item as BaseSubMenuType;\n const label = getItemLabel(submenu);\n const labelText = typeof label === 'string' ? label : undefined;\n const isDanger = 'danger' in submenu && Boolean(submenu.danger);\n const submenuHasSlots = submenu.header != null || submenu.footer != null;\n const submenuBody =\n submenu.children && submenu.children.length > 0 ? (\n renderContextMenuItems(submenu.children, nextKeyPath, {\n iconAlign,\n iconSpaceMode,\n })\n ) : (\n <EmptyMenuItem />\n );\n\n return (\n <ContextMenu.SubmenuRoot\n defaultOpen={submenu.defaultOpen}\n key={itemKey}\n open={submenu.open}\n onOpenChange={submenu.onOpenChange}\n >\n <ContextMenu.SubmenuTrigger\n {...submenu.triggerProps}\n className={cx(styles.item, isDanger && styles.danger)}\n closeDelay={submenu.closeDelay}\n delay={submenu.delay}\n disabled={submenu.disabled}\n label={labelText}\n openOnHover={submenu.openOnHover}\n onClick={submenu.onClick}\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\n className={submenuHasSlots ? cx(styles.popup, styles.popupWithSlots) : styles.popup}\n >\n {submenu.header == null ? null : (\n <div className={styles.header}>{submenu.header}</div>\n )}\n {submenuHasSlots ? (\n <div className={styles.slotViewport}>{submenuBody}</div>\n ) : (\n submenuBody\n )}\n {submenu.footer == null ? null : (\n <div className={styles.footer}>{submenu.footer}</div>\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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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { styles } from "../../Menu/sharedStyle.mjs";
|
|
2
|
-
import { DropdownMenuCheckboxItemIndicator, DropdownMenuCheckboxItemPrimitive, DropdownMenuGroup, DropdownMenuGroupLabel, DropdownMenuItem, DropdownMenuItemContent, DropdownMenuItemDesc, DropdownMenuItemExtra, DropdownMenuItemIcon, DropdownMenuItemLabel, DropdownMenuItemLabelGroup, DropdownMenuPopup, DropdownMenuPortal, DropdownMenuPositioner, DropdownMenuSeparator, DropdownMenuSubmenuArrow, DropdownMenuSubmenuRoot, DropdownMenuSubmenuTrigger, DropdownMenuSwitchItem } from "./atoms.mjs";
|
|
2
|
+
import { DropdownMenuCheckboxItemIndicator, DropdownMenuCheckboxItemPrimitive, DropdownMenuFooter, DropdownMenuGroup, DropdownMenuGroupLabel, DropdownMenuHeader, DropdownMenuItem, DropdownMenuItemContent, DropdownMenuItemDesc, DropdownMenuItemExtra, DropdownMenuItemIcon, DropdownMenuItemLabel, DropdownMenuItemLabelGroup, DropdownMenuPopup, DropdownMenuPortal, DropdownMenuPositioner, DropdownMenuScrollViewport, DropdownMenuSeparator, DropdownMenuSubmenuArrow, DropdownMenuSubmenuRoot, DropdownMenuSubmenuTrigger, DropdownMenuSwitchItem } from "./atoms.mjs";
|
|
3
3
|
import { getItemKey, getItemLabel, hasAnyIcon, hasCheckboxAndIcon, renderIcon } from "../../Menu/renderUtils.mjs";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { Check, ChevronRight } from "lucide-react";
|
|
@@ -106,6 +106,11 @@ const renderDropdownMenuItems = (items, keyPath = [], options) => {
|
|
|
106
106
|
const label = getItemLabel(submenu);
|
|
107
107
|
const labelText = typeof label === "string" ? label : void 0;
|
|
108
108
|
const isDanger = "danger" in submenu && Boolean(submenu.danger);
|
|
109
|
+
const submenuHasSlots = submenu.header != null || submenu.footer != null;
|
|
110
|
+
const submenuItems = submenu.children ? renderDropdownMenuItems(submenu.children, nextKeyPath, {
|
|
111
|
+
iconAlign,
|
|
112
|
+
iconSpaceMode
|
|
113
|
+
}) : null;
|
|
109
114
|
return /* @__PURE__ */ jsxs(DropdownMenuSubmenuRoot, {
|
|
110
115
|
defaultOpen: submenu.defaultOpen,
|
|
111
116
|
open: submenu.open,
|
|
@@ -128,10 +133,14 @@ const renderDropdownMenuItems = (items, keyPath = [], options) => {
|
|
|
128
133
|
alignOffset: -4,
|
|
129
134
|
"data-submenu": "",
|
|
130
135
|
sideOffset: -1,
|
|
131
|
-
children: /* @__PURE__ */
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
136
|
+
children: /* @__PURE__ */ jsxs(DropdownMenuPopup, {
|
|
137
|
+
className: submenuHasSlots ? styles.popupWithSlots : void 0,
|
|
138
|
+
children: [
|
|
139
|
+
submenu.header == null ? null : /* @__PURE__ */ jsx(DropdownMenuHeader, { children: submenu.header }),
|
|
140
|
+
submenuHasSlots ? /* @__PURE__ */ jsx(DropdownMenuScrollViewport, { children: submenuItems }) : submenuItems,
|
|
141
|
+
submenu.footer == null ? null : /* @__PURE__ */ jsx(DropdownMenuFooter, { children: submenu.footer })
|
|
142
|
+
]
|
|
143
|
+
})
|
|
135
144
|
}) })]
|
|
136
145
|
}, itemKey);
|
|
137
146
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderItems.mjs","names":[],"sources":["../../../src/base-ui/DropdownMenu/renderItems.tsx"],"sourcesContent":["import { 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';\n\nimport {\n type BaseMenuItemGroupType,\n type BaseSubMenuType,\n getItemKey,\n getItemLabel,\n hasAnyIcon,\n hasCheckboxAndIcon,\n type MenuDividerType,\n type MenuItemType,\n renderIcon,\n type RenderItemContentOptions,\n type RenderOptions,\n} from '@/Menu';\nimport { styles } from '@/Menu/sharedStyle';\n\nimport {\n DropdownMenuCheckboxItemIndicator,\n DropdownMenuCheckboxItemPrimitive,\n DropdownMenuGroup,\n DropdownMenuGroupLabel,\n DropdownMenuItem,\n DropdownMenuItemContent,\n DropdownMenuItemDesc,\n DropdownMenuItemExtra,\n DropdownMenuItemIcon,\n DropdownMenuItemLabel,\n DropdownMenuItemLabelGroup,\n DropdownMenuPopup,\n DropdownMenuPortal,\n DropdownMenuPositioner,\n DropdownMenuSeparator,\n DropdownMenuSubmenuArrow,\n DropdownMenuSubmenuRoot,\n DropdownMenuSubmenuTrigger,\n DropdownMenuSwitchItem,\n} from './atoms';\nimport {\n type DropdownItem,\n type DropdownMenuCheckboxItem as DropdownMenuCheckboxItemType,\n type DropdownMenuSwitchItem as DropdownMenuSwitchItemType,\n} from './type';\n\nexport type { IconAlign, IconSpaceMode } from '@/Menu';\n\nconst renderItemContent = (\n item: MenuItemType | BaseSubMenuType | DropdownMenuCheckboxItemType | DropdownMenuSwitchItemType,\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\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 <DropdownMenuItemLabelGroup>\n <DropdownMenuItemLabel>{label}</DropdownMenuItemLabel>\n <DropdownMenuItemDesc>{desc}</DropdownMenuItemDesc>\n </DropdownMenuItemLabelGroup>\n ) : (\n <DropdownMenuItemLabel>{label}</DropdownMenuItemLabel>\n );\n\n return (\n <DropdownMenuItemContent className={alignStart ? styles.itemContentAlignStart : undefined}>\n {shouldRenderIcon ? (\n <DropdownMenuItemIcon\n aria-hidden={!hasIcon}\n className={alignStart ? styles.iconAlignStart : undefined}\n >\n {hasCustomIcon ? iconNode : hasIcon ? renderIcon(item.icon) : null}\n </DropdownMenuItemIcon>\n ) : null}\n {labelNode}\n {extra ? <DropdownMenuItemExtra>{extra}</DropdownMenuItemExtra> : null}\n {indicatorOnRight && iconNode ? iconNode : null}\n {options?.submenu ? (\n <DropdownMenuSubmenuArrow>\n <ChevronRight size={16} />\n </DropdownMenuSubmenuArrow>\n ) : null}\n </DropdownMenuItemContent>\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 renderDropdownMenuItems = (\n items: DropdownItem[],\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 DropdownMenuCheckboxItemType).type === 'checkbox') {\n const checkboxItem = item as DropdownMenuCheckboxItemType;\n const label = getItemLabel(checkboxItem);\n const labelText = typeof label === 'string' ? label : undefined;\n const isDanger = Boolean(checkboxItem.danger);\n const indicator = (\n <DropdownMenuCheckboxItemIndicator>{renderIcon(Check)}</DropdownMenuCheckboxItemIndicator>\n );\n\n return (\n <DropdownMenuCheckboxItemPrimitive\n checked={checkboxItem.checked}\n closeOnClick={checkboxItem.closeOnClick}\n danger={isDanger}\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 </DropdownMenuCheckboxItemPrimitive>\n );\n }\n\n if ((item as DropdownMenuSwitchItemType).type === 'switch') {\n const switchItem = item as DropdownMenuSwitchItemType;\n const label = getItemLabel(switchItem);\n const labelText = typeof label === 'string' ? label : undefined;\n const isDanger = Boolean(switchItem.danger);\n\n return (\n <DropdownMenuSwitchItem\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={(checked) => switchItem.onCheckedChange?.(checked)}\n >\n {renderItemContent(switchItem, { iconAlign, reserveIconSpace })}\n </DropdownMenuSwitchItem>\n );\n }\n\n if ((item as MenuDividerType).type === 'divider') {\n return <DropdownMenuSeparator key={itemKey} />;\n }\n\n if ((item as BaseMenuItemGroupType).type === 'group') {\n const group = item as BaseMenuItemGroupType;\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 <DropdownMenuGroup key={itemKey}>\n {group.label ? <DropdownMenuGroupLabel>{group.label}</DropdownMenuGroupLabel> : null}\n {group.children\n ? renderDropdownMenuItems(group.children, nextKeyPath, {\n iconAlign,\n iconSpaceMode,\n indicatorOnRight: groupIndicatorOnRight,\n reserveIconSpace: groupReserveIconSpace,\n })\n : null}\n </DropdownMenuGroup>\n );\n }\n\n if ((item as BaseSubMenuType).type === 'submenu' || 'children' in item) {\n const submenu = item as BaseSubMenuType;\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 <DropdownMenuSubmenuRoot\n defaultOpen={submenu.defaultOpen}\n key={itemKey}\n open={submenu.open}\n onOpenChange={submenu.onOpenChange}\n >\n <DropdownMenuSubmenuTrigger\n {...submenu.triggerProps}\n closeDelay={submenu.closeDelay}\n danger={isDanger}\n delay={submenu.delay}\n disabled={submenu.disabled}\n label={labelText}\n openOnHover={submenu.openOnHover}\n onClick={submenu.onClick}\n >\n {renderItemContent(submenu, {\n iconAlign,\n reserveIconSpace,\n submenu: true,\n })}\n </DropdownMenuSubmenuTrigger>\n <DropdownMenuPortal>\n <DropdownMenuPositioner alignOffset={-4} data-submenu=\"\" sideOffset={-1}>\n <DropdownMenuPopup>\n {submenu.children\n ? renderDropdownMenuItems(submenu.children, nextKeyPath, {\n iconAlign,\n iconSpaceMode,\n })\n : null}\n </DropdownMenuPopup>\n </DropdownMenuPositioner>\n </DropdownMenuPortal>\n </DropdownMenuSubmenuRoot>\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 <DropdownMenuItem\n closeOnClick={menuItem.closeOnClick}\n danger={isDanger}\n disabled={menuItem.disabled}\n key={itemKey}\n label={labelText}\n onClick={(event) => invokeItemClick(menuItem, nextKeyPath, event)}\n >\n {renderItemContent(menuItem, { iconAlign, reserveIconSpace })}\n </DropdownMenuItem>\n );\n });\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"renderItems.mjs","names":[],"sources":["../../../src/base-ui/DropdownMenu/renderItems.tsx"],"sourcesContent":["import { 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';\n\nimport {\n type BaseMenuItemGroupType,\n type BaseSubMenuType,\n getItemKey,\n getItemLabel,\n hasAnyIcon,\n hasCheckboxAndIcon,\n type MenuDividerType,\n type MenuItemType,\n renderIcon,\n type RenderItemContentOptions,\n type RenderOptions,\n} from '@/Menu';\nimport { styles } from '@/Menu/sharedStyle';\n\nimport {\n DropdownMenuCheckboxItemIndicator,\n DropdownMenuCheckboxItemPrimitive,\n DropdownMenuFooter,\n DropdownMenuGroup,\n DropdownMenuGroupLabel,\n DropdownMenuHeader,\n DropdownMenuItem,\n DropdownMenuItemContent,\n DropdownMenuItemDesc,\n DropdownMenuItemExtra,\n DropdownMenuItemIcon,\n DropdownMenuItemLabel,\n DropdownMenuItemLabelGroup,\n DropdownMenuPopup,\n DropdownMenuPortal,\n DropdownMenuPositioner,\n DropdownMenuScrollViewport,\n DropdownMenuSeparator,\n DropdownMenuSubmenuArrow,\n DropdownMenuSubmenuRoot,\n DropdownMenuSubmenuTrigger,\n DropdownMenuSwitchItem,\n} from './atoms';\nimport {\n type DropdownItem,\n type DropdownMenuCheckboxItem as DropdownMenuCheckboxItemType,\n type DropdownMenuSwitchItem as DropdownMenuSwitchItemType,\n} from './type';\n\nexport type { IconAlign, IconSpaceMode } from '@/Menu';\n\nconst renderItemContent = (\n item: MenuItemType | BaseSubMenuType | DropdownMenuCheckboxItemType | DropdownMenuSwitchItemType,\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\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 <DropdownMenuItemLabelGroup>\n <DropdownMenuItemLabel>{label}</DropdownMenuItemLabel>\n <DropdownMenuItemDesc>{desc}</DropdownMenuItemDesc>\n </DropdownMenuItemLabelGroup>\n ) : (\n <DropdownMenuItemLabel>{label}</DropdownMenuItemLabel>\n );\n\n return (\n <DropdownMenuItemContent className={alignStart ? styles.itemContentAlignStart : undefined}>\n {shouldRenderIcon ? (\n <DropdownMenuItemIcon\n aria-hidden={!hasIcon}\n className={alignStart ? styles.iconAlignStart : undefined}\n >\n {hasCustomIcon ? iconNode : hasIcon ? renderIcon(item.icon) : null}\n </DropdownMenuItemIcon>\n ) : null}\n {labelNode}\n {extra ? <DropdownMenuItemExtra>{extra}</DropdownMenuItemExtra> : null}\n {indicatorOnRight && iconNode ? iconNode : null}\n {options?.submenu ? (\n <DropdownMenuSubmenuArrow>\n <ChevronRight size={16} />\n </DropdownMenuSubmenuArrow>\n ) : null}\n </DropdownMenuItemContent>\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 renderDropdownMenuItems = (\n items: DropdownItem[],\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 DropdownMenuCheckboxItemType).type === 'checkbox') {\n const checkboxItem = item as DropdownMenuCheckboxItemType;\n const label = getItemLabel(checkboxItem);\n const labelText = typeof label === 'string' ? label : undefined;\n const isDanger = Boolean(checkboxItem.danger);\n const indicator = (\n <DropdownMenuCheckboxItemIndicator>{renderIcon(Check)}</DropdownMenuCheckboxItemIndicator>\n );\n\n return (\n <DropdownMenuCheckboxItemPrimitive\n checked={checkboxItem.checked}\n closeOnClick={checkboxItem.closeOnClick}\n danger={isDanger}\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 </DropdownMenuCheckboxItemPrimitive>\n );\n }\n\n if ((item as DropdownMenuSwitchItemType).type === 'switch') {\n const switchItem = item as DropdownMenuSwitchItemType;\n const label = getItemLabel(switchItem);\n const labelText = typeof label === 'string' ? label : undefined;\n const isDanger = Boolean(switchItem.danger);\n\n return (\n <DropdownMenuSwitchItem\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={(checked) => switchItem.onCheckedChange?.(checked)}\n >\n {renderItemContent(switchItem, { iconAlign, reserveIconSpace })}\n </DropdownMenuSwitchItem>\n );\n }\n\n if ((item as MenuDividerType).type === 'divider') {\n return <DropdownMenuSeparator key={itemKey} />;\n }\n\n if ((item as BaseMenuItemGroupType).type === 'group') {\n const group = item as BaseMenuItemGroupType;\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 <DropdownMenuGroup key={itemKey}>\n {group.label ? <DropdownMenuGroupLabel>{group.label}</DropdownMenuGroupLabel> : null}\n {group.children\n ? renderDropdownMenuItems(group.children, nextKeyPath, {\n iconAlign,\n iconSpaceMode,\n indicatorOnRight: groupIndicatorOnRight,\n reserveIconSpace: groupReserveIconSpace,\n })\n : null}\n </DropdownMenuGroup>\n );\n }\n\n if ((item as BaseSubMenuType).type === 'submenu' || 'children' in item) {\n const submenu = item as BaseSubMenuType;\n const label = getItemLabel(submenu);\n const labelText = typeof label === 'string' ? label : undefined;\n const isDanger = 'danger' in submenu && Boolean(submenu.danger);\n const submenuHasSlots = submenu.header != null || submenu.footer != null;\n const submenuItems = submenu.children\n ? renderDropdownMenuItems(submenu.children, nextKeyPath, {\n iconAlign,\n iconSpaceMode,\n })\n : null;\n\n return (\n <DropdownMenuSubmenuRoot\n defaultOpen={submenu.defaultOpen}\n key={itemKey}\n open={submenu.open}\n onOpenChange={submenu.onOpenChange}\n >\n <DropdownMenuSubmenuTrigger\n {...submenu.triggerProps}\n closeDelay={submenu.closeDelay}\n danger={isDanger}\n delay={submenu.delay}\n disabled={submenu.disabled}\n label={labelText}\n openOnHover={submenu.openOnHover}\n onClick={submenu.onClick}\n >\n {renderItemContent(submenu, {\n iconAlign,\n reserveIconSpace,\n submenu: true,\n })}\n </DropdownMenuSubmenuTrigger>\n <DropdownMenuPortal>\n <DropdownMenuPositioner alignOffset={-4} data-submenu=\"\" sideOffset={-1}>\n <DropdownMenuPopup className={submenuHasSlots ? styles.popupWithSlots : undefined}>\n {submenu.header == null ? null : (\n <DropdownMenuHeader>{submenu.header}</DropdownMenuHeader>\n )}\n {submenuHasSlots ? (\n <DropdownMenuScrollViewport>{submenuItems}</DropdownMenuScrollViewport>\n ) : (\n submenuItems\n )}\n {submenu.footer == null ? null : (\n <DropdownMenuFooter>{submenu.footer}</DropdownMenuFooter>\n )}\n </DropdownMenuPopup>\n </DropdownMenuPositioner>\n </DropdownMenuPortal>\n </DropdownMenuSubmenuRoot>\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 <DropdownMenuItem\n closeOnClick={menuItem.closeOnClick}\n danger={isDanger}\n disabled={menuItem.disabled}\n key={itemKey}\n label={labelText}\n onClick={(event) => invokeItemClick(menuItem, nextKeyPath, event)}\n >\n {renderItemContent(menuItem, { iconAlign, reserveIconSpace })}\n </DropdownMenuItem>\n );\n });\n};\n"],"mappings":"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"}
|