@pdfme/ui 1.0.0-beta.8 → 1.0.0-beta.9
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.js +1 -1
- package/dist/index.js.LICENSE.txt +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types/class.d.ts +1 -1
- package/dist/types/components/Designer/Sidebar/DetailView/ExampleInputEditor.d.ts +4 -1
- package/dist/types/components/Designer/Sidebar/DetailView/PositionAndSizeEditor.d.ts +4 -1
- package/dist/types/components/Designer/Sidebar/DetailView/TextPropEditor.d.ts +4 -1
- package/dist/types/components/Designer/Sidebar/DetailView/TypeAndKeyEditor.d.ts +4 -1
- package/dist/types/components/Designer/Sidebar/DetailView/index.d.ts +4 -1
- package/dist/types/components/Designer/Sidebar/ListView/Item.d.ts +25 -0
- package/dist/types/components/Designer/Sidebar/ListView/SelectableSortableContainer.d.ts +3 -0
- package/dist/types/components/Designer/Sidebar/ListView/SelectableSortableItem.d.ts +14 -0
- package/dist/types/components/Designer/Sidebar/ListView/index.d.ts +3 -0
- package/dist/types/components/Designer/Sidebar/index.d.ts +2 -7
- package/dist/types/contexts.d.ts +1 -1
- package/dist/types/helper.d.ts +1 -1
- package/dist/types/hooks.d.ts +1 -0
- package/dist/types/i18n.d.ts +5 -2
- package/package.json +4 -3
- package/src/assets/icons/align-horizontal-center.svg +1 -0
- package/src/assets/icons/align-horizontal-left.svg +1 -0
- package/src/assets/icons/align-horizontal-right.svg +1 -0
- package/src/assets/icons/align-vertical-bottom.svg +1 -0
- package/src/assets/icons/align-vertical-middle.svg +1 -0
- package/src/assets/icons/align-vertical-top.svg +1 -0
- package/src/assets/icons/horizontal-distribute.svg +1 -0
- package/src/assets/icons/vertical-distribute.svg +1 -0
- package/src/components/Designer/Main/index.tsx +15 -7
- package/src/components/Designer/Sidebar/DetailView/ExampleInputEditor.tsx +4 -1
- package/src/components/Designer/Sidebar/DetailView/PositionAndSizeEditor.tsx +107 -24
- package/src/components/Designer/Sidebar/DetailView/TextPropEditor.tsx +4 -1
- package/src/components/Designer/Sidebar/DetailView/TypeAndKeyEditor.tsx +2 -2
- package/src/components/Designer/Sidebar/DetailView/index.tsx +4 -1
- package/src/components/Designer/Sidebar/ListView/Item.tsx +113 -0
- package/src/components/Designer/Sidebar/ListView/SelectableSortableContainer.tsx +162 -0
- package/src/components/Designer/Sidebar/ListView/SelectableSortableItem.tsx +78 -0
- package/src/components/Designer/Sidebar/ListView/index.tsx +118 -0
- package/src/components/Designer/Sidebar/index.tsx +18 -6
- package/src/components/Designer/index.tsx +8 -22
- package/src/helper.ts +11 -10
- package/src/hooks.ts +11 -0
- package/src/i18n.ts +12 -7
- package/dist/types/components/Designer/Sidebar/ListView.d.ts +0 -3
- package/src/components/Designer/Sidebar/ListView.tsx +0 -202
@@ -0,0 +1,162 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import { createPortal } from 'react-dom';
|
3
|
+
import {
|
4
|
+
closestCorners,
|
5
|
+
DndContext,
|
6
|
+
DragOverlay,
|
7
|
+
KeyboardSensor,
|
8
|
+
PointerSensor,
|
9
|
+
useSensors,
|
10
|
+
useSensor,
|
11
|
+
} from '@dnd-kit/core';
|
12
|
+
import {
|
13
|
+
SortableContext,
|
14
|
+
arrayMove,
|
15
|
+
sortableKeyboardCoordinates,
|
16
|
+
verticalListSortingStrategy,
|
17
|
+
} from '@dnd-kit/sortable';
|
18
|
+
import { SchemaForUI } from '@pdfme/common';
|
19
|
+
import Item from './Item';
|
20
|
+
import SelectableSortableItem from './SelectableSortableItem';
|
21
|
+
import { SidebarProps } from '../';
|
22
|
+
|
23
|
+
const SelectableSortableContainer = (
|
24
|
+
props: Pick<
|
25
|
+
SidebarProps,
|
26
|
+
'schemas' | 'onEdit' | 'onSortEnd' | 'height' | 'hoveringSchemaId' | 'onChangeHoveringSchemaId'
|
27
|
+
>
|
28
|
+
) => {
|
29
|
+
const { schemas, onEdit, onSortEnd, height, hoveringSchemaId, onChangeHoveringSchemaId } = props;
|
30
|
+
const [selectedSchemas, setSelectedSchemas] = useState<SchemaForUI[]>([]);
|
31
|
+
const [dragOverlaydItems, setClonedItems] = useState<SchemaForUI[] | null>(null);
|
32
|
+
const [activeId, setActiveId] = useState<string | null>(null);
|
33
|
+
const sensors = useSensors(
|
34
|
+
useSensor(PointerSensor, { activationConstraint: { distance: 15 } }),
|
35
|
+
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
|
36
|
+
);
|
37
|
+
|
38
|
+
const isItemSelected = (itemId: string): boolean =>
|
39
|
+
selectedSchemas.map((i) => i.id).includes(itemId);
|
40
|
+
|
41
|
+
const onSelectionChanged = (id: string, isShiftSelect: boolean) => {
|
42
|
+
if (isShiftSelect) {
|
43
|
+
if (isItemSelected(id)) {
|
44
|
+
const newSelectedSchemas = selectedSchemas.filter((item) => item.id !== id);
|
45
|
+
setSelectedSchemas(newSelectedSchemas);
|
46
|
+
} else {
|
47
|
+
const newSelectedItem = schemas.find((schema) => schema.id === id)!;
|
48
|
+
const newSelectedSchemas = selectedSchemas.concat(newSelectedItem);
|
49
|
+
setSelectedSchemas(newSelectedSchemas);
|
50
|
+
}
|
51
|
+
} else {
|
52
|
+
setSelectedSchemas([]);
|
53
|
+
}
|
54
|
+
};
|
55
|
+
|
56
|
+
return (
|
57
|
+
<DndContext
|
58
|
+
sensors={sensors}
|
59
|
+
collisionDetection={closestCorners}
|
60
|
+
onDragStart={({ active }) => {
|
61
|
+
setActiveId(active.id);
|
62
|
+
setClonedItems(schemas);
|
63
|
+
|
64
|
+
if (!isItemSelected(active.id)) {
|
65
|
+
const newSelectedSchemas: SchemaForUI[] = [];
|
66
|
+
setSelectedSchemas(newSelectedSchemas);
|
67
|
+
} else if (selectedSchemas.length > 0) {
|
68
|
+
onSortEnd(
|
69
|
+
selectedSchemas.reduce((ret, selectedItem) => {
|
70
|
+
if (selectedItem.id === active.id) {
|
71
|
+
return ret;
|
72
|
+
}
|
73
|
+
return ret.filter((schema) => schema !== selectedItem);
|
74
|
+
}, schemas)
|
75
|
+
);
|
76
|
+
}
|
77
|
+
}}
|
78
|
+
onDragEnd={({ active, over }) => {
|
79
|
+
const overId = over?.id || '';
|
80
|
+
|
81
|
+
const activeIndex = schemas.map((i) => i.id).indexOf(active.id);
|
82
|
+
const overIndex = schemas.map((i) => i.id).indexOf(overId);
|
83
|
+
|
84
|
+
if (selectedSchemas.length) {
|
85
|
+
let newSchemas = [...schemas];
|
86
|
+
newSchemas = arrayMove(newSchemas, activeIndex, overIndex);
|
87
|
+
newSchemas.splice(
|
88
|
+
overIndex + 1,
|
89
|
+
0,
|
90
|
+
...selectedSchemas.filter((item) => item.id !== activeId)
|
91
|
+
);
|
92
|
+
onSortEnd(newSchemas);
|
93
|
+
setSelectedSchemas([]);
|
94
|
+
} else if (activeIndex !== overIndex) {
|
95
|
+
onSortEnd(arrayMove(schemas, activeIndex, overIndex));
|
96
|
+
}
|
97
|
+
|
98
|
+
setActiveId(null);
|
99
|
+
}}
|
100
|
+
onDragCancel={() => {
|
101
|
+
if (dragOverlaydItems) {
|
102
|
+
onSortEnd(dragOverlaydItems);
|
103
|
+
}
|
104
|
+
|
105
|
+
setActiveId(null);
|
106
|
+
setClonedItems(null);
|
107
|
+
}}
|
108
|
+
>
|
109
|
+
<div style={{ height, overflowY: 'auto' }}>
|
110
|
+
<SortableContext items={schemas} strategy={verticalListSortingStrategy}>
|
111
|
+
<ul style={{ margin: 0, padding: 0, listStyle: 'none', borderRadius: 5 }}>
|
112
|
+
{schemas.map((schema) => (
|
113
|
+
<SelectableSortableItem
|
114
|
+
key={schema.id}
|
115
|
+
style={{
|
116
|
+
border: `1px solid ${schema.id === hoveringSchemaId ? '#18a0fb' : 'transparent'}`,
|
117
|
+
}}
|
118
|
+
schema={schema}
|
119
|
+
schemas={schemas}
|
120
|
+
isSelected={isItemSelected(schema.id) || activeId === schema.id}
|
121
|
+
onEdit={onEdit}
|
122
|
+
onSelect={onSelectionChanged}
|
123
|
+
onMouseEnter={() => onChangeHoveringSchemaId(schema.id)}
|
124
|
+
onMouseLeave={() => onChangeHoveringSchemaId(null)}
|
125
|
+
/>
|
126
|
+
))}
|
127
|
+
</ul>
|
128
|
+
</SortableContext>
|
129
|
+
</div>
|
130
|
+
{createPortal(
|
131
|
+
<DragOverlay adjustScale>
|
132
|
+
{activeId ? (
|
133
|
+
<>
|
134
|
+
<ul style={{ margin: 0, padding: 0, listStyle: 'none' }}>
|
135
|
+
<Item
|
136
|
+
value={schemas.find((schema) => schema.id === activeId)!.key}
|
137
|
+
style={{ color: '#fff', background: '#18a0fb' }}
|
138
|
+
dragOverlay
|
139
|
+
/>
|
140
|
+
</ul>
|
141
|
+
<ul style={{ margin: 0, padding: 0, listStyle: 'none' }}>
|
142
|
+
{selectedSchemas
|
143
|
+
.filter((item) => item.id !== activeId)
|
144
|
+
.map((item) => (
|
145
|
+
<Item
|
146
|
+
key={item.id}
|
147
|
+
value={item.key}
|
148
|
+
style={{ color: '#fff', background: '#18a0fb' }}
|
149
|
+
dragOverlay
|
150
|
+
/>
|
151
|
+
))}
|
152
|
+
</ul>
|
153
|
+
</>
|
154
|
+
) : null}
|
155
|
+
</DragOverlay>,
|
156
|
+
document.body
|
157
|
+
)}
|
158
|
+
</DndContext>
|
159
|
+
);
|
160
|
+
};
|
161
|
+
|
162
|
+
export default SelectableSortableContainer;
|
@@ -0,0 +1,78 @@
|
|
1
|
+
import React, { useContext } from 'react';
|
2
|
+
import { useSortable } from '@dnd-kit/sortable';
|
3
|
+
import { SchemaForUI } from '@pdfme/common';
|
4
|
+
import { I18nContext } from '../../../../contexts';
|
5
|
+
import Item from './Item';
|
6
|
+
import { useMountStatus } from '../../../../hooks';
|
7
|
+
|
8
|
+
interface Props {
|
9
|
+
isSelected: boolean;
|
10
|
+
style?: React.CSSProperties;
|
11
|
+
onSelect: (id: string, isShiftSelect: boolean) => void;
|
12
|
+
onEdit: (id: string) => void;
|
13
|
+
schema: SchemaForUI;
|
14
|
+
schemas: SchemaForUI[];
|
15
|
+
onMouseEnter: () => void;
|
16
|
+
onMouseLeave: () => void;
|
17
|
+
}
|
18
|
+
const SelectableSortableItem = ({
|
19
|
+
isSelected,
|
20
|
+
style,
|
21
|
+
onSelect,
|
22
|
+
onEdit,
|
23
|
+
schema,
|
24
|
+
schemas,
|
25
|
+
onMouseEnter,
|
26
|
+
onMouseLeave,
|
27
|
+
}: Props) => {
|
28
|
+
const i18n = useContext(I18nContext);
|
29
|
+
const { setNodeRef, listeners, isDragging, isSorting, transform, transition } = useSortable({
|
30
|
+
id: schema.id,
|
31
|
+
});
|
32
|
+
const mounted = useMountStatus();
|
33
|
+
const mountedWhileDragging = isDragging && !mounted;
|
34
|
+
|
35
|
+
const newListeners = {
|
36
|
+
...listeners,
|
37
|
+
onClick: (event: any) => onSelect(schema.id, event.shiftKey),
|
38
|
+
};
|
39
|
+
|
40
|
+
let status: undefined | 'is-warning' | 'is-danger';
|
41
|
+
if (!schema.key) {
|
42
|
+
status = 'is-warning';
|
43
|
+
} else if (schemas.find((s) => schema.key && s.key === schema.key && s.id !== schema.id)) {
|
44
|
+
status = 'is-danger';
|
45
|
+
}
|
46
|
+
|
47
|
+
let title = i18n('edit');
|
48
|
+
if (status === 'is-warning') {
|
49
|
+
title = i18n('plsInputName');
|
50
|
+
} else if (status === 'is-danger') {
|
51
|
+
title = i18n('fieldMustUniq');
|
52
|
+
}
|
53
|
+
|
54
|
+
const selectedStyle = isSelected
|
55
|
+
? { color: '#fff', background: '#18a0fb', opacity: isSorting || isDragging ? 0.5 : 1 }
|
56
|
+
: ({} as React.CSSProperties);
|
57
|
+
|
58
|
+
return (
|
59
|
+
<Item
|
60
|
+
ref={setNodeRef}
|
61
|
+
onMouseEnter={onMouseEnter}
|
62
|
+
onMouseLeave={onMouseLeave}
|
63
|
+
onClick={() => onEdit(schema.id)}
|
64
|
+
value={schema.key}
|
65
|
+
status={status}
|
66
|
+
title={title}
|
67
|
+
style={{ ...selectedStyle, ...style }}
|
68
|
+
dragging={isDragging}
|
69
|
+
sorting={isSorting}
|
70
|
+
transition={transition}
|
71
|
+
transform={transform}
|
72
|
+
fadeIn={mountedWhileDragging}
|
73
|
+
listeners={newListeners}
|
74
|
+
/>
|
75
|
+
);
|
76
|
+
};
|
77
|
+
|
78
|
+
export default SelectableSortableItem;
|
@@ -0,0 +1,118 @@
|
|
1
|
+
import React, { useContext, useState } from 'react';
|
2
|
+
import { ZOOM, RULER_HEIGHT, SIDEBAR_WIDTH } from '../../../../constants';
|
3
|
+
import { I18nContext } from '../../../../contexts';
|
4
|
+
import Divider from '../../../Divider';
|
5
|
+
import SelectableSortableContainer from './SelectableSortableContainer';
|
6
|
+
import { SidebarProps } from '..';
|
7
|
+
|
8
|
+
const ListView = (
|
9
|
+
props: Pick<
|
10
|
+
SidebarProps,
|
11
|
+
| 'schemas'
|
12
|
+
| 'onSortEnd'
|
13
|
+
| 'onEdit'
|
14
|
+
| 'size'
|
15
|
+
| 'hoveringSchemaId'
|
16
|
+
| 'onChangeHoveringSchemaId'
|
17
|
+
| 'changeSchemas'
|
18
|
+
>
|
19
|
+
) => {
|
20
|
+
const {
|
21
|
+
schemas,
|
22
|
+
onSortEnd,
|
23
|
+
onEdit,
|
24
|
+
size,
|
25
|
+
hoveringSchemaId,
|
26
|
+
onChangeHoveringSchemaId,
|
27
|
+
changeSchemas,
|
28
|
+
} = props;
|
29
|
+
const i18n = useContext(I18nContext);
|
30
|
+
const [isBulkUpdateFieldNamesMode, setIsBulkUpdateFieldNamesMode] = useState(false);
|
31
|
+
const [fieldNamesValue, setFieldNamesValue] = useState('');
|
32
|
+
const height = size.height - RULER_HEIGHT * ZOOM - 135;
|
33
|
+
return (
|
34
|
+
<div>
|
35
|
+
<div style={{ height: 40, display: 'flex', alignItems: 'center' }}>
|
36
|
+
<p style={{ textAlign: 'center', width: '100%', fontWeight: 'bold' }}>
|
37
|
+
{i18n('fieldsList')}
|
38
|
+
</p>
|
39
|
+
</div>
|
40
|
+
<Divider />
|
41
|
+
{isBulkUpdateFieldNamesMode ? (
|
42
|
+
<div>
|
43
|
+
<textarea
|
44
|
+
wrap="off"
|
45
|
+
value={fieldNamesValue}
|
46
|
+
onChange={(e) => setFieldNamesValue(e.target.value)}
|
47
|
+
style={{
|
48
|
+
height: height - 5,
|
49
|
+
width: SIDEBAR_WIDTH,
|
50
|
+
fontSize: '1rem',
|
51
|
+
lineHeight: '2.25rem',
|
52
|
+
background: 'transparent',
|
53
|
+
margin: 0,
|
54
|
+
padding: 0,
|
55
|
+
fontFamily: 'inherit',
|
56
|
+
}}
|
57
|
+
></textarea>
|
58
|
+
</div>
|
59
|
+
) : (
|
60
|
+
<SelectableSortableContainer
|
61
|
+
height={height}
|
62
|
+
schemas={schemas}
|
63
|
+
hoveringSchemaId={hoveringSchemaId}
|
64
|
+
onChangeHoveringSchemaId={onChangeHoveringSchemaId}
|
65
|
+
onSortEnd={onSortEnd}
|
66
|
+
onEdit={onEdit}
|
67
|
+
/>
|
68
|
+
)}
|
69
|
+
|
70
|
+
<div
|
71
|
+
style={{
|
72
|
+
display: 'flex',
|
73
|
+
justifyContent: 'flex-end',
|
74
|
+
cursor: 'pointer',
|
75
|
+
fontSize: '0.75rem',
|
76
|
+
}}
|
77
|
+
>
|
78
|
+
{isBulkUpdateFieldNamesMode ? (
|
79
|
+
<>
|
80
|
+
<u
|
81
|
+
onClick={() => {
|
82
|
+
const names = fieldNamesValue.split('\n');
|
83
|
+
if (names.length !== schemas.length) {
|
84
|
+
alert(i18n('errorBulkUpdateFieldName'));
|
85
|
+
} else {
|
86
|
+
changeSchemas(
|
87
|
+
names.map((value, index) => ({
|
88
|
+
key: 'key',
|
89
|
+
value,
|
90
|
+
schemaId: schemas[index].id,
|
91
|
+
}))
|
92
|
+
);
|
93
|
+
setIsBulkUpdateFieldNamesMode(false);
|
94
|
+
}
|
95
|
+
}}
|
96
|
+
>
|
97
|
+
{i18n('commitBulkUpdateFieldName')}
|
98
|
+
</u>
|
99
|
+
<span style={{ margin: '0 1rem' }}>/</span>
|
100
|
+
<u onClick={() => setIsBulkUpdateFieldNamesMode(false)}>{i18n('cancel')}</u>
|
101
|
+
</>
|
102
|
+
) : (
|
103
|
+
<u
|
104
|
+
onClick={() => {
|
105
|
+
setFieldNamesValue(schemas.map((s) => s.key).join('\n'));
|
106
|
+
setIsBulkUpdateFieldNamesMode(true);
|
107
|
+
}}
|
108
|
+
>
|
109
|
+
{i18n('bulkUpdateFieldName')}
|
110
|
+
</u>
|
111
|
+
)}
|
112
|
+
</div>
|
113
|
+
<Divider />
|
114
|
+
</div>
|
115
|
+
);
|
116
|
+
};
|
117
|
+
|
118
|
+
export default ListView;
|
@@ -8,16 +8,14 @@ import ListView from './ListView';
|
|
8
8
|
import DetailView from './DetailView';
|
9
9
|
|
10
10
|
export type SidebarProps = {
|
11
|
-
scale: number;
|
12
11
|
height: number;
|
13
12
|
hoveringSchemaId: string | null;
|
14
13
|
onChangeHoveringSchemaId: (id: string | null) => void;
|
15
14
|
size: Size;
|
16
15
|
pageSize: Size;
|
17
|
-
|
18
|
-
activeSchema: SchemaForUI;
|
16
|
+
activeElements: HTMLElement[];
|
19
17
|
schemas: SchemaForUI[];
|
20
|
-
onSortEnd: (
|
18
|
+
onSortEnd: (sortedSchemas: SchemaForUI[]) => void;
|
21
19
|
onEdit: (id: string) => void;
|
22
20
|
onEditEnd: () => void;
|
23
21
|
changeSchemas: (objs: { key: string; value: string | number; schemaId: string }[]) => void;
|
@@ -25,12 +23,22 @@ export type SidebarProps = {
|
|
25
23
|
};
|
26
24
|
|
27
25
|
const Sidebar = (props: SidebarProps) => {
|
28
|
-
const { height, size, addSchema } = props;
|
26
|
+
const { height, size, activeElements, schemas, addSchema } = props;
|
29
27
|
|
30
28
|
const i18n = useContext(I18nContext);
|
31
29
|
const [open, setOpen] = useState(true);
|
32
30
|
const top = 0;
|
33
31
|
|
32
|
+
const getActiveSchemas = () => {
|
33
|
+
const ids = activeElements.map((ae) => ae.id);
|
34
|
+
return schemas.filter((s) => ids.includes(s.id));
|
35
|
+
};
|
36
|
+
|
37
|
+
const getLastActiveSchema = () => {
|
38
|
+
const activeSchemas = getActiveSchemas();
|
39
|
+
return activeSchemas[activeSchemas.length - 1];
|
40
|
+
};
|
41
|
+
|
34
42
|
return (
|
35
43
|
<div
|
36
44
|
style={{ position: 'absolute', right: 0, zIndex: 1, height, width: open ? SIDEBAR_WIDTH : 0 }}
|
@@ -69,7 +77,11 @@ const Sidebar = (props: SidebarProps) => {
|
|
69
77
|
fontWeight: 400,
|
70
78
|
}}
|
71
79
|
>
|
72
|
-
{
|
80
|
+
{getActiveSchemas().length === 0 ? (
|
81
|
+
<ListView {...props} />
|
82
|
+
) : (
|
83
|
+
<DetailView {...props} activeSchema={getLastActiveSchema()} />
|
84
|
+
)}
|
73
85
|
<div
|
74
86
|
style={{
|
75
87
|
display: 'flex',
|
@@ -7,7 +7,6 @@ import { I18nContext } from '../../contexts';
|
|
7
7
|
import {
|
8
8
|
uuid,
|
9
9
|
set,
|
10
|
-
arrayMove,
|
11
10
|
cloneDeep,
|
12
11
|
initShortCuts,
|
13
12
|
destroyShortCuts,
|
@@ -123,12 +122,12 @@ const TemplateEditor = ({
|
|
123
122
|
};
|
124
123
|
const timeTavel = (mode: 'undo' | 'redo') => {
|
125
124
|
const isUndo = mode === 'undo';
|
126
|
-
|
125
|
+
const stack = isUndo ? past : future;
|
126
|
+
if (stack.current.length <= 0) return;
|
127
127
|
(isUndo ? future : past).current.push(cloneDeep(schemasList[pageCursor]));
|
128
128
|
const s = cloneDeep(schemasList);
|
129
|
-
s[pageCursor] =
|
129
|
+
s[pageCursor] = stack.current.pop()!;
|
130
130
|
setSchemasList(s);
|
131
|
-
onEditEnd();
|
132
131
|
};
|
133
132
|
initShortCuts({
|
134
133
|
move: (command, isShift) => {
|
@@ -168,6 +167,7 @@ const TemplateEditor = ({
|
|
168
167
|
save: () => onSaveTemplate && onSaveTemplate(modifiedTemplate),
|
169
168
|
remove: () => removeSchemas(getActiveSchemas().map((s) => s.id)),
|
170
169
|
esc: onEditEnd,
|
170
|
+
selectAll: () => onEdit(schemasList[pageCursor].map((s) => document.getElementById(s.id)!)),
|
171
171
|
});
|
172
172
|
}, [
|
173
173
|
activeElements,
|
@@ -216,24 +216,14 @@ const TemplateEditor = ({
|
|
216
216
|
setTimeout(() => onEdit([document.getElementById(s.id)!]));
|
217
217
|
};
|
218
218
|
|
219
|
-
const onSortEnd = (
|
220
|
-
|
221
|
-
commitSchemas(movedSchema);
|
219
|
+
const onSortEnd = (sortedSchemas: SchemaForUI[]) => {
|
220
|
+
commitSchemas(sortedSchemas);
|
222
221
|
};
|
223
222
|
|
224
223
|
const onChangeHoveringSchemaId = (id: string | null) => {
|
225
224
|
setHoveringSchemaId(id);
|
226
225
|
};
|
227
226
|
|
228
|
-
const getLastActiveSchema = () => {
|
229
|
-
if (activeElements.length === 0) return getInitialSchema();
|
230
|
-
const last = activeElements[activeElements.length - 1];
|
231
|
-
|
232
|
-
return schemasList[pageCursor].find((s) => s.id === last.id) || getInitialSchema();
|
233
|
-
};
|
234
|
-
|
235
|
-
const activeSchema = getLastActiveSchema();
|
236
|
-
|
237
227
|
if (error) {
|
238
228
|
return <Error size={size} error={error} />;
|
239
229
|
}
|
@@ -241,22 +231,18 @@ const TemplateEditor = ({
|
|
241
231
|
return (
|
242
232
|
<Root ref={rootRef} size={size} scale={scale}>
|
243
233
|
<Sidebar
|
244
|
-
scale={scale}
|
245
234
|
hoveringSchemaId={hoveringSchemaId}
|
246
235
|
onChangeHoveringSchemaId={onChangeHoveringSchemaId}
|
247
236
|
height={mainRef.current ? mainRef.current.scrollHeight : 0}
|
248
237
|
size={size}
|
249
238
|
pageSize={pageSizes[pageCursor]}
|
250
|
-
|
239
|
+
activeElements={activeElements}
|
251
240
|
schemas={schemasList[pageCursor]}
|
252
|
-
activeSchema={activeSchema}
|
253
241
|
changeSchemas={changeSchemas}
|
254
242
|
onSortEnd={onSortEnd}
|
255
243
|
onEdit={(id: string) => {
|
256
244
|
const editingElem = document.getElementById(id);
|
257
|
-
|
258
|
-
onEdit([editingElem]);
|
259
|
-
}
|
245
|
+
editingElem && onEdit([editingElem]);
|
260
246
|
}}
|
261
247
|
onEditEnd={onEditEnd}
|
262
248
|
addSchema={addSchema}
|
package/src/helper.ts
CHANGED
@@ -61,15 +61,6 @@ export const round = (number: number, precision: number) => {
|
|
61
61
|
return shift(Math.round(shift(number, precision, false)), precision, true);
|
62
62
|
};
|
63
63
|
|
64
|
-
export const arrayMove = <T>(array: T[], from: number, to: number): T[] => {
|
65
|
-
array = array.slice();
|
66
|
-
const startIndex = to < 0 ? array.length + to : to;
|
67
|
-
const [item] = array.splice(from, 1);
|
68
|
-
array.splice(startIndex, 0, item);
|
69
|
-
|
70
|
-
return array;
|
71
|
-
};
|
72
|
-
|
73
64
|
export const cloneDeep = <T>(value: T): T => JSON.parse(JSON.stringify(value));
|
74
65
|
|
75
66
|
export const flatten = <T>(arr: T[][]): T[] => ([] as T[]).concat(...arr);
|
@@ -96,6 +87,8 @@ const undoWin = 'ctrl+z';
|
|
96
87
|
const undoMac = 'command+z';
|
97
88
|
const saveWin = 'ctrl+s';
|
98
89
|
const saveMac = 'command+s';
|
90
|
+
const selectAllWin = 'ctrl+a';
|
91
|
+
const selectAllMac = 'command+a';
|
99
92
|
|
100
93
|
const keys = [
|
101
94
|
up,
|
@@ -119,6 +112,8 @@ const keys = [
|
|
119
112
|
undoMac,
|
120
113
|
saveWin,
|
121
114
|
saveMac,
|
115
|
+
selectAllWin,
|
116
|
+
selectAllMac,
|
122
117
|
];
|
123
118
|
|
124
119
|
export const initShortCuts = (arg: {
|
@@ -130,6 +125,7 @@ export const initShortCuts = (arg: {
|
|
130
125
|
redo: () => void;
|
131
126
|
undo: () => void;
|
132
127
|
save: () => void;
|
128
|
+
selectAll: () => void;
|
133
129
|
}) => {
|
134
130
|
hotkeys(keys.join(), (e, handler) => {
|
135
131
|
switch (handler.shortcut) {
|
@@ -181,6 +177,11 @@ export const initShortCuts = (arg: {
|
|
181
177
|
e.preventDefault();
|
182
178
|
arg.save();
|
183
179
|
break;
|
180
|
+
case selectAllWin:
|
181
|
+
case selectAllMac:
|
182
|
+
e.preventDefault();
|
183
|
+
arg.selectAll();
|
184
|
+
break;
|
184
185
|
default:
|
185
186
|
break;
|
186
187
|
}
|
@@ -503,7 +504,7 @@ export const moveCommandToChangeSchemasArg = (props: {
|
|
503
504
|
break;
|
504
505
|
}
|
505
506
|
|
506
|
-
return value;
|
507
|
+
return value > 0 ? value : 0;
|
507
508
|
};
|
508
509
|
|
509
510
|
return activeSchemas.map((as) => {
|
package/src/hooks.ts
CHANGED
@@ -105,3 +105,14 @@ export const useScrollPageCursor = ({
|
|
105
105
|
};
|
106
106
|
}, [rootRef, onScroll]);
|
107
107
|
};
|
108
|
+
|
109
|
+
export const useMountStatus = () => {
|
110
|
+
const [isMounted, setIsMounted] = useState(false);
|
111
|
+
|
112
|
+
useEffect(() => {
|
113
|
+
const timeout = setTimeout(() => setIsMounted(true), 500);
|
114
|
+
return () => clearTimeout(timeout);
|
115
|
+
}, []);
|
116
|
+
|
117
|
+
return isMounted;
|
118
|
+
};
|
package/src/i18n.ts
CHANGED
@@ -4,6 +4,7 @@ import { DEFAULT_LANG } from './constants';
|
|
4
4
|
type DictEn = typeof dictEn;
|
5
5
|
|
6
6
|
const dictEn = {
|
7
|
+
cancel: 'Cancel',
|
7
8
|
field: 'field',
|
8
9
|
fieldName: 'Name',
|
9
10
|
require: 'Required',
|
@@ -20,17 +21,20 @@ const dictEn = {
|
|
20
21
|
addNewField: 'Add new field',
|
21
22
|
editField: 'Edit Field',
|
22
23
|
type: 'Type',
|
23
|
-
previewWarnMsg: 'Preview is not available on iOS devices.',
|
24
|
-
previewErrMsg:
|
25
|
-
'An error occurred during the PDF creation process. (Characters that are not in the Helvetica font are not available)',
|
26
24
|
goToFirst: 'Go to first',
|
27
25
|
goToPrevious: 'Back',
|
28
26
|
goToNext: 'Next',
|
29
27
|
goToEnd: 'Go to end',
|
30
|
-
|
28
|
+
select: 'Select',
|
29
|
+
errorOccurred: 'An error occurred',
|
30
|
+
errorBulkUpdateFieldName:
|
31
|
+
'Cannot commit the change because the number of items has been changed.',
|
32
|
+
commitBulkUpdateFieldName: 'Commit Changes',
|
33
|
+
bulkUpdateFieldName: 'Bulk update field names',
|
31
34
|
};
|
32
35
|
|
33
36
|
const dictJa: { [key in keyof DictEn]: string } = {
|
37
|
+
cancel: 'キャンセル',
|
34
38
|
field: '入力項目',
|
35
39
|
fieldName: '項目名',
|
36
40
|
require: '必須',
|
@@ -47,14 +51,15 @@ const dictJa: { [key in keyof DictEn]: string } = {
|
|
47
51
|
addNewField: '入力項目を追加',
|
48
52
|
editField: '入力項目を編集',
|
49
53
|
type: 'タイプ',
|
50
|
-
previewWarnMsg: 'iOS端末ではプレビューができません。',
|
51
|
-
previewErrMsg:
|
52
|
-
'PDF作成処理でエラーが発生しました。お手数ですがコンタクトからお問い合わせください。',
|
53
54
|
goToFirst: '最初に戻る',
|
54
55
|
goToPrevious: '1つ戻る',
|
55
56
|
goToNext: '1つ進む',
|
56
57
|
goToEnd: '最後に進む',
|
58
|
+
select: '選択',
|
57
59
|
errorOccurred: 'エラーが発生しました',
|
60
|
+
errorBulkUpdateFieldName: '項目数が変更されているため変更をコミットできません。',
|
61
|
+
commitBulkUpdateFieldName: '変更を反映',
|
62
|
+
bulkUpdateFieldName: '項目名を一括変更',
|
58
63
|
};
|
59
64
|
|
60
65
|
const i18n = (lang: Lang, key: keyof DictEn) => (lang === DEFAULT_LANG ? dictEn[key] : dictJa[key]);
|