Commit a04462e8 authored by Sendya's avatar Sendya

fix: side menu wrapper

parent 71c634b8
import { createApp, reactive } from 'vue'; import { createApp, reactive } from 'vue';
import 'ant-design-vue/dist/antd.less';
import { Button, message } from 'ant-design-vue'; import { Button, message } from 'ant-design-vue';
import { default as BasicLayout } from '../src/BasicLayout'; import { default as BasicLayout } from '../src/BasicLayout';
import 'ant-design-vue/dist/antd.less';
import { menus } from './menus'; import { menus } from './menus';
import BaseMenu, { useMenuState } from '../src/SiderMenu/BaseMenu'; import { useMenuState } from '../src/SiderMenu/BaseMenu';
import * as Icon from '@ant-design/icons-vue'; import * as Icon from '@ant-design/icons-vue';
const SimpleDemo = { const SimpleDemo = {
...@@ -19,21 +18,25 @@ const SimpleDemo = { ...@@ -19,21 +18,25 @@ const SimpleDemo = {
<div class="components"> <div class="components">
<h2># BasicLayout</h2> <h2># BasicLayout</h2>
<BasicLayout <BasicLayout
menus={menus} v-model={[menuState.collapsed, 'collapsed']}
collapsed={menuState.collapsed} title={'Pro Layout'}
layout={'side'}
theme={'dark'}
isMobile={false}
menuData={menus}
matchMenuKeys={[]}
contentWidth={'Fixed'}
primaryColor={'#1890ff'}
siderWidth={208}
openKeys={menuState.openKeys} openKeys={menuState.openKeys}
selectedKeys={menuState.selectedKeys} selectedKeys={menuState.selectedKeys}
{...{ onOpenChange={$event => {
'onUpdate:collapsed': $event => {
menuState.collapsed = $event;
},
'onUpdate:openKeys': $event => {
menuState.openKeys = $event menuState.openKeys = $event
}, }}
'onUpdate:selectedKeys': $event => { onSelect={$event => {
menuState.selectedKeys = $event menuState.selectedKeys = $event
}
}} }}
> >
<Button <Button
onClick={() => { onClick={() => {
......
...@@ -31,17 +31,17 @@ export const menus: RouteProps[] = [ ...@@ -31,17 +31,17 @@ export const menus: RouteProps[] = [
{ {
path: '/form/basic-form', path: '/form/basic-form',
name: 'basic-form', name: 'basic-form',
meta: { title: 'Basic Form' }, meta: { icon: 'SmileOutlined', title: 'Basic Form' },
}, },
{ {
path: '/form/step-form', path: '/form/step-form',
name: 'step-form', name: 'step-form',
meta: { title: 'Step Form' }, meta: { icon: 'SmileOutlined', title: 'Step Form' },
}, },
{ {
path: '/form/advanced-form', path: '/form/advanced-form',
name: 'advance-form', name: 'advance-form',
meta: { title: 'Advanced Form' }, meta: { icon: 'SmileOutlined', title: 'Advanced Form' },
}, },
], ],
}, },
......
.side-menu-demo {
.ant-pro-basicLayout {
.trigger {
padding: 0 24px;
font-size: 18px;
}
}
}
import { createApp, reactive } from 'vue';
import 'ant-design-vue/dist/antd.less';
import './side-menu.less';
import { Card, Space, Button, Layout } from 'ant-design-vue';
import { menus } from './menus';
import SiderMenuWrapper from '../src/SiderMenu';
import * as Icon from '@ant-design/icons-vue';
import { MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons-vue';
import { useMenuState } from '../src/SiderMenu/BaseMenu';
const DemoComponent = {
setup() {
const {
state: menuState,
} = useMenuState({
collapsed: false,
openKeys: ['/dashboard'] as string[],
selectedKeys: ['/dashboard/monitor'] as string[],
});
const handleClick = () => {
menuState.collapsed = !menuState.collapsed;
console.log('handleClick', menuState.collapsed);
};
const handleOpenChange = (openKeys: string[]) => {
menuState.openKeys = openKeys;
}
const handleSelect = (selectedKeys: string[]) => {
menuState.selectedKeys = selectedKeys;
}
return () => (
<div class="components">
<h2># SideMenu</h2>
<div class="demo" style="background: rgb(244,244,244); min-height: 400px;">
<div class="container side-menu-demo">
<Layout class="ant-pro-basicLayout">
<SiderMenuWrapper
title={'Pro Layout'}
layout={'side'}
theme={'dark'}
isMobile={false}
collapsed={menuState.collapsed}
menuData={menus}
openKeys={menuState.openKeys}
selectedKeys={menuState.selectedKeys}
onOpenChange={handleOpenChange}
onSelect={handleSelect}
matchMenuKeys={[]}
contentWidth={'Fixed'}
primaryColor={'#1890ff'}
siderWidth={208}
/>
<Layout>
<Layout.Header style="background: #fff; padding: 0; height: 48px; line-height: 48px;">
{
menuState.collapsed
? <MenuUnfoldOutlined class="trigger" onClick={handleClick} />
: <MenuFoldOutlined class="trigger" onClick={handleClick} />
}
</Layout.Header>
<Layout.Content style={{ margin: '24px 16px', padding: '24px', background: '#fff', minHeight: '280px' }}>
<div>Context</div>
</Layout.Content>
</Layout>
</Layout>
</div>
</div>
</div>
);
},
};
const app = createApp(DemoComponent);
const filterIcons = ['default', 'createFromIconfontCN', 'getTwoToneColor', 'setTwoToneColor']
Object.keys(Icon)
.filter(k => !filterIcons.includes(k))
.forEach(k => {
app.component(Icon[k].displayName, Icon[k])
})
app.mount('#__vue-content>div');
import './BasicLayoutTest.less'; import './BasicLayoutTest.less';
import { h, App } from 'vue'; import { App } from 'vue';
import { Layout, Menu } from 'ant-design-vue'; import { Layout } from 'ant-design-vue';
import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue'; import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue';
import { default as ProProvider } from './ProProvider'; import { default as ProProvider } from './ProProvider';
import { default as SiderMenu } from './SiderMenu/SiderMenu'; import { createRouteContext } from './RouteContext';
import { createContext } from './RouteContext'; import SiderMenuWrapper from './SiderMenu';
const defaultI18nRender = (key: string) => key const defaultI18nRender = (key: string) => key
const { state, provider: RouteContextProvider } = createContext({ const { state, provider: RouteContextProvider } = createRouteContext({
isMobile: false, isMobile: false,
menuData: [], menuData: [],
hasSiderMenu: true, sideWidth: 208,
hasSideMenu: true,
hasHeader: true, hasHeader: true,
siderWidth: 208,
}) })
const BasicLayout = (props, { emit, slots }) => { const BasicLayout = (props, { emit, slots }) => {
...@@ -32,9 +32,9 @@ const BasicLayout = (props, { emit, slots }) => { ...@@ -32,9 +32,9 @@ const BasicLayout = (props, { emit, slots }) => {
<ProProvider {...props} i18n={defaultI18nRender}> <ProProvider {...props} i18n={defaultI18nRender}>
<RouteContextProvider> <RouteContextProvider>
<Layout class="ant-pro-basicLayout"> <Layout class="ant-pro-basicLayout">
<SiderMenu {...props} /> <SiderMenuWrapper {...props} />
<Layout> <Layout>
<Layout.Header style="background: #fff; padding: 0"> <Layout.Header style="background: #fff; padding: 0; height: 48px; line-height: 48px;">
{ {
props.collapsed props.collapsed
? <MenuUnfoldOutlined class="trigger" onClick={handleClick} /> ? <MenuUnfoldOutlined class="trigger" onClick={handleClick} />
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
.trigger { .trigger {
font-size: 18px; font-size: 18px;
line-height: 64px; line-height: 48px;
padding: 0 24px; padding: 0 12px;
cursor: pointer; cursor: pointer;
transition: color 0.3s; transition: color 0.3s;
......
import { defineComponent, reactive, toRefs, Ref, InjectionKey, provide, SetupContext, App, PropType } from 'vue'; import { defineComponent, reactive, toRefs, Ref, InjectionKey, provide, SetupContext, App, PropType } from 'vue';
import { ContentWidth } from '../typings'; import { ContentWidth } from '../typings';
export const defaultPrefixCls = 'ant-pro';
export interface ProProviderData { export interface ProProviderData {
getPrefixCls?: (suffixCls?: string, customizePrefixCls?: string) => string; getPrefixCls?: (suffixCls?: string, customizePrefixCls?: string) => string;
i18n?: (t: string) => string; i18n?: (t: string) => string;
...@@ -10,7 +12,7 @@ export interface ProProviderData { ...@@ -10,7 +12,7 @@ export interface ProProviderData {
export const defaultProProviderProps: ProProviderData = { export const defaultProProviderProps: ProProviderData = {
getPrefixCls: (suffixCls?: string, customizePrefixCls?: string) => { getPrefixCls: (suffixCls?: string, customizePrefixCls?: string) => {
if (customizePrefixCls) return customizePrefixCls; if (customizePrefixCls) return customizePrefixCls;
return `ant-pro-${suffixCls}`; return `${defaultPrefixCls}-${suffixCls}`;
}, },
i18n: (t: string): string => t, i18n: (t: string): string => t,
contentWidth: 'Fluid', contentWidth: 'Fluid',
......
...@@ -4,8 +4,10 @@ import { defineComponent, h, resolveDynamicComponent, resolveComponent, VNode, r ...@@ -4,8 +4,10 @@ import { defineComponent, h, resolveDynamicComponent, resolveComponent, VNode, r
// import * as Icon from '@ant-design/icons-vue'; // import * as Icon from '@ant-design/icons-vue';
import { createFromIconfontCN } from '@ant-design/icons-vue'; import { createFromIconfontCN } from '@ant-design/icons-vue';
import 'ant-design-vue/es/menu/style' // import 'ant-design-vue/es/menu/style'
import Menu from 'ant-design-vue/es/menu' // import Menu from 'ant-design-vue/es/menu'
import { Menu } from 'ant-design-vue';
import defaultSettings, { PureSettings } from '../defaultSettings'; import defaultSettings, { PureSettings } from '../defaultSettings';
import { isImg, isUrl } from '../utils' import { isImg, isUrl } from '../utils'
......
import './index.less'; import './index.less';
import { computed, ref, VNodeChild, SetupContext, inject } from 'vue';
import { VNodeChild, SetupContext, inject } from 'vue'; // import 'ant-design-vue/es/layout/style';
// import Layout from 'ant-design-vue/es/layout';
import 'ant-design-vue/es/layout/style'; import { Layout } from 'ant-design-vue';
import Layout from 'ant-design-vue/es/layout';
import BaseMenu, { BaseMenuProps } from './BaseMenu'; import BaseMenu, { BaseMenuProps } from './BaseMenu';
import { WithFalse } from '../typings'; import { WithFalse } from '../typings';
import { SiderProps } from './typings'; import { SiderProps } from './typings';
import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue'; import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons-vue';
import { menus } from '../../examples/menus';
import { defaultProProviderProps, injectProConfigKey } from '../ProProvider'; import { defaultProProviderProps, injectProConfigKey } from '../ProProvider';
const { Sider } = Layout; const { Sider } = Layout;
export type PrivateSiderMenuProps = {
matchMenuKeys: string[];
};
export interface SiderMenuProps extends Pick<BaseMenuProps, Exclude<keyof BaseMenuProps, ['onCollapse']>> { export interface SiderMenuProps extends Pick<BaseMenuProps, Exclude<keyof BaseMenuProps, ['onCollapse']>> {
logo?: VNodeChild | JSX.Element; logo?: VNodeChild | JSX.Element;
siderWidth?: number; siderWidth?: number;
collapsedWidth?: number;
menuHeaderRender?: WithFalse< menuHeaderRender?: WithFalse<
(logo: VNodeChild | JSX.Element, title: VNodeChild | JSX.Element, props?: SiderMenuProps) => VNodeChild (logo: VNodeChild | JSX.Element, title: VNodeChild | JSX.Element, props?: SiderMenuProps) => VNodeChild
>; >;
...@@ -25,6 +29,7 @@ export interface SiderMenuProps extends Pick<BaseMenuProps, Exclude<keyof BaseMe ...@@ -25,6 +29,7 @@ export interface SiderMenuProps extends Pick<BaseMenuProps, Exclude<keyof BaseMe
collapsedButtonRender?: WithFalse<(collapsed?: boolean) => VNodeChild>; collapsedButtonRender?: WithFalse<(collapsed?: boolean) => VNodeChild>;
breakpoint?: SiderProps['breakpoint'] | false; breakpoint?: SiderProps['breakpoint'] | false;
onMenuHeaderClick?: (e: MouseEvent) => void; onMenuHeaderClick?: (e: MouseEvent) => void;
fixed?: boolean;
hide?: boolean; hide?: boolean;
onOpenChange?: (openKeys: WithFalse<string[]>) => void; onOpenChange?: (openKeys: WithFalse<string[]>) => void;
onSelect?: (selectedKeys: WithFalse<string[]>) => void; onSelect?: (selectedKeys: WithFalse<string[]>) => void;
...@@ -75,6 +80,7 @@ export const defaultRenderCollapsedButton = (collapsed?: boolean) => ...@@ -75,6 +80,7 @@ export const defaultRenderCollapsedButton = (collapsed?: boolean) =>
const SiderMenu = (props: SiderMenuProps, context: SetupContext) => { const SiderMenu = (props: SiderMenuProps, context: SetupContext) => {
const { const {
menuData,
collapsed, collapsed,
fixSiderbar, fixSiderbar,
menuFooterRender, menuFooterRender,
...@@ -92,32 +98,53 @@ const SiderMenu = (props: SiderMenuProps, context: SetupContext) => { ...@@ -92,32 +98,53 @@ const SiderMenu = (props: SiderMenuProps, context: SetupContext) => {
onOpenChange, onOpenChange,
onSelect, onSelect,
headerHeight, headerHeight,
collapsedWidth = 48,
} = props; } = props;
console.log('props', props) console.log('props', props)
const config = inject(injectProConfigKey, defaultProProviderProps) const { getPrefixCls } = inject(injectProConfigKey, defaultProProviderProps)
const baseClassName = config.getPrefixCls('sider'); const baseClassName = getPrefixCls('sider');
const isMix = computed(() => props.layout === 'mix');
const fixed = computed(() => props.fixed);
const runtimeTheme = computed(() => props.layout === 'mix' && 'light' || 'dark');
const runtimeSideWidth = computed(() => props.collapsed ? props.collapsedWidth : props.siderWidth);
const siderClassName = { const classNames = ref({
[baseClassName]: true, [baseClassName]: true,
[`${baseClassName}-fixed`]: fixSiderbar, [`${baseClassName}-${runtimeTheme.value}`]: true,
[`${baseClassName}-layout-${layout}`]: layout && !isMobile, [`${baseClassName}-${props.layout}`]: true,
[`${baseClassName}-light`]: theme === 'light', [`${baseClassName}-fixed`]: fixed,
}; });
const headerDom = defaultRenderLogoAndTitle(props); const headerDom = defaultRenderLogoAndTitle(props);
const extraDom = menuExtraRender && menuExtraRender(props); const extraDom = menuExtraRender && menuExtraRender(props);
return ( return (
<>
{ fixed.value && (<div style={{
width: `${runtimeSideWidth.value}px`,
overflow: 'hidden',
flex: `0 0 ${runtimeSideWidth.value}px`,
maxWidth: `${runtimeSideWidth.value}px`,
minWidth: `${runtimeSideWidth.value}px`,
}}
/>)}
<Sider <Sider
class={siderClassName} class={classNames.value}
width={siderWidth}
collapsed={collapsed} collapsed={collapsed}
collapsible={false}
collapsedWidth={collapsedWidth}
> >
<div class="ant-pro-sider-logo">
{headerDom}
</div>
<div style="flex: 1 1 0%; overflow: hidden auto;">
<BaseMenu <BaseMenu
{...props} menus={menuData}
menus={menus}
theme={props.theme} theme={props.theme}
mode={props.mode} mode="inline"
collapsed={props.collapsed} collapsed={props.collapsed}
openKeys={props.openKeys} openKeys={props.openKeys}
selectedKeys={props.selectedKeys} selectedKeys={props.selectedKeys}
...@@ -125,8 +152,18 @@ const SiderMenu = (props: SiderMenuProps, context: SetupContext) => { ...@@ -125,8 +152,18 @@ const SiderMenu = (props: SiderMenuProps, context: SetupContext) => {
width: '100%', width: '100%',
}} }}
class={`${baseClassName}-menu`} class={`${baseClassName}-menu`}
{...{
'onUpdate:openKeys': $event => {
onOpenChange($event);
},
'onUpdate:selectedKeys': $event => {
onSelect($event);
}
}}
/> />
</div>
</Sider> </Sider>
</>
); );
}; };
......
import { FunctionalComponent, toRefs } from "vue"
import 'ant-design-vue/es/drawer/style';
import Drawer from 'ant-design-vue/es/drawer';
import SiderMenu, { SiderMenuProps, PrivateSiderMenuProps } from './SiderMenu';
const SiderMenuWrapper: FunctionalComponent<SiderMenuProps & PrivateSiderMenuProps> =
(props, ctx) => {
return props.isMobile ? (
<Drawer>
<SiderMenu
{...props}
/>
</Drawer>
) : (
<SiderMenu
{...props}
/>
)
};
SiderMenuWrapper.inheritAttrs = false
export default SiderMenuWrapper;
...@@ -17,15 +17,6 @@ import { ...@@ -17,15 +17,6 @@ import {
export type ContextType<T> = any; export type ContextType<T> = any;
// VNode<RendererNode, RendererElement, {
// [key: string]: any;
// }>
/**
(props: any, ctx: SetupContext) => DefineComponent<{}, () => VNode<RendererNode, RendererElement, {
[key: string]: any;
}>>;
*/
export interface CreateContext<T> { export interface CreateContext<T> {
provider: DefineComponent<{}, () => VNode | VNode[]>; provider: DefineComponent<{}, () => VNode | VNode[]>;
state: UnwrapRef<T> | T; state: UnwrapRef<T> | T;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment