@hvakr/firestate 0.1.4 → 0.1.5
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 +146 -101
- package/dist/index.d.mts +26 -8
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +74 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2160,6 +2160,37 @@ const shallow = (a, b) => {
|
|
|
2160
2160
|
|
|
2161
2161
|
//#endregion
|
|
2162
2162
|
//#region src/utils/undo.ts
|
|
2163
|
+
const getGroupedActions = (action) => action.actions ?? [action];
|
|
2164
|
+
/**
|
|
2165
|
+
* Apply a group in the required direction. If a member fails, compensate the
|
|
2166
|
+
* members already applied so a failed undo/redo does not leave the group
|
|
2167
|
+
* partially applied (provided the compensating actions themselves succeed).
|
|
2168
|
+
*/
|
|
2169
|
+
const applyGroup = async (actions, operation) => {
|
|
2170
|
+
const ordered = operation === "undo" ? [...actions].reverse() : actions;
|
|
2171
|
+
const applied = [];
|
|
2172
|
+
try {
|
|
2173
|
+
for (const action of ordered) {
|
|
2174
|
+
await action[operation]();
|
|
2175
|
+
applied.push(action);
|
|
2176
|
+
}
|
|
2177
|
+
} catch (error) {
|
|
2178
|
+
const compensate = operation === "undo" ? "redo" : "undo";
|
|
2179
|
+
for (const action of applied.reverse()) await action[compensate]();
|
|
2180
|
+
throw error;
|
|
2181
|
+
}
|
|
2182
|
+
};
|
|
2183
|
+
const mergeGroupedActions = (older, newer) => {
|
|
2184
|
+
const actions = [...getGroupedActions(older), newer];
|
|
2185
|
+
return {
|
|
2186
|
+
undo: () => applyGroup(actions, "undo"),
|
|
2187
|
+
redo: () => applyGroup(actions, "redo"),
|
|
2188
|
+
groupId: newer.groupId,
|
|
2189
|
+
path: newer.path ?? older.path,
|
|
2190
|
+
description: newer.description ?? older.description,
|
|
2191
|
+
actions
|
|
2192
|
+
};
|
|
2193
|
+
};
|
|
2163
2194
|
/**
|
|
2164
2195
|
* Create an undo manager instance.
|
|
2165
2196
|
* This is a standalone, framework-agnostic implementation.
|
|
@@ -2179,7 +2210,7 @@ const shallow = (a, b) => {
|
|
|
2179
2210
|
* ```
|
|
2180
2211
|
*/
|
|
2181
2212
|
const createUndoManager = (config = {}) => {
|
|
2182
|
-
const { maxLength = 20, onNavigate } = config;
|
|
2213
|
+
const { maxLength = 20, onNavigate, onUndo, onRedo, onError } = config;
|
|
2183
2214
|
let undoStack = [];
|
|
2184
2215
|
let redoStack = [];
|
|
2185
2216
|
const subscribers = /* @__PURE__ */ new Set();
|
|
@@ -2203,19 +2234,7 @@ const createUndoManager = (config = {}) => {
|
|
|
2203
2234
|
const last = undoStack[undoStack.length - 1];
|
|
2204
2235
|
if (last?.groupId === action.groupId) {
|
|
2205
2236
|
undoStack.pop();
|
|
2206
|
-
undoStack.push(
|
|
2207
|
-
undo: async () => {
|
|
2208
|
-
await action.undo();
|
|
2209
|
-
await last.undo();
|
|
2210
|
-
},
|
|
2211
|
-
redo: async () => {
|
|
2212
|
-
await last.redo();
|
|
2213
|
-
await action.redo();
|
|
2214
|
-
},
|
|
2215
|
-
groupId: action.groupId,
|
|
2216
|
-
path: action.path ?? last.path,
|
|
2217
|
-
description: action.description ?? last.description
|
|
2218
|
-
});
|
|
2237
|
+
undoStack.push(mergeGroupedActions(last, action));
|
|
2219
2238
|
redoStack = [];
|
|
2220
2239
|
notify();
|
|
2221
2240
|
return;
|
|
@@ -2229,31 +2248,35 @@ const createUndoManager = (config = {}) => {
|
|
|
2229
2248
|
const undo = async () => {
|
|
2230
2249
|
const action = undoStack.pop();
|
|
2231
2250
|
if (!action) return;
|
|
2232
|
-
if (action.path && onNavigate) onNavigate(action.path);
|
|
2233
2251
|
try {
|
|
2252
|
+
if (action.path && onNavigate) onNavigate(action.path);
|
|
2234
2253
|
await action.undo();
|
|
2235
|
-
redoStack.push(action);
|
|
2236
2254
|
} catch (error) {
|
|
2237
2255
|
undoStack.push(action);
|
|
2238
|
-
|
|
2256
|
+
if (onError) onError(error, action, "undo");
|
|
2257
|
+
else console.error("Undo failed:", error);
|
|
2239
2258
|
throw error;
|
|
2240
2259
|
}
|
|
2260
|
+
redoStack.push(action);
|
|
2241
2261
|
notify();
|
|
2262
|
+
onUndo?.(action);
|
|
2242
2263
|
};
|
|
2243
2264
|
const redo = async () => {
|
|
2244
2265
|
const action = redoStack.pop();
|
|
2245
2266
|
if (!action) return;
|
|
2246
|
-
if (action.path && onNavigate) onNavigate(action.path);
|
|
2247
2267
|
try {
|
|
2268
|
+
if (action.path && onNavigate) onNavigate(action.path);
|
|
2248
2269
|
await action.redo();
|
|
2249
|
-
undoStack.push(action);
|
|
2250
|
-
if (undoStack.length > maxLength) undoStack.shift();
|
|
2251
2270
|
} catch (error) {
|
|
2252
2271
|
redoStack.push(action);
|
|
2253
|
-
|
|
2272
|
+
if (onError) onError(error, action, "redo");
|
|
2273
|
+
else console.error("Redo failed:", error);
|
|
2254
2274
|
throw error;
|
|
2255
2275
|
}
|
|
2276
|
+
undoStack.push(action);
|
|
2277
|
+
if (undoStack.length > maxLength) undoStack.shift();
|
|
2256
2278
|
notify();
|
|
2279
|
+
onRedo?.(action);
|
|
2257
2280
|
};
|
|
2258
2281
|
const clear = () => {
|
|
2259
2282
|
undoStack = [];
|
|
@@ -2311,9 +2334,22 @@ const createStore = (config) => {
|
|
|
2311
2334
|
const { firestore, autosave = 1e3, minLoadTime = 0, maxUndoLength = 20 } = config;
|
|
2312
2335
|
let onError = config.onError;
|
|
2313
2336
|
let onNavigate = config.onNavigate;
|
|
2337
|
+
let onUndo = config.onUndo;
|
|
2338
|
+
let onRedo = config.onRedo;
|
|
2314
2339
|
const undoManager = createUndoManager({
|
|
2315
2340
|
maxLength: maxUndoLength,
|
|
2316
|
-
onNavigate: (path) => onNavigate?.(path)
|
|
2341
|
+
onNavigate: (path) => onNavigate?.(path),
|
|
2342
|
+
onUndo: (action) => onUndo?.(action),
|
|
2343
|
+
onRedo: (action) => onRedo?.(action),
|
|
2344
|
+
onError: (error, action, operation) => {
|
|
2345
|
+
const context = {
|
|
2346
|
+
type: "undo",
|
|
2347
|
+
path: action.path ?? "undo",
|
|
2348
|
+
operation
|
|
2349
|
+
};
|
|
2350
|
+
if (onError) onError(error, context);
|
|
2351
|
+
else console.error(`Firestate error in ${context.type} ${context.path} during ${context.operation}:`, error);
|
|
2352
|
+
}
|
|
2317
2353
|
});
|
|
2318
2354
|
const syncStates = /* @__PURE__ */ new Map();
|
|
2319
2355
|
const syncSubscribers = /* @__PURE__ */ new Set();
|
|
@@ -2340,6 +2376,12 @@ const createStore = (config) => {
|
|
|
2340
2376
|
setOnNavigate: (handler) => {
|
|
2341
2377
|
onNavigate = handler;
|
|
2342
2378
|
},
|
|
2379
|
+
setOnUndo: (handler) => {
|
|
2380
|
+
onUndo = handler;
|
|
2381
|
+
},
|
|
2382
|
+
setOnRedo: (handler) => {
|
|
2383
|
+
onRedo = handler;
|
|
2384
|
+
},
|
|
2343
2385
|
subscribeToSyncState: (fn) => {
|
|
2344
2386
|
syncSubscribers.add(fn);
|
|
2345
2387
|
return () => syncSubscribers.delete(fn);
|
|
@@ -2386,14 +2428,16 @@ const createStore = (config) => {
|
|
|
2386
2428
|
* }
|
|
2387
2429
|
* ```
|
|
2388
2430
|
*/
|
|
2389
|
-
const FirestateProvider = ({ firestore, autosave = 1e3, minLoadTime = 0, maxUndoLength = 20, onError, onNavigate, children }) => {
|
|
2431
|
+
const FirestateProvider = ({ firestore, autosave = 1e3, minLoadTime = 0, maxUndoLength = 20, onError, onNavigate, onUndo, onRedo, children }) => {
|
|
2390
2432
|
const store = useMemo(() => createStore({
|
|
2391
2433
|
firestore,
|
|
2392
2434
|
autosave,
|
|
2393
2435
|
minLoadTime,
|
|
2394
2436
|
maxUndoLength,
|
|
2395
2437
|
onError,
|
|
2396
|
-
onNavigate
|
|
2438
|
+
onNavigate,
|
|
2439
|
+
onUndo,
|
|
2440
|
+
onRedo
|
|
2397
2441
|
}), [
|
|
2398
2442
|
firestore,
|
|
2399
2443
|
autosave,
|
|
@@ -2406,6 +2450,12 @@ const FirestateProvider = ({ firestore, autosave = 1e3, minLoadTime = 0, maxUndo
|
|
|
2406
2450
|
useEffect(() => {
|
|
2407
2451
|
store.setOnNavigate(onNavigate);
|
|
2408
2452
|
}, [store, onNavigate]);
|
|
2453
|
+
useEffect(() => {
|
|
2454
|
+
store.setOnUndo(onUndo);
|
|
2455
|
+
}, [store, onUndo]);
|
|
2456
|
+
useEffect(() => {
|
|
2457
|
+
store.setOnRedo(onRedo);
|
|
2458
|
+
}, [store, onRedo]);
|
|
2409
2459
|
return /* @__PURE__ */ jsx(FirestateContext.Provider, {
|
|
2410
2460
|
value: store,
|
|
2411
2461
|
children
|