Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: revamp z-index usage #864

Merged
merged 7 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const ContextMenuSubContent = React.forwardRef<
<ContextMenuPrimitive.SubContent
ref={ref}
className={cn(
"z-[1001] min-w-32 overflow-hidden rounded-md border bg-theme-modal-background-opaque p-1 text-theme-foreground/90 shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:shadow-zinc-800/60",
"min-w-32 overflow-hidden rounded-md border bg-theme-modal-background-opaque p-1 text-theme-foreground/90 shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:shadow-zinc-800/60",
className,
)}
{...props}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import { jotaiStore } from "~/lib/jotai"
import { cn } from "~/lib/utils"

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 @@ -40,12 +38,9 @@ const DeclarativeModalImpl: FC<DeclarativeModalProps> = ({
return (
<AnimatePresence>
{open && (
<>
<ModalInternal isTop onClose={onOpenChange} index={index} item={item}>
{children}
</ModalInternal>
<ModalOverlay zIndex={MODAL_STACK_Z_INDEX - 1 + index} />
</>
<ModalInternal isTop onClose={onOpenChange} index={index} item={item}>
{children}
</ModalInternal>
)}
</AnimatePresence>
)
Expand Down
32 changes: 20 additions & 12 deletions apps/renderer/src/components/ui/modal/stacked/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ import { Divider } from "../../divider"
import { RootPortalProvider } from "../../portal/provider"
import { EllipsisHorizontalTextWithTooltip } from "../../typography"
import { modalStackAtom } from "./atom"
import { MODAL_STACK_Z_INDEX, modalMontionConfig } from "./constants"
import { modalMontionConfig } from "./constants"
import type { CurrentModalContentProps, ModalActionsInternal } from "./context"
import { CurrentModalContext } from "./context"
import { useResizeableModal } from "./hooks"
import type { ModalProps } from "./types"
import { ModalOverlay } from "./overlay"
import type { ModalOverlayOptions, ModalProps } from "./types"

const DragBar = isElectronBuild ? (
<span className="drag-region fixed left-0 right-36 top-0 h-8" />
Expand All @@ -51,9 +52,10 @@ export const ModalInternal = memo(
index: number

isTop: boolean
overlayOptions?: ModalOverlayOptions
onClose?: (open: boolean) => void
} & PropsWithChildren
>(function Modal({ item, index, onClose: onPropsClose, children, isTop }, ref) {
>(function Modal({ item, overlayOptions, onClose: onPropsClose, children, isTop }, ref) {
const {
CustomModalComponent,
modalClassName,
Expand Down Expand Up @@ -96,8 +98,8 @@ export const ModalInternal = memo(
)

const opaque = useUISettingKey("modalOpaque")
const modalSettingOverlay = useUISettingKey("modalOverlay")

const zIndexStyle = useMemo(() => ({ zIndex: MODAL_STACK_Z_INDEX + index + 1 }), [index])
const dismiss = useCallback(
(e: SyntheticEvent) => {
e.stopPropagation()
Expand Down Expand Up @@ -224,10 +226,7 @@ export const ModalInternal = memo(
}
}, [switchHotkeyScope])

const modalStyle = useMemo(
() => ({ ...zIndexStyle, ...resizeableStyle }),
[resizeableStyle, zIndexStyle],
)
const modalStyle = resizeableStyle
const isSelectingRef = useRef(false)
const handleSelectStart = useCallback(() => {
isSelectingRef.current = true
Expand Down Expand Up @@ -269,25 +268,34 @@ export const ModalInternal = memo(
}, [])

useImperativeHandle(ref, () => modalElementRef.current!)

const Overlay = (
<ModalOverlay
blur={overlayOptions?.blur}
className={cn(overlayOptions?.className, {
hidden: item.overlay ? false : !modalSettingOverlay,
})}
/>
)
if (CustomModalComponent) {
return (
<Wrapper>
<Dialog.Root open onOpenChange={onClose} modal={modal}>
<Dialog.Portal>
{Overlay}
<Dialog.DialogTitle className="sr-only">{title}</Dialog.DialogTitle>
<Dialog.Content asChild onOpenAutoFocus={openAutoFocus}>
<div
ref={edgeElementRef}
className={cn(
"no-drag-region fixed z-20",
"no-drag-region fixed",
modal ? "inset-0 overflow-auto" : "left-0 top-0",
currentIsClosing ? "!pointer-events-none" : "!pointer-events-auto",
modalContainerClassName,
)}
onPointerUp={handleDetectSelectEnd}
onClick={handleClickOutsideToDismiss}
onFocus={stopPropagation}
style={zIndexStyle}
>
{DragBar}
<div
Expand Down Expand Up @@ -315,12 +323,12 @@ export const ModalInternal = memo(
<Wrapper>
<Dialog.Root modal={modal} open onOpenChange={onClose}>
<Dialog.Portal>
{Overlay}
<Dialog.Content asChild onOpenAutoFocus={openAutoFocus}>
<div
ref={edgeElementRef}
style={zIndexStyle}
className={cn(
"fixed z-20 flex",
"fixed flex",
modal ? "inset-0 overflow-auto" : "left-0 top-0",
currentIsClosing && "!pointer-events-none",
modalContainerClassName,
Expand Down
11 changes: 7 additions & 4 deletions apps/renderer/src/components/ui/modal/stacked/overlay.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as Dialog from "@radix-ui/react-dialog"
import type { ForwardedRef } from "react"
import { forwardRef } from "react"

import { m } from "~/components/common/Motion"
import { cn } from "~/lib/utils"

import { RootPortal } from "../../portal"
import { softSpringPreset } from "../../constants/spring"

export const ModalOverlay = forwardRef(
(
Expand All @@ -19,20 +20,22 @@ export const ModalOverlay = forwardRef(
},
ref: ForwardedRef<HTMLDivElement>,
) => (
<RootPortal>
<Dialog.Overlay asChild>
<m.div
ref={ref}
id="modal-overlay"
className={cn(
"!pointer-events-none fixed inset-0 z-[11] rounded-[var(--fo-window-radius)] bg-zinc-50/80 dark:bg-neutral-900/80",
// NOTE: pointer-events-none is required, if remove this, when modal is closing, you can not click element behind the modal
"!pointer-events-none fixed inset-0 rounded-[var(--fo-window-radius)] bg-zinc-50/80 dark:bg-neutral-900/80",
blur && "backdrop-blur-sm",
className,
)}
transition={softSpringPreset}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
style={{ zIndex }}
/>
</RootPortal>
</Dialog.Overlay>
),
)
17 changes: 1 addition & 16 deletions apps/renderer/src/components/ui/modal/stacked/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@ import { AnimatePresence } from "framer-motion"
import { useAtomValue } from "jotai"
import type { FC, PropsWithChildren } from "react"

import { useUISettingKey } from "~/atoms/settings/ui"

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

export const ModalStackProvider: FC<PropsWithChildren> = ({ children }) => (
<>
Expand All @@ -19,11 +15,6 @@ export const ModalStackProvider: FC<PropsWithChildren> = ({ children }) => (
const ModalStack = () => {
const stack = useAtomValue(modalStackAtom)

const modalSettingOverlay = useUISettingKey("modalOverlay")

const forceOverlay = stack.some((item) => item.overlay)
const allForceHideOverlay = stack.every((item) => item.overlay === false)

const topModalIndex = stack.findLastIndex((item) => item.modal)
const overlayIndex = stack.findLastIndex((item) => item.overlay || item.modal)
const overlayOptions = stack[overlayIndex]?.overlayOptions
Expand All @@ -35,15 +26,9 @@ const ModalStack = () => {
item={item}
index={index * 2}
isTop={index === topModalIndex * 2}
overlayOptions={overlayOptions}
/>
))}
{stack.length > 0 && (modalSettingOverlay || forceOverlay) && !allForceHideOverlay && (
<ModalOverlay
zIndex={MODAL_STACK_Z_INDEX + overlayIndex * 2 - 2}
blur={overlayOptions?.blur}
className={overlayOptions?.className}
/>
)}
</AnimatePresence>
)
}
2 changes: 1 addition & 1 deletion apps/renderer/src/components/ui/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const SelectContent = React.forwardRef<
<SelectPrimitive.Content
ref={ref}
className={cn(
"shadow-perfect relative z-[1000] max-h-96 min-w-32 overflow-hidden rounded-md border bg-popover text-popover-foreground",
"shadow-perfect relative max-h-96 min-w-32 overflow-hidden rounded-md border bg-popover text-popover-foreground",
position === "popper" && [
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
Expand Down
39 changes: 21 additions & 18 deletions apps/renderer/src/modules/panel/cmdf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react
import { useDebounceCallback, useEventCallback } from "usehooks-ts"

import { softSpringPreset } from "~/components/ui/constants/spring"
import { RootPortal } from "~/components/ui/portal"
import { useInputComposition, useRefValue } from "~/hooks/common"
import { tipcClient } from "~/lib/client"
import { nextFrame } from "~/lib/dom"
Expand Down Expand Up @@ -117,7 +118,7 @@ const CmdFImpl: FC<{
e.preventDefault()
nativeSearch(value)
}}
className="center shadow-perfect fixed right-8 top-12 z-[1000] size-9 w-64 gap-2 rounded-2xl border bg-zinc-50/90 pl-3 pr-2 backdrop-blur duration-200 focus-within:border-accent dark:bg-neutral-800/80"
className="center shadow-perfect fixed right-8 top-12 size-9 w-64 gap-2 rounded-2xl border bg-zinc-50/90 pl-3 pr-2 backdrop-blur duration-200 focus-within:border-accent dark:bg-neutral-800/80"
>
<div className="relative h-full grow">
<input
Expand Down Expand Up @@ -238,22 +239,24 @@ export const CmdF = () => {
setShow(true)
})
return (
<AnimatePresence>
{show && (
<m.div
className="relative z-[1000]"
initial={{ opacity: 0.8, y: -150 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -150 }}
transition={softSpringPreset}
>
<CmdFImpl
onClose={() => {
setShow(false)
}}
/>
</m.div>
)}
</AnimatePresence>
<RootPortal>
<AnimatePresence>
{show && (
<m.div
className="fixed top-0 w-full"
initial={{ opacity: 0.8, y: -150 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -150 }}
transition={softSpringPreset}
>
<CmdFImpl
onClose={() => {
setShow(false)
}}
/>
</m.div>
)}
</AnimatePresence>
</RootPortal>
)
}
10 changes: 5 additions & 5 deletions apps/renderer/src/pages/(main)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,6 @@ export function Component() {
</AppErrorBoundary>
</main>

<SearchCmdK />
<CmdNTrigger />
{ELECTRON && <CmdF />}

{isAuthFail && !user && (
<RootPortal>
<DeclarativeModal
Expand All @@ -141,6 +137,10 @@ export function Component() {
</DeclarativeModal>
</RootPortal>
)}

<SearchCmdK />
<CmdNTrigger />
{ELECTRON && <CmdF />}
</RootContainer>
)
}
Expand All @@ -155,7 +155,7 @@ const RootContainer = forwardRef<HTMLDivElement, PropsWithChildren>(({ children
"--fo-feed-col-w": `${feedColWidth}px`,
} as any
}
className="flex h-screen overflow-hidden"
className="relative z-0 flex h-screen overflow-hidden"
onContextMenu={preventDefault}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const AppLayoutGridContainerProvider: FC<PropsWithChildren> = ({ children

return (
<AppLayoutGridContainerWidthContext.Provider value={width}>
<div ref={ref} className="contents">
<div ref={ref} className="relative z-0 contents">
{children}
</div>
</AppLayoutGridContainerWidthContext.Provider>
Expand Down
13 changes: 7 additions & 6 deletions apps/renderer/src/providers/root-providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,20 @@ export const RootProviders: FC<PropsWithChildren> = ({ children }) => (
<EventProvider />

<UserProvider />

<StableRouterProvider />
<SettingSync />

{import.meta.env.DEV && <Devtools />}
{children}

<Suspense>
<LazyExtensionExposeProvider />
<LazyModalStackProvider />
<LazyContextMenuProvider />
<LazyLottieRenderContainer />
<LazyFeatureFlagDebugger />
</Suspense>

<StableRouterProvider />
<SettingSync />

{import.meta.env.DEV && <Devtools />}
{children}
<Toaster />
</I18nProvider>
</Provider>
Expand Down
Loading