feat(page-tree): show a node only when its row says so - #357
Open
mostafasadeghidev wants to merge 2 commits into
Open
feat(page-tree): show a node only when its row says so#357mostafasadeghidev wants to merge 2 commits into
mostafasadeghidev wants to merge 2 commits into
Conversation
A list whose items are not uniform cannot be built today. Two nodes sit in one card — a video player and a "Coming soon" caption — and exactly one belongs on any given row, decided by whether that row's video field is filled. The card is authored once, so every row gets a blank player or every row gets the caption. Visual CMSs generally call this conditional visibility, and content sites lean on it heavily; Instatic had no equivalent, only the static `hidden` switch. `visibleWhen` on a node names a source, a field and a test. The source is the set the prop bindings already use, so `currentEntry` inside a loop is that iteration's row. Two tests only — `isSet` and `isNotSet` — because comparisons against a value need an operand and a type model, and every case met so far is "does this row have one". Evaluated by the publisher beside `hidden`, where the effect is identical and only the reason differs. Deliberately NOT evaluated by the editor canvas: that is where the node gets edited, and one hidden because the preview row happens to have no video is one the author cannot click. It is the single place the two surfaces differ on purpose, and both the evaluator and this commit say so. A malformed condition parses to `undefined` and the node stays visible — the only safe direction, since the alternative is silently erasing content that was rendering fine. Dynamic detection gains rule 2c: a condition reading a request-dependent source makes the node a Layer C hole. Whether it renders at all now depends on that source, which is a stronger dependency than any prop binding — baking it would freeze one request's answer into the artefact for every visitor. The mutation lives in its own module rather than `mutations.ts`, which the size gate records as grandfathered debt that may only shrink.
…anel Without a control the condition could only be written by a plugin, which left the engine feature unreachable to the person it is for. Three fields in the Attributes view — source, field name, test — plus a sentence stating the rule in words. That sentence is doing real work. The node stays on the canvas whatever the condition says, because the canvas is where it gets edited and one hidden by the preview row is one the author cannot click. So the panel is the only place the editor can honestly report what will happen at publish time, and it says so outright rather than leaving the author to wonder why nothing moved. An empty field name clears the condition instead of storing it: a half-typed rule would otherwise hide the node against a field named "", which is never what was meant. Docs updated in the same change — `hidden` vs `visibleWhen` and what counts as set in the page-tree reference, rule 2c in the publisher's detection table with why a visibility dependency is stronger than a prop-binding one.
mostafasadeghidev
marked this pull request as ready for review
August 9, 2026 03:00
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.
The gap
A list whose items are not uniform cannot be built today.
Two nodes sit in one card — a video player and a "Coming soon" caption — and exactly one belongs on any given row, decided by whether that row's video field is filled. The card is authored once, so every row gets a blank player or every row gets the caption. Visual CMSs generally call this conditional visibility and content sites lean on it heavily; Instatic has only
hidden, which is the same on every render.The change
visibleWhenon a node names a source, a field and a test:source— the set the prop bindings already use, socurrentEntryinside abase.loopis that iteration's row. Dotted paths work (author.name).test—isSet/isNotSetonly. Comparisons against a value need an operand and a type model; every case met so far is "does this row have one".Set from the Properties panel's Attributes view, or with the
setNodeVisibleWhenstore action.Three decisions worth reviewing
The publisher hides; the editor canvas does not. Everywhere else the two surfaces are kept identical, and this is the one place they differ on purpose: the canvas is where the node gets edited, and one hidden because the preview row happens to have no video is one the author cannot click. The panel states the rule in words instead.
A malformed condition parses to
undefinedand the node stays visible — the only safe direction, since the alternative is silently erasing content that was rendering fine.Dynamic detection gains rule 2c. A condition reading a request-dependent source makes the node a Layer C hole. This is a stronger dependency than rule 2: a request-dependent binding changes what a node says, a request-dependent condition changes whether it is there at all, and baking it would freeze one visitor's answer into the artefact for everyone.
Impact
Additive and optional. A node without
visibleWhenbehaves exactly as before; no persisted data changes shape; no migration.setNodeVisibleWhenlives in a newpage-tree/nodeVisibility.tsrather thanmutations.ts, which the module-size gate records as grandfathered debt that may only shrink.Verification
Architecture gates were compared against a clean
maincheckout commit-by-commit: identical failure set, nothing added.