Skip to content

feat(Grid): add Grid component #1606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
52d8431
feat(Grid): add Grid component
JoannaSikora Feb 26, 2025
8d743ab
feat(Grid): update column and row styling for flexible layout
JoannaSikora Feb 26, 2025
d1e6859
feat(Grid): add example of fixed-width column layout
JoannaSikora Feb 26, 2025
2bac6b6
feat(Grid): adjust column sizes in Grid story example
JoannaSikora Feb 26, 2025
b3b9993
feat(Grid): remove Row component and update Grid documentation
JoannaSikora Mar 5, 2025
49e3904
feat(Grid): add horizontal and vertical spacing props
JoannaSikora Mar 5, 2025
6126a4e
chore: update GitHub Actions cache action to v4
JoannaSikora Mar 5, 2025
91ade18
feat(Grid): add alignment props for vertical and horizontal positioning
JoannaSikora Mar 5, 2025
81e98c8
fix(Grid): correct Column component export path casing
JoannaSikora Mar 5, 2025
7fc241e
feat(Grid): improve Grid and Column component styling and add nested …
JoannaSikora Mar 6, 2025
d83d0da
refactor(Grid): remove spacing props and simplify Grid component
JoannaSikora Mar 6, 2025
29b97db
feat(Grid): add flexible column sizing with width and constraint props
JoannaSikora Mar 6, 2025
b4bcbeb
refactor(Grid): use CSS custom properties for column width and constr…
JoannaSikora Mar 6, 2025
e07d625
docs(Grid): update column sizing story description for clarity
JoannaSikora Mar 6, 2025
421baea
docs(Grid): update documentation structure and content
JoannaSikora Mar 6, 2025
56872be
docs(Grid): clarify column sizing and breakpoint usage examples
JoannaSikora Mar 7, 2025
68ab209
refactor(Grid): extract common SCSS utilities and update column styling
JoannaSikora Mar 7, 2025
6bbea5a
feat(Grid): add 'auto' column sizing and example stories for responsi…
JoannaSikora Mar 11, 2025
07e18eb
fix(Grid): update grid class for vertical gap in example story
JoannaSikora Mar 11, 2025
8ad023f
feat(Grid): add example story for automation AI agents with min-width…
JoannaSikora Mar 11, 2025
d952232
feat(Grid): add sales funnel report cards story with responsive arrows
JoannaSikora Mar 11, 2025
26158aa
docs(Grid): add note for TextApp responsive layout considerations
JoannaSikora Mar 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/chromatic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
fetch-depth: 0 # 👈 Required to retrieve git history

- name: Cache node_modules
uses: actions/cache@v2
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
ref: release

- name: Cache node_modules
uses: actions/cache@v2
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
- uses: actions/checkout@v2

- name: Cache node_modules
uses: actions/cache@v2
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
Expand Down
270 changes: 270 additions & 0 deletions packages/react-components/src/components/Grid/Grid.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
import { Meta, Title, Canvas, ArgTypes } from '@storybook/blocks';

import * as Stories from './Grid.stories';

<Meta of={Stories} />

<Title>Grid</Title>

