minecraft-inventory 0.1.24 → 0.1.25

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/README.md CHANGED
@@ -9,7 +9,7 @@ A flexible, scalable React library for rendering Minecraft inventory GUIs. Desig
9
9
  - `<img>`-rendered item textures with automatic `items/` → `blocks/` fallback (via PrismarineJS asset mirror by default)
10
10
  - Tooltips that follow the cursor, matching the original Minecraft style
11
11
  - Full keyboard support: number keys (1-9) to swap hotbar, Q to drop, double-click to collect, scroll wheel to pick/place
12
- - Mobile support: tap to open a context menu (take all / half / custom amount / drop)
12
+ - Mobile support: tap-to-focus inventory interactions plus long-press slot actions (pick half / custom amount / drop one / drop all)
13
13
  - Optional JEI (item browser) panel on the left or right
14
14
  - Bot connector layer — plugs into a mineflayer bot or any custom server connection
15
15
  - Demo connector with action logging for local development
@@ -414,13 +414,13 @@ const myConnector: InventoryConnector = {
414
414
 
415
415
  ## Mobile Support
416
416
 
417
- On touch devices, tapping a slot with no held item opens a context menu instead of immediately picking up the item. The menu appears to the side in landscape or below in portrait.
417
+ On touch devices, tapping a slot uses the mobile focus/swap flow. Long-pressing a populated slot with no held item opens a context menu. The menu appears to the side in landscape or below in portrait.
418
418
 
419
419
  Context menu options:
420
- - **Take All** — picks up the entire stack
421
- - **Take Half**picks up half
422
- - **Take Amount…**`window.prompt` to enter a custom quantity
423
- - **Drop** — drops the stack from the slot
420
+ - **Pick Half** — picks up half and highlights the selected slot
421
+ - **Pick Amount…**`window.prompt` to enter a custom quantity, remembering the last value entered
422
+ - **Drop One**drops a single item from the slot (same as `Q`)
423
+ - **Drop All** — drops the full stack from the slot (same as `Ctrl+Q`)
424
424
  - **Cancel**
425
425
 
426
426
  When you have a held item, tapping a slot places/transfers it (same as left-click on desktop).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minecraft-inventory",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "release": {
@@ -310,7 +310,7 @@ export function InventoryOverlay({
310
310
  lineHeight: 1,
311
311
  }}
312
312
  >
313
- INV 0.1.24
313
+ INV 0.1.25
314
314
  </a>
315
315
  )}
316
316
 
@@ -54,6 +54,8 @@ export function Slot({
54
54
  setPKeyActive,
55
55
  focusedSlot,
56
56
  setFocusedSlot,
57
+ mobilePickAmount,
58
+ setMobilePickAmount,
57
59
  dragEndedRef,
58
60
  noPlaceholders,
59
61
  } = useInventoryContext()
@@ -331,6 +333,7 @@ export function Slot({
331
333
 
332
334
  if (heldItem) {
333
335
  // When holding an item, place it (standard behavior, no focus needed)
336
+ if (focusedSlot !== null) setFocusedSlot(null)
334
337
  sendAction({ type: 'click', slotIndex: index, button: 'left', mode: 'normal' })
335
338
  return
336
339
  }
@@ -351,28 +354,25 @@ export function Slot({
351
354
  [isMobile, disabled, heldItem, sendAction, index, pKeyActive, setPKeyActive, focusedSlot, setFocusedSlot, onClickOverride, cancelLongPress, mobileMenuOpen],
352
355
  )
353
356
 
354
- const handleMobilePickAll = useCallback(() => {
355
- setMobileMenuOpen(false)
356
- setShowTooltip(false)
357
- sendAction({ type: 'click', slotIndex: index, button: 'left', mode: 'normal' })
358
- }, [sendAction, index])
359
-
360
357
  const handleMobilePickHalf = useCallback(() => {
361
358
  setMobileMenuOpen(false)
362
359
  setShowTooltip(false)
360
+ setFocusedSlot(index)
363
361
  sendAction({ type: 'click', slotIndex: index, button: 'right', mode: 'normal' })
364
- }, [sendAction, index])
362
+ }, [sendAction, index, setFocusedSlot])
365
363
 
366
364
  const handleMobilePickCustom = useCallback(() => {
367
365
  if (!item) return
368
- const input = window.prompt(`Pick amount (max ${item.count}):`, String(item.count))
366
+ const input = window.prompt(`Pick amount (max ${item.count}):`, String(mobilePickAmount))
369
367
  const amount = parseInt(input ?? '', 10)
370
368
  if (isNaN(amount) || amount <= 0) return
369
+ setMobilePickAmount(amount)
371
370
  setMobileMenuOpen(false)
372
371
  setShowTooltip(false)
372
+ setFocusedSlot(index)
373
373
  const take = Math.min(amount, item.count)
374
374
  if (take >= item.count) {
375
- // Take all: just left-click
375
+ // Pick all: just left-click
376
376
  sendAction({ type: 'click', slotIndex: index, button: 'left', mode: 'normal' })
377
377
  } else {
378
378
  // Pick up all, then put back (count - take) items one-by-one via right-click
@@ -381,13 +381,21 @@ export function Slot({
381
381
  sendAction({ type: 'click', slotIndex: index, button: 'right', mode: 'normal' })
382
382
  }
383
383
  }
384
- }, [item, sendAction, index])
384
+ }, [item, mobilePickAmount, sendAction, index, setFocusedSlot, setMobilePickAmount])
385
+
386
+ const handleMobileDropOne = useCallback(() => {
387
+ setMobileMenuOpen(false)
388
+ setShowTooltip(false)
389
+ setFocusedSlot(null)
390
+ sendAction({ type: 'drop', slotIndex: index, all: false })
391
+ }, [sendAction, index, setFocusedSlot])
385
392
 
386
- const handleMobileDrop = useCallback(() => {
393
+ const handleMobileDropAll = useCallback(() => {
387
394
  setMobileMenuOpen(false)
388
395
  setShowTooltip(false)
396
+ setFocusedSlot(null)
389
397
  sendAction({ type: 'drop', slotIndex: index, all: true })
390
- }, [sendAction, index])
398
+ }, [sendAction, index, setFocusedSlot])
391
399
 
392
400
  const closeMobileMenu = useCallback(() => {
393
401
  setMobileMenuOpen(false)
@@ -532,10 +540,10 @@ export function Slot({
532
540
  item={item}
533
541
  x={mobileTouchPos.x}
534
542
  y={mobileTouchPos.y}
535
- onPickAll={handleMobilePickAll}
536
543
  onPickHalf={handleMobilePickHalf}
537
544
  onPickCustom={handleMobilePickCustom}
538
- onDrop={handleMobileDrop}
545
+ onDropOne={handleMobileDropOne}
546
+ onDropAll={handleMobileDropAll}
539
547
  onClose={closeMobileMenu}
540
548
  />
541
549
  </>
@@ -548,14 +556,14 @@ interface MobileSlotMenuProps {
548
556
  item: ItemStack
549
557
  x: number
550
558
  y: number
551
- onPickAll(): void
552
559
  onPickHalf(): void
553
560
  onPickCustom(): void
554
- onDrop(): void
561
+ onDropOne(): void
562
+ onDropAll(): void
555
563
  onClose(): void
556
564
  }
557
565
 
558
- function MobileSlotMenu({ item, x, y, onPickAll, onPickHalf, onPickCustom, onDrop, onClose }: MobileSlotMenuProps) {
566
+ function MobileSlotMenu({ item, x, y, onPickHalf, onPickCustom, onDropOne, onDropAll, onClose }: MobileSlotMenuProps) {
559
567
  const { scale } = useScale()
560
568
  const menuRef = useRef<HTMLDivElement>(null)
561
569
  const [pos, setPos] = useState({ left: x, top: y })
@@ -600,10 +608,10 @@ function MobileSlotMenu({ item, x, y, onPickAll, onPickHalf, onPickCustom, onDro
600
608
  <div className={styles.mobileMenuTitle}>
601
609
  {item.displayName ?? item.name ?? `Item #${item.type}`} ×{item.count}
602
610
  </div>
603
- <button className={styles.mobileBtn} {...touchBtn(onPickAll)}>Take All ({item.count})</button>
604
- <button className={styles.mobileBtn} {...touchBtn(onPickHalf)}>Take Half ({Math.ceil(item.count / 2)})</button>
605
- <button className={styles.mobileBtn} {...touchBtn(onPickCustom)}>Take Amount…</button>
606
- <button className={[styles.mobileBtn, styles.mobileBtnDanger].join(' ')} {...touchBtn(onDrop)}>Drop</button>
611
+ <button className={styles.mobileBtn} {...touchBtn(onPickHalf)}>Pick Half ({Math.ceil(item.count / 2)})</button>
612
+ <button className={styles.mobileBtn} {...touchBtn(onPickCustom)}>Pick Amount…</button>
613
+ <button className={[styles.mobileBtn, styles.mobileBtnDanger].join(' ')} {...touchBtn(onDropOne)}>Drop One</button>
614
+ <button className={[styles.mobileBtn, styles.mobileBtnDanger].join(' ')} {...touchBtn(onDropAll)}>Drop All</button>
607
615
  <button className={styles.mobileBtn} {...touchBtn(onClose)}>Cancel</button>
608
616
  </div>
609
617
  )
@@ -44,6 +44,9 @@ export interface InventoryContextValue {
44
44
  /** Pending first digit for P-key slot number entry */
45
45
  pKeyDigit: string
46
46
  setPKeyDigit: (d: string) => void
47
+ /** Last amount entered in the mobile pick-amount prompt */
48
+ mobilePickAmount: number
49
+ setMobilePickAmount: (amount: number) => void
47
50
  /** Ref set to true when a drag just ended; cleared on next mouseDown.
48
51
  * Used by Slot to suppress spurious click events that fire after endDrag. */
49
52
  dragEndedRef: React.MutableRefObject<boolean>
@@ -90,6 +93,7 @@ export function InventoryProvider({ connector, children, noDragSpread = false, n
90
93
  const [pKeyActive, setPKeyActive] = useState(false)
91
94
  const [focusedSlot, setFocusedSlot] = useState<number | null>(null)
92
95
  const [pKeyDigit, setPKeyDigit] = useState('')
96
+ const [mobilePickAmount, setMobilePickAmount] = useState(1)
93
97
 
94
98
  const connectorRef = useRef(connector)
95
99
  connectorRef.current = connector
@@ -320,6 +324,8 @@ export function InventoryProvider({ connector, children, noDragSpread = false, n
320
324
  setFocusedSlot,
321
325
  pKeyDigit,
322
326
  setPKeyDigit,
327
+ mobilePickAmount,
328
+ setMobilePickAmount,
323
329
  dragEndedRef,
324
330
  resolveEnchantmentName,
325
331
  }