@dxos/react-ui-chat 0.8.4-main.b97322e → 0.8.4-main.bc674ce

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