@webinex/chatify 2.0.1-alpha2 → 2.0.2-alpha2
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/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/ui/Conversation/InputBox/InputBoxFile.d.ts +1 -0
- package/dist/esm/types/ui/Conversation/InputBox/InputBoxFileList.d.ts +1 -0
- package/dist/esm/types/ui/Conversation/InputBox/InputFilesBox.d.ts +1 -0
- package/dist/esm/types/ui/Conversation/InputBox/InputSubmitButtonBox.d.ts +1 -0
- package/dist/esm/types/ui/Conversation/InputBox/InputTextBox.d.ts +1 -0
- package/dist/index.d.ts +5 -0
- package/package.json +1 -1
- package/src/ui/Conversation/InputBox/InputBox.tsx +24 -15
- package/src/ui/Conversation/InputBox/InputBoxFile.tsx +3 -1
- package/src/ui/Conversation/InputBox/InputBoxFileList.tsx +4 -2
- package/src/ui/Conversation/InputBox/InputFilesBox.tsx +4 -1
- package/src/ui/Conversation/InputBox/InputSubmitButtonBox.tsx +3 -1
- package/src/ui/Conversation/InputBox/InputTextBox.tsx +3 -1
- package/src/ui/Conversation/Message/MessageFile.tsx +21 -5
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { File } from '../../../core';
|
|
3
3
|
export interface InputBoxFileProps {
|
|
4
4
|
file: File;
|
|
5
|
+
disabled?: boolean;
|
|
5
6
|
onDelete: (file: File) => void;
|
|
6
7
|
}
|
|
7
8
|
export declare const InputBoxFile: import("../../customize").Customizable<import("react").ComponentType<InputBoxFileProps>>;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { File } from '../../../core';
|
|
3
3
|
export interface InputBoxFileListProps {
|
|
4
4
|
files: File[];
|
|
5
|
+
disabled?: boolean;
|
|
5
6
|
onDelete: (file: File) => void;
|
|
6
7
|
}
|
|
7
8
|
export declare const InputBoxFileList: import("../../customize").Customizable<import("react").ComponentType<InputBoxFileListProps>>;
|
|
@@ -3,6 +3,7 @@ export interface TextInputBoxProps {
|
|
|
3
3
|
value: string;
|
|
4
4
|
onChange: (value: string) => void;
|
|
5
5
|
onSend: (value: string) => void;
|
|
6
|
+
disabled?: boolean;
|
|
6
7
|
inputRef?: RefObject<HTMLTextAreaElement>;
|
|
7
8
|
}
|
|
8
9
|
export declare const InputTextBox: import("../../customize").Customizable<import("react").ComponentType<TextInputBoxProps>>;
|
package/dist/index.d.ts
CHANGED
|
@@ -13313,12 +13313,14 @@ declare const InputBox: Customizable<react.ComponentType<unknown>>;
|
|
|
13313
13313
|
|
|
13314
13314
|
interface InputBoxFileProps {
|
|
13315
13315
|
file: File;
|
|
13316
|
+
disabled?: boolean;
|
|
13316
13317
|
onDelete: (file: File) => void;
|
|
13317
13318
|
}
|
|
13318
13319
|
declare const InputBoxFile: Customizable<react.ComponentType<InputBoxFileProps>>;
|
|
13319
13320
|
|
|
13320
13321
|
interface InputBoxFileListProps {
|
|
13321
13322
|
files: File[];
|
|
13323
|
+
disabled?: boolean;
|
|
13322
13324
|
onDelete: (file: File) => void;
|
|
13323
13325
|
}
|
|
13324
13326
|
declare const InputBoxFileList: Customizable<react.ComponentType<InputBoxFileListProps>>;
|
|
@@ -13327,6 +13329,7 @@ interface InputFilesBoxProps {
|
|
|
13327
13329
|
value: File[];
|
|
13328
13330
|
accept?: string;
|
|
13329
13331
|
loading?: boolean;
|
|
13332
|
+
disabled?: boolean;
|
|
13330
13333
|
onAddedClick?: () => void;
|
|
13331
13334
|
onUpload: (value: globalThis.File[]) => void;
|
|
13332
13335
|
}
|
|
@@ -13336,6 +13339,7 @@ declare const InputFilesBox: Customizable<react.ComponentType<InputFilesBoxProps
|
|
|
13336
13339
|
interface InputSubmitButtonBoxProps {
|
|
13337
13340
|
onSubmit: () => void;
|
|
13338
13341
|
disabled?: boolean;
|
|
13342
|
+
loading?: boolean;
|
|
13339
13343
|
}
|
|
13340
13344
|
declare const InputSubmitButtonBox: Customizable<react.ComponentType<InputSubmitButtonBoxProps>>;
|
|
13341
13345
|
|
|
@@ -13343,6 +13347,7 @@ interface TextInputBoxProps {
|
|
|
13343
13347
|
value: string;
|
|
13344
13348
|
onChange: (value: string) => void;
|
|
13345
13349
|
onSend: (value: string) => void;
|
|
13350
|
+
disabled?: boolean;
|
|
13346
13351
|
inputRef?: RefObject<HTMLTextAreaElement>;
|
|
13347
13352
|
}
|
|
13348
13353
|
declare const InputTextBox: Customizable<react.ComponentType<TextInputBoxProps>>;
|
package/package.json
CHANGED
|
@@ -11,6 +11,7 @@ import { InputBoxFileList } from './InputBoxFileList';
|
|
|
11
11
|
function useFormState() {
|
|
12
12
|
const { onSend } = useConversation();
|
|
13
13
|
const [text, setText] = useState('');
|
|
14
|
+
const [sending, setSending] = useState(false);
|
|
14
15
|
const { onUpload, files, loading, setFiles, showFileBox, onDeleteFile } = useFlippoInputFileBox();
|
|
15
16
|
|
|
16
17
|
const onSubmit = useCallback(() => {
|
|
@@ -18,16 +19,17 @@ function useFormState() {
|
|
|
18
19
|
return;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
setSending(true);
|
|
23
|
+
Promise.resolve(onSend({ text, files }))
|
|
24
|
+
.finally(() => setSending(false))
|
|
25
|
+
.then(() => {
|
|
26
|
+
setFiles([]);
|
|
27
|
+
setText('');
|
|
28
|
+
});
|
|
27
29
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
28
30
|
}, [text, onSend, files, setFiles, loading]);
|
|
29
31
|
|
|
30
|
-
return [onSubmit, { text, setText, files, onUpload, loading, showFileBox, onDeleteFile }] as const;
|
|
32
|
+
return [onSubmit, { text, setText, files, onUpload, loading, showFileBox, onDeleteFile, sending }] as const;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
function useFlippoInputFileBox() {
|
|
@@ -64,26 +66,26 @@ function useFlippoInputFileBox() {
|
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
export const InputBox = customize('InputBox', () => {
|
|
67
|
-
const [onSend, { text, setText, files, loading, onUpload, showFileBox, onDeleteFile }] =
|
|
69
|
+
const [onSend, { text, setText, files, loading, onUpload, showFileBox, onDeleteFile, sending }] =
|
|
70
|
+
useFormState();
|
|
68
71
|
const inputRef = useRef<HTMLTextAreaElement>(null);
|
|
69
|
-
const [showFilesModal, setShowFilesModal] = useState(false);
|
|
70
72
|
const [showFileList, setShowFileList] = useState(false);
|
|
71
73
|
const toggleShowFileList = useCallback(() => setShowFileList((prev) => !prev), []);
|
|
72
74
|
|
|
73
75
|
useLayoutEffect(() => inputRef.current?.focus(), []);
|
|
74
76
|
|
|
75
77
|
useEffect(() => {
|
|
76
|
-
if (files.length === 0 &&
|
|
77
|
-
|
|
78
|
+
if (files.length === 0 && showFileList) {
|
|
79
|
+
setShowFileList(false);
|
|
78
80
|
}
|
|
79
|
-
}, [files,
|
|
81
|
+
}, [files, showFileList]);
|
|
80
82
|
|
|
81
83
|
return (
|
|
82
84
|
<div className="wxchtf-input-form">
|
|
83
85
|
<div className="wxchtf-input-box">
|
|
84
86
|
{showFileList && (
|
|
85
87
|
<div className="wxchtf-file-list-box">
|
|
86
|
-
<InputBoxFileList files={files} onDelete={onDeleteFile} />
|
|
88
|
+
<InputBoxFileList files={files} onDelete={onDeleteFile} disabled={sending} />
|
|
87
89
|
</div>
|
|
88
90
|
)}
|
|
89
91
|
<div className="wxchtf-input-box-row">
|
|
@@ -93,10 +95,17 @@ export const InputBox = customize('InputBox', () => {
|
|
|
93
95
|
onUpload={onUpload}
|
|
94
96
|
value={files}
|
|
95
97
|
loading={loading}
|
|
98
|
+
disabled={sending}
|
|
96
99
|
/>
|
|
97
100
|
)}
|
|
98
|
-
<InputTextBox
|
|
99
|
-
|
|
101
|
+
<InputTextBox
|
|
102
|
+
value={text}
|
|
103
|
+
onSend={onSend}
|
|
104
|
+
onChange={setText}
|
|
105
|
+
disabled={sending}
|
|
106
|
+
inputRef={inputRef}
|
|
107
|
+
/>
|
|
108
|
+
<InputSubmitButtonBox onSubmit={onSend} disabled={loading} loading={sending} />
|
|
100
109
|
</div>
|
|
101
110
|
</div>
|
|
102
111
|
</div>
|
|
@@ -7,11 +7,12 @@ import { customize } from '../../customize';
|
|
|
7
7
|
|
|
8
8
|
export interface InputBoxFileProps {
|
|
9
9
|
file: File;
|
|
10
|
+
disabled?: boolean;
|
|
10
11
|
onDelete: (file: File) => void;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export const InputBoxFile = customize('InputBoxFile', (props: InputBoxFileProps) => {
|
|
14
|
-
const { file, onDelete } = props;
|
|
15
|
+
const { file, disabled, onDelete } = props;
|
|
15
16
|
const formatter = useFormatter();
|
|
16
17
|
const onDeleteClick = useCallback(() => onDelete(file), [file, onDelete]);
|
|
17
18
|
|
|
@@ -25,6 +26,7 @@ export const InputBoxFile = customize('InputBoxFile', (props: InputBoxFileProps)
|
|
|
25
26
|
</div>
|
|
26
27
|
<div className="wxchtf-file-actions">
|
|
27
28
|
<Button
|
|
29
|
+
disabled={disabled}
|
|
28
30
|
className="wxchtf-delete"
|
|
29
31
|
type="link"
|
|
30
32
|
icon={<Icon type="delete-file" />}
|
|
@@ -4,15 +4,17 @@ import { InputBoxFile } from './InputBoxFile';
|
|
|
4
4
|
|
|
5
5
|
export interface InputBoxFileListProps {
|
|
6
6
|
files: File[];
|
|
7
|
+
disabled?: boolean;
|
|
7
8
|
onDelete: (file: File) => void;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export const InputBoxFileList = customize('InputBoxFileList', (props: InputBoxFileListProps) => {
|
|
11
|
-
const { files, onDelete } = props;
|
|
12
|
+
const { files, onDelete, disabled } = props;
|
|
13
|
+
|
|
12
14
|
return (
|
|
13
15
|
<div className="wxchtf-file-list">
|
|
14
16
|
{files.map((file) => (
|
|
15
|
-
<InputBoxFile key={file.ref} file={file} onDelete={onDelete} />
|
|
17
|
+
<InputBoxFile key={file.ref} file={file} onDelete={onDelete} disabled={disabled} />
|
|
16
18
|
))}
|
|
17
19
|
</div>
|
|
18
20
|
);
|
|
@@ -8,12 +8,13 @@ export interface InputFilesBoxProps {
|
|
|
8
8
|
value: File[];
|
|
9
9
|
accept?: string;
|
|
10
10
|
loading?: boolean;
|
|
11
|
+
disabled?: boolean;
|
|
11
12
|
onAddedClick?: () => void;
|
|
12
13
|
onUpload: (value: globalThis.File[]) => void;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export const InputFileButton = customize('InputFileButton', (props: InputFilesBoxProps) => {
|
|
16
|
-
const { onUpload, onAddedClick, accept, loading, value } = props;
|
|
17
|
+
const { onUpload, onAddedClick, accept, loading, value, disabled } = props;
|
|
17
18
|
const inputRef = useRef<HTMLInputElement | null>(null);
|
|
18
19
|
const onClick = useCallback(() => inputRef.current?.click(), []);
|
|
19
20
|
const countButtonRef = useRef<HTMLButtonElement | null>(null);
|
|
@@ -40,6 +41,7 @@ export const InputFileButton = customize('InputFileButton', (props: InputFilesBo
|
|
|
40
41
|
loading={loading}
|
|
41
42
|
onClick={onClick}
|
|
42
43
|
type="link"
|
|
44
|
+
disabled={disabled}
|
|
43
45
|
icon={<Icon type="attach" />}
|
|
44
46
|
className="wxchtf-add-files-btn"
|
|
45
47
|
/>
|
|
@@ -50,6 +52,7 @@ export const InputFileButton = customize('InputFileButton', (props: InputFilesBo
|
|
|
50
52
|
onAnimationIteration={onCountButtonAnimationEnd}
|
|
51
53
|
onClick={onAddedClick}
|
|
52
54
|
type="link"
|
|
55
|
+
disabled={disabled}
|
|
53
56
|
icon={<>+{value.length}</>}
|
|
54
57
|
/>
|
|
55
58
|
)}
|
|
@@ -5,10 +5,11 @@ import { Icon } from '../../common/Icon';
|
|
|
5
5
|
export interface InputSubmitButtonBoxProps {
|
|
6
6
|
onSubmit: () => void;
|
|
7
7
|
disabled?: boolean;
|
|
8
|
+
loading?: boolean;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export const InputSubmitButtonBox = customize('InputSubmitButtonBox', (props: InputSubmitButtonBoxProps) => {
|
|
11
|
-
const { onSubmit, disabled } = props;
|
|
12
|
+
const { onSubmit, disabled, loading } = props;
|
|
12
13
|
|
|
13
14
|
return (
|
|
14
15
|
<div className="wxchtf-submit-btn-box">
|
|
@@ -18,6 +19,7 @@ export const InputSubmitButtonBox = customize('InputSubmitButtonBox', (props: In
|
|
|
18
19
|
icon={<Icon type="send" />}
|
|
19
20
|
className="wxchtf-submit-btn"
|
|
20
21
|
disabled={disabled}
|
|
22
|
+
loading={loading}
|
|
21
23
|
/>
|
|
22
24
|
</div>
|
|
23
25
|
);
|
|
@@ -9,6 +9,7 @@ export interface TextInputBoxProps {
|
|
|
9
9
|
value: string;
|
|
10
10
|
onChange: (value: string) => void;
|
|
11
11
|
onSend: (value: string) => void;
|
|
12
|
+
disabled?: boolean;
|
|
12
13
|
inputRef?: RefObject<HTMLTextAreaElement>;
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -19,7 +20,7 @@ const AUTO_SIZE: TextAreaProps['autoSize'] = { maxRows: 5, minRows: 1 };
|
|
|
19
20
|
export const InputTextBox = customize(
|
|
20
21
|
'InputTextBox',
|
|
21
22
|
memo((props: TextInputBoxProps) => {
|
|
22
|
-
const { value, onChange, onSend, inputRef } = props;
|
|
23
|
+
const { value, onChange, onSend, disabled, inputRef } = props;
|
|
23
24
|
const localizer = useLocalizer();
|
|
24
25
|
|
|
25
26
|
const onInputChange = useCallback(
|
|
@@ -46,6 +47,7 @@ export const InputTextBox = customize(
|
|
|
46
47
|
className="wxchtf-text-input-textarea"
|
|
47
48
|
placeholder={localizer.input.placeholder()}
|
|
48
49
|
onKeyDown={onKeyDown}
|
|
50
|
+
disabled={disabled}
|
|
49
51
|
/>
|
|
50
52
|
</div>
|
|
51
53
|
);
|
|
@@ -4,7 +4,7 @@ import { customize, useCustomizeContext } from '../../customize';
|
|
|
4
4
|
import { useFormatter } from '../../useFormatter';
|
|
5
5
|
import { Icon } from '../../common';
|
|
6
6
|
import { ConversationCustomizeValue } from '../Conversation';
|
|
7
|
-
import { useCallback } from 'react';
|
|
7
|
+
import { useCallback, useState } from 'react';
|
|
8
8
|
|
|
9
9
|
function open(url: string) {
|
|
10
10
|
const w = window.open(url, '_blank');
|
|
@@ -15,17 +15,33 @@ export interface MessageFileProps {
|
|
|
15
15
|
file: File;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
function useOpen(props: MessageFileProps) {
|
|
19
19
|
const { file } = props;
|
|
20
20
|
const { flippo } = useCustomizeContext<ConversationCustomizeValue>();
|
|
21
|
-
const
|
|
21
|
+
const [isOpenFetching, setIsOpenFetching] = useState(false);
|
|
22
22
|
|
|
23
|
-
const onOpen = useCallback(
|
|
23
|
+
const onOpen = useCallback(
|
|
24
|
+
() =>
|
|
25
|
+
flippo &&
|
|
26
|
+
Promise.resolve(setIsOpenFetching(true))
|
|
27
|
+
.then(() => flippo!.getSasUrl(file.ref))
|
|
28
|
+
.then(open)
|
|
29
|
+
.finally(() => setIsOpenFetching(false)),
|
|
30
|
+
[flippo, file.ref],
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
return [onOpen, { isOpenFetching }] as const;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const MessageFile = customize('MessageFile', (props: MessageFileProps) => {
|
|
37
|
+
const { file } = props;
|
|
38
|
+
const formatter = useFormatter();
|
|
39
|
+
const [onOpen, { isOpenFetching }] = useOpen(props);
|
|
24
40
|
|
|
25
41
|
return (
|
|
26
42
|
<div className="wxchtf-file">
|
|
27
43
|
<div className="wxchtf-icon">
|
|
28
|
-
<Button onClick={onOpen} type="link" icon={<Icon type="open-file" />} />
|
|
44
|
+
<Button loading={isOpenFetching} onClick={onOpen} type="link" icon={<Icon type="open-file" />} />
|
|
29
45
|
</div>
|
|
30
46
|
<div className="wxchtf-file-info">
|
|
31
47
|
<div className="wxchtf-name">{file.name}</div>
|