@pdfme/ui 4.2.3 → 4.2.4-dev.10
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/dist/index.es.js +12208 -12138
- package/dist/index.umd.js +194 -193
- package/dist/types/class.d.ts +3 -3
- package/dist/types/components/Designer/PluginIcon.d.ts +10 -0
- package/dist/types/components/Designer/RightSidebar/DetailView/index.d.ts +4 -3
- package/dist/types/components/Designer/RightSidebar/ListView/Item.d.ts +2 -0
- package/dist/types/contexts.d.ts +2 -1
- package/dist/types/helper.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/Designer/LeftSidebar.tsx +6 -11
- package/src/components/Designer/PluginIcon.tsx +47 -0
- package/src/components/Designer/RightSidebar/DetailView/ButtonGroupWidget.tsx +1 -1
- package/src/components/Designer/RightSidebar/DetailView/index.tsx +24 -20
- package/src/components/Designer/RightSidebar/ListView/Item.tsx +7 -1
- package/src/components/Designer/RightSidebar/ListView/SelectableSortableContainer.tsx +25 -5
- package/src/components/Designer/RightSidebar/ListView/SelectableSortableItem.tsx +11 -1
- package/src/components/Designer/index.tsx +6 -3
- package/src/components/Renderer.tsx +10 -0
- package/src/helper.ts +5 -2
- package/src/i18n.ts +11 -0
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;
|
@@ -38,9 +37,9 @@ export declare abstract class BaseUIClass {
|
|
38
37
|
rotate: import("zod").ZodOptional<import("zod").ZodNumber>;
|
39
38
|
opacity: import("zod").ZodOptional<import("zod").ZodNumber>;
|
40
39
|
readOnly: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
40
|
+
required: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
41
41
|
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
|
42
42
|
type: import("zod").ZodString;
|
43
|
-
icon: import("zod").ZodOptional<import("zod").ZodString>;
|
44
43
|
content: import("zod").ZodOptional<import("zod").ZodString>;
|
45
44
|
position: import("zod").ZodObject<{
|
46
45
|
x: import("zod").ZodNumber;
|
@@ -57,9 +56,9 @@ export declare abstract class BaseUIClass {
|
|
57
56
|
rotate: import("zod").ZodOptional<import("zod").ZodNumber>;
|
58
57
|
opacity: import("zod").ZodOptional<import("zod").ZodNumber>;
|
59
58
|
readOnly: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
59
|
+
required: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
60
60
|
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
|
61
61
|
type: import("zod").ZodString;
|
62
|
-
icon: import("zod").ZodOptional<import("zod").ZodString>;
|
63
62
|
content: import("zod").ZodOptional<import("zod").ZodString>;
|
64
63
|
position: import("zod").ZodObject<{
|
65
64
|
x: import("zod").ZodNumber;
|
@@ -76,6 +75,7 @@ export declare abstract class BaseUIClass {
|
|
76
75
|
rotate: import("zod").ZodOptional<import("zod").ZodNumber>;
|
77
76
|
opacity: import("zod").ZodOptional<import("zod").ZodNumber>;
|
78
77
|
readOnly: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
78
|
+
required: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
79
79
|
}, import("zod").ZodTypeAny, "passthrough">>>, "many">;
|
80
80
|
basePdf: import("zod").ZodUnion<[import("zod").ZodUnion<[import("zod").ZodString, import("zod").ZodType<ArrayBuffer, import("zod").ZodTypeDef, ArrayBuffer>, import("zod").ZodType<Uint8Array, import("zod").ZodTypeDef, Uint8Array>]>, import("zod").ZodObject<{
|
81
81
|
width: import("zod").ZodNumber;
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { Plugin } from "@pdfme/common";
|
3
|
+
interface PluginIconProps {
|
4
|
+
plugin: Plugin<any>;
|
5
|
+
label: string;
|
6
|
+
size?: number;
|
7
|
+
styles?: React.CSSProperties;
|
8
|
+
}
|
9
|
+
declare const PluginIcon: (props: PluginIconProps) => React.JSX.Element;
|
10
|
+
export default PluginIcon;
|
@@ -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;
|
@@ -2,9 +2,11 @@ import React from 'react';
|
|
2
2
|
import { DraggableSyntheticListeners } from '@dnd-kit/core';
|
3
3
|
interface Props {
|
4
4
|
value: React.ReactNode;
|
5
|
+
icon?: React.ReactNode;
|
5
6
|
style?: React.CSSProperties;
|
6
7
|
status?: 'is-warning' | 'is-danger';
|
7
8
|
title?: string;
|
9
|
+
required?: boolean;
|
8
10
|
dragOverlay?: boolean;
|
9
11
|
onClick?: () => void;
|
10
12
|
onMouseEnter?: () => void;
|
package/dist/types/contexts.d.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/// <reference types="react" />
|
2
2
|
import { Plugins, UIOptions } from '@pdfme/common';
|
3
|
-
export declare const I18nContext: import("react").Context<(key: "type" | "width" | "height" | "rotate" | "opacity" | "cancel" | "field" | "fieldName" | "align" | "edit" | "plsInputName" | "fieldMustUniq" | "notUniq" | "noKeyName" | "fieldsList" | "editField" | "errorOccurred" | "errorBulkUpdateFieldName" | "commitBulkUpdateFieldName" | "bulkUpdateFieldName" | "addPageAfter" | "removePage" | "removePageConfirm" | "hexColorPrompt" | "schemas.color" | "schemas.borderWidth" | "schemas.borderColor" | "schemas.backgroundColor" | "schemas.textColor" | "schemas.bgColor" | "schemas.horizontal" | "schemas.vertical" | "schemas.left" | "schemas.center" | "schemas.right" | "schemas.top" | "schemas.middle" | "schemas.bottom" | "schemas.padding" | "schemas.text.fontName" | "schemas.text.size" | "schemas.text.spacing" | "schemas.text.textAlign" | "schemas.text.verticalAlign" | "schemas.text.lineHeight" | "schemas.text.min" | "schemas.text.max" | "schemas.text.fit" | "schemas.text.dynamicFontSize" | "schemas.text.format" | "schemas.mvt.typingInstructions" | "schemas.mvt.sampleField" | "schemas.mvt.variablesSampleData" | "schemas.barcodes.barColor" | "schemas.barcodes.includetext" | "schemas.table.alternateBackgroundColor" | "schemas.table.tableStyle" | "schemas.table.headStyle" | "schemas.table.bodyStyle" | "schemas.table.columnStyle", dict?: {
|
3
|
+
export declare const I18nContext: import("react").Context<(key: "type" | "width" | "height" | "rotate" | "opacity" | "required" | "cancel" | "field" | "fieldName" | "align" | "edit" | "plsInputName" | "fieldMustUniq" | "notUniq" | "noKeyName" | "fieldsList" | "editField" | "errorOccurred" | "errorBulkUpdateFieldName" | "commitBulkUpdateFieldName" | "bulkUpdateFieldName" | "addPageAfter" | "removePage" | "removePageConfirm" | "hexColorPrompt" | "schemas.color" | "schemas.borderWidth" | "schemas.borderColor" | "schemas.backgroundColor" | "schemas.textColor" | "schemas.bgColor" | "schemas.horizontal" | "schemas.vertical" | "schemas.left" | "schemas.center" | "schemas.right" | "schemas.top" | "schemas.middle" | "schemas.bottom" | "schemas.padding" | "schemas.text.fontName" | "schemas.text.size" | "schemas.text.spacing" | "schemas.text.textAlign" | "schemas.text.verticalAlign" | "schemas.text.lineHeight" | "schemas.text.min" | "schemas.text.max" | "schemas.text.fit" | "schemas.text.dynamicFontSize" | "schemas.text.format" | "schemas.mvt.typingInstructions" | "schemas.mvt.sampleField" | "schemas.mvt.variablesSampleData" | "schemas.barcodes.barColor" | "schemas.barcodes.includetext" | "schemas.table.alternateBackgroundColor" | "schemas.table.tableStyle" | "schemas.table.headStyle" | "schemas.table.bodyStyle" | "schemas.table.columnStyle", dict?: {
|
4
4
|
cancel: string;
|
5
5
|
field: string;
|
6
6
|
fieldName: string;
|
@@ -10,6 +10,7 @@ export declare const I18nContext: import("react").Context<(key: "type" | "width"
|
|
10
10
|
height: string;
|
11
11
|
rotate: string;
|
12
12
|
edit: string;
|
13
|
+
required: string;
|
13
14
|
plsInputName: string;
|
14
15
|
fieldMustUniq: string;
|
15
16
|
notUniq: string;
|
package/dist/types/helper.d.ts
CHANGED
@@ -36,7 +36,7 @@ export declare const template2SchemasList: (_template: Template) => Promise<{
|
|
36
36
|
key: string;
|
37
37
|
opacity?: number | undefined;
|
38
38
|
rotate?: number | undefined;
|
39
|
-
|
39
|
+
required?: boolean | undefined;
|
40
40
|
content?: string | undefined;
|
41
41
|
readOnly?: boolean | undefined;
|
42
42
|
}[][]>;
|
package/package.json
CHANGED
@@ -9,6 +9,7 @@ import { useDraggable } from '@dnd-kit/core';
|
|
9
9
|
import { CSS } from "@dnd-kit/utilities";
|
10
10
|
import Renderer from '../Renderer';
|
11
11
|
import { PluginsRegistry } from '../../contexts';
|
12
|
+
import PluginIcon from "./PluginIcon";
|
12
13
|
|
13
14
|
const Draggable = (props: { plugin: Plugin<any>, scale: number, basePdf: BasePdf, children: React.ReactNode }) => {
|
14
15
|
const { scale, basePdf, plugin } = props;
|
@@ -44,7 +45,6 @@ const Draggable = (props: { plugin: Plugin<any>, scale: number, basePdf: BasePdf
|
|
44
45
|
const LeftSidebar = ({ height, scale, basePdf }: { height: number, scale: number, basePdf: BasePdf }) => {
|
45
46
|
const { token } = theme.useToken();
|
46
47
|
const pluginsRegistry = useContext(PluginsRegistry);
|
47
|
-
|
48
48
|
const [isDragging, setIsDragging] = useState(false);
|
49
49
|
|
50
50
|
useEffect(() => {
|
@@ -76,22 +76,17 @@ const LeftSidebar = ({ height, scale, basePdf }: { height: number, scale: number
|
|
76
76
|
>
|
77
77
|
{Object.entries(pluginsRegistry).map(([label, plugin]) => {
|
78
78
|
if (!plugin?.propPanel.defaultSchema) return null;
|
79
|
+
|
79
80
|
return <Draggable
|
80
81
|
key={label}
|
81
82
|
scale={scale}
|
82
83
|
basePdf={basePdf}
|
83
84
|
plugin={plugin}>
|
84
85
|
<Button
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
}}
|
89
|
-
style={{ width: 35, height: 35, marginTop: '0.25rem', padding: '0.25rem' }}>
|
90
|
-
{plugin.propPanel.defaultSchema.icon ?
|
91
|
-
<div dangerouslySetInnerHTML={{ __html: plugin.propPanel.defaultSchema.icon }} />
|
92
|
-
:
|
93
|
-
<div style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>{label}</div>
|
94
|
-
}
|
86
|
+
onMouseDown={() => setIsDragging(true)}
|
87
|
+
style={{ width: 35, height: 35, marginTop: '0.25rem', padding: '0.25rem' }}
|
88
|
+
>
|
89
|
+
<PluginIcon plugin={plugin} label={label} />
|
95
90
|
</Button>
|
96
91
|
</Draggable>
|
97
92
|
})}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import React, { useContext } from 'react';
|
2
|
+
import { Plugin } from "@pdfme/common";
|
3
|
+
import { OptionsContext } from '../../contexts';
|
4
|
+
|
5
|
+
interface PluginIconProps {
|
6
|
+
plugin: Plugin<any>;
|
7
|
+
label: string;
|
8
|
+
size?: number;
|
9
|
+
styles?: React.CSSProperties;
|
10
|
+
}
|
11
|
+
|
12
|
+
const getWithModifiedSize = (htmlString: string, label: string, size: number, styles?: React.CSSProperties) => {
|
13
|
+
const parser = new DOMParser();
|
14
|
+
const doc = parser.parseFromString(htmlString, 'text/html');
|
15
|
+
|
16
|
+
const modifyNode = (node: HTMLElement) => {
|
17
|
+
if (node.tagName === 'SVG' || node.tagName === 'svg') {
|
18
|
+
node.setAttribute('width', size.toString());
|
19
|
+
node.setAttribute('height', size.toString());
|
20
|
+
}
|
21
|
+
Array.from(node.children).forEach(child => modifyNode(child as HTMLElement));
|
22
|
+
};
|
23
|
+
|
24
|
+
Array.from(doc.body.children).forEach(child => modifyNode(child as HTMLElement));
|
25
|
+
|
26
|
+
return (
|
27
|
+
<div style={styles} title={label} dangerouslySetInnerHTML={{ __html: doc.body.innerHTML }} />
|
28
|
+
);
|
29
|
+
};
|
30
|
+
|
31
|
+
const PluginIcon = (props: PluginIconProps) => {
|
32
|
+
const { plugin, label, size, styles } = props;
|
33
|
+
const options = useContext(OptionsContext);
|
34
|
+
const icon = options.icons?.[plugin.propPanel.defaultSchema.type] ?? plugin.icon;
|
35
|
+
const iconStyles = { ...styles, display: 'flex', justifyContent: 'center' };
|
36
|
+
|
37
|
+
if (icon) {
|
38
|
+
if (size) {
|
39
|
+
return getWithModifiedSize(icon, label, size, iconStyles);
|
40
|
+
}
|
41
|
+
return <div style={iconStyles} title={label} dangerouslySetInnerHTML={{__html: icon}} />
|
42
|
+
}
|
43
|
+
|
44
|
+
return <div style={{...styles, overflow: 'hidden', fontSize: 10, }}>{label}</div>
|
45
|
+
};
|
46
|
+
|
47
|
+
export default PluginIcon;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import FormRender, { useForm } from 'form-render';
|
2
|
-
import React, { useContext,
|
2
|
+
import React, { useContext, useState, 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,17 +13,16 @@ 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);
|
@@ -58,11 +57,10 @@ const DetailView = (
|
|
58
57
|
});
|
59
58
|
}
|
60
59
|
setWidgets(newWidgets);
|
61
|
-
}, [activeSchema,
|
60
|
+
}, [activeSchema, pluginsRegistry, JSON.stringify(options)]);
|
62
61
|
|
63
62
|
useEffect(() => {
|
64
63
|
const values: any = { ...activeSchema };
|
65
|
-
|
66
64
|
// [position] Change the nested position object into a flat, as a three-column layout is difficult to implement
|
67
65
|
values.x = values.position.x;
|
68
66
|
values.y = values.position.y;
|
@@ -73,7 +71,8 @@ const DetailView = (
|
|
73
71
|
}
|
74
72
|
|
75
73
|
form.setValues(values);
|
76
|
-
|
74
|
+
|
75
|
+
}, [activeSchema, form]);
|
77
76
|
|
78
77
|
const handleWatch = (formSchema: any) => {
|
79
78
|
const formAndSchemaValuesDiffer = (formValue: any, schemaValue: any): boolean => {
|
@@ -102,7 +101,7 @@ const DetailView = (
|
|
102
101
|
// FIXME memo: https://github.com/pdfme/pdfme/pull/367#issuecomment-1857468274
|
103
102
|
if (value === null && ['rotate', 'opacity'].includes(key)) value = undefined;
|
104
103
|
|
105
|
-
changes.push({key, value, schemaId: activeSchema.id});
|
104
|
+
changes.push({ key, value, schemaId: activeSchema.id });
|
106
105
|
}
|
107
106
|
}
|
108
107
|
|
@@ -111,11 +110,11 @@ const DetailView = (
|
|
111
110
|
form.validateFields()
|
112
111
|
.then(() => changeSchemas(changes))
|
113
112
|
.catch((reason: ValidateErrorEntity) => {
|
114
|
-
if (reason.errorFields.length)
|
113
|
+
if (reason.errorFields.length) {
|
115
114
|
changes = changes.filter((change: ChangeSchemaItem) => !reason.errorFields.find((field: {
|
116
|
-
|
117
|
-
|
118
|
-
|
115
|
+
name: InternalNamePath;
|
116
|
+
errors: string[];
|
117
|
+
}) => field.name.includes(change.key)
|
119
118
|
));
|
120
119
|
}
|
121
120
|
if (changes.length) {
|
@@ -153,7 +152,8 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
153
152
|
required: true,
|
154
153
|
span: 12,
|
155
154
|
},
|
156
|
-
key: { title: i18n('fieldName'), type: 'string', required: true, span: 12 },
|
155
|
+
key: { title: i18n('fieldName'), type: 'string', required: true, span: 12, props: { autocomplete: "off"} },
|
156
|
+
required: { title: i18n('required'), type: 'boolean', span: 8, hidden: defaultSchema?.readOnly },
|
157
157
|
'-': { type: 'void', widget: 'Divider' },
|
158
158
|
align: { title: i18n('align'), type: 'void', widget: 'AlignWidget' },
|
159
159
|
x: { title: 'X', type: 'number', widget: 'inputNumber', required: true, span: 8, min: 0 },
|
@@ -254,4 +254,8 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
254
254
|
);
|
255
255
|
};
|
256
256
|
|
257
|
-
|
257
|
+
const propsAreUnchanged = (prevProps: DetailViewProps, nextProps: DetailViewProps) => {
|
258
|
+
return JSON.stringify(prevProps.activeSchema) == JSON.stringify(nextProps.activeSchema)
|
259
|
+
};
|
260
|
+
|
261
|
+
export default React.memo(DetailView, propsAreUnchanged);
|
@@ -8,9 +8,11 @@ const { Text } = Typography;
|
|
8
8
|
|
9
9
|
interface Props {
|
10
10
|
value: React.ReactNode;
|
11
|
+
icon?: React.ReactNode;
|
11
12
|
style?: React.CSSProperties;
|
12
13
|
status?: 'is-warning' | 'is-danger';
|
13
14
|
title?: string;
|
15
|
+
required?: boolean;
|
14
16
|
dragOverlay?: boolean;
|
15
17
|
onClick?: () => void;
|
16
18
|
onMouseEnter?: () => void;
|
@@ -26,9 +28,11 @@ const Item = React.memo(
|
|
26
28
|
React.forwardRef<HTMLLIElement, Props>(
|
27
29
|
(
|
28
30
|
{
|
31
|
+
icon,
|
29
32
|
value,
|
30
33
|
status,
|
31
34
|
title,
|
35
|
+
required,
|
32
36
|
style,
|
33
37
|
dragOverlay,
|
34
38
|
onClick,
|
@@ -93,6 +97,7 @@ const Item = React.memo(
|
|
93
97
|
}}
|
94
98
|
icon={<HolderOutlined style={{ cursor: 'grab' }} />}
|
95
99
|
/>
|
100
|
+
{icon}
|
96
101
|
<Text
|
97
102
|
style={{
|
98
103
|
overflow: 'hidden',
|
@@ -105,12 +110,13 @@ const Item = React.memo(
|
|
105
110
|
{status === undefined ? (
|
106
111
|
value
|
107
112
|
) : (
|
108
|
-
<span
|
113
|
+
<span>
|
109
114
|
<ExclamationCircleOutlined width={15} style={{ marginRight: '0.5rem' }} />
|
110
115
|
{status === 'is-warning' ? i18n('noKeyName') : value}
|
111
116
|
{status === 'is-danger' ? i18n('notUniq') : ''}
|
112
117
|
</span>
|
113
118
|
)}
|
119
|
+
{required && <span style={{ color: 'red', marginLeft: '0.5rem' }}>*</span>}
|
114
120
|
</Text>
|
115
121
|
</div>
|
116
122
|
</li>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, { useState } from 'react';
|
1
|
+
import React, { useState, useContext, ReactNode } from 'react';
|
2
2
|
import { createPortal } from 'react-dom';
|
3
3
|
import {
|
4
4
|
closestCorners,
|
@@ -17,9 +17,11 @@ import {
|
|
17
17
|
} from '@dnd-kit/sortable';
|
18
18
|
import { SchemaForUI } from '@pdfme/common';
|
19
19
|
import type { SidebarProps } from '../../../../types';
|
20
|
+
import { PluginsRegistry } from '../../../../contexts';
|
20
21
|
import Item from './Item';
|
21
22
|
import SelectableSortableItem from './SelectableSortableItem';
|
22
23
|
import { theme } from 'antd';
|
24
|
+
import PluginIcon from "../../PluginIcon";
|
23
25
|
|
24
26
|
const SelectableSortableContainer = (
|
25
27
|
props: Pick<
|
@@ -28,11 +30,11 @@ const SelectableSortableContainer = (
|
|
28
30
|
>
|
29
31
|
) => {
|
30
32
|
const { token } = theme.useToken();
|
31
|
-
|
32
33
|
const { schemas, onEdit, onSortEnd, hoveringSchemaId, onChangeHoveringSchemaId } = props;
|
33
34
|
const [selectedSchemas, setSelectedSchemas] = useState<SchemaForUI[]>([]);
|
34
|
-
const [
|
35
|
+
const [dragOverlaidItems, setClonedItems] = useState<SchemaForUI[] | null>(null);
|
35
36
|
const [activeId, setActiveId] = useState<string | null>(null);
|
37
|
+
const pluginsRegistry = useContext(PluginsRegistry);
|
36
38
|
const sensors = useSensors(
|
37
39
|
useSensor(PointerSensor, { activationConstraint: { distance: 15 } }),
|
38
40
|
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
|
@@ -56,6 +58,20 @@ const SelectableSortableContainer = (
|
|
56
58
|
}
|
57
59
|
};
|
58
60
|
|
61
|
+
const getPluginIcon = (inSchema: string|SchemaForUI): ReactNode => {
|
62
|
+
const thisSchema = (typeof inSchema === 'string') ? schemas.find((schema) => schema.id === inSchema) : inSchema;
|
63
|
+
|
64
|
+
const [pluginLabel, activePlugin] = Object.entries(pluginsRegistry).find(
|
65
|
+
([label, plugin]) => plugin?.propPanel.defaultSchema.type === thisSchema?.type
|
66
|
+
)!;
|
67
|
+
|
68
|
+
if (!activePlugin) {
|
69
|
+
return <></>
|
70
|
+
}
|
71
|
+
|
72
|
+
return <PluginIcon plugin={activePlugin} label={pluginLabel} size={20} styles={{marginRight: '0.5rem'}}/>
|
73
|
+
};
|
74
|
+
|
59
75
|
return (
|
60
76
|
<DndContext
|
61
77
|
sensors={sensors}
|
@@ -101,8 +117,8 @@ const SelectableSortableContainer = (
|
|
101
117
|
setActiveId(null);
|
102
118
|
}}
|
103
119
|
onDragCancel={() => {
|
104
|
-
if (
|
105
|
-
onSortEnd(
|
120
|
+
if (dragOverlaidItems) {
|
121
|
+
onSortEnd(dragOverlaidItems);
|
106
122
|
}
|
107
123
|
|
108
124
|
setActiveId(null);
|
@@ -139,7 +155,9 @@ const SelectableSortableContainer = (
|
|
139
155
|
<>
|
140
156
|
<ul style={{ margin: 0, padding: 0, listStyle: 'none' }}>
|
141
157
|
<Item
|
158
|
+
icon={getPluginIcon(activeId)}
|
142
159
|
value={schemas.find((schema) => schema.id === activeId)!.key}
|
160
|
+
required={schemas.find((schema) => schema.id === activeId)!.required}
|
143
161
|
style={{ background: token.colorPrimary }}
|
144
162
|
dragOverlay
|
145
163
|
/>
|
@@ -149,8 +167,10 @@ const SelectableSortableContainer = (
|
|
149
167
|
.filter((item) => item.id !== activeId)
|
150
168
|
.map((item) => (
|
151
169
|
<Item
|
170
|
+
icon={getPluginIcon(item)}
|
152
171
|
key={item.id}
|
153
172
|
value={item.key}
|
173
|
+
required={item.required}
|
154
174
|
style={{ background: token.colorPrimary }}
|
155
175
|
dragOverlay
|
156
176
|
/>
|
@@ -1,10 +1,11 @@
|
|
1
1
|
import React, { useContext } from 'react';
|
2
2
|
import { useSortable } from '@dnd-kit/sortable';
|
3
3
|
import { SchemaForUI } from '@pdfme/common';
|
4
|
-
import { I18nContext } from '../../../../contexts';
|
4
|
+
import { PluginsRegistry, I18nContext } from '../../../../contexts';
|
5
5
|
import Item from './Item';
|
6
6
|
import { useMountStatus } from '../../../../hooks';
|
7
7
|
import { theme } from 'antd';
|
8
|
+
import PluginIcon from "../../PluginIcon";
|
8
9
|
|
9
10
|
interface Props {
|
10
11
|
isSelected: boolean;
|
@@ -29,6 +30,7 @@ const SelectableSortableItem = ({
|
|
29
30
|
const { token } = theme.useToken();
|
30
31
|
|
31
32
|
const i18n = useContext(I18nContext);
|
33
|
+
const pluginsRegistry = useContext(PluginsRegistry);
|
32
34
|
const { setNodeRef, listeners, isDragging, isSorting, transform, transition } = useSortable({
|
33
35
|
id: schema.id,
|
34
36
|
});
|
@@ -40,6 +42,12 @@ const SelectableSortableItem = ({
|
|
40
42
|
onClick: (event: any) => onSelect(schema.id, event.shiftKey),
|
41
43
|
};
|
42
44
|
|
45
|
+
const [pluginLabel, thisPlugin] = Object.entries(pluginsRegistry).find(
|
46
|
+
([label, plugin]) => plugin?.propPanel.defaultSchema.type === schema.type
|
47
|
+
)!;
|
48
|
+
|
49
|
+
const iconStyles = { width: 20, marginRight: '0.5rem' };
|
50
|
+
|
43
51
|
let status: undefined | 'is-warning' | 'is-danger';
|
44
52
|
if (!schema.key) {
|
45
53
|
status = 'is-warning';
|
@@ -64,9 +72,11 @@ const SelectableSortableItem = ({
|
|
64
72
|
onMouseEnter={onMouseEnter}
|
65
73
|
onMouseLeave={onMouseLeave}
|
66
74
|
onClick={() => onEdit(schema.id)}
|
75
|
+
icon={thisPlugin && <PluginIcon plugin={thisPlugin} label={pluginLabel} size={20} styles={iconStyles}/>}
|
67
76
|
value={schema.key}
|
68
77
|
status={status}
|
69
78
|
title={title}
|
79
|
+
required={schema.required}
|
70
80
|
style={{ ...selectedStyle, ...style }}
|
71
81
|
dragging={isDragging}
|
72
82
|
sorting={isSorting}
|
@@ -15,10 +15,11 @@ import RightSidebar from './RightSidebar/index';
|
|
15
15
|
import LeftSidebar from './LeftSidebar';
|
16
16
|
import Canvas from './Canvas/index';
|
17
17
|
import { RULER_HEIGHT, RIGHT_SIDEBAR_WIDTH } from '../../constants';
|
18
|
-
import { I18nContext, PluginsRegistry } from '../../contexts';
|
18
|
+
import { I18nContext, OptionsContext, 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[][]>([]);
|
@@ -61,6 +62,7 @@ const TemplateEditor = ({
|
|
61
62
|
|
62
63
|
const i18n = useContext(I18nContext);
|
63
64
|
const pluginsRegistry = useContext(PluginsRegistry);
|
65
|
+
const options = useContext(OptionsContext);
|
64
66
|
|
65
67
|
const [hoveringSchemaId, setHoveringSchemaId] = useState<string | null>(null);
|
66
68
|
const [activeElements, setActiveElements] = useState<HTMLElement[]>([]);
|
@@ -170,6 +172,7 @@ const TemplateEditor = ({
|
|
170
172
|
x: ensureMiddleValue(paddingLeft, defaultSchema.position.x, pageSize.width - paddingRight - defaultSchema.width),
|
171
173
|
y: ensureMiddleValue(paddingTop, defaultSchema.position.y, pageSize.height - paddingBottom - defaultSchema.height),
|
172
174
|
},
|
175
|
+
required: defaultSchema.readOnly ? false : options.requiredByDefault || defaultSchema.required || false,
|
173
176
|
} as SchemaForUI;
|
174
177
|
|
175
178
|
if (defaultSchema.position.y === 0) {
|
@@ -253,7 +256,7 @@ const TemplateEditor = ({
|
|
253
256
|
const moveY = (event.delta.y - canvasTopOffsetFromPageCorner) / scale;
|
254
257
|
const moveX = (event.delta.x - canvasLeftOffsetFromPageCorner) / scale;
|
255
258
|
|
256
|
-
const position = { x: px2mm(Math.max(0, moveX)), y: px2mm(Math.max(0, moveY)) }
|
259
|
+
const position = { x: round(px2mm(Math.max(0, moveX)), 2), y: round(px2mm(Math.max(0, moveY)), 2) }
|
257
260
|
|
258
261
|
addSchema({ ...(active.data.current as Schema), position });
|
259
262
|
}}
|
package/src/helper.ts
CHANGED
@@ -448,7 +448,7 @@ const handleTypeChange = (
|
|
448
448
|
pluginsRegistry: Plugins
|
449
449
|
) => {
|
450
450
|
if (key !== 'type') return;
|
451
|
-
const keysToKeep = ['id', 'key', 'type', 'position'];
|
451
|
+
const keysToKeep = ['id', 'key', 'type', 'position', 'required'];
|
452
452
|
Object.keys(schema).forEach((key) => {
|
453
453
|
if (!keysToKeep.includes(key)) {
|
454
454
|
delete schema[key as keyof typeof schema];
|
@@ -463,6 +463,9 @@ const handleTypeChange = (
|
|
463
463
|
(schema as any)[key] = propPanel?.defaultSchema[key];
|
464
464
|
}
|
465
465
|
});
|
466
|
+
if (schema.readOnly) {
|
467
|
+
schema.required = false;
|
468
|
+
}
|
466
469
|
};
|
467
470
|
|
468
471
|
export const changeSchemas = (args: {
|
@@ -489,4 +492,4 @@ export const changeSchemas = (args: {
|
|
489
492
|
return acc;
|
490
493
|
}, cloneDeep(schemas));
|
491
494
|
commitSchemas(newSchemas);
|
492
|
-
};
|
495
|
+
};
|