2.1.0 • Published 3 months ago

@skbkontur/react-stack-layout v2.1.0

Weekly downloads
273
License
MIT
Repository
github
Last release
3 months ago

react-stack-layout npm

Library for quick arrangement of controls in vertical or horizontal stacks. Essentially, it represents a layout manager from the world of Desktop applications. This library is particularly well-suited for simple interfaces or rapid prototyping.

Justification

Very often when developing business logic, you need to quickly align controls horizontally one after another, aligning them, for example, by the baseline, while remembering that there should be a small spacing between them. When coding such layouts multiple times, code duplication appears.

In this library, I've generalized the most common scenarios for control placement and created several convenient abstractions built on top of flexbox.

Plus a small bonus: such code is understandable to anyone.

Idea

Suppose you need to arrange several controls in a specific way. Instead of adding additional styles to elements, we propose creating a template (or framework) with placeholders, inside which you can place the needed elements.

What do we have?

Root elements

  • RowStack — arranges child elements in a row.
  • ColumnStack — arranges child elements in a column, one under another.

Placeholders

  • Fit — takes the size corresponding to its content.
  • Fill — occupies all available space.
  • Fixed — has a fixed size.

How to use

Installation

npm install @skbkontur/react-stack-layout

or

yarn add @skbkontur/react-stack-layout

and import

import { ColumnStack, RowStack, Fill, Fit, Fixed } from "@skbkontur/react-stack-layout";

Documentation

RowStack

Arranges elements in a row and has two main properties: verticalAlign and gap. It doesn't wrap elements to the next line if there's not enough space (so keep that in mind!).

  • verticalAlign takes values like top, bottom, center, baseline, or stretch and determines how the placeholder will be positioned vertically inside the container. Pretty straightforward, right?
  • gap defines the horizontal spacing between placeholders. Nothing fancy here.

Basic Example

<RowStack verticalAlign="top">
    <Fit>
        <YellowItem />
    </Fit>
    <Fit>
        <GreenItem />
    </Fit>
    <Fit>
        <BlueItem />
    </Fit>
</RowStack>

fig1

To help you understand the relationships and sizes of elements (because who doesn't love a good visual guide):

  • The gray frame shows the parent element containing our container.
  • The blue frame represents the container itself (RowStack or ColumnStack).
  • The red frame indicates the placeholder (Fit, Fill, or Fixed) for your content.

So basically, the example above looks like this:

fig5

Gap property

<RowStack verticalAlign="top" gap={4}>
    {/*...*/}
</RowStack>

fig6

Using verticalAlign options

<RowStack verticalAlign="baseline" gap={4}>
    {/*...*/}
</RowStack>

fig7

<RowStack verticalAlign="bottom" gap={4}>
    {/*...*/}
</RowStack>

fig8

Stretch - placeholders stretch to the height of the container. But they don't stretch the container itself.

<RowStack verticalAlign="stretch" gap={4}>
    {/*...*/}
</RowStack>

fig9

Center — not the same as baseline :-)

<RowStack verticalAlign="center" gap={4}>
    {/*...*/}
</RowStack>

fig10

Note that the container doesn't take up the full width of the parent. By default, RowStack uses display: inline-flex;, which is more convenient in most cases.

To make the container a block element, use the block property.

<RowStack block verticalAlign="center" gap={4}>
    {/*...*/}
</RowStack>

fig11

Fill

Fill stretches to occupy all available width.

<RowStack block verticalAlign="top">
    <Fit><YellowItem /></Fit>
    <Fill><GreenItem /></Fill>
    <Fit><BlueItem /></Fit>
</RowStack>

fig12

Note that only the container's space is used. If you remove the block property, the green element won't take up as much space:

<RowStack verticalAlign="top">
    <Fit><YellowItem /></Fit>
    <Fill><GreenItem /></Fill>
    <Fit><BlueItem /></Fit>
</RowStack>

fig13

Fixed

Fixed gives the placeholder a fixed width.

<RowStack verticalAlign="top">
    <Fit><YellowItem /></Fit>
    <Fixed width={200}><GreenItem /></Fixed>
    <Fit><BlueItem /></Fit>
</RowStack>

fig14

When there's not enough space in the placeholder:

<RowStack verticalAlign="top">
    <Fit><YellowItem /></Fit>
    <Fixed width={70}><GreenItem /></Fixed>
    <Fit><BlueItem /></Fit>
</RowStack>

fig15

And when there's not enough space in the container:

<RowStack verticalAlign="top">
    <Fit><YellowItem /></Fit>
    <Fixed width={400}><GreenItem /></Fixed>
    <Fit><BlueItem /></Fit>
</RowStack>

fig16

So, Fixed has some issues. Use it with care.

ColumnStack

Arranges elements in a column and has two main properties: horizontalAlign and gap.

  • horizontalAlign takes values like left, right, center, or stretch and determines how the placeholder will be positioned horizontally inside the container.
  • gap defines the vertical spacing between placeholders.

Basic Example

<ColumnStack horizontalAlign="left" gap={5}>
    <Fit><YellowItem /></Fit>
    <Fit><GreenItem /></Fit>
    <Fit><BlueItem /></Fit>
