@pdfme/ui 5.3.11-dev.7 → 5.3.11-dev.8

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 (34) hide show
  1. package/dist/index.es.js +5670 -5589
  2. package/dist/index.umd.js +121 -121
  3. package/dist/types/src/components/Designer/Canvas/Guides.d.ts +3 -9
  4. package/dist/types/src/components/Designer/Canvas/Moveable.d.ts +2 -49
  5. package/dist/types/src/components/Designer/Canvas/Selecto.d.ts +5 -16
  6. package/dist/types/src/components/Designer/PluginIcon.d.ts +2 -2
  7. package/dist/types/src/components/Designer/RightSidebar/ListView/Item.d.ts +17 -0
  8. package/dist/types/src/constants.d.ts +1 -1
  9. package/dist/types/src/contexts.d.ts +1 -1
  10. package/dist/types/src/helper.d.ts +3 -3
  11. package/package.json +1 -1
  12. package/src/components/AppContextProvider.tsx +17 -10
  13. package/src/components/CtlBar.tsx +2 -2
  14. package/src/components/Designer/Canvas/Guides.tsx +4 -13
  15. package/src/components/Designer/Canvas/Moveable.tsx +15 -74
  16. package/src/components/Designer/Canvas/Selecto.tsx +9 -24
  17. package/src/components/Designer/Canvas/index.tsx +3 -56
  18. package/src/components/Designer/LeftSidebar.tsx +2 -2
  19. package/src/components/Designer/PluginIcon.tsx +14 -3
  20. package/src/components/Designer/RightSidebar/DetailView/AlignWidget.tsx +91 -16
  21. package/src/components/Designer/RightSidebar/DetailView/ButtonGroupWidget.tsx +12 -8
  22. package/src/components/Designer/RightSidebar/DetailView/index.tsx +64 -21
  23. package/src/components/Designer/RightSidebar/ListView/Item.tsx +30 -2
  24. package/src/components/Designer/RightSidebar/ListView/SelectableSortableContainer.tsx +23 -4
  25. package/src/components/Designer/RightSidebar/ListView/SelectableSortableItem.tsx +20 -4
  26. package/src/components/Designer/index.tsx +14 -9
  27. package/src/components/Preview.tsx +4 -4
  28. package/src/components/Renderer.tsx +41 -35
  29. package/src/components/Root.tsx +1 -1
  30. package/src/constants.ts +1 -1
  31. package/src/contexts.ts +1 -1
  32. package/src/helper.ts +131 -38
  33. package/src/types/react-guides.d.ts +0 -22
  34. package/src/types/react-selecto.d.ts +0 -35
@@ -1,6 +1,5 @@
1
1
  import React, { useEffect, useContext, ReactNode, useRef, useMemo } from 'react';
2
2
  import {
3
- Dict,
4
3
  Mode,
5
4
  ZOOM,
6
5
  UIRenderProps,
@@ -29,7 +28,7 @@ type RendererProps = Omit<
29
28
  };
30
29
 
31
30
  type ReRenderCheckProps = {
32
- plugin: Plugin<any>;
31
+ plugin?: Plugin<Schema>;
33
32
  value: string;
34
33
  mode: Mode;
35
34
  scale: number;
@@ -48,12 +47,12 @@ const useRerenderDependencies = (arg: ReRenderCheckProps) => {
48
47
  const optionStr = JSON.stringify(_options);
49
48
 
50
49
  return useMemo(() => {
51
- if (plugin.uninterruptedEditMode && mode === 'designer') {
50
+ if (plugin?.uninterruptedEditMode && mode === 'designer') {
52
51
  return [mode];
53
52
  } else {
54
53
  return [value, mode, scale, JSON.stringify(schema), optionStr];
55
54
  }
56
- }, [plugin.uninterruptedEditMode, value, mode, scale, schema, optionStr]);
55
+ }, [plugin?.uninterruptedEditMode, value, mode, scale, schema, optionStr, plugin]);
57
56
  };
58
57
 
