-
-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature Request: useBranchedStateHistory #44
Comments
I haven't actually tested this, so I'm not 100% it will work. But this is my alpha. I will say, I noticed it doesn't really fit the pattern of the other history though, and I'm curious why the team chose to make some design decisions. I like to stay as close to the primitives (runes) as possible. Using abstractions like I also use classes instead of functions for two reasons. First, it's more readable. Second, the methods are in the prototype so they are not re-instantiated every time a new one is created. Reduce reuse recycle ♻️! UsageYou can create a BranchedHistory as follows: // Create state
const history = useBranchedStateHistory("original state")
// Change state
history.state = "some new state"
// Undo
history.undo() // history.state == "original state"
// Create new state
history.state = "a new branch!"
// Undo again
history.undo() // history.state == "original state"
// Get children
children = [...history.children] // [BranchNode {value: "some new state"}, BranchNode {value: "a new branch!"} ]
// Redo
history.redo() // Remembers the last "undid" branch, ergo history.state == "a new branch!"
// Go to specific node
history.goto(children[0]) // history.state == "original state" Proposed sourceimport { Set } from "svelte/reactivity";
/**
* Represents a specific state in the timeline
*/
class BranchNode<T> {
/**
* This is set to the node that we called undo from, so we know where to
* re-do. This should be reactive because it may change.
*/
public redoTarget = $state<BranchNode<T>>();
/**
* Children may change, so we're using Svelte's built-in reactivity set
*/
public readonly children = new Set<BranchNode<T>>();
constructor(
public readonly value: T,
/**
* parent will never change, and therefor does not need to be stateful
*/
public readonly parent: BranchNode<T> | undefined = undefined
) {}
}
class BranchedHistory<T> {
public readonly root: BranchNode<T>;
public node = $state<BranchNode<T>>() as BranchNode<T>;
constructor(def: T) {
this.root = new BranchNode(def);
this.node = this.root;
}
public get state() {
return this.node!.value;
}
public set state(v: T) {
const parentNode = this.node!;
this.node = new BranchNode(v, parentNode);
parentNode.children.add(this.node);
}
canUndo = $derived(!!this.node.parent);
canRedo = $derived(!!this.node.redoTarget);
/**
* Branches coming off this node
*/
children = $derived(this.node.children);
/**
* Undefined if root note
*/
parent = $derived(this.node.parent);
/**
* Go to the selected node
* @param node
*/
public goto(node: BranchNode<T>) {
this.node = node;
}
public undo() {
if (!this.node.parent) return;
const redoNode = this.node;
this.node = this.node.parent;
this.node.redoTarget = redoNode;
}
public redo() {
if (!this.node.redoTarget) return;
this.node = this.node.redoTarget;
}
}
export function useBranchedStateHistory<T>(def: T) {
return new BranchedHistory(def);
} |
The const { x, y } = useMouse(); For returning values directly, I agree that |
Hey @petermakeswebsites , this could really be interesting! Do you want to submit a PR? |
Describe the feature in detail (code, mocks, or screenshots encouraged)
For a Svelte 5 app I made, I created a branched state history, not dissimilar to Git branches. I'd be happy to create an abstraction of this and add it to this lib. The idea is essentially as follows:
Is this something you would all find useful?
What type of pull request would this be?
New Feature
Provide relevant links or additional information.
No response
The text was updated successfully, but these errors were encountered: