UNPKG

@rx-angular/state

Version:

@rx-angular/state is a light-weight, flexible, strongly typed and tested tool dedicated to reduce the complexity of managing component state and side effects in angular

1 lines 15.4 kB
{"version":3,"file":"rx-angular-state-actions.mjs","sources":["../../../../libs/state/actions/src/lib/proxy.ts","../../../../libs/state/actions/src/lib/actions.factory.ts","../../../../libs/state/actions/src/lib/rx-actions.ts","../../../../libs/state/actions/src/lib/transforms.ts","../../../../libs/state/actions/src/rx-angular-state-actions.ts"],"sourcesContent":["import { ErrorHandler } from '@angular/core';\nimport { merge, OperatorFunction, Subject } from 'rxjs';\nimport { EffectMap, KeysOf, RxActions, SubjectMap, ValuesOf } from './types';\n\n/**\n * @internal\n * Internal helper to create the proxy object\n * It lives as standalone function because we don't need to carrie it in memory for every ActionHandler instance\n * @param subjects\n * @param transforms\n */\nexport function actionProxyHandler<T extends object, U extends object>({\n subjectMap,\n transformsMap,\n effectMap,\n errorHandler = null,\n}: {\n subjectMap: SubjectMap<T>;\n transformsMap?: U;\n effectMap: EffectMap<T>;\n errorHandler: ErrorHandler | null;\n}): ProxyHandler<RxActions<T, U>> {\n type KeysOfT = KeysOf<T>;\n type ValuesOfT = ValuesOf<T>;\n\n function getEventEmitter(prop: KeysOfT): Subject<ValuesOfT> {\n if (!subjectMap[prop]) {\n subjectMap[prop] = new Subject<ValuesOfT>();\n }\n return subjectMap[prop];\n }\n function dispatch(value: ValuesOfT, prop: KeysOfT) {\n subjectMap[prop] = subjectMap[prop] || new Subject<ValuesOfT>();\n try {\n const val =\n transformsMap && (transformsMap as any)[prop]\n ? (transformsMap as any)[prop](value)\n : value;\n subjectMap[prop].next(val);\n } catch (err) {\n errorHandler?.handleError(err);\n }\n }\n return {\n // shorthand setter for multiple EventEmitter e.g. actions({propA: 1, propB: 2})\n apply(_: RxActions<T, U>, __: any, props: [T]): any {\n props.forEach((slice) =>\n Object.entries(slice).forEach(([k, v]) =>\n dispatch(v as any, k as any as KeysOfT)\n )\n );\n },\n get(_, property: string) {\n const prop = property as KeysOfT;\n\n // the user wants to get multiple or one single EventEmitter as observable `eventEmitter.prop$`\n if (prop.toString().split('').pop() === '$') {\n // the user wants to get multiple EventEmitter as observable `eventEmitter.$(['prop1', 'prop2'])`\n if (prop.toString().length === 1) {\n return (props: KeysOfT[]) =>\n merge(\n ...props.map((k) => {\n return getEventEmitter(k);\n })\n );\n }\n // the user wants to get a single EventEmitter as observable `eventEmitter.prop$`\n const propName = prop.toString().slice(0, -1) as KeysOfT;\n return getEventEmitter(propName);\n }\n\n // the user wants to get a single EventEmitter and trigger a side effect on event emission\n if (prop.toString().startsWith('on')) {\n // we need to first remove the 'on' from the the prop name\n const slicedPropName = prop.toString().slice(2);\n // now convert the slicedPropName to camelcase\n const propName = (slicedPropName.charAt(0).toLowerCase() +\n slicedPropName.slice(1)) as KeysOfT;\n return (\n behaviour: OperatorFunction<T[KeysOfT], T[KeysOfT]>,\n sf: (v: T[KeysOfT]) => void\n ) => {\n const sub = getEventEmitter(propName).pipe(behaviour).subscribe(sf);\n effectMap[propName] = sub;\n return () => sub.unsubscribe();\n };\n }\n\n // the user wants to get a dispatcher function to imperatively dispatch the EventEmitter\n return (args: ValuesOfT) => {\n dispatch(args, prop);\n };\n },\n set() {\n throw new Error('No setters available. To emit call the property name.');\n },\n };\n}\n","import {\n DestroyRef,\n ErrorHandler,\n inject,\n Injectable,\n Optional,\n} from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { actionProxyHandler } from './proxy';\nimport { Actions, ActionTransforms, EffectMap, RxActions } from './types';\n\ntype SubjectMap<T> = { [K in keyof T]: Subject<T[K]> };\n\n/**\n * @deprecated - use rxActions instead\n *\n * This class creates RxActions bound to Angular's DI life-cycles. This prevents memory leaks and optionally makes the instance reusable across the app.\n * The function has to be used inside an injection context.\n * If the consumer gets destroyed also the actions get destroyed automatically.\n *\n * @example\n * @Component({\n * standalone: true,\n * template: `...`,\n * })\n * export class AnyComponent {\n * ui = rxActions<{search: string, refresh: void}>();\n * }\n */\n@Injectable()\nexport class RxActionFactory<T extends Partial<Actions>> {\n private readonly subjects: SubjectMap<T>[] = [] as SubjectMap<T>[];\n\n constructor(@Optional() private readonly errorHandler?: ErrorHandler) {\n inject(DestroyRef).onDestroy(() => this.destroy());\n }\n\n /*\n * Returns a object based off of the provided typing with a separate setter `[prop](value: T[K]): void` and observable stream `[prop]$: Observable<T[K]>`;\n *\n * { search: string } => { search$: Observable<string>, search: (value: string) => void;}\n *\n * @example\n *\n * interface UIActions {\n * search: string,\n * submit: void\n * };\n *\n * const actions = new RxActionFactory<UIActions>().create();\n *\n * actions.search($event.target.value);\n * actions.search$.subscribe();\n *\n * As it is well typed the following things would not work:\n * actions.submit('not void'); // not void\n * actions.search(); // requires an argument\n * actions.search(42); // not a string\n * actions.search$.error(new Error('traraaa')); // not possible by typings as well as in code\n * actions.search = \"string\"; // not a setter. the proxy will throw an error pointing out that you have to call it\n *\n * @param transforms - A map of transform functions to apply on transformations to actions before emitting them.\n * This is very useful to clean up bloated templates and components. e.g. `[input]=\"$event?.target?.value\"` => `[input]=\"$event\"`\n *\n * @example\n * function coerceSearchActionParams(e: Event | string | number): string {\n * if(e?.target?.value !== undefined) {\n * return e?.target?.value + ''\n * }\n * return e + '';\n * }\n * const actions = getActions<search: string, submit: void>({search: coerceSearchActionParams, submit: (v: any) => void 0;});\n *\n * actions.search($event);\n * actions.search('string');\n * actions.search(42);\n * actions.submit('not void'); // does not error anymore\n * actions.search$.subscribe(); // string Observable\n *\n */\n create<U extends ActionTransforms<T> = object>(\n transforms?: U,\n ): RxActions<T, U> {\n const subjectMap: SubjectMap<T> = {} as SubjectMap<T>;\n const effectMap: EffectMap<T> = {} as EffectMap<T>;\n this.subjects.push(subjectMap);\n\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n function signals(): void {}\n\n return new Proxy(\n signals as any as RxActions<T, U>,\n actionProxyHandler({\n subjectMap,\n effectMap,\n transformsMap: transforms,\n errorHandler: this.errorHandler ?? null,\n }),\n ) as any as RxActions<T, U>;\n }\n\n destroy() {\n this.subjects.forEach((s) => {\n Object.values(s).forEach((subject: any) => subject.complete());\n });\n }\n}\n","import {\n assertInInjectionContext,\n DestroyRef,\n ErrorHandler,\n inject,\n} from '@angular/core';\nimport { actionProxyHandler } from './proxy';\nimport {\n Actions,\n ActionTransforms,\n EffectMap,\n RxActions,\n SubjectMap,\n} from './types';\n\n/**\n * Manage events in components and services in a single place\n *\n * @example\n *\n * interface UI {\n * search: string,\n * submit: void\n * };\n *\n * import { rxActions } from '@rx-angular/state/actions';\n *\n * @Component({...})\n * export class Component {\n * ui = rxActions<{ name: string }>(({transforms}) => transforms({name: v => v}));\n *\n * name$ = this.ui.name$; // Observable<string> - listens to name changes\n * emitName = this.ui.name; // (name: string) => void - emits name change\n * sub = this.ui.onName(o$ => o$.pipe(), console.log) // () => void - stops side effect\n *\n * onInit() {\n * const name$ = this.ui.name$; // Observable<string> - listens to name changes\n * const emitName = this.ui.name; // (name: string) => void - emits name change\n * const stop = this.ui.onName(o$ => o$.pipe(), console.log) // () => void - stops side effect\n * stop();\n * }\n *\n * }\n *\n */\nexport function rxActions<\n T extends Partial<Actions>,\n U extends ActionTransforms<T> = object,\n>(setupFn?: (cfg: { transforms: (t: U) => void }) => void): RxActions<T, U> {\n // Assert rxAction usage\n assertInInjectionContext(rxActions);\n\n const subjectMap: SubjectMap<T> = {} as SubjectMap<T>;\n const effectMap: EffectMap<T> = {} as EffectMap<T>;\n const errorHandler = inject(ErrorHandler);\n let transformsMap = {} as U;\n\n /**\n * @internal\n * Internally used to clean up potential subscriptions to the subjects. (For Actions it is most probably a rare case but still important to care about)\n */\n inject(DestroyRef).onDestroy(() => {\n Object.values(subjectMap).forEach((subject: any) => subject.complete());\n });\n\n // run setup function if given\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n setupFn &&\n setupFn({\n transforms: (t: U) => (transformsMap = t),\n });\n\n // create actions\n function signals(): void {}\n return new Proxy(\n signals as any as RxActions<T, U>,\n actionProxyHandler({\n subjectMap,\n transformsMap,\n effectMap,\n errorHandler,\n }),\n ) as any as RxActions<T, U>;\n}\n","/**\n * @description\n * This transform is a side effecting operation applying `preventDefault` to a passed Event\n * @param e\n */\nexport function preventDefault(e: Event): Event {\n e.preventDefault();\n return e;\n}\n\n/**\n * @description\n * This transform is a side effecting operation applying `stopPropagation` to a passed Event\n * @param e\n */\nexport function stopPropagation(e: Event): Event {\n e.stopPropagation();\n return e;\n}\n\n/**\n * @description\n * This transform is a side effecting operation applying `preventDefault` and `stopPropagation` to a passed Event\n * @param e\n */\nexport function preventDefaultStopPropagation(e: Event): Event {\n e.stopPropagation();\n e.preventDefault();\n return e;\n}\n\n\n/**\n * @description\n * This transform is helps to pluck values from DOM `Event` or forward the value directly.\n * @param e\n */\nexport function eventValue<T = string>(e: Event | T): T {\n // Consider https://stackoverflow.com/questions/1458894/how-to-determine-if-javascript-object-is-an-event\n if((e as unknown as {target: {value: T}})?.target) {\n return (e as unknown as {target: {value: T}})?.target?.value;\n }\n return e as T;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}