@dxos/react-ui-editor 0.4.6-main.aeca3cc → 0.4.6-main.e47f68d

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 (46) hide show
  1. package/dist/lib/browser/index.mjs +143 -96
  2. package/dist/lib/browser/index.mjs.map +3 -3
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/TextEditor/TextEditor.d.ts +2 -0
  5. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/automerge.stories.d.ts +3 -5
  7. package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -1
  8. package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -1
  9. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  10. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  11. package/dist/types/src/extensions/automerge/automerge.d.ts +2 -7
  12. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  13. package/dist/types/src/extensions/automerge/cursor.d.ts +2 -3
  14. package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
  15. package/dist/types/src/extensions/automerge/defs.d.ts +9 -2
  16. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  17. package/dist/types/src/hooks/defs.d.ts +1 -0
  18. package/dist/types/src/hooks/defs.d.ts.map +1 -1
  19. package/dist/types/src/hooks/useEditorView.d.ts +1 -0
  20. package/dist/types/src/hooks/useEditorView.d.ts.map +1 -1
  21. package/dist/types/src/hooks/useTextEditor.d.ts +3 -3
  22. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  23. package/dist/types/src/hooks/useTextModel.d.ts +12 -4
  24. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  25. package/dist/types/src/index.d.ts +1 -1
  26. package/dist/types/src/index.d.ts.map +1 -1
  27. package/dist/types/src/styles/layout.d.ts +2 -3
  28. package/dist/types/src/styles/layout.d.ts.map +1 -1
  29. package/dist/types/src/themes/default.d.ts.map +1 -1
  30. package/package.json +26 -25
  31. package/src/components/TextEditor/MarkdownEditor.stories.tsx +1 -1
  32. package/src/components/TextEditor/TextEditor.tsx +36 -18
  33. package/src/components/TextEditor/automerge.stories.tsx +15 -16
  34. package/src/components/TextEditor/hooks.stories.tsx +11 -8
  35. package/src/components/Toolbar/Toolbar.stories.tsx +9 -6
  36. package/src/components/Toolbar/Toolbar.tsx +22 -2
  37. package/src/extensions/automerge/automerge.ts +10 -15
  38. package/src/extensions/automerge/cursor.ts +2 -3
  39. package/src/extensions/automerge/defs.ts +15 -2
  40. package/src/hooks/defs.ts +2 -0
  41. package/src/hooks/useEditorView.ts +2 -0
  42. package/src/hooks/useTextEditor.ts +8 -12
  43. package/src/hooks/useTextModel.ts +34 -5
  44. package/src/index.ts +1 -7
  45. package/src/styles/layout.ts +2 -5
  46. package/src/themes/default.ts +14 -3
@@ -32,7 +32,7 @@ import { tags as tags2 } from "@lezer/highlight";
32
32
 
33
33
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
34
34
  import { EditorState as EditorState2 } from "@codemirror/state";
35
- import { EditorView as EditorView14 } from "@codemirror/view";
35
+ import { EditorView as EditorView14, scrollPastEnd } from "@codemirror/view";
36
36
  import { useFocusableGroup } from "@fluentui/react-tabster";
37
37
  import defaultsDeep2 from "lodash.defaultsdeep";
38
38
  import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2, useMemo as useMemo2 } from "react";
@@ -189,7 +189,7 @@ import get from "lodash.get";
189
189
  import { next as A } from "@dxos/automerge/automerge";
190
190
  import { log } from "@dxos/log";
191
191
  var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts";
