Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/igrep/svelte-store-tree
Provides writable/readable stores that can 'zoom' into the part of the store value (so called "nested store").
https://github.com/igrep/svelte-store-tree
state-management svelte
Last synced: about 5 hours ago
JSON representation
Provides writable/readable stores that can 'zoom' into the part of the store value (so called "nested store").
- Host: GitHub
- URL: https://github.com/igrep/svelte-store-tree
- Owner: igrep
- License: bsd-3-clause
- Created: 2022-09-08T10:11:43.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2024-04-10T07:48:25.000Z (7 months ago)
- Last Synced: 2024-04-25T05:21:20.664Z (7 months ago)
- Topics: state-management, svelte
- Language: TypeScript
- Homepage:
- Size: 669 KB
- Stars: 11
- Watchers: 3
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: ChangeLog.md
- License: LICENSE
Awesome Lists containing this project
README
# svelte-store-tree
[![npm version](https://badge.fury.io/js/svelte-store-tree.svg)](https://badge.fury.io/js/svelte-store-tree)
[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
![CI](https://github.com/igrep/svelte-store-tree/actions/workflows/ci.yaml/badge.svg)Current status: Experimental.
Provides writable/readable stores that can 'zoom' into a part of the store
value (so-called "nested stores"). It enables us to manage the state of the app
in a single object while keeping the independence of every child component.# Example
```typescript
import { writableTree, Refuse, into, isPresent } from 'svelte-store-tree';
import type { WritableTree } from 'svelte-store-tree';type SomeRecord = {
id: number;
name: string;
contact: {
phone: string;
urls: string[];
};
favoriteColor: Color | undefined;
};type Color = [number, number, number];
// Create a `WritableTree`
const someRecord: WritableTree = writableTree({
id: 0,
name: 'Y. Y',
contact: {
phone: '+81-00-0000-0000',
urls: [
'https://the.igreque.info',
'https://github.com/igrep',
],
},
favoriteColor: undefined
});// Subscribe as an ordinary store.
someRecord.subscribe((newUser) => {
console.log('Updated the user', newUser);
});// `zoom` with the `into` Accessor;
// Create a store that subscribes only a specific field of the object
const name = someRecord.zoom(into('name'));
const contact = someRecord.zoom(into('contact'));
const favoriteColor = someRecord.zoom(into('favoriteColor'));name.subscribe((newName) => {
console.log('Updated the name', newName);
});
contact.subscribe((newContact) => {
console.log('Updated the contact', newContact);
});
favoriteColor.subscribe((newColor) => {
console.log('Updated the color', newColor);
});// We can apply `zoom` deeper:
const urls = contact.zoom(into('urls'));// Notifies the subscribers of `someRecord`, `contact`, and `urls`.
// ** Changes are propagated only to the direct subscribers, and the ancestors'. **
// ** Not to the the siblings' to avoid extra rerendering of the subscribing components. **
urls.update((u) => [...u, 'https://twitter.com/igrep']);// If your record contains a union type, the `choose` method is useful.
// Pass a function that returns a `Refuse` (a unique symbol provided by this library)
// if the value doesn't satisfy the condition.
const favoriteColorNonUndefined =
favoriteColor.choose((color) => color ?? Refuse);// Now, favoriteColorNonUndefined is typed as `WritableTree`,
// while favoriteColor is `WritableTree`.// As a shortcut for a nullable type, svelte-store-tree provides
// the `isPresent` function used with `choose`:
const favoriteColorNonUndefined2 = favoriteColor.choose(isPresent);favoriteColorNonUndefined.subscribe((newColor) => {
console.log('Updated the color', newColor);
});// Notifies the subscribers of `someRecord`, `favoriteColor`, and `favoriteColorNonUndefined`.
favoriteColor.set([0xC0, 0x10, 0x10]);// Notifies the subscribers of `someRecord`, and `favoriteColor` (not `favoriteColorNonUndefined`).
favoriteColor.set(undefined);
```# Working Example App
![Example App running on CodeSandbox](./docs/codesandbox.png "Example App running on CodeSandbox")
# Installation
```bash
$ npm install --save svelte-store-tree
```# API
```typescript
// Core API
export function writableTree(
value: P,
start: StartStopNotifier= noop,
): WritableTree;
export function readableTree
(
value: P,
start: StartStopNotifier= noop,
): ReadableTree/// Types related to the Core API
export type StoreTreeCore= {
zoom(accessor: Accessor): WritableTree;
zoomNoSet(readChild: (parent: P) => C | Refuse): ReadableTree;
choose(readChild: (parent: P) => P_ | Refuse): WritableTree;
};
export type ReadableTree= Readable
& StoreTreeCore
;
export type WritableTree= Writable
& StoreTreeCore
;
export const Refuse: unique symbol = Symbol();
export type Refuse = typeof Refuse;/// Utility function to help the `StoreTreeCore.prototype.choose` method
export function isPresent(parent: P): NonNullable
| Refuse;
// Accessor API
export class Accessor{
constructor(readChild: (parent: P) => C | Refuse, writeChild: (parent: P, newChild: C) => void);
readChild: (parent: P) => C | Refuse;
writeChild: (parent: P, newChild: C) => void;
and(other: Accessor): Accessor;
};/// Various Utility Accessors
export function into(key: K): Accessor
;
export function intoMap(key: K): Accessor, V>;
```