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

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 (49) hide show
  1. package/dist/lib/browser/index.mjs +165 -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/extensions/markdown/image.ts +11 -0
  43. package/src/hooks/defs.ts +2 -0
  44. package/src/hooks/useEditorView.ts +2 -0
  45. package/src/hooks/useTextEditor.ts +8 -12
  46. package/src/hooks/useTextModel.ts +34 -5
  47. package/src/index.ts +1 -7
  48. package/src/styles/layout.ts +2 -5
  49. 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")
1977
1965
  });
1978
- var fencedCodeBottom = Decoration4.replace({
1979
- widget: new FencedCodeBoundary("cm-codeblock-end cm-codeblock-last")
1966
+ var fencedCodeLineFirst = Decoration4.line({
1967
+ class: mx2("cm-code cm-codeblock-line", "cm-codeblock-first")
1968
+ });
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%",
@@ -3281,6 +3253,14 @@ var image = (options = {}) => {
3281
3253
  provide: (field) => EditorView12.decorations.from(field)
3282
3254
  });
3283
3255
  };
3256
+ var preloaded = /* @__PURE__ */ new Set();
3257
+ var preloadImage = (url) => {
3258
+ if (!preloaded.has(url)) {
3259
+ const img = document.createElement("img");
3260
+ img.src = url;
3261
+ preloaded.add(url);
3262
+ }
3263
+ };
3284
3264
  var buildDecorations2 = (from, to, state) => {
3285
3265
  const decorations = [];
3286
3266
  const cursor = state.selection.main.head;
@@ -3291,6 +3271,7 @@ var buildDecorations2 = (from, to, state) => {
3291
3271
  if (urlNode) {
3292
3272
  const hide2 = state.readOnly || cursor < node.from || cursor > node.to;
3293
3273
  const url = state.sliceDoc(urlNode.from, urlNode.to);
3274
+ preloadImage(url);
3294
3275
  decorations.push(Decoration5.replace({
3295
3276
  block: true,
3296
3277
  widget: new ImageWidget(url)
@@ -3573,7 +3554,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
3573
3554
  };
3574
3555
 
3575
3556
  // packages/ui/react-ui-editor/src/themes/default.ts
3576
- import get3 from "lodash.get";
3557
+ import get4 from "lodash.get";
3577
3558
  var defaultTheme = {
3578
3559
  //
3579
3560
  // Main layout:
@@ -3602,22 +3583,26 @@ var defaultTheme = {
3602
3583
  "&.cm-focused": {
3603
3584
  outline: "none"
3604
3585
  },
3586
+ // NOTE: See https://codemirror.net/docs/guide (DOM Structure).
3605
3587
  ".cm-scroller": {
3606
- // overflow: 'visible',
3607
- fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
3608
- lineHeight: 1.4
3588
+ // TODO(burdon): Reconcile with docs: https://codemirror.net/docs/guide
3589
+ // 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.
3590
+ overflowY: "auto",
3591
+ fontFamily: get4(tokens, "fontFamily.mono", []).join(","),
3592
+ lineHeight: 1.5
3609
3593
  },
3610
3594
  ".cm-content": {
3611
- padding: 0,
3595
+ // TODO(burdon): Is it possible to remove the padding value from CM's default theme?
3596
+ // padding: 'unset',
3612
3597
  // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
3613
3598
  fontSize: "16px"
3614
3599
  },
3615
3600
  "&light .cm-content": {
3616
- color: get3(tokens, "extend.semanticColors.base.fg.light", "black"),
3601
+ color: get4(tokens, "extend.semanticColors.base.fg.light", "black"),
3617
3602
  caretColor: "black"
3618
3603
  },
3619
3604
  "&dark .cm-content": {
3620
- color: get3(tokens, "extend.semanticColors.base.fg.dark", "white"),
3605
+ color: get4(tokens, "extend.semanticColors.base.fg.dark", "white"),
3621
3606
  caretColor: "white"
3622
3607
  },
3623
3608
  //
@@ -3630,10 +3615,10 @@ var defaultTheme = {
3630
3615
  borderLeft: "2px solid white"
3631
3616
  },
3632
3617
  "&light .cm-placeholder": {
3633
- color: get3(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
3618
+ color: get4(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
3634
3619
  },
3635
3620
  "&dark .cm-placeholder": {
3636
- color: get3(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
3621
+ color: get4(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
3637
3622
  },
3638
3623
  //
3639
3624
  // line
@@ -3645,39 +3630,45 @@ var defaultTheme = {
3645
3630
  background: "transparent"
3646
3631
  },
3647
3632
  //
3633
+ // gutter
3634
+ //
3635
+ ".cm-gutterElement": {
3636
+ width: "48px"
3637
+ },
3638
+ //
3648
3639
  // Selection
3649
3640
  //
3650
3641
  "&light .cm-selectionBackground": {
3651
- background: get3(tokens, "extend.colors.primary.100")
3642
+ background: get4(tokens, "extend.colors.primary.100")
3652
3643
  },
3653
3644
  "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
3654
- background: get3(tokens, "extend.colors.primary.200")
3645
+ background: get4(tokens, "extend.colors.primary.200")
3655
3646
  },
3656
3647
  "&dark .cm-selectionBackground": {
3657
- background: get3(tokens, "extend.colors.primary.700")
3648
+ background: get4(tokens, "extend.colors.primary.700")
3658
3649
  },
3659
3650
  "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
3660
- background: get3(tokens, "extend.colors.primary.600")
3651
+ background: get4(tokens, "extend.colors.primary.600")
3661
3652
  },
3662
3653
  //
3663
3654
  // Search
3664
3655
  //
3665
3656
  "&light .cm-searchMatch": {
3666
- backgroundColor: get3(tokens, "extend.colors.yellow.100")
3657
+ backgroundColor: get4(tokens, "extend.colors.yellow.100")
3667
3658
  },
3668
3659
  "&dark .cm-searchMatch": {
3669
- backgroundColor: get3(tokens, "extend.colors.yellow.700")
3660
+ backgroundColor: get4(tokens, "extend.colors.yellow.700")
3670
3661
  },
3671
3662
  //
3672
3663
  // link
3673
3664
  //
3674
3665
  ".cm-link": {
3675
- color: get3(tokens, "extend.colors.primary.500"),
3666
+ color: get4(tokens, "extend.colors.primary.500"),
3676
3667
  textDecorationLine: "underline",
3677
3668
  textDecorationThickness: "1px",
3678
3669
  textUnderlineOffset: "2px",
3679
3670
  borderRadius: ".125rem",
3680
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3671
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3681
3672
  },
3682
3673
  //
3683
3674
  // tooltip
@@ -3699,7 +3690,7 @@ var defaultTheme = {
3699
3690
  display: "none"
3700
3691
  },
3701
3692
  ".cm-completionLabel": {
3702
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3693
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3703
3694
  },
3704
3695
  ".cm-completionMatchedText": {
3705
3696
  textDecoration: "none"
@@ -3708,15 +3699,15 @@ var defaultTheme = {
3708
3699
  // table
3709
3700
  //
3710
3701
  ".cm-table *": {
3711
- fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
3702
+ fontFamily: `${get4(tokens, "fontFamily.mono", []).join(",")} !important`,
3712
3703
  textDecoration: "none !important"
3713
3704
  },
3714
3705
  ".cm-table-head": {
3715
3706
  padding: "2px 16px 2px 0px",
3716
- borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
3707
+ borderBottom: `1px solid ${get4(tokens, "extend.colors.neutral.500")}`,
3717
3708
  fontWeight: 100,
3718
3709
  textAlign: "left",
3719
- color: get3(tokens, "extend.colors.neutral.500")
3710
+ color: get4(tokens, "extend.colors.neutral.500")
3720
3711
  },
3721
3712
  ".cm-table-cell": {
3722
3713
  padding: "2px 16px 2px 0px"
@@ -3763,23 +3754,23 @@ var defaultTheme = {
3763
3754
  * </div
3764
3755
  */
3765
3756
  ".cm-panels": {
3766
- border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
3757
+ border: `1px solid ${get4(tokens, "extend.colors.neutral.200")}`
3767
3758
  },
3768
3759
  ".cm-panel": {
3769
- background: get3(tokens, "extend.colors.neutral.50"),
3770
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3760
+ background: get4(tokens, "extend.colors.neutral.50"),
3761
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3771
3762
  },
3772
3763
  ".cm-button": {
3773
3764
  margin: "4px",
3774
- fontFamily: get3(tokens, "fontFamily.body", []).join(","),
3775
- background: get3(tokens, "extend.colors.neutral.100"),
3765
+ fontFamily: get4(tokens, "fontFamily.body", []).join(","),
3766
+ background: get4(tokens, "extend.colors.neutral.100"),
3776
3767
  backgroundImage: "none",
3777
3768
  border: "none",
3778
3769
  "&:hover": {
3779
- background: get3(tokens, "extend.colors.neutral.200")
3770
+ background: get4(tokens, "extend.colors.neutral.200")
3780
3771
  },
3781
3772
  "&:active": {
3782
- background: get3(tokens, "extend.colors.neutral.300"),
3773
+ background: get4(tokens, "extend.colors.neutral.300"),
3783
3774
  backgroundImage: "none"
3784
3775
  }
3785
3776
  },
@@ -3789,32 +3780,32 @@ var defaultTheme = {
3789
3780
  };
3790
3781
  var textTheme = {
3791
3782
  ".cm-scroller": {
3792
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3783
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3793
3784
  },
3794
3785
  ".cm-placeholder": {
3795
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3786
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3796
3787
  }
3797
3788
  };
3798
3789
  var markdownTheme = {
3799
3790
  ".cm-scroller": {
3800
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3791
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3801
3792
  },
3802
3793
  ".cm-placeholder": {
3803
- fontFamily: get3(tokens, "fontFamily.body", []).join(",")
3794
+ fontFamily: get4(tokens, "fontFamily.body", []).join(",")
3804
3795
  }
3805
3796
  };
3806
3797
  var codeTheme = {
3807
3798
  ".cm-scroller": {
3808
- fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
3799
+ fontFamily: get4(tokens, "fontFamily.mono", []).join(",")
3809
3800
  },
3810
3801
  ".cm-placeholder": {
3811
- fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
3802
+ fontFamily: get4(tokens, "fontFamily.mono", []).join(",")
3812
3803
  }
3813
3804
  };
3814
3805
 
3815
3806
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
3816
3807
  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) => {
3808
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo = EditorView14.scrollIntoView(0), moveToEndOfLine, selection, theme, slots = defaultSlots, extensions = [], scrollPastEnd: _scrollPastEnd, debug }, forwardedRef) => {
3818
3809
  const tabsterDOMAttribute = useFocusableGroup({
3819
3810
  tabBehavior: "limited"
3820
3811
  });
@@ -3825,15 +3816,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3825
3816
  view
3826
3817
  ]);
3827
3818
  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
- }
3819
+ if (autoFocus) {
3837
3820
  view?.focus();
3838
3821
  }
3839
3822
  }, [
@@ -3852,22 +3835,24 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3852
3835
  EditorView14.exceptionSink.of((err) => {
3853
3836
  log3.catch(err, void 0, {
3854
3837
  F: __dxlog_file4,
3855
- L: 113,
3838
+ L: 122,
3856
3839
  S: void 0,
3857
3840
  C: (f, a) => f(...a)
3858
3841
  });
3859
3842
  }),
3860
3843
  // Theme.
3861
- // TODO(burdon): Make configurable.
3844
+ // TODO(burdon): Make base theme configurable.
3862
3845
  EditorView14.baseTheme(defaultTheme),
3863
- EditorView14.theme(theme ?? {}),
3846
+ theme && EditorView14.theme(theme),
3864
3847
  EditorView14.darkTheme.of(themeMode === "dark"),
3865
- EditorView14.editorAttributes.of({
3866
- class: slots.editor?.className ?? ""
3848
+ slots.editor?.className && EditorView14.editorAttributes.of({
3849
+ class: slots.editor.className
3867
3850
  }),
3868
- EditorView14.contentAttributes.of({
3869
- class: slots.content?.className ?? ""
3851
+ slots.content?.className && EditorView14.contentAttributes.of({
3852
+ class: slots.content.className
3870
3853
  }),
3854
+ // NOTE: Assumes default line height.
3855
+ _scrollPastEnd && scrollPastEnd(),
3871
3856
  // Focus.
3872
3857
  EditorView14.updateListener.of((update2) => {
3873
3858
  update2.transactions.forEach((transaction) => {
@@ -3886,26 +3871,33 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3886
3871
  ...extensions
3887
3872
  ].filter(isNotFalsy4)
3888
3873
  });
3889
- const newView = new EditorView14({
3874
+ const view2 = new EditorView14({
3890
3875
  state,
3891
3876
  parent: rootRef.current,
3892
3877
  scrollTo,
3893
3878
  // NOTE: Uncomment to debug/monitor all transactions.
3894
3879
  // https://codemirror.net/docs/ref/#view.EditorView.dispatch
3895
- dispatchTransactions: (trs, view2) => {
3880
+ dispatchTransactions: (trs, view3) => {
3896
3881
  if (debug) {
3897
3882
  logChanges(trs);
3898
3883
  }
3899
- view2.update(trs);
3884
+ view3.update(trs);
3900
3885
  }
3901
3886
  });
3902
- view?.destroy();
3903
- setView(newView);
3887
+ setView(view2);
3888
+ if (moveToEndOfLine) {
3889
+ const { to } = view2.state.doc.lineAt(0);
3890
+ view2?.dispatch({
3891
+ selection: {
3892
+ anchor: to
3893
+ }
3894
+ });
3895
+ }
3904
3896
  if (state.facet(editorMode).noTabster) {
3905
3897
  rootRef.current.removeAttribute("data-tabster");
3906
3898
  }
3907
3899
  return () => {
3908
- newView?.destroy();
3900
+ view2?.destroy();
3909
3901
  setView(null);
3910
3902
  };
3911
3903
  }, [
@@ -3989,7 +3981,7 @@ var defaultSlots = {
3989
3981
  className: focusRing
3990
3982
  },
3991
3983
  editor: {
3992
- className: "min-bs-full"
3984
+ className: "bs-full"
3993
3985
  }
3994
3986
  };
3995
3987
  var defaultTextSlots = {
@@ -4002,7 +3994,7 @@ var defaultMarkdownSlots = {
4002
3994
  // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
4003
3995
  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
3996
  import { createContext } from "@radix-ui/react-context";
4005
- import React2 from "react";
3997
+ import React2, { useRef as useRef2, useState as useState3 } from "react";
4006
3998
  import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
4007
3999
  import { getSize } from "@dxos/react-ui-theme";
4008
4000
  var tooltipProps = {
@@ -4060,9 +4052,29 @@ var MarkdownHeading = () => {
4060
4052
  const header = blockType && /heading(\d)/.exec(blockType);
4061
4053
  const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
4062
4054
  const HeadingIcon = HeadingIcons[value ?? "0"];
4063
- return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Select.Root, {
4055
+ const suppressNextTooltip = useRef2(false);
4056
+ const [tooltipOpen, setTooltipOpen] = useState3(false);
4057
+ const [selectOpen, setSelectOpen] = useState3(false);
4058
+ return /* @__PURE__ */ React2.createElement(Tooltip.Root, {
4059
+ open: tooltipOpen,
4060
+ onOpenChange: (nextOpen) => {
4061
+ if (nextOpen && suppressNextTooltip.current) {
4062
+ suppressNextTooltip.current = false;
4063
+ return setTooltipOpen(false);
4064
+ } else {
4065
+ return setTooltipOpen(nextOpen);
4066
+ }
4067
+ }
4068
+ }, /* @__PURE__ */ React2.createElement(Select.Root, {
4064
4069
  disabled: value === null,
4065
4070
  value: value ?? "0",
4071
+ open: selectOpen,
4072
+ onOpenChange: (nextOpen) => {
4073
+ if (!nextOpen) {
4074
+ suppressNextTooltip.current = true;
4075
+ }
4076
+ return setSelectOpen(nextOpen);
4077
+ },
4066
4078
  onValueChange: (value2) => onAction?.({
4067
4079
  type: "heading",
4068
4080
  data: parseInt(value2)
@@ -4406,10 +4418,10 @@ var useActionHandler = (view) => {
4406
4418
  };
4407
4419
 
4408
4420
  // packages/ui/react-ui-editor/src/hooks/useEditorView.ts
4409
- import { useRef as useRef2, useState as useState3 } from "react";
4421
+ import { useRef as useRef3, useState as useState4 } from "react";
4410
4422
  var useEditorView = (id) => {
4411
- const editorRef = useRef2(null);
4412
- const [prev, setPrev] = useState3([
4423
+ const editorRef = useRef3(null);
4424
+ const [prev, setPrev] = useState4([
4413
4425
  null,
4414
4426
  ""
4415
4427
  ]);
@@ -4428,14 +4440,14 @@ var useEditorView = (id) => {
4428
4440
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4429
4441
  import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4430
4442
  import { EditorView as EditorView15 } from "@codemirror/view";
4431
- import { useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
4443
+ import { useEffect as useEffect3, useRef as useRef4, useState as useState5 } from "react";
4432
4444
  import { log as log5 } from "@dxos/log";
4433
4445
  import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
4434
4446
  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);
4447
+ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}, deps) => {
4448
+ const onUpdate = useRef4();
4449
+ const [view, setView] = useState5();
4450
+ const parentRef = useRef4(null);
4439
4451
  useEffect3(() => {
4440
4452
  let view2;
4441
4453
  if (parentRef.current) {
@@ -4447,7 +4459,7 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
4447
4459
  EditorView15.exceptionSink.of((err) => {
4448
4460
  log5.catch(err, void 0, {
4449
4461
  F: __dxlog_file6,
4450
- L: 60,
4462
+ L: 57,
4451
4463
  S: void 0,
4452
4464
  C: (f, a) => f(...a)
4453
4465
  });
@@ -4476,10 +4488,7 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
4476
4488
  return () => {
4477
4489
  view2?.destroy();
4478
4490
  };
4479
- }, [
4480
- parentRef,
4481
- extensions
4482
- ]);
4491
+ }, deps);
4483
4492
  useEffect3(() => {
4484
4493
  if (view) {
4485
4494
  if (!selection && !view.state.selection.main.anchor) {
@@ -4535,16 +4544,35 @@ var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
4535
4544
  };
4536
4545
 
4537
4546
  // 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";
4547
+ import get5 from "lodash.get";
4548
+ import { useState as useState6, useMemo as useMemo3 } from "react";
4540
4549
  import { generateName } from "@dxos/display-name";
4541
4550
  import { getRawDoc } from "@dxos/echo-schema";
4542
4551
  import { invariant as invariant3 } from "@dxos/invariant";
4543
4552
  import { isAutomergeObject } from "@dxos/react-client/echo";
4544
4553
  var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
4554
+ var useTextExtensions = ({ id, text, space, identity }) => {
4555
+ const extensions = [
4556
+ automerge(text)
4557
+ ];
4558
+ if (space && identity) {
4559
+ const awarenessProvider2 = new SpaceAwarenessProvider({
4560
+ space,
4561
+ channel: `awareness.${id}`,
4562
+ peerId: identity.identityKey.toHex(),
4563
+ info: {
4564
+ displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
4565
+ color: cursorColor.color,
4566
+ lightColor: cursorColor.light
4567
+ }
4568
+ });
4569
+ extensions.push(awareness(awarenessProvider2));
4570
+ }
4571
+ return extensions;
4572
+ };
4545
4573
  var useTextModel = (props) => useMemo3(() => createModel(props), Object.values(props));
4546
4574
  var useInMemoryTextModel = ({ id, defaultContent }) => {
4547
- const [content, setContent] = useState5(defaultContent ?? "");
4575
+ const [content, setContent] = useState6(defaultContent ?? "");
4548
4576
  return {
4549
4577
  id,
4550
4578
  content,
@@ -4558,7 +4586,7 @@ var createModel = ({ space, identity, text }) => {
4558
4586
  }
4559
4587
  invariant3(isAutomergeObject(text), void 0, {
4560
4588
  F: __dxlog_file7,
4561
- L: 54,
4589
+ L: 83,
4562
4590
  S: void 0,
4563
4591
  A: [
4564
4592
  "isAutomergeObject(text)",
@@ -4592,7 +4620,7 @@ var createModel = ({ space, identity, text }) => {
4592
4620
  const model = {
4593
4621
  id: obj.id,
4594
4622
  content: doc,
4595
- text: () => get4(doc.handle.docSync(), doc.path),
4623
+ text: () => get5(doc.handle.docSync(), doc.path),
4596
4624
  extension: extensions,
4597
4625
  peer: identity ? {
4598
4626
  id: identity.identityKey.toHex(),
@@ -4646,7 +4674,6 @@ export {
4646
4674
  defaultTheme,
4647
4675
  editorFillLayoutEditor,
4648
4676
  editorFillLayoutRoot,
4649
- editorHalfViewportOverscrollContent,
4650
4677
  editorMode,
4651
4678
  editorWithToolbarLayout,
4652
4679
  focusComment,
@@ -4695,6 +4722,7 @@ export {
4695
4722
  useFormattingState,
4696
4723
  useInMemoryTextModel,
4697
4724
  useTextEditor,
4725
+ useTextExtensions,
4698
4726
  useTextModel,
4699
4727
  useToolbarContext
4700
4728
  };