import { ReactNode, FC, Ref, ForwardRefRenderFunction, ForwardRefExoticComponent, RefAttributes } from 'react'; import { Equality, SelectorContext } from '../types'; export interface WithStoreOptions { displayName?: string; /** * Custom equality function for comparing hook output. * Controls when the memoized render function re-renders. * * Note: To control input props equality, wrap the final component with memo(). */ equality?: Equality; } /** * Hook function that receives SelectorContext and props. * * Can use: * - Store access via ctx.get() * - React hooks (useState, useEffect, useMemo, etc.) * - Return any values including functions * * The hook is called during render phase, so all React hooks rules apply. * * ⚠️ Limitation: Cannot use React hooks inside pick() callbacks: * ```tsx * // ❌ DON'T: React hooks inside pick callback * const value = ctx.pick(store, state => { * const [x] = useState(0); // ❌ Error: Invalid hook call * return state.value + x; * }); * * // ✅ DO: React hooks outside pick * const [x] = useState(0); * const value = ctx.pick(store, state => state.value + x); * ``` * * @example * ```tsx * const Component = withStore( * (ctx, { userId }) => { * const [user] = ctx.get(userStore); * const [count, setCount] = useState(0); * * return { * userName: user.name, * count, * increment: () => setCount(c => c + 1), // ✅ Can return functions * }; * }, * ({ userName, count, increment }) => ( *
{userName}: {count}
* ) * ); * ``` */ export type WithStoreHook = (context: SelectorContext, props: TInput) => TOutput; /** * Render function without ref support. */ export type WithStoreRender = (props: TOutput) => ReactNode; /** * Render function with ref support. */ export type WithStoreRenderWithRef = (props: TOutput, ref: Ref) => ReactNode; /** * Testing utilities exposed on components created with withStore(hook, render) */ export interface WithStoreTestUtils { /** * The hook function for testing. * Call this to test the hook logic independently. * * @example * ```ts * const result = MyComponent.use(mockCtx, { userId: '123' }); * expect(result.name).toBe('John'); * ``` */ use: (context: TContext, props: TInput) => TOutput; /** * The render function for testing. * Call this to test the render output independently. * * @example * ```tsx * const element = MyComponent.render({ name: 'John' }); * // Or with testing-library: * render(MyComponent.render({ name: 'John' })); * ``` */ render: (props: TOutput) => ReactNode; } /** * Testing utilities exposed on HOCs created with withStore(hook) */ export interface WithStoreHOCTestUtils { /** * The hook function for testing. * Call this to test the hook logic independently. * * @example * ```ts * const result = withUserData.use(mockCtx, { userId: '123' }); * expect(result.name).toBe('John'); * ``` */ use: (context: TContext, props: TInput) => TOutput; } /** * Component type with testing utilities (no ref) */ export type WithStoreComponent = FC & WithStoreTestUtils; /** * Component type with testing utilities (with ref) */ export type WithStoreComponentWithRef = ForwardRefExoticComponent> & WithStoreTestUtils; /** * HOC type with testing utilities */ export type WithStoreHOC = { (component: FC): FC; (component: ForwardRefRenderFunction): ForwardRefExoticComponent>; } & WithStoreHOCTestUtils; /** * Generic hook type for createWithStore */ export type GenericWithStoreHook = (context: TContext, props: TInput) => TOutput; /** * WithStore function type bound to a specific context type. */ export interface BoundWithStore { /** * Direct mode: Create component with hook and render function (no ref). */ (hook: GenericWithStoreHook, render: WithStoreRender, options?: WithStoreOptions): WithStoreComponent; /** * Direct mode: Create component with hook and render function (with ref). */ (hook: GenericWithStoreHook, render: WithStoreRenderWithRef, options?: WithStoreOptions): WithStoreComponentWithRef; /** * HOC mode: Create HOC that transforms props using hook. */ (hook: GenericWithStoreHook, options?: WithStoreOptions): WithStoreHOC; } /** * A reactive hook that accepts a selector and returns the selected value. * Similar to useStore's signature. */ export type UseContextHook = (selector: (ctx: TContext) => T) => T; /** * Create a withStore function bound to a custom reactive hook. * * This is the core building block for creating withStore-like patterns with custom contexts. * Useful for single-store apps or custom store patterns. * * @example * ```tsx * // For single-store apps with create() * const [counter, useCounter] = create({ * state: { count: 0 }, * setup({ state }) { * return { increment: () => state.count++ }; * } * }); * * // Create withStore bound to this store's hook * const withCounter = createWithStore(useCounter); * * // Direct mode - hook receives (state, actions) instead of SelectorContext * const Display = withCounter( * (state, actions, props: { multiplier: number }) => ({ * count: state.count * props.multiplier, * increment: actions.increment, * }), * ({ count, increment }) => * ); * * // HOC mode * const withData = withCounter((state) => ({ * value: state.count, * })); * const ValueDisplay = withData(({ value }) =>
{value}
); * ``` * * @param useContextHook - A reactive hook that accepts a selector (like useStore or useCreatedStore) * @returns A withStore function bound to the custom context */ export declare function createWithStore(useContextHook: UseContextHook): BoundWithStore; /** * Direct mode: Create component with hook and render function (no ref). * Returns component with `use` and `render` properties for testing. */ export declare function withStore(hook: WithStoreHook, render: WithStoreRender, options?: WithStoreOptions): WithStoreComponent; /** * Direct mode: Create component with hook and render function (with ref). * Automatically detected when render function has 2 parameters. * Returns component with `use` and `render` properties for testing. */ export declare function withStore(hook: WithStoreHook, render: WithStoreRenderWithRef, options?: WithStoreOptions): WithStoreComponentWithRef; /** * HOC mode: Create HOC that transforms props using hook. * Returns a function that accepts a component, with `use` property for testing. */ export declare function withStore(hook: WithStoreHook, options?: WithStoreOptions): WithStoreHOC; //# sourceMappingURL=withStore.d.ts.map