import { Canvas, Meta } from '@storybook/addon-docs/blocks';

import * as ResponsiveStories from './Responsive.stories';

<Meta title='Responsive Breakpoints' />

# Responsive Breakpoints

Our users have all sorts of different devices with different screen sizes,
browser window sizes, you name it. This makes layouts a challenge, because we
can't assume too much about what's going to fit nicely in the UI.

To work around this, we use responsive breakpoints that change the appearance of
the UI based on the constraints of the window size or container.

## Guidelines

Our screen size breakpoints follow the default
[Tailwind](https://tailwindcss.com/docs/responsive-design) sizes listed below:

| Breakpoint prefix | Minimum width | Rough equivalent   | CSS                                  |
| ----------------- | ------------- | ------------------ | ------------------------------------ |
| `2xs`             | `320px`       | Mobile (narrow)    | `@media (min-width: 320px) { ... }`  |
| `xs`              | `480px`       | Mobile (portrait)  | `@media (min-width: 480px) { ... }`  |
| `sm`              | `640px`       | Mobile (landscape) | `@media (min-width: 640px) { ... }`  |
| `md`              | `768px`       | Tablet             | `@media (min-width: 768px) { ... }`  |
| `lg`              | `1024px`      | Laptop             | `@media (min-width: 1024px) { ... }` |
| `xl`              | `1280px`      | Desktop            | `@media (min-width: 1280px) { ... }` |
| `2xl`             | `1536px`      | Large screen       | `@media (min-width: 1536px) { ... }` |

Breakpoints are inclusive of the minimum width and _any larger_ size.

In general, we should build UI assuming that the screen is small unless we know
otherwise from the media query. The `sm` "mobile" breakpoint effectively just
filters out REALLY tiny screens or portrait mode.

## Implementation

#### Media Queries

`@media` queries target the window size and can function as a proxy for device
type.

#### Tailwind classnames (CSS)

You can prefix a Tailwind class with the the breakpoint size (e.g. `sm:`) to
make that style conditional on a media query.

<Canvas of={ResponsiveStories.TailwindMediaQuery} />

#### `useBreakpoint` (React)

We also have a set of React hooks that correspond to the Tailwind breakpoints
for use cases inside a component where a classname doesn't quite do the trick.

- `useBreakpointSm()`: Typically excludes narrow screens (i.e. portrait mobile)
- `useBreakpointMd()`: Typically used to indicate tablet or larger
- `useBreakpointLg()`: Typically used to indicate desktop or larger
- `useBreakpointXl()`
- `useBreakpointXxl()`

<Canvas of={ResponsiveStories.UseBreakpointSizeHook} />

There is also a version of the hook that accepts an arbitrary min-width
breakpoint. It's available for special cases, but generally we should avoid
using it in favor of one of the predefined sizes.

<Canvas of={ResponsiveStories.UseBreakpointHook} />

### Container Queries

`@container` queries target the size of the closest container. A container needs
to be given a "containment context" with the `container-type` CSS property. The
`@container` Tailwind classname establishes establishes a containment context.

We use the
[defaults](https://github.com/tailwindlabs/tailwindcss-container-queries?tab=readme-ov-file#configuration)
provided by the `@tailwindcss/container-queries` plugin plus a few smaller sizes
that we add.

The table below includes equivalent screen breakpoint sizes, but keep in mind
that existing layouts using screen size media queries are already compensating
for global layout elements like sidebars. It usually will not work to simply
swap a media query for a container query, because the container can be smaller
than the window itself.

| Breakpoint prefix | Minimum width | Notes                |
| ----------------- | ------------- | -------------------- |
| `@4xs`            | `192px`       | Custom size          |
| `@3xs`            | `224px`       | Custom size          |
| `@2xs`            | `256px`       | Custom size          |
| `@xs`             | `320px`       |                      |
| `@sm`             | `384px`       |                      |
| `@md`             | `448px`       |                      |
| `@lg`             | `512px`       |                      |
| `@xl`             | `576px`       |                      |
| `@2xl`            | `672px`       | Close to `sm` screen |
| `@3xl`            | `768px`       | Equal to `md` screen |
| `@4xl`            | `896px`       |                      |
| `@5xl`            | `1024px`      | Equal to `lg` screen |
| `@6xl`            | `1152px`      |                      |
| `@7xl`            | `1280px`      | Equal to `xl` screen |

In the demo below you can resize the dashed container by dragging the right
border.

<Canvas of={ResponsiveStories.TailwindContainerQuery} />
