@kuindji/reactive 1.0.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 +985 -0
- package/dist/action.d.ts +49 -0
- package/dist/action.js +77 -0
- package/dist/actionBus.d.ts +43 -0
- package/dist/actionBus.js +81 -0
- package/dist/actionMap.d.ts +23 -0
- package/dist/actionMap.js +26 -0
- package/dist/event.d.ts +143 -0
- package/dist/event.js +538 -0
- package/dist/eventBus.d.ts +115 -0
- package/dist/eventBus.js +508 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +21 -0
- package/dist/lib/asyncCall.d.ts +1 -0
- package/dist/lib/asyncCall.js +17 -0
- package/dist/lib/listenerSorter.d.ts +5 -0
- package/dist/lib/listenerSorter.js +13 -0
- package/dist/lib/tagsIntersect.d.ts +1 -0
- package/dist/lib/tagsIntersect.js +11 -0
- package/dist/lib/types.d.ts +49 -0
- package/dist/lib/types.js +37 -0
- package/dist/react/ErrorBoundary.d.ts +10 -0
- package/dist/react/ErrorBoundary.js +25 -0
- package/dist/react/useAction.d.ts +21 -0
- package/dist/react/useAction.js +66 -0
- package/dist/react/useActionBus.d.ts +38 -0
- package/dist/react/useActionBus.js +44 -0
- package/dist/react/useActionMap.d.ts +23 -0
- package/dist/react/useActionMap.js +25 -0
- package/dist/react/useEvent.d.ts +47 -0
- package/dist/react/useEvent.js +66 -0
- package/dist/react/useEventBus.d.ts +117 -0
- package/dist/react/useEventBus.js +66 -0
- package/dist/react/useListenToAction.d.ts +3 -0
- package/dist/react/useListenToAction.js +38 -0
- package/dist/react/useListenToEvent.d.ts +4 -0
- package/dist/react/useListenToEvent.js +34 -0
- package/dist/react/useListenToEventBus.d.ts +5 -0
- package/dist/react/useListenToEventBus.js +37 -0
- package/dist/react/useStore.d.ts +51 -0
- package/dist/react/useStore.js +30 -0
- package/dist/react/useStoreState.d.ts +3 -0
- package/dist/react/useStoreState.js +32 -0
- package/dist/react.d.ts +10 -0
- package/dist/react.js +26 -0
- package/dist/store.d.ts +54 -0
- package/dist/store.js +193 -0
- package/package.json +70 -0
- package/src/index.ts +5 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useListenToAction = useListenToAction;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
function useListenToAction(action, listener, errorListener) {
|
|
6
|
+
const listenerRef = (0, react_1.useRef)(listener);
|
|
7
|
+
const actionRef = (0, react_1.useRef)(action);
|
|
8
|
+
const errorListenerRef = (0, react_1.useRef)(errorListener);
|
|
9
|
+
listenerRef.current = listener;
|
|
10
|
+
const genericHandler = (0, react_1.useCallback)((arg) => {
|
|
11
|
+
var _a;
|
|
12
|
+
(_a = listenerRef.current) === null || _a === void 0 ? void 0 : _a.call(listenerRef, arg);
|
|
13
|
+
}, []);
|
|
14
|
+
(0, react_1.useEffect)(() => {
|
|
15
|
+
return () => {
|
|
16
|
+
actionRef.current.removeListener(genericHandler);
|
|
17
|
+
if (errorListenerRef.current) {
|
|
18
|
+
actionRef.current.removeErrorListener(errorListenerRef.current);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}, []);
|
|
22
|
+
(0, react_1.useEffect)(() => {
|
|
23
|
+
actionRef.current.removeListener(genericHandler);
|
|
24
|
+
actionRef.current = action;
|
|
25
|
+
actionRef.current.addListener(genericHandler);
|
|
26
|
+
}, [action]);
|
|
27
|
+
(0, react_1.useEffect)(() => {
|
|
28
|
+
if (errorListenerRef.current !== errorListener) {
|
|
29
|
+
if (errorListenerRef.current) {
|
|
30
|
+
actionRef.current.removeErrorListener(errorListenerRef.current);
|
|
31
|
+
}
|
|
32
|
+
errorListenerRef.current = errorListener;
|
|
33
|
+
if (errorListener) {
|
|
34
|
+
actionRef.current.addErrorListener(errorListener);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}, [errorListener]);
|
|
38
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BaseEvent, ListenerOptions } from "../../src/event";
|
|
2
|
+
import type { ErrorListenerSignature } from "../lib/types";
|
|
3
|
+
export type { BaseEvent, ErrorListenerSignature, ListenerOptions };
|
|
4
|
+
export declare function useListenToEvent<TEvent extends BaseEvent, TListenerSignature extends TEvent["__type"]["signature"], TErrorListenerSignature extends TEvent["__type"]["errorListenerSignature"]>(event: TEvent, listener: TListenerSignature, options?: ListenerOptions, errorListener?: TErrorListenerSignature): void;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useListenToEvent = useListenToEvent;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
function useListenToEvent(event, listener, options, errorListener) {
|
|
6
|
+
const listenerRef = (0, react_1.useRef)(listener);
|
|
7
|
+
const eventRef = (0, react_1.useRef)(event);
|
|
8
|
+
const errorListenerRef = (0, react_1.useRef)(errorListener);
|
|
9
|
+
listenerRef.current = listener;
|
|
10
|
+
const genericHandler = (0, react_1.useCallback)((...args) => {
|
|
11
|
+
return listenerRef.current(...args);
|
|
12
|
+
}, []);
|
|
13
|
+
(0, react_1.useEffect)(() => {
|
|
14
|
+
return () => {
|
|
15
|
+
eventRef.current.removeListener(genericHandler);
|
|
16
|
+
};
|
|
17
|
+
}, []);
|
|
18
|
+
(0, react_1.useEffect)(() => {
|
|
19
|
+
eventRef.current.removeListener(genericHandler);
|
|
20
|
+
eventRef.current = event;
|
|
21
|
+
eventRef.current.addListener(genericHandler, options);
|
|
22
|
+
}, [event]);
|
|
23
|
+
(0, react_1.useEffect)(() => {
|
|
24
|
+
if (errorListenerRef.current !== errorListener) {
|
|
25
|
+
if (errorListenerRef.current) {
|
|
26
|
+
eventRef.current.removeErrorListener(errorListenerRef.current);
|
|
27
|
+
}
|
|
28
|
+
errorListenerRef.current = errorListener;
|
|
29
|
+
if (errorListener) {
|
|
30
|
+
eventRef.current.addErrorListener(errorListener);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}, [errorListener]);
|
|
34
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { BaseEventBus } from "../../src/eventBus";
|
|
2
|
+
import type { ErrorListenerSignature, KeyOf } from "../../src/lib/types";
|
|
3
|
+
import type { ListenerOptions } from "../event";
|
|
4
|
+
export type { BaseEventBus, ErrorListenerSignature, ListenerOptions };
|
|
5
|
+
export declare function useListenToEventBus<TEventBus extends BaseEventBus, TKey extends KeyOf<TEventBus["__type"]["eventSignatures"]>, TListener extends TEventBus["__type"]["eventSignatures"][TKey]>(eventBus: TEventBus, eventName: TKey, listener: TListener, options?: ListenerOptions, errorListener?: ErrorListenerSignature<any[]>): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useListenToEventBus = useListenToEventBus;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
function useListenToEventBus(eventBus, eventName, listener, options, errorListener) {
|
|
6
|
+
const listenerRef = (0, react_1.useRef)(listener);
|
|
7
|
+
const eventBusRef = (0, react_1.useRef)(eventBus);
|
|
8
|
+
const errorListenerRef = (0, react_1.useRef)(errorListener);
|
|
9
|
+
listenerRef.current = listener;
|
|
10
|
+
const genericHandler = (0, react_1.useCallback)((...args) => {
|
|
11
|
+
return listenerRef.current(...args);
|
|
12
|
+
}, []);
|
|
13
|
+
(0, react_1.useEffect)(() => {
|
|
14
|
+
return () => {
|
|
15
|
+
eventBusRef.current.removeListener(eventName, genericHandler);
|
|
16
|
+
if (errorListenerRef.current) {
|
|
17
|
+
eventBusRef.current.removeErrorListener(errorListenerRef.current);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}, []);
|
|
21
|
+
(0, react_1.useEffect)(() => {
|
|
22
|
+
eventBusRef.current.removeListener(eventName, genericHandler);
|
|
23
|
+
eventBusRef.current = eventBus;
|
|
24
|
+
eventBusRef.current.addListener(eventName, genericHandler, options);
|
|
25
|
+
}, [eventBus]);
|
|
26
|
+
(0, react_1.useEffect)(() => {
|
|
27
|
+
if (errorListenerRef.current !== errorListener) {
|
|
28
|
+
if (errorListenerRef.current) {
|
|
29
|
+
eventBusRef.current.removeErrorListener(errorListenerRef.current);
|
|
30
|
+
}
|
|
31
|
+
errorListenerRef.current = errorListener;
|
|
32
|
+
if (errorListener) {
|
|
33
|
+
eventBusRef.current.addErrorListener(errorListener);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}, [errorListener]);
|
|
37
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { BasePropMap, BeforeChangeEventName, ChangeEventName, ErrorEventName, ResetEventName, StoreDefinitionHelper } from "../store";
|
|
2
|
+
export type { BasePropMap, BeforeChangeEventName, ChangeEventName, ErrorEventName, ResetEventName, StoreDefinitionHelper, };
|
|
3
|
+
export declare function useStore<PropMap extends BasePropMap, Store extends StoreDefinitionHelper<PropMap> = StoreDefinitionHelper<PropMap>, Config extends {
|
|
4
|
+
onChange?: Partial<Store["changeEvents"]>;
|
|
5
|
+
pipes?: Partial<Store["pipeEvents"]>;
|
|
6
|
+
control?: Partial<Store["controlEvents"]>;
|
|
7
|
+
} = {
|
|
8
|
+
onChange?: Partial<Store["changeEvents"]>;
|
|
9
|
+
pipes?: Partial<Store["pipeEvents"]>;
|
|
10
|
+
control?: Partial<Store["controlEvents"]>;
|
|
11
|
+
}>(initialData?: Partial<PropMap>, config?: Config): import("..").ApiType<StoreDefinitionHelper<PropMap>, {
|
|
12
|
+
readonly set: {
|
|
13
|
+
<K extends import("..").KeyOf<PropMap>>(key: K, value: PropMap[K]): void;
|
|
14
|
+
(key: Partial<PropMap>): void;
|
|
15
|
+
};
|
|
16
|
+
readonly get: <K extends import("..").KeyOf<PropMap> | import("..").KeyOf<PropMap>[]>(key: K) => K extends import("..").KeyOf<PropMap> ? PropMap[K] : K extends import("..").KeyOf<PropMap>[] ? { [AK in K[number]]: PropMap[AK]; } : never;
|
|
17
|
+
readonly getData: () => PropMap;
|
|
18
|
+
readonly batch: (fn: () => void) => void;
|
|
19
|
+
readonly asyncSet: {
|
|
20
|
+
<K extends import("..").KeyOf<PropMap>>(key: K, value: PropMap[K]): void;
|
|
21
|
+
(key: Partial<PropMap>): void;
|
|
22
|
+
};
|
|
23
|
+
readonly isEmpty: () => boolean;
|
|
24
|
+
readonly reset: () => void;
|
|
25
|
+
readonly onChange: <K extends import("..").KeyOf<import("..").GetEventsMap<{ [K_1 in import("..").KeyOf<PropMap>]: (value: PropMap[K_1], previousValue?: PropMap[K_1] | undefined) => void; }>>, H extends import("..").GetEventsMap<{ [K_1 in import("..").KeyOf<PropMap>]: (value: PropMap[K_1], previousValue?: PropMap[K_1] | undefined) => void; }>[K]["signature"]>(name: K, handler: H, options?: import("..").ListenerOptions) => void;
|
|
26
|
+
readonly removeOnChange: <K extends import("..").KeyOf<import("..").GetEventsMap<{ [K_1 in import("..").KeyOf<PropMap>]: (value: PropMap[K_1], previousValue?: PropMap[K_1] | undefined) => void; }>>, H extends import("..").GetEventsMap<{ [K_1 in import("..").KeyOf<PropMap>]: (value: PropMap[K_1], previousValue?: PropMap[K_1] | undefined) => void; }>[K]["signature"]>(name: K, handler: H, context?: object | null, tag?: string | null) => void;
|
|
27
|
+
readonly pipe: <K extends import("..").KeyOf<import("..").GetEventsMap<{ [K_1 in import("..").KeyOf<PropMap>]: (value: PropMap[K_1]) => PropMap[K_1]; }>>, H extends import("..").GetEventsMap<{ [K_1 in import("..").KeyOf<PropMap>]: (value: PropMap[K_1]) => PropMap[K_1]; }>[K]["signature"]>(name: K, handler: H, options?: import("..").ListenerOptions) => void;
|
|
28
|
+
readonly removePipe: <K extends import("..").KeyOf<import("..").GetEventsMap<{ [K_1 in import("..").KeyOf<PropMap>]: (value: PropMap[K_1]) => PropMap[K_1]; }>>, H extends import("..").GetEventsMap<{ [K_1 in import("..").KeyOf<PropMap>]: (value: PropMap[K_1]) => PropMap[K_1]; }>[K]["signature"]>(name: K, handler: H, context?: object | null, tag?: string | null) => void;
|
|
29
|
+
readonly control: <K extends import("..").KeyOf<import("..").GetEventsMap<{
|
|
30
|
+
beforeChange: <K_1 extends import("..").KeyOf<PropMap>, V extends PropMap[K_1]>(name: K_1, value: V) => boolean;
|
|
31
|
+
change: (names: import("..").KeyOf<PropMap>[]) => void;
|
|
32
|
+
reset: () => void;
|
|
33
|
+
error: import("..").ErrorListenerSignature<any[]>;
|
|
34
|
+
}>>, H extends import("..").GetEventsMap<{
|
|
35
|
+
beforeChange: <K_1 extends import("..").KeyOf<PropMap>, V extends PropMap[K_1]>(name: K_1, value: V) => boolean;
|
|
36
|
+
change: (names: import("..").KeyOf<PropMap>[]) => void;
|
|
37
|
+
reset: () => void;
|
|
38
|
+
error: import("..").ErrorListenerSignature<any[]>;
|
|
39
|
+
}>[K]["signature"]>(name: K, handler: H, options?: import("..").ListenerOptions) => void;
|
|
40
|
+
readonly removeControl: <K extends import("..").KeyOf<import("..").GetEventsMap<{
|
|
41
|
+
beforeChange: <K_1 extends import("..").KeyOf<PropMap>, V extends PropMap[K_1]>(name: K_1, value: V) => boolean;
|
|
42
|
+
change: (names: import("..").KeyOf<PropMap>[]) => void;
|
|
43
|
+
reset: () => void;
|
|
44
|
+
error: import("..").ErrorListenerSignature<any[]>;
|
|
45
|
+
}>>, H extends import("..").GetEventsMap<{
|
|
46
|
+
beforeChange: <K_1 extends import("..").KeyOf<PropMap>, V extends PropMap[K_1]>(name: K_1, value: V) => boolean;
|
|
47
|
+
change: (names: import("..").KeyOf<PropMap>[]) => void;
|
|
48
|
+
reset: () => void;
|
|
49
|
+
error: import("..").ErrorListenerSignature<any[]>;
|
|
50
|
+
}>[K]["signature"]>(name: K, handler: H, context?: object | null, tag?: string | null) => void;
|
|
51
|
+
}>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useStore = useStore;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const store_1 = require("../store");
|
|
6
|
+
function useStore(initialData = {}, config) {
|
|
7
|
+
const store = (0, react_1.useMemo)(() => {
|
|
8
|
+
const store = (0, store_1.createStore)(initialData);
|
|
9
|
+
if (config === null || config === void 0 ? void 0 : config.onChange) {
|
|
10
|
+
for (const key in config.onChange) {
|
|
11
|
+
store.onChange(key, config.onChange[key]);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
if (config === null || config === void 0 ? void 0 : config.pipes) {
|
|
15
|
+
for (const key in config.pipes) {
|
|
16
|
+
// @ts-expect-error
|
|
17
|
+
store.pipe(key, config.pipes[key]);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (config === null || config === void 0 ? void 0 : config.control) {
|
|
21
|
+
for (const key in config.control) {
|
|
22
|
+
store.control(
|
|
23
|
+
// @ts-expect-error
|
|
24
|
+
key, config.control[key]);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return store;
|
|
28
|
+
}, []);
|
|
29
|
+
return store;
|
|
30
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { KeyOf } from "../lib/types";
|
|
2
|
+
import { BaseStore } from "../store";
|
|
3
|
+
export declare function useStoreState<TStore extends BaseStore, TKey extends KeyOf<TStore["__type"]["propTypes"]>>(store: TStore, key: TKey): readonly [TStore["__type"]["propTypes"][TKey], (value: TStore["__type"]["propTypes"][TKey] | ((previousValue?: TStore["__type"]["propTypes"][TKey] | undefined) => TStore["__type"]["propTypes"][TKey])) => void];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useStoreState = useStoreState;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
function useStoreState(store, key) {
|
|
6
|
+
const [value, setValue] = (0, react_1.useState)(store.get(key));
|
|
7
|
+
const storeRef = (0, react_1.useRef)(store);
|
|
8
|
+
const keyRef = (0, react_1.useRef)(key);
|
|
9
|
+
const onChange = (0, react_1.useCallback)((value) => {
|
|
10
|
+
setValue(value);
|
|
11
|
+
}, []);
|
|
12
|
+
const setter = (0, react_1.useCallback)((value) => {
|
|
13
|
+
if (typeof value === "function") {
|
|
14
|
+
storeRef.current.set(keyRef.current, value(storeRef.current.get(keyRef.current)));
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
storeRef.current.set(keyRef.current, value);
|
|
18
|
+
}
|
|
19
|
+
}, []);
|
|
20
|
+
(0, react_1.useEffect)(() => {
|
|
21
|
+
return () => {
|
|
22
|
+
storeRef.current.onChange(keyRef.current, onChange);
|
|
23
|
+
};
|
|
24
|
+
}, []);
|
|
25
|
+
(0, react_1.useEffect)(() => {
|
|
26
|
+
storeRef.current.removeOnChange(keyRef.current, onChange);
|
|
27
|
+
storeRef.current = store;
|
|
28
|
+
keyRef.current = key;
|
|
29
|
+
storeRef.current.onChange(keyRef.current, onChange);
|
|
30
|
+
}, [store, key]);
|
|
31
|
+
return [value, setter];
|
|
32
|
+
}
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./react/useAction";
|
|
2
|
+
export * from "./react/useActionBus";
|
|
3
|
+
export * from "./react/useActionMap";
|
|
4
|
+
export * from "./react/useEvent";
|
|
5
|
+
export * from "./react/useEventBus";
|
|
6
|
+
export * from "./react/useListenToAction";
|
|
7
|
+
export * from "./react/useListenToEvent";
|
|
8
|
+
export * from "./react/useListenToEventBus";
|
|
9
|
+
export * from "./react/useStore";
|
|
10
|
+
export * from "./react/useStoreState";
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./react/useAction"), exports);
|
|
18
|
+
__exportStar(require("./react/useActionBus"), exports);
|
|
19
|
+
__exportStar(require("./react/useActionMap"), exports);
|
|
20
|
+
__exportStar(require("./react/useEvent"), exports);
|
|
21
|
+
__exportStar(require("./react/useEventBus"), exports);
|
|
22
|
+
__exportStar(require("./react/useListenToAction"), exports);
|
|
23
|
+
__exportStar(require("./react/useListenToEvent"), exports);
|
|
24
|
+
__exportStar(require("./react/useListenToEventBus"), exports);
|
|
25
|
+
__exportStar(require("./react/useStore"), exports);
|
|
26
|
+
__exportStar(require("./react/useStoreState"), exports);
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { EventBusDefinitionHelper } from "./eventBus";
|
|
2
|
+
import type { ApiType, ErrorListenerSignature, KeyOf, MapKey } from "./lib/types";
|
|
3
|
+
export interface BasePropMap {
|
|
4
|
+
[key: MapKey]: any;
|
|
5
|
+
}
|
|
6
|
+
export declare const BeforeChangeEventName = "beforeChange";
|
|
7
|
+
export declare const ChangeEventName = "change";
|
|
8
|
+
export declare const ResetEventName = "reset";
|
|
9
|
+
export declare const ErrorEventName = "error";
|
|
10
|
+
type StoreControlEvents<PropMap extends BasePropMap> = {
|
|
11
|
+
[BeforeChangeEventName]: <K extends KeyOf<PropMap>, V extends PropMap[K]>(name: K, value: V) => boolean;
|
|
12
|
+
[ChangeEventName]: (names: KeyOf<PropMap>[]) => void;
|
|
13
|
+
[ResetEventName]: () => void;
|
|
14
|
+
[ErrorEventName]: ErrorListenerSignature<any[]>;
|
|
15
|
+
};
|
|
16
|
+
type StoreChangeEvents<PropMap extends BasePropMap> = {
|
|
17
|
+
[K in KeyOf<PropMap>]: (value: PropMap[K], previousValue?: PropMap[K] | undefined) => void;
|
|
18
|
+
};
|
|
19
|
+
type StorePipeEvents<PropMap extends BasePropMap> = {
|
|
20
|
+
[K in KeyOf<PropMap>]: (value: PropMap[K]) => PropMap[K];
|
|
21
|
+
};
|
|
22
|
+
export type StoreDefinitionHelper<PropMap extends BasePropMap> = {
|
|
23
|
+
propTypes: PropMap;
|
|
24
|
+
controlEvents: StoreControlEvents<PropMap>;
|
|
25
|
+
changeEvents: StoreChangeEvents<PropMap>;
|
|
26
|
+
pipeEvents: StorePipeEvents<PropMap>;
|
|
27
|
+
changeEventBus: EventBusDefinitionHelper<StoreChangeEvents<PropMap>>;
|
|
28
|
+
pipeEventBus: EventBusDefinitionHelper<StorePipeEvents<PropMap>>;
|
|
29
|
+
controlEventBus: EventBusDefinitionHelper<StoreControlEvents<PropMap>>;
|
|
30
|
+
};
|
|
31
|
+
export declare function createStore<PropMap extends BasePropMap = BasePropMap>(initialData?: Partial<PropMap>): ApiType<StoreDefinitionHelper<PropMap>, {
|
|
32
|
+
readonly set: {
|
|
33
|
+
<K extends KeyOf<PropMap>>(key: K, value: PropMap[K]): void;
|
|
34
|
+
(key: Partial<PropMap>): void;
|
|
35
|
+
};
|
|
36
|
+
readonly get: <K extends (KeyOf<PropMap>) | Array<KeyOf<PropMap>>>(key: K) => K extends KeyOf<PropMap> ? PropMap[K] : K extends KeyOf<PropMap>[] ? { [AK in K[number]]: PropMap[AK]; } : never;
|
|
37
|
+
readonly getData: () => PropMap;
|
|
38
|
+
readonly batch: (fn: () => void) => void;
|
|
39
|
+
readonly asyncSet: {
|
|
40
|
+
<K extends KeyOf<PropMap>>(key: K, value: PropMap[K]): void;
|
|
41
|
+
(key: Partial<PropMap>): void;
|
|
42
|
+
};
|
|
43
|
+
readonly isEmpty: () => boolean;
|
|
44
|
+
readonly reset: () => void;
|
|
45
|
+
readonly onChange: <K extends KeyOf<import("./eventBus").GetEventsMap<StoreChangeEvents<PropMap>>>, H extends import("./eventBus").GetEventsMap<StoreChangeEvents<PropMap>>[K]["signature"]>(name: K, handler: H, options?: import("./event").ListenerOptions) => void;
|
|
46
|
+
readonly removeOnChange: <K extends KeyOf<import("./eventBus").GetEventsMap<StoreChangeEvents<PropMap>>>, H extends import("./eventBus").GetEventsMap<StoreChangeEvents<PropMap>>[K]["signature"]>(name: K, handler: H, context?: object | null, tag?: string | null) => void;
|
|
47
|
+
readonly pipe: <K extends KeyOf<import("./eventBus").GetEventsMap<StorePipeEvents<PropMap>>>, H extends import("./eventBus").GetEventsMap<StorePipeEvents<PropMap>>[K]["signature"]>(name: K, handler: H, options?: import("./event").ListenerOptions) => void;
|
|
48
|
+
readonly removePipe: <K extends KeyOf<import("./eventBus").GetEventsMap<StorePipeEvents<PropMap>>>, H extends import("./eventBus").GetEventsMap<StorePipeEvents<PropMap>>[K]["signature"]>(name: K, handler: H, context?: object | null, tag?: string | null) => void;
|
|
49
|
+
readonly control: <K extends KeyOf<import("./eventBus").GetEventsMap<StoreControlEvents<PropMap>>>, H extends import("./eventBus").GetEventsMap<StoreControlEvents<PropMap>>[K]["signature"]>(name: K, handler: H, options?: import("./event").ListenerOptions) => void;
|
|
50
|
+
readonly removeControl: <K extends KeyOf<import("./eventBus").GetEventsMap<StoreControlEvents<PropMap>>>, H extends import("./eventBus").GetEventsMap<StoreControlEvents<PropMap>>[K]["signature"]>(name: K, handler: H, context?: object | null, tag?: string | null) => void;
|
|
51
|
+
}>;
|
|
52
|
+
export type BaseStoreDefinition = StoreDefinitionHelper<BasePropMap>;
|
|
53
|
+
export type BaseStore = ReturnType<typeof createStore<any>>;
|
|
54
|
+
export {};
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ErrorEventName = exports.ResetEventName = exports.ChangeEventName = exports.BeforeChangeEventName = void 0;
|
|
4
|
+
exports.createStore = createStore;
|
|
5
|
+
const eventBus_1 = require("./eventBus");
|
|
6
|
+
exports.BeforeChangeEventName = "beforeChange";
|
|
7
|
+
exports.ChangeEventName = "change";
|
|
8
|
+
exports.ResetEventName = "reset";
|
|
9
|
+
exports.ErrorEventName = "error";
|
|
10
|
+
function createStore(initialData = {}) {
|
|
11
|
+
const data = new Map(Object.entries(initialData));
|
|
12
|
+
const changes = (0, eventBus_1.createEventBus)();
|
|
13
|
+
const pipe = (0, eventBus_1.createEventBus)();
|
|
14
|
+
const control = (0, eventBus_1.createEventBus)();
|
|
15
|
+
const _set = (name, value, triggerChange = true) => {
|
|
16
|
+
var _a, _b, _c;
|
|
17
|
+
const prev = data.get(name);
|
|
18
|
+
if (prev !== value) {
|
|
19
|
+
if (control.firstNonEmpty(exports.BeforeChangeEventName, name, value)
|
|
20
|
+
=== false) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const pipeArgs = [value];
|
|
24
|
+
let newValue;
|
|
25
|
+
try {
|
|
26
|
+
newValue = pipe.pipe(name, ...pipeArgs);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
control.trigger(exports.ErrorEventName, {
|
|
30
|
+
error: error instanceof Error
|
|
31
|
+
? error
|
|
32
|
+
: new Error(String(error)),
|
|
33
|
+
args: pipeArgs,
|
|
34
|
+
type: "store-pipe",
|
|
35
|
+
name,
|
|
36
|
+
});
|
|
37
|
+
if ((_a = control.get(exports.ErrorEventName)) === null || _a === void 0 ? void 0 : _a.hasListener()) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
if (newValue !== undefined) {
|
|
43
|
+
value = newValue;
|
|
44
|
+
}
|
|
45
|
+
data.set(name, value);
|
|
46
|
+
const changeArgs = [
|
|
47
|
+
value,
|
|
48
|
+
prev,
|
|
49
|
+
];
|
|
50
|
+
try {
|
|
51
|
+
changes.trigger(name, ...changeArgs);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
control.trigger(exports.ErrorEventName, {
|
|
55
|
+
error: error instanceof Error
|
|
56
|
+
? error
|
|
57
|
+
: new Error(String(error)),
|
|
58
|
+
args: changeArgs,
|
|
59
|
+
type: "store-change",
|
|
60
|
+
name,
|
|
61
|
+
});
|
|
62
|
+
if ((_b = control.get(exports.ErrorEventName)) === null || _b === void 0 ? void 0 : _b.hasListener()) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
if (triggerChange) {
|
|
68
|
+
try {
|
|
69
|
+
control.trigger(exports.ChangeEventName, [name]);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
control.trigger(exports.ErrorEventName, {
|
|
73
|
+
error: error instanceof Error
|
|
74
|
+
? error
|
|
75
|
+
: new Error(String(error)),
|
|
76
|
+
args: [name],
|
|
77
|
+
type: "store-control",
|
|
78
|
+
name,
|
|
79
|
+
});
|
|
80
|
+
if ((_c = control.get(exports.ErrorEventName)) === null || _c === void 0 ? void 0 : _c.hasListener()) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
};
|
|
90
|
+
function asyncSet(name, value) {
|
|
91
|
+
setTimeout(() => {
|
|
92
|
+
if ((typeof name === "string")
|
|
93
|
+
&& value !== undefined) {
|
|
94
|
+
set(name, value);
|
|
95
|
+
}
|
|
96
|
+
else if (typeof name === "object") {
|
|
97
|
+
set(name);
|
|
98
|
+
}
|
|
99
|
+
}, 0);
|
|
100
|
+
}
|
|
101
|
+
function set(name, value) {
|
|
102
|
+
if ((typeof name === "string")
|
|
103
|
+
&& value !== undefined) {
|
|
104
|
+
_set(name, value);
|
|
105
|
+
}
|
|
106
|
+
else if (typeof name === "object") {
|
|
107
|
+
const changedKeys = [];
|
|
108
|
+
Object.entries(name).forEach(([k, v]) => {
|
|
109
|
+
if (_set(k, v, false)) {
|
|
110
|
+
changedKeys.push(k);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
control.trigger(exports.ChangeEventName, changedKeys);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
throw new Error(`Invalid key: ${String(name)}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const get = (key) => {
|
|
120
|
+
if (typeof key === "string") {
|
|
121
|
+
return data.get(key);
|
|
122
|
+
}
|
|
123
|
+
else if (Array.isArray(key)) {
|
|
124
|
+
// return object with given keys
|
|
125
|
+
return key.reduce((acc, k) => {
|
|
126
|
+
acc[k] = data.get(k);
|
|
127
|
+
return acc;
|
|
128
|
+
}, {});
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
throw new Error(`Invalid key: ${String(key)}`);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const isEmpty = () => {
|
|
135
|
+
if (data.size === 0) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
return Array.from(data.values()).every((value) => value === null || value === undefined);
|
|
139
|
+
};
|
|
140
|
+
const getData = () => {
|
|
141
|
+
return Object.fromEntries(data.entries());
|
|
142
|
+
};
|
|
143
|
+
const batch = (fn) => {
|
|
144
|
+
const allChangedKeys = [];
|
|
145
|
+
const log = [];
|
|
146
|
+
const controlInterceptor = function (name, [changedKeys]) {
|
|
147
|
+
if (name === exports.ChangeEventName) {
|
|
148
|
+
allChangedKeys.push(...changedKeys);
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
return true;
|
|
152
|
+
};
|
|
153
|
+
const changeInterceptor = function (propName, args) {
|
|
154
|
+
log.push([propName, args[0], args[1]]);
|
|
155
|
+
return false;
|
|
156
|
+
};
|
|
157
|
+
changes.intercept(changeInterceptor);
|
|
158
|
+
control.intercept(controlInterceptor);
|
|
159
|
+
fn();
|
|
160
|
+
control.stopIntercepting();
|
|
161
|
+
changes.stopIntercepting();
|
|
162
|
+
for (const [propName, value, prev] of log) {
|
|
163
|
+
const changeArgs = [
|
|
164
|
+
value,
|
|
165
|
+
prev,
|
|
166
|
+
];
|
|
167
|
+
changes.trigger(propName, ...changeArgs);
|
|
168
|
+
}
|
|
169
|
+
if (allChangedKeys.length > 0) {
|
|
170
|
+
control.trigger(exports.ChangeEventName, allChangedKeys);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
const reset = () => {
|
|
174
|
+
data.clear();
|
|
175
|
+
control.trigger(exports.ResetEventName);
|
|
176
|
+
};
|
|
177
|
+
const api = {
|
|
178
|
+
set,
|
|
179
|
+
get,
|
|
180
|
+
getData,
|
|
181
|
+
batch,
|
|
182
|
+
asyncSet,
|
|
183
|
+
isEmpty,
|
|
184
|
+
reset,
|
|
185
|
+
onChange: changes.addListener,
|
|
186
|
+
removeOnChange: changes.removeListener,
|
|
187
|
+
pipe: pipe.addListener,
|
|
188
|
+
removePipe: pipe.removeListener,
|
|
189
|
+
control: control.addListener,
|
|
190
|
+
removeControl: control.removeListener,
|
|
191
|
+
};
|
|
192
|
+
return api;
|
|
193
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kuindji/reactive",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A JavaScript/TypeScript utility library for building reactive applications with events, actions, stores, and React hooks",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"events",
|
|
7
|
+
"actions",
|
|
8
|
+
"store",
|
|
9
|
+
"state-management",
|
|
10
|
+
"react-hooks",
|
|
11
|
+
"typescript",
|
|
12
|
+
"event-emitter",
|
|
13
|
+
"observable",
|
|
14
|
+
"async",
|
|
15
|
+
"event-bus",
|
|
16
|
+
"action-bus"
|
|
17
|
+
],
|
|
18
|
+
"homepage": "https://github.com/kuindji/reactive#readme",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/kuindji/reactive/issues"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/kuindji/reactive.git"
|
|
25
|
+
},
|
|
26
|
+
"license": "ISC",
|
|
27
|
+
"author": "Ivan Kuindzhi",
|
|
28
|
+
"type": "commonjs",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"import": "./dist/index.js",
|
|
32
|
+
"require": "./dist/index.js",
|
|
33
|
+
"types": "./dist/index.d.ts"
|
|
34
|
+
},
|
|
35
|
+
"./react": {
|
|
36
|
+
"import": "./dist/react.js",
|
|
37
|
+
"require": "./dist/react.js",
|
|
38
|
+
"types": "./dist/react.d.ts"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"main": "src/index.ts",
|
|
42
|
+
"types": "dist/index.d.ts",
|
|
43
|
+
"directories": {
|
|
44
|
+
"test": "tests"
|
|
45
|
+
},
|
|
46
|
+
"files": [
|
|
47
|
+
"dist/**/*"
|
|
48
|
+
],
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsc -p ./tsconfig-build.json",
|
|
51
|
+
"lint": "bun eslint .",
|
|
52
|
+
"test": "bun test tests/**/*.spec.ts*"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@happy-dom/global-registrator": "^18.0.1",
|
|
56
|
+
"@testing-library/dom": "^10.4.1",
|
|
57
|
+
"@testing-library/jest-dom": "^6.6.4",
|
|
58
|
+
"@testing-library/react": "^16.3.0",
|
|
59
|
+
"@types/bun": "^1.2.19",
|
|
60
|
+
"@types/react": "^19.1.9",
|
|
61
|
+
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
|
62
|
+
"react": "^19.1.1",
|
|
63
|
+
"typescript": "^5",
|
|
64
|
+
"typescript-eslint": "^8.38.0"
|
|
65
|
+
},
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">=16.0.0"
|
|
68
|
+
},
|
|
69
|
+
"sideEffects": false
|
|
70
|
+
}
|