Composable UI frames and the universal page substrate (0346) - #552
Merged
Conversation
…e substrate
Exploration 0346: what is the UI's compositional unit, and what is the
consistent blank-page substrate?
- Compositional unit: the Frame — {source, viewType, config, tier} — a
live placeable rendering of a node/query/collection through the
ViewRegistry. The repo has four half-implementations (editor embeds,
canvas cards, dashboard widgets, workbench tabs); unify, don't invent.
- Substrate: every page is a document (title + frame stack); grid
(dashboard) and space (canvas) become geometries of the same frame
children, not separate products (BlockSuite/Muse proof).
- Studs made visible: page-scoped entangle bus (hover/select co-presence
across frames), relations badge/rail, drop-to-relate.
- Agents compose declaratively via the existing plan/validate/apply
pipeline (frame-placement tools), never throwaway codegen by default.
- Phase 1 is nearly free: databaseEmbed blocks ship in the editor schema
but XNetEditorHost.renderDatabaseView is wired nowhere — lighting it
gives live database-in-document transclusion with zero new sync code.
- Named gate: 0317 invalidation precision becomes load-bearing for
many-frame pages.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: xNet Test <test@xnet.dev>
…transclusion, /view of… (0346 P1) Phase 1 of exploration 0346 (composable UI frames): - databaseEmbed blocks render LIVE through the app's ViewRegistry: XNetEditorHost.renderDatabaseView is now wired in apps/web (was wired nowhere — embeds rendered a placeholder). Any registry view type (board, map, timeline, plugin views) works inside a document; table renders through the grid engine. Compact bounded card with open affordance (DatabaseEmbed). - pageEmbed blocks upgrade from navigation cards to summary-tier live transclusion via the new renderPageEmbed host callback: live title + first blocks as read-only text with an expand affordance (PageEmbedPreview + extractDocPreviewLines). Nested embeds degrade to marker lines, so transclusion cannot recurse. - /view of… slash command: onSelectDatabaseView host picker enumerates the ViewRegistry (plus shell-owned table) — plugin views are insertable the moment they register (DatabaseViewPicker). - resolveDatabaseMeta wired via the node store. - Seed: 'Composable Frames Demo' page — table frame + map frame of the SAME accounts database (lat/lng), proving cross-frame reactivity, plus a transcluded sample page. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
…irror (0346 P1)
Two integration bugs found by live browser verification of the demo page:
- Embed blocks ballooned to the grid's natural width (2476px inside a
~700px document column) because the BlockNote content wrapper is a
flex row and the NodeView wrapper had no min-width. w-full min-w-0
max-w-full restores containment and activates the grid's own
horizontal scroller.
- Clicks and keystrokes inside a database frame were double-handled by
ProseMirror (native listeners on the ancestor editor element re-grab
focus and node-select the block), so cell edits landed in the document
text. meta: { selectable: false } applies BlockNote's stopEvent
isolation to databaseEmbed and pageEmbed NodeViews; block deletion
still works through the side-menu drag handle.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: xNet Test <test@xnet.dev>
…containers (0346 P2)
Phase 2 of exploration 0346:
- New frames sub-barrel in @xnetjs/views: FrameDef {source, viewType,
config, tier, sortKey, layout} with the Set/Collection duality
(node | query | collection sources) and the CanvasPreviewTier cost
ladder. FrameRenderer dispatches node sources through a
schema-matched frameSourceRegistry, query sources through
SavedViewRunner, collections as live curated lists; transclusion
depth clamps at 2 via context.
- Container adapters (frameFromDatabaseEmbed / frameFromPageEmbed /
frameFromCanvasNode) shim the pre-frame contracts onto FrameDef.
- Generic dashboard frame widget (frame.node): any node through any
registered view as a tile; collection frames configured in place.
- frame tab escape hatch: /frame/<viewType>~<nodeId> + a single 'frame'
TabNodeType open any registry/plugin view full-bleed — plugin views
become openable surfaces with zero app edits.
- 'Open with…': tab-header switcher on database/frame tabs and an
in-embed view switcher (persisted onto the block via the new
onChangeViewType host callback).
- Persistence decision memo: docs/specs/FRAME_PERSISTENCE.md — doc-stack
frames stay block props (content), grid/space arrangements stay node
data (queryable presentation), with the id conventions.
- App wiring: frame source renderers registered once
(lib/frame-renderers.tsx); DashboardView provides the FrameHost.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: xNet Test <test@xnet.dev>
…late (0346 P3) Phase 3 of exploration 0346: the coupling becomes visible. - Entangle bus (@xnetjs/react): page-scoped hover/select co-presence. One bus per page surface (PageView, FrameTabView); per-node subscriptions via useSyncExternalStore so only affected elements re-render. Adopted by grid rows, board cards, calendar chips (extracted CalendarEventBar), map pins (publish on hover + an amber halo layer filtered from the bus), and wikilink chips in the document — hover a row in one frame and the same node lights up in every sibling frame. Hooks no-op without a provider. - Relations rail: the database right island gains a 'Linked from' section — ReverseRelationsPanel (previously unwired) shows rows in other databases whose relation cells point at the peeked row, with per-group 'Open as frame' opening the linking database as a frame tab. - Drop-to-relate: dropping a workspace node onto a database frame offers reversible verbs — add a row titled after the node, or add a row linked through a relation field targeting the dragged row's database. Dropping a database onto a page inserts a LIVE frame (table view); other nodes keep the wikilink reference chip. - Sealed frames: unauthorized/unavailable sources render a calm sealed card in FrameRenderer and both embed components (shipped in P1/P2, boxed here). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
…mes, geometry axis, cycle guard (0346 P4) Phase 4 of exploration 0346: - Node passport: one shared identity section (type, id, created, author) on the right island of every node surface — pages, databases, canvases, and frame tabs all carry the same chrome (apps/web NodePassport, live via subscribeToNode). - Promoted frames: a frame tab renders its database full-bleed (the tab IS the frame) — config.promoted drops the bounded card in favor of full-height chrome, keeping /db as the native surface. - Geometry axis: pages gain geometry: stack | grid | space (select, default stack — additive schema change). The arrangement model (orderForStack / withLayoutDefaults / toggleGeometry) lives in frames/geometry.ts with the round-trip invariant proven by test: toggling geometries preserves the exact frame set; only missing layouts gain defaults. Stack ordering uses code-unit collation. - Convergence per the 0277 playbook: surfaces remain, engines shared — grid rendering is the Dashboard engine (frame widget), space is the Canvas engine (frameFromCanvasNode); recorded in docs/specs/FRAME_PERSISTENCE.md rather than minting a third engine. - Cycle guard: FrameRenderer tracks node ancestry through context — A→A and A→B→A degrade to the summary card, alongside the existing depth-2 clamp. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
…node scope, webhook sink (0346 P5) Phase 5 of exploration 0346: - Agent frame tools (declarative tier): xnet_plan_frame_placement appends live-frame directives (:::xnet-database / :::xnet-page) to a page through the standard plan pipeline (review diff, page.propose); xnet_apply_frame_placement applies with confirmApply (audited, rollbackable); xnet_compose_page creates a page and seeds intro + frames in one audited step — 'set up a trip planner' yields a page of live, human-editable frames, never throwaway generated UI. Tool surface characterization updated; round-trip tests added. - Cross-node formula scope: RELATED(relationColumn, targetColumn) and NODE(nodeId, property) context functions in the one wired formula engine (no second engine, per Coda's lesson). Hosts pre-resolve synchronously via the new FormulaScope; scope formulas bypass the value cache until 0317's predicate-aware invalidation lands; absent scope degrades to empty/null. - 0213 webhook seam closed as a library: createFrameAwareDeliver materializes inbox deliveries into space-stamped ExternalItem nodes (payload-capped) and createIntegrationApply does the same for the signed Stripe/Sentry/PagerDuty actions — both stamp an optional frameTarget page so clients surface the feed as a live frame. Exported from @xnetjs/hub with tests. - Plugin capability rule: registerFrameRenderer namespaces renderer ids under the plugin id and refuses to shadow other providers; the app bridge additionally never lets a plugin override a first-party frame renderer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
…age substrate All 25 implementation items and 11 validation items complete. Adds the frame nesting-clamp react tests and the user-facing changelog fragment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
Contributor
|
Preview removed for PR #552. |
Contributor
🖼️ UI changes in this PRScreensInteractionsAuto-captured by CI · run. Informational — not a blocking check. |
…t two files Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
The frame-tab route rides the web workbench tab machinery; the desktop renderer adopts it with the deferred ShellFrame port (0280 risk 6). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: xNet Test <test@xnet.dev>
crs48
added a commit
that referenced
this pull request
Jul 18, 2026
…e npm Release) (#557) The 0346 changeset listed release-ignored packages (`@xnetjs/editor`, `@xnetjs/views`) alongside published ones, which changesets rejects ("Mixed changesets… are not allowed") — the npm Release workflow has been failing on main since #552 merged. This drops the ignored entries (those packages ship with the app; no changeset needed) and keeps `react`/`plugins`/`data` minor. `changeset status` assembles cleanly with no major bumps. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
crs48
added a commit
that referenced
this pull request
Jul 18, 2026
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @xnetjs/data@2.5.0 ### Minor Changes - [#552](#552) [`c7ef045`](c7ef045) Thanks [@crs48](https://github.com/crs48)! - Composable UI frames (exploration 0346). The `@xnetjs/editor` and `@xnetjs/views` surfaces are release-ignored packages; their changes ship with the app. Live embeds in documents (Phase 1): `databaseEmbed` blocks now pass any registry view type through to the host (map, timeline, plugin views — not just the built-in six), `pageEmbed` blocks render a host-provided live summary transclusion via the new `renderPageEmbed` host callback, and the slash menu gains a `/view of…` command backed by the new `onSelectDatabaseView` host picker. Adds `extractDocPreviewLines` for summary-tier text extraction from a v4 document fragment. `@xnetjs/views` gains the Frame contract (0346 Phase 2): `FrameDef` / `FrameSource` / `FrameTier`, the `FrameRenderer` + `frameSourceRegistry` (schema-dispatched node frames, saved-query frames, curated collection frames, depth-clamped transclusion), container adapters (`frameFromDatabaseEmbed` / `frameFromPageEmbed` / `frameFromCanvasNode`), and the generic dashboard frame widget (`registerFrameWidget`). `@xnetjs/react` gains the entangle bus (0346 Phase 3): `EntangleProvider` / `useEntangledHighlight` / `useEntangleBind` — page-scoped hover/select co-presence so frames on one page (grid rows, board cards, calendar chips, map pins, wikilink chips) highlight the same node together. `ReverseRelationsPanel` gains an `onOpenAsFrame` action. `@xnetjs/plugins` (0346 Phase 5): new agent tools `xnet_plan_frame_placement` / `xnet_apply_frame_placement` / `xnet_compose_page` — the agent composes pages of live frames through the standard plan → validate → apply pipeline (declarative tier only). Plugins gain `registerFrameRenderer` with the own-views-only namespacing rule. `@xnetjs/data` (0346 Phase 5): cross-node formula scope — `RELATED()` and `NODE()` context functions widen the one formula language from row → relations → named nodes (host-resolved, cache-bypassed until 0317's precise invalidation). Pages gain an additive `geometry: stack | grid | space` property (default `stack`). ### Patch Changes - Updated dependencies []: - @xnetjs/storage@2.5.0 - @xnetjs/sqlite@2.5.0 - @xnetjs/sync@2.5.0 - @xnetjs/identity@2.5.0 - @xnetjs/crypto@2.5.0 - @xnetjs/core@2.5.0 ## @xnetjs/plugins@2.5.0 ### Minor Changes - [#552](#552) [`c7ef045`](c7ef045) Thanks [@crs48](https://github.com/crs48)! - Composable UI frames (exploration 0346). The `@xnetjs/editor` and `@xnetjs/views` surfaces are release-ignored packages; their changes ship with the app. Live embeds in documents (Phase 1): `databaseEmbed` blocks now pass any registry view type through to the host (map, timeline, plugin views — not just the built-in six), `pageEmbed` blocks render a host-provided live summary transclusion via the new `renderPageEmbed` host callback, and the slash menu gains a `/view of…` command backed by the new `onSelectDatabaseView` host picker. Adds `extractDocPreviewLines` for summary-tier text extraction from a v4 document fragment. `@xnetjs/views` gains the Frame contract (0346 Phase 2): `FrameDef` / `FrameSource` / `FrameTier`, the `FrameRenderer` + `frameSourceRegistry` (schema-dispatched node frames, saved-query frames, curated collection frames, depth-clamped transclusion), container adapters (`frameFromDatabaseEmbed` / `frameFromPageEmbed` / `frameFromCanvasNode`), and the generic dashboard frame widget (`registerFrameWidget`). `@xnetjs/react` gains the entangle bus (0346 Phase 3): `EntangleProvider` / `useEntangledHighlight` / `useEntangleBind` — page-scoped hover/select co-presence so frames on one page (grid rows, board cards, calendar chips, map pins, wikilink chips) highlight the same node together. `ReverseRelationsPanel` gains an `onOpenAsFrame` action. `@xnetjs/plugins` (0346 Phase 5): new agent tools `xnet_plan_frame_placement` / `xnet_apply_frame_placement` / `xnet_compose_page` — the agent composes pages of live frames through the standard plan → validate → apply pipeline (declarative tier only). Plugins gain `registerFrameRenderer` with the own-views-only namespacing rule. `@xnetjs/data` (0346 Phase 5): cross-node formula scope — `RELATED()` and `NODE()` context functions widen the one formula language from row → relations → named nodes (host-resolved, cache-bypassed until 0317's precise invalidation). Pages gain an additive `geometry: stack | grid | space` property (default `stack`). ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/data@2.5.0 - @xnetjs/abuse@2.5.0 - @xnetjs/core@2.5.0 ## @xnetjs/react@2.5.0 ### Minor Changes - [#552](#552) [`c7ef045`](c7ef045) Thanks [@crs48](https://github.com/crs48)! - Composable UI frames (exploration 0346). The `@xnetjs/editor` and `@xnetjs/views` surfaces are release-ignored packages; their changes ship with the app. Live embeds in documents (Phase 1): `databaseEmbed` blocks now pass any registry view type through to the host (map, timeline, plugin views — not just the built-in six), `pageEmbed` blocks render a host-provided live summary transclusion via the new `renderPageEmbed` host callback, and the slash menu gains a `/view of…` command backed by the new `onSelectDatabaseView` host picker. Adds `extractDocPreviewLines` for summary-tier text extraction from a v4 document fragment. `@xnetjs/views` gains the Frame contract (0346 Phase 2): `FrameDef` / `FrameSource` / `FrameTier`, the `FrameRenderer` + `frameSourceRegistry` (schema-dispatched node frames, saved-query frames, curated collection frames, depth-clamped transclusion), container adapters (`frameFromDatabaseEmbed` / `frameFromPageEmbed` / `frameFromCanvasNode`), and the generic dashboard frame widget (`registerFrameWidget`). `@xnetjs/react` gains the entangle bus (0346 Phase 3): `EntangleProvider` / `useEntangledHighlight` / `useEntangleBind` — page-scoped hover/select co-presence so frames on one page (grid rows, board cards, calendar chips, map pins, wikilink chips) highlight the same node together. `ReverseRelationsPanel` gains an `onOpenAsFrame` action. `@xnetjs/plugins` (0346 Phase 5): new agent tools `xnet_plan_frame_placement` / `xnet_apply_frame_placement` / `xnet_compose_page` — the agent composes pages of live frames through the standard plan → validate → apply pipeline (declarative tier only). Plugins gain `registerFrameRenderer` with the own-views-only namespacing rule. `@xnetjs/data` (0346 Phase 5): cross-node formula scope — `RELATED()` and `NODE()` context functions widen the one formula language from row → relations → named nodes (host-resolved, cache-bypassed until 0317's precise invalidation). Pages gain an additive `geometry: stack | grid | space` property (default `stack`). ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/plugins@2.5.0 - @xnetjs/data@2.5.0 - @xnetjs/runtime@0.5.5 - @xnetjs/data-bridge@2.5.0 - @xnetjs/history@2.5.0 - @xnetjs/sync@2.5.0 - @xnetjs/identity@2.5.0 - @xnetjs/crypto@2.5.0 - @xnetjs/core@2.5.0 ## @xnetjs/abuse@2.5.0 ### Patch Changes - Updated dependencies []: - @xnetjs/identity@2.5.0 - @xnetjs/crypto@2.5.0 ## @xnetjs/cli@0.3.1 ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/plugins@2.5.0 - @xnetjs/data@2.5.0 - @xnetjs/runtime@0.5.5 - @xnetjs/sqlite@2.5.0 - @xnetjs/sync@2.5.0 - @xnetjs/identity@2.5.0 - @xnetjs/crypto@2.5.0 - @xnetjs/core@2.5.0 ## @xnetjs/crypto@2.5.0 ### Patch Changes - Updated dependencies []: - @xnetjs/core@2.5.0 ## @xnetjs/data-bridge@2.5.0 ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/data@2.5.0 - @xnetjs/sqlite@2.5.0 - @xnetjs/sync@2.5.0 - @xnetjs/core@2.5.0 ## @xnetjs/history@2.5.0 ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/data@2.5.0 - @xnetjs/sync@2.5.0 - @xnetjs/core@2.5.0 ## @xnetjs/identity@2.5.0 ### Patch Changes - Updated dependencies []: - @xnetjs/crypto@2.5.0 - @xnetjs/core@2.5.0 ## @xnetjs/runtime@0.5.5 ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/plugins@2.5.0 - @xnetjs/data@2.5.0 - @xnetjs/data-bridge@2.5.0 - @xnetjs/history@2.5.0 - @xnetjs/storage@2.5.0 - @xnetjs/sync@2.5.0 - @xnetjs/identity@2.5.0 - @xnetjs/crypto@2.5.0 - @xnetjs/core@2.5.0 ## @xnetjs/storage@2.5.0 ### Patch Changes - Updated dependencies []: - @xnetjs/sqlite@2.5.0 - @xnetjs/crypto@2.5.0 - @xnetjs/core@2.5.0 ## @xnetjs/sync@2.5.0 ### Patch Changes - Updated dependencies []: - @xnetjs/identity@2.5.0 - @xnetjs/crypto@2.5.0 - @xnetjs/core@2.5.0 ## @xnetjs/core@2.5.0 ## @xnetjs/sqlite@2.5.0 ## xnet-cloud@0.0.23 ### Patch Changes - Updated dependencies []: - @xnetjs/telemetry@0.0.1 - @xnetjs/crypto@2.5.0 - @xnetjs/core@2.5.0 - @xnetjs/cloud@0.0.1 ## xnet-demos@0.1.7 ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/react@2.5.0 - @xnetjs/data@2.5.0 - @xnetjs/devtools@0.1.0 - @xnetjs/identity@2.5.0 ## @xnetjs/brain@0.0.24 ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/data@2.5.0 - @xnetjs/vectors@0.0.1 ## @xnetjs/comms@0.0.24 ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/data@2.5.0 - @xnetjs/crypto@2.5.0 ## @xnetjs/dashboard@0.0.24 ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/react@2.5.0 - @xnetjs/plugins@2.5.0 - @xnetjs/data@2.5.0 - @xnetjs/social@0.0.24 ## @xnetjs/labs@0.0.24 ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/plugins@2.5.0 - @xnetjs/data@2.5.0 ## @xnetjs/licenses@0.0.24 ### Patch Changes - Updated dependencies []: - @xnetjs/crypto@2.5.0 ## @xnetjs/maps@0.0.24 ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/data@2.5.0 ## @xnetjs/meetings@0.0.17 ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/plugins@2.5.0 - @xnetjs/data@2.5.0 ## @xnetjs/server@0.0.23 ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/data@2.5.0 - @xnetjs/data-bridge@2.5.0 - @xnetjs/identity@2.5.0 - @xnetjs/crypto@2.5.0 ## @xnetjs/social@0.0.24 ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/data@2.5.0 - @xnetjs/crypto@2.5.0 ## @xnetjs/unreal@0.0.24 ### Patch Changes - Updated dependencies [[`c7ef045`](c7ef045)]: - @xnetjs/data@2.5.0 ## xnet-desktop@2.5.0 Desktop shell release riding the @xnetjs/core 2.5.0 train. Desktop-specific changes are not tracked here; see the core packages' changelogs for what shipped.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
Implements exploration 0346 end to end — the UI's compositional unit (the Frame), the universal page substrate, visible relations, and agents as declarative composers. Five phases, each independently reviewed by commit:
Phase 1 — Light the embeds (
c7ef045, fix1ba00d4)databaseEmbedblocks render live through the ViewRegistry (the host hookrenderDatabaseViewwas wired nowhere — embeds showed a placeholder). Any registry view works inside a document: board, map, calendar, plugin views; table renders through the grid engine.pageEmbedupgrades from a navigation card to summary-tier live transclusion (renderPageEmbed+extractDocPreviewLines; nested embeds degrade to marker lines, so transclusion cannot recurse)./view of…slash command with a registry-enumerated view chooser.min-w-0on the NodeView wrapper) and ProseMirror event isolation (meta: { selectable: false }) so in-frame clicks/keys stop editing the document.Phase 2 — The Frame contract (
3478659)packages/views/src/frames/:FrameDef {source, viewType, config, tier, sortKey, layout}with the Set/Collection duality (node | query | collectionsources) and the canvas cost ladder;FrameRenderer+ schema-dispatchedframeSourceRegistry; container adapters; the generic dashboard frame widget./frame/<viewType>~<nodeId>+ oneframeTabNodeType — every plugin view becomes an openable surface with zero app edits.docs/specs/FRAME_PERSISTENCE.md.Phase 3 — Visible studs (
290bb2e)@xnetjs/react): page-scoped hover/select co-presence; adopted by grid rows, board cards, calendar chips, map pins (halo layer), and wikilink chips — hover a row and the same node lights up in every frame.ReverseRelationsPanel(previously unwired) on the database right island with per-group Open as frame.Phase 4 — One substrate, three geometries (
21d078f)/dbremains the untouched native surface).geometry: stack | grid | space(additive);toggleGeometrywith the round-trip invariant proven by test (frame set passes through unchanged).Phase 5 — Agents and formulas as composers (
6c12e59)xnet_plan_frame_placement/xnet_apply_frame_placement/xnet_compose_pageriding the existing plan→validate→apply pipeline (declarative tier only; audited; rollbackable). Tool-surface characterization updated.RELATED()/NODE()context functions (one engine; scope formulas bypass the value cache until 0317).createFrameAwareDeliver/createIntegrationApplymaterialize webhook deliveries intoExternalItemnodes with an optionalframeTargetpage.registerFrameRenderernamespaces ids per plugin; first-party renderers can't be shadowed.Validation
isRemoteedits take the identical invalidation path). Screenshot parity for promoted frames holds by construction (/dbsurface untouched).Changeset:
editor/views/react/plugins/dataminor (fixed-core lockstep). Changelog fragment included.🤖 Generated with Claude Code