Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
pro-layout
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
packages
pro-layout
Commits
5bddea71
Unverified
Commit
5bddea71
authored
Feb 27, 2021
by
Sendya
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: Menu, BasicLayout, VNodeType
parent
ec3c7128
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
243 additions
and
105 deletions
+243
-105
README.md
README.md
+3
-8
babel.config.js
babel.config.js
+1
-1
menus.ts
examples/menus.ts
+1
-3
test.html
examples/test.html
+0
-0
test.tsx
examples/test.tsx
+59
-0
BasicLayout.tsx
src/BasicLayout.tsx
+36
-44
index.tsx
src/GlobalHeader/index.tsx
+5
-8
Header.tsx
src/Header.tsx
+8
-14
BaseMenu.tsx
src/SiderMenu/BaseMenu.tsx
+0
-1
SiderMenu.tsx
src/SiderMenu/SiderMenu.tsx
+11
-13
index.less
src/SiderMenu/index.less
+1
-1
typings.ts
src/typings.ts
+3
-1
index.ts
src/utils/index.ts
+13
-1
index.test.tsx.snap
tests/__snapshots__/index.test.tsx.snap
+46
-0
mock-func.ts
tests/_utils/mock-func.ts
+12
-0
index.test.tsx
tests/index.test.tsx
+44
-10
No files found.
README.md
View file @
5bddea71
...
@@ -13,9 +13,9 @@ Ant Design Pro Layout
...
@@ -13,9 +13,9 @@ Ant Design Pro Layout
```
bash
```
bash
# yarn
# yarn
yarn add @ant-design-vue/pro-layout
yarn add @ant-design-vue/pro-layout
@next
# npm
# npm
npm i @ant-design-vue/pro-layout
-S
npm i @ant-design-vue/pro-layout
@next
-S
```
```
## Basic Usage
## Basic Usage
...
@@ -46,7 +46,7 @@ After that, you can use pro-layout in your Vue components as simply as this:
...
@@ -46,7 +46,7 @@ After that, you can use pro-layout in your Vue components as simply as this:
<
script
>
<
script
>
import
{
defineComponent
,
reactive
}
from
'vue'
;
import
{
defineComponent
,
reactive
}
from
'vue'
;
import
ProLayout
,
{
createRouteContext
}
from
'@ant-design-vue/pro-layout'
;
import
{
createRouteContext
}
from
'@ant-design-vue/pro-layout'
;
const
[
RouteContextProvider
]
=
createRouteContext
();
const
[
RouteContextProvider
]
=
createRouteContext
();
...
@@ -56,9 +56,7 @@ export default defineComponent({
...
@@ -56,9 +56,7 @@ export default defineComponent({
collapsed
:
false
,
collapsed
:
false
,
openKeys
:
[
'/dashboard'
],
openKeys
:
[
'/dashboard'
],
setOpenKeys
:
(
keys
)
=>
(
state
.
openKeys
=
keys
),
selectedKeys
:
[
'/welcome'
],
selectedKeys
:
[
'/welcome'
],
setSelectedKeys
:
(
keys
)
=>
(
state
.
selectedKeys
=
keys
),
isMobile
:
false
,
isMobile
:
false
,
fixSiderbar
:
false
,
fixSiderbar
:
false
,
...
@@ -76,7 +74,6 @@ export default defineComponent({
...
@@ -76,7 +74,6 @@ export default defineComponent({
}
}
},
},
components
:
{
components
:
{
ProLayout
,
RouteContextProvider
,
RouteContextProvider
,
}
}
});
});
...
@@ -95,9 +92,7 @@ export default defineComponent({
...
@@ -95,9 +92,7 @@ export default defineComponent({
collapsed
:
false
,
collapsed
:
false
,
openKeys
:
[
'/dashboard'
],
openKeys
:
[
'/dashboard'
],
setOpenKeys
:
(
keys
:
string
[])
=>
(
state
.
openKeys
=
keys
),
selectedKeys
:
[
'/welcome'
],
selectedKeys
:
[
'/welcome'
],
setSelectedKeys
:
(
keys
:
string
[])
=>
(
state
.
selectedKeys
=
keys
),
isMobile
:
false
,
isMobile
:
false
,
fixSiderbar
:
false
,
fixSiderbar
:
false
,
...
...
babel.config.js
View file @
5bddea71
...
@@ -3,7 +3,7 @@ module.exports = {
...
@@ -3,7 +3,7 @@ module.exports = {
test
:
{
test
:
{
presets
:
[[
'@babel/preset-env'
,
{
targets
:
{
node
:
true
}
}]],
presets
:
[[
'@babel/preset-env'
,
{
targets
:
{
node
:
true
}
}]],
plugins
:
[
plugins
:
[
'@vue/babel-plugin-jsx'
,
[
'@vue/babel-plugin-jsx'
,
{
mergeProps
:
false
}]
,
'@babel/plugin-proposal-optional-chaining'
,
'@babel/plugin-proposal-optional-chaining'
,
'@babel/plugin-transform-object-assign'
,
'@babel/plugin-transform-object-assign'
,
'@babel/plugin-proposal-object-rest-spread'
,
'@babel/plugin-proposal-object-rest-spread'
,
...
...
examples/menus.ts
View file @
5bddea71
import
{
RouteProps
}
from
'../src/typings'
;
export
const
menus
=
[
export
const
menus
:
RouteProps
[]
=
[
{
{
path
:
'/welcome'
,
path
:
'/welcome'
,
name
:
'welcome'
,
name
:
'welcome'
,
...
...
examples/test.html
0 → 100644
View file @
5bddea71
examples/test.tsx
0 → 100644
View file @
5bddea71
import
{
createApp
,
reactive
}
from
'vue'
;
import
{
default
as
ProLayout
,
createRouteContext
,
RouteContextProps
}
from
'../src/'
;
import
{
RouterLink
}
from
'./mock-router'
;
import
{
menus
}
from
'./menus'
;
import
registerIcons
from
'./_util/icons'
;
const
SimpleDemo
=
{
setup
()
{
const
[
RouteContextProvider
]
=
createRouteContext
();
const
appState
=
reactive
<
RouteContextProps
>
({
selectedKeys
:
[],
openKeys
:
[],
collapsed
:
true
,
menuData
:
menus
,
});
return
()
=>
(
<
RouteContextProvider
value=
{
appState
}
>
<
ProLayout
title=
"Pro Tests"
logo=
"https://alicdn.antdv.com/v2/assets/logo.1ef800a8.svg"
layout=
"side"
navTheme=
"light"
contentWidth=
"Fluid"
contentStyle=
{
{
minHeight
:
'300px'
}
}
collapsed=
{
appState
.
collapsed
}
onCollapse=
{
collapsed
=>
{
appState
.
collapsed
=
collapsed
;
}
}
onSelect=
{
(
selectedKeys
:
string
[]
|
false
)
=>
{
selectedKeys
&&
(
appState
.
selectedKeys
=
selectedKeys
);
}
}
onOpenKeys=
{
(
openKeys
:
string
[]
|
false
)
=>
{
console
.
log
(
'onOpenKeys'
,
openKeys
);
openKeys
&&
(
appState
.
openKeys
=
openKeys
);
}
}
footerRender=
{
()
=>
<
div
>
custom-footer
</
div
>
}
v
-
slots=
{
{
rightContentRender
:
props
=>
(
<
div
class=
"custom-header-right-content"
>
<
span
>
custom-right-content
</
span
>
</
div
>
),
}
}
>
<
div
>
content
</
div
>
</
ProLayout
>
</
RouteContextProvider
>
);
},
};
const
app
=
createApp
(
SimpleDemo
);
app
.
use
(
ProLayout
);
app
.
use
(
RouterLink
);
app
.
use
(
registerIcons
);
app
.
mount
(
'#__vue-content>div'
);
src/BasicLayout.tsx
View file @
5bddea71
import
{
computed
,
FunctionalComponent
,
CSSProperties
,
VNodeChild
,
VNode
,
unref
}
from
'vue'
;
import
{
computed
,
FunctionalComponent
,
CSSProperties
,
unref
}
from
'vue'
;
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'
;
...
@@ -6,8 +6,8 @@ import { default as ProProvider, ProProviderData } from './ProProvider';
...
@@ -6,8 +6,8 @@ import { default as ProProvider, ProProviderData } from './ProProvider';
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
{
RenderVNodeType
,
WithFalse
}
from
'./typings'
;
import
{
VNodeType
,
CustomRender
,
WithFalse
}
from
'./typings'
;
import
{
getC
omponentOrSlot
,
PropRenderType
,
PropTypes
}
from
'./utils'
;
import
{
getC
ustomRender
,
PropRenderType
,
PropTypes
}
from
'./utils'
;
import
useMediaQuery
from
'./hooks/useMediaQuery'
;
import
useMediaQuery
from
'./hooks/useMediaQuery'
;
import
'./BasicLayout.less'
;
import
'./BasicLayout.less'
;
...
@@ -19,7 +19,7 @@ export type BasicLayoutProps = SiderMenuWrapperProps &
...
@@ -19,7 +19,7 @@ export type BasicLayoutProps = SiderMenuWrapperProps &
/**
/**
*@name logo url
*@name logo url
*/
*/
logo
?:
string
|
RenderVNodeType
|
WithFalse
<
string
|
RenderVNodeType
>
;
logo
?:
VNodeType
;
loading
?:
boolean
;
loading
?:
boolean
;
...
@@ -29,11 +29,9 @@ export type BasicLayoutProps = SiderMenuWrapperProps &
...
@@ -29,11 +29,9 @@ export type BasicLayoutProps = SiderMenuWrapperProps &
onCollapse
?:
(
collapsed
:
boolean
)
=>
void
;
onCollapse
?:
(
collapsed
:
boolean
)
=>
void
;
footerRender
?:
WithFalse
<
footerRender
?:
WithFalse
<
(
props
:
any
/* FooterProps */
)
=>
VNodeType
>
;
(
props
:
any
/* FooterProps */
,
defaultDom
:
RenderVNodeType
)
=>
RenderVNodeType
>
;
headerRender
?:
WithFalse
<
(
props
:
any
/* HeaderProps */
)
=>
Render
VNodeType
>
;
headerRender
?:
WithFalse
<
(
props
:
any
/* HeaderProps */
)
=>
VNodeType
>
;
colSize
?:
string
;
colSize
?:
string
;
/**
/**
...
@@ -68,19 +66,16 @@ const ProLayout: FunctionalComponent<BasicLayoutProps> = (props, { emit, slots }
...
@@ -68,19 +66,16 @@ const ProLayout: FunctionalComponent<BasicLayoutProps> = (props, { emit, slots }
const
isTop
=
computed
(()
=>
layout
===
'top'
);
const
isTop
=
computed
(()
=>
layout
===
'top'
);
// const isSide = computed(() => layout === 'side');
// const isSide = computed(() => layout === 'side');
// const isMix = computed(() => layout === 'mix');
// const isMix = computed(() => layout === 'mix');
// if on event and @event
const
handleCollapse
=
(
collapsed
:
boolean
)
=>
{
const
onCollapse
=
propsOnCollapse
&&
propsOnCollapse
(
collapsed
);
(
propsOnCollapse
&&
propsOnCollapse
)
||
emit
(
'update:collapsed'
,
collapsed
);
((
collapsed
:
boolean
)
=>
emit
(
'update:collapsed'
,
collapsed
));
};
const
onOpenKeys
=
const
handleOpenKeys
=
(
openKeys
:
string
[]
|
false
):
void
=>
{
(
propsOnOpenKeys
&&
propsOnOpenKeys
)
||
propsOnOpenKeys
&&
propsOnOpenKeys
(
openKeys
);
((
openKeys
:
string
[]
|
false
)
=>
emit
(
'update:open-keys'
,
openKeys
));
emit
(
'update:open-keys'
,
openKeys
);
const
onSelect
=
};
(
propsOnSelect
&&
propsOnSelect
)
||
const
handleSelect
=
(
selectedKeys
:
string
[]
|
false
):
void
=>
{
((
selectedKeys
:
string
[]
|
false
)
=>
emit
(
'update:selected-keys'
,
selectedKeys
));
propsOnSelect
&&
propsOnSelect
(
selectedKeys
);
emit
(
'update:selected-keys'
,
selectedKeys
);
};
const
colSize
=
useMediaQuery
();
const
colSize
=
useMediaQuery
();
const
isMobile
=
computed
(
const
isMobile
=
computed
(
()
=>
(
colSize
.
value
===
'sm'
||
colSize
.
value
===
'xs'
)
&&
!
props
.
disableMobile
,
()
=>
(
colSize
.
value
===
'sm'
||
colSize
.
value
===
'xs'
)
&&
!
props
.
disableMobile
,
...
@@ -115,42 +110,39 @@ const ProLayout: FunctionalComponent<BasicLayoutProps> = (props, { emit, slots }
...
@@ -115,42 +110,39 @@ const ProLayout: FunctionalComponent<BasicLayoutProps> = (props, { emit, slots }
const
headerRender
=
(
const
headerRender
=
(
props
:
BasicLayoutProps
&
{
props
:
BasicLayoutProps
&
{
hasSiderMenu
:
boolean
;
hasSiderMenu
:
boolean
;
customHeaderRender
:
VNodeChild
|
false
;
customHeaderRender
:
WithFalse
<
CustomRender
>
;
rightContentRender
:
VNodeChild
|
VNode
|
false
;
rightContentRender
:
WithFalse
<
CustomRender
>
;
},
},
matchMenuKeys
:
string
[],
matchMenuKeys
:
string
[],
):
Render
VNodeType
=>
{
):
VNodeType
=>
{
if
(
props
.
headerRender
===
false
||
props
.
pure
)
{
if
(
props
.
headerRender
===
false
||
props
.
pure
)
{
return
null
;
return
null
;
}
}
return
<
Header
matchMenuKeys=
{
matchMenuKeys
}
{
...
props
}
headerHeight=
{
48
}
/>;
return
<
Header
matchMenuKeys=
{
matchMenuKeys
}
{
...
props
}
headerHeight=
{
48
}
/>;
};
};
const
rightContentRender
=
getComponentOrSlot
(
props
,
slots
,
'rightContentRender'
)
as
any
;
const
rightContentRender
=
getCustomRender
(
props
,
slots
,
'rightContentRender'
);
const
customHeaderRender
=
getComponentOrSlot
(
props
,
slots
,
'headerRender'
);
const
customHeaderRender
=
getCustomRender
(
props
,
slots
,
'headerRender'
);
const
menuHeaderRenderFunc
=
props
[
'menuHeaderRender'
];
const
menuHeaderRender
=
getCustomRender
(
props
,
slots
,
'menuHeaderRender'
);
const
menuHeaderRenderSlot
=
slots
[
'menuHeaderRender'
];
const
footerRender
=
getCustomRender
(
props
,
slots
,
'footerRender'
);
// const menuRender = getCustomRender(props, slots, 'menuRender');
const
headerDom
=
headerRender
(
const
headerDom
=
headerRender
(
{
{
...
props
,
...
props
,
hasSiderMenu
:
!
isTop
.
value
,
hasSiderMenu
:
!
isTop
.
value
,
menuData
,
menuData
,
isMobile
:
unref
(
isMobile
),
isMobile
:
unref
(
isMobile
),
onCollapse
:
handleCollapse
,
onCollapse
,
on
Select
:
handleSelect
,
on
OpenKeys
,
on
OpenKeys
:
handleOpenKeys
,
on
Select
,
customHeaderRender
,
customHeaderRender
,
rightContentRender
,
rightContentRender
,
headerTitleRender
:
headerTitleRender
:
menuHeaderRender
,
menuHeaderRenderFunc
||
(
menuHeaderRenderSlot
&&
(()
=>
menuHeaderRenderSlot
())),
theme
:
(
navTheme
||
'dark'
).
toLocaleLowerCase
().
includes
(
'dark'
)
?
'dark'
:
'light'
,
theme
:
(
navTheme
||
'dark'
).
toLocaleLowerCase
().
includes
(
'dark'
)
?
'dark'
:
'light'
,
},
},
matchMenuKeys
,
matchMenuKeys
,
);
);
const
footerRender
=
getComponentOrSlot
(
props
,
slots
,
'footerRender'
);
// const menuRender = getComponentOrSlot(props, slots, 'menuRender');
// const menuHeaderRender = getComponentOrSlot(props, slots, 'menuHeaderRender');
return
(
return
(
<
ProProvider
i18n=
{
defaultI18nRender
}
>
<
ProProvider
i18n=
{
defaultI18nRender
}
>
{
props
.
pure
?
(
{
props
.
pure
?
(
...
@@ -162,12 +154,10 @@ const ProLayout: FunctionalComponent<BasicLayoutProps> = (props, { emit, slots }
...
@@ -162,12 +154,10 @@ const ProLayout: FunctionalComponent<BasicLayoutProps> = (props, { emit, slots }
<
SiderMenuWrapper
<
SiderMenuWrapper
{
...
props
}
{
...
props
}
isMobile=
{
isMobile
.
value
}
isMobile=
{
isMobile
.
value
}
menuHeaderRender=
{
menuHeaderRender=
{
menuHeaderRender
}
menuHeaderRenderFunc
||
(
menuHeaderRenderSlot
&&
(()
=>
menuHeaderRenderSlot
()))
onCollapse=
{
onCollapse
}
}
onSelect=
{
onSelect
}
onCollapse=
{
handleCollapse
}
onOpenKeys=
{
onOpenKeys
}
onSelect=
{
handleSelect
}
onOpenKeys=
{
handleOpenKeys
}
/>
/>
)
}
)
}
<
Layout
style=
{
genLayoutStyle
}
>
<
Layout
style=
{
genLayoutStyle
}
>
...
@@ -178,7 +168,7 @@ const ProLayout: FunctionalComponent<BasicLayoutProps> = (props, { emit, slots }
...
@@ -178,7 +168,7 @@ const ProLayout: FunctionalComponent<BasicLayoutProps> = (props, { emit, slots }
>
>
{
slots
.
default
?.()
}
{
slots
.
default
?.()
}
</
WrapContent
>
</
WrapContent
>
{
footerRender
!==
false
&&
footerRender
&&
footerRender
}
{
footerRender
&&
footerRender
(
props
)
}
</
Layout
>
</
Layout
>
</
Layout
>
</
Layout
>
</
div
>
</
div
>
...
@@ -266,6 +256,8 @@ ProLayout.props = {
...
@@ -266,6 +256,8 @@ ProLayout.props = {
collapsed
:
PropTypes
.
bool
,
collapsed
:
PropTypes
.
bool
,
/* 菜单的折叠收起事件 (collapsed: boolean) => void */
/* 菜单的折叠收起事件 (collapsed: boolean) => void */
onCollapse
:
PropTypes
.
func
,
onCollapse
:
PropTypes
.
func
,
onSelect
:
PropTypes
.
func
,
onOpenKeys
:
PropTypes
.
func
,
// onPageChange // 请使用 vue-router 监听
// onPageChange // 请使用 vue-router 监听
/* 禁止自动切换到移动页面 */
/* 禁止自动切换到移动页面 */
disableMobile
:
PropTypes
.
bool
,
disableMobile
:
PropTypes
.
bool
,
...
...
src/GlobalHeader/index.tsx
View file @
5bddea71
import
{
computed
,
CSSProperties
,
FunctionalComponent
}
from
'vue'
;
import
{
computed
,
CSSProperties
,
FunctionalComponent
}
from
'vue'
;
import
{
PureSettings
}
from
'../defaultSettings'
;
import
{
PureSettings
}
from
'../defaultSettings'
;
import
{
Render
VNodeType
,
MenuDataItem
,
WithFalse
}
from
'../typings'
;
import
{
VNodeType
,
MenuDataItem
,
WithFalse
}
from
'../typings'
;
import
{
import
{
SiderMenuProps
,
SiderMenuProps
,
PrivateSiderMenuProps
,
PrivateSiderMenuProps
,
...
@@ -18,9 +18,9 @@ export interface GlobalHeaderProps extends Partial<PureSettings> {
...
@@ -18,9 +18,9 @@ export interface GlobalHeaderProps extends Partial<PureSettings> {
collapsed
?:
boolean
;
collapsed
?:
boolean
;
onCollapse
?:
(
collapsed
:
boolean
)
=>
void
;
onCollapse
?:
(
collapsed
:
boolean
)
=>
void
;
isMobile
?:
boolean
;
isMobile
?:
boolean
;
logo
?:
Render
VNodeType
;
logo
?:
VNodeType
;
menuRender
?:
WithFalse
<
(
props
:
HeaderViewProps
,
defaultDom
:
RenderVNodeType
)
=>
Render
VNodeType
>
;
menuRender
?:
WithFalse
<
(
props
:
HeaderViewProps
,
defaultDom
:
VNodeType
)
=>
VNodeType
>
;
rightContentRender
?:
WithFalse
<
(
props
:
HeaderViewProps
)
=>
Render
VNodeType
>
;
rightContentRender
?:
WithFalse
<
(
props
:
HeaderViewProps
)
=>
VNodeType
>
;
className
?:
string
;
className
?:
string
;
prefixCls
?:
string
;
prefixCls
?:
string
;
menuData
?:
MenuDataItem
[];
menuData
?:
MenuDataItem
[];
...
@@ -33,10 +33,7 @@ export interface GlobalHeaderProps extends Partial<PureSettings> {
...
@@ -33,10 +33,7 @@ export interface GlobalHeaderProps extends Partial<PureSettings> {
onSelect
?:
(
selectedKeys
:
WithFalse
<
string
[]
>
)
=>
void
;
onSelect
?:
(
selectedKeys
:
WithFalse
<
string
[]
>
)
=>
void
;
}
}
const
renderLogo
=
(
const
renderLogo
=
(
menuHeaderRender
:
SiderMenuProps
[
'menuHeaderRender'
],
logoDom
:
VNodeType
)
=>
{
menuHeaderRender
:
SiderMenuProps
[
'menuHeaderRender'
],
logoDom
:
RenderVNodeType
,
)
=>
{
if
(
menuHeaderRender
===
false
)
{
if
(
menuHeaderRender
===
false
)
{
return
null
;
return
null
;
}
}
...
...
src/Header.tsx
View file @
5bddea71
...
@@ -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
{
Render
VNodeType
,
WithFalse
}
from
'./typings'
;
import
{
VNodeType
,
WithFalse
}
from
'./typings'
;
import
{
clearMenuItem
}
from
'./utils'
;
import
{
clearMenuItem
}
from
'./utils'
;
import
'./Header.less'
;
import
'./Header.less'
;
...
@@ -18,15 +18,11 @@ interface HeaderViewState {
...
@@ -18,15 +18,11 @@ interface HeaderViewState {
export
type
HeaderViewProps
=
GlobalHeaderProps
&
{
export
type
HeaderViewProps
=
GlobalHeaderProps
&
{
isMobile
?:
boolean
;
isMobile
?:
boolean
;
collapsed
?:
boolean
;
collapsed
?:
boolean
;
logo
?:
Render
VNodeType
;
logo
?:
VNodeType
;
headerRender
?:
WithFalse
<
headerRender
?:
WithFalse
<
(
props
:
HeaderViewProps
,
defaultDom
:
VNodeType
)
=>
VNodeType
>
;
(
props
:
HeaderViewProps
,
defaultDom
:
RenderVNodeType
)
=>
RenderVNodeType
headerTitleRender
?:
WithFalse
<
(
props
:
HeaderViewProps
,
defaultDom
:
VNodeType
)
=>
VNodeType
>
;
>
;
headerContentRender
?:
WithFalse
<
(
props
:
HeaderViewProps
)
=>
VNodeType
>
;
headerTitleRender
?:
WithFalse
<
(
props
:
HeaderViewProps
,
defaultDom
:
RenderVNodeType
)
=>
RenderVNodeType
>
;
headerContentRender
?:
WithFalse
<
(
props
:
HeaderViewProps
)
=>
RenderVNodeType
>
;
siderWidth
?:
number
;
siderWidth
?:
number
;
hasSiderMenu
?:
boolean
;
hasSiderMenu
?:
boolean
;
};
};
...
@@ -66,8 +62,6 @@ export const HeaderView = defineComponent({
...
@@ -66,8 +62,6 @@ export const HeaderView = defineComponent({
setup
(
props
:
HeaderViewProps
)
{
setup
(
props
:
HeaderViewProps
)
{
const
{
const
{
prefixCls
,
prefixCls
,
headerRender
,
headerContentRender
,
isMobile
,
isMobile
,
fixedHeader
,
fixedHeader
,
hasSiderMenu
,
hasSiderMenu
,
...
@@ -96,7 +90,7 @@ export const HeaderView = defineComponent({
...
@@ -96,7 +90,7 @@ export const HeaderView = defineComponent({
const
renderContent
=
()
=>
{
const
renderContent
=
()
=>
{
let
defaultDom
=
(
let
defaultDom
=
(
<
GlobalHeader
{
...
props
}
onCollapse=
{
onCollapse
.
value
}
menuData=
{
clearMenuData
.
value
}
>
<
GlobalHeader
{
...
props
}
onCollapse=
{
onCollapse
.
value
}
menuData=
{
clearMenuData
.
value
}
>
{
headerContentRender
&&
headerContentRender
.
value
&&
headerContentRender
.
value
(
props
)
}
{
props
.
headerContentRender
&&
props
.
headerContentRender
(
props
)
}
</
GlobalHeader
>
</
GlobalHeader
>
);
);
if
(
isTop
.
value
&&
!
isMobile
.
value
)
{
if
(
isTop
.
value
&&
!
isMobile
.
value
)
{
...
@@ -110,8 +104,8 @@ export const HeaderView = defineComponent({
...
@@ -110,8 +104,8 @@ export const HeaderView = defineComponent({
/>
/>
);
);
}
}
if
(
headerRender
.
value
&&
typeof
headerRender
.
value
===
'function'
)
{
if
(
props
.
headerRender
)
{
return
headerRender
.
value
(
props
,
defaultDom
);
return
props
.
headerRender
(
props
,
defaultDom
);
}
}
return
defaultDom
;
return
defaultDom
;
};
};
...
...
src/SiderMenu/BaseMenu.tsx
View file @
5bddea71
...
@@ -117,7 +117,6 @@ class MenuUtil {
...
@@ -117,7 +117,6 @@ class MenuUtil {
constructor
(
props
:
BaseMenuProps
)
{
constructor
(
props
:
BaseMenuProps
)
{
this
.
props
=
props
;
this
.
props
=
props
;
console
.
log
(
'MenuUtil constructor'
,
new
Date
());
}
}
getNavMenuItems
=
(
menusData
:
MenuDataItem
[]
=
[],
isChildren
:
boolean
)
=>
{
getNavMenuItems
=
(
menusData
:
MenuDataItem
[]
=
[],
isChildren
:
boolean
)
=>
{
...
...
src/SiderMenu/SiderMenu.tsx
View file @
5bddea71
...
@@ -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
,
Render
VNodeType
}
from
'../typings'
;
import
{
WithFalse
,
VNodeType
}
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
{
useProProvider
}
from
'../ProProvider'
;
import
{
useProProvider
}
from
'../ProProvider'
;
...
@@ -20,27 +20,26 @@ export type PrivateSiderMenuProps = {
...
@@ -20,27 +20,26 @@ export type PrivateSiderMenuProps = {
export
interface
SiderMenuProps
export
interface
SiderMenuProps
extends
Pick
<
BaseMenuProps
,
Exclude
<
keyof
BaseMenuProps
,
[
'onCollapse'
]
>>
{
extends
Pick
<
BaseMenuProps
,
Exclude
<
keyof
BaseMenuProps
,
[
'onCollapse'
]
>>
{
logo
?:
Render
VNodeType
;
logo
?:
VNodeType
;
siderWidth
?:
number
;
siderWidth
?:
number
;
collapsedWidth
?:
number
;
collapsedWidth
?:
number
;
menuHeaderRender
?:
WithFalse
<
menuHeaderRender
?:
WithFalse
<
(
logo
:
RenderVNodeType
,
title
:
RenderVNodeType
,
props
?:
SiderMenuProps
)
=>
Render
VNodeType
(
logo
:
VNodeType
,
title
:
VNodeType
,
props
?:
SiderMenuProps
)
=>
VNodeType
>
;
>
;
menuFooterRender
?:
WithFalse
<
(
props
?:
SiderMenuProps
)
=>
RenderVNodeType
>
;
menuFooterRender
?:
WithFalse
<
(
props
?:
SiderMenuProps
)
=>
VNodeType
>
;
menuContentRender
?:
WithFalse
<
menuContentRender
?:
WithFalse
<
(
props
:
SiderMenuProps
,
defaultDom
:
VNodeType
)
=>
VNodeType
>
;
(
props
:
SiderMenuProps
,
defaultDom
:
RenderVNodeType
)
=>
RenderVNodeType
menuExtraRender
?:
WithFalse
<
(
props
:
SiderMenuProps
)
=>
VNodeType
>
;
>
;
collapsedButtonRender
?:
WithFalse
<
(
collapsed
?:
boolean
)
=>
VNodeType
>
;
menuExtraRender
?:
WithFalse
<
(
props
:
SiderMenuProps
)
=>
RenderVNodeType
>
;
collapsedButtonRender
?:
WithFalse
<
(
collapsed
?:
boolean
)
=>
RenderVNodeType
>
;
breakpoint
?:
SiderProps
[
'breakpoint'
]
|
false
;
breakpoint
?:
SiderProps
[
'breakpoint'
]
|
false
;
onMenuHeaderClick
?:
(
e
:
MouseEvent
)
=>
void
;
onMenuHeaderClick
?:
(
e
:
MouseEvent
)
=>
void
;
fixed
?:
boolean
;
fixed
?:
boolean
;
hide
?:
boolean
;
hide
?:
boolean
;
onCollapse
?:
(
collapsed
:
boolean
)
=>
void
;
onOpenKeys
?:
(
openKeys
:
WithFalse
<
string
[]
>
)
=>
void
;
onOpenKeys
?:
(
openKeys
:
WithFalse
<
string
[]
>
)
=>
void
;
onSelect
?:
(
selectedKeys
:
WithFalse
<
string
[]
>
)
=>
void
;
onSelect
?:
(
selectedKeys
:
WithFalse
<
string
[]
>
)
=>
void
;
}
}
export
const
defaultRenderLogo
=
(
logo
:
RenderVNodeType
):
Render
VNodeType
=>
{
export
const
defaultRenderLogo
=
(
logo
:
VNodeType
):
VNodeType
=>
{
if
(
typeof
logo
===
'string'
)
{
if
(
typeof
logo
===
'string'
)
{
return
<
img
src=
{
logo
}
alt=
"logo"
/>;
return
<
img
src=
{
logo
}
alt=
"logo"
/>;
}
}
...
@@ -53,7 +52,7 @@ export const defaultRenderLogo = (logo: RenderVNodeType): RenderVNodeType => {
...
@@ -53,7 +52,7 @@ export const defaultRenderLogo = (logo: RenderVNodeType): RenderVNodeType => {
export
const
defaultRenderLogoAndTitle
=
(
export
const
defaultRenderLogoAndTitle
=
(
props
:
SiderMenuProps
,
props
:
SiderMenuProps
,
renderKey
:
string
|
undefined
=
'menuHeaderRender'
,
renderKey
:
string
|
undefined
=
'menuHeaderRender'
,
):
Render
VNodeType
=>
{
):
VNodeType
=>
{
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
,
...
@@ -81,7 +80,7 @@ export const defaultRenderLogoAndTitle = (
...
@@ -81,7 +80,7 @@ export const defaultRenderLogoAndTitle = (
);
);
};
};
export
const
defaultRenderCollapsedButton
=
(
collapsed
?:
boolean
):
Render
VNodeType
=>
export
const
defaultRenderCollapsedButton
=
(
collapsed
?:
boolean
):
VNodeType
=>
collapsed
?
<
MenuUnfoldOutlined
/>
:
<
MenuFoldOutlined
/>;
collapsed
?
<
MenuUnfoldOutlined
/>
:
<
MenuFoldOutlined
/>;
const
SiderMenu
:
FunctionalComponent
<
SiderMenuProps
>
=
(
props
:
SiderMenuProps
)
=>
{
const
SiderMenu
:
FunctionalComponent
<
SiderMenuProps
>
=
(
props
:
SiderMenuProps
)
=>
{
...
@@ -102,7 +101,6 @@ const SiderMenu: FunctionalComponent<SiderMenuProps> = (props: SiderMenuProps) =
...
@@ -102,7 +101,6 @@ const SiderMenu: FunctionalComponent<SiderMenuProps> = (props: SiderMenuProps) =
const
{
getPrefixCls
}
=
useProProvider
();
const
{
getPrefixCls
}
=
useProProvider
();
const
context
=
useRouteContext
();
const
context
=
useRouteContext
();
const
baseClassName
=
getPrefixCls
(
'sider'
);
const
baseClassName
=
getPrefixCls
(
'sider'
);
// const isMix = computed(() => props.layout === 'mix');
// const isMix = computed(() => props.layout === 'mix');
// const fixed = computed(() => context.fixSiderbar);
// const fixed = computed(() => context.fixSiderbar);
const
runtimeTheme
=
computed
(()
=>
(
props
.
layout
===
'mix'
&&
'light'
)
||
props
.
navTheme
);
const
runtimeTheme
=
computed
(()
=>
(
props
.
layout
===
'mix'
&&
'light'
)
||
props
.
navTheme
);
...
...
src/SiderMenu/index.less
View file @
5bddea71
...
@@ -11,7 +11,7 @@
...
@@ -11,7 +11,7 @@
border-right: 0;
border-right: 0;
transition: background-color 0.3s, min-width 0.3s,
transition: background-color 0.3s, min-width 0.3s,
max-width 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
max-width 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
z-index:
9
;
z-index:
100
;
&.@{ant-prefix}-menu-vertical .@{ant-prefix}-menu-item:not(:last-child),
&.@{ant-prefix}-menu-vertical .@{ant-prefix}-menu-item:not(:last-child),
&.@{ant-prefix}-menu-vertical-left .@{ant-prefix}-menu-item:not(:last-child),
&.@{ant-prefix}-menu-vertical-left .@{ant-prefix}-menu-item:not(:last-child),
...
...
src/typings.ts
View file @
5bddea71
import
{
VNode
}
from
'vue'
;
import
{
VNode
}
from
'vue'
;
// define global types
// define global types
export
type
RenderVNodeType
=
VNode
|
Element
|
JSX
.
Element
;
export
type
VNodeType
=
WithFalse
<
string
|
VNode
|
JSX
.
Element
>
;
export
type
MenuTheme
=
'dark'
|
'light'
;
export
type
MenuTheme
=
'dark'
|
'light'
;
...
@@ -67,4 +67,6 @@ export interface MenuDataItem {
...
@@ -67,4 +67,6 @@ export interface MenuDataItem {
export
type
WithFalse
<
T
>
=
T
|
false
;
export
type
WithFalse
<
T
>
=
T
|
false
;
export
type
CustomRender
=
(...
args
:
any
[])
=>
VNode
|
VNode
[];
export
type
FormatMessage
=
(
message
:
string
)
=>
string
;
export
type
FormatMessage
=
(
message
:
string
)
=>
string
;
src/utils/index.ts
View file @
5bddea71
import
{
Slots
,
VNodeChild
}
from
'vue'
;
import
{
Slots
,
VNodeChild
}
from
'vue'
;
import
{
MenuDataItem
}
from
'../typings'
;
import
{
CustomRender
,
MenuDataItem
}
from
'../typings'
;
export
{
getComponent
}
from
'ant-design-vue/es/_util/props-util'
;
export
{
getComponent
}
from
'ant-design-vue/es/_util/props-util'
;
export
{
default
as
PropTypes
}
from
'ant-design-vue/es/_util/vue-types'
;
export
{
default
as
PropTypes
}
from
'ant-design-vue/es/_util/vue-types'
;
...
@@ -12,6 +12,18 @@ export function getComponentOrSlot(props: any, slots: Slots, name: string): VNod
...
@@ -12,6 +12,18 @@ 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
{
const
propRender
=
props
[
name
];
if
(
propRender
===
false
)
{
return
false
;
}
if
(
propRender
)
{
return
propRender
;
}
const
slotVNode
=
slots
[
name
||
'default'
];
return
slotVNode
;
}
export
function
warn
(
valid
:
boolean
,
message
:
string
)
{
export
function
warn
(
valid
:
boolean
,
message
:
string
)
{
// Support uglify
// Support uglify
if
(
process
.
env
.
NODE_ENV
!==
'production'
&&
!
valid
&&
console
!==
undefined
)
{
if
(
process
.
env
.
NODE_ENV
!==
'production'
&&
!
valid
&&
console
!==
undefined
)
{
...
...
tests/__snapshots__/index.test.tsx.snap
0 → 100644
View file @
5bddea71
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`BasicLayout 🥩 base use 1`] = `
<div class="ant-pro-basicLayout ant-pro-basicLayout-side">
<section class="ant-layout ant-pro-basicLayout">
<!---->
<aside class="ant-pro-sider ant-pro-sider-light ant-pro-sider-side ant-layout-sider ant-layout-sider-light" style="flex: 0 0 208px; max-width: 208px; min-width: 208px; width: 208px;">
<div class="ant-layout-sider-children">
<div class="ant-pro-sider-logo"><a><img src="https://alicdn.antdv.com/v2/assets/logo.1ef800a8.svg" alt="logo">
<h1>Pro Tests</h1>
</a></div>
<div style="flex: 1; overflow: hidden auto;">
<ul role="menu" class="ant-pro-sider-menu ant-menu-light ant-menu-root ant-menu ant-menu-inline" style="width: 100%;"></ul>
</div>
<div class="ant-pro-sider-links">
<ul role="menu" class="ant-pro-sider-link-menu ant-menu-light ant-menu-root ant-menu ant-menu-inline">
<!---->
<li role="menuitem" style="padding-left: 16px;" class="ant-pro-sider-collapsed-button ant-menu-item"><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>
<!---->
</li>
</ul>
</div>
</div>
<!---->
</aside>
<section class="ant-layout" style="position: relative; min-height: 0;">
<!---->
<header class="ant-layout-header" style="padding: 0px; height: 48px; line-height: 48px; width: 100%; z-index: 19;">
<div class="ant-pro-global-header ant-pro-global-header-layout-side">
<!---->
<!---->
<!---->
<div style="flex: 1;">
<!---->
</div>
<div class="custom-header-right-content"><span>custom-right-content</span></div>
</div>
</header>
<main class="ant-layout-content ant-pro-basicLayout-content ant-pro-basicLayout-has-header" style="min-height: 300px;">
<div>content</div>
</main>
<div>custom-footer</div>
</section>
</section>
</div>
`;
tests/_utils/mock-func.ts
0 → 100644
View file @
5bddea71
window
.
matchMedia
=
jest
.
fn
().
mockImplementation
(
query
=>
{
return
{
matches
:
false
,
media
:
query
,
onchange
:
null
,
addListener
:
jest
.
fn
(),
// deprecated
removeListener
:
jest
.
fn
(),
// deprecated
addEventListener
:
jest
.
fn
(),
removeEventListener
:
jest
.
fn
(),
dispatchEvent
:
jest
.
fn
(),
};
});
tests/index.test.tsx
View file @
5bddea71
import
{
mount
,
shallowMount
}
from
'@vue/test-utils'
;
import
'./_utils/mock-func'
;
import
{
mount
}
from
'@vue/test-utils'
;
import
BasicLayout
from
'../src/BasicLayout'
;
import
BasicLayout
from
'../src/BasicLayout'
;
describe
(
'BasicLayout'
,
()
=>
{
const
title
=
'Pro Tests'
;
const
logoSrc
=
'https://alicdn.antdv.com/v2/assets/logo.1ef800a8.svg'
;
describe
(
'BasicLayout'
,
()
=>
{
it
(
'🥩 base use'
,
()
=>
{
it
(
'🥩 base use'
,
()
=>
{
// const wrapper = mount({
const
wrapper
=
mount
({
// render() {
render
()
{
// return (
return
(
// <BasicLayout />
<
BasicLayout
// )
title=
{
title
}
// },
logo=
{
logoSrc
}
// });
layout=
"side"
// console.log(wrapper.html());
navTheme=
"light"
contentWidth=
"Fluid"
contentStyle=
{
{
minHeight
:
'300px'
}
}
rightContentRender=
{
()
=>
(
<
div
class=
"custom-header-right-content"
>
<
span
>
custom-right-content
</
span
>
</
div
>
)
}
footerRender=
{
()
=>
<
div
>
custom-footer
</
div
>
}
>
<
div
>
content
</
div
>
</
BasicLayout
>
);
},
});
expect
(
wrapper
.
html
()).
toMatchSnapshot
();
});
});
it
(
'😄 custom title, logo'
,
()
=>
{
const
wrapper
=
mount
({
render
()
{
return
(
<
BasicLayout
title=
{
title
}
logo=
{
logoSrc
}
>
<
div
>
content
</
div
>
</
BasicLayout
>
);
},
});
const
renderTitle
=
wrapper
.
find
(
'.ant-pro-sider-logo h1'
);
const
renderLogo
=
wrapper
.
find
(
'.ant-pro-sider-logo img'
);
expect
(
renderTitle
.
element
.
innerHTML
).
toEqual
(
title
);
expect
(
renderLogo
.
attributes
()).
toHaveProperty
(
'src'
,
logoSrc
);
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment