@pdfme/ui 5.5.10-dev.11 → 5.5.10-dev.125
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/README.md +3 -1
- package/__mocks__/converter.ts +3 -0
- package/__mocks__/form-render.js +3 -3
- package/__mocks__/form-render.ts +18 -0
- package/__mocks__/lucide-react.ts +15 -0
- package/package.json +36 -83
- package/src/Designer.tsx +1 -3
- package/src/Form.tsx +1 -3
- package/src/Viewer.tsx +1 -3
- package/src/class.ts +17 -6
- package/src/components/CtlBar.tsx +7 -2
- package/src/components/Designer/PluginIcon.tsx +64 -16
- package/src/components/Designer/RightSidebar/DetailView/AlignWidget.tsx +1 -2
- package/src/components/Designer/RightSidebar/DetailView/WidgetRenderer.tsx +8 -7
- package/src/components/Designer/RightSidebar/DetailView/index.tsx +15 -17
- package/src/components/Designer/RightSidebar/ListView/Item.tsx +3 -5
- package/src/components/Designer/index.tsx +28 -17
- package/src/components/Preview.tsx +40 -14
- package/src/components/Renderer.tsx +73 -27
- package/src/components/Root.tsx +8 -2
- package/src/contexts.ts +1 -1
- package/src/helper.ts +1 -1
- package/src/hooks.ts +102 -67
- package/tsconfig.build.json +15 -0
- package/tsconfig.json +5 -40
- package/tsconfig.typecheck.json +19 -0
- package/vite.config.mts +46 -5
- package/vitest.setup.ts +47 -0
- package/dist/index.es.js +0 -159737
- package/dist/index.umd.js +0 -1060
- package/dist/types/__tests__/assets/helper.d.ts +0 -3
- package/dist/types/__tests__/components/Designer.test.d.ts +0 -1
- package/dist/types/__tests__/components/PluginIcon.test.d.ts +0 -1
- package/dist/types/__tests__/components/Preview.test.d.ts +0 -1
- package/dist/types/__tests__/helper.test.d.ts +0 -1
- package/dist/types/src/Designer.d.ts +0 -21
- package/dist/types/src/Form.d.ts +0 -24
- package/dist/types/src/Viewer.d.ts +0 -15
- package/dist/types/src/class.d.ts +0 -89
- package/dist/types/src/components/AppContextProvider.d.ts +0 -11
- package/dist/types/src/components/CtlBar.d.ts +0 -14
- package/dist/types/src/components/Designer/Canvas/Guides.d.ts +0 -9
- package/dist/types/src/components/Designer/Canvas/Mask.d.ts +0 -4
- package/dist/types/src/components/Designer/Canvas/Moveable.d.ts +0 -37
- package/dist/types/src/components/Designer/Canvas/Padding.d.ts +0 -6
- package/dist/types/src/components/Designer/Canvas/Selecto.d.ts +0 -10
- package/dist/types/src/components/Designer/Canvas/index.d.ts +0 -22
- package/dist/types/src/components/Designer/LeftSidebar.d.ts +0 -8
- package/dist/types/src/components/Designer/PluginIcon.d.ts +0 -10
- package/dist/types/src/components/Designer/RightSidebar/DetailView/AlignWidget.d.ts +0 -4
- package/dist/types/src/components/Designer/RightSidebar/DetailView/ButtonGroupWidget.d.ts +0 -4
- package/dist/types/src/components/Designer/RightSidebar/DetailView/WidgetRenderer.d.ts +0 -7
- package/dist/types/src/components/Designer/RightSidebar/DetailView/index.d.ts +0 -8
- package/dist/types/src/components/Designer/RightSidebar/ListView/Item.d.ts +0 -45
- package/dist/types/src/components/Designer/RightSidebar/ListView/SelectableSortableContainer.d.ts +0 -4
- package/dist/types/src/components/Designer/RightSidebar/ListView/SelectableSortableItem.d.ts +0 -14
- package/dist/types/src/components/Designer/RightSidebar/ListView/index.d.ts +0 -4
- package/dist/types/src/components/Designer/RightSidebar/index.d.ts +0 -4
- package/dist/types/src/components/Designer/RightSidebar/layout.d.ts +0 -15
- package/dist/types/src/components/Designer/index.d.ts +0 -11
- package/dist/types/src/components/ErrorScreen.d.ts +0 -7
- package/dist/types/src/components/Paper.d.ts +0 -20
- package/dist/types/src/components/Preview.d.ts +0 -15
- package/dist/types/src/components/Renderer.d.ts +0 -13
- package/dist/types/src/components/Root.d.ts +0 -9
- package/dist/types/src/components/Spinner.d.ts +0 -3
- package/dist/types/src/components/StaticSchema.d.ts +0 -10
- package/dist/types/src/components/UnitPager.d.ts +0 -10
- package/dist/types/src/constants.d.ts +0 -11
- package/dist/types/src/contexts.d.ts +0 -10
- package/dist/types/src/helper.d.ts +0 -73
- package/dist/types/src/hooks.d.ts +0 -46
- package/dist/types/src/i18n.d.ts +0 -3
- package/dist/types/src/index.d.ts +0 -4
- package/dist/types/src/theme.d.ts +0 -2
- package/dist/types/src/types.d.ts +0 -19
- package/eslint.config.mjs +0 -41
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useRef, useState, useContext, useCallback, useEffect } from 'react';
|
|
1
|
+
import React, { useRef, useState, useContext, useCallback, useEffect, useLayoutEffect } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
cloneDeep,
|
|
4
4
|
ZOOM,
|
|
@@ -72,6 +72,7 @@ const TemplateEditor = ({
|
|
|
72
72
|
const [pageCursor, setPageCursor] = useState(0);
|
|
73
73
|
const [zoomLevel, setZoomLevel] = useState(options.zoomLevel ?? 1);
|
|
74
74
|
const [sidebarOpen, setSidebarOpen] = useState(options.sidebarOpen ?? true);
|
|
75
|
+
const [canvasHeight, setCanvasHeight] = useState(0);
|
|
75
76
|
const [prevTemplate, setPrevTemplate] = useState<Template | null>(null);
|
|
76
77
|
|
|
77
78
|
const { backgrounds, pageSizes, scale, error, refresh } = useUIPreProcessor({
|
|
@@ -81,8 +82,8 @@ const TemplateEditor = ({
|
|
|
81
82
|
maxZoom,
|
|
82
83
|
});
|
|
83
84
|
|
|
84
|
-
const onEdit = (targets: HTMLElement
|
|
85
|
-
setActiveElements(targets);
|
|
85
|
+
const onEdit = (targets: Array<HTMLElement | null | undefined>) => {
|
|
86
|
+
setActiveElements(targets.filter((target): target is HTMLElement => target instanceof HTMLElement));
|
|
86
87
|
setHoveringSchemaId(null);
|
|
87
88
|
};
|
|
88
89
|
|
|
@@ -91,17 +92,17 @@ const TemplateEditor = ({
|
|
|
91
92
|
setHoveringSchemaId(null);
|
|
92
93
|
};
|
|
93
94
|
|
|
94
|
-
// Update component state only when _options_ changes
|
|
95
|
-
// Ignore exhaustive useEffect dependency warnings here
|
|
96
95
|
useEffect(() => {
|
|
97
|
-
if (typeof options.zoomLevel === 'number'
|
|
96
|
+
if (typeof options.zoomLevel === 'number') {
|
|
98
97
|
setZoomLevel(options.zoomLevel);
|
|
99
98
|
}
|
|
100
|
-
|
|
99
|
+
}, [options.zoomLevel]);
|
|
100
|
+
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
if (typeof options.sidebarOpen === 'boolean') {
|
|
101
103
|
setSidebarOpen(options.sidebarOpen);
|
|
102
104
|
}
|
|
103
|
-
|
|
104
|
-
}, [options]);
|
|
105
|
+
}, [options.sidebarOpen]);
|
|
105
106
|
|
|
106
107
|
useScrollPageCursor({
|
|
107
108
|
ref: canvasRef,
|
|
@@ -115,6 +116,20 @@ const TemplateEditor = ({
|
|
|
115
116
|
},
|
|
116
117
|
});
|
|
117
118
|
|
|
119
|
+
useLayoutEffect(() => {
|
|
120
|
+
const updateHeight = () => {
|
|
121
|
+
setCanvasHeight(canvasRef.current ? canvasRef.current.clientHeight : 0);
|
|
122
|
+
};
|
|
123
|
+
updateHeight();
|
|
124
|
+
|
|
125
|
+
if (typeof ResizeObserver === 'function' && canvasRef.current) {
|
|
126
|
+
const observer = new ResizeObserver(updateHeight);
|
|
127
|
+
observer.observe(canvasRef.current);
|
|
128
|
+
return () => observer.disconnect();
|
|
129
|
+
}
|
|
130
|
+
return undefined;
|
|
131
|
+
}, [scale]);
|
|
132
|
+
|
|
118
133
|
const commitSchemas = useCallback(
|
|
119
134
|
(newSchemas: SchemaForUI[]) => {
|
|
120
135
|
future.current = [];
|
|
@@ -222,7 +237,7 @@ const TemplateEditor = ({
|
|
|
222
237
|
}
|
|
223
238
|
|
|
224
239
|
commitSchemas(schemasList[pageCursor].concat(s));
|
|
225
|
-
setTimeout(() => onEdit([document.getElementById(s.id)
|
|
240
|
+
setTimeout(() => onEdit([document.getElementById(s.id)]));
|
|
226
241
|
};
|
|
227
242
|
|
|
228
243
|
const onSortEnd = (sortedSchemas: SchemaForUI[]) => {
|
|
@@ -239,7 +254,7 @@ const TemplateEditor = ({
|
|
|
239
254
|
onChangeTemplate(newTemplate);
|
|
240
255
|
await updateTemplate(newTemplate);
|
|
241
256
|
void refresh(newTemplate);
|
|
242
|
-
|
|
257
|
+
|
|
243
258
|
// Notify page change with updated total pages
|
|
244
259
|
onPageCursorChange(newPageCursor, sl.length);
|
|
245
260
|
|
|
@@ -313,11 +328,7 @@ const TemplateEditor = ({
|
|
|
313
328
|
}}
|
|
314
329
|
onDragStart={onEditEnd}
|
|
315
330
|
>
|
|
316
|
-
<LeftSidebar
|
|
317
|
-
height={canvasRef.current ? canvasRef.current.clientHeight : 0}
|
|
318
|
-
scale={scale}
|
|
319
|
-
basePdf={template.basePdf}
|
|
320
|
-
/>
|
|
331
|
+
<LeftSidebar height={canvasHeight} scale={scale} basePdf={template.basePdf} />
|
|
321
332
|
|
|
322
333
|
<div style={{ position: 'absolute', width: canvasWidth, marginLeft: LEFT_SIDEBAR_WIDTH }}>
|
|
323
334
|
<CtlBar
|
|
@@ -340,7 +351,7 @@ const TemplateEditor = ({
|
|
|
340
351
|
<RightSidebar
|
|
341
352
|
hoveringSchemaId={hoveringSchemaId}
|
|
342
353
|
onChangeHoveringSchemaId={onChangeHoveringSchemaId}
|
|
343
|
-
height={
|
|
354
|
+
height={canvasHeight}
|
|
344
355
|
size={size}
|
|
345
356
|
pageSize={pageSizes[pageCursor] ?? []}
|
|
346
357
|
basePdf={template.basePdf}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useRef, useState, useEffect, useContext } from 'react';
|
|
1
|
+
import React, { useRef, useState, useEffect, useContext, useCallback } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Template,
|
|
4
4
|
SchemaForUI,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
getDynamicTemplate,
|
|
8
8
|
replacePlaceholders,
|
|
9
9
|
} from '@pdfme/common';
|
|
10
|
-
import { getDynamicHeightsForTable } from '@pdfme/schemas/
|
|
10
|
+
import { getDynamicHeightsForTable } from '@pdfme/schemas/tables';
|
|
11
11
|
import UnitPager from './UnitPager.js';
|
|
12
12
|
import Root from './Root.js';
|
|
13
13
|
import StaticSchema from './StaticSchema.js';
|
|
@@ -57,10 +57,36 @@ const Preview = ({
|
|
|
57
57
|
const isForm = Boolean(onChangeInput);
|
|
58
58
|
|
|
59
59
|
const input = inputs[unitCursor];
|
|
60
|
+
const latestFontRef = useRef(font);
|
|
61
|
+
const latestInputRef = useRef(input);
|
|
62
|
+
const latestRefreshRef = useRef(refresh);
|
|
63
|
+
const isMountedRef = useRef(true);
|
|
64
|
+
const initRequestIdRef = useRef(0);
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
latestFontRef.current = font;
|
|
68
|
+
}, [font]);
|
|
69
|
+
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
latestInputRef.current = input;
|
|
72
|
+
}, [input]);
|
|
73
|
+
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
latestRefreshRef.current = refresh;
|
|
76
|
+
}, [refresh]);
|
|
77
|
+
|
|
78
|
+
useEffect(
|
|
79
|
+
() => () => {
|
|
80
|
+
isMountedRef.current = false;
|
|
81
|
+
},
|
|
82
|
+
[],
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
const init = useCallback((template: Template, inputOverride?: Record<string, string>) => {
|
|
86
|
+
const requestId = ++initRequestIdRef.current;
|
|
87
|
+
const currentInput = inputOverride ?? latestInputRef.current;
|
|
88
|
+
const options = { font: latestFontRef.current };
|
|
89
|
+
const currentRefresh = latestRefreshRef.current;
|
|
64
90
|
getDynamicTemplate({
|
|
65
91
|
template,
|
|
66
92
|
input: currentInput,
|
|
@@ -77,28 +103,28 @@ const Preview = ({
|
|
|
77
103
|
})
|
|
78
104
|
.then(async (dynamicTemplate) => {
|
|
79
105
|
const sl = await template2SchemasList(dynamicTemplate);
|
|
106
|
+
if (!isMountedRef.current || requestId !== initRequestIdRef.current) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
80
109
|
setSchemasList(sl);
|
|
81
|
-
await
|
|
110
|
+
await currentRefresh(dynamicTemplate);
|
|
82
111
|
})
|
|
83
112
|
.catch((err) => console.error(`[@pdfme/ui] `, err));
|
|
84
|
-
};
|
|
113
|
+
}, []);
|
|
85
114
|
|
|
86
|
-
// Update component state only when _options_ changes
|
|
87
|
-
// Ignore exhaustive useEffect dependency warnings here
|
|
88
115
|
useEffect(() => {
|
|
89
|
-
if (typeof options.zoomLevel === 'number'
|
|
116
|
+
if (typeof options.zoomLevel === 'number') {
|
|
90
117
|
setZoomLevel(options.zoomLevel);
|
|
91
118
|
}
|
|
92
|
-
|
|
93
|
-
}, [options]);
|
|
119
|
+
}, [options.zoomLevel]);
|
|
94
120
|
|
|
95
121
|
useEffect(() => {
|
|
96
122
|
if (unitCursor > inputs.length - 1) {
|
|
97
123
|
setUnitCursor(inputs.length - 1);
|
|
124
|
+
return;
|
|
98
125
|
}
|
|
99
|
-
|
|
100
126
|
init(template);
|
|
101
|
-
}, [
|
|
127
|
+
}, [init, inputs, size, template, unitCursor]);
|
|
102
128
|
|
|
103
129
|
useScrollPageCursor({
|
|
104
130
|
ref: containerRef,
|
|
@@ -36,7 +36,7 @@ type ReRenderCheckProps = {
|
|
|
36
36
|
options: UIOptions;
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
const
|
|
39
|
+
const useRenderKey = (arg: ReRenderCheckProps) => {
|
|
40
40
|
const { plugin, value, mode, scale, schema, options } = arg;
|
|
41
41
|
const _options = cloneDeep(options);
|
|
42
42
|
if (_options.font) {
|
|
@@ -48,9 +48,9 @@ const useRerenderDependencies = (arg: ReRenderCheckProps) => {
|
|
|
48
48
|
|
|
49
49
|
return useMemo(() => {
|
|
50
50
|
if (plugin?.uninterruptedEditMode && mode === 'designer') {
|
|
51
|
-
return
|
|
51
|
+
return mode;
|
|
52
52
|
} else {
|
|
53
|
-
return [value, mode, scale,
|
|
53
|
+
return JSON.stringify([value, mode, scale, schema, optionStr]);
|
|
54
54
|
}
|
|
55
55
|
}, [value, mode, scale, schema, optionStr, plugin]);
|
|
56
56
|
};
|
|
@@ -110,8 +110,41 @@ const Renderer = (props: RendererProps) => {
|
|
|
110
110
|
const ref = useRef<HTMLDivElement>(null);
|
|
111
111
|
const _cache = useContext(CacheContext);
|
|
112
112
|
const plugin = pluginsRegistry.findByType(schema.type);
|
|
113
|
+
const renderArgsRef = useRef({
|
|
114
|
+
plugin,
|
|
115
|
+
value,
|
|
116
|
+
schema,
|
|
117
|
+
basePdf,
|
|
118
|
+
mode,
|
|
119
|
+
onChange,
|
|
120
|
+
stopEditing,
|
|
121
|
+
tabIndex,
|
|
122
|
+
placeholder,
|
|
123
|
+
options,
|
|
124
|
+
theme,
|
|
125
|
+
i18n,
|
|
126
|
+
scale,
|
|
127
|
+
_cache,
|
|
128
|
+
});
|
|
113
129
|
|
|
114
|
-
|
|
130
|
+
renderArgsRef.current = {
|
|
131
|
+
plugin,
|
|
132
|
+
value,
|
|
133
|
+
schema,
|
|
134
|
+
basePdf,
|
|
135
|
+
mode,
|
|
136
|
+
onChange,
|
|
137
|
+
stopEditing,
|
|
138
|
+
tabIndex,
|
|
139
|
+
placeholder,
|
|
140
|
+
options,
|
|
141
|
+
theme,
|
|
142
|
+
i18n,
|
|
143
|
+
scale,
|
|
144
|
+
_cache,
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const renderKey = useRenderKey({
|
|
115
148
|
plugin,
|
|
116
149
|
value,
|
|
117
150
|
mode,
|
|
@@ -121,34 +154,47 @@ const Renderer = (props: RendererProps) => {
|
|
|
121
154
|
});
|
|
122
155
|
|
|
123
156
|
useEffect(() => {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
157
|
+
const element = ref.current;
|
|
158
|
+
const renderArgs = renderArgsRef.current;
|
|
159
|
+
if (!renderArgs.plugin?.ui || !element || !schema.type) return;
|
|
160
|
+
|
|
161
|
+
let cancelled = false;
|
|
162
|
+
element.innerHTML = '';
|
|
163
|
+
element.dataset.pdfmeRenderReady = 'false';
|
|
164
|
+
const render = renderArgs.plugin.ui;
|
|
165
|
+
|
|
166
|
+
void Promise.resolve(
|
|
167
|
+
render({
|
|
168
|
+
value: renderArgs.value,
|
|
169
|
+
schema: renderArgs.schema,
|
|
170
|
+
basePdf: renderArgs.basePdf,
|
|
171
|
+
rootElement: element,
|
|
172
|
+
mode: renderArgs.mode,
|
|
173
|
+
onChange: renderArgs.onChange,
|
|
174
|
+
stopEditing: renderArgs.stopEditing,
|
|
175
|
+
tabIndex: renderArgs.tabIndex,
|
|
176
|
+
placeholder: renderArgs.placeholder,
|
|
177
|
+
options: renderArgs.options,
|
|
178
|
+
theme: renderArgs.theme,
|
|
179
|
+
i18n: renderArgs.i18n,
|
|
180
|
+
scale: renderArgs.scale,
|
|
181
|
+
_cache: renderArgs._cache,
|
|
182
|
+
}),
|
|
183
|
+
).finally(() => {
|
|
184
|
+
if (!cancelled) {
|
|
185
|
+
element.dataset.pdfmeRenderReady = 'true';
|
|
186
|
+
}
|
|
144
187
|
});
|
|
145
188
|
|
|
146
189
|
return () => {
|
|
147
|
-
|
|
148
|
-
|
|
190
|
+
cancelled = true;
|
|
191
|
+
if (element) {
|
|
192
|
+
element.dispatchEvent(new Event('beforeRemove'));
|
|
193
|
+
element.innerHTML = '';
|
|
194
|
+
delete element.dataset.pdfmeRenderReady;
|
|
149
195
|
}
|
|
150
196
|
};
|
|
151
|
-
},
|
|
197
|
+
}, [renderKey, schema.type]);
|
|
152
198
|
|
|
153
199
|
if (!plugin) {
|
|
154
200
|
console.error(`[@pdfme/ui] Renderer for type ${schema.type} not found.
|
package/src/components/Root.tsx
CHANGED
|
@@ -29,8 +29,14 @@ const Root = ({ size, scale, children }: Props, ref: Ref<HTMLDivElement>) => {
|
|
|
29
29
|
}, [font]);
|
|
30
30
|
|
|
31
31
|
return (
|
|
32
|
-
<div
|
|
33
|
-
|
|
32
|
+
<div
|
|
33
|
+
className={DESIGNER_CLASSNAME + 'root'}
|
|
34
|
+
ref={ref}
|
|
35
|
+
style={{ position: 'relative', background: BACKGROUND_COLOR, ...size }}
|
|
36
|
+
>
|
|
37
|
+
<div className={DESIGNER_CLASSNAME + 'background'} style={{ margin: '0 auto', ...size }}>
|
|
38
|
+
{scale === 0 ? <Spinner /> : children}
|
|
39
|
+
</div>
|
|
34
40
|
</div>
|
|
35
41
|
);
|
|
36
42
|
};
|
package/src/contexts.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createContext } from 'react';
|
|
2
2
|
import { i18n } from './i18n.js';
|
|
3
3
|
import { getDefaultFont, PluginRegistry, pluginRegistry, UIOptions } from '@pdfme/common';
|
|
4
|
-
import { builtInPlugins } from '@pdfme/schemas';
|
|
4
|
+
import { builtInPlugins } from '@pdfme/schemas/builtins';
|
|
5
5
|
|
|
6
6
|
export const I18nContext = createContext(i18n);
|
|
7
7
|
|
package/src/helper.ts
CHANGED
|
@@ -301,7 +301,7 @@ export const template2SchemasList = async (_template: Template) => {
|
|
|
301
301
|
|
|
302
302
|
return (
|
|
303
303
|
ssl < psl
|
|
304
|
-
? schemasForUI.concat(
|
|
304
|
+
? schemasForUI.concat(Array.from({ length: psl - ssl }, () => cloneDeep([])))
|
|
305
305
|
: schemasForUI.slice(0, pageSizes.length)
|
|
306
306
|
).map((schema, i) => {
|
|
307
307
|
Object.values(schema).forEach((value) => {
|
package/src/hooks.ts
CHANGED
|
@@ -42,81 +42,108 @@ export const useUIPreProcessor = ({ template, size, zoomLevel, maxZoom }: UIPreP
|
|
|
42
42
|
const [pageSizes, setPageSizes] = useState<Size[]>([]);
|
|
43
43
|
const [scale, setScale] = useState(0);
|
|
44
44
|
const [error, setError] = useState<Error | null>(null);
|
|
45
|
+
const isMountedRef = useRef(true);
|
|
46
|
+
const requestIdRef = useRef(0);
|
|
47
|
+
|
|
48
|
+
const init = useCallback(
|
|
49
|
+
async (prop: { template: Template; size: Size }) => {
|
|
50
|
+
const {
|
|
51
|
+
template: { basePdf, schemas },
|
|
52
|
+
size,
|
|
53
|
+
} = prop;
|
|
54
|
+
|
|
55
|
+
let paperWidth: number;
|
|
56
|
+
let paperHeight: number;
|
|
57
|
+
let _backgrounds: string[];
|
|
58
|
+
let _pageSizes: { width: number; height: number }[];
|
|
59
|
+
|
|
60
|
+
if (isBlankPdf(basePdf)) {
|
|
61
|
+
const { width, height } = basePdf;
|
|
62
|
+
paperWidth = width * ZOOM;
|
|
63
|
+
paperHeight = height * ZOOM;
|
|
64
|
+
_backgrounds = schemas.map(
|
|
65
|
+
() =>
|
|
66
|
+
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAA1JREFUGFdj+P///38ACfsD/QVDRcoAAAAASUVORK5CYII=',
|
|
67
|
+
);
|
|
68
|
+
_pageSizes = schemas.map(() => ({ width, height }));
|
|
69
|
+
} else {
|
|
70
|
+
const _basePdf = await getB64BasePdf(basePdf);
|
|
71
|
+
const uint8Array = b64toUint8Array(_basePdf);
|
|
72
|
+
const createPdfArrayBuffer = () => {
|
|
73
|
+
const buffer = new ArrayBuffer(uint8Array.byteLength);
|
|
74
|
+
new Uint8Array(buffer).set(uint8Array);
|
|
75
|
+
return buffer;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const [pageSizeBuffer, imageBuffer] = [createPdfArrayBuffer(), createPdfArrayBuffer()];
|
|
79
|
+
const [_pages, imgBuffers] = await Promise.all([
|
|
80
|
+
pdf2size(pageSizeBuffer),
|
|
81
|
+
pdf2img(imageBuffer, { scale: maxZoom }),
|
|
82
|
+
]);
|
|
83
|
+
_pageSizes = _pages;
|
|
84
|
+
paperWidth = _pageSizes[0].width * ZOOM;
|
|
85
|
+
paperHeight = _pageSizes[0].height * ZOOM;
|
|
86
|
+
_backgrounds = imgBuffers.map(arrayBufferToBase64);
|
|
87
|
+
}
|
|
45
88
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
size,
|
|
50
|
-
} = prop;
|
|
51
|
-
|
|
52
|
-
let paperWidth: number;
|
|
53
|
-
let paperHeight: number;
|
|
54
|
-
let _backgrounds: string[];
|
|
55
|
-
let _pageSizes: { width: number; height: number }[];
|
|
56
|
-
|
|
57
|
-
if (isBlankPdf(basePdf)) {
|
|
58
|
-
const { width, height } = basePdf;
|
|
59
|
-
paperWidth = width * ZOOM;
|
|
60
|
-
paperHeight = height * ZOOM;
|
|
61
|
-
_backgrounds = schemas.map(
|
|
62
|
-
() =>
|
|
63
|
-
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAA1JREFUGFdj+P///38ACfsD/QVDRcoAAAAASUVORK5CYII=',
|
|
89
|
+
const _scale = Math.min(
|
|
90
|
+
getScale(size.width, paperWidth),
|
|
91
|
+
getScale(size.height - RULER_HEIGHT, paperHeight),
|
|
64
92
|
);
|
|
65
|
-
_pageSizes = schemas.map(() => ({ width, height }));
|
|
66
|
-
} else {
|
|
67
|
-
const _basePdf = await getB64BasePdf(basePdf);
|
|
68
|
-
|
|
69
|
-
const uint8Array = b64toUint8Array(_basePdf);
|
|
70
|
-
// Create a new ArrayBuffer copy to avoid detachment issues
|
|
71
|
-
const pdfArrayBuffer = new ArrayBuffer(uint8Array.byteLength);
|
|
72
|
-
new Uint8Array(pdfArrayBuffer).set(uint8Array);
|
|
73
|
-
|
|
74
|
-
const [_pages, imgBuffers] = await Promise.all([
|
|
75
|
-
pdf2size(pdfArrayBuffer),
|
|
76
|
-
pdf2img(pdfArrayBuffer.slice(), { scale: maxZoom }),
|
|
77
|
-
]);
|
|
78
|
-
_pageSizes = _pages;
|
|
79
|
-
paperWidth = _pageSizes[0].width * ZOOM;
|
|
80
|
-
paperHeight = _pageSizes[0].height * ZOOM;
|
|
81
|
-
_backgrounds = imgBuffers.map(arrayBufferToBase64);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const _scale = Math.min(
|
|
85
|
-
getScale(size.width, paperWidth),
|
|
86
|
-
getScale(size.height - RULER_HEIGHT, paperHeight),
|
|
87
|
-
);
|
|
88
93
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
return {
|
|
95
|
+
backgrounds: _backgrounds,
|
|
96
|
+
pageSizes: _pageSizes,
|
|
97
|
+
scale: _scale,
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
[maxZoom],
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
useEffect(
|
|
104
|
+
() => () => {
|
|
105
|
+
isMountedRef.current = false;
|
|
106
|
+
},
|
|
107
|
+
[],
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const runInit = useCallback(
|
|
111
|
+
async (prop: { template: Template; size: Size }) => {
|
|
112
|
+
const requestId = ++requestIdRef.current;
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const { pageSizes, scale, backgrounds } = await init(prop);
|
|
116
|
+
if (!isMountedRef.current || requestId !== requestIdRef.current) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
95
119
|
|
|
96
|
-
useEffect(() => {
|
|
97
|
-
init({ template, size })
|
|
98
|
-
.then(({ pageSizes, scale, backgrounds }) => {
|
|
99
120
|
setPageSizes(pageSizes);
|
|
100
121
|
setScale(scale);
|
|
101
122
|
setBackgrounds(backgrounds);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
123
|
+
setError(null);
|
|
124
|
+
} catch (err: unknown) {
|
|
125
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
126
|
+
if (isMountedRef.current && requestId === requestIdRef.current) {
|
|
127
|
+
setError(error);
|
|
128
|
+
console.error('[@pdfme/ui]', error);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
[init],
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
void runInit({ template, size });
|
|
137
|
+
}, [runInit, template, size]);
|
|
138
|
+
|
|
139
|
+
const refresh = useCallback((template: Template) => runInit({ template, size }), [runInit, size]);
|
|
108
140
|
|
|
109
141
|
return {
|
|
110
142
|
backgrounds,
|
|
111
143
|
pageSizes,
|
|
112
144
|
scale: scale * zoomLevel,
|
|
113
145
|
error,
|
|
114
|
-
refresh
|
|
115
|
-
init({ template, size }).then(({ pageSizes, scale, backgrounds }) => {
|
|
116
|
-
setPageSizes(pageSizes);
|
|
117
|
-
setScale(scale);
|
|
118
|
-
setBackgrounds(backgrounds);
|
|
119
|
-
}),
|
|
146
|
+
refresh,
|
|
120
147
|
};
|
|
121
148
|
};
|
|
122
149
|
|
|
@@ -164,10 +191,11 @@ export const useScrollPageCursor = ({
|
|
|
164
191
|
}, [onChangePageCursor, pageCursor, pageSizes, ref, scale]);
|
|
165
192
|
|
|
166
193
|
useEffect(() => {
|
|
167
|
-
ref.current
|
|
194
|
+
const node = ref.current;
|
|
195
|
+
node?.addEventListener('scroll', onScroll);
|
|
168
196
|
|
|
169
197
|
return () => {
|
|
170
|
-
|
|
198
|
+
node?.removeEventListener('scroll', onScroll);
|
|
171
199
|
};
|
|
172
200
|
}, [ref, onScroll]);
|
|
173
201
|
};
|
|
@@ -196,7 +224,7 @@ interface UseInitEventsParams {
|
|
|
196
224
|
past: React.MutableRefObject<SchemaForUI[][]>;
|
|
197
225
|
future: React.MutableRefObject<SchemaForUI[][]>;
|
|
198
226
|
setSchemasList: React.Dispatch<React.SetStateAction<SchemaForUI[][]>>;
|
|
199
|
-
onEdit: (targets: HTMLElement
|
|
227
|
+
onEdit: (targets: Array<HTMLElement | null | undefined>) => void;
|
|
200
228
|
onEditEnd: () => void;
|
|
201
229
|
}
|
|
202
230
|
|
|
@@ -219,6 +247,11 @@ export const useInitEvents = ({
|
|
|
219
247
|
const copiedSchemas = useRef<SchemaForUI[] | null>(null);
|
|
220
248
|
|
|
221
249
|
const initEvents = useCallback(() => {
|
|
250
|
+
const getElementsByIds = (ids: string[]) =>
|
|
251
|
+
ids
|
|
252
|
+
.map((id) => document.getElementById(id))
|
|
253
|
+
.filter((element): element is HTMLElement => element instanceof HTMLElement);
|
|
254
|
+
|
|
222
255
|
const getActiveSchemas = () => {
|
|
223
256
|
const ids = activeElements.map((ae) => ae.id);
|
|
224
257
|
|
|
@@ -267,7 +300,9 @@ export const useInitEvents = ({
|
|
|
267
300
|
return Object.assign(cloneDeep(cs), { id, name, position });
|
|
268
301
|
});
|
|
269
302
|
commitSchemas(schemasList[pageCursor].concat(pasteSchemas));
|
|
270
|
-
|
|
303
|
+
setTimeout(() => {
|
|
304
|
+
onEdit(getElementsByIds(pasteSchemas.map((s) => s.id)));
|
|
305
|
+
});
|
|
271
306
|
copiedSchemas.current = pasteSchemas;
|
|
272
307
|
},
|
|
273
308
|
redo: () => timeTravel('redo'),
|
|
@@ -276,7 +311,7 @@ export const useInitEvents = ({
|
|
|
276
311
|
onSaveTemplate && onSaveTemplate(schemasList2template(schemasList, template.basePdf)),
|
|
277
312
|
remove: () => removeSchemas(getActiveSchemas().map((s) => s.id)),
|
|
278
313
|
esc: onEditEnd,
|
|
279
|
-
selectAll: () => onEdit(schemasList[pageCursor].map((s) =>
|
|
314
|
+
selectAll: () => onEdit(getElementsByIds(schemasList[pageCursor].map((s) => s.id))),
|
|
280
315
|
});
|
|
281
316
|
}, [
|
|
282
317
|
template,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.build.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"jsx": "react",
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"declarationDir": "./dist",
|
|
7
|
+
"emitDeclarationOnly": true,
|
|
8
|
+
"module": "ESNext",
|
|
9
|
+
"moduleResolution": "bundler",
|
|
10
|
+
"outDir": "./dist",
|
|
11
|
+
"rootDir": "./src",
|
|
12
|
+
"skipLibCheck": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*.ts", "src/**/*.tsx"]
|
|
15
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,48 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
2
3
|
"compilerOptions": {
|
|
3
|
-
"noImplicitAny": true,
|
|
4
|
-
"target": "ES2020",
|
|
5
4
|
"jsx": "react",
|
|
6
|
-
"esModuleInterop": true,
|
|
7
|
-
"isolatedModules": true,
|
|
8
|
-
"declaration": true,
|
|
9
|
-
"declarationDir": "dist/types",
|
|
10
5
|
"module": "ESNext",
|
|
11
|
-
"lib": [
|
|
12
|
-
"ES2020",
|
|
13
|
-
"DOM",
|
|
14
|
-
"DOM.Iterable",
|
|
15
|
-
"ESNext"
|
|
16
|
-
],
|
|
17
6
|
"moduleResolution": "bundler",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"types": ["jest"],
|
|
21
|
-
"typeRoots": [
|
|
22
|
-
"../node_modules/@types",
|
|
23
|
-
"./node_modules/@types",
|
|
24
|
-
"../../node_modules/@types"
|
|
25
|
-
],
|
|
26
|
-
"sourceMap": true,
|
|
27
|
-
"baseUrl": ".",
|
|
28
|
-
"paths": {
|
|
29
|
-
"@pdfme/common": [
|
|
30
|
-
"packages/common/dist/esm/src"
|
|
31
|
-
],
|
|
32
|
-
"@pdfme/schemas": [
|
|
33
|
-
"packages/schemas/dist/esm/src"
|
|
34
|
-
]
|
|
35
|
-
},
|
|
7
|
+
"noEmit": true,
|
|
8
|
+
"typeRoots": ["../node_modules/@types", "./node_modules/@types", "../../node_modules/@types"],
|
|
36
9
|
"skipLibCheck": true
|
|
37
10
|
},
|
|
38
|
-
"include": [
|
|
39
|
-
|
|
40
|
-
"src/**/*.tsx",
|
|
41
|
-
"__tests__/**/*.ts",
|
|
42
|
-
"__tests__/**/*.tsx"
|
|
43
|
-
],
|
|
44
|
-
"exclude": [
|
|
45
|
-
"node_modules",
|
|
46
|
-
"dist"
|
|
47
|
-
]
|
|
11
|
+
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
|
12
|
+
"exclude": ["node_modules", "dist"]
|
|
48
13
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"composite": true,
|
|
5
|
+
"jsx": "react",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"declarationDir": "dist/typecheck",
|
|
8
|
+
"emitDeclarationOnly": true,
|
|
9
|
+
"module": "ESNext",
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"outDir": "dist/typecheck",
|
|
12
|
+
"tsBuildInfoFile": "dist/typecheck/tsconfig.tsbuildinfo",
|
|
13
|
+
"typeRoots": ["../node_modules/@types", "./node_modules/@types", "../../node_modules/@types"],
|
|
14
|
+
"skipLibCheck": true
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
|
17
|
+
"exclude": ["node_modules", "dist"],
|
|
18
|
+
"references": [{ "path": "../common" }, { "path": "../converter" }, { "path": "../schemas" }]
|
|
19
|
+
}
|