refactor(layout): ts

This commit is contained in:
07akioni 2021-01-23 16:45:01 +08:00
parent 62242cf442
commit ddda5c84be
24 changed files with 613 additions and 589 deletions

View File

@ -1,6 +0,0 @@
/* istanbul ignore file */
export { default as NLayout } from './src/Layout.vue'
export { default as NLayoutContent } from './src/Layout.vue'
export { default as NLayoutHeader } from './src/LayoutHeader.vue'
export { default as NLayoutFooter } from './src/LayoutFooter.vue'
export { default as NLayoutSider } from './src/LayoutSider.vue'

6
src/layout/index.ts Normal file
View File

@ -0,0 +1,6 @@
/* istanbul ignore file */
export { default as NLayout } from './src/Layout'
export { default as NLayoutContent } from './src/Layout'
export { default as NLayoutHeader } from './src/LayoutHeader'
export { default as NLayoutFooter } from './src/LayoutFooter'
export { default as NLayoutSider } from './src/LayoutSider'

134
src/layout/src/Layout.tsx Normal file
View File

@ -0,0 +1,134 @@
import {
h,
defineComponent,
computed,
PropType,
reactive,
inject,
provide,
ref
} from 'vue'
import { NScrollbar } from '../../scrollbar'
import type { ScrollbarProps, ScrollbarRef } from '../../scrollbar'
import { useTheme } from '../../_mixins'
import type { ThemeProps } from '../../_mixins'
import { layoutLight } from '../styles'
import type { LayoutTheme } from '../styles'
import style from './styles/layout.cssr'
import { positionProp } from './interface'
export interface LayoutInjection {
hasSider: boolean
siderWidth: number | null
siderCollapsedWidth: number | null
siderCollapseMode: 'width' | 'transform' | null
siderPosition: 'absolute' | 'static' | null
siderCollapsed: boolean | null
}
export default defineComponent({
name: 'Layout',
alias: ['LayoutContent'],
props: {
...(useTheme.props as ThemeProps<LayoutTheme>),
position: positionProp,
nativeScrollbar: {
type: Boolean,
default: true
},
scrollbarProps: Object as PropType<Partial<ScrollbarProps>>
},
setup (props) {
const selfRef = ref<HTMLElement | null>(null)
const scrollbarRef = ref<ScrollbarRef | null>(null)
const themeRef = useTheme('Layout', 'Layout', style, layoutLight, props)
const state = reactive<LayoutInjection>({
hasSider: false,
siderWidth: null,
siderCollapsedWidth: null,
siderCollapseMode: null,
siderPosition: null,
siderCollapsed: null
})
const NLayout = inject<LayoutInjection | null>('NLayout', null)
const styleMarginLeftRef = computed(() => {
if (NLayout?.hasSider) {
if (
NLayout.siderPosition === 'absolute' &&
props.position === 'absolute'
) {
if (NLayout.siderCollapsed) {
return `${NLayout.siderCollapsedWidth as number}px`
} else {
return `${NLayout.siderWidth as number}px`
}
}
}
return ''
})
const mergedLayoutStyleRef = computed(() => {
return {
marginLeft: styleMarginLeftRef.value
}
})
function scrollTo (options: ScrollToOptions): void
function scrollTo (x: number, y: number): void
function scrollTo (options: ScrollToOptions | number, y?: number): void {
if (scrollbarRef.value) {
scrollbarRef.value.scrollTo(options as any, y as any)
} else if (selfRef.value) {
selfRef.value.scrollTo(options as any, y as any)
}
}
provide<LayoutInjection>('NLayout', state)
return {
selfRef,
scrollbarRef,
state,
mergedLayoutStyle: mergedLayoutStyleRef,
scrollTo,
mergedTheme: themeRef,
cssVars: computed(() => {
const {
common: { cubicBezierEaseInOut },
self: { color, textColor }
} = themeRef.value
return {
'--bezier': cubicBezierEaseInOut,
'--color': color,
'--text-color': textColor
}
})
}
},
render () {
return (
<div
ref="selfRef"
class={[
'n-layout',
`n-layout--${this.position}-positioned`,
this.state.siderCollapseMode &&
`n-layout--${this.state.siderCollapseMode}-collapse-mode`,
{
'n-layout--has-sider': this.state.hasSider
}
]}
style={[this.mergedLayoutStyle, this.cssVars] as any}
>
{!this.nativeScrollbar ? (
<NScrollbar
{...this.scrollbarProps}
ref="scrollbarRef"
unstableTheme={this.mergedTheme.peers.Scrollbar}
unstableThemeOverrides={this.mergedTheme.overrides.Scrollbar}
>
{this.$slots}
</NScrollbar>
) : (
this.$slots
)}
</div>
)
}
})

View File

@ -1,134 +0,0 @@
<template>
<div
class="n-layout"
:class="{
[`n-layout--${position}-positioned`]: true,
'n-layout--has-sider': hasSider,
[`n-layout--${siderCollapseMode}-collapse-mode`]: siderCollapseMode
}"
:style="mergedLayoutStyle"
>
<n-scrollbar
v-if="!nativeScrollbar"
ref="scrollbar"
:unstable-theme="mergedTheme.peers.Scrollbar"
:unstable-theme-overrides="mergedTheme.overrides.Scrollbar"
v-bind="scrollbarProps"
>
<slot />
</n-scrollbar>
<slot v-else />
</div>
</template>
<script>
import { nextTick, defineComponent, computed } from 'vue'
import { NScrollbar } from '../../scrollbar'
import { useTheme } from '../../_mixins'
import { layoutLight } from '../styles'
import layoutModeMixin from './layoutModeMixin'
import style from './styles/layout.cssr.js'
export default defineComponent({
name: 'Layout',
alias: ['LayoutContent'],
components: {
NScrollbar
},
mixins: [layoutModeMixin],
provide () {
return {
NLayout: this
}
},
props: {
...useTheme.props,
nativeScrollbar: {
type: Boolean,
default: true
},
scrollbarProps: {
type: Object,
default: undefined
}
},
setup (props) {
const themeRef = useTheme('Layout', 'Layout', style, layoutLight, props)
return {
mergedTheme: themeRef,
cssVars: computed(() => {
const {
common: { cubicBezierEaseInOut },
self: { color, textColor }
} = themeRef.value
return {
'--bezier': cubicBezierEaseInOut,
'--color': color,
'--text-color': textColor
}
})
}
},
data () {
return {
hasSider: false,
siderWidth: null,
collapsedSiderWidth: null,
siderCollapseMode: null,
siderPosition: null,
siderCollapsed: null,
childLayoutTransitionDisabled: false
}
},
computed: {
styleMarginLeft () {
const { NLayout } = this
if (NLayout && NLayout.hasSider) {
if (
NLayout.siderPosition === 'absolute' &&
this.position === 'absolute'
) {
if (NLayout.siderCollapsed) {
return `${NLayout.collapsedSiderWidth}px`
} else {
return `${NLayout.siderWidth}px`
}
}
}
return null
},
mergedLayoutStyle () {
return Object.assign(
{
marginLeft: this.styleMarginLeft,
transition: this.transitionDisabled ? 'none' : null
},
this.cssVars
)
},
transitionDisabled () {
const { NLayout } = this
if (NLayout && NLayout.childLayoutTransitionDisabled) {
return true
} else {
return false
}
}
},
methods: {
scrollTo (...args) {
if (this.$refs.scrollbar) {
this.$refs.scrollbar.scrollTo(...args)
} else {
this.$el.scrollTo(...args)
}
},
blockChildLayoutTransitionOneTick () {
this.childLayoutTransitionDisabled = true
nextTick(() => {
this.childLayoutTransitionDisabled = false
})
}
}
})
</script>

View File

