Unverified Commit 5443a32c authored by Sendya's avatar Sendya

fix: tests, typo, ts

parent 25185efd
...@@ -2,26 +2,21 @@ import { Button, Card, Space, Switch } from 'ant-design-vue'; ...@@ -2,26 +2,21 @@ import { Button, Card, Space, Switch } from 'ant-design-vue';
import 'ant-design-vue/dist/antd.less'; import 'ant-design-vue/dist/antd.less';
import { createApp, reactive } from 'vue'; import { createApp, reactive } from 'vue';
import FooterToolbar, { FooterToolbarProps } from '../src/FooterToolbar'; import FooterToolbar, { FooterToolbarProps } from '../src/FooterToolbar';
import { createRouteContext } from '../src/RouteContext'; import { useRouteContext } from '../src/RouteContext';
const DemoComponent = { const DemoComponent = {
setup() { setup() {
const routeContext = useRouteContext();
const state = reactive({ const state = reactive({
name: 'value', name: '',
hasFooterToolbar: 'unset' as string | boolean, toolbarProps: {
toolbarProps: {} as FooterToolbarProps, extra: undefined,
renderContent: undefined,
} as FooterToolbarProps,
}); });
const setToolbarProps = tProps => {
state.toolbarProps = { ...state.toolbarProps, ...tProps };
};
const [ routeContext, RouteContextProvider ] = createRouteContext({ console.log('routeContext', routeContext);
hasFooterToolbar: false,
setHasFooterToolbar: v => {
state.hasFooterToolbar = v;
routeContext.hasFooterToolbar = v;
},
});
return () => ( return () => (
<div class="components"> <div class="components">
...@@ -43,17 +38,14 @@ const DemoComponent = { ...@@ -43,17 +38,14 @@ const DemoComponent = {
checked={!!state.toolbarProps.extra} checked={!!state.toolbarProps.extra}
onClick={() => { onClick={() => {
state.name = new Date().getTime().toString(); state.name = new Date().getTime().toString();
const extra = !state.toolbarProps.extra ? ( state.toolbarProps.extra = !state.toolbarProps.extra ? (
<img <img
src="https://gw.alipayobjects.com/zos/antfincdn/PmY%24TNNDBI/logo.svg" src="https://gw.alipayobjects.com/zos/antfincdn/PmY%24TNNDBI/logo.svg"
alt="logo" alt="logo"
width="32" width="32"
height="32" height="32"
/> />
) : ( ) : undefined;
undefined
);
setToolbarProps({ extra });
}} }}
/> />
<Switch <Switch
...@@ -62,41 +54,25 @@ const DemoComponent = { ...@@ -62,41 +54,25 @@ const DemoComponent = {
checked={!!state.toolbarProps.renderContent} checked={!!state.toolbarProps.renderContent}
onClick={() => { onClick={() => {
state.name = new Date().getTime().toString(); state.name = new Date().getTime().toString();
const renderContent = !state.toolbarProps.renderContent state.toolbarProps.renderContent = !state.toolbarProps.renderContent
? () => 'home_toolbar' ? () => 'home_toolbar'
: undefined; : undefined;
setToolbarProps({ renderContent });
}} }}
/> />
</Space> </Space>
<div style={{ margin: '12px 0' }}> <div style={{ margin: '12px 0' }}>
state state
<pre> <pre>{JSON.stringify(state, null, 2)}</pre>
{JSON.stringify(
{
name: state.name,
toolbarProps: Object.fromEntries(
Object.entries(state.toolbarProps).map(([k, v]) => [k, typeof v]),
),
},
null,
2,
)}
</pre>
routeContext: routeContext:
<pre>{JSON.stringify(routeContext, null, 2)}</pre> <pre>{JSON.stringify(routeContext, null, 2)}</pre>
</div> </div>
</Card> </Card>
<div> <div>
<RouteContextProvider> {routeContext.hasFooterToolbar && (
{routeContext.hasFooterToolbar && ( <FooterToolbar {...state.toolbarProps}>
<FooterToolbar {...state.toolbarProps}> <Button type="primary">right</Button>
<Button type="primary"> </FooterToolbar>
right )}
</Button>
</FooterToolbar>
)}
</RouteContextProvider>
</div> </div>
</div> </div>
); );
......
import { createApp, defineComponent, reactive } from 'vue'; import { createApp, defineComponent } from 'vue';
import { Card } from 'ant-design-vue'; import { Card } from 'ant-design-vue';
import { ContentWidth } from '../src/typings';
import GlobalFooter from '../src/GlobalFooter'; import GlobalFooter from '../src/GlobalFooter';
import 'ant-design-vue/dist/antd.less'; import 'ant-design-vue/dist/antd.less';
const GlobalFooterDemo = defineComponent({ const GlobalFooterDemo = defineComponent({
setup () { setup() {
const state = reactive({
contentWidth: 'Fixed' as ContentWidth
})
return () => ( return () => (
<div class="components" style={{ background: 'rgb(240, 240, 240)', paddingBottom: '20px' }}> <div class="components" style={{ background: 'rgb(240, 240, 240)', paddingBottom: '20px' }}>
<Card style={{ marginBottom: '24px', background: 'rgb(244,244,244)' }}> <Card style={{ marginBottom: '24px', background: 'rgb(244,244,244)' }}>
...@@ -35,13 +29,17 @@ const GlobalFooterDemo = defineComponent({ ...@@ -35,13 +29,17 @@ const GlobalFooterDemo = defineComponent({
title: '@Sendya', title: '@Sendya',
href: 'https://www.github.com/sendya/', href: 'https://www.github.com/sendya/',
blankTarget: true, blankTarget: true,
} },
]} ]}
copyright={(<a href="https://github.com/vueComponent" target="_blank">vueComponent</a>)} copyright={
<a href="https://github.com/vueComponent" target="_blank">
vueComponent
</a>
}
/> />
</div> </div>
); );
} },
}); });
createApp(GlobalFooterDemo).mount('#__vue-content>div'); createApp(GlobalFooterDemo).mount('#__vue-content>div');
import { createApp, defineComponent, reactive } from 'vue'; import { createApp, defineComponent, reactive } from 'vue';
import { Card, Space, Button } from 'ant-design-vue'; import { Card, Space, Button } from 'ant-design-vue';
import { ContentWidth } from '../src/typings'; import { ContentWidth } from '../src/typings';
import GridContent from '../src/GridContent'; import GridContent, { GridContentProps } from '../src/GridContent';
import 'ant-design-vue/dist/antd.less'; import 'ant-design-vue/dist/antd.less';
const GridContentDemo = defineComponent({ const GridContentDemo = defineComponent({
setup () { setup() {
const state = reactive({ const state = reactive<GridContentProps>({
contentWidth: 'Fixed' as ContentWidth contentWidth: 'Fixed',
}) });
return () => ( return () => (
<div class="components" style={{ background: 'rgb(240, 240, 240)', paddingBottom: '20px' }}> <div class="components" style={{ background: 'rgb(240, 240, 240)', paddingBottom: '20px' }}>
...@@ -26,7 +26,10 @@ const GridContentDemo = defineComponent({ ...@@ -26,7 +26,10 @@ const GridContentDemo = defineComponent({
</Button> </Button>
</Space> </Space>
</Card> </Card>
<GridContent contentWidth={state.contentWidth} style={{ background: 'rgb(220, 220, 220)', padding: '22px' }}> <GridContent
contentWidth={state.contentWidth}
style={{ background: 'rgb(220, 220, 220)', padding: '22px' }}
>
Content Content
<br /> <br />
... ...
...@@ -37,11 +40,12 @@ const GridContentDemo = defineComponent({ ...@@ -37,11 +40,12 @@ const GridContentDemo = defineComponent({
<br /> <br />
... ...
<br /> <br />
...<br /> ...
<br />
</GridContent> </GridContent>
</div> </div>
); );
} },
}); });
createApp(GridContentDemo).mount('#__vue-content>div'); createApp(GridContentDemo).mount('#__vue-content>div');
...@@ -2,20 +2,12 @@ import { createApp, defineComponent, reactive } from 'vue'; ...@@ -2,20 +2,12 @@ import { createApp, defineComponent, reactive } from 'vue';
import 'ant-design-vue/dist/antd.less'; import 'ant-design-vue/dist/antd.less';
import { Button, Descriptions, Space, Statistic, Tag, message } from 'ant-design-vue'; import { Button, Descriptions, Space, Statistic, Tag, message } from 'ant-design-vue';
import { PageContainer } from '../src/PageContainer'; import { PageContainer } from '../src/PageContainer';
import { default as ProProvider } from '../src/ProProvider';
import { createRouteContext } from '../src/RouteContext';
import { LikeOutlined } from '@ant-design/icons-vue'; import { LikeOutlined } from '@ant-design/icons-vue';
import './index.less'; import './index.less';
const App = defineComponent({ const App = defineComponent({
name: 'App', name: 'App',
setup: function() { setup: function () {
const [ RouteContextProvider ] = createRouteContext({
hasSideMenu: true,
collapsed: true,
isMobile: false,
menuData: [],
});
const routes = [ const routes = [
{ {
path: 'index', path: 'index',
...@@ -37,62 +29,60 @@ const App = defineComponent({ ...@@ -37,62 +29,60 @@ const App = defineComponent({
return () => ( return () => (
<div class="demo-page-box" style="padding: 20px; background: #ccc;"> <div class="demo-page-box" style="padding: 20px; background: #ccc;">
<ProProvider prefixCls={'ant-pro'} contentWidth={'Fixed'}> <div style="background: #fff; height: 500px;">
<RouteContextProvider value={{}}> <PageContainer
<div style="background: #fff; height: 500px;"> title="Title"
<PageContainer subTitle="This is a subtitle"
title="Title" breadcrumb={{ routes }}
subTitle="This is a subtitle" onBack={() => message.info('@back click')}
breadcrumb={{ routes }} tags={['Tag 1', 'Tag 2'].map(tag => (
onBack={() => message.info('@back click')} <Tag color="blue">{tag}</Tag>
tags={['Tag 1', 'Tag 2'].map(tag => (<Tag color="blue">{tag}</Tag>))} ))}
extra={[ extra={[
<Button key="3">操作</Button>, <Button key="3">操作</Button>,
<Button key="2">操作</Button>, <Button key="2">操作</Button>,
<Button key="1" type="primary"> <Button key="1" type="primary">
主操作 主操作
</Button>, </Button>,
]} ]}
content={ content={
<Descriptions size="small" column={{ md: 2 }}> <Descriptions size="small" column={{ md: 2 }}>
<Descriptions.Item label="创建人">张三</Descriptions.Item> <Descriptions.Item label="创建人">张三</Descriptions.Item>
<Descriptions.Item label="联系方式"> <Descriptions.Item label="联系方式">
<a>421421</a> <a>421421</a>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="创建时间">2017-01-10</Descriptions.Item> <Descriptions.Item label="创建时间">2017-01-10</Descriptions.Item>
<Descriptions.Item label="更新时间">2017-10-10</Descriptions.Item> <Descriptions.Item label="更新时间">2017-10-10</Descriptions.Item>
<Descriptions.Item label="备注">中国浙江省杭州市西湖区古翠路</Descriptions.Item> <Descriptions.Item label="备注">中国浙江省杭州市西湖区古翠路</Descriptions.Item>
</Descriptions> </Descriptions>
} }
extraContent={ extraContent={
<Space size={24}> <Space size={24}>
<Statistic title="Feedback" value={1128} prefix={<LikeOutlined />} /> <Statistic title="Feedback" value={1128} prefix={<LikeOutlined />} />
<Statistic title="Unmerged" value={93} suffix="/ 100" /> <Statistic title="Unmerged" value={93} suffix="/ 100" />
</Space> </Space>
} }
tabList={[ tabList={[
{ key: '1', tab: 'Details' }, { key: '1', tab: 'Details' },
{ key: '2', tab: 'Rule' }, { key: '2', tab: 'Rule' },
]} ]}
tabProps={{ tabProps={{
type: 'card', type: 'card',
}} }}
tabActiveKey={state.tabActiveKey} tabActiveKey={state.tabActiveKey}
onTabChange={(key: string) => { onTabChange={(key: string) => {
state.tabActiveKey = key; state.tabActiveKey = key;
}} }}
footer={[ footer={[
<Button key="3">重置</Button>, <Button key="3">重置</Button>,
<Button key="2" type="primary"> <Button key="2" type="primary">
提交 提交
</Button>, </Button>,
]} ]}
> >
<div>Page Content</div> <div>Page Content</div>
</PageContainer> </PageContainer>
</div> </div>
</RouteContextProvider>
</ProProvider>
</div> </div>
); );
}, },
......
import { createApp, defineComponent, inject, reactive, toRefs } from 'vue';
import { Card, Space, Button } from 'ant-design-vue';
import { ContentWidth } from '../src/typings';
import { warning } from '../src/utils';
import { default as ProProvider, useProProvider } from '../src/ProProvider';
import 'ant-design-vue/dist/antd.less';
import GridContent from '../src/GridContent';
const trans = {
'render.test.i18n.hello': 'Hello My Friends',
};
const trans2 = {
'render.test.i18n.hello': 'Hello My Dear Friends',
};
const i18nRender = (t: string): string => {
return trans[t];
};
const i18nRender2 = (t: string): string => {
return trans2[t];
};
const ProProviderDemo = defineComponent({
setup() {
const state = reactive({
i18nRender,
contentWidth: 'Fixed' as ContentWidth,
});
return () => (
<>
<ProProvider i18n={state.i18nRender} contentWidth={state.contentWidth}>
<h2># BasicLayout</h2>
<div
class="components"
style={{ background: 'rgb(240, 240, 240)', paddingBottom: '20px' }}
>
<Card style={{ marginBottom: '24px', background: 'rgb(244,244,244)' }}>
<Space size="middle">
Change Current Config:
<Button
type="primary"
onClick={() => {
state.i18nRender = (Math.random() > 0.5 && i18nRender2) || i18nRender;
state.contentWidth = state.contentWidth === 'Fixed' ? 'Fluid' : 'Fixed';
}}
>
{state.contentWidth}
</Button>
</Space>
<div class="env">state.contentWidth: {JSON.stringify(state.contentWidth)}</div>
</Card>
<TestChildComponent style={{ background: 'rgb(220, 220, 220)', padding: '22px' }} />
</div>
</ProProvider>
</>
);
},
});
const TestChildComponent = defineComponent({
setup() {
const config = useProProvider();
const prefixCls = config.getPrefixCls('child-component');
return () => {
const { i18n, contentWidth } = config;
return (
<GridContent contentWidth={contentWidth}>
<div class={prefixCls}>
<p>TestChildComponent:</p>
<div>contentWidth: {contentWidth} , <a>Fixed: 1200px; Fluid: auto width;</a></div>
<p>{i18n('render.test.i18n.hello')}</p>
</div>
</GridContent>
);
};
},
});
const app = createApp(ProProviderDemo);
app.mount('#__vue-content>div');
import { createApp, defineComponent, ref, reactive, toRaw, onMounted } from 'vue';
import { Card, Space, Button } from 'ant-design-vue';
import { createRouteContext, useRouteContext, RouteContextProps } from '../src/RouteContext';
import 'ant-design-vue/dist/antd.less';
const DemoComponent = {
setup() {
const state = reactive({
name: 'value',
});
const context = reactive<RouteContextProps>({
menuData: [],
selectedKeys: [],
openKeys: [],
collapsed: false,
});
const [ RouteContextProvider ] = createRouteContext();
return () => (
<div class="components">
<h2># Template</h2>
<Card style={{ marginBottom: '24px', background: 'rgb(244,244,244)' }}>
<Space size="middle">
<Button
type="primary"
onClick={() => {
state.name = new Date().getTime().toString()
context.collapsed = !context.collapsed
context.menuData = [
{
path: `/dashboard/${state.name}`,
name: `${state.name}`,
meta: { title: `custom title - ${state.name}` },
}
]
}}
>
Change Value
</Button>
</Space>
<div style={{ margin: '12px 0' }}>
<p>state.name: { JSON.stringify(state.name) }</p>
routeContext:
<pre>{ JSON.stringify(context, null, 4) }</pre>
</div>
</Card>
<div class="demo" style="background: rgb(244,244,244);">
<RouteContextProvider value={context}>
<TestChildComponent />
</RouteContextProvider>
</div>
</div>
);
},
};
const TestChildComponent = defineComponent({
setup () {
const routeContext = useRouteContext();
console.log('TestChildComponent.routeContext', routeContext);
return () => {
const { menuData, collapsed } = routeContext
return (
<div class="test-child-component">
menuData:
<pre>
{JSON.stringify(menuData, null, 4)}
</pre>
<p>
collapsed: {collapsed.toString()}
</p>
</div>
)
}
}
});
const app = createApp(DemoComponent);
app.mount('#__vue-content>div');
.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 { Layout, Input, Space, Switch, message } from 'ant-design-vue';
import { menus } from './menus';
import { RouterLink } from './mock-router';
import { default as SiderMenuWrapper } from '../src/SiderMenu';
import { createRouteContext, RouteContextProps } from '../src/RouteContext';
import * as Icon from '@ant-design/icons-vue';
import { MenuTheme } from '../src/typings';
const DemoComponent = {
setup() {
const state = reactive<RouteContextProps>({
collapsed: false,
openKeys: ['/dashboard', '/form'],
setOpenKeys: (keys: string[]) => (state.openKeys = keys),
selectedKeys: ['/welcome'],
setSelectedKeys: (keys: string[]) => (state.selectedKeys = keys),
isMobile: false,
fixSiderbar: false,
fixedHeader: false,
menuData: [...menus],
sideWidth: 208,
hasSideMenu: true,
hasHeader: true,
hasFooterToolbar: false,
setHasFooterToolbar: (has: boolean) => (state.hasFooterToolbar = has),
})
const [ RouteContextProvider ] = createRouteContext();
const myState = reactive({
theme: 'light',
});
const handleCollapse = (collapsed: boolean) => {
state.collapsed = collapsed;
}
return () => (
<div class="components">
<h2># SideMenu</h2>
<div style="margin: 16px;">
<Space>
<Switch checked-children="dark" un-checked-children="light" checked={state.theme === 'dark'} onChange={() => { (myState.theme = myState.theme === 'dark' ? 'light' : 'dark')}} />
</Space>
</div>
<div class="demo" style="background: rgb(244,244,244); min-height: 400px;">
<div class="container side-menu-demo">
<RouteContextProvider value={state}>
<Layout class="ant-pro-basicLayout">
<SiderMenuWrapper
title={'Pro Layout'}
layout={'side'}
navTheme={myState.theme as MenuTheme}
isMobile={false}
collapsed={state.collapsed}
// openKeys={menuState.openKeys}
// selectedKeys={menuState.selectedKeys}
onCollapse={handleCollapse}
matchMenuKeys={[]}
contentWidth={'Fixed'}
primaryColor={'#1890ff'}
siderWidth={208}
menuExtraRender={(props) => !props.collapsed ? (
<div>
<Input.Search placeholder="Search.." style={{ width: '100%' }} onSearch={(value: string) => {
message.info(`Search click: ${value}`)
}} />
</div>
) : null}
// menuFooterRender={(props) => props.collapsed ? undefined : (
// <div style="color: #fff; padding: 8px 16px; overflow: hidden;">
// <span>自定义页脚</span>
// </div>
// )}
/>
<Layout>
<Layout.Header style="background: #fff; padding: 0; height: 48px; line-height: 48px;"></Layout.Header>
<Layout.Content
style={{
margin: '24px 16px',
padding: '24px',
background: '#fff',
minHeight: '280px',
}}
>
<div>Context</div>
</Layout.Content>
</Layout>
</Layout>
</RouteContextProvider>
</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.use(RouterLink).mount('#__vue-content>div');
import { createApp, reactive } from 'vue'; import { createApp, reactive } from 'vue';
import { default as ProLayout, createRouteContext, RouteContextProps } from '../src/'; import { default as ProLayout, RouteContextProps } from '../src/';
import { RouterLink } from './mock-router'; import { RouterLink } from './mock-router';
import { menus } from './menus'; import { menus } from './menus';
...@@ -7,46 +7,34 @@ import registerIcons from './_util/icons'; ...@@ -7,46 +7,34 @@ import registerIcons from './_util/icons';
const SimpleDemo = { const SimpleDemo = {
setup() { setup() {
const [RouteContextProvider] = createRouteContext();
const appState = reactive<RouteContextProps>({ const appState = reactive<RouteContextProps>({
collapsed: false,
selectedKeys: [], selectedKeys: [],
openKeys: [], openKeys: [],
collapsed: true,
menuData: menus, menuData: menus,
}); });
return () => ( return () => (
<RouteContextProvider value={appState}> <ProLayout
<ProLayout title="Pro Tests"
title="Pro Tests" logo="https://alicdn.antdv.com/v2/assets/logo.1ef800a8.svg"
logo="https://alicdn.antdv.com/v2/assets/logo.1ef800a8.svg" onSelect={(selectedKeys: string[] | false) => {
layout="side" selectedKeys && (appState.selectedKeys = selectedKeys);
navTheme="light" }}
contentWidth="Fluid" onOpenKeys={(openKeys: string[] | false) => {
contentStyle={{ minHeight: '300px' }} console.log('onOpenKeys', openKeys);
collapsed={appState.collapsed} openKeys && (appState.openKeys = openKeys);
onCollapse={collapsed => { }}
appState.collapsed = collapsed; footerRender={() => <div>custom-footer</div>}
}} v-slots={{
onSelect={(selectedKeys: string[] | false) => { rightContentRender: () => (
selectedKeys && (appState.selectedKeys = selectedKeys); <div class="custom-header-right-content">
}} <span>custom-right-content</span>
onOpenKeys={(openKeys: string[] | false) => { </div>
console.log('onOpenKeys', openKeys); ),
openKeys && (appState.openKeys = openKeys); }}
}} >
footerRender={() => <div>custom-footer</div>} <div>content</div>
v-slots={{ </ProLayout>
rightContentRender: props => (
<div class="custom-header-right-content">
<span>custom-right-content</span>
</div>
),
}}
>
<div>content</div>
</ProLayout>
</RouteContextProvider>
); );
}, },
}; };
......
...@@ -2,28 +2,23 @@ import { computed, CSSProperties, reactive, unref, provide, defineComponent, toR ...@@ -2,28 +2,23 @@ import { computed, CSSProperties, reactive, unref, provide, defineComponent, toR
import 'ant-design-vue/es/layout/style'; import 'ant-design-vue/es/layout/style';
import Layout from 'ant-design-vue/es/layout'; import Layout from 'ant-design-vue/es/layout';
import { withInstall } from 'ant-design-vue/es/_util/type'; import { withInstall } from 'ant-design-vue/es/_util/type';
import { RouteContextProps } from './RouteContext'; import { getPrefixCls, RouteContextProps } from './RouteContext';
import { default as SiderMenuWrapper, SiderMenuWrapperProps } from './SiderMenu'; import { default as SiderMenuWrapper, SiderMenuWrapperProps } from './SiderMenu';
import { WrapContent } from './WrapContent'; import { WrapContent } from './WrapContent';
import { default as Header, HeaderViewProps } from './Header'; import { default as Header, HeaderViewProps } from './Header';
import { VNodeType, CustomRender, WithFalse } from './typings'; import { CustomRender, WithFalse } from './typings';
import { getCustomRender, getMenuFirstChildren, PropRenderType, PropTypes } from './utils'; import { getCustomRender, PropRenderType, PropTypes } from './utils';
import omit from 'omit.js'; import omit from 'omit.js';
import useMediaQuery from './hooks/useMediaQuery'; import useMediaQuery from './hooks/useMediaQuery';
import './BasicLayout.less'; import './BasicLayout.less';
export const defaultPrefixCls = 'ant-pro';
const getPrefixCls = (suffixCls?: string, customizePrefixCls?: string) => {
if (customizePrefixCls) return customizePrefixCls;
return suffixCls ? `${defaultPrefixCls}-${suffixCls}` : defaultPrefixCls;
};
export type BasicLayoutProps = SiderMenuWrapperProps & export type BasicLayoutProps = SiderMenuWrapperProps &
HeaderViewProps & { HeaderViewProps & {
pure?: boolean; pure?: boolean;
/** /**
*@name logo url *@name logo url
*/ */
logo?: VNodeType; logo?: CustomRender;
loading?: boolean; loading?: boolean;
...@@ -33,9 +28,9 @@ export type BasicLayoutProps = SiderMenuWrapperProps & ...@@ -33,9 +28,9 @@ export type BasicLayoutProps = SiderMenuWrapperProps &
onCollapse?: (collapsed: boolean) => void; onCollapse?: (collapsed: boolean) => void;
footerRender?: WithFalse<(props: any /* FooterProps */) => VNodeType>; footerRender?: WithFalse<(props: any /* FooterProps */) => CustomRender>;
headerRender?: WithFalse<(props: any /* HeaderProps */) => VNodeType>; headerRender?: WithFalse<(props: any /* HeaderProps */) => CustomRender>;
colSize?: string; colSize?: string;
/** /**
...@@ -109,7 +104,7 @@ const ProLayout = defineComponent({ ...@@ -109,7 +104,7 @@ const ProLayout = defineComponent({
rightContentRender: WithFalse<CustomRender>; rightContentRender: WithFalse<CustomRender>;
}, },
matchMenuKeys?: string[], matchMenuKeys?: string[],
): VNodeType | null => { ): CustomRender | null => {
if (p.headerRender === false || p.pure) { if (p.headerRender === false || p.pure) {
return null; return null;
} }
...@@ -161,7 +156,6 @@ const ProLayout = defineComponent({ ...@@ -161,7 +156,6 @@ const ProLayout = defineComponent({
const restProps = computed(() => omit(props, ['onCollapse', 'onOpenKeys', 'onSelect'])); const restProps = computed(() => omit(props, ['onCollapse', 'onOpenKeys', 'onSelect']));
provide('route-context', routeContext); provide('route-context', routeContext);
return () => ( return () => (
<> <>
{pure.value ? ( {pure.value ? (
......
import { computed, defineComponent, onBeforeUnmount, onMounted, PropType, VNodeChild } from 'vue';
import { RouteContextProps, useRouteContext } from '../RouteContext';
import { getMenuFirstChildren } from '../utils';
import './index.less'; import './index.less';
import { computed, defineComponent, onBeforeUnmount, onMounted, PropType } from 'vue';
import { RouteContextProps, useRouteContext } from '../RouteContext';
import { getMenuFirstChildren, PropTypes } from '../utils';
import type { CustomRender } from '../typings';
export interface FooterToolbarProps { export interface FooterToolbarProps {
extra?: VNodeChild | JSX.Element; extra?: CustomRender | JSX.Element;
renderContent?: ( renderContent?: (
props: FooterToolbarProps & RouteContextProps & { leftWidth?: string }, props: FooterToolbarProps & RouteContextProps & { leftWidth?: string },
dom: JSX.Element, dom: CustomRender | JSX.Element,
) => VNodeChild | JSX.Element; ) => CustomRender | JSX.Element;
getContainer?: (triggerNode: HTMLElement) => HTMLElement | null; getContainer?: (triggerNode: HTMLElement) => HTMLElement | null;
prefixCls?: string; prefixCls?: string;
} }
const FooterToolbarProps = { const footerToolbarProps = {
extra: { type: Object as PropType<VNodeChild> }, extra: {
type: Object as PropType<FooterToolbarProps['extra']>,
},
renderContent: { renderContent: {
type: Function as PropType<FooterToolbarProps['renderContent']>, type: Function as PropType<FooterToolbarProps['renderContent']>,
}, },
...@@ -26,7 +29,7 @@ const FooterToolbarProps = { ...@@ -26,7 +29,7 @@ const FooterToolbarProps = {
const FooterToolbar = defineComponent({ const FooterToolbar = defineComponent({
name: 'FooterToolbar', name: 'FooterToolbar',
props: FooterToolbarProps, props: footerToolbarProps,
setup(props, ctx) { setup(props, ctx) {
const { slots } = ctx; const { slots } = ctx;
const routeContext = useRouteContext(); const routeContext = useRouteContext();
......
import { computed, CSSProperties, FunctionalComponent } from 'vue'; import { computed, CSSProperties, FunctionalComponent } from 'vue';
import { PureSettings } from '../defaultSettings'; import { PureSettings } from '../defaultSettings';
import { VNodeType, MenuDataItem, WithFalse } from '../typings'; import { CustomRender, MenuDataItem, WithFalse } from '../typings';
import { import {
SiderMenuProps, SiderMenuProps,
PrivateSiderMenuProps, PrivateSiderMenuProps,
...@@ -12,15 +12,14 @@ import { TopNavHeader } from '../TopNavHeader'; ...@@ -12,15 +12,14 @@ import { TopNavHeader } from '../TopNavHeader';
import { clearMenuItem } from '../utils'; import { clearMenuItem } from '../utils';
import type { HeaderViewProps } from '../Header'; import type { HeaderViewProps } from '../Header';
import './index.less'; import './index.less';
import { useProProvider } from '../ProProvider'; import { useRouteContext } from '../RouteContext';
export interface GlobalHeaderProps extends Partial<PureSettings> { export interface GlobalHeaderProps extends Partial<PureSettings> {
collapsed?: boolean; collapsed?: boolean;
onCollapse?: (collapsed: boolean) => void; onCollapse?: (collapsed: boolean) => void;
isMobile?: boolean; isMobile?: boolean;
logo?: VNodeType; logo?: CustomRender;
menuRender?: WithFalse<(props: HeaderViewProps, defaultDom: VNodeType) => VNodeType>; menuRender?: WithFalse<(props: HeaderViewProps, defaultDom: CustomRender) => CustomRender>;
rightContentRender?: WithFalse<(props: HeaderViewProps) => VNodeType>; rightContentRender?: WithFalse<(props: HeaderViewProps) => CustomRender>;
className?: string; className?: string;
prefixCls?: string; prefixCls?: string;
menuData?: MenuDataItem[]; menuData?: MenuDataItem[];
...@@ -33,7 +32,10 @@ export interface GlobalHeaderProps extends Partial<PureSettings> { ...@@ -33,7 +32,10 @@ export interface GlobalHeaderProps extends Partial<PureSettings> {
onSelect?: (selectedKeys: WithFalse<string[]>) => void; onSelect?: (selectedKeys: WithFalse<string[]>) => void;
} }
const renderLogo = (menuHeaderRender: SiderMenuProps['menuHeaderRender'], logoDom: VNodeType) => { const renderLogo = (
menuHeaderRender: SiderMenuProps['menuHeaderRender'],
logoDom: CustomRender,
) => {
if (menuHeaderRender === false) { if (menuHeaderRender === false) {
return null; return null;
} }
...@@ -63,7 +65,7 @@ export const GlobalHeader: FunctionalComponent<GlobalHeaderProps & PrivateSiderM ...@@ -63,7 +65,7 @@ export const GlobalHeader: FunctionalComponent<GlobalHeaderProps & PrivateSiderM
menuData, menuData,
prefixCls: customPrefixCls, prefixCls: customPrefixCls,
} = props; } = props;
const { getPrefixCls } = useProProvider(); const { getPrefixCls } = useRouteContext();
const prefixCls = customPrefixCls || getPrefixCls(); const prefixCls = customPrefixCls || getPrefixCls();
const baseClassName = computed(() => `${prefixCls}-global-header`); const baseClassName = computed(() => `${prefixCls}-global-header`);
const className = computed(() => { const className = computed(() => {
......
import './GridContent.less';
import { FunctionalComponent, CSSProperties } from 'vue'; import { FunctionalComponent, CSSProperties } from 'vue';
import { useProProvider } from '../ProProvider';
import { PureSettings } from '../defaultSettings'; import { PureSettings } from '../defaultSettings';
import './GridContent.less'; import { useRouteContext } from '../RouteContext';
export interface GridContentProps { export interface GridContentProps {
contentWidth?: PureSettings['contentWidth']; contentWidth?: PureSettings['contentWidth'];
...@@ -10,7 +11,7 @@ export interface GridContentProps { ...@@ -10,7 +11,7 @@ export interface GridContentProps {
} }
const GridContent: FunctionalComponent<GridContentProps> = (props, { slots }) => { const GridContent: FunctionalComponent<GridContentProps> = (props, { slots }) => {
const { contentWidth, getPrefixCls } = useProProvider(); const { contentWidth, getPrefixCls } = useRouteContext();
const customPrefixCls = props.prefixCls || getPrefixCls(); const customPrefixCls = props.prefixCls || getPrefixCls();
const customContentWidth = props.contentWidth || contentWidth; const customContentWidth = props.contentWidth || contentWidth;
return ( return (
......
...@@ -5,7 +5,7 @@ import Layout from 'ant-design-vue/es/layout'; ...@@ -5,7 +5,7 @@ import Layout from 'ant-design-vue/es/layout';
import { GlobalHeader, GlobalHeaderProps } from './GlobalHeader'; import { GlobalHeader, GlobalHeaderProps } from './GlobalHeader';
import { TopNavHeader } from './TopNavHeader'; import { TopNavHeader } from './TopNavHeader';
import { useRouteContext } from './RouteContext'; import { useRouteContext } from './RouteContext';
import { VNodeType, WithFalse } from './typings'; import { CustomRender, WithFalse } from './typings';
import { clearMenuItem } from './utils'; import { clearMenuItem } from './utils';
import './Header.less'; import './Header.less';
...@@ -18,11 +18,11 @@ interface HeaderViewState { ...@@ -18,11 +18,11 @@ interface HeaderViewState {
export type HeaderViewProps = GlobalHeaderProps & { export type HeaderViewProps = GlobalHeaderProps & {
isMobile?: boolean; isMobile?: boolean;
collapsed?: boolean; collapsed?: boolean;
logo?: VNodeType; logo?: CustomRender;
headerRender?: WithFalse<(props: HeaderViewProps, defaultDom: VNodeType) => VNodeType>; headerRender?: WithFalse<(props: HeaderViewProps, defaultDom: CustomRender) => CustomRender>;
headerTitleRender?: WithFalse<(props: HeaderViewProps, defaultDom: VNodeType) => VNodeType>; headerTitleRender?: WithFalse<(props: HeaderViewProps, defaultDom: CustomRender) => CustomRender>;
headerContentRender?: WithFalse<(props: HeaderViewProps) => VNodeType>; headerContentRender?: WithFalse<(props: HeaderViewProps) => CustomRender>;
siderWidth?: number; siderWidth?: number;
hasSiderMenu?: boolean; hasSiderMenu?: boolean;
}; };
...@@ -59,7 +59,7 @@ export const HeaderView = defineComponent({ ...@@ -59,7 +59,7 @@ export const HeaderView = defineComponent({
inheritAttrs: false, inheritAttrs: false,
name: 'HeaderView', name: 'HeaderView',
props: headerProps, props: headerProps,
setup(props: HeaderViewProps) { setup(props /*Required<HeaderViewProps> */) {
const { const {
prefixCls, prefixCls,
isMobile, isMobile,
......
...@@ -6,7 +6,6 @@ import { PageHeaderProps } from './interfaces/PageHeader'; ...@@ -6,7 +6,6 @@ import { PageHeaderProps } from './interfaces/PageHeader';
import { AffixProps } from './interfaces/Affix'; import { AffixProps } from './interfaces/Affix';
/* replace antd ts define end */ /* replace antd ts define end */
import { useRouteContext, RouteContextProps } from '../RouteContext'; import { useRouteContext, RouteContextProps } from '../RouteContext';
import { useProProvider } from '../ProProvider';
import 'ant-design-vue/es/affix/style'; import 'ant-design-vue/es/affix/style';
import Affix from 'ant-design-vue/es/affix'; import Affix from 'ant-design-vue/es/affix';
import 'ant-design-vue/es/page-header/style'; import 'ant-design-vue/es/page-header/style';
...@@ -167,9 +166,8 @@ const defaultPageHeaderRender = ( ...@@ -167,9 +166,8 @@ const defaultPageHeaderRender = (
export const PageContainer: FunctionalComponent<PageContainerProps> = (props, { slots }) => { export const PageContainer: FunctionalComponent<PageContainerProps> = (props, { slots }) => {
const { loading, footer, affixProps, ghost, fixedHeader } = props; // toRefs(props); const { loading, footer, affixProps, ghost, fixedHeader } = props; // toRefs(props);
const { getPrefixCls } = useProProvider();
const value = useRouteContext(); const value = useRouteContext();
const { getPrefixCls } = value;
const prefixCls = props.prefixCls || getPrefixCls(); const prefixCls = props.prefixCls || getPrefixCls();
const prefixedClassName = `${prefixCls}-page-container`; // computed(() => `${prefixCls}-page-container`); const prefixedClassName = `${prefixCls}-page-container`; // computed(() => `${prefixCls}-page-container`);
......
import {
App,
defineComponent,
InjectionKey,
PropType,
provide,
inject,
reactive,
readonly,
SetupContext,
toRefs,
} from 'vue';
import { ContentWidth } from '../typings';
export const defaultPrefixCls = 'ant-pro';
export interface ProProviderData {
getPrefixCls: (suffixCls?: string, customizePrefixCls?: string) => string;
i18n: (t: string) => string;
contentWidth: ContentWidth;
}
export const defaultProProviderProps: ProProviderData = {
getPrefixCls: (suffixCls?: string, customizePrefixCls?: string) => {
if (customizePrefixCls) return customizePrefixCls;
return suffixCls ? `${defaultPrefixCls}-${suffixCls}` : defaultPrefixCls;
},
i18n: (t: string): string => t,
contentWidth: 'Fluid',
};
export const injectProConfigKey: InjectionKey<ProProviderData> = Symbol();
const ProProvider = defineComponent({
name: 'ProProvider',
props: {
prefixCls: {
type: String as PropType<string>,
default: 'ant-pro',
},
contentWidth: {
type: String as PropType<ContentWidth>,
default: 'Fluid',
},
i18n: {
type: Function as PropType<(t: string) => string>,
default: (t: string): string => t,
},
},
setup(props, { slots }: SetupContext) {
const { prefixCls, i18n, contentWidth } = toRefs(props);
const getPrefixCls = (suffixCls?: string, customizePrefixCls?: string): string => {
if (customizePrefixCls) return customizePrefixCls;
return suffixCls ? `${prefixCls.value}-${suffixCls}` : prefixCls.value;
};
const context = reactive({
i18n,
contentWidth,
getPrefixCls,
});
provide(injectProConfigKey, readonly(context));
return () => slots.default?.();
},
});
ProProvider.install = function (app: App) {
app.component(ProProvider.name, ProProvider);
};
export const useProProvider = (): ProProviderData => {
return inject(injectProConfigKey, defaultProProviderProps);
};
export default ProProvider;
import { InjectionKey, VNodeChild } from 'vue'; import { InjectionKey, reactive, VNodeChild } from 'vue';
import { createContext, useContext } from './hooks/context'; import { createContext, useContext } from './hooks/context';
import { MenuDataItem } from './typings'; import { MenuDataItem } from './typings';
import { PureSettings } from './defaultSettings'; import { PureSettings } from './defaultSettings';
...@@ -34,8 +34,8 @@ export interface MenuState { ...@@ -34,8 +34,8 @@ export interface MenuState {
} }
export interface RouteContextProps extends Partial<PureSettings>, MenuState { export interface RouteContextProps extends Partial<PureSettings>, MenuState {
getPrefixCls: (suffixCls?: string, customizePrefixCls?: string) => string; getPrefixCls?: (suffixCls?: string, customizePrefixCls?: string) => string;
i18n: (t: string) => string; i18n?: (t: string) => string;
breadcrumb?: BreadcrumbListReturn; breadcrumb?: BreadcrumbListReturn;
menuData: MenuDataItem[]; menuData: MenuDataItem[];
...@@ -52,13 +52,32 @@ export interface RouteContextProps extends Partial<PureSettings>, MenuState { ...@@ -52,13 +52,32 @@ export interface RouteContextProps extends Partial<PureSettings>, MenuState {
[key: string]: any; [key: string]: any;
} }
export const defaultPrefixCls = 'ant-pro';
export const getPrefixCls = (suffixCls?: string, customizePrefixCls?: string) => {
if (customizePrefixCls) return customizePrefixCls;
return suffixCls ? `${defaultPrefixCls}-${suffixCls}` : defaultPrefixCls;
};
// set default context
const defaultRouteContext = reactive({
getPrefixCls,
i18n: (t: string) => t,
contentWidth: 'Fluid',
hasFooterToolbar: false,
setHasFooterToolbar: (bool: boolean) => (defaultRouteContext.hasFooterToolbar = bool),
});
const routeContextInjectKey: InjectionKey<RouteContextProps> = Symbol('route-context'); const routeContextInjectKey: InjectionKey<RouteContextProps> = Symbol('route-context');
export const createRouteContext = () => export const createRouteContext = () =>
createContext<RouteContextProps>(routeContextInjectKey, 'RouteContext.Provider'); createContext<RouteContextProps>(routeContextInjectKey, 'RouteContext.Provider');
export const useRouteContext = () => export const useRouteContext = () =>
useContext<RouteContextProps>('route-context' /* routeContextInjectKey */); useContext<Required<RouteContextProps>>(
'route-context' /* routeContextInjectKey */,
defaultRouteContext,
);
const Provider = createRouteContext(); const Provider = createRouteContext();
......
...@@ -127,7 +127,7 @@ class MenuUtil { ...@@ -127,7 +127,7 @@ class MenuUtil {
if (Array.isArray(item.children) && item.children.length > 0 && !item?.meta?.hideInMenu) { if (Array.isArray(item.children) && item.children.length > 0 && !item?.meta?.hideInMenu) {
const { prefixCls, i18n } = this.props; const { prefixCls, i18n } = this.props;
const menuTitle = (i18n && i18n(item.meta?.title)) || item.meta?.title; const menuTitle = (i18n && i18n(item.meta?.title)) || item.meta?.title;
const defaultTitle = item?.meta.icon ? ( const defaultTitle = item.meta?.icon ? (
<span class={`${prefixCls}-menu-item`}> <span class={`${prefixCls}-menu-item`}>
{!isChildren && <LazyIcon icon={item.meta.icon} />} {!isChildren && <LazyIcon icon={item.meta.icon} />}
<span class={`${prefixCls}-menu-item-title`}>{menuTitle}</span> <span class={`${prefixCls}-menu-item-title`}>{menuTitle}</span>
...@@ -157,7 +157,7 @@ class MenuUtil { ...@@ -157,7 +157,7 @@ class MenuUtil {
getMenuItem = (item: MenuDataItem, isChildren: boolean) => { getMenuItem = (item: MenuDataItem, isChildren: boolean) => {
const meta = Object.assign({}, item.meta); const meta = Object.assign({}, item.meta);
const target = meta.target || null; const target = (meta.target || null) as string | null;
const hasUrl = isUrl(item.path); const hasUrl = isUrl(item.path);
const CustomTag: any = resolveComponent((target && 'a') || 'router-link'); const CustomTag: any = resolveComponent((target && 'a') || 'router-link');
const props = { to: { name: item.name } }; const props = { to: { name: item.name } };
...@@ -165,7 +165,7 @@ class MenuUtil { ...@@ -165,7 +165,7 @@ class MenuUtil {
const { prefixCls, i18n } = this.props; const { prefixCls, i18n } = this.props;
const menuTitle = (i18n && i18n(item.meta?.title)) || item.meta?.title; const menuTitle = (i18n && i18n(item.meta?.title)) || item.meta?.title;
const defaultTitle = item?.meta.icon ? ( const defaultTitle = item.meta?.icon ? (
<CustomTag {...attrs} {...props}> <CustomTag {...attrs} {...props}>
<span class={`${prefixCls}-menu-item`}> <span class={`${prefixCls}-menu-item`}>
{!isChildren && <LazyIcon icon={item.meta.icon} />} {!isChildren && <LazyIcon icon={item.meta.icon} />}
...@@ -198,7 +198,7 @@ export default defineComponent({ ...@@ -198,7 +198,7 @@ export default defineComponent({
const isInline = computed(() => mode.value === 'inline'); const isInline = computed(() => mode.value === 'inline');
const menuUtil = new MenuUtil(props); const menuUtil = new MenuUtil(props);
const handleOpenChange: OpenEventHandler = (openKeys: string[]): void => { const handleOpenChange = (openKeys: string[]): void => {
emit('update:openKeys', openKeys); emit('update:openKeys', openKeys);
}; };
const handleSelect = (params: { const handleSelect = (params: {
......
...@@ -4,7 +4,7 @@ import Layout from 'ant-design-vue/es/layout'; ...@@ -4,7 +4,7 @@ import Layout from 'ant-design-vue/es/layout';
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 BaseMenu, { BaseMenuProps } from './BaseMenu'; import BaseMenu, { BaseMenuProps } from './BaseMenu';
import { WithFalse, VNodeType } from '../typings'; import { WithFalse, CustomRender } 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 { useRouteContext } from '../RouteContext'; import { useRouteContext } from '../RouteContext';
...@@ -19,16 +19,16 @@ export type PrivateSiderMenuProps = { ...@@ -19,16 +19,16 @@ export type PrivateSiderMenuProps = {
export interface SiderMenuProps export interface SiderMenuProps
extends Pick<BaseMenuProps, Exclude<keyof BaseMenuProps, ['onCollapse']>> { extends Pick<BaseMenuProps, Exclude<keyof BaseMenuProps, ['onCollapse']>> {
logo?: VNodeType; logo?: CustomRender;
siderWidth?: number; siderWidth?: number;
collapsedWidth?: number; collapsedWidth?: number;
menuHeaderRender?: WithFalse< menuHeaderRender?: WithFalse<
(logo: VNodeType, title: VNodeType, props?: SiderMenuProps) => VNodeType (logo: CustomRender, title: CustomRender, props?: SiderMenuProps) => CustomRender
>; >;
menuFooterRender?: WithFalse<(props?: SiderMenuProps) => VNodeType>; menuFooterRender?: WithFalse<(props?: SiderMenuProps) => CustomRender>;
menuContentRender?: WithFalse<(props: SiderMenuProps, defaultDom: VNodeType) => VNodeType>; menuContentRender?: WithFalse<(props: SiderMenuProps, defaultDom: CustomRender) => CustomRender>;
menuExtraRender?: WithFalse<(props: SiderMenuProps) => VNodeType>; menuExtraRender?: WithFalse<(props: SiderMenuProps) => CustomRender>;
collapsedButtonRender?: WithFalse<(collapsed?: boolean) => VNodeType>; collapsedButtonRender?: WithFalse<(collapsed?: boolean) => CustomRender>;
breakpoint?: SiderProps['breakpoint'] | false; breakpoint?: SiderProps['breakpoint'] | false;
onMenuHeaderClick?: (e: MouseEvent) => void; onMenuHeaderClick?: (e: MouseEvent) => void;
fixed?: boolean; fixed?: boolean;
...@@ -38,7 +38,10 @@ export interface SiderMenuProps ...@@ -38,7 +38,10 @@ export interface SiderMenuProps
onSelect?: (selectedKeys: WithFalse<string[]>) => void; onSelect?: (selectedKeys: WithFalse<string[]>) => void;
} }
export const defaultRenderLogo = (logo: VNodeType): VNodeType => { export const defaultRenderLogo = (logo?: CustomRender): CustomRender => {
if (!logo) {
return null;
}
if (typeof logo === 'string') { if (typeof logo === 'string') {
return <img src={logo} alt="logo" />; return <img src={logo} alt="logo" />;
} }
...@@ -51,7 +54,7 @@ export const defaultRenderLogo = (logo: VNodeType): VNodeType => { ...@@ -51,7 +54,7 @@ export const defaultRenderLogo = (logo: VNodeType): VNodeType => {
export const defaultRenderLogoAndTitle = ( export const defaultRenderLogoAndTitle = (
props: SiderMenuProps, props: SiderMenuProps,
renderKey: string | undefined = 'menuHeaderRender', renderKey: string | undefined = 'menuHeaderRender',
): VNodeType | null => { ): CustomRender | null => {
const { const {
logo = 'https://gw.alipayobjects.com/zos/antfincdn/PmY%24TNNDBI/logo.svg', logo = 'https://gw.alipayobjects.com/zos/antfincdn/PmY%24TNNDBI/logo.svg',
title, title,
...@@ -79,7 +82,7 @@ export const defaultRenderLogoAndTitle = ( ...@@ -79,7 +82,7 @@ export const defaultRenderLogoAndTitle = (
); );
}; };
export const defaultRenderCollapsedButton = (collapsed?: boolean): VNodeType => export const defaultRenderCollapsedButton = (collapsed?: boolean): CustomRender =>
collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />; collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />;
const SiderMenu: FunctionalComponent<SiderMenuProps> = (props: SiderMenuProps) => { const SiderMenu: FunctionalComponent<SiderMenuProps> = (props: SiderMenuProps) => {
......
...@@ -32,7 +32,7 @@ export const createContext = <T>( ...@@ -32,7 +32,7 @@ export const createContext = <T>(
}, },
}); });
return ContextProvider; return ContextProvider as any;
}; };
export const useContext = <T>( export const useContext = <T>(
......
import { ref } from 'vue'; import { ref } from 'vue';
export const MediaQueryEnum = { export const MediaQueryEnum /* : {
[key: string]: {
matchMedia: string;
minWidth?: number;
maxWidth?: number;
};
} */ = {
xs: { xs: {
maxWidth: 575, maxWidth: 575,
matchMedia: '(max-width: 575px)', matchMedia: '(max-width: 575px)',
...@@ -60,7 +66,7 @@ const useMedia = () => { ...@@ -60,7 +66,7 @@ const useMedia = () => {
const colSpan = ref<string>(getScreenClassName()); const colSpan = ref<string>(getScreenClassName());
Object.keys(MediaQueryEnum).forEach(key => { Object.keys(MediaQueryEnum).forEach(key => {
const { matchMedia } = MediaQueryEnum[key]; const { matchMedia } = MediaQueryEnum[key as MediaQueryKey];
const query = window.matchMedia(matchMedia); const query = window.matchMedia(matchMedia);
if (query.matches) { if (query.matches) {
colSpan.value = key; colSpan.value = key;
......
import { VNode } from 'vue'; import type { Slot, VNode } from 'vue';
// define global types
export type VNodeType = WithFalse<string | VNode | JSX.Element>;
export type MenuTheme = 'dark' | 'light'; export type MenuTheme = 'dark' | 'light';
...@@ -67,6 +64,14 @@ export interface MenuDataItem { ...@@ -67,6 +64,14 @@ export interface MenuDataItem {
export type WithFalse<T> = T | false; export type WithFalse<T> = T | false;
export type CustomRender = (...args: any[]) => VNode | VNode[]; export type CustomRender =
| Slot
| VNode
| ((...props: any) => Slot)
| ((...props: any) => VNode)
| ((...args: any[]) => VNode)
| VNode[]
| JSX.Element
| null;
export type FormatMessage = (message: string) => string; export type FormatMessage = (message?: string) => string;
...@@ -12,7 +12,11 @@ export function getComponentOrSlot(props: any, slots: Slots, name: string): VNod ...@@ -12,7 +12,11 @@ export function getComponentOrSlot(props: any, slots: Slots, name: string): VNod
return typeof comp === 'function' ? comp() : (comp && (comp as VNodeChild)) || false; return typeof comp === 'function' ? comp() : (comp && (comp as VNodeChild)) || false;
} }
export function getCustomRender(props: any, slots: Slots, name: string): CustomRender | false { export function getCustomRender(
props: any,
slots: Slots,
name: string,
): any | /* | CustomRender */ false | null {
const propRender = props[name]; const propRender = props[name];
if (propRender === false) { if (propRender === false) {
return false; return false;
...@@ -21,7 +25,7 @@ export function getCustomRender(props: any, slots: Slots, name: string): CustomR ...@@ -21,7 +25,7 @@ export function getCustomRender(props: any, slots: Slots, name: string): CustomR
return propRender; return propRender;
} }
const slotVNode = slots[name || 'default']; const slotVNode = slots[name || 'default'];
return slotVNode; return slotVNode || null;
} }
export function warn(valid: boolean, message: string) { export function warn(valid: boolean, message: string) {
...@@ -70,7 +74,7 @@ export function flatMap(menusData: MenuDataItem[]): MenuDataItem[] { ...@@ -70,7 +74,7 @@ export function flatMap(menusData: MenuDataItem[]): MenuDataItem[] {
delete finalItem.children; delete finalItem.children;
return finalItem; return finalItem;
}) })
.filter(item => item); .filter(item => item) as any[];
} }
export function getMenuFirstChildren(menus: MenuDataItem[], key?: string) { export function getMenuFirstChildren(menus: MenuDataItem[], key?: string) {
......
...@@ -36,7 +36,7 @@ exports[`BasicLayout 🥩 base use 1`] = ` ...@@ -36,7 +36,7 @@ exports[`BasicLayout 🥩 base use 1`] = `
<div class="custom-header-right-content"><span>custom-right-content</span></div> <div class="custom-header-right-content"><span>custom-right-content</span></div>
</div> </div>
</header> </header>
<main class="ant-layout-content ant-pro-basicLayout-content ant-pro-basicLayout-has-header" style="min-height: 300px;"> <main class="ant-layout-content ant-pro-basicLayout-content ant-pro-basicLayout-has-header" ischildrenlayout="false" style="min-height: 300px;">
<div>content</div> <div>content</div>
</main> </main>
<div>custom-footer</div> <div>custom-footer</div>
......
...@@ -38,7 +38,7 @@ exports[`PageContainer 🥩 base use 1`] = ` ...@@ -38,7 +38,7 @@ exports[`PageContainer 🥩 base use 1`] = `
</div> </div>
</div> </div>
</div> </div>
<div class="ant-pro-footer-bar"> <div class="ant-pro-footer-bar" style="width: 100%;">
<div class="ant-pro-footer-bar-left"> <div class="ant-pro-footer-bar-left">
<!----> <!---->
</div> </div>
......
import { mount, shallowMount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
// import BasicLayout from '../src/BasicLayout';
import ProProvider from '../src/ProProvider';
import GlobalFooter from '../src/GlobalFooter'; import GlobalFooter from '../src/GlobalFooter';
import { link } from 'fs';
const testLinks = [ const testLinks = [
{ {
...@@ -22,18 +19,23 @@ const testLinks = [ ...@@ -22,18 +19,23 @@ const testLinks = [
title: '@Sendya', title: '@Sendya',
href: 'https://www.github.com/sendya/', href: 'https://www.github.com/sendya/',
blankTarget: true, blankTarget: true,
} },
] ];
describe('GlobalFooter', () => { describe('GlobalFooter', () => {
it('🥩 base use', () => { it('🥩 base use', () => {
const wrapper = mount({ const wrapper = mount({
render() { render() {
return (<GlobalFooter return (
links={testLinks} <GlobalFooter
copyright={(<a href="https://github.com/vueComponent" target="_blank">vueComponent</a>)} links={testLinks}
/>); copyright={
<a href="https://github.com/vueComponent" target="_blank">
vueComponent
</a>
}
/>
);
}, },
}); });
expect(wrapper.html()).toMatchSnapshot(); expect(wrapper.html()).toMatchSnapshot();
...@@ -43,13 +45,17 @@ describe('GlobalFooter', () => { ...@@ -43,13 +45,17 @@ describe('GlobalFooter', () => {
const wrapper = mount({ const wrapper = mount({
render() { render() {
return ( return (
<GlobalFooter links={[{ <GlobalFooter
key: '1', links={[
title: 'Pro Layout', {
href: 'https://www.github.com/vueComponent/pro-layout', key: '1',
blankTarget: true, title: 'Pro Layout',
}]} /> href: 'https://www.github.com/vueComponent/pro-layout',
) blankTarget: true,
},
]}
/>
);
}, },
}); });
const links = wrapper.findAll('.ant-pro-global-footer-links a'); const links = wrapper.findAll('.ant-pro-global-footer-links a');
...@@ -59,12 +65,12 @@ describe('GlobalFooter', () => { ...@@ -59,12 +65,12 @@ describe('GlobalFooter', () => {
it('😄 custom copyright', () => { it('😄 custom copyright', () => {
const wrapper = mount({ const wrapper = mount({
render() { render() {
return ( return <GlobalFooter copyright={<a href="#copyright">vueComponent</a>} />;
<GlobalFooter copyright={(<a href="#copyright">vueComponent</a>)} />
);
}, },
}); });
expect(wrapper.find('.ant-pro-global-footer-copyright a').attributes()).toHaveProperty('href', '#copyright'); expect(wrapper.find('.ant-pro-global-footer-copyright a').attributes()).toHaveProperty(
'href',
'#copyright',
);
}); });
}); });
...@@ -2,18 +2,15 @@ import { mount } from '@vue/test-utils'; ...@@ -2,18 +2,15 @@ import { mount } from '@vue/test-utils';
import GridContent from '../src/GridContent'; import GridContent from '../src/GridContent';
describe('GridContent', () => { describe('GridContent', () => {
it('shoul render with empty children', () => { it('shoul render with empty children', () => {
const wrapper = mount(GridContent, { }); const wrapper = mount(GridContent, {});
expect(wrapper.html()).toMatchSnapshot(); expect(wrapper.html()).toMatchSnapshot();
}); });
it('shoul render with prop Fixed', () => { it('shoul render with prop Fixed', () => {
const wrapper = mount({ const wrapper = mount({
setup() { setup() {
return () => ( return () => <GridContent contentWidth="Fixed"></GridContent>;
<GridContent contentWidth="Fixed"></GridContent>
);
}, },
}); });
expect(wrapper.classes().indexOf('wide') > -1).toBe(true); expect(wrapper.classes().indexOf('wide') > -1).toBe(true);
...@@ -29,6 +26,8 @@ describe('GridContent', () => { ...@@ -29,6 +26,8 @@ describe('GridContent', () => {
); );
}, },
}); });
expect(wrapper.find('.ant-pro-grid-content-children').element.innerHTML === '<div>children</div>').toBe(true); expect(
wrapper.find('.ant-pro-grid-content-children').element.innerHTML === '<div>children</div>',
).toBe(true);
}); });
}); });
import './_utils/mock-func'; import './_utils/mock-func';
import { mount, shallowMount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { reactive } from 'vue'; import { PropType } from 'vue';
import BasicLayout from '../src/BasicLayout'; import BasicLayout, { BasicLayoutProps } from '../src/BasicLayout';
const title = 'Pro Tests'; const title = 'Pro Tests';
const logoSrc = 'https://alicdn.antdv.com/v2/assets/logo.1ef800a8.svg'; const logoSrc = 'https://alicdn.antdv.com/v2/assets/logo.1ef800a8.svg';
...@@ -54,11 +54,11 @@ describe('BasicLayout', () => { ...@@ -54,11 +54,11 @@ describe('BasicLayout', () => {
const wrapper = mount({ const wrapper = mount({
props: { props: {
theme: { theme: {
type: String, type: String as PropType<BasicLayoutProps['navTheme']>,
default: 'light', default: 'light',
}, },
layout: { layout: {
type: String, type: String as PropType<BasicLayoutProps['layout']>,
default: 'mix', default: 'mix',
}, },
}, },
......
...@@ -4,7 +4,6 @@ import { Tag, Button } from 'ant-design-vue'; ...@@ -4,7 +4,6 @@ import { Tag, Button } from 'ant-design-vue';
import { sleep } from './utils'; import { sleep } from './utils';
describe('PageContainer', () => { describe('PageContainer', () => {
const routes = [ const routes = [
{ {
path: 'index', path: 'index',
...@@ -21,20 +20,24 @@ describe('PageContainer', () => { ...@@ -21,20 +20,24 @@ describe('PageContainer', () => {
]; ];
const props = { const props = {
title: 'Title', title: 'Title',
subTitle: "This is a subtitle", subTitle: 'This is a subtitle',
breadcrumb: { routes }, breadcrumb: { routes },
onBack: () => {}, onBack: () => {},
tags: ['Tag 1', 'Tag 2'].map(tag => (<Tag color="blue">{tag}</Tag>)), tags: ['Tag 1', 'Tag 2'].map(tag => <Tag color="blue">{tag}</Tag>),
extra: [<Button key="1" type="primary">主操作</Button>,], extra: [
content: (<div>content</div>), <Button key="1" type="primary">
extraContent: (<div>extraContent</div>), 主操作
</Button>,
],
content: <div>content</div>,
extraContent: <div>extraContent</div>,
footer: [ footer: [
<Button key="3">重置</Button>, <Button key="3">重置</Button>,
<Button key="2" type="primary"> <Button key="2" type="primary">
提交 提交
</Button>, </Button>,
], ],
} };
it('🥩 base use', () => { it('🥩 base use', () => {
const wrapper = mount({ const wrapper = mount({
...@@ -52,12 +55,7 @@ describe('PageContainer', () => { ...@@ -52,12 +55,7 @@ describe('PageContainer', () => {
it('😄 custom title,subTitle', () => { it('😄 custom title,subTitle', () => {
const wrapper = mount({ const wrapper = mount({
render() { render() {
return ( return <PageContainer title="Title" subTitle="SubTitle" />;
<PageContainer
title="Title"
subTitle="SubTitle"
/>
);
}, },
}); });
...@@ -89,7 +87,9 @@ describe('PageContainer', () => { ...@@ -89,7 +87,9 @@ describe('PageContainer', () => {
render() { render() {
return ( return (
<PageContainer <PageContainer
tags={['Tag 1', 'Tag 2'].map(tag => (<Tag color="blue">{tag}</Tag>))} tags={['Tag 1', 'Tag 2'].map(tag => (
<Tag color="blue">{tag}</Tag>
))}
/> />
); );
}, },
......
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