@hprint/plugins 0.0.8 → 0.0.9-alpha.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAwC5D,QAAA,MAAM,aAAa,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAAA;CAqCjD,CAAC;AAGF,QAAA,MAAM,WAAW,EAAE,YAAY,EAqC9B,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AA0C5D,QAAA,MAAM,aAAa,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAAA;CAuCjD,CAAC;AAGF,QAAA,MAAM,WAAW,EAAE,YAAY,EAuC9B,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { fabric, IEditor, IPluginTempl } from '@hprint/core';
2
+ export interface ActualContentLayoutSettings {
3
+ actualContentLayout?: boolean;
4
+ overflowMode?: 'clip' | 'expand';
5
+ }
6
+ type IPlugin = Pick<ActualContentLayoutPlugin, 'applyActualContentLayout'>;
7
+ declare module '@hprint/core' {
8
+ interface IEditor extends IPlugin {
9
+ }
10
+ }
11
+ declare class ActualContentLayoutPlugin implements IPluginTempl {
12
+ canvas: fabric.Canvas;
13
+ editor: IEditor;
14
+ static pluginName: string;
15
+ static apis: string[];
16
+ constructor(canvas: fabric.Canvas, editor: IEditor);
17
+ private layoutOrigins;
18
+ hookTransformObjectEnd(...args: unknown[]): Promise<void>;
19
+ applyActualContentLayout(templateContent: any, templateHeight: number): number;
20
+ private getOriginalTop;
21
+ private getOriginalHeight;
22
+ private getOriginMmValue;
23
+ private preparePrintLayoutObject;
24
+ private isPrintableObject;
25
+ private isEmptyLayoutObject;
26
+ private getActualLayoutHeight;
27
+ }
28
+ export default ActualContentLayoutPlugin;
29
+ //# sourceMappingURL=ActualContentLayoutPlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActualContentLayoutPlugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/ActualContentLayoutPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE1D,MAAM,WAAW,2BAA2B;IACxC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;CACpC;AAED,KAAK,OAAO,GAAG,IAAI,CAAC,yBAAyB,EAAE,0BAA0B,CAAC,CAAC;AAE3E,OAAO,QAAQ,cAAc,CAAC;IAC1B,UAAU,OAAQ,SAAQ,OAAO;KAAG;CACvC;AASD,cAAM,yBAA0B,YAAW,YAAY;IAKxC,MAAM,EAAE,MAAM,CAAC,MAAM;IACrB,MAAM,EAAE,OAAO;IAL1B,MAAM,CAAC,UAAU,SAA+B;IAChD,MAAM,CAAC,IAAI,WAAgC;gBAGhC,MAAM,EAAE,MAAM,CAAC,MAAM,EACrB,MAAM,EAAE,OAAO;IAG1B,OAAO,CAAC,aAAa,CAGjB;IAEE,sBAAsB,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAkB/C,wBAAwB,CAAC,eAAe,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM;IA0GrE,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,gBAAgB;IAiBxB,OAAO,CAAC,wBAAwB;IAahC,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,mBAAmB;IAmB3B,OAAO,CAAC,qBAAqB;CAyBhC;AAED,eAAe,yBAAyB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"CopyPlugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/CopyPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAGtC,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE1D,KAAK,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AAEzC,OAAO,QAAQ,cAAc,CAAC;IAE1B,UAAU,OAAQ,SAAQ,OAAO;KAAG;CACvC;AAED,cAAM,UAAW,YAAW,YAAY;IAMzB,MAAM,EAAE,MAAM,CAAC,MAAM;IACrB,MAAM,EAAE,OAAO;IAN1B,MAAM,CAAC,UAAU,SAAgB;IACjC,MAAM,CAAC,IAAI,WAAa;IACxB,OAAO,EAAE,MAAM,EAAE,CAAwB;IACzC,OAAO,CAAC,KAAK,CAAuD;gBAEzD,MAAM,EAAE,MAAM,CAAC,MAAM,EACrB,MAAM,EAAE,OAAO;IAM1B,oBAAoB,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM;IAiChD,WAAW,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM;IA4BvC,KAAK,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,MAAM;IAYlE,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,aAAa;IAiB/C,WAAW;;;;;;IAcX,OAAO;IAKP,SAAS;IAIH,aAAa,CAAC,KAAK,EAAE,GAAG;CAwHjC;AAED,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"CopyPlugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/CopyPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAGtC,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE1D,KAAK,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AAEzC,OAAO,QAAQ,cAAc,CAAC;IAE1B,UAAU,OAAQ,SAAQ,OAAO;KAAG;CACvC;AAED,cAAM,UAAW,YAAW,YAAY;IAMzB,MAAM,EAAE,MAAM,CAAC,MAAM;IACrB,MAAM,EAAE,OAAO;IAN1B,MAAM,CAAC,UAAU,SAAgB;IACjC,MAAM,CAAC,IAAI,WAAa;IACxB,OAAO,EAAE,MAAM,EAAE,CAAwB;IACzC,OAAO,CAAC,KAAK,CAAuD;gBAEzD,MAAM,EAAE,MAAM,CAAC,MAAM,EACrB,MAAM,EAAE,OAAO;IAM1B,oBAAoB,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM;IAiChD,WAAW,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM;IA8BvC,KAAK,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,MAAM;IAYlE,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,aAAa;IAiB/C,WAAW;;;;;;IAcX,OAAO;IAKP,SAAS;IAIH,aAAa,CAAC,KAAK,EAAE,GAAG;CAwHjC;AAED,eAAe,UAAU,CAAC"}
@@ -0,0 +1,68 @@
1
+ import { fabric, IEditor, IPluginTempl } from '@hprint/core';
2
+ export type ImageTextListLayout = 'item-vertical' | 'icon-text-split' | 'icon-only' | 'text-only';
3
+ export interface ImageTextListItem {
4
+ src: string;
5
+ name: string;
6
+ }
7
+ export interface ImageTextListOptions {
8
+ items?: ImageTextListItem[];
9
+ _renderItems?: ImageTextListItem[];
10
+ _clipContent?: boolean;
11
+ layout?: ImageTextListLayout;
12
+ width?: number;
13
+ height?: number;
14
+ iconSize?: number;
15
+ horizontalGap?: number;
16
+ verticalGap?: number;
17
+ itemGap?: number;
18
+ fontFamily?: string;
19
+ fontSize?: number;
20
+ fontWeight?: string;
21
+ fontStyle?: string;
22
+ underline?: boolean | string;
23
+ linethrough?: boolean | string;
24
+ textAlign?: 'left' | 'center' | 'right' | 'justify';
25
+ textWrap?: boolean;
26
+ lineHeight?: number;
27
+ charSpacing?: number;
28
+ color?: string;
29
+ [key: string]: any;
30
+ }
31
+ type ImageTextListGroup = fabric.Group & {
32
+ extensionType?: string;
33
+ extension?: ImageTextListOptions;
34
+ _originSize?: Record<string, any>;
35
+ setExtension?: (fields: Record<string, any>) => Promise<void>;
36
+ setExtensionByUnit?: (fields: Record<string, any>) => Promise<void>;
37
+ setByUnit?: (field: string, value: any) => Promise<any>;
38
+ __imageTextListModified?: () => void;
39
+ };
40
+ type IPlugin = Pick<ImageTextListPlugin, 'createImageTextList' | 'initImageTextListEvents' | 'refreshImageTextList'>;
41
+ declare module '@hprint/core' {
42
+ interface IEditor extends IPlugin {
43
+ }
44
+ }
45
+ declare class ImageTextListPlugin implements IPluginTempl {
46
+ canvas: fabric.Canvas;
47
+ editor: IEditor;
48
+ static pluginName: string;
49
+ static apis: string[];
50
+ constructor(canvas: fabric.Canvas, editor: IEditor);
51
+ hookTransform(object: any): Promise<void>;
52
+ hookTransformObjectEnd(...args: unknown[]): Promise<void>;
53
+ createImageTextList(items: ImageTextListItem[], options?: ImageTextListOptions): Promise<ImageTextListGroup>;
54
+ initImageTextListEvents(group: ImageTextListGroup): void;
55
+ refreshImageTextList(group: ImageTextListGroup): Promise<void>;
56
+ private normalizeOptions;
57
+ private toPx;
58
+ private getItems;
59
+ private createText;
60
+ private loadImage;
61
+ private buildGroup;
62
+ private createGroup;
63
+ private flowRows;
64
+ private updateOriginSize;
65
+ destroy(): void;
66
+ }
67
+ export default ImageTextListPlugin;
68
+ //# sourceMappingURL=ImageTextListPlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageTextListPlugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/ImageTextListPlugin.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hprint/plugins",
3
- "version": "0.0.8",
3
+ "version": "0.0.9-alpha.0",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -22,8 +22,8 @@
22
22
  "qs": "~6.12.3",
