@flexsurfer/reflex 0.1.1 → 0.1.3
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 +4 -4
- package/dist/index.cjs +122 -0
- package/dist/index.d.cts +53 -1
- package/dist/index.d.ts +53 -1
- package/dist/{index.js → index.mjs} +112 -0
- package/package.json +12 -6
package/README.md
CHANGED
|
@@ -8,8 +8,9 @@ A reactive, functional state management library that brings the elegance and pow
|
|
|
8
8
|
|
|
9
9
|
> ⚠️ **Development Status**: This library is in active development and not yet ready for production use. Perfect for pet projects, experiments, and learning! The community is warmly invited to contribute to the development and improvement of the library, including optimizations for data comparison at different lifecycle stages.
|
|
10
10
|
|
|
11
|
-
[](https://badge.fury.io/js/@flexsurfer%2Freflex)
|
|
12
11
|
[](https://opensource.org/licenses/MIT)
|
|
12
|
+
[](https://www.npmjs.com/package/@flexsurfer/reflex)
|
|
13
|
+
[](https://github.com/flexsurfer/reflex/pulls)
|
|
13
14
|
|
|
14
15
|
📚 **Want to understand the philosophy behind this approach?** Check out the amazing [re-frame documentation](https://day8.github.io/re-frame/re-frame/) which describes the greatness of this framework in the finest details. Everything you learn there applies to reflex! Though we do lose some of ClojureScript's natural immutability magic. Immer helps bridge this gap, but it's not quite as elegant or efficient as CLJS persistent data structures.
|
|
15
16
|
|
|
@@ -57,7 +58,7 @@ regEvent('decrement', ({ draftDb }) => {
|
|
|
57
58
|
regSub('counter');
|
|
58
59
|
|
|
59
60
|
// React component
|
|
60
|
-
|
|
61
|
+
const Counter = () => {
|
|
61
62
|
const counter = useSubscription<number>(['counter']);
|
|
62
63
|
|
|
63
64
|
return (
|
|
@@ -74,7 +75,7 @@ function Counter() {
|
|
|
74
75
|
|
|
75
76
|
### Events & Effects
|
|
76
77
|
|
|
77
|
-
Events
|
|
78
|
+
Events define state transitions and may declare side effects:
|
|
78
79
|
|
|
79
80
|
```typescript
|
|
80
81
|
// Simple state update
|
|
@@ -87,7 +88,6 @@ dispatch(['set-name', 'John Doe']);
|
|
|
87
88
|
|
|
88
89
|
// Event with side effects
|
|
89
90
|
regEvent('save-user', ({ draftDb }, user) => {
|
|
90
|
-
draftDb.user = user;
|
|
91
91
|
draftDb.saving = true;
|
|
92
92
|
return [
|
|
93
93
|
['http', {
|
package/dist/index.cjs
CHANGED
|
@@ -30,7 +30,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var src_exports = {};
|
|
32
32
|
__export(src_exports, {
|
|
33
|
+
HotReloadWrapper: () => HotReloadWrapper,
|
|
33
34
|
clearGlobalInterceptors: () => clearGlobalInterceptors,
|
|
35
|
+
clearHandlers: () => clearHandlers,
|
|
36
|
+
clearHotReloadCallbacks: () => clearHotReloadCallbacks,
|
|
37
|
+
clearReactions: () => clearReactions,
|
|
38
|
+
clearSubs: () => clearSubs,
|
|
34
39
|
debounceAndDispatch: () => debounceAndDispatch,
|
|
35
40
|
defaultErrorHandler: () => defaultErrorHandler,
|
|
36
41
|
disableTracing: () => disableTracing,
|
|
@@ -46,9 +51,14 @@ __export(src_exports, {
|
|
|
46
51
|
regEventErrorHandler: () => regEventErrorHandler,
|
|
47
52
|
regGlobalInterceptor: () => regGlobalInterceptor,
|
|
48
53
|
regSub: () => regSub,
|
|
54
|
+
registerHotReloadCallback: () => registerHotReloadCallback,
|
|
49
55
|
registerTraceCb: () => registerTraceCb,
|
|
50
56
|
setDebugEnabled: () => setDebugEnabled,
|
|
57
|
+
setupSubsHotReload: () => setupSubsHotReload,
|
|
51
58
|
throttleAndDispatch: () => throttleAndDispatch,
|
|
59
|
+
triggerHotReload: () => triggerHotReload,
|
|
60
|
+
useHotReload: () => useHotReload,
|
|
61
|
+
useHotReloadKey: () => useHotReloadKey,
|
|
52
62
|
useSubscription: () => useSubscription
|
|
53
63
|
});
|
|
54
64
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -96,6 +106,25 @@ function registerHandler(kind, id, handlerFn) {
|
|
|
96
106
|
kindToIdToHandler[kind][id] = handlerFn;
|
|
97
107
|
return handlerFn;
|
|
98
108
|
}
|
|
109
|
+
function clearHandlers(kind, id) {
|
|
110
|
+
if (kind == null) {
|
|
111
|
+
for (const k in kindToIdToHandler) {
|
|
112
|
+
kindToIdToHandler[k] = {};
|
|
113
|
+
}
|
|
114
|
+
} else if (id == null) {
|
|
115
|
+
if (!(kind in kindToIdToHandler)) {
|
|
116
|
+
consoleLog("error", `[reflex] Unknown kind: ${kind}`);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
kindToIdToHandler[kind] = {};
|
|
120
|
+
} else {
|
|
121
|
+
if (kindToIdToHandler[kind][id]) {
|
|
122
|
+
delete kindToIdToHandler[kind][id];
|
|
123
|
+
} else {
|
|
124
|
+
consoleLog("warn", `[reflex] can't clear ${kind} handler for ${id}. Handler not found.`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
99
128
|
function hasHandler(kind, id) {
|
|
100
129
|
return !!kindToIdToHandler[kind][id];
|
|
101
130
|
}
|
|
@@ -106,6 +135,18 @@ function getReaction(key) {
|
|
|
106
135
|
function setReaction(key, reaction) {
|
|
107
136
|
reactionsRegistry.set(key, reaction);
|
|
108
137
|
}
|
|
138
|
+
function clearReactions(id) {
|
|
139
|
+
if (id == null) {
|
|
140
|
+
reactionsRegistry.clear();
|
|
141
|
+
} else {
|
|
142
|
+
reactionsRegistry.delete(id);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function clearSubs() {
|
|
146
|
+
clearReactions();
|
|
147
|
+
clearHandlers("sub");
|
|
148
|
+
clearHandlers("subDeps");
|
|
149
|
+
}
|
|
109
150
|
var interceptorsRegistry = /* @__PURE__ */ new Map();
|
|
110
151
|
function getInterceptors(eventId) {
|
|
111
152
|
return interceptorsRegistry.get(eventId) || [];
|
|
@@ -1072,9 +1113,85 @@ function useSubscription(subVector, componentName = "react component") {
|
|
|
1072
1113
|
}, []);
|
|
1073
1114
|
return val;
|
|
1074
1115
|
}
|
|
1116
|
+
|
|
1117
|
+
// src/hot-reload.ts
|
|
1118
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
1119
|
+
var hotReloadCallbacks = /* @__PURE__ */ new Set();
|
|
1120
|
+
function registerHotReloadCallback(callback) {
|
|
1121
|
+
hotReloadCallbacks.add(callback);
|
|
1122
|
+
return () => {
|
|
1123
|
+
hotReloadCallbacks.delete(callback);
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1126
|
+
function triggerHotReload() {
|
|
1127
|
+
consoleLog("log", "[reflex] Triggering hot reload callbacks");
|
|
1128
|
+
for (const callback of hotReloadCallbacks) {
|
|
1129
|
+
try {
|
|
1130
|
+
callback();
|
|
1131
|
+
} catch (error) {
|
|
1132
|
+
consoleLog("error", "[reflex] Error in hot reload callback:", error);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
function clearHotReloadCallbacks() {
|
|
1137
|
+
hotReloadCallbacks.clear();
|
|
1138
|
+
}
|
|
1139
|
+
function useHotReload() {
|
|
1140
|
+
const [, forceUpdate] = (0, import_react2.useState)({});
|
|
1141
|
+
const callbackRef = (0, import_react2.useRef)(null);
|
|
1142
|
+
(0, import_react2.useEffect)(() => {
|
|
1143
|
+
const triggerUpdate = () => {
|
|
1144
|
+
forceUpdate({});
|
|
1145
|
+
};
|
|
1146
|
+
callbackRef.current = triggerUpdate;
|
|
1147
|
+
const unregister = registerHotReloadCallback(triggerUpdate);
|
|
1148
|
+
return () => {
|
|
1149
|
+
unregister();
|
|
1150
|
+
callbackRef.current = null;
|
|
1151
|
+
};
|
|
1152
|
+
}, []);
|
|
1153
|
+
}
|
|
1154
|
+
var keyCounter = 0;
|
|
1155
|
+
function useHotReloadKey() {
|
|
1156
|
+
const [key, setKey] = (0, import_react2.useState)(() => `hot-reload-${++keyCounter}`);
|
|
1157
|
+
const callbackRef = (0, import_react2.useRef)(null);
|
|
1158
|
+
(0, import_react2.useEffect)(() => {
|
|
1159
|
+
const updateKey = () => {
|
|
1160
|
+
setKey(`hot-reload-${++keyCounter}`);
|
|
1161
|
+
};
|
|
1162
|
+
callbackRef.current = updateKey;
|
|
1163
|
+
const unregister = registerHotReloadCallback(updateKey);
|
|
1164
|
+
return () => {
|
|
1165
|
+
unregister();
|
|
1166
|
+
callbackRef.current = null;
|
|
1167
|
+
};
|
|
1168
|
+
}, []);
|
|
1169
|
+
return key;
|
|
1170
|
+
}
|
|
1171
|
+
function setupSubsHotReload() {
|
|
1172
|
+
const dispose = () => {
|
|
1173
|
+
clearSubs();
|
|
1174
|
+
};
|
|
1175
|
+
const accept = (newModule) => {
|
|
1176
|
+
if (newModule) {
|
|
1177
|
+
consoleLog("log", "[reflex] Hot reloading subs module");
|
|
1178
|
+
triggerHotReload();
|
|
1179
|
+
}
|
|
1180
|
+
};
|
|
1181
|
+
return { dispose, accept };
|
|
1182
|
+
}
|
|
1183
|
+
function HotReloadWrapper({ children }) {
|
|
1184
|
+
const key = useHotReloadKey();
|
|
1185
|
+
return import_react2.default.createElement("div", { key, style: { display: "contents" } }, children);
|
|
1186
|
+
}
|
|
1075
1187
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1076
1188
|
0 && (module.exports = {
|
|
1189
|
+
HotReloadWrapper,
|
|
1077
1190
|
clearGlobalInterceptors,
|
|
1191
|
+
clearHandlers,
|
|
1192
|
+
clearHotReloadCallbacks,
|
|
1193
|
+
clearReactions,
|
|
1194
|
+
clearSubs,
|
|
1078
1195
|
debounceAndDispatch,
|
|
1079
1196
|
defaultErrorHandler,
|
|
1080
1197
|
disableTracing,
|
|
@@ -1090,8 +1207,13 @@ function useSubscription(subVector, componentName = "react component") {
|
|
|
1090
1207
|
regEventErrorHandler,
|
|
1091
1208
|
regGlobalInterceptor,
|
|
1092
1209
|
regSub,
|
|
1210
|
+
registerHotReloadCallback,
|
|
1093
1211
|
registerTraceCb,
|
|
1094
1212
|
setDebugEnabled,
|
|
1213
|
+
setupSubsHotReload,
|
|
1095
1214
|
throttleAndDispatch,
|
|
1215
|
+
triggerHotReload,
|
|
1216
|
+
useHotReload,
|
|
1217
|
+
useHotReloadKey,
|
|
1096
1218
|
useSubscription
|
|
1097
1219
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Draft } from 'immer';
|
|
2
|
+
import React from 'react';
|
|
2
3
|
|
|
3
4
|
type Db<T = Record<string, any>> = T;
|
|
4
5
|
type Id = string;
|
|
@@ -105,6 +106,14 @@ declare function setDebugEnabled(enabled: boolean): void;
|
|
|
105
106
|
*/
|
|
106
107
|
declare function isDebugEnabled(): boolean;
|
|
107
108
|
|
|
109
|
+
type Kind = 'event' | 'fx' | 'cofx' | 'sub' | 'subDeps' | 'error';
|
|
110
|
+
declare function clearHandlers(): void;
|
|
111
|
+
declare function clearHandlers(kind: Kind): void;
|
|
112
|
+
declare function clearHandlers(kind: Kind, id: string): void;
|
|
113
|
+
declare function clearReactions(): void;
|
|
114
|
+
declare function clearReactions(id: string): void;
|
|
115
|
+
declare function clearSubs(): void;
|
|
116
|
+
|
|
108
117
|
/**
|
|
109
118
|
* Port of re-frame.router from ClojureScript to TypeScript.
|
|
110
119
|
* Implements an event queue with a finite-state-machine to schedule and process events.
|
|
@@ -128,6 +137,49 @@ declare function throttleAndDispatch(event: EventVector, durationMs: number): vo
|
|
|
128
137
|
|
|
129
138
|
declare function useSubscription<T>(subVector: SubVector, componentName?: string): T;
|
|
130
139
|
|
|
140
|
+
type HotReloadCallback = () => void;
|
|
141
|
+
/**
|
|
142
|
+
* Register a callback to be called when subs are hot reloaded
|
|
143
|
+
*/
|
|
144
|
+
declare function registerHotReloadCallback(callback: HotReloadCallback): () => void;
|
|
145
|
+
/**
|
|
146
|
+
* Trigger all registered hot reload callbacks
|
|
147
|
+
*/
|
|
148
|
+
declare function triggerHotReload(): void;
|
|
149
|
+
/**
|
|
150
|
+
* Clear all hot reload callbacks
|
|
151
|
+
*/
|
|
152
|
+
declare function clearHotReloadCallbacks(): void;
|
|
153
|
+
/**
|
|
154
|
+
* React hook that forces component re-render when subs are hot reloaded
|
|
155
|
+
*/
|
|
156
|
+
declare function useHotReload(): void;
|
|
157
|
+
/**
|
|
158
|
+
* React hook that provides a key that changes when subs are hot reloaded
|
|
159
|
+
* Useful for forcing complete re-mount of component trees
|
|
160
|
+
*/
|
|
161
|
+
declare function useHotReloadKey(): string;
|
|
162
|
+
/**
|
|
163
|
+
* Utility for setting up hot reload in subs modules
|
|
164
|
+
* Returns dispose and accept functions for HMR
|
|
165
|
+
*/
|
|
166
|
+
declare function setupSubsHotReload(): {
|
|
167
|
+
dispose: () => void;
|
|
168
|
+
accept: (newModule?: any) => void;
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* React component that wraps children with hot reload support
|
|
172
|
+
* Uses a key that changes when subs are hot reloaded to force re-mount
|
|
173
|
+
*/
|
|
174
|
+
declare function HotReloadWrapper({ children }: {
|
|
175
|
+
children: React.ReactNode;
|
|
176
|
+
}): React.DetailedReactHTMLElement<{
|
|
177
|
+
key: string;
|
|
178
|
+
style: {
|
|
179
|
+
display: "contents";
|
|
180
|
+
};
|
|
181
|
+
}, HTMLElement>;
|
|
182
|
+
|
|
131
183
|
type TraceID = number;
|
|
132
184
|
interface TraceOpts {
|
|
133
185
|
operation?: string;
|
|
@@ -147,4 +199,4 @@ declare function disableTracing(): void;
|
|
|
147
199
|
declare function registerTraceCb(key: string, cb: TraceCallback): void;
|
|
148
200
|
declare function enableTracePrint(): void;
|
|
149
201
|
|
|
150
|
-
export { CoEffectHandler, CoEffects, Context, Db, DispatchLaterEffect, EffectHandler, Effects, ErrorHandler, EventHandler, EventVector, Id, Interceptor, SubVector, clearGlobalInterceptors, debounceAndDispatch, defaultErrorHandler, disableTracing, dispatch, enableTracePrint, enableTracing, getGlobalInterceptors, initAppDb, isDebugEnabled, regCoeffect, regEffect, regEvent, regEventErrorHandler, regGlobalInterceptor, regSub, registerTraceCb, setDebugEnabled, throttleAndDispatch, useSubscription };
|
|
202
|
+
export { CoEffectHandler, CoEffects, Context, Db, DispatchLaterEffect, EffectHandler, Effects, ErrorHandler, EventHandler, EventVector, HotReloadWrapper, Id, Interceptor, SubVector, clearGlobalInterceptors, clearHandlers, clearHotReloadCallbacks, clearReactions, clearSubs, debounceAndDispatch, defaultErrorHandler, disableTracing, dispatch, enableTracePrint, enableTracing, getGlobalInterceptors, initAppDb, isDebugEnabled, regCoeffect, regEffect, regEvent, regEventErrorHandler, regGlobalInterceptor, regSub, registerHotReloadCallback, registerTraceCb, setDebugEnabled, setupSubsHotReload, throttleAndDispatch, triggerHotReload, useHotReload, useHotReloadKey, useSubscription };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Draft } from 'immer';
|
|
2
|
+
import React from 'react';
|
|
2
3
|
|
|
3
4
|
type Db<T = Record<string, any>> = T;
|
|
4
5
|
type Id = string;
|
|
@@ -105,6 +106,14 @@ declare function setDebugEnabled(enabled: boolean): void;
|
|
|
105
106
|
*/
|
|
106
107
|
declare function isDebugEnabled(): boolean;
|
|
107
108
|
|
|
109
|
+
type Kind = 'event' | 'fx' | 'cofx' | 'sub' | 'subDeps' | 'error';
|
|
110
|
+
declare function clearHandlers(): void;
|
|
111
|
+
declare function clearHandlers(kind: Kind): void;
|
|
112
|
+
declare function clearHandlers(kind: Kind, id: string): void;
|
|
113
|
+
declare function clearReactions(): void;
|
|
114
|
+
declare function clearReactions(id: string): void;
|
|
115
|
+
declare function clearSubs(): void;
|
|
116
|
+
|
|
108
117
|
/**
|
|
109
118
|
* Port of re-frame.router from ClojureScript to TypeScript.
|
|
110
119
|
* Implements an event queue with a finite-state-machine to schedule and process events.
|
|
@@ -128,6 +137,49 @@ declare function throttleAndDispatch(event: EventVector, durationMs: number): vo
|
|
|
128
137
|
|
|
129
138
|
declare function useSubscription<T>(subVector: SubVector, componentName?: string): T;
|
|
130
139
|
|
|
140
|
+
type HotReloadCallback = () => void;
|
|
141
|
+
/**
|
|
142
|
+
* Register a callback to be called when subs are hot reloaded
|
|
143
|
+
*/
|
|
144
|
+
declare function registerHotReloadCallback(callback: HotReloadCallback): () => void;
|
|
145
|
+
/**
|
|
146
|
+
* Trigger all registered hot reload callbacks
|
|
147
|
+
*/
|
|
148
|
+
declare function triggerHotReload(): void;
|
|
149
|
+
/**
|
|
150
|
+
* Clear all hot reload callbacks
|
|
151
|
+
*/
|
|
152
|
+
declare function clearHotReloadCallbacks(): void;
|
|
153
|
+
/**
|
|
154
|
+
* React hook that forces component re-render when subs are hot reloaded
|
|
155
|
+
*/
|
|
156
|
+
declare function useHotReload(): void;
|
|
157
|
+
/**
|
|
158
|
+
* React hook that provides a key that changes when subs are hot reloaded
|
|
159
|
+
* Useful for forcing complete re-mount of component trees
|
|
160
|
+
*/
|
|
161
|
+
declare function useHotReloadKey(): string;
|
|
162
|
+
/**
|
|
163
|
+
* Utility for setting up hot reload in subs modules
|
|
164
|
+
* Returns dispose and accept functions for HMR
|
|
165
|
+
*/
|
|
166
|
+
declare function setupSubsHotReload(): {
|
|
167
|
+
dispose: () => void;
|
|
168
|
+
accept: (newModule?: any) => void;
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* React component that wraps children with hot reload support
|
|
172
|
+
* Uses a key that changes when subs are hot reloaded to force re-mount
|
|
173
|
+
*/
|
|
174
|
+
declare function HotReloadWrapper({ children }: {
|
|
175
|
+
children: React.ReactNode;
|
|
176
|
+
}): React.DetailedReactHTMLElement<{
|
|
177
|
+
key: string;
|
|
178
|
+
style: {
|
|
179
|
+
display: "contents";
|
|
180
|
+
};
|
|
181
|
+
}, HTMLElement>;
|
|
182
|
+
|
|
131
183
|
type TraceID = number;
|
|
132
184
|
interface TraceOpts {
|
|
133
185
|
operation?: string;
|
|
@@ -147,4 +199,4 @@ declare function disableTracing(): void;
|
|
|
147
199
|
declare function registerTraceCb(key: string, cb: TraceCallback): void;
|
|
148
200
|
declare function enableTracePrint(): void;
|
|
149
201
|
|
|
150
|
-
export { CoEffectHandler, CoEffects, Context, Db, DispatchLaterEffect, EffectHandler, Effects, ErrorHandler, EventHandler, EventVector, Id, Interceptor, SubVector, clearGlobalInterceptors, debounceAndDispatch, defaultErrorHandler, disableTracing, dispatch, enableTracePrint, enableTracing, getGlobalInterceptors, initAppDb, isDebugEnabled, regCoeffect, regEffect, regEvent, regEventErrorHandler, regGlobalInterceptor, regSub, registerTraceCb, setDebugEnabled, throttleAndDispatch, useSubscription };
|
|
202
|
+
export { CoEffectHandler, CoEffects, Context, Db, DispatchLaterEffect, EffectHandler, Effects, ErrorHandler, EventHandler, EventVector, HotReloadWrapper, Id, Interceptor, SubVector, clearGlobalInterceptors, clearHandlers, clearHotReloadCallbacks, clearReactions, clearSubs, debounceAndDispatch, defaultErrorHandler, disableTracing, dispatch, enableTracePrint, enableTracing, getGlobalInterceptors, initAppDb, isDebugEnabled, regCoeffect, regEffect, regEvent, regEventErrorHandler, regGlobalInterceptor, regSub, registerHotReloadCallback, registerTraceCb, setDebugEnabled, setupSubsHotReload, throttleAndDispatch, triggerHotReload, useHotReload, useHotReloadKey, useSubscription };
|
|
@@ -41,6 +41,25 @@ function registerHandler(kind, id, handlerFn) {
|
|
|
41
41
|
kindToIdToHandler[kind][id] = handlerFn;
|
|
42
42
|
return handlerFn;
|
|
43
43
|
}
|
|
44
|
+
function clearHandlers(kind, id) {
|
|
45
|
+
if (kind == null) {
|
|
46
|
+
for (const k in kindToIdToHandler) {
|
|
47
|
+
kindToIdToHandler[k] = {};
|
|
48
|
+
}
|
|
49
|
+
} else if (id == null) {
|
|
50
|
+
if (!(kind in kindToIdToHandler)) {
|
|
51
|
+
consoleLog("error", `[reflex] Unknown kind: ${kind}`);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
kindToIdToHandler[kind] = {};
|
|
55
|
+
} else {
|
|
56
|
+
if (kindToIdToHandler[kind][id]) {
|
|
57
|
+
delete kindToIdToHandler[kind][id];
|
|
58
|
+
} else {
|
|
59
|
+
consoleLog("warn", `[reflex] can't clear ${kind} handler for ${id}. Handler not found.`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
44
63
|
function hasHandler(kind, id) {
|
|
45
64
|
return !!kindToIdToHandler[kind][id];
|
|
46
65
|
}
|
|
@@ -51,6 +70,18 @@ function getReaction(key) {
|
|
|
51
70
|
function setReaction(key, reaction) {
|
|
52
71
|
reactionsRegistry.set(key, reaction);
|
|
53
72
|
}
|
|
73
|
+
function clearReactions(id) {
|
|
74
|
+
if (id == null) {
|
|
75
|
+
reactionsRegistry.clear();
|
|
76
|
+
} else {
|
|
77
|
+
reactionsRegistry.delete(id);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function clearSubs() {
|
|
81
|
+
clearReactions();
|
|
82
|
+
clearHandlers("sub");
|
|
83
|
+
clearHandlers("subDeps");
|
|
84
|
+
}
|
|
54
85
|
var interceptorsRegistry = /* @__PURE__ */ new Map();
|
|
55
86
|
function getInterceptors(eventId) {
|
|
56
87
|
return interceptorsRegistry.get(eventId) || [];
|
|
@@ -1017,8 +1048,84 @@ function useSubscription(subVector, componentName = "react component") {
|
|
|
1017
1048
|
}, []);
|
|
1018
1049
|
return val;
|
|
1019
1050
|
}
|
|
1051
|
+
|
|
1052
|
+
// src/hot-reload.ts
|
|
1053
|
+
import React, { useState as useState2, useEffect as useEffect2, useRef } from "react";
|
|
1054
|
+
var hotReloadCallbacks = /* @__PURE__ */ new Set();
|
|
1055
|
+
function registerHotReloadCallback(callback) {
|
|
1056
|
+
hotReloadCallbacks.add(callback);
|
|
1057
|
+
return () => {
|
|
1058
|
+
hotReloadCallbacks.delete(callback);
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
function triggerHotReload() {
|
|
1062
|
+
consoleLog("log", "[reflex] Triggering hot reload callbacks");
|
|
1063
|
+
for (const callback of hotReloadCallbacks) {
|
|
1064
|
+
try {
|
|
1065
|
+
callback();
|
|
1066
|
+
} catch (error) {
|
|
1067
|
+
consoleLog("error", "[reflex] Error in hot reload callback:", error);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
function clearHotReloadCallbacks() {
|
|
1072
|
+
hotReloadCallbacks.clear();
|
|
1073
|
+
}
|
|
1074
|
+
function useHotReload() {
|
|
1075
|
+
const [, forceUpdate] = useState2({});
|
|
1076
|
+
const callbackRef = useRef(null);
|
|
1077
|
+
useEffect2(() => {
|
|
1078
|
+
const triggerUpdate = () => {
|
|
1079
|
+
forceUpdate({});
|
|
1080
|
+
};
|
|
1081
|
+
callbackRef.current = triggerUpdate;
|
|
1082
|
+
const unregister = registerHotReloadCallback(triggerUpdate);
|
|
1083
|
+
return () => {
|
|
1084
|
+
unregister();
|
|
1085
|
+
callbackRef.current = null;
|
|
1086
|
+
};
|
|
1087
|
+
}, []);
|
|
1088
|
+
}
|
|
1089
|
+
var keyCounter = 0;
|
|
1090
|
+
function useHotReloadKey() {
|
|
1091
|
+
const [key, setKey] = useState2(() => `hot-reload-${++keyCounter}`);
|
|
1092
|
+
const callbackRef = useRef(null);
|
|
1093
|
+
useEffect2(() => {
|
|
1094
|
+
const updateKey = () => {
|
|
1095
|
+
setKey(`hot-reload-${++keyCounter}`);
|
|
1096
|
+
};
|
|
1097
|
+
callbackRef.current = updateKey;
|
|
1098
|
+
const unregister = registerHotReloadCallback(updateKey);
|
|
1099
|
+
return () => {
|
|
1100
|
+
unregister();
|
|
1101
|
+
callbackRef.current = null;
|
|
1102
|
+
};
|
|
1103
|
+
}, []);
|
|
1104
|
+
return key;
|
|
1105
|
+
}
|
|
1106
|
+
function setupSubsHotReload() {
|
|
1107
|
+
const dispose = () => {
|
|
1108
|
+
clearSubs();
|
|
1109
|
+
};
|
|
1110
|
+
const accept = (newModule) => {
|
|
1111
|
+
if (newModule) {
|
|
1112
|
+
consoleLog("log", "[reflex] Hot reloading subs module");
|
|
1113
|
+
triggerHotReload();
|
|
1114
|
+
}
|
|
1115
|
+
};
|
|
1116
|
+
return { dispose, accept };
|
|
1117
|
+
}
|
|
1118
|
+
function HotReloadWrapper({ children }) {
|
|
1119
|
+
const key = useHotReloadKey();
|
|
1120
|
+
return React.createElement("div", { key, style: { display: "contents" } }, children);
|
|
1121
|
+
}
|
|
1020
1122
|
export {
|
|
1123
|
+
HotReloadWrapper,
|
|
1021
1124
|
clearGlobalInterceptors,
|
|
1125
|
+
clearHandlers,
|
|
1126
|
+
clearHotReloadCallbacks,
|
|
1127
|
+
clearReactions,
|
|
1128
|
+
clearSubs,
|
|
1022
1129
|
debounceAndDispatch,
|
|
1023
1130
|
defaultErrorHandler,
|
|
1024
1131
|
disableTracing,
|
|
@@ -1034,8 +1141,13 @@ export {
|
|
|
1034
1141
|
regEventErrorHandler,
|
|
1035
1142
|
regGlobalInterceptor,
|
|
1036
1143
|
regSub,
|
|
1144
|
+
registerHotReloadCallback,
|
|
1037
1145
|
registerTraceCb,
|
|
1038
1146
|
setDebugEnabled,
|
|
1147
|
+
setupSubsHotReload,
|
|
1039
1148
|
throttleAndDispatch,
|
|
1149
|
+
triggerHotReload,
|
|
1150
|
+
useHotReload,
|
|
1151
|
+
useHotReloadKey,
|
|
1040
1152
|
useSubscription
|
|
1041
1153
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flexsurfer/reflex",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -11,8 +11,14 @@
|
|
|
11
11
|
"module": "dist/index.mjs",
|
|
12
12
|
"types": "dist/index.d.ts",
|
|
13
13
|
"exports": {
|
|
14
|
-
"import":
|
|
15
|
-
|
|
14
|
+
"import": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.mjs"
|
|
17
|
+
},
|
|
18
|
+
"require": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.cjs"
|
|
21
|
+
}
|
|
16
22
|
},
|
|
17
23
|
"files": [
|
|
18
24
|
"dist",
|
|
@@ -20,8 +26,8 @@
|
|
|
20
26
|
"LICENSE"
|
|
21
27
|
],
|
|
22
28
|
"scripts": {
|
|
23
|
-
"build": "tsup
|
|
24
|
-
"dev": "tsup
|
|
29
|
+
"build": "tsup",
|
|
30
|
+
"dev": "tsup --watch",
|
|
25
31
|
"test": "jest --passWithNoTests",
|
|
26
32
|
"test:clean": "jest --passWithNoTests --silent",
|
|
27
33
|
"test:watch": "jest --passWithNoTests --watch"
|
|
@@ -62,4 +68,4 @@
|
|
|
62
68
|
"pubsub",
|
|
63
69
|
"handler"
|
|
64
70
|
]
|
|
65
|
-
}
|
|
71
|
+
}
|