@dxos/react-ui-editor 0.3.10-main.5515dfe → 0.3.10-main.560f82b

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 (108) hide show
  1. package/dist/lib/browser/index.mjs +1049 -285
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +22 -1
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts +3 -1
  7. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  8. package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts +3 -2
  9. package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts.map +1 -1
  10. package/dist/types/src/components/TextEditor/extensions/basic.d.ts +2 -1
  11. package/dist/types/src/components/TextEditor/extensions/basic.d.ts.map +1 -1
  12. package/dist/types/src/components/TextEditor/extensions/blast.d.ts +25 -0
  13. package/dist/types/src/components/TextEditor/extensions/blast.d.ts.map +1 -0
  14. package/dist/types/src/components/TextEditor/extensions/comments.d.ts +18 -0
  15. package/dist/types/src/components/TextEditor/extensions/comments.d.ts.map +1 -0
  16. package/dist/types/src/components/TextEditor/extensions/demo.d.ts +11 -0
  17. package/dist/types/src/components/TextEditor/extensions/demo.d.ts.map +1 -0
  18. package/dist/types/src/components/TextEditor/extensions/experimental.d.ts.map +1 -1
  19. package/dist/types/src/components/TextEditor/extensions/image.d.ts +4 -0
  20. package/dist/types/src/components/TextEditor/extensions/image.d.ts.map +1 -0
  21. package/dist/types/src/components/TextEditor/extensions/index.d.ts +6 -0
  22. package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -1
  23. package/dist/types/src/components/TextEditor/extensions/link.d.ts.map +1 -1
  24. package/dist/types/src/components/TextEditor/extensions/listener.d.ts +4 -2
  25. package/dist/types/src/components/TextEditor/extensions/listener.d.ts.map +1 -1
  26. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts +2 -1
  27. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +1 -1
  28. package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts +6 -2
  29. package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts.map +1 -1
  30. package/dist/types/src/components/TextEditor/extensions/mention.d.ts +6 -0
  31. package/dist/types/src/components/TextEditor/extensions/mention.d.ts.map +1 -0
  32. package/dist/types/src/components/TextEditor/extensions/table.d.ts +8 -0
  33. package/dist/types/src/components/TextEditor/extensions/table.d.ts.map +1 -0
  34. package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts +2 -4
  35. package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts.map +1 -1
  36. package/dist/types/src/components/TextEditor/themes/default.d.ts +8 -0
  37. package/dist/types/src/components/TextEditor/themes/default.d.ts.map +1 -1
  38. package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/PatchSemaphore.d.ts +3 -0
  39. package/dist/types/src/hooks/automerge/PatchSemaphore.d.ts.map +1 -0
  40. package/dist/types/src/hooks/automerge/automerge.stories.d.ts +16 -0
  41. package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +1 -0
  42. package/dist/types/src/hooks/automerge/handle.d.ts.map +1 -0
  43. package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/index.d.ts +1 -1
  44. package/dist/types/src/hooks/automerge/index.d.ts.map +1 -0
  45. package/dist/types/src/hooks/automerge/plugin.d.ts.map +1 -0
  46. package/dist/types/src/hooks/automerge/translation/automerge-to-codemirror.d.ts +5 -0
  47. package/dist/types/src/hooks/automerge/translation/automerge-to-codemirror.d.ts.map +1 -0
  48. package/dist/types/src/hooks/automerge/translation/codemirror-to-automerge.d.ts +6 -0
  49. package/dist/types/src/hooks/automerge/translation/codemirror-to-automerge.d.ts.map +1 -0
  50. package/dist/types/src/hooks/automerge/translation/index.d.ts +3 -0
  51. package/dist/types/src/hooks/automerge/translation/index.d.ts.map +1 -0
  52. package/dist/types/src/hooks/index.d.ts +0 -1
  53. package/dist/types/src/hooks/index.d.ts.map +1 -1
  54. package/dist/types/src/hooks/useTextModel.d.ts +3 -4
  55. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  56. package/dist/types/src/{components/TextEditor → hooks/yjs}/yjs.stories.d.ts +1 -1
  57. package/dist/types/src/hooks/yjs/yjs.stories.d.ts.map +1 -0
  58. package/dist/types/src/styles/markdown.d.ts +3 -2
  59. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  60. package/dist/types/src/testing/replicator.d.ts.map +1 -1
  61. package/package.json +20 -19
  62. package/src/components/TextEditor/MarkdownEditor.stories.tsx +137 -31
  63. package/src/components/TextEditor/TextEditor.tsx +52 -25
  64. package/src/components/TextEditor/extensions/autocomplete.ts +9 -22
  65. package/src/components/TextEditor/extensions/basic.ts +2 -1
  66. package/src/components/TextEditor/extensions/blast.ts +375 -0
  67. package/src/components/TextEditor/extensions/comments.ts +190 -0
  68. package/src/components/TextEditor/extensions/demo.ts +69 -0
  69. package/src/components/TextEditor/extensions/experimental.tsx +1 -0
  70. package/src/components/TextEditor/extensions/image.ts +68 -0
  71. package/src/components/TextEditor/extensions/index.ts +6 -0
  72. package/src/components/TextEditor/extensions/link.ts +25 -25
  73. package/src/components/TextEditor/extensions/listener.ts +4 -3
  74. package/src/components/TextEditor/extensions/markdown/bundle.ts +18 -18
  75. package/src/components/TextEditor/extensions/markdown/highlight.ts +118 -103
  76. package/src/components/TextEditor/extensions/mention.ts +31 -0
  77. package/src/components/TextEditor/extensions/table.ts +123 -0
  78. package/src/components/TextEditor/extensions/tasklist.ts +89 -81
  79. package/src/components/TextEditor/themes/default.ts +69 -2
  80. package/src/{automerge/automerge-plugin → hooks/automerge}/PatchSemaphore.ts +12 -9
  81. package/src/{automerge → hooks/automerge}/automerge.stories.tsx +5 -3
  82. package/src/{automerge/automerge-plugin → hooks/automerge}/plugin.ts +1 -0
  83. package/src/{automerge/automerge-plugin/amToCodemirror.ts → hooks/automerge/translation/automerge-to-codemirror.ts} +10 -2
  84. package/src/{automerge/automerge-plugin/codeMirrorToAm.ts → hooks/automerge/translation/codemirror-to-automerge.ts} +7 -4
  85. package/src/hooks/automerge/translation/index.ts +6 -0
  86. package/src/hooks/index.ts +0 -1
  87. package/src/hooks/useTextModel.ts +49 -41
  88. package/src/{components/TextEditor → hooks/yjs}/yjs.stories.tsx +1 -1
  89. package/src/styles/markdown.ts +14 -8
  90. package/src/testing/replicator.ts +6 -7
  91. package/dist/types/src/automerge/automerge-plugin/PatchSemaphore.d.ts.map +0 -1
  92. package/dist/types/src/automerge/automerge-plugin/amToCodemirror.d.ts +0 -6
  93. package/dist/types/src/automerge/automerge-plugin/amToCodemirror.d.ts.map +0 -1
  94. package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts +0 -7
  95. package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts.map +0 -1
  96. package/dist/types/src/automerge/automerge-plugin/handle.d.ts.map +0 -1
  97. package/dist/types/src/automerge/automerge-plugin/index.d.ts.map +0 -1
  98. package/dist/types/src/automerge/automerge-plugin/plugin.d.ts.map +0 -1
  99. package/dist/types/src/automerge/automerge.stories.d.ts +0 -9
  100. package/dist/types/src/automerge/automerge.stories.d.ts.map +0 -1
  101. package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
  102. package/dist/types/src/hooks/useCollaboration.d.ts +0 -9
  103. package/dist/types/src/hooks/useCollaboration.d.ts.map +0 -1
  104. package/src/hooks/useCollaboration.ts +0 -45
  105. package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/handle.d.ts +0 -0
  106. package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/plugin.d.ts +0 -0
  107. package/src/{automerge/automerge-plugin → hooks/automerge}/handle.ts +0 -0
  108. package/src/{automerge/automerge-plugin → hooks/automerge}/index.ts +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../src/hooks/automerge/plugin.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,SAAS,EAEd,WAAW,EACX,UAAU,EACV,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,KAAK,SAAS,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAGlE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,MAAM,MAAM,KAAK,GAAG;IAClB,SAAS,EAAE,KAAK,CAAC;IACjB,IAAI,EAAE,IAAI,EAAE,CAAC;IACb,wBAAwB,EAAE,WAAW,EAAE,CAAC;CACzC,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,QAAQ,EAAE,KAAK,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,UAAU,0DAAsC,CAAC;AAE9D,eAAO,MAAM,WAAW,sCAAsB,YAAY,WAAW,CAAgC,CAAC;AAEtG,eAAO,MAAM,YAAY,UAAW,WAAW,uCAAsD,CAAC;AAEtG,eAAO,MAAM,OAAO,UAAW,WAAW,mBAAiB,IAAI,EAA6B,CAAC;AAE7F,MAAM,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;AAMtC,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,eAAe,WAAY,UAAU,QAAQ,IAAI,EAAE,KAAG,eA+DlE,CAAC;AAEF,eAAO,MAAM,uBAAuB,qDAA+B,CAAC;AAEpE,eAAO,MAAM,aAAa,OAAQ,WAAW,KAAG,OAAmD,CAAC;AAEpG,eAAO,MAAM,aAAa,OAAQ,eAAe,SAchD,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { type EditorSelection } from '@codemirror/state';
