Skip to content

cipherlogs/layerzs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 

Repository files navigation

Layerzs

Layerzs

User-friendly API that makes web design and development simpler.
It's available as either Tailwind classes or React components.

X (formerly Twitter) Follow WIP License



How does it work?

Layerzs offers sophisticated layers for various tasks such as layout design, sizing, alignment, typography, table creation, effects, and more. To get a better understanding of how Layerzs is constructed, let's use flexbox as an example:

Tailwind CSS

  • API Layers:
    • Layer1: This is a basic layer that supports the next layer. You usually won't use it directly, but it's necessary for Layer2 to function.

    • Layer2: This is a more advanced layer built on Layer1. It lets you create layouts quickly and easily. It can switch between CSS grid and CSS flexbox automatically, so you don't need to worry about the details. This combination creates a powerful and universal API.

    • Niche Layers: These are built on Layer2. They're used to build components and more complex user interfaces.

Caution

Each new layer in the API is designed to replace the previous one. This means if you're using Layer2, you won't need to use Layer1 or the base layer. This is a key principle of our design. If a new layer doesn't make the previous one obsolete, it's not a good abstraction. That's why our top-level components are built with Layer2. They're not bloated like other UI libraries, and they're easy to read, edit, and modify.

Note: Please read the discussion and vote for what you believe is best.


Next, we'll compare using flexes to using flexbox. Keep in mind that flexes is just Layer1. In practice, you'll be using Layer2 and above.



The Base Layer

The base layer is what you're already using, whether you write vanilla CSS, CSS in JS, or use tailwind classes. The same rules still apply.

Tailwind CSS


Before using it, you need to understand the main axis, the cross axis, and how they change. This is great for beginners, but for advanced users it is inefficient and a waste of time.

Does Layerzs offer a better solution?



The First Layer

Tailwind CSS

Getting Started

In the first layer, we'll be using flexes. This simplifies things by removing unnecessary details and extra work from the base layer.

Start by installing flexes:

$ npm -i flexes

This version of flexes uses tailwind as the base layer, so ensure tailwind is installed. Then, import and initialize flexes:

import flex from "flexes";

function App() {
  const {cls, f} = flex ();

  return (<></>);
}

Here, f contains the entire flexes API, and cls is a utility that helps us manage and run all tailwind classes and layerzs utils.

cls

cls removes tailwind duplicates and conflicts, and helps organize long tailwind class sets. It can also include variables and functions.

className={cls("hover:p-2 hover:p-4")} // → 'hover:p-4'

It also assists in organizing lengthy sets of Tailwind classes.

Instead of this:

className="relative inline-flex items-center justify-center rounded-md p-2 text-gray-400 hover:bg-gray-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"

You could break it down to small sets that makes sense to you

className={cls(
  "relative inline-flex items-center justify-center",
  "rounded-md p-2 text-gray-400",
  "hover:bg-gray-700 hover:text-white",
  "focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white",
)}

You can also include variables and functions,

const display = "flex";
const background = (color = "black") =>
    color === "black"
    ? "bg-black"
    : "bg-white";

...

<div className={cls(display, background,)}></div>
<div className={cls(display, background("white"),)}></div>
<div className={cls(display, "border border-dashed")}></div>

Creating a container

To create a flex box container using flexes, label the parent as a box and its children as items.

<>
  <div className={cls(f.box)}>
    <div className={cls(f.item)}>Child 1</div>
    <div className={cls(f.item)}>Child 2</div>
  </div>
</>

Box API

box(direction, wrap, orders)

  • direction (optional): "row", "col" (default = "row")

  • wrap (optional): enable wrap (default = false)

  • orders (optional): (default = items are ordered automatically)

Dealing with nested containers

Often, you'll need to create a container that's also an item. In this case, you need to help flexes understand the nesting level you're at. Simply use f.lastItem.

<>
  <div className={cls(f.box)}>
    <div className={cls(f.item, f.box)}>
      <p>Child 1</p>
      <div className={cls(f.item)}>Sub child 1</div>
      <div className={cls(f.lastItem)}>Sub child 2</div>
    </div>

    <div className={cls(f.lastItem)}>
      <p>Child 2</p>
    </div>
  </div>
</>

Note: to use this featuer, switch to the dev branch.



Alignments

Flexes is straightforward. It operates with only two fixed axes. These axes don't change, which makes understanding things very simple.

Tailwind CSS

For example, if you want to center an item along the X-axis, it will be centered along the X-axis regardless of the flex direction or other factors. It will always be centered along the X-axis.

Unlike flexbox, where many behaviors depend on various factors that you always have to remember, flexes is different. Its API is like a strict rule that never changes, making it really easy to understand and figure out. Let's try using the center utility and see how it works in two different situations.

Note: When you use center, it's like using both centerX and centerY at once. This means it will center along both the X-axis and the Y-axis.


Tailwind CSS

<>
  <div className={cls(f.box, center)}>
    <div className={cls(f.item)}>Child 1</div>
    <div className={cls(f.item)}>Child 2</div>
    <div className={cls(f.item)}>Child 2</div>
  </div>
