@rpg-engine/long-bow 0.2.86 → 0.2.88

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.
Files changed (35) hide show
  1. package/dist/components/Abstractions/SlotsContainer.d.ts +1 -0
  2. package/dist/components/DraggableContainer.d.ts +1 -0
  3. package/dist/components/Equipment/EquipmentSet.d.ts +4 -0
  4. package/dist/components/Input.d.ts +1 -0
  5. package/dist/components/Item/Inventory/ItemContainer.d.ts +8 -0
  6. package/dist/components/Item/Inventory/ItemQuantitySelector.d.ts +7 -0
  7. package/dist/components/Item/Inventory/ItemSlot.d.ts +5 -0
  8. package/dist/components/RangeSlider.d.ts +1 -0
  9. package/dist/long-bow.cjs.development.js +382 -77
  10. package/dist/long-bow.cjs.development.js.map +1 -1
  11. package/dist/long-bow.cjs.production.min.js +1 -1
  12. package/dist/long-bow.cjs.production.min.js.map +1 -1
  13. package/dist/long-bow.esm.js +383 -78
  14. package/dist/long-bow.esm.js.map +1 -1
  15. package/dist/stories/ItemQuantitySelector.stories.d.ts +5 -0
  16. package/package.json +1 -1
  17. package/src/components/Abstractions/SlotsContainer.tsx +3 -0
  18. package/src/components/DraggableContainer.tsx +3 -0
  19. package/src/components/Equipment/EquipmentSet.tsx +37 -0
  20. package/src/components/Input.tsx +6 -2
  21. package/src/components/Item/Inventory/ItemContainer.tsx +92 -6
  22. package/src/components/Item/Inventory/ItemQuantitySelector.tsx +142 -0
  23. package/src/components/Item/Inventory/ItemSlot.tsx +147 -24
  24. package/src/components/ListMenu.tsx +1 -2
  25. package/src/components/RangeSlider.tsx +37 -14
  26. package/src/mocks/itemContainer.mocks.ts +1 -1
  27. package/src/stories/EquipmentSet.stories.tsx +4 -0
  28. package/src/stories/ItemContainer.stories.tsx +82 -15
  29. package/src/stories/ItemQuantitySelector.stories.tsx +26 -0
  30. package/src/stories/RangeSlider.stories.tsx +10 -9
  31. package/src/.DS_Store +0 -0
  32. package/src/components/NPCDialog/.DS_Store +0 -0
  33. package/src/components/NPCDialog/img/.DS_Store +0 -0
  34. package/src/mocks/.DS_Store +0 -0
  35. package/src/mocks/atlas/.DS_Store +0 -0
@@ -0,0 +1,5 @@
1
+ import { Meta } from '@storybook/react';
2
+ import { IItemQuantitySelectorProps } from '../components/Item/Inventory/ItemQuantitySelector';
3
+ declare const meta: Meta;
4
+ export default meta;
5
+ export declare const Default: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, IItemQuantitySelectorProps>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpg-engine/long-bow",
3
- "version": "0.2.86",
3
+ "version": "0.2.88",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -9,6 +9,7 @@ interface IProps {
9
9
  onClose?: () => void;
10
10
  onPositionChange?: (position: IPosition) => void;
11
11
  onOutsideClick?: () => void;
12
+ initialPosition?: IPosition;
12
13
  }
13
14
 
