minecraft-inventory 0.1.17 → 0.1.18
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,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect, useRef } from 'react'
|
|
1
|
+
import React, { useEffect, useMemo, useRef } from 'react'
|
|
2
2
|
import { useInventoryContext } from '../../context/InventoryContext'
|
|
3
3
|
import { useScale } from '../../context/ScaleContext'
|
|
4
4
|
import { ItemCanvas } from '../ItemCanvas'
|
|
@@ -11,13 +11,21 @@ import { globalMouse } from '../../utils/globalMouse'
|
|
|
11
11
|
* Only re-renders when heldItem or contentSize changes (for ItemCanvas updates).
|
|
12
12
|
*/
|
|
13
13
|
export function CursorItem() {
|
|
14
|
-
const { heldItem } = useInventoryContext()
|
|
14
|
+
const { heldItem, isDragging, dragSlots, dragRemainder } = useInventoryContext()
|
|
15
15
|
const { contentSize } = useScale()
|
|
16
16
|
const isMobile = useMobile()
|
|
17
17
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
18
18
|
const rafRef = useRef(0)
|
|
19
19
|
const halfSizeRef = useRef(Math.round(contentSize / 2))
|
|
20
20
|
|
|
21
|
+
// Determine display item: during spread, show remainder count
|
|
22
|
+
const displayItem = useMemo(() => {
|
|
23
|
+
if (isDragging && dragSlots.length > 1 && heldItem && dragRemainder !== null) {
|
|
24
|
+
return { ...heldItem, count: dragRemainder }
|
|
25
|
+
}
|
|
26
|
+
return heldItem
|
|
27
|
+
}, [isDragging, dragSlots.length, heldItem, dragRemainder])
|
|
28
|
+
|
|
21
29
|
// Update halfSize when contentSize changes
|
|
22
30
|
useEffect(() => {
|
|
23
31
|
halfSizeRef.current = Math.round(contentSize / 2)
|
|
@@ -76,10 +84,29 @@ export function CursorItem() {
|
|
|
76
84
|
}}
|
|
77
85
|
>
|
|
78
86
|
<ItemCanvas
|
|
79
|
-
item={
|
|
87
|
+
item={displayItem!}
|
|
80
88
|
size={contentSize}
|
|
81
89
|
style={{ position: 'absolute', top: 0, left: 0 }}
|
|
82
90
|
/>
|
|
91
|
+
{isDragging && dragSlots.length > 1 && dragRemainder === 0 && (
|
|
92
|
+
<span
|
|
93
|
+
className="mc-inv-cursor-zero"
|
|
94
|
+
style={{
|
|
95
|
+
position: 'absolute',
|
|
96
|
+
bottom: 0,
|
|
97
|
+
right: 0,
|
|
98
|
+
fontSize: Math.max(7, Math.round(contentSize * 0.5)),
|
|
99
|
+
fontFamily: "'Minecraftia', 'Minecraft', monospace",
|
|
100
|
+
color: '#ffff00',
|
|
101
|
+
textShadow: '1px 1px 0 #3f3f00',
|
|
102
|
+
lineHeight: 1,
|
|
103
|
+
pointerEvents: 'none',
|
|
104
|
+
zIndex: 1,
|
|
105
|
+
}}
|
|
106
|
+
>
|
|
107
|
+
0
|
|
108
|
+
</span>
|
|
109
|
+
)}
|
|
83
110
|
</div>
|
|
84
111
|
)
|
|
85
112
|
}
|
|
@@ -374,6 +374,7 @@ export function Slot({
|
|
|
374
374
|
<ItemCanvas
|
|
375
375
|
item={item}
|
|
376
376
|
size={renderSize}
|
|
377
|
+
noCount={!!dragPreviewEntry}
|
|
377
378
|
style={{ position: 'absolute', top: 0, left: 0, pointerEvents: 'none' }}
|
|
378
379
|
/>
|
|
379
380
|
)}
|
|
@@ -420,23 +421,33 @@ export function Slot({
|
|
|
420
421
|
)}
|
|
421
422
|
|
|
422
423
|
{dragPreviewEntry && (
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
424
|
+
<>
|
|
425
|
+
{!item && heldItem && (
|
|
426
|
+
<ItemCanvas
|
|
427
|
+
item={heldItem}
|
|
428
|
+
size={renderSize}
|
|
429
|
+
noCount
|
|
430
|
+
style={{ position: 'absolute', top: 0, left: 0, pointerEvents: 'none' }}
|
|
431
|
+
/>
|
|
432
|
+
)}
|
|
433
|
+
<div
|
|
434
|
+
className="mc-inv-drag-preview-count"
|
|
435
|
+
style={{
|
|
436
|
+
position: 'absolute',
|
|
437
|
+
right: 1,
|
|
438
|
+
bottom: 1,
|
|
439
|
+
fontSize: Math.round(renderSize * 0.45),
|
|
440
|
+
fontFamily: "'Minecraftia', 'Minecraft', monospace",
|
|
441
|
+
color: '#ffff00',
|
|
442
|
+
textShadow: '1px 1px 0 #3f3f00',
|
|
443
|
+
lineHeight: 1,
|
|
444
|
+
pointerEvents: 'none',
|
|
445
|
+
zIndex: 3,
|
|
446
|
+
}}
|
|
447
|
+
>
|
|
448
|
+
{dragPreviewEntry.count}
|
|
449
|
+
</div>
|
|
450
|
+
</>
|
|
440
451
|
)}
|
|
441
452
|
|
|
442
453
|
{item && showTooltip && !mobileMenuOpen && !heldItem && (
|
|
@@ -19,6 +19,8 @@ export interface InventoryContextValue {
|
|
|
19
19
|
dragButton: 'left' | 'right' | null
|
|
20
20
|
/** Client-side preview of item counts for each slot in the current drag */
|
|
21
21
|
dragPreview: Map<number, DragPreviewEntry>
|
|
22
|
+
/** Number of items remaining on the cursor during an active spread drag */
|
|
23
|
+
dragRemainder: number | null
|
|
22
24
|
startDrag: (slotIndex: number, button: 'left' | 'right') => void
|
|
23
25
|
addDragSlot: (slotIndex: number) => void
|
|
24
26
|
endDrag: () => void
|
|
@@ -79,6 +81,7 @@ export function InventoryProvider({ connector, children, noDragSpread = false, n
|
|
|
79
81
|
const [dragSlots, setDragSlots] = useState<number[]>([])
|
|
80
82
|
const [dragButton, setDragButton] = useState<'left' | 'right' | null>(null)
|
|
81
83
|
const [dragPreview, setDragPreview] = useState<Map<number, DragPreviewEntry>>(new Map())
|
|
84
|
+
const [dragRemainder, setDragRemainder] = useState<number | null>(null)
|
|
82
85
|
const [activeNumberKey, setActiveNumberKey] = useState<number | null>(null)
|
|
83
86
|
const [grabOffset, setGrabOffset] = useState<{ x: number; y: number }>({ x: 0, y: 0 })
|
|
84
87
|
const [pKeyActive, setPKeyActive] = useState(false)
|
|
@@ -133,11 +136,12 @@ export function InventoryProvider({ connector, children, noDragSpread = false, n
|
|
|
133
136
|
[],
|
|
134
137
|
)
|
|
135
138
|
|
|
136
|
-
const computeDragPreview = useCallback((slots: number[], button: 'left' | 'right', held: ItemStack | null, ws: InventoryWindowState | null) => {
|
|
139
|
+
const computeDragPreview = useCallback((slots: number[], button: 'left' | 'right', held: ItemStack | null, ws: InventoryWindowState | null): { preview: Map<number, DragPreviewEntry>; remainder: number } => {
|
|
137
140
|
const preview = new Map<number, DragPreviewEntry>()
|
|
138
|
-
if (!held || slots.length === 0) return preview
|
|
141
|
+
if (!held || slots.length === 0) return { preview, remainder: held?.count ?? 0 }
|
|
139
142
|
|
|
140
143
|
const maxStack = getMaxStackSize(held)
|
|
144
|
+
let totalPlaced = 0
|
|
141
145
|
|
|
142
146
|
if (button === 'left') {
|
|
143
147
|
// Only spread into compatible slots (empty or same item type)
|
|
@@ -145,13 +149,15 @@ export function InventoryProvider({ connector, children, noDragSpread = false, n
|
|
|
145
149
|
const existingItem = ws?.slots.find((s) => s.index === idx)?.item
|
|
146
150
|
return !existingItem || isItemEqual(existingItem, held)
|
|
147
151
|
})
|
|
148
|
-
if (compatibleSlots.length === 0) return preview
|
|
152
|
+
if (compatibleSlots.length === 0) return { preview, remainder: held.count }
|
|
149
153
|
const perSlot = Math.floor(held.count / compatibleSlots.length)
|
|
150
154
|
// Vanilla behavior: if perSlot=0 (more slots than items), nothing is distributed
|
|
151
|
-
if (perSlot === 0) return preview
|
|
155
|
+
if (perSlot === 0) return { preview, remainder: held.count }
|
|
152
156
|
for (const idx of compatibleSlots) {
|
|
153
157
|
const existingCount = ws?.slots.find((s) => s.index === idx)?.item?.count ?? 0
|
|
154
158
|
const total = Math.min(existingCount + perSlot, maxStack)
|
|
159
|
+
const added = total - existingCount
|
|
160
|
+
totalPlaced += added
|
|
155
161
|
preview.set(idx, { count: total })
|
|
156
162
|
}
|
|
157
163
|
} else {
|
|
@@ -161,10 +167,12 @@ export function InventoryProvider({ connector, children, noDragSpread = false, n
|
|
|
161
167
|
if (existingItem && !isItemEqual(existingItem, held)) continue
|
|
162
168
|
const existingCount = existingItem ? existingItem.count : 0
|
|
163
169
|
const total = Math.min(existingCount + 1, maxStack)
|
|
170
|
+
const added = total - existingCount
|
|
171
|
+
totalPlaced += added
|
|
164
172
|
preview.set(idx, { count: total })
|
|
165
173
|
}
|
|
166
174
|
}
|
|
167
|
-
return preview
|
|
175
|
+
return { preview, remainder: held.count - totalPlaced }
|
|
168
176
|
}, [])
|
|
169
177
|
|
|
170
178
|
const startDrag = useCallback((slotIndex: number, button: 'left' | 'right') => {
|
|
@@ -174,13 +182,16 @@ export function InventoryProvider({ connector, children, noDragSpread = false, n
|
|
|
174
182
|
setDragButton(button)
|
|
175
183
|
setDragSlots([slotIndex])
|
|
176
184
|
setDragPreview(new Map())
|
|
185
|
+
setDragRemainder(null)
|
|
177
186
|
}, [noDragSpread])
|
|
178
187
|
|
|
179
188
|
const addDragSlot = useCallback((slotIndex: number) => {
|
|
180
189
|
setDragSlots((prev) => {
|
|
181
190
|
if (prev.includes(slotIndex)) return prev
|
|
182
191
|
const next = [...prev, slotIndex]
|
|
183
|
-
|
|
192
|
+
const result = computeDragPreview(next, dragButton!, heldItem, windowState)
|
|
193
|
+
setDragPreview(result.preview)
|
|
194
|
+
setDragRemainder(result.remainder)
|
|
184
195
|
return next
|
|
185
196
|
})
|
|
186
197
|
}, [computeDragPreview, dragButton, heldItem, windowState])
|
|
@@ -255,6 +266,7 @@ export function InventoryProvider({ connector, children, noDragSpread = false, n
|
|
|
255
266
|
setIsDragging(false)
|
|
256
267
|
setDragButton(null)
|
|
257
268
|
setDragPreview(new Map())
|
|
269
|
+
setDragRemainder(null)
|
|
258
270
|
}, [])
|
|
259
271
|
|
|
260
272
|
const cancelDrag = useCallback(() => {
|
|
@@ -262,6 +274,7 @@ export function InventoryProvider({ connector, children, noDragSpread = false, n
|
|
|
262
274
|
setDragSlots([])
|
|
263
275
|
setDragButton(null)
|
|
264
276
|
setDragPreview(new Map())
|
|
277
|
+
setDragRemainder(null)
|
|
265
278
|
}, [])
|
|
266
279
|
|
|
267
280
|
const getSlot = useCallback(
|
|
@@ -295,6 +308,7 @@ export function InventoryProvider({ connector, children, noDragSpread = false, n
|
|
|
295
308
|
dragSlots,
|
|
296
309
|
dragButton,
|
|
297
310
|
dragPreview,
|
|
311
|
+
dragRemainder,
|
|
298
312
|
startDrag,
|
|
299
313
|
addDragSlot,
|
|
300
314
|
endDrag,
|