import { Table } from "baseui/table-semantic";
import Example from "../../components/example";
import Exports from "../../components/exports";
import Layout from "../../components/layout";

import * as LayoutGridExports from "baseui/layout-grid";

import BasicExample from "examples/layout-grid/basic.tsx";
import SpanExample from "examples/layout-grid/span.tsx";
import ResponsiveExample from "examples/layout-grid/responsive.tsx";
import HideExample from "examples/layout-grid/hide.tsx";
import SkipExample from "examples/layout-grid/skip.tsx";
import SkipShrinkExample from "examples/layout-grid/skip-shrink.tsx";
import AlignExample from "examples/layout-grid/align.tsx";
import OrderExample from "examples/layout-grid/order.tsx";
import BehaviorExample from "examples/layout-grid/behavior.tsx";
import CustomExample from "examples/layout-grid/custom.tsx";
import UnitExample from "examples/layout-grid/unit.tsx";
import CompactExample from "examples/layout-grid/compact.tsx";
import OverridesExample from "examples/layout-grid/overrides.tsx";

export default Layout;

# Layout Grid

The `Grid` and `Cell` components can be used to create consistent & responsive layouts across your Base Web application. Within a `Grid` container, `Cell`s can be placed and aligned along a series of columns via the `span` and `skip` props.

The implementation uses [flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Using_CSS_flexible_boxes) which makes it easy to control vertical alignment (`align`) and cell ordering (`order`). Almost all of the props available on `Cell` and `Grid` are responsive, meaning they accept an array of values that map to various breakpoints defined in your app's theme.

Here are the default responsive values for the grid, based on the default Base Web theme breakpoints:

<Table
  columns={["Breakpoint", "Range", "Columns", "Gutter", "Margin"]}
  data={[
    ["Default", "0 to 319px", "1", "-", "16px"],
    ["Small", "320px to 599px", "4", "16px", "16px"],
    ["Medium", "600px to 1135px", "8", "36px", "36px"],
    ["Large", "1136px and up", "12", "36px", "64px"],
  ]}
/>

