{"id":18890898,"url":"https://github.com/igrep/svelte-store-tree","last_synced_at":"2025-04-14T23:31:17.443Z","repository":{"id":59809984,"uuid":"534155298","full_name":"igrep/svelte-store-tree","owner":"igrep","description":"Provides writable/readable stores that can 'zoom' into the part of the store value (so called \"nested store\").","archived":true,"fork":false,"pushed_at":"2024-09-10T01:31:41.000Z","size":786,"stargazers_count":11,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-11T19:25:20.853Z","etag":null,"topics":["state-management","svelte"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/igrep.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-08T10:11:43.000Z","updated_at":"2025-02-11T10:11:24.000Z","dependencies_parsed_at":"2024-09-10T04:57:27.743Z","dependency_job_id":"6a821fda-acea-43fb-9fb5-362d5c808d50","html_url":"https://github.com/igrep/svelte-store-tree","commit_stats":{"total_commits":41,"total_committers":1,"mean_commits":41.0,"dds":0.0,"last_synced_commit":"9d273deb74fd507456c54e437b9bd0ab94809129"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igrep%2Fsvelte-store-tree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igrep%2Fsvelte-store-tree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igrep%2Fsvelte-store-tree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igrep%2Fsvelte-store-tree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/igrep","download_url":"https://codeload.github.com/igrep/svelte-store-tree/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248978633,"owners_count":21192832,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["state-management","svelte"],"created_at":"2024-11-08T07:58:03.636Z","updated_at":"2025-04-14T23:31:16.899Z","avatar_url":"https://github.com/igrep.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# svelte-store-tree\n\n[![npm version](https://badge.fury.io/js/svelte-store-tree.svg)](https://badge.fury.io/js/svelte-store-tree)\n[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)\n![CI](https://github.com/igrep/svelte-store-tree/actions/workflows/ci.yaml/badge.svg)\n\nCurrent status: Experimental.\n\nProvides writable/readable stores that can 'zoom' into a part of the store\nvalue (so-called \"nested stores\"). It enables us to manage the state of the app\nin a single object while keeping the independence of every child component.\n\n# Example\n\n\u003c!-- BEGIN README TEST --\u003e\n\n```typescript\nimport { writableTree, Refuse, into, isPresent } from 'svelte-store-tree';\nimport type { WritableTree } from 'svelte-store-tree';\n\ntype SomeRecord = {\n  id: number;\n  name: string;\n  contact: {\n    phone: string;\n    urls: string[];\n  };\n  favoriteColor: Color | undefined;\n};\n\ntype Color = [number, number, number];\n\n// Create a `WritableTree`\nconst someRecord: WritableTree\u003cSomeRecord\u003e = writableTree({\n  id: 0,\n  name: 'Y. Y',\n  contact: {\n    phone: '+81-00-0000-0000',\n    urls: [\n      'https://the.igreque.info',\n      'https://github.com/igrep',\n    ],\n  },\n  favoriteColor: undefined\n});\n\n// Subscribe as an ordinary store.\nsomeRecord.subscribe((newUser) =\u003e {\n  console.log('Updated the user', newUser);\n});\n\n// `zoom` with the `into` Accessor;\n//    Create a store that subscribes only a specific field of the object\nconst name = someRecord.zoom(into('name'));\nconst contact = someRecord.zoom(into('contact'));\nconst favoriteColor = someRecord.zoom(into('favoriteColor'));\n\nname.subscribe((newName) =\u003e {\n  console.log('Updated the name', newName);\n});\ncontact.subscribe((newContact) =\u003e {\n  console.log('Updated the contact', newContact);\n});\nfavoriteColor.subscribe((newColor) =\u003e {\n  console.log('Updated the color', newColor);\n});\n\n// We can apply `zoom` deeper:\nconst urls = contact.zoom(into('urls'));\n\n// Notifies the subscribers of `someRecord`, `contact`, and `urls`.\n// ** Changes are propagated only to the direct subscribers, and the ancestors'. **\n// ** Not to the the siblings' to avoid extra rerendering of the subscribing components. **\nurls.update((u) =\u003e [...u, 'https://twitter.com/igrep']);\n\n// If your record contains a union type, the `choose` method is useful.\n// Pass a function that returns a `Refuse` (a unique symbol provided by this library)\n// if the value doesn't satisfy the condition.\nconst favoriteColorNonUndefined =\n  favoriteColor.choose((color) =\u003e color ?? Refuse);\n\n// Now, favoriteColorNonUndefined is typed as `WritableTree\u003cColor\u003e`,\n// while favoriteColor is `WritableTree\u003cColor | undefined\u003e`.\n\n// As a shortcut for a nullable type, svelte-store-tree provides\n// the `isPresent` function used with `choose`:\nconst favoriteColorNonUndefined2 = favoriteColor.choose(isPresent);\n\nfavoriteColorNonUndefined.subscribe((newColor) =\u003e {\n  console.log('Updated the color', newColor);\n});\n\n// Notifies the subscribers of `someRecord`, `favoriteColor`, and `favoriteColorNonUndefined`.\nfavoriteColor.set([0xC0, 0x10, 0x10]);\n\n// Notifies the subscribers of `someRecord`, and `favoriteColor` (not `favoriteColorNonUndefined`).\nfavoriteColor.set(undefined);\n```\n\n\u003c!-- END README TEST --\u003e\n\n# Working Example App\n\n\u003ca href=\"https://codesandbox.io/p/github/igrep/svelte-store-tree/draft/floral-sound?workspace=%257B%2522activeFileId%2522%253Anull%252C%2522openFiles%2522%253A%255B%255D%252C%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522gitSidebarPanel%2522%253A%2522COMMIT%2522%252C%2522sidekickItems%2522%253A%255B%257B%2522type%2522%253A%2522PREVIEW%2522%252C%2522taskId%2522%253A%2522dev%2522%252C%2522port%2522%253A5173%252C%2522key%2522%253A%2522cl84b20px00942a69505zsdx2%2522%252C%2522isMinimized%2522%253Afalse%252C%2522path%2522%253A%2522%252Fexample%252F%2522%257D%252C%257B%2522type%2522%253A%2522TASK_LOG%2522%252C%2522taskId%2522%253A%2522dev%2522%252C%2522key%2522%253A%2522cl84b1zcx00452a69im60ktrw%2522%252C%2522isMinimized%2522%253Afalse%257D%255D%257D\"\u003e\nRun on CodeSandbox\n\n![Example App running on CodeSandbox](./docs/codesandbox.png \"Example App running on CodeSandbox\")\n\u003c/a\u003e\n\n# Installation\n\n```bash\n$ npm install --save svelte-store-tree\n```\n\n# API\n\n```typescript\n// Core API\nexport function writableTree\u003cP\u003e(\n  value: P,\n  start: StartStopNotifier\u003cP\u003e = noop,\n): WritableTree\u003cP\u003e;\n\nexport function readableTree\u003cP\u003e(\n  value: P,\n  start: StartStopNotifier\u003cP\u003e = noop,\n): ReadableTree\u003cP\u003e\n\n/// Types related to the Core API\nexport type StoreTreeCore\u003cP\u003e = {\n  zoom\u003cC\u003e(accessor: Accessor\u003cP, C\u003e): WritableTree\u003cC\u003e;\n  zoomNoSet\u003cC\u003e(readChild: (parent: P) =\u003e C | Refuse): ReadableTree\u003cC\u003e;\n  choose\u003cP_ extends P\u003e(readChild: (parent: P) =\u003e P_ | Refuse): WritableTree\u003cP_\u003e;\n};\nexport type ReadableTree\u003cP\u003e = Readable\u003cP\u003e \u0026 StoreTreeCore\u003cP\u003e;\nexport type WritableTree\u003cP\u003e = Writable\u003cP\u003e \u0026 StoreTreeCore\u003cP\u003e;\n\nexport const Refuse: unique symbol = Symbol();\nexport type Refuse = typeof Refuse;\n\n/// Utility function to help the `StoreTreeCore.prototype.choose` method\nexport function isPresent\u003cP\u003e(parent: P): NonNullable\u003cP\u003e | Refuse;\n\n// Accessor API\nexport class Accessor\u003cP, C\u003e {\n  constructor(readChild: (parent: P) =\u003e C | Refuse, writeChild: (parent: P, newChild: C) =\u003e void);\n  readChild: (parent: P) =\u003e C | Refuse;\n  writeChild: (parent: P, newChild: C) =\u003e void;\n  and\u003cGC\u003e(other: Accessor\u003cC, GC\u003e): Accessor\u003cP, GC\u003e;\n};\n\n/// Various Utility Accessors\nexport function into\u003cP, K extends keyof P\u003e(key: K): Accessor\u003cP, P[K]\u003e;\nexport function intoMap\u003cK extends string | number | symbol, V\u003e(key: K): Accessor\u003cMap\u003cK, V\u003e, V\u003e;\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figrep%2Fsvelte-store-tree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Figrep%2Fsvelte-store-tree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figrep%2Fsvelte-store-tree/lists"}