@dxos/react-ui-chat 0.8.4-main.f5c0578 → 0.8.4-main.fcfe5033a5

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 (32) hide show
  1. package/dist/lib/browser/index.mjs +138 -334
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +138 -334
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/components/ChatDialog/ChatDialog.d.ts +1 -1
  8. package/dist/types/src/components/ChatDialog/ChatDialog.d.ts.map +1 -1
  9. package/dist/types/src/components/ChatDialog/ChatDialog.stories.d.ts +35 -5
  10. package/dist/types/src/components/ChatDialog/ChatDialog.stories.d.ts.map +1 -1
  11. package/dist/types/src/components/ChatEditor/ChatEditor.d.ts +7 -9
  12. package/dist/types/src/components/ChatEditor/ChatEditor.d.ts.map +1 -1
  13. package/dist/types/src/components/ChatEditor/ChatEditor.stories.d.ts +20 -5
  14. package/dist/types/src/components/ChatEditor/ChatEditor.stories.d.ts.map +1 -1
  15. package/dist/types/src/components/ChatEditor/references.d.ts +4 -0
  16. package/dist/types/src/components/ChatEditor/references.d.ts.map +1 -1
  17. package/dist/types/src/index.d.ts +1 -0
  18. package/dist/types/src/index.d.ts.map +1 -1
  19. package/dist/types/src/translations.d.ts +2 -35
  20. package/dist/types/src/translations.d.ts.map +1 -1
  21. package/dist/types/tsconfig.tsbuildinfo +1 -1
  22. package/package.json +42 -39
  23. package/src/components/ChatDialog/ChatDialog.stories.tsx +6 -9
  24. package/src/components/ChatDialog/ChatDialog.tsx +27 -17
  25. package/src/components/ChatEditor/ChatEditor.stories.tsx +21 -22
  26. package/src/components/ChatEditor/ChatEditor.tsx +33 -65
  27. package/src/components/ChatEditor/references.ts +18 -12
  28. package/src/index.ts +1 -0
  29. package/src/translations.ts +2 -41
  30. package/dist/types/src/components/ChatEditor/autocomplete.d.ts +0 -26
  31. package/dist/types/src/components/ChatEditor/autocomplete.d.ts.map +0 -1
  32. package/src/components/ChatEditor/autocomplete.ts +0 -220
@@ -1,121 +1,98 @@
1
1
  // src/components/ChatDialog/ChatDialog.tsx
2
- import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
3
2
  import { createContext } from "@radix-ui/react-context";
4
3
  import React, { useEffect, useState } from "react";
5
4
  import { Dialog, Icon, IconButton, useControlledState } from "@dxos/react-ui";
6
5
  import { ResizeHandle, resizeAttributes, sizeStyle } from "@dxos/react-ui-dnd";
7
- import { mx } from "@dxos/react-ui-theme";
6
+ import { mx } from "@dxos/ui-theme";
8
7
  var preventDefault = (event) => event.preventDefault();
9
8
  var Endcap = ({ children }) => {
10
- var _effect = _useSignals();
11
- try {
12
- return /* @__PURE__ */ React.createElement("div", {
13
- className: "grid w-[var(--rail-action)] h-[var(--rail-action)] items-center justify-center"
14
- }, children);
15
- } finally {
16
- _effect.f();
17
- }
9
+ return /* @__PURE__ */ React.createElement("div", {
10
+ className: "grid w-[var(--dx-rail-action)] h-[var(--dx-rail-action)] items-center justify-center"
11
+ }, children);
18
12
  };
19
13
  var [ChatDialogContextProvider, useChatDialogContext] = createContext("ChatDialog");