192
- var cursorConverter = (handle, path) => ({
192
+ var cursorConverter = ({ handle, path }) => ({
193
193
  // TODO(burdon): Handle assoc to associate with a previous character.
194
194
  toCursor: (pos) => {
195
195
  const doc = handle.docSync();
@@ -205,7 +205,7 @@ var cursorConverter = (handle, path) => ({
205
205
  } catch (err) {
206
206
  log.catch(err, void 0, {
207
207
  F: __dxlog_file,
208
- L: 31,
208
+ L: 30,
209
209
  S: void 0,
210
210
  C: (f, a) => f(...a)
211
211
  });
@@ -233,7 +233,7 @@ var cursorConverter = (handle, path) => ({
233
233
  } catch (err) {
234
234
  log.catch(err, void 0, {
235
235
  F: __dxlog_file,
236
- L: 59,
236
+ L: 58,
237
237
  S: void 0,
238
238
  C: (f, a) => f(...a)
239
239
  });
@@ -244,6 +244,7 @@ var cursorConverter = (handle, path) => ({
244
244
 
245
245
  // packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
246
246
  import { Annotation, StateEffect } from "@codemirror/state";
247
+ import get2 from "lodash.get";
247
248
  var getPath = (state, field) => state.field(field).path;
248
249
  var getLastHeads = (state, field) => state.field(field).lastHeads;
249
250
  var updateHeadsEffect = StateEffect.define({});
@@ -441,16 +442,16 @@ var Syncer = class {
441
442
  };
442
443
 
443
444
  // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
444
- var automerge = ({ handle, path }) => {
445
+ var automerge = (accessor) => {
445
446
  const syncState = StateField2.define({
446
447
  create: () => ({
447
- path: path.slice(),
448
- lastHeads: A4.getHeads(handle.docSync()),
448
+ path: accessor.path.slice(),
449
+ lastHeads: A4.getHeads(accessor.handle.docSync()),
449
450
  unreconciledTransactions: []
450
451
  }),
451
452
  update: (value, tr) => {
452
453
  const result = {
453
- path: path.slice(),
454
+ path: accessor.path.slice(),
454
455
  lastHeads: value.lastHeads,
455
456
  unreconciledTransactions: value.unreconciledTransactions.slice()
456
457
  };
@@ -471,18 +472,18 @@ var automerge = ({ handle, path }) => {
471
472
  return result;
472
473
  }
473
474
  });
474
- const syncer = new Syncer(handle, syncState);
475
+ const syncer = new Syncer(accessor.handle, syncState);
475
476
  return [
476
- Cursor.converter.of(cursorConverter(handle, path)),
477
+ Cursor.converter.of(cursorConverter(accessor)),
477
478
  syncState,
478
479
  // Reconcile external updates.
479
480
  ViewPlugin.fromClass(class {
480
481
  constructor(_view) {
481
482
  this._view = _view;
482
- handle.addListener("change", this._handleChange.bind(this));
483
+ accessor.handle.addListener("change", this._handleChange.bind(this));
483
484
  }
484
485
  destroy() {
485
- handle.removeListener("change", this._handleChange.bind(this));
486
+ accessor.handle.removeListener("change", this._handleChange.bind(this));
486
487
  }
487
488
  _handleChange() {
488
489
  syncer.reconcile(this._view, false);
@@ -1133,16 +1134,15 @@ var inlineUrl = mx(code, "px-1");
1133
1134
  var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
1134
1135
 
1135
1136
  // packages/ui/react-ui-editor/src/styles/tokens.ts
1136
- import get2 from "lodash.get";
1137
+ import get3 from "lodash.get";
1137
1138
  import { tailwindConfig } from "@dxos/react-ui-theme";
1138
1139
  var tokens = tailwindConfig({}).theme;
1139
- var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
1140
+ var getToken = (path, defaultValue = void 0) => get3(tokens, path, defaultValue);
1140
1141
 
1141
1142
  // packages/ui/react-ui-editor/src/styles/layout.ts
1142
1143
  var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
1143
- var editorFillLayoutRoot = "bs-full overflow-hidden grid";
1144
- var editorFillLayoutEditor = "bs-full overflow-hidden [&>.cm-scroller]:bs-full [&>.cm-scroller]:overflow-y-auto";
1145
- var editorHalfViewportOverscrollContent = "after:block after:min-bs-[50dvh] after:pointer-events-none";
1144
+ var editorFillLayoutRoot = "bs-full relative";
1145
+ var editorFillLayoutEditor = "!absolute inset-0";
1146
1146
 
1147
1147
  // packages/ui/react-ui-editor/src/util.ts
1148
1148
  import { log as log2 } from "@dxos/log";
@@ -3573,7 +3573,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
3573
3573
  };
3574
3574
 
3575
3575
  // packages/ui/react-ui-editor/src/themes/default.ts
3576
- import get3 from "lodash.get";
3576
+ import get4 from "lodash.get";
3577
3577
  var defaultTheme = {
3578
3578
  //
3579
3579
  // Main layout:
@@ -3602,22 +3602,26 @@ var defaultTheme = {
3602
3602
  "&.cm-focused": {
3603
3603
  outline: "none"
3604
3604
  },
3605
+ // NOTE: See https://codemirror.net/docs/guide (DOM Structure).
3605
3606
  ".cm-scroller": {
3606
- // overflow: 'visible',
3607
- fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
3608
- lineHeight: 1.4
3607
+ // TODO(burdon): Reconcile with docs: https://codemirror.net/docs/guide
3608
+ // Inside of that is the scroller element. If the editor has its own scrollbar, this one should be styled with overflow: auto. But it doesn't have to—the editor also supports growing to accomodate its content, or growing up to a certain max-height and then scrolling.
3609
+ overflowY: "auto",
3610
+ fontFamily: get4(tokens, "fontFamily.mono", []).join(","),
3611
+ lineHeight: 1.5
3609
3612
  },
3610
3613
  ".cm-content": {
3611
- padding: 0,
3614
+ // TODO(burdon): Is it possible to remove the padding value from CM's default theme?
3615
+ // padding: 'unset',
3612
3616
  // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
3613
3617
  fontSize: "16px"
3614
3618
  },
3615
3619
  "&light .cm-content": {
3616
- color: get3(tokens, "extend.semanticColors.base.fg.light", "black"),
3620
+ color: get4(tokens, "extend.semanticColors.base.fg.light", "black"),
3617
3621
  caretColor: "black"
3618
3622
  },
3619
3623
  "&dark .cm-content": {
3620
- color: get3(tokens, "extend.semanticColors.base.fg.dark", "white"),
3624
+ color: get4(tokens, "extend.semanticColors.base.fg.dark", "white"),
3621
3625
  caretColor: "white"
3622
3626
  },
3623
3627
  //
@@ -3630,10 +3634,10 @@ var defaultTheme = {
3630
3634
  borderLeft: "2px solid white"
3631
3635
  },
3632
3636
  "&light .cm-placeholder": {
3633
- color: get3(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
3637
+ color: get4(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
3634
3638
  },
3635
3639
  "&dark .cm-placeholder": {
3636
- color: get3(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
3640
+ color: get4(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
3637
3641
  },
3638
3642
  //
3639
3643
  // line
@@ -3645,39 +3649,45 @@ var defaultTheme = {
3645
3649
  background: "transparent"
3646
3650
  },
3647
3651
  //
3652
+ // gutter
3653
+ //
3654
+ ".cm-gutterElement": {
3655
+ width: "48px"
3656
+ },
3657
+ //
3648
3658
  // Selection
3649
3659
  //
3650
3660
  "&light .cm-selectionBackground": {
3651
- background: get3(tokens, "extend.colors.primary.100")
3661
+ background: get4(tokens, "extend.colors.primary.100")
3652
3662
  },
3653
3663
  "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
3654
- background: get3(tokens, "extend.colors.primary.200")
3664
+ background: get4(tokens, "extend.colors.primary.200")
3655
3665
  },
3656
3666
  "&dark .cm-selectionBackground": {
3657
- background: get3(tokens, "extend.colors.primary.700")
3667
+ background: get4(tokens, "extend.colors.primary.700")
3658
3668
  },
3659
3669
  "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
3660
- background: get3(tokens, "extend.colors.primary.600")
3670
+ background: get4(tokens, "extend.colors.primary.600")
3661
3671
  },
3662
3672
  //
3663
3673
  // Search
3664
3674
  //
3665
3675
  "&light .cm-searchMatch": {
3666
- backgroundColor: get3(tokens, "extend.colors.yellow.100")
3676
+ backgroundColor: get4(tokens, "extend.colors.yellow.100")
3667
3677
  },
3668
3678
  "&dark .cm-searchMatch": {
3669
- backgroundColor: get3(tokens, "extend.colors.yellow.700")
3679
+ backgroundColor: get4(tokens, "extend.colors.yellow.700")
3670
3680
  },
3671
3681
  //
3672
3682
  // link
3673
3683
  //
3674
3684
  ".cm-link": {
3675
- color: get3(tokens, "extend.colors.primary.500"),
3685
+ color: get4(tokens, "extend.colors.primary.500"),
3676
3686
  textDecorationLine: "underline",
3677
3687
  textDecorationThickness: "1px",
3678
3688
  textUnderlineOffset: "2px",
3679
3689
  borderRadius: ".125rem",
3680
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3690
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3681
3691
  },
3682
3692
  //
3683
3693
  // tooltip
@@ -3699,7 +3709,7 @@ var defaultTheme = {
3699
3709
  display: "none"
3700
3710
  },
3701
3711
  ".cm-completionLabel": {
3702
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3712
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3703
3713
  },
3704
3714
  ".cm-completionMatchedText": {
3705
3715
  textDecoration: "none"
@@ -3708,15 +3718,15 @@ var defaultTheme = {
3708
3718
  // table
3709
3719
  //
3710
3720
  ".cm-table *": {
3711
- fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
3721
+ fontFamily: `${get4(tokens, "fontFamily.mono", []).join(",")} !important`,
3712
3722
  textDecoration: "none !important"
3713
3723
  },
3714
3724
  ".cm-table-head": {
3715
3725
  padding: "2px 16px 2px 0px",
3716
- borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
3726
+ borderBottom: `1px solid ${get4(tokens, "extend.colors.neutral.500")}`,
3717
3727
  fontWeight: 100,
3718
3728
  textAlign: "left",
3719
- color: get3(tokens, "extend.colors.neutral.500")
3729
+ color: get4(tokens, "extend.colors.neutral.500")
3720
3730
  },
3721
3731
  ".cm-table-cell": {
3722
3732
  padding: "2px 16px 2px 0px"
@@ -3763,23 +3773,23 @@ var defaultTheme = {
3763
3773
  * </div
3764
3774
  */
3765
3775
  ".cm-panels": {
3766
- border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
3776
+ border: `1px solid ${get4(tokens, "extend.colors.neutral.200")}`
3767
3777
  },
3768
3778
  ".cm-panel": {
3769
- background: get3(tokens, "extend.colors.neutral.50"),
3770
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3779
+ background: get4(tokens, "extend.colors.neutral.50"),
3780
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3771
3781
  },
3772
3782
  ".cm-button": {
3773
3783
  margin: "4px",
3774
- fontFamily: get3(tokens, "fontFamily.body", []).join(","),
3775
- background: get3(tokens, "extend.colors.neutral.100"),
3784
+ fontFamily: get4(tokens, "fontFamily.body", []).join(","),
3785
+ background: get4(tokens, "extend.colors.neutral.100"),
3776
3786
  backgroundImage: "none",
3777
3787
  border: "none",
3778
3788
  "&:hover": {
3779
- background: get3(tokens, "extend.colors.neutral.200")
3789
+ background: get4(tokens, "extend.colors.neutral.200")
3780
3790
  },
3781
3791
  "&:active": {
3782
- background: get3(tokens, "extend.colors.neutral.300"),
3792
+ background: get4(tokens, "extend.colors.neutral.300"),
3783
3793
  backgroundImage: "none"
3784
3794
  }
3785
3795
  },
@@ -3789,32 +3799,32 @@ var defaultTheme = {
3789
3799
  };
3790
3800
  var textTheme = {
3791
3801
  ".cm-scroller": {
3792
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3802
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3793
3803
  },
3794
3804
  ".cm-placeholder": {
3795
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3805
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3796
3806
  }
3797
3807
  };
3798
3808
  var markdownTheme = {
3799
3809
  ".cm-scroller": {
3800
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3810
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3801
3811
  },
3802
3812
  ".cm-placeholder": {
3803
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3813
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3804
3814
  }
3805
3815
  };
3806
3816
  var codeTheme = {
3807
3817
  ".cm-scroller": {
3808
- fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
3818
+ fontFamily: get4(tokens, "fontFamily.mono", []).join(",")
3809
3819
  },
3810
3820
  ".cm-placeholder": {
3811
- fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
3821
+ fontFamily: get4(tokens, "fontFamily.mono", []).join(",")
3812
3822
  }
3813
3823
  };
3814
3824
 
3815
3825
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
3816
3826
  var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
3817
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
3827
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo = EditorView14.scrollIntoView(0), moveToEndOfLine, selection, theme, slots = defaultSlots, extensions = [], scrollPastEnd: _scrollPastEnd, debug }, forwardedRef) => {
3818
3828
  const tabsterDOMAttribute = useFocusableGroup({
3819
3829
  tabBehavior: "limited"
3820
3830
  });
@@ -3825,15 +3835,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3825
3835
  view
3826
3836
  ]);
3827
3837
  useEffect2(() => {
3828
- if (autoFocus && !view?.hasFocus) {
3829
- if (view?.state.selection.main?.from === 0) {
3830
- const { to } = view.state.doc.lineAt(0);
3831
- view?.dispatch({
3832
- selection: {
3833
- anchor: to
3834
- }
3835
- });
3836
- }
3838
+ if (autoFocus) {
3837
3839
  view?.focus();
3838
3840
  }
3839
3841
  }, [
@@ -3852,22 +3854,24 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3852
3854
  EditorView14.exceptionSink.of((err) => {
3853
3855
  log3.catch(err, void 0, {
3854
3856
  F: __dxlog_file4,
3855
- L: 113,
3857
+ L: 122,
3856
3858
  S: void 0,
3857
3859
  C: (f, a) => f(...a)
3858
3860
  });
3859
3861
  }),
3860
3862
  // Theme.
3861
- // TODO(burdon): Make configurable.
3863
+ // TODO(burdon): Make base theme configurable.
3862
3864
  EditorView14.baseTheme(defaultTheme),
3863
- EditorView14.theme(theme ?? {}),
3865
+ theme && EditorView14.theme(theme),
3864
3866
  EditorView14.darkTheme.of(themeMode === "dark"),
3865
- EditorView14.editorAttributes.of({
3866
- class: slots.editor?.className ?? ""
3867
+ slots.editor?.className && EditorView14.editorAttributes.of({
3868
+ class: slots.editor.className
3867
3869
  }),
3868
- EditorView14.contentAttributes.of({
3869
- class: slots.content?.className ?? ""
3870
+ slots.content?.className && EditorView14.contentAttributes.of({
3871
+ class: slots.content.className
3870
3872
  }),
3873
+ // NOTE: Assumes default line height.
3874
+ _scrollPastEnd && scrollPastEnd(),
3871
3875
  // Focus.
3872
3876
  EditorView14.updateListener.of((update2) => {
3873
3877
  update2.transactions.forEach((transaction) => {
@@ -3886,26 +3890,33 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3886
3890
  ...extensions
3887
3891
  ].filter(isNotFalsy4)
3888
3892
  });
3889
- const newView = new EditorView14({
3893
+ const view2 = new EditorView14({
3890
3894
  state,
3891
3895
  parent: rootRef.current,
3892
3896
  scrollTo,
3893
3897
  // NOTE: Uncomment to debug/monitor all transactions.
3894
3898
  // https://codemirror.net/docs/ref/#view.EditorView.dispatch
3895
- dispatchTransactions: (trs, view2) => {
3899
+ dispatchTransactions: (trs, view3) => {
3896
3900
  if (debug) {
3897
3901
  logChanges(trs);
3898
3902
  }
3899
- view2.update(trs);
3903
+ view3.update(trs);
3900
3904
  }
3901
3905
  });
3902
- view?.destroy();
3903
- setView(newView);
3906
+ setView(view2);
3907
+ if (moveToEndOfLine) {
3908
+ const { to } = view2.state.doc.lineAt(0);
3909
+ view2?.dispatch({
3910
+ selection: {
3911
+ anchor: to
3912
+ }
3913
+ });
3914
+ }
3904
3915
  if (state.facet(editorMode).noTabster) {
3905
3916
  rootRef.current.removeAttribute("data-tabster");
3906
3917
  }
3907
3918
  return () => {
3908
- newView?.destroy();
3919
+ view2?.destroy();
3909
3920
  setView(null);
3910
3921
  };
3911
3922
  }, [
@@ -3989,7 +4000,7 @@ var defaultSlots = {
3989
4000
  className: focusRing
3990
4001
  },
3991
4002
  editor: {
3992
- className: "min-bs-full"
4003
+ className: "bs-full"
3993
4004
  }
3994
4005
  };
3995
4006
  var defaultTextSlots = {
@@ -4002,7 +4013,7 @@ var defaultMarkdownSlots = {
4002
4013
  // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
4003
4014
  import { ChatText, Code, CodeBlock, Link, ListBullets, ListChecks, ListNumbers, Paragraph, TextStrikethrough, Table as Table2, TextB, TextHOne, TextHTwo, TextHThree, TextHFour, TextHFive, TextHSix, TextItalic, Quotes } from "@phosphor-icons/react";
4004
4015
  import { createContext } from "@radix-ui/react-context";
4005
- import React2 from "react";
4016
+ import React2, { useRef as useRef2, useState as useState3 } from "react";
4006
4017
  import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
4007
4018
  import { getSize } from "@dxos/react-ui-theme";
4008
4019
  var tooltipProps = {
@@ -4060,9 +4071,29 @@ var MarkdownHeading = () => {
4060
4071
  const header = blockType && /heading(\d)/.exec(blockType);
4061
4072
  const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
4062
4073
  const HeadingIcon = HeadingIcons[value ?? "0"];
4063
- return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Select.Root, {
4074
+ const suppressNextTooltip = useRef2(false);
4075
+ const [tooltipOpen, setTooltipOpen] = useState3(false);
4076
+ const [selectOpen, setSelectOpen] = useState3(false);
4077
+ return /* @__PURE__ */ React2.createElement(Tooltip.Root, {
4078
+ open: tooltipOpen,
4079
+ onOpenChange: (nextOpen) => {
4080
+ if (nextOpen && suppressNextTooltip.current) {
4081
+ suppressNextTooltip.current = false;
4082
+ return setTooltipOpen(false);
4083
+ } else {
4084
+ return setTooltipOpen(nextOpen);
4085
+ }
4086
+ }
4087
+ }, /* @__PURE__ */ React2.createElement(Select.Root, {
4064
4088
  disabled: value === null,
4065
4089
  value: value ?? "0",
4090
+ open: selectOpen,
4091
+ onOpenChange: (nextOpen) => {
4092
+ if (!nextOpen) {
4093
+ suppressNextTooltip.current = true;
4094
+ }
4095
+ return setSelectOpen(nextOpen);
4096
+ },
4066
4097
  onValueChange: (value2) => onAction?.({
4067
4098
  type: "heading",
4068
4099
  data: parseInt(value2)
@@ -4406,10 +4437,10 @@ var useActionHandler = (view) => {
4406
4437
  };
4407
4438
 
4408
4439
  // packages/ui/react-ui-editor/src/hooks/useEditorView.ts
4409
- import { useRef as useRef2, useState as useState3 } from "react";
4440
+ import { useRef as useRef3, useState as useState4 } from "react";
4410
4441
  var useEditorView = (id) => {
4411
- const editorRef = useRef2(null);
4412
- const [prev, setPrev] = useState3([
4442
+ const editorRef = useRef3(null);
4443
+ const [prev, setPrev] = useState4([
4413
4444
  null,
4414
4445
  ""
4415
4446
  ]);
@@ -4428,14 +4459,14 @@ var useEditorView = (id) => {
4428
4459
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4429
4460
  import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4430
4461
  import { EditorView as EditorView15 } from "@codemirror/view";
4431
- import { useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
4462
+ import { useEffect as useEffect3, useRef as useRef4, useState as useState5 } from "react";
4432
4463
  import { log as log5 } from "@dxos/log";
4433
4464
  import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
4434
4465
  var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
4435
- var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}) => {
4436
- const onUpdate = useRef3();
4437
- const [view, setView] = useState4();
4438
- const parentRef = useRef3(null);
4466
+ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}, deps) => {
4467
+ const onUpdate = useRef4();
4468
+ const [view, setView] = useState5();
4469
+ const parentRef = useRef4(null);
4439
4470
  useEffect3(() => {
4440
4471
  let view2;
4441
4472
  if (parentRef.current) {
@@ -4447,7 +4478,7 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
4447
4478
  EditorView15.exceptionSink.of((err) => {
4448
4479
  log5.catch(err, void 0, {
4449
4480
  F: __dxlog_file6,
4450
- L: 60,
4481
+ L: 57,
4451
4482
  S: void 0,
4452
4483
  C: (f, a) => f(...a)
4453
4484
  });
@@ -4476,10 +4507,7 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
4476
4507
  return () => {
4477
4508
  view2?.destroy();
4478
4509
  };
4479
- }, [
4480
- parentRef,
4481
- extensions
4482
- ]);
4510
+ }, deps);
4483
4511
  useEffect3(() => {
4484
4512
  if (view) {
4485
4513
  if (!selection && !view.state.selection.main.anchor) {
@@ -4535,16 +4563,35 @@ var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
4535
4563
  };
4536
4564
 
4537
4565
  // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
4538
- import get4 from "lodash.get";
4539
- import { useState as useState5, useMemo as useMemo3 } from "react";
4566
+ import get5 from "lodash.get";
4567
+ import { useState as useState6, useMemo as useMemo3 } from "react";
4540
4568
  import { generateName } from "@dxos/display-name";
4541
4569
  import { getRawDoc } from "@dxos/echo-schema";
4542
4570
  import { invariant as invariant3 } from "@dxos/invariant";
4543
4571
  import { isAutomergeObject } from "@dxos/react-client/echo";
4544
4572
  var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
4573
+ var useTextExtensions = ({ id, text, space, identity }) => {
4574
+ const extensions = [
4575
+ automerge(text)
4576
+ ];
4577
+ if (space && identity) {
4578
+ const awarenessProvider2 = new SpaceAwarenessProvider({
4579
+ space,
4580
+ channel: `awareness.${id}`,
4581
+ peerId: identity.identityKey.toHex(),
4582
+ info: {
4583
+ displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
4584
+ color: cursorColor.color,
4585
+ lightColor: cursorColor.light
4586
+ }
4587
+ });
4588
+ extensions.push(awareness(awarenessProvider2));
4589
+ }
4590
+ return extensions;
4591
+ };
4545
4592
  var useTextModel = (props) => useMemo3(() => createModel(props), Object.values(props));
4546
4593
  var useInMemoryTextModel = ({ id, defaultContent }) => {
4547
- const [content, setContent] = useState5(defaultContent ?? "");
4594
+ const [content, setContent] = useState6(defaultContent ?? "");
4548
4595
  return {
4549
4596
  id,
4550
4597
  content,
@@ -4558,7 +4605,7 @@ var createModel = ({ space, identity, text }) => {
4558
4605
  }
4559
4606
  invariant3(isAutomergeObject(text), void 0, {
4560
4607
  F: __dxlog_file7,
4561
- L: 54,
4608
+ L: 83,
4562
4609
  S: void 0,
4563
4610
  A: [
4564
4611
  "isAutomergeObject(text)",
@@ -4592,7 +4639,7 @@ var createModel = ({ space, identity, text }) => {
4592
4639
  const model = {
4593
4640
  id: obj.id,
4594
4641
  content: doc,
4595
- text: () => get4(doc.handle.docSync(), doc.path),
4642
+ text: () => get5(doc.handle.docSync(), doc.path),
4596
4643
  extension: extensions,
4597
4644
  peer: identity ? {
4598
4645
  id: identity.identityKey.toHex(),
@@ -4646,7 +4693,6 @@ export {
4646
4693
  defaultTheme,
4647
4694
  editorFillLayoutEditor,
4648
4695
  editorFillLayoutRoot,
4649
- editorHalfViewportOverscrollContent,
4650
4696
  editorMode,
4651
4697
  editorWithToolbarLayout,
4652
4698
  focusComment,
@@ -4695,6 +4741,7 @@ export {
4695
4741
  useFormattingState,
4696
4742
  useInMemoryTextModel,
4697
4743
  useTextEditor,
4744
+ useTextExtensions,
4698
4745
  useTextModel,
4699
4746
  useToolbarContext
4700
4747
  };