fix: fixed error with no expected value in `expandColumnTitle` slot (#7265)
* fix: fixed error report with no expected value in `expandColumnTitle` slot * fix: optimize optional chain * fix: use default render * refactor: use `customRenderSlot` replace `renderSlot` * style: code format * perf: optimize useColumns code * fix: fix path * feat: add customRenderSlot unit testpull/7302/head
parent
c717473568
commit
d870f3f8e0
|
@ -0,0 +1,11 @@
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { customRenderSlot } from '../vnode';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'RenderSlot',
|
||||||
|
setup(_props, { slots }) {
|
||||||
|
return () => {
|
||||||
|
return customRenderSlot(slots, 'default', {}, () => ['default value']);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,26 @@
|
||||||
|
import RenderSlot from '../__mocks__/RenderSlot';
|
||||||
|
import { mount } from '@vue/test-utils';
|
||||||
|
import { nextTick } from 'vue';
|
||||||
|
|
||||||
|
describe('render slot content', () => {
|
||||||
|
it('renders slot content', () => {
|
||||||
|
const wrapper = mount(RenderSlot, {
|
||||||
|
slots: {
|
||||||
|
default: () => 'This is slot content',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.html()).toContain('This is slot content');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('render default value when slot is fragment', async () => {
|
||||||
|
const wrapper = mount(RenderSlot, {
|
||||||
|
slots: {
|
||||||
|
default: () => <></>,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await nextTick();
|
||||||
|
expect(wrapper.html()).toContain('default value');
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,6 +1,6 @@
|
||||||
import { filterEmpty } from './props-util';
|
import { filterEmpty } from './props-util';
|
||||||
import type { VNode, VNodeProps } from 'vue';
|
import type { Slots, VNode, VNodeArrayChildren, VNodeProps } from 'vue';
|
||||||
import { cloneVNode, isVNode, render as VueRender } from 'vue';
|
import { cloneVNode, isVNode, Comment, Fragment, render as VueRender } from 'vue';
|
||||||
import warning from './warning';
|
import warning from './warning';
|
||||||
import type { RefObject } from './createRef';
|
import type { RefObject } from './createRef';
|
||||||
type NodeProps = Record<string, any> &
|
type NodeProps = Record<string, any> &
|
||||||
|
@ -55,3 +55,28 @@ export function deepCloneElement<T, U>(
|
||||||
export function triggerVNodeUpdate(vm: VNode, attrs: Record<string, any>, dom: any) {
|
export function triggerVNodeUpdate(vm: VNode, attrs: Record<string, any>, dom: any) {
|
||||||
VueRender(cloneVNode(vm, { ...attrs }), dom);
|
VueRender(cloneVNode(vm, { ...attrs }), dom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ensureValidVNode = (slot: VNodeArrayChildren | null) => {
|
||||||
|
return (slot || []).some(child => {
|
||||||
|
if (!isVNode(child)) return true;
|
||||||
|
if (child.type === Comment) return false;
|
||||||
|
if (child.type === Fragment && !ensureValidVNode(child.children as VNodeArrayChildren))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
? slot
|
||||||
|
: null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function customRenderSlot(
|
||||||
|
slots: Slots,
|
||||||
|
name: string,
|
||||||
|
props: Record<string, unknown>,
|
||||||
|
fallback?: () => VNodeArrayChildren,
|
||||||
|
) {
|
||||||
|
const slot = slots[name]?.(props);
|
||||||
|
if (ensureValidVNode(slot)) {
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
return fallback?.();
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { VNodeTypes, PropType, VNode, ExtractPropTypes, CSSProperties } from 'vue';
|
import type { VNodeTypes, PropType, VNode, ExtractPropTypes, CSSProperties } from 'vue';
|
||||||
import { isVNode, defineComponent, renderSlot } from 'vue';
|
import { isVNode, defineComponent } from 'vue';
|
||||||
import Tabs from '../tabs';
|
import Tabs from '../tabs';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import { flattenChildren, isEmptyElement, filterEmptyWithUndefined } from '../_util/props-util';
|
import { flattenChildren, isEmptyElement, filterEmptyWithUndefined } from '../_util/props-util';
|
||||||
|
@ -10,6 +10,8 @@ import devWarning from '../vc-util/devWarning';
|
||||||
import useStyle from './style';
|
import useStyle from './style';
|
||||||
import Skeleton from '../skeleton';
|
import Skeleton from '../skeleton';
|
||||||
import type { CustomSlotsType } from '../_util/type';
|
import type { CustomSlotsType } from '../_util/type';
|
||||||
|
import { customRenderSlot } from '../_util/vnode';
|
||||||
|
|
||||||
export interface CardTabListType {
|
export interface CardTabListType {
|
||||||
key: string;
|
key: string;
|
||||||
tab: any;
|
tab: any;
|
||||||
|
@ -152,7 +154,7 @@ const Card = defineComponent({
|
||||||
`tabList slots is deprecated, Please use \`customTab\` instead.`,
|
`tabList slots is deprecated, Please use \`customTab\` instead.`,
|
||||||
);
|
);
|
||||||
let tab = temp !== undefined ? temp : slots[name] ? slots[name](item) : null;
|
let tab = temp !== undefined ? temp : slots[name] ? slots[name](item) : null;
|
||||||
tab = renderSlot(slots, 'customTab', item as any, () => [tab]);
|
tab = customRenderSlot(slots, 'customTab', item as any, () => [tab]);
|
||||||
return <TabPane tab={tab} key={item.key} disabled={item.disabled} />;
|
return <TabPane tab={tab} key={item.key} disabled={item.disabled} />;
|
||||||
})}
|
})}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import classNames from '../../_util/classNames';
|
import classNames from '../../_util/classNames';
|
||||||
import { filterEmpty, flattenChildren, isValidElement } from '../../_util/props-util';
|
import { filterEmpty, flattenChildren, isValidElement } from '../../_util/props-util';
|
||||||
import type { CSSProperties, VNodeArrayChildren } from 'vue';
|
import type { CSSProperties, VNodeArrayChildren } from 'vue';
|
||||||
import { Text, computed, defineComponent, isVNode, renderSlot } from 'vue';
|
import { Text, computed, defineComponent, isVNode } from 'vue';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
DataIndex,
|
DataIndex,
|
||||||
|
@ -23,6 +23,7 @@ import { useInjectSticky } from '../context/StickyContext';
|
||||||
import { warning } from '../../vc-util/warning';
|
import { warning } from '../../vc-util/warning';
|
||||||
import type { MouseEventHandler } from '../../_util/EventInterface';
|
import type { MouseEventHandler } from '../../_util/EventInterface';
|
||||||
import eagerComputed from '../../_util/eagerComputed';
|
import eagerComputed from '../../_util/eagerComputed';
|
||||||
|
import { customRenderSlot } from 'ant-design-vue/es/_util/vnode';
|
||||||
|
|
||||||
/** Check if cell is in hover range */
|
/** Check if cell is in hover range */
|
||||||
function inHoverRange(cellStartRow: number, cellRowSpan: number, startRow: number, endRow: number) {
|
function inHoverRange(cellStartRow: number, cellRowSpan: number, startRow: number, endRow: number) {
|
||||||
|
@ -223,7 +224,7 @@ export default defineComponent<CellProps>({
|
||||||
contextSlots.value.bodyCell &&
|
contextSlots.value.bodyCell &&
|
||||||
!column.slots?.customRender
|
!column.slots?.customRender
|
||||||
) {
|
) {
|
||||||
const child = renderSlot(
|
const child = customRenderSlot(
|
||||||
contextSlots.value,
|
contextSlots.value,
|
||||||
'bodyCell',
|
'bodyCell',
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { warning } from '../../vc-util/warning';
|
import { warning } from '../../vc-util/warning';
|
||||||
import type { ComputedRef, Ref } from 'vue';
|
import type { ComputedRef, Ref } from 'vue';
|
||||||
import { renderSlot, computed, watchEffect } from 'vue';
|
import { computed, watchEffect } from 'vue';
|
||||||
import type {
|
import type {
|
||||||
ColumnsType,
|
ColumnsType,
|
||||||
ColumnType,
|
ColumnType,
|
||||||
|
@ -14,6 +14,7 @@ import type {
|
||||||
import { INTERNAL_COL_DEFINE } from '../utils/legacyUtil';
|
import { INTERNAL_COL_DEFINE } from '../utils/legacyUtil';
|
||||||
import { EXPAND_COLUMN } from '../constant';
|
import { EXPAND_COLUMN } from '../constant';
|
||||||
import { useInjectSlots } from '../../table/context';
|
import { useInjectSlots } from '../../table/context';
|
||||||
|
import { customRenderSlot } from '../../_util/vnode';
|
||||||
|
|
||||||
function flatColumns<RecordType>(columns: ColumnsType<RecordType>): ColumnType<RecordType>[] {
|
function flatColumns<RecordType>(columns: ColumnsType<RecordType>): ColumnType<RecordType>[] {
|
||||||
return columns.reduce((list, column) => {
|
return columns.reduce((list, column) => {
|
||||||
|
@ -179,7 +180,7 @@ function useColumns<RecordType>(
|
||||||
class: `${prefixCls.value}-expand-icon-col`,
|
class: `${prefixCls.value}-expand-icon-col`,
|
||||||
columnType: 'EXPAND_COLUMN',
|
columnType: 'EXPAND_COLUMN',
|
||||||
},
|
},
|
||||||
title: renderSlot(contextSlots.value, 'expandColumnTitle', {}, () => ['']),
|
title: customRenderSlot(contextSlots.value, 'expandColumnTitle', {}, () => ['']),
|
||||||
fixed: fixedColumn,
|
fixed: fixedColumn,
|
||||||
class: `${prefixCls.value}-row-expand-icon-cell`,
|
class: `${prefixCls.value}-row-expand-icon-cell`,
|
||||||
width: expandColumnWidth.value,
|
width: expandColumnWidth.value,
|
||||||
|
|
Loading…
Reference in New Issue