Skip to content

Commit 9d6de18

Browse files
committed
Use a react context in the chat component and its children
1 parent 7a046de commit 9d6de18

File tree

10 files changed

+97
-138
lines changed

10 files changed

+97
-138
lines changed

packages/jupyter-chat/src/components/attachments.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55

66
import CloseIcon from '@mui/icons-material/Close';
77
import { Box, Button, Tooltip } from '@mui/material';
8-
import React, { useContext } from 'react';
8+
import React from 'react';
99
import { PathExt } from '@jupyterlab/coreutils';
1010
import { UUID } from '@lumino/coreutils';
1111

12+
import { useChatContext } from '../context';
1213
import { IAttachment } from '../types';
13-
import { AttachmentOpenerContext } from '../context';
1414

1515
const ATTACHMENT_CLASS = 'jp-chat-attachment';
1616
const ATTACHMENT_CLICKABLE_CLASS = 'jp-chat-attachment-clickable';
@@ -87,7 +87,7 @@ export type AttachmentProps = AttachmentsProps & {
8787
*/
8888
export function AttachmentPreview(props: AttachmentProps): JSX.Element {
8989
const remove_tooltip = 'Remove attachment';
90-
const attachmentOpenerRegistry = useContext(AttachmentOpenerContext);
90+
const { attachmentOpenerRegistry } = useChatContext();
9191
const isClickable = !!attachmentOpenerRegistry?.get(props.attachment.type);
9292

9393
return (

packages/jupyter-chat/src/components/chat.tsx

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
} from './input';
1919
import { JlThemeProvider } from './jl-theme-provider';
2020
import { ChatMessages } from './messages';
21-
import { AttachmentOpenerContext } from '../context';
21+
import { ChatReactContext } from '../context';
2222
import { IChatModel } from '../model';
2323
import {
2424
IAttachmentOpenerRegistry,
@@ -27,7 +27,7 @@ import {
2727
} from '../registers';
2828
import { ChatArea } from '../types';
2929

30-
export function ChatBody(props: Chat.IChatBodyProps): JSX.Element {
30+
export function ChatBody(props: Chat.IChatProps): JSX.Element {
3131
const { model } = props;
3232
let { inputToolbarRegistry } = props;
3333
if (!inputToolbarRegistry) {
@@ -36,17 +36,14 @@ export function ChatBody(props: Chat.IChatBodyProps): JSX.Element {
3636
// const horizontalPadding = props.area === 'main' ? 8 : 4;
3737
const horizontalPadding = 4;
3838

39+
const contextValue: Chat.IChatProps = {
40+
...props,
41+
inputToolbarRegistry
42+
};
43+
3944
return (
40-
<AttachmentOpenerContext.Provider value={props.attachmentOpenerRegistry}>
41-
<ChatMessages
42-
rmRegistry={props.rmRegistry}
43-
model={model}
44-
chatCommandRegistry={props.chatCommandRegistry}
45-
inputToolbarRegistry={inputToolbarRegistry}
46-
messageFooterRegistry={props.messageFooterRegistry}
47-
welcomeMessage={props.welcomeMessage}
48-
area={props.area}
49-
/>
45+
<ChatReactContext.Provider value={contextValue}>
46+
<ChatMessages area={props.area} />
5047
<ChatInput
5148
sx={{
5249
paddingLeft: horizontalPadding,
@@ -55,12 +52,9 @@ export function ChatBody(props: Chat.IChatBodyProps): JSX.Element {
5552
paddingBottom: 0
5653
}}
5754
model={model.input}
58-
chatCommandRegistry={props.chatCommandRegistry}
59-
toolbarRegistry={inputToolbarRegistry}
6055
area={props.area}
61-
chatModel={model}
6256
/>
63-
</AttachmentOpenerContext.Provider>
57+
</ChatReactContext.Provider>
6458
);
6559
}
6660

@@ -117,7 +111,7 @@ export namespace Chat {
117111
/**
118112
* The props for the chat body component.
119113
*/
120-
export interface IChatBodyProps {
114+
export interface IChatProps {
121115
/**
122116
* The chat model.
123117
*/
@@ -155,7 +149,7 @@ export namespace Chat {
155149
/**
156150
* The options to build the Chat UI.
157151
*/
158-
export interface IOptions extends IChatBodyProps {
152+
export interface IOptions extends IChatProps {
159153
/**
160154
* The theme manager.
161155
*/

packages/jupyter-chat/src/components/input/chat-input.tsx

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,28 @@ import {
1414
import clsx from 'clsx';
1515
import React, { useEffect, useRef, useState } from 'react';
1616

17+
import { InputToolbarRegistry } from './toolbar-registry';
18+
import { useChatCommands } from './use-chat-commands';
1719
import { AttachmentPreviewList } from '../attachments';
18-
import {
19-
IInputToolbarRegistry,
20-
InputToolbarRegistry,
21-
useChatCommands
22-
} from '.';
20+
import { useChatContext } from '../../context';
2321
import { IInputModel, InputModel } from '../../input-model';
24-
import { IChatCommandRegistry } from '../../registers';
25-
import { IAttachment, ChatArea } from '../../types';
2622
import { IChatModel } from '../../model';
2723
import { InputWritingIndicator } from './writing-indicator';
24+
import { ChatArea, IAttachment } from '../../types';
2825

2926
const INPUT_BOX_CLASS = 'jp-chat-input-container';
3027
const INPUT_TEXTFIELD_CLASS = 'jp-chat-input-textfield';
3128
const INPUT_TOOLBAR_CLASS = 'jp-chat-input-toolbar';
3229

3330
export function ChatInput(props: ChatInput.IProps): JSX.Element {
34-
const { model, toolbarRegistry } = props;
31+
const { model } = props;
32+
const { chatCommandRegistry, inputToolbarRegistry } = useChatContext();
33+
const chatModel = useChatContext().model;
34+
3535
const [input, setInput] = useState<string>(model.value);
3636
const inputRef = useRef<HTMLInputElement>();
3737

38-
const chatCommands = useChatCommands(model, props.chatCommandRegistry);
38+
const chatCommands = useChatCommands(model, chatCommandRegistry);
3939

4040
const [sendWithShiftEnter, setSendWithShiftEnter] = useState<boolean>(
4141
model.config.sendWithShiftEnter ?? false
@@ -99,22 +99,22 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
9999
*/
100100
useEffect(() => {
101101
const updateToolbar = () => {
102-
setToolbarElements(toolbarRegistry.getItems());
102+
setToolbarElements(inputToolbarRegistry?.getItems() || []);
103103
};
104104

105-
toolbarRegistry.itemsChanged.connect(updateToolbar);
105+
inputToolbarRegistry?.itemsChanged.connect(updateToolbar);
106106
updateToolbar();
107107

108108
return () => {
109-
toolbarRegistry.itemsChanged.disconnect(updateToolbar);
109+
inputToolbarRegistry?.itemsChanged.disconnect(updateToolbar);
110110
};
111-
}, [toolbarRegistry]);
111+
}, [inputToolbarRegistry]);
112112

113113
/**
114114
* Handle the changes in the writers list.
115115
*/
116116
useEffect(() => {
117-
if (!props.chatModel) {
117+
if (!chatModel) {
118118
return;
119119
}
120120

@@ -124,15 +124,15 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
124124
};
125125

126126
// Set initial writers state
127-
const initialWriters = props.chatModel.writers;
127+
const initialWriters = chatModel.writers;
128128
setWriters(initialWriters);
129129

130-
props.chatModel.writersChanged?.connect(updateWriters);
130+
chatModel.writersChanged?.connect(updateWriters);
131131

132132
return () => {
133-
props.chatModel?.writersChanged?.disconnect(updateWriters);
133+
chatModel?.writersChanged?.disconnect(updateWriters);
134134
};
135-
}, [props.chatModel]);
135+
}, [chatModel]);
136136

137137
const inputExists = !!input.trim();
138138

@@ -196,7 +196,7 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
196196
(!sendWithShiftEnter && !event.shiftKey)
197197
) {
198198
// Run all command providers
199-
await props.chatCommandRegistry?.onSubmit(model);
199+
await chatCommandRegistry?.onSubmit(model);
200200
model.send(model.value);
201201
event.stopPropagation();
202202
event.preventDefault();
@@ -333,8 +333,8 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
333333
<item.element
334334
key={index}
335335
model={model}
336-
chatCommandRegistry={props.chatCommandRegistry}
337-
chatModel={props.chatModel}
336+
chatCommandRegistry={chatCommandRegistry}
337+
chatModel={chatModel}
338338
edit={props.edit}
339339
/>
340340
))}
@@ -357,10 +357,6 @@ export namespace ChatInput {
357357
* The input model.
358358
*/
359359
model: IInputModel;
360-
/**
361-
* The toolbar registry.
362-
*/
363-
toolbarRegistry: IInputToolbarRegistry;
364360
/**
365361
* The function to be called to cancel editing.
366362
*/
@@ -369,18 +365,10 @@ export namespace ChatInput {
369365
* Custom mui/material styles.
370366
*/
371367
sx?: SxProps<Theme>;
372-
/**
373-
* Chat command registry.
374-
*/
375-
chatCommandRegistry?: IChatCommandRegistry;
376368
/**
377369
* The area where the chat is displayed.
378370
*/
379371
area?: ChatArea;
380-
/**
381-
* The chat model.
382-
*/
383-
chatModel?: IChatModel;
384372
/**
385373
* Whether the input is in edit mode (editing an existing message).
386374
* Defaults to false (new message mode).

packages/jupyter-chat/src/components/messages/footer.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,17 @@
66
import { Box } from '@mui/material';
77
import React from 'react';
88

9-
import {
10-
IMessageFooterRegistry,
11-
MessageFooterSectionProps
12-
} from '../../registers';
9+
import { useChatContext } from '../../context';
10+
import { IChatMessage } from '../../types';
1311

1412
/**
1513
* The chat footer component properties.
1614
*/
17-
export interface IMessageFootersProps extends MessageFooterSectionProps {
15+
export interface IMessageFootersProps {
1816
/**
19-
* The chat footer registry.
17+
* The chat model.
2018
*/
21-
registry: IMessageFooterRegistry;
19+
message: IChatMessage;
2220
}
2321

2422
/**
@@ -27,9 +25,13 @@ export interface IMessageFootersProps extends MessageFooterSectionProps {
2725
*/
2826
export function MessageFooterComponent(
2927
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();
3335

3436
return (
3537
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>

packages/jupyter-chat/src/components/messages/message-renderer.tsx

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@
33
* Distributed under the terms of the Modified BSD License.
44
*/
55

6-
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
76
import { PromiseDelegate } from '@lumino/coreutils';
87
import React, { useState, useEffect } from 'react';
98
import { createPortal } from 'react-dom';
109

11-
import { CodeToolbar, CodeToolbarProps } from '../code-blocks/code-toolbar';
1210
import { MessageToolbar } from './toolbar';
11+
import { CodeToolbar, CodeToolbarProps } from '../code-blocks/code-toolbar';
12+
import { useChatContext } from '../../context';
1313
import { MarkdownRenderer, MD_RENDERED_CLASS } from '../../markdown-renderer';
14-
import { IChatModel } from '../../model';
1514

1615
/**
1716
* The type of the props for the MessageRenderer component.
@@ -21,14 +20,6 @@ type MessageRendererProps = {
2120
* The string to render.
2221
*/
2322
markdownStr: string;
24-
/**
25-
* The rendermime registry.
26-
*/
27-
rmRegistry: IRenderMimeRegistry;
28-
/**
29-
* The model of the chat.
30-
*/
31-
model: IChatModel;
3223
/**
3324
* The promise to resolve when the message is rendered.
3425
*/
@@ -51,7 +42,8 @@ type MessageRendererProps = {
5142
* The message renderer base component.
5243
*/
5344
function MessageRendererBase(props: MessageRendererProps): JSX.Element {
54-
const { markdownStr, rmRegistry } = props;
45+
const { markdownStr } = props;
46+
const { model, rmRegistry } = useChatContext();
5547
const appendContent = props.appendContent || false;
5648
const [renderedContent, setRenderedContent] = useState<HTMLElement | null>(
5749
null
@@ -81,7 +73,7 @@ function MessageRendererBase(props: MessageRendererProps): JSX.Element {
8173
);
8274
newCodeToolbarDefns.push([
8375
codeToolbarRoot,
84-
{ model: props.model, content: preBlock.textContent || '' }
76+
{ model: model, content: preBlock.textContent || '' }
8577
]);
8678
});
8779

packages/jupyter-chat/src/components/messages/message.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ import { PromiseDelegate } from '@lumino/coreutils';
77
import React, { forwardRef, useEffect, useState } from 'react';
88

99
import { MessageRenderer } from './message-renderer';
10-
import { BaseMessageProps } from './messages';
1110
import { AttachmentPreviewList } from '../attachments';
1211
import { ChatInput } from '../input';
12+
import { useChatContext } from '../../context';
1313
import { IInputModel, InputModel } from '../../input-model';
1414
import { IChatMessage } from '../../types';
1515
import { replaceSpanToMention } from '../../utils';
1616

1717
/**
1818
* The message component props.
1919
*/
20-
type ChatMessageProps = BaseMessageProps & {
20+
type ChatMessageProps = {
2121
/**
2222
* The message to display.
2323
*/
@@ -37,7 +37,8 @@ type ChatMessageProps = BaseMessageProps & {
3737
*/
3838
export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
3939
(props, ref): JSX.Element => {
40-
const { message, model, rmRegistry } = props;
40+
const { message } = props;
41+
const { model } = useChatContext();
4142
const [edit, setEdit] = useState<boolean>(false);
4243
const [deleted, setDeleted] = useState<boolean>(false);
4344
const [canEdit, setCanEdit] = useState<boolean>(false);
@@ -132,15 +133,11 @@ export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
132133
<ChatInput
133134
onCancel={() => cancelEdition()}
134135
model={model.getEditionModel(message.id)!}
135-
chatCommandRegistry={props.chatCommandRegistry}
136-
toolbarRegistry={props.inputToolbarRegistry}
137136
edit={true}
138137
/>
139138
) : (
140139
<MessageRenderer
141-
rmRegistry={rmRegistry}
142140
markdownStr={message.body}
143-
model={model}
144141
edit={canEdit ? startEdition : undefined}
145142
delete={canDelete ? () => deleteMessage(message.id) : undefined}
146143
rendered={props.renderedPromise}

0 commit comments

Comments
 (0)