Skip to content

Commit

Permalink
fix(ux): auto focus input when top modal dismiss
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <tukon479@gmail.com>
  • Loading branch information
Innei committed Oct 15, 2024
1 parent 74abfd3 commit 3c27768
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 12 deletions.
4 changes: 2 additions & 2 deletions apps/renderer/src/components/ui/modal/stacked/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
5 changes: 4 additions & 1 deletion apps/renderer/src/components/ui/modal/stacked/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -147,3 +148,5 @@ export const useResizeableModal = (
preferDragDir,
}
}

export const useIsTopModal = () => useContextSelector(CurrentModalStateContext, (v) => v.isTop)
35 changes: 29 additions & 6 deletions apps/renderer/src/components/ui/modal/stacked/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -220,6 +220,7 @@ export const ModalInternal = memo(
}
/>
)

if (CustomModalComponent) {
return (
<Wrapper>
Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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>
Expand All @@ -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>
)
}
7 changes: 4 additions & 3 deletions apps/renderer/src/modules/discover/DiscoverFeedForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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()

Expand Down

0 comments on commit 3c27768

Please sign in to comment.