@dxos/plugin-markdown 0.6.12 → 0.6.13-main.548ca8d

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 (120) hide show
  1. package/dist/lib/browser/MarkdownContainer-52FJDCTV.mjs +467 -0
  2. package/dist/lib/browser/MarkdownContainer-52FJDCTV.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-4MPY6KRJ.mjs +50 -0
  4. package/dist/lib/browser/chunk-4MPY6KRJ.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-DRJ3FPYF.mjs +15 -0
  6. package/dist/lib/browser/chunk-DRJ3FPYF.mjs.map +7 -0
  7. package/dist/lib/browser/{chunk-CQJL4G4X.mjs → chunk-US5O2P3R.mjs} +4 -2
  8. package/dist/lib/browser/chunk-US5O2P3R.mjs.map +7 -0
  9. package/dist/lib/browser/index.mjs +77 -117
  10. package/dist/lib/browser/index.mjs.map +4 -4
  11. package/dist/lib/browser/meta.json +1 -1
  12. package/dist/lib/browser/meta.mjs +1 -1
  13. package/dist/lib/browser/types/index.mjs +6 -4
  14. package/dist/lib/node/MarkdownContainer-5XPB5VP5.cjs +482 -0
  15. package/dist/lib/node/MarkdownContainer-5XPB5VP5.cjs.map +7 -0
  16. package/dist/lib/node/chunk-MOF6UCLA.cjs +72 -0
  17. package/dist/lib/node/chunk-MOF6UCLA.cjs.map +7 -0
  18. package/dist/lib/node/{DocumentCard-EHJDDSRY.cjs → chunk-P7YU53RP.cjs} +16 -10
  19. package/dist/lib/node/chunk-P7YU53RP.cjs.map +7 -0
  20. package/dist/lib/node/{chunk-VWQH4WC2.cjs → chunk-UJMOZCIA.cjs} +11 -8
  21. package/dist/lib/node/chunk-UJMOZCIA.cjs.map +7 -0
  22. package/dist/lib/node/index.cjs +111 -147
  23. package/dist/lib/node/index.cjs.map +4 -4
  24. package/dist/lib/node/meta.cjs +3 -3
  25. package/dist/lib/node/meta.cjs.map +1 -1
  26. package/dist/lib/node/meta.json +1 -1
  27. package/dist/lib/node/types/index.cjs +8 -6
  28. package/dist/lib/node/types/index.cjs.map +2 -2
  29. package/dist/lib/node-esm/MarkdownContainer-ILCO3PDV.mjs +468 -0
  30. package/dist/lib/node-esm/MarkdownContainer-ILCO3PDV.mjs.map +7 -0
  31. package/dist/lib/node-esm/chunk-CD634NG3.mjs +51 -0
  32. package/dist/lib/node-esm/chunk-CD634NG3.mjs.map +7 -0
  33. package/dist/lib/node-esm/chunk-MIDCCMIX.mjs +42 -0
  34. package/dist/lib/node-esm/chunk-MIDCCMIX.mjs.map +7 -0
  35. package/dist/lib/node-esm/chunk-NEVN5WR6.mjs +17 -0
  36. package/dist/lib/node-esm/chunk-NEVN5WR6.mjs.map +7 -0
  37. package/dist/lib/node-esm/index.mjs +493 -0
  38. package/dist/lib/node-esm/index.mjs.map +7 -0
  39. package/dist/lib/node-esm/meta.json +1 -0
  40. package/dist/lib/node-esm/meta.mjs +10 -0
  41. package/dist/lib/node-esm/types/index.mjs +15 -0
  42. package/dist/types/src/MarkdownPlugin.d.ts.map +1 -1
  43. package/dist/types/src/components/MarkdownContainer.d.ts +15 -0
  44. package/dist/types/src/components/MarkdownContainer.d.ts.map +1 -0
  45. package/dist/types/src/components/MarkdownEditor.d.ts +8 -3
  46. package/dist/types/src/components/MarkdownEditor.d.ts.map +1 -1
  47. package/dist/types/src/components/MarkdownEditor.stories.d.ts +3 -3
  48. package/dist/types/src/components/MarkdownEditor.stories.d.ts.map +1 -1
  49. package/dist/types/src/components/index.d.ts +2 -11
  50. package/dist/types/src/components/index.d.ts.map +1 -1
  51. package/dist/types/src/extensions.d.ts +11 -15
  52. package/dist/types/src/extensions.d.ts.map +1 -1
  53. package/dist/types/src/hooks/index.d.ts +2 -0
  54. package/dist/types/src/hooks/index.d.ts.map +1 -0
  55. package/dist/types/src/hooks/useSelectCurrentThread.d.ts +6 -0
  56. package/dist/types/src/hooks/useSelectCurrentThread.d.ts.map +1 -0
  57. package/dist/types/src/meta.d.ts +4 -9
  58. package/dist/types/src/meta.d.ts.map +1 -1
  59. package/dist/types/src/types/document.d.ts +10 -1
  60. package/dist/types/src/types/document.d.ts.map +1 -1
  61. package/dist/types/src/types/types.d.ts +8 -9
  62. package/dist/types/src/types/types.d.ts.map +1 -1
  63. package/package.json +41 -36
  64. package/src/MarkdownPlugin.tsx +49 -97
  65. package/src/components/MarkdownContainer.tsx +108 -0
  66. package/src/components/MarkdownEditor.stories.tsx +11 -5
  67. package/src/components/MarkdownEditor.tsx +40 -75
  68. package/src/components/index.ts +2 -14
  69. package/src/extensions.tsx +124 -67
  70. package/src/hooks/index.ts +5 -0
  71. package/src/hooks/useSelectCurrentThread.tsx +46 -0
  72. package/src/meta.ts +15 -0
  73. package/src/types/document.ts +12 -0
  74. package/src/types/types.ts +10 -7
  75. package/dist/lib/browser/DocumentCard-2P4EICBA.mjs +0 -11
  76. package/dist/lib/browser/DocumentEditor-GPWV3VN3.mjs +0 -11
  77. package/dist/lib/browser/MarkdownEditor-EKJJQEFL.mjs +0 -10
  78. package/dist/lib/browser/MarkdownEditor-EKJJQEFL.mjs.map +0 -7
  79. package/dist/lib/browser/chunk-354DCID5.mjs +0 -117
  80. package/dist/lib/browser/chunk-354DCID5.mjs.map +0 -7
  81. package/dist/lib/browser/chunk-4GGD6YJO.mjs +0 -19
  82. package/dist/lib/browser/chunk-4GGD6YJO.mjs.map +0 -7
  83. package/dist/lib/browser/chunk-7AF2JLK4.mjs +0 -164
  84. package/dist/lib/browser/chunk-7AF2JLK4.mjs.map +0 -7
  85. package/dist/lib/browser/chunk-CQJL4G4X.mjs.map +0 -7
  86. package/dist/lib/browser/chunk-RL7QY322.mjs +0 -86
  87. package/dist/lib/browser/chunk-RL7QY322.mjs.map +0 -7
  88. package/dist/lib/browser/chunk-VUN4QKTT.mjs +0 -208
  89. package/dist/lib/browser/chunk-VUN4QKTT.mjs.map +0 -7
  90. package/dist/lib/node/DocumentCard-EHJDDSRY.cjs.map +0 -7
  91. package/dist/lib/node/DocumentEditor-I5GCRBKU.cjs +0 -29
  92. package/dist/lib/node/DocumentEditor-I5GCRBKU.cjs.map +0 -7
  93. package/dist/lib/node/MarkdownEditor-UE23H75V.cjs +0 -31
  94. package/dist/lib/node/MarkdownEditor-UE23H75V.cjs.map +0 -7
  95. package/dist/lib/node/chunk-7XIBNEI7.cjs +0 -238
  96. package/dist/lib/node/chunk-7XIBNEI7.cjs.map +0 -7
  97. package/dist/lib/node/chunk-KTYIOXL5.cjs +0 -149
  98. package/dist/lib/node/chunk-KTYIOXL5.cjs.map +0 -7
  99. package/dist/lib/node/chunk-Q4ZSCBQE.cjs +0 -114
  100. package/dist/lib/node/chunk-Q4ZSCBQE.cjs.map +0 -7
  101. package/dist/lib/node/chunk-RVGN72IX.cjs +0 -189
  102. package/dist/lib/node/chunk-RVGN72IX.cjs.map +0 -7
  103. package/dist/lib/node/chunk-TGMR2CKU.cjs +0 -52
  104. package/dist/lib/node/chunk-TGMR2CKU.cjs.map +0 -7
  105. package/dist/lib/node/chunk-VWQH4WC2.cjs.map +0 -7
  106. package/dist/types/src/components/DocumentCard.d.ts +0 -16
  107. package/dist/types/src/components/DocumentCard.d.ts.map +0 -1
  108. package/dist/types/src/components/DocumentEditor.d.ts +0 -14
  109. package/dist/types/src/components/DocumentEditor.d.ts.map +0 -1
  110. package/dist/types/src/components/HeadingMenu.d.ts +0 -13
  111. package/dist/types/src/components/HeadingMenu.d.ts.map +0 -1
  112. package/dist/types/src/components/Layout.d.ts +0 -6
  113. package/dist/types/src/components/Layout.d.ts.map +0 -1
  114. package/src/components/DocumentCard.tsx +0 -107
  115. package/src/components/DocumentEditor.tsx +0 -137
  116. package/src/components/HeadingMenu.tsx +0 -46
  117. package/src/components/Layout.tsx +0 -27
  118. package/src/meta.tsx +0 -19
  119. /package/dist/lib/{browser/DocumentCard-2P4EICBA.mjs.map → node-esm/meta.mjs.map} +0 -0
  120. /package/dist/lib/{browser/DocumentEditor-GPWV3VN3.mjs.map → node-esm/types/index.mjs.map} +0 -0
