@rpg-engine/long-bow 0.5.35 → 0.5.37
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/hooks/useScrollOnDrag.d.ts +11 -0
- package/dist/long-bow.cjs.development.js +99 -10
- package/dist/long-bow.cjs.development.js.map +1 -1
- package/dist/long-bow.cjs.production.min.js +1 -1
- package/dist/long-bow.cjs.production.min.js.map +1 -1
- package/dist/long-bow.esm.js +99 -10
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Item/Inventory/ItemContainer.tsx +72 -11
- package/src/components/RPGUI/RPGUIScrollbar.tsx +2 -2
- package/src/hooks/useScrollOnDrag.ts +78 -0
package/package.json
CHANGED
|
@@ -6,10 +6,11 @@ import {
|
|
|
6
6
|
ItemContainerType,
|
|
7
7
|
ItemType,
|
|
8
8
|
} from '@rpg-engine/shared';
|
|
9
|
-
import React, { useState } from 'react';
|
|
9
|
+
import React, { useCallback, useRef, useState } from 'react';
|
|
10
10
|
import styled from 'styled-components';
|
|
11
11
|
import { SlotsContainer } from '../../Abstractions/SlotsContainer';
|
|
12
12
|
|
|
13
|
+
import { useScrollOnDrag } from '../../../hooks/useScrollOnDrag';
|
|
13
14
|
import { IPosition } from '../../../types/eventTypes';
|
|
14
15
|
import { ShortcutsSetter } from '../../Shortcuts/ShortcutsSetter';
|
|
15
16
|
import { DraggedItem } from './DraggedItem';
|
|
@@ -56,6 +57,15 @@ export interface IItemContainerProps {
|
|
|
56
57
|
onPositionChangeStart?: (position: IPosition) => void;
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
type onDragStart =
|
|
61
|
+
| ((
|
|
62
|
+
item: IItem,
|
|
63
|
+
slotIndex: number,
|
|
64
|
+
itemContainerType: ItemContainerType | null
|
|
65
|
+
) => void)
|
|
66
|
+
| undefined;
|
|
67
|
+
type onDragEnd = ((quantity?: number) => void) | undefined;
|
|
68
|
+
|
|
59
69
|
export const ItemContainer: React.FC<IItemContainerProps> = ({
|
|
60
70
|
itemContainer,
|
|
61
71
|
onClose,
|
|
@@ -89,12 +99,57 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
|
|
|
89
99
|
});
|
|
90
100
|
const [settingShortcutIndex, setSettingShortcutIndex] = useState(-1);
|
|
91
101
|
|
|
102
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
103
|
+
|
|
104
|
+
const { startScrolling, stopScrolling } = useScrollOnDrag({
|
|
105
|
+
containerRef,
|
|
106
|
+
threshold: 50,
|
|
107
|
+
scrollStep: 4,
|
|
108
|
+
});
|
|
109
|
+
|
|
92
110
|
const handleSetShortcut = (item: IItem, index: number) => {
|
|
93
111
|
if (item.type === ItemType.Consumable || item.type === ItemType.Tool) {
|
|
94
112
|
setItemShortcut?.(item.key, index);
|
|
95
113
|
}
|
|
96
114
|
};
|
|
97
115
|
|
|
116
|
+
const handleMouseMove = useCallback(
|
|
117
|
+
(e: MouseEvent) => {
|
|
118
|
+
startScrolling(e.clientY);
|
|
119
|
+
},
|
|
120
|
+
[startScrolling]
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const onDragStartScrollingEvents = useCallback(() => {
|
|
124
|
+
document.addEventListener('pointermove', handleMouseMove);
|
|
125
|
+
document.addEventListener('pointerup', () => {
|
|
126
|
+
stopScrolling();
|
|
127
|
+
document.removeEventListener('pointermove', handleMouseMove);
|
|
128
|
+
});
|
|
129
|
+
}, [handleMouseMove, onItemDragStart, stopScrolling]);
|
|
130
|
+
|
|
131
|
+
const onDragEndScrollingEvents = useCallback(() => {
|
|
132
|
+
stopScrolling();
|
|
133
|
+
document.removeEventListener('pointermove', handleMouseMove);
|
|
134
|
+
}, [handleMouseMove, onItemDragStart, stopScrolling]);
|
|
135
|
+
|
|
136
|
+
const onDragStart: onDragStart = (item, slotIndex, itemContainerType) => {
|
|
137
|
+
console.log('DRAG START');
|
|
138
|
+
if (onItemDragStart) {
|
|
139
|
+
onItemDragStart(item, slotIndex, itemContainerType);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
onDragStartScrollingEvents();
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const onDragEnd: onDragEnd = quantity => {
|
|
146
|
+
console.log('DRAG END');
|
|
147
|
+
if (onItemDragEnd) {
|
|
148
|
+
onItemDragEnd(quantity);
|
|
149
|
+
}
|
|
150
|
+
onDragEndScrollingEvents();
|
|
151
|
+
};
|
|
152
|
+
|
|
98
153
|
const onRenderSlots = () => {
|
|
99
154
|
const slots = [];
|
|
100
155
|
|
|
@@ -119,13 +174,8 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
|
|
|
119
174
|
onSelected={(optionId: string, item: IItem) => {
|
|
120
175
|
if (onSelected) onSelected(optionId, item);
|
|
121
176
|
}}
|
|
122
|
-
onDragStart={
|
|
123
|
-
|
|
124
|
-
onItemDragStart(item, slotIndex, itemContainerType);
|
|
125
|
-
}}
|
|
126
|
-
onDragEnd={quantity => {
|
|
127
|
-
if (onItemDragEnd) onItemDragEnd(quantity);
|
|
128
|
-
}}
|
|
177
|
+
onDragStart={onDragStart}
|
|
178
|
+
onDragEnd={onDragEnd}
|
|
129
179
|
dragScale={scale}
|
|
130
180
|
checkIfItemCanBeMoved={checkIfItemCanBeMoved}
|
|
131
181
|
checkIfItemShouldDragEnd={checkIfItemShouldDragEnd}
|
|
@@ -137,11 +187,22 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
|
|
|
137
187
|
});
|
|
138
188
|
}}
|
|
139
189
|
onPlaceDrop={(item, slotIndex, itemContainerType) => {
|
|
140
|
-
if (onItemPlaceDrop)
|
|
190
|
+
if (onItemPlaceDrop) {
|
|
141
191
|
onItemPlaceDrop(item, slotIndex, itemContainerType);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
console.log('PLACE DROP');
|
|
195
|
+
|
|
196
|
+
onDragEndScrollingEvents();
|
|
142
197
|
}}
|
|
143
198
|
onOutsideDrop={(item, position) => {
|
|
144
|
-
if (onOutsideDrop)
|
|
199
|
+
if (onOutsideDrop) {
|
|
200
|
+
onOutsideDrop(item, position);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
console.log('OUTSIDE DROP');
|
|
204
|
+
|
|
205
|
+
onDragEndScrollingEvents();
|
|
145
206
|
}}
|
|
146
207
|
atlasIMG={atlasIMG}
|
|
147
208
|
atlasJSON={atlasJSON}
|
|
@@ -180,7 +241,7 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
|
|
|
180
241
|
atlasJSON={atlasJSON}
|
|
181
242
|
/>
|
|
182
243
|
)}
|
|
183
|
-
<ItemsContainer className="item-container-body">
|
|
244
|
+
<ItemsContainer className="item-container-body" ref={containerRef}>
|
|
184
245
|
{onRenderSlots()}
|
|
185
246
|
</ItemsContainer>
|
|
186
247
|
</SlotsContainer>
|
|
@@ -14,11 +14,11 @@ const Container = styled.div`
|
|
|
14
14
|
|
|
15
15
|
.rpgui-content ::-webkit-scrollbar,
|
|
16
16
|
.rpgui-content::-webkit-scrollbar {
|
|
17
|
-
width: 25px;
|
|
17
|
+
width: 25px !important;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
.rpgui-content ::-webkit-scrollbar-track,
|
|
21
21
|
.rpgui-content::-webkit-scrollbar-track {
|
|
22
|
-
background-size: 25px 60px;
|
|
22
|
+
background-size: 25px 60px !important;
|
|
23
23
|
}
|
|
24
24
|
`;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useCallback, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
interface IUseScrollOnDragProps {
|
|
4
|
+
containerRef: React.RefObject<HTMLDivElement>;
|
|
5
|
+
threshold: number;
|
|
6
|
+
scrollStep: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const useScrollOnDrag = ({
|
|
10
|
+
containerRef,
|
|
11
|
+
threshold,
|
|
12
|
+
scrollStep,
|
|
13
|
+
}: IUseScrollOnDragProps) => {
|
|
14
|
+
const animationFrameId = useRef<number | null>(null);
|
|
15
|
+
|
|
16
|
+
const startScrolling = useCallback(
|
|
17
|
+
(clientY: number) => {
|
|
18
|
+
const scroll = () => {
|
|
19
|
+
if (containerRef.current) {
|
|
20
|
+
const { top, bottom } = containerRef.current.getBoundingClientRect();
|
|
21
|
+
|
|
22
|
+
const maxScrollTop =
|
|
23
|
+
containerRef.current.scrollHeight -
|
|
24
|
+
containerRef.current.clientHeight;
|
|
25
|
+
const distanceFromTop = clientY - top;
|
|
26
|
+
const distanceFromBottom = bottom - clientY;
|
|
27
|
+
|
|
28
|
+
if (
|
|
29
|
+
distanceFromTop < threshold &&
|
|
30
|
+
containerRef.current.scrollTop > 0
|
|
31
|
+
) {
|
|
32
|
+
containerRef.current.scrollTop -= scrollStep;
|
|
33
|
+
animationFrameId.current = requestAnimationFrame(scroll);
|
|
34
|
+
} else if (
|
|
35
|
+
distanceFromBottom < threshold &&
|
|
36
|
+
containerRef.current.scrollTop < maxScrollTop
|
|
37
|
+
) {
|
|
38
|
+
containerRef.current.scrollTop += scrollStep;
|
|
39
|
+
animationFrameId.current = requestAnimationFrame(scroll);
|
|
40
|
+
} else {
|
|
41
|
+
// Check if we are near the bottom of the container
|
|
42
|
+
if (containerRef.current.scrollTop >= maxScrollTop) {
|
|
43
|
+
// You can perform any action here when the scroll hits the bottom.
|
|
44
|
+
} else {
|
|
45
|
+
// Check if we are near the top of the container
|
|
46
|
+
if (containerRef.current.scrollTop <= 0) {
|
|
47
|
+
// You can perform any action here when the scroll hits the top.
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Stop scrolling if neither condition is met
|
|
51
|
+
stopScrolling();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const stopScrolling = () => {
|
|
57
|
+
if (animationFrameId.current !== null) {
|
|
58
|
+
cancelAnimationFrame(animationFrameId.current);
|
|
59
|
+
animationFrameId.current = null;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
//@ts-ignore
|
|
64
|
+
cancelAnimationFrame(animationFrameId.current); // Cancel any existing animation frame
|
|
65
|
+
animationFrameId.current = requestAnimationFrame(scroll);
|
|
66
|
+
},
|
|
67
|
+
[containerRef, threshold, scrollStep]
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const stopScrolling = useCallback(() => {
|
|
71
|
+
if (animationFrameId.current !== null) {
|
|
72
|
+
cancelAnimationFrame(animationFrameId.current);
|
|
73
|
+
animationFrameId.current = null;
|
|
74
|
+
}
|
|
75
|
+
}, []);
|
|
76
|
+
|
|
77
|
+
return { startScrolling, stopScrolling };
|
|
78
|
+
};
|