Expose React canvas hooks with scoped selectors and resource lifecycles

This commit is contained in:
2026-11-09 17:34:56 +08:00
parent d7b3321df1
commit 575b5a9256
18 changed files with 259 additions and 25 deletions
+48
View File
@@ -13,6 +13,7 @@ Public exports:
| `/service` | Foundry protocol codecs and transport adapters; credentials remain in the host |
| `/browser` | Explicit IndexedDB/Web Locks and module Worker adapters |
| `/bindings` | Portable projection, renderer descriptors, caches, connectors and hit queries |
| `/react` | React Provider and selector, element, action, mode, gesture, operation, asset and sync hooks; no React Flow runtime dependency |
| `/react-flow` | Explicit client adapter, renderer command context and framework node/edge types |
The portable entries have no React, Next, React Flow or other runtime package
@@ -248,3 +249,50 @@ its last live identity is retired. An older Root cannot release temporary bytes
that belong to a newer adoption revision. Collection is explicit and local; this
preview does not enable background deletion on Foundry or claim the full retention,
permission-race and product acceptance matrix is finished.
React bindings:
Wrap descendants in `CanvasProvider` with an existing `engine` and, for session
hooks, an already attached `viewId`. The Provider borrows both; unmounting it does
not close the project or detach a view owned by the host. Explicitly unmount the
surface, detach its view, and close the engine at their respective lifetimes.
Import from `/react` for React only, or the re-export in `/react-flow`.
- `useCanvas(selector, isEqual?)` observes the one immutable project Root. Default
equality is `Object.is`; choose an appropriate comparator for allocated results.
Snapshots are cached per selection and unchanged selections do not notify React.
- `useElement(idOrTarget)` returns `present`, `absent`, `unloaded`, or `stale`.
A Target includes incarnation; a restored element does not silently retarget it.
- `useActions(target)` exposes stable `rename`, `setData`, `resize`, `remove`, and
`moveTo` facades over normal editor commands. Optional command settings retain
label/grouping/history semantics. Call actions from events, not during render.
- `useMode(target)` returns the current view's mode and `setMode`; it never writes
document/history state. Missing view context is an explicit error.
- `useGestureBindings(target)` returns effective geometry, active ownership and
`begin/update/commit/cancel`. A token protects the lease; cleanup cancels only
its own lease. Host input bindings still handle pointer capture and events.
- `useOperation(id)` observes both the logical record and its frozen request.
- `useAsset(id)` resolves a releasable display handle, returns metadata plus
loading/ready/error/url/retry, and releases on ref/owner change or unmount.
Ready means the display handle resolved; it does not prove upload ACK, image
decoding or a successful subsequent fetch of a remote fallback URL.
- `useSyncStatus(canvasId?)` reports pending/blocked/unknown work plus loading,
dirty and persistence errors. Durability is project-wide even when filtering
operations to one canvas. It does not call an undurable Root synced. Pending
counts logical ledger work; running generation/import job progress is observed
separately from document synchronization.
`engine.getDurability()` now returns a stable readonly snapshot including closing,
closed and an optional error. `subscribeDurability` observes successful cuts,
failures and closure without creating another business Root. Hooks and the Provider
own no second document, ledger, network queue or storage lifecycle. Source selectors
still run on Root notifications; this is not a claim of complete per-field indexing.
A React renderer may use these hooks once its real engine exists. For the early
read-only preview before an engine opens, declare a separate `preview` renderer in
its `ReactRendererDefinition`. The assembly exposes `previewNodeTypes` and
`previewEdgeTypes`. An omitted preview gets a passive preparing placeholder; the
app never constructs a fake editor merely to satisfy the hooks. Preview functions
must render the supplied records without requiring CanvasProvider. Built-in preview
renderers are registered explicitly. Framework definitions never enter core data.
+4
View File
@@ -34,6 +34,10 @@
"./react-flow": {
"types": "./modules/canvas-bindings/react-flow.d.ts",
"import": "./modules/canvas-bindings/react-flow.js"
},
"./react": {
"types": "./modules/canvas-bindings/react.d.ts",
"import": "./modules/canvas-bindings/react.js"
}
},
"files": [