@pdfme/ui 0.0.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.
Files changed (97) hide show
  1. package/README.md +9 -0
  2. package/__mocks__/assetsTransformer.js +7 -0
  3. package/__mocks__/form-render.js +7 -0
  4. package/__mocks__/lucide-react.js +19 -0
  5. package/dist/index.es.js +159393 -0
  6. package/dist/index.umd.js +1041 -0
  7. package/dist/types/__tests__/assets/helper.d.ts +3 -0
  8. package/dist/types/__tests__/components/Designer.test.d.ts +1 -0
  9. package/dist/types/__tests__/components/PluginIcon.test.d.ts +1 -0
  10. package/dist/types/__tests__/components/Preview.test.d.ts +1 -0
  11. package/dist/types/__tests__/helper.test.d.ts +1 -0
  12. package/dist/types/src/Designer.d.ts +21 -0
  13. package/dist/types/src/Form.d.ts +24 -0
  14. package/dist/types/src/Viewer.d.ts +15 -0
  15. package/dist/types/src/class.d.ts +89 -0
  16. package/dist/types/src/components/AppContextProvider.d.ts +11 -0
  17. package/dist/types/src/components/CtlBar.d.ts +14 -0
  18. package/dist/types/src/components/Designer/Canvas/Guides.d.ts +9 -0
  19. package/dist/types/src/components/Designer/Canvas/Mask.d.ts +4 -0
  20. package/dist/types/src/components/Designer/Canvas/Moveable.d.ts +37 -0
  21. package/dist/types/src/components/Designer/Canvas/Padding.d.ts +6 -0
  22. package/dist/types/src/components/Designer/Canvas/Selecto.d.ts +10 -0
  23. package/dist/types/src/components/Designer/Canvas/index.d.ts +22 -0
  24. package/dist/types/src/components/Designer/LeftSidebar.d.ts +8 -0
  25. package/dist/types/src/components/Designer/PluginIcon.d.ts +10 -0
  26. package/dist/types/src/components/Designer/RightSidebar/DetailView/AlignWidget.d.ts +4 -0
  27. package/dist/types/src/components/Designer/RightSidebar/DetailView/ButtonGroupWidget.d.ts +4 -0
  28. package/dist/types/src/components/Designer/RightSidebar/DetailView/WidgetRenderer.d.ts +7 -0
  29. package/dist/types/src/components/Designer/RightSidebar/DetailView/index.d.ts +8 -0
  30. package/dist/types/src/components/Designer/RightSidebar/ListView/Item.d.ts +45 -0
  31. package/dist/types/src/components/Designer/RightSidebar/ListView/SelectableSortableContainer.d.ts +4 -0
  32. package/dist/types/src/components/Designer/RightSidebar/ListView/SelectableSortableItem.d.ts +14 -0
  33. package/dist/types/src/components/Designer/RightSidebar/ListView/index.d.ts +4 -0
  34. package/dist/types/src/components/Designer/RightSidebar/index.d.ts +4 -0
  35. package/dist/types/src/components/Designer/RightSidebar/layout.d.ts +15 -0
  36. package/dist/types/src/components/Designer/index.d.ts +11 -0
  37. package/dist/types/src/components/ErrorScreen.d.ts +7 -0
  38. package/dist/types/src/components/Paper.d.ts +20 -0
  39. package/dist/types/src/components/Preview.d.ts +15 -0
  40. package/dist/types/src/components/Renderer.d.ts +13 -0
  41. package/dist/types/src/components/Root.d.ts +9 -0
  42. package/dist/types/src/components/Spinner.d.ts +3 -0
  43. package/dist/types/src/components/StaticSchema.d.ts +10 -0
  44. package/dist/types/src/components/UnitPager.d.ts +10 -0
  45. package/dist/types/src/constants.d.ts +11 -0
  46. package/dist/types/src/contexts.d.ts +10 -0
  47. package/dist/types/src/helper.d.ts +73 -0
  48. package/dist/types/src/hooks.d.ts +46 -0
  49. package/dist/types/src/i18n.d.ts +3 -0
  50. package/dist/types/src/index.d.ts +4 -0
  51. package/dist/types/src/theme.d.ts +2 -0
  52. package/dist/types/src/types.d.ts +19 -0
  53. package/eslint.config.mjs +41 -0
  54. package/package.json +127 -0
  55. package/src/Designer.tsx +107 -0
  56. package/src/Form.tsx +102 -0
  57. package/src/Viewer.tsx +59 -0
  58. package/src/class.ts +188 -0
  59. package/src/components/AppContextProvider.tsx +78 -0
  60. package/src/components/CtlBar.tsx +183 -0
  61. package/src/components/Designer/Canvas/Guides.tsx +49 -0
  62. package/src/components/Designer/Canvas/Mask.tsx +20 -0
  63. package/src/components/Designer/Canvas/Moveable.tsx +91 -0
  64. package/src/components/Designer/Canvas/Padding.tsx +56 -0
  65. package/src/components/Designer/Canvas/Selecto.tsx +45 -0
  66. package/src/components/Designer/Canvas/index.tsx +536 -0
  67. package/src/components/Designer/LeftSidebar.tsx +120 -0
  68. package/src/components/Designer/PluginIcon.tsx +87 -0
  69. package/src/components/Designer/RightSidebar/DetailView/AlignWidget.tsx +229 -0
  70. package/src/components/Designer/RightSidebar/DetailView/ButtonGroupWidget.tsx +78 -0
  71. package/src/components/Designer/RightSidebar/DetailView/WidgetRenderer.tsx +28 -0
  72. package/src/components/Designer/RightSidebar/DetailView/index.tsx +469 -0
  73. package/src/components/Designer/RightSidebar/ListView/Item.tsx +158 -0
  74. package/src/components/Designer/RightSidebar/ListView/SelectableSortableContainer.tsx +204 -0
  75. package/src/components/Designer/RightSidebar/ListView/SelectableSortableItem.tsx +88 -0
  76. package/src/components/Designer/RightSidebar/ListView/index.tsx +116 -0
  77. package/src/components/Designer/RightSidebar/index.tsx +72 -0
  78. package/src/components/Designer/RightSidebar/layout.tsx +75 -0
  79. package/src/components/Designer/index.tsx +389 -0
  80. package/src/components/ErrorScreen.tsx +33 -0
  81. package/src/components/Paper.tsx +117 -0
  82. package/src/components/Preview.tsx +220 -0
  83. package/src/components/Renderer.tsx +165 -0
  84. package/src/components/Root.tsx +38 -0
  85. package/src/components/Spinner.tsx +45 -0
  86. package/src/components/StaticSchema.tsx +50 -0
  87. package/src/components/UnitPager.tsx +119 -0
  88. package/src/constants.ts +21 -0
  89. package/src/contexts.ts +14 -0
  90. package/src/helper.ts +534 -0
  91. package/src/hooks.ts +308 -0
  92. package/src/i18n.ts +903 -0
  93. package/src/index.ts +5 -0
  94. package/src/theme.ts +20 -0
  95. package/src/types.ts +20 -0
  96. package/tsconfig.json +48 -0
  97. package/vite.config.mts +22 -0
