diff --git a/package.json b/package.json index bc8afcc4..4a2a4aae 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "init": "git submodule update --init packages/common", "dev:ui": "pnpm --filter @tdesign/web-components-site dev", "dev:chat": "pnpm --filter @tdesign/web-components-chat-site dev", - "check:types": "tsc -p packages/vite-config/tsconfig.check.json && node --import tsx/esm ./packages/vite-config/src/cli/prepare.mjs && pnpm --filter @tdesign/web-components-shared build && tsc -p packages/components/tsconfig.check.json && pnpm --filter @tdesign/components build && tsc -p packages/pro-components/chat/tsconfig.check.json", + "check:types": "tsc -p packages/vite-config/tsconfig.check.json && node --import tsx/esm ./packages/vite-config/src/cli/prepare.mjs && pnpm --filter @tdesign/web-components-shared build && tsc -p packages/components/tsconfig.check.json && pnpm --filter @tdesign/components build && tsc -p packages/pro-components/chat/tsconfig.check.json && pnpm run check:chat-contracts", + "check:chat-contracts": "node scripts/check-chat-contracts.mjs", "check:pack": "pnpm run build:chat && node scripts/check-pack.mjs", "build": "pnpm run build:chat", "build:ui": "pnpm --filter @tdesign/web-components build", @@ -69,7 +70,7 @@ "vitest": "catalog:tooling" }, "engines": { - "node": ">=22.13.0" + "node": ">=22.18.0" }, "pnpm": { "overrides": { diff --git a/packages/components/affix/affix.tsx b/packages/components/affix/affix.tsx index 10255ed8..396b87d0 100644 --- a/packages/components/affix/affix.tsx +++ b/packages/components/affix/affix.tsx @@ -4,9 +4,9 @@ import { ScrollContainerElement, StyledProps } from '@tdesign/web-components-sha import { isFunction } from 'lodash-es'; import { Component, createRef, tag } from 'omi'; -import { AffixRef, TdAffixProps } from './type'; +import { TdAffixProps } from './type'; -export interface AffixProps extends TdAffixProps, StyledProps, AffixRef {} +export interface AffixProps extends TdAffixProps, StyledProps {} @tag('t-affix') export default class Affix extends Component { diff --git a/packages/components/affix/index.ts b/packages/components/affix/index.ts index f9d2e22d..57f91705 100644 --- a/packages/components/affix/index.ts +++ b/packages/components/affix/index.ts @@ -3,7 +3,6 @@ import './style/index.js'; import _Affix from './affix'; export type { AffixProps } from './affix'; +export type { AffixRef } from './type'; export const Affix = _Affix; export default Affix; - -export * from './type'; diff --git a/packages/components/avatar/index.tsx b/packages/components/avatar/index.tsx index 9004b9be..265ef2ee 100644 --- a/packages/components/avatar/index.tsx +++ b/packages/components/avatar/index.tsx @@ -4,9 +4,9 @@ import _Avatar from './avatar'; import _AvatarGroup from './avatar-group'; export type { AvatarProps } from './avatar'; +export type { AvatarGroupProps } from './avatar-group'; +export type { CascadingValue, ShapeEnum } from './type'; export const Avatar = _Avatar; export const AvatarGroup = _AvatarGroup; export default Avatar; - -export * from './type'; diff --git a/packages/components/avatar/type.ts b/packages/components/avatar/type.ts index d5fd83a9..28cd2da9 100644 --- a/packages/components/avatar/type.ts +++ b/packages/components/avatar/type.ts @@ -1,12 +1,11 @@ -/* eslint-disable */ - /** * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ +import { TElement, TNode } from '@tdesign/web-components-shared/common'; + import { ImageProps } from '../image'; import { PopupProps } from '../popup'; -import { TNode, TElement } from '@tdesign/web-components-shared/common'; export interface TdAvatarProps { /** diff --git a/packages/components/breadcrumb/breadcrumb-item.tsx b/packages/components/breadcrumb/breadcrumb-item.tsx index 12267d2c..907429b8 100644 --- a/packages/components/breadcrumb/breadcrumb-item.tsx +++ b/packages/components/breadcrumb/breadcrumb-item.tsx @@ -8,7 +8,7 @@ import { bind, Component, OmiDOMAttributes, tag } from 'omi'; import { TdBreadcrumbItemProps } from './type'; -interface BreadcrumbItemProps extends TdBreadcrumbItemProps, OmiDOMAttributes {} +export interface BreadcrumbItemProps extends TdBreadcrumbItemProps, OmiDOMAttributes {} interface LocalTBreadcrumb { separator: TNode | string; diff --git a/packages/components/breadcrumb/breadcrumb.tsx b/packages/components/breadcrumb/breadcrumb.tsx index f83952bb..7fbe59e1 100644 --- a/packages/components/breadcrumb/breadcrumb.tsx +++ b/packages/components/breadcrumb/breadcrumb.tsx @@ -7,7 +7,7 @@ import { Component, tag } from 'omi'; import { TdBreadcrumbProps } from './type'; -interface BreadcrumbProps extends TdBreadcrumbProps, StyledProps {} +export interface BreadcrumbProps extends TdBreadcrumbProps, StyledProps {} @tag('t-breadcrumb') export default class Breadcrumb extends Component { diff --git a/packages/components/breadcrumb/index.ts b/packages/components/breadcrumb/index.ts index cc2b4ee2..055a6b83 100644 --- a/packages/components/breadcrumb/index.ts +++ b/packages/components/breadcrumb/index.ts @@ -3,8 +3,8 @@ import './style/index.js'; import _Breadcrumb from './breadcrumb'; import _BreadcrumbItem from './breadcrumb-item'; -export type { TdBreadcrumbItemProps, TdBreadcrumbProps } from './type'; -export * from './type'; +export type { BreadcrumbProps } from './breadcrumb'; +export type { BreadcrumbItemProps } from './breadcrumb-item'; export const Breadcrumb = _Breadcrumb; export const BreadcrumbItem = _BreadcrumbItem; export default Breadcrumb; diff --git a/packages/components/button/index.ts b/packages/components/button/index.ts index d4ae1c0d..025d1a14 100644 --- a/packages/components/button/index.ts +++ b/packages/components/button/index.ts @@ -1,9 +1,6 @@ import './style/index.js'; import _Button from './button'; - export type { ButtonProps } from './button'; export const Button = _Button; export default Button; - -export * from './type'; diff --git a/packages/components/card/index.ts b/packages/components/card/index.ts index eeab2fbc..2c74f195 100644 --- a/packages/components/card/index.ts +++ b/packages/components/card/index.ts @@ -1,9 +1,6 @@ import './style/index.js'; import _Card from './card.jsx'; - export type { CardProps } from './card.jsx'; export const Card = _Card; export default Card; - -export * from './type'; diff --git a/packages/components/card/type.ts b/packages/components/card/type.ts index e26c50c4..a189e13a 100644 --- a/packages/components/card/type.ts +++ b/packages/components/card/type.ts @@ -1,7 +1,7 @@ -/* eslint-disable */ -import { LoadingProps } from '../loading'; import { TNode } from '@tdesign/web-components-shared/common'; +import { LoadingProps } from '../loading'; + export interface TdCardProps { /** * 卡片操作区 diff --git a/packages/components/checkbox/checkbox-group.tsx b/packages/components/checkbox/checkbox-group.tsx index 9d722b0d..dfeb655d 100644 --- a/packages/components/checkbox/checkbox-group.tsx +++ b/packages/components/checkbox/checkbox-group.tsx @@ -14,8 +14,7 @@ import { } from './type'; export interface CheckboxGroupProps - extends TdCheckboxGroupProps, - StyledProps { + extends TdCheckboxGroupProps, StyledProps { children?: TNode; } diff --git a/packages/components/checkbox/index.ts b/packages/components/checkbox/index.ts index 180d3420..3e63c209 100644 --- a/packages/components/checkbox/index.ts +++ b/packages/components/checkbox/index.ts @@ -2,14 +2,11 @@ import './style/index'; import _Checkbox from './checkbox'; import _Group from './checkbox-group'; -import type { TdCheckboxGroupProps, TdCheckboxProps } from './type'; -export type CheckboxProps = TdCheckboxProps; -export type CheckboxGroupProps = TdCheckboxGroupProps; +export type { CheckboxProps } from './checkbox'; +export type { CheckboxGroupProps } from './checkbox-group'; +export type { CheckboxGroupChangeContext, CheckboxGroupValue, CheckboxOption, CheckboxOptionObj } from './type'; export const Checkbox = _Checkbox; export const CheckboxGroup = _Group; - -export * from './type'; - export default Checkbox; diff --git a/packages/components/collapse/index.ts b/packages/components/collapse/index.ts index 29537cab..76217220 100644 --- a/packages/components/collapse/index.ts +++ b/packages/components/collapse/index.ts @@ -4,7 +4,6 @@ import _Collapse from './collapse'; export type { CollapseProps } from './collapse'; export { default as CollapsePanel, type CollapsePanelProps } from './collapse-panel'; -export * from './type'; - +export type { CollapsePanelValue, CollapseValue } from './type'; export const Collapse = _Collapse; export default Collapse; diff --git a/packages/components/date-picker/index.ts b/packages/components/date-picker/index.ts index 7f16e131..4f92677a 100644 --- a/packages/components/date-picker/index.ts +++ b/packages/components/date-picker/index.ts @@ -5,10 +5,9 @@ import _DateRangePicker from './DateRangePicker'; export type { DatePickerProps } from './DatePicker'; export type { DateRangePickerProps } from './DateRangePicker'; +export type { DateRangeValue, DateValue, DisableDate, DisableDateObject, PresetDate, PresetRange } from './type'; export const DatePicker = _DatePicker; export const DateRangePicker = _DateRangePicker; export default DatePicker; - -export * from './type'; diff --git a/packages/components/date-picker/panel/RangePanel.tsx b/packages/components/date-picker/panel/RangePanel.tsx index 1a31b74f..220ea3bc 100644 --- a/packages/components/date-picker/panel/RangePanel.tsx +++ b/packages/components/date-picker/panel/RangePanel.tsx @@ -23,6 +23,7 @@ import { Component, createRef, OmiProps, tag } from 'omi'; import { PaginationMini } from '../../pagination/PaginationMini'; import { TdPaginationMiniProps } from '../../pagination/type'; import { DateValue, DisableDate, PresetRange, TdDateRangePickerProps } from '../type'; +import type { DatePickerTableCell } from './internal-type'; dayjs.locale('zh-cn'); dayjs.extend(isoWeek); @@ -42,26 +43,6 @@ interface WeekInfo { week: number; } -export interface DatePickerTableCell { - text: string | number; - value: Date; - time?: string; - active?: boolean; - highlight?: boolean; - hoverHighlight?: boolean; - disabled?: boolean; - additional?: boolean; - now?: boolean; - firstDayOfMonth?: boolean; - lastDayOfMonth?: boolean; - weekOfYear?: boolean; - startOfRange?: boolean; - endOfRange?: boolean; - hoverStartOfRange?: boolean; - hoverEndOfRange?: boolean; - dayjsObj?: any; -} - export interface RangePanelProps extends Pick< TdDateRangePickerProps, 'mode' | 'firstDayOfWeek' | 'disableDate' | 'presets' | 'presetsPlacement' | 'panelPreselection' diff --git a/packages/components/date-picker/panel/SinglePanel.tsx b/packages/components/date-picker/panel/SinglePanel.tsx index ce11134a..b917099f 100644 --- a/packages/components/date-picker/panel/SinglePanel.tsx +++ b/packages/components/date-picker/panel/SinglePanel.tsx @@ -23,6 +23,7 @@ import { Component, createRef, OmiProps, tag } from 'omi'; import { PaginationMini } from '../../pagination/PaginationMini'; import { TdPaginationMiniProps } from '../../pagination/type'; import { DateValue, DisableDate, PresetDate, TdDatePickerProps } from '../type'; +import type { DatePickerTableCell } from './internal-type'; dayjs.locale('zh-cn'); dayjs.extend(isoWeek); @@ -37,26 +38,6 @@ interface YearOption { type ScrollAnchor = 'default' | 'top' | 'bottom'; -export interface DatePickerTableCell { - text: string | number; - value: Date; - time?: string; - active?: boolean; - highlight?: boolean; - hoverHighlight?: boolean; - disabled?: boolean; - additional?: boolean; - now?: boolean; - firstDayOfMonth?: boolean; - lastDayOfMonth?: boolean; - weekOfYear?: boolean; - startOfRange?: boolean; - endOfRange?: boolean; - hoverStartOfRange?: boolean; - hoverEndOfRange?: boolean; - dayjsObj?: any; -} - export interface SinglePanelProps extends Pick< TdDatePickerProps, 'mode' | 'firstDayOfWeek' | 'disableDate' | 'minDate' | 'maxDate' diff --git a/packages/components/date-picker/panel/internal-type.ts b/packages/components/date-picker/panel/internal-type.ts new file mode 100644 index 00000000..8c5f48b1 --- /dev/null +++ b/packages/components/date-picker/panel/internal-type.ts @@ -0,0 +1,20 @@ +/** DatePicker 单面板与范围面板共享的内部单元格结构。 */ +export interface DatePickerTableCell { + text: string | number; + value: Date; + time?: string; + active?: boolean; + highlight?: boolean; + hoverHighlight?: boolean; + disabled?: boolean; + additional?: boolean; + now?: boolean; + firstDayOfMonth?: boolean; + lastDayOfMonth?: boolean; + weekOfYear?: boolean; + startOfRange?: boolean; + endOfRange?: boolean; + hoverStartOfRange?: boolean; + hoverEndOfRange?: boolean; + dayjsObj?: any; +} diff --git a/packages/components/date-picker/type.ts b/packages/components/date-picker/type.ts index 59c88be9..48cb3841 100644 --- a/packages/components/date-picker/type.ts +++ b/packages/components/date-picker/type.ts @@ -1,6 +1,7 @@ +import type { DateValue as CommonDateValue } from '@common/js/date-picker/utils'; import { TNode } from '@tdesign/web-components-shared/common'; -export type DateValue = string | number | Date; +export type DateValue = CommonDateValue; export type DateRangeValue = Array; diff --git a/packages/components/dialog/index.ts b/packages/components/dialog/index.ts index d818b31e..afa70209 100644 --- a/packages/components/dialog/index.ts +++ b/packages/components/dialog/index.ts @@ -2,10 +2,29 @@ import './style/index.js'; import _Dialog from './dialog'; import { DialogPlugin as _DialogPlugin } from './plugin'; +import type { + DialogAlertMethod, + DialogCloseContext, + DialogConfirmMethod, + DialogEventSource, + DialogInstance, + DialogMethod, + DialogOptions, + TdDialogCardProps, +} from './type'; -export type { DialogProps } from './dialog'; -export * from './type'; +export type { + DialogAlertMethod, + DialogCloseContext, + DialogConfirmMethod, + DialogEventSource, + DialogInstance, + DialogMethod, + DialogOptions, + TdDialogCardProps, +}; +export type { DialogProps } from './dialog'; export const Dialog = _Dialog; export const dialog = _DialogPlugin; export const DialogPlugin = _DialogPlugin; diff --git a/packages/components/dialog/type.ts b/packages/components/dialog/type.ts index d5026638..87540f1f 100644 --- a/packages/components/dialog/type.ts +++ b/packages/components/dialog/type.ts @@ -1,11 +1,10 @@ -/* eslint-disable */ - /** * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ +import { AttachNode, Styles, TNode } from '@tdesign/web-components-shared/common'; + import { ButtonProps } from '../button'; -import { TNode, Styles, AttachNode } from '@tdesign/web-components-shared/common'; export interface TdDialogProps { /** @@ -153,20 +152,19 @@ export interface TdDialogProps { children?: TNode; } -export interface TdDialogCardProps - extends Pick< - TdDialogProps, - | 'body' - | 'cancelBtn' - | 'closeBtn' - | 'confirmBtn' - | 'footer' - | 'header' - | 'theme' - | 'onCancel' - | 'onCloseBtnClick' - | 'onConfirm' - > {} +export type TdDialogCardProps = Pick< + TdDialogProps, + | 'body' + | 'cancelBtn' + | 'closeBtn' + | 'confirmBtn' + | 'footer' + | 'header' + | 'theme' + | 'onCancel' + | 'onCloseBtnClick' + | 'onConfirm' +>; export interface DialogOptions extends Omit { /** diff --git a/packages/components/divider/index.ts b/packages/components/divider/index.ts index 2fb88271..c4228fa6 100644 --- a/packages/components/divider/index.ts +++ b/packages/components/divider/index.ts @@ -1,9 +1,6 @@ import './style/index.js'; import _Divider from './divider'; - export type { DividerProps } from './divider'; -export * from './type'; - export const Divider = _Divider; export default Divider; diff --git a/packages/components/dropdown/README.md b/packages/components/dropdown/README.md index fe2f5f34..a3c589b6 100644 --- a/packages/components/dropdown/README.md +++ b/packages/components/dropdown/README.md @@ -85,7 +85,7 @@ hideAfterItemClick | Boolean | true | 点击选项后是否自动隐藏弹窗 | maxColumnWidth | String / Number | 100 | 选项最大宽度,内容超出时,显示为省略号。值为字符串时,值就是最大宽度;值为数字时,单位:px | N maxHeight | Number | 300 | 弹窗最大高度,单位:px 。统一控制每一列的高度 | N minColumnWidth | String / Number | 10 | 选项最小宽度。值为字符串时,值就是最小宽度;值为数字时,单位:px | N -options | Array | [] | 下拉操作项。TS 类型:`Array` `type DropdownOption = { children?: Array } & TdDropdownItemProps & Record`。[详细类型定义](https://github.com/TDesignOteam/tdesign-web-components/tree/main/src/dropdown/type.ts) | N +options | Array | [] | 下拉操作项。TS 类型:`Array` `type DropdownOption = TdDropdownItemProps & { children?: DropdownOption[] } & Record`。[详细类型定义](https://github.com/TDesignOteam/tdesign-web-components/tree/main/src/dropdown/type.ts) | N panelBottomContent | TNode | - | 面板内的底部内容。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/TDesignOteam/tdesign-web-components/tree/main/src/common.ts) | N panelTopContent | TNode | - | 面板内的顶部内容。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/TDesignOteam/tdesign-web-components/tree/main/src/common.ts) | N placement | String | bottom-left | 弹窗定位方式,可选值同 Popup 组件。可选项:top/left/right/bottom/top-left/top-right/bottom-left/bottom-right/left-top/left-bottom/right-top/right-bottom | N @@ -105,5 +105,5 @@ disabled | Boolean | false | 是否禁用操作项 | N divider | Boolean | false | 是否显示操作项之间的分隔线(分隔线默认在下方) | N prefixIcon | TElement | - | 组件前置图标。TS 类型:`TNode`。[通用类型定义](https://github.com/TDesignOteam/tdesign-web-components/tree/main/src/common.ts) | N theme | String | default | 下拉菜单选项主题。可选项:default/success/warning/error。TS 类型:`DropdownItemTheme` `type DropdownItemTheme = 'default' \| 'success' \| 'warning' \| 'error'`。[详细类型定义](https://github.com/TDesignOteam/tdesign-web-components/tree/main/src/dropdown-menu/type.ts) | N -value | String / Number / Object | - | 下拉操作项唯一标识。TS 类型:`string \| number \| { [key: string]: any }` | N +value | String / Number / Object | - | 下拉操作项唯一标识。TS 类型:`string \| number \| Record` | N onClick | Function | | TS 类型:`(dropdownItem: DropdownOption, context: { e: MouseEvent }) => void`
点击时触发 | N diff --git a/packages/components/dropdown/dropdownMenu.tsx b/packages/components/dropdown/dropdownMenu.tsx index 55963e44..27f7001b 100644 --- a/packages/components/dropdown/dropdownMenu.tsx +++ b/packages/components/dropdown/dropdownMenu.tsx @@ -176,7 +176,7 @@ export default class DropdownMenu extends Component { onClick={ optionItem.disabled || optionItem.children ? () => null - : (value: string | number | { [key: string]: any }, context: { e: MouseEvent }) => + : (value: DropdownOption['value'], context: { e: MouseEvent }) => this.handleItemClick({ data: optionItem, context }) } > diff --git a/packages/components/dropdown/index.ts b/packages/components/dropdown/index.ts index 56896046..6669ea72 100644 --- a/packages/components/dropdown/index.ts +++ b/packages/components/dropdown/index.ts @@ -3,8 +3,7 @@ import './style/index.js'; import _Dropdown from './dropdown'; export type { DropdownProps } from './dropdown'; -export * from './type'; - +export type { DropdownItemTheme, DropdownOption, TdDropdownItemProps } from './type'; export const Dropdown = _Dropdown; export default Dropdown; diff --git a/packages/components/dropdown/type.ts b/packages/components/dropdown/type.ts index 4d63c0dd..97700352 100644 --- a/packages/components/dropdown/type.ts +++ b/packages/components/dropdown/type.ts @@ -1,11 +1,10 @@ -/* eslint-disable */ - /** * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ +import { TElement, TNode } from '@tdesign/web-components-shared/common'; + import { PopupProps } from '../popup'; -import { TNode, TElement } from '@tdesign/web-components-shared/common'; export interface TdDropdownProps { /** @@ -120,13 +119,13 @@ export interface TdDropdownItemProps { /** * 下拉操作项唯一标识 */ - value?: string | number | { [key: string]: any }; + value?: string | number | Record; /** * 点击时触发 */ onClick?: (dropdownItem: DropdownOption, context: { e: MouseEvent }) => void; } -export type DropdownOption = { children?: Array } & TdDropdownItemProps & Record; +export type DropdownOption = TdDropdownItemProps & { children?: DropdownOption[] } & Record; export type DropdownItemTheme = 'default' | 'success' | 'warning' | 'error'; diff --git a/packages/components/grid/index.ts b/packages/components/grid/index.ts index ba030a06..0b012a30 100644 --- a/packages/components/grid/index.ts +++ b/packages/components/grid/index.ts @@ -5,7 +5,6 @@ import _Row from './row'; export type { ColProps } from './col'; export type { RowProps } from './row'; -export * from './type'; - +export type { BaseColProps, GutterObject } from './type'; export const Row = _Row; export const Col = _Col; diff --git a/packages/components/image/README.md b/packages/components/image/README.md index f4b74824..02251bb7 100644 --- a/packages/components/image/README.md +++ b/packages/components/image/README.md @@ -80,7 +80,6 @@ className | String | - | 类名 | N style | Object | - | 样式 | N alt | String | - | 图片描述 | N error | TNode | - | 自定义图片加载失败状态下的显示内容。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/TDesignOteam/tdesign-web-components/src/common.ts) | N -fallback | String | - | 图片加载失败时,显示当前链接设置的图片地址。如果要使用组件图标或完全自定义加载失败时显示的内容,请更为使用 `error` | N fit | String | fill | 图片填充模式。可选项:contain/cover/fill/none/scale-down | N gallery | Boolean | false | 是否展示为图集样式 | N lazy | Boolean | false | 是否开启图片懒加载 | N @@ -89,9 +88,8 @@ overlayContent | TNode | - | 图片上方的浮层内容。TS 类型:`string \ overlayTrigger | String | always | 浮层 `overlayContent` 出现的时机。可选项:always/hover | N placeholder | TNode | - | 占位元素,展示层级低于 `loading` `error` 和图片本身,值类型为字符串时表示占位图片地址。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/TDesignOteam/tdesign-web-components/src/common.ts) | N position | String | center | 等同于原生的 object-position 属性,可选值为 top right bottom left 或 string,可以自定义任何单位,px 或者 百分比 | N -referrerpolicy | String | - | `` 标签的原生属性,[MDN 定义](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)。可选项:no-referrer/no-referrer-when-downgrade/origin/origin-when-cross-origin/same-origin/strict-origin/strict-origin-when-cross-origin/unsafe-url | N shape | String | square | 图片圆角类型。可选项:circle/round/square | N -src | String / Object | - | 用于显示图片的链接或原始图片文件对象。TS 类型:`string \| File` | N -srcset | Object | - | 图片链接集合,用于支持特殊格式的图片,如 `.avif` 和 `.webp`。会优先加载 `srcset` 中的图片格式,浏览器不支持的情况下,加载 `src` 设置的图片地址。TS 类型:`ImageSrcset` `interface ImageSrcset { 'image/avif': string; 'image/webp': string; }`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/image/type.ts) | N -onError | Function | | TS 类型:`(context: { e: ImageEvent }) => void`
图片加载失败时触发 | N -onLoad | Function | | TS 类型:`(context: { e: ImageEvent }) => void`
图片加载完成时触发 | N +src | String | - | 用于显示图片的链接 | N +srcset | Object | - | 图片链接集合,用于支持特殊格式的图片,如 `.avif` 和 `.webp`。会优先加载 `srcset` 中的图片格式,浏览器不支持的情况下,加载 `src` 设置的图片地址。TS 类型:`ImageSrcset`。[详细类型定义](./type.ts) | N +onError | Function | | TS 类型:`(context: { e: Event }) => void`
图片加载失败时触发 | N +onLoad | Function | | TS 类型:`(context: { e: Event }) => void`
图片加载完成时触发 | N diff --git a/packages/components/image/image.en-US.md b/packages/components/image/image.en-US.md index cccfb854..a83012dd 100644 --- a/packages/components/image/image.en-US.md +++ b/packages/components/image/image.en-US.md @@ -9,7 +9,6 @@ className | String | - | 类名 | N style | Object | - | 样式,Typescript:`React.CSSProperties` | N alt | String | - | \- | N error | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/TDesignOteam/tdesign-web-components/tree/main/src/common.ts) | N -fallback | String | - | display `fallback` image on `src` loading failed. you can also use `error` to define more complex error content | N fit | String | fill | options: contain/cover/fill/none/scale-down | N gallery | Boolean | false | \- | N lazy | Boolean | false | \- | N @@ -18,9 +17,8 @@ overlayContent | TNode | - | overlay on the top of image。Typescript:`string overlayTrigger | String | always | options: always/hover | N placeholder | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/TDesignOteam/tdesign-web-components/tree/main/src/common.ts) | N position | String | center | \- | N -referrerpolicy | String | - | attribute of ``, [MDN Definition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)。options: no-referrer/no-referrer-when-downgrade/origin/origin-when-cross-origin/same-origin/strict-origin/strict-origin-when-cross-origin/unsafe-url | N shape | String | square | options: circle/round/square | N -src | String / Object | - | src attribute of ``. image File can also be loaded。Typescript:`string \| File` | N -srcset | Object | - | for `.avif` and `.webp` image url, load `srcset` before `src`。Typescript:`ImageSrcset` `interface ImageSrcset { 'image/avif': string; 'image/webp': string; }`。[see more ts definition](https://github.com/TDesignOteam/tdesign-web-components/tree/main/src/image/type.ts) | N -onError | Function | | Typescript:`(context: { e: ImageEvent }) => void`
trigger on image load failed | N -onLoad | Function | | Typescript:`(context: { e: ImageEvent }) => void`
trigger on image loaded | N \ No newline at end of file +src | String | - | src attribute of `` | N +srcset | Object | - | for `.avif` and `.webp` image url, load `srcset` before `src`。Typescript:`ImageSrcset`。[see more ts definition](./type.ts) | N +onError | Function | | Typescript:`(context: { e: Event }) => void`
trigger on image load failed | N +onLoad | Function | | Typescript:`(context: { e: Event }) => void`
trigger on image loaded | N diff --git a/packages/components/image/type.ts b/packages/components/image/type.ts index 85696f58..780f6296 100644 --- a/packages/components/image/type.ts +++ b/packages/components/image/type.ts @@ -75,90 +75,3 @@ export interface ImageSrcset { 'image/avif': string; 'image/webp': string; } - -export type ImageProps = { - /** - * 图片描述 - * @default '' - */ - alt?: string; - /** - * 自定义图片加载失败状态下的显示内容 - */ - error?: TNode; - /** - * 图片加载失败时,显示当前链接设置的图片地址。如果要使用组件图标或完全自定义加载失败时显示的内容,请更为使用 `error` - * @default '' - */ - fallback?: string; - /** - * 图片填充模式 - * @default fill - */ - fit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down'; - /** - * 是否展示为图集样式 - * @default false - */ - gallery?: boolean; - /** - * 是否开启图片懒加载 - * @default false - */ - lazy?: boolean; - /** - * 自定义加载中状态的图片内容,如:“加载中” - */ - loading?: TNode; - /** - * 图片上方的浮层内容 - */ - overlayContent?: TNode; - /** - * 浮层 `overlayContent` 出现的时机 - * @default always - */ - overlayTrigger?: 'always' | 'hover'; - /** - * 占位元素,展示层级低于 `loading` `error` 和图片本身,值类型为字符串时表示占位图片地址 - */ - placeholder?: TNode; - /** - * 等同于原生的 object-position 属性,可选值为 top right bottom left 或 string,可以自定义任何单位,px 或者 百分比 - * @default center - */ - position?: string; - /** - * `` 标签的原生属性,[MDN 定义](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) - */ - referrerpolicy?: - | 'no-referrer' - | 'no-referrer-when-downgrade' - | 'origin' - | 'origin-when-cross-origin' - | 'same-origin' - | 'strict-origin' - | 'strict-origin-when-cross-origin' - | 'unsafe-url'; - /** - * 图片圆角类型 - * @default square - */ - shape?: 'circle' | 'round' | 'square'; - /** - * 用于显示图片的链接或原始图片文件对象 - */ - src?: string | File; - /** - * 图片链接集合,用于支持特殊格式的图片,如 `.avif` 和 `.webp`。会优先加载 `srcset` 中的图片格式,浏览器不支持的情况下,加载 `src` 设置的图片地址 - */ - srcset?: ImageSrcset; - /** - * 图片加载失败时触发 - */ - onError?: Function; - /** - * 图片加载完成时触发 - */ - onLoad?: Function; -}; diff --git a/packages/components/input/index.ts b/packages/components/input/index.ts index 8184b33c..2a7a4d02 100644 --- a/packages/components/input/index.ts +++ b/packages/components/input/index.ts @@ -5,8 +5,7 @@ import _InputGroup from './input-group'; export type { InputProps, InputRef } from './input'; export type { InputGroupProps } from './input-group'; -export * from './type'; - +export type { InputFormatType, InputValue } from './type'; export const Input = _Input; export const InputGroup = _InputGroup; export default { Input, InputGroup }; diff --git a/packages/components/input/useLengthLimit.ts b/packages/components/input/useLengthLimit.ts index e765373c..47bf46a3 100644 --- a/packages/components/input/useLengthLimit.ts +++ b/packages/components/input/useLengthLimit.ts @@ -22,7 +22,6 @@ export default function useLengthLimit(params: UseLengthLimitParams) { } if (maxcharacter) { const r = getCharacterLength(inputValue, maxcharacter); - console.log(r); if (typeof r === 'object') { return r.characters; } diff --git a/packages/components/list/index.ts b/packages/components/list/index.ts index 8dd0e74b..24ba79c8 100644 --- a/packages/components/list/index.ts +++ b/packages/components/list/index.ts @@ -3,8 +3,7 @@ import './style/index.js'; import _List from './list'; import _ListItem from './list-item'; import _ListMeta from './list-item-meta'; - -export type * from './types'; +export type { ListItemMetaProps, ListItemProps, ListProps } from './types'; export const List = _List; export const ListItem = _ListItem; diff --git a/packages/components/list/list.tsx b/packages/components/list/list.tsx index 9f6054ed..1d922d54 100644 --- a/packages/components/list/list.tsx +++ b/packages/components/list/list.tsx @@ -73,7 +73,6 @@ export default class BackTop extends Component { handleClickLoad = (e: Event, asyncLoading: string) => { if (asyncLoading === 'load-more') { - console.log(e); this.fire('loadMore', { event: e }); } }; diff --git a/packages/components/loading/index.ts b/packages/components/loading/index.ts index 733d1f9f..8f62f1bd 100644 --- a/packages/components/loading/index.ts +++ b/packages/components/loading/index.ts @@ -4,8 +4,7 @@ import _Loading from './loading'; import { LoadingPlugin as _LoadingPlugin } from './plugin'; export type { LoadingProps } from './loading'; -export * from './type'; - +export type { LoadingInstance, LoadingMethod } from './type'; export const Loading = _Loading; export const loading = _LoadingPlugin; export const LoadingPlugin = _LoadingPlugin; diff --git a/packages/components/loading/type.ts b/packages/components/loading/type.ts index 936ee9d5..bb80d696 100644 --- a/packages/components/loading/type.ts +++ b/packages/components/loading/type.ts @@ -1,10 +1,8 @@ -/* eslint-disable */ - /** * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ -import { TNode, AttachNode } from '@tdesign/web-components-shared/common'; +import { AttachNode, TNode } from '@tdesign/web-components-shared/common'; export interface TdLoadingProps { /** diff --git a/packages/components/menu/index.ts b/packages/components/menu/index.ts index 09fedf2e..6e4cb480 100644 --- a/packages/components/menu/index.ts +++ b/packages/components/menu/index.ts @@ -5,8 +5,7 @@ import _MenuItem from './MenuItem'; export type { MenuProps } from './Menu'; export type { MenuItemProps } from './MenuItem'; -export * from './type'; - +export type { MenuValue } from './type'; export const Menu = _Menu; export const MenuItem = _MenuItem; diff --git a/packages/components/message/index.tsx b/packages/components/message/index.tsx index 0aa2d163..37098095 100644 --- a/packages/components/message/index.tsx +++ b/packages/components/message/index.tsx @@ -1,8 +1,44 @@ import './style/index.js'; import _Message, { MessagePlugin as _MessagePlugin } from './message'; +import type { + MessageCloseAllMethod, + MessageConfigMethod, + MessageContainerProps, + MessageErrorMethod, + MessageInfoMethod, + MessageInfoOptions, + MessageInstance, + MessageLoadingMethod, + MessageMethod, + MessageOptions, + MessagePlacementList, + MessagePluginType, + MessageQuestionMethod, + MessageSuccessMethod, + MessageThemeList, + MessageWarningMethod, +} from './type'; -export * from './type'; +export type { MessageProps } from './messageComponent'; +export type { + MessageCloseAllMethod, + MessageConfigMethod, + MessageContainerProps, + MessageErrorMethod, + MessageInfoMethod, + MessageInfoOptions, + MessageInstance, + MessageLoadingMethod, + MessageMethod, + MessageOptions, + MessagePlacementList, + MessagePluginType, + MessageQuestionMethod, + MessageSuccessMethod, + MessageThemeList, + MessageWarningMethod, +}; export const Message = _Message; export const message = _MessagePlugin; export const MessagePlugin = _MessagePlugin; diff --git a/packages/components/message/messageComponent.tsx b/packages/components/message/messageComponent.tsx index 1380617c..7fe2a172 100644 --- a/packages/components/message/messageComponent.tsx +++ b/packages/components/message/messageComponent.tsx @@ -11,13 +11,13 @@ import { tdClassIsGenerator, tdMessageClassGenerator, tdMessagePrefix } from './ import { TdMessageProps } from './type'; // Message 组件参数,需在 api 定义上做部分扩展 -export interface MessageComponentProps extends TdMessageProps, StyledProps { +export interface MessageProps extends TdMessageProps, StyledProps { children?: TNode; } // message 直接作为组件使用时 @tag('t-message') -export default class MessageComponent extends Component { +export default class MessageComponent extends Component { static defaultProps = { theme: 'info', duration: 3000, @@ -65,7 +65,7 @@ export default class MessageComponent extends Component { this.clearTimer(); } - render(props: Omi.OmiProps | MessageComponentProps) { + render(props: Omi.OmiProps | MessageProps) { const { theme, innerClass, children, innerStyle, icon, content, closeBtn, onCloseBtnClick, onClose } = props; const onCloseFn = onClose; const onCloseBtnClickFn = onCloseBtnClick; diff --git a/packages/components/notification/Notification.tsx b/packages/components/notification/Notification.tsx index 97f6c235..54dda7a4 100644 --- a/packages/components/notification/Notification.tsx +++ b/packages/components/notification/Notification.tsx @@ -9,9 +9,9 @@ import { StyledProps } from '@tdesign/web-components-shared/common'; import { Component, createRef, OmiProps, tag } from 'omi'; import { notificationDefaultProps } from './defaultProps'; -import { NotificationInstance, TdNotificationProps } from './type'; +import { TdNotificationProps } from './type'; -export interface NotificationProps extends NotificationInstance, TdNotificationProps, StyledProps { +export interface NotificationProps extends TdNotificationProps, StyledProps { id?: string; } diff --git a/packages/components/notification/index.ts b/packages/components/notification/index.ts index 6b1862a2..bd0aa5ef 100644 --- a/packages/components/notification/index.ts +++ b/packages/components/notification/index.ts @@ -2,9 +2,38 @@ import './style/index.js'; import _Notification from './Notification'; import { NotificationPlugin as _NotificationPlugin } from './NotificationPlugin'; +import type { + NotificationCloseAllMethod, + NotificationCloseMethod, + NotificationConfigMethod, + NotificationErrorMethod, + NotificationInfoMethod, + NotificationInfoOptions, + NotificationInstance, + NotificationMethod, + NotificationOptions, + NotificationPlacementList, + NotificationSuccessMethod, + NotificationThemeList, + NotificationWarningMethod, +} from './type'; -export * from './type'; - +export type { + NotificationCloseAllMethod, + NotificationCloseMethod, + NotificationConfigMethod, + NotificationErrorMethod, + NotificationInfoMethod, + NotificationInfoOptions, + NotificationInstance, + NotificationMethod, + NotificationOptions, + NotificationPlacementList, + NotificationSuccessMethod, + NotificationThemeList, + NotificationWarningMethod, +}; +export type { NotificationProps } from './Notification'; export const Notification = _Notification; export const notification = _NotificationPlugin; export const NotificationPlugin = _NotificationPlugin; diff --git a/packages/components/notification/type.ts b/packages/components/notification/type.ts index 80b54234..99942b95 100644 --- a/packages/components/notification/type.ts +++ b/packages/components/notification/type.ts @@ -1,10 +1,8 @@ -/* eslint-disable */ - /** * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ -import { TNode, AttachNode } from '@tdesign/web-components-shared/common'; +import { AttachNode, TNode } from '@tdesign/web-components-shared/common'; export interface TdNotificationProps { /** diff --git a/packages/components/popconfirm/index.ts b/packages/components/popconfirm/index.ts index 0f47bee9..b0068311 100644 --- a/packages/components/popconfirm/index.ts +++ b/packages/components/popconfirm/index.ts @@ -3,7 +3,6 @@ import './style/index.js'; import _Popconfirm from './popconfirm'; export type { PopconfirmProps } from './popconfirm'; -export * from './type'; - +export type { PopconfirmVisibleChangeContext, TriggerSource } from './type'; export const Popconfirm = _Popconfirm; export default Popconfirm; diff --git a/packages/components/popconfirm/type.ts b/packages/components/popconfirm/type.ts index 7dde61dd..c5f1b41a 100644 --- a/packages/components/popconfirm/type.ts +++ b/packages/components/popconfirm/type.ts @@ -1,10 +1,9 @@ -/* eslint-disable */ - /** * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ -import { TNode, StyledProps } from '@tdesign/web-components-shared/common'; +import { StyledProps, TNode } from '@tdesign/web-components-shared/common'; + import { ButtonProps } from '../button'; import { PopupProps } from '../popup'; diff --git a/packages/components/popup/index.ts b/packages/components/popup/index.ts index ac332265..0cf6b0cf 100644 --- a/packages/components/popup/index.ts +++ b/packages/components/popup/index.ts @@ -3,7 +3,6 @@ import './style/index.js'; import _Popup from './popup'; export type { PopupProps } from './popup'; -export * from './type'; - +export type { PopupPlacement, PopupTriggerEvent, PopupTriggerSource, PopupVisibleChangeContext } from './type'; export const Popup = _Popup; export default Popup; diff --git a/packages/components/popup/type.ts b/packages/components/popup/type.ts index 7147bc28..e22abbe0 100644 --- a/packages/components/popup/type.ts +++ b/packages/components/popup/type.ts @@ -1,10 +1,8 @@ -/* eslint-disable */ - /** * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ -import { TNode, ClassName, Styles, AttachNode } from '@tdesign/web-components-shared/common'; +import { AttachNode, ClassName, Styles, TNode } from '@tdesign/web-components-shared/common'; export interface TdPopupProps { /** diff --git a/packages/components/progress/index.ts b/packages/components/progress/index.ts index 5859b483..8521c574 100644 --- a/packages/components/progress/index.ts +++ b/packages/components/progress/index.ts @@ -3,7 +3,6 @@ import './style/index.js'; import _Progress from './progress'; export type { ProgressProps } from './progress'; +export type { StatusEnum, ThemeEnum } from './type'; export const Progress = _Progress; export default Progress; - -export * from './type'; diff --git a/packages/components/radio/index.ts b/packages/components/radio/index.ts index 92910f10..f5365558 100644 --- a/packages/components/radio/index.ts +++ b/packages/components/radio/index.ts @@ -6,8 +6,7 @@ import _RadioGroup from './radioGroup.jsx'; export type { RadioProps } from './radio'; export type { RadioGroupProps } from './radioGroup'; -export * from './type'; - +export type { RadioOption, RadioOptionObj, RadioValue } from './type'; export const Radio = _Radio; export const RadioButton = _RadioButton; export const RadioGroup = _RadioGroup; diff --git a/packages/components/radio/type.ts b/packages/components/radio/type.ts index 3c477aea..ee9ee0a3 100644 --- a/packages/components/radio/type.ts +++ b/packages/components/radio/type.ts @@ -1,10 +1,8 @@ -/* eslint-disable */ - /** * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ -import { TNode, SizeEnum } from '@tdesign/web-components-shared/common'; +import { SizeEnum, TNode } from '@tdesign/web-components-shared/common'; export interface TdRadioProps { /** diff --git a/packages/components/range-input/index.ts b/packages/components/range-input/index.ts index f5ee0e86..a9522f7e 100644 --- a/packages/components/range-input/index.ts +++ b/packages/components/range-input/index.ts @@ -4,8 +4,8 @@ import _RangeInput from './RangeInput.jsx'; import _RangeInputPopup from './RangeInputPopup'; export type { RangeInputProps } from './RangeInput.jsx'; -export * from './type'; - +export type { RangeInputPopupProps } from './RangeInputPopup'; +export type { RangeInputPosition, RangeInputValue } from './type'; export const RangeInput = _RangeInput; export const RangeInputPopup = _RangeInputPopup; export default RangeInput; diff --git a/packages/components/select-input/SelectInputSingle.tsx b/packages/components/select-input/SelectInputSingle.tsx index ab58d90f..d458bc8b 100644 --- a/packages/components/select-input/SelectInputSingle.tsx +++ b/packages/components/select-input/SelectInputSingle.tsx @@ -6,7 +6,7 @@ import { isObject } from 'lodash-es'; import { Component, createRef, tag } from 'omi'; // import useControlled from '@tdesign/web-components-shared/_util/useControlled'; -import { TdInputProps } from '../input'; +import { TdInputProps } from '../input/type'; import { TdSelectInputProps } from './type'; export interface RenderSelectSingleInputParams { diff --git a/packages/components/select-input/index.tsx b/packages/components/select-input/index.tsx index 028b9f65..242c2d2c 100644 --- a/packages/components/select-input/index.tsx +++ b/packages/components/select-input/index.tsx @@ -1,9 +1,24 @@ import './style/index.js'; import _SelectInput from './SelectInput'; +import type { + SelectInputBlurContext, + SelectInputChangeContext, + SelectInputFocusContext, + SelectInputKeys, + SelectInputValue, + SelectInputValueChangeContext, +} from './type'; export type { SelectInputProps } from './SelectInput'; -export * from './type'; +export type { + SelectInputBlurContext, + SelectInputChangeContext, + SelectInputFocusContext, + SelectInputKeys, + SelectInputValue, + SelectInputValueChangeContext, +}; export const SelectInput = _SelectInput; export default SelectInput; diff --git a/packages/components/select-input/type.ts b/packages/components/select-input/type.ts index 9491cf7d..0d977fa7 100644 --- a/packages/components/select-input/type.ts +++ b/packages/components/select-input/type.ts @@ -1,15 +1,14 @@ -/* eslint-disable */ - /** * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ +import { SizeEnum, TElement, TNode } from '@tdesign/web-components-shared/common'; + import { InputProps } from '../input'; import { PopupProps } from '../popup'; -import { TagInputProps, TagInputValue, TagInputChangeContext } from '../tag-input'; -import { TagProps } from '../tag'; import { PopupVisibleChangeContext } from '../popup'; -import { TNode, TElement, SizeEnum } from '@tdesign/web-components-shared/common'; +import { TagProps } from '../tag'; +import { TagInputChangeContext, TagInputProps, TagInputValue } from '../tag-input'; export interface TdSelectInputProps { /** @@ -218,7 +217,7 @@ export interface SelectInputKeys { children?: string; } -export type SelectInputValue = string | number | boolean | Date | Object | Array | Array; +export type SelectInputValue = string | number | boolean | Date | object | SelectInputValue[]; export type SelectInputBlurContext = PopupVisibleChangeContext & { inputValue: string; tagInputValue?: TagInputValue }; diff --git a/packages/components/select-input/useOverlayInnerStyle.ts b/packages/components/select-input/useOverlayInnerStyle.ts index 852e2d24..42955536 100644 --- a/packages/components/select-input/useOverlayInnerStyle.ts +++ b/packages/components/select-input/useOverlayInnerStyle.ts @@ -2,7 +2,7 @@ import useControlled from '@tdesign/web-components-shared/_util/useControlled'; import { isFunction } from 'lodash-es'; import { Component } from 'omi'; -import { PopupVisibleChangeContext, TdPopupProps } from '../popup'; +import { PopupVisibleChangeContext, TdPopupProps } from '../popup/type'; import { TdSelectInputProps } from './type'; export type overlayStyleProps = Pick< diff --git a/packages/components/select/Select.tsx b/packages/components/select/Select.tsx index addf5cc0..6e4afdf4 100644 --- a/packages/components/select/Select.tsx +++ b/packages/components/select/Select.tsx @@ -5,13 +5,16 @@ import '../loading'; import { getClassPrefix } from '@tdesign/web-components-shared/_util/classname'; import { setExportparts } from '@tdesign/web-components-shared/_util/dom'; +import { StyledProps } from '@tdesign/web-components-shared/common'; import { classNames, Component, OmiProps, tag } from 'omi'; import { selectDefaultProps } from './defaultProps'; import { SelectValue, TdOptionProps, TdSelectProps } from './type'; +export interface SelectProps extends TdSelectProps, StyledProps {} + @tag('t-select') -export default class Select extends Component { +export default class Select extends Component { static css = []; static defaultProps = selectDefaultProps; @@ -53,7 +56,7 @@ export default class Select extends Component { setExportparts(this); } - receiveProps(props: TdSelectProps, oldProps: TdSelectProps) { + receiveProps(props: SelectProps, oldProps: SelectProps) { if (props.value !== undefined && props.value !== oldProps.value) { this.state.innerValue = props.value; } diff --git a/packages/components/select/index.ts b/packages/components/select/index.ts index 243a4116..75c12c06 100644 --- a/packages/components/select/index.ts +++ b/packages/components/select/index.ts @@ -2,10 +2,29 @@ import './style/index.js'; import _Option from './Option'; import _Select from './Select'; +import type { + SelectContext, + SelectKeysType, + SelectOption, + SelectOptionGroup, + SelectRemoveContext, + SelectValue, + SelectValueChangeTrigger, + TdOptionGroupProps, +} from './type'; -export type { SelectValue } from './type'; -export * from './type'; - +export type { + SelectContext, + SelectKeysType, + SelectOption, + SelectOptionGroup, + SelectRemoveContext, + SelectValue, + SelectValueChangeTrigger, + TdOptionGroupProps, +}; +export type { OptionProps } from './Option'; +export type { SelectProps } from './Select'; export const Select = _Select; export const Option = _Option; diff --git a/packages/components/select/type.ts b/packages/components/select/type.ts index 8092692b..6a5823f0 100644 --- a/packages/components/select/type.ts +++ b/packages/components/select/type.ts @@ -1,17 +1,16 @@ -/* eslint-disable */ - /** * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ +import { InfinityScroll, PlainObject, SizeEnum, TElement, TNode } from '@tdesign/web-components-shared/common'; + import { InputProps } from '../input'; import { PopupProps } from '../popup'; +import { PopupVisibleChangeContext } from '../popup'; import { SelectInputProps } from '../select-input'; -import { TagInputProps } from '../tag-input'; -import { TagProps } from '../tag'; import { SelectInputValueChangeContext } from '../select-input'; -import { PopupVisibleChangeContext } from '../popup'; -import { PlainObject, TNode, TElement, SizeEnum, InfinityScroll } from '@tdesign/web-components-shared/common'; +import { TagProps } from '../tag'; +import { TagInputProps } from '../tag-input'; export interface TdSelectProps { /** diff --git a/packages/components/skeleton/index.ts b/packages/components/skeleton/index.ts index 50768c07..1b4f820b 100644 --- a/packages/components/skeleton/index.ts +++ b/packages/components/skeleton/index.ts @@ -3,7 +3,6 @@ import './style/index'; import _Skeleton from './skeleton'; export type { SkeletonProps } from './skeleton'; -export * from './type'; - +export type { SkeletonRowCol, SkeletonRowColObj } from './type'; export const Skeleton = _Skeleton; export default Skeleton; diff --git a/packages/components/slider/index.ts b/packages/components/slider/index.ts index 5b18de17..27906465 100644 --- a/packages/components/slider/index.ts +++ b/packages/components/slider/index.ts @@ -3,7 +3,6 @@ import './style/index.js'; import _Slider from './slider'; export type { SliderProps } from './slider'; -export * from './type'; - +export type { SliderMarks, SliderValue } from './type'; export const Slider = _Slider; export default Slider; diff --git a/packages/components/space/index.ts b/packages/components/space/index.ts index 907fe1b8..f74993f8 100644 --- a/packages/components/space/index.ts +++ b/packages/components/space/index.ts @@ -2,7 +2,7 @@ import './style/index.js'; import _Space from './space'; -export type { TdSpaceProps } from './type'; +export type { SpaceProps } from './space'; export const Space = _Space; diff --git a/packages/components/swiper/index.ts b/packages/components/swiper/index.ts index bcf77a38..f05138ee 100644 --- a/packages/components/swiper/index.ts +++ b/packages/components/swiper/index.ts @@ -3,8 +3,7 @@ import './style/index'; import _Swiper from './swiper'; export type { SwiperProps } from './swiper'; +export type { SwiperChangeSource, SwiperNavigation, SwiperNavigationType } from './type'; export const Swiper = _Swiper; export default Swiper; - -export * from './type'; diff --git a/packages/components/swiper/swiper.tsx b/packages/components/swiper/swiper.tsx index 84d45ba5..ad654495 100644 --- a/packages/components/swiper/swiper.tsx +++ b/packages/components/swiper/swiper.tsx @@ -143,7 +143,6 @@ export default class Swiper extends Component { style.height = offsetHeight; style.transform = `translate3d(0, -${active * 100}%, 0px)`; } else { - console.log(active); style.transform = `translate3d(-${active * 100}%, 0px, 0px)`; } ['msTransform', 'WebkitTransform'].forEach((key) => { @@ -191,7 +190,6 @@ export default class Swiper extends Component { } this.currentIndex.value = targetIndex; - console.log(this.currentIndex.value); } @bind diff --git a/packages/components/switch/index.ts b/packages/components/switch/index.ts index 1968be8a..26c0e093 100644 --- a/packages/components/switch/index.ts +++ b/packages/components/switch/index.ts @@ -3,7 +3,6 @@ import './style/index.js'; import _Switch from './switch'; export type { SwitchProps } from './switch'; -export * from './type'; - +export type { SwitchValue } from './type'; export const Switch = _Switch; export default Switch; diff --git a/packages/components/tabs/index.ts b/packages/components/tabs/index.ts index e27a34ae..265eee57 100644 --- a/packages/components/tabs/index.ts +++ b/packages/components/tabs/index.ts @@ -4,8 +4,7 @@ import _Tabs from './tabs'; export type { TabPanelProps } from './tabPanel'; export type { TabsProps } from './tabs'; +export type { TabsDragSortContext, TabValue } from './type'; export const Tabs = _Tabs; export default Tabs; - -export * from './type'; diff --git a/packages/components/tag-input/index.ts b/packages/components/tag-input/index.ts index df4dec3a..e4d6f739 100644 --- a/packages/components/tag-input/index.ts +++ b/packages/components/tag-input/index.ts @@ -1,9 +1,26 @@ import './style/index.js'; import _TagInput from './tag-input.jsx'; +import type { + InputValueChangeContext, + TagInputChangeContext, + TagInputDragSortContext, + TagInputRemoveContext, + TagInputRemoveTrigger, + TagInputTriggerSource, + TagInputValue, +} from './type'; + +export type { + InputValueChangeContext, + TagInputChangeContext, + TagInputDragSortContext, + TagInputRemoveContext, + TagInputRemoveTrigger, + TagInputTriggerSource, + TagInputValue, +}; export type { TagInputProps } from './tag-input.jsx'; export const TagInput = _TagInput; export default TagInput; - -export * from './type'; diff --git a/packages/components/tag-input/type.ts b/packages/components/tag-input/type.ts index e52be389..d90b194d 100644 --- a/packages/components/tag-input/type.ts +++ b/packages/components/tag-input/type.ts @@ -1,7 +1,7 @@ -/* eslint-disable */ +import { TElement, TNode } from '@tdesign/web-components-shared/common'; + import { InputProps, InputValue } from '../input'; import { TagProps } from '../tag'; -import { TNode, TElement } from '@tdesign/web-components-shared/common'; export interface TdTagInputProps { /** diff --git a/packages/components/tag/index.ts b/packages/components/tag/index.ts index c19d5821..0d349b12 100644 --- a/packages/components/tag/index.ts +++ b/packages/components/tag/index.ts @@ -2,7 +2,6 @@ import './style/index.js'; import _Tag from './tag'; -export * from './type'; - +export type { CheckTagProps, TagProps } from './type'; export const Tag = _Tag; export default Tag; diff --git a/packages/components/textarea/index.ts b/packages/components/textarea/index.ts index 087aa5db..99512c65 100644 --- a/packages/components/textarea/index.ts +++ b/packages/components/textarea/index.ts @@ -3,7 +3,6 @@ import './style/index.js'; import _Textarea from './textarea'; export type { TextareaProps } from './textarea'; +export type { TextareaValue } from './type'; export const Textarea = _Textarea; export default Textarea; - -export * from './type'; diff --git a/packages/components/tooltip/index.ts b/packages/components/tooltip/index.ts index a0c91a2e..81fad727 100644 --- a/packages/components/tooltip/index.ts +++ b/packages/components/tooltip/index.ts @@ -3,7 +3,6 @@ import './style/index.js'; import _Tooltip from './tooltip'; export type { TooltipProps } from './tooltip'; -export * from './type'; - +export type { TdTooltipLiteProps } from './type'; export const Tooltip = _Tooltip; export default Tooltip; diff --git a/packages/components/tooltip/type.ts b/packages/components/tooltip/type.ts index b2c4d6cb..ddbc3977 100644 --- a/packages/components/tooltip/type.ts +++ b/packages/components/tooltip/type.ts @@ -1,12 +1,10 @@ -/* eslint-disable */ - /** * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ -import { PopupPlacement } from '../popup'; -import { TdPopupProps } from '../popup'; -import { Styles, TNode } from '@tdesign/web-components-shared/common'; +import { TNode } from '@tdesign/web-components-shared/common'; + +import { PopupPlacement, TdPopupProps } from '../popup/type'; export interface TdTooltipProps extends TdPopupProps { /** diff --git a/packages/components/upload/ImageCard.tsx b/packages/components/upload/ImageCard.tsx index 86ddaabd..d2ffea05 100644 --- a/packages/components/upload/ImageCard.tsx +++ b/packages/components/upload/ImageCard.tsx @@ -6,8 +6,8 @@ import '../loading'; import zhCn from '@common/js/global-config/locale/zh_CN'; import { abridgeName } from '@common/js/upload/utils'; -import classNames from '@tdesign/web-components-shared/_util/classname'; import { convertToLightDomNode } from '@tdesign/web-components-shared/_util/lightDom'; +import { classNames } from 'omi'; // import ImageViewer from '../../image-viewer'; import { CommonDisplayFileProps } from './interface'; diff --git a/packages/components/upload/NormalFile.tsx b/packages/components/upload/NormalFile.tsx index ffd66082..e278adba 100644 --- a/packages/components/upload/NormalFile.tsx +++ b/packages/components/upload/NormalFile.tsx @@ -6,8 +6,8 @@ import 'tdesign-icons-web-components/esm/components/close'; import '../loading'; import { abridgeName } from '@common/js/upload/utils'; -import classNames from '@tdesign/web-components-shared/_util/classname'; import { convertToLightDomNode } from '@tdesign/web-components-shared/_util/lightDom'; +import { classNames } from 'omi'; import { CommonDisplayFileProps } from './interface'; import { UploadFile } from './type'; diff --git a/packages/components/upload/hooks/useUpload.ts b/packages/components/upload/hooks/useUpload.ts index 020c46fe..c6a8e7a5 100644 --- a/packages/components/upload/hooks/useUpload.ts +++ b/packages/components/upload/hooks/useUpload.ts @@ -119,8 +119,6 @@ export default function useUpload(props: SignalValue) { }); }), ); - console.log(tmpFiles); - setUploadValue(tmpFiles, { trigger: 'add', index: uploadValue.value.length, @@ -143,12 +141,10 @@ export default function useUpload(props: SignalValue) { const onFileChange = (files: File[]) => { if (disabled.value) return; - console.log('====onFileChange', files); const params = { currentSelectedFiles: formatToUploadFile([...files], undefined) }; onSelectChange.value?.([...files], params); validateFile({ uploadValue: uploadValue.value, - // @ts-ignore files: [...files], max: 0, sizeLimit: sizeLimit.value, diff --git a/packages/components/upload/index.ts b/packages/components/upload/index.ts index cf789a74..15d4af31 100644 --- a/packages/components/upload/index.ts +++ b/packages/components/upload/index.ts @@ -1,8 +1,34 @@ import './style/index.js'; +import type { + SizeUnit, + SizeUnitArray, + SuccessContext, + UploadChangeContext, + UploadChangeTrigger, + UploadFailContext, + UploadFile, + UploadInstanceFunctions, + UploadProps, + UploadRemoveContext, + UploadSelectChangeContext, + UploadValidateType, +} from './type'; import _Upload from './upload'; -export * from './type'; - +export type { + SizeUnit, + SizeUnitArray, + SuccessContext, + UploadChangeContext, + UploadChangeTrigger, + UploadFailContext, + UploadFile, + UploadInstanceFunctions, + UploadProps, + UploadRemoveContext, + UploadSelectChangeContext, + UploadValidateType, +}; export const Upload = _Upload; export default Upload; diff --git a/packages/components/upload/interface.ts b/packages/components/upload/interface.ts index d464b98b..a397ae18 100644 --- a/packages/components/upload/interface.ts +++ b/packages/components/upload/interface.ts @@ -1,8 +1,10 @@ -import { StyledProps } from '@tdesign/web-components-shared/common'; import { VNode } from 'omi'; import { TdUploadProps, UploadFile, UploadInstanceFunctions, UploadRemoveContext } from './type'; +/** @deprecated 请从组件入口导入 UploadProps;此转发仅保留 interface.ts 深层导入兼容性。 */ +export type { UploadProps } from './type'; + export interface CommonDisplayFileProps { accept: string; files: TdUploadProps['files']; @@ -28,8 +30,6 @@ export interface CommonDisplayFileProps { onRemove?: (p: UploadRemoveContext) => void; } -export interface UploadProps extends TdUploadProps, StyledProps {} - export interface UploadRef extends UploadInstanceFunctions { upload: HTMLInputElement; uploading: boolean; diff --git a/packages/components/upload/type.ts b/packages/components/upload/type.ts index a7adfbb6..7ce4ff57 100644 --- a/packages/components/upload/type.ts +++ b/packages/components/upload/type.ts @@ -1,4 +1,10 @@ -import { FormatResponseContext, ResponseType, SizeLimitObj } from '@common/js/upload/types'; +import { + FormatResponseContext, + ResponseType, + SizeLimitObj, + type SizeUnit as CommonSizeUnit, + type UploadFile as CommonUploadFile, +} from '@common/js/upload/types'; import { PlainObject, StyledProps, TNode } from '@tdesign/web-components-shared/common'; import { ButtonProps } from '../button'; @@ -130,53 +136,10 @@ export interface UploadInstanceFunctions { uploadFiles: (files?: UploadFile[]) => void; } -export interface UploadFile extends PlainObject { - /** - * 上一次变更的时间 - */ - lastModified?: number; - /** - * 文件名称 - * @default '' - */ - name?: string; - /** - * 下载进度 - */ - percent?: number; - /** - * 原始文件对象 - */ - raw?: File; - /** - * 上传接口返回的数据。`response.error` 存在时会判断此次上传失败,并显示错误文本信息;`response.url` 会作为文件上传成功后的地址,并使用该地址显示图片 - */ - response?: { [key: string]: any }; - /** - * 文件大小 - */ - size?: number; - /** - * 文件上传状态:上传成功,上传失败,上传中,等待上传 - * @default '' - */ - status?: 'success' | 'fail' | 'progress' | 'waiting'; - /** - * 文件类型 - * @default '' - */ - type?: string; - /** - * 上传时间 - * @default '' - */ - uploadTime?: string; - /** - * 文件上传成功后的下载/访问地址 - * @default '' - */ - url?: string; -} +/** + * 上传文件。基础字段由 tdesign-common 统一维护;Web Components 仅补充通用对象扩展能力。 + */ +export interface UploadFile extends CommonUploadFile, PlainObject {} export interface UploadSelectChangeContext { currentSelectedFiles: UploadFile[]; @@ -192,17 +155,11 @@ export interface UploadChangeContext { } export type UploadChangeTrigger = - | 'add' - | 'remove' - | 'abort' - | 'progress-success' - | 'progress' - | 'progress-fail' - | 'default'; + 'add' | 'remove' | 'abort' | 'progress-success' | 'progress' | 'progress-fail' | 'default'; export type SizeUnitArray = ['B', 'KB', 'MB', 'GB']; -export type SizeUnit = SizeUnitArray[number]; +export type SizeUnit = CommonSizeUnit; export interface UploadFailContext { e?: ProgressEvent; diff --git a/packages/components/upload/upload.tsx b/packages/components/upload/upload.tsx index 0bda3639..ffb88fe5 100644 --- a/packages/components/upload/upload.tsx +++ b/packages/components/upload/upload.tsx @@ -1,26 +1,17 @@ import 'tdesign-icons-web-components/esm/components/upload'; -import 'tdesign-icons-web-components/esm/components/delete'; -import 'tdesign-icons-web-components/esm/components/error-circle-filled'; -import 'tdesign-icons-web-components/esm/components/add'; -import 'tdesign-icons-web-components/esm/components/time-filled'; -import 'tdesign-icons-web-components/esm/components/check-circle-filled'; -import 'tdesign-icons-web-components/esm/components/error-circle-filled'; -import 'tdesign-icons-web-components/esm/components/close-circle-filled'; -import 'tdesign-icons-web-components/esm/components/close'; import '../input'; import '../image'; import '../loading'; -import zhCn from '@common/js/global-config/locale/zh_CN'; -import { abridgeName } from '@common/js/upload/utils'; import { classPrefix } from '@tdesign/web-components-shared/_util/classname'; -import { convertToLightDomNode } from '@tdesign/web-components-shared/_util/lightDom'; import { classNames, Component, css, OmiProps, signal, SignalValue, tag } from 'omi'; import { ButtonProps } from '../button'; import useUpload from './hooks/useUpload'; import renderCustomFile from './CustomFile'; +import { renderImageCard } from './ImageCard'; import { CommonDisplayFileProps } from './interface'; +import { renderNormalFile } from './NormalFile'; import { TdUploadProps, UploadFile, UploadProps } from './type'; import { toRef } from './utils'; @@ -31,227 +22,6 @@ export const uploadDefaultProps: TdUploadProps = { showImageFileName: true, }; -export interface ImageCardUploadProps extends CommonDisplayFileProps { - // multiple: TdUploadProps['multiple']; - // max: TdUploadProps['max']; - disabled?: TdUploadProps['disabled']; - // showUploadProgress: TdUploadProps['showUploadProgress']; - triggerUpload?: () => void; - uploadFiles?: (toFiles?: UploadFile[]) => void; - cancelUpload?: (context: { e: MouseEvent; file: UploadFile }) => void; - onPreview?: TdUploadProps['onPreview']; - showImageFileName?: boolean; -} - -export type NormalFileProps = CommonDisplayFileProps; -export function renderNormalFile(props: NormalFileProps) { - const { theme, disabled, classPrefix } = props; - - const uploadPrefix = `${classPrefix}-upload`; - - const renderProgress = (percent: number) => ( -
- {convertToLightDomNode()} - {percent || 0}% -
- ); - - // 输入框型预览 - const renderFilePreviewAsInput = () => { - const file = props.displayFiles[0]; - const inputTextClass = [ - `${classPrefix}-input__inner`, - { [`${uploadPrefix}__placeholder`]: !props.displayFiles[0] }, - ]; - const disabledClass = disabled ? `${classPrefix}-is-disabled` : ''; - const fileName = - props.abridgeName?.length && file?.name ? abridgeName(file.name, ...props.abridgeName) : file?.name; - return ( -
-
- - {file?.name ? fileName : props.placeholder} - - {file?.status === 'progress' && renderProgress(file.percent)} - {file?.status === 'waiting' && - convertToLightDomNode( - , - )} - {file?.name && - file.status === 'success' && - convertToLightDomNode()} - {file?.name && - file.status === 'fail' && - convertToLightDomNode( - , - )} - {Boolean(!disabled && file?.name) && - convertToLightDomNode( - props.onRemove({ e, file, index: 0 })} - />, - )} -
-
- ); - }; - - const renderFilePreviewAsText = (files: UploadFile[]) => { - if (theme !== 'file') return null; - if (files[0]?.status === 'fail' && props.autoUpload) { - return null; - } - return files.map((file, index) => { - const fileName = props.abridgeName && file.name ? abridgeName(file.name, ...props.abridgeName) : file.name; - return ( -
- {fileName} - {file.status === 'fail' && ( -
- {convertToLightDomNode()} -
- )} - {file.status === 'waiting' && ( -
- {convertToLightDomNode()} -
- )} - {file.status === 'progress' && renderProgress(file.percent)} - {!disabled && - file.status !== 'progress' && - convertToLightDomNode( - props.onRemove({ e, file, index })} - />, - )} -
- ); - }); - }; - - const { displayFiles } = props; - - const classes = [`${uploadPrefix}__single`, `${uploadPrefix}__single-${theme}`]; - return ( -
- {theme === 'file-input' && renderFilePreviewAsInput()} - {props.children} - - {theme === 'file' && props.placeholder && !displayFiles[0] && ( - {props.placeholder} - )} - - {renderFilePreviewAsText(displayFiles)} - - {/* 单文件上传失败要显示失败的原因 */} - {displayFiles[0]?.status === 'fail' && theme === 'file' ? ( - {displayFiles[0].response?.error} - ) : null} -
- ); -} - -export function renderImageCard(props: ImageCardUploadProps) { - const locale = zhCn.upload; - const { displayFiles, classPrefix, onRemove, disabled } = props; - - const showTrigger = !displayFiles?.[0]; - - const renderMainContent = (file: UploadFile, index: number) => ( -
- - {!disabled && ( -
- e.stopPropagation()}> - {convertToLightDomNode( onRemove?.({ e, file, index })} />)} - -
- )} -
- ); - const renderProgressFile = (file: UploadFile, loadCard: string) => ( -
- -

- {locale?.progress?.uploadingText} - {props.showUploadProgress ? ` ${file.percent}%` : ''} -

-
- ); - - const renderFailFile = (file: UploadFile, index: number, loadCard: string) => ( -
- {convertToLightDomNode()} -

{file.response?.error || locale?.progress?.failText}

-
- e.stopPropagation()}> - {convertToLightDomNode( props.onRemove?.({ e, file, index })} />)} - -
-
- ); - - const cardItemClasses = `${classPrefix}-upload__card-item ${classPrefix}-is-background`; - - return ( -
-
    - {displayFiles.map((file: UploadFile, index: number) => { - const loadCard = `${classPrefix}-upload__card-container ${classPrefix}-upload__card-box`; - const fileName = props.abridgeName ? abridgeName(file.name, ...props.abridgeName) : file.name; - const fileNameClassName = `${classPrefix}-upload__card-name`; - return ( -
  • - {file.status === 'progress' && renderProgressFile(file, loadCard)} - {file.status === 'fail' && renderFailFile(file, index, loadCard)} - {!['progress', 'fail'].includes(file.status) && renderMainContent(file, index)} - { - fileName && props.showImageFileName && ( - // (file.url ? ( - // - // {fileName} - // - // ) : ( - {fileName} - ) - // )) - } -
  • - ); - })} - {showTrigger && ( -
  • -
    - {convertToLightDomNode()} -

    - {locale?.triggerUploadText?.image} -

    -
    -
  • - )} -
-
- ); -} - @tag('t-upload') export default class Upload extends Component { static css = css` diff --git a/packages/components/watermark/README.md b/packages/components/watermark/README.md index 06a04721..4198c15b 100644 --- a/packages/components/watermark/README.md +++ b/packages/components/watermark/README.md @@ -61,6 +61,7 @@ zIndex | Number | - | 水印元素的 `z-index`,默认值写在 CSS 中 | N 名称 | 类型 | 默认值 | 说明 | 必传 -- | -- | -- | -- | -- fontColor | String | rgba(0,0,0,0.1) | 水印文本文字颜色 | N +fontFamily | String | normal | 水印文本文字样式 | N fontSize | Number | 16 | 水印文本文字大小 | N fontWeight | String | normal | 水印文本文字粗细。可选项:normal/lighter/bold/bolder | N text | String | - | 水印文本内容 | N diff --git a/packages/components/watermark/type.ts b/packages/components/watermark/type.ts index a721790c..df1228b0 100644 --- a/packages/components/watermark/type.ts +++ b/packages/components/watermark/type.ts @@ -1,3 +1,7 @@ +import type { + WatermarkImage as CommonWatermarkImage, + WatermarkText as CommonWatermarkText, +} from '@common/js/watermark/type'; import { TNode } from '@tdesign/web-components-shared/common'; export interface TdWatermarkProps { @@ -74,38 +78,8 @@ export interface TdWatermarkProps { zIndex?: number; } -export interface WatermarkText { - /** - * 水印文本文字颜色 - * @default rgba(0,0,0,0.1) - */ - fontColor?: string; - /** - * 水印文本文字大小 - * @default 16 - */ - fontSize?: number; - /** - * 水印文本文字粗细 - * @default normal - */ - fontWeight?: 'normal' | 'lighter' | 'bold' | 'bolder'; - /** - * 水印文本内容 - * @default '' - */ - text?: string; -} +/** 水印文本配置,由 tdesign-common 统一维护。 */ +export type WatermarkText = CommonWatermarkText; -export interface WatermarkImage { - /** - * 水印图片是否需要灰阶显示 - * @default false - */ - isGrayscale?: boolean; - /** - * 水印图片源地址,为了显示清楚,建议导出 2 倍或 3 倍图 - * @default '' - */ - url?: string; -} +/** 水印图片配置,由 tdesign-common 统一维护。 */ +export type WatermarkImage = CommonWatermarkImage; diff --git a/packages/pro-components/chat/attachments/README.md b/packages/pro-components/chat/attachments/README.md index 020daa69..ca0ddc50 100644 --- a/packages/pro-components/chat/attachments/README.md +++ b/packages/pro-components/chat/attachments/README.md @@ -26,11 +26,11 @@ spline: base ### Attachments Props -名称 | 类型 | 默认值 | 说明 | 必传 --- | -- | -- | -- | -- -items | TdAttachmentItem[] | false | 附件列表,同 Upload UploadFile | Y -onRemove | (item: TdAttachmentItem) => void / undefined | - | 附件移除时的回调函数 | N -removable | boolean | true | 是否显示删除按钮 | N -overflow | 'wrap'/'scrollX'/'scrollY' | 'wrap' | 文件列表超出时样式 | N -imageViewer | Boolean | true | 图片预览开关 | N - +| 名称 | 类型 | 默认值 | 说明 | 必传 | +| ----------- | -------------------------------------------- | -------- | ------------------------ | ---- | +| items | `TdAttachmentItem[]` | - | 附件列表 | Y | +| overflow | `'wrap' \| 'scrollX' \| 'scrollY'` | `'wrap'` | 文件列表超出时的布局方式 | N | +| removable | Boolean | `true` | 是否显示删除按钮 | N | +| imageViewer | Boolean | `true` | 是否启用图片预览 | N | +| onRemove | `(e: CustomEvent) => void` | - | 移除附件时触发 | N | +| onFileClick | `(e: CustomEvent) => void` | - | 点击附件时触发 | N | diff --git a/packages/pro-components/chat/attachments/attachments.tsx b/packages/pro-components/chat/attachments/attachments.tsx index 2906dc15..f5e39f78 100644 --- a/packages/pro-components/chat/attachments/attachments.tsx +++ b/packages/pro-components/chat/attachments/attachments.tsx @@ -26,6 +26,7 @@ export default class Attachments extends Component { }; static defaultProps: Partial = { + overflow: 'wrap', removable: true, imageViewer: true, style: {}, diff --git a/packages/pro-components/chat/attachments/index.ts b/packages/pro-components/chat/attachments/index.ts index 3a039823..b7fca663 100644 --- a/packages/pro-components/chat/attachments/index.ts +++ b/packages/pro-components/chat/attachments/index.ts @@ -1,8 +1,9 @@ import './style/index.js'; import _Attachments from './attachments'; +import type { TdAttachmentsProps } from './type'; + +export type { TdAttachmentsProps }; export const Attachments = _Attachments; export default Attachments; - -export * from './type'; diff --git a/packages/pro-components/chat/attachments/type.ts b/packages/pro-components/chat/attachments/type.ts index 9f494bd2..3baee388 100644 --- a/packages/pro-components/chat/attachments/type.ts +++ b/packages/pro-components/chat/attachments/type.ts @@ -3,10 +3,25 @@ import { StyledProps } from '@tdesign/web-components-shared/common'; import { TdAttachmentItem } from '../filecard'; export interface TdAttachmentsProps extends StyledProps { + /** 附件列表 */ items: TdAttachmentItem[]; + /** + * 超出容器时的布局方式 + * @default wrap + */ overflow?: 'scrollX' | 'scrollY' | 'wrap'; + /** 移除附件时触发 */ onRemove?: (event: CustomEvent) => void; + /** 点击附件时触发 */ onFileClick?: (event: CustomEvent) => void; + /** + * 是否启用图片预览 + * @default true + */ imageViewer?: boolean; + /** + * 是否显示删除按钮 + * @default true + */ removable?: boolean; } diff --git a/packages/pro-components/chat/chat-action/README.md b/packages/pro-components/chat/chat-action/README.md index 75ebc502..d262dc46 100644 --- a/packages/pro-components/chat/chat-action/README.md +++ b/packages/pro-components/chat/chat-action/README.md @@ -10,16 +10,14 @@ spline: base {{ base }} - ## API ### ChatAction Props -名称 | 类型 | 默认值 | 说明 | 必传 --- | -- | -- | -- | -- -actionBar | `TdChatMessageActionName[] / boolean` | true | 操作按钮配置项,可配置操作按钮选项和顺序。TdChatMessageActionName枚举:`'replay'/'copy'/'good'/'bad'/'goodActived'/'badActived'/'share'` | N -onActions | `Record void>` | - | 操作按钮回调函数 | N -presetActions | `Record<{name: TdChatMessageActionName, render: TNode, condition?: (message: ChatMessagesData) => boolean;}>` | - | 预制按钮 | N -message | `any` | - | 对话数据信息 | N -tooltipProps | `TooltipProps` | - | Tooltip Props | N - +| 名称 | 类型 | 默认值 | 说明 | 必传 | +| ------------ | ----------------------------------------------------------- | ------ | ------------------------------------------------------------ | ---- | +| actionBar | `Array \| boolean` | `true` | 操作按钮及顺序;可使用预设名称或 `{ name, render }` 自定义项 | N | +| handleAction | `(name: TdChatActionsName, data: TdChatActionData) => void` | - | 操作按钮点击回调;`data` 包含 `event`、点赞状态等上下文 | N | +| comment | `ChatComment` | `''` | 当前点赞点踩状态 | N | +| copyText | String | `''` | 复制按钮使用的文本 | N | +| tooltipProps | `TooltipProps` | `{}` | 透传 Tooltip 属性 | N | diff --git a/packages/pro-components/chat/chat-action/action.tsx b/packages/pro-components/chat/chat-action/action.tsx index ed748242..fb9ed04e 100644 --- a/packages/pro-components/chat/chat-action/action.tsx +++ b/packages/pro-components/chat/chat-action/action.tsx @@ -14,7 +14,7 @@ import { setExportparts } from '@tdesign/web-components-shared/_util/dom'; import { Component, signal, tag } from 'omi'; import { type ChatComment } from '../chat-engine'; -import { TdChatActionItem, TdChatActionProps, TdChatActionsName } from './type'; +import { TdChatActionData, TdChatActionItem, TdChatActionProps, TdChatActionsName } from './type'; import styles from './style/action.less'; @@ -47,7 +47,7 @@ export const renderActions = ( } }; - const handleClickAction = (action: TdChatActionsName, data: any) => { + const handleClickAction = (action: TdChatActionsName, data: TdChatActionData) => { if (action === 'copy') { clickCopyHandler(); } @@ -150,12 +150,13 @@ export const renderActions = ( { name: 'share', render: defaultPresetActions('share', , '分享') }, ] as TdChatActionItem[]; - const arrayActions: TdChatActionItem[] = + const arrayActions: TdChatActionItem[] = Array.isArray(actionBar) && actionBar.length > 0 ? actionBar.map((action) => { // 兼容preset的旧逻辑 if (typeof action === 'string') { - return presetActions().find((item) => item.name === action); + // 未知字符串按自定义插槽处理,避免类型扩展或旧版 JS 调用时静默丢失操作项。 + return presetActions().find((item) => item.name === action) ?? { name: action, render: null }; } return action; }) @@ -198,8 +199,8 @@ export default class ChatAction extends Component { static css = [styles]; static propTypes = { - actionBar: Object, - handleAction: Object, + actionBar: [Array, Boolean], + handleAction: Function, comment: String, copyText: String, tooltipProps: Object, diff --git a/packages/pro-components/chat/chat-action/index.ts b/packages/pro-components/chat/chat-action/index.ts index d0e93760..2b68dc47 100644 --- a/packages/pro-components/chat/chat-action/index.ts +++ b/packages/pro-components/chat/chat-action/index.ts @@ -1,8 +1,9 @@ import './style/index.js'; import _Action from './action'; +import type { TdChatActionData, TdChatActionItem, TdChatActionProps, TdChatActionsName } from './type'; + +export type { TdChatActionData, TdChatActionItem, TdChatActionProps, TdChatActionsName }; export const ChatAction = _Action; export default ChatAction; - -export * from './type.js'; diff --git a/packages/pro-components/chat/chat-action/type.ts b/packages/pro-components/chat/chat-action/type.ts index 4e1e3d4c..96fa9b66 100644 --- a/packages/pro-components/chat/chat-action/type.ts +++ b/packages/pro-components/chat/chat-action/type.ts @@ -5,17 +5,40 @@ import { type ChatComment } from '../chat-engine'; export type TdChatActionsName = 'copy' | 'good' | 'bad' | 'replay' | 'share'; -export type TdChatActionItem = { - name: TdChatActionsName; +export type TdChatActionItem = { + name: TName; render: TNode; ignoreWrapper?: boolean; }; +export type TdChatActionData = { + event?: MouseEvent; + active?: boolean; + [key: string]: unknown; +}; + interface ChatActionProps { - actionBar?: TdChatActionsName[] | boolean; - handleAction?: (name: TdChatActionsName, data: any) => void; + /** + * 操作按钮及排列顺序 + * @default true + */ + actionBar?: Array> | boolean; + /** 操作按钮点击回调 */ + handleAction?: (name: TdChatActionsName, data: TdChatActionData) => void; + /** + * 当前点赞点踩状态 + * @default '' + */ comment?: ChatComment; + /** + * 复制按钮使用的文本 + * @default '' + */ copyText?: string; + /** + * 透传 Tooltip 属性 + * @default {} + */ tooltipProps?: TooltipProps; } diff --git a/packages/pro-components/chat/chat-loading/README.md b/packages/pro-components/chat/chat-loading/README.md index 61b4da80..95edbafb 100644 --- a/packages/pro-components/chat/chat-loading/README.md +++ b/packages/pro-components/chat/chat-loading/README.md @@ -14,7 +14,7 @@ spline: base ### ChatLoading Props -| 名称 | 类型 | 默认值 | 说明 | 必传 | -| --------- | -------------------------------------- | -------- | ------------ | ---- | -| animation | `skeleton/moving/gradient/dots/circle` | `circle` | 动画效果 | N | -| text | `string / TNode` | - | 加载提示文案 | N | +| 名称 | 类型 | 默认值 | 说明 | 必传 | +| --------- | ------------------------------------------------------------ | ---------- | ------------ | ---- | +| animation | `'skeleton' \| 'moving' \| 'gradient' \| 'dots' \| 'circle'` | `'moving'` | 动画效果 | N | +| text | String | `''` | 加载提示文案 | N | diff --git a/packages/pro-components/chat/chat-loading/index.ts b/packages/pro-components/chat/chat-loading/index.ts index bfade291..5db8d177 100644 --- a/packages/pro-components/chat/chat-loading/index.ts +++ b/packages/pro-components/chat/chat-loading/index.ts @@ -1,8 +1,9 @@ import './style/index.js'; import _Loading from './loading'; +import type { ChatLoadingAnimationType, TdChatLoadingProps } from './type'; + +export type { ChatLoadingAnimationType, TdChatLoadingProps }; export const ChatLoading = _Loading; export default ChatLoading; - -export * from './type'; diff --git a/packages/pro-components/chat/chat-loading/type.ts b/packages/pro-components/chat/chat-loading/type.ts index 192c32ab..eee19e93 100644 --- a/packages/pro-components/chat/chat-loading/type.ts +++ b/packages/pro-components/chat/chat-loading/type.ts @@ -3,7 +3,15 @@ import { StyledProps } from '@tdesign/web-components-shared/common'; export type ChatLoadingAnimationType = 'skeleton' | 'moving' | 'gradient' | 'circle' | 'dots'; interface ChatLoadingProps { + /** + * 加载提示文本 + * @default '' + */ text?: string; + /** + * 加载动画 + * @default moving + */ animation?: ChatLoadingAnimationType; } diff --git a/packages/pro-components/chat/chat-message/README.md b/packages/pro-components/chat/chat-message/README.md index 5e1929e1..20852e3c 100644 --- a/packages/pro-components/chat/chat-message/README.md +++ b/packages/pro-components/chat/chat-message/README.md @@ -1,6 +1,6 @@ --- title: ChatMessage 对话消息内容 -description: xxx +description: 用于渲染用户、助手和系统消息,以及 Markdown、思考、搜索、建议和附件等内容。 isComponent: true usage: { title: '', description: '' } spline: base @@ -37,9 +37,11 @@ spline: base {{ image }} ### 附件内容 + {{ attachment }} ### 自定义内容 + {{ custom }} ### 混合内容 @@ -48,40 +50,37 @@ spline: base ## API -### ChatItem Props - -## 基础属性 +### ChatMessage Props -| 属性名 | 类型 | 默认值 | 说明 | -|--------|------|--------|------| -| `placeholder` | `string` | - | 输入框占位文本 | -| `disabled` | `boolean` | `false` | 是否禁用整个输入组件 | -| `value` | `string` | - | 输入框当前值(受控模式) | -| `defaultValue` | `string` | - | 输入框默认值(非受控模式) | -| `status` | `ChatStatus` | `'idle'` | 聊天状态,可选值:'idle'(空闲)、'pending'(等待中)、'streaming'(流式传输中)、'complete'(完成)、'stop'(停止)、'error'(错误) | +| 名称 | 类型 | 默认值 | 说明 | 必传 | +| ---------------- | ------------------------------------------------------------ | -------------------------------------------- | -------------------------------------------------------------------------------------- | ---- | +| actions | `Array \| boolean` | `['replay', 'copy', 'good', 'bad', 'share']` | 消息操作按钮及顺序;预设名称仅支持 `TdChatActionsName`,可用 `{ name, render }` 自定义 | N | +| animation | `ChatLoadingAnimationType` | `'skeleton'` | 消息加载动画 | N | +| handleActions | `TdChatMessageActionHandlers` | - | 操作按钮和内容事件回调;参数按 action 名称提供精确类型 | N | +| name | `string \| TNode` | - | 作者名称 | N | +| avatar | `string \| TNode` | - | 作者头像 | N | +| datetime | `string \| TNode` | - | 消息时间 | N | +| role | `ChatMessageRole` | - | 消息角色 | N | +| content | `AIMessageContent[] \| UserMessageContent[]` | - | 消息内容;优先级高于 `message.content` | N | +| status | `ChatMessageStatus` | - | 消息状态;优先级高于 `message.status` | N | +| id | String | - | 消息 ID;优先级高于 `message.id` | N | +| variant | `'base' \| 'text' \| 'outline'` | `'text'` | 消息样式 | N | +| placement | `'left' \| 'right'` | `'left'` | 消息方向 | N | +| message | `ChatMessagesData` | - | 完整消息对象 | N | +| chatContentProps | `TdChatContentProps` | - | Markdown、搜索、思考、建议和附件等内容配置 | N | -## 操作按钮配置 +### 操作名称 -| 属性名 | 类型 | 说明 | -|--------|------|------| -| `actions` | `TdChatSenderAction[]` \| `Function` \| `boolean` | 操作按钮配置: - 数组:自定义操作按钮列表 - 函数:(preset) => 操作按钮数组 - 布尔值:是否显示默认操作按钮 | +`TdChatMessageActionName` 包含 `copy`、`good`、`bad`、`replay`、`share`、`searchResult`、`searchItem`、`suggestion` 和 `codeCopy`。其中后四项是内容事件名称,只用于 `handleActions`,不作为 `actions` 的预设字符串。 -## 透传属性 +### 内容配置 -| 属性名 | 类型 | 默认值 | 说明 | -|--------|------|--------|------| -| `attachmentsProps` | `TdAttachmentsProps` | `{ items: [], overflow: 'scrollX' }` | 附件列表配置属性 | -| `textareaProps` | `Partial` | `{ autosize: { minRows: 2 } }` | 文本输入框配置属性 | -| `uploadProps` | `Omit` | - | 文件上传输入框的HTML属性 | +`TdChatContentProps` 提供以下内置配置: -## 事件回调 +- `markdown`:Markdown 渲染配置。 +- `search`:搜索结果折叠配置。 +- `thinking`、`reasoning`:思考过程布局和动画。 +- `suggestion`:推荐问题配置。 +- `attachments`:附件点击、移除和预览配置。 -| 事件名 | 参数类型 | 说明 | -|--------|----------|------| -| `onSend` | `CustomEvent` | 点击发送按钮时触发 | -| `onStop` | `(value: string, context: { e: MouseEvent })` | 点击停止按钮时触发 | -| `onChange` | `(value: string, context: { e: InputEvent \| MouseEvent \| KeyboardEvent })` | 输入内容变化时触发 | -| `onBlur` | `(value: string, context: { e: FocusEvent })` | 输入框失去焦点时触发 | -| `onFocus` | `(value: string, context: { e: FocusEvent })` | 输入框获得焦点时触发 | -| `onFileSelect` | `(files: File[]) => Promise< TdAttachmentItem[]>` | 选择文件时触发 | -| `onFileRemove` | `(files: File[]) => Promise< TdAttachmentItem[]>` | 移除文件时触发 | +消息内容的协议类型来自 `@tdesign/ai-chat-engine`,并由 `@tdesign/web-components-chat/chat-engine` 导出。 diff --git a/packages/pro-components/chat/chat-message/chat-item.tsx b/packages/pro-components/chat/chat-message/chat-item.tsx index 8370aa03..f9888a9c 100644 --- a/packages/pro-components/chat/chat-message/chat-item.tsx +++ b/packages/pro-components/chat/chat-message/chat-item.tsx @@ -18,6 +18,7 @@ import { convertToLightDomNode } from '@tdesign/web-components-shared/_util/ligh import { isString } from 'lodash-es'; import { Component, OmiProps, signal, tag } from 'omi'; +import type { TdChatActionData } from '../chat-action'; import { DefaultChatMessageActionsName } from '../chat-action/action'; import type { ChatMessagesData } from '../chat-engine'; import { @@ -35,7 +36,7 @@ import { renderReasoning } from './content/reasoning-content'; import { renderSearch } from './content/search-content'; import { renderSuggestion } from './content/suggestion-content'; import { renderThinking } from './content/thinking-content'; -import type { TdChatMessageActionName, TdChatMessageProps } from './type'; +import type { TdChatMessageActionData, TdChatMessageActionName, TdChatMessageProps } from './type'; import styles from './style/chat-item.less'; @@ -47,13 +48,13 @@ export default class ChatItem extends Component { static css = [styles]; // 声明哪些prop是slot - static slotProps = ['avatar', 'name']; + static slotProps = ['avatar', 'name', 'datetime']; static propTypes = { - actions: [Array, Function, Boolean], + actions: [Array, Boolean], name: [String, Object], // 支持传入String或ReactNode avatar: [String, Object], // 支持传入String或ReactNode - datetime: String, + datetime: [String, Object], message: Object, role: String, content: Array, @@ -181,15 +182,14 @@ export default class ChatItem extends Component { ) : null; } - private handleClickAction = (action: Partial, data?: any) => { + private handleClickAction = (action: TdChatMessageActionName, data: TdChatActionData = {}) => { const internalMessage = this.getInternalMessage(); const toData = { ...data, message: internalMessage, }; - if (this.props?.handleActions?.[action]) { - this.props.handleActions[action](toData); - } + const handleAction = this.props?.handleActions?.[action] as ((data: TdChatMessageActionData) => void) | undefined; + handleAction?.(toData as TdChatMessageActionData); this.fire( 'chat_message_action', { action, data: toData }, diff --git a/packages/pro-components/chat/chat-message/content/README.md b/packages/pro-components/chat/chat-message/content/README.md index 02dc1526..d9ffd76b 100644 --- a/packages/pro-components/chat/chat-message/content/README.md +++ b/packages/pro-components/chat/chat-message/content/README.md @@ -1,186 +1,87 @@ -# Chat Message Content Components +# ChatMessage 内容渲染器 -## 重构说明 +ChatMessage 内置 Markdown、附件、搜索、建议、Thinking 和 Reasoning 渲染器。消息协议类型来自 `@tdesign/ai-chat-engine`;本目录只维护 Web Components 的展示属性。 -为了减少重复代码并提高维护性,我们将 `ThinkingContent` 和 `ReasoningContent` 的公共逻辑提取到了 `BaseThinkingContent` 中。 +## MarkdownContent -### 组件架构 +`t-chat-md-content` 使用与 ChatMessage 相同的 Cherry Markdown 流式渲染器。 -``` -BaseThinkingContent (基础类) -├── ThinkingContent (简单思考内容) -└── ReasoningContent (复杂推理内容) -``` +| 名称 | 类型 | 默认值 | 说明 | +| ------- | ------------------------ | ------ | ---------------------- | +| content | String | - | Markdown 内容 | +| options | `TdChatContentMDOptions` | `{}` | Cherry Markdown 配置项 | -## ReasoningContent 组件 +`options` 会排除由组件接管的 `id`、`el`、`toolbars`,并支持通过 `themeSettings.codeBlockTheme` 配置代码块主题。 -ReasoningContent 是一个用于渲染 AGUI 协议中 thinking 部分穿插 toolcall 的组件,基于 `BaseThinkingContent` 实现。 +## SearchContent -### 重构后的特性 +`t-chat-search-content` 展示搜索标题及引用链接。 -- 🎯 **代码复用**:与 ThinkingContent 共享基础逻辑 -- 📝 **文本自动渲染**:文本内容自动分段显示 -- 🔌 **插槽机制**:非文本内容通过插槽 `reasoning-{type}-{index}` 自定义渲染 -- 🎨 **样式复用**:复用 thinking 组件的样式类 -- ⚡ **轻量化**:去除内置的复杂渲染逻辑,更加灵活 +| 名称 | 类型 | 默认值 | 说明 | +| ----------------------- | --------------------------------------------------------------------------------------- | ------ | ---------------------------- | +| content | `TdChatSearchContentData` | - | 搜索标题和引用列表 | +| status | `ChatMessageStatus` | - | 当前消息状态 | +| useCollapse | Boolean | `true` | 是否使用折叠面板 | +| collapsed | Boolean | - | 折叠状态 | +| handleSearchResultClick | `({ event, content }: { event: MouseEvent; content: TdChatSearchContentData }) => void` | - | 非折叠模式点击搜索结果时触发 | +| handleSearchItemClick | `({ event, content }: { event: MouseEvent; content: ReferenceItem }) => void` | - | 点击引用项时触发 | -### 类型定义 +## SuggestionContent -```typescript -type TdChatReasoningProps = { - content?: AIMessageContent[]; - status?: ChatMessageStatus; -} & TdChatContentProps['thinking']; -``` +`t-chat-suggestion-content` 展示推荐问题。 -### 使用示例 +| 名称 | 类型 | 默认值 | 说明 | +| ----------------- | ------------------------------------------------------------------------------ | ------ | ---------------- | +| content | `SuggestionItem[]` | - | 推荐问题列表 | +| handlePromptClick | `({ event, content }: { event: MouseEvent; content: SuggestionItem }) => void` | - | 点击推荐问题回调 | -#### 基础用法 +## AttachmentContent -```tsx -const reasoningData: AIMessageContent[] = [ - { - type: 'text', - data: '我需要分析这个问题...', - }, - { - type: 'toolcall', - data: { - toolCallId: 'search_001', - toolCallName: 'web_search', - args: '{"query": "相关信息"}', - result: '搜索结果...', - }, - status: 'complete', - }, - { - type: 'text', - data: '基于搜索结果,我的分析是...', - }, -]; - - -``` +`t-chat-attachment-content` 展示消息中的附件列表。 -#### 在 ChatItem 中使用(带自定义插槽) +| 名称 | 类型 | 默认值 | 说明 | +| ----------- | ------------------------------------------------ | ------ | -------------- | +| content | `AttachmentItem[]` | - | 附件列表 | +| onFileClick | `(event: CustomEvent) => void` | - | 点击附件时触发 | -```tsx - - {/* 自定义工具调用渲染 */} -
-
-

🔧 工具调用

-

函数: {toolCall.toolCallName}

-

参数: {toolCall.args}

-

结果: {toolCall.result}

-
-
- - {/* 自定义搜索结果渲染 */} -
- -
-
-``` +## ThinkingContent -### 插槽命名规则 - -- 文本内容:自动渲染,无需插槽 -- 其他内容:`reasoning-{type}-{index}` - - `reasoning-toolcall-0`:第一个工具调用 - - `reasoning-search-1`:第二个搜索结果 - - `reasoning-image-2`:第三个图片内容 - -### 与 ThinkingContent 的对比 - -| 特性 | ThinkingContent | ReasoningContent | -|------|----------------|------------------| -| 基础类 | BaseThinkingContent | BaseThinkingContent | -| 数据结构 | `{text, title}` | `AIMessageContent[]` | -| 内容渲染 | 纯文本 | 文本 + 插槽 | -| 使用场景 | 简单思考 | 复杂推理 | -| 自定义能力 | 低 | 高 | - -### 样式复用 - -组件复用 thinking 的样式类: - -```less -.t-chat__item__think { - // 基础容器样式(共享) - - &__reasoning { - // reasoning 特有标识(实际复用 think 样式) - - &__text { - // 文本段落样式 - } - - &__custom { - // 自定义内容容器样式 - } - } -} -``` +`t-chat-thinking-content` 用于展示简单思考内容。 -### 最佳实践 +| 名称 | 类型 | 默认值 | 说明 | +| ----------------- | ----------------------------------- | ---------- | -------------- | +| content | `{ text?: string; title?: string }` | - | 思考标题和正文 | +| status | `ChatMessageStatus` | - | 当前消息状态 | +| maxHeight | Number | - | 正文最大高度 | +| animation | `ChatLoadingAnimationType` | `'circle'` | 进行中动画 | +| collapsed | Boolean | - | 受控折叠状态 | +| defaultCollapsed | Boolean | `false` | 默认折叠状态 | +| layout | `'block' \| 'border'` | `'block'` | 展示布局 | +| onCollapsedChange | `(e: CustomEvent) => void` | - | 折叠状态变化 | -1. **插槽使用**:为非文本内容提供对应的插槽实现 -2. **性能优化**:大量内容时设置 `maxHeight` -3. **样式一致性**:自定义插槽内容保持与整体风格一致 -4. **类型安全**:使用 TypeScript 确保内容类型正确 +## ReasoningContent -### 迁移指南 +`t-chat-reasoning-content` 用于展示由文本与工具调用等内容交错组成的推理过程。文本自动渲染,其他内容通过插槽交给业务侧处理。 -如果你之前使用了包含复杂渲染逻辑的版本,现在需要: +| 名称 | 类型 | 默认值 | 说明 | +| ----------------- | ----------------------------------- | ---------- | ------------ | +| content | `AIMessageContent[]` | `[]` | 推理内容 | +| status | `ChatMessageStatus` | - | 当前消息状态 | +| maxHeight | Number | - | 正文最大高度 | +| animation | `ChatLoadingAnimationType` | `'circle'` | 进行中动画 | +| collapsed | Boolean | - | 受控折叠状态 | +| defaultCollapsed | Boolean | `false` | 默认折叠状态 | +| layout | `'block' \| 'border'` | `'border'` | 展示布局 | +| onCollapsedChange | `(e: CustomEvent) => void` | - | 折叠状态变化 | -1. 将工具调用、搜索等内容的渲染逻辑移到插槽中 -2. 使用 `reasoning-{type}-{index}` 命名规则 -3. 保持文本内容不变(自动处理) +非文本内容的插槽名为 `reasoning-{type}-{index}`,例如 `reasoning-toolcall-1`。 -## BaseThinkingContent 基础类 - -提供 thinking 和 reasoning 组件的公共功能: - -### 公共特性 - -- 折叠/展开状态管理 -- 状态指示器渲染 -- 基础样式和布局 -- 事件处理机制 - -### 扩展点 - -- `renderContent()`: 子类实现具体内容渲染 -- `getHeaderTitle()`: 子类定义头部标题 -- `getClassName()`: 子类定义特有样式类 +```tsx + +
自定义工具调用结果
+
+``` -### 使用方式 +## 内部复用边界 -```typescript -// 继承基础类 -export class CustomThinkingComponent extends BaseThinkingContent { - protected renderContent(props: CustomProps) { - // 实现自定义内容渲染 - return
Custom content
; - } - - protected getHeaderTitle(props: CustomProps) { - return props.customTitle || '自定义标题'; - } - - protected getClassName() { - return 'custom-thinking'; - } -} \ No newline at end of file +`BaseThinkingComponent` 和 `renderBaseThinkingContainer` 是 Thinking/Reasoning 的内部复用实现,不属于稳定的组件 API。外部消费者应使用已导出的内容组件及其 Props,避免继承内部基础类。 diff --git a/packages/pro-components/chat/chat-message/content/attachment-content.tsx b/packages/pro-components/chat/chat-message/content/attachment-content.tsx index 352cc912..437e42d7 100644 --- a/packages/pro-components/chat/chat-message/content/attachment-content.tsx +++ b/packages/pro-components/chat/chat-message/content/attachment-content.tsx @@ -10,10 +10,10 @@ import styles from '../style/chat-item.less'; const className = `${getClassPrefix()}-chat__item`; -export type TdChatAttachmentContentProps = { +export interface TdChatAttachmentContentProps { content?: AttachmentItem[]; onFileClick?: (event: CustomEvent) => void; -}; +} // 纯函数渲染器 export const renderAttachments = ({ content, onFileClick }: TdChatAttachmentContentProps) => ( @@ -34,7 +34,7 @@ export default class AttachmentContentComponent extends Component) => void; -} & TdChatContentProps['thinking']; - -// 渲染状态图标的公共函数 -export const renderThinkingStatus = (status: ChatMessageStatus, animation = 'moving') => { - if (status === 'complete' || status === 'stop') - return convertToLightDomNode(); - if (status === 'error') - return convertToLightDomNode(); - return ; -}; - -// 基础思考容器渲染函数 -export const renderBaseThinkingContainer = ({ - key, - status, - maxHeight, - animation = 'moving', - collapsed = false, - layout = 'block', - onChange, - headerContent, - bodyContent, - className: customClassName = '', -}: BaseThinkingProps & { - headerContent: any; - bodyContent: any; - className?: string; -}) => { - const defaultCollapsed = collapsed ? [] : [1]; - const layoutClass = layout === 'border' ? `${className}__think-layout-border` : ``; - - // 通过是否传入onChange判断受控还是非受控 - return ( - - - - -
{bodyContent}
-
-
-
- {status !== 'stop' && renderThinkingStatus(status as ChatMessageStatus, animation)} - {headerContent} -
-
-
- ); -}; - -// 基础思考组件类 -export abstract class BaseThinkingComponent extends Component { - static css = styles; - - pCollapsed = signal(false); - - get computedCollapsed() { - if (!isNil((this.props as any).collapsed)) return (this.props as any).collapsed; - return this.pCollapsed.value; - } - - ready(): void { - this.pCollapsed.value = (this.props as any).defaultCollapsed; - } - - onCollapsedChange = (e: CustomEvent) => { - if (!e.detail.length) { - this.pCollapsed.value = true; - } else { - this.pCollapsed.value = false; - } - this.fire('collapsedChange', this.pCollapsed.value); - }; - - // 子类需要实现的抽象方法 - abstract renderContent(): any; - - abstract getHeaderContent(): any; - - abstract getClassName(): string; - - render(props: T) { - return renderBaseThinkingContainer({ - ...(props as any), - collapsed: this.computedCollapsed, - onChange: this.onCollapsedChange, - headerContent: this.getHeaderContent(), - bodyContent: this.renderContent(), - className: this.getClassName(), - }); - } -} diff --git a/packages/pro-components/chat/chat-message/content/internal-type.ts b/packages/pro-components/chat/chat-message/content/internal-type.ts new file mode 100644 index 00000000..a0781b40 --- /dev/null +++ b/packages/pro-components/chat/chat-message/content/internal-type.ts @@ -0,0 +1,11 @@ +import type { CollapseValue } from '@tdesign/web-components/collapse'; + +export type TdChatCollapsibleContentProps = { + defaultCollapsed?: boolean; + onCollapsedChange?: (e: CustomEvent) => void; +}; + +export type ChatContentRenderProps = T & { + key?: string; + onChange?: (e: CustomEvent) => void; +}; diff --git a/packages/pro-components/chat/chat-message/content/reasoning-content.tsx b/packages/pro-components/chat/chat-message/content/reasoning-content.tsx index 917a5780..aad1f3a7 100644 --- a/packages/pro-components/chat/chat-message/content/reasoning-content.tsx +++ b/packages/pro-components/chat/chat-message/content/reasoning-content.tsx @@ -13,25 +13,20 @@ import { isNil } from 'lodash-es'; import { Component, signal, tag } from 'omi'; import type { TdChatContentProps } from '../type'; +import type { ChatContentRenderProps, TdChatCollapsibleContentProps } from './internal-type'; import styles from '../style/chat-item.less'; const className = `${getClassPrefix()}-chat__item`; type TdChatReasoningBaseProps = { - key?: string; content?: AIMessageContent[]; status?: ChatMessageStatus; } & TdChatContentProps['reasoning']; -export type TdChatReasoningProps = { - defaultCollapsed?: boolean; - onCollapsedChange?: (e: CustomEvent) => void; -} & TdChatReasoningBaseProps; +export type TdChatReasoningProps = TdChatCollapsibleContentProps & TdChatReasoningBaseProps; -export interface IRenderReasoning extends TdChatReasoningBaseProps { - onChange?: (e: CustomEvent) => void; -} +export type IRenderReasoning = ChatContentRenderProps; // 渲染单个内容项 const renderContentItem = (content: AIMessageContent, index: number) => { @@ -43,7 +38,9 @@ const renderContentItem = (content: AIMessageContent, index: number) => { {content.data ?.split('\n') .filter(Boolean) - .map((paragraph, pIndex) =>

