import { Subscribable } from 'rxjs'; import { LimeWebComponentContext } from './context'; /** * Base interface for repositories that provide reactive state subscriptions. * * StateRepository is the foundation for all reactive data sources in the platform. * Repositories like {@link ConfigRepository}, {@link LimeObjectRepository}, * {@link FilterRepository}, etc. extend this interface to provide * subscription-based access to their data. * * The subscription pattern allows components to react to data changes automatically, * ensuring UI stays synchronized with the underlying application state. * * @example RECOMMENDED: Use state decorators for automatic reactive properties * ```ts * import { State } from '@stencil/core'; * import { * SelectCurrentLimeObject, * SelectCurrentUser, * } from '@limetech/lime-web-components'; * * class MyComponent { * @State() * @SelectCurrentUser({ * map: [(user) => user?.fullname], * filter: [(name) => name !== undefined], * }) * private userName: string; * * @State() * @SelectCurrentLimeObject({ * map: [(limeObject) => limeObject?.getValue('name')], * }) * private objectName: string; * } * ``` * * @example ALTERNATIVE: Manual subscription for custom logic * ```ts * import { PlatformServiceName } from '@limetech/lime-web-components'; * * const repository = platform.get(PlatformServiceName.Application); * const logger = platform * .get(PlatformServiceName.Logger) * .createLogger('my-component'); * * const unsubscribe = repository.subscribe( * (state) => { * logger.debug('State updated', { state }); * }, * { * map: [ * (state) => ({ user: state.currentUser, language: state.language }), * ], * filter: [(state) => state.currentUser !== null], * } * ); * * // Remember to unsubscribe when the component is destroyed * unsubscribe(); * ``` * * @public * @group Core */ export interface StateRepository { /** * Subscribe to state changes with optional transformation and filtering. * * The subscription will immediately invoke the callback with the current state * (if any), then continue to call it whenever the state changes. The map and * filter options allow you to transform and selectively receive updates. * * @param callback - Function called with state updates (after map/filter applied) * @param options - Optional transformations and filters for the subscription * @returns Unsubscribe function - call this to stop receiving updates * * @remarks * - Map functions are applied sequentially to transform the state * - Filter functions must all return true for the callback to be invoked * - Functions in map/filter arrays are bound to the component instance * - Always store and call the unsubscribe function when component is destroyed * * @example * ```ts * import { PlatformServiceName } from '@limetech/lime-web-components'; * * const repository = platform.get(PlatformServiceName.Application); * const logger = platform * .get(PlatformServiceName.Logger) * .createLogger('my-component'); * * // Basic subscription * const unsubscribeState = repository.subscribe((state) => { * logger.debug('State updated', { state }); * }); * * // With transformations * const unsubscribeFullname = repository.subscribe( * (fullname) => logger.debug('User', { fullname }), * { map: [(state) => state.currentUser?.fullname] } * ); * ``` */ subscribe(callback: (...args: unknown[]) => void, options?: StateOptions): () => void; } /** * Configuration options for state subscriptions. * * These options allow you to transform and filter state updates before they * reach your callback. Map functions transform the data, while filter functions * determine whether the callback should be invoked at all. * * @example * ```ts * import { LimeObject, StateOptions } from '@limetech/lime-web-components'; * * const options: StateOptions = { * // Extract and transform specific parts of the state * map: [ * (state) => state.objects, * (objects: LimeObject[]) => * objects.map((object) => ({ * id: object.id, * name: object.getValue('name'), * })), * ], * // Only notify when the conditions are met * filter: [ * (objects) => objects.length > 0, * (objects) => * objects.some((item: { name: string }) => item.name === 'Admin'), * ], * }; * ``` * * @public * @group Core */ export interface StateOptions { /** * List of transformation functions applied sequentially to the state. * * Each function receives the output of the previous function (or the raw state * for the first function). Use this to extract, transform, or compute derived * values from the state. Functions are bound to the web component instance. * * @example * ```ts * import { StateOptions } from '@limetech/lime-web-components'; * * type Order = { pending: boolean }; * * // The callback receives the output of the last function, so here: the count of * // pending orders. * const options: StateOptions = { * map: [ * (state) => state.orders, // Extract orders * (orders: Order[]) => orders.filter((order) => order.pending), // Pending only * (pending: Order[]) => pending.length, // Get count * ], * }; * ``` */ map?: Array<(state: any) => any>; /** * List of predicate functions that must all return true for updates to be emitted. * * Filters are evaluated after map transformations. If any filter returns false, * the callback is not invoked for that state change. Useful for preventing * unnecessary updates. Functions are bound to the web component instance. * * @example * ```ts * import { StateOptions } from '@limetech/lime-web-components'; * * const options: StateOptions = { * filter: [ * (state) => state !== null, // Ignore null states * (state) => state.isReady, // Only when ready * (state) => state.items.length > 0, // Only when it has items * ], * }; * ``` */ filter?: Array<(state: any) => boolean>; } /** * Extended state options for repositories that are context-aware. * * Some repositories (like CurrentLimetype and CurrentLimeobject) can automatically * react to context changes. When the context observable emits a new value, these * repositories will re-evaluate and emit their state for the new context. * * @public * @group Core */ export interface ContextAwareStateOptions extends StateOptions { /** * Observable that emits new context values to trigger state re-evaluation. * * When provided, the repository will subscribe to this observable and re-fetch * or re-evaluate its state whenever a new context is emitted. This is particularly * useful for components that need to react to navigation or context switches. * * Only applies to context-aware state services like: * - `CurrentLimetype` - Updates when limetype in context changes * - `CurrentLimeobject` - Re-fetches object when context ID changes */ context?: Subscribable | null; }