package/src/hooks.ts ADDED
@@ -0,0 +1,308 @@
1
+ import { RefObject, useRef, useState, useCallback, useEffect } from 'react';
2
+ import {
3
+ cloneDeep,
4
+ ZOOM,
5
+ Template,
6
+ Size,
7
+ getB64BasePdf,
8
+ b64toUint8Array,
9
+ SchemaForUI,
10
+ ChangeSchemas,
11
+ isBlankPdf,
12
+ } from '@pdfme/common';
13
+ import { pdf2img, pdf2size } from '@pdfme/converter';
14
+
15
+ import {
16
+ schemasList2template,
17
+ uuid,
18
+ getUniqueSchemaName,
19
+ moveCommandToChangeSchemasArg,
20
+ arrayBufferToBase64,
21
+ initShortCuts,
22
+ destroyShortCuts,
23
+ } from './helper.js';
24
+ import { RULER_HEIGHT } from './constants.js';
25
+
26
+ export const usePrevious = <T>(value: T) => {
27
+ const ref = useRef<T | null>(null);
28
+ useEffect(() => {
29
+ ref.current = value;
30
+ });
31
+
32
+ return ref.current;
33
+ };
34
+
35
+ const getScale = (n: number, paper: number) =>
36
+ Math.floor((n / paper > 1 ? 1 : n / paper) * 100) / 100;
37
+
38
+ type UIPreProcessorProps = { template: Template; size: Size; zoomLevel: number; maxZoom: number };
39
+
40
+ export const useUIPreProcessor = ({ template, size, zoomLevel, maxZoom }: UIPreProcessorProps) => {
41
+ const [backgrounds, setBackgrounds] = useState<string[]>([]);
42
+ const [pageSizes, setPageSizes] = useState<Size[]>([]);
43
+ const [scale, setScale] = useState(0);
44
+ const [error, setError] = useState<Error | null>(null);
45
+
46
+ const init = async (prop: { template: Template; size: Size }) => {
47
+ const {
48
+ template: { basePdf, schemas },
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=',
64
+ );
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
+
89
+ return {
90
+ backgrounds: _backgrounds,
91
+ pageSizes: _pageSizes,
92
+ scale: _scale,
93
+ };
94
+ };
95
+
96
+ useEffect(() => {
97
+ init({ template, size })
98
+ .then(({ pageSizes, scale, backgrounds }) => {
99
+ setPageSizes(pageSizes);
100
+ setScale(scale);
101
+ setBackgrounds(backgrounds);
102
+ })
103
+ .catch((err: Error) => {
104
+ setError(err);
105
+ console.error('[@pdfme/ui]', err);
106
+ });
107
+ }, [template, size]);
108
+
109
+ return {
110
+ backgrounds,
111
+ pageSizes,
112
+ scale: scale * zoomLevel,
113
+ error,
114
+ refresh: (template: Template) =>
115
+ init({ template, size }).then(({ pageSizes, scale, backgrounds }) => {
116
+ setPageSizes(pageSizes);
117
+ setScale(scale);
118
+ setBackgrounds(backgrounds);
119
+ }),
120
+ };
121
+ };
122
+
123
+ type ScrollPageCursorProps = {
124
+ ref: RefObject<HTMLDivElement>;
125
+ pageSizes: Size[];
126
+ scale: number;
127
+ pageCursor: number;
128
+ onChangePageCursor: (page: number) => void;
129
+ };
130
+
131
+ export const useScrollPageCursor = ({
132
+ ref,
133
+ pageSizes,
134
+ scale,
135
+ pageCursor,
136
+ onChangePageCursor,
137
+ }: ScrollPageCursorProps) => {
138
+ const onScroll = useCallback(() => {
139
+ if (!pageSizes[0] || !ref.current) {
140
+ return;
141
+ }
142
+
143
+ const scroll = ref.current.scrollTop;
144
+ const { top } = ref.current.getBoundingClientRect();
145
+ const pageHeights = pageSizes.reduce((acc, cur, i) => {
146
+ let value = (cur.height * ZOOM + RULER_HEIGHT) * scale;
147
+ if (i === 0) {
148
+ value += top - value / 2;
149
+ } else {
150
+ value += acc[i - 1];
151
+ }
152
+
153
+ return acc.concat(value);
154
+ }, [] as number[]);
155
+ let _pageCursor = 0;
156
+ pageHeights.forEach((ph, i) => {
157
+ if (scroll > ph) {
158
+ _pageCursor = i + 1 >= pageHeights.length ? pageHeights.length - 1 : i + 1;
159
+ }
160
+ });
161
+ if (_pageCursor !== pageCursor) {
162
+ onChangePageCursor(_pageCursor);
163
+ }
164
+ }, [onChangePageCursor, pageCursor, pageSizes, ref, scale]);
165
+
166
+ useEffect(() => {
167
+ ref.current?.addEventListener('scroll', onScroll);
168
+
169
+ return () => {
170
+ ref.current?.removeEventListener('scroll', onScroll);
171
+ };
172
+ }, [ref, onScroll]);
173
+ };
174
+
175
+ export const useMountStatus = () => {
176
+ const [isMounted, setIsMounted] = useState(false);
177
+
178
+ useEffect(() => {
179
+ const timeout = setTimeout(() => setIsMounted(true), 500);
180
+ return () => clearTimeout(timeout);
181
+ }, []);
182
+
183
+ return isMounted;
184
+ };
185
+
186
+ interface UseInitEventsParams {
187
+ pageCursor: number;
188
+ pageSizes: Size[];
189
+ activeElements: HTMLElement[];
190
+ template: Template;
191
+ schemasList: SchemaForUI[][];
192
+ changeSchemas: ChangeSchemas;
193
+ commitSchemas: (newSchemas: SchemaForUI[]) => void;
194
+ removeSchemas: (ids: string[]) => void;
195
+ onSaveTemplate: (t: Template) => void;
196
+ past: React.MutableRefObject<SchemaForUI[][]>;
197
+ future: React.MutableRefObject<SchemaForUI[][]>;
198
+ setSchemasList: React.Dispatch<React.SetStateAction<SchemaForUI[][]>>;
199
+ onEdit: (targets: HTMLElement[]) => void;
200
+ onEditEnd: () => void;
201
+ }
202
+
203
+ export const useInitEvents = ({
204
+ pageCursor,
205
+ pageSizes,
206
+ activeElements,
207
+ template,
208
+ schemasList,
209
+ changeSchemas,
210
+ commitSchemas,
211
+ removeSchemas,
212
+ onSaveTemplate,
213
+ past,
214
+ future,
215
+ setSchemasList,
216
+ onEdit,
217
+ onEditEnd,
218
+ }: UseInitEventsParams) => {
219
+ const copiedSchemas = useRef<SchemaForUI[] | null>(null);
220
+
221
+ const initEvents = useCallback(() => {
222
+ const getActiveSchemas = () => {
223
+ const ids = activeElements.map((ae) => ae.id);
224
+
225
+ return schemasList[pageCursor].filter((s) => ids.includes(s.id));
226
+ };
227
+ const timeTravel = (mode: 'undo' | 'redo') => {
228
+ const isUndo = mode === 'undo';
229
+ const stack = isUndo ? past : future;
230
+ if (stack.current.length <= 0) return;
231
+ (isUndo ? future : past).current.push(cloneDeep(schemasList[pageCursor]));
232
+ const s = cloneDeep(schemasList);
233
+ s[pageCursor] = stack.current.pop()!;
234
+ setSchemasList(s);
235
+ };
236
+ initShortCuts({
237
+ move: (command, isShift) => {
238
+ const pageSize = pageSizes[pageCursor];
239
+ const activeSchemas = getActiveSchemas();
240
+ const arg = moveCommandToChangeSchemasArg({ command, activeSchemas, pageSize, isShift });
241
+ changeSchemas(arg);
242
+ },
243
+
244
+ copy: () => {
245
+ const activeSchemas = getActiveSchemas();
246
+ if (activeSchemas.length === 0) return;
247
+ copiedSchemas.current = activeSchemas;
248
+ },
249
+ paste: () => {
250
+ if (!copiedSchemas.current || copiedSchemas.current.length === 0) return;
251
+ const schema = schemasList[pageCursor];
252
+ const stackUniqueSchemaNames: string[] = [];
253
+ const pasteSchemas = copiedSchemas.current.map((cs) => {
254
+ const id = uuid();
255
+ const name = getUniqueSchemaName({
256
+ copiedSchemaName: cs.name,
257
+ schema,
258
+ stackUniqueSchemaNames,
259
+ });
260
+ const { height, width, position: p } = cs;
261
+ const ps = pageSizes[pageCursor];
262
+ const position = {
263
+ x: p.x + 10 > ps.width - width ? ps.width - width : p.x + 10,
264
+ y: p.y + 10 > ps.height - height ? ps.height - height : p.y + 10,
265
+ };
266
+
267
+ return Object.assign(cloneDeep(cs), { id, name, position });
268
+ });
269
+ commitSchemas(schemasList[pageCursor].concat(pasteSchemas));
270
+ onEdit(pasteSchemas.map((s) => document.getElementById(s.id)!));
271
+ copiedSchemas.current = pasteSchemas;
272
+ },
273
+ redo: () => timeTravel('redo'),
274
+ undo: () => timeTravel('undo'),
275
+ save: () =>
276
+ onSaveTemplate && onSaveTemplate(schemasList2template(schemasList, template.basePdf)),
277
+ remove: () => removeSchemas(getActiveSchemas().map((s) => s.id)),
278
+ esc: onEditEnd,
279
+ selectAll: () => onEdit(schemasList[pageCursor].map((s) => document.getElementById(s.id)!)),
280
+ });
281
+ }, [
282
+ template,
283
+ activeElements,
284
+ pageCursor,
285
+ pageSizes,
286
+ changeSchemas,
287
+ commitSchemas,
288
+ schemasList,
289
+ onSaveTemplate,
290
+ removeSchemas,
291
+ past,
292
+ future,
293
+ setSchemasList,
294
+ copiedSchemas,
295
+ onEdit,
296
+ onEditEnd,
297
+ ]);
298
+
299
+ const destroyEvents = useCallback(() => {
300
+ destroyShortCuts();
301
+ }, []);
302
+
303
+ useEffect(() => {
304
+ initEvents();
305
+
306
+ return destroyEvents;
307
+ }, [initEvents, destroyEvents]);
308
+ };