2
+ import { type EditorView } from '@codemirror/view';
3
+ import { type Patch, type Prop } from '@dxos/automerge/automerge';
4
+ export declare const automergeToCodemirror: (view: EditorView, selection: EditorSelection, target: Prop[], patches: Patch[]) => void;
5
+ //# sourceMappingURL=automerge-to-codemirror.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automerge-to-codemirror.d.ts","sourceRoot":"","sources":["../../../../../../src/hooks/automerge/translation/automerge-to-codemirror.ts"],"names":[],"mappings":"AAMA,OAAO,EAA8B,KAAK,eAAe,EAAoB,MAAM,mBAAmB,CAAC;AACvG,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAGL,KAAK,KAAK,EACV,KAAK,IAAI,EAGV,MAAM,2BAA2B,CAAC;AAInC,eAAO,MAAM,qBAAqB,SAC1B,UAAU,aACL,eAAe,UAClB,IAAI,EAAE,WACL,KAAK,EAAE,SAkBjB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { type EditorState, type Transaction } from '@codemirror/state';
2
+ import { type Heads } from '@dxos/automerge/automerge';
3
+ import { type IDocHandle } from '../handle';
4
+ import { type Field } from '../plugin';
5
+ export declare const codemirrorToAutomerge: (field: Field, handle: IDocHandle, transactions: Transaction[], state: EditorState) => Heads | undefined;
6
+ //# sourceMappingURL=codemirror-to-automerge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codemirror-to-automerge.d.ts","sourceRoot":"","sources":["../../../../../../src/hooks/automerge/translation/codemirror-to-automerge.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,WAAW,EAAa,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAElF,OAAO,EAAc,KAAK,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAEnE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AAEvC,eAAO,MAAM,qBAAqB,yBAExB,UAAU,gBACJ,WAAW,EAAE,SACpB,WAAW,KACjB,KAAK,GAAG,SAyBV,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from './automerge-to-codemirror';
2
+ export * from './codemirror-to-automerge';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/hooks/automerge/translation/index.ts"],"names":[],"mappings":"AAIA,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC"}
@@ -1,4 +1,3 @@
1
- export * from './useCollaboration';
2
1
  export * from './useTextModel';
