@dxos/react-ui-editor 0.4.5 → 0.4.6-main.20d1ec4

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 (48) hide show
  1. package/dist/lib/browser/index.mjs +156 -137
  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/extensions/markdown/decorate.d.ts.map +1 -1
  18. package/dist/types/src/hooks/defs.d.ts +1 -0
  19. package/dist/types/src/hooks/defs.d.ts.map +1 -1
  20. package/dist/types/src/hooks/useEditorView.d.ts +1 -0
  21. package/dist/types/src/hooks/useEditorView.d.ts.map +1 -1
  22. package/dist/types/src/hooks/useTextEditor.d.ts +3 -3
  23. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  24. package/dist/types/src/hooks/useTextModel.d.ts +12 -4
  25. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  26. package/dist/types/src/index.d.ts +1 -1
  27. package/dist/types/src/index.d.ts.map +1 -1
  28. package/dist/types/src/styles/layout.d.ts +2 -3
  29. package/dist/types/src/styles/layout.d.ts.map +1 -1
  30. package/dist/types/src/themes/default.d.ts.map +1 -1
  31. package/package.json +26 -25
  32. package/src/components/TextEditor/MarkdownEditor.stories.tsx +1 -1
  33. package/src/components/TextEditor/TextEditor.tsx +36 -18
  34. package/src/components/TextEditor/automerge.stories.tsx +15 -16
  35. package/src/components/TextEditor/hooks.stories.tsx +11 -8
  36. package/src/components/Toolbar/Toolbar.stories.tsx +9 -6
  37. package/src/components/Toolbar/Toolbar.tsx +22 -2
  38. package/src/extensions/automerge/automerge.ts +10 -15
  39. package/src/extensions/automerge/cursor.ts +2 -3
  40. package/src/extensions/automerge/defs.ts +15 -2
  41. package/src/extensions/markdown/decorate.ts +13 -49
  42. package/src/hooks/defs.ts +2 -0
  43. package/src/hooks/useEditorView.ts +2 -0
  44. package/src/hooks/useTextEditor.ts +8 -12
  45. package/src/hooks/useTextModel.ts +34 -5
  46. package/src/index.ts +1 -7
  47. package/src/styles/layout.ts +2 -5
  48. 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";
@@ -1900,18 +1900,6 @@ import { syntaxTree } from "@codemirror/language";
1900
1900
  import { RangeSetBuilder } from "@codemirror/state";
1901
1901
  import { EditorView as EditorView10, Decoration as Decoration4, WidgetType as WidgetType2, ViewPlugin as ViewPlugin3 } from "@codemirror/view";
1902
1902
  import { mx as mx2 } from "@dxos/react-ui-theme";
