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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lynx-json/jsua-style

v0.3.15

Published

A package for styling JSUA views

Readme

JSUA Style

Querying

You can query an element or an array of elements:


var element = document.createElement("div");
element.id = "one";

query(element).each(el => console.log(`Selected "${el.id}"`));

// => Selected "one"

var elementArray = [element];
query(elementArray).each(el => console.log(`Selected "${el.id}"`));

// => Selected "one"

You can convert a selection to an array:


var element = document.createElement("div");
element.id = "one";

var a = query(element).toArray();

console.log(`a[0] "${a[0].id}"`);
// => Selected "one"

You can select from the query using CSS selectors or predicate selectors:


var element = document.createElement("div");
element.id = "one";

query(element).select("#one").each(el => console.log(`Selected "${el.id}"`));

// => Selected "one"

query(element).select(el => el.id === "one").each(el => console.log(`Selected "${el.id}"`));

// => Selected "one"

You can filter the current selection using CSS selectors or predicate selectors:


var element = document.createElement("div");
element.id = "one";

query(element).filter("#one").each(el => console.log(`Selected "${el.id}"`));

// => Selected "one"

query(element).filter(el => el.id === "one").each(el => console.log(`Selected "${el.id}"`));

// => Selected "one"

In most cases, rather than chaining a filter function to a query, it makes sense to do a simple filter operation (or many consecutive filter operations) while maintaining the original context. This can be done with the standalone filter function.


var parent = document.createElement("div");
parent.id = "parent";
parent.innerHTML = `
<div id="one"></div>
<div id="two"></div>
<div id="three"></div>
`;

query(parent).map(mappers.children()).each([
  filter("#one", el => console.log(`Selected "${el.id}"`)),
  filter("#two", el => console.log(`Selected "${el.id}"`)),
  filter("#three", el => console.log(`Selected "${el.id}"`))
]);

// => Selected "one"
// => Selected "two"
// => Selected "three"

query(parent.firstElementChild).map(el => el.parent).each(el => console.log(`Selected "${el.id}"`));

// => Selected "parent"

Selectors

In addition to standard CSS selectors for select or filter operations, jsua-style includes the following predicate selectors.

firstChild

Select all elements that are the first child matching the specified selector.

var parent = document.createElement("div");

parent.innerHTML = `
<pre id="one"></pre>
<div id="two"></div>
<div id="three">
  <div id="four"></div>
</div>
`;

query(parent).select(firstChild("div")).each(el => console.log(`Selected "${el.id}"`));

// => Selected "two"
// => Selected "four"

lastChild

Select all elements that are the last child matching the specified selector.

var parent = document.createElement("div");

parent.innerHTML = `
<pre id="one"></pre>
<div id="two"></div>
<div id="three">
  <div id="four"></div>
</div>
<pre id="five"></pre>
`;

query(parent).select(lastChild("div")).each(el => console.log(`Selected "${el.id}"`));

// => Selected "three"
// => Selected "four"

nthChild

Select all child elements at a specified index after filtering by the specified selector.

var parent = document.createElement("div");

parent.innerHTML = `
<pre id="one"></pre>
<div id="two"></div>
<div id="three">
  <div id="four"></div>
</div>
<pre id="five"></pre>
`;

query(parent).select(nthChild(0, "div")).each(el => console.log(`Selected "${el.id}"`));

// => Selected "two"
// => Selected "four"

Note that firstChild, lastChild, and nthChild are similar to, but more flexible than, CSS selectors :nth-of-type, :first-of-type, and :last-of-type.

first

Select only the first element in a selection set.

var parent = document.createElement("div");

parent.innerHTML = `
<pre id="one"></pre>
<div id="two"></div>
<div id="three">
  <div id="four"></div>
</div>
<pre id="five"></pre>
`;

query(parent).select(first("pre")).each(el => console.log(`Selected "${el.id}"`));

// => Selected "one"

has

Select only elements that map to a set of related elements.

var parent = document.createElement("div");
parent.id = "parent";

parent.innerHTML = `
<pre id="one"></pre>
<div id="two">
  <pre></pre>
</div>
<div id="three">
  <div></div>
  <div></div>
</div>
<pre id="four"></pre>
`;

query(parent).select(has(mappers.children("div"))).each(el => console.log(`Selected "${el.id}"`));

// => Selected "parent"
// => Selected "three"

hasOne

Select only elements that map to a single related element.

var parent = document.createElement("div");
parent.id = "parent";

parent.innerHTML = `
<pre id="one"></pre>
<div id="two">
  <pre></pre>
</div>
<div id="three">
  <div></div>
</div>
<pre id="four"></pre>
`;

query(parent).select(hasOne(mappers.children("div"))).each(el => console.log(`Selected "${el.id}"`));

