@difizen/libro-markdown-cell 0.1.2
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/LICENSE +21 -0
- package/README.md +1 -0
- package/es/index.d.ts +7 -0
- package/es/index.d.ts.map +1 -0
- package/es/index.js +6 -0
- package/es/index.less +116 -0
- package/es/markdown-cell-contribution.d.ts +12 -0
- package/es/markdown-cell-contribution.d.ts.map +1 -0
- package/es/markdown-cell-contribution.js +50 -0
- package/es/markdown-cell-model.d.ts +11 -0
- package/es/markdown-cell-model.d.ts.map +1 -0
- package/es/markdown-cell-model.js +77 -0
- package/es/markdown-cell-module.d.ts +3 -0
- package/es/markdown-cell-module.d.ts.map +1 -0
- package/es/markdown-cell-module.js +21 -0
- package/es/markdown-cell-protocol.d.ts +5 -0
- package/es/markdown-cell-protocol.d.ts.map +1 -0
- package/es/markdown-cell-protocol.js +1 -0
- package/es/markdown-cell-view.d.ts +40 -0
- package/es/markdown-cell-view.d.ts.map +1 -0
- package/es/markdown-cell-view.js +293 -0
- package/es/markdown-preview.d.ts +7 -0
- package/es/markdown-preview.d.ts.map +1 -0
- package/es/markdown-preview.js +31 -0
- package/package.json +64 -0
- package/src/index.less +116 -0
- package/src/index.spec.ts +10 -0
- package/src/index.ts +6 -0
- package/src/markdown-cell-contribution.ts +33 -0
- package/src/markdown-cell-model.ts +40 -0
- package/src/markdown-cell-module.ts +26 -0
- package/src/markdown-cell-protocol.ts +6 -0
- package/src/markdown-cell-view.tsx +217 -0
- package/src/markdown-preview.tsx +35 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CodeEditorViewOptions,
|
|
3
|
+
IEditor,
|
|
4
|
+
CodeEditorView,
|
|
5
|
+
} from '@difizen/libro-code-editor';
|
|
6
|
+
import { CodeEditorManager } from '@difizen/libro-code-editor';
|
|
7
|
+
import type { CellCollapsible, CellViewOptions } from '@difizen/libro-core';
|
|
8
|
+
import { CellService, EditorStatus, LibroEditorCellView } from '@difizen/libro-core';
|
|
9
|
+
import { MarkdownParser } from '@difizen/libro-markdown';
|
|
10
|
+
import type { ViewSize } from '@difizen/mana-app';
|
|
11
|
+
import { getOrigin, prop, useInject, watch } from '@difizen/mana-app';
|
|
12
|
+
import {
|
|
13
|
+
view,
|
|
14
|
+
ViewInstance,
|
|
15
|
+
ViewManager,
|
|
16
|
+
ViewOption,
|
|
17
|
+
ViewRender,
|
|
18
|
+
} from '@difizen/mana-app';
|
|
19
|
+
import { inject, transient } from '@difizen/mana-app';
|
|
20
|
+
import { forwardRef, useEffect } from 'react';
|
|
21
|
+
|
|
22
|
+
import './index.less';
|
|
23
|
+
import type { MarkdownCellModel } from './markdown-cell-model.js';
|
|
24
|
+
import { MarkdownPreview } from './markdown-preview.js';
|
|
25
|
+
|
|
26
|
+
export const MarkdownCell = forwardRef<HTMLDivElement>(
|
|
27
|
+
function MarkdownCell(props, ref) {
|
|
28
|
+
const instance = useInject<MarkdownCellView>(ViewInstance);
|
|
29
|
+
const isEdit = instance.isEdit;
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (instance.editorView?.editor) {
|
|
32
|
+
instance.editor = getOrigin(instance.editorView?.editor);
|
|
33
|
+
}
|
|
34
|
+
}, [instance, instance.editorView?.editor]);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (instance.cellmodel.isEdit) {
|
|
38
|
+
instance.createEditor();
|
|
39
|
+
}
|
|
40
|
+
}, [instance, instance.cellmodel.isEdit]);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div
|
|
44
|
+
ref={ref}
|
|
45
|
+
tabIndex={10}
|
|
46
|
+
onBlur={(e) => {
|
|
47
|
+
if (typeof ref !== 'function' && !ref?.current?.contains(e.relatedTarget)) {
|
|
48
|
+
instance.blur();
|
|
49
|
+
}
|
|
50
|
+
}}
|
|
51
|
+
className={instance.className}
|
|
52
|
+
>
|
|
53
|
+
{isEdit && instance.editorView ? (
|
|
54
|
+
<ViewRender view={instance.editorView} />
|
|
55
|
+
) : (
|
|
56
|
+
<MarkdownPreview instance={instance} />
|
|
57
|
+
)}
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
@transient()
|
|
64
|
+
@view('libro-markdown-cell-view')
|
|
65
|
+
export class MarkdownCellView extends LibroEditorCellView implements CellCollapsible {
|
|
66
|
+
override get wrapperCls() {
|
|
67
|
+
if (!this.cellmodel.isEdit) {
|
|
68
|
+
return 'markdown-cell-preview';
|
|
69
|
+
}
|
|
70
|
+
return '';
|
|
71
|
+
}
|
|
72
|
+
override view = MarkdownCell;
|
|
73
|
+
|
|
74
|
+
viewManager: ViewManager;
|
|
75
|
+
|
|
76
|
+
codeEditorManager: CodeEditorManager;
|
|
77
|
+
|
|
78
|
+
@prop()
|
|
79
|
+
editorView?: CodeEditorView;
|
|
80
|
+
|
|
81
|
+
@prop()
|
|
82
|
+
editorAreaHeight = 0;
|
|
83
|
+
|
|
84
|
+
@prop()
|
|
85
|
+
override noEditorAreaHeight = 0;
|
|
86
|
+
|
|
87
|
+
declare editor: IEditor | undefined;
|
|
88
|
+
|
|
89
|
+
@prop()
|
|
90
|
+
headingCollapsed = false;
|
|
91
|
+
|
|
92
|
+
@prop()
|
|
93
|
+
collapsibleChildNumber = 0;
|
|
94
|
+
|
|
95
|
+
@prop()
|
|
96
|
+
override editorStatus: EditorStatus = EditorStatus.NOTLOADED;
|
|
97
|
+
|
|
98
|
+
get isEdit() {
|
|
99
|
+
return (
|
|
100
|
+
this.editorView?.view && this.cellmodel.isEdit && !this.parent.model.readOnly
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
get cellmodel() {
|
|
105
|
+
return this.model as MarkdownCellModel;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
markdownParser: MarkdownParser;
|
|
109
|
+
|
|
110
|
+
constructor(
|
|
111
|
+
@inject(ViewOption) options: CellViewOptions,
|
|
112
|
+
@inject(CellService) cellService: CellService,
|
|
113
|
+
@inject(ViewManager) viewManager: ViewManager,
|
|
114
|
+
@inject(CodeEditorManager) codeEditorManager: CodeEditorManager,
|
|
115
|
+
@inject(MarkdownParser) markdownParser: MarkdownParser,
|
|
116
|
+
) {
|
|
117
|
+
super(options, cellService);
|
|
118
|
+
this.viewManager = viewManager;
|
|
119
|
+
this.codeEditorManager = codeEditorManager;
|
|
120
|
+
this.markdownParser = markdownParser;
|
|
121
|
+
this.className = this.className + ' markdown';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
override onViewMount() {
|
|
125
|
+
if (this.cellmodel.isEdit) {
|
|
126
|
+
this.createEditor();
|
|
127
|
+
}
|
|
128
|
+
watch(this.parent.model, 'readOnly', () => {
|
|
129
|
+
if (this.parent.model.readOnly === true) {
|
|
130
|
+
this.cellmodel.isEdit = false;
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
override onViewResize(size: ViewSize) {
|
|
136
|
+
if (size.height) {
|
|
137
|
+
this.editorAreaHeight = size.height;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
calcEditorAreaHeight() {
|
|
142
|
+
return this.editorAreaHeight;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
protected getEditorOption(): CodeEditorViewOptions {
|
|
146
|
+
const option: CodeEditorViewOptions = {
|
|
147
|
+
model: this.model,
|
|
148
|
+
config: {
|
|
149
|
+
lineNumbers: false,
|
|
150
|
+
foldGutter: false,
|
|
151
|
+
lineWrap: 'on',
|
|
152
|
+
matchBrackets: false,
|
|
153
|
+
autoClosingBrackets: false,
|
|
154
|
+
},
|
|
155
|
+
autoFocus: true,
|
|
156
|
+
};
|
|
157
|
+
return option;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async createEditor() {
|
|
161
|
+
const option = this.getEditorOption();
|
|
162
|
+
|
|
163
|
+
this.editorStatus = EditorStatus.LOADING;
|
|
164
|
+
|
|
165
|
+
// 防止虚拟滚动中编辑器被频繁创建
|
|
166
|
+
if (this.editorView) {
|
|
167
|
+
this.editorStatus = EditorStatus.LOADED;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const editorView = await this.codeEditorManager.getOrCreateEditorView(option);
|
|
172
|
+
|
|
173
|
+
this.editorView = editorView;
|
|
174
|
+
await editorView.editorReady;
|
|
175
|
+
|
|
176
|
+
this.editorStatus = EditorStatus.LOADED;
|
|
177
|
+
|
|
178
|
+
await this.afterEditorReady();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
protected async afterEditorReady() {
|
|
182
|
+
getOrigin(this.editorView)?.editor.focus();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
186
|
+
override shouldEnterEditorMode(e: React.FocusEvent<HTMLElement>) {
|
|
187
|
+
if (!this.cellmodel.isEdit) {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
override focus(toEdit: boolean) {
|
|
194
|
+
if (toEdit) {
|
|
195
|
+
this.cellmodel.isEdit = true;
|
|
196
|
+
} else {
|
|
197
|
+
if (this.container?.current?.parentElement?.contains(document.activeElement)) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
this.container?.current?.parentElement?.focus();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
override blur() {
|
|
205
|
+
this.cellmodel.isEdit = false;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
override redo(): void {
|
|
209
|
+
// this.editor?.trigger('', 'redo', '');
|
|
210
|
+
// this.editor?.focus();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
override undo(): void {
|
|
214
|
+
// this.editor?.trigger('undo', 'undo', {});
|
|
215
|
+
// this.editor?.focus();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { FC } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
3
|
+
|
|
4
|
+
import './index.less';
|
|
5
|
+
import type { MarkdownCellView } from './markdown-cell-view.js';
|
|
6
|
+
|
|
7
|
+
export const MarkdownPreview: FC<{ instance: MarkdownCellView }> = ({ instance }) => {
|
|
8
|
+
const mktRef = useRef<HTMLDivElement>(null);
|
|
9
|
+
// const instance = useInject<MarkdownCellView>(ViewInstance);
|
|
10
|
+
|
|
11
|
+
const enterEdit: React.MouseEventHandler<HTMLDivElement> = useCallback(
|
|
12
|
+
(e) => {
|
|
13
|
+
if (instance.parent.model.readOnly) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
e.preventDefault();
|
|
17
|
+
instance.focus(true);
|
|
18
|
+
},
|
|
19
|
+
[instance],
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (mktRef.current) {
|
|
24
|
+
mktRef.current.innerHTML = instance.markdownParser.render(instance.model.value, {
|
|
25
|
+
cellId: instance.model.id,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}, [instance, instance.model.value]);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div className="libro-markdown-warpper-container" onDoubleClick={enterEdit}>
|
|
32
|
+
<div className="libro-markdown-preview" ref={mktRef} />
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
};
|