@rpg-engine/long-bow 0.7.68 → 0.7.70

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.
@@ -3,18 +3,12 @@ import React from 'react';
3
3
  import { RelativeListMenu } from '../../RelativeListMenu';
4
4
  import { ItemTooltip } from '../Cards/ItemTooltip';
5
5
  import { MobileItemTooltip } from '../Cards/MobileItemTooltip';
6
- import { IContextMenuItem } from './itemContainerHelper';
7
- import type { ContextMenuState, TooltipState } from './ItemSlot';
6
+ import { useItemSlotTooltip } from './context/ItemSlotTooltipContext';
8
7
 
9
8
  interface IProps {
10
- tooltipState: TooltipState;
11
- setTooltipState: React.Dispatch<React.SetStateAction<TooltipState>>;
12
- contextMenuState: ContextMenuState;
13
- setContextMenuState: React.Dispatch<React.SetStateAction<ContextMenuState>>;
14
9
  isFocused: boolean;
15
10
  isContextMenuDisabled: boolean;
16
- item: IItem | null;
17
- contextActions: IContextMenuItem[];
11
+
18
12
  dragScale: number | undefined;
19
13
  onSelected?: (optionId: string, item: IItem) => void;
20
14
  atlasIMG: any;
@@ -23,23 +17,48 @@ interface IProps {
23
17
  }
24
18
 
25
19
  export const ItemSlotToolTips = ({
26
- tooltipState,
27
- setTooltipState,
28
- contextMenuState,
29
- setContextMenuState,
30
20
  isFocused,
31
21
  isContextMenuDisabled,
32
- item,
33
- contextActions,
22
+
34
23
  dragScale,
35
24
  onSelected,
36
25
  atlasIMG,
37
26
  atlasJSON,
38
27
  equipmentSet,
39
28
  }: IProps): JSX.Element => {
29
+ const { itemDetails, updateItemDetails } = useItemSlotTooltip();
30
+
31
+ const item = itemDetails.item;
32
+
33
+ const handleCloseTooltip = () => {
34
+ updateItemDetails({
35
+ item,
36
+ tooltip: { mobileVisible: false },
37
+ });
38
+ };
39
+
40
+ const handleContextMenuSelect = (optionId: string) => {
41
+ updateItemDetails({
42
+ item,
43
+ contextMenu: { visible: false },
44
+ });
45
+ if (item) {
46
+ onSelected?.(optionId, item);
47
+ }
48
+ };
49
+
50
+ const handleOutsideClick = () => {
51
+ updateItemDetails({
52
+ item,
53
+ contextMenu: { visible: false },
54
+ });
55
+ };
56
+
57
+ // monitor why mobileVisible is not working
58
+
40
59
  return (
41
60
  <>
42
- {tooltipState.visible && item && !isFocused && (
61
+ {itemDetails.tooltip?.visible && item && !isFocused && (
43
62
  <ItemTooltip
44
63
  item={item}
45
64
  atlasIMG={atlasIMG}
@@ -48,42 +67,29 @@ export const ItemSlotToolTips = ({
48
67
  />
49
68
  )}
50
69
 
51
- {tooltipState.mobileVisible && item && (
70
+ {itemDetails.tooltip?.mobileVisible && item && (
52
71
  <MobileItemTooltip
53
72
  item={item}
54
73
  atlasIMG={atlasIMG}
55
74
  atlasJSON={atlasJSON}
56
75
  equipmentSet={equipmentSet}
57
- closeTooltip={() => {
58
- setTooltipState(prev => ({ ...prev, mobileVisible: false }));
59
- }}
76
+ closeTooltip={handleCloseTooltip}
60
77
  scale={dragScale}
61
- options={contextActions}
62
- onSelected={(optionId: string) => {
63
- setContextMenuState(prev => ({ ...prev, visible: false }));
64
- if (item) {
65
- onSelected?.(optionId, item);
66
- }
67
- }}
78
+ options={itemDetails.contextMenu?.actions || []}
79
+ onSelected={handleContextMenuSelect}
68
80
  />
69
81
  )}
70
82
 
71
- {!isContextMenuDisabled && contextMenuState.visible && contextActions && (
72
- <RelativeListMenu
73
- options={contextActions}
74
- onSelected={(optionId: string) => {
75
- setContextMenuState(prev => ({ ...prev, visible: false }));
76
-
77
- if (item) {
78
- onSelected?.(optionId, item);
79
- }
80
- }}
81
- onOutsideClick={() => {
82
- setContextMenuState(prev => ({ ...prev, visible: false }));
83
- }}
84
- pos={contextMenuState.position}
85
- />
86
- )}
83
+ {!isContextMenuDisabled &&
84
+ itemDetails.contextMenu?.visible &&
85
+ itemDetails.contextMenu.actions && (
86
+ <RelativeListMenu
87
+ options={itemDetails.contextMenu.actions}
88
+ onSelected={handleContextMenuSelect}
89
+ onOutsideClick={handleOutsideClick}
90
+ pos={itemDetails.contextMenu.position!}
91
+ />
92
+ )}
87
93
  </>
88
94
  );
89
95
  };
@@ -1,21 +1,21 @@
1
1
  import { IItem } from '@rpg-engine/shared';
2
2
  import React, { createContext, useContext, useState } from 'react';
3
3
 
4
- export interface DragState {
4
+ export interface IDragState {
5
5
  isFocused: boolean;
6
6
  wasDragged: boolean;
7
7
  position: { x: number; y: number };
8
8
  dropPosition: { x: number; y: number } | null;
9
9
  }
10
10
 
11
- interface DraggingContextType {
11
+ interface IDraggingContextType {
12
12
  item: IItem | null;
13
13
  setDraggingItem: React.Dispatch<React.SetStateAction<IItem | null>>;
14
- dragState: DragState;
15
- setDragState: React.Dispatch<React.SetStateAction<DragState>>;
14
+ dragState: IDragState;
15
+ setDragState: React.Dispatch<React.SetStateAction<IDragState>>;
16
16
  }
17
17
 
18
- const DraggingContext = createContext<DraggingContextType>({
18
+ const ItemSlotDraggingContext = createContext<IDraggingContextType>({
19
19
  item: null,
20
20
  setDraggingItem: () => {},
21
21
  dragState: {
@@ -31,9 +31,9 @@ interface IProps {
31
31
  children: React.ReactNode;
32
32
  }
33
33
 
34
- export const DraggingProvider = ({ children }: IProps) => {
34
+ export const ItemSlotDraggingProvider = ({ children }: IProps) => {
35
35
  const [item, setDraggingItem] = useState<IItem | null>(null);
36
- const [dragState, setDragState] = useState<DragState>({
36
+ const [dragState, setDragState] = useState<IDragState>({
37
37
  isFocused: false,
38
38
  wasDragged: false,
39
39
  position: { x: 0, y: 0 },
@@ -41,12 +41,12 @@ export const DraggingProvider = ({ children }: IProps) => {
41
41
  });
42
42
 
43
43
  return (
44
- <DraggingContext.Provider
44
+ <ItemSlotDraggingContext.Provider
45
45
  value={{ item, setDraggingItem, dragState, setDragState }}
46
46
  >
47
47
  {children}
48
- </DraggingContext.Provider>
48
+ </ItemSlotDraggingContext.Provider>
49
49
  );
50
50
  };
51
51
 
52
- export const useDragging = () => useContext(DraggingContext);
52
+ export const useItemSlotDragging = () => useContext(ItemSlotDraggingContext);
@@ -0,0 +1,95 @@
1
+ import { IItem } from '@rpg-engine/shared';
2
+ import React, {
3
+ createContext,
4
+ FC,
5
+ ReactNode,
6
+ useCallback,
7
+ useContext,
8
+ useEffect,
9
+ useState,
10
+ } from 'react';
11
+ import { IPosition } from '../../../../types/eventTypes';
12
+ import { IContextMenuItem } from '../itemContainerHelper';
13
+
14
+ // Define smaller, focused interfaces for better readability
15
+ interface TooltipState {
16
+ visible?: boolean;
17
+ mobileVisible?: boolean;
18
+ }
19
+
20
+ interface ContextMenuState {
21
+ visible?: boolean;
22
+ position?: IPosition;
23
+ actions?: IContextMenuItem[];
24
+ }
25
+
26
+ interface ItemDetails {
27
+ item?: IItem | null;
28
+ tooltip?: TooltipState;
29
+ contextMenu?: ContextMenuState;
30
+ }
31
+
32
+ interface ItemSlotTooltipContextProps {
33
+ itemDetails: ItemDetails;
34
+ updateItemDetails: (updates: Partial<ItemDetails>) => void;
35
+ clearItemDetails: () => void;
36
+ }
37
+
38
+ // Set default state with clearly defined initial values
39
+ const defaultItemDetails: ItemDetails = {
40
+ item: null,
41
+ tooltip: { visible: false, mobileVisible: false },
42
+ contextMenu: { visible: false, position: { x: 0, y: 0 }, actions: [] },
43
+ };
44
+
45
+ // Create context with default values
46
+ const ItemSlotTooltipContext = createContext<ItemSlotTooltipContextProps>({
47
+ itemDetails: defaultItemDetails,
48
+ updateItemDetails: () => {},
49
+ clearItemDetails: () => {},
50
+ });
51
+
52
+ // Provider component
53
+ export const ItemSlotTooltipProvider: FC<{ children: ReactNode }> = ({
54
+ children,
55
+ }) => {
56
+ const [itemDetails, setItemDetails] = useState<ItemDetails>(
57
+ defaultItemDetails
58
+ );
59
+
60
+ useEffect(() => {
61
+ console.log('itemDetails', itemDetails);
62
+ }, [itemDetails]);
63
+
64
+ // Memoize the update function to optimize performance
65
+ const updateItemDetails = useCallback((updates: Partial<ItemDetails>) => {
66
+ setItemDetails(prev => ({
67
+ ...prev,
68
+ ...updates,
69
+ tooltip: { ...prev.tooltip, ...updates.tooltip },
70
+ contextMenu: {
71
+ ...prev.contextMenu,
72
+ ...updates.contextMenu,
73
+ // Ensure actions are properly merged or overridden
74
+ actions: updates.contextMenu?.actions ?? prev.contextMenu?.actions,
75
+ },
76
+ }));
77
+ }, []);
78
+
79
+ const clearItemDetails = useCallback(() => {
80
+ setItemDetails(defaultItemDetails);
81
+ }, []);
82
+
83
+ return (
84
+ <ItemSlotTooltipContext.Provider
85
+ value={{ itemDetails, updateItemDetails, clearItemDetails }}
86
+ >
87
+ {children}
88
+ </ItemSlotTooltipContext.Provider>
89
+ );
90
+ };
91
+
92
+ // Custom hook for consuming the context
93
+ export const useItemSlotTooltip = (): ItemSlotTooltipContextProps => {
94
+ return useContext(ItemSlotTooltipContext);
95
+ };
@@ -1,8 +1,8 @@
1
1
  import { IItem, ItemContainerType, ItemType } from '@rpg-engine/shared';
2
2
  import { useCallback, useEffect, useRef } from 'react';
3
3
  import { DraggableEventHandler } from 'react-draggable';
4
- import { useDragging } from '../context/DraggingContext';
5
- import { ContextMenuState, TooltipState } from '../ItemSlot';
4
+ import { useItemSlotDragging } from '../context/ItemSlotDraggingContext';
5
+ import { useItemSlotTooltip } from '../context/ItemSlotTooltipContext';
6
6
 
7
7
  interface IUseItemSlotDragAndDrop {
8
8
  isDepotSystem: boolean;
@@ -30,9 +30,6 @@ interface IUseItemSlotDragAndDrop {
30
30
  onSuccess: (quantity?: number) => void
31
31
  ) => void;
32
32
  isContextMenuDisabled: boolean;
33
- setTooltipState: React.Dispatch<React.SetStateAction<TooltipState>>;
34
- setContextMenuState: React.Dispatch<React.SetStateAction<ContextMenuState>>;
35
- contextMenuState: ContextMenuState;
36
33
  }
37
34
 
38
35
  export const useItemSlotDragAndDrop = ({
@@ -50,8 +47,6 @@ export const useItemSlotDragAndDrop = ({
50
47
  slotIndex,
51
48
  openQuantitySelector,
52
49
  isContextMenuDisabled,
53
- setTooltipState,
54
- setContextMenuState,
55
50
  }: IUseItemSlotDragAndDrop) => {
56
51
  const dragContainer = useRef<HTMLDivElement>(null);
57
52
  const {
@@ -59,7 +54,9 @@ export const useItemSlotDragAndDrop = ({
59
54
  setDraggingItem,
60
55
  dragState,
61
56
  setDragState,
62
- } = useDragging();
57
+ } = useItemSlotDragging();
58
+
59
+ const { updateItemDetails, itemDetails } = useItemSlotTooltip();
63
60
 
64
61
  useEffect(() => {
65
62
  setDragState(prev => ({
@@ -89,16 +86,24 @@ export const useItemSlotDragAndDrop = ({
89
86
  }, []);
90
87
 
91
88
  const resetDragState = useCallback(() => {
89
+ console.log('RESET_DRAG_STATE!');
92
90
  setDragState(prev => ({
93
91
  ...prev,
94
92
  wasDragged: false,
95
93
  isFocused: false,
96
94
  position: { x: 0, y: 0 },
97
95
  }));
98
- }, [setTooltipState, setDragState]);
96
+ setDraggingItem(null);
97
+
98
+ // Reset tooltip visibility
99
+ updateItemDetails({
100
+ tooltip: { visible: false, mobileVisible: false },
101
+ });
102
+ }, [updateItemDetails, setDragState]);
99
103
 
100
104
  const handleSuccessfulDrag = useCallback(
101
105
  (quantity?: number) => {
106
+ console.log('HANDLE_SUCCESSFUL_DRAG!');
102
107
  resetDragState();
103
108
  if (quantity !== -1 && item) {
104
109
  onDragEnd?.(quantity);
@@ -108,31 +113,35 @@ export const useItemSlotDragAndDrop = ({
108
113
  );
109
114
 
110
115
  const onDraggableStart: DraggableEventHandler = useCallback(() => {
116
+ console.log('ON_DRAGGABLE_START!');
111
117
  if (!item || isSelectingShortcut) return;
112
118
  if (onDragStart && containerType) {
113
119
  onDragStart(item, slotIndex, containerType);
114
120
  }
121
+
122
+ if (!draggingItem && item) {
123
+ console.log('!!! SETTING DRAGGING ITEM ', item._id);
124
+ setDraggingItem(item);
125
+ }
115
126
  }, [item, isSelectingShortcut, onDragStart, containerType, slotIndex]);
116
127
 
117
128
  const onDraggableProgress: DraggableEventHandler = useCallback(
118
129
  (_e, data) => {
130
+ console.log('ON_DRAGGABLE_PROGRESS!');
119
131
  const { x, y } = dragState.position;
120
132
  if (Math.abs(data.x - x) > 5 || Math.abs(data.y - y) > 5) {
121
133
  setDragState(prev => ({ ...prev, wasDragged: true, isFocused: true }));
122
134
  }
123
- if (!draggingItem) {
124
- setDraggingItem(item);
125
- }
126
135
  },
127
136
  [dragState.position, draggingItem, item, setDraggingItem, setDragState]
128
137
  );
129
138
 
130
139
  const onDraggableStop: DraggableEventHandler = useCallback(
131
140
  (e, data) => {
132
- setTimeout(() => {
133
- setDraggingItem(null);
134
- }, 50);
141
+ console.log('ON_DRAGGABLE_STOP!');
142
+
135
143
  const target = e.target as HTMLElement;
144
+
136
145
  if (!target) return;
137
146
 
138
147
  target.classList.remove('react-draggable-dragging');
@@ -175,26 +184,39 @@ export const useItemSlotDragAndDrop = ({
175
184
  }, 50);
176
185
  } else if (item) {
177
186
  const isTouch = e.type === 'touchend';
178
- if (
179
- !isContextMenuDisabled &&
180
- isTouch &&
181
- !isSelectingShortcut &&
182
- !draggingItem
183
- ) {
184
- setTooltipState(prev => ({ ...prev, mobileVisible: true }));
187
+
188
+ console.log(`Debug:
189
+ isTouch: ${isTouch},
190
+ isSelectingShortcut: ${isSelectingShortcut},
191
+ draggingItem: ${draggingItem},
192
+ dragginState: ${JSON.stringify(dragState)}
193
+ `);
194
+
195
+ if (!isContextMenuDisabled && isTouch && !isSelectingShortcut) {
196
+ updateItemDetails({
197
+ item,
198
+ tooltip: { mobileVisible: true },
199
+ });
185
200
  } else if (!isContextMenuDisabled && !isSelectingShortcut && !isTouch) {
186
201
  const event = e as MouseEvent;
187
- setContextMenuState(prev => ({
188
- visible: !prev.visible,
189
- position: {
190
- x: event.clientX - 10,
191
- y: event.clientY - 5,
202
+
203
+ updateItemDetails({
204
+ item,
205
+ contextMenu: {
206
+ visible: !itemDetails?.contextMenu?.visible,
207
+ position: {
208
+ x: event.clientX - 10,
209
+ y: event.clientY - 5,
210
+ },
192
211
  },
193
- }));
212
+ });
194
213
  }
195
214
 
196
215
  onPointerDown?.(item.type, containerType ?? null, item);
197
216
  }
217
+
218
+ console.log('setting draggingItem to null');
219
+ setDraggingItem(null);
198
220
  },
199
221
  [
200
222
  dragState.wasDragged,
@@ -206,8 +228,6 @@ export const useItemSlotDragAndDrop = ({
206
228
  handleSuccessfulDrag,
207
229
  resetDragState,
208
230
  isContextMenuDisabled,
209
- setTooltipState,
210
- setContextMenuState,
211
231
  onPointerDown,
212
232
  containerType,
213
233
  setItemShortcut,
@@ -6,37 +6,46 @@ interface ICursorPositionProps {
6
6
  scale?: number;
7
7
  }
8
8
 
9
- export const useCursorPosition = ({ scale = 1 }: ICursorPositionProps): IPosition => {
9
+ export const useCursorPosition = ({
10
+ scale = 1,
11
+ }: ICursorPositionProps): IPosition => {
10
12
  const [position, setPosition] = useState<IPosition>({ x: 0, y: 0 });
11
13
 
12
- const scalePosition = useCallback((x: number, y: number): IPosition => {
13
- return {
14
- x: ((x - GRID_WIDTH / 2) / scale) + GRID_WIDTH / 2,
15
- y: ((y - GRID_HEIGHT / 2) / scale) + GRID_HEIGHT / 2,
16
- };
17
- }, [scale]);
14
+ const scalePosition = useCallback(
15
+ (x: number, y: number): IPosition => {
16
+ return {
17
+ x: (x - GRID_WIDTH / 2) / scale + GRID_WIDTH / 2,
18
+ y: (y - GRID_HEIGHT / 2) / scale + GRID_HEIGHT / 2,
19
+ };
20
+ },
21
+ [scale]
22
+ );
18
23
 
19
- const setFromEvent = useCallback((e: MouseEvent | TouchEvent) => {
20
- let x, y;
24
+ const setFromEvent = useCallback(
25
+ (e: MouseEvent | TouchEvent) => {
26
+ let x, y;
21
27
 
22
- if ('touches' in e) {
23
- x = e.touches[0].clientX;
24
- y = e.touches[0].clientY;
25
- } else {
26
- x = e.clientX;
27
- y = e.clientY;
28
- }
28
+ if ('touches' in e) {
29
+ x = e.touches[0].clientX;
30
+ y = e.touches[0].clientY;
31
+ } else {
32
+ x = e.clientX;
33
+ y = e.clientY;
34
+ }
29
35
 
30
- const scaledPosition = scalePosition(x, y);
31
- setPosition(scaledPosition);
32
- }, [scale, scalePosition]);
36
+ const scaledPosition = scalePosition(x, y);
37
+ setPosition(scaledPosition);
38
+ },
39
+ [scale, scalePosition]
40
+ );
33
41
 
34
42
  const cleanup = useCallback(() => {
35
43
  setPosition({ x: 0, y: 0 });
36
44
  }, []);
37
45
 
38
46
  useEffect(() => {
39
- const handleEvent = (e: Event) => setFromEvent(e as MouseEvent | TouchEvent);
47
+ const handleEvent = (e: Event) =>
48
+ setFromEvent(e as MouseEvent | TouchEvent);
40
49
 
41
50
  window.addEventListener('mousemove', handleEvent);
42
51
  window.addEventListener('touchmove', handleEvent);
@@ -5,10 +5,6 @@ import {
5
5
  getXPForLevel,
6
6
  } from '@rpg-engine/shared';
7
7
 
8
- for (let level = 2; level <= 20; level++) {
9
- console.log(`SP for level ${level}: ${getSPForLevel(level)}`);
10
- }
11
-
12
8
  export const skillMock = {
13
9
  _id: '62aebda8785a9f0089a4f757',
14
10
  stamina: {