@fesjs/fes-design
Version:
fes-design for PC
157 lines (151 loc) • 4.72 kB
JavaScript
import { defineComponent, computed, createVNode, Fragment } from 'vue';
import { useTheme } from '../_theme/useTheme';
import { timelineProps } from './props';
import { COMPONENT_NAME, prefixCls } from './const';
import { cls, calcTitlePosition, calcDescPosition, getTitleOppositePosition } from './utils';
import { useCustomIcons } from './useCustomIcons';
import Icon from './icon';
/** 渲染标题、辅助描述 */
const renderNodeContent = _ref => {
let {
title,
titlePosition,
descPosition,
desc,
titleClass,
descClass,
appendantStyle,
titleWidth,
direction
} = _ref;
const titleElement = createVNode("div", {
"class": [cls('item-title'), cls(`item-title-layout-${titlePosition}`), titleClass]
}, [title]);
const descElement = desc ? createVNode("div", {
"class": [cls('item-desc'), cls(`item-desc-layout-${descPosition}`), descClass]
}, [desc]) : undefined;
// 标题、辅助描述同侧
if (descPosition !== 'opposite') {
return createVNode("div", {
"class": [cls('item-content-wrapper'), cls(`item-content-wrapper-${titlePosition}`)],
"style": appendantStyle
}, [titleElement, descElement]);
}
// 标题、辅助描述分侧
return createVNode(Fragment, null, [createVNode("div", {
"class": [cls('item-content-wrapper'), cls(`item-content-wrapper-${titlePosition}`)],
"style": [appendantStyle, direction === 'column' && descPosition === 'opposite' && titleWidth && {
width: titleWidth
}]
}, [titleElement]), descElement && createVNode("div", {
"class": [cls('item-content-wrapper'), cls(`item-content-wrapper-${getTitleOppositePosition(titlePosition)}`)],
"style": appendantStyle
}, [descElement])]);
};
const renderNode = nodeProps => {
const {
node,
index,
props,
slots,
nodeAppendantStyleMap
} = nodeProps;
const {
direction,
titlePosition,
descPosition,
titleClass,
descClass
} = props;
const {
title,
desc,
icon
} = node;
const calculatedTitlePosition = calcTitlePosition(index, titlePosition, node.titlePosition);
const calculatedDescPosition = calcDescPosition(direction, descPosition);
let descContent;
// prop 的渲染函数优先级高于插槽
if (slots.desc) {
descContent = slots.desc({
index,
item: props.data[index]
});
} else if (typeof desc === 'function') {
descContent = desc({
index,
item: props.data[index]
});
} else {
descContent = desc;
}
// prop 的渲染函数优先级高于插槽
let titleContent;
if (slots.title) {
titleContent = slots.title({
index,
item: props.data[index]
});
} else if (typeof title === 'function') {
titleContent = title({
index,
item: props.data[index]
});
} else {
titleContent = title;
}
const appendantStyle = nodeAppendantStyleMap.value.get(index);
return createVNode("li", {
"class": [cls('item'), cls(`item-layout-${calculatedTitlePosition}`)],
"key": index
}, [createVNode("div", {
"class": [cls('item-tail'), index === props.data.length - 1 && cls('item-tail-last')],
"style": [appendantStyle === null || appendantStyle === void 0 ? void 0 : appendantStyle.tail, props.direction === 'column' && descPosition === 'opposite' && props.titleWidth && {
left: props.titleWidth
}]
}, null), renderNodeContent({
title: titleContent,
titleClass,
descClass,
titlePosition: calculatedTitlePosition,
descPosition: calculatedDescPosition,
desc: descContent,
appendantStyle: appendantStyle === null || appendantStyle === void 0 ? void 0 : appendantStyle.content,
titleWidth: props.titleWidth,
direction: props.direction
}), createVNode(Icon, {
"key": index,
"index": index,
"icon": icon,
"data": props.data,
"style": [props.direction === 'column' && descPosition === 'opposite' && props.titleWidth && {
left: props.titleWidth
}],
"slotRender": slots.icon
}, null)]);
};
var timeline = defineComponent({
name: COMPONENT_NAME,
props: timelineProps,
slots: Object,
setup: (props, _ref2) => {
let {
slots
} = _ref2;
useTheme();
const {
nodeAppendantStyleMap
} = useCustomIcons(props.direction, props.data);
const classList = computed(() => [prefixCls, cls(`direction-${props.direction}`), cls(`layout-${props.titlePosition}`), cls(`desc-${props.descPosition}`)]);
return () => createVNode("ul", {
"class": classList.value
}, [props.data.map((node, index) => renderNode({
node,
index,
props,
slots,
nodeAppendantStyleMap
}))]);
}
});
export { timeline as default };