Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@sanity/ui

Package Overview
Dependencies
Maintainers
55
Versions
434
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sanity/ui - npm Package Compare versions

Comparing version 2.8.0 to 2.8.1

src/core/hooks/useClickOutsideEvent.test.tsx

2

package.json
{
"name": "@sanity/ui",
"version": "2.8.0",
"version": "2.8.1",
"keywords": [

@@ -5,0 +5,0 @@ "sanity",

export * from './useArrayProp'
export * from './useClickOutside'
export * from './useClickOutsideEvent'
export * from './useCustomValidity'

@@ -4,0 +5,0 @@ export * from './useElementRect'

@@ -1,3 +0,2 @@

import {useEffect, useState} from 'react'
import {useEffectEvent} from 'use-effect-event'
import {useEffect, useRef, useState} from 'react'
import {EMPTY_ARRAY} from '../constants'

@@ -15,136 +14,104 @@

/**
* @public
* @deprecated - use your own `const [element, setElement] = useState(null)` logic instead
*/
export type UseClickOutsideSetElement = (el: HTMLElement | null) => void
function _getElements(
element: HTMLElement | null,
elementsArg: ClickOutsideElements,
): HTMLElement[] {
const ret = [element]
for (const el of elementsArg) {
if (Array.isArray(el)) {
ret.push(...el)
} else {
ret.push(el)
}
}
return ret.filter(Boolean) as HTMLElement[]
}
/**
* @public
*/
export function useClickOutside(
listener: ClickOutsideListener | false | undefined,
elementsArg: () => ClickOutsideElements,
boundaryElement?: () => HTMLElement | null,
): void
/**
* @public
* @deprecated - change `useClickOutside(handler, () => [...], boundary)` to `useClickOutside(handler, () => [...], () => boundary)`
*/
export function useClickOutside(
listener: ClickOutsideListener | false | undefined,
elementsArg: () => ClickOutsideElements,
boundaryElement: HTMLElement | null,
): void
/**
* @public
* @deprecated - change `useClickOutside(handler, [...], () => boundary)` to `useClickOutside(handler, () => [...], () => boundary)`
*/
export function useClickOutside(
listener: ClickOutsideListener | false | undefined,
elementsArg: ClickOutsideElements,
boundaryElement: () => HTMLElement | null,
): UseClickOutsideSetElement
/**
* @public
* @deprecated
* Instead of:
* @deprecated replaced by the new `useClickOutsideEvent` hook, instead of:
* ```tsx
* const buttonRef = useRef(null)
* const setElement = useClickOutside(() => {}, [buttonRef.current])
* return (
* <>
* <button ref={buttonRef} />
* {open && <div ref={setElement} />}
* </>
* )
* const [button, setButtonElement] = useState(null)
* useClickOutside((event) => {}, [button])
* return <button ref={setButtonElement} />
* ```
* Use:
* do:
* ```tsx
* const buttonRef = useRef()
* const [element, setElement] = useState(null)
* useClickOutside(() => {}, () => [buttonRef.current, element])
* return (
* <>
* <button ref={buttonRef} />
* {open && <div ref={setElement} />}
* </>
* )
* useClickOutsideEvent((event) => {}, () => [buttonRef.current])
* return <button ref={buttonRef} />
* ```
*/
export function useClickOutside(
listener: ClickOutsideListener | false | undefined,
elementsArg: ClickOutsideElements,
listener: ClickOutsideListener,
elementsArg: ClickOutsideElements = EMPTY_ARRAY,
boundaryElement?: HTMLElement | null,
): UseClickOutsideSetElement
): (el: HTMLElement | null) => void {
const [element, setElement] = useState<HTMLElement | null>(null)
const [elements, setElements] = useState(() => _getElements(element, elementsArg))
const elementsRef = useRef(elements)
/**
* @public
*/
export function useClickOutside(
listener: ClickOutsideListener | false | undefined,
elementsArg: ClickOutsideElements | (() => ClickOutsideElements) = EMPTY_ARRAY,
boundaryElement?: HTMLElement | null | (() => HTMLElement | null),
): UseClickOutsideSetElement | void {
/** @deprecated */
const [legacyElement, setLegacyElement] = useState<HTMLElement | null>(null)
useEffect(() => {
const prevElements = elementsRef.current
const nextElements = _getElements(element, elementsArg)
/**
* The `useEffectEvent` hook allow us to always see the latest value of `listener`, `elementsArg` and `boundaryElement` without needing to
* juggle `useState`, `useRef` and `useState` to make sure the `mousedown` event listener isn't constantly being added and removed.
*/
const onEvent = useEffectEvent((evt: MouseEvent) => {
if (!listener) {
if (prevElements.length !== nextElements.length) {
setElements(nextElements)
elementsRef.current = nextElements
return
}
const target = evt.target
for (const el of prevElements) {
if (!nextElements.includes(el)) {
setElements(nextElements)
elementsRef.current = nextElements
if (!(target instanceof Node)) {
return
return
}
}
const resolvedBoundaryElement =
typeof boundaryElement === 'function' ? boundaryElement() : boundaryElement
for (const el of nextElements) {
if (!prevElements.includes(el)) {
setElements(nextElements)
elementsRef.current = nextElements
if (resolvedBoundaryElement && !resolvedBoundaryElement.contains(target)) {
return
return
}
}
}, [element, elementsArg])
const resolvedElements = Array.isArray(elementsArg)
? [legacyElement, ...elementsArg]
: elementsArg()
const elements = resolvedElements.flat()
useEffect(() => {
if (!listener) return undefined
for (const el of elements) {
if (!el) continue
const handleWindowMouseDown = (evt: MouseEvent) => {
const target = evt.target
if (target === el || el.contains(target)) {
if (!(target instanceof Node)) {
return
}
}
listener(evt)
})
if (boundaryElement && !boundaryElement.contains(target)) {
return
}
const hasListener = Boolean(listener)
for (const el of elements) {
if (target === el || el.contains(target)) {
return
}
}
useEffect(() => {
if (!hasListener) return undefined
listener(evt)
}
const handleEvent = (evt: MouseEvent) => onEvent(evt)
window.addEventListener('mousedown', handleWindowMouseDown)
document.addEventListener('mousedown', handleEvent)
return () => {
document.removeEventListener('mousedown', handleEvent)
window.removeEventListener('mousedown', handleWindowMouseDown)
}
}, [hasListener, onEvent])
}, [boundaryElement, listener, elements])
/**
* Only return the legacy setElement function if the elementsArg is an array
*/
if (Array.isArray(elementsArg)) {
return setLegacyElement as UseClickOutsideSetElement
}
return setElement
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc