npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

yjs-orderedtree

v1.0.1-beta.3

Published

An ordered tree class for yjs. Lets you use a Y.Map like an ordered tree with insert, delete, and move operations. The children are ordered and the position of a child amongst its sibling can be manipulated

Readme

yjs-orderedtree

An ordered tree class for yjs. Lets you use a Y.Map like an ordered tree with insert, delete, and move operations. The children are ordered and the position of a child amongst its sibling can be manipulated.
yjs-orderedtree uses logic and code https://madebyevan.com/algos/crdt-mutable-tree-hierarchy/ and https://madebyevan.com/algos/crdt-fractional-indexing/ to facilitate this.

How it works

The YTree class manages the logic for the tree and ordering operations. It is associated with a Y.Map that it uses to hold information that must be synchronized with peers/clients, that information being the parent history of every node.

It holds a virtual map that is recalculated everytime the tree changes. That virtual map holds calculated values like a node's parent and children. YTree functions usually interact with this virtual map when fetching information about nodes, and they interact with the Y.Map when adding or updating nodes. 

A Y.Map associated with a YTree must have a certain structure. It doesn't absolutely check for this structure, it only checks that the mandatory root node exists. 

Installation

npm i yjs-orderedtree

Usage

Create or fetch a valid Y.Map and pass it to the YTree constructor to use the Y.Map as an ordered tree.

A Y.Map is valid when:

  • It is empty. (Creating a new tree)
  • When it has already been initialized. (Loading an existing tree)

If an initiated Y.Map is passed to the constructor, then the tree structure is setup and the virtual map is computed.

If the constructor is passed an empty Y.Map then it will initiate it by creating a new root node. That would overwrite an existing YTree, if that Y.Map was being used to hold information for a YTree. 

So be aware of when you are creating or loading a YTree. When loading a YTree, check if the Y.Map has been initiated with CheckForYtree().

Creating a tree

Create an empty Y.Map bounded to a yjs document

// create Y.Map
const yMap = new Y.Map();
// bound it to a yjs document
ydoc.getMap("ytree", yMap);
// use YTree constructor to get a YTree object
const yTree = new YTree(yMap);

or

// create Y.Map
const yMap = ydoc.getMap("ytree", new Y.Map());
// use YTree constructor to get a YTree object
const yTree = new YTree(yMap);

Loading a tree

Take the Y.Map and make sure that is initiated by using CheckForYTree

// fetch Y.Map
const yMap = ydoc.getMap("ytree);
if (!checkForYTree(yMap)) {
    throw new Error("Y.Map is not initiated");
}
const yTree = new YTree(yMap);

Using the tree

Take a look at the API reference :)

API Reference

function checkForYTree

checkForYTree(Y.Map):boolean

Checks if the Ymap has been initialized for YTree operations. It specifically checks if root node exists. This should be done any time you want to load a ytree and not create it.

class YTree

const yTree = new YTree(yMap);

YTree uses https://madebyevan.com/algos/crdt-mutable-tree-hierarchy/ and https://madebyevan.com/algos/crdt-fractional-indexing/

It uses them to implement an ordered tree data structure, on top of YJS https://github.com/yjs/yjs, that maintains synchronization and consistency across multiple clients.

constructor(Y.Map): YTree

Constructor is required to be called with a Y.Map instance that is bound to a Y.Doc.

The YMap is required to be empty or initialized.  If given an empty (uninitialized) YMap then it initializes the YMap for YTree operations by creating a root node. If you don't want to accidentally create a Ytree then use checkForYTree beforehand to ensure that a YTree has been initialized.

generateNodeKey(): string

Generates a globally unique node key

createNode(parentKey: string, nodeKey: string, value: object | boolean | string | number | Uint8Array | Y.AbstractType): void

Creates a Node with the given parent and the given value

yTree.createNode("root", yTree.generateNodeKey(), "a_value");

const yArray = new Y.Array();
yTree.createNode("root", yTree.generateNodeKey(), yArray);

yTree.createNode("root", "yourGloballyUniqueKey", 1234);

deleteNodeAndDescendants(nodeKey: string): void

Deletes the node and its descendants

moveChildToParent(childKey: string, parentKey: string): void

Reparents or moves a child to a new parent 

setNodeValueFromKey(nodeKey: string, value: object | boolean | string | number | Uint8Array | Y.AbstractType<any>): void

Sets a value on a node

getNodeValueFromKey(nodeKey: string): object | boolean | string | number | Uint8Array | Y.AbstractType<any>

Gets a value from a node

getNodeChildrenFromKey(nodeKey: string): Array<string>

Get a list of keys of the node's children from the virtual (computed) map

getNodeParentFromKey(nodeKey: string): string

Get the key of the parent of the node from the virtual (computed) map

getAllDescendants(nodeKey: string, allDescendants: Array<string>): void

Gets all the descendants of the node.

setNodeOrderToStart(nodeKey: string): void

Sets the nodes's order index (position) below its siblings

setNodeOrderToEnd(nodeKey: string): void

Sets the node's order index (position) above its siblings

setNodeAfter(nodeKey: string, target: string): void

Sets the the node's order index (position) to be right after the target

The node and target must share the same parent.

setNodeBefore(nodeKey: string, target: string): void

Sets the the node's order index (position) to be right before the target

The node and target must share the same parent.

sortChildrenByOrder(children: Array<string>, parentKey: string): Array<string>

Gets an array of node keys sorted by the node positions.