59
58
  const Wrapper = ({
@@ -105,56 +104,63 @@ const Renderer = (props: RendererProps) => {
105
104
 
106
105
  const pluginsRegistry = useContext(PluginsRegistry);
107
106
  const options = useContext(OptionsContext);
108
- const i18n = useContext(I18nContext) as (key: keyof Dict | string) => string;
107
+ const i18n = useContext(I18nContext) as (key: string) => string;
109
108
  const { token: theme } = antdTheme.useToken();
110
109
 
111
110
  const ref = useRef<HTMLDivElement>(null);
112
111
  const _cache = useContext(CacheContext);
113
- const plugin = Object.values(pluginsRegistry || {}).find(
114
- (plugin) => plugin?.propPanel.defaultSchema.type === schema.type,
115
- ) as Plugin<any> | undefined;
112
+ // Safely extract schema type
113
+ const schemaType = typeof schema.type === 'string' ? schema.type : '';
114
+
115
+ // Find plugin with matching schema type using a type-safe approach
116
+ const plugin = Object.values(pluginsRegistry || {}).find((plugin) => {
117
+ const defaultSchema = plugin?.propPanel?.defaultSchema as Record<string, unknown> | undefined;
118
+ return defaultSchema?.type === schemaType;
119
+ });
116
120
 
117
- if (!plugin || !plugin.ui) {
118
- console.error(`[@pdfme/ui] Renderer for type ${schema.type} not found.
119
- Check this document: https://pdfme.com/docs/custom-schemas`);
120
- return <></>;
121
- }
122
121
  const reRenderDependencies = useRerenderDependencies({
123
- plugin,
122
+ plugin: plugin || ({} as Plugin<Schema>),
124
123
  value,
125
124
  mode,
126
125
  scale,
127
126
  schema,
128
- options: options as UIOptions,
127
+ options,
129
128
  });
130
129
 
131
130
  useEffect(() => {
132
- if (ref.current && schema.type) {
133
- ref.current.innerHTML = '';
134
- const render = plugin.ui;
131
+ if (!plugin?.ui || !ref.current || !schema.type) return;
132
+
133
+ ref.current.innerHTML = '';
134
+ const render = plugin.ui;
135
+
136
+ void render({
137
+ value,
138
+ schema,
139
+ basePdf,
140
+ rootElement: ref.current,
141
+ mode,
142
+ onChange,
143
+ stopEditing,
144
+ tabIndex,
145
+ placeholder,
146
+ options,
147
+ theme,
148
+ i18n,
149
+ _cache,
150
+ });
135
151
 
136
- void render({
137
- value,
138
- schema,
139
- basePdf,
140
- rootElement: ref.current,
141
- mode,
142
- onChange,
143
- stopEditing,
144
- tabIndex,
145
- placeholder,
146
- options: options as UIOptions,
147
- theme,
148
- i18n,
149
- _cache: _cache as Map<any, any>,
150
- });
151
- }
152
152
  return () => {
153
153
  if (ref.current) {
154
154
  ref.current.innerHTML = '';
155
155
  }
156
156
  };
157
- }, reRenderDependencies);
157
+ }, [plugin?.ui, schema.type, reRenderDependencies]);
158
+
159
+ if (!plugin || !plugin.ui) {
160
+ console.error(`[@pdfme/ui] Renderer for type ${schema.type} not found.
161
+ Check this document: https://pdfme.com/docs/custom-schemas`);
162
+ return <></>;
163
+ }
158
164
 
159
165
  return (
160
166
  <Wrapper {...props}>
@@ -19,7 +19,7 @@ const Root = ({ size, scale, children }: Props, ref: Ref<HTMLDivElement>) => {
19
19
  );
20
20
  const newFontFaces = fontFaces.filter((fontFace) => !document.fonts.has(fontFace));
21
21
 
22
- Promise.allSettled(newFontFaces.map((f) => f.load())).then((loadedFontFaces) => {
22
+ void Promise.allSettled(newFontFaces.map((f) => f.load())).then((loadedFontFaces) => {
23
23
  loadedFontFaces.forEach((loadedFontFace) => {
24
24
  if (loadedFontFace.status === 'fulfilled') {
25
25
  document.fonts.add(loadedFontFace.value);
package/src/constants.ts CHANGED
@@ -1,4 +1,4 @@
1
- export const DEFAULT_LANG = 'en' as const;
1
+ export const DEFAULT_LANG = 'en';
2
2
 
3
3
  export const DESTROYED_ERR_MSG = '[@pdfme/ui] this instance is already destroyed';
4
4
 
package/src/contexts.ts CHANGED
@@ -11,4 +11,4 @@ export const PluginsRegistry = createContext<Plugins>(builtInPlugins);
11
11
 
12
12
  export const OptionsContext = createContext<UIOptions>({});
13
13
 
14
- export const CacheContext = createContext<Map<any, any>>(new Map());
14
+ export const CacheContext = createContext<Map<unknown, unknown>>(new Map());
package/src/helper.ts CHANGED
@@ -16,20 +16,28 @@ import { pdf2size } from '@pdfme/converter';
16
16
  import { DEFAULT_MAX_ZOOM, RULER_HEIGHT } from './constants.js';
17
17
  import { OptionsContext } from './contexts.js';
18
18
 
19
+ // Define a type for the hotkeys function with additional properties
20
+ type HotkeysFunction = {
21
+ (keys: string, callback: (e: KeyboardEvent, handler: { shortcut: string }) => void): unknown;
22
+ shift: boolean;
23
+ unbind: (keys: string) => void;
24
+ };
25
+
19
26
  // Create a simple mock for hotkeys to avoid TypeScript errors
20
27
  const hotkeys = function (
21
28
  keys: string,
22
29
  callback: (e: KeyboardEvent, handler: { shortcut: string }) => void,
23
30
  ) {
24
- return (hotkeysJs as any)(keys, callback);
25
- };
31
+ return hotkeysJs(keys, callback);
32
+ } as HotkeysFunction;
26
33
 
27
34
  // Add properties to the hotkeys function
28
- (hotkeys as any).shift = false;
29
- (hotkeys as any).unbind = function (keys: string) {
35
+ hotkeys.shift = false;
36
+ hotkeys.unbind = function (keys: string) {
30
37
  // Do nothing if hotkeysJs doesn't have unbind
31
- if (typeof (hotkeysJs as any).unbind === 'function') {
32
- (hotkeysJs as any).unbind(keys);
38
+ const hotkeysFn = hotkeysJs as unknown as { unbind?: (keys: string) => void };
39
+ if (typeof hotkeysFn.unbind === 'function') {
40
+ hotkeysFn.unbind(keys);
33
41
  }
34
42
  };
35
43
 
@@ -40,29 +48,30 @@ export const uuid = () =>
40
48
  return v.toString(16);
41
49
  });
42
50
 
43
- const set = <T extends object>(obj: T, path: string | string[], value: any) => {
51
+
52
+ const set = <T extends object>(obj: T, path: string | string[], value: unknown) => {
44
53
  path = Array.isArray(path) ? path : path.replace('[', '.').replace(']', '').split('.');
45
- let src: any = obj;
54
+ let src: Record<string, unknown> = obj as Record<string, unknown>;
46
55
  path.forEach((key, index, array) => {
47
56
  if (index == path.length - 1) {
48
57
  src[key] = value;
49
58
  } else {
50
- if (!src.hasOwnProperty(key)) {
59
+ if (!Object.prototype.hasOwnProperty.call(src, key)) {
51
60
  const next = array[index + 1];
52
61
  src[key] = String(Number(next)) === next ? [] : {};
53
62
  }
54
- src = src[key];
63
+ src = src[key] as Record<string, unknown>;
55
64
  }
56
65
  });
57
66
  };
58
67
 
59
- export const debounce = <T extends Function>(cb: T, wait = 20) => {
68
+ export const debounce = <T extends (...args: unknown[]) => unknown>(cb: T, wait = 20) => {
60
69
  let h: null | ReturnType<typeof setTimeout> = null;
61
- const callable = (...args: any) => {
70
+ const callable = (...args: Parameters<T>) => {
62
71
  if (h) clearTimeout(h);
63
72
  h = setTimeout(() => cb(...args), wait);
64
73
  };
65
- return <T>(<any>callable);
74
+ return callable as T;
66
75
  };
67
76
 
68
77
  const shift = (number: number, precision: number, reverseShift: boolean) => {
@@ -147,22 +156,22 @@ export const initShortCuts = (arg: {
147
156
  case up:
148
157
  case shiftUp:
149
158
  e.preventDefault();
150
- arg.move('up', (hotkeys as any).shift);
159
+ arg.move('up', hotkeys.shift);
151
160
  break;
152
161
  case down:
153
162
  case shiftDown:
154
163
  e.preventDefault();
155
- arg.move('down', (hotkeys as any).shift);
164
+ arg.move('down', hotkeys.shift);
156
165
  break;
157
166
  case left:
158
167
  case shiftLeft:
159
168
  e.preventDefault();
160
- arg.move('left', (hotkeys as any).shift);
169
+ arg.move('left', hotkeys.shift);
161
170
  break;
162
171
  case right:
163
172
  case shiftRight:
164
173
  e.preventDefault();
165
- arg.move('right', (hotkeys as any).shift);
174
+ arg.move('right', hotkeys.shift);
166
175
  break;
167
176
  case rmWin:
168
177
  case rmMac:
@@ -204,7 +213,7 @@ export const initShortCuts = (arg: {
204
213
  };
205
214
 
206
215
  export const destroyShortCuts = () => {
207
- (hotkeys as any).unbind(keys.join());
216
+ hotkeys.unbind(keys.join());
208
217
  };
209
218
 
210
219
  /**
@@ -259,10 +268,10 @@ export const arrayBufferToBase64 = (arrayBuffer: ArrayBuffer): string => {
259
268
  };
260
269
 
261
270
  const convertSchemasForUI = (template: Template): SchemaForUI[][] => {
262
- template.schemas.forEach((page: any[]) => {
263
- page.forEach((schema: any) => {
264
- schema.id = uuid();
265
- schema.content = schema.content || '';
271
+ template.schemas.forEach((page) => {
272
+ page.forEach((schema) => {
273
+ (schema as SchemaForUI).id = uuid();
274
+ (schema as SchemaForUI).content = schema.content || '';
266
275
  });
267
276
  });
268
277
 
@@ -282,8 +291,8 @@ export const template2SchemasList = async (_template: Template) => {
282
291
  }));
283
292
  } else {
284
293
  const b64BasePdf = await getB64BasePdf(basePdf);
285
- // @ts-expect-error
286
- const pdfArrayBuffer = b64toUint8Array(b64BasePdf) as ArrayBuffer;
294
+ // pdf2size accepts both ArrayBuffer and Uint8Array
295
+ const pdfArrayBuffer = b64toUint8Array(b64BasePdf);
287
296
 
288
297
  pageSizes = await pdf2size(pdfArrayBuffer);
289
298
  }
@@ -317,7 +326,7 @@ export const template2SchemasList = async (_template: Template) => {
317
326
  export const schemasList2template = (schemasList: SchemaForUI[][], basePdf: BasePdf): Template => ({
318
327
  schemas: cloneDeep(schemasList).map((page) =>
319
328
  page.map((schema) => {
320
- // @ts-ignore
329
+ // @ts-expect-error Property 'id' is used only in UI
321
330
  delete schema.id;
322
331
  return schema;
323
332
  }),
@@ -420,14 +429,14 @@ export const getSidebarContentHeight = (sidebarHeight: number) =>
420
429
  const handlePositionSizeChange = (
421
430
  schema: SchemaForUI,
422
431
  key: string,
423
- value: any,
432
+ value: unknown,
424
433
  basePdf: BasePdf,
425
434
  pageSize: Size,
426
435
  ) => {
427
436
  const padding = isBlankPdf(basePdf) ? basePdf.padding : [0, 0, 0, 0];
428
437
  const [pt, pr, pb, pl] = padding;
429
438
  const { width: pw, height: ph } = pageSize;
430
- const calcBounds = (v: any, min: number, max: number) => Math.min(Math.max(Number(v), min), max);
439
+ const calcBounds = (v: unknown, min: number, max: number) => Math.min(Math.max(Number(v), min), max);
431
440
  if (key === 'position.x') {
432
441
  schema.position.x = calcBounds(value, pl, pw - schema.width - pr);
433
442
  } else if (key === 'position.y') {
@@ -442,7 +451,7 @@ const handlePositionSizeChange = (
442
451
  const handleTypeChange = (
443
452
  schema: SchemaForUI,
444
453
  key: string,
445
- value: any,
454
+ value: unknown,
446
455
  pluginsRegistry: Plugins,
447
456
  ) => {
448
457
  if (key !== 'type') return;
@@ -453,21 +462,105 @@ const handleTypeChange = (
453
462
  }
454
463
  });
455
464
  // Apply attributes from new defaultSchema
456
- const propPanel = Object.values(pluginsRegistry).find(
457
- (plugin) => plugin?.propPanel.defaultSchema.type === value,
458
- )?.propPanel;
459
- Object.keys(propPanel?.defaultSchema || {}).forEach((key) => {
460
- if (!schema.hasOwnProperty(key)) {
461
- (schema as any)[key] = propPanel?.defaultSchema[key];
465
+ // Find the plugin with matching type
466
+ const pluginValue = value as string;
467
+
468
+ // Define a type-safe approach to find the matching plugin
469
+ interface PluginSchema {
470
+ type: string;
471
+ [key: string]: unknown;
472
+ }
473
+
474
+ interface PluginType {
475
+ propPanel: {
476
+ defaultSchema: PluginSchema;
477
+ };
478
+ }
479
+
480
+ // Initialize plugin as undefined
481
+ let plugin: PluginType | undefined;
482
+
483
+ // Safely iterate through plugins to find one with matching type
484
+ const pluginEntries = Object.entries(pluginsRegistry);
485
+ for (let i = 0; i < pluginEntries.length; i++) {
486
+ const [, pluginObj] = pluginEntries[i];
487
+
488
+ // Skip invalid plugins
489
+ if (!pluginObj || typeof pluginObj !== 'object') continue;
490
+
491
+ // Check if propPanel exists and is an object
492
+ if (!('propPanel' in pluginObj) ||
493
+ !pluginObj.propPanel ||
494
+ typeof pluginObj.propPanel !== 'object') continue;
495
+
496
+ // Check if defaultSchema exists and is an object
497
+ const propPanel = pluginObj.propPanel as { defaultSchema?: unknown };
498
+ if (!('defaultSchema' in propPanel) ||
499
+ !propPanel.defaultSchema ||
500
+ typeof propPanel.defaultSchema !== 'object') continue;
501
+
502
+ // Safely check if type property exists and matches
503
+ const defaultSchema = propPanel.defaultSchema as Record<string, unknown>;
504
+ if (!('type' in defaultSchema) ||
505
+ typeof defaultSchema.type !== 'string') continue;
506
+
507
+ // Check if the type matches
508
+ const schemaType = defaultSchema.type;
509
+ if (schemaType === pluginValue) {
510
+ // Create a type-safe copy of the plugin
511
+ const safeSchema: PluginSchema = {
512
+ type: schemaType
513
+ };
514
+
515
+ // Copy other properties safely
516
+ Object.keys(defaultSchema).forEach(key => {
517
+ if (key !== 'type' && Object.prototype.hasOwnProperty.call(defaultSchema, key)) {
518
+ safeSchema[key] = defaultSchema[key];
519
+ }
520
+ });
521
+
522
+ // Found matching plugin with proper typing
523
+ plugin = {
524
+ propPanel: {
525
+ defaultSchema: safeSchema
526
+ }
527
+ };
528
+ break;
462
529
  }
463
- });
530
+ }
531
+
532
+ const propPanel = plugin?.propPanel;
533
+
534
+ // Apply default schema properties if available
535
+ if (propPanel?.defaultSchema) {
536
+ // Create a type-safe copy of the default schema
537
+ const defaultSchema = propPanel.defaultSchema;
538
+ const schemaRecord = schema as Record<string, unknown>;
539
+
540
+ // Use a type-safe approach to copy properties
541
+ for (const key of Object.keys(defaultSchema)) {
542
+ // Only add properties that don't already exist in the schema
543
+ if (!Object.prototype.hasOwnProperty.call(schema, key)) {
544
+ // Create a safe copy of the property
545
+ if (Object.prototype.hasOwnProperty.call(defaultSchema, key)) {
546
+ // Get the property value safely
547
+ const propertyValue = defaultSchema[key];
548
+
549
+ // Only assign if the value is defined
550
+ if (propertyValue !== undefined) {
551
+ schemaRecord[key] = propertyValue;
552
+ }
553
+ }
554
+ }
555
+ }
556
+ }
464
557
  if (schema.readOnly) {
465
558
  schema.required = false;
466
559
  }
467
560
  };
468
561
 
469
562
  export const changeSchemas = (args: {
470
- objs: { key: string; value: any; schemaId: string }[];
563
+ objs: { key: string; value: unknown; schemaId: string }[];
471
564
  schemas: SchemaForUI[];
472
565
  basePdf: BasePdf;
473
566
  pluginsRegistry: Plugins;
@@ -492,8 +585,8 @@ export const changeSchemas = (args: {
492
585
  commitSchemas(newSchemas);
493
586
  };
494
587
 
495
- export const getMaxZoom = () => {
588
+ export const useMaxZoom = () => {
496
589
  const options = useContext(OptionsContext);
497
590
 
498
- return options.maxZoom ? (options.maxZoom as number) / 100 : DEFAULT_MAX_ZOOM;
591
+ return options.maxZoom ? options.maxZoom / 100 : DEFAULT_MAX_ZOOM;
499
592
  };
@@ -1,22 +0,0 @@
1
- declare module '@scena/react-guides' {
2
- import { Component, ForwardRefExoticComponent, RefAttributes } from 'react';
3
-
4
- interface GuidesInterface {
5
- getGuides(): number[];
6
- scroll(pos: number): void;
7
- scrollGuides(pos: number): void;
8
- loadGuides(guides: number[]): void;
9
- resize(): void;
10
- }
11
-
12
- interface GuidesProps {
13
- zoom?: number;
14
- style?: React.CSSProperties;
15
- type?: 'horizontal' | 'vertical';
16
- }
17
-
18
- // Define the component as a ForwardRefExoticComponent to support refs
19
- const GuidesComponent: ForwardRefExoticComponent<GuidesProps & RefAttributes<GuidesInterface>>;
20
-
21
- export default GuidesComponent;
22
- }
@@ -1,35 +0,0 @@
1
- declare module 'react-selecto' {
2
- import { ForwardRefExoticComponent, RefAttributes } from 'react';
3
-
4
- interface OnDragStart {
5
- inputEvent: MouseEvent;
6
- stop: () => void;
7
- isTrusted: boolean;
8
- }
9
-
10
- interface OnSelect {
11
- selected: Element[];
12
- added: Element[];
13
- removed: Element[];
14
- inputEvent: MouseEvent;
15
- rect: DOMRect;
16
- }
17
-
18
- interface SelectoProps {
19
- className?: string;
20
- selectFromInside?: boolean;
21
- selectByClick?: boolean;
22
- preventDefault?: boolean;
23
- hitRate?: number;
24
- selectableTargets?: string[];
25
- container?: HTMLElement | null;
26
- continueSelect?: boolean;
27
- onDragStart?: (e: OnDragStart) => void;
28
- onSelect?: (e: OnSelect) => void;
29
- }
30
-
31
- // Define the component as a ForwardRefExoticComponent
32
- const SelectoComponent: ForwardRefExoticComponent<SelectoProps & RefAttributes<any>>;
33
-
34
- export default SelectoComponent;
35
- }