@dxos/react-ui-editor 0.4.5 → 0.4.6-main.3500f01

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.
@@ -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";
@@ -1140,9 +1140,8 @@ var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue)
1140
1140
 
1141
1141
  // packages/ui/react-ui-editor/src/styles/layout.ts
1142
1142
  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";
1143
+ var editorFillLayoutRoot = "bs-full relative";
1144
+ var editorFillLayoutEditor = "!absolute inset-0";
1146
1145
 
1147
1146
  // packages/ui/react-ui-editor/src/util.ts
1148
1147
  import { log as log2 } from "@dxos/log";
@@ -3602,13 +3601,17 @@ var defaultTheme = {
3602
3601
  "&.cm-focused": {
3603
3602
  outline: "none"
3604
3603
  },
3604
+ // NOTE: See https://codemirror.net/docs/guide (DOM Structure).
3605
3605
  ".cm-scroller": {
3606
- // overflow: 'visible',
3606
+ // TODO(burdon): Reconcile with docs: https://codemirror.net/docs/guide
3607
+ // 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.
3608
+ overflowY: "auto",
3607
3609
  fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
3608
- lineHeight: 1.4
3610
+ lineHeight: 1.5
3609
3611
  },
3610
3612
  ".cm-content": {
3611
- padding: 0,
3613
+ // TODO(burdon): Is it possible to remove the padding value from CM's default theme?
3614
+ // padding: 'unset',
3612
3615
  // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
3613
3616
  fontSize: "16px"
3614
3617
  },
@@ -3814,7 +3817,7 @@ var codeTheme = {
3814
3817
 
3815
3818
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
3816
3819
  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) => {
3820
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo = EditorView14.scrollIntoView(0), moveToEndOfLine, selection, theme, slots = defaultSlots, extensions = [], scrollPastEnd: _scrollPastEnd, debug }, forwardedRef) => {
3818
3821
  const tabsterDOMAttribute = useFocusableGroup({
3819
3822
  tabBehavior: "limited"
3820
3823
  });
@@ -3825,15 +3828,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3825
3828
  view
3826
3829
  ]);
3827
3830
  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
- }
3831
+ if (autoFocus) {
3837
3832
  view?.focus();
3838
3833
  }
3839
3834
  }, [
@@ -3852,22 +3847,24 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3852
3847
  EditorView14.exceptionSink.of((err) => {
3853
3848
  log3.catch(err, void 0, {
3854
3849
  F: __dxlog_file4,
3855
- L: 113,
3850
+ L: 122,
3856
3851
  S: void 0,
3857
3852
  C: (f, a) => f(...a)
3858
3853
  });
3859
3854
  }),
3860
3855
  // Theme.
3861
- // TODO(burdon): Make configurable.
3856
+ // TODO(burdon): Make base theme configurable.
3862
3857
  EditorView14.baseTheme(defaultTheme),
3863
- EditorView14.theme(theme ?? {}),
3858
+ theme && EditorView14.theme(theme),
3864
3859
  EditorView14.darkTheme.of(themeMode === "dark"),
3865
- EditorView14.editorAttributes.of({
3866
- class: slots.editor?.className ?? ""
3860
+ slots.editor?.className && EditorView14.editorAttributes.of({
3861
+ class: slots.editor.className
3867
3862
  }),
3868
- EditorView14.contentAttributes.of({
3869
- class: slots.content?.className ?? ""
3863
+ slots.content?.className && EditorView14.contentAttributes.of({
3864
+ class: slots.content.className
3870
3865
  }),
3866
+ // NOTE: Assumes default line height.
3867
+ _scrollPastEnd && scrollPastEnd(),
3871
3868
  // Focus.
3872
3869
  EditorView14.updateListener.of((update2) => {
3873
3870
  update2.transactions.forEach((transaction) => {
@@ -3886,26 +3883,33 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
3886
3883
  ...extensions
3887
3884
  ].filter(isNotFalsy4)
3888
3885
  });
3889
- const newView = new EditorView14({
3886
+ const view2 = new EditorView14({
3890
3887
  state,
3891
3888
  parent: rootRef.current,
3892
3889
  scrollTo,
3893
3890
  // NOTE: Uncomment to debug/monitor all transactions.
3894
3891
  // https://codemirror.net/docs/ref/#view.EditorView.dispatch
3895
- dispatchTransactions: (trs, view2) => {
3892
+ dispatchTransactions: (trs, view3) => {
3896
3893
  if (debug) {
3897
3894
  logChanges(trs);
3898
3895
  }
3899
- view2.update(trs);
3896
+ view3.update(trs);
3900
3897
  }
3901
3898
  });
3902
- view?.destroy();
3903
- setView(newView);
3899
+ setView(view2);
3900
+ if (moveToEndOfLine) {
3901
+ const { to } = view2.state.doc.lineAt(0);
3902
+ view2?.dispatch({
3903
+ selection: {
3904
+ anchor: to
3905
+ }
3906
+ });
3907
+ }
3904
3908
  if (state.facet(editorMode).noTabster) {
3905
3909
  rootRef.current.removeAttribute("data-tabster");
3906
3910
  }
3907
3911
  return () => {
3908
- newView?.destroy();
3912
+ view2?.destroy();
3909
3913
  setView(null);
3910
3914
  };
3911
3915
  }, [
@@ -3989,7 +3993,7 @@ var defaultSlots = {
3989
3993
  className: focusRing
3990
3994
  },
3991
3995
  editor: {
3992
- className: "min-bs-full"
3996
+ className: "bs-full"
3993
3997
  }
3994
3998
  };
3995
3999
  var defaultTextSlots = {
@@ -4002,7 +4006,7 @@ var defaultMarkdownSlots = {
4002
4006
  // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
4003
4007
  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
4008
  import { createContext } from "@radix-ui/react-context";
4005
- import React2 from "react";
4009
+ import React2, { useRef as useRef2, useState as useState3 } from "react";
4006
4010
  import { DensityProvider, ElevationProvider, Select, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
4007
4011
  import { getSize } from "@dxos/react-ui-theme";
4008
4012
  var tooltipProps = {
@@ -4060,9 +4064,29 @@ var MarkdownHeading = () => {
4060
4064
  const header = blockType && /heading(\d)/.exec(blockType);
4061
4065
  const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
4062
4066
  const HeadingIcon = HeadingIcons[value ?? "0"];
4063
- return /* @__PURE__ */ React2.createElement(Tooltip.Root, null, /* @__PURE__ */ React2.createElement(Select.Root, {
4067
+ const suppressNextTooltip = useRef2(false);
4068
+ const [tooltipOpen, setTooltipOpen] = useState3(false);
4069
+ const [selectOpen, setSelectOpen] = useState3(false);
4070
+ return /* @__PURE__ */ React2.createElement(Tooltip.Root, {
4071
+ open: tooltipOpen,
4072
+ onOpenChange: (nextOpen) => {
4073
+ if (nextOpen && suppressNextTooltip.current) {
4074
+ suppressNextTooltip.current = false;
4075
+ return setTooltipOpen(false);
4076
+ } else {
4077
+ return setTooltipOpen(nextOpen);
4078
+ }
4079
+ }
4080
+ }, /* @__PURE__ */ React2.createElement(Select.Root, {
4064
4081
  disabled: value === null,
4065
4082
  value: value ?? "0",
4083
+ open: selectOpen,
4084
+ onOpenChange: (nextOpen) => {
4085
+ if (!nextOpen) {
4086
+ suppressNextTooltip.current = true;
4087
+ }
4088
+ return setSelectOpen(nextOpen);
4089
+ },
4066
4090
  onValueChange: (value2) => onAction?.({
4067
4091
  type: "heading",
4068
4092
  data: parseInt(value2)
@@ -4406,10 +4430,10 @@ var useActionHandler = (view) => {
4406
4430
  };
4407
4431
 
4408
4432
  // packages/ui/react-ui-editor/src/hooks/useEditorView.ts
4409
- import { useRef as useRef2, useState as useState3 } from "react";
4433
+ import { useRef as useRef3, useState as useState4 } from "react";
4410
4434
  var useEditorView = (id) => {
4411
- const editorRef = useRef2(null);
4412
- const [prev, setPrev] = useState3([
4435
+ const editorRef = useRef3(null);
4436
+ const [prev, setPrev] = useState4([
4413
4437
  null,
4414
4438
  ""
4415
4439
  ]);
@@ -4428,14 +4452,14 @@ var useEditorView = (id) => {
4428
4452
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4429
4453
  import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4430
4454
  import { EditorView as EditorView15 } from "@codemirror/view";
4431
- import { useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
4455
+ import { useEffect as useEffect3, useRef as useRef4, useState as useState5 } from "react";
4432
4456
  import { log as log5 } from "@dxos/log";
4433
4457
  import { isNotFalsy as isNotFalsy5 } from "@dxos/util";
4434
4458
  var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
4435
4459
  var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}) => {
4436
- const onUpdate = useRef3();
4437
- const [view, setView] = useState4();
4438
- const parentRef = useRef3(null);
4460
+ const onUpdate = useRef4();
4461
+ const [view, setView] = useState5();
4462
+ const parentRef = useRef4(null);
4439
4463
  useEffect3(() => {
4440
4464
  let view2;
4441
4465
  if (parentRef.current) {
@@ -4447,7 +4471,7 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
4447
4471
  EditorView15.exceptionSink.of((err) => {
4448
4472
  log5.catch(err, void 0, {
4449
4473
  F: __dxlog_file6,
4450
- L: 60,
4474
+ L: 61,
4451
4475
  S: void 0,
4452
4476
  C: (f, a) => f(...a)
4453
4477
  });
@@ -4477,7 +4501,7 @@ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions }
4477
4501
  view2?.destroy();
4478
4502
  };
4479
4503
  }, [
4480
- parentRef,
4504
+ doc,
4481
4505
  extensions
4482
4506
  ]);
4483
4507
  useEffect3(() => {
@@ -4536,7 +4560,7 @@ var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
4536
4560
 
4537
4561
  // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
4538
4562
  import get4 from "lodash.get";
4539
- import { useState as useState5, useMemo as useMemo3 } from "react";
4563
+ import { useState as useState6, useMemo as useMemo3 } from "react";
4540
4564
  import { generateName } from "@dxos/display-name";
4541
4565
  import { getRawDoc } from "@dxos/echo-schema";
4542
4566
  import { invariant as invariant3 } from "@dxos/invariant";
@@ -4544,7 +4568,7 @@ import { isAutomergeObject } from "@dxos/react-client/echo";
4544
4568
  var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
4545
4569
  var useTextModel = (props) => useMemo3(() => createModel(props), Object.values(props));
4546
4570
  var useInMemoryTextModel = ({ id, defaultContent }) => {
4547
- const [content, setContent] = useState5(defaultContent ?? "");
4571
+ const [content, setContent] = useState6(defaultContent ?? "");
4548
4572
  return {
4549
4573
  id,
4550
4574
  content,
@@ -4646,7 +4670,6 @@ export {
4646
4670
  defaultTheme,
4647
4671
  editorFillLayoutEditor,
4648
4672
  editorFillLayoutRoot,
4649
- editorHalfViewportOverscrollContent,
4650
4673
  editorMode,
4651
4674
  editorWithToolbarLayout,
4652
4675
  focusComment,