23
23
  "socket.io-client": "^4.8.1",
24
24
  "uuid": "~8.3.2",
25
- "@hprint/core": "0.0.8",
26
- "@hprint/shared": "0.0.8"
25
+ "@hprint/core": "0.0.9-alpha.0",
26
+ "@hprint/shared": "0.0.9-alpha.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/bwip-js": "^3.2.3",
package/src/index.ts CHANGED
@@ -36,7 +36,9 @@ import ResizePlugin from './plugins/ResizePlugin';
36
36
  import LockPlugin from './plugins/LockPlugin';
37
37
  import AddBaseTypePlugin from './plugins/AddBaseTypePlugin';
38
38
  import PrintPlugin from './plugins/PrintPlugin';
39
- import CreateElementPlugin from './plugins/CreateElementPlugin';
39
+ import CreateElementPlugin from './plugins/CreateElementPlugin';
40
+ import ImageTextListPlugin from './plugins/ImageTextListPlugin';
41
+ import ActualContentLayoutPlugin from './plugins/ActualContentLayoutPlugin';
40
42
 
41
43
  // 对象形式导出所有插件
42
44
  const pluginsObject: { [key: string]: IPluginTempl } = {
@@ -75,8 +77,10 @@ const pluginsObject: { [key: string]: IPluginTempl } = {
75
77
  LockPlugin,
76
78
  AddBaseTypePlugin,
77
79
  PrintPlugin,
78
- CreateElementPlugin,
79
- };
80
+ CreateElementPlugin,
81
+ ImageTextListPlugin,
82
+ ActualContentLayoutPlugin,
83
+ };
80
84
 
