@pmate/chat-sdk 0.1.16 → 0.1.18
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.
|
@@ -13,6 +13,7 @@ import { EmojiPicker } from "./EmojiPicker";
|
|
|
13
13
|
import { EmojiTrigger } from "./EmojiTrigger";
|
|
14
14
|
import { MoreTrigger } from "./ImageTrigger";
|
|
15
15
|
import { InputSurface } from "./InputSurface";
|
|
16
|
+
import { SendAction } from "./SendAction";
|
|
16
17
|
import { StatusHint } from "./StatusHint";
|
|
17
18
|
import { TextComposer } from "./TextComposer";
|
|
18
19
|
import { WaveformFeedback } from "./WaveformFeedback";
|
|
@@ -182,7 +183,7 @@ function DesktopInner(props) {
|
|
|
182
183
|
position: "absolute",
|
|
183
184
|
left: 0,
|
|
184
185
|
right: 0,
|
|
185
|
-
bottom: 66,
|
|
186
|
+
bottom: props.multiline ? 154 : 66,
|
|
186
187
|
padding: "12px 14px",
|
|
187
188
|
borderRadius: 24,
|
|
188
189
|
background: `color-mix(in srgb, ${tokens.color.surfaceInputFocus} 94%, transparent)`,
|
|
@@ -192,7 +193,46 @@ function DesktopInner(props) {
|
|
|
192
193
|
boxShadow: "0 18px 50px rgba(0, 0, 0, 0.16)",
|
|
193
194
|
backdropFilter: "blur(18px)",
|
|
194
195
|
zIndex: 3,
|
|
195
|
-
}, children: [_jsxs("button", { type: "button", style: attachmentActionStyle, disabled: props.disabled || isUploadingImage, onClick: () => imageInputRef.current?.click(), children: [_jsx("span", { style: attachmentIconStyle, children: _jsx(ImageOutlineIcon, { size: 24 }) }), "\u56FE\u7247"] }), _jsxs("button", { type: "button", style: attachmentActionStyle, disabled: props.disabled, onClick: () => fileInputRef.current?.click(), children: [_jsx("span", { style: attachmentIconStyle, children: _jsx(FileOutlineIcon, { size: 24 }) }), "\u6587\u4EF6"] })] })) : null, voice.status === "recording" ? (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(WaveformFeedback, { levels: voice.waveformLevels, tokens: tokens, compact: true }), _jsxs("span", { style: { color: tokens.color.textSecondary, fontSize: 12 }, children: [Math.max(1, Math.round(voice.durationMs / 1000)), "s"] })] })) : null, _jsxs(
|
|
196
|
+
}, children: [_jsxs("button", { type: "button", style: attachmentActionStyle, disabled: props.disabled || isUploadingImage, onClick: () => imageInputRef.current?.click(), children: [_jsx("span", { style: attachmentIconStyle, children: _jsx(ImageOutlineIcon, { size: 24 }) }), "\u56FE\u7247"] }), _jsxs("button", { type: "button", style: attachmentActionStyle, disabled: props.disabled, onClick: () => fileInputRef.current?.click(), children: [_jsx("span", { style: attachmentIconStyle, children: _jsx(FileOutlineIcon, { size: 24 }) }), "\u6587\u4EF6"] })] })) : null, voice.status === "recording" ? (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(WaveformFeedback, { levels: voice.waveformLevels, tokens: tokens, compact: true }), _jsxs("span", { style: { color: tokens.color.textSecondary, fontSize: 12 }, children: [Math.max(1, Math.round(voice.durationMs / 1000)), "s"] })] })) : null, props.multiline ? (_jsxs(InputSurface, { tokens: tokens, status: state.status, styleOverride: {
|
|
197
|
+
minHeight: 144,
|
|
198
|
+
padding: "16px 18px 12px",
|
|
199
|
+
display: "flex",
|
|
200
|
+
flexDirection: "column",
|
|
201
|
+
gap: 12,
|
|
202
|
+
}, children: [_jsx(TextComposer, { ref: textComposerRef, tokens: tokens, value: state.text, rows: 3, placeholder: "Message PMate", onKeyDown: (event) => {
|
|
203
|
+
if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
|
|
204
|
+
event.preventDefault();
|
|
205
|
+
if (state.text.trim() || state.attachments.length > 0)
|
|
206
|
+
void onSend();
|
|
207
|
+
}
|
|
208
|
+
}, onChange: (event) => {
|
|
209
|
+
state.setText(event.target.value);
|
|
210
|
+
state.setStatus(event.target.value.trim() ? "typing" : "idle");
|
|
211
|
+
props.onChange?.(event.target.value);
|
|
212
|
+
}, style: {
|
|
213
|
+
flex: 1,
|
|
214
|
+
minHeight: 64,
|
|
215
|
+
maxHeight: 180,
|
|
216
|
+
padding: 0,
|
|
217
|
+
overflowY: "auto",
|
|
218
|
+
caretColor: tokens.color.brandPrimary,
|
|
219
|
+
} }), _jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12 }, children: [_jsx(MoreTrigger, { "data-icon-size": 24, onClick: () => { setIsEmojiOpen(false); setIsMoreOpen((prev) => !prev); }, disabled: props.disabled, style: { ...sideActionStyle, color: isMoreOpen ? tokens.color.iconActive : tokens.color.iconDefault, opacity: props.disabled ? 0.4 : 1 } }), _jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [_jsx("button", { type: "button", onClick: () => {
|
|
220
|
+
if (props.disabled || props.enableVoice === false)
|
|
221
|
+
return;
|
|
222
|
+
if (voice.status === "recording") {
|
|
223
|
+
voice.stopRecording("transcribe");
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (voice.status === "transcribing")
|
|
227
|
+
return;
|
|
228
|
+
voice.beginVoiceMode();
|
|
229
|
+
voice.startRecording();
|
|
230
|
+
}, style: {
|
|
231
|
+
...sideActionStyle,
|
|
232
|
+
color: voice.status === "recording" || voice.status === "transcribing" ? tokens.color.iconActive : tokens.color.iconDefault,
|
|
233
|
+
cursor: props.disabled || props.enableVoice === false ? "not-allowed" : "pointer",
|
|
234
|
+
opacity: props.disabled || props.enableVoice === false ? 0.4 : 1,
|
|
235
|
+
}, "aria-label": voice.status === "recording" ? "停止录音并转文字" : voice.status === "transcribing" ? "正在转写语音" : "开始语音输入", children: voice.status === "recording" ? _jsx(StopCircleOutlineIcon, { size: 27 }) : _jsx(MicOutlineIcon, { size: 24, strokeWidth: 2 }) }), _jsx(EmojiTrigger, { ref: emojiAnchorRef, "data-icon-size": 24, style: sideActionStyle, onClick: () => { setIsMoreOpen(false); setIsEmojiOpen((prev) => !prev); } }), _jsx(SendAction, { tokens: tokens, disabled: props.disabled || state.status === "sending" || (!state.text.trim() && state.attachments.length === 0), "aria-label": "\u53D1\u9001\u6D88\u606F", onClick: () => void onSend(), style: { width: 40, height: 40, padding: 0, borderRadius: 999, fontSize: 24, lineHeight: "40px" }, children: "\u2191" })] })] })] })) : _jsxs("div", { style: {
|
|
196
236
|
display: "grid",
|
|
197
237
|
gridTemplateColumns: "32px minmax(0, 1fr) 32px 32px",
|
|
198
238
|
alignItems: "center",
|
|
@@ -1,6 +1,34 @@
|
|
|
1
|
-
export type ChatInputThemeName = "pmate" | "cli" | "compact";
|
|
1
|
+
export type ChatInputThemeName = "pmate" | "dark" | "cli" | "compact";
|
|
2
2
|
export declare const chatInputThemes: {
|
|
3
3
|
pmate: {};
|
|
4
|
+
dark: {
|
|
5
|
+
color: {
|
|
6
|
+
brandPrimary: string;
|
|
7
|
+
surfaceInputDefault: string;
|
|
8
|
+
surfaceInputFocus: string;
|
|
9
|
+
surfaceInputRecording: string;
|
|
10
|
+
surfaceInputError: string;
|
|
11
|
+
textPrimary: string;
|
|
12
|
+
textSecondary: string;
|
|
13
|
+
iconDefault: string;
|
|
14
|
+
iconActive: string;
|
|
15
|
+
actionSendDefault: string;
|
|
16
|
+
actionSendDisabled: string;
|
|
17
|
+
actionSendTextOnPrimary: string;
|
|
18
|
+
borderDefault: string;
|
|
19
|
+
borderFocus: string;
|
|
20
|
+
borderError: string;
|
|
21
|
+
statusError: string;
|
|
22
|
+
statusWarning: string;
|
|
23
|
+
statusSuccess: string;
|
|
24
|
+
voiceWaveformActive: string;
|
|
25
|
+
voiceWaveformBackground: string;
|
|
26
|
+
};
|
|
27
|
+
shadow: {
|
|
28
|
+
inputElevated: string;
|
|
29
|
+
recordingActive: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
4
32
|
cli: {
|
|
5
33
|
color: {
|
|
6
34
|
brandPrimary: string;
|
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
export const chatInputThemes = {
|
|
2
2
|
pmate: {},
|
|
3
|
+
dark: {
|
|
4
|
+
color: {
|
|
5
|
+
brandPrimary: "#8B7CF6",
|
|
6
|
+
surfaceInputDefault: "#171C23",
|
|
7
|
+
surfaceInputFocus: "#1D242D",
|
|
8
|
+
surfaceInputRecording: "#202839",
|
|
9
|
+
surfaceInputError: "#2B191D",
|
|
10
|
+
textPrimary: "#EEF1F5",
|
|
11
|
+
textSecondary: "#8E98A5",
|
|
12
|
+
iconDefault: "#7E8996",
|
|
13
|
+
iconActive: "#A99FFF",
|
|
14
|
+
actionSendDefault: "#7C6FE6",
|
|
15
|
+
actionSendDisabled: "#343A48",
|
|
16
|
+
actionSendTextOnPrimary: "#FFFFFF",
|
|
17
|
+
borderDefault: "#303844",
|
|
18
|
+
borderFocus: "#665CBF",
|
|
19
|
+
borderError: "#A84D59",
|
|
20
|
+
statusError: "#FF7D87",
|
|
21
|
+
statusWarning: "#E5A85E",
|
|
22
|
+
statusSuccess: "#45D495",
|
|
23
|
+
voiceWaveformActive: "#A99FFF",
|
|
24
|
+
voiceWaveformBackground: "#3B365F",
|
|
25
|
+
},
|
|
26
|
+
shadow: {
|
|
27
|
+
inputElevated: "0 8px 24px rgba(0, 0, 0, 0.24)",
|
|
28
|
+
recordingActive: "0 0 0 4px rgba(139, 124, 246, 0.18)",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
3
31
|
cli: {
|
|
4
32
|
color: {
|
|
5
33
|
brandPrimary: "#25D6A0",
|
package/lib/types/chatInput.d.ts
CHANGED
|
@@ -110,6 +110,8 @@ export type ChatImageConfig = {
|
|
|
110
110
|
uploadImage?: (file: File) => Promise<ChatImageUploadResult>;
|
|
111
111
|
};
|
|
112
112
|
export type ChatInputBaseProps = {
|
|
113
|
+
/** Use a taller composer with actions in a bottom toolbar. */
|
|
114
|
+
multiline?: boolean;
|
|
113
115
|
value?: string;
|
|
114
116
|
defaultValue?: string;
|
|
115
117
|
onChange?: (value: string) => void;
|