@dxos/react-ui-editor 0.4.4-next.e0df51e → 0.4.4

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.
@@ -4,14 +4,16 @@
4
4
 
5
5
  import '@dxosTheme';
6
6
 
7
- import React from 'react';
7
+ import React, { useMemo, useState } from 'react';
8
8
 
9
- import { useThemeContext } from '@dxos/react-ui';
9
+ import { Toolbar as NaturalToolbar, Select, useThemeContext } from '@dxos/react-ui';
10
10
  import { attentionSurface, mx, textBlockWidth } from '@dxos/react-ui-theme';
11
11
  import { withTheme } from '@dxos/storybook-utils';
12
12
 
13
13
  import { TextEditor } from './TextEditor';
14
14
  import {
15
+ type EditorMode,
16
+ EditorModes,
15
17
  code,
16
18
  createMarkdownExtensions,
17
19
  formatting,
@@ -45,11 +47,10 @@ type StoryProps = {
45
47
  const Story = ({ autoFocus, placeholder, doc, readonly }: StoryProps) => {
46
48
  const { themeMode } = useThemeContext();
47
49
  const [formattingState, trackFormatting] = useFormattingState();
48
- const { parentRef, view } = useTextEditor({
49
- autoFocus,
50
- doc,
51
- extensions: [
52
- //
50
+ const [editorMode, setEditorMode] = useState<EditorMode>('default');
51
+ const extensions = useMemo(
52
+ () => [
53
+ editorMode ? EditorModes[editorMode] : [],
53
54
  createDataExtensions({ readonly }),
54
55
  createThemeExtensions({
55
56
  themeMode,
@@ -71,16 +72,19 @@ const Story = ({ autoFocus, placeholder, doc, readonly }: StoryProps) => {
71
72
  tasklist(),
72
73
  trackFormatting,
73
74
  ],
74
- });
75
+ [editorMode, themeMode, placeholder, trackFormatting, readonly],
76
+ );
77
+ const { parentRef, view } = useTextEditor({ autoFocus, doc, extensions });
75
78
 
76
79
  const handleAction = useActionHandler(view);
77
80
 
78
- // FIXME This doesn't update the state on view changes. Also not
79
- // sure if view is even guaranteed to exist at this point.
81
+ // TODO(marijn) This doesn't update the state on view changes.
82
+ // Also not sure if view is even guaranteed to exist at this point.
80
83
  return (
81
84
  <div role='none' className={mx('fixed inset-0', editorWithToolbarLayout)}>
82
85
  <Toolbar.Root onAction={handleAction} state={formattingState} classNames={textBlockWidth}>
83
86
  <Toolbar.Markdown />
87
+ <EditorModeToolbar editorMode={editorMode} setEditorMode={setEditorMode} />
84
88
  </Toolbar.Root>
85
89
  <div role='none' className='overflow-y-auto'>
86
90
  <div
@@ -93,6 +97,36 @@ const Story = ({ autoFocus, placeholder, doc, readonly }: StoryProps) => {
93
97
  );
94
98
  };
95
99
 
100
+ const EditorModeToolbar = ({
101
+ editorMode,
102
+ setEditorMode,
103
+ }: {
104
+ editorMode: EditorMode;
105
+ setEditorMode: (mode: EditorMode) => void;
106
+ }) => {
107
+ return (
108
+ <Select.Root value={editorMode} onValueChange={(value) => setEditorMode(value as EditorMode)}>
109
+ <NaturalToolbar.Button asChild>
110
+ <Select.TriggerButton variant='ghost'>{editorMode}</Select.TriggerButton>
111
+ </NaturalToolbar.Button>
112
+ <Select.Portal>
113
+ <Select.Content>
114
+ <Select.ScrollUpButton />
115
+ <Select.Viewport>
116
+ {['default', 'vim'].map((mode) => (
117
+ <Select.Option key={mode} value={mode}>
118
+ {mode}
119
+ </Select.Option>
120
+ ))}
121
+ </Select.Viewport>
122
+ <Select.ScrollDownButton />
123
+ <Select.Arrow />
124
+ </Select.Content>
125
+ </Select.Portal>
126
+ </Select.Root>
127
+ );
128
+ };
129
+
96
130
  export default {
97
131
  title: 'react-ui-editor/useTextEditor',
98
132
  component: TextEditor,
@@ -34,6 +34,7 @@ export type UseTextEditor = {
34
34
  /**
35
35
  * Hook for creating editor.
36
36
  */
37
+ // TODO(wittjosiah): Does not work in strict mode.
37
38
  export const useTextEditor = ({
38
39
  autoFocus,
39
40
  scrollTo,
@@ -45,7 +46,9 @@ export const useTextEditor = ({
45
46
  const onUpdate = useRef<() => void>();
46
47
  const [view, setView] = useState<EditorView>();
47
48
  const parentRef = useRef<HTMLDivElement>(null);
49
+
48
50
  useEffect(() => {
51
+ let view: EditorView;
49
52
  if (parentRef.current) {
50
53
  // https://codemirror.net/docs/ref/#state.EditorStateConfig
51
54
  const state = EditorState.create({
@@ -64,7 +67,7 @@ export const useTextEditor = ({
64
67
  });
65
68
 
66
69
  // https://codemirror.net/docs/ref/#view.EditorViewConfig
67
- const view = new EditorView({
70
+ view = new EditorView({
68
71
  parent: parentRef.current,
69
72
  scrollTo,
70
73
  state,
@@ -84,7 +87,8 @@ export const useTextEditor = ({
84
87
  return () => {
85
88
  view?.destroy();
86
89
  };
87
- }, [parentRef]);
90
+ // TODO(wittjosiah): Does `parentRef` ever change? Only `.current` changes?
91
+ }, [parentRef, extensions]);
88
92
 
89
93
  useEffect(() => {
90
94
  if (view) {