@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpg-engine/long-bow",
3
- "version": "0.5.35",
3
+ "version": "0.5.37",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -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={(item, slotIndex, itemContainerType) => {
123
- if (onItemDragStart)
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) onOutsideDrop(item, position);
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
+ };