UNPKG

@attio/react-native-bottom-sheet-toolbox

Version:
124 lines (110 loc) 4.29 kB
import {nanoid} from "nanoid" export interface BottomSheetToolboxDevToolsAdapter { // biome-ignore lint/suspicious/noExplicitAny: not useful to type sendMessage(method: string, parameters: any): void // biome-ignore lint/suspicious/noExplicitAny: not useful to type addMessageListener(method: string, listener: (parameters: any) => void): () => void } export type BottomSheetToolboxDevToolsMessageFromRN = | { type: "upsert-sheet" payload: { sheetId: string currentPosition: number wrapperHeight: number | null snapPoints: number[] | null isReady: boolean } } | { type: "delete-sheet" payload: { sheetId: string } } | { type: "update-device-config" payload: { width: number height: number theme: "light" | "dark" } } export type BottomSheetToolboxDevToolsMessageFromDevTools = { type: "did-connect" } class BottomSheetToolboxDevTools { private _adaptersWithListenerRemovers: { adapter: BottomSheetToolboxDevToolsAdapter listenerRemovers: Map<string, () => void> }[] = [] private readonly _messageListeners = new Map< string, // biome-ignore lint/suspicious/noExplicitAny: not useful to type readonly [string, (parameters: any) => void] >() public addAdapter(adapter: BottomSheetToolboxDevToolsAdapter) { const adapterWithListenerRemovers = { adapter, listenerRemovers: new Map(), } this._adaptersWithListenerRemovers.push(adapterWithListenerRemovers) for (const [messageListenerId, listenerArgs] of this._messageListeners.entries()) { const [method, listener] = listenerArgs const removeListener = adapter.addMessageListener(method, listener) adapterWithListenerRemovers.listenerRemovers.set(messageListenerId, removeListener) } return () => { this._adaptersWithListenerRemovers = this._adaptersWithListenerRemovers.filter( (adapterWithListenerRemovers) => adapterWithListenerRemovers.adapter !== adapter ) } } public sendMessage<Method extends BottomSheetToolboxDevToolsMessageFromRN["type"]>( method: Method, parameters: Extract<BottomSheetToolboxDevToolsMessageFromRN, {type: Method}> extends { payload: infer Payload } ? Payload : never ) { // Message sent before an adapter is added are lost. this._adaptersWithListenerRemovers.forEach((adapterWithListenerRemovers) => { adapterWithListenerRemovers.adapter.sendMessage(method, parameters) }) } public addMessageListener<Method extends BottomSheetToolboxDevToolsMessageFromDevTools["type"]>( method: Method, listener: ( parameters: Extract< BottomSheetToolboxDevToolsMessageFromDevTools, {type: Method} > extends {payload: infer Payload} ? Payload : never ) => void ) { const messageListenerId = nanoid() const listenerArgs = [method, listener] as const this._messageListeners.set(messageListenerId, listenerArgs) for (const adapterWithListenerRemovers of this._adaptersWithListenerRemovers) { const removeListener = adapterWithListenerRemovers.adapter.addMessageListener( method, listener ) adapterWithListenerRemovers.listenerRemovers.set(messageListenerId, removeListener) } return () => { this._messageListeners.delete(messageListenerId) for (const adapterWithListenerRemovers of this._adaptersWithListenerRemovers) { const removeListener = adapterWithListenerRemovers.listenerRemovers.get(messageListenerId) removeListener?.() } } } } /** * This is for internal use, so we can log to our separate devtools package. */ export const BOTTOM_SHEET_DEV_TOOLS = new BottomSheetToolboxDevTools()