@pdfme/ui 3.0.1 → 3.1.0-dev.1
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/__mocks__/assetsTransformer.js +7 -0
- package/__mocks__/pdfjs-dist.js +15 -0
- package/dist/__vite-browser-external-jWVCDlBL.js +4 -0
- package/dist/index.js +1115 -3
- package/dist/path2d-polyfill.esm-yIGK7UQJ.js +214 -0
- package/dist/style.css +1 -0
- package/dist/types/class.d.ts +3 -3
- package/dist/types/components/AppContextProvider.d.ts +11 -0
- package/dist/types/components/{CtlBar/index.d.ts → CtlBar.d.ts} +2 -2
- package/dist/types/components/Designer/Canvas/Selecto.d.ts +3 -2
- package/dist/types/components/Designer/Sidebar/DetailView/AlignWidget.d.ts +1 -1
- package/dist/types/components/Designer/Sidebar/ListView/SelectableSortableContainer.d.ts +1 -1
- package/dist/types/components/Renderer.d.ts +1 -1
- package/dist/types/components/UnitPager.d.ts +1 -1
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/contexts.d.ts +46 -4
- package/dist/types/helper.d.ts +2 -1
- package/dist/types/hooks.d.ts +19 -2
- package/dist/types/i18n.d.ts +3 -27
- package/dist/types/theme.d.ts +2 -0
- package/package.json +17 -11
- package/src/Designer.tsx +27 -53
- package/src/Form.tsx +22 -23
- package/src/Viewer.tsx +10 -11
- package/src/class.ts +5 -5
- package/src/components/AppContextProvider.tsx +63 -0
- package/src/components/CtlBar.tsx +125 -0
- package/src/components/Designer/Canvas/Guides.tsx +18 -23
- package/src/components/Designer/Canvas/Mask.tsx +2 -1
- package/src/components/Designer/Canvas/Moveable.tsx +60 -60
- package/src/components/Designer/Canvas/Selecto.tsx +33 -20
- package/src/components/Designer/Canvas/index.tsx +21 -15
- package/src/components/Designer/Sidebar/DetailView/AlignWidget.tsx +53 -89
- package/src/components/Designer/Sidebar/DetailView/index.tsx +41 -30
- package/src/components/Designer/Sidebar/ListView/Item.tsx +30 -19
- package/src/components/Designer/Sidebar/ListView/SelectableSortableContainer.tsx +9 -6
- package/src/components/Designer/Sidebar/ListView/SelectableSortableItem.tsx +4 -1
- package/src/components/Designer/Sidebar/ListView/index.tsx +76 -71
- package/src/components/Designer/Sidebar/index.tsx +25 -49
- package/src/components/Designer/index.tsx +24 -82
- package/src/components/ErrorScreen.tsx +13 -11
- package/src/components/Preview.tsx +5 -2
- package/src/components/Renderer.tsx +10 -6
- package/src/components/Root.tsx +2 -8
- package/src/components/Spinner.tsx +12 -31
- package/src/components/UnitPager.tsx +72 -55
- package/src/constants.ts +2 -0
- package/src/contexts.ts +4 -5
- package/src/helper.ts +8 -5
- package/src/hooks.ts +136 -3
- package/src/i18n.ts +168 -59
- package/src/theme.ts +20 -0
- package/tsconfig.json +35 -13
- package/vite.config.ts +27 -0
- package/dist/index.js.LICENSE.txt +0 -142
- package/dist/index.js.map +0 -1
- package/dist/types/components/CtlBar/Pager.d.ts +0 -8
- package/dist/types/components/CtlBar/Zoom.d.ts +0 -7
- package/dist/types/components/Divider.d.ts +0 -3
- package/src/components/CtlBar/Pager.tsx +0 -53
- package/src/components/CtlBar/Zoom.tsx +0 -56
- package/src/components/CtlBar/index.tsx +0 -46
- package/src/components/Divider.tsx +0 -7
- package/webpack.config.js +0 -40
@@ -1,29 +1,42 @@
|
|
1
|
-
import React from 'react';
|
1
|
+
import React, { useEffect } from 'react';
|
2
2
|
import Selecto, { OnDragStart as _OnDragStart, OnSelect as _OnSelect } from 'react-selecto';
|
3
3
|
import { SELECTABLE_CLASSNAME } from '../../../constants';
|
4
|
+
import { theme } from 'antd';
|
4
5
|
|
5
|
-
|
6
|
-
container,
|
7
|
-
continueSelect,
|
8
|
-
onDragStart,
|
9
|
-
onSelect,
|
10
|
-
}: {
|
6
|
+
type Props = {
|
11
7
|
container: HTMLElement | null;
|
12
8
|
continueSelect: boolean;
|
13
9
|
onDragStart: (e: _OnDragStart) => void;
|
14
10
|
onSelect: (e: _OnSelect) => void;
|
15
|
-
}
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
11
|
+
};
|
12
|
+
|
13
|
+
const className = 'pdfme-selecto';
|
14
|
+
|
15
|
+
const _Selecto = (props: Props) => {
|
16
|
+
const { token } = theme.useToken();
|
17
|
+
useEffect(() => {
|
18
|
+
const containerElement = document.querySelector('.' + className) as HTMLElement | null;
|
19
|
+
if (containerElement) {
|
20
|
+
containerElement.style.backgroundColor = token.colorPrimary;
|
21
|
+
containerElement.style.opacity = '0.75';
|
22
|
+
containerElement.style.borderColor = token.colorPrimaryBorder;
|
23
|
+
}
|
24
|
+
}, [props.container]);
|
25
|
+
|
26
|
+
return (
|
27
|
+
<Selecto
|
28
|
+
className={className}
|
29
|
+
selectFromInside={false}
|
30
|
+
selectByClick
|
31
|
+
preventDefault
|
32
|
+
hitRate={0}
|
33
|
+
selectableTargets={[`.${SELECTABLE_CLASSNAME}`]}
|
34
|
+
container={props.container}
|
35
|
+
continueSelect={props.continueSelect}
|
36
|
+
onDragStart={props.onDragStart}
|
37
|
+
onSelect={props.onSelect}
|
38
|
+
/>
|
39
|
+
);
|
40
|
+
};
|
28
41
|
|
29
42
|
export default _Selecto;
|
@@ -9,10 +9,11 @@ import React, {
|
|
9
9
|
forwardRef,
|
10
10
|
useCallback,
|
11
11
|
} from 'react';
|
12
|
+
import { theme, Button } from 'antd';
|
12
13
|
import { OnDrag, OnResize, OnClick, OnRotate } from 'react-moveable';
|
13
14
|
import { ZOOM, SchemaForUI, Size, ChangeSchemas } from '@pdfme/common';
|
14
15
|
import { PluginsRegistry } from '../../../contexts';
|
15
|
-
import {
|
16
|
+
import { CloseOutlined } from '@ant-design/icons';
|
16
17
|
import { RULER_HEIGHT, SIDEBAR_WIDTH } from '../../../constants';
|
17
18
|
import { usePrevious } from '../../../hooks';
|
18
19
|
import { uuid, round, flatten } from '../../../helper';
|
@@ -30,33 +31,33 @@ const isTopLeftResize = (d: string) => d === '-1,-1' || d === '-1,0' || d === '0
|
|
30
31
|
const normalizeRotate = (angle: number) => ((angle % 360) + 360) % 360;
|
31
32
|
|
32
33
|
const DeleteButton = ({ activeElements: aes }: { activeElements: HTMLElement[] }) => {
|
34
|
+
const { token } = theme.useToken();
|
35
|
+
|
36
|
+
const size = 26;
|
33
37
|
const top = Math.min(...aes.map(({ style }) => fmt4Num(style.top)));
|
34
38
|
const left = Math.max(...aes.map(({ style }) => fmt4Num(style.left) + fmt4Num(style.width))) + 10;
|
35
39
|
|
36
40
|
return (
|
37
|
-
<
|
41
|
+
<Button
|
38
42
|
id={DELETE_BTN_ID}
|
39
43
|
style={{
|
40
44
|
position: 'absolute',
|
41
45
|
zIndex: 1,
|
42
46
|
top,
|
43
47
|
left,
|
48
|
+
width: size,
|
49
|
+
height: size,
|
44
50
|
padding: 2,
|
45
|
-
height: 24,
|
46
|
-
width: 24,
|
47
|
-
cursor: 'pointer',
|
48
|
-
color: 'white',
|
49
|
-
border: 'none',
|
50
|
-
fontWeight: 'bold',
|
51
|
-
borderRadius: 2,
|
52
|
-
background: 'rgb(68, 170, 255)',
|
53
51
|
display: 'flex',
|
54
52
|
alignItems: 'center',
|
55
53
|
justifyContent: 'center',
|
54
|
+
borderRadius: token.borderRadius,
|
55
|
+
color: token.colorWhite,
|
56
|
+
background: token.colorPrimary,
|
56
57
|
}}
|
57
58
|
>
|
58
|
-
<
|
59
|
-
</
|
59
|
+
<CloseOutlined style={{ pointerEvents: 'none' }} />
|
60
|
+
</Button>
|
60
61
|
);
|
61
62
|
};
|
62
63
|
|
@@ -103,6 +104,7 @@ const Canvas = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
103
104
|
paperRefs,
|
104
105
|
sidebarOpen,
|
105
106
|
} = props;
|
107
|
+
const { token } = theme.useToken();
|
106
108
|
const pluginsRegistry = useContext(PluginsRegistry);
|
107
109
|
|
108
110
|
const verticalGuides = useRef<GuidesInterface[]>([]);
|
@@ -258,10 +260,12 @@ const Canvas = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
258
260
|
);
|
259
261
|
const schemaTypes = selectedSchemas.map((s) => s.type);
|
260
262
|
const uniqueSchemaTypes = [...new Set(schemaTypes)];
|
261
|
-
const defaultSchemas = Object.values(pluginsRegistry).map(
|
263
|
+
const defaultSchemas = Object.values(pluginsRegistry).map(
|
264
|
+
(plugin) => plugin?.propPanel.defaultSchema
|
265
|
+
);
|
262
266
|
|
263
267
|
return uniqueSchemaTypes.every(
|
264
|
-
(type) => defaultSchemas.find(ds => ds.type === type)?.rotate !== undefined
|
268
|
+
(type) => defaultSchemas.find((ds) => ds.type === type)?.rotate !== undefined
|
265
269
|
);
|
266
270
|
}, [activeElements, pageCursor, schemasList, pluginsRegistry]);
|
267
271
|
|
@@ -378,7 +382,9 @@ const Canvas = (props: Props, ref: Ref<HTMLDivElement>) => {
|
|
378
382
|
changeSchemas([{ key: 'data', value, schemaId: schema.id }]);
|
379
383
|
}}
|
380
384
|
stopEditing={() => setEditing(false)}
|
381
|
-
outline={hoveringSchemaId === schema.id ? '
|
385
|
+
outline={`1px ${hoveringSchemaId === schema.id ? 'solid' : 'dashed'} ${
|
386
|
+
token.colorPrimary
|
387
|
+
}`}
|
382
388
|
scale={scale}
|
383
389
|
/>
|
384
390
|
)}
|
@@ -13,12 +13,21 @@ const svgBaseProp = {
|
|
13
13
|
fill: '#000000',
|
14
14
|
};
|
15
15
|
|
16
|
-
const
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
const createSvgIcon = (path: JSX.Element) => (
|
17
|
+
<svg {...svgBaseProp}>
|
18
|
+
<rect fill="none" height="24" width="24" />
|
19
|
+
{path}
|
20
|
+
</svg>
|
21
|
+
);
|
22
|
+
|
23
|
+
const createButtonConfig = (id: string, path: JSX.Element, onClick: () => void) => ({
|
24
|
+
id,
|
25
|
+
icon: createSvgIcon(path),
|
26
|
+
onClick,
|
27
|
+
});
|
28
|
+
|
29
|
+
const AlignWidget = (props: PropPanelWidgetProps) => {
|
30
|
+
const { activeElements, changeSchemas, schemas, pageSize, schema } = props;
|
22
31
|
const align = (type: 'left' | 'center' | 'right' | 'top' | 'middle' | 'bottom') => {
|
23
32
|
const ids = activeElements.map((ae) => ae.id);
|
24
33
|
const ass = schemas.filter((s) => ids.includes(s.id));
|
@@ -79,92 +88,47 @@ const AlignWidget = ({
|
|
79
88
|
})
|
80
89
|
);
|
81
90
|
};
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
<path d="M22,2v2H2V2H22z M7,22h3V6H7V22z M14,16h3V6h-3V16z" />
|
120
|
-
</svg>
|
121
|
-
),
|
122
|
-
onClick: () => align('top'),
|
123
|
-
},
|
124
|
-
{
|
125
|
-
id: 'middle',
|
126
|
-
icon: (
|
127
|
-
<svg {...svgBaseProp}>
|
128
|
-
<rect fill="none" height="24" width="24" />
|
129
|
-
<polygon points="22,11 17,11 17,6 14,6 14,11 10,11 10,3 7,3 7,11 1.84,11 1.84,13 7,13 7,21 10,21 10,13 14,13 14,18 17,18 17,13 22,13" />
|
130
|
-
</svg>
|
131
|
-
),
|
132
|
-
onClick: () => align('middle'),
|
133
|
-
},
|
134
|
-
{
|
135
|
-
id: 'bottom',
|
136
|
-
icon: (
|
137
|
-
<svg {...svgBaseProp}>
|
138
|
-
<rect fill="none" height="24" width="24" />
|
139
|
-
<path d="M22,22H2v-2h20V22z M10,2H7v16h3V2z M17,8h-3v10h3V8z" />
|
140
|
-
</svg>
|
141
|
-
),
|
142
|
-
onClick: () => align('bottom'),
|
143
|
-
},
|
144
|
-
{
|
145
|
-
id: 'vertical',
|
146
|
-
icon: (
|
147
|
-
<svg {...svgBaseProp}>
|
148
|
-
<rect fill="none" height="24" width="24" />
|
149
|
-
<path d="M22,2v2H2V2H22z M7,10.5v3h10v-3H7z M2,20v2h20v-2H2z" />
|
150
|
-
</svg>
|
151
|
-
),
|
152
|
-
onClick: () => distribute('vertical'),
|
153
|
-
},
|
154
|
-
{
|
155
|
-
id: 'horizontal',
|
156
|
-
icon: (
|
157
|
-
<svg {...svgBaseProp}>
|
158
|
-
<rect fill="none" height="24" width="24" />
|
159
|
-
<path d="M4,22H2V2h2V22z M22,2h-2v20h2V2z M13.5,7h-3v10h3V7z" />
|
160
|
-
</svg>
|
161
|
-
),
|
162
|
-
onClick: () => distribute('horizontal'),
|
163
|
-
},
|
91
|
+
const layoutBtns = [
|
92
|
+
createButtonConfig('left', <path d="M4,22H2V2h2V22z M22,7H6v3h16V7z M16,14H6v3h10V14z" />, () =>
|
93
|
+
align('left')
|
94
|
+
),
|
95
|
+
createButtonConfig(
|
96
|
+
'center',
|
97
|
+
<polygon points="11,2 13,2 13,7 21,7 21,10 13,10 13,14 18,14 18,17 13,17 13,22 11,22 11,17 6,17 6,14 11,14 11,10 3,10 3,7 11,7" />,
|
98
|
+
() => align('center')
|
99
|
+
),
|
100
|
+
createButtonConfig(
|
101
|
+
'right',
|
102
|
+
<path d="M20,2h2v20h-2V2z M2,10h16V7H2V10z M8,17h10v-3H8V17z" />,
|
103
|
+
() => align('right')
|
104
|
+
),
|
105
|
+
createButtonConfig('top', <path d="M22,2v2H2V2H22z M7,22h3V6H7V22z M14,16h3V6h-3V16z" />, () =>
|
106
|
+
align('top')
|
107
|
+
),
|
108
|
+
createButtonConfig(
|
109
|
+
'middle',
|
110
|
+
<polygon points="22,11 17,11 17,6 14,6 14,11 10,11 10,3 7,3 7,11 1.84,11 1.84,13 7,13 7,21 10,21 10,13 14,13 14,18 17,18 17,13 22,13" />,
|
111
|
+
() => align('middle')
|
112
|
+
),
|
113
|
+
createButtonConfig(
|
114
|
+
'bottom',
|
115
|
+
<path d="M22,22H2v-2h20V22z M10,2H7v16h3V2z M17,8h-3v10h3V8z" />,
|
116
|
+
() => align('bottom')
|
117
|
+
),
|
118
|
+
createButtonConfig(
|
119
|
+
'vertical',
|
120
|
+
<path d="M22,2v2H2V2H22z M7,10.5v3h10v-3H7z M2,20v2h20v-2H2z" />,
|
121
|
+
() => distribute('vertical')
|
122
|
+
),
|
123
|
+
createButtonConfig(
|
124
|
+
'horizontal',
|
125
|
+
<path d="M4,22H2V2h2V22z M22,2h-2v20h2V2z M13.5,7h-3v10h3V7z" />,
|
126
|
+
() => distribute('horizontal')
|
127
|
+
),
|
164
128
|
];
|
165
129
|
|
166
130
|
return (
|
167
|
-
<Form.Item label=
|
131
|
+
<Form.Item label={schema.title}>
|
168
132
|
<Button.Group>
|
169
133
|
{layoutBtns.map((btn) => (
|
170
134
|
<Button
|
@@ -1,14 +1,16 @@
|
|
1
1
|
import FormRender, { useForm } from 'form-render';
|
2
2
|
import React, { useContext, useEffect, useState } from 'react';
|
3
|
-
import type { SchemaForUI, PropPanelWidgetProps, PropPanelSchema } from '@pdfme/common';
|
3
|
+
import type { Dict, SchemaForUI, PropPanelWidgetProps, PropPanelSchema } from '@pdfme/common';
|
4
4
|
import type { SidebarProps } from '../../../../types';
|
5
|
-
import {
|
5
|
+
import { MenuOutlined } from '@ant-design/icons';
|
6
6
|
import { I18nContext, PluginsRegistry, OptionsContext } from '../../../../contexts';
|
7
|
-
import {
|
8
|
-
import Divider from '
|
7
|
+
import { getSidebarContentHeight } from '../../../../helper';
|
8
|
+
import { theme, Typography, Button, Divider } from 'antd';
|
9
9
|
import AlignWidget from './AlignWidget';
|
10
10
|
import WidgetRenderer from './WidgetRenderer';
|
11
11
|
|
12
|
+
const { Text } = Typography;
|
13
|
+
|
12
14
|
const DetailView = (
|
13
15
|
props: Pick<
|
14
16
|
SidebarProps,
|
@@ -17,6 +19,8 @@ const DetailView = (
|
|
17
19
|
activeSchema: SchemaForUI;
|
18
20
|
}
|
19
21
|
) => {
|
22
|
+
const { token } = theme.useToken();
|
23
|
+
|
20
24
|
const { size, changeSchemas, deselectSchema, activeSchema, activeElements } = props;
|
21
25
|
const form = useForm();
|
22
26
|
|
@@ -31,18 +35,27 @@ const DetailView = (
|
|
31
35
|
useEffect(() => {
|
32
36
|
const newWidgets: typeof widgets = {
|
33
37
|
AlignWidget: (p) => <AlignWidget {...p} {...props} options={options} />,
|
34
|
-
Divider
|
38
|
+
Divider: () => (
|
39
|
+
<Divider style={{ marginTop: token.marginXS, marginBottom: token.marginXS }} />
|
40
|
+
),
|
35
41
|
};
|
36
42
|
for (const plugin of Object.values(pluginsRegistry)) {
|
37
43
|
const widgets = plugin?.propPanel.widgets || {};
|
38
44
|
Object.entries(widgets).forEach(([widgetKey, widgetValue]) => {
|
39
45
|
newWidgets[widgetKey] = (p) => (
|
40
|
-
<WidgetRenderer
|
46
|
+
<WidgetRenderer
|
47
|
+
{...p}
|
48
|
+
{...props}
|
49
|
+
options={options}
|
50
|
+
theme={token}
|
51
|
+
i18n={i18n as (key: keyof Dict | string) => string}
|
52
|
+
widget={widgetValue}
|
53
|
+
/>
|
41
54
|
);
|
42
55
|
});
|
43
56
|
}
|
44
57
|
setWidgets(newWidgets);
|
45
|
-
}, [activeSchema, activeElements, pluginsRegistry]);
|
58
|
+
}, [activeSchema, activeElements, pluginsRegistry, JSON.stringify(options)]);
|
46
59
|
|
47
60
|
useEffect(() => {
|
48
61
|
form.setValues({ ...activeSchema });
|
@@ -76,7 +89,7 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
76
89
|
column: 2,
|
77
90
|
properties: {
|
78
91
|
type: {
|
79
|
-
title: '
|
92
|
+
title: i18n('type'),
|
80
93
|
type: 'string',
|
81
94
|
widget: 'select',
|
82
95
|
props: {
|
@@ -86,9 +99,9 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
86
99
|
})),
|
87
100
|
},
|
88
101
|
},
|
89
|
-
key: { title: '
|
102
|
+
key: { title: i18n('fieldName'), type: 'string', widget: 'input' },
|
90
103
|
'-': { type: 'void', widget: 'Divider', cellSpan: 2 },
|
91
|
-
align: { title: '
|
104
|
+
align: { title: i18n('align'), type: 'void', widget: 'AlignWidget', cellSpan: 2 },
|
92
105
|
position: {
|
93
106
|
type: 'object',
|
94
107
|
widget: 'card',
|
@@ -97,10 +110,10 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
97
110
|
y: { title: 'Y', type: 'number', widget: 'inputNumber' },
|
98
111
|
},
|
99
112
|
},
|
100
|
-
width: { title: '
|
101
|
-
height: { title: '
|
113
|
+
width: { title: i18n('width'), type: 'number', widget: 'inputNumber', span: 8 },
|
114
|
+
height: { title: i18n('height'), type: 'number', widget: 'inputNumber', span: 8 },
|
102
115
|
rotate: {
|
103
|
-
title: '
|
116
|
+
title: i18n('rotate'),
|
104
117
|
type: 'number',
|
105
118
|
widget: 'inputNumber',
|
106
119
|
span: 8,
|
@@ -112,7 +125,13 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
112
125
|
};
|
113
126
|
|
114
127
|
if (typeof activePropPanelSchema === 'function') {
|
115
|
-
const apps =
|
128
|
+
const apps =
|
129
|
+
activePropPanelSchema({
|
130
|
+
...props,
|
131
|
+
options,
|
132
|
+
theme: token,
|
133
|
+
i18n: i18n as (key: keyof Dict | string) => string,
|
134
|
+
}) || {};
|
116
135
|
propPanelSchema.properties = {
|
117
136
|
...propPanelSchema.properties,
|
118
137
|
...(Object.keys(apps).length === 0
|
@@ -134,36 +153,28 @@ Check this document: https://pdfme.com/docs/custom-schemas`);
|
|
134
153
|
return (
|
135
154
|
<div>
|
136
155
|
<div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
|
137
|
-
<
|
156
|
+
<Button
|
138
157
|
style={{
|
139
158
|
position: 'absolute',
|
140
|
-
top: '0.85rem',
|
141
159
|
zIndex: 100,
|
142
|
-
border: 'none',
|
143
|
-
borderRadius: 2,
|
144
|
-
padding: '0.5rem',
|
145
|
-
cursor: 'pointer',
|
146
|
-
background: '#eee',
|
147
160
|
display: 'flex',
|
148
161
|
alignItems: 'center',
|
149
162
|
justifyContent: 'center',
|
150
|
-
maxWidth: 30,
|
151
|
-
maxHeight: 30,
|
152
163
|
}}
|
153
164
|
onClick={deselectSchema}
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
<span style={{ textAlign: 'center', width: '100%', fontWeight: 'bold' }}>
|
165
|
+
icon={<MenuOutlined />}
|
166
|
+
/>
|
167
|
+
<Text strong style={{ textAlign: 'center', width: '100%' }}>
|
158
168
|
{i18n('editField')}
|
159
|
-
</
|
169
|
+
</Text>
|
160
170
|
</div>
|
161
|
-
<Divider />
|
171
|
+
<Divider style={{ marginTop: token.marginXS, marginBottom: token.marginXS }} />
|
162
172
|
<div
|
163
173
|
style={{
|
164
|
-
height: size.height
|
174
|
+
height: getSidebarContentHeight(size.height),
|
165
175
|
overflowY: 'auto',
|
166
176
|
overflowX: 'hidden',
|
177
|
+
borderBottom: `1px solid ${token.colorSplit}`,
|
167
178
|
}}
|
168
179
|
>
|
169
180
|
<FormRender
|
@@ -1,7 +1,10 @@
|
|
1
1
|
import React, { useEffect, useContext } from 'react';
|
2
2
|
import { DraggableSyntheticListeners } from '@dnd-kit/core';
|
3
3
|
import { I18nContext } from '../../../../contexts';
|
4
|
-
import {
|
4
|
+
import { HolderOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
|
5
|
+
import { Button, Typography } from 'antd';
|
6
|
+
|
7
|
+
const { Text } = Typography;
|
5
8
|
|
6
9
|
interface Props {
|
7
10
|
value: React.ReactNode;
|
@@ -60,6 +63,7 @@ const Item = React.memo(
|
|
60
63
|
return (
|
61
64
|
<li
|
62
65
|
style={{
|
66
|
+
marginTop: 10,
|
63
67
|
transition,
|
64
68
|
transform: `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`,
|
65
69
|
}}
|
@@ -67,40 +71,47 @@ const Item = React.memo(
|
|
67
71
|
onMouseLeave={onMouseLeave}
|
68
72
|
ref={ref}
|
69
73
|
>
|
70
|
-
<div
|
71
|
-
|
74
|
+
<div
|
75
|
+
style={{
|
76
|
+
display: 'flex',
|
77
|
+
alignItems: 'center',
|
78
|
+
cursor: 'pointer',
|
79
|
+
...style,
|
80
|
+
}}
|
81
|
+
{...props}
|
82
|
+
onClick={() => onClick && onClick()}
|
83
|
+
>
|
84
|
+
<Button
|
72
85
|
{...listeners}
|
73
|
-
style={{ padding: '0.5rem', background: 'none', border: 'none', display: 'flex' }}
|
74
|
-
>
|
75
|
-
<object style={{ cursor: 'grab', marginTop: 6 }} width={15}>
|
76
|
-
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="16" height="16">
|
77
|
-
<path d="M10 13a1 1 0 100-2 1 1 0 000 2zm-4 0a1 1 0 100-2 1 1 0 000 2zm1-5a1 1 0 11-2 0 1 1 0 012 0zm3 1a1 1 0 100-2 1 1 0 000 2zm1-5a1 1 0 11-2 0 1 1 0 012 0zM6 5a1 1 0 100-2 1 1 0 000 2z"></path>
|
78
|
-
</svg>
|
79
|
-
</object>
|
80
|
-
</button>
|
81
|
-
<div
|
82
86
|
style={{
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
+
display: 'flex',
|
88
|
+
alignItems: 'center',
|
89
|
+
background: 'none',
|
90
|
+
boxShadow: 'none',
|
91
|
+
border: 'none',
|
92
|
+
paddingLeft: '0.25rem',
|
93
|
+
}}
|
94
|
+
icon={<HolderOutlined style={{ cursor: 'grab' }} />}
|
95
|
+
/>
|
96
|
+
<Text
|
97
|
+
style={{
|
87
98
|
overflow: 'hidden',
|
88
99
|
whiteSpace: 'nowrap',
|
89
100
|
textOverflow: 'ellipsis',
|
101
|
+
width: '100%',
|
90
102
|
}}
|
91
103
|
title={title || ''}
|
92
|
-
onClick={() => onClick && onClick()}
|
93
104
|
>
|
94
105
|
{status === undefined ? (
|
95
106
|
value
|
96
107
|
) : (
|
97
108
|
<span style={{ display: 'flex', alignItems: 'center' }}>
|
98
|
-
<
|
109
|
+
<ExclamationCircleOutlined width={15} style={{ marginRight: '0.5rem' }} />
|
99
110
|
{status === 'is-warning' ? i18n('noKeyName') : value}
|
100
111
|
{status === 'is-danger' ? i18n('notUniq') : ''}
|
101
112
|
</span>
|
102
113
|
)}
|
103
|
-
</
|
114
|
+
</Text>
|
104
115
|
</div>
|
105
116
|
</li>
|
106
117
|
);
|
@@ -19,14 +19,17 @@ import { SchemaForUI } from '@pdfme/common';
|
|
19
19
|
import type { SidebarProps } from '../../../../types';
|
20
20
|
import Item from './Item';
|
21
21
|
import SelectableSortableItem from './SelectableSortableItem';
|
22
|
+
import { theme } from 'antd';
|
22
23
|
|
23
24
|
const SelectableSortableContainer = (
|
24
25
|
props: Pick<
|
25
26
|
SidebarProps,
|
26
|
-
'schemas' | 'onEdit' | 'onSortEnd' | '
|
27
|
+
'schemas' | 'onEdit' | 'onSortEnd' | 'hoveringSchemaId' | 'onChangeHoveringSchemaId'
|
27
28
|
>
|
28
29
|
) => {
|
29
|
-
const {
|
30
|
+
const { token } = theme.useToken();
|
31
|
+
|
32
|
+
const { schemas, onEdit, onSortEnd, hoveringSchemaId, onChangeHoveringSchemaId } = props;
|
30
33
|
const [selectedSchemas, setSelectedSchemas] = useState<SchemaForUI[]>([]);
|
31
34
|
const [dragOverlaydItems, setClonedItems] = useState<SchemaForUI[] | null>(null);
|
32
35
|
const [activeId, setActiveId] = useState<string | null>(null);
|
@@ -107,7 +110,7 @@ const SelectableSortableContainer = (
|
|
107
110
|
}}
|
108
111
|
>
|
109
112
|
<>
|
110
|
-
<div style={{ height, overflowY: 'auto' }}>
|
113
|
+
<div style={{ height: '100%', overflowY: 'auto' }}>
|
111
114
|
<SortableContext items={schemas} strategy={verticalListSortingStrategy}>
|
112
115
|
<ul style={{ margin: 0, padding: 0, listStyle: 'none', borderRadius: 5 }}>
|
113
116
|
{schemas.map((schema) => (
|
@@ -115,7 +118,7 @@ const SelectableSortableContainer = (
|
|
115
118
|
key={schema.id}
|
116
119
|
style={{
|
117
120
|
border: `1px solid ${
|
118
|
-
schema.id === hoveringSchemaId ?
|
121
|
+
schema.id === hoveringSchemaId ? token.colorPrimary : 'transparent'
|
119
122
|
}`,
|
120
123
|
}}
|
121
124
|
schema={schema}
|
@@ -137,7 +140,7 @@ const SelectableSortableContainer = (
|
|
137
140
|
<ul style={{ margin: 0, padding: 0, listStyle: 'none' }}>
|
138
141
|
<Item
|
139
142
|
value={schemas.find((schema) => schema.id === activeId)!.key}
|
140
|
-
style={{
|
143
|
+
style={{ background: token.colorPrimary }}
|
141
144
|
dragOverlay
|
142
145
|
/>
|
143
146
|
</ul>
|
@@ -148,7 +151,7 @@ const SelectableSortableContainer = (
|
|
148
151
|
<Item
|
149
152
|
key={item.id}
|
150
153
|
value={item.key}
|
151
|
-
style={{
|
154
|
+
style={{ background: token.colorPrimary }}
|
152
155
|
dragOverlay
|
153
156
|
/>
|
154
157
|
))}
|
@@ -4,6 +4,7 @@ import { SchemaForUI } from '@pdfme/common';
|
|
4
4
|
import { I18nContext } from '../../../../contexts';
|
5
5
|
import Item from './Item';
|
6
6
|
import { useMountStatus } from '../../../../hooks';
|
7
|
+
import { theme } from 'antd';
|
7
8
|
|
8
9
|
interface Props {
|
9
10
|
isSelected: boolean;
|
@@ -25,6 +26,8 @@ const SelectableSortableItem = ({
|
|
25
26
|
onMouseEnter,
|
26
27
|
onMouseLeave,
|
27
28
|
}: Props) => {
|
29
|
+
const { token } = theme.useToken();
|
30
|
+
|
28
31
|
const i18n = useContext(I18nContext);
|
29
32
|
const { setNodeRef, listeners, isDragging, isSorting, transform, transition } = useSortable({
|
30
33
|
id: schema.id,
|
@@ -52,7 +55,7 @@ const SelectableSortableItem = ({
|
|
52
55
|
}
|
53
56
|
|
54
57
|
const selectedStyle = isSelected
|
55
|
-
? {
|
58
|
+
? { background: token.colorPrimary, opacity: isSorting || isDragging ? 0.5 : 1 }
|
56
59
|
: ({} as React.CSSProperties);
|
57
60
|
|
58
61
|
return (
|