// => Selected "three"

Styling

You can apply style to each item in a selection:


var element = document.createElement("div");

query(element).each(el => el.style.backgroundColor = "red");

Mapping

You can map to one or more related elements:


var parent = document.createElement("div");
parent.id = "parent";
parent.innerHTML = `
<div id="one"></div>
<div id="two"></div>
<div id="three"></div>
`;

query(parent).map(el => el.children).each(el => console.log(`Selected "${el.id}"`));

// => Selected "one"
// => Selected "two"
// => Selected "three"

query(parent.firstElementChild).map(el => el.parent).each(el => console.log(`Selected "${el.id}"`));

// => Selected "parent"

In most cases, rather than chaining a map function to a query, it makes sense to do a simple map operation (or many consecutive map operations) while maintaining the original context. This can be done with the standalone map function.


var parent = document.createElement("div");
parent.id = "parent";
parent.innerHTML = `
<div id="one"></div>
<div id="two"></div>
<div id="three"></div>
`;

query(parent).each([
  map("#one", el => console.log(`Selected "${el.id}"`)),
  map("#two", el => console.log(`Selected "${el.id}"`)),
  map("#three", el => console.log(`Selected "${el.id}"`))
]);

// => Selected "one"
// => Selected "two"
// => Selected "three"

query(parent.firstElementChild).map(el => el.parent).each(el => console.log(`Selected "${el.id}"`));

// => Selected "parent"

Mappers

The map function will take any element or iterable of elements. The jsua-style module provides the following commonly used functions.

  • ancestors: All ancestors of the specified element.

All mappers are used as follows:

query(element).map(mappers.ancestors());

first, last, and nth

TODO: Document

children

var parent = document.createElement("div");
parent.id = "parent";
parent.innerHTML = `
<div id="one"></div>
<div id="two"></div>
<div id="three"></div>
`;

query(parent).map(mappers.children()).each(el => console.log(`Selected "${el.id}"`));

// => Selected "one"
// => Selected "two"
// => Selected "three"

// Include an inline filter
query(parent).map(mappers.children("#two")).each(el => console.log(`Selected "${el.id}"`));

// => Selected "two"

realChildren

var parent = document.createElement("div");
parent.id = "parent";
parent.innerHTML = `
<div role="presentation">
  <div id="one"></div>
</div>
<div role="presentation">
  <div role="presentation">
    <div id="two"></div>
  </div>
</div>
<div id="three"></div>
`;

query(parent).map(mappers.realChildren()).each(el => console.log(`Selected "${el.id}"`));

// => Selected "one"
// => Selected "two"
// => Selected "three"

// Include a filter parameter
query(parent).map(mappers.realChildren("#two")).each(el => console.log(`Selected "${el.id}"`));

// => Selected "two"

parent

var parent = document.createElement("div");
parent.id = "parent";
parent.innerHTML = `
<div id="one"></div>
<div id="two"></div>
<div id="three"></div>
`;

query(parent).select("#two").map(mappers.parent()).each(el => console.log(`Selected "${el.id}"`));

// => Selected "parent"

// Include a filter parameter
query(parent).select("#two").map(mappers.parent("#parent")).each(el => console.log(`Selected "${el.id}"`));

// => Selected "parent"

realParent

var parent = document.createElement("div");
parent.id = "parent";
parent.innerHTML = `
<div role="presentation">
  <div id="one"></div>
</div>
<div role="presentation">
  <div role="presentation">
    <div id="two"></div>
  </div>
</div>
<div id="three"></div>
`;

query(parent).select("#two").map(mappers.realParent()).each(el => console.log(`Selected "${el.id}"`));

// => Selected "parent"

// Include a filter parameter
query(parent).select("#two").map(mappers.realParent("#parent")).each(el => console.log(`Selected "${el.id}"`));

// => Selected "parent"

ancestors

var parent = document.createElement("div");
parent.id = "root";
parent.innerHTML = `
<div id="one">
  <div id="two"></div>
</div>
`;

query(parent).select("#two").map(mappers.ancestors()).each(el => console.log(`Selected "${el.id}"`));

// => Selected "one"
// => Selected "root"

// Include an inline filter
query(parent).select("#two").map(mappers.ancestors("#root")).each(el => console.log(`Selected "${el.id}"`));

// => Selected "root"

descendants

var parent = document.createElement("div");
parent.id = "root";
parent.innerHTML = `
<div id="one">
  <div id="two"></div>
</div>
`;

query(parent).map(mappers.descendants()).each(el => console.log(`Selected "${el.id}"`));

// => Selected "one"
// => Selected "two"

// Include an inline filter
query(parent).map(mappers.descendants("#one")).each(el => console.log(`Selected "${el.id}"`));

