Skip to content

Commit

Permalink
feat: Add horizontal and vertical alignment options to Column (#1428)
Browse files Browse the repository at this point in the history
Co-authored-by: Aram <[email protected]>
  • Loading branch information
VincentSmedinga and alimpens authored Jul 24, 2024
1 parent 6adbd13 commit d5a7766
Show file tree
Hide file tree
Showing 14 changed files with 322 additions and 103 deletions.
2 changes: 1 addition & 1 deletion packages/css/src/components/column/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

# Column

Stacks its children vertically and adds a vertical gap between them.
Stacks its children vertically with gaps between them and offers alignment options.
32 changes: 32 additions & 0 deletions packages/css/src/components/column/column.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,35 @@
}
}
}

.ams-column--align-around {
justify-content: space-around;
}

.ams-column--align-between {
justify-content: space-between;
}

.ams-column--align-center {
justify-content: center;
}

.ams-column--align-end {
justify-content: flex-end;
}

.ams-column--align-evenly {
justify-content: space-evenly;
}

.ams-column--align-horizontal-center {
align-items: center;
}

.ams-column--align-horizontal-end {
align-items: flex-end;
}

.ams-column--align-horizontal-start {
align-items: flex-start;
}
2 changes: 2 additions & 0 deletions packages/css/src/components/row/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- @license CC0-1.0 -->

# Row

Stacks its children horizontally with gaps between them and offers alignment options.
23 changes: 23 additions & 0 deletions packages/react/src/Column/Column.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { render, screen } from '@testing-library/react'
import { createRef } from 'react'
import { Column, columnGapSizes } from './Column'
import { crossAlignOptionsForColumn, mainAlignOptions } from '../common/layout'
import '@testing-library/jest-dom'

describe('Column', () => {
Expand Down Expand Up @@ -64,4 +65,26 @@ describe('Column', () => {

expect(ref.current).toBe(component)
})

describe('Alignment', () => {
mainAlignOptions.map((align) =>
it(`sets the ‘${align}’ alignment`, () => {
const { container } = render(<Column align={align} />)

const component = container.querySelector(':only-child')

expect(component).toHaveClass(`ams-column--align-${align}`)
}),
)

crossAlignOptionsForColumn.map((align) =>
it(`sets the ‘${align}’ vertical alignment`, () => {
const { container } = render(<Column alignHorizontal={align} />)

const component = container.querySelector(':only-child')

expect(component).toHaveClass(`ams-column--align-horizontal-${align}`)
}),
)
})
})
39 changes: 33 additions & 6 deletions packages/react/src/Column/Column.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,49 @@
import clsx from 'clsx'
import { forwardRef } from 'react'
import type { HTMLAttributes, PropsWithChildren } from 'react'
import type { CrossAlignForColumn, MainAlign } from '../common/layout'

export const columnGapSizes: Array<string> = ['none', 'extra-small', 'small', 'large', 'extra-large'] as const
export const columnGapSizes = ['none', 'extra-small', 'small', 'large', 'extra-large'] as const

type ColumnTag = 'article' | 'div' | 'section'
type ColumnGap = (typeof columnGapSizes)[number]
type ColumnTag = 'article' | 'div' | 'section'

export type ColumnProps = {
/** The HTML element to use. */
/**
* The vertical alignment of the items in the column.
* @default start
*/
align?: MainAlign
/**
* The horizontal alignment of the items in the column.
* @default stretch
*/
alignHorizontal?: CrossAlignForColumn
/**
* The HTML element to use.
* @default div
*/
as?: ColumnTag
/** The amount of vertical space between items. */
/**
* The amount of space between items.
* @default medium
*/
gap?: ColumnGap
} & PropsWithChildren<HTMLAttributes<HTMLElement>>

