@dxos/react-ui-editor 0.8.2 → 0.8.3-main.672df60

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 (56) hide show
  1. package/dist/lib/browser/index.mjs +159 -105
  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 +172 -119
  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 +159 -105
  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/extensions/command/menu.d.ts.map +1 -1
  11. package/dist/types/src/extensions/hashtag.d.ts +3 -0
  12. package/dist/types/src/extensions/hashtag.d.ts.map +1 -0
  13. package/dist/types/src/extensions/index.d.ts +1 -0
  14. package/dist/types/src/extensions/index.d.ts.map +1 -1
  15. package/dist/types/src/extensions/json.d.ts.map +1 -1
  16. package/dist/types/src/extensions/markdown/debug.d.ts +2 -2
  17. package/dist/types/src/extensions/markdown/debug.d.ts.map +1 -1
  18. package/dist/types/src/extensions/outliner/outliner.d.ts +1 -3
  19. package/dist/types/src/extensions/outliner/outliner.d.ts.map +1 -1
  20. package/dist/types/src/stories/Command.stories.d.ts +1 -1
  21. package/dist/types/src/stories/Command.stories.d.ts.map +1 -1
  22. package/dist/types/src/stories/Comments.stories.d.ts +1 -1
  23. package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
  24. package/dist/types/src/stories/Experimental.stories.d.ts +1 -1
  25. package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -1
  26. package/dist/types/src/stories/Markdown.stories.d.ts +1 -1
  27. package/dist/types/src/stories/Markdown.stories.d.ts.map +1 -1
  28. package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
  29. package/dist/types/src/stories/Preview.stories.d.ts +1 -1
  30. package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
  31. package/dist/types/src/stories/TextEditor.stories.d.ts +1 -1
  32. package/dist/types/src/stories/TextEditor.stories.d.ts.map +1 -1
  33. package/dist/types/src/stories/components/EditorStory.d.ts +43 -0
  34. package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -0
  35. package/dist/types/src/stories/components/index.d.ts +3 -0
  36. package/dist/types/src/stories/components/index.d.ts.map +1 -0
  37. package/dist/types/src/stories/{util.d.ts → components/util.d.ts} +3 -18
  38. package/dist/types/src/stories/components/util.d.ts.map +1 -0
  39. package/package.json +28 -27
  40. package/src/extensions/command/menu.ts +31 -22
  41. package/src/extensions/hashtag.tsx +68 -0
  42. package/src/extensions/index.ts +1 -0
  43. package/src/extensions/json.ts +2 -1
  44. package/src/extensions/markdown/debug.ts +2 -2
  45. package/src/extensions/outliner/outliner.ts +9 -8
  46. package/src/stories/Command.stories.tsx +1 -1
  47. package/src/stories/Comments.stories.tsx +2 -2
  48. package/src/stories/Experimental.stories.tsx +2 -2
  49. package/src/stories/Markdown.stories.tsx +2 -2
  50. package/src/stories/Outliner.stories.tsx +19 -7
  51. package/src/stories/Preview.stories.tsx +2 -2
  52. package/src/stories/TextEditor.stories.tsx +3 -3
  53. package/src/stories/components/EditorStory.tsx +135 -0
  54. package/src/stories/components/index.ts +6 -0
  55. package/src/stories/{util.tsx → components/util.tsx} +5 -100
  56. package/dist/types/src/stories/util.d.ts.map +0 -1
@@ -11,7 +11,7 @@ import { IconButton, Popover } from '@dxos/react-ui';
11
11
  import { hoverableHidden } from '@dxos/react-ui-theme';
12
12
  import { withLayout, withTheme, type Meta } from '@dxos/storybook-utils';
13
13
 
14
- import { EditorStory } from './util';
14
+ import { EditorStory } from './components';
15
15
  import { RefPopover, useRefPopover } from '../components';
