@pdfme/ui 5.3.8-dev.57 → 5.3.8-dev.58

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 (32) hide show
  1. package/dist/index.es.js +127 -60
  2. package/dist/types/src/components/Designer/LeftSidebar.d.ts +1 -1
  3. package/dist/types/src/components/Designer/PluginIcon.d.ts +1 -1
  4. package/package.json +1 -1
  5. package/src/Designer.tsx +4 -4
  6. package/src/Form.tsx +1 -3
  7. package/src/Viewer.tsx +1 -1
  8. package/src/components/AppContextProvider.tsx +1 -1
  9. package/src/components/CtlBar.tsx +1 -1
  10. package/src/components/Designer/Canvas/Guides.tsx +1 -1
  11. package/src/components/Designer/Canvas/Moveable.tsx +2 -2
  12. package/src/components/Designer/Canvas/Padding.tsx +10 -8
  13. package/src/components/Designer/Canvas/index.tsx +27 -14
  14. package/src/components/Designer/LeftSidebar.tsx +57 -49
  15. package/src/components/Designer/PluginIcon.tsx +21 -8
  16. package/src/components/Designer/RightSidebar/DetailView/AlignWidget.tsx +44 -44
  17. package/src/components/Designer/RightSidebar/DetailView/ButtonGroupWidget.tsx +3 -3
  18. package/src/components/Designer/RightSidebar/DetailView/index.tsx +51 -23
  19. package/src/components/Designer/RightSidebar/ListView/Item.tsx +4 -4
  20. package/src/components/Designer/RightSidebar/ListView/SelectableSortableContainer.tsx +56 -47
  21. package/src/components/Designer/RightSidebar/ListView/SelectableSortableItem.tsx +2 -3
  22. package/src/components/Designer/RightSidebar/ListView/index.tsx +10 -3
  23. package/src/components/Designer/index.tsx +41 -19
  24. package/src/components/Preview.tsx +25 -14
  25. package/src/components/Renderer.tsx +35 -22
  26. package/src/components/Root.tsx +1 -1
  27. package/src/components/Spinner.tsx +1 -1
  28. package/src/components/StaticSchema.tsx +39 -21
  29. package/src/constants.ts +1 -1
  30. package/src/helper.ts +7 -7
  31. package/src/hooks.ts +3 -3
  32. package/src/types/react-guides.d.ts +1 -1
@@ -1,49 +1,57 @@
1
1
  import React, { useContext, useState, useEffect } from 'react';
2
- import {
3
- Schema,
4
- Plugin,
5
- BasePdf,
6
- } from '@pdfme/common';
2
+ import { Schema, Plugin, BasePdf } from '@pdfme/common';
7
3
  import { theme, Button } from 'antd';
8
4
  import { useDraggable } from '@dnd-kit/core';
9
- import { CSS } from "@dnd-kit/utilities";
5
+ import { CSS } from '@dnd-kit/utilities';
10
6
  import Renderer from '../Renderer.js';
11
7
  import { LEFT_SIDEBAR_WIDTH } from '../../constants.js';
12
8
  import { PluginsRegistry } from '../../contexts.js';
13
- import PluginIcon from "./PluginIcon.js";
9
+ import PluginIcon from './PluginIcon.js';
14
10
 
