foldkit@0.157.0
Minor Changes
-
#1000
f26af99Thanks @devinjameson! -Machine.unreachableStatesandMachine.deadTransitionsaccept an optional array of extra walk roots for entry states the declared Edge set does not reach frominitial, such as states restored from persistence or entered through deep links. The roots are additive:initialis always a root, so passing extra roots can only shrink the findings. The analysis docs now state their assumptions plainly: the results describe the declared Edge set walked from its roots, the walk cannot see state advanced outsidetransitionandstep, and entry points other thaninitialmust be passed as extra roots or the analysis reports false positives. -
#1229
13f4f70Thanks @devinjameson! - Let Mount integrations observe whether the rendered view isLiveorPausedthrough the newviewStateChangesStream supplied toMount.defineandMount.defineStreamexecution.The Stream begins with the rendered view state at the moment the Mount is acquired and stays open for the Mount's lifetime. That initial state is retained across asynchronous setup before the Stream is consumed. A live-acquired Mount that survives a time-travel render stays acquired and observes
Live, thenPaused, thenLiveafter the latest live view has been patched back into the DOM. A Mount inserted by a replay starts inPaused, and a runtime without time travel reports onlyLive.A Mount acquired by a historical render cannot dispatch to the live Model. If the resumed live view reuses its element and declares a Mount there, Foldkit releases the replay acquisition before starting the live action with the current args and dispatch. A Mount acquired by the live view stays live so asynchronous setup and external streams can continue; its results follow the latest live Submodel wiring without crossing into historical wiring. Integrations use
viewStateChangesto stop DOM-derived interaction while the historical view is installed. Commands, Subscriptions, ManagedResources, the live Model, and DevTools history also continue normally.This reserves
viewStateChangesas a runtime-supplied Mount execution field. Rename any Mount arg with that name before upgrading. The low-levelMountAction.fview-state parameter is now required; MountAction wrappers must accept and forward it.Custom renderers without time travel can pass the public
Mount.liveViewStateChangesStream to that parameter. It emitsLiveimmediately and stays open. -
#1268
3a4ccd0Thanks @devinjameson! - Preserve structurally refined payload types in exhaustive Foldkit union matchers, migrate OutMessage folds to their owning union matcher, and addAnimation.toggleas a child-owned visibility entry point. -
#1273
62ae446Thanks @devinjameson! - Preserve Message and OutMessage type safety across Story and Scene steps.Story.message,Story.expectOutMessage,Scene.Subscription.emit,Scene.expectOutMessage, andScene.expectOutMessagesare now typed data steps rather than callable simulation transforms. Story and Scene validate those values against the Message and OutMessage types of the update under test, including narrow variants of a wider union.Migration
Passing these steps directly to
storyorsceneis unchanged. Any code that treated one of these returned steps as a function must migrate, including direct invocation, storing it as a simulation transform, or composition through Effect'sflowor another helper in either Story or Scene.Use the new
Story.stepsAPI for a reusable Story sequence. It accepts the same steps asstory, preserves their Model, Message, and OutMessage constraints, and can itself be passed anywhere a Story step is accepted.Scene has no grouped-step API. Pass
Subscription.emitand OutMessage assertion steps as separate arguments toscene; do not compose them as functions.Before:
import { flow } from 'effect' import { given, message } from 'foldkit/story' const givenIncremented = flow( given({ count: 0 }), message(ClickedIncrement()), )
After:
import { given, message, steps } from 'foldkit/story' const givenIncremented = steps( given({ count: 0 }), message(ClickedIncrement()), )
Remove the
flowimport when it was used only to group Story steps. This is not a general deprecation of Effect'sflow; continue to use it for ordinary function composition outside the Story step API. -
#1269
b5ec356Thanks @devinjameson! - Reject children andh.InnerHTMLpassed toh.textareaorh.keyed('textarea')so the Model remains the field's single source of truth. This is a breaking change: move textarea content into the live value property withh.Value(text). The UI Textarea helper now exposes the narrowerTextareaAttributegroup. Animation wrapper elements and Virtual List row elements also excludetextareabecause both render children.
Patch Changes
-
#1250
21d56b2Thanks @devinjameson! - Rename the Foldkit philosophy page to “Why Foldkit” and update its URL in the package README. -
#1213
57e2436Thanks @devinjameson! - Use full Effect module names in published source, examples, templates, and documentation. JavaScript and TypeScript globals that share an Effect module name are now qualified throughglobalThis. -
#1114
1593f90Thanks @devinjameson! - Let a consumer export a Machine Edge built withtoorwhenfromfoldkit/experimental/machine.Edgehas a hidden field that carries the guard value type. Its key was aunique symbolthat Foldkit did not export. TypeScript had to write that key into the consumer's.d.tsfile, but it had no name for it, so it failed withTS4023: ... has or is using name 'EdgeGuardValueTypeId' ... but cannot be named. This hit any package that builds an Edge in one module and exports it, as soon as that package turned on declaration emit.When,Otherwise, andTransitionTableembedEdge, so exporting any of them hit the same error.The key is now a normal property,
'~foldkit/EdgeGuardValue', following the same fix as the runtime boot key. Consumers need to do nothing. The field is still internal and still has no runtime representation. -
#1267
a43f524Thanks @devinjameson! - Move focus into dialogs when the requested initial target is missing or cannot receive focus.