16
16
  import {
17
17
  preview,
@@ -108,8 +108,8 @@ const PreviewBlock: FC<PreviewRenderProps> = ({ readonly, link, onAction, onLook
108
108
 
109
109
  const meta: Meta<typeof EditorStory> = {
110
110
  title: 'ui/react-ui-editor/Preview',
111
+ component: EditorStory,
111
112
  decorators: [withTheme, withLayout({ fullscreen: true })],
112
- render: EditorStory,
113
113
  parameters: { layout: 'fullscreen' },
114
114
  };
115
115
 
@@ -23,7 +23,7 @@ import {
23
23
  names,
24
24
  renderLinkButton,
25
25
  text,
26
- } from './util';
26
+ } from './components';
27
27
  import { editorMonospace } from '../defaults';
28
28
  import {
29
29
  InputModeExtensions,
@@ -41,9 +41,9 @@ import { str } from '../testing';
41
41
 
42
42
  const meta: Meta<typeof EditorStory> = {
43
43
  title: 'ui/react-ui-editor/TextEditor',
44
- render: EditorStory,
44
+ component: EditorStory,
45
45
  decorators: [withTheme, withLayout({ fullscreen: true })],
46
- parameters: { layout: 'fullscreen' },
46
+ parameters: { layout: 'fullscreen', controls: { disable: true } },
47
47
  };
48
48
 
49
49
  export default meta;
@@ -0,0 +1,135 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type EditorView } from '@codemirror/view';
6
+ import React, { type ReactNode, forwardRef, useEffect, useState, useImperativeHandle, useMemo } from 'react';
7
+
8
+ import { Expando } from '@dxos/echo-schema';
9
+ import { invariant } from '@dxos/invariant';
10
+ import { PublicKey } from '@dxos/keys';
11
+ import { live } from '@dxos/live-object';
12
+ import { createDocAccessor, createObject } from '@dxos/react-client/echo';
13
+ import { useForwardedRef, useThemeContext } from '@dxos/react-ui';
14
+ import { useAttentionAttributes } from '@dxos/react-ui-attention';
15
+ import { JsonFilter } from '@dxos/react-ui-syntax-highlighter';
16
+ import { mx } from '@dxos/react-ui-theme';
17
+ import { isNonNullable } from '@dxos/util';
18
+
19
+ import { editorSlots, editorGutter } from '../../defaults';
20
+ import {
21
+ type DebugNode,
22
+ type ThemeExtensionsOptions,
23
+ createDataExtensions,
24
+ createBasicExtensions,
25
+ createMarkdownExtensions,
26
+ createThemeExtensions,
27
+ debugTree,
28
+ } from '../../extensions';
29
+ import { useTextEditor, type UseTextEditorProps } from '../../hooks';
30
+
31
+ // Type definitions.
32
+ export type DebugMode = 'raw' | 'tree' | 'raw+tree';
33
+
34
+ const defaultId = 'editor-' + PublicKey.random().toHex().slice(0, 8);
35
+
36
+ export type StoryProps = Pick<UseTextEditorProps, 'scrollTo' | 'selection' | 'extensions'> &
37
+ Pick<ThemeExtensionsOptions, 'slots'> & {
38
+ id?: string;
39
+ debug?: DebugMode;
40
+ debugCustom?: (view: EditorView) => ReactNode;
41
+ text?: string;
42
+ object?: Expando;
43
+ readOnly?: boolean;
44
+ placeholder?: string;
45
+ lineNumbers?: boolean;
46
+ onReady?: (view: EditorView) => void;
47
+ };
48
+
49
+ export const EditorStory = forwardRef<EditorView | undefined, StoryProps>(
50
+ ({ debug, debugCustom, text, extensions: _extensions, ...props }, forwardedRef) => {
51
+ const attentionAttrs = useAttentionAttributes('testing');
52
+ const [tree, setTree] = useState<DebugNode>();
53
+ const [object] = useState(createObject(live(Expando, { content: text ?? '' })));
54
+ const viewRef = useForwardedRef(forwardedRef);
55
+ const view = viewRef.current;
56
+ const extensions = useMemo(
57
+ () => (debug ? [_extensions, debugTree(setTree)].filter(isNonNullable) : _extensions),
58
+ [debug, _extensions],
59
+ );
60
+
61
+ return (
62
+ <div className={mx('w-full h-full grid overflow-hidden', debug && 'grid-cols-2 lg:grid-cols-[1fr_600px]')}>
63
+ <EditorComponent ref={viewRef} object={object} text={text} extensions={extensions} {...props} />
64
+
65
+ {debug && (
66
+ <div
67
+ className='grid h-full auto-rows-fr border-l border-separator divide-y divide-separator overflow-hidden'
68
+ {...attentionAttrs}
69
+ >
70
+ {view && debugCustom?.(view)}
71
+ {(debug === 'raw' || debug === 'raw+tree') && (
72
+ <pre className='p-1 text-xs text-green-800 dark:text-green-200 overflow-auto'>
73
+ {view?.state.doc.toString()}
74
+ </pre>
75
+ )}
76
+ {(debug === 'tree' || debug === 'raw+tree') && <JsonFilter data={tree} classNames='p-1 text-xs' />}
77
+ </div>
78
+ )}
79
+ </div>
80
+ );
81
+ },
82
+ );
83
+
84
+ /**
85
+ * Default story component.
86
+ */
87
+ export const EditorComponent = forwardRef<EditorView | undefined, StoryProps>(
88
+ (
89
+ {
90
+ id = defaultId,
91
+ text,
92
+ object,
93
+ readOnly,
94
+ placeholder = 'New document.',
95
+ lineNumbers,
96
+ scrollTo,
97
+ selection,
98
+ extensions,
99
+ slots = editorSlots,
100
+ onReady,
101
+ },
102
+ forwardedRef,
103
+ ) => {
104
+ invariant(object);
105
+ const { themeMode } = useThemeContext();
106
+ const attentionAttrs = useAttentionAttributes(id);
107
+ const { parentRef, focusAttributes, view } = useTextEditor(
108
+ () => ({
109
+ id,
110
+ scrollTo,
111
+ selection,
112
+ initialValue: text,
113
+ extensions: [
114
+ createDataExtensions({ id, text: createDocAccessor(object, ['content']) }),
115
+ createBasicExtensions({ readOnly, placeholder, lineNumbers, scrollPastEnd: true }),
116
+ createMarkdownExtensions({ themeMode }),
117
+ createThemeExtensions({ themeMode, syntaxHighlighting: true, slots }),
118
+ editorGutter,
119
+ extensions || [],
120
+ ],
121
+ }),
122
+ [id, object, extensions, themeMode],
123
+ );
124
+
125
+ useImperativeHandle(forwardedRef, () => view, [view]);
126
+
127
+ useEffect(() => {
128
+ if (view) {
129
+ onReady?.(view);
130
+ }
131
+ }, [view]);
132
+
133
+ return <div ref={parentRef} className='flex overflow-hidden' {...attentionAttrs} {...focusAttributes} />;
134
+ },
135
+ );
@@ -0,0 +1,6 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './EditorStory';
6
+ export * from './util';
@@ -4,38 +4,23 @@
4
4
 
5
5
  import { type Completion } from '@codemirror/autocomplete';
6
6
  import { type Extension } from '@codemirror/state';
7
- import { type EditorView } from '@codemirror/view';
8
- import React, { type ReactNode, useEffect, useState, type FC } from 'react';
7
+ import React, { type FC } from 'react';
9
8
 
10
- import { Expando } from '@dxos/echo-schema';
11
- import { PublicKey } from '@dxos/keys';
12
- import { live } from '@dxos/live-object';
13
9
  import { faker } from '@dxos/random';
14
- import { createDocAccessor, createObject } from '@dxos/react-client/echo';
15
- import { useThemeContext, Icon } from '@dxos/react-ui';
16
- import { JsonFilter } from '@dxos/react-ui-syntax-highlighter';
10
+ import { Icon } from '@dxos/react-ui';
17
11
  import { mx } from '@dxos/react-ui-theme';
18
12
 
19
- import { editorSlots, editorGutter } from '../defaults';
20
13
  import {
21
- type DebugNode,
22
14
  type EditorSelectionState,
23
- createDataExtensions,
24
- createBasicExtensions,
25
- createMarkdownExtensions,
26
- createThemeExtensions,
27
15
  decorateMarkdown,
28
- debugTree,
29
16
  folding,
30
17
  formattingKeymap,
31
18
  image,
32
19
  linkTooltip,
33
20
  table,
34
- type ThemeExtensionsOptions,
35
- } from '../extensions';
36
- import { useTextEditor, type UseTextEditorProps } from '../hooks';
37
- import { str } from '../testing';
38
- import { createRenderer } from '../util';
21
+ } from '../../extensions';
22
+ import { str } from '../../testing';
23
+ import { createRenderer } from '../../util';
39
24
 
40
25
  export const num = () => faker.number.int({ min: 0, max: 9999 }).toLocaleString();
41
26
 
@@ -244,83 +229,3 @@ export const headings = str(
244
229
  );
245
230
 
246
231
  export const global = new Map<string, EditorSelectionState>();
247
-
248
- // Type definitions
249
- export type DebugMode = 'raw' | 'tree' | 'raw+tree';
250
-
251
- export type StoryProps = {
252
- id?: string;
253
- debug?: DebugMode;
254
- debugCustom?: (view: EditorView) => ReactNode;
255
- text?: string;
256
- readOnly?: boolean;
257
- placeholder?: string;
258
- lineNumbers?: boolean;
259
- onReady?: (view: EditorView) => void;
260
- } & Pick<UseTextEditorProps, 'scrollTo' | 'selection' | 'extensions'> &
261
- Pick<ThemeExtensionsOptions, 'slots'>;
262
-
263
- // Default story component
264
- export const EditorStory = ({
265
- id = 'editor-' + PublicKey.random().toHex().slice(0, 8),
266
- debug,
267
- debugCustom,
268
- text,
269
- readOnly,
270
- placeholder = 'New document.',
271
- lineNumbers,
272
- scrollTo,
273
- selection,
274
- extensions,
275
- slots = editorSlots,
276
- onReady,
277
- }: StoryProps) => {
278
- const [object] = useState(createObject(live(Expando, { content: text ?? '' })));
279
- const { themeMode } = useThemeContext();
280
- const [tree, setTree] = useState<DebugNode>();
281
- const { parentRef, focusAttributes, view } = useTextEditor(
282
- () => ({
283
- id,
284
- initialValue: text,
285
- extensions: [
286
- createDataExtensions({ id, text: createDocAccessor(object, ['content']) }),
287
- createBasicExtensions({ readOnly, placeholder, lineNumbers, scrollPastEnd: true }),
288
- createMarkdownExtensions({ themeMode }),
289
- createThemeExtensions({
290
- themeMode,
291
- syntaxHighlighting: true,
292
- slots,
293
- }),
294
- editorGutter,
295
- extensions || [],
296
- debug ? debugTree(setTree) : [],
297
- ],
298
- scrollTo,
299
- selection,
300
- }),
301
- [object, extensions, themeMode],
302
- );
303
-
304
- useEffect(() => {
305
- if (view) {
306
- onReady?.(view);
307
- }
308
- }, [view]);
309
-
310
- return (
311
- <div className={mx('w-full h-full grid overflow-hidden', debug && 'grid-cols-[1fr_600px]')}>
312
- <div role='none' className='flex overflow-hidden' ref={parentRef} {...focusAttributes} />
313
- {debug && (
314
- <div className='grid h-full auto-rows-fr border-l border-separator divide-y divide-separator overflow-hidden'>
315
- {view && debugCustom?.(view)}
316
- {(debug === 'raw' || debug === 'raw+tree') && (
317
- <pre className='p-1 text-xs text-green-800 dark:text-green-200 overflow-auto'>
318
- {view?.state.doc.toString()}
319
- </pre>
320
- )}
321
- {(debug === 'tree' || debug === 'raw+tree') && <JsonFilter data={tree} classNames='p-1 text-xs' />}
322
- </div>
323
- )}
324
- </div>
325
- );
326
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../../src/stories/util.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,EAAE,KAAK,SAAS,EAAgC,MAAM,OAAO,CAAC;AAY5E,OAAO,EAEL,KAAK,oBAAoB,EAYzB,KAAK,sBAAsB,EAC5B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAIlE,eAAO,MAAM,GAAG,cAAiE,CAAC;AAElF,eAAO,MAAM,GAAG,yDAAyD,CAAC;AAE1E,eAAO,MAAM,IAAI,QAOhB,CAAC;AAGF,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;CA+FnB,CAAC;AAGF,eAAO,MAAM,IAAI,QAwBhB,CAAC;AAGF,eAAO,MAAM,KAAK,EAAE,UAAU,EAM7B,CAAC;AAEF,eAAO,MAAM,KAAK,UAA4E,CAAC;AAe/F,eAAO,MAAM,iBAAiB;SAVD,MAAM;EAUyB,CAAC;AAU7D,eAAO,MAAM,gBAAgB;SARD,MAAM;EAQwB,CAAC;AAG3D,eAAO,MAAM,iBAAiB,EAAE,SAAS,EAIxC,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,SAAS,EAOpC,CAAC;AAGF,eAAO,MAAM,QAAQ,QAEN,CAAC;AAEhB,eAAO,MAAM,eAAe,QAGb,CAAC;AAEhB,eAAO,MAAM,QAAQ,QAIpB,CAAC;AAEF,eAAO,MAAM,MAAM,mCAA0C,CAAC;AAG9D,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,UAAU,CAAC;AAEpD,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,SAAS,CAAC;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACtC,GAAG,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,WAAW,GAAG,YAAY,CAAC,GACnE,IAAI,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAC;AAGxC,eAAO,MAAM,WAAW,GAAI,wHAazB,UAAU,sBAiDZ,CAAC"}