@chenyomi/leafer-htmltext-editor 1.0.0 → 1.0.1
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/TextEditTool/index.d.ts +2 -1
- package/dist/TextEditTool/index.d.ts.map +1 -1
- package/dist/TextEditTool/index.js +43 -69
- package/dist/TextEditTool/utils.d.ts.map +1 -1
- package/dist/TextEditTool/utils.js +96 -13
- package/dist/TextEditor.d.ts +9 -6
- package/dist/TextEditor.d.ts.map +1 -1
- package/dist/TextEditor.js +65 -63
- package/dist/esm/TextEditTool/index.d.ts +2 -1
- package/dist/esm/TextEditTool/index.d.ts.map +1 -1
- package/dist/esm/TextEditTool/index.js +45 -71
- package/dist/esm/TextEditTool/utils.d.ts.map +1 -1
- package/dist/esm/TextEditTool/utils.js +96 -13
- package/dist/esm/TextEditor.d.ts +9 -6
- package/dist/esm/TextEditor.d.ts.map +1 -1
- package/dist/esm/TextEditor.js +65 -63
- package/dist/esm/index.d.ts +17 -6
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/utils.d.ts +1 -1
- package/dist/esm/utils.d.ts.map +1 -1
- package/dist/esm/utils.js +29 -48
- package/dist/index.d.ts +17 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +134 -77
- package/dist/index.js +168 -87
- package/dist/utils.d.ts +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +29 -48
- package/package.json +3 -3
- package/src/TextEditTool/index.ts +78 -84
- package/src/TextEditTool/utils.ts +101 -29
- package/src/TextEditor.ts +103 -90
- package/src/index.ts +145 -83
- package/src/utils.ts +140 -178
|
@@ -5,141 +5,135 @@
|
|
|
5
5
|
* 作者: chenyomi
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (timeout) clearTimeout(timeout);
|
|
18
|
-
timeout = setTimeout(() => func.apply(this, args), wait);
|
|
19
|
-
};
|
|
20
|
-
}
|
|
8
|
+
// #图形编辑器 [自定义编辑工具]
|
|
9
|
+
import {
|
|
10
|
+
EditTool,
|
|
11
|
+
EditorScaleEvent,
|
|
12
|
+
registerEditTool,
|
|
13
|
+
} from "@leafer-in/editor";
|
|
14
|
+
import { PointerEvent } from "leafer-ui";
|
|
15
|
+
import { quillManager } from "../index";
|
|
16
|
+
import { updataHtmlText } from "../utils";
|
|
21
17
|
|
|
22
18
|
@registerEditTool()
|
|
19
|
+
// 定义插件类,继承自 EditTool,处理矩形圆角编辑交互
|
|
23
20
|
export class TextEditTool extends EditTool {
|
|
21
|
+
// 插件标识标签
|
|
24
22
|
public get tag() {
|
|
25
|
-
return
|
|
23
|
+
return "TextEditTool";
|
|
26
24
|
}
|
|
27
|
-
|
|
28
25
|
public quill: any = null;
|
|
29
|
-
private _dragRAF: number | null = null;
|
|
26
|
+
private _dragRAF: number | null = null; // 用于 requestAnimationFrame 节流拖拽事件
|
|
30
27
|
private updateBoxDebounced: (text: any) => void;
|
|
31
|
-
|
|
28
|
+
// 构造函数,初始化控制点并加入视图
|
|
32
29
|
constructor(editor: any) {
|
|
33
30
|
super(editor);
|
|
34
|
-
this.eventIds = [];
|
|
35
|
-
this.updateBoxDebounced = debounce((text: any) => {
|
|
31
|
+
this.eventIds = []; // 存储事件绑定ID
|
|
32
|
+
this.updateBoxDebounced = this.debounce((text: any) => {
|
|
36
33
|
updataHtmlText(text);
|
|
37
34
|
}, 300);
|
|
38
35
|
}
|
|
39
|
-
|
|
36
|
+
// 自定义防抖函数替代 lodash/debounce
|
|
37
|
+
private debounce<T extends (...args: any[]) => any>(
|
|
38
|
+
func: T,
|
|
39
|
+
wait: number,
|
|
40
|
+
): T {
|
|
41
|
+
let timeout: number | null = null;
|
|
42
|
+
return ((...args: any[]) => {
|
|
43
|
+
if (timeout !== null) {
|
|
44
|
+
window.clearTimeout(timeout);
|
|
45
|
+
}
|
|
46
|
+
timeout = window.setTimeout(
|
|
47
|
+
() => func.apply(this, args),
|
|
48
|
+
wait,
|
|
49
|
+
) as unknown as number;
|
|
50
|
+
}) as T;
|
|
51
|
+
}
|
|
52
|
+
// 绑定事件
|
|
40
53
|
public addEvent(): void {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const text = this.editor.element.findOne('HTMLText');
|
|
44
|
-
if (!text) return;
|
|
45
|
-
|
|
54
|
+
const { editor } = quillManager.getCanvas();
|
|
55
|
+
const text = editor._target.findOne("HTMLText");
|
|
46
56
|
const { scaleX, scaleY } = text.worldTransform;
|
|
47
57
|
const zoomScale = Math.max(Math.abs(scaleX), Math.abs(scaleY));
|
|
48
|
-
const div: any = document.querySelector(
|
|
49
|
-
|
|
50
|
-
if (!div) return;
|
|
51
|
-
|
|
58
|
+
const div: any = document.querySelector("#textInnerEditor");
|
|
52
59
|
const { style } = div;
|
|
53
|
-
|
|
54
60
|
this.eventIds = [
|
|
55
|
-
|
|
56
|
-
if (!text.data) text.data = {};
|
|
61
|
+
editor.on_(EditorScaleEvent.SCALE, (e: any) => {
|
|
57
62
|
if (!text.data.canChangeBox) {
|
|
58
63
|
text.data.canChangeBox = true;
|
|
59
64
|
}
|
|
60
|
-
if (text.data.canChangeBox
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
style.width = parentWidth * zoomScale + 'px';
|
|
64
|
-
style.height = 'auto';
|
|
65
|
-
}
|
|
65
|
+
if (text.data.canChangeBox) {
|
|
66
|
+
style.width = text.parent.width * zoomScale + "px";
|
|
67
|
+
style.height = "auto";
|
|
66
68
|
}
|
|
67
69
|
this.updateBoxDebounced(text);
|
|
68
70
|
}),
|
|
69
|
-
|
|
70
|
-
if (!text.parent
|
|
71
|
-
|
|
71
|
+
editor.on_(PointerEvent.DOUBLE_TAP, () => {
|
|
72
|
+
if (!text.parent.locked) {
|
|
73
|
+
editor.openInnerEditor(text, true);
|
|
72
74
|
}
|
|
73
|
-
})
|
|
75
|
+
}),
|
|
74
76
|
];
|
|
75
77
|
}
|
|
76
78
|
|
|
79
|
+
// 生命周期钩子:插件加载时绑定事件
|
|
77
80
|
public onLoad(): void {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const text: any = this.editor.element.findOne('HTMLText');
|
|
81
|
-
if (!text) return;
|
|
82
|
-
|
|
81
|
+
const { editor } = quillManager.getCanvas();
|
|
82
|
+
const text: any = editor._target.findOne("HTMLText");
|
|
83
83
|
const { scaleX, scaleY } = text.worldTransform;
|
|
84
84
|
const zoomScale = Math.max(Math.abs(scaleX), Math.abs(scaleY));
|
|
85
|
-
|
|
86
85
|
this.addEvent();
|
|
87
|
-
this.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (this.quill && text.text) {
|
|
91
|
-
this.quill.clipboard.dangerouslyPasteHTML(text.text);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const div: any = document.querySelector('#textInnerEditor');
|
|
95
|
-
if (!div) return;
|
|
96
|
-
|
|
86
|
+
this.quill = quillManager.getQuill();
|
|
87
|
+
this.quill.clipboard.dangerouslyPasteHTML(text.text);
|
|
88
|
+
const div: any = document.querySelector("#textInnerEditor");
|
|
97
89
|
const { style } = div;
|
|
98
90
|
|
|
99
|
-
if (text.data
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (parentWidth !== undefined) {
|
|
103
|
-
style.width = parentWidth * zoomScale + 'px';
|
|
104
|
-
}
|
|
105
|
-
if (parentHeight !== undefined) {
|
|
106
|
-
style.height = parentHeight * zoomScale + 'px';
|
|
107
|
-
}
|
|
91
|
+
if (text.data.canChangeBox) {
|
|
92
|
+
style.width = text.parent.width * zoomScale + "px";
|
|
93
|
+
style.height = text.parent.height * zoomScale + "px";
|
|
108
94
|
} else {
|
|
109
|
-
style.width =
|
|
110
|
-
style.height =
|
|
95
|
+
style.width = "auto";
|
|
96
|
+
style.height = "auto";
|
|
111
97
|
}
|
|
98
|
+
// 每次进来就恢复初始的 canChangeBox 和 自动的宽高
|
|
99
|
+
// text.set({
|
|
100
|
+
// width: 0,
|
|
101
|
+
// height: 0
|
|
102
|
+
// })
|
|
103
|
+
// text.data.canChangeBox = false
|
|
112
104
|
}
|
|
113
105
|
|
|
114
106
|
private isUpdatingPoints = false;
|
|
115
107
|
private curveAmount = 0;
|
|
116
|
-
|
|
117
108
|
public updateChangeBoxBound(text: any): void {
|
|
118
|
-
|
|
109
|
+
text &&
|
|
119
110
|
text.set({
|
|
120
111
|
width: text.__layout.boxBounds.width,
|
|
121
|
-
height: text.__layout.boxBounds.height
|
|
112
|
+
height: text.__layout.boxBounds.height,
|
|
122
113
|
});
|
|
123
|
-
}
|
|
124
114
|
}
|
|
125
|
-
|
|
115
|
+
// 生命周期钩子:插件更新时,因为这是全局的生命周期所以判断一定要细致仔细
|
|
126
116
|
public onUpdate(): void {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const el = this.editor.element;
|
|
133
|
-
console.log('文本bound更新');
|
|
117
|
+
const { editor } = quillManager.getCanvas();
|
|
118
|
+
const text = editor._target.findOne("HTMLText");
|
|
119
|
+
const el = editor._target;
|
|
120
|
+
console.log("文本bound更新");
|
|
134
121
|
|
|
135
|
-
|
|
136
|
-
if (this.curveAmount === (text as any).curveAmount) return;
|
|
122
|
+
if (this.curveAmount == (text as any).curveAmount) return;
|
|
137
123
|
if (this.isUpdatingPoints) return;
|
|
124
|
+
// 每次进来就恢复初始的 canChangeBox 和 自动的宽高
|
|
125
|
+
// text.set({
|
|
126
|
+
// width: 0,
|
|
127
|
+
// height: 0
|
|
128
|
+
// })
|
|
138
129
|
}
|
|
139
130
|
|
|
131
|
+
// 生命周期钩子:插件卸载时解绑事件
|
|
140
132
|
public onUnload(): void {
|
|
141
|
-
|
|
133
|
+
const { editor } = quillManager.getCanvas();
|
|
134
|
+
editor.off_(this.eventIds);
|
|
142
135
|
}
|
|
143
136
|
|
|
137
|
+
// 生命周期钩子:销毁插件时清理资源
|
|
144
138
|
public onDestroy(): void {}
|
|
145
139
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { HTMLText } from '@leafer-in/html'; // 导入 html 插件
|
|
2
|
+
import { Box, Path } from 'leafer-ui'
|
|
3
3
|
export function getArcRadius(fontSize: number, curveAmount: number): number {
|
|
4
4
|
if (curveAmount === 0) return Infinity
|
|
5
5
|
const theta = (330 * fontSize * 72) / 96
|
|
@@ -82,22 +82,105 @@ export const handleShowCurve = (element: any, op: boolean) => {
|
|
|
82
82
|
|
|
83
83
|
// base 映射:只需把普通字符 -> 上标/下标(任意已有的上/下标字符)列出来一次
|
|
84
84
|
const baseSuperscript: Record<string, string> = {
|
|
85
|
-
'0': '⁰',
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
'
|
|
85
|
+
'0': '⁰',
|
|
86
|
+
'1': '¹',
|
|
87
|
+
'2': '²',
|
|
88
|
+
'3': '³',
|
|
89
|
+
'4': '⁴',
|
|
90
|
+
'5': '⁵',
|
|
91
|
+
'6': '⁶',
|
|
92
|
+
'7': '⁷',
|
|
93
|
+
'8': '⁸',
|
|
94
|
+
'9': '⁹',
|
|
95
|
+
a: 'ᵃ',
|
|
96
|
+
b: 'ᵇ',
|
|
97
|
+
c: 'ᶜ',
|
|
98
|
+
d: 'ᵈ',
|
|
99
|
+
e: 'ᵉ',
|
|
100
|
+
f: 'ᶠ',
|
|
101
|
+
g: 'ᵍ',
|
|
102
|
+
h: 'ʰ',
|
|
103
|
+
i: 'ⁱ',
|
|
104
|
+
j: 'ʲ',
|
|
105
|
+
k: 'ᵏ',
|
|
106
|
+
l: 'ˡ',
|
|
107
|
+
m: 'ᵐ',
|
|
108
|
+
n: 'ⁿ',
|
|
109
|
+
o: 'ᵒ',
|
|
110
|
+
p: 'ᵖ',
|
|
111
|
+
r: 'ʳ',
|
|
112
|
+
s: 'ˢ',
|
|
113
|
+
t: 'ᵗ',
|
|
114
|
+
u: 'ᵘ',
|
|
115
|
+
v: 'ᵛ',
|
|
116
|
+
w: 'ʷ',
|
|
117
|
+
x: 'ˣ',
|
|
118
|
+
y: 'ʸ',
|
|
119
|
+
z: 'ᶻ',
|
|
120
|
+
A: 'ᴬ',
|
|
121
|
+
B: 'ᴮ',
|
|
122
|
+
D: 'ᴰ',
|
|
123
|
+
E: 'ᴱ',
|
|
124
|
+
G: 'ᴳ',
|
|
125
|
+
H: 'ᴴ',
|
|
126
|
+
I: 'ᴵ',
|
|
127
|
+
J: 'ᴶ',
|
|
128
|
+
K: 'ᴷ',
|
|
129
|
+
L: 'ᴸ',
|
|
130
|
+
M: 'ᴹ',
|
|
131
|
+
N: 'ᴺ',
|
|
132
|
+
O: 'ᴼ',
|
|
133
|
+
P: 'ᴾ',
|
|
134
|
+
R: 'ᴿ',
|
|
135
|
+
T: 'ᵀ',
|
|
136
|
+
U: 'ᵁ',
|
|
137
|
+
W: 'ᵂ',
|
|
138
|
+
'+': '⁺',
|
|
139
|
+
'-': '⁻',
|
|
140
|
+
'=': '⁼',
|
|
141
|
+
'(': '⁽',
|
|
142
|
+
')': '⁾'
|
|
92
143
|
}
|
|
93
144
|
|
|
94
145
|
const baseSubscript: Record<string, string> = {
|
|
95
|
-
'0': '₀',
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
'
|
|
146
|
+
'0': '₀',
|
|
147
|
+
'1': '₁',
|
|
148
|
+
'2': '₂',
|
|
149
|
+
'3': '₃',
|
|
150
|
+
'4': '₄',
|
|
151
|
+
'5': '₅',
|
|
152
|
+
'6': '₆',
|
|
153
|
+
'7': '₇',
|
|
154
|
+
'8': '₈',
|
|
155
|
+
'9': '₉',
|
|
156
|
+
a: 'ₐ',
|
|
157
|
+
e: 'ₑ',
|
|
158
|
+
h: 'ₕ',
|
|
159
|
+
i: 'ᵢ',
|
|
160
|
+
j: 'ⱼ',
|
|
161
|
+
k: 'ₖ',
|
|
162
|
+
l: 'ₗ',
|
|
163
|
+
m: 'ₘ',
|
|
164
|
+
n: 'ₙ',
|
|
165
|
+
o: 'ₒ',
|
|
166
|
+
p: 'ₚ',
|
|
167
|
+
r: 'ᵣ',
|
|
168
|
+
s: 'ₛ',
|
|
169
|
+
t: 'ₜ',
|
|
170
|
+
u: 'ᵤ',
|
|
171
|
+
v: 'ᵥ',
|
|
172
|
+
x: 'ₓ',
|
|
173
|
+
'+': '₊',
|
|
174
|
+
'-': '₋',
|
|
175
|
+
'=': '₌',
|
|
176
|
+
'(': '₍',
|
|
177
|
+
')': '₎',
|
|
99
178
|
// 常见希腊字母的下标形式(如需要可加入)
|
|
100
|
-
|
|
179
|
+
β: 'ᵦ',
|
|
180
|
+
γ: 'ᵧ',
|
|
181
|
+
ρ: 'ᵨ',
|
|
182
|
+
φ: 'ᵩ',
|
|
183
|
+
χ: 'ᵪ'
|
|
101
184
|
}
|
|
102
185
|
|
|
103
186
|
// helper: 从 base 映射中收集所有已知上标/下标字符(用于反向映射)
|
|
@@ -110,13 +193,10 @@ function invertMap(map: Record<string, string>): Record<string, string> {
|
|
|
110
193
|
}
|
|
111
194
|
|
|
112
195
|
const knownSupers = invertMap(baseSuperscript) // '¹' -> '¹', 'ᵃ'->'ᵃ' ...
|
|
113
|
-
const knownSubs = invertMap(baseSubscript)
|
|
196
|
+
const knownSubs = invertMap(baseSubscript) // '₁' -> '₁', 'ₐ'->'ₐ' ...
|
|
114
197
|
|
|
115
198
|
// 生成最终的“鲁棒”映射:接受普通字符、上标字符、下标字符,统一输出目标形式
|
|
116
|
-
function buildSuperscriptMap(
|
|
117
|
-
baseSup: Record<string, string>,
|
|
118
|
-
baseSub: Record<string, string>
|
|
119
|
-
): Record<string, string> {
|
|
199
|
+
function buildSuperscriptMap(baseSup: Record<string, string>, baseSub: Record<string, string>): Record<string, string> {
|
|
120
200
|
const out: Record<string, string> = {}
|
|
121
201
|
|
|
122
202
|
// 普通字符 -> 上标
|
|
@@ -136,10 +216,7 @@ function buildSuperscriptMap(
|
|
|
136
216
|
return out
|
|
137
217
|
}
|
|
138
218
|
|
|
139
|
-
function buildSubscriptMap(
|
|
140
|
-
baseSup: Record<string, string>,
|
|
141
|
-
baseSub: Record<string, string>
|
|
142
|
-
): Record<string, string> {
|
|
219
|
+
function buildSubscriptMap(baseSup: Record<string, string>, baseSub: Record<string, string>): Record<string, string> {
|
|
143
220
|
const out: Record<string, string> = {}
|
|
144
221
|
|
|
145
222
|
// 普通字符 -> 下标
|
|
@@ -177,16 +254,12 @@ export function toSubscript(input: string): string {
|
|
|
177
254
|
return out
|
|
178
255
|
}
|
|
179
256
|
|
|
180
|
-
|
|
181
257
|
export const superscriptMapVal = Object.values(superscriptMap)
|
|
182
258
|
|
|
183
259
|
export const subscriptMapVal = Object.values(subscriptMap)
|
|
184
260
|
|
|
185
261
|
// 构建 normalMap:所有上标、下标字符 → 对应的普通 base 字符
|
|
186
|
-
function buildNormalMap(
|
|
187
|
-
baseSup: Record<string, string>,
|
|
188
|
-
baseSub: Record<string, string>
|
|
189
|
-
): Record<string, string> {
|
|
262
|
+
function buildNormalMap(baseSup: Record<string, string>, baseSub: Record<string, string>): Record<string, string> {
|
|
190
263
|
const normal: Record<string, string> = {}
|
|
191
264
|
|
|
192
265
|
// 上标的 value → key(普通)
|
|
@@ -213,4 +286,3 @@ export function toNormal(input: string): string {
|
|
|
213
286
|
}
|
|
214
287
|
return out
|
|
215
288
|
}
|
|
216
|
-
|