15
-
16
- const Draggable = (props: { plugin: Plugin<any>, scale: number, basePdf: BasePdf, children: React.ReactNode }) => {
11
+ const Draggable = (props: {
12
+ plugin: Plugin<any>;
13
+ scale: number;
14
+ basePdf: BasePdf;
15
+ children: React.ReactNode;
16
+ }) => {
17
17
  const { scale, basePdf, plugin } = props;
18
18
  const { token } = theme.useToken();
19
19
  const defaultSchema = plugin.propPanel.defaultSchema as Schema;
20
20
  const draggable = useDraggable({ id: defaultSchema.type, data: defaultSchema });
21
21
  const { listeners, setNodeRef, attributes, transform, isDragging } = draggable;
22
- const style = { transform: CSS.Translate.toString(transform) }
22
+ const style = { transform: CSS.Translate.toString(transform) };
23
23
 
24
24
  return (
25
25
  <div ref={setNodeRef} style={style} {...listeners} {...attributes}>
26
- {isDragging &&
26
+ {isDragging && (
27
27
  <div style={{ transform: `scale(${scale})` }}>
28
28
  <Renderer
29
29
  schema={{ ...defaultSchema, id: defaultSchema.type }}
30
30
  basePdf={basePdf}
31
31
  value={defaultSchema.content || ''}
32
- onChangeHoveringSchemaId={() => { void 0 }}
32
+ onChangeHoveringSchemaId={() => {
33
+ void 0;
34
+ }}
33
35
  mode={'viewer'}
34
36
  outline={`1px solid ${token.colorPrimary}`}
35
37
  scale={scale}
36
38
  />
37
39
  </div>
38
- }
39
- <div style={{ visibility: isDragging ? 'hidden' : 'visible' }}>
40
- {props.children}
41
- </div>
40
+ )}
41
+ <div style={{ visibility: isDragging ? 'hidden' : 'visible' }}>{props.children}</div>
42
42
  </div>
43
43
  );
44
- }
44
+ };
45
45
 
46
- const LeftSidebar = ({ height, scale, basePdf }: { height: number, scale: number, basePdf: BasePdf }) => {
46
+ const LeftSidebar = ({
47
+ height,
48
+ scale,
49
+ basePdf,
50
+ }: {
51
+ height: number;
52
+ scale: number;
53
+ basePdf: BasePdf;
54
+ }) => {
47
55
  const { token } = theme.useToken();
48
56
  const pluginsRegistry = useContext(PluginsRegistry);
49
57
  const [isDragging, setIsDragging] = useState(false);
@@ -62,36 +70,36 @@ const LeftSidebar = ({ height, scale, basePdf }: { height: number, scale: number
62
70
  };
63
71
  }, [isDragging]);
64
72
 
65
- return <div
66
- style={{
67
- left: 0,
68
- right: 0,
69
- position: 'absolute',
70
- zIndex: 1,
71
- height,
72
- width: LEFT_SIDEBAR_WIDTH,
73
- background: token.colorBgLayout,
74
- textAlign: 'center',
75
- overflow: isDragging ? 'visible' : 'auto',
76
- }}
77
- >
78
- {Object.entries(pluginsRegistry).map(([label, plugin]) => {
79
- if (!plugin?.propPanel.defaultSchema) return null;
73
+ return (
74
+ <div
75
+ style={{
76
+ left: 0,
77
+ right: 0,
78
+ position: 'absolute',
79
+ zIndex: 1,
80
+ height,
81
+ width: LEFT_SIDEBAR_WIDTH,
82
+ background: token.colorBgLayout,
83
+ textAlign: 'center',
84
+ overflow: isDragging ? 'visible' : 'auto',
85
+ }}
86
+ >
87
+ {Object.entries(pluginsRegistry).map(([label, plugin]) => {
88
+ if (!plugin?.propPanel.defaultSchema) return null;
80
89
 
81
- return <Draggable
82
- key={label}
83
- scale={scale}
84
- basePdf={basePdf}
85
- plugin={plugin}>
86
- <Button
87
- onMouseDown={() => setIsDragging(true)}
88
- style={{ width: 35, height: 35, marginTop: '0.25rem', padding: '0.25rem' }}
89
- >
90
- <PluginIcon plugin={plugin} label={label} />
91
- </Button>
92
- </Draggable>
93
- })}
94
- </div>
95
- }
90
+ return (
91
+ <Draggable key={label} scale={scale} basePdf={basePdf} plugin={plugin}>
92
+ <Button
93
+ onMouseDown={() => setIsDragging(true)}
94
+ style={{ width: 35, height: 35, marginTop: '0.25rem', padding: '0.25rem' }}
95
+ >
96
+ <PluginIcon plugin={plugin} label={label} />
97
+ </Button>
98
+ </Draggable>
99
+ );
100
+ })}
101
+ </div>
102
+ );
103
+ };
96
104
 
97
- export default LeftSidebar
105
+ export default LeftSidebar;
@@ -1,9 +1,8 @@
1
1
  import React, { useContext } from 'react';
