@spaced-out/ui-design-system
Version:
Sense UI components library
71 lines • 3.55 kB
TypeScript
import * as React from 'react';
type BoundaryRefType<T extends HTMLElement> = React.RefObject<T | null>;
type TriggerRefType<T extends HTMLElement> = React.RefObject<T | null>;
export interface ChildProps<TTrigger extends HTMLElement = HTMLButtonElement, TBoundary extends HTMLElement = HTMLDivElement> {
onOpen: () => void;
isOpen: boolean;
height: number | null | undefined;
pageBottom: number | null | undefined;
clickAway: () => void;
boundaryRef: BoundaryRefType<TBoundary>;
triggerRef: TriggerRefType<TTrigger>;
}
export interface ClickAwayRefType {
forceClose: () => void;
forceOpen: () => void;
}
export interface ClickAwayProps<TTrigger extends HTMLElement = HTMLButtonElement, TBoundary extends HTMLElement = HTMLDivElement> {
closeOnEscapeKeypress?: boolean;
children: (props: ChildProps<TTrigger, TBoundary>) => React.ReactNode;
onChange?: (isOpen: boolean) => unknown;
clickAwayRef?: React.RefObject<ClickAwayRefType | null>;
/**
* When containsNestedFloatingPortals is true, prevents ClickAway from closing the dropdown if the click target
* is inside a floating portal root element.
*
* This is necessary for nested dropdowns rendered using floating portals,
* such as via `@floating-ui/react`. Floating portals render elements outside
* the normal DOM tree (often directly into `document.body` or another container)
* using `ReactDOM.createPortal`. As a result, these nested dropdowns do not
* appear inside the parent dropdown's `boundaryRef` or `triggerRef` subtree.
*
* To address this, the floating portal ensures that all nested dropdowns
* are mounted into a **shared root element** — effectively maintaining a
* common DOM ancestry. This allows parent dropdowns to detect when clicks
* occur within any of their nested children, even if rendered via portals.
* The shared root element is the closest parent element that has a `data-floating-ui-portal` attribute.
* Because of this, the ClickAway logic will not close the parent menu if the click target is inside boundaryRef's parentElement.
*
* Enabling `containsNestedFloatingPortals` allows the ClickAway logic to account
* for this shared root and avoids incorrectly closing the parent menu when
* interacting with nested dropdowns.
*/
containsNestedFloatingPortals?: boolean;
}
interface ClickAwayState {
isOpen: boolean;
height: number | null | undefined;
pageBottom: number | null | undefined;
}
export declare class ClickAway<TTrigger extends HTMLElement = HTMLButtonElement, TBoundary extends HTMLElement = HTMLDivElement> extends React.Component<ClickAwayProps<TTrigger, TBoundary>, ClickAwayState> {
static defaultProps: {
containsNestedFloatingPortals?: boolean;
closeOnEscapeKeypress?: boolean;
};
state: ClickAwayState;
el: HTMLElement | null | undefined;
boundaryRef: BoundaryRefType<TBoundary>;
triggerRef: TriggerRefType<TTrigger>;
componentDidMount(): void;
componentDidUpdate(_prevProps: Readonly<ClickAwayProps<TTrigger, TBoundary>>, prevState: Readonly<ClickAwayState>): void;
componentWillUnmount(): void;
render(): React.ReactNode;
handleOpenClick: () => void;
handleCloseClick: (evt: MouseEvent) => void;
handleCloseOnEscapeKeypress: (evt?: KeyboardEvent) => void;
forceClose: () => void;
handleOnChange: () => unknown;
pageBottom(): number;
}
export {};
//# sourceMappingURL=click-away.d.ts.map