feat: manually mirror opencoze's code from bytedance

Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
fanlv
2025-07-20 17:36:12 +08:00
commit 890153324f
14811 changed files with 1923430 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
import { mergeConfig } from 'vite';
import svgr from 'vite-plugin-svgr';
/** @type { import('@storybook/react-vite').StorybookConfig } */
const config = {
stories: ['../stories/**/*.mdx', '../stories/**/*.stories.tsx'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-onboarding',
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: 'tag',
},
viteFinal: config =>
mergeConfig(config, {
plugins: [
svgr({
svgrOptions: {
native: false,
},
}),
],
}),
};
export default config;

View File

@@ -0,0 +1,14 @@
/** @type { import('@storybook/react').Preview } */
const preview = {
parameters: {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
};
export default preview;

View File

@@ -0,0 +1,5 @@
const { defineConfig } = require('@coze-arch/stylelint-config');
module.exports = defineConfig({
extends: [],
});

View File

@@ -0,0 +1,16 @@
# @coze-common/chat-uikit-shared
> Project template for react component with storybook.
## Features
- [x] eslint & ts
- [x] esm bundle
- [x] umd bundle
- [x] storybook
## Commands
- init: `rush update`
- dev: `npm run dev`
- build: `npm run build`

View File

@@ -0,0 +1,12 @@
{
"operationSettings": [
{
"operationName": "test:cov",
"outputFolderNames": ["coverage"]
},
{
"operationName": "ts-check",
"outputFolderNames": ["dist"]
}
]
}

View File

@@ -0,0 +1,7 @@
const { defineConfig } = require('@coze-arch/eslint-config');
module.exports = defineConfig({
packageRoot: __dirname,
preset: 'web',
rules: {},
});

View File

@@ -0,0 +1,46 @@
{
"name": "@coze-common/chat-uikit-shared",
"version": "0.0.1",
"description": "chat uikit shared",
"license": "Apache-2.0",
"author": "gaoyuanhan.duty@bytedance.com",
"maintainers": [],
"main": "src/index.ts",
"scripts": {
"build": "exit 0",
"lint": "eslint ./ --cache",
"test": "vitest --run --passWithNoTests",
"test:cov": "npm run test -- --coverage"
},
"dependencies": {
"@coze-arch/bot-md-box-adapter": "workspace:*",
"@coze-common/chat-core": "workspace:*",
"@douyinfe/semi-icons": "^2.36.0",
"ahooks": "^3.7.8",
"classnames": "^2.3.2",
"mitt": "^3.0.1"
},
"devDependencies": {
"@coze-arch/bot-typings": "workspace:*",
"@coze-arch/eslint-config": "workspace:*",
"@coze-arch/stylelint-config": "workspace:*",
"@coze-arch/ts-config": "workspace:*",
"@coze-arch/vitest-config": "workspace:*",
"@testing-library/jest-dom": "^6.1.5",
"@testing-library/react": "^14.1.2",
"@testing-library/react-hooks": "^8.0.1",
"@types/react": "18.2.37",
"@types/react-dom": "18.2.15",
"@vitest/coverage-v8": "~3.0.5",
"react": "~18.2.0",
"react-dom": "~18.2.0",
"stylelint": "^15.11.0",
"vite-plugin-svgr": "~3.3.0",
"vitest": "~3.0.5"
},
"peerDependencies": {
"react": ">=18.2.0",
"react-dom": ">=18.2.0"
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { FILE_TYPE_CONFIG } from '@coze-common/chat-core/shared/const';
const BYTES = 1024;
export const MAX_FILE_MBYTE = 500;
export const DEFAULT_MAX_FILE_SIZE = MAX_FILE_MBYTE * BYTES * BYTES;
export const enum UploadType {
IMAGE = 0,
FILE = 1,
}
export const ACCEPT_FILE_EXTENSION = FILE_TYPE_CONFIG.map(cnf => cnf.accept)
.flat(1)
.join(',');

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { type PropsWithChildren, createContext } from 'react';
import mitt from 'mitt';
import { useCreation } from 'ahooks';
import {
type UIKitEventMap,
type UIKitEventCenter,
type UIKitEventProviderProps,
} from './type';
import { useObserveChatContainer } from './hooks';
export const UIKitEventContext = createContext<UIKitEventCenter | null>(null);
export const UIKitEventProvider: React.FC<
PropsWithChildren<UIKitEventProviderProps>
> = ({ chatContainerRef, children }) => {
const eventCenter = useCreation(() => mitt<UIKitEventMap>(), []);
useObserveChatContainer({ eventCenter, chatContainerRef });
return (
<UIKitEventContext.Provider value={eventCenter}>
{children}
</UIKitEventContext.Provider>
);
};

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useEffect, type RefObject } from 'react';
import { type Emitter } from 'mitt';
import { UIKitEvents, type UIKitEventMap } from './type';
export const useObserveChatContainer = ({
eventCenter,
chatContainerRef,
}: {
eventCenter: Emitter<UIKitEventMap>;
chatContainerRef: RefObject<HTMLDivElement>;
}) => {
useEffect(() => {
if (!chatContainerRef.current) {
return;
}
const resizeObserver = new ResizeObserver(() => {
eventCenter.emit(UIKitEvents.WINDOW_RESIZE);
});
resizeObserver.observe(chatContainerRef.current);
return () => {
resizeObserver.disconnect();
};
}, []);
};

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useContext } from 'react';
import { UIKitEventContext } from './context';
export const useUiKitEventCenter = () => useContext(UIKitEventContext);

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { type RefObject } from 'react';
import { type Emitter } from 'mitt';
export enum UIKitEvents {
WINDOW_RESIZE,
AFTER_CARD_RENDER,
}
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions -- mitt 的类型不认 interface
export type UIKitEventMap = {
[UIKitEvents.WINDOW_RESIZE]: undefined;
[UIKitEvents.AFTER_CARD_RENDER]: { messageId: string };
};
export type UIKitEventCenter = Emitter<UIKitEventMap>;
export interface UIKitEventProviderProps {
chatContainerRef: RefObject<HTMLDivElement>;
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export {
type ICardEmptyConfig,
type ICopywritingConfig,
type IMessage,
type IBaseContentProps,
type IContentConfig,
type IContentConfigs,
type ICardCopywritingConfig,
type IFileCopywritingConfig,
type IChatUploadCopywritingConfig,
type IconType,
Layout,
} from './types/common';
export {
type IContent,
type ISuggestionContent,
type IImageContent,
type IFileContent,
type IFunctionCallContent,
type GetBotInfo,
type MdBoxProps,
ContentBoxType,
} from './types/content';
export {
type ISimpleFunctionContentCopywriting,
type IChatInputCopywritingConfig,
} from './types/copywriting';
export {
type IEventCallbacksParams,
type LinkEventData,
type IOnLinkClickParams,
type IOnImageClickParams,
type IOnCancelUploadParams,
type IOnRetryUploadParams,
type IOnSuggestionClickParams,
type IOnMessageRetryParams,
type IOnCopyUploadParams,
type IOnCardSendMsg,
type IOnCardUpdateStatus,
type MouseEventProps,
type IEventCallbacks,
} from './types/event';
export {
type IFileInfo,
type IFileUploadInfo,
type IFileAttributeKeys,
type IFileCardTooltipsCopyWritingConfig,
} from './types/file';
export { useUiKitEventCenter } from './context/event-center';
export {
UIKitEvents,
type UIKitEventMap,
type UIKitEventCenter,
type UIKitEventProviderProps,
} from './context/event-center/type';
export {
UIKitEventContext,
UIKitEventProvider,
} from './context/event-center/context';
export { useObserveChatContainer } from './context/event-center/hooks';
export {
UploadType,
MAX_FILE_MBYTE,
DEFAULT_MAX_FILE_SIZE,
ACCEPT_FILE_EXTENSION,
} from './constants/file';
export {
type MentionList,
type SendButtonProps,
type SendFileMessagePayload,
type SendTextMessagePayload,
type UiKitChatInputButtonConfig,
type UiKitChatInputButtonStatus,
type IChatInputProps,
type InputMode,
} from './types/chat-input';
export {
type AudioRecordProps,
type AudioRecordEvents,
type AudioRecordOptions,
} from './types/chat-input/audio-record';
export {
type InputNativeCallbacks,
type InputState,
type InputController,
type OnBeforeProcessKeyDown,
} from './types/chat-input/input-native-callbacks';

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export interface AudioRecordProps {
isPointerMoveOut?: boolean;
isRecording?: boolean;
getVolume?: () => number;
text?: string;
}
type EventType = MouseEvent | TouchEvent | KeyboardEvent;
type InteractionEventType = EventType | KeyboardEvent;
export interface AudioRecordEvents {
onStart?: (eventType: InteractionEventType) => void;
onEnd?: (eventType: InteractionEventType | undefined) => void;
onMoveLeave?: () => void;
onMoveEnter?: () => void;
}
export interface AudioRecordOptions {
getIsShortcutKeyDisabled?: () => boolean;
/** 参考 ahooks useKeypress 入参 */
shortcutKey?: string | number;
enabled?: boolean;
getActiveZoneTarget?: () => HTMLElement | null;
}

View File

@@ -0,0 +1,209 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
type ClipboardEventHandler,
type PropsWithChildren,
type ReactNode,
type ComponentType,
type FocusEventHandler,
} from 'react';
import { type IChatInputCopywritingConfig } from '../copywriting';
import { type Layout } from '../common';
import { type UploadType } from '../../constants/file';
import { type InputNativeCallbacks } from './input-native-callbacks';
import {
type AudioRecordEvents,
type AudioRecordOptions,
type AudioRecordProps,
} from './audio-record';
export type InputMode = 'input' | 'audio';
export type MentionList = { id: string }[];
export interface SendTextMessagePayload {
text: string;
mentionList: MentionList;
}
export interface SendFileMessagePayload {
file: File;
mentionList: MentionList;
}
export interface UiKitChatInputButtonStatus {
isSendButtonDisabled: boolean;
isClearHistoryButtonDisabled: boolean;
isClearContextButtonDisabled: boolean;
isMoreButtonDisabled: boolean;
}
export interface UiKitChatInputButtonConfig {
isSendButtonVisible: boolean;
isClearHistoryButtonVisible: boolean;
isMoreButtonVisible: boolean;
isClearContextButtonVisible: boolean;
}
export interface SendButtonProps {
isDisabled?: boolean;
tooltipContent?: ReactNode;
onClick: () => void;
layout?: Layout;
}
// export type InputMode = 'input' | 'audio';
export interface IChatInputProps {
/**
* submit 过程
* 用户操作触发事件 -> 执行 submit -> 执行清空输入框内容
* @returns false 阻止 submit 流程
*/
onBeforeSubmit?: () => boolean;
/**
* input focus 事件回调
*/
onFocus?: FocusEventHandler<HTMLTextAreaElement>;
/**
* input blur 事件回调
*/
onBlur?: FocusEventHandler<HTMLTextAreaElement>;
/**
* 发送消息Message事件回调
*/
onSendMessage?: (payload: SendTextMessagePayload) => void;
/**
* 清除上下文事件回调
*/
onClearContext?: () => void;
/**
* 清除历史事件回调
*/
onClearHistory?: () => void;
/**
* 上传事件回调
* @param uploadType 上传类型 [IMAGE=0 FILE=1]
* @param file 文件
* @returns void
*/
onUpload?: (uploadType: UploadType, payload: SendFileMessagePayload) => void;
/**
* 整个输入框组件是否只读(包括按钮)
*/
isReadonly?: boolean;
/**
* 输入框是否只读
*/
isInputReadonly?: boolean;
/**
* 文案配置
*/
copywritingConfig?: IChatInputCopywritingConfig;
/**
* 左侧插槽
*/
leftActions?: ReactNode;
/**
* 右侧插槽
*/
rightActions?: ReactNode;
/**
* 自定义发送按钮
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
CustomSendButton?: ComponentType<SendButtonProps>;
/**
* 顶部插槽
*/
addonTop?: ReactNode;
/**
* 左侧插槽
*/
addonLeft?: ReactNode;
/**
* 整个 textarea 顶部插槽mentionList 放在这里
*/
aboveOutside?: ReactNode;
/**
* 内置按钮置灰状态
*/
buildInButtonStatus?: Partial<UiKitChatInputButtonStatus>;
/**
* 内置按钮配置
*/
buildInButtonConfig?: Partial<UiKitChatInputButtonConfig>;
/**
* 输入框点击事件
* @returns void
*/
onInputClick?: () => void;
/**
* @deprecated 废弃不消费
*/
className?: string;
/**
* 外容器的 classname
*/
wrapperClassName?: string;
/**
* 除了输入框中的文字 用户也输入了别的可以发送的内容
* 目的是适配文件消息同时发送需求
*/
hasOtherContentToSend?: boolean;
/**
* 布局方式
*/
layout: Layout;
/**
* 可上传文件是否超过数量
*/
isFileCountExceedsLimit: (fileCount: number) => boolean;
inputTooltip?: ComponentType<PropsWithChildren>;
/**
* 是否是背景图模式
*/
showBackground?: boolean;
/**
* 限制文件数量
*/
limitFileCount?: number;
/**
* 粘贴事件的回调
*/
onPaste?: ClipboardEventHandler<HTMLTextAreaElement>;
inputNativeCallbacks?: InputNativeCallbacks;
audioRecordEvents?: AudioRecordEvents;
audioRecordState?: AudioRecordProps;
audioRecordOptions?: AudioRecordOptions;
inputMode?: InputMode;
onInputModeChange?: (mode: InputMode) => void;
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { type KeyboardEvent, type KeyboardEventHandler } from 'react';
export interface InputState {
inputText: string;
isComposing: boolean;
isDisabled: boolean;
selection: { start: number; end: number };
hasSelection: boolean;
}
export interface InputController {
readState: () => InputState;
/**
* by imperative layoutEffect
*/
requireSetMousePosition: (pos: number) => void;
setInputText: (updater: string | ((pre: string) => string)) => void;
focus: () => void;
}
type ProcessRet =
| {
exit: boolean;
}
| undefined;
export type OnBeforeProcessKeyDown = (
evt: KeyboardEvent<HTMLTextAreaElement>,
) => ProcessRet;
export interface InputNativeCallbacks {
onAfterProcessKeyUp?: KeyboardEventHandler<HTMLTextAreaElement>;
onBeforeProcessKeyDown?: OnBeforeProcessKeyDown;
getController?: (controller: InputController) => void;
/**
* 在 onChange 后触发,但是等待一个 Promise避开闭包问题
*/
onAfterOnChange?: () => void;
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { type ForwardRefExoticComponent, type RefAttributes } from 'react';
import type { ContentType, Message } from '@coze-common/chat-core';
import { type IconProps } from '@douyinfe/semi-icons';
import {
type IFileAttributeKeys,
type IFileCardTooltipsCopyWritingConfig,
} from './file';
import { type ISimpleFunctionContentCopywriting } from './copywriting';
import { type ContentBoxType } from './content';
export type ICardEmptyConfig = Partial<{
title: string;
description: string;
}>;
export interface ICopywritingConfig {
cardEmpty?: ICardEmptyConfig;
file?: IFileCardTooltipsCopyWritingConfig;
}
export type IMessage = Message<ContentType>;
export interface IBaseContentProps {
message: IMessage;
readonly?: boolean;
showBackground?: boolean;
className?: string;
}
export interface IContentConfig<T = Record<string, unknown>> {
enable?: boolean;
copywriting?: T;
}
/**
* 后续维护注意,需要扩展参数的类型的卡片默认关闭
*/
export type IContentConfigs = Partial<{
[ContentBoxType.TAKO]: IContentConfig;
[ContentBoxType.CARD]: IContentConfig<ICardCopywritingConfig> & {
region: unknown;
};
[ContentBoxType.IMAGE]: IContentConfig;
[ContentBoxType.TEXT]: IContentConfig;
[ContentBoxType.FILE]: IContentConfig<IFileCopywritingConfig> & {
fileAttributeKeys?: IFileAttributeKeys;
};
[ContentBoxType.SIMPLE_FUNCTION]: IContentConfig<ISimpleFunctionContentCopywriting>;
}>;
export interface ICardCopywritingConfig {
empty: ICardEmptyConfig;
}
export interface IFileCopywritingConfig {
tooltips: IFileCardTooltipsCopyWritingConfig;
}
export type IChatUploadCopywritingConfig = Partial<{
fileSizeReachLimitToast: string;
fileExceedsLimitToast: string;
fileEmptyToast: string;
}>;
export enum Layout {
MOBILE = 'mobile',
PC = 'pc',
}
export type IconType = ForwardRefExoticComponent<
Omit<IconProps, 'ref' | 'svg'> & RefAttributes<HTMLSpanElement>
>;

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
type FileMessageContent,
type ImageMessageContent,
} from '@coze-common/chat-core';
import { type MdBoxLazyProps } from '@coze-arch/bot-md-box-adapter/lazy';
import { type IMessage } from './common';
export type IContent = ISuggestionContent | IImageContent;
export type ISuggestionContent = IMessage[];
export type IImageContent = ImageMessageContent;
export interface IFileContent {
file_list: Array<
FileMessageContent['file_list'][0] & {
upload_status?: number;
upload_percent?: number;
}
>;
}
export const enum ContentBoxType {
TEXT = 1,
IMAGE = 2,
CARD = 3,
FILE = 4,
TAKO = 5,
SUGGESTION = 100,
SIMPLE_FUNCTION = 101,
}
export interface IFunctionCallContent {
name: string;
arguments: {
name: string;
description: string;
};
}
export type GetBotInfo = (id: string) => { nickname: string } | undefined;
export type MdBoxProps = Pick<
MdBoxLazyProps,
'insertedElements' | 'enabledHtmlTags' | 'slots'
>;

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { type ReactNode } from 'react';
import { type IChatUploadCopywritingConfig } from './common';
export interface ISimpleFunctionContentCopywriting {
using: string;
}
export type IChatInputCopywritingConfig = Partial<{
tooltip: Partial<{
sendButtonTooltipContent: ReactNode | string;
clearHistoryButtonTooltipContent: ReactNode | string;
clearContextButtonTooltipContent: ReactNode | string;
moreButtonTooltipContent: ReactNode | string;
audioButtonTooltipContent: ReactNode | string;
keyboardButtonTooltipContent: ReactNode | string;
}>;
inputPlaceholder: string;
uploadConfig: IChatUploadCopywritingConfig;
bottomTips: string;
}>;

View File

@@ -0,0 +1,94 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { type MouseEvent } from 'react';
import { type SendMessageOptions } from '@coze-common/chat-core';
import { type IMessage } from './common';
export interface IEventCallbacksParams<T = Record<string, unknown>> {
message: IMessage;
extra: T;
}
export interface LinkEventData {
url: string;
parsedUrl: URL;
exts: {
// type: LinkType;
wiki_link?: string;
};
}
export type IOnLinkClickParams = IEventCallbacksParams<LinkEventData>;
export type IOnImageClickParams = IEventCallbacksParams<{
url: string;
}>;
export type IOnCancelUploadParams = IEventCallbacksParams;
export type IOnRetryUploadParams = IEventCallbacksParams;
export type IOnSuggestionClickParams = IEventCallbacksParams<{
text: string;
mentionList: { id: string }[];
}>;
export type IOnMessageRetryParams = IEventCallbacksParams;
export type IOnCopyUploadParams = IEventCallbacksParams<{ fileIndex?: number }>;
export type IOnCardSendMsg = IEventCallbacksParams<{
msg: string;
mentionList: { id: string }[];
options?: SendMessageOptions;
}>;
export type IOnCardUpdateStatus = IEventCallbacksParams;
export interface MouseEventProps {
element: HTMLElement;
link: string;
}
export type IEventCallbacks = Partial<{
// 点击 md 中链接的回调函数
onLinkClick: (
params: IOnLinkClickParams,
event: MouseEvent<Element, globalThis.MouseEvent>,
) => void;
// 图片点击事件响应
onImageClick: (params: IOnImageClickParams) => void;
// 取消上传事件响应
onCancelUpload: (params: IOnCancelUploadParams) => void;
// 恢复上传事件响应
onRetryUpload: (params: IOnRetryUploadParams) => void;
// 拷贝文件链接
onCopyUpload: (params: IOnCopyUploadParams) => void;
// 重新发送
onMessageRetry: (params: IOnMessageRetryParams) => void;
// 点击卡片按钮的事件响应
onCardSendMsg: (params: IOnCardSendMsg) => void;
// 更新卡片状态
onCardUpdateStatus: (params: IOnCardUpdateStatus) => void;
onCardLinkElementEnter?: (params: MouseEventProps) => void;
onCardLinkElementLeave?: (params: MouseEventProps) => void;
onMdBoxLinkElementEnter?: (params: MouseEventProps) => void;
onMdBoxLinkElementLeave?: (params: MouseEventProps) => void;
onMdBoxImageElementEnter?: (params: MouseEventProps) => void;
onMdBoxImageElementLeave?: (params: MouseEventProps) => void;
}>;

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { type FileMessageContent } from '@coze-common/chat-core';
export type IFileInfo = FileMessageContent['file_list'][0] & {
upload_status?: number;
upload_percent?: number;
};
export interface IFileUploadInfo {
status: 'uploading' | 'uploaded' | 'failed';
percent: number;
}
export interface IFileAttributeKeys {
statusKey: string;
statusEnum: {
successEnum: number;
failEnum: number;
cancelEnum: number;
uploadingEnum: number;
};
percentKey: string;
}
export interface IFileCardTooltipsCopyWritingConfig {
cancel: string;
copy: string;
retry: string;
}

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// <reference types='@coze-arch/bot-typings' />

View File

@@ -0,0 +1,39 @@
{
"extends": "@coze-arch/ts-config/tsconfig.web.json",
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"jsx": "react-jsx",
"lib": ["DOM", "ESNext"],
"module": "ESNext",
"target": "ES2020",
"moduleResolution": "bundler",
"tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo"
},
"include": ["src"],
"exclude": ["node_modules", "dist"],
"references": [
{
"path": "../../../arch/bot-md-box-adapter/tsconfig.build.json"
},
{
"path": "../../../arch/bot-typings/tsconfig.build.json"
},
{
"path": "../chat-core/tsconfig.build.json"
},
{
"path": "../../../../config/eslint-config/tsconfig.build.json"
},
{
"path": "../../../../config/stylelint-config/tsconfig.build.json"
},
{
"path": "../../../../config/ts-config/tsconfig.build.json"
},
{
"path": "../../../../config/vitest-config/tsconfig.build.json"
}
]
}

View File

@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"exclude": ["**/*"],
"compilerOptions": {
"composite": true
},
"references": [
{
"path": "./tsconfig.build.json"
},
{
"path": "./tsconfig.misc.json"
}
]
}

View File

@@ -0,0 +1,20 @@
{
"extends": "@coze-arch/ts-config/tsconfig.web.json",
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"rootDir": "./",
"outDir": "./dist",
"jsx": "react-jsx",
"lib": ["DOM", "ESNext"],
"module": "ESNext",
"target": "ES2020",
"moduleResolution": "bundler"
},
"include": ["__tests__", "vitest.config.ts", "stories"],
"exclude": ["./dist"],
"references": [
{
"path": "./tsconfig.build.json"
}
]
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { defineConfig } from '@coze-arch/vitest-config';
export default defineConfig({
dirname: __dirname,
preset: 'web',
});