Ordinary entry starts from a state's authored initial path. State.ShallowHistory gives a compound
state another entry route: restore the direct child that was active when the state last exited.
Remember the branch, not the leaf.
Leaving Workspace normally ends its active configuration. Shallow history records which direct child was active and uses that branch the next time you enter through it.
1 · Ordinary entry
Reentry forgets where you were.
Pause from Editing.Body, then return to Workspace itself. Ordinary entry follows the authored initial path, so the editor returns to Browsing and forgets both levels of prior geometry.
import { State, Statechart, States, Transitions } from "@motive/motive";
import { Schema } from "effect";
const BeginEditing = Schema.TaggedStruct("BeginEditing", {});
const EditBody = Schema.TaggedStruct("EditBody", {});
const Pause = Schema.TaggedStruct("Pause", {});
const Resume = Schema.TaggedStruct("Resume", {});
export class Editor extends State.Compound<Editor>()("Editor") {
static states = States.make(() => [Workspace, Paused]);
}
class Workspace extends State.Compound<Workspace>()("Workspace") {
static states = States.make(() => [Browsing, Editing]);
static transitions = Transitions.make(this, ({ on }) => [on(Pause, Paused)]);
}
class Browsing extends State.Atomic<Browsing>()("Browsing") {
static transitions = Transitions.make(this, ({ on }) => [
on(BeginEditing, Editing),
]);
}
class Editing extends State.Compound<Editing>()("Editing") {
static states = States.make(() => [Title, Body]);
}
class Title extends State.Atomic<Title>()("Title") {
static transitions = Transitions.make(this, ({ on }) => [on(EditBody, Body)]);
}
class Body extends State.Atomic<Body>()("Body") {}
class Paused extends State.Atomic<Paused>()("Paused") {
static transitions = Transitions.make(this, ({ on }) => [
on(Resume, Workspace),
]);
}
export const EditorChart = Statechart.make(Editor);
2 · One level of history
State.ShallowHistory restores the branch.
Recent remembers that Editing was active, then enters Editing through its ordinary initial path. The editor returns to Title, not the deeper Body leaf.
import {
HistoryDefault,
State,
Statechart,
States,
Transitions,
} from "@motive/motive";
import { Schema } from "effect";
const BeginEditing = Schema.TaggedStruct("BeginEditing", {});
const EditBody = Schema.TaggedStruct("EditBody", {});
const Pause = Schema.TaggedStruct("Pause", {});
const Resume = Schema.TaggedStruct("Resume", {});
export class Editor extends State.Compound<Editor>()("Editor") {
static states = States.make(() => [Workspace, Paused]);
}
class Workspace extends State.Compound<Workspace>()("Workspace") {
static states = States.make(() => [Browsing, Editing, Recent]);
static transitions = Transitions.make(this, ({ on }) => [on(Pause, Paused)]);
}
class Browsing extends State.Atomic<Browsing>()("Browsing") {
static transitions = Transitions.make(this, ({ on }) => [
on(BeginEditing, Editing),
]);
}
class Editing extends State.Compound<Editing>()("Editing") {
static states = States.make(() => [Title, Body]);
}
class Title extends State.Atomic<Title>()("Title") {
static transitions = Transitions.make(this, ({ on }) => [on(EditBody, Body)]);
}
class Body extends State.Atomic<Body>()("Body") {}
class Recent extends State.ShallowHistory()("Recent") {
static readonly default = HistoryDefault.make(this, () => Browsing);
}
class Paused extends State.Atomic<Paused>()("Paused") {
static transitions = Transitions.make(this, ({ on }) => [on(Resume, Recent)]);
}
export const EditorChart = Statechart.make(Editor);
Reentry has no memory
The first frame leaves Workspace from Editing.Body, then targets Workspace itself on resume.
That is an ordinary entry, so Workspace follows its initial path back to Browsing. Returning to
the same compound state does not imply returning to its former child.
Leaving also ends the old active lifetime. A later ordinary entry constructs fresh facets and remounts owned work just like any other entry; a matching state name does not continue the previous incarnation.
Shallow history remembers the direct child
The second frame adds Recent as a State.ShallowHistory child of Workspace. History is a route,
not a phase: Recent never appears in the active configuration and owns no live work.
When Workspace exits, shallow history records its active direct child, Editing. Resume restores
that child, then follows Editing's ordinary initial path to Title. It remembers which section was
open, but not the nested position inside that section.
The restored configuration is therefore Editor.Workspace.Editing.Title, not the previously active
Editor.Workspace.Editing.Body.
The default covers the absence of history
HistoryDefault.make is required because Recent may be targeted before Workspace has ever
exited. With no record to restore, the default routes to Browsing.
Once a record exists, the recorded direct child wins and the default is not consulted. The default does not initialize or reset the history store; it makes the no-history case explicit and total.
Test the route
- Target
RecentbeforeWorkspacehas exited and confirm that the default selectsBrowsing. - Change the initial child of
Editingand predict where shallow restoration enters it. - Put state-owned data on
EditingandBody, then observe which facet depth is restored.