refactor: update SidePeek composition
This commit is contained in:
@@ -1,55 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation"
|
||||
import React, { Children, cloneElement, useEffect, useState } from "react"
|
||||
|
||||
import SidePeek from "@/components/TempDesignSystem/SidePeek"
|
||||
import { SidePeekContentKey } from "@/components/TempDesignSystem/SidePeek/types"
|
||||
|
||||
export default function SidePeekContainer({
|
||||
children,
|
||||
}: React.PropsWithChildren) {
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
const searchParams = useSearchParams()
|
||||
const [activeSidePeek, setActiveSidePeek] =
|
||||
useState<SidePeekContentKey | null>(() => {
|
||||
const sidePeekParam = searchParams.get(
|
||||
"open"
|
||||
) as SidePeekContentKey | null
|
||||
return sidePeekParam || null
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const sidePeekParam = searchParams.get("open") as SidePeekContentKey | null
|
||||
if (sidePeekParam !== activeSidePeek) {
|
||||
setActiveSidePeek(sidePeekParam)
|
||||
}
|
||||
}, [searchParams, activeSidePeek])
|
||||
|
||||
function handleClose(isOpen: boolean) {
|
||||
if (!isOpen) {
|
||||
setActiveSidePeek(null)
|
||||
|
||||
const nextSearchParams = new URLSearchParams(searchParams.toString())
|
||||
nextSearchParams.delete("open")
|
||||
|
||||
router.push(`${pathname}?${nextSearchParams}`, { scroll: false })
|
||||
}
|
||||
}
|
||||
const childrenWithIsActive = Children.map(children, (child) => {
|
||||
if (!React.isValidElement(child)) {
|
||||
return child
|
||||
}
|
||||
return cloneElement(child as React.ReactElement, {
|
||||
isActive:
|
||||
(child.props.contentKey as SidePeekContentKey) === activeSidePeek,
|
||||
})
|
||||
})
|
||||
|
||||
return (
|
||||
<SidePeek activeContent={activeSidePeek} onClose={handleClose}>
|
||||
{childrenWithIsActive}
|
||||
</SidePeek>
|
||||
)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import { Children, PropsWithChildren } from "react"
|
||||
import { PropsWithChildren } from "react"
|
||||
|
||||
import { CloseIcon } from "@/components/Icons"
|
||||
import { SidePeekContentProps } from "@/components/TempDesignSystem/SidePeek/types"
|
||||
@@ -8,16 +8,16 @@ import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
|
||||
import Button from "../../Button"
|
||||
|
||||
import styles from "./content.module.css"
|
||||
import styles from "./sidePeekItem.module.css"
|
||||
|
||||
export default function Content({
|
||||
function SidePeekItem({
|
||||
title,
|
||||
children,
|
||||
isActive = false,
|
||||
onClose,
|
||||
}: PropsWithChildren<SidePeekContentProps>) {
|
||||
return isActive ? (
|
||||
<aside className={styles.content}>
|
||||
<aside className={styles.sidePeekItem}>
|
||||
<header className={styles.header}>
|
||||
<Title color="burgundy" textTransform="uppercase" level="h2" as="h3">
|
||||
{title}
|
||||
@@ -35,3 +35,5 @@ export default function Content({
|
||||
</aside>
|
||||
) : null
|
||||
}
|
||||
|
||||
export default SidePeekItem
|
||||
@@ -1,11 +1,11 @@
|
||||
.content {
|
||||
.sidePeekItem {
|
||||
display: grid;
|
||||
grid-template-rows: min-content auto;
|
||||
gap: var(--Spacing-x4);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.content > * {
|
||||
.content>* {
|
||||
padding: var(--Spacing-x3) var(--Spacing-x2);
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
@media and screen (min-width: 1367px) {
|
||||
.content > * {
|
||||
@media screen and (min-width: 1367px) {
|
||||
.content>* {
|
||||
padding: var(--Spacing-x4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
"use client"
|
||||
|
||||
import { useIsSSR } from "@react-aria/ssr"
|
||||
import { Children, cloneElement, PropsWithChildren } from "react"
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation"
|
||||
import React, { Children, cloneElement, useEffect, useState } from "react"
|
||||
import {
|
||||
Dialog,
|
||||
DialogTrigger,
|
||||
@@ -9,15 +10,54 @@ import {
|
||||
ModalOverlay,
|
||||
} from "react-aria-components"
|
||||
|
||||
import { SidePeekProps } from "./types"
|
||||
import { SidePeekContentKey } from "@/components/TempDesignSystem/SidePeek/types"
|
||||
|
||||
import styles from "./sidePeek.module.css"
|
||||
|
||||
export default function SidePeek({
|
||||
children,
|
||||
onClose,
|
||||
activeContent,
|
||||
}: PropsWithChildren<SidePeekProps>) {
|
||||
function SidePeek({ children }: React.PropsWithChildren) {
|
||||
// TODO: to make this more reusable,
|
||||
// should the param logic be moved up/out so this component can be
|
||||
// controlled by e.g. URL segments
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
const searchParams = useSearchParams()
|
||||
const [activeSidePeek, setActiveSidePeek] =
|
||||
useState<SidePeekContentKey | null>(() => {
|
||||
const sidePeekParam = searchParams.get(
|
||||
"open"
|
||||
) as SidePeekContentKey | null
|
||||
return sidePeekParam || null
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const sidePeekParam = searchParams.get("open") as SidePeekContentKey | null
|
||||
if (sidePeekParam !== activeSidePeek) {
|
||||
setActiveSidePeek(sidePeekParam)
|
||||
}
|
||||
}, [searchParams, activeSidePeek])
|
||||
|
||||
function handleClose(isOpen: boolean) {
|
||||
if (!isOpen) {
|
||||
setActiveSidePeek(null)
|
||||
|
||||
const nextSearchParams = new URLSearchParams(searchParams.toString())
|
||||
nextSearchParams.delete("open")
|
||||
|
||||
router.push(`${pathname}?${nextSearchParams}`, { scroll: false })
|
||||
}
|
||||
}
|
||||
|
||||
const sidePeekChildren = Children.map(children, (child) => {
|
||||
if (!React.isValidElement(child)) {
|
||||
return child
|
||||
}
|
||||
return cloneElement(child as React.ReactElement, {
|
||||
isActive:
|
||||
(child.props.contentKey as SidePeekContentKey) === activeSidePeek,
|
||||
onClose: handleClose,
|
||||
})
|
||||
})
|
||||
|
||||
const isSSR = useIsSSR()
|
||||
return isSSR ? (
|
||||
<div>{children}</div>
|
||||
@@ -25,24 +65,16 @@ export default function SidePeek({
|
||||
<DialogTrigger>
|
||||
<ModalOverlay
|
||||
className={styles.overlay}
|
||||
isOpen={!!activeContent}
|
||||
onOpenChange={onClose}
|
||||
isOpen={!!activeSidePeek}
|
||||
onOpenChange={handleClose}
|
||||
isDismissable
|
||||
>
|
||||
<Modal className={styles.sidePeek}>
|
||||
<Dialog className={styles.dialog}>
|
||||
{({ close }) => (
|
||||
<>
|
||||
{Children.map(children, (child) => {
|
||||
return cloneElement(child as React.ReactElement, {
|
||||
onClose: close,
|
||||
})
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</Dialog>
|
||||
<Dialog className={styles.dialog}>{sidePeekChildren}</Dialog>
|
||||
</Modal>
|
||||
</ModalOverlay>
|
||||
</DialogTrigger>
|
||||
)
|
||||
}
|
||||
|
||||
export default SidePeek
|
||||
Reference in New Issue
Block a user