Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

sprinkle-js

Package Overview
Dependencies
Maintainers
1
Versions
67
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sprinkle-js

A quick drop in reactive library to sprinkle reactivity in your web-app

  • 0.4.6
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
99
increased by280.77%
Maintainers
1
Weekly downloads
 
Created
Source

Logo

MIT License

npm bundle size

npm

npm

GitHub last commit

Sprinkle JS

Sprinkle JS is the open source alternative to...well nothing!

Joking aside, is a javascript library that let you sprinkle reactivity inside your vanilla imperative javascript. It uses a model very similar (yet far less powerful) than SolidJS to handle reactivity and it was heavily inspired by this post from Ryan Carniato the main developer behind it.

Before diving in the APIs and all the cool stuff it's useful to clarify what is Sprinkle JS philosophy and what Sprinkle JS is not.

Philosophy

Have you ever been fiddling around in Codepen or in a local html file and wondered "Man I wish I could have a bit of reactivity for this stupid app i'm messing with".

Well Sprinkle JS is exactly what you need!

The main philosophy behind is to build a supersmall library that requires no bundler that you can just drop in a script tag or import from a cdn and add a bit a reactivity to your app. We made a bunch of utility functions to bind your variables to your DOM in some way and that's all is needed. Open a new file, drop in Sprinkle JS, declare your variables, declare your bindings and than proceed to write your code without caring about updating the DOM...that's Sprinkle JS work!

What is not

  • Sprinkle JS is not the next big thing after React.
  • Sprinkle JS is not for your big project...i mean if you want to use it feel free to do so but it's not what's meant to be.
  • Sprinkle JS is not for perf aficionados: we as a community are trying to our best and maybe it will become the best version of itself but keep always keep in mind the main philosophy behind it.## Installation To install Sprinkle JS you can run
npm i sprinkle-js

This will install the npm package in your project and will let you import the various exported methods with

import SprinkleJS from "sprinkle-js";

Tip: it's better to actually import the naming exports to allow for tree shaking 🌳

import { createVariable } from "sprinkle-js";

Installing the library from npm will download a copy into your node_modules and will be shipped together with your application when you publish it. This will kind of negate the meaning of this library but you are free to use it like this if you prefer.

To use the library for what is meant to be go on codepen or in a local html file and paste this in the JS tab:

import { createVariable } from "https://cdn.skypack.com/sprinkle-js";

Sprinkle JS is available from all major cdn's

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sprinkle JS App</title>
    <!-- This will load the library in a SprinkleJS global variable -->
    <script src="https://unpkg.com/sprinkle-js/dist/sprinkle-js.iife.js"></script>
    <!-- You can reference that variable and destructure from it in
    your script tag or even in your js file-->
    <script>
        const { createVariable, createEffect } = SprinkleJS;
    </script>
</head>

<body>

</body>

</html>

If you append dist/sprinkle-js.iife.js to each of those links you can also embed it in a script tag.

On Codepen

The easiest way to get started with Sprinkle JS is just by going on Codepen by clicking this.

This will bring you to codepen.io with the Sprinkle JS template.

On Stackblitz

You can quickly initialize a Stackblitz project setup with typescript and Sprinkle JS by going to this template.

Tip: we try to keep this templates up to date but it's safer to always update the dependencies as soon as you fork it.

On Codesandbox

You can quickly initialize a Code Sandbox project setup with typescript and Sprinkle JS by going to this template.

Tip: we try to keep this templates up to date but it's safer to always update the dependencies as soon as you fork it.

Demo

You can see this library in use here.

Authors

Contributing

Any contribution is welcomed, you can either open a New Issue or read the list of the open ones to work on them.

A Contributing guide will be up ASAP.

//⚠ WIP

Documentation

You can check the docs here.

If you want to contribute to the docs website you can file an issue to this repository.

FAQ

Can i use Sprinkle JS in production?

Obviously you can...but i don't recommend it. The main focus of Sprinkle JS is not to give you a fully fledget, bleeding edge, blazingly fast framework. Is mainly to let you fiddle around in your fun little projects without the need to setup a bundler or importing a huge codebase just to get a bit of reactivity.

How can i create a component in Sprinkle JS?

You can't. You could, in theory write a function that returns an array of child nodes but components in the strict term are not part of the Sprinkle JS philosophy. We want to mantain a super small bundle size.

Why i can't create a variable that is not an Object?

Sprinkle uses javascript Proxyes to handle reactivity and unfortunately you can't create a Proxy from a primitive value.

