Skip to content

Commit

Permalink
Feat(web): Introduce Flex layout component #DS-1415
Browse files Browse the repository at this point in the history
  • Loading branch information
adamkudrna committed Aug 20, 2024
1 parent 77a5ec5 commit 1e0571b
Show file tree
Hide file tree
Showing 20 changed files with 722 additions and 35 deletions.
204 changes: 204 additions & 0 deletions packages/web/src/scss/components/Flex/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
# Flex

Flex is a component that allows you to create a flexible one-dimensional layout.

## Basic Usage

Row layout:

```html
<div class="Flex Flex--row Flex--noWrap Flex--alignmentXStretch Flex--alignmentYStretch">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
```

Column layout:

```html
<div class="Flex Flex--column Flex--noWrap Flex--alignmentXStretch Flex--alignmentYStretch">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
```

Usage with a list:

```html
<ul class="Flex Flex--column Flex--noWrap Flex--alignmentXStretch Flex--alignmentYStretch">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
```

ℹ️ For the row layout, the Flex component uses the [`display: flex`][mdn-display-flex] CSS property. For the column
layout, [`display: grid`][mdn-display-grid] is used because of technical advantages: better overflow control or
alignment API consistency.

## Responsive Direction

To create a responsive layout, use the `tablet` and `desktop` infixes, e.g. `Flex--tablet--row` or `Flex--desktop--column`.

```html
<div class="Flex Flex--column Flex--tablet--row Flex--noWrap Flex--alignmentXStretch Flex--alignmentYStretch">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
```

## Wrapping

By default, Flex items will not wrap (the `Flex--noWrap` modifier). To enable wrapping on all breakpoints, use the
`Flex--wrap` modifier class instead.

```html
<div class="Flex Flex--row Flex--wrap Flex--alignmentXStretch Flex--alignmentYStretch">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
```

### Responsive Wrapping

To create a responsive layout, use the `tablet` and `desktop` infixes, e.g. `Flex--tablet--wrap` or `Flex--desktop--wrap`.

```html
<div
class="
Flex
Flex--row
Flex--wrap
Flex--tablet--noWrap
Flex--desktop--wrap
Flex--alignmentXStretch
Flex--alignmentYStretch
"
>
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
```

## Alignment

### Horizontal Alignment

Flex can be horizontally aligned as stretched (default), or justified to the left, center, or right. Additionally, you
can evenly distribute the items using the space-between value. These values come from the extended
[alignmentX dictionary][dictionary-alignment]. Using a corresponding modifier class will align the Flex items accordingly:

- `Flex--alignmentXStretch` (default)
- `Flex--alignmentXLeft`
- `Flex--alignmentXCenter`
- `Flex--alignmentXRight`
- `Flex--alignmentXSpaceBetween`

### Vertical Alignment

Similarly to the horizontal alignment, Flex can be vertically aligned as stretched (default), or justified to the top,
center, or bottom. There is also an option to align the items to the baseline. These values come from the extended
[alignmentY dictionary][dictionary-alignment]. Using a corresponding modifier class will align the Flex items accordingly:

- `Flex--alignmentYStretch` (default)
- `Flex--alignmentYTop`
- `Flex--alignmentYCenter`
- `Flex--alignmentYBottom`
- `Flex--alignmentYBaseline`

Example:

```html
<div class="Flex Flex--row Flex--noWrap Flex--alignmentXRight Flex--alignmentYBaseline">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
```

### Responsive Alignment

To create a responsive layout, use the `tablet` and `desktop` infixes, e.g. `Flex--tablet--alignmentXRight` or
`Flex--desktop--alignmentYBaseline`.

Example:

```html
<div
class="
Flex
Flex--row
Flex--noWrap
Flex--alignmentXLeft
Flex--alignmentYStretch
Flex--tablet--alignmentXSpaceBetween
Flex--tablet--alignmentYBaseline
"
>
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
```

## Custom Spacing

Use CSS custom properties to define custom spacing between items. Set the `--flex-spacing` property to one of the
spacing token values defined on the `:root` element, e.g. `--flex-spacing: var(--spirit-space-800)`.
This will set the spacing to `var(--spirit-space-800)` for all breakpoints.

```html
<div
class="Flex Flex--row Flex--noWrap Flex--alignmentXStretch Flex--alignmentYStretch"
style="--flex-spacing: var(--spirit-space-1200)"
>
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
```