@ -0,0 +1,56 @@
import { h, computed, defineComponent, renderSlot, CSSProperties } from 'vue'
import { useTheme } from '../../_mixins'
import type { ThemeProps } from '../../_mixins'
import { layoutLight } from '../styles'
import type { LayoutTheme } from '../styles'
import { positionProp } from './interface'
import style from './styles/layout-footer.cssr'
export default defineComponent({
name: 'LayoutFooter',
props: {
...(useTheme.props as ThemeProps<LayoutTheme>),
position: positionProp,
bordered: {
type: Boolean,
default: false
}
},
setup (props) {
const themeRef = useTheme(
'Layout',
'LayoutFooter',
style,
layoutLight,
props
)
return {
cssVars: computed(() => {
const {
common: { cubicBezierEaseInOut },
self: { footerBorderColor }
} = themeRef.value
return {
'--bezier': cubicBezierEaseInOut,
'--footer-border-color': footerBorderColor
}
})
}
},
render () {
return (
<div
class={[
'n-layout-footer',
{
[`n-layout-footer--${this.position}-positioned`]: this.position,
'n-layout-footer--bordered': this.bordered
}
]}
style={this.cssVars as CSSProperties}
>
{renderSlot(this.$slots, 'default')}
</div>
)
}
})

View File

@ -1,53 +0,0 @@
<template>
<div
class="n-layout-footer"
:class="{
[`n-layout-footer--${position}-positioned`]: position,
[`n-layout-footer--bordered`]: bordered
}"
:style="cssVars"
>
<slot />
</div>
</template>
<script>
import { computed, defineComponent } from 'vue'
import layoutModeMixin from './layoutModeMixin'
import { useTheme } from '../../_mixins'
import { layoutLight } from '../styles'
import style from './styles/layout-footer.cssr.js'
export default defineComponent({
name: 'LayoutFooter',
mixins: [layoutModeMixin],
props: {
...useTheme.props,
bordered: {
type: Boolean,
default: false
}
},
setup (props) {
const themeRef = useTheme(
'Layout',
'LayoutFooter',
style,
layoutLight,
props
)
return {
cssVars: computed(() => {
const {
common: { cubicBezierEaseInOut },
self: { footerBorderColor }
} = themeRef.value
return {
'--bezier': cubicBezierEaseInOut,
'--footer-border-color': footerBorderColor
}
})
}
}
})
</script>

View File

@ -1,28 +1,16 @@
<template>
<div
class="n-layout-header"
:class="{
[`n-layout-header--${position}-positioned`]: position,
[`n-layout-header--bordered`]: bordered
}"
:style="cssVars"
>
<slot />
</div>
</template>
<script>
import { defineComponent, computed } from 'vue'
import { h, defineComponent, computed, CSSProperties } from 'vue'
import { useTheme } from '../../_mixins'
import layoutModeMixin from './layoutModeMixin'
import type { ThemeProps } from '../../_mixins'
import { layoutLight } from '../styles'
import style from './styles/layout-header.cssr.js'
import type { LayoutTheme } from '../styles'
import { positionProp } from './interface'
import style from './styles/layout-header.cssr'
export default defineComponent({
name: 'LayoutHeader',
mixins: [layoutModeMixin],
props: {
...useTheme.props,
...(useTheme.props as ThemeProps<LayoutTheme>),
position: positionProp,
bordered: {
type: Boolean,
default: false
@ -49,6 +37,21 @@ export default defineComponent({
}
})
}
},
render () {
return (
<div
class={[
'n-layout-header',
this.position && `n-layout-header--${this.position}-positioned`,
{
'n-layout-header--bordered': this.bordered
}
]}
style={this.cssVars as CSSProperties}
>
{this.$slots}
</div>
)
}
})
</script>

View File

