refactor: collapse
parent
740ba04c02
commit
af182533c1
|
@ -0,0 +1,143 @@
|
||||||
|
import { isEmptyElement, initDefaultProps, flattenChildren } from '../_util/props-util';
|
||||||
|
import { cloneElement } from '../_util/vnode';
|
||||||
|
import openAnimationFactory from './openAnimationFactory';
|
||||||
|
import { collapseProps, CollapsibleType } from './commonProps';
|
||||||
|
import { getDataAndAriaProps } from '../_util/util';
|
||||||
|
import { computed, defineComponent, ref, watch } from 'vue';
|
||||||
|
import firstNotUndefined from '../_util/firstNotUndefined';
|
||||||
|
import classNames from '../_util/classNames';
|
||||||
|
|
||||||
|
type Key = number | string;
|
||||||
|
|
||||||
|
function getActiveKeysArray(activeKey: Key | Key[]) {
|
||||||
|
let currentActiveKey = activeKey;
|
||||||
|
if (!Array.isArray(currentActiveKey)) {
|
||||||
|
const activeKeyType = typeof currentActiveKey;
|
||||||
|
currentActiveKey =
|
||||||
|
activeKeyType === 'number' || activeKeyType === 'string' ? [currentActiveKey] : [];
|
||||||
|
}
|
||||||
|
return currentActiveKey.map(key => String(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Collapse',
|
||||||
|
inheritAttrs: false,
|
||||||
|
props: initDefaultProps(collapseProps(), {
|
||||||
|
prefixCls: 'rc-collapse',
|
||||||
|
accordion: false,
|
||||||
|
destroyInactivePanel: false,
|
||||||
|
}),
|
||||||
|
slots: ['expandIcon'],
|
||||||
|
emits: ['change'],
|
||||||
|
setup(props, { attrs, slots, emit }) {
|
||||||
|
const stateActiveKey = ref<Key[]>(
|
||||||
|
getActiveKeysArray(firstNotUndefined([props.activeKey, props.defaultActiveKey])),
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.activeKey,
|
||||||
|
() => {
|
||||||
|
stateActiveKey.value = getActiveKeysArray(props.activeKey);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const currentOpenAnimations = computed(
|
||||||
|
() => props.openAnimation || openAnimationFactory(props.prefixCls),
|
||||||
|
);
|
||||||
|
|
||||||
|
const setActiveKey = (activeKey: Key[]) => {
|
||||||
|
if (props.activeKey === undefined) {
|
||||||
|
stateActiveKey.value = activeKey;
|
||||||
|
}
|
||||||
|
emit('change', props.accordion ? activeKey[0] : activeKey);
|
||||||
|
};
|
||||||
|
const onClickItem = (key: Key) => {
|
||||||
|
let activeKey = stateActiveKey.value;
|
||||||
|
if (props.accordion) {
|
||||||
|
activeKey = activeKey[0] === key ? [] : [key];
|
||||||
|
} else {
|
||||||
|
activeKey = [...activeKey];
|
||||||
|
const index = activeKey.indexOf(key);
|
||||||
|
const isActive = index > -1;
|
||||||
|
if (isActive) {
|
||||||
|
// remove active state
|
||||||
|
activeKey.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
activeKey.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setActiveKey(activeKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getNewChild = (child, index) => {
|
||||||
|
if (isEmptyElement(child)) return;
|
||||||
|
const activeKey = stateActiveKey.value;
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
accordion,
|
||||||
|
destroyInactivePanel,
|
||||||
|
expandIcon = slots.expandIcon,
|
||||||
|
collapsible,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
// If there is no key provide, use the panel order as default key
|
||||||
|
const key = String(child.key ?? index);
|
||||||
|
const {
|
||||||
|
header = child.children?.header?.(),
|
||||||
|
headerClass,
|
||||||
|
collapsible: childCollapsible,
|
||||||
|
disabled,
|
||||||
|
} = child.props || {};
|
||||||
|
let isActive = false;
|
||||||
|
|
||||||
|
if (accordion) {
|
||||||
|
isActive = activeKey[0] === key;
|
||||||
|
} else {
|
||||||
|
isActive = activeKey.indexOf(key) > -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mergeCollapsible: CollapsibleType = childCollapsible ?? collapsible;
|
||||||
|
// legacy 2.x
|
||||||
|
if (disabled || disabled === '') {
|
||||||
|
mergeCollapsible = 'disabled';
|
||||||
|
}
|
||||||
|
const newProps = {
|
||||||
|
key,
|
||||||
|
panelKey: key,
|
||||||
|
header,
|
||||||
|
headerClass,
|
||||||
|
isActive,
|
||||||
|
prefixCls,
|
||||||
|
destroyInactivePanel,
|
||||||
|
openAnimation: currentOpenAnimations.value,
|
||||||
|
accordion,
|
||||||
|
onItemClick: mergeCollapsible === 'disabled' ? null : onClickItem,
|
||||||
|
expandIcon,
|
||||||
|
collapsible: mergeCollapsible,
|
||||||
|
};
|
||||||
|
|
||||||
|
return cloneElement(child, newProps);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getItems = () => {
|
||||||
|
return flattenChildren(slots.default?.()).map(getNewChild);
|
||||||
|
};
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const { prefixCls, accordion } = props;
|
||||||
|
const collapseClassName = classNames({
|
||||||
|
[prefixCls]: true,
|
||||||
|
[attrs.class as string]: !!attrs.class,
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class={collapseClassName}
|
||||||
|
{...getDataAndAriaProps(attrs)}
|
||||||
|
style={attrs.style}
|
||||||
|
role={accordion ? 'tablist' : null}
|
||||||
|
>
|
||||||
|
{getItems()}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,109 @@
|
||||||
|
import PanelContent from './PanelContent';
|
||||||
|
import { initDefaultProps } from '../_util/props-util';
|
||||||
|
import { panelProps } from './commonProps';
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import Transition from '../_util/transition';
|
||||||
|
import classNames from '../_util/classNames';
|
||||||
|
import devWarning from '../vc-util/devWarning';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Panel',
|
||||||
|
props: initDefaultProps(panelProps(), {
|
||||||
|
showArrow: true,
|
||||||
|
isActive: false,
|
||||||
|
onItemClick() {},
|
||||||
|
headerClass: '',
|
||||||
|
forceRender: false,
|
||||||
|
}),
|
||||||
|
slots: ['expandIcon', 'extra', 'header'],
|
||||||
|
emits: ['itemClick'],
|
||||||
|
setup(props, { slots, emit }) {
|
||||||
|
devWarning(
|
||||||
|
!('disabled' in props),
|
||||||
|
'Collapse.Panel',
|
||||||
|
'`disabled` is deprecated. Please use `collapsible="disabled"` instead.',
|
||||||
|
);
|
||||||
|
const handleItemClick = () => {
|
||||||
|
emit('itemClick', props.panelKey);
|
||||||
|
};
|
||||||
|
const handleKeyPress = (e: KeyboardEvent) => {
|
||||||
|
if (e.key === 'Enter' || e.keyCode === 13 || e.which === 13) {
|
||||||
|
handleItemClick();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return () => {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
header = slots.header?.(),
|
||||||
|
headerClass,
|
||||||
|
isActive,
|
||||||
|
showArrow,
|
||||||
|
destroyInactivePanel,
|
||||||
|
accordion,
|
||||||
|
forceRender,
|
||||||
|
openAnimation,
|
||||||
|
expandIcon = slots.expandIcon,
|
||||||
|
extra = slots.extra?.(),
|
||||||
|
collapsible,
|
||||||
|
} = props;
|
||||||
|
const disabled = collapsible === 'disabled';
|
||||||
|
|
||||||
|
const headerCls = classNames(`${prefixCls}-header`, {
|
||||||
|
[headerClass]: headerClass,
|
||||||
|
[`${prefixCls}-header-collapsible-only`]: collapsible === 'header',
|
||||||
|
});
|
||||||
|
const itemCls = classNames({
|
||||||
|
[`${prefixCls}-item`]: true,
|
||||||
|
[`${prefixCls}-item-active`]: isActive,
|
||||||
|
[`${prefixCls}-item-disabled`]: disabled,
|
||||||
|
});
|
||||||
|
|
||||||
|
let icon = <i class="arrow" />;
|
||||||
|
if (showArrow && typeof expandIcon === 'function') {
|
||||||
|
icon = expandIcon(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
const panelContent = (
|
||||||
|
<PanelContent
|
||||||
|
v-show={isActive}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
isActive={isActive}
|
||||||
|
forceRender={forceRender}
|
||||||
|
role={accordion ? 'tabpanel' : null}
|
||||||
|
v-slots={{ default: slots.default }}
|
||||||
|
></PanelContent>
|
||||||
|
);
|
||||||
|
const transitionProps = {
|
||||||
|
appear: true,
|
||||||
|
css: false,
|
||||||
|
...openAnimation,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class={itemCls}>
|
||||||
|
<div
|
||||||
|
class={headerCls}
|
||||||
|
onClick={() => collapsible !== 'header' && handleItemClick()}
|
||||||
|
role={accordion ? 'tab' : 'button'}
|
||||||
|
tabindex={disabled ? -1 : 0}
|
||||||
|
aria-expanded={isActive}
|
||||||
|
onKeypress={handleKeyPress}
|
||||||
|
>
|
||||||
|
{showArrow && icon}
|
||||||
|
{collapsible === 'header' ? (
|
||||||
|
<span onClick={handleItemClick} class={`${prefixCls}-header-text`}>
|
||||||
|
{header}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
header
|
||||||
|
)}
|
||||||
|
{extra && <div class={`${prefixCls}-extra`}>{extra}</div>}
|
||||||
|
</div>
|
||||||
|
<Transition {...transitionProps}>
|
||||||
|
{!destroyInactivePanel || isActive ? panelContent : null}
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { defineComponent, ref, watchEffect } from 'vue';
|
||||||
|
import { panelProps } from './commonProps';
|
||||||
|
import classNames from '../_util/classNames';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'PanelContent',
|
||||||
|
props: panelProps(),
|
||||||
|
setup(props, { slots }) {
|
||||||
|
const rendered = ref(false);
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
if (props.isActive || props.forceRender) {
|
||||||
|
rendered.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (!rendered.value) return null;
|
||||||
|
const { prefixCls, isActive, role } = props;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
class={classNames(`${prefixCls}-content`, {
|
||||||
|
[`${prefixCls}-content-active`]: isActive,
|
||||||
|
[`${prefixCls}-content-inactive`]: !isActive,
|
||||||
|
})}
|
||||||
|
role={role}
|
||||||
|
>
|
||||||
|
<div class={`${prefixCls}-content-box`}>{slots.default?.()}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
|
@ -1,100 +0,0 @@
|
||||||
@prefixCls: rc-collapse;
|
|
||||||
@text-color: #666;
|
|
||||||
@borderStyle: 1px solid #d9d9d9;
|
|
||||||
|
|
||||||
#arrow {
|
|
||||||
.common() {
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
font-size: 0;
|
|
||||||
line-height: 0;
|
|
||||||
}
|
|
||||||
.right(@w, @h, @color) {
|
|
||||||
border-top: @w solid transparent;
|
|
||||||
border-bottom: @w solid transparent;
|
|
||||||
border-left: @h solid @color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottom(@w, @h, @color) {
|
|
||||||
border-left: @w solid transparent;
|
|
||||||
border-right: @w solid transparent;
|
|
||||||
border-top: @h solid @color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.@{prefixCls} {
|
|
||||||
background-color: #f7f7f7;
|
|
||||||
border-radius: 3px;
|
|
||||||
border: @borderStyle;
|
|
||||||
|
|
||||||
&-anim-active {
|
|
||||||
transition: height 0.2s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > &-item {
|
|
||||||
border-top: @borderStyle;
|
|
||||||
&:first-child {
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .@{prefixCls}-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
line-height: 22px;
|
|
||||||
padding: 10px 16px;
|
|
||||||
color: #666;
|
|
||||||
cursor: pointer;
|
|
||||||
.arrow {
|
|
||||||
display: inline-block;
|
|
||||||
content: '\20';
|
|
||||||
#arrow > .common();
|
|
||||||
#arrow > .right(3px, 4px, #666);
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.@{prefixCls}-extra {
|
|
||||||
margin: 0 16px 0 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > &-item-disabled > .@{prefixCls}-header {
|
|
||||||
cursor: not-allowed;
|
|
||||||
color: #999;
|
|
||||||
background-color: #f3f3f3;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-content {
|
|
||||||
overflow: hidden;
|
|
||||||
color: @text-color;
|
|
||||||
padding: 0 16px;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
& > &-box {
|
|
||||||
margin-top: 16px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-inactive {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-item:last-child {
|
|
||||||
> .@{prefixCls}-content {
|
|
||||||
border-radius: 0 0 3px 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > &-item-active {
|
|
||||||
> .@{prefixCls}-header {
|
|
||||||
.arrow {
|
|
||||||
position: relative;
|
|
||||||
top: 2px;
|
|
||||||
#arrow > .bottom(3px, 4px, #666);
|
|
||||||
margin-right: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,7 @@
|
||||||
import PropTypes from '../../_util/vue-types';
|
import type { PropType } from 'vue';
|
||||||
|
import PropTypes from '../_util/vue-types';
|
||||||
|
|
||||||
|
export type CollapsibleType = 'header' | 'disabled';
|
||||||
|
|
||||||
const collapseProps = () => ({
|
const collapseProps = () => ({
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
|
@ -19,6 +22,7 @@ const collapseProps = () => ({
|
||||||
openAnimation: PropTypes.object,
|
openAnimation: PropTypes.object,
|
||||||
expandIconPosition: PropTypes.oneOf(['left', 'right']),
|
expandIconPosition: PropTypes.oneOf(['left', 'right']),
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
|
collapsible: { type: String as PropType<CollapsibleType> },
|
||||||
});
|
});
|
||||||
|
|
||||||
const panelProps = () => ({
|
const panelProps = () => ({
|
||||||
|
@ -34,7 +38,10 @@ const panelProps = () => ({
|
||||||
forceRender: PropTypes.looseBool,
|
forceRender: PropTypes.looseBool,
|
||||||
expandIcon: PropTypes.func,
|
expandIcon: PropTypes.func,
|
||||||
extra: PropTypes.any,
|
extra: PropTypes.any,
|
||||||
panelKey: PropTypes.any,
|
panelKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
|
collapsible: { type: String as PropType<CollapsibleType> },
|
||||||
|
role: String,
|
||||||
|
onItemClick: { type: Function as PropType<(panelKey: string | number) => void> },
|
||||||
});
|
});
|
||||||
|
|
||||||
export { collapseProps, panelProps };
|
export { collapseProps, panelProps };
|
|
@ -1,9 +0,0 @@
|
||||||
// based on rc-collapse 1.11.8
|
|
||||||
import CollapsePanel from './src/Panel';
|
|
||||||
import Collapse from './src/Collapse';
|
|
||||||
import { collapseProps, panelProps } from './src/commonProps';
|
|
||||||
|
|
||||||
Collapse.Panel = CollapsePanel;
|
|
||||||
|
|
||||||
export { collapseProps, panelProps };
|
|
||||||
export default Collapse;
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
// based on rc-collapse 3.1.1
|
||||||
|
import CollapsePanel from './Panel';
|
||||||
|
import Collapse from './Collapse';
|
||||||
|
import { collapseProps, panelProps } from './commonProps';
|
||||||
|
|
||||||
|
Collapse.Panel = CollapsePanel;
|
||||||
|
|
||||||
|
export { collapseProps, panelProps };
|
||||||
|
export default Collapse;
|
|
@ -1,14 +1,14 @@
|
||||||
import cssAnimation from '../../_util/css-animation';
|
import cssAnimation from '../_util/css-animation';
|
||||||
|
|
||||||
function animate(node, show, transitionName, done) {
|
function animate(node: HTMLElement, show: boolean, transitionName: string, done: () => void) {
|
||||||
let height;
|
let height: number;
|
||||||
return cssAnimation(node, transitionName, {
|
return cssAnimation(node, transitionName, {
|
||||||
start() {
|
start() {
|
||||||
if (!show) {
|
if (!show) {
|
||||||
node.style.height = `${node.offsetHeight}px`;
|
node.style.height = `${node.offsetHeight}px`;
|
||||||
} else {
|
} else {
|
||||||
height = node.offsetHeight;
|
height = node.offsetHeight;
|
||||||
node.style.height = 0;
|
node.style.height = '0px';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
active() {
|
active() {
|
||||||
|
@ -21,12 +21,12 @@ function animate(node, show, transitionName, done) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function animation(prefixCls) {
|
function animation(prefixCls: string) {
|
||||||
return {
|
return {
|
||||||
onEnter(node, done) {
|
onEnter(node: HTMLElement, done: () => void) {
|
||||||
return animate(node, true, `${prefixCls}-anim`, done);
|
return animate(node, true, `${prefixCls}-anim`, done);
|
||||||
},
|
},
|
||||||
onLeave(node, done) {
|
onLeave(node: HTMLElement, done: () => void) {
|
||||||
return animate(node, false, `${prefixCls}-anim`, done);
|
return animate(node, false, `${prefixCls}-anim`, done);
|
||||||
},
|
},
|
||||||
};
|
};
|
|
@ -1,148 +0,0 @@
|
||||||
import BaseMixin from '../../_util/BaseMixin';
|
|
||||||
import {
|
|
||||||
hasProp,
|
|
||||||
getPropsData,
|
|
||||||
isEmptyElement,
|
|
||||||
initDefaultProps,
|
|
||||||
getSlot,
|
|
||||||
} from '../../_util/props-util';
|
|
||||||
import { cloneElement } from '../../_util/vnode';
|
|
||||||
import openAnimationFactory from './openAnimationFactory';
|
|
||||||
import { collapseProps } from './commonProps';
|
|
||||||
import { getDataAndAriaProps } from '../../_util/util';
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
|
|
||||||
function _toArray(activeKey) {
|
|
||||||
let currentActiveKey = activeKey;
|
|
||||||
if (!Array.isArray(currentActiveKey)) {
|
|
||||||
const activeKeyType = typeof currentActiveKey;
|
|
||||||
currentActiveKey =
|
|
||||||
activeKeyType === 'number' || activeKeyType === 'string' ? [currentActiveKey] : [];
|
|
||||||
}
|
|
||||||
return currentActiveKey.map(key => String(key));
|
|
||||||
}
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'Collapse',
|
|
||||||
mixins: [BaseMixin],
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: initDefaultProps(collapseProps(), {
|
|
||||||
prefixCls: 'rc-collapse',
|
|
||||||
accordion: false,
|
|
||||||
destroyInactivePanel: false,
|
|
||||||
}),
|
|
||||||
data() {
|
|
||||||
const { activeKey, defaultActiveKey, openAnimation, prefixCls } = this.$props;
|
|
||||||
let currentActiveKey = defaultActiveKey;
|
|
||||||
if (hasProp(this, 'activeKey')) {
|
|
||||||
currentActiveKey = activeKey;
|
|
||||||
}
|
|
||||||
const currentOpenAnimations = openAnimation || openAnimationFactory(prefixCls);
|
|
||||||
return {
|
|
||||||
currentOpenAnimations,
|
|
||||||
stateActiveKey: _toArray(currentActiveKey),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
activeKey(val) {
|
|
||||||
this.setState({
|
|
||||||
stateActiveKey: _toArray(val),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
openAnimation(val) {
|
|
||||||
this.setState({
|
|
||||||
currentOpenAnimations: val,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
onClickItem(key) {
|
|
||||||
let activeKey = this.stateActiveKey;
|
|
||||||
if (this.accordion) {
|
|
||||||
activeKey = activeKey[0] === key ? [] : [key];
|
|
||||||
} else {
|
|
||||||
activeKey = [...activeKey];
|
|
||||||
const index = activeKey.indexOf(key);
|
|
||||||
const isActive = index > -1;
|
|
||||||
if (isActive) {
|
|
||||||
// remove active state
|
|
||||||
activeKey.splice(index, 1);
|
|
||||||
} else {
|
|
||||||
activeKey.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.setActiveKey(activeKey);
|
|
||||||
},
|
|
||||||
getNewChild(child, index) {
|
|
||||||
if (isEmptyElement(child)) return;
|
|
||||||
const activeKey = this.stateActiveKey;
|
|
||||||
const { prefixCls, accordion, destroyInactivePanel, expandIcon } = this.$props;
|
|
||||||
|
|
||||||
// If there is no key provide, use the panel order as default key
|
|
||||||
const key = String(child.key ?? index);
|
|
||||||
const { header, headerClass, disabled } = getPropsData(child);
|
|
||||||
let isActive = false;
|
|
||||||
|
|
||||||
if (accordion) {
|
|
||||||
isActive = activeKey[0] === key;
|
|
||||||
} else {
|
|
||||||
isActive = activeKey.indexOf(key) > -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let panelEvents = {};
|
|
||||||
if (!disabled && disabled !== '') {
|
|
||||||
panelEvents = {
|
|
||||||
onItemClick: this.onClickItem,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = {
|
|
||||||
key,
|
|
||||||
panelKey: key,
|
|
||||||
header,
|
|
||||||
headerClass,
|
|
||||||
isActive,
|
|
||||||
prefixCls,
|
|
||||||
destroyInactivePanel,
|
|
||||||
openAnimation: this.currentOpenAnimations,
|
|
||||||
accordion,
|
|
||||||
expandIcon,
|
|
||||||
...panelEvents,
|
|
||||||
};
|
|
||||||
|
|
||||||
return cloneElement(child, props);
|
|
||||||
},
|
|
||||||
getItems() {
|
|
||||||
const newChildren = [];
|
|
||||||
const children = getSlot(this);
|
|
||||||
children &&
|
|
||||||
children.forEach((child, index) => {
|
|
||||||
newChildren.push(this.getNewChild(child, index));
|
|
||||||
});
|
|
||||||
return newChildren;
|
|
||||||
},
|
|
||||||
setActiveKey(activeKey) {
|
|
||||||
if (!hasProp(this, 'activeKey')) {
|
|
||||||
this.setState({ stateActiveKey: activeKey });
|
|
||||||
}
|
|
||||||
this.__emit('change', this.accordion ? activeKey[0] : activeKey);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
const { prefixCls, accordion } = this.$props;
|
|
||||||
const { class: className, style } = this.$attrs;
|
|
||||||
const collapseClassName = {
|
|
||||||
[prefixCls]: true,
|
|
||||||
[className]: className,
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
class={collapseClassName}
|
|
||||||
{...getDataAndAriaProps(this.$attrs)}
|
|
||||||
style={style}
|
|
||||||
role={accordion ? 'tablist' : null}
|
|
||||||
>
|
|
||||||
{this.getItems()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,94 +0,0 @@
|
||||||
import PanelContent from './PanelContent';
|
|
||||||
import { initDefaultProps, getComponent, getSlot } from '../../_util/props-util';
|
|
||||||
import { panelProps } from './commonProps';
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import BaseMixin from '../../_util/BaseMixin';
|
|
||||||
import Transition from '../../_util/transition';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'Panel',
|
|
||||||
mixins: [BaseMixin],
|
|
||||||
props: initDefaultProps(panelProps(), {
|
|
||||||
showArrow: true,
|
|
||||||
isActive: false,
|
|
||||||
destroyInactivePanel: false,
|
|
||||||
headerClass: '',
|
|
||||||
forceRender: false,
|
|
||||||
}),
|
|
||||||
methods: {
|
|
||||||
handleItemClick() {
|
|
||||||
this.__emit('itemClick', this.panelKey);
|
|
||||||
},
|
|
||||||
handleKeyPress(e) {
|
|
||||||
if (e.key === 'Enter' || e.keyCode === 13 || e.which === 13) {
|
|
||||||
this.handleItemClick();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
prefixCls,
|
|
||||||
headerClass,
|
|
||||||
isActive,
|
|
||||||
showArrow,
|
|
||||||
destroyInactivePanel,
|
|
||||||
disabled,
|
|
||||||
openAnimation,
|
|
||||||
accordion,
|
|
||||||
forceRender,
|
|
||||||
expandIcon,
|
|
||||||
extra,
|
|
||||||
} = this.$props;
|
|
||||||
|
|
||||||
const transitionProps = {
|
|
||||||
appear: true,
|
|
||||||
css: false,
|
|
||||||
...openAnimation,
|
|
||||||
};
|
|
||||||
const headerCls = {
|
|
||||||
[`${prefixCls}-header`]: true,
|
|
||||||
[headerClass]: headerClass,
|
|
||||||
};
|
|
||||||
|
|
||||||
const header = getComponent(this, 'header');
|
|
||||||
const itemCls = {
|
|
||||||
[`${prefixCls}-item`]: true,
|
|
||||||
[`${prefixCls}-item-active`]: isActive,
|
|
||||||
[`${prefixCls}-item-disabled`]: disabled,
|
|
||||||
};
|
|
||||||
let icon = <i class="arrow" />;
|
|
||||||
if (showArrow && typeof expandIcon === 'function') {
|
|
||||||
icon = expandIcon(this.$props);
|
|
||||||
}
|
|
||||||
|
|
||||||
const panelContent = (
|
|
||||||
<PanelContent
|
|
||||||
v-show={isActive}
|
|
||||||
prefixCls={prefixCls}
|
|
||||||
isActive={isActive}
|
|
||||||
destroyInactivePanel={destroyInactivePanel}
|
|
||||||
forceRender={forceRender}
|
|
||||||
role={accordion ? 'tabpanel' : null}
|
|
||||||
>
|
|
||||||
{getSlot(this)}
|
|
||||||
</PanelContent>
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<div class={itemCls} role="tablist">
|
|
||||||
<div
|
|
||||||
class={headerCls}
|
|
||||||
onClick={this.handleItemClick}
|
|
||||||
onKeypress={this.handleKeyPress}
|
|
||||||
role={accordion ? 'tab' : 'button'}
|
|
||||||
tabindex={disabled ? -1 : 0}
|
|
||||||
aria-expanded={isActive}
|
|
||||||
>
|
|
||||||
{showArrow && icon}
|
|
||||||
{header}
|
|
||||||
{extra && <div class={`${prefixCls}-extra`}>{extra}</div>}
|
|
||||||
</div>
|
|
||||||
<Transition {...transitionProps}>{panelContent}</Transition>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,39 +0,0 @@
|
||||||
import PropTypes from '../../_util/vue-types';
|
|
||||||
import { getSlot } from '../../_util/props-util';
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'PanelContent',
|
|
||||||
props: {
|
|
||||||
prefixCls: PropTypes.string,
|
|
||||||
isActive: PropTypes.looseBool,
|
|
||||||
destroyInactivePanel: PropTypes.looseBool,
|
|
||||||
forceRender: PropTypes.looseBool,
|
|
||||||
role: PropTypes.any,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
_isActive: undefined,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
this._isActive = this.forceRender || this._isActive || this.isActive;
|
|
||||||
if (!this._isActive) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const { prefixCls, isActive, destroyInactivePanel, forceRender, role } = this.$props;
|
|
||||||
const contentCls = {
|
|
||||||
[`${prefixCls}-content`]: true,
|
|
||||||
[`${prefixCls}-content-active`]: isActive,
|
|
||||||
};
|
|
||||||
const child =
|
|
||||||
!forceRender && !isActive && destroyInactivePanel ? null : (
|
|
||||||
<div class={`${prefixCls}-content-box`}>{getSlot(this)}</div>
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<div class={contentCls} role={role}>
|
|
||||||
{child}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,4 +1,4 @@
|
||||||
// base rc-steps 3.5.0
|
// base rc-steps 4.1.3
|
||||||
import Steps from './Steps';
|
import Steps from './Steps';
|
||||||
import Step from './Step';
|
import Step from './Step';
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import demo from '../v2-doc/src/docs/timeline/demo/index.vue';
|
import demo from '../v2-doc/src/docs/collapse/demo/index.vue';
|
||||||
// import Affix from '../components/affix';
|
// import Affix from '../components/affix';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
|
2
v2-doc
2
v2-doc
|
@ -1 +1 @@
|
||||||
Subproject commit 3a14ef175850d1fcb3ccd002c3afd1f871dc3257
|
Subproject commit c703df2dd803ee5097b414e2a32482b8fc2225d7
|
Loading…
Reference in New Issue