npm package: @plangrid/structure
Description: CSS structure library
Latest version: 0.37.0

# structure

- [`npm install @plangrid/structure`](https://www.npmjs.com/package/@plangrid/structure)
- [`main.css`](main.css) is the production bundle
- [unpkg](https://unpkg.com/@plangrid/structure/) for [codepen](https://codepen.io/ryanve/pen/gRamvZ)
- [`CONTRIBUTING.md`](CONTRIBUTING.md)
- [JavaScript API](#javascript-api)

## Usage

- Favor flexbox for layout over other layout techniques
- [Flexbox classes](modules/flexbox.css) use pure [flex properties](https://www.w3.org/TR/css-flexbox-1/) to afford layouts in any direction or [alignment](modules/alignment.css)
- Be aware of [flexbugs](https://github.com/philipwalton/flexbugs#flexbugs) and especially test complex layouts for browser differences

### `flex` [balanced grid](https://codepen.io/ryanve/pen/mmgjXE)

```html
<div class="flex">
  <div class="flex-auto">item</div>
  <div class="flex-auto">item</div>
  <div class="flex-auto">item</div>
</div>
```

### `flex` [wrapping grid](https://codepen.io/ryanve/pen/JNzPMw)

```html
<div class="flex flex-wrap">
  <div class="basis-4">grid item</div>
  <div class="basis-4">grid item</div>
  <div class="basis-4">grid item</div>
  <div class="basis-4">grid item</div>
  <div class="basis-4">grid item</div>
</div>
```

### `flex` [reversing](https://codepen.io/ryanve/pen/BdJgzp)

```html
<ol class="flex flex-column-reverse p0">
  <li class="block p2 flex-auto">1</li>
  <li class="block p2 flex-auto">2</li>
  <li class="block p2 flex-auto">3</li>
</ol>
```

### `flex` [centering](https://codepen.io/ryanve/pen/RVOYoZ)

```html
<div class="flex items-center justify-center">
  <p>I'm centered :)
</div>
```

### [`alignment`](modules/alignment.css)

- [Our alignment classes](modules/alignment.css) are useful for aligning flex items
- Properties include [`align-items`](https://developer.mozilla.org/en-US/docs/Web/CSS/align-items) [`align-content`](https://developer.mozilla.org/en-US/docs/Web/CSS/align-content) [`align-self`](https://developer.mozilla.org/en-US/docs/Web/CSS/align-self) [`justify-content`](https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content)
- Values include [alignment values](https://www.w3.org/TR/css-align-3/#alignment-values) that are supportable by our browser coverage
- W3C categorizes values as [positional](https://www.w3.org/TR/css-align-3/#positional-values) | [baseline](https://www.w3.org/TR/css-align-3/#baseline-values) | [distribution](https://www.w3.org/TR/css-align-3/#distribution-values)

### [`spacing`](https://github.com/ryanve/spacing/tree/v0.3.0#classes)

```html
<figure class="m0 mb1 p2 pr4">
  <figure class="p2 m0 mb1 mb0-last">content</figure>
  <figure class="p2 m0 mb1 mb0-last">content</figure>
</figure>
```

#### [Experimental](https://github.com/plangrid/structure/pull/44): [`[data-spacing]`](https://github.com/ryanve/spacing/tree/v0.2.1#data-spacing)

```jsx
<Component data-spacing="mt0 mb2">
```

### [`position`](https://codepen.io/ryanve/pen/PmgBLK)

- `.static`
- `.relative`
- `.absolute`
- `.fixed`
- `.focus-static` for use like `"relative focus-static"` to sink on focus
- `.focus-relative` for use like `"static focus-relative"` to lift on focus
- `.top-auto` `.left-auto` `.right-auto` `.bottom-auto`
- `.top-0` `.left-0` `.right-0` `.bottom-0`

```html
<div class="relative">
  <div class="absolute top-0 left-0 right-0 bottom-0">I fill my container</div>
</div>
```

### [`border`](modules/border.css)

- `.border` **Deprecated.** Favor `border-1px border-solid`
- `.border-top` **Deprecated.** Favor `border-1px bt-solid`
- `.border-left` **Deprecated.** Favor `border-1px bl-solid`
- `.border-right` **Deprecated.** Favor `border-1px br-solid`
- `.border-bottom` **Deprecated.** Favor `border-1px bb-solid`
- `.border-1px` is our standard `border-width` for any bordered component
- `.border-none` `.bt-none` `.br-none` `.bb-none` `.bl-none`
- `.border-dashed` `.bt-dashed` `.br-dashed` `.bb-dashed` `.bl-dashed`
- `.border-solid` `.bt-solid` `.br-solid` `.bb-solid` `.bl-solid`
- `.border-hidden` `.bt-hidden` `.br-hidden` `.bb-hidden` `.bl-hidden`

### [`border-radius`](https://plangrid.github.io/structure/#corners)

Round `>=6px` to `12px` and `<6px` to `3px` because `2px` `3px` `12px` are the most current sizes in our design system. Feature specs may be outdated. Please `#truststructure`

- `.rounded` **Deprecated.** Favor `round-medium`
- `.rounded-stack` **Deprecated.** Favor `round-medium sharp-stack`
- `.rounded-shelf` **Deprecated.** Favor `round-medium sharp-shelf`
- `.round-small` for `2px` corners. Use on pills
- `.round-medium` for `3px` corners. Use on buttons, cards...
- `.round-large` for `12px` corners. Use on modals
- `.round-circle` for `50%` corners
- `.sharp-top` zero top corners
- `.sharp-left` zero left corners
- `.sharp-right` zero right corners
- `.sharp-bottom` zero bottom corners
- `.sharp-shelf` zero interior shelf corners
- `.sharp-stack` zero interior stack corners

```html
<nav class="block p2 round-medium sharp-stack m-auto mt0 mb2">
  <a class="block p2 round-medium sharp-stack mb1">top</a>
  <a class="block p2 round-medium sharp-stack mb1">middle</a>
  <a class="block p2 round-medium sharp-stack mb1">bottom</a>
</nav>
```

```html
<div class="width-em height-em round-circle">circle</div>
```

### [`border-width`](https://codepen.io/ryanve/pen/jYygaX)

Melding and welding refer to the union of borders between siblings. `meld` and `weld` do the same job but with opposing techniques. Compose them together to remove any inner borders. `stack` affects vertical union. `shelf` affects horizontal union.

- `.meld-stack` - meld stacked borders into one via `:not(:first-child)`
- `.meld-shelf` - meld shelved borders into one via `:not(:first-child)`
- `.weld-stack` - weld stacked borders into one via `:not(:last-child)`
- `.weld-shelf` - weld shelved borders into one via `:not(:last-child)`

```html
<a class="block p2 border round-medium sharp-stack meld-stack">top</a>
<a class="block p2 border round-medium sharp-stack meld-stack">middle</a>
<a class="block p2 border round-medium sharp-stack meld-stack">bottom</a>
```

```html
<a class="block p2 border round-medium sharp-shelf meld-shelf">left</a>
<a class="block p2 border round-medium sharp-shelf meld-shelf">right</a>
<a class="block p2 border round-medium sharp-shelf meld-shelf">bottom</a>
```

### [`display`](https://codepen.io/ryanve/pen/aWxjpX)

```html
<label class="block">
  <input class="inline-block mr1" type="checkbox" checked>
  Use functional CSS
</label>
```

### [`visibility`](https://developer.mozilla.org/en-US/docs/Web/CSS/visibility)
- `.vis-visible` default (element box is visible)
- `.vis-hidden` invisible and inaccessible but retains layout
- `.vis-collapse` invisible and inaccessible but retains [flex strut](https://drafts.csswg.org/css-flexbox-1/#visibility-collapse) or [table layout](https://drafts.csswg.org/css-tables-3/#visibility-collapse-rendering) with [careful use](https://developer.mozilla.org/en-US/docs/Web/CSS/visibility#Browser_compatibility)

### [`overflow`](modules/overflow.css)

- `.overflow-visible` or per axis `.ox-visible` `.oy-visible`
- `.overflow-hidden` or per axis `.ox-hidden` `.oy-hidden`
- `.overflow-scroll` or per axis `.ox-scroll` `.oy-scroll`
- `.overflow-auto` or per axis `.ox-auto` `oy-auto`
- `.overflow-dots` sets `text-overflow` to `ellipsis`
- `.wrap-normal` sets `overflow-wrap` to `normal`
- `.wrap-word` sets `overflow-wrap` to `break-word`

```html
<div class="overflow-auto">
  I scroll as needed.
</div>
<div class="oy-scroll">
  I scroll vertically.
</div>
<div class="overflow-hidden overflow-dots ws-nowrap width-fit">
  I truncate normally...
</div>
<div class="overflow-hidden overflow-dots ws-nowrap width-clip width-force">
  I truncate specially...
</div>
```

### [`white-space`](https://developer.mozilla.org/en-US/docs/Web/CSS/white-space)
- `.ws-normal`
- `.ws-nowrap`
- `.ws-pre`
- `.ws-pre-wrap`
- `.ws-pre-line`

### [`sizing`](modules/sizing.css)

```html
<div class="max-viewport min-zero width-all height-all">
  example
</div>
```

### [`float`](https://developer.mozilla.org/en-US/docs/Web/CSS/float)

We avoid floats where possible due to the abundance of more maintainable techniques such as flexbox for many scenarios. We provide `.float-none`, `.float-left`, `.float-right`, `.clearfix` for transitional use and [special cases](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Block_formatting_context).

### [`list-style`](https://developer.mozilla.org/en-US/docs/Web/CSS/list-style)

Use these on `li` or its `ul` or `ol` to affect all children. These only apply when `display` is `list-item`. Avoid `inside` when its children are `block` because [browsers vary in how inside blocks appear](https://developer.mozilla.org/en-US/docs/Web/CSS/list-style-position).

- `.list-disc` sets type to `disc` (initial)
- `.list-circle` sets type to `circle`
- `.list-outside` sets position to `outside` (initial)
- `.list-inside` sets position to `inside`
- `.list-none` sets style to `none`

### [`text-align`](https://developer.mozilla.org/en-US/docs/Web/CSS/text-align)

- `.text-left`
- `.text-right`
- `.text-center`

### [`vertical-align`](https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align)

Favor flexbox techniques for layout but know that these are available for finetuning.

- `.align-baseline` default
- `.align-top`
- `.align-middle`
- `.align-bottom`
- `.align-sub`
- `.align-super`
- `.align-ascent` for `text-top`
- `.align-descent` for `text-bottom`

### [`font`](modules/font.css)

- Display fonts are named in t-shirt sizes. [See demo](https://plangrid.github.io/structure/#fonts) and round to the nearest fit :)
- Components may access via [`import structure from "@plangrid/structure"`](#javascript-api)

```js
structure.bond("FontC") // "font-os font-c"
structure.bond("FontB") // "font-os font-b"
structure.bond("FontXXS") // "font-os font-xxs"
structure.bond("FontXS") // "font-os font-xs"
structure.bond("FontS") // "font-os font-s"
structure.bond("FontM") // "font-os font-m"
structure.bond("FontL") // "font-os font-l"
structure.bond("FontXL") // "font-os font-xl"
```

- `.font-c` is `400 12px/1.25` `none`
- `.font-b` is  `400 14px/1.5` `none`
- `.font-xxs` is `400 12px/1.25` `uppercase`
- `.font-xs` is `600 16px/1.5` `none`
- `.font-s` is `400 20px/1.25` `none`
- `.font-m` is `400 26px/1.25` `none`
- `.font-l` is `600 32px/1.25` `none`
- `.font-xl` is `600 42px/1` `none`

#### `.font-os`

- `.font-os` Recommended. Equals `.family-os` U `normal normal 400`
- `.family-inherit`
- `.family-os`

#### `font-weight`

- `.weight-inherit`
- `.weight-light`
- `.weight-normal` *legacy alias:* `.unbold`
- `.weight-semibold` *legacy alias:* `.semibold`
- `.weight-bold` *legacy alias:* `.bold`

#### `.font-collapse`

- Collapse whitespace or hide text in a11y technique
- `.font-collapse` = `.size-collapse` U `.line-collapse`

#### `font-size`

- `.size-inherit`
- `.size-14px`
- `.size-16px`
- `.size-20px`
- `.size-26px`
- `.size-32px`
- `.size-42px`
- `.size-body` **at risk**
- `.size-caption` **at risk**

#### `line-height`

- `.line-initial` for `normal` initial
- `.line-inherit` for `inherit`
- `.line-single` is `1` for use on headings or alignments
- `.line-subcompact` is `1.125` for use on headings
- `.line-compact` is `1.25` for use on headings
- `.line-passing` is `1.5` for text. [Passes WCAG guidelines](https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-visual-presentation.html)
- `.line-double` is `2` for special cases

### [`text-transform`](https://developer.mozilla.org/en-US/docs/Web/CSS/text-transform)

Case classes transform the entire element while letter classes only transform the `::first-letter` such that you can compose as needed like `"case-lower letter-upper"` for sentence case.

- `.case-none` CSS is composable
- `.case-lower` css is composable
- `.case-upper` CSS IS COMPOSABLE
- `.case-proper` CSS Is Composable
- `.letter-lower` cSS is composable
- `.letter-upper` CSS is composable
- `.case-lower.letter-upper` Css is composable
- `.case-upper.letter-lower` cSS IS COMPOSABLE

### [`text-decoration`](https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration)

- `.underline-none` removes underline. You must provide alternative visual affordance.
- `.underline-focus` adds underline on `:focus`
- `.underline-hover` adds underline on `:hover`
- `.underline` adds underline to all states

### [`cursor`](modules/cursor.css)

- `.pointer` set `cursor` to `pointer` unless disabled

### [`pointer-events`](modules/pointer-events.css)

```css
.events-none { pointer-events: none }
.events-auto { pointer-events: auto }
```

### [`appearance`](modules/vendor.css)

- `.appearance-none` sets vendor appearance to `none` for custom styling

### [`resize`](modules/resize.css)

- `.resize-none`
- `.resize-both`

### [`transform`](modules/transform.css)

- `.-tx100` for `translateX(-100%)`
- `.-ty100` for `translateY(-100%)`
- `.tx0` for `translateX(0)`
- `.ty0` for `translateY(0)`
- `.tx100` for `translateX(100%)`
- `.ty100` for `translateY(100%)`

### [`animation`](modules/animation.css)

- `.anim-initial` resets `animation` to its `initial` values
- `.anim-reverse` reverses animation
- `.anim-seed` uses `backwards` fill mode
- `.anim-stay` uses `forwards` fill mode
- `.anim-fill` uses `both` fill mode
- `.anim-paused` pauses animation
- `.anim-infinite` animates for infinite iterations
- `.keyspeeds-spin` duration for spinner **iterating**
- `.keyframes-spin` rotate from `0deg` to `360deg` **iterating**

### [Presets](preset.css)

Presets provide partials for common needs. Presets load early such that other classes may override them.

- `.preset-box` box-model base
- `.preset-input` input base
- `.preset-textarea` textarea base
- `.preset-button` button base

## JavaScript API

We are developing a JavaScript API to help component developers reliably compose classes.

```
npm install @plangrid/structure
```

```js
const structure = require("@plangrid/structure");
```

[`structure`](structure.js) is a frozen [`cader`](https://github.com/ryanve/cader/tree/v0.7.0#cader) instance.

```js
structure.fuse("FontXL") // "family-os weight-semibold size-42px line-single"
structure.fuse("Tap") // "family-os preset-button fill-current pointer"
structure.fuse("Tap FontXL") // Unique fusion of both
structure.bond("FontXL another") // Unique bonding of saved atom(s) and unsaved atom(s)
structure.bond("FontXL m0 mb1") // "family-os weight-semibold size-42px line-single m0 mb1"
```

- `.bond` permits mixing atoms with external classes whereas `.fuse` is strictly atoms that have been saved
- Call `structure.help()` for help
- `.clone` is available for feature work

```js
const feature = structure.clone() // new instance contains saved structure atoms
feature.save({/* ... */})  // can save more atoms if unique from structure atoms
```
### Available atoms

#### [Font](#font) atoms

```js
structure.bond("FontC") // "font-os font-c"
structure.bond("FontB") // "font-os font-b"
structure.bond("FontXXS") // "font-os font-xxs"
structure.bond("FontXS") // "font-os font-xs"
structure.bond("FontS") // "font-os font-s"
structure.bond("FontM") // "font-os font-m"
structure.bond("FontL") // "font-os font-l"
structure.bond("FontXL") // "font-os font-xl"
```

#### [Border](#border) atoms

```js
structure.bond("ShelfMeld") // "sharp-shelf meld-shelf"
structure.bond("ShelfWeld") // "sharp-shelf weld-shelf"
structure.bond("StackMeld") // "sharp-stack meld-stack"
structure.bond("StackWeld") // "sharp-stack weld-stack"
```

#### [Overflow](#overflow) atoms

```js
structure.bond("TruncateBox") // "overflow-hidden overflow-dots ws-nowrap preset-box"
structure.bond("TruncateDIY") // "overflow-hidden overflow-dots ws-nowrap"
structure.bond("TruncateDIY width-fit") // max-width: 100%
structure.bond("PaneX") // "preset-box oy-hidden ox-auto"
structure.bond("PaneY") // "preset-box ox-hidden oy-auto"
structure.bond("PaneX PaneY") // both auto
```

- See [preset.css](preset.css) to see what `.preset-box` does
- `Pane` is meant to provide our standard scrolling behavior. TBD if we will standardize on `auto` or `scroll`

#### Shadow atoms

```js
structure.bond("FlatControl") // "shadow-ring"
structure.bond("RaiseControl") // "shadow-raised shadow-ring"
structure.bond("RaiseStatic") // "shadow-raised"
```

#### Control atoms

- `HF` = heavy frame
- `LF` = light frame
- `WIP` = work in progress

```js
structure.bond("UnderNone") // "underline-none"
structure.bond("UnderSome") // "underline-none underline-hover"
structure.bond("UnderAll") // "underline"
structure.bond("Ask") // structure.bond("FontB line-single preset-box block-table")
structure.bond("Cbox") // "font-os preset-button cbox"
structure.bond("Rdio") // "font-os preset-button rdio"
structure.bond("Field") // "font-os preset-box border-none"
structure.bond("Tactile") // "font-os preset-box block-table"
structure.bond("InputLF") // "font-os preset-input round-medium border"
structure.bond("InputHF") // structure.bond("InputLF frame-basic")
structure.bond("OpdownWIP") // structure.bond("PaneY round-medium RaiseControl")
structure.bond("OptionLF") // "overflow-hidden overflow-dots ws-nowrap preset-box font-os block"
structure.bond("OptionHF") // structure.bond("OptionLF font-b p1")
structure.bond("TapLF") // "font-os preset-button"
structure.bond("TapHF") // "font-os preset-button pointer"
structure.bond("TextareaLF") // "font-os preset-textarea round-medium border"
structure.bond("TextareaHF") // structure.bond("TextareaLF frame-basic")
structure.bond("PutLF") // "font-os preset-input round-medium border sharp-shelf weld-shelf"
structure.bond("PutHF") // structure.bond("PutLF frame-basic")
```

#### Unstable atoms

```js
structure.bond("Checkbox") // "font-os preset-button cbox shadow-raised shadow-ring tone-check"
structure.bond("Radio") // "font-os preset-button rdio shadow-raised shadow-ring tone-check"
```

#### Deprecated atoms

```js
structure.bond("Tap") // => structure.bond("TapLF")
structure.bond("Input") // => structure.bond("InputHF RaiseControl")
structure.bond("Textarea") // => structure.bond("TextareaHF RaiseControl")
structure.bond("Input:validate") // => structure.bond("InputHF RaiseControl tone-validate")
structure.bond("Input:validity") // => structure.bond("InputHF RaiseControl tone-validity")
structure.bond("Input:valid") // => structure.bond("InputHF RaiseControl tone-valid")
structure.bond("Input:invalid") // => structure.bond("InputHF RaiseControl tone-invalid")
structure.bond("Textarea:validate") // => structure.bond("TextareaHF RaiseControl tone-validate")
structure.bond("Textarea:validity") // => structure.bond("TextareaHF RaiseControl tone-validity")
structure.bond("Textarea:valid") // => structure.bond("TextareaHF RaiseControl tone-valid")
structure.bond("Textarea:invalid") // => structure.bond("TextareaHF RaiseControl tone-invalid")
structure.bond("Button:secondary")
structure.bond("Button:primary")
structure.bond("Button:additive")
structure.bond("Button:destructive")
structure.bond("Secondary")
structure.bond("Primary")
structure.bond("Additive")
structure.bond("Destructive")
structure.bond("Button:link")
structure.bond("Button:icon")
```

## Questions?
Ask in our <b>#css</b> slack channel :)

## Developer commands

```
npm install
npm start
npm test
```