</ColumnStack>

fig17

Using horizontalAlign options

<ColumnStack horizontalAlign="center" gap={5}>
    {/*...*/}
</ColumnStack>

fig18

<ColumnStack horizontalAlign="right" gap={5}>
    {/*...*/}
</ColumnStack>

fig19

Stretch — placeholders stretch to the width of the container. But they don't stretch the container itself.

<ColumnStack horizontalAlign="stretch" gap={5}>
    {/*...*/}
</ColumnStack>

fig20

Don't forget about the block property, which makes the element a block element:

<ColumnStack block horizontalAlign="stretch" gap={5}>
    {/*...*/}
</ColumnStack>

fig21

!!! Fixed for ColumnStack is not applicable in version 1.0.0 !!!

Fill stretches to take up all available height. Remember that the available height is chosen for the container, not for its parent. In the following example, the green element didn't stretch the container to the height of the parent.

<ColumnStack horizontalAlign="left" gap={5}>
    <Fit><YellowItem /></Fit>
    <Fill><GreenItem /></Fill>
    <Fit><BlueItem /></Fit>
</ColumnStack>

fig22

To make it work, you need to make the container as tall as its parent:

<ColumnStack horizontalAlign="left" gap={5} style={{ height: "100%" }}>
    <Fit><YellowItem /></Fit>
    <Fill><GreenItem /></Fill>
    <Fit><BlueItem /></Fit>
</ColumnStack>

fig23

Shorthand properties

For common cases of verticalAlign or horizontalAlign, there are simple shortcuts:

<RowStack baseline />

And for ColumnStack:

<RowStack stretch />

Usage Examples

Common arrangement of controls from react-ui.

Example 1. Controls aligned by baseline.

<RowStack baseline block gap={2}>
    <Fit><Input /></Fit>
    <Fit><Button use="primary">Search</Button></Fit>
    <Fit><Checkbox>Prohibited content</Checkbox></Fit>
</RowStack>

fig24

Example 2. Wide input.

<RowStack baseline block gap={2}>
    <Fill><Input width="100%" /></Fill>
    <Fit><Button use="primary">Search</Button></Fit>
    <Fit><Checkbox>Prohibited content</Checkbox></Fit>
</RowStack>

fig25

Example 3. Another wide input.

<RowStack baseline block gap={2}>
    <Fill><Input width="100%" /></Fill>
    <Fit><Button use="primary" disabled>Search</Button></Fit>
    <Fit><Spinner type={"mini"} caption="Spinner" /></Fit>
</RowStack>

fig26

Example 4. Elements at opposite ends.

<RowStack baseline block gap={2}>
    <Fit><Button>Button 1</Button></Fit>
    <Fill />
    <Fit><Button>Button 2</Button></Fit>
    <Fit><Button>Button 3</Button></Fit>
</RowStack>

fig27

Drop me a line if you know how to expand the list of examples.

Known Issues

  • Sometimes, well actually quite often, there are extra DOM elements (I'm willing to pay that price for code clarity and uniformity).
  • There are a few bugs (help wanted!).
  • Issues with vertical Fill. Using it can sometimes be a bit awkward.
  • Fixed doesn't work with ColumnStack.

Usage Scenarios and Special Considerations

A few more words about usage:

  • Containers are not a replacement for regular layouts. You shouldn't use them for complex and tricky components.
  • Using these components should simplify your layout, not complicate it.
  • In the source code of a single component, you shouldn't use more than three, maybe four, levels of nested components.

API Reference

<RowStack />

Container element in which placeholders (Fit, Fixed, or Fill) must be direct children. Arranges elements horizontally.

Props

  • verticalAlign?: "top" | "bottom" | "center" | "baseline" | "stretch";
    (default = "top") Determines the vertical position of placeholders inside the container.

  • baseline?: boolean;
    Shortcut for verticalAlign="baseline". If verticalAlign is already set, an exception will be thrown.

  • block?: boolean;
    Changes the element's display to flex. By default, the container is inline-flex.

  • inline?: boolean;
    Changes the element's display to inline-flex.

  • gap?: number;
    Sets the gap between elements in arbitrary units. gap={1} equals a 5px gap.

<ColumnStack />

Container element in which placeholders (Fit or Fill) must be direct children. Arranges elements in a column.

Props

  • horizontalAlign?: "left" | "right" | "center" | "stretch";
    (default = "left") Determines the horizontal position of placeholders inside the container.

  • stretch?: boolean;
    Shortcut for horizontalAlign="stretch". If horizontalAlign is already set, an exception will be thrown.

  • block?: boolean;
    Changes the element's display to flex. By default, the container is inline-flex.

  • inline?: boolean;
    Changes the element's display to inline-flex.

  • gap?: number;
    Sets the gap between elements in arbitrary units. gap={1} equals a 5px gap.

<Fit />

Placeholder element. Takes up space corresponding to its content.

<Fill />

Placeholder element. Takes up all available space in the container.

<Fixed />

Placeholder element. Takes up a specified size. Only applicable inside RowStack.

Props

  • width: number;
    Required parameter. Corresponds to the width occupied in the container.