@pdfme/ui 3.2.3-dev.1 → 4.0.0-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.
- package/dist/index.es.js +9298 -8509
- package/dist/index.umd.js +112 -112
- package/dist/types/class.d.ts +57 -10
- package/dist/types/components/AppContextProvider.d.ts +2 -2
- package/dist/types/components/CtlBar.d.ts +2 -0
- package/dist/types/components/Designer/Canvas/Padding.d.ts +6 -0
- package/dist/types/components/Designer/Canvas/index.d.ts +2 -1
- package/dist/types/components/Designer/index.d.ts +1 -2
- package/dist/types/components/Preview.d.ts +1 -1
- package/dist/types/components/Renderer.d.ts +4 -3
- package/dist/types/constants.d.ts +1 -1
- package/dist/types/contexts.d.ts +12 -2
- package/dist/types/helper.d.ts +20 -33
- package/dist/types/hooks.d.ts +1 -0
- package/package.json +1 -1
- package/src/Designer.tsx +8 -3
- package/src/Form.tsx +6 -3
- package/src/Viewer.tsx +0 -1
- package/src/class.ts +28 -5
- package/src/components/AppContextProvider.tsx +3 -1
- package/src/components/CtlBar.tsx +57 -6
- package/src/components/Designer/Canvas/Padding.tsx +54 -0
- package/src/components/Designer/Canvas/index.tsx +85 -19
- package/src/components/Designer/Sidebar/DetailView/index.tsx +7 -11
- package/src/components/Designer/index.tsx +60 -37
- package/src/components/Paper.tsx +1 -2
- package/src/components/Preview.tsx +72 -22
- package/src/components/Renderer.tsx +12 -11
- package/src/constants.ts +1 -1
- package/src/helper.ts +113 -117
- package/src/hooks.ts +46 -14
- package/src/i18n.ts +72 -0
@@ -11,7 +11,7 @@ import React, {
|
|
11
11
|
} from 'react';
|
12
12
|
import { theme, Button } from 'antd';
|
13
13
|
import { OnDrag, OnResize, OnClick, OnRotate } from 'react-moveable';
|
14
|
-
import { ZOOM, SchemaForUI, Size, ChangeSchemas } from '@pdfme/common';
|
14
|
+
import { ZOOM, SchemaForUI, Size, ChangeSchemas, BasePdf, isBlankPdf } from '@pdfme/common';
|
15
15
|
import { PluginsRegistry } from '../../../contexts';
|
16
16
|
import { CloseOutlined } from '@ant-design/icons';
|
17
17
|
import { RULER_HEIGHT, SIDEBAR_WIDTH } from '../../../constants';
|
@@ -23,6 +23,9 @@ import Selecto from './Selecto';
|
|
23
23
|
import Moveable from './Moveable';
|
24
24
|
import Guides from './Guides';
|
25
25
|
import Mask from './Mask';
|
26
|
+
import Padding from './Padding';
|
27
|
+
|
28
|
+
const mm2px = (mm: number) => mm * 3.7795275591;
|
26
29
|
|
27
30
|
const DELETE_BTN_ID = uuid();
|
28
31
|
const fmt4Num = (prop: string) => Number(prop.replace('px', ''));
|
@@ -70,6 +73,7 @@ interface GuidesInterface {
|
|
70
73
|
}
|
71
74
|
|
72
75
|
interface Props {
|
76
|
+
basePdf: BasePdf;
|
73
77
|
height: number;
|
74
78
|
hoveringSchemaId: string | null;
|
75
79
|
onChangeHoveringSchemaId: (id: string | null) => void;
|
@@ -89,6 +93,7 @@ interface Props {
|
|
89
93
|
|
90
94
|
const Canvas = (props: Props, ref: Ref<HTMLDivElement>) => {
|
91
95
|
const {
|
96
|
+
basePdf,
|
92
97
|
pageCursor,
|
93
98
|
scale,
|
94
99
|
backgrounds,
|
@@ -142,7 +147,7 @@ const Canvas = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
142
147
|
|
143
148
|
useEffect(() => {
|
144
149
|
moveable.current?.updateRect();
|
145
|
-
if (prevSchemas
|
150
|
+
if (!prevSchemas) {
|
146
151
|
return;
|
147
152
|
}
|
148
153
|
|
@@ -154,9 +159,37 @@ const Canvas = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
154
159
|
}
|
155
160
|
}, [pageCursor, schemasList, prevSchemas]);
|
156
161
|
|
157
|
-
const onDrag = ({ target,
|
158
|
-
|
159
|
-
|
162
|
+
const onDrag = ({ target, top, left }: OnDrag) => {
|
163
|
+
const { width: _width, height: _height } = target.style;
|
164
|
+
const targetWidth = fmt(_width);
|
165
|
+
const targetHeight = fmt(_height);
|
166
|
+
const actualTop = top / ZOOM;
|
167
|
+
const actualLeft = left / ZOOM;
|
168
|
+
const { width: pageWidth, height: pageHeight } = pageSizes[pageCursor];
|
169
|
+
let topPadding = 0;
|
170
|
+
let rightPadding = 0;
|
171
|
+
let bottomPadding = 0;
|
172
|
+
let leftPadding = 0;
|
173
|
+
|
174
|
+
if (isBlankPdf(basePdf)) {
|
175
|
+
const [t, r, b, l] = basePdf.padding;
|
176
|
+
topPadding = t * ZOOM;
|
177
|
+
rightPadding = r;
|
178
|
+
bottomPadding = b;
|
179
|
+
leftPadding = l * ZOOM;
|
180
|
+
}
|
181
|
+
|
182
|
+
if (actualTop + targetHeight > pageHeight - bottomPadding) {
|
183
|
+
target.style.top = `${(pageHeight - targetHeight - bottomPadding) * ZOOM}px`;
|
184
|
+
} else {
|
185
|
+
target.style.top = `${top < topPadding ? topPadding : top}px`;
|
186
|
+
}
|
187
|
+
|
188
|
+
if (actualLeft + targetWidth > pageWidth - rightPadding) {
|
189
|
+
target.style.left = `${(pageWidth - targetWidth - rightPadding) * ZOOM}px`;
|
190
|
+
} else {
|
191
|
+
target.style.left = `${left < leftPadding ? leftPadding : left}px`;
|
192
|
+
}
|
160
193
|
};
|
161
194
|
|
162
195
|
const onDragEnd = ({ target }: { target: HTMLElement | SVGElement }) => {
|
@@ -195,24 +228,24 @@ const Canvas = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
195
228
|
changeSchemas(flatten(arg));
|
196
229
|
};
|
197
230
|
|
198
|
-
const onResizeEnd =
|
231
|
+
const onResizeEnd = ({ target }: { target: HTMLElement | SVGElement }) => {
|
199
232
|
const { id, style } = target;
|
200
233
|
const { width, height, top, left } = style;
|
201
234
|
changeSchemas([
|
235
|
+
{ key: 'position.x', value: fmt(left), schemaId: id },
|
236
|
+
{ key: 'position.y', value: fmt(top), schemaId: id },
|
202
237
|
{ key: 'width', value: fmt(width), schemaId: id },
|
203
238
|
{ key: 'height', value: fmt(height), schemaId: id },
|
204
|
-
{ key: 'position.y', value: fmt(top), schemaId: id },
|
205
|
-
{ key: 'position.x', value: fmt(left), schemaId: id },
|
206
239
|
]);
|
207
240
|
|
208
241
|
const targetSchema = schemasList[pageCursor].find((schema) => schema.id === id);
|
209
242
|
|
210
243
|
if (!targetSchema) return;
|
211
244
|
|
245
|
+
targetSchema.position.x = fmt(left);
|
246
|
+
targetSchema.position.y = fmt(top);
|
212
247
|
targetSchema.width = fmt(width);
|
213
248
|
targetSchema.height = fmt(height);
|
214
|
-
targetSchema.position.y = fmt(top);
|
215
|
-
targetSchema.position.x = fmt(left);
|
216
249
|
};
|
217
250
|
|
218
251
|
const onResizeEnds = ({ targets }: { targets: (HTMLElement | SVGElement)[] }) => {
|
@@ -227,13 +260,43 @@ const Canvas = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
227
260
|
|
228
261
|
const onResize = ({ target, width, height, direction }: OnResize) => {
|
229
262
|
if (!target) return;
|
230
|
-
|
231
|
-
|
232
|
-
|
263
|
+
let topPadding = 0;
|
264
|
+
let rightPadding = 0;
|
265
|
+
let bottomPadding = 0;
|
266
|
+
let leftPadding = 0;
|
267
|
+
|
268
|
+
if (isBlankPdf(basePdf)) {
|
269
|
+
const [t, r, b, l] = basePdf.padding;
|
270
|
+
topPadding = t * ZOOM;
|
271
|
+
rightPadding = mm2px(r);
|
272
|
+
bottomPadding = mm2px(b);
|
273
|
+
leftPadding = l * ZOOM;
|
274
|
+
}
|
275
|
+
|
276
|
+
const pageWidth = mm2px(pageSizes[pageCursor].width);
|
277
|
+
const pageHeight = mm2px(pageSizes[pageCursor].height);
|
278
|
+
|
233
279
|
const obj: { top?: string; left?: string; width: string; height: string } = {
|
234
280
|
width: `${width}px`,
|
235
281
|
height: `${height}px`,
|
236
282
|
};
|
283
|
+
|
284
|
+
const s = target.style;
|
285
|
+
let newLeft = fmt4Num(s.left) + (fmt4Num(s.width) - width);
|
286
|
+
let newTop = fmt4Num(s.top) + (fmt4Num(s.height) - height);
|
287
|
+
if (newLeft < leftPadding) {
|
288
|
+
newLeft = leftPadding;
|
289
|
+
}
|
290
|
+
if (newTop < topPadding) {
|
291
|
+
newTop = topPadding;
|
292
|
+
}
|
293
|
+
if (newLeft + width > pageWidth - rightPadding) {
|
294
|
+
obj.width = `${pageWidth - rightPadding - newLeft}px`;
|
295
|
+
}
|
296
|
+
if (newTop + height > pageHeight - bottomPadding) {
|
297
|
+
obj.height = `${pageHeight - bottomPadding - newTop}px`;
|
298
|
+
}
|
299
|
+
|
237
300
|
const d = direction.toString();
|
238
301
|
if (isTopLeftResize(d)) {
|
239
302
|
obj.top = `${newTop}px`;
|
@@ -255,7 +318,7 @@ const Canvas = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
255
318
|
};
|
256
319
|
|
257
320
|
const rotatable = useMemo(() => {
|
258
|
-
const selectedSchemas = schemasList[pageCursor].filter((s) =>
|
321
|
+
const selectedSchemas = (schemasList[pageCursor] || []).filter((s) =>
|
259
322
|
activeElements.map((ae) => ae.id).includes(s.id)
|
260
323
|
);
|
261
324
|
const schemaTypes = selectedSchemas.map((s) => s.type);
|
@@ -329,6 +392,7 @@ const Canvas = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
329
392
|
{!editing && activeElements.length > 0 && pageCursor === index && (
|
330
393
|
<DeleteButton activeElements={activeElements} />
|
331
394
|
)}
|
395
|
+
<Padding basePdf={basePdf} />
|
332
396
|
<Guides
|
333
397
|
paperSize={paperSize}
|
334
398
|
horizontalRef={(e) => {
|
@@ -372,19 +436,21 @@ const Canvas = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
372
436
|
<Renderer
|
373
437
|
key={schema.id}
|
374
438
|
schema={schema}
|
439
|
+
basePdf={basePdf}
|
440
|
+
value={schema.content || ''}
|
375
441
|
onChangeHoveringSchemaId={onChangeHoveringSchemaId}
|
376
442
|
mode={
|
377
443
|
editing && activeElements.map((ae) => ae.id).includes(schema.id)
|
378
444
|
? 'designer'
|
379
445
|
: 'viewer'
|
380
446
|
}
|
381
|
-
onChange={(
|
382
|
-
|
447
|
+
onChange={(arg) => {
|
448
|
+
const args = Array.isArray(arg) ? arg : [arg];
|
449
|
+
changeSchemas(args.map(({ key, value }) => ({ key, value, schemaId: schema.id })));
|
383
450
|
}}
|
384
451
|
stopEditing={() => setEditing(false)}
|
385
|
-
outline={`1px ${hoveringSchemaId === schema.id ? 'solid' : 'dashed'} ${
|
386
|
-
|
387
|
-
}`}
|
452
|
+
outline={`1px ${hoveringSchemaId === schema.id ? 'solid' : 'dashed'} ${schema.readOnly && hoveringSchemaId !== schema.id ? 'transparent' : token.colorPrimary
|
453
|
+
}`}
|
388
454
|
scale={scale}
|
389
455
|
/>
|
390
456
|
)}
|
@@ -75,7 +75,7 @@ const DetailView = (
|
|
75
75
|
const handleWatch = (newSchema: any) => {
|
76
76
|
const changes = [];
|
77
77
|
for (let key in newSchema) {
|
78
|
-
if (['id', '
|
78
|
+
if (['id', 'content'].includes(key)) continue;
|
79
79
|
if (newSchema[key] !== (activeSchema as any)[key]) {
|
80
80
|
let value = newSchema[key];
|
81
81
|
// FIXME memo: https://github.com/pdfme/pdfme/pull/367#issuecomment-1857468274
|
@@ -123,15 +123,15 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
123
123
|
key: { title: i18n('fieldName'), type: 'string', required: true, span: 14 },
|
124
124
|
'-': { type: 'void', widget: 'Divider' },
|
125
125
|
align: { title: i18n('align'), type: 'void', widget: 'AlignWidget' },
|
126
|
-
x: { title: 'X', type: 'number', widget: 'inputNumber', required: true, span: 8 },
|
127
|
-
y: { title: 'Y', type: 'number', widget: 'inputNumber', required: true, span: 8 },
|
126
|
+
x: { title: 'X', type: 'number', widget: 'inputNumber', required: true, span: 8, min: 0 },
|
127
|
+
y: { title: 'Y', type: 'number', widget: 'inputNumber', required: true, span: 8, min: 0 },
|
128
128
|
rotate: {
|
129
129
|
title: i18n('rotate'),
|
130
130
|
type: 'number',
|
131
131
|
widget: 'inputNumber',
|
132
132
|
disabled: defaultSchema?.rotate === undefined,
|
133
133
|
max: 360,
|
134
|
-
min: 0,
|
134
|
+
props: { min: 0 },
|
135
135
|
span: 8,
|
136
136
|
},
|
137
137
|
width: {
|
@@ -140,7 +140,7 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
140
140
|
widget: 'inputNumber',
|
141
141
|
required: true,
|
142
142
|
span: 8,
|
143
|
-
min: 0,
|
143
|
+
props: { min: 0 },
|
144
144
|
},
|
145
145
|
height: {
|
146
146
|
title: i18n('height'),
|
@@ -148,18 +148,14 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
148
148
|
widget: 'inputNumber',
|
149
149
|
required: true,
|
150
150
|
span: 8,
|
151
|
-
min: 0,
|
151
|
+
props: { min: 0 },
|
152
152
|
},
|
153
153
|
opacity: {
|
154
154
|
title: i18n('opacity'),
|
155
155
|
type: 'number',
|
156
156
|
widget: 'inputNumber',
|
157
157
|
disabled: defaultSchema?.opacity === undefined,
|
158
|
-
props: {
|
159
|
-
step: 0.1,
|
160
|
-
},
|
161
|
-
max: 1,
|
162
|
-
min: 0,
|
158
|
+
props: { step: 0.1, min: 0, max: 1 },
|
163
159
|
span: 8,
|
164
160
|
},
|
165
161
|
},
|
@@ -8,18 +8,19 @@ import {
|
|
8
8
|
DesignerProps,
|
9
9
|
Size,
|
10
10
|
Plugin,
|
11
|
+
isBlankPdf,
|
11
12
|
} from '@pdfme/common';
|
12
13
|
import Sidebar from './Sidebar/index';
|
13
14
|
import Canvas from './Canvas/index';
|
14
15
|
import { RULER_HEIGHT, SIDEBAR_WIDTH } from '../../constants';
|
15
16
|
import { I18nContext, PluginsRegistry } from '../../contexts';
|
16
17
|
import {
|
17
|
-
|
18
|
+
schemasList2template,
|
18
19
|
uuid,
|
19
|
-
set,
|
20
20
|
cloneDeep,
|
21
|
-
|
21
|
+
template2SchemasList,
|
22
22
|
getPagesScrollTopByIndex,
|
23
|
+
changeSchemas as _changeSchemas,
|
23
24
|
} from '../../helper';
|
24
25
|
import { useUIPreProcessor, useScrollPageCursor, useInitEvents } from '../../hooks';
|
25
26
|
import Root from '../Root';
|
@@ -32,9 +33,10 @@ const TemplateEditor = ({
|
|
32
33
|
onSaveTemplate,
|
33
34
|
onChangeTemplate,
|
34
35
|
}: Omit<DesignerProps, 'domContainer'> & {
|
35
|
-
onSaveTemplate: (t: Template) => void;
|
36
36
|
size: Size;
|
37
|
-
|
37
|
+
onSaveTemplate: (t: Template) => void;
|
38
|
+
onChangeTemplate: (t: Template) => void;
|
39
|
+
}) => {
|
38
40
|
const past = useRef<SchemaForUI[][]>([]);
|
39
41
|
const future = useRef<SchemaForUI[][]>([]);
|
40
42
|
const mainRef = useRef<HTMLDivElement>(null);
|
@@ -51,7 +53,8 @@ const TemplateEditor = ({
|
|
51
53
|
const [sidebarOpen, setSidebarOpen] = useState(true);
|
52
54
|
const [prevTemplate, setPrevTemplate] = useState<Template | null>(null);
|
53
55
|
|
54
|
-
const { backgrounds, pageSizes, scale, error } =
|
56
|
+
const { backgrounds, pageSizes, scale, error, refresh } =
|
57
|
+
useUIPreProcessor({ template, size, zoomLevel });
|
55
58
|
|
56
59
|
const onEdit = (targets: HTMLElement[]) => {
|
57
60
|
setActiveElements(targets);
|
@@ -81,7 +84,7 @@ const TemplateEditor = ({
|
|
81
84
|
const _schemasList = cloneDeep(schemasList);
|
82
85
|
_schemasList[pageCursor] = newSchemas;
|
83
86
|
setSchemasList(_schemasList);
|
84
|
-
onChangeTemplate(
|
87
|
+
onChangeTemplate(schemasList2template(_schemasList, template.basePdf));
|
85
88
|
},
|
86
89
|
[template, schemasList, pageCursor, onChangeTemplate]
|
87
90
|
);
|
@@ -96,32 +99,16 @@ const TemplateEditor = ({
|
|
96
99
|
|
97
100
|
const changeSchemas: ChangeSchemas = useCallback(
|
98
101
|
(objs) => {
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
if (!keysToKeep.includes(key)) {
|
108
|
-
delete tgt[key as keyof typeof tgt];
|
109
|
-
}
|
110
|
-
});
|
111
|
-
const propPanel = Object.values(pluginsRegistry).find(
|
112
|
-
(plugin) => plugin?.propPanel.defaultSchema.type === value
|
113
|
-
)?.propPanel;
|
114
|
-
set(tgt, 'data', propPanel?.defaultValue || '');
|
115
|
-
Object.assign(tgt, propPanel?.defaultSchema || {});
|
116
|
-
} else if (key === 'data' && tgt.readOnly) {
|
117
|
-
set(tgt, 'readOnlyValue', value);
|
118
|
-
}
|
119
|
-
|
120
|
-
return acc;
|
121
|
-
}, cloneDeep(schemasList[pageCursor]));
|
122
|
-
commitSchemas(newSchemas);
|
102
|
+
_changeSchemas({
|
103
|
+
objs,
|
104
|
+
schemas: schemasList[pageCursor],
|
105
|
+
basePdf: template.basePdf,
|
106
|
+
pluginsRegistry,
|
107
|
+
pageSize: pageSizes[pageCursor],
|
108
|
+
commitSchemas,
|
109
|
+
});
|
123
110
|
},
|
124
|
-
[commitSchemas, pageCursor, schemasList]
|
111
|
+
[commitSchemas, pageCursor, schemasList, pluginsRegistry, pageSizes, template.basePdf]
|
125
112
|
);
|
126
113
|
|
127
114
|
useInitEvents({
|
@@ -142,7 +129,7 @@ const TemplateEditor = ({
|
|
142
129
|
});
|
143
130
|
|
144
131
|
const updateTemplate = useCallback(async (newTemplate: Template) => {
|
145
|
-
const sl = await
|
132
|
+
const sl = await template2SchemasList(newTemplate);
|
146
133
|
setSchemasList(sl);
|
147
134
|
onEditEnd();
|
148
135
|
setPageCursor(0);
|
@@ -162,13 +149,16 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
162
149
|
const s = {
|
163
150
|
id: uuid(),
|
164
151
|
key: `${i18n('field')}${schemasList[pageCursor].length + 1}`,
|
165
|
-
data: propPanel.defaultValue || '',
|
166
152
|
...propPanel.defaultSchema,
|
167
153
|
} as SchemaForUI;
|
168
154
|
|
169
155
|
const paper = paperRefs.current[pageCursor];
|
170
156
|
const rectTop = paper ? paper.getBoundingClientRect().top : 0;
|
171
|
-
|
157
|
+
const [paddingTop, , , paddingLeft] = isBlankPdf(template.basePdf)
|
158
|
+
? template.basePdf.padding
|
159
|
+
: [0, 0, 0, 0];
|
160
|
+
s.position.y = rectTop > 0 ? paddingTop : pageSizes[pageCursor].height / 2;
|
161
|
+
s.position.x = paddingLeft;
|
172
162
|
|
173
163
|
commitSchemas(schemasList[pageCursor].concat(s));
|
174
164
|
setTimeout(() => onEdit([document.getElementById(s.id)!]));
|
@@ -182,6 +172,34 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
182
172
|
setHoveringSchemaId(id);
|
183
173
|
};
|
184
174
|
|
175
|
+
const updatePage = async (sl: SchemaForUI[][], newPageCursor: number) => {
|
176
|
+
setPageCursor(newPageCursor);
|
177
|
+
const newTemplate = schemasList2template(sl, template.basePdf);
|
178
|
+
onChangeTemplate(newTemplate);
|
179
|
+
await updateTemplate(newTemplate);
|
180
|
+
void refresh(newTemplate);
|
181
|
+
setTimeout(
|
182
|
+
() =>
|
183
|
+
mainRef.current &&
|
184
|
+
((mainRef.current.scrollTop = getPagesScrollTopByIndex(pageSizes, newPageCursor, scale)), 0)
|
185
|
+
);
|
186
|
+
};
|
187
|
+
|
188
|
+
const handleRemovePage = () => {
|
189
|
+
if (pageCursor === 0) return;
|
190
|
+
if (!window.confirm(i18n('removePageConfirm'))) return;
|
191
|
+
|
192
|
+
const _schemasList = cloneDeep(schemasList);
|
193
|
+
_schemasList.splice(pageCursor, 1);
|
194
|
+
void updatePage(_schemasList, pageCursor - 1);
|
195
|
+
};
|
196
|
+
|
197
|
+
const handleAddPageAfter = () => {
|
198
|
+
const _schemasList = cloneDeep(schemasList);
|
199
|
+
_schemasList.splice(pageCursor + 1, 0, []);
|
200
|
+
void updatePage(_schemasList, pageCursor + 1);
|
201
|
+
};
|
202
|
+
|
185
203
|
if (prevTemplate !== template) {
|
186
204
|
setPrevTemplate(template);
|
187
205
|
void updateTemplate(template);
|
@@ -195,6 +213,9 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
195
213
|
if (error) {
|
196
214
|
return <ErrorScreen size={size} error={error} />;
|
197
215
|
}
|
216
|
+
const pageManipulation = isBlankPdf(template.basePdf)
|
217
|
+
? { addPageAfter: handleAddPageAfter, removePage: handleRemovePage }
|
218
|
+
: {};
|
198
219
|
|
199
220
|
return (
|
200
221
|
<Root size={size} scale={scale}>
|
@@ -210,15 +231,16 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
210
231
|
}}
|
211
232
|
zoomLevel={zoomLevel}
|
212
233
|
setZoomLevel={setZoomLevel}
|
234
|
+
{...pageManipulation}
|
213
235
|
/>
|
214
236
|
<Sidebar
|
215
237
|
hoveringSchemaId={hoveringSchemaId}
|
216
238
|
onChangeHoveringSchemaId={onChangeHoveringSchemaId}
|
217
239
|
height={mainRef.current ? mainRef.current.clientHeight : 0}
|
218
240
|
size={size}
|
219
|
-
pageSize={pageSizes[pageCursor]}
|
241
|
+
pageSize={pageSizes[pageCursor] ?? []}
|
220
242
|
activeElements={activeElements}
|
221
|
-
schemas={schemasList[pageCursor]}
|
243
|
+
schemas={schemasList[pageCursor] ?? []}
|
222
244
|
changeSchemas={changeSchemas}
|
223
245
|
onSortEnd={onSortEnd}
|
224
246
|
onEdit={(id: string) => {
|
@@ -234,6 +256,7 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
234
256
|
<Canvas
|
235
257
|
ref={mainRef}
|
236
258
|
paperRefs={paperRefs}
|
259
|
+
basePdf={template.basePdf}
|
237
260
|
hoveringSchemaId={hoveringSchemaId}
|
238
261
|
onChangeHoveringSchemaId={onChangeHoveringSchemaId}
|
239
262
|
height={size.height - RULER_HEIGHT * ZOOM}
|
package/src/components/Paper.tsx
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
import React, {
|
2
|
-
import
|
1
|
+
import React, { useRef, useState, useEffect, useContext } from 'react';
|
2
|
+
import { Template, SchemaForUI, PreviewProps, Size, getDynamicTemplate } from '@pdfme/common';
|
3
|
+
import { modifyTemplateForTable, getDynamicHeightForTable } from '@pdfme/schemas';
|
3
4
|
import UnitPager from './UnitPager';
|
4
5
|
import Root from './Root';
|
5
6
|
import ErrorScreen from './ErrorScreen';
|
@@ -7,9 +8,12 @@ import CtlBar from './CtlBar';
|
|
7
8
|
import Paper from './Paper';
|
8
9
|
import Renderer from './Renderer';
|
9
10
|
import { useUIPreProcessor, useScrollPageCursor } from '../hooks';
|
10
|
-
import {
|
11
|
+
import { FontContext } from '../contexts';
|
12
|
+
import { template2SchemasList, getPagesScrollTopByIndex } from '../helper';
|
11
13
|
import { theme } from 'antd';
|
12
14
|
|
15
|
+
const _cache = new Map();
|
16
|
+
|
13
17
|
const Preview = ({
|
14
18
|
template,
|
15
19
|
inputs,
|
@@ -21,6 +25,8 @@ const Preview = ({
|
|
21
25
|
}) => {
|
22
26
|
const { token } = theme.useToken();
|
23
27
|
|
28
|
+
const font = useContext(FontContext);
|
29
|
+
|
24
30
|
const containerRef = useRef<HTMLDivElement>(null);
|
25
31
|
const paperRefs = useRef<HTMLDivElement[]>([]);
|
26
32
|
|
@@ -29,38 +35,55 @@ const Preview = ({
|
|
29
35
|
const [zoomLevel, setZoomLevel] = useState(1);
|
30
36
|
const [schemasList, setSchemasList] = useState<SchemaForUI[][]>([[]] as SchemaForUI[][]);
|
31
37
|
|
32
|
-
const { backgrounds, pageSizes, scale, error } =
|
38
|
+
const { backgrounds, pageSizes, scale, error, refresh } =
|
39
|
+
useUIPreProcessor({ template, size, zoomLevel });
|
40
|
+
|
41
|
+
const isForm = Boolean(onChangeInput);
|
42
|
+
|
43
|
+
const input = inputs[unitCursor];
|
33
44
|
|
34
|
-
const init =
|
35
|
-
const
|
36
|
-
|
37
|
-
|
45
|
+
const init = (template: Template) => {
|
46
|
+
const options = { font };
|
47
|
+
getDynamicTemplate({
|
48
|
+
template,
|
49
|
+
input,
|
50
|
+
options,
|
51
|
+
_cache,
|
52
|
+
modifyTemplate: (arg) => {
|
53
|
+
return modifyTemplateForTable(arg);
|
54
|
+
},
|
55
|
+
getDynamicHeight: (value, args) => {
|
56
|
+
if (args.schema.type !== 'table') return Promise.resolve(args.schema.height);
|
57
|
+
return getDynamicHeightForTable(value, args);
|
58
|
+
},
|
59
|
+
})
|
60
|
+
.then(async (dynamicTemplate) => {
|
61
|
+
const sl = await template2SchemasList(dynamicTemplate);
|
62
|
+
setSchemasList(sl);
|
63
|
+
await refresh(dynamicTemplate);
|
64
|
+
})
|
65
|
+
.catch((err) => console.error(`[@pdfme/ui] `, err));
|
66
|
+
};
|
38
67
|
|
39
68
|
useEffect(() => {
|
40
69
|
if (unitCursor > inputs.length - 1) {
|
41
70
|
setUnitCursor(inputs.length - 1);
|
42
71
|
}
|
43
|
-
}, [inputs]);
|
44
72
|
|
45
|
-
|
46
|
-
|
47
|
-
}, [init]);
|
73
|
+
init(template);
|
74
|
+
}, [template, inputs, size]);
|
48
75
|
|
49
76
|
useScrollPageCursor({
|
50
77
|
ref: containerRef,
|
51
78
|
pageSizes,
|
52
79
|
scale,
|
53
80
|
pageCursor,
|
54
|
-
onChangePageCursor:
|
81
|
+
onChangePageCursor: setPageCursor,
|
55
82
|
});
|
56
83
|
|
57
84
|
const handleChangeInput = ({ key, value }: { key: string; value: string }) =>
|
58
85
|
onChangeInput && onChangeInput({ index: unitCursor, key, value });
|
59
86
|
|
60
|
-
const isForm = Boolean(onChangeInput);
|
61
|
-
|
62
|
-
const input = inputs[unitCursor];
|
63
|
-
|
64
87
|
if (error) {
|
65
88
|
return <ErrorScreen size={size} error={error} />;
|
66
89
|
}
|
@@ -94,16 +117,43 @@ const Preview = ({
|
|
94
117
|
pageSizes={pageSizes}
|
95
118
|
backgrounds={backgrounds}
|
96
119
|
renderSchema={({ schema, index }) => {
|
97
|
-
const { key } = schema;
|
98
|
-
const
|
120
|
+
const { key, readOnly } = schema;
|
121
|
+
const content = readOnly ? String(schema.content) || '' : String(input && input[key] || '');
|
99
122
|
return (
|
100
123
|
<Renderer
|
101
124
|
key={schema.id}
|
102
|
-
schema={
|
125
|
+
schema={schema}
|
126
|
+
basePdf={template.basePdf}
|
127
|
+
value={content}
|
103
128
|
mode={isForm ? 'form' : 'viewer'}
|
104
|
-
placeholder={
|
129
|
+
placeholder={schema.content}
|
105
130
|
tabIndex={index + 100}
|
106
|
-
onChange={(
|
131
|
+
onChange={(arg) => {
|
132
|
+
const args = Array.isArray(arg) ? arg : [arg];
|
133
|
+
let isNeedInit = false;
|
134
|
+
args.forEach(({ key: _key, value }) => {
|
135
|
+
if (_key === 'content') {
|
136
|
+
const newValue = value as string;
|
137
|
+
const oldValue = (input?.[key] as string) || '';
|
138
|
+
if (newValue === oldValue) return;
|
139
|
+
handleChangeInput({ key, value: newValue });
|
140
|
+
// TODO Set to true only if the execution of getDynamicTemplate, such as for a table, is required.
|
141
|
+
isNeedInit = true;
|
142
|
+
} else {
|
143
|
+
const targetSchema = schemasList[pageCursor].find(
|
144
|
+
(s) => s.id === schema.id
|
145
|
+
) as SchemaForUI;
|
146
|
+
if (!targetSchema) return;
|
147
|
+
|
148
|
+
// @ts-ignore
|
149
|
+
targetSchema[_key] = value as string;
|
150
|
+
}
|
151
|
+
});
|
152
|
+
if (isNeedInit) {
|
153
|
+
init(template);
|
154
|
+
}
|
155
|
+
setSchemasList([...schemasList])
|
156
|
+
}}
|
107
157
|
outline={
|
108
158
|
isForm && !schema.readOnly ? `1px dashed ${token.colorPrimary}` : 'transparent'
|
109
159
|
}
|
@@ -1,15 +1,16 @@
|
|
1
1
|
import React, { useEffect, useContext, ReactNode, useRef } from 'react';
|
2
|
-
import { Dict, ZOOM, UIRenderProps, SchemaForUI, Schema } from '@pdfme/common';
|
2
|
+
import { Dict, ZOOM, UIRenderProps, SchemaForUI, BasePdf, Schema } from '@pdfme/common';
|
3
3
|
import { theme as antdTheme } from 'antd';
|
4
4
|
import { SELECTABLE_CLASSNAME } from '../constants';
|
5
5
|
import { PluginsRegistry, OptionsContext, I18nContext } from '../contexts';
|
6
6
|
|
7
7
|
type RendererProps = Omit<
|
8
8
|
UIRenderProps<Schema>,
|
9
|
-
'
|
9
|
+
'schema' | 'rootElement' | 'options' | 'theme' | 'i18n' | '_cache'
|
10
10
|
> & {
|
11
|
+
basePdf: BasePdf;
|
11
12
|
schema: SchemaForUI;
|
12
|
-
|
13
|
+
value: string;
|
13
14
|
outline: string;
|
14
15
|
onChangeHoveringSchemaId?: (id: string | null) => void;
|
15
16
|
scale: number;
|
@@ -49,7 +50,8 @@ const Renderer = (props: RendererProps) => {
|
|
49
50
|
const i18n = useContext(I18nContext) as (key: keyof Dict | string) => string;
|
50
51
|
const { token: theme } = antdTheme.useToken();
|
51
52
|
|
52
|
-
const { schema, mode, onChange, stopEditing, tabIndex, placeholder, scale } =
|
53
|
+
const { schema, basePdf, value, mode, onChange, stopEditing, tabIndex, placeholder, scale } =
|
54
|
+
props;
|
53
55
|
|
54
56
|
const ref = useRef<HTMLDivElement>(null);
|
55
57
|
const _cache = useRef<Map<any, any>>(new Map());
|
@@ -68,16 +70,15 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
68
70
|
|
69
71
|
ref.current.innerHTML = '';
|
70
72
|
|
71
|
-
|
72
|
-
|
73
|
-
render({
|
73
|
+
void render({
|
74
74
|
key: schema.key,
|
75
|
-
value
|
75
|
+
value,
|
76
76
|
schema,
|
77
|
+
basePdf,
|
77
78
|
rootElement: ref.current,
|
78
79
|
mode,
|
79
|
-
onChange
|
80
|
-
stopEditing:
|
80
|
+
onChange,
|
81
|
+
stopEditing: stopEditing,
|
81
82
|
tabIndex,
|
82
83
|
placeholder,
|
83
84
|
options,
|
@@ -91,7 +92,7 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
91
92
|
ref.current.innerHTML = '';
|
92
93
|
}
|
93
94
|
};
|
94
|
-
}, [JSON.stringify(schema), JSON.stringify(options), mode, scale]);
|
95
|
+
}, [value, JSON.stringify(schema), JSON.stringify(options), mode, scale]);
|
95
96
|
|
96
97
|
return (
|
97
98
|
<Wrapper {...props}>
|