@mpen/react-external-state 0.1.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 +189 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +30 -0
- package/dist/react.d.ts +39 -0
- package/dist/react.js +70 -0
- package/dist/store-B4lfgyM1.d.ts +33 -0
- package/dist/store-DblPx3Yb.js +55 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# @mpen/react-external-state
|
|
2
|
+
|
|
3
|
+
Small external state stores with optional React bindings and localStorage persistence.
|
|
4
|
+
|
|
5
|
+
The base store does not depend on React. Use `@mpen/react-external-state/react` only when you want hooks or context-scoped stores.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
bun add @mpen/react-external-state
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Store
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { createStore } from '@mpen/react-external-state'
|
|
17
|
+
|
|
18
|
+
const counter = createStore({ count: 0 })
|
|
19
|
+
|
|
20
|
+
const unsubscribe = counter.subscribe((state, previousState) => {
|
|
21
|
+
console.log(previousState.count, '->', state.count)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
counter.setState((state) => ({
|
|
25
|
+
count: state.count + 1,
|
|
26
|
+
}))
|
|
27
|
+
|
|
28
|
+
counter.set({ count: 10 })
|
|
29
|
+
|
|
30
|
+
console.log(counter.get())
|
|
31
|
+
|
|
32
|
+
unsubscribe()
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Use `subscribeSelector` when code outside React only cares about part of the state.
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
const unsubscribe = counter.subscribeSelector(
|
|
39
|
+
(state) => state.count,
|
|
40
|
+
(count) => {
|
|
41
|
+
console.log('count changed:', count)
|
|
42
|
+
},
|
|
43
|
+
{ fireImmediately: true },
|
|
44
|
+
)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## React
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import { createReactStore } from '@mpen/react-external-state/react'
|
|
51
|
+
|
|
52
|
+
const session = createReactStore({
|
|
53
|
+
userId: null as string | null,
|
|
54
|
+
theme: 'system' as 'light' | 'dark' | 'system',
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
export function ThemeButton() {
|
|
58
|
+
const theme = session.use((state) => state.theme)
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<button
|
|
62
|
+
type="button"
|
|
63
|
+
onClick={() => {
|
|
64
|
+
session.setState((state) => ({
|
|
65
|
+
...state,
|
|
66
|
+
theme: state.theme === 'dark' ? 'light' : 'dark',
|
|
67
|
+
}))
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
{theme}
|
|
71
|
+
</button>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
session.setState((state) => ({
|
|
76
|
+
...state,
|
|
77
|
+
userId: 'user_123',
|
|
78
|
+
}))
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
You can also use an existing store with `useStore`.
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
import { createStore } from '@mpen/react-external-state'
|
|
85
|
+
import { useStore } from '@mpen/react-external-state/react'
|
|
86
|
+
|
|
87
|
+
const counter = createStore({ count: 0 })
|
|
88
|
+
|
|
89
|
+
export function Counter() {
|
|
90
|
+
const count = useStore(counter, (state) => state.count)
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<button
|
|
94
|
+
type="button"
|
|
95
|
+
onClick={() => counter.setState((state) => ({ count: state.count + 1 }))}
|
|
96
|
+
>
|
|
97
|
+
{count}
|
|
98
|
+
</button>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## localStorage
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { createLocalStorageStore } from '@mpen/react-external-state'
|
|
107
|
+
|
|
108
|
+
const settings = createLocalStorageStore('app.settings', {
|
|
109
|
+
theme: 'system' as 'light' | 'dark' | 'system',
|
|
110
|
+
sidebarOpen: true,
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
settings.setState((state) => ({
|
|
114
|
+
...state,
|
|
115
|
+
sidebarOpen: !state.sidebarOpen,
|
|
116
|
+
}))
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
By default values are serialized with `JSON.stringify` and restored with `JSON.parse`. Storage failures are ignored unless you pass `onError`.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
const settings = createLocalStorageStore(
|
|
123
|
+
'app.settings',
|
|
124
|
+
{ theme: 'system' },
|
|
125
|
+
{
|
|
126
|
+
onError(error, operation) {
|
|
127
|
+
console.warn(`Could not ${operation} settings`, error)
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Context
|
|
134
|
+
|
|
135
|
+
Use `createStoreContext` when state should be scoped to a React subtree instead of global module state.
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
import { createStoreContext } from '@mpen/react-external-state/react'
|
|
139
|
+
|
|
140
|
+
const DraftContext = createStoreContext({
|
|
141
|
+
title: '',
|
|
142
|
+
body: '',
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
export function DraftEditor() {
|
|
146
|
+
return (
|
|
147
|
+
<DraftContext.Provider initialValue={{ title: 'Untitled', body: '' }}>
|
|
148
|
+
<TitleInput />
|
|
149
|
+
<Preview />
|
|
150
|
+
</DraftContext.Provider>
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function TitleInput() {
|
|
155
|
+
const title = DraftContext.use((state) => state.title)
|
|
156
|
+
const setDraft = DraftContext.useSetState()
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<input
|
|
160
|
+
value={title}
|
|
161
|
+
onChange={(event) => {
|
|
162
|
+
setDraft((state) => ({
|
|
163
|
+
...state,
|
|
164
|
+
title: event.currentTarget.value,
|
|
165
|
+
}))
|
|
166
|
+
}}
|
|
167
|
+
/>
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function Preview() {
|
|
172
|
+
const draft = DraftContext.use()
|
|
173
|
+
|
|
174
|
+
return <article>{draft.title}</article>
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## API
|
|
179
|
+
|
|
180
|
+
- `createStore(initialValue, options?)`
|
|
181
|
+
- `createLocalStorageStore(key, initialValue, options?)`
|
|
182
|
+
- `Store`
|
|
183
|
+
- `store.get()` / `store.getSnapshot()`
|
|
184
|
+
- `store.set(valueOrUpdater)` / `store.setState(valueOrUpdater)`
|
|
185
|
+
- `store.subscribe(listener, options?)`
|
|
186
|
+
- `store.subscribeSelector(selector, listener, options?)`
|
|
187
|
+
- `useStore(store, selector?, options?)` from `@mpen/react-external-state/react`
|
|
188
|
+
- `createReactStore(initialValue, options?)` from `@mpen/react-external-state/react`
|
|
189
|
+
- `createStoreContext(defaultValue, options?)` from `@mpen/react-external-state/react`
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { a as Store, c as StoreSnapshot, d as createStore, f as resolveInitializer, i as StateUpdater, l as SubscribeOptions, n as Initializer, o as StoreListener, p as resolveStateUpdater, r as Selector, s as StoreOptions, t as EqualityFn, u as Unsubscribe } from "./store-B4lfgyM1.js";
|
|
2
|
+
|
|
3
|
+
//#region src/local-storage.d.ts
|
|
4
|
+
type StorageLike = Pick<Storage, 'getItem' | 'setItem'>;
|
|
5
|
+
interface LocalStorageStoreOptions<T> extends StoreOptions<T> {
|
|
6
|
+
storage?: StorageLike | null;
|
|
7
|
+
serialize?: (value: T) => string;
|
|
8
|
+
deserialize?: (value: string) => T;
|
|
9
|
+
onError?: (error: unknown, operation: 'read' | 'write') => void;
|
|
10
|
+
}
|
|
11
|
+
declare function createLocalStorageStore<T>(key: string, initialValue: Initializer<T>, options?: LocalStorageStoreOptions<T>): Store<T>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { type EqualityFn, type Initializer, type LocalStorageStoreOptions, type Selector, type StateUpdater, type StorageLike, Store, type StoreListener, type StoreOptions, type StoreSnapshot, type SubscribeOptions, type Unsubscribe, createLocalStorageStore, createStore, resolveInitializer, resolveStateUpdater };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { i as resolveStateUpdater, n as createStore, r as resolveInitializer, t as Store } from "./store-DblPx3Yb.js";
|
|
2
|
+
//#region src/local-storage.ts
|
|
3
|
+
function getDefaultStorage() {
|
|
4
|
+
if (typeof globalThis.localStorage === "undefined") return null;
|
|
5
|
+
return globalThis.localStorage;
|
|
6
|
+
}
|
|
7
|
+
function createLocalStorageStore(key, initialValue, options) {
|
|
8
|
+
const storage = options?.storage === void 0 ? getDefaultStorage() : options.storage;
|
|
9
|
+
const deserialize = options?.deserialize ?? JSON.parse;
|
|
10
|
+
const serialize = options?.serialize ?? JSON.stringify;
|
|
11
|
+
let value = initialValue;
|
|
12
|
+
if (storage !== null) try {
|
|
13
|
+
const storedValue = storage.getItem(key);
|
|
14
|
+
if (storedValue !== null) value = deserialize(storedValue);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
options?.onError?.(error, "read");
|
|
17
|
+
}
|
|
18
|
+
const store = createStore(value, options);
|
|
19
|
+
store.subscribe((nextValue) => {
|
|
20
|
+
if (storage === null) return;
|
|
21
|
+
try {
|
|
22
|
+
storage.setItem(key, serialize(nextValue));
|
|
23
|
+
} catch (error) {
|
|
24
|
+
options?.onError?.(error, "write");
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return store;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { Store, createLocalStorageStore, createStore, resolveInitializer, resolveStateUpdater };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { a as Store, c as StoreSnapshot, i as StateUpdater, n as Initializer, r as Selector, s as StoreOptions, t as EqualityFn } from "./store-B4lfgyM1.js";
|
|
2
|
+
import * as _$react from "react";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/react.d.ts
|
|
7
|
+
interface UseStoreOptions<S> {
|
|
8
|
+
isEqual?: EqualityFn<S>;
|
|
9
|
+
}
|
|
10
|
+
interface ReactStore<T> extends Store<T> {
|
|
11
|
+
use(): T;
|
|
12
|
+
use<S>(selector: Selector<T, S>, options?: UseStoreOptions<S>): S;
|
|
13
|
+
}
|
|
14
|
+
interface StoreProviderProps<T> {
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
initialValue?: StateUpdater<T>;
|
|
17
|
+
}
|
|
18
|
+
declare function useStore<T>(store: StoreSnapshot<T>): T;
|
|
19
|
+
declare function useStore<T, S>(store: StoreSnapshot<T>, selector: Selector<T, S>, options?: UseStoreOptions<S>): S;
|
|
20
|
+
declare function createReactStore<T>(initialValue: Initializer<T>, options?: StoreOptions<T>): ReactStore<T>;
|
|
21
|
+
declare function createStoreContext<T>(defaultValue: Initializer<T>, options?: StoreOptions<T>): {
|
|
22
|
+
Context: _$react.Context<Store<T> | null>;
|
|
23
|
+
Provider: ({
|
|
24
|
+
children,
|
|
25
|
+
initialValue
|
|
26
|
+
}: StoreProviderProps<T>) => _$react_jsx_runtime0.JSX.Element;
|
|
27
|
+
use: {
|
|
28
|
+
(): T;
|
|
29
|
+
<S>(selector: Selector<T, S>, useOptions?: UseStoreOptions<S>): S;
|
|
30
|
+
};
|
|
31
|
+
useStore: {
|
|
32
|
+
(): T;
|
|
33
|
+
<S>(selector: Selector<T, S>, useOptions?: UseStoreOptions<S>): S;
|
|
34
|
+
};
|
|
35
|
+
useStoreInstance: () => Store<T>;
|
|
36
|
+
useSetState: () => (state: StateUpdater<T>) => T;
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
export { ReactStore, StoreProviderProps, UseStoreOptions, createReactStore, createStoreContext, useStore };
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { i as resolveStateUpdater, n as createStore, r as resolveInitializer, t as Store } from "./store-DblPx3Yb.js";
|
|
2
|
+
import { createContext, useContext, useMemo, useState, useSyncExternalStore } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region src/react.tsx
|
|
5
|
+
const identity = (value) => value;
|
|
6
|
+
function createSelectedSnapshot(store, selector, isEqual) {
|
|
7
|
+
let hasSnapshot = false;
|
|
8
|
+
let lastStoreSnapshot;
|
|
9
|
+
let lastSelectedSnapshot;
|
|
10
|
+
return () => {
|
|
11
|
+
const storeSnapshot = store.getSnapshot();
|
|
12
|
+
if (hasSnapshot && Object.is(storeSnapshot, lastStoreSnapshot)) return lastSelectedSnapshot;
|
|
13
|
+
const selectedSnapshot = selector(storeSnapshot);
|
|
14
|
+
if (hasSnapshot && isEqual(lastSelectedSnapshot, selectedSnapshot)) {
|
|
15
|
+
lastStoreSnapshot = storeSnapshot;
|
|
16
|
+
return lastSelectedSnapshot;
|
|
17
|
+
}
|
|
18
|
+
hasSnapshot = true;
|
|
19
|
+
lastStoreSnapshot = storeSnapshot;
|
|
20
|
+
lastSelectedSnapshot = selectedSnapshot;
|
|
21
|
+
return selectedSnapshot;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function useStore(store, selector = identity, options) {
|
|
25
|
+
const getSnapshot = useMemo(() => createSelectedSnapshot(store, selector, options?.isEqual ?? Object.is), [
|
|
26
|
+
store,
|
|
27
|
+
selector,
|
|
28
|
+
options?.isEqual
|
|
29
|
+
]);
|
|
30
|
+
return useSyncExternalStore((onStoreChange) => store.subscribe(onStoreChange), getSnapshot, getSnapshot);
|
|
31
|
+
}
|
|
32
|
+
function createReactStore(initialValue, options) {
|
|
33
|
+
const store = createStore(initialValue, options);
|
|
34
|
+
function useReactStore(selector, useOptions) {
|
|
35
|
+
return useStore(store, selector ?? identity, useOptions);
|
|
36
|
+
}
|
|
37
|
+
store.use = useReactStore;
|
|
38
|
+
return store;
|
|
39
|
+
}
|
|
40
|
+
function createStoreContext(defaultValue, options) {
|
|
41
|
+
const Context = createContext(null);
|
|
42
|
+
function useStoreInstance() {
|
|
43
|
+
const store = useContext(Context);
|
|
44
|
+
if (store === null) throw new Error("Store context is missing a matching Provider");
|
|
45
|
+
return store;
|
|
46
|
+
}
|
|
47
|
+
function Provider({ children, initialValue }) {
|
|
48
|
+
const [store] = useState(() => {
|
|
49
|
+
const resolvedDefaultValue = resolveInitializer(defaultValue);
|
|
50
|
+
return new Store(initialValue === void 0 ? resolvedDefaultValue : resolveStateUpdater(initialValue, resolvedDefaultValue), options);
|
|
51
|
+
});
|
|
52
|
+
return /* @__PURE__ */ jsx(Context.Provider, {
|
|
53
|
+
value: store,
|
|
54
|
+
children
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function useContextStore(selector, useOptions) {
|
|
58
|
+
return useStore(useStoreInstance(), selector ?? identity, useOptions);
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
Context,
|
|
62
|
+
Provider,
|
|
63
|
+
use: useContextStore,
|
|
64
|
+
useStore: useContextStore,
|
|
65
|
+
useStoreInstance,
|
|
66
|
+
useSetState: () => useStoreInstance().setState
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { createReactStore, createStoreContext, useStore };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/store.d.ts
|
|
2
|
+
type EqualityFn<T> = (a: T, b: T) => boolean;
|
|
3
|
+
type Initializer<T> = T | (() => T);
|
|
4
|
+
type Selector<T, S = T> = (value: T) => S;
|
|
5
|
+
type StateUpdater<T> = T | ((previous: T) => T);
|
|
6
|
+
type StoreListener<T> = (value: T, previousValue: T) => void;
|
|
7
|
+
type Unsubscribe = () => void;
|
|
8
|
+
interface StoreSnapshot<T> {
|
|
9
|
+
subscribe(listener: () => void): Unsubscribe;
|
|
10
|
+
getSnapshot(): T;
|
|
11
|
+
}
|
|
12
|
+
interface StoreOptions<T> {
|
|
13
|
+
isEqual?: EqualityFn<T>;
|
|
14
|
+
}
|
|
15
|
+
interface SubscribeOptions<T> {
|
|
16
|
+
fireImmediately?: boolean;
|
|
17
|
+
isEqual?: EqualityFn<T>;
|
|
18
|
+
}
|
|
19
|
+
declare function resolveInitializer<T>(value: Initializer<T>): T;
|
|
20
|
+
declare function resolveStateUpdater<T>(value: StateUpdater<T>, previousValue: T): T;
|
|
21
|
+
declare class Store<T> implements StoreSnapshot<T> {
|
|
22
|
+
#private;
|
|
23
|
+
constructor(initialValue: Initializer<T>, options?: StoreOptions<T>);
|
|
24
|
+
getSnapshot: () => T;
|
|
25
|
+
get: () => T;
|
|
26
|
+
setState: (state: StateUpdater<T>) => T;
|
|
27
|
+
set: (state: StateUpdater<T>) => T;
|
|
28
|
+
subscribe: (listener: StoreListener<T>, options?: SubscribeOptions<T>) => Unsubscribe;
|
|
29
|
+
subscribeSelector: <S>(selector: Selector<T, S>, listener: StoreListener<S>, options?: SubscribeOptions<S>) => Unsubscribe;
|
|
30
|
+
}
|
|
31
|
+
declare function createStore<T>(initialValue: Initializer<T>, options?: StoreOptions<T>): Store<T>;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { Store as a, StoreSnapshot as c, createStore as d, resolveInitializer as f, StateUpdater as i, SubscribeOptions as l, Initializer as n, StoreListener as o, resolveStateUpdater as p, Selector as r, StoreOptions as s, EqualityFn as t, Unsubscribe as u };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
//#region src/store.ts
|
|
2
|
+
const identity = (value) => value;
|
|
3
|
+
function resolveInitializer(value) {
|
|
4
|
+
if (typeof value === "function") return value();
|
|
5
|
+
return value;
|
|
6
|
+
}
|
|
7
|
+
function resolveStateUpdater(value, previousValue) {
|
|
8
|
+
if (typeof value === "function") return value(previousValue);
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
var Store = class {
|
|
12
|
+
#isEqual;
|
|
13
|
+
#listeners = /* @__PURE__ */ new Set();
|
|
14
|
+
#value;
|
|
15
|
+
constructor(initialValue, options) {
|
|
16
|
+
this.#value = resolveInitializer(initialValue);
|
|
17
|
+
this.#isEqual = options?.isEqual ?? Object.is;
|
|
18
|
+
}
|
|
19
|
+
getSnapshot = () => this.#value;
|
|
20
|
+
get = () => this.#value;
|
|
21
|
+
setState = (state) => {
|
|
22
|
+
const previousValue = this.#value;
|
|
23
|
+
const nextValue = resolveStateUpdater(state, previousValue);
|
|
24
|
+
if (this.#isEqual(previousValue, nextValue)) return this.#value;
|
|
25
|
+
this.#value = nextValue;
|
|
26
|
+
for (const listener of [...this.#listeners]) listener(nextValue, previousValue);
|
|
27
|
+
return nextValue;
|
|
28
|
+
};
|
|
29
|
+
set = this.setState;
|
|
30
|
+
subscribe = (listener, options) => {
|
|
31
|
+
return this.subscribeSelector(identity, listener, options);
|
|
32
|
+
};
|
|
33
|
+
subscribeSelector = (selector, listener, options) => {
|
|
34
|
+
const select = selector;
|
|
35
|
+
const isEqual = options?.isEqual ?? Object.is;
|
|
36
|
+
let selectedValue = select(this.#value);
|
|
37
|
+
const storeListener = (value) => {
|
|
38
|
+
const nextSelectedValue = select(value);
|
|
39
|
+
if (isEqual(selectedValue, nextSelectedValue)) return;
|
|
40
|
+
const previousSelectedValue = selectedValue;
|
|
41
|
+
selectedValue = nextSelectedValue;
|
|
42
|
+
listener(nextSelectedValue, previousSelectedValue);
|
|
43
|
+
};
|
|
44
|
+
this.#listeners.add(storeListener);
|
|
45
|
+
if (options?.fireImmediately) listener(selectedValue, selectedValue);
|
|
46
|
+
return () => {
|
|
47
|
+
this.#listeners.delete(storeListener);
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
function createStore(initialValue, options) {
|
|
52
|
+
return new Store(initialValue, options);
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { resolveStateUpdater as i, createStore as n, resolveInitializer as r, Store as t };
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mpen/react-external-state",
|
|
3
|
+
"description": "Small external state stores with React hooks and localStorage persistence.",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/mnpenner/npm-packages.git",
|
|
8
|
+
"directory": "packages/react-external-state"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"author": "Mark Penner <npm@mpen.ca>",
|
|
12
|
+
"packageManager": "bun@1.3.6",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"sideEffects": false,
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"exports": {
|
|
23
|
+
".": "./dist/index.js",
|
|
24
|
+
"./react": "./dist/react.js",
|
|
25
|
+
"./package.json": "./package.json"
|
|
26
|
+
},
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"react": "^19"
|
|
30
|
+
},
|
|
31
|
+
"peerDependenciesMeta": {
|
|
32
|
+
"react": {
|
|
33
|
+
"optional": true
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/bun": "latest",
|
|
38
|
+
"@types/react": "^19",
|
|
39
|
+
"react": "catalog:",
|
|
40
|
+
"tsdown": "catalog:",
|
|
41
|
+
"typescript": "^6.0.2"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "bun run --bun tsdown",
|
|
45
|
+
"test": "bun test",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"_prepublishOnly": "bun run build && bun run test"
|
|
48
|
+
},
|
|
49
|
+
"main": "./dist/index.js",
|
|
50
|
+
"module": "./dist/index.js"
|
|
51
|
+
}
|