refactor: menu (#4110)

pull/4134/head
tangjinzhou 2021-05-23 21:49:35 +08:00 committed by GitHub
parent ea8ff66989
commit 67952ab5a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 2144 additions and 955 deletions

View File

@ -1,4 +1,12 @@
import { defineComponent, nextTick, Transition as T, TransitionGroup as TG } from 'vue';
import {
BaseTransitionProps,
CSSProperties,
defineComponent,
nextTick,
Ref,
Transition as T,
TransitionGroup as TG,
} from 'vue';
import { findDOMNode } from './props-util';
export const getTransitionProps = (transitionName: string, opt: object = {}) => {
@ -80,6 +88,63 @@ if (process.env.NODE_ENV === 'test') {
});
}
export { Transition, TransitionGroup };
export declare type MotionEvent = (TransitionEvent | AnimationEvent) & {
deadline?: boolean;
};
export declare type MotionEventHandler = (element: Element, done?: () => void) => CSSProperties;
export declare type MotionEndEventHandler = (element: Element, done?: () => void) => boolean | void;
// ================== Collapse Motion ==================
const getCollapsedHeight: MotionEventHandler = () => ({ height: 0, opacity: 0 });
const getRealHeight: MotionEventHandler = node => ({
height: `${node.scrollHeight}px`,
opacity: 1,
});
const getCurrentHeight: MotionEventHandler = (node: any) => ({ height: `${node.offsetHeight}px` });
// const skipOpacityTransition: MotionEndEventHandler = (_, event) =>
// (event as TransitionEvent).propertyName === 'height';
export interface CSSMotionProps extends Partial<BaseTransitionProps<Element>> {
name?: string;
css?: boolean;
}
const collapseMotion = (style: Ref<CSSProperties>, className: Ref<string>): CSSMotionProps => {
return {
name: 'ant-motion-collapse',
appear: true,
css: true,
onBeforeEnter: node => {
className.value = 'ant-motion-collapse';
style.value = getCollapsedHeight(node);
},
onEnter: node => {
nextTick(() => {
style.value = getRealHeight(node);
});
},
onAfterEnter: () => {
className.value = '';
style.value = {};
},
onBeforeLeave: node => {
className.value = 'ant-motion-collapse';
style.value = getCurrentHeight(node);
},
onLeave: node => {
window.setTimeout(() => {
style.value = getCollapsedHeight(node);
});
},
onAfterLeave: () => {
className.value = '';
style.value = {};
},
};
};
export { Transition, TransitionGroup, collapseMotion };
export default Transition;

View File

@ -1,66 +0,0 @@
import { defineComponent, inject } from 'vue';
import { Item, itemProps } from '../vc-menu';
import { getOptionProps, getSlot } from '../_util/props-util';
import Tooltip, { TooltipProps } from '../tooltip';
import { SiderContextProps } from '../layout/Sider';
import { injectExtraPropsKey } from '../vc-menu/FunctionProvider';
import PropTypes from '../_util/vue-types';
export default defineComponent({
name: 'MenuItem',
inheritAttrs: false,
props: {
...itemProps,
onClick: PropTypes.func,
},
isMenuItem: true,
setup() {
return {
getInlineCollapsed: inject<() => boolean>('getInlineCollapsed', () => false),
layoutSiderContext: inject<SiderContextProps>('layoutSiderContext', {}),
injectExtraProps: inject(injectExtraPropsKey, () => ({})),
};
},
methods: {
onKeyDown(e: HTMLElement) {
(this.$refs.menuItem as any).onKeyDown(e);
},
},
render() {
const props = getOptionProps(this);
const { level, title, rootPrefixCls } = { ...props, ...this.injectExtraProps } as any;
const { getInlineCollapsed, $attrs: attrs } = this;
const inlineCollapsed = getInlineCollapsed();
let tooltipTitle = title;
const children = getSlot(this);
if (typeof title === 'undefined') {
tooltipTitle = level === 1 ? children : '';
} else if (title === false) {
tooltipTitle = '';
}
const tooltipProps: TooltipProps = {
title: tooltipTitle,
};
const siderCollapsed = this.layoutSiderContext.sCollapsed;
if (!siderCollapsed && !inlineCollapsed) {
tooltipProps.title = null;
// Reset `visible` to fix control mode tooltip display not correct
// ref: https://github.com/ant-design/ant-design/issues/16742
tooltipProps.visible = false;
}
const itemProps = {
...props,
title,
...attrs,
ref: 'menuItem',
};
const toolTipProps: TooltipProps = {
...tooltipProps,
placement: 'right',
overlayClassName: `${rootPrefixCls}-inline-collapsed-tooltip`,
};
const item = <Item {...itemProps}>{children}</Item>;
return <Tooltip {...toolTipProps}>{item}</Tooltip>;
},
});

View File

@ -1,42 +0,0 @@
import { defineComponent, inject } from 'vue';
import { SubMenu as VcSubMenu } from '../vc-menu';
import classNames from '../_util/classNames';
import { injectExtraPropsKey } from '../vc-menu/FunctionProvider';
export type MenuTheme = 'light' | 'dark';
export interface MenuContextProps {
inlineCollapsed?: boolean;
theme?: MenuTheme;
}
export default defineComponent({
name: 'ASubMenu',
isSubMenu: true,
inheritAttrs: false,
props: { ...VcSubMenu.props },
setup() {
return {
menuPropsContext: inject<MenuContextProps>('menuPropsContext', {}),
injectExtraProps: inject(injectExtraPropsKey, () => ({})),
};
},
methods: {
onKeyDown(e: Event) {
(this.$refs.subMenu as any).onKeyDown(e);
},
},
render() {
const { $slots, $attrs } = this;
const { rootPrefixCls, popupClassName } = { ...this.$props, ...this.injectExtraProps } as any;
const { theme: antdMenuTheme } = this.menuPropsContext;
const props = {
...this.$props,
popupClassName: classNames(`${rootPrefixCls}-${antdMenuTheme}`, popupClassName),
ref: 'subMenu',
...$attrs,
} as any;
return <VcSubMenu {...props} v-slots={$slots}></VcSubMenu>;
},
});

View File

@ -1,327 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./antdv-demo/docs/menu/demo/horizontal.md correctly 1`] = `
<div>
<ul role="menu" class="ant-menu-light ant-menu-root ant-menu ant-menu-horizontal">
<li class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display: none;" role="menuitem">
<!---->
<!---->
<!---->
<div aria-expanded="false" aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div>
</li>
<!---->
<li role="menuitem" class="ant-menu-item ant-menu-item-selected"><span role="img" aria-label="mail" class="anticon anticon-mail"><svg class="" data-icon="mail" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 110.8V792H136V270.8l-27.6-21.5 39.3-50.5 42.8 33.3h643.1l42.8-33.3 39.3 50.5-27.7 21.5zM833.6 232L512 482 190.4 232l-42.8-33.3-39.3 50.5 27.6 21.5 341.6 265.6a55.99 55.99 0 0068.7 0L888 270.8l27.6-21.5-39.3-50.5-42.7 33.2z"></path></svg></span>Navigation One
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display: none;" role="menuitem">
<!---->
<!---->
<!---->
<div aria-expanded="false" aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div>
</li>
<!---->
<li role="menuitem" aria-disabled="true" class="ant-menu-item ant-menu-item-disabled"><span role="img" aria-label="appstore" class="anticon anticon-appstore"><svg class="" data-icon="appstore" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"></path></svg></span>Navigation Two
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display: none;" role="menuitem">
<!---->
<!---->
<!---->
<div aria-expanded="false" aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div>
</li>
<li class="ant-menu-submenu ant-menu-submenu-horizontal" role="menuitem">
<!---->
<!---->
<!---->
<div aria-expanded="false" aria-haspopup="true" class="ant-menu-submenu-title"><span class="submenu-title-wrapper"><span role="img" aria-label="setting" class="anticon anticon-setting"><svg class="" data-icon="setting" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M924.8 625.7l-65.5-56c3.1-19 4.7-38.4 4.7-57.8s-1.6-38.8-4.7-57.8l65.5-56a32.03 32.03 0 009.3-35.2l-.9-2.6a443.74 443.74 0 00-79.7-137.9l-1.8-2.1a32.12 32.12 0 00-35.1-9.5l-81.3 28.9c-30-24.6-63.5-44-99.7-57.6l-15.7-85a32.05 32.05 0 00-25.8-25.7l-2.7-.5c-52.1-9.4-106.9-9.4-159 0l-2.7.5a32.05 32.05 0 00-25.8 25.7l-15.8 85.4a351.86 351.86 0 00-99 57.4l-81.9-29.1a32 32 0 00-35.1 9.5l-1.8 2.1a446.02 446.02 0 00-79.7 137.9l-.9 2.6c-4.5 12.5-.8 26.5 9.3 35.2l66.3 56.6c-3.1 18.8-4.6 38-4.6 57.1 0 19.2 1.5 38.4 4.6 57.1L99 625.5a32.03 32.03 0 00-9.3 35.2l.9 2.6c18.1 50.4 44.9 96.9 79.7 137.9l1.8 2.1a32.12 32.12 0 0035.1 9.5l81.9-29.1c29.8 24.5 63.1 43.9 99 57.4l15.8 85.4a32.05 32.05 0 0025.8 25.7l2.7.5a449.4 449.4 0 00159 0l2.7-.5a32.05 32.05 0 0025.8-25.7l15.7-85a350 350 0 0099.7-57.6l81.3 28.9a32 32 0 0035.1-9.5l1.8-2.1c34.8-41.1 61.6-87.5 79.7-137.9l.9-2.6c4.5-12.3.8-26.3-9.3-35zM788.3 465.9c2.5 15.1 3.8 30.6 3.8 46.1s-1.3 31-3.8 46.1l-6.6 40.1 74.7 63.9a370.03 370.03 0 01-42.6 73.6L721 702.8l-31.4 25.8c-23.9 19.6-50.5 35-79.3 45.8l-38.1 14.3-17.9 97a377.5 377.5 0 01-85 0l-17.9-97.2-37.8-14.5c-28.5-10.8-55-26.2-78.7-45.7l-31.4-25.9-93.4 33.2c-17-22.9-31.2-47.6-42.6-73.6l75.5-64.5-6.5-40c-2.4-14.9-3.7-30.3-3.7-45.5 0-15.3 1.2-30.6 3.7-45.5l6.5-40-75.5-64.5c11.3-26.1 25.6-50.7 42.6-73.6l93.4 33.2 31.4-25.9c23.7-19.5 50.2-34.9 78.7-45.7l37.9-14.3 17.9-97.2c28.1-3.2 56.8-3.2 85 0l17.9 97 38.1 14.3c28.7 10.8 55.4 26.2 79.3 45.8l31.4 25.8 92.8-32.9c17 22.9 31.2 47.6 42.6 73.6L781.8 426l6.5 39.9zM512 326c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm79.2 255.2A111.6 111.6 0 01512 614c-29.9 0-58-11.7-79.2-32.8A111.6 111.6 0 01400 502c0-29.9 11.7-58 32.8-79.2C454 401.6 482.1 390 512 390c29.9 0 58 11.6 79.2 32.8A111.6 111.6 0 01624 502c0 29.9-11.7 58-32.8 79.2z"></path></svg></span> Navigation Three - Submenu </span><i class="ant-menu-submenu-arrow"></i></div>
</li>
<li class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="display: none;" role="menuitem">
<!---->
<!---->
<!---->
<div aria-expanded="false" aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div>
</li>
<!---->
<li role="menuitem" class="ant-menu-item"><a href="https://antdv.com" target="_blank" rel="noopener noreferrer"> Navigation Four - Link </a>
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-horizontal ant-menu-overflowed-submenu" style="visibility: hidden; position: absolute; display: none;" role="menuitem">
<!---->
<!---->
<!---->
<div aria-expanded="false" aria-haspopup="true" class="ant-menu-submenu-title"><span>···</span><i class="ant-menu-submenu-arrow"></i></div>
</li>
</ul>
</div>
`;
exports[`renders ./antdv-demo/docs/menu/demo/inline.md correctly 1`] = `
<div>
<ul role="menu" class="ant-menu-light ant-menu-root ant-menu ant-menu-inline" style="width: 256px;" id="dddddd">
<li class="ant-menu-submenu ant-menu-submenu-inline ant-menu-submenu-open ant-menu-submenu-selected" role="menuitem">
<div aria-expanded="true" aria-owns="sub1$Menu" aria-haspopup="true" style="padding-left: 24px;" class="ant-menu-submenu-title"><span><span role="img" aria-label="mail" class="anticon anticon-mail"><svg class="" data-icon="mail" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 110.8V792H136V270.8l-27.6-21.5 39.3-50.5 42.8 33.3h643.1l42.8-33.3 39.3 50.5-27.7 21.5zM833.6 232L512 482 190.4 232l-42.8-33.3-39.3 50.5 27.6 21.5 341.6 265.6a55.99 55.99 0 0068.7 0L888 270.8l27.6-21.5-39.3-50.5-42.7 33.2z"></path></svg></span><span>Navigation One</span></span><i class="ant-menu-submenu-arrow"></i></div>
<ul role="menu" class="ant-menu-sub ant-menu ant-menu-inline" id="sub1$Menu">
<li class="ant-menu-item-group">
<div class="ant-menu-item-group-title"><span role="img" aria-label="qq" class="anticon anticon-qq"><svg class="" data-icon="qq" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M824.8 613.2c-16-51.4-34.4-94.6-62.7-165.3C766.5 262.2 689.3 112 511.5 112 331.7 112 256.2 265.2 261 447.9c-28.4 70.8-46.7 113.7-62.7 165.3-34 109.5-23 154.8-14.6 155.8 18 2.2 70.1-82.4 70.1-82.4 0 49 25.2 112.9 79.8 159-26.4 8.1-85.7 29.9-71.6 53.8 11.4 19.3 196.2 12.3 249.5 6.3 53.3 6 238.1 13 249.5-6.3 14.1-23.8-45.3-45.7-71.6-53.8 54.6-46.2 79.8-110.1 79.8-159 0 0 52.1 84.6 70.1 82.4 8.5-1.1 19.5-46.4-14.5-155.8z"></path></svg></span><span>Item 1</span></div>
<ul class="ant-menu-item-group-list">
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item ant-menu-item-selected">Option 1
<!---->
</li>
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item">Option 2
<!---->
</li>
</ul>
</li>
<li class="ant-menu-item-group">
<div class="ant-menu-item-group-title" title="Item 2">Item 2</div>
<ul class="ant-menu-item-group-list">
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item"> Option 3
<!---->
</li>
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item"> Option 4
<!---->
</li>
</ul>
</li>
</ul>
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-inline" role="menuitem">
<div aria-expanded="false" aria-haspopup="true" style="padding-left: 24px;" class="ant-menu-submenu-title"><span><span role="img" aria-label="appstore" class="anticon anticon-appstore"><svg class="" data-icon="appstore" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"></path></svg></span><span>Navigation Two</span></span><i class="ant-menu-submenu-arrow"></i></div>
<div></div>
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-inline" role="menuitem">
<div aria-expanded="false" aria-haspopup="true" style="padding-left: 24px;" class="ant-menu-submenu-title"><span><span role="img" aria-label="setting" class="anticon anticon-setting"><svg class="" data-icon="setting" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M924.8 625.7l-65.5-56c3.1-19 4.7-38.4 4.7-57.8s-1.6-38.8-4.7-57.8l65.5-56a32.03 32.03 0 009.3-35.2l-.9-2.6a443.74 443.74 0 00-79.7-137.9l-1.8-2.1a32.12 32.12 0 00-35.1-9.5l-81.3 28.9c-30-24.6-63.5-44-99.7-57.6l-15.7-85a32.05 32.05 0 00-25.8-25.7l-2.7-.5c-52.1-9.4-106.9-9.4-159 0l-2.7.5a32.05 32.05 0 00-25.8 25.7l-15.8 85.4a351.86 351.86 0 00-99 57.4l-81.9-29.1a32 32 0 00-35.1 9.5l-1.8 2.1a446.02 446.02 0 00-79.7 137.9l-.9 2.6c-4.5 12.5-.8 26.5 9.3 35.2l66.3 56.6c-3.1 18.8-4.6 38-4.6 57.1 0 19.2 1.5 38.4 4.6 57.1L99 625.5a32.03 32.03 0 00-9.3 35.2l.9 2.6c18.1 50.4 44.9 96.9 79.7 137.9l1.8 2.1a32.12 32.12 0 0035.1 9.5l81.9-29.1c29.8 24.5 63.1 43.9 99 57.4l15.8 85.4a32.05 32.05 0 0025.8 25.7l2.7.5a449.4 449.4 0 00159 0l2.7-.5a32.05 32.05 0 0025.8-25.7l15.7-85a350 350 0 0099.7-57.6l81.3 28.9a32 32 0 0035.1-9.5l1.8-2.1c34.8-41.1 61.6-87.5 79.7-137.9l.9-2.6c4.5-12.3.8-26.3-9.3-35zM788.3 465.9c2.5 15.1 3.8 30.6 3.8 46.1s-1.3 31-3.8 46.1l-6.6 40.1 74.7 63.9a370.03 370.03 0 01-42.6 73.6L721 702.8l-31.4 25.8c-23.9 19.6-50.5 35-79.3 45.8l-38.1 14.3-17.9 97a377.5 377.5 0 01-85 0l-17.9-97.2-37.8-14.5c-28.5-10.8-55-26.2-78.7-45.7l-31.4-25.9-93.4 33.2c-17-22.9-31.2-47.6-42.6-73.6l75.5-64.5-6.5-40c-2.4-14.9-3.7-30.3-3.7-45.5 0-15.3 1.2-30.6 3.7-45.5l6.5-40-75.5-64.5c11.3-26.1 25.6-50.7 42.6-73.6l93.4 33.2 31.4-25.9c23.7-19.5 50.2-34.9 78.7-45.7l37.9-14.3 17.9-97.2c28.1-3.2 56.8-3.2 85 0l17.9 97 38.1 14.3c28.7 10.8 55.4 26.2 79.3 45.8l31.4 25.8 92.8-32.9c17 22.9 31.2 47.6 42.6 73.6L781.8 426l6.5 39.9zM512 326c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm79.2 255.2A111.6 111.6 0 01512 614c-29.9 0-58-11.7-79.2-32.8A111.6 111.6 0 01400 502c0-29.9 11.7-58 32.8-79.2C454 401.6 482.1 390 512 390c29.9 0 58 11.6 79.2 32.8A111.6 111.6 0 01624 502c0 29.9-11.7 58-32.8 79.2z"></path></svg></span><span>Navigation Three</span></span><i class="ant-menu-submenu-arrow"></i></div>
<div></div>
<!---->
</li>
</ul>
</div>
`;
exports[`renders ./antdv-demo/docs/menu/demo/inline-collapsed.md correctly 1`] = `
<div style="width: 256px;"><button style="margin-bottom: 16px;" class="ant-btn ant-btn-primary" type="button">
<!----><span role="img" aria-label="menu-fold" class="anticon anticon-menu-fold"><svg class="" data-icon="menu-fold" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM115.4 518.9L271.7 642c5.8 4.6 14.4.5 14.4-6.9V388.9c0-7.4-8.5-11.5-14.4-6.9L115.4 505.1a8.74 8.74 0 000 13.8z"></path></svg></span>
</button>
<ul role="menu" class="ant-menu-dark ant-menu-root ant-menu ant-menu-inline">
<!---->
<li role="menuitem" style="padding-left: 24px;" class="ant-menu-item ant-menu-item-selected"><span role="img" aria-label="pie-chart" class="anticon anticon-pie-chart"><svg class="" data-icon="pie-chart" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M864 518H506V160c0-4.4-3.6-8-8-8h-26a398.46 398.46 0 00-282.8 117.1 398.19 398.19 0 00-85.7 127.1A397.61 397.61 0 0072 552a398.46 398.46 0 00117.1 282.8c36.7 36.7 79.5 65.6 127.1 85.7A397.61 397.61 0 00472 952a398.46 398.46 0 00282.8-117.1c36.7-36.7 65.6-79.5 85.7-127.1A397.61 397.61 0 00872 552v-26c0-4.4-3.6-8-8-8zM705.7 787.8A331.59 331.59 0 01470.4 884c-88.1-.4-170.9-34.9-233.2-97.2C174.5 724.1 140 640.7 140 552c0-88.7 34.5-172.1 97.2-234.8 54.6-54.6 124.9-87.9 200.8-95.5V586h364.3c-7.7 76.3-41.3 147-96.6 201.8zM952 462.4l-2.6-28.2c-8.5-92.1-49.4-179-115.2-244.6A399.4 399.4 0 00589 74.6L560.7 72c-4.7-.4-8.7 3.2-8.7 7.9V464c0 4.4 3.6 8 8 8l384-1c4.7 0 8.4-4 8-8.6zm-332.2-58.2V147.6a332.24 332.24 0 01166.4 89.8c45.7 45.6 77 103.6 90 166.1l-256.4.7z"></path></svg></span><span>Option 1</span>
<!---->
</li>
<!---->
<li role="menuitem" style="padding-left: 24px;" class="ant-menu-item"><span role="img" aria-label="desktop" class="anticon anticon-desktop"><svg class="" data-icon="desktop" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M928 140H96c-17.7 0-32 14.3-32 32v496c0 17.7 14.3 32 32 32h380v112H304c-8.8 0-16 7.2-16 16v48c0 4.4 3.6 8 8 8h432c4.4 0 8-3.6 8-8v-48c0-8.8-7.2-16-16-16H548V700h380c17.7 0 32-14.3 32-32V172c0-17.7-14.3-32-32-32zm-40 488H136V212h752v416z"></path></svg></span><span>Option 2</span>
<!---->
</li>
<!---->
<li role="menuitem" style="padding-left: 24px;" class="ant-menu-item"><span role="img" aria-label="inbox" class="anticon anticon-inbox"><svg class="" data-icon="inbox" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="0 0 1024 1024" focusable="false"><path d="M885.2 446.3l-.2-.8-112.2-285.1c-5-16.1-19.9-27.2-36.8-27.2H281.2c-17 0-32.1 11.3-36.9 27.6L139.4 443l-.3.7-.2.8c-1.3 4.9-1.7 9.9-1 14.8-.1 1.6-.2 3.2-.2 4.8V830a60.9 60.9 0 0060.8 60.8h627.2c33.5 0 60.8-27.3 60.9-60.8V464.1c0-1.3 0-2.6-.1-3.7.4-4.9 0-9.6-1.3-14.1zm-295.8-43l-.3 15.7c-.8 44.9-31.8 75.1-77.1 75.1-22.1 0-41.1-7.1-54.8-20.6S436 441.2 435.6 419l-.3-15.7H229.5L309 210h399.2l81.7 193.3H589.4zm-375 76.8h157.3c24.3 57.1 76 90.8 140.4 90.8 33.7 0 65-9.4 90.3-27.2 22.2-15.6 39.5-37.4 50.7-63.6h156.5V814H214.4V480.1z"></path></svg></span><span>Option 3</span>
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-inline ant-menu-submenu-open" role="menuitem">
<div aria-expanded="true" aria-owns="sub1$Menu" aria-haspopup="true" style="padding-left: 24px;" class="ant-menu-submenu-title"><span><span role="img" aria-label="mail" class="anticon anticon-mail"><svg class="" data-icon="mail" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 110.8V792H136V270.8l-27.6-21.5 39.3-50.5 42.8 33.3h643.1l42.8-33.3 39.3 50.5-27.7 21.5zM833.6 232L512 482 190.4 232l-42.8-33.3-39.3 50.5 27.6 21.5 341.6 265.6a55.99 55.99 0 0068.7 0L888 270.8l27.6-21.5-39.3-50.5-42.7 33.2z"></path></svg></span><span>Navigation One</span></span><i class="ant-menu-submenu-arrow"></i></div>
<ul role="menu" class="ant-menu-sub ant-menu ant-menu-inline" id="sub1$Menu">
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item">Option 5
<!---->
</li>
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item">Option 6
<!---->
</li>
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item">Option 7
<!---->
</li>
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item">Option 8
<!---->
</li>
</ul>
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-inline" role="menuitem">
<div aria-expanded="false" aria-haspopup="true" style="padding-left: 24px;" class="ant-menu-submenu-title"><span><span role="img" aria-label="appstore" class="anticon anticon-appstore"><svg class="" data-icon="appstore" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"></path></svg></span><span>Navigation Two</span></span><i class="ant-menu-submenu-arrow"></i></div>
<div></div>
<!---->
</li>
</ul>
</div>
`;
exports[`renders ./antdv-demo/docs/menu/demo/sider-current.md correctly 1`] = `
<div>
<ul role="menu" class="ant-menu-light ant-menu-root ant-menu ant-menu-inline" style="width: 256px;">
<li class="ant-menu-submenu ant-menu-submenu-inline ant-menu-submenu-open" role="menuitem">
<div aria-expanded="true" aria-owns="sub1$Menu" aria-haspopup="true" style="padding-left: 24px;" class="ant-menu-submenu-title"><span><span role="img" aria-label="mail" class="anticon anticon-mail"><svg class="" data-icon="mail" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 110.8V792H136V270.8l-27.6-21.5 39.3-50.5 42.8 33.3h643.1l42.8-33.3 39.3 50.5-27.7 21.5zM833.6 232L512 482 190.4 232l-42.8-33.3-39.3 50.5 27.6 21.5 341.6 265.6a55.99 55.99 0 0068.7 0L888 270.8l27.6-21.5-39.3-50.5-42.7 33.2z"></path></svg></span><span>Navigation One</span></span><i class="ant-menu-submenu-arrow"></i></div>
<ul role="menu" class="ant-menu-sub ant-menu ant-menu-inline" id="sub1$Menu">
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item">Option 1
<!---->
</li>
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item">Option 2
<!---->
</li>
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item">Option 3
<!---->
</li>
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item">Option 4
<!---->
</li>
</ul>
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-inline" role="menuitem">
<div aria-expanded="false" aria-haspopup="true" style="padding-left: 24px;" class="ant-menu-submenu-title"><span><span role="img" aria-label="appstore" class="anticon anticon-appstore"><svg class="" data-icon="appstore" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"></path></svg></span><span>Navigation Two</span></span><i class="ant-menu-submenu-arrow"></i></div>
<div></div>
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-inline" role="menuitem">
<div aria-expanded="false" aria-haspopup="true" style="padding-left: 24px;" class="ant-menu-submenu-title"><span><span role="img" aria-label="setting" class="anticon anticon-setting"><svg class="" data-icon="setting" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M924.8 625.7l-65.5-56c3.1-19 4.7-38.4 4.7-57.8s-1.6-38.8-4.7-57.8l65.5-56a32.03 32.03 0 009.3-35.2l-.9-2.6a443.74 443.74 0 00-79.7-137.9l-1.8-2.1a32.12 32.12 0 00-35.1-9.5l-81.3 28.9c-30-24.6-63.5-44-99.7-57.6l-15.7-85a32.05 32.05 0 00-25.8-25.7l-2.7-.5c-52.1-9.4-106.9-9.4-159 0l-2.7.5a32.05 32.05 0 00-25.8 25.7l-15.8 85.4a351.86 351.86 0 00-99 57.4l-81.9-29.1a32 32 0 00-35.1 9.5l-1.8 2.1a446.02 446.02 0 00-79.7 137.9l-.9 2.6c-4.5 12.5-.8 26.5 9.3 35.2l66.3 56.6c-3.1 18.8-4.6 38-4.6 57.1 0 19.2 1.5 38.4 4.6 57.1L99 625.5a32.03 32.03 0 00-9.3 35.2l.9 2.6c18.1 50.4 44.9 96.9 79.7 137.9l1.8 2.1a32.12 32.12 0 0035.1 9.5l81.9-29.1c29.8 24.5 63.1 43.9 99 57.4l15.8 85.4a32.05 32.05 0 0025.8 25.7l2.7.5a449.4 449.4 0 00159 0l2.7-.5a32.05 32.05 0 0025.8-25.7l15.7-85a350 350 0 0099.7-57.6l81.3 28.9a32 32 0 0035.1-9.5l1.8-2.1c34.8-41.1 61.6-87.5 79.7-137.9l.9-2.6c4.5-12.3.8-26.3-9.3-35zM788.3 465.9c2.5 15.1 3.8 30.6 3.8 46.1s-1.3 31-3.8 46.1l-6.6 40.1 74.7 63.9a370.03 370.03 0 01-42.6 73.6L721 702.8l-31.4 25.8c-23.9 19.6-50.5 35-79.3 45.8l-38.1 14.3-17.9 97a377.5 377.5 0 01-85 0l-17.9-97.2-37.8-14.5c-28.5-10.8-55-26.2-78.7-45.7l-31.4-25.9-93.4 33.2c-17-22.9-31.2-47.6-42.6-73.6l75.5-64.5-6.5-40c-2.4-14.9-3.7-30.3-3.7-45.5 0-15.3 1.2-30.6 3.7-45.5l6.5-40-75.5-64.5c11.3-26.1 25.6-50.7 42.6-73.6l93.4 33.2 31.4-25.9c23.7-19.5 50.2-34.9 78.7-45.7l37.9-14.3 17.9-97.2c28.1-3.2 56.8-3.2 85 0l17.9 97 38.1 14.3c28.7 10.8 55.4 26.2 79.3 45.8l31.4 25.8 92.8-32.9c17 22.9 31.2 47.6 42.6 73.6L781.8 426l6.5 39.9zM512 326c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm79.2 255.2A111.6 111.6 0 01512 614c-29.9 0-58-11.7-79.2-32.8A111.6 111.6 0 01400 502c0-29.9 11.7-58 32.8-79.2C454 401.6 482.1 390 512 390c29.9 0 58 11.6 79.2 32.8A111.6 111.6 0 01624 502c0 29.9-11.7 58-32.8 79.2z"></path></svg></span><span>Navigation Three</span></span><i class="ant-menu-submenu-arrow"></i></div>
<div></div>
<!---->
</li>
</ul>
</div>
`;
exports[`renders ./antdv-demo/docs/menu/demo/switch-mode.md correctly 1`] = `
<div><button class="ant-switch" type="button" role="switch" aria-checked="false">
<!----><span class="ant-switch-inner"><!----></span>
</button> Change Mode <span class="ant-divider" style="margin: 0px 1em;"></span><button class="ant-switch" type="button" role="switch" aria-checked="false">
<!----><span class="ant-switch-inner"><!----></span>
</button> Change Theme <br><br>
<ul role="menu" class="ant-menu-light ant-menu-root ant-menu ant-menu-inline" style="width: 256px;">
<!---->
<li role="menuitem" style="padding-left: 24px;" class="ant-menu-item ant-menu-item-selected"><span role="img" aria-label="mail" class="anticon anticon-mail"><svg class="" data-icon="mail" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 110.8V792H136V270.8l-27.6-21.5 39.3-50.5 42.8 33.3h643.1l42.8-33.3 39.3 50.5-27.7 21.5zM833.6 232L512 482 190.4 232l-42.8-33.3-39.3 50.5 27.6 21.5 341.6 265.6a55.99 55.99 0 0068.7 0L888 270.8l27.6-21.5-39.3-50.5-42.7 33.2z"></path></svg></span> Navigation One
<!---->
</li>
<!---->
<li role="menuitem" style="padding-left: 24px;" class="ant-menu-item"><span role="img" aria-label="calendar" class="anticon anticon-calendar"><svg class="" data-icon="calendar" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"></path></svg></span> Navigation Two
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-inline ant-menu-submenu-open" role="menuitem">
<div aria-expanded="true" aria-owns="sub1$Menu" aria-haspopup="true" style="padding-left: 24px;" class="ant-menu-submenu-title"><span><span role="img" aria-label="appstore" class="anticon anticon-appstore"><svg class="" data-icon="appstore" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"></path></svg></span><span>Navigation Three</span></span><i class="ant-menu-submenu-arrow"></i></div>
<ul role="menu" class="ant-menu-sub ant-menu ant-menu-inline" id="sub1$Menu">
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item">Option 3
<!---->
</li>
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item">Option 4
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-inline" role="menuitem">
<div aria-expanded="false" aria-haspopup="true" title="Submenu" style="padding-left: 48px;" class="ant-menu-submenu-title">Submenu<i class="ant-menu-submenu-arrow"></i></div>
<div></div>
<!---->
</li>
</ul>
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-inline" role="menuitem">
<div aria-expanded="false" aria-haspopup="true" style="padding-left: 24px;" class="ant-menu-submenu-title"><span><span role="img" aria-label="setting" class="anticon anticon-setting"><svg class="" data-icon="setting" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M924.8 625.7l-65.5-56c3.1-19 4.7-38.4 4.7-57.8s-1.6-38.8-4.7-57.8l65.5-56a32.03 32.03 0 009.3-35.2l-.9-2.6a443.74 443.74 0 00-79.7-137.9l-1.8-2.1a32.12 32.12 0 00-35.1-9.5l-81.3 28.9c-30-24.6-63.5-44-99.7-57.6l-15.7-85a32.05 32.05 0 00-25.8-25.7l-2.7-.5c-52.1-9.4-106.9-9.4-159 0l-2.7.5a32.05 32.05 0 00-25.8 25.7l-15.8 85.4a351.86 351.86 0 00-99 57.4l-81.9-29.1a32 32 0 00-35.1 9.5l-1.8 2.1a446.02 446.02 0 00-79.7 137.9l-.9 2.6c-4.5 12.5-.8 26.5 9.3 35.2l66.3 56.6c-3.1 18.8-4.6 38-4.6 57.1 0 19.2 1.5 38.4 4.6 57.1L99 625.5a32.03 32.03 0 00-9.3 35.2l.9 2.6c18.1 50.4 44.9 96.9 79.7 137.9l1.8 2.1a32.12 32.12 0 0035.1 9.5l81.9-29.1c29.8 24.5 63.1 43.9 99 57.4l15.8 85.4a32.05 32.05 0 0025.8 25.7l2.7.5a449.4 449.4 0 00159 0l2.7-.5a32.05 32.05 0 0025.8-25.7l15.7-85a350 350 0 0099.7-57.6l81.3 28.9a32 32 0 0035.1-9.5l1.8-2.1c34.8-41.1 61.6-87.5 79.7-137.9l.9-2.6c4.5-12.3.8-26.3-9.3-35zM788.3 465.9c2.5 15.1 3.8 30.6 3.8 46.1s-1.3 31-3.8 46.1l-6.6 40.1 74.7 63.9a370.03 370.03 0 01-42.6 73.6L721 702.8l-31.4 25.8c-23.9 19.6-50.5 35-79.3 45.8l-38.1 14.3-17.9 97a377.5 377.5 0 01-85 0l-17.9-97.2-37.8-14.5c-28.5-10.8-55-26.2-78.7-45.7l-31.4-25.9-93.4 33.2c-17-22.9-31.2-47.6-42.6-73.6l75.5-64.5-6.5-40c-2.4-14.9-3.7-30.3-3.7-45.5 0-15.3 1.2-30.6 3.7-45.5l6.5-40-75.5-64.5c11.3-26.1 25.6-50.7 42.6-73.6l93.4 33.2 31.4-25.9c23.7-19.5 50.2-34.9 78.7-45.7l37.9-14.3 17.9-97.2c28.1-3.2 56.8-3.2 85 0l17.9 97 38.1 14.3c28.7 10.8 55.4 26.2 79.3 45.8l31.4 25.8 92.8-32.9c17 22.9 31.2 47.6 42.6 73.6L781.8 426l6.5 39.9zM512 326c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm79.2 255.2A111.6 111.6 0 01512 614c-29.9 0-58-11.7-79.2-32.8A111.6 111.6 0 01400 502c0-29.9 11.7-58 32.8-79.2C454 401.6 482.1 390 512 390c29.9 0 58 11.6 79.2 32.8A111.6 111.6 0 01624 502c0 29.9-11.7 58-32.8 79.2z"></path></svg></span><span>Navigation Four</span></span><i class="ant-menu-submenu-arrow"></i></div>
<div></div>
<!---->
</li>
</ul>
</div>
`;
exports[`renders ./antdv-demo/docs/menu/demo/template.md correctly 1`] = `
<div style="width: 256px;"><button style="margin-bottom: 16px;" class="ant-btn ant-btn-primary" type="button">
<!----><span role="img" aria-label="menu-fold" class="anticon anticon-menu-fold"><svg class="" data-icon="menu-fold" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM115.4 518.9L271.7 642c5.8 4.6 14.4.5 14.4-6.9V388.9c0-7.4-8.5-11.5-14.4-6.9L115.4 505.1a8.74 8.74 0 000 13.8z"></path></svg></span>
</button>
<ul role="menu" class="ant-menu-dark ant-menu-root ant-menu ant-menu-inline">
<!---->
<li role="menuitem" style="padding-left: 24px;" class="ant-menu-item ant-menu-item-selected"><span role="img" aria-label="pie-chart" class="anticon anticon-pie-chart"><svg class="" data-icon="pie-chart" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M864 518H506V160c0-4.4-3.6-8-8-8h-26a398.46 398.46 0 00-282.8 117.1 398.19 398.19 0 00-85.7 127.1A397.61 397.61 0 0072 552a398.46 398.46 0 00117.1 282.8c36.7 36.7 79.5 65.6 127.1 85.7A397.61 397.61 0 00472 952a398.46 398.46 0 00282.8-117.1c36.7-36.7 65.6-79.5 85.7-127.1A397.61 397.61 0 00872 552v-26c0-4.4-3.6-8-8-8zM705.7 787.8A331.59 331.59 0 01470.4 884c-88.1-.4-170.9-34.9-233.2-97.2C174.5 724.1 140 640.7 140 552c0-88.7 34.5-172.1 97.2-234.8 54.6-54.6 124.9-87.9 200.8-95.5V586h364.3c-7.7 76.3-41.3 147-96.6 201.8zM952 462.4l-2.6-28.2c-8.5-92.1-49.4-179-115.2-244.6A399.4 399.4 0 00589 74.6L560.7 72c-4.7-.4-8.7 3.2-8.7 7.9V464c0 4.4 3.6 8 8 8l384-1c4.7 0 8.4-4 8-8.6zm-332.2-58.2V147.6a332.24 332.24 0 01166.4 89.8c45.7 45.6 77 103.6 90 166.1l-256.4.7z"></path></svg></span><span>Option 1</span>
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-inline ant-menu-submenu-open" role="menuitem">
<div aria-expanded="true" aria-owns="2$Menu" aria-haspopup="true" style="padding-left: 24px;" class="ant-menu-submenu-title"><span><span role="img" aria-label="mail" class="anticon anticon-mail"><svg class="" data-icon="mail" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 110.8V792H136V270.8l-27.6-21.5 39.3-50.5 42.8 33.3h643.1l42.8-33.3 39.3 50.5-27.7 21.5zM833.6 232L512 482 190.4 232l-42.8-33.3-39.3 50.5 27.6 21.5 341.6 265.6a55.99 55.99 0 0068.7 0L888 270.8l27.6-21.5-39.3-50.5-42.7 33.2z"></path></svg></span><span>Navigation 2</span></span><i class="ant-menu-submenu-arrow"></i></div>
<ul role="menu" class="ant-menu-sub ant-menu ant-menu-inline" id="2$Menu">
<li class="ant-menu-submenu ant-menu-submenu-inline" role="menuitem">
<div aria-expanded="false" aria-haspopup="true" style="padding-left: 48px;" class="ant-menu-submenu-title"><span><span role="img" aria-label="mail" class="anticon anticon-mail"><svg class="" data-icon="mail" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 110.8V792H136V270.8l-27.6-21.5 39.3-50.5 42.8 33.3h643.1l42.8-33.3 39.3 50.5-27.7 21.5zM833.6 232L512 482 190.4 232l-42.8-33.3-39.3 50.5 27.6 21.5 341.6 265.6a55.99 55.99 0 0068.7 0L888 270.8l27.6-21.5-39.3-50.5-42.7 33.2z"></path></svg></span><span>Navigation 3</span></span><i class="ant-menu-submenu-arrow"></i></div>
<div></div>
<!---->
</li>
</ul>
<!---->
</li>
</ul>
</div>
`;
exports[`renders ./antdv-demo/docs/menu/demo/theme.md correctly 1`] = `
<div><button class="ant-switch ant-switch-checked" type="button" role="switch" aria-checked="true">
<!----><span class="ant-switch-inner">dark</span>
</button><br><br>
<ul role="menu" class="ant-menu-dark ant-menu-root ant-menu ant-menu-inline" style="width: 256px;">
<!---->
<li role="menuitem" style="padding-left: 24px;" class="ant-menu-item ant-menu-item-selected"><span role="img" aria-label="mail" class="anticon anticon-mail"><svg class="" data-icon="mail" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 110.8V792H136V270.8l-27.6-21.5 39.3-50.5 42.8 33.3h643.1l42.8-33.3 39.3 50.5-27.7 21.5zM833.6 232L512 482 190.4 232l-42.8-33.3-39.3 50.5 27.6 21.5 341.6 265.6a55.99 55.99 0 0068.7 0L888 270.8l27.6-21.5-39.3-50.5-42.7 33.2z"></path></svg></span> Navigation One
<!---->
</li>
<!---->
<li role="menuitem" style="padding-left: 24px;" class="ant-menu-item"><span role="img" aria-label="calendar" class="anticon anticon-calendar"><svg class="" data-icon="calendar" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"></path></svg></span> Navigation Two
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-inline ant-menu-submenu-open" role="menuitem">
<div aria-expanded="true" aria-owns="sub1$Menu" aria-haspopup="true" style="padding-left: 24px;" class="ant-menu-submenu-title"><span><span role="img" aria-label="appstore" class="anticon anticon-appstore"><svg class="" data-icon="appstore" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"></path></svg></span><span>Navigation Three</span></span><i class="ant-menu-submenu-arrow"></i></div>
<ul role="menu" class="ant-menu-sub ant-menu ant-menu-inline" id="sub1$Menu">
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item">Option 3
<!---->
</li>
<!---->
<li role="menuitem" style="padding-left: 48px;" class="ant-menu-item">Option 4
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-inline" role="menuitem">
<div aria-expanded="false" aria-haspopup="true" title="Submenu" style="padding-left: 48px;" class="ant-menu-submenu-title">Submenu<i class="ant-menu-submenu-arrow"></i></div>
<div></div>
<!---->
</li>
</ul>
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-inline" role="menuitem">
<div aria-expanded="false" aria-haspopup="true" style="padding-left: 24px;" class="ant-menu-submenu-title"><span><span role="img" aria-label="setting" class="anticon anticon-setting"><svg class="" data-icon="setting" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M924.8 625.7l-65.5-56c3.1-19 4.7-38.4 4.7-57.8s-1.6-38.8-4.7-57.8l65.5-56a32.03 32.03 0 009.3-35.2l-.9-2.6a443.74 443.74 0 00-79.7-137.9l-1.8-2.1a32.12 32.12 0 00-35.1-9.5l-81.3 28.9c-30-24.6-63.5-44-99.7-57.6l-15.7-85a32.05 32.05 0 00-25.8-25.7l-2.7-.5c-52.1-9.4-106.9-9.4-159 0l-2.7.5a32.05 32.05 0 00-25.8 25.7l-15.8 85.4a351.86 351.86 0 00-99 57.4l-81.9-29.1a32 32 0 00-35.1 9.5l-1.8 2.1a446.02 446.02 0 00-79.7 137.9l-.9 2.6c-4.5 12.5-.8 26.5 9.3 35.2l66.3 56.6c-3.1 18.8-4.6 38-4.6 57.1 0 19.2 1.5 38.4 4.6 57.1L99 625.5a32.03 32.03 0 00-9.3 35.2l.9 2.6c18.1 50.4 44.9 96.9 79.7 137.9l1.8 2.1a32.12 32.12 0 0035.1 9.5l81.9-29.1c29.8 24.5 63.1 43.9 99 57.4l15.8 85.4a32.05 32.05 0 0025.8 25.7l2.7.5a449.4 449.4 0 00159 0l2.7-.5a32.05 32.05 0 0025.8-25.7l15.7-85a350 350 0 0099.7-57.6l81.3 28.9a32 32 0 0035.1-9.5l1.8-2.1c34.8-41.1 61.6-87.5 79.7-137.9l.9-2.6c4.5-12.3.8-26.3-9.3-35zM788.3 465.9c2.5 15.1 3.8 30.6 3.8 46.1s-1.3 31-3.8 46.1l-6.6 40.1 74.7 63.9a370.03 370.03 0 01-42.6 73.6L721 702.8l-31.4 25.8c-23.9 19.6-50.5 35-79.3 45.8l-38.1 14.3-17.9 97a377.5 377.5 0 01-85 0l-17.9-97.2-37.8-14.5c-28.5-10.8-55-26.2-78.7-45.7l-31.4-25.9-93.4 33.2c-17-22.9-31.2-47.6-42.6-73.6l75.5-64.5-6.5-40c-2.4-14.9-3.7-30.3-3.7-45.5 0-15.3 1.2-30.6 3.7-45.5l6.5-40-75.5-64.5c11.3-26.1 25.6-50.7 42.6-73.6l93.4 33.2 31.4-25.9c23.7-19.5 50.2-34.9 78.7-45.7l37.9-14.3 17.9-97.2c28.1-3.2 56.8-3.2 85 0l17.9 97 38.1 14.3c28.7 10.8 55.4 26.2 79.3 45.8l31.4 25.8 92.8-32.9c17 22.9 31.2 47.6 42.6 73.6L781.8 426l6.5 39.9zM512 326c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm79.2 255.2A111.6 111.6 0 01512 614c-29.9 0-58-11.7-79.2-32.8A111.6 111.6 0 01400 502c0-29.9 11.7-58 32.8-79.2C454 401.6 482.1 390 512 390c29.9 0 58 11.6 79.2 32.8A111.6 111.6 0 01624 502c0 29.9-11.7 58-32.8 79.2z"></path></svg></span><span>Navigation Four</span></span><i class="ant-menu-submenu-arrow"></i></div>
<div></div>
<!---->
</li>
</ul>
</div>
`;
exports[`renders ./antdv-demo/docs/menu/demo/vertical.md correctly 1`] = `
<div>
<ul role="menu" class="ant-menu-light ant-menu-root ant-menu ant-menu-vertical" style="width: 256px;">
<!---->
<li role="menuitem" class="ant-menu-item"><span role="img" aria-label="mail" class="anticon anticon-mail"><svg class="" data-icon="mail" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 110.8V792H136V270.8l-27.6-21.5 39.3-50.5 42.8 33.3h643.1l42.8-33.3 39.3 50.5-27.7 21.5zM833.6 232L512 482 190.4 232l-42.8-33.3-39.3 50.5 27.6 21.5 341.6 265.6a55.99 55.99 0 0068.7 0L888 270.8l27.6-21.5-39.3-50.5-42.7 33.2z"></path></svg></span> Navigation One
<!---->
</li>
<!---->
<li role="menuitem" class="ant-menu-item"><span role="img" aria-label="calendar" class="anticon anticon-calendar"><svg class="" data-icon="calendar" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"></path></svg></span> Navigation Two
<!---->
</li>
<li class="ant-menu-submenu ant-menu-submenu-vertical" role="menuitem">
<!---->
<!---->
<!---->
<div aria-expanded="false" aria-haspopup="true" class="ant-menu-submenu-title"><span><span role="img" aria-label="appstore" class="anticon anticon-appstore"><svg class="" data-icon="appstore" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"></path></svg></span><span>Navigation Three</span></span><i class="ant-menu-submenu-arrow"></i></div>
</li>
<li class="ant-menu-submenu ant-menu-submenu-vertical" role="menuitem">
<!---->
<!---->
<!---->
<div aria-expanded="false" aria-haspopup="true" class="ant-menu-submenu-title"><span><span role="img" aria-label="setting" class="anticon anticon-setting"><svg class="" data-icon="setting" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896" focusable="false"><path d="M924.8 625.7l-65.5-56c3.1-19 4.7-38.4 4.7-57.8s-1.6-38.8-4.7-57.8l65.5-56a32.03 32.03 0 009.3-35.2l-.9-2.6a443.74 443.74 0 00-79.7-137.9l-1.8-2.1a32.12 32.12 0 00-35.1-9.5l-81.3 28.9c-30-24.6-63.5-44-99.7-57.6l-15.7-85a32.05 32.05 0 00-25.8-25.7l-2.7-.5c-52.1-9.4-106.9-9.4-159 0l-2.7.5a32.05 32.05 0 00-25.8 25.7l-15.8 85.4a351.86 351.86 0 00-99 57.4l-81.9-29.1a32 32 0 00-35.1 9.5l-1.8 2.1a446.02 446.02 0 00-79.7 137.9l-.9 2.6c-4.5 12.5-.8 26.5 9.3 35.2l66.3 56.6c-3.1 18.8-4.6 38-4.6 57.1 0 19.2 1.5 38.4 4.6 57.1L99 625.5a32.03 32.03 0 00-9.3 35.2l.9 2.6c18.1 50.4 44.9 96.9 79.7 137.9l1.8 2.1a32.12 32.12 0 0035.1 9.5l81.9-29.1c29.8 24.5 63.1 43.9 99 57.4l15.8 85.4a32.05 32.05 0 0025.8 25.7l2.7.5a449.4 449.4 0 00159 0l2.7-.5a32.05 32.05 0 0025.8-25.7l15.7-85a350 350 0 0099.7-57.6l81.3 28.9a32 32 0 0035.1-9.5l1.8-2.1c34.8-41.1 61.6-87.5 79.7-137.9l.9-2.6c4.5-12.3.8-26.3-9.3-35zM788.3 465.9c2.5 15.1 3.8 30.6 3.8 46.1s-1.3 31-3.8 46.1l-6.6 40.1 74.7 63.9a370.03 370.03 0 01-42.6 73.6L721 702.8l-31.4 25.8c-23.9 19.6-50.5 35-79.3 45.8l-38.1 14.3-17.9 97a377.5 377.5 0 01-85 0l-17.9-97.2-37.8-14.5c-28.5-10.8-55-26.2-78.7-45.7l-31.4-25.9-93.4 33.2c-17-22.9-31.2-47.6-42.6-73.6l75.5-64.5-6.5-40c-2.4-14.9-3.7-30.3-3.7-45.5 0-15.3 1.2-30.6 3.7-45.5l6.5-40-75.5-64.5c11.3-26.1 25.6-50.7 42.6-73.6l93.4 33.2 31.4-25.9c23.7-19.5 50.2-34.9 78.7-45.7l37.9-14.3 17.9-97.2c28.1-3.2 56.8-3.2 85 0l17.9 97 38.1 14.3c28.7 10.8 55.4 26.2 79.3 45.8l31.4 25.8 92.8-32.9c17 22.9 31.2 47.6 42.6 73.6L781.8 426l6.5 39.9zM512 326c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm79.2 255.2A111.6 111.6 0 01512 614c-29.9 0-58-11.7-79.2-32.8A111.6 111.6 0 01400 502c0-29.9 11.7-58 32.8-79.2C454 401.6 482.1 390 512 390c29.9 0 58 11.6 79.2 32.8A111.6 111.6 0 01624 502c0 29.9-11.7 58-32.8 79.2z"></path></svg></span><span>Navigation Four</span></span><i class="ant-menu-submenu-arrow"></i></div>
</li>
</ul>
</div>
`;

View File

@ -1,322 +1,22 @@
import { defineComponent, inject, provide, toRef, App, ExtractPropTypes, Plugin } from 'vue';
import omit from 'omit.js';
import VcMenu, { Divider, ItemGroup } from '../vc-menu';
import SubMenu from './SubMenu';
import PropTypes from '../_util/vue-types';
import animation from '../_util/openAnimation';
import warning from '../_util/warning';
import Item from './MenuItem';
import { hasProp, getOptionProps } from '../_util/props-util';
import BaseMixin from '../_util/BaseMixin';
import commonPropsType from '../vc-menu/commonPropsType';
import { defaultConfigProvider } from '../config-provider';
import { SiderContextProps } from '../layout/Sider';
import { tuple } from '../_util/type';
// import raf from '../_util/raf';
export const MenuMode = PropTypes.oneOf([
'vertical',
'vertical-left',
'vertical-right',
'horizontal',
'inline',
]);
export const menuProps = {
...commonPropsType,
theme: PropTypes.oneOf(tuple('light', 'dark')).def('light'),
mode: MenuMode.def('vertical'),
selectable: PropTypes.looseBool,
selectedKeys: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
defaultSelectedKeys: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
openKeys: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
defaultOpenKeys: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
openAnimation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
openTransitionName: PropTypes.string,
prefixCls: PropTypes.string,
multiple: PropTypes.looseBool,
inlineIndent: PropTypes.number.def(24),
inlineCollapsed: PropTypes.looseBool,
isRootMenu: PropTypes.looseBool.def(true),
focusable: PropTypes.looseBool.def(false),
onOpenChange: PropTypes.func,
onSelect: PropTypes.func,
onDeselect: PropTypes.func,
onClick: PropTypes.func,
onMouseenter: PropTypes.func,
onSelectChange: PropTypes.func,
};
export type MenuProps = Partial<ExtractPropTypes<typeof menuProps>>;
const Menu = defineComponent({
name: 'AMenu',
mixins: [BaseMixin],
inheritAttrs: false,
props: menuProps,
Divider: { ...Divider, name: 'AMenuDivider' },
Item: { ...Item, name: 'AMenuItem' },
SubMenu: { ...SubMenu, name: 'ASubMenu' },
ItemGroup: { ...ItemGroup, name: 'AMenuItemGroup' },
emits: [
'update:selectedKeys',
'update:openKeys',
'mouseenter',
'openChange',
'click',
'selectChange',
'select',
'deselect',
],
setup() {
const layoutSiderContext = inject<SiderContextProps>('layoutSiderContext', {});
const layoutSiderCollapsed = toRef(layoutSiderContext, 'sCollapsed');
return {
configProvider: inject('configProvider', defaultConfigProvider),
layoutSiderContext,
layoutSiderCollapsed,
propsUpdating: false,
switchingModeFromInline: false,
leaveAnimationExecutedWhenInlineCollapsed: false,
inlineOpenKeys: [],
};
},
data() {
const props: MenuProps = getOptionProps(this);
warning(
!('inlineCollapsed' in props && props.mode !== 'inline'),
'Menu',
"`inlineCollapsed` should only be used when Menu's `mode` is inline.",
);
let sOpenKeys: (number | string)[];
if ('openKeys' in props) {
sOpenKeys = props.openKeys;
} else if ('defaultOpenKeys' in props) {
sOpenKeys = props.defaultOpenKeys;
}
return {
sOpenKeys,
};
},
// beforeUnmount() {
// raf.cancel(this.mountRafId);
// },
watch: {
mode(val, oldVal) {
if (oldVal === 'inline' && val !== 'inline') {
this.switchingModeFromInline = true;
}
},
openKeys(val) {
this.setState({ sOpenKeys: val });
},
inlineCollapsed(val) {
this.collapsedChange(val);
},
layoutSiderCollapsed(val) {
this.collapsedChange(val);
},
},
created() {
provide('getInlineCollapsed', this.getInlineCollapsed);
provide('menuPropsContext', this.$props);
},
updated() {
this.propsUpdating = false;
},
methods: {
collapsedChange(val: unknown) {
if (this.propsUpdating) {
return;
}
this.propsUpdating = true;
if (!hasProp(this, 'openKeys')) {
if (val) {
this.switchingModeFromInline = true;
this.inlineOpenKeys = this.sOpenKeys;
this.setState({ sOpenKeys: [] });
} else {
this.setState({ sOpenKeys: this.inlineOpenKeys });
this.inlineOpenKeys = [];
}
} else if (val) {
// openKeysreactopenKeysvue便openKeys
this.switchingModeFromInline = true;
}
},
restoreModeVerticalFromInline() {
if (this.switchingModeFromInline) {
this.switchingModeFromInline = false;
this.$forceUpdate();
}
},
// Restore vertical mode when menu is collapsed responsively when mounted
// https://github.com/ant-design/ant-design/issues/13104
// TODO: not a perfect solution, looking a new way to avoid setting switchingModeFromInline in this situation
handleMouseEnter(e: Event) {
this.restoreModeVerticalFromInline();
this.$emit('mouseenter', e);
},
handleTransitionEnd(e: TransitionEvent) {
// when inlineCollapsed menu width animation finished
// https://github.com/ant-design/ant-design/issues/12864
const widthCollapsed = e.propertyName === 'width' && e.target === e.currentTarget;
// Fix SVGElement e.target.className.indexOf is not a function
// https://github.com/ant-design/ant-design/issues/15699
const { className } = e.target as SVGAnimationElement | HTMLElement;
// SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during an animation.
const classNameValue =
Object.prototype.toString.call(className) === '[object SVGAnimatedString]'
? className.animVal
: className;
// Fix for <Menu style={{ width: '100%' }} />, the width transition won't trigger when menu is collapsed
// https://github.com/ant-design/ant-design-pro/issues/2783
const iconScaled = e.propertyName === 'font-size' && classNameValue.indexOf('anticon') >= 0;
if (widthCollapsed || iconScaled) {
this.restoreModeVerticalFromInline();
}
},
handleClick(e: Event) {
this.handleOpenChange([]);
this.$emit('click', e);
},
handleSelect(info) {
this.$emit('update:selectedKeys', info.selectedKeys);
this.$emit('select', info);
this.$emit('selectChange', info.selectedKeys);
},
handleDeselect(info) {
this.$emit('update:selectedKeys', info.selectedKeys);
this.$emit('deselect', info);
this.$emit('selectChange', info.selectedKeys);
},
handleOpenChange(openKeys: (number | string)[]) {
this.setOpenKeys(openKeys);
this.$emit('update:openKeys', openKeys);
this.$emit('openChange', openKeys);
},
setOpenKeys(openKeys: (number | string)[]) {
if (!hasProp(this, 'openKeys')) {
this.setState({ sOpenKeys: openKeys });
}
},
getRealMenuMode() {
const inlineCollapsed = this.getInlineCollapsed();
if (this.switchingModeFromInline && inlineCollapsed) {
return 'inline';
}
const { mode } = this.$props;
return inlineCollapsed ? 'vertical' : mode;
},
getInlineCollapsed() {
const { inlineCollapsed } = this.$props;
if (this.layoutSiderContext.sCollapsed !== undefined) {
return this.layoutSiderContext.sCollapsed;
}
return inlineCollapsed;
},
getMenuOpenAnimation(menuMode: string) {
const { openAnimation, openTransitionName } = this.$props;
let menuOpenAnimation = openAnimation || openTransitionName;
if (openAnimation === undefined && openTransitionName === undefined) {
if (menuMode === 'horizontal') {
menuOpenAnimation = 'slide-up';
} else if (menuMode === 'inline') {
menuOpenAnimation = animation;
} else {
// When mode switch from inline
// submenu should hide without animation
if (this.switchingModeFromInline) {
menuOpenAnimation = '';
this.switchingModeFromInline = false;
} else {
menuOpenAnimation = 'zoom-big';
}
}
}
return menuOpenAnimation;
},
},
render() {
const { layoutSiderContext } = this;
const { collapsedWidth } = layoutSiderContext;
const { getPopupContainer: getContextPopupContainer } = this.configProvider;
const props = getOptionProps(this);
const { prefixCls: customizePrefixCls, theme, getPopupContainer } = props;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('menu', customizePrefixCls);
const menuMode = this.getRealMenuMode();
const menuOpenAnimation = this.getMenuOpenAnimation(menuMode);
const { class: className, ...otherAttrs } = this.$attrs;
const menuClassName = {
[className as string]: className,
[`${prefixCls}-${theme}`]: true,
[`${prefixCls}-inline-collapsed`]: this.getInlineCollapsed(),
};
const menuProps = {
...omit(props, [
'inlineCollapsed',
'onUpdate:selectedKeys',
'onUpdate:openKeys',
'onSelectChange',
]),
getPopupContainer: getPopupContainer || getContextPopupContainer,
openKeys: this.sOpenKeys,
mode: menuMode,
prefixCls,
...otherAttrs,
onSelect: this.handleSelect,
onDeselect: this.handleDeselect,
onOpenChange: this.handleOpenChange,
onMouseenter: this.handleMouseEnter,
onTransitionend: this.handleTransitionEnd,
// children: getSlot(this),
};
if (!hasProp(this, 'selectedKeys')) {
delete menuProps.selectedKeys;
}
if (menuMode !== 'inline') {
// closing vertical popup submenu after click it
menuProps.onClick = this.handleClick;
menuProps.openTransitionName = menuOpenAnimation;
} else {
menuProps.onClick = (e: Event) => {
this.$emit('click', e);
};
menuProps.openAnimation = menuOpenAnimation;
}
// https://github.com/ant-design/ant-design/issues/8587
const hideMenu =
this.getInlineCollapsed() &&
(collapsedWidth === 0 || collapsedWidth === '0' || collapsedWidth === '0px');
if (hideMenu) {
menuProps.openKeys = [];
}
return <VcMenu {...menuProps} class={menuClassName} v-slots={this.$slots} />;
},
});
import Menu from './src/Menu';
import MenuItem from './src/MenuItem';
import SubMenu from './src/SubMenu';
import ItemGroup from './src/ItemGroup';
import Divider from './src/Divider';
import { App } from 'vue';
/* istanbul ignore next */
Menu.install = function(app: App) {
app.component(Menu.name, Menu);
app.component(Menu.Item.name, Menu.Item);
app.component(Menu.SubMenu.name, Menu.SubMenu);
app.component(Menu.Divider.name, Menu.Divider);
app.component(Menu.ItemGroup.name, Menu.ItemGroup);
app.component(MenuItem.name, MenuItem);
app.component(SubMenu.name, SubMenu);
app.component(Divider.name, Divider);
app.component(ItemGroup.name, ItemGroup);
return app;
};
export default Menu as typeof Menu &
Plugin & {
readonly Item: typeof Item;
readonly Item: typeof MenuItem;
readonly SubMenu: typeof SubMenu;
readonly Divider: typeof Divider;
readonly ItemGroup: typeof ItemGroup;

View File

@ -0,0 +1,13 @@
import { defineComponent } from 'vue';
export default defineComponent({
name: 'Divider',
props: {
prefixCls: String,
},
setup(props) {
return () => {
return <li class={`${props.prefixCls}-item-divider`} />;
};
},
});

View File

@ -0,0 +1,66 @@
import { computed, defineComponent, ref, watch } from '@vue/runtime-core';
import Transition from '../../_util/transition';
import { useInjectMenu, MenuContextProvider } from './hooks/useMenuContext';
import SubMenuList from './SubMenuList';
export default defineComponent({
name: 'InlineSubMenuList',
inheritAttrs: false,
props: {
id: String,
open: Boolean,
keyPath: Array,
},
setup(props, { slots }) {
const fixedMode = computed(() => 'inline');
const { motion, mode, defaultMotions } = useInjectMenu();
const sameModeRef = computed(() => mode.value === fixedMode.value);
const destroy = ref(!sameModeRef.value);
const mergedOpen = computed(() => (sameModeRef.value ? props.open : false));
// ================================= Effect =================================
// Reset destroy state when mode change back
watch(
mode,
() => {
if (sameModeRef.value) {
destroy.value = false;
}
},
{ flush: 'post' },
);
const style = ref({});
const className = ref('');
const mergedMotion = computed(() => {
const m =
motion.value || defaultMotions.value?.[fixedMode.value] || defaultMotions.value?.other;
const res = typeof m === 'function' ? m(style, className) : m;
return { ...res, appear: props.keyPath.length <= 1 };
});
return () => {
if (destroy.value) {
return null;
}
return (
<MenuContextProvider
props={{
mode: fixedMode,
locked: !sameModeRef.value,
}}
>
<Transition {...mergedMotion.value}>
<SubMenuList
v-show={mergedOpen.value}
id={props.id}
style={style.value}
class={className.value}
>
{slots.default?.()}
</SubMenuList>
</Transition>
</MenuContextProvider>
);
};
},
});

View File

@ -0,0 +1,30 @@
import { getPropsSlot } from '../../_util/props-util';
import { computed, defineComponent } from 'vue';
import PropTypes from '../../_util/vue-types';
import { useInjectMenu } from './hooks/useMenuContext';
export default defineComponent({
name: 'AMenuItemGroup',
props: {
title: PropTypes.VNodeChild,
},
inheritAttrs: false,
slots: ['title'],
setup(props, { slots, attrs }) {
const { prefixCls } = useInjectMenu();
const groupPrefixCls = computed(() => `${prefixCls.value}-item-group`);
return () => {
return (
<li {...attrs} onClick={e => e.stopPropagation()} class={groupPrefixCls.value}>
<div
title={typeof props.title === 'string' ? props.title : undefined}
class={`${groupPrefixCls.value}-title`}
>
{getPropsSlot(slots, props, 'title')}
</div>
<ul class={`${groupPrefixCls.value}-list`}>{slots.default?.()}</ul>
</li>
);
};
},
});

View File

@ -0,0 +1,328 @@
import { Key } from '../../_util/type';
import {
computed,
defineComponent,
ExtractPropTypes,
ref,
PropType,
inject,
watchEffect,
watch,
reactive,
onMounted,
toRaw,
unref,
} from 'vue';
import shallowEqual from '../../_util/shallowequal';
import useProvideMenu, { StoreMenuInfo, useProvideFirstLevel } from './hooks/useMenuContext';
import useConfigInject from '../../_util/hooks/useConfigInject';
import {
MenuTheme,
MenuMode,
BuiltinPlacements,
TriggerSubMenuAction,
MenuInfo,
SelectInfo,
} from './interface';
import devWarning from '../../vc-util/devWarning';
import { collapseMotion, CSSMotionProps } from '../../_util/transition';
import uniq from 'lodash-es/uniq';
export const menuProps = {
prefixCls: String,
disabled: Boolean,
inlineCollapsed: Boolean,
overflowDisabled: Boolean,
openKeys: Array,
selectedKeys: Array,
selectable: { type: Boolean, default: true },
multiple: { type: Boolean, default: false },
motion: Object as PropType<CSSMotionProps>,
theme: { type: String as PropType<MenuTheme>, default: 'light' },
mode: { type: String as PropType<MenuMode>, default: 'vertical' },
inlineIndent: { type: Number, default: 24 },
subMenuOpenDelay: { type: Number, default: 0.1 },
subMenuCloseDelay: { type: Number, default: 0.1 },
builtinPlacements: { type: Object as PropType<BuiltinPlacements> },
triggerSubMenuAction: { type: String as PropType<TriggerSubMenuAction>, default: 'hover' },
getPopupContainer: Function as PropType<(node: HTMLElement) => HTMLElement>,
};
export type MenuProps = Partial<ExtractPropTypes<typeof menuProps>>;
export default defineComponent({
name: 'AMenu',
props: menuProps,
emits: ['update:openKeys', 'openChange', 'select', 'deselect', 'update:selectedKeys', 'click'],
setup(props, { slots, emit }) {
const { prefixCls, direction } = useConfigInject('menu', props);
const store = reactive<Record<string, StoreMenuInfo>>({});
const siderCollapsed = inject(
'layoutSiderCollapsed',
computed(() => undefined),
);
const inlineCollapsed = computed(() => {
if (siderCollapsed.value !== undefined) {
return siderCollapsed.value;
}
return props.inlineCollapsed;
});
const isMounted = ref(false);
onMounted(() => {
isMounted.value = true;
});
watchEffect(() => {
devWarning(
!(props.inlineCollapsed === true && props.mode !== 'inline'),
'Menu',
'`inlineCollapsed` should only be used when `mode` is inline.',
);
devWarning(
!(siderCollapsed.value !== undefined && props.inlineCollapsed === true),
'Menu',
'`inlineCollapsed` not control Menu under Sider. Should set `collapsed` on Sider instead.',
);
});
const activeKeys = ref([]);
const mergedSelectedKeys = ref([]);
watch(
() => props.selectedKeys,
(selectedKeys = mergedSelectedKeys.value) => {
mergedSelectedKeys.value = selectedKeys;
},
{ immediate: true },
);
const selectedSubMenuEventKeys = ref([]);
watch(
[store, mergedSelectedKeys],
() => {
let subMenuParentEventKeys = [];
(Object.values(toRaw(store)) as any).forEach((menuInfo: StoreMenuInfo) => {
if (mergedSelectedKeys.value.includes(menuInfo.key)) {
subMenuParentEventKeys.push(...unref(menuInfo.parentEventKeys));
}
});
subMenuParentEventKeys = uniq(subMenuParentEventKeys);
if (!shallowEqual(selectedSubMenuEventKeys.value, subMenuParentEventKeys)) {
selectedSubMenuEventKeys.value = subMenuParentEventKeys;
}
},
{ immediate: true },
);
// >>>>> Trigger select
const triggerSelection = (info: MenuInfo) => {
if (!props.selectable) {
return;
}
// Insert or Remove
const { key: targetKey } = info;
const exist = mergedSelectedKeys.value.includes(targetKey);
let newSelectedKeys: Key[];
if (exist && props.multiple) {
newSelectedKeys = mergedSelectedKeys.value.filter(key => key !== targetKey);
} else if (props.multiple) {
newSelectedKeys = [...mergedSelectedKeys.value, targetKey];
} else {
newSelectedKeys = [targetKey];
}
// Trigger event
const selectInfo: SelectInfo = {
...info,
selectedKeys: newSelectedKeys,
};
if (!('selectedKeys' in props)) {
mergedSelectedKeys.value = newSelectedKeys;
}
if (!shallowEqual(newSelectedKeys, mergedSelectedKeys.value)) {
emit('update:selectedKeys', newSelectedKeys);
if (exist && props.multiple) {
emit('deselect', selectInfo);
} else {
emit('select', selectInfo);
}
}
};
const mergedOpenKeys = ref([]);
watch(
() => props.openKeys,
(openKeys = mergedOpenKeys.value) => {
if (!shallowEqual(mergedOpenKeys.value, openKeys)) {
mergedOpenKeys.value = openKeys;
}
},
{ immediate: true },
);
const changeActiveKeys = (keys: Key[]) => {
activeKeys.value = keys;
};
const disabled = computed(() => !!props.disabled);
const isRtl = computed(() => direction.value === 'rtl');
const mergedMode = ref<MenuMode>('vertical');
const mergedInlineCollapsed = ref(false);
watchEffect(() => {
if (props.mode === 'inline' && inlineCollapsed.value) {
mergedMode.value = 'vertical';
mergedInlineCollapsed.value = inlineCollapsed.value;
} else {
mergedMode.value = props.mode;
mergedInlineCollapsed.value = false;
}
});
const isInlineMode = computed(() => mergedMode.value === 'inline');
// >>>>> Cache & Reset open keys when inlineCollapsed changed
const inlineCacheOpenKeys = ref(mergedOpenKeys.value);
const mountRef = ref(false);
// Cache
watch(
mergedOpenKeys,
() => {
if (isInlineMode.value) {
inlineCacheOpenKeys.value = mergedOpenKeys.value;
}
},
{ immediate: true },
);
// Restore
watch(
isInlineMode,
() => {
if (!mountRef.value) {
mountRef.value = true;
return;
}
if (isInlineMode.value) {
mergedOpenKeys.value = inlineCacheOpenKeys.value;
} else {
const empty = [];
mergedOpenKeys.value = empty;
// Trigger open event in case its in control
emit('update:openKeys', empty);
emit('openChange', empty);
}
},
{ immediate: true },
);
const className = computed(() => {
return {
[`${prefixCls.value}`]: true,
[`${prefixCls.value}-root`]: true,
[`${prefixCls.value}-${mergedMode.value}`]: true,
[`${prefixCls.value}-inline-collapsed`]: mergedInlineCollapsed.value,
[`${prefixCls.value}-rtl`]: isRtl.value,
[`${prefixCls.value}-${props.theme}`]: true,
};
});
const defaultMotions = {
horizontal: { name: `ant-slide-up` },
inline: collapseMotion,
other: { name: `ant-zoom-big` },
};
useProvideFirstLevel(true);
const getChildrenKeys = (eventKeys: string[] = []): Key[] => {
const keys = [];
eventKeys.forEach(eventKey => {
const { key, childrenEventKeys } = store[eventKey];
keys.push(key, ...getChildrenKeys(childrenEventKeys));
});
return keys;
};
// ========================= Open =========================
/**
* Click for item. SubMenu do not have selection status
*/
const onInternalClick = (info: MenuInfo) => {
emit('click', info);
triggerSelection(info);
};
const onInternalOpenChange = (eventKey: Key, open: boolean) => {
const { key, childrenEventKeys } = store[eventKey];
let newOpenKeys = mergedOpenKeys.value.filter(k => k !== key);
if (open) {
newOpenKeys.push(key);
} else if (mergedMode.value !== 'inline') {
// We need find all related popup to close
const subPathKeys = getChildrenKeys(childrenEventKeys);
newOpenKeys = newOpenKeys.filter(k => !subPathKeys.includes(k));
}
if (!shallowEqual(mergedOpenKeys, newOpenKeys)) {
mergedOpenKeys.value = newOpenKeys;
emit('update:openKeys', newOpenKeys);
emit('openChange', newOpenKeys);
}
};
const registerMenuInfo = (key: string, info: StoreMenuInfo) => {
store[key] = info as any;
};
const unRegisterMenuInfo = (key: string) => {
delete store[key];
};
useProvideMenu({
store,
prefixCls,
activeKeys,
openKeys: mergedOpenKeys,
selectedKeys: mergedSelectedKeys,
changeActiveKeys,
disabled,
rtl: isRtl,
mode: mergedMode,
inlineIndent: computed(() => props.inlineIndent),
subMenuCloseDelay: computed(() => props.subMenuCloseDelay),
subMenuOpenDelay: computed(() => props.subMenuOpenDelay),
builtinPlacements: computed(() => props.builtinPlacements),
triggerSubMenuAction: computed(() => props.triggerSubMenuAction),
getPopupContainer: computed(() => props.getPopupContainer),
inlineCollapsed: mergedInlineCollapsed,
antdMenuTheme: computed(() => props.theme),
siderCollapsed,
defaultMotions: computed(() => (isMounted.value ? defaultMotions : null)),
motion: computed(() => (isMounted.value ? props.motion : null)),
overflowDisabled: computed(() => props.overflowDisabled),
onOpenChange: onInternalOpenChange,
onItemClick: onInternalClick,
registerMenuInfo,
unRegisterMenuInfo,
selectedSubMenuEventKeys,
isRootMenu: true,
});
return () => {
return <ul class={className.value}>{slots.default?.()}</ul>;
};
},
});

View File

@ -0,0 +1,196 @@
import { flattenChildren, getPropsSlot, isValidElement } from '../../_util/props-util';
import PropTypes from '../../_util/vue-types';
import { computed, defineComponent, getCurrentInstance, onBeforeUnmount, ref, watch } from 'vue';
import { useInjectKeyPath } from './hooks/useKeyPath';
import { useInjectFirstLevel, useInjectMenu } from './hooks/useMenuContext';
import { cloneElement } from '../../_util/vnode';
import Tooltip from '../../tooltip';
import { MenuInfo } from './interface';
let indexGuid = 0;
export default defineComponent({
name: 'AMenuItem',
props: {
role: String,
disabled: Boolean,
danger: Boolean,
title: { type: [String, Boolean], default: undefined },
icon: PropTypes.VNodeChild,
},
emits: ['mouseenter', 'mouseleave', 'click'],
slots: ['icon'],
inheritAttrs: false,
setup(props, { slots, emit, attrs }) {
const instance = getCurrentInstance();
const key = instance.vnode.key;
const eventKey = `menu_item_${++indexGuid}_$$_${key}`;
const { parentEventKeys } = useInjectKeyPath();
const {
prefixCls,
activeKeys,
disabled,
changeActiveKeys,
rtl,
inlineCollapsed,
siderCollapsed,
onItemClick,
selectedKeys,
store,
registerMenuInfo,
unRegisterMenuInfo,
} = useInjectMenu();
const firstLevel = useInjectFirstLevel();
const isActive = ref(false);
const keyPath = computed(() => {
return [...parentEventKeys.value.map(eK => store[eK].key), key];
});
const keysPath = computed(() => [...parentEventKeys.value, eventKey]);
const menuInfo = {
eventKey,
key,
parentEventKeys,
isLeaf: true,
};
registerMenuInfo(eventKey, menuInfo);
onBeforeUnmount(() => {
unRegisterMenuInfo(eventKey);
});
watch(
activeKeys,
() => {
isActive.value = !!activeKeys.value.find(val => val === key);
},
{ immediate: true },
);
const mergedDisabled = computed(() => disabled.value || props.disabled);
const selected = computed(() => selectedKeys.value.includes(key));
const classNames = computed(() => {
const itemCls = `${prefixCls.value}-item`;
return {
[`${itemCls}`]: true,
[`${itemCls}-danger`]: props.danger,
[`${itemCls}-active`]: isActive.value,
[`${itemCls}-selected`]: selected.value,
[`${itemCls}-disabled`]: mergedDisabled.value,
};
});
const getEventInfo = (e: MouseEvent): MenuInfo => {
return {
key: key,
eventKey: eventKey,
keyPath: keyPath.value,
eventKeyPath: [...parentEventKeys.value, eventKey],
domEvent: e,
};
};
// ============================ Events ============================
const onInternalClick = (e: MouseEvent) => {
if (mergedDisabled.value) {
return;
}
const info = getEventInfo(e);
emit('click', e);
onItemClick(info);
};
const onMouseEnter = (event: MouseEvent) => {
if (!mergedDisabled.value) {
changeActiveKeys(keysPath.value);
console.log('item mouseenter', keysPath.value);
emit('mouseenter', event);
}
};
const onMouseLeave = (event: MouseEvent) => {
if (!mergedDisabled.value) {
changeActiveKeys([]);
emit('mouseleave', event);
}
};
const renderItemChildren = (icon: any, children: any) => {
// inline-collapsed.md demo span , icon span
// ref: https://github.com/ant-design/ant-design/pull/23456
if (!icon || (isValidElement(children) && children.type === 'span')) {
if (children && inlineCollapsed.value && firstLevel && typeof children === 'string') {
return (
<div class={`${prefixCls.value}-inline-collapsed-noicon`}>{children.charAt(0)}</div>
);
}
return children;
}
return <span class={`${prefixCls.value}-title-content`}>{children}</span>;
};
return () => {
const { title } = props;
const children = flattenChildren(slots.default?.());
const childrenLength = children.length;
let tooltipTitle: any = title;
if (typeof title === 'undefined') {
tooltipTitle = firstLevel ? children : '';
} else if (title === false) {
tooltipTitle = '';
}
const tooltipProps: any = {
title: tooltipTitle,
};
if (!siderCollapsed.value && !inlineCollapsed.value) {
tooltipProps.title = null;
// Reset `visible` to fix control mode tooltip display not correct
// ref: https://github.com/ant-design/ant-design/issues/16742
tooltipProps.visible = false;
}
// ============================ Render ============================
const optionRoleProps = {};
if (props.role === 'option') {
optionRoleProps['aria-selected'] = selected.value;
}
const icon = getPropsSlot(slots, props, 'icon');
return (
<Tooltip
{...tooltipProps}
placement={rtl.value ? 'left' : 'right'}
overlayClassName={`${prefixCls.value}-inline-collapsed-tooltip`}
>
<li
{...attrs}
class={[
classNames.value,
{
[`${attrs.class}`]: !!attrs.class,
[`${prefixCls.value}-item-only-child`]:
(icon ? childrenLength + 1 : childrenLength) === 1,
},
]}
role={props.role || 'menuitem'}
tabindex={props.disabled ? null : -1}
data-menu-id={key}
aria-disabled={props.disabled}
{...optionRoleProps}
onMouseenter={onMouseEnter}
onMouseleave={onMouseLeave}
onClick={onInternalClick}
title={typeof title === 'string' ? title : undefined}
>
{cloneElement(icon, {
class: `${prefixCls.value}-item-icon`,
})}
{renderItemChildren(icon, children)}
</li>
</Tooltip>
);
};
},
});

View File

@ -0,0 +1,103 @@
import Trigger from '../../vc-trigger';
import { computed, defineComponent, onBeforeUnmount, PropType, ref, watch } from 'vue';
import { MenuMode } from './interface';
import { useInjectMenu } from './hooks/useMenuContext';
import { placements, placementsRtl } from './placements';
import raf from '../../_util/raf';
import classNames from '../../_util/classNames';
const popupPlacementMap = {
horizontal: 'bottomLeft',
vertical: 'rightTop',
'vertical-left': 'rightTop',
'vertical-right': 'leftTop',
};
export default defineComponent({
name: 'PopupTrigger',
props: {
prefixCls: String,
mode: String as PropType<MenuMode>,
visible: Boolean,
// popup: React.ReactNode;
popupClassName: String,
popupOffset: Array as PropType<number[]>,
disabled: Boolean,
onVisibleChange: Function as PropType<(visible: boolean) => void>,
},
slots: ['popup'],
emits: ['visibleChange'],
inheritAttrs: false,
setup(props, { slots, emit }) {
const innerVisible = ref(false);
const {
getPopupContainer,
rtl,
subMenuOpenDelay,
subMenuCloseDelay,
builtinPlacements,
triggerSubMenuAction,
isRootMenu,
} = useInjectMenu();
const placement = computed(() =>
rtl
? { ...placementsRtl, ...builtinPlacements.value }
: { ...placements, ...builtinPlacements.value },
);
const popupPlacement = computed(() => popupPlacementMap[props.mode]);
const visibleRef = ref<number>();
watch(
() => props.visible,
visible => {
raf.cancel(visibleRef.value);
visibleRef.value = raf(() => {
innerVisible.value = visible;
});
},
{ immediate: true },
);
onBeforeUnmount(() => {
raf.cancel(visibleRef.value);
});
const onVisibleChange = (visible: boolean) => {
emit('visibleChange', visible);
};
return () => {
const { prefixCls, popupClassName, mode, popupOffset, disabled } = props;
return (
<Trigger
prefixCls={prefixCls}
popupClassName={classNames(
`${prefixCls}-popup`,
{
[`${prefixCls}-rtl`]: rtl,
},
popupClassName,
)}
stretch={mode === 'horizontal' ? 'minWidth' : null}
getPopupContainer={
isRootMenu ? getPopupContainer.value : triggerNode => triggerNode.parentNode
}
builtinPlacements={placement.value}
popupPlacement={popupPlacement.value}
popupVisible={innerVisible.value}
popupAlign={popupOffset && { offset: popupOffset }}
action={disabled ? [] : [triggerSubMenuAction.value]}
mouseEnterDelay={subMenuOpenDelay.value}
mouseLeaveDelay={subMenuCloseDelay.value}
onPopupVisibleChange={onVisibleChange}
// forceRender={forceSubMenuRender}
v-slots={{
popup: () => {
return slots.popup?.({ visible: innerVisible.value });
},
default: slots.default,
}}
></Trigger>
);
};
},
});

View File

@ -0,0 +1,294 @@
import PropTypes from '../../_util/vue-types';
import {
computed,
defineComponent,
getCurrentInstance,
ref,
watch,
PropType,
onBeforeUnmount,
} from 'vue';
import useProvideKeyPath, { useInjectKeyPath } from './hooks/useKeyPath';
import { useInjectMenu, useProvideFirstLevel, MenuContextProvider } from './hooks/useMenuContext';
import { getPropsSlot, isValidElement } from '../../_util/props-util';
import classNames from '../../_util/classNames';
import useDirectionStyle from './hooks/useDirectionStyle';
import PopupTrigger from './PopupTrigger';
import SubMenuList from './SubMenuList';
import InlineSubMenuList from './InlineSubMenuList';
import Transition, { getTransitionProps } from '../../_util/transition';
let indexGuid = 0;
export default defineComponent({
name: 'ASubMenu',
props: {
icon: PropTypes.VNodeChild,
title: PropTypes.VNodeChild,
disabled: Boolean,
level: Number,
popupClassName: String,
popupOffset: Array as PropType<number[]>,
internalPopupClose: Boolean,
},
slots: ['icon', 'title'],
emits: ['titleClick', 'mouseenter', 'mouseleave'],
inheritAttrs: false,
setup(props, { slots, attrs, emit }) {
useProvideFirstLevel(false);
const instance = getCurrentInstance();
const key = instance.vnode.key;
const eventKey = `sub_menu_${++indexGuid}_$$_${key}`;
const { parentEventKeys, parentInfo } = useInjectKeyPath();
const keysPath = computed(() => [...parentEventKeys.value, eventKey]);
const childrenEventKeys = ref([]);
const menuInfo = {
eventKey,
key,
parentEventKeys,
childrenEventKeys,
};
parentInfo.childrenEventKeys?.value.push(eventKey);
onBeforeUnmount(() => {
if (parentInfo.childrenEventKeys) {
parentInfo.childrenEventKeys.value = parentInfo.childrenEventKeys?.value.filter(
k => k != eventKey,
);
}
});
useProvideKeyPath(eventKey, menuInfo);
const {
prefixCls,
activeKeys,
disabled: contextDisabled,
changeActiveKeys,
mode,
inlineCollapsed,
antdMenuTheme,
openKeys,
overflowDisabled,
onOpenChange,
registerMenuInfo,
unRegisterMenuInfo,
selectedSubMenuEventKeys,
motion,
defaultMotions,
} = useInjectMenu();
registerMenuInfo(eventKey, menuInfo);
onBeforeUnmount(() => {
unRegisterMenuInfo(eventKey);
});
const subMenuPrefixCls = computed(() => `${prefixCls.value}-submenu`);
const mergedDisabled = computed(() => contextDisabled.value || props.disabled);
const elementRef = ref();
const popupRef = ref();
// // ================================ Icon ================================
// const mergedItemIcon = itemIcon || contextItemIcon;
// const mergedExpandIcon = expandIcon || contextExpandIcon;
// ================================ Open ================================
const originOpen = computed(() => openKeys.value.includes(key));
const open = computed(() => !overflowDisabled.value && originOpen.value);
// =============================== Select ===============================
const childrenSelected = computed(() => {
return selectedSubMenuEventKeys.value.includes(eventKey);
});
const isActive = ref(false);
watch(
activeKeys,
() => {
isActive.value = !!activeKeys.value.find(val => val === key);
},
{ immediate: true },
);
// =============================== Events ===============================
// >>>> Title click
const onInternalTitleClick = (e: Event) => {
// Skip if disabled
if (mergedDisabled.value) {
return;
}
emit('titleClick', e, key);
// Trigger open by click when mode is `inline`
if (mode.value === 'inline') {
onOpenChange(eventKey, !originOpen.value);
}
};
const onMouseEnter = (event: MouseEvent) => {
if (!mergedDisabled.value) {
changeActiveKeys(keysPath.value);
emit('mouseenter', event);
}
};
const onMouseLeave = (event: MouseEvent) => {
if (!mergedDisabled.value) {
changeActiveKeys([]);
emit('mouseleave', event);
}
};
// ========================== DirectionStyle ==========================
const directionStyle = useDirectionStyle(computed(() => keysPath.value.length));
// >>>>> Visible change
const onPopupVisibleChange = (newVisible: boolean) => {
if (mode.value !== 'inline') {
onOpenChange(eventKey, newVisible);
}
};
/**
* Used for accessibility. Helper will focus element without key board.
* We should manually trigger an active
*/
const onInternalFocus = () => {
changeActiveKeys(keysPath.value);
};
// =============================== Render ===============================
const popupId = eventKey && `${eventKey}-popup`;
const popupClassName = computed(() =>
classNames(
prefixCls.value,
`${prefixCls.value}-${antdMenuTheme.value}`,
props.popupClassName,
),
);
const renderTitle = (title: any, icon: any) => {
if (!icon) {
return inlineCollapsed.value && props.level === 1 && title && typeof title === 'string' ? (
<div class={`${prefixCls.value}-inline-collapsed-noicon`}>{title.charAt(0)}</div>
) : (
title
);
}
// inline-collapsed.md demo span , icon span
// ref: https://github.com/ant-design/ant-design/pull/23456
const titleIsSpan = isValidElement(title) && title.type === 'span';
return (
<>
{icon}
{titleIsSpan ? title : <span class={`${prefixCls.value}-title-content`}>{title}</span>}
</>
);
};
// Cache mode if it change to `inline` which do not have popup motion
const triggerModeRef = computed(() => {
return mode.value !== 'inline' && keysPath.value.length > 1 ? 'vertical' : mode.value;
});
const renderMode = computed(() => (mode.value === 'horizontal' ? 'vertical' : mode.value));
const style = ref({});
const className = ref('');
const mergedMotion = computed(() => {
const m = motion.value || defaultMotions.value?.[mode.value] || defaultMotions.value?.other;
const res = typeof m === 'function' ? m(style, className) : m;
return res ? getTransitionProps(res.name) : undefined;
});
return () => {
const icon = getPropsSlot(slots, props, 'icon');
const title = renderTitle(getPropsSlot(slots, props, 'title'), icon);
const subMenuPrefixClsValue = subMenuPrefixCls.value;
let titleNode = (
<div
style={directionStyle.value}
class={`${subMenuPrefixClsValue}-title`}
tabindex={mergedDisabled.value ? null : -1}
ref={elementRef}
title={typeof title === 'string' ? title : null}
data-menu-id={key}
aria-expanded={open.value}
aria-haspopup
aria-controls={popupId}
aria-disabled={mergedDisabled.value}
onClick={onInternalTitleClick}
onFocus={onInternalFocus}
>
{title}
{/* Only non-horizontal mode shows the icon */}
{mode.value !== 'horizontal' && slots.expandIcon ? (
slots.expandIcon({ ...props, isOpen: open.value })
) : (
<i class={`${subMenuPrefixClsValue}-arrow`} />
)}
</div>
);
if (!overflowDisabled.value) {
const triggerMode = triggerModeRef.value;
titleNode = (
<PopupTrigger
mode={triggerMode}
prefixCls={subMenuPrefixClsValue}
visible={!props.internalPopupClose && open.value && mode.value !== 'inline'}
popupClassName={popupClassName.value}
popupOffset={props.popupOffset}
disabled={mergedDisabled.value}
onVisibleChange={onPopupVisibleChange}
v-slots={{
popup: ({ visible }) => (
<MenuContextProvider props={{ mode: triggerModeRef, isRootMenu: false }}>
<Transition {...mergedMotion.value}>
<SubMenuList v-show={visible} id={popupId} ref={popupRef}>
{slots.default?.()}
</SubMenuList>
</Transition>
</MenuContextProvider>
),
}}
>
{titleNode}
</PopupTrigger>
);
}
return (
<MenuContextProvider props={{ mode: renderMode }}>
<li
{...attrs}
role="none"
class={classNames(
subMenuPrefixClsValue,
`${subMenuPrefixClsValue}-${mode.value}`,
attrs.class,
{
[`${subMenuPrefixClsValue}-open`]: open.value,
[`${subMenuPrefixClsValue}-active`]: isActive.value,
[`${subMenuPrefixClsValue}-selected`]: childrenSelected.value,
[`${subMenuPrefixClsValue}-disabled`]: mergedDisabled.value,
},
)}
onMouseenter={onMouseEnter}
onMouseleave={onMouseLeave}
>
{titleNode}
{/* Inline mode */}
{!overflowDisabled.value && (
<InlineSubMenuList id={popupId} open={open.value} keyPath={keysPath.value}>
{slots.default?.()}
</InlineSubMenuList>
)}
</li>
</MenuContextProvider>
);
};
},
});

View File

@ -0,0 +1,23 @@
import classNames from '../../_util/classNames';
import { FunctionalComponent, provide } from 'vue';
import { useInjectMenu } from './hooks/useMenuContext';
const InternalSubMenuList: FunctionalComponent<any> = (_props, { slots, attrs }) => {
const { prefixCls, mode } = useInjectMenu();
return (
<ul
{...attrs}
class={classNames(
prefixCls.value,
`${prefixCls.value}-sub`,
`${prefixCls.value}-${mode.value === 'inline' ? 'inline' : 'vertical'}`,
)}
data-menu-list
>
{slots.default?.()}
</ul>
);
};
InternalSubMenuList.displayName = 'SubMenuList';
export default InternalSubMenuList;

View File

@ -0,0 +1,14 @@
import { computed, ComputedRef, CSSProperties } from 'vue';
import { useInjectMenu } from './useMenuContext';
export default function useDirectionStyle(level: ComputedRef<number>): ComputedRef<CSSProperties> {
const { mode, rtl, inlineIndent } = useInjectMenu();
return computed(() =>
mode.value !== 'inline'
? null
: rtl.value
? { paddingRight: level.value * inlineIndent.value }
: { paddingLeft: level.value * inlineIndent.value },
);
}

View File

@ -0,0 +1,26 @@
import { Key } from '../../../_util/type';
import { computed, ComputedRef, inject, InjectionKey, provide } from 'vue';
import { StoreMenuInfo } from './useMenuContext';
const KeyPathContext: InjectionKey<{
parentEventKeys: ComputedRef<Key[]>;
parentInfo: StoreMenuInfo;
}> = Symbol('KeyPathContext');
const useInjectKeyPath = () => {
return inject(KeyPathContext, {
parentEventKeys: computed(() => []),
parentInfo: {} as StoreMenuInfo,
});
};
const useProvideKeyPath = (eventKey: string, menuInfo: StoreMenuInfo) => {
const { parentEventKeys } = useInjectKeyPath();
const keys = computed(() => [...parentEventKeys.value, eventKey]);
provide(KeyPathContext, { parentEventKeys: keys, parentInfo: menuInfo });
return keys;
};
export { useProvideKeyPath, useInjectKeyPath, KeyPathContext };
export default useProvideKeyPath;

View File

@ -0,0 +1,136 @@
import { Key } from '../../../_util/type';
import {
ComputedRef,
CSSProperties,
defineComponent,
inject,
InjectionKey,
provide,
Ref,
UnwrapRef,
} from 'vue';
import {
BuiltinPlacements,
MenuClickEventHandler,
MenuMode,
MenuTheme,
TriggerSubMenuAction,
} from '../interface';
import { CSSMotionProps } from '../../../_util/transition';
export interface StoreMenuInfo {
eventKey: string;
key: Key;
parentEventKeys: ComputedRef<string[]>;
childrenEventKeys?: Ref<string[]>;
isLeaf?: boolean;
}
export interface MenuContextProps {
isRootMenu: boolean;
store: UnwrapRef<Record<string, StoreMenuInfo>>;
registerMenuInfo: (key: string, info: StoreMenuInfo) => void;
unRegisterMenuInfo: (key: string) => void;
prefixCls: ComputedRef<string>;
openKeys: Ref<Key[]>;
selectedKeys: Ref<Key[]>;
selectedSubMenuEventKeys: Ref<string[]>;
rtl?: ComputedRef<boolean>;
locked?: Ref<boolean>;
inlineCollapsed: Ref<boolean>;
antdMenuTheme?: ComputedRef<MenuTheme>;
siderCollapsed?: ComputedRef<boolean>;
// // Mode
mode: Ref<MenuMode>;
// // Disabled
disabled?: ComputedRef<boolean>;
// // Used for overflow only. Prevent hidden node trigger open
overflowDisabled?: ComputedRef<boolean>;
// // Active
activeKeys: Ref<Key[]>;
changeActiveKeys: (keys: Key[]) => void;
// onActive: (key: string) => void;
// onInactive: (key: string) => void;
// // Selection
// selectedKeys: string[];
// // Level
inlineIndent: ComputedRef<number>;
// // Motion
motion?: ComputedRef<CSSMotionProps | null>;
defaultMotions?: ComputedRef<Partial<
{
[key in MenuMode | 'other']:
| CSSMotionProps
| ((style: Ref<CSSProperties>, className: Ref<string>) => CSSMotionProps);
}
> | null>;
// // Popup
subMenuOpenDelay: ComputedRef<number>;
subMenuCloseDelay: ComputedRef<number>;
// forceSubMenuRender?: boolean;
builtinPlacements?: ComputedRef<BuiltinPlacements>;
triggerSubMenuAction?: ComputedRef<TriggerSubMenuAction>;
// // Icon
// itemIcon?: RenderIconType;
// expandIcon?: RenderIconType;
// // Function
onItemClick: MenuClickEventHandler;
onOpenChange: (key: Key, open: boolean) => void;
getPopupContainer: ComputedRef<(node: HTMLElement) => HTMLElement>;
}
const MenuContextKey: InjectionKey<MenuContextProps> = Symbol('menuContextKey');
const useProvideMenu = (props: MenuContextProps) => {
provide(MenuContextKey, props);
};
const useInjectMenu = () => {
return inject(MenuContextKey);
};
const MenuFirstLevelContextKey: InjectionKey<Boolean> = Symbol('menuFirstLevelContextKey');
const useProvideFirstLevel = (firstLevel: Boolean) => {
provide(MenuFirstLevelContextKey, firstLevel);
};
const useInjectFirstLevel = () => {
return inject(MenuFirstLevelContextKey, true);
};
const MenuContextProvider = defineComponent({
name: 'MenuContextProvider',
inheritAttrs: false,
props: {
props: Object,
},
setup(props, { slots }) {
useProvideMenu({ ...useInjectMenu(), ...props.props });
return () => slots.default?.();
},
});
export {
useProvideMenu,
MenuContextKey,
useInjectMenu,
MenuFirstLevelContextKey,
useProvideFirstLevel,
useInjectFirstLevel,
MenuContextProvider,
};
export default useProvideMenu;

View File

@ -0,0 +1,45 @@
import { Key } from '../../_util/type';
export type MenuTheme = 'light' | 'dark';
// ========================== Basic ==========================
export type MenuMode = 'horizontal' | 'vertical' | 'inline';
export type BuiltinPlacements = Record<string, any>;
export type TriggerSubMenuAction = 'click' | 'hover';
export interface RenderIconInfo {
isSelected?: boolean;
isOpen?: boolean;
isSubMenu?: boolean;
disabled?: boolean;
}
export type RenderIconType = (props: RenderIconInfo) => any;
export interface MenuInfo {
key: Key;
eventKey: string;
keyPath?: Key[];
eventKeyPath: Key[];
domEvent: MouseEvent | KeyboardEvent;
}
export interface MenuTitleInfo {
key: Key;
domEvent: MouseEvent | KeyboardEvent;
}
// ========================== Hover ==========================
export type MenuHoverEventHandler = (info: { key: Key; domEvent: MouseEvent }) => void;
// ======================== Selection ========================
export interface SelectInfo extends MenuInfo {
selectedKeys: Key[];
}
export type SelectEventHandler = (info: SelectInfo) => void;
// ========================== Click ==========================
export type MenuClickEventHandler = (info: MenuInfo) => void;

View File

@ -0,0 +1,52 @@
const autoAdjustOverflow = {
adjustX: 1,
adjustY: 1,
};
export const placements = {
topLeft: {
points: ['bl', 'tl'],
overflow: autoAdjustOverflow,
offset: [0, -7],
},
bottomLeft: {
points: ['tl', 'bl'],
overflow: autoAdjustOverflow,
offset: [0, 7],
},
leftTop: {
points: ['tr', 'tl'],
overflow: autoAdjustOverflow,
offset: [-4, 0],
},
rightTop: {
points: ['tl', 'tr'],
overflow: autoAdjustOverflow,
offset: [4, 0],
},
};
export const placementsRtl = {
topLeft: {
points: ['bl', 'tl'],
overflow: autoAdjustOverflow,
offset: [0, -7],
},
bottomLeft: {
points: ['tl', 'bl'],
overflow: autoAdjustOverflow,
offset: [0, 7],
},
rightTop: {
points: ['tr', 'tl'],
overflow: autoAdjustOverflow,
offset: [-4, 0],
},
leftTop: {
points: ['tl', 'tr'],
overflow: autoAdjustOverflow,
offset: [4, 0],
},
};
export default placements;

View File

@ -1,7 +1,8 @@
.@{menu-prefix-cls} {
// dark theme
&-dark,
&-dark &-sub {
&&-dark,
&-dark &-sub,
&&-dark &-sub {
color: @menu-dark-color;
background: @menu-dark-bg;
.@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-arrow {
@ -19,8 +20,7 @@
}
&-dark &-inline&-sub {
background: @menu-dark-submenu-bg;
box-shadow: 0 2px 8px fade(@black, 45%) inset;
background: @menu-dark-inline-submenu-bg;
}
&-dark&-horizontal {
@ -31,17 +31,23 @@
&-dark&-horizontal > &-submenu {
top: 0;
margin-top: 0;
padding: @menu-item-padding;
border-color: @menu-dark-bg;
border-bottom: 0;
}
&-dark&-horizontal > &-item:hover {
background-color: @menu-dark-item-active-bg;
}
&-dark&-horizontal > &-item > a::before {
bottom: 0;
}
&-dark &-item,
&-dark &-item-group-title,
&-dark &-item > a {
&-dark &-item > a,
&-dark &-item > span > a {
color: @menu-dark-color;
}
@ -77,7 +83,8 @@
&-dark &-submenu-title:hover {
color: @menu-dark-highlight-color;
background-color: transparent;
> a {
> a,
> span > a {
color: @menu-dark-highlight-color;
}
> .@{menu-prefix-cls}-submenu-title,
@ -95,6 +102,10 @@
background-color: @menu-dark-item-hover-bg;
}
&-dark&-dark:not(&-horizontal) &-item-selected {
background-color: @menu-dark-item-active-bg;
}
&-dark &-item-selected {
color: @menu-dark-highlight-color;
border-right: 0;
@ -102,14 +113,19 @@
border-right: 0;
}
> a,
> a:hover {
> span > a,
> a:hover,
> span > a:hover {
color: @menu-dark-highlight-color;
}
.@{menu-prefix-cls}-item-icon,
.@{iconfont-css-prefix} {
color: @menu-dark-selected-item-icon-color;
}
.@{iconfont-css-prefix} + span {
color: @menu-dark-selected-item-text-color;
+ span {
color: @menu-dark-selected-item-text-color;
}
}
}
@ -122,7 +138,8 @@
&-dark &-item-disabled,
&-dark &-submenu-disabled {
&,
> a {
> a,
> span > a {
color: @disabled-color-dark !important;
opacity: 0.8;
}

View File

@ -1,7 +1,15 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './status';
@menu-prefix-cls: ~'@{ant-prefix}-menu';
@menu-animation-duration-normal: 0.15s;
.accessibility-focus() {
box-shadow: 0 0 0 2px fade(@primary-color, 20%);
}
// TODO: Should remove icon style compatible in v5
// default theme
.@{menu-prefix-cls} {
@ -10,14 +18,21 @@
margin-bottom: 0;
padding-left: 0; // Override default ul/ol
color: @menu-item-color;
font-size: @menu-item-font-size;
line-height: 0; // Fix display inline-block gap
text-align: left;
list-style: none;
background: @menu-bg;
outline: none;
box-shadow: @box-shadow-base;
transition: background 0.3s, width 0.3s cubic-bezier(0.2, 0, 0, 1) 0s;
transition: background @animation-duration-slow,
width @animation-duration-slow cubic-bezier(0.2, 0, 0, 1) 0s;
.clearfix();
&&-root:focus-visible {
.accessibility-focus();
}
ul,
ol {
margin: 0;
@ -25,22 +40,29 @@
list-style: none;
}
&-hidden {
&-hidden,
&-submenu-hidden {
display: none;
}
&-item-group-title {
height: @menu-item-group-height;
padding: 8px 16px;
color: @menu-item-group-title-color;
font-size: @font-size-base;
line-height: @line-height-base;
transition: all 0.3s;
font-size: @menu-item-group-title-font-size;
line-height: @menu-item-group-height;
transition: all @animation-duration-slow;
}
&-horizontal &-submenu {
transition: border-color @animation-duration-slow @ease-in-out,
background @animation-duration-slow @ease-in-out;
}
&-submenu,
&-submenu-inline {
transition: border-color 0.3s @ease-in-out, background 0.3s @ease-in-out,
padding 0.15s @ease-in-out;
transition: border-color @animation-duration-slow @ease-in-out,
background @animation-duration-slow @ease-in-out,
padding @menu-animation-duration-normal @ease-in-out;
}
&-submenu-selected {
@ -54,11 +76,11 @@
&-submenu &-sub {
cursor: initial;
transition: background 0.3s @ease-in-out, padding 0.3s @ease-in-out;
transition: background @animation-duration-slow @ease-in-out,
padding @animation-duration-slow @ease-in-out;
}
&-item > a {
display: block;
&-item a {
color: @menu-item-color;
&:hover {
color: @menu-highlight-color;
@ -75,7 +97,7 @@
}
// https://github.com/ant-design/ant-design/issues/19809
&-item > .@{ant-prefix}-badge > a {
&-item > .@{ant-prefix}-badge a {
color: @menu-item-color;
&:hover {
color: @menu-highlight-color;
@ -110,8 +132,8 @@
&-item-selected {
color: @menu-highlight-color;
> a,
> a:hover {
a,
a:hover {
color: @menu-highlight-color;
}
}
@ -125,6 +147,7 @@
&-vertical-left {
border-right: @border-width-base @border-style-base @border-color-split;
}
&-vertical-right {
border-left: @border-width-base @border-style-base @border-color-split;
}
@ -133,9 +156,17 @@
&-vertical-left&-sub,
&-vertical-right&-sub {
min-width: 160px;
max-height: calc(100vh - 100px);
padding: 0;
overflow: hidden;
border-right: 0;
transform-origin: 0 0;
// https://github.com/ant-design/ant-design/issues/22244
// https://github.com/ant-design/ant-design/issues/26812
&:not([class*='-active']) {
overflow-x: hidden;
overflow-y: auto;
}
.@{menu-prefix-cls}-item {
left: 0;
@ -155,26 +186,48 @@
min-width: 114px; // in case of submenu width is too big: https://codesandbox.io/s/qvpwm6mk66
}
&-horizontal &-item,
&-horizontal &-submenu-title {
transition: border-color @animation-duration-slow, background @animation-duration-slow;
}
&-item,
&-submenu-title {
position: relative;
display: block;
margin: 0;
padding: 0 20px;
padding: @menu-item-padding;
white-space: nowrap;
cursor: pointer;
transition: color 0.3s @ease-in-out, border-color 0.3s @ease-in-out,
background 0.3s @ease-in-out, padding 0.15s @ease-in-out;
transition: border-color @animation-duration-slow, background @animation-duration-slow,
padding @animation-duration-slow @ease-in-out;
.@{menu-prefix-cls}-item-icon,
.@{iconfont-css-prefix} {
min-width: 14px;
margin-right: 10px;
font-size: @menu-icon-size;
transition: font-size 0.15s @ease-out, margin 0.3s @ease-in-out;
transition: font-size @menu-animation-duration-normal @ease-out,
margin @animation-duration-slow @ease-in-out, color @animation-duration-slow;
+ span {
margin-left: @menu-icon-margin-right;
opacity: 1;
transition: opacity 0.3s @ease-in-out, width 0.3s @ease-in-out;
// transition: opacity @animation-duration-slow @ease-in-out,
// width @animation-duration-slow @ease-in-out, color @animation-duration-slow;
transition: opacity @animation-duration-slow @ease-in-out, margin @animation-duration-slow,
color @animation-duration-slow;
}
}
&.@{menu-prefix-cls}-item-only-child {
> .@{iconfont-css-prefix},
> .@{menu-prefix-cls}-item-icon {
margin-right: 0;
}
}
&:focus-visible {
.accessibility-focus();
}
}
& > &-item-divider {
@ -190,94 +243,105 @@
&-popup {
position: absolute;
z-index: @zindex-dropdown;
// background: @menu-popup-bg;
background: transparent;
border-radius: @border-radius-base;
box-shadow: none;
transform-origin: 0 0;
.submenu-title-wrapper {
padding-right: 20px;
}
// https://github.com/ant-design/ant-design/issues/13955
&::before {
position: absolute;
top: -7px;
right: 0;
bottom: 0;
left: 0;
z-index: -1;
width: 100%;
height: 100%;
opacity: 0.0001;
content: ' ';
}
}
// https://github.com/ant-design/ant-design/issues/13955
&-placement-rightTop::before {
top: 0;
left: -7px;
}
> .@{menu-prefix-cls} {
background-color: @menu-bg;
border-radius: @border-radius-base;
&-submenu-title::after {
transition: transform 0.3s @ease-in-out;
transition: transform @animation-duration-slow @ease-in-out;
}
}
&-vertical,
&-vertical-left,
&-vertical-right,
&-inline {
> .@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-arrow {
&-popup > .@{menu-prefix-cls} {
background-color: @menu-popup-bg;
}
&-expand-icon,
&-arrow {
position: absolute;
top: 50%;
right: 16px;
width: 10px;
color: @menu-item-color;
transform: translateY(-50%);
transition: transform @animation-duration-slow @ease-in-out;
}
&-arrow {
// →
&::before,
&::after {
position: absolute;
top: 50%;
right: 16px;
width: 10px;
transition: transform 0.3s @ease-in-out;
&::before,
&::after {
position: absolute;
width: 6px;
height: 1.5px;
// background + background-image to makes before & after cross have same color.
// Since `linear-gradient` not work on IE9, we should hack it.
// ref: https://github.com/ant-design/ant-design/issues/15910
background: @menu-bg;
background: ~'@{menu-item-color} \9';
background-image: linear-gradient(to right, @menu-item-color, @menu-item-color);
background-image: ~'none \9';
border-radius: 2px;
transition: background 0.3s @ease-in-out, transform 0.3s @ease-in-out,
top 0.3s @ease-in-out;
content: '';
}
&::before {
transform: rotate(45deg) translateY(-2px);
}
&::after {
transform: rotate(-45deg) translateY(2px);
}
width: 6px;
height: 1.5px;
background-color: currentColor;
border-radius: 2px;
transition: background @animation-duration-slow @ease-in-out,
transform @animation-duration-slow @ease-in-out, top @animation-duration-slow @ease-in-out,
color @animation-duration-slow @ease-in-out;
content: '';
}
> .@{menu-prefix-cls}-submenu-title:hover .@{menu-prefix-cls}-submenu-arrow {
&::after,
&::before {
background: linear-gradient(to right, @menu-highlight-color, @menu-highlight-color);
}
}
}
&-inline > .@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-arrow {
&::before {
transform: rotate(-45deg) translateX(2px);
transform: rotate(45deg) translateY(-2.5px);
}
&::after {
transform: rotate(45deg) translateX(-2px);
transform: rotate(-45deg) translateY(2.5px);
}
}
&-open {
&.@{menu-prefix-cls}-submenu-inline
> .@{menu-prefix-cls}-submenu-title
.@{menu-prefix-cls}-submenu-arrow {
transform: translateY(-2px);
&::after {
transform: rotate(-45deg) translateX(-2px);
}
&::before {
transform: rotate(45deg) translateX(2px);
}
&:hover > &-title > &-expand-icon,
&:hover > &-title > &-arrow {
color: @menu-highlight-color;
}
.@{menu-prefix-cls}-inline-collapsed &-arrow,
&-inline &-arrow {
// ↓
&::before {
transform: rotate(-45deg) translateX(2.5px);
}
&::after {
transform: rotate(45deg) translateX(-2.5px);
}
}
&-horizontal &-arrow {
display: none;
}
&-open&-inline > &-title > &-arrow {
// ↑
transform: translateY(-2px);
&::after {
transform: rotate(-45deg) translateX(-2.5px);
}
&::before {
transform: rotate(45deg) translateX(2.5px);
}
}
}
@ -286,18 +350,34 @@
&-vertical-left &-submenu-selected,
&-vertical-right &-submenu-selected {
color: @menu-highlight-color;
> a {
color: @menu-highlight-color;
}
}
&-horizontal {
line-height: 46px;
white-space: nowrap;
line-height: @menu-horizontal-line-height;
border: 0;
border-bottom: @border-width-base @border-style-base @border-color-split;
box-shadow: none;
&:not(.@{menu-prefix-cls}-dark) {
> .@{menu-prefix-cls}-item,
> .@{menu-prefix-cls}-submenu {
margin: @menu-item-padding;
margin-top: -1px;
margin-bottom: 0;
padding: @menu-item-padding;
padding-right: 0;
padding-left: 0;
&:hover,
&-active,
&-open,
&-selected {
color: @menu-highlight-color;
border-bottom: 2px solid @menu-highlight-color;
}
}
}
> .@{menu-prefix-cls}-item,
> .@{menu-prefix-cls}-submenu {
position: relative;
@ -305,19 +385,14 @@
display: inline-block;
vertical-align: bottom;
border-bottom: 2px solid transparent;
}
&:hover,
&-active,
&-open,
&-selected {
color: @menu-highlight-color;
border-bottom: 2px solid @menu-highlight-color;
}
> .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {
padding: 0;
}
> .@{menu-prefix-cls}-item {
> a {
display: block;
a {
color: @menu-item-color;
&:hover {
color: @menu-highlight-color;
@ -326,7 +401,7 @@
bottom: -2px;
}
}
&-selected > a {
&-selected a {
color: @menu-highlight-color;
}
}
@ -353,7 +428,8 @@
border-right: @menu-item-active-border-width solid @menu-highlight-color;
transform: scaleY(0.0001);
opacity: 0;
transition: transform 0.15s @ease-out, opacity 0.15s @ease-out;
transition: transform @menu-animation-duration-normal @ease-out,
opacity @menu-animation-duration-normal @ease-out;
content: '';
}
}
@ -365,7 +441,6 @@
margin-bottom: @menu-item-vertical-margin;
padding: 0 16px;
overflow: hidden;
font-size: @menu-item-font-size;
line-height: @menu-item-height;
text-overflow: ellipsis;
}
@ -386,6 +461,13 @@
}
}
&-vertical {
.@{menu-prefix-cls}-item-group-list .@{menu-prefix-cls}-submenu-title,
.@{menu-prefix-cls}-submenu-title {
padding-right: 34px;
}
}
&-inline {
width: 100%;
.@{menu-prefix-cls}-selected,
@ -393,7 +475,8 @@
&::after {
transform: scaleY(1);
opacity: 1;
transition: transform 0.15s @ease-in-out, opacity 0.15s @ease-in-out;
transition: transform @menu-animation-duration-normal @ease-in-out,
opacity @menu-animation-duration-normal @ease-in-out;
}
}
@ -402,13 +485,37 @@
width: ~'calc(100% + 1px)';
}
.@{menu-prefix-cls}-item-group-list .@{menu-prefix-cls}-submenu-title,
.@{menu-prefix-cls}-submenu-title {
padding-right: 34px;
}
// Motion enhance for first level
&.@{menu-prefix-cls}-root {
.@{menu-prefix-cls}-item,
.@{menu-prefix-cls}-submenu-title {
display: flex;
align-items: center;
transition: border-color @animation-duration-slow, background @animation-duration-slow,
padding 0.1s @ease-out;
> .@{menu-prefix-cls}-title-content {
flex: auto;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
}
> * {
flex: none;
}
}
}
}
&-inline-collapsed {
&&-inline-collapsed {
width: @menu-collapsed-width;
> .@{menu-prefix-cls}-item,
> .@{menu-prefix-cls}-item-group
> .@{menu-prefix-cls}-item-group-list
@ -419,24 +526,34 @@
> .@{menu-prefix-cls}-submenu-title,
> .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {
left: 0;
padding: 0 ((@menu-collapsed-width - @menu-icon-size-lg) / 2) !important;
padding: 0 ~'calc(50% - @{menu-icon-size-lg} / 2)';
text-overflow: clip;
.@{menu-prefix-cls}-submenu-arrow {
display: none;
}
.@{menu-prefix-cls}-item-icon,
.@{iconfont-css-prefix} {
margin: 0;
font-size: @menu-icon-size-lg;
line-height: @menu-item-height;
+ span {
display: inline-block;
max-width: 0;
opacity: 0;
}
}
}
.@{menu-prefix-cls}-item-icon,
.@{iconfont-css-prefix} {
display: inline-block;
}
&-tooltip {
pointer-events: none;
.@{menu-prefix-cls}-item-icon,
.@{iconfont-css-prefix} {
display: none;
}
@ -470,8 +587,19 @@
box-shadow: none;
}
&-root&-inline-collapsed {
.@{menu-prefix-cls}-item,
.@{menu-prefix-cls}-submenu .@{menu-prefix-cls}-submenu-title {
> .@{menu-prefix-cls}-inline-collapsed-noicon {
font-size: @menu-icon-size-lg;
text-align: center;
}
}
}
&-sub&-inline {
padding: 0;
background: @menu-inline-submenu-bg;
border: 0;
border-radius: 0;
box-shadow: none;
@ -495,7 +623,7 @@
background: none;
border-color: transparent !important;
cursor: not-allowed;
> a {
a {
color: @disabled-color !important;
pointer-events: none;
}
@ -512,4 +640,12 @@
}
}
// Integration with header element so menu items have the same height
.@{ant-prefix}-layout-header {
.@{menu-prefix-cls} {
line-height: inherit;
}
}
@import './dark';
@import './rtl';

View File

@ -0,0 +1,164 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@menu-prefix-cls: ~'@{ant-prefix}-menu';
.@{menu-prefix-cls} {
&&-rtl {
direction: rtl;
text-align: right;
}
&-item-group-title {
.@{menu-prefix-cls}-rtl & {
text-align: right;
}
}
&-inline,
&-vertical {
.@{menu-prefix-cls}-rtl& {
border-right: none;
border-left: @border-width-base @border-style-base @border-color-split;
}
}
&-dark&-inline,
&-dark&-vertical {
.@{menu-prefix-cls}-rtl& {
border-left: none;
}
}
&-vertical&-sub,
&-vertical-left&-sub,
&-vertical-right&-sub {
> .@{menu-prefix-cls}-item,
> .@{menu-prefix-cls}-submenu {
.@{menu-prefix-cls}-rtl& {
transform-origin: top right;
}
}
}
&-item,
&-submenu-title {
.@{menu-prefix-cls}-item-icon,
.@{iconfont-css-prefix} {
.@{menu-prefix-cls}-rtl & {
margin-right: auto;
margin-left: @menu-icon-margin-right;
}
}
&.@{menu-prefix-cls}-item-only-child {
> .@{menu-prefix-cls}-item-icon,
> .@{iconfont-css-prefix} {
.@{menu-prefix-cls}-rtl & {
margin-left: 0;
}
}
}
}
&-submenu {
&-rtl.@{menu-prefix-cls}-submenu-popup {
transform-origin: 100% 0;
}
&-vertical,
&-vertical-left,
&-vertical-right,
&-inline {
> .@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-arrow {
.@{menu-prefix-cls}-rtl & {
right: auto;
left: 16px;
}
}
}
&-vertical,
&-vertical-left,
&-vertical-right {
> .@{menu-prefix-cls}-submenu-title .@{menu-prefix-cls}-submenu-arrow {
&::before {
.@{menu-prefix-cls}-rtl & {
transform: rotate(-45deg) translateY(-2px);
}
}
&::after {
.@{menu-prefix-cls}-rtl & {
transform: rotate(45deg) translateY(2px);
}
}
}
}
}
&-vertical,
&-vertical-left,
&-vertical-right,
&-inline {
.@{menu-prefix-cls}-item {
&::after {
.@{menu-prefix-cls}-rtl& {
right: auto;
left: 0;
}
}
}
.@{menu-prefix-cls}-item,
.@{menu-prefix-cls}-submenu-title {
.@{menu-prefix-cls}-rtl& {
text-align: right;
}
}
}
&-inline {
.@{menu-prefix-cls}-submenu-title {
.@{menu-prefix-cls}-rtl& {
padding-right: 0;
padding-left: 34px;
}
}
}
&-vertical {
.@{menu-prefix-cls}-submenu-title {
.@{menu-prefix-cls}-rtl& {
padding-right: 16px;
padding-left: 34px;
}
}
}
&-inline-collapsed&-vertical {
.@{menu-prefix-cls}-submenu-title {
.@{menu-prefix-cls}-rtl& {
padding: 0 ~'calc(50% - @{menu-icon-size-lg} / 2)';
}
}
}
&-item-group-list {
.@{menu-prefix-cls}-item,
.@{menu-prefix-cls}-submenu-title {
.@{menu-prefix-cls}-rtl & {
padding: 0 28px 0 16px;
}
}
}
&-sub&-inline {
border: 0;
& .@{menu-prefix-cls}-item-group-title {
.@{menu-prefix-cls}-rtl& {
padding-right: 32px;
padding-left: 0;
}
}
}
}

View File

@ -0,0 +1,47 @@
@import './index';
.@{menu-prefix-cls} {
// Danger
&-item-danger&-item {
color: @menu-highlight-danger-color;
&:hover,
&-active {
color: @menu-highlight-danger-color;
}
&:active {
background: @menu-item-active-danger-bg;
}
&-selected {
color: @menu-highlight-danger-color;
> a,
> a:hover {
color: @menu-highlight-danger-color;
}
}
.@{menu-prefix-cls}:not(.@{menu-prefix-cls}-horizontal) &-selected {
background-color: @menu-item-active-danger-bg;
}
.@{menu-prefix-cls}-inline &::after {
border-right-color: @menu-highlight-danger-color;
}
}
// ==================== Dark ====================
&-dark &-item-danger&-item {
&,
&:hover,
& > a {
color: @menu-dark-danger-color;
}
}
&-dark&-dark:not(&-horizontal) &-item-danger&-item-selected {
color: @menu-dark-highlight-color;
background-color: @menu-dark-item-active-danger-bg;
}
}

View File

@ -239,7 +239,6 @@ a {
&[disabled] {
color: @disabled-color;
cursor: not-allowed;
pointer-events: none;
}
}

View File

@ -3,7 +3,6 @@
@import 'motion/move';
@import 'motion/other';
@import 'motion/slide';
@import 'motion/swing';
@import 'motion/zoom';
// For common/openAnimation

View File

@ -1,11 +1,12 @@
.fade-motion(@className, @keyframeName) {
.make-motion(@className, @keyframeName);
.@{className}-enter,
.@{className}-appear {
@name: ~'@{ant-prefix}-@{className}';
.make-motion(@name, @keyframeName);
.@{name}-enter,
.@{name}-appear {
opacity: 0;
animation-timing-function: linear;
}
.@{className}-leave {
.@{name}-leave {
animation-timing-function: linear;
}
}

View File

@ -1,11 +1,12 @@
.move-motion(@className, @keyframeName) {
.make-motion(@className, @keyframeName);
.@{className}-enter,
.@{className}-appear {
@name: ~'@{ant-prefix}-@{className}';
.make-motion(@name, @keyframeName);
.@{name}-enter,
.@{name}-appear {
opacity: 0;
animation-timing-function: @ease-out-circ;
}
.@{className}-leave {
.@{name}-leave {
animation-timing-function: @ease-in-circ;
}
}

View File

@ -4,17 +4,23 @@
}
}
[ant-click-animating='true'],
[ant-click-animating-without-extra-node='true'] {
@click-animating-true: ~"[@{ant-prefix}-click-animating='true']";
@click-animating-with-extra-node-true: ~"[@{ant-prefix}-click-animating-without-extra-node='true']";
@{click-animating-true},
@{click-animating-with-extra-node-true} {
position: relative;
}
html {
--antd-wave-shadow-color: @primary-color;
--scroll-bar: 0;
}
[ant-click-animating-without-extra-node='true']::after,
.ant-click-animating-node {
@click-animating-with-extra-node-true-after: ~'@{click-animating-with-extra-node-true}::after';
@{click-animating-with-extra-node-true-after},
.@{ant-prefix}-click-animating-node {
position: absolute;
top: 0;
right: 0;

View File

@ -1,11 +1,12 @@
.slide-motion(@className, @keyframeName) {
.make-motion(@className, @keyframeName);
.@{className}-enter,
.@{className}-appear {
@name: ~'@{ant-prefix}-@{className}';
.make-motion(@name, @keyframeName);
.@{name}-enter,
.@{name}-appear {
opacity: 0;
animation-timing-function: @ease-out-quint;
}
.@{className}-leave {
.@{name}-leave {
animation-timing-function: @ease-in-quint;
}
}

View File

@ -1,34 +0,0 @@
.swing-motion(@className, @keyframeName) {
.@{className}-enter,
.@{className}-appear {
.motion-common();
animation-play-state: paused;
}
.@{className}-enter.@{className}-enter-active,
.@{className}-appear.@{className}-appear-active {
animation-name: ~'@{keyframeName}In';
animation-play-state: running;
}
}
.swing-motion(swing, antSwing);
@keyframes antSwingIn {
0%,
100% {
transform: translateX(0);
}
20% {
transform: translateX(-10px);
}
40% {
transform: translateX(10px);
}
60% {
transform: translateX(-5px);
}
80% {
transform: translateX(5px);
}
}

View File

@ -1,15 +1,17 @@
.zoom-motion(@className, @keyframeName, @duration: @animation-duration-base) {
.make-motion(@className, @keyframeName, @duration);
.@{className}-enter,
.@{className}-appear {
@name: ~'@{ant-prefix}-@{className}';
.make-motion(@name, @keyframeName, @duration);
.@{name}-enter,
.@{name}-appear {
transform: scale(0); // need this by yiminghe
opacity: 0;
animation-timing-function: @ease-out-circ;
&-prepare {
transform: none;
}
}
.@{className}-leave {
.@{name}-leave {
animation-timing-function: @ease-in-out-circ;
}
}
@ -54,7 +56,7 @@
opacity: 0;
}
5% {
transform: scale(0.2);
transform: scale(0.8);
opacity: 0;
}
100% {

View File

@ -490,28 +490,37 @@
// ---
@menu-inline-toplevel-item-height: 40px;
@menu-item-height: 40px;
@menu-item-group-height: @line-height-base;
@menu-collapsed-width: 80px;
@menu-bg: @component-background;
@menu-popup-bg: @component-background;
@menu-item-color: @text-color;
@menu-inline-submenu-bg: @background-color-light;
@menu-highlight-color: @primary-color;
@menu-item-active-bg: @item-active-bg;
@menu-highlight-danger-color: @error-color;
@menu-item-active-bg: @primary-1;
@menu-item-active-danger-bg: @red-1;
@menu-item-active-border-width: 3px;
@menu-item-group-title-color: @text-color-secondary;
@menu-icon-size: @font-size-base;
@menu-icon-size-lg: @font-size-lg;
@menu-item-vertical-margin: 4px;
@menu-item-font-size: @font-size-base;
@menu-item-boundary-margin: 8px;
@menu-item-padding: 0 20px;
@menu-horizontal-line-height: 46px;
@menu-icon-margin-right: 10px;
@menu-icon-size: @menu-item-font-size;
@menu-icon-size-lg: @font-size-lg;
@menu-item-group-title-font-size: @menu-item-font-size;
// dark theme
@menu-dark-color: @text-color-secondary-dark;
@menu-dark-danger-color: @error-color;
@menu-dark-bg: @layout-header-background;
@menu-dark-arrow-color: #fff;
@menu-dark-submenu-bg: #000c17;
@menu-dark-inline-submenu-bg: #000c17;
@menu-dark-highlight-color: #fff;
@menu-dark-item-active-bg: @primary-color;
@menu-dark-item-active-danger-bg: @error-color;
@menu-dark-selected-item-icon-color: @white;
@menu-dark-selected-item-text-color: @white;
@menu-dark-item-hover-bg: transparent;

View File

@ -0,0 +1,105 @@
import {
computed,
CSSProperties,
defineComponent,
HTMLAttributes,
onUnmounted,
PropType,
ref,
} from 'vue';
import ResizeObserver from '../vc-resize-observer';
import classNames from '../_util/classNames';
import { Key, VueNode } from '../_util/type';
import PropTypes from '../_util/vue-types';
export default defineComponent({
name: 'InternalItem',
props: {
prefixCls: String,
item: PropTypes.any,
renderItem: Function as PropType<(item: any) => VueNode>,
responsive: Boolean,
itemKey: [String, Number],
registerSize: Function as PropType<(key: Key, width: number | null) => void>,
display: Boolean,
order: Number,
component: PropTypes.any,
invalidate: Boolean,
},
setup(props, { slots, expose }) {
const mergedHidden = computed(() => props.responsive && !props.display);
const itemNodeRef = ref();
expose({ itemNodeRef });
// ================================ Effect ================================
function internalRegisterSize(width: number | null) {
props.registerSize(props.itemKey!, width);
}
onUnmounted(() => {
internalRegisterSize(null);
});
return () => {
const {
prefixCls,
invalidate,
item,
renderItem,
responsive,
registerSize,
itemKey,
display,
order,
component: Component = 'div',
...restProps
} = props;
const children = slots.default?.();
// ================================ Render ================================
const childNode = renderItem && item !== undefined ? renderItem(item) : children;
let overflowStyle: CSSProperties | undefined;
if (!invalidate) {
overflowStyle = {
opacity: mergedHidden.value ? 0 : 1,
height: mergedHidden.value ? 0 : undefined,
overflowY: mergedHidden.value ? 'hidden' : undefined,
order: responsive ? order : undefined,
pointerEvents: mergedHidden.value ? 'none' : undefined,
};
}
const overflowProps: HTMLAttributes = {};
if (mergedHidden.value) {
overflowProps['aria-hidden'] = true;
}
let itemNode = (
<Component
class={classNames(!invalidate && prefixCls)}
style={overflowStyle}
{...overflowProps}
{...restProps}
ref={itemNodeRef}
>
{childNode}
</Component>
);
if (responsive) {
itemNode = (
<ResizeObserver
onResize={({ offsetWidth }) => {
internalRegisterSize(offsetWidth);
}}
>
{itemNode}
</ResizeObserver>
);
}
return itemNode;
};
},
});

View File

@ -0,0 +1,5 @@
// import Overflow, { OverflowProps } from './Overflow';
// export { OverflowProps };
// export default Overflow;

View File

@ -47,7 +47,7 @@ export default defineComponent({
showAction: PropTypes.any.def([]),
hideAction: PropTypes.any.def([]),
getPopupClassNameFromAlign: PropTypes.any.def(returnEmptyString),
// onPopupVisibleChange: PropTypes.func.def(noop),
onPopupVisibleChange: PropTypes.func.def(noop),
afterPopupVisibleChange: PropTypes.func.def(noop),
popup: PropTypes.any,
popupStyle: PropTypes.object.def(() => ({})),
@ -443,7 +443,7 @@ export default defineComponent({
},
setPopupVisible(sPopupVisible, event) {
const { alignPoint, sPopupVisible: prevPopupVisible, $attrs } = this;
const { alignPoint, sPopupVisible: prevPopupVisible, onPopupVisibleChange } = this;
this.clearDelayTimer();
if (prevPopupVisible !== sPopupVisible) {
if (!hasProp(this, 'popupVisible')) {
@ -452,7 +452,7 @@ export default defineComponent({
prevPopupVisible,
});
}
$attrs.onPopupVisibleChange && $attrs.onPopupVisibleChange(sPopupVisible);
onPopupVisibleChange && onPopupVisibleChange(sPopupVisible);
}
// Always record the point position since mouseEnterDelay will delay the show
if (alignPoint && event) {

View File

@ -0,0 +1,7 @@
import devWarning, { resetWarned } from './warning';
export { resetWarned };
export default (valid: boolean, component: string, message: string): void => {
devWarning(valid, `[ant-design-vue: ${component}] ${message}`);
};

View File

@ -1,39 +1,107 @@
<template>
<div>
<demo />
<div style="width: 256px">
<a-button type="primary" style="margin-bottom: 16px" @click="toggleCollapsed">
<MenuUnfoldOutlined v-if="collapsed" />
<MenuFoldOutlined v-else />
</a-button>
<a-menu
v-model:openKeys="openKeys"
v-model:selectedKeys="selectedKeys"
mode="inline"
theme="dark"
:inline-collapsed="collapsed"
>
<!-- <a-menu-item key="1">
<template #icon>
<PieChartOutlined />
</template>
<span>Option 1</span>
</a-menu-item>
<a-menu-item key="2">
<template #icon>
<DesktopOutlined />
</template>
<span>Option 2</span>
</a-menu-item>
<a-menu-item key="3">
<template #icon>
<InboxOutlined />
</template>
<span>Option 3</span>
</a-menu-item>
<a-sub-menu key="sub1">
<template #title>
<span>
<MailOutlined />
<span>Navigation One</span>
</span>
</template>
<a-menu-item key="5">Option 5</a-menu-item>
<a-menu-item key="6">Option 6</a-menu-item>
<a-menu-item key="7">Option 7</a-menu-item>
<a-menu-item key="8">Option 8</a-menu-item>
</a-sub-menu> -->
<a-sub-menu key="sub2">
<template #title>
<span>
<AppstoreOutlined />
<span>Navigation Two</span>
</span>
</template>
<a-menu-item key="9">Option 9</a-menu-item>
<a-menu-item key="10">Option 10</a-menu-item>
<a-sub-menu key="sub3" title="Submenu">
<a-menu-item key="11">Option 11</a-menu-item>
<a-menu-item key="12">Option 12</a-menu-item>
</a-sub-menu>
</a-sub-menu>
</a-menu>
</div>
</template>
<script>
import { defineComponent } from 'vue';
import demo from '../v2-doc/src/docs/tooltip/demo/index.vue';
// import Affix from '../components/affix';
<script lang="ts">
import { defineComponent, reactive, toRefs, watch } from 'vue';
import {
MenuFoldOutlined,
MenuUnfoldOutlined,
PieChartOutlined,
MailOutlined,
DesktopOutlined,
InboxOutlined,
AppstoreOutlined,
} from '@ant-design/icons-vue';
export default defineComponent({
components: {
demo,
// Affix,
MenuFoldOutlined,
MenuUnfoldOutlined,
PieChartOutlined,
MailOutlined,
DesktopOutlined,
InboxOutlined,
AppstoreOutlined,
},
data() {
return {
visible: false,
pStyle: {
fontSize: '16px',
color: 'rgba(0,0,0,0.85)',
lineHeight: '24px',
display: 'block',
marginBottom: '16px',
},
pStyle2: {
marginBottom: '24px',
setup() {
const state = reactive({
collapsed: false,
selectedKeys: ['1'],
openKeys: ['sub1'],
preOpenKeys: ['sub1'],
});
watch(
() => state.openKeys,
(val, oldVal) => {
state.preOpenKeys = oldVal;
},
);
const toggleCollapsed = () => {
state.collapsed = !state.collapsed;
// state.openKeys = state.collapsed ? [] : state.preOpenKeys;
};
return {
...toRefs(state),
toggleCollapsed,
};
},
methods: {
showDrawer() {
this.visible = true;
},
onClose() {
this.visible = false;
},
},
});
</script>

2
v2-doc

@ -1 +1 @@
Subproject commit eacad021cf9e4d7d18fe4c4b9a38cbd7e3378d49
Subproject commit d197053285b81e77718621c0b5b94cb3b21831a2