minecraft-inventory 0.1.44 → 0.1.45

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,6 +1,6 @@
1
1
  {
2
2
  "name": "minecraft-inventory",
3
- "version": "0.1.44",
3
+ "version": "0.1.45",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "release": {
@@ -353,7 +353,7 @@ export function InventoryOverlay({
353
353
  lineHeight: 1,
354
354
  }}
355
355
  >
356
- INV 0.1.44
356
+ INV 0.1.45
357
357
  </a>
358
358
  )}
359
359
 
@@ -47,8 +47,9 @@ export function InventoryWindow({
47
47
  const { scale, slotSize, contentSize } = useScale()
48
48
  // borderPx removed from slot positioning: registry coords already point to the item area
49
49
  const borderPx = 0
50
+ const isHotbar = type === 'hotbar'
50
51
 
51
- useKeyboardShortcuts(enableKeyboardShortcuts)
52
+ useKeyboardShortcuts(enableKeyboardShortcuts && !isHotbar)
52
53
 
53
54
  const effectiveSlots = useMemo(() => {
54
55
  if (slotsProp) return slotsProp
@@ -73,7 +74,6 @@ export function InventoryWindow({
73
74
  const effectiveTitle = (type === 'player' || isBeacon) ? undefined : (title ?? windowState?.title ?? def.title)
74
75
  const isVillager = type === 'villager'
75
76
  const isEnchanting = def?.name === 'enchanting_table'
76
- const isHotbar = type === 'hotbar'
77
77
  const isAnvil = def?.name === 'anvil'
78
78
 
79
79
  const resolveItem = (slotIndex: number) => {
@@ -75,12 +75,9 @@
75
75
  z-index: 10001;
76
76
  }
77
77
 
78
- .mobileMenuTitle {
79
- color: #ffffff;
80
- font-weight: bold;
81
- padding-bottom: 4px;
82
- border-bottom: 1px solid #555555;
78
+ .mobileMenuInfo {
83
79
  margin-bottom: 4px;
80
+ flex-shrink: 0;
84
81
  }
85
82
 
86
83
  .mobileBtn {
@@ -4,6 +4,8 @@ import { useInventoryContext } from '../../context/InventoryContext'
4
4
  import { useScale } from '../../context/ScaleContext'
5
5
  import { ItemCanvas } from '../ItemCanvas'
6
6
  import { Tooltip } from '../Tooltip'
7
+ import { ItemTooltipBody } from '../Tooltip/ItemTooltipBody'
8
+ import tooltipStyles from '../Tooltip/Tooltip.module.css'
7
9
  import { useMobile } from '../../hooks/useMobile'
8
10
  import styles from './Slot.module.css'
9
11
 
@@ -606,7 +608,7 @@ function MobileSlotMenu({ item, x, y, onPickAll, onPickHalf, onDropOne, onDropAl
606
608
  if (top + mh > vh - 4) top = vh - mh - 4
607
609
  if (top < 4) top = 4
608
610
  setPos({ left, top })
609
- }, [x, y])
611
+ }, [x, y, item])
610
612
 
611
613
  // Wrapper to handle both touch and click, preventing event bubbling to the slot
612
614
  const touchBtn = (handler: () => void) => ({
@@ -631,8 +633,17 @@ function MobileSlotMenu({ item, x, y, onPickAll, onPickHalf, onDropOne, onDropAl
631
633
  minWidth: 100 * scale,
632
634
  }}
633
635
  >
634
- <div className={styles.mobileMenuTitle}>
635
- {item.displayName ?? item.name ?? `Item #${item.type}`} ×{item.count}
636
+ <div
637
+ className={[tooltipStyles.tooltip, styles.mobileMenuInfo].join(' ')}
638
+ style={{
639
+ fontSize: Math.round(8 * scale),
640
+ padding: Math.round(3 * scale),
641
+ gap: Math.round(0.5 * scale),
642
+ width: 'max-content',
643
+ maxWidth: 'min(90vw, 280px)',
644
+ }}
645
+ >
646
+ <ItemTooltipBody item={item} />
636
647
  </div>
637
648
  <button className={styles.mobileBtn} {...touchBtn(onPickAll)}>Select All ({item.count})</button>
638
649
  <button className={styles.mobileBtn} {...touchBtn(onPickHalf)}>Pick Half ({Math.ceil(item.count / 2)})</button>
@@ -0,0 +1,69 @@
1
+ import React from 'react'
2
+ import type { ItemStack } from '../../types'
3
+ import { MessageFormattedString } from '../Text/MessageFormattedString'
4
+ import styles from './Tooltip.module.css'
5
+
6
+ function getRarityColor(item: ItemStack): string {
7
+ if (item.enchantments && item.enchantments.length > 0) return '#8080ff'
8
+ return '#ffffff'
9
+ }
10
+
11
+ function formatEnchantment(e: { name: string; level: number }): string {
12
+ const roman = ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X']
13
+ return e.level <= 10 ? `${e.name} ${roman[e.level]}` : `${e.name} ${e.level}`
14
+ }
15
+
16
+ export function getItemTooltipDisplayName(item: ItemStack): string {
17
+ return item.displayName ?? (item.name ? item.name.replace(/_/g, ' ') : `Item #${item.type}`)
18
+ }
19
+
20
+ /** Item name, enchantments, lore, durability, and type id — shared by desktop tooltip and mobile menu. */
21
+ export function ItemTooltipBody({ item }: { item: ItemStack }) {
22
+ const nameColor = getRarityColor(item)
23
+ const hasDurability =
24
+ item.durability !== undefined &&
25
+ item.maxDurability !== undefined &&
26
+ item.durability < item.maxDurability
27
+
28
+ return (
29
+ <>
30
+ <div className={styles.name} style={{ color: nameColor }}>
31
+ <MessageFormattedString
32
+ text={getItemTooltipDisplayName(item)}
33
+ fallbackColor={nameColor}
34
+ />
35
+ </div>
36
+
37
+ {item.enchantments && item.enchantments.length > 0 && (
38
+ <div className={styles.section}>
39
+ {item.enchantments.map((e, i) => (
40
+ <div key={i} className={styles.enchantment}>
41
+ {formatEnchantment(e)}
42
+ </div>
43
+ ))}
44
+ </div>
45
+ )}
46
+
47
+ {item.lore && item.lore.length > 0 && (
48
+ <div className={styles.lore}>
49
+ {item.lore.map((line, i) => (
50
+ <div key={i}>
51
+ <MessageFormattedString text={line} />
52
+ </div>
53
+ ))}
54
+ </div>
55
+ )}
56
+
57
+ {hasDurability && (
58
+ <div className={styles.durability}>
59
+ Durability: {item.durability} / {item.maxDurability}
60
+ </div>
61
+ )}
62
+
63
+ <div className={styles.typeId}>
64
+ {item.name ?? `#${item.type}`}
65
+ {item.metadata !== undefined && item.metadata > 0 ? `:${item.metadata}` : ''}
66
+ </div>
67
+ </>
68
+ )
69
+ }
@@ -2,8 +2,8 @@ import React, { useRef, useEffect } from 'react'
2
2
  import { createPortal } from 'react-dom'
3
3
  import type { ItemStack } from '../../types'
4
4
  import { useScale } from '../../context/ScaleContext'
5
- import { MessageFormattedString } from '../Text/MessageFormattedString'
6
5
  import { globalMouse } from '../../utils/globalMouse'
6
+ import { ItemTooltipBody } from './ItemTooltipBody'
7
7
  import styles from './Tooltip.module.css'
8
8
 
9
9
  interface TooltipProps {
@@ -11,16 +11,6 @@ interface TooltipProps {
11
11
  visible: boolean
12
12
  }
13
13
 
14
- function getRarityColor(item: ItemStack): string {
15
- if (item.enchantments && item.enchantments.length > 0) return '#8080ff'
16
- return '#ffffff'
17
- }
18
-
19
- function formatEnchantment(e: { name: string; level: number }): string {
20
- const roman = ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X']
21
- return e.level <= 10 ? `${e.name} ${roman[e.level]}` : `${e.name} ${e.level}`
22
- }
23
-
24
14
  export function Tooltip({ item, visible }: TooltipProps) {
25
15
  const { scale } = useScale()
26
16
  const ref = useRef<HTMLDivElement>(null)
@@ -63,12 +53,6 @@ export function Tooltip({ item, visible }: TooltipProps) {
63
53
 
64
54
  if (!visible) return null
65
55
 
66
- const nameColor = getRarityColor(item)
67
- const hasDurability =
68
- item.durability !== undefined &&
69
- item.maxDurability !== undefined &&
70
- item.durability < item.maxDurability
71
-
72
56
  const fs = Math.round(8 * scale)
73
57
  const pad = Math.round(3 * scale)
74
58
  const gap2 = Math.round(0.5 * scale)
@@ -91,43 +75,7 @@ export function Tooltip({ item, visible }: TooltipProps) {
91
75
  pointerEvents: 'none',
92
76
  }}
93
77
  >
94
- <div className={styles.name} style={{ color: nameColor }}>
95
- <MessageFormattedString
96
- text={item.displayName ?? (item.name ? item.name.replace(/_/g, ' ') : `Item #${item.type}`)}
97
- fallbackColor={nameColor}
98
- />
99
- </div>
100
-
101
- {item.enchantments && item.enchantments.length > 0 && (
102
- <div className={styles.section}>
103
- {item.enchantments.map((e, i) => (
104
- <div key={i} className={styles.enchantment}>
105
- {formatEnchantment(e)}
106
- </div>
107
- ))}
108
- </div>
109
- )}
110
-
111
- {item.lore && item.lore.length > 0 && (
112
- <div className={styles.lore}>
113
- {item.lore.map((line, i) => (
114
- <div key={i}>
115
- <MessageFormattedString text={line} />
116
- </div>
117
- ))}
118
- </div>
119
- )}
120
-
121
- {hasDurability && (
122
- <div className={styles.durability}>
123
- Durability: {item.durability} / {item.maxDurability}
124
- </div>
125
- )}
126
-
127
- <div className={styles.typeId}>
128
- {item.name ?? `#${item.type}`}
129
- {item.metadata !== undefined && item.metadata > 0 ? `:${item.metadata}` : ''}
130
- </div>
78
+ <ItemTooltipBody item={item} />
131
79
  </div>
132
80
  )
133
81