{paragraph}

)} + .map((paragraph, pIndex) => ( +

{paragraph}

+ ))} ); } diff --git a/packages/pro-components/chat/chat-message/content/search-content.tsx b/packages/pro-components/chat/chat-message/content/search-content.tsx index 45f35ced..ed43285d 100644 --- a/packages/pro-components/chat/chat-message/content/search-content.tsx +++ b/packages/pro-components/chat/chat-message/content/search-content.tsx @@ -1,7 +1,7 @@ import '@tdesign/web-components'; import 'tdesign-icons-web-components/esm/components/jump'; -import { ChatMessageStatus, ReferenceItem } from '@tdesign/ai-chat-engine'; +import type { ChatMessageStatus, ReferenceItem, SearchContent } from '@tdesign/ai-chat-engine'; import type { CollapseValue } from '@tdesign/web-components/collapse'; import { getClassPrefix } from '@tdesign/web-components-shared/_util/classname'; import { Component, OmiProps, signal, tag } from 'omi'; @@ -12,19 +12,19 @@ import styles from '../style/chat-item.less'; const className = `${getClassPrefix()}-chat__item`; -type SearchContent = { - title?: string; - references?: ReferenceItem[]; -}; +export type TdChatSearchContentData = SearchContent['data']; export type TdChatSearchContentProps = { - key?: string; - content?: SearchContent; - status?: ChatMessageStatus | ((currentStatus: ChatMessageStatus | undefined) => ChatMessageStatus); - onChange?: (value: CollapseValue) => void; - handleSearchResultClick?: ({ event, content }: { event: MouseEvent; content: SearchContent }) => void; + content?: TdChatSearchContentData; + status?: ChatMessageStatus; + handleSearchResultClick?: ({ event, content }: { event: MouseEvent; content: TdChatSearchContentData }) => void; handleSearchItemClick?: ({ event, content }: { event: MouseEvent; content: ReferenceItem }) => void; } & TdChatContentProps['search']; +type RenderSearchProps = TdChatSearchContentProps & { + key?: string; + onChange?: (value: CollapseValue) => void; +}; + // 纯函数渲染器 export const renderSearch = ({ key, @@ -35,7 +35,7 @@ export const renderSearch = ({ handleSearchResultClick, handleSearchItemClick, onChange, -}: TdChatSearchContentProps) => { +}: RenderSearchProps) => { if (!content) return; const defaultCollapsed = collapsed ? [] : [1]; const { references = [], title } = content; @@ -114,8 +114,8 @@ export default class SearchContentComponent extends Component void; }; +type RenderSuggestionProps = TdChatSuggestionContentProps & { key?: string }; + // 纯函数渲染器 -export const renderSuggestion = ({ key, content, handlePromptClick }: TdChatSuggestionContentProps) => ( +export const renderSuggestion = ({ key, content, handlePromptClick }: RenderSuggestionProps) => (
{content.map( (s, i) => @@ -40,8 +41,8 @@ export default class SuggestionContentComponent extends Component) => void; -} & TdChatThinkBaseProps; +export type TdChatThinkContentProps = TdChatCollapsibleContentProps & TdChatThinkBaseProps; -export interface IRenderThinking extends TdChatThinkBaseProps { - onChange?: (e: CustomEvent) => void; -} +export type IRenderThinking = ChatContentRenderProps; // 纯函数渲染器(无shadow root) export const renderThinking = ({ @@ -77,7 +72,9 @@ export const renderThinking = ({ {text ?.split('\n') .filter(Boolean) - .map((paragraph, index) =>

