newspack-components 4.10.0-alpha.1 → 4.11.0
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 +10 -3
- package/DEVELOPMENT.md +1 -0
- package/dist/cjs/card-sortable-list/index.js +6 -3
- package/dist/cjs/card-sortable-list/index.test.js +21 -0
- package/dist/cjs/card-sortable-list/style.scss +8 -0
- package/dist/cjs/index.js +7 -0
- package/dist/cjs/reorder-modal/index.js +521 -0
- package/dist/cjs/reorder-modal/index.test.js +1223 -0
- package/dist/cjs/reorder-modal/style.scss +114 -0
- package/dist/esm/card-sortable-list/index.js +5 -2
- package/dist/esm/card-sortable-list/index.test.js +21 -0
- package/dist/esm/card-sortable-list/style.scss +8 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/reorder-modal/index.js +514 -0
- package/dist/esm/reorder-modal/index.test.js +1224 -0
- package/dist/esm/reorder-modal/style.scss +114 -0
- package/package.json +3 -3
- package/src/card-sortable-list/index.test.js +13 -0
- package/src/card-sortable-list/index.tsx +4 -1
- package/src/card-sortable-list/style.scss +8 -0
- package/src/index.js +1 -0
- package/src/reorder-modal/index.js +484 -0
- package/src/reorder-modal/index.test.js +566 -0
- package/src/reorder-modal/style.scss +114 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
3
|
+
/**
|
|
4
|
+
* External dependencies
|
|
5
|
+
*/
|
|
6
|
+
import classnames from 'classnames';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* WordPress dependencies
|
|
10
|
+
*/
|
|
11
|
+
import { __, _n, sprintf } from '@wordpress/i18n';
|
|
12
|
+
import { speak } from '@wordpress/a11y';
|
|
13
|
+
import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
|
|
14
|
+
import { useInstanceId } from '@wordpress/compose';
|
|
15
|
+
import { Button, FormToggle, Modal, Notice, Spinner, Tooltip, VisuallyHidden, __experimentalConfirmDialog as ConfirmDialog // eslint-disable-line @wordpress/no-unsafe-wp-apis
|
|
16
|
+
} from '@wordpress/components';
|
|
17
|
+
import { Icon, chevronDown, chevronUp, close, dragHandle } from '@wordpress/icons';
|
|
18
|
+
import { Badge, Card } from '@wordpress/ui';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Internal dependencies
|
|
22
|
+
*/
|
|
23
|
+
import './style.scss';
|
|
24
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
25
|
+
export var moveItem = function moveItem(items, from, to) {
|
|
26
|
+
if (from === to || from < 0 || to < 0 || from >= items.length || to >= items.length) {
|
|
27
|
+
return items;
|
|
28
|
+
}
|
|
29
|
+
var next = _toConsumableArray(items);
|
|
30
|
+
var _next$splice = next.splice(from, 1),
|
|
31
|
+
_next$splice2 = _slicedToArray(_next$splice, 1),
|
|
32
|
+
moved = _next$splice2[0];
|
|
33
|
+
next.splice(to, 0, moved);
|
|
34
|
+
return next;
|
|
35
|
+
};
|
|
36
|
+
var OVERLAY_SELECTOR = '.components-modal__screen-overlay';
|
|
37
|
+
|
|
38
|
+
// The overlay carries the dismissal handling and the drop target, and `Modal`
|
|
39
|
+
// forwards its ref to it today. Deriving it from whatever node arrives keeps
|
|
40
|
+
// both working if core ever forwards that ref somewhere else.
|
|
41
|
+
export var findOverlay = function findOverlay(node) {
|
|
42
|
+
var _node$closest, _node$querySelector, _node$ownerDocument;
|
|
43
|
+
return (node === null || node === void 0 || (_node$closest = node.closest) === null || _node$closest === void 0 ? void 0 : _node$closest.call(node, OVERLAY_SELECTOR)) || (node === null || node === void 0 || (_node$querySelector = node.querySelector) === null || _node$querySelector === void 0 ? void 0 : _node$querySelector.call(node, OVERLAY_SELECTOR)) || (node === null || node === void 0 || (_node$ownerDocument = node.ownerDocument) === null || _node$ownerDocument === void 0 ? void 0 : _node$ownerDocument.querySelector(OVERLAY_SELECTOR)) || null;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Disabled controls stay focusable here, so they report `aria-disabled` rather
|
|
47
|
+
// than the native attribute.
|
|
48
|
+
var isAvailable = function isAvailable(button) {
|
|
49
|
+
return !!button && !button.matches(':disabled, [aria-disabled="true"]');
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Speech input matches on the visible label, so it has to open the accessible
|
|
53
|
+
// name. Composing both from one translated string keeps that true in every locale.
|
|
54
|
+
var nameWithTitle = function nameWithTitle(label, title) {
|
|
55
|
+
return sprintf(/* translators: keep %1$s first: it repeats the button's visible label, which speech input matches on. 1: the control's visible label. 2: title of the content being moved. */
|
|
56
|
+
__('%1$s: %2$s', 'newspack-plugin'), label, title);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Put a short list of items in order and, optionally, choose which are on.
|
|
61
|
+
* Changes apply on Save.
|
|
62
|
+
*
|
|
63
|
+
* @param {Object} props Component props.
|
|
64
|
+
* @param {string} props.title Modal title.
|
|
65
|
+
* @param {Array} props.ids Item IDs, in their current order.
|
|
66
|
+
* @param {Function} props.fetchItems Resolves the IDs to `{ value, label, badge? }`, where `badge` is `{ label, tooltip? }`.
|
|
67
|
+
* @param {Function} props.onSave Called with the new order and, when `enabledIds` is given, the enabled IDs: those
|
|
68
|
+
* on, in that order, then any from `enabledIds` the modal had no row for, kept as they were.
|
|
69
|
+
* @param {Function} props.onClose Called when the modal closes without saving.
|
|
70
|
+
* @param {Array} props.enabledIds Optional. Gives each row an on/off toggle, starting on for these IDs. Save is held while none is on.
|
|
71
|
+
* @param {string} props.description Optional. Introduces the list, above it.
|
|
72
|
+
* @param {string} props.noneOnHelp Why Save is held while no toggle is on.
|
|
73
|
+
*/
|
|
74
|
+
var _ReorderModal = function ReorderModal(_ref) {
|
|
75
|
+
var title = _ref.title,
|
|
76
|
+
ids = _ref.ids,
|
|
77
|
+
fetchItems = _ref.fetchItems,
|
|
78
|
+
onSave = _ref.onSave,
|
|
79
|
+
onClose = _ref.onClose,
|
|
80
|
+
enabledIds = _ref.enabledIds,
|
|
81
|
+
description = _ref.description,
|
|
82
|
+
_ref$noneOnHelp = _ref.noneOnHelp,
|
|
83
|
+
noneOnHelp = _ref$noneOnHelp === void 0 ? __('Turn on at least one item to save.', 'newspack-plugin') : _ref$noneOnHelp;
|
|
84
|
+
var hasToggles = Array.isArray(enabledIds);
|
|
85
|
+
var instanceId = useInstanceId(_ReorderModal, 'newspack-reorder-modal');
|
|
86
|
+
var moveUpLabel = __('Move Up', 'newspack-plugin');
|
|
87
|
+
var moveDownLabel = __('Move Down', 'newspack-plugin');
|
|
88
|
+
var _useState = useState(null),
|
|
89
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
90
|
+
items = _useState2[0],
|
|
91
|
+
setItems = _useState2[1];
|
|
92
|
+
var _useState3 = useState(null),
|
|
93
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
94
|
+
dragIndex = _useState4[0],
|
|
95
|
+
setDragIndex = _useState4[1];
|
|
96
|
+
var _useState5 = useState(false),
|
|
97
|
+
_useState6 = _slicedToArray(_useState5, 2),
|
|
98
|
+
hasFetchError = _useState6[0],
|
|
99
|
+
setHasFetchError = _useState6[1];
|
|
100
|
+
var _useState7 = useState(false),
|
|
101
|
+
_useState8 = _slicedToArray(_useState7, 2),
|
|
102
|
+
isConfirmingDiscard = _useState8[0],
|
|
103
|
+
setIsConfirmingDiscard = _useState8[1];
|
|
104
|
+
var listRef = useRef(null);
|
|
105
|
+
var overlayRef = useRef(null);
|
|
106
|
+
var pendingFocus = useRef(null);
|
|
107
|
+
var closeRef = useRef(null);
|
|
108
|
+
var preDragItems = useRef(null);
|
|
109
|
+
var dragBlocked = useRef(false);
|
|
110
|
+
var captureOverlay = useCallback(function (node) {
|
|
111
|
+
overlayRef.current = findOverlay(node);
|
|
112
|
+
}, []);
|
|
113
|
+
|
|
114
|
+
// The order the modal opened with. Snapshotted so a change to `ids` from
|
|
115
|
+
// elsewhere in the editor cannot desynchronise it from `items`.
|
|
116
|
+
var openedWith = useRef(ids);
|
|
117
|
+
var openedEnabled = useRef(hasToggles ? enabledIds : []);
|
|
118
|
+
var _useState9 = useState(function () {
|
|
119
|
+
return new Set(openedEnabled.current);
|
|
120
|
+
}),
|
|
121
|
+
_useState0 = _slicedToArray(_useState9, 2),
|
|
122
|
+
enabled = _useState0[0],
|
|
123
|
+
setEnabled = _useState0[1];
|
|
124
|
+
var isReordered = !!items && items.some(function (item, index) {
|
|
125
|
+
return item.id !== openedWith.current[index];
|
|
126
|
+
});
|
|
127
|
+
var isToggled = enabled.size !== openedEnabled.current.length || openedEnabled.current.some(function (id) {
|
|
128
|
+
return !enabled.has(id);
|
|
129
|
+
});
|
|
130
|
+
var isDirty = isReordered || hasToggles && isToggled;
|
|
131
|
+
// Enabled IDs without a row can't be switched off here, so Save keeps them.
|
|
132
|
+
var enabledWithoutRow = openedEnabled.current.filter(function (id) {
|
|
133
|
+
return !openedWith.current.includes(id);
|
|
134
|
+
});
|
|
135
|
+
var isNoneOn = hasToggles && 0 === enabled.size && 0 === enabledWithoutRow.length;
|
|
136
|
+
var toggleItem = function toggleItem(id) {
|
|
137
|
+
return setEnabled(function (current) {
|
|
138
|
+
var next = new Set(current);
|
|
139
|
+
if (next.has(id)) {
|
|
140
|
+
next["delete"](id);
|
|
141
|
+
} else {
|
|
142
|
+
next.add(id);
|
|
143
|
+
}
|
|
144
|
+
return next;
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
useEffect(function () {
|
|
148
|
+
var cancelled = false;
|
|
149
|
+
var openIds = openedWith.current;
|
|
150
|
+
var withLabels = function withLabels(labels, badges) {
|
|
151
|
+
return openIds.map(function (id) {
|
|
152
|
+
return {
|
|
153
|
+
id: id,
|
|
154
|
+
label: labels[id] || __('(no title)', 'newspack-plugin'),
|
|
155
|
+
badge: badges[id]
|
|
156
|
+
};
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
fetchItems(openIds).then(function (results) {
|
|
160
|
+
if (cancelled) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
var labels = {};
|
|
164
|
+
var badges = {};
|
|
165
|
+
results.forEach(function (_ref2) {
|
|
166
|
+
var value = _ref2.value,
|
|
167
|
+
label = _ref2.label,
|
|
168
|
+
badge = _ref2.badge;
|
|
169
|
+
labels[value] = label;
|
|
170
|
+
badges[value] = badge;
|
|
171
|
+
});
|
|
172
|
+
var loaded = withLabels(labels, badges);
|
|
173
|
+
setItems(loaded);
|
|
174
|
+
speak(sprintf(/* translators: %d: number of items in the list. */
|
|
175
|
+
_n('%d item ready to reorder.', '%d items ready to reorder.', loaded.length, 'newspack-plugin'), loaded.length));
|
|
176
|
+
})["catch"](function (error) {
|
|
177
|
+
// eslint-disable-next-line no-console
|
|
178
|
+
console.error('Newspack: could not prepare the items to reorder.', error);
|
|
179
|
+
if (!cancelled) {
|
|
180
|
+
setHasFetchError(true);
|
|
181
|
+
// Only to leave the loading state: the error view lists nothing.
|
|
182
|
+
setItems([]);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
return function () {
|
|
186
|
+
cancelled = true;
|
|
187
|
+
};
|
|
188
|
+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
189
|
+
|
|
190
|
+
// A chevron that reaches an end of the list stops accepting moves, so send
|
|
191
|
+
// focus to the row's other chevron.
|
|
192
|
+
useEffect(function () {
|
|
193
|
+
var pending = pendingFocus.current;
|
|
194
|
+
pendingFocus.current = null;
|
|
195
|
+
if (!pending || !listRef.current) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
var row = listRef.current.querySelector("[data-item-id=\"".concat(pending.id, "\"]"));
|
|
199
|
+
if (!row) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
var preferred = row.querySelector("[data-direction=\"".concat(pending.direction, "\"]"));
|
|
203
|
+
var fallback = row.querySelector("[data-direction=\"".concat('up' === pending.direction ? 'down' : 'up', "\"]"));
|
|
204
|
+
if (isAvailable(preferred)) {
|
|
205
|
+
preferred.focus();
|
|
206
|
+
} else if (isAvailable(fallback)) {
|
|
207
|
+
fallback.focus();
|
|
208
|
+
}
|
|
209
|
+
}, [items]);
|
|
210
|
+
var moveTo = function moveTo(from, to, direction) {
|
|
211
|
+
var next = moveItem(items, from, to);
|
|
212
|
+
if (next === items) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
pendingFocus.current = {
|
|
216
|
+
id: items[from].id,
|
|
217
|
+
direction: direction
|
|
218
|
+
};
|
|
219
|
+
setItems(next);
|
|
220
|
+
speak(sprintf(/* translators: 1: title of the moved item. 2: its new position. 3: total number of items. */
|
|
221
|
+
__('%1$s moved to position %2$d of %3$d.', 'newspack-plugin'), items[from].label, to + 1, items.length));
|
|
222
|
+
};
|
|
223
|
+
var requestClose = function requestClose() {
|
|
224
|
+
if (isDirty) {
|
|
225
|
+
setIsConfirmingDiscard(true);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
onClose();
|
|
229
|
+
};
|
|
230
|
+
useEffect(function () {
|
|
231
|
+
closeRef.current = requestClose;
|
|
232
|
+
}, [requestClose]);
|
|
233
|
+
var handleKeyDown = function handleKeyDown(event) {
|
|
234
|
+
if ('Escape' !== event.key || event.defaultPrevented) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
event.preventDefault();
|
|
238
|
+
requestClose();
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// `Modal` plays its exit animation before it reports a close request, which
|
|
242
|
+
// would fade the modal out and back in whenever the confirmation vetoes one.
|
|
243
|
+
// Its own dismissal handlers are off, so drive the overlay press here.
|
|
244
|
+
useEffect(function () {
|
|
245
|
+
var overlay = overlayRef.current;
|
|
246
|
+
if (!overlay) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
var pressedOverlay = false;
|
|
250
|
+
var onPointerDown = function onPointerDown(event) {
|
|
251
|
+
pressedOverlay = event.target === overlay;
|
|
252
|
+
if (pressedOverlay) {
|
|
253
|
+
event.preventDefault();
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
var onPointerUp = function onPointerUp(event) {
|
|
257
|
+
var dismisses = pressedOverlay && 0 === event.button && event.target === overlay;
|
|
258
|
+
pressedOverlay = false;
|
|
259
|
+
if (dismisses) {
|
|
260
|
+
closeRef.current();
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
overlay.addEventListener('pointerdown', onPointerDown);
|
|
264
|
+
overlay.addEventListener('pointerup', onPointerUp);
|
|
265
|
+
return function () {
|
|
266
|
+
overlay.removeEventListener('pointerdown', onPointerDown);
|
|
267
|
+
overlay.removeEventListener('pointerup', onPointerUp);
|
|
268
|
+
};
|
|
269
|
+
}, []);
|
|
270
|
+
|
|
271
|
+
// Rows are the only drop targets, and the frame's own padding is not one, so a
|
|
272
|
+
// release a few pixels wide of the list would report a cancelled drag and undo
|
|
273
|
+
// the reorder. Accepting the drop across the whole dialog leaves "cancelled"
|
|
274
|
+
// meaning only Escape or a release outside it.
|
|
275
|
+
useEffect(function () {
|
|
276
|
+
var _overlayRef$current;
|
|
277
|
+
var frame = (_overlayRef$current = overlayRef.current) === null || _overlayRef$current === void 0 ? void 0 : _overlayRef$current.querySelector('.components-modal__frame');
|
|
278
|
+
if (!frame) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
var accept = function accept(event) {
|
|
282
|
+
return event.preventDefault();
|
|
283
|
+
};
|
|
284
|
+
frame.addEventListener('dragover', accept);
|
|
285
|
+
frame.addEventListener('drop', accept);
|
|
286
|
+
return function () {
|
|
287
|
+
frame.removeEventListener('dragover', accept);
|
|
288
|
+
frame.removeEventListener('drop', accept);
|
|
289
|
+
};
|
|
290
|
+
}, []);
|
|
291
|
+
var handleDragOver = function handleDragOver(event, index) {
|
|
292
|
+
event.preventDefault();
|
|
293
|
+
if (null === dragIndex) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
event.dataTransfer.dropEffect = 'move';
|
|
297
|
+
if (dragIndex === index) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
setItems(moveItem(items, dragIndex, index));
|
|
301
|
+
setDragIndex(index);
|
|
302
|
+
};
|
|
303
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
304
|
+
children: [/*#__PURE__*/_jsx(Modal, {
|
|
305
|
+
ref: captureOverlay,
|
|
306
|
+
title: title,
|
|
307
|
+
onRequestClose: requestClose,
|
|
308
|
+
onKeyDown: handleKeyDown,
|
|
309
|
+
isDismissible: false,
|
|
310
|
+
shouldCloseOnEsc: false,
|
|
311
|
+
shouldCloseOnClickOutside: false,
|
|
312
|
+
headerActions: /*#__PURE__*/_jsx(Button, {
|
|
313
|
+
size: "compact",
|
|
314
|
+
icon: close,
|
|
315
|
+
label: __('Close', 'newspack-plugin'),
|
|
316
|
+
onClick: requestClose
|
|
317
|
+
}),
|
|
318
|
+
size: "medium",
|
|
319
|
+
className: "newspack-reorder-modal",
|
|
320
|
+
aria: {
|
|
321
|
+
describedby: description ? "".concat(instanceId, "-description") : undefined
|
|
322
|
+
},
|
|
323
|
+
children: /*#__PURE__*/_jsxs("div", {
|
|
324
|
+
className: "newspack-reorder-modal__body",
|
|
325
|
+
"aria-busy": !items,
|
|
326
|
+
children: [description && /*#__PURE__*/_jsx("p", {
|
|
327
|
+
id: "".concat(instanceId, "-description"),
|
|
328
|
+
className: "newspack-reorder-modal__description",
|
|
329
|
+
children: description
|
|
330
|
+
}), !items && /*#__PURE__*/_jsxs("div", {
|
|
331
|
+
className: "newspack-reorder-modal__loading",
|
|
332
|
+
children: [/*#__PURE__*/_jsx(Spinner, {}), /*#__PURE__*/_jsx("span", {
|
|
333
|
+
className: "screen-reader-text",
|
|
334
|
+
children: __('Loading content…', 'newspack-plugin')
|
|
335
|
+
})]
|
|
336
|
+
}), items && hasFetchError && /*#__PURE__*/_jsxs(_Fragment, {
|
|
337
|
+
children: [/*#__PURE__*/_jsx(Notice, {
|
|
338
|
+
status: "error",
|
|
339
|
+
isDismissible: false,
|
|
340
|
+
className: "newspack-reorder-modal__notice",
|
|
341
|
+
children: __('The content could not be loaded, so the order cannot be saved.', 'newspack-plugin')
|
|
342
|
+
}), /*#__PURE__*/_jsx("div", {
|
|
343
|
+
className: "newspack-reorder-modal__footer",
|
|
344
|
+
children: /*#__PURE__*/_jsx(Button, {
|
|
345
|
+
variant: "tertiary",
|
|
346
|
+
onClick: requestClose,
|
|
347
|
+
children: __('Cancel', 'newspack-plugin')
|
|
348
|
+
})
|
|
349
|
+
})]
|
|
350
|
+
}), items && !hasFetchError && /*#__PURE__*/_jsxs(_Fragment, {
|
|
351
|
+
children: [/*#__PURE__*/_jsx("ul", {
|
|
352
|
+
className: "newspack-reorder-modal__list",
|
|
353
|
+
role: "list",
|
|
354
|
+
ref: listRef,
|
|
355
|
+
children: items.map(function (item, index) {
|
|
356
|
+
return /*#__PURE__*/_jsxs(Card.Root, {
|
|
357
|
+
render: /*#__PURE__*/_jsx("li", {}),
|
|
358
|
+
"data-item-id": item.id,
|
|
359
|
+
className: classnames('newspack-reorder-modal__item', {
|
|
360
|
+
'is-dragging': dragIndex === index,
|
|
361
|
+
'is-off': hasToggles && !enabled.has(item.id)
|
|
362
|
+
}),
|
|
363
|
+
draggable: true
|
|
364
|
+
// `dragstart` always fires at the draggable row, never at the
|
|
365
|
+
// chevron inside it, so the grab point is recorded separately.
|
|
366
|
+
,
|
|
367
|
+
onPointerDown: function onPointerDown(event) {
|
|
368
|
+
var _event$target$closest, _event$target;
|
|
369
|
+
dragBlocked.current = !!((_event$target$closest = (_event$target = event.target).closest) !== null && _event$target$closest !== void 0 && _event$target$closest.call(_event$target, 'button, input'));
|
|
370
|
+
},
|
|
371
|
+
onDragStart: function onDragStart(event) {
|
|
372
|
+
if (dragBlocked.current) {
|
|
373
|
+
event.preventDefault();
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
preDragItems.current = items;
|
|
377
|
+
// Firefox and Safari will not start a drag until the payload is set.
|
|
378
|
+
event.dataTransfer.setData('text/plain', String(item.id));
|
|
379
|
+
event.dataTransfer.effectAllowed = 'move';
|
|
380
|
+
setDragIndex(index);
|
|
381
|
+
},
|
|
382
|
+
onDragOver: function onDragOver(event) {
|
|
383
|
+
return handleDragOver(event, index);
|
|
384
|
+
},
|
|
385
|
+
onDragEnd: function onDragEnd(event) {
|
|
386
|
+
// A cancelled drag reports no drop effect: put the order back.
|
|
387
|
+
if ('none' === event.dataTransfer.dropEffect && preDragItems.current) {
|
|
388
|
+
setItems(preDragItems.current);
|
|
389
|
+
}
|
|
390
|
+
preDragItems.current = null;
|
|
391
|
+
setDragIndex(null);
|
|
392
|
+
},
|
|
393
|
+
onDrop: function onDrop(event) {
|
|
394
|
+
return event.preventDefault();
|
|
395
|
+
},
|
|
396
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
397
|
+
className: "newspack-reorder-modal__grip",
|
|
398
|
+
"aria-hidden": "true",
|
|
399
|
+
children: /*#__PURE__*/_jsx(Icon, {
|
|
400
|
+
icon: dragHandle
|
|
401
|
+
})
|
|
402
|
+
}), /*#__PURE__*/_jsxs("span", {
|
|
403
|
+
className: "newspack-reorder-modal__move",
|
|
404
|
+
children: [/*#__PURE__*/_jsx(Button, {
|
|
405
|
+
icon: chevronUp,
|
|
406
|
+
size: "small",
|
|
407
|
+
"data-direction": "up",
|
|
408
|
+
disabled: 0 === index,
|
|
409
|
+
accessibleWhenDisabled: true,
|
|
410
|
+
label: moveUpLabel,
|
|
411
|
+
"aria-label": nameWithTitle(moveUpLabel, item.label),
|
|
412
|
+
onClick: function onClick() {
|
|
413
|
+
return moveTo(index, index - 1, 'up');
|
|
414
|
+
}
|
|
415
|
+
}), /*#__PURE__*/_jsx(Button, {
|
|
416
|
+
icon: chevronDown,
|
|
417
|
+
size: "small",
|
|
418
|
+
"data-direction": "down",
|
|
419
|
+
disabled: index === items.length - 1,
|
|
420
|
+
accessibleWhenDisabled: true,
|
|
421
|
+
label: moveDownLabel,
|
|
422
|
+
"aria-label": nameWithTitle(moveDownLabel, item.label),
|
|
423
|
+
onClick: function onClick() {
|
|
424
|
+
return moveTo(index, index + 1, 'down');
|
|
425
|
+
}
|
|
426
|
+
})]
|
|
427
|
+
}), /*#__PURE__*/_jsxs(Card.Content, {
|
|
428
|
+
className: "newspack-reorder-modal__content",
|
|
429
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
430
|
+
className: "newspack-reorder-modal__title",
|
|
431
|
+
title: item.label,
|
|
432
|
+
children: item.label
|
|
433
|
+
}), item.badge && /*#__PURE__*/_jsxs("span", {
|
|
434
|
+
className: "newspack-reorder-modal__badge",
|
|
435
|
+
children: [item.badge.tooltip ? /*#__PURE__*/_jsx(Tooltip, {
|
|
436
|
+
text: item.badge.tooltip,
|
|
437
|
+
children: /*#__PURE__*/_jsx("span", {
|
|
438
|
+
"aria-hidden": "true",
|
|
439
|
+
tabIndex: -1,
|
|
440
|
+
children: /*#__PURE__*/_jsx(Badge, {
|
|
441
|
+
intent: "draft",
|
|
442
|
+
children: item.badge.label
|
|
443
|
+
})
|
|
444
|
+
})
|
|
445
|
+
}) : /*#__PURE__*/_jsx("span", {
|
|
446
|
+
"aria-hidden": "true",
|
|
447
|
+
children: /*#__PURE__*/_jsx(Badge, {
|
|
448
|
+
intent: "draft",
|
|
449
|
+
children: item.badge.label
|
|
450
|
+
})
|
|
451
|
+
}), /*#__PURE__*/_jsx(VisuallyHidden, {
|
|
452
|
+
id: "".concat(instanceId, "-badge-").concat(item.id),
|
|
453
|
+
children: item.badge.tooltip ? "".concat(item.badge.label, ": ").concat(item.badge.tooltip) : item.badge.label
|
|
454
|
+
})]
|
|
455
|
+
})]
|
|
456
|
+
}), hasToggles && /*#__PURE__*/_jsx("span", {
|
|
457
|
+
className: "newspack-reorder-modal__toggle",
|
|
458
|
+
children: /*#__PURE__*/_jsx(FormToggle, {
|
|
459
|
+
checked: enabled.has(item.id),
|
|
460
|
+
onChange: function onChange() {
|
|
461
|
+
return toggleItem(item.id);
|
|
462
|
+
},
|
|
463
|
+
"aria-label": item.label,
|
|
464
|
+
"aria-describedby": item.badge ? "".concat(instanceId, "-badge-").concat(item.id) : undefined
|
|
465
|
+
})
|
|
466
|
+
})]
|
|
467
|
+
}, item.id);
|
|
468
|
+
})
|
|
469
|
+
}), /*#__PURE__*/_jsxs("div", {
|
|
470
|
+
className: "newspack-reorder-modal__footer",
|
|
471
|
+
children: [/*#__PURE__*/_jsx(Button, {
|
|
472
|
+
variant: "tertiary",
|
|
473
|
+
onClick: requestClose,
|
|
474
|
+
children: __('Cancel', 'newspack-plugin')
|
|
475
|
+
}), /*#__PURE__*/_jsx(Button, {
|
|
476
|
+
variant: "primary",
|
|
477
|
+
disabled: !isDirty || isNoneOn,
|
|
478
|
+
accessibleWhenDisabled: true
|
|
479
|
+
// A button with visible children shows a tooltip only when asked and labelled.
|
|
480
|
+
,
|
|
481
|
+
label: __('Save', 'newspack-plugin'),
|
|
482
|
+
showTooltip: isDirty && isNoneOn,
|
|
483
|
+
description: isDirty && isNoneOn ? noneOnHelp : undefined,
|
|
484
|
+
onClick: function onClick() {
|
|
485
|
+
var order = items.map(function (item) {
|
|
486
|
+
return item.id;
|
|
487
|
+
});
|
|
488
|
+
if (hasToggles) {
|
|
489
|
+
onSave(order, [].concat(_toConsumableArray(order.filter(function (id) {
|
|
490
|
+
return enabled.has(id);
|
|
491
|
+
})), _toConsumableArray(enabledWithoutRow)));
|
|
492
|
+
} else {
|
|
493
|
+
onSave(order);
|
|
494
|
+
}
|
|
495
|
+
},
|
|
496
|
+
children: __('Save', 'newspack-plugin')
|
|
497
|
+
})]
|
|
498
|
+
})]
|
|
499
|
+
})]
|
|
500
|
+
})
|
|
501
|
+
}), isConfirmingDiscard && /*#__PURE__*/_jsx(ConfirmDialog, {
|
|
502
|
+
isOpen: true,
|
|
503
|
+
contentLabel: hasToggles ? __('Discard the changes?', 'newspack-plugin') : __('Discard the new order?', 'newspack-plugin'),
|
|
504
|
+
confirmButtonText: __('Discard', 'newspack-plugin'),
|
|
505
|
+
cancelButtonText: __('Keep editing', 'newspack-plugin'),
|
|
506
|
+
onConfirm: onClose,
|
|
507
|
+
onCancel: function onCancel() {
|
|
508
|
+
return setIsConfirmingDiscard(false);
|
|
509
|
+
},
|
|
510
|
+
children: hasToggles ? __('The changes you made will be lost.', 'newspack-plugin') : __('The order you set will be lost.', 'newspack-plugin')
|
|
511
|
+
})]
|
|
512
|
+
});
|
|
513
|
+
};
|
|
514
|
+
export default _ReorderModal;
|