shelving 1.106.0 → 1.107.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  - Schemas (validation)
10
10
  - Databases (via providers including in-memory, Firestore, IndexedDB)
11
11
  - Querying (sorting, filtering, slicing)
12
- - State (events and state)
12
+ - Store (events and state)
13
13
  - React (hooks and state)
14
14
  - Helpers (errors, arrays, objects, strings, dates, equality, merging, diffing, cloning, debug)
15
15
 
@@ -2,27 +2,27 @@ import type { AbstractProvider } from "../provider/Provider.js";
2
2
  import type { StopCallback } from "../util/callback.js";
3
3
  import type { Data } from "../util/data.js";
4
4
  import type { ItemData, ItemValue } from "../util/item.js";
5
- import { BooleanState } from "../state/BooleanState.js";
6
- import { State } from "../state/State.js";
7
- /** Hold the current state of a item. */
8
- export declare class ItemState<T extends Data = Data> extends State<ItemValue<T>> {
5
+ import { BooleanStore } from "../store/BooleanStore.js";
6
+ import { Store } from "../store/Store.js";
7
+ /** Store a single item. */
8
+ export declare class ItemStore<T extends Data = Data> extends Store<ItemValue<T>> {
9
9
  readonly provider: AbstractProvider;
10
10
  readonly collection: string;
11
11
  readonly id: string;
12
- readonly busy: BooleanState;
13
- /** Get the data of this state (throws `RequiredError` if item doesn't exist). */
12
+ readonly busy: BooleanStore;
13
+ /** Get the data of this store (throws `RequiredError` if item doesn't exist). */
14
14
  get data(): ItemData<T>;
15
- /** Set the data of this state. */
15
+ /** Set the data of this store. */
16
16
  set data(data: T | ItemData<T>);
17
17
  /** Does the item exist? */
18
18
  get exists(): boolean;
19
19
  constructor(provider: AbstractProvider, collection: string, id: string);
20
- /** Refresh this state from the source provider. */
20
+ /** Refresh this store from the source provider. */
21
21
  refresh(provider?: AbstractProvider): void;
22
22
  private _refresh;
23
- /** Refresh this state if data in the cache is older than `maxAge` (in milliseconds). */
23
+ /** Refresh this store if data in the cache is older than `maxAge` (in milliseconds). */
24
24
  refreshStale(maxAge: number, provider?: AbstractProvider): void;
25
- /** Subscribe this state to a provider. */
25
+ /** Subscribe this store to a provider. */
26
26
  connect(provider?: AbstractProvider): StopCallback;
27
27
  [Symbol.asyncIterator](): AsyncGenerator<ItemValue<T>, void, void>;
28
28
  private _iterating;
@@ -1,23 +1,23 @@
1
1
  import { CacheProvider } from "../provider/CacheProvider.js";
2
- import { BooleanState } from "../state/BooleanState.js";
3
- import { State } from "../state/State.js";
2
+ import { BooleanStore } from "../store/BooleanStore.js";
3
+ import { Store } from "../store/Store.js";
4
4
  import { call } from "../util/callback.js";
5
5
  import { NONE } from "../util/constants.js";
6
6
  import { getItemData } from "../util/item.js";
7
7
  import { getRequired } from "../util/optional.js";
8
8
  import { runSequence } from "../util/sequence.js";
9
9
  import { getOptionalSource } from "../util/source.js";
10
- /** Hold the current state of a item. */
11
- export class ItemState extends State {
10
+ /** Store a single item. */
11
+ export class ItemStore extends Store {
12
12
  provider;
13
13
  collection;
14
14
  id;
15
- busy = new BooleanState();
16
- /** Get the data of this state (throws `RequiredError` if item doesn't exist). */
15
+ busy = new BooleanStore();
16
+ /** Get the data of this store (throws `RequiredError` if item doesn't exist). */
17
17
  get data() {
18
18
  return getRequired(this.value);
19
19
  }
20
- /** Set the data of this state. */
20
+ /** Set the data of this store. */
21
21
  set data(data) {
22
22
  this.value = getItemData(this.id, data);
23
23
  }
@@ -36,7 +36,7 @@ export class ItemState extends State {
36
36
  if (this.loading)
37
37
  this.refresh();
38
38
  }
39
- /** Refresh this state from the source provider. */
39
+ /** Refresh this store from the source provider. */
40
40
  refresh(provider = this.provider) {
41
41
  if (!this.busy.value)
42
42
  void this._refresh(provider);
@@ -54,16 +54,16 @@ export class ItemState extends State {
54
54
  this.busy.value = false;
55
55
  }
56
56
  }
57
- /** Refresh this state if data in the cache is older than `maxAge` (in milliseconds). */
57
+ /** Refresh this store if data in the cache is older than `maxAge` (in milliseconds). */
58
58
  refreshStale(maxAge, provider) {
59
59
  if (this.age > maxAge)
60
60
  this.refresh(provider);
61
61
  }
62
- /** Subscribe this state to a provider. */
62
+ /** Subscribe this store to a provider. */
63
63
  connect(provider = this.provider) {
64
64
  return runSequence(this.through(provider.getItemSequence(this.collection, this.id)));
65
65
  }
66
- // Override to subscribe to `MemoryProvider` while things are iterating over this state.
66
+ // Override to subscribe to `MemoryProvider` while things are iterating over this store.
67
67
  async *[Symbol.asyncIterator]() {
68
68
  this.start();
69
69
  this._iterating++;
@@ -2,14 +2,14 @@ import type { AbstractProvider } from "../provider/Provider.js";
2
2
  import type { StopCallback } from "../util/callback.js";
3
3
  import type { Data } from "../util/data.js";
4
4
  import type { ItemArray, ItemData, ItemQuery, ItemValue } from "../util/item.js";
5
- import { BooleanState } from "../state/BooleanState.js";
6
- import { State } from "../state/State.js";
7
- /** Hold the current state of a query. */
8
- export declare class QueryState<T extends Data = Data> extends State<ItemArray<T>> implements Iterable<ItemData<T>> {
5
+ import { BooleanStore } from "../store/BooleanStore.js";
6
+ import { Store } from "../store/Store.js";
7
+ /** Store a set of multiple items. */
8
+ export declare class QueryStore<T extends Data = Data> extends Store<ItemArray<T>> implements Iterable<ItemData<T>> {
9
9
  readonly provider: AbstractProvider;
10
10
  readonly collection: string;
11
11
  readonly query: ItemQuery<T>;
12
- readonly busy: BooleanState;
12
+ readonly busy: BooleanStore;
13
13
  readonly limit: number;
14
14
  /** Can more items be loaded after the current result. */
15
15
  get hasMore(): boolean;
@@ -27,12 +27,12 @@ export declare class QueryState<T extends Data = Data> extends State<ItemArray<T
27
27
  /** Get the number of items matching this query. */
28
28
  get count(): number;
29
29
  constructor(provider: AbstractProvider, collection: string, query: ItemQuery<T>);
30
- /** Refresh this state from the source provider. */
30
+ /** Refresh this store from the source provider. */
31
31
  refresh(provider?: AbstractProvider): void;
32
32
  private _refresh;
33
- /** Refresh this state if data in the cache is older than `maxAge` (in milliseconds). */
33
+ /** Refresh this store if data in the cache is older than `maxAge` (in milliseconds). */
34
34
  refreshStale(maxAge: number): void;
35
- /** Subscribe this state to a provider. */
35
+ /** Subscribe this store to a provider. */
36
36
  connect(provider?: AbstractProvider): StopCallback;
37
37
  /**
38
38
  * Load more items after the last once.
@@ -1,6 +1,6 @@
1
1
  import { CacheProvider } from "../provider/CacheProvider.js";
2
- import { BooleanState } from "../state/BooleanState.js";
3
- import { State } from "../state/State.js";
2
+ import { BooleanStore } from "../store/BooleanStore.js";
3
+ import { Store } from "../store/Store.js";
4
4
  import { getOptionalFirstItem, getOptionalLastItem } from "../util/array.js";
5
5
  import { call } from "../util/callback.js";
6
6
  import { NONE } from "../util/constants.js";
@@ -8,12 +8,12 @@ import { getRequired } from "../util/optional.js";
8
8
  import { getAfterQuery, getLimit } from "../util/query.js";
9
9
  import { runSequence } from "../util/sequence.js";
10
10
  import { getOptionalSource } from "../util/source.js";
11
- /** Hold the current state of a query. */
12
- export class QueryState extends State {
11
+ /** Store a set of multiple items. */
12
+ export class QueryStore extends Store {
13
13
  provider;
14
14
  collection;
15
15
  query;
16
- busy = new BooleanState();
16
+ busy = new BooleanStore();
17
17
  limit;
18
18
  /** Can more items be loaded after the current result. */
19
19
  get hasMore() {
@@ -56,7 +56,7 @@ export class QueryState extends State {
56
56
  if (this.loading)
57
57
  this.refresh();
58
58
  }
59
- /** Refresh this state from the source provider. */
59
+ /** Refresh this store from the source provider. */
60
60
  refresh(provider = this.provider) {
61
61
  if (!this.busy.value)
62
62
  void this._refresh(provider);
@@ -76,12 +76,12 @@ export class QueryState extends State {
76
76
  this.busy.value = false;
77
77
  }
78
78
  }
79
- /** Refresh this state if data in the cache is older than `maxAge` (in milliseconds). */
79
+ /** Refresh this store if data in the cache is older than `maxAge` (in milliseconds). */
80
80
  refreshStale(maxAge) {
81
81
  if (this.age > maxAge)
82
82
  this.refresh();
83
83
  }
84
- /** Subscribe this state to a provider. */
84
+ /** Subscribe this store to a provider. */
85
85
  connect(provider = this.provider) {
86
86
  return runSequence(this.through(provider.getQuerySequence(this.collection, this.query)));
87
87
  }
@@ -110,7 +110,7 @@ export class QueryState extends State {
110
110
  this.busy.value = false;
111
111
  }
112
112
  }
113
- // Override to subscribe to `MemoryProvider` while things are iterating over this state.
113
+ // Override to subscribe to `MemoryProvider` while things are iterating over this store.
114
114
  async *[Symbol.asyncIterator]() {
115
115
  this.start();
116
116
  this._iterating++;
package/db/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export * from "./Database.js";
2
2
  export * from "./CollectionReference.js";
3
3
  export * from "./ItemReference.js";
4
- export * from "./ItemState.js";
4
+ export * from "./ItemStore.js";
5
5
  export * from "./QueryReference.js";
6
- export * from "./QueryState.js";
6
+ export * from "./QueryStore.js";
package/db/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export * from "./Database.js";
2
2
  export * from "./CollectionReference.js";
3
3
  export * from "./ItemReference.js";
4
- export * from "./ItemState.js";
4
+ export * from "./ItemStore.js";
5
5
  export * from "./QueryReference.js";
6
- export * from "./QueryState.js";
6
+ export * from "./QueryStore.js";
package/index.d.ts CHANGED
@@ -13,5 +13,5 @@ export * from "./markup/index.js";
13
13
  export * from "./provider/index.js";
14
14
  export * from "./schema/index.js";
15
15
  export * from "./sequence/index.js";
16
- export * from "./state/index.js";
16
+ export * from "./store/index.js";
17
17
  export * from "./util/index.js";
package/index.js CHANGED
@@ -17,6 +17,6 @@ export * from "./provider/index.js";
17
17
  // export * from "./react/index.js"; // Not exported.
18
18
  export * from "./schema/index.js";
19
19
  export * from "./sequence/index.js";
20
- export * from "./state/index.js";
20
+ export * from "./store/index.js";
21
21
  // export * from "./test/index.js"; // Not exported.
22
22
  export * from "./util/index.js";
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "state-management",
12
12
  "query-builder"
13
13
  ],
14
- "version": "1.106.0",
14
+ "version": "1.107.0",
15
15
  "repository": "https://github.com/dhoulb/shelving",
16
16
  "author": "Dave Houlbrooke <dave@shax.com>",
17
17
  "license": "0BSD",
@@ -35,7 +35,7 @@
35
35
  "./react": "./react/index.js",
36
36
  "./schema": "./schema/index.js",
37
37
  "./sequence": "./sequence/index.js",
38
- "./state": "./state/index.js",
38
+ "./store": "./store/index.js",
39
39
  "./test": "./test/index.js",
40
40
  "./util": "./util/index.js"
41
41
  },
@@ -2,17 +2,17 @@
2
2
  import type { AsyncDatabase, Database } from "../db/Database.js";
3
3
  import type { DataKey, Datas } from "../util/data.js";
4
4
  import type { ItemQuery } from "../util/item.js";
5
- import { ItemState } from "../db/ItemState.js";
6
- import { QueryState } from "../db/QueryState.js";
5
+ import { ItemStore } from "../db/ItemStore.js";
6
+ import { QueryStore } from "../db/QueryStore.js";
7
7
  import { type Optional } from "../util/optional.js";
8
8
  /**
9
9
  * Create a data context that can be provided to React elements and allows them to call `useItem()` and `useQuery()`
10
10
  */
11
11
  export declare function createDataContext<T extends Datas>({ provider, }: Database<T> | AsyncDatabase<T>): {
12
- readonly useItem: <K extends DataKey<T>>(collection: K, id: string) => ItemState<T[K]>;
13
- readonly useQuery: <K extends DataKey<T>>(collection: K, query: ItemQuery<T[K]>) => QueryState<T[K]>;
14
- readonly useOptionalItem: <K extends DataKey<T>>(collection: K, id: Optional<string>) => ItemState<T[K]> | undefined;
15
- readonly useOptionalQuery: <K extends DataKey<T>>(collection: K, query: Optional<ItemQuery<T[K]>>) => QueryState<T[K]> | undefined;
12
+ readonly useItem: <K extends DataKey<T>>(collection: K, id: string) => ItemStore<T[K]>;
13
+ readonly useQuery: <K extends DataKey<T>>(collection: K, query: ItemQuery<T[K]>) => QueryStore<T[K]>;
14
+ readonly useOptionalItem: <K extends DataKey<T>>(collection: K, id: Optional<string>) => ItemStore<T[K]> | undefined;
15
+ readonly useOptionalQuery: <K extends DataKey<T>>(collection: K, query: Optional<ItemQuery<T[K]>>) => QueryStore<T[K]> | undefined;
16
16
  readonly DataProvider: ({ children }: {
17
17
  children: React.ReactNode;
18
18
  }) => React.ReactElement;
@@ -1,9 +1,9 @@
1
- import { ItemState } from "../db/ItemState.js";
2
- import { QueryState } from "../db/QueryState.js";
1
+ import { ItemStore } from "../db/ItemStore.js";
2
+ import { QueryStore } from "../db/QueryStore.js";
3
3
  import { setMapItem } from "../util/map.js";
4
4
  import { getRequired } from "../util/optional.js";
5
5
  import { createCacheContext } from "./createCacheContext.js";
6
- import { useState } from "./useState.js";
6
+ import { useStore } from "./useStore.js";
7
7
  /**
8
8
  * Create a data context that can be provided to React elements and allows them to call `useItem()` and `useQuery()`
9
9
  */
@@ -12,12 +12,12 @@ export function createDataContext({ provider, }) {
12
12
  const useOptionalItem = (collection, id) => {
13
13
  const cache = useCache();
14
14
  const key = id && `${collection}/${id}`;
15
- return useState(id && key ? cache.get(key) || setMapItem(cache, key, new ItemState(provider, collection, id)) : undefined);
15
+ return useStore(id && key ? cache.get(key) || setMapItem(cache, key, new ItemStore(provider, collection, id)) : undefined);
16
16
  };
17
17
  const useOptionalQuery = (collection, query) => {
18
18
  const cache = useCache();
19
19
  const key = `${collection}?${JSON.stringify(query)}`;
20
- return useState(query && key ? cache.get(key) || setMapItem(cache, key, new QueryState(provider, collection, query)) : undefined);
20
+ return useStore(query && key ? cache.get(key) || setMapItem(cache, key, new QueryStore(provider, collection, query)) : undefined);
21
21
  };
22
22
  return {
23
23
  useOptionalItem,
package/react/index.d.ts CHANGED
@@ -5,4 +5,4 @@ export * from "./useInstance.js";
5
5
  export * from "./useLazy.js";
6
6
  export * from "./useReduce.js";
7
7
  export * from "./useSequence.js";
8
- export * from "./useState.js";
8
+ export * from "./useStore.js";
package/react/index.js CHANGED
@@ -5,4 +5,4 @@ export * from "./useInstance.js";
5
5
  export * from "./useLazy.js";
6
6
  export * from "./useReduce.js";
7
7
  export * from "./useSequence.js";
8
- export * from "./useState.js";
8
+ export * from "./useStore.js";
@@ -4,6 +4,5 @@
4
4
  * @param sequence An object implementing the `AsyncIterable` interface.
5
5
  * - Subscription is recreated every time this value changes.
6
6
  * - Memoise this value to persist the subscription for the lifetime of the component.
7
- * - If the value is a `State` instance
8
7
  */
9
8
  export declare function useSequence<T>(sequence?: AsyncIterable<T>): T | undefined;
@@ -7,7 +7,6 @@ import { runSequence } from "../util/sequence.js";
7
7
  * @param sequence An object implementing the `AsyncIterable` interface.
8
8
  * - Subscription is recreated every time this value changes.
9
9
  * - Memoise this value to persist the subscription for the lifetime of the component.
10
- * - If the value is a `State` instance
11
10
  */
12
11
  export function useSequence(sequence) {
13
12
  const [value, setValue] = useState(undefined);
@@ -0,0 +1,5 @@
1
+ import type { AnyStore } from "../store/Store.js";
2
+ import type { Optional } from "../util/optional.js";
3
+ /** Subscribe to a Shelving `Store` instance to refresh this component when its value changes. */
4
+ export declare function useStore<T extends AnyStore>(store: T): T;
5
+ export declare function useStore<T extends AnyStore>(store?: Optional<T>): T | undefined;
@@ -0,0 +1,8 @@
1
+ import { useCallback, useSyncExternalStore } from "react";
2
+ import { NONE } from "../util/constants.js";
3
+ import { BLACKHOLE } from "../util/function.js";
4
+ import { runSequence } from "../util/sequence.js";
5
+ export function useStore(store) {
6
+ useSyncExternalStore(useCallback(onStoreChange => (store ? runSequence(store, onStoreChange, onStoreChange) : BLACKHOLE), [store]), () => (!store ? store : store.loading ? NONE : store.value));
7
+ return store ?? undefined;
8
+ }
@@ -1,9 +1,9 @@
1
1
  import type { ImmutableArray } from "../util/array.js";
2
- import { State } from "./State.js";
3
- /** State that stores an array and has additional methods to help with that. */
4
- export declare class ArrayState<T> extends State<ImmutableArray<T>> implements Iterable<T> {
2
+ import { Store } from "./Store.js";
3
+ /** Store an array. */
4
+ export declare class ArrayStore<T> extends Store<ImmutableArray<T>> implements Iterable<T> {
5
5
  constructor(value?: ImmutableArray<T>, time?: number);
6
- /** Get the length of the current value of this state. */
6
+ /** Get the length of the current value of this store. */
7
7
  get count(): number;
8
8
  /** Add items to this array. */
9
9
  add(...items: T[]): void;
@@ -1,11 +1,11 @@
1
1
  import { omitArrayItems, toggleArrayItems, withArrayItems } from "../util/array.js";
2
- import { State } from "./State.js";
3
- /** State that stores an array and has additional methods to help with that. */
4
- export class ArrayState extends State {
2
+ import { Store } from "./Store.js";
3
+ /** Store an array. */
4
+ export class ArrayStore extends Store {
5
5
  constructor(value = [], time) {
6
6
  super(value, time);
7
7
  }
8
- /** Get the length of the current value of this state. */
8
+ /** Get the length of the current value of this store. */
9
9
  get count() {
10
10
  return this.value.length;
11
11
  }
@@ -1,7 +1,7 @@
1
1
  import type { NONE } from "../util/constants.js";
2
- import { State } from "./State.js";
3
- /** State that stores a boolean and has additional methods to help with that. */
4
- export declare class BooleanState extends State<boolean> {
2
+ import { Store } from "./Store.js";
3
+ /** Store a boolean. */
4
+ export declare class BooleanStore extends Store<boolean> {
5
5
  constructor(value?: boolean | typeof NONE, time?: number);
6
6
  /** Toggle the current boolean value. */
7
7
  toggle(): void;
@@ -1,6 +1,6 @@
1
- import { State } from "./State.js";
2
- /** State that stores a boolean and has additional methods to help with that. */
3
- export class BooleanState extends State {
1
+ import { Store } from "./Store.js";
2
+ /** Store a boolean. */
3
+ export class BooleanStore extends Store {
4
4
  constructor(value = false, time) {
5
5
  super(value, time);
6
6
  }
@@ -1,11 +1,11 @@
1
1
  import type { Data, DataKey } from "../util/data.js";
2
2
  import type { Updates } from "../util/update.js";
3
- import { State } from "./State.js";
4
- /** State that stores a data object and has additional methods to help with that. */
5
- export declare class DataState<T extends Data> extends State<T> {
6
- /** Get the data of this state. */
3
+ import { Store } from "./Store.js";
4
+ /** Store a data object. */
5
+ export declare class DataStore<T extends Data> extends Store<T> {
6
+ /** Get the data of this store. */
7
7
  get data(): T;
8
- /** Set the data of this state. */
8
+ /** Set the data of this store. */
9
9
  set data(data: T);
10
10
  /** Update several props in this data. */
11
11
  update(updates: Updates<T>): void;
@@ -14,11 +14,11 @@ export declare class DataState<T extends Data> extends State<T> {
14
14
  /** Update a single named prop in this data. */
15
15
  setProp<K extends DataKey<T>>(name: K, value: T[K]): void;
16
16
  }
17
- /** State that stores an optional data object and has additional methods to help with that. */
18
- export declare class OptionalDataState<T extends Data> extends State<T | undefined> {
19
- /** Get current data value of this state (or throw `Promise` that resolves to the next required value). */
17
+ /** Store an optional data object. */
18
+ export declare class OptionalDataStore<T extends Data> extends Store<T | undefined> {
19
+ /** Get current data value of this store (or throw `Promise` that resolves to the next required value). */
20
20
  get data(): T;
21
- /** Set the data of this state. */
21
+ /** Set the data of this store. */
22
22
  set data(data: T);
23
23
  /** Does the data exist or not? */
24
24
  get exists(): boolean;
@@ -1,14 +1,14 @@
1
1
  import { withProp } from "../util/object.js";
2
2
  import { getRequired } from "../util/optional.js";
3
3
  import { updateData } from "../util/update.js";
4
- import { State } from "./State.js";
5
- /** State that stores a data object and has additional methods to help with that. */
6
- export class DataState extends State {
7
- /** Get the data of this state. */
4
+ import { Store } from "./Store.js";
5
+ /** Store a data object. */
6
+ export class DataStore extends Store {
7
+ /** Get the data of this store. */
8
8
  get data() {
9
9
  return this.value;
10
10
  }
11
- /** Set the data of this state. */
11
+ /** Set the data of this store. */
12
12
  set data(data) {
13
13
  this.value = data;
14
14
  }
@@ -25,13 +25,13 @@ export class DataState extends State {
25
25
  this.value = withProp(this.data, name, value);
26
26
  }
27
27
  }
28
- /** State that stores an optional data object and has additional methods to help with that. */
29
- export class OptionalDataState extends State {
30
- /** Get current data value of this state (or throw `Promise` that resolves to the next required value). */
28
+ /** Store an optional data object. */
29
+ export class OptionalDataStore extends Store {
30
+ /** Get current data value of this store (or throw `Promise` that resolves to the next required value). */
31
31
  get data() {
32
32
  return getRequired(this.value);
33
33
  }
34
- /** Set the data of this state. */
34
+ /** Set the data of this store. */
35
35
  set data(data) {
36
36
  this.value = data;
37
37
  }
@@ -1,10 +1,10 @@
1
1
  import type { DictionaryItem, ImmutableDictionary } from "../util/dictionary.js";
2
2
  import type { Updates } from "../util/update.js";
3
- import { State } from "./State.js";
4
- /** State that stores a dictionary object and has additional methods to help with that. */
5
- export declare class DictionaryState<T> extends State<ImmutableDictionary<T>> implements Iterable<DictionaryItem<T>> {
3
+ import { Store } from "./Store.js";
4
+ /** Store a dictionary object. */
5
+ export declare class DictionaryStore<T> extends Store<ImmutableDictionary<T>> implements Iterable<DictionaryItem<T>> {
6
6
  constructor(value?: ImmutableDictionary<T>, time?: number);
7
- /** Get the length of the current value of this state. */
7
+ /** Get the length of the current value of this store. */
8
8
  get count(): number;
9
9
  /** Set a named entry in this object with a different value. */
10
10
  update(updates: Updates<ImmutableDictionary<T>>): void;
@@ -1,13 +1,13 @@
1
1
  import { getDictionaryItems, omitDictionaryItems } from "../util/dictionary.js";
2
2
  import { withProp } from "../util/object.js";
3
3
  import { updateData } from "../util/update.js";
4
- import { State } from "./State.js";
5
- /** State that stores a dictionary object and has additional methods to help with that. */
6
- export class DictionaryState extends State {
4
+ import { Store } from "./Store.js";
5
+ /** Store a dictionary object. */
6
+ export class DictionaryStore extends Store {
7
7
  constructor(value = {}, time) {
8
8
  super(value, time);
9
9
  }
10
- /** Get the length of the current value of this state. */
10
+ /** Get the length of the current value of this store. */
11
11
  get count() {
12
12
  return Object.keys(this.value).length;
13
13
  }
@@ -0,0 +1,42 @@
1
+ import { DeferredSequence } from "../sequence/DeferredSequence.js";
2
+ import { NONE } from "../util/constants.js";
3
+ /** Any `Store` instance. */
4
+ export type AnyStore = Store<any>;
5
+ /**
6
+ * Store that retains its most recent value and is async-iterable to allow values to be observed.
7
+ * - Current value can be read at `store.value` and `store.data`
8
+ * - Stores also send their most-recent value to any new subscribers immediately when a new subscriber is added.
9
+ * - Stores can also be in a loading store where they do not have a current value.
10
+ *
11
+ * @param initial The initial value for the store, a `Promise` that resolves to the initial value, a source `Subscribable` to subscribe to, or another `Store` instance to take the initial value from and subscribe to.
12
+ * - To set the store to be loading, use the `NONE` constant or a `Promise` value.
13
+ * - To set the store to an explicit value, use that value or another `Store` instance with a value.
14
+ * */
15
+ export declare class Store<T> implements AsyncIterable<T> {
16
+ /** Deferred sequence this store uses to issue values as they change. */
17
+ readonly next: DeferredSequence<T>;
18
+ /** Current value of the store (or throw a promise that resolves when this store receives its next value or error). */
19
+ get value(): T;
20
+ set value(value: T);
21
+ private _value;
22
+ /** Is there a current value, or is it still loading. */
23
+ get loading(): boolean;
24
+ /** Time (in milliseconds) this store was last updated with a new value, or `undefined` if this store is currently loading. */
25
+ get time(): number | undefined;
26
+ private _time;
27
+ /** How old this store's value is (in milliseconds). */
28
+ get age(): number;
29
+ /** Current error of this store (or `undefined` if there is no reason). */
30
+ get reason(): unknown;
31
+ set reason(reason: Error | unknown);
32
+ private _reason;
33
+ /** Store is initiated with an initial store. */
34
+ constructor(value: T | typeof NONE, time?: number);
35
+ /** Set the value of the store. */
36
+ set(next: T): void;
37
+ /** Set the value of the store as values are pulled from a sequence. */
38
+ through(sequence: AsyncIterable<T>): AsyncIterable<T>;
39
+ [Symbol.asyncIterator](): AsyncGenerator<T, void, void>;
40
+ }
41
+ /** Is an unknown value a `Store` instance. */
42
+ export declare const isStore: <T extends AnyStore>(value: unknown) => value is T;
@@ -1,19 +1,19 @@
1
1
  import { DeferredSequence } from "../sequence/DeferredSequence.js";
2
2
  import { NONE } from "../util/constants.js";
3
3
  /**
4
- * Stream that retains its most recent value
5
- * - Current value can be read at `state.value` and `state.data`
6
- * - States also send their most-recent value to any new subscribers immediately when a new subscriber is added.
7
- * - States can also be in a loading state where they do not have a current value.
4
+ * Store that retains its most recent value and is async-iterable to allow values to be observed.
5
+ * - Current value can be read at `store.value` and `store.data`
6
+ * - Stores also send their most-recent value to any new subscribers immediately when a new subscriber is added.
7
+ * - Stores can also be in a loading store where they do not have a current value.
8
8
  *
9
- * @param initial The initial value for the state, a `Promise` that resolves to the initial value, a source `Subscribable` to subscribe to, or another `State` instance to take the initial value from and subscribe to.
10
- * - To set the state to be loading, use the `NONE` constant or a `Promise` value.
11
- * - To set the state to an explicit value, use that value or another `State` instance with a value.
9
+ * @param initial The initial value for the store, a `Promise` that resolves to the initial value, a source `Subscribable` to subscribe to, or another `Store` instance to take the initial value from and subscribe to.
10
+ * - To set the store to be loading, use the `NONE` constant or a `Promise` value.
11
+ * - To set the store to an explicit value, use that value or another `Store` instance with a value.
12
12
  * */
13
- export class State {
14
- /** Deferred sequence this state uses to issue values as they change. */
13
+ export class Store {
14
+ /** Deferred sequence this store uses to issue values as they change. */
15
15
  next = new DeferredSequence();
16
- /** Current value of the state (or throw a promise that resolves when this state receives its next value or error). */
16
+ /** Current value of the store (or throw a promise that resolves when this store receives its next value or error). */
17
17
  get value() {
18
18
  if (this._reason !== undefined)
19
19
  throw this._reason;
@@ -34,17 +34,17 @@ export class State {
34
34
  get loading() {
35
35
  return this._value === NONE;
36
36
  }
37
- /** Time (in milliseconds) this state was last updated with a new value, or `undefined` if this state is currently loading. */
37
+ /** Time (in milliseconds) this store was last updated with a new value, or `undefined` if this store is currently loading. */
38
38
  get time() {
39
39
  return this._value === NONE ? undefined : this._time;
40
40
  }
41
41
  _time;
42
- /** How old this state's value is (in milliseconds). */
42
+ /** How old this store's value is (in milliseconds). */
43
43
  get age() {
44
44
  const time = this.time;
45
45
  return typeof time === "number" ? Date.now() - time : Infinity;
46
46
  }
47
- /** Current error of this state (or `undefined` if there is no reason). */
47
+ /** Current error of this store (or `undefined` if there is no reason). */
48
48
  get reason() {
49
49
  return this._reason;
50
50
  }
@@ -55,16 +55,16 @@ export class State {
55
55
  }
56
56
  }
57
57
  _reason = undefined;
58
- /** State is initiated with an initial state. */
58
+ /** Store is initiated with an initial store. */
59
59
  constructor(value, time = Date.now()) {
60
60
  this._value = value;
61
61
  this._time = time;
62
62
  }
63
- /** Set the value of the state. */
63
+ /** Set the value of the store. */
64
64
  set(next) {
65
65
  this.value = next;
66
66
  }
67
- /** Set the value of the state as values are pulled from a sequence. */
67
+ /** Set the value of the store as values are pulled from a sequence. */
68
68
  async *through(sequence) {
69
69
  for await (const value of sequence) {
70
70
  this.value = value;
@@ -72,7 +72,7 @@ export class State {
72
72
  }
73
73
  }
74
74
  // Implement `AsyncIterable`
75
- // Issues the current value of the state first, then any subsequent values that are issued.
75
+ // Issues the current value of the store first, then any subsequent values that are issued.
76
76
  async *[Symbol.asyncIterator]() {
77
77
  await Promise.resolve(); // Introduce a slight delay, i.e. don't immediately yield `this.value` in case it is changed synchronously.
78
78
  if (!this.loading)
@@ -80,5 +80,5 @@ export class State {
80
80
  yield* this.next;
81
81
  }
82
82
  }
83
- /** Is an unknown value a `State` instance. */
84
- export const isState = (value) => value instanceof State;
83
+ /** Is an unknown value a `Store` instance. */
84
+ export const isStore = (value) => value instanceof Store;
@@ -0,0 +1,5 @@
1
+ export * from "./Store.js";
2
+ export * from "./ArrayStore.js";
3
+ export * from "./BooleanStore.js";
4
+ export * from "./DataStore.js";
5
+ export * from "./DictionaryStore.js";
package/store/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from "./Store.js";
2
+ export * from "./ArrayStore.js";
3
+ export * from "./BooleanStore.js";
4
+ export * from "./DataStore.js";
5
+ export * from "./DictionaryStore.js";
@@ -1,4 +0,0 @@
1
- import type { AnyState } from "../state/State.js";
2
- import type { Optional } from "../util/optional.js";
3
- export declare function useState<T extends AnyState>(state: T): T;
4
- export declare function useState<T extends AnyState>(state?: Optional<T>): T | undefined;
package/react/useState.js DELETED
@@ -1,8 +0,0 @@
1
- import { useCallback, useSyncExternalStore } from "react";
2
- import { NONE } from "../util/constants.js";
3
- import { BLACKHOLE } from "../util/function.js";
4
- import { runSequence } from "../util/sequence.js";
5
- export function useState(state) {
6
- useSyncExternalStore(useCallback(onStateChange => (state ? runSequence(state, onStateChange, onStateChange) : BLACKHOLE), [state]), () => (!state ? state : state.loading ? NONE : state.value));
7
- return state ?? undefined;
8
- }
package/state/State.d.ts DELETED
@@ -1,42 +0,0 @@
1
- import { DeferredSequence } from "../sequence/DeferredSequence.js";
2
- import { NONE } from "../util/constants.js";
3
- /** Any `State` instance. */
4
- export type AnyState = State<any>;
5
- /**
6
- * Stream that retains its most recent value
7
- * - Current value can be read at `state.value` and `state.data`
8
- * - States also send their most-recent value to any new subscribers immediately when a new subscriber is added.
9
- * - States can also be in a loading state where they do not have a current value.
10
- *
11
- * @param initial The initial value for the state, a `Promise` that resolves to the initial value, a source `Subscribable` to subscribe to, or another `State` instance to take the initial value from and subscribe to.
12
- * - To set the state to be loading, use the `NONE` constant or a `Promise` value.
13
- * - To set the state to an explicit value, use that value or another `State` instance with a value.
14
- * */
15
- export declare class State<T> implements AsyncIterable<T> {
16
- /** Deferred sequence this state uses to issue values as they change. */
17
- readonly next: DeferredSequence<T>;
18
- /** Current value of the state (or throw a promise that resolves when this state receives its next value or error). */
19
- get value(): T;
20
- set value(value: T);
21
- private _value;
22
- /** Is there a current value, or is it still loading. */
23
- get loading(): boolean;
24
- /** Time (in milliseconds) this state was last updated with a new value, or `undefined` if this state is currently loading. */
25
- get time(): number | undefined;
26
- private _time;
27
- /** How old this state's value is (in milliseconds). */
28
- get age(): number;
29
- /** Current error of this state (or `undefined` if there is no reason). */
30
- get reason(): unknown;
31
- set reason(reason: Error | unknown);
32
- private _reason;
33
- /** State is initiated with an initial state. */
34
- constructor(value: T | typeof NONE, time?: number);
35
- /** Set the value of the state. */
36
- set(next: T): void;
37
- /** Set the value of the state as values are pulled from a sequence. */
38
- through(sequence: AsyncIterable<T>): AsyncIterable<T>;
39
- [Symbol.asyncIterator](): AsyncGenerator<T, void, void>;
40
- }
41
- /** Is an unknown value a `State` instance. */
42
- export declare const isState: <T extends AnyState>(value: unknown) => value is T;
package/state/index.d.ts DELETED
@@ -1,5 +0,0 @@
1
- export * from "./State.js";
2
- export * from "./ArrayState.js";
3
- export * from "./BooleanState.js";
4
- export * from "./DataState.js";
5
- export * from "./DictionaryState.js";
package/state/index.js DELETED
@@ -1,5 +0,0 @@
1
- export * from "./State.js";
2
- export * from "./ArrayState.js";
3
- export * from "./BooleanState.js";
4
- export * from "./DataState.js";
5
- export * from "./DictionaryState.js";