{"_id":"@appboypov/informers","_rev":"4-a208ecdb810fd598aeabc008d075323c","name":"@appboypov/informers","dist-tags":{"latest":"1.0.0"},"versions":{"0.1.3":{"name":"@appboypov/informers","version":"0.1.3","keywords":["result","response","success","fail","typescript","react"],"license":"MIT","_id":"@appboypov/informers@0.1.3","maintainers":[{"name":"appboypov","email":"info@codaveto.com"}],"dist":{"shasum":"c66351672835291a2ecc3e4f8eba628c3cb6af9a","tarball":"https://registry.npmjs.org/@appboypov/informers/-/informers-0.1.3.tgz","fileCount":6,"integrity":"sha512-Tz3zBhmiRF7gULi2dnELXP1tBilm3DRfjPjDk0LYyCg7OEzvRSEbB7ZuonWCoa2L+9ut4ZWy51iQZNIx7AHYJA==","signatures":[{"sig":"MEQCIHG4peGKT52xePgh+QwsA2LcUXzwGHigpCQRF3E8kkOeAiA8M1KpRpFI2rHVpal6wLiP1o+YgyWHnmudAEy9Giinmw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":42226},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"5d9be12c8dfd171be0e5435c6d97ff69c4090093","scripts":{"dev":"tsup src/index.ts --format cjs,esm --dts --watch","test":"vitest run","build":"tsup src/index.ts --format cjs,esm --dts","typecheck":"tsc --noEmit"},"_npmUser":{"name":"appboypov","email":"info@codaveto.com"},"_npmVersion":"11.3.0","description":"Result type (Success/Fail) for operation outcomes in TypeScript/React","directories":{},"_nodeVersion":"24.1.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^1.0.0","typescript":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/informers_0.1.3_1764042764860_0.5780639018131919","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@appboypov/informers","version":"0.1.4","keywords":["result","response","success","fail","typescript","react"],"license":"MIT","_id":"@appboypov/informers@0.1.4","maintainers":[{"name":"appboypov","email":"info@codaveto.com"}],"dist":{"shasum":"d4f0a1d06a96d9aae70a2127c3f5134581f45deb","tarball":"https://registry.npmjs.org/@appboypov/informers/-/informers-0.1.4.tgz","fileCount":6,"integrity":"sha512-dneD0a3yu0L+mJ1DMzQq42sklipCTX6RpP+mgjc9qbtdXjICCgV2utxiQpl8MHHKb9S/38HLzCdY+i0PESCE8Q==","signatures":[{"sig":"MEQCIFwIdSLx3ESZhzBphoLzb1FqiJFJ+9qJEuEzeUtjZ/rqAiBGULkvTV2EhYaqnoH/zniI3YraQRizcPBVrjvRIU5UfQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":42248},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"11dcfc3dbe4a396119f80fbffa02324d99f176cf","scripts":{"dev":"tsup src/index.ts --format cjs,esm --dts --watch","test":"vitest run","build":"tsup src/index.ts --format cjs,esm --dts","typecheck":"tsc --noEmit"},"_npmUser":{"name":"appboypov","email":"info@codaveto.com"},"_npmVersion":"11.3.0","description":"Result type (Success/Fail) for operation outcomes in TypeScript/React","directories":{},"_nodeVersion":"24.1.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^1.0.0","typescript":"^5.3.0"},"_npmOperationalInternal":{"tmp":"tmp/informers_0.1.4_1764042892588_0.6808540668067808","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@appboypov/informers","version":"0.2.0","keywords":["informer","reactive","state","notifier","typescript","react"],"license":"MIT","_id":"@appboypov/informers@0.2.0","maintainers":[{"name":"appboypov","email":"info@codaveto.com"}],"dist":{"shasum":"0982b19d97d0f1b830fdb99d917979fe90caa176","tarball":"https://registry.npmjs.org/@appboypov/informers/-/informers-0.2.0.tgz","fileCount":6,"integrity":"sha512-NADkJuMKZW6osL5n6pn5kN0oWbUK1cb+LyKaMyRRkVn48U+xtCG7KzRX63QmzzndLx48QY8J3yE6VG+jEMV/SA==","signatures":[{"sig":"MEUCIQCJ497tTw5xp1SGCwajAbznaFlg+HcKFtNMTXDsk9OavQIgRPJWc3e4jYXlyQ2e+SuplpKt98ICcamrUC8XMuqrrc8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":8716},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"58e85791673ca4fab199aaaf1fd9a9b68bf52561","scripts":{"test":"vitest run","build":"tsup src/index.ts --format cjs,esm --dts","typecheck":"tsc --noEmit"},"_npmUser":{"name":"appboypov","email":"info@codaveto.com"},"_npmVersion":"11.3.0","description":"Enhanced reactive state management for React - ValueNotifier-like pattern","directories":{},"_nodeVersion":"24.1.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","react":"^18.2.0","vitest":"^1.0.0","typescript":"^5.3.0","@types/react":"^18.2.0"},"peerDependencies":{"react":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/informers_0.2.0_1764043411722_0.48175871950136195","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@appboypov/informers","version":"1.0.0","description":"Reactive state management for React with Informer class and useInformerListenable hook - Flutter ValueNotifier pattern","main":"dist/index.js","module":"dist/index.mjs","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"scripts":{"build":"tsup src/index.ts --format cjs,esm --dts","test":"vitest run","typecheck":"tsc --noEmit"},"keywords":["informer","reactive","state","notifier","typescript","react"],"license":"MIT","peerDependencies":{"react":">=18.0.0"},"devDependencies":{"@testing-library/react":"^14.3.1","@types/react":"^18.2.0","jsdom":"^27.2.0","react":"^18.2.0","react-dom":"^18.3.1","tsup":"^8.0.0","typescript":"^5.3.0","vitest":"^1.0.0"},"_id":"@appboypov/informers@1.0.0","gitHead":"58e85791673ca4fab199aaaf1fd9a9b68bf52561","_nodeVersion":"24.1.0","_npmVersion":"11.3.0","dist":{"integrity":"sha512-wcW+CNawmhloXt/b9x9dM5cWsKDfdKV1T7d/aOa9JqfBq9tL/mnIMIuWIBkmDHW7SrWAgBC26ej6Ngaz9joz7g==","shasum":"1532f5e107c723575e6be0e6960a429e7f010a1a","tarball":"https://registry.npmjs.org/@appboypov/informers/-/informers-1.0.0.tgz","fileCount":6,"unpackedSize":30753,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCW6TacPvrjscBYG+jJWfPQ58ukeHbkUJEgjEuVkUFDagIgI+EvbBuyN68Zh60WRceRlCS/ymDn59L5jeAszpJGK7U="}]},"_npmUser":{"name":"appboypov","email":"info@codaveto.com"},"directories":{},"maintainers":[{"name":"appboypov","email":"info@codaveto.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/informers_1.0.0_1764634715547_0.649616008194712"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-25T03:52:44.811Z","modified":"2025-12-02T00:18:35.917Z","0.1.3":"2025-11-25T03:52:45.113Z","0.1.4":"2025-11-25T03:54:52.812Z","0.2.0":"2025-11-25T04:03:31.972Z","1.0.0":"2025-12-02T00:18:35.759Z"},"license":"MIT","keywords":["informer","reactive","state","notifier","typescript","react"],"description":"Reactive state management for React with Informer class and useInformerListenable hook - Flutter ValueNotifier pattern","maintainers":[{"name":"appboypov","email":"info@codaveto.com"}],"readme":"# @appboypov/informers\n\nReactive state management for React with a ValueNotifier-like pattern inspired by Flutter.\n\n## Installation\n\n```bash\nnpm install @appboypov/informers\n```\n\n## Features\n\n- **Informer class** - Shared reactive state that can be used across components\n- **useInformerListenable hook** - Subscribe to Informer changes with automatic re-renders\n- **InformerListenableBuilder components** - Declarative component-based subscriptions\n- **React 18 concurrent mode support** via `useSyncExternalStore`\n- **Zero dependencies** (peer dependency on React 18+)\n\n## Quick Start\n\n### Shared State with Informer Class\n\n```tsx\nimport { Informer, useInformerListenable } from '@appboypov/informers';\n\n// Create shared state (outside component)\nconst counter = new Informer(0);\n\nfunction CounterDisplay() {\n  // Subscribe to changes\n  const count = useInformerListenable(counter);\n  return <p>Count: {count}</p>;\n}\n\nfunction CounterButtons() {\n  return (\n    <div>\n      <button onClick={() => counter.update(counter.value + 1)}>+</button>\n      <button onClick={() => counter.updateCurrent(n => n - 1)}>-</button>\n    </div>\n  );\n}\n```\n\n### Builder Components\n\n```tsx\nimport { Informer, InformerListenableBuilder } from '@appboypov/informers';\n\nconst user = new Informer({ name: 'John', age: 30 });\n\nfunction UserCard() {\n  return (\n    <InformerListenableBuilder\n      informer={user}\n      builder={(userData) => (\n        <div>\n          <h2>{userData.name}</h2>\n          <p>Age: {userData.age}</p>\n        </div>\n      )}\n    />\n  );\n}\n```\n\n## API\n\n### `Informer<T>`\n\nA reactive state container that notifies listeners when its value changes.\n\n```typescript\nconst informer = new Informer(initialValue, options?);\n```\n\n#### Constructor Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `forceUpdate` | `boolean` | `false` | Notify listeners even when value is same reference |\n\n#### Properties\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `value` | `T` | Current value (direct access, no subscription) |\n\n#### Methods\n\n| Method | Description |\n|--------|-------------|\n| `update(value, options?)` | Update value. Options: `{ doNotifyListeners?: boolean }` |\n| `updateCurrent(updater, options?)` | Update using function: `(current) => newValue` |\n| `rebuild()` | Force notify listeners without changing value |\n| `dispose()` | Clear all listeners |\n\n#### Example\n\n```typescript\nconst counter = new Informer(0);\n\n// Direct access (no subscription)\nconsole.log(counter.value); // 0\n\n// Update and notify\ncounter.update(5);\n\n// Update with function\ncounter.updateCurrent(n => n + 1);\n\n// Silent update (no re-render)\ncounter.update(10, { doNotifyListeners: false });\n\n// Force rebuild\ncounter.rebuild();\n\n// Cleanup\ncounter.dispose();\n```\n\n### `useInformerListenable<T>(informer: Informer<T>): T`\n\nReact hook that subscribes to an Informer and returns its current value. Component re-renders when the Informer's value changes.\n\n```tsx\nconst counter = new Informer(0);\n\nfunction Counter() {\n  const count = useInformerListenable(counter);\n  return <p>Count: {count}</p>;\n}\n```\n\n### `InformerListenableBuilder<T>`\n\nComponent that rebuilds when an Informer's value changes.\n\n```tsx\n<InformerListenableBuilder\n  informer={counter}\n  builder={(value) => <p>Count: {value}</p>}\n/>\n```\n\n### `InformerListenableBuilder2<T1, T2>`\n\nComponent that rebuilds when either of two Informers change.\n\n```tsx\nconst firstName = new Informer('John');\nconst lastName = new Informer('Doe');\n\n<InformerListenableBuilder2\n  informer1={firstName}\n  informer2={lastName}\n  builder={(first, last) => <p>{first} {last}</p>}\n/>\n```\n\n### `InformerListenableBuilder3<T1, T2, T3>`\n\nComponent that rebuilds when any of three Informers change.\n\n```tsx\n<InformerListenableBuilder3\n  informer1={firstName}\n  informer2={lastName}\n  informer3={age}\n  builder={(first, last, userAge) => (\n    <p>{first} {last}, {userAge} years old</p>\n  )}\n/>\n```\n\n## Patterns\n\n### Global State\n\n```typescript\n// stores/counter.ts\nexport const counterStore = new Informer(0);\n\n// components/Counter.tsx\nimport { counterStore } from '../stores/counter';\n\nfunction Counter() {\n  const count = useInformerListenable(counterStore);\n  return <p>{count}</p>;\n}\n```\n\n### Service with Reactive State\n\n```typescript\nclass UserService {\n  readonly currentUser = new Informer<User | null>(null);\n  readonly isLoading = new Informer(false);\n\n  async login(email: string, password: string) {\n    this.isLoading.update(true);\n    try {\n      const user = await api.login(email, password);\n      this.currentUser.update(user);\n    } finally {\n      this.isLoading.update(false);\n    }\n  }\n}\n\n// In component\nfunction UserStatus() {\n  const user = useInformerListenable(userService.currentUser);\n  const loading = useInformerListenable(userService.isLoading);\n\n  if (loading) return <p>Loading...</p>;\n  return <p>Welcome, {user?.name}</p>;\n}\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}