@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.
Files changed (73) hide show
  1. package/lib/active-cell-manager.js +4 -2
  2. package/lib/components/attachments.js +3 -3
  3. package/lib/components/chat.d.ts +3 -7
  4. package/lib/components/chat.js +9 -5
  5. package/lib/components/code-blocks/code-toolbar.js +8 -28
  6. package/lib/components/code-blocks/copy-button.js +4 -11
  7. package/lib/components/index.d.ts +1 -0
  8. package/lib/components/index.js +1 -0
  9. package/lib/components/input/buttons/attach-button.js +3 -10
  10. package/lib/components/input/buttons/cancel-button.js +6 -10
  11. package/lib/components/input/buttons/save-edit-button.js +6 -13
  12. package/lib/components/input/buttons/send-button.js +6 -23
  13. package/lib/components/input/buttons/stop-button.js +6 -23
  14. package/lib/components/input/chat-input.d.ts +0 -20
  15. package/lib/components/input/chat-input.js +21 -18
  16. package/lib/components/messages/footer.d.ts +5 -5
  17. package/lib/components/messages/footer.js +7 -2
  18. package/lib/components/messages/header.js +10 -8
  19. package/lib/components/messages/message-renderer.d.ts +0 -10
  20. package/lib/components/messages/message-renderer.js +5 -3
  21. package/lib/components/messages/message.d.ts +8 -4
  22. package/lib/components/messages/message.js +4 -2
  23. package/lib/components/messages/messages.d.ts +1 -39
  24. package/lib/components/messages/messages.js +31 -13
  25. package/lib/components/messages/navigation.d.ts +1 -2
  26. package/lib/components/messages/navigation.js +2 -1
  27. package/lib/components/messages/toolbar.js +12 -26
  28. package/lib/components/messages/welcome.d.ts +10 -2
  29. package/lib/components/messages/welcome.js +2 -1
  30. package/lib/components/mui-extras/tooltipped-button.d.ts +28 -1
  31. package/lib/components/mui-extras/tooltipped-button.js +34 -6
  32. package/lib/components/mui-extras/tooltipped-icon-button.d.ts +6 -1
  33. package/lib/components/mui-extras/tooltipped-icon-button.js +8 -7
  34. package/lib/context.d.ts +3 -2
  35. package/lib/context.js +9 -2
  36. package/lib/index.d.ts +1 -0
  37. package/lib/index.js +1 -0
  38. package/lib/tokens.d.ts +11 -0
  39. package/lib/tokens.js +9 -0
  40. package/lib/types.d.ts +4 -0
  41. package/lib/widgets/chat-widget.d.ts +5 -0
  42. package/lib/widgets/chat-widget.js +6 -0
  43. package/lib/widgets/multichat-panel.d.ts +1 -6
  44. package/lib/widgets/multichat-panel.js +3 -13
  45. package/package.json +1 -1
  46. package/src/active-cell-manager.ts +3 -1
  47. package/src/components/attachments.tsx +3 -3
  48. package/src/components/chat.tsx +13 -24
  49. package/src/components/code-blocks/code-toolbar.tsx +29 -55
  50. package/src/components/code-blocks/copy-button.tsx +13 -20
  51. package/src/components/index.ts +1 -0
  52. package/src/components/input/buttons/attach-button.tsx +5 -13
  53. package/src/components/input/buttons/cancel-button.tsx +11 -18
  54. package/src/components/input/buttons/save-edit-button.tsx +13 -22
  55. package/src/components/input/buttons/send-button.tsx +13 -34
  56. package/src/components/input/buttons/stop-button.tsx +13 -34
  57. package/src/components/input/chat-input.tsx +24 -38
  58. package/src/components/messages/footer.tsx +12 -10
  59. package/src/components/messages/header.tsx +23 -17
  60. package/src/components/messages/message-renderer.tsx +5 -13
  61. package/src/components/messages/message.tsx +4 -7
  62. package/src/components/messages/messages.tsx +73 -97
  63. package/src/components/messages/navigation.tsx +3 -3
  64. package/src/components/messages/toolbar.tsx +19 -33
  65. package/src/components/messages/welcome.tsx +13 -2
  66. package/src/components/mui-extras/tooltipped-button.tsx +44 -5
  67. package/src/components/mui-extras/tooltipped-icon-button.tsx +22 -6
  68. package/src/context.ts +15 -5
  69. package/src/index.ts +1 -0
  70. package/src/tokens.ts +24 -0
  71. package/src/types.ts +4 -0
  72. package/src/widgets/chat-widget.tsx +8 -0
  73. 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, rmRegistry } = props;
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: props.model, content: preBlock.textContent || '' }
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 body.
5
+ * The message component props.
7
6
  */
