@jupyter/chat 0.8.1 → 0.10.0

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 (69) hide show
  1. package/lib/__tests__/mocks.d.ts +9 -0
  2. package/lib/__tests__/mocks.js +18 -0
  3. package/lib/__tests__/model.spec.js +17 -10
  4. package/lib/__tests__/widgets.spec.js +4 -4
  5. package/lib/chat-commands/types.d.ts +2 -1
  6. package/lib/components/chat-input.d.ts +4 -12
  7. package/lib/components/chat-input.js +26 -40
  8. package/lib/components/chat-messages.d.ts +17 -4
  9. package/lib/components/chat-messages.js +28 -15
  10. package/lib/components/chat.d.ts +5 -5
  11. package/lib/components/chat.js +9 -8
  12. package/lib/components/code-blocks/copy-button.js +6 -3
  13. package/lib/components/input/buttons/attach-button.d.ts +6 -0
  14. package/lib/components/input/{attach-button.js → buttons/attach-button.js} +11 -8
  15. package/lib/components/input/buttons/cancel-button.d.ts +6 -0
  16. package/lib/components/input/{cancel-button.js → buttons/cancel-button.js} +5 -7
  17. package/lib/components/input/buttons/index.d.ts +3 -0
  18. package/lib/components/input/buttons/index.js +7 -0
  19. package/lib/components/input/buttons/send-button.d.ts +6 -0
  20. package/lib/components/input/{send-button.js → buttons/send-button.js} +52 -42
  21. package/lib/components/input/index.d.ts +3 -3
  22. package/lib/components/input/index.js +3 -3
  23. package/lib/components/input/toolbar-registry.d.ts +98 -0
  24. package/lib/components/input/toolbar-registry.js +85 -0
  25. package/lib/components/input/use-chat-commands.js +6 -5
  26. package/lib/components/mui-extras/tooltipped-button.d.ts +1 -1
  27. package/lib/components/mui-extras/tooltipped-button.js +3 -2
  28. package/lib/components/mui-extras/tooltipped-icon-button.js +4 -2
  29. package/lib/index.d.ts +1 -1
  30. package/lib/index.js +1 -1
  31. package/lib/input-model.d.ts +93 -1
  32. package/lib/input-model.js +55 -1
  33. package/lib/model.d.ts +76 -9
  34. package/lib/model.js +42 -12
  35. package/lib/types.d.ts +5 -18
  36. package/lib/utils.d.ts +15 -0
  37. package/lib/utils.js +29 -0
  38. package/lib/widgets/chat-widget.d.ts +5 -1
  39. package/lib/widgets/chat-widget.js +7 -1
  40. package/package.json +1 -1
  41. package/src/__tests__/mocks.ts +31 -0
  42. package/src/__tests__/model.spec.ts +21 -11
  43. package/src/__tests__/widgets.spec.ts +5 -4
  44. package/src/chat-commands/types.ts +1 -1
  45. package/src/components/chat-input.tsx +41 -66
  46. package/src/components/chat-messages.tsx +44 -17
  47. package/src/components/chat.tsx +12 -21
  48. package/src/components/code-blocks/copy-button.tsx +9 -3
  49. package/src/components/input/{attach-button.tsx → buttons/attach-button.tsx} +15 -20
  50. package/src/components/input/{cancel-button.tsx → buttons/cancel-button.tsx} +9 -16
  51. package/src/components/input/buttons/index.ts +8 -0
  52. package/src/components/input/{send-button.tsx → buttons/send-button.tsx} +62 -61
  53. package/src/components/input/index.ts +3 -3
  54. package/src/components/input/toolbar-registry.tsx +162 -0
  55. package/src/components/input/use-chat-commands.tsx +14 -6
  56. package/src/components/mui-extras/tooltipped-button.tsx +4 -2
  57. package/src/components/mui-extras/tooltipped-icon-button.tsx +5 -2
  58. package/src/index.ts +1 -1
  59. package/src/input-model.ts +140 -2
  60. package/src/model.ts +110 -12
  61. package/src/types.ts +5 -21
  62. package/src/utils.ts +34 -0
  63. package/src/widgets/chat-widget.tsx +8 -1
  64. package/style/base.css +1 -0
  65. package/style/chat.css +6 -0
  66. package/style/input.css +32 -0
  67. package/lib/components/input/attach-button.d.ts +0 -14
  68. package/lib/components/input/cancel-button.d.ts +0 -11
  69. package/lib/components/input/send-button.d.ts +0 -18