@ -0,0 +1,296 @@
import {
h,
defineComponent,
computed,
nextTick,
PropType,
ref,
watch,
CSSProperties,
toRef,
inject,
onBeforeUnmount
} from 'vue'
import { useTheme } from '../../_mixins'
import type { ThemeProps } from '../../_mixins'
import type { MaybeArray } from '../../_utils'
import { call } from '../../_utils'
import { NScrollbar } from '../../scrollbar'
import type { ScrollbarProps, ScrollbarRef } from '../../scrollbar'
import { layoutLight } from '../styles'
import type { LayoutTheme } from '../styles'
import style from './styles/layout-sider.cssr'
import type { LayoutInjection } from './Layout'
import ToggleButton from './ToggleButton'
import ToggleBar from './ToggleBar'
import { positionProp } from './interface'
export default defineComponent({
name: 'LayoutSider',
props: {
...(useTheme.props as ThemeProps<LayoutTheme>),
position: positionProp,
bordered: {
type: Boolean,
default: false
},
collapsedWidth: {
type: Number,
default: 48
},
width: {
type: Number,
default: 272
},
collapseMode: {
type: String as PropType<'width' | 'transform'>,
default: 'transform'
},
collapsed: {
type: Boolean,
default: false
},
showContent: {
type: Boolean,
default: true
},
showTrigger: {
type: [Boolean, String],
default: false
},
nativeScrollbar: {
type: Boolean,
default: true
},
duration: {
type: Number,
default: 300
},
scrollbarProps: Object as PropType<Partial<ScrollbarProps>>,
triggerStyle: Object as PropType<CSSProperties>,
// eslint-disable-next-line vue/prop-name-casing
'onUpdate:collapsed': Function as PropType<
MaybeArray<(value: boolean) => void>
>,
// deprecated
onExpand: Function as PropType<MaybeArray<() => void>>,
onCollapse: Function as PropType<MaybeArray<() => void>>
},
setup (props) {
const selfRef = ref<HTMLElement | null>(null)
const scrollbarRef = ref<ScrollbarRef | null>(null)
let collapseTimerId: number | null = null
const styleWidthRef = ref<string | null>(null)
const styleMaxWidthRef = ref<string | null>(null)
const NLayout = inject<LayoutInjection | null>('NLayout', null)
const styleTransformRef = computed(() => {
if (props.collapseMode === 'transform') {
if (!props.collapsed) return 'translateX(0)'
else return `translateX(-${props.width - props.collapsedWidth}px)`
}
return ''
})
function scrollTo (options: ScrollToOptions): void
function scrollTo (x: number, y: number): void
function scrollTo (options: ScrollToOptions | number, y?: number): void {
if (scrollbarRef.value) {
scrollbarRef.value.scrollTo(options as any, y as any)
} else if (selfRef.value) {
if (y === undefined) {
selfRef.value.scrollTo(options as any)
} else {
selfRef.value.scrollTo(options as any, y as any)
}
}
}
function handleTriggerClick (): void {
const {
'onUpdate:collapsed': onUpdateCollapsed,
collapsed,
// deprecated
onExpand,
onCollapse
} = props
if (onUpdateCollapsed) {
call(onUpdateCollapsed, !collapsed)
}
if (collapsed) {
if (onExpand) call(onExpand)
} else {
if (onCollapse) call(onCollapse)
}
}
watch(toRef(props, 'width'), (value) => {
if (NLayout) {
NLayout.siderWidth = value
}
})
watch(toRef(props, 'collapsedWidth'), (value) => {
if (NLayout) {
NLayout.siderCollapsedWidth = value
}
})
watch(toRef(props, 'collapseMode'), (value) => {
if (NLayout) {
NLayout.siderCollapseMode = value
}
})
watch(toRef(props, 'position'), (value) => {
if (NLayout) {
NLayout.siderPosition = value
}
})
watch(toRef(props, 'collapsed'), (value) => {
if (props.collapseMode === 'width') {
if (collapseTimerId) {
window.clearTimeout(collapseTimerId)
}
if (value) {
styleMaxWidthRef.value = `${props.width}px`
void nextTick(() => {
void selfRef.value?.offsetWidth
styleMaxWidthRef.value = `${props.collapsedWidth}px`
})
collapseTimerId = window.setTimeout(() => {
styleWidthRef.value = `${props.collapsedWidth}px`
styleMaxWidthRef.value = null
}, props.duration)
} else {
styleMaxWidthRef.value = `${props.collapsedWidth}px`
styleWidthRef.value = `${props.width}px`
void nextTick(() => {
void selfRef.value?.offsetWidth
styleMaxWidthRef.value = `${props.width}px`
})
collapseTimerId = window.setTimeout(() => {
styleMaxWidthRef.value = null
}, props.duration)
}
}
if (NLayout) {
NLayout.siderCollapsed = value
}
})
// onCreated, init
if (props.collapseMode === 'width') {
if (props.collapsed) {
styleWidthRef.value = `${props.collapsedWidth}px`
} else {
styleWidthRef.value = `${props.width}px`
}
} else {
styleWidthRef.value = `${props.width}px`
}
if (NLayout) {
NLayout.hasSider = true
NLayout.siderWidth = props.width
NLayout.siderCollapsedWidth = props.collapsedWidth
NLayout.siderCollapseMode = props.collapseMode
NLayout.siderPosition = props.position
NLayout.siderCollapsed = props.collapsed
}
onBeforeUnmount(() => {
if (NLayout) {
NLayout.hasSider = false
NLayout.siderWidth = null
NLayout.siderCollapsedWidth = null
NLayout.siderCollapseMode = null
NLayout.siderPosition = null
NLayout.siderCollapsed = null
}
})
const themeRef = useTheme(
'Layout',
'LayoutSider',
style,
layoutLight,
props
)
return {
selfRef,
scrollbarRef,
mergedTheme: themeRef,
styleTransform: styleTransformRef,
styleMaxWidth: styleMaxWidthRef,
styleWidth: styleWidthRef,
scrollTo,
handleTriggerClick,
cssVars: computed(() => {
const {
common: { cubicBezierEaseInOut },
self: {
siderColor,
siderToggleButtonColor,
siderBorderColor,
siderToggleBarColor,
siderToggleBarColorHover
}
} = themeRef.value
return {
'--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
}
})
}
},
render () {
return (
<aside
ref="selfRef"
class={[
'n-layout-sider',
this.position && [`n-layout-sider--${this.position}-positioned`],
{
'n-layout-sider--bordered': this.bordered,
'n-layout-sider--collapsed': this.collapsed,
'n-layout-sider--show-content': this.showContent
}
]}
style={
[
this.cssVars,
{
transform: this.styleTransform,
maxWidth: this.styleMaxWidth,
width: this.styleWidth
}
] as any
}
>
{!this.nativeScrollbar ? (
<NScrollbar
ref="scrollbarRef"
class="n-layout-sider__content"
{...this.scrollbarProps}
unstableTheme={this.mergedTheme.peers.Scrollbar}
unstableThemeOverrides={this.mergedTheme.overrides.Scrollbar}
>
{this.$slots}
</NScrollbar>
) : (
<div class="n-layout-sider__content">{this.$slots}</div>
)}
{this.bordered ? <div class="n-layout-sider__border" /> : null}
{this.showTrigger ? (
this.showTrigger === 'arrow-circle' ? (
<ToggleButton
style={this.triggerStyle}
onClick={this.handleTriggerClick}
/>
) : (
<ToggleBar
collapsed={this.collapsed}
style={this.triggerStyle}
onClick={this.handleTriggerClick}
/>
)
) : null}
</aside>
)
}
})