8
- export declare const ChatMessage: React.ForwardRefExoticComponent<BaseMessageProps & {
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
- } & React.RefAttributes<HTMLDivElement>>;
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, model, rmRegistry } = props;
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), chatCommandRegistry: props.chatCommandRegistry, toolbarRegistry: props.inputToolbarRegistry, edit: true })) : (React.createElement(MessageRenderer, { rmRegistry: rmRegistry, markdownStr: message.body, model: model, edit: canEdit ? startEdition : undefined, delete: canDelete ? () => deleteMessage(message.id) : undefined, rendered: props.renderedPromise })),
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(props: BaseMessageProps): JSX.Element;
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(props) {
22
- const { model } = props;
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 function cleanup() {
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
- props.model.messagesInViewport = inViewport;
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 = props.area === 'main' ? 8 : 4;
133
+ const horizontalPadding = area === 'main' ? 8 : 4;
116
134
  return (React.createElement(React.Fragment, null,
117
135
  React.createElement(ScrollContainer, { sx: { flexGrow: 1 } },
118
- props.welcomeMessage && (React.createElement(WelcomeMessage, { rmRegistry: props.rmRegistry, content: props.welcomeMessage })),
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) }, messages
128
- .filter(message => !message.deleted)
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: props.area === 'main' ? '25%' : '10%',
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, { ...props, message: message, index: i, renderedPromise: renderedPromise.current[i], ref: el => (listRef.current[i] = el) }),
146
- props.messageFooterRegistry && (React.createElement(MessageFooterComponent, { registry: props.messageFooterRegistry, message: message, model: model }))));
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, { ...props, refMsgBox: refMsgBox, allRendered: allRendered })));
166
+ React.createElement(Navigation, { refMsgBox: refMsgBox, allRendered: allRendered })));
149
167
  }
@@ -1,9 +1,8 @@
1
1
  import React from 'react';
2
- import { BaseMessageProps } from './messages';
3
2
  /**
4
3
  * The navigation component props.
5
4
  */
6
- type NavigationProps = BaseMessageProps & {
5
+ type NavigationProps = {
7
6
  /**
8
7
  * The reference to the messages container.
9
8
  */
@@ -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 } = props;
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, IconButton, Tooltip } from '@mui/material';
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
- // <Tooltip key="edit" title="Edit" placement="top" arrow>
18
- // <span>
19
- // <IconButton
20
- // onClick={props.edit}
21
- // aria-label="Edit"
22
- // sx={{
23
- // width: '24px',
24
- // height: '24px',
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(Tooltip, { key: "delete", title: "Delete", placement: "top", arrow: true },
38
- React.createElement("span", null,
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
- import { MarkdownRenderer } from '../../markdown-renderer';
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: MarkdownRenderer.IOptions): JSX.Element;
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 } = props;
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
- lineHeight: 0,
41
- ...(props.disabled && { opacity: 0.5 }),
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
- const TOOLTIPPED_WRAP_CLASS = 'jp-chat-tooltipped-wrap';
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
- return (React.createElement(ContrastingTooltip, { title: props.tooltip, placement: (_a = props.placement) !== null && _a !== void 0 ? _a : 'top', slotProps: {
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
- marginLeft: '8px',
39
- lineHeight: 0,
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 { IAttachmentOpenerRegistry } from './registers';
3
- export declare const AttachmentOpenerContext: import("react").Context<IAttachmentOpenerRegistry | undefined>;
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 AttachmentOpenerContext = createContext(undefined);
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
@@ -6,5 +6,6 @@ export * from './markdown-renderer';
6
6
  export * from './model';
7
7
  export * from './registers';
8
8
  export * from './selection-watcher';
9
+ export * from './tokens';
9
10
  export * from './types';
10
11
  export * from './widgets';
package/lib/index.js CHANGED
@@ -10,5 +10,6 @@ export * from './markdown-renderer';
10
10
  export * from './model';
11
11
  export * from './registers';
12
12
  export * from './selection-watcher';
13
+ export * from './tokens';
13
14
  export * from './types';
14
15
  export * from './widgets';
@@ -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
@@ -46,6 +46,10 @@ export interface IConfig {
46
46
  * Whether to send typing notification.
47
47
  */
48
48
  sendTypingNotification?: boolean;
49
+ /**
50
+ * Whether to display deleted messages.
51
+ */
52
+ showDeleted?: boolean;
49
53
  }
50
54
  /**
51
55
  * The chat message description.
@@ -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
  */