@rpg-engine/long-bow 0.5.23 → 0.5.26

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.
@@ -1,3 +1,3 @@
1
1
  import { IItem, IItemContainer } from '@rpg-engine/shared';
2
2
  export declare const items: IItem[];
3
- export declare const itemContainerMock: IItemContainer;
3
+ export declare const itemContainerMock: (props?: Record<string, unknown> | undefined) => IItemContainer;
@@ -1,5 +1,12 @@
1
+ import { ItemContainerType } from '@rpg-engine/shared';
1
2
  import { Meta } from '@storybook/react';
2
3
  import { IItemContainerProps } from '../../src/components/Item/Inventory/ItemContainer';
3
4
  declare const meta: Meta;
4
5
  export default meta;
5
- export declare const Default: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, IItemContainerProps>;
6
+ interface ITemplateProps {
7
+ type: ItemContainerType;
8
+ scale?: number;
9
+ }
10
+ export declare const Inventory: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, IItemContainerProps & ITemplateProps>;
11
+ export declare const InventoryScaledDown: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, IItemContainerProps & ITemplateProps>;
12
+ export declare const Depot: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, IItemContainerProps & ITemplateProps>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpg-engine/long-bow",
3
- "version": "0.5.23",
3
+ "version": "0.5.26",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -162,7 +162,7 @@ export const EquipmentSet: React.FC<IEquipmentSetProps> = ({
162
162
 
163
163
  return (
164
164
  <DraggingProvider>
165
- <DraggedItem atlasIMG={atlasIMG} atlasJSON={atlasJSON} />
165
+ <DraggedItem atlasIMG={atlasIMG} atlasJSON={atlasJSON} scale={scale} />
166
166
  <DraggableContainer
167
167
  title={'Equipments'}
168
168
  type={RPGUIContainerTypes.Framed}
@@ -1,7 +1,7 @@
1
1
  import { getItemTextureKeyPath } from '@rpg-engine/shared';
2
2
  import React from 'react';
3
3
  import styled from 'styled-components';
4
- import { useCursorPosition } from '../../../hooks/useMousePosition';
4
+ import { useCursorPosition } from '../../../hooks/useCursorPosition';
5
5
  import { SpriteFromAtlas } from '../../shared/SpriteFromAtlas';
6
6
  import { onRenderStackInfo } from './ItemSlotQty/ItemSlotQty';
7
7
  import { useDragging } from './context/DraggingContext';
@@ -12,14 +12,18 @@ const OFFSET = CONTAINER_SIZE / 2;
12
12
  interface IProps {
13
13
  atlasJSON: any;
14
14
  atlasIMG: any;
15
+ scale?: number;
15
16
  }
16
17
 
17
18
  export const DraggedItem = ({
18
19
  atlasJSON,
19
20
  atlasIMG,
21
+ scale,
20
22
  }: IProps): JSX.Element | null => {
21
23
  const { item } = useDragging();
22
- const { x, y } = useCursorPosition();
24
+ const { x, y } = useCursorPosition({
25
+ scale,
26
+ });
23
27
 
24
28
  if (!item) {
25
29
  return null;
@@ -159,7 +159,7 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
159
159
 
160
160
  return (
161
161
  <DraggingProvider>
162
- <DraggedItem atlasIMG={atlasIMG} atlasJSON={atlasJSON} />
162
+ <DraggedItem atlasIMG={atlasIMG} atlasJSON={atlasJSON} scale={scale} />
163
163
  <SlotsContainer
164
164
  title={itemContainer.name || 'Container'}
165
165
  onClose={onClose}
@@ -83,6 +83,8 @@ export const ItemSlotRenderer: React.FC<IProps> = ({
83
83
  return renderEquipment(itemToRender);
84
84
  case ItemContainerType.Inventory:
85
85
  return renderItem(itemToRender);
86
+ case ItemContainerType.Depot:
87
+ return renderItem(itemToRender);
86
88
  default:
87
89
  return null;
88
90
  }
@@ -5,4 +5,4 @@ export const SHORTCUTS_STORAGE_KEY = 'shortcuts';
5
5
  export const defaultShortcut: IShortcut = {
6
6
  type: ShortcutType.None,
7
7
  payload: null,
8
- };
8
+ };
@@ -0,0 +1,22 @@
1
+ import styled, { css } from 'styled-components';
2
+ import { UI_BREAKPOINT_MOBILE } from '../../constants/uiBreakpoints';
3
+
4
+ interface IScalableContainerProps {
5
+ scale?: number;
6
+ centralize?: boolean;
7
+ breakPoint?: string;
8
+ }
9
+
10
+ export const ScalableContainer = styled.div<IScalableContainerProps>`
11
+ ${({ centralize = true }) =>
12
+ centralize &&
13
+ css`
14
+ display: flex;
15
+ justify-content: center;
16
+ align-items: center;
17
+ `}
18
+
19
+ @media (max-width: ${({ breakPoint }) => breakPoint ?? UI_BREAKPOINT_MOBILE}) {
20
+ transform: scale(${({ scale }) => scale ?? 0.75});
21
+ }
22
+ `;
@@ -0,0 +1,3 @@
1
+
2
+ export const UI_BREAKPOINT_MOBILE = '950px';
3
+ export const UI_BREAKPOINT_SMALL_LAPTOP = '1400px';
@@ -0,0 +1,46 @@
1
+ import { GRID_HEIGHT, GRID_WIDTH } from '@rpg-engine/shared';
2
+ import { useEffect, useState } from 'react';
3
+ import { IPosition } from '../types/eventTypes';
4
+
5
+ interface ICursorPositionProps {
6
+ scale?: number;
7
+ }
8
+
9
+ export const useCursorPosition = ({ scale = 1 }: ICursorPositionProps): IPosition => {
10
+ const [position, setPosition] = useState<IPosition>({ x: 0, y: 0 });
11
+
12
+ const setFromEvent = (e: MouseEvent | TouchEvent) => {
13
+ let x, y;
14
+ const viewportCenterX = window.innerWidth / 2 - GRID_WIDTH;
15
+ const viewportCenterY = window.innerHeight / - GRID_HEIGHT;
16
+
17
+ if ('touches' in e) {
18
+ x = e.touches[0].clientX;
19
+ y = e.touches[0].clientY;
20
+ } else {
21
+ x = e.clientX;
22
+ y = e.clientY;
23
+ }
24
+
25
+ // Adjusting for the global scale
26
+ // Assuming the element is centrally located
27
+ setPosition({
28
+ x: (x - viewportCenterX) / scale + viewportCenterX,
29
+ y: (y - viewportCenterY) / scale + viewportCenterY
30
+ });
31
+ };
32
+
33
+ useEffect(() => {
34
+ window.addEventListener('mousemove', setFromEvent);
35
+ window.addEventListener('touchmove', setFromEvent);
36
+
37
+ console.log("SCALE IS ", scale)
38
+
39
+ return () => {
40
+ window.removeEventListener('mousemove', setFromEvent);
41
+ window.removeEventListener('touchmove', setFromEvent);
42
+ };
43
+ }, [scale]);
44
+
45
+ return position;
46
+ };
@@ -0,0 +1,50 @@
1
+ import { IItem, IShortcut, ShortcutType } from '@rpg-engine/shared';
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ import { SHORTCUTS_STORAGE_KEY, defaultShortcut } from '../components/Spellbook/constants';
4
+
5
+ interface IUseShortcuts {
6
+ itemContainer: { slots: Record<number, IItem | null | undefined>; };
7
+ }
8
+
9
+ export const useShortcuts = ({ itemContainer }: IUseShortcuts) => {
10
+ const [shortcuts, setShortcuts] = useState<IShortcut[]>([]);
11
+
12
+ useEffect(() => {
13
+ const storedShortcuts = localStorage.getItem(SHORTCUTS_STORAGE_KEY);
14
+ if (storedShortcuts) {
15
+ setShortcuts(JSON.parse(storedShortcuts));
16
+ }
17
+ }, []);
18
+
19
+ const setItemShortcut = useCallback((key: string, index: number): void => {
20
+ const storedShortcuts = localStorage.getItem(SHORTCUTS_STORAGE_KEY);
21
+ let updatedShortcuts = storedShortcuts ? JSON.parse(storedShortcuts) as IShortcut[] : [];
22
+
23
+ let item: IItem | null = null;
24
+ Object.keys(itemContainer.slots).forEach(slot => {
25
+ const slotItem = itemContainer.slots[parseInt(slot)];
26
+ if (slotItem && slotItem.key === key) {
27
+ item = slotItem;
28
+ }
29
+ });
30
+
31
+ if (!item) return;
32
+
33
+ updatedShortcuts[index] = { type: ShortcutType.Item, payload: item };
34
+ localStorage.setItem(SHORTCUTS_STORAGE_KEY, JSON.stringify(updatedShortcuts));
35
+ setShortcuts(updatedShortcuts);
36
+ }, [itemContainer]);
37
+
38
+ const removeShortcut = useCallback((index: number): void => {
39
+ const storedShortcuts = localStorage.getItem(SHORTCUTS_STORAGE_KEY);
40
+ let updatedShortcuts = storedShortcuts ? JSON.parse(storedShortcuts) as IShortcut[] : [];
41
+
42
+ if (updatedShortcuts[index]) {
43
+ updatedShortcuts[index] = defaultShortcut;
44
+ localStorage.setItem(SHORTCUTS_STORAGE_KEY, JSON.stringify(updatedShortcuts));
45
+ setShortcuts(updatedShortcuts);
46
+ }
47
+ }, []);
48
+
49
+ return { shortcuts, setItemShortcut, removeShortcut };
50
+ };
@@ -5,7 +5,7 @@ import {
5
5
  ItemSlotType,
6
6
  ItemSubType,
7
7
  ItemType,
8
- UserAccountTypes,
8
+ UserAccountTypes
9
9
  } from '@rpg-engine/shared';
10
10
 
11
11
  export const items: IItem[] = [
@@ -578,33 +578,40 @@ export const items: IItem[] = [
578
578
  },
579
579
  ];
580
580
 
581
- export const itemContainerMock: IItemContainer = {
582
- _id: '629ba0b6fe3f43002f58f23b',
583
- name: 'Item Container',
584
- owner: '629ba0b6fe3f43002f58f23b',
585
- slotQty: 60,
586
- slots: {
587
- 0: items[0],
588
- 1: items[1],
589
- 2: items[2],
590
- 3: items[3],
591
- 4: items[4],
592
- 5: items[5],
593
- 6: items[6],
594
- 7: items[7],
595
- 8: items[8],
596
- 9: items[9],
597
- 10: items[10],
598
- 11: items[11],
599
- 12: items[12],
600
- 13: items[13],
601
- 14: items[14],
602
- 15: items[15],
603
- //remaining slots are considered null by default
604
- },
605
- allowedItemTypes: [],
606
- parentItem: '629ba0b6fe3f43002f58f239',
607
- isEmpty: false,
608
- createdAt: '2022-06-04T18:13:10.581Z',
609
- updatedAt: '2022-06-04T18:13:10.581Z',
610
- };
581
+ export const itemContainerMock = (
582
+ props?: Record<string, unknown>
583
+ ): IItemContainer => {
584
+ {
585
+ return {
586
+ _id: '629ba0b6fe3f43002f58f23b',
587
+ name: 'Item Container',
588
+ owner: '629ba0b6fe3f43002f58f23b',
589
+ slotQty: 60,
590
+ slots: {
591
+ 0: items[0],
592
+ 1: items[1],
593
+ 2: items[2],
594
+ 3: items[3],
595
+ 4: items[4],
596
+ 5: items[5],
597
+ 6: items[6],
598
+ 7: items[7],
599
+ 8: items[8],
600
+ 9: items[9],
601
+ 10: items[10],
602
+ 11: items[11],
603
+ 12: items[12],
604
+ 13: items[13],
605
+ 14: items[14],
606
+ 15: items[15],
607
+ //remaining slots are considered null by default
608
+ },
609
+ allowedItemTypes: [],
610
+ parentItem: '629ba0b6fe3f43002f58f239',
611
+ isEmpty: false,
612
+ createdAt: '2022-06-04T18:13:10.581Z',
613
+ updatedAt: '2022-06-04T18:13:10.581Z',
614
+ ...props,
615
+ };
616
+ }
617
+ }
@@ -1,12 +1,6 @@
1
- import {
2
- IItem,
3
- IShortcut,
4
- ItemContainerType,
5
- ItemType,
6
- ShortcutType,
7
- } from '@rpg-engine/shared';
1
+ import { IItem, ItemContainerType, ItemType } from '@rpg-engine/shared';
8
2
  import { Meta, Story } from '@storybook/react';
9
- import React, { useEffect, useState } from 'react';
3
+ import React, { useState } from 'react';
10
4
  import {
11
5
  IItemContainerProps,
12
6
  ItemContainer,
@@ -14,10 +8,9 @@ import {
14
8
  import { RPGUIRoot } from '../../src/components/RPGUIRoot';
15
9
  import { equipmentSetMock } from '../../src/mocks/equipmentSet.mocks';
16
10
  import { itemContainerMock } from '../../src/mocks/itemContainer.mocks';
17
- import {
18
- defaultShortcut,
19
- SHORTCUTS_STORAGE_KEY,
20
- } from '../components/Spellbook/constants';
11
+ import { ScalableContainer } from '../components/shared/ScalableContainer';
12
+ import { UI_BREAKPOINT_SMALL_LAPTOP } from '../constants/uiBreakpoints';
13
+ import { useShortcuts } from '../hooks/useShortcuts';
21
14
  import atlasJSON from '../mocks/atlas/items/items.json';
22
15
  import atlasIMG from '../mocks/atlas/items/items.png';
23
16
 
@@ -55,147 +48,126 @@ let allowedToDrop = false;
55
48
  let dragSlot = -1;
56
49
  let dropSlot = -1;
57
50
 
58
- const Template: Story<IItemContainerProps> = () => {
59
- const [itemContainer, setItemContainer] = useState(itemContainerMock);
60
- const [shortcuts, setShortcuts] = useState<IShortcut[]>([]);
61
-
62
- useEffect(() => {
63
- const shortcuts = localStorage.getItem(SHORTCUTS_STORAGE_KEY);
64
- if (shortcuts) {
65
- setShortcuts(JSON.parse(shortcuts));
66
- }
67
- }, []);
68
-
69
- const setItemShortcut = (key: string, index: number) => {
70
- const shortcuts = JSON.parse(
71
- localStorage.getItem(SHORTCUTS_STORAGE_KEY) as string
72
- ) as IShortcut[];
73
-
74
- let item: IItem | null = null;
75
-
76
- Object.keys(itemContainer.slots).forEach(slot => {
77
- const slotItem = itemContainer.slots?.[parseInt(slot)];
78
- if (slotItem && slotItem.key === key) {
79
- item = slotItem;
80
- }
81
- });
82
-
83
- if (!item) {
84
- return;
85
- }
86
-
87
- if (!shortcuts) {
88
- const newShortcuts: IShortcut[] = Array(6).fill(defaultShortcut);
89
-
90
- newShortcuts[index] = {
91
- type: ShortcutType.Item,
92
- payload: item,
93
- };
94
-
95
- localStorage.setItem(SHORTCUTS_STORAGE_KEY, JSON.stringify(newShortcuts));
96
- } else {
97
- shortcuts[index] = {
98
- type: ShortcutType.Item,
99
- payload: item,
100
- };
101
-
102
- localStorage.setItem(SHORTCUTS_STORAGE_KEY, JSON.stringify(shortcuts));
103
- }
104
-
105
- setShortcuts(shortcuts);
106
- };
107
-
108
- const removeShortcut = (index: number) => {
109
- const shortcuts = JSON.parse(
110
- localStorage.getItem(SHORTCUTS_STORAGE_KEY) as string
111
- );
112
-
113
- if (!shortcuts) return;
114
-
115
- shortcuts[index] = defaultShortcut;
116
-
117
- localStorage.setItem(SHORTCUTS_STORAGE_KEY, JSON.stringify(shortcuts));
118
-
119
- setShortcuts(shortcuts);
120
- };
121
-
122
- return (
123
- <RPGUIRoot>
124
- <ItemContainer
125
- itemContainer={itemContainer}
126
- onClose={() => console.log('closing item container')}
127
- onMouseOver={onMouseOver}
128
- onSelected={onSelected}
129
- onItemClick={onItemClick}
130
- checkIfItemCanBeMoved={() => allowedToDrop}
131
- onItemDragEnd={quantity => {
132
- // THIS IS ONLY LONG-BOW EXAMPLE FOR DRAG AND DROP
133
-
134
- if (quantity === 0) {
135
- setItemContainer({ ...itemContainer });
136
- } else if (allowedToDrop && dropSlot !== -1) {
137
- const newContainer = { ...itemContainer };
138
-
139
- if (quantity && dragItem && dragItem.stackQty) {
140
- newContainer.slots[dropSlot] = {
51
+ interface ITemplateProps {
52
+ type: ItemContainerType;
53
+ scale?: number;
54
+ }
55
+
56
+ const Template: Story<IItemContainerProps & ITemplateProps> = ({
57
+ type,
58
+ scale,
59
+ }) => {
60
+ const mock = itemContainerMock({ name: type });
61
+
62
+ const [itemContainer, setItemContainer] = useState(mock);
63
+
64
+ const { shortcuts, setItemShortcut, removeShortcut } = useShortcuts({
65
+ itemContainer: mock,
66
+ });
67
+
68
+ const coreItemContainer = (
69
+ <ItemContainer
70
+ itemContainer={itemContainer}
71
+ onClose={() => console.log('closing item container')}
72
+ onMouseOver={onMouseOver}
73
+ onSelected={onSelected}
74
+ onItemClick={onItemClick}
75
+ checkIfItemCanBeMoved={() => allowedToDrop}
76
+ onItemDragEnd={quantity => {
77
+ // THIS IS ONLY LONG-BOW EXAMPLE FOR DRAG AND DROP
78
+
79
+ if (quantity === 0) {
80
+ setItemContainer({ ...itemContainer });
81
+ } else if (allowedToDrop && dropSlot !== -1) {
82
+ const newContainer = { ...itemContainer };
83
+
84
+ if (quantity && dragItem && dragItem.stackQty) {
85
+ newContainer.slots[dropSlot] = {
86
+ ...dragItem,
87
+ stackQty: quantity + (dropItem?.stackQty || 0),
88
+ };
89
+
90
+ if (dragItem.stackQty - quantity === 0)
91
+ newContainer.slots[dragSlot] = null;
92
+ else
93
+ newContainer.slots[dragSlot] = {
141
94
  ...dragItem,
142
- stackQty: quantity + (dropItem?.stackQty || 0),
95
+ stackQty: dragItem.stackQty - quantity,
143
96
  };
144
-
145
- if (dragItem.stackQty - quantity === 0)
146
- newContainer.slots[dragSlot] = null;
147
- else
148
- newContainer.slots[dragSlot] = {
149
- ...dragItem,
150
- stackQty: dragItem.stackQty - quantity,
151
- };
152
- } else {
153
- newContainer.slots[dropSlot] = dragItem;
154
- newContainer.slots[dragSlot] = null;
155
- }
156
- setTimeout(() => {
157
- setItemContainer(newContainer);
158
- }, 100);
97
+ } else {
98
+ newContainer.slots[dropSlot] = dragItem;
99
+ newContainer.slots[dragSlot] = null;
159
100
  }
160
-
101
+ setTimeout(() => {
102
+ setItemContainer(newContainer);
103
+ }, 100);
104
+ }
105
+
106
+ allowedToDrop = false;
107
+ dropSlot = -1;
108
+ dropItem = null;
109
+ dragItem = null;
110
+ }}
111
+ onItemDragStart={(item, slotIndex) => {
112
+ dragItem = item;
113
+ dragSlot = slotIndex;
114
+ }}
115
+ onItemPlaceDrop={(item, slotIndex) => {
116
+ // THIS IS ONLY LONG-BOW EXAMPLE FOR DRAG AND DROP
117
+
118
+ if (!item || (dragItem?.key === item?.key && dragSlot !== slotIndex)) {
119
+ console.log('allow');
120
+ allowedToDrop = true;
121
+ dropSlot = slotIndex;
122
+ dropItem = item ? item : null;
123
+ } else {
161
124
  allowedToDrop = false;
162
125
  dropSlot = -1;
163
126
  dropItem = null;
164
- dragItem = null;
165
- }}
166
- onItemDragStart={(item, slotIndex) => {
167
- dragItem = item;
168
- dragSlot = slotIndex;
169
- }}
170
- onItemPlaceDrop={(item, slotIndex) => {
171
- // THIS IS ONLY LONG-BOW EXAMPLE FOR DRAG AND DROP
172
-
173
- if (
174
- !item ||
175
- (dragItem?.key === item?.key && dragSlot !== slotIndex)
176
- ) {
177
- console.log('allow');
178
- allowedToDrop = true;
179
- dropSlot = slotIndex;
180
- dropItem = item ? item : null;
181
- } else {
182
- allowedToDrop = false;
183
- dropSlot = -1;
184
- dropItem = null;
185
- }
186
- }}
187
- onOutsideDrop={(item, pos) => console.log('drop', item, pos)}
188
- type={ItemContainerType.Inventory}
189
- atlasIMG={atlasIMG}
190
- atlasJSON={atlasJSON}
191
- shortcuts={shortcuts}
192
- setItemShortcut={setItemShortcut}
193
- removeShortcut={removeShortcut}
194
- equipmentSet={equipmentSetMock}
195
- isDepotSystem
196
- />
127
+ }
128
+ }}
129
+ onOutsideDrop={(item, pos) => console.log('drop', item, pos)}
130
+ type={type}
131
+ atlasIMG={atlasIMG}
132
+ atlasJSON={atlasJSON}
133
+ shortcuts={shortcuts}
134
+ setItemShortcut={setItemShortcut}
135
+ removeShortcut={removeShortcut}
136
+ equipmentSet={equipmentSetMock}
137
+ isDepotSystem
138
+ scale={scale}
139
+ />
140
+ );
141
+
142
+ return (
143
+ <RPGUIRoot>
144
+ {scale ? (
145
+ <ScalableContainer
146
+ scale={scale}
147
+ centralize={false}
148
+ breakPoint={UI_BREAKPOINT_SMALL_LAPTOP}
149
+ >
150
+ {coreItemContainer}
151
+ </ScalableContainer>
152
+ ) : (
153
+ coreItemContainer
154
+ )}
197
155
  </RPGUIRoot>
198
156
  );
199
157
  };
200
158
 
201
- export const Default = Template.bind({});
159
+ export const Inventory = Template.bind({});
160
+ Inventory.args = {
161
+ type: ItemContainerType.Inventory,
162
+ };
163
+
164
+ export const InventoryScaledDown = Template.bind({});
165
+ InventoryScaledDown.args = {
166
+ type: ItemContainerType.Inventory,
167
+ scale: 0.8,
168
+ };
169
+
170
+ export const Depot = Template.bind({});
171
+ Depot.args = {
172
+ type: ItemContainerType.Depot,
173
+ };
@@ -1,6 +0,0 @@
1
- interface ICursorPosition {
2
- x: number;
3
- y: number;
4
- }
5
- export declare const useCursorPosition: () => ICursorPosition;
6
- export {};
@@ -1,49 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
-
3
- interface ICursorPosition {
4
- x: number;
5
- y: number;
6
- }
7
-
8
- export const useCursorPosition = (): ICursorPosition => {
9
- const [cursorPosition, setCursorPosition] = useState<ICursorPosition>({ x: 0, y: 0 });
10
-
11
- useEffect(() => {
12
- let animationFrameId: number;
13
-
14
- const updateCursorPosition = (x: number, y: number) => {
15
- // Cancel the previous frame request
16
- cancelAnimationFrame(animationFrameId);
17
-
18
- // Request a new frame
19
- animationFrameId = requestAnimationFrame(() => {
20
- setCursorPosition({ x, y });
21
- });
22
- };
23
-
24
- const handleMouseMove = (event: MouseEvent) => {
25
- updateCursorPosition(event.clientX, event.clientY);
26
- };
27
-
28
- const handleTouchMove = (event: TouchEvent) => {
29
- // Prevent default touch behavior (like scrolling)
30
- event.preventDefault();
31
- if (event.touches.length > 0) {
32
- const touch = event.touches[0];
33
- updateCursorPosition(touch.clientX, touch.clientY);
34
- }
35
- };
36
-
37
- window.addEventListener('mousemove', handleMouseMove);
38
- window.addEventListener('touchmove', handleTouchMove, { passive: false });
39
-
40
- // Cleanup function
41
- return () => {
42
- window.removeEventListener('mousemove', handleMouseMove);
43
- window.removeEventListener('touchmove', handleTouchMove);
44
- cancelAnimationFrame(animationFrameId);
45
- };
46
- }, []);
47
-
48
- return cursorPosition;
49
- };