ℹ️ We highly discourage from using absolute values like `--flex-spacing: 1rem`. It will work, but you will lose
the consistency between the spacing and the design tokens.

If you need to set custom spacing from a specific breakpoint, use the `--flex-spacing-{breakpoint}` property,
e.g. `--flex-spacing-tablet: var(--spirit-space-800)`. The breakpoint value must be one of the breakpoint tokens
except for the `mobile` breakpoint you don't need the suffix at all. The spacing is set to all larger breakpoints
automatically if you don't set them explicitly. E.g. if you set only `--flex-spacing-tablet: var(--spirit-space-800)`
the spacing will be set to `var(--spirit-space-800)` for `tablet` and `desktop` breakpoints while on the `mobile`
breakpoint the default spacing will be used.

Custom spacing from tablet up:

```html
<div
class="Flex Flex--row Flex--noWrap Flex--alignmentXStretch Flex--alignmentYStretch"
style="--flex-spacing-tablet: var(--spirit-space-1200)"
>
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
```

Custom spacing for each breakpoint:

```html
<div
class="Flex Flex--row Flex--noWrap Flex--alignmentXStretch Flex--alignmentYStretch"
style="--flex-spacing: var(--spirit-space-800); --flex-spacing-tablet: var(--spirit-space-1000); --flex-spacing-desktop: var(--spirit-space-1200)"
>
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
```

[mdn-display-flex]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexible_box_layout
[mdn-display-grid]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout
[dictionary-alignment]: https://github.com/lmc-eu/spirit-design-system/blob/main/docs/DICTIONARIES.md#alignment
67 changes: 67 additions & 0 deletions packages/web/src/scss/components/Flex/_Flex.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// 1. Prevent SVG icons from shrinking.
// 2. Use `display: grid` so the orientation of alignmentX and alignmentY does not change as it would with `flex-direction: column`.
// 3. Generate both `wrap` and `noWrap` classes to enable mobile-first and breakpoint-specific wrapping at the same time.

@use 'sass:string';
@use '../../tools/breakpoint';
@use '../../tools/dictionaries';
@use '../../tools/reset';
@use '../../tools/spacing';
@use 'theme';

.Flex {
@include reset.list();
@include spacing.create(
$output-property-name: '--flex-gap',
$responsive-property-base-name: '--flex-spacing',
$breakpoints: theme.$breakpoints,
$default-spacing: theme.$gap
);
}

.Flex > svg {
flex: none; // 1.
}

// stylelint-disable-next-line selector-max-universal -- Let's be bold and tweak all direct descendants regardless of their type to avoid inheritance of spacing for nested Flex.
.Flex > * {
@include spacing.prevent-inheritance(
$responsive-property-base-name: '--flex-spacing',
$breakpoints: theme.$breakpoints
);
}

@each $breakpoint-name, $breakpoint-value in theme.$breakpoints {
$infix: breakpoint.get-modifier('infix', $breakpoint-name, $breakpoint-value);

@include breakpoint.up($breakpoint-value) {
.Flex--#{$infix}row {
display: flex;
}

.Flex--#{$infix}column {
display: grid; // 2.
}

.Flex--#{$infix}wrap {
flex-wrap: wrap; // 3.
}

.Flex--#{$infix}noWrap {
flex-wrap: nowrap; // 3.
}

@include dictionaries.generate-alignments(
$class-name: 'Flex',
$dictionary-values: theme.$alignment-x-dictionary,
$axis: 'x',
$infix: $infix
);
@include dictionaries.generate-alignments(
$class-name: 'Flex',
$dictionary-values: theme.$alignment-y-dictionary,
$axis: 'y',
$infix: $infix
);
}
}
8 changes: 8 additions & 0 deletions packages/web/src/scss/components/Flex/_theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@use 'sass:list';
@use '@tokens' as tokens;
@use '../../settings/dictionaries';

$alignment-x-dictionary: list.join(dictionaries.$alignments-x-extended, space-between);
$alignment-y-dictionary: list.join(dictionaries.$alignments-y-extended, baseline);
$breakpoints: tokens.$breakpoints;
$gap: tokens.$space-600;
Loading

0 comments on commit 1e0571b

Please sign in to comment.