export const Column = forwardRef(
({ as: Tag = 'div', children, className, gap, ...restProps }: ColumnProps, ref: any) => (
<Tag {...restProps} ref={ref} className={clsx('ams-column', gap && `ams-column--gap-${gap}`, className)}>
({ align, alignHorizontal, as: Tag = 'div', children, className, gap, ...restProps }: ColumnProps, ref: any) => (
<Tag
{...restProps}
ref={ref}
className={clsx(
'ams-column',
align && `ams-column--align-${align}`,
alignHorizontal && `ams-column--align-horizontal-${alignHorizontal}`,
gap && `ams-column--gap-${gap}`,
className,
)}
>
{children}
</Tag>
),
Expand Down
27 changes: 21 additions & 6 deletions packages/react/src/Row/Row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,36 @@ import { forwardRef } from 'react'
import type { HTMLAttributes, PropsWithChildren } from 'react'
import type { CrossAlign, MainAlign } from '../common/layout'

export const rowGapSizes: Array<string> = ['none', 'extra-small', 'small', 'large', 'extra-large'] as const
export const rowGapSizes = ['none', 'extra-small', 'small', 'large', 'extra-large'] as const

type RowGap = (typeof rowGapSizes)[number]
type RowTag = 'article' | 'div' | 'section'

export type RowProps = {
/** The horizontal alignment of the items in the row. */
/**
* The horizontal alignment of the items in the row.
* @default start
*/
align?: MainAlign
/** The vertical alignment of the items in the row. */
/**
* The vertical alignment of the items in the row.
* @default stretch
*/
alignVertical?: CrossAlign
/** The HTML element to use. */
/**
* The HTML element to use.
* @default div
*/
as?: RowTag
/** The amount of vertical space between items. */
/**
* The amount of space between items.
* @default medium
*/
gap?: RowGap
/** Whether items of the row can wrap onto multiple lines. */
/**
* Whether items of the row can wrap onto multiple lines.
* @default false
*/
wrap?: boolean
} & PropsWithChildren<HTMLAttributes<HTMLElement>>

Expand Down
9 changes: 7 additions & 2 deletions packages/react/src/common/layout.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
export const crossAlignOptions: Array<string> = ['baseline', 'center', 'end', 'start'] as const
export const crossAlignOptions = ['start', 'center', 'baseline', 'end'] as const
export type CrossAlign = (typeof crossAlignOptions)[number]

export const mainAlignOptions: Array<string> = ['around', 'between', 'center', 'end', 'evenly'] as const
// Baseline alignment doesn’t make much sense in a column.
// This separate type for it clarifies its appearance in Storybook.
export const crossAlignOptionsForColumn = crossAlignOptions.filter((option) => option !== 'baseline')
export type CrossAlignForColumn = (typeof crossAlignOptionsForColumn)[number]

export const mainAlignOptions = ['center', 'end', 'between', 'around', 'evenly'] as const
export type MainAlign = (typeof mainAlignOptions)[number]
63 changes: 51 additions & 12 deletions storybook/config/preview-body.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<style>
:root {
--ams-docs-grey: rgba(0, 0, 0, 0.0625);
--ams-docs-pink: rgba(229, 0, 130, 0.25);
}

.ams-docs-figure {
display: flex;
gap: 0.25rem;
Expand Down Expand Up @@ -33,18 +38,6 @@
width: fit-content;
}

.ams-docs-paragraph {
font-family: "Amsterdam Sans", sans-serif;
font-size: 1rem;
line-height: 1.5;
}

.ams-docs-pink-box {
background-color: rgba(229, 0, 130, 25%); /* stylelint-disable-line color-function-notation */
padding-block: 2rem;
text-align: center;
}

.ams-docs-card {
border: 0.0625rem solid hotpink;
display: flex;
Expand All @@ -60,6 +53,52 @@
padding: 1rem; /* stylelint-disable-line */
}

.ams-docs-column,
.ams-docs-row {
background: repeating-linear-gradient(
135deg,
var(--ams-docs-grey),
var(--ams-docs-grey) 0.5rem,
white 0.5rem,
white 1rem
);
border: thin solid var(--ams-docs-grey);
}

.ams-docs-column {
max-inline-size: 16rem;
min-block-size: 16rem;
}

.ams-docs-row {
min-block-size: 6rem;
}

.ams-docs-grid {
/* Todo columns background */
}

.ams-docs-item {
background-color: var(--ams-docs-pink);
border: thin dashed var(--ams-docs-grey);
font-family: "Amsterdam Sans", sans-serif;
font-size: var(--ams-paragraph-small-font-size);
line-height: var(--ams-paragraph-small-line-height);
margin-block: 0;
margin-inline: 0;
padding-block: 1.5rem;
text-align: center;
}

.ams-docs-row > .ams-docs-item {
flex-basis: 8rem;
padding-inline: 1.5rem;
}

.ams-docs-column > .ams-docs-item {
min-inline-size: 3rem;
}

[class*="ams-docs-token-preview--"] {
block-size: 1rem;
}
Expand Down
43 changes: 35 additions & 8 deletions storybook/src/components/Column/Column.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,12 @@ import README from "../../../../packages/css/src/components/column/README.md?raw

<Markdown>{README}</Markdown>

## Design

The five [space](/docs/foundation-design-tokens-space--docs) sizes are available for the size of the gap.

## How to Use

Wrap a Column around a set of components that need the same amount of white space between them.

To add white space below a single element, the [Margin Bottom](/docs/utilities-css-margin--docs) utility class can be used as well.
- Wrap a Column around a set of elements that need the same amount of white space between them.
- The five sizes of [Component Space](/docs/foundation-design-tokens-space--docs) are available for the width or height of the gap.
- To add white space below a single element, you can add a [Margin Bottom](/docs/utilities-css-margin--docs) instead.
- Align the elements horizontally or vertically through the alignment props.

## Examples

Expand All @@ -26,9 +23,39 @@ To add white space below a single element, the [Margin Bottom](/docs/utilities-c

<Controls />

### Use Another HTML Element
### Alignment

Items in the column can be aligned vertically in several ways:

- **Center**: center items within the column.
- **End**: align items to the bottom of the column – to the bottom.
- **Space Between**: distribute whitespace between items.
- **Space Around**: distribute whitespace around items.
- **Space Evenly**: distribute whitespace evenly around items.

By default, items align to the **start** of the column – at the top.
This option has no class name or prop value.

This example centers three items vertically.

<Canvas of={ColumnStories.Alignment} />

### Horizontal alignment

Items in the column can be aligned horizontally in several ways:

- **Start**: align items to the start of the column. This is the left side in left-to-right languages.
- **Center**: center items within the column.
- **End**: align items to the end of the column. This is the right side in left-to-right languages.

This example centers three items horizontally.

<Canvas of={ColumnStories.HorizontalAlignment} />

### Use another HTML element

By default, a Column renders a `<div>`.
Use the `as` prop to make your markup more semantic.
In this example, the Column uses a `<section>` element to group the heading and the cards.

<Canvas of={ColumnStories.CustomTagName} />
Loading

0 comments on commit d5a7766

Please sign in to comment.