diff --git a/package.json b/package.json index 29e2cf9893..bce3485c4a 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "rollup-plugin-styles": "^4.0.0", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-typescript2": "^0.31.2", - "typescript": "5.6.2", + "typescript": "^6.0.3", "vitest": "^2.1.1" }, "dependencies": { diff --git a/packages/components/affix/Affix.tsx b/packages/components/affix/Affix.tsx index fcf8ba2840..9d41c08df4 100644 --- a/packages/components/affix/Affix.tsx +++ b/packages/components/affix/Affix.tsx @@ -26,8 +26,8 @@ const Affix = forwardRef((props, ref) => { const affixRef = useRef(null); const affixWrapRef = useRef(null); - const placeholderEL = useRef(null); - const scrollContainer = useRef(null); + const placeholderEL = useRef(null); + const scrollContainer = useRef(null); const ticking = useRef(false); @@ -35,6 +35,9 @@ const Affix = forwardRef((props, ref) => { const handleScroll = useCallback(() => { if (!ticking.current) { requestAnimationFrame(() => { + if (!scrollContainer.current) return; + if (!placeholderEL.current) return; + if (!affixWrapRef.current) return; // top = 节点到页面顶部的距离,包含 scroll 中的高度 const { top: wrapToTop = 0, @@ -67,8 +70,13 @@ const Affix = forwardRef((props, ref) => { fixedTop = false; } } else { - const containerHeight = - scrollContainer.current?.[isWindow(scrollContainer.current) ? 'innerHeight' : 'clientHeight'] - wrapHeight; + let containerHeight = 0; + if (isWindow(scrollContainer.current)) { + containerHeight = scrollContainer.current.innerHeight - wrapHeight; + } else { + containerHeight = scrollContainer.current?.clientHeight - wrapHeight; + } + const calcBottom = containerToTop + containerHeight - (offsetBottom ?? 0); // 计算 bottom 相对应的 top 值 if (calcTop <= offsetTop) { // top 的触发 diff --git a/packages/components/anchor/__tests__/anchor.test.tsx b/packages/components/anchor/__tests__/anchor.test.tsx index e6b1e8a2b3..c118f8b10d 100644 --- a/packages/components/anchor/__tests__/anchor.test.tsx +++ b/packages/components/anchor/__tests__/anchor.test.tsx @@ -56,7 +56,7 @@ describe('Anchor 组件测试', () => { ); const anchorItem = wrapper.getByTestId(childTestID); fireEvent.click(anchorItem.firstChild); - expect(fn).toBeCalledTimes(1); + expect(fn).toHaveBeenCalledTimes(1); }); test('render AnchorTarget', async () => { diff --git a/packages/components/avatar/Avatar.tsx b/packages/components/avatar/Avatar.tsx index 41bf581e6a..861e83e386 100644 --- a/packages/components/avatar/Avatar.tsx +++ b/packages/components/avatar/Avatar.tsx @@ -40,7 +40,7 @@ const Avatar = forwardRefWithStatics( imageProps, className, ...avatarProps - } = useDefaultProps(props, avatarDefaultProps); + } = useDefaultProps(props, avatarDefaultProps); const groupSize = useContext(AvatarContext); const { classPrefix } = useConfig(); diff --git a/packages/components/calendar/__tests__/calendar.test.tsx b/packages/components/calendar/__tests__/calendar.test.tsx index 3669084f5f..df29bcc33e 100644 --- a/packages/components/calendar/__tests__/calendar.test.tsx +++ b/packages/components/calendar/__tests__/calendar.test.tsx @@ -12,7 +12,7 @@ describe('Calendar测试', () => { describe(':props', () => { test(':theme', () => { const { container } = render(); - expect(container.firstChild.classList.contains('t-calendar--card')).toBeTruthy(); + expect(container.children[0].classList.contains('t-calendar--card')).toBeTruthy(); }); test('fillWithZero', () => { diff --git a/packages/components/checkbox/__tests__/checkbox.test.tsx b/packages/components/checkbox/__tests__/checkbox.test.tsx index a2553948dd..2645000fee 100644 --- a/packages/components/checkbox/__tests__/checkbox.test.tsx +++ b/packages/components/checkbox/__tests__/checkbox.test.tsx @@ -20,7 +20,7 @@ describe('Checkbox', () => { const { container } = render(); expect(container.firstChild).toHaveClass('t-is-disabled'); fireEvent.click(container.firstChild); - expect(fn).toBeCalledTimes(0); + expect(fn).toHaveBeenCalledTimes(0); }); test('indeterminate', () => { @@ -37,7 +37,7 @@ describe('Checkbox', () => { const fn = vi.fn(); const { container } = render(); fireEvent.click(container.firstChild); - expect(fn).toBeCalledTimes(0); + expect(fn).toHaveBeenCalledTimes(0); }); }); @@ -65,7 +65,7 @@ describe('CheckboxGroup', () => { , ); fireEvent.click(container.firstChild.firstChild); - expect(fn).toBeCalledTimes(1); + expect(fn).toHaveBeenCalledTimes(1); }); test('option', () => { diff --git a/packages/components/color-picker/__tests__/color-picker.test.tsx b/packages/components/color-picker/__tests__/color-picker.test.tsx index c589abf2b8..733d026989 100644 --- a/packages/components/color-picker/__tests__/color-picker.test.tsx +++ b/packages/components/color-picker/__tests__/color-picker.test.tsx @@ -135,6 +135,6 @@ describe('ColorPickerPanel 组件测试', () => { fireEvent.click(container.querySelector('.t-icon-delete')); expect(container.querySelector('.t-icon-delete')).toBeNull(); expect(container.querySelector('.t-is-active')).toBeNull(); - expect(onRecentColorsChange).toBeCalled(); + expect(onRecentColorsChange).toHaveBeenCalled(); }); }); diff --git a/packages/components/config-provider/_example/table.tsx b/packages/components/config-provider/_example/table.tsx index 2af1b352ad..398b8e10b0 100644 --- a/packages/components/config-provider/_example/table.tsx +++ b/packages/components/config-provider/_example/table.tsx @@ -41,8 +41,8 @@ export default function configDemo() { table: { // 支持 String 和 Function 两种数据类型 empty: 'Empty Data', - expandIcon: () => , - sortIcon: () => , + expandIcon: , + sortIcon: , // More config // filterIcon: () => Filter, diff --git a/packages/components/date-picker/__tests__/date-picker-panel.test.tsx b/packages/components/date-picker/__tests__/date-picker-panel.test.tsx index 9d7ca29fa3..70d65ad191 100644 --- a/packages/components/date-picker/__tests__/date-picker-panel.test.tsx +++ b/packages/components/date-picker/__tests__/date-picker-panel.test.tsx @@ -108,7 +108,7 @@ describe('DatePickerPanel', () => { const { container } = render(); fireEvent.click(container.querySelector('.t-date-picker__cell')); - expect(fn).toBeCalledTimes(1); + expect(fn).toHaveBeenCalledTimes(1); }); test('onJumperClick', async () => { @@ -117,11 +117,11 @@ describe('DatePickerPanel', () => { const jumperPrev = container.querySelector('.t-pagination-mini__prev'); fireEvent.click(jumperPrev); - expect(fn).toBeCalledTimes(1); + expect(fn).toHaveBeenCalledTimes(1); const jumperNext = container.querySelector('.t-pagination-mini__next'); fireEvent.click(jumperNext); - expect(fn).toBeCalledTimes(2); + expect(fn).toHaveBeenCalledTimes(2); const jumperCurrent = container.querySelector('.t-pagination-mini__current'); fireEvent.click(jumperCurrent); @@ -140,7 +140,7 @@ describe('DatePickerPanel', () => { const christmasBtn = getByText('圣诞节'); fireEvent.click(christmasBtn); - expect(fn).toBeCalledTimes(1); + expect(fn).toHaveBeenCalledTimes(1); }); test('onYearChange & onMonthChange', async () => { diff --git a/packages/components/date-picker/__tests__/date-picker.test.tsx b/packages/components/date-picker/__tests__/date-picker.test.tsx index 0e8f67700e..d13d09ba51 100644 --- a/packages/components/date-picker/__tests__/date-picker.test.tsx +++ b/packages/components/date-picker/__tests__/date-picker.test.tsx @@ -199,9 +199,9 @@ describe('DatePicker', () => { const { container } = render(); const InputDom = container.querySelector('.t-input__inner'); fireEvent.focus(InputDom); - expect(focusFn).toBeCalledTimes(1); + expect(focusFn).toHaveBeenCalledTimes(1); fireEvent.blur(InputDom); - expect(blurFn).toBeCalledTimes(1); + expect(blurFn).toHaveBeenCalledTimes(1); }); test('onChange onPick', async () => { @@ -212,8 +212,8 @@ describe('DatePicker', () => { const firstDay = document.querySelector('.t-date-picker__cell--first-day-of-month'); fireEvent.click(firstDay); - expect(changeFn).toBeCalledTimes(1); - expect(pickFn).toBeCalledTimes(1); + expect(changeFn).toHaveBeenCalledTimes(1); + expect(pickFn).toHaveBeenCalledTimes(1); }); test('onChange onPick', async () => { @@ -224,8 +224,8 @@ describe('DatePicker', () => { const firstDay = await waitFor(() => document.querySelector('.t-date-picker__cell--first-day-of-month')); fireEvent.click(firstDay); - expect(changeFn).toBeCalledTimes(1); - expect(pickFn).toBeCalledTimes(1); + expect(changeFn).toHaveBeenCalledTimes(1); + expect(pickFn).toHaveBeenCalledTimes(1); }); test('onYearChange', async () => { @@ -241,7 +241,7 @@ describe('DatePicker', () => { const yearOptionNode = await waitFor(() => document.querySelector('.t-popup .t-select-option span[title="2021"]')); fireEvent.click(yearOptionNode); - expect(yearChangeFn).toBeCalledTimes(1); + expect(yearChangeFn).toHaveBeenCalledTimes(1); }); test('onMonthChange', async () => { @@ -265,7 +265,7 @@ describe('DatePicker', () => { const monthOptionNode = await waitFor(() => document.querySelector('.t-popup .t-select-option span[title="1 月"]')); fireEvent.click(monthOptionNode); - expect(monthChangeFn).toBeCalledTimes(1); + expect(monthChangeFn).toHaveBeenCalledTimes(1); }); test('panel select month and year', async () => { @@ -320,7 +320,7 @@ describe('DatePicker', () => { test('cell handleMouseEnter', async () => { const { container, getByText } = render(); - const inputEle = container.querySelector('.t-input__inner'); + const inputEle = container.querySelector('.t-input__inner') as HTMLInputElement; fireEvent.mouseDown(inputEle); const cellBtn = getByText('25'); @@ -332,7 +332,7 @@ describe('DatePicker', () => { test('cell handleClick', async () => { const { container, getByText } = render(); - const inputEle = container.querySelector('.t-input__inner'); + const inputEle = container.querySelector('.t-input__inner') as HTMLInputElement; fireEvent.mouseDown(inputEle); const cellBtn = getByText('25'); @@ -342,7 +342,7 @@ describe('DatePicker', () => { test('onJumperClick', async () => { const { container, getByText } = render(); - const inputEle = container.querySelector('.t-input__inner'); + const inputEle = container.querySelector('.t-input__inner') as HTMLInputElement; fireEvent.mouseDown(inputEle); const jumperPrev = await waitFor(() => document.querySelector('.t-pagination-mini__prev')); diff --git a/packages/components/date-picker/__tests__/date-range-picker-panel.test.tsx b/packages/components/date-picker/__tests__/date-range-picker-panel.test.tsx index 7dc63af085..27fe63441d 100644 --- a/packages/components/date-picker/__tests__/date-range-picker-panel.test.tsx +++ b/packages/components/date-picker/__tests__/date-range-picker-panel.test.tsx @@ -116,7 +116,7 @@ describe('DateRangePickerPanel', () => { fireEvent.click(container.querySelector('.t-date-picker__cell')); fireEvent.click(container.querySelector('.t-date-picker__cell')); - expect(fn).toBeCalledTimes(1); + expect(fn).toHaveBeenCalledTimes(1); }); test('onJumperClick', async () => { @@ -125,7 +125,7 @@ describe('DateRangePickerPanel', () => { const jumperPrev = container.querySelector('.t-pagination-mini__prev'); fireEvent.click(jumperPrev); - expect(fn).toBeCalledTimes(1); + expect(fn).toHaveBeenCalledTimes(1); }); test('onTimePickerChange & onConfirmClick', async () => { @@ -140,13 +140,15 @@ describe('DateRangePickerPanel', () => { const { getByText } = render( , ); const christmasBtn = getByText('圣诞节'); fireEvent.click(christmasBtn); - expect(fn).toBeCalledTimes(1); + expect(fn).toHaveBeenCalledTimes(1); }); test('onYearChange & onMonthChange', async () => { @@ -201,7 +203,11 @@ describe('DateRangePickerPanel', () => { test('onPresetClick', async () => { const { container, getByText } = render( - , + , ); const inputEle = container.querySelector('.t-input__inner'); fireEvent.mouseDown(inputEle); diff --git a/packages/components/date-picker/__tests__/date-range-picker.test.tsx b/packages/components/date-picker/__tests__/date-range-picker.test.tsx index 4fc45e524a..cfa6775ef1 100644 --- a/packages/components/date-picker/__tests__/date-range-picker.test.tsx +++ b/packages/components/date-picker/__tests__/date-range-picker.test.tsx @@ -168,9 +168,9 @@ describe('DateRangePicker', () => { const { container } = render(); const InputDom = container.querySelector('.t-input__inner'); fireEvent.focus(InputDom); - expect(focusFn).toBeCalledTimes(1); + expect(focusFn).toHaveBeenCalledTimes(1); fireEvent.blur(InputDom); - expect(blurFn).toBeCalledTimes(1); + expect(blurFn).toHaveBeenCalledTimes(1); }); it('onChange onPick onInput', async () => { @@ -185,8 +185,8 @@ describe('DateRangePicker', () => { fireEvent.click(firstTBody.firstChild.firstChild.firstChild); fireEvent.click(firstTBody.firstChild.firstChild.firstChild); - expect(changeFn).toBeCalledTimes(2); - expect(pickFn).toBeCalledTimes(2); + expect(changeFn).toHaveBeenCalledTimes(2); + expect(pickFn).toHaveBeenCalledTimes(2); }); it('panel select month and year', async () => { @@ -264,7 +264,11 @@ describe('DateRangePicker', () => { test('onPresetClick', async () => { const { container } = render( - , + , ); const inputEle = container.querySelector('.t-input__inner'); fireEvent.mouseDown(inputEle); diff --git a/packages/components/drawer/__tests__/drawer.test.tsx b/packages/components/drawer/__tests__/drawer.test.tsx index dafa182b4a..495a514965 100644 --- a/packages/components/drawer/__tests__/drawer.test.tsx +++ b/packages/components/drawer/__tests__/drawer.test.tsx @@ -130,8 +130,8 @@ describe('test Drawer', () => { const onCancelFn = vi.fn(); const { getByText } = render(); fireEvent.click(getByText('Open')); - expect(onCancelFn).not.toBeCalled(); + expect(onCancelFn).not.toHaveBeenCalled(); fireEvent.click(getByText('取消')); - expect(onCancelFn).toBeCalled(); + expect(onCancelFn).toHaveBeenCalled(); }); }); diff --git a/packages/components/form/hooks/useInstance.tsx b/packages/components/form/hooks/useInstance.tsx index 51e2ec25cf..4d8fa3c0d5 100644 --- a/packages/components/form/hooks/useInstance.tsx +++ b/packages/components/form/hooks/useInstance.tsx @@ -214,7 +214,7 @@ export default function useInstance( } else { const { type = 'initial', fields = [] } = params; fields.forEach((name) => { - const formItemRef = findFormItem(name, formMapRef); + const formItemRef = findFormItem(name as NamePath, formMapRef); formItemRef?.current?.resetField(type); }); } @@ -235,7 +235,7 @@ export default function useInstance( } else { if (!Array.isArray(fields)) throw new TypeError('The parameter of "clearValidate" must be an array'); fields.forEach((name) => { - const formItemRef = findFormItem(name, formMapRef); + const formItemRef = findFormItem(name as NamePath, formMapRef); formItemRef?.current?.resetValidate(); }); } @@ -259,7 +259,7 @@ export default function useInstance( ? [...formMapRef.current.values()] : fields .map((name) => { - const formItemRef = findFormItem(name, formMapRef); + const formItemRef = findFormItem(name as NamePath, formMapRef); return formItemRef; }) .filter(Boolean); diff --git a/packages/components/grid/__tests__/grid.test.tsx b/packages/components/grid/__tests__/grid.test.tsx index 9c362acbe2..b8136a6c8a 100644 --- a/packages/components/grid/__tests__/grid.test.tsx +++ b/packages/components/grid/__tests__/grid.test.tsx @@ -39,10 +39,12 @@ describe('Grid 组件测试', () => { // Array const { container: container3 } = render( , @@ -50,7 +52,7 @@ describe('Grid 组件测试', () => { // Object const { container: container4 } = render( - + , ); diff --git a/packages/components/image-viewer/__tests__/image-viewer.test.tsx b/packages/components/image-viewer/__tests__/image-viewer.test.tsx index 3752a9476a..3ee8022750 100644 --- a/packages/components/image-viewer/__tests__/image-viewer.test.tsx +++ b/packages/components/image-viewer/__tests__/image-viewer.test.tsx @@ -707,7 +707,11 @@ describe('ImageViewerModal 滚轮向中心缩放', () => { }); await mockDelay(); - const wheelEvent = new WheelEvent('wheel', { deltaY: -120, bubbles: true, cancelable: true }); + const wheelEvent = new WheelEvent('wheel', { + deltaY: -120, + bubbles: true, + cancelable: true, + }); const preventDefaultSpy = vi.spyOn(wheelEvent, 'preventDefault'); act(() => { @@ -1014,7 +1018,10 @@ describe('onClose trigger 来源', () => { act(() => { fireEvent.click(closeBtn); }); - expect(onClose).toHaveBeenCalledWith({ trigger: 'close-btn', e: expect.any(Object) }); + expect(onClose).toHaveBeenCalledWith({ + trigger: 'close-btn', + e: expect.any(Object), + }); }); test('点击遮罩时 trigger 为 overlay', async () => { @@ -1035,7 +1042,10 @@ describe('onClose trigger 来源', () => { act(() => { fireEvent.click(mask); }); - expect(onClose).toHaveBeenCalledWith({ trigger: 'overlay', e: expect.any(Object) }); + expect(onClose).toHaveBeenCalledWith({ + trigger: 'overlay', + e: expect.any(Object), + }); }); test('ESC 关闭时 trigger 为 esc', async () => { @@ -1053,7 +1063,10 @@ describe('onClose trigger 来源', () => { await mockDelay(); await user.type(document.body, '{Escape}'); - expect(onClose).toHaveBeenCalledWith({ trigger: 'esc', e: expect.any(Object) }); + expect(onClose).toHaveBeenCalledWith({ + trigger: 'esc', + e: expect.any(Object), + }); }); }); @@ -1271,17 +1284,12 @@ describe('closeBtn 为函数', () => { test('closeBtn 为函数时渲染自定义关闭按钮', async () => { const BasicImageViewer = () => { const trigger = ({ open }) => open()}>函数关闭按钮; - return ( - ( - - )} - /> + const CloseBtnNode = ({ onClose }: any) => ( + ); + return } />; }; render(); diff --git a/packages/components/image-viewer/__tests__/utils.test.ts b/packages/components/image-viewer/__tests__/utils.test.ts index a6f66d5164..792a4d8400 100644 --- a/packages/components/image-viewer/__tests__/utils.test.ts +++ b/packages/components/image-viewer/__tests__/utils.test.ts @@ -9,6 +9,8 @@ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; import { downloadImage, formatImages } from '@tdesign/common-js/image-viewer/utils'; import { act } from '@test/utils'; +import type { ImageInfo } from '../type'; + // ─── formatImages ──────────────────────────────────────────────────────── describe('formatImages 图片格式化', () => { test('非数组输入返回空数组', () => { @@ -36,8 +38,16 @@ describe('formatImages 图片格式化', () => { const images = [{ mainImage: 'main1.jpg' }, { mainImage: 'main2.jpg', thumbnail: 'thumb2.jpg' }]; const result = formatImages(images); - expect(result[0]).toEqual({ mainImage: 'main1.jpg', thumbnail: 'main1.jpg', download: true }); - expect(result[1]).toEqual({ mainImage: 'main2.jpg', thumbnail: 'thumb2.jpg', download: true }); + expect(result[0]).toEqual({ + mainImage: 'main1.jpg', + thumbnail: 'main1.jpg', + download: true, + }); + expect(result[1]).toEqual({ + mainImage: 'main2.jpg', + thumbnail: 'thumb2.jpg', + download: true, + }); }); test('自定义 download 设置被保留', () => { @@ -51,8 +61,16 @@ describe('formatImages 图片格式化', () => { const result = formatImages(images); expect(result).toEqual([ - { mainImage: 'string-image.jpg', thumbnail: 'string-image.jpg', download: true }, - { mainImage: 'object-main.jpg', thumbnail: 'object-thumb.jpg', download: true }, + { + mainImage: 'string-image.jpg', + thumbnail: 'string-image.jpg', + download: true, + }, + { + mainImage: 'object-main.jpg', + thumbnail: 'object-thumb.jpg', + download: true, + }, ]); }); @@ -66,9 +84,21 @@ describe('formatImages 图片格式化', () => { }); test('ImageInfo 包含全部属性', () => { - const images = [{ mainImage: 'main.jpg', thumbnail: 'thumb.jpg', download: true, isSvg: true }]; + const images = [ + { + mainImage: 'main.jpg', + thumbnail: 'thumb.jpg', + download: true, + isSvg: true, + }, + ]; const result = formatImages(images); - expect(result[0]).toEqual({ mainImage: 'main.jpg', thumbnail: 'thumb.jpg', download: true, isSvg: true }); + expect(result[0]).toEqual({ + mainImage: 'main.jpg', + thumbnail: 'thumb.jpg', + download: true, + isSvg: true, + }); }); test('thumbnail 默认等于 mainImage', () => { @@ -111,7 +141,12 @@ describe('downloadImage 图片下载', () => { test('File 输入使用 URL.createObjectURL', () => { const mockClick = vi.fn(); const mockRemove = vi.fn(); - const mockAnchor = { href: '', download: '', click: mockClick, remove: mockRemove }; + const mockAnchor = { + href: '', + download: '', + click: mockClick, + remove: mockRemove, + }; vi.spyOn(document, 'createElement').mockImplementation((tag) => { if (tag === 'a') return mockAnchor as unknown as HTMLAnchorElement; @@ -129,7 +164,12 @@ describe('downloadImage 图片下载', () => { test('同源 URL 直接下载', () => { const mockClick = vi.fn(); const mockRemove = vi.fn(); - const mockAnchor = { href: '', download: '', click: mockClick, remove: mockRemove }; + const mockAnchor = { + href: '', + download: '', + click: mockClick, + remove: mockRemove, + }; vi.spyOn(document, 'createElement').mockImplementation((tag) => { if (tag === 'a') return mockAnchor as unknown as HTMLAnchorElement; @@ -147,7 +187,12 @@ describe('downloadImage 图片下载', () => { test('从带查询参数的 URL 提取文件名', () => { const mockClick = vi.fn(); const mockRemove = vi.fn(); - const mockAnchor = { href: '', download: '', click: mockClick, remove: mockRemove }; + const mockAnchor = { + href: '', + download: '', + click: mockClick, + remove: mockRemove, + }; vi.spyOn(document, 'createElement').mockImplementation((tag) => { if (tag === 'a') return mockAnchor as unknown as HTMLAnchorElement; @@ -162,7 +207,12 @@ describe('downloadImage 图片下载', () => { test('从带 hash 的 URL 提取文件名', () => { const mockClick = vi.fn(); const mockRemove = vi.fn(); - const mockAnchor = { href: '', download: '', click: mockClick, remove: mockRemove }; + const mockAnchor = { + href: '', + download: '', + click: mockClick, + remove: mockRemove, + }; vi.spyOn(document, 'createElement').mockImplementation((tag) => { if (tag === 'a') return mockAnchor as unknown as HTMLAnchorElement; @@ -184,7 +234,12 @@ describe('downloadImage 图片下载', () => { const mockClick = vi.fn(); const mockRemove = vi.fn(); - const mockAnchor = { href: '', download: '', click: mockClick, remove: mockRemove }; + const mockAnchor = { + href: '', + download: '', + click: mockClick, + remove: mockRemove, + }; vi.spyOn(document, 'createElement').mockImplementation((tag) => { if (tag === 'a') return mockAnchor as unknown as HTMLAnchorElement; return mockCreateElement(tag); @@ -208,7 +263,10 @@ describe('downloadImage 图片下载', () => { }; let onloadFn: (() => void) | null = null; - const mockImage: Partial & { width: number; height: number } = { + const mockImage: Partial & { + width: number; + height: number; + } = { setAttribute: vi.fn(), width: 100, height: 80, @@ -228,7 +286,12 @@ describe('downloadImage 图片下载', () => { }); const mockBlobClick = vi.fn(); - const mockBlobAnchor = { href: '', download: '', click: mockBlobClick, remove: vi.fn() }; + const mockBlobAnchor = { + href: '', + download: '', + click: mockBlobClick, + remove: vi.fn(), + }; vi.spyOn(document, 'createElement').mockImplementation((tag) => { if (tag === 'canvas') return mockCanvas as unknown as HTMLCanvasElement; if (tag === 'a') return mockBlobAnchor as unknown as HTMLAnchorElement; @@ -249,7 +312,12 @@ describe('downloadImage 图片下载', () => { test('URL 无文件名时使用随机名称', () => { const mockClick = vi.fn(); const mockRemove = vi.fn(); - const mockAnchor = { href: '', download: '', click: mockClick, remove: mockRemove }; + const mockAnchor = { + href: '', + download: '', + click: mockClick, + remove: mockRemove, + }; vi.spyOn(document, 'createElement').mockImplementation((tag) => { if (tag === 'a') return mockAnchor as unknown as HTMLAnchorElement; @@ -265,7 +333,12 @@ describe('downloadImage 图片下载', () => { test('URL 含多个 / 和复杂路径时正确提取文件名', () => { const mockClick = vi.fn(); const mockRemove = vi.fn(); - const mockAnchor = { href: '', download: '', click: mockClick, remove: mockRemove }; + const mockAnchor = { + href: '', + download: '', + click: mockClick, + remove: mockRemove, + }; vi.spyOn(document, 'createElement').mockImplementation((tag) => { if (tag === 'a') return mockAnchor as unknown as HTMLAnchorElement; @@ -280,7 +353,12 @@ describe('downloadImage 图片下载', () => { test('File 对象下载后调用 revokeObjectURL', () => { const mockClick = vi.fn(); const mockRemove = vi.fn(); - const mockAnchor = { href: '', download: '', click: mockClick, remove: mockRemove }; + const mockAnchor = { + href: '', + download: '', + click: mockClick, + remove: mockRemove, + }; vi.spyOn(document, 'createElement').mockImplementation((tag) => { if (tag === 'a') return mockAnchor as unknown as HTMLAnchorElement; @@ -300,7 +378,10 @@ describe('downloadImage 图片下载', () => { const crossOriginUrl = 'https://other.com/photo.jpg'; let onloadFn: (() => void) | null = null; - const mockImage: Partial & { width: number; height: number } = { + const mockImage: Partial & { + width: number; + height: number; + } = { setAttribute: vi.fn(), width: 100, height: 100, @@ -321,7 +402,12 @@ describe('downloadImage 图片下载', () => { }; const mockBlobClick = vi.fn(); - const mockBlobAnchor = { href: '', download: '', click: mockBlobClick, remove: vi.fn() }; + const mockBlobAnchor = { + href: '', + download: '', + click: mockBlobClick, + remove: vi.fn(), + }; vi.spyOn(document, 'createElement').mockImplementation((tag) => { if (tag === 'canvas') return mockCanvas as unknown as HTMLCanvasElement; if (tag === 'a') return mockBlobAnchor as unknown as HTMLAnchorElement; diff --git a/packages/components/input-number/__tests__/input-number.test.tsx b/packages/components/input-number/__tests__/input-number.test.tsx index 0fba598aa6..7231b5fd91 100644 --- a/packages/components/input-number/__tests__/input-number.test.tsx +++ b/packages/components/input-number/__tests__/input-number.test.tsx @@ -13,12 +13,12 @@ describe('InputNumber 组件测试', () => { const { container, queryByPlaceholderText } = render( , ); - expect(container.firstChild.classList.contains('t-input-number')).toBeTruthy(); + expect(container.children[0].classList.contains('t-input-number')).toBeTruthy(); expect(queryByPlaceholderText(InputNumberPlaceholder)).toBeInTheDocument(); fireEvent.change(queryByPlaceholderText(InputNumberPlaceholder), { target: { value: InputNumberValue }, }); - expect(changeFn).toBeCalledTimes(1); + expect(changeFn).toHaveBeenCalledTimes(1); expect(changeFn.mock.calls[0][0]).toBe(InputNumberValue); }); @@ -29,7 +29,7 @@ describe('InputNumber 组件测试', () => { fireEvent.mouseEnter(container.firstChild); fireEvent.click(container.querySelector('.t-input-number__increase')); - expect(queryByPlaceholderText(InputNumberPlaceholder).value).toEqual('6'); + expect((queryByPlaceholderText(InputNumberPlaceholder) as HTMLInputElement).value).toEqual('6'); }); test('autofocus', () => { @@ -44,7 +44,7 @@ describe('InputNumber 组件测试', () => { const InputDom = queryByPlaceholderText(InputNumberPlaceholder); fireEvent.change(InputDom, { target: { value: 1 } }); fireEvent.blur(InputDom); - expect(blurFn).toBeCalledTimes(1); + expect(blurFn).toHaveBeenCalledTimes(1); }); test('keyDown', async () => { @@ -57,8 +57,8 @@ describe('InputNumber 组件测试', () => { const InputNumberDom = queryByPlaceholderText(InputNumberPlaceholder); await user.type(InputNumberDom, '123{enter}'); - expect(onEnterFn).toBeCalled(); - expect(onKeydownFn).toBeCalled(); + expect(onEnterFn).toHaveBeenCalled(); + expect(onKeydownFn).toHaveBeenCalled(); }); test('disabled', async () => { @@ -66,11 +66,11 @@ describe('InputNumber 组件测试', () => { const { queryByPlaceholderText } = render( , ); - expect(queryByPlaceholderText(InputNumberPlaceholder).disabled).toBeTruthy(); + expect((queryByPlaceholderText(InputNumberPlaceholder) as HTMLInputElement).disabled).toBeTruthy(); }); test('size', async () => { const { container } = render(); - expect(container.firstChild.classList.contains('t-size-l')).toBeTruthy(); + expect(container.children[0].classList.contains('t-size-l')).toBeTruthy(); }); }); diff --git a/packages/components/input/__tests__/input.test.tsx b/packages/components/input/__tests__/input.test.tsx index 956fb8d37a..acf778a463 100644 --- a/packages/components/input/__tests__/input.test.tsx +++ b/packages/components/input/__tests__/input.test.tsx @@ -10,10 +10,12 @@ describe('Input 组件测试', () => { test('create', async () => { const changeFn = vi.fn(); const { container, queryByPlaceholderText } = render(); - expect(container.firstChild.firstChild.classList.contains('t-input')).toBeTruthy(); + expect(container.children[0].children[0].classList.contains('t-input')).toBeTruthy(); expect(queryByPlaceholderText(InputPlaceholder)).toBeInTheDocument(); - fireEvent.change(queryByPlaceholderText(InputPlaceholder), { target: { value: InputValue } }); - expect(changeFn).toBeCalledTimes(1); + fireEvent.change(queryByPlaceholderText(InputPlaceholder), { + target: { value: InputValue }, + }); + expect(changeFn).toHaveBeenCalledTimes(1); expect(changeFn.mock.calls[0][0]).toBe(InputValue); }); test('clearable', async () => { @@ -21,15 +23,19 @@ describe('Input 组件测试', () => { const { queryByPlaceholderText, container } = render( , ); - fireEvent.change(queryByPlaceholderText(InputPlaceholder), { target: { value: InputValue } }); - expect(queryByPlaceholderText(InputPlaceholder).value).toEqual(InputValue); + fireEvent.change(queryByPlaceholderText(InputPlaceholder), { + target: { value: InputValue }, + }); + expect((queryByPlaceholderText(InputPlaceholder) as HTMLInputElement).value).toEqual(InputValue); fireEvent.mouseEnter(container.firstChild.firstChild); fireEvent.click(container.querySelector('.t-input__suffix-clear')); - expect(queryByPlaceholderText(InputPlaceholder).value).toEqual(''); + expect((queryByPlaceholderText(InputPlaceholder) as HTMLInputElement).value).toEqual(''); }); test('clearable can not work when mouseLeave', async () => { const { queryByPlaceholderText, container } = render(); - fireEvent.change(queryByPlaceholderText(InputPlaceholder), { target: { value: InputValue } }); + fireEvent.change(queryByPlaceholderText(InputPlaceholder), { + target: { value: InputValue }, + }); fireEvent.mouseEnter(container.firstChild.firstChild); expect(container.querySelector('.t-input__suffix-clear')).toBeInTheDocument(); fireEvent.mouseLeave(container.firstChild.firstChild); @@ -47,9 +53,9 @@ describe('Input 组件测试', () => { fireEvent.mouseDown(clearIcon); fireEvent.mouseUp(clearIcon); fireEvent.click(clearIcon); - expect(blurFn).toBeCalledTimes(0); + expect(blurFn).toHaveBeenCalledTimes(0); fireEvent.blur(InputDom); - expect(blurFn).toBeCalledTimes(1); + expect(blurFn).toHaveBeenCalledTimes(1); }); test('onComposition can be call', async () => { const user = userEvent.setup(); @@ -62,15 +68,15 @@ describe('Input 组件测试', () => { onCompositionend={onCompositionEndFn} />, ); - const InputDom = queryByPlaceholderText(InputPlaceholder); + const InputDom = queryByPlaceholderText(InputPlaceholder) as HTMLInputElement; await user.type(InputDom, InputValue); fireEvent.compositionStart(InputDom); await user.type(InputDom, InputValue); fireEvent.compositionEnd(InputDom); fireEvent.compositionEnd(InputDom); await user.type(InputDom, InputValue); - expect(onCompositionStartFn).toBeCalled(); - expect(onCompositionEndFn).toBeCalled(); + expect(onCompositionStartFn).toHaveBeenCalled(); + expect(onCompositionEndFn).toHaveBeenCalled(); expect(InputDom.value).toBe([InputValue, InputValue, InputValue].join('')); }); test('keyDown', async () => { @@ -82,17 +88,17 @@ describe('Input 组件测试', () => { ); const InputDom = queryByPlaceholderText(InputPlaceholder); await user.type(InputDom, 'abc{enter}'); - expect(onEnterFn).toBeCalled(); - expect(onKeydownFn).toBeCalled(); + expect(onEnterFn).toHaveBeenCalled(); + expect(onKeydownFn).toHaveBeenCalled(); }); test('disabled', async () => { const changeFn = vi.fn(); const { queryByPlaceholderText } = render(); - expect(queryByPlaceholderText(InputPlaceholder).disabled).toBeTruthy(); + expect((queryByPlaceholderText(InputPlaceholder) as HTMLInputElement).disabled).toBeTruthy(); }); test('password', async () => { const { queryByPlaceholderText, container } = render(); - expect(queryByPlaceholderText(InputPlaceholder).type).toEqual('password'); + expect((queryByPlaceholderText(InputPlaceholder) as HTMLInputElement).type).toEqual('password'); expect(container.querySelector('.t-icon-browse-off')).toBeTruthy(); fireEvent.click(container.querySelector('.t-input__suffix-clear')); @@ -107,11 +113,11 @@ describe('Input 组件测试', () => { }); test('status', async () => { const { container } = render(); - expect(container.firstChild.firstChild.classList.contains('t-is-error')).toBeTruthy(); + expect(container.children[0].children[0].classList.contains('t-is-error')).toBeTruthy(); }); test('size', async () => { const { container } = render(); - expect(container.firstChild.firstChild.classList.contains('t-size-l')).toBeTruthy(); + expect(container.children[0].children[0].classList.contains('t-size-l')).toBeTruthy(); }); test('label display', async () => { const text = 'test-label'; diff --git a/packages/components/link/__tests__/link.test.tsx b/packages/components/link/__tests__/link.test.tsx index 8d4bba06c7..98b3a71f6e 100644 --- a/packages/components/link/__tests__/link.test.tsx +++ b/packages/components/link/__tests__/link.test.tsx @@ -25,7 +25,7 @@ describe('Link', () => { expect(screen.getByTestId('disabled')).not.toHaveClass('t-link--hover-underline'); fireEvent.click(container.firstChild); - expect(fn).toBeCalledTimes(0); + expect(fn).toHaveBeenCalledTimes(0); }); test('underline', () => { diff --git a/packages/components/list/__tests__/list.test.tsx b/packages/components/list/__tests__/list.test.tsx index 09cf226cb4..75727148d9 100644 --- a/packages/components/list/__tests__/list.test.tsx +++ b/packages/components/list/__tests__/list.test.tsx @@ -31,7 +31,7 @@ describe('List 组件测试', () => { expect(container.querySelector('.t-list__load--load-more')).toBeInTheDocument(); expect(queryByText('点击加载更多')).toBeInTheDocument(); fireEvent.click(queryByText('点击加载更多')); - expect(clickFn).toBeCalledTimes(1); + expect(clickFn).toHaveBeenCalledTimes(1); }); test('onScroll', () => { diff --git a/packages/components/loading/Loading.tsx b/packages/components/loading/Loading.tsx index dffcf331e6..3913e17ed2 100644 --- a/packages/components/loading/Loading.tsx +++ b/packages/components/loading/Loading.tsx @@ -103,10 +103,10 @@ const Loading: React.FC = (props) => { }, [loading, preventScrollThrough, fullscreen, lockClass]); const commonContent = () => { - let renderIndicator = ; + let renderIndicator: React.ReactNode = ; if (indicator && typeof indicator !== 'boolean') { - renderIndicator = indicator as React.ReactElement; + renderIndicator = indicator; } return ( <> diff --git a/packages/components/pagination/__tests__/pagination.test.tsx b/packages/components/pagination/__tests__/pagination.test.tsx index 296760bfad..3265095190 100644 --- a/packages/components/pagination/__tests__/pagination.test.tsx +++ b/packages/components/pagination/__tests__/pagination.test.tsx @@ -83,7 +83,7 @@ describe('Pagination test', () => { fireEvent.change(document.querySelector('.t-pagination__jump .t-input__inner'), { target: { value: '5' } }); fireEvent.keyDown(document.querySelector('.t-pagination__jump .t-input__inner'), { keyCode: 13 }); - expect(document.querySelector('.t-pagination__jump .t-input__inner').value).toEqual('5'); + expect((document.querySelector('.t-pagination__jump .t-input__inner') as HTMLInputElement).value).toEqual('5'); }); test('totalContent works fine', () => { const changeFn = vi.fn(); @@ -93,9 +93,9 @@ describe('Pagination test', () => { expect(getByText('总条数')).toBeInTheDocument(); - const totalContentFn = vi.fn(); + const totalContentFn = vi.fn() as unknown as React.ReactNode; rerender(); - expect(totalContentFn).toBeCalled(); + expect(totalContentFn).toHaveBeenCalled(); }); test('jumper works fine', () => { render(); @@ -119,6 +119,6 @@ describe('Pagination test', () => { fireEvent.change(document.querySelector('.t-pagination__jump .t-input__inner'), { target: { value: '5.555' } }); fireEvent.keyDown(document.querySelector('.t-pagination__jump .t-input__inner'), { keyCode: 13 }); - expect(document.querySelector('.t-pagination__jump .t-input__inner').value).toEqual('5'); + expect((document.querySelector('.t-pagination__jump .t-input__inner') as HTMLInputElement).value).toEqual('5'); }); }); diff --git a/packages/components/pagination/__tests__/paginationMini.test.tsx b/packages/components/pagination/__tests__/paginationMini.test.tsx index 440f9845d9..300202bd6e 100644 --- a/packages/components/pagination/__tests__/paginationMini.test.tsx +++ b/packages/components/pagination/__tests__/paginationMini.test.tsx @@ -50,7 +50,7 @@ describe('PaginationMini test', () => { expect(onChange.mock.calls[1][0].trigger).toBe('current'); next?.dispatchEvent(new MouseEvent('click', { bubbles: true })); expect(onChange.mock.calls[2][0].trigger).toBe('next'); - expect(onChange).toBeCalledTimes(3); + expect(onChange).toHaveBeenCalledTimes(3); }); test('PaginationMini: test title', () => { diff --git a/packages/components/rate/__tests__/rate.test.tsx b/packages/components/rate/__tests__/rate.test.tsx index c08ecabdd0..589a105795 100644 --- a/packages/components/rate/__tests__/rate.test.tsx +++ b/packages/components/rate/__tests__/rate.test.tsx @@ -7,7 +7,7 @@ describe('Rate 组件测试', () => { // 测试渲染 test('create', async () => { const { container } = render(); - expect(container.firstChild.classList.contains('t-rate')).toBeTruthy(); + expect(container.children[0].classList.contains('t-rate')).toBeTruthy(); expect(document.querySelectorAll('.t-rate__item')).toHaveLength(5); }); @@ -16,8 +16,8 @@ describe('Rate 组件测试', () => { const clickFn = vi.fn(); render(); fireEvent.click(document.querySelector('.t-rate__item')); - expect(clickFn).toBeCalledTimes(1); - expect(clickFn).toBeCalledWith(1); + expect(clickFn).toHaveBeenCalledTimes(1); + expect(clickFn).toHaveBeenCalledTimes(1); }); // mouse 事件测试 @@ -43,12 +43,12 @@ describe('Rate 组件测试', () => { const clickFn = vi.fn(); render(); fireEvent.click(document.querySelector('.t-rate__item')); - expect(clickFn).toBeCalledTimes(0); + expect(clickFn).toHaveBeenCalledTimes(0); }); test('icon', () => { const { container } = render(TNode} />); - expect(container.firstChild.classList.contains('t-rate')).toBeTruthy(); + expect(container.children[0].classList.contains('t-rate')).toBeTruthy(); expect(document.querySelectorAll('.custom-node')).toHaveLength(10); }); diff --git a/packages/components/slider/__tests__/SliderHandleButton.test.tsx b/packages/components/slider/__tests__/SliderHandleButton.test.tsx index da939f5697..90a2996649 100644 --- a/packages/components/slider/__tests__/SliderHandleButton.test.tsx +++ b/packages/components/slider/__tests__/SliderHandleButton.test.tsx @@ -8,6 +8,7 @@ describe('SliderHandleButton 组件测试', () => { test('dragging', async () => { const SliderButton = () => ( { expect(stepsItems.length).toBe(3); fireEvent.click(stepsInstance.querySelector('.t-steps-item__inner')); - expect(handleChange).toBeCalledTimes(1); + expect(handleChange).toHaveBeenCalledTimes(1); }); test('layout vertical 测试', async () => { diff --git a/packages/components/switch/__tests__/switch.test.tsx b/packages/components/switch/__tests__/switch.test.tsx index 79dfa2f8a0..9f92b92410 100644 --- a/packages/components/switch/__tests__/switch.test.tsx +++ b/packages/components/switch/__tests__/switch.test.tsx @@ -8,7 +8,7 @@ import Switch from '../Switch'; describe('Switch 组件测试', () => { test('create', async () => { const { container } = render(); - expect(container.firstChild.classList.contains('t-switch')).toBeTruthy(); + expect(container.children[0].classList.contains('t-switch')).toBeTruthy(); }); test('label', async () => { const { queryByText } = render(); @@ -20,11 +20,11 @@ describe('Switch 组件测试', () => { }); test('loading', async () => { const { container } = render(); - expect(container.firstChild.classList.contains('t-is-loading')).toBeTruthy(); + expect(container.children[0].classList.contains('t-is-loading')).toBeTruthy(); }); test('size', async () => { const { container } = render(); - expect(container.firstChild.classList.contains('t-size-s')).toBeTruthy(); + expect(container.children[0].classList.contains('t-size-s')).toBeTruthy(); }); test('disabled', async () => { @@ -32,19 +32,19 @@ describe('Switch 组件测试', () => { const { container } = render(); expect(container.firstChild).toBeDisabled(); fireEvent.click(container.firstChild); - expect(clickFn).toBeCalledTimes(0); + expect(clickFn).toHaveBeenCalledTimes(0); }); test('onChange', async () => { const clickFn = vi.fn(); const { container } = render(); fireEvent.click(container.firstChild); - expect(clickFn).toBeCalledTimes(1); + expect(clickFn).toHaveBeenCalledTimes(1); }); test('should log error if value is not in customValue', async () => { const logSpy = vi.spyOn(log, 'error').mockImplementation(noop); render(); - expect(logSpy).toBeCalledTimes(1); + expect(logSpy).toHaveBeenCalledTimes(1); logSpy.mockRestore(); }); test('beforeChange resolve', async () => { @@ -58,7 +58,7 @@ describe('Switch 组件测试', () => { const { container } = render(); fireEvent.click(container.firstChild); await new Promise((resolve) => setTimeout(resolve, 100)); - expect(container.firstChild.classList.contains('t-is-checked')).toBeTruthy(); + expect(container.children[0].classList.contains('t-is-checked')).toBeTruthy(); }); test('beforeChange reject', async () => { const clickFn = vi.fn(); @@ -71,6 +71,6 @@ describe('Switch 组件测试', () => { const { container } = render(); fireEvent.click(container.firstChild); await new Promise((resolve) => setTimeout(resolve, 100)); - expect(container.firstChild.classList.contains('t-is-checked')).toBeFalsy(); + expect(container.children[0].classList.contains('t-is-checked')).toBeFalsy(); }); }); diff --git a/packages/components/table/__tests__/base.test.tsx b/packages/components/table/__tests__/base.test.tsx index d76dfd348c..6c92d9e3c6 100644 --- a/packages/components/table/__tests__/base.test.tsx +++ b/packages/components/table/__tests__/base.test.tsx @@ -73,7 +73,7 @@ TABLES.forEach((TTable) => { const rowAttrs = () => [{ 'data-level': 'level-1' }, { 'data-name': 'tdesign' }]; const { container } = render( - , + , ); const trWrapper = container.querySelector('tbody').querySelector('tr'); expect(trWrapper.getAttribute('data-level')).toBe('level-1'); @@ -84,7 +84,7 @@ TABLES.forEach((TTable) => { const rowAttrs = [() => [{ 'data-level': 'level-1' }, { 'data-name': 'tdesign' }]]; const { container } = render( - , + , ); const trWrapper = container.querySelector('tbody').querySelector('tr'); expect(trWrapper.getAttribute('data-level')).toBe('level-1'); @@ -356,8 +356,14 @@ TABLES.forEach((TTable) => { // JSDOM 环境下 scrollHeight/clientHeight 默认都为 0,需 mock function mockScrollHeight(element: HTMLElement, scrollHeight: number, clientHeight: number) { - Object.defineProperty(element, 'scrollHeight', { value: scrollHeight, configurable: true }); - Object.defineProperty(element, 'clientHeight', { value: clientHeight, configurable: true }); + Object.defineProperty(element, 'scrollHeight', { + value: scrollHeight, + configurable: true, + }); + Object.defineProperty(element, 'clientHeight', { + value: clientHeight, + configurable: true, + }); } it('props.pagination: scroll position should reset when switching pages', async () => { diff --git a/packages/components/table/__tests__/column.test.tsx b/packages/components/table/__tests__/column.test.tsx index 86fa2c9a29..021e5ba3d2 100644 --- a/packages/components/table/__tests__/column.test.tsx +++ b/packages/components/table/__tests__/column.test.tsx @@ -24,7 +24,7 @@ TABLES.forEach((TTable) => { { title: 'description', colKey: 'description' }, { title: 'Owner', colKey: 'owner', align: 'right' }, ]; - const { container } = render(); + const { container } = render(); const firstTrWrapper = container.querySelector('tbody > tr'); const tdList = firstTrWrapper.querySelectorAll('td'); expect(tdList[0].classList.contains('t-align-center')).toBeTruthy(); @@ -36,7 +36,11 @@ TABLES.forEach((TTable) => { it('Props.columns.attrs', () => { const columns = [ { title: 'Index', colKey: 'index' }, - { title: 'Instance', colKey: 'instance', attrs: { 'col-key': 'instance' } }, + { + title: 'Instance', + colKey: 'instance', + attrs: { 'col-key': 'instance' }, + }, { title: 'description', colKey: 'description' }, { title: 'Owner', colKey: 'owner' }, ]; @@ -50,8 +54,16 @@ TABLES.forEach((TTable) => { const columns = [ { title: 'Index', colKey: 'index', className: () => ['tdesign-class'] }, { title: 'Instance', colKey: 'instance', className: 'tdesign-class' }, - { title: 'description', colKey: 'description', className: [{ 'tdesign-class': true }] }, - { title: 'Owner', colKey: 'owner', className: { 'tdesign-class': true, 'tdesign-class1': false } }, + { + title: 'description', + colKey: 'description', + className: [{ 'tdesign-class': true }], + }, + { + title: 'Owner', + colKey: 'owner', + className: { 'tdesign-class': true, 'tdesign-class1': false }, + }, ]; const { container } = render(); const firstTrWrapper = container.querySelector('tbody > tr'); diff --git a/packages/components/table/__tests__/mount.jsx b/packages/components/table/__tests__/mount.jsx index 6539d41b71..e780008a6e 100644 --- a/packages/components/table/__tests__/mount.jsx +++ b/packages/components/table/__tests__/mount.jsx @@ -36,31 +36,19 @@ export function getNormalTableMount(TTable, props) { footData={getTableData(2)} columns={SIMPLE_COLUMNS} {...props} - > + >, ); } export function getEmptyDataTableMount(TTable, props) { - return render( - - ); + return render(); } /** 获取用于本地数据分页的表格数据(受控和非受控测试) */ export function getDataLengthLargerThanPageSizeTableMount(TTable, props, rerender) { const renderFun = rerender || render; return renderFun( - + , ); } @@ -70,11 +58,6 @@ export function getDataLengthLargerThanPageSizeTableMount(TTable, props, rerende export function getNormalCountDataTableMount(TTable, props, rerender) { const renderFun = rerender || render; return renderFun( - + , ); } diff --git a/packages/components/tabs/__tests__/tabs.test.tsx b/packages/components/tabs/__tests__/tabs.test.tsx index 3194a6adb6..129aa8dd5e 100644 --- a/packages/components/tabs/__tests__/tabs.test.tsx +++ b/packages/components/tabs/__tests__/tabs.test.tsx @@ -193,11 +193,18 @@ describe('Tabs 组件测试', () => { expect(onTabRemoveFn).toHaveBeenCalledTimes(1); expect(onTabPanelRemoveFn).toHaveBeenCalledTimes(1); - expect(onTabRemoveFn).toHaveBeenCalledWith({ value: 'a', e: expect.any(Object), index: 0 }); + expect(onTabRemoveFn).toHaveBeenCalledWith({ + value: 'a', + e: expect.any(Object), + index: 0, + }); const tabRemoveFnArg = onTabRemoveFn.mock.calls[0][0]; expect(tabRemoveFnArg.e.nativeEvent).toBeInstanceOf(MouseEvent); - expect(onTabPanelRemoveFn).toHaveBeenCalledWith({ value: 'a', e: expect.any(Object) }); + expect(onTabPanelRemoveFn).toHaveBeenCalledWith({ + value: 'a', + e: expect.any(Object), + }); const tabPanelRemoveFnArg = onTabPanelRemoveFn.mock.calls[0][0]; expect(tabPanelRemoveFnArg.e.nativeEvent).toBeInstanceOf(MouseEvent); }); @@ -298,7 +305,6 @@ describe('Tabs 组件测试', () => { value: 0, }, ]} - tabClick={() => ''} > , ); @@ -308,7 +314,7 @@ describe('Tabs 组件测试', () => { }); const mockFn = vi.spyOn(HTMLDivElement.prototype, 'getBoundingClientRect'); - mockFn.mockImplementation(() => ({ width: 20, x: 5, clientX: 5 })); + mockFn.mockImplementation(() => ({ width: 20, x: 5, clientX: 5 }) as any); test('test drag', async () => { const onDragSort = vi.fn(() => { @@ -348,8 +354,8 @@ describe('Tabs 组件测试', () => { targetIndex: 0, }, }); - expect(onDragSort).toHaveBeenCalled(1); - expect(onDragSort.mock.calls[0][0].target.value).toEqual('vue'); + expect(onDragSort).toHaveBeenCalled(); + expect((onDragSort as any).mock.calls[0][0].target.value).toEqual('vue'); expect(container.querySelectorAll('.t-tabs__nav-item-text-wrapper').item(0).firstChild.nodeValue).toEqual('react'); }); diff --git a/packages/components/tag-input/__tests__/mount.jsx b/packages/components/tag-input/__tests__/mount.jsx index 440c362ecc..9a83c63938 100644 --- a/packages/components/tag-input/__tests__/mount.jsx +++ b/packages/components/tag-input/__tests__/mount.jsx @@ -3,15 +3,11 @@ import { render } from '@test/utils'; // empty value export function getTagInputDefaultMount(TagInput, props, events) { - return render( - - ); + return render(); } // with default value export function getTagInputValueMount(TagInput, props, events) { const value = ['tdesign-vue', 'tdesign-react', 'tdesign-miniprogram', 'tdesign-mobile-vue', 'tdesign-mobile-react']; - return render( - - ); + return render(); } diff --git a/packages/components/tag-input/__tests__/tag-input.test.tsx b/packages/components/tag-input/__tests__/tag-input.test.tsx index 24d6e1455a..f957a34bf2 100644 --- a/packages/components/tag-input/__tests__/tag-input.test.tsx +++ b/packages/components/tag-input/__tests__/tag-input.test.tsx @@ -6,7 +6,7 @@ import { getTagInputValueMount } from './mount'; describe('TagInput Component', () => { const mockFn = vi.spyOn(HTMLSpanElement.prototype, 'getBoundingClientRect'); - mockFn.mockImplementation(() => ({ width: 20, x: 5, clientX: 5 })); + mockFn.mockImplementation(() => ({ width: 20, x: 5, clientX: 5 }) as any); it('events.drag: dragSort', () => { const defaultValue = ['Vue', 'React', 'Angular']; @@ -58,7 +58,7 @@ describe('TagInput Component', () => { expect(wrapper).toHaveClass('t-tag-input--break-line'); expect(wrapper).toHaveClass('t-tag-input--with-tag'); - expect(inputPrefix).toContainElement(label); + expect(inputPrefix).toContainElement(label as HTMLElement); expect(inputPrefix.querySelectorAll('.t-tag')).toHaveLength(2); expect(container.querySelector('.t-input__inner')).toBeTruthy(); }); diff --git a/packages/components/tag/__tests__/vitest-tag.test.jsx b/packages/components/tag/__tests__/vitest-tag.test.jsx index 3222be2644..1cae860993 100644 --- a/packages/components/tag/__tests__/vitest-tag.test.jsx +++ b/packages/components/tag/__tests__/vitest-tag.test.jsx @@ -5,8 +5,9 @@ * If you need to modify this file, contact PMC first please. */ import React from 'react'; -import { fireEvent, vi, render } from '@test/utils'; -import { Tag, CheckTag } from '..'; +import { fireEvent, render, vi } from '@test/utils'; + +import { CheckTag, Tag } from '..'; describe('Tag Component', () => { it('props.children works fine', () => { diff --git a/packages/components/time-picker/__tests__/time-picker.test.tsx b/packages/components/time-picker/__tests__/time-picker.test.tsx index c337a1062d..ab32a2befa 100644 --- a/packages/components/time-picker/__tests__/time-picker.test.tsx +++ b/packages/components/time-picker/__tests__/time-picker.test.tsx @@ -93,10 +93,10 @@ describe('Timepicker 组件测试', () => { const { container } = render(); const InputDom = container.querySelector('.t-input__inner'); fireEvent.click(InputDom); - expect(handleFocus).toBeCalledTimes(1); + expect(handleFocus).toHaveBeenCalledTimes(1); // input blur is not equal to TimePicker.blur fireEvent.mouseDown(document); - expect(handleBlur).toBeCalledTimes(1); + expect(handleBlur).toHaveBeenCalledTimes(1); }); test('props.onInput&onBlur&onForus works fine', async () => { @@ -108,11 +108,11 @@ describe('Timepicker 组件测试', () => { ); const inputs = container.querySelectorAll('input'); fireEvent.focus(inputs[0]); - expect(handleFocus).toBeCalledTimes(1); + expect(handleFocus).toHaveBeenCalledTimes(1); fireEvent.change(inputs[0], { target: { value: '00:10:20' } }); - expect(handleInput).toBeCalledTimes(1); + expect(handleInput).toHaveBeenCalledTimes(1); fireEvent.blur(inputs[0]); - expect(handleBlur).toBeCalledTimes(1); + expect(handleBlur).toHaveBeenCalledTimes(1); }); test('click to pick', async () => { @@ -123,7 +123,7 @@ describe('Timepicker 组件测试', () => { , ); fireEvent.click(document.querySelector('input')); - expect(handleOpen).toBeCalledTimes(1); + expect(handleOpen).toHaveBeenCalledTimes(1); await waitFor(async () => { const confirmBtn = document.querySelectorAll('.t-time-picker__panel button').item(0); expect(confirmBtn).toBeInTheDocument(); diff --git a/packages/components/tree/__tests__/tree.test.tsx b/packages/components/tree/__tests__/tree.test.tsx index 06de25cfea..276a1f08d5 100644 --- a/packages/components/tree/__tests__/tree.test.tsx +++ b/packages/components/tree/__tests__/tree.test.tsx @@ -156,7 +156,9 @@ describe('Tree test', () => { ); - const { container } = await renderTreeWithProps({ operations: renderOperations }); + const { container } = await renderTreeWithProps({ + operations: renderOperations, + }); await mockDelay(300); expect(container.querySelector('.t-tree__operations')).not.toBeNull(); }); @@ -170,7 +172,9 @@ describe('Tree test', () => { ); - const { container } = await renderTreeWithProps({ operations: renderOperations }); + const { container } = await renderTreeWithProps({ + operations: renderOperations, + }); await mockDelay(300); expect(container.querySelector('.t-tree__operations')).not.toBeNull(); }); @@ -354,7 +358,11 @@ describe('Tree test', () => { onKeyDown={(e) => { console.log('keydown', e.key); if (e.key === 'Enter') { - setData({ ...data, label: e.currentTarget.value, isEditing: false }); + setData({ + ...data, + label: e.currentTarget.value, + isEditing: false, + }); console.log('Enter setData({ ...data, name: e.target.value, isEditing: false })'); } if (e.key === 'Escape') { @@ -380,10 +388,12 @@ describe('Tree test', () => { fireEvent.dblClick(container.querySelector('.tree-item-span')); await mockDelay(300); expect(container.querySelector('.tree-item-input')).not.toBeNull(); - fireEvent.change(container.querySelector('.tree-item-input'), { target: { value: '123' } }); - expect(container.querySelector('.tree-item-input').value).toBe('123'); - container.querySelector('.tree-item-input').focus(); - container.querySelector('.tree-item-input').blur(); + fireEvent.change(container.querySelector('.tree-item-input'), { + target: { value: '123' }, + }); + expect((container.querySelector('.tree-item-input') as HTMLInputElement).value).toBe('123'); + (container.querySelector('.tree-item-input') as HTMLInputElement).focus(); + (container.querySelector('.tree-item-input') as HTMLInputElement).blur(); await mockDelay(300); expect(container.querySelector('.tree-item-input')).toBeNull(); expect(container.querySelector('.tree-item-span')).not.toBeNull(); diff --git a/packages/components/watermark/__tests__/watermark.test.tsx b/packages/components/watermark/__tests__/watermark.test.tsx index 858e2c3e53..0ed7fa2fa2 100644 --- a/packages/components/watermark/__tests__/watermark.test.tsx +++ b/packages/components/watermark/__tests__/watermark.test.tsx @@ -18,11 +18,11 @@ describe('Watermark 组件测试', () => { fillRect: vi.fn(), globalAlpha: 0.5, font: '', - textAlign: '', - textBaseline: '', + textAlign: 'center', + textBaseline: 'middle', fillStyle: '', fillText: vi.fn(), - }); + } as any); mockGetCanvasToDataURL.mockReturnValue('test'); }); @@ -47,7 +47,9 @@ describe('Watermark 组件测试', () => {
, ); - expect(watermark.lastChild).toHaveStyle({ animation: 'watermark infinite 1s' }); + expect(watermark.lastChild).toHaveStyle({ + animation: 'watermark infinite 1s', + }); }); test('mutationObserver', async () => { diff --git a/packages/pro-components/chat/chat-engine/_example/agui-chunk.tsx b/packages/pro-components/chat/chat-engine/_example/agui-chunk.tsx index cd380ebec1..c9cab062ee 100644 --- a/packages/pro-components/chat/chat-engine/_example/agui-chunk.tsx +++ b/packages/pro-components/chat/chat-engine/_example/agui-chunk.tsx @@ -67,7 +67,13 @@ const SearchToolComponent: React.FC> = ({ arg return ( -
+
🔍 搜索工具 {getStatusIcon()} @@ -86,7 +92,14 @@ const SearchToolComponent: React.FC> = ({ arg }} >
参数 (流式接收中):
-
+          
             {args ? JSON.stringify(args, null, 2) : '等待参数...'}
           
@@ -133,7 +146,13 @@ const CalculateToolComponent: React.FC> = return ( -
+
🧮 计算器工具 {getStatusText()} @@ -141,11 +160,23 @@ const CalculateToolComponent: React.FC> =
表达式: - + {args?.expression || '等待输入...'}
@@ -155,7 +186,14 @@ const CalculateToolComponent: React.FC> =
)} {result !== null && ( -
+
结果: {result}
)} @@ -183,7 +221,13 @@ const WeatherToolComponent: React.FC> = ({ a return ( -
+
🌤️ 天气查询 {status === 'executing' && } @@ -191,7 +235,14 @@ const WeatherToolComponent: React.FC> = ({ a
-
+
城市: {args?.city || 接收中...}
@@ -332,7 +383,7 @@ const AguiChunkExample: React.FC = () => { return ( @@ -360,7 +411,7 @@ const AguiChunkExample: React.FC = () => { isLast && message.status !== 'stop' && (
- +
) )} @@ -391,7 +442,12 @@ const AguiChunkExample: React.FC = () => { {/* 模式说明 */}
{mode === 'text' && (
diff --git a/packages/pro-components/chat/chat-engine/_example/agui-test.tsx b/packages/pro-components/chat/chat-engine/_example/agui-test.tsx index 6a296ccde0..aae8d43873 100644 --- a/packages/pro-components/chat/chat-engine/_example/agui-test.tsx +++ b/packages/pro-components/chat/chat-engine/_example/agui-test.tsx @@ -29,7 +29,13 @@ const StockChart = ({ content }) => { return ( -
+
{currentPrice ? currentPrice.toFixed(2) : '--'}{' '} {currency} @@ -341,7 +347,7 @@ export default function AguiBasicExample() { // 处理工具调用响应(如果需要交互式工具) const handleToolCallRespond = async (toolcall, response) => { - const tools = chatEngine.getToolcallByName(toolcall.toolCallName) || {}; + const tools = (chatEngine as any).getToolcallByName(toolcall.toolCallName) || {}; await chatEngine.sendAIMessage({ params: { prompt: inputValue, @@ -394,12 +400,12 @@ export default function AguiBasicExample() { <> {message.content?.map((item, index) => renderMessageContent(item, index, isLast))} {isAIMessage(message) && message.status === 'complete' ? ( - + ) : ( isLast && message.status !== 'stop' && (
- +
) )} diff --git a/packages/pro-components/chat/chat-engine/_example/agui-toolcall.tsx b/packages/pro-components/chat/chat-engine/_example/agui-toolcall.tsx index da577c88da..fb28d8e3d1 100644 --- a/packages/pro-components/chat/chat-engine/_example/agui-toolcall.tsx +++ b/packages/pro-components/chat/chat-engine/_example/agui-toolcall.tsx @@ -116,12 +116,27 @@ const ImageGenProgress: React.FC> = ({ case 'completed': return ( -
+
图片生成完成
{imageUrl && ( - + )} ); @@ -129,7 +144,14 @@ const ImageGenProgress: React.FC> = ({ case 'failed': return ( -
+
图片生成失败
@@ -248,7 +270,7 @@ export default function ImageGenAgentChat() { // 处理工具调用响应(如果需要交互式工具) const handleToolCallRespond = async (toolcall: ToolCall, response: T) => { - const tools = chatEngine.getToolcallByName(toolcall.toolCallName) || {}; + const tools = (chatEngine as any).getToolcallByName(toolcall.toolCallName) || {}; await chatEngine.sendAIMessage({ params: { prompt: inputValue, diff --git a/packages/pro-components/chat/chat-engine/_example/agui-videoclip.tsx b/packages/pro-components/chat/chat-engine/_example/agui-videoclip.tsx index 8da259acee..ab8628aa8b 100644 --- a/packages/pro-components/chat/chat-engine/_example/agui-videoclip.tsx +++ b/packages/pro-components/chat/chat-engine/_example/agui-videoclip.tsx @@ -43,10 +43,26 @@ const { StepItem } = Steps; // 状态映射 const statusMap: Record = { - pending: { theme: 'default', status: 'default', icon: }, - running: { theme: 'primary', status: 'process', icon: }, - completed: { theme: 'success', status: 'finish', icon: }, - failed: { theme: 'danger', status: 'error', icon: }, + pending: { + theme: 'default', + status: 'default', + icon: , + }, + running: { + theme: 'primary', + status: 'process', + icon: , + }, + completed: { + theme: 'success', + status: 'finish', + icon: , + }, + failed: { + theme: 'danger', + status: 'error', + icon: , + }, }; // 自定义Hook:状态跟踪 @@ -495,7 +511,7 @@ export default function VideoClipAgentChatWithSubscription() { const { chatEngine, messages, status } = useChat({ defaultMessages: [], - chatServiceConfig: createChatServiceConfig(), + chatServiceConfig: createChatServiceConfig() as any, }); const senderLoading = React.useMemo(() => status === 'pending' || status === 'streaming', [status]); @@ -540,7 +556,7 @@ export default function VideoClipAgentChatWithSubscription() { const handleToolCallRespond = async (toolcall: ToolCall, response: T) => { try { // 构造新的请求参数 - const tools = chatEngine.getToolcallByName(toolcall.toolCallName) || {}; + const tools = (chatEngine as any).getToolcallByName(toolcall.toolCallName) || {}; const newRequestParams: ChatRequestParams = { prompt: inputValue, toolCallMessage: { @@ -570,7 +586,7 @@ export default function VideoClipAgentChatWithSubscription() { // 使用统一的 ToolCallRenderer 处理所有工具调用 return (
- +
); } @@ -595,7 +611,7 @@ export default function VideoClipAgentChatWithSubscription() { isLast && message.status !== 'stop' && (
- +
) )} @@ -628,7 +644,10 @@ export default function VideoClipAgentChatWithSubscription() {
{/* 聊天区域 */} - + {messages.map((message, idx) => ( {isUserMessage(message) && ( diff --git a/packages/pro-components/chat/chat-engine/_example/agui.tsx b/packages/pro-components/chat/chat-engine/_example/agui.tsx index be86c315c3..7c5fd626bf 100644 --- a/packages/pro-components/chat/chat-engine/_example/agui.tsx +++ b/packages/pro-components/chat/chat-engine/_example/agui.tsx @@ -52,7 +52,9 @@ export default function ComponentsBuild() { console.error('Chatservice Error:', err); }, // 流式对话过程中用户主动结束对话业务自定义行为 - onAbort: async () => '', + onAbort: async () => { + undefined; + }, // 自定义请求参数 onRequest: (innerParams: ChatRequestParams) => { const { prompt } = innerParams; @@ -151,7 +153,7 @@ export default function ComponentsBuild() { key={`toolcall-${index}-${subIndex}`} className="toolcall-wrapper" > - +
); } @@ -204,7 +206,13 @@ export default function ComponentsBuild() { return (
{/* 历史消息加载控制栏 */} -
+
- + {messages.map((message, idx) => ( {renderMsgContents(message, idx === messages.length - 1)} @@ -230,7 +241,7 @@ export default function ComponentsBuild() { ))} {/* 消息列表 */} - + {messages.map((message) => ( = ({ formConfig, onSu type="number" value={value || ''} placeholder={field.placeholder} - min={field.min} - max={field.max} + // min={field.min} + // max={field.max} onChange={(val) => handleInputChange(field.name, val)} status={error ? 'error' : undefined} tips={error} diff --git a/packages/pro-components/chat/chat-engine/_example/components/Toolcall.tsx b/packages/pro-components/chat/chat-engine/_example/components/Toolcall.tsx index 42eea268b5..de0d1c989f 100644 --- a/packages/pro-components/chat/chat-engine/_example/components/Toolcall.tsx +++ b/packages/pro-components/chat/chat-engine/_example/components/Toolcall.tsx @@ -14,7 +14,7 @@ const renderStatusTag = (status: 'pending' | 'streaming' | 'complete') => { const config = statusConfig[status] || statusConfig.complete; return ( - + {config.text} ); @@ -47,7 +47,14 @@ export default function CustomToolCallRenderer({ {searchResult.references && searchResult.references.length > 0 && (
{searchResult.references.map((ref: any, idx: number) => ( -
+
({ think: false, search: false }); + const reqParamsRef = useRef<{ think: boolean; search: boolean }>({ + think: false, + search: false, + }); // 默认初始化消息 const defaultMessages: ChatMessagesData[] = [ @@ -198,7 +201,7 @@ export default function Comprehensive() { /> ); } - return ; + return ; }; // 发送消息 @@ -210,11 +213,13 @@ export default function Comprehensive() { return (
- + {messages.map((message, idx) => { const isLast = idx === messages.length - 1; // 假设只有单条thinking - const thinking = message.content.find((item) => item.type === 'thinking'); + const thinking = message.content.find((item) => (item.type as any) === 'thinking'); // 根据角色配置消息样式 if (message.role === 'user') { diff --git a/packages/pro-components/chat/chat-engine/_example/custom-content.tsx b/packages/pro-components/chat/chat-engine/_example/custom-content.tsx index 211140a20e..16795939c4 100644 --- a/packages/pro-components/chat/chat-engine/_example/custom-content.tsx +++ b/packages/pro-components/chat/chat-engine/_example/custom-content.tsx @@ -21,9 +21,8 @@ import type { SSEChunkData, TdAttachmentItem, TdChatSenderParams, - UploadFile, } from '@tdesign-react/chat'; -import type { ImageViewerProps } from 'tdesign-react'; +import type { ImageViewerProps, UploadFile } from 'tdesign-react'; /** * 自定义内容渲染示例 - AI 生图助手 @@ -114,7 +113,7 @@ const BasicImageViewer = ({ images }) => { alignItems: 'center', justifyContent: 'center', }} - onClick={open} + onClick={() => open()} > 预览 @@ -211,7 +210,10 @@ export default function CustomContent() { const senderRef = useRef(null); const [ratio, setRatio] = useState(0); const [style, setStyle] = useState(''); - const reqParamsRef = useRef<{ ratio: number; style: string; file?: string }>({ ratio: 0, style: '' }); + const reqParamsRef = useRef<{ ratio: number; style: string; file?: string }>({ + ratio: 0, + style: '', + }); const [files, setFiles] = useState([]); const [inputValue, setInputValue] = useState('请为 TDesign 设计三张品牌宣传图'); @@ -318,7 +320,7 @@ export default function CustomContent() { }, 风格:${style ? StyleOptions.filter((item) => item.value === style)[0].content : '默认风格'}`; await chatEngine.sendUserMessage({ - attachments, + attachments: attachments as any, prompt: enhancedPrompt, }); setInputValue(''); @@ -389,7 +391,9 @@ export default function CustomContent() { return (
- + {messages.map((message) => ( (/耗时/.test(rest?.title) ? 'complete' : status), + status: (/耗时/.test(rest?.title) ? 'complete' : status) as ChatMessageStatus, data: { title: rest.title || '深度思考中', text: rest.content || '', @@ -181,7 +182,10 @@ export default function ComponentsBuild() { return (
- + {messages.map((message, idx) => ( {renderMsgContents(message, idx === messages.length - 1)} @@ -189,8 +193,8 @@ export default function ComponentsBuild() { ))} { if (status === 'error') { - return ( - } title="获取天气信息失败"> - {error?.message} - - ); + return } title="获取天气信息失败" message={error?.message}>; } if (status === 'complete' && result) { @@ -123,23 +119,47 @@ const WeatherDisplay: React.FC -
+
{weather.temperature}
-
+
{weather.condition}
-
+
-
+
@@ -148,7 +168,7 @@ const WeatherDisplay: React.FC @@ -201,11 +221,7 @@ const PlanItinerary: React.FC} title="行程规划失败"> - {error?.message} - - ); + return } title="行程规划失败" message={error?.message}>; } if (status === 'complete' && resolvedResult) { @@ -222,7 +238,13 @@ const PlanItinerary: React.FC -
+
¥{resolvedResult.totalBudget} @@ -235,7 +257,13 @@ const PlanItinerary: React.FC ( -
+
第 {day.day} 天 @@ -246,7 +274,12 @@ const PlanItinerary: React.FC (
@@ -289,7 +322,7 @@ const PlanItinerary: React.FC @@ -319,11 +352,7 @@ const PlanItinerary: React.FC> = ({ status, args, result, error }) => { if (status === 'error') { - return ( - } title="获取酒店信息失败"> - {error?.message} - - ); + return } title="获取酒店信息失败" message={error?.message}>; } if (status === 'complete' && result) { const hotels = typeof result === 'string' ? JSON.parse(result) : result; @@ -343,7 +372,13 @@ const HotelRecommend: React.FC> = {hotels.map((hotel: any, index: number) => ( -
+
{hotel.name} @@ -351,7 +386,13 @@ const HotelRecommend: React.FC> = ¥{hotel.price}/晚
-
+
{hotel.rating}分 @@ -368,7 +409,7 @@ const HotelRecommend: React.FC> = ); } - if (status === 'inProgress') { + if ((status as any) === 'inProgress') { return ( @@ -403,11 +444,7 @@ const TravelPreferences: React.FC< const transportationOptions = ['飞机', '高铁', '汽车', '自驾']; if (status === 'error') { - return ( - } title="设置偏好失败"> - {error?.message} - - ); + return } title="设置偏好失败" message={error?.message}>; } if (status === 'complete' && result) { @@ -424,23 +461,47 @@ const TravelPreferences: React.FC< style={{ maxWidth: 500 }} > -
+
{args.destination}
-
+
-
+
¥{result.budget}
-
+
{result.interests.map((interest, index) => ( @@ -450,13 +511,25 @@ const TravelPreferences: React.FC< ))}
-
+
{result.accommodation}
-
+
{result.transportation} @@ -467,7 +540,7 @@ const TravelPreferences: React.FC< ); } - if (status === 'inProgress') { + if ((status as any) === 'inProgress') { return ( @@ -494,7 +567,7 @@ const TravelPreferences: React.FC<
-
- + setInterests(value)}> {interestOptions.map((option) => ( @@ -682,7 +755,7 @@ export const travelPreferencesAction: AgentToolcallConfig = { // }; // 导出所有 action 配置 -export const travelActions = [ +export const travelActions: any = [ weatherForecastAction, itineraryPlanAction, hotelRecommendAction, diff --git a/packages/pro-components/chat/chat-engine/_example/travelToolcall.tsx b/packages/pro-components/chat/chat-engine/_example/travelToolcall.tsx index 0fc93f2624..158ea1539d 100644 --- a/packages/pro-components/chat/chat-engine/_example/travelToolcall.tsx +++ b/packages/pro-components/chat/chat-engine/_example/travelToolcall.tsx @@ -23,9 +23,7 @@ import type { ChatMessagesData, ChatRequestParams, TdChatActionsName, - TdChatListApi, TdChatMessageConfig, - TdChatSenderApi, TdChatSenderParams, ToolCall, } from '@tdesign-react/chat'; @@ -67,8 +65,8 @@ const loadHistoryMessages = async (): Promise => { }; export default function TravelPlannerChat() { - const listRef = useRef(null); - const inputRef = useRef(null); + const listRef = useRef(null); + const inputRef = useRef(null); const [inputValue, setInputValue] = useState('请为我规划一个北京5日游行程'); // 注册旅游相关的 Agent Toolcalls @@ -172,7 +170,7 @@ export default function TravelPlannerChat() { const { chatEngine, messages, status } = useChat({ defaultMessages, - chatServiceConfig: createChatServiceConfig(), + chatServiceConfig: createChatServiceConfig() as any, }); const senderLoading = useMemo(() => status === 'pending' || status === 'streaming', [status]); @@ -224,7 +222,7 @@ export default function TravelPlannerChat() { async (toolcall: ToolCall, response: any) => { try { // 构造新的请求参数 - const tools = chatEngine.getToolcallByName(toolcall.toolCallName) || {}; + const tools = (chatEngine as any).getToolcallByName(toolcall.toolCallName) || {}; const newRequestParams: ChatRequestParams = { toolCallMessage: { ...tools, @@ -306,7 +304,14 @@ export default function TravelPlannerChat() { if (isLoadingHistory) { return (
-
+
加载历史消息中...
@@ -342,7 +347,7 @@ export default function TravelPlannerChat() {
- + {messages.map((message, idx) => ( {renderMsgContents(message, idx === messages.length - 1)} diff --git a/packages/pro-components/chat/chat-markdown/_example/base.tsx b/packages/pro-components/chat/chat-markdown/_example/base.tsx index 8b9fba5086..8efe2c2319 100644 --- a/packages/pro-components/chat/chat-markdown/_example/base.tsx +++ b/packages/pro-components/chat/chat-markdown/_example/base.tsx @@ -150,7 +150,7 @@ export default function ThinkContentDemo() { return (
- + setStreamEnabled(value)} label="流式输出" />
diff --git a/packages/pro-components/chat/chat-markdown/_example/custom.tsx b/packages/pro-components/chat/chat-markdown/_example/custom.tsx index ca1da2593f..0af35dd21e 100644 --- a/packages/pro-components/chat/chat-markdown/_example/custom.tsx +++ b/packages/pro-components/chat/chat-markdown/_example/custom.tsx @@ -48,7 +48,7 @@ const MarkdownExample = () => { return ( ('agent', (newChunk: SSEChunkData, existing: AgentContent) => { console.log('newChunk, existing', newChunk, existing); // 创建新对象避免直接修改原状态 const updated = { ...existing, content: { - ...existing.content, - steps: [...existing.content.steps], + ...(existing as any).content, + steps: [...(existing as any).content.steps], }, }; - const stepIndex = updated.content.steps.findIndex((step: any) => step.agent_id === newChunk.content.agent_id); + const stepIndex = updated.content.steps.findIndex( + (step: any) => step.agent_id === (newChunk as any).content.agent_id, + ); if (stepIndex === -1) return updated; @@ -167,29 +170,29 @@ export default function ChatBotReact() { const step = { ...updated.content.steps[stepIndex], tasks: [...(updated.content.steps[stepIndex].tasks || [])], - status: newChunk.state === 'finish' ? 'finish' : 'pending', + status: (newChunk as any).state === 'finish' ? 'finish' : 'pending', }; // 处理不同类型的新数据 - if (newChunk.state === 'command') { + if ((newChunk as any).state === 'command') { // 新增每个步骤执行的命令 step.tasks.push({ type: 'command', - text: newChunk.content.text, + text: (newChunk as any).content.text, }); - } else if (newChunk.state === 'result') { + } else if ((newChunk as any).state === 'result') { // 新增每个步骤执行的结论是流式输出,需要分情况处理 const resultTaskIndex = step.tasks.findIndex((task: any) => task.type === 'result'); if (resultTaskIndex >= 0) { // 合并到已有结果 step.tasks = step.tasks.map((task: any, index: number) => - index === resultTaskIndex ? { ...task, text: task.text + newChunk.content.text } : task, + index === resultTaskIndex ? { ...task, text: task.text + (newChunk as any).content.text } : task, ); } else { // 添加新结果 step.tasks.push({ type: 'result', - text: newChunk.content.text, + text: (newChunk as any).content.text, }); } } @@ -209,9 +212,9 @@ export default function ChatBotReact() { senderProps={{ defaultValue: '请帮我做一个5岁儿童生日聚会的规划', }} - chatServiceConfig={chatServiceConfig} + chatServiceConfig={chatServiceConfig as any} onMessageChange={(e) => { - setMockMessage(e.detail); + setMockMessage(e.detail as any); }} > {mockMessage diff --git a/packages/pro-components/chat/chatbot/_example/agui-toolcall.tsx b/packages/pro-components/chat/chatbot/_example/agui-toolcall.tsx index 86da6f8c6d..2beabaad46 100644 --- a/packages/pro-components/chat/chatbot/_example/agui-toolcall.tsx +++ b/packages/pro-components/chat/chatbot/_example/agui-toolcall.tsx @@ -272,9 +272,9 @@ export default function AguiBasicExample() { defaultValue: 'AG-UI协议的作用是什么', placeholder: '请输入内容,体验 AG-UI 协议', }} - chatServiceConfig={chatServiceConfig} + chatServiceConfig={chatServiceConfig as any} onMessageChange={(e) => { - setMockMessage(e.detail); + setMockMessage(e.detail as any); }} > {/* 渲染自定义 ToolCall 组件 */} diff --git a/packages/pro-components/chat/chatbot/_example/agui.tsx b/packages/pro-components/chat/chatbot/_example/agui.tsx index cae962d79b..65292349ed 100644 --- a/packages/pro-components/chat/chatbot/_example/agui.tsx +++ b/packages/pro-components/chat/chatbot/_example/agui.tsx @@ -28,7 +28,7 @@ export default function AguiProtocol() { return (
- +
); } diff --git a/packages/pro-components/chat/chatbot/_example/backup/travel.tsx b/packages/pro-components/chat/chatbot/_example/backup/travel.tsx index 7407bf2b86..7c9597b123 100644 --- a/packages/pro-components/chat/chatbot/_example/backup/travel.tsx +++ b/packages/pro-components/chat/chatbot/_example/backup/travel.tsx @@ -10,9 +10,9 @@ import { ChatSender, getMessageContentForCopy, isAIMessage, + useChat, } from '@tdesign-react/chat'; -import { useChat } from '../../hooks/useChat'; import { HotelCard, HumanInputForm, @@ -20,7 +20,7 @@ import { ItineraryCard, PlanningStatePanel, WeatherCard, -} from '../components'; +} from '../../../chat-engine/_example/components'; import type { ReactNode } from 'react'; import type { @@ -35,7 +35,7 @@ import type { TdChatSenderApi, TdChatSenderParams, } from '@tdesign-react/chat'; -import type { FormConfig } from '../components/HumanInputForm'; +import type { FormConfig } from 'tdesign-react'; import './travel-planner.css'; @@ -213,7 +213,7 @@ export default function TravelPlannerChat() { const { chatEngine, messages, status } = useChat({ defaultMessages, - chatServiceConfig: createChatServiceConfig(), + chatServiceConfig: createChatServiceConfig() as any, }); const senderLoading = useMemo(() => status === 'pending' || status === 'streaming', [status]); @@ -267,7 +267,7 @@ export default function TravelPlannerChat() { setUserInputFormConfig(null); // 2. 构造新的请求参数 - const tools = chatEngine.getToolcallByName('get_travel_preferences') || {}; + const tools = (chatEngine as any).getToolcallByName('get_travel_preferences') || {}; const newRequestParams: ChatRequestParams = { prompt: inputValue, toolCallMessage: { @@ -277,7 +277,7 @@ export default function TravelPlannerChat() { }; // 3. 直接调用 chatEngine.continueChat(params) 继续请求 - await chatEngine.continueChat(newRequestParams); + await (chatEngine as any).continueChat(newRequestParams); listRef.current?.scrollList({ to: 'bottom' }); } catch (error) { console.error('提交用户输入失败:', error); @@ -287,10 +287,10 @@ export default function TravelPlannerChat() { // 处理用户输入取消 const handleUserInputCancel = async () => { - await chatEngine.continueChat({ + await (chatEngine as any).continueChat({ prompt: inputValue, toolCallMessage: { - ...chatEngine.getToolcallByName('get_travel_preferences'), + ...(chatEngine as any).getToolcallByName('get_travel_preferences'), result: 'user_cancel', }, }); @@ -320,7 +320,7 @@ export default function TravelPlannerChat() { return (
@@ -404,7 +404,14 @@ export default function TravelPlannerChat() { if (isLoadingHistory) { return (
-
+
加载历史消息中...
@@ -440,7 +447,7 @@ export default function TravelPlannerChat() {
- + {messages.map((message, idx) => ( {renderMsgContents(message, idx === messages.length - 1)} @@ -448,7 +455,7 @@ export default function TravelPlannerChat() { ))} - +
)}
diff --git a/packages/pro-components/chat/chatbot/_example/basic.tsx b/packages/pro-components/chat/chatbot/_example/basic.tsx index 0d6fce85d4..15873fb8e1 100644 --- a/packages/pro-components/chat/chatbot/_example/basic.tsx +++ b/packages/pro-components/chat/chatbot/_example/basic.tsx @@ -48,13 +48,16 @@ export default function chatSample() { const [activeR1, setR1Active] = useState(false); const [activeSearch, setSearchActive] = useState(false); const [ready, setReady] = useState(false); - const reqParamsRef = useRef<{ think: boolean; search: boolean }>({ think: false, search: false }); + const reqParamsRef = useRef<{ think: boolean; search: boolean }>({ + think: false, + search: false, + }); // 消息属性配置 const messageProps = (msg: ChatMessagesData): TdChatMessageConfigItem => { const { role, content } = msg; // 假设只有单条thinking - const thinking = content.find((item) => item.type === 'thinking'); + const thinking = content.find((item) => (item.type as any) === 'thinking'); if (role === 'user') { return { variant: 'base', @@ -190,7 +193,7 @@ export default function chatSample() { senderProps={{ placeholder: '有问题,尽管问~ Enter 发送,Shift+Enter 换行', }} - chatServiceConfig={chatServiceConfig} + chatServiceConfig={chatServiceConfig as any} onChatReady={() => { setReady(true); }} diff --git a/packages/pro-components/chat/chatbot/_example/code.tsx b/packages/pro-components/chat/chatbot/_example/code.tsx index 1484000dd6..31c6f27322 100644 --- a/packages/pro-components/chat/chatbot/_example/code.tsx +++ b/packages/pro-components/chat/chatbot/_example/code.tsx @@ -12,7 +12,6 @@ import type { ChatServiceConfig, SSEChunkData, TdChatbotApi, - TdChatMessageConfig, } from '@tdesign-react/chat'; // 默认初始化消息 @@ -96,7 +95,7 @@ export default function chatSample() { const [mockMessage, setMockMessage] = React.useState(mockData); // 消息属性配置 - const messageProps: TdChatMessageConfig = { + const messageProps: any = { user: { variant: 'base', placement: 'right', @@ -159,8 +158,8 @@ export default function chatSample() { // 自定义:代码运行结果预览 case 'preview': return { - type: 'preview', - status: () => (/完成/.test(rest?.content?.cnName) ? 'complete' : 'streaming'), + type: 'preview' as any, + status: /完成/.test(rest?.content?.cnName) ? 'complete' : 'streaming', data: rest?.content, }; } @@ -189,13 +188,13 @@ export default function chatSample() { defaultMessages={mockData} messageProps={messageProps} onMessageChange={(e) => { - setMockMessage(e.detail); + setMockMessage(e.detail as any); }} senderProps={{ defaultValue: '使用 TDesign 组件库实现一个登录表单的例子', placeholder: '有问题,尽管问~ Enter 发送,Shift+Enter 换行', }} - chatServiceConfig={chatServiceConfig} + chatServiceConfig={chatServiceConfig as any} > {/* 自定义消息体渲染-植入插槽 */} {mockMessage diff --git a/packages/pro-components/chat/chatbot/_example/components/index.ts b/packages/pro-components/chat/chatbot/_example/components/index.ts index 8dd3fc426e..425ab0f6cc 100644 --- a/packages/pro-components/chat/chatbot/_example/components/index.ts +++ b/packages/pro-components/chat/chatbot/_example/components/index.ts @@ -1,6 +1 @@ -export { HotelCard } from './HotelCard'; -export { HumanInputForm } from './HumanInputForm'; -export { HumanInputResult } from './HumanInputResult'; export { ItineraryCard } from './ItineraryCard'; -export { PlanningStatePanel } from './PlanningStatePanel'; -export { WeatherCard } from './WeatherCard'; diff --git a/packages/pro-components/chat/chatbot/_example/comprehensive.tsx b/packages/pro-components/chat/chatbot/_example/comprehensive.tsx index 8deae48260..75cba925c0 100644 --- a/packages/pro-components/chat/chatbot/_example/comprehensive.tsx +++ b/packages/pro-components/chat/chatbot/_example/comprehensive.tsx @@ -61,13 +61,16 @@ export default function chatSample() { const chatRef = useRef(null); const [activeSearch, setSearchActive] = useState(false); const [ready, setReady] = useState(false); - const reqParamsRef = useRef<{ think: boolean; search: boolean }>({ think: false, search: false }); + const reqParamsRef = useRef<{ think: boolean; search: boolean }>({ + think: false, + search: false, + }); // 消息属性配置 const messageProps = (msg: ChatMessagesData): TdChatMessageConfigItem => { const { role, content } = msg; // 假设只有单条thinking - const thinking = content.find((item) => item.type === 'thinking'); + const thinking = content.find((item) => (item.type as any) === 'thinking'); if (role === 'user') { return { variant: 'base', @@ -166,9 +169,7 @@ export default function chatSample() { }; useEffect(() => { - reqParamsRef.current = { - search: activeSearch, - }; + reqParamsRef.current.search = activeSearch; }, [activeSearch]); useEffect(() => { @@ -187,7 +188,7 @@ export default function chatSample() { senderProps={{ placeholder: '有问题,尽管问~ Enter 发送,Shift+Enter 换行', }} - chatServiceConfig={chatServiceConfig} + chatServiceConfig={chatServiceConfig as any} onChatReady={() => { setReady(true); }} diff --git a/packages/pro-components/chat/chatbot/_example/custom-content.tsx b/packages/pro-components/chat/chatbot/_example/custom-content.tsx index b23eea9cd6..9702b10ee7 100644 --- a/packages/pro-components/chat/chatbot/_example/custom-content.tsx +++ b/packages/pro-components/chat/chatbot/_example/custom-content.tsx @@ -129,12 +129,12 @@ export default function CustomContent() { return (
{ - setMessages(e.detail); + setMessages(e.detail as any); }} > {/* 4. 植入自定义内容渲染插槽 */} diff --git a/packages/pro-components/chat/chatbot/_example/custom-merge.tsx b/packages/pro-components/chat/chatbot/_example/custom-merge.tsx index ec1522c949..ce471c9abf 100644 --- a/packages/pro-components/chat/chatbot/_example/custom-merge.tsx +++ b/packages/pro-components/chat/chatbot/_example/custom-merge.tsx @@ -57,9 +57,22 @@ const ProgressDemo = ({ data }) => {
{/* 根据完成状态显示不同的文案 */} <> -
{data.label}
+
+ {data.label} +
-
+
{data.current} / {data.total} ({percentage}%)
@@ -72,12 +85,13 @@ export default function CustomMerge() { const [messages, setMessages] = useState([]); useEffect(() => { - if (!chatRef.current?.isChatEngineReady) { + if (!(chatRef.current as any)?.isChatEngineReady) { return; } // 注册自定义合并策略 // 当内置的 strategy 无法满足需求时,可以注册自定义合并策略 + // @ts-ignore chatRef.current.registerMergeStrategy('progress', (newChunk, existingChunk) => { if (!existingChunk) { // 首次接收,直接返回新数据 @@ -147,12 +161,12 @@ export default function CustomMerge() {
{ - setMessages(e.detail); + setMessages(e.detail as any); }} > {/* 渲染自定义进度条 */} diff --git a/packages/pro-components/chat/chatbot/_example/custom.tsx b/packages/pro-components/chat/chatbot/_example/custom.tsx index c76b1a6c44..f14cfd433e 100644 --- a/packages/pro-components/chat/chatbot/_example/custom.tsx +++ b/packages/pro-components/chat/chatbot/_example/custom.tsx @@ -4,8 +4,8 @@ import { Button, Space } from 'tdesign-react'; import TvisionTcharts from 'tvision-charts-react'; import { ChatBot } from '@tdesign-react/chat'; +import type { AIContentChunkUpdate } from '@tdesign/ai-chat-engine'; import type { - AIContentChunkUpdate, ChatBaseContent, ChatMessagesData, ChatRequestParams, @@ -170,9 +170,9 @@ export default function ChatBotReact() { senderProps={{ defaultValue: '北京今天早晚高峰交通情况如何,需要分别给出曲线图表示每个时段', }} - chatServiceConfig={chatServiceConfig} + chatServiceConfig={chatServiceConfig as any} onMessageChange={(e) => { - setMockMessage(e.detail); + setMockMessage(e.detail as any); }} > {/* 4、植入自定义消息体渲染插槽 */} diff --git a/packages/pro-components/chat/chatbot/_example/docs.tsx b/packages/pro-components/chat/chatbot/_example/docs.tsx index dfba531c1c..67c673f23e 100644 --- a/packages/pro-components/chat/chatbot/_example/docs.tsx +++ b/packages/pro-components/chat/chatbot/_example/docs.tsx @@ -164,7 +164,7 @@ export default function chatSample() { onFileRemove, }} onChatAfterSend={onSend} - chatServiceConfig={chatServiceConfig} + chatServiceConfig={chatServiceConfig as any} >
); diff --git a/packages/pro-components/chat/chatbot/_example/image.tsx b/packages/pro-components/chat/chatbot/_example/image.tsx index e50ec71f37..452eba60f1 100644 --- a/packages/pro-components/chat/chatbot/_example/image.tsx +++ b/packages/pro-components/chat/chatbot/_example/image.tsx @@ -94,7 +94,9 @@ const BasicImageViewer = ({ images }) => { alignItems: 'center', justifyContent: 'center', }} - onClick={open} + onClick={() => { + open(); + }} > 预览 @@ -131,7 +133,10 @@ export default function chatSample() { const chatRef = useRef(null); const [ratio, setRatio] = useState(0); const [style, setStyle] = useState(''); - const reqParamsRef = useRef<{ ratio: number; style: string; file?: string }>({ ratio: 0, style: '' }); + const reqParamsRef = useRef<{ ratio: number; style: string; file?: string }>({ + ratio: 0, + style: '', + }); const [files, setFiles] = useState([]); const [mockMessage, setMockMessage] = React.useState(mockData); @@ -220,7 +225,7 @@ export default function chatSample() { const newFile = { ...e.detail[0], name: e.detail[0].name, - status: 'progress' as ['status'], + status: 'progress' as const, description: '上传中', }; @@ -251,7 +256,7 @@ export default function chatSample() { const { value, attachments } = e.detail; setFiles([]); // 清除掉附件区域 return { - attachments, + attachments: attachments as any, prompt: `${value},要求比例:${ ratio === 0 ? '默认比例' : RatioOptions.filter(({ value }) => value === ratio)[0].content }, 风格:${style ? StyleOptions.filter(({ value }) => value === style)[0].content : '默认风格'}`, @@ -293,9 +298,9 @@ export default function chatSample() { onFileSelect, onFileRemove, }} - chatServiceConfig={chatServiceConfig} + chatServiceConfig={chatServiceConfig as any} onMessageChange={(e) => { - setMockMessage(e.detail); + setMockMessage(e.detail as any); }} > {mockMessage diff --git a/packages/pro-components/chat/chatbot/_example/initial-messages.tsx b/packages/pro-components/chat/chatbot/_example/initial-messages.tsx index 50204a539c..5432d9b866 100644 --- a/packages/pro-components/chat/chatbot/_example/initial-messages.tsx +++ b/packages/pro-components/chat/chatbot/_example/initial-messages.tsx @@ -169,7 +169,7 @@ export default function InitialMessages() { ref={chatRef} defaultMessages={defaultMessages} messageProps={messageProps} - chatServiceConfig={chatServiceConfig} + chatServiceConfig={chatServiceConfig as any} />
diff --git a/packages/pro-components/chat/chatbot/_example/instance-methods.tsx b/packages/pro-components/chat/chatbot/_example/instance-methods.tsx index 67b10cddcf..09611cfca7 100644 --- a/packages/pro-components/chat/chatbot/_example/instance-methods.tsx +++ b/packages/pro-components/chat/chatbot/_example/instance-methods.tsx @@ -175,7 +175,7 @@ export default function InstanceMethods() { {/* 聊天组件 */}
- +
); diff --git a/packages/pro-components/chat/chatbot/_example/nostream.tsx b/packages/pro-components/chat/chatbot/_example/nostream.tsx index 8c1d42a6bf..fbc97901d3 100644 --- a/packages/pro-components/chat/chatbot/_example/nostream.tsx +++ b/packages/pro-components/chat/chatbot/_example/nostream.tsx @@ -9,7 +9,10 @@ export default function chatSample() { const chatRef = useRef(null); const [activeR1, setR1Active] = useState(false); const [activeSearch, setSearchActive] = useState(false); - const reqParamsRef = useRef<{ think: boolean; search: boolean }>({ think: false, search: false }); + const reqParamsRef = useRef<{ think: boolean; search: boolean }>({ + think: false, + search: false, + }); // 聊天服务配置 const chatServiceConfig: ChatServiceConfig = { @@ -64,7 +67,7 @@ export default function chatSample() { senderProps={{ placeholder: '有问题,尽管问~ Enter 发送,Shift+Enter 换行', }} - chatServiceConfig={chatServiceConfig} + chatServiceConfig={chatServiceConfig as any} >
); diff --git a/packages/pro-components/chat/chatbot/_example/quick-start.tsx b/packages/pro-components/chat/chatbot/_example/quick-start.tsx index 2e2e3a8d21..5efd9bc055 100644 --- a/packages/pro-components/chat/chatbot/_example/quick-start.tsx +++ b/packages/pro-components/chat/chatbot/_example/quick-start.tsx @@ -30,7 +30,7 @@ export default function QuickStart() { return (
- +
); } diff --git a/packages/pro-components/chat/chatbot/_example/research.tsx b/packages/pro-components/chat/chatbot/_example/research.tsx index fad6d2ccc9..f5faaa6000 100644 --- a/packages/pro-components/chat/chatbot/_example/research.tsx +++ b/packages/pro-components/chat/chatbot/_example/research.tsx @@ -11,8 +11,8 @@ import type { TdAttachmentItem, TdChatbotApi, TdChatMessageConfig, - UploadFile, } from '@tdesign-react/chat'; +import type { UploadFile } from 'tdesign-react'; // 默认初始化消息 const mockData: ChatMessagesData[] = [ @@ -166,7 +166,7 @@ export default function chatSample() { onFileSelect, onFileRemove, }} - chatServiceConfig={chatServiceConfig} + chatServiceConfig={chatServiceConfig as any} >
); diff --git a/packages/pro-components/chat/chatbot/_example/role-message-config.tsx b/packages/pro-components/chat/chatbot/_example/role-message-config.tsx index 0bbbcdfec1..468bf2cc9a 100644 --- a/packages/pro-components/chat/chatbot/_example/role-message-config.tsx +++ b/packages/pro-components/chat/chatbot/_example/role-message-config.tsx @@ -111,7 +111,10 @@ console.log(greeting); { type: 'suggestion', data: [ - { title: '继续了解 TDesign', prompt: '告诉我更多关于 TDesign 的信息' }, + { + title: '继续了解 TDesign', + prompt: '告诉我更多关于 TDesign 的信息', + }, { title: '查看组件列表', prompt: 'TDesign 有哪些组件?' }, { title: '如何使用', prompt: '如何在项目中使用 TDesign?' }, ], @@ -214,7 +217,11 @@ console.log(greeting); return (
- +
); } diff --git a/packages/pro-components/chat/chatbot/_example/sender-config.tsx b/packages/pro-components/chat/chatbot/_example/sender-config.tsx index f199750514..73f23ae600 100644 --- a/packages/pro-components/chat/chatbot/_example/sender-config.tsx +++ b/packages/pro-components/chat/chatbot/_example/sender-config.tsx @@ -146,7 +146,7 @@ export default function SenderConfig() { {/* 聊天组件 */}
- +
); diff --git a/packages/pro-components/chat/chatbot/_example/service-config.tsx b/packages/pro-components/chat/chatbot/_example/service-config.tsx index 7e6b75776c..0fe9f6c90a 100644 --- a/packages/pro-components/chat/chatbot/_example/service-config.tsx +++ b/packages/pro-components/chat/chatbot/_example/service-config.tsx @@ -130,7 +130,7 @@ export default function ServiceConfig() { return (
- +
); } diff --git a/packages/pro-components/chat/chatbot/_example/utils/messageRenderer.tsx b/packages/pro-components/chat/chatbot/_example/utils/messageRenderer.tsx index 1c4cc4328c..7318ef1b85 100644 --- a/packages/pro-components/chat/chatbot/_example/utils/messageRenderer.tsx +++ b/packages/pro-components/chat/chatbot/_example/utils/messageRenderer.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { HotelCard, HumanInputResult, ItineraryCard, WeatherCard } from '../components'; +import { HotelCard, HumanInputResult, WeatherCard } from '../../../chat-engine/_example/components'; +import { ItineraryCard } from '../components'; import type { AIMessageContent, ChatMessagesData } from '@tdesign-react/chat'; @@ -63,7 +64,7 @@ export const renderMessageContent = ({ item, index, message }: MessageRendererPr } // 规划状态面板 - 不在消息中显示,只用于更新右侧面板 - if (item.type === 'planningState') { + if ((item.type as any) === 'planningState') { return null; } diff --git a/packages/tdesign-react-aigc/site/src/main.jsx b/packages/tdesign-react-aigc/site/src/main.jsx index 4091c5db1d..15cc48d2d2 100644 --- a/packages/tdesign-react-aigc/site/src/main.jsx +++ b/packages/tdesign-react-aigc/site/src/main.jsx @@ -1,18 +1,18 @@ +// import tdesign style; +import '@tdesign/pro-components-chat/style/index.js'; +import '@tdesign/theme-generator'; + import React from 'react'; import { createRoot } from 'react-dom/client'; import { registerLocaleChange } from '@tdesign/site-components'; -import App from './App'; -// import tdesign style; -import '@tdesign/pro-components-chat/style/index.js'; -import '@tdesign/common-style/web/docs.less'; +import App from './App'; import '@tdesign/site-components/lib/styles/style.css'; +import '@tdesign/common-style/web/docs.less'; import '@tdesign/site-components/lib/styles/prism-theme.less'; import '@tdesign/site-components/lib/styles/prism-theme-dark.less'; -import '@tdesign/theme-generator'; - const rootElement = document.getElementById('app'); const root = createRoot(rootElement); diff --git a/packages/tdesign-react-aigc/site/vite.config.js b/packages/tdesign-react-aigc/site/vite.config.js index 2b593a03a0..c63f41548d 100644 --- a/packages/tdesign-react-aigc/site/vite.config.js +++ b/packages/tdesign-react-aigc/site/vite.config.js @@ -1,7 +1,9 @@ import path, { dirname } from 'path'; import { fileURLToPath } from 'url'; + import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; + import pkg from '../package.json'; import tdocPlugin from './plugin-tdoc'; import changelog2Json from './plugins/changelog-to-json'; @@ -48,9 +50,6 @@ export default ({ mode }) => }, }, }, - define: { - __VERSION__: JSON.stringify(pkg.version), - }, jsx: 'react', server: { host: '0.0.0.0', diff --git a/script/rollup.config.js b/script/rollup.config.js index c27c102be1..b3a7b6a507 100644 --- a/script/rollup.config.js +++ b/script/rollup.config.js @@ -1,21 +1,22 @@ -import url from '@rollup/plugin-url'; -import json from '@rollup/plugin-json'; -import babel from '@rollup/plugin-babel'; -import styles from 'rollup-plugin-styles'; +import { join, resolve } from 'path'; + +import { copy as fileCopy } from 'fs-extra'; +import analyzer from 'rollup-plugin-analyzer'; import copy from 'rollup-plugin-copy'; import esbuild from 'rollup-plugin-esbuild'; +import ignoreImport from 'rollup-plugin-ignore-import'; +import multiInput from 'rollup-plugin-multi-input'; import postcss from 'rollup-plugin-postcss'; -import replace from '@rollup/plugin-replace'; -import analyzer from 'rollup-plugin-analyzer'; +import staticImport from 'rollup-plugin-static-import'; +import styles from 'rollup-plugin-styles'; import { terser } from 'rollup-plugin-terser'; -import commonjs from '@rollup/plugin-commonjs'; import { DEFAULT_EXTENSIONS } from '@babel/core'; -import multiInput from 'rollup-plugin-multi-input'; +import babel from '@rollup/plugin-babel'; +import commonjs from '@rollup/plugin-commonjs'; +import json from '@rollup/plugin-json'; import nodeResolve from '@rollup/plugin-node-resolve'; -import staticImport from 'rollup-plugin-static-import'; -import ignoreImport from 'rollup-plugin-ignore-import'; -import { resolve, join } from 'path'; -import { copy as fileCopy } from 'fs-extra'; +import replace from '@rollup/plugin-replace'; +import url from '@rollup/plugin-url'; import pkg from '../packages/tdesign-react/package.json'; diff --git a/test/utils/index.jsx b/test/utils/index.jsx index 9bd47c3b7e..fbaefaa353 100644 --- a/test/utils/index.jsx +++ b/test/utils/index.jsx @@ -1,7 +1,8 @@ import '@testing-library/jest-dom'; + +import { vi } from 'vitest'; import { act, createEvent, fireEvent } from '@testing-library/react'; import _userEvent from '@testing-library/user-event'; -import { vi } from 'vitest'; import { EVENTS_MAP } from './events'; @@ -175,10 +176,11 @@ export function mockIntersectionObserver(mockData, mockFunc) { }, ]; - window.IntersectionObserver = vi.fn((callback, { root, rootMargin }) => ({ + window.IntersectionObserver = vi.fn((callback, { root, rootMargin, scrollMargin }) => ({ root, rootMargin, thresholds, + scrollMargin, observe: observe ? (element) => { observe(element, callback); diff --git a/tsconfig.aigc.build.json b/tsconfig.aigc.build.json index 20729ce2e8..1eeecc35f5 100644 --- a/tsconfig.aigc.build.json +++ b/tsconfig.aigc.build.json @@ -1,6 +1,6 @@ { "extends": "./tsconfig", - "include": ["packages/pro-components/chat"], + "include": ["packages/pro-components/chat", "./globals.d.ts"], "exclude": [ "**/**/__tests__/*", "**/**/_example/*", diff --git a/tsconfig.dev.json b/tsconfig.dev.json index f35b36b264..09f83fcf6a 100644 --- a/tsconfig.dev.json +++ b/tsconfig.dev.json @@ -19,10 +19,12 @@ "compilerOptions": { "declaration": false, "paths": { - "tdesign-react": ["packages/components"], - "@test/utils": ["test/utils"], - "@common/*": ["packages/common/*"], - "@tdesign-react/chat": ["packages/pro-components/chat"], + "tdesign-react": ["./packages/components"], + "@test/utils": ["./test/utils"], + "@common/*": ["./packages/common/*"], + "@tdesign-react/chat": ["./packages/pro-components/chat"], }, + "rootDir": "packages/components", + "noEmit": true } -} \ No newline at end of file +} diff --git a/tsconfig.json b/tsconfig.json index 244253835b..6586e7c471 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "jsx": "react", "experimentalDecorators": true, - "moduleResolution": "node", + "moduleResolution": "bundler", "module": "esnext", "target": "esnext", "outDir": "lib", @@ -14,32 +14,41 @@ ], "importHelpers": true, "allowSyntheticDefaultImports": true, - "baseUrl": "./", "paths": { "tdesign-react": [ - "packages/components" + "./packages/components" ], "tdesign-react/*": [ - "packages/components/*" + "./packages/components/*" + ], + "tdesign-react/es/locale/*": [ + "./packages/components/locale/*" ], "@tdesign-react/chat": [ - "packages/pro-components/chat" + "./packages/pro-components/chat" ], "@tdesign-react/chat/*": [ - "packages/pro-components/chat/*" + "./packages/pro-components/chat/*" ], "@test/utils": [ - "test/utils" + "./test/utils" ], "@common/*": [ - "packages/common/*" + "./packages/common/*" ], }, + "types": [ + "node", + "jest", + "vitest/globals", + "@testing-library/jest-dom", + "@testing-library/react" + ], "allowJs": true, "checkJs": true, - "downlevelIteration": true, "esModuleInterop": true, - "skipLibCheck": true + "skipLibCheck": true, + "strict": false }, "include": [ "./packages/components", @@ -58,13 +67,5 @@ "cjs", "es" ], - "types": [ - "node", - "jest", - "vitest/globals", - "@testing-library/jest-dom", - "@testing-library/react-hooks", - "@testing-library/react" - ], "compileOnSave": false } diff --git a/tsconfig.vitest.json b/tsconfig.vitest.json new file mode 100644 index 0000000000..9253770c95 --- /dev/null +++ b/tsconfig.vitest.json @@ -0,0 +1,24 @@ +{ + "extends": "./tsconfig", + "include": [ + "./packages/components", + "./globals.d.ts" + ], + "exclude": [ + "**/**/__tests__/*", + "**/**/_example-js/*", + "**/config-provider/_example/*", + "**/**/_usage/*", + "node_modules", + "dist", + "lib", + "esm", + "cjs", + "es" + ], + "compilerOptions": { + "declaration": false, + "moduleResolution": "nodenext", + "module": "nodenext" + } +} diff --git a/vitest.config.mts b/vitest.config.mts index bf682b449d..9f15467057 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -1,9 +1,11 @@ import path from 'path'; + import { defineConfig } from 'vitest/config'; -import { InlineConfig } from 'vitest/node'; import pkg from './packages/tdesign-react/package.json'; +import type { InlineConfig } from 'vitest/node'; + // 单元测试相关配置 const testConfig: InlineConfig = { include: @@ -21,6 +23,9 @@ const testConfig: InlineConfig = { reporter: ['text', 'json', 'html'], reportsDirectory: 'test/coverage', }, + typecheck: { + tsconfig: './tsconfig.vitest.json', + }, }; export default defineConfig({