20
- var ChatDialogRoot = ({ children, open: _open = false, expanded: _expanded = false, onOpenChange, onExpandedChange, onEscape }) => {
21
- var _effect = _useSignals();
22
- try {
23
- const [size, setSize] = useState("min-content");
24
- const [open, setOpen] = useControlledState(_open, onOpenChange);
25
- const [expanded, setExpanded] = useControlledState(_expanded, onExpandedChange);
26
- return /* @__PURE__ */ React.createElement(ChatDialogContextProvider, {
27
- open,
28
- setOpen,
29
- expanded,
30
- setExpanded,
31
- size,
32
- setSize
33
- }, /* @__PURE__ */ React.createElement(Dialog.Root, {
34
- modal: false,
35
- open,
36
- onOpenChange: setOpen
37
- }, /* @__PURE__ */ React.createElement("div", {
38
- role: "none",
39
- className: "dx-dialog__overlay bg-transparent pointer-events-none",
40
- "data-block-align": "end"
41
- }, /* @__PURE__ */ React.createElement(Dialog.Content, {
42
- inOverlayLayout: true,
43
- classNames: [
44
- "grid grid-rows-[var(--rail-action)_1fr_min-content] p-0 overflow-hidden",
45
- "box-content md:is-[35rem] md:max-is-none pointer-events-auto"
46
- ],
47
- onEscapeKeyDown: onEscape,
48
- onInteractOutside: preventDefault
49
- }, children))));
50
- } finally {
51
- _effect.f();
52
- }
14
+ var ChatDialogRoot = ({ children, open: openProp = false, expanded: expandedProp = false, onOpenChange, onExpandedChange, onEscape }) => {
15
+ const [size, setSize] = useState("min-content");
16
+ const [open, setOpen] = useControlledState(openProp, onOpenChange);
17
+ const [expanded, setExpanded] = useControlledState(expandedProp, onExpandedChange);
18
+ return /* @__PURE__ */ React.createElement(ChatDialogContextProvider, {
19
+ open,
20
+ setOpen,
21
+ expanded,
22
+ setExpanded,
23
+ size,
24
+ setSize
25
+ }, /* @__PURE__ */ React.createElement(Dialog.Root, {
26
+ modal: false,
27
+ open,
28
+ onOpenChange: setOpen
29
+ }, /* @__PURE__ */ React.createElement("div", {
30
+ role: "none",
31
+ className: "dx-dialog__overlay bg-transparent pointer-events-none",
32
+ "data-block-align": "end"
33
+ }, /* @__PURE__ */ React.createElement(Dialog.Content, {
34
+ size: "md",
35
+ inOverlayLayout: true,
36
+ classNames: [
37
+ "grid grid-rows-[var(--dx-rail-action)_1fr_min-content] p-0 overflow-hidden box-content pointer-events-auto"
38
+ ],
39
+ onEscapeKeyDown: onEscape,
40
+ onInteractOutside: preventDefault
41
+ }, children))));
53
42
  };
54
43
  ChatDialogRoot.displayName = "ChatDialog.Root";
44
+ var CHAT_DIALOG_HEADER_NAME = "ChatDialog.Header";
55
45
  var ChatDialogHeader = ({ classNames, title }) => {
56
- var _effect = _useSignals();
57
- try {
58
- const { expanded, setExpanded } = useChatDialogContext(ChatDialogHeader.displayName);
59
- return /* @__PURE__ */ React.createElement("div", {
60
- className: mx("grid grid-cols-[var(--rail-action)_1fr_min-content] items-center overflow-hidden", classNames)
61
- }, /* @__PURE__ */ React.createElement(Endcap, null, /* @__PURE__ */ React.createElement(Dialog.Close, null, /* @__PURE__ */ React.createElement(Icon, {
62
- icon: "ph--x--regular"
63
- }))), /* @__PURE__ */ React.createElement(Dialog.Title, {
64
- classNames: "flex w-full justify-center text-sm text-subdued select-none cursor-pointer",
65
- onClick: () => setExpanded((expanded2) => !expanded2)
66
- }, title), /* @__PURE__ */ React.createElement(Endcap, null, /* @__PURE__ */ React.createElement(IconButton, {
67
- variant: "ghost",
68
- icon: "ph--caret-up--regular",
69
- iconOnly: true,
70
- classNames: mx("!p-1 [&>svg]:transition [&>svg]:duration-200", expanded && "[&>svg]:rotate-180"),
71
- label: expanded ? "Close" : "Open",
72
- onClick: () => setExpanded((expanded2) => !expanded2)
73
- })));
74
- } finally {
75
- _effect.f();
76
- }
46
+ const { expanded, setExpanded } = useChatDialogContext(CHAT_DIALOG_HEADER_NAME);
47
+ return /* @__PURE__ */ React.createElement("div", {
48
+ className: mx("grid grid-cols-[var(--dx-rail-action)_1fr_min-content] items-center overflow-hidden", classNames)
49
+ }, /* @__PURE__ */ React.createElement(Endcap, null, /* @__PURE__ */ React.createElement(Dialog.Close, null, /* @__PURE__ */ React.createElement(Icon, {
50
+ icon: "ph--x--regular"
51
+ }))), /* @__PURE__ */ React.createElement(Dialog.Title, {
52
+ classNames: "flex w-full justify-center text-sm text-subdued select-none cursor-pointer",
53
+ onClick: () => setExpanded((expanded2) => !expanded2)
54
+ }, title), /* @__PURE__ */ React.createElement(Endcap, null, /* @__PURE__ */ React.createElement(IconButton, {
55
+ variant: "ghost",
56
+ icon: "ph--caret-up--regular",
57
+ iconOnly: true,
58
+ classNames: mx("p-1! [&>svg]:transition [&>svg]:duration-200", expanded && "[&>svg]:rotate-180"),
59
+ label: expanded ? "Close" : "Open",
60
+ onClick: () => setExpanded((expanded2) => !expanded2)
61
+ })));
77
62
  };
78
- ChatDialogHeader.displayName = "ChatDialog.Header";
63
+ ChatDialogHeader.displayName = CHAT_DIALOG_HEADER_NAME;
64
+ var CHAT_DIALOG_CONTENT_NAME = "ChatDialog.Content";
79
65
  var ChatDialogContent = ({ children, classNames }) => {
80
- var _effect = _useSignals();
81
- try {
82
- const { expanded, size, setSize } = useChatDialogContext(ChatDialogContent.displayName);
83
- useEffect(() => {
84
- setSize(expanded ? "min-content" : 0);
85
- }, [
86
- expanded
87
- ]);
88
- return /* @__PURE__ */ React.createElement("div", {
89
- className: mx("flex flex-col overflow-y-auto border-t border-b border-subduedSeparator", 'transition-[block-size] ease-in-out duration-0 [&:not([data-dx-resizing="true"])]:duration-200', classNames),
90
- style: {
91
- ...sizeStyle(size, "vertical", true),
92
- maxBlockSize: "calc(100dvh - env(safe-area-inset-bottom) - env(safe-area-inset-top) - 14rem)"
93
- },
94
- ...resizeAttributes
95
- }, /* @__PURE__ */ React.createElement(ResizeHandle, {
96
- side: "block-start",
97
- iconPosition: "center",
98
- defaultSize: "min-content",
99
- fallbackSize: 0,
100
- minSize: 0,
101
- onSizeChange: setSize
102
- }), children);
103
- } finally {
104
- _effect.f();
105
- }
66
+ const { expanded, size, setSize } = useChatDialogContext(CHAT_DIALOG_CONTENT_NAME);
67
+ useEffect(() => {
68
+ setSize(expanded ? "min-content" : 0);
69
+ }, [
70
+ expanded
71
+ ]);
72
+ return /* @__PURE__ */ React.createElement("div", {
73
+ className: mx("border-t border-b border-subdued-separator", 'transition ease-in-out duration-0 [&:not([data-dx-resizing="true"])]:duration-200', classNames),
74
+ style: {
75
+ ...sizeStyle(size, "vertical", true),
76
+ maxBlockSize: "calc(100dvh - env(safe-area-inset-bottom) - env(safe-area-inset-top) - 14rem)"
77
+ },
78
+ ...resizeAttributes
79
+ }, /* @__PURE__ */ React.createElement(ResizeHandle, {
80
+ side: "block-start",
81
+ iconPosition: "center",
82
+ defaultSize: "min-content",
83
+ fallbackSize: 0,
84
+ minSize: 0,
85
+ onSizeChange: setSize
86
+ }), children);
106
87
  };
107
- ChatDialogContent.displayName = "ChatDialog.Content";
88
+ ChatDialogContent.displayName = CHAT_DIALOG_CONTENT_NAME;
89
+ var CHAT_DIALOG_FOOTER_NAME = "ChatDialog.Footer";
108
90
  var ChatDialogFooter = ({ children, classNames }) => {
109
- var _effect = _useSignals();
110
- try {
111
- return /* @__PURE__ */ React.createElement("div", {
112
- className: mx(classNames)
113
- }, children);
114
- } finally {
115
- _effect.f();
116
- }
91
+ return /* @__PURE__ */ React.createElement("div", {
92
+ className: mx(classNames)
93
+ }, children);
117
94
  };
118
- ChatDialogFooter.displayName = "ChatDialog.Footer";
95
+ ChatDialogFooter.displayName = CHAT_DIALOG_FOOTER_NAME;
119
96
  var ChatDialog = {
120
97
  Root: ChatDialogRoot,
121
98
  Header: ChatDialogHeader,
@@ -133,7 +110,7 @@ var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-chat/src/components/Chat
133
110
  var references = ({ provider, triggerCharacter = "@", debug = false }) => {
134
111
  invariant(triggerCharacter.length === 1, void 0, {
135
112
  F: __dxlog_file,
136
- L: 50,
113
+ L: 56,
137
114
  S: void 0,
138
115
  A: [
139
116
  "triggerCharacter.length === 1",
@@ -186,7 +163,7 @@ var references = ({ provider, triggerCharacter = "@", debug = false }) => {
186
163
  }
187
164
  }, {
188
165
  decorations: (v) => v.decorations,
189
- provide: (plugin) => [
166
+ provide: () => [
190
167
  EditorView.atomicRanges.of((view) => view.plugin(decorationField)?.decorations ?? RangeSet.empty)
191
168
  ]
192
169
  });
@@ -201,7 +178,7 @@ var references = ({ provider, triggerCharacter = "@", debug = false }) => {
201
178
  }
202
179
  }),
203
180
  autocompletion({
204
- tooltipClass: () => "shadow rounded",
181
+ tooltipClass: () => "shadow rounded-sm",
205
182
  activateOnTyping: true,
206
183
  aboveCursor: true,
207
184
  closeOnBlur: !debug,
@@ -234,251 +211,78 @@ var ReferenceWidget = class extends WidgetType {
234
211
  constructor(data) {
235
212
  super(), this.data = data;
236
213
  }
237
- toDOM() {
238
- const span = document.createElement("span");
239
- span.textContent = `@ ${this.data.label}`;
240
- span.className = "cm-reference-pill";
241
- return span;
242
- }
243
- eq(other) {
244
- return other.data.uri === this.data.uri;
245
- }
246
214
  ignoreEvent() {
247
215
  return true;
248
216
  }
249
- };
250
-
251
- // src/components/ChatEditor/ChatEditor.tsx
252
- import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
253
- import React2, { forwardRef, useImperativeHandle } from "react";
254
- import { useThemeContext } from "@dxos/react-ui";
255
- import { createBasicExtensions, createThemeExtensions, useTextEditor } from "@dxos/react-ui-editor";
256
- import { mx as mx2 } from "@dxos/react-ui-theme";
257
- import { isNonNullable } from "@dxos/util";
258
-
259
- // src/components/ChatEditor/autocomplete.ts
260
- import { Prec } from "@codemirror/state";
261
- import { Decoration as Decoration2, EditorView as EditorView2, ViewPlugin as ViewPlugin2, WidgetType as WidgetType2, keymap as keymap2 } from "@codemirror/view";
262
- var autocomplete = ({ fireIfEmpty, onSubmit, onSuggest, onCancel }) => {
263
- const suggest = ViewPlugin2.fromClass(class {
264
- _decorations;
265
- _currentSuggestion = null;
266
- constructor(view) {
267
- this._decorations = this.computeDecorations(view);
268
- }
269
- update(update) {
270
- if (update.docChanged || update.selectionSet) {
271
- this._decorations = this.computeDecorations(update.view);
272
- }
273
- }
274
- computeDecorations(view) {
275
- const text = view.state.doc.toString();
276
- const suggestions = onSuggest?.(text) ?? [];
277
- if (!suggestions.length) {
278
- this._currentSuggestion = null;
279
- return Decoration2.none;
280
- }
281
- this._currentSuggestion = suggestions[0];
282
- const suffix = this._currentSuggestion.slice(text.length);
283
- if (!suffix) {
284
- return Decoration2.none;
285
- }
286
- return Decoration2.set([
287
- Decoration2.widget({
288
- widget: new InlineSuggestionWidget(suffix),
289
- side: 1
290
- }).range(view.state.doc.length)
291
- ]);
292
- }
293
- completeSuggestion(view) {
294
- if (!this._currentSuggestion) {
295
- return false;
296
- }
297
- const text = view.state.doc.toString();
298
- const suffix = this._currentSuggestion.slice(text.length);
299
- if (!suffix) {
300
- return false;
301
- }
302
- view.dispatch({
303
- changes: {
304
- from: view.state.doc.length,
305
- insert: suffix
306
- },
307
- selection: {
308
- anchor: view.state.doc.length + suffix.length
309
- }
310
- });
311
- return true;
312
- }
313
- }, {
314
- decorations: (v) => v._decorations
315
- });
316
- return [
317
- suggest,
318
- EditorView2.theme({
319
- ".cm-inline-suggestion": {
320
- opacity: 0.4
321
- }
322
- }),
323
- Prec.highest(keymap2.of([
324
- {
325
- key: "Tab",
326
- preventDefault: true,
327
- run: (view) => {
328
- const plugin = view.plugin(suggest);
329
- return plugin?.completeSuggestion(view) ?? false;
330
- }
331
- },
332
- {
333
- key: "ArrowRight",
334
- preventDefault: true,
335
- run: (view) => {
336
- if (view.state.selection.main.head !== view.state.doc.length) {
337
- return false;
338
- }
339
- const plugin = view.plugin(suggest);
340
- return plugin?.completeSuggestion(view) ?? false;
341
- }
342
- },
343
- {
344
- key: "Enter",
345
- preventDefault: true,
346
- run: (view) => {
347
- const text = view.state.doc.toString().trim();
348
- if (onSubmit && (fireIfEmpty || text.length > 0)) {
349
- const reset = onSubmit(text);
350
- if (reset) {
351
- view.dispatch({
352
- changes: {
353
- from: 0,
354
- to: view.state.doc.length,
355
- insert: ""
356
- }
357
- });
358
- }
359
- }
360
- return true;
361
- }
362
- },
363
- {
364
- key: "Shift-Enter",
365
- preventDefault: true,
366
- run: (view) => {
367
- view.dispatch({
368
- changes: {
369
- from: view.state.selection.main.head,
370
- insert: "\n"
371
- },
372
- selection: {
373
- anchor: view.state.selection.main.head + 1,
374
- head: view.state.selection.main.head + 1
375
- }
376
- });
377
- return true;
378
- }
379
- },
380
- {
381
- key: "Escape",
382
- preventDefault: true,
383
- run: (view) => {
384
- view.dispatch({
385
- changes: {
386
- from: 0,
387
- to: view.state.doc.length,
388
- insert: ""
389
- }
390
- });
391
- onCancel?.();
392
- return true;
393
- }
394
- }
395
- ]))
396
- ];
397
- };
398
- var InlineSuggestionWidget = class extends WidgetType2 {
399
- suffix;
400
- constructor(suffix) {
401
- super(), this.suffix = suffix;
217
+ eq(other) {
218
+ return this.data.uri === other.data.uri;
402
219
  }
403
220
  toDOM() {
404
221
  const span = document.createElement("span");
405
- span.textContent = this.suffix;
406
- span.className = "cm-inline-suggestion";
222
+ span.textContent = `@${this.data.label}`;
223
+ span.className = "cm-reference-pill";
407
224
  return span;
408
225
  }
409
- eq(other) {
410
- return other.suffix === this.suffix;
411
- }
412
226
  };
413
227
 
414
228
  // src/components/ChatEditor/ChatEditor.tsx
415
- var ChatEditor = /* @__PURE__ */ forwardRef(({ classNames, extensions, references: references2, autoFocus, lineWrapping = false, placeholder, onSubmit, onSuggest, onCancel }, forwardRef2) => {
416
- var _effect = _useSignals2();
417
- try {
418
- const { themeMode } = useThemeContext();
419
- const { parentRef, view } = useTextEditor({
420
- debug: true,
421
- autoFocus,
422
- extensions: [
423
- createThemeExtensions({
424
- themeMode
425
- }),
426
- autocomplete({
427
- onSubmit,
428
- onSuggest,
429
- onCancel
430
- }),
431
- references2 ? references({
432
- provider: references2.provider
433
- }) : [],
434
- createBasicExtensions({
435
- bracketMatching: false,
436
- lineWrapping,
437
- placeholder
438
- }),
439
- extensions
440
- ].filter(isNonNullable)
441
- }, [
442
- themeMode,
443
- extensions,
444
- onSubmit,
445
- onSuggest
446
- ]);
447
- useImperativeHandle(forwardRef2, () => {
448
- return {
449
- focus: () => {
450
- view?.focus();
451
- },
452
- getText: () => view?.state.doc.toString() ?? "",
453
- setText: (text) => {
454
- view?.dispatch({
455
- changes: {
456
- from: 0,
457
- to: view.state.doc.length,
458
- insert: text
459
- },
460
- selection: {
461
- anchor: text.length,
462
- head: text.length
463
- }
464
- });
465
- }
466
- };
467
- }, [
468
- view,
229
+ import React2, { forwardRef, useMemo } from "react";
230
+ import { useThemeContext } from "@dxos/react-ui";
231
+ import { Editor } from "@dxos/react-ui-editor";
232
+ import { createBasicExtensions, createThemeExtensions, submit } from "@dxos/ui-editor";
233
+ import { isTruthy } from "@dxos/util";
234
+ var useChatExtensions = ({ extensions, lineWrapping = false, placeholder, onSubmit }) => {
235
+ const { themeMode } = useThemeContext();
236
+ return useMemo(() => [
237
+ createThemeExtensions({
238
+ themeMode
239
+ }),
240
+ createBasicExtensions({
241
+ bracketMatching: false,
242
+ lineWrapping,
243
+ placeholder
244
+ }),
245
+ submit({
469
246
  onSubmit
470
- ]);
471
- return /* @__PURE__ */ React2.createElement("div", {
472
- ref: parentRef,
473
- className: mx2("is-full", classNames)
474
- });
475
- } finally {
476
- _effect.f();
477
- }
247
+ }),
248
+ extensions
249
+ ].filter(isTruthy), [
250
+ themeMode,
251
+ extensions,
252
+ onSubmit
253
+ ]);
254
+ };
255
+ var ChatEditor = /* @__PURE__ */ forwardRef(({ classNames, autoFocus, extensions: extensionsProp, lineWrapping = false, placeholder, onSubmit }, forwardRef2) => {
256
+ const extensions = useChatExtensions({
257
+ extensions: extensionsProp,
258
+ lineWrapping,
259
+ placeholder,
260
+ onSubmit
261
+ });
262
+ return /* @__PURE__ */ React2.createElement(Editor.Root, {
263
+ ref: forwardRef2
264
+ }, /* @__PURE__ */ React2.createElement(Editor.View, {
265
+ classNames,
266
+ autoFocus,
267
+ extensions
268
+ }));
478
269
  });
270
+
271
+ // src/translations.ts
272
+ var translationKey = "@dxos/react-ui-chat";
273
+ var translations = [
274
+ {
275
+ "en-US": {
276
+ [translationKey]: {}
277
+ }
278
+ }
279
+ ];
479
280
  export {
480
281
  ChatDialog,
481
282
  ChatEditor,
482
- references
283
+ references,
284
+ translationKey,
285
+ translations,
286
+ useChatExtensions
483
287
  };
484
288
  //# sourceMappingURL=index.mjs.map