@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
@@ -14,28 +14,28 @@ import {
14
14
  import clsx from 'clsx';
15
15
  import React, { useEffect, useRef, useState } from 'react';
16
16
 
17
+ import { InputToolbarRegistry } from './toolbar-registry';
18
+ import { useChatCommands } from './use-chat-commands';
17
19
  import { AttachmentPreviewList } from '../attachments';
18
- import {
19
- IInputToolbarRegistry,
20
- InputToolbarRegistry,
21
- useChatCommands
22
- } from '.';
20
+ import { useChatContext } from '../../context';
23
21
  import { IInputModel, InputModel } from '../../input-model';
24
- import { IChatCommandRegistry } from '../../registers';
25
- import { IAttachment, ChatArea } from '../../types';
26
22
  import { IChatModel } from '../../model';
27
23
  import { InputWritingIndicator } from './writing-indicator';
24
+ import { IAttachment } from '../../types';
28
25
 
29
26
  const INPUT_BOX_CLASS = 'jp-chat-input-container';
30
27
  const INPUT_TEXTFIELD_CLASS = 'jp-chat-input-textfield';
31
28
  const INPUT_TOOLBAR_CLASS = 'jp-chat-input-toolbar';
32
29
 
33
30
  export function ChatInput(props: ChatInput.IProps): JSX.Element {
34
- const { model, toolbarRegistry } = props;
31
+ const { model } = props;
32
+ const { area, chatCommandRegistry, inputToolbarRegistry } = useChatContext();
33
+ const chatModel = useChatContext().model;
34
+
35
35
  const [input, setInput] = useState<string>(model.value);
36
36
  const inputRef = useRef<HTMLInputElement>();
37
37
 
38
- const chatCommands = useChatCommands(model, props.chatCommandRegistry);
38
+ const chatCommands = useChatCommands(model, chatCommandRegistry);
39
39
 
40
40
  const [sendWithShiftEnter, setSendWithShiftEnter] = useState<boolean>(
41
41
  model.config.sendWithShiftEnter ?? false
@@ -99,22 +99,22 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
99
99
  */
100
100
  useEffect(() => {
101
101
  const updateToolbar = () => {
102
- setToolbarElements(toolbarRegistry.getItems());
102
+ setToolbarElements(inputToolbarRegistry?.getItems() || []);
103
103
  };
104
104
 
105
- toolbarRegistry.itemsChanged.connect(updateToolbar);
105
+ inputToolbarRegistry?.itemsChanged.connect(updateToolbar);
106
106
  updateToolbar();
107
107
 
108
108
  return () => {
109
- toolbarRegistry.itemsChanged.disconnect(updateToolbar);
109
+ inputToolbarRegistry?.itemsChanged.disconnect(updateToolbar);
110
110
  };
111
- }, [toolbarRegistry]);
111
+ }, [inputToolbarRegistry]);
112
112
 
113
113
  /**
114
114
  * Handle the changes in the writers list.
115
115
  */
116
116
  useEffect(() => {
117
- if (!props.chatModel) {
117
+ if (!chatModel) {
118
118
  return;
119
119
  }
120
120
 
@@ -124,15 +124,15 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
124
124
  };
125
125
 
126
126
  // Set initial writers state
127
- const initialWriters = props.chatModel.writers;
127
+ const initialWriters = chatModel.writers;
128
128
  setWriters(initialWriters);
129
129
 
130
- props.chatModel.writersChanged?.connect(updateWriters);
130
+ chatModel.writersChanged?.connect(updateWriters);
131
131
 
132
132
  return () => {
133
- props.chatModel?.writersChanged?.disconnect(updateWriters);
133
+ chatModel?.writersChanged?.disconnect(updateWriters);
134
134
  };
135
- }, [props.chatModel]);
135
+ }, [chatModel]);
136
136
 
137
137
  const inputExists = !!input.trim();
138
138
 
@@ -196,14 +196,14 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
196
196
  (!sendWithShiftEnter && !event.shiftKey)
197
197
  ) {
198
198
  // Run all command providers
199
- await props.chatCommandRegistry?.onSubmit(model);
199
+ await chatCommandRegistry?.onSubmit(model);
200
200
  model.send(model.value);
201
201
  event.stopPropagation();
202
202
  event.preventDefault();
203
203
  }
