Skip to content

Commit d870f3f

Browse files
authored
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 test
1 parent c717473 commit d870f3f

File tree

6 files changed

+74
-8
lines changed

6 files changed

+74
-8
lines changed

Diff for: components/_util/__mocks__/RenderSlot.tsx

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { defineComponent } from 'vue';
2+
import { customRenderSlot } from '../vnode';
3+
4+
export default defineComponent({
5+
name: 'RenderSlot',
6+
setup(_props, { slots }) {
7+
return () => {
8+
return customRenderSlot(slots, 'default', {}, () => ['default value']);
9+
};
10+
},
11+
});

Diff for: components/_util/__tests__/vNode.test.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import RenderSlot from '../__mocks__/RenderSlot';
2+
import { mount } from '@vue/test-utils';
3+
import { nextTick } from 'vue';
4+
5+
describe('render slot content', () => {
6+
it('renders slot content', () => {
7+
const wrapper = mount(RenderSlot, {
8+
slots: {
9+
default: () => 'This is slot content',
10+
},
11+
});
12+
13+
expect(wrapper.html()).toContain('This is slot content');
14+
});
15+
16+
it('render default value when slot is fragment', async () => {
17+
const wrapper = mount(RenderSlot, {
18+
slots: {
19+
default: () => <></>,
20+
},
21+
});
22+
23+
await nextTick();
24+
expect(wrapper.html()).toContain('default value');
25+
});
26+
});

Diff for: components/_util/vnode.ts

+27-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { filterEmpty } from './props-util';
2-
import type { VNode, VNodeProps } from 'vue';
3-
import { cloneVNode, isVNode, render as VueRender } from 'vue';
2+
import type { Slots, VNode, VNodeArrayChildren, VNodeProps } from 'vue';
3+
import { cloneVNode, isVNode, Comment, Fragment, render as VueRender } from 'vue';
44
import warning from './warning';
55
import type { RefObject } from './createRef';
66
type NodeProps = Record<string, any> &
@@ -55,3 +55,28 @@ export function deepCloneElement<T, U>(
5555
export function triggerVNodeUpdate(vm: VNode, attrs: Record<string, any>, dom: any) {
5656
VueRender(cloneVNode(vm, { ...attrs }), dom);
5757
}
58+
59+
const ensureValidVNode = (slot: VNodeArrayChildren | null) => {
60+
return (slot || []).some(child => {
61+
if (!isVNode(child)) return true;
62+
if (child.type === Comment) return false;
63+
if (child.type === Fragment && !ensureValidVNode(child.children as VNodeArrayChildren))
64+
return false;
65+
return true;
66+
})
67+
? slot
68+
: null;
69+
};
70+
71+
export function customRenderSlot(
72+
slots: Slots,
73+
name: string,
74+
props: Record<string, unknown>,
75+
fallback?: () => VNodeArrayChildren,
76+
) {
77+
const slot = slots[name]?.(props);
78+
if (ensureValidVNode(slot)) {
79+
return slot;
80+
}
81+
return fallback?.();
82+
}

Diff for: components/card/Card.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { VNodeTypes, PropType, VNode, ExtractPropTypes, CSSProperties } from 'vue';
2-
import { isVNode, defineComponent, renderSlot } from 'vue';
2+
import { isVNode, defineComponent } from 'vue';
33
import Tabs from '../tabs';
44
import PropTypes from '../_util/vue-types';
55
import { flattenChildren, isEmptyElement, filterEmptyWithUndefined } from '../_util/props-util';
@@ -10,6 +10,8 @@ import devWarning from '../vc-util/devWarning';
1010
import useStyle from './style';
1111
import Skeleton from '../skeleton';
1212
import type { CustomSlotsType } from '../_util/type';
13+
import { customRenderSlot } from '../_util/vnode';
14+
1315
export interface CardTabListType {
1416
key: string;
1517
tab: any;
@@ -152,7 +154,7 @@ const Card = defineComponent({
152154
`tabList slots is deprecated, Please use \`customTab\` instead.`,
153155
);
154156
let tab = temp !== undefined ? temp : slots[name] ? slots[name](item) : null;
155-
tab = renderSlot(slots, 'customTab', item as any, () => [tab]);
157+
tab = customRenderSlot(slots, 'customTab', item as any, () => [tab]);
156158
return <TabPane tab={tab} key={item.key} disabled={item.disabled} />;
157159
})}
158160
</Tabs>

Diff for: components/vc-table/Cell/index.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import classNames from '../../_util/classNames';
22
import { filterEmpty, flattenChildren, isValidElement } from '../../_util/props-util';
33
import type { CSSProperties, VNodeArrayChildren } from 'vue';
4-
import { Text, computed, defineComponent, isVNode, renderSlot } from 'vue';
4+
import { Text, computed, defineComponent, isVNode } from 'vue';
55

66
import type {
77
DataIndex,
@@ -23,6 +23,7 @@ import { useInjectSticky } from '../context/StickyContext';
2323
import { warning } from '../../vc-util/warning';
2424
import type { MouseEventHandler } from '../../_util/EventInterface';
2525
import eagerComputed from '../../_util/eagerComputed';
26+
import { customRenderSlot } from 'ant-design-vue/es/_util/vnode';
2627

2728
/** Check if cell is in hover range */
2829
function inHoverRange(cellStartRow: number, cellRowSpan: number, startRow: number, endRow: number) {
@@ -223,7 +224,7 @@ export default defineComponent<CellProps>({
223224
contextSlots.value.bodyCell &&
224225
!column.slots?.customRender
225226
) {
226-
const child = renderSlot(
227+
const child = customRenderSlot(
227228
contextSlots.value,
228229
'bodyCell',
229230
{

Diff for: components/vc-table/hooks/useColumns.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { warning } from '../../vc-util/warning';
22
import type { ComputedRef, Ref } from 'vue';
3-
import { renderSlot, computed, watchEffect } from 'vue';
3+
import { computed, watchEffect } from 'vue';
44
import type {
55
ColumnsType,
66
ColumnType,
@@ -14,6 +14,7 @@ import type {
1414
import { INTERNAL_COL_DEFINE } from '../utils/legacyUtil';
1515
import { EXPAND_COLUMN } from '../constant';
1616
import { useInjectSlots } from '../../table/context';
17+
import { customRenderSlot } from '../../_util/vnode';
1718

1819
function flatColumns<RecordType>(columns: ColumnsType<RecordType>): ColumnType<RecordType>[] {
1920
return columns.reduce((list, column) => {
@@ -179,7 +180,7 @@ function useColumns<RecordType>(
179180
class: `${prefixCls.value}-expand-icon-col`,
180181
columnType: 'EXPAND_COLUMN',
181182
},
182-
title: renderSlot(contextSlots.value, 'expandColumnTitle', {}, () => ['']),
183+
title: customRenderSlot(contextSlots.value, 'expandColumnTitle', {}, () => ['']),
183184
fixed: fixedColumn,
184185
class: `${prefixCls.value}-row-expand-icon-cell`,
185186
width: expandColumnWidth.value,

0 commit comments

Comments
 (0)