1903
- var FencedCodeBoundary = class extends WidgetType2 {
1904
- constructor(_className) {
1905
- super();
1906
- this._className = _className;
1907
- }
1908
- toDOM() {
1909
- const el = document.createElement("span");
1910
- el.innerHTML = " ";
1911
- el.className = mx2("cm-code cm-codeblock", this._className);
1912
- return el;
1913
- }
1914
- };
1915
1903
  var HorizontalRuleWidget = class extends WidgetType2 {
1916
1904
  toDOM() {
1917
1905
  const el = document.createElement("span");
@@ -1972,11 +1960,14 @@ var CheckboxWidget = class extends WidgetType2 {
1972
1960
  }
1973
1961
  };
1974
1962
  var hide = Decoration4.replace({});
1975
- var fencedCodeTop = Decoration4.replace({
1976
- widget: new FencedCodeBoundary("cm-codeblock-end cm-codeblock-first")
1963
+ var fencedCodeLine = Decoration4.line({
1964
+ class: mx2("cm-code cm-codeblock-line")
1965
+ });
1966
+ var fencedCodeLineFirst = Decoration4.line({
1967
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
1977
1968
  });
1978
- var fencedCodeBottom = Decoration4.replace({
1979
- widget: new FencedCodeBoundary("cm-codeblock-end cm-codeblock-last")
1969
+ var fencedCodeLineLast = Decoration4.line({
1970
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-last")
1980
1971
  });
1981
1972
  var horizontalRule = Decoration4.replace({
1982
1973
  widget: new HorizontalRuleWidget()
@@ -2017,12 +2008,9 @@ var buildDecorations = (view, options) => {
2017
2008
  }
2018
2009
  const first = block.from <= node.from;
2019
2010
  const last = block.to >= node.to;
2011
+ builder.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
2020
2012
  if (!editing && (first || last)) {
2021
- builder.add(block.from, block.to, first ? fencedCodeTop : fencedCodeBottom);
2022
- } else {
2023
- builder.add(block.from, block.from, Decoration4.line({
2024
- class: mx2("cm-code cm-codeblock-line", first && "cm-codeblock-first", last && "cm-codeblock-last")
2025
- }));
2013
+ builder.add(block.from, block.to, hide);
2026
2014
  }
2027
2015
  }
2028
2016
  return false;
@@ -2113,16 +2101,12 @@ var formattingStyles = EditorView10.baseTheme({
2113
2101
  }
2114
2102
  },
2115
2103
  "& .cm-codeblock-first": {
2116
- "&::after": {
2117
- borderTopLeftRadius: ".5rem",
2118
- borderTopRightRadius: ".5rem"
2119
- }
2104
+ borderTopLeftRadius: ".5rem",
2105
+ borderTopRightRadius: ".5rem"
2120
2106
  },
2121
2107
  "& .cm-codeblock-last": {
2122
- "&::after": {
2123
- borderBottomLeftRadius: ".5rem",
2124
- borderBottomRightRadius: ".5rem"
2125
- }
2108
+ borderBottomLeftRadius: ".5rem",
2109
+ borderBottomRightRadius: ".5rem"
2126
2110
  },
2127
2111
  "&light .cm-codeblock-line, &light .cm-activeLine.cm-codeblock-line": {
2128
2112
  background: getToken("extend.semanticColors.input.light"),
@@ -2132,18 +2116,6 @@ var formattingStyles = EditorView10.baseTheme({
2132
2116
  background: getToken("extend.semanticColors.input.dark"),
2133
2117
  mixBlendMode: "lighten"
2134
2118
  },
2135
- "&light .cm-codeblock-first, &light .cm-codeblock-last": {
2136
- mixBlendMode: "darken",
2137
- "&::after": {
2138
- background: getToken("extend.semanticColors.input.light")
2139
- }
2140
- },
2141
- "&dark .cm-codeblock-first, &dark .cm-codeblock-last": {
2142
- mixBlendMode: "lighten",
2143
- "&::after": {
2144
- background: getToken("extend.semanticColors.input.dark")
2145
- }
2146
- },
2147
2119
  "& .cm-hr": {
2148
2120
  display: "inline-block",
2149
2121
  width: "100%",
@@ -3573,7 +3545,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
3573
3545
  };
3574
3546
 
3575
3547
  // packages/ui/react-ui-editor/src/themes/default.ts
3576
- import get3 from "lodash.get";
3548
+ import get4 from "lodash.get";
3577
3549
  var defaultTheme = {
3578
3550
  //
3579
3551
  // Main layout:
@@ -3602,22 +3574,26 @@ var defaultTheme = {
3602
3574
  "&.cm-focused": {
3603
3575
  outline: "none"
3604
3576
  },
3577
+ // NOTE: See https://codemirror.net/docs/guide (DOM Structure).
3605
3578
  ".cm-scroller": {
3606
- // overflow: 'visible',
3607
- fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
3608
- lineHeight: 1.4
3579
+ // TODO(burdon): Reconcile with docs: https://codemirror.net/docs/guide
3580
+ // 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.
3581
+ overflowY: "auto",
3582
+ fontFamily: get4(tokens, "fontFamily.mono", []).join(","),
3583
+ lineHeight: 1.5
3609
3584
  },
3610
3585
  ".cm-content": {
3611
- padding: 0,
3586
+ // TODO(burdon): Is it possible to remove the padding value from CM's default theme?
3587
+ // padding: 'unset',
3612
3588
  // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
3613
3589
  fontSize: "16px"
3614
3590
  },
3615
3591
  "&light .cm-content": {
3616
- color: get3(tokens, "extend.semanticColors.base.fg.light", "black"),
3592
+ color: get4(tokens, "extend.semanticColors.base.fg.light", "black"),
3617
3593
  caretColor: "black"
3618
3594
  },
3619
3595
  "&dark .cm-content": {
3620
- color: get3(tokens, "extend.semanticColors.base.fg.dark", "white"),
3596
+ color: get4(tokens, "extend.semanticColors.base.fg.dark", "white"),
3621
3597
  caretColor: "white"
3622
3598
  },
3623
3599
  //
@@ -3630,10 +3606,10 @@ var defaultTheme = {
3630
3606
  borderLeft: "2px solid white"
3631
3607
  },
3632
3608
  "&light .cm-placeholder": {
3633
- color: get3(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
3609
+ color: get4(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
3634
3610
  },
3635
3611
  "&dark .cm-placeholder": {
3636
- color: get3(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
3612
+ color: get4(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
3637
3613
  },
3638
3614
  //
3639
3615
  // line
@@ -3645,39 +3621,45 @@ var defaultTheme = {
3645
3621
  background: "transparent"
3646
3622
  },
3647
3623
  //
3624
+ // gutter
3625
+ //
3626
+ ".cm-gutterElement": {
3627
+ width: "48px"
3628
+ },
3629
+ //
3648
3630
  // Selection
3649
3631
  //
3650
3632
  "&light .cm-selectionBackground": {
3651
- background: get3(tokens, "extend.colors.primary.100")
3633
+ background: get4(tokens, "extend.colors.primary.100")
3652
3634
  },
3653
3635
  "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
3654
- background: get3(tokens, "extend.colors.primary.200")
3636
+ background: get4(tokens, "extend.colors.primary.200")
3655
3637
  },
3656
3638
  "&dark .cm-selectionBackground": {
3657
- background: get3(tokens, "extend.colors.primary.700")
3639
+ background: get4(tokens, "extend.colors.primary.700")
3658
3640
  },
3659
3641
  "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
3660
- background: get3(tokens, "extend.colors.primary.600")
3642
+ background: get4(tokens, "extend.colors.primary.600")
3661
3643
  },
3662
3644
  //
3663
3645
  // Search
3664
3646
  //
3665
3647
  "&light .cm-searchMatch": {
3666
- backgroundColor: get3(tokens, "extend.colors.yellow.100")
3648
+ backgroundColor: get4(tokens, "extend.colors.yellow.100")
3667
3649
  },
3668
3650
  "&dark .cm-searchMatch": {
3669
- backgroundColor: get3(tokens, "extend.colors.yellow.700")
3651
+ backgroundColor: get4(tokens, "extend.colors.yellow.700")
3670
3652
  },
3671
3653
  //
3672
3654
  // link
3673
3655
  //
3674
3656
  ".cm-link": {
3675
- color: get3(tokens, "extend.colors.primary.500"),
3657
+ color: get4(tokens, "extend.colors.primary.500"),
3676
3658
  textDecorationLine: "underline",
3677
3659
  textDecorationThickness: "1px",
3678
3660
  textUnderlineOffset: "2px",
3679
3661
  borderRadius: ".125rem",
3680
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3662
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3681
3663
  },
3682
3664
  //
3683
3665
  // tooltip
@@ -3699,7 +3681,7 @@ var defaultTheme = {
3699
3681
  display: "none"
3700
3682
  },
3701
3683
  ".cm-completionLabel": {
3702
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3684
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3703
3685
  },
3704
3686
  ".cm-completionMatchedText": {
3705
3687
  textDecoration: "none"
@@ -3708,15 +3690,15 @@ var defaultTheme = {
3708
3690
  // table
3709
3691
  //
3710
3692
  ".cm-table *": {
3711
- fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
3693
+ fontFamily: `${get4(tokens, "fontFamily.mono", []).join(",")} !important`,
3712
3694
  textDecoration: "none !important"
3713
3695
  },
3714
3696
  ".cm-table-head": {
3715
3697
  padding: "2px 16px 2px 0px",
3716
- borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
3698
+ borderBottom: `1px solid ${get4(tokens, "extend.colors.neutral.500")}`,
3717
3699
  fontWeight: 100,
3718
3700
  textAlign: "left",
3719
- color: get3(tokens, "extend.colors.neutral.500")
3701
+ color: get4(tokens, "extend.colors.neutral.500")
3720
3702
  },
3721
3703
  ".cm-table-cell": {
3722
3704
  padding: "2px 16px 2px 0px"
@@ -3763,23 +3745,23 @@ var defaultTheme = {
3763
3745
  * </div
3764
3746
  */
3765
3747
  ".cm-panels": {
3766
- border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
3748
+ border: `1px solid ${get4(tokens, "extend.colors.neutral.200")}`
3767
3749
  },
3768
3750
  ".cm-panel": {
3769
- background: get3(tokens, "extend.colors.neutral.50"),
3770
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3751
+ background: get4(tokens, "extend.colors.neutral.50"),
3752
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3771
3753
  },
3772
3754
  ".cm-button": {
3773
3755
  margin: "4px",
3774
- fontFamily: get3(tokens, "fontFamily.body", []).join(","),
3775
- background: get3(tokens, "extend.colors.neutral.100"),
3756
+ fontFamily: get4(tokens, "fontFamily.body", []).join(","),
3757
+ background: get4(tokens, "extend.colors.neutral.100"),
3776
3758
  backgroundImage: "none",
3777
3759
  border: "none",
3778
3760
  "&:hover": {
3779
- background: get3(tokens, "extend.colors.neutral.200")
3761
+ background: get4(tokens, "extend.colors.neutral.200")
3780
3762
  },
3781
3763
  "&:active": {
3782
- background: get3(tokens, "extend.colors.neutral.300"),
3764
+ background: get4(tokens, "extend.colors.neutral.300"),
3783
3765
  backgroundImage: "none"
3784
3766
  }
3785
3767
  },
@@ -3789,32 +3771,32 @@ var defaultTheme = {
3789
3771
  };
3790
3772
  var textTheme = {
3791
3773
  ".cm-scroller": {
3792
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3774
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3793
3775
  },
3794
3776
  ".cm-placeholder": {
3795
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3777
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3796
3778
  }
3797
3779
  };
3798
3780
  var markdownTheme = {
3799
3781
  ".cm-scroller": {
3800
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3782
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3801
3783
  },
3802
3784
  ".cm-placeholder": {
3803
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3785
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3804
3786
  }
3805
3787
  };
3806
3788
  var codeTheme = {
3807
3789
  ".cm-scroller": {
3808
- fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
3790
+ fontFamily: get4(tokens, "fontFamily.mono", []).join(",")
3809
3791
  },
3810
3792
  ".cm-placeholder": {
3811
- fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
3793
+ fontFamily: get4(tokens, "fontFamily.mono", []).join(",")
3812
3794
  }
3813
3795
  };
3814
3796
 
3815
3797
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
3816
3798
  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) => {
3799
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo = EditorView14.scrollIntoView(0), moveToEndOfLine, selection, theme, slots = defaultSlots, extensions = [], scrollPastEnd: _scrollPastEnd, debug }, forwardedRef) => {
3818
3800
  const tabsterDOMAttribute = useFocusableGroup({
3819
3801
  tabBehavior: "limited"
3820
3802
  });
@@ -3825,15 +3807,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3825
3807
  view
3826
3808
  ]);
3827
3809
  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
- }
3810
+ if (autoFocus) {
3837
3811
  view?.focus();
3838
3812
  }
3839
3813
  }, [
@@ -3852,22 +3826,24 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3852
3826
  EditorView14.exceptionSink.of((err) => {
3853
3827
  log3.catch(err, void 0, {
3854
3828
  F: __dxlog_file4,
3855
- L: 113,
3829
+ L: 122,
3856
3830
  S: void 0,
3857
3831
  C: (f, a) => f(...a)
3858
3832
  });
3859
3833
  }),
3860
3834
  // Theme.
3861
- // TODO(burdon): Make configurable.
3835
+ // TODO(burdon): Make base theme configurable.
3862
3836
  EditorView14.baseTheme(defaultTheme),
3863
- EditorView14.theme(theme ?? {}),
3837
+ theme && EditorView14.theme(theme),
3864
3838
  EditorView14.darkTheme.of(themeMode === "dark"),
3865
- EditorView14.editorAttributes.of({
3866
- class: slots.editor?.className ?? ""
3839
+ slots.editor?.className && EditorView14.editorAttributes.of({
3840
+ class: slots.editor.className
3867
3841
  }),
3868
- EditorView14.contentAttributes.of({
3869
- class: slots.content?.className ?? ""
3842
+ slots.content?.className && EditorView14.contentAttributes.of({
3843
+ class: slots.content.className
3870
3844
  }),
3845
+ // NOTE: Assumes default line height.
3846
+ _scrollPastEnd && scrollPastEnd(),
3871
3847
  // Focus.
3872
3848
  EditorView14.updateListener.of((update2) => {
3873
3849
  update2.transactions.forEach((transaction) => {
@@ -3886,26 +3862,33 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3886
3862
  ...extensions
3887
3863
  ].filter(isNotFalsy4)
3888
3864
  });
3889
- const newView = new EditorView14({
3865
+ const view2 = new EditorView14({
3890
3866
  state,
3891
3867
  parent: rootRef.current,
3892
3868
  scrollTo,
3893
3869
  // NOTE: Uncomment to debug/monitor all transactions.
3894
3870
  // https://codemirror.net/docs/ref/#view.EditorView.dispatch
3895
- dispatchTransactions: (trs, view2) => {
3871
+ dispatchTransactions: (trs, view3) => {
3896
3872
  if (debug) {
3897
3873
  logChanges(trs);
3898
3874
  }
3899
- view2.update(trs);
3875
+ view3.update(trs);
3900
3876
  }
3901
3877
  });
3902
- view?.destroy();
3903
- setView(newView);
3878
+ setView(view2);
3879
+ if (moveToEndOfLine) {
3880
+ const { to } = view2.state.doc.lineAt(0);
3881
+ view2?.dispatch({
3882
+ selection: {
3883
+ anchor: to
3884
+ }
3885
+ });
3886
+ }
3904
3887
  if (state.facet(editorMode).noTabster) {
3905
3888
  rootRef.current.removeAttribute("data-tabster");
3906
3889
  }
3907
3890
  return () => {
3908
- newView?.destroy();
3891
+ view2?.destroy();
3909
3892
  setView(null);
3910
3893
  };
3911
3894
  }, [
@@ -3989,7 +3972,7 @@ var defaultSlots = {
3989
3972
  className: focusRing
3990
3973
  },
3991
3974
  editor: {
3992
- className: "min-bs-full"
3975
+ className: "bs-full"
3993
3976
  }
3994
3977
  };
3995
3978
  var defaultTextSlots = {
@@ -4002,7 +3985,7 @@ var defaultMarkdownSlots = {
4002
3985
  // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
4003
3986
  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
3987
  import { createContext } from "@radix-ui/react-context";
4005
- import React2 from "react";
3988
+ import React2, { useRef as useRef2, useState as useState3 } from "react";
4006
3989
  import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
4007
3990
  import { getSize } from "@dxos/react-ui-theme";
4008
3991
  var tooltipProps = {
@@ -4060,9 +4043,29 @@ var MarkdownHeading = () => {
4060
4043
  const header = blockType && /heading(\d)/.exec(blockType);
4061
4044
  const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
4062
4045
  const HeadingIcon = HeadingIcons[value ?? "0"];
4063
- return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Select.Root, {
4046
+ const suppressNextTooltip = useRef2(false);
4047
+ const [tooltipOpen, setTooltipOpen] = useState3(false);
4048
+ const [selectOpen, setSelectOpen] = useState3(false);
4049
+ return /* @__PURE__ */ React2.createElement(Tooltip.Root, {
4050
+ open: tooltipOpen,
4051
+ onOpenChange: (nextOpen) => {
4052
+ if (nextOpen && suppressNextTooltip.current) {
4053
+ suppressNextTooltip.current = false;
4054
+ return setTooltipOpen(false);
4055
+ } else {
4056
+ return setTooltipOpen(nextOpen);
4057
+ }
4058
+ }
4059
+ }, /* @__PURE__ */ React2.createElement(Select.Root, {
4064
4060
  disabled: value === null,
4065
4061
  value: value ?? "0",
4062
+ open: selectOpen,
4063
+ onOpenChange: (nextOpen) => {
4064
+ if (!nextOpen) {
4065
+ suppressNextTooltip.current = true;
4066
+ }
4067
+ return setSelectOpen(nextOpen);
4068
+ },
4066
4069
  onValueChange: (value2) => onAction?.({
4067
4070
  type: "heading",
4068
4071
  data: parseInt(value2)
@@ -4406,10 +4409,10 @@ var useActionHandler = (view) => {
4406
4409
  };
4407
4410
 
4408
4411
  // packages/ui/react-ui-editor/src/hooks/useEditorView.ts
4409
- import { useRef as useRef2, useState as useState3 } from "react";
4412
+ import { useRef as useRef3, useState as useState4 } from "react";
4410
4413
  var useEditorView = (id) => {
4411
- const editorRef = useRef2(null);
4412
- const [prev, setPrev] = useState3([
4414
+ const editorRef = useRef3(null);
4415
+ const [prev, setPrev] = useState4([
4413
4416
  null,
4414
4417
  ""
4415
4418
  ]);
@@ -4428,14 +4431,14 @@ var useEditorView = (id) => {
4428
4431
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4429
4432
  import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4430
4433
  import { EditorView as EditorView15 } from "@codemirror/view";
4431
- import { useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
4434
+ import { useEffect as useEffect3, useRef as useRef4, useState as useState5 } from "react";
4432
4435
  import { log as log5 } from "@dxos/log";
4433
4436
  import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
4434
4437
  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);
4438
+ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}, deps) => {
4439
+ const onUpdate = useRef4();
4440
+ const [view, setView] = useState5();
4441
+ const parentRef = useRef4(null);
4439
4442
  useEffect3(() => {
4440
4443
  let view2;
4441
4444
  if (parentRef.current) {
@@ -4447,7 +4450,7 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
4447
4450
  EditorView15.exceptionSink.of((err) => {
4448
4451
  log5.catch(err, void 0, {
4449
4452
  F: __dxlog_file6,
4450
- L: 60,
4453
+ L: 57,
4451
4454
  S: void 0,
4452
4455
  C: (f, a) => f(...a)
4453
4456
  });
@@ -4476,10 +4479,7 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
4476
4479
  return () => {
4477
4480
  view2?.destroy();
4478
4481
  };
4479
- }, [
4480
- parentRef,
4481
- extensions
4482
- ]);
4482
+ }, deps);
4483
4483
  useEffect3(() => {
4484
4484
  if (view) {
4485
4485
  if (!selection && !view.state.selection.main.anchor) {
@@ -4535,16 +4535,35 @@ var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
4535
4535
  };
4536
4536
 
4537
4537
  // 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";
4538
+ import get5 from "lodash.get";
4539
+ import { useState as useState6, useMemo as useMemo3 } from "react";
4540
4540
  import { generateName } from "@dxos/display-name";
4541
4541
  import { getRawDoc } from "@dxos/echo-schema";
4542
4542
  import { invariant as invariant3 } from "@dxos/invariant";
4543
4543
  import { isAutomergeObject } from "@dxos/react-client/echo";
4544
4544
  var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
4545
+ var useTextExtensions = ({ id, text, space, identity }) => {
4546
+ const extensions = [
4547
+ automerge(text)
4548
+ ];
4549
+ if (space && identity) {
4550
+ const awarenessProvider2 = new SpaceAwarenessProvider({
4551
+ space,
4552
+ channel: `awareness.${id}`,
4553
+ peerId: identity.identityKey.toHex(),
4554
+ info: {
4555
+ displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
4556
+ color: cursorColor.color,
4557
+ lightColor: cursorColor.light
4558
+ }
4559
+ });
4560
+ extensions.push(awareness(awarenessProvider2));
4561
+ }
4562
+ return extensions;
4563
+ };
4545
4564
  var useTextModel = (props) => useMemo3(() => createModel(props), Object.values(props));
4546
4565
  var useInMemoryTextModel = ({ id, defaultContent }) => {
4547
- const [content, setContent] = useState5(defaultContent ?? "");
4566
+ const [content, setContent] = useState6(defaultContent ?? "");
4548
4567
  return {
4549
4568
  id,
4550
4569
  content,
@@ -4558,7 +4577,7 @@ var createModel = ({ space, identity, text }) => {
4558
4577
  }
4559
4578
  invariant3(isAutomergeObject(text), void 0, {
4560
4579
  F: __dxlog_file7,
4561
- L: 54,
4580
+ L: 83,
4562
4581
  S: void 0,
4563
4582
  A: [
4564
4583
  "isAutomergeObject(text)",
@@ -4592,7 +4611,7 @@ var createModel = ({ space, identity, text }) => {
4592
4611
  const model = {
4593
4612
  id: obj.id,
4594
4613
  content: doc,
4595
- text: () => get4(doc.handle.docSync(), doc.path),
4614
+ text: () => get5(doc.handle.docSync(), doc.path),
4596
4615
  extension: extensions,
4597
4616
  peer: identity ? {
4598
4617
  id: identity.identityKey.toHex(),
@@ -4646,7 +4665,6 @@ export {
4646
4665
  defaultTheme,
4647
4666
  editorFillLayoutEditor,
4648
4667
  editorFillLayoutRoot,
4649
- editorHalfViewportOverscrollContent,
4650
4668
  editorMode,
4651
4669
  editorWithToolbarLayout,
4652
4670
  focusComment,
@@ -4695,6 +4713,7 @@ export {
4695
4713
  useFormattingState,
4696
4714
  useInMemoryTextModel,
4697
4715
  useTextEditor,
4716
+ useTextExtensions,
4698
4717
  useTextModel,
4699
4718
  useToolbarContext
4700
4719
  };