View File

@ -1,284 +0,0 @@
<template>
<aside
class="n-layout-sider"
:class="{
[`n-layout-sider--${position}-positioned`]: position,
[`n-layout-sider--bordered`]: bordered,
[`n-layout-sider--collapsed`]: collapsed,
[`n-layout-sider--show-content`]: showContent
}"
:style="{
...cssVars,
transform: styleTransform,
maxWidth: styleMaxWidth,
width: styleWidth
}"
>
<n-scrollbar
v-if="!nativeScrollbar"
ref="scrollbar"
class="n-layout-sider__content"
:unstable-theme="NLayout.mergedTheme.peers.Scrollbar"
:unstable-theme-overrides="NLayout.mergedTheme.overrides.Scrollbar"
v-bind="scrollbarProps"
>
<slot />
</n-scrollbar>
<div v-else class="n-layout-sider__content">
<slot />
</div>
<div v-if="bordered" class="n-layout-sider__border" />
<template v-if="showTrigger">
<toggle-button
v-if="showTrigger === 'arrow-circle'"
:style="triggerStyle"
@click="handleTriggerClick"
/>
<toggle-bar
v-else
:collapsed="collapsed"
:style="triggerStyle"
@click="handleTriggerClick"
/>
</template>
</aside>
</template>
<script>
import { defineComponent, computed, nextTick } from 'vue'
import { useTheme } from '../../_mixins'
import { NScrollbar } from '../../scrollbar'
import { layoutLight } from '../styles'
import style from './styles/layout-sider.cssr.js'
import layoutModeMixin from './layoutModeMixin'
import ToggleButton from './ToggleButton.vue'
import ToggleBar from './ToggleBar.vue'
export default defineComponent({
name: 'LayoutSider',
components: {
ToggleButton,
ToggleBar,
NScrollbar
},
mixins: [layoutModeMixin],
props: {
...useTheme.props,
bordered: {
type: Boolean,
default: false
},
collapsedWidth: {
type: Number,
default: 48
},
width: {
type: Number,
default: 272
},
collapseMode: {
validator (value) {
return ['width', 'transform'].includes(value)
},
default: 'transform'
},
collapsed: {
type: Boolean,
default: false
},
showContent: {
type: Boolean,
default: true
},
showTrigger: {
type: [Boolean, String],
default: false
},
nativeScrollbar: {
type: Boolean,
default: true
},
duration: {
type: Number,
default: 300
},
scrollbarProps: {
type: Object,
default: undefined
},
triggerStyle: {
type: Object,
default: undefined
},
// eslint-disable-next-line vue/prop-name-casing
'onUpdate:collapsed': {
type: Function,
default: undefined
},
// deprecated
onExpand: {
type: Function,
default: undefined
},
onCollapse: {
type: Function,
default: undefined
}
},
setup (props) {
const themeRef = useTheme(
'Layout',
'LayoutSider',
style,
layoutLight,
props
)
return {
cssVars: computed(() => {
const {
common: { cubicBezierEaseInOut },
self: {
siderColor,
siderToggleButtonColor,
siderBorderColor,
siderToggleBarColor,
siderToggleBarColorHover
}
} = themeRef.value
return {
'--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
}
})
}
},
data () {
return {
collapseTimerId: null,
styleWidth: null,
styleMaxWidth: null
}
},
computed: {
styleTransform () {
if (this.collapseMode === 'transform') {
if (!this.collapsed) return 'translateX(0)'
else return `translateX(-${this.width - this.collapsedWidth}px)`
}
return null
}
},
watch: {
width (value) {
if (this.NLayout) {
this.NLayout.siderWidth = value
}
},
collapsedWidth (value) {
if (this.NLayout) {
this.NLayout.collapsedWidth = value
}
},
collapseMode (value) {
if (this.NLayout) {
this.NLayout.siderCollapseMode = value
}
},
position (value) {
if (this.NLayout) {
this.NLayout.siderPosition = value
}
},
collapsed (value) {
if (this.collapseMode === 'width') {
if (this.collapseTimerId) {
window.clearTimeout(this.collapseTimerId)
}
if (value) {
this.styleMaxWidth = `${this.width}px`
nextTick(() => {
this.$el.getBoundingClientRect()
this.styleMaxWidth = `${this.collapsedWidth}px`
})
this.collapseTimerId = window.setTimeout(() => {
this.styleWidth = `${this.collapsedWidth}px`
this.styleMaxWidth = null
}, this.duration)
} else {
this.styleMaxWidth = `${this.collapsedWidth}px`
this.styleWidth = `${this.width}px`
nextTick(() => {
this.$el.getBoundingClientRect()
this.styleMaxWidth = `${this.width}px`
})
this.collapseTimerId = window.setTimeout(() => {
this.styleMaxWidth = null
}, this.duration)
}
}
if (this.NLayout) {
this.NLayout.siderCollapsed = value
}
}
},
created () {
if (this.collapseMode === 'width') {
if (this.collapsed) {
this.styleWidth = `${this.collapsedWidth}px`
} else {
this.styleWidth = `${this.width}px`
}
} else {
this.styleWidth = `${this.width}px`
}
const NLayout = this.NLayout
if (NLayout) {
NLayout.hasSider = true
NLayout.siderWidth = this.width
NLayout.collapsedSiderWidth = this.collapsedWidth
NLayout.siderCollapseMode = this.collapseMode
NLayout.siderPosition = this.position
NLayout.siderCollapsed = this.collapsed
}
},
beforeUnmount () {
const NLayout = this.NLayout
if (NLayout) {
NLayout.hasSider = false
NLayout.siderWidth = null
NLayout.collapsedSiderWidth = null
NLayout.siderCollapseMode = null
NLayout.siderPosition = null
NLayout.siderCollapsed = null
}
},
methods: {
scrollTo (...args) {
if (this.$refs.scrollbar) {
this.$refs.scrollbar.scrollTo(...args)
} else {
this.$el.scrollTo(...args)
}
},
handleTriggerClick () {
const {
'onUpdate:collapsed': onUpdateCollapsed,
collapsed,
// deprecated
onExpand,
onCollapse
} = this
if (onUpdateCollapsed) onUpdateCollapsed(!collapsed)
if (collapsed) {
if (onExpand) onExpand()
} else {
if (onCollapse) onCollapse()
}
}
}
})
</script>

