1 | "use strict";
|
2 | var __assign = (this && this.__assign) || function () {
|
3 | __assign = Object.assign || function(t) {
|
4 | for (var s, i = 1, n = arguments.length; i < n; i++) {
|
5 | s = arguments[i];
|
6 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
7 | t[p] = s[p];
|
8 | }
|
9 | return t;
|
10 | };
|
11 | return __assign.apply(this, arguments);
|
12 | };
|
13 | Object.defineProperty(exports, "__esModule", { value: true });
|
14 | exports.DraggableGrid = void 0;
|
15 | var React = require("react");
|
16 | var react_1 = require("react");
|
17 | var react_native_1 = require("react-native");
|
18 | var block_1 = require("./block");
|
19 | var utils_1 = require("./utils");
|
20 | var activeBlockOffset = { x: 0, y: 0 };
|
21 | exports.DraggableGrid = function (props) {
|
22 | var blockPositions = react_1.useState([])[0];
|
23 | var orderMap = react_1.useState({})[0];
|
24 | var itemMap = react_1.useState({})[0];
|
25 | var items = react_1.useState([])[0];
|
26 | var _a = react_1.useState(0), blockHeight = _a[0], setBlockHeight = _a[1];
|
27 | var _b = react_1.useState(0), blockWidth = _b[0], setBlockWidth = _b[1];
|
28 | var gridHeight = react_1.useState(new react_native_1.Animated.Value(0))[0];
|
29 | var _c = react_1.useState(false), hadInitBlockSize = _c[0], setHadInitBlockSize = _c[1];
|
30 | var dragStartAnimatedValue = react_1.useState(new react_native_1.Animated.Value(1))[0];
|
31 | var _d = react_1.useState({
|
32 | x: 0,
|
33 | y: 0,
|
34 | width: 0,
|
35 | height: 0,
|
36 | }), gridLayout = _d[0], setGridLayout = _d[1];
|
37 | var _e = react_1.useState(), activeItemIndex = _e[0], setActiveItemIndex = _e[1];
|
38 | var assessGridSize = function (event) {
|
39 | if (!hadInitBlockSize) {
|
40 | var blockWidth_1 = event.nativeEvent.layout.width / props.numColumns;
|
41 | var blockHeight_1 = props.itemHeight || blockWidth_1;
|
42 | setBlockWidth(blockWidth_1);
|
43 | setBlockHeight(blockHeight_1);
|
44 | setGridLayout(event.nativeEvent.layout);
|
45 | setHadInitBlockSize(true);
|
46 | }
|
47 | };
|
48 | var _f = react_1.useState(false), panResponderCapture = _f[0], setPanResponderCapture = _f[1];
|
49 | var panResponder = react_native_1.PanResponder.create({
|
50 | onStartShouldSetPanResponder: function () { return true; },
|
51 | onStartShouldSetPanResponderCapture: function () { return false; },
|
52 | onMoveShouldSetPanResponder: function () { return panResponderCapture; },
|
53 | onMoveShouldSetPanResponderCapture: function () { return panResponderCapture; },
|
54 | onShouldBlockNativeResponder: function () { return false; },
|
55 | onPanResponderTerminationRequest: function () { return false; },
|
56 | onPanResponderGrant: onStartDrag,
|
57 | onPanResponderMove: onHandMove,
|
58 | onPanResponderRelease: onHandRelease,
|
59 | });
|
60 | function initBlockPositions() {
|
61 | items.forEach(function (_, index) {
|
62 | blockPositions[index] = getBlockPositionByOrder(index);
|
63 | });
|
64 | }
|
65 | function getBlockPositionByOrder(order) {
|
66 | if (blockPositions[order]) {
|
67 | return blockPositions[order];
|
68 | }
|
69 | var columnOnRow = order % props.numColumns;
|
70 | var y = blockHeight * Math.floor(order / props.numColumns);
|
71 | var x = columnOnRow * blockWidth;
|
72 | return {
|
73 | x: x,
|
74 | y: y,
|
75 | };
|
76 | }
|
77 | function resetGridHeight() {
|
78 | var rowCount = Math.ceil(props.data.length / props.numColumns);
|
79 | gridHeight.setValue(rowCount * blockHeight);
|
80 | }
|
81 | function onBlockPress(itemIndex) {
|
82 | props.onItemPress && props.onItemPress(items[itemIndex].itemData);
|
83 | }
|
84 | function onStartDrag(_, gestureState) {
|
85 | var activeItem = getActiveItem();
|
86 | if (!activeItem)
|
87 | return false;
|
88 | props.onDragStart && props.onDragStart(activeItem.itemData);
|
89 | var x0 = gestureState.x0, y0 = gestureState.y0, moveX = gestureState.moveX, moveY = gestureState.moveY;
|
90 | var activeOrigin = blockPositions[orderMap[activeItem.key].order];
|
91 | var x = activeOrigin.x - x0;
|
92 | var y = activeOrigin.y - y0;
|
93 | activeItem.currentPosition.setOffset({
|
94 | x: x,
|
95 | y: y,
|
96 | });
|
97 | activeBlockOffset = {
|
98 | x: x,
|
99 | y: y,
|
100 | };
|
101 | activeItem.currentPosition.setValue({
|
102 | x: moveX,
|
103 | y: moveY,
|
104 | });
|
105 | }
|
106 | function onHandMove(_, gestureState) {
|
107 | var activeItem = getActiveItem();
|
108 | if (!activeItem)
|
109 | return false;
|
110 | var moveX = gestureState.moveX, moveY = gestureState.moveY;
|
111 | props.onDragging && props.onDragging(gestureState);
|
112 | var xChokeAmount = Math.max(0, activeBlockOffset.x + moveX - (gridLayout.width - blockWidth));
|
113 | var xMinChokeAmount = Math.min(0, activeBlockOffset.x + moveX);
|
114 | var dragPosition = {
|
115 | x: moveX - xChokeAmount - xMinChokeAmount,
|
116 | y: moveY,
|
117 | };
|
118 | var originPosition = blockPositions[orderMap[activeItem.key].order];
|
119 | var dragPositionToActivePositionDistance = getDistance(dragPosition, originPosition);
|
120 | activeItem.currentPosition.setValue(dragPosition);
|
121 | var closetItemIndex = activeItemIndex;
|
122 | var closetDistance = dragPositionToActivePositionDistance;
|
123 | items.forEach(function (item, index) {
|
124 | if (item.itemData.disabledReSorted)
|
125 | return;
|
126 | if (index != activeItemIndex) {
|
127 | var dragPositionToItemPositionDistance = getDistance(dragPosition, blockPositions[orderMap[item.key].order]);
|
128 | if (dragPositionToItemPositionDistance < closetDistance &&
|
129 | dragPositionToItemPositionDistance < blockWidth) {
|
130 | closetItemIndex = index;
|
131 | closetDistance = dragPositionToItemPositionDistance;
|
132 | }
|
133 | }
|
134 | });
|
135 | if (activeItemIndex != closetItemIndex) {
|
136 | var closetOrder = orderMap[items[closetItemIndex].key].order;
|
137 | resetBlockPositionByOrder(orderMap[activeItem.key].order, closetOrder);
|
138 | orderMap[activeItem.key].order = closetOrder;
|
139 | props.onResetSort && props.onResetSort(getSortData());
|
140 | }
|
141 | }
|
142 | function onHandRelease() {
|
143 | var activeItem = getActiveItem();
|
144 | if (!activeItem)
|
145 | return false;
|
146 | props.onDragRelease && props.onDragRelease(getSortData());
|
147 | setPanResponderCapture(false);
|
148 | activeItem.currentPosition.flattenOffset();
|
149 | moveBlockToBlockOrderPosition(activeItem.key);
|
150 | setActiveItemIndex(undefined);
|
151 | }
|
152 | function resetBlockPositionByOrder(activeItemOrder, insertedPositionOrder) {
|
153 | var disabledReSortedItemCount = 0;
|
154 | if (activeItemOrder > insertedPositionOrder) {
|
155 | for (var i = activeItemOrder - 1; i >= insertedPositionOrder; i--) {
|
156 | var key = getKeyByOrder(i);
|
157 | var item = itemMap[key];
|
158 | if (item && item.disabledReSorted) {
|
159 | disabledReSortedItemCount++;
|
160 | }
|
161 | else {
|
162 | orderMap[key].order += disabledReSortedItemCount + 1;
|
163 | disabledReSortedItemCount = 0;
|
164 | moveBlockToBlockOrderPosition(key);
|
165 | }
|
166 | }
|
167 | }
|
168 | else {
|
169 | for (var i = activeItemOrder + 1; i <= insertedPositionOrder; i++) {
|
170 | var key = getKeyByOrder(i);
|
171 | var item = itemMap[key];
|
172 | if (item && item.disabledReSorted) {
|
173 | disabledReSortedItemCount++;
|
174 | }
|
175 | else {
|
176 | orderMap[key].order -= disabledReSortedItemCount + 1;
|
177 | disabledReSortedItemCount = 0;
|
178 | moveBlockToBlockOrderPosition(key);
|
179 | }
|
180 | }
|
181 | }
|
182 | }
|
183 | function moveBlockToBlockOrderPosition(itemKey) {
|
184 | var itemIndex = utils_1.findIndex(items, function (item) { return "" + item.key === "" + itemKey; });
|
185 | items[itemIndex].currentPosition.flattenOffset();
|
186 | react_native_1.Animated.timing(items[itemIndex].currentPosition, {
|
187 | toValue: blockPositions[orderMap[itemKey].order],
|
188 | duration: 200,
|
189 | useNativeDriver: false,
|
190 | }).start();
|
191 | }
|
192 | function getKeyByOrder(order) {
|
193 | return utils_1.findKey(orderMap, function (item) { return item.order === order; });
|
194 | }
|
195 | function getSortData() {
|
196 | var sortData = [];
|
197 | items.forEach(function (item) {
|
198 | sortData[orderMap[item.key].order] = item.itemData;
|
199 | });
|
200 | return sortData;
|
201 | }
|
202 | function getDistance(startOffset, endOffset) {
|
203 | var xDistance = startOffset.x + activeBlockOffset.x - endOffset.x;
|
204 | var yDistance = startOffset.y + activeBlockOffset.y - endOffset.y;
|
205 | return Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
|
206 | }
|
207 | function setActiveBlock(itemIndex, item) {
|
208 | if (item.disabledDrag)
|
209 | return;
|
210 | props.onDragItemActive && props.onDragItemActive(item);
|
211 | setPanResponderCapture(true);
|
212 | setActiveItemIndex(itemIndex);
|
213 | }
|
214 | function startDragStartAnimation() {
|
215 | if (!props.dragStartAnimation) {
|
216 | dragStartAnimatedValue.setValue(1);
|
217 | react_native_1.Animated.timing(dragStartAnimatedValue, {
|
218 | toValue: 1.1,
|
219 | duration: 100,
|
220 | useNativeDriver: false,
|
221 | }).start();
|
222 | }
|
223 | }
|
224 | function getBlockStyle(itemIndex) {
|
225 | return [
|
226 | {
|
227 | justifyContent: 'center',
|
228 | alignItems: 'center',
|
229 | },
|
230 | hadInitBlockSize && {
|
231 | width: blockWidth,
|
232 | height: blockHeight,
|
233 | position: 'absolute',
|
234 | top: items[itemIndex].currentPosition.getLayout().top,
|
235 | left: items[itemIndex].currentPosition.getLayout().left,
|
236 | },
|
237 | ];
|
238 | }
|
239 | function getDragStartAnimation(itemIndex) {
|
240 | if (activeItemIndex != itemIndex) {
|
241 | return;
|
242 | }
|
243 | var dragStartAnimation = props.dragStartAnimation || getDefaultDragStartAnimation();
|
244 | return __assign({ zIndex: 3 }, dragStartAnimation);
|
245 | }
|
246 | function getActiveItem() {
|
247 | if (activeItemIndex === undefined)
|
248 | return false;
|
249 | return items[activeItemIndex];
|
250 | }
|
251 | function getDefaultDragStartAnimation() {
|
252 | return {
|
253 | transform: [
|
254 | {
|
255 | scale: dragStartAnimatedValue,
|
256 | },
|
257 | ],
|
258 | shadowColor: '#000000',
|
259 | shadowOpacity: 0.2,
|
260 | shadowRadius: 6,
|
261 | shadowOffset: {
|
262 | width: 1,
|
263 | height: 1,
|
264 | },
|
265 | };
|
266 | }
|
267 | function addItem(item, index) {
|
268 | blockPositions.push(getBlockPositionByOrder(items.length));
|
269 | orderMap[item.key] = {
|
270 | order: index,
|
271 | };
|
272 | itemMap[item.key] = item;
|
273 | items.push({
|
274 | key: item.key,
|
275 | itemData: item,
|
276 | currentPosition: new react_native_1.Animated.ValueXY(getBlockPositionByOrder(index)),
|
277 | });
|
278 | }
|
279 | function removeItem(item) {
|
280 | var itemIndex = utils_1.findIndex(items, function (curItem) { return curItem.key === item.key; });
|
281 | items.splice(itemIndex, 1);
|
282 | blockPositions.pop();
|
283 | delete orderMap[item.key];
|
284 | }
|
285 | function diffData() {
|
286 | props.data.forEach(function (item, index) {
|
287 | if (orderMap[item.key]) {
|
288 | if (orderMap[item.key].order != index) {
|
289 | orderMap[item.key].order = index;
|
290 | moveBlockToBlockOrderPosition(item.key);
|
291 | }
|
292 | var currentItem = items.find(function (i) { return i.key === item.key; });
|
293 | if (currentItem) {
|
294 | currentItem.itemData = item;
|
295 | }
|
296 | itemMap[item.key] = item;
|
297 | }
|
298 | else {
|
299 | addItem(item, index);
|
300 | }
|
301 | });
|
302 | var deleteItems = utils_1.differenceBy(items, props.data, 'key');
|
303 | deleteItems.forEach(function (item) {
|
304 | removeItem(item);
|
305 | });
|
306 | }
|
307 | react_1.useEffect(function () {
|
308 | startDragStartAnimation();
|
309 | }, [activeItemIndex]);
|
310 | react_1.useEffect(function () {
|
311 | if (hadInitBlockSize) {
|
312 | initBlockPositions();
|
313 | }
|
314 | }, [gridLayout]);
|
315 | react_1.useEffect(function () {
|
316 | resetGridHeight();
|
317 | });
|
318 | if (hadInitBlockSize) {
|
319 | diffData();
|
320 | }
|
321 | var itemList = items.map(function (item, itemIndex) {
|
322 | return (<block_1.Block onPress={onBlockPress.bind(null, itemIndex)} onLongPress={setActiveBlock.bind(null, itemIndex, item.itemData)} panHandlers={panResponder.panHandlers} style={getBlockStyle(itemIndex)} dragStartAnimationStyle={getDragStartAnimation(itemIndex)} delayLongPress={props.delayLongPress || 300} key={item.key}>
|
323 | {props.renderItem(item.itemData, orderMap[item.key].order)}
|
324 | </block_1.Block>);
|
325 | });
|
326 | return (<react_native_1.Animated.View style={[
|
327 | styles.draggableGrid,
|
328 | props.style,
|
329 | {
|
330 | height: gridHeight,
|
331 | },
|
332 | ]} onLayout={assessGridSize}>
|
333 | {hadInitBlockSize && itemList}
|
334 | </react_native_1.Animated.View>);
|
335 | };
|
336 | var styles = react_native_1.StyleSheet.create({
|
337 | draggableGrid: {
|
338 | flex: 1,
|
339 | flexDirection: 'row',
|
340 | flexWrap: 'wrap',
|
341 | },
|
342 | });
|
343 |
|
\ | No newline at end of file |