All of these values are [customizable via your theme](https://baseweb.design/guides/theming). The grid will default to whatever values are in your theme but you can additionally override any of them with props on `Grid` and `Cell`.

## Examples

<Example title="Basic" path="layout-grid/basic.tsx">
  <BasicExample />
</Example>

Place cells in a grid container and each cell will align to a column.

Cells are meant to contain your content. The grid implementation calculates margins and paddings for the various containing elements such that any content _inside_ of a cell is properly aligned to a column.

Any cells that do not fit on a single row will wrap to a new row. The default gap between wrapped cell rows is 0. You can specify a gap with the responsive `gridGaps` prop. You can also use a new `Grid` below the first one if you want to closely control vertical spacing.

You can nest grids inside of cells or other elements. The cell widths are calculated as percentages of the parent container. Use caution with this pattern though- the main use case for the grid is to align sections of the page using a consistent layout. Nesting can be an indication of a layout that is too complex and requires some design refactoring.

<Example title="Span" path="layout-grid/span.tsx">
  <SpanExample />
</Example>

Use the `span` prop to specify how many grid columns a cell should span.

If the number passed to `span` exceeds the current number of grid columns (based on current breakpoint), the cell will simply shrink to fit the current number of columns. For instance, a cell with a span of 12 will span 8 on a medium viewport, and 4 on a small viewport.

In the example above, each cell has a span of 2. This causes the excess cells to wrap on our small breakpoint. Cells that wrap to a new line will still align content to the columns of the grid.

Sometimes this wrapping behavior is desirable, but sometimes you want to adapt to different breakpoints by setting spans specific to each breakpoint. The layout grid handles this by exposing "responsive" props.

<Example title="Responsive" path="layout-grid/responsive.tsx">
  <ResponsiveExample />
</Example>

`span` is a "responsive" prop. It accepts both a single value or an array of values. Each value in the array corresponds to each [breakpoint in our theme](https://baseweb.design/guides/theming/#theme-properties).

When you specify the first value in the array, you are specifying the value for any viewport larger than or equal to the first (`small`) breakpoint in your theme. The second value applies to viewports greater than or equal to the `medium` breakpoint, and the third value applies to viewports greater than or equal to the `large` breakpoint.

In the example above, we specify that on the first breakpoint and up each cell should span 1 column. On the second breakpoint and up, each cell should span 2 columns, and on the third breakpoint and up, each cell should span 3 columns: `[1, 2, 3]`. Effectively, this keeps each cell to 1/4 of the width of the grid on all breakpoints.

This terse way of describing responsive values was originally used in our [Block](/components/block) component- it allows you to very quickly specify even the most complicated responsive layouts.

Note, you can omit larger breakpoint values if they do not change. For example, `[1, 2]` is the same as `[1, 2, 2]`. This is a result of using a `min-height` based media query approach in the implementation of the layout grid.

Also note that every `Cell` prop is "responsive". Almost all of the props for `Grid` are also "responsive" props, with the exception of `behavior` and `gridMaxWidth`, which only accept one value across all breakpoints.

Last thing to note: The grid has only one column on viewports smaller than the first breakpoint (`<320px`). Cells will effectively take up the full width of the grid. Most props have no reasonable effect with one column so "responsive" props essentially ignore this range.

<Example title="Hide" path="layout-grid/hide.tsx">
  <HideExample />
</Example>

In this example we hide the first (`1`) cell on viewports larger than the first breakpoint. Notice how we hide the cell by passing a `0` to `span`. This is useful for responsive layouts where some section may be hidden on a specific breakpoint.

<Example title="Skip" path="layout-grid/skip.tsx">
  <SkipExample />
</Example>

Another common layout scenario is "offsetting" or "skipping" columns. In this example we use the `skip` prop to offset the `2` cell by 1 column on small, 4 columns on medium, and 7 columns on large viewports. This effectively maximizes the space between the `1` and `2` cells on each breakpoint.

An important detail: `skip` specifies how many columns the left margin of the cell should span. This means that `skip` can wrap cells onto a new line in order to allow enough space for that margin. This leads to one other behavior that you may not expect...

<Example title="Shrink" path="layout-grid/skip-shrink.tsx">
  <SkipShrinkExample />
</Example>

Notice how the cell has a `span` set to fill each breakpoint, but the `skip` of 1 takes precedence and shrinks the cell to fit on one line.

<Example title="Align" path="layout-grid/align.tsx">
  <AlignExample />
</Example>

You can horizontally align the cells of the grid with the `align` prop. Note that you can pass `align` to the entire grid or to an individual cell (or both).

<Example title="Order" path="layout-grid/order.tsx">
  <OrderExample />
</Example>

Notice that the `1` cell is rendered last even though it is declared first in our markup.

This prop is mostly useful when used as a responsive prop. Imagine a card that is rendered at the top of a list of items on small viewports, but last on larger viewports, when the items are on a single row.

The `order` prop is simply a proxy for the CSS property of the same name. [Click here](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Ordering_Flex_Items) to read more about how `order` works with flexbox.

<Example title="Behavior" path="layout-grid/behavior.tsx">
  <BehaviorExample />
</Example>

The grid can have one of two possible behaviors: `fixed` or `fluid`. By default the grid is `fixed`- that is, once it reaches its maximum width, it will stay centered in the containing element.

A fluid grid essentially ignores any maximum width. The grid will continue to expand to fill the containing element's width ad infinitum. Note, both fluid and fixed grids still have a margin on both sides.

The `behavior` prop is not responsive. This is because, below the maximum width, both `fluid` and `fixed` grids are identical.

<Example title="Custom" path="layout-grid/custom.tsx">
  <CustomExample />
</Example>

In this example we customize the grid to have 12 columns at each breakpoint. We also shrink the gutters and margins, add a row gap for wrapped cells, and increase the maximum width of the grid to `1440px`.

You can customize pretty much any part of the grid while maintaining the core responsibility of aligning cells to columns. Here are the relevant props (also used in the above example) for customizing the grid:

- `gridColumns`
- `gridGaps`
- `gridGutters`
- `gridMargins`
- `gridMaxWidth` (Not responsive)

The grid will use whatever values are on your theme `grid` property as the default values for these props (denoted by the `grid` prefix for those props). This way you do not have to create a "wrapper" grid if yours differs from the default Base grid. [Click here for the full theme shape](https://baseweb.design/guides/theming/#theme-properties)or see below for the grid relevant section of the theme:

```js
const theme = {
  grid: {
    columns: [4, 8, 12],
    gutters: [16, 36, 36],
    margins: [16, 36, 64],
    gaps: 0,
    maxWidth: 1280,
  },
};
```

Note how these are defined in a similar fashion to responsive props. Each value in the array corresponds to a theme breakpoint.

If you want to customize the breakpoints of the grid, you can do so via the `breakpoints` and `mediaQuery` properties. The grid will always pull breakpoints from the theme and correlate responsive props with those breakpoints.

<Example title="Unit" path="layout-grid/unit.tsx">
  <UnitExample />
</Example>

The grid uses `px` as its default CSS unit for measuring layout. You can change this, either globally in your theme, or locally via the `unit` prop on `Grid`. If you do change your grid's unit of measurement, you probably also want to update `gridMaxWidth`, `gutters` and `margins` accordingly. For example, when using `rem` as your CSS unit, you might update the other values like so:

```js
const theme = {
  grid: {
    unit: "rem",
    gutters: [1, 2, 2],
    margins: [1, 2, 4],
    gridMaxWidth: 70,
  },
};
```

The above change will apply to every grid within the theme's subtree. If you want to override the unit for a single `Grid` instance, you can pass an alternative unit via the `gridUnit` prop:

```js
<Grid gridUnit="rem" gridMargins={[1, 2, 3]} gridMaxWidth={40}>
  {/* ... */}
</Grid>
```

<Example title="Compact" path="layout-grid/compact.tsx">
  <CompactExample />
</Example>

If your application has a high density of data or otherwise requires tighter spacing, we provide a compact version of the layout grid, which can be specified with the `gridStyle` prop. This version features smaller gutters and margins, and unlike the default layout grid, it will ignore the grid values provided in your theme. However, you can still override them by manually passing props to `Grid` and `Cell`.

<Example title="Overrides" path="layout-grid/overrides.tsx">
  <OverridesExample />
</Example>

`Grid` and `Cell` also accept an [`overrides`](/guides/understanding-overrides) prop. In the example above, we add a green border around our grid and override a single cell (4) to have a red outline.

You can also pass through props (`props`) or an alternate component implementation (`component`), but there is not much of a reason to do so. If you do decide to pass props through `overrides`, remember that the props for the inner `StyledGrid` and `StyledCell` components have a `$` prefix on all of their props.

Note, you may not need to use `overrides` at all. You can get pretty far by styling an element wrapping `Grid` or immediately inside of a `Cell`. `Grid` and `Cell` are meant to help align your content; generally they should not require styling of their own.

That said, we provide `overrides` just in case your imagination surpasses our API 🚀.

<Exports
  component={LayoutGridExports}
  title="Layout Grid exports"
  path="baseui/layout-grid"
/>