2
- import { Plugin } from "@pdfme/common";
2
+ import { Plugin } from '@pdfme/common';
3
3
  import { OptionsContext } from '../../contexts.js';
4
4
  import { theme } from 'antd';
5
5
 
6
-
7
6
  interface PluginIconProps {
8
7
  plugin: Plugin<any>;
9
8
  label: string;
@@ -11,7 +10,12 @@ interface PluginIconProps {
11
10
  styles?: React.CSSProperties;
12
11
  }
13
12
 
14
- const getWithModifiedSize = (htmlString: string, label: string, size: number, styles?: React.CSSProperties) => {
13
+ const getWithModifiedSize = (
14
+ htmlString: string,
15
+ label: string,
16
+ size: number,
17
+ styles?: React.CSSProperties,
18
+ ) => {
15
19
  const parser = new DOMParser();
16
20
  const doc = parser.parseFromString(htmlString, 'text/html');
17
21
 
@@ -20,10 +24,10 @@ const getWithModifiedSize = (htmlString: string, label: string, size: number, st
20
24
  node.setAttribute('width', size.toString());
21
25
  node.setAttribute('height', size.toString());
22
26
  }
23
- Array.from(node.children).forEach(child => modifyNode(child as HTMLElement));
27
+ Array.from(node.children).forEach((child) => modifyNode(child as HTMLElement));
24
28
  };
25
29
 
26
- Array.from(doc.body.children).forEach(child => modifyNode(child as HTMLElement));
30
+ Array.from(doc.body.children).forEach((child) => modifyNode(child as HTMLElement));
27
31
 
28
32
  return (
29
33
  <div style={styles} title={label} dangerouslySetInnerHTML={{ __html: doc.body.innerHTML }} />
@@ -35,16 +39,25 @@ const PluginIcon = (props: PluginIconProps) => {
35
39
  const { token } = theme.useToken();
36
40
  const options = useContext(OptionsContext);
37
41
  const icon = options.icons?.[plugin.propPanel.defaultSchema.type] ?? plugin.icon;
38
- const iconStyles = { ...styles, color: token.colorText, display: 'flex', justifyContent: 'center' };
42
+ const iconStyles = {
43
+ ...styles,
44
+ color: token.colorText,
45
+ display: 'flex',
46
+ justifyContent: 'center',
47
+ };
39
48
 
40
49
  if (icon) {
41
50
  if (size) {
42
51
  return getWithModifiedSize(icon, label, size, iconStyles);
43
52
  }
44
- return <div style={iconStyles} title={label} dangerouslySetInnerHTML={{ __html: icon }} />
53
+ return <div style={iconStyles} title={label} dangerouslySetInnerHTML={{ __html: icon }} />;
45
54
  }
46
55
 
47
- return <div style={{ ...styles, overflow: 'hidden', fontSize: 10, }} title={label} >{label}</div>
56
+ return (
57
+ <div style={{ ...styles, overflow: 'hidden', fontSize: 10 }} title={label}>
58
+ {label}
59
+ </div>
60
+ );
48
61
  };
49
62
 
50
63
  export default PluginIcon;
@@ -10,7 +10,7 @@ import {
10
10
  AlignEndHorizontal,
11
11
  AlignVerticalSpaceAround,
12
12
  AlignHorizontalSpaceAround,
13
- } from 'lucide-react'
13
+ } from 'lucide-react';
14
14
  import { round } from '../../../../helper.js';
15
15
 
16
16
  const AlignWidget = (props: PropPanelWidgetProps) => {
@@ -44,7 +44,7 @@ const AlignWidget = (props: PropPanelWidgetProps) => {
44
44
  key: `position.${tgtPos}`,
45
45
  value: round(basePos - adjust(as[tgtSize]), 2),
46
46
  schemaId: as.id,
47
- }))
47
+ })),
48
48
  );
49
49
  };
50
50
 
@@ -72,7 +72,7 @@ const AlignWidget = (props: PropPanelWidgetProps) => {
72
72
  prev += index === 0 ? 0 : ass[index - 1][tgtSize] + unit;
73
73
  const value = round(boxPos + prev, 2);
74
74
  return { key: `position.${tgtPos}`, value, schemaId: as.id };
75
- })
75
+ }),
76
76
  );
77
77
  };
78
78
  const layoutBtns: {
@@ -80,47 +80,47 @@ const AlignWidget = (props: PropPanelWidgetProps) => {
80
80
  icon: React.JSX.Element;
81
81
  onClick: () => void;
82
82
  }[] = [
83
- {
84
- id: 'left',
85
- icon: <AlignStartVertical size={15} />,
86
- onClick: () => align('left')
87
- },
88
- {
89
- id: 'center',
90
- icon: <AlignCenterVertical size={15} />,
91
- onClick: () => align('center')
92
- },
93
- {
94
- id: 'right',
95
- icon: <AlignEndVertical size={15} />,
96
- onClick: () => align('right')
97
- },
98
- {
99
- id: 'top',
100
- icon: <AlignStartHorizontal size={15} />,
101
- onClick: () => align('top')
102
- },
103
- {
104
- id: 'middle',
105
- icon: <AlignCenterHorizontal size={15} />,
106
- onClick: () => align('middle')
107
- },
108
- {
109
- id: 'bottom',
110
- icon: <AlignEndHorizontal size={15} />,
111
- onClick: () => align('bottom')
112
- },
113
- {
114
- id: 'vertical',
115
- icon: <AlignVerticalSpaceAround size={15} />,
116
- onClick: () => distribute('vertical')
117
- },
118
- {
119
- id: 'horizontal',
120
- icon: <AlignHorizontalSpaceAround size={15} />,
121
- onClick: () => distribute('horizontal')
122
- },
123
- ];
83
+ {
84
+ id: 'left',
85
+ icon: <AlignStartVertical size={15} />,
86
+ onClick: () => align('left'),
87
+ },
88
+ {
89
+ id: 'center',
90
+ icon: <AlignCenterVertical size={15} />,
91
+ onClick: () => align('center'),
92
+ },
93
+ {
94
+ id: 'right',
95
+ icon: <AlignEndVertical size={15} />,
96
+ onClick: () => align('right'),
97
+ },
98
+ {
99
+ id: 'top',
100
+ icon: <AlignStartHorizontal size={15} />,
101
+ onClick: () => align('top'),
102
+ },
103
+ {
104
+ id: 'middle',
105
+ icon: <AlignCenterHorizontal size={15} />,
106
+ onClick: () => align('middle'),
107
+ },
108
+ {
109
+ id: 'bottom',
110
+ icon: <AlignEndHorizontal size={15} />,
111
+ onClick: () => align('bottom'),
112
+ },
113
+ {
114
+ id: 'vertical',
115
+ icon: <AlignVerticalSpaceAround size={15} />,
116
+ onClick: () => distribute('vertical'),
117
+ },
118
+ {
119
+ id: 'horizontal',
120
+ icon: <AlignHorizontalSpaceAround size={15} />,
121
+ onClick: () => distribute('horizontal'),
122
+ },
123
+ ];
124
124
 
125
125
  return (
126
126
  <Form.Item label={schema.title}>
@@ -22,7 +22,7 @@ const ButtonGroupWidget = (props: PropPanelWidgetProps) => {
22
22
  const oldValue = s[key] ?? false;
23
23
  const newValue = type === 'boolean' ? !oldValue : btn.value;
24
24
  return { key, value: newValue, schemaId: s.id };
25
- })
25
+ }),
26
26
  );
27
27
  };
28
28
 
@@ -33,7 +33,7 @@ const ButtonGroupWidget = (props: PropPanelWidgetProps) => {
33
33
  const ids = activeElements.map((ae) => ae.id);
34
34
  const ass = schemas.filter((s) => ids.includes(s.id)) as SchemaForUI[];
35
35
  ass.forEach((s: Record<string, any>) => {
36
- active = type === 'boolean' ? s[key] ?? false : s[key] === btn.value;
36
+ active = type === 'boolean' ? (s[key] ?? false) : s[key] === btn.value;
37
37
  });
38
38
  return active;
39
39
  };
