@8btc/mditor 0.0.8 → 0.0.9
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/index.css +53 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +506 -158
- package/dist/index.min.js +1 -1
- package/dist/method.js +6 -6
- package/dist/method.min.js +1 -1
- package/dist/ts/util/editorCommonEvent.d.ts +3 -2
- package/dist/ts/wysiwyg/index.d.ts +29 -0
- package/dist/types/index.d.ts +18 -2
- package/package.json +1 -1
- package/src/assets/less/_selection-popover.less +148 -0
- package/src/assets/less/_selection-tag.less +38 -0
- package/src/assets/less/index.less +2 -0
- package/src/index.ts +9 -4
- package/src/method.ts +1 -1
- package/src/ts/ir/index.ts +1 -1
- package/src/ts/ir/process.ts +1 -1
- package/src/ts/markdown/selectionRender.ts +28 -0
- package/src/ts/preview/index.ts +6 -5
- package/src/ts/sv/index.ts +1 -1
- package/src/ts/sv/process.ts +1 -1
- package/src/ts/ui/initUI.ts +4 -2
- package/src/ts/util/Options.ts +8 -1
- package/src/ts/util/editorCommonEvent.ts +296 -184
- package/src/ts/util/processCode.ts +43 -24
- package/src/ts/wysiwyg/afterRenderEvent.ts +1 -1
- package/src/ts/wysiwyg/index.ts +509 -119
- package/src/ts/wysiwyg/renderDomByMd.ts +1 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
@selection-popover-radius: 8px;
|
|
2
|
+
@selection-popover-padding: 4px;
|
|
3
|
+
@selection-popover-gap: 0px;
|
|
4
|
+
@selection-popover-shadow: var(--panel-shadow);
|
|
5
|
+
@selection-popover-bg: var(--panel-background-color);
|
|
6
|
+
@selection-popover-color: var(--textarea-text-color);
|
|
7
|
+
@selection-popover-hover-color: var(--toolbar-icon-hover-color);
|
|
8
|
+
|
|
9
|
+
.vditor-selection-popover {
|
|
10
|
+
position: absolute;
|
|
11
|
+
z-index: 4;
|
|
12
|
+
display: none;
|
|
13
|
+
padding: 0;
|
|
14
|
+
border-radius: @selection-popover-radius;
|
|
15
|
+
background-color: @selection-popover-bg;
|
|
16
|
+
box-shadow: @selection-popover-shadow;
|
|
17
|
+
border: 1px solid var(--border-color);
|
|
18
|
+
user-select: none;
|
|
19
|
+
white-space: nowrap;
|
|
20
|
+
transform-origin: top left;
|
|
21
|
+
opacity: 0;
|
|
22
|
+
transition: opacity 150ms cubic-bezier(0.2, 0, 0.13, 1.5),
|
|
23
|
+
transform 150ms cubic-bezier(0.2, 0, 0.13, 1.5);
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
flex-wrap: nowrap;
|
|
26
|
+
|
|
27
|
+
&__actions {
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-direction: row;
|
|
30
|
+
align-items: center;
|
|
31
|
+
width: 100%;
|
|
32
|
+
border-bottom: 1px solid var(--border-color);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&__input {
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-direction: column;
|
|
38
|
+
width: 327px;
|
|
39
|
+
padding: 12px;
|
|
40
|
+
gap: 8px;
|
|
41
|
+
align-items: flex-end;
|
|
42
|
+
box-sizing: border-box;
|
|
43
|
+
|
|
44
|
+
textarea {
|
|
45
|
+
flex: 1;
|
|
46
|
+
width: 100%;
|
|
47
|
+
height: 60px;
|
|
48
|
+
background: transparent;
|
|
49
|
+
border: none;
|
|
50
|
+
resize: none;
|
|
51
|
+
outline: none;
|
|
52
|
+
color: @selection-popover-color;
|
|
53
|
+
font-size: 14px;
|
|
54
|
+
line-height: 20px;
|
|
55
|
+
padding: 0;
|
|
56
|
+
margin: 0;
|
|
57
|
+
|
|
58
|
+
&::placeholder {
|
|
59
|
+
color: #585a5a;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.vditor-selection-popover__send {
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
justify-content: center;
|
|
67
|
+
width: 32px;
|
|
68
|
+
height: 32px;
|
|
69
|
+
border: none;
|
|
70
|
+
background: var(--toolbar-icon-hover-color);
|
|
71
|
+
border-radius: 8px;
|
|
72
|
+
color: #fff;
|
|
73
|
+
cursor: pointer;
|
|
74
|
+
padding: 0;
|
|
75
|
+
transition: opacity 0.2s;
|
|
76
|
+
|
|
77
|
+
&:hover {
|
|
78
|
+
opacity: 0.8;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
&[disabled] {
|
|
82
|
+
opacity: 0.5;
|
|
83
|
+
cursor: not-allowed;
|
|
84
|
+
pointer-events: none;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
&--loading {
|
|
88
|
+
pointer-events: none;
|
|
89
|
+
opacity: 0.8;
|
|
90
|
+
|
|
91
|
+
svg {
|
|
92
|
+
animation: vditor-rotate 1s linear infinite;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
svg {
|
|
97
|
+
width: 16px;
|
|
98
|
+
height: 16px;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@keyframes vditor-rotate {
|
|
104
|
+
from {
|
|
105
|
+
transform: rotate(0deg);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
to {
|
|
109
|
+
transform: rotate(360deg);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
&__btn {
|
|
114
|
+
display: flex;
|
|
115
|
+
align-items: center;
|
|
116
|
+
justify-content: center;
|
|
117
|
+
height: 32px;
|
|
118
|
+
width: 109px;
|
|
119
|
+
flex: 0 0 109px;
|
|
120
|
+
box-sizing: border-box;
|
|
121
|
+
white-space: nowrap;
|
|
122
|
+
margin: 0 @selection-popover-gap;
|
|
123
|
+
border: none;
|
|
124
|
+
background: transparent;
|
|
125
|
+
color: @selection-popover-color;
|
|
126
|
+
cursor: pointer;
|
|
127
|
+
outline: none;
|
|
128
|
+
font-size: 14px;
|
|
129
|
+
font-weight: 500;
|
|
130
|
+
transition: @transition;
|
|
131
|
+
|
|
132
|
+
&:hover,
|
|
133
|
+
&:focus {
|
|
134
|
+
color: @selection-popover-hover-color;
|
|
135
|
+
background-color: transparent;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&[disabled] {
|
|
139
|
+
opacity: 0.9;
|
|
140
|
+
cursor: not-allowed;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
&__btn+&__btn {
|
|
145
|
+
border-left: 1px solid var(--border-color);
|
|
146
|
+
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Selection tag styles - 参考代码块样式
|
|
2
|
+
.vditor-reset .vditor-selection-tag {
|
|
3
|
+
display: inline-flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
gap: 0.31rem;
|
|
6
|
+
padding: 0.25rem 0.5rem;
|
|
7
|
+
background-color: #f6f8fa;
|
|
8
|
+
border: 1px solid #d1d5da;
|
|
9
|
+
border-radius: 0.25rem;
|
|
10
|
+
font-size: 0.875rem;
|
|
11
|
+
line-height: 1.25rem;
|
|
12
|
+
color: @primaryColor;
|
|
13
|
+
font-family: @font-family-code;
|
|
14
|
+
margin: 0.25rem 0.25rem 0.25rem 0;
|
|
15
|
+
|
|
16
|
+
&__file {
|
|
17
|
+
color: @primaryColor;
|
|
18
|
+
font-weight: 500;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
&__lines {
|
|
22
|
+
color: #586069;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Dark mode
|
|
27
|
+
.vditor--dark .vditor-reset .vditor-selection-tag {
|
|
28
|
+
background-color: #2f363d;
|
|
29
|
+
border-color: #141414;
|
|
30
|
+
|
|
31
|
+
.vditor-selection-tag__file {
|
|
32
|
+
color: #fafafa;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.vditor-selection-tag__lines {
|
|
36
|
+
color: #b9b9b9;
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -203,8 +203,9 @@ class Vditor extends VditorMethod {
|
|
|
203
203
|
* - 依赖配置 `lineNumber: true`,关闭时直接跳过以提升性能
|
|
204
204
|
* @param immediate 为 true 时立即更新;默认为节流更新以避免频繁调用
|
|
205
205
|
*/
|
|
206
|
+
/** 手动更新行号 */
|
|
206
207
|
public updateLineNumbers(immediate = false) {
|
|
207
|
-
if (!this.vditor.options.lineNumber) {
|
|
208
|
+
if (!this.vditor.options.lineNumber?.enable) {
|
|
208
209
|
return;
|
|
209
210
|
}
|
|
210
211
|
const text = getMarkdown(this.vditor);
|
|
@@ -222,6 +223,7 @@ class Vditor extends VditorMethod {
|
|
|
222
223
|
* - 应用高亮样式并在约 500ms 后自动恢复
|
|
223
224
|
* @param numbers 要高亮的行号数组
|
|
224
225
|
*/
|
|
226
|
+
/** 高亮指定行号,时长受 `options.lineNumber.highlightTimer` 控制 */
|
|
225
227
|
public setLinehightNumbers(numbers: number[]) {
|
|
226
228
|
if (!Array.isArray(numbers)) {
|
|
227
229
|
return;
|
|
@@ -240,7 +242,10 @@ class Vditor extends VditorMethod {
|
|
|
240
242
|
if (nodeList.length === 0) {
|
|
241
243
|
return;
|
|
242
244
|
}
|
|
243
|
-
const duration =
|
|
245
|
+
const duration = Math.max(
|
|
246
|
+
0,
|
|
247
|
+
Number(this.vditor.options.lineNumber?.highlightTimer) || 1500
|
|
248
|
+
);
|
|
244
249
|
const apply = () => {
|
|
245
250
|
nodeList.forEach((el) => {
|
|
246
251
|
const old = lineHighlightTimers.get(el);
|
|
@@ -458,7 +463,7 @@ class Vditor extends VditorMethod {
|
|
|
458
463
|
public setValue(markdown: string, clearStack = false) {
|
|
459
464
|
if (this.vditor.currentMode === "sv") {
|
|
460
465
|
this.vditor.sv.element.innerHTML = `<div data-block='0'>${this.vditor.lute.SpinVditorSVDOM(markdown)}</div>`;
|
|
461
|
-
if (this.vditor.options.lineNumber) {
|
|
466
|
+
if (this.vditor.options.lineNumber?.enable) {
|
|
462
467
|
try {
|
|
463
468
|
attachLineNumbersToBlocks(
|
|
464
469
|
this.vditor.sv.element,
|
|
@@ -485,7 +490,7 @@ class Vditor extends VditorMethod {
|
|
|
485
490
|
.forEach((item: HTMLElement) => {
|
|
486
491
|
processCodeRender(item, this.vditor);
|
|
487
492
|
});
|
|
488
|
-
if (this.vditor.options.lineNumber) {
|
|
493
|
+
if (this.vditor.options.lineNumber?.enable) {
|
|
489
494
|
try {
|
|
490
495
|
attachLineNumbersToBlocks(
|
|
491
496
|
this.vditor.ir.element,
|
package/src/method.ts
CHANGED
|
@@ -77,7 +77,7 @@ class Vditor {
|
|
|
77
77
|
public static updateLineNumbers(instance: any, immediate = false) {
|
|
78
78
|
try {
|
|
79
79
|
const v = instance?.vditor ?? instance;
|
|
80
|
-
if (!v?.options?.lineNumber) return;
|
|
80
|
+
if (!v?.options?.lineNumber?.enable) return;
|
|
81
81
|
const text = getMarkdown(v);
|
|
82
82
|
const root = v[v.currentMode].element as HTMLElement;
|
|
83
83
|
if (immediate) {
|
package/src/ts/ir/index.ts
CHANGED
|
@@ -33,7 +33,7 @@ class IR {
|
|
|
33
33
|
constructor(vditor: IVditor) {
|
|
34
34
|
const divElement = document.createElement("div");
|
|
35
35
|
divElement.className = "vditor-ir";
|
|
36
|
-
if (vditor.options.lineNumber) {
|
|
36
|
+
if (vditor.options.lineNumber?.enable) {
|
|
37
37
|
divElement.classList.add("vditor--linenumber");
|
|
38
38
|
}
|
|
39
39
|
|
package/src/ts/ir/process.ts
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 渲染 selection 代码块为文件选择标签
|
|
3
|
+
*/
|
|
4
|
+
export const selectionRender = (element: HTMLElement) => {
|
|
5
|
+
element.querySelectorAll("pre > code.language-selection").forEach((codeElement: HTMLElement) => {
|
|
6
|
+
const preElement = codeElement.parentElement as HTMLElement;
|
|
7
|
+
const content = codeElement.textContent.trim();
|
|
8
|
+
const lines = content.split('\n');
|
|
9
|
+
|
|
10
|
+
const tags = lines.map(line => {
|
|
11
|
+
const match = line.trim().match(/^(.+?)\s+(\d+-\d+)$/);
|
|
12
|
+
if (match) {
|
|
13
|
+
const [, filename, lineRange] = match;
|
|
14
|
+
return `<div class="vditor-selection-tag">
|
|
15
|
+
<span class="vditor-selection-tag__file">${filename}</span>
|
|
16
|
+
<span class="vditor-selection-tag__lines">${lineRange}</span>
|
|
17
|
+
</div>`;
|
|
18
|
+
}
|
|
19
|
+
return '';
|
|
20
|
+
}).filter(tag => tag).join('');
|
|
21
|
+
|
|
22
|
+
if (tags) {
|
|
23
|
+
const container = document.createElement('div');
|
|
24
|
+
container.innerHTML = tags;
|
|
25
|
+
preElement.parentNode.replaceChild(container, preElement);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
};
|
package/src/ts/preview/index.ts
CHANGED
|
@@ -12,11 +12,9 @@ import { SMILESRender } from "../markdown/SMILESRender";
|
|
|
12
12
|
import { markmapRender } from "../markdown/markmapRender";
|
|
13
13
|
import { mindmapRender } from "../markdown/mindmapRender";
|
|
14
14
|
import { plantumlRender } from "../markdown/plantumlRender";
|
|
15
|
-
import {
|
|
16
|
-
hasClosestByClassName,
|
|
17
|
-
hasClosestByMatchTag,
|
|
18
|
-
} from "../util/hasClosest";
|
|
15
|
+
import { hasClosestByClassName, hasClosestByMatchTag } from "../util/hasClosest";
|
|
19
16
|
import { setSelectionFocus } from "../util/selection";
|
|
17
|
+
import { selectionRender } from "../markdown/selectionRender";
|
|
20
18
|
import { previewImage } from "./image";
|
|
21
19
|
|
|
22
20
|
export class Preview {
|
|
@@ -247,8 +245,11 @@ export class Preview {
|
|
|
247
245
|
if (vditor.options.preview.render.media.enable) {
|
|
248
246
|
mediaRender(vditor.preview.previewElement);
|
|
249
247
|
}
|
|
248
|
+
selectionRender(vditor.preview.previewElement);
|
|
250
249
|
vditor.options.customRenders.forEach((item) => {
|
|
251
|
-
|
|
250
|
+
{
|
|
251
|
+
item.render(vditor.preview.previewElement, vditor);
|
|
252
|
+
}
|
|
252
253
|
});
|
|
253
254
|
// toc render
|
|
254
255
|
const editorElement = vditor.preview.element;
|
package/src/ts/sv/index.ts
CHANGED
|
@@ -24,7 +24,7 @@ class Editor {
|
|
|
24
24
|
constructor(vditor: IVditor) {
|
|
25
25
|
this.element = document.createElement("pre");
|
|
26
26
|
this.element.className = "vditor-sv vditor-reset";
|
|
27
|
-
if (vditor.options.lineNumber) {
|
|
27
|
+
if (vditor.options.lineNumber?.enable) {
|
|
28
28
|
this.element.classList.add("vditor--linenumber");
|
|
29
29
|
}
|
|
30
30
|
this.element.setAttribute("placeholder", vditor.options.placeholder);
|
package/src/ts/sv/process.ts
CHANGED
|
@@ -178,7 +178,7 @@ export const processAfterRender = (
|
|
|
178
178
|
vditor.undo.addToUndoStack(vditor);
|
|
179
179
|
}
|
|
180
180
|
try {
|
|
181
|
-
if (vditor.options.lineNumber) {
|
|
181
|
+
if (vditor.options.lineNumber?.enable) {
|
|
182
182
|
attachLineNumbersToBlocksThrottled(vditor.sv.element, text);
|
|
183
183
|
}
|
|
184
184
|
} catch {
|
package/src/ts/ui/initUI.ts
CHANGED
|
@@ -121,7 +121,8 @@ export const setPadding = (vditor: IVditor) => {
|
|
|
121
121
|
vditor.options.preview.maxWidth) /
|
|
122
122
|
2;
|
|
123
123
|
const basePad = Math.max(minPadding, padding);
|
|
124
|
-
const leftExtra =
|
|
124
|
+
const leftExtra =
|
|
125
|
+
vditor.options.lineNumber?.enable && basePad < 40 ? 20 : 0;
|
|
125
126
|
vditor.wysiwyg.element.style.padding = `10px ${basePad}px 10px ${basePad + leftExtra}px`;
|
|
126
127
|
}
|
|
127
128
|
|
|
@@ -131,7 +132,8 @@ export const setPadding = (vditor: IVditor) => {
|
|
|
131
132
|
vditor.options.preview.maxWidth) /
|
|
132
133
|
2;
|
|
133
134
|
const basePad = Math.max(minPadding, padding);
|
|
134
|
-
const leftExtra =
|
|
135
|
+
const leftExtra =
|
|
136
|
+
vditor.options.lineNumber?.enable && basePad < 40 ? 20 : 0;
|
|
135
137
|
vditor.ir.element.style.padding = `10px ${basePad}px 10px ${basePad + leftExtra}px`;
|
|
136
138
|
}
|
|
137
139
|
|
package/src/ts/util/Options.ts
CHANGED
|
@@ -9,6 +9,10 @@ export class Options {
|
|
|
9
9
|
inlinePopover: {
|
|
10
10
|
enable: false,
|
|
11
11
|
},
|
|
12
|
+
selectionPopover: {
|
|
13
|
+
enable: false,
|
|
14
|
+
debounceDelay: 150,
|
|
15
|
+
},
|
|
12
16
|
cache: {
|
|
13
17
|
enable: true,
|
|
14
18
|
},
|
|
@@ -118,7 +122,10 @@ export class Options {
|
|
|
118
122
|
pin: false,
|
|
119
123
|
},
|
|
120
124
|
typewriterMode: false,
|
|
121
|
-
lineNumber:
|
|
125
|
+
lineNumber: {
|
|
126
|
+
enable: false,
|
|
127
|
+
highlightTimer: 1500,
|
|
128
|
+
},
|
|
122
129
|
undoDelay: 800,
|
|
123
130
|
upload: {
|
|
124
131
|
extraData: {},
|