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

@schwingbat/component

v0.0.2

Published

My personal, lightweight component-based app organization method.

Downloads

5

Readme

Component

WARNING: Component is extremely early in development and may not work in real life exactly as this document indicates. This is currently more of a plan for what will be than a description of what is. I don't recommend using Component for anything serious just yet, and you will more than likely have to go read the source code to figure out how to use it. That being said, if you choose to use it anyway, have fun! :) If you have ideas for how to improve it, open an issue. Thanks!

Component is my take on a lightweight component framework. It requires a bit more manual setup to make data reactive, as there is no virtual DOM and the updaters model is a little bit different than most frameworks. Basically, instead of the framework automatically resolving the changes that need to be made, you define a function for each property in your component's state object where you write the DOM manipulation code yourself. The framework ensures that the function runs only when the data is different than the last time it ran, keeping DOM activity to a minimum.

Unlike React, the render function here runs only once on the component's instantiation. Future state changes and resulting manipulations to the DOM are done by the handlers you write in events and updaters. This model allows for much less behind-the-scenes processing in order to update things. Where React is like a sledgehammer, Component is like a scalpel.

I make no promises that this way of doing things will work for anyone else, but if you like it, feel free to adopt it!

Components

Components are basically a capsule for DOM structure and behaviors relating to a particular part of your app. Here's an example of one:

const myComponent = new Component({
    // Supply any selector as 'anchor' and your component
    // will automatically append itself once initialized.
    anchor: "#app",
    state: {
        // Optional: initial state values
        clicks: 0
    },
    render(el, state) {
        return el("div", null, [
            el("h1", null, "Click Counter!"),
            el("p", null, "Click the button to increment the counter."),
            el("p", { id: "click-counter" }, `${state.clicks} clicks`),
            el("button", { id: "the-button" }, "Click me!")
        ]);

        /*
            DOM-wise, this returns:

            <div>
                <h1>Click Counter!</h1>
                <p>Click the button to increment the counter.</p>
                <p>0 Clicks</p>
                <button id="the-button">Click me!</button>
            </div>

            The 'el' function takes three parameters:
                - The tag name (div, li, span, canvas, etc.) Any valid HTML tag
                  can be used.
                - A properties object. These should be named exactly the same
                  way as their HTML counterparts, with the exception of "class",
                  which can be used either in quotes or using the className
                  property as in React. Both map to the element's 'class' property.
                - Children, which can be an array of multiple children or a single
                  child. Any strings will be treated as text nodes.

            -> el(tag, props, children)
        */
    },
    postrender() {
        // postrender() runs immediately after running 'render'
        // which makes this an excellent place to do anything you need to do
        // which requires accessing the component's DOM nodes.
        console.log("myComponent has rendered!");
    },
    events: {
        "click #the-button": function(e, el) {
            // Update the state of myComponent by incrementing 'clicks'
            // when an element with the ID of "#the-button" is clicked.
            this.update({ clicks: this.state.clicks + 1 });
        }
    },
    updaters: {
        clicks: function(value) {
            // Whenever the value of 'clicks' changes, this function runs.
            // If 'clicks' is set to the same value, this function doesn't run.

            // Any elements with an ID are stored in this.nodes
            // by their ID - converted to camelCase:
            // #click-counter ends up as this.nodes.clickCounter
            this.nodes.clickCounter.textContent = `${value} clicks`;
        }
    }
});

Using Components Recursively

This is something that some frameworks do well, others do poorly and a few don't really allow at all. With Component, you can use the clone function of any component to create a carbon copy, even from inside its own render function. Similar to factory components, the clone function takes an object with which to update its state before rendering.

This could be useful for something like a file tree view, where items in the tree can either contain children (if they are a folder), or no children (if they are a file). If we want to use one component for all items in the tree view, we could do something like this:

const treeItem = new Component({
    ...
    render(el, state) {
        const children = [
            el("span", { "class": "tree-item__title" }, state.name)
        ];

        if (state.children) {
            // Add a folder icon to the beginning of 'children'
            children.unshift( el("i", { "class": "icon folder-icon" }) );

            // Add a copy of this component for each child.
            children.push(
                el("ul", { "class": "tree-item__children" }, state.children.map(c => this.clone(c)));
            )
        }

        return el("li", { "class": "tree-item" }, children);
    },
    ...
})

In addition to using this.clone() inside the component, you can also clone it from outside. If you want to make infinitely many copies, but not necessarily recursively (say, a list of components), you can create a single component as your archetype, then clone it as many times as you want with custom state objects.