@@ -2,63 +2,117 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { ArrowSquareDown, ArrowSquareOut, type Icon } from '@phosphor-icons/react';
6
- import React, { type AnchorHTMLAttributes, StrictMode } from 'react';
5
+ import React, { type AnchorHTMLAttributes, type ReactNode, useMemo } from 'react';
7
6
  import { createRoot } from 'react-dom/client';
8
7
 
9
- import { type IntentDispatcher, NavigationAction } from '@dxos/app-framework';
8
+ import { type IntentDispatcher, NavigationAction, useIntentDispatcher } from '@dxos/app-framework';
10
9
  import { invariant } from '@dxos/invariant';
11
- import { fullyQualifiedId, type Query } from '@dxos/react-client/echo';
10
+ import { createDocAccessor, fullyQualifiedId, getSpace, type Query } from '@dxos/react-client/echo';
11
+ import { useIdentity } from '@dxos/react-client/halo';
12
+ import { Icon, ThemeProvider } from '@dxos/react-ui';
13
+ import { createDataExtensions, listener, localStorageStateStoreAdapter, state } from '@dxos/react-ui-editor';
12
14
  import {
13
15
  type AutocompleteResult,
14
- type Extension,
15
16
  type EditorViewMode,
17
+ type Extension,
18
+ InputModeExtensions,
16
19
  autocomplete,
17
20
  decorateMarkdown,
21
+ folding,
22
+ formattingKeymap,
18
23
  linkTooltip,
19
24
  typewriter,
20
- formattingKeymap,
21
- InputModeExtensions,
22
- folding,
23
25
  } from '@dxos/react-ui-editor';
24
- import { getSize, mx } from '@dxos/react-ui-theme';
25
- import { isNotFalsy, nonNullable } from '@dxos/util';
26
+ import { defaultTx } from '@dxos/react-ui-theme';
27
+ import { isNotFalsy } from '@dxos/util';
26
28
 