{paragraph}

)} + .map((paragraph, index) => ( +

{paragraph}

+ ))}
diff --git a/packages/pro-components/chat/chat-message/index.ts b/packages/pro-components/chat/chat-message/index.ts index c5f9e4c6..05d25359 100644 --- a/packages/pro-components/chat/chat-message/index.ts +++ b/packages/pro-components/chat/chat-message/index.ts @@ -2,14 +2,33 @@ import './style/index.js'; import CherryStream from 'cherry-markdown/dist/cherry-markdown.stream.esm.js'; +import _AttachmentContent from './content/attachment-content'; +import type { + TdChatContentMDOptions, + TdChatContentMDPluginConfig, + TdChatContentMDPresetConfig, + TdChatContentMDPresetPlugin, + TdChatMarkdownContentProps, +} from './content/markdown-content'; import _MarkdownContent from './content/markdown-content'; import _ReasoningContent from './content/reasoning-content'; import _SearchContent from './content/search-content'; import _SuggestionContent from './content/suggestion-content'; import _ThinkingContent from './content/thinking-content'; import _ChatItem from './chat-item'; +import type { + TdChatContentProps, + TdChatMessageAction, + TdChatMessageActionData, + TdChatMessageActionDataMap, + TdChatMessageActionHandlers, + TdChatMessageActionName, + TdChatMessageProps, + TdChatMessageVariant, +} from './type'; export const ChatThinkingContent = _ThinkingContent; +export const ChatAttachmentContent = _AttachmentContent; export const ChatSuggestionContent = _SuggestionContent; export const ChatMarkdownContent = _MarkdownContent; export const ChatSearchContent = _SearchContent; @@ -18,11 +37,25 @@ export const ChatReasoningContent = _ReasoningContent; // 外部使用自定义逻辑时使用的CherryMarkdown类必须跟渲染时保持一致 export const TdMarkdownEngine = CherryStream; -export type * from './content/markdown-content'; +export type { TdChatAttachmentContentProps } from './content/attachment-content'; export type { TdChatReasoningProps } from './content/reasoning-content'; export type { TdChatSearchContentProps } from './content/search-content'; export type { TdChatSuggestionContentProps } from './content/suggestion-content'; export type { TdChatThinkContentProps } from './content/thinking-content'; -export type * from './type'; +export type { + TdChatContentMDOptions, + TdChatContentMDPluginConfig, + TdChatContentMDPresetConfig, + TdChatContentMDPresetPlugin, + TdChatContentProps, + TdChatMarkdownContentProps, + TdChatMessageAction, + TdChatMessageActionData, + TdChatMessageActionDataMap, + TdChatMessageActionHandlers, + TdChatMessageActionName, + TdChatMessageProps, + TdChatMessageVariant, +}; export default ChatMessage; diff --git a/packages/pro-components/chat/chat-message/type.ts b/packages/pro-components/chat/chat-message/type.ts index 69aa8c48..02755237 100644 --- a/packages/pro-components/chat/chat-message/type.ts +++ b/packages/pro-components/chat/chat-message/type.ts @@ -1,16 +1,18 @@ import type { TNode } from '@tdesign/web-components-shared/common'; -import type { TdChatActionsName } from '../chat-action'; +import type { TdChatActionData, TdChatActionItem, TdChatActionsName } from '../chat-action'; import type { AIMessageContent, - ChatContentType, ChatMessageRole, ChatMessagesData, ChatMessageStatus, + ReferenceItem, + SearchContent, + SuggestionItem, UserMessageContent, } from '../chat-engine'; import type { ChatLoadingAnimationType, TdChatLoadingProps } from '../chat-loading'; -import { TdChatAttachmentContentProps } from './content/attachment-content'; +import type { TdChatAttachmentContentProps } from './content/attachment-content'; import type { TdChatMarkdownContentProps } from './content/markdown-content'; type TdChatContentSearchProps = { @@ -32,10 +34,27 @@ type TdChatContentSuggestionProps = { export type TdChatMessageVariant = 'base' | 'text' | 'outline'; export type TdChatMessageActionName = TdChatActionsName | 'searchResult' | 'searchItem' | 'suggestion' | 'codeCopy'; -export interface TdChatMessageAction { - name: TdChatMessageActionName; - render: TNode; -} +/** 消息操作栏中的自定义插槽项;内容事件名称不作为预设按钮名称使用。 */ +export type TdChatMessageAction = TdChatActionItem; + +type TdChatMessageActionBaseData = TdChatActionData & { + message?: ChatMessagesData; +}; + +export type TdChatMessageActionDataMap = { + [K in TdChatActionsName]: TdChatMessageActionBaseData; +} & { + searchResult: TdChatMessageActionBaseData & { event: MouseEvent; content: SearchContent['data'] }; + searchItem: TdChatMessageActionBaseData & { event: MouseEvent; content: ReferenceItem }; + suggestion: TdChatMessageActionBaseData & { event: MouseEvent; content: SuggestionItem }; + codeCopy: TdChatMessageActionBaseData & { code: string; lang?: string }; +}; + +export type TdChatMessageActionData = TdChatMessageActionDataMap[TdChatMessageActionName]; + +export type TdChatMessageActionHandlers = { + [K in TdChatMessageActionName]?: (data: TdChatMessageActionDataMap[K]) => void; +}; export type TdChatContentProps = { markdown?: Omit; @@ -43,20 +62,25 @@ export type TdChatContentProps = { thinking?: TdChatContentThinkProps; reasoning?: TdChatContentThinkProps; suggestion?: TdChatContentSuggestionProps; - attachments?: TdChatAttachmentContentProps; - [key: string]: any; // 处理其他ContentType情况 -} & Partial, any>>; + attachments?: Omit; +}; export interface TdChatMessageProps { /** * 操作 + * @default ['replay', 'copy', 'good', 'bad', 'share'] */ actions?: - | TdChatMessageActionName[] + | Array // | ((preset: TdChatMessageAction[], message: ChatMessagesData) => TdChatMessageAction[]) | boolean; + /** + * 消息加载动画 + * @default skeleton + */ animation?: ChatLoadingAnimationType; - handleActions?: Partial void>>; + /** 操作按钮回调 */ + handleActions?: TdChatMessageActionHandlers; /** * 作者 */ @@ -87,9 +111,13 @@ export interface TdChatMessageProps { id?: string; /** * 消息样式,是否有边框,背景色等 + * @default text */ variant?: TdChatMessageVariant; - /** 气泡方向 */ + /** + * 气泡方向 + * @default left + */ placement?: 'left' | 'right'; /** 消息体 (兼容旧版本,优先级低于直接传入的 role/content/status) */ message?: ChatMessagesData; diff --git a/packages/pro-components/chat/chat-message/usage-example.md b/packages/pro-components/chat/chat-message/usage-example.md deleted file mode 100644 index a166b0f8..00000000 --- a/packages/pro-components/chat/chat-message/usage-example.md +++ /dev/null @@ -1,101 +0,0 @@ -# ChatMessage 组件新 API 使用示例 - -## 新的 API 使用方式(推荐) - -```tsx -// 直接传入 role、content、status 属性 - - -// 用户消息示例 - -``` - -## 兼容旧版本 API - -```tsx -// 仍然支持通过 message 属性传入完整消息对象 - -``` - -## 优先级说明 - -当同时传入新旧两种方式的属性时,新的直接属性优先级更高: - -```tsx - -``` - -在上面的例子中,组件会使用 `role="user"`、新的消息内容和 `status="complete"`,而忽略 `message` 属性中的值。 - -## 类型定义 - -```typescript -interface TdChatMessageProps { - // 新增的直接属性 - role?: ChatMessageRole; // 'user' | 'assistant' | 'system' - content?: AIMessageContent[] | UserMessageContent[]; - status?: ChatMessageStatus; // 'pending' | 'streaming' | 'complete' | 'stop' | 'error' - id?: string; - - // 兼容属性(优先级低) - message?: ChatMessagesData; - - // 其他属性保持不变 - name?: string | TNode; - avatar?: string | TNode; - datetime?: string | TNode; - variant?: TdChatMessageVariant; - placement?: 'left' | 'right'; - // ... -} \ No newline at end of file diff --git a/packages/pro-components/chat/chat-sender/README.md b/packages/pro-components/chat/chat-sender/README.md index 9d2a92d8..0db8c9e9 100644 --- a/packages/pro-components/chat/chat-sender/README.md +++ b/packages/pro-components/chat/chat-sender/README.md @@ -22,21 +22,21 @@ spline: base ### ChatSender Props -| 属性名 | 类型 | 默认值 | 说明 | 必传 | -| ---------------- | ------------------------------------- | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | +| 属性名 | 类型 | 默认值 | 说明 | 必传 | +| ---------------- | ------------------------------------------------ | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | | actions | String[] / Object[] / Function / TNode / Boolean | `['send']` | 操作按钮配置。支持预设名称数组 `['uploadImage', 'uploadAttachment', 'attachment'('uploadAttachment'的兼容别名,**后续将废弃**), 'send']`;对象数组 `[{ name: 'uploadImage', uploadProps: { accept: '.png' } }]` 配置上传属性;函数 `(preset) => [{ name, render }]` 自定义渲染;TNode 完全自定义;`true` 显示发送按钮,`false` 隐藏 | N | -| attachmentsProps | Object | `{ items: [], overflow: 'scrollX' }` | 附件列表配置属性,透传 `Attachments` 组件 | N | -| autosize | Boolean / Object | `{ minRows: 2 }` | 高度自动撑开,支持 `true` 或配置项 `{ minRows, maxRows }` | N | -| defaultValue | String | - | 输入框的默认值,非受控模式 | N | -| disabled | Boolean | `false` | 是否禁用输入框 | N | -| loading | Boolean | `false` | 发送按钮是否处于加载状态 | N | -| placeholder | String | - | 输入框默认文案 | N | -| sendBtnDisabled | Boolean / Function | `false` | 禁用发送按钮,支持布尔值或函数 `(inputValue: string) => boolean`;输入为空时发送按钮始终禁用 | N | -| textareaProps | Object | - | 透传 `Textarea` 组件属性 | N | -| uploadProps | Object | - | **已废弃**,建议使用 `actions` 配置上传属性。例如:`actions: [{ name: 'uploadImage', uploadProps: { accept: '.png' } }]`。详见 [TdChatSenderUploadProps](#tdchatsenderuploadprops) | N | -| value | String | - | 输入框的值,支持双向绑定 | N | -| onBlur | Function | - | 输入框失焦事件,TS 类型:`(e: CustomEvent) => void` | N | -| onFocus | Function | - | 输入框聚焦事件,TS 类型:`(e: CustomEvent) => void` | N | +| attachmentsProps | `Partial` | `{ items: [], overflow: 'scrollX' }` | 附件列表配置属性,透传 `Attachments` 组件;可只覆盖所需字段 | N | +| autosize | Boolean / Object | `{ minRows: 2 }` | 高度自动撑开,支持 `true` 或配置项 `{ minRows, maxRows }` | N | +| defaultValue | String | - | 输入框的默认值,非受控模式 | N | +| disabled | Boolean | `false` | 是否禁用输入框 | N | +| loading | Boolean | `false` | 发送按钮是否处于加载状态 | N | +| placeholder | String | - | 输入框默认文案 | N | +| sendBtnDisabled | Boolean / Function | `false` | 禁用发送按钮,支持布尔值或函数 `(inputValue: string) => boolean`;输入为空时发送按钮始终禁用 | N | +| textareaProps | Object | - | 透传 `Textarea` 组件属性 | N | +| uploadProps | Object | - | **已废弃**,建议使用 `actions` 配置上传属性。例如:`actions: [{ name: 'uploadImage', uploadProps: { accept: '.png' } }]`。详见 [TdChatSenderUploadProps](#tdchatsenderuploadprops) | N | +| value | String | - | 输入框的值,支持双向绑定 | N | +| onBlur | Function | - | 输入框失焦事件,TS 类型:`(e: CustomEvent) => void` | N | +| onFocus | Function | - | 输入框聚焦事件,TS 类型:`(e: CustomEvent) => void` | N | ### ChatSender Events @@ -63,41 +63,14 @@ spline: base ### ChatSender Methods -| 名称 | 参数 | 说明 | -| :---------- | :------------------------- | :----------- | -| focus | `(options?: FocusOptions)` | 获取焦点 | -| blur | - | 取消焦点 | -| selectFile | - | 触发文件选择 | +| 名称 | 参数 | 说明 | +| :--------- | :------------------------- | :----------- | +| focus | `(options?: FocusOptions)` | 获取焦点 | +| blur | - | 取消焦点 | +| selectFile | - | 触发文件选择 | -### 类型定义 +### 相关公共类型 -#### TdChatSenderUploadProps +`TdChatSenderUploadProps`、`TdChatSenderAction` 和 `TdAttachmentItem` 均由 `@tdesign/web-components-chat` 导出。精确字段、可选性和联合类型以包声明为唯一来源,本文档不再手写复制接口。 -上传配置属性。 - -| 名称 | 类型 | 说明 | -| :------- | :------ | :---------------------------------------------- | -| accept | String | 接受的文件类型,如 `'image/*'` 或 `'.jpg,.png'` | -| multiple | Boolean | 是否允许多选 | - -#### TdChatSenderAction - -操作按钮配置。 - -| 名称 | 类型 | 说明 | -| :--------- | :------------------------ | :------------------------------------------------------ | -| name | String | 按钮名称,对应预设按钮:`uploadImage`、`uploadAttachment`、`attachment`、`send` | -| uploadProps | TdChatSenderUploadProps | 上传配置,仅对 `uploadImage` 和 `uploadAttachment` 有效 | - -#### TdAttachmentItem - -附件项数据结构。 - -| 名称 | 类型 | 说明 | -| :----- | :------------------------------------ | :--------------- | -| name | String | 文件名称 | -| url | String | 文件地址 | -| size | Number | 文件大小(字节) | -| type | String | 文件 MIME 类型 | -| status | `'success' \| 'error' \| 'uploading'` | 上传状态 | -| raw | File | 原始文件对象 | +其中上传基础字段由 tdesign-common 维护,对话附件协议字段由 `@tdesign/ai-chat-engine` 维护,Chat 仅补充 UI 所需字段。 diff --git a/packages/pro-components/chat/chat-sender/index.ts b/packages/pro-components/chat/chat-sender/index.ts index 6beec7f5..908b4faa 100644 --- a/packages/pro-components/chat/chat-sender/index.ts +++ b/packages/pro-components/chat/chat-sender/index.ts @@ -1,8 +1,25 @@ import './style/index.js'; import _ChatSender from './chat-sender'; +import type { + TdChatSenderAction, + TdChatSenderActionName, + TdChatSenderApi, + TdChatSenderParams, + TdChatSenderProps, + TdChatSenderUploadProps, + UploadActionType, +} from './type'; + +export type { + TdChatSenderAction, + TdChatSenderActionName, + TdChatSenderApi, + TdChatSenderParams, + TdChatSenderProps, + TdChatSenderUploadProps, + UploadActionType, +}; export const ChatSender = _ChatSender; export default ChatSender; - -export * from './type'; diff --git a/packages/pro-components/chat/chat-sender/type.ts b/packages/pro-components/chat/chat-sender/type.ts index e1563e9b..222471a8 100644 --- a/packages/pro-components/chat/chat-sender/type.ts +++ b/packages/pro-components/chat/chat-sender/type.ts @@ -1,4 +1,4 @@ -import { TdTextareaProps } from '@tdesign/web-components/textarea'; +import { TextareaProps } from '@tdesign/web-components/textarea'; import { TNode } from '@tdesign/web-components-shared/common'; import { TdAttachmentsProps } from '../attachments'; @@ -6,7 +6,7 @@ import { TdAttachmentItem } from '../filecard'; export type TdChatSenderActionName = 'uploadImage' | 'uploadAttachment' | 'attachment' | 'send'; -export type UploadActionType = 'uploadImage' | 'uploadAttachment'; +export type UploadActionType = Extract; export interface TdChatSenderUploadProps { /** 接受的文件类型,如 'image/*' 或 '.jpg,.png' */ @@ -61,16 +61,16 @@ export interface TdChatSenderProps { /** 是否加载中 */ loading?: boolean; /** 透传attachment参数 */ - attachmentsProps?: TdAttachmentsProps; + attachmentsProps?: Partial; /** * 高度自动撑开,支持传入 true 或配置项 { minRows, maxRows } * - true: 启用自动撑高 * - object: 配置最小/最大行数 * @default { minRows: 2 } */ - autosize?: TdTextareaProps['autosize']; + autosize?: TextareaProps['autosize']; /** 透传textarea参数 */ - textareaProps?: Partial>; + textareaProps?: Partial>; /** * 文件上传配置 * @deprecated 已废弃,建议使用 actions 配置上传属性。例如:actions: [{ name: 'uploadImage', uploadProps: { accept: '.png' } }] diff --git a/packages/pro-components/chat/chatbot/README.md b/packages/pro-components/chat/chatbot/README.md index dc862d74..b778857a 100644 --- a/packages/pro-components/chat/chatbot/README.md +++ b/packages/pro-components/chat/chatbot/README.md @@ -1,6 +1,6 @@ --- title: Chatbot 智能聊天 -description: 最基础的卡片容器,可承载文字、列表、图片、段落,常用于后台概览页面。 +description: 提供消息列表、输入框和 ChatEngine 编排能力的完整智能对话组件。 isComponent: true usage: { title: '', description: '' } spline: base @@ -36,181 +36,67 @@ spline: base ## API -## Chatbot Props - -### 基础属性 - -| 属性名 | 类型 | 默认值 | 说明 | -|--------|------|--------|------| -| clearHistory | Boolean | false | 是否清除聊天历史记录 | -| layout | String | 'both' | 布局方式,可选值:'both'、'single' | -| autoSendPrompt | Object/String | '' | 配置后会自动触发提问 | -| reverse | Boolean | false | 是否反转消息显示顺序 | -| defaultMessages | ChatMessagesData[] | - | 初始化的聊天消息数组 | -| messageProps | `{ ModelRoleEnum: TdChatMessageProps }` | - | 消息角色配置,它是一个键值对对象,键为角色类型`ModelRoleEnum`(`assistant`/`user`/`system`),值为对应角色的消息配置 `TdChatMessageProps` | -| senderProps | TdChatSenderProps | - | 是聊天输入框组件的属性配置,用于控制输入框的行为和外观,详细见`ChatSender组件` | -| chatServiceConfig | ChatServiceConfig/() => ChatServiceConfig | - | 聊天服务配置,用于初始化ChatEngine | -| injectCSS | Object | - | 注入的自定义CSS样式 | - -### 实例方法 -| 方法名 | 类型 | 说明 | -|--------------------|-------------------------------|--------------------------------------------------------------------| -| sendUserMessage | `(params: ChatRequestParams) => Promise` | 发送用户消息并自动清空附件,返回Promise等待操作完成 | -| sendSystemMessage | `(msg: string) => void` | 发送系统通知类消息 | -| abortChat | 无 | 中止当前进行中的聊天请求,返回Promise等待操作完成 | -| addPrompt | `(prompt: string) => void` | 预填充输入框内容并自动聚焦到输入域 | -| scrollToBottom | 无 | 将消息列表滚动到底部,适用于有新消息时自动定位 | - - -### 事件 - -| 事件名 | 参数 | 说明 | -|--------|------|------| -| `message_change` | `state` | 消息列表发生变化时触发 | -| `chat_submit` | `requestParams` | 提交聊天内容时触发 | -| `chat_stop` | - | 停止聊天时触发 | - -### 插槽(Slot) - -| 插槽名 | 说明 | -|--------|------| -| `sender-header` | 输入框头部内容 | -| `sender-inner-header` | 输入框边框内头部内容 | -| `sender-footer-prefix` | 输入框底部左侧内容 | -| `sender-actions` | 输入框操作按钮 | -| `[message-id]` | 特定消息ID的自定义内容 | - -## 内置对象属性 - -### TdChatMessageProps角色配置属性 - -| 属性名 | 类型 | 说明 | -|--------|------|------| -| actions | `TdChatMessageAction[]` \| `Function` \| `boolean` | 消息操作按钮配置,可以是预设数组、生成函数或布尔值(是否显示) | -| handleActions | `Record` | 操作按钮回调函数 | -| animation | `skeleton/moving/gradient/circle` | 动画效果 | -| name | `string` \| `TNode` | 作者名称或自定义渲染节点 | -| avatar | `string` \| `TNode` | 头像URL或自定义渲染节点 | -| datetime | `string` \| `TNode` | 时间显示或自定义渲染节点 | -| role | `ChatMessageRole` | 消息角色类型 | -| variant | `'base'` \| `'text'` \| `'outline'` | 消息气泡样式变体 | -| placement | `'left'` \| `'right'` | 消息气泡位置 | -| chatContentProps | `{[key in ChatContentType]?: {}}` | 可以针对不同内容类型进行定制化配置。ContentType类型有`text`、`markdown`、`search`、`thinking`、`suggestion`,| -| onMessageChange | `(e: CustomEvent) => void` | 消息更新时触发 | - -### ChatServiceConfig属性 - -| 属性名 | 类型 | 说明 | -|--------|------|------| -| endpoint | string | 聊天服务的API端点URL | -| stream | boolean| 是否使用流式传输 | -| retryInterval | number| 重试间隔时间(毫秒) | -| maxRetries | number | 最大重试次数 | -| onRequest | `(params: ChatRequestParams) => RequestInit \| Promise` | 请求前的回调,可修改请求参数 | -| onMessage | `(chunk: SSEChunkData) => AIMessageContent \| null` | 处理流式消息的回调 | -| onComplete | `(isAborted: boolean, params: RequestInit, result?: any) => void` | 请求完成时的回调 | -| onAbort | `() => Promise` | 中止请求时的回调 | -| onError | `(err: Error \| Response) => void` | 错误处理回调 | - -### injectCSS属性说明 - -| 属性名 | 类型 | 说明 | -|--------|------|------| -| ChatSender | string | 应用于聊天输入框组件的自定义 CSS 样式 | -| chatList | string | 应用于聊天列表组件的自定义 CSS 样式 | -| chatItem | string | 应用于单个聊天消息项的自定义 CSS 样式 | - -### ChatMessagesData 属性说明 - -`ChatMessagesData` 是聊天消息的基础类型,它是一个联合类型,包含三种不同角色的消息类型。 基础结构: - -```typescript -type ChatMessagesData = UserMessage | AIMessage | SystemMessage; -``` - -## 角色消息类型 - -### 公共基础属性 (ChatBaseMessage) - -所有消息类型都继承自 `ChatBaseMessage`,包含以下公共属性: - -| 属性名 | 类型 | 说明 | -|--------|------|------| -| id | string | 消息唯一标识符 | -| status | `ChatMessageStatus` | 消息状态:'pending'(等待中)、'streaming'(流式传输中)、'complete'(完成)、'stop'(停止)、'error'(错误) | -| datetime | string | 消息时间戳 (ISO 8601 格式) | -| ext | any | 扩展数据,可存放自定义业务数据 | - -### 1. SystemMessage (系统消息) - -```typescript -interface SystemMessage extends ChatBaseMessage { - role: 'system'; // 固定为'system' - content: TextContent[]; // 仅支持纯文本内容 -} -``` - -### 2. UserMessage (用户消息) - -```typescript -interface UserMessage extends ChatBaseMessage { - role: 'user'; // 固定为'user' - content: UserMessageContent[]; // 消息内容数组 -} -``` - -**UserMessageContent 内容类型**: -- `TextContent`: 纯文本内容 -- `AttachmentContent`: 附件内容 - -### 3. AIMessage (AI助手消息) - -```typescript -interface AIMessage extends ChatBaseMessage { - role: 'assistant'; // 固定为'assistant' - content: AIMessageContent[]; // 消息内容数组 - comment?: 'good' | 'bad'; // 用户反馈:'good'(点赞)、'bad'(点踩) -} -``` - -## AI消息内容分类说明 -**AIMessageContent 内容类型**: -- `TextContent`: 纯文本内容 -- `MarkdownContent`: Markdown格式内容 -- `ThinkingContent`: 思考中状态内容 -- `ImageContent`: 图片内容 -- `SearchContent`: 搜索结果内容 -- `SuggestionContent`: 建议内容 - -### TextContent (文本内容) - -```typescript -interface TextContent { - type: 'text'; // 固定为'text' - data: string; // 文本内容 - status?: ChatMessageStatus; // 内容状态 - id?: string; // 内容ID -} -``` - -### AttachmentContent (附件内容) - -```typescript -interface AttachmentContent { - type: 'attachment'; // 固定为'attachment' - data: AttachmentItem[]; // 附件项数组 - status?: ChatMessageStatus; // 内容状态 - id?: string; // 内容ID -} - -interface AttachmentItem { - fileType: AttachmentType; // 文件类型:'image'|'video'|'audio'|'pdf'|'doc'|'ppt'|'txt' - name: string; // 文件名 - url: string; // 文件URL - size: number; // 文件大小(字节) - isReference?: boolean; // 是否是引用文件 - width?: number; // 图片/视频宽度(像素) - height?: number; // 图片/视频高度(像素) - metadata?: Record; // 元数据 -} -``` +### Chatbot Props + +| 名称 | 类型 | 默认值 | 说明 | 必传 | +| ------------------- | --------------------------------------------------------------- | -------- | ----------------------------------------------------------- | ---- | +| layout | `'single' \| 'both'` | `'both'` | 单栏或双方对话布局 | N | +| reverse | Boolean | `false` | 是否倒序渲染消息 | N | +| listProps | `TdChatListProps` | - | 透传消息列表配置 | N | +| autoSendPrompt | String | `''` | 初始化完成后自动发送的提问 | N | +| defaultMessages | `ChatMessagesData[]` | `[]` | 初始消息列表 | N | +| messageProps | `TdChatMessageConfig \| ((message) => TdChatMessageConfigItem)` | - | 按角色或按消息配置 ChatMessage | N | +| senderProps | `TdChatSenderProps` | - | 透传 ChatSender 配置 | N | +| chatServiceConfig | `ChatServiceConfigSetter` | - | ChatEngine 服务配置或配置生成函数 | N | +| injectCSS | `TdChatInjectCSS` | - | 向 ChatSender、ChatList、ChatMessage 的 Shadow DOM 注入 CSS | N | +| onMessageChange | `(e: CustomEvent) => void` | - | 消息列表变化时触发 | N | +| onChatReady | `(e: CustomEvent>) => void` | - | ChatEngine 初始化完成时触发 | N | +| onChatAfterSend | `(e: CustomEvent) => void` | - | 用户消息发送完成后触发 | N | +| onChatStop | `(e: CustomEvent>) => void` | - | 用户点击停止按钮时触发 | N | +| onChatMessageAction | `(e: CustomEvent) => void` | - | 消息操作按钮触发 | N | + +### Chatbot Events + +| 名称 | detail | 说明 | +| ----------------- | -------------------------- | ---------------------------------------------- | +| messageChange | `ChatMessagesData[]` | 消息列表变化 | +| chatReady | `Record` | ChatEngine 初始化完成 | +| chat-after-send | `ChatRequestParams` | 用户消息发送完成 | +| chatStop | `Record` | 用户点击停止按钮;兼容保留旧事件 `chat_stop` | +| chatMessageAction | `TdChatMessageActionEvent` | 消息操作;兼容保留旧事件 `chat_message_action` | + +### Chatbot Methods and State + +| 名称 | 类型 | 说明 | +| --------------------- | ----------------------------------------------- | ------------------------ | +| sendUserMessage | `(params: ChatRequestParams) => Promise` | 发送用户消息 | +| sendSystemMessage | `(message: string) => void` | 发送系统消息 | +| sendAIMessage | `(options?) => Promise` | 手动添加或发送 AI 消息 | +| setMessages | `(messages, mode?) => void` | 替换、前插或追加消息 | +| clearMessages | `() => void` | 清空消息列表 | +| abortChat | `() => Promise` | 中止当前请求 | +| addPrompt | `(prompt: string, autoFocus?: boolean) => void` | 填充输入框 | +| scrollList | `(options?: TdChatListScrollToOptions) => void` | 滚动消息列表 | +| selectFile | `() => void` | 打开文件选择器 | +| regenerate | `(keepVersion?: boolean) => Promise` | 重新生成最后一条 AI 消息 | +| registerMergeStrategy | `(type, handler) => void` | 注册自定义内容合并策略 | +| chatMessageValue | `readonly ChatMessagesData[]` | 当前消息列表 | +| chatStatus | `readonly ChatStatus` | 当前聊天状态 | +| senderLoading | `readonly boolean` | 输入框加载状态 | +| isChatEngineReady | `readonly boolean` | ChatEngine 是否就绪 | + +### Chatbot Slots + +| 名称 | 说明 | +| ----------------------------- | ------------------------ | +| sender-header | 输入框外顶部区域 | +| sender-inner-header | 输入框内顶部区域 | +| sender-input-prefix | 输入框前方区域 | +| sender-textarea | 替换默认输入框 | +| sender-footer-prefix | 输入框左下角区域 | +| sender-actions | 输入框右下角区域 | +| `[message-id]-[content-slot]` | 指定消息内容的自定义插槽 | + +### 共享类型 + +`ChatMessagesData`、`ChatServiceConfigSetter`、`AIMessageContent`、`SSEChunkData` 等协议类型由 `@tdesign/ai-chat-engine` 维护,并由 `@tdesign/web-components-chat/chat-engine` 原样导出。本文档不复制其字段,避免协议升级后产生两套定义。 diff --git a/packages/pro-components/chat/chatbot/_example/basic.tsx b/packages/pro-components/chat/chatbot/_example/basic.tsx index d74ea11c..1fcc3662 100644 --- a/packages/pro-components/chat/chatbot/_example/basic.tsx +++ b/packages/pro-components/chat/chatbot/_example/basic.tsx @@ -454,7 +454,7 @@ export default class BasicChat extends Component { console.log('复制', data); }, suggestion: ({ content }) => { - this.chatRef.current.addPrompt(content.prompt); + if (content.prompt) this.chatRef.current.addPrompt(content.prompt); }, searchResult: ({ content }) => { console.log('searchResult', content); diff --git a/packages/pro-components/chat/chatbot/_example/customMDRender.tsx b/packages/pro-components/chat/chatbot/_example/customMDRender.tsx index 06edfbe0..59151816 100644 --- a/packages/pro-components/chat/chatbot/_example/customMDRender.tsx +++ b/packages/pro-components/chat/chatbot/_example/customMDRender.tsx @@ -126,8 +126,7 @@ const colorText = CherryStream.createSyntaxHook('important', CherryStream.consta }, rule() { // 匹配 !!...!! 语法 - // eslint-disable-next-line no-useless-escape - return { reg: /(\!\!)([^\!]+)\1/g }; + return { reg: /(!{2})([^!]+)\1/g }; }, }); diff --git a/packages/pro-components/chat/chatbot/_example/nostream.tsx b/packages/pro-components/chat/chatbot/_example/nostream.tsx index c917647e..1ce63144 100644 --- a/packages/pro-components/chat/chatbot/_example/nostream.tsx +++ b/packages/pro-components/chat/chatbot/_example/nostream.tsx @@ -141,7 +141,7 @@ export default class BasicChat extends Component { console.log('复制', data); }, suggestion: ({ content }) => { - this.chatRef.current.addPrompt(content.prompt); + if (content.prompt) this.chatRef.current.addPrompt(content.prompt); }, searchResult: ({ content }) => { console.log('searchResult', content); diff --git a/packages/pro-components/chat/chatbot/chat.tsx b/packages/pro-components/chat/chatbot/chat.tsx index 48f4f27e..b1991e9d 100644 --- a/packages/pro-components/chat/chatbot/chat.tsx +++ b/packages/pro-components/chat/chatbot/chat.tsx @@ -7,6 +7,7 @@ import { convertNodeListToVNodes, getSlotNodes } from '@tdesign/web-components-s import { merge } from 'lodash-es'; import { Component, createRef, OmiProps, signal, tag } from 'omi'; +import type { TdChatActionData } from '../chat-action'; import { TdChatActionsName } from '../chat-action'; import { DefaultChatMessageActionsName } from '../chat-action/action'; import { ChatEngine, getMessageContentForCopy, isAIMessage } from '../chat-engine'; @@ -19,7 +20,12 @@ import { type ChatRequestParams, type ChatStatus, } from '../chat-engine'; -import type { TdChatMessageActionName, TdChatMessageProps } from '../chat-message/type'; +import type { + TdChatMessageAction, + TdChatMessageActionData, + TdChatMessageActionName, + TdChatMessageProps, +} from '../chat-message/type'; import { TdChatSenderParams } from '../chat-sender'; import type ChatSender from '../chat-sender/chat-sender'; import { TdAttachmentItem } from '../filecard'; @@ -35,9 +41,8 @@ export default class Chatbot extends Component implements TdChatbot static css = [styles]; static propTypes = { - clearHistory: Boolean, layout: String, - autoSendPrompt: Object, + autoSendPrompt: String, reverse: Boolean, defaultMessages: Array, messageProps: [Object, Function], @@ -48,11 +53,12 @@ export default class Chatbot extends Component implements TdChatbot onMessageChange: Function, onChatReady: Function, onChatAfterSend: Function, + onChatStop: Function, + onChatMessageAction: Function, }; static defaultProps = { autoSendPrompt: '', - clearHistory: false, layout: 'both', reverse: false, defaultMessages: [], @@ -68,7 +74,7 @@ export default class Chatbot extends Component implements TdChatbot public isChatEngineReady = false; - private chatMessages: Omi.SignalValue = signal(undefined); + private chatMessages: Omi.SignalValue = signal([]); private uploadedAttachments: AttachmentItem[] = []; @@ -310,6 +316,14 @@ export default class Chatbot extends Component implements TdChatbot */ private handleStop = () => { this.chatEngine.abortChat(); + this.fire( + 'chatStop', + {}, + { + composed: true, + }, + ); + // 兼容旧版 DOM 事件名,后续主事件统一使用 chatStop。 this.fire( 'chat_stop', {}, @@ -320,10 +334,10 @@ export default class Chatbot extends Component implements TdChatbot }; private handleClickAction = ( - action: Partial, + action: TdChatMessageActionName, opts: { messageProps: TdChatMessageProps; - data?: any; + data?: TdChatActionData; }, ) => { const { messageProps, data } = opts; @@ -331,12 +345,19 @@ export default class Chatbot extends Component implements TdChatbot ...data, message: messageProps.message, }; - if (messageProps?.handleActions?.[action]) { - messageProps.handleActions[action](toData); - } + const handleAction = messageProps?.handleActions?.[action] as ((data: TdChatMessageActionData) => void) | undefined; + handleAction?.(toData as TdChatMessageActionData); + this.fire( + 'chatMessageAction', + { action, data: toData as TdChatMessageActionData }, + { + composed: true, + }, + ); + // 兼容旧版 DOM 事件名,后续主事件统一使用 chatMessageAction。 this.fire( 'chat_message_action', - { action, data: toData }, + { action, data: toData as TdChatMessageActionData }, { composed: true, }, @@ -359,7 +380,13 @@ export default class Chatbot extends Component implements TdChatbot itemProps = merge({}, itemProps, this.props.messageProps(item) || {}); } return ( - + {/* 根据id筛选item应该分配的slot */} {itemSlotNames.map((slotName) => { const str = slotName.replace(RegExp(`^${id}-`), ''); @@ -369,7 +396,7 @@ export default class Chatbot extends Component implements TdChatbot {content.length === 0 || (item.status !== 'complete' && item.status !== 'stop') ? null : ( } handleAction={(action, data) => this.handleClickAction(action, { messageProps: itemProps, @@ -414,8 +441,7 @@ export default class Chatbot extends Component implements TdChatbot // 动态注入插槽需要每次render都更新children beforeRender(): void { - // @ts-ignore - if (this.props?.ignoreAttrs) return; + if ('ignoreAttrs' in this.props && this.props.ignoreAttrs) return; // 使用缓存和差异检测优化DOM转换 this.props.children = convertNodeListToVNodes(this.childNodes); } @@ -425,7 +451,7 @@ export default class Chatbot extends Component implements TdChatbot return (
{this.chatMessageValue && ( - + {this.renderItems()} )} diff --git a/packages/pro-components/chat/chatbot/index.ts b/packages/pro-components/chat/chatbot/index.ts index e2838825..a9c05597 100644 --- a/packages/pro-components/chat/chatbot/index.ts +++ b/packages/pro-components/chat/chatbot/index.ts @@ -1,8 +1,45 @@ import './style/index.js'; import _Chat from './chat'; +import type { + BackBottomParams, + FetchSSEOptions, + Layout, + MetaData, + ModelRoleEnum, + ScrollPosition, + SSEEvent, + TdChatbotApi, + TdChatCodeProps, + TdChatInjectCSS, + TdChatListApi, + TdChatListProps, + TdChatListScrollToOptions, + TdChatMessageActionEvent, + TdChatMessageConfig, + TdChatMessageConfigItem, + TdChatProps, +} from './type'; -export const Chat = _Chat; +export type { + BackBottomParams, + FetchSSEOptions, + Layout, + MetaData, + ModelRoleEnum, + ScrollPosition, + SSEEvent, + TdChatbotApi, + TdChatCodeProps, + TdChatInjectCSS, + TdChatListApi, + TdChatListProps, + TdChatListScrollToOptions, + TdChatMessageActionEvent, + TdChatMessageConfig, + TdChatMessageConfigItem, + TdChatProps, +}; -export * from './type'; +export const Chat = _Chat; export default Chat; diff --git a/packages/pro-components/chat/chatbot/mock/sseService.ts b/packages/pro-components/chat/chatbot/mock/sseService.ts index 97b28382..55393dcc 100644 --- a/packages/pro-components/chat/chatbot/mock/sseService.ts +++ b/packages/pro-components/chat/chatbot/mock/sseService.ts @@ -59,7 +59,6 @@ export class SSEResponse { }, ]; - //@ts-ignore private delay(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } diff --git a/packages/pro-components/chat/chatbot/type.ts b/packages/pro-components/chat/chatbot/type.ts index d5f56049..448581a6 100644 --- a/packages/pro-components/chat/chatbot/type.ts +++ b/packages/pro-components/chat/chatbot/type.ts @@ -2,25 +2,40 @@ import type { StyledProps, TNode } from '@tdesign/web-components-shared/common'; import type { AIMessageContent, + ChatMessageRole, ChatMessagesData, ChatMessageSetterMode, ChatRequestParams, ChatServiceConfigSetter, ChatStatus, } from '../chat-engine'; -import type { TdChatMessageProps } from '../chat-message'; +import type { TdChatMessageActionData, TdChatMessageActionName, TdChatMessageProps } from '../chat-message'; import type { TdChatSenderProps } from '../chat-sender'; export interface TdChatProps extends StyledProps { + /** 聊天内容 */ children?: TNode; - /** 布局模式 */ + /** + * 布局模式 + * @default both + */ layout?: 'single' | 'both'; - /** 倒序渲染 */ + /** + * 倒序渲染 + * @default false + */ reverse?: boolean; /** 消息列表配置(透传至t-chat-list) */ listProps?: TdChatListProps; - /** 消息数据源 */ + /** + * 初始化完成后自动发送的提问 + * @default '' + */ autoSendPrompt?: string; + /** + * 初始消息列表 + * @default [] + */ defaultMessages?: Array; /** 角色消息配置 */ messageProps?: TdChatMessageConfig | ((msg: ChatMessagesData) => TdChatMessageConfigItem); @@ -28,12 +43,32 @@ export interface TdChatProps extends StyledProps { senderProps?: TdChatSenderProps; /** 模型服务配置 */ chatServiceConfig?: ChatServiceConfigSetter; + /** Shadow DOM 样式注入配置 */ + injectCSS?: TdChatInjectCSS; /** 消息内容更新回调 */ onMessageChange?: (e: CustomEvent) => void; /** 消息引擎初始化完成回调 */ - onChatReady?: (e: CustomEvent) => void; + onChatReady?: (e: CustomEvent>) => void; /** 消息发送完回调 */ onChatAfterSend?: (e: CustomEvent) => void; + /** 用户点击停止按钮时触发 */ + onChatStop?: (e: CustomEvent>) => void; + /** 消息操作按钮触发 */ + onChatMessageAction?: (e: CustomEvent) => void; +} + +export interface TdChatMessageActionEvent { + action: TdChatMessageActionName; + data: TdChatMessageActionData; +} + +export interface TdChatInjectCSS { + /** 注入 ChatSender 的 CSS */ + ChatSender?: string; + /** 注入 ChatList 的 CSS */ + chatList?: string; + /** 注入每个 ChatMessage 的 CSS */ + chatItem?: string; } export interface TdChatListScrollToOptions { @@ -71,7 +106,7 @@ export interface TdChatbotApi { * - prepend: 将消息添加到现有消息前面 * - append: 将消息追加到现有消息后面 */ - setMessages: (messages: ChatMessagesData[], mode: ChatMessageSetterMode) => void; + setMessages: (messages: ChatMessagesData[], mode?: ChatMessageSetterMode) => void; /** * 清空消息列表 @@ -140,7 +175,7 @@ export type TdChatMessageConfig = { [key in ModelRoleEnum]?: TdChatMessageConfigItem; }; -export type ScrollPosition = 'top' | 'bottom'; +export type ScrollPosition = NonNullable; export interface TdChatListProps { children?: TNode; @@ -179,18 +214,22 @@ export interface MetaData { [key: string]: any; } -export type ModelRoleEnum = 'assistant' | 'user' | 'system'; +export type ModelRoleEnum = ChatMessageRole; -export type Layout = 'single' | 'both'; +/** @deprecated 使用 `TdChatProps['layout']` */ +export type Layout = NonNullable; +/** @deprecated 旧版 SSE 工具类型,请使用 `@tdesign/ai-chat-engine` 导出的类型 */ export interface FetchSSEOptions { success?: (res: SSEEvent) => void; // 流式数据解析成功回调 fail?: () => void; // 流式请求失败回调 complete?: (isOk: boolean, msg?: string, requestid?: string) => void; // 流式请求完成回调 } +/** @deprecated 旧版 SSE 工具类型,请使用 `SSEChunkData` */ export interface SSEEvent { type: string | null; data: string | null; } +/** @deprecated 使用 `TdChatListScrollToOptions` */ export interface BackBottomParams { - behavior?: 'auto' | 'smooth'; + behavior?: TdChatListScrollToOptions['behavior']; } diff --git a/packages/pro-components/chat/filecard/README.md b/packages/pro-components/chat/filecard/README.md index 0bf0ee42..5807a1bb 100644 --- a/packages/pro-components/chat/filecard/README.md +++ b/packages/pro-components/chat/filecard/README.md @@ -18,18 +18,24 @@ spline: base ### Filecard Props -名称 | 类型 | 默认值 | 说明 | 必传 --- | -- | -- | -- | -- -item | TdAttachmentItem | false | 附件,同 Upload UploadFile | Y -removable | boolean | true | 是否显示删除按钮 | N -onRemove | (item: TdAttachmentItem) => void | - | 附件移除时的回调函数 | N -disabled | Boolean | false | 禁用状态 | N -imageViewer | Boolean | true | 图片预览开关 | N -cardType | `file | image` | file | 卡片类型 | N +| 名称 | 类型 | 默认值 | 说明 | 必传 | +| ----------- | -------------------------------------------- | -------- | ---------------- | ---- | +| item | `TdAttachmentItem` | - | 附件数据 | Y | +| removable | Boolean | `true` | 是否显示删除按钮 | N | +| disabled | Boolean | `false` | 是否禁用 | N | +| imageViewer | Boolean | `true` | 是否启用图片预览 | N | +| cardType | `'file' \| 'image'` | `'file'` | 卡片展示类型 | N | +| onRemove | `(e: CustomEvent) => void` | - | 移除附件时触发 | N | +| onFileClick | `(e: CustomEvent) => void` | - | 点击附件时触发 | N | ## TdAttachmentItem 类型说明 -名称 | 类型 | 默认值 | 说明 | 必传 --- | -- | -- | -- | -- -description | String | - | 文件描述信息 | N -extension | String | - | 文件扩展名 | N -(继承属性) | UploadFile | - | 包含 `name`, `size`, `status` 等基础文件属性 | N + +| 名称 | 类型 | 默认值 | 说明 | 必传 | +| ----------- | ---------------- | ------ | -------------------------------------- | ---- | +| description | String | - | 文件描述信息 | N | +| extension | String | - | 文件扩展名 | N | +| key | String | - | 附件唯一标识 | N | +| fileType | `AttachmentType` | - | 聊天消息中的附件类型 | N | +| (继承属性) | `UploadFile` | - | 继承 tdesign-common 的共享上传文件类型 | N | + +`UploadFile` 的基础字段由 tdesign-common 统一维护。上传状态为 `success`、`fail`、`progress` 或 `waiting`;`TdAttachmentItem.fileType` 则描述聊天消息协议中的文件类别,两者语义不同。 diff --git a/packages/pro-components/chat/filecard/index.ts b/packages/pro-components/chat/filecard/index.ts index 93d0258a..965a560f 100644 --- a/packages/pro-components/chat/filecard/index.ts +++ b/packages/pro-components/chat/filecard/index.ts @@ -1,8 +1,9 @@ import './style/index.js'; import _Filecard from './filecard'; +import type { TdAttachmentItem, TdFileCardProps } from './type'; + +export type { TdAttachmentItem, TdFileCardProps }; export const Filecard = _Filecard; export default Filecard; - -export * from './type'; diff --git a/packages/pro-components/chat/filecard/type.ts b/packages/pro-components/chat/filecard/type.ts index a3b06796..f220c470 100644 --- a/packages/pro-components/chat/filecard/type.ts +++ b/packages/pro-components/chat/filecard/type.ts @@ -1,21 +1,49 @@ -import { type UploadFile } from '@common/js/upload/types'; +import type { UploadFile } from '@common/js/upload/types'; import { StyledProps } from '@tdesign/web-components-shared/common'; -import { AttachmentType } from '../chat-engine'; +import type { AttachmentItem } from '../chat-engine'; -export interface TdAttachmentItem extends UploadFile { +interface TdAttachmentProtocolFields { + fileType?: AttachmentItem['fileType']; + isReference?: AttachmentItem['isReference']; + width?: AttachmentItem['width']; + height?: AttachmentItem['height']; + extension?: AttachmentItem['extension']; + metadata?: AttachmentItem['metadata']; +} + +export interface TdAttachmentItem extends UploadFile, TdAttachmentProtocolFields { + /** 附件唯一标识 */ key?: string; - fileType?: AttachmentType; + /** 文件描述 */ description?: string; - extension?: string; } export interface TdFileCardProps extends StyledProps { + /** 附件数据 */ item: TdAttachmentItem; + /** + * 是否显示删除按钮 + * @default true + */ removable?: boolean; + /** 点击附件时触发 */ onFileClick?: (event: CustomEvent) => void; + /** 移除附件时触发 */ onRemove?: (event: CustomEvent) => void; + /** + * 是否禁用 + * @default false + */ disabled?: boolean; + /** + * 是否启用图片预览 + * @default true + */ imageViewer?: boolean; + /** + * 卡片展示类型 + * @default file + */ cardType?: 'file' | 'image'; } diff --git a/packages/pro-components/chat/index.ts b/packages/pro-components/chat/index.ts index b8c55ed6..d64d9096 100644 --- a/packages/pro-components/chat/index.ts +++ b/packages/pro-components/chat/index.ts @@ -1,16 +1,8 @@ -export type * from './attachments'; export * from './attachments'; -export type * from './chat-action'; export * from './chat-action'; -export type * from './chat-engine'; export * from './chat-engine'; -export type * from './chat-loading'; export * from './chat-loading'; -export type * from './chat-message'; export * from './chat-message'; -export type * from './chat-sender'; export * from './chat-sender'; -export type * from './chatbot'; export * from './chatbot'; -export type * from './filecard'; export * from './filecard'; diff --git a/packages/pro-components/chat/tsconfig.build.json b/packages/pro-components/chat/tsconfig.build.json index 76a3efcd..bc598dab 100644 --- a/packages/pro-components/chat/tsconfig.build.json +++ b/packages/pro-components/chat/tsconfig.build.json @@ -3,7 +3,7 @@ "compilerOptions": { "composite": true, "declaration": true, - "declarationMap": true, + "declarationMap": false, "rootDir": ".", "outDir": "dist", "noEmit": false, diff --git a/packages/tdesign-web-components-chat/vite.config.ts b/packages/tdesign-web-components-chat/vite.config.ts index 4d7afe38..fdc1393f 100644 --- a/packages/tdesign-web-components-chat/vite.config.ts +++ b/packages/tdesign-web-components-chat/vite.config.ts @@ -1,11 +1,8 @@ import { dirname, resolve } from 'path'; import { fileURLToPath } from 'url'; -import { - createLibBuildConfig, - type LibViteOptions, -} from '@tdesign/vite-config/lib'; -import pkg from './package.json'; +import { createLibBuildConfig, type LibViteOptions } from '@tdesign/vite-config/lib'; +import pkg from './package.json' with { type: 'json' }; const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -14,13 +11,16 @@ const libOptions: LibViteOptions = { pkg, packageDir: __dirname, srcDir: resolve(__dirname, '../pro-components/chat'), + // 发布包不包含源码,因此只发布可独立使用的 .d.ts,不生成无法解析的声明映射。 + declarationSourcemap: false, iifeGlobalName: 'TDesignWebComponentsChat', iifeExternals: ['@tdesign/web-components'], iifeGlobals: { '@tdesign/web-components': 'TDesignWebComponents', }, pipeline: { - refreshCommonTypes: false, + // Chat 的公开附件类型间接依赖 common;独立构建时也必须刷新声明,避免 submodule 更新后复用旧缓存。 + refreshCommonTypes: true, requireUiBuilt: true, }, }; diff --git a/packages/tdesign-web-components/vite.config.ts b/packages/tdesign-web-components/vite.config.ts index fa583c87..23f90038 100644 --- a/packages/tdesign-web-components/vite.config.ts +++ b/packages/tdesign-web-components/vite.config.ts @@ -1,11 +1,8 @@ import { dirname, resolve } from 'path'; import { fileURLToPath } from 'url'; -import { - createLibBuildConfig, - type LibViteOptions, -} from '@tdesign/vite-config/lib'; -import pkg from './package.json'; +import { createLibBuildConfig, type LibViteOptions } from '@tdesign/vite-config/lib'; +import pkg from './package.json' with { type: 'json' }; const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -14,6 +11,8 @@ const libOptions: LibViteOptions = { pkg, packageDir: __dirname, srcDir: resolve(__dirname, '../components'), + // 发布包不包含源码,因此只发布可独立使用的 .d.ts,不生成无法解析的声明映射。 + declarationSourcemap: false, generateEntry: true, iifeGlobalName: 'TDesignWebComponents', pipeline: {}, diff --git a/packages/vite-config/package.json b/packages/vite-config/package.json index 4d2e9da1..d87cab10 100644 --- a/packages/vite-config/package.json +++ b/packages/vite-config/package.json @@ -17,7 +17,7 @@ "fast-glob": "^3.3.2", "gray-matter": "^4.0.3", "markdown-it-fence": "^0.1.3", - "rolldown-plugin-dts": "^0.27.13", + "rolldown-plugin-dts": "^0.28.2", "vite-plugin-tdoc": "^2.0.4" }, "peerDependencies": { diff --git a/packages/vite-config/src/lib/config.ts b/packages/vite-config/src/lib/config.ts index 07fda7bc..af810685 100644 --- a/packages/vite-config/src/lib/config.ts +++ b/packages/vite-config/src/lib/config.ts @@ -33,6 +33,7 @@ export interface LibViteOptions { }; packageDir: string; srcDir: string; + declarationSourcemap?: boolean; generateEntry?: boolean; iifeGlobalName: string; iifeExternals?: string[]; @@ -82,7 +83,6 @@ function createEsmConfig(options: LibViteOptions): UserConfig { return { ...createSharedUserConfig(options, monorepoRoot), - oxc: { ...libOxcConfig, ...libDtsOxcConfig }, build: { outDir: resolve(options.packageDir, 'esm'), ...BROWSER_BUILD_TARGET, @@ -94,6 +94,7 @@ function createEsmConfig(options: LibViteOptions): UserConfig { rolldownOptions: { input: collectLibInputs(options.srcDir), external: createLibExternal(options.pkg), + preserveEntrySignatures: 'strict', output: { format: 'es', preserveModules: true, @@ -104,7 +105,35 @@ function createEsmConfig(options: LibViteOptions): UserConfig { }, }, }, - plugins: [...createSharedPlugins(monorepoRoot, options.generateEntry ?? false), createLibDtsPlugin(options.srcDir)], + plugins: createSharedPlugins(monorepoRoot, options.generateEntry ?? false), + }; +} + +function createDtsConfig(options: LibViteOptions): UserConfig { + const monorepoRoot = getWorkspaceRoot(options.packageDir); + + return { + ...createSharedUserConfig(options, monorepoRoot), + oxc: { ...libOxcConfig, ...libDtsOxcConfig }, + build: { + outDir: resolve(options.packageDir, 'esm'), + emptyOutDir: false, + rolldownOptions: { + input: collectLibInputs(options.srcDir), + external: createLibExternal(options.pkg), + preserveEntrySignatures: 'strict', + // 声明必须按源码入口完整生成,不能跟随运行时引用关系摇树。 + treeshake: false, + output: { + format: 'es', + preserveModules: true, + preserveModulesRoot: options.srcDir, + banner: createBanner(options.pkg), + entryFileNames: createPreserveModuleFileName(options.srcDir, monorepoRoot), + }, + }, + }, + plugins: [createComponentStylePlugin(), createLibDtsPlugin(options.srcDir, options.declarationSourcemap ?? true)], }; } @@ -177,6 +206,9 @@ function createEsmIifeBuildPlugin(options: LibViteOptions): Plugin { console.log('[lib-esm-iife-build] esm...'); await build({ configFile: false, ...createEsmConfig(options) }); + console.log('[lib-esm-iife-build] dts...'); + await build({ configFile: false, ...createDtsConfig(options) }); + console.log('[lib-esm-iife-build] iife...'); await build({ configFile: false, ...createIifeConfig(options) }); diff --git a/packages/vite-config/src/lib/dts.ts b/packages/vite-config/src/lib/dts.ts index 5f898a4f..e30b241a 100644 --- a/packages/vite-config/src/lib/dts.ts +++ b/packages/vite-config/src/lib/dts.ts @@ -2,13 +2,15 @@ import { resolve } from 'path'; import { dts } from 'rolldown-plugin-dts'; -/** ESM 构建:Rolldown 直出 .d.ts 到发布目录(与 .js 同目录) */ -export function createLibDtsPlugin(srcDir: string) { +/** 声明构建:只输出 .d.ts 到 ESM 发布目录。 */ +export function createLibDtsPlugin(srcDir: string, sourcemap = true) { return dts({ + generator: 'tsc', tsconfig: resolve(srcDir, 'tsconfig.build.json'), cwd: srcDir, - sourcemap: true, + sourcemap, resolver: 'tsc', + emitDtsOnly: true, }); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f640c06a..a2cfb3a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -87,8 +87,8 @@ catalogs: specifier: ^8.65.0 version: 8.65.0 vite: - specifier: ^8.1.5 - version: 8.1.5 + specifier: ^8.2.2 + version: 8.2.2 vitest: specifier: ^4.1.10 version: 4.1.10 @@ -189,10 +189,10 @@ importers: version: 8.65.0(eslint@10.5.0(jiti@2.6.1))(typescript@6.0.3) vite: specifier: catalog:tooling - version: 8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3) + version: 8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3) vitest: specifier: catalog:tooling - version: 4.1.10(@types/node@22.20.1)(jsdom@19.0.0)(vite@8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3)) + version: 4.1.10(@types/node@22.20.1)(jsdom@19.0.0)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3)) packages/common/docs: {} @@ -380,7 +380,7 @@ importers: version: 14.1.2 autoprefixer: specifier: ^10.5.4 - version: 10.5.4(postcss@8.5.22) + version: 10.5.4(postcss@8.5.26) esbuild: specifier: ^0.28.1 version: 0.28.1 @@ -394,8 +394,8 @@ importers: specifier: ^0.1.3 version: 0.1.3 rolldown-plugin-dts: - specifier: ^0.27.13 - version: 0.27.13(rolldown@1.1.5)(typescript@6.0.3) + specifier: ^0.28.2 + version: 0.28.2(rolldown@1.2.5)(typescript@6.0.3) vite-plugin-tdoc: specifier: ^2.0.4 version: 2.0.4(@types/markdown-it@14.1.2) @@ -621,15 +621,6 @@ packages: conventional-commits-parser: optional: true - '@emnapi/core@1.11.1': - resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} - - '@emnapi/runtime@1.11.1': - resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} - - '@emnapi/wasi-threads@1.2.2': - resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} - '@esbuild/aix-ppc64@0.28.1': resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} engines: {node: '>=18'} @@ -904,12 +895,6 @@ packages: '@mermaid-js/parser@1.2.0': resolution: {integrity: sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==} - '@napi-rs/wasm-runtime@1.1.6': - resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} - peerDependencies: - '@emnapi/core': ^1.7.1 - '@emnapi/runtime': ^1.7.1 - '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -922,8 +907,8 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@oxc-project/types@0.139.0': - resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} + '@oxc-project/types@0.146.0': + resolution: {integrity: sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==} '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} @@ -941,97 +926,98 @@ packages: '@codemirror/state': 6.x.x '@codemirror/view': 6.x.x - '@rolldown/binding-android-arm64@1.1.5': - resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} + '@rolldown/binding-android-arm-eabi@1.2.5': + resolution: {integrity: sha512-DLe/i+l8ynIBY7XEQ191TeZvCoowIGa18R+dIV30GW7DiOtp74i/xX8hs8GUjW5ARV7VZuie3d6AumSmCwbeRA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@rolldown/binding-android-arm64@1.2.5': + resolution: {integrity: sha512-zXcwKlQApYAOELHd8PwKDFkagYF9Wy4e0RJ+0qnzl9Pjnpj75TEG8ufv40p2J7kCEfwZAsNiuzRIyNNMWT38ig==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.1.5': - resolution: {integrity: sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==} + '@rolldown/binding-darwin-arm64@1.2.5': + resolution: {integrity: sha512-dK4QakI42nzWgJT5sm4y4y/O//D4OxM75/cH28RLV+nzIN9AY+YsbuUVrUTjlLjXR6vpyxFbSsbmNuJ6BP9sww==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.1.5': - resolution: {integrity: sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==} + '@rolldown/binding-darwin-x64@1.2.5': + resolution: {integrity: sha512-fqSALaUu1Wjd1nK2uW2kJDWdLCc8lx1IcY+MTY26Aurfdx19anlzhqXOgCFbBFQnlFDTn4TC1/7Nz4Bl2mLP3A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.1.5': - resolution: {integrity: sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==} + '@rolldown/binding-freebsd-x64@1.2.5': + resolution: {integrity: sha512-/vCnNxlkxs9tKxNDcyWUePpJ/PgTzxIaVhoM5SmG8UV+GR/IcPam4VYxi7GIMo7PSDuNqlJqvprqii9NqqVCMw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.1.5': - resolution: {integrity: sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==} + '@rolldown/binding-linux-arm-gnueabihf@1.2.5': + resolution: {integrity: sha512-abk0NLA519LxRCszmbE0jYKuQ9YPocOXTiOXOo6Yr+YAT95VH+PtqYAjOJvGKt3viEd/x4qzabAlwd5bHOOARg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.1.5': - resolution: {integrity: sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==} + '@rolldown/binding-linux-arm64-gnu@1.2.5': + resolution: {integrity: sha512-Y7eALiJ8lr0M2HH103Js+g7V34wf6snlpZLAsHI90uLhr3PVlNsbFVAXJC9d/V6BnPyKtpSwI+NcB/RLxsQxuA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.1.5': - resolution: {integrity: sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==} + '@rolldown/binding-linux-arm64-musl@1.2.5': + resolution: {integrity: sha512-xMvZgnbZg4YVnR/AX2b3oOPDTFYJvUVaJg5FedA/LuvexAtXibZQej4cnTkw3rjsJ/ggUROB64TdtETiim+FYA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.1.5': - resolution: {integrity: sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==} + '@rolldown/binding-linux-ppc64-gnu@1.2.5': + resolution: {integrity: sha512-GRjeqTUDHTo5GwntsLaAMcBahG3nlpjftXWZLN73HiYQlhwEowvarFgQnRnQZtIp4keXX7quXFbG38uPZBa2EA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.1.5': - resolution: {integrity: sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==} + '@rolldown/binding-linux-s390x-gnu@1.2.5': + resolution: {integrity: sha512-vLNTR45F2Uwc8AufkNXPmB4VliaXs+FvcheEogIzOXzO4l+LzieXF5A/TWxLy5HtqpsRCHUfd0lPVrrdgXdLHQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.1.5': - resolution: {integrity: sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==} + '@rolldown/binding-linux-x64-gnu@1.2.5': + resolution: {integrity: sha512-Mgj59/HTuYeK9Gz2MA+mBWKnHsAgkBSec15ZMb1st3oIfFbX7gCjOae7GydHhzcyQi9Z/7M1QuN9bR3oFqF0jQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.1.5': - resolution: {integrity: sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==} + '@rolldown/binding-linux-x64-musl@1.2.5': + resolution: {integrity: sha512-mY8AP0/ichsbhAxGnLa3d3+MwV0EfgrPND2bplI3Ym8T6R2pJ0N87bvrKVwNXmdy3jnr6eQBecdqx/HMknBmpA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.1.5': - resolution: {integrity: sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==} + '@rolldown/binding-openharmony-arm64@1.2.5': + resolution: {integrity: sha512-8SLssA2oweAxyRgDp789ACfRb/3P+zNRJpzZxSizxF9m8NUDQ4+3xjo8ttjhVGGw6Qxb70oZiEtIjaKikCO7Yw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.1.5': - resolution: {integrity: sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [wasm32] - - '@rolldown/binding-win32-arm64-msvc@1.1.5': - resolution: {integrity: sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==} + '@rolldown/binding-win32-arm64-msvc@1.2.5': + resolution: {integrity: sha512-vGbruD5zquhoc8D9SViXgN2FBJtNdTyQ4DtG+SWiEGlJiAzoKcZ2xp+xuXCffhubVdt0NJlTZqkeRuERy7g8Cw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.1.5': - resolution: {integrity: sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==} + '@rolldown/binding-win32-x64-msvc@1.2.5': + resolution: {integrity: sha512-e/SXpgISz+IoqVcSSI0rx/d/he8zqLex+/rCWpnHpmVfmPIUjag9H6P7zotf0gJHwPUhQxZ/mF8tr6acebT9yw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -1070,9 +1056,6 @@ packages: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} - '@tybys/wasm-util@0.10.3': - resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} - '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -1345,130 +1328,140 @@ packages: '@vue/shared@3.5.40': resolution: {integrity: sha512-WxnBtruIqOoV3rA4jeKDWzrYI5h7Cp4+pjwDi8kWGHz+IslhiN+wguLVVhtv2l8VoU02rzDCVfDjgCl1lNpZVg==} - '@yuku-codegen/binding-darwin-arm64@0.7.4': - resolution: {integrity: sha512-fjkATm+fg4r6Ss8o82u3j33PfIqhSs4A0WEEw9kOwhMx/ui/RQ0ZAsCtF6e7UG2CWGOGXAJspLlfk2tr3rjjKQ==} + '@yuku-codegen/binding-android-arm64@0.8.7': + resolution: {integrity: sha512-C/0zV5IhgVdYhGJTwrY0v8dknxlhiKwtVJkMUaexu9/QvRmzlV4vfU3hZlUSgqc2BxQHntL1mCVbDq8j0FRFDw==} + cpu: [arm64] + os: [android] + + '@yuku-codegen/binding-darwin-arm64@0.8.7': + resolution: {integrity: sha512-/u+REDMI4a0/lsJXTM4c53/w31OGZLOReZIyg62uhgLs0kc8NHsj/nOcxTdlQjq5gi0zhdkccD9LaLTXcdzPvw==} cpu: [arm64] os: [darwin] - '@yuku-codegen/binding-darwin-x64@0.7.4': - resolution: {integrity: sha512-Hj0KvHpS1RJY/bgM3BADzmXXkKO3+bq3M8bMq4b0j0LsVi1SeWYpD/hJLJFwHeNMS+jO4vlZ343yjb4DEb9XXQ==} + '@yuku-codegen/binding-darwin-x64@0.8.7': + resolution: {integrity: sha512-sMMzFOwCo4WXR+/6zIBThOocSC50iIIZZdfiIDbaLvj0Ax/rWt/iavyfEAqajyvzydLyCqR/ZItdLWSRlu1umw==} cpu: [x64] os: [darwin] - '@yuku-codegen/binding-freebsd-x64@0.7.4': - resolution: {integrity: sha512-GLKBZvqVFvC1bvNPoPZRj0UxUaAZZKCzb8IPNyvRhXesOk+Af9UbhbVPwx9Do4o2AVf6R5FPzyRWWIihQdCp+A==} + '@yuku-codegen/binding-freebsd-x64@0.8.7': + resolution: {integrity: sha512-MpdpKXix9P+Y1rKgjvcNeNtGjXeL1CmttNhYINrWls8kRpm4xM/oBGTmn6w7to8lAlwj5jm8q03dQPl5mRv4Qw==} cpu: [x64] os: [freebsd] - '@yuku-codegen/binding-linux-arm-gnu@0.7.4': - resolution: {integrity: sha512-CAjbJexBJUqHgIPgOCJO7EYRnFluNLt5VD3jNS40wmsNZqa04HbewVVcgfmzfzuBhjX6ookntLDG3lWieyTAVw==} + '@yuku-codegen/binding-linux-arm-gnu@0.8.7': + resolution: {integrity: sha512-rr1srFLlPAmC1vtxfc9C1YLDe3iH09YjfSeeIidBqKhzx1MATjOAq4mjlRUOnhr/L27MotWIYOFKwVsd5JZFOg==} cpu: [arm] os: [linux] libc: [glibc] - '@yuku-codegen/binding-linux-arm-musl@0.7.4': - resolution: {integrity: sha512-HQMuKBltnKFUqhUh8wNiivd76coRwDngdCxbcAULlatAlc2OXo8L6jLTkVnNeUuOw9JYzSq9LY2/7zvrg63Ddg==} + '@yuku-codegen/binding-linux-arm-musl@0.8.7': + resolution: {integrity: sha512-eAufXh8qBRpiSO6ueaMDL+yyoXIGLhpUce72YbcACtZU2qhExwBIJyEtQf5kH2Ki0X2aqkSjSfog4OPtKXan3Q==} cpu: [arm] os: [linux] libc: [musl] - '@yuku-codegen/binding-linux-arm64-gnu@0.7.4': - resolution: {integrity: sha512-cnU7ZVxK/Oq/TIS2iq56rouy1dqnLYgWR2puWcrxGCtmbdxiMISANYhI5t2tMLzTGZMyhawM2zYlyI+gnpBupQ==} + '@yuku-codegen/binding-linux-arm64-gnu@0.8.7': + resolution: {integrity: sha512-gw4w6wPoHObBrdIC4duVWLmJOvpdE25j5D7yrM5mACNlK4klRz/lv8hK+ssQk9EJHBgZjSaqZIJVFgqNYbfv7A==} cpu: [arm64] os: [linux] libc: [glibc] - '@yuku-codegen/binding-linux-arm64-musl@0.7.4': - resolution: {integrity: sha512-NyuabTumcxPtZv/Q+pMVvrcKxLn1SPcpdBGtekVJz7JwI36SuExTq4IG4EZsk7YDmFKP8wDEvmKYOpV/a8Lwhw==} + '@yuku-codegen/binding-linux-arm64-musl@0.8.7': + resolution: {integrity: sha512-L68N6Y4XkqcIaKo3Ra88JEvBEH4AHff44A4INcrxeVWZ8CZtu2tCpfVxe3hR8qQQMcvBSQlDn24KpkCKEhVvfA==} cpu: [arm64] os: [linux] libc: [musl] - '@yuku-codegen/binding-linux-x64-gnu@0.7.4': - resolution: {integrity: sha512-w3EnCLPD2vpJw0F+0qVV/1KSOAw4SgzjbGUbbwXUh9w5Kxo1Hdc3mN+/Nvk50oA6cCbSOCEaILnPHXPCauArvg==} + '@yuku-codegen/binding-linux-x64-gnu@0.8.7': + resolution: {integrity: sha512-dzyAbltJmf3Cqlb8HcFuYIf5Yn0fl1vTr3XJ9HiVNNvOlhqPSArOqtw9vI1p6/VTXTjrMLXlU+s+/kNHiIy/Cw==} cpu: [x64] os: [linux] libc: [glibc] - '@yuku-codegen/binding-linux-x64-musl@0.7.4': - resolution: {integrity: sha512-FXKQlFjDM8FxqJ/TncAni7e7JyaXIB3Hv6boApxSs5ZUlvqP4TbrjYVk3mYDQt6xQAE/kEHplxM6m5SKx5sfRg==} + '@yuku-codegen/binding-linux-x64-musl@0.8.7': + resolution: {integrity: sha512-Otw4MH3404q0Bbvl+YTdW9aoUV5vXmUw8260bWvt1XlaoIX/ceSgI4ygheRDMfBPoHt6FDayQaO9OLVUZAgkFA==} cpu: [x64] os: [linux] libc: [musl] - '@yuku-codegen/binding-win32-arm64@0.7.4': - resolution: {integrity: sha512-rWr899KEvZIWMx9yUXQl4i90OGIs4gaw4X1UsS2rxsI3qnp8acLIVKI3N5WDqaertkW10crDRZvIxxyw7kTMTQ==} + '@yuku-codegen/binding-win32-arm64@0.8.7': + resolution: {integrity: sha512-qo/jyrzryiBuKEsFiuWaBCBe3tRMynQ0qFWFgOEjcCMQeZfBm+wKiVEUEFXXLc7bh8YezguAWp0Mtnhq4ARNyA==} cpu: [arm64] os: [win32] - '@yuku-codegen/binding-win32-x64@0.7.4': - resolution: {integrity: sha512-3Olgmkd5rDrIN9g7wJFMRRC9jub5zAwiQOtwOVhvNe/nZE/rSufFRa7vrFupqSCQml+Zxbcy9npzo3Qne3rA2A==} + '@yuku-codegen/binding-win32-x64@0.8.7': + resolution: {integrity: sha512-D5lDsVDx6m00E6bWySlWdH72Ca4TPSaphDqB6QjU6MpuNLIJqoGoatYyq2rOmBE8Zv/kunot/o58KGL03P3eiA==} cpu: [x64] os: [win32] - '@yuku-parser/binding-darwin-arm64@0.7.4': - resolution: {integrity: sha512-rUetRGukIlPOkDCy+Fo0YTee66n9A04XRQMONptbemWSU27CCV6RDj56+4ne4eSE4gJ0139RWUfbqMtt744pWQ==} + '@yuku-parser/binding-android-arm64@0.8.7': + resolution: {integrity: sha512-eGKYiUDX7Y0V7tDTmg+JTVnXnjMqfXXsorZ+EDf5kxwchQ3Or1HS14MzI2fw+jFhHR85fCWt+mtX33Yao73hIQ==} + cpu: [arm64] + os: [android] + + '@yuku-parser/binding-darwin-arm64@0.8.7': + resolution: {integrity: sha512-Re0RHelKLnjEURulY2/KxW+Ngb8zuNA4BRZuMwgGQNzVumT6u4U2N2hc01oeYVNVof0i7GrXE4UCNBgbpRRnjQ==} cpu: [arm64] os: [darwin] - '@yuku-parser/binding-darwin-x64@0.7.4': - resolution: {integrity: sha512-9bHrGQUot2vWTg0YTdyIBHGd38fy2BSQH1WaqUDVuNqSn7HffrTUzWOgbaWRNd5GTOvDdrt9SDZIG7nfqzeBtg==} + '@yuku-parser/binding-darwin-x64@0.8.7': + resolution: {integrity: sha512-Hn8DROtQkjlA1ACbPgj4a7eP9IuVOI504oiTwpkWPbpaDWD9KdmnVYCqW+1LfenNK/g7O9NhWGpXEdaCNX7lIA==} cpu: [x64] os: [darwin] - '@yuku-parser/binding-freebsd-x64@0.7.4': - resolution: {integrity: sha512-159565OJ/LR6cCP781nH8DxB5GqlqqWk3uyOLZIznQhsj9zeht4X7+jz9IQH1l/TUio+ojEXf8yt2+DJrN+QVw==} + '@yuku-parser/binding-freebsd-x64@0.8.7': + resolution: {integrity: sha512-bAP2OV8wRuzplX/jYxv9+vvqQT8JxyNphI8fLfXGL054Xs+4/J5u33cIm3y4rxY8rdoLmmdiJs2Tq7r7lrDRfA==} cpu: [x64] os: [freebsd] - '@yuku-parser/binding-linux-arm-gnu@0.7.4': - resolution: {integrity: sha512-j3s3LJxEbOyP58hmzuXpJlKzgxaswuOTu8nAbDpE119b5W3gP1SW+HndLscGUOACpyMdH5WJ6gBHRxq0HCRVBw==} + '@yuku-parser/binding-linux-arm-gnu@0.8.7': + resolution: {integrity: sha512-kTYwJQQgmZeAWdDIWabiReIZMpmfLueIj1tCmjStUtFGhR1Z0qwxonKVfUC4N7h/VhGGzLZ//7O1kgt1QKqgCg==} cpu: [arm] os: [linux] libc: [glibc] - '@yuku-parser/binding-linux-arm-musl@0.7.4': - resolution: {integrity: sha512-PUpHPmvWIDxhYTS5oah08RQ28t6dlFBxRPJcftS6HgquiPsm/e0gL5vKwPJpyjaPBHzRH61IAUDDfrRe8iFs8g==} + '@yuku-parser/binding-linux-arm-musl@0.8.7': + resolution: {integrity: sha512-uL4jE8HPT2BLlxAXyD10LqgPuXa9eDa0BKpCdSANmzIJghq/2eZo3/gQNtaxPZMupWoxjYzSad9IXrwu7aYPXQ==} cpu: [arm] os: [linux] libc: [musl] - '@yuku-parser/binding-linux-arm64-gnu@0.7.4': - resolution: {integrity: sha512-Hi3w0et5mu3i7S+qE0UgOev4RqJ/U9DW8xn79t4nttiICYCx3NveC0Goo78uqzxttsDI3hfRY43lrrF26svqcw==} + '@yuku-parser/binding-linux-arm64-gnu@0.8.7': + resolution: {integrity: sha512-3gVN4pWSKZmXiNX7cU164dR9MPvesCHnlH6nPfpK+yQsCuYphjKKplcb4SnZBrhiqmXbgb2HR0c2TS0IZUPhgA==} cpu: [arm64] os: [linux] libc: [glibc] - '@yuku-parser/binding-linux-arm64-musl@0.7.4': - resolution: {integrity: sha512-i073u4ENL9DJeWBRKioRCz8i5hg6EmUcH89eH1lts9f9AFPA1GphODwK6OXOXUbpi2AwZ1deFIUWgLGP2mdmmA==} + '@yuku-parser/binding-linux-arm64-musl@0.8.7': + resolution: {integrity: sha512-S0mwfEjoLpxzXeZw802Wa4RaELsQiPtWqG6INcy8j4GtvNFtl4LCX3eGO1XLn9pyLAISLzTRyU3zUCBUPin8lg==} cpu: [arm64] os: [linux] libc: [musl] - '@yuku-parser/binding-linux-x64-gnu@0.7.4': - resolution: {integrity: sha512-j5pt0LyDGxCzfoqRTR3cmMG21+bgSxIufAzJXFOWXkbg/22Ih51eGEsbInnSD5Q9FvJ3ooIn/jfok0dBdhudnA==} + '@yuku-parser/binding-linux-x64-gnu@0.8.7': + resolution: {integrity: sha512-lnbWdPmerE5D1uH1G4IEZKnPzCrWCStRGrtgpSIe1RibAo5bZIjDbbbPYXmMHCEh4F+x/JaJpElh26a3r+BPbg==} cpu: [x64] os: [linux] libc: [glibc] - '@yuku-parser/binding-linux-x64-musl@0.7.4': - resolution: {integrity: sha512-RR1hNhrSpv3FanLM6u5uD+9CYA9IM8U3uGscgvKKV77gtj7ttO4UubpwN7vcx1KknoEIQHKJFPVKoeVy+avf6w==} + '@yuku-parser/binding-linux-x64-musl@0.8.7': + resolution: {integrity: sha512-769uwndMvMzUvATWbAcEvyLHKA+DzhHSCl/obBUrRdYfRo26yxui6S8y3z7uJ+Naup7UKrDxrpK7OnQkxkl9KQ==} cpu: [x64] os: [linux] libc: [musl] - '@yuku-parser/binding-win32-arm64@0.7.4': - resolution: {integrity: sha512-1xhYwOLo9TjppHHwNYi3X/dGgOvnj9xh62jpgP4U8nEtTGA70NtJDCkN45pRQdU3B6/U7oQj1T4esP3aFJg6BA==} + '@yuku-parser/binding-win32-arm64@0.8.7': + resolution: {integrity: sha512-mEB/9PlaAkisJ6KWGz0zvywXoU6+80dTlR2LwS7s/jcXXoU6fm2+sitBZXtqu3+Q4DcDgPxM45uWMCzPs0TSRw==} cpu: [arm64] os: [win32] - '@yuku-parser/binding-win32-x64@0.7.4': - resolution: {integrity: sha512-HonZAapmSKusxLZPnU9WrMzAUdPSBJliGw3CSkA9Er/aq15STEOEy9SOsVGvj4maBv95EmWxt2LThHXnFnGfNg==} + '@yuku-parser/binding-win32-x64@0.8.7': + resolution: {integrity: sha512-8vNB2DP0ou61nGb8tc/qfi41gfyDXz1MHr2zqL3nR+cJ6CEbiuWV/l/a/vv151gCgiZLLAyGkQGENpozdg716w==} cpu: [x64] os: [win32] - '@yuku-toolchain/types@0.7.4': - resolution: {integrity: sha512-iUFXr+UnUJjzVLNI6GIv07poi9NwcG5hTBJSheJh3SdpkYpIjCl9kAGe7dbJMHn5sXeceCL4H12pKa0b6pkouQ==} + '@yuku-toolchain/types@0.8.7': + resolution: {integrity: sha512-2Z53dNxAJL6UvFoIrDZvYf3zlO8s4VJK4O2hhaB4mXVwwpX/7ajtss3cmfqKvamlNLWyt9FSWs4eoYdlbxpnHA==} abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} @@ -2691,78 +2684,78 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lightningcss-android-arm64@1.32.0: - resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.32.0: - resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.32.0: - resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.32.0: - resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.32.0: - resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.32.0: - resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [glibc] - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [musl] - lightningcss-linux-x64-gnu@1.32.0: - resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [glibc] - lightningcss-linux-x64-musl@1.32.0: - resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [musl] - lightningcss-win32-arm64-msvc@1.32.0: - resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.32.0: - resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.32.0: - resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} engines: {node: '>= 12.0.0'} lilconfig@3.1.3: @@ -2958,6 +2951,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@3.3.18: + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -3201,6 +3199,10 @@ packages: resolution: {integrity: sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.26: + resolution: {integrity: sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==} + engines: {node: ^10 || ^12 || >=14} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -3318,13 +3320,13 @@ packages: robust-predicates@3.0.3: resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} - rolldown-plugin-dts@0.27.13: - resolution: {integrity: sha512-DeVZJbbB0ajp5q6vABqC8ZCJzxftlxbiV60Bk96GFdQaysGVpgTTVjQu0lUt4Lb+aRCtejfOixtQKDRol7IuVQ==} - engines: {node: ^22.18.0 || >=24.11.0} + rolldown-plugin-dts@0.28.2: + resolution: {integrity: sha512-U0Ng45ZaESZ7rJtQtgCWkJYCpMgH42yIj3xv9HGAsh/dJ8XBhjI4lcqh4NOWx8+CAxoY2HWg8VYINML2yE9A5A==} + engines: {node: ^22.18.0 || ^24.11.0 || >=26.0.0} peerDependencies: '@typescript/native-preview': '*' '@volar/typescript': ~2.4.0 - rolldown: ^1.0.0 + rolldown: ^1.2.0 typescript: ^5.0.0 || ^6.0.0 || ~7.0.0 vue-tsc: ~3.2.0 || ~3.3.0 peerDependenciesMeta: @@ -3337,8 +3339,8 @@ packages: vue-tsc: optional: true - rolldown@1.1.5: - resolution: {integrity: sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==} + rolldown@1.2.5: + resolution: {integrity: sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -3617,9 +3619,6 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsx@4.23.1: resolution: {integrity: sha512-GQHnkIfxyx1wYCOS/wonik5MVRZU9hi1TEZmzGZSCJB1y9YgoZ8H6itNE/u4suE+yLmOzuE4E5S4TZ/ZX2wcWQ==} engines: {node: '>=18.0.0'} @@ -3704,13 +3703,13 @@ packages: vite-plugin-tdoc@2.0.4: resolution: {integrity: sha512-KKoEvlhf78opGCb+WjbOc6TRkzqOEm6rLMmJL9POh8OEa6jOCETs1k81TAaPLaIxuoJxqE4k6IAMchV60XoKpw==} - vite@8.1.5: - resolution: {integrity: sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==} + vite@8.2.2: + resolution: {integrity: sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.3.0 + '@vitejs/devtools': ^0.4.0 || ^0.5.0 esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 @@ -3923,14 +3922,14 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yuku-ast@0.7.4: - resolution: {integrity: sha512-Pn6e7uZOBczeJ+JIiPGtD4aw6eRflzKrZJmAdeg092RxM9tQtvAkZAbEoknNgYmsB6dGYESvXPQcUE7Nu8ai7Q==} + yuku-ast@0.8.7: + resolution: {integrity: sha512-h6+4bDfyootiMB9vckk5uKo5r5j0GHrkr17FQTDNfEsFT3DWlN9uu1HJwQwc64pgmLCI945fWM3lbTIqxjT3GQ==} - yuku-codegen@0.7.4: - resolution: {integrity: sha512-bLdC5yzvn507PtU7+kB4CMBLfnvKW1N2m26Vpl1q4Os+FLROnkKTThM7g+clVb+9tHaOlcc6gqQ+rNBY8L/Dxw==} + yuku-codegen@0.8.7: + resolution: {integrity: sha512-adwDZSh8oVDzhE6Du9PwVWxcOxeV0e2EVhUuMKWfhSY4wkrDq9eqixlxFF3l/XGUV1E7UFzhpz9393MUumkyNw==} - yuku-parser@0.7.4: - resolution: {integrity: sha512-HveMyhZPQQfR4z3xskXv5hHJW9g0KIESZW6JvUZv7Jn52FfMFUhCYL77KHBtnWGFti0KrKeTHMZVTY5AUVgFAA==} + yuku-parser@0.8.7: + resolution: {integrity: sha512-vRD9nwt4L3aYpxNqeSC4WqLv58xrXef0Ong1Mc45CTXTIpvLafx7JO05sczmQZwdLEZvywrLOGdNC5+Rp5N1BQ==} zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} @@ -4279,22 +4278,6 @@ snapshots: optionalDependencies: conventional-commits-parser: 6.4.0 - '@emnapi/core@1.11.1': - dependencies: - '@emnapi/wasi-threads': 1.2.2 - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.11.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@emnapi/wasi-threads@1.2.2': - dependencies: - tslib: 2.8.1 - optional: true - '@esbuild/aix-ppc64@0.28.1': optional: true @@ -4507,13 +4490,6 @@ snapshots: '@chevrotain/types': 11.1.2 optional: true - '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': - dependencies: - '@emnapi/core': 1.11.1 - '@emnapi/runtime': 1.11.1 - '@tybys/wasm-util': 0.10.3 - optional: true - '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4526,7 +4502,7 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@oxc-project/types@0.139.0': {} + '@oxc-project/types@0.146.0': {} '@pkgjs/parseargs@0.11.0': optional: true @@ -4541,53 +4517,49 @@ snapshots: '@codemirror/state': 6.7.1 '@codemirror/view': 6.43.6 - '@rolldown/binding-android-arm64@1.1.5': + '@rolldown/binding-android-arm-eabi@1.2.5': optional: true - '@rolldown/binding-darwin-arm64@1.1.5': + '@rolldown/binding-android-arm64@1.2.5': optional: true - '@rolldown/binding-darwin-x64@1.1.5': + '@rolldown/binding-darwin-arm64@1.2.5': optional: true - '@rolldown/binding-freebsd-x64@1.1.5': + '@rolldown/binding-darwin-x64@1.2.5': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.1.5': + '@rolldown/binding-freebsd-x64@1.2.5': optional: true - '@rolldown/binding-linux-arm64-gnu@1.1.5': + '@rolldown/binding-linux-arm-gnueabihf@1.2.5': optional: true - '@rolldown/binding-linux-arm64-musl@1.1.5': + '@rolldown/binding-linux-arm64-gnu@1.2.5': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.1.5': + '@rolldown/binding-linux-arm64-musl@1.2.5': optional: true - '@rolldown/binding-linux-s390x-gnu@1.1.5': + '@rolldown/binding-linux-ppc64-gnu@1.2.5': optional: true - '@rolldown/binding-linux-x64-gnu@1.1.5': + '@rolldown/binding-linux-s390x-gnu@1.2.5': optional: true - '@rolldown/binding-linux-x64-musl@1.1.5': + '@rolldown/binding-linux-x64-gnu@1.2.5': optional: true - '@rolldown/binding-openharmony-arm64@1.1.5': + '@rolldown/binding-linux-x64-musl@1.2.5': optional: true - '@rolldown/binding-wasm32-wasi@1.1.5': - dependencies: - '@emnapi/core': 1.11.1 - '@emnapi/runtime': 1.11.1 - '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + '@rolldown/binding-openharmony-arm64@1.2.5': optional: true - '@rolldown/binding-win32-arm64-msvc@1.1.5': + '@rolldown/binding-win32-arm64-msvc@1.2.5': optional: true - '@rolldown/binding-win32-x64-msvc@1.1.5': + '@rolldown/binding-win32-x64-msvc@1.2.5': optional: true '@rolldown/pluginutils@1.0.1': {} @@ -4633,11 +4605,6 @@ snapshots: '@tootallnate/once@2.0.0': {} - '@tybys/wasm-util@0.10.3': - dependencies: - tslib: 2.8.1 - optional: true - '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -4944,13 +4911,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.1 - '@vitest/mocker@4.1.10(vite@8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3))': + '@vitest/mocker@4.1.10(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3))': dependencies: '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3) + vite: 8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3) '@vitest/pretty-format@4.1.10': dependencies: @@ -5036,73 +5003,79 @@ snapshots: '@vue/shared@3.5.40': {} - '@yuku-codegen/binding-darwin-arm64@0.7.4': + '@yuku-codegen/binding-android-arm64@0.8.7': optional: true - '@yuku-codegen/binding-darwin-x64@0.7.4': + '@yuku-codegen/binding-darwin-arm64@0.8.7': optional: true - '@yuku-codegen/binding-freebsd-x64@0.7.4': + '@yuku-codegen/binding-darwin-x64@0.8.7': optional: true - '@yuku-codegen/binding-linux-arm-gnu@0.7.4': + '@yuku-codegen/binding-freebsd-x64@0.8.7': optional: true - '@yuku-codegen/binding-linux-arm-musl@0.7.4': + '@yuku-codegen/binding-linux-arm-gnu@0.8.7': optional: true - '@yuku-codegen/binding-linux-arm64-gnu@0.7.4': + '@yuku-codegen/binding-linux-arm-musl@0.8.7': optional: true - '@yuku-codegen/binding-linux-arm64-musl@0.7.4': + '@yuku-codegen/binding-linux-arm64-gnu@0.8.7': optional: true - '@yuku-codegen/binding-linux-x64-gnu@0.7.4': + '@yuku-codegen/binding-linux-arm64-musl@0.8.7': optional: true - '@yuku-codegen/binding-linux-x64-musl@0.7.4': + '@yuku-codegen/binding-linux-x64-gnu@0.8.7': optional: true - '@yuku-codegen/binding-win32-arm64@0.7.4': + '@yuku-codegen/binding-linux-x64-musl@0.8.7': optional: true - '@yuku-codegen/binding-win32-x64@0.7.4': + '@yuku-codegen/binding-win32-arm64@0.8.7': optional: true - '@yuku-parser/binding-darwin-arm64@0.7.4': + '@yuku-codegen/binding-win32-x64@0.8.7': optional: true - '@yuku-parser/binding-darwin-x64@0.7.4': + '@yuku-parser/binding-android-arm64@0.8.7': optional: true - '@yuku-parser/binding-freebsd-x64@0.7.4': + '@yuku-parser/binding-darwin-arm64@0.8.7': optional: true - '@yuku-parser/binding-linux-arm-gnu@0.7.4': + '@yuku-parser/binding-darwin-x64@0.8.7': optional: true - '@yuku-parser/binding-linux-arm-musl@0.7.4': + '@yuku-parser/binding-freebsd-x64@0.8.7': optional: true - '@yuku-parser/binding-linux-arm64-gnu@0.7.4': + '@yuku-parser/binding-linux-arm-gnu@0.8.7': optional: true - '@yuku-parser/binding-linux-arm64-musl@0.7.4': + '@yuku-parser/binding-linux-arm-musl@0.8.7': optional: true - '@yuku-parser/binding-linux-x64-gnu@0.7.4': + '@yuku-parser/binding-linux-arm64-gnu@0.8.7': optional: true - '@yuku-parser/binding-linux-x64-musl@0.7.4': + '@yuku-parser/binding-linux-arm64-musl@0.8.7': optional: true - '@yuku-parser/binding-win32-arm64@0.7.4': + '@yuku-parser/binding-linux-x64-gnu@0.8.7': optional: true - '@yuku-parser/binding-win32-x64@0.7.4': + '@yuku-parser/binding-linux-x64-musl@0.8.7': optional: true - '@yuku-toolchain/types@0.7.4': {} + '@yuku-parser/binding-win32-arm64@0.8.7': + optional: true + + '@yuku-parser/binding-win32-x64@0.8.7': + optional: true + + '@yuku-toolchain/types@0.8.7': {} abab@2.0.6: {} @@ -5183,13 +5156,13 @@ snapshots: asynckit@0.4.0: {} - autoprefixer@10.5.4(postcss@8.5.22): + autoprefixer@10.5.4(postcss@8.5.26): dependencies: browserslist: 4.28.7 caniuse-lite: 1.0.30001806 fraction.js: 5.3.4 picocolors: 1.1.1 - postcss: 8.5.22 + postcss: 8.5.26 postcss-value-parser: 4.2.0 balanced-match@1.0.2: {} @@ -6425,54 +6398,54 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lightningcss-android-arm64@1.32.0: + lightningcss-android-arm64@1.33.0: optional: true - lightningcss-darwin-arm64@1.32.0: + lightningcss-darwin-arm64@1.33.0: optional: true - lightningcss-darwin-x64@1.32.0: + lightningcss-darwin-x64@1.33.0: optional: true - lightningcss-freebsd-x64@1.32.0: + lightningcss-freebsd-x64@1.33.0: optional: true - lightningcss-linux-arm-gnueabihf@1.32.0: + lightningcss-linux-arm-gnueabihf@1.33.0: optional: true - lightningcss-linux-arm64-gnu@1.32.0: + lightningcss-linux-arm64-gnu@1.33.0: optional: true - lightningcss-linux-arm64-musl@1.32.0: + lightningcss-linux-arm64-musl@1.33.0: optional: true - lightningcss-linux-x64-gnu@1.32.0: + lightningcss-linux-x64-gnu@1.33.0: optional: true - lightningcss-linux-x64-musl@1.32.0: + lightningcss-linux-x64-musl@1.33.0: optional: true - lightningcss-win32-arm64-msvc@1.32.0: + lightningcss-win32-arm64-msvc@1.33.0: optional: true - lightningcss-win32-x64-msvc@1.32.0: + lightningcss-win32-x64-msvc@1.33.0: optional: true - lightningcss@1.32.0: + lightningcss@1.33.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.32.0 - lightningcss-darwin-arm64: 1.32.0 - lightningcss-darwin-x64: 1.32.0 - lightningcss-freebsd-x64: 1.32.0 - lightningcss-linux-arm-gnueabihf: 1.32.0 - lightningcss-linux-arm64-gnu: 1.32.0 - lightningcss-linux-arm64-musl: 1.32.0 - lightningcss-linux-x64-gnu: 1.32.0 - lightningcss-linux-x64-musl: 1.32.0 - lightningcss-win32-arm64-msvc: 1.32.0 - lightningcss-win32-x64-msvc: 1.32.0 + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 lilconfig@3.1.3: {} @@ -6666,6 +6639,8 @@ snapshots: nanoid@3.3.16: {} + nanoid@3.3.18: {} + natural-compare@1.4.0: {} needle@2.9.1: @@ -6874,6 +6849,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.26: + dependencies: + nanoid: 3.3.18 + picocolors: 1.1.1 + source-map-js: 1.2.1 + prelude-ls@1.2.1: {} prettier@3.9.6: {} @@ -6979,40 +6960,40 @@ snapshots: robust-predicates@3.0.3: optional: true - rolldown-plugin-dts@0.27.13(rolldown@1.1.5)(typescript@6.0.3): + rolldown-plugin-dts@0.28.2(rolldown@1.2.5)(typescript@6.0.3): dependencies: dts-resolver: 3.0.0 get-tsconfig: 5.0.0-beta.5 obug: 2.1.4 - rolldown: 1.1.5 - yuku-ast: 0.7.4 - yuku-codegen: 0.7.4 - yuku-parser: 0.7.4 + rolldown: 1.2.5 + yuku-ast: 0.8.7 + yuku-codegen: 0.8.7 + yuku-parser: 0.8.7 optionalDependencies: typescript: 6.0.3 transitivePeerDependencies: - oxc-resolver - rolldown@1.1.5: + rolldown@1.2.5: dependencies: - '@oxc-project/types': 0.139.0 + '@oxc-project/types': 0.146.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.1.5 - '@rolldown/binding-darwin-arm64': 1.1.5 - '@rolldown/binding-darwin-x64': 1.1.5 - '@rolldown/binding-freebsd-x64': 1.1.5 - '@rolldown/binding-linux-arm-gnueabihf': 1.1.5 - '@rolldown/binding-linux-arm64-gnu': 1.1.5 - '@rolldown/binding-linux-arm64-musl': 1.1.5 - '@rolldown/binding-linux-ppc64-gnu': 1.1.5 - '@rolldown/binding-linux-s390x-gnu': 1.1.5 - '@rolldown/binding-linux-x64-gnu': 1.1.5 - '@rolldown/binding-linux-x64-musl': 1.1.5 - '@rolldown/binding-openharmony-arm64': 1.1.5 - '@rolldown/binding-wasm32-wasi': 1.1.5 - '@rolldown/binding-win32-arm64-msvc': 1.1.5 - '@rolldown/binding-win32-x64-msvc': 1.1.5 + '@rolldown/binding-android-arm-eabi': 1.2.5 + '@rolldown/binding-android-arm64': 1.2.5 + '@rolldown/binding-darwin-arm64': 1.2.5 + '@rolldown/binding-darwin-x64': 1.2.5 + '@rolldown/binding-freebsd-x64': 1.2.5 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.5 + '@rolldown/binding-linux-arm64-gnu': 1.2.5 + '@rolldown/binding-linux-arm64-musl': 1.2.5 + '@rolldown/binding-linux-ppc64-gnu': 1.2.5 + '@rolldown/binding-linux-s390x-gnu': 1.2.5 + '@rolldown/binding-linux-x64-gnu': 1.2.5 + '@rolldown/binding-linux-x64-musl': 1.2.5 + '@rolldown/binding-openharmony-arm64': 1.2.5 + '@rolldown/binding-win32-arm64-msvc': 1.2.5 + '@rolldown/binding-win32-x64-msvc': 1.2.5 roughjs@4.6.6: dependencies: @@ -7359,9 +7340,6 @@ snapshots: ts-interface-checker@0.1.13: {} - tslib@2.8.1: - optional: true - tsx@4.23.1: dependencies: esbuild: 0.28.1 @@ -7458,12 +7436,12 @@ snapshots: transitivePeerDependencies: - '@types/markdown-it' - vite@8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3): + vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3): dependencies: - lightningcss: 1.32.0 + lightningcss: 1.33.0 picomatch: 4.0.5 - postcss: 8.5.22 - rolldown: 1.1.5 + postcss: 8.5.26 + rolldown: 1.2.5 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 22.20.1 @@ -7474,10 +7452,10 @@ snapshots: tsx: 4.23.1 yaml: 2.8.3 - vitest@4.1.10(@types/node@22.20.1)(jsdom@19.0.0)(vite@8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3)): + vitest@4.1.10(@types/node@22.20.1)(jsdom@19.0.0)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3)): dependencies: '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3)) + '@vitest/mocker': 4.1.10(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3)) '@vitest/pretty-format': 4.1.10 '@vitest/runner': 4.1.10 '@vitest/snapshot': 4.1.10 @@ -7494,7 +7472,7 @@ snapshots: tinyexec: 1.1.1 tinyglobby: 0.2.17 tinyrainbow: 3.1.1 - vite: 8.1.5(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3) + vite: 8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.6.1)(less@4.8.0)(tsx@4.23.1)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.20.1 @@ -7631,41 +7609,43 @@ snapshots: yocto-queue@0.1.0: {} - yuku-ast@0.7.4: + yuku-ast@0.8.7: dependencies: - '@yuku-toolchain/types': 0.7.4 + '@yuku-toolchain/types': 0.8.7 - yuku-codegen@0.7.4: + yuku-codegen@0.8.7: dependencies: - '@yuku-toolchain/types': 0.7.4 + '@yuku-toolchain/types': 0.8.7 optionalDependencies: - '@yuku-codegen/binding-darwin-arm64': 0.7.4 - '@yuku-codegen/binding-darwin-x64': 0.7.4 - '@yuku-codegen/binding-freebsd-x64': 0.7.4 - '@yuku-codegen/binding-linux-arm-gnu': 0.7.4 - '@yuku-codegen/binding-linux-arm-musl': 0.7.4 - '@yuku-codegen/binding-linux-arm64-gnu': 0.7.4 - '@yuku-codegen/binding-linux-arm64-musl': 0.7.4 - '@yuku-codegen/binding-linux-x64-gnu': 0.7.4 - '@yuku-codegen/binding-linux-x64-musl': 0.7.4 - '@yuku-codegen/binding-win32-arm64': 0.7.4 - '@yuku-codegen/binding-win32-x64': 0.7.4 - - yuku-parser@0.7.4: - dependencies: - '@yuku-toolchain/types': 0.7.4 - yuku-ast: 0.7.4 + '@yuku-codegen/binding-android-arm64': 0.8.7 + '@yuku-codegen/binding-darwin-arm64': 0.8.7 + '@yuku-codegen/binding-darwin-x64': 0.8.7 + '@yuku-codegen/binding-freebsd-x64': 0.8.7 + '@yuku-codegen/binding-linux-arm-gnu': 0.8.7 + '@yuku-codegen/binding-linux-arm-musl': 0.8.7 + '@yuku-codegen/binding-linux-arm64-gnu': 0.8.7 + '@yuku-codegen/binding-linux-arm64-musl': 0.8.7 + '@yuku-codegen/binding-linux-x64-gnu': 0.8.7 + '@yuku-codegen/binding-linux-x64-musl': 0.8.7 + '@yuku-codegen/binding-win32-arm64': 0.8.7 + '@yuku-codegen/binding-win32-x64': 0.8.7 + + yuku-parser@0.8.7: + dependencies: + '@yuku-toolchain/types': 0.8.7 + yuku-ast: 0.8.7 optionalDependencies: - '@yuku-parser/binding-darwin-arm64': 0.7.4 - '@yuku-parser/binding-darwin-x64': 0.7.4 - '@yuku-parser/binding-freebsd-x64': 0.7.4 - '@yuku-parser/binding-linux-arm-gnu': 0.7.4 - '@yuku-parser/binding-linux-arm-musl': 0.7.4 - '@yuku-parser/binding-linux-arm64-gnu': 0.7.4 - '@yuku-parser/binding-linux-arm64-musl': 0.7.4 - '@yuku-parser/binding-linux-x64-gnu': 0.7.4 - '@yuku-parser/binding-linux-x64-musl': 0.7.4 - '@yuku-parser/binding-win32-arm64': 0.7.4 - '@yuku-parser/binding-win32-x64': 0.7.4 + '@yuku-parser/binding-android-arm64': 0.8.7 + '@yuku-parser/binding-darwin-arm64': 0.8.7 + '@yuku-parser/binding-darwin-x64': 0.8.7 + '@yuku-parser/binding-freebsd-x64': 0.8.7 + '@yuku-parser/binding-linux-arm-gnu': 0.8.7 + '@yuku-parser/binding-linux-arm-musl': 0.8.7 + '@yuku-parser/binding-linux-arm64-gnu': 0.8.7 + '@yuku-parser/binding-linux-arm64-musl': 0.8.7 + '@yuku-parser/binding-linux-x64-gnu': 0.8.7 + '@yuku-parser/binding-linux-x64-musl': 0.8.7 + '@yuku-parser/binding-win32-arm64': 0.8.7 + '@yuku-parser/binding-win32-x64': 0.8.7 zod@4.4.3: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 986ab966..699d7b2b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -43,7 +43,7 @@ catalogs: prettier: 3.9.6 typescript: ^6.0.3 typescript-eslint: ^8.65.0 - vite: ^8.1.5 + vite: ^8.2.2 vitest: ^4.1.10 shamefullyHoist: true diff --git a/scripts/check-chat-contracts.mjs b/scripts/check-chat-contracts.mjs new file mode 100644 index 00000000..d7abd4c9 --- /dev/null +++ b/scripts/check-chat-contracts.mjs @@ -0,0 +1,234 @@ +import { readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; + +import ts from 'typescript'; + +const repoRoot = resolve(import.meta.dirname, '..'); +const chatRoot = resolve(repoRoot, 'packages/pro-components/chat'); +const tsconfigPath = resolve(chatRoot, 'tsconfig.check.json'); +const tsconfig = ts.readConfigFile(tsconfigPath, ts.sys.readFile); +if (tsconfig.error) throw new Error(ts.formatDiagnostic(tsconfig.error, ts.createCompilerHost({}))); +const parsedConfig = ts.parseJsonConfigFileContent(tsconfig.config, ts.sys, chatRoot); +const program = ts.createProgram(parsedConfig.fileNames, parsedConfig.options); +const checker = program.getTypeChecker(); + +const contracts = [ + ['chatbot', 'TdChatProps', 'chat.tsx'], + ['chat-message', 'TdChatMessageProps', 'chat-item.tsx'], + ['chat-sender', 'TdChatSenderProps', 'chat-sender.tsx'], + ['attachments', 'TdAttachmentsProps', 'attachments.tsx'], + ['filecard', 'TdFileCardProps', 'filecard.tsx'], + ['chat-action', 'TdChatActionProps', 'action.tsx'], + ['chat-loading', 'ChatLoadingProps', 'loading.tsx'], +]; + +const contentContracts = [ + ['markdown-content.tsx', 'TdChatMarkdownContentProps'], + ['search-content.tsx', 'TdChatSearchContentProps'], + ['suggestion-content.tsx', 'TdChatSuggestionContentProps'], + ['attachment-content.tsx', 'TdChatAttachmentContentProps'], + ['thinking-content.tsx', 'TdChatThinkContentProps'], + ['reasoning-content.tsx', 'TdChatReasoningProps'], +]; + +const errors = []; + +function parse(path) { + return ts.createSourceFile(path, readFileSync(path, 'utf8'), ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX); +} + +function propertyName(member) { + if (!member.name) return undefined; + if (ts.isIdentifier(member.name) || ts.isStringLiteral(member.name)) return member.name.text; + return undefined; +} + +function publicInterfaceProps(typePath, interfaceName) { + const source = parse(typePath); + const declarations = new Map( + source.statements.filter((node) => ts.isInterfaceDeclaration(node)).map((node) => [node.name.text, node]), + ); + const props = new Set(); + const visited = new Set(); + const collect = (name) => { + if (visited.has(name)) return; + visited.add(name); + const declaration = declarations.get(name); + if (!declaration) return; + for (const heritage of declaration.heritageClauses ?? []) { + for (const type of heritage.types) { + if (ts.isIdentifier(type.expression)) collect(type.expression.text); + } + } + for (const member of declaration.members) { + if (ts.getJSDocTags(member).some((tag) => tag.tagName.text === 'internal')) continue; + const name = propertyName(member); + if (name && name !== 'children') props.add(name); + } + }; + collect(interfaceName); + if (!visited.has(interfaceName)) throw new Error(`Missing interface ${interfaceName}: ${typePath}`); + return [...props]; +} + +function runtimeProps(componentPath) { + const source = parse(componentPath); + let props = []; + source.forEachChild((node) => { + if (!ts.isClassDeclaration(node)) return; + const declaration = node.members.find( + (member) => + ts.isPropertyDeclaration(member) && + member.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword) && + propertyName(member) === 'propTypes', + ); + if (declaration?.initializer && ts.isObjectLiteralExpression(declaration.initializer)) { + props = declaration.initializer.properties.map(propertyName).filter(Boolean); + } + }); + return props; +} + +function resolvedPublicTypeProps(typePath, typeName) { + const source = program.getSourceFile(typePath); + if (!source) throw new Error(`Missing program source: ${typePath}`); + const declaration = source.statements.find( + (node) => (ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)) && node.name.text === typeName, + ); + if (!declaration) throw new Error(`Missing public type ${typeName}: ${typePath}`); + const symbol = checker.getSymbolAtLocation(declaration.name); + const type = checker.getDeclaredTypeOfSymbol(symbol); + return checker + .getPropertiesOfType(type) + .filter( + (property) => + !property.declarations?.some((member) => + ts.getJSDocTags(member).some((tag) => tag.tagName.text === 'internal'), + ), + ) + .map((property) => property.name) + .filter((name) => name !== 'children'); +} + +function runtimePropValidators(componentPath) { + const source = parse(componentPath); + const validators = new Map(); + source.forEachChild((node) => { + if (!ts.isClassDeclaration(node)) return; + const declaration = node.members.find( + (member) => + ts.isPropertyDeclaration(member) && + member.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword) && + propertyName(member) === 'propTypes', + ); + if (!declaration?.initializer || !ts.isObjectLiteralExpression(declaration.initializer)) return; + for (const property of declaration.initializer.properties) { + if (!ts.isPropertyAssignment(property)) continue; + validators.set(propertyName(property), property.initializer.getText(source).replace(/\s+/g, ' ')); + } + }); + return validators; +} + +for (const [folder, interfaceName, componentFile] of contracts) { + const typePath = resolve(chatRoot, folder, 'type.ts'); + const componentPath = resolve(chatRoot, folder, componentFile); + const readmePath = resolve(chatRoot, folder, 'README.md'); + const typeProps = publicInterfaceProps(typePath, interfaceName); + const componentProps = runtimeProps(componentPath); + const readme = readFileSync(readmePath, 'utf8'); + + for (const name of typeProps) { + if (!componentProps.includes(name)) errors.push(`${folder}: type prop "${name}" is missing from runtime propTypes`); + const eventName = /^on[A-Z]/.test(name) ? `${name[2].toLowerCase()}${name.slice(3)}` : undefined; + if (!new RegExp(`\\b${name}\\b`).test(readme) && (!eventName || !new RegExp(`\\b${eventName}\\b`).test(readme))) { + errors.push(`${folder}: type prop "${name}" is missing from README`); + } + } + for (const name of componentProps) { + if (!typeProps.includes(name) && !(folder === 'chat-sender' && name === 'suffix')) { + errors.push(`${folder}: runtime prop "${name}" is missing from public type`); + } + } +} + +const contentReadme = readFileSync(resolve(chatRoot, 'chat-message/content/README.md'), 'utf8'); +for (const [componentFile, typeName] of contentContracts) { + const componentPath = resolve(chatRoot, 'chat-message/content', componentFile); + const typeProps = resolvedPublicTypeProps(componentPath, typeName); + const componentProps = runtimeProps(componentPath); + for (const name of typeProps) { + if (!componentProps.includes(name)) { + errors.push(`chat-message/content/${componentFile}: type prop "${name}" is missing from runtime propTypes`); + } + if (!new RegExp(`\\b${name}\\b`).test(contentReadme)) { + errors.push(`chat-message/content/${componentFile}: type prop "${name}" is missing from README`); + } + } + for (const name of componentProps) { + if (!typeProps.includes(name)) { + errors.push(`chat-message/content/${componentFile}: runtime prop "${name}" is missing from public type`); + } + } +} + +const validatorContracts = [ + ['chat-action/action.tsx', 'actionBar', '[Array, Boolean]'], + ['chat-action/action.tsx', 'handleAction', 'Function'], + ['chat-message/chat-item.tsx', 'actions', '[Array, Boolean]'], + ['chat-message/content/search-content.tsx', 'handleSearchItemClick', 'Function'], + ['chat-message/content/search-content.tsx', 'handleSearchResultClick', 'Function'], + ['chat-message/content/suggestion-content.tsx', 'content', 'Array'], + ['chat-message/content/suggestion-content.tsx', 'handlePromptClick', 'Function'], + ['chat-message/content/attachment-content.tsx', 'content', 'Array'], +]; +for (const [relativePath, prop, expected] of validatorContracts) { + const componentPath = resolve(chatRoot, relativePath); + const actual = runtimePropValidators(componentPath).get(prop); + if (actual !== expected) + errors.push(`${relativePath}: runtime validator for "${prop}" is ${actual}, expected ${expected}`); +} + +const forbiddenDocs = new Map([ + ['chatbot', ['clearHistory', 'scrollToBottom', 'chat_submit']], + ['chat-message', ['TdChatSenderAction', 'textareaProps', 'onSend']], + ['chat-action', ['goodActived', 'badActived', 'onActions', 'presetActions']], +]); +for (const [folder, names] of forbiddenDocs) { + const readme = readFileSync(resolve(chatRoot, folder, 'README.md'), 'utf8'); + for (const name of names) { + if (new RegExp(`\\b${name}\\b`).test(readme)) errors.push(`${folder}: README contains stale API "${name}"`); + } +} + +const uploadType = readFileSync(resolve(repoRoot, 'packages/components/upload/type.ts'), 'utf8'); +if (!/interface UploadFile extends CommonUploadFile, PlainObject/.test(uploadType)) { + errors.push('upload: public UploadFile must derive from the common submodule type'); +} +const filecardType = readFileSync(resolve(chatRoot, 'filecard/type.ts'), 'utf8'); +if (!/from '@common\/js\/upload\/types'/.test(filecardType)) { + errors.push('filecard: TdAttachmentItem must derive from the common submodule UploadFile type'); +} + +const messageType = readFileSync(resolve(chatRoot, 'chat-message/type.ts'), 'utf8'); +if (!/Array/.test(messageType)) { + errors.push('chat-message: actions must only accept preset TdChatActionsName strings or custom items'); +} +if (!/handleActions\?: TdChatMessageActionHandlers/.test(messageType)) { + errors.push('chat-message: handleActions must use the action-specific handler map'); +} + +for (const panel of ['RangePanel.tsx', 'SinglePanel.tsx']) { + const panelSource = readFileSync(resolve(repoRoot, 'packages/components/date-picker/panel', panel), 'utf8'); + if (/export type \{ DatePickerTableCell \}/.test(panelSource)) { + errors.push(`date-picker/${panel}: internal DatePickerTableCell must not be re-exported`); + } +} + +if (errors.length) { + throw new Error(`Chat contract check failed:\n- ${errors.join('\n- ')}`); +} + +console.log( + `[check:chat-contracts] ${contracts.length} primary and ${contentContracts.length} content component contracts aligned`, +); diff --git a/scripts/check-pack.mjs b/scripts/check-pack.mjs index 051f2675..ab4eed82 100644 --- a/scripts/check-pack.mjs +++ b/scripts/check-pack.mjs @@ -75,10 +75,18 @@ function checkPackList({ name, packageDir, iife }) { `[${name}] pack is missing ESM or IIFE output`, ); + const declarationMaps = files.filter((file) => file.endsWith('.d.ts.map')); + assert( + declarationMaps.length === 0, + `[${name}] pack must not publish declaration maps without their source files:\n${declarationMaps.join('\n')}`, + ); + if (name === 'chat') { for (const ext of ['eot', 'svg', 'ttf', 'woff', 'woff2']) { assert(files.includes(`dist/assets/ch-icon.${ext}`), `[chat] missing CDN font asset: ${ext}`); } + const esmIndex = readFileSync(resolve(repoRoot, packageDir, 'esm/index.js'), 'utf8'); + assert(/\bChatAttachmentContent\b/.test(esmIndex), '[chat] root ESM export is missing ChatAttachmentContent'); } console.log(`[check:pack] ${name} pack list ok (${files.length} files)`); @@ -95,12 +103,14 @@ function collectDeclarationFiles(dir) { } function checkDeclarationReferences({ name, packageDir }) { - const declarationFiles = collectDeclarationFiles(resolve(repoRoot, packageDir, 'esm')); + const esmDir = resolve(repoRoot, packageDir, 'esm'); + const declarationFiles = collectDeclarationFiles(esmDir); const forbiddenPatterns = [ ['common type cache', /\.cache\/common-js-types/], ['common source path', /packages\/common/], ['shared source path', /shared\/(?:src|dist)\//], ['workspace absolute path', /(?:\/Users\/|\/home\/runner\/work\/|[A-Za-z]:\\)/], + ['declaration map reference', /sourceMappingURL=.*\.d\.ts\.map/], ]; const violations = []; @@ -112,9 +122,127 @@ function checkDeclarationReferences({ name, packageDir }) { } assert(violations.length === 0, `[${name}] declarations expose internal paths:\n${violations.join('\n')}`); + const declarationSource = declarationFiles.map((file) => readFileSync(file, 'utf8')).join('\n'); + if (name === 'ui') { + for (const typeName of [ + 'ButtonProps', + 'UploadProps', + 'UploadFile', + 'ImageProps', + 'WatermarkProps', + 'WatermarkText', + ]) { + assert( + new RegExp(`(?:interface|type) ${typeName}\\b`).test(declarationSource), + `[ui] declaration surface is missing ${typeName}`, + ); + } + + const entryExports = { + 'alert/index.d.ts': ['AlertProps'], + 'back-top/index.d.ts': ['BackTopProps'], + 'badge/index.d.ts': ['BadgeProps'], + 'button/index.d.ts': ['ButtonProps'], + 'date-picker/index.d.ts': ['DateValue', 'DisableDate', 'DatePickerProps'], + 'image/index.d.ts': ['ImageProps'], + 'link/index.d.ts': ['LinkProps'], + 'upload/index.d.ts': ['UploadFile', 'UploadProps'], + 'watermark/index.d.ts': ['WatermarkProps'], + }; + for (const [entry, typeNames] of Object.entries(entryExports)) { + const source = readFileSync(resolve(esmDir, entry), 'utf8'); + for (const typeName of typeNames) { + assert( + new RegExp(`export\\s*\\{[^}]*\\b${typeName}\\b`, 's').test(source), + `[ui] ${entry} does not export ${typeName}`, + ); + } + } + + const internalPropsByEntry = { + 'affix/index.d.ts': ['TdAffixProps'], + 'avatar/index.d.ts': ['TdAvatarProps', 'TdAvatarGroupProps'], + 'breadcrumb/index.d.ts': ['TdBreadcrumbProps', 'TdBreadcrumbItemProps'], + 'button/index.d.ts': ['TdButtonProps'], + 'card/index.d.ts': ['TdCardProps'], + 'checkbox/index.d.ts': ['TdCheckboxProps', 'TdCheckboxGroupProps'], + 'collapse/index.d.ts': ['TdCollapseProps', 'TdCollapsePanelProps'], + 'date-picker/index.d.ts': ['TdDatePickerProps', 'TdDateRangePickerProps'], + 'dialog/index.d.ts': ['TdDialogProps'], + 'divider/index.d.ts': ['TdDividerProps'], + 'grid/index.d.ts': ['TdColProps', 'TdRowProps'], + 'input/index.d.ts': ['TdInputProps', 'TdInputGroupProps'], + 'loading/index.d.ts': ['TdLoadingProps'], + 'menu/index.d.ts': ['TdMenuProps', 'TdMenuItemProps'], + 'message/index.d.ts': ['TdMessageProps'], + 'notification/index.d.ts': ['TdNotificationProps'], + 'popconfirm/index.d.ts': ['TdPopconfirmProps'], + 'popup/index.d.ts': ['TdPopupProps'], + 'progress/index.d.ts': ['TdProgressProps'], + 'radio/index.d.ts': ['TdRadioProps', 'TdRadioGroupProps'], + 'range-input/index.d.ts': ['TdRangeInputProps', 'TdRangeInputPopupProps'], + 'select/index.d.ts': ['TdSelectProps', 'TdOptionProps'], + 'select-input/index.d.ts': ['TdSelectInputProps'], + 'skeleton/index.d.ts': ['TdSkeletonProps'], + 'slider/index.d.ts': ['TdSliderProps'], + 'space/index.d.ts': ['TdSpaceProps'], + 'swiper/index.d.ts': ['TdSwiperProps'], + 'switch/index.d.ts': ['TdSwitchProps'], + 'tabs/index.d.ts': ['TdTabsProps', 'TdTabPanelProps'], + 'tag-input/index.d.ts': ['TdTagInputProps'], + 'textarea/index.d.ts': ['TdTextareaProps'], + 'tooltip/index.d.ts': ['TdTooltipProps'], + 'upload/index.d.ts': ['TdUploadProps'], + }; + for (const [entry, typeNames] of Object.entries(internalPropsByEntry)) { + const source = readFileSync(resolve(esmDir, entry), 'utf8'); + for (const typeName of typeNames) { + assert( + !new RegExp(`export\\s*\\{[^}]*\\b${typeName}\\b`, 's').test(source), + `[ui] ${entry} must not expose internal ${typeName}`, + ); + } + } + } + if (name === 'chat') { + for (const typeName of [ + 'TdChatProps', + 'TdChatbotApi', + 'TdChatMessageProps', + 'TdChatAttachmentContentProps', + 'TdChatSenderProps', + 'TdAttachmentItem', + ]) { + assert( + new RegExp(`(?:interface|type) ${typeName}\\b`).test(declarationSource), + `[chat] declaration surface is missing ${typeName}`, + ); + } + } console.log(`[check:pack] ${name} declaration references ok (${declarationFiles.length} files)`); } +function checkRuntimeExports({ name, packageDir }) { + if (name !== 'ui') return; + + const runtimeExports = { + 'esm/index.js': ['Button', 'MessagePlugin'], + 'esm/message/index.js': ['Message', 'MessagePlugin', 'message'], + }; + + for (const [entry, exportNames] of Object.entries(runtimeExports)) { + const source = readFileSync(resolve(repoRoot, packageDir, entry), 'utf8'); + for (const exportName of exportNames) { + assert( + new RegExp(`export\\s*\\{[^}]*\\b${exportName}\\b`, 's').test(source), + `[ui] ${entry} does not preserve runtime export ${exportName}`, + ); + } + } + + console.log('[check:pack] ui runtime exports preserved'); +} + function checkResolvable({ name, packageDir, imports }) { const packageRoot = resolve(repoRoot, packageDir); const resolvedImports = JSON.parse( @@ -159,6 +287,7 @@ checkReleaseVersions(); for (const pkg of packages) { checkPackList(pkg); checkDeclarationReferences(pkg); + checkRuntimeExports(pkg); checkResolvable(pkg); checkComponentEntries(pkg); }