@plone/volto 18.0.0-alpha.33 → 18.0.0-alpha.35
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/CHANGELOG.md +29 -0
- package/locales/ca/LC_MESSAGES/volto.po +5 -0
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +5 -0
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +5 -0
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +5 -0
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +5 -0
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +5 -0
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +5 -0
- package/locales/fr.json +1 -1
- package/locales/hi/LC_MESSAGES/volto.po +5 -0
- package/locales/hi.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +5 -0
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +5 -0
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +5 -0
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +5 -0
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +5 -0
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +5 -0
- package/locales/ro.json +1 -1
- package/locales/volto.pot +5 -0
- package/locales/zh_CN/LC_MESSAGES/volto.po +5 -0
- package/locales/zh_CN.json +1 -1
- package/package.json +8 -5
- package/razzle.config.js +20 -5
- package/src/actions/form/form.js +18 -2
- package/src/actions/index.js +1 -1
- package/src/components/manage/Blocks/Block/BlocksForm.jsx +157 -81
- package/src/components/manage/Blocks/Block/BlocksForm.test.jsx +8 -0
- package/src/components/manage/Blocks/Block/Edit.jsx +37 -4
- package/src/components/manage/Blocks/Block/Order/Item.jsx +122 -0
- package/src/components/manage/Blocks/Block/Order/Order.jsx +367 -0
- package/src/components/manage/Blocks/Block/Order/SortableItem.jsx +58 -0
- package/src/components/manage/Blocks/Block/Order/utilities.js +113 -0
- package/src/components/manage/Blocks/Container/Edit.jsx +1 -0
- package/src/components/manage/Blocks/Grid/Edit.jsx +6 -4
- package/src/components/manage/Blocks/Image/schema.js +2 -0
- package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +1 -1
- package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +1 -1
- package/src/components/manage/Form/Form.jsx +159 -151
- package/src/components/manage/Sidebar/Sidebar.jsx +28 -1
- package/src/components/manage/Widgets/InternalUrlWidget.jsx +10 -14
- package/src/components/theme/FormattedDate/FormattedDate.jsx +13 -1
- package/src/components/theme/Icon/Icon.jsx +4 -4
- package/src/config/Loadables.jsx +18 -0
- package/src/config/index.js +0 -1
- package/src/constants/ActionTypes.js +1 -0
- package/src/helpers/Blocks/Blocks.js +198 -4
- package/src/helpers/Blocks/Blocks.test.js +191 -0
- package/src/helpers/index.js +5 -0
- package/src/reducers/form/form.js +18 -1
- package/src/reducers/form/form.test.js +15 -1
- package/theme/themes/pastanaga/extras/blocks.less +7 -6
- package/theme/themes/pastanaga/extras/sidebar.less +145 -0
- package/types/actions/form/form.d.ts +8 -1
- package/types/actions/index.d.ts +1 -1
- package/types/components/manage/Blocks/Block/Order/Item.d.ts +2 -0
- package/types/components/manage/Blocks/Block/Order/Order.d.ts +13 -0
- package/types/components/manage/Blocks/Block/Order/SortableItem.d.ts +9 -0
- package/types/components/manage/Blocks/Block/Order/utilities.d.ts +9 -0
- package/types/components/manage/Blocks/Image/schema.d.ts +2 -0
- package/types/components/theme/Icon/Icon.d.ts +8 -8
- package/types/config/Loadables.d.ts +15 -162
- package/types/constants/ActionTypes.d.ts +1 -0
- package/types/helpers/Blocks/Blocks.d.ts +19 -0
- package/types/helpers/index.d.ts +3 -3
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
import { find, min } from 'lodash';
|
|
4
|
+
|
|
5
|
+
import { flattenTree, getProjection, removeChildrenOf } from './utilities';
|
|
6
|
+
import SortableItem from './SortableItem';
|
|
7
|
+
|
|
8
|
+
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
9
|
+
|
|
10
|
+
export function Order({
|
|
11
|
+
items = [],
|
|
12
|
+
onMoveBlock,
|
|
13
|
+
onDeleteBlock,
|
|
14
|
+
onSelectBlock,
|
|
15
|
+
indentationWidth = 25,
|
|
16
|
+
removable,
|
|
17
|
+
dndKitCore,
|
|
18
|
+
dndKitSortable,
|
|
19
|
+
dndKitUtilities,
|
|
20
|
+
}) {
|
|
21
|
+
const [activeId, setActiveId] = useState(null);
|
|
22
|
+
const [overId, setOverId] = useState(null);
|
|
23
|
+
const [offsetLeft, setOffsetLeft] = useState(0);
|
|
24
|
+
const [currentPosition, setCurrentPosition] = useState(null);
|
|
25
|
+
|
|
26
|
+
const {
|
|
27
|
+
DndContext,
|
|
28
|
+
closestCenter,
|
|
29
|
+
PointerSensor,
|
|
30
|
+
useSensor,
|
|
31
|
+
useSensors,
|
|
32
|
+
DragOverlay,
|
|
33
|
+
MeasuringStrategy,
|
|
34
|
+
defaultDropAnimation,
|
|
35
|
+
} = dndKitCore;
|
|
36
|
+
const { SortableContext, arrayMove, verticalListSortingStrategy } =
|
|
37
|
+
dndKitSortable;
|
|
38
|
+
const { CSS } = dndKitUtilities;
|
|
39
|
+
|
|
40
|
+
const measuring = {
|
|
41
|
+
droppable: {
|
|
42
|
+
strategy: MeasuringStrategy.Always,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const dropAnimationConfig = {
|
|
47
|
+
keyframes({ transform }) {
|
|
48
|
+
return [
|
|
49
|
+
{ opacity: 1, transform: CSS.Transform.toString(transform.initial) },
|
|
50
|
+
{
|
|
51
|
+
opacity: 0,
|
|
52
|
+
transform: CSS.Transform.toString({
|
|
53
|
+
...transform.final,
|
|
54
|
+
x: transform.final.x + 5,
|
|
55
|
+
y: transform.final.y + 5,
|
|
56
|
+
}),
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
},
|
|
60
|
+
easing: 'ease-out',
|
|
61
|
+
sideEffects({ active }) {
|
|
62
|
+
active.node.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
63
|
+
duration: defaultDropAnimation.duration,
|
|
64
|
+
easing: defaultDropAnimation.easing,
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const flattenedItems = useMemo(
|
|
70
|
+
() => removeChildrenOf(flattenTree(items), activeId ? [activeId] : []),
|
|
71
|
+
[activeId, items],
|
|
72
|
+
);
|
|
73
|
+
const projected =
|
|
74
|
+
activeId && overId
|
|
75
|
+
? getProjection(
|
|
76
|
+
flattenedItems,
|
|
77
|
+
activeId,
|
|
78
|
+
overId,
|
|
79
|
+
offsetLeft,
|
|
80
|
+
indentationWidth,
|
|
81
|
+
arrayMove,
|
|
82
|
+
)
|
|
83
|
+
: null;
|
|
84
|
+
const sensorContext = useRef({
|
|
85
|
+
items: flattenedItems,
|
|
86
|
+
offset: offsetLeft,
|
|
87
|
+
});
|
|
88
|
+
const sensors = useSensors(useSensor(PointerSensor));
|
|
89
|
+
|
|
90
|
+
const sortedIds = useMemo(
|
|
91
|
+
() => flattenedItems.map(({ id }) => id),
|
|
92
|
+
[flattenedItems],
|
|
93
|
+
);
|
|
94
|
+
const activeItem = activeId
|
|
95
|
+
? flattenedItems.find(({ id }) => id === activeId)
|
|
96
|
+
: null;
|
|
97
|
+
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
sensorContext.current = {
|
|
100
|
+
items: flattenedItems,
|
|
101
|
+
offset: offsetLeft,
|
|
102
|
+
};
|
|
103
|
+
}, [flattenedItems, offsetLeft]);
|
|
104
|
+
|
|
105
|
+
const announcements = {
|
|
106
|
+
onDragStart({ active }) {
|
|
107
|
+
return `Picked up ${active.id}.`;
|
|
108
|
+
},
|
|
109
|
+
onDragMove({ active, over }) {
|
|
110
|
+
return getMovementAnnouncement('onDragMove', active.id, over?.id);
|
|
111
|
+
},
|
|
112
|
+
onDragOver({ active, over }) {
|
|
113
|
+
return getMovementAnnouncement('onDragOver', active.id, over?.id);
|
|
114
|
+
},
|
|
115
|
+
onDragEnd({ active, over }) {
|
|
116
|
+
return getMovementAnnouncement('onDragEnd', active.id, over?.id);
|
|
117
|
+
},
|
|
118
|
+
onDragCancel({ active }) {
|
|
119
|
+
return `Moving was cancelled. ${active.id} was dropped in its original position.`;
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<DndContext
|
|
125
|
+
accessibility={{ announcements }}
|
|
126
|
+
sensors={sensors}
|
|
127
|
+
collisionDetection={closestCenter}
|
|
128
|
+
measuring={measuring}
|
|
129
|
+
onDragStart={handleDragStart}
|
|
130
|
+
onDragMove={handleDragMove}
|
|
131
|
+
onDragOver={handleDragOver}
|
|
132
|
+
onDragEnd={handleDragEnd}
|
|
133
|
+
onDragCancel={handleDragCancel}
|
|
134
|
+
>
|
|
135
|
+
<SortableContext items={sortedIds} strategy={verticalListSortingStrategy}>
|
|
136
|
+
{flattenedItems.map(({ id, parentId, depth, data }) => (
|
|
137
|
+
<SortableItem
|
|
138
|
+
key={id}
|
|
139
|
+
id={id}
|
|
140
|
+
parentId={parentId}
|
|
141
|
+
data={data}
|
|
142
|
+
depth={min([
|
|
143
|
+
id === activeId && projected ? projected.depth : depth,
|
|
144
|
+
1,
|
|
145
|
+
])}
|
|
146
|
+
indentationWidth={indentationWidth}
|
|
147
|
+
onRemove={removable ? () => handleRemove(id) : undefined}
|
|
148
|
+
onSelectBlock={onSelectBlock}
|
|
149
|
+
/>
|
|
150
|
+
))}
|
|
151
|
+
{createPortal(
|
|
152
|
+
<DragOverlay dropAnimation={dropAnimationConfig}>
|
|
153
|
+
{activeId && activeItem ? (
|
|
154
|
+
<SortableItem
|
|
155
|
+
id={activeId}
|
|
156
|
+
depth={activeItem.depth}
|
|
157
|
+
clone
|
|
158
|
+
data={find(flattenedItems, { id: activeId }).data}
|
|
159
|
+
indentationWidth={indentationWidth}
|
|
160
|
+
/>
|
|
161
|
+
) : null}
|
|
162
|
+
</DragOverlay>,
|
|
163
|
+
document.body,
|
|
164
|
+
)}
|
|
165
|
+
</SortableContext>
|
|
166
|
+
</DndContext>
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
function handleDragStart({ active: { id: activeId } }) {
|
|
170
|
+
setActiveId(activeId);
|
|
171
|
+
setOverId(activeId);
|
|
172
|
+
|
|
173
|
+
const activeItem = flattenedItems.find(({ id }) => id === activeId);
|
|
174
|
+
|
|
175
|
+
if (activeItem) {
|
|
176
|
+
setCurrentPosition({
|
|
177
|
+
parentId: activeItem.parentId,
|
|
178
|
+
overId: activeId,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
document.body.style.setProperty('cursor', 'grabbing');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function handleDragMove({ delta }) {
|
|
186
|
+
setOffsetLeft(delta.x);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function handleDragOver({ over }) {
|
|
190
|
+
setOverId(over?.id ?? null);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function handleDragEnd({ active, over }) {
|
|
194
|
+
if (projected && over) {
|
|
195
|
+
const { depth, parentId } = projected;
|
|
196
|
+
const clonedItems = JSON.parse(JSON.stringify(flattenedItems));
|
|
197
|
+
const overIndex = clonedItems.findIndex(({ id }) => id === over.id);
|
|
198
|
+
const activeIndex = clonedItems.findIndex(({ id }) => id === active.id);
|
|
199
|
+
const activeTreeItem = clonedItems[activeIndex];
|
|
200
|
+
const oldParentId = activeTreeItem.parentId;
|
|
201
|
+
|
|
202
|
+
clonedItems[activeIndex] = { ...activeTreeItem, depth, parentId };
|
|
203
|
+
|
|
204
|
+
// Translate position depending on parent
|
|
205
|
+
if (parentId === oldParentId) {
|
|
206
|
+
// Move from and to toplevel or move within the same grid block
|
|
207
|
+
|
|
208
|
+
let destIndex = clonedItems[overIndex].index;
|
|
209
|
+
if (clonedItems[overIndex].depth > clonedItems[activeIndex].depth) {
|
|
210
|
+
destIndex = find(clonedItems, {
|
|
211
|
+
id: clonedItems[overIndex].parentId,
|
|
212
|
+
}).index;
|
|
213
|
+
}
|
|
214
|
+
onMoveBlock({
|
|
215
|
+
source: {
|
|
216
|
+
position: clonedItems[activeIndex].index,
|
|
217
|
+
parent: oldParentId,
|
|
218
|
+
id: active.id,
|
|
219
|
+
},
|
|
220
|
+
destination: {
|
|
221
|
+
position: destIndex,
|
|
222
|
+
parent: parentId,
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
} else if (parentId && oldParentId) {
|
|
226
|
+
// Move from one gridblock to another
|
|
227
|
+
|
|
228
|
+
onMoveBlock({
|
|
229
|
+
source: {
|
|
230
|
+
position: clonedItems[activeIndex].index,
|
|
231
|
+
parent: oldParentId,
|
|
232
|
+
id: active.id,
|
|
233
|
+
},
|
|
234
|
+
destination: {
|
|
235
|
+
position:
|
|
236
|
+
overIndex < activeIndex
|
|
237
|
+
? clonedItems[overIndex - 1].parentId
|
|
238
|
+
? clonedItems[overIndex - 1].index + 1
|
|
239
|
+
: clonedItems[overIndex].index
|
|
240
|
+
: overIndex + 1 < clonedItems.length
|
|
241
|
+
? clonedItems[overIndex + 1].index
|
|
242
|
+
: clonedItems[overIndex].index + 1,
|
|
243
|
+
parent: parentId,
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
} else if (oldParentId) {
|
|
247
|
+
// Moving to the main container from a gridblock
|
|
248
|
+
|
|
249
|
+
onMoveBlock({
|
|
250
|
+
source: {
|
|
251
|
+
position: clonedItems[activeIndex].index,
|
|
252
|
+
parent: oldParentId,
|
|
253
|
+
id: active.id,
|
|
254
|
+
},
|
|
255
|
+
destination: {
|
|
256
|
+
position:
|
|
257
|
+
overIndex > activeIndex
|
|
258
|
+
? overIndex + 1 < clonedItems.length
|
|
259
|
+
? clonedItems[overIndex + 1].index
|
|
260
|
+
: clonedItems[overIndex].index + 1
|
|
261
|
+
: clonedItems[overIndex].index,
|
|
262
|
+
parent: parentId,
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
} else {
|
|
266
|
+
// Moving from the main container to a gridblock
|
|
267
|
+
|
|
268
|
+
onMoveBlock({
|
|
269
|
+
source: {
|
|
270
|
+
position: clonedItems[activeIndex].index,
|
|
271
|
+
parent: oldParentId,
|
|
272
|
+
id: active.id,
|
|
273
|
+
},
|
|
274
|
+
destination: {
|
|
275
|
+
position:
|
|
276
|
+
overIndex < activeIndex
|
|
277
|
+
? clonedItems[overIndex - 1].parentId
|
|
278
|
+
? clonedItems[overIndex - 1].index + 1
|
|
279
|
+
: clonedItems[overIndex].index
|
|
280
|
+
: overIndex + 1 < clonedItems.length
|
|
281
|
+
? clonedItems[overIndex + 1].index
|
|
282
|
+
: clonedItems[overIndex].index + 1,
|
|
283
|
+
parent: parentId,
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
resetState();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function handleDragCancel() {
|
|
293
|
+
resetState();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function resetState() {
|
|
297
|
+
setOverId(null);
|
|
298
|
+
setActiveId(null);
|
|
299
|
+
setOffsetLeft(0);
|
|
300
|
+
setCurrentPosition(null);
|
|
301
|
+
|
|
302
|
+
document.body.style.setProperty('cursor', '');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function handleRemove(id) {
|
|
306
|
+
onDeleteBlock(id);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function getMovementAnnouncement(eventName, activeId, overId) {
|
|
310
|
+
if (overId && projected) {
|
|
311
|
+
if (eventName !== 'onDragEnd') {
|
|
312
|
+
if (
|
|
313
|
+
currentPosition &&
|
|
314
|
+
projected.parentId === currentPosition.parentId &&
|
|
315
|
+
overId === currentPosition.overId
|
|
316
|
+
) {
|
|
317
|
+
return;
|
|
318
|
+
} else {
|
|
319
|
+
setCurrentPosition({
|
|
320
|
+
parentId: projected.parentId,
|
|
321
|
+
overId,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const clonedItems = JSON.parse(JSON.stringify(flattenTree(items)));
|
|
327
|
+
const overIndex = clonedItems.findIndex(({ id }) => id === overId);
|
|
328
|
+
const activeIndex = clonedItems.findIndex(({ id }) => id === activeId);
|
|
329
|
+
const sortedItems = arrayMove(clonedItems, activeIndex, overIndex);
|
|
330
|
+
|
|
331
|
+
const previousItem = sortedItems[overIndex - 1];
|
|
332
|
+
|
|
333
|
+
let announcement;
|
|
334
|
+
const movedVerb = eventName === 'onDragEnd' ? 'dropped' : 'moved';
|
|
335
|
+
const nestedVerb = eventName === 'onDragEnd' ? 'dropped' : 'nested';
|
|
336
|
+
|
|
337
|
+
if (!previousItem) {
|
|
338
|
+
const nextItem = sortedItems[overIndex + 1];
|
|
339
|
+
announcement = `${activeId} was ${movedVerb} before ${nextItem.id}.`;
|
|
340
|
+
} else {
|
|
341
|
+
if (projected.depth > previousItem.depth) {
|
|
342
|
+
announcement = `${activeId} was ${nestedVerb} under ${previousItem.id}.`;
|
|
343
|
+
} else {
|
|
344
|
+
let previousSibling = previousItem;
|
|
345
|
+
while (previousSibling && projected.depth < previousSibling.depth) {
|
|
346
|
+
const parentId = previousSibling.parentId;
|
|
347
|
+
previousSibling = sortedItems.find(({ id }) => id === parentId);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (previousSibling) {
|
|
351
|
+
announcement = `${activeId} was ${movedVerb} after ${previousSibling.id}.`;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return announcement;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export default injectLazyLibs([
|
|
364
|
+
'dndKitCore',
|
|
365
|
+
'dndKitSortable',
|
|
366
|
+
'dndKitUtilities',
|
|
367
|
+
])(Order);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
4
|
+
|
|
5
|
+
import { Item } from './Item';
|
|
6
|
+
|
|
7
|
+
const animateLayoutChanges = ({ isSorting, wasDragging }) =>
|
|
8
|
+
isSorting || wasDragging ? false : true;
|
|
9
|
+
|
|
10
|
+
export function SortableItem({
|
|
11
|
+
id,
|
|
12
|
+
depth,
|
|
13
|
+
dndKitSortable,
|
|
14
|
+
dndKitUtilities,
|
|
15
|
+
...props
|
|
16
|
+
}) {
|
|
17
|
+
const { useSortable } = dndKitSortable;
|
|
18
|
+
const { CSS } = dndKitUtilities;
|
|
19
|
+
const {
|
|
20
|
+
attributes,
|
|
21
|
+
isDragging,
|
|
22
|
+
isSorting,
|
|
23
|
+
listeners,
|
|
24
|
+
setDraggableNodeRef,
|
|
25
|
+
setDroppableNodeRef,
|
|
26
|
+
transform,
|
|
27
|
+
transition,
|
|
28
|
+
} = useSortable({
|
|
29
|
+
id,
|
|
30
|
+
animateLayoutChanges,
|
|
31
|
+
});
|
|
32
|
+
const style = {
|
|
33
|
+
transform: CSS.Translate.toString(transform),
|
|
34
|
+
transition,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Item
|
|
39
|
+
ref={setDraggableNodeRef}
|
|
40
|
+
wrapperRef={setDroppableNodeRef}
|
|
41
|
+
style={style}
|
|
42
|
+
depth={depth}
|
|
43
|
+
ghost={isDragging}
|
|
44
|
+
disableSelection={false}
|
|
45
|
+
disableInteraction={isSorting}
|
|
46
|
+
id={id}
|
|
47
|
+
handleProps={{
|
|
48
|
+
...attributes,
|
|
49
|
+
...listeners,
|
|
50
|
+
}}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default injectLazyLibs(['dndKitSortable', 'dndKitUtilities'])(
|
|
57
|
+
SortableItem,
|
|
58
|
+
);
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { isArray } from 'lodash';
|
|
2
|
+
|
|
3
|
+
import { getBlocksLayoutFieldname } from '@plone/volto/helpers';
|
|
4
|
+
|
|
5
|
+
function getDragDepth(offset, indentationWidth) {
|
|
6
|
+
return Math.round(offset / indentationWidth);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getProjection(
|
|
10
|
+
items,
|
|
11
|
+
activeId,
|
|
12
|
+
overId,
|
|
13
|
+
dragOffset,
|
|
14
|
+
indentationWidth,
|
|
15
|
+
arrayMove,
|
|
16
|
+
) {
|
|
17
|
+
const overItemIndex = items.findIndex(({ id }) => id === overId);
|
|
18
|
+
const activeItemIndex = items.findIndex(({ id }) => id === activeId);
|
|
19
|
+
const activeItem = items[activeItemIndex];
|
|
20
|
+
const newItems = arrayMove(items, activeItemIndex, overItemIndex);
|
|
21
|
+
const previousItem = newItems[overItemIndex - 1];
|
|
22
|
+
const nextItem = newItems[overItemIndex + 1];
|
|
23
|
+
const dragDepth = getDragDepth(dragOffset, indentationWidth);
|
|
24
|
+
const projectedDepth = activeItem.depth + dragDepth;
|
|
25
|
+
const maxDepth = getMaxDepth({
|
|
26
|
+
previousItem,
|
|
27
|
+
});
|
|
28
|
+
const minDepth = getMinDepth({ nextItem });
|
|
29
|
+
let depth = projectedDepth;
|
|
30
|
+
|
|
31
|
+
if (projectedDepth >= maxDepth) {
|
|
32
|
+
depth = maxDepth;
|
|
33
|
+
} else if (projectedDepth < minDepth) {
|
|
34
|
+
depth = minDepth;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return { depth, maxDepth, minDepth, parentId: getParentId() };
|
|
38
|
+
|
|
39
|
+
function getParentId() {
|
|
40
|
+
if (depth === 0 || !previousItem) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (depth <= previousItem.depth) {
|
|
45
|
+
return previousItem.parentId;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (depth > previousItem.depth) {
|
|
49
|
+
return previousItem.id;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const newParent = newItems
|
|
53
|
+
.slice(0, overItemIndex)
|
|
54
|
+
.reverse()
|
|
55
|
+
.find((item) => item.depth === depth)?.parentId;
|
|
56
|
+
|
|
57
|
+
return newParent ?? null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getMaxDepth({ previousItem }) {
|
|
62
|
+
const blocksLayoutFieldname = getBlocksLayoutFieldname(
|
|
63
|
+
previousItem?.data || {},
|
|
64
|
+
);
|
|
65
|
+
if (previousItem) {
|
|
66
|
+
return isArray(previousItem.data?.[blocksLayoutFieldname]?.items)
|
|
67
|
+
? previousItem.depth + 1
|
|
68
|
+
: previousItem.depth;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function getMinDepth({ nextItem }) {
|
|
75
|
+
if (nextItem) {
|
|
76
|
+
return nextItem.depth;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function flatten(items = [], parentId = null, depth = 0) {
|
|
83
|
+
return items.reduce((acc, item, index) => {
|
|
84
|
+
return [
|
|
85
|
+
...acc,
|
|
86
|
+
{ ...item, parentId, depth, index },
|
|
87
|
+
...flatten(item.children, item.id, depth + 1),
|
|
88
|
+
];
|
|
89
|
+
}, []);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function flattenTree(items) {
|
|
93
|
+
return flatten(items);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function findItem(items, itemId) {
|
|
97
|
+
return items.find(({ id }) => id === itemId);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function removeChildrenOf(items, ids) {
|
|
101
|
+
const excludeParentIds = [...ids];
|
|
102
|
+
|
|
103
|
+
return items.filter((item) => {
|
|
104
|
+
if (item.parentId && excludeParentIds.includes(item.parentId)) {
|
|
105
|
+
if (item.children.length) {
|
|
106
|
+
excludeParentIds.push(item.id);
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return true;
|
|
112
|
+
});
|
|
113
|
+
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import PropTypes from 'prop-types';
|
|
2
2
|
import cx from 'classnames';
|
|
3
|
-
import { useState } from 'react';
|
|
4
3
|
import ContainerEdit from '../Container/Edit';
|
|
4
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
5
|
+
import { setUIState } from '@plone/volto/actions';
|
|
5
6
|
|
|
6
7
|
const GridBlockEdit = (props) => {
|
|
7
8
|
const { data } = props;
|
|
8
9
|
|
|
9
10
|
const columnsLength = data?.blocks_layout?.items?.length || 0;
|
|
10
11
|
|
|
11
|
-
const
|
|
12
|
+
const selectedBlock = useSelector((state) => state.form.ui.gridSelected);
|
|
13
|
+
const dispatch = useDispatch();
|
|
12
14
|
|
|
13
15
|
return (
|
|
14
16
|
<div
|
|
@@ -22,14 +24,14 @@ const GridBlockEdit = (props) => {
|
|
|
22
24
|
// This is required to enabling a small "in-between" clickable area
|
|
23
25
|
// for bringing the Grid sidebar alive once you have selected an inner block
|
|
24
26
|
onClick={(e) => {
|
|
25
|
-
if (!e.block)
|
|
27
|
+
if (!e.block) dispatch(setUIState({ gridSelected: null }));
|
|
26
28
|
}}
|
|
27
29
|
role="presentation"
|
|
28
30
|
>
|
|
29
31
|
<ContainerEdit
|
|
30
32
|
{...props}
|
|
31
33
|
selectedBlock={selectedBlock}
|
|
32
|
-
setSelectedBlock={
|
|
34
|
+
setSelectedBlock={(id) => dispatch(setUIState({ gridSelected: id }))}
|
|
33
35
|
direction="horizontal"
|
|
34
36
|
/>
|
|
35
37
|
</div>
|
|
@@ -77,10 +77,12 @@ export function ImageSchema({ formData, intl }) {
|
|
|
77
77
|
align: {
|
|
78
78
|
title: intl.formatMessage(messages.Align),
|
|
79
79
|
widget: 'align',
|
|
80
|
+
default: 'center',
|
|
80
81
|
},
|
|
81
82
|
size: {
|
|
82
83
|
title: intl.formatMessage(messages.size),
|
|
83
84
|
widget: 'image_size',
|
|
85
|
+
default: 'l',
|
|
84
86
|
},
|
|
85
87
|
href: {
|
|
86
88
|
title: intl.formatMessage(messages.LinkTo),
|
|
@@ -414,7 +414,7 @@ const RelationsMatrix = (props) => {
|
|
|
414
414
|
<Popup
|
|
415
415
|
trigger={
|
|
416
416
|
<a
|
|
417
|
-
href="https://6.docs.plone.org/volto/
|
|
417
|
+
href="https://6.docs.plone.org/volto/development/widget.html#widget-relation-field-label"
|
|
418
418
|
target="_blank"
|
|
419
419
|
rel="noopener noreferrer"
|
|
420
420
|
>
|