@douyinfe/semi-foundation 2.62.0 → 2.63.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/chat/chat.scss +598 -0
- package/chat/chatBoxActionFoundation.ts +64 -0
- package/chat/constants.ts +68 -0
- package/chat/foundation.ts +306 -0
- package/chat/inputboxFoundation.ts +98 -0
- package/chat/rtl.scss +22 -0
- package/chat/variables.scss +125 -0
- package/input/textareaFoundation.ts +5 -0
- package/lib/cjs/chat/chat.css +484 -0
- package/lib/cjs/chat/chat.scss +598 -0
- package/lib/cjs/chat/chatBoxActionFoundation.d.ts +24 -0
- package/lib/cjs/chat/chatBoxActionFoundation.js +49 -0
- package/lib/cjs/chat/constants.d.ts +41 -0
- package/lib/cjs/chat/constants.js +56 -0
- package/lib/cjs/chat/foundation.d.ts +76 -0
- package/lib/cjs/chat/foundation.js +275 -0
- package/lib/cjs/chat/inputboxFoundation.d.ts +20 -0
- package/lib/cjs/chat/inputboxFoundation.js +118 -0
- package/lib/cjs/chat/rtl.scss +22 -0
- package/lib/cjs/chat/variables.scss +125 -0
- package/lib/cjs/input/textareaFoundation.js +7 -0
- package/lib/cjs/treeSelect/foundation.d.ts +3 -3
- package/lib/cjs/treeSelect/foundation.js +2 -6
- package/lib/cjs/upload/foundation.d.ts +1 -0
- package/lib/cjs/upload/foundation.js +3 -1
- package/lib/cjs/upload/upload.css +4 -0
- package/lib/cjs/upload/upload.scss +9 -0
- package/lib/es/chat/chat.css +484 -0
- package/lib/es/chat/chat.scss +598 -0
- package/lib/es/chat/chatBoxActionFoundation.d.ts +24 -0
- package/lib/es/chat/chatBoxActionFoundation.js +41 -0
- package/lib/es/chat/constants.d.ts +41 -0
- package/lib/es/chat/constants.js +51 -0
- package/lib/es/chat/foundation.d.ts +76 -0
- package/lib/es/chat/foundation.js +267 -0
- package/lib/es/chat/inputboxFoundation.d.ts +20 -0
- package/lib/es/chat/inputboxFoundation.js +110 -0
- package/lib/es/chat/rtl.scss +22 -0
- package/lib/es/chat/variables.scss +125 -0
- package/lib/es/input/textareaFoundation.js +7 -0
- package/lib/es/treeSelect/foundation.d.ts +3 -3
- package/lib/es/treeSelect/foundation.js +2 -6
- package/lib/es/upload/foundation.d.ts +1 -0
- package/lib/es/upload/foundation.js +3 -1
- package/lib/es/upload/upload.css +4 -0
- package/lib/es/upload/upload.scss +9 -0
- package/package.json +3 -3
- package/treeSelect/foundation.ts +3 -9
- package/upload/foundation.ts +4 -2
- package/upload/upload.scss +9 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.strings = exports.cssClasses = void 0;
|
|
7
|
+
var _constants = require("../base/constants");
|
|
8
|
+
const cssClasses = exports.cssClasses = {
|
|
9
|
+
PREFIX: `${_constants.BASE_CLASS_PREFIX}-chat`,
|
|
10
|
+
PREFIX_DIVIDER: `${_constants.BASE_CLASS_PREFIX}-chat-divider`,
|
|
11
|
+
PREFIX_CHAT_BOX: `${_constants.BASE_CLASS_PREFIX}-chat-chatBox`,
|
|
12
|
+
PREFIX_CHAT_BOX_ACTION: `${_constants.BASE_CLASS_PREFIX}-chat-chatBox-action`,
|
|
13
|
+
PREFIX_INPUT_BOX: `${_constants.BASE_CLASS_PREFIX}-chat-inputBox`,
|
|
14
|
+
PREFIX_ATTACHMENT: `${_constants.BASE_CLASS_PREFIX}-chat-attachment`,
|
|
15
|
+
PREFIX_HINT: `${_constants.BASE_CLASS_PREFIX}-chat-hint`
|
|
16
|
+
};
|
|
17
|
+
const ROLE = {
|
|
18
|
+
USER: 'user',
|
|
19
|
+
ASSISTANT: 'assistant',
|
|
20
|
+
SYSTEM: 'system',
|
|
21
|
+
DIVIDER: 'divider'
|
|
22
|
+
};
|
|
23
|
+
const CHAT_ALIGN = {
|
|
24
|
+
LEFT_RIGHT: 'leftRight',
|
|
25
|
+
LEFT_ALIGN: 'leftAlign'
|
|
26
|
+
};
|
|
27
|
+
const MESSAGE_STATUS = {
|
|
28
|
+
LOADING: 'loading',
|
|
29
|
+
INCOMPLETE: 'incomplete',
|
|
30
|
+
COMPLETE: 'complete',
|
|
31
|
+
ERROR: 'error'
|
|
32
|
+
};
|
|
33
|
+
const PIC_SUFFIX_ARRAY = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp'];
|
|
34
|
+
const PIC_PREFIX = 'image/';
|
|
35
|
+
const SCROLL_ANIMATION_TIME = 300;
|
|
36
|
+
const SHOW_SCROLL_GAP = 100;
|
|
37
|
+
const MODE = {
|
|
38
|
+
BUBBLE: 'bubble',
|
|
39
|
+
NO_BUBBLE: 'noBubble',
|
|
40
|
+
USER_BUBBLE: 'userBubble'
|
|
41
|
+
};
|
|
42
|
+
const SEND_HOT_KEY = {
|
|
43
|
+
ENTER: 'enter',
|
|
44
|
+
SHIFT_PLUS_ENTER: 'shift+enter'
|
|
45
|
+
};
|
|
46
|
+
const strings = exports.strings = {
|
|
47
|
+
ROLE,
|
|
48
|
+
CHAT_ALIGN,
|
|
49
|
+
MESSAGE_STATUS,
|
|
50
|
+
PIC_SUFFIX_ARRAY,
|
|
51
|
+
PIC_PREFIX,
|
|
52
|
+
SCROLL_ANIMATION_TIME,
|
|
53
|
+
SHOW_SCROLL_GAP,
|
|
54
|
+
MODE,
|
|
55
|
+
SEND_HOT_KEY
|
|
56
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
/// <reference types="lodash" />
|
|
3
|
+
import BaseFoundation, { DefaultAdapter } from "../base/foundation";
|
|
4
|
+
export interface Content {
|
|
5
|
+
type: 'text' | 'image_url' | 'file_url';
|
|
6
|
+
text?: string;
|
|
7
|
+
image_url?: {
|
|
8
|
+
url: string;
|
|
9
|
+
[x: string]: any;
|
|
10
|
+
};
|
|
11
|
+
file_url?: {
|
|
12
|
+
url: string;
|
|
13
|
+
name: string;
|
|
14
|
+
size: string;
|
|
15
|
+
type: string;
|
|
16
|
+
[x: string]: any;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface Message {
|
|
20
|
+
role?: string;
|
|
21
|
+
name?: string;
|
|
22
|
+
id?: string;
|
|
23
|
+
content?: string | Content[];
|
|
24
|
+
parentId?: string;
|
|
25
|
+
createAt?: number;
|
|
26
|
+
status?: 'loading' | 'incomplete' | 'complete' | 'error';
|
|
27
|
+
[x: string]: any;
|
|
28
|
+
}
|
|
29
|
+
export interface ChatAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
|
|
30
|
+
getContainerRef: () => React.RefObject<HTMLDivElement>;
|
|
31
|
+
setWheelScroll: (flag: boolean) => void;
|
|
32
|
+
notifyChatsChange: (chats: Message[]) => void;
|
|
33
|
+
notifyLikeMessage: (message: Message) => void;
|
|
34
|
+
notifyDislikeMessage: (message: Message) => void;
|
|
35
|
+
notifyCopyMessage: (message: Message) => void;
|
|
36
|
+
notifyClearContext: () => void;
|
|
37
|
+
notifyMessageSend: (content: string, attachment: any[]) => void;
|
|
38
|
+
notifyInputChange: (props: {
|
|
39
|
+
inputValue: string;
|
|
40
|
+
attachment: any[];
|
|
41
|
+
}) => void;
|
|
42
|
+
setBackBottomVisible: (visible: boolean) => void;
|
|
43
|
+
registerWheelEvent: () => void;
|
|
44
|
+
unRegisterWheelEvent: () => void;
|
|
45
|
+
notifyStopGenerate: (e: any) => void;
|
|
46
|
+
notifyHintClick: (hint: string) => void;
|
|
47
|
+
setUploadAreaVisible: (visible: boolean) => void;
|
|
48
|
+
manualUpload: (e: any) => void;
|
|
49
|
+
getDropAreaElement: () => HTMLDivElement;
|
|
50
|
+
}
|
|
51
|
+
export default class ChatFoundation<P = Record<string, any>, S = Record<string, any>> extends BaseFoundation<ChatAdapter<P, S>, P, S> {
|
|
52
|
+
animation: any;
|
|
53
|
+
constructor(adapter: ChatAdapter<P, S>);
|
|
54
|
+
init: () => void;
|
|
55
|
+
destroy: () => void;
|
|
56
|
+
stopGenerate: (e: any) => void;
|
|
57
|
+
scrollToBottomImmediately: () => void;
|
|
58
|
+
scrollToBottomWithAnimation: () => void;
|
|
59
|
+
containerScroll: (e: any) => void;
|
|
60
|
+
getScroll: import("lodash").DebouncedFunc<(target: any) => typeof scroll>;
|
|
61
|
+
clearContext: (e: any) => void;
|
|
62
|
+
onMessageSend: (input: string, attachment: any[]) => void;
|
|
63
|
+
onHintClick: (hint: string) => void;
|
|
64
|
+
onInputChange: (props: {
|
|
65
|
+
inputValue: string;
|
|
66
|
+
attachment: any[];
|
|
67
|
+
}) => void;
|
|
68
|
+
deleteMessage: (message: Message) => void;
|
|
69
|
+
likeMessage: (message: Message) => void;
|
|
70
|
+
dislikeMessage: (message: Message) => void;
|
|
71
|
+
resetMessage: (message: Message) => void;
|
|
72
|
+
handleDragOver: (e: any) => void;
|
|
73
|
+
handleContainerDragOver: (e: any) => void;
|
|
74
|
+
handleContainerDrop: (e: any) => void;
|
|
75
|
+
handleContainerDragLeave: (e: any) => void;
|
|
76
|
+
}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _debounce2 = _interopRequireDefault(require("lodash/debounce"));
|
|
8
|
+
var _foundation = _interopRequireDefault(require("../base/foundation"));
|
|
9
|
+
var _constants = require("./constants");
|
|
10
|
+
var _semiAnimation = require("@douyinfe/semi-animation");
|
|
11
|
+
var _uuid = require("../utils/uuid");
|
|
12
|
+
var _a11y = require("../utils/a11y");
|
|
13
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
|
+
const {
|
|
15
|
+
PIC_PREFIX,
|
|
16
|
+
PIC_SUFFIX_ARRAY,
|
|
17
|
+
ROLE,
|
|
18
|
+
SCROLL_ANIMATION_TIME,
|
|
19
|
+
SHOW_SCROLL_GAP
|
|
20
|
+
} = _constants.strings;
|
|
21
|
+
class ChatFoundation extends _foundation.default {
|
|
22
|
+
constructor(adapter) {
|
|
23
|
+
super(Object.assign({}, adapter));
|
|
24
|
+
this.init = () => {
|
|
25
|
+
this.scrollToBottomImmediately();
|
|
26
|
+
this._adapter.registerWheelEvent();
|
|
27
|
+
};
|
|
28
|
+
this.destroy = () => {
|
|
29
|
+
this.animation && this.animation.destroy();
|
|
30
|
+
this._adapter.unRegisterWheelEvent();
|
|
31
|
+
};
|
|
32
|
+
this.stopGenerate = e => {
|
|
33
|
+
this._adapter.notifyStopGenerate(e);
|
|
34
|
+
};
|
|
35
|
+
this.scrollToBottomImmediately = () => {
|
|
36
|
+
const containerRef = this._adapter.getContainerRef();
|
|
37
|
+
const element = containerRef === null || containerRef === void 0 ? void 0 : containerRef.current;
|
|
38
|
+
if (element) {
|
|
39
|
+
element.scrollTop = element.scrollHeight;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
this.scrollToBottomWithAnimation = () => {
|
|
43
|
+
const duration = SCROLL_ANIMATION_TIME;
|
|
44
|
+
const containerRef = this._adapter.getContainerRef();
|
|
45
|
+
const element = containerRef === null || containerRef === void 0 ? void 0 : containerRef.current;
|
|
46
|
+
if (!element) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const from = element.scrollTop;
|
|
50
|
+
const to = element.scrollHeight;
|
|
51
|
+
this.animation = new _semiAnimation.Animation({
|
|
52
|
+
from: {
|
|
53
|
+
scrollTop: from
|
|
54
|
+
},
|
|
55
|
+
to: {
|
|
56
|
+
scrollTop: to
|
|
57
|
+
}
|
|
58
|
+
}, {
|
|
59
|
+
duration,
|
|
60
|
+
easing: 'easeInOutCubic'
|
|
61
|
+
});
|
|
62
|
+
this.animation.on('frame', _ref => {
|
|
63
|
+
let {
|
|
64
|
+
scrollTop
|
|
65
|
+
} = _ref;
|
|
66
|
+
element.scrollTop = scrollTop;
|
|
67
|
+
});
|
|
68
|
+
this.animation.start();
|
|
69
|
+
};
|
|
70
|
+
this.containerScroll = e => {
|
|
71
|
+
if (e.target !== e.currentTarget) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
e.persist();
|
|
75
|
+
const update = () => {
|
|
76
|
+
this.getScroll(e.target);
|
|
77
|
+
};
|
|
78
|
+
requestAnimationFrame(update);
|
|
79
|
+
};
|
|
80
|
+
this.getScroll = (0, _debounce2.default)(target => {
|
|
81
|
+
const scrollHeight = target.scrollHeight;
|
|
82
|
+
const clientHeight = target.clientHeight;
|
|
83
|
+
const scrollTop = target.scrollTop;
|
|
84
|
+
const {
|
|
85
|
+
backBottomVisible
|
|
86
|
+
} = this.getStates();
|
|
87
|
+
if (scrollHeight - scrollTop - clientHeight <= SHOW_SCROLL_GAP) {
|
|
88
|
+
if (backBottomVisible) {
|
|
89
|
+
this._adapter.setBackBottomVisible(false);
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
if (!backBottomVisible) {
|
|
93
|
+
this._adapter.setBackBottomVisible(true);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return scroll;
|
|
97
|
+
}, 100);
|
|
98
|
+
this.clearContext = e => {
|
|
99
|
+
const {
|
|
100
|
+
chats
|
|
101
|
+
} = this.getStates();
|
|
102
|
+
if (chats[chats.length - 1].role === ROLE.DIVIDER) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const dividerMessage = {
|
|
106
|
+
role: ROLE.DIVIDER,
|
|
107
|
+
id: (0, _uuid.getUuidv4)(),
|
|
108
|
+
createAt: Date.now()
|
|
109
|
+
};
|
|
110
|
+
const newChats = [...chats, dividerMessage];
|
|
111
|
+
this._adapter.notifyChatsChange(newChats);
|
|
112
|
+
this._adapter.notifyClearContext();
|
|
113
|
+
};
|
|
114
|
+
this.onMessageSend = (input, attachment) => {
|
|
115
|
+
let content;
|
|
116
|
+
if (Boolean(attachment) && attachment.length === 0) {
|
|
117
|
+
content = input;
|
|
118
|
+
} else {
|
|
119
|
+
content = [];
|
|
120
|
+
input && content.push({
|
|
121
|
+
type: 'text',
|
|
122
|
+
text: input
|
|
123
|
+
});
|
|
124
|
+
(attachment !== null && attachment !== void 0 ? attachment : []).map(item => {
|
|
125
|
+
var _a;
|
|
126
|
+
const {
|
|
127
|
+
fileInstance,
|
|
128
|
+
name = '',
|
|
129
|
+
url,
|
|
130
|
+
size
|
|
131
|
+
} = item;
|
|
132
|
+
const suffix = name.split('.').pop();
|
|
133
|
+
const isImg = ((_a = fileInstance === null || fileInstance === void 0 ? void 0 : fileInstance.type) === null || _a === void 0 ? void 0 : _a.startsWith(PIC_PREFIX)) || PIC_SUFFIX_ARRAY.includes(suffix);
|
|
134
|
+
if (isImg) {
|
|
135
|
+
content.push({
|
|
136
|
+
type: 'image_url',
|
|
137
|
+
image_url: {
|
|
138
|
+
url: url
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
} else {
|
|
142
|
+
content.push({
|
|
143
|
+
type: 'file_url',
|
|
144
|
+
file_url: {
|
|
145
|
+
url: url,
|
|
146
|
+
name: name,
|
|
147
|
+
size: size,
|
|
148
|
+
type: fileInstance === null || fileInstance === void 0 ? void 0 : fileInstance.type
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (content) {
|
|
155
|
+
const newMessage = {
|
|
156
|
+
role: ROLE.USER,
|
|
157
|
+
id: (0, _uuid.getUuidv4)(),
|
|
158
|
+
createAt: Date.now(),
|
|
159
|
+
content
|
|
160
|
+
};
|
|
161
|
+
this._adapter.notifyChatsChange([...this.getStates().chats, newMessage]);
|
|
162
|
+
}
|
|
163
|
+
this._adapter.setWheelScroll(false);
|
|
164
|
+
this._adapter.registerWheelEvent();
|
|
165
|
+
this._adapter.notifyMessageSend(input, attachment);
|
|
166
|
+
};
|
|
167
|
+
this.onHintClick = hint => {
|
|
168
|
+
const {
|
|
169
|
+
chats
|
|
170
|
+
} = this.getStates();
|
|
171
|
+
const newMessage = {
|
|
172
|
+
role: ROLE.USER,
|
|
173
|
+
id: (0, _uuid.getUuidv4)(),
|
|
174
|
+
createAt: Date.now(),
|
|
175
|
+
content: hint
|
|
176
|
+
};
|
|
177
|
+
const newChats = [...chats, newMessage];
|
|
178
|
+
this._adapter.notifyChatsChange(newChats);
|
|
179
|
+
this._adapter.notifyHintClick(hint);
|
|
180
|
+
};
|
|
181
|
+
this.onInputChange = props => {
|
|
182
|
+
this._adapter.notifyInputChange(props);
|
|
183
|
+
};
|
|
184
|
+
this.deleteMessage = message => {
|
|
185
|
+
const {
|
|
186
|
+
onMessageDelete,
|
|
187
|
+
onChatsChange
|
|
188
|
+
} = this.getProps();
|
|
189
|
+
const {
|
|
190
|
+
chats
|
|
191
|
+
} = this.getStates();
|
|
192
|
+
onMessageDelete === null || onMessageDelete === void 0 ? void 0 : onMessageDelete(message);
|
|
193
|
+
const newChats = chats.filter(item => item.id !== message.id);
|
|
194
|
+
onChatsChange === null || onChatsChange === void 0 ? void 0 : onChatsChange(newChats);
|
|
195
|
+
};
|
|
196
|
+
this.likeMessage = message => {
|
|
197
|
+
const {
|
|
198
|
+
chats
|
|
199
|
+
} = this.getStates();
|
|
200
|
+
this._adapter.notifyLikeMessage(message);
|
|
201
|
+
const index = chats.findIndex(item => item.id === message.id);
|
|
202
|
+
const newChat = Object.assign(Object.assign({}, chats[index]), {
|
|
203
|
+
like: !chats[index].like,
|
|
204
|
+
dislike: false
|
|
205
|
+
});
|
|
206
|
+
const newChats = [...chats];
|
|
207
|
+
newChats.splice(index, 1, newChat);
|
|
208
|
+
this._adapter.notifyChatsChange(newChats);
|
|
209
|
+
};
|
|
210
|
+
this.dislikeMessage = message => {
|
|
211
|
+
const {
|
|
212
|
+
chats
|
|
213
|
+
} = this.getStates();
|
|
214
|
+
this._adapter.notifyDislikeMessage(message);
|
|
215
|
+
const index = chats.findIndex(item => item.id === message.id);
|
|
216
|
+
const newChat = Object.assign(Object.assign({}, chats[index]), {
|
|
217
|
+
like: false,
|
|
218
|
+
dislike: !chats[index].dislike
|
|
219
|
+
});
|
|
220
|
+
const newChats = [...chats];
|
|
221
|
+
newChats.splice(index, 1, newChat);
|
|
222
|
+
this._adapter.notifyChatsChange(newChats);
|
|
223
|
+
};
|
|
224
|
+
this.resetMessage = message => {
|
|
225
|
+
const {
|
|
226
|
+
chats
|
|
227
|
+
} = this.getStates();
|
|
228
|
+
const lastMessage = chats[chats.length - 1];
|
|
229
|
+
const newLastChat = Object.assign(Object.assign({}, lastMessage), {
|
|
230
|
+
status: 'loading',
|
|
231
|
+
content: '',
|
|
232
|
+
id: (0, _uuid.getUuidv4)(),
|
|
233
|
+
createAt: Date.now()
|
|
234
|
+
});
|
|
235
|
+
const newChats = chats.slice(0, -1).concat(newLastChat);
|
|
236
|
+
this._adapter.notifyChatsChange(newChats);
|
|
237
|
+
const {
|
|
238
|
+
onMessageReset
|
|
239
|
+
} = this.getProps();
|
|
240
|
+
onMessageReset === null || onMessageReset === void 0 ? void 0 : onMessageReset(message);
|
|
241
|
+
};
|
|
242
|
+
this.handleDragOver = e => {
|
|
243
|
+
this._adapter.setUploadAreaVisible(true);
|
|
244
|
+
};
|
|
245
|
+
this.handleContainerDragOver = e => {
|
|
246
|
+
(0, _a11y.handlePrevent)(e);
|
|
247
|
+
};
|
|
248
|
+
this.handleContainerDrop = e => {
|
|
249
|
+
var _a;
|
|
250
|
+
this._adapter.setUploadAreaVisible(false);
|
|
251
|
+
this._adapter.manualUpload((_a = e === null || e === void 0 ? void 0 : e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files);
|
|
252
|
+
// 禁用默认实现,防止文件被打开
|
|
253
|
+
//Disable the default implementation, preventing files from being opened
|
|
254
|
+
(0, _a11y.handlePrevent)(e);
|
|
255
|
+
};
|
|
256
|
+
this.handleContainerDragLeave = e => {
|
|
257
|
+
(0, _a11y.handlePrevent)(e);
|
|
258
|
+
// 鼠标移动至 container 的子元素,则不做任何操作
|
|
259
|
+
// If the mouse moves to the child element of container, no operation will be performed.
|
|
260
|
+
const dropAreaElement = this._adapter.getDropAreaElement();
|
|
261
|
+
if (dropAreaElement !== e.target && dropAreaElement.contains(e.target)) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* 延迟隐藏 container ,防止父元素的 mouseOver 被触发,导致 container 无法隐藏
|
|
266
|
+
* Delay hiding of the container to prevent the parent element's mouseOver from being triggered,
|
|
267
|
+
* causing the container to be unable to be hidden.
|
|
268
|
+
*/
|
|
269
|
+
setTimeout(() => {
|
|
270
|
+
this._adapter.setUploadAreaVisible(false);
|
|
271
|
+
});
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
exports.default = ChatFoundation;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import BaseFoundation, { DefaultAdapter } from "../base/foundation";
|
|
2
|
+
export interface InputBoxAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
|
|
3
|
+
notifyInputChange: (props: {
|
|
4
|
+
inputValue: string;
|
|
5
|
+
attachment: any[];
|
|
6
|
+
}) => void;
|
|
7
|
+
setInputValue: (value: string) => void;
|
|
8
|
+
setAttachment: (attachment: any[]) => void;
|
|
9
|
+
notifySend: (content: string, attachment: any[]) => void;
|
|
10
|
+
}
|
|
11
|
+
export default class InputBoxFoundation<P = Record<string, any>, S = Record<string, any>> extends BaseFoundation<InputBoxAdapter<P, S>, P, S> {
|
|
12
|
+
constructor(adapter: InputBoxAdapter<P, S>);
|
|
13
|
+
onInputAreaChange: (value: string) => void;
|
|
14
|
+
onAttachmentAdd: (props: any) => void;
|
|
15
|
+
onAttachmentDelete: (props: any) => void;
|
|
16
|
+
onSend: (e: any) => void;
|
|
17
|
+
getDisableSend: () => any;
|
|
18
|
+
onEnterPress: (e: any) => void;
|
|
19
|
+
onPaste: (e: any) => void;
|
|
20
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _a11y = require("../utils/a11y");
|
|
8
|
+
var _foundation = _interopRequireDefault(require("../base/foundation"));
|
|
9
|
+
var _constants = require("./constants");
|
|
10
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
const {
|
|
12
|
+
SEND_HOT_KEY
|
|
13
|
+
} = _constants.strings;
|
|
14
|
+
class InputBoxFoundation extends _foundation.default {
|
|
15
|
+
constructor(adapter) {
|
|
16
|
+
super(Object.assign({}, adapter));
|
|
17
|
+
this.onInputAreaChange = value => {
|
|
18
|
+
const attachment = this.getState('attachment');
|
|
19
|
+
this._adapter.setInputValue(value);
|
|
20
|
+
this._adapter.notifyInputChange({
|
|
21
|
+
inputValue: value,
|
|
22
|
+
attachment
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
this.onAttachmentAdd = props => {
|
|
26
|
+
const {
|
|
27
|
+
fileList
|
|
28
|
+
} = props;
|
|
29
|
+
const {
|
|
30
|
+
uploadProps
|
|
31
|
+
} = this.getProps();
|
|
32
|
+
const {
|
|
33
|
+
onChange
|
|
34
|
+
} = uploadProps;
|
|
35
|
+
if (onChange) {
|
|
36
|
+
onChange(props);
|
|
37
|
+
}
|
|
38
|
+
const {
|
|
39
|
+
content
|
|
40
|
+
} = this.getStates();
|
|
41
|
+
let newFileList = [...fileList];
|
|
42
|
+
this._adapter.setAttachment(newFileList);
|
|
43
|
+
this._adapter.notifyInputChange({
|
|
44
|
+
inputValue: content,
|
|
45
|
+
attachment: newFileList
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
this.onAttachmentDelete = props => {
|
|
49
|
+
const {
|
|
50
|
+
content,
|
|
51
|
+
attachment
|
|
52
|
+
} = this.getStates();
|
|
53
|
+
const newAttachMent = attachment.filter(item => item.uid !== props.uid);
|
|
54
|
+
this._adapter.setAttachment(newAttachMent);
|
|
55
|
+
this._adapter.notifyInputChange({
|
|
56
|
+
inputValue: content,
|
|
57
|
+
attachment: newAttachMent
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
this.onSend = e => {
|
|
61
|
+
if (this.getDisableSend()) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const {
|
|
65
|
+
content,
|
|
66
|
+
attachment
|
|
67
|
+
} = this.getStates();
|
|
68
|
+
this._adapter.setInputValue('');
|
|
69
|
+
this._adapter.setAttachment([]);
|
|
70
|
+
this._adapter.notifySend(content, attachment);
|
|
71
|
+
};
|
|
72
|
+
this.getDisableSend = () => {
|
|
73
|
+
const {
|
|
74
|
+
content,
|
|
75
|
+
attachment
|
|
76
|
+
} = this.getStates();
|
|
77
|
+
const {
|
|
78
|
+
disableSend: disableSendInProps
|
|
79
|
+
} = this.getProps();
|
|
80
|
+
const disabledSend = disableSendInProps || content.length === 0 && attachment.length === 0;
|
|
81
|
+
return disabledSend;
|
|
82
|
+
};
|
|
83
|
+
this.onEnterPress = e => {
|
|
84
|
+
const {
|
|
85
|
+
sendHotKey
|
|
86
|
+
} = this.getProps();
|
|
87
|
+
if (sendHotKey === SEND_HOT_KEY.SHIFT_PLUS_ENTER && e.shiftKey === false) {
|
|
88
|
+
return;
|
|
89
|
+
} else if (sendHotKey === SEND_HOT_KEY.ENTER && e.shiftKey === true) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
(0, _a11y.handlePrevent)(e);
|
|
93
|
+
this.onSend(e);
|
|
94
|
+
};
|
|
95
|
+
this.onPaste = e => {
|
|
96
|
+
var _a;
|
|
97
|
+
const items = (_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.items;
|
|
98
|
+
const {
|
|
99
|
+
manualUpload
|
|
100
|
+
} = this.getProps();
|
|
101
|
+
let files = [];
|
|
102
|
+
if (items) {
|
|
103
|
+
for (const it of items) {
|
|
104
|
+
const file = it.getAsFile();
|
|
105
|
+
file && files.push(it.getAsFile());
|
|
106
|
+
}
|
|
107
|
+
if (files.length) {
|
|
108
|
+
// 文件上传,则需要阻止默认粘贴行为
|
|
109
|
+
// File upload, you need to prevent the default paste behavior
|
|
110
|
+
manualUpload(files);
|
|
111
|
+
e.preventDefault();
|
|
112
|
+
e.stopPropagation();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
exports.default = InputBoxFoundation;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
$module: #{$prefix}-chat;
|
|
3
|
+
|
|
4
|
+
.#{$prefix}-rtl,
|
|
5
|
+
.#{$prefix}-portal-rtl {
|
|
6
|
+
.#{$module} {
|
|
7
|
+
direction: rtl;
|
|
8
|
+
|
|
9
|
+
&-hint-icon {
|
|
10
|
+
transform: scaleX(-1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
&-inputBox-sendButton-icon {
|
|
14
|
+
transform: rotate(225deg);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
&-chatBox-action-icon-redo {
|
|
18
|
+
transform: scaleX(-1);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
}
|