Why i need to wrap everything in a function to use Sprinkle JS?

Sprinkle JS uses the same model of Vue or Solid to handle the reactivity. To keep track of the dependencies of a function it saves that function in a stack before calling it. This allows every variable accessed in that function to know that it's used in that function. This has some drawbacks. If you don't wrap everything inside a function the variable will be accessed before the effect can save himself into the stack. If you want to understand this better you can check this article from Ryan Carniato or watch this video from VueMastery on Vue reactivity.

Why my createEffect does not re-run? I've used a reactive variable inside it.

It could be a lot of different things but probably is because you are running asynchronous code inside of it. You can run asynchronous code inside a createEffect but for it to track your dependencies you have to make sure to use them before the async part. You can even just access it just by writing variablename.fieldname; and it will be correctly tracked.

Usage/Examples

setup

Given that Sprinkle JS uses the two core methods to do everything with this method you can plug your own reactivity system inside Sprinkle JS. Why should you do this? I don't know! For fun, or maybe because you already have @vue/reactivity in use in your application and you want to use it with Sprinkle JS methods.

To plug your own reactivity system into Sprinkle JS you need to provide a method to createVariable and one for createEffect. Optionally you can provide an override for createComputed. This will override the core functionalities and the reactivity system of Sprinkle JS and every other method will use your reactivity system instead.

Obviously there are constraints:

  • createEffect needs to automatically check its own dependencies
  • ideally you want to return an object or a Proxy from createVariable
  • if you don't return a Proxy from createVariable you'll probably need to provide also a createComputed override

@vue/reactivity provides a very similar set of core functionalities to Sprinkle JS so it's very easy to plug it into it.

import { effect, reactive } from "@vue/reactivity";
import { setup } from "sprinkle-js";

setup({
  createVariable: reactive,
  createEffect: effect,
});

And that's it...from this moment on all the methods of Sprinkle JS will use @vue/reactivity as their reactivity system.

Warning while pretty similar the reactivity system of @vue/reactivity it's a bit different so you might found some differences in behavior for some of your applications.

The setup function returns a function to reset the setup.

import { effect, reactive } from "@vue/reactivity";
import { createEffect, createVariable, setup } from "sprinkle-js";

const reset = setup({
  createVariable: reactive,
  createEffect: effect,
});

//this variable uses @vue/reactivity
const vueReactivityVar = createVariable({ whosCool: "you" });

createEffect(() => {
  console.log(vueReactivityVar.whosCool);
});

reset();

//this variable uses sprinkle-js
const sprinkleVar = createVariable({ whosCool: "you" });

createEffect(() => {
  console.log(sprinkleVar.whosCool);
});

N.B. once created inside a reactivity system the variable will continue to use that reactivity system even after the reset.

While returning an object or a Proxy from createVariable is preferable it's not required. This means that if you want to use signals from solid-js you can do something like this

import { createEffect as solidEffect, createSignal } from "solid-js";
import {
  bindTextContent,
  createEffect,
  createVariable,
  setup,
} from "sprinkle-js";

setup({
  createVariable: (...props) => {
    return createSignal(...props);
  },
  createEffect: (...props) => {
    solidEffect(...props);
  },
});

//note that the limit of passing an object to createVariable it's not present since we are using solid
//createSignal under the hood, also the returned value it's not a variable but an array with an
//accessor and a setter
const [state, setState] = createVariable(1);

createEffect(() => {
  //here we access the state like we would do in solid
  console.log(state());
});

//we need to use the same access method also inside the methods of Sprinkle JS
bindTextContent("#app", () => `The content of the state is ${state()}`);
createRef

This method is used to create a reactive variable for a primitive. It wraps the primitive in an object with a value property.

const ref = createRef(1);
console.log(ref.value); // 1

if you use this variable inside a createEffect or inside another method whenever you'll update the value the method will re-run.

You can also pass an equality function that will determine how to check for equality for this ref. By default it will use Object.is.

const ref = createRef(1, (before, after) => before > after);
console.log(ref.value); // 1

The above ref will not trigger an effect re-run if the previous value is greater than the new value.

Please note: if you are using typescript you can't pass something different than a primitive value to the ref and if you pass an equality function is recommended to also use the generic version of the fucntion createRef<number>(1, (before, after)=> before > after) otherwise Typescript will narrow the type to a constant. If you are using this in Javascript you are allowed to pass object to the ref (although is not recommended since you'll have to access it unnecessarly via the .value property), the object passed will be deeply reactive.

