Skip to content
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

Feat(web): Extend Flex direction by reverse value #1842

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
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 apps/demo/partials/cover.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="Container">

<h1
class="Flex Flex--noWrap Flex--alignmentXStretch Flex--alignmentYCenter Flex--row typography-heading-xlarge-bold"
class="Flex Flex--noWrap Flex--alignmentXStretch Flex--alignmentYCenter Flex--horizontal typography-heading-xlarge-bold"
style="--flex-spacing: var(--spirit-space-1000)"
>
{{title}}
Expand Down
2 changes: 1 addition & 1 deletion apps/web-twig-demo/templates/partials/cover.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Container>

<h1
class="Flex Flex--noWrap Flex--alignmentXStretch Flex--alignmentYCenter Flex--row typography-heading-xlarge-bold"
class="Flex Flex--noWrap Flex--alignmentXStretch Flex--alignmentYCenter Flex--horizontal typography-heading-xlarge-bold"
style="--flex-spacing: var(--spirit-space-1000)"
>
{{ title }}
Expand Down
9 changes: 5 additions & 4 deletions docs/DICTIONARIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ This project uses `dictionaries` to unify props between different components.

### Direction

| Dictionary | Values | Code name |
| ------------- | ------------------------ | ------------- |
| Direction | `horizontal`, `vertical` | Direction |
| DirectionAxis | `x`, `y` | DirectionAxis |
| Dictionary | Values | Code name |
| ----------------- | --------------------------------------------- | ----------------- |
| Direction | `horizontal`, `vertical` | Direction |
| DirectionExtended | `horizontal`, `vertical`, `horizontalReverse` | DirectionExtended |
| DirectionAxis | `x`, `y` | DirectionAxis |

### Emphasis

Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ <h2 class="typography-heading-small-regular text-secondary mb-1000">
Development Preview
</h2>

<div class="Flex Flex--row Flex--wrap Flex--alignmentXCenter Flex--alignmentYCenter">
<div class="Flex Flex--horizontal Flex--wrap Flex--alignmentXCenter Flex--alignmentYCenter">
<a
href="https://spirit.supernova-docs.io/spirit/"
class="Button Button--tertiary Button--large"
Expand Down
21 changes: 21 additions & 0 deletions packages/codemods/src/transforms/v4/web-react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,24 @@ npx @lmc-eu/spirit-codemods -p <path> -t v4/web-react/collapse-isDisposable-prop
- <UncontrolledCollapse hideOnCollapse … />
+ <UncontrolledCollapse isDisposable … />
```

### `v4/web-react/flex-direction-values` - Flex direction prop values `row` to `horizontal` and `column` to `vertical`
pavelklibani marked this conversation as resolved.
Show resolved Hide resolved

This codemod updates `direction` values of `Flex` component by replacing `row` to `horizontal` and `column` to `vertical`.

#### Usage

```sh
npx @lmc-eu/spirit-codemods -p <path> -t v4/web-react/flex-direction-values
```

#### Example

```diff
- <Flex direction="row" … />
- <Flex direction="column" … />
- <Flex direction={{ mobile: "column", tablet: "row" }} … />
+ <Flex direction="horizontal" … />
+ <Flex direction="vertical" … />
+ <Flex direction={{ mobile: 'vertical', tablet: 'horizontal' }} … />
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
// @ts-ignore: No declaration -- The library is not installed; we don't need to install it for fixtures.
import { Flex } from '@lmc-eu/spirit-web-react';

