refactor: layout
parent
fe99051b55
commit
3825c6507f
|
@ -1,17 +1,25 @@
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import { inject, provide, PropType, defineComponent, nextTick } from 'vue';
|
import {
|
||||||
|
inject,
|
||||||
|
PropType,
|
||||||
|
defineComponent,
|
||||||
|
ExtractPropTypes,
|
||||||
|
ref,
|
||||||
|
watch,
|
||||||
|
onMounted,
|
||||||
|
onBeforeUnmount,
|
||||||
|
CSSProperties,
|
||||||
|
provide,
|
||||||
|
} from 'vue';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import { tuple } from '../_util/type';
|
import { tuple } from '../_util/type';
|
||||||
import { getOptionProps, hasProp, getComponent, getSlot } from '../_util/props-util';
|
|
||||||
import initDefaultProps from '../_util/props-util/initDefaultProps';
|
import initDefaultProps from '../_util/props-util/initDefaultProps';
|
||||||
import BaseMixin from '../_util/BaseMixin';
|
|
||||||
import isNumeric from '../_util/isNumeric';
|
import isNumeric from '../_util/isNumeric';
|
||||||
import { defaultConfigProvider } from '../config-provider';
|
|
||||||
import BarsOutlined from '@ant-design/icons-vue/BarsOutlined';
|
import BarsOutlined from '@ant-design/icons-vue/BarsOutlined';
|
||||||
import RightOutlined from '@ant-design/icons-vue/RightOutlined';
|
import RightOutlined from '@ant-design/icons-vue/RightOutlined';
|
||||||
import LeftOutlined from '@ant-design/icons-vue/LeftOutlined';
|
import LeftOutlined from '@ant-design/icons-vue/LeftOutlined';
|
||||||
import omit from 'omit.js';
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
import { SiderHookProvider } from './layout';
|
import { SiderCollapsedKey, SiderHookProviderKey } from './injectionKey';
|
||||||
|
|
||||||
const dimensionMaxMap = {
|
const dimensionMaxMap = {
|
||||||
xs: '479.98px',
|
xs: '479.98px',
|
||||||
|
@ -24,7 +32,7 @@ const dimensionMaxMap = {
|
||||||
|
|
||||||
export type CollapseType = 'clickTrigger' | 'responsive';
|
export type CollapseType = 'clickTrigger' | 'responsive';
|
||||||
|
|
||||||
export const SiderProps = {
|
export const siderProps = {
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
collapsible: PropTypes.looseBool,
|
collapsible: PropTypes.looseBool,
|
||||||
collapsed: PropTypes.looseBool,
|
collapsed: PropTypes.looseBool,
|
||||||
|
@ -40,6 +48,7 @@ export const SiderProps = {
|
||||||
onCollapse: Function as PropType<(collapsed: boolean, type: CollapseType) => void>,
|
onCollapse: Function as PropType<(collapsed: boolean, type: CollapseType) => void>,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type SiderProps = Partial<ExtractPropTypes<typeof siderProps>>;
|
||||||
// export interface SiderState {
|
// export interface SiderState {
|
||||||
// collapsed?: boolean;
|
// collapsed?: boolean;
|
||||||
// below: boolean;
|
// below: boolean;
|
||||||
|
@ -61,10 +70,8 @@ const generateId = (() => {
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ALayoutSider',
|
name: 'ALayoutSider',
|
||||||
mixins: [BaseMixin],
|
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
__ANT_LAYOUT_SIDER: true,
|
props: initDefaultProps(siderProps, {
|
||||||
props: initDefaultProps(SiderProps, {
|
|
||||||
collapsible: false,
|
collapsible: false,
|
||||||
defaultCollapsed: false,
|
defaultCollapsed: false,
|
||||||
reverseArrow: false,
|
reverseArrow: false,
|
||||||
|
@ -72,173 +79,141 @@ export default defineComponent({
|
||||||
collapsedWidth: 80,
|
collapsedWidth: 80,
|
||||||
}),
|
}),
|
||||||
emits: ['breakpoint', 'update:collapsed', 'collapse'],
|
emits: ['breakpoint', 'update:collapsed', 'collapse'],
|
||||||
setup() {
|
setup(props, { emit, attrs, slots }) {
|
||||||
return {
|
const { prefixCls } = useConfigInject('layout-sider', props);
|
||||||
siderHook: inject<SiderHookProvider>('siderHook', {}),
|
const siderHook = inject(SiderHookProviderKey);
|
||||||
configProvider: inject('configProvider', defaultConfigProvider),
|
const collapsed = ref(
|
||||||
};
|
!!(props.collapsed !== undefined ? props.collapsed : props.defaultCollapsed),
|
||||||
},
|
|
||||||
data() {
|
|
||||||
const uniqueId = generateId('ant-sider-');
|
|
||||||
let matchMedia: typeof window.matchMedia;
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
matchMedia = window.matchMedia;
|
|
||||||
}
|
|
||||||
const props = getOptionProps(this) as any;
|
|
||||||
let mql: MediaQueryList;
|
|
||||||
if (matchMedia && props.breakpoint && props.breakpoint in dimensionMaxMap) {
|
|
||||||
mql = matchMedia(`(max-width: ${dimensionMaxMap[props.breakpoint]})`);
|
|
||||||
}
|
|
||||||
let sCollapsed: boolean;
|
|
||||||
if ('collapsed' in props) {
|
|
||||||
sCollapsed = props.collapsed;
|
|
||||||
} else {
|
|
||||||
sCollapsed = props.defaultCollapsed;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
sCollapsed,
|
|
||||||
below: false,
|
|
||||||
belowShow: false,
|
|
||||||
uniqueId,
|
|
||||||
mql,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
collapsed(val) {
|
|
||||||
this.setState({
|
|
||||||
sCollapsed: val,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
provide('layoutSiderContext', this); // menu组件中使用
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
nextTick(() => {
|
|
||||||
if (this.mql) {
|
|
||||||
this.mql.addListener(this.responsiveHandler);
|
|
||||||
this.responsiveHandler(this.mql);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.siderHook.addSider) {
|
|
||||||
this.siderHook.addSider(this.uniqueId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
beforeUnmount() {
|
|
||||||
if (this.mql) {
|
|
||||||
this.mql.removeListener(this.responsiveHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.siderHook.removeSider) {
|
|
||||||
this.siderHook.removeSider(this.uniqueId);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
responsiveHandler(mql: MediaQueryListEvent | MediaQueryList) {
|
|
||||||
this.setState({ below: mql.matches });
|
|
||||||
this.$emit('breakpoint', mql.matches);
|
|
||||||
if (this.sCollapsed !== mql.matches) {
|
|
||||||
this.setCollapsed(mql.matches, 'responsive');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setCollapsed(collapsed: boolean, type: CollapseType) {
|
|
||||||
if (!hasProp(this, 'collapsed')) {
|
|
||||||
this.setState({
|
|
||||||
sCollapsed: collapsed,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.$emit('update:collapsed', collapsed);
|
|
||||||
this.$emit('collapse', collapsed, type);
|
|
||||||
},
|
|
||||||
|
|
||||||
toggle() {
|
|
||||||
const collapsed = !this.sCollapsed;
|
|
||||||
this.setCollapsed(collapsed, 'clickTrigger');
|
|
||||||
},
|
|
||||||
|
|
||||||
belowShowChange() {
|
|
||||||
this.setState({ belowShow: !this.belowShow });
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
prefixCls: customizePrefixCls,
|
|
||||||
class: className,
|
|
||||||
theme,
|
|
||||||
collapsible,
|
|
||||||
reverseArrow,
|
|
||||||
style,
|
|
||||||
width,
|
|
||||||
collapsedWidth,
|
|
||||||
zeroWidthTriggerStyle,
|
|
||||||
...others
|
|
||||||
} = { ...getOptionProps(this), ...this.$attrs } as any;
|
|
||||||
const getPrefixCls = this.configProvider.getPrefixCls;
|
|
||||||
const prefixCls = getPrefixCls('layout-sider', customizePrefixCls);
|
|
||||||
const divProps = omit(others, [
|
|
||||||
'collapsed',
|
|
||||||
'defaultCollapsed',
|
|
||||||
'onCollapse',
|
|
||||||
'breakpoint',
|
|
||||||
'onBreakpoint',
|
|
||||||
'siderHook',
|
|
||||||
'zeroWidthTriggerStyle',
|
|
||||||
'trigger',
|
|
||||||
]);
|
|
||||||
const trigger = getComponent(this, 'trigger');
|
|
||||||
const rawWidth = this.sCollapsed ? collapsedWidth : width;
|
|
||||||
// use "px" as fallback unit for width
|
|
||||||
const siderWidth = isNumeric(rawWidth) ? `${rawWidth}px` : String(rawWidth);
|
|
||||||
// special trigger when collapsedWidth == 0
|
|
||||||
const zeroWidthTrigger =
|
|
||||||
parseFloat(String(collapsedWidth || 0)) === 0 ? (
|
|
||||||
<span
|
|
||||||
onClick={this.toggle}
|
|
||||||
class={`${prefixCls}-zero-width-trigger ${prefixCls}-zero-width-trigger-${
|
|
||||||
reverseArrow ? 'right' : 'left'
|
|
||||||
}`}
|
|
||||||
style={zeroWidthTriggerStyle}
|
|
||||||
>
|
|
||||||
<BarsOutlined />
|
|
||||||
</span>
|
|
||||||
) : null;
|
|
||||||
const iconObj = {
|
|
||||||
expanded: reverseArrow ? <RightOutlined /> : <LeftOutlined />,
|
|
||||||
collapsed: reverseArrow ? <LeftOutlined /> : <RightOutlined />,
|
|
||||||
};
|
|
||||||
const status = this.sCollapsed ? 'collapsed' : 'expanded';
|
|
||||||
const defaultTrigger = iconObj[status];
|
|
||||||
const triggerDom =
|
|
||||||
trigger !== null
|
|
||||||
? zeroWidthTrigger || (
|
|
||||||
<div class={`${prefixCls}-trigger`} onClick={this.toggle} style={{ width: siderWidth }}>
|
|
||||||
{trigger || defaultTrigger}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
: null;
|
|
||||||
const divStyle = {
|
|
||||||
...style,
|
|
||||||
flex: `0 0 ${siderWidth}`,
|
|
||||||
maxWidth: siderWidth, // Fix width transition bug in IE11
|
|
||||||
minWidth: siderWidth, // https://github.com/ant-design/ant-design/issues/6349
|
|
||||||
width: siderWidth,
|
|
||||||
};
|
|
||||||
const siderCls = classNames(className, prefixCls, `${prefixCls}-${theme}`, {
|
|
||||||
[`${prefixCls}-collapsed`]: !!this.sCollapsed,
|
|
||||||
[`${prefixCls}-has-trigger`]: collapsible && trigger !== null && !zeroWidthTrigger,
|
|
||||||
[`${prefixCls}-below`]: !!this.below,
|
|
||||||
[`${prefixCls}-zero-width`]: parseFloat(siderWidth) === 0,
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<aside class={siderCls} {...divProps} style={divStyle}>
|
|
||||||
<div class={`${prefixCls}-children`}>{getSlot(this)}</div>
|
|
||||||
{collapsible || (this.below && zeroWidthTrigger) ? triggerDom : null}
|
|
||||||
</aside>
|
|
||||||
);
|
);
|
||||||
|
const below = ref(false);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.collapsed,
|
||||||
|
() => {
|
||||||
|
collapsed.value = !!props.collapsed;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
provide(SiderCollapsedKey, collapsed);
|
||||||
|
|
||||||
|
const handleSetCollapsed = (value: boolean, type: CollapseType) => {
|
||||||
|
if (props.collapsed === undefined) {
|
||||||
|
collapsed.value = value;
|
||||||
|
}
|
||||||
|
emit('update:collapsed', value);
|
||||||
|
emit('collapse', value, type);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========================= Responsive =========================
|
||||||
|
const responsiveHandlerRef = ref<(mql: MediaQueryListEvent | MediaQueryList) => void>(
|
||||||
|
(mql: MediaQueryListEvent | MediaQueryList) => {
|
||||||
|
below.value = mql.matches;
|
||||||
|
emit('breakpoint', mql.matches);
|
||||||
|
|
||||||
|
if (collapsed.value !== mql.matches) {
|
||||||
|
handleSetCollapsed(mql.matches, 'responsive');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let mql: MediaQueryList;
|
||||||
|
function responsiveHandler(mql: MediaQueryListEvent | MediaQueryList) {
|
||||||
|
return responsiveHandlerRef.value!(mql);
|
||||||
|
}
|
||||||
|
const uniqueId = generateId('ant-sider-');
|
||||||
|
onMounted(() => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const { matchMedia } = window;
|
||||||
|
if (matchMedia! && props.breakpoint && props.breakpoint in dimensionMaxMap) {
|
||||||
|
mql = matchMedia(`(max-width: ${dimensionMaxMap[props.breakpoint]})`);
|
||||||
|
try {
|
||||||
|
mql.addEventListener('change', responsiveHandler);
|
||||||
|
} catch (error) {
|
||||||
|
mql.addListener(responsiveHandler);
|
||||||
|
}
|
||||||
|
responsiveHandler(mql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
siderHook && siderHook.addSider(uniqueId);
|
||||||
|
});
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
try {
|
||||||
|
mql?.removeEventListener('change', responsiveHandler);
|
||||||
|
} catch (error) {
|
||||||
|
mql?.removeListener(responsiveHandler);
|
||||||
|
}
|
||||||
|
siderHook && siderHook.removeSider(uniqueId);
|
||||||
|
});
|
||||||
|
|
||||||
|
const toggle = () => {
|
||||||
|
handleSetCollapsed(!collapsed.value, 'clickTrigger');
|
||||||
|
};
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const pre = prefixCls.value;
|
||||||
|
const {
|
||||||
|
collapsedWidth,
|
||||||
|
width,
|
||||||
|
reverseArrow,
|
||||||
|
zeroWidthTriggerStyle,
|
||||||
|
trigger,
|
||||||
|
collapsible,
|
||||||
|
theme,
|
||||||
|
} = props;
|
||||||
|
const rawWidth = collapsed.value ? collapsedWidth : width;
|
||||||
|
// use "px" as fallback unit for width
|
||||||
|
const siderWidth = isNumeric(rawWidth) ? `${rawWidth}px` : String(rawWidth);
|
||||||
|
// special trigger when collapsedWidth == 0
|
||||||
|
const zeroWidthTrigger =
|
||||||
|
parseFloat(String(collapsedWidth || 0)) === 0 ? (
|
||||||
|
<span
|
||||||
|
onClick={toggle}
|
||||||
|
class={classNames(
|
||||||
|
`${pre}-zero-width-trigger`,
|
||||||
|
`${pre}-zero-width-trigger-${reverseArrow ? 'right' : 'left'}`,
|
||||||
|
)}
|
||||||
|
style={zeroWidthTriggerStyle}
|
||||||
|
>
|
||||||
|
{trigger || <BarsOutlined />}
|
||||||
|
</span>
|
||||||
|
) : null;
|
||||||
|
const iconObj = {
|
||||||
|
expanded: reverseArrow ? <RightOutlined /> : <LeftOutlined />,
|
||||||
|
collapsed: reverseArrow ? <LeftOutlined /> : <RightOutlined />,
|
||||||
|
};
|
||||||
|
const status = collapsed.value ? 'collapsed' : 'expanded';
|
||||||
|
const defaultTrigger = iconObj[status];
|
||||||
|
const triggerDom =
|
||||||
|
trigger !== null
|
||||||
|
? zeroWidthTrigger || (
|
||||||
|
<div class={`${pre}-trigger`} onClick={toggle} style={{ width: siderWidth }}>
|
||||||
|
{trigger || defaultTrigger}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
const divStyle = {
|
||||||
|
...(attrs.style as CSSProperties),
|
||||||
|
flex: `0 0 ${siderWidth}`,
|
||||||
|
maxWidth: siderWidth, // Fix width transition bug in IE11
|
||||||
|
minWidth: siderWidth, // https://github.com/ant-design/ant-design/issues/6349
|
||||||
|
width: siderWidth,
|
||||||
|
};
|
||||||
|
const siderCls = classNames(
|
||||||
|
pre,
|
||||||
|
`${pre}-${theme}`,
|
||||||
|
{
|
||||||
|
[`${pre}-collapsed`]: !!collapsed.value,
|
||||||
|
[`${pre}-has-trigger`]: collapsible && trigger !== null && !zeroWidthTrigger,
|
||||||
|
[`${pre}-below`]: !!below.value,
|
||||||
|
[`${pre}-zero-width`]: parseFloat(siderWidth) === 0,
|
||||||
|
},
|
||||||
|
attrs.class,
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<aside {...attrs} class={siderCls} style={divStyle} ref={ref}>
|
||||||
|
<div class={`${pre}-children`}>{slots.default?.()}</div>
|
||||||
|
{collapsible || (below && zeroWidthTrigger) ? triggerDom : null}
|
||||||
|
</aside>
|
||||||
|
);
|
||||||
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,6 +2,9 @@ import { App, Plugin } from 'vue';
|
||||||
import Layout from './layout';
|
import Layout from './layout';
|
||||||
import Sider from './Sider';
|
import Sider from './Sider';
|
||||||
|
|
||||||
|
export { BasicProps as LayoutProps } from './layout';
|
||||||
|
export { SiderProps } from './Sider';
|
||||||
|
|
||||||
Layout.Sider = Sider;
|
Layout.Sider = Sider;
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Ref, InjectionKey } from 'vue';
|
||||||
|
|
||||||
|
export type SiderCollapsed = Ref<boolean>;
|
||||||
|
|
||||||
|
export const SiderCollapsedKey: InjectionKey<SiderCollapsed> = Symbol('siderCollapsed');
|
||||||
|
|
||||||
|
export interface SiderHookProvider {
|
||||||
|
addSider?: (id: string) => void;
|
||||||
|
removeSider?: (id: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SiderHookProviderKey: InjectionKey<SiderHookProvider> = Symbol('siderHookProvider');
|
|
@ -1,17 +1,8 @@
|
||||||
import {
|
import { createVNode, defineComponent, provide, ref, ExtractPropTypes, HTMLAttributes } from 'vue';
|
||||||
createVNode,
|
|
||||||
defineComponent,
|
|
||||||
inject,
|
|
||||||
provide,
|
|
||||||
toRefs,
|
|
||||||
ref,
|
|
||||||
ExtractPropTypes,
|
|
||||||
HTMLAttributes,
|
|
||||||
} from 'vue';
|
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import { defaultConfigProvider } from '../config-provider';
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
import { flattenChildren } from '../_util/props-util';
|
import { SiderHookProviderKey } from './injectionKey';
|
||||||
|
|
||||||
export const basicProps = {
|
export const basicProps = {
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
|
@ -21,40 +12,29 @@ export const basicProps = {
|
||||||
|
|
||||||
export type BasicProps = Partial<ExtractPropTypes<typeof basicProps>> & HTMLAttributes;
|
export type BasicProps = Partial<ExtractPropTypes<typeof basicProps>> & HTMLAttributes;
|
||||||
|
|
||||||
export interface SiderHookProvider {
|
|
||||||
addSider?: (id: string) => void;
|
|
||||||
removeSider?: (id: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
type GeneratorArgument = {
|
type GeneratorArgument = {
|
||||||
suffixCls: string;
|
suffixCls: string;
|
||||||
tagName: string;
|
tagName: 'header' | 'footer' | 'main' | 'section';
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function generator({ suffixCls, tagName, name }: GeneratorArgument) {
|
function generator({ suffixCls, tagName, name }: GeneratorArgument) {
|
||||||
return (BasicComponent: typeof Basic) => {
|
return (BasicComponent: typeof Basic) => {
|
||||||
const Adapter = defineComponent<BasicProps>({
|
const Adapter = defineComponent({
|
||||||
name,
|
name,
|
||||||
|
props: basicProps,
|
||||||
setup(props, { slots }) {
|
setup(props, { slots }) {
|
||||||
const { getPrefixCls } = inject('configProvider', defaultConfigProvider);
|
const { prefixCls } = useConfigInject(suffixCls, props);
|
||||||
return () => {
|
return () => {
|
||||||
const { prefixCls: customizePrefixCls } = props;
|
|
||||||
const prefixCls = getPrefixCls(suffixCls, customizePrefixCls);
|
|
||||||
const basicComponentProps = {
|
const basicComponentProps = {
|
||||||
prefixCls,
|
prefixCls: prefixCls.value,
|
||||||
...props,
|
|
||||||
tagName,
|
tagName,
|
||||||
|
...props,
|
||||||
};
|
};
|
||||||
return (
|
return <BasicComponent {...basicComponentProps}>{slots.default?.()}</BasicComponent>;
|
||||||
<BasicComponent {...basicComponentProps}>
|
|
||||||
{flattenChildren(slots.default?.())}
|
|
||||||
</BasicComponent>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
Adapter.props = basicProps;
|
|
||||||
return Adapter;
|
return Adapter;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -62,30 +42,32 @@ function generator({ suffixCls, tagName, name }: GeneratorArgument) {
|
||||||
const Basic = defineComponent({
|
const Basic = defineComponent({
|
||||||
props: basicProps,
|
props: basicProps,
|
||||||
setup(props, { slots }) {
|
setup(props, { slots }) {
|
||||||
const { prefixCls, tagName } = toRefs(props);
|
return () => createVNode(props.tagName, { class: props.prefixCls }, slots.default?.());
|
||||||
return () => createVNode(tagName.value, { class: prefixCls.value }, slots.default?.());
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const BasicLayout = defineComponent({
|
const BasicLayout = defineComponent({
|
||||||
props: basicProps,
|
props: basicProps,
|
||||||
setup(props, { slots }) {
|
setup(props, { slots }) {
|
||||||
|
const { direction } = useConfigInject('', props);
|
||||||
const siders = ref<string[]>([]);
|
const siders = ref<string[]>([]);
|
||||||
const siderHookProvider: SiderHookProvider = {
|
const siderHookProvider = {
|
||||||
addSider: id => {
|
addSider: (id: string) => {
|
||||||
siders.value = [...siders.value, id];
|
siders.value = [...siders.value, id];
|
||||||
},
|
},
|
||||||
removeSider: id => {
|
removeSider: (id: string) => {
|
||||||
siders.value = siders.value.filter(currentId => currentId !== id);
|
siders.value = siders.value.filter(currentId => currentId !== id);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
provide('siderHook', siderHookProvider);
|
|
||||||
|
provide(SiderHookProviderKey, siderHookProvider);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
const { prefixCls, hasSider, tagName } = props;
|
const { prefixCls, hasSider, tagName } = props;
|
||||||
const divCls = classNames(prefixCls, {
|
const divCls = classNames(prefixCls, {
|
||||||
[`${prefixCls}-has-sider`]:
|
[`${prefixCls}-has-sider`]:
|
||||||
typeof hasSider === 'boolean' ? hasSider : siders.value.length > 0,
|
typeof hasSider === 'boolean' ? hasSider : siders.value.length > 0,
|
||||||
|
[`${prefixCls}-rtl`]: direction.value === 'rtl',
|
||||||
});
|
});
|
||||||
return createVNode(tagName, { class: divCls }, slots.default?.());
|
return createVNode(tagName, { class: divCls }, slots.default?.());
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
@import '../../style/mixins/index';
|
@import '../../style/mixins/index';
|
||||||
|
|
||||||
@layout-prefix-cls: ~'@{ant-prefix}-layout';
|
@layout-prefix-cls: ~'@{ant-prefix}-layout';
|
||||||
|
@layout-menu-prefix-cls: ~'@{ant-prefix}-menu';
|
||||||
|
|
||||||
.@{layout-prefix-cls} {
|
.@{layout-prefix-cls} {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -18,9 +19,10 @@
|
||||||
|
|
||||||
&&-has-sider {
|
&&-has-sider {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
||||||
> .@{layout-prefix-cls},
|
> .@{layout-prefix-cls},
|
||||||
> .@{layout-prefix-cls}-content {
|
> .@{layout-prefix-cls}-content {
|
||||||
overflow-x: hidden;
|
width: 0; // https://segmentfault.com/a/1190000019498300
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +34,7 @@
|
||||||
&-header {
|
&-header {
|
||||||
height: @layout-header-height;
|
height: @layout-header-height;
|
||||||
padding: @layout-header-padding;
|
padding: @layout-header-padding;
|
||||||
|
color: @layout-header-color;
|
||||||
line-height: @layout-header-height;
|
line-height: @layout-header-height;
|
||||||
background: @layout-header-background;
|
background: @layout-header-background;
|
||||||
}
|
}
|
||||||
|
@ -64,6 +67,10 @@
|
||||||
// https://github.com/ant-design/ant-design/issues/7967
|
// https://github.com/ant-design/ant-design/issues/7967
|
||||||
// solution from https://stackoverflow.com/a/33132624/3040605
|
// solution from https://stackoverflow.com/a/33132624/3040605
|
||||||
padding-top: 0.1px;
|
padding-top: 0.1px;
|
||||||
|
|
||||||
|
.@{layout-menu-prefix-cls}.@{layout-menu-prefix-cls}-inline-collapsed {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-has-trigger {
|
&-has-trigger {
|
||||||
|
@ -88,7 +95,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&-zero-width {
|
&-zero-width {
|
||||||
& > * {
|
> * {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,8 +115,19 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.3s ease;
|
transition: background 0.3s ease;
|
||||||
|
|
||||||
&:hover {
|
&::after {
|
||||||
background: tint(@layout-sider-background, 10%);
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
background: transparent;
|
||||||
|
transition: all 0.3s;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover::after {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
&-right {
|
&-right {
|
||||||
|
@ -122,3 +140,4 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@import './light';
|
@import './light';
|
||||||
|
@import './rtl';
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
.@{layout-prefix-cls} {
|
.@{layout-prefix-cls}-sider-light {
|
||||||
&-sider {
|
background: @layout-sider-background-light;
|
||||||
&-light {
|
.@{layout-prefix-cls}-sider-trigger {
|
||||||
background: @layout-sider-background-light;
|
color: @layout-trigger-color-light;
|
||||||
}
|
background: @layout-trigger-background-light;
|
||||||
&-light &-trigger {
|
}
|
||||||
color: @layout-trigger-color-light;
|
.@{layout-prefix-cls}-sider-zero-width-trigger {
|
||||||
background: @layout-trigger-background-light;
|
color: @layout-trigger-color-light;
|
||||||
}
|
background: @layout-trigger-background-light;
|
||||||
&-light &-zero-width-trigger {
|
|
||||||
color: @layout-trigger-color-light;
|
|
||||||
background: @layout-trigger-background-light;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
@import '../../style/themes/index';
|
||||||
|
@import '../../style/mixins/index';
|
||||||
|
|
||||||
|
@layout-prefix-cls: ~'@{ant-prefix}-layout';
|
||||||
|
|
||||||
|
.@{layout-prefix-cls} {
|
||||||
|
&-rtl {
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ import {
|
||||||
import devWarning from '../../vc-util/devWarning';
|
import devWarning from '../../vc-util/devWarning';
|
||||||
import { collapseMotion, CSSMotionProps } from '../../_util/transition';
|
import { collapseMotion, CSSMotionProps } from '../../_util/transition';
|
||||||
import uniq from 'lodash-es/uniq';
|
import uniq from 'lodash-es/uniq';
|
||||||
|
import { SiderCollapsedKey } from '../../layout/injectionKey';
|
||||||
|
|
||||||
export const menuProps = {
|
export const menuProps = {
|
||||||
prefixCls: String,
|
prefixCls: String,
|
||||||
|
@ -72,10 +73,7 @@ export default defineComponent({
|
||||||
setup(props, { slots, emit }) {
|
setup(props, { slots, emit }) {
|
||||||
const { prefixCls, direction } = useConfigInject('menu', props);
|
const { prefixCls, direction } = useConfigInject('menu', props);
|
||||||
const store = reactive<Record<string, StoreMenuInfo>>({});
|
const store = reactive<Record<string, StoreMenuInfo>>({});
|
||||||
const siderCollapsed = inject(
|
const siderCollapsed = inject(SiderCollapsedKey, ref(undefined));
|
||||||
'layoutSiderCollapsed',
|
|
||||||
computed(() => undefined),
|
|
||||||
);
|
|
||||||
const inlineCollapsed = computed(() => {
|
const inlineCollapsed = computed(() => {
|
||||||
if (siderCollapsed.value !== undefined) {
|
if (siderCollapsed.value !== undefined) {
|
||||||
return siderCollapsed.value;
|
return siderCollapsed.value;
|
||||||
|
|
|
@ -300,10 +300,11 @@
|
||||||
// Layout
|
// Layout
|
||||||
@layout-body-background: #f0f2f5;
|
@layout-body-background: #f0f2f5;
|
||||||
@layout-header-background: #001529;
|
@layout-header-background: #001529;
|
||||||
@layout-footer-background: @layout-body-background;
|
|
||||||
@layout-header-height: 64px;
|
@layout-header-height: 64px;
|
||||||
@layout-header-padding: 0 50px;
|
@layout-header-padding: 0 50px;
|
||||||
|
@layout-header-color: @text-color;
|
||||||
@layout-footer-padding: 24px 50px;
|
@layout-footer-padding: 24px 50px;
|
||||||
|
@layout-footer-background: @layout-body-background;
|
||||||
@layout-sider-background: @layout-header-background;
|
@layout-sider-background: @layout-header-background;
|
||||||
@layout-trigger-height: 48px;
|
@layout-trigger-height: 48px;
|
||||||
@layout-trigger-background: #002140;
|
@layout-trigger-background: #002140;
|
||||||
|
|
Loading…
Reference in New Issue