@@ -43,7 +43,7 @@ const ButtonGroupWidget = (props: PropPanelWidgetProps) => {
43
43
 
44
44
  const svgIcon = (svgString: string) => {
45
45
  const svgDataUrl = `data:image/svg+xml;utf8,${encodeURIComponent(
46
- replaceCurrentColor(svgString, token.colorText)
46
+ replaceCurrentColor(svgString, token.colorText),
47
47
  )}`;
48
48
  return <img width={17} height={17} src={svgDataUrl} />;
49
49
  };
@@ -1,6 +1,12 @@
1
1
  import { useForm } from 'form-render';
2
2
  import React, { useRef, useContext, useState, useEffect } from 'react';
3
- import type { ChangeSchemaItem, Dict, SchemaForUI, PropPanelWidgetProps, PropPanelSchema } from '@pdfme/common';
3
+ import type {
4
+ ChangeSchemaItem,
5
+ Dict,
6
+ SchemaForUI,
7
+ PropPanelWidgetProps,
8
+ PropPanelSchema,
9
+ } from '@pdfme/common';
4
10
  import type { SidebarProps } from '../../../../types.js';
5
11
  import { Menu } from 'lucide-react';
6
12
  import { I18nContext, PluginsRegistry, OptionsContext } from '../../../../contexts.js';
@@ -9,15 +15,22 @@ import { theme, Typography, Button, Divider } from 'antd';
9
15
  import AlignWidget from './AlignWidget.js';
10
16
  import WidgetRenderer from './WidgetRenderer.js';
11
17
  import ButtonGroupWidget from './ButtonGroupWidget.js';
12
- import { InternalNamePath, ValidateErrorEntity } from "rc-field-form/es/interface.js";
18
+ import { InternalNamePath, ValidateErrorEntity } from 'rc-field-form/es/interface.js';
13
19
 
14
20
  // Import FormRender as a default import
15
21
  import FormRenderComponent from 'form-render';
16
22
 
17
23
  const { Text } = Typography;
18
24
 
19
- type DetailViewProps = Pick<SidebarProps,
20
- 'size' | 'schemas' | 'schemasList' | 'pageSize' | 'changeSchemas' | 'activeElements' | 'deselectSchema'
25
+ type DetailViewProps = Pick<
26
+ SidebarProps,
27
+ | 'size'
28
+ | 'schemas'
29
+ | 'schemasList'
30
+ | 'pageSize'
31
+ | 'changeSchemas'
32
+ | 'activeElements'
33
+ | 'deselectSchema'
21
34
  > & {
22
35
  activeSchema: SchemaForUI;
23
36
  };
@@ -64,11 +77,11 @@ const DetailView = (props: DetailViewProps) => {
64
77
 
65
78
  useEffect(() => {
66
79
  const values: any = { ...activeSchema };
67
- values.editable = !(values.readOnly)
80
+ values.editable = !values.readOnly;
68
81
  form.setValues(values);
69
82
  }, [activeSchema, form]);
70
83
 
71
- useEffect(() => form.resetFields(), [activeSchema.id])
84
+ useEffect(() => form.resetFields(), [activeSchema.id]);
72
85
 
73
86
  useEffect(() => {
74
87
  uniqueSchemaName.current = (value: string): boolean => {
@@ -85,7 +98,8 @@ const DetailView = (props: DetailViewProps) => {
85
98
 
86
99
  const uniqueSchemaName = useRef((value: string): boolean => true);
87
100
 
88
- const validateUniqueSchemaName = (_: any, value: string): boolean => uniqueSchemaName.current(value)
101
+ const validateUniqueSchemaName = (_: any, value: string): boolean =>
102
+ uniqueSchemaName.current(value);
89
103
 
90
104
  const handleWatch = debounce((formSchema: any) => {
91
105
  const formAndSchemaValuesDiffer = (formValue: any, schemaValue: any): boolean => {
@@ -93,7 +107,7 @@ const DetailView = (props: DetailViewProps) => {
93
107
  return JSON.stringify(formValue) !== JSON.stringify(schemaValue);
94
108
  }
95
109
  return formValue !== schemaValue;
96
- }
110
+ };
97
111
 
98
112
  let changes: ChangeSchemaItem[] = [];
99
113
  for (const key in formSchema) {
@@ -121,15 +135,17 @@ const DetailView = (props: DetailViewProps) => {
121
135
 
122
136
  if (changes.length) {
123
137
  // Only commit these schema changes if they have passed form validation
124
- form.validateFields()
138
+ form
139
+ .validateFields()
125
140
  .then(() => changeSchemas(changes))
126
141
  .catch((reason: ValidateErrorEntity) => {
127
142
  if (reason.errorFields.length) {
128
- changes = changes.filter((change: ChangeSchemaItem) => !reason.errorFields.find((field: {
129
- name: InternalNamePath;
130
- errors: string[];
131
- }) => field.name.includes(change.key)
132
- ));
143
+ changes = changes.filter(
144
+ (change: ChangeSchemaItem) =>
145
+ !reason.errorFields.find((field: { name: InternalNamePath; errors: string[] }) =>
146
+ field.name.includes(change.key),
147
+ ),
148
+ );
133
149
  }
134
150
  if (changes.length) {
135
151
  changeSchemas(changes);
@@ -139,7 +155,7 @@ const DetailView = (props: DetailViewProps) => {
139
155
  }, 100);
140
156
 
141
157
  const activePlugin = Object.values(pluginsRegistry).find(
142
- (plugin) => plugin?.propPanel.defaultSchema.type === activeSchema.type
158
+ (plugin) => plugin?.propPanel.defaultSchema.type === activeSchema.type,
143
159
  )!;
144
160
 
145
161
  const activePropPanelSchema = activePlugin?.propPanel.schema;
@@ -171,14 +187,26 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
171
187
  type: 'string',
172
188
  required: true,
173
189
  span: 12,
174
- rules: [{
175
- validator: validateUniqueSchemaName,
176
- message: i18n('validation.uniqueName'),
177
- }],
178
- props: { autoComplete: "off" }
190
+ rules: [
191
+ {
192
+ validator: validateUniqueSchemaName,
193
+ message: i18n('validation.uniqueName'),
194
+ },
195
+ ],
196
+ props: { autoComplete: 'off' },
197
+ },
198
+ editable: {
199
+ title: i18n('editable'),
200
+ type: 'boolean',
201
+ span: 8,
202
+ hidden: defaultSchema?.readOnly !== undefined,
203
+ },
204
+ required: {
205
+ title: i18n('required'),
206
+ type: 'boolean',
207
+ span: 16,
208
+ hidden: '{{!formData.editable}}',
179
209
  },
180
- editable: { title: i18n('editable'), type: 'boolean', span: 8, hidden: defaultSchema?.readOnly !== undefined },
181
- required: { title: i18n('required'), type: 'boolean', span: 16, hidden: "{{!formData.editable}}" },
182
210
  '-': { type: 'void', widget: 'Divider' },
183
211
  align: { title: i18n('align'), type: 'void', widget: 'AlignWidget' },
184
212
  position: {
@@ -187,7 +215,7 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
187
215
  properties: {
188
216
  x: { title: 'X', type: 'number', widget: 'inputNumber', required: true, span: 8, min: 0 },
189
217
  y: { title: 'Y', type: 'number', widget: 'inputNumber', required: true, span: 8, min: 0 },
190
- }
218
+ },
191
219
  },
192
220
  width: {
193
221
  title: i18n('width'),
@@ -1,7 +1,7 @@
1
1
  import React, { useEffect, useContext } from 'react';
2
2
  import { DraggableSyntheticListeners } from '@dnd-kit/core';
3
3
  import { I18nContext } from '../../../../contexts.js';
4
- import { GripVertical, CircleAlert, Lock } from 'lucide-react'
4
+ import { GripVertical, CircleAlert, Lock } from 'lucide-react';
5
5
  import { Button, Typography } from 'antd';
6
6
 
7
7
  const { Text } = Typography;
@@ -48,7 +48,7 @@ const Item = React.memo(
48
48
  transform,
49
49
  ...props
50
50
  },
51
- ref
51
+ ref,
52
52
  ) => {
53
53
  const i18n = useContext(I18nContext);
54
54
 
@@ -125,8 +125,8 @@ const Item = React.memo(
125
125
  </div>
126
126
  </li>
127
127
  );
128
- }
129
- )
128
+ },
129
+ ),
130
130
  );
131
131
 
132
132
  export default Item;