@pdfme/ui 4.2.2 → 4.2.3-dev.4
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 +27 -13
- package/dist/index.es.js +122 -110
- package/dist/index.umd.js +7 -7
- package/dist/types/class.d.ts +0 -3
- package/dist/types/components/Designer/RightSidebar/DetailView/index.d.ts +4 -3
- package/dist/types/helper.d.ts +0 -1
- package/package.json +1 -1
- package/src/components/Designer/LeftSidebar.tsx +6 -3
- package/src/components/Designer/RightSidebar/DetailView/index.tsx +66 -59
- package/src/components/Designer/index.tsx +3 -2
- package/src/helper.ts +7 -2
package/dist/types/class.d.ts
CHANGED
@@ -21,7 +21,6 @@ export declare abstract class BaseUIClass {
|
|
21
21
|
getTemplate(): import("zod").objectOutputType<{
|
22
22
|
schemas: import("zod").ZodArray<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodObject<{
|
23
23
|
type: import("zod").ZodString;
|
24
|
-
icon: import("zod").ZodOptional<import("zod").ZodString>;
|
25
24
|
content: import("zod").ZodOptional<import("zod").ZodString>;
|
26
25
|
position: import("zod").ZodObject<{
|
27
26
|
x: import("zod").ZodNumber;
|
@@ -40,7 +39,6 @@ export declare abstract class BaseUIClass {
|
|
40
39
|
readOnly: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
41
40
|
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
|
42
41
|
type: import("zod").ZodString;
|
43
|
-
icon: import("zod").ZodOptional<import("zod").ZodString>;
|
44
42
|
content: import("zod").ZodOptional<import("zod").ZodString>;
|
45
43
|
position: import("zod").ZodObject<{
|
46
44
|
x: import("zod").ZodNumber;
|
@@ -59,7 +57,6 @@ export declare abstract class BaseUIClass {
|
|
59
57
|
readOnly: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
60
58
|
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
|
61
59
|
type: import("zod").ZodString;
|
62
|
-
icon: import("zod").ZodOptional<import("zod").ZodString>;
|
63
60
|
content: import("zod").ZodOptional<import("zod").ZodString>;
|
64
61
|
position: import("zod").ZodObject<{
|
65
62
|
x: import("zod").ZodNumber;
|
@@ -1,7 +1,8 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import type { SchemaForUI } from '@pdfme/common';
|
3
3
|
import type { SidebarProps } from '../../../../types';
|
4
|
-
|
4
|
+
type DetailViewProps = Pick<SidebarProps, 'size' | 'schemas' | 'pageSize' | 'changeSchemas' | 'activeElements' | 'deselectSchema'> & {
|
5
5
|
activeSchema: SchemaForUI;
|
6
|
-
}
|
7
|
-
|
6
|
+
};
|
7
|
+
declare const _default: React.MemoExoticComponent<(props: DetailViewProps) => React.JSX.Element>;
|
8
|
+
export default _default;
|
package/dist/types/helper.d.ts
CHANGED
@@ -36,7 +36,6 @@ export declare const template2SchemasList: (_template: Template) => Promise<{
|
|
36
36
|
key: string;
|
37
37
|
opacity?: number | undefined;
|
38
38
|
rotate?: number | undefined;
|
39
|
-
icon?: string | undefined;
|
40
39
|
content?: string | undefined;
|
41
40
|
readOnly?: boolean | undefined;
|
42
41
|
}[][]>;
|
package/package.json
CHANGED
@@ -8,7 +8,7 @@ import { theme, Button } from 'antd';
|
|
8
8
|
import { useDraggable } from '@dnd-kit/core';
|
9
9
|
import { CSS } from "@dnd-kit/utilities";
|
10
10
|
import Renderer from '../Renderer';
|
11
|
-
import { PluginsRegistry } from '../../contexts';
|
11
|
+
import { PluginsRegistry, OptionsContext } from '../../contexts';
|
12
12
|
|
13
13
|
const Draggable = (props: { plugin: Plugin<any>, scale: number, basePdf: BasePdf, children: React.ReactNode }) => {
|
14
14
|
const { scale, basePdf, plugin } = props;
|
@@ -44,6 +44,7 @@ const Draggable = (props: { plugin: Plugin<any>, scale: number, basePdf: BasePdf
|
|
44
44
|
const LeftSidebar = ({ height, scale, basePdf }: { height: number, scale: number, basePdf: BasePdf }) => {
|
45
45
|
const { token } = theme.useToken();
|
46
46
|
const pluginsRegistry = useContext(PluginsRegistry);
|
47
|
+
const options = useContext(OptionsContext);
|
47
48
|
|
48
49
|
const [isDragging, setIsDragging] = useState(false);
|
49
50
|
|
@@ -76,6 +77,8 @@ const LeftSidebar = ({ height, scale, basePdf }: { height: number, scale: number
|
|
76
77
|
>
|
77
78
|
{Object.entries(pluginsRegistry).map(([label, plugin]) => {
|
78
79
|
if (!plugin?.propPanel.defaultSchema) return null;
|
80
|
+
const icon = options.icons?.[plugin.propPanel.defaultSchema.type] ?? plugin.icon;
|
81
|
+
|
79
82
|
return <Draggable
|
80
83
|
key={label}
|
81
84
|
scale={scale}
|
@@ -87,8 +90,8 @@ const LeftSidebar = ({ height, scale, basePdf }: { height: number, scale: number
|
|
87
90
|
setIsDragging(true);
|
88
91
|
}}
|
89
92
|
style={{ width: 35, height: 35, marginTop: '0.25rem', padding: '0.25rem' }}>
|
90
|
-
{
|
91
|
-
<div dangerouslySetInnerHTML={{ __html:
|
93
|
+
{icon ?
|
94
|
+
<div dangerouslySetInnerHTML={{ __html: icon }} />
|
92
95
|
:
|
93
96
|
<div style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>{label}</div>
|
94
97
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import FormRender, { useForm } from 'form-render';
|
2
|
-
import React, { useContext, useEffect
|
2
|
+
import React, { useContext, useEffect } from 'react';
|
3
3
|
import type { ChangeSchemaItem, Dict, SchemaForUI, PropPanelWidgetProps, PropPanelSchema } from '@pdfme/common';
|
4
4
|
import type { SidebarProps } from '../../../../types';
|
5
5
|
import { MenuOutlined } from '@ant-design/icons';
|
@@ -13,79 +13,57 @@ import { InternalNamePath, ValidateErrorEntity } from "rc-field-form/es/interfac
|
|
13
13
|
|
14
14
|
const { Text } = Typography;
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
) => {
|
16
|
+
type DetailViewProps = Pick<SidebarProps,
|
17
|
+
'size' | 'schemas' | 'pageSize' | 'changeSchemas' | 'activeElements' | 'deselectSchema'
|
18
|
+
> & {
|
19
|
+
activeSchema: SchemaForUI;
|
20
|
+
};
|
21
|
+
|
22
|
+
const DetailView = (props: DetailViewProps) => {
|
24
23
|
const { token } = theme.useToken();
|
25
24
|
|
26
|
-
const { size, changeSchemas, deselectSchema, activeSchema
|
25
|
+
const { size, changeSchemas, deselectSchema, activeSchema } = props;
|
27
26
|
const form = useForm();
|
28
27
|
|
29
28
|
const i18n = useContext(I18nContext);
|
30
29
|
const pluginsRegistry = useContext(PluginsRegistry);
|
31
30
|
const options = useContext(OptionsContext);
|
32
31
|
|
33
|
-
const [widgets, setWidgets] = useState<{
|
34
|
-
[key: string]: (props: PropPanelWidgetProps) => React.JSX.Element;
|
35
|
-
}>({});
|
36
|
-
|
37
|
-
useEffect(() => {
|
38
|
-
const newWidgets: typeof widgets = {
|
39
|
-
AlignWidget: (p) => <AlignWidget {...p} {...props} options={options} />,
|
40
|
-
Divider: () => (
|
41
|
-
<Divider style={{ marginTop: token.marginXS, marginBottom: token.marginXS }} />
|
42
|
-
),
|
43
|
-
ButtonGroup: (p) => <ButtonGroupWidget {...p} {...props} options={options} />,
|
44
|
-
};
|
45
|
-
for (const plugin of Object.values(pluginsRegistry)) {
|
46
|
-
const widgets = plugin?.propPanel.widgets || {};
|
47
|
-
Object.entries(widgets).forEach(([widgetKey, widgetValue]) => {
|
48
|
-
newWidgets[widgetKey] = (p) => (
|
49
|
-
<WidgetRenderer
|
50
|
-
{...p}
|
51
|
-
{...props}
|
52
|
-
options={options}
|
53
|
-
theme={token}
|
54
|
-
i18n={i18n as (key: keyof Dict | string) => string}
|
55
|
-
widget={widgetValue}
|
56
|
-
/>
|
57
|
-
);
|
58
|
-
});
|
59
|
-
}
|
60
|
-
setWidgets(newWidgets);
|
61
|
-
}, [activeSchema, activeElements, pluginsRegistry, JSON.stringify(options)]);
|
62
|
-
|
63
32
|
useEffect(() => {
|
64
33
|
const values: any = { ...activeSchema };
|
65
|
-
|
66
34
|
// [position] Change the nested position object into a flat, as a three-column layout is difficult to implement
|
67
35
|
values.x = values.position.x;
|
68
36
|
values.y = values.position.y;
|
69
37
|
delete values.position;
|
38
|
+
form.setValues(values);
|
70
39
|
|
71
|
-
|
72
|
-
form.resetFields();
|
73
|
-
}
|
40
|
+
}, [activeSchema, form]);
|
74
41
|
|
75
|
-
form.setValues(values);
|
76
|
-
}, [form, activeSchema]);
|
77
42
|
|
78
|
-
const handleWatch = (
|
43
|
+
const handleWatch = (formSchema: any) => {
|
44
|
+
const formAndSchemaValuesDiffer = (formValue: any, schemaValue: any): boolean => {
|
45
|
+
if (typeof formValue === 'object') {
|
46
|
+
return JSON.stringify(formValue) !== JSON.stringify(schemaValue);
|
47
|
+
}
|
48
|
+
return formValue !== schemaValue;
|
49
|
+
}
|
50
|
+
|
79
51
|
let changes: ChangeSchemaItem[] = [];
|
80
|
-
for (let key in
|
52
|
+
for (let key in formSchema) {
|
81
53
|
if (['id', 'content'].includes(key)) continue;
|
82
54
|
|
83
|
-
|
84
|
-
|
85
|
-
if (key === 'y') key = 'position.y';
|
55
|
+
let value = formSchema[key];
|
56
|
+
let changed = false;
|
86
57
|
|
87
|
-
if (
|
88
|
-
|
58
|
+
if (['x', 'y'].includes(key)) {
|
59
|
+
// [position] Return the flattened position to its original form.
|
60
|
+
changed = value !== (activeSchema as any)['position'][key];
|
61
|
+
key = 'position.' + key;
|
62
|
+
} else {
|
63
|
+
changed = formAndSchemaValuesDiffer(value, (activeSchema as any)[key]);
|
64
|
+
}
|
65
|
+
|
66
|
+
if (changed) {
|
89
67
|
// FIXME memo: https://github.com/pdfme/pdfme/pull/367#issuecomment-1857468274
|
90
68
|
if (value === null && ['rotate', 'opacity'].includes(key)) value = undefined;
|
91
69
|
|
@@ -98,11 +76,11 @@ const DetailView = (
|
|
98
76
|
form.validateFields()
|
99
77
|
.then(() => changeSchemas(changes))
|
100
78
|
.catch((reason: ValidateErrorEntity) => {
|
101
|
-
if (reason.errorFields.length)
|
79
|
+
if (reason.errorFields.length) {
|
102
80
|
changes = changes.filter((change: ChangeSchemaItem) => !reason.errorFields.find((field: {
|
103
|
-
|
104
|
-
|
105
|
-
|
81
|
+
name: InternalNamePath;
|
82
|
+
errors: string[];
|
83
|
+
}) => field.name.includes(change.key)
|
106
84
|
));
|
107
85
|
}
|
108
86
|
if (changes.length) {
|
@@ -203,6 +181,31 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
203
181
|
};
|
204
182
|
}
|
205
183
|
|
184
|
+
const allWidgets: {
|
185
|
+
[key: string]: (props: PropPanelWidgetProps) => React.JSX.Element;
|
186
|
+
} = {
|
187
|
+
AlignWidget: (p) => <AlignWidget {...p} {...props} options={options} />,
|
188
|
+
Divider: () => (
|
189
|
+
<Divider style={{ marginTop: token.marginXS, marginBottom: token.marginXS }} />
|
190
|
+
),
|
191
|
+
ButtonGroup: (p) => <ButtonGroupWidget {...p} {...props} options={options} />,
|
192
|
+
};
|
193
|
+
for (const plugin of Object.values(pluginsRegistry)) {
|
194
|
+
const widgets = plugin?.propPanel.widgets || {};
|
195
|
+
Object.entries(widgets).forEach(([widgetKey, widgetValue]) => {
|
196
|
+
allWidgets[widgetKey] = (p) => (
|
197
|
+
<WidgetRenderer
|
198
|
+
{...p}
|
199
|
+
{...props}
|
200
|
+
options={options}
|
201
|
+
theme={token}
|
202
|
+
i18n={i18n as (key: keyof Dict | string) => string}
|
203
|
+
widget={widgetValue}
|
204
|
+
/>
|
205
|
+
);
|
206
|
+
});
|
207
|
+
}
|
208
|
+
|
206
209
|
return (
|
207
210
|
<div>
|
208
211
|
<div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
|
@@ -232,7 +235,7 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
232
235
|
<FormRender
|
233
236
|
form={form}
|
234
237
|
schema={propPanelSchema}
|
235
|
-
widgets={
|
238
|
+
widgets={allWidgets}
|
236
239
|
watch={{ '#': handleWatch }}
|
237
240
|
locale="en-US"
|
238
241
|
/>
|
@@ -241,4 +244,8 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
241
244
|
);
|
242
245
|
};
|
243
246
|
|
244
|
-
|
247
|
+
const propsAreUnchanged = (prevProps: DetailViewProps, nextProps: DetailViewProps) => {
|
248
|
+
return JSON.stringify(prevProps.activeSchema) == JSON.stringify(nextProps.activeSchema)
|
249
|
+
};
|
250
|
+
|
251
|
+
export default React.memo(DetailView, propsAreUnchanged);
|
@@ -19,6 +19,7 @@ import { I18nContext, PluginsRegistry } from '../../contexts';
|
|
19
19
|
import {
|
20
20
|
schemasList2template,
|
21
21
|
uuid,
|
22
|
+
round,
|
22
23
|
cloneDeep,
|
23
24
|
template2SchemasList,
|
24
25
|
getPagesScrollTopByIndex,
|
@@ -51,7 +52,7 @@ const TemplateEditor = ({
|
|
51
52
|
onSaveTemplate: (t: Template) => void;
|
52
53
|
onChangeTemplate: (t: Template) => void;
|
53
54
|
} & {
|
54
|
-
onChangeTemplate: (t: Template) => void
|
55
|
+
onChangeTemplate: (t: Template) => void
|
55
56
|
onPageCursorChange: (newPageCursor: number) => void
|
56
57
|
}) => {
|
57
58
|
const past = useRef<SchemaForUI[][]>([]);
|
@@ -253,7 +254,7 @@ const TemplateEditor = ({
|
|
253
254
|
const moveY = (event.delta.y - canvasTopOffsetFromPageCorner) / scale;
|
254
255
|
const moveX = (event.delta.x - canvasLeftOffsetFromPageCorner) / scale;
|
255
256
|
|
256
|
-
const position = { x: px2mm(Math.max(0, moveX)), y: px2mm(Math.max(0, moveY)) }
|
257
|
+
const position = { x: round(px2mm(Math.max(0, moveX)), 2), y: round(px2mm(Math.max(0, moveY)), 2) }
|
257
258
|
|
258
259
|
addSchema({ ...(active.data.current as Schema), position });
|
259
260
|
}}
|
package/src/helper.ts
CHANGED
@@ -454,10 +454,15 @@ const handleTypeChange = (
|
|
454
454
|
delete schema[key as keyof typeof schema];
|
455
455
|
}
|
456
456
|
});
|
457
|
+
// Apply attributes from new defaultSchema
|
457
458
|
const propPanel = Object.values(pluginsRegistry).find(
|
458
459
|
(plugin) => plugin?.propPanel.defaultSchema.type === value
|
459
460
|
)?.propPanel;
|
460
|
-
Object.
|
461
|
+
Object.keys(propPanel?.defaultSchema || {}).forEach((key) => {
|
462
|
+
if (!schema.hasOwnProperty(key)) {
|
463
|
+
(schema as any)[key] = propPanel?.defaultSchema[key];
|
464
|
+
}
|
465
|
+
});
|
461
466
|
};
|
462
467
|
|
463
468
|
export const changeSchemas = (args: {
|
@@ -484,4 +489,4 @@ export const changeSchemas = (args: {
|
|
484
489
|
return acc;
|
485
490
|
}, cloneDeep(schemas));
|
486
491
|
commitSchemas(newSchemas);
|
487
|
-
};
|
492
|
+
};
|