export const MyComponent = () => (
<>
<Flex>Flex</Flex>
<Flex direction="row">Flex</Flex>
<Flex direction="column">Flex</Flex>
<Flex direction={{ mobile: 'row', tablet: 'column' }}>Flex</Flex>
</>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
// @ts-ignore: No declaration -- The library is not installed; we don't need to install it for fixtures.
import { Flex } from '@lmc-eu/spirit-web-react';

export const MyComponent = () => (
<>
<Flex>Flex</Flex>
<Flex direction="horizontal">Flex</Flex>
<Flex direction="vertical">Flex</Flex>
<Flex direction={{ mobile: 'horizontal', tablet: 'vertical' }}>Flex</Flex>
</>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { testTransform } from '../../../../../tests/testUtils';

testTransform(__dirname, 'flex-direction-values');
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { API, FileInfo } from 'jscodeshift';
import { removeParentheses } from '../../../helpers';

const transform = (fileInfo: FileInfo, api: API) => {
const j = api.jscodeshift;
const root = j(fileInfo.source);

// Define the mapping from old direction values to new ones
const directionMap: { [key: string]: string } = {
row: 'horizontal',
column: 'vertical',
};

// Find all Flex components
root
.find(j.JSXOpeningElement, { name: { type: 'JSXIdentifier', name: 'Flex' } })
.find(j.JSXAttribute, { name: { type: 'JSXIdentifier', name: 'direction' } })
.forEach((attributePath) => {
const attribute = attributePath.node;

if (attribute.value) {
// Handle string literal values
if (attribute.value.type === 'StringLiteral') {
const newValue = directionMap[attribute.value.value];
if (newValue) {
attribute.value = j.stringLiteral(newValue);
}
}

// Handle object values
else if (
attribute.value.type === 'JSXExpressionContainer' &&
attribute.value.expression.type === 'ObjectExpression'
) {
const objectExpression = attribute.value.expression;

objectExpression.properties.forEach((property) => {
if (
property.type === 'ObjectProperty' &&
(property.key.type === 'Identifier' || property.key.type === 'Literal') &&
property.value.type === 'StringLiteral'
) {
const oldValue = property.value.value;

// Update the value if it matches a key in directionMap
if (oldValue in directionMap) {
// Manually create a single-quoted Literal
property.value = j.literal(directionMap[oldValue]);
// We need single quotes in object values
// @ts-expect-error extra is not defined on Literal
property.value.extra = {
raw: `'${directionMap[oldValue]}'`,
rawValue: directionMap[oldValue],
};
}
}
});
}
}
});

// Convert the transformed code to source with double quotes for strings
return removeParentheses(root.toSource({ quote: 'double' }));
};

export default transform;
13 changes: 13 additions & 0 deletions packages/web-react/DEPRECATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,18 @@ We are providing a [codemod][codemod-collapse] to assist with this change.

- `<UncontrolledCollapse id="collapse" renderTrigger={…} hideOnCollapse … />` → `<UncontrolledCollapse id="collapse" renderTrigger={…} isDisposable … />`

### Flex

The direction values `row` and `column` were removed, please use `horizontal` and `vertical` instead.

### Migration Guide

We are providing a [codemod][codemod-flex] to assist with this change.

- `<Flex direction="row" />` → ` <Flex direction="horizontal" />`
- `<Flex direction="column" />` → `<Flex direction="vertical" />`
- `<Flex direction={{ mobile: 'column', tablet: 'row' }} />` → `<Flex direction={{ mobile: 'vertical', tablet: 'horizontal' }} />`

[codemod-collapse]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/codemods/src/transforms/v4/web-react/README.md#v4web-reactcollapse-isdisposable-prop--uncontrolledcollapse-hideoncollapse-to-isdisposable-prop-change
[codemod-flex]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/codemods/src/transforms/v4/web-react/README.md#v4web-reactflex-direction-values---flex-direction-prop-values-row-to-horizontal-and-column-to-vertical
[readme-deprecations]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#deprecations
14 changes: 10 additions & 4 deletions packages/web-react/src/components/Flex/Flex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,29 @@

import classNames from 'classnames';
import React, { ElementType } from 'react';
import { AlignmentXExtended, AlignmentYExtended } from '../../constants';
import { AlignmentXExtended, AlignmentYExtended, DirectionExtended } from '../../constants';
import { useStyleProps } from '../../hooks';
import { SpiritFlexProps } from '../../types';
import { useFlexStyleProps } from './useFlexStyleProps';

const defaultProps: Partial<SpiritFlexProps> = {
alignmentX: AlignmentXExtended.STRETCH,
alignmentY: AlignmentYExtended.STRETCH,
direction: 'row',
direction: DirectionExtended.HORIZONTAL,
elementType: 'div',
isWrapping: false,
};

const Flex = <T extends ElementType = 'div'>(props: SpiritFlexProps<T>): JSX.Element => {
const propsWithDefaults = { ...defaultProps, ...props };
const { elementType: ElementTag = 'div', children, ...restProps } = propsWithDefaults;
const { classProps, props: modifiedProps, styleProps: flexStyle } = useFlexStyleProps(restProps);
const {
elementType: ElementTag = 'div',
/** @deprecated "row" and "column" values will be removed in the next major version. Please use "horizontal" and "vertical" instead. */
pavelklibani marked this conversation as resolved.
Show resolved Hide resolved
direction,
children,
...restProps
} = propsWithDefaults;
const { classProps, props: modifiedProps, styleProps: flexStyle } = useFlexStyleProps({ direction, ...restProps });
const { styleProps, props: otherProps } = useStyleProps(modifiedProps);

const flexStyleProps = {
Expand Down
51 changes: 34 additions & 17 deletions packages/web-react/src/components/Flex/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

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

## ⚠️ DEPRECATION NOTICE

Direction values `row` and `column` are deprecated and will be removed in the next major release. Use `horizontal` and `vertical` values instead.

[What are deprecations?][readme-deprecations]

## Basic Usage

Row layout:
Horizontal layout:

```jsx
<Flex>
Expand All @@ -14,10 +20,20 @@ Row layout:
</Flex>
```

Column layout:
Horizontal reverse layout:

```jsx
<Flex direction="horizontal-reverse">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</Flex>
```

Vertical layout:

```jsx
<Flex direction="column">
<Flex direction="vertical">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
Expand All @@ -27,14 +43,14 @@ Column layout:
Usage with a list:

```jsx
<Flex elementType="ul" direction="column">
<Flex elementType="ul" direction="vertical">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</Flex>
```

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

Expand All @@ -43,7 +59,7 @@ alignment API consistency.
To create a responsive layout, pass an object as the value for the `direction` property, using breakpoint keys to specify different layouts for each screen size.

```jsx
<Flex direction={{ mobile: 'column', tablet: 'row' }}>
<Flex direction={{ mobile: 'vertical', tablet: 'horizontal' }}>
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
Expand Down Expand Up @@ -158,25 +174,26 @@ Custom vertical (y-axis) spacing:

## API

| Name | Type | Default | Required | Description |
| ------------- | -------------------------------------------------------------------- | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `alignmentX` | \[[AlignmentXExtended dictionary][dictionary-alignment] \| `object`] | `stretch` | ✕ | Apply horizontal alignment of items, use an object to set responsive values, e.g. `{ mobile: 'left', tablet: 'center', desktop: 'right' }` |
| `alignmentY` | \[[AlignmentYExtended dictionary][dictionary-alignment] \| `object`] | `stretch` | ✕ | Apply vertical alignment of items, use an object to set responsive values, e.g. `{ mobile: 'top', tablet: 'center', desktop: 'bottom' }` |
| `direction` | \[[Direction dictionary][direction-dictionary] \| `object` ] | `row` | ✕ | Direction of the items, use an object to set responsive values, e.g. `{ mobile: 'row', tablet: 'row', desktop: 'column' }` |
| `elementType` | HTML element | `div` | ✕ | Element type to use for the Grid |
| `isWrapping` | \[ `bool` \| `object` ] | `false` | ✕ | Whether items will wrap, use an object to set responsive values, e.g. `{ mobile: true, tablet: true, desktop: false }` |
| `spacing` | \[`SpaceToken` \| `Partial<Record<BreakpointToken, SpaceToken>>`] | — | ✕ | Apply [custom spacing](#custom-spacing) in both horizontal and vertical directions between items |
| `spacingX` | \[`SpaceToken` \| `Partial<Record<BreakpointToken, SpaceToken>>`] | — | ✕ | Apply horizontal [custom spacing](#custom-spacing) between items |
| `spacingY` | \[`SpaceToken` \| `Partial<Record<BreakpointToken, SpaceToken>>`] | — | ✕ | Apply vertical [custom spacing](#custom-spacing) between items |
| Name | Type | Default | Required | Description |
| ------------- | ---------------------------------------------------------------------------------------- | ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `alignmentX` | [[AlignmentXExtended dictionary][dictionary-alignment] \| `object`] | `stretch` | ✕ | Apply horizontal alignment of items, use an object to set responsive values, e.g. `{ mobile: 'left', tablet: 'center', desktop: 'right' }` |
| `alignmentY` | [[AlignmentYExtended dictionary][dictionary-alignment] \| `object`] | `stretch` | ✕ | Apply vertical alignment of items, use an object to set responsive values, e.g. `{ mobile: 'top', tablet: 'center', desktop: 'bottom' }` |
| `direction` | [[DirectionExtended dictionary][dictionary-direction] \| `row` \| `column` \| `object` ] | `horizontal` | ✕ | [**DEPRECATED**][readme-deprecations] Row and column will be removed in favor of `DirectionExtended`; Direction of the items, use an object to set responsive values, e.g. `{ mobile: 'horizontal', tablet: 'horizontal', desktop: 'vertical' }` |
| `elementType` | HTML element | `div` | ✕ | Element type to use for the Grid |
| `isWrapping` | [ `bool` \| `object` ] | `false` | ✕ | Whether items will wrap, use an object to set responsive values, e.g. `{ mobile: true, tablet: true, desktop: false }` |
| `spacing` | [`SpaceToken` \| `Partial<Record<BreakpointToken, SpaceToken>>`] | — | ✕ | Apply [custom spacing](#custom-spacing) in both horizontal and vertical directions between items |
| `spacingX` | [`SpaceToken` \| `Partial<Record<BreakpointToken, SpaceToken>>`] | — | ✕ | Apply horizontal [custom spacing](#custom-spacing) between items |
| `spacingY` | [`SpaceToken` \| `Partial<Record<BreakpointToken, SpaceToken>>`] | — | ✕ | Apply vertical [custom spacing](#custom-spacing) between items |

On top of the API options, the components accept [additional attributes][readme-additional-attributes].
If you need more control over the styling of a component, you can use [style props][readme-style-props]
and [escape hatches][readme-escape-hatches].

[dictionary-alignment]: https://github.com/lmc-eu/spirit-design-system/blob/main/docs/DICTIONARIES.md#alignment
[direction-dictionary]: https://github.com/lmc-eu/spirit-design-system/blob/main/docs/DICTIONARIES.md#direction
[dictionary-direction]: https://github.com/lmc-eu/spirit-design-system/blob/main/docs/DICTIONARIES.md#direction
[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
[readme-additional-attributes]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#additional-attributes
[readme-deprecations]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-twig/README.md#deprecations
[readme-escape-hatches]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#escape-hatches
[readme-style-props]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#style-props
10 changes: 5 additions & 5 deletions packages/web-react/src/components/Flex/__tests__/Flex.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ describe('Flex', () => {

expect(screen.getByText(text)).toBeInTheDocument();
expect(screen.getByTestId(testId)).toHaveClass(
'Flex Flex--noWrap Flex--row Flex--alignmentXStretch Flex--alignmentYStretch',
'Flex Flex--noWrap Flex--horizontal Flex--alignmentXStretch Flex--alignmentYStretch',
);
});

it('should have direction class name', () => {
render(<Flex direction="column" data-testid={testId} />);
render(<Flex direction="vertical" data-testid={testId} />);

expect(screen.getByTestId(testId)).toHaveClass('Flex--column');
expect(screen.getByTestId(testId)).toHaveClass('Flex--vertical');
});

it('should have responsive direction class name', () => {
render(<Flex direction={{ mobile: 'row', tablet: 'column', desktop: 'column' }} data-testid={testId} />);
render(<Flex direction={{ mobile: 'horizontal', tablet: 'vertical', desktop: 'vertical' }} data-testid={testId} />);

expect(screen.getByTestId(testId)).toHaveClass('Flex--row Flex--tablet--column Flex--desktop--column');
expect(screen.getByTestId(testId)).toHaveClass('Flex--horizontal Flex--tablet--vertical Flex--desktop--vertical');
});

it('should have alignmentX class name', () => {
Expand Down
Loading
Loading