@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.
@@ -5,141 +5,135 @@
5
5
  * 作者: chenyomi
6
6
  */
7
7
 
8
- import { DragEvent, PointerEvent, WatchEvent } from 'leafer-ui';
9
- import { EditTool, Editor, registerEditTool, EditorScaleEvent, EditorMoveEvent } from '@leafer-in/editor';
10
- import { updataHtmlText } from '../utils';
11
- import { TextEditor } from '../TextEditor';
12
-
13
- // 简单的防抖函数实现
14
- function debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void {
15
- let timeout: ReturnType<typeof setTimeout> | null = null;
16
- return function(this: any, ...args: Parameters<T>) {
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 'TextEditTool';
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
- if (!this.editor?.element) return;
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('#textInnerEditor');
49
-
50
- if (!div) return;
51
-
58
+ const div: any = document.querySelector("#textInnerEditor");
52
59
  const { style } = div;
53
-
54
60
  this.eventIds = [
55
- this.editor.on_(EditorScaleEvent.SCALE, (e: any) => {
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 && text.parent) {
61
- const parentWidth = text.parent.width;
62
- if (parentWidth !== undefined) {
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
- this.editor.on_(PointerEvent.DOUBLE_TAP, () => {
70
- if (!text.parent?.locked) {
71
- this.editor.openInnerEditor(text, true);
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
- if (!this.editor?.element) return;
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.editBox.add(this.view);
88
-
89
- this.quill = TextEditor.quill;
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?.canChangeBox && text.parent) {
100
- const parentWidth = text.parent.width;
101
- const parentHeight = text.parent.height;
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 = 'auto';
110
- style.height = 'auto';
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
- if (text && text.__layout?.boxBounds) {
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
- if (!this.editor?.element) return;
128
-
129
- const text = this.editor.element.findOne('HTMLText');
130
- if (!text) return;
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
- // 记录上一次的 curveAmount,只有变化时才触发
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
- this.editor.off_(this.eventIds);
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 { Text, Box, Path } from 'leafer-ui'
2
- import { HTMLText } from '@leafer-in/html' // 导入 html 插件
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': '⁰','1': '¹','2': '²','3': '³','4': '⁴','5': '⁵','6': '⁶','7': '⁷','8': '⁸','9': '⁹',
86
- a: '', b: '', c: 'ᶜ', d: 'ᵈ', e: 'ᵉ', f: 'ᶠ', g: 'ᵍ', h: 'ʰ', i: 'ⁱ', j: 'ʲ', k: 'ᵏ',
87
- l: 'ˡ', m: '', n: 'ⁿ', o: 'ᵒ', p: 'ᵖ', r: 'ʳ', s: 'ˢ', t: 'ᵗ', u: 'ᵘ', v: 'ᵛ', w: 'ʷ',
88
- x: 'ˣ', y: 'ʸ', z: 'ᶻ',
89
- A: '', B: '', D: 'ᴰ', E: 'ᴱ', G: 'ᴳ', H: 'ᴴ', I: 'ᴵ', J: 'ᴶ', K: 'ᴷ', L: 'ᴸ', M: 'ᴹ',
90
- N: '', O: '', P: 'ᴾ', R: 'ᴿ', T: 'ᵀ', U: 'ᵁ', W: 'ᵂ',
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': '₀','1': '₁','2': '₂','3': '₃','4': '₄','5': '₅','6': '₆','7': '₇','8': '₈','9': '₉',
96
- a: '', e: '', h: 'ₕ', i: 'ᵢ', j: 'ⱼ', k: 'ₖ', l: 'ₗ', m: 'ₘ', n: 'ₙ', o: 'ₒ', p: 'ₚ',
97
- r: '', s: '', t: 'ₜ', u: 'ᵤ', v: 'ᵥ', x: 'ₓ',
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
-