Skip to content

Commit

Permalink
feat: modal
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <[email protected]>
  • Loading branch information
Innei committed Jun 26, 2024
1 parent 1149d24 commit 9098ebc
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 54 deletions.
5 changes: 5 additions & 0 deletions src/renderer/src/components/ui/modal/stacked/atom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { atom } from "jotai"

import type { ModalProps } from "./types"

export const modalStackAtom = atom([] as (ModalProps & { id: string })[])
2 changes: 2 additions & 0 deletions src/renderer/src/components/ui/modal/stacked/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ export const modalMontionConfig = {
exit: initialStyle,
transition: microReboundPreset,
}

export const MODAL_STACK_Z_INDEX = 100
10 changes: 1 addition & 9 deletions src/renderer/src/components/ui/modal/stacked/context.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { atom } from "jotai"
import type { FC, RefObject } from "react"
import { createContext, useContext } from "react"

import type { ModalProps } from "./types"

export const modalIdToPropsMap = {} as Record<string, ModalProps>
import { createContext } from "react"

export type CurrentModalContentProps = ModalContentPropsInternal & {
ref: RefObject<HTMLElement | null>
Expand All @@ -14,10 +9,7 @@ export const CurrentModalContext = createContext<CurrentModalContentProps>(
null as any,
)

export const useCurrentModal = () => useContext(CurrentModalContext)

export type ModalContentComponent<T> = FC<ModalContentPropsInternal & T>
export type ModalContentPropsInternal = {
dismiss: () => void
}
export const modalStackAtom = atom([] as (ModalProps & { id: string })[])
17 changes: 10 additions & 7 deletions src/renderer/src/components/ui/modal/stacked/declarative-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import { AnimatePresence } from "framer-motion"
import type { FC, ReactNode } from "react"
import { useId, useMemo } from "react"

import { modalStackAtom } from "./context"
import { modalStackAtom } from "./atom"
import { MODAL_STACK_Z_INDEX } from "./constants"
import { ModalInternal } from "./modal"
import { ModalOverlay } from "./overlay"
import type { ModalProps } from "./types"

export interface DeclarativeModalProps extends Omit<ModalProps, "content"> {
Expand Down Expand Up @@ -37,18 +39,19 @@ const DeclarativeModalImpl: FC<DeclarativeModalProps> = ({
return (
<AnimatePresence>
{open && (
<ModalInternal isTop onClose={onOpenChange} index={index} item={item}>
{children}
</ModalInternal>
<>
<ModalInternal isTop onClose={onOpenChange} index={index} item={item}>
{children}
</ModalInternal>
<ModalOverlay zIndex={MODAL_STACK_Z_INDEX - 1 + index} />
</>
)}
</AnimatePresence>
)
}

const FooterAction: Component = ({ children, className }) => (
<div
className={cn("mt-4 flex items-center justify-end gap-2", className)}
>
<div className={cn("mt-4 flex items-center justify-end gap-2", className)}>
{children}
</div>
)
Expand Down
8 changes: 6 additions & 2 deletions src/renderer/src/components/ui/modal/stacked/hooks.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { jotaiStore } from "@renderer/lib/jotai"
import { useUIStore } from "@renderer/store"
import { useCallback, useEffect, useId, useRef } from "react"
import { useCallback, useContext, useEffect, useId, useRef } from "react"
import { useLocation } from "react-router-dom"

import { modalIdToPropsMap, modalStackAtom } from "./context"
import { modalStackAtom } from "./atom"
import { CurrentModalContext } from "./context"
import type { ModalProps, ModalStackOptions } from "./types"

export const modalIdToPropsMap = {} as Record<string, ModalProps>
export const useModalStack = (options?: ModalStackOptions) => {
const id = useId()
const currentCount = useRef(0)
Expand Down Expand Up @@ -77,3 +79,5 @@ export const useDismissAllWhenRouterChange = () => {
actions.dismissAll()
}, [pathname])
}

export const useCurrentModal = () => useContext(CurrentModalContext)
1 change: 1 addition & 0 deletions src/renderer/src/components/ui/modal/stacked/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from "./context"
export * from "./helper"
export * from "./hooks"
export * from "./modal"
export * from "./provider"
export * from "./types"
49 changes: 14 additions & 35 deletions src/renderer/src/components/ui/modal/stacked/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,17 @@ import {
useRef,
} from "react"
import { useEventCallback } from "usehooks-ts"
import { useShallow } from "zustand/react/shallow"

import { Divider } from "../../divider"
import { modalMontionConfig } from "./constants"
import { modalStackAtom } from "./atom"
import { MODAL_STACK_Z_INDEX, modalMontionConfig } from "./constants"
import type {
CurrentModalContentProps,
ModalContentPropsInternal,
} from "./context"
import { CurrentModalContext, modalStackAtom } from "./context"
import { CurrentModalContext } from "./context"
import type { ModalProps } from "./types"

const DialogOverlay = ({
onClick,
zIndex,
}: {
onClick?: () => void
zIndex?: number
}) => (
<Dialog.Overlay asChild>
<m.div
onClick={onClick}
className="fixed inset-0 z-[11] bg-zinc-50/80 dark:bg-neutral-900/80"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
style={{ zIndex }}
/>
</Dialog.Overlay>
)

export const ModalInternal: Component<{
item: ModalProps & { id: string }
index: number
Expand Down Expand Up @@ -73,12 +54,13 @@ export const ModalInternal: Component<{
[close],
)

const { opaque, overlay: defaultOverlay } = useUIStore(
useShallow((state) => ({
overlay: state.modalOverlay,
opaque: state.modalOpaque,
})),
)
// const { opaque, overlay: defaultOverlay } = useUIStore(
// useShallow((state) => ({
// overlay: state.modalOverlay,
// opaque: state.modalOpaque,
// })),
// )
const opaque = useUIStore((state) => state.modalOpaque)

const {
CustomModalComponent,
Expand All @@ -90,10 +72,10 @@ export const ModalInternal: Component<{
wrapper: Wrapper = Fragment,
max,
icon,
overlay = defaultOverlay,

draggable = false,
} = item
const modalStyle = useMemo(() => ({ zIndex: 99 + index }), [index])
const zIndexStyle = useMemo(() => ({ zIndex: MODAL_STACK_Z_INDEX + index }), [index])
const dismiss = useCallback(
(e: SyntheticEvent) => {
e.stopPropagation()
Expand Down Expand Up @@ -180,8 +162,6 @@ export const ModalInternal: Component<{
<Wrapper>
<Dialog.Root open onOpenChange={onClose}>
<Dialog.Portal>
{overlay && <DialogOverlay zIndex={19} />}

<Dialog.DialogTitle className="sr-only">{title}</Dialog.DialogTitle>
<Dialog.Content asChild>
<div
Expand Down Expand Up @@ -209,19 +189,18 @@ export const ModalInternal: Component<{
<Wrapper>
<Dialog.Root open onOpenChange={onClose}>
<Dialog.Portal>
{overlay && <DialogOverlay zIndex={19 + index} />}

<Dialog.Content asChild>
<div
ref={edgeElementRef}
style={zIndexStyle}
className={cn(
"center fixed inset-0 z-20 flex",
modalContainerClassName,
)}
onClick={clickOutsideToDismiss ? dismiss : noticeModal}
>
<m.div
style={modalStyle}
style={zIndexStyle}
{...modalMontionConfig}
animate={animateController}
className={cn(
Expand Down
28 changes: 28 additions & 0 deletions src/renderer/src/components/ui/modal/stacked/overlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useUIStore } from "@renderer/store"
import { m } from "framer-motion"

import { RootPortal } from "../../portal"

export const ModalOverlay = ({
onClick,
zIndex,
}: {
onClick?: () => void
zIndex?: number
}) => {
const modalSettingOverlay = useUIStore((state) => state.modalOverlay)
if (!modalSettingOverlay) return null
return (
<RootPortal>
<m.div
id="modal-overlay"
onClick={onClick}
className="fixed inset-0 z-[11] bg-zinc-50/80 dark:bg-neutral-900/80"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
style={{ zIndex }}
/>
</RootPortal>
)
}
5 changes: 4 additions & 1 deletion src/renderer/src/components/ui/modal/stacked/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import { AnimatePresence } from "framer-motion"
import { useAtomValue } from "jotai"
import type { FC, PropsWithChildren } from "react"

import { modalStackAtom } from "./context"
import { modalStackAtom } from "./atom"
import { MODAL_STACK_Z_INDEX } from "./constants"
import { useDismissAllWhenRouterChange } from "./hooks"
import { ModalInternal } from "./modal"
import { ModalOverlay } from "./overlay"

export const ModalStackProvider: FC<PropsWithChildren> = ({ children }) => (
<>
Expand All @@ -28,6 +30,7 @@ const ModalStack = () => {
isTop={index === stack.length - 1}
/>
))}
{stack.length > 0 && <ModalOverlay zIndex={MODAL_STACK_Z_INDEX + stack.length - 1} />}
</AnimatePresence>
)
}

0 comments on commit 9098ebc

Please sign in to comment.