UNPKG

16.5 kBJavaScriptView Raw
1"use strict";
2var __extends = (this && this.__extends) || (function () {
3 var extendStatics = function (d, b) {
4 extendStatics = Object.setPrototypeOf ||
5 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
7 return extendStatics(d, b);
8 };
9 return function (d, b) {
10 extendStatics(d, b);
11 function __() { this.constructor = d; }
12 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
13 };
14})();
15var __assign = (this && this.__assign) || function () {
16 __assign = Object.assign || function(t) {
17 for (var s, i = 1, n = arguments.length; i < n; i++) {
18 s = arguments[i];
19 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
20 t[p] = s[p];
21 }
22 return t;
23 };
24 return __assign.apply(this, arguments);
25};
26var __importStar = (this && this.__importStar) || function (mod) {
27 if (mod && mod.__esModule) return mod;
28 var result = {};
29 if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
30 result["default"] = mod;
31 return result;
32};
33Object.defineProperty(exports, "__esModule", { value: true });
34var React = __importStar(require("react"));
35var ReactDOM = __importStar(require("react-dom"));
36var utils_1 = require("./utils");
37var List = /** @class */ (function (_super) {
38 __extends(List, _super);
39 function List() {
40 var _this = _super !== null && _super.apply(this, arguments) || this;
41 _this.listRef = React.createRef();
42 _this.ghostRef = React.createRef();
43 _this.topOffsets = [];
44 _this.itemTranslateOffsets = [];
45 _this.initialYOffset = 0;
46 _this.lastScroll = 0;
47 _this.needle = -1;
48 _this.afterIndex = -2;
49 _this.state = {
50 itemDragged: -1,
51 selectedItem: -1,
52 initialX: 0,
53 initialY: 0,
54 targetX: 0,
55 targetY: 0,
56 targetHeight: 0,
57 targetWidth: 0,
58 liveText: ''
59 };
60 _this.getChildren = function () {
61 if (_this.listRef && _this.listRef.current) {
62 return Array.from(_this.listRef.current.children);
63 }
64 console.warn('No items found in the List container. Did you forget to pass & spread the `props` param in renderList?');
65 return [];
66 };
67 _this.calculateOffsets = function () {
68 _this.topOffsets = _this.getChildren().map(function (item) {
69 return item.getBoundingClientRect().top;
70 });
71 _this.itemTranslateOffsets = _this.getChildren().map(function (item) {
72 return utils_1.getTranslateOffset(item);
73 });
74 };
75 _this.getTargetIndex = function (e) {
76 return _this.getChildren().findIndex(function (child) { return child === e.target || child.contains(e.currentTarget); });
77 };
78 _this.onMouseDown = function (e) {
79 if (e.button !== 0)
80 return;
81 document.addEventListener('mousemove', _this.onMouseMove, { passive: true });
82 document.addEventListener('mouseup', _this.onEnd, { passive: true });
83 var index = _this.getTargetIndex(e);
84 if (index === -1)
85 return;
86 _this.onStart(_this.getChildren()[index], e.clientX, e.clientY, index);
87 };
88 _this.onTouchStart = function (e) {
89 document.addEventListener('touchmove', _this.onTouchMove, { passive: true });
90 document.addEventListener('touchend', _this.onEnd, { passive: true });
91 document.addEventListener('touchcancel', _this.onEnd, { passive: true });
92 var index = _this.getTargetIndex(e);
93 if (index === -1)
94 return;
95 _this.onStart(_this.getChildren()[index], e.touches[0].clientX, e.touches[0].clientY, index);
96 };
97 _this.getYOffset = function () {
98 var listScroll = _this.listRef.current
99 ? _this.listRef.current.scrollTop
100 : 0;
101 return window.pageYOffset + listScroll;
102 };
103 _this.onStart = function (target, clientX, clientY, index) {
104 if (_this.state.selectedItem > -1) {
105 _this.setState({ selectedItem: -1 });
106 _this.needle = -1;
107 }
108 var targetRect = target.getBoundingClientRect();
109 var targetStyles = window.getComputedStyle(target);
110 _this.calculateOffsets();
111 _this.initialYOffset = _this.getYOffset();
112 _this.setState({
113 itemDragged: index,
114 targetX: targetRect.x - parseInt(targetStyles['margin-left'], 10),
115 targetY: targetRect.y - parseInt(targetStyles['margin-top'], 10),
116 targetHeight: targetRect.height,
117 targetWidth: targetRect.width,
118 initialX: clientX,
119 initialY: clientY
120 });
121 };
122 _this.onMouseMove = function (e) { return _this.onMove(e.clientX, e.clientY); };
123 _this.onTouchMove = function (e) {
124 return _this.onMove(e.touches[0].clientX, e.touches[0].clientY);
125 };
126 _this.onWheel = function (e) {
127 if (_this.state.itemDragged < 0)
128 return;
129 _this.lastScroll = _this.listRef.current.scrollTop += e.deltaY;
130 _this.moveOtherItems();
131 };
132 _this.onMove = function (clientX, clientY) {
133 if (_this.state.itemDragged === -1)
134 return null;
135 utils_1.transformItem(_this.ghostRef.current, clientY - _this.state.initialY, _this.props.lockVertically ? 0 : clientX - _this.state.initialX);
136 _this.moveOtherItems();
137 };
138 _this.moveOtherItems = function () {
139 var targetRect = _this.ghostRef.current.getBoundingClientRect();
140 var itemVerticalCenter = targetRect.top + targetRect.height / 2;
141 var offset = utils_1.getTranslateOffset(_this.getChildren()[_this.state.itemDragged]);
142 var currentYOffset = _this.getYOffset();
143 // adjust offsets if scrolling happens during the item movement
144 if (_this.initialYOffset !== currentYOffset) {
145 _this.topOffsets = _this.topOffsets.map(function (offset) { return offset - (currentYOffset - _this.initialYOffset); });
146 _this.initialYOffset = currentYOffset;
147 }
148 _this.afterIndex = utils_1.binarySearch(_this.topOffsets, itemVerticalCenter);
149 _this.animateItems(_this.afterIndex === -1 ? 0 : _this.afterIndex, _this.state.itemDragged, offset);
150 };
151 _this.animateItems = function (needle, movedItem, offset, animateMovedItem) {
152 if (animateMovedItem === void 0) { animateMovedItem = false; }
153 _this.getChildren().forEach(function (item, i) {
154 utils_1.setItemTransition(item, _this.props.transitionDuration);
155 if (movedItem === i && animateMovedItem) {
156 if (movedItem === needle) {
157 return utils_1.transformItem(item, null);
158 }
159 utils_1.transformItem(item, movedItem < needle
160 ? _this.itemTranslateOffsets
161 .slice(movedItem + 1, needle + 1)
162 .reduce(function (a, b) { return a + b; }, 0)
163 : _this.itemTranslateOffsets
164 .slice(needle, movedItem)
165 .reduce(function (a, b) { return a + b; }, 0) * -1);
166 }
167 else if (movedItem < needle && i > movedItem && i <= needle) {
168 utils_1.transformItem(item, -offset);
169 }
170 else if (i < movedItem && movedItem > needle && i >= needle) {
171 utils_1.transformItem(item, offset);
172 }
173 else {
174 utils_1.transformItem(item, null);
175 }
176 });
177 };
178 _this.onEnd = function () {
179 document.removeEventListener('mousemove', _this.onMouseMove);
180 document.removeEventListener('touchmove', _this.onTouchMove);
181 document.removeEventListener('mouseup', _this.onEnd);
182 document.removeEventListener('touchup', _this.onEnd);
183 document.removeEventListener('touchcancel', _this.onEnd);
184 if (_this.afterIndex > -1 && _this.state.itemDragged !== _this.afterIndex) {
185 _this.props.onChange({
186 oldIndex: _this.state.itemDragged,
187 newIndex: _this.afterIndex
188 });
189 }
190 _this.getChildren().forEach(function (item) {
191 utils_1.setItemTransition(item, 0);
192 utils_1.transformItem(item, null);
193 });
194 _this.setState({ itemDragged: -1 });
195 _this.afterIndex = -2;
196 // sometimes the scroll gets messed up after the drop, fix:
197 if (_this.lastScroll > 0) {
198 _this.listRef.current.scrollTop = _this.lastScroll;
199 _this.lastScroll = 0;
200 }
201 };
202 _this.onKeyDown = function (e) {
203 var selectedItem = _this.state.selectedItem;
204 var index = _this.getTargetIndex(e);
205 if (index === -1)
206 return;
207 if (e.key === ' ') {
208 e.preventDefault();
209 if (selectedItem === index) {
210 if (selectedItem !== _this.needle) {
211 _this.getChildren().forEach(function (item) {
212 utils_1.setItemTransition(item, 0);
213 utils_1.transformItem(item, null);
214 });
215 _this.props.onChange({
216 oldIndex: selectedItem,
217 newIndex: _this.needle
218 });
219 _this.getChildren()[_this.needle].focus();
220 }
221 _this.setState({
222 selectedItem: -1,
223 liveText: _this.props.voiceover.dropped(selectedItem + 1, _this.needle + 1)
224 });
225 _this.needle = -1;
226 }
227 else {
228 _this.setState({
229 selectedItem: index,
230 liveText: _this.props.voiceover.lifted(index + 1)
231 });
232 _this.needle = index;
233 }
234 }
235 if ((e.key === 'ArrowDown' || e.key === 'j') &&
236 selectedItem > -1 &&
237 _this.needle < _this.props.values.length - 1) {
238 e.preventDefault();
239 var offset = utils_1.getTranslateOffset(_this.getChildren()[selectedItem]);
240 _this.needle++;
241 _this.animateItems(_this.needle, selectedItem, offset, true);
242 _this.setState({
243 liveText: _this.props.voiceover.moved(_this.needle + 1, false)
244 });
245 }
246 if ((e.key === 'ArrowUp' || e.key === 'k') &&
247 selectedItem > -1 &&
248 _this.needle > 0) {
249 e.preventDefault();
250 var offset = utils_1.getTranslateOffset(_this.getChildren()[selectedItem]);
251 _this.needle--;
252 _this.animateItems(_this.needle, selectedItem, offset, true);
253 _this.setState({
254 liveText: _this.props.voiceover.moved(_this.needle + 1, true)
255 });
256 }
257 if (e.key === 'Escape' && selectedItem > -1) {
258 _this.getChildren().forEach(function (item) {
259 utils_1.setItemTransition(item, 0);
260 utils_1.transformItem(item, null);
261 });
262 _this.setState({
263 selectedItem: -1,
264 liveText: _this.props.voiceover.canceled(selectedItem + 1)
265 });
266 _this.needle = -1;
267 }
268 if ((e.key === 'Tab' || e.key === 'Enter') && selectedItem > -1) {
269 e.preventDefault();
270 }
271 };
272 return _this;
273 }
274 List.prototype.componentDidMount = function () {
275 this.calculateOffsets();
276 };
277 List.prototype.render = function () {
278 var _this = this;
279 var baseStyle = {
280 userDrag: 'none',
281 userSelect: 'none',
282 boxSizing: 'border-box',
283 position: 'relative'
284 };
285 var ghostStyle = __assign({}, baseStyle, { top: this.state.targetY, left: this.state.targetX, width: this.state.targetWidth, height: this.state.targetHeight, display: 'block', position: 'fixed', marginTop: 0 });
286 return (React.createElement(React.Fragment, null,
287 this.props.renderList({
288 children: this.props.values.map(function (value, index) {
289 var isDragged = index === _this.state.itemDragged;
290 var isSelected = index === _this.state.selectedItem;
291 var props = {
292 key: index,
293 tabIndex: 0,
294 'aria-roledescription': _this.props.voiceover.item(index + 1),
295 onKeyDown: _this.onKeyDown,
296 onMouseDown: _this.onMouseDown,
297 onTouchStart: _this.onTouchStart,
298 style: __assign({}, baseStyle, { visibility: isDragged ? 'hidden' : undefined, zIndex: isSelected ? 5000 : 0 })
299 };
300 return _this.props.renderItem({
301 value: value,
302 props: props,
303 index: index,
304 isDragged: isDragged,
305 isSelected: isSelected
306 });
307 }),
308 isDragged: this.state.itemDragged > -1,
309 props: {
310 ref: this.listRef
311 }
312 }),
313 this.state.itemDragged > -1 &&
314 ReactDOM.createPortal(this.props.renderItem({
315 value: this.props.values[this.state.itemDragged],
316 props: {
317 ref: this.ghostRef,
318 style: ghostStyle,
319 onWheel: this.onWheel
320 },
321 isDragged: true,
322 isSelected: false
323 }), document.body),
324 React.createElement("div", { "aria-live": "assertive", role: "log", "aria-atomic": "true", style: {
325 position: 'absolute',
326 width: '1px',
327 height: '1px',
328 margin: '-1px',
329 border: '0px',
330 padding: '0px',
331 overflow: 'hidden',
332 clip: 'react(0px, 0px, 0px, 0px)',
333 clipPath: 'inset(100%)'
334 } }, this.state.liveText)));
335 };
336 List.defaultProps = {
337 transitionDuration: 300,
338 lockVertically: false,
339 voiceover: {
340 item: function (position) {
341 return "You are currently at a draggable item at position " + position + ". Press space bar to lift.";
342 },
343 lifted: function (position) {
344 return "You have lifted item at position " + position + ". Press j to move down, k to move up, space bar to drop and escape to cancel.";
345 },
346 moved: function (position, up) {
347 return "You have moved the lifted item " + (up ? 'up' : 'down') + " to position " + position + ". Press j to move down, k to move up, space bar to drop and escape to cancel.";
348 },
349 dropped: function (from, to) {
350 return "You have dropped the item. It has moved from position " + from + " to " + to + ".";
351 },
352 canceled: function (position) {
353 return "You have cancelled the movement. The item has returned to its starting position of " + position + ".";
354 }
355 }
356 };
357 return List;
358}(React.Component));
359exports.default = List;