createVariable

This method is used to create a reactive variable for an object. It'll throw if you try to pass a primitive value to it.

const variable = createVariable({ whosCool: "you" });
console.log(variable.whosCool); // you

if you use this variable inside a createEffect or inside another method whenever you'll update the value the method will re-run.

You can also pass an object containing an equality function for every field of the object that will determine how to check for equality for that field. By default it will use Object.is.

const variable = createVariable({ whosCool: "you" }, {
  whosCool: (before, after) => before.length === after.length,
});
console.log(variable.whosCool); // you

The above variable will not trigger an effect re-run if the previous value has the same length as the new value.

createVariable works with nested property too. You can pass object inside objects and updating a values inside those object will trigger the rerun of the effects where it's been used. To pass an equality function relative to a nested object you should pass an object containing the properties of the object you want a particular equality function. If you pass a built in object tho (like Set, Map or HTMLElement) it will not become reactive. If you use a nested object you can pass an object with the same structure to the equality functions object to specify an equality function for every field. If you pass a function the equality function will not be applied to the nested object.

//here the name field will use the custom equality function
const variable = createVariable({ whosCool: { name: "you" } }, {
  whosCool: { name: (before, after) => before.length === after.length },
});

//here the equality function will be applied only to the whosCool object
const variable = createVariable({ whosCool: { name: "you" } }, {
  whosCool: (before, after) => before.length === after.length,
});
const variable = createVariable({ whosCool: { pronoun: "you" } }, {
  whosCool: { pronoun: (before, after) => before.length === after.length },
});
console.log(variable.whosCool.pronoun); // you

in the above example variable.whosCool.pronoun is still reactive.

createCssVariable

This method is used to create a reactive variable for an object and map every field to a css variable. It'll throw if you try to pass a primitive value to it. In typescript you can pass only string or numbers as values of the object but every value will be stringified before assigning it to the css variable so if you pass a complex object you'll get "[object Object]" instead.

//this will create two css variable at the root level --x and --y with the values of 0 and 0
//you can use those variable inside your css
const variable = createCssVariable({ x: 0, y: 0 });

//setting this will also set the --x css variable to 200
variable.x = 200;

if you use this variable inside a createEffect or inside another method whenever you'll update the value the method will re-run.

You can also pass an object containing an equality function for every field of the object that will determine how to check for equality for that field. By default it will use Object.is.

const variable = createCssVariable({ whosCool: "you" }, {
  whosCool: (before, after) => before.length === after.length,
});

The above variable will not trigger an effect re-run if the previous value has the same length as the new value.

A third argument of this method is a selector or an HTMLElement of the element you want to apply the css variables to. It default to :root. If the provided selector does not select anything it will apply the css variable to the :root

createStored

This method is used to create a reactive variable for an object also persisting it in localStorage or sessionStorage. It'll throw if you try to pass a primitive value to it. It will also automatically add a listener for the storage to update the variable whenever the storage changes. It will take a key and an initial value as input but will discard the initial value if the key is already present in the storage. It will also throw if the object in the storage is not Object-like

const variable = createStored("cool-stored", { whosCool: "you" });
console.log(variable.whosCool); // you
console.log(window.localStorage.getItem("cool-stored")); // '{ "whosCool": "you" }'

if you use this variable inside a createEffect or inside another method whenever you'll update the value the method will re-run.

You can also pass an object containing an equality function for every field of the object that will determine how to check for equality for that field. By default it will use Object.is.

const variable = createStored("cool-stored", { whosCool: "you" }, {
  whosCool: (before, after) => before.length === after.length,
});
console.log(variable.whosCool); // you

The above variable will not trigger an effect re-run if the previous value has the same length as the new value.

Differently from createVariable a stored object is not deeply reactive.

createComputed

This method is used to create a reactive computed variable. You need to pass a function that will return a value. The return value of the function will be inside of the .value field of the returned computed. If you use some other variable to compute the this value it will always be in sync.

const variable = createVariable({ whosCool: "you" });
const computed = createComputed(() => `${variable.whosCool} is cool!`);
console.log(computed.value); // you is cool!
variable.whosCool = "whoever uses SprinkleJS";
console.log(computed.value); // whoever uses SprinkleJS is cool!

if you use this variable inside a createEffect or inside another method it will be rerunned whenever this computed changes. You can't set the value of a computed value and trying would still result in the same value being inside that computed.

