{"_id":"@canvasgfx/stateful","_rev":"2-d9ce7709edeab2ddfae83d8cc39671de","name":"@canvasgfx/stateful","dist-tags":{"latest":"1.0.4"},"versions":{"1.0.3":{"name":"@canvasgfx/stateful","version":"1.0.3","description":"A minimal state management store for RxJS.","author":{"name":"reactgular.com"},"homepage":"https://github.com/canvasgfx/stateful.git","license":"MIT","main":"lib/index.js","types":"lib/index.d.ts","repository":{"type":"git","url":"git+https://github.com/canvasgfx/stateful.git"},"bugs":{"url":"https://github.com/canvasgfx/stateful/issues"},"keywords":["javascript","typescript","rxjs","state","redux","store","library"],"scripts":{"test":"jest","coveralls":"jest --coverage && cat ./coverage/lcov.info | coveralls","build":"rm -fr ./lib && tsc","lint":"tslint -p tsconfig.json","prepublishOnly":"npm test && npm run lint","preversion":"npm run lint"},"peerDependencies":{"rxjs":"^6.0.0"},"devDependencies":{"@types/jest":"^24.0.18","coveralls":"^3.0.6","jest":"^24.9.0","rxjs":"~6.4.0","ts-jest":"^24.0.2","tslint":"^5.19.0","typescript":"~3.6.2"},"gitHead":"f6964c6c3e92a598217e074d59ba4b2e11b411f4","_id":"@canvasgfx/stateful@1.0.3","_nodeVersion":"16.13.0","_npmVersion":"9.4.0","dist":{"integrity":"sha512-z8GLUygS6HhsW0elepj9U+HUMNNRSLQDUhG66c+cuPY9flXbd3480hVtP6lkj+lMZ8fk9nAmvOqdqEM2/Td6yA==","shasum":"6b7978615ecb33449f2f90fba9c922e4bb18dd4f","tarball":"https://registry.npmjs.org/@canvasgfx/stateful/-/stateful-1.0.3.tgz","fileCount":3,"unpackedSize":9179,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFat2xmME0nUbd5jzxyYefCQAbraXdJhKYQQFKy1WaTKAiAgyqfx3FPlrS22auUvSGds2qlAtySkWU3SLaNfGEnOWg=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj2qGrACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp8+BAAjqkZpKIXSiVPev56diD2WCVV+SxZUwOMs20RBsgz5Z+F5b6m\r\nz+a+AJkAK4fNsmjO2+7jD/Dst7UwI/z8QsihQcQhBPQIg2tntOBFZZljUYbI\r\nfI5lSIkfteo8uG71JVRapZXqX1PZ7RiFCMQmmno09c94sP/M7lmrhRidCx9W\r\n/S05Xnr8qq7/Qnz85p1i5+f7mKLe1r4wX1XhELcYMjUbsRsIX65iaMFizk9y\r\nSvECdA9yp6iVEUmRbzyxUy/AsPQm61BulRIsLhgrM+Cl7E3iqC4AT2MCeBfn\r\nmyEpeQY247wKnpwc3VaFrBnH/yZmONJO/59gsFkKHVwkVLSEc3oagtwIFXN0\r\nIUc3Pdp7aNvXmJkEGAA323CozcczJmjKbkiuT7aPTZshugZ6Lum154CDIqBA\r\nZywBTf2V3lMR32G0+PWTjRVDUk0nxCfUklVUrdIA47m/nO02zzPCb8beeIaY\r\noP7O9tV8vBC5/Brt0jKzdAKX57t2e+lcybWVKOB8PtnJaV4IwnP5AJtbhnDZ\r\nEiG3AVwsA0MBwlcLpHmW0KZy4FH9hvxsrWVasS9Sm1DbWX9nEDp0fIFWA/Jw\r\n8weqfw4cotanFwmuUwsmRrraPfbUrEtDBM1N9Das6pstR6jTqRmf8ZuA+gkv\r\nK9JlWIiYhPqaBn4PHGukEj3rYc5VtMFDfMA=\r\n=0jxY\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"jbrousseau","email":"jeanbaptiste.rousseau@gmail.com"},"directories":{},"maintainers":[{"name":"jbrousseau","email":"jeanbaptiste.rousseau@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/stateful_1.0.3_1675272619510_0.14456688189236022"},"_hasShrinkwrap":false},"1.0.4":{"name":"@canvasgfx/stateful","version":"1.0.4","description":"A minimal state management store for RxJS.","author":{"name":"reactgular.com"},"homepage":"https://github.com/canvasgfx/stateful.git","license":"MIT","main":"lib/index.js","types":"lib/index.d.ts","repository":{"type":"git","url":"git+https://github.com/canvasgfx/stateful.git"},"bugs":{"url":"https://github.com/canvasgfx/stateful/issues"},"keywords":["javascript","typescript","rxjs","state","redux","store","library"],"scripts":{"test":"jest","coveralls":"jest --coverage && cat ./coverage/lcov.info | coveralls","build":"rm -fr ./lib && tsc","lint":"tslint -p tsconfig.json","prepublishOnly":"npm test && npm run lint","preversion":"npm run lint"},"peerDependencies":{"rxjs":"^6.0.0"},"devDependencies":{"@types/jest":"^24.0.18","coveralls":"^3.0.6","jest":"^24.9.0","rxjs":"~6.4.0","ts-jest":"^24.0.2","tslint":"^5.19.0","typescript":"~3.6.2"},"gitHead":"908995bd8180682f6a2468ad64c9672623faaeb6","_id":"@canvasgfx/stateful@1.0.4","_nodeVersion":"16.13.0","_npmVersion":"9.4.0","dist":{"integrity":"sha512-VRK8AC3txN1/322NsKvT9wF2rwQBf1olCtPlYmtd+55zWRQGZOCTw/OftlfhkQwKxuPrv6akeP7DvUKVpMrwcw==","shasum":"a1e5fa66c56fdc5124c006556641e2f9b3aa7d31","tarball":"https://registry.npmjs.org/@canvasgfx/stateful/-/stateful-1.0.4.tgz","fileCount":12,"unpackedSize":18807,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHRKpL4WrLOYE9ZbtHnT+WkKYBzS9SQIgKQaSi1B6BVpAiEAlrnUmuVPq27xpHYgZ/bxHfrmQsm2+JbbY/xuZqEDBwg="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj2t6KACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmr9lQ//VjkRBO+EdM8H+S3GaBEUIXKbwU5T8uulGlowz+cYpqwXtpoU\r\n8IcnG7HpSubvSR9o481fdWHBeL7CjlEyuEFikU+4dv9+7Orbjdx/aGXuFNoL\r\n/VgK/Ho4RtnJJvwPIHvzdCysIkUFcOpAhK9AbDWysxrRlKxyiw9zeGFW4hc6\r\nIfXUAw3Odhnk1xozWQSE1sQGHl8XpevHGROKqRwdlxQ+yjv0/glwrpmuu7vk\r\n4FrCGswy8RoGw6TINRaw2+t4eaoMScBv3XckBsRRv5OpDyHudV8Z81reFq05\r\nUyHk23tlYAdnE869DEP+Zfp1qM0E1fNb4oo6OH7R98D2o5RL44eMmYzPOy0n\r\n3hVMQUKdLyd5v8hx1Z0BEjRLXMOq7pSiW+Xetjsv8MuZ9Otn1n3hHXRiiDLt\r\nyOMF4xhUCzcdp3GRHTPqg/QYHLXFf14jFT3nL081stxYC6EgqpodNGmM3BJN\r\nHxokcxjSc3HPc2qIAbmDEJ+2HixS6hgo7RONiiKJ2YfhtBIwqwEmfjj8aQpp\r\n0cK0K+m5Cv6S1f8ZcCVbkLBoKhwFNyX/C/MzVgGnUEYZetMLkB5lNCAyfP/x\r\nbu5nNBrsB/VN5z2pQH92593M0b8bSsVHgLkhfyuP2CEpGLLpkyVcxeYZTfTe\r\nCAdle6uOq3pewTnKD815na4tuz4on83HADc=\r\n=m8JX\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"jbrousseau","email":"jeanbaptiste.rousseau@gmail.com"},"directories":{},"maintainers":[{"name":"jbrousseau","email":"jeanbaptiste.rousseau@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/stateful_1.0.4_1675288202289_0.2863143979402416"},"_hasShrinkwrap":false}},"time":{"created":"2023-02-01T17:30:19.419Z","1.0.3":"2023-02-01T17:30:19.634Z","modified":"2023-02-02T14:36:40.994Z","1.0.4":"2023-02-01T21:50:02.502Z"},"maintainers":[{"email":"alex.hughes000@gmail.com","name":"g0ddish"},{"email":"jeanbaptiste.rousseau@gmail.com","name":"jbrousseau"}],"description":"A minimal state management store for RxJS.","homepage":"https://github.com/canvasgfx/stateful.git","keywords":["javascript","typescript","rxjs","state","redux","store","library"],"repository":{"type":"git","url":"git+https://github.com/canvasgfx/stateful.git"},"author":{"name":"reactgular.com"},"bugs":{"url":"https://github.com/canvasgfx/stateful/issues"},"license":"MIT","readme":"[![Build Status](https://travis-ci.org/reactgular/stateful.svg?branch=master)](https://travis-ci.org/reactgular/stateful)\r\n[![Coverage Status](https://coveralls.io/repos/github/reactgular/stateful/badge.svg?branch=master)](https://coveralls.io/github/reactgular/stateful?branch=master)\r\n[![npm version](https://badge.fury.io/js/%40reactgular%2Fstateful.svg)](https://badge.fury.io/js/%40reactgular%2Fstateful)\r\n\r\n## What is Stateful?\r\n\r\nStateful is a tiny state manager for TypeScript and [RxJS](https://github.com/ReactiveX/RxJS) projects. It's a class that encapsulates a [BehaviorSubject](https://www.learnrxjs.io/subjects/behaviorsubject.html) and \r\nprovides basic store manipulation methods. It's indented for use in small classes that don't need the complexity of a larger state manager.\r\n\r\nStateful is about **1kb** in size after *minification*. \r\n\r\n## Installation\r\n\r\nTo get started, install the package from npm.\r\n\r\n```bash\r\nnpm install --save @reactgular/stateful\r\n```\r\n\r\n## Usage\r\n\r\nStateful is small, simple and easy to use.\r\n\r\n- You construct a Stateful object with a *default state* and use an interface to define the *state object* type.\r\n- You can then `patch()`, `set()` and `reset()` the internal state.\r\n- You use `select()` to create observables of state property changes, and `selector()` to create custom selectors.\r\n\r\n```typescript\r\nimport {Stateful} from '@reactgular/stateful';\r\n\r\ninterface ExampleState {name: string; count: number; }\r\nconst state = new Stateful<ExampleState>({name: \"Example\", count: 4});\r\nstate.patch({name: 'Something'});\r\nstate.select('name').subscribe(value => console.log(value)); // prints \"Something\"\r\n```\r\n\r\n# Stateful Class\r\n\r\nUsage documentation for the `Stateful<TState>` class.\r\n\r\n#### Properties\r\n\r\n- `state$`: An observable that emits all changes to the state.\r\n\r\n#### Methods\r\n\r\n- `complete()`: Stops emitting changes made to the state.\r\n- `default()`: Returns the default state used with the constructor or reset.\r\n- `patch(state: Partial<TState>)`: Patches the current state with partial values.\r\n- `patch<TKey extends keyof TState>(name: TKey, value: TState[TKey])`: Patches a single property on the state with a value.\r\n- `reset(defaultState?: TState)`: Resets the state to the original state used by the constructor, or updates the original state with the passed argument.\r\n- `select<TKey extends keyof TState>(name: TKey): Observable<TState[TKey]>`: Creates an observable that emits values from a property on the state object.\r\n- `selector<TValue>(selector: (s: TState) => TValue): Observable<TValue>`: Creates an observable that emits values produced by the selector function. \r\n- `set(state: TState)`: Sets the current state.\r\n- `snapshot(): TState`: Peeks at the current internal state.\r\n\r\n## Examples\r\n\r\nYou can create *selectors* from the state by using property names. TypeScript will *infer* the correct `Observable<Type>` from the property key.\r\n\r\n```typescript\r\nimport {Stateful} from '@reactgular/stateful';\r\n\r\ninterface ExampleState {name: string; count: number; }\r\nconst state = new Stateful<ExampleState>({name: \"Example\", count: 4});\r\n\r\nconst name$ = state.select('name'); // Observable<string>\r\nname$.subscribe(value => console.log(value)); // prints \"Example\", \"Hello World\"\r\n\r\nstate.patch({name: \"Hello World\"});\r\n```\r\n\r\nYou can write your own custom *selectors*.\r\n\r\n```typescript\r\nimport {Stateful} from '@reactgular/stateful';\r\n\r\ninterface ExampleState {name: string; count: number; }\r\nconst state = new Stateful<ExampleState>({name: \"Example\", count: 4});\r\n\r\nconst nameAndCount$ = state.selector(state => `${state.name} AND ${state.count}`);\r\nnameAndCount$.subscribe(value => console.log(value)); // prints \"Example AND 4\"\r\n```\r\n\r\n## Example Angular Service\r\n\r\nYou can use Stateful as a base class for an Angular service.\r\n\r\n```typescript\r\nimport {Observable} from 'rxjs'; \r\nimport {Stateful} from '@reactgular/stateful';\r\n\r\ninterface ExampleState { counter: number }\r\n\r\n@Injectable()\r\nexport class ExampleService extends Stateful<ExampleState> {\r\n    public constructor() {\r\n        super({counter: 0})\r\n    }\r\n \r\n    public counter(): Observable<number> {\r\n        return this.select('counter');\r\n    }\r\n\r\n    public increment() {\r\n        const counter = this.snapshot().counter + 1;\r\n        this.patch({counter});\r\n    }\r\n\r\n    public decrement() {\r\n        const counter = this.snapshot().counter - 1;\r\n        this.patch({counter});\r\n    }\r\n}\r\n```\r\n\r\n## Example Angular Component\r\n\r\nYou can use Stateful as an internal state manager for an Angular component. By patching incoming `@Input()` properties into the Stateful\r\nobject you can more easily work with observables.\r\n\r\n```typescript\r\ninterface ProductState {\r\n    productId?: number;\r\n    price?: number;\r\n}\r\n\r\n@Component({\r\n    selector: 'project',\r\n    template: `<span>Price: {{price$ | async}}</span>\r\n               <span>Taxes: {{taxes$ | async}}</span>`\r\n})\r\nexport class ProductComponent implements OnInit {\r\n    private state: Stateful<ProductState> = new Stateful<ProductState>({});\r\n\r\n    public price$ = this.state.select('price');\r\n\r\n    public taxes$ = this.state.select('price').pipe(\r\n        map(price => price * 0.07)    \r\n    );\r\n\r\n    @Input()\r\n    public set productId(productId: string) {\r\n        this.state.patch({productId});    \r\n    }\r\n  \r\n    @Input()\r\n    public set price(price: string) {\r\n        this.state.patch({price});    \r\n    }\r\n}\r\n```\r\n\r\n# StorageStateful Class\r\n\r\nStorageStateful extends Stateful and offers persistence of state to a storage service like `localStorage` or `sessionStorage`.\r\n\r\n```typescript\r\nimport {StorageStateful} from '@reactgular/stateful';\r\n\r\ninterface ExampleState {name: string; count: number; }\r\nconst state = new StorageStateful<ExampleState>('app', {name: \"Example\", count: 4});\r\n```\r\n\r\nPass the storage `key` as the first parameter to the constructor, and the default state as the second parameter. The state will\r\nbe persisted to `localStorage` by default under that `key`. Any changes patched to the state are serialized to storage.\r\n\r\nYou can configure custom serializers and storage objects using the `StorageStatefulConfig<TState extends {}>` interface as the third parameter.\r\n\r\n```typescript\r\n/**\r\n * Configuration options for the StorageStateful class.\r\n */\r\nexport interface StorageStatefulConfig<TState extends {}> {\r\n    /**\r\n     * A deserialize function that converts a string into a state object.\r\n     */\r\n    deserializer?: (state: string) => TState;\r\n\r\n    /**\r\n     * A serialize function that converts a state object into a string.\r\n     */\r\n    serializer?: (state: TState) => string;\r\n\r\n    /**\r\n     * The storage object to use (can be localStorage or sessionStorage).\r\n     */\r\n    storage?: Storage;\r\n}\r\n```\r\n","readmeFilename":"README.md"}