@voidhash/mimic-react 1.0.0-beta.11 → 1.0.0-beta.13
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/.turbo/turbo-build.log +22 -15
- package/dist/zustand/index.cjs +3 -1
- package/dist/zustand/index.d.cts +2 -1
- package/dist/zustand/index.d.mts +2 -1
- package/dist/zustand/index.mjs +2 -1
- package/dist/zustand/middleware.cjs +5 -1
- package/dist/zustand/middleware.d.cts.map +1 -1
- package/dist/zustand/middleware.d.mts.map +1 -1
- package/dist/zustand/middleware.mjs +5 -1
- package/dist/zustand/middleware.mjs.map +1 -1
- package/dist/zustand/types.d.cts +2 -0
- package/dist/zustand/types.d.cts.map +1 -1
- package/dist/zustand/types.d.mts +2 -0
- package/dist/zustand/types.d.mts.map +1 -1
- package/dist/zustand/useDraft.cjs +64 -0
- package/dist/zustand/useDraft.d.cts +32 -0
- package/dist/zustand/useDraft.d.cts.map +1 -0
- package/dist/zustand/useDraft.d.mts +32 -0
- package/dist/zustand/useDraft.d.mts.map +1 -0
- package/dist/zustand/useDraft.mjs +65 -0
- package/dist/zustand/useDraft.mjs.map +1 -0
- package/package.json +3 -3
- package/src/zustand/index.ts +3 -0
- package/src/zustand/middleware.ts +4 -0
- package/src/zustand/types.ts +2 -0
- package/src/zustand/useDraft.ts +112 -0
- package/tests/zustand/middleware.test.ts +4 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @voidhash/mimic-react@1.0.0-beta.
|
|
2
|
+
> @voidhash/mimic-react@1.0.0-beta.13 build /home/runner/work/mimic/mimic/packages/mimic-react
|
|
3
3
|
> tsdown
|
|
4
4
|
|
|
5
5
|
[34mℹ[39m tsdown [2mv0.18.2[22m powered by rolldown [2mv1.0.0-beta.55[22m
|
|
@@ -9,47 +9,53 @@
|
|
|
9
9
|
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
10
10
|
[34mℹ[39m Build start
|
|
11
11
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[1mzustand-commander/index.cjs[22m [2m0.78 kB[22m [2m│ gzip: 0.24 kB[22m
|
|
12
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[1mzustand/index.cjs[22m [2m0.
|
|
12
|
+
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[1mzustand/index.cjs[22m [2m0.20 kB[22m [2m│ gzip: 0.11 kB[22m
|
|
13
13
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[1mindex.cjs[22m [2m0.00 kB[22m [2m│ gzip: 0.02 kB[22m
|
|
14
14
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mzustand-commander/commander.cjs [2m5.39 kB[22m [2m│ gzip: 1.54 kB[22m
|
|
15
15
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mzustand-commander/hooks.cjs [2m4.18 kB[22m [2m│ gzip: 1.46 kB[22m
|
|
16
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22mzustand/middleware.cjs [2m3.
|
|
16
|
+
[34mℹ[39m [33m[CJS][39m [2mdist/[22mzustand/middleware.cjs [2m3.17 kB[22m [2m│ gzip: 1.14 kB[22m
|
|
17
|
+
[34mℹ[39m [33m[CJS][39m [2mdist/[22mzustand/useDraft.cjs [2m1.85 kB[22m [2m│ gzip: 0.64 kB[22m
|
|
17
18
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m_virtual/_@oxc-project_runtime@0.103.0/helpers/objectSpread2.cjs [2m0.95 kB[22m [2m│ gzip: 0.43 kB[22m
|
|
18
19
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mzustand-commander/types.cjs [2m0.91 kB[22m [2m│ gzip: 0.34 kB[22m
|
|
19
20
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m_virtual/_@oxc-project_runtime@0.103.0/helpers/typeof.cjs [2m0.53 kB[22m [2m│ gzip: 0.29 kB[22m
|
|
20
21
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m_virtual/_@oxc-project_runtime@0.103.0/helpers/toPrimitive.cjs [2m0.52 kB[22m [2m│ gzip: 0.32 kB[22m
|
|
21
22
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m_virtual/_@oxc-project_runtime@0.103.0/helpers/defineProperty.cjs [2m0.40 kB[22m [2m│ gzip: 0.24 kB[22m
|
|
22
23
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m_virtual/_@oxc-project_runtime@0.103.0/helpers/toPropertyKey.cjs [2m0.37 kB[22m [2m│ gzip: 0.23 kB[22m
|
|
23
|
-
[34mℹ[39m [33m[CJS][39m
|
|
24
|
+
[34mℹ[39m [33m[CJS][39m 13 files, total: 19.23 kB
|
|
24
25
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mzustand-commander/types.d.cts.map [2m2.75 kB[22m [2m│ gzip: 1.17 kB[22m
|
|
25
26
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mzustand/types.d.cts.map [2m1.24 kB[22m [2m│ gzip: 0.59 kB[22m
|
|
27
|
+
[34mℹ[39m [33m[CJS][39m [2mdist/[22mzustand/useDraft.d.cts.map [2m0.60 kB[22m [2m│ gzip: 0.30 kB[22m
|
|
26
28
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mzustand-commander/hooks.d.cts.map [2m0.48 kB[22m [2m│ gzip: 0.30 kB[22m
|
|
27
29
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mzustand/middleware.d.cts.map [2m0.38 kB[22m [2m│ gzip: 0.23 kB[22m
|
|
28
30
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mzustand-commander/commander.d.cts.map [2m0.30 kB[22m [2m│ gzip: 0.20 kB[22m
|
|
29
31
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32m[1mzustand-commander/index.d.cts[22m[39m [2m1.14 kB[22m [2m│ gzip: 0.36 kB[22m
|
|
30
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32m[1mzustand/index.d.cts[22m[39m [2m0.
|
|
32
|
+
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32m[1mzustand/index.d.cts[22m[39m [2m0.34 kB[22m [2m│ gzip: 0.17 kB[22m
|
|
31
33
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32m[1mindex.d.cts[22m[39m [2m0.01 kB[22m [2m│ gzip: 0.03 kB[22m
|
|
32
34
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mzustand-commander/types.d.cts[39m [2m7.04 kB[22m [2m│ gzip: 2.06 kB[22m
|
|
33
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mzustand/types.d.cts[39m [2m3.
|
|
35
|
+
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mzustand/types.d.cts[39m [2m3.23 kB[22m [2m│ gzip: 1.04 kB[22m
|
|
34
36
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mzustand-commander/hooks.d.cts[39m [2m2.52 kB[22m [2m│ gzip: 0.89 kB[22m
|
|
35
37
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mzustand/middleware.d.cts[39m [2m2.13 kB[22m [2m│ gzip: 0.85 kB[22m
|
|
36
38
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mzustand-commander/commander.d.cts[39m [2m1.63 kB[22m [2m│ gzip: 0.64 kB[22m
|
|
37
|
-
[34mℹ[39m [33m[CJS][39m
|
|
38
|
-
[
|
|
39
|
+
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mzustand/useDraft.d.cts[39m [2m1.45 kB[22m [2m│ gzip: 0.61 kB[22m
|
|
40
|
+
[34mℹ[39m [33m[CJS][39m 15 files, total: 25.23 kB
|
|
41
|
+
[32m✔[39m Build complete in [32m3602ms[39m
|
|
39
42
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[1mzustand-commander/index.mjs[22m [2m 0.47 kB[22m [2m│ gzip: 0.20 kB[22m
|
|
40
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[1mzustand/index.mjs[22m [2m 0.
|
|
43
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[1mzustand/index.mjs[22m [2m 0.11 kB[22m [2m│ gzip: 0.09 kB[22m
|
|
41
44
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[1mindex.mjs[22m [2m 0.01 kB[22m [2m│ gzip: 0.03 kB[22m
|
|
42
45
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand-commander/commander.mjs.map [2m11.46 kB[22m [2m│ gzip: 3.07 kB[22m
|
|
43
46
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand-commander/types.mjs.map [2m10.16 kB[22m [2m│ gzip: 2.60 kB[22m
|
|
44
47
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand-commander/hooks.mjs.map [2m 9.15 kB[22m [2m│ gzip: 2.82 kB[22m
|
|
45
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand/middleware.mjs.map [2m 6.
|
|
48
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand/middleware.mjs.map [2m 6.89 kB[22m [2m│ gzip: 2.11 kB[22m
|
|
46
49
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand-commander/commander.mjs [2m 5.05 kB[22m [2m│ gzip: 1.54 kB[22m
|
|
50
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand/useDraft.mjs.map [2m 4.58 kB[22m [2m│ gzip: 1.56 kB[22m
|
|
47
51
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand-commander/hooks.mjs [2m 3.95 kB[22m [2m│ gzip: 1.46 kB[22m
|
|
48
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand/middleware.mjs [2m 3.
|
|
52
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand/middleware.mjs [2m 3.10 kB[22m [2m│ gzip: 1.15 kB[22m
|
|
49
53
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand-commander/types.d.mts.map [2m 2.75 kB[22m [2m│ gzip: 1.17 kB[22m
|
|
54
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand/useDraft.mjs [2m 1.81 kB[22m [2m│ gzip: 0.66 kB[22m
|
|
50
55
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand/types.d.mts.map [2m 1.24 kB[22m [2m│ gzip: 0.59 kB[22m
|
|
51
56
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m_virtual/_@oxc-project_runtime@0.103.0/helpers/objectSpread2.mjs [2m 0.90 kB[22m [2m│ gzip: 0.42 kB[22m
|
|
52
57
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand-commander/types.mjs [2m 0.84 kB[22m [2m│ gzip: 0.35 kB[22m
|
|
58
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand/useDraft.d.mts.map [2m 0.60 kB[22m [2m│ gzip: 0.30 kB[22m
|
|
53
59
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand-commander/hooks.d.mts.map [2m 0.48 kB[22m [2m│ gzip: 0.30 kB[22m
|
|
54
60
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m_virtual/_@oxc-project_runtime@0.103.0/helpers/toPrimitive.mjs [2m 0.47 kB[22m [2m│ gzip: 0.30 kB[22m
|
|
55
61
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m_virtual/_@oxc-project_runtime@0.103.0/helpers/typeof.mjs [2m 0.43 kB[22m [2m│ gzip: 0.24 kB[22m
|
|
@@ -58,12 +64,13 @@
|
|
|
58
64
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m_virtual/_@oxc-project_runtime@0.103.0/helpers/toPropertyKey.mjs [2m 0.30 kB[22m [2m│ gzip: 0.21 kB[22m
|
|
59
65
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mzustand-commander/commander.d.mts.map [2m 0.30 kB[22m [2m│ gzip: 0.20 kB[22m
|
|
60
66
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32m[1mzustand-commander/index.d.mts[22m[39m [2m 1.14 kB[22m [2m│ gzip: 0.36 kB[22m
|
|
61
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32m[1mzustand/index.d.mts[22m[39m [2m 0.
|
|
67
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32m[1mzustand/index.d.mts[22m[39m [2m 0.34 kB[22m [2m│ gzip: 0.17 kB[22m
|
|
62
68
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32m[1mindex.d.mts[22m[39m [2m 0.01 kB[22m [2m│ gzip: 0.03 kB[22m
|
|
63
69
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mzustand-commander/types.d.mts[39m [2m 7.04 kB[22m [2m│ gzip: 2.06 kB[22m
|
|
64
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mzustand/types.d.mts[39m [2m 3.
|
|
70
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mzustand/types.d.mts[39m [2m 3.23 kB[22m [2m│ gzip: 1.04 kB[22m
|
|
65
71
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mzustand-commander/hooks.d.mts[39m [2m 2.52 kB[22m [2m│ gzip: 0.89 kB[22m
|
|
66
72
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mzustand/middleware.d.mts[39m [2m 2.13 kB[22m [2m│ gzip: 0.85 kB[22m
|
|
67
73
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mzustand-commander/commander.d.mts[39m [2m 1.63 kB[22m [2m│ gzip: 0.64 kB[22m
|
|
68
|
-
[34mℹ[39m [34m[ESM][39m
|
|
69
|
-
[
|
|
74
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mzustand/useDraft.d.mts[39m [2m 1.45 kB[22m [2m│ gzip: 0.61 kB[22m
|
|
75
|
+
[34mℹ[39m [34m[ESM][39m 33 files, total: 85.29 kB
|
|
76
|
+
[32m✔[39m Build complete in [32m3628ms[39m
|
package/dist/zustand/index.cjs
CHANGED
package/dist/zustand/index.d.cts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { MimicMiddlewareOptions, MimicObject, MimicSlice, MimicStateCreator } from "./types.cjs";
|
|
2
2
|
import { mimic } from "./middleware.cjs";
|
|
3
|
-
|
|
3
|
+
import { UseDraftReturn, useDraft } from "./useDraft.cjs";
|
|
4
|
+
export { type MimicMiddlewareOptions, type MimicObject, type MimicSlice, type MimicStateCreator, type UseDraftReturn, mimic, useDraft };
|
package/dist/zustand/index.d.mts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { MimicMiddlewareOptions, MimicObject, MimicSlice, MimicStateCreator } from "./types.mjs";
|
|
2
2
|
import { mimic } from "./middleware.mjs";
|
|
3
|
-
|
|
3
|
+
import { UseDraftReturn, useDraft } from "./useDraft.mjs";
|
|
4
|
+
export { type MimicMiddlewareOptions, type MimicObject, type MimicSlice, type MimicStateCreator, type UseDraftReturn, mimic, useDraft };
|
package/dist/zustand/index.mjs
CHANGED
|
@@ -18,7 +18,8 @@ const createMimicObject = (document) => {
|
|
|
18
18
|
isConnected: document.isConnected(),
|
|
19
19
|
isReady: document.isReady(),
|
|
20
20
|
pendingCount: document.getPendingCount(),
|
|
21
|
-
hasPendingChanges: document.hasPendingChanges()
|
|
21
|
+
hasPendingChanges: document.hasPendingChanges(),
|
|
22
|
+
activeDraftIds: document.getActiveDraftIds()
|
|
22
23
|
};
|
|
23
24
|
};
|
|
24
25
|
/**
|
|
@@ -43,6 +44,9 @@ const mimicImpl = (document, config, options = {}) => {
|
|
|
43
44
|
},
|
|
44
45
|
onReady: () => {
|
|
45
46
|
updateMimicState();
|
|
47
|
+
},
|
|
48
|
+
onDraftChange: () => {
|
|
49
|
+
updateMimicState();
|
|
46
50
|
}
|
|
47
51
|
});
|
|
48
52
|
(_document$presence = document.presence) === null || _document$presence === void 0 || _document$presence.subscribe({ onPresenceChange: () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.cts","names":[],"sources":["../../src/zustand/middleware.ts"],"sourcesContent":[],"mappings":";;;;;;KAaK,eAAA,oBACa,SAAA,CAAU,gCACR,QAAA,CAAS,6EAEd,sDACA,mDAEH,cAAA,CAAe,eAAe,SAAS,oBACzC,aAAa,IAAI,WAAW,SAAS,YAAY,KAAK,KAAK,cACzD,2BACP,aAAa,IAAI,WAAW,SAAS,YAAY,KAAK,KAAK,IAAI,WAAW,SAAS;;AAhBvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"middleware.d.cts","names":[],"sources":["../../src/zustand/middleware.ts"],"sourcesContent":[],"mappings":";;;;;;KAaK,eAAA,oBACa,SAAA,CAAU,gCACR,QAAA,CAAS,6EAEd,sDACA,mDAEH,cAAA,CAAe,eAAe,SAAS,oBACzC,aAAa,IAAI,WAAW,SAAS,YAAY,KAAK,KAAK,cACzD,2BACP,aAAa,IAAI,WAAW,SAAS,YAAY,KAAK,KAAK,IAAI,WAAW,SAAS;;AAhBvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuKjB;;;;;;cAAa,OAAgC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.mts","names":[],"sources":["../../src/zustand/middleware.ts"],"sourcesContent":[],"mappings":";;;;;;KAaK,eAAA,oBACa,SAAA,CAAU,gCACR,QAAA,CAAS,6EAEd,sDACA,mDAEH,cAAA,CAAe,eAAe,SAAS,oBACzC,aAAa,IAAI,WAAW,SAAS,YAAY,KAAK,KAAK,cACzD,2BACP,aAAa,IAAI,WAAW,SAAS,YAAY,KAAK,KAAK,IAAI,WAAW,SAAS;;AAhBvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"middleware.d.mts","names":[],"sources":["../../src/zustand/middleware.ts"],"sourcesContent":[],"mappings":";;;;;;KAaK,eAAA,oBACa,SAAA,CAAU,gCACR,QAAA,CAAS,6EAEd,sDACA,mDAEH,cAAA,CAAe,eAAe,SAAS,oBACzC,aAAa,IAAI,WAAW,SAAS,YAAY,KAAK,KAAK,cACzD,2BACP,aAAa,IAAI,WAAW,SAAS,YAAY,KAAK,KAAK,IAAI,WAAW,SAAS;;AAhBvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuKjB;;;;;;cAAa,OAAgC"}
|
|
@@ -18,7 +18,8 @@ const createMimicObject = (document) => {
|
|
|
18
18
|
isConnected: document.isConnected(),
|
|
19
19
|
isReady: document.isReady(),
|
|
20
20
|
pendingCount: document.getPendingCount(),
|
|
21
|
-
hasPendingChanges: document.hasPendingChanges()
|
|
21
|
+
hasPendingChanges: document.hasPendingChanges(),
|
|
22
|
+
activeDraftIds: document.getActiveDraftIds()
|
|
22
23
|
};
|
|
23
24
|
};
|
|
24
25
|
/**
|
|
@@ -43,6 +44,9 @@ const mimicImpl = (document, config, options = {}) => {
|
|
|
43
44
|
},
|
|
44
45
|
onReady: () => {
|
|
45
46
|
updateMimicState();
|
|
47
|
+
},
|
|
48
|
+
onDraftChange: () => {
|
|
49
|
+
updateMimicState();
|
|
46
50
|
}
|
|
47
51
|
});
|
|
48
52
|
(_document$presence = document.presence) === null || _document$presence === void 0 || _document$presence.subscribe({ onPresenceChange: () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.mjs","names":["mimicImpl: MimicMiddlewareImpl"],"sources":["../../src/zustand/middleware.ts"],"sourcesContent":["import type { StateCreator, StoreMutatorIdentifier } from \"zustand\";\nimport type { ClientDocument } from \"@voidhash/mimic/client\";\nimport type { Primitive, Presence } from \"@voidhash/mimic\";\nimport type {\n MimicSlice,\n MimicObject,\n MimicMiddlewareOptions,\n} from \"./types\";\n\n// =============================================================================\n// Middleware Implementation\n// =============================================================================\n\ntype MimicMiddleware = <\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends Presence.AnyPresence | undefined = undefined,\n T extends object = object,\n Mps extends [StoreMutatorIdentifier, unknown][] = [],\n Mcs extends [StoreMutatorIdentifier, unknown][] = [],\n>(\n document: ClientDocument.ClientDocument<TSchema, TPresence>,\n config: StateCreator<T & MimicSlice<TSchema, TPresence>, Mps, Mcs, T>,\n options?: MimicMiddlewareOptions\n) => StateCreator<T & MimicSlice<TSchema, TPresence>, Mps, Mcs, T & MimicSlice<TSchema, TPresence>>;\n\ntype MimicMiddlewareImpl = <\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends Presence.AnyPresence | undefined = undefined,\n T extends object = object,\n>(\n document: ClientDocument.ClientDocument<TSchema, TPresence>,\n config: StateCreator<T & MimicSlice<TSchema, TPresence>, [], [], T>,\n options?: MimicMiddlewareOptions\n) => StateCreator<T & MimicSlice<TSchema, TPresence>, [], [], T & MimicSlice<TSchema, TPresence>>;\n\n/**\n * Creates a MimicObject from the current document state.\n */\nconst createMimicObject = <\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends Presence.AnyPresence | undefined = undefined\n>(\n document: ClientDocument.ClientDocument<TSchema, TPresence>\n): MimicObject<TSchema, TPresence> => {\n const presence = document.presence\n ? {\n selfId: document.presence.selfId(),\n self: document.presence.self(),\n // Important: clone Maps to ensure zustand selectors re-render\n // when presence changes (the underlying ClientDocument mutates Maps in-place).\n others: new Map(document.presence.others()),\n all: new Map(document.presence.all()),\n }\n : undefined;\n\n return {\n document,\n snapshot: document.root.toSnapshot() as Primitive.InferSnapshot<TSchema>,\n presence: presence as MimicObject<TSchema, TPresence>[\"presence\"],\n isConnected: document.isConnected(),\n isReady: document.isReady(),\n pendingCount: document.getPendingCount(),\n hasPendingChanges: document.hasPendingChanges(),\n };\n};\n\n/**\n * Implementation of the mimic middleware.\n */\nconst mimicImpl: MimicMiddlewareImpl = <\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends Presence.AnyPresence | undefined = undefined,\n _T extends object = object\n>(\n document: ClientDocument.ClientDocument<TSchema, TPresence>,\n config: any,\n options: MimicMiddlewareOptions = {}\n) => {\n const { autoSubscribe = true, autoConnect = true } = options;\n\n return (set: any, get: any, api: any) => {\n // Create initial mimic slice\n const initialMimic = createMimicObject(document);\n\n // Helper to update mimic state\n const updateMimicState = () => {\n const newMimic = createMimicObject(document);\n set(\n (state: any) => ({\n ...state,\n mimic: newMimic,\n }),\n false\n );\n };\n\n // Subscribe to document changes\n if (autoSubscribe) {\n document.subscribe({\n onStateChange: () => {\n updateMimicState();\n },\n onConnectionChange: () => {\n updateMimicState();\n },\n onReady: () => {\n updateMimicState();\n },\n });\n\n // Subscribe to presence changes (if presence schema is enabled)\n document.presence?.subscribe({\n onPresenceChange: () => {\n updateMimicState();\n },\n });\n }\n\n if (autoConnect) {\n document.connect();\n }\n\n // Get user's state - pass through set/get/api directly\n // The user's set calls won't affect mimic state since we update it separately\n const userState = config(set, get, api);\n\n // Combine user state with mimic slice\n return {\n ...userState,\n mimic: initialMimic,\n };\n };\n};\n\n/**\n * Zustand middleware that integrates a ClientDocument.\n * \n * Adds a `mimic` object to the store containing:\n * - `document`: The ClientDocument instance for performing transactions\n * - `snapshot`: Read-only snapshot of the document state (reactive)\n * - `presence`: Reactive presence snapshot (self + others). Undefined if presence is not enabled on the ClientDocument.\n * - `isConnected`: Connection status\n * - `isReady`: Ready status\n * - `pendingCount`: Number of pending transactions\n * - `hasPendingChanges`: Whether there are pending changes\n * \n * @example\n * ```ts\n * import { create } from 'zustand'\n * import { mimic } from '@voidhash/mimic-react/zustand'\n * \n * const useStore = create(\n * mimic(clientDocument, (set, get) => ({\n * // Your additional store state\n * }))\n * )\n * \n * // Read snapshot (reactive)\n * const snapshot = useStore(state => state.mimic.snapshot)\n * \n * // Read presence (reactive, if enabled)\n * const myPresence = useStore(state => state.mimic.presence?.self)\n * const othersPresence = useStore(state => state.mimic.presence?.others)\n * \n * // Write via document\n * store.getState().mimic.document.transaction(root => {\n * root.name.set(\"New Name\")\n * })\n * ```\n */\nexport const mimic = mimicImpl as unknown as MimicMiddleware;\n"],"mappings":";;;;;;AAsCA,MAAM,qBAIJ,aACoC;CACpC,MAAM,WAAW,SAAS,WACtB;EACE,QAAQ,SAAS,SAAS,QAAQ;EAClC,MAAM,SAAS,SAAS,MAAM;EAG9B,QAAQ,IAAI,IAAI,SAAS,SAAS,QAAQ,CAAC;EAC3C,KAAK,IAAI,IAAI,SAAS,SAAS,KAAK,CAAC;EACtC,GACD;AAEJ,QAAO;EACL;EACA,UAAU,SAAS,KAAK,YAAY;EAC1B;EACV,aAAa,SAAS,aAAa;EACnC,SAAS,SAAS,SAAS;EAC3B,cAAc,SAAS,iBAAiB;EACxC,mBAAmB,SAAS,mBAAmB;
|
|
1
|
+
{"version":3,"file":"middleware.mjs","names":["mimicImpl: MimicMiddlewareImpl"],"sources":["../../src/zustand/middleware.ts"],"sourcesContent":["import type { StateCreator, StoreMutatorIdentifier } from \"zustand\";\nimport type { ClientDocument } from \"@voidhash/mimic/client\";\nimport type { Primitive, Presence } from \"@voidhash/mimic\";\nimport type {\n MimicSlice,\n MimicObject,\n MimicMiddlewareOptions,\n} from \"./types\";\n\n// =============================================================================\n// Middleware Implementation\n// =============================================================================\n\ntype MimicMiddleware = <\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends Presence.AnyPresence | undefined = undefined,\n T extends object = object,\n Mps extends [StoreMutatorIdentifier, unknown][] = [],\n Mcs extends [StoreMutatorIdentifier, unknown][] = [],\n>(\n document: ClientDocument.ClientDocument<TSchema, TPresence>,\n config: StateCreator<T & MimicSlice<TSchema, TPresence>, Mps, Mcs, T>,\n options?: MimicMiddlewareOptions\n) => StateCreator<T & MimicSlice<TSchema, TPresence>, Mps, Mcs, T & MimicSlice<TSchema, TPresence>>;\n\ntype MimicMiddlewareImpl = <\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends Presence.AnyPresence | undefined = undefined,\n T extends object = object,\n>(\n document: ClientDocument.ClientDocument<TSchema, TPresence>,\n config: StateCreator<T & MimicSlice<TSchema, TPresence>, [], [], T>,\n options?: MimicMiddlewareOptions\n) => StateCreator<T & MimicSlice<TSchema, TPresence>, [], [], T & MimicSlice<TSchema, TPresence>>;\n\n/**\n * Creates a MimicObject from the current document state.\n */\nconst createMimicObject = <\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends Presence.AnyPresence | undefined = undefined\n>(\n document: ClientDocument.ClientDocument<TSchema, TPresence>\n): MimicObject<TSchema, TPresence> => {\n const presence = document.presence\n ? {\n selfId: document.presence.selfId(),\n self: document.presence.self(),\n // Important: clone Maps to ensure zustand selectors re-render\n // when presence changes (the underlying ClientDocument mutates Maps in-place).\n others: new Map(document.presence.others()),\n all: new Map(document.presence.all()),\n }\n : undefined;\n\n return {\n document,\n snapshot: document.root.toSnapshot() as Primitive.InferSnapshot<TSchema>,\n presence: presence as MimicObject<TSchema, TPresence>[\"presence\"],\n isConnected: document.isConnected(),\n isReady: document.isReady(),\n pendingCount: document.getPendingCount(),\n hasPendingChanges: document.hasPendingChanges(),\n activeDraftIds: document.getActiveDraftIds(),\n };\n};\n\n/**\n * Implementation of the mimic middleware.\n */\nconst mimicImpl: MimicMiddlewareImpl = <\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends Presence.AnyPresence | undefined = undefined,\n _T extends object = object\n>(\n document: ClientDocument.ClientDocument<TSchema, TPresence>,\n config: any,\n options: MimicMiddlewareOptions = {}\n) => {\n const { autoSubscribe = true, autoConnect = true } = options;\n\n return (set: any, get: any, api: any) => {\n // Create initial mimic slice\n const initialMimic = createMimicObject(document);\n\n // Helper to update mimic state\n const updateMimicState = () => {\n const newMimic = createMimicObject(document);\n set(\n (state: any) => ({\n ...state,\n mimic: newMimic,\n }),\n false\n );\n };\n\n // Subscribe to document changes\n if (autoSubscribe) {\n document.subscribe({\n onStateChange: () => {\n updateMimicState();\n },\n onConnectionChange: () => {\n updateMimicState();\n },\n onReady: () => {\n updateMimicState();\n },\n onDraftChange: () => {\n updateMimicState();\n },\n });\n\n // Subscribe to presence changes (if presence schema is enabled)\n document.presence?.subscribe({\n onPresenceChange: () => {\n updateMimicState();\n },\n });\n }\n\n if (autoConnect) {\n document.connect();\n }\n\n // Get user's state - pass through set/get/api directly\n // The user's set calls won't affect mimic state since we update it separately\n const userState = config(set, get, api);\n\n // Combine user state with mimic slice\n return {\n ...userState,\n mimic: initialMimic,\n };\n };\n};\n\n/**\n * Zustand middleware that integrates a ClientDocument.\n * \n * Adds a `mimic` object to the store containing:\n * - `document`: The ClientDocument instance for performing transactions\n * - `snapshot`: Read-only snapshot of the document state (reactive)\n * - `presence`: Reactive presence snapshot (self + others). Undefined if presence is not enabled on the ClientDocument.\n * - `isConnected`: Connection status\n * - `isReady`: Ready status\n * - `pendingCount`: Number of pending transactions\n * - `hasPendingChanges`: Whether there are pending changes\n * \n * @example\n * ```ts\n * import { create } from 'zustand'\n * import { mimic } from '@voidhash/mimic-react/zustand'\n * \n * const useStore = create(\n * mimic(clientDocument, (set, get) => ({\n * // Your additional store state\n * }))\n * )\n * \n * // Read snapshot (reactive)\n * const snapshot = useStore(state => state.mimic.snapshot)\n * \n * // Read presence (reactive, if enabled)\n * const myPresence = useStore(state => state.mimic.presence?.self)\n * const othersPresence = useStore(state => state.mimic.presence?.others)\n * \n * // Write via document\n * store.getState().mimic.document.transaction(root => {\n * root.name.set(\"New Name\")\n * })\n * ```\n */\nexport const mimic = mimicImpl as unknown as MimicMiddleware;\n"],"mappings":";;;;;;AAsCA,MAAM,qBAIJ,aACoC;CACpC,MAAM,WAAW,SAAS,WACtB;EACE,QAAQ,SAAS,SAAS,QAAQ;EAClC,MAAM,SAAS,SAAS,MAAM;EAG9B,QAAQ,IAAI,IAAI,SAAS,SAAS,QAAQ,CAAC;EAC3C,KAAK,IAAI,IAAI,SAAS,SAAS,KAAK,CAAC;EACtC,GACD;AAEJ,QAAO;EACL;EACA,UAAU,SAAS,KAAK,YAAY;EAC1B;EACV,aAAa,SAAS,aAAa;EACnC,SAAS,SAAS,SAAS;EAC3B,cAAc,SAAS,iBAAiB;EACxC,mBAAmB,SAAS,mBAAmB;EAC/C,gBAAgB,SAAS,mBAAmB;EAC7C;;;;;AAMH,MAAMA,aAKJ,UACA,QACA,UAAkC,EAAE,KACjC;CACH,MAAM,EAAE,gBAAgB,MAAM,cAAc,SAAS;AAErD,SAAQ,KAAU,KAAU,QAAa;EAEvC,MAAM,eAAe,kBAAkB,SAAS;EAGhD,MAAM,yBAAyB;GAC7B,MAAM,WAAW,kBAAkB,SAAS;AAC5C,QACG,4CACI,cACH,OAAO,aAET,MACD;;AAIH,MAAI,eAAe;;AACjB,YAAS,UAAU;IACjB,qBAAqB;AACnB,uBAAkB;;IAEpB,0BAA0B;AACxB,uBAAkB;;IAEpB,eAAe;AACb,uBAAkB;;IAEpB,qBAAqB;AACnB,uBAAkB;;IAErB,CAAC;AAGF,kCAAS,0EAAU,UAAU,EAC3B,wBAAwB;AACtB,sBAAkB;MAErB,CAAC;;AAGJ,MAAI,YACF,UAAS,SAAS;AAQpB,2CAHkB,OAAO,KAAK,KAAK,IAAI,SAKrC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCb,MAAa,QAAQ"}
|
package/dist/zustand/types.d.cts
CHANGED
|
@@ -49,6 +49,8 @@ interface MimicObject<TSchema extends Primitive.AnyPrimitive, TPresence extends
|
|
|
49
49
|
readonly pendingCount: number;
|
|
50
50
|
/** Whether there are pending changes */
|
|
51
51
|
readonly hasPendingChanges: boolean;
|
|
52
|
+
/** Set of active draft IDs */
|
|
53
|
+
readonly activeDraftIds: ReadonlySet<string>;
|
|
52
54
|
}
|
|
53
55
|
/**
|
|
54
56
|
* The state slice added by the mimic middleware.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.cts","names":[],"sources":["../../src/zustand/types.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAWA;AAAiD,UAAhC,aAAyC,CAAA,kBAAT,QAAA,CAAS,WAAA,CAAA,CAAA;EAW1B;;;;EAO5B,SAAS,MAAA,EAAA,MAAA,GAAA,SAAA;EAFM;;;;EAQH,SAAA,IAAA,EAbC,QAAA,CAAS,KAaV,CAbgB,SAahB,CAAA,GAAA,SAAA;EAAW;AAU3B;;EAEoB,SAAS,MAAA,EApBV,WAoBU,CAAA,MAAA,EAlBzB,QAAA,CAAS,aAkBgB,CAlBF,QAAA,CAAS,KAkBP,CAlBa,SAkBb,CAAA,CAAA,CAAA;EAGsB;;;EAEN,SAAA,GAAA,EAjB7B,WAiB6B,CAAA,MAAA,EAfzC,QAAA,CAAS,aAegC,CAflB,QAAA,CAAS,KAeS,CAfH,SAeG,CAAA,CAAA,CAAA;;;;;;
|
|
1
|
+
{"version":3,"file":"types.d.cts","names":[],"sources":["../../src/zustand/types.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAWA;AAAiD,UAAhC,aAAyC,CAAA,kBAAT,QAAA,CAAS,WAAA,CAAA,CAAA;EAW1B;;;;EAO5B,SAAS,MAAA,EAAA,MAAA,GAAA,SAAA;EAFM;;;;EAQH,SAAA,IAAA,EAbC,QAAA,CAAS,KAaV,CAbgB,SAahB,CAAA,GAAA,SAAA;EAAW;AAU3B;;EAEoB,SAAS,MAAA,EApBV,WAoBU,CAAA,MAAA,EAlBzB,QAAA,CAAS,aAkBgB,CAlBF,QAAA,CAAS,KAkBP,CAlBa,SAkBb,CAAA,CAAA,CAAA;EAGsB;;;EAEN,SAAA,GAAA,EAjB7B,WAiB6B,CAAA,MAAA,EAfzC,QAAA,CAAS,aAegC,CAflB,QAAA,CAAS,KAeS,CAfH,SAeG,CAAA,CAAA,CAAA;;;;;;AAiBlB,UAxBV,WAwBU,CAAA,gBAvBT,SAAA,CAAU,YAuBD,EAAA,kBAtBP,QAAA,CAAS,WAsBF,GAAA,SAAA,GAAA,SAAA,CAAA,CAAA;EAAW;EAMrB,SAAA,QAAU,EAzBN,cAAA,CAAe,cAyBT,CAzBwB,OAyBxB,EAzBiC,SAyBjC,CAAA;EACT;EACE,SAAS,QAAA,EAzBR,SAAA,CAAU,aAyBF,CAzBgB,OAyBhB,CAAA;EAGC;;;;EAsBlB,SAAA,QAAA,EA7CS,SA6CQ,SA7CU,QAAA,CAAS,WA6CnB,GA5CvB,aA4CuB,CA5CT,SA4CS,CAAA,GAAA,SAAA;EACX;EACE,SAAS,WAAA,EAAA,OAAA;EAEd;EACA,SAAA,OAAA,EAAA,OAAA;EACE;EAAe,SAAA,YAAA,EAAA,MAAA;EAAS;EAApB,SAAA,iBAAA,EAAA,OAAA;EAAgC;EAAK,SAAA,cAAA,EAvC/B,WAuC+B,CAAA,MAAA,CAAA;;;;AAK1D;UAtCiB,2BACC,SAAA,CAAU,gCACR,QAAA,CAAS;;kBAGX,YAAY,SAAS;;;;;KAsB3B,kCACM,SAAA,CAAU,gCACR,QAAA,CAAS,yCAEd,sDACA,2CACX,aAAa,IAAI,WAAW,SAAS,YAAY,KAAK,KAAK;;;;UAK9C,sBAAA"}
|
package/dist/zustand/types.d.mts
CHANGED
|
@@ -49,6 +49,8 @@ interface MimicObject<TSchema extends Primitive.AnyPrimitive, TPresence extends
|
|
|
49
49
|
readonly pendingCount: number;
|
|
50
50
|
/** Whether there are pending changes */
|
|
51
51
|
readonly hasPendingChanges: boolean;
|
|
52
|
+
/** Set of active draft IDs */
|
|
53
|
+
readonly activeDraftIds: ReadonlySet<string>;
|
|
52
54
|
}
|
|
53
55
|
/**
|
|
54
56
|
* The state slice added by the mimic middleware.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../src/zustand/types.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAWA;AAAiD,UAAhC,aAAyC,CAAA,kBAAT,QAAA,CAAS,WAAA,CAAA,CAAA;EAW1B;;;;EAO5B,SAAS,MAAA,EAAA,MAAA,GAAA,SAAA;EAFM;;;;EAQH,SAAA,IAAA,EAbC,QAAA,CAAS,KAaV,CAbgB,SAahB,CAAA,GAAA,SAAA;EAAW;AAU3B;;EAEoB,SAAS,MAAA,EApBV,WAoBU,CAAA,MAAA,EAlBzB,QAAA,CAAS,aAkBgB,CAlBF,QAAA,CAAS,KAkBP,CAlBa,SAkBb,CAAA,CAAA,CAAA;EAGsB;;;EAEN,SAAA,GAAA,EAjB7B,WAiB6B,CAAA,MAAA,EAfzC,QAAA,CAAS,aAegC,CAflB,QAAA,CAAS,KAeS,CAfH,SAeG,CAAA,CAAA,CAAA;;;;;;
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../../src/zustand/types.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAWA;AAAiD,UAAhC,aAAyC,CAAA,kBAAT,QAAA,CAAS,WAAA,CAAA,CAAA;EAW1B;;;;EAO5B,SAAS,MAAA,EAAA,MAAA,GAAA,SAAA;EAFM;;;;EAQH,SAAA,IAAA,EAbC,QAAA,CAAS,KAaV,CAbgB,SAahB,CAAA,GAAA,SAAA;EAAW;AAU3B;;EAEoB,SAAS,MAAA,EApBV,WAoBU,CAAA,MAAA,EAlBzB,QAAA,CAAS,aAkBgB,CAlBF,QAAA,CAAS,KAkBP,CAlBa,SAkBb,CAAA,CAAA,CAAA;EAGsB;;;EAEN,SAAA,GAAA,EAjB7B,WAiB6B,CAAA,MAAA,EAfzC,QAAA,CAAS,aAegC,CAflB,QAAA,CAAS,KAeS,CAfH,SAeG,CAAA,CAAA,CAAA;;;;;;AAiBlB,UAxBV,WAwBU,CAAA,gBAvBT,SAAA,CAAU,YAuBD,EAAA,kBAtBP,QAAA,CAAS,WAsBF,GAAA,SAAA,GAAA,SAAA,CAAA,CAAA;EAAW;EAMrB,SAAA,QAAU,EAzBN,cAAA,CAAe,cAyBT,CAzBwB,OAyBxB,EAzBiC,SAyBjC,CAAA;EACT;EACE,SAAS,QAAA,EAzBR,SAAA,CAAU,aAyBF,CAzBgB,OAyBhB,CAAA;EAGC;;;;EAsBlB,SAAA,QAAA,EA7CS,SA6CQ,SA7CU,QAAA,CAAS,WA6CnB,GA5CvB,aA4CuB,CA5CT,SA4CS,CAAA,GAAA,SAAA;EACX;EACE,SAAS,WAAA,EAAA,OAAA;EAEd;EACA,SAAA,OAAA,EAAA,OAAA;EACE;EAAe,SAAA,YAAA,EAAA,MAAA;EAAS;EAApB,SAAA,iBAAA,EAAA,OAAA;EAAgC;EAAK,SAAA,cAAA,EAvC/B,WAuC+B,CAAA,MAAA,CAAA;;;;AAK1D;UAtCiB,2BACC,SAAA,CAAU,gCACR,QAAA,CAAS;;kBAGX,YAAY,SAAS;;;;;KAsB3B,kCACM,SAAA,CAAU,gCACR,QAAA,CAAS,yCAEd,sDACA,2CACX,aAAa,IAAI,WAAW,SAAS,YAAY,KAAK,KAAK;;;;UAK9C,sBAAA"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
let react = require("react");
|
|
2
|
+
|
|
3
|
+
//#region src/zustand/useDraft.ts
|
|
4
|
+
/**
|
|
5
|
+
* React hook for managing a draft lifecycle with auto-cleanup on unmount.
|
|
6
|
+
*
|
|
7
|
+
* @param store - The zustand store containing the mimic slice
|
|
8
|
+
* @returns Draft control methods
|
|
9
|
+
*/
|
|
10
|
+
const useDraft = (store) => {
|
|
11
|
+
const draftRef = (0, react.useRef)(null);
|
|
12
|
+
const versionRef = (0, react.useRef)(0);
|
|
13
|
+
const subscribe = (0, react.useCallback)((onStoreChange) => {
|
|
14
|
+
return store.subscribe(onStoreChange);
|
|
15
|
+
}, [store]);
|
|
16
|
+
const getSnapshot = (0, react.useCallback)(() => {
|
|
17
|
+
return versionRef.current;
|
|
18
|
+
}, []);
|
|
19
|
+
(0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
20
|
+
const bumpVersion = (0, react.useCallback)(() => {
|
|
21
|
+
versionRef.current++;
|
|
22
|
+
}, []);
|
|
23
|
+
const begin = (0, react.useCallback)(() => {
|
|
24
|
+
if (draftRef.current !== null) throw new Error("A draft is already active. Commit or discard it first.");
|
|
25
|
+
draftRef.current = store.getState().mimic.document.createDraft();
|
|
26
|
+
bumpVersion();
|
|
27
|
+
}, [store, bumpVersion]);
|
|
28
|
+
const commit = (0, react.useCallback)(() => {
|
|
29
|
+
if (draftRef.current === null) return;
|
|
30
|
+
draftRef.current.commit();
|
|
31
|
+
draftRef.current = null;
|
|
32
|
+
bumpVersion();
|
|
33
|
+
}, [bumpVersion]);
|
|
34
|
+
const discard = (0, react.useCallback)(() => {
|
|
35
|
+
if (draftRef.current === null) return;
|
|
36
|
+
draftRef.current.discard();
|
|
37
|
+
draftRef.current = null;
|
|
38
|
+
bumpVersion();
|
|
39
|
+
}, [bumpVersion]);
|
|
40
|
+
const update = (0, react.useCallback)((fn) => {
|
|
41
|
+
if (draftRef.current === null) throw new Error("No active draft. Call begin() first.");
|
|
42
|
+
draftRef.current.update(fn);
|
|
43
|
+
}, []);
|
|
44
|
+
(0, react.useEffect)(() => {
|
|
45
|
+
return () => {
|
|
46
|
+
if (draftRef.current !== null) {
|
|
47
|
+
try {
|
|
48
|
+
draftRef.current.discard();
|
|
49
|
+
} catch (_unused) {}
|
|
50
|
+
draftRef.current = null;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}, []);
|
|
54
|
+
return {
|
|
55
|
+
draft: draftRef.current,
|
|
56
|
+
begin,
|
|
57
|
+
commit,
|
|
58
|
+
discard,
|
|
59
|
+
update
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
exports.useDraft = useDraft;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { MimicSlice } from "./types.cjs";
|
|
2
|
+
import { StoreApi } from "zustand";
|
|
3
|
+
import { ClientDocument } from "@voidhash/mimic/client";
|
|
4
|
+
import * as _voidhash_mimic0 from "@voidhash/mimic";
|
|
5
|
+
import { Primitive } from "@voidhash/mimic";
|
|
6
|
+
|
|
7
|
+
//#region src/zustand/useDraft.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* Return type of the useDraft hook.
|
|
10
|
+
*/
|
|
11
|
+
interface UseDraftReturn<TSchema extends Primitive.AnyPrimitive> {
|
|
12
|
+
/** The active draft handle, or null if no draft is active */
|
|
13
|
+
readonly draft: ClientDocument.DraftHandle<TSchema> | null;
|
|
14
|
+
/** Creates a new draft. Throws if a draft is already active. */
|
|
15
|
+
readonly begin: () => void;
|
|
16
|
+
/** Commits the active draft. No-op if no draft is active. */
|
|
17
|
+
readonly commit: () => void;
|
|
18
|
+
/** Discards the active draft. No-op if no draft is active. */
|
|
19
|
+
readonly discard: () => void;
|
|
20
|
+
/** Runs an update on the active draft. Throws if no draft is active. */
|
|
21
|
+
readonly update: (fn: (root: Primitive.InferProxy<TSchema>) => void) => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* React hook for managing a draft lifecycle with auto-cleanup on unmount.
|
|
25
|
+
*
|
|
26
|
+
* @param store - The zustand store containing the mimic slice
|
|
27
|
+
* @returns Draft control methods
|
|
28
|
+
*/
|
|
29
|
+
declare const useDraft: <TSchema extends Primitive.AnyPrimitive, TPresence extends _voidhash_mimic0.Presence.AnyPresence | undefined = undefined>(store: StoreApi<MimicSlice<TSchema, TPresence>>) => UseDraftReturn<TSchema>;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { UseDraftReturn, useDraft };
|
|
32
|
+
//# sourceMappingURL=useDraft.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDraft.d.cts","names":[],"sources":["../../src/zustand/useDraft.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAUiB,UAAA,cAAc,CAAA,gBAAiB,SAAA,CAAU,YAA3B,CAAA,CAAA;EAAiB;EAEH,SAAA,KAAA,EAA3B,cAAA,CAAe,WAAY,CAAA,OAAA,CAAA,GAAA,IAAA;EAA3B;EAQkC,SAAA,KAAA,EAAA,GAAA,GAAA,IAAA;EAArB;EAAoB,SAAA,MAAA,EAAA,GAAA,GAAA,IAAA;EAStC;EACK,SAAU,OAAA,EAAA,GAAA,GAAA,IAAA;EACkB;EAEjB,SAAA,MAAA,EAAA,CAAA,EAAA,EAAA,CAAA,IAAA,EAbE,SAAA,CAAU,UAaZ,CAbuB,OAavB,CAAA,EAAA,GAAA,IAAA,EAAA,GAAA,IAAA;;;;;;;;cAJhB,2BACK,SAAA,CAAU,gCACkB,gBAAA,CAAA,QAAA,CAAS,WAAA,iCAE9C,SAAS,WAAW,SAAS,gBACnC,eAAe"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { MimicSlice } from "./types.mjs";
|
|
2
|
+
import { StoreApi } from "zustand";
|
|
3
|
+
import { ClientDocument } from "@voidhash/mimic/client";
|
|
4
|
+
import * as _voidhash_mimic0 from "@voidhash/mimic";
|
|
5
|
+
import { Primitive } from "@voidhash/mimic";
|
|
6
|
+
|
|
7
|
+
//#region src/zustand/useDraft.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* Return type of the useDraft hook.
|
|
10
|
+
*/
|
|
11
|
+
interface UseDraftReturn<TSchema extends Primitive.AnyPrimitive> {
|
|
12
|
+
/** The active draft handle, or null if no draft is active */
|
|
13
|
+
readonly draft: ClientDocument.DraftHandle<TSchema> | null;
|
|
14
|
+
/** Creates a new draft. Throws if a draft is already active. */
|
|
15
|
+
readonly begin: () => void;
|
|
16
|
+
/** Commits the active draft. No-op if no draft is active. */
|
|
17
|
+
readonly commit: () => void;
|
|
18
|
+
/** Discards the active draft. No-op if no draft is active. */
|
|
19
|
+
readonly discard: () => void;
|
|
20
|
+
/** Runs an update on the active draft. Throws if no draft is active. */
|
|
21
|
+
readonly update: (fn: (root: Primitive.InferProxy<TSchema>) => void) => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* React hook for managing a draft lifecycle with auto-cleanup on unmount.
|
|
25
|
+
*
|
|
26
|
+
* @param store - The zustand store containing the mimic slice
|
|
27
|
+
* @returns Draft control methods
|
|
28
|
+
*/
|
|
29
|
+
declare const useDraft: <TSchema extends Primitive.AnyPrimitive, TPresence extends _voidhash_mimic0.Presence.AnyPresence | undefined = undefined>(store: StoreApi<MimicSlice<TSchema, TPresence>>) => UseDraftReturn<TSchema>;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { UseDraftReturn, useDraft };
|
|
32
|
+
//# sourceMappingURL=useDraft.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDraft.d.mts","names":[],"sources":["../../src/zustand/useDraft.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAUiB,UAAA,cAAc,CAAA,gBAAiB,SAAA,CAAU,YAA3B,CAAA,CAAA;EAAiB;EAEH,SAAA,KAAA,EAA3B,cAAA,CAAe,WAAY,CAAA,OAAA,CAAA,GAAA,IAAA;EAA3B;EAQkC,SAAA,KAAA,EAAA,GAAA,GAAA,IAAA;EAArB;EAAoB,SAAA,MAAA,EAAA,GAAA,GAAA,IAAA;EAStC;EACK,SAAU,OAAA,EAAA,GAAA,GAAA,IAAA;EACkB;EAEjB,SAAA,MAAA,EAAA,CAAA,EAAA,EAAA,CAAA,IAAA,EAbE,SAAA,CAAU,UAaZ,CAbuB,OAavB,CAAA,EAAA,GAAA,IAAA,EAAA,GAAA,IAAA;;;;;;;;cAJhB,2BACK,SAAA,CAAU,gCACkB,gBAAA,CAAA,QAAA,CAAS,WAAA,iCAE9C,SAAS,WAAW,SAAS,gBACnC,eAAe"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useSyncExternalStore } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/zustand/useDraft.ts
|
|
4
|
+
/**
|
|
5
|
+
* React hook for managing a draft lifecycle with auto-cleanup on unmount.
|
|
6
|
+
*
|
|
7
|
+
* @param store - The zustand store containing the mimic slice
|
|
8
|
+
* @returns Draft control methods
|
|
9
|
+
*/
|
|
10
|
+
const useDraft = (store) => {
|
|
11
|
+
const draftRef = useRef(null);
|
|
12
|
+
const versionRef = useRef(0);
|
|
13
|
+
const subscribe = useCallback((onStoreChange) => {
|
|
14
|
+
return store.subscribe(onStoreChange);
|
|
15
|
+
}, [store]);
|
|
16
|
+
const getSnapshot = useCallback(() => {
|
|
17
|
+
return versionRef.current;
|
|
18
|
+
}, []);
|
|
19
|
+
useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
20
|
+
const bumpVersion = useCallback(() => {
|
|
21
|
+
versionRef.current++;
|
|
22
|
+
}, []);
|
|
23
|
+
const begin = useCallback(() => {
|
|
24
|
+
if (draftRef.current !== null) throw new Error("A draft is already active. Commit or discard it first.");
|
|
25
|
+
draftRef.current = store.getState().mimic.document.createDraft();
|
|
26
|
+
bumpVersion();
|
|
27
|
+
}, [store, bumpVersion]);
|
|
28
|
+
const commit = useCallback(() => {
|
|
29
|
+
if (draftRef.current === null) return;
|
|
30
|
+
draftRef.current.commit();
|
|
31
|
+
draftRef.current = null;
|
|
32
|
+
bumpVersion();
|
|
33
|
+
}, [bumpVersion]);
|
|
34
|
+
const discard = useCallback(() => {
|
|
35
|
+
if (draftRef.current === null) return;
|
|
36
|
+
draftRef.current.discard();
|
|
37
|
+
draftRef.current = null;
|
|
38
|
+
bumpVersion();
|
|
39
|
+
}, [bumpVersion]);
|
|
40
|
+
const update = useCallback((fn) => {
|
|
41
|
+
if (draftRef.current === null) throw new Error("No active draft. Call begin() first.");
|
|
42
|
+
draftRef.current.update(fn);
|
|
43
|
+
}, []);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
return () => {
|
|
46
|
+
if (draftRef.current !== null) {
|
|
47
|
+
try {
|
|
48
|
+
draftRef.current.discard();
|
|
49
|
+
} catch (_unused) {}
|
|
50
|
+
draftRef.current = null;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}, []);
|
|
54
|
+
return {
|
|
55
|
+
draft: draftRef.current,
|
|
56
|
+
begin,
|
|
57
|
+
commit,
|
|
58
|
+
discard,
|
|
59
|
+
update
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
export { useDraft };
|
|
65
|
+
//# sourceMappingURL=useDraft.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDraft.mjs","names":[],"sources":["../../src/zustand/useDraft.ts"],"sourcesContent":["import { useRef, useCallback, useEffect } from \"react\";\nimport { useSyncExternalStore } from \"react\";\nimport type { StoreApi } from \"zustand\";\nimport type { ClientDocument } from \"@voidhash/mimic/client\";\nimport type { Primitive } from \"@voidhash/mimic\";\nimport type { MimicSlice } from \"./types\";\n\n/**\n * Return type of the useDraft hook.\n */\nexport interface UseDraftReturn<TSchema extends Primitive.AnyPrimitive> {\n /** The active draft handle, or null if no draft is active */\n readonly draft: ClientDocument.DraftHandle<TSchema> | null;\n /** Creates a new draft. Throws if a draft is already active. */\n readonly begin: () => void;\n /** Commits the active draft. No-op if no draft is active. */\n readonly commit: () => void;\n /** Discards the active draft. No-op if no draft is active. */\n readonly discard: () => void;\n /** Runs an update on the active draft. Throws if no draft is active. */\n readonly update: (fn: (root: Primitive.InferProxy<TSchema>) => void) => void;\n}\n\n/**\n * React hook for managing a draft lifecycle with auto-cleanup on unmount.\n *\n * @param store - The zustand store containing the mimic slice\n * @returns Draft control methods\n */\nexport const useDraft = <\n TSchema extends Primitive.AnyPrimitive,\n TPresence extends import(\"@voidhash/mimic\").Presence.AnyPresence | undefined = undefined,\n>(\n store: StoreApi<MimicSlice<TSchema, TPresence>>\n): UseDraftReturn<TSchema> => {\n const draftRef = useRef<ClientDocument.DraftHandle<TSchema> | null>(null);\n // Use a counter to force re-renders when draft state changes\n const versionRef = useRef(0);\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n // We piggyback on the zustand store subscription to know when drafts change\n return store.subscribe(onStoreChange);\n },\n [store]\n );\n\n const getSnapshot = useCallback(() => {\n return versionRef.current;\n }, []);\n\n useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const bumpVersion = useCallback(() => {\n versionRef.current++;\n }, []);\n\n const begin = useCallback(() => {\n if (draftRef.current !== null) {\n throw new Error(\"A draft is already active. Commit or discard it first.\");\n }\n const document = store.getState().mimic.document;\n draftRef.current = document.createDraft();\n bumpVersion();\n }, [store, bumpVersion]);\n\n const commit = useCallback(() => {\n if (draftRef.current === null) return;\n draftRef.current.commit();\n draftRef.current = null;\n bumpVersion();\n }, [bumpVersion]);\n\n const discard = useCallback(() => {\n if (draftRef.current === null) return;\n draftRef.current.discard();\n draftRef.current = null;\n bumpVersion();\n }, [bumpVersion]);\n\n const update = useCallback(\n (fn: (root: Primitive.InferProxy<TSchema>) => void) => {\n if (draftRef.current === null) {\n throw new Error(\"No active draft. Call begin() first.\");\n }\n draftRef.current.update(fn);\n },\n []\n );\n\n // Auto-discard on unmount\n useEffect(() => {\n return () => {\n if (draftRef.current !== null) {\n try {\n draftRef.current.discard();\n } catch {\n // Draft may already be consumed\n }\n draftRef.current = null;\n }\n };\n }, []);\n\n return {\n draft: draftRef.current,\n begin,\n commit,\n discard,\n update,\n };\n};\n"],"mappings":";;;;;;;;;AA6BA,MAAa,YAIX,UAC4B;CAC5B,MAAM,WAAW,OAAmD,KAAK;CAEzE,MAAM,aAAa,OAAO,EAAE;CAE5B,MAAM,YAAY,aACf,kBAA8B;AAE7B,SAAO,MAAM,UAAU,cAAc;IAEvC,CAAC,MAAM,CACR;CAED,MAAM,cAAc,kBAAkB;AACpC,SAAO,WAAW;IACjB,EAAE,CAAC;AAEN,sBAAqB,WAAW,aAAa,YAAY;CAEzD,MAAM,cAAc,kBAAkB;AACpC,aAAW;IACV,EAAE,CAAC;CAEN,MAAM,QAAQ,kBAAkB;AAC9B,MAAI,SAAS,YAAY,KACvB,OAAM,IAAI,MAAM,yDAAyD;AAG3E,WAAS,UADQ,MAAM,UAAU,CAAC,MAAM,SACZ,aAAa;AACzC,eAAa;IACZ,CAAC,OAAO,YAAY,CAAC;CAExB,MAAM,SAAS,kBAAkB;AAC/B,MAAI,SAAS,YAAY,KAAM;AAC/B,WAAS,QAAQ,QAAQ;AACzB,WAAS,UAAU;AACnB,eAAa;IACZ,CAAC,YAAY,CAAC;CAEjB,MAAM,UAAU,kBAAkB;AAChC,MAAI,SAAS,YAAY,KAAM;AAC/B,WAAS,QAAQ,SAAS;AAC1B,WAAS,UAAU;AACnB,eAAa;IACZ,CAAC,YAAY,CAAC;CAEjB,MAAM,SAAS,aACZ,OAAsD;AACrD,MAAI,SAAS,YAAY,KACvB,OAAM,IAAI,MAAM,uCAAuC;AAEzD,WAAS,QAAQ,OAAO,GAAG;IAE7B,EAAE,CACH;AAGD,iBAAgB;AACd,eAAa;AACX,OAAI,SAAS,YAAY,MAAM;AAC7B,QAAI;AACF,cAAS,QAAQ,SAAS;sBACpB;AAGR,aAAS,UAAU;;;IAGtB,EAAE,CAAC;AAEN,QAAO;EACL,OAAO,SAAS;EAChB;EACA;EACA;EACA;EACD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voidhash/mimic-react",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -37,12 +37,12 @@
|
|
|
37
37
|
"typescript": "5.8.3",
|
|
38
38
|
"vite-tsconfig-paths": "^5.1.4",
|
|
39
39
|
"vitest": "^3.2.4",
|
|
40
|
-
"@voidhash/tsconfig": "1.0.0-beta.
|
|
40
|
+
"@voidhash/tsconfig": "1.0.0-beta.13"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"effect": "^3.16.0",
|
|
44
44
|
"react": "^18.0.0 || ^19.0.0",
|
|
45
|
-
"@voidhash/mimic": "1.0.0-beta.
|
|
45
|
+
"@voidhash/mimic": "1.0.0-beta.13"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"build": "tsdown",
|
package/src/zustand/index.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
// =============================================================================
|
|
12
12
|
|
|
13
13
|
export { mimic } from "./middleware";
|
|
14
|
+
export { useDraft } from "./useDraft";
|
|
14
15
|
|
|
15
16
|
// =============================================================================
|
|
16
17
|
// Types
|
|
@@ -22,3 +23,5 @@ export type {
|
|
|
22
23
|
MimicMiddlewareOptions,
|
|
23
24
|
MimicStateCreator,
|
|
24
25
|
} from "./types";
|
|
26
|
+
|
|
27
|
+
export type { UseDraftReturn } from "./useDraft";
|
|
@@ -61,6 +61,7 @@ const createMimicObject = <
|
|
|
61
61
|
isReady: document.isReady(),
|
|
62
62
|
pendingCount: document.getPendingCount(),
|
|
63
63
|
hasPendingChanges: document.hasPendingChanges(),
|
|
64
|
+
activeDraftIds: document.getActiveDraftIds(),
|
|
64
65
|
};
|
|
65
66
|
};
|
|
66
67
|
|
|
@@ -106,6 +107,9 @@ const mimicImpl: MimicMiddlewareImpl = <
|
|
|
106
107
|
onReady: () => {
|
|
107
108
|
updateMimicState();
|
|
108
109
|
},
|
|
110
|
+
onDraftChange: () => {
|
|
111
|
+
updateMimicState();
|
|
112
|
+
},
|
|
109
113
|
});
|
|
110
114
|
|
|
111
115
|
// Subscribe to presence changes (if presence schema is enabled)
|
package/src/zustand/types.ts
CHANGED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { useRef, useCallback, useEffect } from "react";
|
|
2
|
+
import { useSyncExternalStore } from "react";
|
|
3
|
+
import type { StoreApi } from "zustand";
|
|
4
|
+
import type { ClientDocument } from "@voidhash/mimic/client";
|
|
5
|
+
import type { Primitive } from "@voidhash/mimic";
|
|
6
|
+
import type { MimicSlice } from "./types";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Return type of the useDraft hook.
|
|
10
|
+
*/
|
|
11
|
+
export interface UseDraftReturn<TSchema extends Primitive.AnyPrimitive> {
|
|
12
|
+
/** The active draft handle, or null if no draft is active */
|
|
13
|
+
readonly draft: ClientDocument.DraftHandle<TSchema> | null;
|
|
14
|
+
/** Creates a new draft. Throws if a draft is already active. */
|
|
15
|
+
readonly begin: () => void;
|
|
16
|
+
/** Commits the active draft. No-op if no draft is active. */
|
|
17
|
+
readonly commit: () => void;
|
|
18
|
+
/** Discards the active draft. No-op if no draft is active. */
|
|
19
|
+
readonly discard: () => void;
|
|
20
|
+
/** Runs an update on the active draft. Throws if no draft is active. */
|
|
21
|
+
readonly update: (fn: (root: Primitive.InferProxy<TSchema>) => void) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* React hook for managing a draft lifecycle with auto-cleanup on unmount.
|
|
26
|
+
*
|
|
27
|
+
* @param store - The zustand store containing the mimic slice
|
|
28
|
+
* @returns Draft control methods
|
|
29
|
+
*/
|
|
30
|
+
export const useDraft = <
|
|
31
|
+
TSchema extends Primitive.AnyPrimitive,
|
|
32
|
+
TPresence extends import("@voidhash/mimic").Presence.AnyPresence | undefined = undefined,
|
|
33
|
+
>(
|
|
34
|
+
store: StoreApi<MimicSlice<TSchema, TPresence>>
|
|
35
|
+
): UseDraftReturn<TSchema> => {
|
|
36
|
+
const draftRef = useRef<ClientDocument.DraftHandle<TSchema> | null>(null);
|
|
37
|
+
// Use a counter to force re-renders when draft state changes
|
|
38
|
+
const versionRef = useRef(0);
|
|
39
|
+
|
|
40
|
+
const subscribe = useCallback(
|
|
41
|
+
(onStoreChange: () => void) => {
|
|
42
|
+
// We piggyback on the zustand store subscription to know when drafts change
|
|
43
|
+
return store.subscribe(onStoreChange);
|
|
44
|
+
},
|
|
45
|
+
[store]
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const getSnapshot = useCallback(() => {
|
|
49
|
+
return versionRef.current;
|
|
50
|
+
}, []);
|
|
51
|
+
|
|
52
|
+
useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
53
|
+
|
|
54
|
+
const bumpVersion = useCallback(() => {
|
|
55
|
+
versionRef.current++;
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
58
|
+
const begin = useCallback(() => {
|
|
59
|
+
if (draftRef.current !== null) {
|
|
60
|
+
throw new Error("A draft is already active. Commit or discard it first.");
|
|
61
|
+
}
|
|
62
|
+
const document = store.getState().mimic.document;
|
|
63
|
+
draftRef.current = document.createDraft();
|
|
64
|
+
bumpVersion();
|
|
65
|
+
}, [store, bumpVersion]);
|
|
66
|
+
|
|
67
|
+
const commit = useCallback(() => {
|
|
68
|
+
if (draftRef.current === null) return;
|
|
69
|
+
draftRef.current.commit();
|
|
70
|
+
draftRef.current = null;
|
|
71
|
+
bumpVersion();
|
|
72
|
+
}, [bumpVersion]);
|
|
73
|
+
|
|
74
|
+
const discard = useCallback(() => {
|
|
75
|
+
if (draftRef.current === null) return;
|
|
76
|
+
draftRef.current.discard();
|
|
77
|
+
draftRef.current = null;
|
|
78
|
+
bumpVersion();
|
|
79
|
+
}, [bumpVersion]);
|
|
80
|
+
|
|
81
|
+
const update = useCallback(
|
|
82
|
+
(fn: (root: Primitive.InferProxy<TSchema>) => void) => {
|
|
83
|
+
if (draftRef.current === null) {
|
|
84
|
+
throw new Error("No active draft. Call begin() first.");
|
|
85
|
+
}
|
|
86
|
+
draftRef.current.update(fn);
|
|
87
|
+
},
|
|
88
|
+
[]
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// Auto-discard on unmount
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
return () => {
|
|
94
|
+
if (draftRef.current !== null) {
|
|
95
|
+
try {
|
|
96
|
+
draftRef.current.discard();
|
|
97
|
+
} catch {
|
|
98
|
+
// Draft may already be consumed
|
|
99
|
+
}
|
|
100
|
+
draftRef.current = null;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}, []);
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
draft: draftRef.current,
|
|
107
|
+
begin,
|
|
108
|
+
commit,
|
|
109
|
+
discard,
|
|
110
|
+
update,
|
|
111
|
+
};
|
|
112
|
+
};
|
|
@@ -79,6 +79,10 @@ const createMockClientDocument = (
|
|
|
79
79
|
isReady: () => state.isReady,
|
|
80
80
|
getPendingCount: () => state.pendingCount,
|
|
81
81
|
hasPendingChanges: () => state.hasPendingChanges,
|
|
82
|
+
getActiveDraftIds: () => new Set<string>(),
|
|
83
|
+
createDraft: () => {
|
|
84
|
+
throw new Error("Not implemented in mock");
|
|
85
|
+
},
|
|
82
86
|
connect: () => {
|
|
83
87
|
// Mock connect - does nothing in tests
|
|
84
88
|
},
|