@jupyter/chat 0.1.0 → 0.2.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.
@@ -0,0 +1,129 @@
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
+ import { IAutocompletionCommandsProps } from './types';
7
+
8
+ /**
9
+ * The token for the autocomplete registry, which can be provided by an extension
10
+ * using @jupyter/chat package.
11
+ */
12
+ export const IAutocompletionRegistry = new Token<IAutocompletionRegistry>(
13
+ '@jupyter/chat:IAutocompleteRegistry'
14
+ );
15
+
16
+ /**
17
+ * The interface of a registry to provide autocompleters.
18
+ */
19
+ export interface IAutocompletionRegistry {
20
+ /**
21
+ * The default autocompletion name.
22
+ */
23
+ default: string | null;
24
+ /**
25
+ * Get the default autocompletion.
26
+ */
27
+ getDefaultCompletion(): IAutocompletionCommandsProps | undefined;
28
+ /**
29
+ * Return a registered autocomplete props.
30
+ *
31
+ * @param name - the name of the registered autocomplete props.
32
+ */
33
+ get(name: string): IAutocompletionCommandsProps | undefined;
34
+
35
+ /**
36
+ * Register autocomplete props.
37
+ *
38
+ * @param name - the name for the registration.
39
+ * @param autocompletion - the autocomplete props.
40
+ */
41
+ add(name: string, autocompletion: IAutocompletionCommandsProps): boolean;
42
+
43
+ /**
44
+ * Remove a registered autocomplete props.
45
+ *
46
+ * @param name - the name of the autocomplete props.
47
+ */
48
+ remove(name: string): boolean;
49
+ }
50
+
51
+ /**
52
+ * A registry to provide autocompleters.
53
+ */
54
+ export class AutocompletionRegistry implements IAutocompletionRegistry {
55
+ /**
56
+ * Getter and setter for the default autocompletion name.
57
+ */
58
+ get default(): string | null {
59
+ return this._default;
60
+ }
61
+ set default(name: string | null) {
62
+ if (name === null || this._autocompletions.has(name)) {
63
+ this._default = name;
64
+ } else {
65
+ console.warn(`There is no registered completer with the name '${name}'`);
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Get the default autocompletion.
71
+ */
72
+ getDefaultCompletion(): IAutocompletionCommandsProps | undefined {
73
+ if (this._default === null) {
74
+ return undefined;
75
+ }
76
+ return this._autocompletions.get(this._default);
77
+ }
78
+
79
+ /**
80
+ * Return a registered autocomplete props.
81
+ *
82
+ * @param name - the name of the registered autocomplete props.
83
+ */
84
+ get(name: string): IAutocompletionCommandsProps | undefined {
85
+ return this._autocompletions.get(name);
86
+ }
87
+
88
+ /**
89
+ * Register autocomplete props.
90
+ *
91
+ * @param name - the name for the registration.
92
+ * @param autocompletion - the autocomplete props.
93
+ */
94
+ add(
95
+ name: string,
96
+ autocompletion: IAutocompletionCommandsProps,
97
+ isDefault: boolean = false
98
+ ): boolean {
99
+ if (!this._autocompletions.has(name)) {
100
+ this._autocompletions.set(name, autocompletion);
101
+ if (this._autocompletions.size === 1 || isDefault) {
102
+ this.default = name;
103
+ }
104
+ return true;
105
+ } else {
106
+ console.warn(`A completer with the name '${name}' is already registered`);
107
+ return false;
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Remove a registered autocomplete props.
113
+ *
114
+ * @param name - the name of the autocomplete props.
115
+ */
116
+ remove(name: string): boolean {
117
+ return this._autocompletions.delete(name);
118
+ }
119
+
120
+ /**
121
+ * Remove all registered autocompletions.
122
+ */
123
+ removeAll(): void {
124
+ this._autocompletions.clear();
125
+ }
126
+
127
+ private _default: string | null = null;
128
+ private _autocompletions = new Map<string, IAutocompletionCommandsProps>();
129
+ }
package/src/types.ts CHANGED
@@ -19,22 +19,37 @@ export interface IUser {
19
19
  * The configuration interface.
20
20
  */
21
21
  export interface IConfig {
22
+ /**
23
+ * Whether to send a message via Shift-Enter instead of Enter.
24
+ */
22
25
  sendWithShiftEnter?: boolean;
26
+ /**
27
+ * Last read message (no use yet).
28
+ */
23
29
  lastRead?: number;
30
+ /**
31
+ * Whether to stack consecutive messages from same user.
32
+ */
33
+ stackMessages?: boolean;
34
+ /**
35
+ * Whether to enable or not the notifications on unread messages.
36
+ */
37
+ unreadNotifications?: boolean;
24
38
  }
25
39
 
26
40
  /**
27
- * The chat message decription.
41
+ * The chat message description.
28
42
  */
29
- export interface IChatMessage {
43
+ export interface IChatMessage<T = IUser> {
30
44
  type: 'msg';
31
45
  body: string;
32
46
  id: string;
33
47
  time: number;
34
- sender: IUser | string;
48
+ sender: T;
35
49
  raw_time?: boolean;
36
50
  deleted?: boolean;
37
51
  edited?: boolean;
52
+ stacked?: boolean;
38
53
  }
39
54
 
40
55
  /**
@@ -53,6 +68,45 @@ export interface INewMessage {
53
68
  }
54
69
 
55
70
  /**
56
- * An empty interface to describe optional settings taht could be fetched from server.
71
+ * An empty interface to describe optional settings that could be fetched from server.
57
72
  */
58
73
  export interface ISettings {}
74
+
75
+ /**
76
+ * The autocomplete command type.
77
+ */
78
+ export type AutocompleteCommand = {
79
+ label: string;
80
+ };
81
+
82
+ /**
83
+ * The properties of the autocompletion.
84
+ *
85
+ * The autocompletion component will open if the 'opener' string is typed at the
86
+ * beginning of the input field.
87
+ */
88
+ export interface IAutocompletionCommandsProps {
89
+ /**
90
+ * The string that open the completer.
91
+ */
92
+ opener: string;
93
+ /**
94
+ * The list of available commands.
95
+ */
96
+ commands?: AutocompleteCommand[] | (() => Promise<AutocompleteCommand[]>);
97
+ /**
98
+ * The props for the Autocomplete component.
99
+ *
100
+ * Must be compatible with https://mui.com/material-ui/api/autocomplete/#props.
101
+ *
102
+ * ## NOTES:
103
+ * - providing `options` will overwrite the commands argument.
104
+ * - providing `renderInput` will overwrite the input component.
105
+ * - providing `renderOptions` allows to customize the rendering of the component.
106
+ * - some arguments should not be provided and would be overwritten:
107
+ * - inputValue
108
+ * - onInputChange
109
+ * - onHighlightChange
110
+ */
111
+ props?: any;
112
+ }
@@ -3,26 +3,14 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
 
6
- import { IThemeManager, ReactWidget } from '@jupyterlab/apputils';
7
- import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
6
+ import { ReactWidget } from '@jupyterlab/apputils';
8
7
  import React from 'react';
9
8
 
10
9
  import { Chat } from '../components/chat';
11
10
  import { chatIcon } from '../icons';
12
- import { IChatModel } from '../model';
13
11
 
14
- export function buildChatSidebar(
15
- chatModel: IChatModel,
16
- themeManager: IThemeManager | null,
17
- rmRegistry: IRenderMimeRegistry
18
- ): ReactWidget {
19
- const ChatWidget = ReactWidget.create(
20
- <Chat
21
- model={chatModel}
22
- themeManager={themeManager}
23
- rmRegistry={rmRegistry}
24
- />
25
- );
12
+ export function buildChatSidebar(options: Chat.IOptions): ReactWidget {
13
+ const ChatWidget = ReactWidget.create(<Chat {...options} />);
26
14
  ChatWidget.id = 'jupyter-chat::side-panel';
27
15
  ChatWidget.title.icon = chatIcon;
28
16
  ChatWidget.title.caption = 'Jupyter Chat'; // TODO: i18n
@@ -3,8 +3,7 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
 
6
- import { IThemeManager, ReactWidget } from '@jupyterlab/apputils';
7
- import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
6
+ import { ReactWidget } from '@jupyterlab/apputils';
8
7
  import React from 'react';
9
8
 
10
9
  import { Chat } from '../components/chat';
@@ -19,33 +18,21 @@ export class ChatWidget extends ReactWidget {
19
18
  this.title.icon = chatIcon;
20
19
  this.title.caption = 'Jupyter Chat'; // TODO: i18n
21
20
 
22
- this._model = options.model;
23
- this._themeManager = options?.themeManager || null;
24
- this._rmRegistry = options.rmRegistry;
21
+ this._chatOptions = options;
25
22
  }
26
23
 
27
24
  /**
28
- * Gte the model of the widget.
25
+ * Get the model of the widget.
29
26
  */
30
27
  get model(): IChatModel {
31
- return this._model;
28
+ return this._chatOptions.model;
32
29
  }
33
30
 
34
31
  render() {
35
- return (
36
- <Chat
37
- model={this._model}
38
- themeManager={this._themeManager}
39
- rmRegistry={this._rmRegistry}
40
- />
41
- );
32
+ // The model need to be passed, otherwise it is undefined in the widget in
33
+ // the case of collaborative document.
34
+ return <Chat {...this._chatOptions} model={this._chatOptions.model} />;
42
35
  }
43
36
 
44
- private readonly _model: IChatModel;
45
- private _themeManager: IThemeManager | null;
46
- private _rmRegistry: IRenderMimeRegistry;
47
- }
48
-
49
- export namespace ChatWidget {
50
- export interface IOptions extends Chat.IOptions {}
37
+ private _chatOptions: Chat.IOptions;
51
38
  }
package/style/chat.css CHANGED
@@ -2,6 +2,17 @@
2
2
  * Copyright (c) Jupyter Development Team.
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
+ .jp-chat-message:not(:first-child):not(.jp-chat-message-stacked) {
6
+ border-top: 1px solid var(--jp-border-color2);
7
+ }
8
+
9
+ .jp-chat-message:not(.jp-chat-message-stacked) {
10
+ padding: 1em 1em 0 1em;
11
+ }
12
+
13
+ .jp-chat-message.jp-chat-message-stacked {
14
+ padding: 0 1em;
15
+ }
5
16
 
6
17
  .jp-chat-rendermime-markdown {
7
18
  position: relative;
@@ -51,3 +62,32 @@
51
62
  .jp-chat-toolbar > .jp-ToolbarButtonComponent {
52
63
  margin-top: 0px;
53
64
  }
65
+
66
+ .jp-chat-navigation {
67
+ position: absolute;
68
+ right: 10px;
69
+ width: 24px;
70
+ height: 24px;
71
+ border-radius: 50%;
72
+ min-width: 0;
73
+ }
74
+
75
+ .jp-chat-navigation-unread {
76
+ border: solid 2px var(--jp-cell-inprompt-font-color);
77
+ }
78
+
79
+ .jp-chat-navigation::part(control) {
80
+ padding: 0;
81
+ }
82
+
83
+ .jp-chat-navigation-top {
84
+ top: 10px;
85
+ }
86
+
87
+ .jp-chat-navigation-top svg {
88
+ transform: rotate(180deg);
89
+ }
90
+
91
+ .jp-chat-navigation-bottom {
92
+ bottom: 100px;
93
+ }
@@ -0,0 +1,11 @@
1
+ <svg height="24px" viewBox="0 0 24 24" width="24px" xmlns="http://www.w3.org/2000/svg">
2
+ <g>
3
+ <path
4
+ style="display:inline;fill:none;fill-opacity:1;stroke:#545454;stroke-width:1.54693;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:1.5;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
5
+ d="M 2.2734634,9 V 20.226537 H 21.726536 V 9" />
6
+ <path
7
+ style="display:inline;fill:none;stroke:#545454;stroke-width:1.54528;stroke-linecap:square;stroke-miterlimit:10"
8
+ transform="matrix(0.81805878,0.57513462,-0.81805878,0.57513462,0,0)"
9
+ d="M 9.5141659,-5.1535239 H 20.802967 V 6.1352773 H 9.5141659 Z" />
10
+ </g>
11
+ </svg>