81
85
  // 数组形式导出所有插件
82
86
  const pluginsList: IPluginTempl[] = [
@@ -115,7 +119,9 @@ const pluginsList: IPluginTempl[] = [
115
119
  LockPlugin,
116
120
  AddBaseTypePlugin,
117
121
  PrintPlugin,
118
- CreateElementPlugin,
119
- ];
122
+ CreateElementPlugin,
123
+ ImageTextListPlugin,
124
+ ActualContentLayoutPlugin,
125
+ ];
120
126
 
121
127
  export { pluginsObject, pluginsList, SelectEvent, SelectMode };
@@ -0,0 +1,276 @@
1
+ import { fabric } from '@hprint/core';
2
+ import type { IEditor, IPluginTempl } from '@hprint/core';
3
+
4
+ export interface ActualContentLayoutSettings {
5
+ actualContentLayout?: boolean;
6
+ overflowMode?: 'clip' | 'expand';
7
+ }
8
+
9
+ type IPlugin = Pick<ActualContentLayoutPlugin, 'applyActualContentLayout'>;
10
+
11
+ declare module '@hprint/core' {
12
+ interface IEditor extends IPlugin {}
13
+ }
14
+
15
+ type LayoutEntry = {
16
+ object: fabric.Object;
17
+ index: number;
18
+ originalTop: number;
19
+ originalBottom: number;
20
+ };
21
+
22
+ class ActualContentLayoutPlugin implements IPluginTempl {
23
+ static pluginName = 'ActualContentLayoutPlugin';
24
+ static apis = ['applyActualContentLayout'];
25
+
26
+ constructor(
27
+ public canvas: fabric.Canvas,
28
+ public editor: IEditor
29
+ ) {}
30
+
31
+ private layoutOrigins = new WeakMap<
32
+ fabric.Object,
33
+ { top: number; height: number }
34
+ >();
35
+
36
+ async hookTransformObjectEnd(...args: unknown[]) {
37
+ const { originObject, fabricObject } = args[0] as {
38
+ originObject: any;
39
+ fabricObject: fabric.Object;
40
+ };
41
+ if (!this.isPrintableObject(originObject)) return;
42
+
43
+ const mmPerPx = Number(this.editor.getSizeByUnit?.(1, 'mm')) || 1;
44
+ this.layoutOrigins.set(fabricObject, {
45
+ top: this.getOriginalTop(originObject, fabricObject, mmPerPx),
46
+ height: this.getOriginalHeight(
47
+ originObject,
48
+ fabricObject,
49
+ mmPerPx
50
+ ),
51
+ });
52
+ }
53
+
54
+ applyActualContentLayout(templateContent: any, templateHeight: number) {
55
+ const settings = (templateContent?.templateSettings ||
56
+ {}) as ActualContentLayoutSettings;
57
+ if (!settings.actualContentLayout) return templateHeight;
58
+
59
+ const fabricObjects = this.canvas
60
+ .getObjects()
61
+ .filter(this.isPrintableObject);
62
+ const mmPerPx = Number(this.editor.getSizeByUnit?.(1, 'mm')) || 1;
63
+
64
+ fabricObjects.forEach((object) => this.preparePrintLayoutObject(object));
65
+
66
+ const entries = fabricObjects.map((object, index) => {
67
+ const origin = this.layoutOrigins.get(object);
68
+ const originalTop =
69
+ origin?.top ?? Number(object.top || 0) * mmPerPx;
70
+ const originalHeight =
71
+ origin?.height ??
72
+ Number(object.getScaledHeight?.() || object.height || 0) *
73
+ mmPerPx;
74
+ return {
75
+ object,
76
+ index,
77
+ originalTop,
78
+ originalBottom: originalTop + originalHeight,
79
+ };
80
+ }) as LayoutEntry[];
81
+
82
+ entries.sort(
83
+ (a, b) => a.originalTop - b.originalTop || a.index - b.index
84
+ );
85
+ const rows: LayoutEntry[][] = [];
86
+ const sameRowTolerance = 0.01;
87
+ entries.forEach((entry) => {
88
+ const row = rows[rows.length - 1];
89
+ if (
90
+ row &&
91
+ Math.abs(row[0].originalTop - entry.originalTop) <=
92
+ sameRowTolerance
93
+ ) {
94
+ row.push(entry);
95
+ } else {
96
+ rows.push([entry]);
97
+ }
98
+ });
99
+
100
+ let previousOriginalBottom: number | undefined;
101
+ let previousActualBottom: number | undefined;
102
+ let pendingGap = 0;
103
+ let lastVisibleOriginalBottom = 0;
104
+
105
+ rows.forEach((row) => {
106
+ const rowOriginalTop = row[0].originalTop;
107
+ const rowOriginalBottom = Math.max(
108
+ ...row.map((entry) => entry.originalBottom)
109
+ );
110
+ if (previousOriginalBottom !== undefined) {
111
+ pendingGap += Math.max(
112
+ 0,
113
+ rowOriginalTop - previousOriginalBottom
114
+ );
115
+ }
116
+ previousOriginalBottom = rowOriginalBottom;
117
+
118
+ const visibleEntries = row.filter(
119
+ (entry) => !this.isEmptyLayoutObject(entry.object)
120
+ );
121
+ if (!visibleEntries.length) return;
122
+
123
+ const targetTop =
124
+ previousActualBottom === undefined
125
+ ? rowOriginalTop
126
+ : previousActualBottom + pendingGap;
127
+ visibleEntries.forEach((entry) => {
128
+ entry.object.set('top', targetTop / mmPerPx);
129
+ entry.object.setCoords();
130
+ });
131
+ previousActualBottom = Math.max(
132
+ ...visibleEntries.map(
133
+ (entry) =>
134
+ (Number(entry.object.top || 0) +
135
+ this.getActualLayoutHeight(entry.object)) *
136
+ mmPerPx
137
+ )
138
+ );
139
+ lastVisibleOriginalBottom = rowOriginalBottom;
140
+ pendingGap = 0;
141
+ });
142
+
143
+ this.canvas.requestRenderAll();
144
+ if (
145
+ settings.overflowMode !== 'expand' ||
146
+ previousActualBottom === undefined
147
+ ) {
148
+ return templateHeight;
149
+ }
150
+ const bottomSpace = Math.max(
151
+ 0,
152
+ templateHeight - lastVisibleOriginalBottom
153
+ );
154
+ return Math.max(
155
+ templateHeight,
156
+ previousActualBottom + bottomSpace
157
+ );
158
+ }
159
+
160
+ private getOriginalTop(
161
+ source: any,
162
+ object: fabric.Object,
163
+ mmPerPx: number
164
+ ) {
165
+ const top = Number(source?.top);
166
+ if (Number.isFinite(top)) return top * mmPerPx;
167
+ return this.getOriginMmValue(
168
+ source,
169
+ 'top',
170
+ Number(object.top || 0) * mmPerPx
171
+ );
172
+ }
173
+
174
+ private getOriginalHeight(
175
+ source: any,
176
+ object: fabric.Object,
177
+ mmPerPx: number
178
+ ) {
179
+ const height = Number(source?.height);
180
+ const scaleY = Number(source?.scaleY ?? 1);
181
+ if (Number.isFinite(height) && Number.isFinite(scaleY)) {
182
+ return Math.abs(height * scaleY) * mmPerPx;
183
+ }
184
+ return this.getOriginMmValue(
185
+ source,
186
+ 'height',
187
+ Number(object.getScaledHeight?.() || object.height || 0) *
188
+ mmPerPx
189
+ );
190
+ }
191
+
192
+ private getOriginMmValue(
193
+ source: any,
194
+ field: 'top' | 'height',
195
+ fallback: number
196
+ ) {
197
+ const originalValue = source?._originSize?.mm?.[field];
198
+ if (
199
+ originalValue === undefined ||
200
+ originalValue === null ||
201
+ originalValue === ''
202
+ ) {
203
+ return fallback;
204
+ }
205
+ const value = Number(originalValue);
206
+ return Number.isFinite(value) ? value : fallback;
207
+ }
208
+
209
+ private preparePrintLayoutObject(object: any) {
210
+ if (object?.extensionType !== 'imageTextList') return;
211
+ if (object.extension?._clipContent === true) return;
212
+
213
+ // Design canvases can opt into clipping, but print/layout canvases should
214
+ // measure and render the natural image-text content height.
215
+ if (object.clipPath) object.set('clipPath', undefined);
216
+ object.set({
217
+ objectCaching: false,
218
+ dirty: true,
219
+ });
220
+ }
221
+
222
+ private isPrintableObject(object: any) {
223
+ return (
224
+ object?.id !== 'workspace' &&
225
+ object?.id !== 'coverMask' &&
226
+ object?.type !== 'GuideLine'
227
+ );
228
+ }
229
+
230
+ private isEmptyLayoutObject(object: any) {
231
+ if (object?.visible === false) return true;
232
+ const field = object?.extension?._field_;
233
+ if (!field) return false;
234
+ if (object.type === 'textbox') {
235
+ return String(object.text ?? '') === '';
236
+ }
237
+ if (['barcode', 'qrcode'].includes(object.extensionType)) {
238
+ return String(object.extension?.value ?? '') === '';
239
+ }
240
+ if (object.extensionType === 'imageTextList') {
241
+ return (
242
+ !Array.isArray(object.extension?.items) ||
243
+ object.extension.items.length === 0
244
+ );
245
+ }
246
+ return false;
247
+ }
248
+
249
+ private getActualLayoutHeight(object: any) {
250
+ if (object?.extensionType !== 'imageTextList') {
251
+ return Number(
252
+ object.getScaledHeight?.() || object.height || 0
253
+ );
254
+ }
255
+
256
+ const children = object.getObjects?.() || object._objects || [];
257
+ const contentChildren = children.slice(1);
258
+ if (!contentChildren.length) return 0;
259
+
260
+ const groupHeight = Number(object.height || 0);
261
+ const groupScaleY = Math.abs(Number(object.scaleY ?? 1));
262
+ const contentBottom = Math.max(
263
+ ...contentChildren.map(
264
+ (child: any) =>
265
+ Number(child.top || 0) +
266
+ groupHeight / 2 +
267
+ Number(
268
+ child.getScaledHeight?.() || child.height || 0
269
+ )
270
+ )
271
+ );
272
+ return Math.max(0, contentBottom) * groupScaleY;
273
+ }
274
+ }
275
+
276
+ export default ActualContentLayoutPlugin;
@@ -74,9 +74,11 @@ class CopyPlugin implements IPluginTempl {
74
74
  this.editor.addSetAndSyncByUnit(cloned);
75
75
  if (cloned.extensionType === 'barcode') {
76
76
  this.editor.initBarcodeEvents(cloned)
77
- } else if (cloned.extensionType === 'qrcode') {
78
- this.editor.initQrcodeEvents(cloned);
79
- }
77
+ } else if (cloned.extensionType === 'qrcode') {
78
+ this.editor.initQrcodeEvents(cloned);
79
+ } else if (cloned.extensionType === 'imageTextList') {
80
+ this.editor.initImageTextListEvents(cloned);
81
+ }
80
82
  canvas.add(cloned);
81
83
  canvas.setActiveObject(cloned);
82
84
  canvas.requestRenderAll();