[Intro](#Intro) | [Usage](#Usage) | [Breakpoints](#Breakpoints) | [Column System](#ColumnSystem) | [Component API](#ComponentAPI)

## Intro <a id="Intro" />

The `Grid` component provides a flexible and responsive layout system based on CSS Grid and Flexbox. It helps create consistent layouts across different screen sizes using a column-based system.

## Usage <a id="Usage" />

> Note: In the examples below, some stories include a grid overlay to help visualize the column structure.
> This overlay is only available in Storybook and is not part of the actual component.

Here's a basic example of how to use the Grid system:

```tsx
import { Grid, Column } from '@livechat/design-system-react-components';

return (
<Grid>
<Column lg={8}>
<div>Half width on large screens</div>
</Column>
<Column lg={8}>
<div>Half width on large screens</div>
</Column>
<Column lg={4}>
<div>Quarter width</div>
</Column>
<Column lg={4}>
<div>Quarter width</div>
</Column>
<Column lg={4}>
<div>Quarter width</div>
</Column>
<Column lg={4}>
<div>Quarter width</div>
</Column>
</Grid>
);
```

## Breakpoints <a id="Breakpoints" />

The grid system uses five breakpoints by default:

```scss
$breakpoints: (
sm: 320px, // Small devices
md: 672px, // Medium devices
lg: 1024px, // Large devices
xlg: 1312px, // Extra large devices
max: 1584px // Maximum width
);
```

> **Note for TextApp**: Since TextApp is designed with a minimal layout width of 1024px (corresponding to the `lg` breakpoint), you may not need to implement responsive behaviors for smaller breakpoints (`sm` and `md`). Focus on using `lg`, `xlg`, and `max` breakpoints for your layout needs.

## Column System <a id="ColumnSystem" />

The grid uses the doubling columns system, which means that the number of columns is doubled for each of the main breakpoint:

```scss
$grid-columns: (
sm: 4, // 4 columns for small screens
md: 8, // 8 columns for medium screens
lg: 16, // 16 columns for large screens
xlg: 16, // 16 columns for extra large screens
max: 16 // 16 columns for maximum width
);
```

### Column Props

Columns can be specified for each breakpoint:

```tsx
<Column
sm={2} // Takes 2 of 4 columns (50%) on small screens
md={4} // Takes 4 of 8 columns (50%) on medium screens
lg={8} // Takes 8 of 16 columns (50%) on large screens
xlg={8} // Takes 8 of 16 columns (50%) on extra large screens
max={8} // Takes 8 of 16 columns (50%) at maximum width
>
Content
</Column>
```

Each breakpoint prop (`sm`, `md`, `lg`, `xlg`, `max`) can accept either:
- A number representing the number of columns to span
- The value `'auto'` to make the column automatically adjust its width

For example:
```tsx
<Column sm={4} md="auto">
{/* Takes full width (4 columns) on small screens */}
{/* Automatically adjusts width on medium and larger screens */}
</Column>
```

When using `'auto'` at a breakpoint:
- The column will use `flex: 1 1 auto` to grow and shrink as needed
- It will maintain `max-width: 100%` to prevent overflow
- Perfect for responsive layouts where you want columns to naturally share available space
- Useful for card layouts that should adjust based on content

When specifying breakpoints, columns follow these behaviors:

1. **Single Breakpoint**
```tsx
<Column sm={4}>
{/* Takes 4 columns on small screens */}
{/* Maintains this same width percentage on larger breakpoints */}
{/* (Since sm=4 means 100% on small screens, it will stay 100% on larger screens) */}
</Column>

<Column lg={8}>
{/* Starts as a flexible column (autoadjusting width flex: 1 1 auto) on smaller screens */}
{/* Takes 8 columns (50%) starting from large breakpoint */}
</Column>
```

2. **Multiple Breakpoints with Gaps**
```tsx
<Column sm={2} lg={16}>
{/* Takes 2 columns (50%) on small screens */}
{/* Maintains 50% width on medium screens (inherited from sm breakpoint) */}
{/* Takes 16 columns (100%) on large screens and up */}
</Column>
```

3. **Default Behavior**
- By default, columns have `flex: 1 1 auto` and `max-width: 100%`
- The width set at a breakpoint persists until another breakpoint overwrites it
- There is no "reverting" to auto-adjustment after a breakpoint - the last specified width continues to apply

### Auto-width Columns

You can create flexible columns that automatically adjust their width:

```tsx
<Grid>
<Column>
Auto width
</Column>
<Column>
Auto width
</Column>
</Grid>
```

### Nested Grids

The Grid system supports nesting:

```tsx
<Grid>
<Column lg={8}>
<Grid>
<Column lg={8}>Nested content</Column>
<Column lg={8}>Nested content</Column>
</Grid>
</Column>
<Column lg={8}>
Regular content
</Column>
</Grid>
```

#### Nested Grid Proportions

When using nested grids, it's important to understand how column widths relate to each other. Each grid is divided into 16 columns, and when you nest a grid inside a column, that column becomes the new "100%" width for the nested grid.

For example:
- If you have a column that's `lg={4}` (4/16 = 25% of the outer grid)
- And inside it, you place a nested grid with a column that's `lg={8}` (8/16 = 50% of the nested grid)
- The nested column will actually occupy 50% of 25% of the total width, which equals 12.5% of the outer grid width
- This is equivalent to a `lg={2}` column in the outer grid (2/16 = 12.5%)

This proportional relationship helps maintain consistent spacing and alignment throughout your layout hierarchy.


### Column Sizing Methods

The Column component supports three different approaches to sizing:

1. **Grid-based sizing** (using breakpoint props)
```tsx
<Column sm={2} md={4} lg={8}>
{/* Takes specific column spans at different breakpoints */}
</Column>
```

2. **Direct width control**
```tsx
<Column width="200px">
{/* Fixed width column */}
</Column>

<Column width="50%">
{/* Percentage-based width */}
</Column>
```

3. **Flexible with constraints**
```tsx
<Column minWidth="150px" maxWidth="300px">
{/* Flexible column with size constraints */}
</Column>
```

> **Important**: These sizing methods are mutually exclusive. You cannot mix breakpoint-based sizing (sm, md, lg, etc.) with direct width control or constraints.

#### Width Properties

- `width`: Sets a fixed width for the column (CSS width value)
- `minWidth`: Sets a minimum width constraint (CSS width value)
- `maxWidth`: Sets a maximum width constraint (CSS width value)

These properties accept any valid CSS width value (px, %, rem, etc.).

#### Usage Guidelines

1. **Breakpoint-based sizing**
- Best for responsive layouts that need different widths at different screen sizes
- Uses the grid's column system

2. **Direct width control**
- Best for fixed-width columns
- Cannot be used with breakpoint props (sm, md, lg, etc.)

3. **Flexible with constraints**
- Best for columns that need to flex while respecting size limits
- Can use minWidth and/or maxWidth independently
- Works with the auto-flexible behavior

#### Examples

```tsx
// Fixed width
<Column width="200px">Fixed width</Column>

// Breakpoint-based width
<Column
sm={4}
md={6}
lg={8}
>
Grid breakpoint column based width
</Column>

// Auto-flexible (default behavior)
<Column>Flexible width</Column>
```

## Component API <a id="ComponentAPI" />

### Grid Props

<ArgTypes of={Stories.Default} include={['fullWidth', 'className']} />

### Column Props

<ArgTypes of={Stories.Default} />
81 changes: 81 additions & 0 deletions packages/react-components/src/components/Grid/Grid.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
@use 'sass:math';
@use 'sass:map';
@use 'sass:string';
@use './_grid-utils.scss' as grid-utils;

$breakpoints: (
sm: 320px,
md: 672px,
lg: 1024px,
xlg: 1312px,
max: 1584px,
);

$grid-columns: (
sm: 4,
md: 8,
lg: 16,
xlg: 16,
max: 16,
);

@mixin column-styles($width) {
flex: 0 0 $width;
max-width: $width;
}

.grid {
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
width: 100%;

// Alignment styles
&.align-start {
align-items: flex-start;
}

&.align-center {
align-items: center;
}

&.align-end {
align-items: flex-end;
}

&.justify-start {
justify-content: flex-start;
}

&.justify-center {
justify-content: center;
}

&.justify-end {
justify-content: flex-end;
}

&.justify-space-between {
justify-content: space-between;
}

&.justify-space-around {
justify-content: space-around;
}
}

// Generate column classes for each breakpoint
@each $breakpoint, $columns in $grid-columns {
@include grid-utils.breakpoint(map.get($breakpoints, $breakpoint)) {
@for $i from 1 through $columns {
.column#{grid-utils.capitalize($breakpoint)}#{$i} {
@include column-styles(math.percentage(math.div($i, $columns)));
}
}

.column#{grid-utils.capitalize($breakpoint)}Auto {
flex: 1 1 auto;
max-width: 100%;
}
}
}
Loading