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

@nichoth/jazz-signals

v0.0.6

Published

An example of Jazz + preact signals

Downloads

11

Readme

jazz signals

A library to help use Jazz with preact signals.

install

npm i -S @nichoth/jazz-signals

develop

Start a local vite server

npm start

API

localAuth

Import a function localAuth that helps with authentication, and has a property createState that returns observable state. This will create and return a signal of a localNode, the object used for persistence/telepathicState.

import { localAuth } from '@nichoth/jazz-signals'

localAuth.createState

Create a state object that includes signals.

export interface LocalAuthState {
    authStatus:Signal<AuthStatus>;
    localNode:Signal<LocalNode|null>;
    logoutCount:Signal<number>;
    syncAddress?:string;
}

localAuth.createState = function ():LocalAuthState

The returned state object should be passed into the localAuth function. See an example in the example app.

The signals returned are plain signals; you would want to wrap them in a call to useMemo if you use them in a view component.

function localAuth (
    appName:string,
    appHostname:string|undefined,
    opts:LocalAuthState
):() => void

This will create a new BrowserLocalAuth, and mutate the signals passed in as opts:LocalAuthState. The return value is a function that will unsubscribe from BrowserLocalAuth. See the example for a demonstration of how the unsubscribe function can be used.

To check if you are logged in, look for the authStatus.value.logout property. If .logout exists, then you are logged in. Call authStatus.value.signUp or authStatus.value.signIn to handle creating an account and logging in, respectively. See an example of handling auth.

telepathicSignal

function telepathicSignal<T extends CoValueImpl> ({
    id,
    localNode
}:{
    id?:CoID<T>,
    localNode:Signal<LocalNode|null>
}):Signal<[ T|null, (()=>void)|null ]> {

example

localAuth

An example of an application that consumes this package is in the example directory.

Create a localNode by mutating the signals that are passed in. Signals are created by localNode.createState.

You should create a state object first with localAuth.createState, then pass the state to localAuth.

import { localAuth } from '@nichoth/jazz-signals'
import { useEffect, useMemo } from 'preact/hooks'

function MyComponent ({ appHostName, syncAddress, appName }) {
    const state = useMemo(() => localAuth.createState(), [])
    const { localNode } = state  // <-- a signal for our localNode

    /**
     * Handle auth, create a node
     */
    useEffect(() => {
        let unlisten:()=>void = () => null

        localAuth(appName, appHostName, { ...state }).then(_unlisten => {
            unlisten = _unlisten
        })

        return unlisten
    }, [appName, appHostName, syncAddress, logoutCount.value])
}

telepathicSignal

Create a new signal that is subscribed to any changes from the cojson object referenced by the given id.

import { telepathicSignal } from '@nichoth/jazz-signals'

const mySignal = telepathicSignal({
    id: 'co_zPLDBXZD5UuZtYGzpqAvgAAHhs4',
    localNode
})
import { telepathicSignal } from '@nichoth/jazz-signals'
import { useMemo } from 'preact/hooks'

function Component () {
    const projectSignal = useMemo(() => {
        return telepathicSignal({
            // get the `id` from the URL or something
            id: 'co_zPLDBXZD5UuZtYGzpqAvgAAHhs4',
            localNode  // <-- here we consume the localNode we created earlier
        })
    }, [params.id, localNode.value])

    const [project] = projectSignal.value

    // get tasks (the list of things to do)
    // this is where we subscribe to task changes
    const tasksSignal = useMemo(() => {
        if (!project) return signal([])
        // we depend on the 'tasks' key existing.
        const tasksId = project.get('tasks')

        return telepathicSignal({ id: tasksId, localNode })
    }, [project, localNode.value])

    const [tasks] = tasksSignal.value

    return (<div>
        <h2>{project.get('title')}</h2>

        <ul className="todo-list">
            {tasks?.map((taskId: CoID<Task>) => {
                // subscribe to each TODO list item
                const [task] = useMemo(
                    () => telepathicSignal<Task>({ id: taskId, localNode }),
                    [taskId, localNode.value]
                ).value

                // The view will re-render when the task updates.
                // This is magically in sync with multiple devices.
                // You can create an invitation for a second device, and changes
                // will automatically be visible in both places.
                return (<li key={taskId}>
                    {task?.get('done') ?
                        (<s>{task.get('text')}</s>) :
                        (<span>{task.get('text')}</span>)
                    }
                </li>)
            })}
        </ul>
    </div>)
}