doxum 0.1.10 → 0.1.12
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 +8 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{integration-BKgGuodm.cjs → integration-BShL68Nc.cjs} +2 -2
- package/dist/{integration-BKgGuodm.cjs.map → integration-BShL68Nc.cjs.map} +1 -1
- package/dist/{integration-VTZ3ICsO.js → integration-CWjttg7H.js} +2 -2
- package/dist/{integration-VTZ3ICsO.js.map → integration-CWjttg7H.js.map} +1 -1
- package/dist/integration.cjs +2 -2
- package/dist/integration.d.cts +1 -1
- package/dist/integration.d.ts +1 -1
- package/dist/integration.js +2 -2
- package/dist/react.cjs +29 -2
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +3 -2
- package/dist/react.d.ts +3 -2
- package/dist/react.js +29 -3
- package/dist/react.js.map +1 -1
- package/dist/{store-Bs0C0rNd.d.ts → store-2i8pYXqa.d.ts} +2 -1
- package/dist/{store-DHFXfWSz.js → store-7XBEcR8s.js} +6 -1
- package/dist/{store-DHFXfWSz.js.map → store-7XBEcR8s.js.map} +1 -1
- package/dist/{store-DU2u-qFH.cjs → store-DBv58dns.cjs} +6 -1
- package/dist/{store-DU2u-qFH.cjs.map → store-DBv58dns.cjs.map} +1 -1
- package/dist/{store-CJuwJl_K.d.cts → store-Ks80xWS_.d.cts} +2 -1
- package/package.json +1 -1
- package/skills/doxum-runtime/SKILL.md +10 -1
- package/skills/doxum-runtime/references/guide.en.md +9 -0
- package/skills/doxum-runtime/references/guide.zh-CN.md +7 -0
- package/skills/doxum-runtime/references/patterns.en.md +8 -2
- package/skills/doxum-runtime/references/patterns.zh-CN.md +6 -2
- package/skills/doxum-runtime/references/projections.en.md +220 -0
- package/skills/doxum-runtime/references/projections.zh-CN.md +203 -0
package/README.md
CHANGED
|
@@ -223,6 +223,7 @@ const scaled = project({ count, zoom }, ({ count, zoom }) => count * zoom);
|
|
|
223
223
|
const store = createProjectionStore({ onError: console.error });
|
|
224
224
|
store.get(scaled);
|
|
225
225
|
store.set(zoom, 2);
|
|
226
|
+
const title = store.item(titles, taskId); // Stable Readable<string | undefined>.
|
|
226
227
|
```
|
|
227
228
|
|
|
228
229
|
Projection declarations are lazy and reusable. A `ProjectionStore` owns
|
|
@@ -234,6 +235,13 @@ Pure computations receive current values. Advanced processors use tagged specs:
|
|
|
234
235
|
`project({ kind: 'collection', sources, build })`.
|
|
235
236
|
Document collection events provide scoped `read.get/has/ids`, final candidate
|
|
236
237
|
keys, order dirtiness, commits and reset state.
|
|
238
|
+
Ordinary mappers intentionally model only one-source, same-key transforms.
|
|
239
|
+
Cross-collection relationships use an advanced collection processor with explicit,
|
|
240
|
+
application-owned dependency indexes; processor reads are not tracked automatically.
|
|
241
|
+
For per-key observation, `store.item(collection, key)` returns a stable `Readable`
|
|
242
|
+
that only notifies for that key. React components use
|
|
243
|
+
`useProjectionItem(collection, key)`; unrelated keys and order-only changes do not
|
|
244
|
+
rerender the component.
|
|
237
245
|
|
|
238
246
|
Processors settle before external listeners. `store.batch` defers graph
|
|
239
247
|
settlement and projection notifications, but document commits/listeners remain
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_issue = require("./issue-DhrNdQNg.cjs");
|
|
3
|
-
const require_store = require("./store-
|
|
3
|
+
const require_store = require("./store-DBv58dns.cjs");
|
|
4
4
|
const require_driver = require("./driver-xOIkwrB8.cjs");
|
|
5
5
|
//#region core/src/history.ts
|
|
6
6
|
const createHistory = (input) => {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { $ as ObjectShape, D as snapshot, E as replace, F as ChangeSet, G as DocumentTreeNode, H as DocumentAnchor, I as MemberChange, K as DocumentTreeValue, L as ValueTransition, P as Change, Q as ObjectNode, S as DocumentImpact, T as Read, U as DocumentListConfig, V as DocumentAddress, W as DocumentNode, X as ListNode, Y as Infer, Z as MapNode, _ as Unsubscribe, _t as ParseError, a as DocumentDisposedError, at as TreeNode, b as MutationIssueCode, bt as parse, c as DocumentReentrancyError, ct as VariantShape, d as LocalHistory, dt as map, et as OptionalNode, f as ObserverError, ft as object, g as TransactionResult, gt as variant, h as TransactionRejected, ht as tree, i as DocumentDiagnostic, it as TableNode, l as DocumentRuntime, lt as field, mt as table, n as CommitSource, nt as ReadonlyValue, o as DocumentProblem, p as OperationResult, pt as optional, q as FieldNode, r as DocumentCommit, rt as SchemaPath, s as DocumentReadable, st as VariantNode, u as HistoryState, ut as list, v as Readable, vt as ParseIssue, w as Draft, x as CollectionImpact, y as MutationIssue, yt as Validator } from "./contract-DtGVSXSK.cjs";
|
|
2
|
-
import { C as ProjectionDisposedError, S as project, _ as ProjectionSources, a as AdvancedCollectionSpec, b as ValueProjection, c as CollectionProjection, d as DocumentCollectionProjection, f as DocumentEvent, g as ProjectionEvents, h as Projection, i as AdvancedCollectionProcess, l as CollectionSource, m as InputProjection, n as createProjectionStore, o as AdvancedValueSpec, p as DocumentProjection, s as CollectionEvent, t as ProjectionStore, u as DocumentCollectionEvent, v as ProjectionValues, w as ProjectionError, x as input, y as ValueEvent } from "./store-
|
|
2
|
+
import { C as ProjectionDisposedError, S as project, _ as ProjectionSources, a as AdvancedCollectionSpec, b as ValueProjection, c as CollectionProjection, d as DocumentCollectionProjection, f as DocumentEvent, g as ProjectionEvents, h as Projection, i as AdvancedCollectionProcess, l as CollectionSource, m as InputProjection, n as createProjectionStore, o as AdvancedValueSpec, p as DocumentProjection, s as CollectionEvent, t as ProjectionStore, u as DocumentCollectionEvent, v as ProjectionValues, w as ProjectionError, x as input, y as ValueEvent } from "./store-Ks80xWS_.cjs";
|
|
3
3
|
|
|
4
4
|
//#region core/src/runtime.d.ts
|
|
5
5
|
declare const createDocument: <S extends ObjectNode>(input: {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { $ as ObjectShape, D as snapshot, E as replace, F as ChangeSet, G as DocumentTreeNode, H as DocumentAnchor, I as MemberChange, K as DocumentTreeValue, L as ValueTransition, P as Change, Q as ObjectNode, S as DocumentImpact, T as Read, U as DocumentListConfig, V as DocumentAddress, W as DocumentNode, X as ListNode, Y as Infer, Z as MapNode, _ as Unsubscribe, _t as ParseError, a as DocumentDisposedError, at as TreeNode, b as MutationIssueCode, bt as parse, c as DocumentReentrancyError, ct as VariantShape, d as LocalHistory, dt as map, et as OptionalNode, f as ObserverError, ft as object, g as TransactionResult, gt as variant, h as TransactionRejected, ht as tree, i as DocumentDiagnostic, it as TableNode, l as DocumentRuntime, lt as field, mt as table, n as CommitSource, nt as ReadonlyValue, o as DocumentProblem, p as OperationResult, pt as optional, q as FieldNode, r as DocumentCommit, rt as SchemaPath, s as DocumentReadable, st as VariantNode, u as HistoryState, ut as list, v as Readable, vt as ParseIssue, w as Draft, x as CollectionImpact, y as MutationIssue, yt as Validator } from "./contract-CeAnEPBA.js";
|
|
2
|
-
import { C as ProjectionDisposedError, S as project, _ as ProjectionSources, a as AdvancedCollectionSpec, b as ValueProjection, c as CollectionProjection, d as DocumentCollectionProjection, f as DocumentEvent, g as ProjectionEvents, h as Projection, i as AdvancedCollectionProcess, l as CollectionSource, m as InputProjection, n as createProjectionStore, o as AdvancedValueSpec, p as DocumentProjection, s as CollectionEvent, t as ProjectionStore, u as DocumentCollectionEvent, v as ProjectionValues, w as ProjectionError, x as input, y as ValueEvent } from "./store-
|
|
2
|
+
import { C as ProjectionDisposedError, S as project, _ as ProjectionSources, a as AdvancedCollectionSpec, b as ValueProjection, c as CollectionProjection, d as DocumentCollectionProjection, f as DocumentEvent, g as ProjectionEvents, h as Projection, i as AdvancedCollectionProcess, l as CollectionSource, m as InputProjection, n as createProjectionStore, o as AdvancedValueSpec, p as DocumentProjection, s as CollectionEvent, t as ProjectionStore, u as DocumentCollectionEvent, v as ProjectionValues, w as ProjectionError, x as input, y as ValueEvent } from "./store-2i8pYXqa.js";
|
|
3
3
|
|
|
4
4
|
//#region core/src/runtime.d.ts
|
|
5
5
|
declare const createDocument: <S extends ObjectNode>(input: {
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A as insert, D as equal, F as remove, L as profile, M as keys, N as matches, _ as resolveTreeContainer, a as compiledShape, c as debugKey, d as overlaps, f as read, g as resolveLocated, h as resolveContainer, i as AddressIndex, j as install, l as memberKey, n as fail, o as contains, p as resolveAddress, r as invalidValue, s as createAddressResolver, t as MutationRejected, v as resolveValue } from "./issue-DVaGQGeP.js";
|
|
2
|
-
import { A as object, B as parse, C as createAccess, D as field, E as compilePath, F as ParseError, I as checkKey, L as checkValue, M as table, N as tree, O as list, P as variant, R as copyValue, T as snapshot, _ as readWith, a as input, b as TransactionRejected, c as createNotification, d as shareNotification, g as bindRuntimeAccess, h as accessOf, i as ProjectionError, j as optional, k as map, l as disposeNotification, m as subscribeTargets, o as project, p as subscribeRoot, r as ProjectionDisposedError, s as bindDocumentReadable, t as createProjectionStore, u as notify, v as DocumentDisposedError, w as replace, x as createImpact, y as DocumentReentrancyError, z as equalValue } from "./store-
|
|
2
|
+
import { A as object, B as parse, C as createAccess, D as field, E as compilePath, F as ParseError, I as checkKey, L as checkValue, M as table, N as tree, O as list, P as variant, R as copyValue, T as snapshot, _ as readWith, a as input, b as TransactionRejected, c as createNotification, d as shareNotification, g as bindRuntimeAccess, h as accessOf, i as ProjectionError, j as optional, k as map, l as disposeNotification, m as subscribeTargets, o as project, p as subscribeRoot, r as ProjectionDisposedError, s as bindDocumentReadable, t as createProjectionStore, u as notify, v as DocumentDisposedError, w as replace, x as createImpact, y as DocumentReentrancyError, z as equalValue } from "./store-7XBEcR8s.js";
|
|
3
3
|
import { n as bindRuntimeDriver, o as decodeChanges, r as disposeRuntimeDriver, s as sealChanges, t as assertRuntimeWritable } from "./driver-BlR81Dqg.js";
|
|
4
4
|
//#region core/src/history.ts
|
|
5
5
|
const createHistory = (input) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_store = require("./store-
|
|
1
|
+
const require_store = require("./store-DBv58dns.cjs");
|
|
2
2
|
//#region core/src/access/dependency.ts
|
|
3
3
|
const createDependencyTracker = () => {
|
|
4
4
|
const targets = [];
|
|
@@ -27,4 +27,4 @@ Object.defineProperty(exports, "track", {
|
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
//# sourceMappingURL=integration-
|
|
30
|
+
//# sourceMappingURL=integration-BShL68Nc.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration-
|
|
1
|
+
{"version":3,"file":"integration-BShL68Nc.cjs","names":["readWith"],"sources":["../core/src/access/dependency.ts","../core/src/integration.ts"],"sourcesContent":["import type { ImpactTarget } from '../schema';\nimport * as impactTarget from '../impact-target';\n\nexport type DependencyTracker = {\n readonly record: (target: ImpactTarget<unknown>) => void;\n readonly snapshot: () => readonly ImpactTarget<unknown>[];\n};\n\nexport const createDependencyTracker = (): DependencyTracker => {\n const targets: ImpactTarget<unknown>[] = [];\n return {\n record: value => {\n if (!targets.some(entry => impactTarget.same(entry, value))) targets.push(value);\n },\n snapshot: () => Object.freeze(targets.slice()),\n };\n};\n","import type { ObjectNode, ImpactTarget } from './schema';\nimport type { Read } from './access/scope';\nimport type { DocumentReadable } from './runtime/contract';\nimport { createDependencyTracker } from './access/dependency';\nimport { readWith } from './runtime/access';\nexport { projectionStoreDebug } from './projection/store';\nexport type { AddressRef } from './address';\nexport { contains, debugKey, overlaps, read as readAddress, resolveAddress } from './address';\nexport { subscribeDependencies } from './runtime/notification';\nexport { same as sameTarget } from './impact-target';\nexport type { ImpactTarget } from './schema';\n\nexport type TrackedSelection<TValue> = {\n readonly value: TValue;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\n// Framework adapters receive one immutable result instead of coordinating a\n// mutable collector with the reader's scoped lifetime themselves.\nexport const track = <TSchema extends ObjectNode, TValue>(\n runtime: DocumentReadable<TSchema>,\n selector: (read: Read<TSchema>) => TValue\n): TrackedSelection<TValue> => {\n const dependencies = createDependencyTracker();\n const value = readWith(runtime, selector, dependencies);\n return Object.freeze({ value, targets: dependencies.snapshot() });\n};\n"],"mappings":";;AAQA,MAAa,gCAAmD;CAC9D,MAAM,UAAmC,EAAE;AAC3C,QAAO;EACL,SAAQ,UAAS;AACf,OAAI,CAAC,QAAQ,MAAK,UAAA,cAAA,KAA2B,OAAO,MAAM,CAAC,CAAE,SAAQ,KAAK,MAAM;;EAElF,gBAAgB,OAAO,OAAO,QAAQ,OAAO,CAAC;EAC/C;;;;ACIH,MAAa,SACX,SACA,aAC6B;CAC7B,MAAM,eAAe,yBAAyB;CAC9C,MAAM,QAAQA,cAAAA,SAAS,SAAS,UAAU,aAAa;AACvD,QAAO,OAAO,OAAO;EAAE;EAAO,SAAS,aAAa,UAAU;EAAE,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as same, _ as readWith } from "./store-
|
|
1
|
+
import { S as same, _ as readWith } from "./store-7XBEcR8s.js";
|
|
2
2
|
//#region core/src/access/dependency.ts
|
|
3
3
|
const createDependencyTracker = () => {
|
|
4
4
|
const targets = [];
|
|
@@ -22,4 +22,4 @@ const track = (runtime, selector) => {
|
|
|
22
22
|
//#endregion
|
|
23
23
|
export { track as t };
|
|
24
24
|
|
|
25
|
-
//# sourceMappingURL=integration-
|
|
25
|
+
//# sourceMappingURL=integration-CWjttg7H.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration-
|
|
1
|
+
{"version":3,"file":"integration-CWjttg7H.js","names":["impactTarget.same"],"sources":["../core/src/access/dependency.ts","../core/src/integration.ts"],"sourcesContent":["import type { ImpactTarget } from '../schema';\nimport * as impactTarget from '../impact-target';\n\nexport type DependencyTracker = {\n readonly record: (target: ImpactTarget<unknown>) => void;\n readonly snapshot: () => readonly ImpactTarget<unknown>[];\n};\n\nexport const createDependencyTracker = (): DependencyTracker => {\n const targets: ImpactTarget<unknown>[] = [];\n return {\n record: value => {\n if (!targets.some(entry => impactTarget.same(entry, value))) targets.push(value);\n },\n snapshot: () => Object.freeze(targets.slice()),\n };\n};\n","import type { ObjectNode, ImpactTarget } from './schema';\nimport type { Read } from './access/scope';\nimport type { DocumentReadable } from './runtime/contract';\nimport { createDependencyTracker } from './access/dependency';\nimport { readWith } from './runtime/access';\nexport { projectionStoreDebug } from './projection/store';\nexport type { AddressRef } from './address';\nexport { contains, debugKey, overlaps, read as readAddress, resolveAddress } from './address';\nexport { subscribeDependencies } from './runtime/notification';\nexport { same as sameTarget } from './impact-target';\nexport type { ImpactTarget } from './schema';\n\nexport type TrackedSelection<TValue> = {\n readonly value: TValue;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\n// Framework adapters receive one immutable result instead of coordinating a\n// mutable collector with the reader's scoped lifetime themselves.\nexport const track = <TSchema extends ObjectNode, TValue>(\n runtime: DocumentReadable<TSchema>,\n selector: (read: Read<TSchema>) => TValue\n): TrackedSelection<TValue> => {\n const dependencies = createDependencyTracker();\n const value = readWith(runtime, selector, dependencies);\n return Object.freeze({ value, targets: dependencies.snapshot() });\n};\n"],"mappings":";;AAQA,MAAa,gCAAmD;CAC9D,MAAM,UAAmC,EAAE;AAC3C,QAAO;EACL,SAAQ,UAAS;AACf,OAAI,CAAC,QAAQ,MAAK,UAASA,KAAkB,OAAO,MAAM,CAAC,CAAE,SAAQ,KAAK,MAAM;;EAElF,gBAAgB,OAAO,OAAO,QAAQ,OAAO,CAAC;EAC/C;;;;ACIH,MAAa,SACX,SACA,aAC6B;CAC7B,MAAM,eAAe,yBAAyB;CAC9C,MAAM,QAAQ,SAAS,SAAS,UAAU,aAAa;AACvD,QAAO,OAAO,OAAO;EAAE;EAAO,SAAS,aAAa,UAAU;EAAE,CAAC"}
|
package/dist/integration.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_issue = require("./issue-DhrNdQNg.cjs");
|
|
3
|
-
const require_store = require("./store-
|
|
4
|
-
const require_integration = require("./integration-
|
|
3
|
+
const require_store = require("./store-DBv58dns.cjs");
|
|
4
|
+
const require_integration = require("./integration-BShL68Nc.cjs");
|
|
5
5
|
exports.contains = require_issue.contains;
|
|
6
6
|
exports.debugKey = require_issue.debugKey;
|
|
7
7
|
exports.overlaps = require_issue.overlaps;
|
package/dist/integration.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A as debugKey, J as ImpactTarget, M as read, N as resolveAddress, O as AddressRef, Q as ObjectNode, T as Read, _ as Unsubscribe, j as overlaps, k as contains, s as DocumentReadable, t as CommitListener } from "./contract-DtGVSXSK.cjs";
|
|
2
|
-
import { r as projectionStoreDebug } from "./store-
|
|
2
|
+
import { r as projectionStoreDebug } from "./store-Ks80xWS_.cjs";
|
|
3
3
|
|
|
4
4
|
//#region core/src/impact-target.d.ts
|
|
5
5
|
declare const same: (left: ImpactTarget<unknown>, right: ImpactTarget<unknown>) => boolean;
|
package/dist/integration.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A as debugKey, J as ImpactTarget, M as read, N as resolveAddress, O as AddressRef, Q as ObjectNode, T as Read, _ as Unsubscribe, j as overlaps, k as contains, s as DocumentReadable, t as CommitListener } from "./contract-CeAnEPBA.js";
|
|
2
|
-
import { r as projectionStoreDebug } from "./store-
|
|
2
|
+
import { r as projectionStoreDebug } from "./store-2i8pYXqa.js";
|
|
3
3
|
|
|
4
4
|
//#region core/src/impact-target.d.ts
|
|
5
5
|
declare const same: (left: ImpactTarget<unknown>, right: ImpactTarget<unknown>) => boolean;
|
package/dist/integration.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { c as debugKey, d as overlaps, f as read, o as contains, p as resolveAddress } from "./issue-DVaGQGeP.js";
|
|
2
|
-
import { S as same, f as subscribeDependencies, n as projectionStoreDebug } from "./store-
|
|
3
|
-
import { t as track } from "./integration-
|
|
2
|
+
import { S as same, f as subscribeDependencies, n as projectionStoreDebug } from "./store-7XBEcR8s.js";
|
|
3
|
+
import { t as track } from "./integration-CWjttg7H.js";
|
|
4
4
|
export { contains, debugKey, overlaps, projectionStoreDebug, read as readAddress, resolveAddress, same as sameTarget, subscribeDependencies, track };
|
package/dist/react.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_store = require("./store-
|
|
3
|
-
const require_integration = require("./integration-
|
|
2
|
+
const require_store = require("./store-DBv58dns.cjs");
|
|
3
|
+
const require_integration = require("./integration-BShL68Nc.cjs");
|
|
4
4
|
let react = require("react");
|
|
5
5
|
//#region react/src/hooks.ts
|
|
6
6
|
const ProjectionContext = (0, react.createContext)(void 0);
|
|
@@ -12,6 +12,32 @@ function useProjection(projection, store) {
|
|
|
12
12
|
const read = (0, react.useCallback)(() => owner.get(projection), [owner, projection]);
|
|
13
13
|
return (0, react.useSyncExternalStore)((0, react.useCallback)((listener) => owner.subscribe(projection, listener), [owner, projection]), read, read);
|
|
14
14
|
}
|
|
15
|
+
function useProjectionItem(projection, key, store) {
|
|
16
|
+
const context = (0, react.useContext)(ProjectionContext);
|
|
17
|
+
const owner = store ?? context;
|
|
18
|
+
if (!owner) throw new Error("ProjectionStore is required.");
|
|
19
|
+
const item = (0, react.useMemo)(() => owner.item(projection, key), [
|
|
20
|
+
key,
|
|
21
|
+
owner,
|
|
22
|
+
projection
|
|
23
|
+
]);
|
|
24
|
+
const read = (0, react.useMemo)(() => {
|
|
25
|
+
let previousRevision = -1;
|
|
26
|
+
let snapshot;
|
|
27
|
+
return () => {
|
|
28
|
+
const value = item.current();
|
|
29
|
+
const revision = item.revision();
|
|
30
|
+
if (snapshot && revision === previousRevision) return snapshot;
|
|
31
|
+
previousRevision = revision;
|
|
32
|
+
snapshot = {
|
|
33
|
+
value,
|
|
34
|
+
revision
|
|
35
|
+
};
|
|
36
|
+
return snapshot;
|
|
37
|
+
};
|
|
38
|
+
}, [item]);
|
|
39
|
+
return (0, react.useSyncExternalStore)((0, react.useCallback)((listener) => item.subscribe(listener), [item]), read, read).value;
|
|
40
|
+
}
|
|
15
41
|
function useSetProjection(projection, store) {
|
|
16
42
|
const context = (0, react.useContext)(ProjectionContext);
|
|
17
43
|
const owner = store ?? context;
|
|
@@ -120,6 +146,7 @@ exports.ProjectionProvider = ProjectionProvider;
|
|
|
120
146
|
exports.useDocumentSelector = useDocumentSelector;
|
|
121
147
|
exports.useHistory = useHistory;
|
|
122
148
|
exports.useProjection = useProjection;
|
|
149
|
+
exports.useProjectionItem = useProjectionItem;
|
|
123
150
|
exports.useReadable = useReadable;
|
|
124
151
|
exports.useSetProjection = useSetProjection;
|
|
125
152
|
|
package/dist/react.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.cjs","names":["sameTarget","track","subscribeDependencies"],"sources":["../react/src/hooks.ts"],"sourcesContent":["import type {\n DocumentReadable,\n ObjectNode,\n DocumentSelector,\n HistoryState,\n LocalHistory,\n OperationResult,\n Readable,\n ProjectionStore,\n ValueProjection,\n InputProjection,\n} from 'doxum';\nimport { track, subscribeDependencies, sameTarget, type ImpactTarget } from 'doxum/integration';\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\n\nexport const ProjectionContext = createContext<ProjectionStore | undefined>(undefined);\nexport const ProjectionProvider = ProjectionContext.Provider;\n\nexport function useProjection<T>(projection: ValueProjection<T>, store?: ProjectionStore): T {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n const read = useCallback(() => owner.get(projection), [owner, projection]);\n const subscribe = useCallback(\n (listener: () => void) => owner.subscribe(projection, listener),\n [owner, projection]\n );\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport function useSetProjection<T>(\n projection: InputProjection<T>,\n store?: ProjectionStore\n): (value: T) => void {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n return useCallback((value: T) => owner.set(projection, value), [owner, projection]);\n}\n\nexport type DocumentSelectorOptions<TResult> = {\n readonly isEqual?: (previous: TResult, next: TResult) => boolean;\n readonly server?: () => TResult;\n};\n\ntype SelectorCache<TSchema extends ObjectNode, TResult> = {\n readonly runtime: DocumentReadable<TSchema>;\n readonly value: TResult;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\nconst objectIs = <T>(previous: T, next: T): boolean => Object.is(previous, next);\nconst sameTargets = (\n left: readonly ImpactTarget<unknown>[],\n right: readonly ImpactTarget<unknown>[]\n): boolean => {\n if (left.length !== right.length) return false;\n for (let index = 0; index < left.length; index += 1)\n if (!sameTarget(left[index], right[index])) return false;\n return true;\n};\n\nexport function useDocumentSelector<TSchema extends ObjectNode, TResult>(\n runtime: DocumentReadable<TSchema>,\n selector: DocumentSelector<TSchema, TResult>,\n options?: DocumentSelectorOptions<TResult>\n): TResult {\n const equality = options?.isEqual ?? objectIs;\n const cache = useRef<SelectorCache<TSchema, TResult> | undefined>(undefined);\n const serverCache = useRef<\n | {\n readonly runtime: DocumentReadable<TSchema>;\n readonly selector: DocumentSelector<TSchema, TResult>;\n readonly source: (() => TResult) | undefined;\n readonly value: TResult;\n }\n | undefined\n >(undefined);\n\n const read = useMemo(() => {\n // Each selector closure owns its revision cache, including inline selectors\n // that allocate arrays or objects. Equality only compares distinct snapshots.\n let snapshot: { readonly revision: number; readonly value: TResult } | undefined;\n return (): TResult => {\n const revision = runtime.revision();\n if (snapshot?.revision === revision) return snapshot.value;\n const selection = track(runtime, selector);\n const previous = cache.current;\n const value =\n previous && previous.runtime === runtime && equality(previous.value, selection.value)\n ? previous.value\n : selection.value;\n cache.current = { runtime, value, targets: selection.targets };\n snapshot = { revision, value };\n return value;\n };\n }, [equality, runtime, selector]);\n\n const subscribe = useCallback(\n (listener: () => void) => {\n read();\n let targets = cache.current?.targets ?? [];\n let unsubscribe: () => void = () => undefined;\n const install = () => {\n if (targets.length === 0) return () => undefined;\n return subscribeDependencies(runtime, targets, onCommit);\n };\n const onCommit = () => {\n const previous = cache.current;\n const next = read();\n const nextTargets = cache.current?.targets ?? [];\n if (!sameTargets(targets, nextTargets)) {\n unsubscribe();\n targets = nextTargets;\n unsubscribe = install();\n }\n if (previous && !Object.is(previous.value, next)) listener();\n };\n unsubscribe = install();\n return () => unsubscribe();\n },\n [read, runtime]\n );\n\n const server = options?.server;\n const readServer = useCallback((): TResult => {\n const previous = serverCache.current;\n if (\n previous &&\n previous.source === server &&\n previous.runtime === runtime &&\n previous.selector === selector\n )\n return previous.value;\n const value = server ? server() : read();\n serverCache.current = { runtime, selector, source: server, value };\n return value;\n }, [read, server, runtime, selector]);\n\n return useSyncExternalStore(subscribe, read, readServer);\n}\n\nexport function useReadable<T>(readable: Readable<T>): T {\n const subscribe = useCallback((listener: () => void) => readable.subscribe(listener), [readable]);\n const read = useCallback(() => readable.current(), [readable]);\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport function useHistory<TCommit>(history: LocalHistory<TCommit>): HistoryState & {\n undo(): OperationResult<TCommit>;\n redo(): OperationResult<TCommit>;\n} {\n const subscribe = useCallback((listener: () => void) => history.subscribe(listener), [history]);\n const read = useCallback(() => history.current(), [history]);\n const state = useSyncExternalStore(subscribe, read, read);\n const undo = useCallback(() => history.undo(), [history]);\n const redo = useCallback(() => history.redo(), [history]);\n\n return useMemo(() => ({ ...state, undo, redo }), [redo, state, undo]);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"react.cjs","names":["sameTarget","track","subscribeDependencies"],"sources":["../react/src/hooks.ts"],"sourcesContent":["import type {\n DocumentReadable,\n ObjectNode,\n DocumentSelector,\n HistoryState,\n LocalHistory,\n OperationResult,\n Readable,\n ProjectionStore,\n CollectionProjection,\n ValueProjection,\n InputProjection,\n} from 'doxum';\nimport { track, subscribeDependencies, sameTarget, type ImpactTarget } from 'doxum/integration';\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\n\nexport const ProjectionContext = createContext<ProjectionStore | undefined>(undefined);\nexport const ProjectionProvider = ProjectionContext.Provider;\n\nexport function useProjection<T>(projection: ValueProjection<T>, store?: ProjectionStore): T {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n const read = useCallback(() => owner.get(projection), [owner, projection]);\n const subscribe = useCallback(\n (listener: () => void) => owner.subscribe(projection, listener),\n [owner, projection]\n );\n return useSyncExternalStore(subscribe, read, read);\n}\n\ntype ProjectionItemSnapshot<T> = {\n readonly value: T | undefined;\n readonly revision: number;\n};\n\nexport function useProjectionItem<K extends string, V>(\n projection: CollectionProjection<K, V>,\n key: K,\n store?: ProjectionStore\n): V | undefined {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n const item = useMemo(() => owner.item(projection, key), [key, owner, projection]);\n const read = useMemo(() => {\n let previousRevision = -1;\n let snapshot: ProjectionItemSnapshot<V> | undefined;\n return (): ProjectionItemSnapshot<V> => {\n const value = item.current();\n const revision = item.revision();\n if (snapshot && revision === previousRevision) return snapshot;\n previousRevision = revision;\n snapshot = { value, revision };\n return snapshot;\n };\n }, [item]);\n const subscribe = useCallback((listener: () => void) => item.subscribe(listener), [item]);\n return useSyncExternalStore(subscribe, read, read).value;\n}\n\nexport function useSetProjection<T>(\n projection: InputProjection<T>,\n store?: ProjectionStore\n): (value: T) => void {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n return useCallback((value: T) => owner.set(projection, value), [owner, projection]);\n}\n\nexport type DocumentSelectorOptions<TResult> = {\n readonly isEqual?: (previous: TResult, next: TResult) => boolean;\n readonly server?: () => TResult;\n};\n\ntype SelectorCache<TSchema extends ObjectNode, TResult> = {\n readonly runtime: DocumentReadable<TSchema>;\n readonly value: TResult;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\nconst objectIs = <T>(previous: T, next: T): boolean => Object.is(previous, next);\nconst sameTargets = (\n left: readonly ImpactTarget<unknown>[],\n right: readonly ImpactTarget<unknown>[]\n): boolean => {\n if (left.length !== right.length) return false;\n for (let index = 0; index < left.length; index += 1)\n if (!sameTarget(left[index], right[index])) return false;\n return true;\n};\n\nexport function useDocumentSelector<TSchema extends ObjectNode, TResult>(\n runtime: DocumentReadable<TSchema>,\n selector: DocumentSelector<TSchema, TResult>,\n options?: DocumentSelectorOptions<TResult>\n): TResult {\n const equality = options?.isEqual ?? objectIs;\n const cache = useRef<SelectorCache<TSchema, TResult> | undefined>(undefined);\n const serverCache = useRef<\n | {\n readonly runtime: DocumentReadable<TSchema>;\n readonly selector: DocumentSelector<TSchema, TResult>;\n readonly source: (() => TResult) | undefined;\n readonly value: TResult;\n }\n | undefined\n >(undefined);\n\n const read = useMemo(() => {\n // Each selector closure owns its revision cache, including inline selectors\n // that allocate arrays or objects. Equality only compares distinct snapshots.\n let snapshot: { readonly revision: number; readonly value: TResult } | undefined;\n return (): TResult => {\n const revision = runtime.revision();\n if (snapshot?.revision === revision) return snapshot.value;\n const selection = track(runtime, selector);\n const previous = cache.current;\n const value =\n previous && previous.runtime === runtime && equality(previous.value, selection.value)\n ? previous.value\n : selection.value;\n cache.current = { runtime, value, targets: selection.targets };\n snapshot = { revision, value };\n return value;\n };\n }, [equality, runtime, selector]);\n\n const subscribe = useCallback(\n (listener: () => void) => {\n read();\n let targets = cache.current?.targets ?? [];\n let unsubscribe: () => void = () => undefined;\n const install = () => {\n if (targets.length === 0) return () => undefined;\n return subscribeDependencies(runtime, targets, onCommit);\n };\n const onCommit = () => {\n const previous = cache.current;\n const next = read();\n const nextTargets = cache.current?.targets ?? [];\n if (!sameTargets(targets, nextTargets)) {\n unsubscribe();\n targets = nextTargets;\n unsubscribe = install();\n }\n if (previous && !Object.is(previous.value, next)) listener();\n };\n unsubscribe = install();\n return () => unsubscribe();\n },\n [read, runtime]\n );\n\n const server = options?.server;\n const readServer = useCallback((): TResult => {\n const previous = serverCache.current;\n if (\n previous &&\n previous.source === server &&\n previous.runtime === runtime &&\n previous.selector === selector\n )\n return previous.value;\n const value = server ? server() : read();\n serverCache.current = { runtime, selector, source: server, value };\n return value;\n }, [read, server, runtime, selector]);\n\n return useSyncExternalStore(subscribe, read, readServer);\n}\n\nexport function useReadable<T>(readable: Readable<T>): T {\n const subscribe = useCallback((listener: () => void) => readable.subscribe(listener), [readable]);\n const read = useCallback(() => readable.current(), [readable]);\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport function useHistory<TCommit>(history: LocalHistory<TCommit>): HistoryState & {\n undo(): OperationResult<TCommit>;\n redo(): OperationResult<TCommit>;\n} {\n const subscribe = useCallback((listener: () => void) => history.subscribe(listener), [history]);\n const read = useCallback(() => history.current(), [history]);\n const state = useSyncExternalStore(subscribe, read, read);\n const undo = useCallback(() => history.undo(), [history]);\n const redo = useCallback(() => history.redo(), [history]);\n\n return useMemo(() => ({ ...state, undo, redo }), [redo, state, undo]);\n}\n"],"mappings":"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"}
|
package/dist/react.d.cts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as _$react from "react";
|
|
2
|
-
import { DocumentReadable, DocumentSelector, HistoryState, InputProjection, LocalHistory, ObjectNode, OperationResult, ProjectionStore, Readable, ValueProjection } from "doxum";
|
|
2
|
+
import { CollectionProjection, DocumentReadable, DocumentSelector, HistoryState, InputProjection, LocalHistory, ObjectNode, OperationResult, ProjectionStore, Readable, ValueProjection } from "doxum";
|
|
3
3
|
|
|
4
4
|
//#region react/src/hooks.d.ts
|
|
5
5
|
declare const ProjectionContext: _$react.Context<ProjectionStore | undefined>;
|
|
6
6
|
declare const ProjectionProvider: _$react.Provider<ProjectionStore | undefined>;
|
|
7
7
|
declare function useProjection<T>(projection: ValueProjection<T>, store?: ProjectionStore): T;
|
|
8
|
+
declare function useProjectionItem<K extends string, V>(projection: CollectionProjection<K, V>, key: K, store?: ProjectionStore): V | undefined;
|
|
8
9
|
declare function useSetProjection<T>(projection: InputProjection<T>, store?: ProjectionStore): (value: T) => void;
|
|
9
10
|
type DocumentSelectorOptions<TResult> = {
|
|
10
11
|
readonly isEqual?: (previous: TResult, next: TResult) => boolean;
|
|
@@ -17,5 +18,5 @@ declare function useHistory<TCommit>(history: LocalHistory<TCommit>): HistorySta
|
|
|
17
18
|
redo(): OperationResult<TCommit>;
|
|
18
19
|
};
|
|
19
20
|
//#endregion
|
|
20
|
-
export { type DocumentSelectorOptions, ProjectionContext, ProjectionProvider, useDocumentSelector, useHistory, useProjection, useReadable, useSetProjection };
|
|
21
|
+
export { type DocumentSelectorOptions, ProjectionContext, ProjectionProvider, useDocumentSelector, useHistory, useProjection, useProjectionItem, useReadable, useSetProjection };
|
|
21
22
|
//# sourceMappingURL=react.d.cts.map
|
package/dist/react.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as _$react from "react";
|
|
2
|
-
import { DocumentReadable, DocumentSelector, HistoryState, InputProjection, LocalHistory, ObjectNode, OperationResult, ProjectionStore, Readable, ValueProjection } from "doxum";
|
|
2
|
+
import { CollectionProjection, DocumentReadable, DocumentSelector, HistoryState, InputProjection, LocalHistory, ObjectNode, OperationResult, ProjectionStore, Readable, ValueProjection } from "doxum";
|
|
3
3
|
|
|
4
4
|
//#region react/src/hooks.d.ts
|
|
5
5
|
declare const ProjectionContext: _$react.Context<ProjectionStore | undefined>;
|
|
6
6
|
declare const ProjectionProvider: _$react.Provider<ProjectionStore | undefined>;
|
|
7
7
|
declare function useProjection<T>(projection: ValueProjection<T>, store?: ProjectionStore): T;
|
|
8
|
+
declare function useProjectionItem<K extends string, V>(projection: CollectionProjection<K, V>, key: K, store?: ProjectionStore): V | undefined;
|
|
8
9
|
declare function useSetProjection<T>(projection: InputProjection<T>, store?: ProjectionStore): (value: T) => void;
|
|
9
10
|
type DocumentSelectorOptions<TResult> = {
|
|
10
11
|
readonly isEqual?: (previous: TResult, next: TResult) => boolean;
|
|
@@ -17,5 +18,5 @@ declare function useHistory<TCommit>(history: LocalHistory<TCommit>): HistorySta
|
|
|
17
18
|
redo(): OperationResult<TCommit>;
|
|
18
19
|
};
|
|
19
20
|
//#endregion
|
|
20
|
-
export { type DocumentSelectorOptions, ProjectionContext, ProjectionProvider, useDocumentSelector, useHistory, useProjection, useReadable, useSetProjection };
|
|
21
|
+
export { type DocumentSelectorOptions, ProjectionContext, ProjectionProvider, useDocumentSelector, useHistory, useProjection, useProjectionItem, useReadable, useSetProjection };
|
|
21
22
|
//# sourceMappingURL=react.d.ts.map
|
package/dist/react.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as same, f as subscribeDependencies } from "./store-
|
|
2
|
-
import { t as track } from "./integration-
|
|
1
|
+
import { S as same, f as subscribeDependencies } from "./store-7XBEcR8s.js";
|
|
2
|
+
import { t as track } from "./integration-CWjttg7H.js";
|
|
3
3
|
import { createContext, useCallback, useContext, useMemo, useRef, useSyncExternalStore } from "react";
|
|
4
4
|
//#region react/src/hooks.ts
|
|
5
5
|
const ProjectionContext = createContext(void 0);
|
|
@@ -11,6 +11,32 @@ function useProjection(projection, store) {
|
|
|
11
11
|
const read = useCallback(() => owner.get(projection), [owner, projection]);
|
|
12
12
|
return useSyncExternalStore(useCallback((listener) => owner.subscribe(projection, listener), [owner, projection]), read, read);
|
|
13
13
|
}
|
|
14
|
+
function useProjectionItem(projection, key, store) {
|
|
15
|
+
const context = useContext(ProjectionContext);
|
|
16
|
+
const owner = store ?? context;
|
|
17
|
+
if (!owner) throw new Error("ProjectionStore is required.");
|
|
18
|
+
const item = useMemo(() => owner.item(projection, key), [
|
|
19
|
+
key,
|
|
20
|
+
owner,
|
|
21
|
+
projection
|
|
22
|
+
]);
|
|
23
|
+
const read = useMemo(() => {
|
|
24
|
+
let previousRevision = -1;
|
|
25
|
+
let snapshot;
|
|
26
|
+
return () => {
|
|
27
|
+
const value = item.current();
|
|
28
|
+
const revision = item.revision();
|
|
29
|
+
if (snapshot && revision === previousRevision) return snapshot;
|
|
30
|
+
previousRevision = revision;
|
|
31
|
+
snapshot = {
|
|
32
|
+
value,
|
|
33
|
+
revision
|
|
34
|
+
};
|
|
35
|
+
return snapshot;
|
|
36
|
+
};
|
|
37
|
+
}, [item]);
|
|
38
|
+
return useSyncExternalStore(useCallback((listener) => item.subscribe(listener), [item]), read, read).value;
|
|
39
|
+
}
|
|
14
40
|
function useSetProjection(projection, store) {
|
|
15
41
|
const context = useContext(ProjectionContext);
|
|
16
42
|
const owner = store ?? context;
|
|
@@ -114,6 +140,6 @@ function useHistory(history) {
|
|
|
114
140
|
]);
|
|
115
141
|
}
|
|
116
142
|
//#endregion
|
|
117
|
-
export { ProjectionContext, ProjectionProvider, useDocumentSelector, useHistory, useProjection, useReadable, useSetProjection };
|
|
143
|
+
export { ProjectionContext, ProjectionProvider, useDocumentSelector, useHistory, useProjection, useProjectionItem, useReadable, useSetProjection };
|
|
118
144
|
|
|
119
145
|
//# sourceMappingURL=react.js.map
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","names":["sameTarget"],"sources":["../react/src/hooks.ts"],"sourcesContent":["import type {\n DocumentReadable,\n ObjectNode,\n DocumentSelector,\n HistoryState,\n LocalHistory,\n OperationResult,\n Readable,\n ProjectionStore,\n ValueProjection,\n InputProjection,\n} from 'doxum';\nimport { track, subscribeDependencies, sameTarget, type ImpactTarget } from 'doxum/integration';\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\n\nexport const ProjectionContext = createContext<ProjectionStore | undefined>(undefined);\nexport const ProjectionProvider = ProjectionContext.Provider;\n\nexport function useProjection<T>(projection: ValueProjection<T>, store?: ProjectionStore): T {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n const read = useCallback(() => owner.get(projection), [owner, projection]);\n const subscribe = useCallback(\n (listener: () => void) => owner.subscribe(projection, listener),\n [owner, projection]\n );\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport function useSetProjection<T>(\n projection: InputProjection<T>,\n store?: ProjectionStore\n): (value: T) => void {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n return useCallback((value: T) => owner.set(projection, value), [owner, projection]);\n}\n\nexport type DocumentSelectorOptions<TResult> = {\n readonly isEqual?: (previous: TResult, next: TResult) => boolean;\n readonly server?: () => TResult;\n};\n\ntype SelectorCache<TSchema extends ObjectNode, TResult> = {\n readonly runtime: DocumentReadable<TSchema>;\n readonly value: TResult;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\nconst objectIs = <T>(previous: T, next: T): boolean => Object.is(previous, next);\nconst sameTargets = (\n left: readonly ImpactTarget<unknown>[],\n right: readonly ImpactTarget<unknown>[]\n): boolean => {\n if (left.length !== right.length) return false;\n for (let index = 0; index < left.length; index += 1)\n if (!sameTarget(left[index], right[index])) return false;\n return true;\n};\n\nexport function useDocumentSelector<TSchema extends ObjectNode, TResult>(\n runtime: DocumentReadable<TSchema>,\n selector: DocumentSelector<TSchema, TResult>,\n options?: DocumentSelectorOptions<TResult>\n): TResult {\n const equality = options?.isEqual ?? objectIs;\n const cache = useRef<SelectorCache<TSchema, TResult> | undefined>(undefined);\n const serverCache = useRef<\n | {\n readonly runtime: DocumentReadable<TSchema>;\n readonly selector: DocumentSelector<TSchema, TResult>;\n readonly source: (() => TResult) | undefined;\n readonly value: TResult;\n }\n | undefined\n >(undefined);\n\n const read = useMemo(() => {\n // Each selector closure owns its revision cache, including inline selectors\n // that allocate arrays or objects. Equality only compares distinct snapshots.\n let snapshot: { readonly revision: number; readonly value: TResult } | undefined;\n return (): TResult => {\n const revision = runtime.revision();\n if (snapshot?.revision === revision) return snapshot.value;\n const selection = track(runtime, selector);\n const previous = cache.current;\n const value =\n previous && previous.runtime === runtime && equality(previous.value, selection.value)\n ? previous.value\n : selection.value;\n cache.current = { runtime, value, targets: selection.targets };\n snapshot = { revision, value };\n return value;\n };\n }, [equality, runtime, selector]);\n\n const subscribe = useCallback(\n (listener: () => void) => {\n read();\n let targets = cache.current?.targets ?? [];\n let unsubscribe: () => void = () => undefined;\n const install = () => {\n if (targets.length === 0) return () => undefined;\n return subscribeDependencies(runtime, targets, onCommit);\n };\n const onCommit = () => {\n const previous = cache.current;\n const next = read();\n const nextTargets = cache.current?.targets ?? [];\n if (!sameTargets(targets, nextTargets)) {\n unsubscribe();\n targets = nextTargets;\n unsubscribe = install();\n }\n if (previous && !Object.is(previous.value, next)) listener();\n };\n unsubscribe = install();\n return () => unsubscribe();\n },\n [read, runtime]\n );\n\n const server = options?.server;\n const readServer = useCallback((): TResult => {\n const previous = serverCache.current;\n if (\n previous &&\n previous.source === server &&\n previous.runtime === runtime &&\n previous.selector === selector\n )\n return previous.value;\n const value = server ? server() : read();\n serverCache.current = { runtime, selector, source: server, value };\n return value;\n }, [read, server, runtime, selector]);\n\n return useSyncExternalStore(subscribe, read, readServer);\n}\n\nexport function useReadable<T>(readable: Readable<T>): T {\n const subscribe = useCallback((listener: () => void) => readable.subscribe(listener), [readable]);\n const read = useCallback(() => readable.current(), [readable]);\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport function useHistory<TCommit>(history: LocalHistory<TCommit>): HistoryState & {\n undo(): OperationResult<TCommit>;\n redo(): OperationResult<TCommit>;\n} {\n const subscribe = useCallback((listener: () => void) => history.subscribe(listener), [history]);\n const read = useCallback(() => history.current(), [history]);\n const state = useSyncExternalStore(subscribe, read, read);\n const undo = useCallback(() => history.undo(), [history]);\n const redo = useCallback(() => history.redo(), [history]);\n\n return useMemo(() => ({ ...state, undo, redo }), [redo, state, undo]);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"react.js","names":["sameTarget"],"sources":["../react/src/hooks.ts"],"sourcesContent":["import type {\n DocumentReadable,\n ObjectNode,\n DocumentSelector,\n HistoryState,\n LocalHistory,\n OperationResult,\n Readable,\n ProjectionStore,\n CollectionProjection,\n ValueProjection,\n InputProjection,\n} from 'doxum';\nimport { track, subscribeDependencies, sameTarget, type ImpactTarget } from 'doxum/integration';\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\n\nexport const ProjectionContext = createContext<ProjectionStore | undefined>(undefined);\nexport const ProjectionProvider = ProjectionContext.Provider;\n\nexport function useProjection<T>(projection: ValueProjection<T>, store?: ProjectionStore): T {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n const read = useCallback(() => owner.get(projection), [owner, projection]);\n const subscribe = useCallback(\n (listener: () => void) => owner.subscribe(projection, listener),\n [owner, projection]\n );\n return useSyncExternalStore(subscribe, read, read);\n}\n\ntype ProjectionItemSnapshot<T> = {\n readonly value: T | undefined;\n readonly revision: number;\n};\n\nexport function useProjectionItem<K extends string, V>(\n projection: CollectionProjection<K, V>,\n key: K,\n store?: ProjectionStore\n): V | undefined {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n const item = useMemo(() => owner.item(projection, key), [key, owner, projection]);\n const read = useMemo(() => {\n let previousRevision = -1;\n let snapshot: ProjectionItemSnapshot<V> | undefined;\n return (): ProjectionItemSnapshot<V> => {\n const value = item.current();\n const revision = item.revision();\n if (snapshot && revision === previousRevision) return snapshot;\n previousRevision = revision;\n snapshot = { value, revision };\n return snapshot;\n };\n }, [item]);\n const subscribe = useCallback((listener: () => void) => item.subscribe(listener), [item]);\n return useSyncExternalStore(subscribe, read, read).value;\n}\n\nexport function useSetProjection<T>(\n projection: InputProjection<T>,\n store?: ProjectionStore\n): (value: T) => void {\n const context = useContext(ProjectionContext);\n const owner = store ?? context;\n if (!owner) throw new Error('ProjectionStore is required.');\n return useCallback((value: T) => owner.set(projection, value), [owner, projection]);\n}\n\nexport type DocumentSelectorOptions<TResult> = {\n readonly isEqual?: (previous: TResult, next: TResult) => boolean;\n readonly server?: () => TResult;\n};\n\ntype SelectorCache<TSchema extends ObjectNode, TResult> = {\n readonly runtime: DocumentReadable<TSchema>;\n readonly value: TResult;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\nconst objectIs = <T>(previous: T, next: T): boolean => Object.is(previous, next);\nconst sameTargets = (\n left: readonly ImpactTarget<unknown>[],\n right: readonly ImpactTarget<unknown>[]\n): boolean => {\n if (left.length !== right.length) return false;\n for (let index = 0; index < left.length; index += 1)\n if (!sameTarget(left[index], right[index])) return false;\n return true;\n};\n\nexport function useDocumentSelector<TSchema extends ObjectNode, TResult>(\n runtime: DocumentReadable<TSchema>,\n selector: DocumentSelector<TSchema, TResult>,\n options?: DocumentSelectorOptions<TResult>\n): TResult {\n const equality = options?.isEqual ?? objectIs;\n const cache = useRef<SelectorCache<TSchema, TResult> | undefined>(undefined);\n const serverCache = useRef<\n | {\n readonly runtime: DocumentReadable<TSchema>;\n readonly selector: DocumentSelector<TSchema, TResult>;\n readonly source: (() => TResult) | undefined;\n readonly value: TResult;\n }\n | undefined\n >(undefined);\n\n const read = useMemo(() => {\n // Each selector closure owns its revision cache, including inline selectors\n // that allocate arrays or objects. Equality only compares distinct snapshots.\n let snapshot: { readonly revision: number; readonly value: TResult } | undefined;\n return (): TResult => {\n const revision = runtime.revision();\n if (snapshot?.revision === revision) return snapshot.value;\n const selection = track(runtime, selector);\n const previous = cache.current;\n const value =\n previous && previous.runtime === runtime && equality(previous.value, selection.value)\n ? previous.value\n : selection.value;\n cache.current = { runtime, value, targets: selection.targets };\n snapshot = { revision, value };\n return value;\n };\n }, [equality, runtime, selector]);\n\n const subscribe = useCallback(\n (listener: () => void) => {\n read();\n let targets = cache.current?.targets ?? [];\n let unsubscribe: () => void = () => undefined;\n const install = () => {\n if (targets.length === 0) return () => undefined;\n return subscribeDependencies(runtime, targets, onCommit);\n };\n const onCommit = () => {\n const previous = cache.current;\n const next = read();\n const nextTargets = cache.current?.targets ?? [];\n if (!sameTargets(targets, nextTargets)) {\n unsubscribe();\n targets = nextTargets;\n unsubscribe = install();\n }\n if (previous && !Object.is(previous.value, next)) listener();\n };\n unsubscribe = install();\n return () => unsubscribe();\n },\n [read, runtime]\n );\n\n const server = options?.server;\n const readServer = useCallback((): TResult => {\n const previous = serverCache.current;\n if (\n previous &&\n previous.source === server &&\n previous.runtime === runtime &&\n previous.selector === selector\n )\n return previous.value;\n const value = server ? server() : read();\n serverCache.current = { runtime, selector, source: server, value };\n return value;\n }, [read, server, runtime, selector]);\n\n return useSyncExternalStore(subscribe, read, readServer);\n}\n\nexport function useReadable<T>(readable: Readable<T>): T {\n const subscribe = useCallback((listener: () => void) => readable.subscribe(listener), [readable]);\n const read = useCallback(() => readable.current(), [readable]);\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport function useHistory<TCommit>(history: LocalHistory<TCommit>): HistoryState & {\n undo(): OperationResult<TCommit>;\n redo(): OperationResult<TCommit>;\n} {\n const subscribe = useCallback((listener: () => void) => history.subscribe(listener), [history]);\n const read = useCallback(() => history.current(), [history]);\n const state = useSyncExternalStore(subscribe, read, read);\n const undo = useCallback(() => history.undo(), [history]);\n const redo = useCallback(() => history.redo(), [history]);\n\n return useMemo(() => ({ ...state, undo, redo }), [redo, state, undo]);\n}\n"],"mappings":";;;;AAuBA,MAAa,oBAAoB,cAA2C,KAAA,EAAU;AACtF,MAAa,qBAAqB,kBAAkB;AAEpD,SAAgB,cAAiB,YAAgC,OAA4B;CAC3F,MAAM,UAAU,WAAW,kBAAkB;CAC7C,MAAM,QAAQ,SAAS;AACvB,KAAI,CAAC,MAAO,OAAM,IAAI,MAAM,+BAA+B;CAC3D,MAAM,OAAO,kBAAkB,MAAM,IAAI,WAAW,EAAE,CAAC,OAAO,WAAW,CAAC;AAK1E,QAAO,qBAJW,aACf,aAAyB,MAAM,UAAU,YAAY,SAAS,EAC/D,CAAC,OAAO,WAAW,CAEgB,EAAE,MAAM,KAAK;;AAQpD,SAAgB,kBACd,YACA,KACA,OACe;CACf,MAAM,UAAU,WAAW,kBAAkB;CAC7C,MAAM,QAAQ,SAAS;AACvB,KAAI,CAAC,MAAO,OAAM,IAAI,MAAM,+BAA+B;CAC3D,MAAM,OAAO,cAAc,MAAM,KAAK,YAAY,IAAI,EAAE;EAAC;EAAK;EAAO;EAAW,CAAC;CACjF,MAAM,OAAO,cAAc;EACzB,IAAI,mBAAmB;EACvB,IAAI;AACJ,eAAwC;GACtC,MAAM,QAAQ,KAAK,SAAS;GAC5B,MAAM,WAAW,KAAK,UAAU;AAChC,OAAI,YAAY,aAAa,iBAAkB,QAAO;AACtD,sBAAmB;AACnB,cAAW;IAAE;IAAO;IAAU;AAC9B,UAAO;;IAER,CAAC,KAAK,CAAC;AAEV,QAAO,qBADW,aAAa,aAAyB,KAAK,UAAU,SAAS,EAAE,CAAC,KAAK,CACnD,EAAE,MAAM,KAAK,CAAC;;AAGrD,SAAgB,iBACd,YACA,OACoB;CACpB,MAAM,UAAU,WAAW,kBAAkB;CAC7C,MAAM,QAAQ,SAAS;AACvB,KAAI,CAAC,MAAO,OAAM,IAAI,MAAM,+BAA+B;AAC3D,QAAO,aAAa,UAAa,MAAM,IAAI,YAAY,MAAM,EAAE,CAAC,OAAO,WAAW,CAAC;;AAcrF,MAAM,YAAe,UAAa,SAAqB,OAAO,GAAG,UAAU,KAAK;AAChF,MAAM,eACJ,MACA,UACY;AACZ,KAAI,KAAK,WAAW,MAAM,OAAQ,QAAO;AACzC,MAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,EAChD,KAAI,CAACA,KAAW,KAAK,QAAQ,MAAM,OAAO,CAAE,QAAO;AACrD,QAAO;;AAGT,SAAgB,oBACd,SACA,UACA,SACS;CACT,MAAM,WAAW,SAAS,WAAW;CACrC,MAAM,QAAQ,OAAoD,KAAA,EAAU;CAC5E,MAAM,cAAc,OAQlB,KAAA,EAAU;CAEZ,MAAM,OAAO,cAAc;EAGzB,IAAI;AACJ,eAAsB;GACpB,MAAM,WAAW,QAAQ,UAAU;AACnC,OAAI,UAAU,aAAa,SAAU,QAAO,SAAS;GACrD,MAAM,YAAY,MAAM,SAAS,SAAS;GAC1C,MAAM,WAAW,MAAM;GACvB,MAAM,QACJ,YAAY,SAAS,YAAY,WAAW,SAAS,SAAS,OAAO,UAAU,MAAM,GACjF,SAAS,QACT,UAAU;AAChB,SAAM,UAAU;IAAE;IAAS;IAAO,SAAS,UAAU;IAAS;AAC9D,cAAW;IAAE;IAAU;IAAO;AAC9B,UAAO;;IAER;EAAC;EAAU;EAAS;EAAS,CAAC;CAEjC,MAAM,YAAY,aACf,aAAyB;AACxB,QAAM;EACN,IAAI,UAAU,MAAM,SAAS,WAAW,EAAE;EAC1C,IAAI,oBAAgC,KAAA;EACpC,MAAM,gBAAgB;AACpB,OAAI,QAAQ,WAAW,EAAG,cAAa,KAAA;AACvC,UAAO,sBAAsB,SAAS,SAAS,SAAS;;EAE1D,MAAM,iBAAiB;GACrB,MAAM,WAAW,MAAM;GACvB,MAAM,OAAO,MAAM;GACnB,MAAM,cAAc,MAAM,SAAS,WAAW,EAAE;AAChD,OAAI,CAAC,YAAY,SAAS,YAAY,EAAE;AACtC,iBAAa;AACb,cAAU;AACV,kBAAc,SAAS;;AAEzB,OAAI,YAAY,CAAC,OAAO,GAAG,SAAS,OAAO,KAAK,CAAE,WAAU;;AAE9D,gBAAc,SAAS;AACvB,eAAa,aAAa;IAE5B,CAAC,MAAM,QAAQ,CAChB;CAED,MAAM,SAAS,SAAS;AAexB,QAAO,qBAAqB,WAAW,MAdpB,kBAA2B;EAC5C,MAAM,WAAW,YAAY;AAC7B,MACE,YACA,SAAS,WAAW,UACpB,SAAS,YAAY,WACrB,SAAS,aAAa,SAEtB,QAAO,SAAS;EAClB,MAAM,QAAQ,SAAS,QAAQ,GAAG,MAAM;AACxC,cAAY,UAAU;GAAE;GAAS;GAAU,QAAQ;GAAQ;GAAO;AAClE,SAAO;IACN;EAAC;EAAM;EAAQ;EAAS;EAAS,CAEmB,CAAC;;AAG1D,SAAgB,YAAe,UAA0B;CACvD,MAAM,YAAY,aAAa,aAAyB,SAAS,UAAU,SAAS,EAAE,CAAC,SAAS,CAAC;CACjG,MAAM,OAAO,kBAAkB,SAAS,SAAS,EAAE,CAAC,SAAS,CAAC;AAC9D,QAAO,qBAAqB,WAAW,MAAM,KAAK;;AAGpD,SAAgB,WAAoB,SAGlC;CACA,MAAM,YAAY,aAAa,aAAyB,QAAQ,UAAU,SAAS,EAAE,CAAC,QAAQ,CAAC;CAC/F,MAAM,OAAO,kBAAkB,QAAQ,SAAS,EAAE,CAAC,QAAQ,CAAC;CAC5D,MAAM,QAAQ,qBAAqB,WAAW,MAAM,KAAK;CACzD,MAAM,OAAO,kBAAkB,QAAQ,MAAM,EAAE,CAAC,QAAQ,CAAC;CACzD,MAAM,OAAO,kBAAkB,QAAQ,MAAM,EAAE,CAAC,QAAQ,CAAC;AAEzD,QAAO,eAAe;EAAE,GAAG;EAAO;EAAM;EAAM,GAAG;EAAC;EAAM;EAAO;EAAK,CAAC"}
|
|
@@ -239,6 +239,7 @@ declare const createProjectionEngine: (options: {
|
|
|
239
239
|
type ProjectionStore = {
|
|
240
240
|
get<K extends string, V>(projection: CollectionProjection<K, V>): CollectionRead<K, V>;
|
|
241
241
|
get<T>(projection: ValueProjection<T>): T;
|
|
242
|
+
item<K extends string, V>(projection: CollectionProjection<K, V>, key: K): Readable<V | undefined>;
|
|
242
243
|
set<T>(projection: InputProjection<T>, value: T): void;
|
|
243
244
|
subscribe<K extends string, V>(projection: CollectionProjection<K, V>, listener: (change: CollectionImpact<K>) => void): Unsubscribe;
|
|
244
245
|
subscribe<T>(projection: ValueProjection<T>, listener: () => void): Unsubscribe;
|
|
@@ -259,4 +260,4 @@ declare const createProjectionStore: (options: {
|
|
|
259
260
|
}) => ProjectionStore;
|
|
260
261
|
//#endregion
|
|
261
262
|
export { ProjectionDisposedError as C, project as S, ProjectionSources as _, AdvancedCollectionSpec as a, ValueProjection as b, CollectionProjection as c, DocumentCollectionProjection as d, DocumentEvent as f, ProjectionEvents as g, Projection as h, AdvancedCollectionProcess as i, CollectionSource as l, InputProjection as m, createProjectionStore as n, AdvancedValueSpec as o, DocumentProjection as p, projectionStoreDebug as r, CollectionEvent as s, ProjectionStore as t, DocumentCollectionEvent as u, ProjectionValues as v, ProjectionError as w, input as x, ValueEvent as y };
|
|
262
|
-
//# sourceMappingURL=store-
|
|
263
|
+
//# sourceMappingURL=store-2i8pYXqa.d.ts.map
|
|
@@ -2514,6 +2514,11 @@ const createProjectionStore = (options) => {
|
|
|
2514
2514
|
if ("current" in instance && typeof instance.current === "function") return instance.current();
|
|
2515
2515
|
throw new TypeError("Projection is a source and has no published value.");
|
|
2516
2516
|
}),
|
|
2517
|
+
item: ((projection, key) => {
|
|
2518
|
+
const instance = materialize(projection);
|
|
2519
|
+
if (!("item" in instance) || typeof instance.item !== "function") throw new TypeError("Projection is not a materialized collection.");
|
|
2520
|
+
return instance.item(key);
|
|
2521
|
+
}),
|
|
2517
2522
|
set: (projection, value) => {
|
|
2518
2523
|
materialize(projection);
|
|
2519
2524
|
const target = inputs.get(projection);
|
|
@@ -2551,4 +2556,4 @@ const createProjectionStore = (options) => {
|
|
|
2551
2556
|
//#endregion
|
|
2552
2557
|
export { object as A, parse as B, createAccess as C, field as D, compilePath as E, ParseError as F, checkKey as I, checkValue as L, table as M, tree as N, list as O, variant as P, copyValue as R, same as S, snapshot as T, readWith as _, input as a, TransactionRejected as b, createNotification as c, shareNotification as d, subscribeDependencies as f, bindRuntimeAccess as g, accessOf as h, ProjectionError as i, optional as j, map as k, disposeNotification as l, subscribeTargets as m, projectionStoreDebug as n, project as o, subscribeRoot as p, ProjectionDisposedError as r, bindDocumentReadable as s, createProjectionStore as t, notify as u, DocumentDisposedError as v, replace as w, createImpact as x, DocumentReentrancyError as y, equalValue as z };
|
|
2553
2558
|
|
|
2554
|
-
//# sourceMappingURL=store-
|
|
2559
|
+
//# sourceMappingURL=store-7XBEcR8s.js.map
|