@pdfme/ui 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +45 -0
- package/README.md +280 -0
- package/declaration.d.ts +8 -0
- package/dist/@pdfme/ui.js +3 -0
- package/dist/@pdfme/ui.js.LICENSE.txt +95 -0
- package/dist/@pdfme/ui.js.map +1 -0
- package/dist/types/common/src/barcode.d.ts +2 -0
- package/dist/types/common/src/constants.d.ts +6 -0
- package/dist/types/common/src/helper.d.ts +15 -0
- package/dist/types/common/src/index.d.ts +4 -0
- package/dist/types/common/src/schema.d.ts +3613 -0
- package/dist/types/common/src/type.d.ts +64 -0
- package/dist/types/common/src/utils.d.ts +12 -0
- package/dist/types/ui/src/Designer.d.ts +13 -0
- package/dist/types/ui/src/Form.d.ts +13 -0
- package/dist/types/ui/src/Viewer.d.ts +7 -0
- package/dist/types/ui/src/class.d.ts +72 -0
- package/dist/types/ui/src/components/Designer/Main/Guides.d.ts +9 -0
- package/dist/types/ui/src/components/Designer/Main/Mask.d.ts +3 -0
- package/dist/types/ui/src/components/Designer/Main/Moveable.d.ts +31 -0
- package/dist/types/ui/src/components/Designer/Main/Selecto.d.ts +8 -0
- package/dist/types/ui/src/components/Designer/Main/index.d.ts +24 -0
- package/dist/types/ui/src/components/Designer/Sidebar/DetailView/ExampleInputEditor.d.ts +3 -0
- package/dist/types/ui/src/components/Designer/Sidebar/DetailView/PositionAndSizeEditor.d.ts +3 -0
- package/dist/types/ui/src/components/Designer/Sidebar/DetailView/TextPropEditor.d.ts +3 -0
- package/dist/types/ui/src/components/Designer/Sidebar/DetailView/TypeAndKeyEditor.d.ts +3 -0
- package/dist/types/ui/src/components/Designer/Sidebar/DetailView/index.d.ts +3 -0
- package/dist/types/ui/src/components/Designer/Sidebar/ListView.d.ts +3 -0
- package/dist/types/ui/src/components/Designer/Sidebar/index.d.ts +26 -0
- package/dist/types/ui/src/components/Designer/index.d.ts +99 -0
- package/dist/types/ui/src/components/Divider.d.ts +2 -0
- package/dist/types/ui/src/components/Error.d.ts +7 -0
- package/dist/types/ui/src/components/Paper.d.ts +19 -0
- package/dist/types/ui/src/components/Preview/Pager/Page.d.ts +8 -0
- package/dist/types/ui/src/components/Preview/Pager/Unit.d.ts +8 -0
- package/dist/types/ui/src/components/Preview/index.d.ts +4 -0
- package/dist/types/ui/src/components/Root.d.ts +9 -0
- package/dist/types/ui/src/components/Schemas/BarcodeSchema.d.ts +15 -0
- package/dist/types/ui/src/components/Schemas/ImageSchema.d.ts +15 -0
- package/dist/types/ui/src/components/Schemas/SchemaUI.d.ts +14 -0
- package/dist/types/ui/src/components/Schemas/TextSchema.d.ts +22 -0
- package/dist/types/ui/src/components/Spinner.d.ts +2 -0
- package/dist/types/ui/src/constants.d.ts +5 -0
- package/dist/types/ui/src/contexts.d.ts +7 -0
- package/dist/types/ui/src/helper.d.ts +91 -0
- package/dist/types/ui/src/hooks.d.ts +26 -0
- package/dist/types/ui/src/i18n.d.ts +30 -0
- package/dist/types/ui/src/index.d.ts +5 -0
- package/dist/types/ui/src/libs/class.d.ts +84 -0
- package/dist/types/ui/src/libs/contexts.d.ts +7 -0
- package/dist/types/ui/src/libs/helper.d.ts +64 -0
- package/dist/types/ui/src/libs/hooks.d.ts +26 -0
- package/dist/types/ui/src/libs/i18n.d.ts +30 -0
- package/dist/types/ui/src/libs/ui.d.ts +64 -0
- package/package.json +80 -0
- package/public/Designer.html +90 -0
- package/public/Form.html +74 -0
- package/public/SauceHanSansJP.ttf +0 -0
- package/public/SauceHanSerifJP.ttf +0 -0
- package/public/Viewer.html +73 -0
- package/public/helper.js +51 -0
- package/public/index.html +54 -0
- package/src/Designer.tsx +72 -0
- package/src/Form.tsx +45 -0
- package/src/Viewer.tsx +27 -0
- package/src/assets/barcodeExamples/code128.png +0 -0
- package/src/assets/barcodeExamples/code39.png +0 -0
- package/src/assets/barcodeExamples/ean13.png +0 -0
- package/src/assets/barcodeExamples/ean8.png +0 -0
- package/src/assets/barcodeExamples/itf14.png +0 -0
- package/src/assets/barcodeExamples/japanpost.png +0 -0
- package/src/assets/barcodeExamples/nw7.png +0 -0
- package/src/assets/barcodeExamples/qrcode.png +0 -0
- package/src/assets/barcodeExamples/upca.png +0 -0
- package/src/assets/barcodeExamples/upce.png +0 -0
- package/src/assets/icons/back.svg +4 -0
- package/src/assets/icons/double-left.svg +11 -0
- package/src/assets/icons/double-right.svg +11 -0
- package/src/assets/icons/drag.svg +3 -0
- package/src/assets/icons/forward.svg +4 -0
- package/src/assets/icons/left.svg +4 -0
- package/src/assets/icons/right.svg +4 -0
- package/src/assets/icons/warning.svg +4 -0
- package/src/assets/imageExample.png +0 -0
- package/src/class.ts +147 -0
- package/src/components/Designer/Main/Guides.tsx +53 -0
- package/src/components/Designer/Main/Mask.tsx +19 -0
- package/src/components/Designer/Main/Moveable.tsx +79 -0
- package/src/components/Designer/Main/Selecto.tsx +29 -0
- package/src/components/Designer/Main/index.tsx +314 -0
- package/src/components/Designer/Sidebar/DetailView/ExampleInputEditor.tsx +62 -0
- package/src/components/Designer/Sidebar/DetailView/PositionAndSizeEditor.tsx +98 -0
- package/src/components/Designer/Sidebar/DetailView/TextPropEditor.tsx +178 -0
- package/src/components/Designer/Sidebar/DetailView/TypeAndKeyEditor.tsx +79 -0
- package/src/components/Designer/Sidebar/DetailView/index.tsx +39 -0
- package/src/components/Designer/Sidebar/ListView.tsx +180 -0
- package/src/components/Designer/Sidebar/index.tsx +102 -0
- package/src/components/Designer/index.tsx +283 -0
- package/src/components/Divider.tsx +7 -0
- package/src/components/Error.tsx +31 -0
- package/src/components/Paper.tsx +77 -0
- package/src/components/Preview/Pager/Page.tsx +85 -0
- package/src/components/Preview/Pager/Unit.tsx +87 -0
- package/src/components/Preview/index.tsx +102 -0
- package/src/components/Root.tsx +52 -0
- package/src/components/Schemas/BarcodeSchema.tsx +111 -0
- package/src/components/Schemas/ImageSchema.tsx +81 -0
- package/src/components/Schemas/SchemaUI.tsx +64 -0
- package/src/components/Schemas/TextSchema.tsx +62 -0
- package/src/components/Spinner.tsx +37 -0
- package/src/constants.ts +9 -0
- package/src/contexts.ts +8 -0
- package/src/helper.ts +516 -0
- package/src/hooks.ts +107 -0
- package/src/i18n.ts +64 -0
- package/src/index.ts +77 -0
- package/tsconfig.json +21 -0
- package/webpack.config.js +73 -0
package/src/helper.ts
ADDED
@@ -0,0 +1,516 @@
|
|
1
|
+
// @ts-ignore
|
2
|
+
import PDFJSWorker from 'pdfjs-dist/build/pdf.worker.entry';
|
3
|
+
import { getDocument, GlobalWorkerOptions } from 'pdfjs-dist';
|
4
|
+
GlobalWorkerOptions.workerSrc = PDFJSWorker;
|
5
|
+
import hotkeys from 'hotkeys-js';
|
6
|
+
import {
|
7
|
+
getB64BasePdf,
|
8
|
+
b64toUint8Array,
|
9
|
+
Template,
|
10
|
+
SchemaForUI,
|
11
|
+
Schema,
|
12
|
+
Size,
|
13
|
+
DEFAULT_ALIGNMENT,
|
14
|
+
DEFAULT_FONT_SIZE,
|
15
|
+
DEFAULT_CHARACTER_SPACING,
|
16
|
+
DEFAULT_LINE_HEIGHT,
|
17
|
+
} from '@pdfme/common';
|
18
|
+
|
19
|
+
export const uuid = () =>
|
20
|
+
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
21
|
+
const r = (Math.random() * 16) | 0;
|
22
|
+
const v = c == 'x' ? r : (r & 0x3) | 0x8;
|
23
|
+
return v.toString(16);
|
24
|
+
});
|
25
|
+
|
26
|
+
export const set = <T extends object>(obj: T, path: string | string[], value: any) => {
|
27
|
+
path = Array.isArray(path) ? path : path.replace('[', '.').replace(']', '').split('.');
|
28
|
+
let src: any = obj;
|
29
|
+
path.forEach((key, index, array) => {
|
30
|
+
if (index == path.length - 1) {
|
31
|
+
src[key] = value;
|
32
|
+
} else {
|
33
|
+
if (!src.hasOwnProperty(key)) {
|
34
|
+
const next = array[index + 1];
|
35
|
+
src[key] = String(Number(next)) === next ? [] : {};
|
36
|
+
}
|
37
|
+
src = src[key];
|
38
|
+
}
|
39
|
+
});
|
40
|
+
};
|
41
|
+
|
42
|
+
export const debounce = <T extends Function>(cb: T, wait = 20) => {
|
43
|
+
let h: null | ReturnType<typeof setTimeout> = null;
|
44
|
+
const callable = (...args: any) => {
|
45
|
+
if (h) clearTimeout(h);
|
46
|
+
h = setTimeout(() => cb(...args), wait);
|
47
|
+
};
|
48
|
+
return <T>(<any>callable);
|
49
|
+
};
|
50
|
+
|
51
|
+
const shift = (number: number, precision: number, reverseShift: boolean) => {
|
52
|
+
if (reverseShift) {
|
53
|
+
precision = -precision;
|
54
|
+
}
|
55
|
+
const numArray = `${number}`.split('e');
|
56
|
+
|
57
|
+
return Number(`${numArray[0]}e${numArray[1] ? Number(numArray[1]) + precision : precision}`);
|
58
|
+
};
|
59
|
+
|
60
|
+
export const round = (number: number, precision: number) => {
|
61
|
+
return shift(Math.round(shift(number, precision, false)), precision, true);
|
62
|
+
};
|
63
|
+
|
64
|
+
export const arrayMove = <T>(array: T[], from: number, to: number): T[] => {
|
65
|
+
array = array.slice();
|
66
|
+
const startIndex = to < 0 ? array.length + to : to;
|
67
|
+
const [item] = array.splice(from, 1);
|
68
|
+
array.splice(startIndex, 0, item);
|
69
|
+
|
70
|
+
return array;
|
71
|
+
};
|
72
|
+
|
73
|
+
export const cloneDeep = <T>(value: T): T => JSON.parse(JSON.stringify(value));
|
74
|
+
|
75
|
+
export const flatten = <T>(arr: T[][]): T[] => ([] as T[]).concat(...arr);
|
76
|
+
|
77
|
+
const up = 'up';
|
78
|
+
const shiftUp = 'shift+up';
|
79
|
+
const down = 'down';
|
80
|
+
const shiftDown = 'shift+down';
|
81
|
+
const left = 'left';
|
82
|
+
const shiftLeft = 'shift+left';
|
83
|
+
const right = 'right';
|
84
|
+
const shiftRight = 'shift+right';
|
85
|
+
|
86
|
+
const rmWin = 'backspace';
|
87
|
+
const rmMac = 'delete';
|
88
|
+
const esc = 'esc';
|
89
|
+
const copyWin = 'ctrl+c';
|
90
|
+
const copyMac = 'command+c';
|
91
|
+
const pasteWin = 'ctrl+v';
|
92
|
+
const pasteMac = 'command+v';
|
93
|
+
const redoWin = 'ctrl+y';
|
94
|
+
const redoMac = 'shift+command+z';
|
95
|
+
const undoWin = 'ctrl+z';
|
96
|
+
const undoMac = 'command+z';
|
97
|
+
const saveWin = 'ctrl+s';
|
98
|
+
const saveMac = 'command+s';
|
99
|
+
|
100
|
+
const keys = [
|
101
|
+
up,
|
102
|
+
shiftUp,
|
103
|
+
down,
|
104
|
+
shiftDown,
|
105
|
+
left,
|
106
|
+
shiftLeft,
|
107
|
+
right,
|
108
|
+
shiftRight,
|
109
|
+
rmMac,
|
110
|
+
rmWin,
|
111
|
+
esc,
|
112
|
+
copyWin,
|
113
|
+
copyMac,
|
114
|
+
pasteWin,
|
115
|
+
pasteMac,
|
116
|
+
redoWin,
|
117
|
+
redoMac,
|
118
|
+
undoWin,
|
119
|
+
undoMac,
|
120
|
+
saveWin,
|
121
|
+
saveMac,
|
122
|
+
];
|
123
|
+
|
124
|
+
export const initShortCuts = (arg: {
|
125
|
+
move: (command: 'up' | 'down' | 'left' | 'right', isShift: boolean) => void;
|
126
|
+
remove: () => void;
|
127
|
+
esc: () => void;
|
128
|
+
copy: () => void;
|
129
|
+
paste: () => void;
|
130
|
+
redo: () => void;
|
131
|
+
undo: () => void;
|
132
|
+
save: () => void;
|
133
|
+
}) => {
|
134
|
+
hotkeys(keys.join(), (e, handler) => {
|
135
|
+
switch (handler.shortcut) {
|
136
|
+
case up:
|
137
|
+
case shiftUp:
|
138
|
+
e.preventDefault();
|
139
|
+
arg.move('up', hotkeys.shift);
|
140
|
+
break;
|
141
|
+
case down:
|
142
|
+
case shiftDown:
|
143
|
+
e.preventDefault();
|
144
|
+
arg.move('down', hotkeys.shift);
|
145
|
+
break;
|
146
|
+
case left:
|
147
|
+
case shiftLeft:
|
148
|
+
e.preventDefault();
|
149
|
+
arg.move('left', hotkeys.shift);
|
150
|
+
break;
|
151
|
+
case right:
|
152
|
+
case shiftRight:
|
153
|
+
e.preventDefault();
|
154
|
+
arg.move('right', hotkeys.shift);
|
155
|
+
break;
|
156
|
+
case rmWin:
|
157
|
+
case rmMac:
|
158
|
+
arg.remove();
|
159
|
+
break;
|
160
|
+
case esc:
|
161
|
+
arg.esc();
|
162
|
+
break;
|
163
|
+
case copyWin:
|
164
|
+
case copyMac:
|
165
|
+
arg.copy();
|
166
|
+
break;
|
167
|
+
case pasteWin:
|
168
|
+
case pasteMac:
|
169
|
+
arg.paste();
|
170
|
+
break;
|
171
|
+
case redoWin:
|
172
|
+
case redoMac:
|
173
|
+
arg.redo();
|
174
|
+
break;
|
175
|
+
case undoWin:
|
176
|
+
case undoMac:
|
177
|
+
arg.undo();
|
178
|
+
break;
|
179
|
+
case saveWin:
|
180
|
+
case saveMac:
|
181
|
+
e.preventDefault();
|
182
|
+
arg.save();
|
183
|
+
break;
|
184
|
+
default:
|
185
|
+
break;
|
186
|
+
}
|
187
|
+
});
|
188
|
+
};
|
189
|
+
|
190
|
+
export const destroyShortCuts = () => {
|
191
|
+
hotkeys.unbind(keys.join());
|
192
|
+
};
|
193
|
+
|
194
|
+
const readFile = (file: File | null, type: 'text' | 'dataURL' | 'arrayBuffer') => {
|
195
|
+
return new Promise<string | ArrayBuffer>((r) => {
|
196
|
+
const fileReader = new FileReader();
|
197
|
+
fileReader.addEventListener('load', (e) => {
|
198
|
+
if (e && e.target && e.target.result && file !== null) {
|
199
|
+
r(e.target.result);
|
200
|
+
}
|
201
|
+
});
|
202
|
+
if (file !== null) {
|
203
|
+
if (type === 'text') {
|
204
|
+
fileReader.readAsText(file);
|
205
|
+
} else if (type === 'dataURL') {
|
206
|
+
fileReader.readAsDataURL(file);
|
207
|
+
} else if (type === 'arrayBuffer') {
|
208
|
+
fileReader.readAsArrayBuffer(file);
|
209
|
+
}
|
210
|
+
}
|
211
|
+
});
|
212
|
+
};
|
213
|
+
|
214
|
+
export const readFiles = (files: FileList | null, type: 'text' | 'dataURL' | 'arrayBuffer') => {
|
215
|
+
return new Promise<string | ArrayBuffer>((r) => {
|
216
|
+
const fileReader = new FileReader();
|
217
|
+
fileReader.addEventListener('load', (e) => {
|
218
|
+
if (e && e.target && e.target.result && files !== null) {
|
219
|
+
r(e.target.result);
|
220
|
+
}
|
221
|
+
});
|
222
|
+
if (files !== null && files[0]) {
|
223
|
+
readFile(files[0], type).then((data) => r(data));
|
224
|
+
}
|
225
|
+
});
|
226
|
+
};
|
227
|
+
|
228
|
+
const sortSchemasList = (template: Template, pageNum: number): SchemaForUI[][] =>
|
229
|
+
new Array(pageNum).fill('').reduce((acc, _, i) => {
|
230
|
+
acc.push(
|
231
|
+
template.schemas[i]
|
232
|
+
? Object.entries(template.schemas[i])
|
233
|
+
.sort((a, b) => {
|
234
|
+
const aIndex = (template.columns ?? []).findIndex((c) => c === a[0]);
|
235
|
+
const bIndex = (template.columns ?? []).findIndex((c) => c === b[0]);
|
236
|
+
|
237
|
+
return aIndex > bIndex ? 1 : -1;
|
238
|
+
})
|
239
|
+
.map((e) => {
|
240
|
+
const [key, value] = e;
|
241
|
+
const data = template.sampledata ? template.sampledata[0][key] : '';
|
242
|
+
|
243
|
+
return Object.assign(value, {
|
244
|
+
key,
|
245
|
+
data,
|
246
|
+
id: uuid(),
|
247
|
+
});
|
248
|
+
})
|
249
|
+
: []
|
250
|
+
);
|
251
|
+
|
252
|
+
return acc;
|
253
|
+
}, [] as SchemaForUI[][]);
|
254
|
+
|
255
|
+
const pt2mm = (pt: number) => {
|
256
|
+
// https://www.ddc.co.jp/words/archives/20090701114500.html
|
257
|
+
const mmRatio = 0.3527;
|
258
|
+
|
259
|
+
return parseFloat(String(pt)) * mmRatio;
|
260
|
+
};
|
261
|
+
|
262
|
+
export const getPdfPageSizes = async (pdfBlob: Blob) => {
|
263
|
+
const url = URL.createObjectURL(pdfBlob);
|
264
|
+
const pdfDoc = await getDocument({ url }).promise;
|
265
|
+
|
266
|
+
const promises = Promise.all(
|
267
|
+
new Array(pdfDoc.numPages).fill('').map(async (_, i) => {
|
268
|
+
const pageSize = await pdfDoc.getPage(i + 1).then((page) => {
|
269
|
+
const { height, width } = page.getViewport({ scale: 1 });
|
270
|
+
|
271
|
+
return { height: pt2mm(height), width: pt2mm(width) };
|
272
|
+
});
|
273
|
+
|
274
|
+
return pageSize;
|
275
|
+
})
|
276
|
+
);
|
277
|
+
|
278
|
+
URL.revokeObjectURL(url);
|
279
|
+
|
280
|
+
return promises;
|
281
|
+
};
|
282
|
+
|
283
|
+
const pdf2Images = async (pdfBlob: Blob, width: number, imageType: 'png' | 'jpeg') => {
|
284
|
+
const url = URL.createObjectURL(pdfBlob);
|
285
|
+
const pdfDoc = await getDocument({ url }).promise;
|
286
|
+
|
287
|
+
const promises = Promise.all(
|
288
|
+
new Array(pdfDoc.numPages).fill('').map(async (_, i) => {
|
289
|
+
const image = await pdfDoc.getPage(i + 1).then((page) => {
|
290
|
+
const canvas = document.createElement('canvas');
|
291
|
+
canvas.width = width * 2;
|
292
|
+
const canvasContext = canvas.getContext('2d')!;
|
293
|
+
const scaleRequired = canvas.width / page.getViewport({ scale: 1 }).width;
|
294
|
+
const viewport = page.getViewport({ scale: scaleRequired });
|
295
|
+
canvas.height = viewport.height;
|
296
|
+
|
297
|
+
return page
|
298
|
+
.render({ canvasContext, viewport })
|
299
|
+
.promise.then(() => canvas.toDataURL(`image/${imageType}`));
|
300
|
+
});
|
301
|
+
|
302
|
+
return image;
|
303
|
+
})
|
304
|
+
);
|
305
|
+
URL.revokeObjectURL(url);
|
306
|
+
|
307
|
+
return promises;
|
308
|
+
};
|
309
|
+
|
310
|
+
export const pdf2Pngs = (pdfBlob: Blob, width: number) => pdf2Images(pdfBlob, width, 'png');
|
311
|
+
|
312
|
+
export const b64toBlob = (base64: string) => {
|
313
|
+
const uniy8Array = b64toUint8Array(base64);
|
314
|
+
const [, , mimeType] = base64.match(/(:)([a-z/]+)(;)/)!;
|
315
|
+
|
316
|
+
return new Blob([uniy8Array.buffer], { type: mimeType });
|
317
|
+
};
|
318
|
+
|
319
|
+
export const templateSchemas2SchemasList = async (_template: Template) => {
|
320
|
+
const template = cloneDeep(_template);
|
321
|
+
const sortedSchemasList = sortSchemasList(template, template.schemas.length);
|
322
|
+
const basePdf = await getB64BasePdf(template.basePdf);
|
323
|
+
const pdfBlob = b64toBlob(basePdf);
|
324
|
+
const pageSizes = await getPdfPageSizes(pdfBlob);
|
325
|
+
const ssl = sortedSchemasList.length;
|
326
|
+
const psl = pageSizes.length;
|
327
|
+
const schemasList = (
|
328
|
+
ssl < psl
|
329
|
+
? sortedSchemasList.concat(new Array(psl - ssl).fill(cloneDeep([])))
|
330
|
+
: sortedSchemasList.slice(0, pageSizes.length)
|
331
|
+
).map((schema, i) => {
|
332
|
+
Object.values(schema).forEach((value) => {
|
333
|
+
const { width, height } = pageSizes[i];
|
334
|
+
const xEdge = value.position.x + value.width;
|
335
|
+
const yEdge = value.position.y + value.height;
|
336
|
+
if (width < xEdge) {
|
337
|
+
const diff = xEdge - width;
|
338
|
+
value.position.x += diff;
|
339
|
+
}
|
340
|
+
if (height < yEdge) {
|
341
|
+
const diff = yEdge - height;
|
342
|
+
value.position.y += diff;
|
343
|
+
}
|
344
|
+
});
|
345
|
+
|
346
|
+
return schema;
|
347
|
+
});
|
348
|
+
|
349
|
+
return schemasList;
|
350
|
+
};
|
351
|
+
|
352
|
+
export const fmtTemplate = (template: Template, schemasList: SchemaForUI[][]): Template => {
|
353
|
+
const schemaAddedTemplate: Template = {
|
354
|
+
schemas: cloneDeep(schemasList).map((schema) =>
|
355
|
+
schema.reduce((acc, cur) => {
|
356
|
+
const k = cur.key;
|
357
|
+
// @ts-ignore
|
358
|
+
delete cur.id;
|
359
|
+
// @ts-ignore
|
360
|
+
delete cur.key;
|
361
|
+
// @ts-ignore
|
362
|
+
delete cur.data;
|
363
|
+
acc[k] = cur;
|
364
|
+
|
365
|
+
return acc;
|
366
|
+
}, {} as { [key: string]: Schema })
|
367
|
+
),
|
368
|
+
columns: cloneDeep(schemasList).reduce(
|
369
|
+
(acc, cur) => acc.concat(cur.map((s) => s.key)),
|
370
|
+
[] as string[]
|
371
|
+
),
|
372
|
+
sampledata: [
|
373
|
+
cloneDeep(schemasList).reduce((acc, cur) => {
|
374
|
+
cur.forEach((c) => {
|
375
|
+
acc[c.key] = c.data;
|
376
|
+
});
|
377
|
+
|
378
|
+
return acc;
|
379
|
+
}, {} as { [key: string]: string }),
|
380
|
+
],
|
381
|
+
basePdf: template.basePdf,
|
382
|
+
};
|
383
|
+
|
384
|
+
return schemaAddedTemplate;
|
385
|
+
};
|
386
|
+
|
387
|
+
export const getInitialSchema = (): SchemaForUI => ({
|
388
|
+
id: uuid(),
|
389
|
+
key: '',
|
390
|
+
data: '',
|
391
|
+
type: 'text',
|
392
|
+
position: { x: 0, y: 0 },
|
393
|
+
width: 35,
|
394
|
+
height: 7,
|
395
|
+
alignment: DEFAULT_ALIGNMENT,
|
396
|
+
fontSize: DEFAULT_FONT_SIZE,
|
397
|
+
characterSpacing: DEFAULT_CHARACTER_SPACING,
|
398
|
+
lineHeight: DEFAULT_LINE_HEIGHT,
|
399
|
+
});
|
400
|
+
|
401
|
+
export const getSampleByType = (type: string) => {
|
402
|
+
const defaultValue: { [key: string]: string } = {
|
403
|
+
qrcode: 'https://pdfme.com/',
|
404
|
+
japanpost: '6540123789-A-K-Z',
|
405
|
+
ean13: '2112345678900',
|
406
|
+
ean8: '02345673',
|
407
|
+
code39: 'THIS IS CODE 39',
|
408
|
+
code128: 'This is Code 128!',
|
409
|
+
nw7: 'A0123456789B',
|
410
|
+
itf14: '04601234567893',
|
411
|
+
upca: '416000336108',
|
412
|
+
upce: '00123457',
|
413
|
+
};
|
414
|
+
|
415
|
+
return defaultValue[type] ? defaultValue[type] : '';
|
416
|
+
};
|
417
|
+
|
418
|
+
export const getKeepRatioHeightByWidth = (type: string, width: number) => {
|
419
|
+
const raito: { [key: string]: number } = {
|
420
|
+
qrcode: 1,
|
421
|
+
japanpost: 0.09,
|
422
|
+
ean13: 0.4,
|
423
|
+
ean8: 0.5,
|
424
|
+
code39: 0.5,
|
425
|
+
code128: 0.5,
|
426
|
+
nw7: 0.5,
|
427
|
+
itf14: 0.3,
|
428
|
+
upca: 0.4,
|
429
|
+
upce: 0.5,
|
430
|
+
};
|
431
|
+
|
432
|
+
return width * (raito[type] ? raito[type] : 1);
|
433
|
+
};
|
434
|
+
|
435
|
+
export const getUniqSchemaKey = (arg: {
|
436
|
+
copiedSchemaKey: string;
|
437
|
+
schema: SchemaForUI[];
|
438
|
+
stackUniqSchemaKeys: string[];
|
439
|
+
}) => {
|
440
|
+
const { copiedSchemaKey, schema, stackUniqSchemaKeys } = arg;
|
441
|
+
const schemaKeys = schema.map((s) => s.key).concat(stackUniqSchemaKeys);
|
442
|
+
const tmp: { [originalKey: string]: number } = schemaKeys.reduce(
|
443
|
+
(acc, cur) => Object.assign(acc, { originalKey: cur, copiedNum: 0 }),
|
444
|
+
{}
|
445
|
+
);
|
446
|
+
const extractOriginalKey = (key: string) => key.replace(/ copy$| copy [0-9]*$/, '');
|
447
|
+
schemaKeys
|
448
|
+
.filter((key) => / copy$| copy [0-9]*$/.test(key))
|
449
|
+
.forEach((key) => {
|
450
|
+
const originalKey = extractOriginalKey(key);
|
451
|
+
const match = key.match(/[0-9]*$/);
|
452
|
+
const copiedNum = match && match[0] ? Number(match[0]) : 1;
|
453
|
+
if ((tmp[originalKey] ?? 0) < copiedNum) {
|
454
|
+
tmp[originalKey] = copiedNum;
|
455
|
+
}
|
456
|
+
});
|
457
|
+
|
458
|
+
const originalKey = extractOriginalKey(copiedSchemaKey);
|
459
|
+
if (tmp[originalKey]) {
|
460
|
+
const copiedNum = tmp[originalKey];
|
461
|
+
const uniqKey = `${originalKey} copy ${copiedNum + 1}`;
|
462
|
+
stackUniqSchemaKeys.push(uniqKey);
|
463
|
+
|
464
|
+
return uniqKey;
|
465
|
+
}
|
466
|
+
const uniqKey = `${copiedSchemaKey} copy`;
|
467
|
+
stackUniqSchemaKeys.push(uniqKey);
|
468
|
+
|
469
|
+
return uniqKey;
|
470
|
+
};
|
471
|
+
|
472
|
+
export const moveCommandToChangeSchemasArg = (props: {
|
473
|
+
command: 'up' | 'down' | 'left' | 'right';
|
474
|
+
activeSchemas: SchemaForUI[];
|
475
|
+
isShift: boolean;
|
476
|
+
pageSize: Size;
|
477
|
+
}) => {
|
478
|
+
const { command, activeSchemas, isShift, pageSize } = props;
|
479
|
+
const key = command === 'up' || command === 'down' ? 'y' : 'x';
|
480
|
+
const num = isShift ? 0.1 : 1;
|
481
|
+
|
482
|
+
const getValue = (as: SchemaForUI) => {
|
483
|
+
let value = 0;
|
484
|
+
const { position } = as;
|
485
|
+
switch (command) {
|
486
|
+
case 'up':
|
487
|
+
value = round(position.y - num, 2);
|
488
|
+
break;
|
489
|
+
case 'down':
|
490
|
+
value = round(position.y + num, 2);
|
491
|
+
break;
|
492
|
+
case 'left':
|
493
|
+
value = round(position.x - num, 2);
|
494
|
+
break;
|
495
|
+
case 'right':
|
496
|
+
value = round(position.x + num, 2);
|
497
|
+
break;
|
498
|
+
default:
|
499
|
+
break;
|
500
|
+
}
|
501
|
+
|
502
|
+
return value;
|
503
|
+
};
|
504
|
+
|
505
|
+
return activeSchemas.map((as) => {
|
506
|
+
let value = getValue(as);
|
507
|
+
const { width, height } = as;
|
508
|
+
if (key === 'x') {
|
509
|
+
value = value > pageSize.width - width ? round(pageSize.width - width, 2) : value;
|
510
|
+
} else {
|
511
|
+
value = value > pageSize.height - height ? round(pageSize.height - height, 2) : value;
|
512
|
+
}
|
513
|
+
|
514
|
+
return { key: `position.${key}`, value, schemaId: as.id };
|
515
|
+
});
|
516
|
+
};
|
package/src/hooks.ts
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
import { RefObject, useRef, useState, useCallback, useEffect } from 'react';
|
2
|
+
import { Template, Size, getB64BasePdf } from '@pdfme/common';
|
3
|
+
import { pdf2Pngs, getPdfPageSizes, b64toBlob } from './helper';
|
4
|
+
import { ZOOM, RULER_HEIGHT } from './constants';
|
5
|
+
|
6
|
+
export const usePrevious = <T>(value: T) => {
|
7
|
+
const ref = useRef<T | null>(null);
|
8
|
+
useEffect(() => {
|
9
|
+
ref.current = value;
|
10
|
+
});
|
11
|
+
|
12
|
+
return ref.current;
|
13
|
+
};
|
14
|
+
|
15
|
+
const getScale = (n: number, paper: number) => (n / paper > 1 ? 1 : n / paper);
|
16
|
+
|
17
|
+
type UIPreProcessorProps = { template: Template; size: Size; offset?: number };
|
18
|
+
|
19
|
+
export const useUIPreProcessor = ({ template, size, offset = 0 }: UIPreProcessorProps) => {
|
20
|
+
const [backgrounds, setBackgrounds] = useState<string[]>([]);
|
21
|
+
const [pageSizes, setPageSizes] = useState<Size[]>([]);
|
22
|
+
const [scale, setScale] = useState(0);
|
23
|
+
const [error, setError] = useState<Error | null>(null);
|
24
|
+
|
25
|
+
const init = useCallback(async () => {
|
26
|
+
const _basePdf = await getB64BasePdf(template.basePdf);
|
27
|
+
const pdfBlob = b64toBlob(_basePdf);
|
28
|
+
const _pageSizes = await getPdfPageSizes(pdfBlob);
|
29
|
+
const paperWidth = _pageSizes[0].width * ZOOM;
|
30
|
+
const paperHeight = _pageSizes[0].height * ZOOM;
|
31
|
+
const _backgrounds = await pdf2Pngs(pdfBlob, paperWidth);
|
32
|
+
|
33
|
+
const _scale = Math.min(
|
34
|
+
getScale(size.width, paperWidth),
|
35
|
+
getScale(size.height - offset, paperHeight)
|
36
|
+
);
|
37
|
+
|
38
|
+
return { backgrounds: _backgrounds, pageSizes: _pageSizes, scale: _scale };
|
39
|
+
}, [template, size, offset]);
|
40
|
+
|
41
|
+
useEffect(() => {
|
42
|
+
init()
|
43
|
+
.then((data) => {
|
44
|
+
setPageSizes(data.pageSizes);
|
45
|
+
setScale(data.scale);
|
46
|
+
setBackgrounds(data.backgrounds);
|
47
|
+
})
|
48
|
+
.catch((e: Error) => {
|
49
|
+
console.error(e);
|
50
|
+
setError(e);
|
51
|
+
});
|
52
|
+
}, [init]);
|
53
|
+
|
54
|
+
return { backgrounds, pageSizes, scale, error };
|
55
|
+
};
|
56
|
+
|
57
|
+
type ScrollPageCursorProps = {
|
58
|
+
rootRef: RefObject<HTMLDivElement>;
|
59
|
+
pageSizes: Size[];
|
60
|
+
scale: number;
|
61
|
+
pageCursor: number;
|
62
|
+
onChangePageCursor: (page: number) => void;
|
63
|
+
};
|
64
|
+
|
65
|
+
export const useScrollPageCursor = ({
|
66
|
+
rootRef,
|
67
|
+
pageSizes,
|
68
|
+
scale,
|
69
|
+
pageCursor,
|
70
|
+
onChangePageCursor,
|
71
|
+
}: ScrollPageCursorProps) => {
|
72
|
+
const onScroll = useCallback(() => {
|
73
|
+
if (!pageSizes[0] || !rootRef.current) {
|
74
|
+
return;
|
75
|
+
}
|
76
|
+
|
77
|
+
const scroll = rootRef.current.scrollTop;
|
78
|
+
const { top } = rootRef.current.getBoundingClientRect();
|
79
|
+
const pageHeights = pageSizes.reduce((acc, cur, i) => {
|
80
|
+
let value = (cur.height * ZOOM + RULER_HEIGHT) * scale;
|
81
|
+
if (i === 0) {
|
82
|
+
value += top - value / 2;
|
83
|
+
} else {
|
84
|
+
value += acc[i - 1];
|
85
|
+
}
|
86
|
+
|
87
|
+
return acc.concat(value);
|
88
|
+
}, [] as number[]);
|
89
|
+
let _pageCursor = 0;
|
90
|
+
pageHeights.forEach((ph, i) => {
|
91
|
+
if (scroll > ph) {
|
92
|
+
_pageCursor = i + 1 >= pageHeights.length ? pageHeights.length - 1 : i + 1;
|
93
|
+
}
|
94
|
+
});
|
95
|
+
if (_pageCursor !== pageCursor) {
|
96
|
+
onChangePageCursor(_pageCursor);
|
97
|
+
}
|
98
|
+
}, [onChangePageCursor, pageCursor, pageSizes, rootRef, scale]);
|
99
|
+
|
100
|
+
useEffect(() => {
|
101
|
+
rootRef.current?.addEventListener('scroll', onScroll);
|
102
|
+
|
103
|
+
return () => {
|
104
|
+
rootRef.current?.removeEventListener('scroll', onScroll);
|
105
|
+
};
|
106
|
+
}, [rootRef, onScroll]);
|
107
|
+
};
|
package/src/i18n.ts
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
import { Lang } from '@pdfme/common';
|
2
|
+
import { DEFAULT_LANG } from './constants';
|
3
|
+
|
4
|
+
type DictEn = typeof dictEn;
|
5
|
+
|
6
|
+
const dictEn = {
|
7
|
+
field: 'field',
|
8
|
+
fieldName: 'Name',
|
9
|
+
require: 'Required',
|
10
|
+
uniq: 'Unique',
|
11
|
+
inputExample: 'Input Example',
|
12
|
+
edit: 'Edit',
|
13
|
+
plsSelect: 'Please select',
|
14
|
+
plsInputName: 'Please input name',
|
15
|
+
plsAddNewField: 'Please add new field',
|
16
|
+
fieldMustUniq: 'Name of field is not unique',
|
17
|
+
notUniq: '(Not unique name)',
|
18
|
+
noKeyName: 'No name',
|
19
|
+
fieldsList: 'List of Fields',
|
20
|
+
addNewField: 'Add new field',
|
21
|
+
editField: 'Edit Field',
|
22
|
+
type: 'Type',
|
23
|
+
previewWarnMsg: 'Preview is not available on iOS devices.',
|
24
|
+
previewErrMsg:
|
25
|
+
'An error occurred during the PDF creation process. (Characters that are not in the Helvetica font are not available)',
|
26
|
+
goToFirst: 'Go to first',
|
27
|
+
goToPrevious: 'Back',
|
28
|
+
goToNext: 'Next',
|
29
|
+
goToEnd: 'Go to end',
|
30
|
+
select: 'Select',
|
31
|
+
errorOccurred: 'An error occurred.',
|
32
|
+
};
|
33
|
+
|
34
|
+
const dictJa: { [key in keyof DictEn]: string } = {
|
35
|
+
field: '入力項目',
|
36
|
+
fieldName: '項目名',
|
37
|
+
require: '必須',
|
38
|
+
uniq: '他の項目名と同一不可',
|
39
|
+
inputExample: '記入例',
|
40
|
+
edit: '編集する',
|
41
|
+
plsSelect: '選択してください',
|
42
|
+
plsInputName: '項目名を入力してください',
|
43
|
+
plsAddNewField: '入力項目を追加してください',
|
44
|
+
fieldMustUniq: '他の入力項目名と被っています',
|
45
|
+
notUniq: '(他の項目名と重複しています)',
|
46
|
+
noKeyName: '項目名なし',
|
47
|
+
fieldsList: '入力項目一覧',
|
48
|
+
addNewField: '入力項目を追加',
|
49
|
+
editField: '入力項目を編集',
|
50
|
+
type: 'タイプ',
|
51
|
+
previewWarnMsg: 'iOS端末ではプレビューができません。',
|
52
|
+
previewErrMsg:
|
53
|
+
'PDF作成処理でエラーが発生しました。お手数ですがコンタクトからお問い合わせください。',
|
54
|
+
goToFirst: '最初に戻る',
|
55
|
+
goToPrevious: '1つ戻る',
|
56
|
+
goToNext: '1つ進む',
|
57
|
+
goToEnd: '最後に進む',
|
58
|
+
select: '選択',
|
59
|
+
errorOccurred: 'エラーが発生しました',
|
60
|
+
};
|
61
|
+
|
62
|
+
const i18n = (lang: Lang, key: keyof DictEn) => (lang === DEFAULT_LANG ? dictEn[key] : dictJa[key]);
|
63
|
+
|
64
|
+
export const curriedI18n = (lang: Lang) => (key: keyof DictEn) => i18n(lang, key);
|