update: better picker component

This commit is contained in:
alikia2x 2024-07-13 20:21:56 +08:00
parent 8d39e2833c
commit f4b9257dc9
3 changed files with 65 additions and 35 deletions

View File

@ -27,10 +27,27 @@ export default function Picker(props: PickerProps) {
return; return;
} }
const buttonRect = buttonRef.current.getBoundingClientRect(); const buttonRect = buttonRef.current.getBoundingClientRect();
const listWidth = itemListRef.current.getBoundingClientRect().width; const listRect = itemListRef.current.getBoundingClientRect();
// Align to center // Align to center
itemListRef.current.style.left = buttonRect.x + buttonRect.width / 2 - listWidth / 2 + "px"; itemListRef.current.style.left =
Math.max(
Math.min(
buttonRect.x + buttonRect.width / 2 - listRect.width / 2,
window.screen.width - listRect.width - 16
),
0
) + "px";
if (window.screen.height - buttonRect.top < 192) {
itemListRef.current.style.transformOrigin = "bottom center";
itemListRef.current.style.top = buttonRect.top - listRect.height - 16 + "px";
} else {
itemListRef.current.style.top = buttonRect.y + buttonRect.height + 16 + "px"; itemListRef.current.style.top = buttonRect.y + buttonRect.height + 16 + "px";
}
if (listRect.top + listRect.height > window.screen.height - 16) {
itemListRef.current.style.height = window.screen.height - listRect.top - 12 + "px";
} else {
itemListRef.current.style.height = "fit-content";
}
}; };
useEffect(() => { useEffect(() => {
@ -50,8 +67,8 @@ export default function Picker(props: PickerProps) {
function toggleDisplay(targetState?: boolean) { function toggleDisplay(targetState?: boolean) {
function hideList() { function hideList() {
if (itemListRef.current) { if (itemListRef.current) {
itemListRef.current.style.transitionDuration = "200ms";
itemListRef.current.style.opacity = "0%"; itemListRef.current.style.opacity = "0%";
itemListRef.current.style.transform = "scaleX(.85) scaleY(.85)";
} }
setTimeout(() => { setTimeout(() => {
setDisplayList(false); setDisplayList(false);
@ -60,10 +77,20 @@ export default function Picker(props: PickerProps) {
function showList() { function showList() {
setDisplayList(true); setDisplayList(true);
setTimeout(() => { setTimeout(() => {
if (!itemListRef.current || !buttonRef.current) {
return;
}
updatePosition(); updatePosition();
if (itemListRef.current) { if (window.screen.height - buttonRef.current.getBoundingClientRect().top < 128) {
itemListRef.current.style.transformOrigin = "bottom center";
}
itemListRef.current.style.transitionDuration = "100ms";
itemListRef.current.style.opacity = "100%"; itemListRef.current.style.opacity = "100%";
itemListRef.current.style.transform = "scaleX(1) scaleY(1)"; updatePosition();
const listRect = itemListRef.current.getBoundingClientRect();
if (listRect.top < 8) {
itemListRef.current.style.height = window.screen.height - 8 + "px";
itemListRef.current.style.top = "8px";
} }
}, 20); }, 20);
} }
@ -112,13 +139,15 @@ interface PickerListProps {
} }
const PickerList = React.forwardRef<HTMLDivElement, PickerListProps>((props, ref) => { const PickerList = React.forwardRef<HTMLDivElement, PickerListProps>((props, ref) => {
const { selected, selectionOnChange, selectionItems } = props; const { selected, selectionOnChange, selectionItems, toggleDisplay } = props;
return createPortal( return createPortal(
<div className="absolute w-screen h-screen" onClick={()=>{toggleDisplay(false)}}>
<div <div
ref={ref} ref={ref}
className="absolute w-fit text-black dark:text-white opacity-0 duration-200 className="overflow-y-auto fixed w-fit text-black dark:text-white opacity-0 duration-200
bg-zinc-50 shadow-lg border-1 border-zinc-200 dark:border-zinc-600 dark:bg-zinc-700 px-2 py-2 rounded-xl text-align-left scale-[.85]" bg-zinc-50 shadow-lg border-1 border-zinc-200 dark:border-zinc-600
dark:bg-zinc-800 px-2 py-2 rounded-xl text-align-left"
style={{ transformOrigin: "top center" }} style={{ transformOrigin: "top center" }}
> >
{Object.keys(selectionItems).map((key: string, index) => { {Object.keys(selectionItems).map((key: string, index) => {
@ -126,10 +155,10 @@ const PickerList = React.forwardRef<HTMLDivElement, PickerListProps>((props, ref
<div <div
key={index} key={index}
className="relative py-2 w-full min-w-32 pl-2 cursor-pointer rounded-lg className="relative py-2 w-full min-w-32 pl-2 cursor-pointer rounded-lg
hover:bg-zinc-200 dark:hover:bg-zinc-600 flex justify-between items-center" hover:bg-zinc-200 dark:hover:bg-zinc-700 flex justify-between items-center"
onClick={() => { onClick={() => {
selectionOnChange(key); selectionOnChange(key);
props.toggleDisplay(); toggleDisplay(false);
}} }}
> >
<span>{selectionItems[key]}</span> <span>{selectionItems[key]}</span>
@ -140,6 +169,7 @@ const PickerList = React.forwardRef<HTMLDivElement, PickerListProps>((props, ref
</div> </div>
); );
})} })}
</div>
</div>, </div>,
document.body document.body
); );

View File

@ -1,7 +1,7 @@
{ {
"name": "sparkhome", "name": "sparkhome",
"private": false, "private": false,
"version": "5.2.2", "version": "5.2.3",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "bun server.ts", "dev": "bun server.ts",

View File

@ -12,7 +12,7 @@ export default function Homepage() {
const setBgFocus = useSetAtom(bgFocusAtom); const setBgFocus = useSetAtom(bgFocusAtom);
return ( return (
<div className="h-full fixed overflow-hidden w-full bg-black"> <div className="h-screen fixed overflow-hidden w-screen bg-black">
<Background /> <Background />
<EngineSelector <EngineSelector
className="absolute top-20 lg:top-44 short:top-0 translate-x-[-50%] translate-y-[-0.2rem] className="absolute top-20 lg:top-44 short:top-0 translate-x-[-50%] translate-y-[-0.2rem]