27
- import { type DocumentType, type MarkdownSettingsProps } from './types';
29
+ import { type DocumentType, type MarkdownPluginState, type MarkdownSettingsProps } from './types';
30
+ import { setFallbackName } from './util';
28
31
 
29
- export type ExtensionsOptions = {
30
- viewMode?: EditorViewMode;
31
- settings?: MarkdownSettingsProps;
32
- document?: DocumentType;
33
- debug?: boolean;
34
- experimental?: boolean;
35
- numberedHeadings?: boolean;
36
- folding?: boolean;
37
- query?: Query<DocumentType>;
32
+ type ExtensionsOptions = {
33
+ document: DocumentType;
38
34
  dispatch?: IntentDispatcher;
35
+ query?: Query<DocumentType>;
36
+ settings: MarkdownSettingsProps;
37
+ viewMode?: EditorViewMode;
39
38
  };
40
39
 
41
- /**
42
- * Create extension instances for editor.
43
- */
44
- export const createBaseExtensions = ({
45
- viewMode,
46
- settings,
40
+ // TODO(burdon): Merge with createBaseExtensions above.
41
+ export const useExtensions = ({
42
+ extensionProviders,
47
43
  document,
48
- query,
49
- dispatch,
50
- }: ExtensionsOptions): Extension[] => {
51
- const extensions: Extension[] = [];
44
+ settings,
45
+ viewMode,
46
+ }: Pick<ExtensionsOptions, 'document' | 'settings' | 'viewMode'> &
47
+ Pick<MarkdownPluginState, 'extensionProviders'>): Extension[] => {
48
+ const dispatch = useIntentDispatcher();
49
+ const identity = useIdentity();
50
+ const space = getSpace(document);
51
+
52
+ // TODO(wittjosiah): Autocomplete is not working and this query is causing performance issues.
53
+ // TODO(burdon): Unsubscribe.
54
+ // const query = space?.db.query(Filter.schema(DocumentType));
55
+ // query?.subscribe();
56
+ const baseExtensions = useMemo(
57
+ () =>
58
+ createBaseExtensions({
59
+ document,
60
+ settings,
61
+ viewMode,
62
+ dispatch,
63
+ // query,
64
+ }),
65
+ [document, viewMode, dispatch, settings, settings.folding, settings.numberedHeadings],
66
+ );
52
67
 
53
68
  //
54
- // Editor mode.
69
+ // External extensions from other plugins.
55
70
  //
56
- if (settings?.editorInputMode) {
57
- const extension = InputModeExtensions[settings.editorInputMode];
58
- if (extension) {
59
- extensions.push(extension);
60
- }
61
- }
71
+ const pluginExtensions = useMemo<Extension[] | undefined>(
72
+ () =>
73
+ extensionProviders?.reduce((acc: Extension[], provider) => {
74
+ const extension = typeof provider === 'function' ? provider({ document }) : provider;
75
+ if (extension) {
76
+ acc.push(extension);
77
+ }
78
+
79
+ return acc;
80
+ }, []),
81
+ [extensionProviders],
82
+ );
83
+
84
+ //
85
+ // Basic plugins.
86
+ //
87
+ return useMemo<Extension[]>(
88
+ () =>
89
+ [
90
+ // NOTE: Data extensions must be first so that automerge is updated before other extensions compute their state.
91
+ createDataExtensions({
92
+ id: document.id,
93
+ text: document.content && createDocAccessor(document.content, ['content']),
94
+ space,
95
+ identity,
96
+ }),
97
+ state(localStorageStateStoreAdapter),
98
+ listener({
99
+ onChange: (text) => setFallbackName(document, text),
100
+ }),
101
+ baseExtensions,
102
+ pluginExtensions,
103
+ ].filter(isNotFalsy),
104
+ [baseExtensions, pluginExtensions, document, document.content, space, identity],
105
+ );
106
+ };
107
+
108
+ /**
109
+ * Create extension instances for editor.
110
+ */
111
+ const createBaseExtensions = ({ document, dispatch, settings, query, viewMode }: ExtensionsOptions): Extension[] => {
112
+ const extensions: Extension[] = [
113
+ settings.editorInputMode && InputModeExtensions[settings.editorInputMode],
114
+ settings.folding && folding(),
115
+ ].filter(isNotFalsy);
62
116
 
63
117
  //
64
118
  // Markdown
@@ -69,7 +123,7 @@ export const createBaseExtensions = ({
69
123
  formattingKeymap(),
70
124
  decorateMarkdown({
71
125
  selectionChangeDelay: 100,
72
- numberedHeadings: settings?.numberedHeadings ? { from: 2 } : undefined,
126
+ numberedHeadings: settings.numberedHeadings ? { from: 2 } : undefined,
73
127
  // TODO(wittjosiah): For internal links, consider ignoring the link text and rendering the label of the object being linked to.
74
128
  renderLinkButton:
75
129
  dispatch && document
@@ -98,7 +152,6 @@ export const createBaseExtensions = ({
98
152
  extensions.push(
99
153
  autocomplete({
100
154
  onSearch: (text: string) => {
101
- // TODO query
102
155
  // TODO(burdon): Specify filter (e.g., stack).
103
156
  return query.objects
104
157
  .map<AutocompleteResult | undefined>((object) =>
@@ -110,29 +163,27 @@ export const createBaseExtensions = ({
110
163
  }
111
164
  : undefined,
112
165
  )
113
- .filter(nonNullable);
166
+ .filter(isNotFalsy);
114
167
  },
115
168
  }),
116
169
  );
117
170
  }
118
171
 
119
- extensions.push(
120
- ...[
121
- //
122
- settings?.folding && folding(),
123
- ].filter(isNotFalsy),
124
- );
125
-
126
- if (settings?.debug) {
127
- const items = settings.typewriter ?? '';
128
- extensions.push(...[items ? typewriter({ items: items.split(/[,\n]/) }) : undefined].filter(nonNullable));
172
+ if (settings.debug) {
173
+ const items = settings.typewriter?.split(/[,\n]/) ?? '';
174
+ if (items) {
175
+ extensions.push(typewriter({ items }));
176
+ }
129
177
  }
130
178
 
131
179
  return extensions;
132
180
  };
133
181
 
134
- // TODO(burdon): Factor out style.
135
- const hover = 'rounded-sm text-primary-600 hover:text-primary-500 dark:text-primary-300 hover:dark:text-primary-200';
182
+ // TODO(burdon): Factor out styles.
183
+ const style = {
184
+ hover: 'rounded-sm text-primary-500 hover:text-primary-600 dark:text-primary-500 hover:dark:text-primary-400',
185
+ icon: 'inline-block leading-none mis-1 cursor-pointer',
186
+ };
136
187
 
137
188
  const onRenderLink = (onSelectObject: (id: string) => void) => (el: Element, url: string) => {
138
189
  // TODO(burdon): Formalize/document internal link format.
@@ -155,25 +206,31 @@ const onRenderLink = (onSelectObject: (id: string) => void) => (el: Element, url
155
206
  target: '_blank',
156
207
  };
157
208
 
158
- const LinkIcon: Icon = isInternal ? ArrowSquareDown : ArrowSquareOut;
159
-
160
- createRoot(el).render(
161
- <StrictMode>
162
- <a {...options} className={hover}>
163
- <LinkIcon weight='bold' className={mx(getSize(4), 'inline-block leading-none mis-1 cursor-pointer')} />
164
- </a>
165
- </StrictMode>,
209
+ renderRoot(
210
+ el,
211
+ <a {...options} className={style.hover}>
212
+ <Icon
213
+ icon={isInternal ? 'ph--arrow-square-down--bold' : 'ph--arrow-square-out--bold'}
214
+ size={4}
215
+ classNames={style.icon}
216
+ />
217
+ </a>,
166
218
  );
167
219
  };
168
220
 
169
221
  const renderLinkTooltip = (el: Element, url: string) => {
170
222
  const web = new URL(url);
171
- createRoot(el).render(
172
- <StrictMode>
173
- <a href={url} target='_blank' rel='noreferrer' className={hover}>
174
- {web.origin}
175
- <ArrowSquareOut weight='bold' className={mx(getSize(4), 'inline-block leading-none mis-1 cursor-pointer')} />
176
- </a>
177
- </StrictMode>,
223
+ renderRoot(
224
+ el,
225
+ <a href={url} rel='noreferrer' target='_blank' className={style.hover}>
226
+ {web.origin}
227
+ <Icon icon='ph--arrow-square-out--bold' size={4} classNames={style.icon} />
228
+ </a>,
178
229
  );
179
230
  };
231
+
232
+ // TODO(burdon): Remove react rendering; use DOM directly.
233
+ export const renderRoot = <T extends Element>(root: T, node: ReactNode): T => {
234
+ createRoot(root).render(<ThemeProvider tx={defaultTx}>{node}</ThemeProvider>);
235
+ return root;
236
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './useSelectCurrentThread';
@@ -0,0 +1,46 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { EditorView } from '@codemirror/view';
6
+ import { useCallback } from 'react';
7
+
8
+ import { LayoutAction, useIntentResolver } from '@dxos/app-framework';
9
+ import { Cursor, setSelection } from '@dxos/react-ui-editor';
10
+
11
+ import { MARKDOWN_PLUGIN } from '../meta';
12
+
13
+ /**
14
+ * Handle scrolling and selection of the current thread in a markdown editor.
15
+ */
16
+ export const useSelectCurrentThread = (editorView: EditorView | undefined, documentId: string) => {
17
+ const handleScrollIntoView = useCallback(
18
+ ({ action, data }: { action: string; data?: any }) => {
19
+ if (action === LayoutAction.SCROLL_INTO_VIEW) {
20
+ if (editorView && data?.id === documentId && data?.cursor) {
21
+ // TODO(burdon): We need typed intents.
22
+ const range = Cursor.getRangeFromCursor(editorView.state, data.cursor);
23
+ if (range) {
24
+ const selection = editorView.state.selection.main.from !== range.from ? { anchor: range.from } : undefined;
25
+ const effects = [
26
+ // NOTE: This does not use the DOM scrollIntoView function.
27
+ EditorView.scrollIntoView(range.from, { y: 'start', yMargin: 96 }),
28
+ ];
29
+ if (selection) {
30
+ // Update the editor selection to get bi-directional highlighting.
31
+ effects.push(setSelection.of({ current: documentId }));
32
+ }
33
+
34
+ editorView.dispatch({
35
+ effects,
36
+ selection: selection ? { anchor: range.from } : undefined,
37
+ });
38
+ }
39
+ }
40
+ }
41
+ },
42
+ [documentId, editorView],
43
+ );
44
+
45
+ useIntentResolver(MARKDOWN_PLUGIN, handleScrollIntoView);
46
+ };
package/src/meta.ts ADDED
@@ -0,0 +1,15 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type PluginMeta } from '@dxos/app-framework';
6
+
7
+ export const MARKDOWN_PLUGIN = 'dxos.org/plugin/markdown';
8
+
9
+ export default {
10
+ id: MARKDOWN_PLUGIN,
11
+ name: 'Markdown Editor',
12
+ description: 'Text editor supporting extended Markdown.',
13
+ homePage: 'https://github.com/dxos/dxos/tree/main/packages/apps/plugins/plugin-markdown',
14
+ icon: 'ph--text-aa--regular',
15
+ } satisfies PluginMeta;
@@ -15,3 +15,15 @@ export class DocumentType extends TypedObject({ typename: 'dxos.org/type/Documen
15
15
  content: ref(TextType),
16
16
  threads: S.mutable(S.Array(ref(ThreadType))),
17
17
  }) {}
18
+
19
+ /**
20
+ * Checks if an object conforms to the interface needed to render an editor.
21
+ */
22
+ // TODO(burdon): Normalize types (from FilesPlugin).
23
+ export const isEditorModel = (data: any): data is { id: string; text: string } =>
24
+ data &&
25
+ typeof data === 'object' &&
26
+ 'id' in data &&
27
+ typeof data.id === 'string' &&
28
+ 'text' in data &&
29
+ typeof data.text === 'string';
@@ -12,6 +12,7 @@ import type {
12
12
  TranslationsProvides,
13
13
  } from '@dxos/app-framework';
14
14
  import { type SchemaProvides } from '@dxos/plugin-client';
15
+ import { type SpaceInitProvides } from '@dxos/plugin-space';
15
16
  import { type Extension, type EditorInputMode, type EditorViewMode } from '@dxos/react-ui-editor';
16
17
 
17
18
  import { type DocumentType } from './document';
@@ -26,13 +27,15 @@ export enum MarkdownAction {
26
27
 
27
28
  export type MarkdownProperties = Record<string, any>;
28
29
 
29
- export type ExtensionsProvider = (props: { document?: DocumentType }) => Extension[];
30
+ // TODO(burdon): Async.
31
+ export type MarkdownExtensionProvider = (props: { document?: DocumentType }) => Extension | undefined;
30
32
 
31
33
  export type OnChange = (text: string) => void;
32
34
 
33
35
  export type MarkdownExtensionProvides = {
36
+ // TODO(burdon): Rename.
34
37
  markdown: {
35
- extensions: ExtensionsProvider;
38
+ extensions: MarkdownExtensionProvider;
36
39
  };
37
40
  };
38
41
 
@@ -45,11 +48,11 @@ type StackProvides = {
45
48
 
46
49
  export type MarkdownPluginState = {
47
50
  // Codemirror extensions provided by other plugins.
48
- extensionProviders: NonNullable<ExtensionsProvider>[];
51
+ extensionProviders?: MarkdownExtensionProvider[];
49
52
 
50
53
  // TODO(burdon): Extend view mode per document to include scroll position, etc.
51
54
  // View mode per document.
52
- viewMode: { [key: string]: EditorViewMode };
55
+ viewMode: Record<string, EditorViewMode>;
53
56
  };
54
57
 
55
58
  export type MarkdownSettingsProps = {
@@ -64,12 +67,11 @@ export type MarkdownSettingsProps = {
64
67
  folding?: boolean;
65
68
  };
66
69
 
67
- // TODO(Zan): Move this to the plugin-space plugin or another common location
68
- // when we implement comments in sheets.
70
+ // TODO(Zan): Move this to the plugin-space plugin or another common location when we implement comments in sheets.
69
71
  type ThreadProvides<T> = {
70
72
  thread: {
71
73
  predicate: (obj: any) => obj is T;
72
- createSort: (obj: T) => (anchorA: string, anchorB: string) => number;
74
+ createSort: (obj: T) => (anchorA: string | undefined, anchorB: string | undefined) => number;
73
75
  };
74
76
  };
75
77
 
@@ -81,5 +83,6 @@ export type MarkdownPluginProvides = SurfaceProvides &
81
83
  SettingsProvides<MarkdownSettingsProps> &
82
84
  TranslationsProvides &
83
85
  SchemaProvides &
86
+ SpaceInitProvides &
84
87
  StackProvides &
85
88
  ThreadProvides<DocumentType>;
@@ -1,11 +0,0 @@
1
- import {
2
- DocumentCard,
3
- DocumentCard_default
4
- } from "./chunk-RL7QY322.mjs";
5
- import "./chunk-354DCID5.mjs";
6
- import "./chunk-4GGD6YJO.mjs";
7
- export {
8
- DocumentCard,
9
- DocumentCard_default as default
10
- };
11
- //# sourceMappingURL=DocumentCard-2P4EICBA.mjs.map
@@ -1,11 +0,0 @@
1
- import {
2
- DocumentEditor_default
3
- } from "./chunk-7AF2JLK4.mjs";
4
- import "./chunk-CQJL4G4X.mjs";
5
- import "./chunk-354DCID5.mjs";
6
- import "./chunk-VUN4QKTT.mjs";
7
- import "./chunk-4GGD6YJO.mjs";
8
- export {
9
- DocumentEditor_default as default
10
- };
11
- //# sourceMappingURL=DocumentEditor-GPWV3VN3.mjs.map
@@ -1,10 +0,0 @@
1
- import {
2
- MarkdownEditor,
3
- MarkdownEditor_default
4
- } from "./chunk-VUN4QKTT.mjs";
5
- import "./chunk-4GGD6YJO.mjs";
6
- export {
7
- MarkdownEditor,
8
- MarkdownEditor_default as default
9
- };
10
- //# sourceMappingURL=MarkdownEditor-EKJJQEFL.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,117 +0,0 @@
1
- // packages/plugins/plugin-markdown/src/extensions.tsx
2
- import { ArrowSquareDown, ArrowSquareOut } from "@phosphor-icons/react";
3
- import React, { StrictMode } from "react";
4
- import { createRoot } from "react-dom/client";
5
- import { NavigationAction } from "@dxos/app-framework";
6
- import { invariant } from "@dxos/invariant";
7
- import { fullyQualifiedId } from "@dxos/react-client/echo";
8
- import { autocomplete, decorateMarkdown, linkTooltip, typewriter, formattingKeymap, InputModeExtensions, folding } from "@dxos/react-ui-editor";
9
- import { getSize, mx } from "@dxos/react-ui-theme";
10
- import { isNotFalsy, nonNullable } from "@dxos/util";
11
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/plugins/plugin-markdown/src/extensions.tsx";
12
- var createBaseExtensions = ({ viewMode, settings, document, query, dispatch }) => {
13
- const extensions = [];
14
- if (settings?.editorInputMode) {
15
- const extension = InputModeExtensions[settings.editorInputMode];
16
- if (extension) {
17
- extensions.push(extension);
18
- }
19
- }
20
- if (viewMode !== "source") {
21
- extensions.push(...[
22
- formattingKeymap(),
23
- decorateMarkdown({
24
- selectionChangeDelay: 100,
25
- numberedHeadings: settings?.numberedHeadings ? {
26
- from: 2
27
- } : void 0,
28
- // TODO(wittjosiah): For internal links, consider ignoring the link text and rendering the label of the object being linked to.
29
- renderLinkButton: dispatch && document ? onRenderLink((id) => {
30
- void dispatch({
31
- action: NavigationAction.ADD_TO_ACTIVE,
32
- data: {
33
- id,
34
- part: "main",
35
- pivotId: fullyQualifiedId(document),
36
- scrollIntoView: true
37
- }
38
- });
39
- }) : void 0
40
- }),
41
- linkTooltip(renderLinkTooltip)
42
- ]);
43
- }
44
- if (query) {
45
- extensions.push(autocomplete({
46
- onSearch: (text) => {
47
- return query.objects.map((object) => object.name?.length && object.id !== document?.id ? {
48
- label: object.name,
49
- // TODO(burdon): Factor out URL builder.
50
- apply: `[${object.name}](/${fullyQualifiedId(object)})`
51
- } : void 0).filter(nonNullable);
52
- }
53
- }));
54
- }
55
- extensions.push(...[
56
- //
57
- settings?.folding && folding()
58
- ].filter(isNotFalsy));
59
- if (settings?.debug) {
60
- const items = settings.typewriter ?? "";
61
- extensions.push(...[
62
- items ? typewriter({
63
- items: items.split(/[,\n]/)
64
- }) : void 0
65
- ].filter(nonNullable));
66
- }
67
- return extensions;
68
- };
69
- var hover = "rounded-sm text-primary-600 hover:text-primary-500 dark:text-primary-300 hover:dark:text-primary-200";
70
- var onRenderLink = (onSelectObject) => (el, url) => {
71
- const isInternal = url.startsWith("/") || // TODO(wittjosiah): This should probably be parsed out on paste?
72
- url.startsWith(window.location.origin);
73
- const options = isInternal ? {
74
- onClick: () => {
75
- const qualifiedId = url.split("/").at(-1);
76
- invariant(qualifiedId, "Invalid link format.", {
77
- F: __dxlog_file,
78
- L: 148,
79
- S: void 0,
80
- A: [
81
- "qualifiedId",
82
- "'Invalid link format.'"
83
- ]
84
- });
85
- onSelectObject(qualifiedId);
86
- }
87
- } : {
88
- href: url,
89
- rel: "noreferrer",
90
- target: "_blank"
91
- };
92
- const LinkIcon = isInternal ? ArrowSquareDown : ArrowSquareOut;
93
- createRoot(el).render(/* @__PURE__ */ React.createElement(StrictMode, null, /* @__PURE__ */ React.createElement("a", {
94
- ...options,
95
- className: hover
96
- }, /* @__PURE__ */ React.createElement(LinkIcon, {
97
- weight: "bold",
98
- className: mx(getSize(4), "inline-block leading-none mis-1 cursor-pointer")
99
- }))));
100
- };
101
- var renderLinkTooltip = (el, url) => {
102
- const web = new URL(url);
103
- createRoot(el).render(/* @__PURE__ */ React.createElement(StrictMode, null, /* @__PURE__ */ React.createElement("a", {
104
- href: url,
105
- target: "_blank",
106
- rel: "noreferrer",
107
- className: hover
108
- }, web.origin, /* @__PURE__ */ React.createElement(ArrowSquareOut, {
109
- weight: "bold",
110
- className: mx(getSize(4), "inline-block leading-none mis-1 cursor-pointer")
111
- }))));
112
- };
113
-
114
- export {
115
- createBaseExtensions
116
- };
117
- //# sourceMappingURL=chunk-354DCID5.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/extensions.tsx"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { ArrowSquareDown, ArrowSquareOut, type Icon } from '@phosphor-icons/react';\nimport React, { type AnchorHTMLAttributes, StrictMode } from 'react';\nimport { createRoot } from 'react-dom/client';\n\nimport { type IntentDispatcher, NavigationAction } from '@dxos/app-framework';\nimport { invariant } from '@dxos/invariant';\nimport { fullyQualifiedId, type Query } from '@dxos/react-client/echo';\nimport {\n type AutocompleteResult,\n type Extension,\n type EditorViewMode,\n autocomplete,\n decorateMarkdown,\n linkTooltip,\n typewriter,\n formattingKeymap,\n InputModeExtensions,\n folding,\n} from '@dxos/react-ui-editor';\nimport { getSize, mx } from '@dxos/react-ui-theme';\nimport { isNotFalsy, nonNullable } from '@dxos/util';\n\nimport { type DocumentType, type MarkdownSettingsProps } from './types';\n\nexport type ExtensionsOptions = {\n viewMode?: EditorViewMode;\n settings?: MarkdownSettingsProps;\n document?: DocumentType;\n debug?: boolean;\n experimental?: boolean;\n numberedHeadings?: boolean;\n folding?: boolean;\n query?: Query<DocumentType>;\n dispatch?: IntentDispatcher;\n};\n\n/**\n * Create extension instances for editor.\n */\nexport const createBaseExtensions = ({\n viewMode,\n settings,\n document,\n query,\n dispatch,\n}: ExtensionsOptions): Extension[] => {\n const extensions: Extension[] = [];\n\n //\n // Editor mode.\n //\n if (settings?.editorInputMode) {\n const extension = InputModeExtensions[settings.editorInputMode];\n if (extension) {\n extensions.push(extension);\n }\n }\n\n //\n // Markdown\n //\n if (viewMode !== 'source') {\n extensions.push(\n ...[\n formattingKeymap(),\n decorateMarkdown({\n selectionChangeDelay: 100,\n numberedHeadings: settings?.numberedHeadings ? { from: 2 } : undefined,\n // TODO(wittjosiah): For internal links, consider ignoring the link text and rendering the label of the object being linked to.\n renderLinkButton:\n dispatch && document\n ? onRenderLink((id: string) => {\n void dispatch({\n action: NavigationAction.ADD_TO_ACTIVE,\n data: {\n id,\n part: 'main',\n pivotId: fullyQualifiedId(document),\n scrollIntoView: true,\n },\n });\n })\n : undefined,\n }),\n linkTooltip(renderLinkTooltip),\n ],\n );\n }\n\n //\n // Autocomplete object links.\n //\n if (query) {\n extensions.push(\n autocomplete({\n onSearch: (text: string) => {\n // TODO query\n // TODO(burdon): Specify filter (e.g., stack).\n return query.objects\n .map<AutocompleteResult | undefined>((object) =>\n object.name?.length && object.id !== document?.id\n ? {\n label: object.name,\n // TODO(burdon): Factor out URL builder.\n apply: `[${object.name}](/${fullyQualifiedId(object)})`,\n }\n : undefined,\n )\n .filter(nonNullable);\n },\n }),\n );\n }\n\n extensions.push(\n ...[\n //\n settings?.folding && folding(),\n ].filter(isNotFalsy),\n );\n\n if (settings?.debug) {\n const items = settings.typewriter ?? '';\n extensions.push(...[items ? typewriter({ items: items.split(/[,\\n]/) }) : undefined].filter(nonNullable));\n }\n\n return extensions;\n};\n\n// TODO(burdon): Factor out style.\nconst hover = 'rounded-sm text-primary-600 hover:text-primary-500 dark:text-primary-300 hover:dark:text-primary-200';\n\nconst onRenderLink = (onSelectObject: (id: string) => void) => (el: Element, url: string) => {\n // TODO(burdon): Formalize/document internal link format.\n const isInternal =\n url.startsWith('/') ||\n // TODO(wittjosiah): This should probably be parsed out on paste?\n url.startsWith(window.location.origin);\n\n const options: AnchorHTMLAttributes<any> = isInternal\n ? {\n onClick: () => {\n const qualifiedId = url.split('/').at(-1);\n invariant(qualifiedId, 'Invalid link format.');\n onSelectObject(qualifiedId);\n },\n }\n : {\n href: url,\n rel: 'noreferrer',\n target: '_blank',\n };\n\n const LinkIcon: Icon = isInternal ? ArrowSquareDown : ArrowSquareOut;\n\n createRoot(el).render(\n <StrictMode>\n <a {...options} className={hover}>\n <LinkIcon weight='bold' className={mx(getSize(4), 'inline-block leading-none mis-1 cursor-pointer')} />\n </a>\n </StrictMode>,\n );\n};\n\nconst renderLinkTooltip = (el: Element, url: string) => {\n const web = new URL(url);\n createRoot(el).render(\n <StrictMode>\n <a href={url} target='_blank' rel='noreferrer' className={hover}>\n {web.origin}\n <ArrowSquareOut weight='bold' className={mx(getSize(4), 'inline-block leading-none mis-1 cursor-pointer')} />\n </a>\n </StrictMode>,\n );\n};\n"],
5
- "mappings": ";AAIA,SAASA,iBAAiBC,sBAAiC;AAC3D,OAAOC,SAAoCC,kBAAkB;AAC7D,SAASC,kBAAkB;AAE3B,SAAgCC,wBAAwB;AACxD,SAASC,iBAAiB;AAC1B,SAASC,wBAAoC;AAC7C,SAIEC,cACAC,kBACAC,aACAC,YACAC,kBACAC,qBACAC,eACK;AACP,SAASC,SAASC,UAAU;AAC5B,SAASC,YAAYC,mBAAmB;;AAmBjC,IAAMC,uBAAuB,CAAC,EACnCC,UACAC,UACAC,UACAC,OACAC,SAAQ,MACU;AAClB,QAAMC,aAA0B,CAAA;AAKhC,MAAIJ,UAAUK,iBAAiB;AAC7B,UAAMC,YAAYd,oBAAoBQ,SAASK,eAAe;AAC9D,QAAIC,WAAW;AACbF,iBAAWG,KAAKD,SAAAA;IAClB;EACF;AAKA,MAAIP,aAAa,UAAU;AACzBK,eAAWG,KAAI,GACV;MACDhB,iBAAAA;MACAH,iBAAiB;QACfoB,sBAAsB;QACtBC,kBAAkBT,UAAUS,mBAAmB;UAAEC,MAAM;QAAE,IAAIC;;QAE7DC,kBACET,YAAYF,WACRY,aAAa,CAACC,OAAAA;AACZ,eAAKX,SAAS;YACZY,QAAQ/B,iBAAiBgC;YACzBC,MAAM;cACJH;cACAI,MAAM;cACNC,SAASjC,iBAAiBe,QAAAA;cAC1BmB,gBAAgB;YAClB;UACF,CAAA;QACF,CAAA,IACAT;MACR,CAAA;MACAtB,YAAYgC,iBAAAA;KACb;EAEL;AAKA,MAAInB,OAAO;AACTE,eAAWG,KACTpB,aAAa;MACXmC,UAAU,CAACC,SAAAA;AAGT,eAAOrB,MAAMsB,QACVC,IAAoC,CAACC,WACpCA,OAAOC,MAAMC,UAAUF,OAAOZ,OAAOb,UAAUa,KAC3C;UACEe,OAAOH,OAAOC;;UAEdG,OAAO,IAAIJ,OAAOC,IAAI,MAAMzC,iBAAiBwC,MAAAA,CAAAA;QAC/C,IACAf,MAAAA,EAELoB,OAAOlC,WAAAA;MACZ;IACF,CAAA,CAAA;EAEJ;AAEAO,aAAWG,KAAI,GACV;;IAEDP,UAAUP,WAAWA,QAAAA;IACrBsC,OAAOnC,UAAAA,CAAAA;AAGX,MAAII,UAAUgC,OAAO;AACnB,UAAMC,QAAQjC,SAASV,cAAc;AACrCc,eAAWG,KAAI,GAAI;MAAC0B,QAAQ3C,WAAW;QAAE2C,OAAOA,MAAMC,MAAM,OAAA;MAAS,CAAA,IAAKvB;MAAWoB,OAAOlC,WAAAA,CAAAA;EAC9F;AAEA,SAAOO;AACT;AAGA,IAAM+B,QAAQ;AAEd,IAAMtB,eAAe,CAACuB,mBAAyC,CAACC,IAAaC,QAAAA;AAE3E,QAAMC,aACJD,IAAIE,WAAW,GAAA;EAEfF,IAAIE,WAAWC,OAAOC,SAASC,MAAM;AAEvC,QAAMC,UAAqCL,aACvC;IACEM,SAAS,MAAA;AACP,YAAMC,cAAcR,IAAIJ,MAAM,GAAA,EAAKa,GAAG,EAAC;AACvC9D,gBAAU6D,aAAa,wBAAA;;;;;;;;;AACvBV,qBAAeU,WAAAA;IACjB;EACF,IACA;IACEE,MAAMV;IACNW,KAAK;IACLC,QAAQ;EACV;AAEJ,QAAMC,WAAiBZ,aAAa5D,kBAAkBC;AAEtDG,aAAWsD,EAAAA,EAAIe,OACb,sBAAA,cAACtE,YAAAA,MACC,sBAAA,cAACuE,KAAAA;IAAG,GAAGT;IAASU,WAAWnB;KACzB,sBAAA,cAACgB,UAAAA;IAASI,QAAO;IAAOD,WAAW3D,GAAGD,QAAQ,CAAA,GAAI,gDAAA;;AAI1D;AAEA,IAAM2B,oBAAoB,CAACgB,IAAaC,QAAAA;AACtC,QAAMkB,MAAM,IAAIC,IAAInB,GAAAA;AACpBvD,aAAWsD,EAAAA,EAAIe,OACb,sBAAA,cAACtE,YAAAA,MACC,sBAAA,cAACuE,KAAAA;IAAEL,MAAMV;IAAKY,QAAO;IAASD,KAAI;IAAaK,WAAWnB;KACvDqB,IAAIb,QACL,sBAAA,cAAC/D,gBAAAA;IAAe2E,QAAO;IAAOD,WAAW3D,GAAGD,QAAQ,CAAA,GAAI,gDAAA;;AAIhE;",
6
- "names": ["ArrowSquareDown", "ArrowSquareOut", "React", "StrictMode", "createRoot", "NavigationAction", "invariant", "fullyQualifiedId", "autocomplete", "decorateMarkdown", "linkTooltip", "typewriter", "formattingKeymap", "InputModeExtensions", "folding", "getSize", "mx", "isNotFalsy", "nonNullable", "createBaseExtensions", "viewMode", "settings", "document", "query", "dispatch", "extensions", "editorInputMode", "extension", "push", "selectionChangeDelay", "numberedHeadings", "from", "undefined", "renderLinkButton", "onRenderLink", "id", "action", "ADD_TO_ACTIVE", "data", "part", "pivotId", "scrollIntoView", "renderLinkTooltip", "onSearch", "text", "objects", "map", "object", "name", "length", "label", "apply", "filter", "debug", "items", "split", "hover", "onSelectObject", "el", "url", "isInternal", "startsWith", "window", "location", "origin", "options", "onClick", "qualifiedId", "at", "href", "rel", "target", "LinkIcon", "render", "a", "className", "weight", "web", "URL"]
7
- }
@@ -1,19 +0,0 @@
1
- // packages/plugins/plugin-markdown/src/meta.tsx
2
- import { TextAa } from "@phosphor-icons/react";
3
- import React from "react";
4
- import { pluginMeta } from "@dxos/app-framework";
5
- var MARKDOWN_PLUGIN = "dxos.org/plugin/markdown";
6
- var meta_default = pluginMeta({
7
- id: MARKDOWN_PLUGIN,
8
- name: "Editor",
9
- description: "Markdown text editor.",
10
- homePage: "https://github.com/dxos/dxos/tree/main/packages/apps/plugins/plugin-markdown",
11
- iconComponent: (props) => /* @__PURE__ */ React.createElement(TextAa, props),
12
- iconSymbol: "ph--text-aa--regular"
13
- });
14
-
15
- export {
16
- MARKDOWN_PLUGIN,
17
- meta_default
18
- };
19
- //# sourceMappingURL=chunk-4GGD6YJO.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/meta.tsx"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type IconProps, TextAa } from '@phosphor-icons/react';\nimport React from 'react';\n\nimport { pluginMeta } from '@dxos/app-framework';\n\nexport const MARKDOWN_PLUGIN = 'dxos.org/plugin/markdown';\n\nexport default pluginMeta({\n id: MARKDOWN_PLUGIN,\n name: 'Editor',\n description: 'Markdown text editor.',\n homePage: 'https://github.com/dxos/dxos/tree/main/packages/apps/plugins/plugin-markdown',\n iconComponent: (props: IconProps) => <TextAa {...props} />,\n iconSymbol: 'ph--text-aa--regular',\n});\n"],
5
- "mappings": ";AAIA,SAAyBA,cAAc;AACvC,OAAOC,WAAW;AAElB,SAASC,kBAAkB;AAEpB,IAAMC,kBAAkB;AAE/B,IAAA,eAAeC,WAAW;EACxBC,IAAIF;EACJG,MAAM;EACNC,aAAa;EACbC,UAAU;EACVC,eAAe,CAACC,UAAqB,sBAAA,cAACC,QAAWD,KAAAA;EACjDE,YAAY;AACd,CAAA;",
6
- "names": ["TextAa", "React", "pluginMeta", "MARKDOWN_PLUGIN", "pluginMeta", "id", "name", "description", "homePage", "iconComponent", "props", "TextAa", "iconSymbol"]
7
- }