Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | 1x 23x 23x 23x 23x 1x 22x | /**
* TechniqueBarContainer - Positioned container for TechniqueBar
*
* Provides consistent positioning and styling for TechniqueBar across
* Combat and Training screens. Handles responsive positioning and z-index.
*
* Eliminates 60+ lines of duplicate code between CombatScreen3D and TrainingScreen3D.
*
* @module components/shared/three/ui/TechniqueBarContainer
* @category Combat UI
* @korean 기술바컨테이너
*/
import React, { useMemo } from "react";
import { TechniqueBar, type TechniqueBarProps } from "./TechniqueBar";
import { getTechniqueBarBottom, LAYOUT_BOTTOM_POSITIONS } from "../../../../types/constants/layout";
import { Z_INDEX } from "../../../../types/LayoutTypes";
export interface TechniqueBarContainerProps extends TechniqueBarProps {
/** Whether to show the TechniqueBar (allows conditional rendering) */
readonly visible?: boolean;
}
/**
* TechniqueBarContainer - Positioned wrapper for TechniqueBar
*
* Provides consistent positioning, styling, and pointer event handling
* for the TechniqueBar across different screen contexts (Combat and Training).
*
* Features:
* - Memoized styles for performance
* - Centralized positioning using layout constants
* - Semantic z-index (Z_INDEX.TECHNIQUE_BAR)
* - Pointer event handling (container non-interactive, inner interactive)
*
* @example
* ```tsx
* <TechniqueBarContainer
* visible={combatState.roundStarted && !combatState.roundEnded}
* techniques={availableTechniques}
* player={player}
* selectedIndex={selectedIndex}
* cooldowns={cooldownsMap}
* onTechniqueSelect={handleSelect}
* onTechniqueHover={handleHover}
* isMobile={isMobile}
* screenWidth={width}
* screenHeight={height}
* />
* ```
*/
export const TechniqueBarContainer: React.FC<TechniqueBarContainerProps> = ({
visible = true,
...techniqueBarProps
}) => {
const { isMobile } = techniqueBarProps;
// Memoize container styles to prevent unnecessary re-renders
// Positioned at bottom to minimize arena obstruction (gameplay priority)
const containerStyle = useMemo(() => ({
position: "absolute" as const,
left: 0,
bottom: getTechniqueBarBottom(isMobile),
width: "100%",
height: `${LAYOUT_BOTTOM_POSITIONS.TECHNIQUE_BAR_HEIGHT}px`,
pointerEvents: "none" as const,
zIndex: Z_INDEX.TECHNIQUE_BAR,
display: "flex",
justifyContent: "center" as const,
alignItems: "flex-end" as const,
// Semi-transparent background to not fully obstruct arena
background: "linear-gradient(to top, rgba(0, 0, 0, 0.4) 0%, rgba(0, 0, 0, 0) 100%)",
}), [isMobile]);
// Memoize inner div style for pointer events
const innerStyle = useMemo(() => ({
pointerEvents: "auto" as const,
}), []);
if (!visible) {
return null;
}
return (
<div style={containerStyle} data-testid="technique-bar-container">
<div style={innerStyle}>
<TechniqueBar {...techniqueBarProps} key={techniqueBarProps.player.currentStance} />
</div>
</div>
);
};
export default TechniqueBarContainer;
|