import React, { useMemo } from 'react' import type { SlotState } from '../../types' import { getInventoryType } from '../../registry' import { useInventoryContext } from '../../context/InventoryContext' import { useScale } from '../../context/ScaleContext' import { useKeyboardShortcuts } from '../../hooks/useKeyboardShortcuts' import { Slot } from '../Slot' import { InventoryBackground } from './InventoryBackground' import { ProgressBar } from './ProgressBar' import { VillagerTradeList } from './VillagerTradeList' import { EnchantmentOptions } from './EnchantmentOptions' import { HotbarExtras } from './HotbarExtras' import { AnvilInput } from './AnvilInput' import { AnvilCost } from './AnvilCost' import { EntityDisplay } from './EntityDisplay' import { BeaconEffects } from './BeaconEffects' interface InventoryWindowProps { type: string title?: string slots?: SlotState[] properties?: Record className?: string style?: React.CSSProperties enableKeyboardShortcuts?: boolean showDebug?: boolean /** When true, entity slot shows layout debug bounds instead of the default placeholder image. */ entityDisplayDebug?: boolean /** Override entity display rendering. Pass a function returning JSX, or null to hide. */ renderEntity?: ((width: number, height: number) => React.ReactNode) | null } export function InventoryWindow({ type, title, slots: slotsProp, properties = {}, className, style, enableKeyboardShortcuts = true, showDebug = false, entityDisplayDebug = false, renderEntity, }: InventoryWindowProps) { const def = getInventoryType(type) const { windowState, getSlot } = useInventoryContext() const { scale, slotSize, contentSize } = useScale() // borderPx removed from slot positioning: registry coords already point to the item area const borderPx = 0 const isHotbar = type === 'hotbar' useKeyboardShortcuts(enableKeyboardShortcuts && !isHotbar) const effectiveSlots = useMemo(() => { if (slotsProp) return slotsProp return windowState?.slots ?? [] }, [slotsProp, windowState]) const effectiveProperties = useMemo(() => { return { ...properties, ...(windowState?.properties ?? {}) } }, [properties, windowState]) if (!def) { return (
Unknown inventory type: {type}
) } // Player inventory: don't show title (it's just the player's own inventory) // Beacon: vanilla overrides renderLabels to show "Primary/Secondary Power" instead of title const isBeacon = def?.name === 'beacon' const effectiveTitle = (type === 'player' || isBeacon) ? undefined : (title ?? windowState?.title ?? def.title) const isVillager = type === 'villager' const isEnchanting = def?.name === 'enchanting_table' const isAnvil = def?.name === 'anvil' const resolveItem = (slotIndex: number) => { const fromProp = effectiveSlots.find((s) => s.index === slotIndex) if (fromProp) return fromProp.item return getSlot(slotIndex)?.item ?? null } return (
{/* Render slots */} {def.slots.map((slotDef) => (
))} {/* Entity display area */} {def.entityDisplay && def.entityPlaceholder && ( )} {/* Progress bars */} {def.progressBars?.map((pb) => ( ))} {/* Villager trades */} {isVillager && } {/* Enchanting options */} {isEnchanting && ( )} {/* Anvil rename input + cost display */} {isAnvil && } {isAnvil && } {/* Beacon effect selection panel */} {isBeacon && } {/* Hotbar extras: active slot indicator, offhand slot, open-inventory button */} {isHotbar && ( )}
) }