Skip to content

Repository files navigation

fusion

Version BadgeLicenseBuild Status

Reactive CSS-in-JS

Install

Download the CJS, ESM, UMD versions or install via NPM:

npm install @ryanmorr/fusion

Usage

Fusion is a tiny CSS-in-JS library that combines declarative CSS building with reactive stores to create data to CSS variable bindings:

import{css,store}from'@ryanmorr/fusion';constcolor=store('red');conststyle=css` .foo {color:${color} }`;document.head.appendChild(style);color.set('blue');

API

store(value?)

Create a reactive store that encapsulates a value and can notify subscribers when the value changes:

import{store}from'@ryanmorr/fusion';// Create a store with an initial valueconstcount=store(0);// Get the store valuecount.value();//=> 0// Set the store valuecount.set(1);// Set the store value with a callback functioncount.update((val)=>val+1);// Subscribe a callback function to be invoked when the value changes,// it returns a function to unsubscribe from future updatesconstunsubscribe=count.subscribe((nextVal,prevVal)=>{// Do something});

derived(...stores, callback)

Create a reactive store that is based on the value of one or more other stores:

import{derived,store}from'@ryanmorr/fusion';constfirstName=store('John');constlastName=store('Doe');constfullName=derived(firstName,lastName,(first,last)=>`${first}${last}`);fullName.value();//=> "John Doe"firstName.set('Jane');fullName.value();//=> "Jane Doe"// Subscribe to be notified of changesconstunsubscribe=fullName.subscribe((nextVal,prevVal)=>{// Do something});

If the callback function defines an extra parameter in its signature, the derived store is treated as asynchronous. The callback function is provided a setter for the store's value and no longer relies on the return value:

import{derived,store}from'@ryanmorr/fusion';constquery=store();// Perform an ajax request when the query changes// and notify subscribers with the resultsconstresults=derived(query,(string,set)=>{fetch(`path/to/server/${encodeURIComponent(string)}`).then(set);});

css(strings, ...values?)

Create CSS stylesheets declaratively via tagged template literals with support for nested rules:

import{css}from'@ryanmorr/fusion';// Create a <style> elementconststylesheet=css` .foo {color: red;&:hover {color: blue; }@media (max-width:750px) {& {color: purple; } } .bar {color: green; } } .baz {color: yellow; }`;// Append styles to documentdocument.head.appendChild(stylesheet);

Bindings

When a reactive store is interpolated into a css stylesheet, it is replaced with a unique CSS variable bound to that store and will be automatically updated when the internal store value changes:

import{css,store}from'@ryanmorr/fusion';constwidth=store('10px');document.head.appendChild(css` .foo {width:${width}; }`);constelement=document.querySelector('.foo');getComputedStyle(element).getPropertyValue('width');//=> "10px"width.set('50px');getComputedStyle(element).getPropertyValue('width');//=> "50px"

Similarly to stores, promises can also be interpolated into a css stylesheet, setting the value of the binding CSS variable when the promise resolves:

import{html}from'@ryanmorr/fusion';constheight=Promise.resolve('100px');conststyle=css` .foo {height:${height}; }`;

If a store or promise returns a value of null or undefined, the binding CSS variable will be unset.


style(strings, ...values?)

Create styles for an element and its descendants declaratively via tagged template literals and return a unique class name. Just like css, it supports nested rules and interpolating stores and promises:

import{style,store}from'@ryanmorr/fusion';constcolor=store('red');// Create a style declaration and return a class nameconstclassName=style` width: 100px; &:hover { color: white; } .foo { color: ${color}; } @media only screen and (max-width: 30em) { & { width: 200px; } }`;// Add the unique class to an elementelement.classList.add(className);

keyframes(strings, ...values?)

Create a keyframes animation via tagged template literals and return a unique animation name that can be easily applied to a css stylesheet or style class name declaration:

import{keyframes,css}from'@ryanmorr/fusion';// Create a keyframes animationconstslideIn=keyframes`from {transform:translateX(0%); }to {transform:translateX(100%); }`;// Add the animation to a `css` stylesheetconststylesheet=css` .foo {animation:${slideIn}1s ease-in; }`;

fallback(...values)

Add one or more fallback values for a CSS variable, supporting stores, promises, and CSS variable names. Moving left to right, if the value provided is null or undefined then precedence moves to the next fallback value:

import{fallback,store,css}from'@ryanmorr/fusion';constcolor=store();// Because the store is unset, it defaults to the fallback value of blueconststylesheet=css` .foo {color:${fallback(color,'blue')}; }`;// When the reactive store is set, it takes precedencecolor.set('red');

media(mediaQuery)

Create a reactive store for a media query that can also be interpolated into a css stylesheet or style declaration:

import{media,css}from'@ryanmorr/fusion';// Create the media query storeconstsmallScreen=media('(max-width: 750px)');// Returns true if the media query currently matchesconstisSmallScreen=smallScreen.value();//=> true/false// Interpolate the media query into a stylesheetconststyle=css`${smallScreen} { .foo {color: green; } }`;// Subscribers are called when the status of the media query changessmallScreen.subscribe((isSmallScreen)=>{// Do something});

query(selector)

Create a reactive store for a live array of DOM elements that match a CSS selector string. The store is automatically updated anytime one or more elements matching the CSS selector are added to or removed from the DOM. It can also be interpolated into a css stylesheet or style declaration:

import{query,css}from'@ryanmorr/fusion';// Create the element storeconstfooElements=query('.foo');// Returns an array of elements that match the CSS selectorconstelements=fooElements.value();// Interpolate the CSS selector into a stylesheetconststyle=css`${fooElements} {color: yellow; }`;// Subscribers are called when elements matching the// CSS selector are added to or removed from the DOMfooElements.subscribe((nextElements,prevElements)=>{// Do something});

DOM

For a DOM-based solution, refer to reflex, a similar library that brings reactivity to elements and attributes. It is also 100% compatible with fusion.

License

This project is dedicated to the public domain as described by the Unlicense.

About

Reactive CSS-in-JS

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages