@pdfme/ui 2.2.0 → 3.0.0-beta.2
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 +33 -35
- package/__mocks__/form-render.js +7 -0
- package/dist/index.js +1 -1
- package/dist/index.js.LICENSE.txt +42 -4
- package/dist/index.js.map +1 -1
- package/dist/types/Designer.d.ts +3 -0
- package/dist/types/builtInPropPanel.d.ts +3 -0
- package/dist/types/builtInRenderer.d.ts +3 -0
- package/dist/types/class.d.ts +18 -38
- package/dist/types/components/CtlBar/Pager.d.ts +3 -2
- package/dist/types/components/CtlBar/Zoom.d.ts +3 -2
- package/dist/types/components/CtlBar/index.d.ts +3 -2
- package/dist/types/components/Designer/{Main → Canvas}/Guides.d.ts +2 -2
- package/dist/types/components/Designer/Canvas/Mask.d.ts +4 -0
- package/dist/types/components/Designer/Canvas/Moveable.d.ts +37 -0
- package/dist/types/components/Designer/{Main → Canvas}/Selecto.d.ts +2 -1
- package/dist/types/components/Designer/{Main → Canvas}/index.d.ts +3 -6
- package/dist/types/components/Designer/Sidebar/DetailView/AlignWidget.d.ts +4 -0
- package/dist/types/components/Designer/Sidebar/DetailView/WidgetRenderer.d.ts +7 -0
- package/dist/types/components/Designer/Sidebar/DetailView/index.d.ts +5 -4
- package/dist/types/components/Designer/Sidebar/ListView/SelectableSortableContainer.d.ts +3 -2
- package/dist/types/components/Designer/Sidebar/ListView/SelectableSortableItem.d.ts +1 -1
- package/dist/types/components/Designer/Sidebar/ListView/index.d.ts +3 -2
- package/dist/types/components/Designer/Sidebar/index.d.ts +3 -23
- package/dist/types/components/Designer/index.d.ts +6 -107
- package/dist/types/components/Divider.d.ts +2 -1
- package/dist/types/components/ErrorScreen.d.ts +7 -0
- package/dist/types/components/Paper.d.ts +3 -2
- package/dist/types/components/Preview.d.ts +10 -2
- package/dist/types/components/Renderer.d.ts +10 -0
- package/dist/types/components/Root.d.ts +1 -1
- package/dist/types/components/Spinner.d.ts +2 -1
- package/dist/types/components/UnitPager.d.ts +3 -2
- package/dist/types/constants.d.ts +3 -3
- package/dist/types/contexts.d.ts +4 -1
- package/dist/types/helper.d.ts +4 -46
- package/dist/types/hooks.d.ts +2 -2
- package/dist/types/i18n.d.ts +4 -2
- package/dist/types/index.d.ts +1 -4
- package/dist/types/types.d.ts +25 -0
- package/package.json +19 -8
- package/src/Designer.tsx +69 -21
- package/src/Form.tsx +18 -14
- package/src/Viewer.tsx +6 -2
- package/src/builtInPropPanel.ts +5 -0
- package/src/builtInRenderer.ts +5 -0
- package/src/class.ts +25 -2
- package/src/components/CtlBar/index.tsx +4 -7
- package/src/components/Designer/{Main → Canvas}/Guides.tsx +2 -2
- package/src/components/Designer/{Main → Canvas}/Moveable.tsx +23 -19
- package/src/components/Designer/{Main → Canvas}/index.tsx +77 -30
- package/src/components/Designer/Sidebar/DetailView/AlignWidget.tsx +182 -0
- package/src/components/Designer/Sidebar/DetailView/WidgetRenderer.tsx +28 -0
- package/src/components/Designer/Sidebar/DetailView/index.tsx +153 -22
- package/src/components/Designer/Sidebar/ListView/Item.tsx +1 -1
- package/src/components/Designer/Sidebar/ListView/SelectableSortableContainer.tsx +6 -6
- package/src/components/Designer/Sidebar/ListView/index.tsx +1 -4
- package/src/components/Designer/Sidebar/index.tsx +26 -60
- package/src/components/Designer/index.tsx +53 -32
- package/src/components/{Error.tsx → ErrorScreen.tsx} +2 -2
- package/src/components/Paper.tsx +35 -9
- package/src/components/Preview.tsx +48 -50
- package/src/components/Renderer.tsx +90 -0
- package/src/components/Root.tsx +5 -1
- package/src/constants.ts +4 -4
- package/src/contexts.ts +7 -0
- package/src/helper.ts +19 -122
- package/src/hooks.ts +6 -5
- package/src/i18n.ts +48 -11
- package/src/index.ts +1 -76
- package/src/types.ts +36 -0
- package/tsconfig.json +2 -1
- package/webpack.config.js +6 -1
- package/dist/types/components/Designer/Main/Mask.d.ts +0 -3
- package/dist/types/components/Designer/Main/Moveable.d.ts +0 -31
- package/dist/types/components/Designer/Sidebar/DetailView/ExampleInputEditor.d.ts +0 -6
- package/dist/types/components/Designer/Sidebar/DetailView/PositionAndSizeEditor.d.ts +0 -6
- package/dist/types/components/Designer/Sidebar/DetailView/TextPropEditor.d.ts +0 -6
- package/dist/types/components/Designer/Sidebar/DetailView/TypeAndKeyEditor.d.ts +0 -6
- package/dist/types/components/Error.d.ts +0 -6
- package/dist/types/components/Schemas/BarcodeSchema.d.ts +0 -15
- package/dist/types/components/Schemas/ImageSchema.d.ts +0 -15
- package/dist/types/components/Schemas/SchemaUI.d.ts +0 -15
- package/dist/types/components/Schemas/TextSchema.d.ts +0 -28
- package/src/components/Designer/Sidebar/DetailView/ExampleInputEditor.tsx +0 -85
- package/src/components/Designer/Sidebar/DetailView/PositionAndSizeEditor.tsx +0 -275
- package/src/components/Designer/Sidebar/DetailView/TextPropEditor.tsx +0 -357
- package/src/components/Designer/Sidebar/DetailView/TypeAndKeyEditor.tsx +0 -87
- package/src/components/Schemas/BarcodeSchema.tsx +0 -124
- package/src/components/Schemas/ImageSchema.tsx +0 -87
- package/src/components/Schemas/SchemaUI.tsx +0 -62
- package/src/components/Schemas/TextSchema.tsx +0 -175
- /package/src/components/Designer/{Main → Canvas}/Mask.tsx +0 -0
- /package/src/components/Designer/{Main → Canvas}/Selecto.tsx +0 -0
@@ -1,9 +1,9 @@
|
|
1
1
|
import React, { useContext, useState } from 'react';
|
2
|
+
import type { SidebarProps } from '../../../../types';
|
2
3
|
import { RULER_HEIGHT, SIDEBAR_WIDTH } from '../../../../constants';
|
3
4
|
import { I18nContext } from '../../../../contexts';
|
4
5
|
import Divider from '../../../Divider';
|
5
6
|
import SelectableSortableContainer from './SelectableSortableContainer';
|
6
|
-
import { SidebarProps } from '../index';
|
7
7
|
|
8
8
|
const ListView = (
|
9
9
|
props: Pick<
|
@@ -38,7 +38,6 @@ const ListView = (
|
|
38
38
|
</span>
|
39
39
|
</div>
|
40
40
|
<Divider />
|
41
|
-
|
42
41
|
{isBulkUpdateFieldNamesMode ? (
|
43
42
|
<div>
|
44
43
|
<textarea
|
@@ -68,7 +67,6 @@ const ListView = (
|
|
68
67
|
onEdit={onEdit}
|
69
68
|
/>
|
70
69
|
)}
|
71
|
-
|
72
70
|
<div
|
73
71
|
style={{
|
74
72
|
display: 'flex',
|
@@ -112,7 +110,6 @@ const ListView = (
|
|
112
110
|
</u>
|
113
111
|
)}
|
114
112
|
</div>
|
115
|
-
<Divider />
|
116
113
|
</div>
|
117
114
|
);
|
118
115
|
};
|
@@ -1,55 +1,17 @@
|
|
1
|
-
import React, {
|
2
|
-
import {
|
3
|
-
import {
|
4
|
-
import { I18nContext
|
1
|
+
import React, { useContext } from 'react';
|
2
|
+
import type { SidebarProps } from '../../../types';
|
3
|
+
import { SIDEBAR_WIDTH } from '../../../constants';
|
4
|
+
import { I18nContext } from '../../../contexts';
|
5
5
|
import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline';
|
6
6
|
import ListView from './ListView/index';
|
7
7
|
import DetailView from './DetailView/index';
|
8
|
-
import { getFallbackFontName } from '@pdfme/common';
|
9
|
-
|
10
|
-
export type SidebarProps = {
|
11
|
-
height: number;
|
12
|
-
hoveringSchemaId: string | null;
|
13
|
-
onChangeHoveringSchemaId: (id: string | null) => void;
|
14
|
-
size: Size;
|
15
|
-
pageSize: Size;
|
16
|
-
activeElements: HTMLElement[];
|
17
|
-
schemas: SchemaForUI[];
|
18
|
-
onSortEnd: (sortedSchemas: SchemaForUI[]) => void;
|
19
|
-
onEdit: (id: string) => void;
|
20
|
-
onEditEnd: () => void;
|
21
|
-
changeSchemas: (
|
22
|
-
objs: {
|
23
|
-
key: string; value: undefined | string | number | {
|
24
|
-
min: number;
|
25
|
-
max: number;
|
26
|
-
}; schemaId: string
|
27
|
-
}[]
|
28
|
-
) => void;
|
29
|
-
addSchema: () => void;
|
30
|
-
};
|
31
8
|
|
32
9
|
const Sidebar = (props: SidebarProps) => {
|
33
|
-
const {
|
10
|
+
const { sidebarOpen, setSidebarOpen, activeElements, schemas, addSchema } = props;
|
34
11
|
|
35
12
|
const i18n = useContext(I18nContext);
|
36
|
-
const
|
37
|
-
|
38
|
-
const [open, setOpen] = useState(true);
|
39
|
-
|
40
|
-
const getActiveSchemas = () => {
|
41
|
-
const ids = activeElements.map((ae) => ae.id);
|
42
|
-
const activeSchema = schemas.find((s) => ids.includes(s.id));
|
43
|
-
|
44
|
-
if (activeSchema?.type === 'text') {
|
45
|
-
if (!activeSchema.fontName) {
|
46
|
-
activeSchema.fontName = fallbackFont;
|
47
|
-
}
|
48
|
-
}
|
49
|
-
|
50
|
-
return schemas.filter((s) => ids.includes(s.id));
|
51
|
-
};
|
52
|
-
|
13
|
+
const getActiveSchemas = () =>
|
14
|
+
schemas.filter((s) => activeElements.map((ae) => ae.id).includes(s.id));
|
53
15
|
const getLastActiveSchema = () => {
|
54
16
|
const activeSchemas = getActiveSchemas();
|
55
17
|
return activeSchemas[activeSchemas.length - 1];
|
@@ -61,16 +23,18 @@ const Sidebar = (props: SidebarProps) => {
|
|
61
23
|
position: 'absolute',
|
62
24
|
right: 0,
|
63
25
|
zIndex: 1,
|
64
|
-
height:
|
65
|
-
width:
|
26
|
+
height: '100%',
|
27
|
+
width: sidebarOpen ? SIDEBAR_WIDTH : 0,
|
28
|
+
fontSize: '1rem',
|
66
29
|
}}
|
67
30
|
>
|
68
|
-
<div
|
31
|
+
<div>
|
69
32
|
<button
|
33
|
+
type="button"
|
70
34
|
style={{
|
71
35
|
position: 'absolute',
|
72
|
-
top: '1.
|
73
|
-
right: '
|
36
|
+
top: '1.15rem',
|
37
|
+
right: '1rem',
|
74
38
|
zIndex: 100,
|
75
39
|
border: 'none',
|
76
40
|
borderRadius: 2,
|
@@ -80,9 +44,9 @@ const Sidebar = (props: SidebarProps) => {
|
|
80
44
|
width: 30,
|
81
45
|
height: 30,
|
82
46
|
}}
|
83
|
-
onClick={() =>
|
47
|
+
onClick={() => setSidebarOpen(!sidebarOpen)}
|
84
48
|
>
|
85
|
-
{
|
49
|
+
{sidebarOpen ? (
|
86
50
|
<ArrowRightIcon width={15} height={15} />
|
87
51
|
) : (
|
88
52
|
<ArrowLeftIcon width={15} height={15} />
|
@@ -91,20 +55,20 @@ const Sidebar = (props: SidebarProps) => {
|
|
91
55
|
<div
|
92
56
|
style={{
|
93
57
|
width: SIDEBAR_WIDTH,
|
94
|
-
height:
|
95
|
-
display:
|
96
|
-
top:
|
58
|
+
height: '100%',
|
59
|
+
display: sidebarOpen ? 'block' : 'none',
|
60
|
+
top: 0,
|
97
61
|
right: 0,
|
98
62
|
position: 'absolute',
|
99
|
-
background: '#
|
63
|
+
background: '#fffffffa',
|
100
64
|
color: '#333',
|
101
65
|
border: '1px solid #eee',
|
102
|
-
padding: '0.
|
66
|
+
padding: '0.7rem 1rem',
|
103
67
|
overflowY: 'auto',
|
104
68
|
fontFamily: "'Open Sans', sans-serif",
|
105
69
|
fontWeight: 400,
|
106
70
|
textAlign: 'left',
|
107
|
-
boxSizing: '
|
71
|
+
boxSizing: 'border-box',
|
108
72
|
}}
|
109
73
|
>
|
110
74
|
{getActiveSchemas().length === 0 ? (
|
@@ -114,8 +78,6 @@ const Sidebar = (props: SidebarProps) => {
|
|
114
78
|
)}
|
115
79
|
<div
|
116
80
|
style={{
|
117
|
-
display: 'flex',
|
118
|
-
justifyContent: 'space-around',
|
119
81
|
position: 'absolute',
|
120
82
|
width: '100%',
|
121
83
|
left: 0,
|
@@ -123,13 +85,17 @@ const Sidebar = (props: SidebarProps) => {
|
|
123
85
|
paddingTop: '1rem',
|
124
86
|
}}
|
125
87
|
>
|
88
|
+
<div style={{ marginBottom: '1rem', borderBottom: '1px solid #e5e5e5' }} />
|
126
89
|
<button
|
90
|
+
type="button"
|
127
91
|
style={{
|
128
92
|
padding: '0.5rem',
|
129
93
|
background: '#18a0fb',
|
130
94
|
border: 'none',
|
131
95
|
borderRadius: 2,
|
132
96
|
cursor: 'pointer',
|
97
|
+
margin: '0 auto',
|
98
|
+
display: 'block',
|
133
99
|
}}
|
134
100
|
onClick={addSchema}
|
135
101
|
>
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import React, { useRef, useState, useEffect, useContext, useCallback } from 'react';
|
2
|
-
import {
|
2
|
+
import { ZOOM, Template, SchemaForUI, ChangeSchemas, DesignerProps, Size } from '@pdfme/common';
|
3
3
|
import Sidebar from './Sidebar/index';
|
4
|
-
import
|
5
|
-
import {
|
6
|
-
import { I18nContext } from '../../contexts';
|
4
|
+
import Canvas from './Canvas/index';
|
5
|
+
import { RULER_HEIGHT, SIDEBAR_WIDTH } from '../../constants';
|
6
|
+
import { I18nContext, PropPanelRegistry } from '../../contexts';
|
7
7
|
import {
|
8
8
|
uuid,
|
9
9
|
set,
|
@@ -12,16 +12,13 @@ import {
|
|
12
12
|
destroyShortCuts,
|
13
13
|
templateSchemas2SchemasList,
|
14
14
|
fmtTemplate,
|
15
|
-
getInitialSchema,
|
16
|
-
getSampleByType,
|
17
|
-
getKeepRatioHeightByWidth,
|
18
15
|
getUniqSchemaKey,
|
19
16
|
moveCommandToChangeSchemasArg,
|
20
17
|
getPagesScrollTopByIndex,
|
21
18
|
} from '../../helper';
|
22
19
|
import { useUIPreProcessor, useScrollPageCursor } from '../../hooks';
|
23
20
|
import Root from '../Root';
|
24
|
-
import
|
21
|
+
import ErrorScreen from '../ErrorScreen';
|
25
22
|
import CtlBar from '../CtlBar/index';
|
26
23
|
|
27
24
|
const TemplateEditor = ({
|
@@ -29,7 +26,10 @@ const TemplateEditor = ({
|
|
29
26
|
size,
|
30
27
|
onSaveTemplate,
|
31
28
|
onChangeTemplate,
|
32
|
-
}:
|
29
|
+
}: Omit<DesignerProps, 'domContainer'> & {
|
30
|
+
onSaveTemplate: (t: Template) => void;
|
31
|
+
size: Size;
|
32
|
+
} & { onChangeTemplate: (t: Template) => void }) => {
|
33
33
|
const copiedSchemas = useRef<SchemaForUI[] | null>(null);
|
34
34
|
const past = useRef<SchemaForUI[][]>([]);
|
35
35
|
const future = useRef<SchemaForUI[][]>([]);
|
@@ -37,12 +37,14 @@ const TemplateEditor = ({
|
|
37
37
|
const paperRefs = useRef<HTMLDivElement[]>([]);
|
38
38
|
|
39
39
|
const i18n = useContext(I18nContext);
|
40
|
+
const propPanelRegistry = useContext(PropPanelRegistry);
|
40
41
|
|
41
42
|
const [hoveringSchemaId, setHoveringSchemaId] = useState<string | null>(null);
|
42
43
|
const [activeElements, setActiveElements] = useState<HTMLElement[]>([]);
|
43
44
|
const [schemasList, setSchemasList] = useState<SchemaForUI[][]>([[]] as SchemaForUI[][]);
|
44
45
|
const [pageCursor, setPageCursor] = useState(0);
|
45
46
|
const [zoomLevel, setZoomLevel] = useState(1);
|
47
|
+
const [sidebarOpen, setSidebarOpen] = useState(true);
|
46
48
|
|
47
49
|
const { backgrounds, pageSizes, scale, error } = useUIPreProcessor({ template, size, zoomLevel });
|
48
50
|
|
@@ -89,20 +91,23 @@ const TemplateEditor = ({
|
|
89
91
|
[schemasList, pageCursor, commitSchemas]
|
90
92
|
);
|
91
93
|
|
92
|
-
const changeSchemas = useCallback(
|
93
|
-
(objs
|
94
|
+
const changeSchemas: ChangeSchemas = useCallback(
|
95
|
+
(objs) => {
|
94
96
|
const newSchemas = objs.reduce((acc, { key, value, schemaId }) => {
|
95
|
-
const tgt = acc.find((s) => s.id === schemaId)
|
97
|
+
const tgt = acc.find((s) => s.id === schemaId)! as SchemaForUI;
|
96
98
|
// Assign to reference
|
97
99
|
set(tgt, key, value);
|
100
|
+
|
98
101
|
if (key === 'type') {
|
99
|
-
const
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
102
|
+
const keysToKeep = ['id', 'key', 'type', 'position'];
|
103
|
+
Object.keys(tgt).forEach((key) => {
|
104
|
+
if (!keysToKeep.includes(key)) {
|
105
|
+
delete tgt[key as keyof typeof tgt];
|
106
|
+
}
|
107
|
+
});
|
108
|
+
const propPanel = propPanelRegistry[value as string];
|
109
|
+
set(tgt, 'data', propPanel?.defaultValue || '');
|
110
|
+
Object.assign(tgt, propPanel?.defaultSchema || {});
|
106
111
|
}
|
107
112
|
|
108
113
|
return acc;
|
@@ -204,12 +209,24 @@ const TemplateEditor = ({
|
|
204
209
|
}, [initEvents, destroyEvents]);
|
205
210
|
|
206
211
|
const addSchema = () => {
|
207
|
-
const
|
212
|
+
const propPanel = Object.values(propPanelRegistry)[0];
|
213
|
+
|
214
|
+
if (!propPanel) {
|
215
|
+
throw new Error(`[@pdfme/ui] addSchema failed: propPanel is empty.
|
216
|
+
Check this document: https://pdfme.com/docs/custom-schemas`);
|
217
|
+
}
|
218
|
+
|
219
|
+
const s = {
|
220
|
+
id: uuid(),
|
221
|
+
key: `${i18n('field')}${schemasList[pageCursor].length + 1}`,
|
222
|
+
data: propPanel.defaultValue || '',
|
223
|
+
...propPanel.defaultSchema,
|
224
|
+
} as SchemaForUI;
|
225
|
+
|
208
226
|
const paper = paperRefs.current[pageCursor];
|
209
227
|
const rectTop = paper ? paper.getBoundingClientRect().top : 0;
|
210
228
|
s.position.y = rectTop > 0 ? 0 : pageSizes[pageCursor].height / 2;
|
211
|
-
|
212
|
-
s.key = `${i18n('field')}${schemasList[pageCursor].length + 1}`;
|
229
|
+
|
213
230
|
commitSchemas(schemasList[pageCursor].concat(s));
|
214
231
|
setTimeout(() => onEdit([document.getElementById(s.id)!]));
|
215
232
|
};
|
@@ -222,14 +239,19 @@ const TemplateEditor = ({
|
|
222
239
|
setHoveringSchemaId(id);
|
223
240
|
};
|
224
241
|
|
242
|
+
const sizeExcSidebar = {
|
243
|
+
width: sidebarOpen ? size.width - SIDEBAR_WIDTH : size.width,
|
244
|
+
height: size.height,
|
245
|
+
};
|
246
|
+
|
225
247
|
if (error) {
|
226
|
-
return <
|
248
|
+
return <ErrorScreen size={size} error={error} />;
|
227
249
|
}
|
228
250
|
|
229
251
|
return (
|
230
252
|
<Root size={size} scale={scale}>
|
231
253
|
<CtlBar
|
232
|
-
size={
|
254
|
+
size={sizeExcSidebar}
|
233
255
|
pageCursor={pageCursor}
|
234
256
|
pageNum={schemasList.length}
|
235
257
|
setPageCursor={(p) => {
|
@@ -239,12 +261,7 @@ const TemplateEditor = ({
|
|
239
261
|
onEditEnd();
|
240
262
|
}}
|
241
263
|
zoomLevel={zoomLevel}
|
242
|
-
setZoomLevel={
|
243
|
-
if (mainRef.current) {
|
244
|
-
mainRef.current.scrollTop = getPagesScrollTopByIndex(pageSizes, pageCursor, scale);
|
245
|
-
}
|
246
|
-
setZoomLevel(zoom);
|
247
|
-
}}
|
264
|
+
setZoomLevel={setZoomLevel}
|
248
265
|
/>
|
249
266
|
<Sidebar
|
250
267
|
hoveringSchemaId={hoveringSchemaId}
|
@@ -262,8 +279,11 @@ const TemplateEditor = ({
|
|
262
279
|
}}
|
263
280
|
onEditEnd={onEditEnd}
|
264
281
|
addSchema={addSchema}
|
282
|
+
deselectSchema={onEditEnd}
|
283
|
+
sidebarOpen={sidebarOpen}
|
284
|
+
setSidebarOpen={setSidebarOpen}
|
265
285
|
/>
|
266
|
-
<
|
286
|
+
<Canvas
|
267
287
|
ref={mainRef}
|
268
288
|
paperRefs={paperRefs}
|
269
289
|
hoveringSchemaId={hoveringSchemaId}
|
@@ -271,13 +291,14 @@ const TemplateEditor = ({
|
|
271
291
|
height={size.height - RULER_HEIGHT * ZOOM}
|
272
292
|
pageCursor={pageCursor}
|
273
293
|
scale={scale}
|
274
|
-
size={
|
294
|
+
size={sizeExcSidebar}
|
275
295
|
pageSizes={pageSizes}
|
276
296
|
backgrounds={backgrounds}
|
277
297
|
activeElements={activeElements}
|
278
298
|
schemasList={schemasList}
|
279
299
|
changeSchemas={changeSchemas}
|
280
300
|
removeSchemas={removeSchemas}
|
301
|
+
sidebarOpen={sidebarOpen}
|
281
302
|
onEdit={onEdit}
|
282
303
|
/>
|
283
304
|
</Root>
|
@@ -2,7 +2,7 @@ import React, { useContext } from 'react';
|
|
2
2
|
import { Size } from '@pdfme/common';
|
3
3
|
import { I18nContext } from '../contexts';
|
4
4
|
|
5
|
-
const
|
5
|
+
const ErrorScreen = ({ size, error }: { size: Size; error: Error }) => {
|
6
6
|
const i18n = useContext(I18nContext);
|
7
7
|
|
8
8
|
return (
|
@@ -28,4 +28,4 @@ const Error = ({ size, error }: { size: Size; error: Error }) => {
|
|
28
28
|
);
|
29
29
|
};
|
30
30
|
|
31
|
-
export default
|
31
|
+
export default ErrorScreen;
|
package/src/components/Paper.tsx
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import React, { MutableRefObject, ReactNode, useContext } from 'react';
|
2
|
-
import { SchemaForUI, Size, getFallbackFontName } from '@pdfme/common';
|
2
|
+
import { ZOOM, SchemaForUI, Size, getFallbackFontName } from '@pdfme/common';
|
3
3
|
import { FontContext } from '../contexts';
|
4
|
-
import {
|
4
|
+
import { RULER_HEIGHT, PAGE_GAP } from '../constants';
|
5
5
|
|
6
6
|
const Paper = (props: {
|
7
7
|
paperRefs: MutableRefObject<HTMLDivElement[]>;
|
@@ -12,10 +12,21 @@ const Paper = (props: {
|
|
12
12
|
backgrounds: string[];
|
13
13
|
renderPaper?: (arg: { index: number; paperSize: Size }) => ReactNode;
|
14
14
|
renderSchema: (arg: { index: number; schema: SchemaForUI }) => ReactNode;
|
15
|
+
hasRulers?: boolean;
|
15
16
|
}) => {
|
16
|
-
const {
|
17
|
-
|
17
|
+
const {
|
18
|
+
paperRefs,
|
19
|
+
scale,
|
20
|
+
size,
|
21
|
+
schemasList,
|
22
|
+
pageSizes,
|
23
|
+
backgrounds,
|
24
|
+
renderPaper,
|
25
|
+
renderSchema,
|
26
|
+
hasRulers,
|
27
|
+
} = props;
|
18
28
|
const font = useContext(FontContext);
|
29
|
+
const rulerHeight = hasRulers ? RULER_HEIGHT : 0;
|
19
30
|
|
20
31
|
if (pageSizes.length !== backgrounds.length || pageSizes.length !== schemasList.length) {
|
21
32
|
return null;
|
@@ -25,14 +36,30 @@ const Paper = (props: {
|
|
25
36
|
<div
|
26
37
|
style={{
|
27
38
|
transform: `scale(${scale})`,
|
28
|
-
transformOrigin: '
|
29
|
-
|
39
|
+
transformOrigin: 'top left',
|
40
|
+
// NOTE: These values do not impact the UI unless they exceed the Paper sizes.
|
41
|
+
// We set them to the scale value to ensure the container is redrawn when you zoom in/out.
|
42
|
+
height: scale,
|
43
|
+
width: scale,
|
30
44
|
}}
|
31
45
|
>
|
32
46
|
{backgrounds.map((background, paperIndex) => {
|
33
47
|
const pageSize = pageSizes[paperIndex];
|
34
48
|
const paperSize = { width: pageSize.width * ZOOM, height: pageSize.height * ZOOM };
|
35
49
|
|
50
|
+
// We want to center the content within the available viewport, but transform: scale()
|
51
|
+
// must be done from the top-left or CSS crops off left-hand content as you zoom in.
|
52
|
+
// However, we want to display the content centrally, so we apply a left indent for
|
53
|
+
// when the content does not exceed its container
|
54
|
+
const leftCenteringIndent =
|
55
|
+
paperSize.width * scale + rulerHeight < size.width
|
56
|
+
? `${(size.width / scale - paperSize.width) / 2}px`
|
57
|
+
: `${rulerHeight}px`;
|
58
|
+
|
59
|
+
// Rulers are drawn above/before the top of each page, so we place the start of the page below them
|
60
|
+
const pageTop =
|
61
|
+
paperIndex > 0 ? `${(rulerHeight + PAGE_GAP) * (paperIndex + 1)}px` : `${rulerHeight}px`;
|
62
|
+
|
36
63
|
return (
|
37
64
|
<div
|
38
65
|
id={`@pdfme/ui-paper${paperIndex}`}
|
@@ -54,9 +81,8 @@ const Paper = (props: {
|
|
54
81
|
}}
|
55
82
|
style={{
|
56
83
|
fontFamily: `'${getFallbackFontName(font)}'`,
|
57
|
-
top:
|
58
|
-
left:
|
59
|
-
margin: '0 auto',
|
84
|
+
top: pageTop,
|
85
|
+
left: leftCenteringIndent,
|
60
86
|
position: 'relative',
|
61
87
|
backgroundImage: `url(${background})`,
|
62
88
|
backgroundSize: `${paperSize.width}px ${paperSize.height}px`,
|
@@ -1,17 +1,24 @@
|
|
1
1
|
import React, { useCallback, useRef, useState, useEffect } from 'react';
|
2
|
-
import {
|
3
|
-
import { ZOOM, RULER_HEIGHT } from '../constants';
|
2
|
+
import type { SchemaForUI, PreviewProps, Size } from '@pdfme/common';
|
4
3
|
import UnitPager from './UnitPager';
|
5
4
|
import Root from './Root';
|
6
|
-
import
|
5
|
+
import ErrorScreen from './ErrorScreen';
|
7
6
|
import CtlBar from './CtlBar/index';
|
8
7
|
import Paper from './Paper';
|
9
|
-
import
|
8
|
+
import Renderer from './Renderer';
|
10
9
|
import { useUIPreProcessor, useScrollPageCursor } from '../hooks';
|
11
10
|
import { templateSchemas2SchemasList, getPagesScrollTopByIndex } from '../helper';
|
12
11
|
|
13
|
-
const Preview = ({
|
14
|
-
|
12
|
+
const Preview = ({
|
13
|
+
template,
|
14
|
+
inputs,
|
15
|
+
size,
|
16
|
+
onChangeInput,
|
17
|
+
}: Omit<PreviewProps, 'domContainer'> & {
|
18
|
+
onChangeInput?: (args: { index: number; value: string; key: string }) => void;
|
19
|
+
size: Size;
|
20
|
+
}) => {
|
21
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
15
22
|
const paperRefs = useRef<HTMLDivElement[]>([]);
|
16
23
|
|
17
24
|
const [unitCursor, setUnitCursor] = useState(0);
|
@@ -37,7 +44,7 @@ const Preview = ({ template, inputs, size, onChangeInput }: PreviewReactProps) =
|
|
37
44
|
}, [init]);
|
38
45
|
|
39
46
|
useScrollPageCursor({
|
40
|
-
ref:
|
47
|
+
ref: containerRef,
|
41
48
|
pageSizes,
|
42
49
|
scale,
|
43
50
|
pageCursor,
|
@@ -47,68 +54,59 @@ const Preview = ({ template, inputs, size, onChangeInput }: PreviewReactProps) =
|
|
47
54
|
const handleChangeInput = ({ key, value }: { key: string; value: string }) =>
|
48
55
|
onChangeInput && onChangeInput({ index: unitCursor, key, value });
|
49
56
|
|
50
|
-
const
|
57
|
+
const isForm = Boolean(onChangeInput);
|
58
|
+
|
51
59
|
const input = inputs[unitCursor];
|
52
60
|
|
53
61
|
if (error) {
|
54
|
-
return <
|
62
|
+
return <ErrorScreen size={size} error={error} />;
|
55
63
|
}
|
56
64
|
|
57
|
-
const pageSizesHeightSum = pageSizes.reduce(
|
58
|
-
(acc, cur) => acc + (cur.height * ZOOM + RULER_HEIGHT * scale) * scale,
|
59
|
-
0
|
60
|
-
);
|
61
|
-
|
62
65
|
return (
|
63
|
-
<Root
|
66
|
+
<Root size={size} scale={scale}>
|
64
67
|
<CtlBar
|
65
|
-
size={
|
68
|
+
size={size}
|
66
69
|
pageCursor={pageCursor}
|
67
70
|
pageNum={schemasList.length}
|
68
71
|
setPageCursor={(p) => {
|
69
|
-
if (!
|
70
|
-
|
72
|
+
if (!containerRef.current) return;
|
73
|
+
containerRef.current.scrollTop = getPagesScrollTopByIndex(pageSizes, p, scale);
|
71
74
|
setPageCursor(p);
|
72
75
|
}}
|
73
76
|
zoomLevel={zoomLevel}
|
74
|
-
setZoomLevel={
|
75
|
-
if (rootRef.current) {
|
76
|
-
rootRef.current.scrollTop = getPagesScrollTopByIndex(pageSizes, pageCursor, scale);
|
77
|
-
}
|
78
|
-
setZoomLevel(zoom);
|
79
|
-
}}
|
77
|
+
setZoomLevel={setZoomLevel}
|
80
78
|
/>
|
81
79
|
<UnitPager
|
82
|
-
size={
|
80
|
+
size={size}
|
83
81
|
unitCursor={unitCursor}
|
84
82
|
unitNum={inputs.length}
|
85
83
|
setUnitCursor={setUnitCursor}
|
86
84
|
/>
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
85
|
+
<div ref={containerRef} style={{ ...size, position: 'relative', overflow: 'auto' }}>
|
86
|
+
<Paper
|
87
|
+
paperRefs={paperRefs}
|
88
|
+
scale={scale}
|
89
|
+
size={size}
|
90
|
+
schemasList={schemasList}
|
91
|
+
pageSizes={pageSizes}
|
92
|
+
backgrounds={backgrounds}
|
93
|
+
renderSchema={({ schema, index }) => {
|
94
|
+
const { key } = schema;
|
95
|
+
const data = (input && input[key]) || '';
|
96
|
+
return (
|
97
|
+
<Renderer
|
98
|
+
key={schema.id}
|
99
|
+
schema={Object.assign(schema, { data })}
|
100
|
+
mode={isForm ? 'form' : 'viewer'}
|
101
|
+
placeholder={template.sampledata?.[0]?.[key] ?? ''}
|
102
|
+
tabIndex={index + 100}
|
103
|
+
onChange={(value) => handleChangeInput({ key, value })}
|
104
|
+
outline={isForm ? '1px dashed #4af' : 'transparent'}
|
105
|
+
/>
|
106
|
+
);
|
107
|
+
}}
|
108
|
+
/>
|
109
|
+
</div>
|
112
110
|
</Root>
|
113
111
|
);
|
114
112
|
};
|