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 🙏

© 2024 – Pkg Stats / Ryan Hefner

vyjs

v2.0.5

Published

This project provides utilities for synchronizing Yjs documents with plain objects, applying diffs/deltas, and handling nested structures, arrays, and text types.

Downloads

92

Readme

vyjs - Vanilla Yjs Integration

Build Status

This project provides utilities for synchronizing Yjs documents with plain objects, applying diffs/deltas, and handling nested structures, arrays, and text types. It aims to simplify the integration of Yjs with React applications by offering a straightforward and vanilla approach.

Table of Contents

Introduction

vyjs (Vanilla Yjs) is a utility library designed to simplify the integration of Yjs with React and other JavaScript frameworks. It provides a minimalistic approach to synchronize Yjs documents with plain JavaScript objects, making it easier to build real-time collaborative applications without the overhead of complex abstractions.

Features

  • Vanilla Integration: Offers a straightforward way to use Yjs without additional abstractions.
  • React Compatibility: Simplifies the integration of Yjs with React applications.
  • Synchronization: Automatically synchronize Yjs documents with plain JavaScript objects.
  • Difference Application: Apply the difference between two JSON objects to Yjs types.
  • Nested Structures: Support for nested maps, arrays, and text types within Yjs documents.
  • Conflict Resolution: Handle concurrent changes with Yjs's built-in conflict resolution mechanisms.
  • Comprehensive Tests: A suite of tests demonstrating various synchronization scenarios.

Installation

Install vyjs via npm:

npm install vyjs

Usage

Synchronizing Yjs Documents with Plain Objects

Import the necessary modules:

import * as Y from 'yjs';
import { getYjsEventsHandler } from 'vyjs';

const ydoc = new Y.Doc();
const yMap = ydoc.getMap('rootMap');
let currentValue = {};

const callback = (updatedValue) => {
  currentValue = updatedValue;
  console.log('Updated Value:', currentValue);
};

const eventsHandler = getYjsEventsHandler(currentValue, callback);
yMap.observeDeep(eventsHandler);

// Now, any changes made to yMap will be reflected in currentValue via the callback:

ydoc.transact(() => {
  yMap.set('number', 42);
  yMap.set('text', new Y.Text('Hello, Yjs!'));
});

Integrating with React

vyjs makes it easier to integrate Yjs with React by keeping your component state in sync with Yjs documents.

import React, { useEffect, useState } from 'react';
import * as Y from 'yjs';
import { getYjsEventsHandler } from 'vyjs';

const ydoc = new Y.Doc();
const yMap = ydoc.getMap('rootMap');

function App() {
  const [state, setState] = useState({});

  useEffect(() => {
    let currentValue = {};

    const callback = (updatedValue) => {
      setState(updatedValue);
    };

    const eventsHandler = getYjsEventsHandler(currentValue, callback);

    yMap.observeDeep(eventsHandler);

    return () => {
      yMap.unobserveDeep(eventsHandler);
    };
  }, []);

  return (
    <div>
      <h1>Yjs and React Integration</h1>
      <pre>{JSON.stringify(state, null, 2)}</pre>
    </div>
  );
}

export default App;

With this setup, any changes to the Yjs document will automatically update the React component's state, ensuring seamless synchronization between the collaborative data and your UI.

Applying Differences Between JSON Objects to Yjs Types

Import the applyJsonDiffToYjs function:

import { applyJsonDiffToYjs } from 'vyjs';
import * as Y from 'yjs';

const ydoc = new Y.Doc();
const yMap = ydoc.getMap('map');

const oldValue = {
  number: 42,
  text: 'Hello, Yjs!',
};

const newValue = {
  number: 100,
  text: 'Hi',
  status: true,
};

// Initialize yMap with oldValue
Object.keys(oldValue).forEach((key) => {
  yMap.set(key, oldValue[key]);
});

// Apply the difference between oldValue and newValue to yMap
applyJsonDiffToYjs(oldValue, newValue, yMap);

console.log(yMap.get('number')); // Output: 100
console.log(yMap.get('status')); // Output: true
console.log(yMap.get('text').toString()); // Output: 'Hi'

Running Tests

npm test

API Reference

getYjsEventsHandler(currentValue, callback)

Returns an event handler function that synchronizes changes from a Yjs document to a plain JavaScript object.

  • Parameters:
    • currentValue (Object): The current value of the plain JavaScript object.
    • callback (Function): The function to call with the updated value.
  • Returns:
    • (Function): An event handler to be used with yMap.observeDeep().

Usage:

const eventsHandler = getYjsEventsHandler(currentValue, callback);
yMap.observeDeep(eventsHandler);

applyJsonDiffToYjs(oldValue, newValue, yValue, yValueParent, yValueKey)

Applies the difference between two JSON objects to a Yjs type.

  • Parameters:
    • oldValue (any): The original JSON value.
    • newValue (any): The new JSON value.
    • yValue (Y.Map | Y.Array | Y.Text): The Yjs type to apply the changes to.
    • yValueParent (Y.Map | Y.Array | undefined): The parent of the Yjs type.
    • yValueKey (string | number | undefined): The key or index in the parent where yValue is located.
  • Returns:
    • void

Usage:

applyJsonDiffToYjs(oldValue, newValue, yValue, yValueParent, yValueKey);

jsonToYType(object)

Converts a JSON object to a Yjs type.

  • Parameters:
    • object (any): The JSON object to convert.
  • Returns:
    • Y.Map | Y.Array | Y.Text | primitive value

Usage:

const yType = jsonToYType(jsonObject);

Examples

Nested Structures Synchronization

Synchronize nested maps and arrays between a Yjs document and a plain object.

ydoc.transact(() => {
  const nestedMap = new Y.Map();
  nestedMap.set('key1', 'value1');
  yMap.set('nested', nestedMap);
});

console.log(currentValue);
// Output:
// {
//   nested: {
//     key1: 'value1',
//   },
// }

// Update nested map
ydoc.transact(() => {
  const nestedMap = yMap.get('nested');
  nestedMap.set('key2', 'value2');
});

console.log(currentValue);
// Output:
// {
//   nested: {
//     key1: 'value1',
//     key2: 'value2',
//   },
// }

License

This project is licensed under the MIT License. See the LICENSE file for details.

Acknowledgments

  • Yjs: A powerful CRDT implementation for building collaborative applications.