14
15
  export const SlotsContainer: React.FC<IProps> = ({
@@ -17,6 +18,7 @@ export const SlotsContainer: React.FC<IProps> = ({
17
18
  onClose,
18
19
  onPositionChange,
19
20
  onOutsideClick,
21
+ initialPosition,
20
22
  }) => {
21
23
  return (
22
24
  <DraggableContainer
@@ -35,6 +37,7 @@ export const SlotsContainer: React.FC<IProps> = ({
35
37
  }
36
38
  }}
37
39
  onOutsideClick={onOutsideClick}
40
+ initialPosition={initialPosition}
38
41
  >
39
42
  {children}
40
43
  </DraggableContainer>
@@ -19,6 +19,7 @@ export interface IDraggableContainerProps {
19
19
  cancelDrag?: string;
20
20
  onPositionChange?: (position: IPosition) => void;
21
21
  onOutsideClick?: () => void;
22
+ initialPosition?: IPosition;
22
23
  }
23
24
 
24
25
  export const DraggableContainer: React.FC<IDraggableContainerProps> = ({
@@ -34,6 +35,7 @@ export const DraggableContainer: React.FC<IDraggableContainerProps> = ({
34
35
  cancelDrag,
35
36
  onPositionChange,
36
37
  onOutsideClick,
38
+ initialPosition = { x: 0, y: 0 },
37
39
  }) => {
38
40
  const draggableRef = useRef(null);
39
41
 
@@ -66,6 +68,7 @@ export const DraggableContainer: React.FC<IDraggableContainerProps> = ({
66
68
  });
67
69
  }
68
70
  }}
71
+ defaultPosition={initialPosition}
69
72
  >
70
73
  <Container
71
74
  ref={draggableRef}
@@ -20,6 +20,18 @@ export interface IEquipmentSetProps {
20
20
  item: IItem,
21
21
  itemContainerType: ItemContainerType | null
22
22
  ) => void;
23
+ onItemDragStart?: (
24
+ item: IItem,
25
+ slotIndex: number,
26
+ itemContainerType: ItemContainerType | null
27
+ ) => void;
28
+ onItemDragEnd?: (quantity?: number) => void;
29
+ onItemPlaceDrop?: (
30
+ item: IItem | null,
31
+ slotIndex: number,
32
+ itemContainerType: ItemContainerType | null
33
+ ) => void;
34
+ checkIfItemCanBeMoved: () => boolean;
23
35
  onMouseOver?: (e: any, slotIndex: number, item: IItem | null) => void;
24
36
  onSelected?: (optionId: string) => void;
25
37
  initialPosition?: { x: number; y: number };
@@ -36,6 +48,10 @@ export const EquipmentSet: React.FC<IEquipmentSetProps> = ({
36
48
  onItemClick,
37
49
  atlasIMG,
38
50
  atlasJSON,
51
+ onItemDragEnd,
52
+ onItemDragStart,
53
+ onItemPlaceDrop,
54
+ checkIfItemCanBeMoved,
39
55
  }) => {
40
56
  const {
41
57
  neck,
@@ -102,6 +118,25 @@ export const EquipmentSet: React.FC<IEquipmentSetProps> = ({
102
118
  onSelected={(optionId: string) => {
103
119
  if (onSelected) onSelected(optionId);
104
120
  }}
121
+ onDragStart={(item, slotIndex, itemContainerType) => {
122
+ if (!item) {
123
+ return;
124
+ }
125
+
126
+ if (onItemDragStart)
127
+ onItemDragStart(item, slotIndex, itemContainerType);
128
+ }}
129
+ onDragEnd={quantity => {
130
+ if (onItemDragEnd) onItemDragEnd(quantity);
131
+ }}
132
+ checkIfItemCanBeMoved={checkIfItemCanBeMoved}
133
+ onPlaceDrop={(item, slotIndex, itemContainerType) => {
134
+ if (!item) {
135
+ return;
136
+ }
137
+ if (onItemPlaceDrop)
138
+ onItemPlaceDrop(item, slotIndex, itemContainerType);
139
+ }}
105
140
  atlasIMG={atlasIMG}
106
141
  atlasJSON={atlasJSON}
107
142
  />
@@ -134,6 +169,7 @@ const EquipmentSetContainer = styled.div`
134
169
  justify-content: center;
135
170
  flex-wrap: wrap;
136
171
  flex-direction: row;
172
+ touch-action: none;
137
173
  `;
138
174
 
139
175
  const EquipmentColumn = styled.div`
@@ -141,4 +177,5 @@ const EquipmentColumn = styled.div`
141
177
  justify-content: center;
142
178
  flex-wrap: wrap;
143
179
  flex-direction: column;
180
+ touch-action: none;
144
181
  `;
@@ -4,8 +4,12 @@ export interface IInputProps
4
4
  extends React.DetailedHTMLProps<
5
5
  React.InputHTMLAttributes<HTMLInputElement>,
6
6
  HTMLInputElement
7
- > {}
7
+ > {
8
+ innerRef?: React.Ref<HTMLInputElement>;
9
+ }
8
10
 
9
11
  export const Input: React.FC<IInputProps> = ({ ...props }) => {
10
- return <input {...props} />;
12
+ const { innerRef, ...rest } = props;
13
+
14
+ return <input {...rest} ref={props.innerRef} />;
11
15
  };
@@ -1,7 +1,8 @@
1
1
  import { IItem, IItemContainer, ItemContainerType } from '@rpg-engine/shared';
2
- import React from 'react';
2
+ import React, { useState } from 'react';
3
3
  import styled from 'styled-components';
4
4
  import { SlotsContainer } from '../../Abstractions/SlotsContainer';
5
+ import { ItemQuantitySelector } from './ItemQuantitySelector';
5
6
 
6
7
  import { ItemSlot } from './ItemSlot';
7
8
 
@@ -13,12 +14,25 @@ export interface IItemContainerProps {
13
14
  ItemType: IItem['type'],
14
15
  itemContainerType: ItemContainerType | null
15
16
  ) => void;
17
+ onItemDragStart?: (
18
+ item: IItem,
19
+ slotIndex: number,
20
+ itemContainerType: ItemContainerType | null
21
+ ) => void;
22
+ onItemDragEnd?: (quantity?: number) => void;
23
+ onItemPlaceDrop?: (
24
+ item: IItem | null,
25
+ slotIndex: number,
26
+ itemContainerType: ItemContainerType | null
27
+ ) => void;
28
+ checkIfItemCanBeMoved: () => boolean;
16
29
  onMouseOver?: (e: any, slotIndex: number, item: IItem | null) => void;
17
30
  onSelected?: (optionId: string, item: IItem) => void;
18
31
  type: ItemContainerType;
19
32
  atlasJSON: any;
20
33
  atlasIMG: any;
21
34
  disableContextMenu?: boolean;
35
+ initialPosition?: { x: number; y: number };
22
36
  }
23
37
 
24
38
  export const ItemContainer: React.FC<IItemContainerProps> = ({
@@ -31,7 +45,18 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
31
45
  atlasJSON,
32
46
  atlasIMG,
33
47
  disableContextMenu = false,
48
+ onItemDragEnd,
49
+ onItemDragStart,
50
+ onItemPlaceDrop,
51
+ checkIfItemCanBeMoved,
52
+ initialPosition,
34
53
  }) => {
54
+ const [quantitySelect, setQuantitySelect] = useState({
55
+ isOpen: false,
56
+ maxQuantity: 1,
57
+ callback: (_quantity: number) => {},
58
+ });
59
+
35
60
  const onRenderSlots = () => {
36
61
  const slots = [];
37
62
 
@@ -52,6 +77,25 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
52
77
  onSelected={(optionId: string, item: IItem) => {
53
78
  if (onSelected) onSelected(optionId, item);
54
79
  }}
80
+ onDragStart={(item, slotIndex, itemContainerType) => {
81
+ if (onItemDragStart)
82
+ onItemDragStart(item, slotIndex, itemContainerType);
83
+ }}
84
+ onDragEnd={quantity => {
85
+ if (onItemDragEnd) onItemDragEnd(quantity);
86
+ }}
87
+ checkIfItemCanBeMoved={checkIfItemCanBeMoved}
88
+ openQuantitySelector={(maxQuantity, callback) => {
89
+ setQuantitySelect({
90
+ isOpen: true,
91
+ maxQuantity,
92
+ callback,
93
+ });
94
+ }}
95
+ onPlaceDrop={(item, slotIndex, itemContainerType) => {
96
+ if (onItemPlaceDrop)
97
+ onItemPlaceDrop(item, slotIndex, itemContainerType);
98
+ }}
55
99
  atlasIMG={atlasIMG}
56
100
  atlasJSON={atlasJSON}
57
101
  />
@@ -61,11 +105,40 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
61
105
  };
62
106
 
63
107
  return (
64
- <SlotsContainer title={itemContainer.name || 'Container'} onClose={onClose}>
65
- <ItemsContainer className="item-container-body">
66
- {onRenderSlots()}
67
- </ItemsContainer>
68
- </SlotsContainer>
108
+ <>
109
+ <SlotsContainer
110
+ title={itemContainer.name || 'Container'}
111
+ onClose={onClose}
112
+ initialPosition={initialPosition}
113
+ >
114
+ <ItemsContainer className="item-container-body">
115
+ {onRenderSlots()}
116
+ </ItemsContainer>
117
+ </SlotsContainer>
118
+ {quantitySelect.isOpen && (
119
+ <QuantitySelectorContainer>
120
+ <ItemQuantitySelector
121
+ quantity={quantitySelect.maxQuantity}
122
+ onConfirm={quantity => {
123
+ quantitySelect.callback(quantity);
124
+ setQuantitySelect({
125
+ isOpen: false,
126
+ maxQuantity: 1,
127
+ callback: () => {},
128
+ });
129
+ }}
130
+ onClose={() => {
131
+ quantitySelect.callback(-1);
132
+ setQuantitySelect({
133
+ isOpen: false,
134
+ maxQuantity: 1,
135
+ callback: () => {},
136
+ });
137
+ }}
138
+ />
139
+ </QuantitySelectorContainer>
140
+ )}
141
+ </>
69
142
  );
70
143
  };
71
144
 
@@ -75,3 +148,16 @@ const ItemsContainer = styled.div`
75
148
  justify-content: center;
76
149
  flex-wrap: wrap;
77
150
  `;
151
+
152
+ const QuantitySelectorContainer = styled.div`
153
+ position: absolute;
154
+ top: 0;
155
+ left: 0;
156
+ width: 100vw;
157
+ height: 100vh;
158
+ z-index: 100;
159
+ display: flex;
160
+ justify-content: center;
161
+ align-items: center;
162
+ background-color: rgba(0, 0, 0, 0.5);
163
+ `;
@@ -0,0 +1,142 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import styled from 'styled-components';
3
+ import { Button, ButtonTypes } from '../../Button';
4
+ import { Input } from '../../Input';
5
+ import { RPGUIContainer, RPGUIContainerTypes } from '../../RPGUIContainer';
6
+ import { RangeSlider, RangeSliderType } from '../../RangeSlider';
7
+
8
+ export interface IItemQuantitySelectorProps {
9
+ quantity: number;
10
+ onConfirm: (quantity: number) => void;
11
+ onClose: () => void;
12
+ }
13
+
14
+ export const ItemQuantitySelector: React.FC<IItemQuantitySelectorProps> = ({
15
+ quantity,
16
+ onConfirm,
17
+ onClose,
18
+ }) => {
19
+ const [value, setValue] = useState(quantity);
20
+
21
+ const inputRef = useRef<HTMLInputElement>(null);
22
+
23
+ useEffect(() => {
24
+ if (inputRef.current) {
25
+ inputRef.current.focus();
26
+ inputRef.current.select();
27
+
28
+ const closeSelector = (e: KeyboardEvent) => {
29
+ if (e.key === 'Escape') {
30
+ onClose();
31
+ }
32
+ };
33
+
34
+ document.addEventListener('keydown', closeSelector);
35
+
36
+ return () => {
37
+ document.removeEventListener('keydown', closeSelector);
38
+ };
39
+ }
40
+
41
+ return () => {};
42
+ }, []);
43
+
44
+ return (
45
+ <StyledContainer type={RPGUIContainerTypes.Framed} width="25rem">
46
+ <CloseButton
47
+ className="container-close"
48
+ onClick={onClose}
49
+ onTouchStart={onClose}
50
+ >
51
+ X
52
+ </CloseButton>
53
+ <h2>Select quantity to move</h2>
54
+ <StyledForm
55
+ style={{ width: '100%' }}
56
+ onSubmit={e => {
57
+ e.preventDefault();
58
+
59
+ const numberValue = Number(value);
60
+
61
+ if (Number.isNaN(numberValue)) {
62
+ return;
63
+ }
64
+
65
+ onConfirm(Math.max(1, Math.min(quantity, numberValue)));
66
+ }}
67
+ noValidate
68
+ >
69
+ <StyledInput
70
+ innerRef={inputRef}
71
+ placeholder="Enter quantity"
72
+ type="number"
73
+ min={1}
74
+ max={quantity}
75
+ value={value}
76
+ onChange={e => {
77
+ if (Number(e.target.value) >= quantity) {
78
+ setValue(quantity);
79
+ return;
80
+ }
81
+
82
+ setValue((e.target.value as unknown) as number);
83
+ }}
84
+ onBlur={e => {
85
+ const newValue = Math.max(
86
+ 1,
87
+ Math.min(quantity, Number(e.target.value))
88
+ );
89
+
90
+ setValue(newValue);
91
+ }}
92
+ />
93
+ <RangeSlider
94
+ type={RangeSliderType.Slider}
95
+ valueMin={1}
96
+ valueMax={quantity}
97
+ width="100%"
98
+ onChange={setValue}
99
+ value={value}
100
+ />
101
+ <Button buttonType={ButtonTypes.RPGUIButton} type="submit">
102
+ Confirm
103
+ </Button>
104
+ </StyledForm>
105
+ </StyledContainer>
106
+ );
107
+ };
108
+
109
+ const StyledContainer = styled(RPGUIContainer)`
110
+ display: flex;
111
+ flex-direction: column;
112
+ align-items: center;
113
+ `;
114
+
115
+ const StyledForm = styled.form`
116
+ display: flex;
117
+ flex-direction: column;
118
+ align-items: center;
119
+ width: 100%;
120
+ `;
121
+ const StyledInput = styled(Input)`
122
+ text-align: center;
123
+
124
+ &::-webkit-outer-spin-button,
125
+ &::-webkit-inner-spin-button {
126
+ -webkit-appearance: none;
127
+ margin: 0;
128
+ }
129
+
130
+ &[type='number'] {
131
+ -moz-appearance: textfield;
132
+ }
133
+ `;
134
+
135
+ const CloseButton = styled.div`
136
+ position: absolute;
137
+ top: 3px;
138
+ right: 0px;
139
+ color: white;
140
+ z-index: 22;
141
+ font-size: 0.8rem;
142
+ `;
@@ -4,11 +4,12 @@ import {
4
4
  IItemContainer,
5
5
  ItemContainerType,
6
6
  ItemSlotType,
7
- ItemType
7
+ ItemType,
8
8
  } from '@rpg-engine/shared';
9
9
 
10
10
  import { observer } from 'mobx-react-lite';
11
- import React, { useEffect, useState } from 'react';
11
+ import React, { useEffect, useRef, useState } from 'react';
12
+ import Draggable from 'react-draggable';
12
13
  import styled from 'styled-components';
13
14
  import { v4 as uuidv4 } from 'uuid';
14
15
  import { uiFonts } from '../../../constants/uiFonts';
@@ -52,6 +53,19 @@ interface IProps {
52
53
  itemContainerType: ItemContainerType | null,
53
54
  item: IItem
54
55
  ) => void;
56
+ onDragStart: (
57
+ item: IItem,
58
+ slotIndex: number,
59
+ itemContainerType: ItemContainerType | null
60
+ ) => void;
61
+ onDragEnd: (quantity?: number) => void;
62
+ checkIfItemCanBeMoved: () => boolean;
63
+ openQuantitySelector?: (maxQuantity: number, callback: () => void) => void;
64
+ onPlaceDrop: (
65
+ item: IItem | null,
66
+ slotIndex: number,
67
+ itemContainerType: ItemContainerType | null
68
+ ) => void;
55
69
  atlasJSON: any;
56
70
  atlasIMG: any;
57
71
  isContextMenuDisabled?: boolean;
@@ -70,16 +84,28 @@ export const ItemSlot: React.FC<IProps> = observer(
70
84
  atlasJSON,
71
85
  atlasIMG,
72
86
  isContextMenuDisabled = false,
87
+ onDragEnd,
88
+ onDragStart,
89
+ onPlaceDrop,
90
+ checkIfItemCanBeMoved,
91
+ openQuantitySelector,
73
92
  }) => {
74
93
  const [isTooltipVisible, setTooltipVisible] = useState(false);
75
94
 
76
95
  const [isContextMenuVisible, setIsContextMenuVisible] = useState(false);
77
96
 
97
+ const [isFocused, setIsFocused] = useState(false);
98
+ const [wasDragged, setWasDragged] = useState(false);
99
+ const [dragPosition, setDragPosition] = useState({ x: 0, y: 0 });
100
+ const dragContainer = useRef<HTMLDivElement>(null);
101
+
78
102
  const [contextActions, setContextActions] = useState<IContextMenuItem[]>(
79
103
  []
80
104
  );
81
105
 
82
106
  useEffect(() => {
107
+ setDragPosition({ x: 0, y: 0 });
108
+
83
109
  if (item) {
84
110
  setContextActions(generateContextMenu(item, containerType));
85
111
  }
@@ -112,7 +138,7 @@ export const ItemSlot: React.FC<IProps> = observer(
112
138
 
113
139
  const renderItem = (itemToRender: IItem | null) => {
114
140
  const element = [];
115
-
141
+
116
142
  if (itemToRender?.texturePath) {
117
143
  element.push(
118
144
  <ErrorBoundary key={itemToRender._id}>
@@ -150,7 +176,7 @@ export const ItemSlot: React.FC<IProps> = observer(
150
176
  itemToRender.allowedEquipSlotType?.includes(slotSpriteMask!)
151
177
  ) {
152
178
  const element = [];
153
-
179
+
154
180
  element.push(
155
181
  <ErrorBoundary key={itemToRender._id}>
156
182
  <SpriteFromAtlas
@@ -205,29 +231,121 @@ export const ItemSlot: React.FC<IProps> = observer(
205
231
  }
206
232
  };
207
233
 
234
+ const resetItem = () => {
235
+ setTooltipVisible(false);
236
+ setIsFocused(false);
237
+ setWasDragged(false);
238
+ };
239
+
240
+ const onSuccesfulDrag = (quantity?: number) => {
241
+ resetItem();
242
+
243
+ if (quantity === -1) setDragPosition({ x: 0, y: 0 });
244
+ else if (item) {
245
+ onDragEnd(quantity);
246
+ resetItem();
247
+ }
248
+ };
249
+
208
250
  return (
209
251
  <Container
210
252
  className="rpgui-icon empty-slot"
211
- onMouseOver={event =>
212
- onMouseOver(event, slotIndex, item, event.clientX, event.clientY)
213
- }
214
- onMouseOut={() => {
215
- if (onMouseOut) onMouseOut();
253
+ onMouseUp={() => {
254
+ const data = item ? item : null;
255
+ if (onPlaceDrop) onPlaceDrop(data, slotIndex, containerType);
216
256
  }}
217
- onMouseEnter={() => setTooltipVisible(true)}
218
- onMouseLeave={() => setTooltipVisible(false)}
219
- onClick={() => {
220
- setTooltipVisible(false);
221
-
222
- if (item) {
223
- if (!isContextMenuDisabled) {
224
- setIsContextMenuVisible(!isContextMenuVisible);
225
- }
257
+ onTouchEnd={e => {
258
+ const { clientX, clientY } = e.changedTouches[0];
259
+ const simulatedEvent = new MouseEvent('mouseup', {
260
+ clientX,
261
+ clientY,
262
+ bubbles: true,
263
+ });
226
264
 
227
- onClick(item.type, containerType, item);
228
- }
265
+ document
266
+ .elementFromPoint(clientX, clientY)
267
+ ?.dispatchEvent(simulatedEvent);
229
268
  }}
230
269
  >
270
+ <Draggable
271
+ defaultClassName={item ? 'draggable' : 'empty-slot'}
272
+ onStop={() => {
273
+ if (!item) {
274
+ return;
275
+ }
276
+
277
+ if (wasDragged) {
278
+ setWasDragged(false);
279
+
280
+ const target = dragContainer.current;
281
+ if (!target || !wasDragged) return;
282
+
283
+ const style = window.getComputedStyle(target);
284
+ const matrix = new DOMMatrixReadOnly(style.transform);
285
+ const x = matrix.m41;
286
+ const y = matrix.m42;
287
+
288
+ setDragPosition({ x, y });
289
+
290
+ setTimeout(() => {
291
+ if (checkIfItemCanBeMoved()) {
292
+ if (
293
+ item.stackQty &&
294
+ item.stackQty !== 1 &&
295
+ openQuantitySelector
296
+ )
297
+ openQuantitySelector(item.stackQty, onSuccesfulDrag);
298
+ else onSuccesfulDrag(item.stackQty);
299
+ } else {
300
+ resetItem();
301
+ setDragPosition({ x: 0, y: 0 });
302
+ }
303
+ }, 100);
304
+ } else if (item) {
305
+ if (!isContextMenuDisabled)
306
+ setIsContextMenuVisible(!isContextMenuVisible);
307
+
308
+ onClick(item.type, containerType, item);
309
+ }
310
+ }}
311
+ onStart={() => {
312
+ if (!item) {
313
+ return;
314
+ }
315
+
316
+ if (onDragStart) {
317
+ onDragStart(item, slotIndex, containerType);
318
+ }
319
+ }}
320
+ onDrag={() => {
321
+ setWasDragged(true);
322
+ setIsFocused(true);
323
+ }}
324
+ position={dragPosition}
325
+ cancel=".empty-slot"
326
+ >
327
+ <ItemContainer
328
+ ref={dragContainer}
329
+ isFocused={isFocused}
330
+ onMouseOver={event => {
331
+ onMouseOver(event, slotIndex, item, event.clientX, event.clientY);
332
+ }}
333
+ onMouseOut={() => {
334
+ if (onMouseOut) onMouseOut();
335
+ }}
336
+ onMouseEnter={() => {
337
+ setTooltipVisible(true);
338
+ }}
339
+ onMouseLeave={() => {
340
+ setTooltipVisible(false);
341
+ }}
342
+ >
343
+ {onRenderSlot(item)}
344
+ </ItemContainer>
345
+ </Draggable>
346
+
347
+ {isTooltipVisible && item && <ItemTooltip label={item.name} />}
348
+
231
349
  {!isContextMenuDisabled && isContextMenuVisible && contextActions && (
232
350
  <RelativeListMenu
233
351
  options={contextActions}
@@ -242,10 +360,6 @@ export const ItemSlot: React.FC<IProps> = observer(
242
360
  }}
243
361
  />
244
362
  )}
245
-
246
- {isTooltipVisible && item && <ItemTooltip label={item.name} />}
247
-
248
- {onRenderSlot(item)}
249
363
  </Container>
250
364
  );
251
365
  }
@@ -261,12 +375,21 @@ const Container = styled.div`
261
375
  position: relative;
262
376
  `;
263
377
 
378
+ const ItemContainer = styled.div<{ isFocused?: boolean }>`
379
+ width: 100%;
380
+ height: 100%;
381
+ position: relative;
382
+
383
+ ${props => props.isFocused && 'z-index: 100; pointer-events: none;'}
384
+ `;
385
+
264
386
  const ItemQtyContainer = styled.div`
265
387
  position: relative;
266
388
  width: 85%;
267
389
  height: 16px;
268
390
  top: 25px;
269
391
  left: 2px;
392
+ pointer-events: none;
270
393
 
271
394
  display: flex;
272
395
  justify-content: flex-end;
@@ -26,8 +26,7 @@ export const ListMenu: React.FC<IListMenuProps> = ({
26
26
  {options.map((params, index) => (
27
27
  <ListElement
28
28
  key={params?.id || index}
29
- onClick={(e: any) => {
30
- e.stopPropagation();
29
+ onClick={() => {
31
30
  onSelected(params?.id);
32
31
  }}
33
32
  >