@dxos/react-ui-editor 0.3.10-main.dcfebef → 0.3.10-main.e38869c

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 (78) hide show
  1. package/dist/lib/browser/index.mjs +1181 -372
  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 +23 -2
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts +2 -1
  7. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  8. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +3 -0
  9. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  10. package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts.map +1 -1
  11. package/dist/types/src/components/TextEditor/extensions/basic.d.ts +2 -1
  12. package/dist/types/src/components/TextEditor/extensions/basic.d.ts.map +1 -1
  13. package/dist/types/src/components/TextEditor/extensions/blast.d.ts +25 -0
  14. package/dist/types/src/components/TextEditor/extensions/blast.d.ts.map +1 -0
  15. package/dist/types/src/components/TextEditor/extensions/code.d.ts +2 -0
  16. package/dist/types/src/components/TextEditor/extensions/code.d.ts.map +1 -0
  17. package/dist/types/src/components/TextEditor/extensions/comments.d.ts +2 -2
  18. package/dist/types/src/components/TextEditor/extensions/comments.d.ts.map +1 -1
  19. package/dist/types/src/components/TextEditor/extensions/demo.d.ts +2 -1
  20. package/dist/types/src/components/TextEditor/extensions/demo.d.ts.map +1 -1
  21. package/dist/types/src/components/TextEditor/extensions/experimental.d.ts +1 -1
  22. package/dist/types/src/components/TextEditor/extensions/experimental.d.ts.map +1 -1
  23. package/dist/types/src/components/TextEditor/extensions/highlight.d.ts +24 -0
  24. package/dist/types/src/components/TextEditor/extensions/highlight.d.ts.map +1 -0
  25. package/dist/types/src/components/TextEditor/extensions/image.d.ts +4 -0
  26. package/dist/types/src/components/TextEditor/extensions/image.d.ts.map +1 -0
  27. package/dist/types/src/components/TextEditor/extensions/index.d.ts +6 -0
  28. package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -1
  29. package/dist/types/src/components/TextEditor/extensions/link.d.ts.map +1 -1
  30. package/dist/types/src/components/TextEditor/extensions/listener.d.ts.map +1 -1
  31. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts +10 -1
  32. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +1 -1
  33. package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts +9 -3
  34. package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts.map +1 -1
  35. package/dist/types/src/components/TextEditor/extensions/mention.d.ts +6 -0
  36. package/dist/types/src/components/TextEditor/extensions/mention.d.ts.map +1 -0
  37. package/dist/types/src/components/TextEditor/extensions/table.d.ts +8 -0
  38. package/dist/types/src/components/TextEditor/extensions/table.d.ts.map +1 -0
  39. package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts +2 -1
  40. package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts.map +1 -1
  41. package/dist/types/src/components/TextEditor/themes/default.d.ts +5 -0
  42. package/dist/types/src/components/TextEditor/themes/default.d.ts.map +1 -1
  43. package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +1 -1
  44. package/dist/types/src/hooks/useTextModel.d.ts +6 -0
  45. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  46. package/dist/types/src/{components/TextEditor → hooks/yjs}/yjs.stories.d.ts +2 -2
  47. package/dist/types/src/hooks/yjs/yjs.stories.d.ts.map +1 -0
  48. package/dist/types/src/styles/markdown.d.ts +3 -2
  49. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  50. package/dist/types/src/testing/replicator.d.ts.map +1 -1
  51. package/package.json +23 -21
  52. package/src/components/TextEditor/MarkdownEditor.stories.tsx +124 -32
  53. package/src/components/TextEditor/TextEditor.stories.tsx +12 -1
  54. package/src/components/TextEditor/TextEditor.tsx +31 -24
  55. package/src/components/TextEditor/extensions/autocomplete.ts +5 -20
  56. package/src/components/TextEditor/extensions/basic.ts +6 -4
  57. package/src/components/TextEditor/extensions/blast.ts +373 -0
  58. package/src/components/TextEditor/extensions/code.ts +99 -0
  59. package/src/components/TextEditor/extensions/comments.ts +29 -46
  60. package/src/components/TextEditor/extensions/demo.ts +4 -1
  61. package/src/components/TextEditor/extensions/experimental.tsx +15 -36
  62. package/src/components/TextEditor/extensions/highlight.ts +128 -0
  63. package/src/components/TextEditor/extensions/image.ts +67 -0
  64. package/src/components/TextEditor/extensions/index.ts +6 -0
  65. package/src/components/TextEditor/extensions/link.ts +17 -25
  66. package/src/components/TextEditor/extensions/listener.ts +3 -3
  67. package/src/components/TextEditor/extensions/markdown/bundle.ts +45 -37
  68. package/src/components/TextEditor/extensions/markdown/highlight.ts +148 -108
  69. package/src/components/TextEditor/extensions/mention.ts +31 -0
  70. package/src/components/TextEditor/extensions/table.ts +119 -0
  71. package/src/components/TextEditor/extensions/tasklist.ts +42 -28
  72. package/src/components/TextEditor/themes/default.ts +98 -4
  73. package/src/hooks/automerge/automerge.stories.tsx +1 -0
  74. package/src/hooks/useTextModel.ts +9 -0
  75. package/src/{components/TextEditor → hooks/yjs}/yjs.stories.tsx +2 -2
  76. package/src/styles/markdown.ts +15 -8
  77. package/src/testing/replicator.ts +1 -0
  78. package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"default.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/themes/default.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAI3C;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE;IACzB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAyI/B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE;IACtB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAQ/B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE;IAC1B,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAM/B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE;IACtB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAQ/B,CAAC"}