</>

By default, the API targets the container. To target an item, we add 'i' to any method we want. So instead of using 'center', we'll use item center 'iCenter'.

Tailwind CSS

<>
  <div className={cls(f.box)}>
    <div className={cls(f.item, f.iCenter(3))}>Child 1</div>
    <div className={cls(f.item)}>Child 2</div>
    <div className={cls(f.item)}>Child 2</div>
  </div>
</>

That's interesting, flexbox doesn't have justify-self how's flexes capable of centering an item along the X-axis when direction is row?



Order

Flexes automatically manages the arrangement of items. If you need to change the order of a specific item, you can use 'iShift'.

Tailwind CSS



<>
  <div className={cls(f.box)}>
    <div className={cls(f.item, f.iShift(2))}>Child 1</div>
    <div className={cls(f.item)}>Child 2</div>
    <div className={cls(f.item)}>Child 2</div>
  </div>
</>

iShift API

iShift(n)

  • n: (default = 0)

    • if n > 0 -> shift to the right by n (if direction is col, it will shift to the bottom)

    • if n < 0 -> shift to the left by n (if direction is col, it will shift to the top)

    • if n == 0 -> no mouvement

Sometimes, you might want to set a custom order. Here's an example:

.item:nth-child(3n+1) { order: 1; }
.item:nth-child(3n+2) { order: 2; }
.item:nth-child(3n)   { order: 3; }

You can create a custom order and use it with flex.

const orders = {
  // "start, step": order
  "1, 3": 1,
  "2, 3": 2,
  "3, 3": 3,
};

<div className={cls(f.box("col", true, orders))}>...</div>

In the second layer, you can't set a custom order. Instead, you get access to a higher level API that lets you do more without worrying about low-level details.

To learn more, check out the API



Orientation

Tailwind CSS

<>
  <div className={cls(f.box, flip)}>
    <div className={cls(f.item)}>Child 1</div>
    <div className={cls(f.item)}>Child 2</div>
    <div className={cls(f.item)}>Child 2</div>
  </div>
</>

flip API

flip(mode)

it will flip the direction, but only if wrap in on, if wrap is off and you want to flip the direction, use flip("dir")

The reverse function changes the direction but keeps the layout the same. It looks like the item orders are reversed. To only reverse the direction, use flip ("dir"), or just flip if wrap is on.

Note: Please take a moment to vote ↑ on upcoming API changes.



Spacing

You can manage spacing from the container globally using autoGap. There are 4 modes: none, around, between, even, and a fallback value if the mode can't be used.

Example:

  • autoGap ("around")
  • autoGap ("even", "gap-2")
  • autoGap ("none", "gap-x-2 gap-y-2")

If you don't provide a fallback, a gap of gap-2 will be used.

Tailwind CSS

<>
  <div className={cls(f.box, f.autoGap)}>
    <div className={cls(f.item)}>Child 1</div>
    <div className={cls(f.item)}>Child 2</div>
    <div className={cls(f.item)}>Child 2</div>
  </div>
</>

autoGap API

autoGap(mode, fallback)

  • mode:

    • "none"
    • "around"
    • "even"
    • "between"
  • fallback: any value you want using tailwind classes (default gap-1)

To control the spacing of each item, use iSpace. It can do two things:

In order to control the spacing of each item, you can use iSpace. to instruct it to do two things

  • Decide what to do when there's extra space:

    • Either add that space inside the item. Inject
    • Or put that space after, before or around the item. Put
  • Decide what to do when there's no space left (by default items will shrink). You can stop this or control how fast each item shrinks compared to others.

Tailwind CSS

<>
  <div className={cls(f.box)}>
    <div className={cls(f.item)}>Child 1</div>
    <div className={cls(f.item, f.iSpace("inject"))}>Child 2</div>
    <div className={cls(f.item)}>Child 2</div>
  </div>
</>

iSpace API

iSpace(arg1, arg2)

  • arg1: what to do when there's available free space

    • "inject"

      • iSpace("inject"), or explicitly add the amount iSpace("inject", 4)
    • "put"

      • "putBefore"
      • "putAfter"
      • "putAround"
  • arg2: what to do when there's no avilable free space (default shrink)

    • control the amount of shrinking

      • iSpace("inject", 1, 2)
      • iSpace("putAround", 2)
    • stop shrinking

      • iSpace("inject", 1, 0)
      • iSpace("putAround", 0)

This compact API lets you do everything you could with flexbox, and more.

Keep in mind, the next layer built on top of this should only use Layer1 and should render this layer obsolete. You've seen how simple and seamless it is to work with flexbox using Layer1. But what about Layer2, which is the layer you'll actually be using?



What's coming next?

Star this repository to receive updates on upcoming changes and join the discussion! discussion

Please vote for what you believe is best.

About

Higher level toolkits for creating robust modern web designs fast.

Topics

Resources

License

Stars

Watchers

Forks