You can also pass an equality function that will determine how to check for equality for this computed. By default it will use Object.is.

const variable = createVariable({ whosCool: "you" });
const computed = createComputed(
  () => `${variable.whosCool} is cool!`,
  (before, after) => before.length === after.length,
);
console.log(computed.value); // you is cool!
variable.whosCool = "whoever uses SprinkleJS";
console.log(computed.value); // whoever uses SprinkleJS is cool!

The above ref will not trigger an effect re-run if the previous value has the same length as the new value.

Another simple way to create a computed value if by defining a function that return a value using a reactive variable like this

const variable = createVariable({ whosCool: "you" });
const computed = () => `${variable.whosCool} is cool!`;
console.log(computed()); // you is cool!
variable.whosCool = "whoever uses SprinkleJS";
console.log(computed()); // whoever uses SprinkleJS is cool!

As you can see in the example, this require you to call the function to access the value (instead of accessing it by .value)

However this second method will rerun the effect it's used in even if it has the same value as before.

createEffect

This method is used to create an effect that will keep track of it's dependencies and re-run every time they changed

const variable = createVariable({ whosCool: "you" });
const ref = createRef(1);

createEffect(() => {
  console.log(variable.whosCool, ref.value);
});
//will log (you, 1) the first time

ref.value++;
//the effect run again logging (you, 2)

variable.whosCool = "whoever uses Sprinkle JS";
//the effect run again logging (whoever uses Sprinkle JS, 2)

You can also return a function that will be run before the new function to clean up the previous effect.

const variable = createVariable({ whosCool: "you" });
const ref = createRef(1);

createEffect(() => {
  console.log(variable.whosCool, ref.value);

  return () => {
    console.log("cleaning up");
  };
});
//will log (you, 1) the first time

ref.value++;
//the effect run again logging first "cleaning up" and then (you, 2)

variable.whosCool = "whoever uses Sprinkle JS";
//the effect run again logging first "cleaning up" and then (whoever uses Sprinkle JS, 2)
untrack

This function can be used inside a createEffect to untrack a dependency. This way you can use a reactive variable inside a create effect without triggering the re-run when that variable changes. It takes a function as input and it return anything returned from that function.

const variable = createVariable({ whosCool: "you" });
const ref = createRef(1);

createEffect(() => {
  const refValue = untrack(() => ref.value);
  console.log(variable.whosCool, refValue);
});
//will log (you, 1) the first time

ref.value++;
//the effect will not run again because ref.value has been accessed inside the untrack

variable.whosCool = "whoever uses Sprinkle JS";
//the effect run again logging  (whoever uses Sprinkle JS, 2)
batch

This function can be used to avoid running effects multiple times when changing multiple variables. It's as simple as calling batch and passing a function that will change some variables.

const variable = createVariable({ name: "John", lastName: "Doe" });

createEffect(() => {
  console.log(`The full name is ${variable.name} ${variable.lastName}`);
});
//the effect will still run the first time logging "The full name is John Doe"

batch(() => {
  variable.name = "Albert";
  variable.lastName = "Einstein";
});
//changin both variables without the batch would've run the effect twice
//in this case the effect will run a single time loggin "The full name is Albert Einstein"
bindTextContent

This function is used to bind a string value to the text content of an element. It takes a dom element or a selector as the first argument and a function returning the value to bind to the text content as the second argument.

const variable = createVariable({ whosCool: "you" });
const ref = createRef(1);

bindTextContent("#div-to-bind", () => `${ref.value} ${variable.whosCool}`);
//the text content of the div with the id div-to-bind will be "1 you"

ref.value++;
//the text content of the div with the id div-to-bind will be "2 you"

variable.whosCool = "whoever uses Sprinkle JS";
//the text content of the div with the id div-to-bind will be "2 whoever uses Sprinkle JS"

The callback you pass in also takes the element as the first argument, in Typescript you can pass a generic type specifying what kind of element you are expecting

const variable = createVariable({ whosCool: "you" });
const ref = createRef(1);

bindTextContent<HTMLDivElement>(
  "#div-to-bind",
  (element: HTMLDivElement) =>
    `${element?.textContent} ${ref.value} ${variable.whosCool}`,
);
//the text content of the div with the id div-to-bind will be "1 you"

ref.value++;
//the text content of the div with the id div-to-bind will be "1 you 2 you"

variable.whosCool = "whoever uses Sprinkle JS";
//the text content of the div with the id div-to-bind will be "1 you 2 you 2 whoever uses Sprinkle JS"

