feat(layout): n-layout-sider & n-layout-footer & n-layout-header add inverted prop.

This commit is contained in:
07akioni 2021-05-25 13:11:20 +08:00
parent 92e79591ad
commit c986b375a3
26 changed files with 331 additions and 119 deletions

View File

@ -19,6 +19,7 @@
- `n-tabs` add `tab-style` prop.
- `n-tabs` add `tabs-padding` prop.
- `n-tabs` add `default-value` prop.
- `n-layout-sider` & `n-layout-footer` & `n-layout-header` add `inverted` prop.
### Fixes

View File

@ -19,6 +19,7 @@
- `n-tabs` 新增 `tab-style` 属性
- `n-tabs` 新增 `tabs-padding` 属性
- `n-tabs` 新增 `default-value` 属性
- `n-layout-sider` & `n-layout-footer` & `n-layout-header` 新增 `inverted` 属性
### Fixes

View File

@ -166,6 +166,7 @@ const derived: ThemeCommonVars = {
bodyColor: base.neutralBody,
tagColor: neutral(base.alphaTag),
avatarColor: overlay(base.alphaAvatar),
invertedColor: base.neutralBase,
inputColor: overlay(base.alphaInput),
codeColor: overlay(base.alphaCode),

View File

@ -165,6 +165,7 @@ const derived = {
bodyColor: base.neutralBody,
tagColor: 'rgb(250, 250, 252)',
avatarColor: neutral(base.alphaAvatar),
invertedColor: 'rgb(0, 20, 40)',
inputColor: neutral(base.alphaInput),
codeColor: 'rgb(244, 244, 248)',

View File

@ -13,6 +13,7 @@ export const self = (vars: ThemeCommonVars) => {
dividerColor,
hoverColor,
popoverColor,
invertedColor,
borderRadius,
fontSizeSmall,
fontSizeMedium,
@ -53,7 +54,7 @@ export const self = (vars: ThemeCommonVars) => {
optionTextColorHoverInverted: '#FFF',
optionTextColorActiveInverted: '#FFF',
optionTextColorChildActiveInverted: '#FFF',
colorInverted: 'rgb(0, 20, 40)',
colorInverted: invertedColor,
dividerColorInverted: '#BBB',
suffixColorInverted: '#BBB',
prefixColorInverted: '#BBB',

View File

@ -38,6 +38,7 @@ scroll-to
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| bordered | `boolean` | `false` | |
| inverted | `boolean` | `false` | Whether to use inverted background. |
| position | `'static' \| 'absolute'` | `'static'` | `static` position will make it css position set to `static`. `absolute` position will make it css position set to `absolute` and `left`, `right`, `top` to `0`. `absolute` position is very useful when you want to make content scroll in a fixed container or make the whole page's layout in a fixed position. You may need to change the style of the component to make it display as you expect. |
### Layout Header Props
@ -45,6 +46,7 @@ scroll-to
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| bordered | `boolean` | `false` | |
| inverted | `boolean` | `false` | Whether to use inverted background. |
| position | `'static' \| 'absolute'` | `'static'` | `static` position will make it css position set to `static`. `absolute` position will make it css position set to `absolute` and `left`, `right`, `bottom` to `0`. `absolute` position is very useful when you want to make content scroll in a fixed container or make the whole page's layout in a fixed position. You may need to change the style of the component to ma ke as you expect. |
### Layout Sider Props
@ -57,6 +59,7 @@ scroll-to
| collapsed-width | `number` | `48` | |
| content-style | `string \| Object` | `undefined` | Style of scrollable content node. |
| default-collapsed | `boolean` | `false` | |
| inverted | `boolean` | `false` | Whether to use inverted background. |
| native-scrollbar | `boolean` | `true` | Whether to use native scrollbar on itself. If set to `false`, sider will use a naive-ui style scrollbar for content |
| position | `'static' \| 'absolute'` | `'static'` | `static` position will make it css position set to `static`. `absolute` position will make it css position set to `absolute` and `left`, `top`, `bottom` to `0`. `absolute` position is very useful when you want to make content scroll in a fixed container or make the whole page's layout in a fixed position. You may need to change the style of the component to make it as you expect. |
| show-content | `boolean` | `true` | If set to `false`, sider content will be invisible. |

View File

@ -18,6 +18,7 @@ absolute
scrollbar
collapse
trigger-button
inverted
show-sider-content
scroll-to
```
@ -38,6 +39,7 @@ scroll-to
| 名称 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| bordered | `boolean` | `false` | |
| inverted | `boolean` | `false` | 使用反转背景色 |
| position | `'static' \| 'absolute'` | `'static'` | `static` 模式将会把 CSS `position` 设为 `static` `absolute` 模式将会把 CSS `position` 设为 `absolute`,还将 `left`、`right`、`bottom` 设为 `0`。`absolute` 模式在你想将内容在一个固定容器或者将这个页面的布局设为固定位置的时候很有用。你可能需要修改一些 style 来确保它按照你预想的方式展示 |
### Layout Header Props
@ -45,6 +47,7 @@ scroll-to
| 名称 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| bordered | `boolean` | `false` | |
| inverted | `boolean` | `false` | 使用反转背景色 |
| position | `'static' \| 'absolute'` | `'static'` | `static` 模式将会把 CSS `position` 设为 `static` `absolute` 模式将会把 CSS `position` 设为 `absolute`,还将 `left`、`right`、`top` 设为 `0`。`absolute` 模式在你想将内容在一个固定容器或者将这个页面的布局设为固定位置的时候很有用。你可能需要修改一些 style 来确保它按照你预想的方式展示 |
### Layout Sider Props
@ -57,6 +60,7 @@ scroll-to
| collapsed-width | `number` | `48` | |
| content-style | `string \| Object` | `undefined` | 可滚动内容节点的样式 |
| default-collapsed | `boolean` | `false` | |
| inverted | `boolean` | `false` | 使用反转背景色 |
| native-scrollbar | `boolean` | `true` | 是否在自身使用原生滚动条。如果设定为 `false`, Sider 将会对内容使用 naive-ui 风格的滚动条 |
| position | `'static' \| 'absolute'` | `'static'` | `static` 模式将会把 CSS `position` 设为 `static` `absolute` 模式将会把 CSS `position` 设为 `absolute`,还将 `left`、`top`、`bottom` 设为 `0`。`absolute` 模式在你想将内容在一个固定容器或者将这个页面的布局设为固定位置的时候很有用。你可能需要修改一些 style 来确保它按照你预想的方式展示 |
| show-content | `boolean` | `true` | 如果设为 `false`Sider 的内容将会变透明 |

View File

@ -0,0 +1,138 @@
# 反转
使用 `inverted` 增加对比度,可以使用在 header、footer 和 sider 上,可以和 menu 搭配使用。
```html
<n-space vertical>
<n-space> <n-switch v-model:value="inverted" /> inverted </n-space>
<n-layout>
<n-layout-header :inverted="inverted" bordered>
Header Header Header
<n-menu mode="horizontal" :inverted="inverted" :options="menuOptions" />
</n-layout-header>
<n-layout has-sider>
<n-layout-sider
bordered
show-trigger
collapse-mode="width"
:collapsed-width="64"
:width="240"
:native-scrollbar="false"
:inverted="inverted"
style="max-height: 320px;"
>
<n-menu
:inverted="inverted"
:collapsed-width="64"
:collapsed-icon-size="22"
:options="menuOptions"
/>
</n-layout-sider>
<n-layout style="max-height: 320px;">
<span>内容</span>
</n-layout>
</n-layout>
<n-layout-footer :inverted="inverted" bordered>
Footer Footer Footer
</n-layout-footer>
</n-layout>
</n-space>
```
```js
import { h, defineComponent, ref } from 'vue'
import { NIcon } from 'naive-ui'
import {
BookOutline as BookIcon,
PersonOutline as PersonIcon,
WineOutline as WineIcon
} from '@vicons/ionicons5'
function renderIcon (icon) {
return () => h(NIcon, null, { default: () => h(icon) })
}
const menuOptions = [
{
label: '且听风吟',
key: 'hear-the-wind-sing',
icon: renderIcon(BookIcon)
},
{
label: '1973年的弹珠玩具',
key: 'pinball-1973',
icon: renderIcon(BookIcon),
disabled: true,
children: [
{
label: '鼠',
key: 'rat'
}
]
},
{
label: '寻羊冒险记',
key: 'a-wild-sheep-chase',
disabled: true,
icon: renderIcon(BookIcon)
},
{
label: '舞,舞,舞',
key: 'dance-dance-dance',
icon: renderIcon(BookIcon),
children: [
{
type: 'group',
label: '人物',
key: 'people',
children: [
{
label: '叙事者',
key: 'narrator',
icon: renderIcon(PersonIcon)
},
{
label: '羊男',
key: 'sheep-man',
icon: renderIcon(PersonIcon)
}
]
},
{
label: '饮品',
key: 'beverage',
icon: renderIcon(WineIcon),
children: [
{
label: '威士忌',
key: 'whisky'
}
]
},
{
label: '食物',
key: 'food',
children: [
{
label: '三明治',
key: 'sandwich'
}
]
},
{
label: '过去增多,未来减少',
key: 'the-past-increases-the-future-recedes'
}
]
}
]
export default defineComponent({
setup () {
return {
inverted: ref(false),
menuOptions
}
}
})
```

View File

@ -9,11 +9,9 @@ import type { ExtractPublicPropTypes } from '../../_utils'
const layoutFooterProps = {
...(useTheme.props as ThemeProps<LayoutTheme>),
inverted: Boolean,
position: positionProp,
bordered: {
type: Boolean,
default: false
}
bordered: Boolean
}
export type LayoutFooterProps = ExtractPublicPropTypes<typeof layoutFooterProps>
@ -36,13 +34,21 @@ export default defineComponent({
cssVars: computed(() => {
const {
common: { cubicBezierEaseInOut },
self: { footerBorderColor, footerColor }
self
} = themeRef.value
return {
'--bezier': cubicBezierEaseInOut,
'--color': footerColor,
'--border-color': footerBorderColor
const vars: any = {
'--bezier': cubicBezierEaseInOut
}
if (props.inverted) {
vars['--color'] = self.footerColorInverted
vars['--text-color'] = self.textColorInverted
vars['--border-color'] = self.footerBorderColorInverted
} else {
vars['--color'] = self.footerColor
vars['--text-color'] = self.textColor
vars['--border-color'] = self.footerBorderColor
}
return vars
})
}
},
@ -52,11 +58,9 @@ export default defineComponent({
<div
class={[
`${mergedClsPrefix}-layout-footer`,
{
[`${mergedClsPrefix}-layout-footer--${this.position}-positioned`]: this
.position,
[`${mergedClsPrefix}-layout-footer--bordered`]: this.bordered
}
this.position &&
`${mergedClsPrefix}-layout-footer--${this.position}-positioned`,
this.bordered && `${mergedClsPrefix}-layout-footer--bordered`
]}
style={this.cssVars as CSSProperties}
>

View File

@ -9,6 +9,7 @@ import { ExtractPublicPropTypes } from '../../_utils'
const headerProps = {
position: positionProp,
inverted: Boolean,
bordered: {
type: Boolean,
default: false
@ -38,13 +39,21 @@ export default defineComponent({
cssVars: computed(() => {
const {
common: { cubicBezierEaseInOut },
self: { headerColor, headerBorderColor }
self
} = themeRef.value
return {
'--bezier': cubicBezierEaseInOut,
'--header-color': headerColor,
'--header-border-color': headerBorderColor
const vars: any = {
'--bezier': cubicBezierEaseInOut
}
if (props.inverted) {
vars['--color'] = self.headerColorInverted
vars['--text-color'] = self.textColorInverted
vars['--border-color'] = self.headerBorderColorInverted
} else {
vars['--color'] = self.headerColor
vars['--text-color'] = self.textColor
vars['--border-color'] = self.headerBorderColor
}
return vars
})
}
},

View File

@ -6,7 +6,8 @@ import {
ref,
CSSProperties,
toRef,
inject
inject,
provide
} from 'vue'
import { useConfig, useTheme } from '../../_mixins'
import type { ThemeProps } from '../../_mixins'
@ -19,16 +20,13 @@ import type { LayoutTheme } from '../styles'
import style from './styles/layout-sider.cssr'
import ToggleButton from './ToggleButton'
import ToggleBar from './ToggleBar'
import { positionProp } from './interface'
import { layoutSiderInjectionKey, positionProp } from './interface'
import { useMergedState } from 'vooks'
import { layoutInjectionKey } from './Layout'
const layoutSiderProps = {
position: positionProp,
bordered: {
type: Boolean,
default: false
},
bordered: Boolean,
collapsedWidth: {
type: Number,
default: 48
@ -49,10 +47,7 @@ const layoutSiderProps = {
type: Boolean as PropType<boolean | undefined>,
default: undefined
},
defaultCollapsed: {
type: Boolean,
default: false
},
defaultCollapsed: Boolean,
showContent: {
type: Boolean,
default: true
@ -69,6 +64,7 @@ const layoutSiderProps = {
type: Number,
default: 300
},
inverted: Boolean,
scrollbarProps: Object as PropType<
Partial<ScrollbarProps> & { style: CSSProperties }
>,
@ -174,6 +170,9 @@ export default defineComponent({
if (onCollapse) call(onCollapse)
}
}
provide(layoutSiderInjectionKey, {
collapsedRef: mergedCollapsedRef
})
const { mergedClsPrefixRef } = useConfig(props)
const themeRef = useTheme(
'Layout',
@ -197,22 +196,30 @@ export default defineComponent({
cssVars: computed(() => {
const {
common: { cubicBezierEaseInOut },
self: {
siderColor,
siderToggleButtonColor,
siderBorderColor,
siderToggleBarColor,
siderToggleBarColorHover
}
self
} = themeRef.value
return {
const {
siderToggleButtonColor,
siderToggleBarColor,
siderToggleBarColorHover
} = self
const vars: any = {
'--bezier': cubicBezierEaseInOut,
'--sider-color': siderColor,
'--sider-border-color': siderBorderColor,
'--sider-toggle-button-color': siderToggleButtonColor,
'--sider-toggle-bar-color': siderToggleBarColor,
'--sider-toggle-bar-color-hover': siderToggleBarColorHover
'--toggle-button-color': siderToggleButtonColor,
'--toggle-bar-color': siderToggleBarColor,
'--toggle-bar-color-hover': siderToggleBarColorHover
}
if (props.inverted) {
vars['--color'] = self.siderColorInverted
vars['--text-color'] = self.textColorInverted
vars['--border-color'] = self.siderBorderColorInverted
vars.__invertScrollbar = self.__invertScrollbar
} else {
vars['--color'] = self.siderColor
vars['--text-color'] = self.textColor
vars['--border-color'] = self.siderBorderColor
}
return vars
})
}
},
@ -224,15 +231,12 @@ export default defineComponent({
class={[
`${mergedClsPrefix}-layout-sider`,
`${mergedClsPrefix}-layout-sider--${this.position}-positioned`,
{
[`${mergedClsPrefix}-layout-sider--bordered`]: this.bordered,
[`${mergedClsPrefix}-layout-sider--collapsed`]: this
.mergedCollapsed,
[`${mergedClsPrefix}-layout-sider--show-content`]: this.showContent
}
this.bordered && `${mergedClsPrefix}-layout-sider--bordered`,
this.mergedCollapsed && `${mergedClsPrefix}-layout-sider--collapsed`,
this.showContent && `${mergedClsPrefix}-layout-sider--show-content`
]}
style={[
this.cssVars as any,
this.cssVars,
{
maxWidth: this.styleMaxWidth,
width: formatLength(this.width)
@ -248,6 +252,16 @@ export default defineComponent({
contentStyle={this.contentStyle}
theme={this.mergedTheme.peers.Scrollbar}
themeOverrides={this.mergedTheme.peerOverrides.Scrollbar}
// here is a hack, since in light theme the scrollbar color is dark,
// we need to invert it in light color...
builtinThemeOverrides={
this.inverted && this.cssVars.__invertScrollbar === 'true'
? {
colorHover: 'rgba(255, 255, 255, .4)',
color: 'rgba(255, 255, 255, .3)'
}
: undefined
}
>
{this.$slots}
</NScrollbar>
@ -259,9 +273,6 @@ export default defineComponent({
{this.$slots}
</div>
)}
{this.bordered ? (
<div class={`${mergedClsPrefix}-layout-sider__border`} />
) : null}
{this.showTrigger ? (
this.showTrigger === 'arrow-circle' ? (
<ToggleButton

View File

@ -1,4 +1,8 @@
import { PropType } from 'vue'
import { InjectionKey, PropType, Ref } from 'vue'
export const layoutSiderInjectionKey: InjectionKey<{
collapsedRef: Ref<boolean>
}> = Symbol('layoutSiderInjection')
export const positionProp = {
type: String as PropType<'static' | 'absolute'>,

View File

@ -4,10 +4,13 @@ import { cB, cM } from '../../../_utils/cssr'
// --bezier
// --color
// --border-color
// --text-color
export default cB('layout-footer', `
transition:
color .3s var(--bezier),
background-color .3s var(--bezier),
border-color .3s var(--bezier);
color: var(--text-color);
background-color: var(--color);
box-sizing: border-box;
`, [

View File

@ -2,16 +2,19 @@ import { cB, cM } from '../../../_utils/cssr'
// vars:
// --bezier
// --header-color
// --header-border-color
// --text-color
// --color
// --border-color
export default cB('layout-header', `
transition:
color .3s var(--bezier),
background-color .3s var(--bezier),
box-shadow .3s var(--bezier),
border-color .3s var(--bezier);
box-sizing: border-box;
width: 100%;
background-color: var(--header-color);
background-color: var(--color);
color: var(--text-color);
`, [
cM('absolute-positioned', `
position: absolute;
@ -20,6 +23,6 @@ export default cB('layout-header', `
top: 0;
`),
cM('bordered', `
border-bottom: solid 1px var(--header-border-color);
border-bottom: solid 1px var(--border-color);
`)
])

View File

@ -2,22 +2,26 @@ import { c, cB, cE, cM } from '../../../_utils/cssr'
// vars:
// --bezier
// --sider-color
// --sider-border-color
// --sider-toggle-button-color
// --sider-toggle-bar-color
// --sider-toggle-bar-color-hover
// --color
// --text-color
// --border-color
// --toggle-button-color
// --toggle-bar-color
// --toggle-bar-color-hover
export default cB('layout-sider', `
flex-shrink: 0;
box-sizing: border-box;
position: relative;
z-index: 1;
color: var(--text-color);
transition:
color .3s var(--bezier),
border-color .3s var(--bezier),
min-width .3s var(--bezier),
max-width .3s var(--bezier),
transform .3s var(--bezier),
background-color .3s var(--bezier);
background-color: var(--sider-color);
background-color: var(--color);
display: flex;
justify-content: flex-end;
`, [
@ -32,7 +36,7 @@ export default cB('layout-sider', `
top: 50%;
right: 0;
transform: translateX(50%) translateY(-50%);
fill: var(--sider-toggle-button-color);
fill: var(--toggle-button-color);
`),
cB('layout-toggle-bar', `
cursor: pointer;
@ -75,11 +79,11 @@ export default cB('layout-sider', `
])
]),
cE('top, bottom', {
backgroundColor: 'var(--sider-toggle-bar-color)'
backgroundColor: 'var(--toggle-bar-color)'
}),
c('&:hover', [
cE('top, bottom', {
backgroundColor: 'var(--sider-toggle-bar-color-hover)'
backgroundColor: 'var(--toggle-bar-color-hover)'
})
])
]),
@ -92,6 +96,7 @@ export default cB('layout-sider', `
transition: background-color .3s var(--bezier);
`),
cE('content', `
flex-grow: 1;
flex-shrink: 0;
box-sizing: border-box;
height: 100%;
@ -115,9 +120,7 @@ export default cB('layout-sider', `
top: 0;
bottom: 0;
`),
cM('bordered', [
cE('border', {
backgroundColor: 'var(--sider-border-color)'
})
])
cM('bordered', `
border-right: 1px solid var(--border-color);
`)
])

View File

@ -1,7 +1,7 @@
import { commonDark } from '../../_styles/common'
import { scrollbarDark } from '../../scrollbar/styles'
import type { LayoutTheme } from './light'
import { self } from './light'
import { composite } from 'seemly'
const layoutDark: LayoutTheme = {
name: 'Layout',
@ -10,11 +10,35 @@ const layoutDark: LayoutTheme = {
Scrollbar: scrollbarDark
},
self (vars) {
const commonSelf = self(vars)
const { cardColor } = vars
commonSelf.siderToggleButtonColor = 'rgba(255, 255, 255, .3)'
commonSelf.footerColor = cardColor
return commonSelf
const {
textColor2,
bodyColor,
cardColor,
dividerColor,
scrollbarColor,
scrollbarColorHover
} = vars
return {
textColor: textColor2,
textColorInverted: textColor2,
color: bodyColor,
headerColor: cardColor,
headerColorInverted: cardColor,
footerColor: cardColor,
footerColorInverted: cardColor,
headerBorderColor: dividerColor,
headerBorderColorInverted: dividerColor,
footerBorderColor: dividerColor,
footerBorderColorInverted: dividerColor,
siderBorderColor: dividerColor,
siderBorderColorInverted: dividerColor,
siderColor: cardColor,
siderColorInverted: cardColor,
siderToggleButtonColor: 'rgba(255, 255, 255, .3)',
siderToggleBarColor: composite(bodyColor, scrollbarColor),
siderToggleBarColorHover: composite(bodyColor, scrollbarColorHover),
__invertScrollbar: 'false'
}
}
}

View File

@ -12,20 +12,29 @@ export const self = (vars: ThemeCommonVars) => {
dividerColor,
actionColor,
scrollbarColor,
scrollbarColorHover
scrollbarColorHover,
invertedColor
} = vars
return {
textColor: textColor2,
textColorInverted: '#FFF',
color: bodyColor,
headerColor: cardColor,
headerColorInverted: invertedColor,
footerColor: actionColor,
footerColorInverted: invertedColor,
headerBorderColor: dividerColor,
headerBorderColorInverted: invertedColor,
footerBorderColor: dividerColor,
footerBorderColorInverted: invertedColor,
siderBorderColor: dividerColor,
siderBorderColorInverted: invertedColor,
siderColor: cardColor,
siderColorInverted: invertedColor,
siderToggleButtonColor: 'rgba(0, 0, 0, .15)',
siderToggleBarColor: composite(bodyColor, scrollbarColor),
siderToggleBarColorHover: composite(bodyColor, scrollbarColorHover)
siderToggleBarColorHover: composite(bodyColor, scrollbarColorHover),
__invertScrollbar: 'true'
}
}

View File

@ -4,24 +4,18 @@ Set `inverted` to add contrast.
```html
<n-space vertical>
<n-space>
<n-switch v-model:value="collapsed" /> collapsed
<n-switch v-model:value="inverted" /> inverted
</n-space>
<n-space> <n-switch v-model:value="inverted" /> inverted </n-space>
<n-layout has-sider>
<n-layout-sider
bordered
collapse-mode="width"
:collapsed-width="64"
:width="240"
:collapsed="collapsed"
show-trigger
@collapse="collapsed = true"
@expand="collapsed = false"
:inverted="inverted"
>
<n-menu
:inverted="inverted"
:collapsed="collapsed"
:collapsed-width="64"
:collapsed-icon-size="22"
:options="menuOptions"
@ -126,8 +120,6 @@ const menuOptions = [
export default defineComponent({
setup () {
return {
activeKey: ref(null),
collapsed: ref(false),
inverted: ref(false),
menuOptions
}

View File

@ -4,28 +4,21 @@
```html
<n-space vertical>
<n-space>
<n-switch v-model:value="collapsed" /> collapsed
<n-switch v-model:value="inverted" /> inverted
</n-space>
<n-space> <n-switch v-model:value="inverted" /> inverted </n-space>
<n-layout has-sider>
<n-layout-sider
bordered
collapse-mode="width"
:collapsed-width="64"
:width="240"
:collapsed="collapsed"
show-trigger
@collapse="collapsed = true"
@expand="collapsed = false"
:inverted="inverted"
>
<n-menu
:inverted="inverted"
:collapsed="collapsed"
:collapsed-width="64"
:collapsed-icon-size="22"
:options="menuOptions"
v-model:value="activeKey"
/>
</n-layout-sider>
<n-layout>
@ -126,8 +119,6 @@ const menuOptions = [
export default defineComponent({
setup () {
return {
activeKey: ref(null),
collapsed: ref(false),
inverted: ref(false),
menuOptions
}

View File

@ -8,7 +8,8 @@ import {
PropType,
ExtractPropTypes,
InjectionKey,
CSSProperties
CSSProperties,
inject
} from 'vue'
import { createTreeMate, Key } from 'treemate'
import { useCompitable, useMergedState } from 'vooks'
@ -28,6 +29,7 @@ import {
OnUpdateValueImpl,
OnUpdateKeysImpl
} from './interface'
import { layoutSiderInjectionKey } from '../../layout/src/interface'
const menuProps = {
...(useTheme.props as ThemeProps<MenuTheme>),
@ -46,8 +48,8 @@ const menuProps = {
default: undefined
},
collapsed: {
type: Boolean,
default: false
type: Boolean as PropType<boolean | undefined>,
default: undefined
},
collapsedWidth: {
type: Number,
@ -170,6 +172,12 @@ export default defineComponent({
mergedClsPrefixRef
)
const layoutSider = inject(layoutSiderInjectionKey, null)
const mergedCollapsedRef = computed(() => {
return props.collapsed ?? layoutSider?.collapsedRef.value ?? false
})
const treeMateRef = computed(() =>
createTreeMate<MenuOption, MenuGroupOption>(
props.items || props.options,
@ -205,6 +213,7 @@ export default defineComponent({
})
provide(menuInjectionKey, {
props,
mergedCollapsedRef,
mergedThemeRef: themeRef,
mergedValueRef,
mergedExpandedKeysRef,
@ -265,6 +274,7 @@ export default defineComponent({
activePath: activePathRef,
tmNodes: tmNodesRef,
mergedTheme: themeRef,
mergedCollapsed: mergedCollapsedRef,
cssVars: computed(() => {
const { inverted } = props
const {
@ -331,7 +341,7 @@ export default defineComponent({
class={[
`${mergedClsPrefix}-menu`,
`${mergedClsPrefix}-menu--${this.mode}`,
this.collapsed && `${mergedClsPrefix}-menu--collapsed`
this.mergedCollapsed && `${mergedClsPrefix}-menu--collapsed`
]}
style={this.cssVars as CSSProperties}
>

View File

@ -48,7 +48,7 @@ export default defineComponent({
setup (props) {
const MenuChild = useMenuChild(props)
const { NMenu, NSubmenu } = MenuChild
const { props: menuProps } = NMenu
const { props: menuProps, mergedCollapsedRef } = NMenu
const mergedDisabledRef = computed(() => {
const { disabled } = props
if (NSubmenu?.mergedDisabledRef.value) return true
@ -67,7 +67,7 @@ export default defineComponent({
}
function handleClick (): void {
if (!mergedDisabledRef.value) {
if (!menuProps.collapsed) {
if (!mergedCollapsedRef.value) {
NMenu.toggleExpand(props.internalKey)
}
doClick()
@ -94,7 +94,7 @@ export default defineComponent({
}),
collapsed: computed(() => {
if (menuProps.mode === 'horizontal') return false
if (menuProps.collapsed) {
if (mergedCollapsedRef.value) {
return true
}
return !NMenu.mergedExpandedKeysRef.value.includes(props.internalKey)
@ -102,7 +102,7 @@ export default defineComponent({
dropdownEnabled: computed(() => {
return (
!mergedDisabledRef.value &&
(menuProps.mode === 'horizontal' || menuProps.collapsed)
(menuProps.mode === 'horizontal' || mergedCollapsedRef.value)
)
}),
handlePopoverShowChange,

View File

@ -29,13 +29,12 @@ export default cB('menu', `
color: var(--item-text-color);
overflow: hidden;
transition: background-color .3s var(--bezier);
width: 100%;
box-sizing: border-box;
font-size: var(--font-size);
padding-bottom: 6px;
`, [
cM('horizontal', {
display: 'flex',
display: 'inline-flex',
paddingBottom: 0
}, [
cB('submenu', {

View File

@ -13,7 +13,6 @@ const ICON_MARGIN_RIGHT = 8
export interface MenuInjection {
props: {
mode: 'vertical' | 'horizontal'
collapsed: boolean
iconSize: number
collapsedIconSize: number | undefined
indent: number
@ -21,6 +20,7 @@ export interface MenuInjection {
collapsedWidth: number
disabled: boolean
}
mergedCollapsedRef: Ref<boolean>
invertedRef: Ref<boolean>
isHorizontalRef: Ref<boolean>
mergedClsPrefixRef: Ref<string>
@ -56,7 +56,7 @@ export interface UseMenuChild {
export function useMenuChild (props: UseMenuChildProps): UseMenuChild {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const NMenu = inject(menuInjectionKey)!
const { props: menuProps } = NMenu
const { props: menuProps, mergedCollapsedRef } = NMenu
const NSubmenu = inject(submenuInjectionKey, null)
const NMenuOptionGroup = inject<MenuOptionGroupInjection | null>(
menuItemGroupInjectionKey,
@ -79,7 +79,7 @@ export function useMenuChild (props: UseMenuChildProps): UseMenuChild {
)
})
const activeIconSizeRef = computed(() => {
if (!horizontalRef.value && props.root && menuProps.collapsed) {
if (!horizontalRef.value && props.root && mergedCollapsedRef.value) {
return menuProps.collapsedIconSize ?? menuProps.iconSize
} else {
return menuProps.iconSize
@ -91,7 +91,7 @@ export function useMenuChild (props: UseMenuChildProps): UseMenuChild {
const { root, isGroup } = props
const mergedRootIndent = rootIndent === undefined ? indent : rootIndent
if (root) {
if (menuProps.collapsed) {
if (mergedCollapsedRef.value) {
return collapsedWidth / 2 - maxIconSizeRef.value / 2
}
return mergedRootIndent
@ -113,7 +113,7 @@ export function useMenuChild (props: UseMenuChildProps): UseMenuChild {
const { root } = props
if (horizontalRef.value) return ICON_MARGIN_RIGHT
if (!root) return ICON_MARGIN_RIGHT
if (!menuProps.collapsed) return ICON_MARGIN_RIGHT
if (!mergedCollapsedRef.value) return ICON_MARGIN_RIGHT
const mergedRootIndent = rootIndent === undefined ? indent : rootIndent
return (
mergedRootIndent +

View File

@ -56,7 +56,7 @@ export const self = (vars: ThemeCommonVars) => {
arrowColorHover: primaryColorHover,
arrowColorChildActive: primaryColor,
arrowColorActive: primaryColor,
colorInverted: 'rgb(0, 20, 40)',
colorInverted: '#0000',
itemColorActiveInverted: primaryColor,
itemColorActiveCollapsedInverted: primaryColor,
borderColorHorizontal: '#0000',

View File

@ -19,7 +19,7 @@ display-directive
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| addable | `boolean \| { disabled?: boolean }` | `false` | Whether to show add button. Only works when type is `'card'`. |
| default-value | `string \| number` | `name` of the first tab | |
| default-value | `string \| number` | name prop of the first tab | |
| closable | `boolean` | `false` | Whether to allow tab to close, Only works when type is `'card'`. |
| justify-content | `'space-between' \| 'space-around' \| 'space-evenly'` | `undefined` | |
| label-size | `'small' \| 'medium' \| 'large' \| 'huge'` | `'medium'` | Size of tabs. Only works when type is `'line'`. |

View File

@ -21,7 +21,7 @@ line-debug
| --- | --- | --- | --- |
| addable | `boolean \| { disabled?: boolean }` | `false` | 是否展示增加按钮,只在 type 为 `'card'` 时生效 |
| closable | `boolean` | `false` | 是否允许 tab 关闭,只在 type 为 `'card'` 时生效 |
| default-value | `string \| number` | 第一个标签页的 `name` | |
| default-value | `string \| number` | 第一个标签页的 name 属性 | |
| justify-content | `'space-between' \| 'space-around' \| 'space-evenly'` | `undefined` | |
| label-size | `'small' \| 'medium' \| 'large' \| 'huge'` | `'medium'` | 标签的尺寸,只对线型的 Tabs 生效 |
| show-divider | `boolean` | `false` | 是否展示分割线,只在 type 为 `'line'` 时生效 |