import { useWidgetStore } from './widget-store' import type { WidgetState } from './types' import { useShallow } from 'zustand/shallow' /** * Scoped selector hook for reading a single widget's state from the store. * * Consolidates multiple `useWidgetStore(useShallow(...))` calls into a single * subscription per component. The selector receives only this widget's state * (or undefined if not yet registered), and uses shallow comparison to avoid * re-renders when unrelated properties change. * * @param widgetId - The widget ID to subscribe to. * @param selector - A function that extracts the needed properties from the widget state. * Must be a stable reference (inline arrow is fine due to useCallback wrapping). * * @example * ```tsx * // Before: 4 separate subscriptions * const title = useWidgetStore(useShallow((s) => s.getWidget(id)?.title)) * const collapsed = useWidgetStore(useShallow((s) => s.getWidget(id)?.collapsed)) * const disabled = useWidgetStore(useShallow((s) => s.getWidget(id)?.disabled)) * const isFetching = useWidgetStore(useShallow((s) => s.getWidget(id)?.isFetching)) * * // After: 1 subscription * const { title, collapsed, disabled, isFetching } = useWidgetSelector(id, (w) => ({ * title: w?.title, collapsed: w?.collapsed, disabled: w?.disabled, isFetching: w?.isFetching, * })) * * // With extra dependencies (e.g., index prop): * const value = useWidgetSelector( * id, * (w) => (w as MyState | undefined)?.data?.[index]?.value, * [index], * ) * ``` */ export function useWidgetSelector( widgetId: string, selector: (widget: WidgetState | undefined) => T, ): T { return useWidgetStore( useShallow((state: { widgets: Record }) => selector(state.widgets[widgetId]), ), ) }