View File

@ -0,0 +1,25 @@
import { h, defineComponent } from 'vue'
export default defineComponent({
props: {
collapsed: {
type: Boolean,
default: false
}
},
render () {
return (
<div
class={[
'n-layout-toggle-bar',
{
'n-layout-toggle-bar--collapsed': this.collapsed
}
]}
>
<div class="n-layout-toggle-bar__top" />
<div class="n-layout-toggle-bar__bottom" />
</div>
)
}
})

View File

@ -1,22 +0,0 @@
<template>
<div
class="n-layout-toggle-bar"
:class="{
'n-layout-toggle-bar--collapsed': collapsed
}"
>
<div class="n-layout-toggle-bar__top" />
<div class="n-layout-toggle-bar__bottom" />
</div>
</template>
<script>
export default {
props: {
collapsed: {
type: Boolean,
default: false
}
}
}
</script>

View File

@ -0,0 +1,17 @@
import { h, defineComponent } from 'vue'
export default defineComponent({
name: 'LayoutToggleButton',
render () {
return (
<div class="n-layout-toggle-button">
<svg viewBox="0 0 56.06 56.06">
<path
d="M50,22A28,28,0,1,0,78,50,28.06,28.06,0,0,0,50,22ZM65.09,52.16h-25l7.1,7.1a2.16,2.16,0,0,1-3.05,3.05L33.38,51.52a2.15,2.15,0,0,1,0-3L44.16,37.69a2.16,2.16,0,0,1,3.05,3.05l-7.1,7.1h25a2.16,2.16,0,0,1,0,4.32Z"
transform="translate(-21.97 -21.97)"
/>
</svg>
</div>
)
}
})

View File

@ -1,10 +0,0 @@
<template>
<div class="n-layout-toggle-button">
<svg viewBox="0 0 56.06 56.06">
<path
d="M50,22A28,28,0,1,0,78,50,28.06,28.06,0,0,0,50,22ZM65.09,52.16h-25l7.1,7.1a2.16,2.16,0,0,1-3.05,3.05L33.38,51.52a2.15,2.15,0,0,1,0-3L44.16,37.69a2.16,2.16,0,0,1,3.05,3.05l-7.1,7.1h25a2.16,2.16,0,0,1,0,4.32Z"
transform="translate(-21.97 -21.97)"
/>
</svg>
</div>
</template>

View File

@ -0,0 +1,6 @@
import { PropType } from 'vue'
export const positionProp = {
type: String as PropType<'static' | 'absolute'>,
default: 'static'
}

View File

@ -1,15 +0,0 @@
export default {
inject: {
NLayout: {
default: null
}
},
props: {
position: {
default: 'static',
validator (value) {
return ['static', 'absolute'].includes(value)
}
}
}
}

View File

@ -108,15 +108,7 @@ export default cB('layout-sider', `
left: 0;
top: 0;
bottom: 0;
`, [
cE('content', `
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
`)
]),
`),
cM('bordered', [
cE('border', {
backgroundColor: 'var(--sider-border-color)'

View File

@ -1,8 +1,9 @@
import { composite } from 'seemly'
import { commonDark } from '../../_styles/new-common'
import { scrollbarDark } from '../../scrollbar/styles'
import type { LayoutTheme } from './light'
export default {
const layoutDark: LayoutTheme = {
name: 'Layout',
common: commonDark,
peers: {
@ -31,3 +32,5 @@ export default {
}
}
}
export default layoutDark

View File

@ -1,2 +0,0 @@
export { default as layoutDark } from './dark.js'
export { default as layoutLight } from './light.js'

View File

@ -0,0 +1,3 @@
export { default as layoutDark } from './dark'
export { default as layoutLight } from './light'
export type { LayoutTheme, LayoutThemeVars } from './light'

View File

@ -1,33 +0,0 @@
import { composite } from 'seemly'
import { commonLight } from '../../_styles/new-common'
import { scrollbarLight } from '../../scrollbar/styles'
export default {
name: 'Layout',
common: commonLight,
peers: {
Scrollbar: scrollbarLight
},
self (vars) {
const {
textColor2,
bodyColor,
cardColor,
dividerColorOverlay,
scrollbarColorOverlay,
scrollbarColorHoverOverlay
} = vars
return {
textColor: textColor2,
color: bodyColor,
headerColor: cardColor,
headerBorderColor: dividerColorOverlay,
footerBorderColor: dividerColorOverlay,
siderBorderColor: dividerColorOverlay,
siderColor: cardColor,
siderToggleButtonColor: 'rgba(0, 0, 0, .15)',
siderToggleBarColor: composite(bodyColor, scrollbarColorOverlay),
siderToggleBarColorHover: composite(bodyColor, scrollbarColorHoverOverlay)
}
}
}

View File

@ -0,0 +1,42 @@
import { composite } from 'seemly'
import { commonLight } from '../../_styles/new-common'
import type { ThemeCommonVars } from '../../_styles/new-common'
import { scrollbarLight } from '../../scrollbar/styles'
import { createTheme } from '../../_mixins'
const self = (vars: ThemeCommonVars) => {
const {
textColor2,
bodyColor,
cardColor,
dividerColorOverlay,
scrollbarColorOverlay,
scrollbarColorHoverOverlay
} = vars
return {
textColor: textColor2,
color: bodyColor,
headerColor: cardColor,
headerBorderColor: dividerColorOverlay,
footerBorderColor: dividerColorOverlay,
siderBorderColor: dividerColorOverlay,
siderColor: cardColor,
siderToggleButtonColor: 'rgba(0, 0, 0, .15)',
siderToggleBarColor: composite(bodyColor, scrollbarColorOverlay),
siderToggleBarColorHover: composite(bodyColor, scrollbarColorHoverOverlay)
}
}
export type LayoutThemeVars = ReturnType<typeof self>
const layoutLight = createTheme({
name: 'Layout',
common: commonLight,
peers: {
Scrollbar: scrollbarLight
},
self
})
export default layoutLight
export type LayoutTheme = typeof layoutLight