TranscendencePopover closes properly
This commit is contained in:
parent
46467a354f
commit
e5a1fb7b1e
3 changed files with 127 additions and 96 deletions
|
|
@ -17,6 +17,7 @@ interface Props
|
|||
HTMLDivElement
|
||||
> {
|
||||
type: 'character' | 'summon'
|
||||
starRef: React.RefObject<HTMLDivElement>
|
||||
open: boolean
|
||||
stage: number
|
||||
onOpenChange?: (open: boolean) => void
|
||||
|
|
@ -24,8 +25,9 @@ interface Props
|
|||
}
|
||||
|
||||
const TranscendencePopover = ({
|
||||
children,
|
||||
open: popoverOpen,
|
||||
starRef,
|
||||
children,
|
||||
type,
|
||||
stage,
|
||||
tabIndex,
|
||||
|
|
@ -45,8 +47,8 @@ const TranscendencePopover = ({
|
|||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (open) popoverRef.current?.focus()
|
||||
}, [])
|
||||
setOpen(popoverOpen)
|
||||
}, [popoverOpen])
|
||||
|
||||
useEffect(() => {
|
||||
if (stage) setCurrentStage(stage)
|
||||
|
|
@ -57,10 +59,6 @@ const TranscendencePopover = ({
|
|||
else if (type === 'summon') setBaseLevel(200)
|
||||
}, [type])
|
||||
|
||||
useEffect(() => {
|
||||
setOpen(popoverOpen)
|
||||
}, [popoverOpen])
|
||||
|
||||
function handleFragmentClicked(newStage: number) {
|
||||
setCurrentStage(newStage)
|
||||
if (sendValue) sendValue(newStage)
|
||||
|
|
@ -70,13 +68,33 @@ const TranscendencePopover = ({
|
|||
setCurrentStage(newStage)
|
||||
}
|
||||
|
||||
function closePopover() {
|
||||
setOpen(false)
|
||||
if (onOpenChange) onOpenChange(false)
|
||||
}
|
||||
|
||||
function handlePointerDownOutside(
|
||||
event: CustomEvent<{ originalEvent: PointerEvent }>
|
||||
) {
|
||||
const target = event.detail.originalEvent.target as Element
|
||||
if (
|
||||
target &&
|
||||
starRef.current &&
|
||||
target.closest('.TranscendenceStar') !== starRef.current
|
||||
) {
|
||||
closePopover()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={onOpenChange}>
|
||||
<Popover open={open}>
|
||||
<PopoverAnchor>{children}</PopoverAnchor>
|
||||
<PopoverContent
|
||||
className={styles.transcendence}
|
||||
className="transcendence"
|
||||
ref={popoverRef}
|
||||
tabIndex={tabIndex}
|
||||
onEscapeKeyDown={closePopover}
|
||||
onPointerDownOutside={handlePointerDownOutside}
|
||||
>
|
||||
<TranscendenceStar
|
||||
className="interactive base"
|
||||
|
|
|
|||
|
|
@ -20,97 +20,102 @@ interface Props
|
|||
|
||||
const NUM_FRAGMENTS = 5
|
||||
|
||||
const TranscendenceStar = ({
|
||||
className,
|
||||
interactive,
|
||||
stage,
|
||||
editable,
|
||||
tabIndex,
|
||||
onStarClick,
|
||||
onFragmentClick,
|
||||
onFragmentHover,
|
||||
}: Props) => {
|
||||
const [visibleStage, setVisibleStage] = useState(0)
|
||||
const [currentStage, setCurrentStage] = useState(0)
|
||||
const [immutable, setImmutable] = useState(false)
|
||||
|
||||
// Classes
|
||||
const starClasses = classnames({
|
||||
[styles.star]: true,
|
||||
[styles.immutable]: immutable,
|
||||
[styles.empty]: stage === 0,
|
||||
[styles.stage1]: stage === 1,
|
||||
[styles.stage2]: stage === 2,
|
||||
[styles.stage3]: stage === 3,
|
||||
[styles.stage4]: stage === 4,
|
||||
[styles.stage5]: stage === 5,
|
||||
})
|
||||
|
||||
const baseImageClasses = classnames(
|
||||
const TranscendenceStar = React.forwardRef<HTMLDivElement, Props>(
|
||||
function TranscendenceStar(
|
||||
{
|
||||
[styles.figure]: true,
|
||||
},
|
||||
className?.split(' ').map((c) => styles[c])
|
||||
)
|
||||
className,
|
||||
interactive,
|
||||
stage,
|
||||
editable,
|
||||
tabIndex,
|
||||
onStarClick,
|
||||
onFragmentClick,
|
||||
onFragmentHover,
|
||||
}: Props,
|
||||
forwardedRef
|
||||
) {
|
||||
const [visibleStage, setVisibleStage] = useState(0)
|
||||
const [currentStage, setCurrentStage] = useState(0)
|
||||
const [immutable, setImmutable] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setVisibleStage(stage)
|
||||
setCurrentStage(stage)
|
||||
}, [stage])
|
||||
// Classes
|
||||
const starClasses = classnames({
|
||||
TranscendenceStar: true,
|
||||
[styles.star]: true,
|
||||
[styles.immutable]: immutable,
|
||||
[styles.empty]: stage === 0,
|
||||
[styles.stage1]: stage === 1,
|
||||
[styles.stage2]: stage === 2,
|
||||
[styles.stage3]: stage === 3,
|
||||
[styles.stage4]: stage === 4,
|
||||
[styles.stage5]: stage === 5,
|
||||
})
|
||||
|
||||
function handleClick() {
|
||||
if (onStarClick) {
|
||||
onStarClick()
|
||||
const baseImageClasses = classnames(
|
||||
{
|
||||
[styles.figure]: true,
|
||||
},
|
||||
className?.split(' ').map((c) => styles[c])
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
setVisibleStage(stage)
|
||||
setCurrentStage(stage)
|
||||
}, [stage])
|
||||
|
||||
function handleClick() {
|
||||
if (onStarClick) onStarClick()
|
||||
}
|
||||
}
|
||||
|
||||
function handleFragmentClick(index: number) {
|
||||
let newStage = index
|
||||
if (index === currentStage) newStage = 0
|
||||
function handleFragmentClick(index: number) {
|
||||
let newStage = index
|
||||
if (index === currentStage) newStage = 0
|
||||
|
||||
setVisibleStage(newStage)
|
||||
setCurrentStage(newStage)
|
||||
if (onFragmentClick) onFragmentClick(newStage)
|
||||
}
|
||||
setVisibleStage(newStage)
|
||||
setCurrentStage(newStage)
|
||||
if (onFragmentClick) onFragmentClick(newStage)
|
||||
}
|
||||
|
||||
function handleFragmentHover(index: number) {
|
||||
setVisibleStage(index)
|
||||
if (onFragmentHover) onFragmentHover(index)
|
||||
}
|
||||
function handleFragmentHover(index: number) {
|
||||
setVisibleStage(index)
|
||||
if (onFragmentHover) onFragmentHover(index)
|
||||
}
|
||||
|
||||
function handleMouseLeave() {
|
||||
setVisibleStage(currentStage)
|
||||
if (onFragmentHover) onFragmentHover(currentStage)
|
||||
}
|
||||
function handleMouseLeave() {
|
||||
setVisibleStage(currentStage)
|
||||
if (onFragmentHover) onFragmentHover(currentStage)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={starClasses}
|
||||
onClick={editable ? handleClick : () => {}}
|
||||
onMouseLeave={interactive ? handleMouseLeave : () => {}}
|
||||
tabIndex={tabIndex}
|
||||
>
|
||||
<div className={styles.fragments}>
|
||||
{[...Array(NUM_FRAGMENTS)].map((e, i) => {
|
||||
const loopStage = i + 1
|
||||
return interactive ? (
|
||||
<TranscendenceFragment
|
||||
key={`fragment_${loopStage}`}
|
||||
stage={loopStage}
|
||||
visible={loopStage <= visibleStage}
|
||||
interactive={interactive}
|
||||
onClick={handleFragmentClick}
|
||||
onHover={handleFragmentHover}
|
||||
/>
|
||||
) : (
|
||||
''
|
||||
)
|
||||
})}
|
||||
return (
|
||||
<div
|
||||
className={starClasses}
|
||||
onClick={editable ? handleClick : () => {}}
|
||||
onMouseLeave={interactive ? handleMouseLeave : () => {}}
|
||||
ref={forwardedRef}
|
||||
tabIndex={tabIndex}
|
||||
>
|
||||
<div className={styles.fragments}>
|
||||
{[...Array(NUM_FRAGMENTS)].map((e, i) => {
|
||||
const loopStage = i + 1
|
||||
return interactive ? (
|
||||
<TranscendenceFragment
|
||||
key={`fragment_${loopStage}`}
|
||||
stage={loopStage}
|
||||
visible={loopStage <= visibleStage}
|
||||
interactive={interactive}
|
||||
onClick={handleFragmentClick}
|
||||
onHover={handleFragmentHover}
|
||||
/>
|
||||
) : (
|
||||
''
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<i className={baseImageClasses} />
|
||||
</div>
|
||||
<i className={baseImageClasses} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
TranscendenceStar.defaultProps = {
|
||||
stage: 0,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ const UncapIndicator = (props: Props) => {
|
|||
|
||||
const [popoverOpen, setPopoverOpen] = useState(false)
|
||||
|
||||
const transcendenceStarRef = React.createRef<HTMLDivElement>()
|
||||
|
||||
const classes = classNames(
|
||||
{
|
||||
[styles.wrapper]: true,
|
||||
|
|
@ -82,7 +84,11 @@ const UncapIndicator = (props: Props) => {
|
|||
|
||||
function sendTranscendenceStage(stage: number) {
|
||||
if (props.updateTranscendence) props.updateTranscendence(stage)
|
||||
togglePopover(false)
|
||||
setPopoverOpen(false)
|
||||
}
|
||||
|
||||
function handleStarClicked() {
|
||||
if (props.editable) togglePopover(!popoverOpen)
|
||||
}
|
||||
|
||||
const transcendence = (i: number) => {
|
||||
|
|
@ -90,25 +96,27 @@ const UncapIndicator = (props: Props) => {
|
|||
return props.type === 'character' || props.type === 'summon' ? (
|
||||
<TranscendencePopover
|
||||
open={popoverOpen}
|
||||
stage={props.transcendenceStage ? props.transcendenceStage : 0}
|
||||
stage={props.transcendenceStage || 0}
|
||||
type={props.type}
|
||||
onOpenChange={togglePopover}
|
||||
sendValue={sendTranscendenceStage}
|
||||
key={`star_${i}`}
|
||||
key={`popover_${i}_${popoverOpen}`}
|
||||
starRef={transcendenceStarRef}
|
||||
tabIndex={tabIndex}
|
||||
>
|
||||
<TranscendenceStar
|
||||
key={`star_${i}`}
|
||||
stage={props.transcendenceStage}
|
||||
stage={props.transcendenceStage || 0}
|
||||
editable={props.editable}
|
||||
interactive={false}
|
||||
onStarClick={() => togglePopover(true)}
|
||||
ref={transcendenceStarRef}
|
||||
onStarClick={handleStarClicked}
|
||||
/>
|
||||
</TranscendencePopover>
|
||||
) : (
|
||||
<TranscendenceStar
|
||||
key={`star_${i}`}
|
||||
stage={props.transcendenceStage}
|
||||
stage={props.transcendenceStage || 0}
|
||||
editable={props.editable}
|
||||
interactive={false}
|
||||
tabIndex={tabIndex}
|
||||
|
|
|
|||
Loading…
Reference in a new issue