3
2
  export * from './yjs';
4
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAIA,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,OAAO,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/hooks/index.ts"],"names":[],"mappings":"AAIA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,OAAO,CAAC"}
@@ -1,16 +1,15 @@
1
+ import { type Extension } from '@codemirror/state';
1
2
  import type * as awarenessProtocol from 'y-protocols/awareness';
2
3
  import { type DocAccessor, type Space, type TextObject } from '@dxos/react-client/echo';
3
4
  import { type Identity } from '@dxos/react-client/halo';
4
5
  import type { YText, YXmlFragment } from '@dxos/text-model';
5
6
  type Awareness = awarenessProtocol.Awareness;
6
- type Provider = {
7
- awareness: Awareness;
8
- };
9
7
  export type EditorModel = {
10
8
  id: string;
11
9
  content: string | YText | YXmlFragment | DocAccessor;
12
10
  text: () => string;
13
- provider?: Provider;
11
+ extension?: Extension;
12
+ awareness?: Awareness;
14
13
  peer?: {
15
14
  id: string;
16
15
  name?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"useTextModel.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useTextModel.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,iBAAiB,MAAM,uBAAuB,CAAC;AAEhE,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,KAAK,EACV,KAAK,UAAU,EAIhB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAK5D,KAAK,SAAS,GAAG,iBAAiB,CAAC,SAAS,CAAC;AAC7C,KAAK,QAAQ,GAAG;IAAE,SAAS,EAAE,SAAS,CAAA;CAAE,CAAC;AAGzC,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,GAAG,KAAK,GAAG,YAAY,GAAG,WAAW,CAAC;IACrD,IAAI,EAAE,MAAM,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,IAAI,CAAC,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH,CAAC;AAGF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB,CAAC;AAKF,eAAO,MAAM,YAAY,8BAA+B,mBAAmB,KAAG,WAAW,GAAG,SAuD3F,CAAC"}
1
+ {"version":3,"file":"useTextModel.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useTextModel.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAInD,OAAO,KAAK,KAAK,iBAAiB,MAAM,uBAAuB,CAAC;AAGhE,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,KAAK,EACV,KAAK,UAAU,EAIhB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAM5D,KAAK,SAAS,GAAG,iBAAiB,CAAC,SAAS,CAAC;AAG7C,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IAEX,OAAO,EAAE,MAAM,GAAG,KAAK,GAAG,YAAY,GAAG,WAAW,CAAC;IACrD,IAAI,EAAE,MAAM,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,IAAI,CAAC,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH,CAAC;AAGF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB,CAAC;AAIF,eAAO,MAAM,YAAY,8BAA+B,mBAAmB,KAAG,WAAW,GAAG,SAM3F,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import '@dxosTheme';
2
2
  import React from 'react';
3
3
  declare const _default: {
4
- component: React.ForwardRefExoticComponent<import("./TextEditor").TextEditorProps & React.RefAttributes<import("./TextEditor").TextEditorRef>>;
4
+ component: React.ForwardRefExoticComponent<import("../../components").TextEditorProps & React.RefAttributes<import("../../components").TextEditorRef>>;
5
5
  decorators: import("@storybook/react").Decorator[];
6
6
  };
7
7
  export default _default;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yjs.stories.d.ts","sourceRoot":"","sources":["../../../../../src/hooks/yjs/yjs.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,YAAY,CAAC;AAEpB,OAAO,KAAmB,MAAM,OAAO,CAAC;;;;;AAWxC,wBAGE;AA+BF,eAAO,MAAM,OAAO;;;CAInB,CAAC"}
@@ -1,5 +1,6 @@
1
1
  export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
2
- export declare const heading: Record<HeadingLevel, string>;
2
+ export declare const headings: Record<HeadingLevel, string[]>;
3
+ export declare const heading: (level: HeadingLevel, readonly?: boolean) => string;
3
4
  export declare const text = "text-neutral-800 dark:text-neutral-200";
4
5
  export declare const light = "text-neutral-200 dark:text-neutral-800";
5
6
  export declare const mark: string;
@@ -12,7 +13,7 @@ export declare const codeMark = "font-mono text-primary-500";
12
13
  export declare const codeBlock = "mlb-2 font-mono bg-neutral-500/10 p-3 rounded";
13
14
  export declare const inlineUrl: string;
14
15
  export declare const blockquote: string;
15
- export declare const horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-500/50";
16
+ export declare const horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-200 dark:border-neutral-800";
16
17
  export declare const unorderedList = "mlb-2 grid grid-cols-[min-content_1fr] [&>li:before]:content-[attr(marker)] [&>li:before]:mlb-1 [&>li:before]:mie-2";
17
18
  export declare const orderedList = "mlb-2 grid grid-cols-[min-content_1fr] [&>li:before]:content-[counters(section,_\".\")_\"._\"] [counter-reset:section] [&>li:before]:mlb-1";
18
19
  export declare const listItem = "contents before:[counter-increment:section]";
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../../src/styles/markdown.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAGjD,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAOhD,CAAC;AAEF,eAAO,MAAM,IAAI,2CAA2C,CAAC;AAC7D,eAAO,MAAM,KAAK,2CAA2C,CAAC;AAE9D,eAAO,MAAM,IAAI,QAAmE,CAAC;AAErF,eAAO,MAAM,SAAS,UAAU,CAAC;AAEjC,eAAO,MAAM,IAAI,cAAc,CAAC;AAChC,eAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,eAAO,MAAM,aAAa,iBAAiB,CAAC;AAE5C,eAAO,MAAM,IAAI,mEAAmE,CAAC;AACrF,eAAO,MAAM,QAAQ,+BAA+B,CAAC;AACrD,eAAO,MAAM,SAAS,kDAAkD,CAAC;AAEzE,eAAO,MAAM,SAAS,QAAmB,CAAC;AAG1C,eAAO,MAAM,UAAU,QAAsF,CAAC;AAG9G,eAAO,MAAM,cAAc,qFAAqF,CAAC;AAGjH,eAAO,MAAM,aAAa,wHAC6F,CAAC;AACxH,eAAO,MAAM,WAAW,+IACkH,CAAC;AAE3I,eAAO,MAAM,QAAQ,gDAAgD,CAAC"}
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../../src/styles/markdown.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAGjD,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,CAOnD,CAAC;AAEF,eAAO,MAAM,OAAO,UAAW,YAAY,aAAa,OAAO,WAG9D,CAAC;AAEF,eAAO,MAAM,IAAI,2CAA2C,CAAC;AAC7D,eAAO,MAAM,KAAK,2CAA2C,CAAC;AAE9D,eAAO,MAAM,IAAI,QAAmE,CAAC;AAErF,eAAO,MAAM,SAAS,UAAU,CAAC;AAEjC,eAAO,MAAM,IAAI,cAAc,CAAC;AAChC,eAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,eAAO,MAAM,aAAa,iBAAiB,CAAC;AAE5C,eAAO,MAAM,IAAI,mEAAmE,CAAC;AACrF,eAAO,MAAM,QAAQ,+BAA+B,CAAC;AACrD,eAAO,MAAM,SAAS,kDAAkD,CAAC;AAEzE,eAAO,MAAM,SAAS,QAAmB,CAAC;AAG1C,eAAO,MAAM,UAAU,QAAsF,CAAC;AAG9G,eAAO,MAAM,cAAc,0GAC8E,CAAC;AAG1G,eAAO,MAAM,aAAa,wHAC6F,CAAC;AACxH,eAAO,MAAM,WAAW,+IACkH,CAAC;AAE3I,eAAO,MAAM,QAAQ,gDAAgD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"replicator.d.ts","sourceRoot":"","sources":["../../../../src/testing/replicator.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,KAAK,iBAAiB,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,OAAO,EAAE,QAAQ,EAAE,MAAM,4CAA4C,CAAC;AAEtE,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzD,KAAK,SAAS,GAAG,iBAAiB,CAAC,SAAS,CAAC;AAM7C;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,UAAU,CAAC,GAAG,CAAC;IACpD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAY;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAM;gBAEf,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE;QAAE,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;QAAC,GAAG,EAAE,GAAG,CAAC;QAAC,SAAS,CAAC,EAAE,SAAS,CAAA;KAAE;IA+BtG,IAAI,SAAS,IAAI,SAAS,CAEzB;IAED,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,sBAAsB;IAY9B,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,YAAY;IA0CpB,OAAO,CAAC,mBAAmB;CAG5B;AAED;;GAEG;AACH,qBAAa,UAAU;IAIT,OAAO,CAAC,QAAQ,CAAC,KAAK;IAHlC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2B;IACnD,OAAO,CAAC,MAAM,CAAqB;gBAEN,KAAK,EAAE,QAAQ;IAE5C,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE;IAI7B,UAAU,OAAQ,MAAM,QAAO,GAAG,KAAe,WAAW,CAoB1D;CACH;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,UAAU,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,GAAG,CAAC;CACX,CAAC;AAEF,eAAO,MAAM,WAAW,4BAA6B,kBAAkB,KAAG,WAGzE,CAAC"}
1
+ {"version":3,"file":"replicator.d.ts","sourceRoot":"","sources":["../../../../src/testing/replicator.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,KAAK,iBAAiB,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,OAAO,EAAE,QAAQ,EAAE,MAAM,4CAA4C,CAAC;AAEtE,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzD,KAAK,SAAS,GAAG,iBAAiB,CAAC,SAAS,CAAC;AAM7C;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,UAAU,CAAC,GAAG,CAAC;IACpD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAY;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAM;gBAEf,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE;QAAE,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;QAAC,GAAG,EAAE,GAAG,CAAC;QAAC,SAAS,CAAC,EAAE,SAAS,CAAA;KAAE;IA+BtG,IAAI,SAAS,IAAI,SAAS,CAEzB;IAED,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,sBAAsB;IAY9B,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,YAAY;IA0CpB,OAAO,CAAC,mBAAmB;CAG5B;AAED;;GAEG;AACH,qBAAa,UAAU;IAIT,OAAO,CAAC,QAAQ,CAAC,KAAK;IAHlC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2B;IACnD,OAAO,CAAC,MAAM,CAAqB;gBAEN,KAAK,EAAE,QAAQ;IAE5C,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE;IAI7B,UAAU,OAAQ,MAAM,QAAO,GAAG,KAAe,WAAW,CAoB1D;CACH;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,EAAE,UAAU,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,GAAG,CAAC;CACX,CAAC;AAEF,eAAO,MAAM,WAAW,4BAA6B,kBAAkB,KAAG,WAEzE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-editor",
3
- "version": "0.3.10-main.5515dfe",
3
+ "version": "0.3.10-main.560f82b",
4
4
  "description": "Document editing experience within a DXOS shell.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -36,18 +36,19 @@
36
36
  "y-codemirror.next": "^0.3.2",
37
37
  "y-protocols": "^1.0.5",
38
38
  "yjs": "^13.6.10",
39
- "@dxos/automerge": "0.3.10-main.5515dfe",
40
- "@dxos/debug": "0.3.10-main.5515dfe",
41
- "@dxos/display-name": "0.3.10-main.5515dfe",
42
- "@dxos/echo-schema": "0.3.10-main.5515dfe",
43
- "@dxos/invariant": "0.3.10-main.5515dfe",
44
- "@dxos/log": "0.3.10-main.5515dfe",
45
- "@dxos/react-async": "0.3.10-main.5515dfe",
46
- "@dxos/protocols": "0.3.10-main.5515dfe",
47
- "@dxos/react-ui": "0.3.10-main.5515dfe",
48
- "@dxos/react-ui-theme": "0.3.10-main.5515dfe",
49
- "@dxos/text-model": "0.3.10-main.5515dfe",
50
- "@dxos/util": "0.3.10-main.5515dfe"
39
+ "@dxos/async": "0.3.10-main.560f82b",
40
+ "@dxos/display-name": "0.3.10-main.560f82b",
41
+ "@dxos/automerge": "0.3.10-main.560f82b",
42
+ "@dxos/debug": "0.3.10-main.560f82b",
43
+ "@dxos/echo-schema": "0.3.10-main.560f82b",
44
+ "@dxos/log": "0.3.10-main.560f82b",
45
+ "@dxos/invariant": "0.3.10-main.560f82b",
46
+ "@dxos/protocols": "0.3.10-main.560f82b",
47
+ "@dxos/react-async": "0.3.10-main.560f82b",
48
+ "@dxos/react-ui-theme": "0.3.10-main.560f82b",
49
+ "@dxos/react-ui": "0.3.10-main.560f82b",
50
+ "@dxos/util": "0.3.10-main.560f82b",
51
+ "@dxos/text-model": "0.3.10-main.560f82b"
51
52
  },
52
53
  "devDependencies": {
53
54
  "@automerge/automerge-repo-network-broadcastchannel": "^1.0.19",
@@ -60,17 +61,17 @@
60
61
  "@types/react-dom": "^18.0.6",
61
62
  "react": "^18.2.0",
62
63
  "react-dom": "^18.2.0",
63
- "@dxos/config": "0.3.10-main.5515dfe",
64
- "@dxos/echo-typegen": "0.3.10-main.5515dfe",
65
- "@dxos/react-client": "0.3.10-main.5515dfe",
66
- "@dxos/react-ui": "0.3.10-main.5515dfe",
67
- "@dxos/storybook-utils": "0.3.10-main.5515dfe"
64
+ "@dxos/config": "0.3.10-main.560f82b",
65
+ "@dxos/react-client": "0.3.10-main.560f82b",
66
+ "@dxos/echo-typegen": "0.3.10-main.560f82b",
67
+ "@dxos/storybook-utils": "0.3.10-main.560f82b",
68
+ "@dxos/react-ui": "0.3.10-main.560f82b"
68
69
  },
69
70
  "peerDependencies": {
70
71
  "@phosphor-icons/react": "^2.0.5",
71
72
  "react": "^18.2.0",
72
73
  "react-dom": "^18.2.0",
73
- "@dxos/react-client": "0.3.10-main.5515dfe"
74
+ "@dxos/react-client": "0.3.10-main.560f82b"
74
75
  },
75
76
  "publishConfig": {
76
77
  "access": "public"
@@ -3,37 +3,52 @@
3
3
  //
4
4
 
5
5
  import '@dxosTheme';
6
+
6
7
  import { EditorView } from '@codemirror/view';
7
8
  import { faker } from '@faker-js/faker';
8
9
  import { ArrowSquareOut } from '@phosphor-icons/react';
10
+ import defaultsDeep from 'lodash.defaultsdeep';
9
11
  import React, { StrictMode, useRef, useState } from 'react';
10
12
  import { createRoot } from 'react-dom/client';
11
13
 
12
14
  import { TextObject } from '@dxos/echo-schema';
15
+ import { PublicKey } from '@dxos/keys';
13
16
  import { fixedInsetFlexLayout, getSize, groupSurface, mx } from '@dxos/react-ui-theme';
14
17
  import { withTheme } from '@dxos/storybook-utils';
15
18
 
16
19
  import { MarkdownEditor, type TextEditorProps, type TextEditorRef } from './TextEditor';
17
- import { autocomplete, listener, link, tasklist, tooltip, type TooltipOptions, type LinkOptions } from './extensions';
20
+ import {
21
+ autocomplete,
22
+ listener,
23
+ link,
24
+ tasklist,
25
+ tooltip,
26
+ type TooltipOptions,
27
+ type LinkOptions,
28
+ comments,
29
+ table,
30
+ image,
31
+ mention,
32
+ blast,
33
+ demo,
34
+ defaultOptions,
35
+ } from './extensions';
18
36
  import { useTextModel } from '../../hooks';
19
37
 
20
- // TODO(burdon): Read-only render mode (presentation).
21
- // TODO(burdon): Slides.
22
- // TODO(burdon): Autocomplete.
23
- // TODO(burdon): Block quote.
24
- // TODO(burdon): Images.
25
- // TODO(burdon): Tables.
26
-
27
38
  const str = (...lines: string[]) => lines.join('\n');
28
39
 
40
+ const num = () => faker.number.int({ min: 0, max: 9999 }).toLocaleString();
41
+
29
42
  // prettier-ignore
30
43
  const text = {
31
44
  tasks: str(
32
45
  '## Tasks',
33
46
  '',
34
- '- [x] parsing',
35
- '- [ ] styling',
36
- '- [ ] rendering',
47
+ '- [x] decorator',
48
+ '- [ ] checkbox',
49
+ ' - [ ] state',
50
+ ' - [ ] indent',
51
+ ' - [x] style',
37
52
  ),
38
53
 
39
54
  list: str(
@@ -65,6 +80,7 @@ const text = {
65
80
  ' const x = 100;',
66
81
  ' return () => <div>Test</div>;',
67
82
  '};',
83
+ '',
68
84
  '```'
69
85
  ),
70
86
 
@@ -80,6 +96,21 @@ const text = {
80
96
  headings: str(
81
97
  ...[1, 2, 3, 4, 5, 6].map((level) => ['#'.repeat(level) + ` Heading ${level}`, faker.lorem.sentences(), '']).flat(),
82
98
  ),
99
+
100
+ paragraphs: str(...faker.helpers.multiple(() => [faker.lorem.paragraph(), ''], { count: 3 }).flat()),
101
+
102
+ table: str(
103
+ '# Table',
104
+ '',
105
+ `| ${faker.lorem.word()} | ${faker.lorem.word()} | ${faker.lorem.word()} |`,
106
+ '|---|---|---|',
107
+ `| ${num()} | ${num()} | ${num()} |`,
108
+ `| ${num()} | ${num()} | ${num()} |`,
109
+ `| ${num()} | ${num()} | ${num()} |`,
110
+ '', // TODO(burdon): Possible GFM parsing bug if no newline?
111
+ ),
112
+
113
+ image: str('# Image', '', '![dxos](https://pbs.twimg.com/profile_banners/1268328127673044992/1684766689/1500x500)'),
83
114
  };
84
115
 
85
116
  const document = str(
@@ -89,9 +120,7 @@ const document = str(
89
120
  '',
90
121
  'This is all about https://dxos.org and related technologies.',
91
122
  '',
92
- 'This this is **bold**, __underlined__, _italic_, and `f(INLINE)`.',
93
- '',
94
- '__NOTE__: Fenced code uses the base font.',
123
+ 'This this is **bold**, ~~strikethrough~~, _italic_, and `f(INLINE)`.',
95
124
  '',
96
125
  '---',
97
126
  text.links,
@@ -105,6 +134,10 @@ const document = str(
105
134
  text.code,
106
135
  '---',
107
136
  text.headings,
137
+ '---',
138
+ text.table,
139
+ '---',
140
+ text.image,
108
141
  );
109
142
 
110
143
  const links = [
@@ -144,7 +177,7 @@ const Story = ({
144
177
  text,
145
178
  automerge,
146
179
  ...props
147
- }: { text?: string; automerge?: boolean } & Pick<TextEditorProps, 'extensions' | 'slots'>) => {
180
+ }: { text?: string; automerge?: boolean } & Pick<TextEditorProps, 'readonly' | 'extensions' | 'slots'>) => {
148
181
  const ref = useRef<TextEditorRef>(null);
149
182
  const [item] = useState({ text: new TextObject(text, undefined, undefined, { useAutomergeBackend: automerge }) });
150
183
  const model = useTextModel({ text: item.text });
@@ -171,20 +204,23 @@ export default {
171
204
  render: Story,
172
205
  };
173
206
 
207
+ const extensions = [
208
+ link({ onRender }),
209
+ tooltip({ onHover }),
210
+ tasklist(),
211
+ table(),
212
+ image(),
213
+ autocomplete({
214
+ onSearch: (text) => links.filter(({ label }) => label.toLowerCase().includes(text.toLowerCase())),
215
+ }),
216
+ ];
217
+
174
218
  export const Default = {
175
- render: () => (
176
- <Story
177
- text={document}
178
- extensions={[
179
- link({ onRender }),
180
- tooltip({ onHover }),
181
- tasklist(),
182
- autocomplete({
183
- getOptions: (text) => links.filter(({ label }) => label.toLowerCase().includes(text.toLowerCase())),
184
- }),
185
- ]}
186
- />
187
- ),
219
+ render: () => <Story text={document} extensions={extensions} />,
220
+ };
221
+
222
+ export const Readonly = {
223
+ render: () => <Story text={document} extensions={extensions} readonly />,
188
224
  };
189
225
 
190
226
  export const Simple = {
@@ -199,14 +235,26 @@ export const Links = {
199
235
  render: () => <Story text={text.links} extensions={[link({ onRender })]} />,
200
236
  };
201
237
 
238
+ export const Table = {
239
+ render: () => (
240
+ <Story text={str('This is a table', '', text.table, '', text.table, '', '')} readonly extensions={[table()]} />
241
+ ),
242
+ };
243
+
244
+ export const Image = {
245
+ render: () => <Story text={str('This is an image', '', text.image, '', '')} readonly extensions={[image()]} />,
246
+ };
247
+
202
248
  export const TaskList = {
203
249
  render: () => (
204
250
  <Story
205
251
  text={str(text.tasks, '', text.list)}
206
252
  extensions={[
207
253
  tasklist(),
208
- listener((text) => {
209
- console.log(text);
254
+ listener({
255
+ onChange: (text) => {
256
+ console.log(text);
257
+ },
210
258
  }),
211
259
  ]}
212
260
  />
@@ -220,7 +268,39 @@ export const Autocomplete = {
220
268
  extensions={[
221
269
  link({ onRender }),
222
270
  autocomplete({
223
- getOptions: (text) => links.filter(({ label }) => label.toLowerCase().includes(text.toLowerCase())),
271
+ onSearch: (text) => links.filter(({ label }) => label.toLowerCase().includes(text.toLowerCase())),
272
+ }),
273
+ ]}
274
+ />
275
+ ),
276
+ };
277
+
278
+ const names = ['adam', 'alice', 'alison', 'bob', 'carol', 'charlie', 'sayuri', 'shoko'];
279
+
280
+ export const Mention = {
281
+ render: () => (
282
+ <Story
283
+ text={str('# Mention', '', '', '', '', '', '')}
284
+ extensions={[
285
+ mention({
286
+ onSearch: (text) => names.filter((name) => name.toLowerCase().startsWith(text.toLowerCase())),
287
+ }),
288
+ ]}
289
+ />
290
+ ),
291
+ };
292
+
293
+ const mark = () => `[^${PublicKey.random().toHex()}]`;
294
+ export const Comments = {
295
+ render: () => (
296
+ <Story
297
+ text={str(mark(), '', text.paragraphs, mark(), '', mark(), '')}
298
+ extensions={[
299
+ comments({
300
+ onCreate: () => PublicKey.random().toHex(),
301
+ onUpdate: (info) => {
302
+ console.log('update', info);
303
+ },
224
304
  }),
225
305
  ]}
226
306
  />
@@ -240,3 +320,29 @@ export const Diagnostics = {
240
320
  />
241
321
  ),
242
322
  };
323
+
324
+ export const Demo = {
325
+ render: () => <Story text={text.paragraphs} extensions={[demo()]} />,
326
+ };
327
+
328
+ export const Blast = {
329
+ render: () => (
330
+ <Story
331
+ text={str(text.paragraphs, text.code, text.paragraphs)}
332
+ extensions={[
333
+ blast(
334
+ defaultsDeep(
335
+ {
336
+ effect: 2,
337
+ particleGravity: 0.2,
338
+ particleShrinkRate: 0.995,
339
+ color: () => [faker.number.int({ min: 100, max: 200 }), 0, 0],
340
+ // color: () => [faker.number.int(256), faker.number.int(256), faker.number.int(256)],
341
+ },
342
+ defaultOptions,
343
+ ),
344
+ ),
345
+ ]}
346
+ />
347
+ ),
348
+ };
@@ -16,15 +16,13 @@ import React, {
16
16
  useImperativeHandle,
17
17
  useState,
18
18
  } from 'react';
19
- import { yCollab } from 'y-codemirror.next';
20
19
 
21
20
  import { generateName } from '@dxos/display-name';
22
21
  import { useThemeContext } from '@dxos/react-ui';
23
22
  import { getColorForValue, inputSurface, mx } from '@dxos/react-ui-theme';
24
- import { type YText } from '@dxos/text-model';
25
23
 
26
- import { basicBundle, markdownBundle } from './extensions';
27
- import { defaultTheme, textTheme } from './themes';
24
+ import { basicBundle, demo, markdownBundle } from './extensions';
25
+ import { defaultTheme, markdownTheme, textTheme } from './themes';
28
26
  import { type EditorModel } from '../../hooks';
29
27
  import { type ThemeStyles } from '../../styles';
30
28
 
@@ -58,9 +56,10 @@ export type TextEditorSlots = {
58
56
 
59
57
  export type TextEditorProps = {
60
58
  model: EditorModel;
59
+ readonly?: boolean;
60
+ editorMode?: EditorMode;
61
61
  extensions?: Extension[];
62
62
  slots?: TextEditorSlots;
63
- editorMode?: EditorMode;
64
63
  };
65
64
 
66
65
  /**
@@ -68,27 +67,26 @@ export type TextEditorProps = {
68
67
  * NOTE: Rather than adding properties, try to create extensions that can be reused.
69
68
  */
70
69
  export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
71
- ({ model, extensions = [], slots = defaultSlots, editorMode }, forwardedRef) => {
70
+ ({ model, readonly, editorMode, extensions = [], slots = defaultSlots }, forwardedRef) => {
72
71
  const { themeMode } = useThemeContext();
73
72
  const tabsterDOMAttribute = useFocusableGroup({ tabBehavior: 'limited' });
74
73
 
75
- // TODO(burdon): Factor out extension (remove logic from react-ui-editor).
76
- // const collaboration = useCollaboration(model, themeMode);
77
- const { provider, peer } = model;
74
+ const [root, setRoot] = useState<HTMLDivElement | null>(null);
75
+ const [state, setState] = useState<EditorState>();
76
+ const [view, setView] = useState<EditorView>();
77
+ useImperativeHandle(forwardedRef, () => ({ root, state, view }), [view, state, root]);
78
+
79
+ // TODO(burdon): Factor out?
80
+ const { awareness, peer } = model;
78
81
  useEffect(() => {
79
- if (provider && peer) {
80
- provider.awareness.setLocalStateField('user', {
82
+ if (awareness && peer) {
83
+ awareness.setLocalStateField('user', {
81
84
  name: peer.name ?? generateName(peer.id),
82
85
  color: getColorForValue({ value: peer.id, type: 'color' }),
83
86
  colorLight: getColorForValue({ value: peer.id, themeMode, type: 'highlight' }),
84
87
  });
85
88
  }
86
- }, [provider, peer, themeMode]);
87
-
88
- const [root, setRoot] = useState<HTMLDivElement | null>(null);
89
- const [state, setState] = useState<EditorState>();
90
- const [view, setView] = useState<EditorView>();
91
- useImperativeHandle(forwardedRef, () => ({ root, state, view }), [view, state, root]);
89
+ }, [awareness, peer, themeMode]);
92
90
 
93
91
  useEffect(() => {
94
92
  if (!root) {
@@ -98,6 +96,8 @@ export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
98
96
  const state = EditorState.create({
99
97
  doc: model.text(),
100
98
  extensions: [
99
+ readonly && EditorState.readOnly.of(readonly),
100
+
101
101
  // TODO(burdon): Factor out VIM mode?
102
102
  editorMode === 'vim' && vim(),
103
103
 
@@ -108,7 +108,7 @@ export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
108
108
  EditorView.darkTheme.of(themeMode === 'dark'),
109
109
 
110
110
  // Storage and replication.
111
- yCollab(model.content as YText, model.provider?.awareness),
111
+ model.extension,
112
112
 
113
113
  // Custom.
114
114
  ...extensions,
@@ -127,7 +127,7 @@ export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
127
127
  setView(undefined);
128
128
  setState(undefined);
129
129
  };
130
- }, [root, model.content, themeMode, editorMode]);
130
+ }, [root, model, themeMode, readonly, editorMode]);
131
131
 
132
132
  const handleKeyUp = useCallback(
133
133
  (event: KeyboardEvent) => {
@@ -160,15 +160,30 @@ export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
160
160
  },
161
161
  );
162
162
 
163
- // TODO(burdon): Set default text theme?
163
+ // TODO(burdon): Allow plugins to set extensions (factory).
164
+ const maybeDebug = (): Extension => {
165
+ // TODO(burdon): Parse JSON script format (with key bindings?)
166
+ const items = localStorage.getItem('dxos.composer.demo');
167
+ if (items) {
168
+ return demo({ items: items.split(',') });
169
+ }
170
+
171
+ return [];
172
+ };
173
+
164
174
  export const TextEditor = forwardRef<TextEditorRef, TextEditorProps>(
165
- ({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
175
+ ({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
166
176
  const { themeMode } = useThemeContext();
167
177
  const slots = defaultsDeep({}, _slots, defaultTextSlots);
168
178
  return (
169
179
  <BaseTextEditor
170
180
  ref={forwardedRef}
171
- extensions={[basicBundle({ themeMode, placeholder: slots?.editor?.placeholder }), ...extensions]}
181
+ readonly={readonly}
182
+ extensions={[
183
+ basicBundle({ readonly, themeMode, placeholder: slots?.editor?.placeholder }),
184
+ maybeDebug(),
185
+ ...extensions,
186
+ ]}
172
187
  slots={slots}
173
188
  {...props}
174
189
  />
@@ -177,13 +192,18 @@ export const TextEditor = forwardRef<TextEditorRef, TextEditorProps>(
177
192
  );
178
193
 
179
194
  export const MarkdownEditor = forwardRef<TextEditorRef, TextEditorProps>(
180
- ({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
195
+ ({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
181
196
  const { themeMode } = useThemeContext();
182
- const slots = defaultsDeep({}, _slots, defaultSlots);
197
+ const slots = defaultsDeep({}, _slots, defaultMarkdownSlots);
183
198
  return (
184
199
  <BaseTextEditor
185
200
  ref={forwardedRef}
186
- extensions={[markdownBundle({ themeMode, placeholder: slots?.editor?.placeholder }), ...extensions]}
201
+ readonly={readonly}
202
+ extensions={[
203
+ markdownBundle({ readonly, themeMode, placeholder: slots?.editor?.placeholder }),
204
+ maybeDebug(),
205
+ ...extensions,
206
+ ]}
187
207
  slots={slots}
188
208
  {...props}
189
209
  />
@@ -203,3 +223,10 @@ export const defaultTextSlots: TextEditorSlots = {
203
223
  theme: textTheme,
204
224
  },
205
225
  };
226
+
227
+ export const defaultMarkdownSlots: TextEditorSlots = {
228
+ ...defaultSlots,
229
+ editor: {
230
+ theme: markdownTheme,
231
+ },
232
+ };