@dxos/react-ui-editor 0.8.1-main.ba2dec9 → 0.8.1-staging.31c3ee1

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 (52) hide show
  1. package/dist/lib/browser/index.mjs +283 -147
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +317 -185
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +283 -147
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/InputMode.stories.d.ts +2 -2
  11. package/dist/types/src/TextEditor.stories.d.ts +5 -40
  12. package/dist/types/src/TextEditor.stories.d.ts.map +1 -1
  13. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
  14. package/dist/types/src/defaults.d.ts +2 -0
  15. package/dist/types/src/defaults.d.ts.map +1 -1
  16. package/dist/types/src/extensions/command/command.d.ts +4 -2
  17. package/dist/types/src/extensions/command/command.d.ts.map +1 -1
  18. package/dist/types/src/extensions/command/hint.d.ts.map +1 -1
  19. package/dist/types/src/extensions/command/menu.d.ts +12 -0
  20. package/dist/types/src/extensions/command/menu.d.ts.map +1 -0
  21. package/dist/types/src/extensions/command/preview.d.ts +12 -0
  22. package/dist/types/src/extensions/command/preview.d.ts.map +1 -0
  23. package/dist/types/src/extensions/command/state.d.ts.map +1 -1
  24. package/dist/types/src/extensions/comments.d.ts +3 -3
  25. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  26. package/dist/types/src/extensions/factories.d.ts +2 -1
  27. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  28. package/dist/types/src/{styles/stack-item-content-class-names.d.ts → fragments.d.ts} +1 -1
  29. package/dist/types/src/fragments.d.ts.map +1 -0
  30. package/dist/types/src/hooks/useTextEditor.d.ts +3 -3
  31. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  32. package/dist/types/src/index.d.ts +0 -1
  33. package/dist/types/src/index.d.ts.map +1 -1
  34. package/dist/types/src/styles/theme.d.ts.map +1 -1
  35. package/package.json +28 -28
  36. package/src/InputMode.stories.tsx +4 -4
  37. package/src/TextEditor.stories.tsx +173 -59
  38. package/src/components/EditorToolbar/EditorToolbar.tsx +4 -5
  39. package/src/defaults.ts +12 -0
  40. package/src/extensions/command/command.ts +21 -2
  41. package/src/extensions/command/hint.ts +3 -0
  42. package/src/extensions/command/menu.ts +100 -0
  43. package/src/extensions/command/preview.ts +79 -0
  44. package/src/extensions/command/state.ts +9 -4
  45. package/src/extensions/comments.ts +6 -10
  46. package/src/extensions/factories.ts +4 -3
  47. package/src/{styles/stack-item-content-class-names.ts → fragments.ts} +4 -2
  48. package/src/hooks/useTextEditor.ts +17 -8
  49. package/src/index.ts +0 -4
  50. package/src/styles/theme.ts +6 -1
  51. package/src/util/debug.ts +1 -1
  52. package/dist/types/src/styles/stack-item-content-class-names.d.ts.map +0 -1
@@ -7,11 +7,11 @@ import React, { useCallback } from 'react';
7
7
  import { type NodeArg } from '@dxos/app-graph';
8
8
  import { ElevationProvider } from '@dxos/react-ui';
9
9
  import {
10
- ToolbarMenu,
11
- MenuProvider,
12
10
  type MenuActionHandler,
13
- useMenuActions,
11
+ MenuProvider,
12
+ ToolbarMenu,
14
13
  createGapSeparator,
14
+ useMenuActions,
15
15
  } from '@dxos/react-ui-menu';
16
16
  import { textBlockWidth } from '@dxos/react-ui-theme';
17
17
 
@@ -27,7 +27,7 @@ import {
27
27
  editorToolbarSearch,
28
28
  } from './util';
29
29
  import { createViewMode } from './viewMode';
30
- import { stackItemContentToolbarClassNames } from '../../styles/stack-item-content-class-names';
30
+ import { stackItemContentToolbarClassNames } from '../../fragments';
31
31
 
