Skip to content

Commit 01c7e8d

Browse files
committed
feat: add useClickOutside hooks, hidden dropmenu when clickOutside
1 parent a699aac commit 01c7e8d

File tree

4 files changed

+40
-5
lines changed

4 files changed

+40
-5
lines changed

src/components/main/MessageItem.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { For, Show } from 'solid-js/web'
2-
import { createSignal } from 'solid-js'
2+
import { createSignal, onCleanup } from 'solid-js'
33
import { useStore } from '@nanostores/solid'
44
import { useClipboardCopy } from '@/hooks'
55
import { deleteMessageByConversationId, spliceMessageByConversationId, spliceUpdateMessageByConversationId } from '@/stores/messages'
@@ -20,12 +20,12 @@ interface Props {
2020
}
2121

2222
export default (props: Props) => {
23+
let inputRef: HTMLTextAreaElement
2324
const $conversationMap = useStore(conversationMap)
2425

2526
const [showRawCode, setShowRawCode] = createSignal(false)
2627
const [copied, setCopied] = createSignal(false)
2728
const [isEditing, setIsEditing] = createSignal(false)
28-
let inputRef: HTMLTextAreaElement
2929
const [inputPrompt, setInputPrompt] = createSignal(props.message.content)
3030

3131
const currentConversation = () => {
@@ -38,6 +38,7 @@ export default (props: Props) => {
3838
setCopied(Iscopied())
3939
setTimeout(() => setCopied(false), 1000)
4040
}
41+
4142
const handleDeleteMessageItem = () => {
4243
deleteMessageByConversationId(props.conversationId, props.message)
4344
}

src/components/ui/base/DropdownMenu.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import * as menu from '@zag-js/menu'
22
import { normalizeProps, useMachine } from '@zag-js/solid'
33
import { Show, children, createEffect, createMemo, createUniqueId } from 'solid-js'
44
import { Dynamic, For, Portal, spread } from 'solid-js/web'
5-
import type { JSX, JSXElement } from 'solid-js'
5+
import { useClickOutside } from '@/hooks'
6+
import type { Accessor, JSX, JSXElement } from 'solid-js'
67

78
export interface MenuItem {
89
id: string
@@ -16,6 +17,7 @@ export interface MenuItem {
1617
interface Props {
1718
children: JSX.Element
1819
menuList: MenuItem[]
20+
close?: () => Accessor<boolean>
1921
}
2022

2123
export const DropDownMenu = (props: Props) => {
@@ -31,6 +33,7 @@ export const DropDownMenu = (props: Props) => {
3133
},
3234
}),
3335
)
36+
let dropDownMenuRef: HTMLDivElement
3437

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

@@ -45,15 +48,20 @@ export const DropDownMenu = (props: Props) => {
4548
createEffect(() => {
4649
// https://github.com/chakra-ui/zag/issues/595
4750
api().setPositioning({})
51+
52+
dropDownMenuRef = document.getElementById('DropDownMenuRef') as HTMLDivElement
53+
useClickOutside(dropDownMenuRef, () => {
54+
api().close()
55+
})
4856
})
4957

5058
return (
51-
<div class="!outline-none">
59+
<div id="DropDownMenuRef" class="!outline-none" >
5260
<Dynamic component={resolvedChild} />
5361
<Show when={api().isOpen}>
5462
<Portal>
5563
<div {...api().positionerProps} z-20>
56-
<div {...api().contentProps} class=" bg-white dark-bg-zinc-900 flex flex-col space-y-1 rounded-md shadow-md">
64+
<div {...api().contentProps} class="bg-white dark-bg-zinc-900 flex flex-col space-y-1 rounded-md shadow-md ">
5765
<Show when={api().isOpen}>
5866
<For each={props.menuList}>
5967
{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>)}

src/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './useDark'
22
export * from './useCopy'
3+
export * from './useClickOutside'

src/hooks/useClickOutside.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { createSignal, onCleanup } from 'solid-js'
2+
3+
export const useClickOutside = (ref: HTMLElement, handler: (e: MouseEvent) => any) => {
4+
const [clickedOutside, setClickedOutside] = createSignal(false)
5+
6+
const handleClick = (event: MouseEvent) => {
7+
if (ref && (ref.contains(event.target as Node) || event.composedPath().includes(ref))) {
8+
setClickedOutside(false)
9+
return clickedOutside()
10+
} else {
11+
setClickedOutside(true)
12+
handler(event)
13+
}
14+
}
15+
16+
const handleCleanup = () => {
17+
document.removeEventListener('click', handleClick)
18+
}
19+
20+
document.addEventListener('click', handleClick)
21+
22+
onCleanup(handleCleanup)
23+
24+
return clickedOutside()
25+
}

0 commit comments

Comments
 (0)