// => Selected "one"

previousSiblings and nextSiblings

var parent = document.createElement("div");
parent.id = "root";
parent.innerHTML = `
<div id="one"></div>
<div id="two"></div>
<div id="three"></div>
<div id="four"></div>
`;

query(parent).select("#three").map(mappers.previousSiblings()).each(el => console.log(`Selected "${el.id}"`));

// => Selected "two"
// => Selected "one"

// Include a filter parameter
query(parent).select("#two").map(mappers.nextSiblings("#four")).each(el => console.log(`Selected "${el.id}"`));

// => Selected "four"

slot

You can map to a component's named slot (see "Components" below).

query(component).each([
  map(mappers.slot("header"), [
    el => el.style.borderBottom = "1px solid #cccccc"
  ])
]);

In the case where an element uses more than one component, you can pass the name of the component as a second parameter.

query(component).each([
  map(mappers.slot("header", "material-card"), [
    el => el.style.borderBottom = "1px solid #cccccc"
  ])
]);

wrapper

You can wrap an element and return the wrapper.

query(el).each([
  map(mappers.wrapper(), [
    el => el.style.padding = "20px"
  ])
]);

Styling Based on Visual State

You can style an element in one or many states (using on to respond to events and when to apply styles only when the element is in a particular state):

query(element).each([
  el => el.style.backgroundColor = "red",
  on("mouseover", setState("hover")),
  on("mouseout", clearState("hover")),
  when("normal", el => el.style.backgroundColor = "red"),
  when("hover", el => el.style.backgroundColor = "blue"),
  setState("normal")
]);

Styling within a when function will be called in the order of declaration. In the example above, the normal styles will be applied and then, if the element is in the 'hover' state, the hover styles will be applied. The end result, when in the hover state, is a blue background.

Mirroring the State of Another Element

Consider an input field with an invalid input. I'd like to turn the label red when the input is invalid.

Here's the structure of the input field:

<div id="input-field">
  <label>First name</div>
  <input type="text" />
</div>

The input field itself does not have validity, but it can mirror the validity of its input and act as if it does.

select("#input-field", [
  when("validity", "invalid", [
    select("label", el => el.style.color = "red")
  ]),
  // The input field is mirroring the state of its input.
  mirrorState("validity", mappers.children("input"))
])

Other Styling Functions

Context

You can add information about visual context with the context function.

query(element).each([
  context("page")
]);

// Now you can add style based on that context.
query(element).select("[data-jsua-context~=page] > [data-lynx-hints~=header]")
  .each(el => el.style.padding = "16px");

Components

You can create a named component with slotted HTML structure.

var element = document.createElement("div");
var initialHTML = `
<div data-jsua-style-slot-name="label">Label</div>
<div>Other Content</div>
`;

element.innerHTML = initialHTML;

var componentHTML = `
<div role="presentation" data-jsua-style-slot="label"></div>
<div role="presentation" data-jsua-style-slot="content"></div>
`
query(element).each([
  component("material-card", componentHTML)
]);

The component now has the following HTML.

<div data-jsua-style-component="material-card">
  <div role="presentation" data-jsua-style-slot="label">
    <div data-jsua-style-slot-name="label">Label</div>
  </div>
  <div role="presentation" data-jsua-style-slot="content">
    <div>Other Content</div>
  </div>
</div>

By default, children will be added to an element with the attribute data-jsua-style-slot="content". If the child has a data-jsua-style-slot-name attribute, it will be added to an element with the same value for data-jsua-style-slot.

We could also have added an element to a specific slot after the component had been created.

var mapHeader = mappers.realChildren("[data-lynx-hints~=header]");
query(component).each([
  slot("header", mapHeader)
]);

For more on Authoring Components visit the wiki.

Media Queries

You can achieve responsive styling using the media function.

const largeScreen = "(min-width: 840px)";
const mediumScreen = "(min-width: 600px) and (max-width: 839px)";
const smallScreen = "(max-width: 599px)";

query(element).each([
  media(largeScreen, [
    el => el.style.backgroundColor = "green"
  ]),
  media(mediumScreen, [
    el => el.style.backgroundColor = "yellow"
  ]),
  media(smallScreen, [
    el => el.style.backgroundColor = "red"
  ])
]);

Styling Adjustments

After styling has been applied to the element and its children, it is sometimes necessary to make adjustments. For example, it may be necessary to set an overflow state if it turns out there's insufficient room for an element. Use the adjust function for this purpose.

adjust([
  filter(el => el.offsetHeight > 200, setState("overflow")),
  filter(el => el.offsetHeight <= 200, clearState("overflow"))
])

The adjust function is called at the end of a finishing pass and after any changes in the media context. Children are adjusted before parents.