32
32
  const createToolbar = ({
33
33
  state,
@@ -86,7 +86,6 @@ const createToolbar = ({
86
86
 
87
87
  const useEditorToolbarActionGraph = ({ onAction, ...props }: EditorToolbarProps) => {
88
88
  const menuCreator = useCallback(() => createToolbar(props), [props]);
89
-
90
89
  const { resolveGroupItems } = useMenuActions(menuCreator);
91
90
 
92
91
  return { resolveGroupItems, onAction: onAction as MenuActionHandler };
package/src/defaults.ts CHANGED
@@ -41,3 +41,15 @@ export const editorMonospace = EditorView.theme({
41
41
 
42
42
  export const editorWithToolbarLayout =
43
43
  'grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden';
44
+
45
+ export const stackItemContentEditorClassNames = (role?: string) =>
46
+ mx(
47
+ 'attention-surface dx-focus-ring-inset data-[toolbar=disabled]:pbs-2',
48
+ role === 'section' ? '[&_.cm-scroller]:overflow-hidden [&_.cm-scroller]:min-bs-24' : 'min-bs-0',
49
+ );
50
+
51
+ export const stackItemContentToolbarClassNames = (role?: string) =>
52
+ mx(
53
+ 'attention-surface is-full border-be !border-separator',
54
+ role === 'section' && 'sticky block-start-0 z-[1] -mbe-px min-is-0',
55
+ );
@@ -6,6 +6,8 @@ import { type Extension } from '@codemirror/state';
6
6
  import { EditorView, keymap } from '@codemirror/view';
7
7
 
8
8
  import { hintViewPlugin } from './hint';
9
+ import { floatingMenu } from './menu';
10
+ import { preview, type PreviewOptions } from './preview';
9
11
  import { closeEffect, commandConfig, commandKeyBindings, commandState } from './state';
10
12
 
11
13
  // TODO(burdon): Create knowledge base for CM notes and ideas.
@@ -13,23 +15,40 @@ import { closeEffect, commandConfig, commandKeyBindings, commandState } from './
13
15
  // https://github.com/saminzadeh/codemirror-extension-inline-suggestion
14
16
  // https://github.com/ChromeDevTools/devtools-frontend/blob/main/front_end/ui/components/text_editor/config.ts#L370
15
17
 
18
+ // TODO(burdon): Discriminated union.
16
19
  export type CommandAction = {
17
20
  insert?: string;
18
21
  };
19
22
 
20
23
  export type CommandOptions = {
21
- onRender: (el: HTMLElement, cb: (action?: CommandAction) => void) => void;
22
24
  onHint: () => string | undefined;
23
- };
25
+ onRenderDialog: (el: HTMLElement, cb: (action?: CommandAction) => void) => void;
26
+ onRenderMenu: (el: HTMLElement, cb: () => void) => void;
27
+ } & Pick<PreviewOptions, 'onRenderPreview'>;
24
28
 
25
29
  export const command = (options: CommandOptions): Extension => {
26
30
  return [
27
31
  commandConfig.of(options),
28
32
  commandState,
29
33
  keymap.of(commandKeyBindings),
34
+ preview(options),
35
+ floatingMenu(options),
30
36
  hintViewPlugin(options),
31
37
  EditorView.focusChangeEffect.of((_, focusing) => {
32
38
  return focusing ? closeEffect.of(null) : null;
33
39
  }),
40
+ EditorView.theme({
41
+ '.cm-tooltip': {
42
+ background: 'transparent',
43
+ },
44
+ '.cm-preview': {
45
+ marginLeft: '-1rem',
46
+ marginRight: '-1rem',
47
+ padding: '1rem',
48
+ borderRadius: '1rem',
49
+ background: 'var(--dx-modalSurface)',
50
+ border: '1px solid var(--dx-separator)',
51
+ },
52
+ }),
34
53
  ];
35
54
  };
@@ -24,6 +24,7 @@ class CommandHint extends WidgetType {
24
24
  } else {
25
25
  wrap.setAttribute('aria-hidden', 'true');
26
26
  }
27
+
27
28
  return wrap;
28
29
  }
29
30
 
@@ -32,12 +33,14 @@ class CommandHint extends WidgetType {
32
33
  if (!rects.length) {
33
34
  return null;
34
35
  }
36
+
35
37
  const style = window.getComputedStyle(dom.parentNode as HTMLElement);
36
38
  const rect = flattenRect(rects[0], style.direction !== 'rtl');
37
39
  const lineHeight = parseInt(style.lineHeight);
38
40
  if (rect.bottom - rect.top > lineHeight * 1.5) {
39
41
  return { left: rect.left, right: rect.right, top: rect.top, bottom: rect.top + lineHeight };
40
42
  }
43
+
41
44
  return rect;
42
45
  }
43
46
 
@@ -0,0 +1,100 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { type BlockInfo, type EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';
6
+
7
+ import { type CommandOptions } from './command';
8
+ import { closeEffect, openCommand, openEffect } from './state';
9
+
10
+ // TODO(burdon): Trigger completion on click.
11
+ // TODO(burdon): Hide when dialog is open.
12
+ export const floatingMenu = (options: CommandOptions) =>
13
+ ViewPlugin.fromClass(
14
+ class {
15
+ button: HTMLElement;
16
+ view: EditorView;
17
+ rafId: number | null = null;
18
+
19
+ constructor(view: EditorView) {
20
+ this.view = view;
21
+
22
+ // Position context: scrollDOM
23
+ const container = view.scrollDOM;
24
+ if (getComputedStyle(container).position === 'static') {
25
+ container.style.position = 'relative';
26
+ }
27
+
28
+ // Render menu externally.
29
+ this.button = document.createElement('div');
30
+ this.button.style.position = 'absolute';
31
+ this.button.style.zIndex = '10';
32
+ this.button.style.display = 'none';
33
+
34
+ options.onRenderMenu(this.button, () => {
35
+ openCommand(view);
36
+ });
37
+ container.appendChild(this.button);
38
+
39
+ // Listen for scroll events.
40
+ container.addEventListener('scroll', this.scheduleUpdate);
41
+ this.scheduleUpdate();
42
+ }
43
+
44
+ update(update: ViewUpdate) {
45
+ // TODO(burdon): Timer to fade in/out.
46
+ if (update.transactions.some((tr) => tr.effects.some((effect) => effect.is(openEffect)))) {
47
+ this.button.style.display = 'none';
48
+ } else if (update.transactions.some((tr) => tr.effects.some((effect) => effect.is(closeEffect)))) {
49
+ this.button.style.display = 'block';
50
+ } else if (update.selectionSet || update.viewportChanged || update.docChanged || update.geometryChanged) {
51
+ this.scheduleUpdate();
52
+ }
53
+ }
54
+
55
+ scheduleUpdate() {
56
+ if (this.rafId != null) {
57
+ cancelAnimationFrame(this.rafId);
58
+ }
59
+ this.rafId = requestAnimationFrame(() => this.updateButtonPosition());
60
+ }
61
+
62
+ updateButtonPosition() {
63
+ const pos = this.view.state.selection.main.head;
64
+ const lineBlock: BlockInfo = this.view.lineBlockAt(pos);
65
+ const domInfo = this.view.domAtPos(lineBlock.from);
66
+
67
+ // Find nearest HTMLElement for the line block
68
+ let node: Node | null = domInfo.node;
69
+ while (node && !(node instanceof HTMLElement)) {
70
+ node = node.parentNode;
71
+ }
72
+
73
+ if (!node) {
74
+ this.button.style.display = 'none';
75
+ return;
76
+ }
77
+
78
+ const lineRect = (node as HTMLElement).getBoundingClientRect();
79
+ const containerRect = this.view.scrollDOM.getBoundingClientRect();
80
+
81
+ // Account for scroll and padding/margin in scrollDOM.
82
+ const offsetTop = lineRect.top - containerRect.top + this.view.scrollDOM.scrollTop;
83
+ const offsetLeft = this.view.scrollDOM.clientWidth + this.view.scrollDOM.scrollLeft - lineRect.x;
84
+
85
+ // TODO(burdon): Position is incorrect if cursor is in fenced code block.
86
+ // console.log('offsetTop', lineRect, containerRect);
87
+
88
+ this.button.style.top = `${offsetTop}px`;
89
+ this.button.style.left = `${offsetLeft}px`;
90
+ this.button.style.display = 'block';
91
+ }
92
+
93
+ destroy() {
94
+ this.button.remove();
95
+ if (this.rafId != null) {
96
+ cancelAnimationFrame(this.rafId);
97
+ }
98
+ }
99
+ },
100
+ );
@@ -0,0 +1,79 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { syntaxTree } from '@codemirror/language';
6
+ import {
7
+ type EditorState,
8
+ type Extension,
9
+ type RangeSet,
10
+ RangeSetBuilder,
11
+ StateField,
12
+ type Transaction,
13
+ } from '@codemirror/state';
14
+ import { Decoration, type DecorationSet, EditorView, WidgetType } from '@codemirror/view';
15
+
16
+ export type PreviewOptions = {
17
+ onRenderPreview: (el: HTMLElement, props: { url: string; text: string }) => void;
18
+ };
19
+
20
+ /**
21
+ * Create image decorations.
22
+ */
23
+ export const preview = (options: PreviewOptions): Extension => {
24
+ return [
25
+ StateField.define<DecorationSet>({
26
+ create: (state) => buildDecorations(state, options),
27
+ update: (_: RangeSet<Decoration>, tr: Transaction) => buildDecorations(tr.state, options),
28
+ // TODO(burdon): Make atomic.
29
+ provide: (field) => EditorView.decorations.from(field),
30
+ }),
31
+ ];
32
+ };
33
+
34
+ // TODO(burdon): Make atomic.
35
+ const buildDecorations = (state: EditorState, options: PreviewOptions) => {
36
+ const builder = new RangeSetBuilder<Decoration>();
37
+ syntaxTree(state).iterate({
38
+ enter: (node) => {
39
+ if (node.name === 'Link') {
40
+ const urlNode = node.node.getChild('URL');
41
+ if (urlNode) {
42
+ const text = state.sliceDoc(node.from + 1, urlNode.from - 2);
43
+ const url = state.sliceDoc(urlNode.from, urlNode.to);
44
+ builder.add(
45
+ node.from,
46
+ node.to,
47
+ Decoration.replace({
48
+ block: true, // Prevent cursor from entering.
49
+ widget: new PreviewWidget(options.onRenderPreview, url, text),
50
+ }),
51
+ );
52
+ }
53
+ }
54
+ },
55
+ });
56
+
57
+ return builder.finish();
58
+ };
59
+
60
+ class PreviewWidget extends WidgetType {
61
+ constructor(
62
+ readonly _onRenderPreview: PreviewOptions['onRenderPreview'],
63
+ readonly _url: string,
64
+ readonly _text: string,
65
+ ) {
66
+ super();
67
+ }
68
+
69
+ override eq(other: this) {
70
+ return this._url === (other as any as PreviewWidget)._url;
71
+ }
72
+
73
+ override toDOM(view: EditorView) {
74
+ const root = document.createElement('div');
75
+ root.classList.add('cm-preview');
76
+ this._onRenderPreview(root, { url: this._url, text: this._text });
77
+ return root;
78
+ }
79
+ }
@@ -4,10 +4,10 @@
4
4
 
5
5
  import { StateEffect, StateField } from '@codemirror/state';
6
6
  import {
7
+ showTooltip,
7
8
  type Command,
8
9
  type EditorView,
9
10
  type KeyBinding,
10
- showTooltip,
11
11
  type Tooltip,
12
12
  type TooltipView,
13
13
  } from '@codemirror/view';
@@ -50,14 +50,17 @@ export const commandState = StateField.define<CommandState>({
50
50
  }
51
51
 
52
52
  // Render react component.
53
- options.onRender(dom, (action) => {
53
+ options.onRenderDialog(dom, (action) => {
54
54
  view.dispatch({ effects: closeEffect.of(null) });
55
55
  if (action?.insert?.length) {
56
+ // Insert into editor.
57
+ const text = action.insert + '\n';
56
58
  view.dispatch({
57
- changes: { from: pos, insert: action.insert },
58
- selection: { anchor: pos + action.insert.length },
59
+ changes: { from: pos, insert: text },
60
+ selection: { anchor: pos + text.length },
59
61
  });
60
62
  }
63
+
61
64
  // NOTE: Truncates text if set focus immediately.
62
65
  requestAnimationFrame(() => view.focus());
63
66
  });
@@ -88,6 +91,7 @@ export const openCommand: Command = (view: EditorView) => {
88
91
  return true;
89
92
  }
90
93
  }
94
+
91
95
  return false;
92
96
  };
93
97
 
@@ -96,6 +100,7 @@ export const closeCommand: Command = (view: EditorView) => {
96
100
  view.dispatch({ effects: closeEffect.of(null) });
97
101
  return true;
98
102
  }
103
+
99
104
  return false;
100
105
  };
101
106
 
@@ -4,12 +4,12 @@
4
4
 
5
5
  import { invertedEffects } from '@codemirror/commands';
6
6
  import {
7
+ type ChangeDesc,
8
+ type EditorState,
7
9
  type Extension,
8
10
  StateEffect,
9
11
  StateField,
10
12
  type Text,
11
- type ChangeDesc,
12
- type EditorState,
13
13
  } from '@codemirror/state';
14
14
  import {
15
15
  hoverTooltip,
@@ -24,7 +24,7 @@ import {
24
24
  import sortBy from 'lodash.sortby';
25
25
  import { useEffect, useMemo } from 'react';
26
26
 
27
- import { debounce, type UnsubscribeCallback } from '@dxos/async';
27
+ import { debounce, type CleanupFn } from '@dxos/async';
28
28
  import { type ReactiveObject } from '@dxos/live-object';
29
29
  import { log } from '@dxos/log';
30
30
  import { isNonNullable } from '@dxos/util';
@@ -181,6 +181,7 @@ const handleCommentClick = EditorView.domEventHandlers({
181
181
  return false;
182
182
  },
183
183
  });
184
+
184
185
  //
185
186
  // Cut-and-paste.
186
187
  //
@@ -575,12 +576,7 @@ const hasActiveSelection = (state: EditorState): boolean => {
575
576
  class ExternalCommentSync implements PluginValue {
576
577
  private readonly unsubscribe: () => void;
577
578
 
578
- constructor(
579
- view: EditorView,
580
- id: string,
581
- subscribe: (sink: () => void) => UnsubscribeCallback,
582
- getComments: () => Comment[],
583
- ) {
579
+ constructor(view: EditorView, id: string, subscribe: (sink: () => void) => CleanupFn, getComments: () => Comment[]) {
584
580
  const updateComments = () => {
585
581
  const comments = getComments();
586
582
  if (id === view.state.facet(documentId)) {
@@ -599,7 +595,7 @@ class ExternalCommentSync implements PluginValue {
599
595
  // TODO(burdon): Needs comment.
600
596
  export const createExternalCommentSync = (
601
597
  id: string,
602
- subscribe: (sink: () => void) => UnsubscribeCallback,
598
+ subscribe: (sink: () => void) => CleanupFn,
603
599
  getComments: () => Comment[],
604
600
  ): Extension =>
605
601
  ViewPlugin.fromClass(
@@ -61,7 +61,8 @@ export type BasicExtensionsOptions = {
61
61
  lineNumbers?: boolean;
62
62
  lineWrapping?: boolean;
63
63
  placeholder?: string;
64
- readonly?: boolean;
64
+ /** If true user cannot edit the text, but they can still select and copy it. */
65
+ readOnly?: boolean;
65
66
  search?: boolean;
66
67
  scrollPastEnd?: boolean;
67
68
  standardKeymap?: boolean;
@@ -73,7 +74,6 @@ const defaultBasicOptions: BasicExtensionsOptions = {
73
74
  bracketMatching: true,
74
75
  closeBrackets: true,
75
76
  drawSelection: true,
76
- editable: true,
77
77
  focus: true,
78
78
  history: true,
79
79
  keymap: 'standard',
@@ -101,13 +101,14 @@ export const createBasicExtensions = (_props?: BasicExtensionsOptions): Extensio
101
101
  props.closeBrackets && closeBrackets(),
102
102
  props.dropCursor && dropCursor(),
103
103
  props.drawSelection && drawSelection({ cursorBlinkRate: 1_200 }),
104
+ props.editable !== undefined && EditorView.editable.of(props.editable),
104
105
  props.focus && focus,
105
106
  props.highlightActiveLine && highlightActiveLine(),
106
107
  props.history && history(),
107
108
  props.lineNumbers && lineNumbers(),
108
109
  props.lineWrapping && EditorView.lineWrapping,
109
110
  props.placeholder && placeholder(props.placeholder),
110
- props.readonly && [EditorState.readOnly.of(true), EditorView.editable.of(false)],
111
+ props.readOnly !== undefined && EditorState.readOnly.of(props.readOnly),
111
112
  props.scrollPastEnd && scrollPastEnd(),
112
113
  props.tabSize && EditorState.tabSize.of(props.tabSize),
113
114
 
@@ -4,10 +4,12 @@
4
4
 
5
5
  import { mx } from '@dxos/react-ui-theme';
6
6
 
7
+ // TODO(burdon): Move this to a common plugin.
8
+
7
9
  export const stackItemContentEditorClassNames = (role?: string) =>
8
10
  mx(
9
- 'dx-focus-ring-inset data-[toolbar=disabled]:pbs-2 attention-surface',
10
- role === 'article' ? 'min-bs-0' : '[&_.cm-scroller]:overflow-hidden [&_.cm-scroller]:min-bs-24',
11
+ 'attention-surface dx-focus-ring-inset data-[toolbar=disabled]:pbs-2',
12
+ role === 'section' ? '[&_.cm-scroller]:overflow-hidden [&_.cm-scroller]:min-bs-24' : 'min-bs-0',
11
13
  );
12
14
 
13
15
  export const stackItemContentToolbarClassNames = (role?: string) =>
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { EditorState, type EditorStateConfig } from '@codemirror/state';
6
6
  import { EditorView } from '@codemirror/view';
7
- import { useFocusableGroup } from '@fluentui/react-tabster';
7
+ import { useFocusableGroup, type TabsterTypes } from '@fluentui/react-tabster';
8
8
  import {
9
9
  type DependencyList,
10
10
  type KeyboardEventHandler,
@@ -19,14 +19,14 @@ import {
19
19
  import { log } from '@dxos/log';
20
20
  import { getProviderValue, isNotFalsy, type MaybeProvider } from '@dxos/util';
21
21
 
22
- import { editorInputMode, type EditorSelection, documentId, createEditorStateTransaction } from '../extensions';
22
+ import { type EditorSelection, documentId, createEditorStateTransaction, editorInputMode } from '../extensions';
23
23
  import { debugDispatcher } from '../util';
24
24
 
25
25
  export type UseTextEditor = {
26
26
  // TODO(burdon): Rename.
27
27
  parentRef: RefObject<HTMLDivElement>;
28
28
  view?: EditorView;
29
- focusAttributes: ReturnType<typeof useFocusableGroup> & {
29
+ focusAttributes?: TabsterTypes.TabsterDOMAttribute & {
30
30
  tabIndex: 0;
31
31
  onKeyUp: KeyboardEventHandler<HTMLDivElement>;
32
32
  };
@@ -55,7 +55,7 @@ export type UseTextEditorProps = Pick<EditorStateConfig, 'extensions'> & {
55
55
  let instanceCount = 0;
56
56
 
57
57
  /**
58
- * Hook for creating editor.
58
+ * Creates codemirror text editor.
59
59
  */
60
60
  export const useTextEditor = (
61
61
  props: MaybeProvider<UseTextEditorProps> = {},
@@ -155,9 +155,11 @@ export const useTextEditor = (
155
155
  }
156
156
  }, [autoFocus, view]);
157
157
 
158
- const focusableGroup = useFocusableGroup({
158
+ const focusableGroupAttrs = useFocusableGroup({
159
159
  tabBehavior: 'limited',
160
- ignoreDefaultKeydown: { Escape: view?.state.facet(editorInputMode).noTabster },
160
+ ignoreDefaultKeydown: {
161
+ Escape: view?.state.facet(editorInputMode).noTabster,
162
+ },
161
163
  });
162
164
 
163
165
  // Focus editor on Enter (e.g., when tabbing to this component).
@@ -176,6 +178,13 @@ export const useTextEditor = (
176
178
  [view],
177
179
  );
178
180
 
179
- const focusAttributes = { tabIndex: 0 as const, ...focusableGroup, onKeyUp: handleKeyUp };
180
- return { parentRef, view, focusAttributes };
181
+ return {
182
+ parentRef,
183
+ view,
184
+ focusAttributes: {
185
+ tabIndex: 0 as const,
186
+ ...focusableGroupAttrs,
187
+ onKeyUp: handleKeyUp,
188
+ },
189
+ };
181
190
  };
package/src/index.ts CHANGED
@@ -14,10 +14,6 @@ export * from './components';
14
14
  export * from './defaults';
15
15
  export * from './extensions';
16
16
  export * from './hooks';
17
- export {
18
- stackItemContentEditorClassNames,
19
- stackItemContentToolbarClassNames,
20
- } from './styles/stack-item-content-class-names';
21
17
  export * from './types';
22
18
  export * from './util';
23
19
 
@@ -77,6 +77,10 @@ export const defaultTheme: ThemeStyles = {
77
77
  background: 'transparent',
78
78
  },
79
79
  '.cm-gutter': {},
80
+ '.cm-gutter.cm-lineNumbers': {
81
+ paddingRight: '4px',
82
+ borderRight: '1px solid var(--dx-separator)',
83
+ },
80
84
  '.cm-gutter.cm-lineNumbers .cm-gutterElement': {
81
85
  minWidth: '40px',
82
86
  alignContent: 'center',
@@ -86,7 +90,7 @@ export const defaultTheme: ThemeStyles = {
86
90
  */
87
91
  '.cm-gutterElement': {
88
92
  alignItems: 'center',
89
- fontSize: '16px',
93
+ fontSize: '12px',
90
94
  },
91
95
 
92
96
  /**
@@ -137,6 +141,7 @@ export const defaultTheme: ThemeStyles = {
137
141
  '.cm-link': {
138
142
  textDecorationLine: 'underline',
139
143
  textDecorationThickness: '1px',
144
+ textDecorationColor: 'var(--dx-separator)',
140
145
  textUnderlineOffset: '2px',
141
146
  borderRadius: '.125rem',
142
147
  },
package/src/util/debug.ts CHANGED
@@ -59,6 +59,6 @@ export const logChanges = (trs: readonly Transaction[]) => {
59
59
  .filter(Boolean);
60
60
 
61
61
  if (changes.length) {
62
- log.info('changes', { changes });
62
+ log('changes', { changes });
63
63
  }
64
64
  };
@@ -1 +0,0 @@
1
- {"version":3,"file":"stack-item-content-class-names.d.ts","sourceRoot":"","sources":["../../../../src/styles/stack-item-content-class-names.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,gCAAgC,UAAW,MAAM,WAI3D,CAAC;AAEJ,eAAO,MAAM,iCAAiC,UAAW,MAAM,WAI5D,CAAC"}