204
204
  }
205
205
 
206
- const horizontalPadding = props.area === 'sidebar' ? 1.5 : 2;
206
+ const horizontalPadding = area === 'sidebar' ? 1.5 : 2;
207
207
 
208
208
  return (
209
209
  <Box
@@ -258,6 +258,7 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
258
258
  variant="standard"
259
259
  className={INPUT_TEXTFIELD_CLASS}
260
260
  multiline
261
+ maxRows={10}
261
262
  onKeyDown={handleKeyDown}
262
263
  placeholder="Type a chat message, @ to mention..."
263
264
  inputRef={inputRef}
@@ -269,6 +270,7 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
269
270
  sx={{
270
271
  padding: 1.5,
271
272
  margin: 0,
273
+ boxSizing: 'border-box',
272
274
  backgroundColor: 'var(--jp-layout-color0)',
273
275
  transition: 'background-color 0.2s ease',
274
276
  '& .MuiInputBase-root': {
@@ -333,8 +335,8 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
333
335
  <item.element
334
336
  key={index}
335
337
  model={model}
336
- chatCommandRegistry={props.chatCommandRegistry}
337
- chatModel={props.chatModel}
338
+ chatCommandRegistry={chatCommandRegistry}
339
+ chatModel={chatModel}
338
340
  edit={props.edit}
339
341
  />
340
342
  ))}
@@ -357,10 +359,6 @@ export namespace ChatInput {
357
359
  * The input model.
358
360
  */
359
361
  model: IInputModel;
360
- /**
361
- * The toolbar registry.
362
- */
363
- toolbarRegistry: IInputToolbarRegistry;
364
362
  /**
365
363
  * The function to be called to cancel editing.
366
364
  */
@@ -369,18 +367,6 @@ export namespace ChatInput {
369
367
  * Custom mui/material styles.
370
368
  */
371
369
  sx?: SxProps<Theme>;
372
- /**
373
- * Chat command registry.
374
- */
375
- chatCommandRegistry?: IChatCommandRegistry;
376
- /**
377
- * The area where the chat is displayed.
378
- */
379
- area?: ChatArea;
380
- /**
381
- * The chat model.
382
- */
383
- chatModel?: IChatModel;
384
370
  /**
385
371
  * Whether the input is in edit mode (editing an existing message).
386
372
  * Defaults to false (new message mode).
@@ -6,19 +6,17 @@
6
6
  import { Box } from '@mui/material';
7
7
  import React from 'react';
8
8
 
9
- import {
10
- IMessageFooterRegistry,
11
- MessageFooterSectionProps
12
- } from '../../registers';
9
+ import { useChatContext } from '../../context';
10
+ import { IChatMessage } from '../../types';
13
11
 
14
12
  /**
15
13
  * The chat footer component properties.
16
14
  */
17
- export interface IMessageFootersProps extends MessageFooterSectionProps {
15
+ export interface IMessageFootersProps {
18
16
  /**
19
- * The chat footer registry.
17
+ * The chat model.
20
18
  */
21
- registry: IMessageFooterRegistry;
19
+ message: IChatMessage;
22
20
  }
23
21
 
24
22
  /**
@@ -27,9 +25,13 @@ export interface IMessageFootersProps extends MessageFooterSectionProps {
27
25
  */
28
26
  export function MessageFooterComponent(
29
27
  props: IMessageFootersProps
30
- ): JSX.Element {
31
- const { message, model, registry } = props;
32
- const footer = registry.getFooter();
28
+ ): JSX.Element | null {
29
+ const { message } = props;
30
+ const { model, messageFooterRegistry } = useChatContext();
31
+ if (!messageFooterRegistry) {
32
+ return null;
33
+ }
34
+ const footer = messageFooterRegistry.getFooter();
33
35
 
34
36
  return (
35
37
  <Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
@@ -30,12 +30,16 @@ type ChatMessageHeaderProps = {
30
30
  * The message header component.
31
31
  */
32
32
  export function ChatMessageHeader(props: ChatMessageHeaderProps): JSX.Element {
33
- // Don't render header for stacked messages or current user messages
34
- if (props.message.stacked || props.isCurrentUser) {
33
+ const message = props.message;
34
+ // Don't render header for stacked messages not deleted or edited.
35
+ if (message.stacked && !message.deleted && !message.edited) {
35
36
  return <></>;
36
37
  }
38
+
39
+ // Flag to display only the deleted or edited information (stacked message).
40
+ const onlyState = message.stacked && (message.deleted || message.edited);
41
+
37
42
  const [datetime, setDatetime] = useState<Record<number, string>>({});
38
- const message = props.message;
39
43
  const sender = message.sender;
40
44
  /**
41
45
  * Effect: update cached datetime strings upon receiving a new message.
@@ -88,10 +92,10 @@ export function ChatMessageHeader(props: ChatMessageHeaderProps): JSX.Element {
88
92
  '& > :not(:last-child)': {
89
93
  marginRight: 3
90
94
  },
91
- marginBottom: message.stacked ? '0px' : '12px'
95
+ marginBottom: message.stacked || props.isCurrentUser ? '0px' : '12px'
92
96
  }}
93
97
  >
94
- {avatar}
98
+ {!props.isCurrentUser && !onlyState && avatar}
95
99
  <Box
96
100
  sx={{
97
101
  display: 'flex',
@@ -102,7 +106,7 @@ export function ChatMessageHeader(props: ChatMessageHeaderProps): JSX.Element {
102
106
  }}
103
107
  >
104
108
  <Box sx={{ display: 'flex', alignItems: 'center' }}>
105
- {!message.stacked && (
109
+ {!onlyState && !props.isCurrentUser && (
106
110
  <Typography
107
111
  sx={{
108
112
  fontWeight: 700,
@@ -124,17 +128,19 @@ export function ChatMessageHeader(props: ChatMessageHeaderProps): JSX.Element {
124
128
  </Typography>
125
129
  )}
126
130
  </Box>
127
- <Typography
128
- className={MESSAGE_TIME_CLASS}
129
- sx={{
130
- fontSize: '0.8em',
131
- color: 'var(--jp-ui-font-color2)',
132
- fontWeight: 300
133
- }}
134
- title={message.raw_time ? 'Unverified time' : ''}
135
- >
136
- {`${datetime[message.time]}${message.raw_time ? '*' : ''}`}
137
- </Typography>
131
+ {!onlyState && (
132
+ <Typography
133
+ className={MESSAGE_TIME_CLASS}
134
+ sx={{
135
+ fontSize: '0.8em',
136
+ color: 'var(--jp-ui-font-color2)',
137
+ fontWeight: 300
138
+ }}
139
+ title={message.raw_time ? 'Unverified time' : ''}
140
+ >
141
+ {`${datetime[message.time]}${message.raw_time ? '*' : ''}`}
142
+ </Typography>
143
+ )}
138
144
  </Box>
139
145
  </Box>
140
146
  );
@@ -3,15 +3,14 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
 
6
- import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
7
6
  import { PromiseDelegate } from '@lumino/coreutils';
8
7
  import React, { useState, useEffect } from 'react';
9
8
  import { createPortal } from 'react-dom';
10
9
 
11
- import { CodeToolbar, CodeToolbarProps } from '../code-blocks/code-toolbar';
12
10
  import { MessageToolbar } from './toolbar';
11
+ import { CodeToolbar, CodeToolbarProps } from '../code-blocks/code-toolbar';
12
+ import { useChatContext } from '../../context';
13
13
  import { MarkdownRenderer, MD_RENDERED_CLASS } from '../../markdown-renderer';
14
- import { IChatModel } from '../../model';
15
14
 
16
15
  /**
17
16
  * The type of the props for the MessageRenderer component.
@@ -21,14 +20,6 @@ type MessageRendererProps = {
21
20
  * The string to render.
22
21
  */
23
22
  markdownStr: string;
24
- /**
25
- * The rendermime registry.
26
- */
27
- rmRegistry: IRenderMimeRegistry;
28
- /**
29
- * The model of the chat.
30
- */
31
- model: IChatModel;
32
23
  /**
33
24
  * The promise to resolve when the message is rendered.
34
25
  */
@@ -51,7 +42,8 @@ type MessageRendererProps = {
51
42
  * The message renderer base component.
52
43
  */
53
44
  function MessageRendererBase(props: MessageRendererProps): JSX.Element {
54
- const { markdownStr, rmRegistry } = props;
45
+ const { markdownStr } = props;
46
+ const { model, rmRegistry } = useChatContext();
55
47
  const appendContent = props.appendContent || false;
56
48
  const [renderedContent, setRenderedContent] = useState<HTMLElement | null>(
57
49
  null
@@ -81,7 +73,7 @@ function MessageRendererBase(props: MessageRendererProps): JSX.Element {
81
73
  );
82
74
  newCodeToolbarDefns.push([
83
75
  codeToolbarRoot,
84
- { model: props.model, content: preBlock.textContent || '' }
76
+ { model: model, content: preBlock.textContent || '' }
85
77
  ]);
86
78
  });
87
79
 
@@ -7,9 +7,9 @@ import { PromiseDelegate } from '@lumino/coreutils';
7
7
  import React, { forwardRef, useEffect, useState } from 'react';
8
8
 
9
9
  import { MessageRenderer } from './message-renderer';
10
- import { BaseMessageProps } from './messages';
11
10
  import { AttachmentPreviewList } from '../attachments';
12
11
  import { ChatInput } from '../input';
12
+ import { useChatContext } from '../../context';
13
13
  import { IInputModel, InputModel } from '../../input-model';
14
14
  import { IChatMessage } from '../../types';
15
15
  import { replaceSpanToMention } from '../../utils';
@@ -17,7 +17,7 @@ import { replaceSpanToMention } from '../../utils';
17
17
  /**
18
18
  * The message component props.
19
19
  */
20
- type ChatMessageProps = BaseMessageProps & {
20
+ type ChatMessageProps = {
21
21
  /**
22
22
  * The message to display.
23
23
  */
@@ -37,7 +37,8 @@ type ChatMessageProps = BaseMessageProps & {
37
37
  */
38
38
  export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
39
39
  (props, ref): JSX.Element => {
40
- const { message, model, rmRegistry } = props;
40
+ const { message } = props;
41
+ const { model } = useChatContext();
41
42
  const [edit, setEdit] = useState<boolean>(false);
42
43
  const [deleted, setDeleted] = useState<boolean>(false);
43
44
  const [canEdit, setCanEdit] = useState<boolean>(false);
@@ -132,15 +133,11 @@ export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
132
133
  <ChatInput
133
134
  onCancel={() => cancelEdition()}
134
135
  model={model.getEditionModel(message.id)!}
135
- chatCommandRegistry={props.chatCommandRegistry}
136
- toolbarRegistry={props.inputToolbarRegistry}
137
136
  edit={true}
138
137
  />
139
138
  ) : (
140
139
  <MessageRenderer
141
- rmRegistry={rmRegistry}
142
140
  markdownStr={message.body}
143
- model={model}
144
141
  edit={canEdit ? startEdition : undefined}
145
142
  delete={canDelete ? () => deleteMessage(message.id) : undefined}
146
143
  rendered={props.renderedPromise}
@@ -3,7 +3,6 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
 
6
- import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
7
6
  import { PromiseDelegate } from '@lumino/coreutils';
8
7
  import { Box } from '@mui/material';
9
8
  import clsx from 'clsx';
@@ -14,58 +13,28 @@ import { ChatMessageHeader } from './header';
14
13
  import { ChatMessage } from './message';
15
14
  import { Navigation } from './navigation';
16
15
  import { WelcomeMessage } from './welcome';
17
- import { IInputToolbarRegistry } from '../input';
18
16
  import { ScrollContainer } from '../scroll-container';
19
- import { IChatCommandRegistry, IMessageFooterRegistry } from '../../registers';
17
+ import { useChatContext } from '../../context';
18
+ import { IChatMessage, IConfig } from '../../types';
20
19
  import { IChatModel } from '../../model';
21
- import { ChatArea, IChatMessage } from '../../types';
22
20
 
23
21
  export const MESSAGE_CLASS = 'jp-chat-message';
24
22
  const MESSAGES_BOX_CLASS = 'jp-chat-messages-container';
25
23
  const MESSAGE_STACKED_CLASS = 'jp-chat-message-stacked';
26
24
 
27
- /**
28
- * The base components props.
29
- */
30
- export type BaseMessageProps = {
31
- /**
32
- * The mime renderer registry.
33
- */
34
- rmRegistry: IRenderMimeRegistry;
35
- /**
36
- * The chat model.
37
- */
38
- model: IChatModel;
39
- /**
40
- * The chat commands registry.
41
- */
42
- chatCommandRegistry?: IChatCommandRegistry;
43
- /**
44
- * The input toolbar registry.
45
- */
46
- inputToolbarRegistry: IInputToolbarRegistry;
47
- /**
48
- * The footer registry.
49
- */
50
- messageFooterRegistry?: IMessageFooterRegistry;
51
- /**
52
- * The welcome message.
53
- */
54
- welcomeMessage?: string;
55
- /**
56
- * The area where the chat is displayed.
57
- */
58
- area?: ChatArea;
59
- };
60
-
61
25
  /**
62
26
  * The messages list component.
63
27
  */
64
- export function ChatMessages(props: BaseMessageProps): JSX.Element {
65
- const { model } = props;
28
+ export function ChatMessages(): JSX.Element {
29
+ const { area, messageFooterRegistry, model, welcomeMessage } =
30
+ useChatContext();
31
+
66
32
  const [messages, setMessages] = useState<IChatMessage[]>(model.messages);
67
33
  const refMsgBox = useRef<HTMLDivElement>(null);
68
34
  const [allRendered, setAllRendered] = useState<boolean>(false);
35
+ const [showDeleted, setShowDeleted] = useState<boolean>(
36
+ model.config.showDeleted ?? false
37
+ );
69
38
 
70
39
  // The list of message DOM and their rendered promises.
71
40
  const listRef = useRef<(HTMLDivElement | null)[]>([]);
@@ -95,14 +64,29 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element {
95
64
  function handleChatEvents() {
96
65
  setMessages([...model.messages]);
97
66
  }
98
-
99
67
  model.messagesUpdated.connect(handleChatEvents);
100
68
 
101
- return function cleanup() {
69
+ return () => {
102
70
  model.messagesUpdated.disconnect(handleChatEvents);
103
71
  };
104
72
  }, [model]);
105
73
 
74
+ /**
75
+ * Effect: Listen to the config change.
76
+ */
77
+ useEffect(() => {
78
+ function handleConfigChange(_: IChatModel, config: IConfig) {
79
+ if (config.showDeleted !== showDeleted) {
80
+ setShowDeleted(config.showDeleted ?? false);
81
+ }
82
+ }
83
+ model.configChanged.connect(handleConfigChange);
84
+
85
+ return () => {
86
+ model.configChanged.disconnect(handleConfigChange);
87
+ };
88
+ }, [model, showDeleted]);
89
+
106
90
  /**
107
91
  * Observe the messages to update the current viewport and the unread messages.
108
92
  */
@@ -137,7 +121,7 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element {
137
121
  }
138
122
  });
139
123
 
140
- props.model.messagesInViewport = inViewport;
124
+ model.messagesInViewport = inViewport;
141
125
 
142
126
  // Ensure that all messages are rendered before updating unread messages, otherwise
143
127
  // it can lead to wrong assumption , because more message are in the viewport
@@ -165,16 +149,11 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element {
165
149
  };
166
150
  }, [messages, allRendered]);
167
151
 
168
- const horizontalPadding = props.area === 'main' ? 8 : 4;
152
+ const horizontalPadding = area === 'main' ? 8 : 4;
169
153
  return (
170
154
  <>
171
155
  <ScrollContainer sx={{ flexGrow: 1 }}>
172
- {props.welcomeMessage && (
173
- <WelcomeMessage
174
- rmRegistry={props.rmRegistry}
175
- content={props.welcomeMessage}
176
- />
177
- )}
156
+ {welcomeMessage && <WelcomeMessage content={welcomeMessage} />}
178
157
  <Box
179
158
  sx={{
180
159
  paddingLeft: horizontalPadding,
@@ -188,55 +167,52 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element {
188
167
  ref={refMsgBox}
189
168
  className={clsx(MESSAGES_BOX_CLASS)}
190
169
  >
191
- {messages
192
- .filter(message => !message.deleted)
193
- .map((message, i) => {
194
- renderedPromise.current[i] = new PromiseDelegate();
195
- const isCurrentUser =
196
- model.user !== undefined &&
197
- model.user.username === message.sender.username;
198
- return (
199
- // extra div needed to ensure each bubble is on a new line
200
- <Box
201
- key={i}
202
- sx={{
203
- ...(isCurrentUser && {
204
- marginLeft: props.area === 'main' ? '25%' : '10%',
205
- backgroundColor: 'var(--jp-layout-color2)',
206
- border: 'none',
207
- borderRadius: 2,
208
- padding: 2
209
- })
210
- }}
211
- className={clsx(
212
- MESSAGE_CLASS,
213
- message.stacked ? MESSAGE_STACKED_CLASS : ''
214
- )}
215
- >
216
- <ChatMessageHeader
217
- message={message}
218
- isCurrentUser={isCurrentUser}
219
- />
220
- <ChatMessage
221
- {...props}
222
- message={message}
223
- index={i}
224
- renderedPromise={renderedPromise.current[i]}
225
- ref={el => (listRef.current[i] = el)}
226
- />
227
- {props.messageFooterRegistry && (
228
- <MessageFooterComponent
229
- registry={props.messageFooterRegistry}
230
- message={message}
231
- model={model}
232
- />
233
- )}
234
- </Box>
235
- );
236
- })}
170
+ {/* Filter the deleted message if user don't expect to see it. */}
171
+ {(showDeleted
172
+ ? messages
173
+ : messages.filter(message => !message.deleted)
174
+ ).map((message, i) => {
175
+ renderedPromise.current[i] = new PromiseDelegate();
176
+ const isCurrentUser =
177
+ model.user !== undefined &&
178
+ model.user.username === message.sender.username;
179
+ return (
180
+ // extra div needed to ensure each bubble is on a new line
181
+ <Box
182
+ key={i}
183
+ sx={{
184
+ ...(isCurrentUser && {
185
+ marginLeft: area === 'main' ? '25%' : '10%',
186
+ backgroundColor: 'var(--jp-layout-color2)',
187
+ border: 'none',
188
+ borderRadius: 2,
189
+ padding: 2
190
+ })
191
+ }}
192
+ className={clsx(
193
+ MESSAGE_CLASS,
194
+ message.stacked ? MESSAGE_STACKED_CLASS : ''
195
+ )}
196
+ >
197
+ <ChatMessageHeader
198
+ message={message}
199
+ isCurrentUser={isCurrentUser}
200
+ />
201
+ <ChatMessage
202
+ message={message}
203
+ index={i}
204
+ renderedPromise={renderedPromise.current[i]}
205
+ ref={el => (listRef.current[i] = el)}
206
+ />
207
+ {messageFooterRegistry && (
208
+ <MessageFooterComponent message={message} />
209
+ )}
210
+ </Box>
211
+ );
212
+ })}
237
213
  </Box>
238
214
  </ScrollContainer>
239
- <Navigation {...props} refMsgBox={refMsgBox} allRendered={allRendered} />
215
+ <Navigation refMsgBox={refMsgBox} allRendered={allRendered} />
240
216
  </>
241
217
  );
242
218
  }
@@ -11,7 +11,7 @@ import {
11
11
  } from '@jupyterlab/ui-components';
12
12
  import React, { useEffect, useState } from 'react';
13
13
 
14
- import { BaseMessageProps } from './messages';
14
+ import { useChatContext } from '../../context';
15
15
  import { IChatModel } from '../../model';
16
16
 
17
17
  const NAVIGATION_BUTTON_CLASS = 'jp-chat-navigation';
@@ -22,7 +22,7 @@ const NAVIGATION_BOTTOM_CLASS = 'jp-chat-navigation-bottom';
22
22
  /**
23
23
  * The navigation component props.
24
24
  */
25
- type NavigationProps = BaseMessageProps & {
25
+ type NavigationProps = {
26
26
  /**
27
27
  * The reference to the messages container.
28
28
  */
@@ -37,7 +37,7 @@ type NavigationProps = BaseMessageProps & {
37
37
  * The navigation component, to navigate to unread messages.
38
38
  */
39
39
  export function Navigation(props: NavigationProps): JSX.Element {
40
- const { model } = props;
40
+ const { model } = useChatContext();
41
41
  const [lastInViewport, setLastInViewport] = useState<boolean>(true);
42
42
  const [unreadBefore, setUnreadBefore] = useState<number | null>(null);
43
43
  const [unreadAfter, setUnreadAfter] = useState<number | null>(null);