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

widow-best

v1.0.2

Published

Given a variable number of items and a range representing the minimum / maximum grid columns, returns the denominator for the best grid layout that prevents widows (an item appearing on its own row all alone)

Downloads

9

Readme

Install

Install with npm:

$ npm install --save widow-best

Usage

import { widowBest } from 'widow-best';

// we want a grid layout with a minimum of 1 column and a maximum of 4 columns
const layout4 = widowBest([1, 4]);

// pretend we have 5 items in an array
const items = [{}, {}, {}, {}, {}];

// to prevent widows, each item should have a width of 1/3 of its grid container.
const gridLayoutPerItem = '1/' + layout4(items.length); // 1/3

Why do I need this?

In design, there are often times you'll want to lay out items into a grid, but the number of items within the grid may vary.

Let's say you've defined a static layout of 6 columns. Each item would be 1/6 the width of its container. So far, so good.

┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│     │ │     │ │     │ │     │ │     │ │     │
│     │ │     │ │     │ │     │ │     │ │     │
└─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘  

But then, someone adds a 7th item. Naturally, the layout would look like this:

┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│     │ │     │ │     │ │     │ │     │ │     │
│     │ │     │ │     │ │     │ │     │ │     │
└─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘
┌─────┐                                        
│     │                                        
│     │  < A widow, all by itself.             
└─────┘                                        

It looks even worse if the intended layout is to have items on a new row centered, e.g.:

┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│     │ │     │ │     │ │     │ │     │ │     │
│     │ │     │ │     │ │     │ │     │ │     │
└─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘
                    ┌─────┐                    
                    │     │                    
                    │     │                    
                    └─────┘                    

What's needed to resolve this is for the denominator of each item's width to be dynamic, based on how many items exist within a container. For instance, given 7 items and an allowed range of 1-6 columns, a more pleasing layout might be in 1/4s:

        ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
        │     │ │     │ │     │ │     │
        │     │ │     │ │     │ │     │
        └─────┘ └─────┘ └─────┘ └─────┘
            ┌─────┐ ┌─────┐ ┌─────┐    
            │     │ │     │ │     │    
            │     │ │     │ │     │    
            └─────┘ └─────┘ └─────┘     

If you've ever written code that even remotely looks like this:

if (items.length == 2) {
  width = '50%';
} else if (items.length == 3) {
  width = '33.333%';
} else if (items.length == 4) {
  width = '25%';
} else if (items.length == 5) {
  width = '33.333%';
} else if (items.length == 6) {
  width = '33.333%';
}
// etc, etc.

You'll instantly know why I wrote this utility :)

More usage examples

Basic example. Given a minimum and maximum number of columns, attempt to calculate the best denominator for each item:

// pretend we have 7 items.
const howManyItems = 7;

// we want a layout with a minimum of 1 equal column (meaning, 
// if we only have 1 item, spread that item across the full
// width of the container),
// and a maximum of 6 columns before we need to add new rows.
const denominator = widowBest([1, 6], howManyItems); // => 4

widowBest accepts 2 arguments, 1) the range (array) of minimum, maximum columns, and 2) the number of items we have. widowBest is curried, so if the 2nd argument is not provided, it will return a function you can call later.

// we don't know how many items we have yet, we just know we want
// columns of 6
const bestLayoutFor6 = widowBest([1, 6]); // returns a function we can call later

// call the function with the number of items we actually have
const denominator = bestLayoutFor6(7); // now returns a number

Or, we can just define a layout on-the-fly and call everything at once:

const denominator = widowBest([1, 4], 4); // => 4

You may have a situation where you still want empty columns for the first row. In that case:

// we need a minimum of 2 columns, but only have 1 item at this point.
const denominator = widowBest([2, 4], 1); // => 2 - as in, 
// the 1 item would be 1/2 width, and we've have a 2nd empty column / white space.

What's a widow?

In copywriting and print terminology, a "widow" is a single word that, due to a given column spacing and layout, happens to appear on its own line, all by itself. Designers tend to try to avoid such layouts by either moving the preceding word to the next line as well, or adjusting things like tracking (letter-spacing), etc.