If you need to have access to the selected element (to add event listeners for example), the element is returned from the function.

//this will bind the variables to the textContent and you'll have access to the element itself inside the variable divToBind
const divToBind = bindTextContent<HTMLDivElement>(
  "#div-to-bind",
  (element: HTMLDivElement) =>
    `${element?.textContent} ${ref.value} ${variable.whosCool}`,
);
bindInnerHTML

Warning Sprinkle JS does not sanitize the content of the innerHTML. If you use this function with user input make sure to sanitize it first to avoid expose yourself to XSS attacks.

This function is used to bind a string value to the innerHTML of an element. It takes a dom element or a selector as the first argument and a function returning the value to bind to the innerHTML as the second argument.

const variable = createVariable({ whosCool: "you" });
const ref = createRef(1);

bindInnerHTML(
  "#div-to-bind",
  () => `<span>${ref.value} <strong>${variable.whosCool}</strong></span>`,
);
//the innerhtml of the div with the id div-to-bind will be "<span>1 <strong>you</strong></span>"

ref.value++;
//the innerhtml of the div with the id div-to-bind will be "<span>2 <strong>you</strong></span>"

variable.whosCool = "whoever uses Sprinkle JS";
//the innerhtml of the div with the id div-to-bind will be "<span>2 <strong>whoever uses Sprinkle JS</strong></span>"

The callback you pass in also takes the element as the first argument, in Typescript you can pass a generic type specifying what kind of element you are expecting

const variable = createVariable({ whosCool: "you" });
const ref = createRef(1);

bindInnerHTML<HTMLDivElement>(
  "#div-to-bind",
  (element: HTMLDivElement) =>
    `<span>${element?.textContent} ${ref.value} <strong>${variable.whosCool}</strong></span>`,
);
//the innerhtml of the div with the id div-to-bind will be "<span>1 <strong>you</strong></span>"

ref.value++;
//the innerhtml of the div with the id div-to-bind will be "<span>1 you 2 <strong>you</strong></span>"

variable.whosCool = "whoever uses Sprinkle JS";
//the innerhtml of the div with the id div-to-bind will be "<span>1 you 2 you 2 <strong>whoever uses Sprinkle JS</strong></span>"

If you need to have access to the selected element (to add event listeners for example), the element is returned from the function.

//this will bind the variables to the textContent and you'll have access to the element itself inside the variable divToBind
const divToBind = bindInnerHTML<HTMLDivElement>(
  "#div-to-bind",
  (element: HTMLDivElement) =>
    `${element?.textContent} ${ref.value} ${variable.whosCool}`,
);
bindInputValue

This function is used to bind a string value to the value of an input element. It takes an input dom element or a selector as the first argument and a function returning the value to bind to the input value as the second argument.

The following code will bind the input value to the variable.whosCool field. Note that is a one-way binding so make sure to also add an event listener on the input to complete the flow. We are saving the return value of the function into bindInputValue to later add the event listener to it.

const variable = createVariable({ whosCool: "you" });

const inputToBind = bindInputValue("#input-to-bind", () => variable.whosCool);

inputToBind.addEventListener("input", (e) => {
  variable.whosCool = e.target.value;
});

The callback you pass in also takes the element as the first argument.

const variable = createVariable({ whosCool: "you" });

const inputToBind = bindInputValue(
  "#input-to-bind",
  (element) => element.innerText + " " + variable.whosCool,
);

inputToBind.addEventListener("input", (e) => {
  variable.whosCool = e.target.value;
});
bindDom

This function is used to bind an object that describe some DOM properties to the actual DOM properties. It takes a dom element or a selector as the first argument and a function returning the object as the second argument.

The following code will bind the ariaLabel value to the variable.whosCool field and the checked value for the checkbox.

const variable = createVariable({ whosCool: "you" });

bindDom("#checkbox", (element) => ({
  ariaLabel: variable.whosCool,
  checked: variable.whosCool === "you",
}));
bindClass

This function is used to bind a class to the actual element. It takes a dom element or a selector as the first argument, the class that you want to apply and a function returning a boolean as the third argument.

const variable = createVariable({ count: 0 });

bindClass("#div-to-bind", "dark", (element) => variable.count % 2 === 0);
//the div will have the dark class set by default

//this will remove the class;
variable.count++;

//this will add the class again;
variable.count++;
bindClasses

This function is used to bind multiple classes to the actual element. It takes a dom element or a selector as the first argument, and an object containing the classes that you want to apply as the keys and a boolean as the value. Each class will be applied only if the corrispondent value is true.

const variable = createVariable({ count: 1 });

bindClasses("#to-bind", () => ({
  one: variable.count === 1,
  two: variable.count === 2,
  three: variable.count === 3,
  lessThanFive: variable.count < 5,
}));
//the div will have the classes one and lessThanFive

//the div will have the classes two and lessThanFive
variable.count++;

//the div will have the classes three and lessThanFive
variable.count++;

//the div will have the class lessThanFive
variable.count++;

//the div will have no classes
variable.count++;
bindStyle

This function is used to bind an object that describe the style of an element to the actual element style. It takes a dom element or a selector as the first argument and a function returning the object as the second argument.

The following code will bind color property and the backgroundColor property value to the variable.color and variable.bg field.

const variable = createVariable({ color: "black", bg: "#BADA55" });

bindStyle("#div-to-bind", (element) => ({
  color: variable.color,
  backgroundColor: variable.bg,
}));

variable.bg = "#C0FFEE"; //the div will now have #C0FFEE as backgroundColor
variable.color = "white"; //the div will now have white as the color
bindChildren

This function is used to bind html as the children of an element. How is this different than bindInnerHTML? Each item can have a key attribute and if the key attribute does not change the element will not change either (it will have the same reference in the dom). It takes a dom element or a selector as the first argument, a function returning a document fragment or a string or an array of document fragments of an array of strings as the second argument and an option function to run after the diffing as the third parameter.

The third argument can be useful to bind something to the newly created element. It takes the root element and a Map object as parameter where the keys are all the keys you've specified in the template and the values are the element associated with that key that is on the DOM. Every element has an isNew flag that specifies if it's a newly added element or an old one

Given that sometimes is difficult to build a document fragment from scratch Sprinkle JS an html tagged template to transform your string into an actual document fragment. Inside this tagged template literal is possible to include events with the syntax on:eventname and there's a special event on:bind to run code whenever the element will be binded to the DOM by sprinkle JS. This event will get the actual element as the parameter and it's possible to use this to call other Sprinkle JS methods on that specific element. For example:

const variable = createVariable({inputVal: ""});

bindChildren("#div-to-bind", ()=> html`
    <input
        on:bind=${(inputElement)=>{
            bindInputValue(inputElement, ()=> variable.inputVal)
        }}
        on:input=${(e)=>{
            variable.inputVal= e.target.value;
        }} />
`);

will bound to the div #div-to-bind an input as children and will bind the inputValue of it variable.inputVal.

Tip: this is a better way than the afterRun function that bindChildren takes as a third argoument to bind something to an element.

Every array inside the tagged template literal will be treated as separate elements. So for example

html`${[1,2,3,4].map(num => html`
<button>${num}</button>
`)}`

will return a fragment with 4 buttons.

As you've seen from this previous example one small caveat of this function is that you have to repeat the tag at each new "level" (you can skip the first one since everything you return will still get passed through the html function automatically but you have to include it inside the map function) but this allow for enaugh composability that you can actually start to create some sort of components.

A component it's simply a function that return the return value of an html tagged template literal. The above example could be rewritten like so

const MagicButton = ({num})=>{
  return html`<button>${num}</button>`
}

html`${[1,2,3,4].map(num => MagicButton({num}))}`

Those are all small examples so here's a fully featured one

const variable = createVariable({
  listOfCoolThings: [
    "you",
    "sprinkle-js",
    "javascript",
  ],
});

bindChildren(
  "#ul-to-bind",
  (element) => variable.listOfCoolThings.map((coolThing) => html`
      <li key="${coolThing}">
        <button 
          key="${coolThing}-button"
          on:click=${()=>{
            console.log(`You've pressed the ${coolThing} button`);
          }}
          >Log ${coolThing}</button>
      </li>`
    ),
  (element, elements) => {
    const youElement = elements.get("you");
    //yeah i know this is a silly example
    bindClasses(youElement, ()=>({
      "classForYou": true,
    });
  },
);
variable.listOfCoolThings = [...variable.listOfCoolThings, "npm"];
//this will add a new li element to the ul

A small caveat is that given that every nested element get's diffed you should add a key to every element that you want to preserve the reference to.

Warning bindChildren changed api's over time so make sure you are on the latest version o refer to previous versions of this readme for the old documentation.

Running Tests

To run tests, run the following command

npm run test

Keywords

FAQs

Package last updated on 27 Oct 2022

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc