Add RadixPopover and refactor TranscendencePopover

This commit is contained in:
Justin Edmund 2023-01-22 19:27:04 -08:00
parent eb8183fe29
commit 7876f0d9a7
8 changed files with 226 additions and 49 deletions

View file

@ -0,0 +1,6 @@
.Popover {
background: var(--dialog-bg);
border-radius: $card-corner;
border: 0.5px solid rgba(0, 0, 0, 0.18);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.24);
}

View file

@ -0,0 +1,37 @@
import React, { PropsWithChildren } from 'react'
import classnames from 'classnames'
import * as PopoverPrimitive from '@radix-ui/react-popover'
import './index.scss'
interface Props
extends React.DetailedHTMLProps<
React.DialogHTMLAttributes<HTMLDivElement>,
HTMLDivElement
> {}
export const Popover = PopoverPrimitive.Root
export const PopoverAnchor = PopoverPrimitive.Anchor
export const PopoverTrigger = PopoverPrimitive.Trigger
export const PopoverContent = React.forwardRef<HTMLDivElement, Props>(
({ children, ...props }: PropsWithChildren<Props>, forwardedRef) => {
const classes = classnames(props.className, {
Popover: true,
})
return (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
sideOffset={5}
{...props}
className={classes}
ref={forwardedRef}
>
{children}
<PopoverPrimitive.Arrow />
</PopoverPrimitive.Content>
</PopoverPrimitive.Portal>
)
}
)

View file

@ -1,21 +1,16 @@
.Transcendence.Popover { .Transcendence.Popover {
align-items: center; align-items: center;
background: var(--dialog-bg);
border-radius: $card-corner;
border: 0.5px solid rgba(0, 0, 0, 0.18);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.24);
display: none;
flex-direction: column; flex-direction: column;
gap: $unit-half; gap: $unit-half;
display: flex;
width: 80px; width: 80px;
height: 80px; height: 80px;
padding: $unit; padding: $unit;
justify-content: center; justify-content: center;
position: absolute; // position: absolute;
opacity: 0; z-index: 32;
z-index: 31; // top: -32px;
top: -32px; // right: -40px;
right: -40px;
&.open { &.open {
opacity: 1; opacity: 1;

View file

@ -1,8 +1,10 @@
import React, { useEffect, useState } from 'react' import React, { PropsWithChildren, useEffect, useState } from 'react'
import { useTranslation } from 'next-i18next' import { useTranslation } from 'next-i18next'
import classNames from 'classnames' import classNames from 'classnames'
import { Popover, PopoverAnchor, PopoverContent } from '~components/Popover'
import TranscendenceStar from '~components/TranscendenceStar' import TranscendenceStar from '~components/TranscendenceStar'
import './index.scss' import './index.scss'
interface Props interface Props
@ -10,7 +12,6 @@ interface Props
React.DialogHTMLAttributes<HTMLDivElement>, React.DialogHTMLAttributes<HTMLDivElement>,
HTMLDivElement HTMLDivElement
> { > {
className?: string
open: boolean open: boolean
stage: number stage: number
onOpenChange?: (open: boolean) => void onOpenChange?: (open: boolean) => void
@ -18,36 +19,71 @@ interface Props
} }
const TranscendencePopover = ({ const TranscendencePopover = ({
className, children,
open: popoverOpen, open: popoverOpen,
stage, stage,
tabIndex, tabIndex,
onOpenChange, onOpenChange,
sendValue, sendValue,
}: Props) => { }: PropsWithChildren<Props>) => {
const { t } = useTranslation('common') const { t } = useTranslation('common')
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [currentStage, setCurrentStage] = useState(0) const [currentStage, setCurrentStage] = useState(0)
const popoverRef = React.createRef<HTMLDivElement>()
const classes = classNames({ const classes = classNames({
Transcendence: true, Transcendence: true,
Popover: true,
open: open,
}) })
const levelClasses = classNames({ const levelClasses = classNames({
Pending: stage != currentStage, Pending: stage != currentStage,
}) })
useEffect(() => {
const handleClickOutside = (event: Event) => {
const target = event.target instanceof Element ? event.target : null
console.log('Handling click outside...?')
console.log(popoverRef.current)
console.log(open)
if (
popoverRef.current &&
target &&
!popoverRef.current.contains(target) &&
open &&
onOpenChange
) {
onOpenChange(false)
}
}
document.addEventListener('click', handleClickOutside, true)
return () => {
document.removeEventListener('click', handleClickOutside, true)
}
}, [onOpenChange])
useEffect(() => {
if (open) popoverRef.current?.focus()
}, [])
useEffect(() => { useEffect(() => {
setCurrentStage(stage) setCurrentStage(stage)
}, [stage]) }, [stage])
useEffect(() => { useEffect(() => {
console.log(`Setting popover state to ${popoverOpen}`)
setOpen(popoverOpen) setOpen(popoverOpen)
if (popoverOpen) {
console.log(popoverRef.current)
popoverRef.current?.focus()
}
}, [popoverOpen]) }, [popoverOpen])
function handleFragmentClicked(newStage: number) { function handleFragmentClicked(newStage: number) {
@ -59,28 +95,32 @@ const TranscendencePopover = ({
setCurrentStage(newStage) setCurrentStage(newStage)
} }
function handleKeyPress(event: React.KeyboardEvent<HTMLDivElement>) { function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
console.log(`Key pressed, ${event.key}`) console.log(`Key pressed, ${event.key}`)
console.log(window.event)
if (event.key === 'Escape') { if (event.key === 'Escape') {
if (onOpenChange) onOpenChange(false) if (onOpenChange) onOpenChange(false)
} }
} }
return ( return (
<div className={classes} onKeyPress={handleKeyPress} tabIndex={tabIndex}> <Popover open={open} onOpenChange={onOpenChange}>
<TranscendenceStar <PopoverAnchor>{children}</PopoverAnchor>
className="Interactive Base" <PopoverContent className={classes} ref={popoverRef} tabIndex={tabIndex}>
editable={true} <TranscendenceStar
interactive={true} className="Interactive Base"
stage={stage} editable={true}
onFragmentClick={handleFragmentClicked} interactive={true}
onFragmentHover={handleFragmentHovered} stage={stage}
/> onFragmentClick={handleFragmentClicked}
<h4> onFragmentHover={handleFragmentHovered}
<span>{t('level')}&nbsp;</span> />
<span className={levelClasses}>{100 + 10 * currentStage}</span> <h4>
</h4> <span>{t('level')}&nbsp;</span>
</div> <span className={levelClasses}>{100 + 10 * currentStage}</span>
</h4>
</PopoverContent>
</Popover>
) )
} }

View file

@ -82,7 +82,7 @@ const TranscendenceStar = ({
} }
return ( return (
<li <div
className={starClasses} className={starClasses}
onClick={editable ? handleClick : () => {}} onClick={editable ? handleClick : () => {}}
onMouseLeave={interactive ? handleMouseLeave : () => {}} onMouseLeave={interactive ? handleMouseLeave : () => {}}
@ -106,7 +106,7 @@ const TranscendenceStar = ({
})} })}
</div> </div>
<i className={baseImageClasses} /> <i className={baseImageClasses} />
</li> </div>
) )
} }

View file

@ -1,9 +1,9 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import UncapStar from '~components/UncapStar' import UncapStar from '~components/UncapStar'
import TranscendencePopover from '~components/TranscendencePopover'
import TranscendenceStar from '~components/TranscendenceStar' import TranscendenceStar from '~components/TranscendenceStar'
import './index.scss' import './index.scss'
import TranscendencePopover from '~components/TranscendencePopover'
interface Props { interface Props {
type: 'character' | 'weapon' | 'summon' type: 'character' | 'weapon' | 'summon'
@ -76,7 +76,24 @@ const UncapIndicator = (props: Props) => {
} }
const transcendence = (i: number) => { const transcendence = (i: number) => {
return ( return props.type === 'character' || props.type === 'summon' ? (
<TranscendencePopover
open={popoverOpen}
stage={props.transcendenceStage ? props.transcendenceStage : 0}
onOpenChange={togglePopover}
sendValue={sendTranscendenceStage}
tabIndex={props.position * 7 + 7 + 1}
>
<TranscendenceStar
key={`star_${i}`}
stage={props.transcendenceStage}
editable={props.editable}
interactive={false}
onStarClick={() => togglePopover(true)}
tabIndex={props.position * 7 + i + 1}
/>
</TranscendencePopover>
) : (
<TranscendenceStar <TranscendenceStar
key={`star_${i}`} key={`star_${i}`}
stage={props.transcendenceStage} stage={props.transcendenceStage}
@ -129,19 +146,7 @@ const UncapIndicator = (props: Props) => {
) )
} }
const transcendencePopover = () => { const transcendencePopover = () => {}
return props.type === 'character' || props.type === 'summon' ? (
<TranscendencePopover
open={popoverOpen}
stage={props.transcendenceStage ? props.transcendenceStage : 0}
onOpenChange={togglePopover}
sendValue={sendTranscendenceStage}
tabIndex={props.position * 7 + 7 + 1}
/>
) : (
''
)
}
return ( return (
<div className="Uncap"> <div className="Uncap">

93
package-lock.json generated
View file

@ -10,6 +10,7 @@
"@radix-ui/react-dialog": "^1.0.2", "@radix-ui/react-dialog": "^1.0.2",
"@radix-ui/react-dropdown-menu": "^2.0.1", "@radix-ui/react-dropdown-menu": "^2.0.1",
"@radix-ui/react-hover-card": "^1.0.2", "@radix-ui/react-hover-card": "^1.0.2",
"@radix-ui/react-popover": "^1.0.3",
"@radix-ui/react-select": "^1.1.2", "@radix-ui/react-select": "^1.1.2",
"@radix-ui/react-switch": "^1.0.1", "@radix-ui/react-switch": "^1.0.1",
"@radix-ui/react-toast": "^1.1.2", "@radix-ui/react-toast": "^1.1.2",
@ -2325,6 +2326,55 @@
"react-dom": "^16.8 || ^17.0 || ^18.0" "react-dom": "^16.8 || ^17.0 || ^18.0"
} }
}, },
"node_modules/@radix-ui/react-popover": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.0.3.tgz",
"integrity": "sha512-YwedSukfWsyJs3/yP3yXUq44k4/JBe3jqU63Z8v2i19qZZ3dsx32oma17ztgclWPNuqp3A+Xa9UiDlZHyVX8Vg==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-dismissable-layer": "1.0.2",
"@radix-ui/react-focus-guards": "1.0.0",
"@radix-ui/react-focus-scope": "1.0.1",
"@radix-ui/react-id": "1.0.0",
"@radix-ui/react-popper": "1.1.0",
"@radix-ui/react-portal": "1.0.1",
"@radix-ui/react-presence": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-slot": "1.0.1",
"@radix-ui/react-use-controllable-state": "1.0.0",
"aria-hidden": "^1.1.1",
"react-remove-scroll": "2.5.5"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-popper": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.0.tgz",
"integrity": "sha512-07U7jpI0dZcLRAxT7L9qs6HecSoPhDSJybF7mEGHJDBDv+ZoGCvIlva0s+WxMXwJEav+ckX3hAlXBtnHmuvlCQ==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@floating-ui/react-dom": "0.7.2",
"@radix-ui/react-arrow": "1.0.1",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-use-callback-ref": "1.0.0",
"@radix-ui/react-use-layout-effect": "1.0.0",
"@radix-ui/react-use-rect": "1.0.0",
"@radix-ui/react-use-size": "1.0.0",
"@radix-ui/rect": "1.0.0"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-popper": { "node_modules/@radix-ui/react-popper": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.0.1.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.0.1.tgz",
@ -8809,6 +8859,49 @@
"react-remove-scroll": "2.5.5" "react-remove-scroll": "2.5.5"
} }
}, },
"@radix-ui/react-popover": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.0.3.tgz",
"integrity": "sha512-YwedSukfWsyJs3/yP3yXUq44k4/JBe3jqU63Z8v2i19qZZ3dsx32oma17ztgclWPNuqp3A+Xa9UiDlZHyVX8Vg==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-dismissable-layer": "1.0.2",
"@radix-ui/react-focus-guards": "1.0.0",
"@radix-ui/react-focus-scope": "1.0.1",
"@radix-ui/react-id": "1.0.0",
"@radix-ui/react-popper": "1.1.0",
"@radix-ui/react-portal": "1.0.1",
"@radix-ui/react-presence": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-slot": "1.0.1",
"@radix-ui/react-use-controllable-state": "1.0.0",
"aria-hidden": "^1.1.1",
"react-remove-scroll": "2.5.5"
},
"dependencies": {
"@radix-ui/react-popper": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.0.tgz",
"integrity": "sha512-07U7jpI0dZcLRAxT7L9qs6HecSoPhDSJybF7mEGHJDBDv+ZoGCvIlva0s+WxMXwJEav+ckX3hAlXBtnHmuvlCQ==",
"requires": {
"@babel/runtime": "^7.13.10",
"@floating-ui/react-dom": "0.7.2",
"@radix-ui/react-arrow": "1.0.1",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-use-callback-ref": "1.0.0",
"@radix-ui/react-use-layout-effect": "1.0.0",
"@radix-ui/react-use-rect": "1.0.0",
"@radix-ui/react-use-size": "1.0.0",
"@radix-ui/rect": "1.0.0"
}
}
}
},
"@radix-ui/react-popper": { "@radix-ui/react-popper": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.0.1.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.0.1.tgz",

View file

@ -15,6 +15,7 @@
"@radix-ui/react-dialog": "^1.0.2", "@radix-ui/react-dialog": "^1.0.2",
"@radix-ui/react-dropdown-menu": "^2.0.1", "@radix-ui/react-dropdown-menu": "^2.0.1",
"@radix-ui/react-hover-card": "^1.0.2", "@radix-ui/react-hover-card": "^1.0.2",
"@radix-ui/react-popover": "^1.0.3",
"@radix-ui/react-select": "^1.1.2", "@radix-ui/react-select": "^1.1.2",
"@radix-ui/react-switch": "^1.0.1", "@radix-ui/react-switch": "^1.0.1",
"@radix-ui/react-toast": "^1.1.2", "@radix-ui/react-toast": "^1.1.2",