Skip to content

Commit

Permalink
feat: add useClickOutside hooks, hidden dropmenu when clickOutside
Browse files Browse the repository at this point in the history
  • Loading branch information
yzh990918 committed May 8, 2023
1 parent a699aac commit 01c7e8d
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 5 deletions.
5 changes: 3 additions & 2 deletions src/components/main/MessageItem.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { For, Show } from 'solid-js/web'
import { createSignal } from 'solid-js'
import { createSignal, onCleanup } from 'solid-js'
import { useStore } from '@nanostores/solid'
import { useClipboardCopy } from '@/hooks'
import { deleteMessageByConversationId, spliceMessageByConversationId, spliceUpdateMessageByConversationId } from '@/stores/messages'
Expand All @@ -20,12 +20,12 @@ interface Props {
}

export default (props: Props) => {
let inputRef: HTMLTextAreaElement
const $conversationMap = useStore(conversationMap)

const [showRawCode, setShowRawCode] = createSignal(false)
const [copied, setCopied] = createSignal(false)
const [isEditing, setIsEditing] = createSignal(false)
let inputRef: HTMLTextAreaElement
const [inputPrompt, setInputPrompt] = createSignal(props.message.content)

const currentConversation = () => {
Expand All @@ -38,6 +38,7 @@ export default (props: Props) => {
setCopied(Iscopied())
setTimeout(() => setCopied(false), 1000)
}

const handleDeleteMessageItem = () => {
deleteMessageByConversationId(props.conversationId, props.message)
}
Expand Down
14 changes: 11 additions & 3 deletions src/components/ui/base/DropdownMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import * as menu from '@zag-js/menu'
import { normalizeProps, useMachine } from '@zag-js/solid'
import { Show, children, createEffect, createMemo, createUniqueId } from 'solid-js'
import { Dynamic, For, Portal, spread } from 'solid-js/web'
import type { JSX, JSXElement } from 'solid-js'
import { useClickOutside } from '@/hooks'
import type { Accessor, JSX, JSXElement } from 'solid-js'

export interface MenuItem {
id: string
Expand All @@ -16,6 +17,7 @@ export interface MenuItem {
interface Props {
children: JSX.Element
menuList: MenuItem[]
close?: () => Accessor<boolean>
}

export const DropDownMenu = (props: Props) => {
Expand All @@ -31,6 +33,7 @@ export const DropDownMenu = (props: Props) => {
},
}),
)
let dropDownMenuRef: HTMLDivElement

const api = createMemo(() => menu.connect(state, send, normalizeProps))

Expand All @@ -45,15 +48,20 @@ export const DropDownMenu = (props: Props) => {
createEffect(() => {
// https://github.com/chakra-ui/zag/issues/595
api().setPositioning({})

dropDownMenuRef = document.getElementById('DropDownMenuRef') as HTMLDivElement
useClickOutside(dropDownMenuRef, () => {
api().close()
})
})

return (
<div class="!outline-none">
<div id="DropDownMenuRef" class="!outline-none" >
<Dynamic component={resolvedChild} />
<Show when={api().isOpen}>
<Portal>
<div {...api().positionerProps} z-20>
<div {...api().contentProps} class=" bg-white dark-bg-zinc-900 flex flex-col space-y-1 rounded-md shadow-md">
<div {...api().contentProps} class="bg-white dark-bg-zinc-900 flex flex-col space-y-1 rounded-md shadow-md ">
<Show when={api().isOpen}>
<For each={props.menuList}>
{item => (<div class="px-3 py-2 flex items-center space-x-2 hv-base" {...api().getItemProps({ id: item.id })}>{item.icon && <div class={item.icon} />}<div>{item.label}</div></div>)}
Expand Down
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './useDark'
export * from './useCopy'
export * from './useClickOutside'
25 changes: 25 additions & 0 deletions src/hooks/useClickOutside.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { createSignal, onCleanup } from 'solid-js'

export const useClickOutside = (ref: HTMLElement, handler: (e: MouseEvent) => any) => {
const [clickedOutside, setClickedOutside] = createSignal(false)

const handleClick = (event: MouseEvent) => {
if (ref && (ref.contains(event.target as Node) || event.composedPath().includes(ref))) {
setClickedOutside(false)
return clickedOutside()
} else {
setClickedOutside(true)
handler(event)
}
}

const handleCleanup = () => {
document.removeEventListener('click', handleClick)
}

document.addEventListener('click', handleClick)

onCleanup(handleCleanup)

return clickedOutside()
}

0 comments on commit 01c7e8d

Please sign in to comment.