@dxos/plugin-markdown 0.9.0 → 0.9.1-staging.ee54ba693a
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.
- package/dist/lib/neutral/{MarkdownArticle-LWT5RFFJ.mjs → MarkdownArticle-ZHBXH7YF.mjs} +5 -7
- package/dist/lib/neutral/MarkdownArticle-ZHBXH7YF.mjs.map +7 -0
- package/dist/lib/neutral/{MarkdownCard-TBLIRDBO.mjs → MarkdownCard-2HUXCGZP.mjs} +3 -3
- package/dist/lib/neutral/MarkdownCard-2HUXCGZP.mjs.map +7 -0
- package/dist/lib/neutral/MarkdownPlugin.mjs +8 -15
- package/dist/lib/neutral/MarkdownPlugin.mjs.map +3 -3
- package/dist/lib/neutral/MarkdownPlugin.node.mjs +4 -2
- package/dist/lib/neutral/MarkdownPlugin.node.mjs.map +3 -3
- package/dist/lib/neutral/MarkdownPlugin.workerd.mjs +6 -17
- package/dist/lib/neutral/MarkdownPlugin.workerd.mjs.map +4 -4
- package/dist/lib/neutral/MarkdownSettings-5VMOYMND.mjs +43 -0
- package/dist/lib/neutral/MarkdownSettings-5VMOYMND.mjs.map +7 -0
- package/dist/lib/neutral/{anchor-sort-UXN4RHFX.mjs → anchor-sort-QF7UDG2A.mjs} +4 -3
- package/dist/lib/neutral/anchor-sort-QF7UDG2A.mjs.map +7 -0
- package/dist/lib/neutral/capabilities/index.mjs +10 -16
- package/dist/lib/neutral/capabilities/index.mjs.map +3 -3
- package/dist/lib/neutral/capabilities/node.mjs +5 -3
- package/dist/lib/neutral/capabilities/node.mjs.map +3 -3
- package/dist/lib/neutral/chunk-2V6A5NDQ.mjs +8 -0
- package/dist/lib/neutral/{operation-handler-2ARMPBGZ.mjs → chunk-ANHHOTCD.mjs} +3 -4
- package/dist/lib/neutral/{operation-handler-2ARMPBGZ.mjs.map → chunk-ANHHOTCD.mjs.map} +1 -1
- package/dist/lib/neutral/chunk-CNYFGIDS.mjs +32 -0
- package/dist/lib/neutral/chunk-CNYFGIDS.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-LXNSKCPD.mjs → chunk-EV4ZOL4P.mjs} +12 -11
- package/dist/lib/neutral/chunk-EV4ZOL4P.mjs.map +7 -0
- package/dist/lib/neutral/chunk-OC3JD73N.mjs +43 -0
- package/dist/lib/neutral/chunk-OC3JD73N.mjs.map +7 -0
- package/dist/lib/neutral/chunk-YJF6XOXX.mjs +175 -0
- package/dist/lib/neutral/chunk-YJF6XOXX.mjs.map +7 -0
- package/dist/lib/neutral/chunk-YMBC62S7.mjs +14 -0
- package/dist/lib/neutral/chunk-YMBC62S7.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-Y2LQRUU7.mjs → chunk-ZJ3GWRUJ.mjs} +24 -23
- package/dist/lib/neutral/chunk-ZJ3GWRUJ.mjs.map +7 -0
- package/dist/lib/neutral/{comment-config-EGY7RPPW.mjs → comment-config-M5OGFULS.mjs} +6 -4
- package/dist/lib/neutral/comment-config-M5OGFULS.mjs.map +7 -0
- package/dist/lib/neutral/components/index.mjs +19 -57
- package/dist/lib/neutral/components/index.mjs.map +4 -4
- package/dist/lib/neutral/containers/index.mjs +5 -3
- package/dist/lib/neutral/containers/index.mjs.map +3 -3
- package/dist/lib/neutral/{create-JK35XC4R.mjs → create-OQUMKL5I.mjs} +2 -2
- package/dist/lib/neutral/{create-markdown-7MLE625M.mjs → create-markdown-4O5FDA77.mjs} +2 -2
- package/dist/lib/neutral/{create-object-MU2LGXG6.mjs → create-object-RSEWTCMM.mjs} +2 -6
- package/dist/lib/neutral/create-object-RSEWTCMM.mjs.map +7 -0
- package/dist/lib/neutral/hooks/index.mjs +53 -23
- package/dist/lib/neutral/hooks/index.mjs.map +3 -3
- package/dist/lib/neutral/index.mjs +10 -16
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/lib/neutral/meta.mjs +1 -1
- package/dist/lib/neutral/{open-5YC77C4O.mjs → open-BAZIRXII.mjs} +2 -2
- package/dist/lib/neutral/operation-handler-SDCXGMGK.mjs +8 -0
- package/dist/lib/neutral/operations/index.mjs +1 -1
- package/dist/lib/neutral/plugin.mjs +2 -2
- package/dist/lib/neutral/plugin.workerd.mjs +12 -0
- package/dist/lib/neutral/plugin.workerd.mjs.map +7 -0
- package/dist/lib/neutral/{react-surface-XYZJBKHZ.mjs → react-surface-37GL3UVG.mjs} +10 -15
- package/dist/lib/neutral/react-surface-37GL3UVG.mjs.map +7 -0
- package/dist/lib/neutral/{scroll-to-anchor-GAFB7W55.mjs → scroll-to-anchor-I6HFE5AH.mjs} +2 -2
- package/dist/lib/neutral/{set-view-mode-N7UHYMPG.mjs → set-view-mode-NY5OYYIM.mjs} +2 -2
- package/dist/lib/neutral/{settings-TDGDLCUR.mjs → settings-O6O6HT3I.mjs} +3 -3
- package/dist/lib/neutral/settings-O6O6HT3I.mjs.map +7 -0
- package/dist/lib/neutral/skill-definition-ET7BYY47.mjs +8 -0
- package/dist/lib/neutral/skill-definition-ET7BYY47.mjs.map +7 -0
- package/dist/lib/neutral/skills/index.mjs +8 -0
- package/dist/lib/neutral/skills/index.mjs.map +7 -0
- package/dist/lib/neutral/state-3BR7L6CW.mjs +69 -0
- package/dist/lib/neutral/state-3BR7L6CW.mjs.map +7 -0
- package/dist/lib/neutral/testing.mjs +2 -2
- package/dist/lib/neutral/testing.mjs.map +3 -3
- package/dist/lib/neutral/translations.mjs +1 -1
- package/dist/lib/neutral/translations.mjs.map +3 -3
- package/dist/lib/neutral/types/index.mjs +1 -1
- package/dist/lib/neutral/update-markdown-M4PTA6VS.mjs +24 -0
- package/dist/lib/neutral/update-markdown-M4PTA6VS.mjs.map +7 -0
- package/dist/types/dx.config.d.ts +28 -0
- package/dist/types/dx.config.d.ts.map +1 -0
- package/dist/types/src/MarkdownPlugin.d.ts.map +1 -1
- package/dist/types/src/MarkdownPlugin.node.d.ts.map +1 -1
- package/dist/types/src/MarkdownPlugin.workerd.d.ts.map +1 -1
- package/dist/types/src/capabilities/anchor-sort.d.ts +1 -2
- package/dist/types/src/capabilities/anchor-sort.d.ts.map +1 -1
- package/dist/types/src/capabilities/comment-config.d.ts +1 -2
- package/dist/types/src/capabilities/comment-config.d.ts.map +1 -1
- package/dist/types/src/capabilities/create-object.d.ts +1 -7
- package/dist/types/src/capabilities/create-object.d.ts.map +1 -1
- package/dist/types/src/capabilities/editor-view-state.d.ts +7 -0
- package/dist/types/src/capabilities/editor-view-state.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +7 -16
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/node.d.ts +2 -6
- package/dist/types/src/capabilities/node.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +2 -2
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/settings.d.ts +1 -2
- package/dist/types/src/capabilities/settings.d.ts.map +1 -1
- package/dist/types/src/capabilities/skill-definition.d.ts +5 -0
- package/dist/types/src/capabilities/skill-definition.d.ts.map +1 -0
- package/dist/types/src/capabilities/state.d.ts +1 -2
- package/dist/types/src/capabilities/state.d.ts.map +1 -1
- package/dist/types/src/components/MarkdownEditor/FileUpload.d.ts +2 -2
- package/dist/types/src/components/MarkdownEditor/FileUpload.d.ts.map +1 -1
- package/dist/types/src/components/MarkdownEditor/MarkdownEditor.d.ts +5 -6
- package/dist/types/src/components/MarkdownEditor/MarkdownEditor.d.ts.map +1 -1
- package/dist/types/src/components/MarkdownEditor/MarkdownEditor.stories.d.ts +3 -2
- package/dist/types/src/components/MarkdownEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/MarkdownEditor/MarkdownEditorContent.d.ts.map +1 -1
- package/dist/types/src/components/MarkdownEditor/MarkdownEditorToolbar.d.ts +2 -2
- package/dist/types/src/components/MarkdownEditor/MarkdownEditorToolbar.d.ts.map +1 -1
- package/dist/types/src/components/PreviewComponent/PreviewComponent.d.ts +17 -0
- package/dist/types/src/components/PreviewComponent/PreviewComponent.d.ts.map +1 -0
- package/dist/types/src/components/PreviewComponent/index.d.ts +2 -0
- package/dist/types/src/components/PreviewComponent/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/MarkdownArticle/MarkdownArticle.d.ts +6 -17
- package/dist/types/src/containers/MarkdownArticle/MarkdownArticle.d.ts.map +1 -1
- package/dist/types/src/containers/MarkdownArticle/MarkdownArticle.stories.d.ts.map +1 -1
- package/dist/types/src/{components → containers}/MarkdownSettings/MarkdownSettings.d.ts +1 -1
- package/dist/types/src/{components → containers}/MarkdownSettings/MarkdownSettings.d.ts.map +1 -1
- package/dist/types/src/{components → containers}/MarkdownSettings/MarkdownSettings.stories.d.ts.map +1 -1
- package/dist/types/src/{components → containers}/MarkdownSettings/index.d.ts.map +1 -1
- package/dist/types/src/containers/index.d.ts +1 -0
- package/dist/types/src/containers/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useExtensions.d.ts +5 -5
- package/dist/types/src/hooks/useExtensions.d.ts.map +1 -1
- package/dist/types/src/hooks/useLinkQuery.d.ts +2 -2
- package/dist/types/src/hooks/useLinkQuery.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +32 -2
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/operations/update-markdown.d.ts.map +1 -1
- package/dist/types/src/plugin.workerd.d.ts +2 -0
- package/dist/types/src/plugin.workerd.d.ts.map +1 -0
- package/dist/types/src/skills/index.d.ts +2 -0
- package/dist/types/src/skills/index.d.ts.map +1 -0
- package/dist/types/src/skills/markdown-skill.d.ts +4 -0
- package/dist/types/src/skills/markdown-skill.d.ts.map +1 -0
- package/dist/types/src/types/Markdown.d.ts +12 -20
- package/dist/types/src/types/Markdown.d.ts.map +1 -1
- package/dist/types/src/types/MarkdownCapabilities.d.ts.map +1 -1
- package/dist/types/src/types/MarkdownOperation.d.ts +5 -28
- package/dist/types/src/types/MarkdownOperation.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +2 -0
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dx.config.ts +31 -0
- package/package.json +67 -59
- package/src/MarkdownPlugin.node.ts +2 -1
- package/src/MarkdownPlugin.test.ts +1 -1
- package/src/MarkdownPlugin.tsx +7 -16
- package/src/MarkdownPlugin.workerd.ts +5 -2
- package/src/capabilities/anchor-sort.ts +3 -2
- package/src/capabilities/comment-config.ts +6 -9
- package/src/capabilities/create-object.ts +1 -4
- package/src/capabilities/editor-view-state.ts +28 -0
- package/src/capabilities/index.ts +2 -16
- package/src/capabilities/node.ts +1 -0
- package/src/capabilities/react-surface.tsx +29 -13
- package/src/capabilities/settings.ts +2 -2
- package/src/capabilities/skill-definition.ts +14 -0
- package/src/capabilities/state.ts +8 -4
- package/src/components/MarkdownEditor/FileUpload.tsx +2 -2
- package/src/components/MarkdownEditor/MarkdownEditor.stories.tsx +72 -30
- package/src/components/MarkdownEditor/MarkdownEditor.tsx +14 -40
- package/src/components/MarkdownEditor/MarkdownEditorContent.tsx +7 -6
- package/src/components/MarkdownEditor/MarkdownEditorToolbar.tsx +2 -2
- package/src/components/PreviewComponent/PreviewComponent.tsx +195 -0
- package/src/components/PreviewComponent/index.ts +5 -0
- package/src/components/index.ts +1 -4
- package/src/containers/MarkdownArticle/MarkdownArticle.stories.tsx +3 -4
- package/src/containers/MarkdownArticle/MarkdownArticle.tsx +6 -6
- package/src/containers/MarkdownCard/MarkdownCard.tsx +2 -2
- package/src/{components → containers}/MarkdownSettings/MarkdownSettings.stories.tsx +1 -1
- package/src/containers/MarkdownSettings/MarkdownSettings.tsx +54 -0
- package/src/containers/index.ts +1 -0
- package/src/hooks/useEditorMenuOptions.ts +2 -2
- package/src/hooks/useExtensions.tsx +42 -22
- package/src/hooks/useLinkQuery.ts +5 -3
- package/src/index.ts +1 -2
- package/src/meta.ts +2 -22
- package/src/operations/create.conversations.json +1 -1
- package/src/operations/create.test.ts +5 -12
- package/src/operations/update-markdown.ts +7 -27
- package/src/operations/update.conversations.json +1 -1
- package/src/operations/update.test.ts +86 -16
- package/src/plugin.workerd.ts +5 -0
- package/src/skills/index.ts +5 -0
- package/src/{blueprints/markdown-blueprint.ts → skills/markdown-skill.ts} +8 -7
- package/src/testing.ts +2 -2
- package/src/translations.ts +1 -1
- package/src/types/Markdown.ts +20 -19
- package/src/types/MarkdownCapabilities.ts +7 -5
- package/src/types/MarkdownEvents.ts +1 -1
- package/src/types/MarkdownOperation.ts +12 -6
- package/src/types/types.ts +2 -7
- package/dist/lib/neutral/MarkdownArticle-LWT5RFFJ.mjs.map +0 -7
- package/dist/lib/neutral/MarkdownCard-TBLIRDBO.mjs.map +0 -7
- package/dist/lib/neutral/MarkdownSettings-YCTZJL5V.mjs +0 -32
- package/dist/lib/neutral/MarkdownSettings-YCTZJL5V.mjs.map +0 -7
- package/dist/lib/neutral/anchor-sort-UXN4RHFX.mjs.map +0 -7
- package/dist/lib/neutral/app-graph-builder-BWBA23FF.mjs +0 -67
- package/dist/lib/neutral/app-graph-builder-BWBA23FF.mjs.map +0 -7
- package/dist/lib/neutral/app-graph-serializer-EN5E3BMG.mjs +0 -56
- package/dist/lib/neutral/app-graph-serializer-EN5E3BMG.mjs.map +0 -7
- package/dist/lib/neutral/blueprint-definition-DSPXK77L.mjs +0 -15
- package/dist/lib/neutral/blueprint-definition-DSPXK77L.mjs.map +0 -7
- package/dist/lib/neutral/blueprints/index.mjs +0 -8
- package/dist/lib/neutral/chunk-36QFEVOZ.mjs +0 -30
- package/dist/lib/neutral/chunk-36QFEVOZ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-67DKWOKF.mjs +0 -10
- package/dist/lib/neutral/chunk-67DKWOKF.mjs.map +0 -7
- package/dist/lib/neutral/chunk-CIJD7P6X.mjs +0 -8
- package/dist/lib/neutral/chunk-LXNSKCPD.mjs.map +0 -7
- package/dist/lib/neutral/chunk-Y2LQRUU7.mjs.map +0 -7
- package/dist/lib/neutral/comment-config-EGY7RPPW.mjs.map +0 -7
- package/dist/lib/neutral/create-object-MU2LGXG6.mjs.map +0 -7
- package/dist/lib/neutral/navigation-resolver-3KBOMN4U.mjs +0 -14
- package/dist/lib/neutral/navigation-resolver-3KBOMN4U.mjs.map +0 -7
- package/dist/lib/neutral/react-surface-XYZJBKHZ.mjs.map +0 -7
- package/dist/lib/neutral/settings-TDGDLCUR.mjs.map +0 -7
- package/dist/lib/neutral/state-5COCF5PN.mjs +0 -44
- package/dist/lib/neutral/state-5COCF5PN.mjs.map +0 -7
- package/dist/lib/neutral/update-markdown-NNINDDV5.mjs +0 -44
- package/dist/lib/neutral/update-markdown-NNINDDV5.mjs.map +0 -7
- package/dist/types/src/blueprints/index.d.ts +0 -2
- package/dist/types/src/blueprints/index.d.ts.map +0 -1
- package/dist/types/src/blueprints/markdown-blueprint.d.ts +0 -4
- package/dist/types/src/blueprints/markdown-blueprint.d.ts.map +0 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +0 -6
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +0 -1
- package/dist/types/src/capabilities/app-graph-serializer.d.ts +0 -5
- package/dist/types/src/capabilities/app-graph-serializer.d.ts.map +0 -1
- package/dist/types/src/capabilities/blueprint-definition.d.ts +0 -6
- package/dist/types/src/capabilities/blueprint-definition.d.ts.map +0 -1
- package/dist/types/src/capabilities/navigation-resolver.d.ts +0 -6
- package/dist/types/src/capabilities/navigation-resolver.d.ts.map +0 -1
- package/dist/types/src/paths.d.ts +0 -3
- package/dist/types/src/paths.d.ts.map +0 -1
- package/src/blueprints/index.ts +0 -5
- package/src/capabilities/app-graph-builder.ts +0 -63
- package/src/capabilities/app-graph-serializer.ts +0 -64
- package/src/capabilities/blueprint-definition.ts +0 -19
- package/src/capabilities/navigation-resolver.ts +0 -19
- package/src/components/MarkdownSettings/MarkdownSettings.tsx +0 -35
- package/src/paths.ts +0 -11
- /package/dist/lib/neutral/{chunk-CIJD7P6X.mjs.map → chunk-2V6A5NDQ.mjs.map} +0 -0
- /package/dist/lib/neutral/{create-JK35XC4R.mjs.map → create-OQUMKL5I.mjs.map} +0 -0
- /package/dist/lib/neutral/{create-markdown-7MLE625M.mjs.map → create-markdown-4O5FDA77.mjs.map} +0 -0
- /package/dist/lib/neutral/{open-5YC77C4O.mjs.map → open-BAZIRXII.mjs.map} +0 -0
- /package/dist/lib/neutral/{blueprints/index.mjs.map → operation-handler-SDCXGMGK.mjs.map} +0 -0
- /package/dist/lib/neutral/{scroll-to-anchor-GAFB7W55.mjs.map → scroll-to-anchor-I6HFE5AH.mjs.map} +0 -0
- /package/dist/lib/neutral/{set-view-mode-N7UHYMPG.mjs.map → set-view-mode-NY5OYYIM.mjs.map} +0 -0
- /package/dist/types/src/{components → containers}/MarkdownSettings/MarkdownSettings.stories.d.ts +0 -0
- /package/dist/types/src/{components → containers}/MarkdownSettings/index.d.ts +0 -0
- /package/src/{components → containers}/MarkdownSettings/index.ts +0 -0
|
@@ -2,15 +2,19 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
5
|
+
import { type Decorator, type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
6
|
import * as Effect from 'effect/Effect';
|
|
7
7
|
import React from 'react';
|
|
8
8
|
|
|
9
9
|
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
10
|
+
import { AppActivationEvents } from '@dxos/app-toolkit';
|
|
10
11
|
import { Filter, Obj } from '@dxos/echo';
|
|
11
|
-
import { ClientPlugin } from '@dxos/plugin-client/testing';
|
|
12
|
-
import {
|
|
12
|
+
import { ClientPlugin, initializeIdentity } from '@dxos/plugin-client/testing';
|
|
13
|
+
import { Sketch } from '@dxos/plugin-sketch';
|
|
14
|
+
import { SketchPlugin } from '@dxos/plugin-sketch/plugin';
|
|
15
|
+
import { SketchBuilder } from '@dxos/plugin-sketch/testing';
|
|
13
16
|
import { corePlugins } from '@dxos/plugin-testing';
|
|
17
|
+
import { type Client } from '@dxos/react-client';
|
|
14
18
|
import { useQuery, useSpaces } from '@dxos/react-client/echo';
|
|
15
19
|
import { Panel } from '@dxos/react-ui';
|
|
16
20
|
import { AttendableContainer } from '@dxos/react-ui-attention';
|
|
@@ -19,16 +23,23 @@ import { translations as editorTranslations } from '@dxos/react-ui-editor/transl
|
|
|
19
23
|
import { Loading, withLayout } from '@dxos/react-ui/testing';
|
|
20
24
|
import { Text } from '@dxos/schema';
|
|
21
25
|
|
|
26
|
+
import { useLinkQuery } from '#hooks';
|
|
22
27
|
import { translations } from '#translations';
|
|
23
28
|
import { Markdown } from '#types';
|
|
24
29
|
|
|
25
30
|
import { MarkdownEditor, MarkdownEditorProvider, type MarkdownEditorProviderProps } from './MarkdownEditor';
|
|
26
31
|
|
|
27
|
-
|
|
32
|
+
// A minimal sketch (tldraw `tldraw.com/2`) snapshot, used as a test sketch.
|
|
33
|
+
const SKETCH_CONTENT = new SketchBuilder()
|
|
34
|
+
.rectangle({ id: 'rect', x: 0, y: 0, text: 'DXOS', color: 'blue', fill: 'solid', size: 'l' })
|
|
35
|
+
.build();
|
|
28
36
|
|
|
29
|
-
|
|
37
|
+
type StoryArgs = Omit<MarkdownEditorProviderProps, 'id' | 'extensions' | 'children'>;
|
|
38
|
+
|
|
39
|
+
const DefaultStory = (props: StoryArgs) => {
|
|
30
40
|
const [space] = useSpaces();
|
|
31
41
|
const [doc] = useQuery(space?.db, Filter.type(Markdown.Document));
|
|
42
|
+
const handleLinkQuery = useLinkQuery(space?.db, doc);
|
|
32
43
|
const id = doc && Obj.getURI(doc);
|
|
33
44
|
if (!id) {
|
|
34
45
|
return <Loading data={{ id }} />;
|
|
@@ -36,15 +47,19 @@ const DefaultStory = (props: DefaultStoryProps) => {
|
|
|
36
47
|
|
|
37
48
|
return (
|
|
38
49
|
<AttendableContainer id={id} tabIndex={0} classNames='dx-container'>
|
|
39
|
-
<MarkdownEditorProvider id={id} object={doc} {...props}>
|
|
50
|
+
<MarkdownEditorProvider id={id} attendableId={id} object={doc} onLinkQuery={handleLinkQuery} {...props}>
|
|
40
51
|
{(editorRootProps) => (
|
|
41
52
|
<Editor.Root {...editorRootProps}>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
53
|
+
{/* Mirror MarkdownArticle: Panel.Toolbar/Content are NOT `asChild` (MarkdownEditor.Toolbar is not
|
|
54
|
+
composable, so asChild wraps it in a dx-slot-warning div that breaks the grid-area layout). */}
|
|
55
|
+
<Panel.Root role='article'>
|
|
56
|
+
<Panel.Toolbar>
|
|
57
|
+
<MarkdownEditor.Toolbar classNames='dx-document' />
|
|
45
58
|
</Panel.Toolbar>
|
|
46
|
-
<Panel.Content
|
|
59
|
+
<Panel.Content>
|
|
47
60
|
<MarkdownEditor.Content />
|
|
61
|
+
{/* Embedded objects (transclusions) portal into block-container elements created by the editor. */}
|
|
62
|
+
<MarkdownEditor.Blocks />
|
|
48
63
|
</Panel.Content>
|
|
49
64
|
</Panel.Root>
|
|
50
65
|
</Editor.Root>
|
|
@@ -54,28 +69,49 @@ const DefaultStory = (props: DefaultStoryProps) => {
|
|
|
54
69
|
);
|
|
55
70
|
};
|
|
56
71
|
|
|
72
|
+
const withClient = (seed: (client: Client) => Effect.Effect<void>): Decorator =>
|
|
73
|
+
withPluginManager({
|
|
74
|
+
// SketchPlugin's section surface reads its Settings atom, contributed on SetupSettings.
|
|
75
|
+
setupEvents: [AppActivationEvents.SetupSettings],
|
|
76
|
+
plugins: [
|
|
77
|
+
...corePlugins(),
|
|
78
|
+
SketchPlugin(),
|
|
79
|
+
ClientPlugin({
|
|
80
|
+
types: [Markdown.Document, Text.Text, Sketch.Sketch, Sketch.Canvas],
|
|
81
|
+
onClientInitialized: ({ client }) => seed(client),
|
|
82
|
+
}),
|
|
83
|
+
],
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const seedPlainDocument = (client: Client) =>
|
|
87
|
+
Effect.gen(function* () {
|
|
88
|
+
const { personalSpace } = yield* initializeIdentity(client);
|
|
89
|
+
personalSpace.db.add(Markdown.make({ content: Array.from({ length: 100 }, (_, i) => `Line ${i + 1}`).join('\n') }));
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const seedEmbeddedSketch = (client: Client) =>
|
|
93
|
+
Effect.gen(function* () {
|
|
94
|
+
const { personalSpace } = yield* initializeIdentity(client);
|
|
95
|
+
const sketch = personalSpace.db.add(Sketch.make({ name: 'Test Sketch', canvas: { content: SKETCH_CONTENT } }));
|
|
96
|
+
const uri = Obj.getURI(sketch);
|
|
97
|
+
personalSpace.db.add(
|
|
98
|
+
Markdown.make({
|
|
99
|
+
content: [
|
|
100
|
+
'# Test Document',
|
|
101
|
+
'',
|
|
102
|
+
'The sketch below renders inline as a block surface:',
|
|
103
|
+
'',
|
|
104
|
+
``,
|
|
105
|
+
'',
|
|
106
|
+
].join('\n'),
|
|
107
|
+
}),
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
|
|
57
111
|
const meta: Meta<typeof DefaultStory> = {
|
|
58
112
|
title: 'plugins/plugin-markdown/components/MarkdownEditor',
|
|
59
113
|
render: DefaultStory,
|
|
60
|
-
decorators: [
|
|
61
|
-
withLayout({ layout: 'column' }),
|
|
62
|
-
withPluginManager({
|
|
63
|
-
plugins: [
|
|
64
|
-
...corePlugins(),
|
|
65
|
-
// TODO(burdon): Try to write story without ClientPlugin.
|
|
66
|
-
ClientPlugin({
|
|
67
|
-
types: [Markdown.Document, Text.Text],
|
|
68
|
-
onClientInitialized: ({ client }) =>
|
|
69
|
-
Effect.gen(function* () {
|
|
70
|
-
const { personalSpace } = yield* initializeIdentity(client);
|
|
71
|
-
personalSpace.db.add(
|
|
72
|
-
Markdown.make({ content: Array.from({ length: 100 }, (_, i) => `Line ${i + 1}`).join('\n') }),
|
|
73
|
-
);
|
|
74
|
-
}),
|
|
75
|
-
}),
|
|
76
|
-
],
|
|
77
|
-
}),
|
|
78
|
-
],
|
|
114
|
+
decorators: [withLayout({ layout: 'column' })],
|
|
79
115
|
parameters: {
|
|
80
116
|
translations: [...translations, ...editorTranslations],
|
|
81
117
|
},
|
|
@@ -85,4 +121,10 @@ export default meta;
|
|
|
85
121
|
|
|
86
122
|
type Story = StoryObj<typeof meta>;
|
|
87
123
|
|
|
88
|
-
export const Default: Story = {
|
|
124
|
+
export const Default: Story = {
|
|
125
|
+
decorators: [withClient(seedPlainDocument)],
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export const WithEmbeddedSketch: Story = {
|
|
129
|
+
decorators: [withClient(seedEmbeddedSketch)],
|
|
130
|
+
};
|
|
@@ -9,11 +9,6 @@ import { createContext } from '@radix-ui/react-context';
|
|
|
9
9
|
import React, { type ReactNode, useCallback, useMemo, useState } from 'react';
|
|
10
10
|
import { createPortal } from 'react-dom';
|
|
11
11
|
|
|
12
|
-
import { Surface } from '@dxos/app-framework/ui';
|
|
13
|
-
import { AppSurface } from '@dxos/app-toolkit/ui';
|
|
14
|
-
import { Obj } from '@dxos/echo';
|
|
15
|
-
import { URI } from '@dxos/keys';
|
|
16
|
-
import { useClient } from '@dxos/react-client';
|
|
17
12
|
import { type ThemedClassName } from '@dxos/react-ui';
|
|
18
13
|
import { composable, composableProps } from '@dxos/react-ui';
|
|
19
14
|
import {
|
|
@@ -22,7 +17,7 @@ import {
|
|
|
22
17
|
createEditorController,
|
|
23
18
|
useEditorContext,
|
|
24
19
|
} from '@dxos/react-ui-editor';
|
|
25
|
-
import { type
|
|
20
|
+
import { type XmlWidgetState } from '@dxos/ui-editor';
|
|
26
21
|
import { isNonNullable } from '@dxos/util';
|
|
27
22
|
|
|
28
23
|
import {
|
|
@@ -49,7 +44,7 @@ import {
|
|
|
49
44
|
type MarkdownEditorContextValue = {
|
|
50
45
|
id: string;
|
|
51
46
|
attendableId?: string;
|
|
52
|
-
|
|
47
|
+
widgets: XmlWidgetState[];
|
|
53
48
|
} & Pick<ExtensionsOptions, 'compact' | 'viewMode'> &
|
|
54
49
|
Pick<NaturalMarkdownToolbarProps, 'onAction' | 'onFileUpload' | 'onViewModeChange'>;
|
|
55
50
|
|
|
@@ -74,7 +69,7 @@ export type MarkdownEditorProviderProps = {
|
|
|
74
69
|
'id' | 'attendableId' | 'viewMode' | 'compact' | 'onAction' | 'onFileUpload' | 'onViewModeChange'
|
|
75
70
|
> &
|
|
76
71
|
Pick<UseEditorMenuOptionsProps, 'slashCommandGroups' | 'onLinkQuery'> &
|
|
77
|
-
Pick<ExtensionsOptions, 'editorStateStore' | '
|
|
72
|
+
Pick<ExtensionsOptions, 'editorStateStore' | 'viewState' | 'settings' | 'onSelectObject'>;
|
|
78
73
|
|
|
79
74
|
export const MarkdownEditorProvider = ({
|
|
80
75
|
children,
|
|
@@ -84,7 +79,7 @@ export const MarkdownEditorProvider = ({
|
|
|
84
79
|
settings,
|
|
85
80
|
compact,
|
|
86
81
|
viewMode,
|
|
87
|
-
|
|
82
|
+
viewState,
|
|
88
83
|
editorStateStore,
|
|
89
84
|
extensions: extensionsProp,
|
|
90
85
|
slashCommandGroups,
|
|
@@ -94,20 +89,8 @@ export const MarkdownEditorProvider = ({
|
|
|
94
89
|
onFileUpload,
|
|
95
90
|
onViewModeChange,
|
|
96
91
|
}: MarkdownEditorProviderProps) => {
|
|
97
|
-
//
|
|
98
|
-
const [
|
|
99
|
-
const previewOptions = useMemo<PreviewOptions>(
|
|
100
|
-
() => ({
|
|
101
|
-
db: Obj.isObject(object) ? Obj.getDatabase(object) : undefined,
|
|
102
|
-
addBlockContainer: (block) => {
|
|
103
|
-
setPreviewBlocks((prev) => [...prev, block]);
|
|
104
|
-
},
|
|
105
|
-
removeBlockContainer: ({ link }) => {
|
|
106
|
-
setPreviewBlocks((prev) => prev.filter(({ link: prevLink }) => prevLink.dxn !== link.dxn));
|
|
107
|
-
},
|
|
108
|
-
}),
|
|
109
|
-
[object],
|
|
110
|
-
);
|
|
92
|
+
// Widget portals driven by xmlTags.
|
|
93
|
+
const [widgets, setWidgets] = useState<XmlWidgetState[]>([]);
|
|
111
94
|
|
|
112
95
|
// Context menu options (Editor.Root calls useEditorMenu with these props).
|
|
113
96
|
const menuOptions = useEditorMenuOptions({ slashCommandGroups, onLinkQuery });
|
|
@@ -118,9 +101,9 @@ export const MarkdownEditorProvider = ({
|
|
|
118
101
|
object,
|
|
119
102
|
compact,
|
|
120
103
|
viewMode,
|
|
121
|
-
|
|
104
|
+
viewState,
|
|
122
105
|
editorStateStore,
|
|
123
|
-
|
|
106
|
+
setWidgets,
|
|
124
107
|
settings,
|
|
125
108
|
onSelectObject,
|
|
126
109
|
});
|
|
@@ -149,12 +132,12 @@ export const MarkdownEditorProvider = ({
|
|
|
149
132
|
attendableId,
|
|
150
133
|
compact,
|
|
151
134
|
viewMode,
|
|
152
|
-
|
|
135
|
+
widgets,
|
|
153
136
|
onAction,
|
|
154
137
|
onFileUpload,
|
|
155
138
|
onViewModeChange,
|
|
156
139
|
}),
|
|
157
|
-
[id, attendableId, compact, viewMode,
|
|
140
|
+
[id, attendableId, compact, viewMode, widgets, onAction, onFileUpload, onViewModeChange],
|
|
158
141
|
);
|
|
159
142
|
|
|
160
143
|
return (
|
|
@@ -251,12 +234,12 @@ const MARKDOWN_EDITOR_BLOCKS_NAME = 'MarkdownEditor.Blocks';
|
|
|
251
234
|
type MarkdownEditorBlocksProps = {};
|
|
252
235
|
|
|
253
236
|
const MarkdownEditorBlocks = (_props: MarkdownEditorBlocksProps) => {
|
|
254
|
-
const {
|
|
237
|
+
const { widgets } = useMarkdownEditorContext(MARKDOWN_EDITOR_BLOCKS_NAME);
|
|
255
238
|
|
|
256
239
|
return (
|
|
257
240
|
<>
|
|
258
|
-
{
|
|
259
|
-
<
|
|
241
|
+
{widgets.map(({ id, root, Component, props }) => (
|
|
242
|
+
<div key={id}>{createPortal(<Component {...props} />, root)}</div>
|
|
260
243
|
))}
|
|
261
244
|
</>
|
|
262
245
|
);
|
|
@@ -264,15 +247,6 @@ const MarkdownEditorBlocks = (_props: MarkdownEditorBlocksProps) => {
|
|
|
264
247
|
|
|
265
248
|
MarkdownEditorBlocks.displayName = MARKDOWN_EDITOR_BLOCKS_NAME;
|
|
266
249
|
|
|
267
|
-
const PreviewBlock = ({ el, link }: PreviewBlock) => {
|
|
268
|
-
const client = useClient();
|
|
269
|
-
const dxn = URI.make(link.dxn);
|
|
270
|
-
const subject = client.graph.makeRef(dxn).target;
|
|
271
|
-
const data = useMemo(() => ({ subject }), [subject]);
|
|
272
|
-
|
|
273
|
-
return createPortal(<Surface.Surface type={AppSurface.Card} data={data} limit={1} />, el);
|
|
274
|
-
};
|
|
275
|
-
|
|
276
250
|
//
|
|
277
251
|
// MarkdownEditor
|
|
278
252
|
//
|
|
@@ -284,7 +258,7 @@ export const MarkdownEditor = {
|
|
|
284
258
|
Blocks: MarkdownEditorBlocks,
|
|
285
259
|
};
|
|
286
260
|
|
|
287
|
-
export type { MarkdownEditorContentProps, MarkdownEditorToolbarProps
|
|
261
|
+
export type { MarkdownEditorBlocksProps, MarkdownEditorContentProps, MarkdownEditorToolbarProps };
|
|
288
262
|
|
|
289
263
|
/** @deprecated Use `MarkdownEditorProviderProps`. */
|
|
290
264
|
export type MarkdownEditorRootProps = MarkdownEditorProviderProps;
|
|
@@ -7,6 +7,7 @@ import { type Atom, RegistryContext } from '@effect-atom/atom-react';
|
|
|
7
7
|
import React, { forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo } from 'react';
|
|
8
8
|
|
|
9
9
|
import { useCapabilities } from '@dxos/app-framework/ui';
|
|
10
|
+
import { AppSurface } from '@dxos/app-toolkit/ui';
|
|
10
11
|
import { type ThemedClassName, useThemeContext, useTranslation } from '@dxos/react-ui';
|
|
11
12
|
import {
|
|
12
13
|
type EditorMenuGroup,
|
|
@@ -18,15 +19,15 @@ import {
|
|
|
18
19
|
type EditorSelectionState,
|
|
19
20
|
type EditorStateStore,
|
|
20
21
|
type ThemeExtensionsOptions,
|
|
21
|
-
mobileSlots,
|
|
22
22
|
createBasicExtensions,
|
|
23
23
|
createMarkdownExtensions,
|
|
24
24
|
createThemeExtensions,
|
|
25
|
-
dropFile,
|
|
26
25
|
documentSlots,
|
|
26
|
+
dropFile,
|
|
27
|
+
editorClassNames,
|
|
27
28
|
formattingListener,
|
|
29
|
+
mobileSlots,
|
|
28
30
|
processEditorPayload,
|
|
29
|
-
editorClassNames,
|
|
30
31
|
scrollbarAutohide,
|
|
31
32
|
} from '@dxos/ui-editor';
|
|
32
33
|
import { type EditorViewMode } from '@dxos/ui-editor/types';
|
|
@@ -72,7 +73,7 @@ export const MarkdownEditorContent = forwardRef<EditorView | null, MarkdownEdito
|
|
|
72
73
|
},
|
|
73
74
|
forwardedRef,
|
|
74
75
|
) => {
|
|
75
|
-
const { t } = useTranslation(meta.
|
|
76
|
+
const { t } = useTranslation(meta.profile.key);
|
|
76
77
|
const { themeMode } = useThemeContext();
|
|
77
78
|
const registry = useContext(RegistryContext);
|
|
78
79
|
|
|
@@ -95,7 +96,7 @@ export const MarkdownEditorContent = forwardRef<EditorView | null, MarkdownEdito
|
|
|
95
96
|
focusAttributes,
|
|
96
97
|
} = useTextEditor(
|
|
97
98
|
() => ({
|
|
98
|
-
...(role !==
|
|
99
|
+
...(role !== AppSurface.Section.role && {
|
|
99
100
|
id,
|
|
100
101
|
scrollTo,
|
|
101
102
|
selection,
|
|
@@ -117,7 +118,7 @@ export const MarkdownEditorContent = forwardRef<EditorView | null, MarkdownEdito
|
|
|
117
118
|
createMarkdownExtensions(),
|
|
118
119
|
scrollbarAutohide(),
|
|
119
120
|
toolbarState && formattingListener(updateToolbarState),
|
|
120
|
-
role !==
|
|
121
|
+
role !== AppSurface.Section.role &&
|
|
121
122
|
onFileUpload &&
|
|
122
123
|
dropFile({
|
|
123
124
|
// TODO(wittjosiah): Factor out to file uploader plugin.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { type EditorView } from '@codemirror/view';
|
|
6
6
|
import React, { useCallback, useState } from 'react';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { AppCapabilities } from '@dxos/app-toolkit';
|
|
9
9
|
import { composable, composableProps } from '@dxos/react-ui';
|
|
10
10
|
import { Editor, type EditorToolbarProps } from '@dxos/react-ui-editor';
|
|
11
11
|
|
|
@@ -17,7 +17,7 @@ export type MarkdownEditorToolbarProps = {
|
|
|
17
17
|
// that React 19.2's dev render-logger would walk into a cross-origin frame. See
|
|
18
18
|
// `react-ui-editor/.../controller.ts` for the full rationale.
|
|
19
19
|
getView?: () => EditorView | null;
|
|
20
|
-
onFileUpload?: (file: File) => Promise<FileInfo | undefined>;
|
|
20
|
+
onFileUpload?: (file: File) => Promise<AppCapabilities.FileInfo | undefined>;
|
|
21
21
|
} & Pick<EditorToolbarProps, 'role' | 'customActions' | 'onAction' | 'onViewModeChange'>;
|
|
22
22
|
|
|
23
23
|
export const MarkdownEditorToolbar = composable<HTMLDivElement, MarkdownEditorToolbarProps>(
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import { Surface, useOperationInvoker } from '@dxos/app-framework/ui';
|
|
8
|
+
import { LayoutOperation, Paths } from '@dxos/app-toolkit';
|
|
9
|
+
import { AppSurface } from '@dxos/app-toolkit/ui';
|
|
10
|
+
import { Obj } from '@dxos/echo';
|
|
11
|
+
import { URI } from '@dxos/keys';
|
|
12
|
+
import { useClient } from '@dxos/react-client';
|
|
13
|
+
import { Icon, IconButton } from '@dxos/react-ui';
|
|
14
|
+
import { ResizeHandle, type Size, resizeAttributes, sizeStyle } from '@dxos/react-ui-dnd';
|
|
15
|
+
import { type XmlWidgetProps } from '@dxos/ui-editor';
|
|
16
|
+
|
|
17
|
+
export type PreviewComponentProps = XmlWidgetProps<{
|
|
18
|
+
label: string;
|
|
19
|
+
dxn: string;
|
|
20
|
+
block?: boolean;
|
|
21
|
+
suggest?: boolean;
|
|
22
|
+
onOpen?: (dxn: URI.URI) => void;
|
|
23
|
+
}>;
|
|
24
|
+
|
|
25
|
+
// Persisted height (px) lives in the image alt text after the label, Obsidian-style: ``.
|
|
26
|
+
const HEIGHT_PATTERN = /^(.*)\|(\d+)$/;
|
|
27
|
+
|
|
28
|
+
const parseEmbedLabel = (alt: string): { baseLabel: string; height?: number } => {
|
|
29
|
+
const match = HEIGHT_PATTERN.exec(alt ?? '');
|
|
30
|
+
if (match) {
|
|
31
|
+
const height = Number.parseInt(match[2], 10);
|
|
32
|
+
if (Number.isFinite(height) && height > 0) {
|
|
33
|
+
return { baseLabel: match[1], height };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return { baseLabel: alt ?? '' };
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const formatEmbedLabel = (baseLabel: string, height?: number): string =>
|
|
40
|
+
height != null ? `${baseLabel}|${height}` : baseLabel;
|
|
41
|
+
|
|
42
|
+
const MIN_SIZE = 6;
|
|
43
|
+
const FALLBACK_SIZE = 320;
|
|
44
|
+
|
|
45
|
+
/** Scroll the element's top into view (honoring its `scroll-margin`) only if that top is not already visible. */
|
|
46
|
+
const scrollTopIntoViewIfNeeded = (element: HTMLElement): void => {
|
|
47
|
+
let parent = element.parentElement;
|
|
48
|
+
while (parent) {
|
|
49
|
+
const { overflowY } = getComputedStyle(parent);
|
|
50
|
+
if (
|
|
51
|
+
(overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'overlay') &&
|
|
52
|
+
parent.scrollHeight > parent.clientHeight
|
|
53
|
+
) {
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
parent = parent.parentElement;
|
|
57
|
+
}
|
|
58
|
+
const elementTop = element.getBoundingClientRect().top;
|
|
59
|
+
const viewTop = parent ? parent.getBoundingClientRect().top : 0;
|
|
60
|
+
const viewBottom = parent ? parent.getBoundingClientRect().bottom : window.innerHeight;
|
|
61
|
+
if (elementTop < viewTop || elementTop > viewBottom) {
|
|
62
|
+
element.scrollIntoView({ block: 'start', inline: 'nearest' });
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Registry-backed block widget for URL-scheme preview slots.
|
|
68
|
+
* Replaces the addBlockContainer callback pattern.
|
|
69
|
+
* Used as the Component entry in a urlSchemes XmlWidgetDef.
|
|
70
|
+
*/
|
|
71
|
+
export const PreviewComponent = ({ dxn, label: alt, onOpen, view, range }: PreviewComponentProps) => {
|
|
72
|
+
const client = useClient();
|
|
73
|
+
const { invokePromise } = useOperationInvoker();
|
|
74
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
75
|
+
const uri = dxn ? URI.make(dxn) : undefined;
|
|
76
|
+
const subject = uri ? client.graph.makeRef<Obj.Unknown>(uri).target : undefined;
|
|
77
|
+
|
|
78
|
+
// px per rem; ResizeHandle works in rem while the persisted height is in px.
|
|
79
|
+
const remSize = useMemo(() => parseFloat(getComputedStyle(document.documentElement).fontSize) || 16, []);
|
|
80
|
+
const { height } = parseEmbedLabel(alt);
|
|
81
|
+
|
|
82
|
+
// `min-content` keeps the embed at its intrinsic height until the user resizes it; the handle then
|
|
83
|
+
// measures the rendered box and switches to an explicit height.
|
|
84
|
+
const [size, setSize] = useState<Size>(height != null ? height / remSize : 'min-content');
|
|
85
|
+
|
|
86
|
+
// Tell the surface it is sized by its container (vs. intrinsic) so content (e.g. an image) can fit.
|
|
87
|
+
const extrinsic = size !== 'min-content';
|
|
88
|
+
const data = useMemo(
|
|
89
|
+
() => (subject ? { subject, attendableId: dxn, extrinsic } : undefined),
|
|
90
|
+
[subject, dxn, extrinsic],
|
|
91
|
+
);
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
setSize(height != null ? height / remSize : 'min-content');
|
|
94
|
+
}, [height, remSize]);
|
|
95
|
+
|
|
96
|
+
// Persist the height (px) into the alt text on drop by rewriting the image node in the source. The
|
|
97
|
+
// node bounds and base label are re-derived from the live document (the captured `range`/`label`
|
|
98
|
+
// can lag a prior edit before React re-renders the widget). When the same object is transcluded
|
|
99
|
+
// more than once, the node whose start is NEAREST the widget's range is chosen so a duplicate
|
|
100
|
+
// embed isn't rewritten by mistake.
|
|
101
|
+
const handleResize = useCallback(
|
|
102
|
+
(next: Size, commit?: boolean) => {
|
|
103
|
+
setSize(next);
|
|
104
|
+
if (!commit || typeof next !== 'number' || !view) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const doc = view.state.doc.toString();
|
|
108
|
+
const marker = `](${dxn})`;
|
|
109
|
+
let open = -1;
|
|
110
|
+
let close = -1;
|
|
111
|
+
for (let at = doc.indexOf(marker); at >= 0; at = doc.indexOf(marker, at + marker.length)) {
|
|
112
|
+
const start = doc.lastIndexOf('`;
|
|
123
|
+
view.dispatch({ changes: { from: open, to: close + marker.length, insert } });
|
|
124
|
+
// After the resized box has laid out, bring its top into frame — but only if that top scrolled
|
|
125
|
+
// out of view. Scroll the element itself (not the CM view) so it works whichever ancestor
|
|
126
|
+
// actually scrolls (cm-scroller or an outer panel); defer a frame so the new height applies first.
|
|
127
|
+
requestAnimationFrame(() => {
|
|
128
|
+
if (containerRef.current) {
|
|
129
|
+
scrollTopIntoViewIfNeeded(containerRef.current);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
[view, range, dxn, remSize],
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
// Open the referenced object: defer to the caller's handler when provided, else navigate to it.
|
|
137
|
+
const handleOpen = useCallback(() => {
|
|
138
|
+
if (!uri || !subject) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (onOpen) {
|
|
142
|
+
onOpen(uri);
|
|
143
|
+
} else {
|
|
144
|
+
void invokePromise?.(LayoutOperation.Open, {
|
|
145
|
+
subject: [Paths.getObjectPathFromObject(subject)],
|
|
146
|
+
navigation: 'immediate',
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}, [uri, subject, onOpen, invokePromise]);
|
|
150
|
+
|
|
151
|
+
if (!uri || !subject || !data) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const objectLabel = Obj.getLabel(subject);
|
|
156
|
+
const objectIcon = Obj.getIcon(subject);
|
|
157
|
+
|
|
158
|
+
// Frame transcluded block embeds so they read as a self-contained card within the document flow.
|
|
159
|
+
// The clip/border live on an inner element so they don't clip the resize handle (which straddles the
|
|
160
|
+
// bottom edge); the inner grid stretches the surface to fill the resizable box, overriding any
|
|
161
|
+
// intrinsic aspect.
|
|
162
|
+
return (
|
|
163
|
+
<div
|
|
164
|
+
className='relative grid scroll-mt-16'
|
|
165
|
+
style={sizeStyle(size, 'vertical')}
|
|
166
|
+
{...resizeAttributes}
|
|
167
|
+
ref={containerRef}
|
|
168
|
+
>
|
|
169
|
+
<div className='grid overflow-hidden border border-subdued-separator rounded-md'>
|
|
170
|
+
<Surface.Surface type={AppSurface.Section} data={data} limit={1} />
|
|
171
|
+
</div>
|
|
172
|
+
<div className='absolute top-1 right-1 flex items-center justify-end gap-1'>
|
|
173
|
+
<span className='dx-tag dx-tag--neutral flex items-center gap-1'>
|
|
174
|
+
{objectIcon && <Icon icon={objectIcon.icon} size={4} />}
|
|
175
|
+
{objectLabel}
|
|
176
|
+
</span>
|
|
177
|
+
<IconButton
|
|
178
|
+
density='sm'
|
|
179
|
+
icon='ph--arrow-square-out--regular'
|
|
180
|
+
iconOnly
|
|
181
|
+
label='Open'
|
|
182
|
+
variant='ghost'
|
|
183
|
+
onClick={handleOpen}
|
|
184
|
+
/>
|
|
185
|
+
</div>
|
|
186
|
+
<ResizeHandle
|
|
187
|
+
side='block-end'
|
|
188
|
+
fallbackSize={FALLBACK_SIZE}
|
|
189
|
+
minSize={MIN_SIZE}
|
|
190
|
+
size={size}
|
|
191
|
+
onSizeChange={handleResize}
|
|
192
|
+
/>
|
|
193
|
+
</div>
|
|
194
|
+
);
|
|
195
|
+
};
|
package/src/components/index.ts
CHANGED
|
@@ -91,10 +91,9 @@ const meta = {
|
|
|
91
91
|
const createObjects = createObjectFactory(personalSpace.db, generator);
|
|
92
92
|
yield* Effect.promise(() => createObjects([{ type: Organization.Organization, count: 10 }]));
|
|
93
93
|
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
yield* Effect.promise(() => queue.append([kai, dxos]));
|
|
94
|
+
const kai = personalSpace.db.add(Obj.make(Person.Person, { fullName: 'Kai' }));
|
|
95
|
+
const dxos = personalSpace.db.add(Obj.make(Organization.Organization, { name: 'DXOS' }));
|
|
96
|
+
yield* Effect.promise(() => personalSpace.db.flush());
|
|
98
97
|
|
|
99
98
|
personalSpace.db.add(
|
|
100
99
|
Markdown.make({
|
|
@@ -13,14 +13,14 @@ import { Obj } from '@dxos/echo';
|
|
|
13
13
|
import { useActionRunner } from '@dxos/plugin-graph';
|
|
14
14
|
import { useObject } from '@dxos/react-client/echo';
|
|
15
15
|
import { Panel } from '@dxos/react-ui';
|
|
16
|
-
import { type
|
|
16
|
+
import { type ViewStateManager } from '@dxos/react-ui-attention';
|
|
17
17
|
import { Editor } from '@dxos/react-ui-editor';
|
|
18
18
|
import { Text } from '@dxos/schema';
|
|
19
19
|
|
|
20
20
|
import {
|
|
21
21
|
MarkdownEditor,
|
|
22
|
-
MarkdownEditorProvider,
|
|
23
22
|
type MarkdownEditorContentProps,
|
|
23
|
+
MarkdownEditorProvider,
|
|
24
24
|
type MarkdownEditorProviderProps,
|
|
25
25
|
} from '#components';
|
|
26
26
|
import { useLinkQuery } from '#hooks';
|
|
@@ -31,7 +31,7 @@ export type MarkdownArticleProps = AppSurface.ObjectArticleProps<
|
|
|
31
31
|
{
|
|
32
32
|
id: string;
|
|
33
33
|
settings: Markdown.Settings;
|
|
34
|
-
|
|
34
|
+
viewState?: ViewStateManager;
|
|
35
35
|
} & Pick<MarkdownPluginState, 'extensionProviders'> &
|
|
36
36
|
Pick<MarkdownEditorProviderProps, 'viewMode' | 'onSelectObject' | 'onViewModeChange'> &
|
|
37
37
|
Pick<MarkdownEditorContentProps, 'editorStateStore'>
|
|
@@ -90,7 +90,7 @@ export const MarkdownArticle = forwardRef<HTMLDivElement, MarkdownArticleProps>(
|
|
|
90
90
|
}, [db, upload]);
|
|
91
91
|
|
|
92
92
|
// Query for @ refs.
|
|
93
|
-
const handleLinkQuery = useLinkQuery(db);
|
|
93
|
+
const handleLinkQuery = useLinkQuery(db, Obj.isObject(object) ? object : undefined);
|
|
94
94
|
|
|
95
95
|
// Open linked objects.
|
|
96
96
|
const { invokePromise } = useOperationInvoker();
|
|
@@ -115,7 +115,7 @@ export const MarkdownArticle = forwardRef<HTMLDivElement, MarkdownArticleProps>(
|
|
|
115
115
|
id={id}
|
|
116
116
|
attendableId={attendableId}
|
|
117
117
|
object={object}
|
|
118
|
-
compact={role !==
|
|
118
|
+
compact={role !== AppSurface.Article.role}
|
|
119
119
|
extensions={extensions}
|
|
120
120
|
settings={settings}
|
|
121
121
|
viewMode={viewMode}
|
|
@@ -129,7 +129,7 @@ export const MarkdownArticle = forwardRef<HTMLDivElement, MarkdownArticleProps>(
|
|
|
129
129
|
<Editor.Root {...editorRootProps}>
|
|
130
130
|
<Panel.Root role={role} ref={forwardedRef}>
|
|
131
131
|
{settings.toolbar && (
|
|
132
|
-
<Panel.Toolbar
|
|
132
|
+
<Panel.Toolbar>
|
|
133
133
|
<MarkdownEditor.Toolbar classNames='dx-document' customActions={customActions} />
|
|
134
134
|
</Panel.Toolbar>
|
|
135
135
|
)}
|
|
@@ -20,7 +20,7 @@ import { snippet as snippetExtension } from './snippet';
|
|
|
20
20
|
export type MarkdownCardProps = { subject: Markdown.Document | Text.Text };
|
|
21
21
|
|
|
22
22
|
export const MarkdownCard = ({ subject }: MarkdownCardProps) => {
|
|
23
|
-
const { t } = useTranslation(meta.
|
|
23
|
+
const { t } = useTranslation(meta.profile.key);
|
|
24
24
|
// NOTE: Newline is added so that Fade does not obscure the last line.
|
|
25
25
|
const snippet = useMemo(() => getSnippet(subject) + '\n', [subject]);
|
|
26
26
|
const extensions = useMemo(() => [snippetExtension({ height: 300, scale: 0.8 })], []);
|
|
@@ -29,7 +29,7 @@ export const MarkdownCard = ({ subject }: MarkdownCardProps) => {
|
|
|
29
29
|
return (
|
|
30
30
|
<Card.Body>
|
|
31
31
|
{snippet && (
|
|
32
|
-
<Card.Section className='relative'>
|
|
32
|
+
<Card.Section className='aspect-square relative'>
|
|
33
33
|
<Card.Row fullWidth>
|
|
34
34
|
<MarkdownEditorProvider id={subject.id} viewMode='readonly' extensions={extensions}>
|
|
35
35
|
{(editorRootProps) => (
|
|
@@ -11,7 +11,7 @@ import { translations } from '#translations';
|
|
|
11
11
|
import { MarkdownSettings } from './MarkdownSettings';
|
|
12
12
|
|
|
13
13
|
const meta = {
|
|
14
|
-
title: 'plugins/plugin-markdown/
|
|
14
|
+
title: 'plugins/plugin-markdown/containers/MarkdownSettings',
|
|
15
15
|
tags: ['settings'],
|
|
16
16
|
component: MarkdownSettings,
|
|
17
17
|
decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
|