@jupyter/chat 0.19.0-alpha.1 → 0.19.0-alpha.3
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/lib/components/attachments.js +3 -3
- package/lib/components/chat.d.ts +3 -7
- package/lib/components/chat.js +9 -5
- package/lib/components/code-blocks/code-toolbar.js +8 -28
- package/lib/components/code-blocks/copy-button.js +4 -11
- package/lib/components/input/buttons/attach-button.js +3 -10
- package/lib/components/input/buttons/cancel-button.js +6 -10
- package/lib/components/input/buttons/save-edit-button.js +6 -13
- package/lib/components/input/buttons/send-button.js +8 -23
- package/lib/components/input/buttons/stop-button.js +6 -23
- package/lib/components/input/chat-input.d.ts +0 -20
- package/lib/components/input/chat-input.js +22 -22
- package/lib/components/messages/footer.d.ts +5 -5
- package/lib/components/messages/footer.js +7 -2
- package/lib/components/messages/header.js +10 -8
- package/lib/components/messages/message-renderer.d.ts +0 -10
- package/lib/components/messages/message-renderer.js +5 -3
- package/lib/components/messages/message.d.ts +8 -4
- package/lib/components/messages/message.js +4 -2
- package/lib/components/messages/messages.d.ts +1 -39
- package/lib/components/messages/messages.js +31 -13
- package/lib/components/messages/navigation.d.ts +1 -2
- package/lib/components/messages/navigation.js +2 -1
- package/lib/components/messages/toolbar.js +12 -26
- package/lib/components/messages/welcome.d.ts +10 -2
- package/lib/components/messages/welcome.js +2 -1
- package/lib/components/mui-extras/tooltipped-button.d.ts +6 -0
- package/lib/components/mui-extras/tooltipped-button.js +6 -7
- package/lib/components/mui-extras/tooltipped-icon-button.d.ts +12 -17
- package/lib/components/mui-extras/tooltipped-icon-button.js +10 -7
- package/lib/context.d.ts +3 -2
- package/lib/context.js +9 -2
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/theme-provider.d.ts +19 -0
- package/lib/theme-provider.js +74 -3
- package/lib/tokens.d.ts +11 -0
- package/lib/tokens.js +9 -0
- package/lib/types.d.ts +4 -0
- package/lib/widgets/chat-widget.d.ts +9 -0
- package/lib/widgets/chat-widget.js +44 -1
- package/lib/widgets/multichat-panel.d.ts +1 -6
- package/lib/widgets/multichat-panel.js +4 -14
- package/package.json +3 -1
- package/src/components/attachments.tsx +3 -3
- package/src/components/chat.tsx +13 -24
- package/src/components/code-blocks/code-toolbar.tsx +29 -55
- package/src/components/code-blocks/copy-button.tsx +13 -20
- package/src/components/input/buttons/attach-button.tsx +4 -12
- package/src/components/input/buttons/cancel-button.tsx +11 -18
- package/src/components/input/buttons/save-edit-button.tsx +13 -22
- package/src/components/input/buttons/send-button.tsx +16 -34
- package/src/components/input/buttons/stop-button.tsx +13 -34
- package/src/components/input/chat-input.tsx +25 -44
- package/src/components/messages/footer.tsx +12 -10
- package/src/components/messages/header.tsx +23 -17
- package/src/components/messages/message-renderer.tsx +5 -13
- package/src/components/messages/message.tsx +4 -7
- package/src/components/messages/messages.tsx +73 -97
- package/src/components/messages/navigation.tsx +3 -3
- package/src/components/messages/toolbar.tsx +19 -33
- package/src/components/messages/welcome.tsx +13 -2
- package/src/components/mui-extras/tooltipped-button.tsx +10 -5
- package/src/components/mui-extras/tooltipped-icon-button.tsx +19 -24
- package/src/context.ts +15 -5
- package/src/index.ts +1 -0
- package/src/theme-provider.ts +95 -3
- package/src/tokens.ts +24 -0
- package/src/types.ts +4 -0
- package/src/widgets/chat-widget.tsx +52 -1
- package/src/widgets/multichat-panel.tsx +12 -27
- package/style/chat.css +10 -0
- package/style/input.css +4 -0
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import CloseIcon from '@mui/icons-material/Close';
|
|
6
6
|
import { Box, Button, Tooltip } from '@mui/material';
|
|
7
|
-
import React
|
|
7
|
+
import React from 'react';
|
|
8
8
|
import { PathExt } from '@jupyterlab/coreutils';
|
|
9
9
|
import { UUID } from '@lumino/coreutils';
|
|
10
|
-
import {
|
|
10
|
+
import { useChatContext } from '../context';
|
|
11
11
|
const ATTACHMENT_CLASS = 'jp-chat-attachment';
|
|
12
12
|
const ATTACHMENT_CLICKABLE_CLASS = 'jp-chat-attachment-clickable';
|
|
13
13
|
const REMOVE_BUTTON_CLASS = 'jp-chat-attachment-remove';
|
|
@@ -52,7 +52,7 @@ export function AttachmentPreviewList(props) {
|
|
|
52
52
|
*/
|
|
53
53
|
export function AttachmentPreview(props) {
|
|
54
54
|
const remove_tooltip = 'Remove attachment';
|
|
55
|
-
const attachmentOpenerRegistry =
|
|
55
|
+
const { attachmentOpenerRegistry } = useChatContext();
|
|
56
56
|
const isClickable = !!(attachmentOpenerRegistry === null || attachmentOpenerRegistry === void 0 ? void 0 : attachmentOpenerRegistry.get(props.attachment.type));
|
|
57
57
|
return (React.createElement(Box, { className: ATTACHMENT_CLASS, sx: {
|
|
58
58
|
border: '1px solid var(--jp-border-color1)',
|
package/lib/components/chat.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { IInputToolbarRegistry } from './input';
|
|
|
5
5
|
import { IChatModel } from '../model';
|
|
6
6
|
import { IAttachmentOpenerRegistry, IChatCommandRegistry, IMessageFooterRegistry } from '../registers';
|
|
7
7
|
import { ChatArea } from '../types';
|
|
8
|
-
export declare function ChatBody(props: Chat.
|
|
8
|
+
export declare function ChatBody(props: Chat.IChatProps): JSX.Element;
|
|
9
9
|
export declare function Chat(props: Chat.IOptions): JSX.Element;
|
|
10
10
|
/**
|
|
11
11
|
* The chat UI namespace
|
|
@@ -14,7 +14,7 @@ export declare namespace Chat {
|
|
|
14
14
|
/**
|
|
15
15
|
* The props for the chat body component.
|
|
16
16
|
*/
|
|
17
|
-
interface
|
|
17
|
+
interface IChatProps {
|
|
18
18
|
/**
|
|
19
19
|
* The chat model.
|
|
20
20
|
*/
|
|
@@ -51,15 +51,11 @@ export declare namespace Chat {
|
|
|
51
51
|
/**
|
|
52
52
|
* The options to build the Chat UI.
|
|
53
53
|
*/
|
|
54
|
-
interface IOptions extends
|
|
54
|
+
interface IOptions extends IChatProps {
|
|
55
55
|
/**
|
|
56
56
|
* The theme manager.
|
|
57
57
|
*/
|
|
58
58
|
themeManager?: IThemeManager | null;
|
|
59
|
-
/**
|
|
60
|
-
* The view to render.
|
|
61
|
-
*/
|
|
62
|
-
chatView?: View;
|
|
63
59
|
/**
|
|
64
60
|
* A settings panel that can be used for dedicated settings (e.g. jupyter-ai)
|
|
65
61
|
*/
|
package/lib/components/chat.js
CHANGED
|
@@ -10,7 +10,7 @@ import React, { useState } from 'react';
|
|
|
10
10
|
import { ChatInput, InputToolbarRegistry } from './input';
|
|
11
11
|
import { JlThemeProvider } from './jl-theme-provider';
|
|
12
12
|
import { ChatMessages } from './messages';
|
|
13
|
-
import {
|
|
13
|
+
import { ChatReactContext } from '../context';
|
|
14
14
|
export function ChatBody(props) {
|
|
15
15
|
const { model } = props;
|
|
16
16
|
let { inputToolbarRegistry } = props;
|
|
@@ -19,18 +19,22 @@ export function ChatBody(props) {
|
|
|
19
19
|
}
|
|
20
20
|
// const horizontalPadding = props.area === 'main' ? 8 : 4;
|
|
21
21
|
const horizontalPadding = 4;
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const contextValue = {
|
|
23
|
+
...props,
|
|
24
|
+
inputToolbarRegistry
|
|
25
|
+
};
|
|
26
|
+
return (React.createElement(ChatReactContext.Provider, { value: contextValue },
|
|
27
|
+
React.createElement(ChatMessages, null),
|
|
24
28
|
React.createElement(ChatInput, { sx: {
|
|
25
29
|
paddingLeft: horizontalPadding,
|
|
26
30
|
paddingRight: horizontalPadding,
|
|
27
31
|
paddingTop: 0,
|
|
28
32
|
paddingBottom: 0
|
|
29
|
-
}, model: model.input
|
|
33
|
+
}, model: model.input })));
|
|
30
34
|
}
|
|
31
35
|
export function Chat(props) {
|
|
32
36
|
var _a;
|
|
33
|
-
const [view, setView] = useState(
|
|
37
|
+
const [view, setView] = useState(Chat.View.chat);
|
|
34
38
|
return (React.createElement(JlThemeProvider, { themeManager: (_a = props.themeManager) !== null && _a !== void 0 ? _a : null },
|
|
35
39
|
React.createElement(Box
|
|
36
40
|
// Add .jp-ThemedContainer for CSS compatibility in both JL <4.3.0 and >=4.3.0.
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
import { addAboveIcon, addBelowIcon } from '@jupyterlab/ui-components';
|
|
6
|
-
import { Box
|
|
6
|
+
import { Box } from '@mui/material';
|
|
7
7
|
import React, { useEffect, useState } from 'react';
|
|
8
8
|
import { CopyButton } from './copy-button';
|
|
9
|
+
import { TooltippedIconButton } from '../mui-extras';
|
|
9
10
|
import { replaceCellIcon } from '../../icons';
|
|
10
11
|
const CODE_TOOLBAR_CLASS = 'jp-chat-code-toolbar';
|
|
11
12
|
const CODE_TOOLBAR_ITEM_CLASS = 'jp-chat-code-toolbar-item';
|
|
@@ -63,29 +64,15 @@ function InsertAboveButton(props) {
|
|
|
63
64
|
const tooltip = props.activeCellAvailable
|
|
64
65
|
? 'Insert above active cell'
|
|
65
66
|
: 'Insert above active cell (no active cell)';
|
|
66
|
-
return (React.createElement(
|
|
67
|
-
React.createElement("
|
|
68
|
-
React.createElement(IconButton, { className: props.className, onClick: () => { var _a; return (_a = props.activeCellManager) === null || _a === void 0 ? void 0 : _a.insertAbove(props.content); }, disabled: !props.activeCellAvailable, "aria-label": tooltip, sx: {
|
|
69
|
-
lineHeight: 0,
|
|
70
|
-
'&.Mui-disabled': {
|
|
71
|
-
opacity: 0.5
|
|
72
|
-
}
|
|
73
|
-
} },
|
|
74
|
-
React.createElement(addAboveIcon.react, { height: "16px", width: "16px" })))));
|
|
67
|
+
return (React.createElement(TooltippedIconButton, { className: props.className, tooltip: tooltip, onClick: () => { var _a; return (_a = props.activeCellManager) === null || _a === void 0 ? void 0 : _a.insertAbove(props.content); }, disabled: !props.activeCellAvailable, inputToolbar: false },
|
|
68
|
+
React.createElement(addAboveIcon.react, { height: "16px", width: "16px" })));
|
|
75
69
|
}
|
|
76
70
|
function InsertBelowButton(props) {
|
|
77
71
|
const tooltip = props.activeCellAvailable
|
|
78
72
|
? 'Insert below active cell'
|
|
79
73
|
: 'Insert below active cell (no active cell)';
|
|
80
|
-
return (React.createElement(
|
|
81
|
-
React.createElement("
|
|
82
|
-
React.createElement(IconButton, { className: props.className, disabled: !props.activeCellAvailable, onClick: () => { var _a; return (_a = props.activeCellManager) === null || _a === void 0 ? void 0 : _a.insertBelow(props.content); }, "aria-label": tooltip, sx: {
|
|
83
|
-
lineHeight: 0,
|
|
84
|
-
'&.Mui-disabled': {
|
|
85
|
-
opacity: 0.5
|
|
86
|
-
}
|
|
87
|
-
} },
|
|
88
|
-
React.createElement(addBelowIcon.react, { height: "16px", width: "16px" })))));
|
|
74
|
+
return (React.createElement(TooltippedIconButton, { className: props.className, tooltip: tooltip, disabled: !props.activeCellAvailable, onClick: () => { var _a; return (_a = props.activeCellManager) === null || _a === void 0 ? void 0 : _a.insertBelow(props.content); }, inputToolbar: false },
|
|
75
|
+
React.createElement(addBelowIcon.react, { height: "16px", width: "16px" })));
|
|
89
76
|
}
|
|
90
77
|
function ReplaceButton(props) {
|
|
91
78
|
var _a, _b;
|
|
@@ -111,13 +98,6 @@ function ReplaceButton(props) {
|
|
|
111
98
|
(_c = props.activeCellManager) === null || _c === void 0 ? void 0 : _c.replace(props.content);
|
|
112
99
|
}
|
|
113
100
|
};
|
|
114
|
-
return (React.createElement(
|
|
115
|
-
React.createElement("
|
|
116
|
-
React.createElement(IconButton, { className: props.className, disabled: disabled, onClick: replace, "aria-label": tooltip, sx: {
|
|
117
|
-
lineHeight: 0,
|
|
118
|
-
'&.Mui-disabled': {
|
|
119
|
-
opacity: 0.5
|
|
120
|
-
}
|
|
121
|
-
} },
|
|
122
|
-
React.createElement(replaceCellIcon.react, { height: "16px", width: "16px" })))));
|
|
101
|
+
return (React.createElement(TooltippedIconButton, { className: props.className, tooltip: tooltip, disabled: disabled, onClick: replace, inputToolbar: false },
|
|
102
|
+
React.createElement(replaceCellIcon.react, { height: "16px", width: "16px" })));
|
|
123
103
|
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Copyright (c) Jupyter Development Team.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
-
import React, { useState, useCallback, useRef } from 'react';
|
|
6
5
|
import { copyIcon } from '@jupyterlab/ui-components';
|
|
7
|
-
import {
|
|
6
|
+
import React, { useState, useCallback, useRef } from 'react';
|
|
7
|
+
import { TooltippedIconButton } from '../mui-extras';
|
|
8
8
|
var CopyStatus;
|
|
9
9
|
(function (CopyStatus) {
|
|
10
10
|
CopyStatus[CopyStatus["None"] = 0] = "None";
|
|
@@ -42,13 +42,6 @@ export function CopyButton(props) {
|
|
|
42
42
|
timeoutId.current = window.setTimeout(() => setCopyStatus(CopyStatus.None), 1000);
|
|
43
43
|
}, [copyStatus, props.value]);
|
|
44
44
|
const tooltip = COPYBTN_TEXT_BY_STATUS[copyStatus];
|
|
45
|
-
return (React.createElement(
|
|
46
|
-
React.createElement("
|
|
47
|
-
React.createElement(IconButton, { disabled: isCopyDisabled, className: props.className, onClick: copy, "aria-label": "Copy to clipboard", sx: {
|
|
48
|
-
lineHeight: 0,
|
|
49
|
-
'&.Mui-disabled': {
|
|
50
|
-
opacity: 0.5
|
|
51
|
-
}
|
|
52
|
-
} },
|
|
53
|
-
React.createElement(copyIcon.react, { height: "16px", width: "16px" })))));
|
|
45
|
+
return (React.createElement(TooltippedIconButton, { disabled: isCopyDisabled, className: props.className, tooltip: tooltip, placement: "top", onClick: copy, "aria-label": "Copy to clipboard", inputToolbar: false },
|
|
46
|
+
React.createElement(copyIcon.react, { height: "16px", width: "16px" })));
|
|
54
47
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { FileDialog } from '@jupyterlab/filebrowser';
|
|
6
6
|
import AttachFileIcon from '@mui/icons-material/AttachFile';
|
|
7
7
|
import React from 'react';
|
|
8
|
-
import {
|
|
8
|
+
import { TooltippedIconButton } from '../../mui-extras';
|
|
9
9
|
const ATTACH_BUTTON_CLASS = 'jp-chat-attach-button';
|
|
10
10
|
/**
|
|
11
11
|
* The attach button.
|
|
@@ -38,16 +38,9 @@ export function AttachButton(props) {
|
|
|
38
38
|
console.warn('Error selecting files to attach', e);
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
|
-
return (React.createElement(
|
|
42
|
-
size: 'small',
|
|
43
|
-
variant: 'text',
|
|
41
|
+
return (React.createElement(TooltippedIconButton, { onClick: onclick, tooltip: tooltip, buttonProps: {
|
|
44
42
|
title: tooltip,
|
|
45
43
|
className: ATTACH_BUTTON_CLASS
|
|
46
|
-
}, sx: {
|
|
47
|
-
width: '24px',
|
|
48
|
-
height: '24px',
|
|
49
|
-
minWidth: '24px',
|
|
50
|
-
color: 'gray'
|
|
51
44
|
} },
|
|
52
|
-
React.createElement(AttachFileIcon,
|
|
45
|
+
React.createElement(AttachFileIcon, null)));
|
|
53
46
|
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
import CloseIcon from '@mui/icons-material/Close';
|
|
6
|
-
import { IconButton, Tooltip } from '@mui/material';
|
|
7
6
|
import React from 'react';
|
|
7
|
+
import { TooltippedIconButton } from '../../mui-extras';
|
|
8
8
|
const CANCEL_BUTTON_CLASS = 'jp-chat-cancel-button';
|
|
9
9
|
/**
|
|
10
10
|
* The cancel button.
|
|
@@ -14,13 +14,9 @@ export function CancelButton(props) {
|
|
|
14
14
|
return React.createElement(React.Fragment, null);
|
|
15
15
|
}
|
|
16
16
|
const tooltip = 'Cancel editing';
|
|
17
|
-
return (React.createElement(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
padding: 0,
|
|
23
|
-
lineHeight: 0
|
|
24
|
-
} },
|
|
25
|
-
React.createElement(CloseIcon, { sx: { fontSize: '16px' } })))));
|
|
17
|
+
return (React.createElement(TooltippedIconButton, { onClick: props.model.cancel, tooltip: tooltip, buttonProps: {
|
|
18
|
+
title: tooltip,
|
|
19
|
+
className: CANCEL_BUTTON_CLASS
|
|
20
|
+
} },
|
|
21
|
+
React.createElement(CloseIcon, null)));
|
|
26
22
|
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
import CheckIcon from '@mui/icons-material/Check';
|
|
6
|
-
import { IconButton, Tooltip } from '@mui/material';
|
|
7
6
|
import React, { useEffect, useState } from 'react';
|
|
7
|
+
import { TooltippedIconButton } from '../../mui-extras';
|
|
8
8
|
const SAVE_EDIT_BUTTON_CLASS = 'jp-chat-save-edit-button';
|
|
9
9
|
/**
|
|
10
10
|
* The save edit button.
|
|
@@ -36,16 +36,9 @@ export function SaveEditButton(props) {
|
|
|
36
36
|
await (chatCommandRegistry === null || chatCommandRegistry === void 0 ? void 0 : chatCommandRegistry.onSubmit(model));
|
|
37
37
|
model.send(model.value);
|
|
38
38
|
}
|
|
39
|
-
return (React.createElement(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
padding: 0,
|
|
45
|
-
lineHeight: 0,
|
|
46
|
-
'&.Mui-disabled': {
|
|
47
|
-
opacity: 0.5
|
|
48
|
-
}
|
|
49
|
-
} },
|
|
50
|
-
React.createElement(CheckIcon, { sx: { fontSize: '16px' } })))));
|
|
39
|
+
return (React.createElement(TooltippedIconButton, { onClick: save, tooltip: tooltip, disabled: disabled, buttonProps: {
|
|
40
|
+
title: tooltip,
|
|
41
|
+
className: SAVE_EDIT_BUTTON_CLASS
|
|
42
|
+
}, "aria-label": tooltip },
|
|
43
|
+
React.createElement(CheckIcon, null)));
|
|
51
44
|
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
|
|
6
|
-
import { Button, Tooltip } from '@mui/material';
|
|
7
6
|
import React, { useEffect, useState } from 'react';
|
|
7
|
+
import { TooltippedIconButton } from '../../mui-extras';
|
|
8
8
|
const SEND_BUTTON_CLASS = 'jp-chat-send-button';
|
|
9
9
|
/**
|
|
10
10
|
* The send button.
|
|
@@ -33,6 +33,8 @@ export function SendButton(props) {
|
|
|
33
33
|
: 'Send message (ENTER)');
|
|
34
34
|
};
|
|
35
35
|
model.configChanged.connect(configChanged);
|
|
36
|
+
// Initialize the tooltip.
|
|
37
|
+
configChanged(model, model.config);
|
|
36
38
|
return () => {
|
|
37
39
|
var _a, _b;
|
|
38
40
|
model.valueChanged.disconnect(inputChanged);
|
|
@@ -51,26 +53,9 @@ export function SendButton(props) {
|
|
|
51
53
|
model.value = '';
|
|
52
54
|
model.focus();
|
|
53
55
|
}
|
|
54
|
-
return (React.createElement(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
minWidth: '24px',
|
|
60
|
-
width: '24px',
|
|
61
|
-
height: '24px',
|
|
62
|
-
borderRadius: '4px',
|
|
63
|
-
boxShadow: 'none',
|
|
64
|
-
lineHeight: 0,
|
|
65
|
-
'&:hover': {
|
|
66
|
-
backgroundColor: 'var(--jp-brand-color0)',
|
|
67
|
-
boxShadow: 'none'
|
|
68
|
-
},
|
|
69
|
-
'&.Mui-disabled': {
|
|
70
|
-
backgroundColor: 'var(--jp-border-color2)',
|
|
71
|
-
color: 'var(--jp-ui-font-color3)',
|
|
72
|
-
opacity: 0.5
|
|
73
|
-
}
|
|
74
|
-
} },
|
|
75
|
-
React.createElement(ArrowUpwardIcon, { sx: { fontSize: '16px' } })))));
|
|
56
|
+
return (React.createElement(TooltippedIconButton, { onClick: send, tooltip: tooltip, disabled: disabled, buttonProps: {
|
|
57
|
+
title: tooltip,
|
|
58
|
+
className: SEND_BUTTON_CLASS
|
|
59
|
+
}, "aria-label": tooltip },
|
|
60
|
+
React.createElement(ArrowUpwardIcon, null)));
|
|
76
61
|
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
import StopIcon from '@mui/icons-material/Stop';
|
|
6
|
-
import { Button, Tooltip } from '@mui/material';
|
|
7
6
|
import React, { useEffect, useState } from 'react';
|
|
7
|
+
import { TooltippedIconButton } from '../../mui-extras';
|
|
8
8
|
const STOP_BUTTON_CLASS = 'jp-chat-stop-button';
|
|
9
9
|
/**
|
|
10
10
|
* The stop button.
|
|
@@ -38,26 +38,9 @@ export function StopButton(props) {
|
|
|
38
38
|
// This will need to be implemented based on how the chat model handles stopping AI responses
|
|
39
39
|
console.log('Stop button clicked');
|
|
40
40
|
}
|
|
41
|
-
return (React.createElement(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
minWidth: '24px',
|
|
47
|
-
width: '24px',
|
|
48
|
-
height: '24px',
|
|
49
|
-
borderRadius: '4px',
|
|
50
|
-
boxShadow: 'none',
|
|
51
|
-
lineHeight: 0,
|
|
52
|
-
'&:hover': {
|
|
53
|
-
backgroundColor: 'var(--jp-error-color0)',
|
|
54
|
-
boxShadow: 'none'
|
|
55
|
-
},
|
|
56
|
-
'&.Mui-disabled': {
|
|
57
|
-
backgroundColor: 'var(--jp-border-color2)',
|
|
58
|
-
color: 'var(--jp-ui-font-color3)',
|
|
59
|
-
opacity: 0.5
|
|
60
|
-
}
|
|
61
|
-
} },
|
|
62
|
-
React.createElement(StopIcon, { sx: { fontSize: '16px' } })))));
|
|
41
|
+
return (React.createElement(TooltippedIconButton, { onClick: stop, tooltip: tooltip, disabled: disabled, buttonProps: {
|
|
42
|
+
title: tooltip,
|
|
43
|
+
className: STOP_BUTTON_CLASS
|
|
44
|
+
}, "aria-label": tooltip },
|
|
45
|
+
React.createElement(StopIcon, null)));
|
|
63
46
|
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { SxProps, Theme } from '@mui/material';
|
|
3
|
-
import { IInputToolbarRegistry } from '.';
|
|
4
3
|
import { IInputModel } from '../../input-model';
|
|
5
|
-
import { IChatCommandRegistry } from '../../registers';
|
|
6
|
-
import { ChatArea } from '../../types';
|
|
7
|
-
import { IChatModel } from '../../model';
|
|
8
4
|
export declare function ChatInput(props: ChatInput.IProps): JSX.Element;
|
|
9
5
|
/**
|
|
10
6
|
* The chat input namespace.
|
|
@@ -18,10 +14,6 @@ export declare namespace ChatInput {
|
|
|
18
14
|
* The input model.
|
|
19
15
|
*/
|
|
20
16
|
model: IInputModel;
|
|
21
|
-
/**
|
|
22
|
-
* The toolbar registry.
|
|
23
|
-
*/
|
|
24
|
-
toolbarRegistry: IInputToolbarRegistry;
|
|
25
17
|
/**
|
|
26
18
|
* The function to be called to cancel editing.
|
|
27
19
|
*/
|
|
@@ -30,18 +22,6 @@ export declare namespace ChatInput {
|
|
|
30
22
|
* Custom mui/material styles.
|
|
31
23
|
*/
|
|
32
24
|
sx?: SxProps<Theme>;
|
|
33
|
-
/**
|
|
34
|
-
* Chat command registry.
|
|
35
|
-
*/
|
|
36
|
-
chatCommandRegistry?: IChatCommandRegistry;
|
|
37
|
-
/**
|
|
38
|
-
* The area where the chat is displayed.
|
|
39
|
-
*/
|
|
40
|
-
area?: ChatArea;
|
|
41
|
-
/**
|
|
42
|
-
* The chat model.
|
|
43
|
-
*/
|
|
44
|
-
chatModel?: IChatModel;
|
|
45
25
|
/**
|
|
46
26
|
* Whether the input is in edit mode (editing an existing message).
|
|
47
27
|
* Defaults to false (new message mode).
|
|
@@ -5,22 +5,24 @@
|
|
|
5
5
|
import { Autocomplete, Box, TextField } from '@mui/material';
|
|
6
6
|
import clsx from 'clsx';
|
|
7
7
|
import React, { useEffect, useRef, useState } from 'react';
|
|
8
|
+
import { useChatCommands } from './use-chat-commands';
|
|
8
9
|
import { AttachmentPreviewList } from '../attachments';
|
|
9
|
-
import {
|
|
10
|
+
import { useChatContext } from '../../context';
|
|
10
11
|
import { InputWritingIndicator } from './writing-indicator';
|
|
11
12
|
const INPUT_BOX_CLASS = 'jp-chat-input-container';
|
|
12
13
|
const INPUT_TEXTFIELD_CLASS = 'jp-chat-input-textfield';
|
|
13
14
|
const INPUT_TOOLBAR_CLASS = 'jp-chat-input-toolbar';
|
|
14
15
|
export function ChatInput(props) {
|
|
15
16
|
var _a;
|
|
16
|
-
const { model
|
|
17
|
+
const { model } = props;
|
|
18
|
+
const { area, chatCommandRegistry, inputToolbarRegistry } = useChatContext();
|
|
19
|
+
const chatModel = useChatContext().model;
|
|
17
20
|
const [input, setInput] = useState(model.value);
|
|
18
21
|
const inputRef = useRef();
|
|
19
|
-
const chatCommands = useChatCommands(model,
|
|
22
|
+
const chatCommands = useChatCommands(model, chatCommandRegistry);
|
|
20
23
|
const [sendWithShiftEnter, setSendWithShiftEnter] = useState((_a = model.config.sendWithShiftEnter) !== null && _a !== void 0 ? _a : false);
|
|
21
24
|
const [attachments, setAttachments] = useState(model.attachments);
|
|
22
25
|
const [toolbarElements, setToolbarElements] = useState([]);
|
|
23
|
-
const [isFocused, setIsFocused] = useState(false);
|
|
24
26
|
const [writers, setWriters] = useState([]);
|
|
25
27
|
/**
|
|
26
28
|
* Auto-focus the input when the component is first mounted.
|
|
@@ -69,20 +71,20 @@ export function ChatInput(props) {
|
|
|
69
71
|
*/
|
|
70
72
|
useEffect(() => {
|
|
71
73
|
const updateToolbar = () => {
|
|
72
|
-
setToolbarElements(
|
|
74
|
+
setToolbarElements((inputToolbarRegistry === null || inputToolbarRegistry === void 0 ? void 0 : inputToolbarRegistry.getItems()) || []);
|
|
73
75
|
};
|
|
74
|
-
|
|
76
|
+
inputToolbarRegistry === null || inputToolbarRegistry === void 0 ? void 0 : inputToolbarRegistry.itemsChanged.connect(updateToolbar);
|
|
75
77
|
updateToolbar();
|
|
76
78
|
return () => {
|
|
77
|
-
|
|
79
|
+
inputToolbarRegistry === null || inputToolbarRegistry === void 0 ? void 0 : inputToolbarRegistry.itemsChanged.disconnect(updateToolbar);
|
|
78
80
|
};
|
|
79
|
-
}, [
|
|
81
|
+
}, [inputToolbarRegistry]);
|
|
80
82
|
/**
|
|
81
83
|
* Handle the changes in the writers list.
|
|
82
84
|
*/
|
|
83
85
|
useEffect(() => {
|
|
84
86
|
var _a;
|
|
85
|
-
if (!
|
|
87
|
+
if (!chatModel) {
|
|
86
88
|
return;
|
|
87
89
|
}
|
|
88
90
|
const updateWriters = (_, writers) => {
|
|
@@ -90,14 +92,14 @@ export function ChatInput(props) {
|
|
|
90
92
|
setWriters(writers);
|
|
91
93
|
};
|
|
92
94
|
// Set initial writers state
|
|
93
|
-
const initialWriters =
|
|
95
|
+
const initialWriters = chatModel.writers;
|
|
94
96
|
setWriters(initialWriters);
|
|
95
|
-
(_a =
|
|
97
|
+
(_a = chatModel.writersChanged) === null || _a === void 0 ? void 0 : _a.connect(updateWriters);
|
|
96
98
|
return () => {
|
|
97
|
-
var _a
|
|
98
|
-
(
|
|
99
|
+
var _a;
|
|
100
|
+
(_a = chatModel === null || chatModel === void 0 ? void 0 : chatModel.writersChanged) === null || _a === void 0 ? void 0 : _a.disconnect(updateWriters);
|
|
99
101
|
};
|
|
100
|
-
}, [
|
|
102
|
+
}, [chatModel]);
|
|
101
103
|
const inputExists = !!input.trim();
|
|
102
104
|
/**
|
|
103
105
|
* `handleKeyDown()`: callback invoked when the user presses any key in the
|
|
@@ -106,7 +108,6 @@ export function ChatInput(props) {
|
|
|
106
108
|
* component.
|
|
107
109
|
*/
|
|
108
110
|
async function handleKeyDown(event) {
|
|
109
|
-
var _a;
|
|
110
111
|
/**
|
|
111
112
|
* IMPORTANT: This statement ensures that arrow keys can be used to navigate
|
|
112
113
|
* the multiline input when the chat commands menu is closed.
|
|
@@ -151,19 +152,17 @@ export function ChatInput(props) {
|
|
|
151
152
|
if ((sendWithShiftEnter && event.shiftKey) ||
|
|
152
153
|
(!sendWithShiftEnter && !event.shiftKey)) {
|
|
153
154
|
// Run all command providers
|
|
154
|
-
await (
|
|
155
|
+
await (chatCommandRegistry === null || chatCommandRegistry === void 0 ? void 0 : chatCommandRegistry.onSubmit(model));
|
|
155
156
|
model.send(model.value);
|
|
156
157
|
event.stopPropagation();
|
|
157
158
|
event.preventDefault();
|
|
158
159
|
}
|
|
159
160
|
}
|
|
160
|
-
const horizontalPadding =
|
|
161
|
+
const horizontalPadding = area === 'sidebar' ? 1.5 : 2;
|
|
161
162
|
return (React.createElement(Box, { sx: props.sx, className: clsx(INPUT_BOX_CLASS), "data-input-id": model.id },
|
|
162
163
|
React.createElement(Box, { sx: {
|
|
163
164
|
border: '1px solid',
|
|
164
|
-
borderColor:
|
|
165
|
-
? 'var(--jp-brand-color1)'
|
|
166
|
-
: 'var(--jp-border-color1)',
|
|
165
|
+
borderColor: 'var(--jp-border-color1)',
|
|
167
166
|
borderRadius: 2,
|
|
168
167
|
transition: 'border-color 0.2s ease',
|
|
169
168
|
display: 'flex',
|
|
@@ -186,9 +185,10 @@ export function ChatInput(props) {
|
|
|
186
185
|
padding: 0
|
|
187
186
|
}
|
|
188
187
|
}
|
|
189
|
-
}, renderInput: params => (React.createElement(TextField, { ...params, fullWidth: true, variant: "standard", className: INPUT_TEXTFIELD_CLASS, multiline: true, onKeyDown: handleKeyDown, placeholder: "Type a chat message, @ to mention...", inputRef: inputRef,
|
|
188
|
+
}, renderInput: params => (React.createElement(TextField, { ...params, fullWidth: true, variant: "standard", className: INPUT_TEXTFIELD_CLASS, multiline: true, maxRows: 10, onKeyDown: handleKeyDown, placeholder: "Type a chat message, @ to mention...", inputRef: inputRef, onSelect: () => { var _a, _b; return (model.cursorIndex = (_b = (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.selectionStart) !== null && _b !== void 0 ? _b : null); }, sx: {
|
|
190
189
|
padding: 1.5,
|
|
191
190
|
margin: 0,
|
|
191
|
+
boxSizing: 'border-box',
|
|
192
192
|
backgroundColor: 'var(--jp-layout-color0)',
|
|
193
193
|
transition: 'background-color 0.2s ease',
|
|
194
194
|
'& .MuiInputBase-root': {
|
|
@@ -232,6 +232,6 @@ export function ChatInput(props) {
|
|
|
232
232
|
borderColor: 'var(--jp-border-color1)',
|
|
233
233
|
backgroundColor: 'var(--jp-layout-color0)',
|
|
234
234
|
transition: 'background-color 0.2s ease'
|
|
235
|
-
} }, toolbarElements.map((item, index) => (React.createElement(item.element, { key: index, model: model, chatCommandRegistry:
|
|
235
|
+
} }, toolbarElements.map((item, index) => (React.createElement(item.element, { key: index, model: model, chatCommandRegistry: chatCommandRegistry, chatModel: chatModel, edit: props.edit }))))),
|
|
236
236
|
React.createElement(InputWritingIndicator, { writers: writers })));
|
|
237
237
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import {
|
|
2
|
+
import { IChatMessage } from '../../types';
|
|
3
3
|
/**
|
|
4
4
|
* The chat footer component properties.
|
|
5
5
|
*/
|
|
6
|
-
export interface IMessageFootersProps
|
|
6
|
+
export interface IMessageFootersProps {
|
|
7
7
|
/**
|
|
8
|
-
* The chat
|
|
8
|
+
* The chat model.
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
message: IChatMessage;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* The chat footer component, which displays footer components on a row according to
|
|
14
14
|
* their respective positions.
|
|
15
15
|
*/
|
|
16
|
-
export declare function MessageFooterComponent(props: IMessageFootersProps): JSX.Element;
|
|
16
|
+
export declare function MessageFooterComponent(props: IMessageFootersProps): JSX.Element | null;
|
|
@@ -4,14 +4,19 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { Box } from '@mui/material';
|
|
6
6
|
import React from 'react';
|
|
7
|
+
import { useChatContext } from '../../context';
|
|
7
8
|
/**
|
|
8
9
|
* The chat footer component, which displays footer components on a row according to
|
|
9
10
|
* their respective positions.
|
|
10
11
|
*/
|
|
11
12
|
export function MessageFooterComponent(props) {
|
|
12
13
|
var _a, _b, _c;
|
|
13
|
-
const { message
|
|
14
|
-
const
|
|
14
|
+
const { message } = props;
|
|
15
|
+
const { model, messageFooterRegistry } = useChatContext();
|
|
16
|
+
if (!messageFooterRegistry) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const footer = messageFooterRegistry.getFooter();
|
|
15
20
|
return (React.createElement(Box, { sx: { display: 'flex', justifyContent: 'space-between' } },
|
|
16
21
|
((_a = footer.left) === null || _a === void 0 ? void 0 : _a.component) ? (React.createElement(footer.left.component, { message: message, model: model })) : (React.createElement("div", null)),
|
|
17
22
|
((_b = footer.center) === null || _b === void 0 ? void 0 : _b.component) ? (React.createElement(footer.center.component, { message: message, model: model })) : (React.createElement("div", null)),
|
|
@@ -12,12 +12,14 @@ const MESSAGE_TIME_CLASS = 'jp-chat-message-time';
|
|
|
12
12
|
*/
|
|
13
13
|
export function ChatMessageHeader(props) {
|
|
14
14
|
var _a, _b;
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const message = props.message;
|
|
16
|
+
// Don't render header for stacked messages not deleted or edited.
|
|
17
|
+
if (message.stacked && !message.deleted && !message.edited) {
|
|
17
18
|
return React.createElement(React.Fragment, null);
|
|
18
19
|
}
|
|
20
|
+
// Flag to display only the deleted or edited information (stacked message).
|
|
21
|
+
const onlyState = message.stacked && (message.deleted || message.edited);
|
|
19
22
|
const [datetime, setDatetime] = useState({});
|
|
20
|
-
const message = props.message;
|
|
21
23
|
const sender = message.sender;
|
|
22
24
|
/**
|
|
23
25
|
* Effect: update cached datetime strings upon receiving a new message.
|
|
@@ -61,9 +63,9 @@ export function ChatMessageHeader(props) {
|
|
|
61
63
|
'& > :not(:last-child)': {
|
|
62
64
|
marginRight: 3
|
|
63
65
|
},
|
|
64
|
-
marginBottom: message.stacked ? '0px' : '12px'
|
|
66
|
+
marginBottom: message.stacked || props.isCurrentUser ? '0px' : '12px'
|
|
65
67
|
} },
|
|
66
|
-
avatar,
|
|
68
|
+
!props.isCurrentUser && !onlyState && avatar,
|
|
67
69
|
React.createElement(Box, { sx: {
|
|
68
70
|
display: 'flex',
|
|
69
71
|
flexGrow: 1,
|
|
@@ -72,7 +74,7 @@ export function ChatMessageHeader(props) {
|
|
|
72
74
|
alignItems: 'center'
|
|
73
75
|
} },
|
|
74
76
|
React.createElement(Box, { sx: { display: 'flex', alignItems: 'center' } },
|
|
75
|
-
!
|
|
77
|
+
!onlyState && !props.isCurrentUser && (React.createElement(Typography, { sx: {
|
|
76
78
|
fontWeight: 700,
|
|
77
79
|
color: 'var(--jp-ui-font-color1)',
|
|
78
80
|
paddingRight: '0.5em'
|
|
@@ -81,9 +83,9 @@ export function ChatMessageHeader(props) {
|
|
|
81
83
|
fontStyle: 'italic',
|
|
82
84
|
fontSize: 'var(--jp-content-font-size0)'
|
|
83
85
|
} }, message.deleted ? '(message deleted)' : '(edited)'))),
|
|
84
|
-
React.createElement(Typography, { className: MESSAGE_TIME_CLASS, sx: {
|
|
86
|
+
!onlyState && (React.createElement(Typography, { className: MESSAGE_TIME_CLASS, sx: {
|
|
85
87
|
fontSize: '0.8em',
|
|
86
88
|
color: 'var(--jp-ui-font-color2)',
|
|
87
89
|
fontWeight: 300
|
|
88
|
-
}, title: message.raw_time ? 'Unverified time' : '' }, `${datetime[message.time]}${message.raw_time ? '*' : ''}`))));
|
|
90
|
+
}, title: message.raw_time ? 'Unverified time' : '' }, `${datetime[message.time]}${message.raw_time ? '*' : ''}`)))));
|
|
89
91
|
}
|