@@ -3,7 +3,6 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
 
6
- import { IDocumentManager } from '@jupyterlab/docmanager';
7
6
  import {
8
7
  Autocomplete,
9
8
  AutocompleteInputChangeReason,
@@ -17,16 +16,20 @@ import clsx from 'clsx';
17
16
  import React, { useEffect, useRef, useState } from 'react';
18
17
 
19
18
  import { AttachmentPreviewList } from './attachments';
20
- import { AttachButton, CancelButton, SendButton } from './input';
19
+ import {
20
+ IInputToolbarRegistry,
21
+ InputToolbarRegistry,
22
+ useChatCommands
23
+ } from './input';
21
24
  import { IInputModel, InputModel } from '../input-model';
22
- import { IAttachment, Selection } from '../types';
23
- import { useChatCommands } from './input/use-chat-commands';
24
25
  import { IChatCommandRegistry } from '../chat-commands';
26
+ import { IAttachment } from '../types';
25
27
 
26
28
  const INPUT_BOX_CLASS = 'jp-chat-input-container';
29
+ const INPUT_TOOLBAR_CLASS = 'jp-chat-input-toolbar';
27
30
 
28
31
  export function ChatInput(props: ChatInput.IProps): JSX.Element {
29
- const { documentManager, model } = props;
32
+ const { model, toolbarRegistry } = props;
30
33
  const [input, setInput] = useState<string>(model.value);
31
34
  const inputRef = useRef<HTMLInputElement>();
32
35
 
@@ -38,14 +41,16 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
38
41
  const [attachments, setAttachments] = useState<IAttachment[]>(
39
42
  model.attachments
40
43
  );
44
+ const [toolbarElements, setToolbarElements] = useState<
45
+ InputToolbarRegistry.IToolbarItem[]
46
+ >([]);
41
47
 
42
- // Display the include selection menu if it is not explicitly hidden, and if at least
43
- // one of the tool to check for text or cell selection is enabled.
44
- let hideIncludeSelection = props.hideIncludeSelection ?? false;
45
- if (model.activeCellManager === null && model.selectionWatcher === null) {
46
- hideIncludeSelection = true;
47
- }
48
-
48
+ /**
49
+ * Handle the changes on the model that affect the input.
50
+ * - focus requested
51
+ * - config changed
52
+ * - attachments changed
53
+ */
49
54
  useEffect(() => {
50
55
  const inputChanged = (_: IInputModel, value: string) => {
51
56
  setInput(value);
@@ -76,6 +81,22 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
76
81
  };
77
82
  }, [model]);
78
83
 
84
+ /**
85
+ * Handle the changes in the toolbar items.
86
+ */
87
+ useEffect(() => {
88
+ const updateToolbar = () => {
89
+ setToolbarElements(toolbarRegistry.getItems());
90
+ };
91
+
92
+ toolbarRegistry.itemsChanged.connect(updateToolbar);
93
+ updateToolbar();
94
+
95
+ return () => {
96
+ toolbarRegistry.itemsChanged.disconnect(updateToolbar);
97
+ };
98
+ }, [toolbarRegistry]);
99
+
79
100
  const inputExists = !!input.trim();
80
101
 
81
102
  /**
@@ -136,38 +157,12 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
136
157
  (sendWithShiftEnter && event.shiftKey) ||
137
158
  (!sendWithShiftEnter && !event.shiftKey)
138
159
  ) {
139
- onSend();
160
+ model.send(input);
140
161
  event.stopPropagation();
141
162
  event.preventDefault();
142
163
  }
143
164
  }
144
165
 
145
- /**
146
- * Triggered when sending the message.
147
- *
148
- * Add code block if cell or text is selected.
149
- */
150
- function onSend(selection?: Selection) {
151
- let content = input;
152
- if (selection) {
153
- content += `
154
-
155
- \`\`\`
156
- ${selection.source}
157
- \`\`\`
158
- `;
159
- }
160
- props.onSend(content);
161
- model.value = '';
162
- }
163
-
164
- /**
165
- * Triggered when cancelling edition.
166
- */
167
- function onCancel() {
168
- props.onCancel?.();
169
- }
170
-
171
166
  // Set the helper text based on whether Shift+Enter is used for sending.
172
167
  const helperText = sendWithShiftEnter ? (
173
168
  <span>
@@ -221,22 +216,10 @@ ${selection.source}
221
216
  InputProps={{
222
217
  ...params.InputProps,
223
218
  endAdornment: (
224
- <InputAdornment position="end">
225
- {documentManager && model.addAttachment && (
226
- <AttachButton
227
- documentManager={documentManager}
228
- onAttach={model.addAttachment}
229
- />
230
- )}
231
- {props.onCancel && <CancelButton onCancel={onCancel} />}
232
- <SendButton
233
- model={model}
234
- sendWithShiftEnter={sendWithShiftEnter}
235
- inputExists={inputExists || attachments.length > 0}
236
- onSend={onSend}
237
- hideIncludeSelection={hideIncludeSelection}
238
- hasButtonOnLeft={!!props.onCancel}
239
- />
219
+ <InputAdornment position="end" className={INPUT_TOOLBAR_CLASS}>
220
+ {toolbarElements.map(item => (
221
+ <item.element model={model} />
222
+ ))}
240
223
  </InputAdornment>
241
224
  )
242
225
  }}
@@ -273,29 +256,21 @@ export namespace ChatInput {
273
256
  */
274
257
  export interface IProps {
275
258
  /**
276
- * The chat model.
259
+ * The input model.
277
260
  */
278
261
  model: IInputModel;
279
262
  /**
280
- * The function to be called to send the message.
263
+ * The toolbar registry.
281
264
  */
282
- onSend: (input: string) => unknown;
265
+ toolbarRegistry: IInputToolbarRegistry;
283
266
  /**
284
267
  * The function to be called to cancel editing.
285
268
  */
286
269
  onCancel?: () => unknown;
287
- /**
288
- * Whether to allow or not including selection.
289
- */
290
- hideIncludeSelection?: boolean;
291
270
  /**
292
271
  * Custom mui/material styles.
293
272
  */
294
273
  sx?: SxProps<Theme>;
295
- /**
296
- * The document manager.
297
- */
298
- documentManager?: IDocumentManager;
299
274
  /**
300
275
  * Chat command registry.
301
276
  */
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  import { Button } from '@jupyter/react-components';
7
- import { IDocumentManager } from '@jupyterlab/docmanager';
8
7
  import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
9
8
  import {
10
9
  LabIcon,
@@ -19,12 +18,14 @@ import React, { useEffect, useState, useRef, forwardRef } from 'react';
19
18
 
20
19
  import { AttachmentPreviewList } from './attachments';
21
20
  import { ChatInput } from './chat-input';
21
+ import { IInputToolbarRegistry } from './input';
22
22
  import { MarkdownRenderer } from './markdown-renderer';
23
23
  import { ScrollContainer } from './scroll-container';
24
24
  import { IChatCommandRegistry } from '../chat-commands';
25
25
  import { IInputModel, InputModel } from '../input-model';
26
26
  import { IChatModel } from '../model';
27
27
  import { IChatMessage, IUser } from '../types';
28
+ import { replaceSpanToMention } from '../utils';
28
29
 
29
30
  const MESSAGES_BOX_CLASS = 'jp-chat-messages-container';
30
31
  const MESSAGE_CLASS = 'jp-chat-message';
@@ -41,10 +42,22 @@ const NAVIGATION_BOTTOM_CLASS = 'jp-chat-navigation-bottom';
41
42
  * The base components props.
42
43
  */
43
44
  type BaseMessageProps = {
45
+ /**
46
+ * The mime renderer registry.
47
+ */
44
48
  rmRegistry: IRenderMimeRegistry;
49
+ /**
50
+ * The chat model.
51
+ */
45
52
  model: IChatModel;
53
+ /**
54
+ * The chat commands registry.
55
+ */
46
56
  chatCommandRegistry?: IChatCommandRegistry;
47
- documentManager?: IDocumentManager;
57
+ /**
58
+ * The input toolbar registry.
59
+ */
60
+ inputToolbarRegistry: IInputToolbarRegistry;
48
61
  };
49
62
 
50
63
  /**
@@ -200,8 +213,10 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element {
200
213
  * The message header props.
201
214
  */
202
215
  type ChatMessageHeaderProps = {
216
+ /**
217
+ * The chat message.
218
+ */
203
219
  message: IChatMessage;
204
- sx?: SxProps<Theme>;
205
220
  };
206
221
 
207
222
  /**
@@ -262,8 +277,7 @@ export function ChatMessageHeader(props: ChatMessageHeaderProps): JSX.Element {
262
277
  '& > :not(:last-child)': {
263
278
  marginRight: 3
264
279
  },
265
- marginBottom: message.stacked ? '0px' : '12px',
266
- ...props.sx
280
+ marginBottom: message.stacked ? '0px' : '12px'
267
281
  }}
268
282
  >
269
283
  {avatar}
@@ -362,17 +376,27 @@ export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
362
376
  // Create an input model only if the message is edited.
363
377
  useEffect(() => {
364
378
  if (edit && canEdit) {
365
- setInputModel(
366
- new InputModel({
367
- value: message.body,
379
+ setInputModel(() => {
380
+ let body = message.body;
381
+ message.mentions?.forEach(user => {
382
+ body = replaceSpanToMention(body, user);
383
+ });
384
+ return new InputModel({
385
+ chatContext: model.createChatContext(),
386
+ onSend: (input: string, model?: IInputModel) =>
387
+ updateMessage(message.id, input, model),
388
+ onCancel: () => cancelEdition(),
389
+ value: body,
368
390
  activeCellManager: model.activeCellManager,
369
391
  selectionWatcher: model.selectionWatcher,
392
+ documentManager: model.documentManager,
370
393
  config: {
371
394
  sendWithShiftEnter: model.config.sendWithShiftEnter
372
395
  },
373
- attachments: message.attachments
374
- })
375
- );
396
+ attachments: message.attachments,
397
+ mentions: message.mentions
398
+ });
399
+ });
376
400
  } else {
377
401
  setInputModel(null);
378
402
  }
@@ -384,14 +408,19 @@ export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
384
408
  };
385
409
 
386
410
  // Update the content of the message.
387
- const updateMessage = (id: string, input: string): void => {
388
- if (!canEdit) {
411
+ const updateMessage = (
412
+ id: string,
413
+ input: string,
414
+ inputModel?: IInputModel
415
+ ): void => {
416
+ if (!canEdit || !inputModel) {
389
417
  return;
390
418
  }
391
419
  // Update the message
392
420
  const updatedMessage = { ...message };
393
421
  updatedMessage.body = input;
394
- updatedMessage.attachments = inputModel?.attachments;
422
+ updatedMessage.attachments = inputModel.attachments;
423
+ updatedMessage.mentions = inputModel.mentions;
395
424
  model.updateMessage!(id, updatedMessage);
396
425
  setEdit(false);
397
426
  };
@@ -411,12 +440,10 @@ export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
411
440
  <div ref={ref} data-index={props.index}>
412
441
  {edit && canEdit && inputModel ? (
413
442
  <ChatInput
414
- onSend={(input: string) => updateMessage(message.id, input)}
415
443
  onCancel={() => cancelEdition()}
416
444
  model={inputModel}
417
- hideIncludeSelection={true}
418
445
  chatCommandRegistry={props.chatCommandRegistry}
419
- documentManager={props.documentManager}
446
+ toolbarRegistry={props.inputToolbarRegistry}
420
447
  />
421
448
  ) : (
422
449
  <MarkdownRenderer
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  import { IThemeManager } from '@jupyterlab/apputils';
7
- import { IDocumentManager } from '@jupyterlab/docmanager';
8
7
  import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
9
8
  import ArrowBackIcon from '@mui/icons-material/ArrowBack';
10
9
  import SettingsIcon from '@mui/icons-material/Settings';
@@ -16,16 +15,17 @@ import { JlThemeProvider } from './jl-theme-provider';
16
15
  import { IChatCommandRegistry } from '../chat-commands';
17
16
  import { ChatMessages } from './chat-messages';
18
17
  import { ChatInput } from './chat-input';
18
+ import { IInputToolbarRegistry, InputToolbarRegistry } from './input';
19
19
  import { AttachmentOpenerContext } from '../context';
20
20
  import { IChatModel } from '../model';
21
21
  import { IAttachmentOpenerRegistry } from '../registry';
22
22
 
23
23
  export function ChatBody(props: Chat.IChatBodyProps): JSX.Element {
24
24
  const { model } = props;
25
- const onSend = async (input: string) => {
26
- // send message to backend
27
- model.sendMessage({ body: input });
28
- };
25
+ let { inputToolbarRegistry } = props;
26
+ if (!inputToolbarRegistry) {
27
+ inputToolbarRegistry = InputToolbarRegistry.defaultToolbarRegistry();
28
+ }
29
29
 
30
30
  return (
31
31
  <AttachmentOpenerContext.Provider value={props.attachmentOpenerRegistry}>
@@ -33,10 +33,9 @@ export function ChatBody(props: Chat.IChatBodyProps): JSX.Element {
33
33
  rmRegistry={props.rmRegistry}
34
34
  model={model}
35
35
  chatCommandRegistry={props.chatCommandRegistry}
36
- documentManager={props.documentManager}
36
+ inputToolbarRegistry={inputToolbarRegistry}
37
37
  />
38
38
  <ChatInput
39
- onSend={onSend}
40
39
  sx={{
41
40
  paddingLeft: 4,
42
41
  paddingRight: 4,
@@ -45,8 +44,8 @@ export function ChatBody(props: Chat.IChatBodyProps): JSX.Element {
45
44
  borderTop: '1px solid var(--jp-border-color1)'
46
45
  }}
47
46
  model={model.input}
48
- documentManager={props.documentManager}
49
47
  chatCommandRegistry={props.chatCommandRegistry}
48
+ toolbarRegistry={inputToolbarRegistry}
50
49
  />
51
50
  </AttachmentOpenerContext.Provider>
52
51
  );
@@ -89,15 +88,7 @@ export function Chat(props: Chat.IOptions): JSX.Element {
89
88
  )}
90
89
  </Box>
91
90
  {/* body */}
92
- {view === Chat.View.chat && (
93
- <ChatBody
94
- model={props.model}
95
- rmRegistry={props.rmRegistry}
96
- documentManager={props.documentManager}
97
- chatCommandRegistry={props.chatCommandRegistry}
98
- attachmentOpenerRegistry={props.attachmentOpenerRegistry}
99
- />
100
- )}
91
+ {view === Chat.View.chat && <ChatBody {...props} />}
101
92
  {view === Chat.View.settings && props.settingsPanel && (
102
93
  <props.settingsPanel />
103
94
  )}
@@ -122,10 +113,6 @@ export namespace Chat {
122
113
  * The rendermime registry.
123
114
  */
124
115
  rmRegistry: IRenderMimeRegistry;
125
- /**
126
- * The document manager.
127
- */
128
- documentManager?: IDocumentManager;
129
116
  /**
130
117
  * Chat command registry.
131
118
  */
@@ -134,6 +121,10 @@ export namespace Chat {
134
121
  * Attachment opener registry.
135
122
  */
136
123
  attachmentOpenerRegistry?: IAttachmentOpenerRegistry;
124
+ /**
125
+ * The input toolbar registry
126
+ */
127
+ inputToolbarRegistry?: IInputToolbarRegistry;
137
128
  }
138
129
 
139
130
  /**
@@ -12,13 +12,15 @@ import { TooltippedIconButton } from '../mui-extras/tooltipped-icon-button';
12
12
  enum CopyStatus {
13
13
  None,
14
14
  Copying,
15
- Copied
15
+ Copied,
16
+ Disabled
16
17
  }
17
18
 
18
19
  const COPYBTN_TEXT_BY_STATUS: Record<CopyStatus, string> = {
19
20
  [CopyStatus.None]: 'Copy to clipboard',
20
21
  [CopyStatus.Copying]: 'Copying…',
21
- [CopyStatus.Copied]: 'Copied!'
22
+ [CopyStatus.Copied]: 'Copied!',
23
+ [CopyStatus.Disabled]: 'Copy to clipboard disabled in insecure context'
22
24
  };
23
25
 
24
26
  type CopyButtonProps = {
@@ -27,7 +29,10 @@ type CopyButtonProps = {
27
29
  };
28
30
 
29
31
  export function CopyButton(props: CopyButtonProps): JSX.Element {
30
- const [copyStatus, setCopyStatus] = useState<CopyStatus>(CopyStatus.None);
32
+ const isCopyDisabled = navigator.clipboard === undefined;
33
+ const [copyStatus, setCopyStatus] = useState<CopyStatus>(
34
+ isCopyDisabled ? CopyStatus.Disabled : CopyStatus.None
35
+ );
31
36
  const timeoutId = useRef<number | null>(null);
32
37
 
33
38
  const copy = useCallback(async () => {
@@ -56,6 +61,7 @@ export function CopyButton(props: CopyButtonProps): JSX.Element {
56
61
 
57
62
  return (
58
63
  <TooltippedIconButton
64
+ disabled={isCopyDisabled}
59
65
  className={props.className}
60
66
  tooltip={COPYBTN_TEXT_BY_STATUS[copyStatus]}
61
67
  placement="top"
@@ -3,40 +3,41 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
 
6
- import { IDocumentManager } from '@jupyterlab/docmanager';
7
6
  import { FileDialog } from '@jupyterlab/filebrowser';
8
7
  import AttachFileIcon from '@mui/icons-material/AttachFile';
9
8
  import React from 'react';
10
9
 
11
- import { TooltippedButton } from '../mui-extras/tooltipped-button';
12
- import { IAttachment } from '../../types';
10
+ import { InputToolbarRegistry } from '../toolbar-registry';
11
+ import { TooltippedButton } from '../../mui-extras/tooltipped-button';
13
12
 
14
13
  const ATTACH_BUTTON_CLASS = 'jp-chat-attach-button';
15
14
 
16
- /**
17
- * The attach button props.
18
- */
19
- export type AttachButtonProps = {
20
- documentManager: IDocumentManager;
21
- onAttach: (attachment: IAttachment) => void;
22
- };
23
-
24
15
  /**
25
16
  * The attach button.
26
17
  */
27
- export function AttachButton(props: AttachButtonProps): JSX.Element {
18
+ export function AttachButton(
19
+ props: InputToolbarRegistry.IToolbarItemProps
20
+ ): JSX.Element {
21
+ const { model } = props;
28
22
  const tooltip = 'Add attachment';
29
23
 
24
+ if (!model.documentManager || !model.addAttachment) {
25
+ return <></>;
26
+ }
27
+
30
28
  const onclick = async () => {
29
+ if (!model.documentManager || !model.addAttachment) {
30
+ return;
31
+ }
31
32
  try {
32
33
  const files = await FileDialog.getOpenFiles({
33
34
  title: 'Select files to attach',
34
- manager: props.documentManager
35
+ manager: model.documentManager
35
36
  });
36
37
  if (files.value) {
37
38
  files.value.forEach(file => {
38
39
  if (file.type !== 'directory') {
39
- props.onAttach({ type: 'file', value: file.path });
40
+ model.addAttachment?.({ type: 'file', value: file.path });
40
41
  }
41
42
  });
42
43
  }
@@ -55,12 +56,6 @@ export function AttachButton(props: AttachButtonProps): JSX.Element {
55
56
  title: tooltip,
56
57
  className: ATTACH_BUTTON_CLASS
57
58
  }}
58
- sx={{
59
- minWidth: 'unset',
60
- padding: '4px',
61
- borderRadius: '2px 0px 0px 2px',
62
- marginRight: '1px'
63
- }}
64
59
  >
65
60
  <AttachFileIcon />
66
61
  </TooltippedButton>
@@ -6,25 +6,24 @@
6
6
  import CancelIcon from '@mui/icons-material/Cancel';
7
7
  import React from 'react';
8
8
 
9
- import { TooltippedButton } from '../mui-extras/tooltipped-button';
9
+ import { InputToolbarRegistry } from '../toolbar-registry';
10
+ import { TooltippedButton } from '../../mui-extras/tooltipped-button';
10
11
 
11
12
  const CANCEL_BUTTON_CLASS = 'jp-chat-cancel-button';
12
13
 
13
- /**
14
- * The cancel button props.
15
- */
16
- export type CancelButtonProps = {
17
- onCancel: () => void;
18
- };
19
-
20
14
  /**
21
15
  * The cancel button.
22
16
  */
23
- export function CancelButton(props: CancelButtonProps): JSX.Element {
17
+ export function CancelButton(
18
+ props: InputToolbarRegistry.IToolbarItemProps
19
+ ): JSX.Element {
20
+ if (!props.model.cancel) {
21
+ return <></>;
22
+ }
24
23
  const tooltip = 'Cancel edition';
25
24
  return (
26
25
  <TooltippedButton
27
- onClick={props.onCancel}
26
+ onClick={props.model.cancel}
28
27
  tooltip={tooltip}
29
28
  buttonProps={{
30
29
  size: 'small',
@@ -32,12 +31,6 @@ export function CancelButton(props: CancelButtonProps): JSX.Element {
32
31
  title: tooltip,
33
32
  className: CANCEL_BUTTON_CLASS
34
33
  }}
35
- sx={{
36
- minWidth: 'unset',
37
- padding: '4px',
38
- borderRadius: '2px 0px 0px 2px',
39
- marginRight: '1px'
40
- }}
41
34
  >
42
35
  <CancelIcon />
43
36
  </TooltippedButton>
@@ -0,0 +1,8 @@
1
+ /*
2
+ * Copyright (c) Jupyter Development Team.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+
6
+ export { AttachButton } from './attach-button';
7
+ export { CancelButton } from './cancel-button';
8
+ export { SendButton } from './send-button';