1
+ {"version":3,"file":"default.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/themes/default.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAI3C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,EAAE;IACzB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAkO/B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE;IACtB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAQ/B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE;IAC1B,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAM/B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE;IACtB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAQ/B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"automerge.stories.d.ts","sourceRoot":"","sources":["../../../../../src/hooks/automerge/automerge.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,uBAAuB,CAAC;AAO/B,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAGtD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAG3C,KAAK,WAAW,GAAG;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,IAAI,EAAE,CAAC;CACd,CAAC;;;;;AA+DF,wBAGE;AAEF,eAAO,MAAM,OAAO;;CAEnB,CAAC"}
1
+ {"version":3,"file":"automerge.stories.d.ts","sourceRoot":"","sources":["../../../../../src/hooks/automerge/automerge.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,uBAAuB,CAAC;AAQ/B,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAGtD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAG3C,KAAK,WAAW,GAAG;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,IAAI,EAAE,CAAC;CACd,CAAC;;;;;AA+DF,wBAGE;AAEF,eAAO,MAAM,OAAO;;CAEnB,CAAC"}
@@ -4,10 +4,16 @@ import { type DocAccessor, type Space, type TextObject } from '@dxos/react-clien
4
4
  import { type Identity } from '@dxos/react-client/halo';
5
5
  import type { YText, YXmlFragment } from '@dxos/text-model';
6
6
  type Awareness = awarenessProtocol.Awareness;
7
+ export type DocumentRange = {
8
+ id: string;
9
+ from: number;
10
+ to: number;
11
+ };
7
12
  export type EditorModel = {
8
13
  id: string;
9
14
  content: string | YText | YXmlFragment | DocAccessor;
10
15
  text: () => string;
16
+ ranges: DocumentRange[];
11
17
  extension?: Extension;
12
18
  awareness?: Awareness;
13
19
  peer?: {
@@ -1 +1 @@
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
+ {"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;AAE7C,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAGF,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,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,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,12 +1,12 @@
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
+ title: string;
5
+ component: React.ForwardRefExoticComponent<import("../../components").TextEditorProps & React.RefAttributes<import("../../components").TextEditorRef>>;
5
6
  decorators: import("@storybook/react").Decorator[];
6
7
  };
7
8
  export default _default;
8
9
  export declare const Default: {
9
- title: string;
10
10
  render: () => JSX.Element;
11
11
  };
12
12
  //# sourceMappingURL=yjs.stories.d.ts.map
@@ -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,wBAIE;AA+BF,eAAO,MAAM,OAAO;;CAGnB,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;AAIjD,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,WAEzE,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,CAqB1D;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.dcfebef",
3
+ "version": "0.3.10-main.e38869c",
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",
@@ -23,7 +23,7 @@
23
23
  "@codemirror/state": "^6.3.3",
24
24
  "@codemirror/theme-one-dark": "^6.1.2",
25
25
  "@codemirror/view": "^6.22.2",
26
- "@fluentui/react-tabster": "^9.12.0",
26
+ "@fluentui/react-tabster": "^9.16.1",
27
27
  "@lezer/common": "^1.1.1",
28
28
  "@lezer/highlight": "^1.2.0",
29
29
  "@lezer/markdown": "^1.1.1",
@@ -32,23 +32,24 @@
32
32
  "lib0": "^0.2.65",
33
33
  "lodash.defaultsdeep": "^4.6.1",
34
34
  "lodash.get": "^4.4.2",
35
+ "lodash.sortby": "^4.7.0",
35
36
  "style-mod": "^4.1.0",
36
37
  "y-codemirror.next": "^0.3.2",
37
38
  "y-protocols": "^1.0.5",
38
39
  "yjs": "^13.6.10",
39
- "@dxos/async": "0.3.10-main.dcfebef",
40
- "@dxos/automerge": "0.3.10-main.dcfebef",
41
- "@dxos/display-name": "0.3.10-main.dcfebef",
42
- "@dxos/echo-schema": "0.3.10-main.dcfebef",
43
- "@dxos/log": "0.3.10-main.dcfebef",
44
- "@dxos/debug": "0.3.10-main.dcfebef",
45
- "@dxos/protocols": "0.3.10-main.dcfebef",
46
- "@dxos/react-async": "0.3.10-main.dcfebef",
47
- "@dxos/react-ui": "0.3.10-main.dcfebef",
48
- "@dxos/invariant": "0.3.10-main.dcfebef",
49
- "@dxos/react-ui-theme": "0.3.10-main.dcfebef",
50
- "@dxos/util": "0.3.10-main.dcfebef",
51
- "@dxos/text-model": "0.3.10-main.dcfebef"
40
+ "@dxos/async": "0.3.10-main.e38869c",
41
+ "@dxos/debug": "0.3.10-main.e38869c",
42
+ "@dxos/automerge": "0.3.10-main.e38869c",
43
+ "@dxos/invariant": "0.3.10-main.e38869c",
44
+ "@dxos/log": "0.3.10-main.e38869c",
45
+ "@dxos/display-name": "0.3.10-main.e38869c",
46
+ "@dxos/echo-schema": "0.3.10-main.e38869c",
47
+ "@dxos/protocols": "0.3.10-main.e38869c",
48
+ "@dxos/react-async": "0.3.10-main.e38869c",
49
+ "@dxos/react-ui-theme": "0.3.10-main.e38869c",
50
+ "@dxos/react-ui": "0.3.10-main.e38869c",
51
+ "@dxos/text-model": "0.3.10-main.e38869c",
52
+ "@dxos/util": "0.3.10-main.e38869c"
52
53
  },
53
54
  "devDependencies": {
54
55
  "@automerge/automerge-repo-network-broadcastchannel": "^1.0.19",
@@ -57,21 +58,22 @@
57
58
  "@preact/signals-react": "^1.3.6",
58
59
  "@types/lodash.defaultsdeep": "^4.6.6",
59
60
  "@types/lodash.get": "^4.4.7",
61
+ "@types/lodash.sortby": "^4.7.7",
60
62
  "@types/react": "^18.0.21",
61
63
  "@types/react-dom": "^18.0.6",
62
64
  "react": "^18.2.0",
63
65
  "react-dom": "^18.2.0",
64
- "@dxos/config": "0.3.10-main.dcfebef",
65
- "@dxos/echo-typegen": "0.3.10-main.dcfebef",
66
- "@dxos/react-client": "0.3.10-main.dcfebef",
67
- "@dxos/react-ui": "0.3.10-main.dcfebef",
68
- "@dxos/storybook-utils": "0.3.10-main.dcfebef"
66
+ "@dxos/config": "0.3.10-main.e38869c",
67
+ "@dxos/echo-typegen": "0.3.10-main.e38869c",
68
+ "@dxos/react-client": "0.3.10-main.e38869c",
69
+ "@dxos/react-ui": "0.3.10-main.e38869c",
70
+ "@dxos/storybook-utils": "0.3.10-main.e38869c"
69
71
  },
70
72
  "peerDependencies": {
71
73
  "@phosphor-icons/react": "^2.0.5",
72
74
  "react": "^18.2.0",
73
75
  "react-dom": "^18.2.0",
74
- "@dxos/react-client": "0.3.10-main.dcfebef"
76
+ "@dxos/react-client": "0.3.10-main.e38869c"
75
77
  },
76
78
  "publishConfig": {
77
79
  "access": "public"
@@ -3,9 +3,11 @@
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
 
@@ -24,18 +26,25 @@ import {
24
26
  type TooltipOptions,
25
27
  type LinkOptions,
26
28
  comments,
29
+ table,
30
+ image,
31
+ mention,
32
+ blast,
33
+ demo,
34
+ defaultOptions,
35
+ highlight,
36
+ code,
27
37
  } from './extensions';
28
38
  import { useTextModel } from '../../hooks';
29
39
 
30
- // TODO(burdon): Read-only render mode (presentation).
31
- // TODO(burdon): Slides.
32
- // TODO(burdon): Autocomplete.
33
- // TODO(burdon): Block quote.
34
- // TODO(burdon): Images.
35
- // TODO(burdon): Tables.
40
+ // Extensions:
41
+ // TODO(burdon): Table of contents.
42
+ // TODO(burdon): Front-matter
36
43
 
37
44
  const str = (...lines: string[]) => lines.join('\n');
38
45
 
46
+ const num = () => faker.number.int({ min: 0, max: 9999 }).toLocaleString();
47
+
39
48
  // prettier-ignore
40
49
  const text = {
41
50
  tasks: str(
@@ -75,8 +84,10 @@ const text = {
75
84
  '```tsx',
76
85
  'const Component = () => {',
77
86
  ' const x = 100;',
87
+ '',
78
88
  ' return () => <div>Test</div>;',
79
89
  '};',
90
+ '',
80
91
  '```'
81
92
  ),
82
93
 
@@ -89,11 +100,26 @@ const text = {
89
100
  '',
90
101
  ),
91
102
 
103
+ table: str(
104
+ '# Table',
105
+ '',
106
+ `| ${faker.lorem.word().padStart(8)} | ${faker.lorem.word().padStart(8)} | ${faker.lorem.word().padStart(8)} |`,
107
+ '|----------|----------|----------|',
108
+ `| ${num().padStart(8)} | ${num().padStart(8)} | ${num().padStart(8)} |`,
109
+ `| ${num().padStart(8)} | ${num().padStart(8)} | ${num().padStart(8)} |`,
110
+ `| ${num().padStart(8)} | ${num().padStart(8)} | ${num().padStart(8)} |`,
111
+ '', // TODO(burdon): Possible GFM parsing bug if no newline?
112
+ ),
113
+
114
+ image: str('# Image', '', '![dxos](https://pbs.twimg.com/profile_banners/1268328127673044992/1684766689/1500x500)'),
115
+
92
116
  headings: str(
93
117
  ...[1, 2, 3, 4, 5, 6].map((level) => ['#'.repeat(level) + ` Heading ${level}`, faker.lorem.sentences(), '']).flat(),
94
118
  ),
95
119
 
96
- paragraphs: str(...faker.helpers.multiple(() => [faker.lorem.paragraph(), ''], { count: 3 }).flat())
120
+ paragraphs: str(...faker.helpers.multiple(() => [faker.lorem.paragraph(), ''], { count: 3 }).flat()),
121
+
122
+ footer: str('', '', '', '', '')
97
123
  };
98
124
 
99
125
  const document = str(
@@ -103,9 +129,7 @@ const document = str(
103
129
  '',
104
130
  'This is all about https://dxos.org and related technologies.',
105
131
  '',
106
- 'This this is **bold**, __underlined__, _italic_, and `f(INLINE)`.',
107
- '',
108
- '__NOTE__: Fenced code uses the base font.',
132
+ 'This this is **bold**, ~~strikethrough~~, _italic_, and `f(INLINE)`.',
109
133
  '',
110
134
  '---',
111
135
  text.links,
@@ -119,6 +143,12 @@ const document = str(
119
143
  text.code,
120
144
  '---',
121
145
  text.headings,
146
+ '---',
147
+ text.table,
148
+ '---',
149
+ text.image,
150
+ '',
151
+ text.footer,
122
152
  );
123
153
 
124
154
  const links = [
@@ -154,11 +184,12 @@ const onRender: LinkOptions['onRender'] = (el, url) => {
154
184
  );
155
185
  };
156
186
 
187
+ // TODO(burdon): Pass in model.
157
188
  const Story = ({
158
189
  text,
159
190
  automerge,
160
191
  ...props
161
- }: { text?: string; automerge?: boolean } & Pick<TextEditorProps, 'extensions' | 'slots'>) => {
192
+ }: { text?: string; automerge?: boolean } & Pick<TextEditorProps, 'readonly' | 'extensions' | 'slots'>) => {
162
193
  const ref = useRef<TextEditorRef>(null);
163
194
  const [item] = useState({ text: new TextObject(text, undefined, undefined, { useAutomergeBackend: automerge }) });
164
195
  const model = useTextModel({ text: item.text });
@@ -185,38 +216,50 @@ export default {
185
216
  render: Story,
186
217
  };
187
218
 
219
+ const extensions = [
220
+ autocomplete({
221
+ onSearch: (text) => links.filter(({ label }) => label.toLowerCase().includes(text.toLowerCase())),
222
+ }),
223
+ code(),
224
+ image(),
225
+ link({ onRender }),
226
+ table(),
227
+ tasklist(),
228
+ tooltip({ onHover }),
229
+ ];
230
+
188
231
  export const Default = {
189
- render: () => (
190
- <Story
191
- text={document}
192
- extensions={[
193
- link({ onRender }),
194
- tooltip({ onHover }),
195
- tasklist(),
196
- autocomplete({
197
- onSearch: (text) => links.filter(({ label }) => label.toLowerCase().includes(text.toLowerCase())),
198
- }),
199
- ]}
200
- />
201
- ),
232
+ render: () => <Story text={document} extensions={extensions} />,
202
233
  };
203
234
 
204
- export const Simple = {
205
- render: () => <Story text={document} />,
235
+ export const Readonly = {
236
+ render: () => <Story text={document} extensions={extensions} readonly />,
206
237
  };
207
238
 
208
239
  export const Tooltips = {
209
- render: () => <Story text={text.links} extensions={[tooltip({ onHover })]} />,
240
+ render: () => <Story text={str(text.links, text.footer)} extensions={[tooltip({ onHover })]} />,
210
241
  };
211
242
 
212
243
  export const Links = {
213
- render: () => <Story text={text.links} extensions={[link({ onRender })]} />,
244
+ render: () => <Story text={str(text.links, text.footer)} extensions={[link({ onRender })]} />,
245
+ };
246
+
247
+ export const Code = {
248
+ render: () => <Story text={str(text.code, text.footer)} extensions={[code()]} readonly />,
249
+ };
250
+
251
+ export const Table = {
252
+ render: () => <Story text={str(text.table, text.footer)} extensions={[table()]} />,
253
+ };
254
+
255
+ export const Image = {
256
+ render: () => <Story text={str(text.image, text.footer)} readonly extensions={[image()]} />,
214
257
  };
215
258
 
216
259
  export const TaskList = {
217
260
  render: () => (
218
261
  <Story
219
- text={str(text.tasks, '', text.list)}
262
+ text={str(text.tasks, '', text.list, text.footer)}
220
263
  extensions={[
221
264
  tasklist(),
222
265
  listener({
@@ -232,7 +275,7 @@ export const TaskList = {
232
275
  export const Autocomplete = {
233
276
  render: () => (
234
277
  <Story
235
- text={str('# Autocomplete', '', '', '', '', '', '')}
278
+ text={str('# Autocomplete', '', 'Press CTRL-SPACE', text.footer)}
236
279
  extensions={[
237
280
  link({ onRender }),
238
281
  autocomplete({
@@ -243,18 +286,34 @@ export const Autocomplete = {
243
286
  ),
244
287
  };
245
288
 
289
+ const names = ['adam', 'alice', 'alison', 'bob', 'carol', 'charlie', 'sayuri', 'shoko'];
290
+
291
+ export const Mention = {
292
+ render: () => (
293
+ <Story
294
+ text={str('# Mention', '', 'Type @...', text.footer)}
295
+ extensions={[
296
+ mention({
297
+ onSearch: (text) => names.filter((name) => name.toLowerCase().startsWith(text.toLowerCase())),
298
+ }),
299
+ ]}
300
+ />
301
+ ),
302
+ };
303
+
246
304
  const mark = () => `[^${PublicKey.random().toHex()}]`;
247
305
  export const Comments = {
248
306
  render: () => (
249
307
  <Story
250
- text={str(mark(), '', text.paragraphs, mark(), '', mark(), '')}
308
+ text={str(text.paragraphs, mark(), '', mark(), text.footer)}
251
309
  extensions={[
252
310
  comments({
253
311
  onCreate: () => PublicKey.random().toHex(),
254
312
  onUpdate: (info) => {
255
- console.log('update', info);
313
+ // console.log('update', info);
256
314
  },
257
315
  }),
316
+ highlight(),
258
317
  ]}
259
318
  />
260
319
  ),
@@ -273,3 +332,36 @@ export const Diagnostics = {
273
332
  />
274
333
  ),
275
334
  };
335
+
336
+ export const Demo = {
337
+ render: () => <Story text={str(text.paragraphs, text.footer)} extensions={[demo()]} />,
338
+ };
339
+
340
+ export const Blast = {
341
+ render: () => (
342
+ <Story
343
+ text={str(text.paragraphs, text.code, text.paragraphs)}
344
+ extensions={[
345
+ demo({
346
+ items: localStorage.getItem('dxos.composer.extension.demo')?.split(','),
347
+ }),
348
+ blast(
349
+ defaultsDeep(
350
+ {
351
+ effect: 2,
352
+ particleGravity: 0.2,
353
+ particleShrinkRate: 0.995,
354
+ color: () => [faker.number.int({ min: 100, max: 200 }), 0, 0],
355
+ // color: () => [faker.number.int(256), faker.number.int(256), faker.number.int(256)],
356
+ },
357
+ defaultOptions,
358
+ ),
359
+ ),
360
+ ]}
361
+ />
362
+ ),
363
+ };
364
+
365
+ export const NoExtensions = {
366
+ render: () => <Story text={document} />,
367
+ };
@@ -57,6 +57,17 @@ export default {
57
57
  };
58
58
 
59
59
  export const Default = {
60
+ render: () => (
61
+ <Story
62
+ slots={defaultsDeep(
63
+ { editor: { theme: textTheme, placeholder: 'Enter text...' } } satisfies TextEditorSlots,
64
+ defaultSlots,
65
+ )}
66
+ />
67
+ ),
68
+ };
69
+
70
+ export const Text = {
60
71
  render: () => (
61
72
  <Story
62
73
  text={initialText}
@@ -71,12 +82,12 @@ export const Default = {
71
82
  export const Automerge = {
72
83
  render: () => (
73
84
  <Story
85
+ automerge
74
86
  text={initialText}
75
87
  slots={defaultsDeep(
76
88
  { editor: { theme: textTheme, placeholder: 'Enter text...' } } satisfies TextEditorSlots,
77
89
  defaultSlots,
78
90
  )}
79
- automerge
80
91
  />
81
92
  ),
82
93
  };
@@ -21,7 +21,7 @@ import { generateName } from '@dxos/display-name';
21
21
  import { useThemeContext } from '@dxos/react-ui';
22
22
  import { getColorForValue, inputSurface, mx } from '@dxos/react-ui-theme';
23
23
 
24
- import { basicBundle, demo, markdownBundle } from './extensions';
24
+ import { basicBundle, markdownBundle } from './extensions';
25
25
  import { defaultTheme, markdownTheme, textTheme } from './themes';
26
26
  import { type EditorModel } from '../../hooks';
27
27
  import { type ThemeStyles } from '../../styles';
@@ -56,9 +56,10 @@ export type TextEditorSlots = {
56
56
 
57
57
  export type TextEditorProps = {
58
58
  model: EditorModel;
59
+ readonly?: boolean;
60
+ editorMode?: EditorMode;
59
61
  extensions?: Extension[];
60
62
  slots?: TextEditorSlots;
61
- editorMode?: EditorMode;
62
63
  };
63
64
 
64
65
  /**
@@ -66,7 +67,7 @@ export type TextEditorProps = {
66
67
  * NOTE: Rather than adding properties, try to create extensions that can be reused.
67
68
  */
68
69
  export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
69
- ({ model, extensions = [], slots = defaultSlots, editorMode }, forwardedRef) => {
70
+ ({ model, readonly, editorMode, extensions = [], slots = defaultSlots }, forwardedRef) => {
70
71
  const { themeMode } = useThemeContext();
71
72
  const tabsterDOMAttribute = useFocusableGroup({ tabBehavior: 'limited' });
72
73
 
@@ -87,6 +88,12 @@ export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
87
88
  }
88
89
  }, [awareness, peer, themeMode]);
89
90
 
91
+ // TODO(burdon): Get from model.
92
+ // useHighlights(view, [
93
+ // { id: 'c-1', from: 0, to: 20 },
94
+ // { id: 'c-2', from: 100, to: 120 },
95
+ // ]);
96
+
90
97
  useEffect(() => {
91
98
  if (!root) {
92
99
  return;
@@ -95,10 +102,13 @@ export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
95
102
  const state = EditorState.create({
96
103
  doc: model.text(),
97
104
  extensions: [
105
+ readonly && EditorState.readOnly.of(readonly),
106
+
98
107
  // TODO(burdon): Factor out VIM mode?
99
108
  editorMode === 'vim' && vim(),
100
109
 
101
110
  // Theme.
111
+ // TODO(burdon): Make optional.
102
112
  EditorView.baseTheme(defaultTheme),
103
113
  EditorView.theme(slots?.editor?.theme ?? {}),
104
114
  // TODO(burdon): themeMode doesn't change in storybooks.
@@ -116,7 +126,17 @@ export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
116
126
  // If the new state is derived from the old state, it will likely not be visible other than the cursor resetting.
117
127
  // Ideally this should not be hit except when changing between text objects.
118
128
  view?.destroy();
119
- setView(new EditorView({ state, parent: root }));
129
+ setView(
130
+ new EditorView({
131
+ state,
132
+ parent: root,
133
+ // NOTE: Uncomment to spy on all transactions.
134
+ // https://codemirror.net/docs/ref/#view.EditorView.dispatch
135
+ // dispatch: (transaction, view) => {
136
+ // view.update([transaction]);
137
+ // },
138
+ }),
139
+ );
120
140
  setState(state);
121
141
 
122
142
  return () => {
@@ -124,7 +144,7 @@ export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
124
144
  setView(undefined);
125
145
  setState(undefined);
126
146
  };
127
- }, [root, model, themeMode, editorMode]);
147
+ }, [root, model, themeMode, readonly, editorMode]);
128
148
 
129
149
  const handleKeyUp = useCallback(
130
150
  (event: KeyboardEvent) => {
@@ -157,25 +177,15 @@ export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
157
177
  },
158
178
  );
159
179
 
160
- // TODO(burdon): Allow plugins to set extensions (factory).
161
- const maybeDebug = (): Extension => {
162
- // TODO(burdon): Parse JSON script format (with key bindings?)
163
- const items = localStorage.getItem('dxos.composer.demo');
164
- if (items) {
165
- return demo({ items: items.split(',') });
166
- }
167
-
168
- return [];
169
- };
170
-
171
180
  export const TextEditor = forwardRef<TextEditorRef, TextEditorProps>(
172
- ({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
181
+ ({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
173
182
  const { themeMode } = useThemeContext();
174
183
  const slots = defaultsDeep({}, _slots, defaultTextSlots);
175
184
  return (
176
185
  <BaseTextEditor
177
186
  ref={forwardedRef}
178
- extensions={[basicBundle({ themeMode, placeholder: slots?.editor?.placeholder }), maybeDebug(), ...extensions]}
187
+ readonly={readonly}
188
+ extensions={[basicBundle({ readonly, themeMode, placeholder: slots?.editor?.placeholder }), ...extensions]}
179
189
  slots={slots}
180
190
  {...props}
181
191
  />
@@ -184,17 +194,14 @@ export const TextEditor = forwardRef<TextEditorRef, TextEditorProps>(
184
194
  );
185
195
 
186
196
  export const MarkdownEditor = forwardRef<TextEditorRef, TextEditorProps>(
187
- ({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
197
+ ({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
188
198
  const { themeMode } = useThemeContext();
189
199
  const slots = defaultsDeep({}, _slots, defaultMarkdownSlots);
190
200
  return (
191
201
  <BaseTextEditor
192
202
  ref={forwardedRef}
193
- extensions={[
194
- markdownBundle({ themeMode, placeholder: slots?.editor?.placeholder }),
195
- maybeDebug(),
196
- ...extensions,
197
- ]}
203
+ readonly={readonly}
204
+ extensions={[markdownBundle({ readonly, themeMode, placeholder: slots?.editor?.placeholder }), ...extensions]}
198
205
  slots={slots}
199
206
  {...props}
200
207
  />
@@ -2,23 +2,15 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- // TODO(burdon): Automcomplete: https://codemirror.net/5/doc/manual.html#addon_runmode
6
- // TODO(burdon): Modes: parallel parsing and decoration (e.g., associated with language).
7
- // TODO(burdon): Add-on: runmode: run lexer over content (with rendering codemirror).
8
- // https://codemirror.net/5/doc/manual.html#addon_runmode
9
- // TODO(burdon): Add-on: dialog.
10
- // TODO(burdon): Comments: https://codemirror.net/5/doc/manual.html#setBookmark
11
- // TODO(burdon): Split view: https://codemirror.net/examples/split
12
-
13
5
  // https://codemirror.net/examples/autocompletion
14
6
  // https://codemirror.net/docs/ref/#autocomplete.autocompletion
15
7
  // https://codemirror.net/docs/ref/#autocomplete.Completion
16
8
 
17
9
  import {
18
10
  autocompletion,
11
+ completionKeymap,
19
12
  type Completion,
20
13
  type CompletionContext,
21
- completionKeymap,
22
14
  type CompletionResult,
23
15
  } from '@codemirror/autocomplete';
24
16
  import { keymap } from '@codemirror/view';
@@ -51,21 +43,14 @@ export const autocomplete = ({ onSearch }: AutocompleteOptions) => {
51
43
  // TODO(burdon): Optional decoration via addToOptions
52
44
  override: [
53
45
  (context: CompletionContext): CompletionResult | null => {
54
- const word = context.matchBefore(/\w*/);
55
- if (!word || (word.from === word.to && !context.explicit)) {
46
+ const match = context.matchBefore(/\w*/);
47
+ if (!match || (match.from === match.to && !context.explicit)) {
56
48
  return null;
57
49
  }
58
50
 
59
- // TODO(burdon): Option to convert to links?
60
51
  return {
61
- from: word.from,
62
- options: onSearch(word.text.toLowerCase()),
63
- // options: [
64
- // { label: 'apple', type: 'keyword' },
65
- // { label: 'amazon', type: 'keyword' },
66
- // { label: 'hello', type: 'variable', info: '(World)' },
67
- // { label: 'magic', type: 'text', apply: '⠁⭒*.✩.*⭒⠁', detail: 'macro' },
68
- // ],
52
+ from: match.from,
53
+ options: onSearch(match.text.toLowerCase()),
69
54
  };
70
55
  },
71
56
  ],