@jupyter/chat 0.19.0-alpha.0 → 0.19.0-alpha.2
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/active-cell-manager.js +4 -2
- 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/index.d.ts +1 -0
- package/lib/components/index.js +1 -0
- 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 +6 -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 +21 -18
- 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 +28 -1
- package/lib/components/mui-extras/tooltipped-button.js +34 -6
- package/lib/components/mui-extras/tooltipped-icon-button.d.ts +6 -1
- package/lib/components/mui-extras/tooltipped-icon-button.js +8 -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/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 +5 -0
- package/lib/widgets/chat-widget.js +6 -0
- package/lib/widgets/multichat-panel.d.ts +1 -6
- package/lib/widgets/multichat-panel.js +3 -13
- package/package.json +1 -1
- package/src/active-cell-manager.ts +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/index.ts +1 -0
- package/src/components/input/buttons/attach-button.tsx +5 -13
- 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 +13 -34
- package/src/components/input/buttons/stop-button.tsx +13 -34
- package/src/components/input/chat-input.tsx +24 -38
- 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 +44 -5
- package/src/components/mui-extras/tooltipped-icon-button.tsx +22 -6
- package/src/context.ts +15 -5
- package/src/index.ts +1 -0
- package/src/tokens.ts +24 -0
- package/src/types.ts +4 -0
- package/src/widgets/chat-widget.tsx +8 -0
- package/src/widgets/multichat-panel.tsx +7 -26
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
2
1
|
import { PromiseDelegate } from '@lumino/coreutils';
|
|
3
2
|
import React from 'react';
|
|
4
|
-
import { IChatModel } from '../../model';
|
|
5
3
|
/**
|
|
6
4
|
* The type of the props for the MessageRenderer component.
|
|
7
5
|
*/
|
|
@@ -10,14 +8,6 @@ type MessageRendererProps = {
|
|
|
10
8
|
* The string to render.
|
|
11
9
|
*/
|
|
12
10
|
markdownStr: string;
|
|
13
|
-
/**
|
|
14
|
-
* The rendermime registry.
|
|
15
|
-
*/
|
|
16
|
-
rmRegistry: IRenderMimeRegistry;
|
|
17
|
-
/**
|
|
18
|
-
* The model of the chat.
|
|
19
|
-
*/
|
|
20
|
-
model: IChatModel;
|
|
21
11
|
/**
|
|
22
12
|
* The promise to resolve when the message is rendered.
|
|
23
13
|
*/
|
|
@@ -4,14 +4,16 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import React, { useState, useEffect } from 'react';
|
|
6
6
|
import { createPortal } from 'react-dom';
|
|
7
|
-
import { CodeToolbar } from '../code-blocks/code-toolbar';
|
|
8
7
|
import { MessageToolbar } from './toolbar';
|
|
8
|
+
import { CodeToolbar } from '../code-blocks/code-toolbar';
|
|
9
|
+
import { useChatContext } from '../../context';
|
|
9
10
|
import { MarkdownRenderer, MD_RENDERED_CLASS } from '../../markdown-renderer';
|
|
10
11
|
/**
|
|
11
12
|
* The message renderer base component.
|
|
12
13
|
*/
|
|
13
14
|
function MessageRendererBase(props) {
|
|
14
|
-
const { markdownStr
|
|
15
|
+
const { markdownStr } = props;
|
|
16
|
+
const { model, rmRegistry } = useChatContext();
|
|
15
17
|
const appendContent = props.appendContent || false;
|
|
16
18
|
const [renderedContent, setRenderedContent] = useState(null);
|
|
17
19
|
// each element is a two-tuple with the structure [codeToolbarRoot, codeToolbarProps].
|
|
@@ -31,7 +33,7 @@ function MessageRendererBase(props) {
|
|
|
31
33
|
(_a = preBlock.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(codeToolbarRoot, preBlock.nextSibling);
|
|
32
34
|
newCodeToolbarDefns.push([
|
|
33
35
|
codeToolbarRoot,
|
|
34
|
-
{ model:
|
|
36
|
+
{ model: model, content: preBlock.textContent || '' }
|
|
35
37
|
]);
|
|
36
38
|
});
|
|
37
39
|
setCodeToolbarDefns(newCodeToolbarDefns);
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { PromiseDelegate } from '@lumino/coreutils';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { BaseMessageProps } from './messages';
|
|
4
3
|
import { IChatMessage } from '../../types';
|
|
5
4
|
/**
|
|
6
|
-
* The message component
|
|
5
|
+
* The message component props.
|
|
7
6
|
*/
|
|
8
|
-
|
|
7
|
+
type ChatMessageProps = {
|
|
9
8
|
/**
|
|
10
9
|
* The message to display.
|
|
11
10
|
*/
|
|
@@ -18,4 +17,9 @@ export declare const ChatMessage: React.ForwardRefExoticComponent<BaseMessagePro
|
|
|
18
17
|
* The promise to resolve when the message is rendered.
|
|
19
18
|
*/
|
|
20
19
|
renderedPromise: PromiseDelegate<void>;
|
|
21
|
-
}
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* The message component body.
|
|
23
|
+
*/
|
|
24
|
+
export declare const ChatMessage: React.ForwardRefExoticComponent<ChatMessageProps & React.RefAttributes<HTMLDivElement>>;
|
|
25
|
+
export {};
|
|
@@ -6,13 +6,15 @@ import React, { forwardRef, useEffect, useState } from 'react';
|
|
|
6
6
|
import { MessageRenderer } from './message-renderer';
|
|
7
7
|
import { AttachmentPreviewList } from '../attachments';
|
|
8
8
|
import { ChatInput } from '../input';
|
|
9
|
+
import { useChatContext } from '../../context';
|
|
9
10
|
import { InputModel } from '../../input-model';
|
|
10
11
|
import { replaceSpanToMention } from '../../utils';
|
|
11
12
|
/**
|
|
12
13
|
* The message component body.
|
|
13
14
|
*/
|
|
14
15
|
export const ChatMessage = forwardRef((props, ref) => {
|
|
15
|
-
const { message
|
|
16
|
+
const { message } = props;
|
|
17
|
+
const { model } = useChatContext();
|
|
16
18
|
const [edit, setEdit] = useState(false);
|
|
17
19
|
const [deleted, setDeleted] = useState(false);
|
|
18
20
|
const [canEdit, setCanEdit] = useState(false);
|
|
@@ -94,7 +96,7 @@ export const ChatMessage = forwardRef((props, ref) => {
|
|
|
94
96
|
};
|
|
95
97
|
// Empty if the message has been deleted.
|
|
96
98
|
return deleted ? (React.createElement("div", { ref: ref, "data-index": props.index })) : (React.createElement("div", { ref: ref, "data-index": props.index },
|
|
97
|
-
edit && canEdit && model.getEditionModel(message.id) ? (React.createElement(ChatInput, { onCancel: () => cancelEdition(), model: model.getEditionModel(message.id),
|
|
99
|
+
edit && canEdit && model.getEditionModel(message.id) ? (React.createElement(ChatInput, { onCancel: () => cancelEdition(), model: model.getEditionModel(message.id), edit: true })) : (React.createElement(MessageRenderer, { markdownStr: message.body, edit: canEdit ? startEdition : undefined, delete: canDelete ? () => deleteMessage(message.id) : undefined, rendered: props.renderedPromise })),
|
|
98
100
|
message.attachments && !edit && (
|
|
99
101
|
// Display the attachments only if message is not edited, otherwise the
|
|
100
102
|
// input component display them.
|
|
@@ -1,44 +1,6 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
3
|
-
import { IInputToolbarRegistry } from '../input';
|
|
4
|
-
import { IChatCommandRegistry, IMessageFooterRegistry } from '../../registers';
|
|
5
|
-
import { IChatModel } from '../../model';
|
|
6
|
-
import { ChatArea } from '../../types';
|
|
7
2
|
export declare const MESSAGE_CLASS = "jp-chat-message";
|
|
8
|
-
/**
|
|
9
|
-
* The base components props.
|
|
10
|
-
*/
|
|
11
|
-
export type BaseMessageProps = {
|
|
12
|
-
/**
|
|
13
|
-
* The mime renderer registry.
|
|
14
|
-
*/
|
|
15
|
-
rmRegistry: IRenderMimeRegistry;
|
|
16
|
-
/**
|
|
17
|
-
* The chat model.
|
|
18
|
-
*/
|
|
19
|
-
model: IChatModel;
|
|
20
|
-
/**
|
|
21
|
-
* The chat commands registry.
|
|
22
|
-
*/
|
|
23
|
-
chatCommandRegistry?: IChatCommandRegistry;
|
|
24
|
-
/**
|
|
25
|
-
* The input toolbar registry.
|
|
26
|
-
*/
|
|
27
|
-
inputToolbarRegistry: IInputToolbarRegistry;
|
|
28
|
-
/**
|
|
29
|
-
* The footer registry.
|
|
30
|
-
*/
|
|
31
|
-
messageFooterRegistry?: IMessageFooterRegistry;
|
|
32
|
-
/**
|
|
33
|
-
* The welcome message.
|
|
34
|
-
*/
|
|
35
|
-
welcomeMessage?: string;
|
|
36
|
-
/**
|
|
37
|
-
* The area where the chat is displayed.
|
|
38
|
-
*/
|
|
39
|
-
area?: ChatArea;
|
|
40
|
-
};
|
|
41
3
|
/**
|
|
42
4
|
* The messages list component.
|
|
43
5
|
*/
|
|
44
|
-
export declare function ChatMessages(
|
|
6
|
+
export declare function ChatMessages(): JSX.Element;
|
|
@@ -12,17 +12,20 @@ import { ChatMessage } from './message';
|
|
|
12
12
|
import { Navigation } from './navigation';
|
|
13
13
|
import { WelcomeMessage } from './welcome';
|
|
14
14
|
import { ScrollContainer } from '../scroll-container';
|
|
15
|
+
import { useChatContext } from '../../context';
|
|
15
16
|
export const MESSAGE_CLASS = 'jp-chat-message';
|
|
16
17
|
const MESSAGES_BOX_CLASS = 'jp-chat-messages-container';
|
|
17
18
|
const MESSAGE_STACKED_CLASS = 'jp-chat-message-stacked';
|
|
18
19
|
/**
|
|
19
20
|
* The messages list component.
|
|
20
21
|
*/
|
|
21
|
-
export function ChatMessages(
|
|
22
|
-
|
|
22
|
+
export function ChatMessages() {
|
|
23
|
+
var _a;
|
|
24
|
+
const { area, messageFooterRegistry, model, welcomeMessage } = useChatContext();
|
|
23
25
|
const [messages, setMessages] = useState(model.messages);
|
|
24
26
|
const refMsgBox = useRef(null);
|
|
25
27
|
const [allRendered, setAllRendered] = useState(false);
|
|
28
|
+
const [showDeleted, setShowDeleted] = useState((_a = model.config.showDeleted) !== null && _a !== void 0 ? _a : false);
|
|
26
29
|
// The list of message DOM and their rendered promises.
|
|
27
30
|
const listRef = useRef([]);
|
|
28
31
|
const renderedPromise = useRef([]);
|
|
@@ -49,10 +52,25 @@ export function ChatMessages(props) {
|
|
|
49
52
|
setMessages([...model.messages]);
|
|
50
53
|
}
|
|
51
54
|
model.messagesUpdated.connect(handleChatEvents);
|
|
52
|
-
return
|
|
55
|
+
return () => {
|
|
53
56
|
model.messagesUpdated.disconnect(handleChatEvents);
|
|
54
57
|
};
|
|
55
58
|
}, [model]);
|
|
59
|
+
/**
|
|
60
|
+
* Effect: Listen to the config change.
|
|
61
|
+
*/
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
function handleConfigChange(_, config) {
|
|
64
|
+
var _a;
|
|
65
|
+
if (config.showDeleted !== showDeleted) {
|
|
66
|
+
setShowDeleted((_a = config.showDeleted) !== null && _a !== void 0 ? _a : false);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
model.configChanged.connect(handleConfigChange);
|
|
70
|
+
return () => {
|
|
71
|
+
model.configChanged.disconnect(handleConfigChange);
|
|
72
|
+
};
|
|
73
|
+
}, [model, showDeleted]);
|
|
56
74
|
/**
|
|
57
75
|
* Observe the messages to update the current viewport and the unread messages.
|
|
58
76
|
*/
|
|
@@ -88,7 +106,7 @@ export function ChatMessages(props) {
|
|
|
88
106
|
}
|
|
89
107
|
}
|
|
90
108
|
});
|
|
91
|
-
|
|
109
|
+
model.messagesInViewport = inViewport;
|
|
92
110
|
// Ensure that all messages are rendered before updating unread messages, otherwise
|
|
93
111
|
// it can lead to wrong assumption , because more message are in the viewport
|
|
94
112
|
// before they are rendered.
|
|
@@ -112,10 +130,10 @@ export function ChatMessages(props) {
|
|
|
112
130
|
});
|
|
113
131
|
};
|
|
114
132
|
}, [messages, allRendered]);
|
|
115
|
-
const horizontalPadding =
|
|
133
|
+
const horizontalPadding = area === 'main' ? 8 : 4;
|
|
116
134
|
return (React.createElement(React.Fragment, null,
|
|
117
135
|
React.createElement(ScrollContainer, { sx: { flexGrow: 1 } },
|
|
118
|
-
|
|
136
|
+
welcomeMessage && React.createElement(WelcomeMessage, { content: welcomeMessage }),
|
|
119
137
|
React.createElement(Box, { sx: {
|
|
120
138
|
paddingLeft: horizontalPadding,
|
|
121
139
|
paddingRight: horizontalPadding,
|
|
@@ -124,9 +142,9 @@ export function ChatMessages(props) {
|
|
|
124
142
|
display: 'flex',
|
|
125
143
|
flexDirection: 'column',
|
|
126
144
|
gap: 4
|
|
127
|
-
}, ref: refMsgBox, className: clsx(MESSAGES_BOX_CLASS) },
|
|
128
|
-
|
|
129
|
-
.map((message, i) => {
|
|
145
|
+
}, ref: refMsgBox, className: clsx(MESSAGES_BOX_CLASS) }, (showDeleted
|
|
146
|
+
? messages
|
|
147
|
+
: messages.filter(message => !message.deleted)).map((message, i) => {
|
|
130
148
|
renderedPromise.current[i] = new PromiseDelegate();
|
|
131
149
|
const isCurrentUser = model.user !== undefined &&
|
|
132
150
|
model.user.username === message.sender.username;
|
|
@@ -134,7 +152,7 @@ export function ChatMessages(props) {
|
|
|
134
152
|
// extra div needed to ensure each bubble is on a new line
|
|
135
153
|
React.createElement(Box, { key: i, sx: {
|
|
136
154
|
...(isCurrentUser && {
|
|
137
|
-
marginLeft:
|
|
155
|
+
marginLeft: area === 'main' ? '25%' : '10%',
|
|
138
156
|
backgroundColor: 'var(--jp-layout-color2)',
|
|
139
157
|
border: 'none',
|
|
140
158
|
borderRadius: 2,
|
|
@@ -142,8 +160,8 @@ export function ChatMessages(props) {
|
|
|
142
160
|
})
|
|
143
161
|
}, className: clsx(MESSAGE_CLASS, message.stacked ? MESSAGE_STACKED_CLASS : '') },
|
|
144
162
|
React.createElement(ChatMessageHeader, { message: message, isCurrentUser: isCurrentUser }),
|
|
145
|
-
React.createElement(ChatMessage, {
|
|
146
|
-
|
|
163
|
+
React.createElement(ChatMessage, { message: message, index: i, renderedPromise: renderedPromise.current[i], ref: el => (listRef.current[i] = el) }),
|
|
164
|
+
messageFooterRegistry && (React.createElement(MessageFooterComponent, { message: message }))));
|
|
147
165
|
}))),
|
|
148
|
-
React.createElement(Navigation, {
|
|
166
|
+
React.createElement(Navigation, { refMsgBox: refMsgBox, allRendered: allRendered })));
|
|
149
167
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { Button } from '@jupyter/react-components';
|
|
6
6
|
import { LabIcon, caretDownEmptyIcon, classes } from '@jupyterlab/ui-components';
|
|
7
7
|
import React, { useEffect, useState } from 'react';
|
|
8
|
+
import { useChatContext } from '../../context';
|
|
8
9
|
const NAVIGATION_BUTTON_CLASS = 'jp-chat-navigation';
|
|
9
10
|
const NAVIGATION_UNREAD_CLASS = 'jp-chat-navigation-unread';
|
|
10
11
|
const NAVIGATION_TOP_CLASS = 'jp-chat-navigation-top';
|
|
@@ -13,7 +14,7 @@ const NAVIGATION_BOTTOM_CLASS = 'jp-chat-navigation-bottom';
|
|
|
13
14
|
* The navigation component, to navigate to unread messages.
|
|
14
15
|
*/
|
|
15
16
|
export function Navigation(props) {
|
|
16
|
-
const { model } =
|
|
17
|
+
const { model } = useChatContext();
|
|
17
18
|
const [lastInViewport, setLastInViewport] = useState(true);
|
|
18
19
|
const [unreadBefore, setUnreadBefore] = useState(null);
|
|
19
20
|
const [unreadAfter, setUnreadAfter] = useState(null);
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
// import EditIcon from '@mui/icons-material/Edit';
|
|
6
6
|
import DeleteIcon from '@mui/icons-material/Delete';
|
|
7
|
-
import { Box
|
|
7
|
+
import { Box } from '@mui/material';
|
|
8
8
|
import React from 'react';
|
|
9
|
+
import { TooltippedIconButton } from '../mui-extras';
|
|
9
10
|
const TOOLBAR_CLASS = 'jp-chat-toolbar';
|
|
10
11
|
/**
|
|
11
12
|
* The toolbar attached to a message.
|
|
@@ -14,35 +15,20 @@ export function MessageToolbar(props) {
|
|
|
14
15
|
const buttons = [];
|
|
15
16
|
// if (props.edit !== undefined) {
|
|
16
17
|
// const editButton = (
|
|
17
|
-
// <
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
// padding: 0,
|
|
26
|
-
// lineHeight: 0
|
|
27
|
-
// }}
|
|
28
|
-
// >
|
|
29
|
-
// <EditIcon sx={{ fontSize: '16px' }} />
|
|
30
|
-
// </IconButton>
|
|
31
|
-
// </span>
|
|
32
|
-
// </Tooltip>
|
|
18
|
+
// <TooltippedIconButton
|
|
19
|
+
// tooltip={'edit'}
|
|
20
|
+
// onClick={props.edit}
|
|
21
|
+
// aria-label={'Edit'}
|
|
22
|
+
// inputToolbar={false}
|
|
23
|
+
// >
|
|
24
|
+
// <EditIcon />
|
|
25
|
+
// </TooltippedIconButton>
|
|
33
26
|
// );
|
|
34
27
|
// buttons.push(editButton);
|
|
35
28
|
// }
|
|
36
29
|
if (props.delete !== undefined) {
|
|
37
|
-
const deleteButton = (React.createElement(
|
|
38
|
-
React.createElement(
|
|
39
|
-
React.createElement(IconButton, { onClick: props.delete, "aria-label": "Delete", sx: {
|
|
40
|
-
width: '24px',
|
|
41
|
-
height: '24px',
|
|
42
|
-
padding: 0,
|
|
43
|
-
lineHeight: 0
|
|
44
|
-
} },
|
|
45
|
-
React.createElement(DeleteIcon, { sx: { fontSize: '16px' } })))));
|
|
30
|
+
const deleteButton = (React.createElement(TooltippedIconButton, { tooltip: 'Delete', onClick: props.delete, "aria-label": 'Delete', inputToolbar: false },
|
|
31
|
+
React.createElement(DeleteIcon, null)));
|
|
46
32
|
buttons.push(deleteButton);
|
|
47
33
|
}
|
|
48
34
|
return (React.createElement(Box, { className: TOOLBAR_CLASS, sx: {
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* The component props.
|
|
4
|
+
*/
|
|
5
|
+
export interface IWelcomeMessageProps {
|
|
6
|
+
/**
|
|
7
|
+
* The content of the welcome message (markdown).
|
|
8
|
+
*/
|
|
9
|
+
content: string;
|
|
10
|
+
}
|
|
3
11
|
/**
|
|
4
12
|
* The welcome message component.
|
|
5
13
|
* This message is displayed on top of the chat messages, and is rendered using a
|
|
6
14
|
* markdown renderer.
|
|
7
15
|
*/
|
|
8
|
-
export declare function WelcomeMessage(props:
|
|
16
|
+
export declare function WelcomeMessage(props: IWelcomeMessageProps): JSX.Element;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { classes } from '@jupyterlab/ui-components';
|
|
6
6
|
import React, { useEffect, useRef } from 'react';
|
|
7
|
+
import { useChatContext } from '../../context';
|
|
7
8
|
import { MarkdownRenderer, MD_RENDERED_CLASS } from '../../markdown-renderer';
|
|
8
9
|
const WELCOME_MESSAGE_CLASS = 'jp-chat-welcome-message';
|
|
9
10
|
/**
|
|
@@ -12,7 +13,7 @@ const WELCOME_MESSAGE_CLASS = 'jp-chat-welcome-message';
|
|
|
12
13
|
* markdown renderer.
|
|
13
14
|
*/
|
|
14
15
|
export function WelcomeMessage(props) {
|
|
15
|
-
const { rmRegistry } =
|
|
16
|
+
const { rmRegistry } = useChatContext();
|
|
16
17
|
const content = props.content + '\n----\n';
|
|
17
18
|
// ref that tracks the content container to store the rendermime node in
|
|
18
19
|
const renderingContainer = useRef(null);
|
|
@@ -1,9 +1,36 @@
|
|
|
1
|
-
import { ButtonProps, SxProps, TooltipProps } from '@mui/material';
|
|
1
|
+
import { ButtonOwnProps, ButtonProps, SxProps, TooltipProps } from '@mui/material';
|
|
2
2
|
import React from 'react';
|
|
3
|
+
export declare const TOOLTIPPED_WRAP_CLASS = "jp-chat-tooltipped-wrap";
|
|
4
|
+
export declare const DEFAULT_BUTTON_PROPS: Partial<ButtonOwnProps>;
|
|
5
|
+
export declare const DEFAULT_BUTTON_SX: {
|
|
6
|
+
minWidth: string;
|
|
7
|
+
width: string;
|
|
8
|
+
height: string;
|
|
9
|
+
lineHeight: number;
|
|
10
|
+
'&:disabled': {
|
|
11
|
+
opacity: number;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export declare const INPUT_TOOLBAR_BUTTON_SX: {
|
|
15
|
+
backgroundColor: string;
|
|
16
|
+
color: string;
|
|
17
|
+
borderRadius: string;
|
|
18
|
+
boxShadow: string;
|
|
19
|
+
'&:hover': {
|
|
20
|
+
backgroundColor: string;
|
|
21
|
+
boxShadow: string;
|
|
22
|
+
};
|
|
23
|
+
'&:disabled': {
|
|
24
|
+
backgroundColor: string;
|
|
25
|
+
color: string;
|
|
26
|
+
opacity: number;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
3
29
|
export type TooltippedButtonProps = {
|
|
4
30
|
onClick: React.MouseEventHandler<HTMLButtonElement>;
|
|
5
31
|
tooltip: string;
|
|
6
32
|
children: JSX.Element;
|
|
33
|
+
inputToolbar?: boolean;
|
|
7
34
|
disabled?: boolean;
|
|
8
35
|
placement?: TooltipProps['placement'];
|
|
9
36
|
/**
|
|
@@ -5,7 +5,35 @@
|
|
|
5
5
|
import { Button } from '@mui/material';
|
|
6
6
|
import React from 'react';
|
|
7
7
|
import { ContrastingTooltip } from './contrasting-tooltip';
|
|
8
|
-
const TOOLTIPPED_WRAP_CLASS = 'jp-chat-tooltipped-wrap';
|
|
8
|
+
export const TOOLTIPPED_WRAP_CLASS = 'jp-chat-tooltipped-wrap';
|
|
9
|
+
export const DEFAULT_BUTTON_PROPS = {
|
|
10
|
+
size: 'small',
|
|
11
|
+
variant: 'contained'
|
|
12
|
+
};
|
|
13
|
+
export const DEFAULT_BUTTON_SX = {
|
|
14
|
+
minWidth: '24px',
|
|
15
|
+
width: '24px',
|
|
16
|
+
height: '24px',
|
|
17
|
+
lineHeight: 0,
|
|
18
|
+
'&:disabled': {
|
|
19
|
+
opacity: 0.5
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
export const INPUT_TOOLBAR_BUTTON_SX = {
|
|
23
|
+
backgroundColor: 'var(--jp-brand-color1)',
|
|
24
|
+
color: 'white',
|
|
25
|
+
borderRadius: '4px',
|
|
26
|
+
boxShadow: 'none',
|
|
27
|
+
'&:hover': {
|
|
28
|
+
backgroundColor: 'var(--jp-brand-color0)',
|
|
29
|
+
boxShadow: 'none'
|
|
30
|
+
},
|
|
31
|
+
'&:disabled': {
|
|
32
|
+
backgroundColor: 'var(--jp-border-color2)',
|
|
33
|
+
color: 'var(--jp-ui-font-color3)',
|
|
34
|
+
opacity: 0.5
|
|
35
|
+
}
|
|
36
|
+
};
|
|
9
37
|
/**
|
|
10
38
|
* A component that renders an MUI `Button` with a high-contrast tooltip
|
|
11
39
|
* provided by `ContrastingTooltip`. This component differs from the MUI
|
|
@@ -22,7 +50,7 @@ const TOOLTIPPED_WRAP_CLASS = 'jp-chat-tooltipped-wrap';
|
|
|
22
50
|
* features available to `TooltippedIconButton`.
|
|
23
51
|
*/
|
|
24
52
|
export function TooltippedButton(props) {
|
|
25
|
-
var _a;
|
|
53
|
+
var _a, _b, _c;
|
|
26
54
|
return (React.createElement(ContrastingTooltip, { title: props.tooltip, placement: (_a = props.placement) !== null && _a !== void 0 ? _a : 'top', slotProps: {
|
|
27
55
|
popper: {
|
|
28
56
|
modifiers: [
|
|
@@ -36,9 +64,9 @@ export function TooltippedButton(props) {
|
|
|
36
64
|
}
|
|
37
65
|
} },
|
|
38
66
|
React.createElement("span", { style: { cursor: 'default' }, className: TOOLTIPPED_WRAP_CLASS },
|
|
39
|
-
React.createElement(Button, { ...props.buttonProps, onClick: props.onClick, disabled: props.disabled, sx: {
|
|
40
|
-
|
|
41
|
-
...(props.
|
|
67
|
+
React.createElement(Button, { ...DEFAULT_BUTTON_PROPS, ...props.buttonProps, onClick: props.onClick, disabled: props.disabled, sx: {
|
|
68
|
+
...DEFAULT_BUTTON_SX,
|
|
69
|
+
...(((_b = props.inputToolbar) !== null && _b !== void 0 ? _b : true) && INPUT_TOOLBAR_BUTTON_SX),
|
|
42
70
|
...props.sx
|
|
43
|
-
}, "aria-label": props['aria-label'] }, props.children))));
|
|
71
|
+
}, "aria-label": (_c = props['aria-label']) !== null && _c !== void 0 ? _c : props.tooltip }, props.children))));
|
|
44
72
|
}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import { IconButtonProps, TooltipProps } from '@mui/material';
|
|
2
|
+
import { IconButtonProps, SvgIconOwnProps, TooltipProps } from '@mui/material';
|
|
3
3
|
export type TooltippedIconButtonProps = {
|
|
4
4
|
onClick: () => unknown;
|
|
5
5
|
tooltip: string;
|
|
6
6
|
children: JSX.Element;
|
|
7
7
|
className?: string;
|
|
8
|
+
inputToolbar?: boolean;
|
|
8
9
|
disabled?: boolean;
|
|
9
10
|
placement?: TooltipProps['placement'];
|
|
11
|
+
/**
|
|
12
|
+
* The font size of the icon. By default it will be set to 'small'.
|
|
13
|
+
*/
|
|
14
|
+
fontSize?: SvgIconOwnProps['fontSize'];
|
|
10
15
|
/**
|
|
11
16
|
* The offset of the tooltip popup.
|
|
12
17
|
*
|
|
@@ -6,7 +6,7 @@ import { classes } from '@jupyterlab/ui-components';
|
|
|
6
6
|
import { IconButton } from '@mui/material';
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import { ContrastingTooltip } from './contrasting-tooltip';
|
|
9
|
-
|
|
9
|
+
import { DEFAULT_BUTTON_PROPS, DEFAULT_BUTTON_SX, INPUT_TOOLBAR_BUTTON_SX, TOOLTIPPED_WRAP_CLASS } from './tooltipped-button';
|
|
10
10
|
/**
|
|
11
11
|
* A component that renders an MUI `IconButton` with a high-contrast tooltip
|
|
12
12
|
* provided by `ContrastingTooltip`. This component differs from the MUI
|
|
@@ -20,8 +20,10 @@ const TOOLTIPPED_WRAP_CLASS = 'jp-chat-tooltipped-wrap';
|
|
|
20
20
|
* vertical space in SVG icons.
|
|
21
21
|
*/
|
|
22
22
|
export function TooltippedIconButton(props) {
|
|
23
|
-
var _a;
|
|
24
|
-
|
|
23
|
+
var _a, _b, _c;
|
|
24
|
+
// Override the default icon font size from 'medium' to 'small'
|
|
25
|
+
props.children.props.fontSize = (_a = props.fontSize) !== null && _a !== void 0 ? _a : 'small';
|
|
26
|
+
return (React.createElement(ContrastingTooltip, { title: props.tooltip, placement: (_b = props.placement) !== null && _b !== void 0 ? _b : 'top', slotProps: {
|
|
25
27
|
popper: {
|
|
26
28
|
modifiers: [
|
|
27
29
|
{
|
|
@@ -34,9 +36,8 @@ export function TooltippedIconButton(props) {
|
|
|
34
36
|
}
|
|
35
37
|
} },
|
|
36
38
|
React.createElement("span", { className: classes(props.className, TOOLTIPPED_WRAP_CLASS) },
|
|
37
|
-
React.createElement(IconButton, { ...props.iconButtonProps, onClick: props.onClick, disabled: props.disabled, sx: {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
...(props.disabled && { opacity: 0.5 })
|
|
39
|
+
React.createElement(IconButton, { ...DEFAULT_BUTTON_PROPS, ...props.iconButtonProps, onClick: props.onClick, disabled: props.disabled, sx: {
|
|
40
|
+
...DEFAULT_BUTTON_SX,
|
|
41
|
+
...(((_c = props.inputToolbar) !== null && _c !== void 0 ? _c : true) && INPUT_TOOLBAR_BUTTON_SX)
|
|
41
42
|
}, "aria-label": props['aria-label'] }, props.children))));
|
|
42
43
|
}
|
package/lib/context.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import {
|
|
3
|
-
export declare const
|
|
2
|
+
import { Chat } from './components';
|
|
3
|
+
export declare const ChatReactContext: import("react").Context<Chat.IChatProps | undefined>;
|
|
4
|
+
export declare function useChatContext(): Chat.IChatProps;
|
package/lib/context.js
CHANGED
|
@@ -2,5 +2,12 @@
|
|
|
2
2
|
* Copyright (c) Jupyter Development Team.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
-
import { createContext } from 'react';
|
|
6
|
-
export const
|
|
5
|
+
import { createContext, useContext } from 'react';
|
|
6
|
+
export const ChatReactContext = createContext(undefined);
|
|
7
|
+
export function useChatContext() {
|
|
8
|
+
const context = useContext(ChatReactContext);
|
|
9
|
+
if (!context) {
|
|
10
|
+
throw new Error('The chat context is missing in the chat');
|
|
11
|
+
}
|
|
12
|
+
return context;
|
|
13
|
+
}
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
package/lib/tokens.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IWidgetTracker, MainAreaWidget } from '@jupyterlab/apputils';
|
|
2
|
+
import { Token } from '@lumino/coreutils';
|
|
3
|
+
import { ChatWidget } from './widgets';
|
|
4
|
+
/**
|
|
5
|
+
* the chat tracker type.
|
|
6
|
+
*/
|
|
7
|
+
export type IChatTracker = IWidgetTracker<ChatWidget | MainAreaWidget<ChatWidget>>;
|
|
8
|
+
/**
|
|
9
|
+
* A chat tracker token.
|
|
10
|
+
*/
|
|
11
|
+
export declare const IChatTracker: Token<IChatTracker>;
|
package/lib/tokens.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Jupyter Development Team.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
import { Token } from '@lumino/coreutils';
|
|
6
|
+
/**
|
|
7
|
+
* A chat tracker token.
|
|
8
|
+
*/
|
|
9
|
+
export const IChatTracker = new Token('@jupyter/chat:IChatTracker', 'The chat widget tracker');
|
package/lib/types.d.ts
CHANGED
|
@@ -3,12 +3,17 @@ import React from 'react';
|
|
|
3
3
|
import { Message } from '@lumino/messaging';
|
|
4
4
|
import { Chat, IInputToolbarRegistry } from '../components';
|
|
5
5
|
import { IChatModel } from '../model';
|
|
6
|
+
import { ChatArea } from '../types';
|
|
6
7
|
export declare class ChatWidget extends ReactWidget {
|
|
7
8
|
constructor(options: Chat.IOptions);
|
|
8
9
|
/**
|
|
9
10
|
* Get the model of the widget.
|
|
10
11
|
*/
|
|
11
12
|
get model(): IChatModel;
|
|
13
|
+
/**
|
|
14
|
+
* The area where the chat is opened.
|
|
15
|
+
*/
|
|
16
|
+
get area(): ChatArea | undefined;
|
|
12
17
|
/**
|
|
13
18
|
* Get the input toolbar registry (if it has been provided when creating the widget).
|
|
14
19
|
*/
|
|
@@ -46,6 +46,12 @@ export class ChatWidget extends ReactWidget {
|
|
|
46
46
|
get model() {
|
|
47
47
|
return this._chatOptions.model;
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* The area where the chat is opened.
|
|
51
|
+
*/
|
|
52
|
+
get area() {
|
|
53
|
+
return this._chatOptions.area;
|
|
54
|
+
}
|
|
49
55
|
/**
|
|
50
56
|
* Get the input toolbar registry (if it has been provided when creating the widget).
|
|
51
57
|
*/
|