fix(ux): auto focus input when top modal dismiss
Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
parent
74abfd3907
commit
3c27768830
|
|
@ -21,9 +21,9 @@ const defaultCtxValue: CurrentModalContentProps = {
|
|||
|
||||
export const CurrentModalContext = reactCreateContext<CurrentModalContentProps>(defaultCtxValue)
|
||||
export const CurrentModalStateContext = createContextSelector<{
|
||||
isActive: boolean
|
||||
isTop: boolean
|
||||
}>({
|
||||
isActive: false,
|
||||
isTop: true,
|
||||
})
|
||||
|
||||
export type ModalContentComponent<T = object> = FC<ModalActionsInternal & T>
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ import type { DragControls } from "framer-motion"
|
|||
import type { ResizeCallback, ResizeStartCallback } from "re-resizable"
|
||||
import { useCallback, useContext, useId, useRef, useState } from "react"
|
||||
import { flushSync } from "react-dom"
|
||||
import { useContextSelector } from "use-context-selector"
|
||||
import { useEventCallback } from "usehooks-ts"
|
||||
|
||||
import { getUISettings } from "~/atoms/settings/ui"
|
||||
import { jotaiStore } from "~/lib/jotai"
|
||||
|
||||
import { modalStackAtom } from "./atom"
|
||||
import { CurrentModalContext } from "./context"
|
||||
import { CurrentModalContext, CurrentModalStateContext } from "./context"
|
||||
import type { ModalProps, ModalStackOptions } from "./types"
|
||||
|
||||
export const modalIdToPropsMap = {} as Record<string, ModalProps>
|
||||
|
|
@ -147,3 +148,5 @@ export const useResizeableModal = (
|
|||
preferDragDir,
|
||||
}
|
||||
}
|
||||
|
||||
export const useIsTopModal = () => useContextSelector(CurrentModalStateContext, (v) => v.isTop)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import type { BoundingBox } from "framer-motion"
|
|||
import { produce } from "immer"
|
||||
import { useSetAtom } from "jotai"
|
||||
import { Resizable } from "re-resizable"
|
||||
import type { PropsWithChildren, SyntheticEvent } from "react"
|
||||
import type { FC, PropsWithChildren, SyntheticEvent } from "react"
|
||||
import {
|
||||
createElement,
|
||||
forwardRef,
|
||||
|
|
@ -34,7 +34,7 @@ import { EllipsisHorizontalTextWithTooltip } from "../../typography"
|
|||
import { modalStackAtom } from "./atom"
|
||||
import { MODAL_STACK_Z_INDEX, modalMontionConfig } from "./constants"
|
||||
import type { CurrentModalContentProps, ModalActionsInternal } from "./context"
|
||||
import { CurrentModalContext } from "./context"
|
||||
import { CurrentModalContext, CurrentModalStateContext } from "./context"
|
||||
import { useModalAnimate } from "./internal/use-animate"
|
||||
import { useModalResizeAndDrag } from "./internal/use-drag"
|
||||
import { useModalSelect } from "./internal/use-select"
|
||||
|
|
@ -220,6 +220,7 @@ export const ModalInternal = memo(
|
|||
}
|
||||
/>
|
||||
)
|
||||
|
||||
if (CustomModalComponent) {
|
||||
return (
|
||||
<Wrapper>
|
||||
|
|
@ -251,9 +252,9 @@ export const ModalInternal = memo(
|
|||
onSelect={handleSelectStart}
|
||||
onKeyUp={handleDetectSelectEnd}
|
||||
>
|
||||
<CurrentModalContext.Provider value={ModalContextProps}>
|
||||
<ModalContext modalContextProps={ModalContextProps} isTop={!!isTop}>
|
||||
<CustomModalComponent>{finalChildren}</CustomModalComponent>
|
||||
</CurrentModalContext.Provider>
|
||||
</ModalContext>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
|
|
@ -350,9 +351,9 @@ export const ModalInternal = memo(
|
|||
<Divider className="my-2 shrink-0 border-slate-200 opacity-80 dark:border-neutral-800" />
|
||||
|
||||
<div className="min-h-0 shrink grow overflow-auto px-4 py-2">
|
||||
<CurrentModalContext.Provider value={ModalContextProps}>
|
||||
<ModalContext modalContextProps={ModalContextProps} isTop={!!isTop}>
|
||||
{finalChildren}
|
||||
</CurrentModalContext.Provider>
|
||||
</ModalContext>
|
||||
</div>
|
||||
</ResizeSwitch>
|
||||
</m.div>
|
||||
|
|
@ -374,3 +375,25 @@ const useShortcutScope = () => {
|
|||
}
|
||||
}, [switchHotkeyScope])
|
||||
}
|
||||
|
||||
const ModalContext: FC<
|
||||
PropsWithChildren & {
|
||||
modalContextProps: CurrentModalContentProps
|
||||
isTop: boolean
|
||||
}
|
||||
> = ({ modalContextProps, isTop, children }) => {
|
||||
return (
|
||||
<CurrentModalContext.Provider value={modalContextProps}>
|
||||
<CurrentModalStateContext.Provider
|
||||
value={useMemo(
|
||||
() => ({
|
||||
isTop: !!isTop,
|
||||
}),
|
||||
[isTop],
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</CurrentModalStateContext.Provider>
|
||||
</CurrentModalContext.Provider>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { CopyButton } from "~/components/ui/code-highlighter"
|
|||
import { Form, FormItem, FormLabel } from "~/components/ui/form"
|
||||
import { Input } from "~/components/ui/input"
|
||||
import { Markdown } from "~/components/ui/markdown"
|
||||
import { useCurrentModal, useModalStack } from "~/components/ui/modal"
|
||||
import { useCurrentModal, useIsTopModal, useModalStack } from "~/components/ui/modal"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
|
|
@ -226,12 +226,13 @@ export const DiscoverFeedForm = ({
|
|||
)
|
||||
|
||||
const formElRef = useRef<HTMLFormElement>(null)
|
||||
|
||||
const isTop = useIsTopModal()
|
||||
useLayoutEffect(() => {
|
||||
if (!isTop) return
|
||||
const $form = formElRef.current
|
||||
if (!$form) return
|
||||
$form.querySelectorAll("input")[0]?.focus()
|
||||
}, [formElRef])
|
||||
}, [formElRef, isTop])
|
||||
|
||||
const modal = useCurrentModal()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue